diff --git a/index.html b/index.html
index 31c70de9..af85bf20 100644
--- a/index.html
+++ b/index.html
@@ -273,12 +273,15 @@ canvas.pixelated {
+
+
+
diff --git a/src/cpu/6809.js b/src/cpu/6809.js
new file mode 100644
index 00000000..5e45f38b
--- /dev/null
+++ b/src/cpu/6809.js
@@ -0,0 +1,2451 @@
+"use strict";
+/*
+The MIT License (MIT)
+Copyright (c) 2014 Martin Maly, http://retrocip.cz, http://www.uelectronics.info,
+twitter: @uelectronics
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+var CPU6809 = function() {
+
+var ticks;
+var rA,rB,rX,rY,rU,rS,PC,CC,DP,
+F_CARRY =1,
+F_OVERFLOW =2,
+F_ZERO =4,
+F_NEGATIVE =8,
+F_IRQMASK =16,
+F_HALFCARRY =32,
+F_FIRQMASK =64,
+F_ENTIRE =128,
+
+vecRESET = 0xFFFE,
+vecNMI = 0xFFFC,
+vecSWI = 0xFFFA,
+vecIRQ = 0xFFF8,
+vecFIRQ = 0xFFF6,
+vecSWI2 = 0xFFF4,
+vecSWI3 = 0xFFF2,
+
+T=0;
+
+var IRQs;
+
+var byteTo, byteAt;
+
+var cycles = [
+ 6,0,0,6,6,0,6,6,6,6,6,0,6,6,3,6, /* 00-0F */
+ 0,0,2,4,0,0,5,9,0,2,3,0,3,2,8,6, /* 10-1F */
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, /* 20-2F */
+ 4,4,4,4,5,5,5,5,0,5,3,6,9,11,0,19, /* 30-3F */
+ 2,0,0,2,2,0,2,2,2,2,2,0,2,2,0,2, /* 40-4F */
+ 2,0,0,2,2,0,2,2,2,2,2,0,2,2,0,2, /* 50-5F */
+ 6,0,0,6,6,0,6,6,6,6,6,0,6,6,3,6, /* 60-6F */
+ 7,0,0,7,7,0,7,7,7,7,7,0,7,7,4,7, /* 70-7F */
+ 2,2,2,4,2,2,2,0,2,2,2,2,4,7,3,0, /* 80-8F */
+ 4,4,4,6,4,4,4,4,4,4,4,4,6,7,5,5, /* 90-9F */
+ 4,4,4,6,4,4,4,4,4,4,4,4,6,7,5,5, /* A0-AF */
+ 5,5,5,7,5,5,5,5,5,5,5,5,7,8,6,6, /* B0-BF */
+ 2,2,2,4,2,2,2,0,2,2,2,2,3,0,3,0, /* C0-CF */
+ 4,4,4,6,4,4,4,4,4,4,4,4,5,5,5,5, /* D0-DF */
+ 4,4,4,6,4,4,4,4,4,4,4,4,5,5,5,5, /* E0-EF */
+ 5,5,5,7,5,5,5,5,5,5,5,5,6,6,6,6]; /* F0-FF */
+
+/* Instruction timing for the two-byte opcodes */
+var cycles2 = [
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00-0F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10-1F */
+ 0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, /* 20-2F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20, /* 30-3F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40-4F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50-5F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60-6F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70-7F */
+ 0,0,0,5,0,0,0,0,0,0,0,0,5,0,4,0, /* 80-8F */
+ 0,0,0,7,0,0,0,0,0,0,0,0,7,0,6,6, /* 90-9F */
+ 0,0,0,7,0,0,0,0,0,0,0,0,7,0,6,6, /* A0-AF */
+ 0,0,0,8,0,0,0,0,0,0,0,0,8,0,7,7, /* B0-BF */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0, /* C0-CF */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6, /* D0-DF */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6, /* E0-EF */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7]; /* F0-FF */
+
+/* Negative and zero flags for quicker flag settings */
+var flagsNZ = [
+ 4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00-0F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10-1F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 20-2F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 30-3F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40-4F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50-5F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60-6F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70-7F */
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, /* 80-8F */
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, /* 90-9F */
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, /* A0-AF */
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, /* B0-BF */
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, /* C0-CF */
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, /* D0-DF */
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, /* E0-EF */
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8]; /* F0-FF */
+
+var setV8 = function(a,b,r) {CC |= (((a^b^r^(r>>1))&0x80)>>6);};
+var setV16 = function(a,b,r) {CC |= (((a^b^r^(r>>1))&0x8000)>>14);};
+var getD = function() {return rA*256+rB;};
+var setD = function(v) {rA = (v>>8)& 0xff;rB=v&0xff;};
+var PUSHB = function(b) {
+ byteTo(--rS, b & 0xff);
+};
+var PUSHW = function(b) {
+ byteTo(--rS, b & 0xff);
+ byteTo(--rS, (b>>8) & 0xff);
+};
+
+var PUSHBU = function(b) {
+ byteTo(--rU, b & 0xff);
+};
+var PUSHWU = function(b) {
+ byteTo(--rU, b & 0xff);
+ byteTo(--rU, (b>>8) & 0xff);
+};
+var PULLB = function(b) {
+ return byteAt(rS++);
+};
+var PULLW = function(b) {
+ return byteAt(rS++) * 256 + byteAt(rS++);
+};
+
+var PULLBU = function(b) {
+ return byteAt(rU++);
+};
+var PULLWU = function(b) {
+ return byteAt(rU++) * 256 + byteAt(rU++);
+};
+
+var PSHS = function(ucTemp) {
+ var i = 0;
+ if (ucTemp & 0x80) {PUSHW(PC);i += 2;}
+ if (ucTemp & 0x40) {PUSHW(rU);i += 2;}
+ if (ucTemp & 0x20){PUSHW(rY);i += 2;}
+ if (ucTemp & 0x10){PUSHW(rX);i += 2;}
+ if (ucTemp & 0x8){PUSHB(DP); i++;}
+ if (ucTemp & 0x4){PUSHB(rB); i++;}
+ if (ucTemp & 0x2){PUSHB(rA); i++;}
+ if (ucTemp & 0x1){PUSHB(CC); i++;}
+ T+=i; //timing
+};
+var PSHU = function(ucTemp) {
+ var i = 0;
+ if (ucTemp & 0x80) {PUSHWU(PC);i += 2;}
+ if (ucTemp & 0x40) {PUSHWU(rS);i += 2;}
+ if (ucTemp & 0x20){PUSHWU(rY);i += 2;}
+ if (ucTemp & 0x10){PUSHWU(rX);i += 2;}
+ if (ucTemp & 0x8){PUSHBU(DP); i++;}
+ if (ucTemp & 0x4){PUSHBU(rB); i++;}
+ if (ucTemp & 0x2){PUSHBU(rA); i++;}
+ if (ucTemp & 0x1){PUSHBU(CC); i++;}
+ T+=i; //timing
+};
+var PULS = function(ucTemp) {
+ var i = 0;
+ if (ucTemp & 0x1){CC = PULLB(); i++;}
+ if (ucTemp & 0x2){rA = PULLB(); i++;}
+ if (ucTemp & 0x4){rB = PULLB(); i++;}
+ if (ucTemp & 0x8){DP = PULLB(); i++;}
+ if (ucTemp & 0x10){rX = PULLW();i += 2;}
+ if (ucTemp & 0x20){rY = PULLW();i += 2;}
+ if (ucTemp & 0x40) {rU = PULLW();i += 2;}
+ if (ucTemp & 0x80) {PC = PULLW();i += 2;}
+ T+=i; //timing
+};
+var PULU = function(ucTemp) {
+ var i = 0;
+ if (ucTemp & 0x1){CC = PULLBU(); i++;}
+ if (ucTemp & 0x2){rA = PULLBU(); i++;}
+ if (ucTemp & 0x4){rB = PULLBU(); i++;}
+ if (ucTemp & 0x8){DP = PULLBU(); i++;}
+ if (ucTemp & 0x10){rX = PULLWU();i += 2;}
+ if (ucTemp & 0x20){rY = PULLWU();i += 2;}
+ if (ucTemp & 0x40) {rS = PULLWU();i += 2;}
+ if (ucTemp & 0x80) {PC = PULLWU();i += 2;}
+ T+=i; //timing
+};
+
+
+var getPBR = function(ucPostByte) {
+ switch(ucPostByte & 0xf) {
+ case 0x00: /* D */
+ return getD();
+ case 0x1: /* X */
+ return rX;
+ case 0x2: /* Y */
+ return rY;
+ case 0x3: /* U */
+ return rU;
+ case 0x4: /* S */
+ return rS;
+ case 0x5: /* PC */
+ return PC;
+ case 0x8: /* A */
+ return rA;
+ case 0x9: /* B */
+ return rB;
+ case 0xA: /* CC */
+ return CC;
+ case 0xB: /* DP */
+ return DP;
+ default: /* illegal */
+ return null;
+ }
+};
+var setPBR = function(ucPostByte, v) {
+ switch(ucPostByte & 0xf) /* Get destination register */
+ {
+ case 0x00: /* D */
+ setD(v);return;
+ case 0x1: /* X */
+ rX = v; return;
+ case 0x2: /* Y */
+ rY = v; return;
+ case 0x3: /* U */
+ rU = v; return;
+ case 0x4: /* S */
+ rS = v; return;
+ case 0x5: /* PC */
+ PC = v; return;
+ case 0x8: /* A */
+ rA = v; return;
+ case 0x9: /* B */
+ rB = v; return;
+ case 0xA: /* CC */
+ CC = v; return;
+ case 0xB: /* DP */
+ DP = v; return;
+ default: /* illegal */
+ return;
+ }
+};
+
+var TFREXG = function(ucPostByte, bExchange)
+{
+
+ var ucTemp = ucPostByte & 0x88;
+ if (ucTemp == 0x80 || ucTemp == 0x08)
+ ucTemp = 0; /* PROBLEM! */
+
+ if (bExchange)
+ {
+ ucTemp = getPBR(ucPostByte>>4);
+ setPBR(ucPostByte>>4, getPBR(ucPostByte));
+ setPBR(ucPostByte, ucTemp);
+ }
+ else /* Transfer */ {
+ setPBR(ucPostByte, getPBR(ucPostByte>>4));
+ }
+} ;
+
+var signed = function(x) {
+ return (x>127)?(x-256):x;
+};
+var signed16 = function(x) {
+ return (x>32767)?(x-65536):x;
+};
+
+var fetch = function() {
+ var v = byteAt(PC++);
+ PC &= 0xffff;
+ return v;
+};
+var fetch16 = function() {
+ var v1 = byteAt(PC++);
+ PC &= 0xffff;
+ var v2 = byteAt(PC++);
+ PC &= 0xffff;
+ return v1*256+v2;
+};
+
+var ReadWord = function(addr) {
+ var v1 = byteAt(addr++);
+ addr &= 0xffff;
+ var v2 = byteAt(addr++);
+ addr &= 0xffff;
+ return v1*256+v2;
+};
+var WriteWord = function(addr,v) {
+ byteTo(addr++,(v>>8)&0xff);
+ addr &= 0xffff;
+ byteTo(addr,v&0xff);
+};
+
+var PostByte = function() {
+ var pb = fetch();
+ var preg;
+ switch (pb & 0x60) {
+ case 0:
+ preg = rX; break;
+ case 0x20:
+ preg = rY; break;
+ case 0x40:
+ preg = rU; break;
+ case 0x60:
+ preg = rS; break;
+ }
+
+ var xchg = null;
+ var addr = null;
+ var sTemp;
+
+ if (pb & 0x80) /* Complex stuff */
+ {
+ switch (pb & 0x0f)
+ {
+ case 0: /* EA = ,reg+ */
+ addr = preg;
+ xchg = preg + 1;
+ T += 2;
+ break;
+ case 1: /* EA = ,reg++ */
+ addr = preg;
+ xchg = preg + 2;
+ T += 3;
+ break;
+ case 2: /* EA = ,-reg */
+ xchg = preg - 1;
+ addr = xchg;
+ T += 2;
+ break;
+ case 3: /* EA = ,--reg */
+ xchg = preg - 2;
+ addr = xchg;
+ T += 3;
+ break;
+ case 4: /* EA = ,reg */
+ addr = preg;
+ break;
+ case 5: /* EA = ,reg + B */
+ //usAddr = *pReg + (signed short)(signed char)regs->ucRegB;
+ addr = preg + signed(rB);
+ T += 1;
+ break;
+ case 6: /* EA = ,reg + A */
+ addr = preg + signed(rA);
+ T += 1;
+ break;
+ case 7: /* illegal */
+ addr = 0;
+ break;
+ case 8: /* EA = ,reg + 8-bit offset */
+ addr = preg + signed(fetch());
+ T += 1;
+ break;
+ case 9: /* EA = ,reg + 16-bit offset */
+ addr = preg + signed16(fetch16());
+ T += 4;
+ break;
+ case 0xA: /* illegal */
+ addr = 0;
+ break;
+ case 0xB: /* EA = ,reg + D */
+ T += 4;
+ addr = preg + getD();
+ break;
+ case 0xC: /* EA = PC + 8-bit offset */
+ sTemp = signed(fetch());
+ addr = PC + sTemp;
+ T += 1;
+ break;
+ case 0xD: /* EA = PC + 16-bit offset */
+ sTemp = signed16(fetch16());
+ addr = PC + sTemp;
+ T += 5;
+ break;
+ case 0xe: /* Illegal */
+ addr = 0;
+ break;
+ case 0xF: /* EA = [,address] */
+ T += 5;
+ addr = fetch16();
+ break;
+ } /* switch */
+
+ addr &= 0xffff;
+
+ if (pb & 0x10) /* Indirect addressing */
+ {
+ addr = byteAt(addr)*256+byteAt((addr+1) & 0xffff);
+ T += 3;
+ }
+ }
+ else /* Just a 5 bit signed offset + register */
+ {
+ var sByte = pb & 0x1f;
+ if (sByte > 15) /* Two's complement 5-bit value */
+ sByte -= 32;
+ addr = preg + sByte;
+ T += 1;
+ }
+
+ if (xchg!==null) {
+ switch (pb & 0x60) {
+ case 0:
+ rX = xchg; break;
+ case 0x20:
+ rY = xchg; break;
+ case 0x40:
+ rU = xchg; break;
+ case 0x60:
+ rS = xchg; break;
+ }
+
+ }
+
+ return addr & 0xffff; /* Return the effective address */
+};
+
+var flagsNZ16 = function(word) {
+ CC &= ~(F_ZERO | F_NEGATIVE);
+ if (word===0) CC |= F_ZERO;
+ if (word & 0x8000) CC |= F_NEGATIVE;
+};
+
+// ============= Operations
+
+var oINC = function(b) {
+ b++;
+ b &= 0xff;
+ CC &= ~(F_ZERO | F_OVERFLOW | F_NEGATIVE);
+ CC |= flagsNZ[b];
+ if (b === 0 || b == 0x80) CC |= F_OVERFLOW;
+ return b;
+};
+var oDEC = function(b) {
+ b--;
+ b &= 0xff;
+ CC &= ~(F_ZERO | F_OVERFLOW | F_NEGATIVE);
+ CC |= flagsNZ[b];
+ if (b === 0x7f || b == 0xff) CC |= F_OVERFLOW;
+ return b;
+};
+var oSUB = function(b,v) {
+ var temp = b-v;
+ //temp &= 0xff;
+ CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
+ CC |= flagsNZ[temp & 0xff];
+ if (temp&0x100) CC|=F_CARRY;
+ setV8(b,v,temp);
+ return temp&0xff;
+};
+var oSUB16 = function(b,v) {
+ var temp = b-v;
+ //temp &= 0xff;
+ CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
+ if ((temp&0xffff)===0) CC|=F_ZERO;
+ if (temp&0x8000) CC|=F_NEGATIVE;
+ if (temp&0x10000) CC|=F_CARRY;
+ setV16(b,v,temp);
+ return temp&0xffff;
+};
+var oADD = function(b,v) {
+ var temp = b+v;
+ //temp &= 0xff;
+ CC &= ~(F_HALFCARRY | F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
+ CC |= flagsNZ[temp & 0xff];
+ if (temp&0x100) CC|=F_CARRY;
+ setV8(b,v,temp);
+ if ((temp ^ b ^ v)&0x10) CC |= F_HALFCARRY;
+ return temp&0xff;
+};
+var oADD16 = function(b,v) {
+ var temp = b+v;
+ //temp &= 0xff;
+ CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
+ if ((temp&0xffff)===0) CC|=F_ZERO;
+ if (temp&0x8000) CC|=F_NEGATIVE;
+ if (temp&0x10000) CC|=F_CARRY;
+ setV16(b,v,temp);
+ return temp&0xffff;
+};
+var oADC = function(b,v) {
+ var temp = b+v+(CC & F_CARRY);
+ //temp &= 0xff;
+ CC &= ~(F_HALFCARRY | F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
+ CC |= flagsNZ[temp & 0xff];
+ if (temp&0x100) CC|=F_CARRY;
+ setV8(b,v,temp);
+ if ((temp ^ b ^ v)&0x10) CC |= F_HALFCARRY;
+ return temp&0xff;
+};
+var oSBC = function(b,v) {
+ var temp = b-v-(CC & F_CARRY);
+ //temp &= 0xff;
+ CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
+ CC |= flagsNZ[temp & 0xff];
+ if (temp&0x100) CC|=F_CARRY;
+ setV8(b,v,temp);
+ return temp&0xff;
+};
+var oCMP = function(b,v) {
+ var temp = b-v;
+ //temp &= 0xff;
+ CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
+ CC |= flagsNZ[temp & 0xff];
+ if (temp&0x100) CC|=F_CARRY;
+ setV8(b,v,temp);
+ return;
+};
+var oCMP16 = function(b,v) {
+ var temp = b-v;
+ //temp &= 0xff;
+ CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
+ if ((temp&0xffff)===0) CC|=F_ZERO;
+ if (temp&0x8000) CC|=F_NEGATIVE;
+ if (temp&0x10000) CC|=F_CARRY;
+ setV16(b,v,temp);
+ return;
+};
+
+var oNEG = function(b) {
+ CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
+ if (b == 0x80)
+ CC |= F_OVERFLOW;
+ b = ((~b)&0xff) + 1;
+ if (b === 0) CC |= F_ZERO;
+ if (b & 0x80) CC |= F_NEGATIVE | F_CARRY;
+ return b;
+};
+
+var oLSR = function(b) {
+ CC &= ~(F_ZERO | F_CARRY | F_NEGATIVE);
+ if (b & 0x01) CC |= F_CARRY;
+ b >>= 1;
+ if (b === 0) CC |= F_ZERO;
+ return b & 0xff;
+};
+var oASR = function(b) {
+ CC &= ~(F_ZERO | F_CARRY | F_NEGATIVE);
+ if (b & 0x01) CC |= F_CARRY;
+ b = (b & 0x80) | (b>>1);
+ CC |= flagsNZ[b];
+ return b;
+};
+var oASL = function(b) {
+ var temp = b;
+ CC &= ~(F_ZERO | F_CARRY | F_NEGATIVE | F_OVERFLOW);
+ if (b & 0x80) CC |= F_CARRY;
+ b <<= 1;
+ CC |= flagsNZ[b];
+ if ((b ^ temp) & 0x80) CC|=F_OVERFLOW;
+ return b;
+};
+var oROL = function(b) {
+ var temp = b;
+ var oldc = CC&F_CARRY;
+ CC &= ~(F_ZERO | F_CARRY | F_NEGATIVE | F_OVERFLOW);
+ if (b & 0x80) CC |= F_CARRY;
+ b = b<<1 | oldc;
+ CC |= flagsNZ[b];
+ if ((b ^ temp) & 0x80) CC|=F_OVERFLOW;
+ return b;
+};
+var oROR = function(b) {
+ var oldc = CC&F_CARRY;
+ CC &= ~(F_ZERO | F_CARRY | F_NEGATIVE);
+ if (b & 0x01) CC |= F_CARRY;
+ b = b>>1 | oldc<<7;
+ CC |= flagsNZ[b];
+// if ((b ^ temp) & 0x80) CC|=F_OVERFLOW;
+ return b;
+};
+
+var oEOR = function(b,v) {
+ CC &= ~(F_ZERO | F_NEGATIVE | F_OVERFLOW);
+ b ^= v;
+ CC |= flagsNZ[b];
+ return b;
+};
+var oOR = function(b,v) {
+ CC &= ~(F_ZERO | F_NEGATIVE | F_OVERFLOW);
+ b |= v;
+ CC |= flagsNZ[b];
+ return b;
+};
+var oAND = function(b,v) {
+ CC &= ~(F_ZERO | F_NEGATIVE | F_OVERFLOW);
+ b &= v;
+ CC |= flagsNZ[b];
+ return b;
+};
+var oCOM = function(b) {
+ CC &= ~(F_ZERO | F_NEGATIVE | F_OVERFLOW);
+ b ^= 0xff;
+ CC |= flagsNZ[b];
+ return b;
+};
+
+//----common
+var dpadd = function() {
+ //direct page + 8bit index
+ return DP*256 + fetch();
+};
+
+var step = function() {
+ var oldT = T;
+
+ if (IRQs) {
+ //;;;
+ }
+
+ var addr = null;
+ var pb = null;
+
+ var oldPC = PC;
+ var opcode = fetch();
+ T+=cycles[opcode];
+ switch (opcode) {
+ case 0x00: //NEG DP
+ addr = dpadd();
+ byteTo(addr, oNEG(byteAt(addr)));
+ break;
+ case 0x03: //COM DP
+ addr = dpadd();
+ byteTo(addr, oCOM(byteAt(addr)));
+ break;
+ case 0x04: //LSR DP
+ addr = dpadd();
+ byteTo(addr, oLSR(byteAt(addr)));
+ break;
+ case 0x06: //ROR DP
+ addr = dpadd();
+ byteTo(addr, oROR(byteAt(addr)));
+ break;
+ case 0x07: //ASR DP
+ addr = dpadd();
+ byteTo(addr, oASR(byteAt(addr)));
+ break;
+ case 0x08: //ASL DP
+ addr = dpadd();
+ byteTo(addr, oASL(byteAt(addr)));
+ break;
+ case 0x09: //ROL DP
+ addr = dpadd();
+ byteTo(addr, oROL(byteAt(addr)));
+ break;
+
+ case 0x0A: //DEC DP
+ addr = dpadd();
+ byteTo(addr, oDEC(byteAt(addr)));
+ break;
+ case 0x0C: //INC DP
+ addr = dpadd();
+ byteTo(addr, oINC(byteAt(addr)));
+ break;
+
+ case 0x0D: //TST DP
+ addr = dpadd();
+ pb = byteAt(addr);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[pb];
+ break;
+
+ case 0x0E: //JMP DP
+ addr = dpadd();
+ PC = addr;
+ break;
+ case 0x0F: //CLR DP
+ addr = dpadd();
+ byteTo(addr,0);
+ CC&=~(F_CARRY|F_NEGATIVE|F_OVERFLOW);
+ CC |= F_ZERO;
+ break;
+
+ case 0x12: //NOP
+ break;
+ case 0x13: //SYNC
+ break;
+ case 0x16: //LBRA relative
+ addr = signed16(fetch16());
+ PC += addr;
+ break;
+ case 0x17: //LBSR relative
+ addr = signed16(fetch16());
+ PUSHW(PC);
+ PC += addr;
+ break;
+ case 0x19: //DAA
+ var cf = 0;
+ var nhi = rA & 0xf0, nlo = rA & 0x0f;
+ if( nlo>0x09 || CC & 0x20 ) cf |= 0x06;
+ if( nhi>0x80 && nlo>0x09 ) cf |= 0x60;
+ if( nhi>0x90 || CC & 0x01 ) cf |= 0x60;
+ addr = cf + rA;
+ CC &= ~(F_CARRY | F_NEGATIVE | F_ZERO | F_OVERFLOW);
+ if (addr & 0x100)
+ CC |= F_CARRY;
+ rA = addr & 0xff;
+ CC |= flagsNZ[rA];
+ break;
+ case 0x1A: //ORCC
+ CC |= fetch();
+ break;
+ case 0x1C: //ANDCC
+ CC &= fetch();
+ break;
+ case 0x1D: //SEX
+ rA = (rB & 0x80)?0xff:0;
+ flagsNZ16(getD());
+ CC &= ~F_OVERFLOW;
+ break;
+ case 0x1E: //EXG
+ pb = fetch();
+ TFREXG(pb,true);
+ break;
+ case 0x1F: //EXG
+ pb = fetch();
+ TFREXG(pb,false);
+ break;
+
+ case 0x20: //BRA
+ addr = signed(fetch());
+ PC += addr;
+ break;
+ case 0x21: //BRN
+ addr = signed(fetch());
+ break;
+ case 0x22: //BHI
+ addr = signed(fetch());
+ if (!(CC&(F_CARRY | F_ZERO))) PC += addr;
+ break;
+ case 0x23: //BLS
+ addr = signed(fetch());
+ if (CC&(F_CARRY | F_ZERO)) PC += addr;
+ break;
+ case 0x24: //BCC
+ addr = signed(fetch());
+ if (!(CC&F_CARRY)) PC += addr;
+ break;
+ case 0x25: //BCS
+ addr = signed(fetch());
+ if (CC&F_CARRY) PC += addr;
+ break;
+ case 0x26: //BNE
+ addr = signed(fetch());
+ if (!(CC&F_ZERO)) PC += addr;
+ break;
+ case 0x27: //BEQ
+ addr = signed(fetch());
+ if (CC&F_ZERO) PC += addr;
+ break;
+ case 0x28: //BVC
+ addr = signed(fetch());
+ if (!(CC&F_OVERFLOW)) PC += addr;
+ break;
+ case 0x29: //BVS
+ addr = signed(fetch());
+ if (CC&F_OVERFLOW) PC += addr;
+ break;
+ case 0x2A: //BPL
+ addr = signed(fetch());
+ if (!(CC&F_NEGATIVE)) PC += addr;
+ break;
+ case 0x2B: //BMI
+ addr = signed(fetch());
+ if (CC&F_NEGATIVE) PC += addr;
+ break;
+ case 0x2C: //BGE
+ addr = signed(fetch());
+ if (!((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2))) PC += addr;
+ break;
+ case 0x2D: //BLT
+ addr = signed(fetch());
+ if ((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2)) PC += addr;
+ break;
+ case 0x2E: //BGT
+ addr = signed(fetch());
+ if (!((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2) || (CC&F_ZERO))) PC += addr;
+ break;
+ case 0x2F: //BLE
+ addr = signed(fetch());
+ if ((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2) || (CC&F_ZERO)) PC += addr;
+ break;
+
+ case 0x30: //LEAX
+ rX = PostByte();
+ if (rX===0) CC|=F_ZERO; else CC&=~F_ZERO;
+ break;
+ case 0x31: //LEAY
+ rY = PostByte();
+ if (rY===0) CC|=F_ZERO; else CC&=~F_ZERO;
+ break;
+ case 0x32: //LEAS
+ rS = PostByte();
+ break;
+ case 0x33: //LEAU
+ rU = PostByte();
+ break;
+
+ case 0x34: //PSHS
+ PSHS(fetch());
+ break;
+ case 0x35: //PULS
+ PULS(fetch());
+ break;
+ case 0x36: //PSHU
+ PSHU(fetch());
+ break;
+ case 0x37: //PULU
+ PULU(fetch());
+ break;
+ case 0x39: //RTS
+ PC = PULLW();
+ break;
+ case 0x3A: //ABX
+ rX += rB;
+ break;
+ case 0x3B: //RTI
+ CC = PULLB();
+ if (cc & F_ENTIRE) {
+ T+=9;
+ rA = PULLB();
+ rB = PULLB();
+ DP = PULLB();
+ rX = PULLW();
+ rY = PULLW();
+ rU = PULLW();
+ }
+ PC = PULLW();
+ break;
+ case 0x3C: //CWAI **todo
+ CC &= fetch();
+ break;
+ case 0x3D: //MUL
+ addr = rA * rB;
+ if (addr===0) CC|=F_ZERO; else CC&=~F_ZERO;
+ if (addr&0x80) CC|=F_CARRY; else CC&=~F_CARRY;
+ setD(addr);
+ break;
+ case 0x3F: //SWI
+ CC |= F_ENTIRE;
+ PUSHW(PC);
+ PUSHW(rU);
+ PUSHW(rY);
+ PUSHW(rX);
+ PUSHB(DP);
+ PUSHB(rB);
+ PUSHB(rA);
+ PUSHB(CC);
+ CC |= F_IRQMASK | F_FIRQMASK;
+ PC = ReadWord(vecSWI);
+ break;
+
+ case 0x40:
+ rA = oNEG(rA);
+ break;
+ case 0x43:
+ rA = oCOM(rA);
+ break;
+ case 0x44:
+ rA = oLSR(rA);
+ break;
+ case 0x46:
+ rA = oROR(rA);
+ break;
+ case 0x47:
+ rA = oASR(rA);
+ break;
+ case 0x48:
+ rA = oASL(rA);
+ break;
+ case 0x49:
+ rA = oROL(rA);
+ break;
+ case 0x4A:
+ rA = oDEC(rA);
+ break;
+ case 0x4C:
+ rA = oINC(rA);
+ break;
+ case 0x4D:
+ CC &= ~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rA];
+ break;
+ case 0x4F:
+ rA = 0;
+ CC &= ~(F_NEGATIVE|F_OVERFLOW|F_CARRY);
+ CC |= F_ZERO;
+ break;
+
+ case 0x50:
+ rB = oNEG(rB);
+ break;
+ case 0x53:
+ rB = oCOM(rB);
+ break;
+ case 0x54:
+ rB = oLSR(rB);
+ break;
+ case 0x56:
+ rB = oROR(rB);
+ break;
+ case 0x57:
+ rB = oASR(rB);
+ break;
+ case 0x58:
+ rB = oASL(rB);
+ break;
+ case 0x59:
+ rB = oROL(rB);
+ break;
+ case 0x5A:
+ rB = oDEC(rB);
+ break;
+ case 0x5C:
+ rB = oINC(rB);
+ break;
+ case 0x5D:
+ CC &= ~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rB];
+ break;
+ case 0x5F:
+ rB = 0;
+ CC &= ~(F_NEGATIVE|F_OVERFLOW|F_CARRY);
+ CC |= F_ZERO;
+ break;
+
+ case 0x60: //NEG indexed
+ addr = PostByte();
+ byteTo(addr, oNEG(byteAt(addr)));
+ break;
+ case 0x63: //COM indexed
+ addr = PostByte();
+ byteTo(addr, oCOM(byteAt(addr)));
+ break;
+ case 0x64: //LSR indexed
+ addr = PostByte();
+ byteTo(addr, oLSR(byteAt(addr)));
+ break;
+ case 0x66: //ROR indexed
+ addr = PostByte();
+ byteTo(addr, oROR(byteAt(addr)));
+ break;
+ case 0x67: //ASR indexed
+ addr = PostByte();
+ byteTo(addr, oASR(byteAt(addr)));
+ break;
+ case 0x68: //ASL indexed
+ addr = PostByte();
+ byteTo(addr, oASL(byteAt(addr)));
+ break;
+ case 0x69: //ROL indexed
+ addr = PostByte();
+ byteTo(addr, oROL(byteAt(addr)));
+ break;
+
+ case 0x6A: //DEC indexed
+ addr = PostByte();
+ byteTo(addr, oDEC(byteAt(addr)));
+ break;
+ case 0x6C: //INC indexed
+ addr = PostByte();
+ byteTo(addr, oINC(byteAt(addr)));
+ break;
+
+ case 0x6D: //TST indexed
+ addr = PostByte();
+ pb = byteAt(addr);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[pb];
+ break;
+
+ case 0x6E: //JMP indexed
+ addr = PostByte();
+ PC = addr;
+ break;
+ case 0x6F: //CLR indexed
+ addr = PostByte();
+ byteTo(addr,0);
+ CC&=~(F_CARRY|F_NEGATIVE|F_OVERFLOW);
+ CC |= F_ZERO;
+ break;
+
+
+ case 0x70: //NEG extended
+ addr = fetch16();
+ byteTo(addr, oNEG(byteAt(addr)));
+ break;
+ case 0x73: //COM extended
+ addr = fetch16();
+ byteTo(addr, oCOM(byteAt(addr)));
+ break;
+ case 0x74: //LSR extended
+ addr = fetch16();
+ byteTo(addr, oLSR(byteAt(addr)));
+ break;
+ case 0x76: //ROR extended
+ addr = fetch16();
+ byteTo(addr, oROR(byteAt(addr)));
+ break;
+ case 0x77: //ASR extended
+ addr = fetch16();
+ byteTo(addr, oASR(byteAt(addr)));
+ break;
+ case 0x78: //ASL extended
+ addr = fetch16();
+ byteTo(addr, oASL(byteAt(addr)));
+ break;
+ case 0x79: //ROL extended
+ addr = fetch16();
+ byteTo(addr, oROL(byteAt(addr)));
+ break;
+
+ case 0x7A: //DEC extended
+ addr = fetch16();
+ byteTo(addr, oDEC(byteAt(addr)));
+ break;
+ case 0x7C: //INC extended
+ addr = fetch16();
+ byteTo(addr, oINC(byteAt(addr)));
+ break;
+
+ case 0x7D: //TST extended
+ addr = fetch16();
+ pb = byteAt(addr);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[pb];
+ break;
+
+ case 0x7E: //JMP extended
+ addr = fetch16();
+ PC = addr;
+ break;
+ case 0x7F: //CLR extended
+ addr = fetch16();
+ byteTo(addr,0);
+ CC&=~(F_CARRY|F_NEGATIVE|F_OVERFLOW);
+ CC |= F_ZERO;
+ break;
+
+ // regs A,X
+
+ case 0x80: //SUBA imm
+ rA = oSUB(rA, fetch());
+ break;
+ case 0x81: //CMPA imm
+ oCMP(rA, fetch());
+ break;
+ case 0x82: //SBCA imm
+ rA = oSBC(rA, fetch());
+ break;
+ case 0x83: //SUBD imm
+ setD(oSUB16(getD(),fetch16()));
+ break;
+ case 0x84: //ANDA imm
+ rA = oAND(rA, fetch());
+ break;
+ case 0x85: //BITA imm
+ oAND(rA, fetch());
+ break;
+ case 0x86: //LDA imm
+ rA = fetch();
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rA];
+ break;
+ case 0x88: //EORA imm
+ rA = oEOR(rA, fetch());
+ break;
+ case 0x89: //ADCA imm
+ rA = oADC(rA, fetch());
+ break;
+ case 0x8A: //ORA imm
+ rA = oOR(rA, fetch());
+ break;
+ case 0x8B: //ADDA imm
+ rA = oADD(rA, fetch());
+ break;
+ case 0x8C: //CMPX imm
+ oCMP16(rX, fetch16());
+ break;
+
+ case 0x8D: //JSR imm
+ addr = signed(fetch());
+ PUSHW(PC);
+ PC+=addr;
+ break;
+ case 0x8E: //LDX imm
+ rX = fetch16();
+ flagsNZ16(rX);
+ CC&=~F_OVERFLOW;
+ break;
+
+
+ case 0x90: //SUBA direct
+ addr = dpadd();
+ rA = oSUB(rA, byteAt(addr));
+ break;
+ case 0x91: //CMPA direct
+ addr = dpadd();
+ oCMP(rA, byteAt(addr));
+ break;
+ case 0x92: //SBCA direct
+ addr = dpadd();
+ rA = oSBC(rA, byteAt(addr));
+ break;
+ case 0x93: //SUBD direct
+ addr = dpadd();
+ setD(oSUB16(getD(),ReadWord(addr)));
+ break;
+ case 0x94: //ANDA direct
+ addr = dpadd();
+ rA = oAND(rA, byteAt(addr));
+ break;
+ case 0x95: //BITA direct
+ addr = dpadd();
+ oAND(rA, byteAt(addr));
+ break;
+ case 0x96: //LDA direct
+ addr = dpadd();
+ rA = byteAt(addr);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rA];
+ break;
+ case 0x97: //STA direct
+ addr = dpadd();
+ byteTo(addr,rA);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rA];
+ break;
+ case 0x98: //EORA direct
+ addr = dpadd();
+ rA = oEOR(rA, byteAt(addr));
+ break;
+ case 0x99: //ADCA direct
+ addr = dpadd();
+ rA = oADC(rA, byteAt(addr));
+ break;
+ case 0x9A: //ORA direct
+ addr = dpadd();
+ rA = oOR(rA, byteAt(addr));
+ break;
+ case 0x9B: //ADDA direct
+ addr = dpadd();
+ rA = oADD(rA, byteAt(addr));
+ break;
+ case 0x9C: //CMPX direct
+ addr = dpadd();
+ oCMP16(rX, ReadWord(addr));
+ break;
+
+ case 0x9D: //JSR direct
+ addr = dpadd();
+ PUSHW(PC);
+ PC=addr;
+ break;
+ case 0x9E: //LDX direct
+ addr = dpadd();
+ rX = ReadWord(addr);
+ flagsNZ16(rX);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0x9F: //STX direct
+ addr = dpadd();
+ WriteWord(addr,rX);
+ flagsNZ16(rX);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xA0: //SUBA indexed
+ addr = PostByte();
+ rA = oSUB(rA, byteAt(addr));
+ break;
+ case 0xA1: //CMPA indexed
+ addr = PostByte();
+ oCMP(rA, byteAt(addr));
+ break;
+ case 0xA2: //SBCA indexed
+ addr = PostByte();
+ rA = oSBC(rA, byteAt(addr));
+ break;
+ case 0xA3: //SUBD indexed
+ addr = PostByte();
+ setD(oSUB16(getD(),ReadWord(addr)));
+ break;
+ case 0xA4: //ANDA indexed
+ addr = PostByte();
+ rA = oAND(rA, byteAt(addr));
+ break;
+ case 0xA5: //BITA indexed
+ addr = PostByte();
+ oAND(rA, byteAt(addr));
+ break;
+ case 0xA6: //LDA indexed
+ addr = PostByte();
+ rA = byteAt(addr);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rA];
+ break;
+ case 0xA7: //STA indexed
+ addr = PostByte();
+ byteTo(addr,rA);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rA];
+ break;
+ case 0xA8: //EORA indexed
+ addr = PostByte();
+ rA = oEOR(rA, byteAt(addr));
+ break;
+ case 0xA9: //ADCA indexed
+ addr = PostByte();
+ rA = oADC(rA, byteAt(addr));
+ break;
+ case 0xAA: //ORA indexed
+ addr = PostByte();
+ rA = oOR(rA, byteAt(addr));
+ break;
+ case 0xAB: //ADDA indexed
+ addr = PostByte();
+ rA = oADD(rA, byteAt(addr));
+ break;
+ case 0xAC: //CMPX indexed
+ addr = PostByte();
+ oCMP16(rX, ReadWord(addr));
+ break;
+
+ case 0xAD: //JSR indexed
+ addr = PostByte();
+ PUSHW(PC);
+ PC=addr;
+ break;
+ case 0xAE: //LDX indexed
+ addr = PostByte();
+ rX = ReadWord(addr);
+ flagsNZ16(rX);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xAF: //STX indexed
+ addr = PostByte();
+ WriteWord(addr,rX);
+ flagsNZ16(rX);
+ CC&=~F_OVERFLOW;
+ break;
+
+
+ case 0xB0: //SUBA extended
+ addr = fetch16();
+ rA = oSUB(rA, byteAt(addr));
+ break;
+ case 0xB1: //CMPA extended
+ addr = fetch16();
+ oCMP(rA, byteAt(addr));
+ break;
+ case 0xB2: //SBCA extended
+ addr = fetch16();
+ rA = oSBC(rA, byteAt(addr));
+ break;
+ case 0xB3: //SUBD extended
+ addr = fetch16();
+ setD(oSUB16(getD(),ReadWord(addr)));
+ break;
+ case 0xB4: //ANDA extended
+ addr = fetch16();
+ rA = oAND(rA, byteAt(addr));
+ break;
+ case 0xB5: //BITA extended
+ addr = fetch16();
+ oAND(rA, byteAt(addr));
+ break;
+ case 0xB6: //LDA extended
+ addr = fetch16();
+ rA = byteAt(addr);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rA];
+ break;
+ case 0xB7: //STA extended
+ addr = fetch16();
+ byteTo(addr,rA);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rA];
+ break;
+ case 0xB8: //EORA extended
+ addr = fetch16();
+ rA = oEOR(rA, byteAt(addr));
+ break;
+ case 0xB9: //ADCA extended
+ addr = fetch16();
+ rA = oADC(rA, byteAt(addr));
+ break;
+ case 0xBA: //ORA extended
+ addr = fetch16();
+ rA = oOR(rA, byteAt(addr));
+ break;
+ case 0xBB: //ADDA extended
+ addr = fetch16();
+ rA = oADD(rA, byteAt(addr));
+ break;
+ case 0xBC: //CMPX extended
+ addr = fetch16();
+ oCMP16(rX, ReadWord(addr));
+ break;
+
+ case 0xBD: //JSR extended
+ addr = fetch16();
+ PUSHW(PC);
+ PC=addr;
+ break;
+ case 0xBE: //LDX extended
+ addr = fetch16();
+ rX = ReadWord(addr);
+ flagsNZ16(rX);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xBF: //STX extended
+ addr = fetch16();
+ WriteWord(addr,rX);
+ flagsNZ16(rX);
+ CC&=~F_OVERFLOW;
+ break;
+
+ //Regs B, Y
+
+ case 0xC0: //SUBB imm
+ rB = oSUB(rB, fetch());
+ break;
+ case 0xC1: //CMPB imm
+ oCMP(rB, fetch());
+ break;
+ case 0xC2: //SBCB imm
+ rB = oSBC(rB, fetch());
+ break;
+ case 0xC3: //ADDD imm
+ setD(oADD16(getD(),fetch16()));
+ break;
+ case 0xC4: //ANDB imm
+ rB = oAND(rB, fetch());
+ break;
+ case 0xC5: //BITB imm
+ oAND(rB, fetch());
+ break;
+ case 0xC6: //LDB imm
+ rB = fetch();
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rB];
+ break;
+ case 0xC8: //EORB imm
+ rB = oEOR(rB, fetch());
+ break;
+ case 0xC9: //ADCB imm
+ rB = oADC(rB, fetch());
+ break;
+ case 0xCA: //ORB imm
+ rB = oOR(rB, fetch());
+ break;
+ case 0xCB: //ADDB imm
+ rB = oADD(rB, fetch());
+ break;
+ case 0xCC: //LDD imm
+ addr = fetch16();
+ setD(addr);
+ flagsNZ16(addr);
+ CC&=~F_OVERFLOW;
+ break;
+
+ case 0xCE: //LDU imm
+ rU = fetch16();
+ flagsNZ16(rU);
+ CC&=~F_OVERFLOW;
+ break;
+
+
+ case 0xD0: //SUBB direct
+ addr = dpadd();
+ rB = oSUB(rB, byteAt(addr));
+ break;
+ case 0xD1: //CMPB direct
+ addr = dpadd();
+ oCMP(rB, byteAt(addr));
+ break;
+ case 0xD2: //SBCB direct
+ addr = dpadd();
+ rB = oSBC(rB, byteAt(addr));
+ break;
+ case 0xD3: //ADDD direct
+ addr = dpadd();
+ setD(oADD16(getD(),ReadWord(addr)));
+ break;
+ case 0xD4: //ANDB direct
+ addr = dpadd();
+ rB = oAND(rB, byteAt(addr));
+ break;
+ case 0xD5: //BITB direct
+ addr = dpadd();
+ oAND(rB, byteAt(addr));
+ break;
+ case 0xD6: //LDB direct
+ addr = dpadd();
+ rB = byteAt(addr);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rB];
+ break;
+ case 0xD7: //STB direct
+ addr = dpadd();
+ byteTo(addr,rB);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rB];
+ break;
+ case 0xD8: //EORB direct
+ addr = dpadd();
+ rB = oEOR(rB, byteAt(addr));
+ break;
+ case 0xD9: //ADCB direct
+ addr = dpadd();
+ rB = oADC(rB, byteAt(addr));
+ break;
+ case 0xDA: //ORB direct
+ addr = dpadd();
+ rB = oOR(rB, byteAt(addr));
+ break;
+ case 0xDB: //ADDB direct
+ addr = dpadd();
+ rB = oADD(rB, byteAt(addr));
+ break;
+ case 0xDC: //LDD direct
+ addr = dpadd();
+ pb = ReadWord(addr);
+ setD(pb);
+ flagsNZ16(pb);
+ CC&=~F_OVERFLOW;
+ break;
+
+ case 0xDD: //STD direct
+ addr = dpadd();
+ WriteWord(addr, getD());
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xDE: //LDU direct
+ addr = dpadd();
+ rU = ReadWord(addr);
+ flagsNZ16(rX);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xDF: //STU direct
+ addr = dpadd();
+ WriteWord(addr,rU);
+ flagsNZ16(rU);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xE0: //SUBB indexed
+ addr = PostByte();
+ rB = oSUB(rB, byteAt(addr));
+ break;
+ case 0xE1: //CMPB indexed
+ addr = PostByte();
+ oCMP(rB, byteAt(addr));
+ break;
+ case 0xE2: //SBCB indexed
+ addr = PostByte();
+ rB = oSBC(rB, byteAt(addr));
+ break;
+ case 0xE3: //ADDD indexed
+ addr = PostByte();
+ setD(oADD16(getD(),ReadWord(addr)));
+ break;
+ case 0xE4: //ANDB indexed
+ addr = PostByte();
+ rB = oAND(rB, byteAt(addr));
+ break;
+ case 0xE5: //BITB indexed
+ addr = PostByte();
+ oAND(rB, byteAt(addr));
+ break;
+ case 0xE6: //LDB indexed
+ addr = PostByte();
+ rB = byteAt(addr);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rB];
+ break;
+ case 0xE7: //STB indexed
+ addr = PostByte();
+ byteTo(addr,rB);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rB];
+ break;
+ case 0xE8: //EORB indexed
+ addr = PostByte();
+ rB = oEOR(rB, byteAt(addr));
+ break;
+ case 0xE9: //ADCB indexed
+ addr = PostByte();
+ rB = oADC(rB, byteAt(addr));
+ break;
+ case 0xEA: //ORB indexed
+ addr = PostByte();
+ rB = oOR(rB, byteAt(addr));
+ break;
+ case 0xEB: //ADDB indexed
+ addr = PostByte();
+ rB = oADD(rB, byteAt(addr));
+ break;
+ case 0xEC: //LDD indexed
+ addr = PostByte();
+ pb = ReadWord(addr);
+ setD(pb);
+ flagsNZ16(pb);
+ CC&=~F_OVERFLOW;
+ break;
+
+ case 0xED: //STD indexed
+ addr = PostByte();
+ WriteWord(addr, getD());
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xEE: //LDU indexed
+ addr = PostByte();
+ rU = ReadWord(addr);
+ flagsNZ16(rU);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xEF: //STU indexed
+ addr = PostByte();
+ WriteWord(addr,rU);
+ flagsNZ16(rU);
+ CC&=~F_OVERFLOW;
+ break;
+
+
+ case 0xF0: //SUBB extended
+ addr = fetch16();
+ rB = oSUB(rB, byteAt(addr));
+ break;
+ case 0xF1: //CMPB extended
+ addr = fetch16();
+ oCMP(rB, byteAt(addr));
+ break;
+ case 0xF2: //SBCB extended
+ addr = fetch16();
+ rB = oSBC(rB, byteAt(addr));
+ break;
+ case 0xF3: //ADDD extended
+ addr = fetch16();
+ setD(oADD16(getD(),ReadWord(addr)));
+ break;
+ case 0xF4: //ANDB extended
+ addr = fetch16();
+ rB = oAND(rB, byteAt(addr));
+ break;
+ case 0xF5: //BITB extended
+ addr = fetch16();
+ oAND(rB, byteAt(addr));
+ break;
+ case 0xF6: //LDB extended
+ addr = fetch16();
+ rB = byteAt(addr);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rB];
+ break;
+ case 0xF7: //STB extended
+ addr = fetch16();
+ byteTo(addr,rB);
+ CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
+ CC |= flagsNZ[rB];
+ break;
+ case 0xF8: //EORB extended
+ addr = fetch16();
+ rB = oEOR(rB, byteAt(addr));
+ break;
+ case 0xF9: //ADCB extended
+ addr = fetch16();
+ rB = oADC(rB, byteAt(addr));
+ break;
+ case 0xFA: //ORB extended
+ addr = fetch16();
+ rB = oOR(rB, byteAt(addr));
+ break;
+ case 0xFB: //ADDB extended
+ addr = fetch16();
+ rB = oADD(rB, byteAt(addr));
+ break;
+ case 0xFC: //LDD extended
+ addr = fetch16();
+ pb = ReadWord(addr);
+ setD(pb);
+ flagsNZ16(pb);
+ CC&=~F_OVERFLOW;
+ break;
+
+ case 0xFD: //STD extended
+ addr = fetch16();
+ WriteWord(addr, getD());
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xFE: //LDU extended
+ addr = fetch16();
+ rU = ReadWord(addr);
+ flagsNZ16(rU);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xFF: //STU extended
+ addr = fetch16();
+ WriteWord(addr,rU);
+ flagsNZ16(rU);
+ CC&=~F_OVERFLOW;
+ break;
+
+ // page 1
+ case 0x10: //page 1
+ {
+ opcode = fetch();
+ T+=cycles2[opcode];
+ switch(opcode) {
+ case 0x21: //BRN
+ addr = signed16(fetch16());
+ break;
+ case 0x22: //BHI
+ addr = signed16(fetch16());
+ if (!(CC&(F_CARRY | F_ZERO))) PC += addr;
+ break;
+ case 0x23: //BLS
+ addr = signed16(fetch16());
+ if (CC&(F_CARRY | F_ZERO)) PC += addr;
+ break;
+ case 0x24: //BCC
+ addr = signed16(fetch16());
+ if (!(CC&F_CARRY)) PC += addr;
+ break;
+ case 0x25: //BCS
+ addr = signed16(fetch16());
+ if (CC&F_CARRY) PC += addr;
+ break;
+ case 0x26: //BNE
+ addr = signed16(fetch16());
+ if (!(CC&F_ZERO)) PC += addr;
+ break;
+ case 0x27: //BEQ
+ addr = signed16(fetch16());
+ if (CC&F_ZERO) PC += addr;
+ break;
+ case 0x28: //BVC
+ addr = signed16(fetch16());
+ if (!(CC&F_OVERFLOW)) PC += addr;
+ break;
+ case 0x29: //BVS
+ addr = signed16(fetch16());
+ if (CC&F_OVERFLOW) PC += addr;
+ break;
+ case 0x2A: //BPL
+ addr = signed16(fetch16());
+ if (!(CC&F_NEGATIVE)) PC += addr;
+ break;
+ case 0x2B: //BMI
+ addr = signed16(fetch16());
+ if (CC&F_NEGATIVE) PC += addr;
+ break;
+ case 0x2C: //BGE
+ addr = signed16(fetch16());
+ if (!((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2))) PC += addr;
+ break;
+ case 0x2D: //BLT
+ addr = signed16(fetch16());
+ if ((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2)) PC += addr;
+ break;
+ case 0x2E: //BGT
+ addr = signed16(fetch16());
+ if (!((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2) || (CC&F_ZERO))) PC += addr;
+ break;
+ case 0x2F: //BLE
+ addr = signed16(fetch16());
+ if ((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2) || (CC&F_ZERO)) PC += addr;
+ break;
+ case 0x3f: //SWI2
+ CC |= F_ENTIRE;
+ PUSHW(PC);
+ PUSHW(rU);
+ PUSHW(rY);
+ PUSHW(rX);
+ PUSHB(DP);
+ PUSHB(rB);
+ PUSHB(rA);
+ PUSHB(CC);
+ CC |= F_IRQMASK | F_FIRQMASK;
+ PC = ReadWord(vecSWI2);
+ break;
+ case 0x83: //CMPD imm
+ oCMP16(getD(),fetch16());
+ break;
+ case 0x8C: //CMPY imm
+ oCMP16(rY,fetch16());
+ break;
+ case 0x8E: //LDY imm
+ rY = fetch16();
+ flagsNZ16(rY);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0x93: //CMPD direct
+ addr = dpadd();
+ oCMP16(getD(),ReadWord(addr));
+ break;
+ case 0x9C: //CMPY direct
+ addr = dpadd();
+ oCMP16(rY,ReadWord(addr));
+ break;
+ case 0x9E: //LDY direct
+ addr = dpadd();
+ rY = ReadWord(addr);
+ flagsNZ16(rY);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0x9F: //STY direct
+ addr = dpadd();
+ WriteWord(addr,rY);
+ flagsNZ16(rY);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xA3: //CMPD indexed
+ addr = PostByte();
+ oCMP16(getD(),ReadWord(addr));
+ break;
+ case 0xAC: //CMPY indexed
+ addr = PostByte();
+ oCMP16(rY,ReadWord(addr));
+ break;
+ case 0xAE: //LDY indexed
+ addr = PostByte();
+ rY = ReadWord(addr);
+ flagsNZ16(rY);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xAF: //STY indexed
+ addr = PostByte();
+ WriteWord(addr,rY);
+ flagsNZ16(rY);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xB3: //CMPD extended
+ addr = fetch16();
+ oCMP16(getD(),ReadWord(addr));
+ break;
+ case 0xBC: //CMPY extended
+ addr = fetch16();
+ oCMP16(rY,ReadWord(addr));
+ break;
+ case 0xBE: //LDY extended
+ addr = fetch16();
+ rY = ReadWord(addr);
+ flagsNZ16(rY);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xBF: //STY extended
+ addr = fetch16();
+ WriteWord(addr,rY);
+ flagsNZ16(rY);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xCE: //LDS imm
+ rS = fetch16();
+ flagsNZ16(rS);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xDE: //LDS direct
+ addr = dpadd();
+ rS = ReadWord(addr);
+ flagsNZ16(rS);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xDF: //STS direct
+ addr = dpadd();
+ WriteWord(addr,rS);
+ flagsNZ16(rS);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xEE: //LDS indexed
+ addr = PostByte();
+ rS = ReadWord(addr);
+ flagsNZ16(rS);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xEF: //STS indexed
+ addr = PostByte();
+ WriteWord(addr,rS);
+ flagsNZ16(rS);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xFE: //LDS extended
+ addr = fetch16();
+ rS = ReadWord(addr);
+ flagsNZ16(rS);
+ CC&=~F_OVERFLOW;
+ break;
+ case 0xFF: //STS extended
+ addr = fetch16();
+ WriteWord(addr,rS);
+ flagsNZ16(rS);
+ CC&=~F_OVERFLOW;
+ break;
+ }
+ }
+ break;
+ // page 2
+ case 0x11: //page 2
+ {
+ opcode = fetch();
+ T+=cycles2[opcode];
+ switch(opcode) {
+ case 0x3f: //SWI3
+ CC |= F_ENTIRE;
+ PUSHW(PC);
+ PUSHW(rU);
+ PUSHW(rY);
+ PUSHW(rX);
+ PUSHB(DP);
+ PUSHB(rB);
+ PUSHB(rA);
+ PUSHB(CC);
+ CC |= F_IRQMASK | F_FIRQMASK;
+ PC = ReadWord(vecSWI3);
+ break;
+ case 0x83: //CMPU imm
+ oCMP16(rU, fetch16());
+ break;
+ case 0x8C: //CMPS imm
+ oCMP16(rS, fetch16());
+ break;
+ case 0x93: //CMPU imm
+ addr = dpadd();
+ oCMP16(rU, ReadWord(addr));
+ break;
+ case 0x9C: //CMPS imm
+ addr = dpadd();
+ oCMP16(rS, ReadWord(addr));
+ break;
+ case 0xA3: //CMPU imm
+ addr = PostByte();
+ oCMP16(rU, ReadWord(addr));
+ break;
+ case 0xAC: //CMPS imm
+ addr = PostByte();
+ oCMP16(rS, ReadWord(addr));
+ break;
+ case 0xB3: //CMPU imm
+ addr = fetch16();
+ oCMP16(rU, ReadWord(addr));
+ break;
+ case 0xBC: //CMPS imm
+ addr = fetch16();
+ oCMP16(rS, ReadWord(addr));
+ break;
+
+ }
+ }
+ break;
+
+
+ }
+
+ rA &= 0xff;
+ rB &= 0xff;
+ CC &= 0xff;
+ DP &= 0xff;
+ rX &= 0xffff;
+ rY &= 0xffff;
+ rU &= 0xffff;
+ rS &= 0xffff;
+ PC &= 0xffff;
+ return T-oldT;
+
+};
+
+var reset = function(){
+ PC = ReadWord(vecRESET);
+ DP = 0;
+ CC |= F_FIRQMASK | F_IRQMASK;
+ T=0;
+ rA=rB=DP=rX=rY=rU=rS=0;
+};
+
+//---------- Disassembler
+
+/*
+ILLEGAL 0
+DIRECT 1
+INHERENT 2
+BRANCH_REL_16 3
+IMMEDIAT_8 4
+BRANCH_REL_8 5
+INDEXED 6
+EXTENDED 7
+IMMEDIAT_16 8
+
+PSHS 10
+PSHU 11
+
+EXG, TFR 20
+*/
+var ds = [
+[2, 1,"NEG"],
+[1, 0,"???"],
+[1, 0,"???"],
+[2, 1,"COM"],
+[2, 1,"LSR"],
+[1, 0,"???"],
+[2, 1,"ROR"],
+[2, 1,"ASR"],
+[2, 1,"LSL"],
+[2, 1,"ROL"],
+[2, 1,"DEC"],
+[1, 0,"???"],
+[2, 1,"INC"],
+[2, 1,"TST"],
+[2, 1,"JMP"],
+[2, 1,"CLR"],
+[1, 0,"Prefix"],
+[1, 0,"Prefix"],
+[1, 2,"NOP"],
+[1, 2,"SYNC"],
+[1, 0,"???"],
+[1, 0,"???"],
+[3, 3,"LBRA"],
+[3, 3,"LBSR"],
+[1, 0,"???"],
+[1, 2,"DAA"],
+[2, 4,"ORCC"],
+[1, 0,"???"],
+[2, 4,"ANDCC"],
+[1, 2,"SEX"],
+[2, 20,"EXG"],
+[2, 20,"TFR"],
+[2, 5,"BRA"],
+[2, 5,"BRN"],
+[2, 5,"BHI"],
+[2, 5,"BLS"],
+[2, 5,"BCC"],
+[2, 5,"BCS"],
+[2, 5,"BNE"],
+[2, 5,"BEQ"],
+[2, 5,"BVC"],
+[2, 5,"BVS"],
+[2, 5,"BPL"],
+[2, 5,"BMI"],
+[2, 5,"BGE"],
+[2, 5,"BLT"],
+[2, 5,"BGT"],
+[2, 5,"BLE"],
+[2, 6,"LEAX"],
+[2, 6,"LEAY"],
+[2, 6,"LEAS"],
+[2, 6,"LEAU"],
+[2, 10,"PSHS"],
+[2, 10,"PULS"],
+[2, 11,"PSHU"],
+[2, 11,"PULU"],
+[1, 0,"???"],
+[1, 2,"RTS"],
+[1, 2,"ABX"],
+[1, 2,"RTI"],
+[2, 2,"CWAI"],
+[1, 2,"MUL"],
+[1, 2,"RESET"],
+[1, 2,"SWI1"],
+[1, 2,"NEGA"],
+[1, 0,"???"],
+[1, 0,"???"],
+[1, 2,"COMA"],
+[1, 2,"LSRA"],
+[1, 0,"???"],
+[1, 2,"RORA"],
+[1, 2,"ASRA"],
+[1, 2,"ASLA"],
+[1, 2,"ROLA"],
+[1, 2,"DECA"],
+[1, 0,"???"],
+[1, 2,"INCA"],
+[1, 2,"TSTA"],
+[1, 0,"???"],
+[1, 2,"CLRA"],
+[1, 2,"NEGB"],
+[1, 0,"???"],
+[1, 0,"???"],
+[1, 2,"COMB"],
+[1, 2,"LSRB"],
+[1, 0,"???"],
+[1, 2,"RORB"],
+[1, 2,"ASRB"],
+[1, 2,"ASLB"],
+[1, 2,"ROLB"],
+[1, 2,"DECB"],
+[1, 0,"???"],
+[1, 2,"INCB"],
+[1, 2,"TSTB"],
+[1, 0,"???"],
+[1, 2,"CLRB"],
+[2, 6,"NEG"],
+[1, 0,"???"],
+[1, 0,"???"],
+[2, 6,"COM"],
+[2, 6,"LSR"],
+[1, 0,"???"],
+[2, 6,"ROR"],
+[2, 6,"ASR"],
+[2, 6,"LSL"],
+[2, 6,"ROL"],
+[2, 6,"DEC"],
+[1, 0,"???"],
+[2, 6,"INC"],
+[2, 6,"TST"],
+[2, 6,"JMP"],
+[2, 6,"CLR"],
+[3, 7,"NEG"],
+[1, 0,"???"],
+[1, 0,"???"],
+[3, 7,"COM"],
+[3, 7,"LSR"],
+[1, 0,"???"],
+[3, 7,"ROR"],
+[3, 7,"ASR"],
+[3, 7,"LSL"],
+[3, 7,"ROL"],
+[3, 7,"DEC"],
+[1, 0,"???"],
+[3, 7,"INC"],
+[3, 7,"TST"],
+[3, 7,"JMP"],
+[3, 7,"CLR"],
+[2, 4,"SUBA"],
+[2, 4,"CMPA"],
+[2, 4,"SBCA"],
+[3, 8,"SUBD"],
+[2, 4,"ANDA"],
+[2, 4,"BITA"],
+[2, 4,"LDA"],
+[1, 0,"???"],
+[2, 4,"EORA"],
+[2, 4,"ADCA"],
+[2, 4,"ORA"],
+[2, 4,"ADDA"],
+[3, 8,"CMPX"],
+[2, 5,"BSR"],
+[3, 8,"LDX"],
+[1, 0,"???"],
+[2, 1,"SUBA"],
+[2, 1,"CMPA"],
+[2, 1,"SBCA"],
+[2, 1,"SUBd"],
+[2, 1,"ANDA"],
+[2, 1,"BITA"],
+[2, 1,"LDA"],
+[2, 1,"STA"],
+[2, 1,"EORA"],
+[2, 1,"ADCA"],
+[2, 1,"ORA"],
+[2, 1,"ADDA"],
+[2, 1,"CMPX"],
+[2, 1,"JSR"],
+[2, 1,"LDX"],
+[2, 1,"STX"],
+[2, 6,"SUBA"],
+[2, 6,"CMPA"],
+[2, 6,"SBCA"],
+[2, 6,"SUBD"],
+[2, 6,"ANDA"],
+[2, 6,"BITA"],
+[2, 6,"LDA"],
+[2, 6,"STA"],
+[2, 6,"EORA"],
+[2, 6,"ADCA"],
+[2, 6,"ORA"],
+[2, 6,"ADDA"],
+[2, 6,"CMPX"],
+[2, 6,"JSR"],
+[2, 6,"LDX"],
+[2, 6,"STX"],
+[3, 7,"SUBA"],
+[3, 7,"CMPA"],
+[3, 7,"SBCA"],
+[3, 7,"SUBD"],
+[3, 7,"ANDA"],
+[3, 7,"BITA"],
+[3, 7,"LDA"],
+[3, 7,"STA"],
+[3, 7,"EORA"],
+[3, 7,"ADCA"],
+[3, 7,"ORA"],
+[3, 7,"ADDA"],
+[3, 7,"CMPX"],
+[3, 7,"JSR"],
+[3, 7,"LDX"],
+[3, 7,"STX"],
+[2, 4,"SUBB"],
+[2, 4,"CMPB"],
+[2, 4,"SBCB"],
+[3, 8,"ADDD"],
+[2, 4,"ANDB"],
+[2, 4,"BITB"],
+[2, 4,"LDB"],
+[1, 0,"???"],
+[2, 4,"EORB"],
+[2, 4,"ADCB"],
+[2, 4,"ORB"],
+[2, 4,"ADDB"],
+[3, 8,"LDD"],
+[1, 0,"???"],
+[3, 8,"LDU"],
+[1, 0,"???"],
+[2, 1,"SUBB"],
+[2, 1,"CMPB"],
+[2, 1,"SBCB"],
+[2, 1,"ADDD"],
+[2, 1,"ANDB"],
+[2, 1,"BITB"],
+[2, 1,"LDB"],
+[2, 1,"STB"],
+[2, 1,"EORB"],
+[2, 1,"ADCB"],
+[2, 1,"ORB "],
+[2, 1,"ADDB"],
+[2, 1,"LDD "],
+[2, 1,"STD "],
+[2, 1,"LDU "],
+[2, 1,"STU "],
+[2, 6,"SUBB"],
+[2, 6,"CMPB"],
+[2, 6,"SBCB"],
+[2, 6,"ADDD"],
+[2, 6,"ANDB"],
+[2, 6,"BITB"],
+[2, 6,"LDB"],
+[2, 6,"STB"],
+[2, 6,"EORB"],
+[2, 6,"ADCB"],
+[2, 6,"ORB"],
+[2, 6,"ADDB"],
+[2, 6,"LDD"],
+[2, 6,"STD"],
+[2, 6,"LDU"],
+[2, 6,"STU"],
+[3, 7,"SUBB"],
+[3, 7,"CMPB"],
+[3, 7,"SBCB"],
+[3, 7,"ADDD"],
+[3, 7,"ANDB"],
+[3, 7,"BITB"],
+[3, 7,"LDB"],
+[3, 7,"STB"],
+[3, 7,"EORB"],
+[3, 7,"ADCB"],
+[3, 7,"ORB"],
+[3, 7,"ADDB"],
+[3, 7,"LDD"],
+[3, 7,"STD"],
+[3, 7,"LDU"],
+[3, 7,"STU"]
+];
+
+var ds11 = {
+0x3F: [2,2,"SWI3"],
+0x83: [4,8,"CMPU"],
+0x8C: [4,8,"CMPS"],
+0x93: [3,1,"CMPU"],
+0x9C: [3,1,"CMPS"],
+0xA3: [3,6,"CMPU"],
+0xAC: [3,6,"CMPS"],
+0xB3: [4,7,"CMPU"],
+0xBC: [4,7,"CMPS"]
+};
+
+var ds10 = {
+0x21:[5,3,"LBRN"],
+0x22:[5,3,"LBHI"],
+0x23:[5,3,"LBLS"],
+0x24:[5,3,"LBCC"],
+0x25:[5,3,"LBCS"],
+0x26:[5,3,"LBNE"],
+0x27:[5,3,"LBEQ"],
+0x28:[5,3,"LBVC"],
+0x29:[5,3,"LBVS"],
+0x2a:[5,3,"LBPL"],
+0x2b:[5,3,"LBMI"],
+0x2c:[5,3,"LBGE"],
+0x2d:[5,3,"LBLT"],
+0x2e:[5,3,"LBGT"],
+0x2f:[5,3,"LBLE"],
+0x3F:[2,2,"SWI2"],
+0x83:[4,8,"CMPD"],
+0x8C:[4,8,"CMPY"],
+0x8E:[4,8,"LDY"],
+0x93:[3,1,"CMPD"],
+0x9C:[3,1,"CMPY"],
+0x9E:[3,1,"LDY"],
+0x9F:[3,1,"STY"],
+0xA3:[3,6,"CMPD"],
+0xAC:[3,6,"CMPY"],
+0xAE:[3,6,"LDY"],
+0xAF:[3,6,"STY"],
+0xB3:[4,7,"CMPD"],
+0xBC:[4,7,"CMPY"],
+0xBE:[4,7,"LDY"],
+0xBF:[4,7,"STY"],
+0xCE:[4,8,"LDS"],
+0xDE:[3,1,"LDS"],
+0xDF:[3,1,"STS"],
+0xEE:[3,6,"LDS"],
+0xEF:[3,6,"STS"],
+0xFE:[4,7,"LDS"],
+0xFF:[4,7,"STS"]
+};
+/*
+ILLEGAL 0
+DIRECT 1
+INHERENT 2
+BRANCH_REL_16 3
+IMMEDIAT_8 4
+BRANCH_REL_8 5
+INDEXED 6
+EXTENDED 7
+IMMEDIAT_16 8
+*/
+
+var disasm = function(i,a,b,c,d,pc) {
+ var toHexN = function(n,d) {
+ var s = n.toString(16);
+ while (s.length >5];
+ if (!(pb & 0x80)) {
+ //direct5
+ var disp = pb & 0x1f;
+ if (disp>15) disp = disp-32;
+ mnemo+=disp+','+ixr;
+ break;
+ }
+ var ind = pb & 0x10;
+ var mod = pb & 0x0f;
+ var ofs8 = (b>127)?(b-256):b;
+ var ofs16 = ((b*256+c)>32767)?((b*256+c)-65536):(b*256+c);
+ if (!ind) {
+ switch (mod) {
+ case 0: mnemo += ","+ixr+'+'; break;
+ case 1: mnemo += ","+ixr+'++'; break;
+ case 2: mnemo += ",-"+ixr; break;
+ case 3: mnemo += ",--"+ixr; break;
+ case 4: mnemo += ","+ixr; break;
+ case 5: mnemo += "B,"+ixr; break;
+ case 6: mnemo += "A,"+ixr; break;
+ case 7: mnemo += "???"; break;
+ case 8: mnemo += ofs8+","+ixr; bytes++; break;
+ case 9: mnemo += ofs16+","+ixr; bytes+=2; break;
+ case 10: mnemo += "???"; break;
+ case 11: mnemo += "D,"+ixr; break;
+ case 12: mnemo += ofs8+",PC"; bytes++; break;
+ case 13: mnemo += ofs16+",PC"; bytes+=2; break;
+ case 14: mnemo += "???"; break;
+ case 15: mnemo += "$"+toHex4((b*256+c)); bytes+=2; break;
+ }
+ } else {
+ switch (mod) {
+ case 0: mnemo += "???"; break;
+ case 1: mnemo += "[,"+ixr+'++]'; break;
+ case 2: mnemo += "???"; break;
+ case 3: mnemo += "[,--"+ixr+']'; break;
+ case 4: mnemo += "[,"+ixr+']'; break;
+ case 5: mnemo += "[B,"+ixr+']'; break;
+ case 6: mnemo += "[A,"+ixr+']'; break;
+ case 7: mnemo += "???"; break;
+ case 8: mnemo += "["+ofs8+","+ixr+']'; bytes++; break;
+ case 9: mnemo += "["+ofs16+","+ixr+']'; bytes+=2; break;
+ case 10: mnemo += "???"; break;
+ case 11: mnemo += "[D,"+ixr+']'; break;
+ case 12: mnemo += "["+ofs8+",PC]"; bytes++; break;
+ case 13: mnemo += "["+ofs16+",PC]"; bytes+=2; break;
+ case 14: mnemo += "???"; break;
+ case 15: mnemo += "[$"+toHex4((b*256+c))+']'; bytes+=2; break;
+ }
+ }
+
+ break;
+ case 7: //extended
+ mnemo+=" $"+toHex4(a*256+b); break;
+ case 8: //imm16
+ mnemo+=" #$"+toHex4(a*256+b); break;
+
+ case 10: //pshs, puls
+ rx = ['PC','U','Y','X','DP','B','A','CC'];
+ ro = [];
+ for (j=0;j<8;j++) {
+ if ((a & 1)!==0) {ro.push(rx[7-j]);}
+ a>>=1;
+ }
+ mnemo += ' '+ro.join(',');
+ break;
+ case 11: //pshs, puls
+ rx = ['PC','S','Y','X','DP','B','A','CC'];
+ ro = [];
+ for (j=0;j<8;j++) {
+ if ((a & 1)!==0) {ro.push(rx[7-j]);}
+ a>>=1;
+ }
+ mnemo += ' '+ro.join(',');
+ break;
+ case 20: //TFR etc
+ rx = ['D','X','Y','U','S','PC','?','?','A','B','CC','DP','?','?','?','?'];
+ mnemo += ' '+rx[a>>4]+','+rx[a&0x0f];
+ break;
+ }
+
+ return {line:mnemo,nbytes:bytes};
+ };
+
+
+//---------- Exports
+
+return {
+ steps: function(Ts){
+ //T=0;
+ while (Ts>0){
+ Ts-=step();
+ }
+ },
+ T:function(){return T;},
+ reset: reset,
+ init: function(bt,ba,tck){
+ byteTo=bt;
+ byteAt=ba;
+ ticks=tck;
+ reset();
+ },
+ getPC: function() { return PC; },
+ saveState: function() {
+ return {
+ PC:PC,
+ SP:rS,
+ U:rU,
+ A:rA,
+ B:rB,
+ X:rX,
+ Y:rY,
+ DP:DP,
+ CC:CC,
+ T:T
+ };
+ },
+ loadState: function(s) {
+ PC=s.PC;
+ rS=s.SP;
+ rU=s.U;
+ rA=s.A;
+ rB=s.B;
+ rX=s.X;
+ rY=s.Y;
+ DP=s.DP;
+ CC=s.CC;
+ T=s.T;
+ },
+ firq: function() {
+ if (CC & F_FIRQMASK) return;
+ PUSHW(PC);
+ CC &= ~F_ENTIRE;
+ PUSHB(CC);
+ CC |= F_IRQMASK | F_FIRQMASK;
+ PC = ReadWord(vecFIRQ);
+ },
+ interrupt: function() {
+ if (CC & F_IRQMASK) return;
+ PUSHW(PC);
+ PUSHW(rU);
+ PUSHW(rY);
+ PUSHW(rX);
+ PUSHB(DP);
+ PUSHB(rB);
+ PUSHB(rA);
+ CC |= F_ENTIRE;
+ PUSHB(CC);
+ CC |= F_IRQMASK;
+ PC = ReadWord(vecIRQ);
+ },
+ nmi: function() {
+ PUSHW(PC);
+ PUSHW(rU);
+ PUSHW(rY);
+ PUSHW(rX);
+ PUSHB(DP);
+ PUSHB(rB);
+ PUSHB(rA);
+ CC |= F_ENTIRE;
+ PUSHB(CC);
+ CC |= F_IRQMASK | F_FIRQMASK;
+ PC = ReadWord(vecNMI);
+ },
+ set:function(reg,value) {
+ switch (reg.toUpperCase()) {
+ case "PC": PC=value;return;
+ case "A": rA=value;return;
+ case "B": rB=value;return;
+ case "X": rX=value;return;
+ case "Y": rY=value;return;
+ case "SP": rS=value;return;
+ case "U": rU=value;return;
+ case "FLAGS": CC=value;return;
+ }
+ },
+ flagsToString: function() {
+ var f='',fx = "EFHINZVC";
+ for (var i=0;i<8;i++) {
+ var n = CC&(0x80>>i);
+ if (n===0) {f+=fx[i].toLowerCase();} else {f+=fx[i];}
+ }
+ return f;
+ },
+ disasm: disasm,
+};
+
+};
diff --git a/src/cpu/z80.coffee b/src/cpu/z80.coffee
index 7b8bb81c..32dc3e2f 100644
--- a/src/cpu/z80.coffee
+++ b/src/cpu/z80.coffee
@@ -2444,13 +2444,13 @@ window.buildZ80 = (opts) ->
regPairs[#{rpSP}] = snapRegs['SP'];
regPairs[#{rpPC}] = snapRegs['PC'];
regPairs[#{rpIR}] = snapRegs['IR'];
- iff1 = snapRegs['iff1'];
- iff2 = snapRegs['iff2'];
- im = snapRegs['im'];
- halted = snapRegs['halted'];
- tstates = snapRegs['tstates'];
- interruptPending = snapRegs['intp'];
- interruptDataBus = snapRegs['intd'];
+ iff1 = snapRegs['iff1'] & 1;
+ iff2 = snapRegs['iff2'] & 1;
+ im = snapRegs['im'] & 1;
+ halted = !!snapRegs['halted'];
+ tstates = snapRegs['T'] * 1;
+ interruptPending = !!snapRegs['intp'];
+ interruptDataBus = snapRegs['intd'] & 0xffff;
};
self.saveState = function() {
@@ -2472,7 +2472,7 @@ window.buildZ80 = (opts) ->
iff2: iff2,
im: im,
halted: halted,
- tstates: tstates,
+ T: tstates,
intp: interruptPending,
intd: interruptDataBus,
};
@@ -2577,23 +2577,23 @@ window.buildZ80 = (opts) ->
regPairs[#{rpPC}] = val;
}
self.setIFF1 = function(val) {
- iff1 = val;
+ iff1 = val & 1;
}
self.setIFF2 = function(val) {
- iff2 = val;
+ iff2 = val & 1;
}
self.setIM = function(val) {
- im = val;
+ im = val & 1;
}
self.setHalted = function(val) {
- halted = val;
+ halted = !!val;
}
self.getTstates = function() {
return tstates;
}
self.setTstates = function(val) {
- tstates = val;
+ tstates = val * 1;
}
self.getCarry_ = function() {
diff --git a/src/cpu/z80.js b/src/cpu/z80.js
index 740c1618..234eab9e 100644
--- a/src/cpu/z80.js
+++ b/src/cpu/z80.js
@@ -1666,7 +1666,7 @@ of the host processor, as typed arrays are native-endian
The indirection on 'eval' causes most browsers to evaluate it in the global
scope, giving a significant speed boost
*/
- defineZ80JS = "window.Z80 = function(opts) {\n var self = {};\n\n " + setUpStateJS + "\n\n self.requestInterrupt = function(dataBus) {\n interruptPending = true;\n interruptDataBus = dataBus & 0xffff;\n /* TODO: use event scheduling to keep the interrupt line active for a fixed\n ~48T window, to support retriggered interrupts and interrupt blocking via\n chains of EI or DD/FD prefixes */\n }\n self.nonMaskableInterrupt = function() {\n iff1 = 1;\n self.requestInterrupt(0x66);\n }\n var z80Interrupt = function() {\n if (iff1) {\n if (halted) {\n /* move PC on from the HALT opcode */\n regPairs[" + rpPC + "]++;\n halted = false;\n }\n\n iff1 = iff2 = 0;\n\n /* push current PC in readiness for call to interrupt handler */\n regPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rpPC + "] >> 8);\n regPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rpPC + "] & 0xff);\n\n /* TODO: R register */\n\n switch (im) {\n case 0:\n regPairs[" + rpPC + "] = interruptDataBus; // assume always RST\n tstates += 6;\n break;\n case 1:\n regPairs[" + rpPC + "] = 0x0038;\n tstates += 7;\n break;\n case 2:\n inttemp = (regs[" + rI + "] << 8) | (interruptDataBus & 0xff);\n l = READMEM(inttemp);\n inttemp = (inttemp+1) & 0xffff;\n h = READMEM(inttemp);\n console.log(hex(interruptDataBus), hex(inttemp), hex(l), hex(h));\n regPairs[" + rpPC + "] = (h<<8) | l;\n tstates += 7;\n break;\n }\n }\n };\n\n self.runFrame = function(frameLength) {\n var lastOpcodePrefix, offset, opcode;\n\n while (tstates < frameLength || opcodePrefix) {\n if (interruptible && interruptPending) {\n z80Interrupt();\n interruptPending = false;\n }\n interruptible = true; /* unless overridden by opcode */\n lastOpcodePrefix = opcodePrefix;\n opcodePrefix = '';\n switch (lastOpcodePrefix) {\n case '':\n CONTEND_READ(regPairs[" + rpPC + "], 4);\n opcode = memory.read(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n regs[" + rR + "] = ((regs[" + rR + "] + 1) & 0x7f) | (regs[" + rR + "] & 0x80);\n " + (opcodeSwitch(OPCODE_RUN_STRINGS, null, opts.traps)) + "\n break;\n case 'CB':\n CONTEND_READ(regPairs[" + rpPC + "], 4);\n opcode = memory.read(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n regs[" + rR + "] = ((regs[" + rR + "] + 1) & 0x7f) | (regs[" + rR + "] & 0x80);\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_CB)) + "\n break;\n case 'DD':\n CONTEND_READ(regPairs[" + rpPC + "], 4);\n opcode = memory.read(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n regs[" + rR + "] = ((regs[" + rR + "] + 1) & 0x7f) | (regs[" + rR + "] & 0x80);\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_DD, OPCODE_RUN_STRINGS)) + "\n break;\n case 'DDCB':\n offset = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n if (offset & 0x80) offset -= 0x100;\n CONTEND_READ(regPairs[" + rpPC + "], 3);\n opcode = memory.read(regPairs[" + rpPC + "]);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n regPairs[" + rpPC + "]++;\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_DDCB)) + "\n break;\n case 'ED':\n CONTEND_READ(regPairs[" + rpPC + "], 4);\n opcode = memory.read(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n regs[" + rR + "] = ((regs[" + rR + "] + 1) & 0x7f) | (regs[" + rR + "] & 0x80);\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_ED)) + "\n break;\n case 'FD':\n CONTEND_READ(regPairs[" + rpPC + "], 4);\n opcode = memory.read(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n regs[" + rR + "] = ((regs[" + rR + "] + 1) & 0x7f) | (regs[" + rR + "] & 0x80);\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_FD, OPCODE_RUN_STRINGS)) + "\n break;\n case 'FDCB':\n offset = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n if (offset & 0x80) offset -= 0x100;\n CONTEND_READ(regPairs[" + rpPC + "], 3);\n opcode = memory.read(regPairs[" + rpPC + "]);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n regPairs[" + rpPC + "]++;\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_FDCB)) + "\n break;\n default:\n throw(\"Unknown opcode prefix: \" + lastOpcodePrefix);\n }\n }\n while (display.nextEventTime != null && display.nextEventTime <= tstates) display.doEvent();\n };\n\n self.reset = function() {\n regPairs[" + rpPC + "] = regPairs[" + rpIR + "] = 0;\n iff1 = 0; iff2 = 0; im = 0; halted = false;\n };\n\n self.loadState = function(snapRegs) {\n regPairs[" + rpAF + "] = snapRegs['AF'];\n regPairs[" + rpBC + "] = snapRegs['BC'];\n regPairs[" + rpDE + "] = snapRegs['DE'];\n regPairs[" + rpHL + "] = snapRegs['HL'];\n regPairs[" + rpAF_ + "] = snapRegs['AF_'];\n regPairs[" + rpBC_ + "] = snapRegs['BC_'];\n regPairs[" + rpDE_ + "] = snapRegs['DE_'];\n regPairs[" + rpHL_ + "] = snapRegs['HL_'];\n regPairs[" + rpIX + "] = snapRegs['IX'];\n regPairs[" + rpIY + "] = snapRegs['IY'];\n regPairs[" + rpSP + "] = snapRegs['SP'];\n regPairs[" + rpPC + "] = snapRegs['PC'];\n regPairs[" + rpIR + "] = snapRegs['IR'];\n iff1 = snapRegs['iff1'];\n iff2 = snapRegs['iff2'];\n im = snapRegs['im'];\n halted = snapRegs['halted'];\n tstates = snapRegs['tstates'];\n interruptPending = snapRegs['intp'];\n interruptDataBus = snapRegs['intd'];\n };\n\n self.saveState = function() {\n return {\n AF: regPairs[" + rpAF + "],\n BC: regPairs[" + rpBC + "],\n DE: regPairs[" + rpDE + "],\n HL: regPairs[" + rpHL + "],\n AF_: regPairs[" + rpAF_ + "],\n BC_: regPairs[" + rpBC_ + "],\n DE_: regPairs[" + rpDE_ + "],\n HL_: regPairs[" + rpHL_ + "],\n IX: regPairs[" + rpIX + "],\n IY: regPairs[" + rpIY + "],\n SP: regPairs[" + rpSP + "],\n PC: regPairs[" + rpPC + "],\n IR: regPairs[" + rpIR + "],\n iff1: iff1,\n iff2: iff2,\n im: im,\n halted: halted,\n tstates: tstates,\n intp: interruptPending,\n intd: interruptDataBus,\n };\n };\n\n /* Register / flag accessors (used for tape trapping and test harness) */\n self.getAF = function() {\n return regPairs[" + rpAF + "];\n }\n self.getBC = function() {\n return regPairs[" + rpBC + "];\n }\n self.getDE = function() {\n return regPairs[" + rpDE + "];\n }\n self.getHL = function() {\n return regPairs[" + rpHL + "];\n }\n self.getAF_ = function() {\n return regPairs[" + rpAF_ + "];\n }\n self.getBC_ = function() {\n return regPairs[" + rpBC_ + "];\n }\n self.getDE_ = function() {\n return regPairs[" + rpDE_ + "];\n }\n self.getHL_ = function() {\n return regPairs[" + rpHL_ + "];\n }\n self.getIX = function() {\n return regPairs[" + rpIX + "];\n }\n self.getIY = function() {\n return regPairs[" + rpIY + "];\n }\n self.getI = function() {\n return regs[" + rI + "];\n }\n self.getR = function() {\n return regs[" + rR + "];\n }\n self.getSP = function() {\n return regPairs[" + rpSP + "];\n }\n self.getPC = function() {\n return regPairs[" + rpPC + "];\n }\n self.getIFF1 = function() {\n return iff1;\n }\n self.getIFF2 = function() {\n return iff2;\n }\n self.getIM = function() {\n return im;\n }\n self.getHalted = function() {\n return halted;\n }\n\n self.setAF = function(val) {\n regPairs[" + rpAF + "] = val;\n }\n self.setBC = function(val) {\n regPairs[" + rpBC + "] = val;\n }\n self.setDE = function(val) {\n regPairs[" + rpDE + "] = val;\n }\n self.setHL = function(val) {\n regPairs[" + rpHL + "] = val;\n }\n self.setAF_ = function(val) {\n regPairs[" + rpAF_ + "] = val;\n }\n self.setBC_ = function(val) {\n regPairs[" + rpBC_ + "] = val;\n }\n self.setDE_ = function(val) {\n regPairs[" + rpDE_ + "] = val;\n }\n self.setHL_ = function(val) {\n regPairs[" + rpHL_ + "] = val;\n }\n self.setIX = function(val) {\n regPairs[" + rpIX + "] = val;\n }\n self.setIY = function(val) {\n regPairs[" + rpIY + "] = val;\n }\n self.setI = function(val) {\n regs[" + rI + "] = val;\n }\n self.setR = function(val) {\n regs[" + rR + "] = val;\n }\n self.setSP = function(val) {\n regPairs[" + rpSP + "] = val;\n }\n self.setPC = function(val) {\n regPairs[" + rpPC + "] = val;\n }\n self.setIFF1 = function(val) {\n iff1 = val;\n }\n self.setIFF2 = function(val) {\n iff2 = val;\n }\n self.setIM = function(val) {\n im = val;\n }\n self.setHalted = function(val) {\n halted = val;\n }\n\n self.getTstates = function() {\n return tstates;\n }\n self.setTstates = function(val) {\n tstates = val;\n }\n\n self.getCarry_ = function() {\n return regs[" + rF_ + "] & " + FLAG_C + ";\n };\n self.setCarry = function(val) {\n if (val) {\n regs[" + rF + "] |= " + FLAG_C + ";\n } else {\n regs[" + rF + "] &= " + (~FLAG_C) + ";\n }\n };\n self.getA_ = function() {\n return regs[" + rA_ + "];\n };\n\n return self;\n};";
+ defineZ80JS = "window.Z80 = function(opts) {\n var self = {};\n\n " + setUpStateJS + "\n\n self.requestInterrupt = function(dataBus) {\n interruptPending = true;\n interruptDataBus = dataBus & 0xffff;\n /* TODO: use event scheduling to keep the interrupt line active for a fixed\n ~48T window, to support retriggered interrupts and interrupt blocking via\n chains of EI or DD/FD prefixes */\n }\n self.nonMaskableInterrupt = function() {\n iff1 = 1;\n self.requestInterrupt(0x66);\n }\n var z80Interrupt = function() {\n if (iff1) {\n if (halted) {\n /* move PC on from the HALT opcode */\n regPairs[" + rpPC + "]++;\n halted = false;\n }\n\n iff1 = iff2 = 0;\n\n /* push current PC in readiness for call to interrupt handler */\n regPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rpPC + "] >> 8);\n regPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rpPC + "] & 0xff);\n\n /* TODO: R register */\n\n switch (im) {\n case 0:\n regPairs[" + rpPC + "] = interruptDataBus; // assume always RST\n tstates += 6;\n break;\n case 1:\n regPairs[" + rpPC + "] = 0x0038;\n tstates += 7;\n break;\n case 2:\n inttemp = (regs[" + rI + "] << 8) | (interruptDataBus & 0xff);\n l = READMEM(inttemp);\n inttemp = (inttemp+1) & 0xffff;\n h = READMEM(inttemp);\n console.log(hex(interruptDataBus), hex(inttemp), hex(l), hex(h));\n regPairs[" + rpPC + "] = (h<<8) | l;\n tstates += 7;\n break;\n }\n }\n };\n\n self.runFrame = function(frameLength) {\n var lastOpcodePrefix, offset, opcode;\n\n while (tstates < frameLength || opcodePrefix) {\n if (interruptible && interruptPending) {\n z80Interrupt();\n interruptPending = false;\n }\n interruptible = true; /* unless overridden by opcode */\n lastOpcodePrefix = opcodePrefix;\n opcodePrefix = '';\n switch (lastOpcodePrefix) {\n case '':\n CONTEND_READ(regPairs[" + rpPC + "], 4);\n opcode = memory.read(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n regs[" + rR + "] = ((regs[" + rR + "] + 1) & 0x7f) | (regs[" + rR + "] & 0x80);\n " + (opcodeSwitch(OPCODE_RUN_STRINGS, null, opts.traps)) + "\n break;\n case 'CB':\n CONTEND_READ(regPairs[" + rpPC + "], 4);\n opcode = memory.read(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n regs[" + rR + "] = ((regs[" + rR + "] + 1) & 0x7f) | (regs[" + rR + "] & 0x80);\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_CB)) + "\n break;\n case 'DD':\n CONTEND_READ(regPairs[" + rpPC + "], 4);\n opcode = memory.read(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n regs[" + rR + "] = ((regs[" + rR + "] + 1) & 0x7f) | (regs[" + rR + "] & 0x80);\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_DD, OPCODE_RUN_STRINGS)) + "\n break;\n case 'DDCB':\n offset = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n if (offset & 0x80) offset -= 0x100;\n CONTEND_READ(regPairs[" + rpPC + "], 3);\n opcode = memory.read(regPairs[" + rpPC + "]);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n regPairs[" + rpPC + "]++;\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_DDCB)) + "\n break;\n case 'ED':\n CONTEND_READ(regPairs[" + rpPC + "], 4);\n opcode = memory.read(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n regs[" + rR + "] = ((regs[" + rR + "] + 1) & 0x7f) | (regs[" + rR + "] & 0x80);\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_ED)) + "\n break;\n case 'FD':\n CONTEND_READ(regPairs[" + rpPC + "], 4);\n opcode = memory.read(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n regs[" + rR + "] = ((regs[" + rR + "] + 1) & 0x7f) | (regs[" + rR + "] & 0x80);\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_FD, OPCODE_RUN_STRINGS)) + "\n break;\n case 'FDCB':\n offset = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n if (offset & 0x80) offset -= 0x100;\n CONTEND_READ(regPairs[" + rpPC + "], 3);\n opcode = memory.read(regPairs[" + rpPC + "]);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n regPairs[" + rpPC + "]++;\n " + (opcodeSwitch(OPCODE_RUN_STRINGS_FDCB)) + "\n break;\n default:\n throw(\"Unknown opcode prefix: \" + lastOpcodePrefix);\n }\n }\n while (display.nextEventTime != null && display.nextEventTime <= tstates) display.doEvent();\n };\n\n self.reset = function() {\n regPairs[" + rpPC + "] = regPairs[" + rpIR + "] = 0;\n iff1 = 0; iff2 = 0; im = 0; halted = false;\n };\n\n self.loadState = function(snapRegs) {\n regPairs[" + rpAF + "] = snapRegs['AF'];\n regPairs[" + rpBC + "] = snapRegs['BC'];\n regPairs[" + rpDE + "] = snapRegs['DE'];\n regPairs[" + rpHL + "] = snapRegs['HL'];\n regPairs[" + rpAF_ + "] = snapRegs['AF_'];\n regPairs[" + rpBC_ + "] = snapRegs['BC_'];\n regPairs[" + rpDE_ + "] = snapRegs['DE_'];\n regPairs[" + rpHL_ + "] = snapRegs['HL_'];\n regPairs[" + rpIX + "] = snapRegs['IX'];\n regPairs[" + rpIY + "] = snapRegs['IY'];\n regPairs[" + rpSP + "] = snapRegs['SP'];\n regPairs[" + rpPC + "] = snapRegs['PC'];\n regPairs[" + rpIR + "] = snapRegs['IR'];\n iff1 = snapRegs['iff1'] & 0xffff;\n iff2 = snapRegs['iff2'] & 0xffff;\n im = snapRegs['im'] & 0xffff;\n halted = !!snapRegs['halted'];\n tstates = snapRegs['T'] * 1;\n interruptPending = !!snapRegs['intp'];\n interruptDataBus = snapRegs['intd'] & 0xffff;\n };\n\n self.saveState = function() {\n return {\n AF: regPairs[" + rpAF + "],\n BC: regPairs[" + rpBC + "],\n DE: regPairs[" + rpDE + "],\n HL: regPairs[" + rpHL + "],\n AF_: regPairs[" + rpAF_ + "],\n BC_: regPairs[" + rpBC_ + "],\n DE_: regPairs[" + rpDE_ + "],\n HL_: regPairs[" + rpHL_ + "],\n IX: regPairs[" + rpIX + "],\n IY: regPairs[" + rpIY + "],\n SP: regPairs[" + rpSP + "],\n PC: regPairs[" + rpPC + "],\n IR: regPairs[" + rpIR + "],\n iff1: iff1,\n iff2: iff2,\n im: im,\n halted: halted,\n T: tstates,\n intp: interruptPending,\n intd: interruptDataBus,\n };\n };\n\n /* Register / flag accessors (used for tape trapping and test harness) */\n self.getAF = function() {\n return regPairs[" + rpAF + "];\n }\n self.getBC = function() {\n return regPairs[" + rpBC + "];\n }\n self.getDE = function() {\n return regPairs[" + rpDE + "];\n }\n self.getHL = function() {\n return regPairs[" + rpHL + "];\n }\n self.getAF_ = function() {\n return regPairs[" + rpAF_ + "];\n }\n self.getBC_ = function() {\n return regPairs[" + rpBC_ + "];\n }\n self.getDE_ = function() {\n return regPairs[" + rpDE_ + "];\n }\n self.getHL_ = function() {\n return regPairs[" + rpHL_ + "];\n }\n self.getIX = function() {\n return regPairs[" + rpIX + "];\n }\n self.getIY = function() {\n return regPairs[" + rpIY + "];\n }\n self.getI = function() {\n return regs[" + rI + "];\n }\n self.getR = function() {\n return regs[" + rR + "];\n }\n self.getSP = function() {\n return regPairs[" + rpSP + "];\n }\n self.getPC = function() {\n return regPairs[" + rpPC + "];\n }\n self.getIFF1 = function() {\n return iff1;\n }\n self.getIFF2 = function() {\n return iff2;\n }\n self.getIM = function() {\n return im;\n }\n self.getHalted = function() {\n return halted;\n }\n\n self.setAF = function(val) {\n regPairs[" + rpAF + "] = val;\n }\n self.setBC = function(val) {\n regPairs[" + rpBC + "] = val;\n }\n self.setDE = function(val) {\n regPairs[" + rpDE + "] = val;\n }\n self.setHL = function(val) {\n regPairs[" + rpHL + "] = val;\n }\n self.setAF_ = function(val) {\n regPairs[" + rpAF_ + "] = val;\n }\n self.setBC_ = function(val) {\n regPairs[" + rpBC_ + "] = val;\n }\n self.setDE_ = function(val) {\n regPairs[" + rpDE_ + "] = val;\n }\n self.setHL_ = function(val) {\n regPairs[" + rpHL_ + "] = val;\n }\n self.setIX = function(val) {\n regPairs[" + rpIX + "] = val;\n }\n self.setIY = function(val) {\n regPairs[" + rpIY + "] = val;\n }\n self.setI = function(val) {\n regs[" + rI + "] = val;\n }\n self.setR = function(val) {\n regs[" + rR + "] = val;\n }\n self.setSP = function(val) {\n regPairs[" + rpSP + "] = val;\n }\n self.setPC = function(val) {\n regPairs[" + rpPC + "] = val;\n }\n self.setIFF1 = function(val) {\n iff1 = val & 0xffff;\n }\n self.setIFF2 = function(val) {\n iff2 = val & 0xffff;\n }\n self.setIM = function(val) {\n im = val & 0xffff;\n }\n self.setHalted = function(val) {\n halted = !!val;\n }\n\n self.getTstates = function() {\n return tstates;\n }\n self.setTstates = function(val) {\n tstates = val * 1;\n }\n\n self.getCarry_ = function() {\n return regs[" + rF_ + "] & " + FLAG_C + ";\n };\n self.setCarry = function(val) {\n if (val) {\n regs[" + rF + "] |= " + FLAG_C + ";\n } else {\n regs[" + rF + "] &= " + (~FLAG_C) + ";\n }\n };\n self.getA_ = function() {\n return regs[" + rA_ + "];\n };\n\n return self;\n};";
defineZ80JS = defineZ80JS.replace(/READMEM\((.*?)\)/g, '(CONTEND_READ($1, 3), memory.read($1))');
defineZ80JS = defineZ80JS.replace(/WRITEMEM\((.*?),(.*?)\)/g, "CONTEND_WRITE($1, 3);\nwhile (display.nextEventTime != null && display.nextEventTime < tstates) display.doEvent();\nmemory.write($1,$2);");
if (opts.applyContention) {
diff --git a/src/emu.js b/src/emu.js
index e98e93a4..c4e803d1 100644
--- a/src/emu.js
+++ b/src/emu.js
@@ -45,6 +45,8 @@ var RasterVideo = function(mainElement, width, height, options) {
canvas.style.transform = "rotate("+options.rotate+"deg)";
if (canvas.width > canvas.height)
canvas.style.paddingTop = canvas.style.paddingBottom = "10%";
+ else
+ canvas.style.paddingLeft = canvas.style.paddingRight = "10%";
}
ctx = canvas.getContext('2d');
imageData = ctx.createImageData(width, height);
@@ -332,7 +334,7 @@ function cpuStateToLongString_6502(c) {
// s += c.I ? " I" : " -";
return s;
}
- return "PC " + hex(c.PC,4) + " " + decodeFlags(c) + " " + getTIAPosString() + "\n"
+ return "PC " + hex(c.PC,4) + " " + decodeFlags(c) + "\n"
+ " A " + hex(c.A) + " " + (c.R ? "" : "BUSY") + "\n"
+ " X " + hex(c.X) + "\n"
+ " Y " + hex(c.Y) + " " + "SP " + hex(c.SP) + "\n";
@@ -389,7 +391,8 @@ var Base6502Platform = function() {
onBreakpointHit = null;
debugCondition = null;
}
- this.breakpointHit = function() {
+ this.breakpointHit = function(targetClock) {
+ debugTargetClock = targetClock;
debugBreakState = this.saveState();
debugBreakState.c.PC = (debugBreakState.c.PC-1) & 0xffff;
console.log("Breakpoint at clk", debugClock, "PC", debugBreakState.c.PC.toString(16));
@@ -410,8 +413,7 @@ var Base6502Platform = function() {
} else {
if (thisState.PC != previousPC && thisState.T == 0) {
//console.log(previousPC.toString(16), thisPC.toString(16));
- debugTargetClock = debugClock-1;
- self.breakpointHit();
+ self.breakpointHit(debugClock-1);
return true;
}
}
@@ -426,12 +428,10 @@ var Base6502Platform = function() {
this.setDebugCondition(function() {
if (debugClock++ >= debugTargetClock && prevState) {
self.loadState(prevState);
- debugTargetClock = prevClock-1;
- self.breakpointHit();
+ self.breakpointHit(prevClock-1);
return true;
} else if (debugClock > debugTargetClock-10 && debugClock < debugTargetClock) {
if (self.getCPUState().T == 0) {
- console.log(debugClock, self.getCPUState());
prevState = self.saveState();
prevClock = debugClock;
}
@@ -446,8 +446,7 @@ var Base6502Platform = function() {
var cpuState = self.getCPUState();
cpuState.PC = (cpuState.PC-1)&0xffff;
if (evalfunc(cpuState)) {
- self.breakpointHit();
- debugTargetClock = debugClock-1;
+ self.breakpointHit(debugClock-1);
return true;
} else {
return false;
@@ -497,6 +496,8 @@ function dumpRAM(ram, ramofs, ramlen) {
return s;
}
+////// Z80
+
function cpuStateToLongString_Z80(c) {
function decodeFlags(flags) {
var flagspec = "SZ-H-VNC";
@@ -505,7 +506,7 @@ function cpuStateToLongString_Z80(c) {
s += (flags & (128>>i)) ? flagspec.slice(i,i+1) : "-";
return s; // TODO
}
- return "PC " + hex(c.PC,4) + " " + decodeFlags(c.AF) + " " + getTIAPosString() + "\n"
+ return "PC " + hex(c.PC,4) + " " + decodeFlags(c.AF) + "\n"
+ "SP " + hex(c.SP,4) + " IR " + hex(c.IR,4) + "\n"
+ "IX " + hex(c.IX,4) + " IY " + hex(c.IY,4) + "\n"
+ "AF " + hex(c.AF,4) + " BC " + hex(c.BC,4) + "\n"
@@ -513,8 +514,6 @@ function cpuStateToLongString_Z80(c) {
;
}
-////// Z80
-
var BaseZ80Platform = function() {
var onBreakpointHit;
@@ -536,8 +535,8 @@ var BaseZ80Platform = function() {
this.restartDebugState = function() {
if (debugCondition && !debugBreakState && debugTargetClock > 0) {
debugSavedState = this.saveState();
- debugTargetClock -= debugSavedState.c.tstates;
- debugSavedState.c.tstates = 0;
+ debugTargetClock -= debugSavedState.c.T;
+ debugSavedState.c.T = 0;
this.loadState(debugSavedState);
}
}
@@ -554,10 +553,11 @@ var BaseZ80Platform = function() {
onBreakpointHit = null;
debugCondition = null;
}
- this.breakpointHit = function() {
+ this.breakpointHit = function(targetClock) {
+ debugTargetClock = targetClock;
debugBreakState = this.saveState();
//debugBreakState.c.PC = (debugBreakState.c.PC-1) & 0xffff;
- console.log("Breakpoint at clk", debugBreakState.c.tstates, "PC", debugBreakState.c.PC.toString(16));
+ console.log("Breakpoint at clk", debugBreakState.c.T, "PC", debugBreakState.c.PC.toString(16));
this.pause();
if (onBreakpointHit) {
onBreakpointHit(debugBreakState);
@@ -568,9 +568,8 @@ var BaseZ80Platform = function() {
var self = this;
this.setDebugCondition(function() {
var cpuState = self.getCPUState();
- if (cpuState.tstates > debugTargetClock) {
- debugTargetClock = cpuState.tstates;
- self.breakpointHit();
+ if (cpuState.T > debugTargetClock) {
+ self.breakpointHit(cpuState.T);
return true;
}
return false;
@@ -582,11 +581,10 @@ var BaseZ80Platform = function() {
var prevClock;
this.setDebugCondition(function() {
var cpuState = self.getCPUState();
- var debugClock = cpuState.tstates;
+ var debugClock = cpuState.T;
if (debugClock >= debugTargetClock && prevState) {
self.loadState(prevState);
- debugTargetClock = prevClock;
- self.breakpointHit();
+ self.breakpointHit(prevClock);
return true;
} else if (debugClock > debugTargetClock-20 && debugClock < debugTargetClock) {
prevState = self.saveState();
@@ -599,10 +597,9 @@ var BaseZ80Platform = function() {
var self = this;
this.setDebugCondition(function() {
var cpuState = self.getCPUState();
- if (cpuState.tstates > debugTargetClock) {
+ if (cpuState.T > debugTargetClock) {
if (evalfunc(cpuState)) {
- debugTargetClock = cpuState.tstates;
- self.breakpointHit();
+ self.breakpointHit(cpuState.T);
return true;
}
}
@@ -622,9 +619,6 @@ var BaseZ80Platform = function() {
--depth;
return false;
});
- }
- this.disassemble = function(mem, start, end, pcvisits) {
- return new Disassembler6502().disassemble(mem, start, end, pcvisits);
}
this.cpuStateToLongString = function(c) {
return cpuStateToLongString_Z80(c);
@@ -638,6 +632,171 @@ var BaseZ80Platform = function() {
//this.getOpcodeMetadata = function() { }
}
+////// 6809
+
+function cpuStateToLongString_6809(c) {
+ function decodeFlags(flags) {
+ var flagspec = "SZ-H-VNC";
+ var s = "";
+ for (var i=0; i<8; i++)
+ s += (flags & (128>>i)) ? flagspec.slice(i,i+1) : "-";
+ return s; // TODO
+ }
+ return "PC " + hex(c.PC,4) + " " + decodeFlags(c.CC) + "\n"
+ + "SP " + hex(c.SP,4) + "\n"
+ ;
+}
+
+var Base6809Platform = function() {
+ this.__proto__ = new BaseZ80Platform();
+
+ this.runUntilReturn = function() {
+ var self = this;
+ var depth = 1;
+ self.runEval(function(c) {
+ if (depth <= 0)
+ return true;
+ var op = self.readAddress(c.PC);
+ // TODO: 6809 opcodes
+ if (op == 0xcd) // CALL
+ depth++;
+ else if (op == 0xc0 || op == 0xc8 || op == 0xc9 || op == 0xd0) // RET (TODO?)
+ --depth;
+ return false;
+ });
+ }
+ this.cpuStateToLongString = function(c) {
+ return cpuStateToLongString_6809(c);
+ }
+ this.getToolForFilename = function(fn) {
+ if (fn.endsWith(".c")) return "sdcc";
+ if (fn.endsWith(".s")) return "sdasz80";
+ return "z80asm";
+ }
+ // TODO
+ this.disassemble = function(pc, read) {
+ // TODO: don't create new CPU
+ return new CPU6809().disasm(read(pc), read(pc+1), read(pc+2), read(pc+3), read(pc+4), pc);
+ }
+ //this.getOpcodeMetadata = function() { }
+}
+
+//////////
+
+var Keys = {
+ VK_ESCAPE: {c: 27, n: "Esc"},
+ VK_F1: {c: 112, n: "F1"},
+ VK_F2: {c: 113, n: "F2"},
+ VK_F3: {c: 114, n: "F3"},
+ VK_F4: {c: 115, n: "F4"},
+ VK_F5: {c: 116, n: "F5"},
+ VK_F6: {c: 117, n: "F6"},
+ VK_F7: {c: 118, n: "F7"},
+ VK_F8: {c: 119, n: "F8"},
+ VK_F9: {c: 120, n: "F9"},
+ VK_F10: {c: 121, n: "F10"},
+ VK_F11: {c: 122, n: "F11"},
+ VK_F12: {c: 123, n: "F12"},
+ VK_SCROLL_LOCK: {c: 145, n: "ScrLck"},
+ VK_PAUSE: {c: 19, n: "Pause"},
+ VK_QUOTE: {c: 192, n: "'"},
+ VK_TILDE: {c: 222, n: "~"},
+ VK_1: {c: 49, n: "1"},
+ VK_2: {c: 50, n: "2"},
+ VK_3: {c: 51, n: "3"},
+ VK_4: {c: 52, n: "4"},
+ VK_5: {c: 53, n: "5"},
+ VK_6: {c: 54, n: "6"},
+ VK_7: {c: 55, n: "7"},
+ VK_8: {c: 56, n: "8"},
+ VK_9: {c: 57, n: "9"},
+ VK_0: {c: 48, n: "0"},
+ VK_MINUS: {c: 189, n: "-"},
+ VK_MINUS2: {c: 173, n: "-"},
+ VK_EQUALS: {c: 187, n: "="},
+ VK_EQUALS2: {c: 61, n: "="},
+ VK_BACK_SPACE: {c: 8, n: "Bkspc"},
+ VK_TAB: {c: 9, n: "Tab"},
+ VK_Q: {c: 81, n: "Q"},
+ VK_W: {c: 87, n: "W"},
+ VK_E: {c: 69, n: "E"},
+ VK_R: {c: 82, n: "R"},
+ VK_T: {c: 84, n: "T"},
+ VK_Y: {c: 89, n: "Y"},
+ VK_U: {c: 85, n: "U"},
+ VK_I: {c: 73, n: "I"},
+ VK_O: {c: 79, n: "O"},
+ VK_P: {c: 80, n: "P"},
+ VK_ACUTE: {c: 219, n: "´"},
+ VK_OPEN_BRACKET: {c: 221, n: "["},
+ VK_CLOSE_BRACKET: {c: 220, n: "]"},
+ VK_CAPS_LOCK: {c: 20, n: "CpsLck"},
+ VK_A: {c: 65, n: "A"},
+ VK_S: {c: 83, n: "S"},
+ VK_D: {c: 68, n: "D"},
+ VK_F: {c: 70, n: "F"},
+ VK_G: {c: 71, n: "G"},
+ VK_H: {c: 72, n: "H"},
+ VK_J: {c: 74, n: "J"},
+ VK_K: {c: 75, n: "K"},
+ VK_L: {c: 76, n: "L"},
+ VK_CEDILLA: {c: 186, n: "Ç"},
+ VK_TILDE: {c: 222, n: "~"},
+ VK_ENTER: {c: 13, n: "Enter"},
+ VK_SHIFT: {c: 16, n: "Shift"},
+ VK_BACK_SLASH: {c: 226, n: "\\"},
+ VK_Z: {c: 90, n: "Z"},
+ VK_X: {c: 88, n: "X"},
+ VK_C: {c: 67, n: "C"},
+ VK_V: {c: 86, n: "V"},
+ VK_B: {c: 66, n: "B"},
+ VK_N: {c: 78, n: "N"},
+ VK_M: {c: 77, n: "M"},
+ VK_COMMA: {c: 188, n: "] ="},
+ VK_PERIOD: {c: 190, n: "."},
+ VK_SEMICOLON: {c: 191, n: ";"},
+ VK_SLASH: {c: 193, n: "/"},
+ VK_CONTROL: {c: 17, n: "Ctrl"},
+ VK_ALT: {c: 18, n: "Alt"},
+ VK_SPACE: {c: 32, n: "Space"},
+ VK_INSERT: {c: 45, n: "Ins"},
+ VK_DELETE: {c: 46, n: "Del"},
+ VK_HOME: {c: 36, n: "Home"},
+ VK_END: {c: 35, n: "End"},
+ VK_PAGE_UP: {c: 33, n: "PgUp"},
+ VK_PAGE_DOWN: {c: 34, n: "PgDown"},
+ VK_UP: {c: 38, n: "Up"},
+ VK_DOWN: {c: 40, n: "Down"},
+ VK_LEFT: {c: 37, n: "Left"},
+ VK_RIGHT: {c: 39, n: "Right"},
+ VK_NUM_LOCK: {c: 144, n: "Num"},
+ VK_DIVIDE: {c: 111, n: "Num /"},
+ VK_MULTIPLY: {c: 106, n: "Num *"},
+ VK_SUBTRACT: {c: 109, n: "Num -"},
+ VK_ADD: {c: 107, n: "Num +"},
+ VK_DECIMAL: {c: 194, n: "Num ."},
+ VK_NUMPAD0: {c: 96, n: "Num 0"},
+ VK_NUMPAD1: {c: 97, n: "Num 1"},
+ VK_NUMPAD2: {c: 98, n: "Num 2"},
+ VK_NUMPAD3: {c: 99, n: "Num 3"},
+ VK_NUMPAD4: {c: 100, n: "Num 4"},
+ VK_NUMPAD5: {c: 101, n: "Num 5"},
+ VK_NUMPAD6: {c: 102, n: "Num 6"},
+ VK_NUMPAD7: {c: 103, n: "Num 7"},
+ VK_NUMPAD8: {c: 104, n: "Num 8"},
+ VK_NUMPAD9: {c: 105, n: "Num 9"},
+ VK_NUMPAD_CENTER: {c: 12, n: "Num Cntr"}
+};
+
+function makeKeycodeMap(table) {
+ var map = {};
+ for (var i=0; i=" + start + " && a<="+end + "){";
- s += "a&="+(mask?mask:0xffff)+";";
+ if (mask) s += "a&="+mask+";";
s += "return this.__fn"+i+"(a,v)&0xff;}\n";
}
s += "return 0;"; // TODO: noise()?
diff --git a/src/platform/spaceinv.js b/src/platform/spaceinv.js
index b18efba7..38f7d399 100644
--- a/src/platform/spaceinv.js
+++ b/src/platform/spaceinv.js
@@ -206,12 +206,6 @@ var SpaceInvadersPlatform = function(mainElement) {
}
this.readAddress = function(addr) {
return membus.read(addr);
- }
-
- this.ramStateToLongString = function(state) {
- return "";
- //var stack = state.b.slice(state.c.SP & 0x1fff, 0x400);
- //return "\n" + dumpRAM(stack, state.c.SP, stack.length);
}
}
diff --git a/src/platform/williams.js b/src/platform/williams.js
new file mode 100644
index 00000000..783635e4
--- /dev/null
+++ b/src/platform/williams.js
@@ -0,0 +1,224 @@
+
+"use strict";
+var WILLIAMS_PRESETS = [
+];
+
+var WilliamsPlatform = function(mainElement) {
+ var self = this;
+ this.__proto__ = new Base6809Platform();
+
+ var cpu, ram, membus, iobus, rom, nvram;
+ var video, timer, pixels, displayPCs;
+ var banksel = 0;
+ var watchdog_counter;
+ var video_counter;
+ var pia6821 = [0,0,0,0,0,0,0,0];
+ var screenNeedsRefresh = false;
+
+ var xtal = 12000000;
+ var cpuFrequency = xtal/3/4;
+ var cpuCyclesPerFrame = cpuFrequency/60; // TODO
+ var INITIAL_WATCHDOG = 64;
+ var PIXEL_ON = 0xffeeeeee;
+ var PIXEL_OFF = 0xff000000;
+
+ var KEYCODE_MAP = makeKeycodeMap([
+ [Keys.VK_SPACE, 4, 0x1],
+ [Keys.VK_RIGHT, 4, 0x2],
+ [Keys.VK_Z, 4, 0x4],
+ [Keys.VK_X, 4, 0x8],
+ [Keys.VK_2, 4, 0x10],
+ [Keys.VK_1, 4, 0x20],
+ [Keys.VK_LEFT, 4, 0x40],
+ [Keys.VK_DOWN, 4, 0x80],
+ [Keys.VK_UP, 6, 0x1],
+ [Keys.VK_5, 0, 0x4],
+ [Keys.VK_7, 0, 0x1],
+ [Keys.VK_8, 0, 0x2],
+ [Keys.VK_9, 0, 0x8],
+ ]);
+
+ var palette = [];
+ for (var ii=0; ii<16; ii++)
+ palette[ii] = 0xff000000;
+
+ this.getPresets = function() {
+ return WILLIAMS_PRESETS;
+ }
+
+ var ioread = new AddressDecoder([
+ [0x400, 0x5ff, 0x1ff, function(a) { return nvram.mem[a]; }],
+ [0x800, 0x800, 0, function(a) { return video_counter; }],
+ [0xc00, 0xc07, 0x7, function(a) { return pia6821[a]; }],
+ [0x0, 0xfff, 0, function(a) { console.log('ioread',hex(a)); }],
+ ]);
+
+ var iowrite = new AddressDecoder([
+ [0x0, 0xf, 0xf, function(a,v) {
+ // RRRGGGBB
+ var color = 0xff000000 | ((v&7)<<5) | (((v>>3)&7)<<13) | (((v>>6)<<22));
+ if (color != palette[a]) {
+ palette[a] = color;
+ screenNeedsRefresh = true;
+ }
+ }],
+ [0x3fc, 0x3ff, 0, function(a,v) { if (v == 56) watchdog_counter = INITIAL_WATCHDOG; }], // TODO: check value?
+ [0x400, 0x5ff, 0x1ff, function(a,v) { nvram.mem[a] = v; }],
+ [0xc00, 0xc07, 0x7, function(a,v) { pia6821[a] = v; }],
+ [0x0, 0xfff, 0, function(a,v) { console.log('iowrite',hex(a),hex(v)); }],
+ ]);
+
+ function drawDisplayByte(a,v) {
+ var ofs = ((a&0xff00)<<1) | ((a&0xff)^0xff);
+ pixels[ofs] = palette[v>>4];
+ pixels[ofs+256] = palette[v&0xf];
+ }
+
+ this.start = function() {
+ ram = new RAM(0xc000);
+ nvram = new RAM(0x200);
+ // TODO: save in browser storage?
+ nvram.mem.set([240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,242,241,242,247,240,244,244,245,242,244,250,240,241,248,243,241,245,245,243,244,241,244,253,240,241,245,249,242,240,244,252,244,245,244,244,240,241,244,242,248,245,245,240,244,247,244,244,240,241,242,245,242,240,244,243,245,242,244,242,240,241,241,240,243,245,244,253,245,242,245,243,240,240,248,242,246,245,245,243,245,243,245,242,240,240,246,240,241,240,245,244,244,253,244,248,240,240,245,250,240,241,240,240,240,243,240,243,240,241,240,244,240,241,240,241,240,240,240,240,240,240,240,245,241,245,240,241,240,245,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240]);
+ displayPCs = new Uint16Array(new ArrayBuffer(0x9800*2));
+ rom = padBytes(new lzgmini().decode(DEFENDER_ROM).slice(0), 0x7000);
+ membus = {
+ read: new AddressDecoder([
+ [0x0000, 0xbfff, 0xffff, function(a) { return ram.mem[a]; }],
+ [0xc000, 0xcfff, 0x0fff, function(a) {
+ switch (banksel) {
+ case 0: return ioread(a);
+ case 1: return rom[a+0x3000];
+ case 2: return rom[a+0x4000];
+ case 3: return rom[a+0x5000];
+ case 4:
+ case 5:
+ case 6:
+ case 7: return rom[a+0x6000];
+ default: return 0; // TODO: error light
+ }
+ }],
+ [0xd000, 0xffff, 0xffff, function(a) { return rom ? rom[a-0xd000] : 0; }],
+ ]),
+ write: new AddressDecoder([
+ [0x9800, 0xbfff, 0, function(a,v) { ram.mem[a] = v; }],
+ [0x0000, 0x97ff, 0, function(a,v) {
+ ram.mem[a] = v;
+ drawDisplayByte(a, v);
+ displayPCs[a] = cpu.getPC(); // save program counter
+ }],
+ [0xc000, 0xcfff, 0x0fff, iowrite],
+ [0xd000, 0xdfff, 0, function(a,v) { banksel = v&0x7; }],
+ [0, 0xffff, 0, function(a,v) { console.log(hex(a), hex(v)); }],
+ ]),
+ };
+ cpu = new CPU6809();
+ cpu.init(membus.write, membus.read, 0);
+ video = new RasterVideo(mainElement,256,304,{rotate:-90});
+ video.create();
+ $(video.canvas).click(function(e) {
+ var x = Math.floor(e.offsetX * video.canvas.width / $(video.canvas).width());
+ var y = Math.floor(e.offsetY * video.canvas.height / $(video.canvas).height());
+ var addr = (x>>3) + (y*32) + 0x400;
+ console.log(x, y, hex(addr,4), "PC", hex(displayPCs[addr],4));
+ });
+ var idata = video.getFrameData();
+ video.setKeyboardEvents(function(key,code,flags) {
+ var o = KEYCODE_MAP[key];
+ if (o) {
+ console.log(key,code,flags,o);
+ if (flags & 1) {
+ pia6821[o.index] |= o.mask;
+ } else {
+ pia6821[o.index] &= ~o.mask;
+ }
+ }
+ });
+ pixels = video.getFrameData();
+ timer = new AnimationTimer(60, function() {
+ if (!self.isRunning())
+ return;
+ var debugCond = self.getDebugCallback();
+ // interrupts happen every 1/4 of the screen
+ for (var quarter=0; quarter<4; quarter++) {
+ video_counter = (quarter & 1) ? 0xff : 0x00;
+ if (pia6821[7] == 0x3c) { // TODO?
+ cpu.interrupt();
+ //console.log(cpu.getPC());
+ }
+ var targetTstates = cpu.T() + cpuCyclesPerFrame/4;
+ if (debugCond) {
+ while (cpu.T() < targetTstates) {
+ if (debugCond && debugCond()) {
+ debugCond = null;
+ break;
+ }
+ cpu.steps(1);
+ }
+ } else {
+ cpu.steps(cpuCyclesPerFrame);
+ }
+ }
+ if (screenNeedsRefresh) {
+ for (var i=0; i<0x9800; i++)
+ drawDisplayByte(i, ram.mem[i]);
+ screenNeedsRefresh = false;
+ }
+ video.updateFrame();
+ if (watchdog_counter-- <= 0) {
+ console.log("WATCHDOG FIRED, PC =", cpu.getPC().toString(16)); // TODO: alert on video
+ // TODO: self.breakpointHit(cpu.T());
+ self.reset();
+ }
+ self.restartDebugState();
+ });
+ }
+
+ this.loadROM = function(title, data) {
+ // TODO
+ self.reset();
+ }
+
+ this.loadState = function(state) {
+ cpu.loadState(state.c);
+ ram.mem.set(state.b);
+ nvram.mem.set(state.nvram);
+ watchdog_counter = state.wdc;
+ banksel = state.bs;
+ pia6821 = state.pia;
+ }
+ this.saveState = function() {
+ return {
+ c:self.getCPUState(),
+ b:ram.mem.slice(0),
+ nvram:nvram.mem.slice(0),
+ wdc:watchdog_counter,
+ bs:banksel,
+ pia:pia6821,
+ };
+ }
+ this.getRAMForState = function(state) {
+ return ram.mem;
+ }
+ this.getCPUState = function() {
+ return cpu.saveState();
+ }
+
+ this.isRunning = function() {
+ return timer.isRunning();
+ }
+ this.pause = function() {
+ timer.stop();
+ }
+ this.resume = function() {
+ timer.start();
+ }
+ this.reset = function() {
+ cpu.reset();
+ watchdog_counter = INITIAL_WATCHDOG;
+ }
+ this.readAddress = function(addr) {
+ return membus.read(addr);
+ }
+}
+
+PLATFORMS['williams'] = WilliamsPlatform;
diff --git a/src/ui.js b/src/ui.js
index 3938b0bf..25e2d5bb 100644
--- a/src/ui.js
+++ b/src/ui.js
@@ -418,13 +418,6 @@ function setCurrentLine(line) {
editor.setSelection({line:line,ch:0}, {line:line-1,ch:0}, {scroll:true});
}
-function getTIAPosString() {
- if (platform.getRasterPosition) {
- var pos = platform.getRasterPosition();
- return "V" + pos.y + " H" + pos.x;
- } else return "";
-}
-
var lastDebugInfo;
var lastDebugState;
@@ -458,6 +451,10 @@ function showMemory(state) {
var s = "";
if (state) {
s = platform.cpuStateToLongString(state.c);
+ if (platform.getRasterPosition) {
+ var pos = platform.getRasterPosition();
+ s += "H:" + pos.x + " V:" + pos.y + "\n"; // TODO: padding
+ }
if (platform.ramStateToLongString) {
s += platform.ramStateToLongString(state);
}
@@ -739,7 +736,6 @@ function updateDisassembly() {
var div = $("#disassembly");
if (div.is(':visible')) {
var state = lastDebugState || platform.saveState();
- var mem = state.b;
var pc = state.c.PC;
if (assemblyfile && assemblyfile.text) {
disasmview.setValue(assemblyfile.text);
@@ -752,28 +748,29 @@ function updateDisassembly() {
}
return;
}
- var gutters = [];
+ var curline = 0;
var selline = 0;
// TODO: not perfect disassembler
function disassemble(start, end) {
if (start < 0) start = 0;
- if (end > mem.length) end = mem.length;
- // TODO: use platform.readMemory()
- var disasm = platform.disassemble(mem, start, end, pcvisits);
+ if (end > 0xffff) end = 0xffff;
+ // TODO: use pc2visits
+ var a = start;
var s = "";
- for (a in disasm) {
+ while (a < end) {
+ var disasm = platform.disassemble(a, platform.readAddress);
var srclinenum = sourcefile.offset2line[a];
if (srclinenum) {
var srcline = editor.getLine(srclinenum-1);
if (srcline && srcline.trim().length) {
s += "; " + srclinenum + ":\t" + srcline + "\n";
- gutters.push([a]);
}
}
- var dline = hex(parseInt(a)) + "\t" + disasm[a] + "\n";
+ var dline = hex(parseInt(a)) + "\t" + disasm.line + "\n";
s += dline;
- if (a == pc) selline = gutters.length;
- gutters.push([]);
+ if (a == pc) selline = curline;
+ curline++;
+ a += disasm.nbytes;
}
return s;
}