I have written a lot about SIMPL over the years, but it is my conviction that it has uses as a tool to help bootstrap various novel processors – and to ease the early stages of processor code development. It’s not a fully fledged interpreted language like Forth or BASIC but just enough to make writing code easier on unfamiliar processors.
SIMPL may be written in about 100 lines of C code, or ported directly to the native assembly language of the target processor for even more compactness and speed, which is the approach I have used with the MSP430.
With this in mind, I will attempt to use SIMPL to provide an interactive coding environment for the 1949 EDSAC, – or at least a simulated or an FPGA softcore version of it – as part of the Wuthering Bytes EDSAC Challenge – to be held i Hebden Bridge in early September.
This is a work in progress – so don’t expect too much just yet.
SIMPL is a character interpreter running within a loop and as such, models a virtual machine:
NEXT: Fetch next Character from buffer
Increment Program Counter
Decode to form unique Jump Address
Jump to code body, execute code – end with Jump back to NEXT
This forms the heart of a very simple virtual machine which is capable of executing unique code functions based on the character found in the memory buffer. This elementary execution model is equivalent to most modern processor systems, so with a little bit of work, SIMPL can form the basis of a simulator for most basic processor architectures.
The character may be fetched from a serial terminal input buffer and executed immediately in an interactive manner, or the Instruction Pointer can point to a general area of program memory, and execute the character instructions found there.
It is this combination of using SIMPL either interactively at the terminal or as a means of entering and editing text into memory and subsequently running it from RAM, that makes SIMPL a powerful tool – to have in the programmer’s tool kit.
As a kernel, capable of executing the basic inner kernel loop, SIMPL may be coded in about 300 bytes on most small processors such as the MSP430 – this includes the overhead of setting up the mcu, oscillator, UART and GPIO etc – so that it supports serial terminal interaction.
As more functions are added, the code size grows by approximately 16 bytes per function – so it’s possible to have a small but usable SIMPL running in about 1K bytes.
The users application code will further extend this by perhaps a similar amount – but it still has an extremely small footprint, making it an ideal serial command shell for resource limited processors.
SIMPL when coded in C has been ported to a number of microcontrollers including ATmega, ATtiny, ARM M4, and MSP430. The kernel has also been rewritten in MSP430 assembly language for speed and compactness, and work is ongoing to port it to the J1 Forth mcu.
The ability to encode the basic inner interpreter virtual machine in the native assembly language of a range of processors makes this a powerful technique of getting the basis of a useful “monitor” programme onto a variety of processors. It also means that once the kernel has been coded in the native assembly language, then the user is working with a common set of instructions running on the virtual machine, at a level somewhat higher than the native assembly. This creates a common language instruction set – a kind of “lingua franca” that makes interaction with a wide range of processors much easier. It also opens up the door for different processors to communicate with each other through this common character encoded language.
SIMPL has some of it’s roots in Forth, and indeed Charles Moore’s Forth language has been a source of inspiration for the development of SIMPL. However SIMPL is not a fully fledged language, more like a multi-function tool (Leatherman) which just makes the interpreted interaction with a range of small processors a lot easier, and less painful than the usual edit-compile-run cycle of code development found within a modern C compiler IDE.
Assembler and Instruction Set Decoder.
At it’s heart, SIMPL, when the kernel is coded in C, uses techniques such as switch-case statements and look-up table, or hash table to create the code address associated with the input character.
This technique allows not just a jump address to be associated with the character, but also other data, such as instruction look-up – for extending an 8 bit character into a longer instruction length – with individually coded bit-fields. This is the method used in generating J1 assembly language instructions from the common SIMPL command set. This is a form of microcoding and is a powerful technique used when writing assembly language for different target hosts. The (expanded instructions decoded in SIMPL can be written to RAM, creating the object code for the new target.
SIMPL also has uses in the automation of cpu simpulation. Any small cpu (with small instruction set) may be simulated in a few dozen lines of C code, and a processor model including memory, registers and ALU created. SIMPL commands can be used to create assembly instructions to test this model, single step through executable code runs and examine the results on a hex dump display that shows the memory contents and principal register contents. A full screen of serial data can be updated in less than 0.1 seconds – making single stepping more productive.
It is this processor simulation that I chose to explore next, and my target cpu will be one of the earliest processors – the 1949 EDSAC – built at Cambridge university.
Fortunately the EDSAC had very few instructions and is well documented. On a less fortunate note, the machine uses an instruction set input via a 5 bit paper tape, which is somewhat different in order to the more familiar ascii character set, and uses “figure shift” and “letter shift” to access the various characters of the teleprinter keyboard. This means that serially typed ascii characters will have to go through a further layer of decode to turn them into the Murray coded characters as used on the Creed teleprinters of that time, and a further translation back again into ascii for output to a serial terminal. However these character translations can be done with simple look-up or switch-case statements.