#define PINRESET 3 #define PINCLOCK 13 #define PINDELAYEDCLOCK 2 // Connections: // 54 to 61 - address 0 to address 7 on ROM (A0 to A7) // 62 to 69 - BUS0 to BUS7 (A8 to A15) // 22 to 29 - D0 to D7 - watch the ordering // 30 to 37 - IR0 to IR7 // 38 to 45 - Y0 to Y7 // 46 to 53 - AC0 to7 // 4 - !XL // 5 - !YL // 6 - !IX // 7 - EH // 8 - EL // 9 - !OL // 10 - !LD // 11 - !PL // 12 - !PH int realClockCount=0; unsigned int realAddressBus; unsigned int realBus; unsigned int realData; unsigned int realIR; unsigned int realY; unsigned int realAC; unsigned char realYL; unsigned char realXL; unsigned char realIX; unsigned char realEH; unsigned char realEL; unsigned char realOL; unsigned char realLD; unsigned char realPL; unsigned char realPH; unsigned char simYL; unsigned char simXL; unsigned char simIX; unsigned char simEH; unsigned char simEL; unsigned char simOL; unsigned char simLD; unsigned char simPL; unsigned char simPH; typedef struct { // TTL state that the CPU controls uint16_t PC; uint8_t IR, D, AC, X, Y, OUT, undef; uint8_t CO; } CpuState; typedef struct { uint16_t addr; uint8_t data; } MemValue; MemValue RAM[256]; int ramcounter=0; CpuState State; const unsigned char ROMIR[] = { 0x00,0x18,0x18,0x00,0xd6,0x00,0x69,0xca,0xc2,0x69,0xec,0x00,0x69,0xca,0x61,0xf0,0x01,0xfc,0x82,0x00,0xc2,0xec,0xa0,0x01,0xec,0xa0,0x00,0x18,0x18,0x00,0xd2,0xd6,0x01,0xf4,0x8d,0x60,0xc2,0x01,0xf4,0x81,0x60,0xc2,0x81,0xc2,0x01,0x80,0xec,0xd2,0x01,0x80,0xec,0xd6,0x00,0x18,0x18,0x01,0x81,0x80,0xec,0x00,0x01,0x80,0xc2,0x60,0xa0,0xc2,0x00,0xc2,0x90,0x00,0xd6,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0x00,0xc2,0xc2,0xc2,0xc2,0xc2,0x00,0x18,0x18,0x14,0x00,0xc2,0x10,0xc2,0xde,0x20,0xec,0x01,0xfc,0x81,0x60,}; const unsigned char ROMD[] = { 0x00,0x80,0xc0,0x01,0x01,0xff,0x00,0x00,0x00,0x00,0x0a,0xff,0x00,0x00,0x00,0x13,0x01,0x04,0x00,0xff,0x00,0x15,0x01,0x00,0x14,0x01,0x01,0x80,0xc0,0x00,0x18,0x19,0x06,0x24,0x00,0xbf,0x06,0x07,0x29,0x06,0xc1,0x07,0x08,0x08,0x18,0x01,0x20,0x18,0x19,0x01,0x20,0x19,0x03,0x80,0xc0,0x04,0x05,0x5a,0x3e,0x00,0x04,0x01,0x04,0xff,0x59,0x05,0xee,0x16,0x02,0x01,0x17,0x59,0x98,0x2b,0x22,0xb4,0xfb,0xb4,0xe2,0xff,0x0e,0x0f,0x10,0x11,0x12,0x07,0x80,0xc0,0x07,0x00,0x02,0x00,0x1d,0x00,0x20,0x62,0x1d,0x64,0x1d,0x7f,}; void WriteMemory(uint16_t addr, uint8_t data) { int i; Serial.print("Writing "); Serial.print(data); Serial.print(" to address "); Serial.println(addr); i=0; while ((i> 5; // Instruction int mod = (S.IR >> 2) & 7; // Addressing mode (or condition) int bus = S.IR&3; // Busmode int W = (ins == 6); // Write instruction? int J = (ins == 7); // Jump instruction? uint8_t lo=S.D, hi=0, *to=NULL; // Mode Decoder int incX=0; if (!J) switch (mod) { #define E(p) (W?0:p) // Disable AC and OUT loading during RAM write case 0: to=E(&T.AC); break; case 1: to=E(&T.AC); lo=S.X; break; case 2: to=E(&T.AC); hi=S.Y; break; case 3: to=E(&T.AC); lo=S.X; hi=S.Y; break; case 4: to= &T.X; break; case 5: to= &T.Y; break; case 6: to=E(&T.OUT); break; case 7: to=E(&T.OUT); lo=S.X; hi=S.Y; incX=1; break; } uint16_t addr = (hi << 8) | lo; int B = 0; switch (bus) { case 0: B=S.D; break; case 1: if (!W) B = ReadMemory(addr&0x7fff); break; case 2: B=S.AC; break; case 3: B=0xFF; break; } if (W) WriteMemory(addr&0x7fff,B); // Random Access Memory uint8_t ALU; // Arithmetic and Logic Unit switch (ins) { case 0: ALU = B; break; // LD case 1: ALU = S.AC & B; break; // ANDA case 2: ALU = S.AC | B; break; // ORA case 3: ALU = S.AC ^ B; break; // XORA case 4: ALU = S.AC + B; break; // ADDA case 5: ALU = S.AC - B; break; // SUBA case 6: ALU = S.AC; break; // ST case 7: ALU = -S.AC; break; // Bcc/JMP } if (to) *to = ALU; // Load value into register if (incX) T.X = S.X + 1; // Increment X // I'm really not sure of this - I think the carry out is much more complicated S.CO = (S.AC==0); T.PC = S.PC + 1; // Next instruction if (J) { if (mod != 0) { // Conditional branch within page int cond = (S.AC>>7) + 2*(S.AC==0); if (mod & (1 << cond)) // 74153 T.PC = (S.PC & 0xff00) | B; } else T.PC = (S.Y << 8) | B; // Unconditional far jump } return T; } void CalcAdditionalSignals(int IR, int ac7, int co) { int modelines[4]; int inslines[5]; int ins = IR >> 5; // Instruction int mod = (IR >> 2) & 7; // Addressing mode (or condition) int bus = IR&3; // Busmode int cond; modedecoder(IR, modelines); insdecoder(IR, inslines); if (ins==7) { cond=0; if((ac7==0)&&(co==0)) cond=(IR&0x04); if((ac7==1)&&(co==0)) cond=(IR&0x08); if((ac7==0)&&(co==1)) cond=(IR&0x10); if((ac7==1)&&(co==1)) cond=0; } else { cond=0; } if (mod==5) simYL=0; else simYL=1; if (mod==4) simXL=0; else simXL=1; if (mod==4) simIX=1; else simIX=0; simEH=modelines[3]; simEL=modelines[2]; if ((modelines[1]==1)||(ins==6)) simOL=1; else simOL=0; if ((modelines[0]==1)||(ins==6)) simLD=1; else simLD=0; if ((ins!=7)||(mod>0)) simPH=1; else simPH=0; if ((simPH==1)&&(cond==0)) simPL=1; else simPL=0; } void setup() { int i; //start serial connection Serial.begin(115200); pinMode(PINCLOCK, OUTPUT); // Clock pinMode(PINDELAYEDCLOCK, OUTPUT); // Delayed Clock pinMode(PINRESET, OUTPUT); // Reset for(i=4;i<13;i++) { pinMode(i, INPUT); } for(i=22;i<70;i++) { pinMode(i, INPUT); } for(i=0;i<256;i++) { RAM[i].addr=0xffff; RAM[i].data=0; } } void DoReset() { digitalWrite(PINCLOCK,LOW); digitalWrite(PINDELAYEDCLOCK,LOW); digitalWrite(PINRESET,LOW); delay(500); DoClock(); DoClock(); realClockCount=0; State.PC=0; digitalWrite(PINRESET,HIGH); } void DoClock() { digitalWrite(PINCLOCK,LOW); delay(20); digitalWrite(PINDELAYEDCLOCK,LOW); delay(250); realClockCount++; digitalWrite(PINCLOCK,HIGH); delay(20); digitalWrite(PINDELAYEDCLOCK,HIGH); delay(250); } int digitalReadAndShift(int pin, int *total) { int c; c=digitalRead(pin); *total=*total<<1; if (c) *total+=1; return c; } void printpaddedhex(int hex) { if (hex<0x10) Serial.print("0"); Serial.print(hex,HEX); } void printbinarynum(int d, int digits) { for(int i = digits; i >= 0; i--) Serial.print(bitRead(d,i)); } void printcombined(int d, int bits) { if (bits>4) { printpaddedhex(d); } else { Serial.print(d,HEX); } Serial.print(" ("); printbinarynum(d, bits); Serial.print(")"); } void modedecoder(int IR, int *modelines) { int ins = IR >> 5; // Instruction int mod = (IR >> 2) & 7; // Addressing mode (or condition) // Simulation of the mode line diode decoder thing modelines[0]=1; modelines[1]=1; modelines[2]=1; modelines[3]=1; if (ins != 7) { switch (mod) { case 0: modelines[0]=0; break; case 1: modelines[0]=0; modelines[2]=0; break; case 2: modelines[0]=0; modelines[3]=0; break; case 3: modelines[0]=0; modelines[2]=0; modelines[3]=0; break; case 6: modelines[1]=0; break; case 7: modelines[1]=0; modelines[2]=0; modelines[3]=0; break; default: break; } } } void insdecoder(int IR, int *inslines) { int ins = IR >> 5; // Instruction inslines[0]=1; inslines[1]=1; inslines[2]=1; inslines[3]=1; inslines[4]=1; switch (ins) { case 0: inslines[2]=0; inslines[3]=0; inslines[4]=0; break; case 1: inslines[3]=0; inslines[4]=0; break; case 2: inslines[1]=0; inslines[2]=0; inslines[3]=0; inslines[4]=0; break; case 3: inslines[1]=0; inslines[2]=0; inslines[4]=0; break; case 4: inslines[2]=0; inslines[3]=0; break; case 5: inslines[0]=0; inslines[1]=0; break; case 6: break; case 7: inslines[0]=0; inslines[2]=0; inslines[4]=0; break; default: break; } } void printinstruction(int IR) { int ins = IR >> 5; // Instruction switch (ins) { case 0: Serial.print("LD "); break; case 1: Serial.print("AND "); break; case 2: Serial.print("OR "); break; case 3: Serial.print("XOR "); break; case 4: Serial.print("ADD "); break; case 5: Serial.print("SUB "); break; case 6: Serial.print("ST "); break; case 7: Serial.print("BCC "); break; default: break; } } void printir(int IR) { int modelines[4]; int inslines[5]; int i; int ins = IR >> 5; // Instruction int mod = (IR >> 2) & 7; // Addressing mode (or condition) int bus = IR&3; // Busmode int W = (ins == 6); // Write instruction? int J = (ins == 7); // Jump instruction? int ld; printpaddedhex(IR); Serial.print(" ["); modedecoder(IR, modelines); insdecoder(IR, inslines); Serial.print("ins:"); Serial.print(ins); Serial.print("-"); printinstruction(IR); if ((modelines[0]==1)||(ins==6)) ld=1; else ld=0; for(i=4;i>=0;i--) Serial.print(inslines[i]); Serial.print(" mod:"); Serial.print(mod); Serial.print("-"); for(i=3;i>=0;i--) Serial.print(modelines[i]); Serial.print(" bus-"); printbinarynum(bus,3); switch (bus) { case 0: Serial.print("-ROM"); break; case 1: if (!W) Serial.print("-RAM"); else Serial.print("-UND"); break; case 2: Serial.print("-AC "); break; case 3: Serial.print("-IN "); break; } Serial.print(" W:"); Serial.print(W); Serial.print(" J:"); Serial.print(J); if (J) { Serial.print("-"); if (mod != 0) { Serial.print("cond"); } else { Serial.print("uncj"); } } Serial.print(" LD:"); Serial.print(ld); Serial.print(" ]"); } void PrintAllSignals() { Serial.print("Clock cycle:"); Serial.print(realClockCount); if (realAddressBus>0) { Serial.print(" ROM Lookup: IR:"); Serial.print(ROMIR[realAddressBus-1],HEX); Serial.print(" D:"); Serial.println(ROMD[realAddressBus-1],HEX); } Serial.println(""); Serial.print("ROM ADR:"); printpaddedhex(realAddressBus>>8); printpaddedhex(realAddressBus&0xFF); Serial.print(" BUS:"); printcombined(realBus,8); Serial.print(" Data:"); printcombined(realData,8); Serial.println(""); Serial.print("IR:"); printir(realIR); Serial.println(""); Serial.print("Y:"); printcombined(realY,8); Serial.print(" AC:"); printcombined(realAC,8); Serial.print(" YL:"); Serial.print(realYL); Serial.print(" XL:"); Serial.print(realYL); Serial.print(" EH:"); Serial.print(realEH); Serial.print(" EL:"); Serial.print(realEL); Serial.print(" OL:"); Serial.print(realOL); Serial.print(" LD:"); Serial.print(realLD); Serial.print(" PL:"); Serial.print(realPL); Serial.print(" PH:"); Serial.print(realPH); Serial.println(""); Serial.println(""); } void ReportState(CpuState S) { Serial.print("PC:"); Serial.print(S.PC); Serial.print(" IR:"); printir(S.IR); Serial.println(""); Serial.print("D:"); printpaddedhex(S.D); Serial.print(" AC:"); printcombined(S.AC,8); Serial.print(" X:"); printpaddedhex(S.X); Serial.print(" Y:"); printpaddedhex(S.Y); Serial.println(""); // Now report 'internal' signals Serial.print("YL:"); Serial.print(simYL); Serial.print(" XL:"); Serial.print(simYL); Serial.print(" EH:"); Serial.print(simEH); Serial.print(" EL:"); Serial.print(simEL); Serial.print(" OL:"); Serial.print(simOL); Serial.print(" LD:"); Serial.print(simLD); Serial.print(" PL:"); Serial.print(simPL); Serial.print(" PH:"); Serial.print(simPH); Serial.print(" CO:"); Serial.print(S.CO); Serial.print(" AC7:"); Serial.print((S.AC&0x80)>0); Serial.println(""); } unsigned int ReadBlock(int sourcepins) { unsigned int res; int i; res=0; for(i=sourcepins+7;i>=sourcepins;i--) { res=res<<1; if (digitalRead(i)) res|=1; } return res; } unsigned int TestRead(int sourcepins) { int i; Serial.print("Reading "); Serial.print(sourcepins); Serial.print(" "); for(i=sourcepins+7;i>=sourcepins;i--) { Serial.print(digitalRead(i)); } Serial.println(""); } void ReadSignals() { realAddressBus=ReadBlock(54); realBus=ReadBlock(62); realData=ReadBlock(22); // TestRead(30); realIR=ReadBlock(30); realY=ReadBlock(38); realAC=ReadBlock(46); realXL=digitalRead(4); realYL=digitalRead(5); realIX=digitalRead(6); realEH=digitalRead(7); realEL=digitalRead(8); realOL=digitalRead(9); realLD=digitalRead(10); realPL=digitalRead(11); realPH=digitalRead(12); } void loop() { char c; if (Serial.available()) { c=Serial.read(); if (c==' ') { ReadSignals(); PrintAllSignals(); } if (c=='\r') { // ReadSignals(); DoClock(); ReadSignals(); PrintAllSignals(); State = cpuCycle(State); CalcAdditionalSignals(State.IR, (State.AC&0x80), State.CO); ReportState(State); Serial.println("---------------"); } if ((c=='r')||(c=='R')) { Serial.println("Reset"); DoReset(); ReadSignals(); PrintAllSignals(); } } }