#include <SD.h>
#include "StringHelper.h"
File file;
bool jump;
bool jumping;
bool running;
char label [10];
char fileName [16];
byte storage [64];
const char* const PROGMEM instructions [] = {
"j", "li", "lb", "sb", "beq", "bgt", "blt", "bge", "ble",
"add", "sub", "mul", "divu", "addi", "sll", "srl", "andi"
};
// Exits a program.
void exitProgram()
{
file.close();
running = false;
}
// Reserved storage handling.
void readFromStorage(uint8_t rd, uint8_t rs)
{
switch(rs)
{
case 1:
storage[rd] = 5 * (analogRead(A0) / 1023.0);
break;
case 2:
storage[rd] = 5 * (analogRead(A1) / 1023.0);
break;
case 3:
storage[rd] = DDRB;
break;
case 4:
storage[rd] = PINB;
break;
case 5:
storage[rd] = DDRD;
break;
case 6:
storage[rd] = PIND;
break;
case 7:
storage[rd] = DDRC;
break;
case 8:
storage[rd] = PINC;
case 9:
storage[rd] = 5 * (analogRead(A2) / 1023.0);
break;
case 10:
storage[rd] = 5 * (analogRead(A3) / 1023.0);
break;
case 11:
storage[rd] = 5 * (analogRead(A4) / 1023.0);
break;
case 12:
storage[rd] = 5 * (analogRead(A5) / 1023.0);
break;
default:
break;
}
}
// Reserved storage handling.
void writeToStorage(uint8_t rd)
{
if (rd == 1)
{
char c = (char)storage[1];
c = c == '[' ? ' ' : c;
c = c == ']' ? '\n' : c;
Serial.print(c);
}
else if (rd == 2)
{
Serial.print(storage[2]);
}
else if (rd == 3)
{
DDRB = storage[3];
}
else if (rd == 4)
{
PORTB = storage[4];
}
else if (rd == 5)
{
DDRD = storage[5];
}
else if (rd == 6)
{
PORTD = storage[6];
}
else if (rd == 7)
{
DDRC = storage[7];
}
else if (rd == 8)
{
PORTC = storage[8];
}
else if (rd == 9)
{
delayMicroseconds(storage[9]);
}
else if (rd == 10)
{
delay(storage[10]);
}
else if (rd == 11)
{
storage[11] = random(0, storage[11]);
}
else if (rd == 12)
{
exitProgram();
}
}
// jump
void j(char* line)
{
memset(&label[0], 0, sizeof(label));
uint8_t len = strlen(line);
subString(line, 2, len, label);
jump = true;
}
// load immediate
void li(char* line)
{
char* results [3];
splitString(results, line, " ", 3);
uint8_t rd = atoi(results[1]);
char* imm = results[2];
if (isAlpha(imm[0]))
{
storage[rd] = (byte)imm[0];
}
else if (imm[0] == '[' || imm[0] == ']')
{
storage[rd] = (byte)imm[0];
}
else
{
storage[rd] = (byte)atoi(imm);
}
writeToStorage(rd);
}
// load byte
void lb(char* line)
{
char* results [3];
splitString(results, line, " ", 3);
uint8_t rd = atoi(results[1]);
uint8_t rs = atoi(results[2]);
storage[rd] = storage[rs];
readFromStorage(rd, rs);
}
// store byte
void sb(char* line)
{
char* results [3];
splitString(results, line, " ", 3);
uint8_t rs = atoi(results[1]);
uint8_t rd = atoi(results[2]);
storage[rd] = storage[rs];
writeToStorage(rd);
}
// branch if equal
void beq(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rs1 = atoi(results[1]);
uint8_t rs2 = atoi(results[2]);
uint8_t val1 = storage[rs1];
uint8_t val2 = storage[rs2];
if (val1 == val2)
{
strcpy(label, results[3]);
jump = true;
}
}
// branch if greater than
void bgt(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rs1 = atoi(results[1]);
uint8_t rs2 = atoi(results[2]);
uint8_t val1 = storage[rs1];
uint8_t val2 = storage[rs2];
if (val1 > val2)
{
strcpy(label, results[3]);
jump = true;
}
}
// branch if less than
void blt(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rs1 = atoi(results[1]);
uint8_t rs2 = atoi(results[2]);
uint8_t val1 = storage[rs1];
uint8_t val2 = storage[rs2];
if (val1 < val2)
{
strcpy(label, results[3]);
jump = true;
}
}
// branch if greater than or equal to
void bge(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rs1 = atoi(results[1]);
uint8_t rs2 = atoi(results[2]);
uint8_t val1 = storage[rs1];
uint8_t val2 = storage[rs2];
if (val1 >= val2)
{
strcpy(label, results[3]);
jump = true;
}
}
// branch if less than or equal to
void ble(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rs1 = atoi(results[1]);
uint8_t rs2 = atoi(results[2]);
uint8_t val1 = storage[rs1];
uint8_t val2 = storage[rs2];
if (val1 <= val2)
{
strcpy(label, results[3]);
jump = true;
}
}
// add
void add(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rd = atoi(results[1]);
uint8_t rs1 = atoi(results[2]);
uint8_t rs2 = atoi(results[3]);
uint8_t val1 = storage[rs1];
uint8_t val2 = storage[rs2];
storage[rd] = val1 + val2;
writeToStorage(rd);
}
// subtract
void sub(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rd = atoi(results[1]);
uint8_t rs1 = atoi(results[2]);
uint8_t rs2 = atoi(results[3]);
uint8_t val1 = storage[rs1];
uint8_t val2 = storage[rs2];
storage[rd] = val1 - val2;
writeToStorage(rd);
}
// multiply
void mul(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rd = atoi(results[1]);
uint8_t rs1 = atoi(results[2]);
uint8_t rs2 = atoi(results[3]);
uint8_t val1 = storage[rs1];
uint8_t val2 = storage[rs2];
storage[rd] = val1 * val2;
writeToStorage(rd);
}
// divide unsigned
void divu(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rd = atoi(results[1]);
uint8_t rs1 = atoi(results[2]);
uint8_t rs2 = atoi(results[3]);
uint8_t val1 = storage[rs1];
uint8_t val2 = storage[rs2];
storage[rd] = val1 / val2;
writeToStorage(rd);
}
// add immediate
void addi(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rd = atoi(results[1]);
uint8_t rs = atoi(results[2]);
uint8_t imm = atoi(results[3]);
uint8_t valS = storage[rs];
storage[rd] = valS + imm;
writeToStorage(rd);
}
// shift left
void sll(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rd = atoi(results[1]);
uint8_t rs1 = atoi(results[2]);
uint8_t rs2 = atoi(results[3]);
uint8_t val1 = storage[rs1];
uint8_t val2 = storage[rs2];
storage[rd] = val1 << val2;
writeToStorage(rd);
}
// shift right
void srl(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rd = atoi(results[1]);
uint8_t rs1 = atoi(results[2]);
uint8_t rs2 = atoi(results[3]);
uint8_t val1 = storage[rs1];
uint8_t val2 = storage[rs2];
storage[rd] = val1 >> val2;
writeToStorage(rd);
}
// AND Immediate
void andi(char* line)
{
char* results [4];
splitString(results, line, " ", 4);
uint8_t rd = atoi(results[1]);
uint8_t rs = atoi(results[2]);
uint8_t imm = atoi(results[3]);
uint8_t valS = storage[rs];
storage[rd] = valS & imm;
writeToStorage(rd);
}
// Interprets an instruction.
void execute(char line [64])
{
char linecopy [64];
strcpy(linecopy, line);
char* instruction = strtok(line, " ");
void (*insptr[])(char*) = {
j, li, lb, sb, beq, bgt, blt, bge, ble,
add, sub, mul, divu, addi, sll, srl, andi
};
for (uint8_t i = 0; i < 17; ++i)
{
if (strcmp(instruction, (char*)pgm_read_word(&(instructions[i]))) == 0)
{
(*insptr[i])(linecopy);
break;
}
}
}
// Reads program files and executes commands.
void runProgram()
{
jump = false;
file.close();
file = SD.open(fileName, FILE_READ);
if (file)
{
running = true;
char line [64];
uint8_t index = 0;
while (file.available() && jump == false)
{
char c = file.read();
if (c == '\n')
{
line[index] = '\0';
execute(line);
line[0] = '\0';
index = 0;
}
else
{
line[index] = c;
index++;
}
}
}
else
{
Serial.println("Failed to open file!");
}
}
// Determines where the next instruction is read from.
void jumpToLabel()
{
jumping = true;
file.close();
file = SD.open(fileName, FILE_READ);
if (file)
{
char line [64];
uint8_t index = 0;
while (file.available())
{
char c = file.read();
if (c == '\n')
{
line[index] = '\0';
if (jump == false)
{
execute(line);
}
else if (strcmp(line, label) == 0)
{
jump = false;
jumping = false;
}
line[0] = '\0';
index = 0;
}
else
{
line[index] = c;
index++;
}
}
}
else
{
exitProgram();
Serial.println("Failed to open file!");
}
}
// Initialization.
void setup()
{
Serial.begin(115200);
SD.begin(10);
strcpy(fileName, "boot.txt");
runProgram();
}
// Loops consecutively.
void loop()
{
if (jump == true && jumping == false)
{
jumpToLabel();
}
else if (Serial.available() && !running)
{
memset(&fileName[0], 0, sizeof(fileName));
Serial.readBytesUntil('\n', fileName, 16);
runProgram();
}
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
sd1:CD
sd1:DO
sd1:GND
sd1:SCK
sd1:VCC
sd1:DI
sd1:CS
bz1:1
bz1:2
led1:A
led1:C
sr1:Q1
sr1:Q2
sr1:Q3
sr1:Q4
sr1:Q5
sr1:Q6
sr1:Q7
sr1:GND
sr1:Q7S
sr1:MR
sr1:SHCP
sr1:STCP
sr1:OE
sr1:DS
sr1:Q0
sr1:VCC
bargraph1:A1
bargraph1:A2
bargraph1:A3
bargraph1:A4
bargraph1:A5
bargraph1:A6
bargraph1:A7
bargraph1:A8
bargraph1:A9
bargraph1:A10
bargraph1:C1
bargraph1:C2
bargraph1:C3
bargraph1:C4
bargraph1:C5
bargraph1:C6
bargraph1:C7
bargraph1:C8
bargraph1:C9
bargraph1:C10
led2:A
led2:C
r1:1
r1:2
r2:1
r2:2
blink:BLINK
led3:A
led3:C
r3:1
r3:2
r4:1
r4:2
pot1:GND
pot1:SIG
pot1:VCC