Created
September 21, 2015 21:34
-
-
Save monsonite/e5f618a7b094585e1d59 to your computer and use it in GitHub Desktop.
32bit math SIMPL Serial Interpreted Minimal Language - for Arduino &ct
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SIMPL | |
// A Serial Interpreted Minimal Programming Language | |
// Inspired by Txtzyme - by Ward Cunningham | |
// Filename simpl_2015_slim_11 | |
// This is the slim version of simpl that removes most of the Arduino specific routines - saving almost 1800 bytes | |
// In Version 10: Added printlong() to print out a 32 bit integer plus some 32bit arithmetic and timing functions | |
// 32bit support pushes codesize up by about 1Kbytes - as all math routines now are 32 bit | |
// Some fixed "Musical Tones" | |
// 40{1o1106u0o1106u} // A 440 Hz | |
// 45{1o986u0o986u} // B 493.88 Hz | |
// 51{1o929u0o929u} // C 523.25 Hz | |
// 57{1o825u0o825u} // D 587.33 Hz | |
// 64{1o733u0o733u} // E 659.26 Hz | |
// 72{1o690u0o691u} // F 698.46 Hz | |
// 81{1o613u0o613u} // G 783.99 HZ | |
// This 32 bit SIMPL compiles in under 5090 bytes - leaving lots of room for other stuff | |
// 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 | |
#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] = { // Define a 26 x 48 array for the colon definitions | |
{"6d40{h1106ul1106u}"}, | |
{"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 | |
unsigned long y = 0; | |
unsigned int z = 0; | |
unsigned char bite; | |
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* parray; | |
char buf[64]; | |
char* addr; | |
unsigned int num = 0; | |
unsigned int num_val = 0; | |
int j; | |
char num_buf[11]; // long enough to hold a 32 bit long | |
int decade = 0; | |
char digit = 0; | |
//void setup() | |
int main() | |
{ | |
// ----------------------------------------------------------------------------------- | |
// Setup the various arrary and initialisation routines | |
// This replaces setup() | |
// 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 | |
parray = &array[0][0]; // parray is the pointer to the first element | |
// ----------------------------------------------------------------------------------- | |
while(1) // 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 | |
} | |
} // End of main() | |
// --------------------------------------------------------------------------------------------------------- | |
// Functions | |
void txtRead (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 txtChk (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 txtEval (char *buf) // Evaluate the instructiona and jump to the action toutine | |
{ | |
unsigned 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': | |
printlong(x); | |
crlf(); | |
break; | |
case 'q': | |
printlong(x); | |
crlf(); | |
break; | |
/* | |
case 'a': | |
a = x; | |
break; | |
*/ | |
case 'b': | |
printlong(millis()); | |
break; | |
case 'c': | |
printlong(micros()); | |
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); | |
txtEval(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++) { | |
bite = bufRead( parray + (j *len )+i); // read the array | |
u_putchar(bite); // 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(x); | |
break; | |
case 'u': | |
delayMicroseconds(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; | |
//-------------------------------------------------------------------------------------- | |
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 | |
// while (!Serial.available()||millis()-old_millis<=(x*1000)) | |
// { } | |
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; | |
} | |
} | |
} | |
//-------------------------------------------------------------------------------------- | |
// 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 | |
/* | |
void printnum(int num) | |
{ | |
// num is likely going to be a 16 bit iunsigned int - so we are handling up to 5 digits | |
// We need to test which decade it is in - and convert the leading digit to ascii - remembering to suppress leading zeroes | |
num_val = num; // make a copy of num for later | |
// Extract the digits into the num_buff | |
decade = 10000; | |
for (j = 5; j>0; j--) | |
{ | |
z = num/decade; | |
num_buf[j]=z+48; | |
num = num - (decade*z); | |
decade = decade/10; | |
} | |
// Now print out the array - correcting to allow for leading zero suppression | |
if (num_val == 0) | |
{ | |
{num_buf[5] = 48;} | |
} | |
decade = 10000; // we need to know what decade we are in for leading zero suppression | |
j=5; | |
while(num_buf[j]!=0) | |
{ | |
if(num_buf[j] == 48 && (num_val <= decade)) {j--;} // suppress leading zeroes | |
else | |
{ | |
u_putchar(num_buf[j]); // send the number | |
num_buf[j]=0; // erase the array for next time | |
j--; | |
} | |
decade = decade/10; // update the decade | |
} | |
if(!num_val){u_putchar(48); } // separately handle the case when num == 0 | |
} | |
*/ | |
//---------------------------------------------------------------------------------------------------------- | |
// Print a string | |
void printstring(char *buf) | |
{ | |
} | |
//---------------------------------------------------------------------------------------------------------- | |
// Print a CR-LF | |
void crlf(void) // send a crlf | |
{ | |
u_putchar(10); | |
u_putchar(13); | |
} | |
//--------------------------------------------------------------------------------------------------------- | |
// Print a 32 bit integer | |
void printlong(long D_num) | |
{ | |
// num is likely going to be a 16 bit iunsigned int - so we are handling up to 5 digits | |
// We need to test which decade it is in - and convert the leading digit to ascii - remembering to suppress leading zeroes | |
D_val = D_num; // make a copy of num for later | |
// Extract the digits into the num_buff | |
D_decade = 1000000000; | |
for (j = 10; j>0; j--) | |
{ | |
z = D_num/D_decade; | |
num_buf[j]=z+48; | |
D_num = D_num - (D_decade*z); | |
D_decade = D_decade/10; | |
} | |
// Now print out the array - correcting to allow for leading zero suppression | |
if (D_val == 0) | |
{ | |
{num_buf[10] = 48;} | |
} | |
D_decade = 1000000000; // we need to know what decade we are in for leading zero suppression | |
j=10; | |
while(num_buf[j]!=0) | |
{ | |
if(num_buf[j] == 48 && (D_val <= D_decade)) {j--;} // suppress leading zeroes | |
else | |
{ | |
u_putchar(num_buf[j]); // send the number | |
num_buf[j]=0; // erase the array for next time | |
j--; | |
} | |
D_decade = D_decade/10; // update the decade | |
} | |
if(!D_val){u_putchar(48); } // separately handle the case when num == 0 | |
// crlf(); | |
u_putchar(10); | |
u_putchar(13); | |
} | |
//----------------------------------------------------------------------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment