z80go/z80go.go

234 lines
5.2 KiB
Go

// Package z80go provides basic Z80 CPU emulation
package z80go
const (
PushValueTypeDefault = iota // Unknown status of word on stack
PushValueTypeCall // Return from call address on stack
PushValueTypeRst // Return from RST address on stack
PushValueTypePush // 16-bit value, PUSH-ed to stack
//PushValueTypeMaskableInt
//PushValueTypeNonMaskableInt
)
type PushValueType byte
// MemIoRW interface for CPU to access memory and io ports of emulated computer
type MemIoRW interface {
//// M1MemRead Read byte from memory for specified address @ M1 cycle
//M1MemRead(addr uint16) byte
// MemRead Read byte from memory for specified address
MemRead(addr uint16) byte
// MemWrite Write byte to memory to specified address
MemWrite(addr uint16, val byte)
// IORead Read byte from specified port
IORead(port uint16) byte
// IOWrite Write byte to specified port
IOWrite(port uint16, val byte)
}
// CPUInterface Interface to CPU emulator
type CPUInterface interface {
// Reset CPU to initial state
Reset()
// RunInstruction Run single instruction, return number of CPU cycles
RunInstruction() uint32
// GetState Get current CPU state
GetState() *CPU
// SetState Set current CPU state
SetState(state *CPU)
// DebugOutput out current CPU state
DebugOutput()
}
// FlagsType - Processor flags
type FlagsType struct {
S bool `json:"s,omitempty"` // Sign flag
Z bool `json:"z,omitempty"` // Zero flag
Y bool `json:"y,omitempty"` // Y undocumented flag
H bool `json:"h,omitempty"` // Half carry flag
X bool `json:"x,omitempty"` // X undocumented flag
P bool `json:"p,omitempty"` // Parity/Overflow flag
N bool `json:"n,omitempty"` // Add/Substract flag
C bool `json:"c,omitempty"` // Carry flag
}
// CPU - Processor state
type CPU struct {
// 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
// map of stack data marking
extendedStack map[uint16]PushValueType
iffDelay byte
intPending bool
nmiPending bool
}
// AsByte - return flags as byte value
// Used to simplify manipulations with AF register from debugger
func (f *FlagsType) AsByte() byte {
var flags byte = 0
if f.S {
flags |= 0x80
}
if f.Z {
flags |= 0x40
}
if f.Y {
flags |= 0x20
}
if f.H {
flags |= 0x10
}
if f.X {
flags |= 0x08
}
if f.P {
flags |= 0x04
}
if f.N {
flags |= 0x02
}
if f.C {
flags |= 0x01
}
return flags
}
// String - return string representation of CPU flags
func (f *FlagsType) String() string {
flags := []byte{'-', '-', '-', '-', '-', '-', '-', '-'}
if f.S {
flags[0] = 'S'
}
if f.Z {
flags[1] = 'Z'
}
if f.Y {
flags[2] = '5'
}
if f.H {
flags[3] = 'H'
}
if f.X {
flags[4] = '3'
}
if f.P {
flags[5] = 'P'
}
if f.N {
flags[6] = 'N'
}
if f.C {
flags[7] = 'C'
}
return string(flags)
}
func (z *CPU) IIFStr() string {
flags := []byte{'-', '-'}
if z.Iff1 {
flags[0] = '1'
}
if z.Iff2 {
flags[1] = '2'
}
return string(flags)
}
// 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
func (f *FlagsType) SetFlags(flags byte) {
f.S = flags&0x80 != 0
f.Z = flags&0x40 != 0
f.Y = flags&0x20 != 0
f.H = flags&0x10 != 0
f.X = flags&0x08 != 0
f.P = flags&0x04 != 0
f.N = flags&0x02 != 0
f.C = flags&0x01 != 0
}
// GetPC - return PC register value only, for fast breakpoints test from debugger
func (z *CPU) GetPC() uint16 {
return z.PC
}