Arduino Code

// Create a Microcomputer Trainer with Arduino
// DIO pin 8
// CLK pin 9
// STB pin 7

#include <TM1638.h>

#define RAMSIZE 128 // Feel free to increase this if desired
#define MEMSIZE 16
#define BRIGHT 0
#define BUZZER  3

// define a module on data pin 8, clock pin 9 and strobe pin 7
TM1638 module(8, 9, 7);

byte ACCA;  // A accumulator
byte ACCB;  // B accumulator
byte REGY;  // Y register
byte REGZ;  // Z register
byte ACCAP; // Used for swap
byte ACCBP; // Used for swap
byte REGYP; // Used for swap
byte REGZP; // Used for swap
int PC;    // Program Counter: Can go to 128
byte LEDS;   // LED buffer
byte VAL;   // Current value of input
byte MEM[MEMSIZE];  // Array simulating memory
byte PROG[RAMSIZE]; // Array simulating program space
boolean FLAG;   // Flag that is set with instructions
byte KEY;   // current selected key


void setup() {

  pinMode(BUZZER, OUTPUT);
  Serial.begin(9600);

  initAll();

  module.setupDisplay(true, BRIGHT);
  // display a hexadecimal number and set the left 4 dots
  // module.setDisplayToHexNumber(0x1234ABCD, 0xF0);
  // byte keys = module.getButtons();
}

void loop() {

  displayOut(PC, VAL, false, 0);

  KEY = module.getButtons();
  while (!KEY) {
    KEY = module.getButtons();
  }

  switch (KEY) {

    case 128: // Increment Value displayed
      VAL += 1;
      if (VAL > 15) VAL = 0;
      break;

    case 64:  // Decriment Value displayed
      if (VAL == 0) VAL = 15;
      else  VAL -= 1;
      break;

    case 1: // Reset
      PC = 0;
      VAL = PROG[PC];
      LEDS = 0;
      module.setLEDs(LEDS);
      break;

    case 2: // Increment with value
      PROG[PC] = VAL;
      PC += 1;
      VAL = PROG[PC];
      break;

    case 4: // Run the program

      while (module.getButtons() != 1) {
        parseNext();
      }
      PC = 0;
      VAL = PROG[PC];
      break;

    case 8: // Address set
      memSet();
      break;

    case 16: // Save program
      saveProgram();
      break;

    case 32: // Load program
      loadProgram();
      break;
  }

  while (KEY) {
    KEY = module.getButtons();
  }

}

// ***********************************
// parse and execute next instruction
// ***********************************

