Close
0%
0%

SIMPL

Serial Interpreted Minimal Programming Language
for exploring microcontrollers & new cpu architectures

Similar projects worth following
SIMPL is a very small, interpreted language for interactive communication and control of resource limited microcontrollers and experimental cpu architectures.

Most small, flash based mcus have a Harvard architecture so can only execute code directly out of flash. The SIMPL virtual machine allows VM code to be directly executed out of RAM.

The user can interactively modify the code in RAM, thus changing the program function, without re-flashing. For example:

13d10{h100ml200m} - that is all that is required to flash a LED on pin 13, 10 times, 100mS on 200mS off.

SIMPL provides an interactive programming environment, much smaller than either BASIC or Forth was for the early 8-bit home computers.

SIMPL has been inspired by others, with extra features added as part of my own personal exploration, and hopefully these project logs will encourage and inspire others to look at low level languages.

In short, SIMPL is intended to be an educational project.


SIMPL - a Tiny Interactive  Language for Microcontrollers or Experimental CPUs.

SIMPL is a symbolic language for programming microcontrollers based on printable ascii characters.

Each character, read in turn from RAM is interpreted and forms either an instruction, or a jump to an executable block of code, running on a virtual machine. The virtual machine is assumed to have a 16-bit wordsize and a 64Kbyte address space.

For example + will perform a 16-bit addition on the top two elements of the stack, whereas p will take the top element of the stack and print it to the terminal as a 16-bit decimal number.

In each case, the character is used in a look-up table or switch-case structure, to generate a unique jump to a block of code in ROM, which performs the command action.

Characters can be chosen by the programmer to have a strong mnemonic value,  such as +  for ADD and p for PRINT. Reducing these instructions to single characters makes the language very concise.

Thus SIMPL provides a shorthand means to communicate with a microcontroller or other computing device using an interactive command shell.  This allows control the microcontroller and its harware peripherals using short snippets of code, or "microscripts"  typed at the keyboard, or sent as a text file from a terminal emulator.

The interpreter can be pointed to any location in memory to begin parsing SIMPL code from there.  Any location in memory containing a valid, printable ascii character (ascii  $20 to $7E) will result in a jump to a legitimate code block, or trapped as an unused command.

In the case of commands typed from the keyboard, this memory will be an array in RAM that forms the Text Input Buffer (TIB). The code in the TIB will be executed immediately when the parser receives a carriage return character.  This is called Immediate Mode.

The interpreter may also be pointed to a location in RAM containing the User's program. It will begin execution there and will continue until it finds a non-printable ascii character.  This could be a carriage return or a null character.  This is called Run Mode.  A user program might be very short, or it might involve many nested loops - for example printing out a hex-dump of a block of memory.
 
A third mode of operation is possible, where SIMPL code is executed from ROM. This allows commonly used routines to be stored permanently in ROM. Again, the SIMPL code is likely to be more concise than the native assembly language of the microcontroller, as a single byte character represents an instruction or even a complete routine.

A SIMPL Example

SIMPL consists of short snippets of code, which I will call "microscripts".

A microscript consists of a series of commands, normally in lowercase alpha ascii characters, with numerical parameters to define the behaviour of the commands.

For example, to flash a LED on an Arduino, the microscript would be as follows:

13d10{h100ml100m}   - this gives 10 short 100mS flashes of the LED on pin 13

We cam modify this example easily - to play a tone on a small speaker connected to a digital pin. In this case we would use the microseconds delay command u contained within a loop.

8d1000{h500ul500u}   - this gives a 1kHz tone of 1 second duration to a small speaker connected to Digital Pin 8.

The microscripts give a great amount of flexibility, and as they are directly executed out of RAM, they can be edited "on the fly" and pasted back into the command line, to bring about an immediate change in function.

SIMPL was originally designed  to provide an easy means to control the common microcontroller peripherals (for example on Arduino) including UART, digital inputs and outputs, ADC, SPI, I2C etc. Parameters can be interactively passed to the peripheral driver routine, using a single character command to access that routine.  For example if user command S is used to call spi.transfer() SPI data can be sent directly...

