156 lines
5.2 KiB
C
156 lines
5.2 KiB
C
// 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<<y)|(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(i<count) {
|
|
if(cpu->irq && !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;
|
|
}
|