z80 emulator refactoring and fixes

This commit is contained in:
Роман Бойков 2026-03-07 23:58:41 +03:00
parent fe19e5c8c7
commit eb4339b86a
13 changed files with 510 additions and 588 deletions

39
main.go
View File

@ -23,7 +23,7 @@ var BuildTime = "2026-03-01"
//go:embed hex/format.hex
var serialBytes []byte
//go:embed bin/zexall.com
//go:embed bin/TET.COM
var ramBytes []byte
var needReset = false
@ -47,14 +47,14 @@ func main() {
computer.SetSerialBytes(serialBytes)
computer.LoadFloppy()
w, raster, label := mainWindow(computer, conf)
w, raster, label := mainWindow(computer)
go emulator(computer)
go screen(computer, raster, label, conf)
(*w).ShowAndRun()
}
func mainWindow(computer *okean240.ComputerType, emuConfig *config.OkEmuConfig) (*fyne.Window, *canvas.Raster, *widget.Label) {
func mainWindow(computer *okean240.ComputerType) (*fyne.Window, *canvas.Raster, *widget.Label) {
emulatorApp := app.New()
w := emulatorApp.NewWindow("Океан 240.2")
w.Canvas().SetOnTypedKey(
@ -107,9 +107,9 @@ func mainWindow(computer *okean240.ComputerType, emuConfig *config.OkEmuConfig)
widget.NewButton("RUN", func() {
computer.SetRamBytes(ramBytes)
}),
widget.NewButton("DUMP", func() {
computer.Dump(0x399, 15000)
}),
//widget.NewButton("DUMP", func() {
// computer.Dump(0x399, 15000)
//}),
widget.NewSeparator(),
widget.NewButton("Reset", func() {
needReset = true
@ -138,10 +138,6 @@ func screen(computer *okean240.ComputerType, raster *canvas.Raster, label *widge
var freq uint64 = 0
for range ticker.C {
if needReset {
computer.Reset(emuConfig)
needReset = false
}
frame++
// redraw screen here
fyne.Do(func() {
@ -156,20 +152,31 @@ func screen(computer *okean240.ComputerType, raster *canvas.Raster, label *widge
}
}
const ticksPerTicker = 3
func emulator(computer *okean240.ComputerType) {
ticker := time.NewTicker(133 * time.Nanosecond)
ticker := time.NewTicker(66 * time.Nanosecond)
var ticks = 0
var ticksCPU = 0
var nextClock = ticks + ticksPerTicker
//var ticksCPU = 3
for range ticker.C {
time.Sleep(133 * time.Nanosecond)
//for {
//time.Sleep(133 * time.Nanosecond)
ticks++
if ticks%5 == 0 {
if ticks%10 == 0 {
// 1.5 MHz
computer.TimerClk()
}
if ticks > ticksCPU {
ticksCPU = ticks + computer.Do()*2
if ticks >= nextClock {
nextClock = ticks + computer.Do()*ticksPerTicker
}
if needReset {
computer.Reset()
needReset = false
}
//if ticks > ticksCPU {
//ticksCPU = ticks + computer.Do()*2
//}
}
}

View File

@ -2,7 +2,6 @@ package okean240
import (
_ "embed"
"encoding/binary"
"image/color"
"okemu/config"
"okemu/okean240/fdc"
@ -10,7 +9,6 @@ import (
"okemu/okean240/pit"
"okemu/okean240/usart"
"okemu/z80em"
"os"
"fyne.io/fyne/v2"
log "github.com/sirupsen/logrus"
@ -54,7 +52,7 @@ type ComputerInterface interface {
PutCtrlKey(shortcut fyne.Shortcut)
SaveFloppy()
LoadFloppy()
Dump(start uint16, length uint16)
//Dump(start uint16, length uint16)
}
func (c *ComputerType) M1MemRead(addr uint16) byte {
@ -97,20 +95,17 @@ func New(cfg *config.OkEmuConfig) *ComputerType {
return &c
}
func (c *ComputerType) Reset(cfg *config.OkEmuConfig) {
func (c *ComputerType) Reset() {
c.cpu.Reset()
c.cycles = 0
c.vShift = 0
c.hShift = 0
c.memory = Memory{}
c.memory.Init(cfg.MonitorFile, cfg.CPMFile)
c.cycles = 0
c.dd17EnableOut = false
c.screenWidth = 512
c.screenHeight = 256
c.vRAM = c.memory.allMemory[3]
//c.vShift = 0
//c.hShift = 0
//c.memory = Memory{}
//c.memory.Init(cfg.MonitorFile, cfg.CPMFile)
//c.dd17EnableOut = false
//c.screenWidth = 256
//c.screenHeight = 256
//c.vRAM = c.memory.allMemory[3]
}
@ -250,25 +245,25 @@ func (c *ComputerType) SetRamBytes(bytes []byte) {
//c.cpu.PC = 0x100
}
func (c *ComputerType) Dump(start uint16, length uint16) {
file, err := os.Create("dump.dat")
if err != nil {
log.Error(err)
return
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
log.Error(err)
}
}(file)
var buffer []byte
for addr := 0; addr < 65535; addr++ {
buffer = append(buffer, c.memory.MemRead(uint16(addr)))
}
err = binary.Write(file, binary.LittleEndian, buffer)
if err != nil {
log.Error("Save memory dump failed:", err)
}
}
//func (c *ComputerType) Dump(start uint16, length uint16) {
// file, err := os.Create("dump.dat")
// if err != nil {
// log.Error(err)
// return
// }
// defer func(file *os.File) {
// err := file.Close()
// if err != nil {
// log.Error(err)
// }
// }(file)
//
// var buffer []byte
// for addr := 0; addr < 65535; addr++ {
// buffer = append(buffer, c.memory.MemRead(uint16(addr)))
// }
// err = binary.Write(file, binary.LittleEndian, buffer)
// if err != nil {
// log.Error("Save memory dump failed:", err)
// }
//}

View File

@ -5,154 +5,151 @@ package okean240
*/
// USR_DD79PA User port A
const USR_DD79PA = 0x00
//const USR_DD79PA = 0x00
// USR_DD79PB User port B
const USR_DD79PB = 0x01
//const USR_DD79PB = 0x01
// USR_DD79PC User port C
const USR_DD79PC = 0x02
//const USR_DD79PC = 0x02
// USR_DD79CTR Config
const USR_DD79CTR = 0x03 // Config: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
// Configure: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
// Set bit: [0][xxx][bbb][0|1]
//const USR_DD79CTR = 0x03
/*
* КР1818ВГ93 FDC Controller
*/
// FDC_CMD FDC Command
const FDC_CMD = 0x20
// FdcCmd FDC Command
const FdcCmd = 0x20
// FDC_TRACK FDC Track No
const FDC_TRACK = 0x21
// FdcTrack FDC Track No
const FdcTrack = 0x21
// FDC_SECT FDC Sector
const FDC_SECT = 0x22
// FdcSect FDC Sector
const FdcSect = 0x22
// FDC_DATA FDC Data
const FDC_DATA = 0x23
// FdcData FDC Data
const FdcData = 0x23
// FDC_DRQ Read DRQ state from FDC
const FDC_DRQ = 0x24
// FdcDrq Read DRQ state from FDC
const FdcDrq = 0x24
/*
* Floppy Controller port
*/
// FLOPPY Floppy Controller port
const FLOPPY = 0x25 // WR: 5-SSEN, 4-#DDEN, 3-INIT, 2-DRSEL, 1-MOT1, 0-MOT0
// Floppy Controller port
// WR: 5-SSEN, 4-#DDEN, 3-INIT, 2-DRSEL, 1-MOT1, 0-MOT0
// RD: 7-MOTST, 6-SSEL, 5,4-x , 3-DRSEL, 2-MOT1, 1-MOT0, 0-INT
const Floppy = 0x25
/*
* КР580ВВ55 DD78 Keyboard
*/
// KBD_DD78PA Port A - Keyboard Data
const KBD_DD78PA = 0x40
// KbdDd78pa Port A - Keyboard Data
const KbdDd78pa = 0x40
// KBD_DD78PB Port B - JST3,SHFT,CTRL,ACK,TAPE5,TAPE4,GK,GC
const KBD_DD78PB = 0x41
// KbdDd78pb Port B - JST3,SHFT,CTRL,ACK,TAPE5,TAPE4,GK,GC
const KbdDd78pb = 0x41
// KBD_DD78PC Port C - [PC7:5],[KBD_ACK],[PC3:0]
const KBD_DD78PC = 0x42
//const KBD_DD78PC = 0x42
// KBD_DD78CTR Control port
const KBD_DD78CTR = 0x43 // Сonfig: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
// Configure: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
// Set bit: [0][xxx][bbb][0|1]
// const KBD_DD78CTR = 0x43
/*
* КР580ВИ53 DD70
*/
// TMR_DD70C1 Timer load 1
const TMR_DD70C1 = 0x60
// TmrDd70c1 Timer load 1
const TmrDd70c1 = 0x60
// TMR_DD70C2 Timer load 2
const TMR_DD70C2 = 0x61
// TmrDd70c2 Timer load 2
const TmrDd70c2 = 0x61
// TMR_DD70C3 Timer load 3
const TMR_DD70C3 = 0x62
// TmrDd70c3 Timer load 3
const TmrDd70c3 = 0x62
// TmrDd70ctr
// Timer config: [sc1,sc0][rl1,rl0][m2,m1,m0][bcd]
//
// sc - timer, rl=01-LSB, 10-MSB, 11-LSB+MSB
// mode 000 - intRq on fin,
// 001 - one shot,
// x10 - rate gen,
// x11-sq wave
const TmrDd70ctr = 0x63
/*
TMR_DD70CTR
Timer config: [sc1,sc0][rl1,rl0][m2,m1,m0][bcd]
sc - timer, rl=01-LSB, 10-MSB, 11-LSB+MSB
mode 000 - intRq on fin,
001 - one shot,
x10 - rate gen,
x11-sq wave
*/
const TMR_DD70CTR = 0x63
/*
* Programmable Interrupt controller PIC KR580VV59
* Programmable Interrupt controller PIC КР580ВН59
*/
const RstKbdNo = 1
const RstTimerNo = 4
const Rst0Mask = 0x01 // System interrupt
const Rst1Mask = 0x02 // Keyboard interrupt
const Rst2Mask = 0x04 // Serial interface interrupt
const RstЗMask = 0x08 // Printer ready
const Rst4Mask = 0x10
const Rst5Mask = 0x20 // Power intRq
const Rst6Mask = 0x40 // User device 1 interrupt
const Rst7Mask = 0x80 // User device 1 interrupt
//const Rst0Mask = 0x01 // System interrupt
//const Rst1Mask = 0x02 // Keyboard interrupt
//const Rst2Mask = 0x04 // Serial interface interrupt
//const Rst3Mask = 0x08 // Printer ready
//const Rst4Mask = 0x10
//const Rst5Mask = 0x20 // Power intRq
//const Rst6Mask = 0x40 // User device 1 interrupt
//const Rst7Mask = 0x80 // User device 1 interrupt
// PIC_DD75A Port A (a0=0)
const PIC_DD75A = 0x80
// PicDd75a Port A (a0=0)
//const PicDd75a = 0x80
// PIC_DD75B Port B (a0=1)
const PIC_DD75B = 0x81
//const PIC_DD75B = 0x81
/*
* КР580ВВ51 DD72
*/
// UART_DD72RD Serial data
const UART_DD72RD = 0xA0
// UartDd72rd Serial data
const UartDd72rd = 0xA0
// UART_DD72RR Serial status [RST,RQ_RX,RST_ERR,PAUSE,RX_EN,RX_RDY,TX_RDY]
const UART_DD72RR = 0xA1
// UartDd72rr Serial status [RST,RQ_RX,RST_ERR,PAUSE,RX_EN,RX_RDY,TX_RDY]
const UartDd72rr = 0xA1
/*
* КР580ВВ55 DD17 System port
*/
// Port A - VShift[8..1] Vertical shift
const SYS_DD17PA = 0xC0
// SysDd17pa Port A - VShift[8..1] Vertical shift
const SysDd17pa = 0xC0
// Port B - Memory mapper [ROM14,13][REST][ENROM-][A18,17,16][32k]
const SYS_DD17PB = 0xC1
// SysDd17pb Port B - Memory mapper [ROM14,13][REST][ENROM-][A18,17,16][32k]
const SysDd17pb = 0xC1
// Port C - HShift[HS5..1,SB3..1] Horisontal shift
const SYS_DD17PC = 0xC2
// SysDd17pc Port C - HShift[HS5..1,SB3..1] Horisontal shift
const SysDd17pc = 0xC2
/*
* SYS_DD17CTR
* Сonfig: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
* Set bit: [0][xxx][bbb][0|1]
*/
const SYS_DD17CTR = 0xC3
// SysDd17ctr Configure: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
// Set bit: [0][xxx][bbb][0|1]
const SysDd17ctr = 0xC3
/*
* КР580ВВ55 DD67
*/
// LPT_DD67PA Port A - Printer Data
const LPT_DD67PA = 0xE0
//const LPT_DD67PA = 0xE0
// VID_DD67PB Port B - Video control [VSU,C/M,FL3:1,COL3:1]
const VID_DD67PB = 0xE1
//const VID_DD67PB = 0xE1
// DD67PC Port C - [USER3:1, STB-LP, BELL, TAPE3:1]
const DD67PC = 0xE2
//const DD67PC = 0xE2
/*
* DD67CTR
* Сonfig: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
* Set bit: [0][xxx][bbb][0|1]
*/
const DD67CTR = 0xE3
// DD67CTR
// Configure: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
// Set bit: [0][xxx][bbb][0|1]
// const DD67CTR = 0xE3

View File

@ -50,7 +50,7 @@ const (
const (
StatusTR0 = 0x04 // TR0 - Head at track 0
StatusRNF = 0x10 // RNF - Record not found
StatusSeekError = 0x10 // Sector out of disk
// StatusSeekError = 0x10 // Sector out of disk
StatusHeadLoaded = 0x20 // Head on disk
)

View File

@ -12,31 +12,31 @@ import log "github.com/sirupsen/logrus"
func (c *ComputerType) IORead(port uint16) byte {
switch port & 0x00ff {
case PIC_DD75A:
case PicDd75a:
// PIO xx59, get IRR register
return c.pic.IRR()
case UART_DD72RR:
case UartDd72rr:
// USART VV51 CMD
return c.usart.Status()
case UART_DD72RD:
case UartDd72rd:
// USART VV51 Data
return c.usart.Receive()
case KBD_DD78PA:
case KbdDd78pa:
// Keyboard data
return c.ioPorts[KBD_DD78PA]
case KBD_DD78PB:
return c.ioPorts[KBD_DD78PB]
case FDC_CMD:
return c.ioPorts[KbdDd78pa]
case KbdDd78pb:
return c.ioPorts[KbdDd78pb]
case FdcCmd:
return c.fdc.Status()
case FDC_DRQ:
case FdcDrq:
return c.fdc.Drq()
case FLOPPY:
case Floppy:
return c.fdc.GetFloppy()
case FDC_DATA:
case FdcData:
return c.fdc.Data()
case FDC_TRACK:
case FdcTrack:
return c.fdc.Track()
case FDC_SECT:
case FdcSect:
return c.fdc.Sector()
default:
@ -50,11 +50,11 @@ func (c *ComputerType) IOWrite(port uint16, val byte) {
c.ioPorts[bp] = val
//log.Debugf("OUT (%x), %x", bp, val)
switch bp {
case SYS_DD17PB:
case SysDd17pb:
if c.dd17EnableOut {
c.memory.Configure(val)
}
case SYS_DD17CTR:
case SysDd17ctr:
c.dd17EnableOut = val == 0x80
case VID_DD67PB:
if val&VidVsuBit == 0 {
@ -73,38 +73,38 @@ func (c *ComputerType) IOWrite(port uint16, val byte) {
}
c.palette = val & 0x07
c.bgColor = (val >> 3) & 0x07
case SYS_DD17PA:
case SysDd17pa:
c.vShift = val
case SYS_DD17PC:
case SysDd17pc:
c.hShift = val
case TMR_DD70CTR:
case TmrDd70ctr:
// Timer VI63 config register
c.pit.Configure(val)
case TMR_DD70C1:
case TmrDd70c1:
// Timer VI63 counter0 register
c.pit.Load(0, val)
case TMR_DD70C2:
case TmrDd70c2:
// Timer VI63 counter1 register
c.pit.Load(1, val)
case TMR_DD70C3:
case TmrDd70c3:
// Timer VI63 counter2 register
c.pit.Load(2, val)
case UART_DD72RR:
case UartDd72rr:
// USART VV51 CMD
c.usart.Command(val)
case UART_DD72RD:
case UartDd72rd:
// USART VV51 Data
c.usart.Send(val)
case FDC_CMD:
case FdcCmd:
c.fdc.SetCmd(val)
case FDC_DATA:
case FdcData:
c.fdc.SetData(val)
case FDC_TRACK:
case FdcTrack:
c.fdc.SetTrackNo(val)
case FDC_SECT:
case FdcSect:
c.fdc.SetSectorNo(val)
case FLOPPY:
case Floppy:
c.fdc.SetFloppy(val)
default:
//log.Debugf("OUT to Unknown port (%x), %x", bp, val)

View File

@ -9,7 +9,7 @@ func (c *ComputerType) PutKey(key *fyne.KeyEvent) {
code := RemapCmdKey[key.Name]
if code > 0 {
//log.Debugf("PutKey keyName: %s", key.Name)
c.ioPorts[KBD_DD78PA] = code
c.ioPorts[KbdDd78pa] = code
c.pic.SetIRQ(RstKbdNo)
}
@ -19,7 +19,7 @@ func (c *ComputerType) PutRune(key rune) {
//log.Debugf("Put Rune: %c Lo: %x, Hi: %x", key, key&0xff, key>>8)
c.ioPorts[KBD_DD78PA] = byte(key & 0xff)
c.ioPorts[KbdDd78pa] = byte(key & 0xff)
c.pic.SetIRQ(RstKbdNo)
}
@ -37,8 +37,8 @@ func (c *ComputerType) PutRune(key rune) {
*/
func (c *ComputerType) PutCtrlKey(key byte) {
c.ioPorts[KBD_DD78PA] = key
c.ioPorts[KbdDd78pa] = key
c.pic.SetIRQ(RstKbdNo)
//c.ioPorts[PIC_DD75RS] |= Rst1Mask
c.ioPorts[KBD_DD78PB] &= 0x1f | 0x20
c.ioPorts[KbdDd78pb] &= 0x1f | 0x20
}

View File

@ -39,7 +39,6 @@ type I8253 struct {
}
type I8253Interface interface {
//Init()
Configure(value byte)
Load(chNo int, value byte)
Counter(chNo int) uint16

View File

@ -33,164 +33,164 @@ var RemapCmdKey = map[fyne.KeyName]byte{
fyne.KeyUnknown: 0x00,
}
var RemapKey = map[fyne.KeyName]byte{
fyne.KeyEscape: 0x1B,
fyne.KeyReturn: 0x0A,
fyne.KeyTab: 0x09,
fyne.KeyBackspace: 0x08,
fyne.KeyInsert: 0x00,
fyne.KeyDelete: 0x08,
fyne.KeyRight: 0x18,
fyne.KeyLeft: 0x08,
fyne.KeyDown: 0x0A,
fyne.KeyUp: 0x19,
fyne.KeyPageUp: 0x00,
fyne.KeyPageDown: 0x00,
fyne.KeyHome: 0x0C,
fyne.KeyEnd: 0x1A,
fyne.KeyF1: 0x00,
fyne.KeyF2: 0x00,
fyne.KeyF3: 0x00,
fyne.KeyF4: 0x00,
fyne.KeyF5: 0x00,
fyne.KeyF6: 0x00,
fyne.KeyF7: 0x00,
fyne.KeyF8: 0x00,
fyne.KeyF9: 0x00,
fyne.KeyF10: 0x00,
fyne.KeyF11: 0x00,
fyne.KeyF12: 0x00,
fyne.KeyEnter: 0x0D,
fyne.Key0: 0x30,
fyne.Key1: 0x31,
fyne.Key2: 0x32,
fyne.Key3: 0x33,
fyne.Key4: 0x34,
fyne.Key5: 0x35,
fyne.Key6: 0x36,
fyne.Key7: 0x37,
fyne.Key8: 0x38,
fyne.Key9: 0x39,
fyne.KeyA: 0x61,
fyne.KeyB: 0x62,
fyne.KeyC: 0x63,
fyne.KeyD: 0x64,
fyne.KeyE: 0x65,
fyne.KeyF: 0x66,
fyne.KeyG: 0x67,
fyne.KeyH: 0x68,
fyne.KeyI: 0x69,
fyne.KeyJ: 0x6a,
fyne.KeyK: 0x6b,
fyne.KeyL: 0x6c,
fyne.KeyM: 0x6d,
fyne.KeyN: 0x6e,
fyne.KeyO: 0x6f,
fyne.KeyP: 0x70,
fyne.KeyQ: 0x71,
fyne.KeyR: 0x72,
fyne.KeyS: 0x73,
fyne.KeyT: 0x74,
fyne.KeyU: 0x75,
fyne.KeyV: 0x76,
fyne.KeyW: 0x77,
fyne.KeyX: 0x78,
fyne.KeyY: 0x79,
fyne.KeyZ: 0x7A,
fyne.KeySpace: 0x20,
fyne.KeyApostrophe: 0x27,
fyne.KeyComma: 0x2c,
fyne.KeyMinus: 0x2d,
fyne.KeyPeriod: 0x2E,
fyne.KeySlash: 0x2F,
fyne.KeyBackslash: 0x5C,
fyne.KeyLeftBracket: 0x5B,
fyne.KeyRightBracket: 0x5D,
fyne.KeySemicolon: 0x3B,
fyne.KeyEqual: 0x3D,
fyne.KeyAsterisk: 0x2A,
fyne.KeyPlus: 0x2B,
fyne.KeyBackTick: 0x60,
fyne.KeyUnknown: 0x00,
}
var RemapKeyShift = map[fyne.KeyName]byte{
fyne.KeyEscape: 0x1B,
fyne.KeyReturn: 0x0A,
fyne.KeyTab: 0x09,
fyne.KeyBackspace: 0x08,
fyne.KeyInsert: 0x00,
fyne.KeyDelete: 0x08,
fyne.KeyRight: 0x18,
fyne.KeyLeft: 0x08,
fyne.KeyDown: 0x0A,
fyne.KeyUp: 0x19,
fyne.KeyPageUp: 0x00,
fyne.KeyPageDown: 0x00,
fyne.KeyHome: 0x0C,
fyne.KeyEnd: 0x1A,
fyne.KeyF1: 0x00,
fyne.KeyF2: 0x00,
fyne.KeyF3: 0x00,
fyne.KeyF4: 0x00,
fyne.KeyF5: 0x00,
fyne.KeyF6: 0x00,
fyne.KeyF7: 0x00,
fyne.KeyF8: 0x00,
fyne.KeyF9: 0x00,
fyne.KeyF10: 0x00,
fyne.KeyF11: 0x00,
fyne.KeyF12: 0x00,
fyne.KeyEnter: 0x0D,
fyne.Key0: 0x29,
fyne.Key1: 0x21,
fyne.Key2: 0x40,
fyne.Key3: 0x23,
fyne.Key4: 0x24,
fyne.Key5: 0x25,
fyne.Key6: 0x5E,
fyne.Key7: 0x26,
fyne.Key8: 0x2A,
fyne.Key9: 0x28,
fyne.KeyA: 0x41,
fyne.KeyB: 0x42,
fyne.KeyC: 0x43,
fyne.KeyD: 0x44,
fyne.KeyE: 0x45,
fyne.KeyF: 0x46,
fyne.KeyG: 0x47,
fyne.KeyH: 0x48,
fyne.KeyI: 0x49,
fyne.KeyJ: 0x4a,
fyne.KeyK: 0x4b,
fyne.KeyL: 0x4c,
fyne.KeyM: 0x4d,
fyne.KeyN: 0x4e,
fyne.KeyO: 0x4f,
fyne.KeyP: 0x50,
fyne.KeyQ: 0x51,
fyne.KeyR: 0x52,
fyne.KeyS: 0x53,
fyne.KeyT: 0x54,
fyne.KeyU: 0x55,
fyne.KeyV: 0x56,
fyne.KeyW: 0x57,
fyne.KeyX: 0x58,
fyne.KeyY: 0x59,
fyne.KeyZ: 0x5A,
fyne.KeySpace: 0x20,
fyne.KeyApostrophe: 0x22,
fyne.KeyComma: 0x3C,
fyne.KeyMinus: 0x5F,
fyne.KeyPeriod: 0x3E,
fyne.KeySlash: 0x3F,
fyne.KeyBackslash: 0x7C,
fyne.KeyLeftBracket: 0x7B,
fyne.KeyRightBracket: 0x7D,
fyne.KeySemicolon: 0x3A,
fyne.KeyEqual: 0x2B,
fyne.KeyAsterisk: 0x7E,
fyne.KeyPlus: 0x7E,
fyne.KeyBackTick: 0x60,
}
//var RemapKey = map[fyne.KeyName]byte{
// fyne.KeyEscape: 0x1B,
// fyne.KeyReturn: 0x0A,
// fyne.KeyTab: 0x09,
// fyne.KeyBackspace: 0x08,
// fyne.KeyInsert: 0x00,
// fyne.KeyDelete: 0x08,
// fyne.KeyRight: 0x18,
// fyne.KeyLeft: 0x08,
// fyne.KeyDown: 0x0A,
// fyne.KeyUp: 0x19,
// fyne.KeyPageUp: 0x00,
// fyne.KeyPageDown: 0x00,
// fyne.KeyHome: 0x0C,
// fyne.KeyEnd: 0x1A,
// fyne.KeyF1: 0x00,
// fyne.KeyF2: 0x00,
// fyne.KeyF3: 0x00,
// fyne.KeyF4: 0x00,
// fyne.KeyF5: 0x00,
// fyne.KeyF6: 0x00,
// fyne.KeyF7: 0x00,
// fyne.KeyF8: 0x00,
// fyne.KeyF9: 0x00,
// fyne.KeyF10: 0x00,
// fyne.KeyF11: 0x00,
// fyne.KeyF12: 0x00,
// fyne.KeyEnter: 0x0D,
// fyne.Key0: 0x30,
// fyne.Key1: 0x31,
// fyne.Key2: 0x32,
// fyne.Key3: 0x33,
// fyne.Key4: 0x34,
// fyne.Key5: 0x35,
// fyne.Key6: 0x36,
// fyne.Key7: 0x37,
// fyne.Key8: 0x38,
// fyne.Key9: 0x39,
// fyne.KeyA: 0x61,
// fyne.KeyB: 0x62,
// fyne.KeyC: 0x63,
// fyne.KeyD: 0x64,
// fyne.KeyE: 0x65,
// fyne.KeyF: 0x66,
// fyne.KeyG: 0x67,
// fyne.KeyH: 0x68,
// fyne.KeyI: 0x69,
// fyne.KeyJ: 0x6a,
// fyne.KeyK: 0x6b,
// fyne.KeyL: 0x6c,
// fyne.KeyM: 0x6d,
// fyne.KeyN: 0x6e,
// fyne.KeyO: 0x6f,
// fyne.KeyP: 0x70,
// fyne.KeyQ: 0x71,
// fyne.KeyR: 0x72,
// fyne.KeyS: 0x73,
// fyne.KeyT: 0x74,
// fyne.KeyU: 0x75,
// fyne.KeyV: 0x76,
// fyne.KeyW: 0x77,
// fyne.KeyX: 0x78,
// fyne.KeyY: 0x79,
// fyne.KeyZ: 0x7A,
// fyne.KeySpace: 0x20,
// fyne.KeyApostrophe: 0x27,
// fyne.KeyComma: 0x2c,
// fyne.KeyMinus: 0x2d,
// fyne.KeyPeriod: 0x2E,
// fyne.KeySlash: 0x2F,
// fyne.KeyBackslash: 0x5C,
// fyne.KeyLeftBracket: 0x5B,
// fyne.KeyRightBracket: 0x5D,
// fyne.KeySemicolon: 0x3B,
// fyne.KeyEqual: 0x3D,
// fyne.KeyAsterisk: 0x2A,
// fyne.KeyPlus: 0x2B,
// fyne.KeyBackTick: 0x60,
// fyne.KeyUnknown: 0x00,
//}
//
//var RemapKeyShift = map[fyne.KeyName]byte{
// fyne.KeyEscape: 0x1B,
// fyne.KeyReturn: 0x0A,
// fyne.KeyTab: 0x09,
// fyne.KeyBackspace: 0x08,
// fyne.KeyInsert: 0x00,
// fyne.KeyDelete: 0x08,
// fyne.KeyRight: 0x18,
// fyne.KeyLeft: 0x08,
// fyne.KeyDown: 0x0A,
// fyne.KeyUp: 0x19,
// fyne.KeyPageUp: 0x00,
// fyne.KeyPageDown: 0x00,
// fyne.KeyHome: 0x0C,
// fyne.KeyEnd: 0x1A,
// fyne.KeyF1: 0x00,
// fyne.KeyF2: 0x00,
// fyne.KeyF3: 0x00,
// fyne.KeyF4: 0x00,
// fyne.KeyF5: 0x00,
// fyne.KeyF6: 0x00,
// fyne.KeyF7: 0x00,
// fyne.KeyF8: 0x00,
// fyne.KeyF9: 0x00,
// fyne.KeyF10: 0x00,
// fyne.KeyF11: 0x00,
// fyne.KeyF12: 0x00,
// fyne.KeyEnter: 0x0D,
//
// fyne.Key0: 0x29,
// fyne.Key1: 0x21,
// fyne.Key2: 0x40,
// fyne.Key3: 0x23,
// fyne.Key4: 0x24,
// fyne.Key5: 0x25,
// fyne.Key6: 0x5E,
// fyne.Key7: 0x26,
// fyne.Key8: 0x2A,
// fyne.Key9: 0x28,
// fyne.KeyA: 0x41,
// fyne.KeyB: 0x42,
// fyne.KeyC: 0x43,
// fyne.KeyD: 0x44,
// fyne.KeyE: 0x45,
// fyne.KeyF: 0x46,
// fyne.KeyG: 0x47,
// fyne.KeyH: 0x48,
// fyne.KeyI: 0x49,
// fyne.KeyJ: 0x4a,
// fyne.KeyK: 0x4b,
// fyne.KeyL: 0x4c,
// fyne.KeyM: 0x4d,
// fyne.KeyN: 0x4e,
// fyne.KeyO: 0x4f,
// fyne.KeyP: 0x50,
// fyne.KeyQ: 0x51,
// fyne.KeyR: 0x52,
// fyne.KeyS: 0x53,
// fyne.KeyT: 0x54,
// fyne.KeyU: 0x55,
// fyne.KeyV: 0x56,
// fyne.KeyW: 0x57,
// fyne.KeyX: 0x58,
// fyne.KeyY: 0x59,
// fyne.KeyZ: 0x5A,
// fyne.KeySpace: 0x20,
// fyne.KeyApostrophe: 0x22,
// fyne.KeyComma: 0x3C,
// fyne.KeyMinus: 0x5F,
// fyne.KeyPeriod: 0x3E,
// fyne.KeySlash: 0x3F,
// fyne.KeyBackslash: 0x7C,
// fyne.KeyLeftBracket: 0x7B,
// fyne.KeyRightBracket: 0x7D,
// fyne.KeySemicolon: 0x3A,
// fyne.KeyEqual: 0x2B,
// fyne.KeyAsterisk: 0x7E,
// fyne.KeyPlus: 0x7E,
// fyne.KeyBackTick: 0x60,
//}

View File

@ -190,7 +190,7 @@ var instructions = []func(s *Z80Type){
},
// 0x22 : LD (nn), HL
0x22: func(s *Z80Type) {
addr := s.getAddr()
addr := s.nextWord()
s.core.MemWrite(addr, s.L)
s.core.MemWrite(addr+1, s.H)
},
@ -252,7 +252,7 @@ var instructions = []func(s *Z80Type){
},
// 0x2a : LD HL, (nn)
0x2A: func(s *Z80Type) {
addr := s.getAddr()
addr := s.nextWord()
s.L = s.core.MemRead(addr)
s.H = s.core.MemRead(addr + 1)
},
@ -293,7 +293,7 @@ var instructions = []func(s *Z80Type){
},
// 0x32 : LD (nn), A
0x32: func(s *Z80Type) {
s.core.MemWrite(s.getAddr(), s.A)
s.core.MemWrite(s.nextWord(), s.A)
},
// 0x33 : INC SP
0x33: func(s *Z80Type) {
@ -329,7 +329,7 @@ var instructions = []func(s *Z80Type){
},
// 0x3a : LD A, (nn)
0x3A: func(s *Z80Type) {
s.A = s.core.MemRead(s.getAddr())
s.A = s.core.MemRead(s.nextWord())
},
// 0x3b : DEC SP
0x3B: func(s *Z80Type) {
@ -648,10 +648,10 @@ var instructions = []func(s *Z80Type){
},
}
func (z *Z80Type) getAddr() uint16 {
func (z *Z80Type) nextWord() uint16 {
z.PC++
addr := uint16(z.core.MemRead(z.PC))
word := uint16(z.core.MemRead(z.PC))
z.PC++
addr |= uint16(z.core.MemRead(z.PC)) << 8
return addr
word |= uint16(z.core.MemRead(z.PC)) << 8
return word
}

View File

@ -1,7 +1,7 @@
package z80em
func (z *Z80Type) opcodeCB() {
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
z.incR()
z.PC++
opcode := z.core.M1MemRead(z.PC)
bitNumber := (opcode & 0x38) >> 3
@ -29,28 +29,30 @@ func (z *Z80Type) opcodeCB() {
}
} else if opcode < 0x80 {
// BIT instructions
mask := byte(1 << bitNumber)
switch regCode {
case 0:
z.Flags.Z = z.B&(1<<bitNumber) == 0
z.Flags.Z = z.B&mask == 0
case 1:
z.Flags.Z = z.C&(1<<bitNumber) == 0
z.Flags.Z = z.C&mask == 0
case 2:
z.Flags.Z = z.D&(1<<bitNumber) == 0
z.Flags.Z = z.D&mask == 0
case 3:
z.Flags.Z = z.E&(1<<bitNumber) == 0
z.Flags.Z = z.E&mask == 0
case 4:
z.Flags.Z = z.H&(1<<bitNumber) == 0
z.Flags.Z = z.H&mask == 0
case 5:
z.Flags.Z = z.L&(1<<bitNumber) == 0
z.Flags.Z = z.L&mask == 0
case 6:
z.Flags.Z = z.core.MemRead(z.hl())&(1<<bitNumber) == 0
z.Flags.Z = z.core.MemRead(z.hl())&mask == 0
default:
z.Flags.Z = z.A&(1<<bitNumber) == 0
z.Flags.Z = z.A&mask == 0
}
z.Flags.N = false
z.Flags.H = true
z.Flags.P = z.Flags.Z
z.Flags.S = (bitNumber == 7) && !z.Flags.Z
// TODO: ZXALL fail this
// For the BIT n, (HL) instruction, the X and Y flags are obtained
// from what is apparently an internal temporary register used for
// some of the 16-bit arithmetic instructions.

View File

@ -11,13 +11,11 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x21 : LD IX, nn
0x21: func(s *Z80Type) {
s.IX = s.getAddr()
s.IX = s.nextWord()
},
// 0x22 : LD (nn), IX
0x22: func(s *Z80Type) {
addr := s.getAddr()
s.core.MemWrite(addr, byte(s.IX&0x00ff))
s.core.MemWrite(addr+1, byte(s.IX>>8))
s.setWord(s.nextWord(), s.IX)
},
// 0x23 : INC IX
0x23: func(s *Z80Type) {
@ -42,8 +40,7 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x2a : LD IX, (nn)
0x2A: func(s *Z80Type) {
addr := s.getAddr()
s.IX = (uint16(s.core.MemRead(addr)) << 8) | uint16(s.core.MemRead(addr+1))
s.IX = s.getWord(s.nextWord())
},
// 0x2b : DEC IX
0x2B: func(s *Z80Type) {
@ -94,8 +91,7 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x46 : LD B, (IX+n)
0x46: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.B = s.core.MemRead(offset)
s.B = s.core.MemRead(s.getOffset(s.IX))
},
// 0x4c : LD C, IXH (Undocumented)
0x4C: func(s *Z80Type) {
@ -107,8 +103,7 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x4e : LD C, (IX+n)
0x4E: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.C = s.core.MemRead(offset)
s.C = s.core.MemRead(s.getOffset(s.IX))
},
// 0x54 : LD D, IXH (Undocumented)
0x54: func(s *Z80Type) {
@ -116,7 +111,7 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x55 : LD D, IXL (Undocumented)
0x55: func(s *Z80Type) {
s.D = byte(s.IX & 0x00ff)
s.D = byte(s.IX)
},
// 0x56 : LD D, (IX+n)
0x56: func(s *Z80Type) {
@ -125,12 +120,11 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x5d : LD E, IXL (Undocumented)
0x5D: func(s *Z80Type) {
s.E = byte(s.IX & 0x00ff)
s.E = byte(s.IX)
},
// 0x5e : LD E, (IX+n)
0x5E: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.E = s.core.MemRead(offset)
s.E = s.core.MemRead(s.getOffset(s.IX))
},
// 0x60 : LD IXH, B (Undocumented)
0x60: func(s *Z80Type) {
@ -158,8 +152,7 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x66 : LD H, (IX+n)
0x66: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.H = s.core.MemRead(offset)
s.H = s.core.MemRead(s.getOffset(s.IX))
},
// 0x67 : LD IXH, A (Undocumented)
0x67: func(s *Z80Type) {
@ -191,8 +184,7 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x6e : LD L, (IX+n)
0x6e: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.L = s.core.MemRead(offset)
s.L = s.core.MemRead(s.getOffset(s.IX))
},
// 0x6f : LD IXL, A (Undocumented)
0x6f: func(s *Z80Type) {
@ -200,38 +192,31 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x70 : LD (IX+n), B
0x70: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.core.MemWrite(offset, s.B)
s.core.MemWrite(s.getOffset(s.IX), s.B)
},
// 0x71 : LD (IX+n), C
0x71: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.core.MemWrite(offset, s.C)
s.core.MemWrite(s.getOffset(s.IX), s.C)
},
// 0x72 : LD (IX+n), D
0x72: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.core.MemWrite(offset, s.D)
s.core.MemWrite(s.getOffset(s.IX), s.D)
},
// 0x73 : LD (IX+n), E
0x73: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.core.MemWrite(offset, s.E)
s.core.MemWrite(s.getOffset(s.IX), s.E)
},
// 0x74 : LD (IX+n), H
0x74: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.core.MemWrite(offset, s.H)
s.core.MemWrite(s.getOffset(s.IX), s.H)
},
// 0x75 : LD (IX+n), L
0x75: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.core.MemWrite(offset, s.L)
s.core.MemWrite(s.getOffset(s.IX), s.L)
},
// 0x77 : LD (IX+n), A
0x77: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.core.MemWrite(offset, s.A)
s.core.MemWrite(s.getOffset(s.IX), s.A)
},
// 0x7c : LD A, IXH (Undocumented)
0x7C: func(s *Z80Type) {
@ -243,8 +228,7 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x7e : LD A, (IX+n)
0x7E: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.A = s.core.MemRead(offset)
s.A = s.core.MemRead(s.getOffset(s.IX))
},
// 0x84 : ADD A, IXH (Undocumented)
0x84: func(s *Z80Type) {
@ -252,12 +236,11 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x85 : ADD A, IXL (Undocumented)
0x85: func(s *Z80Type) {
s.doAdd(byte(s.IX & 0x00ff))
s.doAdd(byte(s.IX))
},
// 0x86 : ADD A, (IX+n)
0x86: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.doAdd(s.core.MemRead(offset))
s.doAdd(s.core.MemRead(s.getOffset(s.IX)))
},
// 0x8c : ADC A, IXH (Undocumented)
0x8C: func(s *Z80Type) {
@ -265,12 +248,11 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x8d : ADC A, IXL (Undocumented)
0x8D: func(s *Z80Type) {
s.doAdc(byte(s.IX & 0x00ff))
s.doAdc(byte(s.IX))
},
// 0x8e : ADC A, (IX+n)
0x8E: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.doAdc(s.core.MemRead(offset))
s.doAdc(s.core.MemRead(s.getOffset(s.IX)))
},
// 0x94 : SUB IXH (Undocumented)
0x94: func(s *Z80Type) {
@ -278,12 +260,11 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x95 : SUB IXL (Undocumented)
0x95: func(s *Z80Type) {
s.doSub(byte(s.IX & 0x00ff))
s.doSub(byte(s.IX))
},
// 0x96 : SUB A, (IX+n)
0x96: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.doSub(s.core.MemRead(offset))
s.doSub(s.core.MemRead(s.getOffset(s.IX)))
},
// 0x9c : SBC IXH (Undocumented)
0x9C: func(s *Z80Type) {
@ -291,12 +272,11 @@ var ddInstructions = []func(s *Z80Type){
},
// 0x9d : SBC IXL (Undocumented)
0x9D: func(s *Z80Type) {
s.doSbc(byte(s.IX & 0x00ff))
s.doSbc(byte(s.IX))
},
// 0x9e : SBC A, (IX+n)
0x9E: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.doSbc(s.core.MemRead(offset))
s.doSbc(s.core.MemRead(s.getOffset(s.IX)))
},
// 0xa4 : AND IXH (Undocumented)
0xA4: func(s *Z80Type) {
@ -304,12 +284,11 @@ var ddInstructions = []func(s *Z80Type){
},
// 0xa5 : AND IXL (Undocumented)
0xA5: func(s *Z80Type) {
s.doAnd(byte(s.IX & 0x00ff))
s.doAnd(byte(s.IX))
},
// 0xa6 : AND A, (IX+n)
0xA6: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.doAnd(s.core.MemRead(offset))
s.doAnd(s.core.MemRead(s.getOffset(s.IX)))
},
// 0xac : XOR IXH (Undocumented)
0xAC: func(s *Z80Type) {
@ -317,12 +296,11 @@ var ddInstructions = []func(s *Z80Type){
},
// 0xad : XOR IXL (Undocumented)
0xAD: func(s *Z80Type) {
s.doXor(byte(s.IX & 0x00ff))
s.doXor(byte(s.IX))
},
// 0xae : XOR A, (IX+n)
0xAE: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.doXor(s.core.MemRead(offset))
s.doXor(s.core.MemRead(s.getOffset(s.IX)))
},
// 0xb4 : OR IXH (Undocumented)
0xB4: func(s *Z80Type) {
@ -330,12 +308,11 @@ var ddInstructions = []func(s *Z80Type){
},
// 0xb5 : OR IXL (Undocumented)
0xB5: func(s *Z80Type) {
s.doOr(byte(s.IX & 0x00ff))
s.doOr(byte(s.IX))
},
// 0xb6 : OR A, (IX+n)
0xB6: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.doOr(s.core.MemRead(offset))
s.doOr(s.core.MemRead(s.getOffset(s.IX)))
},
// 0xbc : CP IXH (Undocumented)
0xBC: func(s *Z80Type) {
@ -343,12 +320,11 @@ var ddInstructions = []func(s *Z80Type){
},
// 0xbd : CP IXL (Undocumented)
0xBD: func(s *Z80Type) {
s.doCp(byte(s.IX & 0x00ff))
s.doCp(byte(s.IX))
},
// 0xbe : CP A, (IX+n)
0xBE: func(s *Z80Type) {
offset := s.getOffset(s.IX)
s.doCp(s.core.MemRead(offset))
s.doCp(s.core.MemRead(s.getOffset(s.IX)))
},
// 0xcb : CB Prefix (IX bit instructions)
0xCB: func(s *Z80Type) {
@ -360,11 +336,9 @@ var ddInstructions = []func(s *Z80Type){
},
// 0xe3 : EX (SP), IX
0xE3: func(s *Z80Type) {
temp := s.IX
s.IX = uint16(s.core.MemRead(s.SP))
s.IX |= uint16(s.core.MemRead(s.SP+1)) << 8
s.core.MemWrite(s.SP, byte(temp&0x00ff))
s.core.MemWrite(s.SP+1, byte(temp>>8))
ix := s.IX
s.IX = s.getWord(s.SP)
s.setWord(s.SP, ix)
},
// 0xe5 : PUSH IX
0xE5: func(s *Z80Type) {
@ -393,13 +367,12 @@ func (z *Z80Type) getOffset(reg uint16) uint16 {
}
func (z *Z80Type) opcodeDD() {
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
z.incR()
z.PC++
opcode := z.core.M1MemRead(z.PC)
fun := ddInstructions[opcode]
if fun != nil {
//func = func.bind(this);
fun(z)
z.CycleCounter += CycleCountsDd[opcode]
} else {
@ -481,3 +454,22 @@ func (z *Z80Type) opcodeDDCB() {
z.CycleCounter += CycleCountsCb[opcode] + 8
}
// opcodeFD do same for IY as for IX (DD prefix)
func (z *Z80Type) opcodeFD() {
z.incR()
z.PC++
opcode := z.core.M1MemRead(z.PC)
fun := ddInstructions[opcode]
if fun != nil {
var temp = z.IX
z.IX = z.IY
fun(z)
z.IY = z.IX
z.IX = temp
z.CycleCounter += CycleCountsDd[opcode]
} else {
z.PC--
z.CycleCounter += CycleCounts[0]
}
}

View File

@ -3,21 +3,19 @@ package z80em
var edInstructions = []func(s *Z80Type){
// 0x40 : IN B, (C)
0x40: func(s *Z80Type) {
s.B = s.doIn((uint16(s.B) << 8) | uint16(s.C))
s.B = s.doIn(s.bc())
},
// 0x41 : OUT (C), B
0x41: func(s *Z80Type) {
s.core.IOWrite((uint16(s.B)<<8)|uint16(s.C), s.B)
s.core.IOWrite(s.bc(), s.B)
},
// 0x42 : SBC HL, BC
0x42: func(s *Z80Type) {
s.doHlSbc(uint16(s.C) | (uint16(s.B) << 8))
s.doHlSbc(s.bc())
},
// 0x43 : LD (nn), BC
0x43: func(s *Z80Type) {
addr := s.getAddr()
s.core.MemWrite(addr, s.C)
s.core.MemWrite(addr+1, s.B)
s.setWord(s.nextWord(), s.bc())
},
// 0x44 : NEG
0x44: func(s *Z80Type) {
@ -50,9 +48,7 @@ var edInstructions = []func(s *Z80Type){
},
// 0x4b : LD BC, (nn)
0x4B: func(s *Z80Type) {
addr := s.getAddr()
s.C = s.core.MemRead(addr)
s.B = s.core.MemRead(addr + 1)
s.setBc(s.getWord(s.nextWord()))
},
// 0x4c : NEG (Undocumented)
0x4C: func(s *Z80Type) {
@ -84,9 +80,7 @@ var edInstructions = []func(s *Z80Type){
},
// 0x53 : LD (nn), DE
0x53: func(s *Z80Type) {
addr := s.getAddr()
s.core.MemWrite(addr, s.E)
s.core.MemWrite(addr+1, s.D)
s.setWord(s.nextWord(), s.de())
},
// 0x54 : NEG (Undocumented)
0x54: func(s *Z80Type) {
@ -126,9 +120,7 @@ var edInstructions = []func(s *Z80Type){
},
// 0x5b : LD DE, (nn)
0x5B: func(s *Z80Type) {
addr := s.getAddr()
s.E = s.core.MemRead(addr)
s.D = s.core.MemRead(addr + 1)
s.setDe(s.getWord(s.nextWord()))
},
// 0x5c : NEG (Undocumented)
0x5C: func(s *Z80Type) {
@ -168,9 +160,7 @@ var edInstructions = []func(s *Z80Type){
},
// 0x63 : LD (nn), HL (Undocumented)
0x63: func(s *Z80Type) {
addr := s.getAddr()
s.core.MemWrite(addr, s.L)
s.core.MemWrite(addr+1, s.H)
s.setWord(s.nextWord(), s.hl())
},
// 0x64 : NEG (Undocumented)
0x64: func(s *Z80Type) {
@ -215,9 +205,7 @@ var edInstructions = []func(s *Z80Type){
},
// 0x6b : LD HL, (nn) (Undocumented)
0x6B: func(s *Z80Type) {
addr := s.getAddr()
s.L = s.core.MemRead(addr)
s.H = s.core.MemRead(addr + 1)
s.setHl(s.getWord(s.nextWord()))
},
// 0x6C : NEG (Undocumented)
0x6C: func(s *Z80Type) {
@ -262,9 +250,7 @@ var edInstructions = []func(s *Z80Type){
},
// 0x73 : LD (nn), SP
0x73: func(s *Z80Type) {
addr := s.getAddr()
s.core.MemWrite(addr, byte(s.SP&0x00ff))
s.core.MemWrite(addr+1, byte(s.SP>>8))
s.setWord(s.nextWord(), s.SP)
},
// 0x74 : NEG (Undocumented)
0x74: func(s *Z80Type) {
@ -293,9 +279,7 @@ var edInstructions = []func(s *Z80Type){
},
// 0x7b : LD SP, (nn)
0x7B: func(s *Z80Type) {
addr := s.getAddr()
s.SP = uint16(s.core.MemRead(addr))
s.SP |= uint16(s.core.MemRead(addr+1)) << 8
s.SP = s.getWord(s.nextWord())
},
// 0x7c : NEG (Undocumented)
0x7C: func(s *Z80Type) {
@ -409,7 +393,7 @@ var edInstructions = []func(s *Z80Type){
}
func (z *Z80Type) opcodeED() {
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
z.incR()
z.PC++
opcode := z.core.M1MemRead(z.PC)

View File

@ -52,7 +52,7 @@ type Z80Type struct {
}
type MemIoRW interface {
// M1MemRead Read byte from memory for specified address
// M1MemRead Read byte from memory for specified address @ M1 cycle
M1MemRead(addr uint16) byte
// MemRead Read byte from memory for specified address
MemRead(addr uint16) byte
@ -198,12 +198,7 @@ func New(memIoRW MemIoRW) *Z80Type {
func (z *Z80Type) RunInstruction() byte {
// R is incremented at the start of every instruction cycle,
// before the instruction actually runs.
// The high bit of R is not affected by this increment,
// it can only be changed using the LD R, A instruction.
// Note: also a HALT does increment the R register.
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
z.incR()
if !z.Halted {
// If the previous instruction was a DI or an EI,
@ -242,11 +237,13 @@ func (z *Z80Type) RunInstruction() byte {
cycleCounter := z.CycleCounter
z.CycleCounter = 0
return cycleCounter
} else { // HALTED
}
// HALTED
// During HALT, NOPs are executed which is 4T
z.core.M1MemRead(z.PC) // HALT does a normal M1 fetch to keep the memory refresh active. The result is ignored (NOP).
return 4
}
}
// Simulates pulsing the processor's INT (or NMI) pin
@ -262,7 +259,7 @@ func (z *Z80Type) interrupt(nonMaskable bool, data byte) {
// The high bit of R is not affected by this increment,
// it can only be changed using the LD R, A instruction.
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
z.incR()
// Non-maskable interrupts are always handled the same way;
// clear IFF1 and then do a CALL 0x0066.
@ -283,7 +280,7 @@ func (z *Z80Type) interrupt(nonMaskable bool, data byte) {
// The high bit of R is not affected by this increment,
// it can only be changed using the LD R,A instruction.
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
z.incR()
z.Halted = false
z.Iff1 = 0
@ -312,7 +309,7 @@ func (z *Z80Type) interrupt(nonMaskable bool, data byte) {
// but it doesn't appear that this is actually the case on the hardware,
// so we don't attempt to enforce that here.
vectorAddress := (uint16(z.I) << 8) | uint16(data)
z.PC = uint16(z.core.MemRead(vectorAddress)) | (uint16(z.core.MemRead(vectorAddress+1)) << 8)
z.PC = z.getWord(vectorAddress) //uint16( z.core.MemRead(vectorAddress)) | (uint16(z.core.MemRead(vectorAddress+1)) << 8)
z.CycleCounter += 19
// A "notification" is generated so that the calling program can break on it.
z.interruptOccurred = true
@ -342,7 +339,7 @@ func (z *Z80Type) getOperand(opcode byte) byte {
case 5:
return z.L
case 6:
return z.core.MemRead(uint16(z.H)<<8 | uint16(z.L))
return z.core.MemRead(z.hl())
default:
return z.A
}
@ -381,7 +378,7 @@ func (z *Z80Type) load8bit(opcode byte, operand byte) {
case 5:
z.L = operand
case 6:
z.core.MemWrite(uint16(z.H)<<8|uint16(z.L), operand)
z.core.MemWrite(z.hl(), operand)
default:
z.A = operand
}
@ -409,10 +406,6 @@ func (z *Z80Type) alu8bit(opcode byte, operand byte) {
}
}
func (z *Z80Type) otherInstructions(opcode byte) {
}
// getFlagsRegister return whole F register
func (z *Z80Type) getFlagsRegister() byte {
return getFlags(&z.Flags)
@ -478,10 +471,6 @@ func (z *Z80Type) updateXYFlags(result byte) {
z.Flags.X = result&0x08 != 0
}
func getParity(value byte) bool {
return ParityBits[value]
}
// PushWord - Decrement stack pointer and put specified word value to stack
func (z *Z80Type) PushWord(operand uint16) {
z.SP--
@ -507,8 +496,7 @@ func (z *Z80Type) doConditionalAbsoluteJump(condition bool) {
// because the instruction decoder increments the PC
// unconditionally at the end of every instruction,
// and we need to counteract that so we end up at the jump target.
// TODO: Check for increment CycleCounter
z.PC = uint16(z.core.MemRead(z.PC+1)) | (uint16(z.core.MemRead(z.PC+2)) << 8)
z.PC = z.getWord(z.PC + 1) //uint16( z.core.MemRead(z.PC+1)) | (uint16(z.core.MemRead(z.PC+2)) << 8)
z.PC--
} else {
// We're not taking this jump, just move the PC past the operand.
@ -540,7 +528,7 @@ func (z *Z80Type) doConditionalCall(condition bool) {
if condition {
z.CycleCounter += 7
z.PushWord(z.PC + 3)
z.PC = uint16(z.core.MemRead(z.PC+1)) | (uint16(z.core.MemRead(z.PC+2)) << 8)
z.PC = z.getWord(z.PC + 1) // uint16( z.core.MemRead(z.PC+1)) | (uint16(z.core.MemRead(z.PC+2)) << 8)
z.PC--
} else {
z.PC += 2
@ -560,16 +548,6 @@ func (z *Z80Type) doReset(address uint16) {
z.PC = address - 1
}
//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) {
var result = uint16(z.A) + uint16(operand)
@ -585,6 +563,7 @@ func (z *Z80Type) doAdd(operand byte) {
z.updateXYFlags(z.A)
}
// doAdc Handle ADC A, [operand] instructions.
func (z *Z80Type) doAdc(operand byte) {
add := byte(0)
if z.Flags.C {
@ -603,6 +582,7 @@ func (z *Z80Type) doAdc(operand byte) {
z.updateXYFlags(z.A)
}
// doSub Handle SUB A, [operand] instructions.
func (z *Z80Type) doSub(operand byte) {
var result = uint16(z.A) - uint16(operand)
@ -617,6 +597,7 @@ func (z *Z80Type) doSub(operand byte) {
z.updateXYFlags(z.A)
}
// doSbc Handle SBC A, [operand] instructions.
func (z *Z80Type) doSbc(operand byte) {
sub := byte(0)
if z.Flags.C {
@ -635,6 +616,7 @@ func (z *Z80Type) doSbc(operand byte) {
z.updateXYFlags(z.A)
}
// setLogicFlags Set common flags for logic ALU Ops
func (z *Z80Type) setLogicFlags() {
z.Flags.S = z.A&0x80 != 0
z.Flags.Z = z.A == 0
@ -643,6 +625,7 @@ func (z *Z80Type) setLogicFlags() {
z.Flags.C = false
}
// doAnd handle AND [operand] instructions.
func (z *Z80Type) doAnd(operand byte) {
z.A &= operand
z.setLogicFlags()
@ -650,6 +633,7 @@ func (z *Z80Type) doAnd(operand byte) {
z.updateXYFlags(z.A)
}
// doXor handle XOR [operand] instructions.
func (z *Z80Type) doXor(operand byte) {
z.A ^= operand
z.setLogicFlags()
@ -657,6 +641,7 @@ func (z *Z80Type) doXor(operand byte) {
z.updateXYFlags(z.A)
}
// doOr handle OR [operand] instructions.
func (z *Z80Type) doOr(operand byte) {
z.A |= operand
z.setLogicFlags()
@ -664,6 +649,7 @@ func (z *Z80Type) doOr(operand byte) {
z.updateXYFlags(z.A)
}
// doCp handle CP [operand] instructions.
func (z *Z80Type) doCp(operand byte) {
tmp := z.A
z.doSub(operand)
@ -671,6 +657,7 @@ func (z *Z80Type) doCp(operand byte) {
z.updateXYFlags(operand)
}
// doInc handle INC [operand] instructions.
func (z *Z80Type) doInc(operand byte) byte {
var result = uint16(operand) + 1
r8 := byte(result & 0xff)
@ -685,6 +672,7 @@ func (z *Z80Type) doInc(operand byte) byte {
return r8
}
// doDec handle DEC [operand] instructions.
func (z *Z80Type) doDec(operand byte) byte {
var result = uint16(operand) - 1
r8 := byte(result & 0xff)
@ -699,27 +687,30 @@ func (z *Z80Type) doDec(operand byte) byte {
return r8
}
// doHlAdd handle ADD HL,[operand] instructions.
func (z *Z80Type) doHlAdd(operand uint16) {
// The HL arithmetic instructions are the same as the A ones,
// just with twice as many bits happening.
hl := uint16(z.L) | (uint16(z.H) << 8)
hl := z.hl() //uint16(z.L) | (uint16(z.H) << 8)
result := uint32(hl) + uint32(operand)
z.Flags.N = false
z.Flags.C = result > 0xffff
z.Flags.H = ((hl&0x0fff)+(operand&0x0fff))&0x1000 > 0
z.L = byte(result & 0xff)
z.H = byte((result & 0xff00) >> 8)
z.setHl(uint16(result))
//z.L = byte(result & 0xff)
//z.H = byte((result & 0xff00) >> 8)
z.updateXYFlags(z.H)
}
// doHlAdc handle ADC HL,[operand] instructions.
func (z *Z80Type) doHlAdc(operand uint16) {
if z.Flags.C {
operand++
}
hl := uint16(z.L) | (uint16(z.H) << 8)
hl := z.hl()
result := uint32(hl) + uint32(operand)
z.Flags.S = (result & 0x8000) != 0
@ -729,18 +720,20 @@ func (z *Z80Type) doHlAdc(operand uint16) {
z.Flags.N = false
z.Flags.C = result > 0xffff
z.L = byte(result & 0xff)
z.H = byte((result & 0xff00) >> 8)
z.setHl(uint16(result))
//z.L = byte(result & 0xff)
//z.H = byte((result & 0xff00) >> 8)
z.updateXYFlags(z.H)
}
// doHlSbc handle SBC HL,[operand] instructions.
func (z *Z80Type) doHlSbc(operand uint16) {
if z.Flags.C {
operand++
}
hl := uint16(z.L) | (uint16(z.H) << 8)
hl := z.hl() //uint16(z.L) | (uint16(z.H) << 8)
result := uint32(hl) - uint32(operand)
z.Flags.S = (result & 0x8000) != 0
@ -750,8 +743,9 @@ func (z *Z80Type) doHlSbc(operand uint16) {
z.Flags.N = true
z.Flags.C = result > 0xffff
z.L = byte(result & 0xff)
z.H = byte((result & 0xff00) >> 8)
z.setHl(uint16(result))
//z.L = byte(result & 0xff)
//z.H = byte((result & 0xff00) >> 8)
z.updateXYFlags(z.H)
}
@ -786,10 +780,8 @@ func (z *Z80Type) doNeg() {
func (z *Z80Type) doLdi() {
// Copy the value that we're supposed to copy.
hl := uint16(z.L) | (uint16(z.H) << 8)
de := uint16(z.E) | (uint16(z.D) << 8)
readValue := z.core.MemRead(hl)
z.core.MemWrite(de, readValue)
readValue := z.core.MemRead(z.hl())
z.core.MemWrite(z.de(), readValue)
z.incDe()
z.incHl()
@ -802,63 +794,49 @@ func (z *Z80Type) doLdi() {
z.Flags.X = ((z.A+readValue)&0x08)>>3 != 0
}
func (z *Z80Type) fhv() byte {
if z.Flags.H {
return 1
}
return 0
}
func (z *Z80Type) doCpi() {
tempCarry := z.Flags.C
hl := uint16(z.L) | (uint16(z.H) << 8)
readValue := z.core.MemRead(hl)
readValue := z.core.MemRead(z.hl())
z.doCp(readValue)
z.Flags.C = tempCarry
var fh byte = 0
if z.Flags.H {
fh = 1
}
fh := z.fhv()
z.Flags.Y = ((z.A-readValue-fh)&0x02)>>1 != 0
z.Flags.X = ((z.A-readValue-fh)&0x08)>>3 != 0
z.incHl()
z.decBc()
z.Flags.P = (z.B | z.C) != 0
}
func (z *Z80Type) doIni() {
hl := (uint16(z.H) << 8) | uint16(z.L)
bc := (uint16(z.B) << 8) | uint16(z.C)
z.core.MemWrite(hl, z.core.IORead(bc))
z.core.MemWrite(z.hl(), z.core.IORead(z.bc()))
z.incHl()
z.B = z.doDec(z.B)
z.Flags.N = true
}
func (z *Z80Type) doOuti() {
// Zilog pseudo code is wrong, see: https://github.com/maziac/z80-instruction-set/pull/10
z.B = z.doDec(z.B)
hl := (uint16(z.H) << 8) | uint16(z.L)
bc := (uint16(z.B) << 8) | uint16(z.C)
z.core.IOWrite(bc, z.core.MemRead(hl))
z.core.IOWrite(z.bc(), z.core.MemRead(z.hl()))
z.incHl()
z.Flags.N = true
}
func (z *Z80Type) doLdd() {
z.Flags.N = false
z.Flags.H = false
hl := (uint16(z.H) << 8) | uint16(z.L)
de := (uint16(z.D) << 8) | uint16(z.E)
readValue := z.core.MemRead(hl)
z.core.MemWrite(de, readValue)
readValue := z.core.MemRead(z.hl())
z.core.MemWrite(z.de(), readValue)
z.decDe()
z.decHl()
z.decBc()
z.Flags.P = (z.C | z.B) != 0
z.Flags.Y = ((z.A+readValue)&0x02)>>1 != 0
z.Flags.X = ((z.A+readValue)&0x08)>>3 != 0
@ -866,16 +844,12 @@ func (z *Z80Type) doLdd() {
func (z *Z80Type) doCpd() {
tempCarry := z.Flags.C
hl := uint16(z.L) | (uint16(z.H) << 8)
readValue := z.core.MemRead(hl)
readValue := z.core.MemRead(z.hl())
z.doCp(readValue)
z.Flags.C = tempCarry
var fh byte = 0
if z.Flags.H {
fh = 1
}
fh := z.fhv()
z.Flags.Y = ((z.A-readValue-fh)&0x02)>>1 != 0
z.Flags.X = ((z.A-readValue-fh)&0x08)>>3 != 0
@ -887,20 +861,15 @@ func (z *Z80Type) doCpd() {
}
func (z *Z80Type) doInd() {
hl := (uint16(z.H) << 8) | uint16(z.L)
bc := (uint16(z.B) << 8) | uint16(z.C)
z.core.MemWrite(hl, z.core.IORead(bc))
z.core.MemWrite(z.hl(), z.core.IORead(z.bc()))
z.decHl()
z.B = z.doDec(z.B)
z.Flags.N = true
}
func (z *Z80Type) doOutd() {
// Zilog pseudo code is wrong, see: https://github.com/maziac/z80-instruction-set/pull/10
z.B = z.doDec(z.B)
hl := (uint16(z.H) << 8) | uint16(z.L)
bc := (uint16(z.B) << 8) | uint16(z.C)
z.core.IOWrite(bc, z.core.MemRead(hl))
z.core.IOWrite(z.bc(), z.core.MemRead(z.hl()))
z.decHl()
z.Flags.N = true
}
@ -999,29 +968,6 @@ func (z *Z80Type) setShiftFlags(operand byte) {
z.updateXYFlags(operand)
}
//type Operation func()
func (z *Z80Type) opcodeFD() {
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
z.PC++
opcode := z.core.M1MemRead(z.PC)
fun := ddInstructions[opcode]
if fun != nil {
// Rather than copy and paste all the IX instructions into IY instructions,
// what we'll do is sneakily copy IY into IX, run the IX instruction,
// and then copy the result into IY and restore the old IX.
var temp = z.IX
z.IX = z.IY
fun(z)
z.IY = z.IX
z.IX = temp
z.CycleCounter += CycleCountsDd[opcode]
} else {
z.PC--
z.CycleCounter += CycleCounts[0]
}
}
// ============== get register pairs
func (z *Z80Type) bc() uint16 {
@ -1039,58 +985,58 @@ func (z *Z80Type) hl() uint16 {
// ============ helper fn
func (z *Z80Type) incBc() {
z.changeBc(+1)
z.setBc(z.bc() + 1)
}
func (z *Z80Type) decBc() {
z.changeBc(-1)
}
func (z *Z80Type) incHl() {
z.changeHl(+1)
}
func (z *Z80Type) decHl() {
z.changeHl(-1)
z.setBc(z.bc() - 1)
}
func (z *Z80Type) incDe() {
z.changeDe(+1)
z.setDe(z.de() + 1)
}
func (z *Z80Type) decDe() {
z.changeDe(-1)
z.setDe(z.de() - 1)
}
func (z *Z80Type) changeDe(val int8) {
de := (uint16(z.D) << 8) | uint16(z.E)
if val < 0 {
de--
} else {
de++
}
z.E = byte(de & 0xff)
z.D = byte(de >> 8)
func (z *Z80Type) incHl() {
z.setHl(z.hl() + 1)
}
func (z *Z80Type) changeBc(val int8) {
bc := (uint16(z.B) << 8) | uint16(z.C)
if val < 0 {
bc--
} else {
bc++
}
z.C = byte(bc & 0x00ff)
z.B = byte(bc >> 8)
func (z *Z80Type) decHl() {
z.setHl(z.hl() - 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 >> 8)
func (z *Z80Type) setHl(val uint16) {
z.L = byte(val & 0xff)
z.H = byte(val >> 8)
}
func (z *Z80Type) setDe(val uint16) {
z.E = byte(val & 0xff)
z.D = byte(val >> 8)
}
func (z *Z80Type) setBc(val uint16) {
z.C = byte(val & 0xff)
z.B = byte(val >> 8)
}
// incR Increment R at the start of every instruction cycle.
// The high bit of R is not affected by this increment,
// it can only be changed using the LD R, A instruction.
// Note: also a HALT does increment the R register.
func (z *Z80Type) incR() {
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
}
// getWord Return 16bit value from memory by specified address
func (z *Z80Type) getWord(address uint16) uint16 {
return (uint16(z.core.MemRead(address+1)) << 8) | uint16(z.core.MemRead(address))
}
func (z *Z80Type) setWord(address uint16, value uint16) {
z.core.MemWrite(address, byte(value))
z.core.MemWrite(address+1, byte(value>>8))
}