Skip to content

Commit

Permalink
Add HostContext interface for exposing host elements to the virtual h…
Browse files Browse the repository at this point in the history
…ardware

Not in love with the current interface yet.

probably want to add logging methods rather than expose the logger itself, but i-i-i-i-terationnnnnn
  • Loading branch information
maxfierke committed Jan 18, 2024
1 parent 397d86c commit ba353ef
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 62 deletions.
3 changes: 1 addition & 2 deletions debug/gb_doctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"

"github.com/maxfierke/gogo-gb/cpu"
"github.com/maxfierke/gogo-gb/devices"
"github.com/maxfierke/gogo-gb/mem"
)

Expand All @@ -28,7 +27,7 @@ func (gbd *GBDoctorDebugger) OnExecute(cpu *cpu.CPU, mmu *mem.MMU) {
func (gbd *GBDoctorDebugger) OnInterrupt(cpu *cpu.CPU, mmu *mem.MMU) {}

func (gbd *GBDoctorDebugger) OnRead(mmu *mem.MMU, addr uint16) mem.MemRead {
if addr == devices.REG_LCD_LY {
if addr == 0xFF44 {
return mem.ReadReplace(0x90) // gameboy-doctor needs a stubbed out LCD
}

Expand Down
38 changes: 38 additions & 0 deletions devices/host.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package devices

import (
"log"
)

type HostContext interface {
Logger() *log.Logger
SerialCable() SerialCable
}

type Host struct {
logger *log.Logger
serialCable SerialCable
}

func NewHost() *Host {
return &Host{
logger: log.Default(),
serialCable: &NullSerialCable{},
}
}

func (h *Host) Logger() *log.Logger {
return h.logger
}

func (h *Host) SetLogger(logger *log.Logger) {
h.logger = logger
}

func (h *Host) SerialCable() SerialCable {
return h.serialCable
}

func (h *Host) SetSerialCable(serialCable SerialCable) {
h.serialCable = serialCable
}
56 changes: 56 additions & 0 deletions devices/serial_cable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package devices

import (
"bytes"
"io"
)

type SerialCable interface {
ReadByte() (byte, error)
WriteByte(value byte) error
}

type NullSerialCable struct{}

func (sc *NullSerialCable) ReadByte() (byte, error) {
return 0xFF, nil
}

func (sc *NullSerialCable) WriteByte(value byte) error {
return nil
}

type HostSerialCable struct {
reader io.Reader
writer io.Writer
}

func NewHostSerialCable() *HostSerialCable {
return &HostSerialCable{
reader: bytes.NewReader([]byte{}),
writer: io.Discard,
}
}

func (sc *HostSerialCable) ReadByte() (byte, error) {
readBuf := []byte{0x00}

if _, err := sc.reader.Read(readBuf); err != nil {
return 0xFF, err
}

return readBuf[0], nil
}

func (sc *HostSerialCable) WriteByte(value byte) error {
_, err := sc.writer.Write([]byte{value})
return err
}

func (sc *HostSerialCable) SetReader(reader io.Reader) {
sc.reader = reader
}

func (sc *HostSerialCable) SetWriter(writer io.Writer) {
sc.writer = writer
}
41 changes: 15 additions & 26 deletions devices/serial_port.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package devices

import (
"bytes"
"fmt"
"io"
"log"

"github.com/maxfierke/gogo-gb/mem"
)
Expand Down Expand Up @@ -76,29 +73,19 @@ func (sc *SerialCtrl) SetClockInternal(enabled bool) {
}

type SerialPort struct {
clk uint
ctrl SerialCtrl
recv byte
buf byte
reader io.Reader
writer io.Writer
clk uint
ctrl SerialCtrl
recv byte
buf byte
host HostContext
}

func NewSerialPort() *SerialPort {
func NewSerialPort(host HostContext) *SerialPort {
return &SerialPort{
reader: bytes.NewReader([]byte{}),
writer: io.Discard,
host: host,
}
}

func (sp *SerialPort) SetReader(reader io.Reader) {
sp.reader = reader
}

func (sp *SerialPort) SetWriter(writer io.Writer) {
sp.writer = writer
}

func (sp *SerialPort) Step(cycles uint8, ic *InterruptController) {
if !sp.ctrl.IsTransferEnabled() {
return
Expand Down Expand Up @@ -135,20 +122,22 @@ func (sp *SerialPort) OnWrite(mmu *mem.MMU, addr uint16, value byte) mem.MemWrit
sp.ctrl.Write(value)

if sp.ctrl.IsTransferEnabled() && sp.ctrl.IsClockInternal() {
cable := sp.host.SerialCable()
logger := sp.host.Logger()

// TODO(GBC): derive this somehow and factor in GBC speeds when relevant
sp.clk = 8192

_, err := sp.writer.Write([]byte{sp.buf})
err := cable.WriteByte(sp.buf)
if err != nil {
// TODO: Use logger from DMG here
log.Printf("Unable to write 0x%02X @ 0x%04X due to an error: %v\n", value, addr, err)
logger.Printf("Unable to write 0x%02X to serial cable: %v\n", value, err)
}

readBuf := make([]byte, 1)
if bytesRead, err := sp.reader.Read(readBuf); err != nil || bytesRead == 0 {
recvVal, err := cable.ReadByte()
if err != nil {
sp.recv = 0xFF
} else {
sp.recv = readBuf[0]
sp.recv = recvVal
}
}

Expand Down
26 changes: 7 additions & 19 deletions hardware/dmg.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package hardware

import (
"io"
"log"

"github.com/maxfierke/gogo-gb/cart"
Expand All @@ -25,15 +24,15 @@ type DMG struct {

// Non-components
debugger debug.Debugger
logger *log.Logger
host devices.HostContext
}

func NewDMG() (*DMG, error) {
func NewDMG(host devices.HostContext) (*DMG, error) {
debugger := debug.NewNullDebugger()
return NewDMGDebug(debugger)
return NewDMGDebug(host, debugger)
}

func NewDMGDebug(debugger debug.Debugger) (*DMG, error) {
func NewDMGDebug(host devices.HostContext, debugger debug.Debugger) (*DMG, error) {
cpu, err := cpu.NewCPU()
if err != nil {
return nil, err
Expand All @@ -42,7 +41,7 @@ func NewDMGDebug(debugger debug.Debugger) (*DMG, error) {
cartridge := cart.NewCartridge()
ic := devices.NewInterruptController()
lcd := devices.NewLCD()
serial := devices.NewSerialPort()
serial := devices.NewSerialPort(host)
timer := devices.NewTimer()

ram := make([]byte, DMG_RAM_SIZE)
Expand Down Expand Up @@ -72,6 +71,7 @@ func NewDMGDebug(debugger debug.Debugger) (*DMG, error) {
cartridge: cartridge,
debugger: debugger,
ic: ic,
host: host,
lcd: lcd,
serial: serial,
timer: timer,
Expand All @@ -91,7 +91,7 @@ func (dmg *DMG) Step() bool {

cycles, err := dmg.cpu.Step(dmg.mmu)
if err != nil {
dmg.logger.Printf("Unexpected error while executing instruction: %v\n", err)
dmg.host.Logger().Printf("Unexpected error while executing instruction: %v\n", err)
return false
}

Expand All @@ -110,15 +110,3 @@ func (dmg *DMG) Run() {
dmg.debugger.OnExecute(dmg.cpu, dmg.mmu)
}
}

func (dmg *DMG) SetLogger(logger *log.Logger) {
dmg.logger = logger
}

func (dmg *DMG) SetSerialReader(serial io.Reader) {
dmg.serial.SetReader(serial)
}

func (dmg *DMG) SetSerialWriter(serial io.Writer) {
dmg.serial.SetWriter(serial)
}
36 changes: 21 additions & 15 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/maxfierke/gogo-gb/cart"
"github.com/maxfierke/gogo-gb/cpu/isa"
"github.com/maxfierke/gogo-gb/debug"
"github.com/maxfierke/gogo-gb/devices"
"github.com/maxfierke/gogo-gb/hardware"
)

Expand Down Expand Up @@ -102,32 +103,37 @@ func debugPrintOpcodes(options *CLIOptions) {
func initDMG(options *CLIOptions) *hardware.DMG {
logger := options.logger

debugger, err := debug.NewDebugger(options.debugger)
if err != nil {
logger.Fatalf("Unable to initialize Debugger: %v\n", err)
}

dmg, err := hardware.NewDMGDebug(debugger)
if err != nil {
logger.Fatalf("Unable to initialize DMG: %v\n", err)
}

dmg.SetLogger(logger)
host := devices.NewHost()
host.SetLogger(logger)

if options.serialPort != "" {
serialCable := devices.NewHostSerialCable()

if options.serialPort == "stdout" || options.serialPort == "/dev/stdout" {
dmg.SetSerialWriter(os.Stdout)
serialCable.SetWriter(os.Stdout)
} else if options.serialPort == "stderr" || options.serialPort == "/dev/stderr" {
dmg.SetSerialWriter(os.Stderr)
serialCable.SetWriter(os.Stderr)
} else {
serialPort, err := os.Create(options.serialPort)
if err != nil {
logger.Fatalf("Unable to open file '%s' as serial port: %v\n", options.serialPort, err)
}

dmg.SetSerialReader(serialPort)
dmg.SetSerialWriter(serialPort)
serialCable.SetReader(serialPort)
serialCable.SetWriter(serialPort)
}

host.SetSerialCable(serialCable)
}

debugger, err := debug.NewDebugger(options.debugger)
if err != nil {
logger.Fatalf("Unable to initialize Debugger: %v\n", err)
}

dmg, err := hardware.NewDMGDebug(host, debugger)
if err != nil {
logger.Fatalf("Unable to initialize DMG: %v\n", err)
}

return dmg
Expand Down

0 comments on commit ba353ef

Please sign in to comment.