/* Tiny Machine-Code Monitor - see http://www.technoblogy.com/show?283C David Johnson-Davies - www.technoblogy.com - 18th July 2018 ATtiny85 @ 8 MHz (internal oscillator; BOD disabled) CC BY 4.0 Licensed under a Creative Commons Attribution 4.0 International license: http://creativecommons.org/licenses/by/4.0/ */ #include #include // 20-key Matrix keypad ******************************************************* const int Matrix = A2; // PB4 const int RUN = 17; const int Up = 18; const int Down = 19; const int ON = 20; const int SmallestGap = 24; int AnalogVals[] = {1023, 728, 693, 657, 632, 605, 567, 541, 517, 477, 439, 404, 371, 316, 290, 264, 220, 186, 151, 93, 0, -100}; int Buttons[] = {-1, 1, 2, 3, 10, 17, 4, 7, 14, 5, 8, 0, 6, 9, 11, 15, 12, 18, 13, 19, 20}; // Returns the keypad character or -1 if no button pressed int ReadKeypad() { int val, lastval=0, count = 0; do { val = analogRead(Matrix); if (abs(val-lastval)<2) count++; else { lastval = val; count = 0; } } while (count < 3); int i = 0; val = val - SmallestGap/2; while (val < AnalogVals[i]) { i++; } return Buttons[i - 1]; } // OLED I2C 128 x 32 monochrome display ********************************************** const int OLEDAddress = 0x3C; // Initialisation sequence for OLED module int const InitLen = 15; const unsigned char Init[InitLen] PROGMEM = { 0xA8, // Set multiplex 0x1F, // for 32 rows 0x8D, // Charge pump 0x14, 0x20, // Memory mode 0x01, // Vertical addressing 0xA1, // 0xA0/0xA1 flip horizontally 0xC8, // 0xC0/0xC8 flip vertically 0xDA, // Set comp ins 0x02, 0xD9, // Set pre charge 0xF1, 0xDB, // Set vcom deselect 0x40, 0xAF // Display on }; const int data = 0x40; const int single = 0x80; const int command = 0x00; void InitDisplay () { Wire.beginTransmission(OLEDAddress); Wire.write(command); for (uint8_t c=0; c>8); } } } Wire.endTransmission(); Column = Column + Scale; } // Print text at line, column void Print (PGM_P s) { int p = (int)s; while (1) { char c = pgm_read_byte(p++); if (c == 0) return; Pchar(c); } } char Hex (uint8_t byte) { return (byte < 10) ? byte+'0' : byte-10+'A'; } void Phex (uint8_t byte) { Pchar(Hex(byte)); } // Print a hex byte void Pbyte (uint8_t byte) { Phex(byte>>4); Phex(byte & 0xF); } // Display a 4-digit decimal number void PlotNumber (int num) { for (long d=1000; d>0; d=d/10) { Pchar(num/d % 10 + '0'); } } // MINIL Interpreter ********************************************** const int MemorySize = 64; const int StackSize = 72; int stk[StackSize]; uint8_t mem[MemorySize]; int reg[8]; int pc = 0, sp = 0; boolean err = false; void error (PGM_P s) { Line = 0; Column = 0; Print(s); err = true; delay(1000); } const int Timeout = 30; // Sleep after this many secs // Wait for keypress and go to sleep after Timeout int WaitForKey () { int key; unsigned long Start = millis(); do { key = ReadKeypad(); if (millis() - Start > Timeout*1000) { DisplayOnOff(0); // Blank display uint8_t temp = TIMSK; TIMSK = 0; // Disable timer interrupt(s) GIMSK = 1<>4 & 0xf; low = byte & 0xf; jump = byte & 0x1f; if (high == 0 && low == 0) { Print(PSTR("BRK ")); } else if (high == 1 && low == 1) { Print(PSTR("NOP ")); } else if (high == 6 && low == 6) { Print(PSTR("TOG ")); } else if (high == 7 && low == 7) { Print(PSTR("RTS ")); } else if (high < 8 && low < 8) { Print(PSTR("MOV R")); Phex(high); Print(PSTR(",R")); Phex(low); } else if (high < 8) { if (low == 0x8) Print(PSTR("PSH R")); else if (low == 0x9) Print(PSTR("POP R")); else if (low == 0xA) Print(PSTR("ADD R")); else if (low == 0xB) Print(PSTR("SUB R")); else if (low == 0xC) Print(PSTR("CPY #")); else if (low == 0xD) Print(PSTR("DEC R")); else if (low == 0xE) Print(PSTR("ENT R")); else if (low == 0xF) Print(PSTR("??? R")); Phex(high); Print(PSTR(" ")); } else if (high >= 0x8) { if (high <= 0x9) Print(PSTR("JZ ")); else if (high <= 0xB) Print(PSTR("JNZ")); else if (high <= 0xD) Print(PSTR("JC ")); else Print(PSTR("JSR")); Print(PSTR(" ")); Pchar('L'); Pbyte(jump); Print(PSTR(" ")); } } void Run () { int pc = 0, sp = 0; boolean zero = false, carry = false; uint8_t byte, high, low, jump; err = false; for (int r=0; r<8; r++) reg[r]=0; do { byte = mem[pc++]; high = byte>>4 & 0xf; low = byte & 0xf; jump = byte & 0x1f; if (high == 0 && low == 0) { error(PSTR("BREAK")); } else if (high == 6 && low == 6) { digitalWrite(1, !digitalRead(1)); } else if (high == 7 && low == 7) { if (sp == 0) error(PSTR("STACK <")); pc = stk[--sp]; } else if (high < 8 && low < 8) { reg[high] = reg[low]; } else if (high < 8) { // Single register operations if (low == 0x8) { if (sp >= StackSize-1) error(PSTR("STACK >")); stk[sp++] = reg[high]; } else if (low == 0x9) { if (sp == 0) error(PSTR("STACK <")); reg[high] = stk[--sp]; } else if (low == 0xA) { carry = (reg[0] + reg[high]) > 9999; reg[0] = reg[0] + reg[high]; if (carry) reg[0] = reg[0] - 10000; zero = reg[0] == 0; } else if (low == 0xB) { carry = reg[high] > reg[0]; reg[0] = reg[0] - reg[high]; if (carry) reg[0] = reg[0] + 10000; zero = reg[0] == 0; } else if (low == 0xC) { reg[0] = high; } else if (low == 0xD) { carry = reg[high] == 0; reg[high]--; if (carry) reg[high] = 9999; zero = reg[high] == 0; } else if (low == 0xE) { err = enter(high); } } else if (high >= 0x8) { // Jumps if (high <= 0x9) { if (zero) pc = jump;} else if (high <= 0xB) { if (!zero) pc = jump;} else if (high <= 0xD) { if (carry) pc = jump;} else { if (sp >= StackSize-1) error(PSTR("STACK >")); stk[sp++] = pc; pc = jump; } } } while (err == false && digitalRead(4) == 1); digitalWrite(1, LOW); } // Display screen with pc on bottom line void DisplayScreen (int pc) { pc = pc - 3; for (int l=0; l<4; l++) { Line = l; Column = 0; if (pc >= 0) Disassemble(pc); else Print(PSTR(" ")); pc++; } } // Setup ********************************************** void setup() { pinMode(1,OUTPUT); Wire.begin(); set_sleep_mode(SLEEP_MODE_PWR_DOWN); InitDisplay(); ClearDisplay(); Scale = 2; Line = 0; Column = 0; Print(PSTR("TINY MINIL")); delay(1000); } // PCINT0 interrupt wakes from sleep ISR(PCINT0_vect) { } void loop() { int key, key0 = -1; boolean done = false; // // Entry mode ClearDisplay(); Scale = 1; pc = 0; DisplayScreen(pc); do { key = WaitForKey(); // Decode key if (key == Up && key0 == -1 && pc > 0) { pc--; DisplayScreen(pc); } else if (key == Down && key0 == -1) { pc++; DisplayScreen(pc); } else if (key >= 0 && key <= 15) { if (key0 == -1) { Column = 3; Phex(key); Pchar('_'); key0 = key; } else { Column = 4; Phex(key); mem[pc] = key0<<4 | key; Disassemble(pc); key0 = -1; } } else if (key == RUN) done = true; // Wait for key release WaitForRelease(); } while (!done); // // Run mode ClearDisplay(); Scale = 2; Run(); }