mirror of
https://github.com/romychs/Ocean-240.2-Emulator.git
synced 2026-04-21 11:03:21 +03:00
split screen/cpu to 2 go subs
fix alu op flags in Z80 em
This commit is contained in:
parent
50f4e2521f
commit
fe19e5c8c7
73
main.go
73
main.go
@ -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++ {
|
||||||
|
|||||||
@ -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]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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,
|
||||||
|
//}
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
251
z80em/z80em.go
251
z80em/z80em.go
@ -18,29 +18,28 @@ type FlagsType struct {
|
|||||||
|
|
||||||
// Z80Type - Processor state
|
// Z80Type - Processor state
|
||||||
type Z80Type struct {
|
type Z80Type struct {
|
||||||
A byte
|
A byte
|
||||||
B byte
|
B byte
|
||||||
C byte
|
C byte
|
||||||
D byte
|
D byte
|
||||||
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
|
||||||
R byte
|
R byte
|
||||||
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
|
||||||
@ -163,28 +162,28 @@ func (z *Z80Type) SetState(state *Z80Type) {
|
|||||||
// New Create new
|
// New Create new
|
||||||
func New(memIoRW MemIoRW) *Z80Type {
|
func New(memIoRW MemIoRW) *Z80Type {
|
||||||
return &Z80Type{
|
return &Z80Type{
|
||||||
A: 0,
|
A: 0,
|
||||||
B: 0,
|
B: 0,
|
||||||
C: 0,
|
C: 0,
|
||||||
D: 0,
|
D: 0,
|
||||||
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,
|
||||||
|
|
||||||
R: 0,
|
R: 0,
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user