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>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; }