void parseNext() {       // Entering with PC pointing to current instruction to execute
  int instruction = 0;
  byte tmp; // temp value used in swapping

  if (PROG[PC] == 14) {
    PC += 1;
    instruction = 16 + PROG[PC];
  } else {
    instruction = PROG[PC];
  }
  // Program Counter is on the current instruction

  FLAG = 1; //This is the dfault and tells the program to continue with the next instruction
  // Will set this to 0 if we need to skip a JMP or CAL instruction

  switch (instruction) {

    case 0: // KA
      tmp = module.getButtons();
      if (tmp) {
        for (int i = 1; i < 8; i++) if (bitRead(tmp, i)) ACCA = i;
        FLAG = 0;
      }
      break;

    case 1: // AO
      {
        displayOut(PC, ACCA, false, 0);
        break;
      }

    case 2: // CH
      tmp = ACCA;
      ACCA = ACCB;
      ACCB = tmp;
      tmp = REGY;
      REGY = REGZ;
      REGZ = tmp;
      break;

    case 3:  // CY
      tmp = ACCA;
      ACCA = REGY;
      REGY = tmp;
      break;

    case 4:  // AM
      MEM[REGY] = ACCA;
      break;

    case 5:  // MA
      ACCA = MEM[REGY];
      break;

    case 6:  // M+
      ACCA = MEM[REGY] + ACCA;
      if (ACCA > 15) ACCA -= 15; // Get rid of the carry
      else FLAG = 0;
      break;

    case 7:  // M-
      ACCA = MEM[REGY] - ACCA;
      if (ACCA > 15) ACCA = 0xff - ACCA;
      else FLAG = 0;
      break;

    case 8:  // TIA
      PC += 1; // Advance to the argument
      ACCA = PROG[PC];
      break;

    case 9:  // AIA
      PC += 1; // Advance to the argument
      ACCA += PROG[PC];

      if (ACCA > 15) ACCA -= 16; // Get rid of the carry
      else FLAG = 0;
      break;

    case 10: // TIY
      PC += 1; // Advance to the argument
      REGY = PROG[PC];
      break;

    case 11: // AIY
      PC += 1; // Advance to the argument
      REGY += PROG[PC];

      if (REGY > 15) REGY -= 16; // Get rid of the carry
      else FLAG = 0;
      break;

    case 12: // CIA
      PC += 1; // Advance to the argument
      if (ACCA != PROG[PC]) FLAG = 0;
      break;

    case 13: // CIY
      PC += 1; // Advance to the argument
      if (REGY == PROG[PC]) FLAG = 0;
      break;

    case 14: // CALL (not used alone)
      break;

    case 15: // JUMP
      PC = PROG[PC + 1] * 16 + PROG[PC + 2] - 1; // Need the -1 because all cases end in a PC increment
      break;

    case 16: // RSTO
      displayOut(PC, VAL, true, 0);
      break;

    case 17: // SETR
      tmp = 0x00;
      bitSet(tmp, REGY);
      LEDS = LEDS | tmp;
      module.setLEDs(LEDS);
      break;

    case 18: // RSTR
      tmp = 0xFF;
      bitClear(tmp, REGY);
      LEDS = LEDS & tmp;
      module.setLEDs(LEDS);
      break;

    case 19: // NOT USED - Using it for HEX KEY input
      while (module.getButtons() != 0) {}

      ACCA = getKey();
      break;

    case 20: // CMPL
      ACCA = 15 - ACCA;
      break;

    case 21: // CHNG
      tmp = ACCA;
      ACCA = ACCAP;
      ACCAP = tmp;
      tmp = ACCB;
      ACCB = ACCBP;
      ACCBP = tmp;
      tmp = REGY;
      REGY = REGYP;
      REGYP = tmp;
      tmp = REGZ;
      REGZ = REGZP;
      REGZP = tmp;
      break;

    case 22: // SIFT
      if (bitRead(ACCA, 0) == 0) FLAG = 0;
      ACCA = ACCA >> 1;
      break;

    case 23: // ENDS
      soundOut(70, 200);
      soundOut(30, 200);
      break;

    case 24: // ERRS
      soundOut(10, 100);
      delay(10);
      soundOut(10, 100);
      delay(10);
      soundOut(10, 100);
      break;

    case 25: // SHTS
      soundOut(40, 250);
      break;

    case 26: // LONS
      soundOut(40, 750);
      break;

    case 27: // SUND
      soundOut(ACCA * 10, 200);
      break;

    case 28: // TIMR
      delay((ACCA + 1) * 100);
      break;

    case 29: // DSPR
      LEDS = MEM[14] << 4 | MEM[15];
      module.setLEDs(LEDS);
      break;

    case 30: // DEM-
      if (MEM[REGY] >= ACCA) {
        MEM[REGY] -= ACCA;
      } else {
        MEM[REGY] = MEM[REGY] + 10 - ACCA;
      }
      REGY -= 1;
      break;

    case 31: // DEM+
      tmp = ACCA + MEM[REGY];
      if (tmp > 9) {
        MEM[REGY] = tmp - 10;
        REGY -= 1;
        MEM[REGY] += 1;
      } else {
        MEM[REGY] = tmp;
        REGY -= 1;
      }
      break;
  }

  if (!FLAG) {
    if (PROG[PC + 1] == 14) PC += 2; // if there is no carry skip Call statement.
    if (PROG[PC + 1] == 15) PC += 3; // if there is no carry skip Jump statement.
  }
  PC += 1; // Return with PC pointing to next executable address
}

