mirror of
https://github.com/romychs/z80go.git
synced 2026-04-16 00:34:22 +03:00
CPU emulator pass all tests
This commit is contained in:
parent
44c36ecb94
commit
d05db31cd2
29
cpu.go
29
cpu.go
@ -22,6 +22,7 @@ func NewCPU(core MemIoRW) *CPU {
|
||||
// z.codeCoverage map[uint16]bool
|
||||
z.extendedStackEnabled = false
|
||||
//z.extendedStack [65536]uint8
|
||||
z.extendedStack = map[uint16]PushValueType{}
|
||||
return &z
|
||||
}
|
||||
|
||||
@ -68,15 +69,10 @@ func (z *CPU) SetState(state *CPU) {
|
||||
z.I = state.I
|
||||
z.R = state.R
|
||||
|
||||
z.Flags.S = state.Flags.S
|
||||
z.Flags.Z = state.Flags.Z
|
||||
z.Flags.Y = state.Flags.Y
|
||||
z.Flags.H = state.Flags.H
|
||||
z.Flags.X = state.Flags.X
|
||||
z.Flags.P = state.Flags.P
|
||||
z.Flags.N = state.Flags.N
|
||||
z.Flags.C = state.Flags.C
|
||||
z.Flags = state.Flags
|
||||
z.FlagsAlt = state.FlagsAlt
|
||||
|
||||
z.MemPtr = state.MemPtr
|
||||
z.IMode = state.IMode
|
||||
z.Iff1 = state.Iff1
|
||||
z.Iff2 = state.Iff2
|
||||
@ -108,8 +104,8 @@ func (z *CPU) GetState() *CPU {
|
||||
SP: z.SP,
|
||||
PC: z.PC,
|
||||
|
||||
Flags: z.flags(),
|
||||
FlagsAlt: z.altFlags(),
|
||||
Flags: z.Flags,
|
||||
FlagsAlt: z.FlagsAlt,
|
||||
IMode: z.IMode,
|
||||
Iff1: z.Iff1,
|
||||
Iff2: z.Iff2,
|
||||
@ -117,7 +113,7 @@ func (z *CPU) GetState() *CPU {
|
||||
CycleCount: z.cycleCount,
|
||||
IntOccurred: z.IntOccurred,
|
||||
NmiOccurred: z.NmiOccurred,
|
||||
memPtr: z.memPtr,
|
||||
MemPtr: z.MemPtr,
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,17 +143,18 @@ func (z *CPU) CodeCoverage() map[uint16]bool {
|
||||
func (z *CPU) SetExtendedStack(enabled bool) {
|
||||
z.extendedStackEnabled = enabled
|
||||
if enabled {
|
||||
for addr := 0; addr < 65536; addr++ {
|
||||
z.extendedStack[addr] = PushValueTypeDefault
|
||||
}
|
||||
clear(z.extendedStack)
|
||||
//for addr := 0; addr < 65536; addr++ {
|
||||
// z.extendedStack[uint16(addr)] = PushValueTypeDefault
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
// ExtendedStack - return array with markers of PushValueType* for each byte of memory
|
||||
func (z *CPU) ExtendedStack() ([]byte, error) {
|
||||
func (z *CPU) ExtendedStack() (map[uint16]PushValueType, error) {
|
||||
var err error
|
||||
if !z.extendedStackEnabled {
|
||||
err = errors.New("error, z80: ExtendedStack disabled")
|
||||
}
|
||||
return z.extendedStack[:], err
|
||||
return z.extendedStack, err
|
||||
}
|
||||
|
||||
@ -2,20 +2,21 @@ package dis
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"okemu/z80"
|
||||
"strings"
|
||||
|
||||
"github.com/romychs/z80go"
|
||||
)
|
||||
|
||||
type Disassembler struct {
|
||||
pc uint16
|
||||
core z80.MemIoRW
|
||||
core z80go.MemIoRW
|
||||
}
|
||||
|
||||
type Disassembly interface {
|
||||
Disassm(pc uint16) string
|
||||
}
|
||||
|
||||
func NewDisassembler(core z80.MemIoRW) *Disassembler {
|
||||
func NewDisassembler(core z80go.MemIoRW) *Disassembler {
|
||||
d := Disassembler{
|
||||
pc: 0,
|
||||
core: core,
|
||||
|
||||
@ -46,6 +46,7 @@ func setMemory(addr uint16, value []byte) {
|
||||
var test = []byte{0x31, 0x2c, 0x05, 0x11, 0x0e, 0x01, 0x0e, 0x09, 0xcd, 0x05, 0x00, 0xc3, 0x00, 0x00}
|
||||
|
||||
func Test_LD_SP_nn(t *testing.T) {
|
||||
t.Logf("Disassembler Z80 test")
|
||||
expected := " 0100 LD SP, 0x052C"
|
||||
setMemory(0x100, test)
|
||||
res := disasm.Disassm(0x100)
|
||||
|
||||
4
go.mod
4
go.mod
@ -4,5 +4,7 @@ go 1.25
|
||||
|
||||
require (
|
||||
github.com/sirupsen/logrus v1.9.4
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.13.0 // indirect
|
||||
|
||||
3
go.sum
3
go.sum
@ -1,3 +1,6 @@
|
||||
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@ -191,7 +191,7 @@ func (z *CPU) Reset() {
|
||||
z.SP = 0xFFFF
|
||||
z.IX = 0
|
||||
z.IY = 0
|
||||
z.memPtr = 0
|
||||
z.MemPtr = 0
|
||||
|
||||
z.A = 0xFF
|
||||
z.B = 0
|
||||
@ -213,7 +213,7 @@ func (z *CPU) Reset() {
|
||||
z.R = 0
|
||||
|
||||
z.Flags.SetFlags(0xff)
|
||||
z.FlagsAlt.SetFlags(0xff)
|
||||
z.FlagsAlt.SetFlags(0x00)
|
||||
|
||||
z.iffDelay = 0
|
||||
z.IMode = 0
|
||||
|
||||
87
opcodes.go
87
opcodes.go
@ -5,7 +5,7 @@ import log "github.com/sirupsen/logrus"
|
||||
// jumps to an address
|
||||
func (z *CPU) jump(addr uint16) {
|
||||
z.PC = addr
|
||||
z.memPtr = addr
|
||||
z.MemPtr = addr
|
||||
}
|
||||
|
||||
// jumps to next word in memory if condition is true
|
||||
@ -14,7 +14,7 @@ func (z *CPU) condJump(condition bool) {
|
||||
if condition {
|
||||
z.jump(addr)
|
||||
}
|
||||
z.memPtr = addr
|
||||
z.MemPtr = addr
|
||||
}
|
||||
|
||||
// calls to next word in memory
|
||||
@ -22,7 +22,7 @@ func (z *CPU) call(addr uint16) {
|
||||
z.pushW(z.PC)
|
||||
z.extendedStack[z.SP] = PushValueTypeCall
|
||||
z.PC = addr
|
||||
z.memPtr = addr
|
||||
z.MemPtr = addr
|
||||
}
|
||||
|
||||
// calls to next word in memory if condition is true
|
||||
@ -32,13 +32,13 @@ func (z *CPU) condCall(condition bool) {
|
||||
z.call(addr)
|
||||
z.cycleCount += 7
|
||||
}
|
||||
z.memPtr = addr
|
||||
z.MemPtr = addr
|
||||
}
|
||||
|
||||
// returns from subroutine
|
||||
func (z *CPU) ret() {
|
||||
z.PC = z.popW()
|
||||
z.memPtr = z.PC
|
||||
z.MemPtr = z.PC
|
||||
}
|
||||
|
||||
// returns from subroutine if condition is true
|
||||
@ -55,7 +55,7 @@ func (z *CPU) jr(offset byte) {
|
||||
} else {
|
||||
z.PC += uint16(offset)
|
||||
}
|
||||
z.memPtr = z.PC
|
||||
z.MemPtr = z.PC
|
||||
}
|
||||
|
||||
func (z *CPU) condJr(condition bool) {
|
||||
@ -101,7 +101,7 @@ func (z *CPU) addW(a uint16, b uint16, cy bool) uint16 {
|
||||
msb := z.addB(byte(a>>8), byte(b>>8), z.Flags.C)
|
||||
result := (uint16(msb) << 8) | uint16(lsb)
|
||||
z.Flags.Z = result == 0
|
||||
z.memPtr = a + 1
|
||||
z.MemPtr = a + 1
|
||||
return result
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ func (z *CPU) subW(a uint16, b uint16, cy bool) uint16 {
|
||||
msb := z.subB(byte(a>>8), byte(b>>8), z.Flags.C)
|
||||
result := (uint16(msb) << 8) | uint16(lsb)
|
||||
z.Flags.Z = result == 0
|
||||
z.memPtr = a + 1
|
||||
z.MemPtr = a + 1
|
||||
return result
|
||||
}
|
||||
|
||||
@ -388,14 +388,14 @@ func (z *CPU) cpi() {
|
||||
z.Flags.Y = val&0x02 != 0
|
||||
z.Flags.P = z.bc() != 0
|
||||
z.Flags.C = cf
|
||||
z.memPtr += 1
|
||||
z.MemPtr += 1
|
||||
}
|
||||
|
||||
func (z *CPU) cpd() {
|
||||
z.cpi()
|
||||
// same as cpi but HL is decremented instead of incremented
|
||||
z.setHL(z.hl() - 2)
|
||||
z.memPtr -= 2
|
||||
z.MemPtr -= 2
|
||||
}
|
||||
|
||||
func (z *CPU) inRC(r *byte) {
|
||||
@ -410,7 +410,7 @@ func (z *CPU) inRC(r *byte) {
|
||||
func (z *CPU) ini() {
|
||||
val := z.core.IORead(z.bc())
|
||||
z.wb(z.hl(), val)
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
z.B--
|
||||
|
||||
other := val + z.C + 1
|
||||
@ -432,7 +432,7 @@ func (z *CPU) ini() {
|
||||
func (z *CPU) ind() {
|
||||
val := z.core.IORead(z.bc())
|
||||
z.wb(z.hl(), val)
|
||||
z.memPtr = z.bc() - 1
|
||||
z.MemPtr = z.bc() - 1
|
||||
z.B--
|
||||
|
||||
other := val + z.C - 1
|
||||
@ -451,13 +451,7 @@ func (z *CPU) ind() {
|
||||
z.updateXY(z.B)
|
||||
z.setHL(z.hl() - 1)
|
||||
}
|
||||
|
||||
func (z *CPU) outi() {
|
||||
val := z.rb(z.hl())
|
||||
z.B--
|
||||
z.memPtr = z.bc() + 1
|
||||
z.core.IOWrite(z.bc(), val)
|
||||
z.setHL(z.hl() + 1)
|
||||
func (z *CPU) outCmnFlags(val uint8) {
|
||||
other := val + z.L
|
||||
z.Flags.N = val&0x80 != 0
|
||||
if other < val {
|
||||
@ -473,25 +467,22 @@ func (z *CPU) outi() {
|
||||
z.updateXY(z.B)
|
||||
}
|
||||
|
||||
func (z *CPU) outi() {
|
||||
val := z.rb(z.hl())
|
||||
z.B--
|
||||
z.MemPtr = z.bc() + 1
|
||||
z.core.IOWrite(z.bc(), val)
|
||||
z.setHL(z.hl() + 1)
|
||||
z.outCmnFlags(val)
|
||||
}
|
||||
|
||||
func (z *CPU) outd() {
|
||||
val := z.rb(z.hl())
|
||||
z.B--
|
||||
z.memPtr = z.bc() - 1
|
||||
z.MemPtr = z.bc() - 1
|
||||
z.core.IOWrite(z.bc(), val)
|
||||
z.setHL(z.hl() - 1)
|
||||
other := val + z.L
|
||||
z.Flags.N = val&0x80 != 0
|
||||
if other < val {
|
||||
z.Flags.H = true
|
||||
z.Flags.C = true
|
||||
} else {
|
||||
z.Flags.H = false
|
||||
z.Flags.C = false
|
||||
}
|
||||
z.Flags.P = parity((other & 0x07) ^ z.B)
|
||||
z.Flags.Z = z.B == 0
|
||||
z.Flags.S = z.B&0x80 != 0
|
||||
z.updateXY(z.B)
|
||||
z.outCmnFlags(val)
|
||||
}
|
||||
|
||||
func (z *CPU) daa() {
|
||||
@ -529,7 +520,7 @@ func (z *CPU) displace(baseAddr uint16, offset byte) uint16 {
|
||||
addr += uint16(offset)
|
||||
}
|
||||
//addr := baseAddr + uint16(displacement)
|
||||
z.memPtr = addr
|
||||
z.MemPtr = addr
|
||||
return addr
|
||||
}
|
||||
|
||||
@ -751,29 +742,29 @@ func (z *CPU) execOpcode(opcode byte) {
|
||||
case 0x0A:
|
||||
// ld a,(bc)
|
||||
z.A = z.rb(z.bc())
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x1A:
|
||||
// ld a,(de)
|
||||
z.A = z.rb(z.de())
|
||||
z.memPtr = z.de() + 1
|
||||
z.MemPtr = z.de() + 1
|
||||
case 0x3A:
|
||||
// ld a,(**)
|
||||
addr := z.nextW()
|
||||
z.A = z.rb(addr)
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x02:
|
||||
// ld (bc),a
|
||||
z.wb(z.bc(), z.A)
|
||||
z.memPtr = (uint16(z.A) << 8) | ((z.bc() + 1) & 0xFF)
|
||||
z.MemPtr = (uint16(z.A) << 8) | ((z.bc() + 1) & 0xFF)
|
||||
case 0x12:
|
||||
// ld (de),a
|
||||
z.wb(z.de(), z.A)
|
||||
z.memPtr = (uint16(z.A) << 8) | ((z.de() + 1) & 0xFF)
|
||||
z.MemPtr = (uint16(z.A) << 8) | ((z.de() + 1) & 0xFF)
|
||||
case 0x32:
|
||||
// ld (**),a
|
||||
addr := z.nextW()
|
||||
z.wb(addr, z.A)
|
||||
z.memPtr = (uint16(z.A) << 8) | ((addr + 1) & 0xFF)
|
||||
z.MemPtr = (uint16(z.A) << 8) | ((addr + 1) & 0xFF)
|
||||
case 0x01:
|
||||
z.setBC(z.nextW()) // ld bc,**
|
||||
case 0x11:
|
||||
@ -787,12 +778,12 @@ func (z *CPU) execOpcode(opcode byte) {
|
||||
// ld hl,(**)
|
||||
addr := z.nextW()
|
||||
z.setHL(z.rw(addr))
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x22:
|
||||
// ld (**),hl
|
||||
addr := z.nextW()
|
||||
z.ww(addr, z.hl())
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0xF9:
|
||||
z.SP = z.hl() // ld sp,hl
|
||||
|
||||
@ -806,7 +797,7 @@ func (z *CPU) execOpcode(opcode byte) {
|
||||
val := z.rw(z.SP)
|
||||
z.ww(z.SP, z.hl())
|
||||
z.setHL(val)
|
||||
z.memPtr = val
|
||||
z.MemPtr = val
|
||||
case 0x87:
|
||||
z.A = z.addB(z.A, z.A, false) // add a,a
|
||||
case 0x80:
|
||||
@ -1103,7 +1094,7 @@ func (z *CPU) execOpcode(opcode byte) {
|
||||
z.condJr(z.B != 0) // djnz *
|
||||
case 0x18:
|
||||
z.PC += uint16(z.nextB()) // jr *
|
||||
z.memPtr = z.PC
|
||||
z.MemPtr = z.PC
|
||||
case 0x20:
|
||||
z.condJr(!z.Flags.Z) // jr nz, *
|
||||
case 0x28:
|
||||
@ -1202,19 +1193,19 @@ func (z *CPU) execOpcode(opcode byte) {
|
||||
// in a,(n)
|
||||
port := (uint16(z.A) << 8) | uint16(z.nextB())
|
||||
z.A = z.core.IORead(port)
|
||||
z.memPtr = port + 1 // (uint16(a) << 8) | (uint16(z.a+1) & 0x00ff)
|
||||
z.MemPtr = port + 1 // (uint16(a) << 8) | (uint16(z.a+1) & 0x00ff)
|
||||
case 0xD3:
|
||||
// out (n), a
|
||||
port := uint16(z.nextB())
|
||||
z.core.IOWrite(port, z.A)
|
||||
z.memPtr = ((port + 1) & 0x00ff) | (uint16(z.A) << 8)
|
||||
z.MemPtr = ((port + 1) & 0x00ff) | (uint16(z.A) << 8)
|
||||
case 0x08:
|
||||
// ex af,af'
|
||||
a := z.A
|
||||
f := z.Flags.Flags()
|
||||
f := z.Flags.AsByte()
|
||||
|
||||
z.A = z.AAlt
|
||||
z.Flags.SetFlags(z.FlagsAlt.Flags())
|
||||
z.Flags.SetFlags(z.FlagsAlt.AsByte())
|
||||
|
||||
z.AAlt = a
|
||||
z.FlagsAlt.SetFlags(f)
|
||||
|
||||
@ -63,7 +63,7 @@ func (z *CPU) execOpcodeCB(opcode byte) {
|
||||
|
||||
// in bit (hl), x/y flags are handled differently:
|
||||
if z_ == 6 {
|
||||
z.updateXY(byte(z.memPtr >> 8))
|
||||
z.updateXY(byte(z.MemPtr >> 8))
|
||||
z.cycleCount += 4
|
||||
}
|
||||
|
||||
|
||||
@ -96,11 +96,11 @@ func (z *CPU) execOpcodeDDFD(opcode byte, iz *uint16) {
|
||||
case 0x2A:
|
||||
addr := z.nextW()
|
||||
*iz = z.rw(addr) // ld iz,(**)
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x22:
|
||||
addr := z.nextW()
|
||||
z.ww(addr, *iz) // ld (**),iz
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x21:
|
||||
*iz = z.nextW() // ld iz,**
|
||||
case 0x36:
|
||||
@ -192,7 +192,7 @@ func (z *CPU) execOpcodeDDFD(opcode byte, iz *uint16) {
|
||||
val := z.rw(z.SP)
|
||||
z.ww(z.SP, *iz)
|
||||
*iz = val
|
||||
z.memPtr = val
|
||||
z.MemPtr = val
|
||||
case 0xCB:
|
||||
addr := z.displace(*iz, z.nextB())
|
||||
op := z.nextB()
|
||||
|
||||
60
opcodesED.go
60
opcodesED.go
@ -44,7 +44,7 @@ func (z *CPU) execOpcodeED(opcode byte) {
|
||||
if z.bc() != 0 {
|
||||
z.PC -= 2
|
||||
z.cycleCount += 5
|
||||
z.memPtr = z.PC + 1
|
||||
z.MemPtr = z.PC + 1
|
||||
}
|
||||
} // ldir
|
||||
|
||||
@ -57,7 +57,7 @@ func (z *CPU) execOpcodeED(opcode byte) {
|
||||
if z.bc() != 0 {
|
||||
z.PC -= 2
|
||||
z.cycleCount += 5
|
||||
z.memPtr = z.PC + 1
|
||||
z.MemPtr = z.PC + 1
|
||||
}
|
||||
} // lddr
|
||||
|
||||
@ -71,7 +71,7 @@ func (z *CPU) execOpcodeED(opcode byte) {
|
||||
if z.bc() != 0 && !z.Flags.Z {
|
||||
z.PC -= 2
|
||||
z.cycleCount += 5
|
||||
z.memPtr = z.PC + 1
|
||||
z.MemPtr = z.PC + 1
|
||||
} else {
|
||||
//z.mem_ptr++
|
||||
}
|
||||
@ -82,15 +82,15 @@ func (z *CPU) execOpcodeED(opcode byte) {
|
||||
if z.bc() != 0 && !z.Flags.Z {
|
||||
z.PC -= 2
|
||||
z.cycleCount += 5
|
||||
z.memPtr = z.PC + 1
|
||||
z.MemPtr = z.PC + 1
|
||||
} else {
|
||||
//z.mem_ptr++
|
||||
}
|
||||
case 0x40:
|
||||
z.inRC(&z.B) // in b, (c)
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x48:
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
z.inRC(&z.C) // in c, (c)
|
||||
z.updateXY(z.C)
|
||||
//case 0x4e:
|
||||
@ -98,28 +98,28 @@ func (z *CPU) execOpcodeED(opcode byte) {
|
||||
|
||||
case 0x50:
|
||||
z.inRC(&z.D) // in d, (c)
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x58:
|
||||
// in e, (c)
|
||||
z.inRC(&z.E)
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
z.updateXY(z.E)
|
||||
case 0x60:
|
||||
z.inRC(&z.H) // in h, (c)
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x68:
|
||||
z.inRC(&z.L) // in l, (c)
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
z.updateXY(z.L)
|
||||
case 0x70:
|
||||
// in (c)
|
||||
var val byte
|
||||
z.inRC(&val)
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x78:
|
||||
// in a, (c)
|
||||
z.inRC(&z.A)
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
z.updateXY(z.A)
|
||||
case 0xA2:
|
||||
z.ini() // ini
|
||||
@ -142,29 +142,29 @@ func (z *CPU) execOpcodeED(opcode byte) {
|
||||
}
|
||||
case 0x41:
|
||||
z.core.IOWrite(z.bc(), z.B) // out (c), b
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x49:
|
||||
z.core.IOWrite(z.bc(), z.C) // out (c), c
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x51:
|
||||
z.core.IOWrite(z.bc(), z.D) // out (c), d
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x59:
|
||||
z.core.IOWrite(z.bc(), z.E) // out (c), e
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x61:
|
||||
z.core.IOWrite(z.bc(), z.H) // out (c), h
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x69:
|
||||
z.core.IOWrite(z.bc(), z.L) // out (c), l
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x71:
|
||||
z.core.IOWrite(z.bc(), 0) // out (c), 0
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0x79:
|
||||
// out (c), a
|
||||
z.core.IOWrite(z.bc(), z.A)
|
||||
z.memPtr = z.bc() + 1
|
||||
z.MemPtr = z.bc() + 1
|
||||
case 0xA3:
|
||||
z.outi() // outi
|
||||
case 0xB3:
|
||||
@ -204,42 +204,42 @@ func (z *CPU) execOpcodeED(opcode byte) {
|
||||
// ld (**), bc
|
||||
addr := z.nextW()
|
||||
z.ww(addr, z.bc())
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x53:
|
||||
// ld (**), de
|
||||
addr := z.nextW()
|
||||
z.ww(addr, z.de())
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x63:
|
||||
// ld (**), hl
|
||||
addr := z.nextW()
|
||||
z.ww(addr, z.hl())
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x73:
|
||||
// ld (**), hl
|
||||
addr := z.nextW()
|
||||
z.ww(addr, z.SP)
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x4B:
|
||||
// ld bc, (**)
|
||||
addr := z.nextW()
|
||||
z.setBC(z.rw(addr))
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x5B:
|
||||
// ld de, (**)
|
||||
addr := z.nextW()
|
||||
z.setDE(z.rw(addr))
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x6B:
|
||||
// ld hl, (**)
|
||||
addr := z.nextW()
|
||||
z.setHL(z.rw(addr))
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x7B:
|
||||
// ld sp,(**)
|
||||
addr := z.nextW()
|
||||
z.SP = z.rw(addr)
|
||||
z.memPtr = addr + 1
|
||||
z.MemPtr = addr + 1
|
||||
case 0x44, 0x54, 0x64, 0x74, 0x4C, 0x5C, 0x6C, 0x7C:
|
||||
z.A = z.subB(0, z.A, false) // neg
|
||||
case 0x46, 0x4e, 0x66, 0x6e:
|
||||
@ -261,7 +261,7 @@ func (z *CPU) execOpcodeED(opcode byte) {
|
||||
z.Flags.Z = z.A == 0
|
||||
z.Flags.S = z.A&0x80 != 0
|
||||
z.Flags.P = parity(z.A)
|
||||
z.memPtr = z.hl() + 1
|
||||
z.MemPtr = z.hl() + 1
|
||||
case 0x6F:
|
||||
// rld
|
||||
a := z.A
|
||||
@ -274,7 +274,7 @@ func (z *CPU) execOpcodeED(opcode byte) {
|
||||
z.Flags.Z = z.A == 0
|
||||
z.Flags.S = z.A&0x80 != 0
|
||||
z.Flags.P = parity(z.A)
|
||||
z.memPtr = z.hl() + 1
|
||||
z.MemPtr = z.hl() + 1
|
||||
default:
|
||||
log.Errorf("Unknown ED opcode: %02X\n", opcode)
|
||||
}
|
||||
|
||||
136
z80go.go
136
z80go.go
@ -59,52 +59,78 @@ type FlagsType struct {
|
||||
|
||||
// CPU - Processor state
|
||||
type CPU struct {
|
||||
A byte `json:"a,omitempty"`
|
||||
B byte `json:"b,omitempty"`
|
||||
C byte `json:"c,omitempty"`
|
||||
D byte `json:"d,omitempty"`
|
||||
E byte `json:"e,omitempty"`
|
||||
H byte `json:"h,omitempty"`
|
||||
L byte `json:"l,omitempty"`
|
||||
AAlt byte `json:"AAlt,omitempty"`
|
||||
BAlt byte `json:"BAlt,omitempty"`
|
||||
CAlt byte `json:"CAlt,omitempty"`
|
||||
DAlt byte `json:"DAlt,omitempty"`
|
||||
EAlt byte `json:"EAlt,omitempty"`
|
||||
HAlt byte `json:"HAlt,omitempty"`
|
||||
LAlt byte `json:"LAlt,omitempty"`
|
||||
IX uint16 `json:"IX,omitempty"`
|
||||
IY uint16 `json:"IY,omitempty"`
|
||||
I byte `json:"i,omitempty"`
|
||||
R byte `json:"r,omitempty"`
|
||||
SP uint16 `json:"SP,omitempty"`
|
||||
PC uint16 `json:"PC,omitempty"`
|
||||
Flags FlagsType `json:"flags"`
|
||||
FlagsAlt FlagsType `json:"flagsAlt"`
|
||||
IMode byte `json:"IMode,omitempty"`
|
||||
Iff1 bool `json:"iff1,omitempty"`
|
||||
Iff2 bool `json:"iff2,omitempty"`
|
||||
Halted bool `json:"halted,omitempty"`
|
||||
CycleCount uint32 `json:"cycleCount,omitempty"`
|
||||
IntOccurred bool `json:"intOccurred,omitempty"`
|
||||
NmiOccurred bool `json:"interruptOccurred,omitempty"`
|
||||
memPtr uint16
|
||||
core MemIoRW
|
||||
intData byte
|
||||
cycleCount uint32 // cycle count (t-states)
|
||||
memAccess map[uint16]byte
|
||||
codeCoverageEnabled bool
|
||||
codeCoverage map[uint16]bool
|
||||
// base register set
|
||||
A byte `json:"a,omitempty"`
|
||||
B byte `json:"b,omitempty"`
|
||||
C byte `json:"c,omitempty"`
|
||||
D byte `json:"d,omitempty"`
|
||||
E byte `json:"e,omitempty"`
|
||||
H byte `json:"h,omitempty"`
|
||||
L byte `json:"l,omitempty"`
|
||||
// alternate register set
|
||||
AAlt byte `json:"AAlt,omitempty"`
|
||||
BAlt byte `json:"BAlt,omitempty"`
|
||||
CAlt byte `json:"CAlt,omitempty"`
|
||||
DAlt byte `json:"DAlt,omitempty"`
|
||||
EAlt byte `json:"EAlt,omitempty"`
|
||||
HAlt byte `json:"HAlt,omitempty"`
|
||||
LAlt byte `json:"LAlt,omitempty"`
|
||||
// index registers
|
||||
IX uint16 `json:"IX,omitempty"`
|
||||
IY uint16 `json:"IY,omitempty"`
|
||||
|
||||
I byte `json:"i,omitempty"`
|
||||
|
||||
// memory refresh register
|
||||
R byte `json:"r,omitempty"`
|
||||
|
||||
// stack pointer
|
||||
SP uint16 `json:"SP,omitempty"`
|
||||
|
||||
// program counter
|
||||
PC uint16 `json:"PC,omitempty"`
|
||||
|
||||
// cpu flags
|
||||
Flags FlagsType `json:"flags"`
|
||||
|
||||
// alternate cpu flags
|
||||
FlagsAlt FlagsType `json:"flagsAlt"`
|
||||
|
||||
// Interrupt mode
|
||||
IMode byte `json:"IMode,omitempty"`
|
||||
Iff1 bool `json:"iff1,omitempty"`
|
||||
Iff2 bool `json:"iff2,omitempty"`
|
||||
Halted bool `json:"halted,omitempty"`
|
||||
CycleCount uint32 `json:"cycleCount,omitempty"`
|
||||
IntOccurred bool `json:"intOccurred,omitempty"`
|
||||
NmiOccurred bool `json:"interruptOccurred,omitempty"`
|
||||
// mw hidden register
|
||||
MemPtr uint16
|
||||
|
||||
// methods to access CPU to memory and IO ports of computer
|
||||
core MemIoRW
|
||||
intData byte
|
||||
// Total CPU cycle count (t-states)
|
||||
cycleCount uint32
|
||||
// map of memory access
|
||||
memAccess map[uint16]byte
|
||||
// enable or disable code coverage marking
|
||||
codeCoverageEnabled bool
|
||||
// map of code coverage
|
||||
codeCoverage map[uint16]bool
|
||||
// enable of disable stack data marking
|
||||
extendedStackEnabled bool
|
||||
extendedStack map[uint16]PushValueType
|
||||
iffDelay byte
|
||||
intPending bool
|
||||
nmiPending bool
|
||||
// map of stack data marking
|
||||
extendedStack map[uint16]PushValueType
|
||||
|
||||
iffDelay byte
|
||||
intPending bool
|
||||
nmiPending bool
|
||||
}
|
||||
|
||||
// Flags - return flags as byte value
|
||||
// AsByte - return flags as byte value
|
||||
// Used to simplify manipulations with AF register from debugger
|
||||
func (f *FlagsType) Flags() byte {
|
||||
func (f *FlagsType) AsByte() byte {
|
||||
var flags byte = 0
|
||||
if f.S {
|
||||
flags |= 0x80
|
||||
@ -174,19 +200,19 @@ func (z *CPU) IIFStr() string {
|
||||
return string(flags)
|
||||
}
|
||||
|
||||
//// Flags - return state of CPU flags
|
||||
//func Flags(f byte) FlagsType {
|
||||
// return FlagsType{
|
||||
// S: f&0x80 != 0,
|
||||
// Z: f&0x40 != 0,
|
||||
// Y: f&0x20 != 0,
|
||||
// H: f&0x10 != 0,
|
||||
// X: f&0x08 != 0,
|
||||
// P: f&0x04 != 0,
|
||||
// N: f&0x02 != 0,
|
||||
// C: f&0x01 != 0,
|
||||
// }
|
||||
//}
|
||||
// NewFlags build new object of FlagsType from byte
|
||||
func NewFlags(f byte) *FlagsType {
|
||||
return &FlagsType{
|
||||
S: f&0x80 != 0,
|
||||
Z: f&0x40 != 0,
|
||||
Y: f&0x20 != 0,
|
||||
H: f&0x10 != 0,
|
||||
X: f&0x08 != 0,
|
||||
P: f&0x04 != 0,
|
||||
N: f&0x02 != 0,
|
||||
C: f&0x01 != 0,
|
||||
}
|
||||
}
|
||||
|
||||
// SetFlags - set CPU flags by flags byte.
|
||||
// Used to simplify manipulations with AF register from debugger
|
||||
|
||||
@ -4,12 +4,11 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"okemu/z80"
|
||||
"okemu/z80/c99"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/romychs/z80go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@ -82,7 +81,7 @@ var testIn []byte
|
||||
var testExpected []byte
|
||||
|
||||
type Computer struct {
|
||||
cpu *c99.Z80
|
||||
cpu *z80go.CPU
|
||||
memory [65536]byte
|
||||
ports [256]byte
|
||||
}
|
||||
@ -94,8 +93,6 @@ var computer Computer
|
||||
|
||||
var testNames []string
|
||||
|
||||
//var z80 *c99.Z80
|
||||
|
||||
func init() {
|
||||
z80TestsIn = make(map[string]Z80TestIn)
|
||||
z80TestsExpected = make(map[string]Expect)
|
||||
@ -107,7 +104,7 @@ func init() {
|
||||
for addr := 0; addr < 255; addr++ {
|
||||
computer.ports[addr] = 0
|
||||
}
|
||||
computer.cpu = c99.New(&computer)
|
||||
computer.cpu = z80go.NewCPU(&computer)
|
||||
}
|
||||
|
||||
func (c *Computer) M1MemRead(addr uint16) byte {
|
||||
@ -403,7 +400,8 @@ func TestZ80Fuse(t *testing.T) {
|
||||
}
|
||||
cy := uint32(0)
|
||||
for {
|
||||
cy += computer.cpu.RunInstruction()
|
||||
c, _ := computer.cpu.RunInstruction()
|
||||
cy += c
|
||||
if cy >= uint32(exp.state.tStates) {
|
||||
break
|
||||
}
|
||||
@ -413,38 +411,37 @@ func TestZ80Fuse(t *testing.T) {
|
||||
}
|
||||
|
||||
func setComputerState(test Z80TestIn) {
|
||||
state := z80.CPU{
|
||||
A: byte(test.registers.AF >> 8),
|
||||
B: byte(test.registers.BC >> 8),
|
||||
C: byte(test.registers.BC),
|
||||
D: byte(test.registers.DE >> 8),
|
||||
E: byte(test.registers.DE),
|
||||
H: byte(test.registers.HL >> 8),
|
||||
L: byte(test.registers.HL),
|
||||
AAlt: byte(test.registers.AFa >> 8),
|
||||
BAlt: byte(test.registers.BCa >> 8),
|
||||
CAlt: byte(test.registers.BCa),
|
||||
DAlt: byte(test.registers.DEa >> 8),
|
||||
EAlt: byte(test.registers.DEa),
|
||||
HAlt: byte(test.registers.HLa >> 8),
|
||||
LAlt: byte(test.registers.HLa),
|
||||
IX: test.registers.IX,
|
||||
IY: test.registers.IY,
|
||||
I: test.state.I,
|
||||
R: test.state.R,
|
||||
SP: test.registers.SP,
|
||||
PC: test.registers.PC,
|
||||
Flags: z80.GetFlags(byte(test.registers.AF)),
|
||||
FlagsAlt: z80.GetFlags(byte(test.registers.AFa)),
|
||||
IMode: test.state.IM,
|
||||
Iff1: test.state.IFF1,
|
||||
Iff2: test.state.IFF2,
|
||||
Halted: test.state.isHalted,
|
||||
DoDelayedDI: false,
|
||||
DoDelayedEI: false,
|
||||
CycleCount: 0,
|
||||
InterruptOccurred: false,
|
||||
MemPtr: test.registers.MemPtr,
|
||||
state := z80go.CPU{
|
||||
A: byte(test.registers.AF >> 8),
|
||||
B: byte(test.registers.BC >> 8),
|
||||
C: byte(test.registers.BC),
|
||||
D: byte(test.registers.DE >> 8),
|
||||
E: byte(test.registers.DE),
|
||||
H: byte(test.registers.HL >> 8),
|
||||
L: byte(test.registers.HL),
|
||||
AAlt: byte(test.registers.AFa >> 8),
|
||||
BAlt: byte(test.registers.BCa >> 8),
|
||||
CAlt: byte(test.registers.BCa),
|
||||
DAlt: byte(test.registers.DEa >> 8),
|
||||
EAlt: byte(test.registers.DEa),
|
||||
HAlt: byte(test.registers.HLa >> 8),
|
||||
LAlt: byte(test.registers.HLa),
|
||||
IX: test.registers.IX,
|
||||
IY: test.registers.IY,
|
||||
I: test.state.I,
|
||||
R: test.state.R,
|
||||
SP: test.registers.SP,
|
||||
PC: test.registers.PC,
|
||||
Flags: *z80go.NewFlags(byte(test.registers.AF)),
|
||||
FlagsAlt: *z80go.NewFlags(byte(test.registers.AFa)),
|
||||
IMode: test.state.IM,
|
||||
Iff1: test.state.IFF1,
|
||||
Iff2: test.state.IFF2,
|
||||
Halted: test.state.isHalted,
|
||||
CycleCount: 0,
|
||||
IntOccurred: false,
|
||||
NmiOccurred: false,
|
||||
MemPtr: test.registers.MemPtr,
|
||||
}
|
||||
|
||||
// Setup CPU
|
||||
@ -577,12 +574,12 @@ func checkComputerState(t *testing.T, name string) {
|
||||
}
|
||||
|
||||
// FLAGS
|
||||
if lo(exp.registers.AF) != state.Flags.GetFlags() {
|
||||
t.Errorf("%s: Expected Flags to be %08b, got %08b", name, lo(exp.registers.AF), state.Flags.GetFlags())
|
||||
if lo(exp.registers.AF) != state.Flags.AsByte() {
|
||||
t.Errorf("%s: Expected Flags to be %08b, got %08b", name, lo(exp.registers.AF), state.Flags.AsByte())
|
||||
}
|
||||
|
||||
if lo(exp.registers.AFa) != state.FlagsAlt.GetFlags() {
|
||||
t.Errorf("%s: Expected Flags' to be %08b, got %08b", name, lo(exp.registers.AFa), state.FlagsAlt.GetFlags())
|
||||
if lo(exp.registers.AFa) != state.FlagsAlt.AsByte() {
|
||||
t.Errorf("%s: Expected Flags' to be %08b, got %08b", name, lo(exp.registers.AFa), state.FlagsAlt.AsByte())
|
||||
}
|
||||
|
||||
// Check memory
|
||||
|
||||
Loading…
Reference in New Issue
Block a user