diff options
author | aiju <devnull@localhost> | 2014-03-13 20:07:36 +0100 |
---|---|---|
committer | aiju <devnull@localhost> | 2014-03-13 20:07:36 +0100 |
commit | 85a414751a1b9ba09dd7a72eee8746d81a7dcf53 (patch) | |
tree | 6f07928c81f37dd99b84b60a00433d114c41e8a7 /sys/src | |
parent | eed487167489ee16dd16effe9ebff9a5086ffc70 (diff) |
added games/snes
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/games/snes/cpu.c | 961 | ||||
-rw-r--r-- | sys/src/games/snes/dat.h | 70 | ||||
-rw-r--r-- | sys/src/games/snes/fns.h | 13 | ||||
-rw-r--r-- | sys/src/games/snes/mem.c | 509 | ||||
-rw-r--r-- | sys/src/games/snes/mkfile | 14 | ||||
-rw-r--r-- | sys/src/games/snes/ppu.c | 548 | ||||
-rw-r--r-- | sys/src/games/snes/snes.c | 258 | ||||
-rw-r--r-- | sys/src/games/snes/spc.c | 740 |
8 files changed, 3113 insertions, 0 deletions
diff --git a/sys/src/games/snes/cpu.c b/sys/src/games/snes/cpu.c new file mode 100644 index 000000000..73ab20940 --- /dev/null +++ b/sys/src/games/snes/cpu.c @@ -0,0 +1,961 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include "dat.h" +#include "fns.h" + +u8int rP, emu, irq, nmi, dma; +u16int rA, rX, rY, rS, rD, pc; +u32int rDB, rPB, curpc, hdma; +static u8int m8, x8; +static int cyc; +static u32int lastpc; + +static u8int +fetch8(void) +{ + return memread(pc++ | rPB); +} + +static u16int +fetch16(void) +{ + u16int r; + + r = memread(pc++ | rPB); + r |= memread(pc++ | rPB) << 8; + return r; +} + +static u16int +mem16(u32int a) +{ + u16int r; + + r = memread(a++); + r |= memread(a) << 8; + return r; +} + +static u16int +mem816(u32int a, u16int v) +{ + if(m8) + return memread(a) | v; + cyc++; + return mem16(a); +} + +static u16int +memx816(u32int a) +{ + if(x8) + return memread(a); + cyc++; + return mem16(a); +} + + +static void +memw816(u32int a, u16int v) +{ + memwrite(a, v); + if(m8) + return; + memwrite(++a, v >> 8); + cyc++; +} + +static void +memwx816(u32int a, u16int v) +{ + memwrite(a, v); + if(x8) + return; + memwrite(++a, v >> 8); + cyc++; +} + +static void +push8(u8int a) +{ + memwrite(rS, a); + if(emu && (rS & 0xFF) == 0) + rS |= 0xFF; + else + rS--; +} + +static u8int +pop8(void) +{ + if(emu && (rS & 0xFF) == 0xFF) + rS &= ~0xFF; + else + rS++; + return memread(rS); +} + +static void +push16(u16int a) +{ + push8(a >> 8); + push8(a); +} + +static u16int +pop16(void) +{ + u16int r; + + r = pop8(); + r |= pop8() << 8; + return r; +} + +static void +push816(u16int v, int m) +{ + if(!m){ + push8(v >> 8); + cyc++; + } + push8(v); +} + +static u16int +pop816(u16int a, int m) +{ + u16int r; + + r = pop8(); + if(m) + return r | a; + cyc++; + r |= pop8() << 8; + return r; +} + +static u16int +nz8(u16int v) +{ + rP &= ~(FLAGN | FLAGZ); + if((v & 0xFF) == 0) + rP |= FLAGZ; + rP |= (v & 0x80); + return v; +} + +static u16int +nz16(u16int v) +{ + rP &= ~(FLAGN | FLAGZ); + if(v == 0) + rP |= FLAGZ; + if((v & 0x8000) != 0) + rP |= FLAGN; + return v; +} + +static u16int +nz(u16int v) +{ + if(m8) + return nz8(v); + return nz16(v); +} + +static u16int +nzx(u16int v) +{ + if(x8) + return nz8(v); + return nz16(v); +} + +static u16int +imm(int a) +{ + if(m8) + return fetch8() | a; + cyc++; + return fetch16(); +} + +static u16int +immx(int a) +{ + if(x8) + return fetch8() | a; + cyc++; + return fetch16(); +} + +static u32int +abso(int l, int x) +{ + u32int p; + + p = fetch16(); + if(l) + p |= fetch8() << 16; + else + p |= rDB; + switch(x){ + case 1: p += rX; break; + case 2: p += rY; break; + } + return p; +} + +static u32int +absi(int x) +{ + u16int p; + u32int b, r; + + p = fetch16(); + if(x){ + p += rX; + b = rPB; + }else + b = 0; + r = memread(p++ | b); + r |= memread(p | b) << 8; + return r; +} + +static u32int +dp(int x) +{ + u32int p; + + if((rD & 0xFF) != 0) + cyc++; + p = fetch8(); + switch(x){ + case 1: p += rX; break; + case 2: p += rY; break; + } + if(emu && (rD & 0xFF) == 0) + p = rD & 0xFF00 | p & 0xFF; + else + p = (p + rD) & 0xFFFF; + return p; +} + +static u32int +dpi(int l, int x, int y) +{ + u32int p, r, s; + u32int b; + + p = dp(x); + r = memread(p++); + if(emu && (rD & 0xFF) == 0){ + if((p & 0xFF) == 0) + p -= 0x100; + }else + p &= 0xFFFF; + r |= memread(p++) << 8; + if(l){ + if(emu && (rD & 0xFF) == 0){ + if((p & 0xFF) == 0) + p -= 0x100; + }else + p &= 0xFFFF; + b = memread(p) << 16; + }else + b = rDB; + if(y){ + s = r + rY; + if(x8 && ((r ^ s) & 0xFF00) != 0) + cyc++; + r = s; + } + r += b; + return r; +} + +static u32int +sr(void) +{ + return (rS + fetch8()) & 0xFFFF; +} + +static u32int +sry(void) +{ + return (mem16((rS + fetch8()) & 0xFFFF) | rDB) + rY; +} + +static void +rmw(u32int a, u16int, u16int w) +{ + memw816(a, w); + nz(w); +} + +static int +branch(void) +{ + signed char t; + u16int npc; + + t = fetch8(); + npc = pc + t; + if(emu && (npc ^ pc) >> 8){ + pc = npc; + return 4; + } + pc = npc; + return 3; +} + +static void +setrp(u8int v) +{ + if(emu) + v |= 0x30; + else if((v & 0x10) != 0){ + rX &= 0xff; + rY &= 0xff; + } + rP = v; +} + +static void +adc(u16int a) +{ + int r; + + if((rP & FLAGD) != 0) + print("decimal mode\n"); + if(m8){ + r = (rA & 0xff) + a + (rP & FLAGC); + rP &= ~(FLAGC | FLAGN | FLAGV | FLAGZ); + if(r > 0xFF) + rP |= FLAGC; + rP |= r & 0x80; + if((~(rA ^ a) & (rA ^ r)) & 0x80) + rP |= FLAGV; + r &= 0xFF; + if(r == 0) + rP |= FLAGZ; + rA = rA & 0xFF00 | r; + }else{ + r = rA + a + (rP & FLAGC); + rP &= ~(FLAGC | FLAGN | FLAGV | FLAGZ); + if(r > 0xFFFF) + rP |= FLAGC; + if((r & 0x8000) != 0) + rP |= FLAGN; + if((~(rA ^ a) & (rA ^ r)) & 0x8000) + rP |= FLAGV; + rA = r; + if(rA == 0) + rP |= FLAGZ; + } +} + +static void +asl(u32int a) +{ + u16int v; + + v = mem816(a, 0); + rP &= ~FLAGC; + rP |= v >> (m8 ? 7 : 15); + rmw(a, v, v << 1); +} + +static void +bit(u16int a) +{ + rP &= ~(FLAGN | FLAGZ | FLAGV); + if((a & rA) == 0) + rP |= FLAGZ; + if(m8) + rP |= a & 0xC0; + else + rP |= (a >> 8) & 0xC0; +} + +static void +block(int incr) +{ + u32int sb; + + rDB = fetch8() << 16; + sb = fetch8() << 16; + memwrite(rDB | rY, memread(sb | rX)); + if(incr){ + rX++; + rY++; + }else{ + rX--; + rY--; + } + if(x8){ + rX &= 0xff; + rY &= 0xff; + } + if(rA-- != 0) + pc -= 3; +} + +static void +cmp(u16int a, u16int b, int m) +{ + if(m){ + a &= 0xff; + b &= 0xff; + } + rP &= ~(FLAGN | FLAGZ | FLAGC); + if(a == b) + rP |= FLAGZ; + if(a >= b) + rP |= FLAGC; + if((a - b) & (m ? 0x80 : 0x8000)) + rP |= FLAGN; +} + +static void +dec(u32int a) +{ + u16int v; + + v = mem816(a, 0); + rmw(a, v, v-1); +} + +static void +inc(u32int a) +{ + u16int v; + + v = mem816(a, 0); + rmw(a, v, v+1); +} + +static void +lsr(u32int a) +{ + u16int v; + + v = mem816(a, 0); + rP &= ~FLAGC; + rP |= v & 1; + rmw(a, v, v>>1); +} + +static void +rol(u32int a) +{ + u16int v, w; + + v = rP & FLAGC; + w = mem816(a, 0); + rP &= ~FLAGC; + rP |= w >> (m8 ? 7 : 15); + rmw(a, w, w<<1 | v); +} + +static void +ror(u32int a) +{ + u16int v, w; + + v = (rP & FLAGC) << (m8 ? 7 : 15); + w = mem816(a, 0); + rP &= ~FLAGC; + rP |= w & 1; + rmw(a, w, w>>1 | v); +} + +static void +sbc(u16int a) +{ + int r; + + if((rP & FLAGD) != 0) + print("decimal mode\n"); + if(m8){ + r = (rA & 0xff) + (a ^ 0xff) + (rP & FLAGC); + rP &= ~(FLAGC | FLAGN | FLAGV | FLAGZ); + if(r > 0xFF) + rP |= FLAGC; + rP |= r & 0x80; + if(((rA ^ a) & (rA ^ r)) & 0x80) + rP |= FLAGV; + r &= 0xFF; + if(r == 0) + rP |= FLAGZ; + rA = rA & 0xFF00 | r; + }else{ + r = rA + (a ^ 0xffff) + (rP & FLAGC); + rP &= ~(FLAGC | FLAGN | FLAGV | FLAGZ); + if(r > 0xFFFF) + rP |= FLAGC; + if((r & 0x8000) != 0) + rP |= FLAGN; + if(((rA ^ a) & (rA ^ r)) & 0x8000) + rP |= FLAGV; + rA = r; + if(rA == 0) + rP |= FLAGZ; + } + +} + +static void +setra(u16int a) +{ + if(m8) + rA = rA & 0xff00 | nz8(a & 0xff); + else + rA = nz16(a); +} + +static void +setx(u16int a, u16int *b) +{ + if(x8) + *b = nz8(a & 0xff); + else + *b = nz16(a); +} + +static void +tsb(u32int a, int set) +{ + u16int v; + + v = mem816(a, 0); + rP &= ~FLAGZ; + if(m8){ + if((rA & v & 0xFF) == 0) + rP |= FLAGZ; + }else + if((rA & v) == 0) + rP |= FLAGZ; + if(set) + memw816(a, v | rA); + else + memw816(a, v & ~rA); +} + +enum { COP = 0, BRK = 1, NMI = 3, IRQ = 5 }; + +static void +interrupt(int src) +{ + if(!emu) + push8(rPB >> 16); + push16(pc); + if(emu && src != BRK) + push8(rP & ~(1<<5)); + else + push8(rP); + if(emu && src == BRK) + src = IRQ; + pc = mem16(0xffe4 + src * 2 + emu * 0x10); + rP |= FLAGI; + rP &= ~FLAGD; + rPB = 0; + if(emu) + rDB = 0; +} + +void +cpureset(void) +{ + pc = mem16(0xfffc); + rD = 0; + rDB = 0; + rPB = 0; + rS = 0x100; + rP = 0x35; +} + +int trace; + +int +cpustep(void) +{ + u8int op; + int a; + static int cnt; + + if(nmi) + if(--nmi == 0){ + interrupt(NMI); + return 8 - emu; + } + if((hdma & 0xffff) != 0){ + curpc = -1; + return hdmastep(); + } + if(dma){ + curpc = -1; + return dmastep(); + } + if(irq && (rP & FLAGI) == 0){ + interrupt(IRQ); + return 8 - emu; + } + curpc = pc|rPB; + m8 = (rP & FLAGM) != 0; + x8 = (rP & FLAGX) != 0; + op = fetch8(); + if(op == 0) + print("BRK PC=%.6x from PC=%.6x\n", curpc, lastpc); + lastpc = curpc; + if(trace) + print("%.6x %.2x A=%.4x X=%.4x Y=%.4x P=%.2x %.2x %x\n", curpc, op, rA, rX, rY, rP, rS, memread(0x05)); + cyc = 0; + switch(op){ + case 0x00: pc++; interrupt(BRK); return 8 - emu; + case 0x01: nz(rA |= mem816(dpi(0, 1, 0), 0)); return 6+cyc; + case 0x02: pc++; interrupt(COP); return 8 - emu; + case 0x03: nz(rA |= mem816(sr(), 0)); return 4+cyc; + case 0x04: tsb(dp(0), 1); return 5+cyc; + case 0x05: nz(rA |= mem816(dp(0), 0)); return 3+cyc; + case 0x06: asl(dp(0)); return 5+cyc; + case 0x07: nz(rA |= mem816(dpi(1, 0, 0), 0)); return 6+cyc; + case 0x08: push8(rP); return 3+cyc; + case 0x09: nz(rA |= imm(0)); return 3+cyc; + case 0x0A: + rP &= ~FLAGC; + if(m8){ + rP |= (rA >> 7) & 1; + rA = (rA & 0xFF00) | ((rA << 1) & 0xFF); + }else{ + rP |= (rA >> 15) & 1; + rA <<= 1; + } + nz(rA); + return 2; + case 0x0B: push16(rD); return 4+cyc; + case 0x0C: tsb(abso(0, 0), 1); return 6+cyc; + case 0x0D: nz(rA |= mem816(abso(0, 0), 0)); return 4+cyc; + case 0x0E: asl(abso(0, 0)); return 6+cyc; + case 0x0F: nz(rA |= mem816(abso(1, 0), 0)); return 5+cyc; + case 0x10: if((rP & FLAGN) == 0) return branch(); pc++; return 2; + case 0x11: nz(rA |= mem816(dpi(0, 0, 1), 0)); return 5+cyc; + case 0x12: nz(rA |= mem816(dpi(0, 0, 0), 0)); return 5+cyc; + case 0x13: nz(rA |= mem816(sry(), 0)); return 7+cyc; + case 0x14: tsb(dp(0), 0); return 5+cyc; + case 0x15: nz(rA |= mem816(dp(1), 0)); return 4+cyc; + case 0x16: asl(dp(1)); return 6+cyc; + case 0x17: nz(rA |= mem816(dpi(1, 0, 1), 0)); return 6+cyc; + case 0x18: rP &= ~FLAGC; return 2; + case 0x19: nz(rA |= mem816(abso(0, 2), 0)); return 4+cyc; + case 0x1A: + if(m8 && (rA & 0xFF) == 0xFF) + rA &= ~0xFF; + else + rA++; + nz(rA); + return 2; + case 0x1B: rS = rA; if(emu) rS = rS & 0xff | 0x100; return 2; + case 0x1C: tsb(abso(0, 0), 0); return 6+cyc; + case 0x1D: nz(rA |= mem816(abso(0, 1), 0)); return 4+cyc; + case 0x1E: asl(abso(0, 1)); return 7+cyc; + case 0x1F: nz(rA |= mem816(abso(1, 1), 0)); return 4+cyc; + case 0x20: push16(pc+1); pc = fetch16(); return 6+cyc; + case 0x21: nz(rA &= mem816(dpi(0, 1, 0), 0xFF00)); return 6+cyc; + case 0x22: push8(rPB>>16); push16(pc+2); a = fetch16(); rPB = fetch8()<<16; pc = a; return 8+cyc; + case 0x23: nz(rA &= mem816(sr(), 0xFF00)); return 4+cyc; + case 0x24: bit(mem816(dp(0), 0)); return 3+cyc; + case 0x25: nz(rA &= mem816(dp(0), 0xFF00)); return 3+cyc; + case 0x26: rol(dp(0)); return 5+cyc; + case 0x27: nz(rA &= mem816(dpi(1, 0, 0), 0xFF00)); return 6+cyc; + case 0x28: setrp(pop8()); return 5+cyc; + case 0x29: nz(rA &= imm(0xFF00)); return 2+cyc; + case 0x2A: + a = rP & FLAGC; + rP &= ~FLAGC; + if(m8){ + rP |= (rA >> 7) & 1; + rA = (rA & 0xFF00) | ((rA << 1) & 0xFF) | a; + }else{ + rP |= (rA >> 15) & 1; + rA = (rA << 1) | a; + } + nz(rA); + return 2; + case 0x2B: nz16(rD = pop16()); return 5; + case 0x2C: bit(mem816(abso(0, 0), 0)); return 4+cyc; + case 0x2D: nz(rA &= mem816(abso(0, 0), 0xFF00)); return 4+cyc; + case 0x2E: rol(abso(0, 0)); return 6+cyc; + case 0x2F: nz(rA &= mem816(abso(1, 0), 0xFF00)); return 5+cyc; + case 0x30: if((rP & FLAGN) != 0) return branch(); pc++; return 2; + case 0x31: nz(rA &= mem816(dpi(0, 0, 1), 0xFF00)); return 5+cyc; + case 0x32: nz(rA &= mem816(dpi(0, 0, 0), 0xFF00)); return 5+cyc; + case 0x33: nz(rA &= mem816(sry(), 0xFF00)); return 7+cyc; + case 0x34: bit(mem816(dp(1), 0)); return 4+cyc; + case 0x35: nz(rA &= mem816(dp(1), 0xFF00)); return 4+cyc; + case 0x36: rol(dp(1)); return 6+cyc; + case 0x37: nz(rA &= mem816(dpi(1, 0, 1), 0xFF00)); return 6+cyc; + case 0x38: rP |= FLAGC; return 2; + case 0x39: nz(rA &= mem816(abso(0, 2), 0xFF00)); return 4+cyc; + case 0x3A: + if(m8 && (rA & 0xFF) == 0) + rA |= 0xFF; + else + rA--; + nz(rA); + return 2; + case 0x3B: nz(rA = rS); return 2; + case 0x3C: bit(mem816(abso(0, 1), 0)); return 4+cyc; + case 0x3D: nz(rA &= mem816(abso(0, 1), 0xFF00)); return 4+cyc; + case 0x3E: rol(abso(0, 1)); return 7+cyc; + case 0x3F: nz(rA &= mem816(abso(1, 1), 0xFF00)); return 4+cyc; + case 0x40: + setrp(pop8()); + pc = pop16(); + if(!emu) + rPB = pop8() << 16; + return 7 - emu; + case 0x41: nz(rA ^= mem816(dpi(0, 1, 0), 0)); return 6+cyc; + case 0x42: fetch8(); return 2; + case 0x43: nz(rA ^= mem816(sr(), 0)); return 4+cyc; + case 0x44: block(0); return 7; + case 0x45: nz(rA ^= mem816(dp(0), 0)); return 3+cyc; + case 0x46: lsr(dp(0)); return 5+cyc; + case 0x47: nz(rA ^= mem816(dpi(1, 0, 0), 0)); return 6+cyc; + case 0x48: push816(rA, m8); return 3+cyc; + case 0x49: nz(rA ^= imm(0)); return 2+cyc; + case 0x4A: + rP &= ~FLAGC; + rP |= rA & 1; + if(m8) + rA = rA & 0xFF00 | (rA >> 1) & 0x7F; + else + rA >>= 1; + nz(rA); + return 2; + case 0x4B: push8(rPB >> 16); return 3; + case 0x4C: pc = fetch16(); return 3; + case 0x4D: nz(rA ^= mem816(abso(0, 0), 0)); return 4+cyc; + case 0x4E: lsr(abso(0, 0)); return 6+cyc; + case 0x4F: nz(rA ^= mem816(abso(1, 0), 0)); return 5+cyc; + case 0x50: if((rP & FLAGV) == 0) return branch(); pc++; return 2; + case 0x51: nz(rA ^= mem816(dpi(0, 0, 1), 0)); return 5+cyc; + case 0x52: nz(rA ^= mem816(dpi(0, 0, 0), 0)); return 5+cyc; + case 0x53: nz(rA ^= mem816(sry(), 0)); return 7+cyc; + case 0x54: block(1); return 7; + case 0x55: nz(rA ^= mem816(dp(1), 0)); return 4+cyc; + case 0x56: lsr(dp(1)); return 6+cyc; + case 0x57: nz(rA ^= mem816(dpi(1, 0, 1), 0)); return 6+cyc; + case 0x58: rP &= ~FLAGI; return 2; + case 0x59: nz(rA ^= mem816(abso(0, 2), 0)); return 4+cyc; + case 0x5A: push816(rY, x8); return 3+cyc; + case 0x5B: nz16(rD = rA); return 2; + case 0x5C: a = fetch16(); rPB = fetch8() << 16; pc = a; return 4; + case 0x5D: nz(rA ^= mem816(abso(0, 1), 0)); return 4+cyc; + case 0x5E: lsr(abso(0, 1)); return 7+cyc; + case 0x5F: nz(rA ^= mem816(abso(1, 1), 0)); return 5+cyc; + case 0x60: pc = pop16() + 1; return 6; + case 0x61: adc(mem816(dpi(0, 1, 0), 0)); return 6+cyc; + case 0x62: a = fetch16(); push16(a + pc); return 6; + case 0x63: adc(mem816(sr(), 0)); return 4+cyc; + case 0x64: memw816(dp(0), 0); return 3+cyc; + case 0x65: adc(mem816(dp(0), 0)); return 3+cyc; + case 0x66: ror(dp(0)); return 5+cyc; + case 0x67: adc(mem816(dpi(1, 0, 0), 0)); return 6+cyc; + case 0x68: nz(rA = pop816(rA & 0xFF00, m8)); return 4+cyc; + case 0x69: adc(imm(0)); return 2+cyc; + case 0x6A: + a = rP & FLAGC; + rP &= ~FLAGC; + rP |= rA & 1; + if(m8) + rA = rA & 0xFF00 | (rA >> 1) & 0x7F | a << 7; + else + rA = rA >> 1 | a << 15; + nz(rA); + return 2; + case 0x6B: pc = pop16() + 1; rPB = pop8() << 16; return 6; + case 0x6C: pc = absi(0); return 5; + case 0x6D: adc(mem816(abso(0, 0), 0)); return 4+cyc; + case 0x6E: ror(abso(0, 0)); return 6+cyc; + case 0x6F: adc(mem816(abso(1, 0), 0)); return 6+cyc; + case 0x70: if((rP & FLAGV) != 0) return branch(); pc++; return 2; + case 0x71: adc(mem816(dpi(0, 0, 1), 0)); return 5+cyc; + case 0x72: adc(mem816(dpi(0, 0, 0), 0)); return 5+cyc; + case 0x73: adc(mem816(sry(), 0)); return 7+cyc; + case 0x74: memw816(dp(1), 0); return 4+cyc; + case 0x75: adc(mem816(dp(1), 0)); return 4+cyc; + case 0x76: ror(dp(1)); return 6+cyc; + case 0x77: adc(mem816(dpi(1, 0, 1), 0)); return 6+cyc; + case 0x78: rP |= FLAGI; return 2; + case 0x79: adc(mem816(abso(0, 2), 0)); return 6+cyc; + case 0x7A: nzx(rY = pop816(0, x8)); return 4+cyc; + case 0x7B: nz16(rA = rD); return 2; + case 0x7C: pc = absi(1); return 6; + case 0x7D: adc(mem816(abso(0, 1), 0)); return 4+cyc; + case 0x7E: ror(abso(0, 1)); return 7+cyc; + case 0x7F: adc(mem816(abso(1, 1), 0)); return 5+cyc; + case 0x80: return branch(); + case 0x81: memw816(dpi(0, 1, 0), rA); return 6+cyc; + case 0x82: a = fetch16(); pc += a; return 4; + case 0x83: memw816(sr(), rA); return 4+cyc; + case 0x84: memwx816(dp(0), rY); return 3+cyc; + case 0x85: memw816(dp(0), rA); return 3+cyc; + case 0x86: memwx816(dp(0), rX); return 3+cyc; + case 0x87: memw816(dpi(1, 0, 0), rA); return 6+cyc; + case 0x88: + rY--; + if(x8) + rY &= 0xff; + nzx(rY); + return 2; + case 0x89: bit(imm(0)); return 2+cyc; + case 0x8A: setra(rX); return 2+cyc; + case 0x8B: push8(rDB >> 16); return 3; + case 0x8C: memwx816(abso(0, 0), rY); return 4+cyc; + case 0x8D: memw816(abso(0, 0), rA); return 4+cyc; + case 0x8E: memwx816(abso(0, 0), rX); return 4+cyc; + case 0x8F: memw816(abso(1, 0), rA); return 5+cyc; + case 0x90: if((rP & FLAGC) == 0) return branch(); pc++; return 2; + case 0x91: memw816(dpi(0, 0, 1), rA); return 6+cyc; + case 0x92: memw816(dpi(0, 0, 0), rA); return 6+cyc; + case 0x93: memw816(sry(), rA); return 6+cyc; + case 0x94: memwx816(dp(1), rY); return 4+cyc; + case 0x95: memw816(dp(1), rA); return 4+cyc; + case 0x96: memwx816(dp(2), rX); return 4+cyc; + case 0x97: memw816(dpi(1, 0, 1), rA); return 6+cyc; + case 0x98: setra(rY); return 2; + case 0x99: memw816(abso(0, 2), rA); return 3+cyc; + case 0x9A: rS = rX; if(emu) rS = rS & 0xff | 0x100; return 2; + case 0x9B: setx(rX, &rY); return 2; + case 0x9C: memw816(abso(0, 0), 0); return 3+cyc; + case 0x9D: memw816(abso(0, 1), rA); return 5+cyc; + case 0x9E: memw816(abso(0, 1), 0); return 5+cyc; + case 0x9F: memw816(abso(1, 1), rA); return 4+cyc; + case 0xA0: nzx(rY = immx(0)); return 2+cyc; + case 0xA1: nz(rA = mem816(dpi(0, 1, 0), rA & 0xFF00)); return 6+cyc; + case 0xA2: nzx(rX = immx(0)); return 2+cyc; + case 0xA3: nz(rA = mem816(sr(), rA & 0xFF00)); return 4+cyc; + case 0xA4: nzx(rY = memx816(dp(0))); return 3+cyc; + case 0xA5: nz(rA = mem816(dp(0), rA & 0xFF00)); return 3+cyc; + case 0xA6: nzx(rX = memx816(dp(0))); return 3+cyc; + case 0xA7: nz(rA = mem816(dpi(1, 0, 0), rA & 0xFF00)); return 6+cyc; + case 0xA8: setx(rA, &rY); return 2; + case 0xA9: nz(rA = imm(rA & 0xFF00)); return 2+cyc; + case 0xAA: setx(rA, &rX); return 2; + case 0xAB: rDB = nz8(pop8()) << 16; return 4; + case 0xAC: nzx(rY = memx816(abso(0, 0))); return 4+cyc; + case 0xAD: nz(rA = mem816(abso(0, 0), rA & 0xFF00)); return 4+cyc; + case 0xAE: nzx(rX = memx816(abso(0, 0))); return 4+cyc; + case 0xAF: nz(rA = mem816(abso(1, 0), rA & 0xFF00)); return 5+cyc; + case 0xB0: if((rP & FLAGC) != 0) return branch(); pc++; return 2; + case 0xB1: nz(rA = mem816(dpi(0, 0, 1), rA & 0xFF00)); return 5+cyc; + case 0xB2: nz(rA = mem816(dpi(0, 0, 0), rA & 0xFF00)); return 5+cyc; + case 0xB3: nz(rA = mem816(sry(), rA & 0xFF00)); return 7+cyc; + case 0xB4: nzx(rY = memx816(dp(1))); return 4+cyc; + case 0xB5: nz(rA = mem816(dp(1), rA & 0xFF00)); return 4+cyc; + case 0xB6: nzx(rX = memx816(dp(2))); return 4+cyc; + case 0xB7: nz(rA = mem816(dpi(1, 0, 1), rA & 0xFF00)); return 6+cyc; + case 0xB8: rP &= ~FLAGV; return 2; + case 0xB9: nz(rA = mem816(abso(0, 2), rA & 0xFF00)); return 4+cyc; + case 0xBA: setx(rS, &rX); return 2; + case 0xBB: setx(rY, &rX); return 2; + case 0xBC: nzx(rY = memx816(abso(0, 1))); return 4+cyc; + case 0xBD: nz(rA = mem816(abso(0, 1), rA & 0xFF00)); return 4+cyc; + case 0xBE: nzx(rX = memx816(abso(0, 2))); return 4+cyc; + case 0xBF: nz(rA = mem816(abso(1, 1), rA & 0xFF00)); return 5+cyc; + case 0xC0: cmp(rY, immx(0), x8); return 2+cyc; + case 0xC1: cmp(rA, mem816(dpi(0, 1, 0), 0), m8); return 6+cyc; + case 0xC2: setrp(rP & ~fetch8()); return 3; + case 0xC3: cmp(rA, mem816(sr(), 0), m8); return 4+cyc; + case 0xC4: cmp(rY, memx816(dp(0)), x8); return 3+cyc; + case 0xC5: cmp(rA, mem816(dp(0), 0), m8); return 3+cyc; + case 0xC6: dec(dp(0)); return 5+cyc; + case 0xC7: cmp(rA, mem816(dpi(1, 0, 0), 0), m8); return 6+cyc; + case 0xC8: + rY++; + if(x8) + rY &= 0xff; + nzx(rY); + return 2; + case 0xC9: cmp(rA, imm(0), m8); return 2+cyc; + case 0xCA: + rX--; + if(x8) + rX &= 0xff; + nzx(rX); + return 2; + case 0xCC: cmp(rY, memx816(abso(0, 0)), x8); return 4+cyc; + case 0xCD: cmp(rA, mem816(abso(0, 0), 0), m8); return 4+cyc; + case 0xCE: dec(abso(0, 0)); return 6+cyc; + case 0xCF: cmp(rA, mem816(abso(1, 0), 0), m8); return 4+cyc; + case 0xD0: if((rP & FLAGZ) == 0) return branch(); pc++; return 2; + case 0xD1: cmp(rA, mem816(dpi(0, 0, 1), 0), m8); return 5+cyc; + case 0xD2: cmp(rA, mem816(dpi(0, 0, 0), 0), m8); return 5+cyc; + case 0xD3: cmp(rA, mem816(sry(), 0), m8); return 7+cyc; + case 0xD4: push16(dpi(0, 0, 0)); return 6+cyc; + case 0xD5: cmp(rA, mem816(dp(1), 0), m8); return 4+cyc; + case 0xD6: dec(dp(1)); return 6+cyc; + case 0xD7: cmp(rA, mem816(dpi(1, 0, 1), 0), m8); return 6+cyc; + case 0xD8: rP &= ~FLAGD; return 2; + case 0xD9: cmp(rA, mem816(abso(0, 2), 0), m8); return 4+cyc; + case 0xDA: push816(rX, x8); return 3+cyc; + case 0xDC: a = fetch16(); pc = memread(a) | memread((u16int)(a+1))<<8; rPB = memread((u16int)(a+2)) << 16; return 6; + case 0xDD: cmp(rA, mem816(abso(0, 1), 0), m8); return 4+cyc; + case 0xDE: dec(abso(0, 1)); return 7+cyc; + case 0xDF: cmp(rA, mem816(abso(1, 1), 0), m8); return 7+cyc; + case 0xE0: cmp(rX, immx(0), x8); return 2+cyc; + case 0xE1: sbc(mem816(dpi(0, 1, 0), 0)); return 6+cyc; + case 0xE2: setrp(rP | fetch8()); return 2; + case 0xE3: sbc(mem816(sr(), 0)); return 4+cyc; + case 0xE4: cmp(rX, memx816(dp(0)), x8); return 3+cyc; + case 0xE5: sbc(mem816(dp(0), 0)); return 3+cyc; + case 0xE6: inc(dp(0)); return 5+cyc; + case 0xE7: sbc(mem816(dpi(1, 0, 0), 0)); return 6+cyc; + case 0xE8: + rX++; + if(x8) + rX &= 0xff; + nzx(rX); + return 2; + case 0xE9: sbc(imm(0)); return 2+cyc; + case 0xEA: return 2; + case 0xEB: nz8(rA = (rA >> 8) | (rA << 8)); return 3; + case 0xEC: cmp(rX, memx816(abso(0, 0)), x8); return 4+cyc; + case 0xED: sbc(mem816(abso(0, 0), 0)); return 4+cyc; + case 0xEE: inc(abso(0, 0)); return 6+cyc; + case 0xEF: sbc(mem816(abso(1, 0), 0)); return 5+cyc; + case 0xF0: if((rP & FLAGZ) != 0) return branch(); pc++; return 2; + case 0xF1: sbc(mem816(dpi(0, 0, 1), 0)); return 5+cyc; + case 0xF2: sbc(mem816(dpi(0, 0, 0), 0)); return 5+cyc; + case 0xF3: sbc(mem816(sry(), 0)); return 7+cyc; + case 0xF4: push16(fetch16()); return 5; + case 0xF5: sbc(mem816(dp(1), 0)); return 4+cyc; + case 0xF6: inc(dp(1)); return 6+cyc; + case 0xF7: sbc(mem816(dpi(1, 0, 1), 0)); return 6+cyc; + case 0xF8: rP |= FLAGD; return 2; + case 0xF9: sbc(mem816(abso(0, 2), 0)); return 4+cyc; + case 0xFA: nzx(rX = pop816(0, x8)); return 4+cyc; + case 0xFB: + a = emu; + emu = rP & 1; + if(emu){ + rX &= 0xff; + rY &= 0xff; + rS = rS & 0xff | 0x100; + } + rP &= ~1; + rP |= 0x30 | a; + return 2; + case 0xFC: push16(pc+1); pc = absi(1); return 8+cyc; + case 0xFD: sbc(mem816(abso(0, 1), 0)); return 4+cyc; + case 0xFE: inc(abso(0, 1)); return 7+cyc; + case 0xFF: sbc(mem816(abso(1, 1), 0)); return 5+cyc; + default: + print("undefined %#x (pc %#.6x)\n", op, curpc); + return 2; + } +} diff --git a/sys/src/games/snes/dat.h b/sys/src/games/snes/dat.h new file mode 100644 index 000000000..dcb7b439f --- /dev/null +++ b/sys/src/games/snes/dat.h @@ -0,0 +1,70 @@ +extern u16int pc; +extern u32int rPB, curpc; +extern u8int dma, nmi, irq; +extern u32int hdma; +extern int trace; + +extern uchar *prg, *sram; +extern int nprg, nsram, keys; +extern u16int keylatch; +extern u8int reg[32768], spcmem[65536], vram[65536], oam[544]; +extern u16int cgram[256]; + +extern int ppux, ppuy; +extern u16int vtime, htime, subcolor, oamaddr; +extern u16int m7[6], hofs[4], vofs[4]; + +extern int battery, saveclock; + +enum { + FLAGC = 1<<0, + FLAGZ = 1<<1, + FLAGI = 1<<2, + FLAGD = 1<<3, + FLAGX = 1<<4, + FLAGM = 1<<5, + FLAGV = 1<<6, + FLAGN = 1<<7, +}; + +enum { + FREQ = 21477272, + SPCDIV = 21, + SAVEFREQ = FREQ / 4, + + XLEFT = 22, + XRIGHT = 22 + 255, +}; + +enum { + INIDISP = 0x2100, + FORBLANK = 0x80, + OBSEL = 0x2101, + OAMADDH = 0x2103, + BGMODE = 0x2105, + MOSAIC = 0x2106, + WIN1 = 2, + INVW1 = 1, + WIN2 = 8, + INVW2 = 4, + TM = 0x212c, + TS = 0x212d, + TMW = 0x212e, + TSW = 0x212f, + CGWSEL = 0x2130, + CGADSUB = 0x2131, + DIRCOL = 1, + SETINI = 0x2133, + OVERSCAN = 1<<2, + AUTOJOY = 1, + NMITIMEN = 0x4200, + RDNMI = 0x4210, + VBLANK = 1<<7, + VCNTIRQ = 1<<5, + HCNTIRQ = 1<<4, +}; + +enum { + IRQPPU = 1<<7, +}; + diff --git a/sys/src/games/snes/fns.h b/sys/src/games/snes/fns.h new file mode 100644 index 000000000..262cbfbaf --- /dev/null +++ b/sys/src/games/snes/fns.h @@ -0,0 +1,13 @@ +u8int memread(u32int); +void memwrite(u32int, u8int); +void cpureset(void); +int cpustep(void); +void spcreset(void); +int spcstep(void); +void spctimerstep(void); +int dmastep(void); +void ppustep(void); +void memreset(void); +int hdmastep(void); +void flush(void); +void message(char *, ...); diff --git a/sys/src/games/snes/mem.c b/sys/src/games/snes/mem.c new file mode 100644 index 000000000..dcf136e3d --- /dev/null +++ b/sys/src/games/snes/mem.c @@ -0,0 +1,509 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include "dat.h" +#include "fns.h" + +u8int reg[32768]; +u8int mem[131072]; +u8int oam[544], vram[65536]; +u16int cgram[256]; +u16int oamaddr, vramlatch, keylatch; +enum { + OAMLATCH, + CGLATCH, + CGLH, + OFSPREV, + M7PREV, + OPCTLATCH, + OPHCTH, + OPVCTH, +}; + +static void +incvram(int i, int r) +{ + u16int a, b; + int c; + + c = reg[0x2115]; + if((c >> 7) != i) + return; + a = reg[0x2116] | reg[0x2117] << 8; + if((c & 0x0c) != 0) + print("address remapping\n"); + if(r){ + b = a<<1; + vramlatch = vram[b++]; + vramlatch |= vram[b] << 8; + } + switch(c & 3){ + case 0: a++; break; + case 1: a += 32; break; + default: a += 128; break; + } + reg[0x2116] = a; + reg[0x2117] = (a >> 8) & 0x7f; +} + +static void +hvlatch(void) +{ + reg[0x213c] = ppux; + reg[OPHCTH] = ppux >> 8; + reg[0x213d] = ppuy; + reg[OPVCTH] = ppuy >> 8; + reg[OPCTLATCH] |= 0x40; +} + +static u16int +swaprb(u16int a) +{ + return (a & 0x83e0) | (a & 0x7c00) >> 10 | (a & 0x001f) << 10; +} + +u8int +regread(u16int p) +{ + u8int v; + u16int a; + int r; + + if(p < 0x2000) + return mem[p]; + switch(p){ + case 0x2134: case 0x2135: case 0x2136: + r = ((signed short)m7[0] * (signed char)reg[0x211c]) & 0xffffff; + return r >> 8 * (p - 0x2134); + case 0x2137: + if((reg[0x4201] & 0x80) != 0) + hvlatch(); + return 0; + case 0x2138: + if(oamaddr < 0x200) + v = oam[oamaddr]; + else + v = oam[oamaddr & 0x21f]; + oamaddr = (oamaddr + 1) & 0x3ff; + return v; + case 0x2139: + v = vramlatch; + incvram(0, 1); + return v; + case 0x213a: + v = vramlatch >> 8; + incvram(1, 1); + return v; + case 0x213b: + a = swaprb(cgram[reg[0x2121]]); + if(reg[CGLH] != 0){ + a >>= 8; + reg[0x2121]++; + } + reg[CGLH] ^= 1; + return a; + case 0x213c: + reg[OPCTLATCH] ^= 1; + if((reg[OPCTLATCH] & 1) == 0) + return reg[OPHCTH]; + break; + case 0x213d: + reg[OPCTLATCH] ^= 2; + if((reg[OPCTLATCH] & 2) == 0) + return reg[OPVCTH]; + break; + case 0x213f: + v = 2 | reg[OPCTLATCH] & 0x40; + if((reg[0x4201] & 0x80) != 0) + reg[OPCTLATCH] &= ~0x43; + else + reg[OPCTLATCH] &= ~3; + return v; + case 0x2180: + v = memread(reg[0x2181] | reg[0x2182] << 8 | reg[0x2183] << 16); + reg[0x2181]++; + return v; + case 0x4016: + if((reg[0x4016] & 1) != 0) + return keylatch >> 15; + v = keylatch >> 15; + keylatch = (keylatch << 1) | 1; + return v; + case 0x4017: + return 0; + case 0x4211: + v = irq; + irq &= ~IRQPPU; + return v; + case 0x4212: + v = 0; + if(ppux >= 274 || ppux == 0) + v |= 0x40; + a = (reg[SETINI] & OVERSCAN) != 0 ? 0xf0 : 0xe1; + if(ppuy >= a){ + v |= 0x80; + if(ppuy <= a + 2 && (reg[NMITIMEN] & AUTOJOY) != 0) + v |= 1; + } + return v; + } + if((p & 0xff40) == 0x2140) + return spcmem[0xf4 | p & 3]; + return reg[p]; +} + +void +regwrite(u16int p, u8int v) +{ + u16int a; + + if(p < 0x2000){ + mem[p] = v; + return; + } + switch(p){ + case 0x2102: + oamaddr &= 0x200; + oamaddr |= v << 1; + break; + case 0x2103: + oamaddr &= 0x1fe; + oamaddr |= (v & 1) << 9; + break; + case 0x2104: + if((oamaddr & 1) == 0) + reg[OAMLATCH] = v; + if(oamaddr < 0x200){ + if((oamaddr & 1) != 0){ + oam[oamaddr - 1] = reg[OAMLATCH]; + oam[oamaddr] = v; + } + }else + oam[oamaddr & 0x21f] = v; + oamaddr = (oamaddr + 1) & 0x3ff; + return; + case 0x210d: case 0x210f: + case 0x2111: case 0x2113: + a = (p - 0x210d) >> 1; + hofs[a] = (v << 8) | reg[OFSPREV] & ~7 | (hofs[a] >> 8) & 7; + reg[OFSPREV] = v; + break; + case 0x210e: case 0x2110: + case 0x2112: case 0x2114: + vofs[(p - 0x210e) >> 1] = (v << 8) | reg[OFSPREV]; + reg[OFSPREV] = v; + break; + case 0x2116: + break; + case 0x2117: + v &= 0x7f; + break; + case 0x2118: + a = reg[0x2116] << 1 | reg[0x2117] << 9; + vram[a] = v; + incvram(0, 0); + return; + case 0x2119: + a = reg[0x2116] << 1 | reg[0x2117] << 9; + vram[a|1] = v; + incvram(1, 0); + return; + case 0x211b: case 0x211c: case 0x211d: + case 0x211e: case 0x211f: case 0x2120: + m7[p - 0x211b] = (v << 8) | reg[M7PREV]; + reg[M7PREV] = v; + break; + case 0x2121: + reg[CGLH] = 0; + break; + case 0x2122: + if(reg[CGLH] == 0) + reg[CGLATCH] = v; + else + cgram[reg[0x2121]++] = swaprb(reg[CGLATCH] | v << 8); + reg[CGLH] ^= 1; + break; + case 0x2132: + if((v & 0x80) != 0) subcolor = subcolor & 0x7fe0 | v & 0x1f; + if((v & 0x40) != 0) subcolor = subcolor & 0x7c1f | (v & 0x1f) << 5; + if((v & 0x20) != 0) subcolor = subcolor & 0x03ff | (v & 0x1f) << 10; + return; + case 0x2180: + memwrite(reg[0x2181] | reg[0x2182] << 8 | reg[0x2183] << 16, v); + reg[0x2181]++; + return; + case 0x213e: + return; + case 0x4016: + if((reg[0x4016] & 1) != 0 && (v & 1) == 0) + keylatch = keys; + break; + case 0x4200: + if((reg[0x4200] & 0x80) == 0 && (v & 0x80) != 0 && (reg[RDNMI] & 0x80) != 0) + nmi = 2; + break; + case 0x4201: + if((reg[0x4201] & 0x80) == 0 && (v & 0x80) != 0) + hvlatch(); + break; + case 0x4203: + a = reg[0x4202] * v; + reg[0x4216] = a; + reg[0x4217] = a >> 8; + break; + case 0x4206: + if(v == 0){ + reg[0x4214] = 0xff; + reg[0x4215] = 0xff; + reg[0x4216] = reg[0x4204]; + reg[0x4217] = reg[0x4205]; + }else{ + a = reg[0x4204] | reg[0x4205] << 8; + reg[0x4214] = a / v; + reg[0x4215] = (a / v) >> 8; + reg[0x4216] = a % v; + reg[0x4217] = (a % v) >> 8; + } + break; + case 0x4207: + htime = htime & 0x100 | v; + break; + case 0x4208: + htime = htime & 0xff | (v & 1) << 8; + break; + case 0x4209: + vtime = vtime & 0x100 | v; + break; + case 0x420a: + vtime = vtime & 0xff | (v & 1) << 8; + break; + case 0x420b: + dma |= v & ~reg[0x420c]; + break; + case 0x4210: + return; + case 0x4211: + irq &= ~IRQPPU; + return; + case 0x4216: case 0x4217: + case 0x4218: case 0x4219: case 0x421a: case 0x421b: + case 0x421c: case 0x421d: case 0x421e: case 0x421f: + return; + } + if((p & 0xff40) == 0x2140) + p &= 0xff43; + reg[p] = v; +} + +u8int +memread(u32int a) +{ + u16int al; + u8int b; + + al = a; + b = (a>>16) & 0x7f; + if(al < 0x8000){ + if(b < 0x40) + return regread(al); + if(b >= 0x70 && b < 0x78 && nsram != 0) + return sram[((a & 0x7fffff) - 0x700000) & (nsram - 1)]; + } + if(b >= 0x7e && (a & (1<<23)) == 0) + return mem[a - 0x7e0000]; + return prg[(b%nprg) << 15 | al & 0x7fff]; +} + +void +memwrite(u32int a, u8int v) +{ + u16int al; + u8int b; + + al = a; + b = (a>>16) & 0x7f; + if(b >= 0x7e && a < 0x800000) + mem[a - 0x7e0000] = v; + if(al < 0x8000){ + if(b < 0x40){ + regwrite(a, v); + return; + } + if(b >= 0x70 && b < 0x78 && nsram != 0){ + sram[((a & 0x7fffff) - 0x700000) & (nsram - 1)] = v; + if(saveclock == 0) + saveclock = SAVEFREQ; + return; + } + } +} + +static u8int nbytes[] = {1, 2, 2, 4, 4, 4, 2, 4}; +static u8int modes[] = {0x00, 0x04, 0x00, 0x50, 0xe4, 0x44, 0x00, 0x50}; + +static int +dmavalid(int a, int b) +{ + if(b) + return 1; + if((a & 0x400000) != 0) + return 1; + switch(a >> 8){ + case 0x21: return 0; + case 0x42: return a != 0x420b && a != 0x420c; + case 0x43: return 0; + } + return 1; +} + +int +dmastep(void) +{ + int i, j, n, m, cyc; + u32int a; + u8int b, c, *p; + u32int v; + + cyc = 0; + for(i = 0; i < 8; i++) + if((dma & (1<<i)) != 0) + break; + if(i == 8) + return 0; + p = reg + 0x4300 + (i << 4); + c = *p; + n = nbytes[c & 7]; + m = modes[c & 7]; + for(j = 0; j < n; j++){ + a = p[2] | p[3] << 8 | p[4] << 16; + b = p[1] + (m & 3); + if((c & 0x80) != 0){ + v = dmavalid(b, 1) ? memread(0x2100 | b) : 0; + if(dmavalid(a, 0)) + memwrite(a, v); + }else{ + v = dmavalid(a, 0) ? memread(a) : 0; + if(dmavalid(b, 1)) + memwrite(0x2100 | b, v); + } + cyc++; + m >>= 2; + if((c & 0x08) == 0){ + if((c & 0x10) != 0){ + if(--p[2] == 0xff) + p[3]--; + }else{ + if(++p[2] == 0x00) + p[3]++; + } + } + if(p[5] == 0){ + p[5] = 0xff; + p[6]--; + }else if(--p[5] == 0 && p[6] == 0){ + dma &= ~(1<<i); + break; + } + } + return cyc; +} + +static int +hdmaload(u8int *p) +{ + u32int a; + + a = p[8] | p[9] << 8 | p[4] << 16; + p[10] = dmavalid(a, 0) ? memread(a) : 0; + a++; + if((p[0] & 0x40) != 0){ + p[5] = dmavalid(a, 0) ? memread(a) : 0; + a++; + p[6] = dmavalid(a, 0) ? memread(a) : 0; + a++; + } + p[8] = a; + p[9] = a >> 8; + return (p[0] & 0x40) != 0 ? 3 : 1; +} + +int +hdmastep(void) +{ + int i, j, cyc; + u8int *p, *q, n, m, b, v, c; + u32int a; + + cyc = 0; + if(dma != 0) + dma &= ~((hdma & 0xff00) >> 8 | (hdma & 0xff)); + if((hdma & 0xff) == 0) + goto init; + cyc += 2; + for(i = 0; i < 8; i++){ + if(((hdma >> i) & (1<<24|1)) != 1) + continue; + p = reg + 0x4300 + (i << 4); + c = p[0]; + if((hdma & (1<<(16+i))) != 0){ + n = nbytes[c & 7]; + m = modes[c & 7]; + if((c & 0x40) != 0) + q = p + 5; + else + q = p + 8; + for(j = 0; j < n; j++){ + a = q[0] | q[1] << 8 | p[4] << 16; + b = p[1] + (m & 3); + if((c & 0x80) != 0){ + v = dmavalid(b, 1) ? memread(0x2100 | b) : 0; + if(dmavalid(a, 0)) + memwrite(a, v); + }else{ + v = dmavalid(a, 0) ? memread(a) : 0; + if(dmavalid(b, 1)) + memwrite(0x2100 | b, v); + } + if(++q[0] == 0) + q[1]++; + cyc++; + m >>= 2; + } + } + p[10]--; + hdma = (hdma & ~(1<<(16+i))) | ((p[10] & 0x80) << (9+i)); + cyc++; + if((p[10] & 0x7f) == 0){ + cyc += hdmaload(p)-1; + if(p[10] == 0) + hdma |= 1<<(24+i); + hdma |= 1<<(16+i); + } + } + hdma &= ~0xff; + if((hdma & 0xff00) == 0) + return cyc; +init: + for(i = 0; i < 8; i++){ + if((hdma & (1<<(8+i))) == 0) + continue; + p = reg + 0x4300 + (i << 4); + p[8] = p[2]; + p[9] = p[3]; + cyc += hdmaload(p); + if(p[10] == 0) + hdma |= 1<<(24+i); + hdma |= 1<<(16+i); + } + cyc += 2; + hdma &= ~0xff00; + return cyc; +} + +void +memreset(void) +{ + reg[0x213e] = 1; + reg[0x4201] = 0xff; + reg[0x4210] = 2; +} diff --git a/sys/src/games/snes/mkfile b/sys/src/games/snes/mkfile new file mode 100644 index 000000000..b7289906f --- /dev/null +++ b/sys/src/games/snes/mkfile @@ -0,0 +1,14 @@ +</$objtype/mkfile + +BIN=/$objtype/bin/games +TARG=snes +OFILES=\ + cpu.$O\ + snes.$O\ + mem.$O\ + ppu.$O\ + spc.$O\ + +HFILES=dat.h fns.h + +</sys/src/cmd/mkone diff --git a/sys/src/games/snes/ppu.c b/sys/src/games/snes/ppu.c new file mode 100644 index 000000000..90469b10e --- /dev/null +++ b/sys/src/games/snes/ppu.c @@ -0,0 +1,548 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include "dat.h" +#include "fns.h" + +int ppux, ppuy, rx; +static u8int mode, bright, pixelpri[2]; +static u32int pixelcol[2]; +u16int vtime = 0x1ff, htime = 0x1ff, subcolor, mosatop; +uchar pic[256*239*2*9]; +u16int m7[6], hofs[4], vofs[4]; + +enum { OBJ = 4, COL = 5, OBJNC = 6 }; + +static u16int +darken(u16int v) +{ + u8int r, g, b; + + r = (v >> 10) & 0x1f; + g = (v >> 5) & 0x1f; + b = v & 0x1f; + r = r * bright / 15; + g = g * bright / 15; + b = b * bright / 15; + return r << 10 | g << 5 | b; +} + +static void +pixeldraw(int x, int y, u16int v) +{ + uchar *p; + + if(bright != 0xf) + v = darken(v); + p = pic + (x + y * 256) * 2; + *p++ = v; + *p = v >> 8; +} + +static int +window(int n) +{ + int a, w1, w2; + + a = reg[0x2123 + (n >> 1)]; + if((n & 1) != 0) + a >>= 4; + if((a & (WIN1|WIN2)) == 0) + return 0; + w1 = rx >= reg[0x2126] && rx <= reg[0x2127]; + w2 = rx >= reg[0x2128] && rx <= reg[0x2129]; + if((a & INVW1) != 0) + w1 = !w1; + if((a & INVW2) != 0) + w2 = !w2; + if((a & (WIN1|WIN2)) != (WIN1|WIN2)) + return (a & WIN1) != 0 ? w1 : w2; + a = reg[0x212a + (n >> 2)] >> ((n & 3) << 1); + switch(a & 3){ + case 1: return w1 & w2; + case 2: return w1 ^ w2; + case 3: return w1 ^ w2 ^ 1; + } + return w1 | w2; +} + +static void +pixel(int n, int v, int pri) +{ + int a; + + a = 1<<n; + if((reg[TM] & a) != 0 && pri > pixelpri[0] && ((reg[TMW] & a) == 0 || !window(n))){ + pixelcol[0] = v; + pixelpri[0] = pri; + } + if((reg[TS] & a) != 0 && pri > pixelpri[1] && ((reg[TSW] & a) == 0 || !window(n))){ + pixelcol[1] = v; + pixelpri[1] = pri; + } +} + +static u16int +tile(int n, int tx, int ty) +{ + int a; + u16int ta; + u16int t; + + a = reg[0x2107 + n]; + ta = ((a & ~3) << 9) + ((tx & 0x1f) << 1) + ((ty & 0x1f) << 6); + if((a & 1) != 0) + ta += (tx & 0x20) << 6; + if((a & 2) != 0) + ta += (ty & 0x20) << (6 + (a & 1)); + t = vram[ta++]; + return t | vram[ta] << 8; +} + +static void +chr(int n, int nb, int sz, u16int t, int x, int y, u8int c[]) +{ + int i; + u16int a; + + if(sz == 16){ + if(y >= 8){ + t += ((x >> 3 ^ t >> 14) & 1) + ((~t >> 11) & 16); + y -= 8; + }else + t += ((x >> 3 ^ t >> 14) & 1) + ((t >> 11) & 16); + } + if((t & 0x8000) != 0) + y = 7 - y; + a = reg[0x210b + (n >> 1)]; + if((n & 1) != 0) + a >>= 4; + else + a &= 0xf; + a = (a << 13) + (t & 0x3ff) * 8 * nb + y * 2; + for(i = 0; i < nb; i += 2){ + c[i] = vram[a++]; + c[i+1] = vram[a]; + a += 15; + } +} + +static int +palette(int n, int p) +{ + switch(mode){ + case 0: + return p << 2 | n << 5; + case 1: + if(n >= 2) + return p << 2; + case 2: + case 6: + return p << 4; + case 5: + if(n == 0) + return p << 4; + return p << 2; + case 3: + if(n != 0) + return p << 4; + case 4: + if(n != 0) + return p << 2; + if((reg[CGWSEL] & DIRCOL) != 0) + return 0x10000; + } + return 0; +} + +static void +shift(u8int *c, int nb, int n, int d) +{ + u8int *e; + + e = c + nb; + if(d) + while(c < e) + *c++ >>= n; + else + while(c < e) + *c++ <<= n; +} + +static u8int +bgpixel(u8int *c, int nb, int d) +{ + u8int v; + int i; + + v = 0; + if(d) + for(i = 0; i < nb; i++){ + v |= (*c & 1) << i; + *c++ >>= 1; + } + else + for(i = 0; i < nb; i++){ + v |= (*c & 0x80) >> (7 - i); + *c++ <<= 1; + } + return v; +} + +static void +bg(int n, int nb, int prilo, int prihi) +{ + static struct bg { + u8int sz, szsh; + u16int tx, ty, tnx, tny; + u16int t; + u8int c[8]; + int pal; + u8int msz, mv, mx; + } bgs[4]; + struct bg *p; + int v, sx, sy; + + p = bgs + n; + if(rx == 0){ + p->szsh = (reg[BGMODE] & (1<<(4+n))) != 0 ? 4 : 3; + if(mode >= 5) + p->szsh = 4; + p->sz = 1<<p->szsh; + sx = hofs[n]; + sy = vofs[n] + ppuy; + if(reg[MOSAIC] != 0 && (reg[MOSAIC] & (1<<n)) != 0){ + p->msz = (reg[MOSAIC] >> 4) + 1; + if(p->msz != 1){ + sx -= p->mx = sx % p->msz; + sy -= sy % p->msz; + } + }else + p->msz = 1; + redo: + p->tx = sx >> p->szsh; + p->tnx = sx & (p->sz - 1); + p->ty = sy >> p->szsh; + p->tny = sy & (p->sz - 1); + p->t = tile(n, p->tx, p->ty); + chr(n, nb, p->sz, p->t, p->tnx, p->tny, p->c); + p->pal = palette(n, p->t >> 10 & 7); + if(p->tnx != 0) + shift(p->c, nb, p->tnx, p->t & 0x4000); + if(p->msz != 1 && p->mx != 0 && sx % p->msz == 0){ + p->mv = bgpixel(p->c, nb, p->t & 0x4000); + if(p->tnx + p->mx >= 8){ + sx += p->mx; + goto redo; + }else if(p->mx > 1) + shift(p->c, nb, p->mx - 1, p->t & 0x4000); + } + } + v = bgpixel(p->c, nb, p->t & 0x4000); + if(p->msz != 1) + if(p->mx++ == 0) + p->mv = v; + else{ + if(p->mx == p->msz) + p->mx = 0; + v = p->mv; + } + if(v != 0) + pixel(n, p->pal + v, (p->t & 0x2000) != 0 ? prihi : prilo); + if(++p->tnx == p->sz){ + p->tx++; + p->tnx = 0; + p->t = tile(n, p->tx, p->ty); + p->pal = palette(n, p->t >> 10 & 7); + } + if((p->tnx & 7) == 0) + chr(n, nb, p->sz, p->t, p->tnx, p->tny, p->c); +} + +static void +bgs(void) +{ + static int bitch[8]; + + switch(mode){ + case 0: + bg(0, 2, 0x80, 0xb0); + bg(1, 2, 0x71, 0xa1); + bg(2, 2, 0x22, 0x52); + bg(3, 2, 0x13, 0x43); + break; + case 1: + bg(0, 4, 0x80, 0xb0); + bg(1, 4, 0x71, 0xa1); + bg(2, 2, 0x12, (reg[BGMODE] & 8) != 0 ? 0xd2 : 0x42); + break; + default: + if(bitch[mode]++ == 0) + print("bg mode %d not implemented\n", mode); + } +} + +static void +sprites(void) +{ + static struct { + short x; + u8int y, i, c, sx, sy; + u16int t0, t1; + } s[32], *sp; + static struct { + short x; + u8int sx, i, c, pal, pri; + u8int *ch; + } t[32], *tp; + static uchar ch[34*4], *cp; + static uchar *p, q, over; + static int n, m; + static int *sz; + static int szs[] = { + 8, 8, 16, 16, 8, 8, 32, 32, + 8, 8, 64, 64, 16, 16, 32, 32, + 16, 16, 64, 64, 32, 32, 64, 64, + 16, 32, 32, 64, 16, 32, 32, 32 + }; + static u16int base[2]; + u8int dy, v, col, pri0, pri1, prio; + u16int a; + int i, nt, dx; + + if(rx == 0){ + n = 0; + over = 1; + sp = s; + sz = szs + ((reg[OBSEL] & 0xe0) >> 3); + base[0] = (reg[OBSEL] & 0x07) << 14; + base[1] = base[0] + (((reg[OBSEL] & 0x18) + 8) << 10); + } + if((rx & 1) == 0){ + p = oam + 2 * rx; + if(p[1] == 0xf0) + goto nope; + q = (oam[512 + (rx >> 3)] >> (rx & 6)) & 3; + dy = ppuy - p[1]; + sp->sx = sz[q & 2]; + sp->sy = sz[(q & 2) + 1]; + if(dy >= sp->sy) + goto nope; + sp->x = p[0]; + if((q & 1) != 0) + sp->x |= 0xff00; + if(sp->x < -(short)sp->sx && sp->x != -256) + goto nope; + if(n == 32){ + over |= 0x40; + goto nope; + } + sp->i = rx >> 1; + sp->y = p[1]; + sp->c = p[3]; + sp->t0 = p[2] << 5; + sp->t1 = base[sp->c & 1]; + sp++; + n++; + } +nope: + if(ppuy != 0){ + col = 0; + pri0 = 0; + pri1 = 128; + if((reg[OAMADDH] & 0x80) != 0) + prio = oamaddr >> 2; + else + prio = 0; + for(i = 0, tp = t; i < m; i++, tp++){ + dx = rx - tp->x; + if(dx < 0 || dx >= tp->sx) + continue; + p = tp->ch + (dx >> 1 & 0xfc); + if((tp->c & 0x40) != 0){ + v = p[2] & 1 | p[3] << 1 & 2 | p[0] << 2 & 4 | p[1] << 3 & 8; + p[0] >>= 1; + p[1] >>= 1; + p[2] >>= 1; + p[3] >>= 1; + }else{ + v = p[0] >> 7 & 1 | p[1] >> 6 & 2 | p[2] >> 5 & 4 | p[3] >> 4 & 8; + p[0] <<= 1; + p[1] <<= 1; + p[2] <<= 1; + p[3] <<= 1; + } + nt = (tp->i - prio) & 0x7f; + if(v != 0 && nt < pri1){ + col = tp->pal + v; + pri0 = tp->pri; + pri1 = nt; + } + } + if(col > 0) + pixel(OBJ, col, pri0); + } + if(rx == 255){ + cp = ch; + m = n; + for(sp = s + n - 1, tp = t + n - 1; sp >= s; sp--, tp--){ + tp->x = sp->x; + tp->sx = 0; + tp->c = sp->c; + tp->pal = 0x80 | sp->c << 3 & 0x70; + tp->pri = 3 * (0x10 + (sp->c & 0x30)); + if((tp->c & 8) != 0) + tp->pri |= OBJ; + else + tp->pri |= OBJNC; + tp->ch = cp; + tp->i = sp->i; + nt = sp->sx >> 2; + dy = ppuy - sp->y; + if((sp->c & 0x80) != 0) + dy = sp->sy - 1 - dy; + a = sp->t0 | (dy & 7) << 1; + if(dy >= 8) + a += (dy & ~7) << 6; + if((sp->c & 0x40) != 0){ + a += sp->sx * 4; + for(i = 0; i < nt; i++){ + if(cp < ch + sizeof(ch)){ + a -= 16; + *(u16int*)cp = *(u16int*)&vram[sp->t1 | a & 0x1fff]; + cp += 2; + tp->sx += 4; + }else + over |= 0x80; + } + }else + for(i = 0; i < nt; i++){ + if(cp < ch + sizeof(ch)){ + *(u16int*)cp = *(u16int*)&vram[sp->t1 | a & 0x1fff]; + cp += 2; + tp->sx += 4; + a += 16; + }else + over |= 0x80; + } + } + reg[0x213e] = over; + } +} + +static u16int +colormath(void) +{ + u16int v, w, r, g, b; + u8int m, m2; + int cw; + + m = reg[CGWSEL]; + m2 = reg[CGADSUB]; + cw = -1; + switch(m >> 6){ + default: v = 1; break; + case 1: v = cw = window(COL); break; + case 2: v = !(cw = window(COL)); break; + case 3: v = 0; break; + } + if(v){ + if((pixelcol[0] & 0x10000) != 0) + v = pixelcol[0]; + else + v = cgram[pixelcol[0] & 0xff]; + } + if((m2 & (1 << (pixelpri[0] & 0xf))) == 0) + return v; + switch((m >> 4) & 3){ + case 0: break; + case 1: if(cw < 0) cw = window(COL); if(!cw) return v; break; + case 2: if(cw < 0) cw = window(COL); if(cw) return v; break; + default: return v; + } + if((m & 2) != 0){ + if((pixelcol[1] & 0x10000) != 0) + w = pixelcol[1]; + else + w = cgram[pixelcol[1] & 0xff]; + }else + w = subcolor; + if((m2 & 0x80) != 0){ + r = (v & 0x7c00) - (w & 0x7c00); + g = (v & 0x03e0) - (w & 0x03e0); + b = (v & 0x001f) - (w & 0x001f); + if((m2 & 0x40) != 0){ + r = (r >> 1) & 0xfc00; + g = (g >> 1) & 0xffe0; + b >>= 1; + } + if(r > 0x7c00) r = 0; + if(g > 0x03e0) g = 0; + if(b > 0x001f) b = 0; + return r | g | b; + }else{ + r = (v & 0x7c00) + (w & 0x7c00); + g = (v & 0x03e0) + (w & 0x03e0); + b = (v & 0x001f) + (w & 0x001f); + if((m2 & 0x40) != 0){ + r = (r >> 1) & 0xfc00; + g = (g >> 1) & 0xffe0; + b >>= 1; + } + if(r > 0x7c00) r = 0x7c00; + if(g > 0x03e0) g = 0x03e0; + if(b > 0x001f) b = 0x001f; + return r | g | b; + } +} + +void +ppustep(void) +{ + int yvbl; + + mode = reg[BGMODE] & 7; + bright = reg[INIDISP] & 0xf; + yvbl = (reg[SETINI] & OVERSCAN) != 0 ? 0xf0 : 0xe1; + + if(ppux >= XLEFT && ppux <= XRIGHT && ppuy < 0xf0){ + rx = ppux - XLEFT; + if(ppuy < yvbl && (reg[INIDISP] & 0x80) == 0){ + pixelcol[0] = 0; + pixelpri[0] = COL; + pixelcol[1] = 0x10000 | subcolor; + pixelpri[1] = COL; + bgs(); + sprites(); + if(ppuy != 0) + pixeldraw(rx, ppuy - 1, colormath()); + }else if(ppuy != 0) + pixeldraw(rx, ppuy - 1, ppuy >= yvbl ? 0x31c8 : 0); + } + + if(ppux == 0x116 && ppuy <= yvbl) + hdma |= reg[0x420c]; + if((reg[NMITIMEN] & HCNTIRQ) != 0 && htime == ppux && ((reg[NMITIMEN] & VCNTIRQ) == 0 || vtime == ppuy)) + irq |= IRQPPU; + if(++ppux >= 340){ + ppux = 0; + if(++ppuy >= 262){ + ppuy = 0; + reg[RDNMI] &= ~VBLANK; + hdma = reg[0x420c]<<8; + flush(); + } + if(ppuy == yvbl){ + reg[RDNMI] |= VBLANK; + if((reg[NMITIMEN] & VBLANK) != 0) + nmi = 2; + if((reg[NMITIMEN] & AUTOJOY) != 0){ + reg[0x4218] = keys; + reg[0x4219] = keys >> 8; + keylatch = 0xffff; + } + } + if((reg[NMITIMEN] & (HCNTIRQ|VCNTIRQ)) == VCNTIRQ && vtime == ppuy) + irq |= IRQPPU; + } +} diff --git a/sys/src/games/snes/snes.c b/sys/src/games/snes/snes.c new file mode 100644 index 000000000..44c6b76f6 --- /dev/null +++ b/sys/src/games/snes/snes.c @@ -0,0 +1,258 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <draw.h> +#include <keyboard.h> +#include <mouse.h> +#include <ctype.h> +#include "dat.h" +#include "fns.h" + +uchar *prg, *sram; +int nprg, nsram, hirom, battery; + +int ppuclock, spcclock, stimerclock, saveclock, msgclock, paused; +Mousectl *mc; +QLock pauselock; +int keys, savefd; +int scale; +Rectangle picr; +Image *tmp, *bg; + +void +flushram(void) +{ + if(savefd >= 0) + pwrite(savefd, sram, nsram, 0); + saveclock = 0; +} + +void +loadrom(char *file) +{ + static char buf[512]; + char *s; + int fd; + vlong size; + + fd = open(file, OREAD); + if(fd < 0) + sysfatal("open: %r"); + size = seek(fd, 0, 2); + if(size < 0) + sysfatal("seek: %r"); + if(size == 0) + sysfatal("empty file"); + if((size & 1023) == 512){ + size -= 512; + seek(fd, 512, 0); + }else if((size & 1023) == 0) + seek(fd, 0, 0); + else + sysfatal("invalid rom size"); + if(size >= 16*1048576) + sysfatal("rom too big"); + nprg = (size + 32767) / 32768; + prg = malloc(nprg * 32768); + if(prg == nil) + sysfatal("malloc: %r"); + if(readn(fd, prg, size) < size) + sysfatal("read: %r"); + close(fd); + switch(memread(0xffd6)){ + case 0: + break; + case 2: + battery++; + case 1: + nsram = memread(0xffd8); + if(nsram == 0) + break; + if(nsram >= 0x0c) + sysfatal("invalid rom (too much ram specified)"); + nsram = 1<<(nsram + 10); + sram = malloc(nsram); + if(sram == nil) + sysfatal("malloc: %r"); + break; + default: + print("unknown rom type %d\n", memread(0xffd5)); + } + if(battery && nsram != 0){ + strncpy(buf, file, sizeof buf - 5); + s = buf + strlen(buf) - 4; + if(s < buf || strcmp(s, ".smc") != 0) + s += 4; + strcpy(s, ".sav"); + savefd = create(buf, ORDWR | OEXCL, 0666); + if(savefd < 0) + savefd = open(buf, ORDWR); + if(savefd < 0) + message("open: %r"); + else + readn(savefd, sram, nsram); + atexit(flushram); + } +} + +void +keyproc(void *) +{ + int fd, k; + static char buf[256]; + char *s; + Rune r; + + fd = open("/dev/kbd", OREAD); + if(fd < 0) + sysfatal("open: %r"); + for(;;){ + if(read(fd, buf, sizeof(buf) - 1) <= 0) + sysfatal("read /dev/kbd: %r"); + if(buf[0] == 'c'){ + if(utfrune(buf, Kdel)){ + close(fd); + threadexitsall(nil); + } + if(utfrune(buf, 't')) + trace = !trace; + } + if(buf[0] != 'k' && buf[0] != 'K') + continue; + s = buf + 1; + k = 0; + while(*s != 0){ + s += chartorune(&r, s); + switch(r){ + case Kdel: close(fd); threadexitsall(nil); + case 'z': k |= 1<<15; break; + case 'x': k |= 1<<7; break; + case 'a': k |= 1<<14; break; + case 's': k |= 1<<6; break; + case 'q': k |= 1<<5; break; + case 'w': k |= 1<<4; break; + case Kshift: k |= 1<<13; break; + case 10: k |= 1<<12; break; + case Kup: k |= 1<<11; break; + case Kdown: k |= 1<<10; break; + case Kleft: k |= 1<<9; break; + case Kright: k |= 1<<8; break; + case Kesc: + if(paused) + qunlock(&pauselock); + else + qlock(&pauselock); + paused = !paused; + break; + } + } + keys = k; + } +} + +void +screeninit(void) +{ + Point p; + + originwindow(screen, Pt(0, 0), screen->r.min); + p = divpt(addpt(screen->r.min, screen->r.max), 2); + picr = (Rectangle){subpt(p, Pt(scale * 128, scale * 112)), addpt(p, Pt(scale * 128, scale * 112))}; + tmp = allocimage(display, Rect(0, 0, scale * 256, scale * 239), RGB15, 0, 0); + bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF); + draw(screen, screen->r, bg, nil, ZP); +} + +void +threadmain(int argc, char **argv) +{ + int t; + extern u16int pc; + + scale = 1; + ARGBEGIN { + case 's': + battery++; + break; + } ARGEND; + + if(argc != 1){ + fprint(2, "usage: %s rom\n", argv0); + threadexitsall("usage"); + } + loadrom(argv[0]); + if(initdraw(nil, nil, nil) < 0) + sysfatal("initdraw: %r"); + mc = initmouse(nil, screen); + if(mc == nil) + sysfatal("initmouse: %r"); + screeninit(); + proccreate(keyproc, 0, 8192); + cpureset(); + memreset(); + spcreset(); + for(;;){ + if(paused){ + qlock(&pauselock); + qunlock(&pauselock); + } + t = cpustep() * 8; + spcclock -= t; + stimerclock += t; + ppuclock += t; + + while(ppuclock >= 4){ + ppustep(); + ppuclock -= 4; + } + while(spcclock < 0) + spcclock += spcstep() * SPCDIV; + if(stimerclock >= SPCDIV*16){ + spctimerstep(); + stimerclock -= SPCDIV*16; + } + if(saveclock > 0){ + saveclock -= t; + if(saveclock <= 0) + flushram(); + } + if(msgclock > 0){ + msgclock -= t; + if(msgclock <= 0){ + draw(screen, screen->r, bg, nil, ZP); + msgclock = 0; + } + } + } +} + +void +flush(void) +{ + extern uchar pic[256*240*2*9]; + Mouse m; + + while(nbrecv(mc->c, &m) > 0) + ; + if(nbrecvul(mc->resizec) > 0){ + if(getwindow(display, Refnone) < 0) + sysfatal("resize failed: %r"); + screeninit(); + } + loadimage(tmp, tmp->r, pic, 256*239*2*scale*scale); + draw(screen, picr, tmp, nil, ZP); + flushimage(display, 1); +} + +void +message(char *fmt, ...) +{ + va_list va; + static char buf[512]; + + va_start(va, fmt); + vsnprint(buf, sizeof buf, fmt, va); + string(screen, Pt(10, 10), display->black, ZP, display->defaultfont, buf); + msgclock = FREQ; + va_end(va); +} diff --git a/sys/src/games/snes/spc.c b/sys/src/games/snes/spc.c new file mode 100644 index 000000000..9cabeb92e --- /dev/null +++ b/sys/src/games/snes/spc.c @@ -0,0 +1,740 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include "dat.h" +#include "fns.h" + +u8int sA, sX, sY, sP, sS; +u16int spc, scurpc; +u8int spcmem[65536]; +u8int spctimer[4]; +static u8int ipl[64]; + +enum { + SPCN = 1<<7, + SPCV = 1<<6, + SPCP = 1<<5, + SPCB = 1<<4, + SPCH = 1<<3, + SPCI = 1<<2, + SPCZ = 1<<1, + SPCC = 1<<0, +}; + +static u8int +spcread(u16int p) +{ + u8int v; + + if(p >= 0xffc0 && (spcmem[0xf1] & 0x80) != 0) + return ipl[p - 0xffc0]; + if((p & 0xfff0) == 0x00f0) + switch(p){ + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + return reg[0x2140 | p & 3]; + case 0xfa: + case 0xfb: + case 0xfc: + return 0; + case 0xfd: + case 0xfe: + case 0xff: + v = spcmem[p]; + spcmem[p] = 0; + return v; + } + return spcmem[p]; +} + +static void +spcwrite(u16int p, u8int v) +{ + if((p & 0xfff0) == 0x00f0) + switch(p){ + case 0xf0: + if(v != 0x0a) + print("SPC test register set to value %#x != 0xa\n", v); + return; + case 0xf1: + if((v & 0x10) != 0) + reg[0x2140] = reg[0x2141] = 0; + if((v & 0x20) != 0) + reg[0x2142] = reg[0x2143] = 0; + if((spcmem[0xf1] & 1) == 0 && (v & 1) != 0) + spctimer[0] = spcmem[0xfd] = 0; + if((spcmem[0xf1] & 2) == 0 && (v & 2) != 0) + spctimer[1] = spcmem[0xfe] = 0; + if((spcmem[0xf1] & 4) == 0 && (v & 4) != 0) + spctimer[2] = spcmem[0xff] = 0; + break; + case 0xfd: + case 0xfe: + case 0xff: + return; + } + spcmem[p] = v; +} + +void +spctimerstep(void) +{ + u8int m; + + m = spcmem[0xf1]; + if(spctimer[3] == 7){ + spctimer[3] = 0; + if((m & 1) != 0 && ++spctimer[0] == spcmem[0xfa]){ + spctimer[0] = 0; + spcmem[0xfd] = (spcmem[0xfd] + 1) & 0xf; + } + if((m & 2) != 0 && ++spctimer[1] == spcmem[0xfb]){ + spctimer[1] = 0; + spcmem[0xfe] = (spcmem[0xfe] + 1) & 0xf; + } + }else + spctimer[3]++; + if((m & 4) != 0 && ++spctimer[2] == spcmem[0xfc]){ + spctimer[2] = 0; + spcmem[0xff] = (spcmem[0xff] + 1) & 0xf; + } +} + +static u8int +fetch8(void) +{ + return spcread(spc++); +} + +static u16int +fetch16(void) +{ + int a; + + a = fetch8(); + a |= fetch8() << 8; + return a; +} + +static u16int +mem16(u16int p) +{ + int a; + + a = spcread(p++); + a |= spcread(p) << 8; + return a; +} + +static u16int +memd16(u16int p) +{ + int a; + + a = spcread(p); + if((p & 0xff) == 0xff) + p &= ~0xff; + else + p++; + a |= spcread(p) << 8; + return a; +} + +static void +push8(u8int v) +{ + spcwrite(0x100 | sS--, v); +} + +static void +push16(u16int v) +{ + spcwrite(0x100 | sS--, v>>8); + spcwrite(0x100 | sS--, v); +} + +static u8int +pop8(void) +{ + return spcread(0x100 | ++sS); +} + +static u16int +pop16(void) +{ + u16int v; + + v = spcread(0x100 | ++sS); + v |= spcread(0x100 | ++sS) << 8; + return v; +} + +#define imm() fetch8() +#define dp ((sP&SPCP)<<3) +#define azp() (fetch8()|dp) +#define azpX() ((u8int)(fetch8()+sX)|dp) +#define azpY() ((u8int)(fetch8()+sY)|dp) +#define zp() spcread(azp()) +#define zpX() spcread(azpX()) +#define zpY() spcread(azpY()) +#define abs() spcread(fetch16()) +#define absX() spcread(fetch16()+sX) +#define absY() spcread(fetch16()+sY) +#define indX() spcread(aindX()) +#define indY() spcread(aindY()) + +static u16int +aindX(void) +{ + u8int r; + u16int a; + + r = fetch8() + sX; + a = spcread(r++ | dp); + a |= spcread(r | dp) << 8; + return a; +} + +static u16int +aindY(void) +{ + u8int r; + u16int a; + + r = fetch8(); + a = spcread(r++ | dp) + sY; + a += spcread(r | dp) << 8; + return a; +} + +static u8int +nz(u8int v) +{ + sP &= ~(SPCN|SPCZ); + sP |= v & 0x80; + if(v == 0) + sP |= SPCZ; + return v; +} + +static void +nz16(void) +{ + sP &= ~(SPCN|SPCZ); + if(sA == 0 && sY == 0) + sP |= SPCZ; + if(sY & 0x80) + sP |= SPCN; +} + +static int +branch(int c, int n) +{ + static char s; + u16int npc; + + if(!c){ + spc++; + return n; + } + s = fetch8(); + npc = spc + s; + if(((npc ^ spc) & 0xff00) != 0) + n++; + spc = npc; + return ++n; +} + +static void +clrb(u16int a, int b) +{ + spcwrite(a, spcread(a) & ~(1<<b)); +} + +static void +cmp(u8int a, u8int b) +{ + sP &= ~(SPCZ|SPCN|SPCC); + if(a >= b) + sP |= SPCC; + if(a == b) + sP |= SPCZ; + if((a - b) & 0x80) + sP |= SPCN; +} + +static u8int +adc(u8int a, u8int b) +{ + u16int r; + u8int r8; + + r8 = r = a + b + (sP & SPCC); + sP &= ~(SPCC|SPCZ|SPCH|SPCV|SPCN); + if(r >= 0x100) + sP |= SPCC; + sP |= r8 & SPCN; + if((a ^ b ^ r) & 0x10) + sP |= SPCH; + if((~(a ^ b) & (a ^ r)) & 0x80) + sP |= SPCV; + if(r8 == 0) + sP |= SPCZ; + return r8; +} + +static void +inc(u16int a) +{ + spcwrite(a, nz(spcread(a) + 1)); +} + +static void +jsr(u16int a) +{ + push16(spc); + spc = a; +} +static void +asl(u16int a) +{ + u8int v; + + v = spcread(a); + sP &= ~SPCC; + sP |= v >> 7 & 1; + spcwrite(a, nz(v << 1)); +} + +static void +lsr(u16int a) +{ + u8int v; + + v = spcread(a); + sP &= ~SPCC; + sP |= v & 1; + spcwrite(a, nz(v >> 1)); +} + +static void +rol(u16int a) +{ + u8int v, c; + + v = spcread(a); + c = sP & SPCC; + sP &= ~SPCC; + sP |= v >> 7 & 1; + v = v<<1 | c; + spcwrite(a, nz(v)); +} + +static void +inc16(u16int a, int c) +{ + u16int v; + + v = memd16(a) + c; + sP &= ~(SPCN|SPCZ); + if(v == 0) + sP |= SPCZ; + if((v & 0x8000) != 0) + sP |= SPCN; + spcwrite(a, v); + spcwrite(a+1, v>>8); +} + +static void +ror(u16int a) +{ + u8int v, c; + + v = spcread(a); + c = sP & SPCC; + sP &= ~SPCC; + sP |= v & 1; + v = v>>1 | c<<7; + spcwrite(a, nz(v)); +} + +static u8int +sbc(u8int a, u8int b) +{ + return adc(a, ~b); +} + +static void +setb(u16int a, int b) +{ + spcwrite(a, spcread(a) | (1<<b)); +} + +static void +setnbit(u16int a, int c) +{ + u8int v, b; + + b = a >> 13; + v = spcread(a & 0x1fff) & ~(1<<b); + if(c) + v |= (1<<b); + spcwrite(a & 0x1fff, v); +} + +static void +tset(u16int a, int set) +{ + u8int v; + + v = spcread(a); + nz(sA - v); + if(set) + v |= sA; + else + v &= ~sA; + spcwrite(a, v); +} + +static void +div(void) +{ + u32int v, x; + int i; + + sP &= ~(SPCH|SPCV); + if((sX & 0xf) <= (sY & 0xf)) + sP |= SPCH; + v = sA | sY << 8; + x = sX << 9; + for(i = 0; i < 9; i++){ + v = (v << 1 | v >> 16) & 0x1ffff; + if(v >= x) + v ^= 1; + if((v & 1) != 0) + v = (v - x) & 0x1ffff; + } + nz(sA = v); + sY = v >> 9; + if((v & 0x100) != 0) + sP |= SPCV; +} + +void +spcreset(void) +{ + spcmem[0xf0] = 0x0a; + spcmem[0xf1] = 0xb0; + spc = spcread(0xfffe) | spcread(0xffff) << 8; +} + +int +spcstep(void) +{ + static int ctr; + u8int op, a; + u16int b, c; + + scurpc = spc; + op = fetch8(); + if(trace) + print("SPC %.4x %.2x A=%.2x X=%.2x Y=%.2x P=%.2x S=%.2x\n", spc-1, op, sA, sX, sY, sP, sS); + switch(op){ + case 0x01: jsr(mem16(0xffde)); return 8; + case 0x02: setb(azp(), 0); return 4; + case 0x03: return branch((zp() & 0x01) != 0, 5); + case 0x04: nz(sA |= zp()); return 3; + case 0x05: nz(sA |= abs()); return 4; + case 0x06: nz(sA |= spcread(sX|dp)); return 3; + case 0x07: nz(sA |= indX()); return 6; + case 0x08: nz(sA |= imm()); return 2; + case 0x09: b = zp(); c = azp(); spcwrite(c, nz(b | spcread(c))); return 6; + case 0x0A: b = fetch16(); sP |= (spcread(b & 0x1fff) >> (b >> 13)) & 1; return 4; + case 0x0B: asl(azp()); return 5; + case 0x0C: asl(fetch16()); return 5; + case 0x0D: push8(sP); return 4; + case 0x0E: tset(fetch16(), 1); return 6; + case 0x10: return branch((sP & SPCN) == 0, 2); + case 0x11: jsr(mem16(0xffdc)); return 8; + case 0x12: clrb(azp(), 0); return 4; + case 0x13: return branch((zp() & 0x01) == 0, 5); + case 0x14: nz(sA |= zpX()); return 4; + case 0x15: nz(sA |= absX()); return 5; + case 0x16: nz(sA |= absY()); return 5; + case 0x17: nz(sA |= indY()); return 6; + case 0x18: a = imm(); b = azp(); spcwrite(b, nz(spcread(b) | a)); return 5; + case 0x19: spcwrite(sX|dp, nz(spcread(sX|dp) | spcread(sY|dp))); return 5; + case 0x1A: inc16(azp(), -1); return 6; + case 0x1B: asl(azpX()); return 5; + case 0x1C: sP &= ~SPCC; sP |= sA >> 7; nz(sA <<= 1); return 2; + case 0x1D: nz(--sX); return 2; + case 0x1E: cmp(sX, abs()); return 4; + case 0x1F: spc = mem16(fetch16() + sX); return 6; + case 0x20: sP &= ~SPCP; return 2; + case 0x21: jsr(mem16(0xffda)); return 8; + case 0x22: setb(azp(), 1); return 4; + case 0x23: return branch((zp() & 0x02) != 0, 5); + case 0x24: nz(sA &= zp()); return 3; + case 0x25: nz(sA &= abs()); return 4; + case 0x26: nz(sA &= spcread(sX|dp)); return 3; + case 0x27: nz(sA &= indX()); return 6; + case 0x28: nz(sA &= imm()); return 2; + case 0x29: b = zp(); c = azp(); spcwrite(c, nz(b & spcread(c))); return 6; + case 0x2A: b = fetch16(); sP |= (~spcread(b & 0x1fff) >> (b >> 13)) & 1; return 4; + case 0x2B: rol(azp()); return 4; + case 0x2C: rol(fetch16()); return 5; + case 0x2D: push8(sA); return 4; + case 0x2E: return branch(sA != zp(), 5); + case 0x2F: return branch(1, 2); + case 0x30: return branch((sP & SPCN) != 0, 2); + case 0x31: jsr(mem16(0xffd8)); return 8; + case 0x32: clrb(azp(), 1); return 4; + case 0x33: return branch((zp() & 0x02) == 0, 5); + case 0x34: nz(sA &= zpX()); return 4; + case 0x35: nz(sA &= absX()); return 5; + case 0x36: nz(sA &= absY()); return 5; + case 0x37: nz(sA &= indY()); return 6; + case 0x38: a = imm(); b = azp(); spcwrite(b, nz(spcread(b) & a)); return 5; + case 0x39: spcwrite(sX|dp, nz(spcread(sX|dp) & spcread(sY|dp))); return 5; + case 0x3A: inc16(azp(), 1); return 6; + case 0x3B: rol(azpX()); return 5; + case 0x3C: + a = sP & SPCC; + sP &= ~SPCC; + sP |= sA >> 7 & 1; + sA = sA << 1 | a; + nz(sA); + return 2; + case 0x3D: nz(++sX); return 2; + case 0x3E: cmp(sX, zp()); return 3; + case 0x3F: jsr(fetch16()); return 8; + case 0x40: sP |= SPCP; return 2; + case 0x41: jsr(mem16(0xffd6)); return 8; + case 0x42: setb(azp(), 2); return 4; + case 0x43: return branch((zp() & 0x04) != 0, 5); + case 0x44: nz(sA ^= zp()); return 3; + case 0x45: nz(sA ^= abs()); return 4; + case 0x46: nz(sA ^= spcread(sX|dp)); return 3; + case 0x47: nz(sA ^= indX()); return 6; + case 0x48: nz(sA ^= imm()); return 2; + case 0x49: b = zp(); c = azp(); spcwrite(c, nz(b ^ spcread(c))); return 6; + case 0x4A: b = fetch16(); sP &= 0xfe | (spcread(b & 0x1fff) >> (b >> 13)) & 1; return 4; + case 0x4B: lsr(azp()); return 4; + case 0x4C: lsr(fetch16()); return 5; + case 0x4D: push8(sX); return 4; + case 0x4E: tset(fetch16(), 0); return 5; + case 0x4F: jsr(0xff00 | fetch8()); return 6; + case 0x50: return branch((sP & SPCV) == 0, 2); + case 0x51: jsr(mem16(0xffd4)); return 8; + case 0x52: clrb(azp(), 2); return 4; + case 0x53: return branch((zp() & 0x04) == 0, 5); + case 0x54: nz(sA ^= zpX()); return 4; + case 0x55: nz(sA ^= absX()); return 5; + case 0x56: nz(sA ^= absY()); return 5; + case 0x57: nz(sA ^= indY()); return 6; + case 0x58: a = imm(); b = azp(); spcwrite(b, nz(spcread(b) ^ a)); return 5; + case 0x59: spcwrite(sX|dp, nz(spcread(sX|dp) ^ spcread(sY|dp))); return 5; + case 0x5A: + b = sA | sY << 8; + c = memd16(azp()); + sP &= ~(SPCN|SPCZ|SPCC); + if(b >= c) + sP |= SPCC; + if(b == c) + sP |= SPCZ; + if(((b - c) & 0x8000) != 0) + sP |= SPCN; + return 4; + case 0x5B: lsr(azpX()); return 4; + case 0x5C: sP &= ~SPCC; sP |= sA & 1; nz(sA >>= 1); return 2; + case 0x5D: nz(sX = sA); return 2; + case 0x5E: cmp(sY, abs()); return 4; + case 0x5F: spc = fetch16(); return 3; + case 0x60: sP &= ~SPCC; return 2; + case 0x61: jsr(mem16(0xffd2)); return 8; + case 0x62: setb(azp(), 3); return 4; + case 0x63: return branch((zp() & 0x08) != 0, 5); + case 0x64: cmp(sA, zp()); return 3; + case 0x65: cmp(sA, abs()); return 4; + case 0x66: cmp(sA, spcread(sX|dp)); return 3; + case 0x67: cmp(sA, indX()); return 6; + case 0x68: cmp(sA, imm()); return 2; + case 0x69: a = zp(); cmp(zp(), a); return 6; + case 0x6A: b = fetch16(); sP &= ~((spcread(b & 0x1fff) >> (b >> 13)) & 1); return 4; + case 0x6B: ror(azp()); return 4; + case 0x6C: ror(fetch16()); return 5; + case 0x6D: push8(sY); return 4; + case 0x6E: b = azp(); a = spcread(b)-1; spcwrite(b, a); return branch(a != 0, 5); + case 0x6F: spc = pop16(); return 5; + case 0x70: return branch((sP & SPCV) != 0, 2); + case 0x72: clrb(azp(), 3); return 4; + case 0x71: jsr(mem16(0xffd0)); return 8; + case 0x73: return branch((zp() & 0x08) == 0, 5); + case 0x74: cmp(sA, zpX()); return 4; + case 0x75: cmp(sA, absX()); return 5; + case 0x76: cmp(sA, absY()); return 5; + case 0x77: cmp(sA, indY()); return 6; + case 0x78: a = imm(); cmp(zp(), a); return 5; + case 0x79: cmp(spcread(sX|dp), spcread(sY|dp)); return 5; + case 0x7A: + b = memd16(azp()); + sA = adc(sA, b); + sY = adc(sY, b >> 8); + if(sA != 0) + sP &= ~SPCZ; + return 5; + case 0x7B: ror(azpX()); return 5; + case 0x7C: + a = sP & SPCC; + sP &= ~SPCC; + sP |= sA & 1; + sA = sA >> 1 | a << 7; + nz(sA); + return 2; + case 0x7D: nz(sA = sX); return 2; + case 0x7E: cmp(sY, zp()); return 3; + case 0x7F: sP = pop8(); spc = pop16(); return 6; + case 0x80: sP |= SPCC; return 2; + case 0x81: jsr(mem16(0xffce)); return 8; + case 0x82: setb(azp(), 4); return 4; + case 0x83: return branch((zp() & 0x10) != 0, 5); + case 0x84: sA = adc(sA, zp()); return 3; + case 0x85: sA = adc(sA, abs()); return 4; + case 0x86: sA = adc(sA, spcread(sX|dp)); return 3; + case 0x87: sA = adc(sA, indX()); return 6; + case 0x88: sA = adc(sA, imm()); return 2; + case 0x89: b = zp(); c = azp(); spcwrite(c, adc(b, spcread(c))); return 6; + case 0x8A: b = fetch16(); sP ^= (spcread(b & 0x1fff) >> (b >> 13)) & 1; return 4; + case 0x8B: b = azp(); spcwrite(b, nz(spcread(b)-1)); return 4; + case 0x8C: b = fetch16(); spcwrite(b, nz(spcread(b)-1)); return 4; + case 0x8D: nz(sY = imm()); return 2; + case 0x8E: sP = pop8(); return 2; + case 0x8F: a = fetch8(); spcwrite(azp(), a); return 5; + case 0x90: return branch((sP & SPCC) == 0, 2); + case 0x91: jsr(mem16(0xffcc)); return 8; + case 0x92: clrb(azp(), 4); return 4; + case 0x93: return branch((zp() & 0x10) == 0, 5); + case 0x94: sA = adc(sA, zpX()); return 4; + case 0x95: sA = adc(sA, absX()); return 5; + case 0x96: sA = adc(sA, absY()); return 5; + case 0x97: sA = adc(sA, indY()); return 6; + case 0x98: a = imm(); b = azp(); spcwrite(b, adc(spcread(b), a)); return 5; + case 0x99: spcwrite(sX|dp, adc(spcread(sX|dp), spcread(sY|dp))); return 5; + case 0x9A: + b = memd16(azp()); + sA = sbc(sA, b); + sY = sbc(sY, b >> 8); + if(sA != 0) + sP &= ~SPCZ; + return 5; + case 0x9B: b = azpX(); spcwrite(b, nz(spcread(b)-1)); return 4; + case 0x9C: nz(--sA); return 2; + case 0x9D: nz(sX = sS); return 2; + case 0x9E: div(); return 12; + case 0x9F: nz(sA = sA >> 4 | sA << 4); return 5; + case 0xA0: sP |= SPCI; return 2; + case 0xA1: jsr(mem16(0xffca)); return 8; + case 0xA2: setb(azp(), 5); return 4; + case 0xA3: return branch((zp() & 0x20) != 0, 5); + case 0xA4: sA = sbc(sA, zp()); return 3; + case 0xA5: sA = sbc(sA, abs()); return 4; + case 0xA6: sA = sbc(sA, spcread(sX|dp)); return 3; + case 0xA7: sA = sbc(sA, indX()); return 6; + case 0xA8: sA = sbc(sA, imm()); return 2; + case 0xA9: b = zp(); c = azp(); spcwrite(c, sbc(spcread(c), b)); return 6; + case 0xAA: b = fetch16(); sP &= ~1; sP |= (spcread(b & 0x1fff) >> (b >> 13)) & 1; return 4; + case 0xAB: inc(azp()); return 4; + case 0xAC: inc(fetch16()); return 5; + case 0xAD: cmp(sY, imm()); return 2; + case 0xAE: sA = pop8(); return 2; + case 0xAF: spcwrite(sX++|dp, sA); return 4; + case 0xB0: return branch((sP & SPCC) != 0, 2); + case 0xB1: jsr(mem16(0xffc8)); return 8; + case 0xB2: clrb(azp(), 5); return 4; + case 0xB3: return branch((zp() & 0x20) == 0, 5); + case 0xB4: sA = sbc(sA, zpX()); return 4; + case 0xB5: sA = sbc(sA, absX()); return 5; + case 0xB6: sA = sbc(sA, absY()); return 5; + case 0xB7: sA = sbc(sA, indY()); return 6; + case 0xB8: a = imm(); b = azp(); spcwrite(b, sbc(spcread(b), a)); return 5; + case 0xB9: spcwrite(sX|dp, sbc(spcread(sX|dp), spcread(sY|dp))); return 5; + case 0xBA: a = fetch8(); sA = spcread(a++|dp); sY = spcread(a|dp); nz16(); return 5; + case 0xBB: inc(azpX()); return 4; + case 0xBC: nz(++sA); return 2; + case 0xBD: sS = sX; return 2; + case 0xBF: nz(sA = spcread(sX++|dp)); return 3; + case 0xC0: sP &= ~SPCI; return 2; + case 0xC1: jsr(mem16(0xffc6)); return 8; + case 0xC2: setb(azp(), 6); return 4; + case 0xC3: return branch((zp() & 0x40) != 0, 5); + case 0xC4: spcwrite(azp(), sA); return 4; + case 0xC5: spcwrite(fetch16(), sA); return 5; + case 0xC6: spcwrite(sX|dp, sA); return 4; + case 0xC7: spcwrite(aindX(), sA); return 7; + case 0xC8: cmp(sX, imm()); return 2; + case 0xC9: spcwrite(fetch16(), sX); return 5; + case 0xCA: b = fetch16(); setnbit(b, sP & SPCC); return 6; + case 0xCB: spcwrite(azp(), sY); return 4; + case 0xCC: spcwrite(fetch16(), sY); return 5; + case 0xCD: nz(sX = imm()); return 2; + case 0xCE: sX = pop8(); return 2; + case 0xCF: b = sY * sA; nz(sY = b >> 8); sA = b; return 9; + case 0xD0: return branch((sP & SPCZ) == 0, 2); + case 0xD1: jsr(mem16(0xffc4)); return 8; + case 0xD2: clrb(azp(), 6); return 4; + case 0xD3: return branch((zp() & 0x40) == 0, 5); + case 0xD4: spcwrite(azpX(), sA); return 4; + case 0xD5: spcwrite(fetch16() + sX, sA); return 6; + case 0xD6: spcwrite(fetch16() + sY, sA); return 6; + case 0xD7: spcwrite(aindY(), sA); return 7; + case 0xD8: spcwrite(azp(), sX); return 4; + case 0xD9: spcwrite(azpY(), sX); return 5; + case 0xDA: a = fetch8(); spcwrite(a++|dp, sA); spcwrite(a|dp, sY); return 5; + case 0xDB: spcwrite(azpX(), sY); return 5; + case 0xDC: nz(--sY); return 2; + case 0xDD: nz(sA = sY); return 2; + case 0xDE: return branch(sA != zpX(), 6); + case 0xE0: sP &= ~(SPCV|SPCH); return 2; + case 0xE1: jsr(mem16(0xffc2)); return 8; + case 0xE2: setb(azp(), 7); return 4; + case 0xE3: return branch((zp() & 0x80) != 0, 5); + case 0xE4: nz(sA = zp()); return 3; + case 0xE5: nz(sA = abs()); return 4; + case 0xE6: nz(sA = spcread(sX|dp)); return 3; + case 0xE7: nz(sA = indX()); return 6; + case 0xE8: nz(sA = imm()); return 2; + case 0xE9: nz(sX = abs()); return 4; + case 0xEA: b = fetch16(); spcwrite(b & 0x1fff, spcread(b & 0x1fff) ^ (1<<(b>>13))); return 6; + case 0xEB: nz(sY = zp()); return 3; + case 0xEC: nz(sY = abs()); return 4; + case 0xED: sP ^= SPCC; return 3; + case 0xEE: sY = pop8(); return 4; + case 0xF0: return branch((sP & SPCZ) != 0, 2); + case 0xF1: jsr(mem16(0xffc0)); return 8; + case 0xF2: clrb(azp(), 7); return 4; + case 0xF3: return branch((zp() & 0x80) == 0, 5); + case 0xF4: nz(sA = zpX()); return 4; + case 0xF5: nz(sA = absX()); return 5; + case 0xF6: nz(sA = absY()); return 5; + case 0xF7: nz(sA = indY()); return 6; + case 0xF8: nz(sX = zp()); return 3; + case 0xF9: nz(sX = zpY()); return 4; + case 0xFA: a = zp(); spcwrite(azp(), a); return 5; + case 0xFB: nz(sY = zpX()); return 4; + case 0xFC: nz(++sY); return 2; + case 0xFD: nz(sY = sA); return 2; + case 0xFE: return branch(--sY, 4); + default: + print("undefined spc op %.2x at %.4x\n", op, spc-1); + return 2; + } +} + +static u8int ipl[64] = { + 0xcd, 0xef, 0xbd, 0xe8, 0x00, 0xc6, 0x1d, 0xd0, 0xfc, 0x8f, 0xaa, 0xf4, 0x8f, 0xbb, 0xf5, 0x78, + 0xcc, 0xf4, 0xd0, 0xfb, 0x2f, 0x19, 0xeb, 0xf4, 0xd0, 0xfc, 0x7e, 0xf4, 0xd0, 0x0b, 0xe4, 0xf5, + 0xcb, 0xf4, 0xd7, 0x00, 0xfc, 0xd0, 0xf3, 0xab, 0x01, 0x10, 0xef, 0x7e, 0xf4, 0x10, 0xeb, 0xba, + 0xf6, 0xda, 0x00, 0xba, 0xf4, 0xc4, 0xf4, 0xdd, 0x5d, 0xd0, 0xdb, 0x1f, 0x00, 0x00, 0xc0, 0xff, +}; |