byte getKey() {
  VAL = 0;
  boolean done = false;

  while (!done) {

    displayOut(PC, VAL, false, 1);
    KEY = module.getButtons();
    while (!KEY) {
      KEY = module.getButtons();
    }
    switch (KEY) {

      case 128: // Increment Value displayed
        VAL += 1;
        if (VAL > 15) VAL = 0;
        break;

      case 64:  // Decriment Value displayed
        if (VAL == 0) VAL = 15;
        else  VAL -= 1;
        break;

      case 2: // Enter
        done = true;
        break;
    }
    while (KEY) {
      KEY = module.getButtons();
    }
  }
  return VAL;
}

void memSet() {
  byte mPC = 0;
  byte mVal = MEM[mPC];
  boolean done = false;

  while (!done) {

    displayOut(5 * 16 + mPC, mVal, false, 2);
    KEY = module.getButtons();
    while (!KEY) {
      KEY = module.getButtons();
    }
    switch (KEY) {

      case 128: // Increment Value displayed
        mVal += 1;
        if (mVal > 15) mVal = 0;
        break;

      case 64:  // Decriment Value displayed
        if (mVal == 0) mVal = 15;
        else  mVal -= 1;
        break;

      case 2: // Enter
        MEM[mPC] = mVal;
        mPC += 1;
        if (mPC > 15) mPC = 0;
        mVal = MEM[mPC];
        break;

      case 1:
        done = true;
        break;
    }
    while (KEY) {
      KEY = module.getButtons();
    }
  }
}

void soundOut(int toneS, int timeS) {
  analogWrite(BUZZER, toneS);      // Almost any value can be used except 0 and 255
  // experiment to get the best tone
  delay(timeS);          // wait for a delayms ms
  analogWrite(BUZZER, 0);       // 0 turns it off

}

void displayOut(byte Addr, byte Data, boolean HEXoff, byte Msg) {
  module.setDisplayDigit(Addr >> 4, 0, false);
  module.setDisplayDigit(0x0F & Addr, 1, false);
  module.clearDisplayDigit(2, false);
  module.clearDisplayDigit(3, false);
  module.clearDisplayDigit(4, false);
  switch (Msg) {
    case 1:
      module.setDisplayDigit(14, 5, false);
      break;
    case 2:
      module.setDisplayDigit(13, 5, false);
      break;
    default:
      module.clearDisplayDigit(5, false);
  }
  module.clearDisplayDigit(6, false);
  if (HEXoff) module.clearDisplayDigit(7, true);
  else  module.setDisplayDigit(Data, 7, false);
}

void saveProgram() {
  for (int i = 0; i < 128; i++) {
    Serial.print(PROG[i], HEX);
  }
}

void loadProgram() {
  initAll();
  byte count = 0;
  displayOut(count, 5, true, 2);
  while (Serial.available()) { // Flush the input buffer
    Serial.read();
  }

  while (module.getButtons() != 1 | count > 127) {
    if (Serial.available() > 0) {
      PROG[count] = AStoHEX(Serial.read());
      displayOut(count, PROG[count], false, 0);
      count += 1;
    }
  }
  VAL = PROG[0];
}

byte AStoHEX(byte bIn) {
  if (bIn > 47 & bIn < 58) return bIn - 48;
  if (bIn > 64 & bIn < 71) return bIn - 55;
  else return 0;
}

void initAll() {
  ACCA = 0;
  ACCB = 0;
  REGY = 0;
  REGZ = 0;
  PC = 0;
  LEDS = 0;
  FLAG = 0;
  VAL = 0;
  KEY = 0;

  for (int i = 0; i < MEMSIZE; i++) {
    MEM[i] = 0;
  }
  for (int i = 0; i < RAMSIZE; i++) {
    PROG[i] = 0;
  }
  module.setLEDs(LEDS);
}

No comments:

Post a Comment