Read more »

  • SIMPL on the Arduino

    monsonite2 days ago 2 comments

    Whilst I have discussed some of the wider aspects of SIMPL , I thought that it might be beneficial to take it back to its roots, as a simple sketch running on an Arduino Uno.

    SIMPL was inspired by Ward Cunningham's Txtzyme and it was his compact interpreter that provides an essential part of the evolution.

    Ward Cunningham's Txtzyme made good use of the lowercase alpha characters as a series of inbuilt commands designed to allow the hardware peripherals to be exercised. 

    This has been well documented in Ward's Txtzyme Github so won't be repeated here, needless to say that SIMPL has incorporated these commands and uses the same convention of lowercase alpha characters for inbuilt hardware functions.

    Deconstructing SIMPL

    SIMPL can be broken down into a few basic routines:

    Read a character from RAM                                                      txtRead

    Compare against colon character                                            txtChk

    Look up the character and execute associated code block  txtEval

    These 3 routines are enclosed in a tight loop and provide the Read-Evaluate-Print Loop 

    In Arduino the code is as follows:

    void loop()                // This is the endless while loop which implements the interpreter
    
    { 
      txtRead(buf, 64);        // Get the next "instruction" character from the buffer 
      txtChk(buf);             // check if it is a : character for beginning a colon definition 
      txtEval(buf);            // evaluate and execute the instruction 
    }

    Supporting these routines, are four others for handling the serial input and output and numerical conversion

    u_getchar       Get a character from the UART

    u_putchar       Send a character to the UART

    number           Read in a decimal numeric string and convert it into a 16-bit integer stored into a variable x

    printnum16      Print out the 16-bit decimal integer stored in x via the UART

    With just these 7 routines you have the fundamental building blocks to build the SIMPL kernel, and with this kernel create a framework from which the remainder of the application can be built.

    To keep the kernel codesize to a minimum, I have avoided the Arduino serial library. Instead I have used very compact UART code borrowed from AVR Freaks.

    As such, the 16-bit kernel fits into 1500 bytes.  With a change to printnum16 it can be modified to accept 32-bit integers. This pushes the code up to 1688 bytes.

    I have placed the 32-bit SIMPL kernel code in my SIMPL  Github repository.

    Extending the Kernel

    At this point, the kernel is very basic, - purposefully with very few functions.

    • You can enter a 32-bit decimal number, which is stored in a variable x  eg.   1234567890 enter
    • You can enter a 2nd decimal number separated by a space and it will be stored in variable y eg.  123456789 54321 enter
    • You can print out the value of x as a 32-bit decimal number using the p command  9876543210p
    • You can assign a 32-bit number to any of the user functions A-Z, using the colon command  :A2468013579 and print it later using the p command  Ap
    • You can use the ? command to list all of the User Commands A-Z and see if any value or code has been allocated to them.

    Maths Operations

    The obvious extension to the kernel is to add the maths functions, addition, subtraction, multiplication and division. 

    It is necessary to provide the means for a second parameter, y.  Txtzyme only allows one parameter x.

    Providing a second variable to hold  the y parameter makes arithmetic and logic operations possible.

    When a number is entered, it automatically is placed in the x variable. By inserting an ascii space invokes a transfer of the first number...

    Read more »

  • SIMPL as an Instruction Set

    monsonite01/16/2021 at 22:26 0 comments

    As stated earlier, SIMPL will run on a microcontroller or other processor device using an interpreter which forms the basis of a Virtual Machine, which I have chosen to call a SIMPL Machine.

    The SIMPL Machine uses printable ascii characters to create a concise, human readable language.

    For convenience the printable ascii are divided into 4 sub-sets:

    Numbers  0-9  A numerical string will be converted to a 16-bit integer in the range 0-65535

    Lowercase  a-z   Lowercase alpha characters are generally used to call ROM based functions for printing and control of I/O

    Uppercase A-Z  Uppercase alpha characters are generally used for user defined commands, variables and registers

    Symbols     + - * /  etc.  These 33 symbols are used to define the primitive instructions and structures for the SIMPL Machine language.

    It is the symbol and punctuation characters which will be used to define the Instruction Set, along the lines of the MISC machines developed by CH Ting and CH Moore.

    The SIMPL instruction set is concise because each command is a single ascii character. 

    It takes the form of human readable shorthand which removes the need to memorise hex codes or processor specific instruction mnemonics. Traditional assembly language frequently uses mnemonics that are 3 characters long,  ADD, SUB, AND XOR.

    Note: Although each instruction is represented by a single character. If however a more traditional listing were required it would be an easy programming exercise to substitute the character for a more conventional mnemonic. 

    SIMPL replaces these with single characters which minimises the text and vastly simplifies the overheads of parsing multi character text.

    Source code is much more compact than traditional assembly language.  It can be loaded directly into RAM - either by typing or using the Send File feature of most terminal emulator programs.

    SIMPL could become a lingua franca for microcontrollers or microprocessors.

    Provided that the SIMPL VM was coded into the target cpu, whether AVR, ARM, Z80 or 6502 etc. the same SIMPL source code will run on any of the machines.  It forms a universal assemby language and could be used to replace cpu specific mnemonics and assembly listings.

    Instruction Primitives.

    These are allocated to the 33 printable ascii symbols.  They provide arithmetic, logic and comparison operations as well as memory and register access, looping and program flow control. 

    Using the concept of a Minimal Instruction Set Computer  (MISC) a complete machine can be created with fewer than 32 primitive instructions. 

    There have been several historical machines that illustrate this concept - such as the PDP-8, the MSP430, Marcel van Kervinck's Gigatron TTL computer and several of the Forth cpus by Charles H. Moore. 

    The SIMPL VM is based on a stack machine with a 4 level circular stack. Most operations operate on the top 2 elements of the stack.

    Arithmetical and Logical Operations 

    +       ADD

    -        SUB

    *        MUL (Left Shift)

    /        DIV   (Right Shift)

    &       AND

    |         OR

    ^        XOR

    ~        NOT

    `         INCREMENT

    Memory Access

    @       FETCH

    !         STORE

    Stack Manipulation

    "         DUP

    '          DROP

    $         SWAP

    %        OVER

               SPACE - used to PUSH consecutive numbers onto the stack

    Conditional / Comparison 

    <         LESS

    >         GREATER

    =         EQUAL

    Input / Output

    .   ...

    Read more »

  • More about the SIMPL Project

    monsonite01/15/2021 at 15:06 0 comments

    SIMPL - is the acronym for Serial Interpreted Minimal Programming Language.

    SIMPL is an extensible language allowing it to grow to suit the requirements of the application.

    In this project: 

    • I will explain the programming concepts and the minimalist philosophy behind SIMPL.
    • I will show how the kernel is built from a few basic routines
    • There will be example code given for implementations on Arduino and MSP430
    • I will investigate how SIMPL can be ported to custom CPUs, existing as a simulation or as a soft-core implemented on an FPGA
    • I will explore the concept of the SIMPL Machine - a CPU architecture optimised for running SIMPL as it's native instruction set.
    • I will show how the SIMPL framework can be used as the basis for several applications.

    A 2 minute Introduction to SIMPL.

    The following brief example shows how SIMPL allows you to flash a blinky LED on an Arduino or similar. The Arduino is loaded with the SIMPL kernel and connects via the serial terminal, allowing commands, shown in bold,  to be typed. 13 d            First we identify that we want to use the LED attached to digital pin 13 using the d command.  1 o              The o command allows us to send either a LOW or HIGH to the selected pin 12 - 1o turns the LED on,  0o turns it off

    1000 m      We use the m command to initiate a millisecond delay in this case 1000 mS 

    10{...........}   We  create a loop using curly braces - in this case the contents of the braces will be repeated 10 times Now we put it all together as a microscript

    13 d 10 {1o 1000m 0o 1000m}   This will flash the LED 10 times ON for 1 second and OFF for 1 second

    13d10{1o1000m0o1000m}         But the spaces were only for clarity - they can be omitted. We can edit the delay periods to create different on and off times: 13d10{1o200m0o100m}            200mS on and 100mS off Or we can alternatively use the microsecond delay command u to generate audio tones into a small speaker

    13d1000{1o500u0o500u}    This will generate 1 second of 1kHz tone But SIMPL is extensible - if we like the 1kHz beep, we can allocate a user command to it -  for example B for Beep

    We do use this using colon : and semicolon ; to define our new command

    :B13d1000{1o500u0o500u};

    Every time B is typed a tone will be generated.

    BBBB    Generate 4 seconds of tone

    Now create a higher tone and call it C

    :C13d1200{1o400u0o400u}; 

    CBCBCBCB  Generate an alternating siren sound. 

     We have created a sound effect using a few numerical parameters  and a few ascii characters as commands  d  o  m  u  {  } :  and  ;  Three conventions are used: Lowercase characters a-z are used for pre-programmed commands that are generally coded into the Flash ROM

    Uppercase characters A-Z are generally used for User Defined commands (microscripts) or variables that are stored in RAM

    Punctuation characters and other symbols are used for arithmetic and logical operations and program flow such as looping.

    How SIMPL Works

    A small program flashed into ROM provides the serial interface and command interpreter.

    Every ascii character read in, causes the interpreter to jump to a unique block of code which executes the command action before returning to the interpreter to read in the next character.

    This very simple interpreter has amazing flexibility and can be tailored to suit the requirements of a wide variety of applications such as CNC (plotters, 3D printers, routers, laser cutters), robotics, hardware control etc. 

    The microscripts...

    Read more »

  • Implementing the SIMPL Machine.

    monsonite01/14/2021 at 22:19 0 comments

    The previous log The SIMPL Machine, looked at how the J1 Forth CPU simulation could be used as the basis of a cpu targeted to execute the SIMPL language. 

    Here are some notes regarding the implementation on the Teensy 4.0

    A switch-case structure will translate the SIMPL ascii character commands into 16-bit instructions to feed the J1 cpu simulated cpu.

    I took the SIMPL text interpreter framework and mapped into it the J1 instructions, focusing initially on the stack, ALU and memory operations – listed below

    SIMPL               Operation                J1 hex code
    
    ”                   DUP                      6081
    
    ‘                   DROP                     6183
    
    $                   SWAP                     6180
    
    %                   OVER                     6181
    
    +                   ADD                      6203
    
    &                   AND                      6303
    
    |                   OR                       6403
    
    ^                   XOR                      6503
    
    ~                   INV                      6600
    
    @                   FETCH                    6C00
    
    !                   STORE                    6123

  • The SIMPL Machine

    monsonite01/14/2021 at 12:28 0 comments

    In the previous log it was identified that SIMPL would be hosted as a virtual machine running from ROM on the chosen microcontroller.

    In this log I explore the practicalities of creating a simulated stack machine running on a Teensy 4.0 and programmed using the Arduino IDE.

    The aim is to run SIMPL on a virtual machine with a minimum instruction set with fewer than 32 primitive instructions, in order to keep the complexity down.

    As SIMPL is based around a 16-bit wordsize and a 16-bit address space, it will be a better fit to a machine that has a native 16-bit architechture. For this reason, much of the early exploration of SIMPL has been done on the MSP430 range of 16-bit microcontrollers, rather than the 8-bit AVR devices.

    I stated in the last log that the SIMPL machine would be based on a stack architecture.

    Unfortunately there are very few stack machines available as almost every modern microcontroller has a register based design. A large set of registers are almost essential for the efficient implementation of a high-level language such as C.

    With no stack machines readily available, we need to create our own stack structures in software, either on an existing microcontroller,  as a simulation, or on a soft core design on an FPGA.

    This provides 3 options which I wish to explore in turn.

    1. Use an MSP430 16-bit microcontroller to implement the SIMPL machine
    2. Simulate the SIMPL machine on a high performance 600MHz ARM Cortex M7 using a $20 Teensy 4.0
    3. Implement the SIMPL machine as a soft core on an FPGA using verilog.

    Option 1  will be done using a low cost Launchpad development board. Fortunately Dr. ChenHanson Ting has written extensively about implementing his eForth system on an MSP430 so the mechanics of a stack machine have already been defined.

    Option 2 makes use of the low cost Teensy 4.0 board as a target machine. The Teensy 4 with it's 600MHz clock can readily simulate many of the early microprocessors at many times their original operating speed. 

    Option 3. Teensy 4 may also be used to simulate experimantal cpus with custom instruction sets. One of these is James Bowman's J1 Forth cpu which might make a suitable candidate for the SIMPL machine, as it has already been implemented and proven in verilog on a Lattice ICE 40 FPGA.

    As the MSP430 implementation has been covered elsewhere, and the MSP430 performance is somewhat limited by modern ARM standards, I intend to explore Options 2 and 3, with a software simulation of the J1 Forth cpu providing experience that will be directly relevant to the FPGA implementation.

    The J1 Forth CPU

    In 2010 James Bowman created a simple 16-bit stack machine that was targeted at executing the Forth language.  Since then it has been implemented in verilog and also as custom silicon that has found it's way into a number of graphics controller ICs by FTDI and their Singaporean silicon fabricators Bridgetek Pte.

    The J1 is described in this J1 2010 Euroforth Paper


    The J1 has a very compact instruction set, a minimal stack machine architechture  and can be described in fewer than 100 lines of C code or verilog. This makes it easy to understand and easy to implement on an FPGA using opensource tools.

    The J1 instruction word is 16-bits wide and the individual bit fields operate directly on the hardware without an intermediate layer of instruction decoding. 

    However, memorising 16-bit instructions is not easy, and an assembler or high level language is essential for program development. This is where I believe that SIMPL can be employed to advantage, as a human readable pseudo-code that allows interactive programming of the J1 - as an alternative to assembly language or Forth.

    The J1 Architecture.

    Having read James Bowman’s J1 Paper several times over, I managed to build up a simplified model of his instruction set and architecture.

    J1 uses 16 bit long instruction words – where each word is divided into different length fields.

    The following 3 images...

    Read more »

  • SIMPL: A subset of Forth

    monsonite01/13/2021 at 15:19 0 comments

    As SIMPL evolved it became clear that the Txtzyme command interpreter with only 13 basic commands for exercising peripheral hardware could be developed further into a virtual machine with its own tailored instruction set. 

    From an early stage in development it was decided that the VM instructions would be single character printable ascii codes. This was done initially to make the language more human readable, and was well suited the serial terminal interface. 

    The extensions to Txtzyme allowed SIMPL commands to be executed from RAM, and each of these commands had an accompanying command action stored as inline code in the Flash ROM.

    This transition from instructions in RAM, executing blocks of code contained in ROM effectively released the microcontroller from the constraints of the Harvard architecture by using a Von Neumann virtual machine.

    SIMPL and Forth


    SIMPL has been greatly influenced by the Forth language developed by Charles H. Moore between 1958 and 1970. During the 1970s it was ported onto a wide range of minicomputers and microcomputers. It is a compact and extensible stack-based language.

    The stack based machine is the obvious candidate for executing the Forth language as it matches the needs of the Forth machine model.

    As SIMPL is a subset of Forth, it would seem sensible to make the SIMPL VM a stack based architecture.

    Traditionally Forth was based around a 16-bit wordsize and a 16-bit addressing range that was commonplace amongst mini computers in the 1970s.  

    Chuck Moore and Dr. C.H. Ting worked together in the 1990s to create a minimal instruction set computer (MISC) which could efficiently execute Forth primitive instructions. Moore and Ting identified that Forth could be effectively synthesised from 32 or fewer primitive instructions.
    Chen-Hanson Ting developed an eForth model, which was a formal specification for a Forth, implemented from a set of 32 primitives.

    Chuck Moore took on the hardware design challenge of MISC Forth processors, and developed a series of designs characterised by small instruction sets and minimal hardware.

    A full sized Forth implemantation would typically be around 6K bytes.

    SIMPL proposes the use of a stack-based virtual machine, implementing a small number of primitive instructions which allow an extensible language to be created. It is suggested that the SIMPL machine can be inplemented in about  1 to 2K bytes of Flash memory depending on the target microcontroller.

    Forth on an 8-Bit AVR

    A tiny Forth with 28 primitives may be implemented in about 2K bytes of AVR assembly language. This implementation is by T. Nakagawa of Japan.

    To implement Forth on an 8-bit AVR microcontroller requires an average of about 10 AVR assembly language instructions to implement each primitive.  There is also the overhead of the interpreter. This slows the execution speed down by a factor of 10 or 20. On the 20MHz AVR this corresponds to about 1 million Forth instructions per second (FIPS). 

View all 6 project logs

Enjoy this project?

Share

Discussions

monsonite wrote 21 hours ago point

Owen,

SIMPL has been highly influenced by Forth, and it is evolving into a subset of Forth.  Forth is typically 6 to 8k bytes if written in assembly language, perhaps double this if written in C. I hope that SIMPL will be under 4k bytes when written in C.

I wanted something quick and dirty that could easily be ported between microcontrollers. Once you get past "Hello World" or flashing a LED with a new microcontroller, you want something that allows you to quickly try out ideas, without the tedious Edit-Compile-Flash work flow.

SIMPL hopefully provides the means to accelerate you quickly past the LED flashing breakthrough.

It's been a work in progress since May of 2013, when I first stumbled across Ward Cunningham's Txtzyme.  I hope to use this latest  phase of lockdown to explore some more ideas and to formalise the language.

For the first few project logs, I am going to use a standard Arduino Uno as a target board. Everybody has some sort of access to an Arduino - and it allows new code to be tested out quickly.

Unfortunately the Arduino built in language functions are fairly verbose,  setup(), loop(), digital read/write and the serial library add hundreds of unnecessary bytes to the interpreter code.  This can be addressed later, as SIMPL is currently just a proof of concept.

  Are you sure? yes | no

Owen wrote 5 days ago point

The ability to rapidly write a SIMPL interpreter in C or assembly for a _fresh_ micro is probably what sets this apart from almost everything else.

Doing a "port" to any platform would be a simple exercise, and would allow customisation on the way, for example, to add SPI/I2C support, or commands for an unusual on-chip (or external) peripheral.

Couple of comments (I did not see the answers by reading through - might well have missed them)…

1 - An infinite loop invoked by having zero as the loop count, eg 0{1o0o}

But how to break out? Look for a serial port interrupt? Do a hard reset?

2 - Instead of interpreting a line received over serial, perhaps a command that inserts the line into RAM, another command to execute? Extend that to support multiple lines.

A program could be structured from various :; blocks defined first up (subroutines), then the functional code uses those macros to execute a 'program'.

I don't know how this would work in practice. How would you identify one line from a bunch of lines? For example to change a parameter or fix a typo? It starts to get difficult.

However, this is probably stepping away from your original project goal of a quick interpreter meant to allow a hardware designer to test his circuit...

  Are you sure? yes | no

monsonite wrote 5 days ago point

Hi Owen - thankyou for your questions...... I hope the following answers are of help.

A zero loop 0{.........} will never be executed

0 {_Have a nice day Owen_}  will never be executed - so is actually a comment

But 1 {_Have a nice day Owen_}  will produce a serial output  "Have a nice day Owen"

any process that leaves a logic 1 before a loop  {........} will result in that code being executed - such as a digital input that returns a 1.

The text interpreter is invoked by the carriage return and will end when the code is finished.

Eg:    100{kp}  will print from 100 to 0 and then end. There is no CTRL-C break out (yet)

The interpreter can be pointed to anywhere in RAM and execute the code that it finds there. If you have a terminal emulator with "send file"  you can send a whole stream of executable code to SIMPL.

I will put an example up on Github that shows what can be done - using Arduino target.

However my main interest is a tiny language for experimental cpus - existing only as a simulation in C or as a softcore on an FPGA.

  Are you sure? yes | no

Owen wrote a day ago point

Thanks for your response.

I can see the logic behind a zero loop 0{…} which makes perfect sense.

I've wasted so much time over the years writing use-once, throw-away, write-again-for-another-device code snippets to test the functionality of new hardware! SIMPL would have made it _so_ much easier.

Although I don't have a use for SIMPL at the moment, it is a great project, and at some stage I'll no doubt end up coming back and porting it to some piece of hardware I've just made.

Cheers


  Are you sure? yes | no

marazm wrote 01/12/2021 at 16:43 point

Why using simply language if You have mruby?

  Are you sure? yes | no

monsonite wrote 01/12/2021 at 16:52 point

SIMPL can be written for any of the smallest microcontrollers with 2k bytes of Flash ROM and 512 bytes of RAM.

It requires nothing more than a serial terminal to communicate with the mcu.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates