ref: 85a414751a1b9ba09dd7a72eee8746d81a7dcf53
parent: eed487167489ee16dd16effe9ebff9a5086ffc70
author: aiju <devnull@localhost>
date: Thu Mar 13 16:07:36 EDT 2014
added games/snes
--- /dev/null
+++ b/sys/src/games/snes/cpu.c
@@ -1,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;
+ }
+}
--- /dev/null
+++ b/sys/src/games/snes/dat.h
@@ -1,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,
+};
+
--- /dev/null
+++ b/sys/src/games/snes/fns.h
@@ -1,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 *, ...);
--- /dev/null
+++ b/sys/src/games/snes/mem.c
@@ -1,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;
+}
--- /dev/null
+++ b/sys/src/games/snes/mkfile
@@ -1,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
--- /dev/null
+++ b/sys/src/games/snes/ppu.c
@@ -1,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;
+ }
+}
--- /dev/null
+++ b/sys/src/games/snes/snes.c
@@ -1,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);
+}
--- /dev/null
+++ b/sys/src/games/snes/spc.c
@@ -1,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,
+};