split screen/cpu to 2 go subs

fix alu op flags in Z80 em
This commit is contained in:
Роман Бойков 2026-03-07 12:31:01 +03:00
parent 50f4e2521f
commit fe19e5c8c7
8 changed files with 215 additions and 199 deletions

73
main.go
View File

@ -23,7 +23,7 @@ var BuildTime = "2026-03-01"
//go:embed hex/format.hex //go:embed hex/format.hex
var serialBytes []byte var serialBytes []byte
//go:embed bin/MB.COM //go:embed bin/zexall.com
var ramBytes []byte var ramBytes []byte
var needReset = false var needReset = false
@ -45,11 +45,12 @@ func main() {
computer := okean240.New(conf) computer := okean240.New(conf)
computer.SetSerialBytes(serialBytes) computer.SetSerialBytes(serialBytes)
computer.LoadFloppy()
w, raster, label := mainWindow(computer, conf) w, raster, label := mainWindow(computer, conf)
go emulator(computer, raster, label, conf) go emulator(computer)
go screen(computer, raster, label, conf)
(*w).ShowAndRun() (*w).ShowAndRun()
} }
@ -88,6 +89,12 @@ func mainWindow(computer *okean240.ComputerType, emuConfig *config.OkEmuConfig)
w.Resize(fyne.NewSize(600, 600)) w.Resize(fyne.NewSize(600, 600))
hBox := container.NewHBox( hBox := container.NewHBox(
//widget.NewButton("++", func() {
// computer.IncOffset()
//}),
//widget.NewButton("--", func() {
// computer.DecOffset()
//}),
widget.NewButton("Ctrl+C", func() { widget.NewButton("Ctrl+C", func() {
computer.PutCtrlKey(0x03) computer.PutCtrlKey(0x03)
}), }),
@ -124,24 +131,37 @@ func mainWindow(computer *okean240.ComputerType, emuConfig *config.OkEmuConfig)
return &w, raster, label return &w, raster, label
} }
func emulator(computer *okean240.ComputerType, raster *canvas.Raster, label *widget.Label, emuConfig *config.OkEmuConfig) { func screen(computer *okean240.ComputerType, raster *canvas.Raster, label *widget.Label, emuConfig *config.OkEmuConfig) {
ticker := time.NewTicker(133 * time.Nanosecond) ticker := time.NewTicker(20 * time.Millisecond)
var ticks = 0
var ticksCPU = 3
//var ticksSCR = TicksPerFrame
//var frameStartTime = time.Now().UnixMicro()
frameNextTime := time.Now().UnixMicro() + 20000
frame := 0 frame := 0
var pre uint64 = 0 var pre uint64 = 0
var freq uint64 = 0 var freq uint64 = 0
nextSecond := time.Now().Add(time.Second).UnixMicro()
//curScrWidth := 256
for range ticker.C { for range ticker.C {
if needReset { if needReset {
computer.Reset(emuConfig) computer.Reset(emuConfig)
needReset = false needReset = false
} }
frame++
// redraw screen here
fyne.Do(func() {
// status for every 50 frames
if frame%50 == 0 {
freq = computer.Cycles() - pre
pre = computer.Cycles()
label.SetText(fmt.Sprintf("Screen size: %dx%d F: %d", computer.ScreenWidth(), computer.ScreenHeight(), freq))
}
raster.Refresh()
})
}
}
func emulator(computer *okean240.ComputerType) {
ticker := time.NewTicker(133 * time.Nanosecond)
var ticks = 0
var ticksCPU = 0
for range ticker.C {
time.Sleep(133 * time.Nanosecond)
ticks++ ticks++
if ticks%5 == 0 { if ticks%5 == 0 {
// 1.5 MHz // 1.5 MHz
@ -150,37 +170,10 @@ func emulator(computer *okean240.ComputerType, raster *canvas.Raster, label *wid
if ticks > ticksCPU { if ticks > ticksCPU {
ticksCPU = ticks + computer.Do()*2 ticksCPU = ticks + computer.Do()*2
} }
if time.Now().UnixMicro() > nextSecond {
nextSecond = time.Now().Add(time.Second).UnixMicro()
freq = computer.Cycles() - pre
pre = computer.Cycles()
}
//if ticks >= ticksSCR {
if time.Now().UnixMicro() > frameNextTime {
frameNextTime = time.Now().UnixMicro() + 20000
//ticksSCR = ticks + TicksPerFrame
frame++
// redraw screen here
fyne.Do(func() {
// check for screen mode changed
//if computer.ScreenWidth() != curScrWidth {
// curScrWidth = computer.ScreenWidth()
// newSize := fyne.NewSize(float32(curScrWidth*2), float32(computer.ScreenHeight()*2))
// raster.SetMinSize(newSize)
// raster.Resize(newSize)
//}
// status for every 25 frames
if frame%50 == 0 {
label.SetText(fmt.Sprintf("Screen size: %dx%d F: %d", computer.ScreenWidth(), computer.ScreenHeight(), freq))
}
raster.Refresh()
})
}
} }
} }
// Add shortcuts for all Ctrl+<Letter>
func addShortcuts(c fyne.Canvas, computer *okean240.ComputerType) { func addShortcuts(c fyne.Canvas, computer *okean240.ComputerType) {
// Add shortcuts for Ctrl+A to Ctrl+Z // Add shortcuts for Ctrl+A to Ctrl+Z
for kName := 'A'; kName <= 'Z'; kName++ { for kName := 'A'; kName <= 'Z'; kName++ {

View File

@ -35,6 +35,7 @@ type ComputerType struct {
kbdBuffer []byte kbdBuffer []byte
vShift byte vShift byte
hShift byte hShift byte
//aOffset uint16
} }
const VRAMBlock0 = 3 const VRAMBlock0 = 3
@ -86,6 +87,7 @@ func New(cfg *config.OkEmuConfig) *ComputerType {
c.vShift = 0 c.vShift = 0
c.hShift = 0 c.hShift = 0
//c.aOffset = 0x100
c.pit = pit.New() c.pit = pit.New()
c.usart = usart.New() c.usart = usart.New()
@ -119,9 +121,9 @@ func (c *ComputerType) Do() int {
//} //}
ticks := uint64(c.cpu.RunInstruction()) ticks := uint64(c.cpu.RunInstruction())
c.cycles += ticks c.cycles += ticks
if c.cpu.PC == 0xFF26 { //if c.cpu.PC == 0xFF26 {
log.Debugf("%4X: H:%X L:%X A:%X B: %X C: %X D: %X E: %X", c.cpu.PC, c.cpu.H, c.cpu.L, c.cpu.A, c.cpu.B, c.cpu.C, c.cpu.D, c.cpu.E) // log.Debugf("%4X: H:%X L:%X A:%X B: %X C: %X D: %X E: %X", c.cpu.PC, c.cpu.H, c.cpu.L, c.cpu.A, c.cpu.B, c.cpu.C, c.cpu.D, c.cpu.E)
} //}
return int(ticks) return int(ticks)
} }
@ -138,17 +140,20 @@ func (c *ComputerType) GetPixel(x uint16, y uint16) color.RGBA {
return CWhite return CWhite
} }
var offset uint16
if (c.vShift != 0) && (y > 255-uint16(c.vShift)) {
offset = 0x100
} else {
offset = 0
}
y += uint16(c.vShift) & 0x00ff y += uint16(c.vShift) & 0x00ff
x += uint16(c.hShift-7) & 0x00ff x += uint16(c.hShift-7) & 0x00ff
// Color 256x256 mode // Color 256x256 mode
addr = ((x & 0xf8) << 6) | y addr = ((x & 0xf8) << 6) | y
//if c.vShift != 0 {
// addr -= 8
//}
cl := (c.vRAM.memory[addr&0x3fff] >> (x & 0x07)) & 1 cl := (c.vRAM.memory[(addr-offset)&0x3fff] >> (x & 0x07)) & 1
cl |= ((c.vRAM.memory[(addr+0x100)&0x3fff] >> (x & 0x07)) & 1) << 1 cl |= ((c.vRAM.memory[(addr+0x100-offset)&0x3fff] >> (x & 0x07)) & 1) << 1
if cl == 0 { if cl == 0 {
resColor = BgColorPalette[c.bgColor] resColor = BgColorPalette[c.bgColor]
} else { } else {
@ -159,13 +164,20 @@ func (c *ComputerType) GetPixel(x uint16, y uint16) color.RGBA {
return CWhite return CWhite
} }
var offset uint16
if (c.vShift != 0) && (y > 255-uint16(c.vShift)) {
offset = 0x100
} else {
offset = 0
}
// Shifts // Shifts
y += uint16(c.vShift) & 0x00ff y += uint16(c.vShift) & 0x00ff
x += uint16(c.hShift-7) & 0x001ff x += uint16(c.hShift-7) & 0x001ff
// Mono 512x256 mode // Mono 512x256 mode
addr = ((x & 0x1f8) << 5) | y addr = (((x & 0x1f8) << 5) + y) - offset
pix := c.vRAM.memory[addr] >> (x & 0x07) & 1 pix := c.vRAM.memory[addr&0x3fff] >> (x & 0x07) & 1
if c.palette == 6 { if c.palette == 6 {
if pix == 0 { if pix == 0 {
resColor = CBlack resColor = CBlack
@ -176,7 +188,7 @@ func (c *ComputerType) GetPixel(x uint16, y uint16) color.RGBA {
if pix == 0 { if pix == 0 {
resColor = BgColorPalette[c.bgColor] resColor = BgColorPalette[c.bgColor]
} else { } else {
resColor = MonoPalette[c.bgColor] resColor = MonoPalette[c.palette]
} }
} }
} }

View File

@ -19,9 +19,9 @@ import (
// Floppy parameters // Floppy parameters
const ( const (
FloppySizeK = 720 FloppySizeK = 720
SectorSize = 128 SectorSize = 512
SideCount = 2 SideCount = 2
SectorPerTrack = 36 SectorPerTrack = 9
SizeInSectors = FloppySizeK * 1024 / SectorSize SizeInSectors = FloppySizeK * 1024 / SectorSize
TracksCount = SizeInSectors / SideCount / SectorPerTrack TracksCount = SizeInSectors / SideCount / SectorPerTrack
@ -30,7 +30,7 @@ const (
TrackHeaderSize = 146 TrackHeaderSize = 146
TrackSectorSize = 626 TrackSectorSize = 626
TrackFooterSize = 256 * 3 TrackFooterSize = 256 * 3
TrackBufferSize = TrackHeaderSize + TrackSectorSize*9 + TrackFooterSize TrackBufferSize = TrackHeaderSize + TrackSectorSize*SectorPerTrack + TrackFooterSize
) )
// FDC Commands // FDC Commands
@ -325,7 +325,7 @@ func New() *FloppyDriveController {
sec := [SizeInSectors]SectorType{} sec := [SizeInSectors]SectorType{}
for i := 0; i < SizeInSectors; i++ { for i := 0; i < SizeInSectors; i++ {
sec[i] = make([]byte, SectorSize) sec[i] = make([]byte, SectorSize)
for s := 0; s < 128; s++ { for s := 0; s < SectorSize; s++ {
sec[i][s] = 0xE5 sec[i][s] = 0xE5
} }
} }

View File

@ -72,7 +72,7 @@ func (c *ComputerType) IOWrite(port uint16, val byte) {
c.screenWidth = 512 c.screenWidth = 512
} }
c.palette = val & 0x07 c.palette = val & 0x07
c.bgColor = val & 0x38 >> 3 c.bgColor = (val >> 3) & 0x07
case SYS_DD17PA: case SYS_DD17PA:
c.vShift = val c.vShift = val
case SYS_DD17PC: case SYS_DD17PC:

View File

@ -8,7 +8,7 @@ var CGreen = color.RGBA{R: 0x12, G: 0x76, B: 0x22, A: 0xff}
var CBlue = color.RGBA{R: 0x2A, G: 0x60, B: 0x99, A: 0xff} var CBlue = color.RGBA{R: 0x2A, G: 0x60, B: 0x99, A: 0xff}
var CLBlue = color.RGBA{R: 0x72, G: 0x9F, B: 0xCF, A: 0xff} var CLBlue = color.RGBA{R: 0x72, G: 0x9F, B: 0xCF, A: 0xff}
var CCrimson = color.RGBA{R: 0xbf, G: 0x00, B: 0xbf, A: 0xff} var CCrimson = color.RGBA{R: 0xbf, G: 0x00, B: 0xbf, A: 0xff}
var CWhite = color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff} var CWhite = color.RGBA{R: 0xee, G: 0xee, B: 0xee, A: 0xff}
var CYellow = color.RGBA{R: 0xff, G: 0xff, B: 0x00, A: 0xff} var CYellow = color.RGBA{R: 0xff, G: 0xff, B: 0x00, A: 0xff}
var CBlack = color.RGBA{R: 0, G: 0, B: 0, A: 0xff} var CBlack = color.RGBA{R: 0, G: 0, B: 0, A: 0xff}
@ -41,11 +41,11 @@ var BgColorPalette = [8]color.RGBA{
CBlack, CBlue, CGreen, CLBlue, CRed, CCrimson /*CYellow*/, CBlack, CWhite, CBlack, CBlue, CGreen, CLBlue, CRed, CCrimson /*CYellow*/, CBlack, CWhite,
} }
//var MonoPalette = [8]color.RGBA{
// CWhite, CRed, CGreen, CBlue, CLBlue, CYellow, CLGreen, CBlack,
//}
// MonoPalette R8 Style monochrome mode palette
var MonoPalette = [8]color.RGBA{ var MonoPalette = [8]color.RGBA{
CRed, CBlue, CCrimson, CGreen, CYellow, CLBlue, CWhite, CBlack, CWhite, CRed, CGreen, CBlue, CLBlue, CYellow, CLGreen, CBlack,
} }
//// MonoPalette R8 Style monochrome mode palette
//var MonoPalette = [8]color.RGBA{
// CRed, CBlue, CCrimson, CGreen, CYellow, CLBlue, CWhite, CBlack,
//}

View File

@ -49,7 +49,7 @@ var instructions = []func(s *Z80Type){
}, },
// 0x08 : EX AF, AF' // 0x08 : EX AF, AF'
0x08: func(s *Z80Type) { 0x08: func(s *Z80Type) {
s.A, s.APrime = s.APrime, s.A s.A, s.AAlt = s.AAlt, s.A
temp := s.getFlagsRegister() temp := s.getFlagsRegister()
s.setFlagsRegister(s.getFlagsPrimeRegister()) s.setFlagsRegister(s.getFlagsPrimeRegister())
s.setFlagsPrimeRegister(temp) s.setFlagsPrimeRegister(temp)
@ -468,12 +468,12 @@ var instructions = []func(s *Z80Type){
}, },
// 0xd9 : EXX // 0xd9 : EXX
0xD9: func(s *Z80Type) { 0xD9: func(s *Z80Type) {
s.B, s.BPrime = s.BPrime, s.B s.B, s.BAlt = s.BAlt, s.B
s.C, s.CPrime = s.CPrime, s.C s.C, s.CAlt = s.CAlt, s.C
s.D, s.DPrime = s.DPrime, s.D s.D, s.DAlt = s.DAlt, s.D
s.E, s.EPrime = s.EPrime, s.E s.E, s.EAlt = s.EAlt, s.E
s.H, s.HPrime = s.HPrime, s.H s.H, s.HAlt = s.HAlt, s.H
s.L, s.LPrime = s.LPrime, s.L s.L, s.LAlt = s.LAlt, s.L
}, },
// 0xda : JP C, nn // 0xda : JP C, nn
0xDA: func(s *Z80Type) { 0xDA: func(s *Z80Type) {

View File

@ -415,30 +415,29 @@ func (z *Z80Type) opcodeDD() {
} }
func (z *Z80Type) opcodeDDCB() { func (z *Z80Type) opcodeDDCB() {
offset := z.getOffset(z.IX) offset := z.getOffset(z.IX)
z.PC++ z.PC++
opcode := z.core.M1MemRead(z.PC) opcode := z.core.MemRead(z.PC)
value := byte(0) value := byte(0)
bitTestOp := false bitTestOp := false
// As with the "normal" CB prefix, we implement the DDCB prefix // As with the "normal" CB prefix, we implement the DDCB prefix
// by decoding the opcode directly, rather than using a table. // by decoding the opcode directly, rather than using a table.
if opcode < 0x40 { if opcode < 0x40 {
// Shift and rotate instructions. // Shift and rotate instructions.
ddcbFunctions := []OpShift{z.doRlc, z.doRrc, z.doRl, z.doRr, z.doSla, z.doSra, z.doSll, z.doSrl} 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, // Most of the opcodes in this range are not valid,
// so we map this opcode onto one of the ones that is. // so we map this opcode onto one of the ones that is.
fun := ddcbFunctions[(opcode&0x38)>>3] fun := ddcbFunctions[(opcode&0x38)>>3]
value = fun(z.core.MemRead(offset)) value = fun(z.core.MemRead(offset))
z.core.MemWrite(offset, value) z.core.MemWrite(offset, value)
} else { } else {
bitNumber := (opcode & 0x38) >> 3 bitNumber := (opcode & 0x38) >> 3
if opcode < 0x80 { if opcode < 0x80 {
// BIT // bit test
bitTestOp = true bitTestOp = true
z.Flags.N = false z.Flags.N = false
z.Flags.H = true z.Flags.H = true
@ -447,19 +446,20 @@ func (z *Z80Type) opcodeDDCB() {
z.Flags.S = (bitNumber == 7) && !z.Flags.Z z.Flags.S = (bitNumber == 7) && !z.Flags.Z
} else if opcode < 0xc0 { } else if opcode < 0xc0 {
// RES // RES
value = z.core.MemRead(offset) & ^(1 << bitNumber) value = z.core.MemRead(offset) & (^(1 << bitNumber))
z.core.MemWrite(offset, value) z.core.MemWrite(offset, value)
} else { } else {
// SET // SET
value = z.core.MemRead(offset | (1 << bitNumber)) value = z.core.MemRead(offset) | (1 << bitNumber)
z.core.MemWrite(offset, value) z.core.MemWrite(offset, value)
} }
} }
// This implements the undocumented shift, RES, and SET opcodes, // This implements the undocumented shift, RES, and SET opcodes,
// which write their result to memory and also to an 8080 register. // which write their result to memory and also to an 8080 register.
if !bitTestOp { if !bitTestOp {
value := byte(1) //value := byte(1)
switch opcode & 0x07 { switch opcode & 0x07 {
case 0: case 0:
z.B = value z.B = value

View File

@ -25,13 +25,13 @@ type Z80Type struct {
E byte E byte
H byte H byte
L byte L byte
APrime byte AAlt byte
BPrime byte BAlt byte
CPrime byte CAlt byte
DPrime byte DAlt byte
EPrime byte EAlt byte
HPrime byte HAlt byte
LPrime byte LAlt byte
IX uint16 IX uint16
IY uint16 IY uint16
I byte I byte
@ -39,8 +39,7 @@ type Z80Type struct {
SP uint16 SP uint16
PC uint16 PC uint16
Flags FlagsType Flags FlagsType
FlagsPrime FlagsType FlagsAlt FlagsType
IMode byte IMode byte
Iff1 byte Iff1 byte
Iff2 byte Iff2 byte
@ -106,19 +105,19 @@ func (z *Z80Type) GetState() *Z80Type {
E: z.E, E: z.E,
H: z.H, H: z.H,
L: z.L, L: z.L,
APrime: z.APrime, AAlt: z.AAlt,
BPrime: z.BPrime, BAlt: z.BAlt,
CPrime: z.CPrime, CAlt: z.CAlt,
DPrime: z.DPrime, DAlt: z.DAlt,
EPrime: z.EPrime, EAlt: z.EAlt,
HPrime: z.HPrime, HAlt: z.HAlt,
IX: z.IX, IX: z.IX,
IY: z.IY, IY: z.IY,
R: z.R, R: z.R,
SP: z.SP, SP: z.SP,
PC: z.PC, PC: z.PC,
Flags: z.Flags, Flags: z.Flags,
FlagsPrime: z.FlagsPrime, FlagsAlt: z.FlagsAlt,
IMode: z.IMode, IMode: z.IMode,
Iff1: z.Iff1, Iff1: z.Iff1,
Iff2: z.Iff2, Iff2: z.Iff2,
@ -137,12 +136,12 @@ func (z *Z80Type) SetState(state *Z80Type) {
z.E = state.E z.E = state.E
z.H = state.H z.H = state.H
z.L = state.L z.L = state.L
z.APrime = state.APrime z.AAlt = state.AAlt
z.BPrime = state.BPrime z.BAlt = state.BAlt
z.CPrime = state.CPrime z.CAlt = state.CAlt
z.DPrime = state.DPrime z.DAlt = state.DAlt
z.EPrime = state.EPrime z.EAlt = state.EAlt
z.HPrime = state.HPrime z.HAlt = state.HAlt
z.IX = state.IX z.IX = state.IX
z.IY = state.IY z.IY = state.IY
z.I = state.I z.I = state.I
@ -150,7 +149,7 @@ func (z *Z80Type) SetState(state *Z80Type) {
z.SP = state.SP z.SP = state.SP
z.PC = state.PC z.PC = state.PC
z.Flags = state.Flags z.Flags = state.Flags
z.FlagsPrime = state.FlagsPrime z.FlagsAlt = state.FlagsAlt
z.IMode = state.IMode z.IMode = state.IMode
z.Iff1 = state.Iff1 z.Iff1 = state.Iff1
z.Iff2 = state.Iff2 z.Iff2 = state.Iff2
@ -170,12 +169,12 @@ func New(memIoRW MemIoRW) *Z80Type {
E: 0, E: 0,
H: 0, H: 0,
L: 0, L: 0,
APrime: 0, AAlt: 0,
BPrime: 0, BAlt: 0,
CPrime: 0, CAlt: 0,
DPrime: 0, DAlt: 0,
EPrime: 0, EAlt: 0,
HPrime: 0, HAlt: 0,
IX: 0, IX: 0,
IY: 0, IY: 0,
I: 0, I: 0,
@ -184,7 +183,7 @@ func New(memIoRW MemIoRW) *Z80Type {
SP: SpDefault, SP: SpDefault,
PC: 0, PC: 0,
Flags: FlagsType{false, false, false, false, false, false, false, false}, Flags: FlagsType{false, false, false, false, false, false, false, false},
FlagsPrime: FlagsType{false, false, false, false, false, false, false, false}, FlagsAlt: FlagsType{false, false, false, false, false, false, false, false},
IMode: 0, IMode: 0,
Iff1: 0, Iff1: 0,
Iff2: 0, Iff2: 0,
@ -355,20 +354,14 @@ func (z *Z80Type) decodeInstruction(opcode byte) {
if opcode == OpHalt { if opcode == OpHalt {
z.Halted = true z.Halted = true
} else if opcode >= OpLdBB && opcode < OpAddAB { } else if opcode >= OpLdBB && opcode < OpAddAB {
// This entire range is all 8-bit register loads. // 8-bit register loads.
// Get the operand and assign it to the correct destination.
z.load8bit(opcode, z.getOperand(opcode)) z.load8bit(opcode, z.getOperand(opcode))
} else if (opcode >= OpAddAB) && (opcode < OpRetNz) { } else if (opcode >= OpAddAB) && (opcode < OpRetNz) {
// These are the 8-bit register ALU instructions. // 8-bit register ALU instructions.
// We'll get the operand and then use this "jump table"
// to call the correct utility function for the instruction.
z.alu8bit(opcode, z.getOperand(opcode)) z.alu8bit(opcode, z.getOperand(opcode))
} else { } else {
// This is one of the less formulaic instructions;
// we'll get the specific function for it from our array.
fun := instructions[opcode] fun := instructions[opcode]
fun(z) fun(z)
//z.otherInstructions(opcode)
} }
z.CycleCounter += CycleCounts[opcode] z.CycleCounter += CycleCounts[opcode]
} }
@ -394,6 +387,7 @@ func (z *Z80Type) load8bit(opcode byte, operand byte) {
} }
} }
// alu8bit Handle ALU Operations, ADD, ADC SUB, SBC, AND, XOR, OR
func (z *Z80Type) alu8bit(opcode byte, operand byte) { func (z *Z80Type) alu8bit(opcode byte, operand byte) {
switch (opcode & 0x38) >> 3 { switch (opcode & 0x38) >> 3 {
case 0: case 0:
@ -426,7 +420,7 @@ func (z *Z80Type) getFlagsRegister() byte {
// getFlagsRegister return whole F' register // getFlagsRegister return whole F' register
func (z *Z80Type) getFlagsPrimeRegister() byte { func (z *Z80Type) getFlagsPrimeRegister() byte {
return getFlags(&z.FlagsPrime) return getFlags(&z.FlagsAlt)
} }
func getFlags(f *FlagsType) byte { func getFlags(f *FlagsType) byte {
@ -437,27 +431,21 @@ func getFlags(f *FlagsType) byte {
if f.Z { if f.Z {
flags |= 0x40 flags |= 0x40
} }
if f.Y { if f.Y {
flags |= 0x20 flags |= 0x20
} }
if f.H { if f.H {
flags |= 0x10 flags |= 0x10
} }
if f.X { if f.X {
flags |= 0x08 flags |= 0x08
} }
if f.P { if f.P {
flags |= 0x04 flags |= 0x04
} }
if f.N { if f.N {
flags |= 0x02 flags |= 0x02
} }
if f.C { if f.C {
flags |= 0x01 flags |= 0x01
} }
@ -470,7 +458,7 @@ func (z *Z80Type) setFlagsRegister(flags byte) {
} }
func (z *Z80Type) setFlagsPrimeRegister(flags byte) { func (z *Z80Type) setFlagsPrimeRegister(flags byte) {
setFlags(flags, &z.FlagsPrime) setFlags(flags, &z.FlagsAlt)
} }
func setFlags(flags byte, f *FlagsType) { func setFlags(flags byte, f *FlagsType) {
@ -484,15 +472,10 @@ func setFlags(flags byte, f *FlagsType) {
f.C = flags&0x01 != 0 f.C = flags&0x01 != 0
} }
// updateXYFlags Set flags X and Y based on result bits
func (z *Z80Type) updateXYFlags(result byte) { func (z *Z80Type) updateXYFlags(result byte) {
// Most of the time, the undocumented flags z.Flags.Y = result&0x20 != 0
// (sometimes called X and Y, or 3 and 5), z.Flags.X = result&0x08 != 0
// take their values from the corresponding bits
// of the result of the instruction,
// or from some other related value.
// This is a utility function to set those flags based on those bits.
z.Flags.Y = (result&0x20)>>5 != 0
z.Flags.X = (result&0x08)>>3 != 0
} }
func getParity(value byte) bool { func getParity(value byte) bool {
@ -577,62 +560,84 @@ func (z *Z80Type) doReset(address uint16) {
z.PC = address - 1 z.PC = address - 1
} }
func (z *Z80Type) setBaseFlags(operand byte, result uint16) { //func (z *Z80Type) setBaseFlags(operand byte, result uint16) {
z.Flags.C = result > 0x00ff // z.Flags.S = result&0x80 != 0
z.Flags.S = result&0x80 != 0 // z.Flags.Z = result&0x00ff == 0
z.Flags.Z = result&0xff == 0 // z.Flags.H = (((operand & 0x0f) + (z.A & 0x0f)) & 0x10) != 0
z.Flags.H = (((operand & 0x0f) + (z.A & 0x0f)) & 0x10) != 0 // // An overflow has happened if the sign bits of the accumulator and the operand
// An overflow has happened if the sign bits of the accumulator and the operand // // don't match the sign bit of the result value.
// don't match the sign bit of the result value. // z.Flags.P = ((z.A & 0x80) == (operand & 0x80)) && (z.A&0x80 != byte(result&0x80))
z.Flags.P = ((z.A & 0x80) == (operand & 0x80)) && (z.A&0x80 != byte(result&0x80)) // z.Flags.C = result&0x0100 != 0
} //}
// doAdd Handle ADD A, [operand] instructions.
func (z *Z80Type) doAdd(operand byte) { func (z *Z80Type) doAdd(operand byte) {
// This is the ADD A, [operand] instructions.
// We'll do the literal addition, which includes any overflow,
// so that we can more easily figure out whether we had
// an overflow or a carry and set the flags accordingly.
var result = uint16(z.A) + uint16(operand) var result = uint16(z.A) + uint16(operand)
z.A = byte(result & 0xff)
z.setBaseFlags(operand, result) 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.N = false
z.Flags.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A) z.updateXYFlags(z.A)
} }
func (z *Z80Type) doAdc(operand byte) { func (z *Z80Type) doAdc(operand byte) {
var result = uint16(z.A) + uint16(operand) add := byte(0)
if z.Flags.C { if z.Flags.C {
result++ add = 1
} }
z.A = byte(result & 0xff) var result = uint16(z.A) + uint16(operand) + uint16(add)
z.setBaseFlags(operand, result)
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.N = false
z.Flags.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A) z.updateXYFlags(z.A)
} }
func (z *Z80Type) doSub(operand byte) { func (z *Z80Type) doSub(operand byte) {
var result = uint16(z.A) - uint16(operand) var result = uint16(z.A) - uint16(operand)
z.A = byte(result & 0xff)
z.setBaseFlags(operand, result) 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.N = true
z.Flags.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A) z.updateXYFlags(z.A)
} }
func (z *Z80Type) doSbc(operand byte) { func (z *Z80Type) doSbc(operand byte) {
var result = uint16(z.A) - uint16(operand) sub := byte(0)
if z.Flags.C { if z.Flags.C {
result-- sub = 1
} }
z.A = byte(result & 0xff) var result = uint16(z.A) - uint16(operand) - uint16(sub)
z.setBaseFlags(operand, result)
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.N = true
z.Flags.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A) z.updateXYFlags(z.A)
} }
func (z *Z80Type) setLogicFlags() { func (z *Z80Type) setLogicFlags() {
z.Flags.S = z.A&0x80 != 0 z.Flags.S = z.A&0x80 != 0
z.Flags.Z = z.A == 0 z.Flags.Z = z.A == 0
z.Flags.H = true
z.Flags.P = ParityBits[z.A] z.Flags.P = ParityBits[z.A]
z.Flags.N = false z.Flags.N = false
z.Flags.C = false z.Flags.C = false
@ -641,18 +646,21 @@ func (z *Z80Type) setLogicFlags() {
func (z *Z80Type) doAnd(operand byte) { func (z *Z80Type) doAnd(operand byte) {
z.A &= operand z.A &= operand
z.setLogicFlags() z.setLogicFlags()
z.Flags.H = true
z.updateXYFlags(z.A) z.updateXYFlags(z.A)
} }
func (z *Z80Type) doXor(operand byte) { func (z *Z80Type) doXor(operand byte) {
z.A ^= operand z.A ^= operand
z.setLogicFlags() z.setLogicFlags()
z.Flags.H = false
z.updateXYFlags(z.A) z.updateXYFlags(z.A)
} }
func (z *Z80Type) doOr(operand byte) { func (z *Z80Type) doOr(operand byte) {
z.A |= operand z.A |= operand
z.setLogicFlags() z.setLogicFlags()
z.Flags.H = false
z.updateXYFlags(z.A) z.updateXYFlags(z.A)
} }
@ -666,12 +674,13 @@ func (z *Z80Type) doCp(operand byte) {
func (z *Z80Type) doInc(operand byte) byte { func (z *Z80Type) doInc(operand byte) byte {
var result = uint16(operand) + 1 var result = uint16(operand) + 1
r8 := byte(result & 0xff) r8 := byte(result & 0xff)
z.Flags.S = r8&0x80 > 0
z.Flags.S = r8&0x80 != 0
z.Flags.Z = r8 == 0 z.Flags.Z = r8 == 0
z.Flags.H = (operand & 0x0f) == 0x0f z.Flags.H = (operand & 0x0f) == 0x0f
// It'z a good deal easier to detect overflow for an increment/decrement.
z.Flags.P = operand == 0x7f z.Flags.P = operand == 0x7f
z.Flags.N = false z.Flags.N = false
z.updateXYFlags(r8) z.updateXYFlags(r8)
return r8 return r8
} }
@ -679,11 +688,13 @@ func (z *Z80Type) doInc(operand byte) byte {
func (z *Z80Type) doDec(operand byte) byte { func (z *Z80Type) doDec(operand byte) byte {
var result = uint16(operand) - 1 var result = uint16(operand) - 1
r8 := byte(result & 0xff) r8 := byte(result & 0xff)
z.Flags.S = r8&0x80 > 0
z.Flags.S = r8&0x80 != 0
z.Flags.Z = r8 == 0 z.Flags.Z = r8 == 0
z.Flags.H = (operand & 0x0f) == 0x00 z.Flags.H = (operand & 0x0f) == 0x00
z.Flags.P = operand == 0x80 z.Flags.P = operand == 0x80
z.Flags.N = true z.Flags.N = true
z.updateXYFlags(r8) z.updateXYFlags(r8)
return r8 return r8
} }
@ -1051,17 +1062,6 @@ func (z *Z80Type) decDe() {
z.changeDe(-1) z.changeDe(-1)
} }
func (z *Z80Type) changeHl(val int8) {
hl := (uint16(z.H) << 8) | uint16(z.L)
if val < 0 {
hl--
} else {
hl++
}
z.L = byte(hl & 0xff)
z.H = byte((hl & 0xff00) >> 8)
}
func (z *Z80Type) changeDe(val int8) { func (z *Z80Type) changeDe(val int8) {
de := (uint16(z.D) << 8) | uint16(z.E) de := (uint16(z.D) << 8) | uint16(z.E)
if val < 0 { if val < 0 {
@ -1070,7 +1070,7 @@ func (z *Z80Type) changeDe(val int8) {
de++ de++
} }
z.E = byte(de & 0xff) z.E = byte(de & 0xff)
z.D = byte((de & 0xff00) >> 8) z.D = byte(de >> 8)
} }
func (z *Z80Type) changeBc(val int8) { func (z *Z80Type) changeBc(val int8) {
@ -1081,5 +1081,16 @@ func (z *Z80Type) changeBc(val int8) {
bc++ bc++
} }
z.C = byte(bc & 0x00ff) z.C = byte(bc & 0x00ff)
z.B = byte((bc & 0xff00) >> 8) z.B = byte(bc >> 8)
}
func (z *Z80Type) changeHl(val int8) {
hl := (uint16(z.H) << 8) | uint16(z.L)
if val < 0 {
hl--
} else {
hl++
}
z.L = byte(hl & 0xff)
z.H = byte(hl >> 8)
} }