fdc mostly fixed

This commit is contained in:
Роман Бойков 2026-03-06 13:16:38 +03:00
parent 42fb80813c
commit b133807f05
10 changed files with 490 additions and 155 deletions

53
main.go
View File

@ -1,6 +1,7 @@
package main package main
import ( import (
_ "embed"
"fmt" "fmt"
"image/color" "image/color"
"okemu/config" "okemu/config"
@ -19,6 +20,14 @@ import (
var Version = "v1.0.0" var Version = "v1.0.0"
var BuildTime = "2026-03-01" var BuildTime = "2026-03-01"
//go:embed hex/format.hex
var serialBytes []byte
//go:embed bin/TYPE.COM
var ramBytes []byte
var needReset = false
func main() { func main() {
fmt.Printf("Starting Ocean-240.2 emulator %s build at %s\n", Version, BuildTime) fmt.Printf("Starting Ocean-240.2 emulator %s build at %s\n", Version, BuildTime)
@ -32,9 +41,19 @@ func main() {
conf := config.GetConfig() conf := config.GetConfig()
// Reconfigure logging by config values // Reconfigure logging by config values
//logger.ReconfigureLogging(conf) // logger.ReconfigureLogging(conf)
computer := okean240.New(conf)
computer := okean240.New(conf)
computer.SetSerialBytes(serialBytes)
w, raster, label := mainWindow(computer, conf)
go emulator(computer, raster, label, conf)
(*w).ShowAndRun()
}
func mainWindow(computer *okean240.ComputerType, emuConfig *config.OkEmuConfig) (*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(
@ -42,6 +61,11 @@ func main() {
computer.PutKey(key) computer.PutKey(key)
}) })
w.Canvas().SetOnTypedRune(
func(key rune) {
computer.PutRune(key)
})
addShortcuts(w.Canvas(), computer) addShortcuts(w.Canvas(), computer)
label := widget.NewLabel(fmt.Sprintf("Screen size: %dx%d", computer.ScreenWidth(), computer.ScreenHeight())) label := widget.NewLabel(fmt.Sprintf("Screen size: %dx%d", computer.ScreenWidth(), computer.ScreenHeight()))
@ -61,9 +85,22 @@ func main() {
widget.NewButton("Ctrl+C", func() { widget.NewButton("Ctrl+C", func() {
computer.PutCtrlKey(0x03) computer.PutCtrlKey(0x03)
}), }),
widget.NewButton("Load Floppy", func() {
computer.LoadFloppy()
}),
widget.NewButton("Save Floppy", func() {
computer.SaveFloppy()
}),
widget.NewButton("RUN", func() {
computer.SetRamBytes(ramBytes)
}),
widget.NewButton("DUMP", func() {
computer.Dump(0x399, 15000)
}),
widget.NewSeparator(), widget.NewSeparator(),
widget.NewButton("Reset", func() { widget.NewButton("Reset", func() {
computer.Reset() needReset = true
//computer.Reset(conf)
}), }),
widget.NewSeparator(), widget.NewSeparator(),
widget.NewButton("Закрыть", func() { widget.NewButton("Закрыть", func() {
@ -78,12 +115,10 @@ func main() {
w.SetContent(vBox) w.SetContent(vBox)
go emulator(computer, raster, label) return &w, raster, label
w.ShowAndRun()
} }
func emulator(computer *okean240.ComputerType, raster *canvas.Raster, label *widget.Label) { func emulator(computer *okean240.ComputerType, raster *canvas.Raster, label *widget.Label, emuConfig *config.OkEmuConfig) {
ticker := time.NewTicker(133 * time.Nanosecond) ticker := time.NewTicker(133 * time.Nanosecond)
var ticks = 0 var ticks = 0
var ticksCPU = 3 var ticksCPU = 3
@ -97,6 +132,10 @@ func emulator(computer *okean240.ComputerType, raster *canvas.Raster, label *wid
nextSecond := time.Now().Add(time.Second).UnixMicro() nextSecond := time.Now().Add(time.Second).UnixMicro()
curScrWidth := 256 curScrWidth := 256
for range ticker.C { for range ticker.C {
if needReset {
computer.Reset(emuConfig)
needReset = false
}
ticks++ ticks++
if ticks%5 == 0 { if ticks%5 == 0 {
// 1.5 MHz // 1.5 MHz

View File

@ -1,12 +1,16 @@
package okean240 package okean240
import ( import (
_ "embed"
"encoding/binary"
"image/color" "image/color"
"okemu/config" "okemu/config"
fdc2 "okemu/okean240/fdc" fdc2 "okemu/okean240/fdc"
"okemu/okean240/pic"
"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"
@ -26,6 +30,7 @@ type ComputerType struct {
bgColor byte bgColor byte
dd70 *pit.I8253 dd70 *pit.I8253
dd72 *usart.I8251 dd72 *usart.I8251
dd75 *pic.I8259
fdc *fdc2.FloppyDriveController fdc *fdc2.FloppyDriveController
kbdBuffer []byte kbdBuffer []byte
vShift byte vShift byte
@ -45,7 +50,11 @@ type ComputerInterface interface {
Do() uint64 Do() uint64
TimerClk() TimerClk()
PutKey(key *fyne.KeyEvent) PutKey(key *fyne.KeyEvent)
PutRune(key rune)
PutCtrlKey(shortcut fyne.Shortcut) PutCtrlKey(shortcut fyne.Shortcut)
SaveFloppy()
LoadFloppy()
Dump(start uint16, length uint16)
} }
func (c *ComputerType) M1MemRead(addr uint16) byte { func (c *ComputerType) M1MemRead(addr uint16) byte {
@ -81,25 +90,39 @@ func New(cfg *config.OkEmuConfig) *ComputerType {
c.dd70 = pit.NewI8253() c.dd70 = pit.NewI8253()
c.dd72 = usart.NewI8251() c.dd72 = usart.NewI8251()
c.dd75 = pic.NewI8259()
c.fdc = fdc2.NewFDCType() c.fdc = fdc2.NewFDCType()
return &c return &c
} }
func (c *ComputerType) Reset() { func (c *ComputerType) Reset(cfg *config.OkEmuConfig) {
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.Init(cfg.MonitorFile, cfg.CPMFile)
c.cycles = 0
c.dd17EnableOut = false
c.screenWidth = 512
c.screenHeight = 256
c.vRAM = c.memory.allMemory[3]
} }
func (c *ComputerType) Do() int { func (c *ComputerType) Do() int {
s := c.cpu.GetState() //s := c.cpu.GetState()
if s.PC == 0xe0db { //if s.PC == 0xe0db {
log.Debugf("breakpoint") // log.Debugf("breakpoint")
} //}
ticks := uint64(c.cpu.RunInstruction()) ticks := uint64(c.cpu.RunInstruction())
c.cycles += ticks c.cycles += ticks
//if c.cpu.PC == 0x2C2 {
// log.Debugf("%4X: H:%X L:%X", c.cpu.PC, c.cpu.H, c.cpu.L)
//}
return int(ticks) return int(ticks)
} }
@ -115,15 +138,17 @@ func (c *ComputerType) GetPixel(x uint16, y uint16) color.RGBA {
if x > 255 { if x > 255 {
return CWhite return CWhite
} }
y += uint16(c.vShift)
x += uint16(c.hShift) y += uint16(c.vShift) & 0x00ff
x += uint16(c.hShift) & 0x00ff
// Color 256x256 mode // Color 256x256 mode
addr = ((x & 0xf8) << 6) | (y & 0xff) addr = ((x & 0xf8) << 6) | (y & 0xff)
if c.vShift != 0 { if c.vShift != 0 {
addr -= 8 addr -= 8
} }
var cl byte = (c.vRAM.memory[addr&0x3fff] >> (x & 0x07)) & 1 cl := (c.vRAM.memory[addr&0x3fff] >> (x & 0x07)) & 1
cl |= (c.vRAM.memory[(addr+0x100)&0x3fff] >> (x & 0x07)) & 1 << 1 cl |= (c.vRAM.memory[(addr+0x100)&0x3fff] >> (x & 0x07)) & 1 << 1
if cl == 0 { if cl == 0 {
resColor = BgColorPalette[c.bgColor] resColor = BgColorPalette[c.bgColor]
@ -174,10 +199,61 @@ func (c *ComputerType) TimerClk() {
// IRQ from timer // IRQ from timer
if c.dd70.Fired(0) { if c.dd70.Fired(0) {
c.ioPorts[PIC_DD75RS] |= Rst4TmrFlag c.dd75.SetIRQ(RstTimerNo)
//c.ioPorts[PIC_DD75RS] |= Rst4Mask
} }
// clock for SIO KR580VV51 // clock for SIO KR580VV51
if c.dd70.Fired(1) { if c.dd70.Fired(1) {
c.dd72.Tick() c.dd72.Tick()
} }
} }
func (c *ComputerType) LoadFloppy() {
c.fdc.LoadFloppy()
}
func (c *ComputerType) SaveFloppy() {
c.fdc.SaveFloppy()
}
func (c *ComputerType) SetSerialBytes(bytes []byte) {
c.dd72.SetRxBytes(bytes)
}
func (c *ComputerType) SetRamBytes(bytes []byte) {
addr := 0x100
for i := 0; i < len(bytes); i++ {
c.memory.MemWrite(uint16(addr), bytes[i])
addr++
}
pages := len(bytes) / 256
if len(bytes)%256 != 0 {
pages++
}
log.Debugf("Loaded bytes: %d; blocks: %d", len(bytes), pages)
//c.cpu.SP = 0x100
//c.cpu.PC = 0x100
}
func (c *ComputerType) Dump(start uint16, length uint16) {
file, err := os.Create("dump.dat")
if err != nil {
log.Error(err)
return
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
log.Error(err)
}
}(file)
var buffer []byte
for addr := 0; addr < 65535; addr++ {
buffer = append(buffer, c.memory.MemRead(uint16(addr)))
}
err = binary.Write(file, binary.LittleEndian, buffer)
if err != nil {
log.Error("Save memory dump failed:", err)
}
}

View File

@ -89,20 +89,23 @@ const TMR_DD70CTR = 0x63
* Programmable Interrupt controller PIC KR580VV59 * Programmable Interrupt controller PIC KR580VV59
*/ */
// PIC_DD75RS RS Port const RstKbdNo = 1
const PIC_DD75RS = 0x80 const RstTimerNo = 4
const Rst0SysFlag = 0x01 // System interrupt const Rst0Mask = 0x01 // System interrupt
const Rst1KbdFlag = 0x02 // Keyboard interrupt const Rst1Mask = 0x02 // Keyboard interrupt
const Rst2SerFlag = 0x04 // Serial interface interrupt const Rst2Mask = 0x04 // Serial interface interrupt
const RstЗLptFlag = 0x08 // Printer ready const RstЗMask = 0x08 // Printer ready
const Rst4TmrFlag = 0x10 // System timer const Rst4Mask = 0x10
const Rst5PwrFlag = 0x20 // Power intRq const Rst5Mask = 0x20 // Power intRq
const Rst6UsrFlag = 0x40 // User device 1 interrupt const Rst6Mask = 0x40 // User device 1 interrupt
const Rst7UsrFlag = 0x80 // User device 1 interrupt const Rst7Mask = 0x80 // User device 1 interrupt
// PIC_DD75RM RM Port // PIC_DD75A Port A (a0=0)
const PIC_DD75RM = 0x81 const PIC_DD75A = 0x80
// PIC_DD75B Port B (a0=1)
const PIC_DD75B = 0x81
/* /*
* КР580ВВ51 DD72 * КР580ВВ51 DD72

View File

@ -1,48 +1,82 @@
package fdc package fdc
/** /**
Floppy drive controller, based on * Floppy drive controller, based on
MB8877, К1818ВГ93 * MB8877, К1818ВГ93
*
By Romych, 2025.03.05 * By Romych, 2025.03.05
*/ */
import ( import (
"encoding/binary"
"os"
"slices"
"strconv"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
const FloppySizeK = 360 // Floppy parameters
const (
FloppySizeK = 720
SectorSize = 128
SideCount = 2
SectorPerTrack = 36
const SectorSize = 128 SizeInSectors = FloppySizeK * 1024 / SectorSize
const SideCount = 2 TracksCount = SizeInSectors / SideCount / SectorPerTrack
const SectorPerTrack = 36 SectorsPerSide = SizeInSectors / SideCount
const SizeInSectors = FloppySizeK * 1024 / SectorSize TrackHeaderSize = 146
const TracksCount = SizeInSectors / SideCount / SectorPerTrack TrackSectorSize = 626
const SectorsPerSide = SizeInSectors / SideCount TrackFooterSize = 256 * 3
TrackBufferSize = TrackHeaderSize + TrackSectorSize*9 + TrackFooterSize
)
// FDC Commands
const (
CmdRestore byte = 0x0
CmdSeek byte = 0x1
CmdStep byte = 0x2
CmdStepIn byte = 0x5
CmdStepOut byte = 0x7
CmdReadSector byte = 0x8
CmdReadSectorMulti byte = 0x9
CmdWriteSector byte = 0xa
CmdWriteTrack byte = 0xf
CmdNoCommand byte = 0xff
)
const (
StatusTR0 = 0x04 // TR0 - Head at track 0
StatusRNF = 0x10 // RNF - Record not found
StatusSeekError = 0x10 // Sector out of disk
StatusHeadLoaded = 0x20 // Head on disk
)
type SectorType []byte type SectorType []byte
type FloppyDriveController struct { type FloppyDriveController struct {
// Floppy controller port // Floppy controller port
sideSel byte sideNo byte
ddEn byte ddEn byte
init byte init byte
drSel byte drive byte
mot1 byte mot1 byte
mot0 byte mot0 byte
intRq byte intRq byte
motSt byte motSt byte
sector byte sectorNo byte
track byte trackNo byte
drq byte drq byte
// FloppyStorage // FloppyStorage
sectors [SizeInSectors]SectorType sectors [SizeInSectors]SectorType
data byte data byte
status byte status byte
lastCmd byte lastCmd byte
curSector *SectorType //curSector *SectorType
bytePtr uint16 bytePtr uint16
trackBuffer []byte
} }
type FloppyDriveControllerInterface interface { type FloppyDriveControllerInterface interface {
@ -55,59 +89,96 @@ type FloppyDriveControllerInterface interface {
SetData(value byte) SetData(value byte)
Data() byte Data() byte
Drq() byte Drq() byte
SaveFloppy()
GetSectorNo() uint16
Track() byte
Sector() byte
}
func (f *FloppyDriveController) GetSectorNo() uint16 {
return uint16(f.sideNo)*SectorsPerSide + uint16(f.trackNo)*SectorPerTrack + uint16(f.sectorNo) - 1
} }
func (f *FloppyDriveController) SetFloppy(val byte) { func (f *FloppyDriveController) SetFloppy(val byte) {
// WR: 5-SSEN, 4-#DDEN, 3-INIT, 2-DRSEL, 1-MOT1, 0-MOT0 // WR: 5-SSEL, 4-#DDEN, 3-INIT, 2-DRSEL, 1-MOT1, 0-MOT0
f.sideSel = 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.drSel = 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.drSel << 3) | (f.sideSel << 6) | (f.motSt << 7) floppy := f.intRq | (f.mot0 << 1) | (f.mot1 << 2) | (f.drive << 3) | (f.sideNo << 6) | (f.motSt << 7)
return floppy return floppy
} }
const (
FdcCmdRestore byte = 0
FdcCmdSeek byte = 1
FdcCmdStep byte = 2
FdcCmdReadSector byte = 8
)
func (f *FloppyDriveController) SetCmd(value byte) { func (f *FloppyDriveController) SetCmd(value byte) {
//log.Debugf("FCD CMD: %x", value)
f.lastCmd = value >> 4 f.lastCmd = value >> 4
switch f.lastCmd { switch f.lastCmd {
case FdcCmdRestore: case CmdRestore:
log.Debug("CMD Restore (seek track 0)") log.Debug("CMD Restore (seek trackNo 0)")
f.status = 0x24 // TR0 & Head loaded f.trackNo = 0
f.track = 0 f.status = StatusTR0 | StatusHeadLoaded // TR0 & Head loaded
case FdcCmdSeek: case CmdSeek:
log.Debugf("CMD Seek %x", value&0xf) log.Debugf("CMD Seek %x", value&0xf)
f.status = 0x04 // Head loaded f.status = StatusHeadLoaded
f.track = f.data f.trackNo = f.data
case FdcCmdStep: case CmdStep:
log.Debugf("CMD Step %x", value&0xf) log.Debugf("CMD Step %x", value&0xf)
f.status = 0x04 // Head loaded f.status = StatusHeadLoaded
f.track = f.data f.trackNo = f.data
case FdcCmdReadSector: case CmdStepIn:
f.status = 0x04 log.Debugf("CMD StepIn (Next track) %x", value&0xf)
sectorNo := uint16(f.sideSel)*SectorsPerSide + uint16(f.track)*SectorPerTrack + uint16(f.sector) f.status = StatusHeadLoaded
log.Debugf("CMD Read single sector: %d", sectorNo) if f.trackNo < TracksCount {
if sectorNo >= SizeInSectors { f.trackNo++
f.status = 0x10 // RNF - Record not found }
} else { case CmdStepOut:
f.curSector = &f.sectors[sectorNo] log.Debugf("CMD StepOut (Previous track) %x", value&0xf)
f.bytePtr = 0 f.status = StatusHeadLoaded
if f.trackNo > 0 {
f.trackNo--
}
case CmdReadSector:
sectorNo := f.GetSectorNo()
log.Debugf("CMD Read single sectorNo: %d", sectorNo)
if sectorNo < SizeInSectors {
f.trackBuffer = slices.Clone(f.sectors[sectorNo])
f.drq = 1 f.drq = 1
f.status = 0x00 f.status = 0x00
} else {
f.drq = 0
f.status = StatusRNF
} }
case CmdReadSectorMulti:
sectorNo := f.GetSectorNo()
f.trackBuffer = []byte{}
for c := 0; c < SectorPerTrack; c++ {
f.trackBuffer = slices.Concat(f.trackBuffer, f.sectors[sectorNo])
sectorNo++
}
f.drq = 1
f.status = 0x0
case CmdWriteSector:
sectorNo := f.GetSectorNo()
log.Debugf("CMD Write Sector %d", sectorNo)
if sectorNo < SizeInSectors {
f.bytePtr = 0
f.drq = 1
f.status = 0x0
f.trackBuffer = []byte{}
} else {
f.drq = 0
f.status = StatusRNF
}
case CmdWriteTrack:
log.Debugf("CMD Write Track %x", f.trackNo)
f.status = 0x00
f.trackBuffer = []byte{}
f.drq = 1
default: default:
log.Debugf("Unknown CMD: %x VAL: %x", f.lastCmd, value&0xf) log.Debugf("Unknown CMD: %x VAL: %x", f.lastCmd, value&0xf)
} }
@ -117,31 +188,72 @@ func (f *FloppyDriveController) Status() byte {
return f.status return f.status
} }
func (f *FloppyDriveController) SetTrack(value byte) { func (f *FloppyDriveController) SetTrackNo(value byte) {
log.Debugf("FCD Track: %d", value) //log.Debugf("FDC Track: %d", value)
f.track = value if value > TracksCount {
f.status |= 0x10 /// RNF
log.Error("Track not found!")
} else {
f.trackNo = value
}
} }
func (f *FloppyDriveController) SetSector(value byte) { func (f *FloppyDriveController) SetSectorNo(value byte) {
log.Debugf("FCD Sector: %d", value) //log.Debugf("FDC Sector: %d", value)
f.sector = value if value > SectorPerTrack {
f.status |= 0x10
log.Error("Record not found!")
} else {
f.sectorNo = value
}
} }
func (f *FloppyDriveController) SetData(value byte) { func (f *FloppyDriveController) SetData(value byte) {
log.Debugf("FCD Data: %d", value) //log.Debugf("FCD Data: %d", value)
if f.lastCmd == CmdWriteTrack {
if len(f.trackBuffer) < TrackBufferSize {
f.trackBuffer = append(f.trackBuffer, value)
f.drq = 1
f.status = 0x00
} else {
//f.dump()
f.drq = 0
f.status = 0x00
f.lastCmd = CmdNoCommand
}
} else if f.lastCmd == CmdWriteSector {
if len(f.trackBuffer) < SectorSize {
f.trackBuffer = append(f.trackBuffer, value)
if len(f.trackBuffer) == SectorSize {
f.drq = 0
} else {
f.drq = 1
}
}
if len(f.trackBuffer) == SectorSize {
f.drq = 0
f.sectors[f.GetSectorNo()] = slices.Clone(f.trackBuffer)
f.lastCmd = CmdNoCommand
}
}
f.data = value f.data = value
} }
func (f *FloppyDriveController) Data() byte { func (f *FloppyDriveController) Data() byte {
if f.lastCmd == FdcCmdReadSector { switch f.lastCmd {
if f.bytePtr < SectorSize { case CmdReadSector, CmdReadSectorMulti:
if len(f.trackBuffer) > 0 {
f.drq = 1 f.drq = 1
f.data = (*f.curSector)[f.bytePtr] f.data = f.trackBuffer[0]
f.bytePtr++ f.trackBuffer = f.trackBuffer[1:]
} else { }
if len(f.trackBuffer) == 0 {
f.drq = 0 f.drq = 0
f.status = 0 f.status = 0
f.lastCmd = CmdNoCommand
} }
default:
f.data = 0xff
} }
return f.data return f.data
} }
@ -150,19 +262,78 @@ func (f *FloppyDriveController) Drq() byte {
return f.drq return f.drq
} }
func (f *FloppyDriveController) LoadFloppy() {
log.Debug("Load Floppy content.")
file, err := os.Open("floppy.okd")
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(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() {
log.Debug("Save Floppy content.")
file, err := os.Create("floppy.okd")
if err != nil {
log.Error(err)
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 NewFDCType() *FloppyDriveController { func NewFDCType() *FloppyDriveController {
sec := [SizeInSectors]SectorType{} sec := [SizeInSectors]SectorType{}
for i := 0; i < int(SizeInSectors); i++ { for i := 0; i < SizeInSectors; i++ {
sec[i] = make([]byte, SectorSize) sec[i] = make([]byte, SectorSize)
for s := 0; s < 128; s++ { for s := 0; s < 128; s++ {
sec[i][s] = 0 sec[i][s] = 0xE5
} }
} }
return &FloppyDriveController{ return &FloppyDriveController{
sideSel: 0, sideNo: 0,
ddEn: 0, ddEn: 0,
init: 0, init: 0,
drSel: 0, drive: 0,
mot1: 0, mot1: 0,
mot0: 0, mot0: 0,
intRq: 0, intRq: 0,
@ -174,4 +345,33 @@ func NewFDCType() *FloppyDriveController {
} }
} }
func (f *FloppyDriveController) dump() {
log.Debug("Dump Buffer content.")
file, err := os.Create("track-" + strconv.Itoa(int(f.trackNo)) + ".dat")
if err != nil {
log.Error(err)
return
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
log.Error(err)
}
}(file)
err = binary.Write(file, binary.LittleEndian, f.trackBuffer)
if err != nil {
log.Error("Save track content failed:", err)
}
}
func (f *FloppyDriveController) Track() byte {
return f.trackNo
}
func (f *FloppyDriveController) Sector() byte {
return f.sectorNo
}
// //

View File

@ -12,16 +12,14 @@ 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_DD75RS: case PIC_DD75A:
// PIO VN59 // PIO xx59, get IRR register
v := c.ioPorts[PIC_DD75RS] return c.dd75.IRR()
c.ioPorts[PIC_DD75RS] = 0
return v
case UART_DD72RR: case UART_DD72RR:
// SIO VV51 CMD // USART VV51 CMD
return c.dd72.Status() return c.dd72.Status()
case UART_DD72RD: case UART_DD72RD:
// SIO VV51 Data // USART VV51 Data
return c.dd72.Receive() return c.dd72.Receive()
case KBD_DD78PA: case KBD_DD78PA:
// Keyboard data // Keyboard data
@ -36,6 +34,10 @@ func (c *ComputerType) IORead(port uint16) byte {
return c.fdc.GetFloppy() return c.fdc.GetFloppy()
case FDC_DATA: case FDC_DATA:
return c.fdc.Data() return c.fdc.Data()
case FDC_TRACK:
return c.fdc.Track()
case FDC_SECT:
return c.fdc.Sector()
default: default:
log.Debugf("IORead from port: %x", port) log.Debugf("IORead from port: %x", port)
@ -89,23 +91,22 @@ func (c *ComputerType) IOWrite(port uint16, val byte) {
c.dd70.Load(2, val) c.dd70.Load(2, val)
case UART_DD72RR: case UART_DD72RR:
// SIO VV51 CMD // USART VV51 CMD
c.dd72.Command(val) c.dd72.Command(val)
case UART_DD72RD: case UART_DD72RD:
// SIO VV51 Data // USART VV51 Data
c.dd72.Send(val) c.dd72.Send(val)
case FDC_CMD: case FDC_CMD:
c.fdc.SetCmd(val) c.fdc.SetCmd(val)
case FDC_DATA: case FDC_DATA:
c.fdc.SetData(val) c.fdc.SetData(val)
case FDC_TRACK: case FDC_TRACK:
c.fdc.SetTrack(val) c.fdc.SetTrackNo(val)
case FDC_SECT: case FDC_SECT:
c.fdc.SetSector(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)
} }
} }

View File

@ -2,49 +2,25 @@ package okean240
import ( import (
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
log "github.com/sirupsen/logrus"
) )
func (c *ComputerType) PutKey(key *fyne.KeyEvent) { func (c *ComputerType) PutKey(key *fyne.KeyEvent) {
if key.Name == fyne.KeyUnknown { code := RemapCmdKey[key.Name]
log.Debugf("Unknown key scancode: %X", key.Physical.ScanCode) if code > 0 {
return //log.Debugf("PutKey keyName: %s", key.Name)
c.ioPorts[KBD_DD78PA] = code
c.dd75.SetIRQ(RstKbdNo)
} }
log.Debugf("PutKey keyName: %s", key.Name) }
if len(c.kbdBuffer) < KbdBufferSize { func (c *ComputerType) PutRune(key rune) {
var code byte //log.Debugf("Put Rune: %c Lo: %x, Hi: %x", key, key&0xff, key>>8)
if (c.ioPorts[KBD_DD78PB] & 0x40) == 0 {
// No shift
code = RemapKey[key.Name]
} else {
// Shift
code = RemapKeyShift[key.Name]
}
c.ioPorts[KBD_DD78PB] &= 0x1f
if code != 0 {
c.ioPorts[KBD_DD78PA] = code
c.ioPorts[PIC_DD75RS] |= Rst1KbdFlag
} else {
switch key.Name {
case "LeftAlt", "RightAlt":
c.ioPorts[KBD_DD78PB] |= 0x80
case "LeftControl", "RightControl":
c.ioPorts[KBD_DD78PB] |= 0x20
case "LeftShift", "RightShift":
log.Debug("Shift")
c.ioPorts[KBD_DD78PB] |= 0x40
default:
log.Debugf("Unhandled KeyName: %s code: %X", key.Name, key.Physical.ScanCode)
}
}
}
c.ioPorts[KBD_DD78PA] = byte(key & 0xff)
c.dd75.SetIRQ(RstKbdNo)
} }
/* /*
@ -62,6 +38,7 @@ func (c *ComputerType) PutKey(key *fyne.KeyEvent) {
func (c *ComputerType) PutCtrlKey(key byte) { func (c *ComputerType) PutCtrlKey(key byte) {
c.ioPorts[KBD_DD78PA] = key c.ioPorts[KBD_DD78PA] = key
c.ioPorts[PIC_DD75RS] |= Rst1KbdFlag c.dd75.SetIRQ(RstKbdNo)
//c.ioPorts[PIC_DD75RS] |= Rst1Mask
c.ioPorts[KBD_DD78PB] &= 0x1f | 0x20 c.ioPorts[KBD_DD78PB] &= 0x1f | 0x20
} }

View File

@ -38,7 +38,7 @@ var ColorPalette = [8][4]color.RGBA{
// BgColorPalette Background color palette // BgColorPalette Background color palette
var BgColorPalette = [8]color.RGBA{ var BgColorPalette = [8]color.RGBA{
CBlack, CBlue, CGreen, CLBlue, CRed, CCrimson, CYellow, CWhite, CBlack, CBlue, CGreen, CLBlue, CRed, CCrimson /*CYellow*/, CBlack, CWhite,
} }
//var MonoPalette = [8]color.RGBA{ //var MonoPalette = [8]color.RGBA{

View File

@ -2,6 +2,37 @@ package okean240
import "fyne.io/fyne/v2" import "fyne.io/fyne/v2"
var RemapCmdKey = map[fyne.KeyName]byte{
fyne.KeyEscape: 0x1B,
fyne.KeyReturn: 0x0A,
fyne.KeyTab: 0x09,
fyne.KeyBackspace: 0x08,
fyne.KeyInsert: 0x00,
fyne.KeyDelete: 0x08,
fyne.KeyRight: 0x18,
fyne.KeyLeft: 0x08,
fyne.KeyDown: 0x0A,
fyne.KeyUp: 0x19,
fyne.KeyPageUp: 0x00,
fyne.KeyPageDown: 0x00,
fyne.KeyHome: 0x0C,
fyne.KeyEnd: 0x1A,
fyne.KeyF1: 0x00,
fyne.KeyF2: 0x00,
fyne.KeyF3: 0x00,
fyne.KeyF4: 0x00,
fyne.KeyF5: 0x00,
fyne.KeyF6: 0x00,
fyne.KeyF7: 0x00,
fyne.KeyF8: 0x00,
fyne.KeyF9: 0x00,
fyne.KeyF10: 0x00,
fyne.KeyF11: 0x00,
fyne.KeyF12: 0x00,
fyne.KeyEnter: 0x0D,
fyne.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,
@ -162,5 +193,4 @@ var RemapKeyShift = map[fyne.KeyName]byte{
fyne.KeyAsterisk: 0x7E, fyne.KeyAsterisk: 0x7E,
fyne.KeyPlus: 0x7E, fyne.KeyPlus: 0x7E,
fyne.KeyBackTick: 0x60, fyne.KeyBackTick: 0x60,
fyne.KeyUnknown: 0x00,
} }

View File

@ -1,5 +1,7 @@
package usart package usart
import log "github.com/sirupsen/logrus"
/** /**
Universal Serial Asynchronous Receiver/Transmitter Universal Serial Asynchronous Receiver/Transmitter
i8051, MSM82C51, КР580ВВ51 i8051, MSM82C51, КР580ВВ51
@ -133,12 +135,19 @@ func (s *I8251) Send(value byte) {
} }
func (s *I8251) Receive() byte { func (s *I8251) Receive() byte {
if s.rxe { if s.rxe {
if len(s.bufferRx) > 0 { if len(s.bufferRx) > 0 {
res := s.bufferRx[0] res := s.bufferRx[0]
s.bufferRx = s.bufferRx[1:] s.bufferRx = s.bufferRx[1:]
log.Debugf("ReceiveByte: %x", res)
return res return res
} }
} }
log.Debugf("ReceiveByte: empty buffer")
return 0 return 0
} }
func (s *I8251) SetRxBytes(bytes []byte) {
s.bufferRx = append(s.bufferRx, bytes...)
}

View File

@ -1,4 +1,4 @@
logFile: "okemu.log" logFile: "okemu.log"
logLevel: "info" logLevel: "info"
monitorFile: "rom/MON_r6.bin" monitorFile: "rom/MON_r8_9c6c6546.bin"
cpmFile: "rom/CPM_r7.bin" cpmFile: "rom/CPM_r8_bc0695e4.bin"