Close

SIMPL on the Arduino

A project log for SIMPL

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

monsonitemonsonite 01/23/2021 at 16:282 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.

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 from x into y, and allows a second number to be entered.

123 456    this puts 123 into x, transfers it to y and then places 456 into x.

We can then add the operator to make addition possible:

123 456+p   ADD 123 to 456 and print it out as a decimal number.

We can now add the four common maths operations to the code.

 case '+':      x = x+y;      break;     //  ADD
 case '-':      x = x-y;      break;     //  SUB
 case '*':      x = x*y;      break;     //  MUL
 case '/':      x = x/y;      break;     //  DIV

This effectively forms the basis of a very simple 4 function calculator, but the printnum routine will have to be modified to handle negative numbers.  Adding these 4 functions pushes the codesize up to 1940 bytes.

So building upon the basic numerical input and output routines we add the maths functions and this makes simple calculations possible.

We can also add the logic operations:  AND, OR, XOR and INV:

case '&':      x = x&y;      break;     //  AND
case '|':      x = x|y;      break;     //  OR
case '^':      x = x^y;      break;     //  XOR
case '~':      x = ~x ;      break;     //  INV

Looping

One of the principle functions borrowed from Txtzyme is the looping structure. 

This introduces a new parameter k which is equal to the loop index counter. k is used to initiate the loop function and is decremented each time the interpreter executes the loop. 

The loop terminates  when k=0.  The code to be executed in the loop is contained within curly braces {...........}. If the loop counter k is set to zero, the code within the braces will never be executed - and this can be used to create inline comments, eg.    0{This is a comment}

Adding the looping control code increases the codesize to 2124 bytes

// Looping and program control group

    case '{':
      k = x;
      loop = buf;
      while ((ch = *buf++) && ch != '}') {
      }

    case '}':
      if (k) {
        k--;
        buf = loop;
             }
      break;
     
    case 'k':      x = k;      break;


SIMPL follows a subtley different approach to Txtzyme, whilst retaining basic functional compatibility.  SIMPL has been designed to provide an executable symbolic language for virtual machines - as an alternative to their native assembly language.

With arithmetic commands and the loop structure that allows conditional flow there is the basis of a simple virtual machine instruction set.

In the next log we will look at the options for implementing a virtual machine.

 

Discussions

Paul McClay wrote 01/24/2021 at 16:29 point

Ah. Thanks for expanding this. I didn't understand the x y syntax before.

I don't have an application right now but SIMPL looks like a tool that will find a use.

  Are you sure? yes | no

monsonite wrote 01/24/2021 at 17:32 point

Adding a second variable makes arithmetic and logic functions possible. It's a simplification of having a data stack, where one value is pushed down the stack to make room for a new value to be input. It's effectively a two level stack, which is about as simple as you can get.  If it were a full Forth, it would have many more levels. The next log will add further functions to take it from a four function desktop calculator to the equivalent of a small programmable cpu.

For the moment I will be using a standard Arduino Uno to illustrate the code.  If it can be written for an 8-bit microcontroller such as the ATmega328, it can be written for any other mcu.  Thanks for following.

  Are you sure? yes | no