From 6c07508a33c15bd29cd4499d05dc939df5d7a09e Mon Sep 17 00:00:00 2001 From: yuvia Date: Sun, 7 Sep 2025 14:36:05 +0000 Subject: [PATCH] try again --- scemu.c | 847 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 847 insertions(+) create mode 100644 scemu.c diff --git a/scemu.c b/scemu.c new file mode 100644 index 0000000..bd0f26f --- /dev/null +++ b/scemu.c @@ -0,0 +1,847 @@ +#include +#include + +enum { + Negative = 1<<7, + Overflow = 1<<6, + Break = 1<<4, + Decimal = 1<<3, + Interrupt = 1<<2, + Zero = 1<<1, + Carry = 1 +}; + +int step(void); +static u16int fetch16(void); + +u8int mem[65536]; +u8int rA, rS, rX, rY, rP; +u16int pc; + +int irq, nmi; + +u8int *prog; + +void +usage(void) +{ + fprint(2, "usage: %s [ -s target speed ] [ prog ]\n", argv0); + exits("usage"); +} + +void +openprog(char *f, vlong *progsiz) +{ + int fd; + long n; + Dir *d; + + prog = nil; + if(f == nil) + f = "a.out"; + fd = open(f, OREAD); + if(fd < 0) + return; + d = dirfstat(fd); + *progsiz = d->length; + free(d); + prog = malloc(*progsiz); + if(prog == nil) + sysfatal("bad malloc"); + n = read(fd, prog, *progsiz); + if(n != *progsiz) + fprint(2, "tried to read %lld bytes, got only %ld bytes\n", *progsiz, n); + close(fd); +} + +void +main(int argc, char **argv) +{ + int c; + vlong t, t2, t3, progsiz; + vlong target; + + target = 1000; + ARGBEGIN{ + case 's': + target = atoll(EARGF(usage())); + break; + default: + usage(); + break; + }ARGEND + openprog(*argv, &progsiz); + if(prog == nil) + sysfatal("bad program: %r"); + memmove(mem+0x8000, prog, progsiz); + rP = 0x34; + pc = 0xFFFC; + pc = fetch16(); + for(;;){ + c = step(); + while(c >= 0){ + t = nsec(); + --c; + t2 = nsec(); + t3 = t2-t; + while(t3 < target){ + t2 = nsec(); + t3 = t2-t; + } + } + } +} + +static void +push8(u8int v) +{ + mem[0x100 | rS--] = v; +} + +static void +push16(u16int v) +{ + mem[0x100 | rS--] = v >> 8; + mem[0x100 | rS--] = v&0xff; +} + +static u8int +pop8(void) +{ + return mem[0x100 | ++rS]; +} + +static u16int +pop16(void) +{ + u16int v; + + v = mem[0x100 | ++rS]; + v |= mem[0x100 | ++rS] << 8; + return v; +} + +static u8int +fetch8(void) +{ + return mem[pc++]; +} + +static u16int +fetch16(void) +{ + u16int v; + + v = fetch8(); + v |= fetch8() << 8; + return v; +} + +static void +nz(u8int v) +{ + rP &= ~(Negative | Zero); + if(v & 0x80) + rP |= Negative; + if(v == 0) + rP |= Zero; +} + +static void +adc(u8int d) +{ + int r; + + r = rA + d + (rP & Carry); + rP &= ~(Negative | Zero | Overflow | Carry); + if(r > 0xFF) rP |= Carry; + if(r & 0x80) rP |= Negative; + if((~(rA ^ d) & (rA ^ r)) & 0x80) rP |= Overflow; + rA = r; + if(rA == 0) rP |= Zero; +} + +static void +sbc(u8int d) +{ + int r; + + r = rA + (u8int)~d + (rP & Carry); + rP &= ~(Negative | Zero | Overflow | Carry); + if(r > 0xFF) rP |= Carry; + if((~(rA ^ d) & (rA ^ r)) & 0x80) rP |= Overflow; + rA = r; + if(rA == 0) rP |= Zero; + if(rA & 0x80) rP |= Negative; +} + +static void +asl(u16int a) +{ + u8int v; + + rP &= ~(Negative | Zero | Carry); + v = mem[a]; + if(v & 0x80) + rP |= Carry; + v <<= 1; + if(v == 0) + rP |= Zero; + if(v & 0x80) + rP |= Negative; + mem[a] = v; +} + +static void +lsr(u16int a) +{ + u8int v; + + v = mem[a]; + rP &= ~(Negative | Zero | Carry); + rP |= v & 1; + v >>= 1; + if(v == 0) rP |= Zero; + if(v & 0x80) rP |= Negative; + mem[a] = v; +} + +static void +rol(u16int a) +{ + u8int v, b; + + v = mem[a]; + b = rP & Carry; + rP &= ~(Carry | Negative | Zero); + if(v & 0x80) rP |= Carry; + v = (v << 1) | b; + if(v & 0x80) rP |= Negative; + if(v == 0) rP |= Zero; + mem[a] = v; +} + +static void +ror(u16int a) +{ + u8int v, b; + + v = mem[a]; + b = rP & Carry; + rP &= ~(Carry | Negative | Zero); + rP |= v & 1; + v = (v >> 1) | (b << 7); + if(v & 0x80) rP |= Negative; + if(v == 0) rP |= Zero; + mem[a] = v; +} + +static void +cmp(u8int A, u8int B) +{ + rP &= ~(Negative | Zero | Carry); + if(A == B) rP |= Zero; + if(A >= B) rP |= Carry; + if((A - B) & 0x80) rP |= Negative; +} + +static void +inc(u16int a) +{ + u8int v; + + v = mem[a]; + v++; + nz(v); + mem[a] = v; +} + +static void +dec(u16int a) +{ + u8int v; + + v = mem[a]; + v--; + nz(v); + mem[a] = v; +} + +static int +branch(void) +{ + s8int t; + u16int npc; + + t = fetch8(); + npc = pc+t; + if((npc ^ pc) >> 8){ + pc = npc; + return 4; + } + pc = npc; + return 3; +} + +static u16int +aindX(void) +{ + u8int r; + u16int b; + + r = fetch8() + rX; + b = mem[r++]; + b |= mem[r] << 8; + return b; +} + +static u16int +aindY(int *p) +{ + u8int r; + u16int b; + + r = fetch8(); + b = mem[r++] + rY; + *p = b > 0xFF; + b += mem[r] << 8; + return b; +} + +static void +interrupt(int nmi, int brk) +{ + push16(pc); + push8(rP | 0x20 | (brk << 4)); + pc = mem[0xFFFA | (!nmi << 2)]; + pc |= mem[0xFFFB | (!nmi << 2)] << 8; + rP |= Interrupt; +} + +#define zp() mem[fetch8()] +#define zpX() mem[(u8int)(fetch8()+rX)] +#define zpY() mem[(u8int)(fetch8()+rY)] +#define abso() mem[fetch16()] +#define absX() mem[a = fetch16()+rX] +#define absY() mem[a = fetch16()+rY] +#define indX() mem[aindX()] +#define indY(c) mem[aindY(c)] + +int +step(void) +{ + u8int op; + u16int a, v, cpc; + int c; + + if(nmi) + if(--nmi == 0){ + interrupt(1, 0); + nmi = 0; + return 7; + } + if(irq && (rP & Interrupt) == 0){ + interrupt(0, 0); + return 7; + } + cpc = pc; + op = fetch8(); + print("%02x %08b %08b %08b %08b %04x %02x\n", + op, rA, rX, rY, rP, cpc, rS); + switch(op){ + case 0x00: + pc++; + interrupt(0, 1); + return 7; + case 0x01: + nz(rA |= indX()); + return 6; + case 0x05: + nz(rA |= zp()); + return 3; + case 0x06: + asl(fetch8()); + return 5; + case 0x08: + push8(rP | 0x30); + return 3; + case 0x09: + nz(rA |= fetch8()); + return 2; + case 0x0A: + rP &= ~(Negative | Zero | Carry); + if(rA & 0x80) rP |= Carry; + rA <<= 1; + if(rA == 0) rP |= Zero; + if(rA & 0x80) rP |= Negative; + return 2; + case 0x0D: + nz(rA |= abso()); + return 4; + case 0x0E: + asl(fetch16()); + return 6; + case 0x10: + if((rP & Negative) == 0) return branch(); + pc++; + return 2; + case 0x11: + nz(rA |= indY(&c)); + return 5+c; + case 0x15: + nz(rA |= zpX()); + return 4; + case 0x16: + asl((u8int)(fetch8() + rX)); + return 6; + case 0x18: + rP &= ~Carry; + return 2; + case 0x19: + nz(rA |= absY()); + return 4 + ((u8int)a < rY); + case 0x1D: + nz(rA |= absX()); + return 4 + ((u8int)a < rX); + case 0x1E: + asl(fetch16() + rX); + return 7; + case 0x20: + push16(pc+1); + pc = fetch16(); + return 6; + case 0x21: + nz(rA &= indX()); + return 6; + case 0x24: + a = mem[fetch8()]; + rP &= ~(Negative | Zero | Overflow); + rP |= a & 0xC0; + if((a & rA) == 0) rP |= Zero; + return 3; + case 0x25: + nz(rA &= zp()); + return 3; + case 0x26: + rol(fetch8()); + return 5; + case 0x28: + rP = pop8() & 0xcf; + return 4; + case 0x29: + nz(rA &= fetch8()); + return 2; + case 0x2A: + a = rP & Carry; + rP &= ~(Carry | Zero | Negative); + if(rA & 0x80) rP |= Carry; + rA = (rA << 1) | a; + if(rA & 0x80) rP |= Negative; + if(rA == 0) rP |= Zero; + return 2; + case 0x2C: + a = mem[fetch16()]; + rP &= ~(Negative | Zero | Overflow); + rP |= a & 0xC0; + if((a & rA) == 0) rP |= Zero; + return 4; + case 0x2D: + nz(rA &= abso()); + return 4; + case 0x2E: + rol(fetch16()); + return 6; + case 0x30: + if((rP & Negative) != 0) return branch(); + pc++; + return 3; + case 0x31: + nz(rA &= indY(&c)); + return 5+c; + case 0x35: + nz(rA &= zpX()); + return 4; + case 0x36: + rol((u8int)(fetch8() + rX)); + return 6; + case 0x38: + rP |= Carry; + return 2; + case 0x39: + nz(rA &= absY()); + return 4 + ((u8int)a < rY); + case 0x3E: + rol(fetch16() + rX); + return 7; + case 0x3D: + nz(rA &= absX()); + return 4 + ((u8int)a < rX); + case 0x40: + rP = pop8() & 0xcf; + pc = pop16(); + return 6; + case 0x41: + nz(rA ^= indX()); + return 6; + case 0x45: + nz(rA ^= zp()); + return 3; + case 0x46: + lsr(fetch8()); + return 5; + case 0x48: + push8(rA); + return 3; + case 0x49: + nz(rA ^= fetch8()); + return 2; + case 0x4A: + rP &= ~(Negative | Zero | Carry); + rP |= rA & 1; + rA >>= 1; + if(rA == 0) rP |= Zero; + if(rA & 0x80) rP |= Negative; + return 2; + case 0x4C: + pc = fetch16(); + return 3; + case 0x4D: + nz(rA ^= abso()); + return 4; + case 0x4E: + lsr(fetch16()); + return 6; + case 0x51: + nz(rA ^= indY(&c)); + return 5+c; + case 0x56: + lsr((u8int)(fetch8() + rX)); + return 6; + case 0x58: + rP &= ~Interrupt; + return 2; + case 0x50: + if((rP & Overflow) == 0) return branch(); + pc++; + return 3; + case 0x55: + nz(rA ^= zpX()); + return 4; + case 0x59: + nz(rA ^= absY()); + return 4 + ((u8int)a < rX); + case 0x5D: + nz(rA ^= absX()); + return 4 + ((u8int)a < rX); + case 0x5E: + lsr(fetch16() + rX); + return 7; + case 0x60: + pc = pop16() + 1; + return 6; + case 0x61: + adc(indX()); + return 6; + case 0x65: + adc(zp()); + return 3; + case 0x66: + ror(fetch8()); + return 5; + case 0x68: + nz(rA = pop8()); + return 4; + case 0x69: + adc(fetch8()); + return 2; + case 0x6A: + a = rP & Carry; + rP &= ~(Carry | Negative | Zero); + rP |= rA & 1; + rA = (rA >> 1) | (a << 7); + if(rA & 0x80) rP |= Negative; + if(rA == 0) rP |= Zero; + return 2; + case 0x6C: + v = fetch16(); + pc = mem[v] | (mem[(v & 0xFF00) | (u8int)(v+1)] << 8); + return 5; + case 0x6D: + adc(abso()); + return 4; + case 0x6E: + ror(fetch16()); + return 6; + case 0x70: + if((rP & Overflow) != 0) return branch(); + pc++; + return 3; + case 0x71: + adc(indY(&c)); + return 5+c; + case 0x75: + adc(zpX()); + return 4; + case 0x76: + ror((u8int)(fetch8() + rX)); + return 6; + case 0x78: + rP |= Interrupt; + return 2; + case 0x79: + adc(absY()); + return 4 + ((u8int)a < rY); + case 0x7D: + adc(absX()); + return 4 + ((u8int)a < rX); + case 0x7E: + ror(fetch16() + rX); + return 7; + case 0x81: + mem[aindX()] = rA; + return 6; + case 0x84: + mem[fetch8()] = rY; + return 3; + case 0x85: + mem[fetch8()] = rA; + return 3; + case 0x86: + mem[fetch8()] = rX; + return 3; + case 0x88: + nz(--rY); + return 2; + case 0x8A: + nz(rA = rX); + return 2; + case 0x8C: + mem[fetch16()] = rY; + return 4; + case 0x8D: + mem[fetch16()] = rA; + return 4; + case 0x8E: + mem[fetch16()] = rX; + return 4; + case 0x90: + if((rP & Carry) == 0) return branch(); + pc++; + return 3; + case 0x91: + mem[aindY(&c)] = rA; + return 6; + case 0x94: + mem[(u8int)(fetch8() + rX)] = rY; + return 4; + case 0x95: + mem[(u8int)(fetch8() + rX)] = rA; + return 4; + case 0x96: + mem[(u8int)(fetch8() + rY)] = rX; + return 4; + case 0x98: + nz(rA = rY); + return 2; + case 0x99: + mem[fetch16() + rY] = rA; + return 5; + case 0x9A: + rS = rX; + return 2; + case 0x9D: + mem[fetch16() + rX] = rA; + return 5; + case 0xA0: + nz(rY = fetch8()); + return 2; + case 0xA1: + nz(rA = indX()); + return 6; + case 0xA2: + nz(rX = fetch8()); + return 2; + case 0xA4: + nz(rY = zp()); + return 3; + case 0xA5: + nz(rA = zp()); + return 3; + case 0xA6: + nz(rX = zp()); + return 3; + case 0xA8: + nz(rY = rA); + return 2; + case 0xA9: + nz(rA = fetch8()); + return 2; + case 0xAA: + nz(rX = rA); + return 2; + case 0xAC: + nz(rY = abso()); + return 4; + case 0xAE: + nz(rX = abso()); + return 4; + case 0xAD: + nz(rA = abso()); + return 4; + case 0xB0: + if((rP & Carry) != 0) return branch(); + pc++; + return 3; + case 0xB1: + nz(rA = indY(&c)); + return 5+c; + case 0xB4: + nz(rY = zpX()); + return 4; + case 0xB5: + nz(rA = zpX()); + return 4; + case 0xB6: + nz(rX = zpY()); + return 4; + case 0xB8: + rP &= ~Overflow; + return 2; + case 0xB9: + nz(rA = absY()); + return 4 + ((u8int)a < rY); + case 0xBA: + nz(rX = rS); + return 2; + case 0xBC: + nz(rY = absX()); + return 4 + ((u8int)a < rX); + case 0xBD: + nz(rA = absX()); + return 4 + ((u8int)a < rX); + case 0xBE: + nz(rX = absY()); + return 4 + ((u8int)a < rY); + case 0xC1: + cmp(rA, indX()); + return 6; + case 0xC5: + cmp(rA, zp()); + return 3; + case 0xC9: + cmp(rA, fetch8()); + return 2; + case 0xCD: + cmp(rA, abso()); + return 4; + case 0xD0: + if((rP & Zero) == 0) return branch(); + pc++; + return 3; + case 0xD1: + cmp(rA, indY(&c)); + return 5 + c; + case 0xD5: + cmp(rA, zpX()); + return 4; + case 0xD8: + rP &= ~Decimal; + return 2; + case 0xD9: + cmp(rA, absY()); + return 4 + ((u8int)a < rY); + case 0xDD: + cmp(rA, absX()); + return 4 + ((u8int)a < rX); + case 0xC0: + cmp(rY, fetch8()); + return 2; + case 0xC4: + cmp(rY, zp()); + return 3; + case 0xC6: + dec(fetch8()); + return 5; + case 0xC8: + nz(++rY); + return 2; + case 0xCA: + nz(--rX); + return 2; + case 0xCC: + cmp(rY, abso()); + return 4; + case 0xCE: + dec(fetch16()); + return 6; + case 0xD6: + dec((u8int)(fetch8() + rX)); + return 6; + case 0xDE: + dec(fetch16() + rX); + return 7; + case 0xE0: + cmp(rX, fetch8()); + return 2; + case 0xE1: + sbc(indX()); + return 6; + case 0xE4: + cmp(rX, zp()); + return 3; + case 0xE5: + sbc(zp()); + return 3; + case 0xE6: + inc(fetch8()); + return 5; + case 0xE8: + nz(++rX); + return 2; + case 0xE9: + sbc(fetch8()); + return 2; + case 0xEA: + return 2; + case 0xEC: + cmp(rX, abso()); + return 4; + case 0xED: + sbc(abso()); + return 4; + case 0xEE: + inc(fetch16()); + return 6; + case 0xF0: + if((rP & Zero) != 0) return branch(); + pc++; + return 3; + case 0xF1: + sbc(indY(&c)); + return 5+c; + case 0xF5: + sbc(zpX()); + return 4; + case 0xF6: + inc((u8int)(fetch8() + rX)); + return 6; + case 0xF8: + rP |= Decimal; + return 2; + case 0xF9: + sbc(absY()); + return 4 + ((u8int)a < rY); + case 0xFD: + sbc(absX()); + return 4 + ((u8int)a < rX); + case 0xFE: + inc(fetch16() + rX); + return 7; + default: + print("unimplemented %#02x\n", op); + exits(nil); + case 0xFF: + print("%s\n", (s8int*)mem+0x500); + exits(nil); + } +}