diff --git a/asm/adder.asm b/asm/adder.asm new file mode 100644 index 0000000..f6ed309 --- /dev/null +++ b/asm/adder.asm @@ -0,0 +1,10 @@ +;;;-------------------------------------------------------------------------------- +;;; Simple 8080 addition program. +;;;-------------------------------------------------------------------------------- + LDA 0080H ; 00 111 010 10 000 000 00 000 000 + MOV B,A ; 01 000 111 + LDA 0081H ; 00 111 010 10 000 001 00 000 000 + ADD B ; 10 000 000 + STA 0082H ; 00 110 010 10 000 010 00 000 000 + JMP 0000H ; 11 000 011 00 000 000 00 000 000 +;;;-------------------------------------------------------------------------------- diff --git a/design/altair-8800-panel.afdesign b/design/altair-8800-panel.afdesign new file mode 100644 index 0000000..56cc02e Binary files /dev/null and b/design/altair-8800-panel.afdesign differ diff --git a/doc/8080_instructions.txt b/doc/8080_instructions.txt new file mode 100644 index 0000000..b70e63f --- /dev/null +++ b/doc/8080_instructions.txt @@ -0,0 +1,109 @@ +;; http://www.classiccmp.org/dunfield/r/8080.txt + +8080 instruction encoding: + +Conventions in instruction source: + D = Destination register (8 bit) + S = Source register (8 bit) + RP = Register pair (16 bit) + # = 8 or 16 bit immediate operand + a = 16 bit Memory address + p = 8 bit port address + ccc = Conditional + +Conventions in instruction encoding: + db = Data byte (8 bit) + lb = Low byte of 16 bit value + hb = High byte of 16 bit value + pa = Port address (8 bit) + +Dest and Source reg fields: + 111=A (Accumulator) + 000=B + 001=C + 010=D + 011=E + 100=H + 101=L + 110=M (Memory reference through address in H:L) + +Register pair 'RP' fields: + 00=BC (B:C as 16 bit register) + 01=DE (D:E as 16 bit register) + 10=HL (H:L as 16 bit register) + 11=SP (Stack pointer, refers to PSW (FLAGS:A) for PUSH/POP) + +Condition code 'CCC' fields: (FLAGS: S Z x A x P x C) + 000=NZ ('Z'ero flag not set) + 001=Z ('Z'ero flag set) + 010=NC ('C'arry flag not set) + 011=C ('C'arry flag set) + 100=PO ('P'arity flag not set - ODD) + 101=PE ('P'arity flag set - EVEN) + 110=P ('S'ign flag not set - POSITIVE) + 111=M ('S'ign flag set - MINUS) + +Inst Encoding Flags Description +---------------------------------------------------------------------- +MOV D,S 01DDDSSS - Move register to register +MVI D,# 00DDD110 db - Move immediate to register +LXI RP,# 00RP0001 lb hb - Load register pair immediate +LDA a 00111010 lb hb - Load A from memory +STA a 00110010 lb hb - Store A to memory +LHLD a 00101010 lb hb - Load H:L from memory +SHLD a 00100010 lb hb - Store H:L to memory +LDAX RP 00RP1010 *1 - Load indirect through BC or DE +STAX RP 00RP0010 *1 - Store indirect through BC or DE +XCHG 11101011 - Exchange DE and HL content +ADD S 10000SSS ZSPCA Add register to A +ADI # 11000110 db ZSCPA Add immediate to A +ADC S 10001SSS ZSCPA Add register to A with carry +ACI # 11001110 db ZSCPA Add immediate to A with carry +SUB S 10010SSS ZSCPA Subtract register from A +SUI # 11010110 db ZSCPA Subtract immediate from A +SBB S 10011SSS ZSCPA Subtract register from A with borrow +SBI # 11011110 db ZSCPA Subtract immediate from A with borrow +INR D 00DDD100 ZSPA Increment register +DCR D 00DDD101 ZSPA Decrement register +INX RP 00RP0011 - Increment register pair +DCX RP 00RP1011 - Decrement register pair +DAD RP 00RP1001 C Add register pair to HL (16 bit add) +DAA 00100111 ZSPCA Decimal Adjust accumulator +ANA S 10100SSS ZSCPA AND register with A +ANI # 11100110 db ZSPCA AND immediate with A +ORA S 10110SSS ZSPCA OR register with A +ORI # 11110110 ZSPCA OR immediate with A +XRA S 10101SSS ZSPCA ExclusiveOR register with A +XRI # 11101110 db ZSPCA ExclusiveOR immediate with A +CMP S 10111SSS ZSPCA Compare register with A +CPI # 11111110 ZSPCA Compare immediate with A +RLC 00000111 C Rotate A left +RRC 00001111 C Rotate A right +RAL 00010111 C Rotate A left through carry +RAR 00011111 C Rotate A right through carry +CMA 00101111 - Compliment A +CMC 00111111 C Compliment Carry flag +STC 00110111 C Set Carry flag +JMP a 11000011 lb hb - Unconditional jump +Jccc a 11CCC010 lb hb - Conditional jump +CALL a 11001101 lb hb - Unconditional subroutine call +Cccc a 11CCC100 lb hb - Conditional subroutine call +RET 11001001 - Unconditional return from subroutine +Rccc 11CCC000 - Conditional return from subroutine +RST n 11NNN111 - Restart (Call n*8) +PCHL 11101001 - Jump to address in H:L +PUSH RP 11RP0101 *2 - Push register pair on the stack +POP RP 11RP0001 *2 *2 Pop register pair from the stack +XTHL 11100011 - Swap H:L with top word on stack +SPHL 11111001 - Set SP to content of H:L +IN p 11011011 pa - Read input port into A +OUT p 11010011 pa - Write A to output port +EI 11111011 - Enable interrupts +DI 11110011 - Disable interrupts +HLT 01110110 - Halt processor +NOP 00000000 - No operation + +*1 = Only RP=00(BC) and 01(DE) are allowed for LDAX/STAX + +*2 = RP=11 refers to PSW for PUSH/POP (cannot push/pop SP). + When PSW is POP'd, ALL flags are affected. diff --git a/doc/altair_8800_operator_manual.pdf b/doc/altair_8800_operator_manual.pdf new file mode 100644 index 0000000..a3f8de7 Binary files /dev/null and b/doc/altair_8800_operator_manual.pdf differ diff --git a/js/8080.js b/js/8080.js new file mode 100644 index 0000000..b22ddd8 --- /dev/null +++ b/js/8080.js @@ -0,0 +1,2420 @@ +/** + * @fileoverview Intel 8008 CPU simulator. + * + * This is a copy of the JavaScript code at https://github.com/maly/8080js + * See below for the copyright notice of the original code. + */ + +// Copyright (C) 2013, 2014 Martin Maly +// +// Precise JS emulator for Intel 8080 CPU. +// +// Based on BSD-licensed work by Copyright (C) 2008 Chris Double +// +// All flags and instructions fixed to provide perfect compatibility +// with original "silicon" CPU. +// +// This emulator passes the Exerciser http://www.idb.me.uk/sunhillow/8080.html +// +// Big thanks to Roman Borik (http://pmd85.borik.net). His help lets me +// achieve such a perfect HW compatibility. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +/* jshint sub: true */ + + + (function(exports){ + var ds = [["NOP",1],["LXI B,#1",3],["STAX B",1],["INX B",1],["INR B",1],["DCR B",1],["MVI B, %1",2],["RLC",1],["-",0],["DAD B",1],["LDAX B",1], + ["DCX B",1],["INR C",1],["DCR C",1],["MVI C,%1",2],["RRC",1],["-",0],["LXI D,#1",3],["STAX D",1],["INX D",1],["INR D",1],["DCR D",1],["MVI D, %1",2], + ["RAL",1],["-",0],["DAD D",1],["LDAX D",1],["DCX D",1],["INR E",1],["DCR E",1],["MVI E,%1",2],["RAR",1],["RIM",1],["LXI H,#1",3],["SHLD #1",3], + ["INX H",1],["INR H",1],["DCR H",1],["MVI H,%1",2],["DAA",1],["-",0],["DAD H",1],["LHLD #1",3],["DCX H",1],["INR L",1],["DCR L",1],["MVI L, %1",2], + ["CMA",1],["SIM",1],["LXI SP, #1",3],["STA #1",3],["INX SP",1],["INR M",1],["DCR M",1],["MVI M,%1",2],["STC",1],["-",0],["DAD SP",1],["LDA #1",3], + ["DCX SP",1],["INR A",1],["DCR A",1],["MVI A,%1",2],["CMC",1],["MOV B,B",1],["MOV B,C",1],["MOV B,D",1],["MOV B,E",1],["MOV B,H",1],["MOV B,L",1], + ["MOV B,M",1],["MOV B,A",1],["MOV C,B",1],["MOV C,C",1],["MOV C,D",1],["MOV C,E",1],["MOV C,H",1],["MOV C,L",1],["MOV C,M",1],["MOV C,A",1], + ["MOV D,B",1],["MOV D,C",1],["MOV D,D",1],["MOV D,E",1],["MOV D,H",1],["MOV D,L",1],["MOV D,M",1],["MOV D,A",1],["MOV E,B",1],["MOV E,C",1], + ["MOV E,D",1],["MOV E,E",1],["MOV E,H",1],["MOV E,L",1],["MOV E,M",1],["MOV E,A",1],["MOV H,B",1],["MOV H,C",1],["MOV H,D",1],["MOV H,E",1], + ["MOV H,H",1],["MOV H,L",1],["MOV H,M",1],["MOV H,A",1],["MOV L,B",1],["MOV L,C",1],["MOV L,D",1],["MOV L,E",1],["MOV L,H",1],["MOV L,L",1], + ["MOV L,M",1],["MOV L,A",1],["MOV M,B",1],["MOV M,C",1],["MOV M,D",1],["MOV M,E",1],["MOV M,H",1],["MOV M,L",1],["HLT",1],["MOV M,A",1], + ["MOV A,B",1],["MOV A,C",1],["MOV A,D",1],["MOV A,E",1],["MOV A,H",1],["MOV A,L",1],["MOV A,M",1],["MOV A,A",1],["ADD B",1],["ADD C",1],["ADD D",1], + ["ADD E",1],["ADD H",1],["ADD L",1],["ADD M",1],["ADD A",1],["ADC B",1],["ADC C",1],["ADC D",1],["ADC E",1],["ADC H",1],["ADC L",1],["ADC M",1], + ["ADC A",1],["SUB B",1],["SUB C",1],["SUB D",1],["SUB E",1],["SUB H",1],["SUB L",1],["SUB M",1],["SUB A",1],["SBB B",1],["SBB C",1],["SBB D",1], + ["SBB E",1],["SBB H",1],["SBB L",1],["SBB M",1],["SBB A",1],["ANA B",1],["ANA C",1],["ANA D",1],["ANA E",1],["ANA H",1],["ANA L",1],["ANA M",1], + ["ANA A",1],["XRA B",1],["XRA C",1],["XRA D",1],["XRA E",1],["XRA H",1],["XRA L",1],["XRA M",1],["XRA A",1],["ORA B",1],["ORA C",1],["ORA D",1], + ["ORA E",1],["ORA H",1],["ORA L",1],["ORA M",1],["ORA A",1],["CMP B",1],["CMP C",1],["CMP D",1],["CMP E",1],["CMP H",1],["CMP L",1],["CMP M",1], + ["CMP A",1],["RNZ",1],["POP B",1],["JNZ #1",3],["JMP #1",3],["CNZ #1",3],["PUSH B",1],["ADI %1",2],["RST 0",1],["RZ",1],["RET",1],["JZ #1",3],["-",0], + ["CZ #1",3],["CALL #1",3],["ACI %1",2],["RST 1",1],["RNC",1],["POP D",1],["JNC #1",3],["OUT %1",2],["CNC #1",3],["PUSH D",1],["SUI %1",2],["RST 2",1], + ["RC",1],["-",0],["JC #1",3],["IN %1",2],["CC #1",3],["-",0],["SBI %1",2],["RST 3",1],["RPO",1],["POP H",1],["JPO #1",3],["XTHL",1],["CPO #1",3], + ["PUSH H",1],["ANI %1",2],["RST 4",1],["RPE",1],["PCHL",1],["JPE #1",3],["XCHG",1],["CPE #1",3],["-",0],["XRI %1",2],["RST 5",1],["RP",1],["POP PSW",1], + ["JP #1",3],["DI",1],["CP #1",3],["PUSH PSW",1],["ORI %1",2],["RST 6",1],["RM",1],["SPHL",1],["JM #1",3],["EI",1],["CM #1",3],["-",0],["CPI %1",2],["RST 7",1]]; + + var toHexN = function(n,d) { + var s = n.toString(16); + while (s.length > 8 & 0xFF; + this.f = n & 0xFF; +}; + +Cpu.prototype.bc = function () { + return ((this.b & 0xff) << 8) | (this.c & 0xff); +}; + +Cpu.prototype.BC = function(n) { + this.b = (n >> 8) & 0xFF; + this.c = n & 0xFF; +}; + +Cpu.prototype.de = function () { + return this.d << 8 | this.e; +}; + +Cpu.prototype.DE = function(n) { + this.d = n >> 8 & 0xFF; + this.e = n & 0xFF; +}; + +Cpu.prototype.hl = function () { + return this.h << 8 | this.l; +}; + +Cpu.prototype.HL = function(n) { + this.h = n >> 8 & 0xFF; + this.l = n & 0xFF; +}; + +Cpu.prototype.set = function(flag) { + this.f |= flag; +}; + +Cpu.prototype.clear = function(flag) { + this.f &= ~flag & 0xFF ; +}; + +Cpu.prototype.toString = function() { + return "{" + + " af: " + pad(this.af().toString(16),4) + + " bc: " + pad(this.bc().toString(16),4) + + " de: " + pad(this.de().toString(16),4) + + " hl: " + pad(this.hl().toString(16),4) + + " pc: " + pad(this.pc.toString(16),4) + + " sp: " + pad(this.sp.toString(16),4) + + " flags: " + + (this.f & ZERO ? "z" : ".") + + (this.f & SIGN ? "s" : ".") + + (this.f & PARITY ? "p" : ".") + + (this.f & CARRY ? "c" : ".") + + " " + + " }"; +}; + +// Load the data from the array into the Cpu memory +// starting at address. + +// Step through one instruction +Cpu.prototype.step = function() { + if (this.halted===1) { + this.cycles++; + return 1; + } + var i = byteAt(this.pc++); + var inT = this.cycles; + this.execute(i); + this.pc &= 0xFFFF; + //this.processInterrupts(); + return this.cycles-inT; +}; + +Cpu.prototype.writePort = function (port, v) { + if (portOut) portOut(port & 0xff,v); +}; + +Cpu.prototype.readPort = function (port) { + if (portIn) return portIn(port & 0xff); + return 255; +}; + +Cpu.prototype.getByte = function (addr) { + return byteAt(addr & 0xffff); +}; + +Cpu.prototype.getWord = function (addr) { + //var ram = this.ram; + var l = byteAt(addr & 0xffff); + var h = byteAt((addr+1) & 0xffff); + return h << 8 | l; +}; + +Cpu.prototype.nextByte = function() { + var pc = this.pc; + var b = byteAt(pc & 0xffff); + this.pc = (pc + 1) & 0xFFFF; + return b; +}; + +Cpu.prototype.nextWord = function() { + var pc = this.pc; + //var ram = this.ram; + var l = byteAt(pc & 0xffff); + var h = byteAt((pc+1) & 0xffff); + this.pc = (pc + 2) & 0xFFFF; + return h << 8 | l; +}; + +Cpu.prototype.writeByte = function(addr, value) { + + var v = value & 0xFF; + byteTo(addr & 0xffff, v); +}; + +Cpu.prototype.writeWord = function(addr, value) { + var l = value; + var h = value >> 8; + this.writeByte(addr & 0xffff, l); + this.writeByte((addr+1) & 0xffff, h); +}; + + +// set flags after arithmetic and logical ops +Cpu.prototype.calcFlags = function(v, lhs, rhs) { + var x = v & 0xFF; + + if (v >= 0x100 || v < 0) + this.f |= CARRY; + else + this.f &= ~CARRY & 0xFF; + + + this.f = flagTable[x]; + if (v >= 0x100 || v < 0) + this.f |= CARRY; + else + this.f &= ~CARRY & 0xFF; + + return x; +}; + +//R,A,result +Cpu.prototype.acADD = function(a1,a2,r){ + var aux = [ 0, HALFCARRY, HALFCARRY, HALFCARRY, 0, 0, 0, HALFCARRY ]; + var dis = (r&8)>>1 | (a2&8)>>2 | (a1&8)>>3; + var ac = aux[dis]; + this.f = this.f & ~HALFCARRY | ac; +}; +Cpu.prototype.acSUB = function(a1,a2,r){ + var aux = [ HALFCARRY, HALFCARRY, 0, HALFCARRY, 0, HALFCARRY, 0 ,0 ]; + var dis = (r&8)>>1 | (a2&8)>>2 | (a1&8)>>3; + var ac = aux[dis]; + this.f = this.f & ~HALFCARRY | ac; +}; + + +Cpu.prototype.incrementByte = function(o) { + var c = this.f & CARRY; // carry isnt affected + var r = this.calcFlags(o+1, o, 1); + this.f = (this.f & ~CARRY & 0xFF) | c; + if ((r & 0x0f) === 0) { + this.f = this.f | HALFCARRY ; + } else { + this.f &= ~HALFCARRY & 0xff ; + } + return r; +}; + +Cpu.prototype.decrementByte = function(o) { + var c = this.f & CARRY; // carry isnt affected + var r = this.calcFlags(o-1, o, 1); + this.f = (this.f & ~CARRY & 0xFF) | c; + if ((o & 0x0f) > 0) { + this.f = this.f | HALFCARRY ; + } else { + this.f &= ~HALFCARRY & 0xff ; + } + + return r; +}; + +Cpu.prototype.addByte = function(lhs, rhs) { + var mid = this.calcFlags(lhs + rhs, lhs, rhs); + this.acADD(lhs,rhs,mid); + return mid; +}; + +Cpu.prototype.addByteWithCarry = function(lhs, rhs) { + var mid = this.addByte(lhs, rhs + ((this.f & CARRY) ? 1 : 0)); + this.acADD(lhs,rhs,mid); + return mid; +}; + +Cpu.prototype.subtractByte = function(lhs, rhs) { + var mid = this.calcFlags(lhs - rhs, lhs, rhs); + this.acSUB(lhs,rhs,mid); + return mid; +}; + +Cpu.prototype.subtractByteWithCarry = function(lhs, rhs) { + var nrhs = rhs + ((this.f & CARRY) ? 1 : 0); + var mid = this.calcFlags(lhs - nrhs, lhs, nrhs); +// var mid = this.calcFlags(lhs, rhs + ((this.f & CARRY) ? 1 : 0)); + this.acSUB(lhs,rhs,mid); + return mid; +}; + +Cpu.prototype.andByte = function(lhs, rhs) { + var x = this.calcFlags(lhs & rhs, lhs, rhs); + var ac = (lhs & 0x08) | (rhs & 0x08); + if (ac>0) { + this.f |= HALFCARRY; + } else { + this.f &= ~HALFCARRY; + } + this.f &= ~CARRY & 0xFF; + return x; +}; + +Cpu.prototype.xorByte = function(lhs, rhs) { + var x = this.calcFlags(lhs ^ rhs, lhs, rhs); + //this.f |= HALFCARRY; + this.f &= ~HALFCARRY; + this.f &= ~CARRY & 0xFF; + return x; +}; + +Cpu.prototype.orByte = function(lhs, rhs) { + var x = this.calcFlags(lhs | rhs, lhs, rhs); + //this.f |= HALFCARRY; + this.f &= ~HALFCARRY; + this.f &= ~CARRY & 0xFF; + return x; +}; + +Cpu.prototype.addWord = function(lhs, rhs) { + var r = lhs + rhs; + if (r > 0xFFFF) + {this.f |= CARRY;} + else { + this.f &= ~CARRY; + } + +/* + this.f |= SIGN; + this.f |= ZERO; + this.f |= HALFCARRY; + this.f |= PARITY; +*/ + return r & 0xFFFF; +}; + +Cpu.prototype.pop = function() { + var pc = this.getWord(this.sp); + this.sp = (this.sp + 2) & 0xffff; + return pc; +}; + +Cpu.prototype.push = function(v) { + this.sp = (this.sp - 2) & 0xffff; + this.writeWord(this.sp, v); +}; + +Cpu.prototype.processInterrupts = function() { +}; + +Cpu.prototype.execute = function(i) { + + var addr, w, c; + + this.f &= 0xd7; + this.f |= 0x02; + + switch(i) { + case 0x00: + case 0x08: + case 0x10: + case 0x18: + case 0x20: + case 0x28: + case 0x30: + case 0x38: + { + // NOP + this.cycles += 4; + } + break; + case 0x01: + { + // LD BC,nn + this.BC(this.nextWord()); + this.cycles += 10; + } + break; + case 0x02: + { + // LD (BC),A + this.writeByte(this.bc(), this.a); + this.cycles += 7; + } + break; + case 0x03: + { + // INC BC + this.BC((this.bc() + 1) & 0xFFFF); + this.cycles += 6; + } + break; + case 0x04: + { + // INC B + this.b = this.incrementByte(this.b); + this.cycles += 5 ; + } + break; + case 0x05: + { + // DEC B + this.b = this.decrementByte(this.b); + this.cycles += 5; + } + break; + case 0x06: + { + // LD B,n + this.b = this.nextByte(); + this.cycles += 7; + } + break; + case 0x07: + { + // RLCA + var l = (this.a & 0x80) >> 7; + if (l) + this.f |= CARRY; + else + this.f &= ~CARRY & 0xFF; + + this.a = ((this.a << 1) & 0xFE) | l; + this.cycles += 4; + } + break; + case 0x09: + { + // ADD HL,BC + this.HL(this.addWord(this.hl(), this.bc())); + this.cycles += 11; + } + break; + case 0x0A: + { + // LD A,(BC) + this.a = byteAt(this.bc()); + this.cycles += 7; + } + break; + case 0x0B: + { + // DEC BC + this.BC((this.bc() + 65535) & 0xFFFF); + this.cycles += 6; + } + break; + case 0x0C: + { + // INC C + this.c = this.incrementByte(this.c); + this.cycles += 5; + } + break; + case 0x0D: + { + // DEC C + this.c = this.decrementByte(this.c); + this.cycles += 5; + } + break; + case 0x0E: + { + // LD C,n + this.c = this.nextByte(); + this.cycles += 7; + } + break; + case 0x0F: + { + // RRCA + var h = (this.a & 1) << 7; + if (h) + this.f |= CARRY; + else + this.f &= ~CARRY & 0xFF; + + this.a = ((this.a >> 1) & 0x7F) | h; + this.cycles += 4; + } + break; + case 0x11: + { + // LD DE,nn + this.DE(this.nextWord()); + this.cycles += 10; + } + break; + case 0x12: + { + // LD (DE),A + this.writeByte(this.de(), this.a); + this.cycles += 7; + } + break; + case 0x13: + { + // INC DE + this.DE((this.de() + 1) & 0xFFFF); + this.cycles += 6; + } + break; + case 0x14: + { + // INC D + this.d = this.incrementByte(this.d); + this.cycles += 5; + } + break; + case 0x15: + { + // DEC D + this.d = this.decrementByte(this.d); + this.cycles += 5; + } + break; + case 0x16: + { + // LD D,n + this.d = this.nextByte(); + this.cycles += 7; + } + break; + case 0x17: + { + // RLA + c = (this.f & CARRY) ? 1 : 0; + if(this.a & 128) + this.f |= CARRY; + else + this.f &= ~CARRY & 0xFF; + this.a = ((this.a << 1) & 0xFE) | c; + this.cycles += 4; + } + break; + case 0x19: + { + // ADD HL,DE + this.HL(this.addWord(this.hl(), this.de())); + this.cycles += 11; + } + break; + case 0x1A: + { + // LD A,(DE) + this.a = byteAt(this.de()); + this.cycles += 7; + } + break; + case 0x1B: + { + // DEC DE + this.DE((this.de() - 1) & 0xFFFF); + this.cycles += 6; + } + break; + case 0x1C: + { + // INC E + this.e = this.incrementByte(this.e); + this.cycles += 5; + } + break; + case 0x1D: + { + // DEC E + this.e = this.decrementByte(this.e); + this.cycles += 5; + } + break; + case 0x1E: + { + // LD E,n + this.e = this.nextByte(); + this.cycles += 7; + } + break; + case 0x1F: + { + // RRA + var cy = (this.f & CARRY) ? 128 : 0; + if(this.a & 1) + this.f |= CARRY; + else + this.f &= ~CARRY & 0xFF; + this.a = ((this.a >> 1) & 0x7F) | cy; + this.cycles += 4; + } + break; + case 0x21: + { + // LD HL,nn + this.HL(this.nextWord()); + this.cycles += 10; + } + break; + case 0x22: + { + // LD (nn),HL + this.writeWord(this.nextWord(), this.hl()); + this.cycles += 16; + } + break; + case 0x23: + { + // INC HL + this.HL((this.hl() + 1) & 0xFFFF); + this.cycles += 6; + } + break; + case 0x24: + { + // INC H + this.h = this.incrementByte(this.h); + this.cycles += 5; + } + break; + case 0x25: + { + // DEC H + this.h = this.decrementByte(this.h); + this.cycles += 5; + } + break; + case 0x26: + { + // LD H,n + this.h = this.nextByte(); + this.cycles += 7; + } + break; + case 0x27: + { + // DAA + var temp = this.a; + if (this.f & CARRY) {temp |= 0x100;} + if (this.f & HALFCARRY) {temp |= 0x200;} + var AF = daaTable[temp]; + this.a = (AF>>8)&0xff; + this.f = AF&0xd7|0x02; + this.cycles += 4; + } + break; + case 0x29: + { + // ADD HL,HL + this.HL(this.addWord(this.hl(), this.hl())); + this.cycles += 11; + } + break; + case 0x2A: + { + // LD HL,(nn) + this.HL(this.getWord(this.nextWord())); + this.cycles += 16; + } + break; + case 0x2B: + { + // DEC HL + this.HL((this.hl() - 1) & 0xFFFF); + this.cycles += 6; + } + break; + case 0x2C: + { + // INC L + this.l = this.incrementByte(this.l); + this.cycles += 5; + } + break; + case 0x2D: + { + // DEC L + this.l = this.decrementByte(this.l); + this.cycles += 5; + } + break; + case 0x2E: + { + // LD L,n + this.l = this.nextByte(); + this.cycles += 7; + } + break; + case 0x2F: + { + // CPL + this.a ^= 0xFF; + this.cycles += 4; + } + break; + case 0x31: + { + // LD SP,nn + this.sp = this.nextWord(); + this.cycles += 10; + } + break; + case 0x32: + { + // LD (nn),A + this.writeByte(this.nextWord(), this.a); + this.cycles += 13; + } + break; + case 0x33: + { + // INC SP + this.sp = ((this.sp + 1) & 0xFFFF); + this.cycles += 6; + } + break; + case 0x34: + { + // INC (HL) + addr = this.hl(); + this.writeByte(addr, this.incrementByte(byteAt(addr))); + this.cycles += 10; + } + break; + case 0x35: + { + // DEC (HL) + addr = this.hl(); + this.writeByte(addr, this.decrementByte(byteAt(addr))); + this.cycles += 10; + } + break; + case 0x36: + { + // LD (HL),n + this.writeByte(this.hl(), this.nextByte()); + this.cycles += 10; + } + break; + case 0x37: + { + // SCF + this.f |= CARRY; + this.cycles += 4; + } + break; + case 0x39: + { + // ADD HL,SP + this.HL(this.addWord(this.hl(), this.sp)); + this.cycles += 11; + } + break; + case 0x3A: + { + // LD A,(nn) + this.a = byteAt(this.nextWord()); + this.cycles += 13; + } + break; + case 0x3B: + { + // DEC SP + this.sp = (this.sp - 1) & 0xFFFF; + this.cycles += 6; + } + break; + case 0x3C: + { + // INC A + this.a = this.incrementByte(this.a); + this.cycles += 5; + } + break; + case 0x3D: + { + // DEC A + this.a = this.decrementByte(this.a); + this.cycles += 5; + } + break; + case 0x3E: + { + // LD A,n + this.a = this.nextByte(); + this.cycles += 7; + } + break; + case 0x3F: + { + // CCF + this.f ^= CARRY; + this.cycles += 4; + } + break; + case 0x40: + { + // LD B,B + this.b = this.b; + this.cycles += 5; + } + break; + case 0x41: + { + //LD B,C + this.b = this.c; + this.cycles += 5; + } + break; + case 0x42: + { + // LD B,D + this.b = this.d; + this.cycles += 5; + } + break; + case 0x43: + { + // LD B,E + this.b = this.e; + this.cycles += 5; + } + break; + case 0x44: + { + // LD B,H + this.b = this.h; + this.cycles += 5; + } + break; + case 0x45: + { + // LD B,L + this.b = this.l; + this.cycles += 5; + } + break; + case 0x46: + { + // LD B,(HL) + this.b = byteAt(this.hl()); + this.cycles += 7; + } + break; + case 0x47: + { + // LD B,A + this.b = this.a; + this.cycles += 5; + } + break; + case 0x48: + { + // LD C,B + this.c = this.b; + this.cycles += 5; + } + break; + case 0x49: + { + // LD C,C + this.c = this.c; + this.cycles += 5; + } + break; + case 0x4A: + { + // LD C,D + this.c = this.d; + this.cycles += 5; + } + break; + case 0x4B: + { + // LD C,E + this.c = this.e; + this.cycles += 5; + } + break; + case 0x4C: + { + // LD C,H + this.c = this.h; + this.cycles += 5; + } + break; + case 0x4D: + { + // LD C,L + this.c = this.l; + this.cycles += 5; + } + break; + case 0x4E: + { + // LD C,(HL) + this.c = byteAt(this.hl()); + this.cycles += 7; + } + break; + case 0x4F: + { + // LD C,A + this.c = this.a; + this.cycles += 5; + } + break; + case 0x50: + { + // LD D,B + this.d = this.b; + this.cycles += 5; + } + break; + case 0x51: + { + // LD D,C + this.d = this.c; + this.cycles += 5; + } + break; + case 0x52: + { + // LD D,D + this.d = this.d; + this.cycles += 5; + } + break; + case 0x53: + { + // LD D,E + this.d = this.e; + this.cycles += 5; + } + break; + case 0x54: + { + // LD D,H + this.d = this.h; + this.cycles += 5; + } + break; + case 0x55: + { + // LD D,L + this.d = this.l; + this.cycles += 5; + } + break; + case 0x56: + { + // LD D,(HL) + this.d = byteAt(this.hl()); + this.cycles += 7; + } + break; + case 0x57: + { + // LD D,A + this.d = this.a; + this.cycles += 5; + } + break; + case 0x58: + { + // LD E,B + this.e = this.b; + this.cycles += 5; + } + break; + case 0x59: + { + // LD E,C + this.e = this.c; + this.cycles += 5; + } + break; + case 0x5A: + { + // LD E,D + this.e = this.d; + this.cycles += 5; + } + break; + case 0x5B: + { + // LD E,E + this.e = this.e; + this.cycles += 5; + } + break; + case 0x5C: + { + // LD E,H + this.e = this.h; + this.cycles += 5; + } + break; + case 0x5D: + { + // LD E,L + this.e = this.l; + this.cycles += 5; + } + break; + case 0x5E: + { + // LD E,(HL) + this.e = byteAt(this.hl()); + this.cycles += 7; + } + break; + case 0x5F: + { + // LD E,A + this.e = this.a; + this.cycles += 5; + } + break; + case 0x60: + { + // LD H,B + this.h = this.b; + this.cycles += 5; + } + break; + case 0x61: + { + // LD H,C + this.h = this.c; + this.cycles += 5; + } + break; + case 0x62: + { + // LD H,D + this.h = this.d; + this.cycles += 5; + } + break; + case 0x63: + { + // LD H,E + this.h = this.e; + this.cycles += 5; + } + break; + case 0x64: + { + // LD H,H + this.h = this.h; + this.cycles += 5; + } + break; + case 0x65: + { + // LD H,L + this.h = this.l; + this.cycles += 5; + } + break; + case 0x66: + { + // LD H,(HL) + this.h = byteAt(this.hl()); + this.cycles += 7; + } + break; + case 0x67: + { + // LD H,A + this.h = this.a; + this.cycles += 5; + } + break; + case 0x68: + { + // LD L,B + this.l = this.b; + this.cycles += 5; + } + break; + case 0x69: + { + // LD L,C + this.l = this.c; + this.cycles += 5; + } + break; + case 0x6A: + { + // LD L,D + this.l = this.d; + this.cycles += 5; + } + break; + case 0x6B: + { + // LD L,E + this.l = this.e; + this.cycles += 5; + } + break; + case 0x6C: + { + // LD L,H + this.l = this.h; + this.cycles += 5; + } + break; + case 0x6D: + { + // LD L,L + this.l = this.l; + this.cycles += 5; + } + break; + case 0x6E: + { + // LD L,(HL) + this.l = byteAt(this.hl()); + this.cycles += 7; + } + break; + case 0x6F: + { + // LD L,A + this.l = this.a; + this.cycles += 5; + } + break; + + case 0x70: + { + // LD (HL),B + this.writeByte(this.hl(), this.b); + this.cycles += 7; + } + break; + case 0x71: + { + // LD (HL),C + this.writeByte(this.hl(), this.c); + this.cycles += 7; + } + break; + case 0x72: + { + // LD (HL),D + this.writeByte(this.hl(), this.d); + this.cycles += 7; + } + break; + case 0x73: + { + // LD (HL),E + this.writeByte(this.hl(), this.e); + this.cycles += 7; + } + break; + case 0x74: + { + // LD (HL),H + this.writeByte(this.hl(), this.h); + this.cycles += 7; + } + break; + case 0x75: + { + // LD (HL),L + this.writeByte(this.hl(), this.l); + this.cycles += 7; + } + break; + case 0x76: + { + // HALT + this.cycles += 7; + this.halted = 1; + } + break; + case 0x77: + { + // LD (HL),A + this.writeByte(this.hl(), this.a); + this.cycles += 7; + } + break; + case 0x78: + { + // LD A,B + this.a = this.b; + this.cycles += 5; + } + break; + case 0x79: + { + // LD A,C + this.a = this.c; + this.cycles += 5; + } + break; + case 0x7A: + { + // LD A,D + this.a = this.d; + this.cycles += 5; + } + break; + case 0x7B: + { + // LD A,E + this.a = this.e; + this.cycles += 5; + } + break; + case 0x7C: + { + // LD A,H + this.a = this.h; + this.cycles += 5; + } + break; + case 0x7D: + { + // LD A,L + this.a = this.l; + this.cycles += 5; + } + break; + case 0x7E: + { + // LD A,(HL) + this.a = byteAt(this.hl()); + this.cycles += 7; + } + break; + case 0x7F: + { + // LD A,A + this.a = this.a; + this.cycles += 5; + } + break; + case 0x80: + { + // ADD A,B + this.a = this.addByte(this.a, this.b); + this.cycles += 4; + } + break; + case 0x81: + { + // ADD A,C + this.a = this.addByte(this.a, this.c); + this.cycles += 4; + } + break; + case 0x82: + { + // ADD A,D + this.a = this.addByte(this.a, this.d); + this.cycles += 4; + } + break; + case 0x83: + { + // ADD A,E + this.a = this.addByte(this.a, this.e); + this.cycles += 4; + } + break; + case 0x84: + { + // ADD A,H + this.a = this.addByte(this.a, this.h); + this.cycles += 4; + } + break; + case 0x85: + { + // ADD A,L + this.a = this.addByte(this.a, this.l); + this.cycles += 4; + } + break; + case 0x86: + { + // ADD A,(HL) + this.a = this.addByte(this.a, byteAt(this.hl())); + this.cycles += 7; + } + break; + case 0x87: + { + // ADD A,A + this.a = this.addByte(this.a, this.a); + this.cycles += 4; + } + break; + case 0x88: + { + // ADC A,B + this.a = this.addByteWithCarry(this.a, this.b); + this.cycles += 4; + } + break; + case 0x89: + { + // ADC A,C + this.a = this.addByteWithCarry(this.a, this.c); + this.cycles += 4; + } + break; + case 0x8A: + { + // ADC A,D + this.a = this.addByteWithCarry(this.a, this.d); + this.cycles += 4; + } + break; + case 0x8B: + { + // ADC A,E + this.a = this.addByteWithCarry(this.a, this.e); + this.cycles += 4; + } + break; + case 0x8C: + { + // ADC A,H + this.a = this.addByteWithCarry(this.a, this.h); + this.cycles += 4; + } + break; + case 0x8D: + { + // ADC A,L + this.a = this.addByteWithCarry(this.a, this.l); + this.cycles += 4; + } + break; + case 0x8E: + { + // ADC A,(HL) + this.a = this.addByteWithCarry(this.a, byteAt(this.hl())); + this.cycles += 7; + } + break; + case 0x8F: + { + // ADC A,A + this.a = this.addByteWithCarry(this.a, this.a); + this.cycles += 4; + } + break; + case 0x90: + { + // SUB B + this.a = this.subtractByte(this.a, this.b); + this.cycles += 4; + } + break; + case 0x91: + { + // SUB C + this.a = this.subtractByte(this.a, this.c); + this.cycles += 4; + } + break; + case 0x92: + { + // SUB D + this.a = this.subtractByte(this.a, this.d); + this.cycles += 4; + } + break; + case 0x93: + { + // SUB E + this.a = this.subtractByte(this.a, this.e); + this.cycles += 4; + } + break; + case 0x94: + { + // SUB H + this.a = this.subtractByte(this.a, this.h); + this.cycles += 4; + } + break; + case 0x95: + { + // SUB L + this.a = this.subtractByte(this.a, this.l); + this.cycles += 4; + } + break; + case 0x96: + { + // SUB (HL) + this.a = this.subtractByte(this.a, byteAt(this.hl())); + this.cycles += 7; + } + break; + case 0x97: + { + // SUB A + this.a = this.subtractByte(this.a, this.a); + this.cycles += 4; + } + break; + case 0x98: + { + // SBC A,B + this.a = this.subtractByteWithCarry(this.a, this.b); + this.cycles += 4; + } + break; + case 0x99: + { + // SBC A,C + this.a = this.subtractByteWithCarry(this.a, this.c); + this.cycles += 4; + } + break; + case 0x9A: + { + // SBC A,D + this.a = this.subtractByteWithCarry(this.a, this.d); + this.cycles += 4; + } + break; + case 0x9B: + { + // SBC A,E + this.a = this.subtractByteWithCarry(this.a, this.e); + this.cycles += 4; + } + break; + case 0x9C: + { + // SBC A,H + this.a = this.subtractByteWithCarry(this.a, this.h); + this.cycles += 4; + } + break; + case 0x9D: + { + // SBC A,L + this.a = this.subtractByteWithCarry(this.a, this.l); + this.cycles += 4; + } + break; + case 0x9E: + { + // SBC A,(HL) + this.a = this.subtractByteWithCarry(this.a, byteAt(this.hl())); + this.cycles += 7; + } + break; + case 0x9F: + { + // SBC A,A + this.a = this.subtractByteWithCarry(this.a, this.a); + this.cycles += 4; + } + break; + case 0xA0: + { + // AND B + this.a = this.andByte(this.a, this.b); + this.cycles += 4; + } + break; + case 0xA1: + { + // AND C + this.a = this.andByte(this.a, this.c); + this.cycles += 4; + } + break; + case 0xA2: + { + // AND D + this.a = this.andByte(this.a, this.d); + this.cycles += 4; + } + break; + case 0xA3: + { + // AND E + this.a = this.andByte(this.a, this.e); + this.cycles += 4; + } + break; + case 0xA4: + { + // AND H + this.a = this.andByte(this.a, this.h); + this.cycles += 4; + } + break; + case 0xA5: + { + // AND L + this.a = this.andByte(this.a, this.l); + this.cycles += 4; + } + break; + case 0xA6: + { + // AND (HL) + this.a = this.andByte(this.a, byteAt(this.hl())); + this.cycles += 7; + } + break; + case 0xA7: + { + // AND A + this.a = this.andByte(this.a, this.a); + this.cycles += 4; + } + break; + case 0xA8: + { + // XOR B + this.a = this.xorByte(this.a, this.b); + this.cycles += 4; + } + break; + case 0xA9: + { + // XOR C + this.a = this.xorByte(this.a, this.c); + this.cycles += 4; + } + break; + case 0xAA: + { + // XOR D + this.a = this.xorByte(this.a, this.d); + this.cycles += 4; + } + break; + case 0xAB: + { + // XOR E + this.a = this.xorByte(this.a, this.e); + this.cycles += 4; + } + break; + case 0xAC: + { + // XOR H + this.a = this.xorByte(this.a, this.h); + this.cycles += 4; + } + break; + case 0xAD: + { + // XOR L + this.a = this.xorByte(this.a, this.l); + this.cycles += 4; + } + break; + case 0xAE: + { + // XOR (HL) + this.a = this.xorByte(this.a, byteAt(this.hl())); + this.cycles += 7; + } + break; + case 0xAF: + { + // XOR A + this.a = this.xorByte(this.a, this.a); + this.cycles += 4; + } + break; + case 0xB0: + { + // OR B + this.a = this.orByte(this.a, this.b); + this.cycles += 4; + } + break; + case 0xB1: + { + // OR C + this.a = this.orByte(this.a, this.c); + this.cycles += 4; + } + break; + case 0xB2: + { + // OR D + this.a = this.orByte(this.a, this.d); + this.cycles += 4; + } + break; + case 0xB3: + { + // OR E + this.a = this.orByte(this.a, this.e); + this.cycles += 4; + } + break; + case 0xB4: + { + // OR H + this.a = this.orByte(this.a, this.h); + this.cycles += 4; + } + break; + case 0xB5: + { + // OR L + this.a = this.orByte(this.a, this.l); + this.cycles += 4; + } + break; + case 0xB6: + { + // OR (HL) + this.a = this.orByte(this.a, byteAt(this.hl())); + this.cycles += 7; + } + break; + case 0xB7: + { + // OR A + this.a = this.orByte(this.a, this.a); + this.cycles += 4; + } + break; + case 0xB8: + { + // CP B + this.subtractByte(this.a, this.b); + this.cycles += 4; + } + break; + case 0xB9: + { + // CP C + this.subtractByte(this.a, this.c); + this.cycles += 4; + } + break; + case 0xBA: + { + // CP D + this.subtractByte(this.a, this.d); + this.cycles += 4; + } + break; + case 0xBB: + { + // CP E + this.subtractByte(this.a, this.e); + this.cycles += 4; + } + break; + case 0xBC: + { + // CP H + this.subtractByte(this.a, this.h); + this.cycles += 4; + } + break; + case 0xBD: + { + // CP L + this.subtractByte(this.a, this.l); + this.cycles += 4; + } + break; + case 0xBE: + { + // CP (HL) + this.subtractByte(this.a, byteAt(this.hl())); + this.cycles += 7; + } + break; + case 0xBF: + { + // CP A + this.subtractByte(this.a, this.a); + this.cycles += 4; + } + break; + case 0xC0: + { + // RET NZ ; opcode C0 cycles 05 + if (this.f & ZERO) + this.cycles += 5; + else { + this.pc = this.pop(); + this.cycles += 11; + } + } + break; + case 0xC1: + { + // POP BC + this.BC(this.pop()); + this.cycles += 10; + } + break; + case 0xC2: + { + // JP NZ,nn + if (this.f & ZERO) { + this.pc = (this.pc + 2) & 0xFFFF; + } + else { + this.pc = this.nextWord(); + } + this.cycles += 10; + } + break; + case 0xC3: + case 0xCB: + { + // JP nn + this.pc = this.getWord(this.pc); + this.cycles += 10; + } + break; + case 0xC4: + { + // CALL NZ,nn + if (this.f & ZERO) { + this.cycles += 11; + this.pc = (this.pc + 2) & 0xFFFF; + } + else { + this.cycles += 17; + w = this.nextWord(); + this.push(this.pc); + this.pc = w; + } + } + break; + case 0xC5: + { + // PUSH BC + this.push(this.bc()); + this.cycles += 11; + } + break; + case 0xC6: + { + // ADD A,n + this.a = this.addByte(this.a, this.nextByte()); + this.cycles += 7; + } + break; + case 0xC7: + { + // RST 0 + this.push(this.pc); + this.pc = 0; + this.cycles += 11; + } + break; + case 0xC8: + { + // RET Z + if (this.f & ZERO) { + this.pc = this.pop(); + this.cycles += 11; + } + else { + this.cycles += 5; + } + } + break; + case 0xC9: + case 0xD9: + { + // RET nn + this.pc = this.pop(); + this.cycles += 10; + } + break; + case 0xCA: + { + // JP Z,nn + if (this.f & ZERO) { + this.pc = this.nextWord(); + } + else { + this.pc = (this.pc + 2) & 0xFFFF; + } + this.cycles += 10; + } + break; + case 0xCC: + { + // CALL Z,nn + if (this.f & ZERO) { + this.cycles += 17; + w = this.nextWord(); + this.push(this.pc); + this.pc = w; + } + else { + this.cycles += 11; + this.pc = (this.pc + 2) & 0xFFFF; + } + } + break; + case 0xCD: + case 0xDD: + case 0xED: + case 0xFD: + { + // CALL nn + w = this.nextWord(); + this.push(this.pc); + this.pc = w; + this.cycles += 17; + } + break; + case 0xCE: + { + // ADC A,n + this.a = this.addByteWithCarry(this.a, this.nextByte()); + this.cycles += 7; + } + break; + case 0xCF: + { + // RST 8 + this.push(this.pc); + this.pc = 8; + this.cycles += 11; + } + break; + case 0xD0: + { + // RET NC + if (this.f & CARRY) { + this.cycles += 5; + } + else { + this.pc = this.pop(); + this.cycles += 11; + } + } + break; + case 0xD1: + { + // POP DE + this.DE(this.pop()); + this.cycles += 10; + } + break; + case 0xD2: + { + // JP NC,nn + if (this.f & CARRY) { + this.pc = (this.pc + 2) & 0xFFFF; + } + else { + this.pc = this.nextWord(); + } + this.cycles += 10; + } + break; + case 0xD3: + { + // OUT (n),A + this.writePort(this.nextByte(), this.a); + this.cycles += 10; + } + break; + case 0xD4: + { + // CALL NC,nn + if (this.f & CARRY) { + this.cycles += 11; + this.pc = (this.pc + 2) & 0xFFFF; + } + else { + this.cycles += 17; + w = this.nextWord(); + this.push(this.pc); + this.pc = w; + } + } + break; + case 0xD5: + { + // PUSH DE + this.push(this.de()); + this.cycles += 11; + } + break; + case 0xD6: + { + // SUB n + this.a = this.subtractByte(this.a, this.nextByte()); + this.cycles += 7; + } + break; + case 0xD7: + { + // RST 10H + this.push(this.pc); + this.pc = 0x10; + this.cycles += 11; + } + break; + case 0xD8: + { + // RET C + if (this.f & CARRY) { + this.pc = this.pop(); + this.cycles += 11; + } + else { + this.cycles += 5; + } + } + break; + case 0xDA: + { + // JP C,nn + if (this.f & CARRY) { + this.pc = this.nextWord(); + } + else { + this.pc = (this.pc + 2) & 0xFFFF; + } + this.cycles += 10; + } + break; + case 0xDB: + { + // IN A,(n) + this.a = this.readPort(this.nextByte()); + this.cycles += 10; + } + break; + case 0xDC: + { + // CALL C,nn + if (this.f & CARRY) { + this.cycles += 17; + w = this.nextWord(); + this.push(this.pc); + this.pc = w; + } + else { + this.cycles += 11; + this.pc = (this.pc + 2) & 0xFFFF; + } + } + break; + case 0xDE: + { + // SBC A,n + this.a = this.subtractByteWithCarry(this.a, this.nextByte()); + this.cycles += 7; + } + break; + case 0xDF: + { + // RST 18H + this.push(this.pc); + this.pc = 0x18; + this.cycles += 11; + } + break; + case 0xE0: + { + // RET PO + if (this.f & PARITY) { + this.cycles += 5; + } + else { + this.pc = this.pop(); + this.cycles += 11; + } + } + break; + case 0xE1: + { + // POP HL + this.HL(this.pop()); + this.cycles += 10; + } + break; + case 0xE2: + { + // JP PO,nn + if (this.f & PARITY) { + this.pc = (this.pc + 2) & 0xFFFF; + } + else { + this.pc = this.nextWord(); + } + this.cycles += 10; + } + break; + case 0xE3: + { + // EX (SP),HL ; + var a = this.getWord(this.sp); + this.writeWord(this.sp, this.hl()); + this.HL(a); + this.cycles += 4; + } + break; + case 0xE4: + { + // CALL PO,nn + if (this.f & PARITY) { + this.cycles += 11; + this.pc = (this.pc + 2) & 0xFFFF; + } + else { + this.cycles += 17; + w = this.nextWord(); + this.push(this.pc); + this.pc = w; + } + } + break; + case 0xE5: + { + // PUSH HL + this.push(this.hl()); + this.cycles += 11; + } + break; + case 0xE6: + { + // AND n + this.a = this.andByte(this.a, this.nextByte()); + this.cycles += 7; + } + break; + case 0xE7: + { + // RST 20H + this.push(this.pc); + this.pc = 0x20; + this.cycles += 11; + } + break; + case 0xE8: + { + // RET PE + if (this.f & PARITY) { + this.pc = this.pop(); + this.cycles += 11; + } + else { + this.cycles += 5; + } + } + break; + case 0xE9: + { + // JP (HL) + this.pc = this.hl(); + this.cycles += 4; + } + break; + case 0xEA: + { + // JP PE,nn + if (this.f & PARITY) { + this.pc = this.nextWord(); + } + else { + this.pc = (this.pc + 2) & 0xFFFF; + } + this.cycles += 10; + } + break; + case 0xEB: + { + // EX DE,HL + w = this.de(); + this.DE(this.hl()); + this.HL(w); + this.cycles += 4; + } + break; + case 0xEC: + { + // CALL PE,nn + if (this.f & PARITY) { + this.cycles += 17; + w = this.nextWord(); + this.push(this.pc); + this.pc = w; + } + else { + this.cycles += 11; + this.pc = (this.pc + 2) & 0xFFFF; + } + } + break; + case 0xEE: + { + // XOR n + this.a = this.xorByte(this.a, this.nextByte()); + this.cycles += 7; + } + break; + case 0xEF: + { + // RST 28H + this.push(this.pc); + this.pc = 0x28; + this.cycles += 11; + } + break; + case 0xF0: + { + // RET P + if (this.f & SIGN) { + this.cycles += 5; + } + else { + this.pc = this.pop(); + this.cycles += 11; + } + } + break; + case 0xF1: + { + // POP AF + this.AF(this.pop()); + this.cycles += 10; + } + break; + case 0xF2: + { + // JP P,nn + if (this.f & SIGN) { + this.pc = (this.pc + 2) & 0xFFFF; + } + else { + this.pc = this.nextWord(); + } + this.cycles += 10; + } + break; + case 0xF3: + { + // DI + this.inte = 0; + this.cycles += 4; + } + break; + case 0xF4: + { + // CALL P,nn + if (this.f & SIGN) { + this.cycles += 11; + this.pc = (this.pc + 2) & 0xFFFF; + } + else { + this.cycles += 17; + w = this.nextWord(); + this.push(this.pc); + this.pc = w; + } + } + break; + case 0xF5: + { + // PUSH AF + this.push(this.af()); + this.cycles += 11; + } + break; + case 0xF6: + { + // OR n + this.a = this.orByte(this.a, this.nextByte()); + this.cycles += 7; + } + break; + case 0xF7: + { + // RST 30H + this.push(this.pc); + this.pc = 0x30; + this.cycles += 11; + } + break; + case 0xF8: + { + // RET M + if (this.f & SIGN) { + this.pc = this.pop(); + this.cycles += 11; + } + else { + this.cycles += 5; + } + } + break; + case 0xF9: + { + // LD SP,HL + this.sp = this.hl(); + this.cycles += 6; + } + break; + case 0xFA: + { + // JP M,nn + if (this.f & SIGN) { + this.pc = this.nextWord(); + } + else { + this.pc = (this.pc + 2) & 0xFFFF; + } + this.cycles += 10; + } + break; + case 0xFB: + { + // EI + this.inte = 1; + this.cycles += 4; + } + break; + case 0xFC: + { + // CALL M,nn + if (this.f & SIGN) { + this.cycles += 17; + w = this.nextWord(); + this.push(this.pc); + this.pc = w; + } + else { + this.cycles += 11; + this.pc = (this.pc + 2) & 0xFFFF; + } + } + break; + case 0xFE: + { + // CP n + this.subtractByte(this.a, this.nextByte()); + this.cycles += 7; + } + break; + case 0xFF: + { + // RST 38H + this.push(this.pc); + this.pc = 0x38; + this.cycles += 11; + } + break; + default: + { + // NOP + this.cycles += 4; + } + break; + + } + this.f &= 0xd7; + this.f |= 0x02; + +}; + +var proc, tracer=false; + +var reset = function(){ + //pc=wordAt(ResetTo); + proc.pc=0; + proc.sp=0; + proc.halted = 0; + proc.a=proc.b=proc.c=proc.d=proc.e=proc.h=proc.l=0; + proc.f=2; + proc.inte = 0; + proc.cycles=0; +}; + +var goTrace = function(proc){ + console.log(toHex4(proc.pc)); +}; + + +exports["trace"] = function(stat) {tracer = stat;}; +exports["steps"] = function(Ts){ + T=0; + + + while (Ts>0){ + + Ts-=proc.step(); + + + if (tracer) goTrace(proc); + } + }; +exports["T"] = function(){return proc.cycles;}; +exports["reset"] = reset; +exports["init"] = function(bt,ba,tck,porto,porti){ + byteTo=bt; + byteAt = ba; + ticks=tck; + portOut = porto; + portIn = porti; + proc = new Cpu(); + reset(); + }; +exports["status"] = function() { + return { + "pc":proc.pc, + "sp":proc.sp, + "a":proc.a, + "b":proc.b, + "c":proc.c, + "d":proc.d, + "e":proc.e, + "f":proc.f, + "h":proc.h, + "l":proc.l + }; + }; +exports['interrupt'] = function(vector) { + if (proc.inte) { + proc.halted = 0; + proc.push(proc.pc); + proc.pc = vector || 0x38; + } + }; +exports["set"] = function(reg,value) { + reg = reg.toUpperCase(); + switch (reg) { + case "PC": proc.pc=value;return; + case "A": proc.a=value;return; + case "B": proc.b=value;return; + case "C": proc.c=value;return; + case "D": proc.d=value;return; + case "E": proc.e=value;return; + case "H": proc.h=value;return; + case "L": proc.l=value;return; + case "F": proc.f=value;return; + case "SP": proc.sp=value;return; + } + }; + exports["flagsToString"] = function() { + var f='',fx = "SZ0A0P1C"; + for (var i=0;i<8;i++) { + var n = proc.f&(0x80>>i); + if (n===0) {f+=fx[i].toLowerCase();} else {f+=fx[i];} + } + return f; + }; + + +})(typeof exports === 'undefined'? this['CPU8080']={}: exports);