Ocean-240.2-Emulator/okean240/computer.go
2026-03-06 22:31:52 +03:00

263 lines
4.9 KiB
Go

package okean240
import (
_ "embed"
"encoding/binary"
"image/color"
"okemu/config"
"okemu/okean240/fdc"
"okemu/okean240/pic"
"okemu/okean240/pit"
"okemu/okean240/usart"
"okemu/z80em"
"os"
"fyne.io/fyne/v2"
log "github.com/sirupsen/logrus"
)
type ComputerType struct {
cpu *z80em.Z80Type
memory Memory
ioPorts [256]byte
cycles uint64
dd17EnableOut bool
colorMode bool
screenWidth int
screenHeight int
vRAM *RamBlock
palette byte
bgColor byte
pit *pit.I8253
usart *usart.I8251
pic *pic.I8259
fdc *fdc.FloppyDriveController
kbdBuffer []byte
vShift byte
hShift byte
}
const VRAMBlock0 = 3
const VRAMBlock1 = 7
const VidVsuBit = 0x80
const VidColorBit = 0x40
type ComputerInterface interface {
Run()
Reset()
GetPixel(x uint16, y uint16) color.RGBA
Do() uint64
TimerClk()
PutKey(key *fyne.KeyEvent)
PutRune(key rune)
PutCtrlKey(shortcut fyne.Shortcut)
SaveFloppy()
LoadFloppy()
Dump(start uint16, length uint16)
}
func (c *ComputerType) M1MemRead(addr uint16) byte {
return c.memory.M1MemRead(addr)
}
func (c *ComputerType) MemRead(addr uint16) byte {
return c.memory.MemRead(addr)
}
func (c *ComputerType) MemWrite(addr uint16, val byte) {
c.memory.MemWrite(addr, val)
}
// New Builds new computer
func New(cfg *config.OkEmuConfig) *ComputerType {
c := ComputerType{}
c.memory = Memory{}
c.memory.Init(cfg.MonitorFile, cfg.CPMFile)
c.cpu = z80em.New(&c)
c.cycles = 0
c.dd17EnableOut = false
c.screenWidth = 512
c.screenHeight = 256
c.vRAM = c.memory.allMemory[3]
c.palette = 0
c.bgColor = 0
c.vShift = 0
c.hShift = 0
c.pit = pit.New()
c.usart = usart.New()
c.pic = pic.New()
c.fdc = fdc.New()
return &c
}
func (c *ComputerType) Reset(cfg *config.OkEmuConfig) {
c.cpu.Reset()
c.cycles = 0
c.vShift = 0
c.hShift = 0
c.memory = Memory{}
c.memory.Init(cfg.MonitorFile, cfg.CPMFile)
c.cycles = 0
c.dd17EnableOut = false
c.screenWidth = 512
c.screenHeight = 256
c.vRAM = c.memory.allMemory[3]
}
func (c *ComputerType) Do() int {
//s := c.cpu.GetState()
//if s.PC == 0xe0db {
// log.Debugf("breakpoint")
//}
ticks := uint64(c.cpu.RunInstruction())
c.cycles += ticks
if c.cpu.PC == 0xFF26 {
log.Debugf("%4X: H:%X L:%X A:%X B: %X C: %X D: %X E: %X", c.cpu.PC, c.cpu.H, c.cpu.L, c.cpu.A, c.cpu.B, c.cpu.C, c.cpu.D, c.cpu.E)
}
return int(ticks)
}
func (c *ComputerType) GetPixel(x uint16, y uint16) color.RGBA {
if y > 255 {
return CWhite
}
var addr uint16
var resColor color.RGBA
if c.colorMode {
if x > 255 {
return CWhite
}
y += uint16(c.vShift) & 0x00ff
x += uint16(c.hShift-7) & 0x00ff
// Color 256x256 mode
addr = ((x & 0xf8) << 6) | y
//if c.vShift != 0 {
// addr -= 8
//}
cl := (c.vRAM.memory[addr&0x3fff] >> (x & 0x07)) & 1
cl |= ((c.vRAM.memory[(addr+0x100)&0x3fff] >> (x & 0x07)) & 1) << 1
if cl == 0 {
resColor = BgColorPalette[c.bgColor]
} else {
resColor = ColorPalette[c.palette][cl]
}
} else {
if x > 511 {
return CWhite
}
// Shifts
y += uint16(c.vShift) & 0x00ff
x += uint16(c.hShift-7) & 0x001ff
// Mono 512x256 mode
addr = ((x & 0x1f8) << 5) | y
pix := c.vRAM.memory[addr] >> (x & 0x07) & 1
if c.palette == 6 {
if pix == 0 {
resColor = CBlack
} else {
resColor = CLGreen
}
} else {
if pix == 0 {
resColor = BgColorPalette[c.bgColor]
} else {
resColor = MonoPalette[c.bgColor]
}
}
}
return resColor
}
func (c *ComputerType) ScreenWidth() int {
return c.screenWidth
}
func (c *ComputerType) ScreenHeight() int {
return c.screenHeight
}
func (c *ComputerType) Cycles() uint64 {
return c.cycles
}
func (c *ComputerType) TimerClk() {
// DD70 KR580VI53 CLK0, CKL1 @ 1.5MHz
c.pit.Tick(0)
c.pit.Tick(1)
// IRQ from timer
if c.pit.Fired(0) {
c.pic.SetIRQ(RstTimerNo)
//c.ioPorts[PIC_DD75RS] |= Rst4Mask
}
// clock for SIO KR580VV51
if c.pit.Fired(1) {
c.usart.Tick()
}
}
func (c *ComputerType) LoadFloppy() {
c.fdc.LoadFloppy()
}
func (c *ComputerType) SaveFloppy() {
c.fdc.SaveFloppy()
}
func (c *ComputerType) SetSerialBytes(bytes []byte) {
c.usart.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)
}
}