I decided to use the 32 x IO (Servo, Analogue, Digital) as my test ground for the VM – the firmware will in this case include easyIPC (SPI in this case) and a 32 channel programmable IO controller. Each of the channels have capabilities like:
- Servo with a 14 bit pulse resolution.
- PWM out with 14 bit resolution. This is a bit-banged PWM that can be used on all channels.
- Digital Signal Input
- Digital Signal Output
Some of the channels will have the following:
- High resolution/frequency PWM signals
- Analogue Input
- Analogue output.
This firmware is an excellent test-ground because it includes highly programmable logic and a hard real-time core on the bit-banging part.
Lets draft some PLAIN Assembly code:
Enum uint32 Mode
Servo=0
PWM=1
DigitalIn=2
DigitalOut=3
HRPWM=4
AnalogueIn=5
Analogueout=6
End
Object Channel
Mode chMode = Mode.Servo
uint32 position=0
uint32 frequency = 0
uint32 duty = 0
uint32 analogueOut = 0
uint32 analogueIn = 0
End
Channel Ch1
Channel Ch2
Channel Ch3
Channel Ch4
...
Bit digitalIn[32]
Bit digitalOut[32]
This is a draft of how I want PLAIN Assembly to see the easyIPC objects. Ch1.Mode will be located at register 0x8000, but we can also locate data on selected registers as follows
Channel Ch1 at R(0x8010)
In this example I force Ch1 to be located at Register 0x8010.
The more tricky part is the integration with C/C++ code. The challenge is that the module and data we transfer must match what the C/C++ firmware expects. This last mapping is done by the real-time linker in the firmware that receive the above as a “PLAIN Module Specification”. If it fail it will need to reject the module. In theory it should never fail as the assembler should stop us, but it is always the possibility of firmware version mismatch. This part will need to be strict or we will just dig into loads of debug problems.
Map Channel to C(Channel)
Map digitalIn to C(DigIn)
Map digitalOut to C(DigOut)
Assign Ch1.chMode = Mode.Servo
Assign Ch2.chMode = Mode.DigitalIn
Assign Ch3.chMode = Mode.DigitalIn
Event digitalIn[2]
Assign Ch1.position = 0
End
Event digitalIn[3]
Assign Ch1.position = 100
End
This example configure Ch1 as a Servo and Ch2, Ch3 as digital input pins. The Map statements link the objects to associated C/C++ code. The Assembler (and real-time linker) will check these exact names and parameters – parameters must match on name and data type.
The Event statement “digitalIn[2]” declare that any change to bit 2 in the digitalIn will cause a call to this bit of logic. This will be called regardless if it is C/C++ or PLAIN assembly that makes the change.
I think this will work, but I need to let it mature to catch up missing bits and see if I can optimize this. Notice that while this example is ca 40 lines in assembly we would be talking about ca 7 instructions in the resulting code (+ initialization). The initialization will in this case be nothing since 0 is the default value on all registers. The VM will automatically reset this before execution to avoid that we have random, default values. “Event digitalIn[2]” will generate 2 instructions – an Assign and a Return.
But, keep in mind that this draft is work in progress. I will implement this next to see how it actually works out in real life.