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
var serialBytes []byte
//go:embed bin/MB.COM
//go:embed bin/zexall.com
var ramBytes []byte
var needReset = false
@ -45,11 +45,12 @@ func main() {
computer := okean240.New(conf)
computer.SetSerialBytes(serialBytes)
computer.LoadFloppy()
w, raster, label := mainWindow(computer, conf)
go emulator(computer, raster, label, conf)
go emulator(computer)
go screen(computer, raster, label, conf)
(*w).ShowAndRun()
}
@ -88,6 +89,12 @@ func mainWindow(computer *okean240.ComputerType, emuConfig *config.OkEmuConfig)
w.Resize(fyne.NewSize(600, 600))
hBox := container.NewHBox(
//widget.NewButton("++", func() {
// computer.IncOffset()
//}),
//widget.NewButton("--", func() {
// computer.DecOffset()
//}),
widget.NewButton("Ctrl+C", func() {
computer.PutCtrlKey(0x03)
}),
@ -124,24 +131,37 @@ func mainWindow(computer *okean240.ComputerType, emuConfig *config.OkEmuConfig)
return &w, raster, label
}
func emulator(computer *okean240.ComputerType, raster *canvas.Raster, label *widget.Label, emuConfig *config.OkEmuConfig) {
ticker := time.NewTicker(133 * time.Nanosecond)
var ticks = 0
var ticksCPU = 3
//var ticksSCR = TicksPerFrame
//var frameStartTime = time.Now().UnixMicro()
frameNextTime := time.Now().UnixMicro() + 20000
func screen(computer *okean240.ComputerType, raster *canvas.Raster, label *widget.Label, emuConfig *config.OkEmuConfig) {
ticker := time.NewTicker(20 * time.Millisecond)
frame := 0
var pre uint64 = 0
var freq uint64 = 0
nextSecond := time.Now().Add(time.Second).UnixMicro()
//curScrWidth := 256
for range ticker.C {
if needReset {
computer.Reset(emuConfig)
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++
if ticks%5 == 0 {
// 1.5 MHz
@ -150,37 +170,10 @@ func emulator(computer *okean240.ComputerType, raster *canvas.Raster, label *wid
if ticks > ticksCPU {
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) {
// Add shortcuts for Ctrl+A to Ctrl+Z
for kName := 'A'; kName <= 'Z'; kName++ {

View File

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

View File

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

View File

@ -72,7 +72,7 @@ func (c *ComputerType) IOWrite(port uint16, val byte) {
c.screenWidth = 512
}
c.palette = val & 0x07
c.bgColor = val & 0x38 >> 3
c.bgColor = (val >> 3) & 0x07
case SYS_DD17PA:
c.vShift = val
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 CLBlue = color.RGBA{R: 0x72, G: 0x9F, B: 0xCF, 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 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,
}
//var MonoPalette = [8]color.RGBA{
// 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,
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: func(s *Z80Type) {
s.A, s.APrime = s.APrime, s.A
s.A, s.AAlt = s.AAlt, s.A
temp := s.getFlagsRegister()
s.setFlagsRegister(s.getFlagsPrimeRegister())
s.setFlagsPrimeRegister(temp)
@ -468,12 +468,12 @@ var instructions = []func(s *Z80Type){
},
// 0xd9 : EXX
0xD9: func(s *Z80Type) {
s.B, s.BPrime = s.BPrime, s.B
s.C, s.CPrime = s.CPrime, s.C
s.D, s.DPrime = s.DPrime, s.D
s.E, s.EPrime = s.EPrime, s.E
s.H, s.HPrime = s.HPrime, s.H
s.L, s.LPrime = s.LPrime, s.L
s.B, s.BAlt = s.BAlt, s.B
s.C, s.CAlt = s.CAlt, s.C
s.D, s.DAlt = s.DAlt, s.D
s.E, s.EAlt = s.EAlt, s.E
s.H, s.HAlt = s.HAlt, s.H
s.L, s.LAlt = s.LAlt, s.L
},
// 0xda : JP C, nn
0xDA: func(s *Z80Type) {

View File

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

View File

@ -25,13 +25,13 @@ type Z80Type struct {
E byte
H byte
L byte
APrime byte
BPrime byte
CPrime byte
DPrime byte
EPrime byte
HPrime byte
LPrime byte
AAlt byte
BAlt byte
CAlt byte
DAlt byte
EAlt byte
HAlt byte
LAlt byte
IX uint16
IY uint16
I byte
@ -39,8 +39,7 @@ type Z80Type struct {
SP uint16
PC uint16
Flags FlagsType
FlagsPrime FlagsType
FlagsAlt FlagsType
IMode byte
Iff1 byte
Iff2 byte
@ -106,19 +105,19 @@ func (z *Z80Type) GetState() *Z80Type {
E: z.E,
H: z.H,
L: z.L,
APrime: z.APrime,
BPrime: z.BPrime,
CPrime: z.CPrime,
DPrime: z.DPrime,
EPrime: z.EPrime,
HPrime: z.HPrime,
AAlt: z.AAlt,
BAlt: z.BAlt,
CAlt: z.CAlt,
DAlt: z.DAlt,
EAlt: z.EAlt,
HAlt: z.HAlt,
IX: z.IX,
IY: z.IY,
R: z.R,
SP: z.SP,
PC: z.PC,
Flags: z.Flags,
FlagsPrime: z.FlagsPrime,
FlagsAlt: z.FlagsAlt,
IMode: z.IMode,
Iff1: z.Iff1,
Iff2: z.Iff2,
@ -137,12 +136,12 @@ func (z *Z80Type) SetState(state *Z80Type) {
z.E = state.E
z.H = state.H
z.L = state.L
z.APrime = state.APrime
z.BPrime = state.BPrime
z.CPrime = state.CPrime
z.DPrime = state.DPrime
z.EPrime = state.EPrime
z.HPrime = state.HPrime
z.AAlt = state.AAlt
z.BAlt = state.BAlt
z.CAlt = state.CAlt
z.DAlt = state.DAlt
z.EAlt = state.EAlt
z.HAlt = state.HAlt
z.IX = state.IX
z.IY = state.IY
z.I = state.I
@ -150,7 +149,7 @@ func (z *Z80Type) SetState(state *Z80Type) {
z.SP = state.SP
z.PC = state.PC
z.Flags = state.Flags
z.FlagsPrime = state.FlagsPrime
z.FlagsAlt = state.FlagsAlt
z.IMode = state.IMode
z.Iff1 = state.Iff1
z.Iff2 = state.Iff2
@ -170,12 +169,12 @@ func New(memIoRW MemIoRW) *Z80Type {
E: 0,
H: 0,
L: 0,
APrime: 0,
BPrime: 0,
CPrime: 0,
DPrime: 0,
EPrime: 0,
HPrime: 0,
AAlt: 0,
BAlt: 0,
CAlt: 0,
DAlt: 0,
EAlt: 0,
HAlt: 0,
IX: 0,
IY: 0,
I: 0,
@ -184,7 +183,7 @@ func New(memIoRW MemIoRW) *Z80Type {
SP: SpDefault,
PC: 0,
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,
Iff1: 0,
Iff2: 0,
@ -355,20 +354,14 @@ func (z *Z80Type) decodeInstruction(opcode byte) {
if opcode == OpHalt {
z.Halted = true
} else if opcode >= OpLdBB && opcode < OpAddAB {
// This entire range is all 8-bit register loads.
// Get the operand and assign it to the correct destination.
// 8-bit register loads.
z.load8bit(opcode, z.getOperand(opcode))
} else if (opcode >= OpAddAB) && (opcode < OpRetNz) {
// These are the 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.
// 8-bit register ALU instructions.
z.alu8bit(opcode, z.getOperand(opcode))
} else {
// This is one of the less formulaic instructions;
// we'll get the specific function for it from our array.
fun := instructions[opcode]
fun(z)
//z.otherInstructions(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) {
switch (opcode & 0x38) >> 3 {
case 0:
@ -426,7 +420,7 @@ func (z *Z80Type) getFlagsRegister() byte {
// getFlagsRegister return whole F' register
func (z *Z80Type) getFlagsPrimeRegister() byte {
return getFlags(&z.FlagsPrime)
return getFlags(&z.FlagsAlt)
}
func getFlags(f *FlagsType) byte {
@ -437,27 +431,21 @@ func getFlags(f *FlagsType) byte {
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
}
@ -470,7 +458,7 @@ func (z *Z80Type) setFlagsRegister(flags byte) {
}
func (z *Z80Type) setFlagsPrimeRegister(flags byte) {
setFlags(flags, &z.FlagsPrime)
setFlags(flags, &z.FlagsAlt)
}
func setFlags(flags byte, f *FlagsType) {
@ -484,15 +472,10 @@ func setFlags(flags byte, f *FlagsType) {
f.C = flags&0x01 != 0
}
// updateXYFlags Set flags X and Y based on result bits
func (z *Z80Type) updateXYFlags(result byte) {
// Most of the time, the undocumented flags
// (sometimes called X and Y, or 3 and 5),
// 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
z.Flags.Y = result&0x20 != 0
z.Flags.X = result&0x08 != 0
}
func getParity(value byte) bool {
@ -577,62 +560,84 @@ func (z *Z80Type) doReset(address uint16) {
z.PC = address - 1
}
func (z *Z80Type) setBaseFlags(operand byte, result uint16) {
z.Flags.C = result > 0x00ff
z.Flags.S = result&0x80 != 0
z.Flags.Z = result&0xff == 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
// don't match the sign bit of the result value.
z.Flags.P = ((z.A & 0x80) == (operand & 0x80)) && (z.A&0x80 != byte(result&0x80))
}
//func (z *Z80Type) setBaseFlags(operand byte, result uint16) {
// z.Flags.S = result&0x80 != 0
// z.Flags.Z = result&0x00ff == 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
// // 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.C = result&0x0100 != 0
//}
// doAdd Handle ADD A, [operand] instructions.
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)
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.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A)
}
func (z *Z80Type) doAdc(operand byte) {
var result = uint16(z.A) + uint16(operand)
add := byte(0)
if z.Flags.C {
result++
add = 1
}
z.A = byte(result & 0xff)
z.setBaseFlags(operand, result)
var result = uint16(z.A) + uint16(operand) + uint16(add)
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.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A)
}
func (z *Z80Type) doSub(operand byte) {
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.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A)
}
func (z *Z80Type) doSbc(operand byte) {
var result = uint16(z.A) - uint16(operand)
sub := byte(0)
if z.Flags.C {
result--
sub = 1
}
z.A = byte(result & 0xff)
z.setBaseFlags(operand, result)
var result = uint16(z.A) - uint16(operand) - uint16(sub)
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.C = result&0x0100 != 0
z.A = byte(result & 0xff)
z.updateXYFlags(z.A)
}
func (z *Z80Type) setLogicFlags() {
z.Flags.S = z.A&0x80 != 0
z.Flags.Z = z.A == 0
z.Flags.H = true
z.Flags.P = ParityBits[z.A]
z.Flags.N = false
z.Flags.C = false
@ -641,18 +646,21 @@ func (z *Z80Type) setLogicFlags() {
func (z *Z80Type) doAnd(operand byte) {
z.A &= operand
z.setLogicFlags()
z.Flags.H = true
z.updateXYFlags(z.A)
}
func (z *Z80Type) doXor(operand byte) {
z.A ^= operand
z.setLogicFlags()
z.Flags.H = false
z.updateXYFlags(z.A)
}
func (z *Z80Type) doOr(operand byte) {
z.A |= operand
z.setLogicFlags()
z.Flags.H = false
z.updateXYFlags(z.A)
}
@ -666,12 +674,13 @@ func (z *Z80Type) doCp(operand byte) {
func (z *Z80Type) doInc(operand byte) byte {
var result = uint16(operand) + 1
r8 := byte(result & 0xff)
z.Flags.S = r8&0x80 > 0
z.Flags.S = r8&0x80 != 0
z.Flags.Z = r8 == 0
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.N = false
z.updateXYFlags(r8)
return r8
}
@ -679,11 +688,13 @@ func (z *Z80Type) doInc(operand byte) byte {
func (z *Z80Type) doDec(operand byte) byte {
var result = uint16(operand) - 1
r8 := byte(result & 0xff)
z.Flags.S = r8&0x80 > 0
z.Flags.S = r8&0x80 != 0
z.Flags.Z = r8 == 0
z.Flags.H = (operand & 0x0f) == 0x00
z.Flags.P = operand == 0x80
z.Flags.N = true
z.updateXYFlags(r8)
return r8
}
@ -1051,17 +1062,6 @@ func (z *Z80Type) decDe() {
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) {
de := (uint16(z.D) << 8) | uint16(z.E)
if val < 0 {
@ -1070,7 +1070,7 @@ func (z *Z80Type) changeDe(val int8) {
de++
}
z.E = byte(de & 0xff)
z.D = byte((de & 0xff00) >> 8)
z.D = byte(de >> 8)
}
func (z *Z80Type) changeBc(val int8) {
@ -1081,5 +1081,16 @@ func (z *Z80Type) changeBc(val int8) {
bc++
}
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)
}