Tridora-CPU/tridoraemu/tridoraemu.go
2024-09-19 14:12:22 +02:00

159 lines
3.3 KiB
Go

// Copyright 2021-2024 Sebastian Lederer. See the file LICENSE.md for details
package main
import (
"fmt"
"log"
"errors"
"flag"
"time"
"github.com/hajimehoshi/ebiten/v2"
// "github.com/hajimehoshi/ebiten/v2/ebitenutil"
// "image/color"
)
const IdleTicks = 1000
var consoleChan chan byte
var cpu CPU
var mem Mem
var uart UART
var framebuffer Framebuffer
var sdspi SDSPI
var irqc IRQC
var Terminated = errors.New("terminated")
var idleCounter int = IdleTicks
func idle(canGoIdle bool) {
if canGoIdle {
if idleCounter > 0 { idleCounter -= 1 }
} else {
if idleCounter != IdleTicks { idleCounter = IdleTicks }
}
}
type Game struct{
x,y int
stepsPerFrame int
lastFrameDuration time.Duration
}
func (g *Game) Update() error {
startTime := time.Now()
for i := 0; i < g.stepsPerFrame; i++ {
err := cpu.step()
if err != nil {
log.Printf("Stopped by error at PC %08X",cpu.PC)
log.Print(err)
return Terminated
}
if cpu.stopped { return Terminated }
if idleCounter == 0 { break }
}
g.lastFrameDuration = time.Since(startTime)
return nil
}
func (g *Game) Draw(screen *ebiten.Image) {
screen.DrawImage(framebuffer.framebuffer, nil)
/*
buf := fmt.Sprintf("PC: %08X FP: %08X RP: %08X ESP: %2X\n%v", cpu.PC, cpu.FP, cpu.RP, cpu.ESP, g.lastFrameDuration)
ebitenutil.DebugPrint(screen, buf)
screen.Set(g.x, g.y, color.RGBA{255,0,0,0})
screen.Set(g.x, g.y+1, color.RGBA{0,255,0,0})
screen.Set(g.x, g.y+2, color.RGBA{0,255,255,0})
screen.Set(g.x, g.y+3, color.RGBA{255,255,255,0})
g.x += 1
if g.x > 319 { g.x = 0 }
*/
// if idleCounter == 0 { ebitenutil.DebugPrint(screen, "idle") }
}
func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
return 640, 400
}
func main() {
var codefile string = ""
addrPtr := flag.Int("a",0,"starting address")
tracePtr := flag.Bool("t",false,"trace")
cardImgPtr := flag.String("i", "sdcard.img", "SD card image file")
flag.Parse()
if len(flag.Args()) > 0 {
codefile = flag.Args()[0]
} else {
codefile = "rommon.prog"
}
log.SetFlags(0)
oldState, err := SetRawConsole()
if err != nil {
panic(err)
}
defer RestoreConsole(oldState)
cpu.initialize()
mem.initialize(4096 * 1024 / 4)
uart.cpu = &cpu
mem.attachIO(&uart, 0)
err = sdspi.openImage(*cardImgPtr)
if err != nil {
panic(err)
}
defer sdspi.closeImage()
//sdspi.debug = true
mem.attachIO(&sdspi, 1)
framebuffer.initialize()
mem.attachIO(&framebuffer, 2)
irqc.initialize()
mem.attachIO(&irqc, 3)
cpu.mem = &mem
cpu.PC = word(*addrPtr)
if codefile != "" {
mem.loadFromFile(codefile, *addrPtr)
}
consoleChan = make(chan byte)
uart.consoleChan = make(chan byte)
ebiten.SetWindowSize(800, 600)
ebiten.SetWindowTitle("Tridora Framebuffer")
g := Game{}
cpu.trace = *tracePtr
g.stepsPerFrame = 166666
// g.stepsPerFrame = 1
go func(ch chan byte) {
for {
buf := make([] byte,1);
n, err := ConsoleRead(buf)
if err != nil {
fmt.Println("read error on stdin, closing channel")
close(ch)
return
}
if n > 0 {ch <- buf[0] }
}
}(uart.consoleChan)
if err := ebiten.RunGame(&g); err != Terminated && err != nil {
log.Panic(err)
}
}