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

@ -18,29 +18,28 @@ type FlagsType struct {
// Z80Type - Processor state
type Z80Type struct {
A byte
B byte
C byte
D byte
E byte
H byte
L byte
APrime byte
BPrime byte
CPrime byte
DPrime byte
EPrime byte
HPrime byte
LPrime byte
IX uint16
IY uint16
I byte
R byte
SP uint16
PC uint16
Flags FlagsType
FlagsPrime FlagsType
A byte
B byte
C byte
D byte
E byte
H byte
L byte
AAlt byte
BAlt byte
CAlt byte
DAlt byte
EAlt byte
HAlt byte
LAlt byte
IX uint16
IY uint16
I byte
R byte
SP uint16
PC uint16
Flags 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
@ -163,28 +162,28 @@ func (z *Z80Type) SetState(state *Z80Type) {
// New Create new
func New(memIoRW MemIoRW) *Z80Type {
return &Z80Type{
A: 0,
B: 0,
C: 0,
D: 0,
E: 0,
H: 0,
L: 0,
APrime: 0,
BPrime: 0,
CPrime: 0,
DPrime: 0,
EPrime: 0,
HPrime: 0,
IX: 0,
IY: 0,
I: 0,
A: 0,
B: 0,
C: 0,
D: 0,
E: 0,
H: 0,
L: 0,
AAlt: 0,
BAlt: 0,
CAlt: 0,
DAlt: 0,
EAlt: 0,
HAlt: 0,
IX: 0,
IY: 0,
I: 0,
R: 0,
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)
}