mirror of
https://github.com/romychs/Ocean-240.2-Emulator.git
synced 2026-04-21 11:03:21 +03:00
Additional floppy drive C 720k
This commit is contained in:
parent
e28b052cbf
commit
ed43a19a10
@ -15,6 +15,8 @@ type OkEmuConfig struct {
|
|||||||
LogLevel string `yaml:"logLevel"`
|
LogLevel string `yaml:"logLevel"`
|
||||||
MonitorFile string `yaml:"monitorFile"`
|
MonitorFile string `yaml:"monitorFile"`
|
||||||
CPMFile string `yaml:"cpmFile"`
|
CPMFile string `yaml:"cpmFile"`
|
||||||
|
FloppyB string `yaml:"floppyB"`
|
||||||
|
FloppyC string `yaml:"floppyC"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var config *OkEmuConfig
|
var config *OkEmuConfig
|
||||||
|
|||||||
BIN
floppy.okd
BIN
floppy.okd
Binary file not shown.
29
main.go
29
main.go
@ -7,6 +7,7 @@ import (
|
|||||||
"okemu/config"
|
"okemu/config"
|
||||||
"okemu/logger"
|
"okemu/logger"
|
||||||
"okemu/okean240"
|
"okemu/okean240"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
@ -23,10 +24,11 @@ var BuildTime = "2026-03-01"
|
|||||||
//go:embed hex/format.hex
|
//go:embed hex/format.hex
|
||||||
var serialBytes []byte
|
var serialBytes []byte
|
||||||
|
|
||||||
//go:embed bin/TET.COM
|
//go:embed bin/FORMAT.COM
|
||||||
var ramBytes []byte
|
var ramBytes []byte
|
||||||
|
|
||||||
var needReset = false
|
var needReset = false
|
||||||
|
var fullSpeed atomic.Bool
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
@ -107,9 +109,12 @@ func mainWindow(computer *okean240.ComputerType) (*fyne.Window, *canvas.Raster,
|
|||||||
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(0x100, 15000)
|
||||||
//}),
|
}),
|
||||||
|
widget.NewCheck("Full speed", func(b bool) {
|
||||||
|
fullSpeed.Store(b)
|
||||||
|
}),
|
||||||
widget.NewSeparator(),
|
widget.NewSeparator(),
|
||||||
widget.NewButton("Reset", func() {
|
widget.NewButton("Reset", func() {
|
||||||
needReset = true
|
needReset = true
|
||||||
@ -152,31 +157,31 @@ func screen(computer *okean240.ComputerType, raster *canvas.Raster, label *widge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ticksPerTicker uint64 = 3
|
const ticksPerTact uint64 = 3
|
||||||
|
|
||||||
func emulator(computer *okean240.ComputerType) {
|
func emulator(computer *okean240.ComputerType) {
|
||||||
ticker := time.NewTicker(66 * time.Nanosecond)
|
ticker := time.NewTicker(66 * time.Nanosecond)
|
||||||
var ticks uint64 = 0
|
var ticks uint64 = 0
|
||||||
var nextClock uint64 = ticks + ticksPerTicker
|
var nextClock = ticks + ticksPerTact
|
||||||
//var ticksCPU = 3
|
//var ticksCPU = 3
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
//for {
|
|
||||||
//time.Sleep(133 * time.Nanosecond)
|
|
||||||
ticks++
|
ticks++
|
||||||
if ticks%10 == 0 {
|
if ticks%10 == 0 {
|
||||||
// 1.5 MHz
|
// 1.5 MHz
|
||||||
computer.TimerClk()
|
computer.TimerClk()
|
||||||
}
|
}
|
||||||
|
if fullSpeed.Load() {
|
||||||
|
computer.Do()
|
||||||
|
} else {
|
||||||
if ticks >= nextClock {
|
if ticks >= nextClock {
|
||||||
nextClock = ticks + computer.Do()*ticksPerTicker
|
nextClock = ticks + computer.Do()*ticksPerTact
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
//computer.Do()
|
||||||
if needReset {
|
if needReset {
|
||||||
computer.Reset()
|
computer.Reset()
|
||||||
needReset = false
|
needReset = false
|
||||||
}
|
}
|
||||||
//if ticks > ticksCPU {
|
|
||||||
//ticksCPU = ticks + computer.Do()*2
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,20 +2,25 @@ package okean240
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"encoding/binary"
|
||||||
"image/color"
|
"image/color"
|
||||||
"okemu/config"
|
"okemu/config"
|
||||||
"okemu/okean240/fdc"
|
"okemu/okean240/fdc"
|
||||||
"okemu/okean240/pic"
|
"okemu/okean240/pic"
|
||||||
"okemu/okean240/pit"
|
"okemu/okean240/pit"
|
||||||
"okemu/okean240/usart"
|
"okemu/okean240/usart"
|
||||||
"okemu/z80/js"
|
"os"
|
||||||
|
|
||||||
|
//"okemu/z80"
|
||||||
|
"okemu/z80/c99"
|
||||||
|
//"okemu/z80/js"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ComputerType struct {
|
type ComputerType struct {
|
||||||
cpu *js.Z80
|
cpu *c99.Z80
|
||||||
memory Memory
|
memory Memory
|
||||||
ioPorts [256]byte
|
ioPorts [256]byte
|
||||||
cycles uint64
|
cycles uint64
|
||||||
@ -73,7 +78,7 @@ func New(cfg *config.OkEmuConfig) *ComputerType {
|
|||||||
c.memory = Memory{}
|
c.memory = Memory{}
|
||||||
c.memory.Init(cfg.MonitorFile, cfg.CPMFile)
|
c.memory.Init(cfg.MonitorFile, cfg.CPMFile)
|
||||||
|
|
||||||
c.cpu = js.New(&c)
|
c.cpu = c99.New(&c)
|
||||||
|
|
||||||
c.cycles = 0
|
c.cycles = 0
|
||||||
c.dd17EnableOut = false
|
c.dd17EnableOut = false
|
||||||
@ -90,7 +95,7 @@ func New(cfg *config.OkEmuConfig) *ComputerType {
|
|||||||
c.pit = pit.New()
|
c.pit = pit.New()
|
||||||
c.usart = usart.New()
|
c.usart = usart.New()
|
||||||
c.pic = pic.New()
|
c.pic = pic.New()
|
||||||
c.fdc = fdc.New()
|
c.fdc = fdc.New(cfg)
|
||||||
|
|
||||||
return &c
|
return &c
|
||||||
}
|
}
|
||||||
@ -110,14 +115,11 @@ func (c *ComputerType) Reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ComputerType) Do() uint64 {
|
func (c *ComputerType) Do() uint64 {
|
||||||
//s := c.cpu.GetState()
|
|
||||||
//if s.PC == 0xe0db {
|
|
||||||
// log.Debugf("breakpoint")
|
|
||||||
//}
|
|
||||||
ticks := c.cpu.RunInstruction()
|
ticks := c.cpu.RunInstruction()
|
||||||
c.cycles += ticks
|
c.cycles += ticks
|
||||||
//if c.cpu.PC == 0xFF26 {
|
//pc := c.cpu.GetState().PC
|
||||||
// log.Debugf("%4X: H:%X L:%X A:%X B: %X C: %X D: %X E: %X", c.cpu.PC, c.cpu.H, c.cpu.L, c.cpu.A, c.cpu.B, c.cpu.C, c.cpu.D, c.cpu.E)
|
//if pc >= 0xfea3 && pc <= 0xff25 {
|
||||||
|
// c.cpu.DebugOutput()
|
||||||
//}
|
//}
|
||||||
return ticks
|
return ticks
|
||||||
}
|
}
|
||||||
@ -245,25 +247,28 @@ 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 := start; addr < start+length; addr++ {
|
||||||
// buffer = append(buffer, c.memory.MemRead(uint16(addr)))
|
buffer = append(buffer, c.memory.MemRead(addr))
|
||||||
// }
|
}
|
||||||
// err = binary.Write(file, binary.LittleEndian, buffer)
|
_, err = file.Write(buffer)
|
||||||
// if err != nil {
|
err = binary.Write(file, binary.LittleEndian, buffer)
|
||||||
// log.Error("Save memory dump failed:", err)
|
if err != nil {
|
||||||
// }
|
log.Error("Save memory dump failed:", err)
|
||||||
//}
|
} else {
|
||||||
|
log.Debug("Memory dump saved successfully")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -8,7 +8,9 @@ package fdc
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"okemu/config"
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -18,6 +20,7 @@ import (
|
|||||||
|
|
||||||
// Floppy parameters
|
// Floppy parameters
|
||||||
const (
|
const (
|
||||||
|
TotalDrives = 2
|
||||||
FloppySizeK = 720
|
FloppySizeK = 720
|
||||||
SectorSize = 512
|
SectorSize = 512
|
||||||
SideCount = 2
|
SideCount = 2
|
||||||
@ -69,14 +72,16 @@ type FloppyDriveController struct {
|
|||||||
sectorNo byte
|
sectorNo byte
|
||||||
trackNo byte
|
trackNo byte
|
||||||
drq byte
|
drq byte
|
||||||
// FloppyStorage
|
// FloppyStorage B and C
|
||||||
sectors [SizeInSectors]SectorType
|
sectors [TotalDrives][SizeInSectors]SectorType
|
||||||
data byte
|
data byte
|
||||||
status byte
|
status byte
|
||||||
lastCmd byte
|
lastCmd byte
|
||||||
//curSector *SectorType
|
//curSector *SectorType
|
||||||
bytePtr uint16
|
bytePtr uint16
|
||||||
trackBuffer []byte
|
trackBuffer []byte
|
||||||
|
floppyBFile string
|
||||||
|
floppyCFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
type FloppyDriveControllerInterface interface {
|
type FloppyDriveControllerInterface interface {
|
||||||
@ -95,8 +100,12 @@ type FloppyDriveControllerInterface interface {
|
|||||||
Sector() byte
|
Sector() byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getSectorNo(side byte, track byte, sector byte) uint16 {
|
||||||
|
return uint16(side)*SectorsPerSide + uint16(track)*SectorPerTrack + uint16(sector) - 1
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FloppyDriveController) GetSectorNo() uint16 {
|
func (f *FloppyDriveController) GetSectorNo() uint16 {
|
||||||
return uint16(f.sideNo)*SectorsPerSide + uint16(f.trackNo)*SectorPerTrack + uint16(f.sectorNo) - 1
|
return getSectorNo(f.sideNo, f.trackNo, f.sectorNo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FloppyDriveController) SetFloppy(val byte) {
|
func (f *FloppyDriveController) SetFloppy(val byte) {
|
||||||
@ -104,14 +113,14 @@ func (f *FloppyDriveController) SetFloppy(val byte) {
|
|||||||
f.sideNo = val >> 5 & 0x01
|
f.sideNo = val >> 5 & 0x01
|
||||||
f.ddEn = val >> 4 & 0x01
|
f.ddEn = val >> 4 & 0x01
|
||||||
f.init = val >> 3 & 0x01
|
f.init = val >> 3 & 0x01
|
||||||
f.drive = val >> 2 & 0x01
|
f.drive = (^val) >> 2 & 0x01
|
||||||
f.mot1 = val >> 1 & 0x01
|
f.mot1 = val >> 1 & 0x01
|
||||||
f.mot0 = val & 0x01
|
f.mot0 = val & 0x01
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FloppyDriveController) GetFloppy() byte {
|
func (f *FloppyDriveController) GetFloppy() byte {
|
||||||
// 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
|
||||||
floppy := f.intRq | (f.mot0 << 1) | (f.mot1 << 2) | (f.drive << 3) | (f.sideNo << 6) | (f.motSt << 7)
|
floppy := f.intRq | (f.mot0 << 1) | (f.mot1 << 2) | ((^f.drive & 1) << 3) | (f.sideNo << 6) | (f.motSt << 7)
|
||||||
return floppy
|
return floppy
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,34 +128,34 @@ func (f *FloppyDriveController) SetCmd(value byte) {
|
|||||||
f.lastCmd = value >> 4
|
f.lastCmd = value >> 4
|
||||||
switch f.lastCmd {
|
switch f.lastCmd {
|
||||||
case CmdRestore:
|
case CmdRestore:
|
||||||
log.Debug("CMD Restore (seek trackNo 0)")
|
log.Trace("CMD Restore (seek trackNo 0)")
|
||||||
f.trackNo = 0
|
f.trackNo = 0
|
||||||
f.status = StatusTR0 | StatusHeadLoaded // TR0 & Head loaded
|
f.status = StatusTR0 | StatusHeadLoaded // TR0 & Head loaded
|
||||||
case CmdSeek:
|
case CmdSeek:
|
||||||
log.Debugf("CMD Seek %x", value&0xf)
|
log.Tracef("CMD Seek %x", value&0xf)
|
||||||
f.status = StatusHeadLoaded
|
f.status = StatusHeadLoaded
|
||||||
f.trackNo = f.data
|
f.trackNo = f.data
|
||||||
case CmdStep:
|
case CmdStep:
|
||||||
log.Debugf("CMD Step %x", value&0xf)
|
log.Tracef("CMD Step %x", value&0xf)
|
||||||
f.status = StatusHeadLoaded
|
f.status = StatusHeadLoaded
|
||||||
f.trackNo = f.data
|
f.trackNo = f.data
|
||||||
case CmdStepIn:
|
case CmdStepIn:
|
||||||
log.Debugf("CMD StepIn (Next track) %x", value&0xf)
|
log.Tracef("CMD StepIn (Next track) %x", value&0xf)
|
||||||
f.status = StatusHeadLoaded
|
f.status = StatusHeadLoaded
|
||||||
if f.trackNo < TracksCount {
|
if f.trackNo < TracksCount {
|
||||||
f.trackNo++
|
f.trackNo++
|
||||||
}
|
}
|
||||||
case CmdStepOut:
|
case CmdStepOut:
|
||||||
log.Debugf("CMD StepOut (Previous track) %x", value&0xf)
|
log.Tracef("CMD StepOut (Previous track) %x", value&0xf)
|
||||||
f.status = StatusHeadLoaded
|
f.status = StatusHeadLoaded
|
||||||
if f.trackNo > 0 {
|
if f.trackNo > 0 {
|
||||||
f.trackNo--
|
f.trackNo--
|
||||||
}
|
}
|
||||||
case CmdReadSector:
|
case CmdReadSector:
|
||||||
sectorNo := f.GetSectorNo()
|
sectorNo := f.GetSectorNo()
|
||||||
log.Debugf("CMD Read single sectorNo: %d", sectorNo)
|
log.Tracef("CMD Read single sectorNo: %d", sectorNo)
|
||||||
if sectorNo < SizeInSectors {
|
if sectorNo < SizeInSectors {
|
||||||
f.trackBuffer = slices.Clone(f.sectors[sectorNo])
|
f.trackBuffer = slices.Clone(f.sectors[f.drive][sectorNo])
|
||||||
f.drq = 1
|
f.drq = 1
|
||||||
f.status = 0x00
|
f.status = 0x00
|
||||||
} else {
|
} else {
|
||||||
@ -157,14 +166,14 @@ func (f *FloppyDriveController) SetCmd(value byte) {
|
|||||||
sectorNo := f.GetSectorNo()
|
sectorNo := f.GetSectorNo()
|
||||||
f.trackBuffer = []byte{}
|
f.trackBuffer = []byte{}
|
||||||
for c := 0; c < SectorPerTrack; c++ {
|
for c := 0; c < SectorPerTrack; c++ {
|
||||||
f.trackBuffer = slices.Concat(f.trackBuffer, f.sectors[sectorNo])
|
f.trackBuffer = slices.Concat(f.trackBuffer, f.sectors[f.drive][sectorNo])
|
||||||
sectorNo++
|
sectorNo++
|
||||||
}
|
}
|
||||||
f.drq = 1
|
f.drq = 1
|
||||||
f.status = 0x0
|
f.status = 0x0
|
||||||
case CmdWriteSector:
|
case CmdWriteSector:
|
||||||
sectorNo := f.GetSectorNo()
|
sectorNo := f.GetSectorNo()
|
||||||
log.Debugf("CMD Write Sector %d", sectorNo)
|
log.Tracef("CMD Write Sector %d", sectorNo)
|
||||||
if sectorNo < SizeInSectors {
|
if sectorNo < SizeInSectors {
|
||||||
f.bytePtr = 0
|
f.bytePtr = 0
|
||||||
f.drq = 1
|
f.drq = 1
|
||||||
@ -175,12 +184,12 @@ func (f *FloppyDriveController) SetCmd(value byte) {
|
|||||||
f.status = StatusRNF
|
f.status = StatusRNF
|
||||||
}
|
}
|
||||||
case CmdWriteTrack:
|
case CmdWriteTrack:
|
||||||
log.Debugf("CMD Write Track %x", f.trackNo)
|
log.Tracef("CMD Write Track %x", f.trackNo)
|
||||||
f.status = 0x00
|
f.status = 0x00
|
||||||
f.trackBuffer = []byte{}
|
f.trackBuffer = []byte{}
|
||||||
f.drq = 1
|
f.drq = 1
|
||||||
default:
|
default:
|
||||||
log.Debugf("Unknown CMD: %x VAL: %x", f.lastCmd, value&0xf)
|
log.Errorf("Unknown CMD: %x VAL: %x", f.lastCmd, value&0xf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +198,7 @@ func (f *FloppyDriveController) Status() byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *FloppyDriveController) SetTrackNo(value byte) {
|
func (f *FloppyDriveController) SetTrackNo(value byte) {
|
||||||
//log.Debugf("FDC Track: %d", value)
|
//log.Tracef("FDC Track: %d", value)
|
||||||
if value > TracksCount {
|
if value > TracksCount {
|
||||||
f.status |= 0x10 /// RNF
|
f.status |= 0x10 /// RNF
|
||||||
log.Error("Track not found!")
|
log.Error("Track not found!")
|
||||||
@ -199,17 +208,17 @@ func (f *FloppyDriveController) SetTrackNo(value byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *FloppyDriveController) SetSectorNo(value byte) {
|
func (f *FloppyDriveController) SetSectorNo(value byte) {
|
||||||
//log.Debugf("FDC Sector: %d", value)
|
//log.Tracef("FDC Sector: %d", value)
|
||||||
if value > SectorPerTrack {
|
if value > SectorPerTrack {
|
||||||
f.status |= 0x10
|
f.status |= 0x10
|
||||||
log.Error("Record not found!")
|
log.Errorf("Record not found %d!", value)
|
||||||
} else {
|
} else {
|
||||||
f.sectorNo = value
|
f.sectorNo = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FloppyDriveController) SetData(value byte) {
|
func (f *FloppyDriveController) SetData(value byte) {
|
||||||
//log.Debugf("FCD Data: %d", value)
|
//log.Tracef("FCD Data: %d", value)
|
||||||
if f.lastCmd == CmdWriteTrack {
|
if f.lastCmd == CmdWriteTrack {
|
||||||
if len(f.trackBuffer) < TrackBufferSize {
|
if len(f.trackBuffer) < TrackBufferSize {
|
||||||
f.trackBuffer = append(f.trackBuffer, value)
|
f.trackBuffer = append(f.trackBuffer, value)
|
||||||
@ -217,6 +226,7 @@ func (f *FloppyDriveController) SetData(value byte) {
|
|||||||
f.status = 0x00
|
f.status = 0x00
|
||||||
} else {
|
} else {
|
||||||
//f.dump()
|
//f.dump()
|
||||||
|
f.writeTrack()
|
||||||
f.drq = 0
|
f.drq = 0
|
||||||
f.status = 0x00
|
f.status = 0x00
|
||||||
f.lastCmd = CmdNoCommand
|
f.lastCmd = CmdNoCommand
|
||||||
@ -232,13 +242,44 @@ func (f *FloppyDriveController) SetData(value byte) {
|
|||||||
}
|
}
|
||||||
if len(f.trackBuffer) == SectorSize {
|
if len(f.trackBuffer) == SectorSize {
|
||||||
f.drq = 0
|
f.drq = 0
|
||||||
f.sectors[f.GetSectorNo()] = slices.Clone(f.trackBuffer)
|
f.sectors[f.drive][f.GetSectorNo()] = slices.Clone(f.trackBuffer)
|
||||||
f.lastCmd = CmdNoCommand
|
f.lastCmd = CmdNoCommand
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.data = value
|
f.data = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SectorInfoSize = 626
|
||||||
|
const SectorInfoOffset = 0x0092
|
||||||
|
const TrackNoOffset = 0x0010
|
||||||
|
const SideNoOffset = 0x0011
|
||||||
|
const SectorNoOffset = 0x0012
|
||||||
|
const SectorLengthOffset = 0x0013
|
||||||
|
const SectorDataOffset = 0x003b
|
||||||
|
|
||||||
|
var SectorLengths = []int{128, 256, 512, 1024}
|
||||||
|
|
||||||
|
func (f *FloppyDriveController) writeTrack() {
|
||||||
|
// skip header
|
||||||
|
ptr := SectorInfoOffset
|
||||||
|
// repeat for every sector on track
|
||||||
|
for sec := 0; sec < SectorPerTrack; sec++ {
|
||||||
|
// get info from header
|
||||||
|
trackNo := f.trackBuffer[ptr+TrackNoOffset]
|
||||||
|
sideNo := f.trackBuffer[ptr+SideNoOffset]
|
||||||
|
sectorNo := f.trackBuffer[ptr+SectorNoOffset]
|
||||||
|
sectorLength := SectorLengths[f.trackBuffer[ptr+SectorLengthOffset]&0x03]
|
||||||
|
// get sector data
|
||||||
|
sectorData := f.trackBuffer[ptr+SectorDataOffset : ptr+SectorDataOffset+sectorLength]
|
||||||
|
absSector := getSectorNo(sideNo, trackNo, sectorNo)
|
||||||
|
log.Debugf("Write Drive: %d; side:%d; T: %d S: %d Len: %d Data: [%X..%X]; Abs sector: %d", f.drive, sideNo, trackNo, sectorNo, len(sectorData), sectorData[0], sectorData[len(sectorData)-1], absSector)
|
||||||
|
// write data to sector buffer
|
||||||
|
f.sectors[f.drive][absSector] = slices.Clone(sectorData)
|
||||||
|
// shift pointer to next sector info block
|
||||||
|
ptr += SectorInfoSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FloppyDriveController) Data() byte {
|
func (f *FloppyDriveController) Data() byte {
|
||||||
switch f.lastCmd {
|
switch f.lastCmd {
|
||||||
case CmdReadSector, CmdReadSectorMulti:
|
case CmdReadSector, CmdReadSectorMulti:
|
||||||
@ -263,70 +304,26 @@ func (f *FloppyDriveController) Drq() byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *FloppyDriveController) LoadFloppy() {
|
func (f *FloppyDriveController) LoadFloppy() {
|
||||||
log.Debug("Load Floppy content.")
|
log.Debug("Load Floppy B")
|
||||||
file, err := os.Open("floppy.okd")
|
loadFloppy(&f.sectors[0], f.floppyBFile)
|
||||||
if err != nil {
|
log.Debug("Load Floppy C")
|
||||||
log.Error(err)
|
loadFloppy(&f.sectors[1], f.floppyCFile)
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func(file *os.File) {
|
|
||||||
err := file.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
}(file)
|
|
||||||
|
|
||||||
for sector := 0; sector < SizeInSectors; sector++ {
|
|
||||||
var n int
|
|
||||||
n, err = file.Read(f.sectors[sector])
|
|
||||||
if n != SectorSize {
|
|
||||||
log.Error("Load floppy error, sector size: %d <> %d", n, SectorSize)
|
|
||||||
}
|
|
||||||
// err = binary.Read(file, binary.LittleEndian, f.sectors[sector])
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Load floppy content failed:", err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FloppyDriveController) SaveFloppy() {
|
func (f *FloppyDriveController) SaveFloppy() {
|
||||||
log.Debug("Save Floppy content.")
|
log.Debug("Save Floppy B")
|
||||||
file, err := os.Create("floppy.okd")
|
saveFloppy(&f.sectors[0], f.floppyBFile)
|
||||||
if err != nil {
|
log.Debug("Save Floppy C")
|
||||||
log.Error(err)
|
saveFloppy(&f.sectors[1], f.floppyCFile)
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func(file *os.File) {
|
|
||||||
err := file.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
}(file)
|
|
||||||
|
|
||||||
// Write the struct to the file in little-endian byte order
|
|
||||||
for sector := 0; sector < SizeInSectors; sector++ {
|
|
||||||
var n int
|
|
||||||
n, err = file.Write(f.sectors[sector])
|
|
||||||
if n != SectorSize {
|
|
||||||
log.Errorf("Save floppy error, sector %d size: %d <> %d", sector, n, SectorSize)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Save floppy content failed:", err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *FloppyDriveController {
|
func New(conf *config.OkEmuConfig) *FloppyDriveController {
|
||||||
sec := [SizeInSectors]SectorType{}
|
sec := [2][SizeInSectors]SectorType{}
|
||||||
|
// for each drive
|
||||||
|
for d := 0; d < TotalDrives; d++ {
|
||||||
|
// for each sector
|
||||||
for i := 0; i < SizeInSectors; i++ {
|
for i := 0; i < SizeInSectors; i++ {
|
||||||
sec[i] = make([]byte, SectorSize)
|
sec[d][i] = bytes.Repeat([]byte{0xe5}, SectorSize)
|
||||||
for s := 0; s < SectorSize; s++ {
|
|
||||||
sec[i][s] = 0xE5
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &FloppyDriveController{
|
return &FloppyDriveController{
|
||||||
@ -342,11 +339,13 @@ func New() *FloppyDriveController {
|
|||||||
lastCmd: 0xff,
|
lastCmd: 0xff,
|
||||||
sectors: sec,
|
sectors: sec,
|
||||||
bytePtr: 0xffff,
|
bytePtr: 0xffff,
|
||||||
|
floppyBFile: conf.FloppyB,
|
||||||
|
floppyCFile: conf.FloppyC,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FloppyDriveController) dump() {
|
func (f *FloppyDriveController) dump() {
|
||||||
log.Debug("Dump Buffer content.")
|
log.Trace("Dump Buffer content.")
|
||||||
file, err := os.Create("track-" + strconv.Itoa(int(f.trackNo)) + ".dat")
|
file, err := os.Create("track-" + strconv.Itoa(int(f.trackNo)) + ".dat")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
@ -375,3 +374,58 @@ func (f *FloppyDriveController) Sector() byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
func loadFloppy(sectors *[SizeInSectors]SectorType, fileName string) {
|
||||||
|
log.Debugf("Load Floppy content from file %s.", fileName)
|
||||||
|
file, err := os.Open(fileName)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func(file *os.File) {
|
||||||
|
err := file.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}(file)
|
||||||
|
|
||||||
|
for sector := 0; sector < SizeInSectors; sector++ {
|
||||||
|
var n int
|
||||||
|
n, err = file.Read(sectors[sector])
|
||||||
|
if n != SectorSize {
|
||||||
|
log.Error("Load floppy error, sector size: %d <> %d", n, SectorSize)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Load floppy content failed:", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveFloppy(sectors *[SizeInSectors]SectorType, fileName string) {
|
||||||
|
log.Debugf("Save Floppy to file %s.", fileName)
|
||||||
|
file, err := os.Create(fileName)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(file *os.File) {
|
||||||
|
err := file.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}(file)
|
||||||
|
|
||||||
|
for sector := 0; sector < SizeInSectors; sector++ {
|
||||||
|
var n int
|
||||||
|
n, err = file.Write(sectors[sector])
|
||||||
|
if n != SectorSize {
|
||||||
|
log.Errorf("Save floppy error, sector %d size: %d <> %d", sector, n, SectorSize)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Save floppy content failed:", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,3 +2,5 @@ logFile: "okemu.log"
|
|||||||
logLevel: "info"
|
logLevel: "info"
|
||||||
monitorFile: "rom/MON_r8_9c6c6546.bin"
|
monitorFile: "rom/MON_r8_9c6c6546.bin"
|
||||||
cpmFile: "rom/CPM_r8_bc0695e4.bin"
|
cpmFile: "rom/CPM_r8_bc0695e4.bin"
|
||||||
|
floppyB: "floppy/floppyB.okd"
|
||||||
|
floppyC: "floppy/floppyC.okd"
|
||||||
@ -155,7 +155,7 @@ func (z *Z80) updateXY(result byte) {
|
|||||||
z.xf = result&0x08 != 0
|
z.xf = result&0x08 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Z80) debugOutput() {
|
func (z *Z80) DebugOutput() {
|
||||||
log.Debugf("PC: %04X, AF: %04X, BC: %04X, DE: %04X, HL: %04X, SP: %04X, IX: %04X, IY: %04X, I: %02X, R: %02X",
|
log.Debugf("PC: %04X, AF: %04X, BC: %04X, DE: %04X, HL: %04X, SP: %04X, IX: %04X, IY: %04X, I: %02X, R: %02X",
|
||||||
z.pc, (uint16(z.a)<<8)|uint16(z.get_f()), z.get_bc(), z.get_de(), z.get_hl(), z.sp,
|
z.pc, (uint16(z.a)<<8)|uint16(z.get_f()), z.get_bc(), z.get_de(), z.get_hl(), z.sp,
|
||||||
z.ix, z.iy, z.i, z.r)
|
z.ix, z.iy, z.i, z.r)
|
||||||
@ -163,3 +163,7 @@ func (z *Z80) debugOutput() {
|
|||||||
log.Debugf("\t(%02X %02X %02X %02X), cyc: %d\n", z.rb(z.pc), z.rb(z.pc+1),
|
log.Debugf("\t(%02X %02X %02X %02X), cyc: %d\n", z.rb(z.pc), z.rb(z.pc+1),
|
||||||
z.rb(z.pc+2), z.rb(z.pc+3), z.cyc)
|
z.rb(z.pc+2), z.rb(z.pc+3), z.cyc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (z *Z80) Reset() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -22,6 +22,8 @@ type CPUInterface interface {
|
|||||||
GetState() *Z80CPU
|
GetState() *Z80CPU
|
||||||
// SetState Set current CPU state
|
// SetState Set current CPU state
|
||||||
SetState(state *Z80CPU)
|
SetState(state *Z80CPU)
|
||||||
|
// DebugOutput out current CPU state
|
||||||
|
DebugOutput()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlagsType - Processor flags
|
// FlagsType - Processor flags
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user