Ocean-240.2-Emulator/z80/js/cpu.go

900 lines
20 KiB
Go

package js
import (
"fmt"
"okemu/z80"
log "github.com/sirupsen/logrus"
)
type Z80 struct {
z80.Z80CPU
core z80.MemIoRW
}
func (z *Z80) Reset() {
z.A = 0
z.R = 0
z.SP = 0xff
z.PC = 0
z.Flags.SetFlags(0xff)
// Interrupts disabled
z.IMode = 0
z.Iff1 = false
z.Iff2 = false
z.InterruptOccurred = false
// Start not halted
z.Halted = false
z.DoDelayedDI = false
z.DoDelayedEI = false
// no cycles
z.CycleCounter = 0
fmt.Println("CPUInterface State Reset")
}
func (z *Z80) GetState() *z80.Z80CPU {
return &z80.Z80CPU{
A: z.A,
B: z.B,
C: z.C,
D: z.D,
E: z.E,
H: z.H,
L: z.L,
AAlt: z.AAlt,
BAlt: z.BAlt,
CAlt: z.CAlt,
DAlt: z.DAlt,
EAlt: z.EAlt,
HAlt: z.HAlt,
IX: z.IX,
IY: z.IY,
R: z.R,
SP: z.SP,
PC: z.PC,
Flags: z.Flags,
FlagsAlt: z.FlagsAlt,
IMode: z.IMode,
Iff1: z.Iff1,
Iff2: z.Iff2,
Halted: z.Halted,
DoDelayedDI: z.DoDelayedDI,
DoDelayedEI: z.DoDelayedEI,
CycleCounter: z.CycleCounter,
}
}
func (z *Z80) SetState(state *Z80) {
z.A = state.A
z.B = state.B
z.C = state.C
z.D = state.D
z.E = state.E
z.H = state.H
z.L = state.L
z.AAlt = state.AAlt
z.BAlt = state.BAlt
z.CAlt = state.CAlt
z.DAlt = state.DAlt
z.EAlt = state.EAlt
z.HAlt = state.HAlt
z.IX = state.IX
z.IY = state.IY
z.I = state.I
z.R = state.R
z.SP = state.SP
z.PC = state.PC
z.Flags = state.Flags
z.FlagsAlt = state.FlagsAlt
z.IMode = state.IMode
z.Iff1 = state.Iff1
z.Iff2 = state.Iff2
z.Halted = state.Halted
z.DoDelayedDI = state.DoDelayedDI
z.DoDelayedEI = state.DoDelayedEI
z.CycleCounter = state.CycleCounter
}
// New Create new
func New(memIoRW z80.MemIoRW) *Z80 {
return &Z80{
Z80CPU: z80.Z80CPU{
A: 0,
B: 0,
C: 0,
D: 0,
E: 0,
H: 0,
L: 0,
AAlt: 0,
BAlt: 0,
CAlt: 0,
DAlt: 0,
EAlt: 0,
HAlt: 0,
IX: 0,
IY: 0,
I: 0,
R: 0,
SP: 0xffff,
PC: 0,
Flags: z80.FlagsType{S: true, Z: true, Y: true, H: true, X: true, P: true, N: true, C: true},
FlagsAlt: z80.FlagsType{S: true, Z: true, Y: true, H: true, X: true, P: true, N: true, C: true},
IMode: 0,
Iff1: false,
Iff2: false,
Halted: false,
DoDelayedDI: false,
DoDelayedEI: false,
CycleCounter: 0,
InterruptOccurred: false,
},
core: memIoRW,
}
}
func (z *Z80) RunInstruction() uint64 {
z.incR()
if !z.Halted {
// If the previous instruction was a DI or an EI,
// we'll need to disable or enable interrupts
// after whatever instruction we're about to run is finished.
doingDelayedDi := false
doingDelayedEi := false
if z.DoDelayedDI {
z.DoDelayedDI = false
doingDelayedDi = true
} else if z.DoDelayedEI {
z.DoDelayedEI = false
doingDelayedEi = true
}
// Read the byte at the PC and run the instruction it encodes.
opcode := z.core.M1MemRead(z.PC)
z.decodeInstruction(opcode)
// HALT does not increase the PC
if !z.Halted {
z.PC++
}
// Actually do the delayed interrupt disable/enable if we have one.
if doingDelayedDi {
z.Iff1 = false
z.Iff2 = false
} else if doingDelayedEi {
z.Iff1 = true
z.Iff2 = true
}
// And finally clear out the cycle counter for the next instruction
// before returning it to the emulator core.
cycleCounter := z.CycleCounter
z.CycleCounter = 0
return uint64(cycleCounter)
}
// HALTED
// During HALT, NOPs are executed which is 4T
z.core.M1MemRead(z.PC) // HALT does a normal M1 fetch to keep the memory refresh active. The result is ignored (NOP).
return 4
}
// Simulates pulsing the processor's INT (or NMI) pin
//
// nonMaskable - true if this is a non-maskable interrupt
// data - the value to be placed on the data bus, if needed
func (z *Z80) interrupt(nonMaskable bool, data byte) {
if nonMaskable {
// An interrupt, if halted, does increase the PC
if z.Halted {
z.PC++
}
// The high bit of R is not affected by this increment,
// it can only be changed using the LD R, A instruction.
z.incR()
// Non-maskable interrupts are always handled the same way;
// clear IFF1 and then do a CALL 0x0066.
// Also, all interrupts reset the HALT state.
z.Halted = false
z.Iff2 = z.Iff1
z.Iff1 = false
z.pushWord(z.PC)
z.PC = 0x66
z.CycleCounter += 11
} else if z.Iff1 {
// An interrupt, if halted, does increase the PC
if z.Halted {
z.PC++
}
// The high bit of R is not affected by this increment,
// it can only be changed using the LD R,A instruction.
z.incR()
z.Halted = false
z.Iff1 = false
z.Iff2 = false
if z.IMode == 0 {
// In the 8080-compatible interrupt mode,
// decode the content of the data bus as an instruction and run it.
// it'z probably a RST instruction, which pushes (PC+1) onto the stack
// so we should decrement PC before we decode the instruction
z.PC--
z.decodeInstruction(data)
z.PC++ // increment PC upon return
z.CycleCounter += 2
} else if z.IMode == 1 {
// Mode 1 is always just RST 0x38.
z.pushWord(z.PC)
z.PC = 0x0038
z.CycleCounter += 13
} else if z.IMode == 2 {
// Mode 2 uses the value on the data bus as in index
// into the vector table pointer to by the I register.
z.pushWord(z.PC)
// The Z80 manual says that this address must be 2-byte aligned,
// but it doesn't appear that this is actually the case on the hardware,
// so we don't attempt to enforce that here.
vectorAddress := (uint16(z.I) << 8) | uint16(data)
z.PC = z.getWord(vectorAddress) //uint16( z.core.MemRead(vectorAddress)) | (uint16(z.core.MemRead(vectorAddress+1)) << 8)
z.CycleCounter += 19
// A "notification" is generated so that the calling program can break on it.
z.InterruptOccurred = true
}
}
}
func (z *Z80) pushWord(operand uint16) {
z.SP--
z.core.MemWrite(z.SP, byte(operand>>8))
z.SP--
z.core.MemWrite(z.SP, byte(operand&0x00ff))
}
func (z *Z80) getOperand(opcode byte) byte {
switch opcode & 0x07 {
case 0:
return z.B
case 1:
return z.C
case 2:
return z.D
case 3:
return z.E
case 4:
return z.H
case 5:
return z.L
case 6:
return z.core.MemRead(z.hl())
default:
return z.A
}
}
func (z *Z80) decodeInstruction(opcode byte) {
// Handle HALT right up front, because it fouls up our LD decoding
// by falling where LD (HL), (HL) ought to be.
if opcode == OpHalt {
z.Halted = true
} else if opcode >= OpLdBB && opcode < OpAddAB {
// 8-bit register loads.
z.load8bit(opcode, z.getOperand(opcode))
} else if (opcode >= OpAddAB) && (opcode < OpRetNz) {
// 8-bit register ALU instructions.
z.alu8bit(opcode, z.getOperand(opcode))
} else {
fun := instructions[opcode]
fun(z)
}
z.CycleCounter += CycleCounts[opcode]
}
func (z *Z80) load8bit(opcode byte, operand byte) {
switch (opcode & 0x38) >> 3 {
case 0:
z.B = operand
case 1:
z.C = operand
case 2:
z.D = operand
case 3:
z.E = operand
case 4:
z.H = operand
case 5:
z.L = operand
case 6:
z.core.MemWrite(z.hl(), operand)
default:
z.A = operand
}
}
// alu8bit Handle ALU Operations, ADD, ADC SUB, SBC, AND, XOR, OR
func (z *Z80) alu8bit(opcode byte, operand byte) {
switch (opcode & 0x38) >> 3 {
case 0:
z.doAdd(operand)
case 1:
z.doAdc(operand)
case 2:
z.doSub(operand)
case 3:
z.doSbc(operand)
case 4:
z.doAnd(operand)
case 5:
z.doXor(operand)
case 6:
z.doOr(operand)
default:
z.doCp(operand)
}
}
// updateXYFlags Set flags X and Y based on result bits
func (z *Z80) updateXYFlags(result byte) {
z.Flags.Y = result&0x20 != 0
z.Flags.X = result&0x08 != 0
}
// PushWord - Decrement stack pointer and put specified word value to stack
func (z *Z80) PushWord(operand uint16) {
z.SP--
z.core.MemWrite(z.SP, byte((operand&0xff00)>>8))
z.SP--
z.core.MemWrite(z.SP, byte(operand&0x00ff))
}
// PopWord - Get word value from top of stack and increment stack pointer
func (z *Z80) PopWord() uint16 {
result := uint16(z.core.MemRead(z.SP))
z.SP++
result |= uint16(z.core.MemRead(z.SP)) << 8
z.SP++
return result
}
// doConditionalAbsoluteJump - Implements the JP [condition],nn instructions.
func (z *Z80) doConditionalAbsoluteJump(condition bool) {
if condition {
// We're taking this jump, so write the new PC,
// and then decrement the thing we just wrote,
// because the instruction decoder increments the PC
// unconditionally at the end of every instruction,
// and we need to counteract that so we end up at the jump target.
z.PC = z.getWord(z.PC + 1) //uint16( z.core.MemRead(z.PC+1)) | (uint16(z.core.MemRead(z.PC+2)) << 8)
z.PC--
} else {
// We're not taking this jump, just move the PC past the operand.
z.PC += 2
}
}
// doConditionalRelativeJump - Implements the JR [condition],nn instructions.
func (z *Z80) doConditionalRelativeJump(condition bool) {
if condition {
// We need a few more cycles to actually take the jump.
z.CycleCounter += 5
// Calculate the offset specified by our operand.
offset := z.core.MemRead(z.PC + 1)
// Add the offset to the PC, also skipping past this instruction.
if offset < 0 {
z.PC = z.PC - uint16(-offset)
} else {
z.PC = z.PC + uint16(offset)
}
}
z.PC++
}
// doConditionalCall - Implements CALL [condition],nn instructions.
func (z *Z80) doConditionalCall(condition bool) {
if condition {
z.CycleCounter += 7
z.PushWord(z.PC + 3)
z.PC = z.getWord(z.PC + 1) // uint16( z.core.MemRead(z.PC+1)) | (uint16(z.core.MemRead(z.PC+2)) << 8)
z.PC--
} else {
z.PC += 2
}
}
func (z *Z80) doConditionalReturn(condition bool) {
if condition {
z.CycleCounter += 6
z.PC = z.PopWord() - 1
}
}
// doReset - Implements RST [address] instructions.
func (z *Z80) doReset(address uint16) {
z.PushWord(z.PC + 1)
z.PC = address - 1
}
// doAdd Handle ADD A, [operand] instructions.
func (z *Z80) doAdd(operand byte) {
var result = uint16(z.A) + uint16(operand)
z.Flags.S = result&0x80 != 0
z.Flags.Z = result&0x00ff == 0
z.Flags.H = (((operand & 0x0f) + (z.A & 0x0f)) & 0x10) != 0
z.Flags.P = ((z.A & 0x80) == (operand & 0x80)) && (z.A&0x80 != byte(result&0x80))
z.Flags.N = false
z.Flags.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A)
}
// doAdc Handle ADC A, [operand] instructions.
func (z *Z80) doAdc(operand byte) {
add := byte(0)
if z.Flags.C {
add = 1
}
var result = uint16(z.A) + uint16(operand) + uint16(add)
z.Flags.S = result&0x80 != 0
z.Flags.Z = result&0x00ff == 0
z.Flags.H = (((operand & 0x0f) + (z.A & 0x0f) + add) & 0x10) != 0
z.Flags.P = ((z.A & 0x80) == (operand & 0x80)) && (z.A&0x80 != byte(result&0x80))
z.Flags.N = false
z.Flags.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A)
}
// doSub Handle SUB A, [operand] instructions.
func (z *Z80) doSub(operand byte) {
var result = uint16(z.A) - uint16(operand)
z.Flags.S = result&0x80 != 0
z.Flags.Z = result&0x00ff == 0
z.Flags.H = (((z.A & 0x0f) - (operand & 0x0f)) & 0x10) != 0
z.Flags.P = ((z.A & 0x80) != (operand & 0x80)) && ((z.A & 0x80) != byte(result&0x80))
z.Flags.N = true
z.Flags.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A)
}
// doSbc Handle SBC A, [operand] instructions.
func (z *Z80) doSbc(operand byte) {
sub := byte(0)
if z.Flags.C {
sub = 1
}
var result = uint16(z.A) - uint16(operand) - uint16(sub)
z.Flags.S = result&0x80 != 0
z.Flags.Z = result&0x00ff == 0
z.Flags.H = (((z.A & 0x0f) - (operand & 0x0f) - sub) & 0x10) != 0
z.Flags.P = ((z.A & 0x80) != (operand & 0x80)) && (z.A&0x80 != byte(result&0x80))
z.Flags.N = true
z.Flags.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A)
}
// setLogicFlags Set common flags for logic ALU Ops
func (z *Z80) setLogicFlags() {
z.Flags.S = z.A&0x80 != 0
z.Flags.Z = z.A == 0
z.Flags.P = ParityBits[z.A]
z.Flags.N = false
z.Flags.C = false
}
// doAnd handle AND [operand] instructions.
func (z *Z80) doAnd(operand byte) {
z.A &= operand
z.setLogicFlags()
z.Flags.H = true
z.updateXYFlags(z.A)
}
// doXor handle XOR [operand] instructions.
func (z *Z80) doXor(operand byte) {
z.A ^= operand
z.setLogicFlags()
z.Flags.H = false
z.updateXYFlags(z.A)
}
// doOr handle OR [operand] instructions.
func (z *Z80) doOr(operand byte) {
z.A |= operand
z.setLogicFlags()
z.Flags.H = false
z.updateXYFlags(z.A)
}
// doCp handle CP [operand] instructions.
func (z *Z80) doCp(operand byte) {
tmp := z.A
z.doSub(operand)
z.A = tmp
z.updateXYFlags(operand)
}
// doInc handle INC [operand] instructions.
func (z *Z80) doInc(operand byte) byte {
var result = uint16(operand) + 1
r8 := byte(result & 0xff)
z.Flags.S = r8&0x80 != 0
z.Flags.Z = r8 == 0
z.Flags.H = (operand & 0x0f) == 0x0f
z.Flags.P = operand == 0x7f
z.Flags.N = false
z.updateXYFlags(r8)
return r8
}
// doDec handle DEC [operand] instructions.
func (z *Z80) doDec(operand byte) byte {
var result = uint16(operand) - 1
r8 := byte(result & 0xff)
z.Flags.S = r8&0x80 != 0
z.Flags.Z = r8 == 0
z.Flags.H = (operand & 0x0f) == 0x00
z.Flags.P = operand == 0x80
z.Flags.N = true
z.updateXYFlags(r8)
return r8
}
// doHlAdd handle ADD HL,[operand] instructions.
func (z *Z80) doHlAdd(operand uint16) {
// The HL arithmetic instructions are the same as the A ones,
// just with twice as many bits happening.
hl := z.hl() //uint16(z.L) | (uint16(z.H) << 8)
result := uint32(hl) + uint32(operand)
z.Flags.N = false
z.Flags.C = result > 0xffff
z.Flags.H = ((hl&0x0fff)+(operand&0x0fff))&0x1000 > 0
z.setHl(uint16(result))
z.updateXYFlags(z.H)
}
// doHlAdc handle ADC HL,[operand] instructions.
func (z *Z80) doHlAdc(operand uint16) {
if z.Flags.C {
operand++
}
hl := z.hl()
result := uint32(hl) + uint32(operand)
z.Flags.S = (result & 0x8000) != 0
z.Flags.Z = result&0xffff == 0
z.Flags.H = (((hl & 0x0fff) + (operand & 0x0fff)) & 0x1000) != 0
z.Flags.P = ((hl & 0x8000) == (operand & 0x8000)) && (uint16(result&0x8000) != (hl & 0x8000))
z.Flags.N = false
z.Flags.C = result > 0xffff
z.setHl(uint16(result))
z.updateXYFlags(z.H)
}
// doHlSbc handle SBC HL,[operand] instructions.
func (z *Z80) doHlSbc(operand uint16) {
if z.Flags.C {
operand++
}
hl := z.hl() //uint16(z.L) | (uint16(z.H) << 8)
result := uint32(hl) - uint32(operand)
z.Flags.S = (result & 0x8000) != 0
z.Flags.Z = result&0xffff == 0
z.Flags.H = (((hl & 0x0fff) - (operand & 0x0fff)) & 0x1000) != 0
z.Flags.P = ((hl & 0x8000) != (operand & 0x8000)) && (uint16(result&0x8000) != (hl & 0x8000))
z.Flags.N = true
z.Flags.C = result > 0xffff
z.setHl(uint16(result))
z.updateXYFlags(z.H)
}
func (z *Z80) doIn(port uint16) byte {
var result = z.core.IORead(port)
z.Flags.S = result&0x80 != 0
z.Flags.Z = result == 0
z.Flags.H = false
z.Flags.P = ParityBits[result]
z.Flags.N = false
z.updateXYFlags(result)
return result
}
func (z *Z80) doNeg() {
// This instruction is defined to not alter the register if it === 0x80.
a := int8(z.A)
if z.A != 0x80 {
// This is a signed operation, so convert A to a signed value.
z.A = byte(-a)
}
z.Flags.S = z.A&0x80 != 0
z.Flags.Z = z.A == 0
z.Flags.H = ((-a) & 0x0f) > 0
z.Flags.P = z.A == 0x80
z.Flags.N = true
z.Flags.C = z.A != 0
z.updateXYFlags(z.A)
}
func (z *Z80) doLdi() {
// Copy the value that we're supposed to copy.
readValue := z.core.MemRead(z.hl())
z.core.MemWrite(z.de(), readValue)
z.incDe()
z.incHl()
z.decBc()
z.Flags.H = false
z.Flags.P = (z.C | z.B) != 0
z.Flags.N = false
z.Flags.Y = ((z.A+readValue)&0x02)>>1 != 0
z.Flags.X = ((z.A+readValue)&0x08)>>3 != 0
}
func (z *Z80) fhv() byte {
if z.Flags.H {
return 1
}
return 0
}
func (z *Z80) doCpi() {
tempCarry := z.Flags.C
readValue := z.core.MemRead(z.hl())
z.doCp(readValue)
z.Flags.C = tempCarry
fh := z.fhv()
z.Flags.Y = ((z.A - readValue - fh) & 0x02) != 0
z.Flags.X = ((z.A - readValue - fh) & 0x08) != 0
z.incHl()
z.decBc()
z.Flags.P = (z.B | z.C) != 0
}
func (z *Z80) doIni() {
z.core.MemWrite(z.hl(), z.core.IORead(z.bc()))
z.incHl()
z.B = z.doDec(z.B)
z.Flags.N = true
}
func (z *Z80) doOuti() {
z.B = z.doDec(z.B)
z.core.IOWrite(z.bc(), z.core.MemRead(z.hl()))
z.incHl()
z.Flags.N = true
}
func (z *Z80) doLdd() {
z.Flags.N = false
z.Flags.H = false
readValue := z.core.MemRead(z.hl())
z.core.MemWrite(z.de(), readValue)
z.decDe()
z.decHl()
z.decBc()
z.Flags.P = (z.C | z.B) != 0
z.Flags.Y = ((z.A + readValue) & 0x02) != 0
z.Flags.X = ((z.A + readValue) & 0x08) != 0
}
func (z *Z80) doCpd() {
tempCarry := z.Flags.C
readValue := z.core.MemRead(z.hl())
z.doCp(readValue)
z.Flags.C = tempCarry
fh := z.fhv()
z.Flags.Y = ((z.A-readValue-fh)&0x02)>>1 != 0
z.Flags.X = ((z.A-readValue-fh)&0x08)>>3 != 0
z.decHl()
z.decBc()
z.Flags.P = (z.B | z.C) != 0
}
func (z *Z80) doInd() {
z.core.MemWrite(z.hl(), z.core.IORead(z.bc()))
z.decHl()
z.B = z.doDec(z.B)
z.Flags.N = true
}
func (z *Z80) doOutd() {
z.B = z.doDec(z.B)
z.core.IOWrite(z.bc(), z.core.MemRead(z.hl()))
z.decHl()
z.Flags.N = true
}
type OpShift func(operand byte) byte
func (z *Z80) doRlc(operand byte) byte {
z.Flags.C = operand&0x80 != 0
var fc byte = 0
if z.Flags.C {
fc = 1
}
operand = (operand << 1) | fc
z.setShiftFlags(operand)
return operand
}
func (z *Z80) doRrc(operand byte) byte {
z.Flags.C = operand&1 != 0
var fc byte = 0
if z.Flags.C {
fc = 0x80
}
operand = ((operand >> 1) & 0x7f) | fc
z.setShiftFlags(operand)
return operand
}
func (z *Z80) doRl(operand byte) byte {
var fc byte = 0
if z.Flags.C {
fc = 1
}
z.Flags.C = operand&0x80 != 0
operand = (operand << 1) | fc
z.setShiftFlags(operand)
return operand
}
func (z *Z80) doRr(operand byte) byte {
var fc byte = 0
if z.Flags.C {
fc = 0x80
}
z.Flags.C = operand&1 != 0
operand = ((operand >> 1) & 0x7f) | fc
z.setShiftFlags(operand)
return operand
}
func (z *Z80) doSla(operand byte) byte {
z.Flags.C = operand&0x80 != 0
operand = operand << 1
z.setShiftFlags(operand)
return operand
}
func (z *Z80) doSra(operand byte) byte {
z.Flags.C = operand&1 != 0
operand = ((operand >> 1) & 0x7f) | (operand & 0x80)
z.setShiftFlags(operand)
return operand
}
func (z *Z80) doSll(operand byte) byte {
z.Flags.C = operand&0x80 != 0
operand = (operand << 1) | 1
z.setShiftFlags(operand)
return operand
}
func (z *Z80) doSrl(operand byte) byte {
z.Flags.C = operand&1 != 0
operand = (operand >> 1) & 0x7f
z.setShiftFlags(operand)
z.Flags.S = false
return operand
}
func (z *Z80) doIxAdd(operand uint16) {
z.Flags.N = false
result := uint32(z.IX) + uint32(operand)
z.Flags.C = result > 0xffff
z.Flags.H = (((z.IX & 0xfff) + (operand & 0xfff)) & 0x1000) != 0
z.updateXYFlags(byte((result & 0xff00) >> 8))
z.IX = uint16(result & 0xffff)
}
func (z *Z80) setShiftFlags(operand byte) {
z.Flags.N = false
z.Flags.H = false
z.Flags.Z = operand == 0
z.Flags.P = ParityBits[operand]
z.Flags.S = (operand & 0x80) != 0
z.updateXYFlags(operand)
}
// ============== get register pairs
func (z *Z80) bc() uint16 {
return (uint16(z.B) << 8) | uint16(z.C)
}
func (z *Z80) de() uint16 {
return (uint16(z.D) << 8) | uint16(z.E)
}
func (z *Z80) hl() uint16 {
return (uint16(z.H) << 8) | uint16(z.L)
}
// ============ helper fn
func (z *Z80) incBc() {
z.setBc(z.bc() + 1)
}
func (z *Z80) decBc() {
z.setBc(z.bc() - 1)
}
func (z *Z80) incDe() {
z.setDe(z.de() + 1)
}
func (z *Z80) decDe() {
z.setDe(z.de() - 1)
}
func (z *Z80) incHl() {
z.setHl(z.hl() + 1)
}
func (z *Z80) decHl() {
z.setHl(z.hl() - 1)
}
func (z *Z80) setHl(val uint16) {
z.L = byte(val & 0xff)
z.H = byte(val >> 8)
}
func (z *Z80) setDe(val uint16) {
z.E = byte(val & 0xff)
z.D = byte(val >> 8)
}
func (z *Z80) setBc(val uint16) {
z.C = byte(val & 0xff)
z.B = byte(val >> 8)
}
// incR Increment R at the start of every instruction cycle.
// The high bit of R is not affected by this increment,
// it can only be changed using the LD R, A instruction.
// Note: also a HALT does increment the R register.
func (z *Z80) incR() {
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
}
// getWord Return 16bit value from memory by specified address
func (z *Z80) getWord(address uint16) uint16 {
return (uint16(z.core.MemRead(address+1)) << 8) | uint16(z.core.MemRead(address))
}
func (z *Z80) setWord(address uint16, value uint16) {
z.core.MemWrite(address, byte(value))
z.core.MemWrite(address+1, byte(value>>8))
}
func (z *Z80) debugOutput() {
log.Debugf("PC: %04X, AF: %04X, BC: %04X, DE: %04X, HL: %04X, SP: %04X, IX: %04X, IY: %04X, I: %02X, R: %02X",
z.PC, (uint16(z.A)<<8)|uint16(z.Flags.GetFlags()), z.bc(), z.de(), z.hl(), z.SP, z.IX, z.IY, z.I, z.R)
log.Debugf("\t(%02X %02X %02X %02X), cyc: %d\n", z.core.MemRead(z.PC), z.core.MemRead(z.PC+1),
z.core.MemRead(z.PC+2), z.core.MemRead(z.PC+3), z.CycleCounter)
}