CPU emulator pass all tests

This commit is contained in:
Роман Бойков 2026-04-01 19:43:10 +03:00
parent 44c36ecb94
commit d05db31cd2
12 changed files with 220 additions and 202 deletions

29
cpu.go
View File

@ -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
}

View File

@ -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,

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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()

View File

@ -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
View File

@ -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

View File

@ -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