Previous steps involved are datiled in the series of articles
"AMP with Raspberry Pi: Cookbook".
Based on previous work with 6502 emulation an AMP example app was developed:
AMP on Linux GUI (Raspbian) |
One local process (Linux) send keystrokes to a shared memory location (remote keyboard)
Second local process (Linux) show Ascii data comming to the other shared memory location (remote monitor)
The process run asyncronously and the IPC (inter process comunication) is imperfect, as no signaling was implemented.
In order to get the example working you need:
AMP framework: (the same as previous posts) Linux on Cores 0,1,2 using lower RAM and Bare Metal on Core 3 using upper RAM (above 0x20000000). See Step 1 for details.
Get example files from git:
git clone https://github.com/telmomoya/AMP
Enough Linux privileges
In a Linux terminal do
cd /bare-metal
./start-metal.sh
cd ..
./monitor6510-char 0x20002ed1
This will start the bare-metal process and the Linux process for monitor basic output.
Keep that terminal open and in another one type:
./keyboard6510-char 0x200058d4
Test the EhBASIC interpeter (answer only "enter" for Memory size)
You can stop emulator with
./stop-metal.sh
And restart it ( again with ./start-metal.sh) so you have LCM.
If you start ehbasic with Warm option you can list your previous "sesion" basic program, as it remained in memory.
Using bare-metal app via ssh |
Under the hood
In bare-metal folder you will find 3 scripts:
start-metal.sh
This script can be used for load the img file (up-metal-6510.img) at 0x2000000 (upper 512Mb) and point Core3 Mailbox3 to that address to start it's execution.
stop-metal.sh
This script stops bare-metal execution
build-up-metal.sh
Used for bare-metal compilation & linking (uses rpi.x linker script)
In root folder you have two files for local (Linux) run.
keyboard6510-char
Waits one text line and sends characters to remote process (bare-metal)
monitor6510-char
Looks to mailbox variable physical address and print if value changes (no signaling implemented, must be improved)
Life control managment
When Linux boots puts all unused cores in a loop, looking for their mailbox 3. When that mailbox is no 0 the core jumps to the address contained there.
The linker script used sets at execution start the code contained in the startup assembler file armc-08-start.S (file listing and comments in this post).
That file prepare the environment (stack and variables initialization) and junps to C code kernel_main function, located at 6510.c in this case.
When kernel_main returns to assembler startup (armc-08-start.S) encounters a loop, similar to Linux one, looking for mailbox3.
So, the restart procedure is identical to initial start: write address execution in mailbox 3.
Now let's see how the stop process was implemented. Take a look to kernel_main function, included at 6510.c
volatile char live=0x1; //LCM flag
volatile char mailbox=0x20; //Emulator OUT (Monitor)
volatile char mailbox2=0x0; //Emulator IN(Keyboard)
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "6502/6502.h"
#include "io/gpios.h"
void kernel_main( unsigned int r0, unsigned int r1, unsigned int atags )
{
reset6502();
while(live){
step6502();
}
}
nm up-metal-6510.elf | grep live
In that way the provided script stop-metal.sh does:
lcm_control=0x$(nm up-metal-6510.elf | grep 'D live' | awk '{print $1}')
./devmem $lcm_control b 0x00
First obtain physical address for "live" variable and the writes 0 to it.
IPC
Inter Process Comunication is implemented using shared memory, specifically locations used by mailbox and mailbox2 variables (volatile). Lets list mailbox symbols:
nm up-metal-6510.elf | grep mailbox
20002ed1 D mailbox
200058d4 B mailbox2
That file prepare the environment (stack and variables initialization) and junps to C code kernel_main function, located at 6510.c in this case.
When kernel_main returns to assembler startup (armc-08-start.S) encounters a loop, similar to Linux one, looking for mailbox3.
So, the restart procedure is identical to initial start: write address execution in mailbox 3.
Now let's see how the stop process was implemented. Take a look to kernel_main function, included at 6510.c
volatile char live=0x1; //LCM flag
volatile char mailbox=0x20; //Emulator OUT (Monitor)
volatile char mailbox2=0x0; //Emulator IN(Keyboard)
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "6502/6502.h"
#include "io/gpios.h"
void kernel_main( unsigned int r0, unsigned int r1, unsigned int atags )
{
reset6502();
while(live){
step6502();
}
}
Please note: live and mailbox definitions as volatile, in order to avoid compiler optimizations, ensuring variables in memory, accesible for Linux process.
You can see that kernel_main execution depends on "live" value. The idea here is make live=0 from Linux to stop execution (really return Core 3 to the loop looking to mailbox 3 in armc-08-start.S).
In order to determine the physical address for "live" variable we can lists symbols from object file:nm up-metal-6510.elf | grep live
In that way the provided script stop-metal.sh does:
lcm_control=0x$(nm up-metal-6510.elf | grep 'D live' | awk '{print $1}')
./devmem $lcm_control b 0x00
First obtain physical address for "live" variable and the writes 0 to it.
IPC
Inter Process Comunication is implemented using shared memory, specifically locations used by mailbox and mailbox2 variables (volatile). Lets list mailbox symbols:
nm up-metal-6510.elf | grep mailbox
20002ed1 D mailbox
200058d4 B mailbox2
On linux you can call
./monitor6510-char 0x20002ed1
that prints on terminal any change to that physicall address, that is mailbox bare-metal variable.
And in another terminal
./keyboard6510-char 0x200058d4
Sends to mailbox2 the typed chars.
-------------------------------------------------------------
If you want to compile provided sourcefiles do:
Linux keyboard and monitor apps:
cd linux
gcc -o monitor6510-char monitor6510-char.c
gcc -o keyboard6510-char keyboard6510-char.c
Bare-metal emulator:
cd bare-metal
build-up-metal.sh