Skip to content

Instantly share code, notes, and snippets.

Created February 2, 2016 00:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/a5bf920f42da5d2c44cc to your computer and use it in GitHub Desktop.
Save anonymous/a5bf920f42da5d2c44cc to your computer and use it in GitHub Desktop.
32bit version of SIMPL "Serial Interpreted Minimal Programming Language"
// SIMPL
// A Serial Interpreted Minimal Programming Language
// Inspired by Txtzyme - by Ward Cunningham
// Ken Boak 2013 - 2016
// Filename simpl_2015_32bit_list8
// Requires UART routines - compiles on Arduino 1.04
// This is the slim version of simpl that removes all of the Arduino specific routines
// setup() and loop() removed - but there was a problem with the millisecond delay() without loop()
// This version can do maths and print out a 32 bit integer plus some 32bit arithmetic and timing functions
// 32bit support pushes codesize up by about 624 bytes - as all math routines now are 32 bit - including * / and % which eat memory
// This 32 bit SIMPL compiles in under 2892 bytes - leaving lots of room for other stuff
// The 16 bit version is just 2268 bytes
// The core kernel is only 2k bytes
// SIMPL allows new words to be defined by preceding them with colon : (Like Forth)
// New words use CAPITALS - so 26 words are possible in the user's vocabulary
// Words A-F have been predefined as musical tones - but you can write over them
// A word can be a maximum of 48 characters long
// Type ? to get a list off all defined words
#define F_CPU 16000000UL // define the clock frequency as 16MHz
#define BAUD 115200
#include <util/setbaud.h> // Set up the Uart baud rate generator
#include <uart.h>
// MACRO for a 62.5nS delay
#define NOP __asm__ __volatile__ ("nop\n\t")
#define bufRead(addr) (*(unsigned char *)(addr))
#define bufWrite(addr, b) (*(unsigned char *)(addr) = (b))
// This character array is used to hold the User's words
char array[26][48];
/* // Include the following array if you wish to initialise the memory with musical tones etc
= { // Define a 26 x 48 array for the colon definitions
{"6d40{h1106ul1106u}"}, // Musical tones A - G
{"6d45{h986ul986u}"},
{"6d51{h929ul929u}"},
{"6d57{h825ul825u}"},
{"6d64{h733ul733u}"},
{"6d72{h690ul691u}"},
{"6d81{h613ul613u}"},
{"_Hello World, and welcome to SIMPL_"},
{"5{ABC}"},
{""},
{""},
{""},
{"_This is a test message - about 48 characters_"}
};
*/
int a = 0; // integer variables a,b,c,d
int b = 0;
int c = 0;
int d = 6; // d is used to denote the digital port pin for I/O operations
// int d =13; // d is used to denote the digital port pin for I/O operations Pin 13 on Arduino
unsigned long x = 0; // Three gen purpose variables - Uncomment for 32 bit version
unsigned long y = 0;
unsigned int z = 0;
// unsigned int x = 0; // Three gen purpose variables - Uncomment for 16 bit version
// unsigned int y = 0;
// unsigned int z = 0;
unsigned char in_byte;
int len = 48; // the max length of a User word
long old_millis=0;
long new_millis=0;
long D_num = 0;
long D_val = 0;
long D_decade = 0;
char name;
char digit = 0;
char num_buf[11]; // long enough to hold a 32 bit long
char* parray;
char buf[64];
char* addr;
unsigned int num = 0;
unsigned int num_val = 0;
int j, w;
int decade = 0;
// -----------------------------------------------------------------------------------
// Setup the various arrary and initialisation routines
//void setup()
main()
{
// Enable UART
uart_init();
DDRD = DDRD | B11111100; // Sets pins 2 to 7 as outputs without changing the value of pins 0 & 1, which are RX & TX
DDRB = DDRB | B11111111; // Port B (Pin 9 - 13) is also output
PORTB &= B11111110; // Set pin 8 low
parray = &array[0][0]; // parray is the pointer to the first element
// -----------------------------------------------------------------------------------
//void loop() // This is the endless while loop which implements the interpreter - just 3 simple functions
while(1)
{
textRead(buf, 64); // Get the next "instruction" character from the buffer
textChk(buf); // check if it is a : character for beginning a colon definition
textEval(buf); // evaluate and execute the instruction
}
}
// ---------------------------------------------------------------------------------------------------------
// Functions
void textRead (char *p, byte n)
{
byte i = 0;
while (i < (n-1)) {
// while (!Serial.available());
char ch = u_getchar(); // get the character from the buffer
if (ch == '\r' || ch == '\n')
break;
if (ch >= ' ' && ch <= '~') {
*p++ = ch;
i++;
}
}
*p = 0;
}
// ---------------------------------------------------------------------------------------------------------
void textChk (char *buf) // Check if the text starts with a colon and if so store in temp[]
{
if (*buf == ':') {
char ch;
int i =0;
while ((ch = *buf++)){
if (ch == ':') {
u_putchar(*buf); // get the name from the first character
u_putchar(10);
u_putchar(13);
name = *buf ;
buf++;
}
bufWrite((parray + (len*(name-65) +i)),*buf);
i++;
}
x = 1;
}
}
// ---------------------------------------------------------------------------------------------------------
void textEval (char *buf) // Evaluate the instructiona and jump to the action toutine
{
long k = 0;
char *loop;
char *start;
char ch;
while ((ch = *buf++)) {
switch (ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
x = ch - '0';
while (*buf >= '0' && *buf <= '9') {
x = x*10 + (*buf++ - '0');
}
break;
case 'p': // print integer
printlong(x);
break;
case 'q': // print integer with crlf
printlong(x);
crlf();
break;
/*
case 'a':
a = x;
break;
*/
case 'b':
// printlong(millis());
crlf();
break;
case 'c':
// printlong(micros());
crlf();
break;
case 'd':
d = x;
break;
//--------------------------------------------------------------------------
// I/O Group
case 'h':
PORTD |= B01000000; // Set bit 6 high
break;
case 'l':
PORTD &= B10111111; // Set bit 6 low
break;
//-------------------------------------------------------------------------------
// User Words
case 'A': // Point the interpreter to the array containing the words
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
name = ch - 65;
addr = parray + (len*name);
textEval(addr);
break;
//----------------------------------------------------------
// Memory Group
case '!': // store
y = x;
break;
case '@': // fetch
x = y;
break;
//----------------------------------------------------------
// Arithmetic Group
case '+':
x = x+y;
break;
case '-':
x = x-y;
break;
case '*':
x = x*y;
break;
case '/':
x = x/y;
break;
case '%':
x = x%y;
break;
case 'x':
x = x + 1;
break;
case 'y':
y = y + 1;
break;
//--------------------------------------------------------------------
// Logical Group - provides bitwise logical function between x and y
case '&':
x = x&y; // Logical AND
break;
case '|':
x = x|y; // Logical OR
break;
case '^':
x = x^y; // Logical XOR
break;
case '~':
x = !x; // Complement x
break;
//--------------------------------------------------------------------
// Comparison Test and conditional Group
case '<':
if(x<y){x=1;} // If x<y x= 1 - can be combined with jump j
else x=0;
break;
case '>':
if(x>y){x=1;} // If x>y x= 1 - can be combined with jump j
else x=0;
break;
case 'j': // test if x = 1 and jump next instruction
if(x==1){*buf++;}
break;
//----------------------------------------------------------------------------------
// Byte wide output
/*
case 'n': // Output an 8 bit value on I/O Dig 2 - Dig 9
// Can be extended to 12 bits on Dig 2 - Dig 13
if(x>=128){digitalWrite(9,HIGH); x = x- 128;} else {digitalWrite(9,LOW);}
if(x>=64){digitalWrite(8,HIGH); x = x- 64;} else {digitalWrite(8,LOW);}
if(x>=32){digitalWrite(7,HIGH); x = x- 32;} else {digitalWrite(7,LOW);}
if(x>=16){digitalWrite(6,HIGH); x = x- 16;} else {digitalWrite(6,LOW);}
if(x>=8){digitalWrite(5,HIGH); x = x- 8;} else {digitalWrite(5,LOW);}
if(x>=4){digitalWrite(4,HIGH); x = x- 4;} else {digitalWrite(4,LOW);}
if(x>=2){digitalWrite(3,HIGH); x = x- 2;} else {digitalWrite(3,LOW);}
if(x>=1){digitalWrite(2,HIGH); x = x- 1;} else {digitalWrite(2,LOW);}
break;
*/
//----------------------------------------------------------------------------------
// Print out the current word list
case '?': // Print out all the RAM
parray = &array[0][0]; // reset parray to the pointer to the first element
for (int j = 0; j<26; j++) {
u_putchar(j+65); // print the caps word name
u_putchar(32); // space
for (int i=0; i<len; i++) {
in_byte = bufRead( parray + (j *len )+i); // read the array
u_putchar(in_byte); // print the character to the serial port
}
crlf();
}
for(int i = 0; i <11; i++) // add some spaces to make it more legible on the page
{
crlf();
}
break;
//----------------------------------------------------------------------------------------------------
// Added 15-2-2015 - all appears to be working
case '[': // The start of a condition test
k = x;
start = buf; // remember the start position of the test
while ((ch = *buf++) && ch != ']') { // get the next character into ch and increment the buffer pointer *buf - evaluate the code
}
case ']':
if (x) { // if x is positive - go around again
buf = start;
}
break;
//--------------------------------------------------------------------------------------------------
case '.':
while ((ch = *buf++) && ch != '.') {
// Serial.print(ch);
name = ch - 65;
addr = parray + (len*name);
while ((ch = *addr++) && ch != '.') {
u_putchar(ch);
}
}
crlf();
break;
// txtEval(addr);
// break;
case ' ': // Transfer x into second variable y
k=y; // Transfer loop counter into k
y= x;
break;
case '$': // Load x with the ASCII value of the next character i.e. 5 = 35H or 53 decimal
x=*(buf-2);
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------
// Analogue and Digital Input and Output Group
case 'a':
// analogWrite(d,x);
break;
case 's':
// x = analogRead(x);
break;
case 'i':
// x = digitalRead(d);
break;
case 'o':
// digitalWrite(d, x%2);
break;
//----------------------------------------------------------------------------------------------------------
// Timing and Delays Group
case 'm':
delay_mS(x);
break;
case 'u':
delay_uS(x);
break;
//----------------------------------------------------------------------------------------------------------
// 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;
case '_':
while ((ch = *buf++) && ch != '_') {
u_putchar(ch);
}
crlf();
break;
//---------------------------------------------------------------------------------------
// Select some code from a list separated by commas
//5(0p,1p,2p,3p,4p,5p,6p) should select 5 and print it
case '(':
k = x; // copy x to use as the "phrase counter"
// decrement k to see whether to interpret or not
while (k)
{
ch = *buf++;
if (ch == ',')
{ k--;}
}
break;
case ',':
k--; //
while (k<0) // k < 0 so skip the remaining entries in the list
{
ch = *buf++; // skip the remaining characters
if (ch == ')') {break;}
}
break;
//--------------------------------------------------------------------------------------
case 't':
// printlong(micros());
break;
case 'z': // z is a non-blocking pause or nap - measured in "zeconds" which allows UART characters,
// old_millis = millis(); // get the millisecond count when you enter the switch-case
printstring("waiting for escape");
// Serial.println("Got a char");
ch = u_getchar();
printstring("Got a £");
// Put the idle loop and escape code here
if(ch=='£')
{
printstring("Escape");
break;
}
// interrupts or digital Inputs to break the pause
// Serial.println(millis());
// break;
}
}
if(*buf == 0)
{
u_putchar(111); //ok followed by crlf
u_putchar(107);
u_putchar(10);
u_putchar(13);
}
}
//--------------------------------------------------------------------------------------
// UART Routines
//--------------------------------------------------------------------------------------
void uart_init(void)
{
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= _BV(U2X0);
#else
UCSR0A &= ~(_BV(U2X0));
#endif
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */
}
void u_putchar(char c) {
loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
UDR0 = c;
}
char u_getchar(void) {
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
return UDR0;
}
//-----------------------------------------------------------------------------------------
// Print a 16 bit int number
// Put a Number
static void printlong(unsigned short num) {
if (num / (unsigned short)10 != 0) printlong(num / (unsigned short)10);
u_putchar((char)(num % (unsigned short)10) + '0');
return;
}
//----------------------------------------------------------------------------------------------------------
// Print a string
void printstring(char *buf)
{
}
//----------------------------------------------------------------------------------------------------------
// Print a CR-LF
void crlf(void) // send a crlf
{
u_putchar(10);
u_putchar(13);
}
//---------------------------------------------------------------------------------------------------------
// Print OK
void OK(void) // send OK crlf
{
u_putchar('O');
u_putchar('K');
u_putchar(10);
u_putchar(13);
}
//---------------------------------------------------------------------------------------------------------
// Generate a multiple uS delay
void delay_uS(int w)
{
int k;
for(k = 0; k <= w; k++)
{
NOP;
}
}
//---------------------------------------------------------------------------------------------------------
void delay_mS(int z)
{
for(j = 0; j <= z; j++)
{
delay_uS(1000); // 1000 us delay
}
}
//------------------------------------That's All Folks!-------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment