mirror of
https://github.com/romychs/Ocean-240.2-Emulator.git
synced 2026-04-21 11:03:21 +03:00
Refactoring
This commit is contained in:
parent
fc91bab922
commit
b70b02a4be
4
main.go
4
main.go
@ -157,7 +157,7 @@ func screen(computer *okean240.ComputerType, raster *canvas.Raster, label *widge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ticksPerTact uint64 = 3
|
const ticksPerTact uint64 = 4
|
||||||
|
|
||||||
func emulator(computer *okean240.ComputerType) {
|
func emulator(computer *okean240.ComputerType) {
|
||||||
ticker := time.NewTicker(66 * time.Nanosecond)
|
ticker := time.NewTicker(66 * time.Nanosecond)
|
||||||
@ -174,7 +174,7 @@ func emulator(computer *okean240.ComputerType) {
|
|||||||
computer.Do()
|
computer.Do()
|
||||||
} else {
|
} else {
|
||||||
if ticks >= nextClock {
|
if ticks >= nextClock {
|
||||||
nextClock = ticks + computer.Do()*ticksPerTact
|
nextClock = ticks + uint64(computer.Do())*ticksPerTact
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//computer.Do()
|
//computer.Do()
|
||||||
|
|||||||
@ -114,9 +114,9 @@ func (c *ComputerType) Reset() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ComputerType) Do() uint64 {
|
func (c *ComputerType) Do() uint32 {
|
||||||
ticks := c.cpu.RunInstruction()
|
ticks := c.cpu.RunInstruction()
|
||||||
c.cycles += ticks
|
c.cycles += uint64(ticks)
|
||||||
//pc := c.cpu.GetState().PC
|
//pc := c.cpu.GetState().PC
|
||||||
//if pc >= 0xfea3 && pc <= 0xff25 {
|
//if pc >= 0xfea3 && pc <= 0xff25 {
|
||||||
// c.cpu.DebugOutput()
|
// c.cpu.DebugOutput()
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package c99
|
package c99
|
||||||
|
|
||||||
var cyc_00 = [256]byte{
|
var cycles00 = [256]byte{
|
||||||
4, 10, 7, 6, 4, 4, 7, 4, 4, 11, 7, 6, 4, 4, 7, 4,
|
4, 10, 7, 6, 4, 4, 7, 4, 4, 11, 7, 6, 4, 4, 7, 4,
|
||||||
8, 10, 7, 6, 4, 4, 7, 4, 12, 11, 7, 6, 4, 4, 7, 4,
|
8, 10, 7, 6, 4, 4, 7, 4, 12, 11, 7, 6, 4, 4, 7, 4,
|
||||||
7, 10, 16, 6, 4, 4, 7, 4, 7, 11, 16, 6, 4, 4, 7, 4,
|
7, 10, 16, 6, 4, 4, 7, 4, 7, 11, 16, 6, 4, 4, 7, 4,
|
||||||
@ -19,7 +19,7 @@ var cyc_00 = [256]byte{
|
|||||||
5, 10, 10, 4, 10, 11, 7, 11, 5, 6, 10, 4, 10, 0, 7, 11,
|
5, 10, 10, 4, 10, 11, 7, 11, 5, 6, 10, 4, 10, 0, 7, 11,
|
||||||
}
|
}
|
||||||
|
|
||||||
var cyc_ed = [256]byte{
|
var cyclesED = [256]byte{
|
||||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||||
@ -38,7 +38,7 @@ var cyc_ed = [256]byte{
|
|||||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
var cyc_ddfd = [256]byte{
|
var cyclesDDFD = [256]byte{
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 15, 4, 4, 4, 4, 4, 4,
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 15, 4, 4, 4, 4, 4, 4,
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 15, 4, 4, 4, 4, 4, 4,
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 15, 4, 4, 4, 4, 4, 4,
|
||||||
4, 14, 20, 10, 8, 8, 11, 4, 4, 15, 20, 10, 8, 8, 11, 4,
|
4, 14, 20, 10, 8, 8, 11, 4, 4, 15, 20, 10, 8, 8, 11, 4,
|
||||||
|
|||||||
@ -5,14 +5,13 @@ import "okemu/z80"
|
|||||||
type Z80 struct {
|
type Z80 struct {
|
||||||
|
|
||||||
// cycle count (t-states)
|
// cycle count (t-states)
|
||||||
cyc uint64
|
cycleCount uint32
|
||||||
inst_cyc byte
|
|
||||||
|
|
||||||
// special purpose registers
|
// special purpose registers
|
||||||
pc, sp, ix, iy uint16
|
pc, sp, ix, iy uint16
|
||||||
|
|
||||||
// "wz" register
|
// "wz" register
|
||||||
mem_ptr uint16
|
memPtr uint16
|
||||||
|
|
||||||
// main registers
|
// main registers
|
||||||
a, b, c, d, e, h, l byte
|
a, b, c, d, e, h, l byte
|
||||||
@ -25,14 +24,14 @@ type Z80 struct {
|
|||||||
|
|
||||||
// flags: sign, zero, yf, half-carry, xf, parity/overflow, negative, carry
|
// flags: sign, zero, yf, half-carry, xf, parity/overflow, negative, carry
|
||||||
sf, zf, yf, hf, xf, pf, nf, cf bool
|
sf, zf, yf, hf, xf, pf, nf, cf bool
|
||||||
iff_delay byte
|
iffDelay byte
|
||||||
interrupt_mode byte
|
interruptMode byte
|
||||||
int_data byte
|
intData byte
|
||||||
iff1 bool
|
iff1 bool
|
||||||
iff2 bool
|
iff2 bool
|
||||||
halted bool
|
isHalted bool
|
||||||
int_pending bool
|
intPending bool
|
||||||
nmi_pending bool
|
nmiPending bool
|
||||||
|
|
||||||
core z80.MemIoRW
|
core z80.MemIoRW
|
||||||
}
|
}
|
||||||
@ -42,16 +41,14 @@ func New(core z80.MemIoRW) *Z80 {
|
|||||||
z := Z80{}
|
z := Z80{}
|
||||||
z.core = core
|
z.core = core
|
||||||
|
|
||||||
z.cyc = 0
|
z.cycleCount = 0
|
||||||
|
|
||||||
z.pc = 0
|
z.pc = 0
|
||||||
z.sp = 0xFFFF
|
z.sp = 0xFFFF
|
||||||
z.ix = 0
|
z.ix = 0
|
||||||
z.iy = 0
|
z.iy = 0
|
||||||
z.mem_ptr = 0
|
z.memPtr = 0
|
||||||
|
|
||||||
// af and sp are set to 0xFFFF after reset,
|
|
||||||
// and the other values are undefined (z80-documented)
|
|
||||||
z.a = 0xFF
|
z.a = 0xFF
|
||||||
z.b = 0
|
z.b = 0
|
||||||
z.c = 0
|
z.c = 0
|
||||||
@ -81,32 +78,32 @@ func New(core z80.MemIoRW) *Z80 {
|
|||||||
z.nf = true
|
z.nf = true
|
||||||
z.cf = true
|
z.cf = true
|
||||||
|
|
||||||
z.iff_delay = 0
|
z.iffDelay = 0
|
||||||
z.interrupt_mode = 0
|
z.interruptMode = 0
|
||||||
z.iff1 = false
|
z.iff1 = false
|
||||||
z.iff2 = false
|
z.iff2 = false
|
||||||
z.halted = false
|
z.isHalted = false
|
||||||
z.int_pending = false
|
z.intPending = false
|
||||||
z.nmi_pending = false
|
z.nmiPending = false
|
||||||
z.int_data = 0
|
z.intData = 0
|
||||||
return &z
|
return &z
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunInstruction executes the next instruction in memory + handles interrupts
|
// RunInstruction executes the next instruction in memory + handles interrupts
|
||||||
func (z *Z80) RunInstruction() uint64 {
|
func (z *Z80) RunInstruction() uint32 {
|
||||||
pre := z.cyc
|
pre := z.cycleCount
|
||||||
if z.halted {
|
if z.isHalted {
|
||||||
z.exec_opcode(0x00)
|
z.execOpcode(0x00)
|
||||||
} else {
|
} else {
|
||||||
opcode := z.nextb()
|
opcode := z.nextB()
|
||||||
z.exec_opcode(opcode)
|
z.execOpcode(opcode)
|
||||||
}
|
}
|
||||||
z.process_interrupts()
|
z.processInterrupts()
|
||||||
return z.cyc - pre
|
return z.cycleCount - pre
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) SetState(state *z80.Z80CPU) {
|
func (z *Z80) SetState(state *z80.Z80CPU) {
|
||||||
z.cyc = 0
|
z.cycleCount = 0
|
||||||
z.a = state.A
|
z.a = state.A
|
||||||
z.b = state.B
|
z.b = state.B
|
||||||
z.c = state.C
|
z.c = state.C
|
||||||
@ -129,7 +126,7 @@ func (z *Z80) SetState(state *z80.Z80CPU) {
|
|||||||
z.iy = state.IY
|
z.iy = state.IY
|
||||||
z.i = state.I
|
z.i = state.I
|
||||||
z.r = state.R
|
z.r = state.R
|
||||||
z.mem_ptr = state.MemPtr
|
z.memPtr = state.MemPtr
|
||||||
|
|
||||||
z.sf = state.Flags.S
|
z.sf = state.Flags.S
|
||||||
z.zf = state.Flags.Z
|
z.zf = state.Flags.Z
|
||||||
@ -143,13 +140,13 @@ func (z *Z80) SetState(state *z80.Z80CPU) {
|
|||||||
z.f_ = state.FlagsAlt.GetFlags()
|
z.f_ = state.FlagsAlt.GetFlags()
|
||||||
|
|
||||||
//z.iff_delay = 0
|
//z.iff_delay = 0
|
||||||
z.interrupt_mode = state.IMode
|
z.interruptMode = state.IMode
|
||||||
z.iff1 = state.Iff1
|
z.iff1 = state.Iff1
|
||||||
z.iff2 = state.Iff2
|
z.iff2 = state.Iff2
|
||||||
z.halted = state.Halted
|
z.isHalted = state.Halted
|
||||||
z.int_pending = state.InterruptOccurred
|
z.intPending = state.InterruptOccurred
|
||||||
z.nmi_pending = false
|
z.nmiPending = false
|
||||||
z.int_data = 0
|
z.intData = 0
|
||||||
}
|
}
|
||||||
func (z *Z80) GetState() *z80.Z80CPU {
|
func (z *Z80) GetState() *z80.Z80CPU {
|
||||||
return &z80.Z80CPU{
|
return &z80.Z80CPU{
|
||||||
@ -177,15 +174,15 @@ func (z *Z80) GetState() *z80.Z80CPU {
|
|||||||
|
|
||||||
Flags: z.getFlags(),
|
Flags: z.getFlags(),
|
||||||
FlagsAlt: z.getAltFlags(),
|
FlagsAlt: z.getAltFlags(),
|
||||||
IMode: z.interrupt_mode,
|
IMode: z.interruptMode,
|
||||||
Iff1: z.iff1,
|
Iff1: z.iff1,
|
||||||
Iff2: z.iff2,
|
Iff2: z.iff2,
|
||||||
Halted: z.halted,
|
Halted: z.isHalted,
|
||||||
DoDelayedDI: z.int_pending,
|
DoDelayedDI: z.intPending,
|
||||||
DoDelayedEI: z.int_pending,
|
DoDelayedEI: z.intPending,
|
||||||
CycleCounter: z.inst_cyc,
|
CycleCount: z.cycleCount,
|
||||||
InterruptOccurred: z.int_pending,
|
InterruptOccurred: z.intPending,
|
||||||
MemPtr: z.mem_ptr,
|
MemPtr: z.memPtr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,56 +19,56 @@ func (z *Z80) ww(addr uint16, val uint16) {
|
|||||||
z.core.MemWrite(addr+1, byte(val>>8))
|
z.core.MemWrite(addr+1, byte(val>>8))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) pushw(val uint16) {
|
func (z *Z80) pushW(val uint16) {
|
||||||
z.sp -= 2
|
z.sp -= 2
|
||||||
z.ww(z.sp, val)
|
z.ww(z.sp, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) popw() uint16 {
|
func (z *Z80) popW() uint16 {
|
||||||
z.sp += 2
|
z.sp += 2
|
||||||
return z.rw(z.sp - 2)
|
return z.rw(z.sp - 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) nextb() byte {
|
func (z *Z80) nextB() byte {
|
||||||
b := z.rb(z.pc)
|
b := z.rb(z.pc)
|
||||||
z.pc++
|
z.pc++
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) nextw() uint16 {
|
func (z *Z80) nextW() uint16 {
|
||||||
w := z.rw(z.pc)
|
w := z.rw(z.pc)
|
||||||
z.pc += 2
|
z.pc += 2
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) get_bc() uint16 {
|
func (z *Z80) bc() uint16 {
|
||||||
return (uint16(z.b) << 8) | uint16(z.c)
|
return (uint16(z.b) << 8) | uint16(z.c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) get_de() uint16 {
|
func (z *Z80) de() uint16 {
|
||||||
return (uint16(z.d) << 8) | uint16(z.e)
|
return (uint16(z.d) << 8) | uint16(z.e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) get_hl() uint16 {
|
func (z *Z80) hl() uint16 {
|
||||||
return (uint16(z.h) << 8) | uint16(z.l)
|
return (uint16(z.h) << 8) | uint16(z.l)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) set_bc(val uint16) {
|
func (z *Z80) setBC(val uint16) {
|
||||||
z.b = byte(val >> 8)
|
z.b = byte(val >> 8)
|
||||||
z.c = byte(val)
|
z.c = byte(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) set_de(val uint16) {
|
func (z *Z80) setDE(val uint16) {
|
||||||
z.d = byte(val >> 8)
|
z.d = byte(val >> 8)
|
||||||
z.e = byte(val)
|
z.e = byte(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) set_hl(val uint16) {
|
func (z *Z80) setHL(val uint16) {
|
||||||
z.h = byte(val >> 8)
|
z.h = byte(val >> 8)
|
||||||
z.l = byte(val)
|
z.l = byte(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) get_f() byte {
|
func (z *Z80) f() byte {
|
||||||
val := byte(0)
|
val := byte(0)
|
||||||
if z.cf {
|
if z.cf {
|
||||||
val |= 0x01
|
val |= 0x01
|
||||||
@ -97,7 +97,7 @@ func (z *Z80) get_f() byte {
|
|||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) set_f(val byte) {
|
func (z *Z80) setF(val byte) {
|
||||||
z.cf = val&1 != 0
|
z.cf = val&1 != 0
|
||||||
z.nf = (val>>1)&1 != 0
|
z.nf = (val>>1)&1 != 0
|
||||||
z.pf = (val>>2)&1 != 0
|
z.pf = (val>>2)&1 != 0
|
||||||
@ -109,7 +109,7 @@ func (z *Z80) set_f(val byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// increments R, keeping the highest byte intact
|
// increments R, keeping the highest byte intact
|
||||||
func (z *Z80) inc_r() {
|
func (z *Z80) incR() {
|
||||||
z.r = (z.r & 0x80) | ((z.r + 1) & 0x7f)
|
z.r = (z.r & 0x80) | ((z.r + 1) & 0x7f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,10 +122,10 @@ func boolToInt32(b bool) int32 {
|
|||||||
|
|
||||||
// returns if there was a carry between bit "bit_no" and "bit_no - 1" when
|
// returns if there was a carry between bit "bit_no" and "bit_no - 1" when
|
||||||
// executing "a + b + cy"
|
// executing "a + b + cy"
|
||||||
func carry(bit_no int, a uint16, b uint16, cy bool) bool {
|
func carry(bitNo int, a uint16, b uint16, cy bool) bool {
|
||||||
result := int32(a) + int32(b) + boolToInt32(cy)
|
result := int32(a) + int32(b) + boolToInt32(cy)
|
||||||
carry := result ^ int32(a) ^ int32(b)
|
carry := result ^ int32(a) ^ int32(b)
|
||||||
return (carry & (1 << bit_no)) != 0
|
return (carry & (1 << bitNo)) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the parity of byte: 0 if number of 1 bits in `val` is odd, else 1
|
// returns the parity of byte: 0 if number of 1 bits in `val` is odd, else 1
|
||||||
@ -137,6 +137,7 @@ func parity(val byte) bool {
|
|||||||
return (ones & 1) == 0
|
return (ones & 1) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateXY set undocumented 3rd (X) and 5th (Y) flags
|
||||||
func (z *Z80) updateXY(result byte) {
|
func (z *Z80) updateXY(result byte) {
|
||||||
z.yf = result&0x20 != 0
|
z.yf = result&0x20 != 0
|
||||||
z.xf = result&0x08 != 0
|
z.xf = result&0x08 != 0
|
||||||
@ -144,13 +145,56 @@ func (z *Z80) updateXY(result byte) {
|
|||||||
|
|
||||||
func (z *Z80) DebugOutput() {
|
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",
|
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.get_f()), z.get_bc(), z.get_de(), z.get_hl(), z.sp,
|
z.pc, (uint16(z.a)<<8)|uint16(z.f()), z.bc(), z.de(), z.hl(), z.sp,
|
||||||
z.ix, z.iy, z.i, z.r)
|
z.ix, z.iy, z.i, z.r)
|
||||||
|
|
||||||
log.Debugf("\t(%02X %02X %02X %02X), cyc: %d\n", z.rb(z.pc), z.rb(z.pc+1),
|
log.Debugf("\t(%02X %02X %02X %02X), cycleCount: %d\n", z.rb(z.pc), z.rb(z.pc+1),
|
||||||
z.rb(z.pc+2), z.rb(z.pc+3), z.cyc)
|
z.rb(z.pc+2), z.rb(z.pc+3), z.cycleCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) Reset() {
|
func (z *Z80) Reset() {
|
||||||
|
z.cycleCount = 0
|
||||||
|
z.pc = 0
|
||||||
|
z.sp = 0xFFFF
|
||||||
|
z.ix = 0
|
||||||
|
z.iy = 0
|
||||||
|
z.memPtr = 0
|
||||||
|
|
||||||
|
z.a = 0xFF
|
||||||
|
z.b = 0
|
||||||
|
z.c = 0
|
||||||
|
z.d = 0
|
||||||
|
z.e = 0
|
||||||
|
z.h = 0
|
||||||
|
z.l = 0
|
||||||
|
|
||||||
|
z.a_ = 0
|
||||||
|
z.b_ = 0
|
||||||
|
z.c_ = 0
|
||||||
|
z.d_ = 0
|
||||||
|
z.e_ = 0
|
||||||
|
z.h_ = 0
|
||||||
|
z.l_ = 0
|
||||||
|
z.f_ = 0
|
||||||
|
|
||||||
|
z.i = 0
|
||||||
|
z.r = 0
|
||||||
|
|
||||||
|
z.sf = true
|
||||||
|
z.zf = true
|
||||||
|
z.yf = true
|
||||||
|
z.hf = true
|
||||||
|
z.xf = true
|
||||||
|
z.pf = true
|
||||||
|
z.nf = true
|
||||||
|
z.cf = true
|
||||||
|
|
||||||
|
z.iffDelay = 0
|
||||||
|
z.interruptMode = 0
|
||||||
|
z.iff1 = false
|
||||||
|
z.iff2 = false
|
||||||
|
z.isHalted = false
|
||||||
|
z.intPending = false
|
||||||
|
z.nmiPending = false
|
||||||
|
z.intData = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,46 +5,46 @@ import log "github.com/sirupsen/logrus"
|
|||||||
// jumps to an address
|
// jumps to an address
|
||||||
func (z *Z80) jump(addr uint16) {
|
func (z *Z80) jump(addr uint16) {
|
||||||
z.pc = addr
|
z.pc = addr
|
||||||
z.mem_ptr = addr
|
z.memPtr = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// jumps to next word in memory if condition is true
|
// jumps to next word in memory if condition is true
|
||||||
func (z *Z80) cond_jump(condition bool) {
|
func (z *Z80) cond_jump(condition bool) {
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
if condition {
|
if condition {
|
||||||
z.jump(addr)
|
z.jump(addr)
|
||||||
}
|
}
|
||||||
z.mem_ptr = addr
|
z.memPtr = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// calls to next word in memory
|
// calls to next word in memory
|
||||||
func (z *Z80) call(addr uint16) {
|
func (z *Z80) call(addr uint16) {
|
||||||
z.pushw(z.pc)
|
z.pushW(z.pc)
|
||||||
z.pc = addr
|
z.pc = addr
|
||||||
z.mem_ptr = addr
|
z.memPtr = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// calls to next word in memory if condition is true
|
// calls to next word in memory if condition is true
|
||||||
func (z *Z80) cond_call(condition bool) {
|
func (z *Z80) cond_call(condition bool) {
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
if condition {
|
if condition {
|
||||||
z.call(addr)
|
z.call(addr)
|
||||||
z.cyc += 7
|
z.cycleCount += 7
|
||||||
}
|
}
|
||||||
z.mem_ptr = addr
|
z.memPtr = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns from subroutine
|
// returns from subroutine
|
||||||
func (z *Z80) ret() {
|
func (z *Z80) ret() {
|
||||||
z.pc = z.popw()
|
z.pc = z.popW()
|
||||||
z.mem_ptr = z.pc
|
z.memPtr = z.pc
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns from subroutine if condition is true
|
// returns from subroutine if condition is true
|
||||||
func (z *Z80) cond_ret(condition bool) {
|
func (z *Z80) cond_ret(condition bool) {
|
||||||
if condition {
|
if condition {
|
||||||
z.ret()
|
z.ret()
|
||||||
z.cyc += 6
|
z.cycleCount += 6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,14 +54,14 @@ func (z *Z80) jr(offset byte) {
|
|||||||
} else {
|
} else {
|
||||||
z.pc += uint16(offset)
|
z.pc += uint16(offset)
|
||||||
}
|
}
|
||||||
z.mem_ptr = z.pc
|
z.memPtr = z.pc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) cond_jr(condition bool) {
|
func (z *Z80) cond_jr(condition bool) {
|
||||||
b := z.nextb()
|
b := z.nextB()
|
||||||
if condition {
|
if condition {
|
||||||
z.jr(b)
|
z.jr(b)
|
||||||
z.cyc += 5
|
z.cycleCount += 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ func (z *Z80) addw(a uint16, b uint16, cy bool) uint16 {
|
|||||||
msb := z.addb(byte(a>>8), byte(b>>8), z.cf)
|
msb := z.addb(byte(a>>8), byte(b>>8), z.cf)
|
||||||
result := (uint16(msb) << 8) | uint16(lsb)
|
result := (uint16(msb) << 8) | uint16(lsb)
|
||||||
z.zf = result == 0
|
z.zf = result == 0
|
||||||
z.mem_ptr = a + 1
|
z.memPtr = a + 1
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ func (z *Z80) subw(a uint16, b uint16, cy bool) uint16 {
|
|||||||
msb := z.subb(byte(a>>8), byte(b>>8), z.cf)
|
msb := z.subb(byte(a>>8), byte(b>>8), z.cf)
|
||||||
result := (uint16(msb) << 8) | uint16(lsb)
|
result := (uint16(msb) << 8) | uint16(lsb)
|
||||||
z.zf = result == 0
|
z.zf = result == 0
|
||||||
z.mem_ptr = a + 1
|
z.memPtr = a + 1
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,8 +119,8 @@ func (z *Z80) addhl(val uint16) {
|
|||||||
sf := z.sf
|
sf := z.sf
|
||||||
zf := z.zf
|
zf := z.zf
|
||||||
pf := z.pf
|
pf := z.pf
|
||||||
result := z.addw(z.get_hl(), val, false)
|
result := z.addw(z.hl(), val, false)
|
||||||
z.set_hl(result)
|
z.setHL(result)
|
||||||
z.sf = sf
|
z.sf = sf
|
||||||
z.zf = zf
|
z.zf = zf
|
||||||
z.pf = pf
|
z.pf = pf
|
||||||
@ -140,18 +140,18 @@ func (z *Z80) addiz(reg *uint16, val uint16) {
|
|||||||
|
|
||||||
// adchl adds a word (+ carry) to HL
|
// adchl adds a word (+ carry) to HL
|
||||||
func (z *Z80) adchl(val uint16) {
|
func (z *Z80) adchl(val uint16) {
|
||||||
result := z.addw(z.get_hl(), val, z.cf)
|
result := z.addw(z.hl(), val, z.cf)
|
||||||
z.sf = result&0x8000 != 0
|
z.sf = result&0x8000 != 0
|
||||||
z.zf = result == 0
|
z.zf = result == 0
|
||||||
z.set_hl(result)
|
z.setHL(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sbchl subtracts a word (+ carry) to HL
|
// sbchl subtracts a word (+ carry) to HL
|
||||||
func (z *Z80) sbchl(val uint16) {
|
func (z *Z80) sbchl(val uint16) {
|
||||||
result := z.subw(z.get_hl(), val, z.cf)
|
result := z.subw(z.hl(), val, z.cf)
|
||||||
z.sf = result&0x8000 != 0
|
z.sf = result&0x8000 != 0
|
||||||
z.zf = result == 0
|
z.zf = result == 0
|
||||||
z.set_hl(result)
|
z.setHL(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// increments a byte value
|
// increments a byte value
|
||||||
@ -347,14 +347,14 @@ func (z *Z80) cb_bit(val byte, n byte) byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) ldi() {
|
func (z *Z80) ldi() {
|
||||||
de := z.get_de()
|
de := z.de()
|
||||||
hl := z.get_hl()
|
hl := z.hl()
|
||||||
val := z.rb(hl)
|
val := z.rb(hl)
|
||||||
z.wb(de, val)
|
z.wb(de, val)
|
||||||
|
|
||||||
z.set_hl(z.get_hl() + 1)
|
z.setHL(z.hl() + 1)
|
||||||
z.set_de(z.get_de() + 1)
|
z.setDE(z.de() + 1)
|
||||||
z.set_bc(z.get_bc() - 1)
|
z.setBC(z.bc() - 1)
|
||||||
|
|
||||||
// see https://wikiti.brandonw.net/index.php?title=Z80_Instruction_Set
|
// see https://wikiti.brandonw.net/index.php?title=Z80_Instruction_Set
|
||||||
// for the calculation of xf/yf on LDI
|
// for the calculation of xf/yf on LDI
|
||||||
@ -365,67 +365,42 @@ func (z *Z80) ldi() {
|
|||||||
|
|
||||||
z.nf = false
|
z.nf = false
|
||||||
z.hf = false
|
z.hf = false
|
||||||
z.pf = z.get_bc() > 0
|
z.pf = z.bc() > 0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) ldd() {
|
func (z *Z80) ldd() {
|
||||||
z.ldi()
|
z.ldi()
|
||||||
// same as ldi but HL and DE are decremented instead of incremented
|
// same as ldi but HL and DE are decremented instead of incremented
|
||||||
z.set_hl(z.get_hl() - 2)
|
z.setHL(z.hl() - 2)
|
||||||
z.set_de(z.get_de() - 2)
|
z.setDE(z.de() - 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) cpi() {
|
func (z *Z80) cpi() {
|
||||||
cf := z.cf
|
cf := z.cf
|
||||||
result := z.subb(z.a, z.rb(z.get_hl()), false)
|
result := z.subb(z.a, z.rb(z.hl()), false)
|
||||||
z.set_hl(z.get_hl() + 1)
|
z.setHL(z.hl() + 1)
|
||||||
z.set_bc(z.get_bc() - 1)
|
z.setBC(z.bc() - 1)
|
||||||
|
|
||||||
val := result - bToByte(z.hf)
|
val := result - bToByte(z.hf)
|
||||||
z.xf = val&0x08 != 0
|
z.xf = val&0x08 != 0
|
||||||
z.yf = val&0x02 != 0
|
z.yf = val&0x02 != 0
|
||||||
z.pf = z.get_bc() != 0
|
z.pf = z.bc() != 0
|
||||||
z.cf = cf
|
z.cf = cf
|
||||||
z.mem_ptr += 1
|
z.memPtr += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) cpd() {
|
func (z *Z80) cpd() {
|
||||||
z.cpi()
|
z.cpi()
|
||||||
// same as cpi but HL is decremented instead of incremented
|
// same as cpi but HL is decremented instead of incremented
|
||||||
z.set_hl(z.get_hl() - 2)
|
z.setHL(z.hl() - 2)
|
||||||
z.mem_ptr -= 2
|
z.memPtr -= 2
|
||||||
}
|
}
|
||||||
|
|
||||||
var halfCarrySubTable = []bool{false, false, true, false, true, false, true, true}
|
//var halfCarrySubTable = []bool{false, false, true, false, true, false, true, true}
|
||||||
|
|
||||||
func (z *Z80) cpir() {
|
func (z *Z80) inRC(r *byte) {
|
||||||
value := z.rb(z.get_hl())
|
*r = z.core.IORead(z.bc())
|
||||||
diff := uint8(uint16(z.a) - uint16(value))
|
|
||||||
lookup := ((z.a & 0x08) >> 3) | ((value & 0x08) >> 2) | ((diff & 0x08) >> 1)
|
|
||||||
z.set_bc(z.get_bc() - 1)
|
|
||||||
z.hf = halfCarrySubTable[lookup]
|
|
||||||
z.pf = z.get_bc() != 0 // V=P
|
|
||||||
z.nf = true
|
|
||||||
z.zf = diff == 0
|
|
||||||
z.sf = diff&0x80 != 0
|
|
||||||
if z.hf {
|
|
||||||
diff--
|
|
||||||
}
|
|
||||||
z.xf = (diff & 0x08) != 0
|
|
||||||
z.yf = (diff & 0x02) != 0
|
|
||||||
if z.pf && !z.zf {
|
|
||||||
z.cyc += 5
|
|
||||||
z.pc -= 2
|
|
||||||
z.mem_ptr = z.pc + 1
|
|
||||||
} else {
|
|
||||||
z.mem_ptr++
|
|
||||||
}
|
|
||||||
z.set_hl(z.get_hl() + 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (z *Z80) in_r_c(r *byte) {
|
|
||||||
*r = z.core.IORead(z.get_bc())
|
|
||||||
z.zf = *r == 0
|
z.zf = *r == 0
|
||||||
z.sf = *r&0x80 != 0
|
z.sf = *r&0x80 != 0
|
||||||
z.pf = parity(*r)
|
z.pf = parity(*r)
|
||||||
@ -434,9 +409,9 @@ func (z *Z80) in_r_c(r *byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) ini() {
|
func (z *Z80) ini() {
|
||||||
val := z.core.IORead(z.get_bc())
|
val := z.core.IORead(z.bc())
|
||||||
z.wb(z.get_hl(), val)
|
z.wb(z.hl(), val)
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
z.b--
|
z.b--
|
||||||
|
|
||||||
other := val + z.c + 1
|
other := val + z.c + 1
|
||||||
@ -452,13 +427,13 @@ func (z *Z80) ini() {
|
|||||||
z.sf = z.b&0x80 != 0
|
z.sf = z.b&0x80 != 0
|
||||||
z.zf = z.b == 0
|
z.zf = z.b == 0
|
||||||
z.updateXY(z.b)
|
z.updateXY(z.b)
|
||||||
z.set_hl(z.get_hl() + 1)
|
z.setHL(z.hl() + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) ind() {
|
func (z *Z80) ind() {
|
||||||
val := z.core.IORead(z.get_bc())
|
val := z.core.IORead(z.bc())
|
||||||
z.wb(z.get_hl(), val)
|
z.wb(z.hl(), val)
|
||||||
z.mem_ptr = z.get_bc() - 1
|
z.memPtr = z.bc() - 1
|
||||||
z.b--
|
z.b--
|
||||||
|
|
||||||
other := val + z.c - 1
|
other := val + z.c - 1
|
||||||
@ -475,15 +450,15 @@ func (z *Z80) ind() {
|
|||||||
z.sf = z.b&0x80 != 0
|
z.sf = z.b&0x80 != 0
|
||||||
z.zf = z.b == 0
|
z.zf = z.b == 0
|
||||||
z.updateXY(z.b)
|
z.updateXY(z.b)
|
||||||
z.set_hl(z.get_hl() - 1)
|
z.setHL(z.hl() - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) outi() {
|
func (z *Z80) outi() {
|
||||||
val := z.rb(z.get_hl())
|
val := z.rb(z.hl())
|
||||||
z.b--
|
z.b--
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
z.core.IOWrite(z.get_bc(), val)
|
z.core.IOWrite(z.bc(), val)
|
||||||
z.set_hl(z.get_hl() + 1)
|
z.setHL(z.hl() + 1)
|
||||||
other := val + z.l
|
other := val + z.l
|
||||||
z.nf = val&0x80 != 0
|
z.nf = val&0x80 != 0
|
||||||
if other < val {
|
if other < val {
|
||||||
@ -500,11 +475,11 @@ func (z *Z80) outi() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) outd() {
|
func (z *Z80) outd() {
|
||||||
val := z.rb(z.get_hl())
|
val := z.rb(z.hl())
|
||||||
z.b--
|
z.b--
|
||||||
z.mem_ptr = z.get_bc() - 1
|
z.memPtr = z.bc() - 1
|
||||||
z.core.IOWrite(z.get_bc(), val)
|
z.core.IOWrite(z.bc(), val)
|
||||||
z.set_hl(z.get_hl() - 1)
|
z.setHL(z.hl() - 1)
|
||||||
other := val + z.l
|
other := val + z.l
|
||||||
z.nf = val&0x80 != 0
|
z.nf = val&0x80 != 0
|
||||||
if other < val {
|
if other < val {
|
||||||
@ -555,80 +530,80 @@ func (z *Z80) daa() {
|
|||||||
z.updateXY(z.a)
|
z.updateXY(z.a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) displace(base_addr uint16, offset byte) uint16 {
|
func (z *Z80) displace(baseAddr uint16, offset byte) uint16 {
|
||||||
addr := base_addr
|
addr := baseAddr
|
||||||
if offset&0x80 == 0x80 {
|
if offset&0x80 == 0x80 {
|
||||||
addr += 0xff00 | uint16(offset)
|
addr += 0xff00 | uint16(offset)
|
||||||
} else {
|
} else {
|
||||||
addr += uint16(offset)
|
addr += uint16(offset)
|
||||||
}
|
}
|
||||||
//addr := base_addr + uint16(displacement)
|
//addr := baseAddr + uint16(displacement)
|
||||||
z.mem_ptr = addr
|
z.memPtr = addr
|
||||||
return addr
|
return addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) process_interrupts() {
|
func (z *Z80) processInterrupts() {
|
||||||
// "When an EI instruction is executed, any pending interrupt request
|
// "When an EI instruction is executed, any pending interrupt request
|
||||||
// is not accepted until after the instruction following EI is executed."
|
// is not accepted until after the instruction following EI is executed."
|
||||||
if z.iff_delay > 0 {
|
if z.iffDelay > 0 {
|
||||||
z.iff_delay -= 1
|
z.iffDelay -= 1
|
||||||
if z.iff_delay == 0 {
|
if z.iffDelay == 0 {
|
||||||
z.iff1 = true
|
z.iff1 = true
|
||||||
z.iff2 = true
|
z.iff2 = true
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if z.nmi_pending {
|
if z.nmiPending {
|
||||||
z.nmi_pending = false
|
z.nmiPending = false
|
||||||
z.halted = false
|
z.isHalted = false
|
||||||
z.iff1 = false
|
z.iff1 = false
|
||||||
z.inc_r()
|
z.incR()
|
||||||
|
|
||||||
z.cyc += 11
|
z.cycleCount += 11
|
||||||
z.call(0x0066)
|
z.call(0x0066)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if z.int_pending && z.iff1 {
|
if z.intPending && z.iff1 {
|
||||||
z.int_pending = false
|
z.intPending = false
|
||||||
z.halted = false
|
z.isHalted = false
|
||||||
z.iff1 = false
|
z.iff1 = false
|
||||||
z.iff2 = false
|
z.iff2 = false
|
||||||
z.inc_r()
|
z.incR()
|
||||||
|
|
||||||
switch z.interrupt_mode {
|
switch z.interruptMode {
|
||||||
case 0:
|
case 0:
|
||||||
z.cyc += 11
|
z.cycleCount += 11
|
||||||
z.exec_opcode(z.int_data)
|
z.execOpcode(z.intData)
|
||||||
case 1:
|
case 1:
|
||||||
z.cyc += 13
|
z.cycleCount += 13
|
||||||
z.call(0x38)
|
z.call(0x38)
|
||||||
case 2:
|
case 2:
|
||||||
z.cyc += 19
|
z.cycleCount += 19
|
||||||
z.call(z.rw((uint16(z.i) << 8) | uint16(z.int_data)))
|
z.call(z.rw((uint16(z.i) << 8) | uint16(z.intData)))
|
||||||
default:
|
default:
|
||||||
log.Errorf("Unsupported interrupt mode %d\n", z.interrupt_mode)
|
log.Errorf("Unsupported interrupt mode %d\n", z.interruptMode)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// z80_gen_nmi function to call when an NMI is to be serviced
|
// GenNMI function to call when an NMI is to be serviced
|
||||||
func (z *Z80) z80_gen_nmi() {
|
func (z *Z80) GenNMI() {
|
||||||
z.nmi_pending = true
|
z.nmiPending = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// z80_gen_int function to call when an INT is to be serviced
|
// GenINT function to call when an INT is to be serviced
|
||||||
func (z *Z80) z80_gen_int(data byte) {
|
func (z *Z80) GenINT(data byte) {
|
||||||
z.int_pending = true
|
z.intPending = true
|
||||||
z.int_data = data
|
z.intData = data
|
||||||
}
|
}
|
||||||
|
|
||||||
// executes a non-prefixed opcode
|
// executes a non-prefixed opcode
|
||||||
func (z *Z80) exec_opcode(opcode byte) {
|
func (z *Z80) execOpcode(opcode byte) {
|
||||||
z.cyc += uint64(cyc_00[opcode])
|
z.cycleCount += uint32(cycles00[opcode])
|
||||||
z.inc_r()
|
z.incR()
|
||||||
|
|
||||||
switch opcode {
|
switch opcode {
|
||||||
case 0x7F:
|
case 0x7F:
|
||||||
@ -737,110 +712,110 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
z.l = z.l // ld l,l
|
z.l = z.l // ld l,l
|
||||||
|
|
||||||
case 0x7E:
|
case 0x7E:
|
||||||
z.a = z.rb(z.get_hl()) // ld a,(hl)
|
z.a = z.rb(z.hl()) // ld a,(hl)
|
||||||
case 0x46:
|
case 0x46:
|
||||||
z.b = z.rb(z.get_hl()) // ld b,(hl)
|
z.b = z.rb(z.hl()) // ld b,(hl)
|
||||||
case 0x4E:
|
case 0x4E:
|
||||||
z.c = z.rb(z.get_hl()) // ld c,(hl)
|
z.c = z.rb(z.hl()) // ld c,(hl)
|
||||||
case 0x56:
|
case 0x56:
|
||||||
z.d = z.rb(z.get_hl()) // ld d,(hl)
|
z.d = z.rb(z.hl()) // ld d,(hl)
|
||||||
case 0x5E:
|
case 0x5E:
|
||||||
z.e = z.rb(z.get_hl()) // ld e,(hl)
|
z.e = z.rb(z.hl()) // ld e,(hl)
|
||||||
case 0x66:
|
case 0x66:
|
||||||
z.h = z.rb(z.get_hl()) // ld h,(hl)
|
z.h = z.rb(z.hl()) // ld h,(hl)
|
||||||
case 0x6E:
|
case 0x6E:
|
||||||
z.l = z.rb(z.get_hl()) // ld l,(hl)
|
z.l = z.rb(z.hl()) // ld l,(hl)
|
||||||
|
|
||||||
case 0x77:
|
case 0x77:
|
||||||
z.wb(z.get_hl(), z.a) // ld (hl),a
|
z.wb(z.hl(), z.a) // ld (hl),a
|
||||||
case 0x70:
|
case 0x70:
|
||||||
z.wb(z.get_hl(), z.b) // ld (hl),b
|
z.wb(z.hl(), z.b) // ld (hl),b
|
||||||
case 0x71:
|
case 0x71:
|
||||||
z.wb(z.get_hl(), z.c) // ld (hl),c
|
z.wb(z.hl(), z.c) // ld (hl),c
|
||||||
case 0x72:
|
case 0x72:
|
||||||
z.wb(z.get_hl(), z.d) // ld (hl),d
|
z.wb(z.hl(), z.d) // ld (hl),d
|
||||||
case 0x73:
|
case 0x73:
|
||||||
z.wb(z.get_hl(), z.e) // ld (hl),e
|
z.wb(z.hl(), z.e) // ld (hl),e
|
||||||
case 0x74:
|
case 0x74:
|
||||||
z.wb(z.get_hl(), z.h) // ld (hl),h
|
z.wb(z.hl(), z.h) // ld (hl),h
|
||||||
case 0x75:
|
case 0x75:
|
||||||
z.wb(z.get_hl(), z.l) // ld (hl),l
|
z.wb(z.hl(), z.l) // ld (hl),l
|
||||||
|
|
||||||
case 0x3E:
|
case 0x3E:
|
||||||
z.a = z.nextb() // ld a,*
|
z.a = z.nextB() // ld a,*
|
||||||
case 0x06:
|
case 0x06:
|
||||||
z.b = z.nextb() // ld b,*
|
z.b = z.nextB() // ld b,*
|
||||||
case 0x0E:
|
case 0x0E:
|
||||||
z.c = z.nextb() // ld c,*
|
z.c = z.nextB() // ld c,*
|
||||||
case 0x16:
|
case 0x16:
|
||||||
z.d = z.nextb() // ld d,*
|
z.d = z.nextB() // ld d,*
|
||||||
case 0x1E:
|
case 0x1E:
|
||||||
z.e = z.nextb() // ld e,*
|
z.e = z.nextB() // ld e,*
|
||||||
case 0x26:
|
case 0x26:
|
||||||
z.h = z.nextb() // ld h,*
|
z.h = z.nextB() // ld h,*
|
||||||
case 0x2E:
|
case 0x2E:
|
||||||
z.l = z.nextb() // ld l,*
|
z.l = z.nextB() // ld l,*
|
||||||
case 0x36:
|
case 0x36:
|
||||||
z.wb(z.get_hl(), z.nextb()) // ld (hl),*
|
z.wb(z.hl(), z.nextB()) // ld (hl),*
|
||||||
case 0x0A:
|
case 0x0A:
|
||||||
// ld a,(bc)
|
// ld a,(bc)
|
||||||
z.a = z.rb(z.get_bc())
|
z.a = z.rb(z.bc())
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x1A:
|
case 0x1A:
|
||||||
// ld a,(de)
|
// ld a,(de)
|
||||||
z.a = z.rb(z.get_de())
|
z.a = z.rb(z.de())
|
||||||
z.mem_ptr = z.get_de() + 1
|
z.memPtr = z.de() + 1
|
||||||
case 0x3A:
|
case 0x3A:
|
||||||
// ld a,(**)
|
// ld a,(**)
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.a = z.rb(addr)
|
z.a = z.rb(addr)
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x02:
|
case 0x02:
|
||||||
// ld (bc),a
|
// ld (bc),a
|
||||||
z.wb(z.get_bc(), z.a)
|
z.wb(z.bc(), z.a)
|
||||||
z.mem_ptr = (uint16(z.a) << 8) | ((z.get_bc() + 1) & 0xFF)
|
z.memPtr = (uint16(z.a) << 8) | ((z.bc() + 1) & 0xFF)
|
||||||
case 0x12:
|
case 0x12:
|
||||||
// ld (de),a
|
// ld (de),a
|
||||||
z.wb(z.get_de(), z.a)
|
z.wb(z.de(), z.a)
|
||||||
z.mem_ptr = (uint16(z.a) << 8) | ((z.get_de() + 1) & 0xFF)
|
z.memPtr = (uint16(z.a) << 8) | ((z.de() + 1) & 0xFF)
|
||||||
case 0x32:
|
case 0x32:
|
||||||
// ld (**),a
|
// ld (**),a
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.wb(addr, z.a)
|
z.wb(addr, z.a)
|
||||||
z.mem_ptr = (uint16(z.a) << 8) | ((addr + 1) & 0xFF)
|
z.memPtr = (uint16(z.a) << 8) | ((addr + 1) & 0xFF)
|
||||||
case 0x01:
|
case 0x01:
|
||||||
z.set_bc(z.nextw()) // ld bc,**
|
z.setBC(z.nextW()) // ld bc,**
|
||||||
case 0x11:
|
case 0x11:
|
||||||
z.set_de(z.nextw()) // ld de,**
|
z.setDE(z.nextW()) // ld de,**
|
||||||
case 0x21:
|
case 0x21:
|
||||||
z.set_hl(z.nextw()) // ld hl,**
|
z.setHL(z.nextW()) // ld hl,**
|
||||||
case 0x31:
|
case 0x31:
|
||||||
z.sp = z.nextw() // ld sp,**
|
z.sp = z.nextW() // ld sp,**
|
||||||
|
|
||||||
case 0x2A:
|
case 0x2A:
|
||||||
// ld hl,(**)
|
// ld hl,(**)
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.set_hl(z.rw(addr))
|
z.setHL(z.rw(addr))
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x22:
|
case 0x22:
|
||||||
// ld (**),hl
|
// ld (**),hl
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.ww(addr, z.get_hl())
|
z.ww(addr, z.hl())
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0xF9:
|
case 0xF9:
|
||||||
z.sp = z.get_hl() // ld sp,hl
|
z.sp = z.hl() // ld sp,hl
|
||||||
|
|
||||||
case 0xEB:
|
case 0xEB:
|
||||||
// ex de,hl
|
// ex de,hl
|
||||||
de := z.get_de()
|
de := z.de()
|
||||||
z.set_de(z.get_hl())
|
z.setDE(z.hl())
|
||||||
z.set_hl(de)
|
z.setHL(de)
|
||||||
case 0xE3:
|
case 0xE3:
|
||||||
// ex (sp),hl
|
// ex (sp),hl
|
||||||
val := z.rw(z.sp)
|
val := z.rw(z.sp)
|
||||||
z.ww(z.sp, z.get_hl())
|
z.ww(z.sp, z.hl())
|
||||||
z.set_hl(val)
|
z.setHL(val)
|
||||||
z.mem_ptr = val
|
z.memPtr = val
|
||||||
case 0x87:
|
case 0x87:
|
||||||
z.a = z.addb(z.a, z.a, false) // add a,a
|
z.a = z.addb(z.a, z.a, false) // add a,a
|
||||||
case 0x80:
|
case 0x80:
|
||||||
@ -856,9 +831,9 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
case 0x85:
|
case 0x85:
|
||||||
z.a = z.addb(z.a, z.l, false) // add a,l
|
z.a = z.addb(z.a, z.l, false) // add a,l
|
||||||
case 0x86:
|
case 0x86:
|
||||||
z.a = z.addb(z.a, z.rb(z.get_hl()), false) // add a,(hl)
|
z.a = z.addb(z.a, z.rb(z.hl()), false) // add a,(hl)
|
||||||
case 0xC6:
|
case 0xC6:
|
||||||
z.a = z.addb(z.a, z.nextb(), false) // add a,*
|
z.a = z.addb(z.a, z.nextB(), false) // add a,*
|
||||||
|
|
||||||
case 0x8F:
|
case 0x8F:
|
||||||
z.a = z.addb(z.a, z.a, z.cf) // adc a,a
|
z.a = z.addb(z.a, z.a, z.cf) // adc a,a
|
||||||
@ -875,9 +850,9 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
case 0x8D:
|
case 0x8D:
|
||||||
z.a = z.addb(z.a, z.l, z.cf) // adc a,l
|
z.a = z.addb(z.a, z.l, z.cf) // adc a,l
|
||||||
case 0x8E:
|
case 0x8E:
|
||||||
z.a = z.addb(z.a, z.rb(z.get_hl()), z.cf) // adc a,(hl)
|
z.a = z.addb(z.a, z.rb(z.hl()), z.cf) // adc a,(hl)
|
||||||
case 0xCE:
|
case 0xCE:
|
||||||
z.a = z.addb(z.a, z.nextb(), z.cf) // adc a,*
|
z.a = z.addb(z.a, z.nextB(), z.cf) // adc a,*
|
||||||
|
|
||||||
case 0x97:
|
case 0x97:
|
||||||
z.a = z.subb(z.a, z.a, false) // sub a,a
|
z.a = z.subb(z.a, z.a, false) // sub a,a
|
||||||
@ -894,9 +869,9 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
case 0x95:
|
case 0x95:
|
||||||
z.a = z.subb(z.a, z.l, false) // sub a,l
|
z.a = z.subb(z.a, z.l, false) // sub a,l
|
||||||
case 0x96:
|
case 0x96:
|
||||||
z.a = z.subb(z.a, z.rb(z.get_hl()), false) // sub a,(hl)
|
z.a = z.subb(z.a, z.rb(z.hl()), false) // sub a,(hl)
|
||||||
case 0xD6:
|
case 0xD6:
|
||||||
z.a = z.subb(z.a, z.nextb(), false) // sub a,*
|
z.a = z.subb(z.a, z.nextB(), false) // sub a,*
|
||||||
|
|
||||||
case 0x9F:
|
case 0x9F:
|
||||||
z.a = z.subb(z.a, z.a, z.cf) // sbc a,a
|
z.a = z.subb(z.a, z.a, z.cf) // sbc a,a
|
||||||
@ -913,16 +888,16 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
case 0x9D:
|
case 0x9D:
|
||||||
z.a = z.subb(z.a, z.l, z.cf) // sbc a,l
|
z.a = z.subb(z.a, z.l, z.cf) // sbc a,l
|
||||||
case 0x9E:
|
case 0x9E:
|
||||||
z.a = z.subb(z.a, z.rb(z.get_hl()), z.cf) // sbc a,(hl)
|
z.a = z.subb(z.a, z.rb(z.hl()), z.cf) // sbc a,(hl)
|
||||||
case 0xDE:
|
case 0xDE:
|
||||||
z.a = z.subb(z.a, z.nextb(), z.cf) // sbc a,*
|
z.a = z.subb(z.a, z.nextB(), z.cf) // sbc a,*
|
||||||
|
|
||||||
case 0x09:
|
case 0x09:
|
||||||
z.addhl(z.get_bc()) // add hl,bc
|
z.addhl(z.bc()) // add hl,bc
|
||||||
case 0x19:
|
case 0x19:
|
||||||
z.addhl(z.get_de()) // add hl,de
|
z.addhl(z.de()) // add hl,de
|
||||||
case 0x29:
|
case 0x29:
|
||||||
z.addhl(z.get_hl()) // add hl,hl
|
z.addhl(z.hl()) // add hl,hl
|
||||||
case 0x39:
|
case 0x39:
|
||||||
z.addhl(z.sp) // add hl,sp
|
z.addhl(z.sp) // add hl,sp
|
||||||
|
|
||||||
@ -930,10 +905,10 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
z.iff1 = false
|
z.iff1 = false
|
||||||
z.iff2 = false // di
|
z.iff2 = false // di
|
||||||
case 0xFB:
|
case 0xFB:
|
||||||
z.iff_delay = 1 // ei
|
z.iffDelay = 1 // ei
|
||||||
case 0x00: // nop
|
case 0x00: // nop
|
||||||
case 0x76:
|
case 0x76:
|
||||||
z.halted = true // halt
|
z.isHalted = true // halt
|
||||||
z.pc--
|
z.pc--
|
||||||
case 0x3C:
|
case 0x3C:
|
||||||
z.a = z.inc(z.a) // inc a
|
z.a = z.inc(z.a) // inc a
|
||||||
@ -951,8 +926,8 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
z.l = z.inc(z.l) // inc l
|
z.l = z.inc(z.l) // inc l
|
||||||
case 0x34:
|
case 0x34:
|
||||||
// inc (hl)
|
// inc (hl)
|
||||||
result := z.inc(z.rb(z.get_hl()))
|
result := z.inc(z.rb(z.hl()))
|
||||||
z.wb(z.get_hl(), result)
|
z.wb(z.hl(), result)
|
||||||
case 0x3D:
|
case 0x3D:
|
||||||
z.a = z.dec(z.a) // dec a
|
z.a = z.dec(z.a) // dec a
|
||||||
case 0x05:
|
case 0x05:
|
||||||
@ -969,22 +944,22 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
z.l = z.dec(z.l) // dec l
|
z.l = z.dec(z.l) // dec l
|
||||||
case 0x35:
|
case 0x35:
|
||||||
// dec (hl)
|
// dec (hl)
|
||||||
result := z.dec(z.rb(z.get_hl()))
|
result := z.dec(z.rb(z.hl()))
|
||||||
z.wb(z.get_hl(), result)
|
z.wb(z.hl(), result)
|
||||||
case 0x03:
|
case 0x03:
|
||||||
z.set_bc(z.get_bc() + 1) // inc bc
|
z.setBC(z.bc() + 1) // inc bc
|
||||||
case 0x13:
|
case 0x13:
|
||||||
z.set_de(z.get_de() + 1) // inc de
|
z.setDE(z.de() + 1) // inc de
|
||||||
case 0x23:
|
case 0x23:
|
||||||
z.set_hl(z.get_hl() + 1) // inc hl
|
z.setHL(z.hl() + 1) // inc hl
|
||||||
case 0x33:
|
case 0x33:
|
||||||
z.sp = z.sp + 1 // inc sp
|
z.sp = z.sp + 1 // inc sp
|
||||||
case 0x0B:
|
case 0x0B:
|
||||||
z.set_bc(z.get_bc() - 1) // dec bc
|
z.setBC(z.bc() - 1) // dec bc
|
||||||
case 0x1B:
|
case 0x1B:
|
||||||
z.set_de(z.get_de() - 1) // dec de
|
z.setDE(z.de() - 1) // dec de
|
||||||
case 0x2B:
|
case 0x2B:
|
||||||
z.set_hl(z.get_hl() - 1) // dec hl
|
z.setHL(z.hl() - 1) // dec hl
|
||||||
case 0x3B:
|
case 0x3B:
|
||||||
z.sp = z.sp - 1 // dec sp
|
z.sp = z.sp - 1 // dec sp
|
||||||
case 0x27:
|
case 0x27:
|
||||||
@ -1000,13 +975,13 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
z.cf = true
|
z.cf = true
|
||||||
z.nf = false
|
z.nf = false
|
||||||
z.hf = false
|
z.hf = false
|
||||||
z.updateXY(z.a | z.get_f())
|
z.updateXY(z.a | z.f())
|
||||||
case 0x3F:
|
case 0x3F:
|
||||||
// ccf
|
// ccf
|
||||||
z.hf = z.cf
|
z.hf = z.cf
|
||||||
z.cf = !z.cf
|
z.cf = !z.cf
|
||||||
z.nf = false
|
z.nf = false
|
||||||
z.updateXY(z.a | z.get_f())
|
z.updateXY(z.a | z.f())
|
||||||
case 0x07:
|
case 0x07:
|
||||||
// rlca (rotate left)
|
// rlca (rotate left)
|
||||||
z.cf = z.a&0x80 != 0
|
z.cf = z.a&0x80 != 0
|
||||||
@ -1052,9 +1027,9 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
case 0xA5:
|
case 0xA5:
|
||||||
z.land(z.l) // and l
|
z.land(z.l) // and l
|
||||||
case 0xA6:
|
case 0xA6:
|
||||||
z.land(z.rb(z.get_hl())) // and (hl)
|
z.land(z.rb(z.hl())) // and (hl)
|
||||||
case 0xE6:
|
case 0xE6:
|
||||||
z.land(z.nextb()) // and *
|
z.land(z.nextB()) // and *
|
||||||
|
|
||||||
case 0xAF:
|
case 0xAF:
|
||||||
z.lxor(z.a) // xor a
|
z.lxor(z.a) // xor a
|
||||||
@ -1071,9 +1046,9 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
case 0xAD:
|
case 0xAD:
|
||||||
z.lxor(z.l) // xor l
|
z.lxor(z.l) // xor l
|
||||||
case 0xAE:
|
case 0xAE:
|
||||||
z.lxor(z.rb(z.get_hl())) // xor (hl)
|
z.lxor(z.rb(z.hl())) // xor (hl)
|
||||||
case 0xEE:
|
case 0xEE:
|
||||||
z.lxor(z.nextb()) // xor *
|
z.lxor(z.nextB()) // xor *
|
||||||
|
|
||||||
case 0xB7:
|
case 0xB7:
|
||||||
z.lor(z.a) // or a
|
z.lor(z.a) // or a
|
||||||
@ -1090,9 +1065,9 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
case 0xB5:
|
case 0xB5:
|
||||||
z.lor(z.l) // or l
|
z.lor(z.l) // or l
|
||||||
case 0xB6:
|
case 0xB6:
|
||||||
z.lor(z.rb(z.get_hl())) // or (hl)
|
z.lor(z.rb(z.hl())) // or (hl)
|
||||||
case 0xF6:
|
case 0xF6:
|
||||||
z.lor(z.nextb()) // or *
|
z.lor(z.nextB()) // or *
|
||||||
|
|
||||||
case 0xBF:
|
case 0xBF:
|
||||||
z.cp(z.a) // cp a
|
z.cp(z.a) // cp a
|
||||||
@ -1109,12 +1084,12 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
case 0xBD:
|
case 0xBD:
|
||||||
z.cp(z.l) // cp l
|
z.cp(z.l) // cp l
|
||||||
case 0xBE:
|
case 0xBE:
|
||||||
z.cp(z.rb(z.get_hl())) // cp (hl)
|
z.cp(z.rb(z.hl())) // cp (hl)
|
||||||
case 0xFE:
|
case 0xFE:
|
||||||
z.cp(z.nextb()) // cp *
|
z.cp(z.nextB()) // cp *
|
||||||
|
|
||||||
case 0xC3:
|
case 0xC3:
|
||||||
z.jump(z.nextw()) // jm **
|
z.jump(z.nextW()) // jm **
|
||||||
case 0xC2:
|
case 0xC2:
|
||||||
z.cond_jump(!z.zf) // jp nz, **
|
z.cond_jump(!z.zf) // jp nz, **
|
||||||
case 0xCA:
|
case 0xCA:
|
||||||
@ -1136,8 +1111,8 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
z.b--
|
z.b--
|
||||||
z.cond_jr(z.b != 0) // djnz *
|
z.cond_jr(z.b != 0) // djnz *
|
||||||
case 0x18:
|
case 0x18:
|
||||||
z.pc += uint16(z.nextb()) // jr *
|
z.pc += uint16(z.nextB()) // jr *
|
||||||
z.mem_ptr = z.pc
|
z.memPtr = z.pc
|
||||||
case 0x20:
|
case 0x20:
|
||||||
z.cond_jr(!z.zf) // jr nz, *
|
z.cond_jr(!z.zf) // jr nz, *
|
||||||
case 0x28:
|
case 0x28:
|
||||||
@ -1148,9 +1123,9 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
z.cond_jr(z.cf) // jr c, *
|
z.cond_jr(z.cf) // jr c, *
|
||||||
|
|
||||||
case 0xE9:
|
case 0xE9:
|
||||||
z.pc = z.get_hl() // jp (hl)
|
z.pc = z.hl() // jp (hl)
|
||||||
case 0xCD:
|
case 0xCD:
|
||||||
z.call(z.nextw()) // call
|
z.call(z.nextW()) // call
|
||||||
|
|
||||||
case 0xC4:
|
case 0xC4:
|
||||||
z.cond_call(!z.zf) // cnz
|
z.cond_call(!z.zf) // cnz
|
||||||
@ -1206,42 +1181,42 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
z.call(0x38) // rst 7
|
z.call(0x38) // rst 7
|
||||||
|
|
||||||
case 0xC5:
|
case 0xC5:
|
||||||
z.pushw(z.get_bc()) // push bc
|
z.pushW(z.bc()) // push bc
|
||||||
case 0xD5:
|
case 0xD5:
|
||||||
z.pushw(z.get_de()) // push de
|
z.pushW(z.de()) // push de
|
||||||
case 0xE5:
|
case 0xE5:
|
||||||
z.pushw(z.get_hl()) // push hl
|
z.pushW(z.hl()) // push hl
|
||||||
case 0xF5:
|
case 0xF5:
|
||||||
z.pushw((uint16(z.a) << 8) | uint16(z.get_f())) // push af
|
z.pushW((uint16(z.a) << 8) | uint16(z.f())) // push af
|
||||||
|
|
||||||
case 0xC1:
|
case 0xC1:
|
||||||
z.set_bc(z.popw()) // pop bc
|
z.setBC(z.popW()) // pop bc
|
||||||
case 0xD1:
|
case 0xD1:
|
||||||
z.set_de(z.popw()) // pop de
|
z.setDE(z.popW()) // pop de
|
||||||
case 0xE1:
|
case 0xE1:
|
||||||
z.set_hl(z.popw()) // pop hl
|
z.setHL(z.popW()) // pop hl
|
||||||
case 0xF1:
|
case 0xF1:
|
||||||
// pop af
|
// pop af
|
||||||
val := z.popw()
|
val := z.popW()
|
||||||
z.a = byte(val >> 8)
|
z.a = byte(val >> 8)
|
||||||
z.set_f(byte(val))
|
z.setF(byte(val))
|
||||||
case 0xDB:
|
case 0xDB:
|
||||||
// in a,(n)
|
// in a,(n)
|
||||||
port := (uint16(z.a) << 8) | uint16(z.nextb())
|
port := (uint16(z.a) << 8) | uint16(z.nextB())
|
||||||
z.a = z.core.IORead(port)
|
z.a = z.core.IORead(port)
|
||||||
z.mem_ptr = port + 1 // (uint16(a) << 8) | (uint16(z.a+1) & 0x00ff)
|
z.memPtr = port + 1 // (uint16(a) << 8) | (uint16(z.a+1) & 0x00ff)
|
||||||
case 0xD3:
|
case 0xD3:
|
||||||
// out (n), a
|
// out (n), a
|
||||||
port := uint16(z.nextb())
|
port := uint16(z.nextB())
|
||||||
z.core.IOWrite(port, z.a)
|
z.core.IOWrite(port, z.a)
|
||||||
z.mem_ptr = ((port + 1) & 0x00ff) | (uint16(z.a) << 8)
|
z.memPtr = ((port + 1) & 0x00ff) | (uint16(z.a) << 8)
|
||||||
case 0x08:
|
case 0x08:
|
||||||
// ex af,af'
|
// ex af,af'
|
||||||
a := z.a
|
a := z.a
|
||||||
f := z.get_f()
|
f := z.f()
|
||||||
|
|
||||||
z.a = z.a_
|
z.a = z.a_
|
||||||
z.set_f(z.f_)
|
z.setF(z.f_)
|
||||||
|
|
||||||
z.a_ = a
|
z.a_ = a
|
||||||
z.f_ = f
|
z.f_ = f
|
||||||
@ -1268,13 +1243,13 @@ func (z *Z80) exec_opcode(opcode byte) {
|
|||||||
z.h_ = h
|
z.h_ = h
|
||||||
z.l_ = l
|
z.l_ = l
|
||||||
case 0xCB:
|
case 0xCB:
|
||||||
z.exec_opcode_cb(z.nextb())
|
z.execOpcodeCB(z.nextB())
|
||||||
case 0xED:
|
case 0xED:
|
||||||
z.exec_opcode_ed(z.nextb())
|
z.execOpcodeED(z.nextB())
|
||||||
case 0xDD:
|
case 0xDD:
|
||||||
z.exec_opcode_ddfd(z.nextb(), &z.ix)
|
z.execOpcodeDDFD(z.nextB(), &z.ix)
|
||||||
case 0xFD:
|
case 0xFD:
|
||||||
z.exec_opcode_ddfd(z.nextb(), &z.iy)
|
z.execOpcodeDDFD(z.nextB(), &z.iy)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Errorf("Unknown opcode %02X\n", opcode)
|
log.Errorf("Unknown opcode %02X\n", opcode)
|
||||||
|
|||||||
@ -3,9 +3,9 @@ package c99
|
|||||||
import log "github.com/sirupsen/logrus"
|
import log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
// executes a CB opcode
|
// executes a CB opcode
|
||||||
func (z *Z80) exec_opcode_cb(opcode byte) {
|
func (z *Z80) execOpcodeCB(opcode byte) {
|
||||||
z.cyc += 8
|
z.cycleCount += 8
|
||||||
z.inc_r()
|
z.incR()
|
||||||
|
|
||||||
// decoding instructions from http://z80.info/decoding.htm#cb
|
// decoding instructions from http://z80.info/decoding.htm#cb
|
||||||
x_ := (opcode >> 6) & 3 // 0b11
|
x_ := (opcode >> 6) & 3 // 0b11
|
||||||
@ -29,7 +29,7 @@ func (z *Z80) exec_opcode_cb(opcode byte) {
|
|||||||
case 5:
|
case 5:
|
||||||
reg = &z.l
|
reg = &z.l
|
||||||
case 6:
|
case 6:
|
||||||
hl = z.rb(z.get_hl())
|
hl = z.rb(z.hl())
|
||||||
reg = &hl
|
reg = &hl
|
||||||
case 7:
|
case 7:
|
||||||
reg = &z.a
|
reg = &z.a
|
||||||
@ -63,8 +63,8 @@ func (z *Z80) exec_opcode_cb(opcode byte) {
|
|||||||
|
|
||||||
// in bit (hl), x/y flags are handled differently:
|
// in bit (hl), x/y flags are handled differently:
|
||||||
if z_ == 6 {
|
if z_ == 6 {
|
||||||
z.updateXY(byte(z.mem_ptr >> 8))
|
z.updateXY(byte(z.memPtr >> 8))
|
||||||
z.cyc += 4
|
z.cycleCount += 4
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
@ -74,11 +74,11 @@ func (z *Z80) exec_opcode_cb(opcode byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (x_ == 0 || x_ == 2 || x_ == 3) && z_ == 6 {
|
if (x_ == 0 || x_ == 2 || x_ == 3) && z_ == 6 {
|
||||||
z.cyc += 7
|
z.cycleCount += 7
|
||||||
}
|
}
|
||||||
|
|
||||||
if reg == &hl {
|
if reg == &hl {
|
||||||
z.wb(z.get_hl(), hl)
|
z.wb(z.hl(), hl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ func (z *Z80) exec_opcode_dcb(opcode byte, addr uint16) {
|
|||||||
z.l = result
|
z.l = result
|
||||||
// always false
|
// always false
|
||||||
//case 6:
|
//case 6:
|
||||||
// z.wb(z.get_hl(), result)
|
// z.wb(z.hl(), result)
|
||||||
case 7:
|
case 7:
|
||||||
z.a = result
|
z.a = result
|
||||||
}
|
}
|
||||||
@ -154,9 +154,9 @@ func (z *Z80) exec_opcode_dcb(opcode byte, addr uint16) {
|
|||||||
|
|
||||||
if x_ == 1 {
|
if x_ == 1 {
|
||||||
// bit instructions take 20 cycles, others take 23
|
// bit instructions take 20 cycles, others take 23
|
||||||
z.cyc += 20
|
z.cycleCount += 20
|
||||||
} else {
|
} else {
|
||||||
z.wb(addr, result)
|
z.wb(addr, result)
|
||||||
z.cyc += 23
|
z.cycleCount += 23
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,23 @@
|
|||||||
package c99
|
package c99
|
||||||
|
|
||||||
// executes a DD/FD opcode (IZ = IX or IY)
|
// executes a DD/FD opcode (IZ = IX or IY)
|
||||||
func (z *Z80) exec_opcode_ddfd(opcode byte, iz *uint16) {
|
func (z *Z80) execOpcodeDDFD(opcode byte, iz *uint16) {
|
||||||
z.cyc += uint64(cyc_ddfd[opcode])
|
z.cycleCount += uint32(cyclesDDFD[opcode])
|
||||||
z.inc_r()
|
z.incR()
|
||||||
|
|
||||||
switch opcode {
|
switch opcode {
|
||||||
case 0xE1:
|
case 0xE1:
|
||||||
*iz = z.popw() // pop iz
|
*iz = z.popW() // pop iz
|
||||||
case 0xE5:
|
case 0xE5:
|
||||||
z.pushw(*iz) // push iz
|
z.pushW(*iz) // push iz
|
||||||
case 0xE9:
|
case 0xE9:
|
||||||
// jp iz
|
// jp iz
|
||||||
z.pc = *iz
|
z.pc = *iz
|
||||||
//z.jump(*iz)
|
//z.jump(*iz)
|
||||||
case 0x09:
|
case 0x09:
|
||||||
z.addiz(iz, z.get_bc()) // add iz,bc
|
z.addiz(iz, z.bc()) // add iz,bc
|
||||||
case 0x19:
|
case 0x19:
|
||||||
z.addiz(iz, z.get_de()) // add iz,de
|
z.addiz(iz, z.de()) // add iz,de
|
||||||
case 0x29:
|
case 0x29:
|
||||||
z.addiz(iz, *iz) // add iz,iz
|
z.addiz(iz, *iz) // add iz,iz
|
||||||
case 0x39:
|
case 0x39:
|
||||||
@ -32,13 +32,13 @@ func (z *Z80) exec_opcode_ddfd(opcode byte, iz *uint16) {
|
|||||||
case 0x8D:
|
case 0x8D:
|
||||||
z.a = z.addb(z.a, byte(*iz), z.cf) // adc a,izl
|
z.a = z.addb(z.a, byte(*iz), z.cf) // adc a,izl
|
||||||
case 0x86:
|
case 0x86:
|
||||||
z.a = z.addb(z.a, z.rb(z.displace(*iz, z.nextb())), false) // add a,(iz+*)
|
z.a = z.addb(z.a, z.rb(z.displace(*iz, z.nextB())), false) // add a,(iz+*)
|
||||||
case 0x8E:
|
case 0x8E:
|
||||||
z.a = z.addb(z.a, z.rb(z.displace(*iz, z.nextb())), z.cf) // adc a,(iz+*)
|
z.a = z.addb(z.a, z.rb(z.displace(*iz, z.nextB())), z.cf) // adc a,(iz+*)
|
||||||
case 0x96:
|
case 0x96:
|
||||||
z.a = z.subb(z.a, z.rb(z.displace(*iz, z.nextb())), false) // sub (iz+*)
|
z.a = z.subb(z.a, z.rb(z.displace(*iz, z.nextB())), false) // sub (iz+*)
|
||||||
case 0x9E:
|
case 0x9E:
|
||||||
z.a = z.subb(z.a, z.rb(z.displace(*iz, z.nextb())), z.cf) // sbc (iz+*)
|
z.a = z.subb(z.a, z.rb(z.displace(*iz, z.nextB())), z.cf) // sbc (iz+*)
|
||||||
case 0x94:
|
case 0x94:
|
||||||
z.a = z.subb(z.a, byte(*iz>>8), false) // sub izh
|
z.a = z.subb(z.a, byte(*iz>>8), false) // sub izh
|
||||||
case 0x95:
|
case 0x95:
|
||||||
@ -49,26 +49,26 @@ func (z *Z80) exec_opcode_ddfd(opcode byte, iz *uint16) {
|
|||||||
z.a = z.subb(z.a, byte(*iz), z.cf) // sbc izl
|
z.a = z.subb(z.a, byte(*iz), z.cf) // sbc izl
|
||||||
|
|
||||||
case 0xA6:
|
case 0xA6:
|
||||||
z.land(z.rb(z.displace(*iz, z.nextb()))) // and (iz+*)
|
z.land(z.rb(z.displace(*iz, z.nextB()))) // and (iz+*)
|
||||||
case 0xA4:
|
case 0xA4:
|
||||||
z.land(byte(*iz >> 8)) // and izh
|
z.land(byte(*iz >> 8)) // and izh
|
||||||
case 0xA5:
|
case 0xA5:
|
||||||
z.land(byte(*iz)) // and izl
|
z.land(byte(*iz)) // and izl
|
||||||
|
|
||||||
case 0xAE:
|
case 0xAE:
|
||||||
z.lxor(z.rb(z.displace(*iz, z.nextb()))) // xor (iz+*)
|
z.lxor(z.rb(z.displace(*iz, z.nextB()))) // xor (iz+*)
|
||||||
case 0xAC:
|
case 0xAC:
|
||||||
z.lxor(byte(*iz >> 8)) // xor izh
|
z.lxor(byte(*iz >> 8)) // xor izh
|
||||||
case 0xAD:
|
case 0xAD:
|
||||||
z.lxor(byte(*iz)) // xor izl
|
z.lxor(byte(*iz)) // xor izl
|
||||||
case 0xB6:
|
case 0xB6:
|
||||||
z.lor(z.rb(z.displace(*iz, z.nextb()))) // or (iz+*)
|
z.lor(z.rb(z.displace(*iz, z.nextB()))) // or (iz+*)
|
||||||
case 0xB4:
|
case 0xB4:
|
||||||
z.lor(byte(*iz >> 8)) // or izh
|
z.lor(byte(*iz >> 8)) // or izh
|
||||||
case 0xB5:
|
case 0xB5:
|
||||||
z.lor(byte(*iz)) // or izl
|
z.lor(byte(*iz)) // or izl
|
||||||
case 0xBE:
|
case 0xBE:
|
||||||
z.cp(z.rb(z.displace(*iz, z.nextb()))) // cp (iz+*)
|
z.cp(z.rb(z.displace(*iz, z.nextB()))) // cp (iz+*)
|
||||||
case 0xBC:
|
case 0xBC:
|
||||||
z.cp(byte(*iz >> 8)) // cp izh
|
z.cp(byte(*iz >> 8)) // cp izh
|
||||||
case 0xBD:
|
case 0xBD:
|
||||||
@ -79,11 +79,11 @@ func (z *Z80) exec_opcode_ddfd(opcode byte, iz *uint16) {
|
|||||||
*iz -= 1 // dec iz
|
*iz -= 1 // dec iz
|
||||||
case 0x34:
|
case 0x34:
|
||||||
// inc (iz+*)
|
// inc (iz+*)
|
||||||
addr := z.displace(*iz, z.nextb())
|
addr := z.displace(*iz, z.nextB())
|
||||||
z.wb(addr, z.inc(z.rb(addr)))
|
z.wb(addr, z.inc(z.rb(addr)))
|
||||||
case 0x35:
|
case 0x35:
|
||||||
// dec (iz+*)
|
// dec (iz+*)
|
||||||
addr := z.displace(*iz, z.nextb())
|
addr := z.displace(*iz, z.nextB())
|
||||||
z.wb(addr, z.dec(z.rb(addr)))
|
z.wb(addr, z.dec(z.rb(addr)))
|
||||||
case 0x24:
|
case 0x24:
|
||||||
*iz = (*iz & 0x00ff) | (uint16(z.inc(byte(*iz>>8))) << 8) // inc izh
|
*iz = (*iz & 0x00ff) | (uint16(z.inc(byte(*iz>>8))) << 8) // inc izh
|
||||||
@ -94,47 +94,47 @@ func (z *Z80) exec_opcode_ddfd(opcode byte, iz *uint16) {
|
|||||||
case 0x2D:
|
case 0x2D:
|
||||||
*iz = (*iz & 0xff00) | uint16(z.dec(byte(*iz))) // dec izl
|
*iz = (*iz & 0xff00) | uint16(z.dec(byte(*iz))) // dec izl
|
||||||
case 0x2A:
|
case 0x2A:
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
*iz = z.rw(addr) // ld iz,(**)
|
*iz = z.rw(addr) // ld iz,(**)
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x22:
|
case 0x22:
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.ww(addr, *iz) // ld (**),iz
|
z.ww(addr, *iz) // ld (**),iz
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x21:
|
case 0x21:
|
||||||
*iz = z.nextw() // ld iz,**
|
*iz = z.nextW() // ld iz,**
|
||||||
case 0x36:
|
case 0x36:
|
||||||
// ld (iz+*),*
|
// ld (iz+*),*
|
||||||
addr := z.displace(*iz, z.nextb())
|
addr := z.displace(*iz, z.nextB())
|
||||||
z.wb(addr, z.nextb())
|
z.wb(addr, z.nextB())
|
||||||
case 0x70:
|
case 0x70:
|
||||||
z.wb(z.displace(*iz, z.nextb()), z.b) // ld (iz+*),b
|
z.wb(z.displace(*iz, z.nextB()), z.b) // ld (iz+*),b
|
||||||
case 0x71:
|
case 0x71:
|
||||||
z.wb(z.displace(*iz, z.nextb()), z.c) // ld (iz+*),c
|
z.wb(z.displace(*iz, z.nextB()), z.c) // ld (iz+*),c
|
||||||
case 0x72:
|
case 0x72:
|
||||||
z.wb(z.displace(*iz, z.nextb()), z.d) // ld (iz+*),d
|
z.wb(z.displace(*iz, z.nextB()), z.d) // ld (iz+*),d
|
||||||
case 0x73:
|
case 0x73:
|
||||||
z.wb(z.displace(*iz, z.nextb()), z.e) // ld (iz+*),e
|
z.wb(z.displace(*iz, z.nextB()), z.e) // ld (iz+*),e
|
||||||
case 0x74:
|
case 0x74:
|
||||||
z.wb(z.displace(*iz, z.nextb()), z.h) // ld (iz+*),h
|
z.wb(z.displace(*iz, z.nextB()), z.h) // ld (iz+*),h
|
||||||
case 0x75:
|
case 0x75:
|
||||||
z.wb(z.displace(*iz, z.nextb()), z.l) // ld (iz+*),l
|
z.wb(z.displace(*iz, z.nextB()), z.l) // ld (iz+*),l
|
||||||
case 0x77:
|
case 0x77:
|
||||||
z.wb(z.displace(*iz, z.nextb()), z.a) // ld (iz+*),a
|
z.wb(z.displace(*iz, z.nextB()), z.a) // ld (iz+*),a
|
||||||
case 0x46:
|
case 0x46:
|
||||||
z.b = z.rb(z.displace(*iz, z.nextb())) // ld b,(iz+*)
|
z.b = z.rb(z.displace(*iz, z.nextB())) // ld b,(iz+*)
|
||||||
case 0x4E:
|
case 0x4E:
|
||||||
z.c = z.rb(z.displace(*iz, z.nextb())) // ld c,(iz+*)
|
z.c = z.rb(z.displace(*iz, z.nextB())) // ld c,(iz+*)
|
||||||
case 0x56:
|
case 0x56:
|
||||||
z.d = z.rb(z.displace(*iz, z.nextb())) // ld d,(iz+*)
|
z.d = z.rb(z.displace(*iz, z.nextB())) // ld d,(iz+*)
|
||||||
case 0x5E:
|
case 0x5E:
|
||||||
z.e = z.rb(z.displace(*iz, z.nextb())) // ld e,(iz+*)
|
z.e = z.rb(z.displace(*iz, z.nextB())) // ld e,(iz+*)
|
||||||
case 0x66:
|
case 0x66:
|
||||||
z.h = z.rb(z.displace(*iz, z.nextb())) // ld h,(iz+*)
|
z.h = z.rb(z.displace(*iz, z.nextB())) // ld h,(iz+*)
|
||||||
case 0x6E:
|
case 0x6E:
|
||||||
z.l = z.rb(z.displace(*iz, z.nextb())) // ld l,(iz+*)
|
z.l = z.rb(z.displace(*iz, z.nextB())) // ld l,(iz+*)
|
||||||
case 0x7E:
|
case 0x7E:
|
||||||
z.a = z.rb(z.displace(*iz, z.nextb())) // ld a,(iz+*)
|
z.a = z.rb(z.displace(*iz, z.nextB())) // ld a,(iz+*)
|
||||||
case 0x44:
|
case 0x44:
|
||||||
z.b = byte(*iz >> 8) // ld b,izh
|
z.b = byte(*iz >> 8) // ld b,izh
|
||||||
case 0x4C:
|
case 0x4C:
|
||||||
@ -169,7 +169,7 @@ func (z *Z80) exec_opcode_ddfd(opcode byte, iz *uint16) {
|
|||||||
case 0x67:
|
case 0x67:
|
||||||
*iz = (uint16(z.a) << 8) | (*iz & 0x00ff) // ld izh,a
|
*iz = (uint16(z.a) << 8) | (*iz & 0x00ff) // ld izh,a
|
||||||
case 0x26:
|
case 0x26:
|
||||||
*iz = (uint16(z.nextb()) << 8) | (*iz & 0x00ff) // ld izh,*
|
*iz = (uint16(z.nextB()) << 8) | (*iz & 0x00ff) // ld izh,*
|
||||||
case 0x68:
|
case 0x68:
|
||||||
*iz = (*iz & 0xff00) | uint16(z.b) // ld izl,b
|
*iz = (*iz & 0xff00) | uint16(z.b) // ld izl,b
|
||||||
case 0x69:
|
case 0x69:
|
||||||
@ -184,7 +184,7 @@ func (z *Z80) exec_opcode_ddfd(opcode byte, iz *uint16) {
|
|||||||
case 0x6F:
|
case 0x6F:
|
||||||
*iz = (*iz & 0xff00) | uint16(z.a) // ld izl,a
|
*iz = (*iz & 0xff00) | uint16(z.a) // ld izl,a
|
||||||
case 0x2E:
|
case 0x2E:
|
||||||
*iz = (*iz & 0xff00) | uint16(z.nextb()) // ld izl,*
|
*iz = (*iz & 0xff00) | uint16(z.nextB()) // ld izl,*
|
||||||
case 0xF9:
|
case 0xF9:
|
||||||
z.sp = *iz // ld sp,iz
|
z.sp = *iz // ld sp,iz
|
||||||
case 0xE3:
|
case 0xE3:
|
||||||
@ -192,15 +192,15 @@ func (z *Z80) exec_opcode_ddfd(opcode byte, iz *uint16) {
|
|||||||
val := z.rw(z.sp)
|
val := z.rw(z.sp)
|
||||||
z.ww(z.sp, *iz)
|
z.ww(z.sp, *iz)
|
||||||
*iz = val
|
*iz = val
|
||||||
z.mem_ptr = val
|
z.memPtr = val
|
||||||
case 0xCB:
|
case 0xCB:
|
||||||
addr := z.displace(*iz, z.nextb())
|
addr := z.displace(*iz, z.nextB())
|
||||||
op := z.nextb()
|
op := z.nextB()
|
||||||
z.exec_opcode_dcb(op, addr)
|
z.exec_opcode_dcb(op, addr)
|
||||||
default:
|
default:
|
||||||
// any other FD/DD opcode behaves as a non-prefixed opcode:
|
// any other FD/DD opcode behaves as a non-prefixed opcode:
|
||||||
z.exec_opcode(opcode)
|
z.execOpcode(opcode)
|
||||||
// R should not be incremented twice:
|
// R should not be incremented twice:
|
||||||
z.inc_r()
|
z.incR()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,9 @@ package c99
|
|||||||
import log "github.com/sirupsen/logrus"
|
import log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
// executes a ED opcode
|
// executes a ED opcode
|
||||||
func (z *Z80) exec_opcode_ed(opcode byte) {
|
func (z *Z80) execOpcodeED(opcode byte) {
|
||||||
z.cyc += uint64(cyc_ed[opcode])
|
z.cycleCount += uint32(cyclesED[opcode])
|
||||||
z.inc_r()
|
z.incR()
|
||||||
switch opcode {
|
switch opcode {
|
||||||
case 0x47:
|
case 0x47:
|
||||||
z.i = z.a // ld i,a
|
z.i = z.a // ld i,a
|
||||||
@ -41,10 +41,10 @@ func (z *Z80) exec_opcode_ed(opcode byte) {
|
|||||||
{
|
{
|
||||||
z.ldi()
|
z.ldi()
|
||||||
|
|
||||||
if z.get_bc() != 0 {
|
if z.bc() != 0 {
|
||||||
z.pc -= 2
|
z.pc -= 2
|
||||||
z.cyc += 5
|
z.cycleCount += 5
|
||||||
z.mem_ptr = z.pc + 1
|
z.memPtr = z.pc + 1
|
||||||
}
|
}
|
||||||
} // ldir
|
} // ldir
|
||||||
|
|
||||||
@ -54,10 +54,10 @@ func (z *Z80) exec_opcode_ed(opcode byte) {
|
|||||||
{
|
{
|
||||||
z.ldd()
|
z.ldd()
|
||||||
|
|
||||||
if z.get_bc() != 0 {
|
if z.bc() != 0 {
|
||||||
z.pc -= 2
|
z.pc -= 2
|
||||||
z.cyc += 5
|
z.cycleCount += 5
|
||||||
z.mem_ptr = z.pc + 1
|
z.memPtr = z.pc + 1
|
||||||
}
|
}
|
||||||
} // lddr
|
} // lddr
|
||||||
|
|
||||||
@ -68,10 +68,10 @@ func (z *Z80) exec_opcode_ed(opcode byte) {
|
|||||||
case 0xB1:
|
case 0xB1:
|
||||||
// cpir
|
// cpir
|
||||||
z.cpi()
|
z.cpi()
|
||||||
if z.get_bc() != 0 && !z.zf {
|
if z.bc() != 0 && !z.zf {
|
||||||
z.pc -= 2
|
z.pc -= 2
|
||||||
z.cyc += 5
|
z.cycleCount += 5
|
||||||
z.mem_ptr = z.pc + 1
|
z.memPtr = z.pc + 1
|
||||||
} else {
|
} else {
|
||||||
//z.mem_ptr++
|
//z.mem_ptr++
|
||||||
}
|
}
|
||||||
@ -79,47 +79,47 @@ func (z *Z80) exec_opcode_ed(opcode byte) {
|
|||||||
case 0xB9:
|
case 0xB9:
|
||||||
// cpdr
|
// cpdr
|
||||||
z.cpd()
|
z.cpd()
|
||||||
if z.get_bc() != 0 && !z.zf {
|
if z.bc() != 0 && !z.zf {
|
||||||
z.pc -= 2
|
z.pc -= 2
|
||||||
z.cyc += 5
|
z.cycleCount += 5
|
||||||
z.mem_ptr = z.pc + 1
|
z.memPtr = z.pc + 1
|
||||||
} else {
|
} else {
|
||||||
//z.mem_ptr++
|
//z.mem_ptr++
|
||||||
}
|
}
|
||||||
case 0x40:
|
case 0x40:
|
||||||
z.in_r_c(&z.b) // in b, (c)
|
z.inRC(&z.b) // in b, (c)
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x48:
|
case 0x48:
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
z.in_r_c(&z.c) // in c, (c)
|
z.inRC(&z.c) // in c, (c)
|
||||||
z.updateXY(z.c)
|
z.updateXY(z.c)
|
||||||
//case 0x4e:
|
//case 0x4e:
|
||||||
// ld c,(iy+dd)
|
// ld c,(iy+dd)
|
||||||
|
|
||||||
case 0x50:
|
case 0x50:
|
||||||
z.in_r_c(&z.d) // in d, (c)
|
z.inRC(&z.d) // in d, (c)
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x58:
|
case 0x58:
|
||||||
// in e, (c)
|
// in e, (c)
|
||||||
z.in_r_c(&z.e)
|
z.inRC(&z.e)
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
z.updateXY(z.e)
|
z.updateXY(z.e)
|
||||||
case 0x60:
|
case 0x60:
|
||||||
z.in_r_c(&z.h) // in h, (c)
|
z.inRC(&z.h) // in h, (c)
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x68:
|
case 0x68:
|
||||||
z.in_r_c(&z.l) // in l, (c)
|
z.inRC(&z.l) // in l, (c)
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
z.updateXY(z.l)
|
z.updateXY(z.l)
|
||||||
case 0x70:
|
case 0x70:
|
||||||
// in (c)
|
// in (c)
|
||||||
var val byte
|
var val byte
|
||||||
z.in_r_c(&val)
|
z.inRC(&val)
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x78:
|
case 0x78:
|
||||||
// in a, (c)
|
// in a, (c)
|
||||||
z.in_r_c(&z.a)
|
z.inRC(&z.a)
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
z.updateXY(z.a)
|
z.updateXY(z.a)
|
||||||
case 0xA2:
|
case 0xA2:
|
||||||
z.ini() // ini
|
z.ini() // ini
|
||||||
@ -128,7 +128,7 @@ func (z *Z80) exec_opcode_ed(opcode byte) {
|
|||||||
z.ini()
|
z.ini()
|
||||||
if z.b > 0 {
|
if z.b > 0 {
|
||||||
z.pc -= 2
|
z.pc -= 2
|
||||||
z.cyc += 5
|
z.cycleCount += 5
|
||||||
}
|
}
|
||||||
case 0xAA:
|
case 0xAA:
|
||||||
// ind
|
// ind
|
||||||
@ -138,33 +138,33 @@ func (z *Z80) exec_opcode_ed(opcode byte) {
|
|||||||
z.ind()
|
z.ind()
|
||||||
if z.b > 0 {
|
if z.b > 0 {
|
||||||
z.pc -= 2
|
z.pc -= 2
|
||||||
z.cyc += 5
|
z.cycleCount += 5
|
||||||
}
|
}
|
||||||
case 0x41:
|
case 0x41:
|
||||||
z.core.IOWrite(z.get_bc(), z.b) // out (c), b
|
z.core.IOWrite(z.bc(), z.b) // out (c), b
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x49:
|
case 0x49:
|
||||||
z.core.IOWrite(z.get_bc(), z.c) // out (c), c
|
z.core.IOWrite(z.bc(), z.c) // out (c), c
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x51:
|
case 0x51:
|
||||||
z.core.IOWrite(z.get_bc(), z.d) // out (c), d
|
z.core.IOWrite(z.bc(), z.d) // out (c), d
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x59:
|
case 0x59:
|
||||||
z.core.IOWrite(z.get_bc(), z.e) // out (c), e
|
z.core.IOWrite(z.bc(), z.e) // out (c), e
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x61:
|
case 0x61:
|
||||||
z.core.IOWrite(z.get_bc(), z.h) // out (c), h
|
z.core.IOWrite(z.bc(), z.h) // out (c), h
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x69:
|
case 0x69:
|
||||||
z.core.IOWrite(z.get_bc(), z.l) // out (c), l
|
z.core.IOWrite(z.bc(), z.l) // out (c), l
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x71:
|
case 0x71:
|
||||||
z.core.IOWrite(z.get_bc(), 0) // out (c), 0
|
z.core.IOWrite(z.bc(), 0) // out (c), 0
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0x79:
|
case 0x79:
|
||||||
// out (c), a
|
// out (c), a
|
||||||
z.core.IOWrite(z.get_bc(), z.a)
|
z.core.IOWrite(z.bc(), z.a)
|
||||||
z.mem_ptr = z.get_bc() + 1
|
z.memPtr = z.bc() + 1
|
||||||
case 0xA3:
|
case 0xA3:
|
||||||
z.outi() // outi
|
z.outi() // outi
|
||||||
case 0xB3:
|
case 0xB3:
|
||||||
@ -172,7 +172,7 @@ func (z *Z80) exec_opcode_ed(opcode byte) {
|
|||||||
z.outi()
|
z.outi()
|
||||||
if z.b > 0 {
|
if z.b > 0 {
|
||||||
z.pc -= 2
|
z.pc -= 2
|
||||||
z.cyc += 5
|
z.cycleCount += 5
|
||||||
}
|
}
|
||||||
case 0xAB:
|
case 0xAB:
|
||||||
z.outd() // outd
|
z.outd() // outd
|
||||||
@ -180,80 +180,80 @@ func (z *Z80) exec_opcode_ed(opcode byte) {
|
|||||||
// otdr
|
// otdr
|
||||||
z.outd()
|
z.outd()
|
||||||
if z.b > 0 {
|
if z.b > 0 {
|
||||||
z.cyc += 5
|
z.cycleCount += 5
|
||||||
z.pc -= 2
|
z.pc -= 2
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x42:
|
case 0x42:
|
||||||
z.sbchl(z.get_bc()) // sbc hl,bc
|
z.sbchl(z.bc()) // sbc hl,bc
|
||||||
case 0x52:
|
case 0x52:
|
||||||
z.sbchl(z.get_de()) // sbc hl,de
|
z.sbchl(z.de()) // sbc hl,de
|
||||||
case 0x62:
|
case 0x62:
|
||||||
z.sbchl(z.get_hl()) // sbc hl,hl
|
z.sbchl(z.hl()) // sbc hl,hl
|
||||||
case 0x72:
|
case 0x72:
|
||||||
z.sbchl(z.sp) // sbc hl,sp
|
z.sbchl(z.sp) // sbc hl,sp
|
||||||
case 0x4A:
|
case 0x4A:
|
||||||
z.adchl(z.get_bc()) // adc hl,bc
|
z.adchl(z.bc()) // adc hl,bc
|
||||||
case 0x5A:
|
case 0x5A:
|
||||||
z.adchl(z.get_de()) // adc hl,de
|
z.adchl(z.de()) // adc hl,de
|
||||||
case 0x6A:
|
case 0x6A:
|
||||||
z.adchl(z.get_hl()) // adc hl,hl
|
z.adchl(z.hl()) // adc hl,hl
|
||||||
case 0x7A:
|
case 0x7A:
|
||||||
z.adchl(z.sp) // adc hl,sp
|
z.adchl(z.sp) // adc hl,sp
|
||||||
case 0x43:
|
case 0x43:
|
||||||
// ld (**), bc
|
// ld (**), bc
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.ww(addr, z.get_bc())
|
z.ww(addr, z.bc())
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x53:
|
case 0x53:
|
||||||
// ld (**), de
|
// ld (**), de
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.ww(addr, z.get_de())
|
z.ww(addr, z.de())
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x63:
|
case 0x63:
|
||||||
// ld (**), hl
|
// ld (**), hl
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.ww(addr, z.get_hl())
|
z.ww(addr, z.hl())
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x73:
|
case 0x73:
|
||||||
// ld (**), hl
|
// ld (**), hl
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.ww(addr, z.sp)
|
z.ww(addr, z.sp)
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x4B:
|
case 0x4B:
|
||||||
// ld bc, (**)
|
// ld bc, (**)
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.set_bc(z.rw(addr))
|
z.setBC(z.rw(addr))
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x5B:
|
case 0x5B:
|
||||||
// ld de, (**)
|
// ld de, (**)
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.set_de(z.rw(addr))
|
z.setDE(z.rw(addr))
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x6B:
|
case 0x6B:
|
||||||
// ld hl, (**)
|
// ld hl, (**)
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.set_hl(z.rw(addr))
|
z.setHL(z.rw(addr))
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x7B:
|
case 0x7B:
|
||||||
// ld sp,(**)
|
// ld sp,(**)
|
||||||
addr := z.nextw()
|
addr := z.nextW()
|
||||||
z.sp = z.rw(addr)
|
z.sp = z.rw(addr)
|
||||||
z.mem_ptr = addr + 1
|
z.memPtr = addr + 1
|
||||||
case 0x44, 0x54, 0x64, 0x74, 0x4C, 0x5C, 0x6C, 0x7C:
|
case 0x44, 0x54, 0x64, 0x74, 0x4C, 0x5C, 0x6C, 0x7C:
|
||||||
z.a = z.subb(0, z.a, false) // neg
|
z.a = z.subb(0, z.a, false) // neg
|
||||||
case 0x46, 0x4e, 0x66, 0x6e:
|
case 0x46, 0x4e, 0x66, 0x6e:
|
||||||
z.interrupt_mode = 0 // im 0
|
z.interruptMode = 0 // im 0
|
||||||
case 0x56, 0x76:
|
case 0x56, 0x76:
|
||||||
z.interrupt_mode = 1 // im 1
|
z.interruptMode = 1 // im 1
|
||||||
case 0x5E, 0x7E:
|
case 0x5E, 0x7E:
|
||||||
z.interrupt_mode = 2 // im 2
|
z.interruptMode = 2 // im 2
|
||||||
case 0x67:
|
case 0x67:
|
||||||
// rrd
|
// rrd
|
||||||
a := z.a
|
a := z.a
|
||||||
val := z.rb(z.get_hl())
|
val := z.rb(z.hl())
|
||||||
z.a = (a & 0xF0) | (val & 0xF)
|
z.a = (a & 0xF0) | (val & 0xF)
|
||||||
z.wb(z.get_hl(), (val>>4)|(a<<4))
|
z.wb(z.hl(), (val>>4)|(a<<4))
|
||||||
|
|
||||||
z.nf = false
|
z.nf = false
|
||||||
z.hf = false
|
z.hf = false
|
||||||
@ -261,20 +261,20 @@ func (z *Z80) exec_opcode_ed(opcode byte) {
|
|||||||
z.zf = z.a == 0
|
z.zf = z.a == 0
|
||||||
z.sf = z.a&0x80 != 0
|
z.sf = z.a&0x80 != 0
|
||||||
z.pf = parity(z.a)
|
z.pf = parity(z.a)
|
||||||
z.mem_ptr = z.get_hl() + 1
|
z.memPtr = z.hl() + 1
|
||||||
case 0x6F:
|
case 0x6F:
|
||||||
// rld
|
// rld
|
||||||
a := z.a
|
a := z.a
|
||||||
val := z.rb(z.get_hl())
|
val := z.rb(z.hl())
|
||||||
z.a = (a & 0xF0) | (val >> 4)
|
z.a = (a & 0xF0) | (val >> 4)
|
||||||
z.wb(z.get_hl(), (val<<4)|(a&0xF))
|
z.wb(z.hl(), (val<<4)|(a&0xF))
|
||||||
z.nf = false
|
z.nf = false
|
||||||
z.hf = false
|
z.hf = false
|
||||||
z.updateXY(z.a)
|
z.updateXY(z.a)
|
||||||
z.zf = z.a == 0
|
z.zf = z.a == 0
|
||||||
z.sf = z.a&0x80 != 0
|
z.sf = z.a&0x80 != 0
|
||||||
z.pf = parity(z.a)
|
z.pf = parity(z.a)
|
||||||
z.mem_ptr = z.get_hl() + 1
|
z.memPtr = z.hl() + 1
|
||||||
default:
|
default:
|
||||||
log.Errorf("Unknown ED opcode: %02X\n", opcode)
|
log.Errorf("Unknown ED opcode: %02X\n", opcode)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ type CPUInterface interface {
|
|||||||
// Reset CPU to initial state
|
// Reset CPU to initial state
|
||||||
Reset()
|
Reset()
|
||||||
// RunInstruction Run single instruction, return number of CPU cycles
|
// RunInstruction Run single instruction, return number of CPU cycles
|
||||||
RunInstruction() uint64
|
RunInstruction() uint32
|
||||||
// GetState Get current CPU state
|
// GetState Get current CPU state
|
||||||
GetState() *Z80CPU
|
GetState() *Z80CPU
|
||||||
// SetState Set current CPU state
|
// SetState Set current CPU state
|
||||||
@ -68,7 +68,7 @@ type Z80CPU struct {
|
|||||||
Halted bool
|
Halted bool
|
||||||
DoDelayedDI bool
|
DoDelayedDI bool
|
||||||
DoDelayedEI bool
|
DoDelayedEI bool
|
||||||
CycleCounter byte
|
CycleCount uint32
|
||||||
InterruptOccurred bool
|
InterruptOccurred bool
|
||||||
MemPtr uint16
|
MemPtr uint16
|
||||||
//core MemIoRW
|
//core MemIoRW
|
||||||
|
|||||||
@ -6,8 +6,6 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
"okemu/z80"
|
"okemu/z80"
|
||||||
"okemu/z80/c99"
|
"okemu/z80/c99"
|
||||||
|
|
||||||
// "okemu/z80/c99"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -17,7 +15,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
ScanNone int = iota
|
ScanNone int = iota
|
||||||
ScanDescr
|
ScanDesc
|
||||||
ScanEvent
|
ScanEvent
|
||||||
ScanRegs
|
ScanRegs
|
||||||
ScanState
|
ScanState
|
||||||
@ -157,7 +155,7 @@ func parseTestExpected() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ScanNone == scanState {
|
if ScanNone == scanState {
|
||||||
scanState = ScanDescr
|
scanState = ScanDesc
|
||||||
} else if len(line) > 0 && line[0] == ' ' {
|
} else if len(line) > 0 && line[0] == ' ' {
|
||||||
scanState = ScanEvent
|
scanState = ScanEvent
|
||||||
}
|
}
|
||||||
@ -168,7 +166,7 @@ func parseTestExpected() {
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
switch scanState {
|
switch scanState {
|
||||||
case ScanDescr:
|
case ScanDesc:
|
||||||
testName = line
|
testName = line
|
||||||
scanState = ScanRegs
|
scanState = ScanRegs
|
||||||
case ScanEvent:
|
case ScanEvent:
|
||||||
@ -214,12 +212,12 @@ func parseTestIn() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ScanNone == scanState {
|
if ScanNone == scanState {
|
||||||
scanState = ScanDescr
|
scanState = ScanDesc
|
||||||
} else if line == "-1" {
|
} else if line == "-1" {
|
||||||
scanState = ScanEnd
|
scanState = ScanEnd
|
||||||
}
|
}
|
||||||
switch scanState {
|
switch scanState {
|
||||||
case ScanDescr:
|
case ScanDesc:
|
||||||
testName = line
|
testName = line
|
||||||
scanState = ScanRegs
|
scanState = ScanRegs
|
||||||
case ScanRegs:
|
case ScanRegs:
|
||||||
@ -401,28 +399,21 @@ func TestZ80Fuse(t *testing.T) {
|
|||||||
t.Logf("Fuse-type Z80 emulator test")
|
t.Logf("Fuse-type Z80 emulator test")
|
||||||
computer.cpu.Reset()
|
computer.cpu.Reset()
|
||||||
for _, name := range testNames {
|
for _, name := range testNames {
|
||||||
z80Test := z80TestsIn[name]
|
setComputerState(z80TestsIn[name])
|
||||||
//t.Logf("Run test: %s", name)
|
|
||||||
setComputerState(z80Test)
|
|
||||||
//if name == "edb9" {
|
|
||||||
// t.Logf("stop test")
|
|
||||||
//}
|
|
||||||
|
|
||||||
exp, exists := z80TestsExpected[name]
|
exp, exists := z80TestsExpected[name]
|
||||||
if !exists {
|
if !exists {
|
||||||
t.Errorf("Expected values for test %s not exists!", name)
|
t.Errorf("Expected values for test %s not exists!", name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cy := uint64(0)
|
cy := uint32(0)
|
||||||
for {
|
for {
|
||||||
cy += computer.cpu.RunInstruction()
|
cy += computer.cpu.RunInstruction()
|
||||||
if cy >= uint64(exp.state.tStates) {
|
if cy >= uint32(exp.state.tStates) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkComputerState(t, name)
|
checkComputerState(t, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setComputerState(test Z80TestIn) {
|
func setComputerState(test Z80TestIn) {
|
||||||
@ -455,7 +446,7 @@ func setComputerState(test Z80TestIn) {
|
|||||||
Halted: test.state.isHalted,
|
Halted: test.state.isHalted,
|
||||||
DoDelayedDI: false,
|
DoDelayedDI: false,
|
||||||
DoDelayedEI: false,
|
DoDelayedEI: false,
|
||||||
CycleCounter: 0,
|
CycleCount: 0,
|
||||||
InterruptOccurred: false,
|
InterruptOccurred: false,
|
||||||
MemPtr: test.registers.MemPtr,
|
MemPtr: test.registers.MemPtr,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,101 +0,0 @@
|
|||||||
package js
|
|
||||||
|
|
||||||
const OpHalt = 0x76
|
|
||||||
const OpLdBB = 0x40
|
|
||||||
const OpAddAB = 0x80
|
|
||||||
const OpRetNz = 0xc0
|
|
||||||
|
|
||||||
var CycleCounts = []byte{
|
|
||||||
4, 10, 7, 6, 4, 4, 7, 4, 4, 11, 7, 6, 4, 4, 7, 4,
|
|
||||||
8, 10, 7, 6, 4, 4, 7, 4, 12, 11, 7, 6, 4, 4, 7, 4,
|
|
||||||
7, 10, 16, 6, 4, 4, 7, 4, 7, 11, 16, 6, 4, 4, 7, 4,
|
|
||||||
7, 10, 13, 6, 11, 11, 10, 4, 7, 11, 13, 6, 4, 4, 7, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
|
||||||
7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
|
||||||
5, 10, 10, 10, 10, 11, 7, 11, 5, 10, 10, 0, 10, 17, 7, 11,
|
|
||||||
5, 10, 10, 11, 10, 11, 7, 11, 5, 4, 10, 11, 10, 0, 7, 11,
|
|
||||||
5, 10, 10, 19, 10, 11, 7, 11, 5, 4, 10, 4, 10, 0, 7, 11,
|
|
||||||
5, 10, 10, 4, 10, 11, 7, 11, 5, 6, 10, 4, 10, 0, 7, 11,
|
|
||||||
}
|
|
||||||
|
|
||||||
var CycleCountsCb = []byte{
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8,
|
|
||||||
}
|
|
||||||
|
|
||||||
var CycleCountsDd = []byte{
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 14, 20, 10, 8, 8, 11, 0, 0, 15, 20, 10, 8, 8, 11, 0,
|
|
||||||
0, 0, 0, 0, 23, 23, 19, 0, 0, 15, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 8, 8, 19, 0, 0, 0, 0, 0, 8, 8, 19, 0,
|
|
||||||
0, 0, 0, 0, 8, 8, 19, 0, 0, 0, 0, 0, 8, 8, 19, 0,
|
|
||||||
8, 8, 8, 8, 8, 8, 19, 8, 8, 8, 8, 8, 8, 8, 19, 8,
|
|
||||||
19, 19, 19, 19, 19, 19, 0, 19, 0, 0, 0, 0, 8, 8, 19, 0,
|
|
||||||
0, 0, 0, 0, 8, 8, 19, 0, 0, 0, 0, 0, 8, 8, 19, 0,
|
|
||||||
0, 0, 0, 0, 8, 8, 19, 0, 0, 0, 0, 0, 8, 8, 19, 0,
|
|
||||||
0, 0, 0, 0, 8, 8, 19, 0, 0, 0, 0, 0, 8, 8, 19, 0,
|
|
||||||
0, 0, 0, 0, 8, 8, 19, 0, 0, 0, 0, 0, 8, 8, 19, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 14, 0, 23, 0, 15, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
var CycleCountsEd = []byte{
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
12, 12, 15, 20, 8, 14, 8, 9, 12, 12, 15, 20, 8, 14, 8, 9,
|
|
||||||
12, 12, 15, 20, 8, 14, 8, 9, 12, 12, 15, 20, 8, 14, 8, 9,
|
|
||||||
12, 12, 15, 20, 8, 14, 8, 18, 12, 12, 15, 20, 8, 14, 8, 18,
|
|
||||||
12, 12, 15, 20, 8, 14, 8, 0, 12, 12, 15, 20, 8, 14, 8, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
16, 16, 16, 16, 0, 0, 0, 0, 16, 16, 16, 16, 0, 0, 0, 0,
|
|
||||||
16, 16, 16, 16, 0, 0, 0, 0, 16, 16, 16, 16, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
var ParityBits = []bool{
|
|
||||||
true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true,
|
|
||||||
false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false,
|
|
||||||
false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false,
|
|
||||||
true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true,
|
|
||||||
false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false,
|
|
||||||
true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true,
|
|
||||||
true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true,
|
|
||||||
false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false,
|
|
||||||
false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false,
|
|
||||||
true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true,
|
|
||||||
true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true,
|
|
||||||
false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false,
|
|
||||||
true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true,
|
|
||||||
false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false,
|
|
||||||
false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false,
|
|
||||||
true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true,
|
|
||||||
}
|
|
||||||
899
z80/js/cpu.go
899
z80/js/cpu.go
@ -1,899 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
657
z80/js/opcode.go
657
z80/js/opcode.go
@ -1,657 +0,0 @@
|
|||||||
package js
|
|
||||||
|
|
||||||
var instructions = []func(s *Z80){
|
|
||||||
// NOP
|
|
||||||
0x00: func(s *Z80) {
|
|
||||||
// NOP
|
|
||||||
},
|
|
||||||
// LD BC, nn
|
|
||||||
0x01: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.C = s.core.MemRead(s.PC)
|
|
||||||
s.PC++
|
|
||||||
s.B = s.core.MemRead(s.PC)
|
|
||||||
},
|
|
||||||
// LD (BC), A
|
|
||||||
0x02: func(s *Z80) {
|
|
||||||
s.core.MemWrite(s.bc(), s.A)
|
|
||||||
},
|
|
||||||
// 0x03 : INC BC
|
|
||||||
0x03: func(s *Z80) {
|
|
||||||
s.incBc()
|
|
||||||
},
|
|
||||||
// 0x04 : INC B
|
|
||||||
0x04: func(s *Z80) {
|
|
||||||
s.B = s.doInc(s.B)
|
|
||||||
},
|
|
||||||
// 0x05 : DEC B
|
|
||||||
0x05: func(s *Z80) {
|
|
||||||
s.B = s.doDec(s.B)
|
|
||||||
},
|
|
||||||
// 0x06 : LD B, n
|
|
||||||
0x06: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.B = s.core.MemRead(s.PC)
|
|
||||||
},
|
|
||||||
// 0x07 : RLCA
|
|
||||||
0x07: func(s *Z80) {
|
|
||||||
// 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 *Z80) {
|
|
||||||
s.A, s.AAlt = s.AAlt, s.A
|
|
||||||
temp := s.Flags.GetFlags()
|
|
||||||
s.Flags.SetFlags(s.FlagsAlt.GetFlags()) //setFlagsRegister(s.getFlagsPrimeRegister())
|
|
||||||
s.FlagsAlt.SetFlags(temp)
|
|
||||||
},
|
|
||||||
// 0x09 : ADD HL, BC
|
|
||||||
0x09: func(s *Z80) {
|
|
||||||
s.doHlAdd(s.bc())
|
|
||||||
},
|
|
||||||
// 0x0a : LD A, (BC)
|
|
||||||
0x0A: func(s *Z80) {
|
|
||||||
s.A = s.core.MemRead(s.bc())
|
|
||||||
},
|
|
||||||
// 0x0b : DEC BC
|
|
||||||
0x0B: func(s *Z80) {
|
|
||||||
s.decBc()
|
|
||||||
},
|
|
||||||
// 0x0c : INC C
|
|
||||||
0x0C: func(s *Z80) {
|
|
||||||
s.C = s.doInc(s.C)
|
|
||||||
},
|
|
||||||
// 0x0d : DEC C
|
|
||||||
0x0D: func(s *Z80) {
|
|
||||||
s.C = s.doDec(s.C)
|
|
||||||
},
|
|
||||||
// 0x0e : LD C, n
|
|
||||||
0x0E: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.C = s.core.MemRead(s.PC)
|
|
||||||
},
|
|
||||||
// 0x0f : RRCA
|
|
||||||
0x0F: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
s.B--
|
|
||||||
s.doConditionalRelativeJump(s.B != 0)
|
|
||||||
},
|
|
||||||
// 0x11 : LD DE, nn
|
|
||||||
0x11: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
s.core.MemWrite(s.de(), s.A)
|
|
||||||
},
|
|
||||||
// 0x13 : INC DE
|
|
||||||
0x13: func(s *Z80) {
|
|
||||||
s.incDe()
|
|
||||||
},
|
|
||||||
// 0x14 : INC D
|
|
||||||
0x14: func(s *Z80) {
|
|
||||||
s.D = s.doInc(s.D)
|
|
||||||
},
|
|
||||||
// 0x15 : DEC D
|
|
||||||
0x15: func(s *Z80) {
|
|
||||||
s.D = s.doDec(s.D)
|
|
||||||
},
|
|
||||||
// 0x16 : LD D, n
|
|
||||||
0x16: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.D = s.core.MemRead(s.PC)
|
|
||||||
},
|
|
||||||
// 0x17 : RLA
|
|
||||||
0x17: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
s.doHlAdd(s.de())
|
|
||||||
},
|
|
||||||
// 0x1a : LD A, (DE)
|
|
||||||
0x1A: func(s *Z80) {
|
|
||||||
s.A = s.core.MemRead(s.de())
|
|
||||||
},
|
|
||||||
// 0x1b : DEC DE
|
|
||||||
0x1B: func(s *Z80) {
|
|
||||||
s.decDe()
|
|
||||||
},
|
|
||||||
// 0x1c : INC E
|
|
||||||
0x1C: func(s *Z80) {
|
|
||||||
s.E = s.doInc(s.E)
|
|
||||||
},
|
|
||||||
// 0x1d : DEC E
|
|
||||||
0x1D: func(s *Z80) {
|
|
||||||
s.E = s.doDec(s.E)
|
|
||||||
},
|
|
||||||
// 0x1e : LD E, n
|
|
||||||
0x1E: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.E = s.core.MemRead(s.PC)
|
|
||||||
},
|
|
||||||
// 0x1f : RRA
|
|
||||||
0x1F: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
s.doConditionalRelativeJump(!s.Flags.Z)
|
|
||||||
},
|
|
||||||
// 0x21 : LD HL, nn
|
|
||||||
0x21: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
addr := s.nextWord()
|
|
||||||
s.core.MemWrite(addr, s.L)
|
|
||||||
s.core.MemWrite(addr+1, s.H)
|
|
||||||
},
|
|
||||||
// 0x23 : INC HL
|
|
||||||
0x23: func(s *Z80) {
|
|
||||||
s.incHl()
|
|
||||||
},
|
|
||||||
// 0x24 : INC H
|
|
||||||
0x24: func(s *Z80) {
|
|
||||||
s.H = s.doInc(s.H)
|
|
||||||
},
|
|
||||||
// 0x25 : DEC H
|
|
||||||
0x25: func(s *Z80) {
|
|
||||||
s.H = s.doDec(s.H)
|
|
||||||
},
|
|
||||||
// 0x26 : LD H, n
|
|
||||||
0x26: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.H = s.core.MemRead(s.PC)
|
|
||||||
},
|
|
||||||
// 0x27 : DAA
|
|
||||||
0x27: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
s.doConditionalRelativeJump(s.Flags.Z)
|
|
||||||
},
|
|
||||||
// 0x29 : ADD HL, HL
|
|
||||||
0x29: func(s *Z80) {
|
|
||||||
s.doHlAdd(s.hl())
|
|
||||||
},
|
|
||||||
// 0x2a : LD HL, (nn)
|
|
||||||
0x2A: func(s *Z80) {
|
|
||||||
addr := s.nextWord()
|
|
||||||
s.L = s.core.MemRead(addr)
|
|
||||||
s.H = s.core.MemRead(addr + 1)
|
|
||||||
},
|
|
||||||
// 0x2b : DEC HL
|
|
||||||
0x2B: func(s *Z80) {
|
|
||||||
s.decHl()
|
|
||||||
},
|
|
||||||
// 0x2c : INC L
|
|
||||||
0x2C: func(s *Z80) {
|
|
||||||
s.L = s.doInc(s.L)
|
|
||||||
},
|
|
||||||
// 0x2d : DEC L
|
|
||||||
0x2D: func(s *Z80) {
|
|
||||||
s.L = s.doDec(s.L)
|
|
||||||
},
|
|
||||||
// 0x2e : LD L, n
|
|
||||||
0x2E: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.L = s.core.MemRead(s.PC)
|
|
||||||
},
|
|
||||||
// 0x2f : CPL
|
|
||||||
0x2F: func(s *Z80) {
|
|
||||||
s.A = ^s.A
|
|
||||||
s.Flags.N = true
|
|
||||||
s.Flags.H = true
|
|
||||||
s.updateXYFlags(s.A)
|
|
||||||
},
|
|
||||||
// 0x30 : JR NC, n
|
|
||||||
0x30: func(s *Z80) {
|
|
||||||
s.doConditionalRelativeJump(!s.Flags.C)
|
|
||||||
},
|
|
||||||
// 0x31 : LD SP, nn
|
|
||||||
0x31: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
s.core.MemWrite(s.nextWord(), s.A)
|
|
||||||
},
|
|
||||||
// 0x33 : INC SP
|
|
||||||
0x33: func(s *Z80) {
|
|
||||||
s.SP++
|
|
||||||
},
|
|
||||||
// 0x34 : INC (HL)
|
|
||||||
0x34: func(s *Z80) {
|
|
||||||
s.core.MemWrite(s.hl(), s.doInc(s.core.MemRead(s.hl())))
|
|
||||||
},
|
|
||||||
// 0x35 : DEC (HL)
|
|
||||||
0x35: func(s *Z80) {
|
|
||||||
s.core.MemWrite(s.hl(), s.doDec(s.core.MemRead(s.hl())))
|
|
||||||
},
|
|
||||||
// 0x36 : LD (HL), n
|
|
||||||
0x36: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.core.MemWrite(s.hl(), s.core.MemRead(s.PC))
|
|
||||||
},
|
|
||||||
// 0x37 : SCF
|
|
||||||
0x37: func(s *Z80) {
|
|
||||||
s.Flags.N = false
|
|
||||||
s.Flags.H = false
|
|
||||||
s.Flags.C = true
|
|
||||||
s.updateXYFlags(s.A)
|
|
||||||
},
|
|
||||||
// 0x38 : JR C, n
|
|
||||||
0x38: func(s *Z80) {
|
|
||||||
s.doConditionalRelativeJump(s.Flags.C)
|
|
||||||
},
|
|
||||||
// 0x39 : ADD HL, SP
|
|
||||||
0x39: func(s *Z80) {
|
|
||||||
s.doHlAdd(s.SP)
|
|
||||||
},
|
|
||||||
// 0x3a : LD A, (nn)
|
|
||||||
0x3A: func(s *Z80) {
|
|
||||||
s.A = s.core.MemRead(s.nextWord())
|
|
||||||
},
|
|
||||||
// 0x3b : DEC SP
|
|
||||||
0x3B: func(s *Z80) {
|
|
||||||
s.SP--
|
|
||||||
},
|
|
||||||
// 0x3c : INC A
|
|
||||||
0x3C: func(s *Z80) {
|
|
||||||
s.A = s.doInc(s.A)
|
|
||||||
},
|
|
||||||
// 0x3d : DEC A
|
|
||||||
0x3D: func(s *Z80) {
|
|
||||||
s.A = s.doDec(s.A)
|
|
||||||
},
|
|
||||||
// 0x3e : LD A, n
|
|
||||||
0x3E: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.A = s.core.MemRead(s.PC)
|
|
||||||
},
|
|
||||||
// 0x3f : CCF
|
|
||||||
0x3F: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
s.doConditionalReturn(!s.Flags.Z)
|
|
||||||
},
|
|
||||||
// 0xc1 : POP BC
|
|
||||||
0xC1: func(s *Z80) {
|
|
||||||
result := s.PopWord()
|
|
||||||
s.C = byte(result & 0xff)
|
|
||||||
s.B = byte((result & 0xff00) >> 8)
|
|
||||||
},
|
|
||||||
// 0xc2 : JP NZ, nn
|
|
||||||
0xC2: func(s *Z80) {
|
|
||||||
s.doConditionalAbsoluteJump(!s.Flags.Z)
|
|
||||||
},
|
|
||||||
// 0xc3 : JP nn
|
|
||||||
0xC3: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
s.doConditionalCall(!s.Flags.Z)
|
|
||||||
},
|
|
||||||
// 0xc5 : PUSH BC
|
|
||||||
0xC5: func(s *Z80) {
|
|
||||||
s.pushWord((uint16(s.B) << 8) | uint16(s.C))
|
|
||||||
},
|
|
||||||
// 0xc6 : ADD A, n
|
|
||||||
0xC6: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.doAdd(s.core.MemRead(s.PC))
|
|
||||||
},
|
|
||||||
// 0xc7 : RST 00h
|
|
||||||
0xC7: func(s *Z80) {
|
|
||||||
s.doReset(0x0000)
|
|
||||||
},
|
|
||||||
// 0xc8 : RET Z
|
|
||||||
0xC8: func(s *Z80) {
|
|
||||||
s.doConditionalReturn(s.Flags.Z)
|
|
||||||
},
|
|
||||||
// 0xc9 : RET
|
|
||||||
0xC9: func(s *Z80) {
|
|
||||||
s.PC = s.PopWord() - 1
|
|
||||||
},
|
|
||||||
// 0xca : JP Z, nn
|
|
||||||
0xCA: func(s *Z80) {
|
|
||||||
s.doConditionalAbsoluteJump(s.Flags.Z)
|
|
||||||
},
|
|
||||||
// 0xcb : CB Prefix
|
|
||||||
0xCB: func(s *Z80) {
|
|
||||||
s.opcodeCB()
|
|
||||||
},
|
|
||||||
// 0xcc : CALL Z, nn
|
|
||||||
0xCC: func(s *Z80) {
|
|
||||||
s.doConditionalCall(s.Flags.Z)
|
|
||||||
},
|
|
||||||
// 0xcd : CALL nn
|
|
||||||
0xCD: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.doAdc(s.core.MemRead(s.PC))
|
|
||||||
},
|
|
||||||
// 0xcf : RST 08h
|
|
||||||
0xCF: func(s *Z80) {
|
|
||||||
s.doReset(0x0008)
|
|
||||||
},
|
|
||||||
// 0xd0 : RET NC
|
|
||||||
0xD0: func(s *Z80) {
|
|
||||||
s.doConditionalReturn(!s.Flags.C)
|
|
||||||
},
|
|
||||||
// 0xd1 : POP DE
|
|
||||||
0xD1: func(s *Z80) {
|
|
||||||
result := s.PopWord()
|
|
||||||
s.E = byte(result & 0xff)
|
|
||||||
s.D = byte((result & 0xff00) >> 8)
|
|
||||||
},
|
|
||||||
// 0xd2 : JP NC, nn
|
|
||||||
0xD2: func(s *Z80) {
|
|
||||||
s.doConditionalAbsoluteJump(!s.Flags.C)
|
|
||||||
},
|
|
||||||
// 0xd3 : OUT (n), A
|
|
||||||
0xD3: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.core.IOWrite((uint16(s.A)<<8)|uint16(s.core.MemRead(s.PC)), s.A)
|
|
||||||
},
|
|
||||||
// 0xd4 : CALL NC, nn
|
|
||||||
0xD4: func(s *Z80) {
|
|
||||||
s.doConditionalCall(!s.Flags.C)
|
|
||||||
},
|
|
||||||
// 0xd5 : PUSH DE
|
|
||||||
0xD5: func(s *Z80) {
|
|
||||||
s.pushWord((uint16(s.D) << 8) | uint16(s.E))
|
|
||||||
},
|
|
||||||
// 0xd6 : SUB n
|
|
||||||
0xD6: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.doSub(s.core.MemRead(s.PC))
|
|
||||||
},
|
|
||||||
// 0xd7 : RST 10h
|
|
||||||
0xD7: func(s *Z80) {
|
|
||||||
s.doReset(0x0010)
|
|
||||||
},
|
|
||||||
// 0xd8 : RET C
|
|
||||||
0xD8: func(s *Z80) {
|
|
||||||
s.doConditionalReturn(s.Flags.C)
|
|
||||||
},
|
|
||||||
// 0xd9 : EXX
|
|
||||||
0xD9: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
s.doConditionalAbsoluteJump(s.Flags.C)
|
|
||||||
},
|
|
||||||
// 0xdb : IN A, (n)
|
|
||||||
0xDB: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.A = s.core.IORead((uint16(s.A) << 8) | uint16(s.core.MemRead(s.PC)))
|
|
||||||
},
|
|
||||||
// 0xdc : CALL C, nn
|
|
||||||
0xDC: func(s *Z80) {
|
|
||||||
s.doConditionalCall(s.Flags.C)
|
|
||||||
},
|
|
||||||
// 0xdd : DD Prefix (IX instructions)
|
|
||||||
0xDD: func(s *Z80) {
|
|
||||||
s.opcodeDD()
|
|
||||||
},
|
|
||||||
// 0xde : SBC n
|
|
||||||
0xDE: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.doSbc(s.core.MemRead(s.PC))
|
|
||||||
},
|
|
||||||
// 0xdf : RST 18h
|
|
||||||
0xDF: func(s *Z80) {
|
|
||||||
s.doReset(0x0018)
|
|
||||||
},
|
|
||||||
// 0xe0 : RET PO
|
|
||||||
0xE0: func(s *Z80) {
|
|
||||||
s.doConditionalReturn(!s.Flags.P)
|
|
||||||
},
|
|
||||||
// 0xe1 : POP HL
|
|
||||||
0xE1: func(s *Z80) {
|
|
||||||
result := s.PopWord()
|
|
||||||
s.L = byte(result & 0xff)
|
|
||||||
s.H = byte((result & 0xff00) >> 8)
|
|
||||||
},
|
|
||||||
// 0xe2 : JP PO, (nn)
|
|
||||||
0xE2: func(s *Z80) {
|
|
||||||
s.doConditionalAbsoluteJump(!s.Flags.P)
|
|
||||||
},
|
|
||||||
// 0xe3 : EX (SP), HL
|
|
||||||
0xE3: func(s *Z80) {
|
|
||||||
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 *Z80) {
|
|
||||||
s.doConditionalCall(!s.Flags.P)
|
|
||||||
},
|
|
||||||
// 0xe5 : PUSH HL
|
|
||||||
0xE5: func(s *Z80) {
|
|
||||||
s.pushWord((uint16(s.H) << 8) | uint16(s.L))
|
|
||||||
},
|
|
||||||
// 0xe6 : AND n
|
|
||||||
0xE6: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.doAnd(s.core.MemRead(s.PC))
|
|
||||||
},
|
|
||||||
// 0xe7 : RST 20h
|
|
||||||
0xE7: func(s *Z80) {
|
|
||||||
s.doReset(0x0020)
|
|
||||||
},
|
|
||||||
// 0xe8 : RET PE
|
|
||||||
0xE8: func(s *Z80) {
|
|
||||||
s.doConditionalReturn(s.Flags.P)
|
|
||||||
},
|
|
||||||
// 0xe9 : JP (HL)
|
|
||||||
0xE9: func(s *Z80) {
|
|
||||||
s.PC = uint16(s.H)<<8 | uint16(s.L)
|
|
||||||
s.PC--
|
|
||||||
},
|
|
||||||
// 0xea : JP PE, nn
|
|
||||||
0xEA: func(s *Z80) {
|
|
||||||
s.doConditionalAbsoluteJump(s.Flags.P)
|
|
||||||
},
|
|
||||||
// 0xeb : EX DE, HL
|
|
||||||
0xEB: func(s *Z80) {
|
|
||||||
s.D, s.H = s.H, s.D
|
|
||||||
s.E, s.L = s.L, s.E
|
|
||||||
},
|
|
||||||
// 0xec : CALL PE, nn
|
|
||||||
0xEC: func(s *Z80) {
|
|
||||||
s.doConditionalCall(s.Flags.P)
|
|
||||||
},
|
|
||||||
// 0xed : ED Prefix
|
|
||||||
0xED: func(s *Z80) {
|
|
||||||
s.opcodeED()
|
|
||||||
},
|
|
||||||
// 0xee : XOR n
|
|
||||||
0xEE: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.doXor(s.core.MemRead(s.PC))
|
|
||||||
},
|
|
||||||
// 0xef : RST 28h
|
|
||||||
0xEF: func(s *Z80) {
|
|
||||||
s.doReset(0x0028)
|
|
||||||
},
|
|
||||||
// 0xf0 : RET P
|
|
||||||
0xF0: func(s *Z80) {
|
|
||||||
s.doConditionalReturn(!s.Flags.S)
|
|
||||||
},
|
|
||||||
// 0xf1 : POP AF
|
|
||||||
0xF1: func(s *Z80) {
|
|
||||||
var result = s.PopWord()
|
|
||||||
s.Flags.SetFlags(byte(result & 0xff))
|
|
||||||
s.A = byte((result & 0xff00) >> 8)
|
|
||||||
},
|
|
||||||
// 0xf2 : JP P, nn
|
|
||||||
0xF2: func(s *Z80) {
|
|
||||||
s.doConditionalAbsoluteJump(!s.Flags.S)
|
|
||||||
},
|
|
||||||
// 0xf3 : DI
|
|
||||||
0xF3: func(s *Z80) {
|
|
||||||
// DI doesn't actually take effect until after the next instruction.
|
|
||||||
s.DoDelayedDI = true
|
|
||||||
},
|
|
||||||
// 0xf4 : CALL P, nn
|
|
||||||
0xF4: func(s *Z80) {
|
|
||||||
s.doConditionalCall(!s.Flags.S)
|
|
||||||
},
|
|
||||||
// 0xf5 : PUSH AF
|
|
||||||
0xF5: func(s *Z80) {
|
|
||||||
s.pushWord(uint16(s.Flags.GetFlags()) | (uint16(s.A) << 8))
|
|
||||||
},
|
|
||||||
// 0xf6 : OR n
|
|
||||||
0xF6: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.doOr(s.core.MemRead(s.PC))
|
|
||||||
},
|
|
||||||
// 0xf7 : RST 30h
|
|
||||||
0xF7: func(s *Z80) {
|
|
||||||
s.doReset(0x0030)
|
|
||||||
},
|
|
||||||
// 0xf8 : RET M
|
|
||||||
0xF8: func(s *Z80) {
|
|
||||||
s.doConditionalReturn(s.Flags.S)
|
|
||||||
},
|
|
||||||
// 0xf9 : LD SP, HL
|
|
||||||
0xF9: func(s *Z80) {
|
|
||||||
s.SP = uint16(s.H)<<8 | uint16(s.L)
|
|
||||||
},
|
|
||||||
// 0xfa : JP M, nn
|
|
||||||
0xFA: func(s *Z80) {
|
|
||||||
s.doConditionalAbsoluteJump(s.Flags.S)
|
|
||||||
},
|
|
||||||
// 0xfb : EI
|
|
||||||
0xFB: func(s *Z80) {
|
|
||||||
// EI doesn't actually take effect until after the next instruction.
|
|
||||||
s.DoDelayedEI = true
|
|
||||||
},
|
|
||||||
// 0xfc : CALL M, nn
|
|
||||||
0xFC: func(s *Z80) {
|
|
||||||
s.doConditionalCall(s.Flags.S)
|
|
||||||
},
|
|
||||||
// 0xfd : FD Prefix (IY instructions)
|
|
||||||
0xFD: func(s *Z80) {
|
|
||||||
s.opcodeFD()
|
|
||||||
},
|
|
||||||
// 0xfe : CP n
|
|
||||||
0xFE: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.doCp(s.core.MemRead(s.PC))
|
|
||||||
},
|
|
||||||
// 0xff : RST 38h
|
|
||||||
0xFF: func(s *Z80) {
|
|
||||||
s.doReset(0x0038)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (z *Z80) nextWord() uint16 {
|
|
||||||
z.PC++
|
|
||||||
word := uint16(z.core.MemRead(z.PC))
|
|
||||||
z.PC++
|
|
||||||
word |= uint16(z.core.MemRead(z.PC)) << 8
|
|
||||||
return word
|
|
||||||
}
|
|
||||||
@ -1,108 +0,0 @@
|
|||||||
package js
|
|
||||||
|
|
||||||
func (z *Z80) opcodeCB() {
|
|
||||||
z.incR()
|
|
||||||
z.PC++
|
|
||||||
opcode := z.core.M1MemRead(z.PC)
|
|
||||||
bitNumber := (opcode & 0x38) >> 3
|
|
||||||
regCode := opcode & 0x07
|
|
||||||
if opcode < 0x40 {
|
|
||||||
// Shift/rotate instructions
|
|
||||||
opArray := []OpShift{z.doRlc, z.doRrc, z.doRl, z.doRr, z.doSla, z.doSra, z.doSll, z.doSrl}
|
|
||||||
switch regCode {
|
|
||||||
case 0:
|
|
||||||
z.B = opArray[bitNumber](z.B)
|
|
||||||
case 1:
|
|
||||||
z.C = opArray[bitNumber](z.C)
|
|
||||||
case 2:
|
|
||||||
z.D = opArray[bitNumber](z.D)
|
|
||||||
case 3:
|
|
||||||
z.E = opArray[bitNumber](z.E)
|
|
||||||
case 4:
|
|
||||||
z.H = opArray[bitNumber](z.H)
|
|
||||||
case 5:
|
|
||||||
z.L = opArray[bitNumber](z.L)
|
|
||||||
case 6:
|
|
||||||
z.core.MemWrite(z.hl(), opArray[bitNumber](z.core.MemRead(z.hl())))
|
|
||||||
default:
|
|
||||||
z.A = opArray[bitNumber](z.A)
|
|
||||||
}
|
|
||||||
} else if opcode < 0x80 {
|
|
||||||
// BIT instructions
|
|
||||||
mask := byte(1 << bitNumber)
|
|
||||||
switch regCode {
|
|
||||||
case 0:
|
|
||||||
z.Flags.Z = z.B&mask == 0
|
|
||||||
case 1:
|
|
||||||
z.Flags.Z = z.C&mask == 0
|
|
||||||
case 2:
|
|
||||||
z.Flags.Z = z.D&mask == 0
|
|
||||||
case 3:
|
|
||||||
z.Flags.Z = z.E&mask == 0
|
|
||||||
case 4:
|
|
||||||
z.Flags.Z = z.H&mask == 0
|
|
||||||
case 5:
|
|
||||||
z.Flags.Z = z.L&mask == 0
|
|
||||||
case 6:
|
|
||||||
z.Flags.Z = z.core.MemRead(z.hl())&mask == 0
|
|
||||||
default:
|
|
||||||
z.Flags.Z = z.A&mask == 0
|
|
||||||
}
|
|
||||||
z.Flags.N = false
|
|
||||||
z.Flags.H = true
|
|
||||||
z.Flags.P = z.Flags.Z
|
|
||||||
z.Flags.S = (bitNumber == 7) && !z.Flags.Z
|
|
||||||
// TODO: ZXALL fail this
|
|
||||||
// For the BIT n, (HL) instruction, the X and Y flags are obtained
|
|
||||||
// from what is apparently an internal temporary register used for
|
|
||||||
// some of the 16-bit arithmetic instructions.
|
|
||||||
// I haven't implemented that register here,
|
|
||||||
// so for now we'll set X and Y the same way for every BIT opcode,
|
|
||||||
// which means that they will usually be wrong for BIT n, (HL).
|
|
||||||
z.Flags.Y = (bitNumber == 5) && !z.Flags.Z
|
|
||||||
z.Flags.X = (bitNumber == 3) && !z.Flags.Z
|
|
||||||
} else if opcode < 0xC0 {
|
|
||||||
// RES instructions
|
|
||||||
negMask := byte(^(1 << bitNumber))
|
|
||||||
switch regCode {
|
|
||||||
case 0:
|
|
||||||
z.B &= negMask
|
|
||||||
case 1:
|
|
||||||
z.C &= negMask
|
|
||||||
case 2:
|
|
||||||
z.D &= negMask
|
|
||||||
case 3:
|
|
||||||
z.E &= negMask
|
|
||||||
case 4:
|
|
||||||
z.H &= negMask
|
|
||||||
case 5:
|
|
||||||
z.L &= negMask
|
|
||||||
case 6:
|
|
||||||
z.core.MemWrite(z.hl(), z.core.MemRead(z.hl())&negMask)
|
|
||||||
default:
|
|
||||||
z.A &= negMask
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// SET instructions
|
|
||||||
mask := byte(1 << bitNumber)
|
|
||||||
switch regCode {
|
|
||||||
case 0:
|
|
||||||
z.B |= mask
|
|
||||||
case 1:
|
|
||||||
z.C |= mask
|
|
||||||
case 2:
|
|
||||||
z.D |= mask
|
|
||||||
case 3:
|
|
||||||
z.E |= mask
|
|
||||||
case 4:
|
|
||||||
z.H |= mask
|
|
||||||
case 5:
|
|
||||||
z.L |= mask
|
|
||||||
case 6:
|
|
||||||
z.core.MemWrite(z.hl(), z.core.MemRead(z.hl())|mask)
|
|
||||||
default:
|
|
||||||
z.A |= mask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
z.CycleCounter += CycleCountsCb[opcode]
|
|
||||||
}
|
|
||||||
@ -1,475 +0,0 @@
|
|||||||
package js
|
|
||||||
|
|
||||||
var ddInstructions = []func(s *Z80){
|
|
||||||
// 0x09 : ADD IX, BC
|
|
||||||
0x09: func(s *Z80) {
|
|
||||||
s.doIxAdd(s.bc())
|
|
||||||
},
|
|
||||||
// 0x19 : ADD IX, DE
|
|
||||||
0x19: func(s *Z80) {
|
|
||||||
s.doIxAdd(s.de())
|
|
||||||
},
|
|
||||||
// 0x21 : LD IX, nn
|
|
||||||
0x21: func(s *Z80) {
|
|
||||||
s.IX = s.nextWord()
|
|
||||||
},
|
|
||||||
// 0x22 : LD (nn), IX
|
|
||||||
0x22: func(s *Z80) {
|
|
||||||
s.setWord(s.nextWord(), s.IX)
|
|
||||||
},
|
|
||||||
// 0x23 : INC IX
|
|
||||||
0x23: func(s *Z80) {
|
|
||||||
s.IX++
|
|
||||||
},
|
|
||||||
// 0x24 : INC IXH (Undocumented)
|
|
||||||
0x24: func(s *Z80) {
|
|
||||||
s.IX = (uint16(s.doInc(byte(s.IX>>8))) << 8) | (s.IX & 0x00ff)
|
|
||||||
},
|
|
||||||
// 0x25 : DEC IXH (Undocumented)
|
|
||||||
0x25: func(s *Z80) {
|
|
||||||
s.IX = (uint16(s.doDec(byte(s.IX>>8))) << 8) | (s.IX & 0x00ff)
|
|
||||||
},
|
|
||||||
// 0x26 : LD IXH, n (Undocumented)
|
|
||||||
0x26: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.IX = (uint16(s.core.MemRead(s.PC)) << 8) | (s.IX & 0x00ff)
|
|
||||||
},
|
|
||||||
// 0x29 : ADD IX, IX
|
|
||||||
0x29: func(s *Z80) {
|
|
||||||
s.doIxAdd(s.IX)
|
|
||||||
},
|
|
||||||
// 0x2a : LD IX, (nn)
|
|
||||||
0x2A: func(s *Z80) {
|
|
||||||
s.IX = s.getWord(s.nextWord())
|
|
||||||
},
|
|
||||||
// 0x2b : DEC IX
|
|
||||||
0x2B: func(s *Z80) {
|
|
||||||
s.IX--
|
|
||||||
},
|
|
||||||
// 0x2c : INC IXL (Undocumented)
|
|
||||||
0x2C: func(s *Z80) {
|
|
||||||
s.IX = (uint16(s.doInc(byte(s.IX & 0x00ff)))) | (s.IX & 0xff00)
|
|
||||||
},
|
|
||||||
// 0x2d : DEC IXL (Undocumented)
|
|
||||||
0x2D: func(s *Z80) {
|
|
||||||
s.IX = (uint16(s.doDec(byte(s.IX & 0x00ff)))) | (s.IX & 0xff00)
|
|
||||||
},
|
|
||||||
// 0x2e : LD IXL, n (Undocumented)
|
|
||||||
0x2E: func(s *Z80) {
|
|
||||||
s.PC++
|
|
||||||
s.IX = (uint16(s.core.MemRead(s.PC))) | (s.IX & 0xff00)
|
|
||||||
},
|
|
||||||
// 0x34 : INC (IX+n)
|
|
||||||
0x34: func(s *Z80) {
|
|
||||||
offset := s.getOffset(s.IX)
|
|
||||||
value := s.core.MemRead(offset)
|
|
||||||
s.core.MemWrite(offset, s.doInc(value))
|
|
||||||
},
|
|
||||||
// 0x35 : DEC (IX+n)
|
|
||||||
0x35: func(s *Z80) {
|
|
||||||
offset := s.getOffset(s.IX)
|
|
||||||
value := s.core.MemRead(offset)
|
|
||||||
s.core.MemWrite(offset, s.doDec(value))
|
|
||||||
},
|
|
||||||
// 0x36 : LD (IX+n), n
|
|
||||||
0x36: func(s *Z80) {
|
|
||||||
offset := s.getOffset(s.IX)
|
|
||||||
s.PC++
|
|
||||||
s.core.MemWrite(offset, s.core.MemRead(s.PC))
|
|
||||||
},
|
|
||||||
// 0x39 : ADD IX, SP
|
|
||||||
0x39: func(s *Z80) {
|
|
||||||
s.doIxAdd(s.SP)
|
|
||||||
},
|
|
||||||
// 0x44 : LD B, IXH (Undocumented)
|
|
||||||
0x44: func(s *Z80) {
|
|
||||||
s.B = byte(s.IX >> 8)
|
|
||||||
},
|
|
||||||
// 0x45 : LD B, IXL (Undocumented)
|
|
||||||
0x45: func(s *Z80) {
|
|
||||||
s.B = byte(s.IX & 0x00ff)
|
|
||||||
},
|
|
||||||
// 0x46 : LD B, (IX+n)
|
|
||||||
0x46: func(s *Z80) {
|
|
||||||
s.B = s.core.MemRead(s.getOffset(s.IX))
|
|
||||||
},
|
|
||||||
// 0x4c : LD C, IXH (Undocumented)
|
|
||||||
0x4C: func(s *Z80) {
|
|
||||||
s.C = byte(s.IX >> 8)
|
|
||||||
},
|
|
||||||
// 0x4d : LD C, IXL (Undocumented)
|
|
||||||
0x4D: func(s *Z80) {
|
|
||||||
s.C = byte(s.IX & 0x00ff)
|
|
||||||
},
|
|
||||||
// 0x4e : LD C, (IX+n)
|
|
||||||
0x4E: func(s *Z80) {
|
|
||||||
s.C = s.core.MemRead(s.getOffset(s.IX))
|
|
||||||
},
|
|
||||||
// 0x54 : LD D, IXH (Undocumented)
|
|
||||||
0x54: func(s *Z80) {
|
|
||||||
s.D = byte(s.IX >> 8)
|
|
||||||
},
|
|
||||||
// 0x55 : LD D, IXL (Undocumented)
|
|
||||||
0x55: func(s *Z80) {
|
|
||||||
s.D = byte(s.IX)
|
|
||||||
},
|
|
||||||
// 0x56 : LD D, (IX+n)
|
|
||||||
0x56: func(s *Z80) {
|
|
||||||
offset := s.getOffset(s.IX)
|
|
||||||
s.D = s.core.MemRead(offset)
|
|
||||||
},
|
|
||||||
// 0x5d : LD E, IXL (Undocumented)
|
|
||||||
0x5D: func(s *Z80) {
|
|
||||||
s.E = byte(s.IX)
|
|
||||||
},
|
|
||||||
// 0x5e : LD E, (IX+n)
|
|
||||||
0x5E: func(s *Z80) {
|
|
||||||
s.E = s.core.MemRead(s.getOffset(s.IX))
|
|
||||||
},
|
|
||||||
// 0x60 : LD IXH, B (Undocumented)
|
|
||||||
0x60: func(s *Z80) {
|
|
||||||
s.IX = uint16(s.B)<<8 | s.IX&0x00ff
|
|
||||||
},
|
|
||||||
// 0x61 : LD IXH, C (Undocumented)
|
|
||||||
0x61: func(s *Z80) {
|
|
||||||
s.IX = uint16(s.C)<<8 | s.IX&0x00ff
|
|
||||||
},
|
|
||||||
// 0x62 : LD IXH, D (Undocumented)
|
|
||||||
0x62: func(s *Z80) {
|
|
||||||
s.IX = uint16(s.D)<<8 | s.IX&0x00ff
|
|
||||||
},
|
|
||||||
// 0x63 : LD IXH, E (Undocumented)
|
|
||||||
0x63: func(s *Z80) {
|
|
||||||
s.IX = uint16(s.E)<<8 | s.IX&0x00ff
|
|
||||||
},
|
|
||||||
// 0x64 : LD IXH, IXH (Undocumented)
|
|
||||||
0x64: func(s *Z80) {
|
|
||||||
// NOP
|
|
||||||
},
|
|
||||||
// 0x65 : LD IXH, IXL (Undocumented)
|
|
||||||
0x65: func(s *Z80) {
|
|
||||||
s.IX = (s.IX << 8) | (s.IX & 0x00ff)
|
|
||||||
},
|
|
||||||
// 0x66 : LD H, (IX+n)
|
|
||||||
0x66: func(s *Z80) {
|
|
||||||
s.H = s.core.MemRead(s.getOffset(s.IX))
|
|
||||||
},
|
|
||||||
// 0x67 : LD IXH, A (Undocumented)
|
|
||||||
0x67: func(s *Z80) {
|
|
||||||
s.IX = (uint16(s.A) << 8) | (s.IX & 0x00ff)
|
|
||||||
},
|
|
||||||
// 0x68 : LD IXL, B (Undocumented)
|
|
||||||
0x68: func(s *Z80) {
|
|
||||||
s.IX = (s.IX & 0xff00) | uint16(s.B)
|
|
||||||
},
|
|
||||||
// 0x69 : LD IXL, C (Undocumented)
|
|
||||||
0x69: func(s *Z80) {
|
|
||||||
s.IX = (s.IX & 0xff00) | uint16(s.C)
|
|
||||||
},
|
|
||||||
// 0x6a : LD IXL, D (Undocumented)
|
|
||||||
0x6a: func(s *Z80) {
|
|
||||||
s.IX = (s.IX & 0xff00) | uint16(s.D)
|
|
||||||
},
|
|
||||||
// 0x6b : LD IXL, E (Undocumented)
|
|
||||||
0x6b: func(s *Z80) {
|
|
||||||
s.IX = (s.IX & 0xff00) | uint16(s.E)
|
|
||||||
},
|
|
||||||
// 0x6c : LD IXL, IXH (Undocumented)
|
|
||||||
0x6c: func(s *Z80) {
|
|
||||||
s.IX = (s.IX >> 8) | (s.IX & 0xff00)
|
|
||||||
},
|
|
||||||
// 0x6d : LD IXL, IXL (Undocumented)
|
|
||||||
0x6d: func(s *Z80) {
|
|
||||||
// NOP
|
|
||||||
},
|
|
||||||
// 0x6e : LD L, (IX+n)
|
|
||||||
0x6e: func(s *Z80) {
|
|
||||||
s.L = s.core.MemRead(s.getOffset(s.IX))
|
|
||||||
},
|
|
||||||
// 0x6f : LD IXL, A (Undocumented)
|
|
||||||
0x6f: func(s *Z80) {
|
|
||||||
s.IX = uint16(s.A) | (s.IX & 0xff00)
|
|
||||||
},
|
|
||||||
// 0x70 : LD (IX+n), B
|
|
||||||
0x70: func(s *Z80) {
|
|
||||||
s.core.MemWrite(s.getOffset(s.IX), s.B)
|
|
||||||
},
|
|
||||||
// 0x71 : LD (IX+n), C
|
|
||||||
0x71: func(s *Z80) {
|
|
||||||
s.core.MemWrite(s.getOffset(s.IX), s.C)
|
|
||||||
},
|
|
||||||
// 0x72 : LD (IX+n), D
|
|
||||||
0x72: func(s *Z80) {
|
|
||||||
s.core.MemWrite(s.getOffset(s.IX), s.D)
|
|
||||||
},
|
|
||||||
// 0x73 : LD (IX+n), E
|
|
||||||
0x73: func(s *Z80) {
|
|
||||||
s.core.MemWrite(s.getOffset(s.IX), s.E)
|
|
||||||
},
|
|
||||||
// 0x74 : LD (IX+n), H
|
|
||||||
0x74: func(s *Z80) {
|
|
||||||
s.core.MemWrite(s.getOffset(s.IX), s.H)
|
|
||||||
},
|
|
||||||
// 0x75 : LD (IX+n), L
|
|
||||||
0x75: func(s *Z80) {
|
|
||||||
s.core.MemWrite(s.getOffset(s.IX), s.L)
|
|
||||||
},
|
|
||||||
// 0x77 : LD (IX+n), A
|
|
||||||
0x77: func(s *Z80) {
|
|
||||||
s.core.MemWrite(s.getOffset(s.IX), s.A)
|
|
||||||
},
|
|
||||||
// 0x7c : LD A, IXH (Undocumented)
|
|
||||||
0x7C: func(s *Z80) {
|
|
||||||
s.A = byte(s.IX >> 8)
|
|
||||||
},
|
|
||||||
// 0x7d : LD A, IXL (Undocumented)
|
|
||||||
0x7D: func(s *Z80) {
|
|
||||||
s.A = byte(s.IX & 0x00ff)
|
|
||||||
},
|
|
||||||
// 0x7e : LD A, (IX+n)
|
|
||||||
0x7E: func(s *Z80) {
|
|
||||||
s.A = s.core.MemRead(s.getOffset(s.IX))
|
|
||||||
},
|
|
||||||
// 0x84 : ADD A, IXH (Undocumented)
|
|
||||||
0x84: func(s *Z80) {
|
|
||||||
s.doAdd(byte(s.IX >> 8))
|
|
||||||
},
|
|
||||||
// 0x85 : ADD A, IXL (Undocumented)
|
|
||||||
0x85: func(s *Z80) {
|
|
||||||
s.doAdd(byte(s.IX))
|
|
||||||
},
|
|
||||||
// 0x86 : ADD A, (IX+n)
|
|
||||||
0x86: func(s *Z80) {
|
|
||||||
s.doAdd(s.core.MemRead(s.getOffset(s.IX)))
|
|
||||||
},
|
|
||||||
// 0x8c : ADC A, IXH (Undocumented)
|
|
||||||
0x8C: func(s *Z80) {
|
|
||||||
s.doAdc(byte(s.IX >> 8))
|
|
||||||
},
|
|
||||||
// 0x8d : ADC A, IXL (Undocumented)
|
|
||||||
0x8D: func(s *Z80) {
|
|
||||||
s.doAdc(byte(s.IX))
|
|
||||||
},
|
|
||||||
// 0x8e : ADC A, (IX+n)
|
|
||||||
0x8E: func(s *Z80) {
|
|
||||||
s.doAdc(s.core.MemRead(s.getOffset(s.IX)))
|
|
||||||
},
|
|
||||||
// 0x94 : SUB IXH (Undocumented)
|
|
||||||
0x94: func(s *Z80) {
|
|
||||||
s.doSub(byte(s.IX >> 8))
|
|
||||||
},
|
|
||||||
// 0x95 : SUB IXL (Undocumented)
|
|
||||||
0x95: func(s *Z80) {
|
|
||||||
s.doSub(byte(s.IX))
|
|
||||||
},
|
|
||||||
// 0x96 : SUB A, (IX+n)
|
|
||||||
0x96: func(s *Z80) {
|
|
||||||
s.doSub(s.core.MemRead(s.getOffset(s.IX)))
|
|
||||||
},
|
|
||||||
// 0x9c : SBC IXH (Undocumented)
|
|
||||||
0x9C: func(s *Z80) {
|
|
||||||
s.doSbc(byte(s.IX >> 8))
|
|
||||||
},
|
|
||||||
// 0x9d : SBC IXL (Undocumented)
|
|
||||||
0x9D: func(s *Z80) {
|
|
||||||
s.doSbc(byte(s.IX))
|
|
||||||
},
|
|
||||||
// 0x9e : SBC A, (IX+n)
|
|
||||||
0x9E: func(s *Z80) {
|
|
||||||
s.doSbc(s.core.MemRead(s.getOffset(s.IX)))
|
|
||||||
},
|
|
||||||
// 0xa4 : AND IXH (Undocumented)
|
|
||||||
0xA4: func(s *Z80) {
|
|
||||||
s.doAnd(byte(s.IX >> 8))
|
|
||||||
},
|
|
||||||
// 0xa5 : AND IXL (Undocumented)
|
|
||||||
0xA5: func(s *Z80) {
|
|
||||||
s.doAnd(byte(s.IX))
|
|
||||||
},
|
|
||||||
// 0xa6 : AND A, (IX+n)
|
|
||||||
0xA6: func(s *Z80) {
|
|
||||||
s.doAnd(s.core.MemRead(s.getOffset(s.IX)))
|
|
||||||
},
|
|
||||||
// 0xac : XOR IXH (Undocumented)
|
|
||||||
0xAC: func(s *Z80) {
|
|
||||||
s.doXor(byte(s.IX >> 8))
|
|
||||||
},
|
|
||||||
// 0xad : XOR IXL (Undocumented)
|
|
||||||
0xAD: func(s *Z80) {
|
|
||||||
s.doXor(byte(s.IX))
|
|
||||||
},
|
|
||||||
// 0xae : XOR A, (IX+n)
|
|
||||||
0xAE: func(s *Z80) {
|
|
||||||
s.doXor(s.core.MemRead(s.getOffset(s.IX)))
|
|
||||||
},
|
|
||||||
// 0xb4 : OR IXH (Undocumented)
|
|
||||||
0xB4: func(s *Z80) {
|
|
||||||
s.doOr(byte(s.IX >> 8))
|
|
||||||
},
|
|
||||||
// 0xb5 : OR IXL (Undocumented)
|
|
||||||
0xB5: func(s *Z80) {
|
|
||||||
s.doOr(byte(s.IX))
|
|
||||||
},
|
|
||||||
// 0xb6 : OR A, (IX+n)
|
|
||||||
0xB6: func(s *Z80) {
|
|
||||||
s.doOr(s.core.MemRead(s.getOffset(s.IX)))
|
|
||||||
},
|
|
||||||
// 0xbc : CP IXH (Undocumented)
|
|
||||||
0xBC: func(s *Z80) {
|
|
||||||
s.doCp(byte(s.IX >> 8))
|
|
||||||
},
|
|
||||||
// 0xbd : CP IXL (Undocumented)
|
|
||||||
0xBD: func(s *Z80) {
|
|
||||||
s.doCp(byte(s.IX))
|
|
||||||
},
|
|
||||||
// 0xbe : CP A, (IX+n)
|
|
||||||
0xBE: func(s *Z80) {
|
|
||||||
s.doCp(s.core.MemRead(s.getOffset(s.IX)))
|
|
||||||
},
|
|
||||||
// 0xcb : CB Prefix (IX bit instructions)
|
|
||||||
0xCB: func(s *Z80) {
|
|
||||||
s.opcodeDDCB()
|
|
||||||
},
|
|
||||||
// 0xe1 : POP IX
|
|
||||||
0xE1: func(s *Z80) {
|
|
||||||
s.IX = s.PopWord()
|
|
||||||
},
|
|
||||||
// 0xe3 : EX (SP), IX
|
|
||||||
0xE3: func(s *Z80) {
|
|
||||||
ix := s.IX
|
|
||||||
s.IX = s.getWord(s.SP)
|
|
||||||
s.setWord(s.SP, ix)
|
|
||||||
},
|
|
||||||
// 0xe5 : PUSH IX
|
|
||||||
0xE5: func(s *Z80) {
|
|
||||||
s.pushWord(s.IX)
|
|
||||||
},
|
|
||||||
// 0xe9 : JP (IX)
|
|
||||||
0xE9: func(s *Z80) {
|
|
||||||
s.PC = s.IX - 1
|
|
||||||
},
|
|
||||||
// 0xf9 : LD SP, IX
|
|
||||||
0xf9: func(s *Z80) {
|
|
||||||
s.SP = s.IX
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// =====================================================
|
|
||||||
func (z *Z80) getOffset(reg uint16) uint16 {
|
|
||||||
z.PC++
|
|
||||||
offset := z.core.MemRead(z.PC)
|
|
||||||
if offset < 0 {
|
|
||||||
reg -= uint16(-offset)
|
|
||||||
} else {
|
|
||||||
reg += uint16(offset)
|
|
||||||
}
|
|
||||||
return reg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (z *Z80) opcodeDD() {
|
|
||||||
z.incR()
|
|
||||||
z.PC++
|
|
||||||
opcode := z.core.M1MemRead(z.PC)
|
|
||||||
|
|
||||||
fun := ddInstructions[opcode]
|
|
||||||
if fun != nil {
|
|
||||||
fun(z)
|
|
||||||
z.CycleCounter += CycleCountsDd[opcode]
|
|
||||||
} else {
|
|
||||||
// Apparently if a DD opcode doesn't exist,
|
|
||||||
// it gets treated as an unprefixed opcode.
|
|
||||||
// What we'll do to handle that is just back up the
|
|
||||||
// program counter, so that this byte gets decoded
|
|
||||||
// as a normal instruction.
|
|
||||||
z.PC--
|
|
||||||
// And we'll add in the cycle count for a NOP.
|
|
||||||
z.CycleCounter += CycleCounts[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (z *Z80) opcodeDDCB() {
|
|
||||||
|
|
||||||
offset := z.getOffset(z.IX)
|
|
||||||
z.PC++
|
|
||||||
|
|
||||||
opcode := z.core.MemRead(z.PC)
|
|
||||||
|
|
||||||
value := byte(0)
|
|
||||||
bitTestOp := false
|
|
||||||
|
|
||||||
// As with the "normal" CB prefix, we implement the DDCB prefix
|
|
||||||
// by decoding the opcode directly, rather than using a table.
|
|
||||||
if opcode < 0x40 {
|
|
||||||
// Shift and rotate instructions.
|
|
||||||
ddcbFunctions := []OpShift{z.doRlc, z.doRrc, z.doRl, z.doRr, z.doSla, z.doSra, z.doSll, z.doSrl}
|
|
||||||
// Most of the opcodes in this range are not valid,
|
|
||||||
// so we map this opcode onto one of the ones that is.
|
|
||||||
fun := ddcbFunctions[(opcode&0x38)>>3]
|
|
||||||
value = fun(z.core.MemRead(offset))
|
|
||||||
z.core.MemWrite(offset, value)
|
|
||||||
} else {
|
|
||||||
bitNumber := (opcode & 0x38) >> 3
|
|
||||||
if opcode < 0x80 {
|
|
||||||
// bit test
|
|
||||||
bitTestOp = true
|
|
||||||
z.Flags.N = false
|
|
||||||
z.Flags.H = true
|
|
||||||
z.Flags.Z = z.core.MemRead(offset)&(1<<bitNumber) == 0
|
|
||||||
z.Flags.P = z.Flags.Z
|
|
||||||
z.Flags.S = (bitNumber == 7) && !z.Flags.Z
|
|
||||||
} else if opcode < 0xc0 {
|
|
||||||
// RES
|
|
||||||
value = z.core.MemRead(offset) & (^(1 << bitNumber))
|
|
||||||
z.core.MemWrite(offset, value)
|
|
||||||
} else {
|
|
||||||
// SET
|
|
||||||
value = z.core.MemRead(offset) | (1 << bitNumber)
|
|
||||||
z.core.MemWrite(offset, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This implements the undocumented shift, RES, and SET opcodes,
|
|
||||||
// which write their result to memory and also to an 8080 register.
|
|
||||||
|
|
||||||
if !bitTestOp {
|
|
||||||
//value := byte(1)
|
|
||||||
switch opcode & 0x07 {
|
|
||||||
case 0:
|
|
||||||
z.B = value
|
|
||||||
case 1:
|
|
||||||
z.C = value
|
|
||||||
case 2:
|
|
||||||
z.D = value
|
|
||||||
case 3:
|
|
||||||
z.E = value
|
|
||||||
case 4:
|
|
||||||
z.H = value
|
|
||||||
case 5:
|
|
||||||
z.L = value
|
|
||||||
// 6 is the documented opcode, which doesn't set a register.
|
|
||||||
case 7:
|
|
||||||
z.A = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
z.CycleCounter += CycleCountsCb[opcode] + 8
|
|
||||||
}
|
|
||||||
|
|
||||||
// opcodeFD do same for IY as for IX (DD prefix)
|
|
||||||
func (z *Z80) opcodeFD() {
|
|
||||||
z.incR()
|
|
||||||
z.PC++
|
|
||||||
opcode := z.core.M1MemRead(z.PC)
|
|
||||||
fun := ddInstructions[opcode]
|
|
||||||
if fun != nil {
|
|
||||||
var temp = z.IX
|
|
||||||
z.IX = z.IY
|
|
||||||
fun(z)
|
|
||||||
z.IY = z.IX
|
|
||||||
z.IX = temp
|
|
||||||
z.CycleCounter += CycleCountsDd[opcode]
|
|
||||||
} else {
|
|
||||||
z.PC--
|
|
||||||
z.CycleCounter += CycleCounts[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,410 +0,0 @@
|
|||||||
package js
|
|
||||||
|
|
||||||
var edInstructions = []func(s *Z80){
|
|
||||||
// 0x40 : IN B, (C)
|
|
||||||
0x40: func(s *Z80) {
|
|
||||||
s.B = s.doIn(s.bc())
|
|
||||||
},
|
|
||||||
// 0x41 : OUT (C), B
|
|
||||||
0x41: func(s *Z80) {
|
|
||||||
s.core.IOWrite(s.bc(), s.B)
|
|
||||||
},
|
|
||||||
// 0x42 : SBC HL, BC
|
|
||||||
0x42: func(s *Z80) {
|
|
||||||
s.doHlSbc(s.bc())
|
|
||||||
},
|
|
||||||
// 0x43 : LD (nn), BC
|
|
||||||
0x43: func(s *Z80) {
|
|
||||||
s.setWord(s.nextWord(), s.bc())
|
|
||||||
},
|
|
||||||
// 0x44 : NEG
|
|
||||||
0x44: func(s *Z80) {
|
|
||||||
s.doNeg()
|
|
||||||
},
|
|
||||||
// 0x45 : RETN
|
|
||||||
0x45: func(s *Z80) {
|
|
||||||
s.PC = s.PopWord() - 1
|
|
||||||
s.Iff1 = s.Iff2
|
|
||||||
},
|
|
||||||
// 0x46 : IM 0
|
|
||||||
0x46: func(s *Z80) {
|
|
||||||
s.IMode = 0
|
|
||||||
},
|
|
||||||
// 0x47 : LD I, A
|
|
||||||
0x47: func(s *Z80) {
|
|
||||||
s.I = s.A
|
|
||||||
},
|
|
||||||
// 0x48 : IN C, (C)
|
|
||||||
0x48: func(s *Z80) {
|
|
||||||
s.C = s.doIn(s.bc())
|
|
||||||
},
|
|
||||||
// 0x49 : OUT (C), C
|
|
||||||
0x49: func(s *Z80) {
|
|
||||||
s.core.IOWrite(s.bc(), s.C)
|
|
||||||
},
|
|
||||||
// 0x4a : ADC HL, BC
|
|
||||||
0x4A: func(s *Z80) {
|
|
||||||
s.doHlAdc(s.bc())
|
|
||||||
},
|
|
||||||
// 0x4b : LD BC, (nn)
|
|
||||||
0x4B: func(s *Z80) {
|
|
||||||
s.setBc(s.getWord(s.nextWord()))
|
|
||||||
},
|
|
||||||
// 0x4c : NEG (Undocumented)
|
|
||||||
0x4C: func(s *Z80) {
|
|
||||||
s.doNeg()
|
|
||||||
},
|
|
||||||
// 0x4d : RETI
|
|
||||||
0x4D: func(s *Z80) {
|
|
||||||
s.PC = s.PopWord() - 1
|
|
||||||
},
|
|
||||||
// 0x4e : IM 0 (Undocumented)
|
|
||||||
0x4E: func(s *Z80) {
|
|
||||||
s.IMode = 0
|
|
||||||
},
|
|
||||||
// 0x4f : LD R, A
|
|
||||||
0x4F: func(s *Z80) {
|
|
||||||
s.R = s.A
|
|
||||||
},
|
|
||||||
// 0x50 : IN D, (C)
|
|
||||||
0x50: func(s *Z80) {
|
|
||||||
s.D = s.doIn(s.bc())
|
|
||||||
},
|
|
||||||
// 0x51 : OUT (C), D
|
|
||||||
0x51: func(s *Z80) {
|
|
||||||
s.core.IOWrite(s.bc(), s.D)
|
|
||||||
},
|
|
||||||
// 0x52 : SBC HL, DE
|
|
||||||
0x52: func(s *Z80) {
|
|
||||||
s.doHlSbc(s.de())
|
|
||||||
},
|
|
||||||
// 0x53 : LD (nn), DE
|
|
||||||
0x53: func(s *Z80) {
|
|
||||||
s.setWord(s.nextWord(), s.de())
|
|
||||||
},
|
|
||||||
// 0x54 : NEG (Undocumented)
|
|
||||||
0x54: func(s *Z80) {
|
|
||||||
s.doNeg()
|
|
||||||
},
|
|
||||||
// 0x55 : RETN
|
|
||||||
0x55: func(s *Z80) {
|
|
||||||
s.PC = s.PopWord() - 1
|
|
||||||
s.Iff1 = s.Iff2
|
|
||||||
},
|
|
||||||
// 0x56 : IM 1
|
|
||||||
0x56: func(s *Z80) {
|
|
||||||
s.IMode = 1
|
|
||||||
},
|
|
||||||
// 0x57 : LD A, I
|
|
||||||
0x57: func(s *Z80) {
|
|
||||||
s.A = s.I
|
|
||||||
s.Flags.S = s.A&0x80 != 0
|
|
||||||
s.Flags.Z = s.A == 0
|
|
||||||
s.Flags.H = false
|
|
||||||
s.Flags.P = s.Iff2
|
|
||||||
s.Flags.N = false
|
|
||||||
s.updateXYFlags(s.A)
|
|
||||||
|
|
||||||
},
|
|
||||||
// 0x58 : IN E, (C)
|
|
||||||
0x58: func(s *Z80) {
|
|
||||||
s.E = s.doIn(s.bc())
|
|
||||||
},
|
|
||||||
// 0x59 : OUT (C), E
|
|
||||||
0x59: func(s *Z80) {
|
|
||||||
s.core.IOWrite(s.bc(), s.E)
|
|
||||||
},
|
|
||||||
// 0x5a : ADC HL, DE
|
|
||||||
0x5A: func(s *Z80) {
|
|
||||||
s.doHlAdc(s.de())
|
|
||||||
},
|
|
||||||
// 0x5b : LD DE, (nn)
|
|
||||||
0x5B: func(s *Z80) {
|
|
||||||
s.setDe(s.getWord(s.nextWord()))
|
|
||||||
},
|
|
||||||
// 0x5c : NEG (Undocumented)
|
|
||||||
0x5C: func(s *Z80) {
|
|
||||||
s.doNeg()
|
|
||||||
},
|
|
||||||
// 0x5d : RETN
|
|
||||||
0x5D: func(s *Z80) {
|
|
||||||
s.PC = s.PopWord() - 1
|
|
||||||
s.Iff1 = s.Iff2
|
|
||||||
},
|
|
||||||
// 0x5e : IM 2
|
|
||||||
0x5E: func(s *Z80) {
|
|
||||||
s.IMode = 2
|
|
||||||
},
|
|
||||||
// 0x5f : LD A, R
|
|
||||||
0x5F: func(s *Z80) {
|
|
||||||
s.A = s.R
|
|
||||||
s.Flags.S = s.A&0x80 != 0
|
|
||||||
s.Flags.Z = s.A == 0
|
|
||||||
s.Flags.H = false
|
|
||||||
s.Flags.P = s.Iff2
|
|
||||||
s.Flags.N = false
|
|
||||||
s.updateXYFlags(s.A)
|
|
||||||
|
|
||||||
},
|
|
||||||
// 0x60 : IN H, (C)
|
|
||||||
0x60: func(s *Z80) {
|
|
||||||
s.H = s.doIn(s.bc())
|
|
||||||
},
|
|
||||||
// 0x61 : OUT (C), H
|
|
||||||
0x61: func(s *Z80) {
|
|
||||||
s.core.IOWrite(s.bc(), s.H)
|
|
||||||
},
|
|
||||||
// 0x62 : SBC HL, HL
|
|
||||||
0x62: func(s *Z80) {
|
|
||||||
s.doHlSbc(s.hl())
|
|
||||||
},
|
|
||||||
// 0x63 : LD (nn), HL (Undocumented)
|
|
||||||
0x63: func(s *Z80) {
|
|
||||||
s.setWord(s.nextWord(), s.hl())
|
|
||||||
},
|
|
||||||
// 0x64 : NEG (Undocumented)
|
|
||||||
0x64: func(s *Z80) {
|
|
||||||
s.doNeg()
|
|
||||||
},
|
|
||||||
// 0x65 : RETN
|
|
||||||
0x65: func(s *Z80) {
|
|
||||||
s.PC = s.PopWord() - 1
|
|
||||||
s.Iff1 = s.Iff2
|
|
||||||
},
|
|
||||||
// 0x66 : IM 0
|
|
||||||
0x66: func(s *Z80) {
|
|
||||||
s.IMode = 0
|
|
||||||
},
|
|
||||||
// 0x67 : RRD
|
|
||||||
0x67: func(s *Z80) {
|
|
||||||
hlValue := s.core.M1MemRead(s.hl())
|
|
||||||
temp1 := hlValue & 0x0f
|
|
||||||
temp2 := s.A & 0x0f
|
|
||||||
hlValue = ((hlValue & 0xf0) >> 4) | (temp2 << 4)
|
|
||||||
s.A = (s.A & 0xf0) | temp1
|
|
||||||
s.core.MemWrite(s.hl(), hlValue)
|
|
||||||
s.Flags.S = s.A&0x80 != 0
|
|
||||||
s.Flags.Z = s.A == 0
|
|
||||||
s.Flags.H = false
|
|
||||||
s.Flags.P = ParityBits[s.A]
|
|
||||||
s.Flags.N = false
|
|
||||||
s.updateXYFlags(s.A)
|
|
||||||
|
|
||||||
},
|
|
||||||
// 0x68 : IN L, (C)
|
|
||||||
0x68: func(s *Z80) {
|
|
||||||
s.L = s.doIn(s.bc())
|
|
||||||
},
|
|
||||||
// 0x69 : OUT (C), L
|
|
||||||
0x69: func(s *Z80) {
|
|
||||||
s.core.IOWrite(s.bc(), s.L)
|
|
||||||
},
|
|
||||||
// 0x6a : ADC HL, HL
|
|
||||||
0x6A: func(s *Z80) {
|
|
||||||
s.doHlAdc(s.hl())
|
|
||||||
},
|
|
||||||
// 0x6b : LD HL, (nn) (Undocumented)
|
|
||||||
0x6B: func(s *Z80) {
|
|
||||||
s.setHl(s.getWord(s.nextWord()))
|
|
||||||
},
|
|
||||||
// 0x6C : NEG (Undocumented)
|
|
||||||
0x6C: func(s *Z80) {
|
|
||||||
s.doNeg()
|
|
||||||
},
|
|
||||||
// 0x6D : RETN
|
|
||||||
0x6D: func(s *Z80) {
|
|
||||||
s.PC = s.PopWord() - 1
|
|
||||||
s.Iff1 = s.Iff2
|
|
||||||
},
|
|
||||||
// 0x6E : IM 0
|
|
||||||
0x6E: func(s *Z80) {
|
|
||||||
s.IMode = 0
|
|
||||||
},
|
|
||||||
// 0x6f : RLD
|
|
||||||
0x6F: func(s *Z80) {
|
|
||||||
hlValue := s.core.MemRead(s.hl())
|
|
||||||
temp1 := hlValue & 0xf0
|
|
||||||
temp2 := s.A & 0x0f
|
|
||||||
hlValue = ((hlValue & 0x0f) << 4) | temp2
|
|
||||||
s.A = (s.A & 0xf0) | (temp1 >> 4)
|
|
||||||
s.core.MemWrite(s.hl(), hlValue)
|
|
||||||
|
|
||||||
s.Flags.S = s.A&0x80 != 0
|
|
||||||
s.Flags.Z = s.A == 0
|
|
||||||
s.Flags.H = false
|
|
||||||
s.Flags.P = ParityBits[s.A]
|
|
||||||
s.Flags.N = false
|
|
||||||
s.updateXYFlags(s.A)
|
|
||||||
},
|
|
||||||
// 0x70 : INF
|
|
||||||
0x70: func(s *Z80) {
|
|
||||||
s.doIn(s.bc())
|
|
||||||
},
|
|
||||||
// 0x71 : OUT (C), 0 (Undocumented)
|
|
||||||
0x71: func(s *Z80) {
|
|
||||||
s.core.IOWrite(s.bc(), 0)
|
|
||||||
},
|
|
||||||
// 0x72 : SBC HL, SP
|
|
||||||
0x72: func(s *Z80) {
|
|
||||||
s.doHlSbc(s.SP)
|
|
||||||
},
|
|
||||||
// 0x73 : LD (nn), SP
|
|
||||||
0x73: func(s *Z80) {
|
|
||||||
s.setWord(s.nextWord(), s.SP)
|
|
||||||
},
|
|
||||||
// 0x74 : NEG (Undocumented)
|
|
||||||
0x74: func(s *Z80) {
|
|
||||||
s.doNeg()
|
|
||||||
},
|
|
||||||
// 0x75 : RETN
|
|
||||||
0x75: func(s *Z80) {
|
|
||||||
s.PC = s.PopWord() - 1
|
|
||||||
s.Iff1 = s.Iff2
|
|
||||||
},
|
|
||||||
// 0x76 : IM 1
|
|
||||||
0x76: func(s *Z80) {
|
|
||||||
s.IMode = 1
|
|
||||||
},
|
|
||||||
// 0x78 : IN A, (C)
|
|
||||||
0x78: func(s *Z80) {
|
|
||||||
s.A = s.core.IORead(s.bc())
|
|
||||||
},
|
|
||||||
// 0x79 : OUT (C), A
|
|
||||||
0x79: func(s *Z80) {
|
|
||||||
s.core.IOWrite(s.bc(), s.A)
|
|
||||||
},
|
|
||||||
// 0x7a : ADC HL, SP
|
|
||||||
0x7A: func(s *Z80) {
|
|
||||||
s.doHlAdc(s.SP)
|
|
||||||
},
|
|
||||||
// 0x7b : LD SP, (nn)
|
|
||||||
0x7B: func(s *Z80) {
|
|
||||||
s.SP = s.getWord(s.nextWord())
|
|
||||||
},
|
|
||||||
// 0x7c : NEG (Undocumented)
|
|
||||||
0x7C: func(s *Z80) {
|
|
||||||
s.doNeg()
|
|
||||||
},
|
|
||||||
// 0x7d : RETN
|
|
||||||
0x7D: func(s *Z80) {
|
|
||||||
s.PC = s.PopWord() - 1
|
|
||||||
s.Iff1 = s.Iff2
|
|
||||||
},
|
|
||||||
// 0x7e : IM 2
|
|
||||||
0x7E: func(s *Z80) {
|
|
||||||
s.IMode = 2
|
|
||||||
},
|
|
||||||
// 0xa0 : LDI
|
|
||||||
0xA0: func(s *Z80) {
|
|
||||||
s.doLdi()
|
|
||||||
},
|
|
||||||
// 0xa1 : CPI
|
|
||||||
0xA1: func(s *Z80) {
|
|
||||||
s.doCpi()
|
|
||||||
},
|
|
||||||
// 0xa2 : INI
|
|
||||||
0xA2: func(s *Z80) {
|
|
||||||
s.doIni()
|
|
||||||
},
|
|
||||||
// 0xa3 : OUTI
|
|
||||||
0xA3: func(s *Z80) {
|
|
||||||
s.doOuti()
|
|
||||||
},
|
|
||||||
// 0xa8 : LDD
|
|
||||||
0xA8: func(s *Z80) {
|
|
||||||
s.doLdd()
|
|
||||||
},
|
|
||||||
// 0xa9 : CPD
|
|
||||||
0xA9: func(s *Z80) {
|
|
||||||
s.doCpd()
|
|
||||||
},
|
|
||||||
// 0xaa : IND
|
|
||||||
0xAA: func(s *Z80) {
|
|
||||||
s.doInd()
|
|
||||||
},
|
|
||||||
// 0xab : OUTD
|
|
||||||
0xAB: func(s *Z80) {
|
|
||||||
s.doOutd()
|
|
||||||
},
|
|
||||||
// 0xb0 : LDIR
|
|
||||||
0xB0: func(s *Z80) {
|
|
||||||
s.doLdi()
|
|
||||||
if (s.B | s.C) != 0 {
|
|
||||||
s.CycleCounter += 5
|
|
||||||
s.PC -= 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 0xb1 : CPIR
|
|
||||||
0xB1: func(s *Z80) {
|
|
||||||
s.doCpi()
|
|
||||||
if !s.Flags.Z && (s.B|s.C) != 0 {
|
|
||||||
s.CycleCounter += 5
|
|
||||||
s.PC -= 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 0xb2 : INIR
|
|
||||||
0xB2: func(s *Z80) {
|
|
||||||
s.doIni()
|
|
||||||
if s.B != 0 {
|
|
||||||
s.CycleCounter += 5
|
|
||||||
s.PC -= 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 0xb3 : OTIR
|
|
||||||
0xB3: func(s *Z80) {
|
|
||||||
s.doOuti()
|
|
||||||
if s.B != 0 {
|
|
||||||
s.CycleCounter += 5
|
|
||||||
s.PC -= 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 0xb8 : LDDR
|
|
||||||
0xB8: func(s *Z80) {
|
|
||||||
s.doLdd()
|
|
||||||
if (s.B | s.C) != 0 {
|
|
||||||
s.CycleCounter += 5
|
|
||||||
s.PC -= 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 0xb9 : CPDR
|
|
||||||
0xB9: func(s *Z80) {
|
|
||||||
s.doCpd()
|
|
||||||
if !s.Flags.Z && (s.B|s.C) != 0 {
|
|
||||||
s.CycleCounter += 5
|
|
||||||
s.PC -= 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 0xba : INDR
|
|
||||||
0xBA: func(s *Z80) {
|
|
||||||
s.doInd()
|
|
||||||
if s.B != 0 {
|
|
||||||
s.CycleCounter += 5
|
|
||||||
s.PC -= 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 0xbb : OTDR
|
|
||||||
0xBB: func(s *Z80) {
|
|
||||||
s.doOutd()
|
|
||||||
if s.B != 0 {
|
|
||||||
s.CycleCounter += 5
|
|
||||||
s.PC -= 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (z *Z80) opcodeED() {
|
|
||||||
z.incR()
|
|
||||||
z.PC++
|
|
||||||
|
|
||||||
opcode := z.core.M1MemRead(z.PC)
|
|
||||||
|
|
||||||
fun := edInstructions[opcode]
|
|
||||||
if fun != nil {
|
|
||||||
fun(z)
|
|
||||||
z.CycleCounter += CycleCountsEd[opcode]
|
|
||||||
} else {
|
|
||||||
z.PC--
|
|
||||||
z.CycleCounter += CycleCounts[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user