Last active
January 21, 2017 23:34
-
-
Save westonal/1fd2ae7ee19d568cb425eee77ef1a321 to your computer and use it in GitHub Desktop.
TIS-100 arduino
This file contains hidden or 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
| #include <LiquidCrystal.h> | |
| LiquidCrystal lcd(7, 6, 5, 4, 3, 2); | |
| void setup() { | |
| Serial.begin(9600); | |
| lcd.begin(16, 2); | |
| setProgram(); | |
| compile(); | |
| lcd.setCursor(0,1); | |
| lcd.write("ACC="); | |
| lcd.setCursor(8,1); | |
| lcd.write("BCK="); | |
| } | |
| const int MAX_LINES = 15; | |
| typedef struct { | |
| char *id; | |
| char *cmd; | |
| char *arg1; | |
| char *arg2; | |
| } line; | |
| line program_lines[MAX_LINES]; | |
| static char program[MAX_LINES][16]; | |
| char mode[2] = "-"; | |
| void setProgram(){ | |
| for(int i=0;i<MAX_LINES;i++){ | |
| sprintf(program[i], ""); | |
| } | |
| int i=0; | |
| sprintf(program[i++], "JRO 999"); | |
| sprintf(program[i++], "Q:"); | |
| sprintf(program[i++], "JRO -1"); | |
| //sprintf(program[i++], "MOV UP ACC"); | |
| //sprintf(program[i++], "SAV"); | |
| //sprintf(program[i++], "ADD ACC"); | |
| //sprintf(program[i++], "SUB UP"); | |
| //sprintf(program[i++], "MOV ACC DOWN"); | |
| sprintf(program[i++], "MOV 10 ACC"); | |
| sprintf(program[i++], "SWP"); | |
| sprintf(program[i++], "MOV 5 ACC"); | |
| sprintf(program[i++], "L:SUB 1"); | |
| sprintf(program[i++], "SWP"); | |
| sprintf(program[i++], "JEZ E"); | |
| sprintf(program[i++], "JMP L"); | |
| sprintf(program[i++], "E:SWP"); | |
| sprintf(program[i++], "MOV ACC DOWN"); | |
| sprintf(program[i++], "JMP Q"); | |
| } | |
| void debug(char *str){ | |
| Serial.write("\""); | |
| Serial.write(str); | |
| Serial.write("\"\n"); | |
| } | |
| void compile(){ | |
| for(int i=0;i<MAX_LINES;i++){ | |
| line *line = &program_lines[i]; | |
| char *source = malloc(17); | |
| strcpy(source, program[i]); | |
| //Label | |
| char *found = strstr(source, ":"); | |
| if(found == NULL){ | |
| line->id = NULL; | |
| }else{ | |
| line->id = source; | |
| *found = '\0'; | |
| source = found+1; | |
| } | |
| //command | |
| found = strstr(source, " "); | |
| if(found == NULL){ | |
| line->cmd = source; //no args | |
| line->arg1 = NULL; | |
| line->arg2 = NULL; | |
| continue; | |
| }else{ | |
| line->cmd = source; | |
| *found = '\0'; | |
| source = found+1; | |
| } | |
| //arg 1 | |
| found = strstr(source, " "); | |
| if(found == NULL){ | |
| line->arg1 = source; //no 2nd arg | |
| line->arg2 = NULL; | |
| continue; | |
| }else{ | |
| line->arg1 = source; | |
| *found = '\0'; | |
| line->arg2 = found+1; | |
| } | |
| } | |
| } | |
| void spitOutCompiled(){ | |
| debug("All:"); | |
| for(int i=0;i<MAX_LINES;i++){ | |
| line *line = &program_lines[i]; | |
| debug(line->id); | |
| debug(line->cmd); | |
| debug(line->arg1); | |
| debug(line->arg2); | |
| debug("---"); | |
| } | |
| } | |
| int pc; //program counter | |
| int acc; //accumulator register | |
| int bck; //backup register | |
| void lcdWriteDecimal(int value){ | |
| static char temp[6]; | |
| sprintf(&temp[0], "%03d ", value); //"-999 " | |
| temp[4]='\0'; | |
| lcd.write(temp); | |
| } | |
| void displayCurrentCommand(){ | |
| static char temp[17]; | |
| sprintf(temp, "%-16s", program[pc]); | |
| lcd.setCursor(0,0); | |
| lcd.write(temp); | |
| } | |
| void displayRegisterValues(){ | |
| lcd.setCursor(4,1); | |
| lcdWriteDecimal(acc); | |
| lcd.setCursor(12,1); | |
| lcdWriteDecimal(bck); | |
| } | |
| void displayTheMode(){ | |
| lcd.setCursor(15, 0); | |
| lcd.write(mode); | |
| } | |
| bool isNullOrEmpty(char *str){ | |
| return str == NULL || str[0] == '\0'; | |
| } | |
| void moveNextCommand(){ | |
| do { | |
| pc=(pc+1)%MAX_LINES; | |
| } while(isNullOrEmpty(program_lines[pc].cmd)); | |
| } | |
| void moveToLastCommand(){ | |
| pc = MAX_LINES-1; | |
| while(isNullOrEmpty(program_lines[pc].cmd)){ | |
| pc=(MAX_LINES + pc - 1)%MAX_LINES; | |
| } | |
| } | |
| bool startsWith(const char *str, const char *pre) { | |
| return strncmp(pre, str, strlen(pre)) == 0; | |
| } | |
| int serialReadInt(){ | |
| setReadMode(); | |
| Serial.write("Input required:"); | |
| static char readString[15]; | |
| int idx = 0; | |
| while (idx < 2 || readString[idx-1] != '\n') { | |
| delay(3); //delay to allow buffer to fill | |
| if (Serial.available() >0) { | |
| readString[idx++] = Serial.read(); | |
| } | |
| } | |
| readString[idx-1] = '\0'; | |
| debug(readString); | |
| return atoi(readString); | |
| } | |
| int evaluate(char *arg){ | |
| if(strcmp(arg, "UP")==0){ | |
| return clamp(serialReadInt()); | |
| } | |
| if(strcmp(arg, "ACC")==0){ | |
| return acc; | |
| } | |
| return clamp(atoi(arg)); | |
| } | |
| void executeMov(){ | |
| line *line = &program_lines[pc]; | |
| int inputValue = evaluate(line->arg1); | |
| char *dest = line->arg2; | |
| if(strcmp(dest, "ACC")==0){ | |
| acc = inputValue; | |
| return; | |
| } | |
| if(strcmp(dest, "DOWN")==0){ | |
| setWriteMode(); | |
| char temp[5]; | |
| sprintf(temp, "%03d\n", inputValue); | |
| Serial.write(temp); | |
| return; | |
| } | |
| } | |
| void setRunMode1(){ | |
| mode[0] = '>'; | |
| displayTheMode(); | |
| } | |
| void setRunMode2(){ | |
| mode[0] = 255; | |
| displayTheMode(); | |
| } | |
| void setReadMode(){ | |
| mode[0] = 'R'; | |
| displayTheMode(); | |
| } | |
| void setWriteMode(){ | |
| mode[0] = 'W'; | |
| displayTheMode(); | |
| } | |
| int clamp(int val){ | |
| if(val > 999) return 999; | |
| if(val < -999) return -999; | |
| return val; | |
| } | |
| void executeAdd(char *arg){ | |
| acc = clamp(acc + evaluate(arg)); | |
| } | |
| void executeSub(char *arg){ | |
| acc = clamp(acc - evaluate(arg)); | |
| } | |
| void executeSwp(){ | |
| int temp = bck; | |
| bck = acc; | |
| acc = temp; | |
| } | |
| bool executeJmp(char *label){ | |
| for(int i=0;i<MAX_LINES;i++){ | |
| char *lineLabel = program_lines[i].id; | |
| if(lineLabel != NULL && strcmp(lineLabel, label)==0){ | |
| pc = i; | |
| if(isNullOrEmpty(program_lines[pc].cmd)){ | |
| moveNextCommand(); | |
| } | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| bool executeJro(char *arg){ | |
| int numberToJmp = evaluate(arg); | |
| Serial.println(numberToJmp); | |
| if(numberToJmp == 0) | |
| return true; | |
| int quantity = 1; | |
| if(numberToJmp < 0){ | |
| quantity = -1; | |
| } | |
| while(numberToJmp!=0){ | |
| pc=pc+quantity; | |
| if(pc < 0){ | |
| pc = -1; | |
| moveNextCommand(); | |
| return true; | |
| } | |
| if(pc >= MAX_LINES){ | |
| pc = MAX_LINES; | |
| moveToLastCommand(); | |
| return true; | |
| } | |
| if(isNullOrEmpty(program_lines[pc].cmd)){ | |
| numberToJmp = numberToJmp + quantity; | |
| } | |
| } | |
| return true; | |
| } | |
| bool executeCommand(){ | |
| line *line = &program_lines[pc]; | |
| if(strcmp(line->cmd, "MOV")==0){ | |
| executeMov(); | |
| return false; | |
| } | |
| if(strcmp(line->cmd, "ADD")==0){ | |
| executeAdd(line->arg1); | |
| return false; | |
| } | |
| if(strcmp(line->cmd, "SUB")==0){ | |
| executeSub(line->arg1); | |
| return false; | |
| } | |
| if(strcmp(line->cmd, "JMP")==0){ | |
| return executeJmp(line->arg1); | |
| } | |
| if(strcmp(line->cmd, "JEZ")==0){ | |
| if(acc==0) | |
| return executeJmp(line->arg1); | |
| return false; | |
| } | |
| if(strcmp(line->cmd, "JNZ")==0){ | |
| if(acc!=0) | |
| return executeJmp(line->arg1); | |
| return false; | |
| } | |
| if(strcmp(line->cmd, "JGZ")==0){ | |
| if(acc>0) | |
| return executeJmp(line->arg1); | |
| return false; | |
| } | |
| if(strcmp(line->cmd, "JLZ")==0){ | |
| if(acc<0) | |
| return executeJmp(line->arg1); | |
| return false; | |
| } | |
| if(strcmp(line->cmd, "JRO")==0){ | |
| return executeJro(line->arg1); | |
| } | |
| if(strcmp(line->cmd, "SWP")==0){ | |
| executeSwp(); | |
| return false; | |
| } | |
| if(strcmp(line->cmd, "SAV")==0){ | |
| bck = acc; | |
| return false; | |
| } | |
| return false; | |
| } | |
| void loop() { | |
| //digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) | |
| //delay(1000); // wait for a second | |
| //digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW | |
| //delay(1000); // wait for a second | |
| displayCurrentCommand(); | |
| displayRegisterValues(); | |
| setRunMode1(); | |
| delay(500); | |
| bool jumped = executeCommand(); | |
| if(!jumped) | |
| moveNextCommand(); | |
| setRunMode2(); | |
| displayRegisterValues(); | |
| delay(500); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment