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.codeCoverage map[uint16]bool
z.extendedStackEnabled = false z.extendedStackEnabled = false
//z.extendedStack [65536]uint8 //z.extendedStack [65536]uint8
z.extendedStack = map[uint16]PushValueType{}
return &z return &z
} }
@ -68,15 +69,10 @@ func (z *CPU) SetState(state *CPU) {
z.I = state.I z.I = state.I
z.R = state.R z.R = state.R
z.Flags.S = state.Flags.S z.Flags = state.Flags
z.Flags.Z = state.Flags.Z z.FlagsAlt = state.FlagsAlt
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.MemPtr = state.MemPtr
z.IMode = state.IMode z.IMode = state.IMode
z.Iff1 = state.Iff1 z.Iff1 = state.Iff1
z.Iff2 = state.Iff2 z.Iff2 = state.Iff2
@ -108,8 +104,8 @@ func (z *CPU) GetState() *CPU {
SP: z.SP, SP: z.SP,
PC: z.PC, PC: z.PC,
Flags: z.flags(), Flags: z.Flags,
FlagsAlt: z.altFlags(), FlagsAlt: z.FlagsAlt,
IMode: z.IMode, IMode: z.IMode,
Iff1: z.Iff1, Iff1: z.Iff1,
Iff2: z.Iff2, Iff2: z.Iff2,
@ -117,7 +113,7 @@ func (z *CPU) GetState() *CPU {
CycleCount: z.cycleCount, CycleCount: z.cycleCount,
IntOccurred: z.IntOccurred, IntOccurred: z.IntOccurred,
NmiOccurred: z.NmiOccurred, 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) { func (z *CPU) SetExtendedStack(enabled bool) {
z.extendedStackEnabled = enabled z.extendedStackEnabled = enabled
if enabled { if enabled {
for addr := 0; addr < 65536; addr++ { clear(z.extendedStack)
z.extendedStack[addr] = PushValueTypeDefault //for addr := 0; addr < 65536; addr++ {
} // z.extendedStack[uint16(addr)] = PushValueTypeDefault
//}
} }
} }
// ExtendedStack - return array with markers of PushValueType* for each byte of memory // 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 var err error
if !z.extendedStackEnabled { if !z.extendedStackEnabled {
err = errors.New("error, z80: ExtendedStack disabled") err = errors.New("error, z80: ExtendedStack disabled")
} }
return z.extendedStack[:], err return z.extendedStack, err
} }

View File

