diff --git a/src/cpu/ZilogZ80.ts b/src/cpu/ZilogZ80.ts new file mode 100644 index 00000000..ba41e46e --- /dev/null +++ b/src/cpu/ZilogZ80.ts @@ -0,0 +1,1747 @@ +// Generated by CoffeeScript 1.9.3 + +import { CPU, Bus, InstructionBased, IOBusConnected, SavesState, Interruptable } from "../devices"; + +/* +Z80 core. +To avoid mass repetition of code across the numerous instruction variants +the code for this component is built up programmatically and evaluated in +the global scope. CoffeeScript is used here for its support of multi-line +strings, and expression interpolation in strings. + */ + + +/* +Registers are stored in a typed array as a way of automatically casting +calculations to 8/16 bit, and to allow accessing them interchangeably as +register pairs or individual registers by having two arrays backed by the +same buffer. For the latter to work, we need to find out the endianness +of the host processor, as typed arrays are native-endian + (http://lists.w3.org/Archives/Public/public-script-coord/2010AprJun/0048.html, + http://cat-in-136.blogspot.com/2011/03/javascript-typed-array-use-native.html) + */ + +var buildZ80 = function(opts) { + var ADC_A, ADC_HL_RR, ADD_A, ADD_RR_RR, AND_A, BIT_N_R, BIT_N_iHLi, BIT_N_iRRpNNi, CALL_C_NN, CALL_NN, CCF, CPD, CPDR, CPI, CPIR, CPIR_CPDR, CPI_CPD, CPL, CP_A, DAA, DEC, DEC_RR, DI, DJNZ_N, EI, EXX, EX_RR_RR, EX_iSPi_RR, FLAG_3, FLAG_5, FLAG_C, FLAG_H, FLAG_N, FLAG_P, FLAG_S, FLAG_V, FLAG_Z, HALT, IM, INC, INC_RR, IND, INDR, INI, INIR, INIR_INDR, INI_IND, IN_A_N, IN_F_iCi, IN_R_iCi, JP_C_NN, JP_NN, JP_RR, JR_C_N, JR_N, LDBITOP, LDD, LDDR, LDI, LDIR, LDIR_LDDR, LDI_LDD, LDSHIFTOP, LD_A_iNNi, LD_RR_NN, LD_RR_RR, LD_RR_iNNi, LD_R_N, LD_R_R, LD_R_iRRi, LD_R_iRRpNNi, LD_iNNi_A, LD_iNNi_RR, LD_iRRi_N, LD_iRRi_R, LD_iRRpNNi_N, LD_iRRpNNi_R, NEG, NOP, OPCODE_RUN_STRINGS, OPCODE_RUN_STRINGS_CB, OPCODE_RUN_STRINGS_DD, OPCODE_RUN_STRINGS_DDCB, OPCODE_RUN_STRINGS_ED, OPCODE_RUN_STRINGS_FD, OPCODE_RUN_STRINGS_FDCB, OR_A, OTDR, OTIR, OTIR_OTDR, OUTD, OUTI, OUTI_OUTD, OUT_iCi_0, OUT_iCi_R, OUT_iNi_A, POP_RR, PUSH_RR, RES, RET, RETN, RET_C, RL, RLA, RLC, RLCA, RLD, RR, RRA, RRC, RRCA, RRD, RST, SBC_A, SBC_HL_RR, SCF, SET, SHIFT, SLA, SLL, SRA, SRL, SUB_A, XOR_A, defineZ80JS, endianTestBuffer, endianTestUint16, endianTestUint8, generateddfdOpcodeSet, generateddfdcbOpcodeSet, getParamBoilerplate, indirectEval, isBigEndian, opcodeSwitch, rA, rA_, rB, rB_, rC, rC_, rD, rD_, rE, rE_, rF, rF_, rH, rH_, rI, rIXH, rIXL, rIYH, rIYL, rL, rL_, rR, registerIndexes, registerPairIndexes, rpAF, rpAF_, rpBC, rpBC_, rpDE, rpDE_, rpHL, rpHL_, rpIR, rpIX, rpIY, rpPC, rpSP, setUpStateJS; + if (opts == null) { + opts = {}; + } + endianTestBuffer = new ArrayBuffer(2); + endianTestUint16 = new Uint16Array(endianTestBuffer); + endianTestUint8 = new Uint8Array(endianTestBuffer); + endianTestUint16[0] = 0x0100; + isBigEndian = endianTestUint8[0] === 0x01; + rpAF = 0; + rpBC = 1; + rpDE = 2; + rpHL = 3; + rpAF_ = 4; + rpBC_ = 5; + rpDE_ = 6; + rpHL_ = 7; + rpIX = 8; + rpIY = 9; + rpIR = 10; + rpSP = 11; + rpPC = 12; + registerPairIndexes = { + 'IX': 8, + 'IY': 9 + }; + if (isBigEndian) { + rA = 0; + rF = 1; + rB = 2; + rC = 3; + rD = 4; + rE = 5; + rH = 6; + rL = 7; + rA_ = 8; + rF_ = 9; + rB_ = 10; + rC_ = 11; + rD_ = 12; + rE_ = 13; + rH_ = 14; + rL_ = 15; + rIXH = 16; + rIXL = 17; + rIYH = 18; + rIYL = 19; + rI = 20; + rR = 21; + registerIndexes = { + A: 0, + F: 1, + B: 2, + C: 3, + D: 4, + E: 5, + H: 6, + L: 7, + IXH: 16, + IXL: 17, + IYH: 18, + IYL: 19 + }; + } else { + rF = 0; + rA = 1; + rC = 2; + rB = 3; + rE = 4; + rD = 5; + rL = 6; + rH = 7; + rF_ = 8; + rA_ = 9; + rC_ = 10; + rB_ = 11; + rE_ = 12; + rD_ = 13; + rL_ = 14; + rH_ = 15; + rIXL = 16; + rIXH = 17; + rIYL = 18; + rIYH = 19; + rR = 20; + rI = 21; + registerIndexes = { + F: 0, + A: 1, + C: 2, + B: 3, + E: 4, + D: 5, + L: 6, + H: 7, + IXL: 16, + IXH: 17, + IYL: 18, + IYH: 19 + }; + } + FLAG_C = 0x01; + FLAG_N = 0x02; + FLAG_P = 0x04; + FLAG_V = 0x04; + FLAG_3 = 0x08; + FLAG_H = 0x10; + FLAG_5 = 0x20; + FLAG_Z = 0x40; + FLAG_S = 0x80; + setUpStateJS = "var memory = opts.memory;\nvar ioBus = opts.ioBus;\nvar display = opts.display;\n\nvar registerBuffer = new ArrayBuffer(26);\n/* Expose registerBuffer as both register pairs and individual registers */\nvar regPairs = new Uint16Array(registerBuffer);\nvar regs = new Uint8Array(registerBuffer);\n\nvar tstates = 0; /* number of tstates since start of this frame */\nvar iff1 = 0;\nvar iff2 = 0;\nvar im = 0;\nvar halted = false;\n\n/* tables for setting Z80 flags */\n\n/*\n Whether a half carry occurred or not can be determined by looking at\n the 3rd bit of the two arguments and the result; these are hashed\n into this table in the form r12, where r is the 3rd bit of the\n result, 1 is the 3rd bit of the 1st argument and 2 is the\n third bit of the 2nd argument; the tables differ for add and subtract\n operations\n*/\nvar halfcarryAddTable = new Uint8Array([0, " + FLAG_H + ", " + FLAG_H + ", " + FLAG_H + ", 0, 0, 0, " + FLAG_H + "]);\nvar halfcarrySubTable = new Uint8Array([0, 0, " + FLAG_H + ", 0, " + FLAG_H + ", 0, " + FLAG_H + ", " + FLAG_H + "]);\n\n/*\n Similarly, overflow can be determined by looking at the 7th bits; again\n the hash into this table is r12\n*/\nvar overflowAddTable = new Uint8Array([0, 0, 0, " + FLAG_V + ", " + FLAG_V + ", 0, 0, 0]);\nvar overflowSubTable = new Uint8Array([0, " + FLAG_V + ", 0, 0, 0, 0, " + FLAG_V + ", 0]);\n\nvar sz53Table = new Uint8Array(0x100); /* The S, Z, 5 and 3 bits of the index */\nvar parityTable = new Uint8Array(0x100); /* The parity of the lookup value */\nvar sz53pTable = new Uint8Array(0x100); /* OR the above two tables together */\n\nfor (var i = 0; i < 0x100; i++) {\n sz53Table[i] = i & ( " + (FLAG_3 | FLAG_5 | FLAG_S) + " );\n var j = i;\n var parity = 0;\n for (var k = 0; k < 8; k++) {\n parity ^= j & 1;\n j >>=1;\n }\n\n parityTable[i] = (parity ? 0 : " + FLAG_P + ");\n sz53pTable[i] = sz53Table[i] | parityTable[i];\n\n sz53Table[0] |= " + FLAG_Z + ";\n sz53pTable[0] |= " + FLAG_Z + ";\n}\n\nvar interruptible = true;\nvar interruptPending = false;\nvar interruptDataBus = 0;\nvar opcodePrefix = '';"; + + /* + Boilerplate generator: a helper to deal with classes of opcodes which perform + the same task on different types of operands: e.g. XOR B, XOR (HL), XOR nn, XOR (IX+nn). + This function accepts the parameter in question, and returns a set of canned strings + for use in the opcode runner body: + 'getter': a block of code that performs any necessary memory access etc in order to + make 'v' a valid expression; + 'v': an expression with no side effects, evaluating to the operand's value. (Must also be a valid lvalue for assignment) + 'trunc': an expression such as '& 0xff' to truncate v back to its proper range, if appropriate + 'setter': a block of code that writes an updated value back to its proper location, if any + + Passing hasIXOffsetAlready = true indicates that we have already read the offset value of (IX+nn)/(IY+nn) + into a variable 'offset' (necessary because DDCB/FFCB instructions put this before the final opcode byte). + */ + getParamBoilerplate = function(param, hasIXOffsetAlready) { + var getter, match, regNum, rp; + if (hasIXOffsetAlready == null) { + hasIXOffsetAlready = false; + } + if (param.match(/^[AFBCDEHL]|I[XY][HL]$/)) { + regNum = registerIndexes[param]; + return { + 'getter': '', + 'v': "regs[" + regNum + "]", + 'trunc': '', + 'setter': '' + }; + } else if (param === '(HL)') { + return { + 'getter': "var val = READMEM(regPairs[" + rpHL + "]);", + 'v': 'val', + 'trunc': '& 0xff', + 'setter': "CONTEND_READ_NO_MREQ(regPairs[" + rpHL + "], 1);\nWRITEMEM(regPairs[" + rpHL + "], val);" + }; + } else if (param === 'nn') { + return { + 'getter': "var val = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;", + 'v': 'val', + 'trunc': '& 0xff', + 'setter': '' + }; + } else if ((match = param.match(/^\((I[XY])\+nn\)$/))) { + rp = registerPairIndexes[match[1]]; + if (hasIXOffsetAlready) { + getter = ''; + } else { + getter = "var offset = READMEM(regPairs[" + rpPC + "]);\nif (offset & 0x80) offset -= 0x100;\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nregPairs[" + rpPC + "]++;"; + } + getter += "var addr = (regPairs[" + rp + "] + offset) & 0xffff;\nvar val = READMEM(addr);"; + return { + 'getter': getter, + 'v': 'val', + 'trunc': '& 0xff', + 'setter': "CONTEND_READ_NO_MREQ(addr, 1);\nWRITEMEM(addr, val);" + }; + } else if (param === 'add') { + return { + 'getter': '', + 'v': 'add', + 'trunc': '', + 'setter': '' + }; + } else { + throw "Unknown param format: " + param; + } + }; + + /* + Opcode generator functions: each returns a string of Javascript that performs the opcode + when executed within this module's scope. Note that instructions with DDCBnn opcodes also + require an 'offset' variable to be defined as nn (as a signed byte). + */ + ADC_A = function(param) { + var operand; + operand = getParamBoilerplate(param); + return operand.getter + "\n\nvar adctemp = regs[" + rA + "] + " + operand.v + " + (regs[" + rF + "] & " + FLAG_C + ");\nvar lookup = ( (regs[" + rA + "] & 0x88) >> 3 ) | ( (" + operand.v + " & 0x88) >> 2 ) | ( (adctemp & 0x88) >> 1 );\nregs[" + rA + "] = adctemp;\nregs[" + rF + "] = ( adctemp & 0x100 ? " + FLAG_C + " : 0 ) | halfcarryAddTable[lookup & 0x07] | overflowAddTable[lookup >> 4] | sz53Table[regs[" + rA + "]];"; + }; + ADC_HL_RR = function(rp2) { + return "var add16temp = regPairs[" + rpHL + "] + regPairs[" + rp2 + "] + (regs[" + rF + "] & " + FLAG_C + ");\nvar lookup = (\n ( (regPairs[" + rpHL + "] & 0x8800) >> 11 ) |\n ( (regPairs[" + rp2 + "] & 0x8800) >> 10 ) |\n ( (add16temp & 0x8800) >> 9 )\n);\nregPairs[" + rpHL + "] = add16temp;\nregs[" + rF + "] = (\n (add16temp & 0x10000 ? " + FLAG_C + " : 0) |\n overflowAddTable[lookup >> 4] |\n (regs[" + rH + "] & " + (FLAG_3 | FLAG_5 | FLAG_S) + ") |\n halfcarryAddTable[lookup & 0x07] |\n (regPairs[" + rpHL + "] ? 0 : " + FLAG_Z + ")\n);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);"; + }; + ADD_A = function(param) { + var operand; + operand = getParamBoilerplate(param); + return operand.getter + "\n\nvar addtemp = regs[" + rA + "] + " + operand.v + ";\nvar lookup = ( (regs[" + rA + "] & 0x88) >> 3 ) | ( (" + operand.v + " & 0x88) >> 2 ) | ( (addtemp & 0x88) >> 1 );\nregs[" + rA + "] = addtemp;\nregs[" + rF + "] = ( addtemp & 0x100 ? " + FLAG_C + " : 0 ) | halfcarryAddTable[lookup & 0x07] | overflowAddTable[lookup >> 4] | sz53Table[regs[" + rA + "]];"; + }; + ADD_RR_RR = function(rp1, rp2) { + return "var add16temp = regPairs[" + rp1 + "] + regPairs[" + rp2 + "];\nvar lookup = ( (regPairs[" + rp1 + "] & 0x0800) >> 11 ) | ( (regPairs[" + rp2 + "] & 0x0800) >> 10 ) | ( (add16temp & 0x0800) >> 9 );\nregPairs[" + rp1 + "] = add16temp;\nregs[" + rF + "] = ( regs[" + rF + "] & ( " + (FLAG_V | FLAG_Z | FLAG_S) + " ) ) | ( add16temp & 0x10000 ? " + FLAG_C + " : 0 ) | ( ( add16temp >> 8 ) & ( " + (FLAG_3 | FLAG_5) + " ) ) | halfcarryAddTable[lookup];\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);"; + }; + AND_A = function(param) { + var operand; + operand = getParamBoilerplate(param); + return operand.getter + "\n\nregs[" + rA + "] &= " + operand.v + ";\nregs[" + rF + "] = " + FLAG_H + " | sz53pTable[regs[" + rA + "]];"; + }; + BIT_N_iRRpNNi = function(bit, rp) { + var updateSignFlag; + if (bit === 7) { + updateSignFlag = "if (value & 0x80) regs[" + rF + "] |= " + FLAG_S + ";"; + } else { + updateSignFlag = ""; + } + return "var addr = (regPairs[" + rp + "] + offset) & 0xffff;\nvar value = READMEM(addr);\nregs[" + rF + "] = ( regs[" + rF + "] & " + FLAG_C + " ) | " + FLAG_H + " | ( ( addr >> 8 ) & " + (FLAG_3 | FLAG_5) + " );\nif ( !(value & " + (0x01 << bit) + ") ) regs[" + rF + "] |= " + (FLAG_P | FLAG_Z) + ";\n" + updateSignFlag + "\nCONTEND_READ_NO_MREQ(addr, 1);"; + }; + BIT_N_iHLi = function(bit) { + var updateSignFlag; + if (bit === 7) { + updateSignFlag = "if (value & 0x80) regs[" + rF + "] |= " + FLAG_S + ";"; + } else { + updateSignFlag = ""; + } + return "var addr = regPairs[" + rpHL + "];\nvar value = READMEM(addr);\nCONTEND_READ_NO_MREQ(addr, 1);\nregs[" + rF + "] = ( regs[" + rF + "] & " + FLAG_C + " ) | " + FLAG_H + " | ( value & " + (FLAG_3 | FLAG_5) + " );\nif( !(value & " + (0x01 << bit) + ") ) regs[" + rF + "] |= " + (FLAG_P | FLAG_Z) + ";\n" + updateSignFlag; + }; + BIT_N_R = function(bit, r) { + var updateSignFlag; + if (bit === 7) { + updateSignFlag = "if (regs[" + r + "] & 0x80) regs[" + rF + "] |= " + FLAG_S + ";"; + } else { + updateSignFlag = ""; + } + return "regs[" + rF + "] = ( regs[" + rF + "] & " + FLAG_C + " ) | " + FLAG_H + " | ( regs[" + r + "] & " + (FLAG_3 | FLAG_5) + " );\nif( !(regs[" + r + "] & " + (0x01 << bit) + ") ) regs[" + rF + "] |= " + (FLAG_P | FLAG_Z) + ";\n" + updateSignFlag; + }; + CALL_C_NN = function(flag, sense) { + var condition; + condition = "regs[" + rF + "] & " + flag; + if (!sense) { + condition = "!(" + condition + ")"; + } + return "if (" + condition + ") {\n var l = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n var h = READMEM(regPairs[" + rpPC + "]);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n regPairs[" + rpPC + "]++;\n regPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rpPC + "] >> 8);\n regPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rpPC + "] & 0xff);\n regPairs[" + rpPC + "] = (h<<8) | l;\n} else {\n CONTEND_READ(regPairs[" + rpPC + "], 3);\n regPairs[" + rpPC + "]++;\n CONTEND_READ(regPairs[" + rpPC + "], 3);\n regPairs[" + rpPC + "]++;\n}"; + }; + CALL_NN = function() { + return "var l = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar h = READMEM(regPairs[" + rpPC + "]);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nregPairs[" + rpPC + "]++;\nregPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rpPC + "] >> 8);\nregPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rpPC + "] & 0xff);\nregPairs[" + rpPC + "] = (h<<8) | l;"; + }; + CCF = function() { + return "regs[" + rF + "] = ( regs[" + rF + "] & " + (FLAG_P | FLAG_Z | FLAG_S) + " ) | ( (regs[" + rF + "] & " + FLAG_C + ") ? " + FLAG_H + " : " + FLAG_C + " ) | ( regs[" + rA + "] & " + (FLAG_3 | FLAG_5) + " );"; + }; + CP_A = function(param) { + var operand; + operand = getParamBoilerplate(param); + return operand.getter + "\n\nvar cptemp = regs[" + rA + "] - " + operand.v + ";\nvar lookup = ( (regs[" + rA + "] & 0x88) >> 3 ) | ( (" + operand.v + " & 0x88) >> 2 ) | ( (cptemp & 0x88) >> 1 );\nregs[" + rF + "] = ( cptemp & 0x100 ? " + FLAG_C + " : ( cptemp ? 0 : " + FLAG_Z + " ) ) | " + FLAG_N + " | halfcarrySubTable[lookup & 0x07] | overflowSubTable[lookup >> 4] | ( " + operand.v + " & " + (FLAG_3 | FLAG_5) + " ) | ( cptemp & " + FLAG_S + " );"; + }; + CPI_CPD = function(modifier) { + return "var value = READMEM(regPairs[" + rpHL + "]);\nvar bytetemp = (regs[" + rA + "] - value) & 0xff;\nvar lookup = ((regs[" + rA + "] & 0x08) >> 3) | ((value & 0x08) >> 2) | ((bytetemp & 0x08) >> 1);\nvar originalHL = regPairs[" + rpHL + "];\nCONTEND_READ_NO_MREQ(originalHL, 1);\nCONTEND_READ_NO_MREQ(originalHL, 1);\nCONTEND_READ_NO_MREQ(originalHL, 1);\nCONTEND_READ_NO_MREQ(originalHL, 1);\nCONTEND_READ_NO_MREQ(originalHL, 1);\nregPairs[" + rpHL + "]" + modifier + "; regPairs[" + rpBC + "]--;\nregs[" + rF + "] = (regs[" + rF + "] & " + FLAG_C + ") | (regPairs[" + rpBC + "] ? " + (FLAG_V | FLAG_N) + " : " + FLAG_N + ") | halfcarrySubTable[lookup] | (bytetemp ? 0 : " + FLAG_Z + ") | (bytetemp & " + FLAG_S + ");\nif (regs[" + rF + "] & " + FLAG_H + ") bytetemp--;\nregs[" + rF + "] |= (bytetemp & " + FLAG_3 + ") | ( (bytetemp & 0x02) ? " + FLAG_5 + " : 0 );"; + }; + CPIR_CPDR = function(modifier) { + return (CPI_CPD(modifier)) + "\nif ((regs[" + rF + "] & " + (FLAG_V | FLAG_Z) + ") == " + FLAG_V + ") {\n regPairs[" + rpPC + "] -= 2;\n CONTEND_READ_NO_MREQ(originalHL, 1);\n CONTEND_READ_NO_MREQ(originalHL, 1);\n CONTEND_READ_NO_MREQ(originalHL, 1);\n CONTEND_READ_NO_MREQ(originalHL, 1);\n CONTEND_READ_NO_MREQ(originalHL, 1);\n}"; + }; + CPD = function() { + return CPI_CPD('--'); + }; + CPI = function() { + return CPI_CPD('++'); + }; + CPDR = function() { + return CPIR_CPDR('--'); + }; + CPIR = function() { + return CPIR_CPDR('++'); + }; + DAA = function() { + var addClause, subClause; + subClause = SUB_A('add'); + addClause = ADD_A('add'); + return "var add = 0;\nvar carry = regs[" + rF + "] & " + FLAG_C + ";\nif( ( regs[" + rF + "] & " + FLAG_H + " ) || ( ( regs[" + rA + "] & 0x0f ) > 9 ) ) add = 6;\nif( carry || ( regs[" + rA + "] > 0x99 ) ) add |= 0x60;\nif( regs[" + rA + "] > 0x99 ) carry = " + FLAG_C + ";\nif( regs[" + rF + "] & " + FLAG_N + " ) {\n " + subClause + "\n} else {\n " + addClause + "\n}\nregs[" + rF + "] = ( regs[" + rF + "] & " + (~(FLAG_C | FLAG_P)) + " ) | carry | parityTable[regs[" + rA + "]];"; + }; + CPL = function() { + return "regs[" + rA + "] ^= 0xff;\nregs[" + rF + "] = (regs[" + rF + "] & " + (FLAG_C | FLAG_P | FLAG_Z | FLAG_S) + ") | (regs[" + rA + "] & " + (FLAG_3 | FLAG_5) + ") | " + (FLAG_N | FLAG_H) + ";"; + }; + DEC = function(param) { + var operand; + operand = getParamBoilerplate(param); + return operand.getter + "\n\nregs[" + rF + "] = (regs[" + rF + "] & " + FLAG_C + " ) | ( " + operand.v + " & 0x0f ? 0 : " + FLAG_H + " ) | " + FLAG_N + ";\n" + operand.v + " = (" + operand.v + " - 1) " + operand.trunc + ";\n\n" + operand.setter + "\nregs[" + rF + "] |= (" + operand.v + " == 0x7f ? " + FLAG_V + " : 0) | sz53Table[" + operand.v + "];"; + }; + DEC_RR = function(rp) { + return "regPairs[" + rp + "]--;\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);"; + }; + DI = function() { + return "iff1 = iff2 = 0;"; + }; + DJNZ_N = function() { + return "CONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nregs[" + rB + "]--;\nif (regs[" + rB + "]) {\n /* take branch */\n var offset = READMEM(regPairs[" + rpPC + "]);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n regPairs[" + rpPC + "]++;\n regPairs[" + rpPC + "] += (offset & 0x80 ? offset - 0x100 : offset);\n} else {\n /* do not take branch */\n CONTEND_READ(regPairs[" + rpPC + "], 3);\n regPairs[" + rpPC + "]++;\n}"; + }; + EI = function() { + return "iff1 = iff2 = 1;\ninterruptible = false;"; + }; + EX_iSPi_RR = function(rp) { + return "var l = READMEM(regPairs[" + rpSP + "]);\nvar spPlus1 = (regPairs[" + rpSP + "] + 1) & 0xffff;\nvar h = READMEM(spPlus1);\nCONTEND_READ_NO_MREQ(spPlus1, 1);\nWRITEMEM(spPlus1, regPairs[" + rp + "] >> 8);\nWRITEMEM(regPairs[" + rpSP + "], regPairs[" + rp + "] & 0xff);\nregPairs[" + rp + "] = (h<<8) | l;\nCONTEND_WRITE_NO_MREQ(regPairs[" + rpSP + "], 1);\nCONTEND_WRITE_NO_MREQ(regPairs[" + rpSP + "], 1);"; + }; + EX_RR_RR = function(rp1, rp2) { + return "var temp = regPairs[" + rp1 + "];\nregPairs[" + rp1 + "] = regPairs[" + rp2 + "];\nregPairs[" + rp2 + "] = temp;"; + }; + EXX = function() { + return "var wordtemp;\nwordtemp = regPairs[" + rpBC + "]; regPairs[" + rpBC + "] = regPairs[" + rpBC_ + "]; regPairs[" + rpBC_ + "] = wordtemp;\nwordtemp = regPairs[" + rpDE + "]; regPairs[" + rpDE + "] = regPairs[" + rpDE_ + "]; regPairs[" + rpDE_ + "] = wordtemp;\nwordtemp = regPairs[" + rpHL + "]; regPairs[" + rpHL + "] = regPairs[" + rpHL_ + "]; regPairs[" + rpHL_ + "] = wordtemp;"; + }; + HALT = function() { + return "halted = true;\nregPairs[" + rpPC + "]--;"; + }; + IM = function(val) { + return "im = " + val + ";"; + }; + IN_A_N = function() { + return "var val = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar port = (regs[" + rA + "] << 8) | val;\nCONTEND_PORT_EARLY(port);\nregs[" + rA + "] = ioBus.read(port);\nCONTEND_PORT_LATE(port);"; + }; + IN_F_iCi = function() { + return "var port = regPairs[" + rpBC + "];\nCONTEND_PORT_EARLY(port);\nvar result = ioBus.read(port);\nCONTEND_PORT_LATE(port);\nregs[" + rF + "] = (regs[" + rF + "] & " + FLAG_C + ") | sz53pTable[result];"; + }; + IN_R_iCi = function(r) { + return "var port = regPairs[" + rpBC + "];\nCONTEND_PORT_EARLY(port);\nregs[" + r + "] = ioBus.read(port);\nCONTEND_PORT_LATE(port);\nregs[" + rF + "] = (regs[" + rF + "] & " + FLAG_C + ") | sz53pTable[regs[" + r + "]];"; + }; + INC = function(param) { + var operand; + operand = getParamBoilerplate(param); + return operand.getter + "\n\nregs[" + rF + "] = (regs[" + rF + "] & " + FLAG_C + ") | (" + operand.v + " & 0x0f ? 0 : " + FLAG_H + ") | " + FLAG_N + ";\n" + operand.v + " = (" + operand.v + " + 1) " + operand.trunc + ";\n\n" + operand.setter + "\nregs[" + rF + "] = (regs[" + rF + "] & " + FLAG_C + ") | ( " + operand.v + " == 0x80 ? " + FLAG_V + " : 0 ) | ( " + operand.v + " & 0x0f ? 0 : " + FLAG_H + " ) | sz53Table[" + operand.v + "];"; + }; + INC_RR = function(rp) { + return "regPairs[" + rp + "]++;\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);"; + }; + INI_IND = function(modifier) { + return "CONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_PORT_EARLY(regPairs[" + rpBC + "]);\nvar initemp = ioBus.read(regPairs[" + rpBC + "]);\nCONTEND_PORT_LATE(regPairs[" + rpBC + "]);\nWRITEMEM(regPairs[" + rpHL + "], initemp);\nregs[" + rB + "]--;\nvar originalHL = regPairs[" + rpHL + "];\nregPairs[" + rpHL + "]" + modifier + modifier + ";\nvar initemp2 = (initemp + regs[" + rC + "] " + modifier + " 1) & 0xff;\n\nregs[" + rF + "] = (initemp & 0x80 ? " + FLAG_N + " : 0) | ((initemp2 < initemp) ? " + (FLAG_H | FLAG_C) + " : 0 ) | ( parityTable[ (initemp2 & 0x07) ^ regs[" + rB + "] ] ? " + FLAG_P + " : 0 ) | sz53Table[regs[" + rB + "]];"; + }; + INIR_INDR = function(modifier) { + return (INI_IND(modifier)) + "\nif (regs[" + rB + "]) {\n CONTEND_WRITE_NO_MREQ(originalHL, 1);\n CONTEND_WRITE_NO_MREQ(originalHL, 1);\n CONTEND_WRITE_NO_MREQ(originalHL, 1);\n CONTEND_WRITE_NO_MREQ(originalHL, 1);\n CONTEND_WRITE_NO_MREQ(originalHL, 1);\n regPairs[" + rpPC + "] -= 2;\n}"; + }; + INI = function() { + return INI_IND('+'); + }; + IND = function() { + return INI_IND('-'); + }; + INIR = function() { + return INIR_INDR('+'); + }; + INDR = function() { + return INIR_INDR('-'); + }; + JP_C_NN = function(flag, sense) { + var condition; + condition = "regs[" + rF + "] & " + flag; + if (!sense) { + condition = "!(" + condition + ")"; + } + return "if (" + condition + ") {\n var l = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n var h = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\n regPairs[" + rpPC + "] = (h<<8) | l;\n} else {\n CONTEND_READ(regPairs[" + rpPC + "], 3);\n regPairs[" + rpPC + "]++;\n CONTEND_READ(regPairs[" + rpPC + "], 3);\n regPairs[" + rpPC + "]++;\n}"; + }; + JP_RR = function(rp) { + return "regPairs[" + rpPC + "] = regPairs[" + rp + "];"; + }; + JP_NN = function() { + return "var l = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar h = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nregPairs[" + rpPC + "] = (h<<8) | l;"; + }; + JR_C_N = function(flag, sense) { + var condition; + condition = "regs[" + rF + "] & " + flag; + if (!sense) { + condition = "!(" + condition + ")"; + } + return "if (" + condition + ") {\n var offset = READMEM(regPairs[" + rpPC + "]);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\n regPairs[" + rpPC + "]++;\n regPairs[" + rpPC + "] += (offset & 0x80 ? offset - 0x100 : offset);\n} else {\n CONTEND_READ(regPairs[" + rpPC + "], 3);\n regPairs[" + rpPC + "]++; /* skip past offset byte */\n}"; + }; + JR_N = function() { + return "var offset = READMEM(regPairs[" + rpPC + "]);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nregPairs[" + rpPC + "]++;\nregPairs[" + rpPC + "] += (offset & 0x80 ? offset - 0x100 : offset);"; + }; + LD_A_iNNi = function() { + return "var l = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar h = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar addr = (h<<8) | l;\nregs[" + rA + "] = READMEM(addr);"; + }; + LD_iNNi_A = function() { + return "var l = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar h = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar addr = (h<<8) | l;\nWRITEMEM(addr, regs[" + rA + "]);"; + }; + LD_iNNi_RR = function(rp) { + return "var l = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar h = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar addr = (h<<8) | l;\nWRITEMEM(addr, regPairs[" + rp + "] & 0xff);\naddr = (addr + 1) & 0xffff;\nWRITEMEM(addr, regPairs[" + rp + "] >> 8);"; + }; + LD_iRRi_N = function(rp) { + return "var n = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nWRITEMEM(regPairs[" + rp + "], n);"; + }; + LD_iRRi_R = function(rp, r) { + return "WRITEMEM(regPairs[" + rp + "], regs[" + r + "]);"; + }; + LD_iRRpNNi_N = function(rp) { + return "var offset = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nif (offset & 0x80) offset -= 0x100;\nvar addr = (regPairs[" + rp + "] + offset) & 0xffff;\n\nvar val = READMEM(regPairs[" + rpPC + "]);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nregPairs[" + rpPC + "]++;\nWRITEMEM(addr, val);"; + }; + LD_iRRpNNi_R = function(rp, r) { + return "var offset = READMEM(regPairs[" + rpPC + "]);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nregPairs[" + rpPC + "]++;\nif (offset & 0x80) offset -= 0x100;\nvar addr = (regPairs[" + rp + "] + offset) & 0xffff;\n\nWRITEMEM(addr, regs[" + r + "]);"; + }; + LD_R_iRRi = function(r, rp) { + return "regs[" + r + "] = READMEM(regPairs[" + rp + "]);"; + }; + LD_R_iRRpNNi = function(r, rp) { + return "var offset = READMEM(regPairs[" + rpPC + "]);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpPC + "], 1);\nregPairs[" + rpPC + "]++;\nif (offset & 0x80) offset -= 0x100;\nvar addr = (regPairs[" + rp + "] + offset) & 0xffff;\n\nregs[" + r + "] = READMEM(addr);"; + }; + LD_R_N = function(r) { + return "regs[" + r + "] = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;"; + }; + LD_R_R = function(r1, r2) { + var output; + if (r1 === rI || r2 === rI || r1 === rR || r2 === rR) { + output = "CONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nregs[" + r1 + "] = regs[" + r2 + "];"; + if (r1 === rA) { + output += "regs[" + rF + "] = (regs[" + rF + "] & " + FLAG_C + ") | sz53Table[regs[" + rA + "]] | ( iff2 ? " + FLAG_V + " : 0 );"; + } + return output; + } else { + return "regs[" + r1 + "] = regs[" + r2 + "];"; + } + }; + LD_RR_iNNi = function(rp, shifted) { + return "var l = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar h = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar addr = (h<<8) | l;\nl = READMEM(addr);\naddr = (addr + 1) & 0xffff;\nh = READMEM(addr);\nregPairs[" + rp + "] = (h<<8) | l;"; + }; + LD_RR_NN = function(rp) { + return "var l = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nvar h = READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nregPairs[" + rp + "] = (h<<8) | l;"; + }; + LD_RR_RR = function(rp1, rp2) { + return "regPairs[" + rp1 + "] = regPairs[" + rp2 + "];\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);"; + }; + LDBITOP = function(regName, opcode, bit, rp) { + var regNum; + regNum = registerIndexes[regName]; + return "var addr = (regPairs[" + rp + "] + offset) & 0xffff;\nregs[" + regNum + "] = READMEM(addr);\n" + (opcode(bit, regName)) + "\nCONTEND_READ_NO_MREQ(addr, 1);\nWRITEMEM(addr, regs[" + regNum + "]);"; + }; + LDI_LDD = function(modifier) { + return "var bytetemp = READMEM(regPairs[" + rpHL + "]);\nregPairs[" + rpBC + "]--;\nWRITEMEM(regPairs[" + rpDE + "],bytetemp);\nvar originalDE = regPairs[" + rpDE + "];\nregPairs[" + rpDE + "]" + modifier + "; regPairs[" + rpHL + "]" + modifier + ";\nbytetemp = (bytetemp + regs[" + rA + "]) & 0xff;\nregs[" + rF + "] = (regs[" + rF + "] & " + (FLAG_C | FLAG_Z | FLAG_S) + ") | (regPairs[" + rpBC + "] ? " + FLAG_V + " : 0) | (bytetemp & " + FLAG_3 + ") | ((bytetemp & 0x02) ? " + FLAG_5 + " : 0);\nCONTEND_READ_NO_MREQ(originalDE, 1);\nCONTEND_READ_NO_MREQ(originalDE, 1);"; + }; + LDIR_LDDR = function(modifier) { + return (LDI_LDD(modifier)) + "\nif (regPairs[" + rpBC + "]) {\n regPairs[" + rpPC + "]-=2;\n CONTEND_READ_NO_MREQ(originalDE, 1);\n CONTEND_READ_NO_MREQ(originalDE, 1);\n CONTEND_READ_NO_MREQ(originalDE, 1);\n CONTEND_READ_NO_MREQ(originalDE, 1);\n CONTEND_READ_NO_MREQ(originalDE, 1);\n}"; + }; + LDI = function() { + return LDI_LDD('++'); + }; + LDD = function() { + return LDI_LDD('--'); + }; + LDIR = function() { + return LDIR_LDDR('++'); + }; + LDDR = function() { + return LDIR_LDDR('--'); + }; + LDSHIFTOP = function(regName, opcode, rp) { + var regNum; + regNum = registerIndexes[regName]; + return "var addr = (regPairs[" + rp + "] + offset) & 0xffff;\nregs[" + regNum + "] = READMEM(addr);\n" + (opcode(regName)) + "\nCONTEND_READ_NO_MREQ(addr, 1);\nWRITEMEM(addr, regs[" + regNum + "]);"; + }; + NEG = function() { + return "var val = regs[" + rA + "];\nvar subtemp = -val;\nvar lookup = ( (val & 0x88) >> 2 ) | ( (subtemp & 0x88) >> 1 );\nregs[" + rA + "] = subtemp;\nregs[" + rF + "] = ( subtemp & 0x100 ? " + FLAG_C + " : 0 ) | " + FLAG_N + " | halfcarrySubTable[lookup & 0x07] | overflowSubTable[lookup >> 4] | sz53Table[regs[" + rA + "]];"; + }; + NOP = function() { + return " "; + }; + OR_A = function(param) { + var operand; + operand = getParamBoilerplate(param); + return operand.getter + "\n\nregs[" + rA + "] |= " + operand.v + ";\nregs[" + rF + "] = sz53pTable[regs[" + rA + "]];"; + }; + OUT_iCi_0 = function(r) { + return "CONTEND_PORT_EARLY(regPairs[" + rpBC + "]);\nioBus.write(regPairs[" + rpBC + "], 0, tstates);\nCONTEND_PORT_LATE(regPairs[" + rpBC + "]);"; + }; + OUT_iCi_R = function(r) { + return "CONTEND_PORT_EARLY(regPairs[" + rpBC + "]);\nioBus.write(regPairs[" + rpBC + "], regs[" + r + "], tstates);\nCONTEND_PORT_LATE(regPairs[" + rpBC + "]);"; + }; + OUT_iNi_A = function() { + return "var port = (regs[" + rA + "] << 8) | READMEM(regPairs[" + rpPC + "]); regPairs[" + rpPC + "]++;\nCONTEND_PORT_EARLY(port);\nioBus.write(port, regs[" + rA + "], tstates);\nCONTEND_PORT_LATE(port);"; + }; + OUTI_OUTD = function(modifier) { + return "CONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nvar outitemp = READMEM(regPairs[" + rpHL + "]);\nregs[" + rB + "]--; /* This does happen first, despite what the specs say */\nCONTEND_PORT_EARLY(regPairs[" + rpBC + "]);\nioBus.write(regPairs[" + rpBC + "], outitemp, tstates);\nCONTEND_PORT_LATE(regPairs[" + rpBC + "]);\n\nregPairs[" + rpHL + "]" + modifier + ";\noutitemp2 = (outitemp + regs[" + rL + "]) & 0xff;\nregs[" + rF + "] = (outitemp & 0x80 ? " + FLAG_N + " : 0) | ( (outitemp2 < outitemp) ? " + (FLAG_H | FLAG_C) + " : 0) | (parityTable[ (outitemp2 & 0x07) ^ regs[" + rB + "] ] ? " + FLAG_P + " : 0 ) | sz53Table[ regs[" + rB + "] ];"; + }; + OTIR_OTDR = function(modifier) { + return (OUTI_OUTD(modifier)) + "\nif (regs[" + rB + "]) {\n regPairs[" + rpPC + "]-=2;\n CONTEND_READ_NO_MREQ(regPairs[" + rpBC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpBC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpBC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpBC + "], 1);\n CONTEND_READ_NO_MREQ(regPairs[" + rpBC + "], 1);\n}"; + }; + OUTD = function() { + return OUTI_OUTD('--'); + }; + OUTI = function() { + return OUTI_OUTD('++'); + }; + OTDR = function() { + return OTIR_OTDR('--'); + }; + OTIR = function() { + return OTIR_OTDR('++'); + }; + POP_RR = function(rp) { + return "var l = READMEM(regPairs[" + rpSP + "]); regPairs[" + rpSP + "]++;\nvar h = READMEM(regPairs[" + rpSP + "]); regPairs[" + rpSP + "]++;\nregPairs[" + rp + "] = (h<<8) | l;"; + }; + PUSH_RR = function(rp) { + return "CONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nregPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rp + "] >> 8);\nregPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rp + "] & 0xff);"; + }; + RES = function(bit, param) { + var hexMask, operand; + operand = getParamBoilerplate(param, true); + hexMask = 0xff ^ (1 << bit); + return operand.getter + "\n" + operand.v + " &= " + hexMask + ";\n" + operand.setter; + }; + RET = function() { + return "var l = READMEM(regPairs[" + rpSP + "]); regPairs[" + rpSP + "]++;\nvar h = READMEM(regPairs[" + rpSP + "]); regPairs[" + rpSP + "]++;\nregPairs[" + rpPC + "] = (h<<8) | l;"; + }; + RET_C = function(flag, sense) { + var condition; + condition = "regs[" + rF + "] & " + flag; + if (!sense) { + condition = "!(" + condition + ")"; + } + return "CONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nif (" + condition + ") {\n var l = READMEM(regPairs[" + rpSP + "]); regPairs[" + rpSP + "]++;\n var h = READMEM(regPairs[" + rpSP + "]); regPairs[" + rpSP + "]++;\n regPairs[" + rpPC + "] = (h<<8) | l;\n}"; + }; + RETN = function() { + return "iff1 = iff2;\n" + (RET()); + }; + RL = function(param) { + var operand; + operand = getParamBoilerplate(param, true); + return operand.getter + "\nvar rltemp = " + operand.v + ";\n" + operand.v + " = ( (" + operand.v + " << 1) | (regs[" + rF + "] & " + FLAG_C + ") ) " + operand.trunc + ";\nregs[" + rF + "] = ( rltemp >> 7 ) | sz53pTable[" + operand.v + "];\n" + operand.setter; + }; + RLA = function() { + return "var bytetemp = regs[" + rA + "];\nregs[" + rA + "] = (regs[" + rA + "] << 1) | (regs[" + rF + "] & " + FLAG_C + ");\nregs[" + rF + "] = (regs[" + rF + "] & " + (FLAG_P | FLAG_Z | FLAG_S) + ") | (regs[" + rA + "] & " + (FLAG_3 | FLAG_5) + ") | (bytetemp >> 7);"; + }; + RLC = function(param) { + var operand; + operand = getParamBoilerplate(param, true); + return operand.getter + "\n" + operand.v + " = ( (" + operand.v + " << 1) | (" + operand.v + " >> 7) ) " + operand.trunc + ";\nregs[" + rF + "] = (" + operand.v + " & " + FLAG_C + ") | sz53pTable[" + operand.v + "];\n" + operand.setter; + }; + RLD = function() { + return "var bytetemp = READMEM(regPairs[" + rpHL + "]);\nCONTEND_READ_NO_MREQ(regPairs[" + rpHL + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpHL + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpHL + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpHL + "], 1);\nvar val = (bytetemp << 4) | (regs[" + rA + "] & 0x0f);\nWRITEMEM(regPairs[" + rpHL + "], val);\nregs[" + rA + "] = (regs[" + rA + "] & 0xf0) | (bytetemp >> 4);\nregs[" + rF + "] = (regs[" + rF + "] & " + FLAG_C + ") | sz53pTable[regs[" + rA + "]];"; + }; + RLCA = function() { + return "regs[" + rA + "] = (regs[" + rA + "] << 1) | (regs[" + rA + "] >> 7);\nregs[" + rF + "] = (regs[" + rF + "] & " + (FLAG_P | FLAG_Z | FLAG_S) + ") | (regs[" + rA + "] & " + (FLAG_C | FLAG_3 | FLAG_5) + ");"; + }; + RR = function(param) { + var operand; + operand = getParamBoilerplate(param, true); + return operand.getter + "\nvar rrtemp = " + operand.v + ";\n" + operand.v + " = ( (" + operand.v + " >> 1) | ( regs[" + rF + "] << 7 ) ) " + operand.trunc + ";\nregs[" + rF + "] = (rrtemp & " + FLAG_C + ") | sz53pTable[" + operand.v + "];\n" + operand.setter; + }; + RRA = function() { + return "var bytetemp = regs[" + rA + "];\nregs[" + rA + "] = (bytetemp >> 1) | (regs[" + rF + "] << 7);\nregs[" + rF + "] = (regs[" + rF + "] & " + (FLAG_P | FLAG_Z | FLAG_S) + ") | (regs[" + rA + "] & " + (FLAG_3 | FLAG_5) + ") | (bytetemp & " + FLAG_C + ");"; + }; + RRC = function(param) { + var operand; + operand = getParamBoilerplate(param, true); + return operand.getter + "\nregs[" + rF + "] = " + operand.v + " & " + FLAG_C + ";\n" + operand.v + " = ( (" + operand.v + " >> 1) | (" + operand.v + " << 7) ) " + operand.trunc + ";\nregs[" + rF + "] |= sz53pTable[" + operand.v + "];\n" + operand.setter; + }; + RRCA = function() { + return "regs[" + rF + "] = (regs[" + rF + "] & " + (FLAG_P | FLAG_Z | FLAG_S) + ") | (regs[" + rA + "] & " + FLAG_C + ");\nregs[" + rA + "] = (regs[" + rA + "] >> 1) | (regs[" + rA + "] << 7);\nregs[" + rF + "] |= (regs[" + rA + "] & " + (FLAG_3 | FLAG_5) + ");"; + }; + RRD = function() { + return "var bytetemp = READMEM(regPairs[" + rpHL + "]);\nCONTEND_READ_NO_MREQ(regPairs[" + rpHL + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpHL + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpHL + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpHL + "], 1);\nvar val = (regs[" + rA + "] << 4) | (bytetemp >> 4);\nWRITEMEM(regPairs[" + rpHL + "], val);\nregs[" + rA + "] = (regs[" + rA + "] & 0xf0) | (bytetemp & 0x0f);\nregs[" + rF + "] = (regs[" + rF + "] & " + FLAG_C + ") | sz53pTable[regs[" + rA + "]];"; + }; + RST = function(addr) { + return "CONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nregPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rpPC + "] >> 8);\nregPairs[" + rpSP + "]--; WRITEMEM(regPairs[" + rpSP + "], regPairs[" + rpPC + "] & 0xff);\nregPairs[" + rpPC + "] = " + addr + ";"; + }; + SBC_A = function(param) { + var operand; + operand = getParamBoilerplate(param); + return operand.getter + "\nvar sbctemp = regs[" + rA + "] - " + operand.v + " - (regs[" + rF + "] & " + FLAG_C + ");\nvar lookup = ( (regs[" + rA + "] & 0x88) >> 3 ) | ( (" + operand.v + " & 0x88) >> 2 ) | ( (sbctemp & 0x88) >> 1 );\nregs[" + rA + "] = sbctemp;\nregs[" + rF + "] = ( sbctemp & 0x100 ? " + FLAG_C + " : 0 ) | " + FLAG_N + " | halfcarrySubTable[lookup & 0x07] | overflowSubTable[lookup >> 4] | sz53Table[regs[" + rA + "]];"; + }; + SBC_HL_RR = function(rp) { + return "var sub16temp = regPairs[" + rpHL + "] - regPairs[" + rp + "] - (regs[" + rF + "] & " + FLAG_C + ");\nvar lookup = ( (regPairs[" + rpHL + "] & 0x8800) >> 11 ) | ( (regPairs[" + rp + "] & 0x8800) >> 10 ) | ( (sub16temp & 0x8800) >> 9 );\nregPairs[" + rpHL + "] = sub16temp;\nregs[" + rF + "] = ( sub16temp & 0x10000 ? " + FLAG_C + " : 0 ) | " + FLAG_N + " | overflowSubTable[lookup >> 4] | (regs[" + rH + "] & " + (FLAG_3 | FLAG_5 | FLAG_S) + ") | halfcarrySubTable[lookup&0x07] | (regPairs[" + rpHL + "] ? 0 : " + FLAG_Z + ");\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);\nCONTEND_READ_NO_MREQ(regPairs[" + rpIR + "], 1);"; + }; + SCF = function() { + return "regs[" + rF + "] = (regs[" + rF + "] & " + (FLAG_P | FLAG_Z | FLAG_S) + ") | (regs[" + rA + "] & " + (FLAG_3 | FLAG_5) + ") | " + FLAG_C + ";"; + }; + SET = function(bit, param) { + var hexMask, operand; + hexMask = 1 << bit; + operand = getParamBoilerplate(param, true); + return operand.getter + "\n" + operand.v + " |= " + hexMask + ";\n" + operand.setter; + }; + SHIFT = function(prefix) { + return "opcodePrefix = '" + prefix + "';\ninterruptible = false;"; + }; + SLA = function(param) { + var operand; + operand = getParamBoilerplate(param, true); + return operand.getter + "\nregs[" + rF + "] = " + operand.v + " >> 7;\n" + operand.v + " = (" + operand.v + " << 1) " + operand.trunc + ";\nregs[" + rF + "] |= sz53pTable[" + operand.v + "];\n" + operand.setter; + }; + SLL = function(param) { + var operand; + operand = getParamBoilerplate(param, true); + return operand.getter + "\nregs[" + rF + "] = " + operand.v + " >> 7;\n" + operand.v + " = (((" + operand.v + ") << 1) " + operand.trunc + ") | 0x01;\nregs[" + rF + "] |= sz53pTable[" + operand.v + "];\n" + operand.setter; + }; + SRA = function(param) { + var operand; + operand = getParamBoilerplate(param, true); + return operand.getter + "\nregs[" + rF + "] = " + operand.v + " & " + FLAG_C + ";\n" + operand.v + " = ( (" + operand.v + " & 0x80) | (" + operand.v + " >> 1) ) " + operand.trunc + ";\nregs[" + rF + "] |= sz53pTable[" + operand.v + "];\n" + operand.setter; + }; + SRL = function(param) { + var operand; + operand = getParamBoilerplate(param, true); + return operand.getter + "\nregs[" + rF + "] = " + operand.v + " & " + FLAG_C + ";\n" + operand.v + " >>= 1;\nregs[" + rF + "] |= sz53pTable[" + operand.v + "];\n" + operand.setter; + }; + SUB_A = function(param) { + var operand; + operand = getParamBoilerplate(param); + return operand.getter + "\nvar subtemp = regs[" + rA + "] - " + operand.v + ";\nvar lookup = ( (regs[" + rA + "] & 0x88) >> 3 ) | ( (" + operand.v + " & 0x88) >> 2 ) | ( (subtemp & 0x88) >> 1 );\nregs[" + rA + "] = subtemp;\nregs[" + rF + "] = ( subtemp & 0x100 ? " + FLAG_C + " : 0 ) | " + FLAG_N + " | halfcarrySubTable[lookup & 0x07] | overflowSubTable[lookup >> 4] | sz53Table[regs[" + rA + "]];"; + }; + XOR_A = function(param) { + var operand; + operand = getParamBoilerplate(param); + return operand.getter + "\nregs[" + rA + "] ^= " + operand.v + ";\nregs[" + rF + "] = sz53pTable[regs[" + rA + "]];"; + }; + + /* + Given a table mapping opcodes to Javascript snippets (and optionally a fallback + table for opcodes that aren't defined in the first one), build an enormous + switch statement for them + */ + opcodeSwitch = function(runStringTable, fallbackTable, traps) { + var action, address, clauses, i, j, opcode, relevantTraps, runString, trapCode; + if (fallbackTable == null) { + fallbackTable = {}; + } + if (traps == null) { + traps = []; + } + clauses = []; + for (i = j = 0; j < 256; i = ++j) { + runString = runStringTable[i]; + if (runString == null) { + runString = fallbackTable[i]; + } + if (runString != null) { + relevantTraps = (function() { + var k, len, ref, results; + results = []; + for (k = 0, len = traps.length; k < len; k++) { + ref = traps[k], address = ref[0], opcode = ref[1], action = ref[2]; + if (opcode === i) { + results.push([address, action]); + } + } + return results; + })(); + trapCode = (function() { + var k, len, ref, results; + results = []; + for (k = 0, len = relevantTraps.length; k < len; k++) { + ref = relevantTraps[k], address = ref[0], action = ref[1]; + results.push("if (regPairs[" + rpPC + "] == " + ((address + 1) & 0xffff) + " && !(" + action + ")) break;"); + } + return results; + })(); + clauses.push("case " + i + ": { var fn" + i + " = function() {\n " + (trapCode.join("\n")) + "\n " + runString + "\n}; fn" + i + "(); }\n break;"); + } + } + return "switch (opcode) {\n " + (clauses.join('')) + "\n default:\n var addr = regPairs[" + rpPC + "] - 1;\n throw(\"Unimplemented opcode \" + opcode + \" in page " + runStringTable[0x100] + " - PC = \" + addr);\n}"; + }; + OPCODE_RUN_STRINGS_CB = { + 0x00: RLC("B"), + 0x01: RLC("C"), + 0x02: RLC("D"), + 0x03: RLC("E"), + 0x04: RLC("H"), + 0x05: RLC("L"), + 0x06: RLC("(HL)"), + 0x07: RLC("A"), + 0x08: RRC("B"), + 0x09: RRC("C"), + 0x0a: RRC("D"), + 0x0b: RRC("E"), + 0x0c: RRC("H"), + 0x0d: RRC("L"), + 0x0e: RRC("(HL)"), + 0x0f: RRC("A"), + 0x10: RL('B'), + 0x11: RL('C'), + 0x12: RL('D'), + 0x13: RL('E'), + 0x14: RL('H'), + 0x15: RL('L'), + 0x16: RL('(HL)'), + 0x17: RL('A'), + 0x18: RR('B'), + 0x19: RR('C'), + 0x1a: RR('D'), + 0x1b: RR('E'), + 0x1c: RR('H'), + 0x1d: RR('L'), + 0x1e: RR('(HL)'), + 0x1f: RR('A'), + 0x20: SLA('B'), + 0x21: SLA('C'), + 0x22: SLA('D'), + 0x23: SLA('E'), + 0x24: SLA('H'), + 0x25: SLA('L'), + 0x26: SLA('(HL)'), + 0x27: SLA('A'), + 0x28: SRA('B'), + 0x29: SRA('C'), + 0x2a: SRA('D'), + 0x2b: SRA('E'), + 0x2c: SRA('H'), + 0x2d: SRA('L'), + 0x2e: SRA('(HL)'), + 0x2f: SRA('A'), + 0x30: SLL('B'), + 0x31: SLL('C'), + 0x32: SLL('D'), + 0x33: SLL('E'), + 0x34: SLL('H'), + 0x35: SLL('L'), + 0x36: SLL('(HL)'), + 0x37: SLL('A'), + 0x38: SRL('B'), + 0x39: SRL('C'), + 0x3a: SRL('D'), + 0x3b: SRL('E'), + 0x3c: SRL('H'), + 0x3d: SRL('L'), + 0x3e: SRL('(HL)'), + 0x3f: SRL('A'), + 0x40: BIT_N_R(0, rB), + 0x41: BIT_N_R(0, rC), + 0x42: BIT_N_R(0, rD), + 0x43: BIT_N_R(0, rE), + 0x44: BIT_N_R(0, rH), + 0x45: BIT_N_R(0, rL), + 0x46: BIT_N_iHLi(0), + 0x47: BIT_N_R(0, rA), + 0x48: BIT_N_R(1, rB), + 0x49: BIT_N_R(1, rC), + 0x4A: BIT_N_R(1, rD), + 0x4B: BIT_N_R(1, rE), + 0x4C: BIT_N_R(1, rH), + 0x4D: BIT_N_R(1, rL), + 0x4E: BIT_N_iHLi(1), + 0x4F: BIT_N_R(1, rA), + 0x50: BIT_N_R(2, rB), + 0x51: BIT_N_R(2, rC), + 0x52: BIT_N_R(2, rD), + 0x53: BIT_N_R(2, rE), + 0x54: BIT_N_R(2, rH), + 0x55: BIT_N_R(2, rL), + 0x56: BIT_N_iHLi(2), + 0x57: BIT_N_R(2, rA), + 0x58: BIT_N_R(3, rB), + 0x59: BIT_N_R(3, rC), + 0x5A: BIT_N_R(3, rD), + 0x5B: BIT_N_R(3, rE), + 0x5C: BIT_N_R(3, rH), + 0x5D: BIT_N_R(3, rL), + 0x5E: BIT_N_iHLi(3), + 0x5F: BIT_N_R(3, rA), + 0x60: BIT_N_R(4, rB), + 0x61: BIT_N_R(4, rC), + 0x62: BIT_N_R(4, rD), + 0x63: BIT_N_R(4, rE), + 0x64: BIT_N_R(4, rH), + 0x65: BIT_N_R(4, rL), + 0x66: BIT_N_iHLi(4), + 0x67: BIT_N_R(4, rA), + 0x68: BIT_N_R(5, rB), + 0x69: BIT_N_R(5, rC), + 0x6A: BIT_N_R(5, rD), + 0x6B: BIT_N_R(5, rE), + 0x6C: BIT_N_R(5, rH), + 0x6D: BIT_N_R(5, rL), + 0x6E: BIT_N_iHLi(5), + 0x6F: BIT_N_R(5, rA), + 0x70: BIT_N_R(6, rB), + 0x71: BIT_N_R(6, rC), + 0x72: BIT_N_R(6, rD), + 0x73: BIT_N_R(6, rE), + 0x74: BIT_N_R(6, rH), + 0x75: BIT_N_R(6, rL), + 0x76: BIT_N_iHLi(6), + 0x77: BIT_N_R(6, rA), + 0x78: BIT_N_R(7, rB), + 0x79: BIT_N_R(7, rC), + 0x7A: BIT_N_R(7, rD), + 0x7B: BIT_N_R(7, rE), + 0x7C: BIT_N_R(7, rH), + 0x7D: BIT_N_R(7, rL), + 0x7E: BIT_N_iHLi(7), + 0x7F: BIT_N_R(7, rA), + 0x80: RES(0, 'B'), + 0x81: RES(0, 'C'), + 0x82: RES(0, 'D'), + 0x83: RES(0, 'E'), + 0x84: RES(0, 'H'), + 0x85: RES(0, 'L'), + 0x86: RES(0, '(HL)'), + 0x87: RES(0, 'A'), + 0x88: RES(1, 'B'), + 0x89: RES(1, 'C'), + 0x8A: RES(1, 'D'), + 0x8B: RES(1, 'E'), + 0x8C: RES(1, 'H'), + 0x8D: RES(1, 'L'), + 0x8E: RES(1, '(HL)'), + 0x8F: RES(1, 'A'), + 0x90: RES(2, 'B'), + 0x91: RES(2, 'C'), + 0x92: RES(2, 'D'), + 0x93: RES(2, 'E'), + 0x94: RES(2, 'H'), + 0x95: RES(2, 'L'), + 0x96: RES(2, '(HL)'), + 0x97: RES(2, 'A'), + 0x98: RES(3, 'B'), + 0x99: RES(3, 'C'), + 0x9A: RES(3, 'D'), + 0x9B: RES(3, 'E'), + 0x9C: RES(3, 'H'), + 0x9D: RES(3, 'L'), + 0x9E: RES(3, '(HL)'), + 0x9F: RES(3, 'A'), + 0xA0: RES(4, 'B'), + 0xA1: RES(4, 'C'), + 0xA2: RES(4, 'D'), + 0xA3: RES(4, 'E'), + 0xA4: RES(4, 'H'), + 0xA5: RES(4, 'L'), + 0xA6: RES(4, '(HL)'), + 0xA7: RES(4, 'A'), + 0xA8: RES(5, 'B'), + 0xA9: RES(5, 'C'), + 0xAA: RES(5, 'D'), + 0xAB: RES(5, 'E'), + 0xAC: RES(5, 'H'), + 0xAD: RES(5, 'L'), + 0xAE: RES(5, '(HL)'), + 0xAF: RES(5, 'A'), + 0xB0: RES(6, 'B'), + 0xB1: RES(6, 'C'), + 0xB2: RES(6, 'D'), + 0xB3: RES(6, 'E'), + 0xB4: RES(6, 'H'), + 0xB5: RES(6, 'L'), + 0xB6: RES(6, '(HL)'), + 0xB7: RES(6, 'A'), + 0xB8: RES(7, 'B'), + 0xB9: RES(7, 'C'), + 0xBA: RES(7, 'D'), + 0xBB: RES(7, 'E'), + 0xBC: RES(7, 'H'), + 0xBD: RES(7, 'L'), + 0xBE: RES(7, '(HL)'), + 0xBF: RES(7, 'A'), + 0xC0: SET(0, 'B'), + 0xC1: SET(0, 'C'), + 0xC2: SET(0, 'D'), + 0xC3: SET(0, 'E'), + 0xC4: SET(0, 'H'), + 0xC5: SET(0, 'L'), + 0xC6: SET(0, '(HL)'), + 0xC7: SET(0, 'A'), + 0xC8: SET(1, 'B'), + 0xC9: SET(1, 'C'), + 0xCA: SET(1, 'D'), + 0xCB: SET(1, 'E'), + 0xCC: SET(1, 'H'), + 0xCD: SET(1, 'L'), + 0xCE: SET(1, '(HL)'), + 0xCF: SET(1, 'A'), + 0xD0: SET(2, 'B'), + 0xD1: SET(2, 'C'), + 0xD2: SET(2, 'D'), + 0xD3: SET(2, 'E'), + 0xD4: SET(2, 'H'), + 0xD5: SET(2, 'L'), + 0xD6: SET(2, '(HL)'), + 0xD7: SET(2, 'A'), + 0xD8: SET(3, 'B'), + 0xD9: SET(3, 'C'), + 0xDA: SET(3, 'D'), + 0xDB: SET(3, 'E'), + 0xDC: SET(3, 'H'), + 0xDD: SET(3, 'L'), + 0xDE: SET(3, '(HL)'), + 0xDF: SET(3, 'A'), + 0xE0: SET(4, 'B'), + 0xE1: SET(4, 'C'), + 0xE2: SET(4, 'D'), + 0xE3: SET(4, 'E'), + 0xE4: SET(4, 'H'), + 0xE5: SET(4, 'L'), + 0xE6: SET(4, '(HL)'), + 0xE7: SET(4, 'A'), + 0xE8: SET(5, 'B'), + 0xE9: SET(5, 'C'), + 0xEA: SET(5, 'D'), + 0xEB: SET(5, 'E'), + 0xEC: SET(5, 'H'), + 0xED: SET(5, 'L'), + 0xEE: SET(5, '(HL)'), + 0xEF: SET(5, 'A'), + 0xF0: SET(6, 'B'), + 0xF1: SET(6, 'C'), + 0xF2: SET(6, 'D'), + 0xF3: SET(6, 'E'), + 0xF4: SET(6, 'H'), + 0xF5: SET(6, 'L'), + 0xF6: SET(6, '(HL)'), + 0xF7: SET(6, 'A'), + 0xF8: SET(7, 'B'), + 0xF9: SET(7, 'C'), + 0xFA: SET(7, 'D'), + 0xFB: SET(7, 'E'), + 0xFC: SET(7, 'H'), + 0xFD: SET(7, 'L'), + 0xFE: SET(7, '(HL)'), + 0xFF: SET(7, 'A'), + 0x100: 'cb' + }; + generateddfdcbOpcodeSet = function(prefix) { + var rh, rhn, rl, rln, rp, rpn; + if (prefix === 'DDCB') { + rp = rpIX; + rh = rIXH; + rl = rIXL; + rpn = 'IX'; + rhn = 'IXH'; + rln = 'IXL'; + } else { + rp = rpIY; + rh = rIYH; + rl = rIYL; + rpn = 'IY'; + rhn = 'IYH'; + rln = 'IYL'; + } + return { + 0x00: LDSHIFTOP('B', RLC, rp), + 0x01: LDSHIFTOP('C', RLC, rp), + 0x02: LDSHIFTOP('D', RLC, rp), + 0x03: LDSHIFTOP('E', RLC, rp), + 0x04: LDSHIFTOP('H', RLC, rp), + 0x05: LDSHIFTOP('L', RLC, rp), + 0x06: RLC("(" + rpn + "+nn)"), + 0x07: LDSHIFTOP('A', RLC, rp), + 0x08: LDSHIFTOP('B', RRC, rp), + 0x09: LDSHIFTOP('C', RRC, rp), + 0x0A: LDSHIFTOP('D', RRC, rp), + 0x0B: LDSHIFTOP('E', RRC, rp), + 0x0C: LDSHIFTOP('H', RRC, rp), + 0x0D: LDSHIFTOP('L', RRC, rp), + 0x0E: RRC("(" + rpn + "+nn)"), + 0x0F: LDSHIFTOP('A', RRC, rp), + 0x10: LDSHIFTOP('B', RL, rp), + 0x11: LDSHIFTOP('C', RL, rp), + 0x12: LDSHIFTOP('D', RL, rp), + 0x13: LDSHIFTOP('E', RL, rp), + 0x14: LDSHIFTOP('H', RL, rp), + 0x15: LDSHIFTOP('L', RL, rp), + 0x16: RL("(" + rpn + "+nn)"), + 0x17: LDSHIFTOP('A', RL, rp), + 0x18: LDSHIFTOP('B', RR, rp), + 0x19: LDSHIFTOP('C', RR, rp), + 0x1A: LDSHIFTOP('D', RR, rp), + 0x1B: LDSHIFTOP('E', RR, rp), + 0x1C: LDSHIFTOP('H', RR, rp), + 0x1D: LDSHIFTOP('L', RR, rp), + 0x1E: RR("(" + rpn + "+nn)"), + 0x1F: LDSHIFTOP('A', RR, rp), + 0x20: LDSHIFTOP('B', SLA, rp), + 0x21: LDSHIFTOP('C', SLA, rp), + 0x22: LDSHIFTOP('D', SLA, rp), + 0x23: LDSHIFTOP('E', SLA, rp), + 0x24: LDSHIFTOP('H', SLA, rp), + 0x25: LDSHIFTOP('L', SLA, rp), + 0x26: SLA("(" + rpn + "+nn)"), + 0x27: LDSHIFTOP('A', SLA, rp), + 0x28: LDSHIFTOP('B', SRA, rp), + 0x29: LDSHIFTOP('C', SRA, rp), + 0x2A: LDSHIFTOP('D', SRA, rp), + 0x2B: LDSHIFTOP('E', SRA, rp), + 0x2C: LDSHIFTOP('H', SRA, rp), + 0x2D: LDSHIFTOP('L', SRA, rp), + 0x2E: SRA("(" + rpn + "+nn)"), + 0x2F: LDSHIFTOP('A', SRA, rp), + 0x30: LDSHIFTOP('B', SLL, rp), + 0x31: LDSHIFTOP('C', SLL, rp), + 0x32: LDSHIFTOP('D', SLL, rp), + 0x33: LDSHIFTOP('E', SLL, rp), + 0x34: LDSHIFTOP('H', SLL, rp), + 0x35: LDSHIFTOP('L', SLL, rp), + 0x36: SLL("(" + rpn + "+nn)"), + 0x37: LDSHIFTOP('A', SLL, rp), + 0x38: LDSHIFTOP('B', SRL, rp), + 0x39: LDSHIFTOP('C', SRL, rp), + 0x3A: LDSHIFTOP('D', SRL, rp), + 0x3B: LDSHIFTOP('E', SRL, rp), + 0x3C: LDSHIFTOP('H', SRL, rp), + 0x3D: LDSHIFTOP('L', SRL, rp), + 0x3E: SRL("(" + rpn + "+nn)"), + 0x3F: LDSHIFTOP('A', SRL, rp), + 0x40: BIT_N_iRRpNNi(0, rp), + 0x41: BIT_N_iRRpNNi(0, rp), + 0x42: BIT_N_iRRpNNi(0, rp), + 0x43: BIT_N_iRRpNNi(0, rp), + 0x44: BIT_N_iRRpNNi(0, rp), + 0x45: BIT_N_iRRpNNi(0, rp), + 0x46: BIT_N_iRRpNNi(0, rp), + 0x47: BIT_N_iRRpNNi(0, rp), + 0x48: BIT_N_iRRpNNi(1, rp), + 0x49: BIT_N_iRRpNNi(1, rp), + 0x4A: BIT_N_iRRpNNi(1, rp), + 0x4B: BIT_N_iRRpNNi(1, rp), + 0x4C: BIT_N_iRRpNNi(1, rp), + 0x4D: BIT_N_iRRpNNi(1, rp), + 0x4E: BIT_N_iRRpNNi(1, rp), + 0x4F: BIT_N_iRRpNNi(1, rp), + 0x50: BIT_N_iRRpNNi(2, rp), + 0x51: BIT_N_iRRpNNi(2, rp), + 0x52: BIT_N_iRRpNNi(2, rp), + 0x53: BIT_N_iRRpNNi(2, rp), + 0x54: BIT_N_iRRpNNi(2, rp), + 0x55: BIT_N_iRRpNNi(2, rp), + 0x56: BIT_N_iRRpNNi(2, rp), + 0x57: BIT_N_iRRpNNi(2, rp), + 0x58: BIT_N_iRRpNNi(3, rp), + 0x59: BIT_N_iRRpNNi(3, rp), + 0x5A: BIT_N_iRRpNNi(3, rp), + 0x5B: BIT_N_iRRpNNi(3, rp), + 0x5C: BIT_N_iRRpNNi(3, rp), + 0x5D: BIT_N_iRRpNNi(3, rp), + 0x5E: BIT_N_iRRpNNi(3, rp), + 0x5F: BIT_N_iRRpNNi(3, rp), + 0x60: BIT_N_iRRpNNi(4, rp), + 0x61: BIT_N_iRRpNNi(4, rp), + 0x62: BIT_N_iRRpNNi(4, rp), + 0x63: BIT_N_iRRpNNi(4, rp), + 0x64: BIT_N_iRRpNNi(4, rp), + 0x65: BIT_N_iRRpNNi(4, rp), + 0x66: BIT_N_iRRpNNi(4, rp), + 0x67: BIT_N_iRRpNNi(4, rp), + 0x68: BIT_N_iRRpNNi(5, rp), + 0x69: BIT_N_iRRpNNi(5, rp), + 0x6A: BIT_N_iRRpNNi(5, rp), + 0x6B: BIT_N_iRRpNNi(5, rp), + 0x6C: BIT_N_iRRpNNi(5, rp), + 0x6D: BIT_N_iRRpNNi(5, rp), + 0x6E: BIT_N_iRRpNNi(5, rp), + 0x6F: BIT_N_iRRpNNi(5, rp), + 0x70: BIT_N_iRRpNNi(6, rp), + 0x71: BIT_N_iRRpNNi(6, rp), + 0x72: BIT_N_iRRpNNi(6, rp), + 0x73: BIT_N_iRRpNNi(6, rp), + 0x74: BIT_N_iRRpNNi(6, rp), + 0x75: BIT_N_iRRpNNi(6, rp), + 0x76: BIT_N_iRRpNNi(6, rp), + 0x77: BIT_N_iRRpNNi(6, rp), + 0x78: BIT_N_iRRpNNi(7, rp), + 0x79: BIT_N_iRRpNNi(7, rp), + 0x7A: BIT_N_iRRpNNi(7, rp), + 0x7B: BIT_N_iRRpNNi(7, rp), + 0x7C: BIT_N_iRRpNNi(7, rp), + 0x7D: BIT_N_iRRpNNi(7, rp), + 0x7E: BIT_N_iRRpNNi(7, rp), + 0x7F: BIT_N_iRRpNNi(7, rp), + 0x80: LDBITOP('B', RES, 0, rp), + 0x81: LDBITOP('C', RES, 0, rp), + 0x82: LDBITOP('D', RES, 0, rp), + 0x83: LDBITOP('E', RES, 0, rp), + 0x84: LDBITOP('H', RES, 0, rp), + 0x85: LDBITOP('L', RES, 0, rp), + 0x86: RES(0, "(" + rpn + "+nn)"), + 0x87: LDBITOP('A', RES, 0, rp), + 0x88: LDBITOP('B', RES, 1, rp), + 0x89: LDBITOP('C', RES, 1, rp), + 0x8A: LDBITOP('D', RES, 1, rp), + 0x8B: LDBITOP('E', RES, 1, rp), + 0x8C: LDBITOP('H', RES, 1, rp), + 0x8D: LDBITOP('L', RES, 1, rp), + 0x8E: RES(1, "(" + rpn + "+nn)"), + 0x8F: LDBITOP('A', RES, 1, rp), + 0x90: LDBITOP('B', RES, 2, rp), + 0x91: LDBITOP('C', RES, 2, rp), + 0x92: LDBITOP('D', RES, 2, rp), + 0x93: LDBITOP('E', RES, 2, rp), + 0x94: LDBITOP('H', RES, 2, rp), + 0x95: LDBITOP('L', RES, 2, rp), + 0x96: RES(2, "(" + rpn + "+nn)"), + 0x97: LDBITOP('A', RES, 2, rp), + 0x98: LDBITOP('B', RES, 3, rp), + 0x99: LDBITOP('C', RES, 3, rp), + 0x9A: LDBITOP('D', RES, 3, rp), + 0x9B: LDBITOP('E', RES, 3, rp), + 0x9C: LDBITOP('H', RES, 3, rp), + 0x9D: LDBITOP('L', RES, 3, rp), + 0x9E: RES(3, "(" + rpn + "+nn)"), + 0x9F: LDBITOP('A', RES, 3, rp), + 0xA0: LDBITOP('B', RES, 4, rp), + 0xA1: LDBITOP('C', RES, 4, rp), + 0xA2: LDBITOP('D', RES, 4, rp), + 0xA3: LDBITOP('E', RES, 4, rp), + 0xA4: LDBITOP('H', RES, 4, rp), + 0xA5: LDBITOP('L', RES, 4, rp), + 0xA6: RES(4, "(" + rpn + "+nn)"), + 0xA7: LDBITOP('A', RES, 4, rp), + 0xA8: LDBITOP('B', RES, 5, rp), + 0xA9: LDBITOP('C', RES, 5, rp), + 0xAA: LDBITOP('D', RES, 5, rp), + 0xAB: LDBITOP('E', RES, 5, rp), + 0xAC: LDBITOP('H', RES, 5, rp), + 0xAD: LDBITOP('L', RES, 5, rp), + 0xAE: RES(5, "(" + rpn + "+nn)"), + 0xAF: LDBITOP('A', RES, 5, rp), + 0xB0: LDBITOP('B', RES, 6, rp), + 0xB1: LDBITOP('C', RES, 6, rp), + 0xB2: LDBITOP('D', RES, 6, rp), + 0xB3: LDBITOP('E', RES, 6, rp), + 0xB4: LDBITOP('H', RES, 6, rp), + 0xB5: LDBITOP('L', RES, 6, rp), + 0xB6: RES(6, "(" + rpn + "+nn)"), + 0xB7: LDBITOP('A', RES, 6, rp), + 0xB8: LDBITOP('B', RES, 7, rp), + 0xB9: LDBITOP('C', RES, 7, rp), + 0xBA: LDBITOP('D', RES, 7, rp), + 0xBB: LDBITOP('E', RES, 7, rp), + 0xBC: LDBITOP('H', RES, 7, rp), + 0xBD: LDBITOP('L', RES, 7, rp), + 0xBE: RES(7, "(" + rpn + "+nn)"), + 0xBF: LDBITOP('A', RES, 7, rp), + 0xC0: LDBITOP('B', SET, 0, rp), + 0xC1: LDBITOP('C', SET, 0, rp), + 0xC2: LDBITOP('D', SET, 0, rp), + 0xC3: LDBITOP('E', SET, 0, rp), + 0xC4: LDBITOP('H', SET, 0, rp), + 0xC5: LDBITOP('L', SET, 0, rp), + 0xC6: SET(0, "(" + rpn + "+nn)"), + 0xC7: LDBITOP('A', SET, 0, rp), + 0xC8: LDBITOP('B', SET, 1, rp), + 0xC9: LDBITOP('C', SET, 1, rp), + 0xCA: LDBITOP('D', SET, 1, rp), + 0xCB: LDBITOP('E', SET, 1, rp), + 0xCC: LDBITOP('H', SET, 1, rp), + 0xCD: LDBITOP('L', SET, 1, rp), + 0xCE: SET(1, "(" + rpn + "+nn)"), + 0xCF: LDBITOP('A', SET, 1, rp), + 0xD0: LDBITOP('B', SET, 2, rp), + 0xD1: LDBITOP('C', SET, 2, rp), + 0xD2: LDBITOP('D', SET, 2, rp), + 0xD3: LDBITOP('E', SET, 2, rp), + 0xD4: LDBITOP('H', SET, 2, rp), + 0xD5: LDBITOP('L', SET, 2, rp), + 0xD6: SET(2, "(" + rpn + "+nn)"), + 0xD7: LDBITOP('A', SET, 2, rp), + 0xD8: LDBITOP('B', SET, 3, rp), + 0xD9: LDBITOP('C', SET, 3, rp), + 0xDA: LDBITOP('D', SET, 3, rp), + 0xDB: LDBITOP('E', SET, 3, rp), + 0xDC: LDBITOP('H', SET, 3, rp), + 0xDD: LDBITOP('L', SET, 3, rp), + 0xDE: SET(3, "(" + rpn + "+nn)"), + 0xDF: LDBITOP('A', SET, 3, rp), + 0xE0: LDBITOP('B', SET, 4, rp), + 0xE1: LDBITOP('C', SET, 4, rp), + 0xE2: LDBITOP('D', SET, 4, rp), + 0xE3: LDBITOP('E', SET, 4, rp), + 0xE4: LDBITOP('H', SET, 4, rp), + 0xE5: LDBITOP('L', SET, 4, rp), + 0xE6: SET(4, "(" + rpn + "+nn)"), + 0xE7: LDBITOP('A', SET, 4, rp), + 0xE8: LDBITOP('B', SET, 5, rp), + 0xE9: LDBITOP('C', SET, 5, rp), + 0xEA: LDBITOP('D', SET, 5, rp), + 0xEB: LDBITOP('E', SET, 5, rp), + 0xEC: LDBITOP('H', SET, 5, rp), + 0xED: LDBITOP('L', SET, 5, rp), + 0xEE: SET(5, "(" + rpn + "+nn)"), + 0xEF: LDBITOP('A', SET, 5, rp), + 0xF0: LDBITOP('B', SET, 6, rp), + 0xF1: LDBITOP('C', SET, 6, rp), + 0xF2: LDBITOP('D', SET, 6, rp), + 0xF3: LDBITOP('E', SET, 6, rp), + 0xF4: LDBITOP('H', SET, 6, rp), + 0xF5: LDBITOP('L', SET, 6, rp), + 0xF6: SET(6, "(" + rpn + "+nn)"), + 0xF7: LDBITOP('A', SET, 6, rp), + 0xF8: LDBITOP('B', SET, 7, rp), + 0xF9: LDBITOP('C', SET, 7, rp), + 0xFA: LDBITOP('D', SET, 7, rp), + 0xFB: LDBITOP('E', SET, 7, rp), + 0xFC: LDBITOP('H', SET, 7, rp), + 0xFD: LDBITOP('L', SET, 7, rp), + 0xFE: SET(7, "(" + rpn + "+nn)"), + 0xFF: LDBITOP('A', SET, 7, rp), + 0x100: 'ddcb' + }; + }; + OPCODE_RUN_STRINGS_DDCB = generateddfdcbOpcodeSet('DDCB'); + OPCODE_RUN_STRINGS_FDCB = generateddfdcbOpcodeSet('FDCB'); + generateddfdOpcodeSet = function(prefix) { + var rh, rhn, rl, rln, rp, rpn; + if (prefix === 'DD') { + rp = rpIX; + rh = rIXH; + rl = rIXL; + rpn = 'IX'; + rhn = 'IXH'; + rln = 'IXL'; + } else { + rp = rpIY; + rh = rIYH; + rl = rIYL; + rpn = 'IY'; + rhn = 'IYH'; + rln = 'IYL'; + } + return { + 0x09: ADD_RR_RR(rp, rpBC), + 0x19: ADD_RR_RR(rp, rpDE), + 0x21: LD_RR_NN(rp), + 0x22: LD_iNNi_RR(rp), + 0x23: INC_RR(rp), + 0x24: INC(rhn), + 0x25: DEC(rhn), + 0x26: LD_R_N(rh), + 0x29: ADD_RR_RR(rp, rp), + 0x2A: LD_RR_iNNi(rp), + 0x2B: DEC_RR(rp), + 0x2C: INC(rln), + 0x2D: DEC(rln), + 0x2E: LD_R_N(rl), + 0x34: INC("(" + rpn + "+nn)"), + 0x35: DEC("(" + rpn + "+nn)"), + 0x36: LD_iRRpNNi_N(rp), + 0x39: ADD_RR_RR(rp, rpSP), + 0x44: LD_R_R(rB, rh), + 0x45: LD_R_R(rB, rl), + 0x46: LD_R_iRRpNNi(rB, rp), + 0x4C: LD_R_R(rC, rh), + 0x4D: LD_R_R(rC, rl), + 0x4E: LD_R_iRRpNNi(rC, rp), + 0x54: LD_R_R(rD, rh), + 0x55: LD_R_R(rD, rl), + 0x56: LD_R_iRRpNNi(rD, rp), + 0x5C: LD_R_R(rE, rh), + 0x5D: LD_R_R(rE, rl), + 0x5E: LD_R_iRRpNNi(rE, rp), + 0x60: LD_R_R(rh, rB), + 0x61: LD_R_R(rh, rC), + 0x62: LD_R_R(rh, rD), + 0x63: LD_R_R(rh, rE), + 0x64: LD_R_R(rh, rh), + 0x65: LD_R_R(rh, rl), + 0x66: LD_R_iRRpNNi(rH, rp), + 0x67: LD_R_R(rh, rA), + 0x68: LD_R_R(rl, rB), + 0x69: LD_R_R(rl, rC), + 0x6A: LD_R_R(rl, rD), + 0x6B: LD_R_R(rl, rE), + 0x6C: LD_R_R(rl, rh), + 0x6D: LD_R_R(rl, rl), + 0x6E: LD_R_iRRpNNi(rL, rp), + 0x6F: LD_R_R(rl, rA), + 0x70: LD_iRRpNNi_R(rp, rB), + 0x71: LD_iRRpNNi_R(rp, rC), + 0x72: LD_iRRpNNi_R(rp, rD), + 0x73: LD_iRRpNNi_R(rp, rE), + 0x74: LD_iRRpNNi_R(rp, rH), + 0x75: LD_iRRpNNi_R(rp, rL), + 0x77: LD_iRRpNNi_R(rp, rA), + 0x7C: LD_R_R(rA, rh), + 0x7D: LD_R_R(rA, rl), + 0x7E: LD_R_iRRpNNi(rA, rp), + 0x84: ADD_A(rhn), + 0x85: ADD_A(rln), + 0x86: ADD_A("(" + rpn + "+nn)"), + 0x8C: ADC_A(rhn), + 0x8D: ADC_A(rln), + 0x8E: ADC_A("(" + rpn + "+nn)"), + 0x94: SUB_A(rhn), + 0x95: SUB_A(rln), + 0x96: SUB_A("(" + rpn + "+nn)"), + 0x9C: SBC_A(rhn), + 0x9D: SBC_A(rln), + 0x9E: SBC_A("(" + rpn + "+nn)"), + 0xA4: AND_A(rhn), + 0xA5: AND_A(rln), + 0xA6: AND_A("(" + rpn + "+nn)"), + 0xAC: XOR_A(rhn), + 0xAD: XOR_A(rln), + 0xAE: XOR_A("(" + rpn + "+nn)"), + 0xB4: OR_A(rhn), + 0xB5: OR_A(rln), + 0xB6: OR_A("(" + rpn + "+nn)"), + 0xBC: CP_A(rhn), + 0xBD: CP_A(rln), + 0xBE: CP_A("(" + rpn + "+nn)"), + 0xCB: SHIFT(prefix + 'CB'), + 0xDD: SHIFT('DD'), + 0xE1: POP_RR(rp), + 0xE3: EX_iSPi_RR(rp), + 0xE5: PUSH_RR(rp), + 0xE9: JP_RR(rp), + 0xF9: LD_RR_RR(rpSP, rp), + 0xFD: SHIFT('FD'), + 0x100: 'dd' + }; + }; + OPCODE_RUN_STRINGS_DD = generateddfdOpcodeSet('DD'); + OPCODE_RUN_STRINGS_ED = { + 0x40: IN_R_iCi(rB), + 0x41: OUT_iCi_R(rB), + 0x42: SBC_HL_RR(rpBC), + 0x43: LD_iNNi_RR(rpBC), + 0x44: NEG(), + 0x45: RETN(), + 0x46: IM(0), + 0x47: LD_R_R(rI, rA), + 0x48: IN_R_iCi(rC), + 0x49: OUT_iCi_R(rC), + 0x4A: ADC_HL_RR(rpBC), + 0x4B: LD_RR_iNNi(rpBC), + 0x4C: NEG(), + 0x4D: RETN(), + 0x4E: IM(0), + 0x4F: LD_R_R(rR, rA), + 0x50: IN_R_iCi(rD), + 0x51: OUT_iCi_R(rD), + 0x52: SBC_HL_RR(rpDE), + 0x53: LD_iNNi_RR(rpDE), + 0x54: NEG(), + 0x55: RETN(), + 0x56: IM(1), + 0x57: LD_R_R(rA, rI), + 0x58: IN_R_iCi(rE), + 0x59: OUT_iCi_R(rE), + 0x5A: ADC_HL_RR(rpDE), + 0x5B: LD_RR_iNNi(rpDE), + 0x5C: NEG(), + 0x5D: RETN(), + 0x5E: IM(2), + 0x5F: LD_R_R(rA, rR), + 0x60: IN_R_iCi(rH), + 0x61: OUT_iCi_R(rH), + 0x62: SBC_HL_RR(rpHL), + 0x63: LD_iNNi_RR(rpHL), + 0x64: NEG(), + 0x65: RETN(), + 0x66: IM(0), + 0x67: RRD(), + 0x68: IN_R_iCi(rL), + 0x69: OUT_iCi_R(rL), + 0x6A: ADC_HL_RR(rpHL), + 0x6B: LD_RR_iNNi(rpHL, true), + 0x6C: NEG(), + 0x6D: RETN(), + 0x6E: IM(0), + 0x6F: RLD(), + 0x70: IN_F_iCi(), + 0x71: OUT_iCi_0(), + 0x72: SBC_HL_RR(rpSP), + 0x73: LD_iNNi_RR(rpSP), + 0x74: NEG(), + 0x75: RETN(), + 0x76: IM(1), + 0x78: IN_R_iCi(rA), + 0x79: OUT_iCi_R(rA), + 0x7A: ADC_HL_RR(rpSP), + 0x7B: LD_RR_iNNi(rpSP), + 0x7C: NEG(), + 0x7D: RETN(), + 0x7E: IM(2), + 0xA0: LDI(), + 0xA1: CPI(), + 0xA2: INI(), + 0xA3: OUTI(), + 0xA8: LDD(), + 0xA9: CPD(), + 0xAA: IND(), + 0xAB: OUTD(), + 0xB0: LDIR(), + 0xb1: CPIR(), + 0xB2: INIR(), + 0xB3: OTIR(), + 0xB8: LDDR(), + 0xb9: CPDR(), + 0xBA: INDR(), + 0xBB: OTDR(), + 0x100: 'ed' + }; + OPCODE_RUN_STRINGS_FD = generateddfdOpcodeSet('FD'); + OPCODE_RUN_STRINGS = { + 0x00: NOP(), + 0x01: LD_RR_NN(rpBC), + 0x02: LD_iRRi_R(rpBC, rA), + 0x03: INC_RR(rpBC), + 0x04: INC("B"), + 0x05: DEC("B"), + 0x06: LD_R_N(rB), + 0x07: RLCA(), + 0x08: EX_RR_RR(rpAF, rpAF_), + 0x09: ADD_RR_RR(rpHL, rpBC), + 0x0A: LD_R_iRRi(rA, rpBC), + 0x0B: DEC_RR(rpBC), + 0x0C: INC("C"), + 0x0D: DEC("C"), + 0x0E: LD_R_N(rC), + 0x0F: RRCA(), + 0x10: DJNZ_N(), + 0x11: LD_RR_NN(rpDE), + 0x12: LD_iRRi_R(rpDE, rA), + 0x13: INC_RR(rpDE), + 0x14: INC("D"), + 0x15: DEC("D"), + 0x16: LD_R_N(rD), + 0x17: RLA(), + 0x18: JR_N(), + 0x19: ADD_RR_RR(rpHL, rpDE), + 0x1A: LD_R_iRRi(rA, rpDE), + 0x1B: DEC_RR(rpDE), + 0x1C: INC("E"), + 0x1D: DEC("E"), + 0x1E: LD_R_N(rE), + 0x1F: RRA(), + 0x20: JR_C_N(FLAG_Z, false), + 0x21: LD_RR_NN(rpHL), + 0x22: LD_iNNi_RR(rpHL), + 0x23: INC_RR(rpHL), + 0x24: INC("H"), + 0x25: DEC("H"), + 0x26: LD_R_N(rH), + 0x27: DAA(), + 0x28: JR_C_N(FLAG_Z, true), + 0x29: ADD_RR_RR(rpHL, rpHL), + 0x2A: LD_RR_iNNi(rpHL), + 0x2B: DEC_RR(rpHL), + 0x2C: INC("L"), + 0x2D: DEC("L"), + 0x2E: LD_R_N(rL), + 0x2F: CPL(), + 0x30: JR_C_N(FLAG_C, false), + 0x31: LD_RR_NN(rpSP), + 0x32: LD_iNNi_A(), + 0x33: INC_RR(rpSP), + 0x34: INC("(HL)"), + 0x35: DEC("(HL)"), + 0x36: LD_iRRi_N(rpHL), + 0x37: SCF(), + 0x38: JR_C_N(FLAG_C, true), + 0x39: ADD_RR_RR(rpHL, rpSP), + 0x3A: LD_A_iNNi(), + 0x3B: DEC_RR(rpSP), + 0x3C: INC("A"), + 0x3D: DEC("A"), + 0x3E: LD_R_N(rA), + 0x3F: CCF(), + 0x40: LD_R_R(rB, rB), + 0x41: LD_R_R(rB, rC), + 0x42: LD_R_R(rB, rD), + 0x43: LD_R_R(rB, rE), + 0x44: LD_R_R(rB, rH), + 0x45: LD_R_R(rB, rL), + 0x46: LD_R_iRRi(rB, rpHL), + 0x47: LD_R_R(rB, rA), + 0x48: LD_R_R(rC, rB), + 0x49: LD_R_R(rC, rC), + 0x4a: LD_R_R(rC, rD), + 0x4b: LD_R_R(rC, rE), + 0x4c: LD_R_R(rC, rH), + 0x4d: LD_R_R(rC, rL), + 0x4e: LD_R_iRRi(rC, rpHL), + 0x4f: LD_R_R(rC, rA), + 0x50: LD_R_R(rD, rB), + 0x51: LD_R_R(rD, rC), + 0x52: LD_R_R(rD, rD), + 0x53: LD_R_R(rD, rE), + 0x54: LD_R_R(rD, rH), + 0x55: LD_R_R(rD, rL), + 0x56: LD_R_iRRi(rD, rpHL), + 0x57: LD_R_R(rD, rA), + 0x58: LD_R_R(rE, rB), + 0x59: LD_R_R(rE, rC), + 0x5a: LD_R_R(rE, rD), + 0x5b: LD_R_R(rE, rE), + 0x5c: LD_R_R(rE, rH), + 0x5d: LD_R_R(rE, rL), + 0x5e: LD_R_iRRi(rE, rpHL), + 0x5f: LD_R_R(rE, rA), + 0x60: LD_R_R(rH, rB), + 0x61: LD_R_R(rH, rC), + 0x62: LD_R_R(rH, rD), + 0x63: LD_R_R(rH, rE), + 0x64: LD_R_R(rH, rH), + 0x65: LD_R_R(rH, rL), + 0x66: LD_R_iRRi(rH, rpHL), + 0x67: LD_R_R(rH, rA), + 0x68: LD_R_R(rL, rB), + 0x69: LD_R_R(rL, rC), + 0x6a: LD_R_R(rL, rD), + 0x6b: LD_R_R(rL, rE), + 0x6c: LD_R_R(rL, rH), + 0x6d: LD_R_R(rL, rL), + 0x6e: LD_R_iRRi(rL, rpHL), + 0x6f: LD_R_R(rL, rA), + 0x70: LD_iRRi_R(rpHL, rB), + 0x71: LD_iRRi_R(rpHL, rC), + 0x72: LD_iRRi_R(rpHL, rD), + 0x73: LD_iRRi_R(rpHL, rE), + 0x74: LD_iRRi_R(rpHL, rH), + 0x75: LD_iRRi_R(rpHL, rL), + 0x76: HALT(), + 0x77: LD_iRRi_R(rpHL, rA), + 0x78: LD_R_R(rA, rB), + 0x79: LD_R_R(rA, rC), + 0x7a: LD_R_R(rA, rD), + 0x7b: LD_R_R(rA, rE), + 0x7c: LD_R_R(rA, rH), + 0x7d: LD_R_R(rA, rL), + 0x7e: LD_R_iRRi(rA, rpHL), + 0x7f: LD_R_R(rA, rA), + 0x80: ADD_A("B"), + 0x81: ADD_A("C"), + 0x82: ADD_A("D"), + 0x83: ADD_A("E"), + 0x84: ADD_A("H"), + 0x85: ADD_A("L"), + 0x86: ADD_A("(HL)"), + 0x87: ADD_A("A"), + 0x88: ADC_A("B"), + 0x89: ADC_A("C"), + 0x8a: ADC_A("D"), + 0x8b: ADC_A("E"), + 0x8c: ADC_A("H"), + 0x8d: ADC_A("L"), + 0x8e: ADC_A("(HL)"), + 0x8f: ADC_A("A"), + 0x90: SUB_A("B"), + 0x91: SUB_A("C"), + 0x92: SUB_A("D"), + 0x93: SUB_A("E"), + 0x94: SUB_A("H"), + 0x95: SUB_A("L"), + 0x96: SUB_A("(HL)"), + 0x97: SUB_A("A"), + 0x98: SBC_A("B"), + 0x99: SBC_A("C"), + 0x9a: SBC_A("D"), + 0x9b: SBC_A("E"), + 0x9c: SBC_A("H"), + 0x9d: SBC_A("L"), + 0x9e: SBC_A("(HL)"), + 0x9f: SBC_A("A"), + 0xa0: AND_A("B"), + 0xa1: AND_A("C"), + 0xa2: AND_A("D"), + 0xa3: AND_A("E"), + 0xa4: AND_A("H"), + 0xa5: AND_A("L"), + 0xa6: AND_A("(HL)"), + 0xa7: AND_A("A"), + 0xA8: XOR_A("B"), + 0xA9: XOR_A("C"), + 0xAA: XOR_A("D"), + 0xAB: XOR_A("E"), + 0xAC: XOR_A("H"), + 0xAD: XOR_A("L"), + 0xAE: XOR_A("(HL)"), + 0xAF: XOR_A("A"), + 0xb0: OR_A("B"), + 0xb1: OR_A("C"), + 0xb2: OR_A("D"), + 0xb3: OR_A("E"), + 0xb4: OR_A("H"), + 0xb5: OR_A("L"), + 0xb6: OR_A("(HL)"), + 0xb7: OR_A("A"), + 0xb8: CP_A("B"), + 0xb9: CP_A("C"), + 0xba: CP_A("D"), + 0xbb: CP_A("E"), + 0xbc: CP_A("H"), + 0xbd: CP_A("L"), + 0xbe: CP_A("(HL)"), + 0xbf: CP_A("A"), + 0xC0: RET_C(FLAG_Z, false), + 0xC1: POP_RR(rpBC), + 0xC2: JP_C_NN(FLAG_Z, false), + 0xC3: JP_NN(), + 0xC4: CALL_C_NN(FLAG_Z, false), + 0xC5: PUSH_RR(rpBC), + 0xC6: ADD_A("nn"), + 0xC7: RST(0x0000), + 0xC8: RET_C(FLAG_Z, true), + 0xC9: RET(), + 0xCA: JP_C_NN(FLAG_Z, true), + 0xCB: SHIFT('CB'), + 0xCC: CALL_C_NN(FLAG_Z, true), + 0xCD: CALL_NN(), + 0xCE: ADC_A("nn"), + 0xCF: RST(0x0008), + 0xD0: RET_C(FLAG_C, false), + 0xD1: POP_RR(rpDE), + 0xD2: JP_C_NN(FLAG_C, false), + 0xD3: OUT_iNi_A(), + 0xD4: CALL_C_NN(FLAG_C, false), + 0xD5: PUSH_RR(rpDE), + 0xD6: SUB_A("nn"), + 0xD7: RST(0x0010), + 0xD8: RET_C(FLAG_C, true), + 0xD9: EXX(), + 0xDA: JP_C_NN(FLAG_C, true), + 0xDB: IN_A_N(), + 0xDC: CALL_C_NN(FLAG_C, true), + 0xDD: SHIFT('DD'), + 0xDE: SBC_A("nn"), + 0xDF: RST(0x0018), + 0xE0: RET_C(FLAG_P, false), + 0xE1: POP_RR(rpHL), + 0xE2: JP_C_NN(FLAG_P, false), + 0xE3: EX_iSPi_RR(rpHL), + 0xE4: CALL_C_NN(FLAG_P, false), + 0xE5: PUSH_RR(rpHL), + 0xE6: AND_A("nn"), + 0xE7: RST(0x0020), + 0xE8: RET_C(FLAG_P, true), + 0xE9: JP_RR(rpHL), + 0xEA: JP_C_NN(FLAG_P, true), + 0xEB: EX_RR_RR(rpDE, rpHL), + 0xEC: CALL_C_NN(FLAG_P, true), + 0xED: SHIFT('ED'), + 0xEE: XOR_A("nn"), + 0xEF: RST(0x0028), + 0xF0: RET_C(FLAG_S, false), + 0xF1: POP_RR(rpAF), + 0xF2: JP_C_NN(FLAG_S, false), + 0xF3: DI(), + 0xF4: CALL_C_NN(FLAG_S, false), + 0xF5: PUSH_RR(rpAF), + 0xF6: OR_A("nn"), + 0xF7: RST(0x0030), + 0xF8: RET_C(FLAG_S, true), + 0xF9: LD_RR_RR(rpSP, rpHL), + 0xFA: JP_C_NN(FLAG_S, true), + 0xFB: EI(), + 0xFC: CALL_C_NN(FLAG_S, true), + 0xFD: SHIFT('FD'), + 0xFE: CP_A("nn"), + 0xFF: RST(0x0038), + 0x100: 0 + }; + + /* + Assemble and evaluate the final JS code for the Z80 component. + The indirection on 'eval' causes most browsers to evaluate it in the global + scope, giving a significant speed boost + */ + defineZ80JS = "this._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 && (iff1 || !self.retryInterrupts)) {\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'] & 1;\n iff2 = snapRegs['iff2'] & 1;\n im = snapRegs['im'] & 3;\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 & 1;\n }\n self.setIFF2 = function(val) {\n iff2 = val & 1;\n }\n self.setIM = function(val) {\n im = val & 1;\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 self.retryInterrupts = false;\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) { + defineZ80JS = defineZ80JS.replace(/CONTEND_READ\((.*?),(.*?)\)/g, '(tstates += memory.contend($1, tstates) + ($2))'); + defineZ80JS = defineZ80JS.replace(/CONTEND_WRITE\((.*?),(.*?)\)/g, '(tstates += memory.contend($1, tstates) + ($2))'); + defineZ80JS = defineZ80JS.replace(/CONTEND_READ_NO_MREQ\((.*?),(.*?)\)/g, '(tstates += memory.contend($1, tstates) + ($2))'); + defineZ80JS = defineZ80JS.replace(/CONTEND_WRITE_NO_MREQ\((.*?),(.*?)\)/g, '(tstates += memory.contend($1, tstates) + ($2))'); + defineZ80JS = defineZ80JS.replace(/CONTEND_PORT_EARLY\((.*?)\)/g, "var isContendedMemory = memory.isContended($1);\nvar isULAPort = ioBus.isULAPort($1);\nif (isContendedMemory) tstates += ioBus.contend($1, tstates);\ntstates += 1;\nwhile (display.nextEventTime != null && display.nextEventTime < tstates) display.doEvent();"); + defineZ80JS = defineZ80JS.replace(/CONTEND_PORT_LATE\((.*?)\)/g, "if (isContendedMemory || isULAPort) {\n ioBus.contend($1);\n tstates += 1;\n if (!isULAPort) {\n ioBus.contend($1); tstates += 1;\n ioBus.contend($1); tstates += 1;\n } else {\n tstates += 2;\n }\n} else {\n tstates += 3;\n}"); + } else { + defineZ80JS = defineZ80JS.replace(/CONTEND_READ\((.*?),(.*?)\)/g, 'tstates += ($2)'); + defineZ80JS = defineZ80JS.replace(/CONTEND_WRITE\((.*?),(.*?)\)/g, 'tstates += ($2)'); + defineZ80JS = defineZ80JS.replace(/CONTEND_READ_NO_MREQ\((.*?),(.*?)\)/g, 'tstates += ($2)'); + defineZ80JS = defineZ80JS.replace(/CONTEND_WRITE_NO_MREQ\((.*?),(.*?)\)/g, 'tstates += ($2)'); + defineZ80JS = defineZ80JS.replace(/CONTEND_PORT_EARLY\((.*?)\)/g, 'tstates += 1'); + defineZ80JS = defineZ80JS.replace(/CONTEND_PORT_LATE\((.*?)\)/g, 'tstates += 3'); + } + indirectEval = eval; + return indirectEval(defineZ80JS); +}; + +export interface Z80State { + AF,BC,DE,HL,AF_,BC_,DE_,HL_,IX,IY,SP,PC,IR : number; + iff1,iff2,im,halted : number; + T,intp,intd : number; +} + +export class Z80 implements CPU, InstructionBased, IOBusConnected, SavesState, Interruptable { + + cpu; + interruptType; + memBus : Bus; + ioBus : Bus; + + private buildCPU(z80opts?) { + if (this.memBus && this.ioBus) { + this.cpu = buildZ80(z80opts||{})({ + display: {}, + memory: this.memBus, + ioBus: this.ioBus, + }); + } + } + connectMemoryBus(bus:Bus) { + this.memBus = bus; + this.buildCPU(); + } + connectIOBus(bus:Bus) { + this.ioBus = bus; + this.buildCPU(); + } + advanceInsn() { + let t0 = this.cpu.getTstates(); + this.cpu.runFrame(t0+1); //TODO + return this.cpu.getTstates() - t0; + } + reset() { + this.cpu.reset(); + } + interrupt(itype:number) { + this.cpu.requestInterrupt(itype); + } + getSP() { + return this.cpu.getSP(); + } + getPC() { + return this.cpu.getPC(); + } + saveState() { + return this.cpu.saveState(); + } + loadState(s) { + this.cpu.loadState(s); + } + // TODO: metadata + // TODO: disassembler +} diff --git a/src/devices.ts b/src/devices.ts index 32f86fd9..fc0ea7c5 100644 --- a/src/devices.ts +++ b/src/devices.ts @@ -68,6 +68,10 @@ export interface MemoryBusConnected { connectMemoryBus(bus:Bus) : void; } +export interface IOBusConnected { + connectIOBus(bus:Bus) : void; +} + export interface CPU extends MemoryBusConnected, Resettable { getPC() : number; getSP() : number; diff --git a/test/cli/6502/test6502sim.js b/test/cli/6502/test6502sim.js index 35d32638..fbb02c2d 100644 --- a/test/cli/6502/test6502sim.js +++ b/test/cli/6502/test6502sim.js @@ -2,8 +2,8 @@ var assert = require('assert'); var fs = require('fs'); -var emu = require("gen/nemu/nemu.js"); -var MOS6502 = require("gen/nemu/cpu/MOS6502.js"); +var emu = require("gen/devices.js"); +var MOS6502 = require("gen/cpu/MOS6502.js"); var testbin = fs.readFileSync('test/cli/6502/6502_functional_test.bin', null); describe('MOS6502', function() { diff --git a/test/cli/z80/testzexall.js b/test/cli/z80/testzexall.js new file mode 100644 index 00000000..b67539a6 --- /dev/null +++ b/test/cli/z80/testzexall.js @@ -0,0 +1,59 @@ + +var assert = require('assert'); +var fs = require('fs'); + +var emu = require("gen/devices.js"); +var ZilogZ80 = require("gen/cpu/ZilogZ80.js"); +var testbin = fs.readFileSync('test/cli/z80/zexall.bin', null); +var runall = false; + +describe('ZilogZ80', function() { + it('Should pass functional tests', function() { + assert.equal(8590, testbin.length); + var mem = new Uint8Array(65536); + mem.set(testbin, 0x100); + var bus = { + read: (a) => { return mem[a]; }, + write: (a,v) => { mem[a] = v; } + }; + var iobus = { + read: (a) => { return 0; }, + write: (a,v) => { } + }; + mem[0] = 0xC3; + mem[1] = 0x00; + mem[2] = 0x01; // JP 0x100 CP/M TPA + mem[5] = 0xC9; // Return from BDOS call + var cpu = new ZilogZ80.Z80(); + cpu.connectMemoryBus(bus); + cpu.connectIOBus(bus); + cpu.reset(); + let cycles = 0; + let finish = false; + var maxcyc = runall ? 10000000000 : 1000000; + for (var i=0; i