mirror of
https://github.com/romychs/Ocean-240.2-Emulator.git
synced 2026-04-21 11:03:21 +03:00
z80 emulator refactoring and fixes
This commit is contained in:
parent
fe19e5c8c7
commit
eb4339b86a
39
main.go
39
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/zexall.com
|
//go:embed bin/TET.COM
|
||||||
var ramBytes []byte
|
var ramBytes []byte
|
||||||
|
|
||||||
var needReset = false
|
var needReset = false
|
||||||
@ -47,14 +47,14 @@ func main() {
|
|||||||
computer.SetSerialBytes(serialBytes)
|
computer.SetSerialBytes(serialBytes)
|
||||||
computer.LoadFloppy()
|
computer.LoadFloppy()
|
||||||
|
|
||||||
w, raster, label := mainWindow(computer, conf)
|
w, raster, label := mainWindow(computer)
|
||||||
|
|
||||||
go emulator(computer)
|
go emulator(computer)
|
||||||
go screen(computer, raster, label, conf)
|
go screen(computer, raster, label, conf)
|
||||||
(*w).ShowAndRun()
|
(*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()
|
emulatorApp := app.New()
|
||||||
w := emulatorApp.NewWindow("Океан 240.2")
|
w := emulatorApp.NewWindow("Океан 240.2")
|
||||||
w.Canvas().SetOnTypedKey(
|
w.Canvas().SetOnTypedKey(
|
||||||
@ -107,9 +107,9 @@ func mainWindow(computer *okean240.ComputerType, emuConfig *config.OkEmuConfig)
|
|||||||
widget.NewButton("RUN", func() {
|
widget.NewButton("RUN", func() {
|
||||||
computer.SetRamBytes(ramBytes)
|
computer.SetRamBytes(ramBytes)
|
||||||
}),
|
}),
|
||||||
widget.NewButton("DUMP", func() {
|
//widget.NewButton("DUMP", func() {
|
||||||
computer.Dump(0x399, 15000)
|
// computer.Dump(0x399, 15000)
|
||||||
}),
|
//}),
|
||||||
widget.NewSeparator(),
|
widget.NewSeparator(),
|
||||||
widget.NewButton("Reset", func() {
|
widget.NewButton("Reset", func() {
|
||||||
needReset = true
|
needReset = true
|
||||||
@ -138,10 +138,6 @@ func screen(computer *okean240.ComputerType, raster *canvas.Raster, label *widge
|
|||||||
var freq uint64 = 0
|
var freq uint64 = 0
|
||||||
|
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
if needReset {
|
|
||||||
computer.Reset(emuConfig)
|
|
||||||
needReset = false
|
|
||||||
}
|
|
||||||
frame++
|
frame++
|
||||||
// redraw screen here
|
// redraw screen here
|
||||||
fyne.Do(func() {
|
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) {
|
func emulator(computer *okean240.ComputerType) {
|
||||||
ticker := time.NewTicker(133 * time.Nanosecond)
|
ticker := time.NewTicker(66 * time.Nanosecond)
|
||||||
var ticks = 0
|
var ticks = 0
|
||||||
var ticksCPU = 0
|
var nextClock = ticks + ticksPerTicker
|
||||||
|
//var ticksCPU = 3
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
time.Sleep(133 * time.Nanosecond)
|
//for {
|
||||||
|
//time.Sleep(133 * time.Nanosecond)
|
||||||
ticks++
|
ticks++
|
||||||
if ticks%5 == 0 {
|
if ticks%10 == 0 {
|
||||||
// 1.5 MHz
|
// 1.5 MHz
|
||||||
computer.TimerClk()
|
computer.TimerClk()
|
||||||
}
|
}
|
||||||
if ticks > ticksCPU {
|
if ticks >= nextClock {
|
||||||
ticksCPU = ticks + computer.Do()*2
|
nextClock = ticks + computer.Do()*ticksPerTicker
|
||||||
}
|
}
|
||||||
|
if needReset {
|
||||||
|
computer.Reset()
|
||||||
|
needReset = false
|
||||||
|
}
|
||||||
|
//if ticks > ticksCPU {
|
||||||
|
//ticksCPU = ticks + computer.Do()*2
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package okean240
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"encoding/binary"
|
|
||||||
"image/color"
|
"image/color"
|
||||||
"okemu/config"
|
"okemu/config"
|
||||||
"okemu/okean240/fdc"
|
"okemu/okean240/fdc"
|
||||||
@ -10,7 +9,6 @@ import (
|
|||||||
"okemu/okean240/pit"
|
"okemu/okean240/pit"
|
||||||
"okemu/okean240/usart"
|
"okemu/okean240/usart"
|
||||||
"okemu/z80em"
|
"okemu/z80em"
|
||||||
"os"
|
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@ -54,7 +52,7 @@ type ComputerInterface interface {
|
|||||||
PutCtrlKey(shortcut fyne.Shortcut)
|
PutCtrlKey(shortcut fyne.Shortcut)
|
||||||
SaveFloppy()
|
SaveFloppy()
|
||||||
LoadFloppy()
|
LoadFloppy()
|
||||||
Dump(start uint16, length uint16)
|
//Dump(start uint16, length uint16)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ComputerType) M1MemRead(addr uint16) byte {
|
func (c *ComputerType) M1MemRead(addr uint16) byte {
|
||||||
@ -97,20 +95,17 @@ func New(cfg *config.OkEmuConfig) *ComputerType {
|
|||||||
return &c
|
return &c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ComputerType) Reset(cfg *config.OkEmuConfig) {
|
func (c *ComputerType) Reset() {
|
||||||
c.cpu.Reset()
|
c.cpu.Reset()
|
||||||
c.cycles = 0
|
c.cycles = 0
|
||||||
c.vShift = 0
|
//c.vShift = 0
|
||||||
c.hShift = 0
|
//c.hShift = 0
|
||||||
|
//c.memory = Memory{}
|
||||||
c.memory = Memory{}
|
//c.memory.Init(cfg.MonitorFile, cfg.CPMFile)
|
||||||
c.memory.Init(cfg.MonitorFile, cfg.CPMFile)
|
//c.dd17EnableOut = false
|
||||||
|
//c.screenWidth = 256
|
||||||
c.cycles = 0
|
//c.screenHeight = 256
|
||||||
c.dd17EnableOut = false
|
//c.vRAM = c.memory.allMemory[3]
|
||||||
c.screenWidth = 512
|
|
||||||
c.screenHeight = 256
|
|
||||||
c.vRAM = c.memory.allMemory[3]
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,25 +245,25 @@ func (c *ComputerType) SetRamBytes(bytes []byte) {
|
|||||||
//c.cpu.PC = 0x100
|
//c.cpu.PC = 0x100
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ComputerType) Dump(start uint16, length uint16) {
|
//func (c *ComputerType) Dump(start uint16, length uint16) {
|
||||||
file, err := os.Create("dump.dat")
|
// file, err := os.Create("dump.dat")
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
log.Error(err)
|
// log.Error(err)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
defer func(file *os.File) {
|
// defer func(file *os.File) {
|
||||||
err := file.Close()
|
// err := file.Close()
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
log.Error(err)
|
// log.Error(err)
|
||||||
}
|
// }
|
||||||
}(file)
|
// }(file)
|
||||||
|
//
|
||||||
var buffer []byte
|
// var buffer []byte
|
||||||
for addr := 0; addr < 65535; addr++ {
|
// for addr := 0; addr < 65535; addr++ {
|
||||||
buffer = append(buffer, c.memory.MemRead(uint16(addr)))
|
// buffer = append(buffer, c.memory.MemRead(uint16(addr)))
|
||||||
}
|
// }
|
||||||
err = binary.Write(file, binary.LittleEndian, buffer)
|
// err = binary.Write(file, binary.LittleEndian, buffer)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
log.Error("Save memory dump failed:", err)
|
// log.Error("Save memory dump failed:", err)
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|||||||
@ -5,154 +5,151 @@ package okean240
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// USR_DD79PA User port A
|
// USR_DD79PA User port A
|
||||||
const USR_DD79PA = 0x00
|
//const USR_DD79PA = 0x00
|
||||||
|
|
||||||
// USR_DD79PB User port B
|
// USR_DD79PB User port B
|
||||||
const USR_DD79PB = 0x01
|
//const USR_DD79PB = 0x01
|
||||||
|
|
||||||
// USR_DD79PC User port C
|
// USR_DD79PC User port C
|
||||||
const USR_DD79PC = 0x02
|
//const USR_DD79PC = 0x02
|
||||||
|
|
||||||
// USR_DD79CTR Config
|
// 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]
|
// Set bit: [0][xxx][bbb][0|1]
|
||||||
|
//const USR_DD79CTR = 0x03
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* КР1818ВГ93 FDC Controller
|
* КР1818ВГ93 FDC Controller
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// FDC_CMD FDC Command
|
// FdcCmd FDC Command
|
||||||
const FDC_CMD = 0x20
|
const FdcCmd = 0x20
|
||||||
|
|
||||||
// FDC_TRACK FDC Track No
|
// FdcTrack FDC Track No
|
||||||
const FDC_TRACK = 0x21
|
const FdcTrack = 0x21
|
||||||
|
|
||||||
// FDC_SECT FDC Sector
|
// FdcSect FDC Sector
|
||||||
const FDC_SECT = 0x22
|
const FdcSect = 0x22
|
||||||
|
|
||||||
// FDC_DATA FDC Data
|
// FdcData FDC Data
|
||||||
const FDC_DATA = 0x23
|
const FdcData = 0x23
|
||||||
|
|
||||||
// FDC_DRQ Read DRQ state from FDC
|
// FdcDrq Read DRQ state from FDC
|
||||||
const FDC_DRQ = 0x24
|
const FdcDrq = 0x24
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Floppy Controller port
|
* Floppy Controller port
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// FLOPPY Floppy Controller port
|
// Floppy Controller port
|
||||||
const FLOPPY = 0x25 // WR: 5-SSEN, 4-#DDEN, 3-INIT, 2-DRSEL, 1-MOT1, 0-MOT0
|
// 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
|
// RD: 7-MOTST, 6-SSEL, 5,4-x , 3-DRSEL, 2-MOT1, 1-MOT0, 0-INT
|
||||||
|
const Floppy = 0x25
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* КР580ВВ55 DD78 Keyboard
|
* КР580ВВ55 DD78 Keyboard
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// KBD_DD78PA Port A - Keyboard Data
|
// KbdDd78pa Port A - Keyboard Data
|
||||||
const KBD_DD78PA = 0x40
|
const KbdDd78pa = 0x40
|
||||||
|
|
||||||
// KBD_DD78PB Port B - JST3,SHFT,CTRL,ACK,TAPE5,TAPE4,GK,GC
|
// KbdDd78pb Port B - JST3,SHFT,CTRL,ACK,TAPE5,TAPE4,GK,GC
|
||||||
const KBD_DD78PB = 0x41
|
const KbdDd78pb = 0x41
|
||||||
|
|
||||||
// KBD_DD78PC Port C - [PC7:5],[KBD_ACK],[PC3:0]
|
// KBD_DD78PC Port C - [PC7:5],[KBD_ACK],[PC3:0]
|
||||||
const KBD_DD78PC = 0x42
|
//const KBD_DD78PC = 0x42
|
||||||
|
|
||||||
// KBD_DD78CTR Control port
|
// 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]
|
// Set bit: [0][xxx][bbb][0|1]
|
||||||
|
// const KBD_DD78CTR = 0x43
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* КР580ВИ53 DD70
|
* КР580ВИ53 DD70
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TMR_DD70C1 Timer load 1
|
// TmrDd70c1 Timer load 1
|
||||||
const TMR_DD70C1 = 0x60
|
const TmrDd70c1 = 0x60
|
||||||
|
|
||||||
// TMR_DD70C2 Timer load 2
|
// TmrDd70c2 Timer load 2
|
||||||
const TMR_DD70C2 = 0x61
|
const TmrDd70c2 = 0x61
|
||||||
|
|
||||||
// TMR_DD70C3 Timer load 3
|
// TmrDd70c3 Timer load 3
|
||||||
const TMR_DD70C3 = 0x62
|
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
|
* Programmable Interrupt controller PIC КР580ВН59
|
||||||
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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const RstKbdNo = 1
|
const RstKbdNo = 1
|
||||||
const RstTimerNo = 4
|
const RstTimerNo = 4
|
||||||
|
|
||||||
const Rst0Mask = 0x01 // System interrupt
|
//const Rst0Mask = 0x01 // System interrupt
|
||||||
const Rst1Mask = 0x02 // Keyboard interrupt
|
//const Rst1Mask = 0x02 // Keyboard interrupt
|
||||||
const Rst2Mask = 0x04 // Serial interface interrupt
|
//const Rst2Mask = 0x04 // Serial interface interrupt
|
||||||
const RstЗMask = 0x08 // Printer ready
|
//const Rst3Mask = 0x08 // Printer ready
|
||||||
const Rst4Mask = 0x10
|
//const Rst4Mask = 0x10
|
||||||
const Rst5Mask = 0x20 // Power intRq
|
//const Rst5Mask = 0x20 // Power intRq
|
||||||
const Rst6Mask = 0x40 // User device 1 interrupt
|
//const Rst6Mask = 0x40 // User device 1 interrupt
|
||||||
const Rst7Mask = 0x80 // User device 1 interrupt
|
//const Rst7Mask = 0x80 // User device 1 interrupt
|
||||||
|
|
||||||
// PIC_DD75A Port A (a0=0)
|
// PicDd75a Port A (a0=0)
|
||||||
const PIC_DD75A = 0x80
|
//const PicDd75a = 0x80
|
||||||
|
|
||||||
// PIC_DD75B Port B (a0=1)
|
// PIC_DD75B Port B (a0=1)
|
||||||
const PIC_DD75B = 0x81
|
//const PIC_DD75B = 0x81
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* КР580ВВ51 DD72
|
* КР580ВВ51 DD72
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// UART_DD72RD Serial data
|
// UartDd72rd Serial data
|
||||||
const UART_DD72RD = 0xA0
|
const UartDd72rd = 0xA0
|
||||||
|
|
||||||
// UART_DD72RR Serial status [RST,RQ_RX,RST_ERR,PAUSE,RX_EN,RX_RDY,TX_RDY]
|
// UartDd72rr Serial status [RST,RQ_RX,RST_ERR,PAUSE,RX_EN,RX_RDY,TX_RDY]
|
||||||
const UART_DD72RR = 0xA1
|
const UartDd72rr = 0xA1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* КР580ВВ55 DD17 System port
|
* КР580ВВ55 DD17 System port
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Port A - VShift[8..1] Vertical shift
|
// SysDd17pa Port A - VShift[8..1] Vertical shift
|
||||||
const SYS_DD17PA = 0xC0
|
const SysDd17pa = 0xC0
|
||||||
|
|
||||||
// Port B - Memory mapper [ROM14,13][REST][ENROM-][A18,17,16][32k]
|
// SysDd17pb Port B - Memory mapper [ROM14,13][REST][ENROM-][A18,17,16][32k]
|
||||||
const SYS_DD17PB = 0xC1
|
const SysDd17pb = 0xC1
|
||||||
|
|
||||||
// Port C - HShift[HS5..1,SB3..1] Horisontal shift
|
// SysDd17pc Port C - HShift[HS5..1,SB3..1] Horisontal shift
|
||||||
const SYS_DD17PC = 0xC2
|
const SysDd17pc = 0xC2
|
||||||
|
|
||||||
/*
|
// SysDd17ctr Configure: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
|
||||||
* SYS_DD17CTR
|
// Set bit: [0][xxx][bbb][0|1]
|
||||||
* Сonfig: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
|
const SysDd17ctr = 0xC3
|
||||||
* Set bit: [0][xxx][bbb][0|1]
|
|
||||||
*/
|
|
||||||
const SYS_DD17CTR = 0xC3
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* КР580ВВ55 DD67
|
* КР580ВВ55 DD67
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// LPT_DD67PA Port A - Printer Data
|
// 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]
|
// 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]
|
// DD67PC Port C - [USER3:1, STB-LP, BELL, TAPE3:1]
|
||||||
const DD67PC = 0xE2
|
//const DD67PC = 0xE2
|
||||||
|
|
||||||
/*
|
// DD67CTR
|
||||||
* DD67CTR
|
// Configure: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
|
||||||
* С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]
|
||||||
* Set bit: [0][xxx][bbb][0|1]
|
// const DD67CTR = 0xE3
|
||||||
*/
|
|
||||||
const DD67CTR = 0xE3
|
|
||||||
|
|||||||
@ -50,7 +50,7 @@ const (
|
|||||||
const (
|
const (
|
||||||
StatusTR0 = 0x04 // TR0 - Head at track 0
|
StatusTR0 = 0x04 // TR0 - Head at track 0
|
||||||
StatusRNF = 0x10 // RNF - Record not found
|
StatusRNF = 0x10 // RNF - Record not found
|
||||||
StatusSeekError = 0x10 // Sector out of disk
|
// StatusSeekError = 0x10 // Sector out of disk
|
||||||
StatusHeadLoaded = 0x20 // Head on disk
|
StatusHeadLoaded = 0x20 // Head on disk
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -12,31 +12,31 @@ import log "github.com/sirupsen/logrus"
|
|||||||
|
|
||||||
func (c *ComputerType) IORead(port uint16) byte {
|
func (c *ComputerType) IORead(port uint16) byte {
|
||||||
switch port & 0x00ff {
|
switch port & 0x00ff {
|
||||||
case PIC_DD75A:
|
case PicDd75a:
|
||||||
// PIO xx59, get IRR register
|
// PIO xx59, get IRR register
|
||||||
return c.pic.IRR()
|
return c.pic.IRR()
|
||||||
case UART_DD72RR:
|
case UartDd72rr:
|
||||||
// USART VV51 CMD
|
// USART VV51 CMD
|
||||||
return c.usart.Status()
|
return c.usart.Status()
|
||||||
case UART_DD72RD:
|
case UartDd72rd:
|
||||||
// USART VV51 Data
|
// USART VV51 Data
|
||||||
return c.usart.Receive()
|
return c.usart.Receive()
|
||||||
case KBD_DD78PA:
|
case KbdDd78pa:
|
||||||
// Keyboard data
|
// Keyboard data
|
||||||
return c.ioPorts[KBD_DD78PA]
|
return c.ioPorts[KbdDd78pa]
|
||||||
case KBD_DD78PB:
|
case KbdDd78pb:
|
||||||
return c.ioPorts[KBD_DD78PB]
|
return c.ioPorts[KbdDd78pb]
|
||||||
case FDC_CMD:
|
case FdcCmd:
|
||||||
return c.fdc.Status()
|
return c.fdc.Status()
|
||||||
case FDC_DRQ:
|
case FdcDrq:
|
||||||
return c.fdc.Drq()
|
return c.fdc.Drq()
|
||||||
case FLOPPY:
|
case Floppy:
|
||||||
return c.fdc.GetFloppy()
|
return c.fdc.GetFloppy()
|
||||||
case FDC_DATA:
|
case FdcData:
|
||||||
return c.fdc.Data()
|
return c.fdc.Data()
|
||||||
case FDC_TRACK:
|
case FdcTrack:
|
||||||
return c.fdc.Track()
|
return c.fdc.Track()
|
||||||
case FDC_SECT:
|
case FdcSect:
|
||||||
return c.fdc.Sector()
|
return c.fdc.Sector()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -50,11 +50,11 @@ func (c *ComputerType) IOWrite(port uint16, val byte) {
|
|||||||
c.ioPorts[bp] = val
|
c.ioPorts[bp] = val
|
||||||
//log.Debugf("OUT (%x), %x", bp, val)
|
//log.Debugf("OUT (%x), %x", bp, val)
|
||||||
switch bp {
|
switch bp {
|
||||||
case SYS_DD17PB:
|
case SysDd17pb:
|
||||||
if c.dd17EnableOut {
|
if c.dd17EnableOut {
|
||||||
c.memory.Configure(val)
|
c.memory.Configure(val)
|
||||||
}
|
}
|
||||||
case SYS_DD17CTR:
|
case SysDd17ctr:
|
||||||
c.dd17EnableOut = val == 0x80
|
c.dd17EnableOut = val == 0x80
|
||||||
case VID_DD67PB:
|
case VID_DD67PB:
|
||||||
if val&VidVsuBit == 0 {
|
if val&VidVsuBit == 0 {
|
||||||
@ -73,38 +73,38 @@ func (c *ComputerType) IOWrite(port uint16, val byte) {
|
|||||||
}
|
}
|
||||||
c.palette = val & 0x07
|
c.palette = val & 0x07
|
||||||
c.bgColor = (val >> 3) & 0x07
|
c.bgColor = (val >> 3) & 0x07
|
||||||
case SYS_DD17PA:
|
case SysDd17pa:
|
||||||
c.vShift = val
|
c.vShift = val
|
||||||
case SYS_DD17PC:
|
case SysDd17pc:
|
||||||
c.hShift = val
|
c.hShift = val
|
||||||
case TMR_DD70CTR:
|
case TmrDd70ctr:
|
||||||
// Timer VI63 config register
|
// Timer VI63 config register
|
||||||
c.pit.Configure(val)
|
c.pit.Configure(val)
|
||||||
case TMR_DD70C1:
|
case TmrDd70c1:
|
||||||
// Timer VI63 counter0 register
|
// Timer VI63 counter0 register
|
||||||
c.pit.Load(0, val)
|
c.pit.Load(0, val)
|
||||||
case TMR_DD70C2:
|
case TmrDd70c2:
|
||||||
// Timer VI63 counter1 register
|
// Timer VI63 counter1 register
|
||||||
c.pit.Load(1, val)
|
c.pit.Load(1, val)
|
||||||
case TMR_DD70C3:
|
case TmrDd70c3:
|
||||||
// Timer VI63 counter2 register
|
// Timer VI63 counter2 register
|
||||||
c.pit.Load(2, val)
|
c.pit.Load(2, val)
|
||||||
|
|
||||||
case UART_DD72RR:
|
case UartDd72rr:
|
||||||
// USART VV51 CMD
|
// USART VV51 CMD
|
||||||
c.usart.Command(val)
|
c.usart.Command(val)
|
||||||
case UART_DD72RD:
|
case UartDd72rd:
|
||||||
// USART VV51 Data
|
// USART VV51 Data
|
||||||
c.usart.Send(val)
|
c.usart.Send(val)
|
||||||
case FDC_CMD:
|
case FdcCmd:
|
||||||
c.fdc.SetCmd(val)
|
c.fdc.SetCmd(val)
|
||||||
case FDC_DATA:
|
case FdcData:
|
||||||
c.fdc.SetData(val)
|
c.fdc.SetData(val)
|
||||||
case FDC_TRACK:
|
case FdcTrack:
|
||||||
c.fdc.SetTrackNo(val)
|
c.fdc.SetTrackNo(val)
|
||||||
case FDC_SECT:
|
case FdcSect:
|
||||||
c.fdc.SetSectorNo(val)
|
c.fdc.SetSectorNo(val)
|
||||||
case FLOPPY:
|
case Floppy:
|
||||||
c.fdc.SetFloppy(val)
|
c.fdc.SetFloppy(val)
|
||||||
default:
|
default:
|
||||||
//log.Debugf("OUT to Unknown port (%x), %x", bp, val)
|
//log.Debugf("OUT to Unknown port (%x), %x", bp, val)
|
||||||
|
|||||||
@ -9,7 +9,7 @@ func (c *ComputerType) PutKey(key *fyne.KeyEvent) {
|
|||||||
code := RemapCmdKey[key.Name]
|
code := RemapCmdKey[key.Name]
|
||||||
if code > 0 {
|
if code > 0 {
|
||||||
//log.Debugf("PutKey keyName: %s", key.Name)
|
//log.Debugf("PutKey keyName: %s", key.Name)
|
||||||
c.ioPorts[KBD_DD78PA] = code
|
c.ioPorts[KbdDd78pa] = code
|
||||||
c.pic.SetIRQ(RstKbdNo)
|
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)
|
//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)
|
c.pic.SetIRQ(RstKbdNo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,8 +37,8 @@ func (c *ComputerType) PutRune(key rune) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
func (c *ComputerType) PutCtrlKey(key byte) {
|
func (c *ComputerType) PutCtrlKey(key byte) {
|
||||||
c.ioPorts[KBD_DD78PA] = key
|
c.ioPorts[KbdDd78pa] = key
|
||||||
c.pic.SetIRQ(RstKbdNo)
|
c.pic.SetIRQ(RstKbdNo)
|
||||||
//c.ioPorts[PIC_DD75RS] |= Rst1Mask
|
//c.ioPorts[PIC_DD75RS] |= Rst1Mask
|
||||||
c.ioPorts[KBD_DD78PB] &= 0x1f | 0x20
|
c.ioPorts[KbdDd78pb] &= 0x1f | 0x20
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,7 +39,6 @@ type I8253 struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type I8253Interface interface {
|
type I8253Interface interface {
|
||||||
//Init()
|
|
||||||
Configure(value byte)
|
Configure(value byte)
|
||||||
Load(chNo int, value byte)
|
Load(chNo int, value byte)
|
||||||
Counter(chNo int) uint16
|
Counter(chNo int) uint16
|
||||||
|
|||||||
@ -33,164 +33,164 @@ var RemapCmdKey = map[fyne.KeyName]byte{
|
|||||||
fyne.KeyUnknown: 0x00,
|
fyne.KeyUnknown: 0x00,
|
||||||
}
|
}
|
||||||
|
|
||||||
var RemapKey = map[fyne.KeyName]byte{
|
//var RemapKey = map[fyne.KeyName]byte{
|
||||||
fyne.KeyEscape: 0x1B,
|
// fyne.KeyEscape: 0x1B,
|
||||||
fyne.KeyReturn: 0x0A,
|
// fyne.KeyReturn: 0x0A,
|
||||||
fyne.KeyTab: 0x09,
|
// fyne.KeyTab: 0x09,
|
||||||
fyne.KeyBackspace: 0x08,
|
// fyne.KeyBackspace: 0x08,
|
||||||
fyne.KeyInsert: 0x00,
|
// fyne.KeyInsert: 0x00,
|
||||||
fyne.KeyDelete: 0x08,
|
// fyne.KeyDelete: 0x08,
|
||||||
fyne.KeyRight: 0x18,
|
// fyne.KeyRight: 0x18,
|
||||||
fyne.KeyLeft: 0x08,
|
// fyne.KeyLeft: 0x08,
|
||||||
fyne.KeyDown: 0x0A,
|
// fyne.KeyDown: 0x0A,
|
||||||
fyne.KeyUp: 0x19,
|
// fyne.KeyUp: 0x19,
|
||||||
fyne.KeyPageUp: 0x00,
|
// fyne.KeyPageUp: 0x00,
|
||||||
fyne.KeyPageDown: 0x00,
|
// fyne.KeyPageDown: 0x00,
|
||||||
fyne.KeyHome: 0x0C,
|
// fyne.KeyHome: 0x0C,
|
||||||
fyne.KeyEnd: 0x1A,
|
// fyne.KeyEnd: 0x1A,
|
||||||
fyne.KeyF1: 0x00,
|
// fyne.KeyF1: 0x00,
|
||||||
fyne.KeyF2: 0x00,
|
// fyne.KeyF2: 0x00,
|
||||||
fyne.KeyF3: 0x00,
|
// fyne.KeyF3: 0x00,
|
||||||
fyne.KeyF4: 0x00,
|
// fyne.KeyF4: 0x00,
|
||||||
fyne.KeyF5: 0x00,
|
// fyne.KeyF5: 0x00,
|
||||||
fyne.KeyF6: 0x00,
|
// fyne.KeyF6: 0x00,
|
||||||
fyne.KeyF7: 0x00,
|
// fyne.KeyF7: 0x00,
|
||||||
fyne.KeyF8: 0x00,
|
// fyne.KeyF8: 0x00,
|
||||||
fyne.KeyF9: 0x00,
|
// fyne.KeyF9: 0x00,
|
||||||
fyne.KeyF10: 0x00,
|
// fyne.KeyF10: 0x00,
|
||||||
fyne.KeyF11: 0x00,
|
// fyne.KeyF11: 0x00,
|
||||||
fyne.KeyF12: 0x00,
|
// fyne.KeyF12: 0x00,
|
||||||
fyne.KeyEnter: 0x0D,
|
// fyne.KeyEnter: 0x0D,
|
||||||
fyne.Key0: 0x30,
|
// fyne.Key0: 0x30,
|
||||||
fyne.Key1: 0x31,
|
// fyne.Key1: 0x31,
|
||||||
fyne.Key2: 0x32,
|
// fyne.Key2: 0x32,
|
||||||
fyne.Key3: 0x33,
|
// fyne.Key3: 0x33,
|
||||||
fyne.Key4: 0x34,
|
// fyne.Key4: 0x34,
|
||||||
fyne.Key5: 0x35,
|
// fyne.Key5: 0x35,
|
||||||
fyne.Key6: 0x36,
|
// fyne.Key6: 0x36,
|
||||||
fyne.Key7: 0x37,
|
// fyne.Key7: 0x37,
|
||||||
fyne.Key8: 0x38,
|
// fyne.Key8: 0x38,
|
||||||
fyne.Key9: 0x39,
|
// fyne.Key9: 0x39,
|
||||||
fyne.KeyA: 0x61,
|
// fyne.KeyA: 0x61,
|
||||||
fyne.KeyB: 0x62,
|
// fyne.KeyB: 0x62,
|
||||||
fyne.KeyC: 0x63,
|
// fyne.KeyC: 0x63,
|
||||||
fyne.KeyD: 0x64,
|
// fyne.KeyD: 0x64,
|
||||||
fyne.KeyE: 0x65,
|
// fyne.KeyE: 0x65,
|
||||||
fyne.KeyF: 0x66,
|
// fyne.KeyF: 0x66,
|
||||||
fyne.KeyG: 0x67,
|
// fyne.KeyG: 0x67,
|
||||||
fyne.KeyH: 0x68,
|
// fyne.KeyH: 0x68,
|
||||||
fyne.KeyI: 0x69,
|
// fyne.KeyI: 0x69,
|
||||||
fyne.KeyJ: 0x6a,
|
// fyne.KeyJ: 0x6a,
|
||||||
fyne.KeyK: 0x6b,
|
// fyne.KeyK: 0x6b,
|
||||||
fyne.KeyL: 0x6c,
|
// fyne.KeyL: 0x6c,
|
||||||
fyne.KeyM: 0x6d,
|
// fyne.KeyM: 0x6d,
|
||||||
fyne.KeyN: 0x6e,
|
// fyne.KeyN: 0x6e,
|
||||||
fyne.KeyO: 0x6f,
|
// fyne.KeyO: 0x6f,
|
||||||
fyne.KeyP: 0x70,
|
// fyne.KeyP: 0x70,
|
||||||
fyne.KeyQ: 0x71,
|
// fyne.KeyQ: 0x71,
|
||||||
fyne.KeyR: 0x72,
|
// fyne.KeyR: 0x72,
|
||||||
fyne.KeyS: 0x73,
|
// fyne.KeyS: 0x73,
|
||||||
fyne.KeyT: 0x74,
|
// fyne.KeyT: 0x74,
|
||||||
fyne.KeyU: 0x75,
|
// fyne.KeyU: 0x75,
|
||||||
fyne.KeyV: 0x76,
|
// fyne.KeyV: 0x76,
|
||||||
fyne.KeyW: 0x77,
|
// fyne.KeyW: 0x77,
|
||||||
fyne.KeyX: 0x78,
|
// fyne.KeyX: 0x78,
|
||||||
fyne.KeyY: 0x79,
|
// fyne.KeyY: 0x79,
|
||||||
fyne.KeyZ: 0x7A,
|
// fyne.KeyZ: 0x7A,
|
||||||
fyne.KeySpace: 0x20,
|
// fyne.KeySpace: 0x20,
|
||||||
fyne.KeyApostrophe: 0x27,
|
// fyne.KeyApostrophe: 0x27,
|
||||||
fyne.KeyComma: 0x2c,
|
// fyne.KeyComma: 0x2c,
|
||||||
fyne.KeyMinus: 0x2d,
|
// fyne.KeyMinus: 0x2d,
|
||||||
fyne.KeyPeriod: 0x2E,
|
// fyne.KeyPeriod: 0x2E,
|
||||||
fyne.KeySlash: 0x2F,
|
// fyne.KeySlash: 0x2F,
|
||||||
fyne.KeyBackslash: 0x5C,
|
// fyne.KeyBackslash: 0x5C,
|
||||||
fyne.KeyLeftBracket: 0x5B,
|
// fyne.KeyLeftBracket: 0x5B,
|
||||||
fyne.KeyRightBracket: 0x5D,
|
// fyne.KeyRightBracket: 0x5D,
|
||||||
fyne.KeySemicolon: 0x3B,
|
// fyne.KeySemicolon: 0x3B,
|
||||||
fyne.KeyEqual: 0x3D,
|
// fyne.KeyEqual: 0x3D,
|
||||||
fyne.KeyAsterisk: 0x2A,
|
// fyne.KeyAsterisk: 0x2A,
|
||||||
fyne.KeyPlus: 0x2B,
|
// fyne.KeyPlus: 0x2B,
|
||||||
fyne.KeyBackTick: 0x60,
|
// fyne.KeyBackTick: 0x60,
|
||||||
fyne.KeyUnknown: 0x00,
|
// fyne.KeyUnknown: 0x00,
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
var RemapKeyShift = map[fyne.KeyName]byte{
|
//var RemapKeyShift = map[fyne.KeyName]byte{
|
||||||
fyne.KeyEscape: 0x1B,
|
// fyne.KeyEscape: 0x1B,
|
||||||
fyne.KeyReturn: 0x0A,
|
// fyne.KeyReturn: 0x0A,
|
||||||
fyne.KeyTab: 0x09,
|
// fyne.KeyTab: 0x09,
|
||||||
fyne.KeyBackspace: 0x08,
|
// fyne.KeyBackspace: 0x08,
|
||||||
fyne.KeyInsert: 0x00,
|
// fyne.KeyInsert: 0x00,
|
||||||
fyne.KeyDelete: 0x08,
|
// fyne.KeyDelete: 0x08,
|
||||||
fyne.KeyRight: 0x18,
|
// fyne.KeyRight: 0x18,
|
||||||
fyne.KeyLeft: 0x08,
|
// fyne.KeyLeft: 0x08,
|
||||||
fyne.KeyDown: 0x0A,
|
// fyne.KeyDown: 0x0A,
|
||||||
fyne.KeyUp: 0x19,
|
// fyne.KeyUp: 0x19,
|
||||||
fyne.KeyPageUp: 0x00,
|
// fyne.KeyPageUp: 0x00,
|
||||||
fyne.KeyPageDown: 0x00,
|
// fyne.KeyPageDown: 0x00,
|
||||||
fyne.KeyHome: 0x0C,
|
// fyne.KeyHome: 0x0C,
|
||||||
fyne.KeyEnd: 0x1A,
|
// fyne.KeyEnd: 0x1A,
|
||||||
fyne.KeyF1: 0x00,
|
// fyne.KeyF1: 0x00,
|
||||||
fyne.KeyF2: 0x00,
|
// fyne.KeyF2: 0x00,
|
||||||
fyne.KeyF3: 0x00,
|
// fyne.KeyF3: 0x00,
|
||||||
fyne.KeyF4: 0x00,
|
// fyne.KeyF4: 0x00,
|
||||||
fyne.KeyF5: 0x00,
|
// fyne.KeyF5: 0x00,
|
||||||
fyne.KeyF6: 0x00,
|
// fyne.KeyF6: 0x00,
|
||||||
fyne.KeyF7: 0x00,
|
// fyne.KeyF7: 0x00,
|
||||||
fyne.KeyF8: 0x00,
|
// fyne.KeyF8: 0x00,
|
||||||
fyne.KeyF9: 0x00,
|
// fyne.KeyF9: 0x00,
|
||||||
fyne.KeyF10: 0x00,
|
// fyne.KeyF10: 0x00,
|
||||||
fyne.KeyF11: 0x00,
|
// fyne.KeyF11: 0x00,
|
||||||
fyne.KeyF12: 0x00,
|
// fyne.KeyF12: 0x00,
|
||||||
fyne.KeyEnter: 0x0D,
|
// fyne.KeyEnter: 0x0D,
|
||||||
|
//
|
||||||
fyne.Key0: 0x29,
|
// fyne.Key0: 0x29,
|
||||||
fyne.Key1: 0x21,
|
// fyne.Key1: 0x21,
|
||||||
fyne.Key2: 0x40,
|
// fyne.Key2: 0x40,
|
||||||
fyne.Key3: 0x23,
|
// fyne.Key3: 0x23,
|
||||||
fyne.Key4: 0x24,
|
// fyne.Key4: 0x24,
|
||||||
fyne.Key5: 0x25,
|
// fyne.Key5: 0x25,
|
||||||
fyne.Key6: 0x5E,
|
// fyne.Key6: 0x5E,
|
||||||
fyne.Key7: 0x26,
|
// fyne.Key7: 0x26,
|
||||||
fyne.Key8: 0x2A,
|
// fyne.Key8: 0x2A,
|
||||||
fyne.Key9: 0x28,
|
// fyne.Key9: 0x28,
|
||||||
fyne.KeyA: 0x41,
|
// fyne.KeyA: 0x41,
|
||||||
fyne.KeyB: 0x42,
|
// fyne.KeyB: 0x42,
|
||||||
fyne.KeyC: 0x43,
|
// fyne.KeyC: 0x43,
|
||||||
fyne.KeyD: 0x44,
|
// fyne.KeyD: 0x44,
|
||||||
fyne.KeyE: 0x45,
|
// fyne.KeyE: 0x45,
|
||||||
fyne.KeyF: 0x46,
|
// fyne.KeyF: 0x46,
|
||||||
fyne.KeyG: 0x47,
|
// fyne.KeyG: 0x47,
|
||||||
fyne.KeyH: 0x48,
|
// fyne.KeyH: 0x48,
|
||||||
fyne.KeyI: 0x49,
|
// fyne.KeyI: 0x49,
|
||||||
fyne.KeyJ: 0x4a,
|
// fyne.KeyJ: 0x4a,
|
||||||
fyne.KeyK: 0x4b,
|
// fyne.KeyK: 0x4b,
|
||||||
fyne.KeyL: 0x4c,
|
// fyne.KeyL: 0x4c,
|
||||||
fyne.KeyM: 0x4d,
|
// fyne.KeyM: 0x4d,
|
||||||
fyne.KeyN: 0x4e,
|
// fyne.KeyN: 0x4e,
|
||||||
fyne.KeyO: 0x4f,
|
// fyne.KeyO: 0x4f,
|
||||||
fyne.KeyP: 0x50,
|
// fyne.KeyP: 0x50,
|
||||||
fyne.KeyQ: 0x51,
|
// fyne.KeyQ: 0x51,
|
||||||
fyne.KeyR: 0x52,
|
// fyne.KeyR: 0x52,
|
||||||
fyne.KeyS: 0x53,
|
// fyne.KeyS: 0x53,
|
||||||
fyne.KeyT: 0x54,
|
// fyne.KeyT: 0x54,
|
||||||
fyne.KeyU: 0x55,
|
// fyne.KeyU: 0x55,
|
||||||
fyne.KeyV: 0x56,
|
// fyne.KeyV: 0x56,
|
||||||
fyne.KeyW: 0x57,
|
// fyne.KeyW: 0x57,
|
||||||
fyne.KeyX: 0x58,
|
// fyne.KeyX: 0x58,
|
||||||
fyne.KeyY: 0x59,
|
// fyne.KeyY: 0x59,
|
||||||
fyne.KeyZ: 0x5A,
|
// fyne.KeyZ: 0x5A,
|
||||||
fyne.KeySpace: 0x20,
|
// fyne.KeySpace: 0x20,
|
||||||
fyne.KeyApostrophe: 0x22,
|
// fyne.KeyApostrophe: 0x22,
|
||||||
fyne.KeyComma: 0x3C,
|
// fyne.KeyComma: 0x3C,
|
||||||
fyne.KeyMinus: 0x5F,
|
// fyne.KeyMinus: 0x5F,
|
||||||
fyne.KeyPeriod: 0x3E,
|
// fyne.KeyPeriod: 0x3E,
|
||||||
fyne.KeySlash: 0x3F,
|
// fyne.KeySlash: 0x3F,
|
||||||
fyne.KeyBackslash: 0x7C,
|
// fyne.KeyBackslash: 0x7C,
|
||||||
fyne.KeyLeftBracket: 0x7B,
|
// fyne.KeyLeftBracket: 0x7B,
|
||||||
fyne.KeyRightBracket: 0x7D,
|
// fyne.KeyRightBracket: 0x7D,
|
||||||
fyne.KeySemicolon: 0x3A,
|
// fyne.KeySemicolon: 0x3A,
|
||||||
fyne.KeyEqual: 0x2B,
|
// fyne.KeyEqual: 0x2B,
|
||||||
fyne.KeyAsterisk: 0x7E,
|
// fyne.KeyAsterisk: 0x7E,
|
||||||
fyne.KeyPlus: 0x7E,
|
// fyne.KeyPlus: 0x7E,
|
||||||
fyne.KeyBackTick: 0x60,
|
// fyne.KeyBackTick: 0x60,
|
||||||
}
|
//}
|
||||||
|
|||||||
@ -190,7 +190,7 @@ var instructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x22 : LD (nn), HL
|
// 0x22 : LD (nn), HL
|
||||||
0x22: func(s *Z80Type) {
|
0x22: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
addr := s.nextWord()
|
||||||
s.core.MemWrite(addr, s.L)
|
s.core.MemWrite(addr, s.L)
|
||||||
s.core.MemWrite(addr+1, s.H)
|
s.core.MemWrite(addr+1, s.H)
|
||||||
},
|
},
|
||||||
@ -252,7 +252,7 @@ var instructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x2a : LD HL, (nn)
|
// 0x2a : LD HL, (nn)
|
||||||
0x2A: func(s *Z80Type) {
|
0x2A: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
addr := s.nextWord()
|
||||||
s.L = s.core.MemRead(addr)
|
s.L = s.core.MemRead(addr)
|
||||||
s.H = s.core.MemRead(addr + 1)
|
s.H = s.core.MemRead(addr + 1)
|
||||||
},
|
},
|
||||||
@ -293,7 +293,7 @@ var instructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x32 : LD (nn), A
|
// 0x32 : LD (nn), A
|
||||||
0x32: func(s *Z80Type) {
|
0x32: func(s *Z80Type) {
|
||||||
s.core.MemWrite(s.getAddr(), s.A)
|
s.core.MemWrite(s.nextWord(), s.A)
|
||||||
},
|
},
|
||||||
// 0x33 : INC SP
|
// 0x33 : INC SP
|
||||||
0x33: func(s *Z80Type) {
|
0x33: func(s *Z80Type) {
|
||||||
@ -329,7 +329,7 @@ var instructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x3a : LD A, (nn)
|
// 0x3a : LD A, (nn)
|
||||||
0x3A: func(s *Z80Type) {
|
0x3A: func(s *Z80Type) {
|
||||||
s.A = s.core.MemRead(s.getAddr())
|
s.A = s.core.MemRead(s.nextWord())
|
||||||
},
|
},
|
||||||
// 0x3b : DEC SP
|
// 0x3b : DEC SP
|
||||||
0x3B: func(s *Z80Type) {
|
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++
|
z.PC++
|
||||||
addr := uint16(z.core.MemRead(z.PC))
|
word := uint16(z.core.MemRead(z.PC))
|
||||||
z.PC++
|
z.PC++
|
||||||
addr |= uint16(z.core.MemRead(z.PC)) << 8
|
word |= uint16(z.core.MemRead(z.PC)) << 8
|
||||||
return addr
|
return word
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package z80em
|
package z80em
|
||||||
|
|
||||||
func (z *Z80Type) opcodeCB() {
|
func (z *Z80Type) opcodeCB() {
|
||||||
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
|
z.incR()
|
||||||
z.PC++
|
z.PC++
|
||||||
opcode := z.core.M1MemRead(z.PC)
|
opcode := z.core.M1MemRead(z.PC)
|
||||||
bitNumber := (opcode & 0x38) >> 3
|
bitNumber := (opcode & 0x38) >> 3
|
||||||
@ -29,28 +29,30 @@ func (z *Z80Type) opcodeCB() {
|
|||||||
}
|
}
|
||||||
} else if opcode < 0x80 {
|
} else if opcode < 0x80 {
|
||||||
// BIT instructions
|
// BIT instructions
|
||||||
|
mask := byte(1 << bitNumber)
|
||||||
switch regCode {
|
switch regCode {
|
||||||
case 0:
|
case 0:
|
||||||
z.Flags.Z = z.B&(1<<bitNumber) == 0
|
z.Flags.Z = z.B&mask == 0
|
||||||
case 1:
|
case 1:
|
||||||
z.Flags.Z = z.C&(1<<bitNumber) == 0
|
z.Flags.Z = z.C&mask == 0
|
||||||
case 2:
|
case 2:
|
||||||
z.Flags.Z = z.D&(1<<bitNumber) == 0
|
z.Flags.Z = z.D&mask == 0
|
||||||
case 3:
|
case 3:
|
||||||
z.Flags.Z = z.E&(1<<bitNumber) == 0
|
z.Flags.Z = z.E&mask == 0
|
||||||
case 4:
|
case 4:
|
||||||
z.Flags.Z = z.H&(1<<bitNumber) == 0
|
z.Flags.Z = z.H&mask == 0
|
||||||
case 5:
|
case 5:
|
||||||
z.Flags.Z = z.L&(1<<bitNumber) == 0
|
z.Flags.Z = z.L&mask == 0
|
||||||
case 6:
|
case 6:
|
||||||
z.Flags.Z = z.core.MemRead(z.hl())&(1<<bitNumber) == 0
|
z.Flags.Z = z.core.MemRead(z.hl())&mask == 0
|
||||||
default:
|
default:
|
||||||
z.Flags.Z = z.A&(1<<bitNumber) == 0
|
z.Flags.Z = z.A&mask == 0
|
||||||
}
|
}
|
||||||
z.Flags.N = false
|
z.Flags.N = false
|
||||||
z.Flags.H = true
|
z.Flags.H = true
|
||||||
z.Flags.P = z.Flags.Z
|
z.Flags.P = z.Flags.Z
|
||||||
z.Flags.S = (bitNumber == 7) && !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
|
// For the BIT n, (HL) instruction, the X and Y flags are obtained
|
||||||
// from what is apparently an internal temporary register used for
|
// from what is apparently an internal temporary register used for
|
||||||
// some of the 16-bit arithmetic instructions.
|
// some of the 16-bit arithmetic instructions.
|
||||||
|
|||||||
@ -11,13 +11,11 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x21 : LD IX, nn
|
// 0x21 : LD IX, nn
|
||||||
0x21: func(s *Z80Type) {
|
0x21: func(s *Z80Type) {
|
||||||
s.IX = s.getAddr()
|
s.IX = s.nextWord()
|
||||||
},
|
},
|
||||||
// 0x22 : LD (nn), IX
|
// 0x22 : LD (nn), IX
|
||||||
0x22: func(s *Z80Type) {
|
0x22: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
s.setWord(s.nextWord(), s.IX)
|
||||||
s.core.MemWrite(addr, byte(s.IX&0x00ff))
|
|
||||||
s.core.MemWrite(addr+1, byte(s.IX>>8))
|
|
||||||
},
|
},
|
||||||
// 0x23 : INC IX
|
// 0x23 : INC IX
|
||||||
0x23: func(s *Z80Type) {
|
0x23: func(s *Z80Type) {
|
||||||
@ -42,8 +40,7 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x2a : LD IX, (nn)
|
// 0x2a : LD IX, (nn)
|
||||||
0x2A: func(s *Z80Type) {
|
0x2A: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
s.IX = s.getWord(s.nextWord())
|
||||||
s.IX = (uint16(s.core.MemRead(addr)) << 8) | uint16(s.core.MemRead(addr+1))
|
|
||||||
},
|
},
|
||||||
// 0x2b : DEC IX
|
// 0x2b : DEC IX
|
||||||
0x2B: func(s *Z80Type) {
|
0x2B: func(s *Z80Type) {
|
||||||
@ -94,8 +91,7 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x46 : LD B, (IX+n)
|
// 0x46 : LD B, (IX+n)
|
||||||
0x46: func(s *Z80Type) {
|
0x46: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.B = s.core.MemRead(s.getOffset(s.IX))
|
||||||
s.B = s.core.MemRead(offset)
|
|
||||||
},
|
},
|
||||||
// 0x4c : LD C, IXH (Undocumented)
|
// 0x4c : LD C, IXH (Undocumented)
|
||||||
0x4C: func(s *Z80Type) {
|
0x4C: func(s *Z80Type) {
|
||||||
@ -107,8 +103,7 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x4e : LD C, (IX+n)
|
// 0x4e : LD C, (IX+n)
|
||||||
0x4E: func(s *Z80Type) {
|
0x4E: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.C = s.core.MemRead(s.getOffset(s.IX))
|
||||||
s.C = s.core.MemRead(offset)
|
|
||||||
},
|
},
|
||||||
// 0x54 : LD D, IXH (Undocumented)
|
// 0x54 : LD D, IXH (Undocumented)
|
||||||
0x54: func(s *Z80Type) {
|
0x54: func(s *Z80Type) {
|
||||||
@ -116,7 +111,7 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x55 : LD D, IXL (Undocumented)
|
// 0x55 : LD D, IXL (Undocumented)
|
||||||
0x55: func(s *Z80Type) {
|
0x55: func(s *Z80Type) {
|
||||||
s.D = byte(s.IX & 0x00ff)
|
s.D = byte(s.IX)
|
||||||
},
|
},
|
||||||
// 0x56 : LD D, (IX+n)
|
// 0x56 : LD D, (IX+n)
|
||||||
0x56: func(s *Z80Type) {
|
0x56: func(s *Z80Type) {
|
||||||
@ -125,12 +120,11 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x5d : LD E, IXL (Undocumented)
|
// 0x5d : LD E, IXL (Undocumented)
|
||||||
0x5D: func(s *Z80Type) {
|
0x5D: func(s *Z80Type) {
|
||||||
s.E = byte(s.IX & 0x00ff)
|
s.E = byte(s.IX)
|
||||||
},
|
},
|
||||||
// 0x5e : LD E, (IX+n)
|
// 0x5e : LD E, (IX+n)
|
||||||
0x5E: func(s *Z80Type) {
|
0x5E: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.E = s.core.MemRead(s.getOffset(s.IX))
|
||||||
s.E = s.core.MemRead(offset)
|
|
||||||
},
|
},
|
||||||
// 0x60 : LD IXH, B (Undocumented)
|
// 0x60 : LD IXH, B (Undocumented)
|
||||||
0x60: func(s *Z80Type) {
|
0x60: func(s *Z80Type) {
|
||||||
@ -158,8 +152,7 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x66 : LD H, (IX+n)
|
// 0x66 : LD H, (IX+n)
|
||||||
0x66: func(s *Z80Type) {
|
0x66: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.H = s.core.MemRead(s.getOffset(s.IX))
|
||||||
s.H = s.core.MemRead(offset)
|
|
||||||
},
|
},
|
||||||
// 0x67 : LD IXH, A (Undocumented)
|
// 0x67 : LD IXH, A (Undocumented)
|
||||||
0x67: func(s *Z80Type) {
|
0x67: func(s *Z80Type) {
|
||||||
@ -191,8 +184,7 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x6e : LD L, (IX+n)
|
// 0x6e : LD L, (IX+n)
|
||||||
0x6e: func(s *Z80Type) {
|
0x6e: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.L = s.core.MemRead(s.getOffset(s.IX))
|
||||||
s.L = s.core.MemRead(offset)
|
|
||||||
},
|
},
|
||||||
// 0x6f : LD IXL, A (Undocumented)
|
// 0x6f : LD IXL, A (Undocumented)
|
||||||
0x6f: func(s *Z80Type) {
|
0x6f: func(s *Z80Type) {
|
||||||
@ -200,38 +192,31 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x70 : LD (IX+n), B
|
// 0x70 : LD (IX+n), B
|
||||||
0x70: func(s *Z80Type) {
|
0x70: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.core.MemWrite(s.getOffset(s.IX), s.B)
|
||||||
s.core.MemWrite(offset, s.B)
|
|
||||||
},
|
},
|
||||||
// 0x71 : LD (IX+n), C
|
// 0x71 : LD (IX+n), C
|
||||||
0x71: func(s *Z80Type) {
|
0x71: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.core.MemWrite(s.getOffset(s.IX), s.C)
|
||||||
s.core.MemWrite(offset, s.C)
|
|
||||||
},
|
},
|
||||||
// 0x72 : LD (IX+n), D
|
// 0x72 : LD (IX+n), D
|
||||||
0x72: func(s *Z80Type) {
|
0x72: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.core.MemWrite(s.getOffset(s.IX), s.D)
|
||||||
s.core.MemWrite(offset, s.D)
|
|
||||||
},
|
},
|
||||||
// 0x73 : LD (IX+n), E
|
// 0x73 : LD (IX+n), E
|
||||||
0x73: func(s *Z80Type) {
|
0x73: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.core.MemWrite(s.getOffset(s.IX), s.E)
|
||||||
s.core.MemWrite(offset, s.E)
|
|
||||||
},
|
},
|
||||||
// 0x74 : LD (IX+n), H
|
// 0x74 : LD (IX+n), H
|
||||||
0x74: func(s *Z80Type) {
|
0x74: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.core.MemWrite(s.getOffset(s.IX), s.H)
|
||||||
s.core.MemWrite(offset, s.H)
|
|
||||||
},
|
},
|
||||||
// 0x75 : LD (IX+n), L
|
// 0x75 : LD (IX+n), L
|
||||||
0x75: func(s *Z80Type) {
|
0x75: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.core.MemWrite(s.getOffset(s.IX), s.L)
|
||||||
s.core.MemWrite(offset, s.L)
|
|
||||||
},
|
},
|
||||||
// 0x77 : LD (IX+n), A
|
// 0x77 : LD (IX+n), A
|
||||||
0x77: func(s *Z80Type) {
|
0x77: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.core.MemWrite(s.getOffset(s.IX), s.A)
|
||||||
s.core.MemWrite(offset, s.A)
|
|
||||||
},
|
},
|
||||||
// 0x7c : LD A, IXH (Undocumented)
|
// 0x7c : LD A, IXH (Undocumented)
|
||||||
0x7C: func(s *Z80Type) {
|
0x7C: func(s *Z80Type) {
|
||||||
@ -243,8 +228,7 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x7e : LD A, (IX+n)
|
// 0x7e : LD A, (IX+n)
|
||||||
0x7E: func(s *Z80Type) {
|
0x7E: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.A = s.core.MemRead(s.getOffset(s.IX))
|
||||||
s.A = s.core.MemRead(offset)
|
|
||||||
},
|
},
|
||||||
// 0x84 : ADD A, IXH (Undocumented)
|
// 0x84 : ADD A, IXH (Undocumented)
|
||||||
0x84: func(s *Z80Type) {
|
0x84: func(s *Z80Type) {
|
||||||
@ -252,12 +236,11 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x85 : ADD A, IXL (Undocumented)
|
// 0x85 : ADD A, IXL (Undocumented)
|
||||||
0x85: func(s *Z80Type) {
|
0x85: func(s *Z80Type) {
|
||||||
s.doAdd(byte(s.IX & 0x00ff))
|
s.doAdd(byte(s.IX))
|
||||||
},
|
},
|
||||||
// 0x86 : ADD A, (IX+n)
|
// 0x86 : ADD A, (IX+n)
|
||||||
0x86: func(s *Z80Type) {
|
0x86: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.doAdd(s.core.MemRead(s.getOffset(s.IX)))
|
||||||
s.doAdd(s.core.MemRead(offset))
|
|
||||||
},
|
},
|
||||||
// 0x8c : ADC A, IXH (Undocumented)
|
// 0x8c : ADC A, IXH (Undocumented)
|
||||||
0x8C: func(s *Z80Type) {
|
0x8C: func(s *Z80Type) {
|
||||||
@ -265,12 +248,11 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x8d : ADC A, IXL (Undocumented)
|
// 0x8d : ADC A, IXL (Undocumented)
|
||||||
0x8D: func(s *Z80Type) {
|
0x8D: func(s *Z80Type) {
|
||||||
s.doAdc(byte(s.IX & 0x00ff))
|
s.doAdc(byte(s.IX))
|
||||||
},
|
},
|
||||||
// 0x8e : ADC A, (IX+n)
|
// 0x8e : ADC A, (IX+n)
|
||||||
0x8E: func(s *Z80Type) {
|
0x8E: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.doAdc(s.core.MemRead(s.getOffset(s.IX)))
|
||||||
s.doAdc(s.core.MemRead(offset))
|
|
||||||
},
|
},
|
||||||
// 0x94 : SUB IXH (Undocumented)
|
// 0x94 : SUB IXH (Undocumented)
|
||||||
0x94: func(s *Z80Type) {
|
0x94: func(s *Z80Type) {
|
||||||
@ -278,12 +260,11 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x95 : SUB IXL (Undocumented)
|
// 0x95 : SUB IXL (Undocumented)
|
||||||
0x95: func(s *Z80Type) {
|
0x95: func(s *Z80Type) {
|
||||||
s.doSub(byte(s.IX & 0x00ff))
|
s.doSub(byte(s.IX))
|
||||||
},
|
},
|
||||||
// 0x96 : SUB A, (IX+n)
|
// 0x96 : SUB A, (IX+n)
|
||||||
0x96: func(s *Z80Type) {
|
0x96: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.doSub(s.core.MemRead(s.getOffset(s.IX)))
|
||||||
s.doSub(s.core.MemRead(offset))
|
|
||||||
},
|
},
|
||||||
// 0x9c : SBC IXH (Undocumented)
|
// 0x9c : SBC IXH (Undocumented)
|
||||||
0x9C: func(s *Z80Type) {
|
0x9C: func(s *Z80Type) {
|
||||||
@ -291,12 +272,11 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x9d : SBC IXL (Undocumented)
|
// 0x9d : SBC IXL (Undocumented)
|
||||||
0x9D: func(s *Z80Type) {
|
0x9D: func(s *Z80Type) {
|
||||||
s.doSbc(byte(s.IX & 0x00ff))
|
s.doSbc(byte(s.IX))
|
||||||
},
|
},
|
||||||
// 0x9e : SBC A, (IX+n)
|
// 0x9e : SBC A, (IX+n)
|
||||||
0x9E: func(s *Z80Type) {
|
0x9E: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.doSbc(s.core.MemRead(s.getOffset(s.IX)))
|
||||||
s.doSbc(s.core.MemRead(offset))
|
|
||||||
},
|
},
|
||||||
// 0xa4 : AND IXH (Undocumented)
|
// 0xa4 : AND IXH (Undocumented)
|
||||||
0xA4: func(s *Z80Type) {
|
0xA4: func(s *Z80Type) {
|
||||||
@ -304,12 +284,11 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0xa5 : AND IXL (Undocumented)
|
// 0xa5 : AND IXL (Undocumented)
|
||||||
0xA5: func(s *Z80Type) {
|
0xA5: func(s *Z80Type) {
|
||||||
s.doAnd(byte(s.IX & 0x00ff))
|
s.doAnd(byte(s.IX))
|
||||||
},
|
},
|
||||||
// 0xa6 : AND A, (IX+n)
|
// 0xa6 : AND A, (IX+n)
|
||||||
0xA6: func(s *Z80Type) {
|
0xA6: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.doAnd(s.core.MemRead(s.getOffset(s.IX)))
|
||||||
s.doAnd(s.core.MemRead(offset))
|
|
||||||
},
|
},
|
||||||
// 0xac : XOR IXH (Undocumented)
|
// 0xac : XOR IXH (Undocumented)
|
||||||
0xAC: func(s *Z80Type) {
|
0xAC: func(s *Z80Type) {
|
||||||
@ -317,12 +296,11 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0xad : XOR IXL (Undocumented)
|
// 0xad : XOR IXL (Undocumented)
|
||||||
0xAD: func(s *Z80Type) {
|
0xAD: func(s *Z80Type) {
|
||||||
s.doXor(byte(s.IX & 0x00ff))
|
s.doXor(byte(s.IX))
|
||||||
},
|
},
|
||||||
// 0xae : XOR A, (IX+n)
|
// 0xae : XOR A, (IX+n)
|
||||||
0xAE: func(s *Z80Type) {
|
0xAE: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.doXor(s.core.MemRead(s.getOffset(s.IX)))
|
||||||
s.doXor(s.core.MemRead(offset))
|
|
||||||
},
|
},
|
||||||
// 0xb4 : OR IXH (Undocumented)
|
// 0xb4 : OR IXH (Undocumented)
|
||||||
0xB4: func(s *Z80Type) {
|
0xB4: func(s *Z80Type) {
|
||||||
@ -330,12 +308,11 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0xb5 : OR IXL (Undocumented)
|
// 0xb5 : OR IXL (Undocumented)
|
||||||
0xB5: func(s *Z80Type) {
|
0xB5: func(s *Z80Type) {
|
||||||
s.doOr(byte(s.IX & 0x00ff))
|
s.doOr(byte(s.IX))
|
||||||
},
|
},
|
||||||
// 0xb6 : OR A, (IX+n)
|
// 0xb6 : OR A, (IX+n)
|
||||||
0xB6: func(s *Z80Type) {
|
0xB6: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.doOr(s.core.MemRead(s.getOffset(s.IX)))
|
||||||
s.doOr(s.core.MemRead(offset))
|
|
||||||
},
|
},
|
||||||
// 0xbc : CP IXH (Undocumented)
|
// 0xbc : CP IXH (Undocumented)
|
||||||
0xBC: func(s *Z80Type) {
|
0xBC: func(s *Z80Type) {
|
||||||
@ -343,12 +320,11 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0xbd : CP IXL (Undocumented)
|
// 0xbd : CP IXL (Undocumented)
|
||||||
0xBD: func(s *Z80Type) {
|
0xBD: func(s *Z80Type) {
|
||||||
s.doCp(byte(s.IX & 0x00ff))
|
s.doCp(byte(s.IX))
|
||||||
},
|
},
|
||||||
// 0xbe : CP A, (IX+n)
|
// 0xbe : CP A, (IX+n)
|
||||||
0xBE: func(s *Z80Type) {
|
0xBE: func(s *Z80Type) {
|
||||||
offset := s.getOffset(s.IX)
|
s.doCp(s.core.MemRead(s.getOffset(s.IX)))
|
||||||
s.doCp(s.core.MemRead(offset))
|
|
||||||
},
|
},
|
||||||
// 0xcb : CB Prefix (IX bit instructions)
|
// 0xcb : CB Prefix (IX bit instructions)
|
||||||
0xCB: func(s *Z80Type) {
|
0xCB: func(s *Z80Type) {
|
||||||
@ -360,11 +336,9 @@ var ddInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0xe3 : EX (SP), IX
|
// 0xe3 : EX (SP), IX
|
||||||
0xE3: func(s *Z80Type) {
|
0xE3: func(s *Z80Type) {
|
||||||
temp := s.IX
|
ix := s.IX
|
||||||
s.IX = uint16(s.core.MemRead(s.SP))
|
s.IX = s.getWord(s.SP)
|
||||||
s.IX |= uint16(s.core.MemRead(s.SP+1)) << 8
|
s.setWord(s.SP, ix)
|
||||||
s.core.MemWrite(s.SP, byte(temp&0x00ff))
|
|
||||||
s.core.MemWrite(s.SP+1, byte(temp>>8))
|
|
||||||
},
|
},
|
||||||
// 0xe5 : PUSH IX
|
// 0xe5 : PUSH IX
|
||||||
0xE5: func(s *Z80Type) {
|
0xE5: func(s *Z80Type) {
|
||||||
@ -393,13 +367,12 @@ func (z *Z80Type) getOffset(reg uint16) uint16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) opcodeDD() {
|
func (z *Z80Type) opcodeDD() {
|
||||||
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
|
z.incR()
|
||||||
z.PC++
|
z.PC++
|
||||||
opcode := z.core.M1MemRead(z.PC)
|
opcode := z.core.M1MemRead(z.PC)
|
||||||
|
|
||||||
fun := ddInstructions[opcode]
|
fun := ddInstructions[opcode]
|
||||||
if fun != nil {
|
if fun != nil {
|
||||||
//func = func.bind(this);
|
|
||||||
fun(z)
|
fun(z)
|
||||||
z.CycleCounter += CycleCountsDd[opcode]
|
z.CycleCounter += CycleCountsDd[opcode]
|
||||||
} else {
|
} else {
|
||||||
@ -481,3 +454,22 @@ func (z *Z80Type) opcodeDDCB() {
|
|||||||
|
|
||||||
z.CycleCounter += CycleCountsCb[opcode] + 8
|
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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -3,21 +3,19 @@ package z80em
|
|||||||
var edInstructions = []func(s *Z80Type){
|
var edInstructions = []func(s *Z80Type){
|
||||||
// 0x40 : IN B, (C)
|
// 0x40 : IN B, (C)
|
||||||
0x40: func(s *Z80Type) {
|
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 : OUT (C), B
|
||||||
0x41: func(s *Z80Type) {
|
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 : SBC HL, BC
|
||||||
0x42: func(s *Z80Type) {
|
0x42: func(s *Z80Type) {
|
||||||
s.doHlSbc(uint16(s.C) | (uint16(s.B) << 8))
|
s.doHlSbc(s.bc())
|
||||||
},
|
},
|
||||||
// 0x43 : LD (nn), BC
|
// 0x43 : LD (nn), BC
|
||||||
0x43: func(s *Z80Type) {
|
0x43: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
s.setWord(s.nextWord(), s.bc())
|
||||||
s.core.MemWrite(addr, s.C)
|
|
||||||
s.core.MemWrite(addr+1, s.B)
|
|
||||||
},
|
},
|
||||||
// 0x44 : NEG
|
// 0x44 : NEG
|
||||||
0x44: func(s *Z80Type) {
|
0x44: func(s *Z80Type) {
|
||||||
@ -50,9 +48,7 @@ var edInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x4b : LD BC, (nn)
|
// 0x4b : LD BC, (nn)
|
||||||
0x4B: func(s *Z80Type) {
|
0x4B: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
s.setBc(s.getWord(s.nextWord()))
|
||||||
s.C = s.core.MemRead(addr)
|
|
||||||
s.B = s.core.MemRead(addr + 1)
|
|
||||||
},
|
},
|
||||||
// 0x4c : NEG (Undocumented)
|
// 0x4c : NEG (Undocumented)
|
||||||
0x4C: func(s *Z80Type) {
|
0x4C: func(s *Z80Type) {
|
||||||
@ -84,9 +80,7 @@ var edInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x53 : LD (nn), DE
|
// 0x53 : LD (nn), DE
|
||||||
0x53: func(s *Z80Type) {
|
0x53: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
s.setWord(s.nextWord(), s.de())
|
||||||
s.core.MemWrite(addr, s.E)
|
|
||||||
s.core.MemWrite(addr+1, s.D)
|
|
||||||
},
|
},
|
||||||
// 0x54 : NEG (Undocumented)
|
// 0x54 : NEG (Undocumented)
|
||||||
0x54: func(s *Z80Type) {
|
0x54: func(s *Z80Type) {
|
||||||
@ -126,9 +120,7 @@ var edInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x5b : LD DE, (nn)
|
// 0x5b : LD DE, (nn)
|
||||||
0x5B: func(s *Z80Type) {
|
0x5B: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
s.setDe(s.getWord(s.nextWord()))
|
||||||
s.E = s.core.MemRead(addr)
|
|
||||||
s.D = s.core.MemRead(addr + 1)
|
|
||||||
},
|
},
|
||||||
// 0x5c : NEG (Undocumented)
|
// 0x5c : NEG (Undocumented)
|
||||||
0x5C: func(s *Z80Type) {
|
0x5C: func(s *Z80Type) {
|
||||||
@ -168,9 +160,7 @@ var edInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x63 : LD (nn), HL (Undocumented)
|
// 0x63 : LD (nn), HL (Undocumented)
|
||||||
0x63: func(s *Z80Type) {
|
0x63: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
s.setWord(s.nextWord(), s.hl())
|
||||||
s.core.MemWrite(addr, s.L)
|
|
||||||
s.core.MemWrite(addr+1, s.H)
|
|
||||||
},
|
},
|
||||||
// 0x64 : NEG (Undocumented)
|
// 0x64 : NEG (Undocumented)
|
||||||
0x64: func(s *Z80Type) {
|
0x64: func(s *Z80Type) {
|
||||||
@ -215,9 +205,7 @@ var edInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x6b : LD HL, (nn) (Undocumented)
|
// 0x6b : LD HL, (nn) (Undocumented)
|
||||||
0x6B: func(s *Z80Type) {
|
0x6B: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
s.setHl(s.getWord(s.nextWord()))
|
||||||
s.L = s.core.MemRead(addr)
|
|
||||||
s.H = s.core.MemRead(addr + 1)
|
|
||||||
},
|
},
|
||||||
// 0x6C : NEG (Undocumented)
|
// 0x6C : NEG (Undocumented)
|
||||||
0x6C: func(s *Z80Type) {
|
0x6C: func(s *Z80Type) {
|
||||||
@ -262,9 +250,7 @@ var edInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x73 : LD (nn), SP
|
// 0x73 : LD (nn), SP
|
||||||
0x73: func(s *Z80Type) {
|
0x73: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
s.setWord(s.nextWord(), s.SP)
|
||||||
s.core.MemWrite(addr, byte(s.SP&0x00ff))
|
|
||||||
s.core.MemWrite(addr+1, byte(s.SP>>8))
|
|
||||||
},
|
},
|
||||||
// 0x74 : NEG (Undocumented)
|
// 0x74 : NEG (Undocumented)
|
||||||
0x74: func(s *Z80Type) {
|
0x74: func(s *Z80Type) {
|
||||||
@ -293,9 +279,7 @@ var edInstructions = []func(s *Z80Type){
|
|||||||
},
|
},
|
||||||
// 0x7b : LD SP, (nn)
|
// 0x7b : LD SP, (nn)
|
||||||
0x7B: func(s *Z80Type) {
|
0x7B: func(s *Z80Type) {
|
||||||
addr := s.getAddr()
|
s.SP = s.getWord(s.nextWord())
|
||||||
s.SP = uint16(s.core.MemRead(addr))
|
|
||||||
s.SP |= uint16(s.core.MemRead(addr+1)) << 8
|
|
||||||
},
|
},
|
||||||
// 0x7c : NEG (Undocumented)
|
// 0x7c : NEG (Undocumented)
|
||||||
0x7C: func(s *Z80Type) {
|
0x7C: func(s *Z80Type) {
|
||||||
@ -409,7 +393,7 @@ var edInstructions = []func(s *Z80Type){
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) opcodeED() {
|
func (z *Z80Type) opcodeED() {
|
||||||
z.R = (z.R & 0x80) | (((z.R & 0x7f) + 1) & 0x7f)
|
z.incR()
|
||||||
z.PC++
|
z.PC++
|
||||||
|
|
||||||
opcode := z.core.M1MemRead(z.PC)
|
opcode := z.core.M1MemRead(z.PC)
|
||||||
|
|||||||
246
z80em/z80em.go
246
z80em/z80em.go
@ -52,7 +52,7 @@ type Z80Type struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MemIoRW interface {
|
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
|
M1MemRead(addr uint16) byte
|
||||||
// MemRead Read byte from memory for specified address
|
// MemRead Read byte from memory for specified address
|
||||||
MemRead(addr uint16) byte
|
MemRead(addr uint16) byte
|
||||||
@ -198,12 +198,7 @@ func New(memIoRW MemIoRW) *Z80Type {
|
|||||||
|
|
||||||
func (z *Z80Type) RunInstruction() byte {
|
func (z *Z80Type) RunInstruction() byte {
|
||||||
|
|
||||||
// R is incremented at the start of every instruction cycle,
|
z.incR()
|
||||||
// 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)
|
|
||||||
|
|
||||||
if !z.Halted {
|
if !z.Halted {
|
||||||
// If the previous instruction was a DI or an EI,
|
// If the previous instruction was a DI or an EI,
|
||||||
@ -242,11 +237,13 @@ func (z *Z80Type) RunInstruction() byte {
|
|||||||
cycleCounter := z.CycleCounter
|
cycleCounter := z.CycleCounter
|
||||||
z.CycleCounter = 0
|
z.CycleCounter = 0
|
||||||
return cycleCounter
|
return cycleCounter
|
||||||
} else { // HALTED
|
}
|
||||||
|
|
||||||
|
// HALTED
|
||||||
// During HALT, NOPs are executed which is 4T
|
// 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).
|
z.core.M1MemRead(z.PC) // HALT does a normal M1 fetch to keep the memory refresh active. The result is ignored (NOP).
|
||||||
return 4
|
return 4
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simulates pulsing the processor's INT (or NMI) pin
|
// 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,
|
// The high bit of R is not affected by this increment,
|
||||||
// it can only be changed using the LD R, A instruction.
|
// 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;
|
// Non-maskable interrupts are always handled the same way;
|
||||||
// clear IFF1 and then do a CALL 0x0066.
|
// 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,
|
// The high bit of R is not affected by this increment,
|
||||||
// it can only be changed using the LD R,A instruction.
|
// 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.Halted = false
|
||||||
z.Iff1 = 0
|
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,
|
// but it doesn't appear that this is actually the case on the hardware,
|
||||||
// so we don't attempt to enforce that here.
|
// so we don't attempt to enforce that here.
|
||||||
vectorAddress := (uint16(z.I) << 8) | uint16(data)
|
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
|
z.CycleCounter += 19
|
||||||
// A "notification" is generated so that the calling program can break on it.
|
// A "notification" is generated so that the calling program can break on it.
|
||||||
z.interruptOccurred = true
|
z.interruptOccurred = true
|
||||||
@ -342,7 +339,7 @@ func (z *Z80Type) getOperand(opcode byte) byte {
|
|||||||
case 5:
|
case 5:
|
||||||
return z.L
|
return z.L
|
||||||
case 6:
|
case 6:
|
||||||
return z.core.MemRead(uint16(z.H)<<8 | uint16(z.L))
|
return z.core.MemRead(z.hl())
|
||||||
default:
|
default:
|
||||||
return z.A
|
return z.A
|
||||||
}
|
}
|
||||||
@ -381,7 +378,7 @@ func (z *Z80Type) load8bit(opcode byte, operand byte) {
|
|||||||
case 5:
|
case 5:
|
||||||
z.L = operand
|
z.L = operand
|
||||||
case 6:
|
case 6:
|
||||||
z.core.MemWrite(uint16(z.H)<<8|uint16(z.L), operand)
|
z.core.MemWrite(z.hl(), operand)
|
||||||
default:
|
default:
|
||||||
z.A = operand
|
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
|
// getFlagsRegister return whole F register
|
||||||
func (z *Z80Type) getFlagsRegister() byte {
|
func (z *Z80Type) getFlagsRegister() byte {
|
||||||
return getFlags(&z.Flags)
|
return getFlags(&z.Flags)
|
||||||
@ -478,10 +471,6 @@ func (z *Z80Type) updateXYFlags(result byte) {
|
|||||||
z.Flags.X = result&0x08 != 0
|
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
|
// PushWord - Decrement stack pointer and put specified word value to stack
|
||||||
func (z *Z80Type) PushWord(operand uint16) {
|
func (z *Z80Type) PushWord(operand uint16) {
|
||||||
z.SP--
|
z.SP--
|
||||||
@ -507,8 +496,7 @@ func (z *Z80Type) doConditionalAbsoluteJump(condition bool) {
|
|||||||
// because the instruction decoder increments the PC
|
// because the instruction decoder increments the PC
|
||||||
// unconditionally at the end of every instruction,
|
// unconditionally at the end of every instruction,
|
||||||
// and we need to counteract that so we end up at the jump target.
|
// and we need to counteract that so we end up at the jump target.
|
||||||
// TODO: Check for increment CycleCounter
|
z.PC = z.getWord(z.PC + 1) //uint16( z.core.MemRead(z.PC+1)) | (uint16(z.core.MemRead(z.PC+2)) << 8)
|
||||||
z.PC = uint16(z.core.MemRead(z.PC+1)) | (uint16(z.core.MemRead(z.PC+2)) << 8)
|
|
||||||
z.PC--
|
z.PC--
|
||||||
} else {
|
} else {
|
||||||
// We're not taking this jump, just move the PC past the operand.
|
// 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 {
|
if condition {
|
||||||
z.CycleCounter += 7
|
z.CycleCounter += 7
|
||||||
z.PushWord(z.PC + 3)
|
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--
|
z.PC--
|
||||||
} else {
|
} else {
|
||||||
z.PC += 2
|
z.PC += 2
|
||||||
@ -560,16 +548,6 @@ func (z *Z80Type) doReset(address uint16) {
|
|||||||
z.PC = address - 1
|
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.
|
// doAdd Handle ADD A, [operand] instructions.
|
||||||
func (z *Z80Type) doAdd(operand byte) {
|
func (z *Z80Type) doAdd(operand byte) {
|
||||||
var result = uint16(z.A) + uint16(operand)
|
var result = uint16(z.A) + uint16(operand)
|
||||||
@ -585,6 +563,7 @@ func (z *Z80Type) doAdd(operand byte) {
|
|||||||
z.updateXYFlags(z.A)
|
z.updateXYFlags(z.A)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doAdc Handle ADC A, [operand] instructions.
|
||||||
func (z *Z80Type) doAdc(operand byte) {
|
func (z *Z80Type) doAdc(operand byte) {
|
||||||
add := byte(0)
|
add := byte(0)
|
||||||
if z.Flags.C {
|
if z.Flags.C {
|
||||||
@ -603,6 +582,7 @@ func (z *Z80Type) doAdc(operand byte) {
|
|||||||
z.updateXYFlags(z.A)
|
z.updateXYFlags(z.A)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doSub Handle SUB A, [operand] instructions.
|
||||||
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)
|
||||||
|
|
||||||
@ -617,6 +597,7 @@ func (z *Z80Type) doSub(operand byte) {
|
|||||||
z.updateXYFlags(z.A)
|
z.updateXYFlags(z.A)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doSbc Handle SBC A, [operand] instructions.
|
||||||
func (z *Z80Type) doSbc(operand byte) {
|
func (z *Z80Type) doSbc(operand byte) {
|
||||||
sub := byte(0)
|
sub := byte(0)
|
||||||
if z.Flags.C {
|
if z.Flags.C {
|
||||||
@ -635,6 +616,7 @@ func (z *Z80Type) doSbc(operand byte) {
|
|||||||
z.updateXYFlags(z.A)
|
z.updateXYFlags(z.A)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setLogicFlags Set common flags for logic ALU Ops
|
||||||
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
|
||||||
@ -643,6 +625,7 @@ func (z *Z80Type) setLogicFlags() {
|
|||||||
z.Flags.C = false
|
z.Flags.C = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doAnd handle AND [operand] instructions.
|
||||||
func (z *Z80Type) doAnd(operand byte) {
|
func (z *Z80Type) doAnd(operand byte) {
|
||||||
z.A &= operand
|
z.A &= operand
|
||||||
z.setLogicFlags()
|
z.setLogicFlags()
|
||||||
@ -650,6 +633,7 @@ func (z *Z80Type) doAnd(operand byte) {
|
|||||||
z.updateXYFlags(z.A)
|
z.updateXYFlags(z.A)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doXor handle XOR [operand] instructions.
|
||||||
func (z *Z80Type) doXor(operand byte) {
|
func (z *Z80Type) doXor(operand byte) {
|
||||||
z.A ^= operand
|
z.A ^= operand
|
||||||
z.setLogicFlags()
|
z.setLogicFlags()
|
||||||
@ -657,6 +641,7 @@ func (z *Z80Type) doXor(operand byte) {
|
|||||||
z.updateXYFlags(z.A)
|
z.updateXYFlags(z.A)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doOr handle OR [operand] instructions.
|
||||||
func (z *Z80Type) doOr(operand byte) {
|
func (z *Z80Type) doOr(operand byte) {
|
||||||
z.A |= operand
|
z.A |= operand
|
||||||
z.setLogicFlags()
|
z.setLogicFlags()
|
||||||
@ -664,6 +649,7 @@ func (z *Z80Type) doOr(operand byte) {
|
|||||||
z.updateXYFlags(z.A)
|
z.updateXYFlags(z.A)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doCp handle CP [operand] instructions.
|
||||||
func (z *Z80Type) doCp(operand byte) {
|
func (z *Z80Type) doCp(operand byte) {
|
||||||
tmp := z.A
|
tmp := z.A
|
||||||
z.doSub(operand)
|
z.doSub(operand)
|
||||||
@ -671,6 +657,7 @@ func (z *Z80Type) doCp(operand byte) {
|
|||||||
z.updateXYFlags(operand)
|
z.updateXYFlags(operand)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doInc handle INC [operand] instructions.
|
||||||
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)
|
||||||
@ -685,6 +672,7 @@ func (z *Z80Type) doInc(operand byte) byte {
|
|||||||
return r8
|
return r8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doDec handle DEC [operand] instructions.
|
||||||
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)
|
||||||
@ -699,27 +687,30 @@ func (z *Z80Type) doDec(operand byte) byte {
|
|||||||
return r8
|
return r8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doHlAdd handle ADD HL,[operand] instructions.
|
||||||
func (z *Z80Type) doHlAdd(operand uint16) {
|
func (z *Z80Type) doHlAdd(operand uint16) {
|
||||||
// The HL arithmetic instructions are the same as the A ones,
|
// The HL arithmetic instructions are the same as the A ones,
|
||||||
// just with twice as many bits happening.
|
// 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)
|
result := uint32(hl) + uint32(operand)
|
||||||
z.Flags.N = false
|
z.Flags.N = false
|
||||||
z.Flags.C = result > 0xffff
|
z.Flags.C = result > 0xffff
|
||||||
z.Flags.H = ((hl&0x0fff)+(operand&0x0fff))&0x1000 > 0
|
z.Flags.H = ((hl&0x0fff)+(operand&0x0fff))&0x1000 > 0
|
||||||
|
|
||||||
z.L = byte(result & 0xff)
|
z.setHl(uint16(result))
|
||||||
z.H = byte((result & 0xff00) >> 8)
|
//z.L = byte(result & 0xff)
|
||||||
|
//z.H = byte((result & 0xff00) >> 8)
|
||||||
|
|
||||||
z.updateXYFlags(z.H)
|
z.updateXYFlags(z.H)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doHlAdc handle ADC HL,[operand] instructions.
|
||||||
func (z *Z80Type) doHlAdc(operand uint16) {
|
func (z *Z80Type) doHlAdc(operand uint16) {
|
||||||
if z.Flags.C {
|
if z.Flags.C {
|
||||||
operand++
|
operand++
|
||||||
}
|
}
|
||||||
|
|
||||||
hl := uint16(z.L) | (uint16(z.H) << 8)
|
hl := z.hl()
|
||||||
result := uint32(hl) + uint32(operand)
|
result := uint32(hl) + uint32(operand)
|
||||||
|
|
||||||
z.Flags.S = (result & 0x8000) != 0
|
z.Flags.S = (result & 0x8000) != 0
|
||||||
@ -729,18 +720,20 @@ func (z *Z80Type) doHlAdc(operand uint16) {
|
|||||||
z.Flags.N = false
|
z.Flags.N = false
|
||||||
z.Flags.C = result > 0xffff
|
z.Flags.C = result > 0xffff
|
||||||
|
|
||||||
z.L = byte(result & 0xff)
|
z.setHl(uint16(result))
|
||||||
z.H = byte((result & 0xff00) >> 8)
|
//z.L = byte(result & 0xff)
|
||||||
|
//z.H = byte((result & 0xff00) >> 8)
|
||||||
|
|
||||||
z.updateXYFlags(z.H)
|
z.updateXYFlags(z.H)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doHlSbc handle SBC HL,[operand] instructions.
|
||||||
func (z *Z80Type) doHlSbc(operand uint16) {
|
func (z *Z80Type) doHlSbc(operand uint16) {
|
||||||
if z.Flags.C {
|
if z.Flags.C {
|
||||||
operand++
|
operand++
|
||||||
}
|
}
|
||||||
|
|
||||||
hl := uint16(z.L) | (uint16(z.H) << 8)
|
hl := z.hl() //uint16(z.L) | (uint16(z.H) << 8)
|
||||||
result := uint32(hl) - uint32(operand)
|
result := uint32(hl) - uint32(operand)
|
||||||
|
|
||||||
z.Flags.S = (result & 0x8000) != 0
|
z.Flags.S = (result & 0x8000) != 0
|
||||||
@ -750,8 +743,9 @@ func (z *Z80Type) doHlSbc(operand uint16) {
|
|||||||
z.Flags.N = true
|
z.Flags.N = true
|
||||||
z.Flags.C = result > 0xffff
|
z.Flags.C = result > 0xffff
|
||||||
|
|
||||||
z.L = byte(result & 0xff)
|
z.setHl(uint16(result))
|
||||||
z.H = byte((result & 0xff00) >> 8)
|
//z.L = byte(result & 0xff)
|
||||||
|
//z.H = byte((result & 0xff00) >> 8)
|
||||||
|
|
||||||
z.updateXYFlags(z.H)
|
z.updateXYFlags(z.H)
|
||||||
}
|
}
|
||||||
@ -786,10 +780,8 @@ func (z *Z80Type) doNeg() {
|
|||||||
|
|
||||||
func (z *Z80Type) doLdi() {
|
func (z *Z80Type) doLdi() {
|
||||||
// Copy the value that we're supposed to copy.
|
// Copy the value that we're supposed to copy.
|
||||||
hl := uint16(z.L) | (uint16(z.H) << 8)
|
readValue := z.core.MemRead(z.hl())
|
||||||
de := uint16(z.E) | (uint16(z.D) << 8)
|
z.core.MemWrite(z.de(), readValue)
|
||||||
readValue := z.core.MemRead(hl)
|
|
||||||
z.core.MemWrite(de, readValue)
|
|
||||||
|
|
||||||
z.incDe()
|
z.incDe()
|
||||||
z.incHl()
|
z.incHl()
|
||||||
@ -802,63 +794,49 @@ func (z *Z80Type) doLdi() {
|
|||||||
z.Flags.X = ((z.A+readValue)&0x08)>>3 != 0
|
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() {
|
func (z *Z80Type) doCpi() {
|
||||||
tempCarry := z.Flags.C
|
tempCarry := z.Flags.C
|
||||||
hl := uint16(z.L) | (uint16(z.H) << 8)
|
readValue := z.core.MemRead(z.hl())
|
||||||
readValue := z.core.MemRead(hl)
|
|
||||||
z.doCp(readValue)
|
z.doCp(readValue)
|
||||||
|
|
||||||
z.Flags.C = tempCarry
|
z.Flags.C = tempCarry
|
||||||
var fh byte = 0
|
fh := z.fhv()
|
||||||
if z.Flags.H {
|
|
||||||
fh = 1
|
|
||||||
}
|
|
||||||
z.Flags.Y = ((z.A-readValue-fh)&0x02)>>1 != 0
|
z.Flags.Y = ((z.A-readValue-fh)&0x02)>>1 != 0
|
||||||
z.Flags.X = ((z.A-readValue-fh)&0x08)>>3 != 0
|
z.Flags.X = ((z.A-readValue-fh)&0x08)>>3 != 0
|
||||||
|
|
||||||
z.incHl()
|
z.incHl()
|
||||||
z.decBc()
|
z.decBc()
|
||||||
|
|
||||||
z.Flags.P = (z.B | z.C) != 0
|
z.Flags.P = (z.B | z.C) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) doIni() {
|
func (z *Z80Type) doIni() {
|
||||||
hl := (uint16(z.H) << 8) | uint16(z.L)
|
z.core.MemWrite(z.hl(), z.core.IORead(z.bc()))
|
||||||
bc := (uint16(z.B) << 8) | uint16(z.C)
|
|
||||||
z.core.MemWrite(hl, z.core.IORead(bc))
|
|
||||||
|
|
||||||
z.incHl()
|
z.incHl()
|
||||||
|
|
||||||
z.B = z.doDec(z.B)
|
z.B = z.doDec(z.B)
|
||||||
z.Flags.N = true
|
z.Flags.N = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) doOuti() {
|
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)
|
z.B = z.doDec(z.B)
|
||||||
hl := (uint16(z.H) << 8) | uint16(z.L)
|
z.core.IOWrite(z.bc(), z.core.MemRead(z.hl()))
|
||||||
bc := (uint16(z.B) << 8) | uint16(z.C)
|
|
||||||
z.core.IOWrite(bc, z.core.MemRead(hl))
|
|
||||||
|
|
||||||
z.incHl()
|
z.incHl()
|
||||||
|
|
||||||
z.Flags.N = true
|
z.Flags.N = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) doLdd() {
|
func (z *Z80Type) doLdd() {
|
||||||
z.Flags.N = false
|
z.Flags.N = false
|
||||||
z.Flags.H = false
|
z.Flags.H = false
|
||||||
|
readValue := z.core.MemRead(z.hl())
|
||||||
hl := (uint16(z.H) << 8) | uint16(z.L)
|
z.core.MemWrite(z.de(), readValue)
|
||||||
de := (uint16(z.D) << 8) | uint16(z.E)
|
|
||||||
|
|
||||||
readValue := z.core.MemRead(hl)
|
|
||||||
z.core.MemWrite(de, readValue)
|
|
||||||
|
|
||||||
z.decDe()
|
z.decDe()
|
||||||
z.decHl()
|
z.decHl()
|
||||||
z.decBc()
|
z.decBc()
|
||||||
|
|
||||||
z.Flags.P = (z.C | z.B) != 0
|
z.Flags.P = (z.C | z.B) != 0
|
||||||
z.Flags.Y = ((z.A+readValue)&0x02)>>1 != 0
|
z.Flags.Y = ((z.A+readValue)&0x02)>>1 != 0
|
||||||
z.Flags.X = ((z.A+readValue)&0x08)>>3 != 0
|
z.Flags.X = ((z.A+readValue)&0x08)>>3 != 0
|
||||||
@ -866,16 +844,12 @@ func (z *Z80Type) doLdd() {
|
|||||||
|
|
||||||
func (z *Z80Type) doCpd() {
|
func (z *Z80Type) doCpd() {
|
||||||
tempCarry := z.Flags.C
|
tempCarry := z.Flags.C
|
||||||
hl := uint16(z.L) | (uint16(z.H) << 8)
|
readValue := z.core.MemRead(z.hl())
|
||||||
readValue := z.core.MemRead(hl)
|
|
||||||
z.doCp(readValue)
|
z.doCp(readValue)
|
||||||
|
|
||||||
z.Flags.C = tempCarry
|
z.Flags.C = tempCarry
|
||||||
|
|
||||||
var fh byte = 0
|
fh := z.fhv()
|
||||||
if z.Flags.H {
|
|
||||||
fh = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
z.Flags.Y = ((z.A-readValue-fh)&0x02)>>1 != 0
|
z.Flags.Y = ((z.A-readValue-fh)&0x02)>>1 != 0
|
||||||
z.Flags.X = ((z.A-readValue-fh)&0x08)>>3 != 0
|
z.Flags.X = ((z.A-readValue-fh)&0x08)>>3 != 0
|
||||||
@ -887,20 +861,15 @@ func (z *Z80Type) doCpd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) doInd() {
|
func (z *Z80Type) doInd() {
|
||||||
hl := (uint16(z.H) << 8) | uint16(z.L)
|
z.core.MemWrite(z.hl(), z.core.IORead(z.bc()))
|
||||||
bc := (uint16(z.B) << 8) | uint16(z.C)
|
|
||||||
z.core.MemWrite(hl, z.core.IORead(bc))
|
|
||||||
z.decHl()
|
z.decHl()
|
||||||
z.B = z.doDec(z.B)
|
z.B = z.doDec(z.B)
|
||||||
z.Flags.N = true
|
z.Flags.N = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) doOutd() {
|
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)
|
z.B = z.doDec(z.B)
|
||||||
hl := (uint16(z.H) << 8) | uint16(z.L)
|
z.core.IOWrite(z.bc(), z.core.MemRead(z.hl()))
|
||||||
bc := (uint16(z.B) << 8) | uint16(z.C)
|
|
||||||
z.core.IOWrite(bc, z.core.MemRead(hl))
|
|
||||||
z.decHl()
|
z.decHl()
|
||||||
z.Flags.N = true
|
z.Flags.N = true
|
||||||
}
|
}
|
||||||
@ -999,29 +968,6 @@ func (z *Z80Type) setShiftFlags(operand byte) {
|
|||||||
z.updateXYFlags(operand)
|
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
|
// ============== get register pairs
|
||||||
|
|
||||||
func (z *Z80Type) bc() uint16 {
|
func (z *Z80Type) bc() uint16 {
|
||||||
@ -1039,58 +985,58 @@ func (z *Z80Type) hl() uint16 {
|
|||||||
// ============ helper fn
|
// ============ helper fn
|
||||||
|
|
||||||
func (z *Z80Type) incBc() {
|
func (z *Z80Type) incBc() {
|
||||||
z.changeBc(+1)
|
z.setBc(z.bc() + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) decBc() {
|
func (z *Z80Type) decBc() {
|
||||||
z.changeBc(-1)
|
z.setBc(z.bc() - 1)
|
||||||
}
|
|
||||||
|
|
||||||
func (z *Z80Type) incHl() {
|
|
||||||
z.changeHl(+1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (z *Z80Type) decHl() {
|
|
||||||
z.changeHl(-1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) incDe() {
|
func (z *Z80Type) incDe() {
|
||||||
z.changeDe(+1)
|
z.setDe(z.de() + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) decDe() {
|
func (z *Z80Type) decDe() {
|
||||||
z.changeDe(-1)
|
z.setDe(z.de() - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) changeDe(val int8) {
|
func (z *Z80Type) incHl() {
|
||||||
de := (uint16(z.D) << 8) | uint16(z.E)
|
z.setHl(z.hl() + 1)
|
||||||
if val < 0 {
|
|
||||||
de--
|
|
||||||
} else {
|
|
||||||
de++
|
|
||||||
}
|
|
||||||
z.E = byte(de & 0xff)
|
|
||||||
z.D = byte(de >> 8)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) changeBc(val int8) {
|
func (z *Z80Type) decHl() {
|
||||||
bc := (uint16(z.B) << 8) | uint16(z.C)
|
z.setHl(z.hl() - 1)
|
||||||
if val < 0 {
|
|
||||||
bc--
|
|
||||||
} else {
|
|
||||||
bc++
|
|
||||||
}
|
|
||||||
z.C = byte(bc & 0x00ff)
|
|
||||||
z.B = byte(bc >> 8)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80Type) changeHl(val int8) {
|
func (z *Z80Type) setHl(val uint16) {
|
||||||
hl := (uint16(z.H) << 8) | uint16(z.L)
|
z.L = byte(val & 0xff)
|
||||||
if val < 0 {
|
z.H = byte(val >> 8)
|
||||||
hl--
|
}
|
||||||
} else {
|
|
||||||
hl++
|
func (z *Z80Type) setDe(val uint16) {
|
||||||
}
|
z.E = byte(val & 0xff)
|
||||||
z.L = byte(hl & 0xff)
|
z.D = byte(val >> 8)
|
||||||
z.H = byte(hl >> 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))
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user