@ -2,20 +2,21 @@ package dis
import ( import (
"fmt" "fmt"
"okemu/z80"
"strings" "strings"
"github.com/romychs/z80go"
) )
type Disassembler struct { type Disassembler struct {
pc uint16 pc uint16
core z80.MemIoRW core z80go.MemIoRW
} }
type Disassembly interface { type Disassembly interface {
Disassm(pc uint16) string Disassm(pc uint16) string
} }
func NewDisassembler(core z80.MemIoRW) *Disassembler { func NewDisassembler(core z80go.MemIoRW) *Disassembler {
d := Disassembler{ d := Disassembler{
pc: 0, pc: 0,
core: core, 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} 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) { func Test_LD_SP_nn(t *testing.T) {
t.Logf("Disassembler Z80 test")
expected := " 0100 LD SP, 0x052C" expected := " 0100 LD SP, 0x052C"
setMemory(0x100, test) setMemory(0x100, test)
res := disasm.Disassm(0x100) res := disasm.Disassm(0x100)

2
go.mod
View File

@ -6,3 +6,5 @@ require (
github.com/sirupsen/logrus v1.9.4 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= 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/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= 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.SP = 0xFFFF
z.IX = 0 z.IX = 0
z.IY = 0 z.IY = 0
z.memPtr = 0 z.MemPtr = 0
z.A = 0xFF z.A = 0xFF
z.B = 0 z.B = 0
@ -213,7 +213,7 @@ func (z *CPU) Reset() {
z.R = 0 z.R = 0
z.Flags.SetFlags(0xff) z.Flags.SetFlags(0xff)
z.FlagsAlt.SetFlags(0xff) z.FlagsAlt.SetFlags(0x00)
z.iffDelay = 0 z.iffDelay = 0
z.IMode = 0 z.IMode = 0

View File

@ -5,7 +5,7 @@ import log "github.com/sirupsen/logrus"
// jumps to an address // jumps to an address
func (z *CPU) jump(addr uint16) { func (z *CPU) jump(addr uint16) {
z.PC = addr z.PC = addr
z.memPtr = addr z.MemPtr = addr
} }
// jumps to next word in memory if condition is true // jumps to next word in memory if condition is true
@ -14,7 +14,7 @@ func (z *CPU) condJump(condition bool) {
if condition { if condition {
z.jump(addr) z.jump(addr)
} }
z.memPtr = addr z.MemPtr = addr
} }
// calls to next word in memory // calls to next word in memory
@ -22,7 +22,7 @@ func (z *CPU) call(addr uint16) {
z.pushW(z.PC) z.pushW(z.PC)
z.extendedStack[z.SP] = PushValueTypeCall z.extendedStack[z.SP] = PushValueTypeCall
z.PC = addr z.PC = addr
z.memPtr = addr z.MemPtr = addr
} }
// calls to next word in memory if condition is true // calls to next word in memory if condition is true
@ -32,13 +32,13 @@ func (z *CPU) condCall(condition bool) {
z.call(addr) z.call(addr)
z.cycleCount += 7 z.cycleCount += 7
} }
z.memPtr = addr z.MemPtr = addr
} }
// returns from subroutine // returns from subroutine
func (z *CPU) ret() { func (z *CPU) ret() {
z.PC = z.popW() z.PC = z.popW()
z.memPtr = z.PC z.MemPtr = z.PC
} }
// returns from subroutine if condition is true // returns from subroutine if condition is true
@ -55,7 +55,7 @@ func (z *CPU) jr(offset byte) {
} else { } else {
z.PC += uint16(offset) z.PC += uint16(offset)
} }
z.memPtr = z.PC z.MemPtr = z.PC
} }
func (z *CPU) condJr(condition bool) { 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) msb := z.addB(byte(a>>8), byte(b>>8), z.Flags.C)
result := (uint16(msb) << 8) | uint16(lsb) result := (uint16(msb) << 8) | uint16(lsb)
z.Flags.Z = result == 0 z.Flags.Z = result == 0
z.memPtr = a + 1 z.MemPtr = a + 1
return result 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) msb := z.subB(byte(a>>8), byte(b>>8), z.Flags.C)
result := (uint16(msb) << 8) | uint16(lsb) result := (uint16(msb) << 8) | uint16(lsb)
z.Flags.Z = result == 0 z.Flags.Z = result == 0
z.memPtr = a + 1 z.MemPtr = a + 1
return result return result
} }
@ -388,14 +388,14 @@ func (z *CPU) cpi() {
z.Flags.Y = val&0x02 != 0 z.Flags.Y = val&0x02 != 0
z.Flags.P = z.bc() != 0 z.Flags.P = z.bc() != 0
z.Flags.C = cf z.Flags.C = cf
z.memPtr += 1 z.MemPtr += 1
} }
func (z *CPU) cpd() { func (z *CPU) 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.setHL(z.hl() - 2) z.setHL(z.hl() - 2)
z.memPtr -= 2 z.MemPtr -= 2
} }
func (z *CPU) inRC(r *byte) { func (z *CPU) inRC(r *byte) {
@ -410,7 +410,7 @@ func (z *CPU) inRC(r *byte) {
func (z *CPU) ini() { func (z *CPU) ini() {
val := z.core.IORead(z.bc()) val := z.core.IORead(z.bc())
z.wb(z.hl(), val) z.wb(z.hl(), val)
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
z.B-- z.B--
other := val + z.C + 1 other := val + z.C + 1
@ -432,7 +432,7 @@ func (z *CPU) ini() {
func (z *CPU) ind() { func (z *CPU) ind() {
val := z.core.IORead(z.bc()) val := z.core.IORead(z.bc())
z.wb(z.hl(), val) z.wb(z.hl(), val)
z.memPtr = z.bc() - 1 z.MemPtr = z.bc() - 1
z.B-- z.B--
other := val + z.C - 1 other := val + z.C - 1
@ -451,13 +451,7 @@ func (z *CPU) ind() {
z.updateXY(z.B) z.updateXY(z.B)
z.setHL(z.hl() - 1) z.setHL(z.hl() - 1)
} }
func (z *CPU) outCmnFlags(val uint8) {
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)
other := val + z.L other := val + z.L
z.Flags.N = val&0x80 != 0 z.Flags.N = val&0x80 != 0
if other < val { if other < val {
@ -473,25 +467,22 @@ func (z *CPU) outi() {
z.updateXY(z.B) 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() { func (z *CPU) outd() {
val := z.rb(z.hl()) val := z.rb(z.hl())
z.B-- z.B--
z.memPtr = z.bc() - 1 z.MemPtr = z.bc() - 1
z.core.IOWrite(z.bc(), val) z.core.IOWrite(z.bc(), val)
z.setHL(z.hl() - 1) z.setHL(z.hl() - 1)
other := val + z.L z.outCmnFlags(val)
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)
} }
func (z *CPU) daa() { func (z *CPU) daa() {
@ -529,7 +520,7 @@ func (z *CPU) displace(baseAddr uint16, offset byte) uint16 {
addr += uint16(offset) addr += uint16(offset)
} }
//addr := baseAddr + uint16(displacement) //addr := baseAddr + uint16(displacement)
z.memPtr = addr z.MemPtr = addr
return addr return addr
} }
@ -751,29 +742,29 @@ func (z *CPU) execOpcode(opcode byte) {
case 0x0A: case 0x0A:
// ld a,(bc) // ld a,(bc)
z.A = z.rb(z.bc()) z.A = z.rb(z.bc())
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x1A: case 0x1A:
// ld a,(de) // ld a,(de)
z.A = z.rb(z.de()) z.A = z.rb(z.de())
z.memPtr = z.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.memPtr = addr + 1 z.MemPtr = addr + 1
case 0x02: case 0x02:
// ld (bc),a // ld (bc),a
z.wb(z.bc(), z.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: case 0x12:
// ld (de),a // ld (de),a
z.wb(z.de(), z.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: case 0x32:
// ld (**),a // ld (**),a
addr := z.nextW() addr := z.nextW()
z.wb(addr, z.A) 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: case 0x01:
z.setBC(z.nextW()) // ld bc,** z.setBC(z.nextW()) // ld bc,**
case 0x11: case 0x11:
@ -787,12 +778,12 @@ func (z *CPU) execOpcode(opcode byte) {
// ld hl,(**) // ld hl,(**)
addr := z.nextW() addr := z.nextW()
z.setHL(z.rw(addr)) z.setHL(z.rw(addr))
z.memPtr = addr + 1 z.MemPtr = addr + 1
case 0x22: case 0x22:
// ld (**),hl // ld (**),hl
addr := z.nextW() addr := z.nextW()
z.ww(addr, z.hl()) z.ww(addr, z.hl())
z.memPtr = addr + 1 z.MemPtr = addr + 1
case 0xF9: case 0xF9:
z.SP = z.hl() // ld sp,hl z.SP = z.hl() // ld sp,hl
@ -806,7 +797,7 @@ func (z *CPU) execOpcode(opcode byte) {
val := z.rw(z.SP) val := z.rw(z.SP)
z.ww(z.SP, z.hl()) z.ww(z.SP, z.hl())
z.setHL(val) z.setHL(val)
z.memPtr = 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:
@ -1103,7 +1094,7 @@ func (z *CPU) execOpcode(opcode byte) {
z.condJr(z.B != 0) // djnz * z.condJr(z.B != 0) // djnz *
case 0x18: case 0x18:
z.PC += uint16(z.nextB()) // jr * z.PC += uint16(z.nextB()) // jr *
z.memPtr = z.PC z.MemPtr = z.PC
case 0x20: case 0x20:
z.condJr(!z.Flags.Z) // jr nz, * z.condJr(!z.Flags.Z) // jr nz, *
case 0x28: case 0x28:
@ -1202,19 +1193,19 @@ func (z *CPU) execOpcode(opcode byte) {
// 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.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: 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.memPtr = ((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.Flags.Flags() f := z.Flags.AsByte()
z.A = z.AAlt z.A = z.AAlt
z.Flags.SetFlags(z.FlagsAlt.Flags()) z.Flags.SetFlags(z.FlagsAlt.AsByte())
z.AAlt = a z.AAlt = a
z.FlagsAlt.SetFlags(f) 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: // in bit (hl), x/y flags are handled differently:
if z_ == 6 { if z_ == 6 {
z.updateXY(byte(z.memPtr >> 8)) z.updateXY(byte(z.MemPtr >> 8))
z.cycleCount += 4 z.cycleCount += 4
} }

View File

@ -96,11 +96,11 @@ func (z *CPU) execOpcodeDDFD(opcode byte, iz *uint16) {
case 0x2A: case 0x2A:
addr := z.nextW() addr := z.nextW()
*iz = z.rw(addr) // ld iz,(**) *iz = z.rw(addr) // ld iz,(**)
z.memPtr = 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.memPtr = addr + 1 z.MemPtr = addr + 1
case 0x21: case 0x21:
*iz = z.nextW() // ld iz,** *iz = z.nextW() // ld iz,**
case 0x36: case 0x36:
@ -192,7 +192,7 @@ func (z *CPU) execOpcodeDDFD(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.memPtr = 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()

View File

@ -44,7 +44,7 @@ func (z *CPU) execOpcodeED(opcode byte) {
if z.bc() != 0 { if z.bc() != 0 {
z.PC -= 2 z.PC -= 2
z.cycleCount += 5 z.cycleCount += 5
z.memPtr = z.PC + 1 z.MemPtr = z.PC + 1
} }
} // ldir } // ldir
@ -57,7 +57,7 @@ func (z *CPU) execOpcodeED(opcode byte) {
if z.bc() != 0 { if z.bc() != 0 {
z.PC -= 2 z.PC -= 2
z.cycleCount += 5 z.cycleCount += 5
z.memPtr = z.PC + 1 z.MemPtr = z.PC + 1
} }
} // lddr } // lddr
@ -71,7 +71,7 @@ func (z *CPU) execOpcodeED(opcode byte) {
if z.bc() != 0 && !z.Flags.Z { if z.bc() != 0 && !z.Flags.Z {
z.PC -= 2 z.PC -= 2
z.cycleCount += 5 z.cycleCount += 5
z.memPtr = z.PC + 1 z.MemPtr = z.PC + 1
} else { } else {
//z.mem_ptr++ //z.mem_ptr++
} }
@ -82,15 +82,15 @@ func (z *CPU) execOpcodeED(opcode byte) {
if z.bc() != 0 && !z.Flags.Z { if z.bc() != 0 && !z.Flags.Z {
z.PC -= 2 z.PC -= 2
z.cycleCount += 5 z.cycleCount += 5
z.memPtr = z.PC + 1 z.MemPtr = z.PC + 1
} else { } else {
//z.mem_ptr++ //z.mem_ptr++
} }
case 0x40: case 0x40:
z.inRC(&z.B) // in b, (c) z.inRC(&z.B) // in b, (c)
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x48: case 0x48:
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
z.inRC(&z.C) // in c, (c) z.inRC(&z.C) // in c, (c)
z.updateXY(z.C) z.updateXY(z.C)
//case 0x4e: //case 0x4e:
@ -98,28 +98,28 @@ func (z *CPU) execOpcodeED(opcode byte) {
case 0x50: case 0x50:
z.inRC(&z.D) // in d, (c) z.inRC(&z.D) // in d, (c)
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x58: case 0x58:
// in e, (c) // in e, (c)
z.inRC(&z.E) z.inRC(&z.E)
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
z.updateXY(z.E) z.updateXY(z.E)
case 0x60: case 0x60:
z.inRC(&z.H) // in h, (c) z.inRC(&z.H) // in h, (c)
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x68: case 0x68:
z.inRC(&z.L) // in l, (c) z.inRC(&z.L) // in l, (c)
z.memPtr = z.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.inRC(&val) z.inRC(&val)
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x78: case 0x78:
// in a, (c) // in a, (c)
z.inRC(&z.A) z.inRC(&z.A)
z.memPtr = z.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
@ -142,29 +142,29 @@ func (z *CPU) execOpcodeED(opcode byte) {
} }
case 0x41: case 0x41:
z.core.IOWrite(z.bc(), z.B) // out (c), b z.core.IOWrite(z.bc(), z.B) // out (c), b
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x49: case 0x49:
z.core.IOWrite(z.bc(), z.C) // out (c), c z.core.IOWrite(z.bc(), z.C) // out (c), c
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x51: case 0x51:
z.core.IOWrite(z.bc(), z.D) // out (c), d z.core.IOWrite(z.bc(), z.D) // out (c), d
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x59: case 0x59:
z.core.IOWrite(z.bc(), z.E) // out (c), e z.core.IOWrite(z.bc(), z.E) // out (c), e
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x61: case 0x61:
z.core.IOWrite(z.bc(), z.H) // out (c), h z.core.IOWrite(z.bc(), z.H) // out (c), h
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x69: case 0x69:
z.core.IOWrite(z.bc(), z.L) // out (c), l z.core.IOWrite(z.bc(), z.L) // out (c), l
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x71: case 0x71:
z.core.IOWrite(z.bc(), 0) // out (c), 0 z.core.IOWrite(z.bc(), 0) // out (c), 0
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0x79: case 0x79:
// out (c), a // out (c), a
z.core.IOWrite(z.bc(), z.A) z.core.IOWrite(z.bc(), z.A)
z.memPtr = z.bc() + 1 z.MemPtr = z.bc() + 1
case 0xA3: case 0xA3:
z.outi() // outi z.outi() // outi
case 0xB3: case 0xB3:
@ -204,42 +204,42 @@ func (z *CPU) execOpcodeED(opcode byte) {
// ld (**), bc // ld (**), bc
addr := z.nextW() addr := z.nextW()
z.ww(addr, z.bc()) z.ww(addr, z.bc())
z.memPtr = addr + 1 z.MemPtr = addr + 1
case 0x53: case 0x53:
// ld (**), de // ld (**), de
addr := z.nextW() addr := z.nextW()
z.ww(addr, z.de()) z.ww(addr, z.de())
z.memPtr = addr + 1 z.MemPtr = addr + 1
case 0x63: case 0x63:
// ld (**), hl // ld (**), hl
addr := z.nextW() addr := z.nextW()
z.ww(addr, z.hl()) z.ww(addr, z.hl())
z.memPtr = 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.memPtr = addr + 1 z.MemPtr = addr + 1
case 0x4B: case 0x4B:
// ld bc, (**) // ld bc, (**)
addr := z.nextW() addr := z.nextW()
z.setBC(z.rw(addr)) z.setBC(z.rw(addr))
z.memPtr = addr + 1 z.MemPtr = addr + 1
case 0x5B: case 0x5B:
// ld de, (**) // ld de, (**)
addr := z.nextW() addr := z.nextW()
z.setDE(z.rw(addr)) z.setDE(z.rw(addr))
z.memPtr = addr + 1 z.MemPtr = addr + 1
case 0x6B: case 0x6B:
// ld hl, (**) // ld hl, (**)
addr := z.nextW() addr := z.nextW()
z.setHL(z.rw(addr)) z.setHL(z.rw(addr))
z.memPtr = 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.memPtr = 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:
@ -261,7 +261,7 @@ func (z *CPU) execOpcodeED(opcode byte) {
z.Flags.Z = z.A == 0 z.Flags.Z = z.A == 0
z.Flags.S = z.A&0x80 != 0 z.Flags.S = z.A&0x80 != 0
z.Flags.P = parity(z.A) z.Flags.P = parity(z.A)
z.memPtr = z.hl() + 1 z.MemPtr = z.hl() + 1
case 0x6F: case 0x6F:
// rld // rld
a := z.A a := z.A
@ -274,7 +274,7 @@ func (z *CPU) execOpcodeED(opcode byte) {
z.Flags.Z = z.A == 0 z.Flags.Z = z.A == 0
z.Flags.S = z.A&0x80 != 0 z.Flags.S = z.A&0x80 != 0
z.Flags.P = parity(z.A) z.Flags.P = parity(z.A)
z.memPtr = z.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)
} }

View File

@ -59,6 +59,7 @@ type FlagsType struct {
// CPU - Processor state // CPU - Processor state
type CPU struct { type CPU struct {
// base register set
A byte `json:"a,omitempty"` A byte `json:"a,omitempty"`
B byte `json:"b,omitempty"` B byte `json:"b,omitempty"`
C byte `json:"c,omitempty"` C byte `json:"c,omitempty"`
@ -66,6 +67,7 @@ type CPU struct {
E byte `json:"e,omitempty"` E byte `json:"e,omitempty"`
H byte `json:"h,omitempty"` H byte `json:"h,omitempty"`
L byte `json:"l,omitempty"` L byte `json:"l,omitempty"`
// alternate register set
AAlt byte `json:"AAlt,omitempty"` AAlt byte `json:"AAlt,omitempty"`
BAlt byte `json:"BAlt,omitempty"` BAlt byte `json:"BAlt,omitempty"`
CAlt byte `json:"CAlt,omitempty"` CAlt byte `json:"CAlt,omitempty"`
@ -73,14 +75,28 @@ type CPU struct {
EAlt byte `json:"EAlt,omitempty"` EAlt byte `json:"EAlt,omitempty"`
HAlt byte `json:"HAlt,omitempty"` HAlt byte `json:"HAlt,omitempty"`
LAlt byte `json:"LAlt,omitempty"` LAlt byte `json:"LAlt,omitempty"`
// index registers
IX uint16 `json:"IX,omitempty"` IX uint16 `json:"IX,omitempty"`
IY uint16 `json:"IY,omitempty"` IY uint16 `json:"IY,omitempty"`
I byte `json:"i,omitempty"` I byte `json:"i,omitempty"`
// memory refresh register
R byte `json:"r,omitempty"` R byte `json:"r,omitempty"`
// stack pointer
SP uint16 `json:"SP,omitempty"` SP uint16 `json:"SP,omitempty"`
// program counter
PC uint16 `json:"PC,omitempty"` PC uint16 `json:"PC,omitempty"`
// cpu flags
Flags FlagsType `json:"flags"` Flags FlagsType `json:"flags"`
// alternate cpu flags
FlagsAlt FlagsType `json:"flagsAlt"` FlagsAlt FlagsType `json:"flagsAlt"`
// Interrupt mode
IMode byte `json:"IMode,omitempty"` IMode byte `json:"IMode,omitempty"`
Iff1 bool `json:"iff1,omitempty"` Iff1 bool `json:"iff1,omitempty"`
Iff2 bool `json:"iff2,omitempty"` Iff2 bool `json:"iff2,omitempty"`
@ -88,23 +104,33 @@ type CPU struct {
CycleCount uint32 `json:"cycleCount,omitempty"` CycleCount uint32 `json:"cycleCount,omitempty"`
IntOccurred bool `json:"intOccurred,omitempty"` IntOccurred bool `json:"intOccurred,omitempty"`
NmiOccurred bool `json:"interruptOccurred,omitempty"` NmiOccurred bool `json:"interruptOccurred,omitempty"`
memPtr uint16 // mw hidden register
MemPtr uint16
// methods to access CPU to memory and IO ports of computer
core MemIoRW core MemIoRW
intData byte intData byte
cycleCount uint32 // cycle count (t-states) // Total CPU cycle count (t-states)
cycleCount uint32
// map of memory access
memAccess map[uint16]byte memAccess map[uint16]byte
// enable or disable code coverage marking
codeCoverageEnabled bool codeCoverageEnabled bool
// map of code coverage
codeCoverage map[uint16]bool codeCoverage map[uint16]bool
// enable of disable stack data marking
extendedStackEnabled bool extendedStackEnabled bool
// map of stack data marking
extendedStack map[uint16]PushValueType extendedStack map[uint16]PushValueType
iffDelay byte iffDelay byte
intPending bool intPending bool
nmiPending bool nmiPending bool
} }
// Flags - return flags as byte value // AsByte - return flags as byte value
// Used to simplify manipulations with AF register from debugger // Used to simplify manipulations with AF register from debugger
func (f *FlagsType) Flags() byte { func (f *FlagsType) AsByte() byte {
var flags byte = 0 var flags byte = 0
if f.S { if f.S {
flags |= 0x80 flags |= 0x80
@ -174,19 +200,19 @@ func (z *CPU) IIFStr() string {
return string(flags) return string(flags)
} }
//// Flags - return state of CPU flags // NewFlags build new object of FlagsType from byte
//func Flags(f byte) FlagsType { func NewFlags(f byte) *FlagsType {
// return FlagsType{ return &FlagsType{
// S: f&0x80 != 0, S: f&0x80 != 0,
// Z: f&0x40 != 0, Z: f&0x40 != 0,
// Y: f&0x20 != 0, Y: f&0x20 != 0,
// H: f&0x10 != 0, H: f&0x10 != 0,
// X: f&0x08 != 0, X: f&0x08 != 0,
// P: f&0x04 != 0, P: f&0x04 != 0,
// N: f&0x02 != 0, N: f&0x02 != 0,
// C: f&0x01 != 0, C: f&0x01 != 0,
// } }
//} }
// SetFlags - set CPU flags by flags byte. // SetFlags - set CPU flags by flags byte.
// Used to simplify manipulations with AF register from debugger // Used to simplify manipulations with AF register from debugger

View File

@ -4,12 +4,11 @@ import (
"bufio" "bufio"
"bytes" "bytes"
_ "embed" _ "embed"
"okemu/z80"
"okemu/z80/c99"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
"github.com/romychs/z80go"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -82,7 +81,7 @@ var testIn []byte
var testExpected []byte var testExpected []byte
type Computer struct { type Computer struct {
cpu *c99.Z80 cpu *z80go.CPU
memory [65536]byte memory [65536]byte
ports [256]byte ports [256]byte
} }
@ -94,8 +93,6 @@ var computer Computer
var testNames []string var testNames []string
//var z80 *c99.Z80
func init() { func init() {
z80TestsIn = make(map[string]Z80TestIn) z80TestsIn = make(map[string]Z80TestIn)
z80TestsExpected = make(map[string]Expect) z80TestsExpected = make(map[string]Expect)
@ -107,7 +104,7 @@ func init() {
for addr := 0; addr < 255; addr++ { for addr := 0; addr < 255; addr++ {
computer.ports[addr] = 0 computer.ports[addr] = 0
} }
computer.cpu = c99.New(&computer) computer.cpu = z80go.NewCPU(&computer)
} }
func (c *Computer) M1MemRead(addr uint16) byte { func (c *Computer) M1MemRead(addr uint16) byte {
@ -403,7 +400,8 @@ func TestZ80Fuse(t *testing.T) {
} }
cy := uint32(0) cy := uint32(0)
for { for {
cy += computer.cpu.RunInstruction() c, _ := computer.cpu.RunInstruction()
cy += c
if cy >= uint32(exp.state.tStates) { if cy >= uint32(exp.state.tStates) {
break break
} }
@ -413,7 +411,7 @@ func TestZ80Fuse(t *testing.T) {
} }
func setComputerState(test Z80TestIn) { func setComputerState(test Z80TestIn) {
state := z80.CPU{ state := z80go.CPU{
A: byte(test.registers.AF >> 8), A: byte(test.registers.AF >> 8),
B: byte(test.registers.BC >> 8), B: byte(test.registers.BC >> 8),
C: byte(test.registers.BC), C: byte(test.registers.BC),
@ -434,16 +432,15 @@ func setComputerState(test Z80TestIn) {
R: test.state.R, R: test.state.R,
SP: test.registers.SP, SP: test.registers.SP,
PC: test.registers.PC, PC: test.registers.PC,
Flags: z80.GetFlags(byte(test.registers.AF)), Flags: *z80go.NewFlags(byte(test.registers.AF)),
FlagsAlt: z80.GetFlags(byte(test.registers.AFa)), FlagsAlt: *z80go.NewFlags(byte(test.registers.AFa)),
IMode: test.state.IM, IMode: test.state.IM,
Iff1: test.state.IFF1, Iff1: test.state.IFF1,
Iff2: test.state.IFF2, Iff2: test.state.IFF2,
Halted: test.state.isHalted, Halted: test.state.isHalted,
DoDelayedDI: false,
DoDelayedEI: false,
CycleCount: 0, CycleCount: 0,
InterruptOccurred: false, IntOccurred: false,
NmiOccurred: false,
MemPtr: test.registers.MemPtr, MemPtr: test.registers.MemPtr,
} }
@ -577,12 +574,12 @@ func checkComputerState(t *testing.T, name string) {
} }
// FLAGS // FLAGS
if 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.GetFlags()) 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() { 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.GetFlags()) t.Errorf("%s: Expected Flags' to be %08b, got %08b", name, lo(exp.registers.AFa), state.FlagsAlt.AsByte())
} }
// Check memory // Check memory