diff --git a/main.go b/main.go index 77c73d5..9256651 100644 --- a/main.go +++ b/main.go @@ -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+ func addShortcuts(c fyne.Canvas, computer *okean240.ComputerType) { // Add shortcuts for Ctrl+A to Ctrl+Z for kName := 'A'; kName <= 'Z'; kName++ { diff --git a/okean240/computer.go b/okean240/computer.go index 8be79d0..aff0c81 100644 --- a/okean240/computer.go +++ b/okean240/computer.go @@ -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] } } } diff --git a/okean240/fdc/fdc.go b/okean240/fdc/fdc.go index feff94d..f27f5c5 100644 --- a/okean240/fdc/fdc.go +++ b/okean240/fdc/fdc.go @@ -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 } } diff --git a/okean240/ioports.go b/okean240/ioports.go index 56a4365..0d069b9 100644 --- a/okean240/ioports.go +++ b/okean240/ioports.go @@ -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: diff --git a/okean240/palette.go b/okean240/palette.go index 0f726ab..5a1a8c2 100644 --- a/okean240/palette.go +++ b/okean240/palette.go @@ -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, +//} diff --git a/z80em/opcode.go b/z80em/opcode.go index 6f98089..f111809 100644 --- a/z80em/opcode.go +++ b/z80em/opcode.go @@ -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) { diff --git a/z80em/opcodeDD.go b/z80em/opcodeDD.go index 37348bf..61a5458 100644 --- a/z80em/opcodeDD.go +++ b/z80em/opcodeDD.go @@ -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 diff --git a/z80em/z80em.go b/z80em/z80em.go index 3a2220b..f2eb13e 100644 --- a/z80em/z80em.go +++ b/z80em/z80em.go @@ -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) }