// 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