// 8608emulator.c // This is the backend portion of the 8608 emulator application. // It uses the generated instruction code from instructions_gen.c to emulate the internals of the 8608 CPU. // It is included into the application by 8608emulator.lua, which provides the frontend. #define lobyte(x) (x&0xFF) #define hibyte(x) ((x>>8)&0xFF) #define wordfrombytes(h,l) (((h<<8)&0xFF00)|(l&0xFF)) #define popbyte readmemory(((--cpu->s)%256)+0x0100) #define loadimmed readmemory(cpu->i++) #define loadstackrel readmemory(cpu->t) #define loadstackrelp1 readmemory(cpu->t+1) #define wordut (wordfrombytes(cpu->u, cpu->t)) #define wordcb (wordfrombytes(cpu->c, cpu->b)) #define loadut readmemory(wordut) #define loadutp1 readmemory((wordut+1)%65536) #define loadp readmemory(cpu->p) #define loadq readmemory(cpu->q) #define loadpinc readmemory((cpu->p++)%65536) #define loadqinc readmemory((cpu->q++)%65536) #define loadpp1 readmemory((cpu->p+1)%65536) #define loadqp1 readmemory((cpu->q+1)%65536) #define loadput readmemory((cpu->p+wordut)%65536) #define loadqut readmemory((cpu->q+wordut)%65536) #define signed8(x) (x>=128 ? x|0xFF00 : x) #define setzf(x) cpu->nz=(x!=0); #define loadimmedt cpu->t = loadimmed; #define loadimm161 cpu->u = loadimmed; #define loadimm162 cpu->t = loadimmed; #define loadstackrelu cpu->u = loadstackrel; #define storestackrel(x) writememory(cpu->t, x); #define storestackrelu storestackrel(cpu->u); #define storestackrel161(x) writememory(cpu->t , hibyte(x)); #define storestackrel162(x) writememory(cpu->t+1, lobyte(x)); #define loadstackrel161 cpu->u=loadstackrel; #define loadstackrel162 cpu->t=loadstackrelp1; #define storeut(x) writememory(wordut, x); #define storeutp1(x) writememory((wordut+1)%65536, x); #define storep(x) writememory(cpu->p, x); #define storeq(x) writememory(cpu->q, x); #define storepinc(x) writememory(cpu->p++, x); #define storeqinc(x) writememory(cpu->q++, x); #define storepp1(x) writememory((cpu->p+1)%65536, x); #define storeqp1(x) writememory((cpu->q+1)%65536, x); #define storeput(x) writememory((cpu->p+wordut)%65536, x); #define storequt(x) writememory((cpu->q+wordut)%65536, x); #define pushretaddr1 writememory(((cpu->s++)%256)+0x0100, hibyte((cpu->i-1)%65536)); #define pushretaddr2 writememory(((cpu->s++)%256)+0x0100, lobyte((cpu->i-1)%65536)); #define lni cpu->instr = readmemory(cpu->i++); cpu->cycle = 0; #define ldi cpu->instr = readmemory(cpu->i); cpu->cycle = 0; #define addf(x,y) { x=(x+y)&0x1FF; cpu->cf=x>=256; x&=0xFF; setzf(x); } #define subf(x,y) addf(x,(-y)&0xFF); #define cmpf(x,y) { int t=x+((-y)&0xFF); cpu->cf=t>=256; t&=0xFF; setzf(t); } #define rol(x,y) x=(x<>(8-y)); #define ror(x,y) x=(x>>y)|(x<<(8-y)); #define sra(x,y) x=(x>>y); #define jmpabsp cpu->i=cpu->p; lni; #define jmpabsq cpu->i=cpu->q; lni; #define jmpabsut cpu->i=wordut; lni; #define jmpabsutplus1 cpu->i=(wordut+1)%65536; lni; #define pushbyte(b) writememory(((cpu->s++)%256)+0x0100, b); #define push161(x) pushbyte(hibyte(x)); #define push162(x) pushbyte(lobyte(x)); #define pop161 cpu->t=popbyte; #define pop162 cpu->u=popbyte; #define tst(x) cpu->cf = x>=128; cpu->nz = x!=0; #define instrpreload cpu->instrpre = loadimmed; #define instrloadpre cpu->instr = cpu->instrpre; cpu->cycle = 0; #define jmprelt cpu->i = (cpu->i + signed8(cpu->t))%65536; lni; #define saveretaddr cpu->q = (cpu->i+1)%65536; #define readmemory(x) _readmemory(cpu, mem, x) #define writememory(x, y) _writememory(cpu, mem, x, y) struct CPU { int a; int b; int c; int u; int t; int p; int q; int s; int v; int i; int cf; int nz; int irq; int ifg; int rfg; int ien; int instr; int cycle; int instrpre; int frame; }; struct Event { int id; int addr; }; struct Memory { int data[65536]; int canwrite[65536]; int writes[65536]; int reads[65536]; int onread[65536]; int onwrite[65536]; struct Event events[4096]; int numevents; }; void postEvent(struct Memory* const mem, int id, int addr) { if(mem->numevents<4096) { mem->events[mem->numevents].id = id; mem->events[mem->numevents].addr = addr; mem->numevents++; } } int _readmemory(const struct CPU* const cpu, struct Memory* const mem, const int addr) { int addr2 = addr%65536; mem->reads[addr2] = cpu->frame; if(mem->onread[addr2]) { postEvent(mem, mem->onread[addr2], addr2); } return mem->data[addr2]; } int _writememory(const struct CPU* const cpu, struct Memory* const mem, const int addr, const int data) { int addr2 = addr%65536; if(mem->canwrite[addr2]) { mem->writes[addr2] = cpu->frame; mem->data[addr2] = data%256; } if(mem->onwrite[addr2]) { postEvent(mem, mem->onwrite[addr2], addr2); } } typedef void(*CPUInstruction)(struct CPU* const cpu, struct Memory* const mem); #include "instructions_gen.c" int TickCPU(struct CPU* const cpu, struct Memory* const mem, const int count, const int countinstrs, const int breakaddr) { int i = 0; while(iirq && !cpu->ifg && cpu->cycle==0 && cpu->ien) { cpu->instr = 0x01; } if(cpu->rfg || cpu->ifg || (cpu->irq && cpu->ien)) { CPUInstruction instr = CPUInstructions[cpu->instr][cpu->cycle]; if(instr) instr(cpu, mem); if(!countinstrs || cpu->cycle==0) { i++; } if(cpu->i==breakaddr) { i = count; break; } } else { i = count; break; } if(mem->numevents!=0) { break; } } return count-i; }