Ocean-240.2-Emulator/z80em/opcode.go

658 lines
13 KiB
Go

package z80em
var instructions = []func(s *Z80Type){
// NOP
0x00: func(s *Z80Type) {
// NOP
},
// LD BC, nn
0x01: func(s *Z80Type) {
s.PC++
s.C = s.core.MemRead(s.PC)
s.PC++
s.B = s.core.MemRead(s.PC)
},
// LD (BC), A
0x02: func(s *Z80Type) {
s.core.MemWrite(s.bc(), s.A)
},
// 0x03 : INC BC
0x03: func(s *Z80Type) {
s.incBc()
},
// 0x04 : INC B
0x04: func(s *Z80Type) {
s.B = s.doInc(s.B)
},
// 0x05 : DEC B
0x05: func(s *Z80Type) {
s.B = s.doDec(s.B)
},
// 0x06 : LD B, n
0x06: func(s *Z80Type) {
s.PC++
s.B = s.core.MemRead(s.PC)
},
// 0x07 : RLCA
0x07: func(s *Z80Type) {
// This instruction is implemented as a special case of the
// more general Z80-specific RLC instruction.
// Specifially, RLCA is a version of RLC A that affects fewer flags.
// The same applies to RRCA, RLA, and RRA.
tempS := s.Flags.S
tempZ := s.Flags.Z
tempP := s.Flags.P
s.A = s.doRlc(s.A)
s.Flags.S = tempS
s.Flags.Z = tempZ
s.Flags.P = tempP
},
// 0x08 : EX AF, AF'
0x08: func(s *Z80Type) {
s.A, s.AAlt = s.AAlt, s.A
temp := s.getFlagsRegister()
s.setFlagsRegister(s.getFlagsPrimeRegister())
s.setFlagsPrimeRegister(temp)
},
// 0x09 : ADD HL, BC
0x09: func(s *Z80Type) {
s.doHlAdd(s.bc())
},
// 0x0a : LD A, (BC)
0x0A: func(s *Z80Type) {
s.A = s.core.MemRead(s.bc())
},
// 0x0b : DEC BC
0x0B: func(s *Z80Type) {
s.decBc()
},
// 0x0c : INC C
0x0C: func(s *Z80Type) {
s.C = s.doInc(s.C)
},
// 0x0d : DEC C
0x0D: func(s *Z80Type) {
s.C = s.doDec(s.C)
},
// 0x0e : LD C, n
0x0E: func(s *Z80Type) {
s.PC++
s.C = s.core.MemRead(s.PC)
},
// 0x0f : RRCA
0x0F: func(s *Z80Type) {
tempS := s.Flags.S
tempZ := s.Flags.Z
tempP := s.Flags.P
s.A = s.doRrc(s.A)
s.Flags.S = tempS
s.Flags.Z = tempZ
s.Flags.P = tempP
},
// 0x10 : DJNZ nn
0x10: func(s *Z80Type) {
s.B--
s.doConditionalRelativeJump(s.B != 0)
},
// 0x11 : LD DE, nn
0x11: func(s *Z80Type) {
s.PC++
s.E = s.core.MemRead(s.PC)
s.PC++
s.D = s.core.MemRead(s.PC)
},
// 0x12 : LD (DE), A
0x12: func(s *Z80Type) {
s.core.MemWrite(s.de(), s.A)
},
// 0x13 : INC DE
0x13: func(s *Z80Type) {
s.incDe()
},
// 0x14 : INC D
0x14: func(s *Z80Type) {
s.D = s.doInc(s.D)
},
// 0x15 : DEC D
0x15: func(s *Z80Type) {
s.D = s.doDec(s.D)
},
// 0x16 : LD D, n
0x16: func(s *Z80Type) {
s.PC++
s.D = s.core.MemRead(s.PC)
},
// 0x17 : RLA
0x17: func(s *Z80Type) {
tempS := s.Flags.S
tempZ := s.Flags.Z
tempP := s.Flags.P
s.A = s.doRl(s.A)
s.Flags.S = tempS
s.Flags.Z = tempZ
s.Flags.P = tempP
},
// 0x18 : JR n
0x18: func(s *Z80Type) {
var o = int8(s.core.MemRead(s.PC + 1))
if o > 0 {
s.PC += uint16(o)
} else {
s.PC -= uint16(-o)
}
s.PC++
},
// 0x19 : ADD HL, DE
0x19: func(s *Z80Type) {
s.doHlAdd(s.de())
},
// 0x1a : LD A, (DE)
0x1A: func(s *Z80Type) {
s.A = s.core.MemRead(s.de())
},
// 0x1b : DEC DE
0x1B: func(s *Z80Type) {
s.decDe()
},
// 0x1c : INC E
0x1C: func(s *Z80Type) {
s.E = s.doInc(s.E)
},
// 0x1d : DEC E
0x1D: func(s *Z80Type) {
s.E = s.doDec(s.E)
},
// 0x1e : LD E, n
0x1E: func(s *Z80Type) {
s.PC++
s.E = s.core.MemRead(s.PC)
},
// 0x1f : RRA
0x1F: func(s *Z80Type) {
tempS := s.Flags.S
tempZ := s.Flags.Z
tempP := s.Flags.P
s.A = s.doRr(s.A)
s.Flags.S = tempS
s.Flags.Z = tempZ
s.Flags.P = tempP
},
// 0x20 : JR NZ, n
0x20: func(s *Z80Type) {
s.doConditionalRelativeJump(!s.Flags.Z)
},
// 0x21 : LD HL, nn
0x21: func(s *Z80Type) {
s.PC++
s.L = s.core.MemRead(s.PC)
s.PC++
s.H = s.core.MemRead(s.PC)
},
// 0x22 : LD (nn), HL
0x22: func(s *Z80Type) {
addr := s.nextWord()
s.core.MemWrite(addr, s.L)
s.core.MemWrite(addr+1, s.H)
},
// 0x23 : INC HL
0x23: func(s *Z80Type) {
s.incHl()
},
// 0x24 : INC H
0x24: func(s *Z80Type) {
s.H = s.doInc(s.H)
},
// 0x25 : DEC H
0x25: func(s *Z80Type) {
s.H = s.doDec(s.H)
},
// 0x26 : LD H, n
0x26: func(s *Z80Type) {
s.PC++
s.H = s.core.MemRead(s.PC)
},
// 0x27 : DAA
0x27: func(s *Z80Type) {
temp := s.A
if !s.Flags.N {
if s.Flags.H || ((s.A & 0x0f) > 9) {
temp += 0x06
}
if s.Flags.C || (s.A > 0x99) {
temp += 0x60
}
} else {
if s.Flags.H || ((s.A & 0x0f) > 9) {
temp -= 0x06
}
if s.Flags.C || (s.A > 0x99) {
temp -= 0x60
}
}
s.Flags.S = (temp & 0x80) != 0
s.Flags.Z = temp == 0
s.Flags.H = ((s.A & 0x10) ^ (temp & 0x10)) != 0
s.Flags.P = ParityBits[temp]
// DAA never clears the carry flag if it was already set,
// but it is able to set the carry flag if it was clear.
// Don't ask me, I don't know.
// Note also that we check for a BCD carry, instead of the usual.
s.Flags.C = s.Flags.C || (s.A > 0x99)
s.A = temp
s.updateXYFlags(s.A)
},
// 0x28 : JR Z, n
0x28: func(s *Z80Type) {
s.doConditionalRelativeJump(s.Flags.Z)
},
// 0x29 : ADD HL, HL
0x29: func(s *Z80Type) {
s.doHlAdd(s.hl())
},
// 0x2a : LD HL, (nn)
0x2A: func(s *Z80Type) {
addr := s.nextWord()
s.L = s.core.MemRead(addr)
s.H = s.core.MemRead(addr + 1)
},
// 0x2b : DEC HL
0x2B: func(s *Z80Type) {
s.decHl()
},
// 0x2c : INC L
0x2C: func(s *Z80Type) {
s.L = s.doInc(s.L)
},
// 0x2d : DEC L
0x2D: func(s *Z80Type) {
s.L = s.doDec(s.L)
},
// 0x2e : LD L, n
0x2E: func(s *Z80Type) {
s.PC++
s.L = s.core.MemRead(s.PC)
},
// 0x2f : CPL
0x2F: func(s *Z80Type) {
s.A = ^s.A
s.Flags.N = true
s.Flags.H = true
s.updateXYFlags(s.A)
},
// 0x30 : JR NC, n
0x30: func(s *Z80Type) {
s.doConditionalRelativeJump(!s.Flags.C)
},
// 0x31 : LD SP, nn
0x31: func(s *Z80Type) {
s.PC++
lo := s.core.MemRead(s.PC)
s.PC++
s.SP = (uint16(s.core.MemRead(s.PC)) << 8) | uint16(lo)
},
// 0x32 : LD (nn), A
0x32: func(s *Z80Type) {
s.core.MemWrite(s.nextWord(), s.A)
},
// 0x33 : INC SP
0x33: func(s *Z80Type) {
s.SP++
},
// 0x34 : INC (HL)
0x34: func(s *Z80Type) {
s.core.MemWrite(s.hl(), s.doInc(s.core.MemRead(s.hl())))
},
// 0x35 : DEC (HL)
0x35: func(s *Z80Type) {
s.core.MemWrite(s.hl(), s.doDec(s.core.MemRead(s.hl())))
},
// 0x36 : LD (HL), n
0x36: func(s *Z80Type) {
s.PC++
s.core.MemWrite(s.hl(), s.core.MemRead(s.PC))
},
// 0x37 : SCF
0x37: func(s *Z80Type) {
s.Flags.N = false
s.Flags.H = false
s.Flags.C = true
s.updateXYFlags(s.A)
},
// 0x38 : JR C, n
0x38: func(s *Z80Type) {
s.doConditionalRelativeJump(s.Flags.C)
},
// 0x39 : ADD HL, SP
0x39: func(s *Z80Type) {
s.doHlAdd(s.SP)
},
// 0x3a : LD A, (nn)
0x3A: func(s *Z80Type) {
s.A = s.core.MemRead(s.nextWord())
},
// 0x3b : DEC SP
0x3B: func(s *Z80Type) {
s.SP--
},
// 0x3c : INC A
0x3C: func(s *Z80Type) {
s.A = s.doInc(s.A)
},
// 0x3d : DEC A
0x3D: func(s *Z80Type) {
s.A = s.doDec(s.A)
},
// 0x3e : LD A, n
0x3E: func(s *Z80Type) {
s.PC++
s.A = s.core.MemRead(s.PC)
},
// 0x3f : CCF
0x3F: func(s *Z80Type) {
s.Flags.N = false
s.Flags.H = s.Flags.C
s.Flags.C = !s.Flags.C
s.updateXYFlags(s.A)
},
// 0xc0 : RET NZ
0xC0: func(s *Z80Type) {
s.doConditionalReturn(!s.Flags.Z)
},
// 0xc1 : POP BC
0xC1: func(s *Z80Type) {
result := s.PopWord()
s.C = byte(result & 0xff)
s.B = byte((result & 0xff00) >> 8)
},
// 0xc2 : JP NZ, nn
0xC2: func(s *Z80Type) {
s.doConditionalAbsoluteJump(!s.Flags.Z)
},
// 0xc3 : JP nn
0xC3: func(s *Z80Type) {
s.PC = uint16(s.core.MemRead(s.PC+1)) | (uint16(s.core.MemRead(s.PC+2)) << 8)
s.PC--
},
// 0xc4 : CALL NZ, nn
0xC4: func(s *Z80Type) {
s.doConditionalCall(!s.Flags.Z)
},
// 0xc5 : PUSH BC
0xC5: func(s *Z80Type) {
s.pushWord((uint16(s.B) << 8) | uint16(s.C))
},
// 0xc6 : ADD A, n
0xC6: func(s *Z80Type) {
s.PC++
s.doAdd(s.core.MemRead(s.PC))
},
// 0xc7 : RST 00h
0xC7: func(s *Z80Type) {
s.doReset(0x0000)
},
// 0xc8 : RET Z
0xC8: func(s *Z80Type) {
s.doConditionalReturn(s.Flags.Z)
},
// 0xc9 : RET
0xC9: func(s *Z80Type) {
s.PC = s.PopWord() - 1
},
// 0xca : JP Z, nn
0xCA: func(s *Z80Type) {
s.doConditionalAbsoluteJump(s.Flags.Z)
},
// 0xcb : CB Prefix
0xCB: func(s *Z80Type) {
s.opcodeCB()
},
// 0xcc : CALL Z, nn
0xCC: func(s *Z80Type) {
s.doConditionalCall(s.Flags.Z)
},
// 0xcd : CALL nn
0xCD: func(s *Z80Type) {
s.pushWord(s.PC + 3)
s.PC = uint16(s.core.MemRead(s.PC+1)) | (uint16(s.core.MemRead(s.PC+2)) << 8)
s.PC--
},
// 0xce : ADC A, n
0xCE: func(s *Z80Type) {
s.PC++
s.doAdc(s.core.MemRead(s.PC))
},
// 0xcf : RST 08h
0xCF: func(s *Z80Type) {
s.doReset(0x0008)
},
// 0xd0 : RET NC
0xD0: func(s *Z80Type) {
s.doConditionalReturn(!s.Flags.C)
},
// 0xd1 : POP DE
0xD1: func(s *Z80Type) {
result := s.PopWord()
s.E = byte(result & 0xff)
s.D = byte((result & 0xff00) >> 8)
},
// 0xd2 : JP NC, nn
0xD2: func(s *Z80Type) {
s.doConditionalAbsoluteJump(!s.Flags.C)
},
// 0xd3 : OUT (n), A
0xD3: func(s *Z80Type) {
s.PC++
s.core.IOWrite((uint16(s.A)<<8)|uint16(s.core.MemRead(s.PC)), s.A)
},
// 0xd4 : CALL NC, nn
0xD4: func(s *Z80Type) {
s.doConditionalCall(!s.Flags.C)
},
// 0xd5 : PUSH DE
0xD5: func(s *Z80Type) {
s.pushWord((uint16(s.D) << 8) | uint16(s.E))
},
// 0xd6 : SUB n
0xD6: func(s *Z80Type) {
s.PC++
s.doSub(s.core.MemRead(s.PC))
},
// 0xd7 : RST 10h
0xD7: func(s *Z80Type) {
s.doReset(0x0010)
},
// 0xd8 : RET C
0xD8: func(s *Z80Type) {
s.doConditionalReturn(s.Flags.C)
},
// 0xd9 : EXX
0xD9: func(s *Z80Type) {
s.B, s.BAlt = s.BAlt, s.B
s.C, s.CAlt = s.CAlt, s.C
s.D, s.DAlt = s.DAlt, s.D
s.E, s.EAlt = s.EAlt, s.E
s.H, s.HAlt = s.HAlt, s.H
s.L, s.LAlt = s.LAlt, s.L
},
// 0xda : JP C, nn
0xDA: func(s *Z80Type) {
s.doConditionalAbsoluteJump(s.Flags.C)
},
// 0xdb : IN A, (n)
0xDB: func(s *Z80Type) {
s.PC++
s.A = s.core.IORead((uint16(s.A) << 8) | uint16(s.core.MemRead(s.PC)))
},
// 0xdc : CALL C, nn
0xDC: func(s *Z80Type) {
s.doConditionalCall(s.Flags.C)
},
// 0xdd : DD Prefix (IX instructions)
0xDD: func(s *Z80Type) {
s.opcodeDD()
},
// 0xde : SBC n
0xDE: func(s *Z80Type) {
s.PC++
s.doSbc(s.core.MemRead(s.PC))
},
// 0xdf : RST 18h
0xDF: func(s *Z80Type) {
s.doReset(0x0018)
},
// 0xe0 : RET PO
0xE0: func(s *Z80Type) {
s.doConditionalReturn(!s.Flags.P)
},
// 0xe1 : POP HL
0xE1: func(s *Z80Type) {
result := s.PopWord()
s.L = byte(result & 0xff)
s.H = byte((result & 0xff00) >> 8)
},
// 0xe2 : JP PO, (nn)
0xE2: func(s *Z80Type) {
s.doConditionalAbsoluteJump(!s.Flags.P)
},
// 0xe3 : EX (SP), HL
0xE3: func(s *Z80Type) {
temp := s.core.MemRead(s.SP)
s.core.MemWrite(s.SP, s.L)
s.L = temp
temp = s.core.MemRead(s.SP + 1)
s.core.MemWrite(s.SP+1, s.H)
s.H = temp
},
// 0xe4 : CALL PO, nn
0xE4: func(s *Z80Type) {
s.doConditionalCall(!s.Flags.P)
},
// 0xe5 : PUSH HL
0xE5: func(s *Z80Type) {
s.pushWord((uint16(s.H) << 8) | uint16(s.L))
},
// 0xe6 : AND n
0xE6: func(s *Z80Type) {
s.PC++
s.doAnd(s.core.MemRead(s.PC))
},
// 0xe7 : RST 20h
0xE7: func(s *Z80Type) {
s.doReset(0x0020)
},
// 0xe8 : RET PE
0xE8: func(s *Z80Type) {
s.doConditionalReturn(s.Flags.P)
},
// 0xe9 : JP (HL)
0xE9: func(s *Z80Type) {
s.PC = uint16(s.H)<<8 | uint16(s.L)
s.PC--
},
// 0xea : JP PE, nn
0xEA: func(s *Z80Type) {
s.doConditionalAbsoluteJump(s.Flags.P)
},
// 0xeb : EX DE, HL
0xEB: func(s *Z80Type) {
s.D, s.H = s.H, s.D
s.E, s.L = s.L, s.E
},
// 0xec : CALL PE, nn
0xEC: func(s *Z80Type) {
s.doConditionalCall(s.Flags.P)
},
// 0xed : ED Prefix
0xED: func(s *Z80Type) {
s.opcodeED()
},
// 0xee : XOR n
0xEE: func(s *Z80Type) {
s.PC++
s.doXor(s.core.MemRead(s.PC))
},
// 0xef : RST 28h
0xEF: func(s *Z80Type) {
s.doReset(0x0028)
},
// 0xf0 : RET P
0xF0: func(s *Z80Type) {
s.doConditionalReturn(!s.Flags.S)
},
// 0xf1 : POP AF
0xF1: func(s *Z80Type) {
var result = s.PopWord()
s.setFlagsRegister(byte(result & 0xff))
s.A = byte((result & 0xff00) >> 8)
},
// 0xf2 : JP P, nn
0xF2: func(s *Z80Type) {
s.doConditionalAbsoluteJump(!s.Flags.S)
},
// 0xf3 : DI
0xF3: func(s *Z80Type) {
// DI doesn't actually take effect until after the next instruction.
s.DoDelayedDI = true
},
// 0xf4 : CALL P, nn
0xF4: func(s *Z80Type) {
s.doConditionalCall(!s.Flags.S)
},
// 0xf5 : PUSH AF
0xF5: func(s *Z80Type) {
s.pushWord(uint16(s.getFlagsRegister()) | (uint16(s.A) << 8))
},
// 0xf6 : OR n
0xF6: func(s *Z80Type) {
s.PC++
s.doOr(s.core.MemRead(s.PC))
},
// 0xf7 : RST 30h
0xF7: func(s *Z80Type) {
s.doReset(0x0030)
},
// 0xf8 : RET M
0xF8: func(s *Z80Type) {
s.doConditionalReturn(s.Flags.S)
},
// 0xf9 : LD SP, HL
0xF9: func(s *Z80Type) {
s.SP = uint16(s.H)<<8 | uint16(s.L)
},
// 0xfa : JP M, nn
0xFA: func(s *Z80Type) {
s.doConditionalAbsoluteJump(s.Flags.S)
},
// 0xfb : EI
0xFB: func(s *Z80Type) {
// EI doesn't actually take effect until after the next instruction.
s.DoDelayedEI = true
},
// 0xfc : CALL M, nn
0xFC: func(s *Z80Type) {
s.doConditionalCall(s.Flags.S)
},
// 0xfd : FD Prefix (IY instructions)
0xFD: func(s *Z80Type) {
s.opcodeFD()
},
// 0xfe : CP n
0xFE: func(s *Z80Type) {
s.PC++
s.doCp(s.core.MemRead(s.PC))
},
// 0xff : RST 38h
0xFF: func(s *Z80Type) {
s.doReset(0x0038)
},
}
func (z *Z80Type) nextWord() uint16 {
z.PC++
word := uint16(z.core.MemRead(z.PC))
z.PC++
word |= uint16(z.core.MemRead(z.PC)) << 8
return word
}