99 lines
1.9 KiB
Go
99 lines
1.9 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"log"
|
||
|
|
||
|
"github.com/koron-go/z80"
|
||
|
)
|
||
|
|
||
|
// ioPeripheral is a z80.IO device at a given address.
|
||
|
type ioPeripheral struct {
|
||
|
start uint8
|
||
|
length uint8
|
||
|
peripheral z80.IO
|
||
|
}
|
||
|
|
||
|
// ioArbiter is a collection of I/O devices at addresses. It implements z80.IO
|
||
|
// itself, dispatching to the appropriate device as needed.
|
||
|
type ioArbiter struct {
|
||
|
peripherals []*ioPeripheral
|
||
|
}
|
||
|
|
||
|
func (i *ioArbiter) get(addr uint8) *ioPeripheral {
|
||
|
for _, periph := range i.peripherals {
|
||
|
if addr < periph.start {
|
||
|
continue
|
||
|
}
|
||
|
if addr > periph.start+periph.length {
|
||
|
continue
|
||
|
}
|
||
|
return periph
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (i *ioArbiter) In(addr uint8) uint8 {
|
||
|
p := i.get(addr)
|
||
|
if p == nil {
|
||
|
log.Fatalf("Unhandled I/O In at %02x", addr)
|
||
|
return 0
|
||
|
}
|
||
|
return p.peripheral.In(addr - p.start)
|
||
|
}
|
||
|
func (i *ioArbiter) Out(addr uint8, value uint8) {
|
||
|
p := i.get(addr)
|
||
|
if p == nil {
|
||
|
log.Fatalf("Unhandled I/O Out at %02x", addr)
|
||
|
return
|
||
|
}
|
||
|
p.peripheral.Out(addr-p.start, value)
|
||
|
}
|
||
|
|
||
|
// memory is a continuous memory region at a given address, optionally marked
|
||
|
// read only.
|
||
|
type memory struct {
|
||
|
start uint16
|
||
|
data []uint8
|
||
|
readonly bool
|
||
|
}
|
||
|
|
||
|
// memoryArbiter implements Z80.Memory and dispatches accesses to subordinate
|
||
|
// memory instances.
|
||
|
type memoryArbiter struct {
|
||
|
memories []memory
|
||
|
}
|
||
|
|
||
|
func (m *memoryArbiter) get(addr uint16) *memory {
|
||
|
for _, mem := range m.memories {
|
||
|
if addr < mem.start {
|
||
|
continue
|
||
|
}
|
||
|
if addr >= mem.start+uint16(len(mem.data)) {
|
||
|
continue
|
||
|
}
|
||
|
return &mem
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (m *memoryArbiter) Get(addr uint16) uint8 {
|
||
|
mem := m.get(addr)
|
||
|
if mem == nil {
|
||
|
log.Fatalf("Unhandled memory Get at %04x", addr)
|
||
|
return 0
|
||
|
}
|
||
|
return mem.data[addr-mem.start]
|
||
|
}
|
||
|
|
||
|
func (m *memoryArbiter) Set(addr uint16, value uint8) {
|
||
|
mem := m.get(addr)
|
||
|
if mem == nil {
|
||
|
log.Fatalf("Unhandled memory Set at %04x", addr)
|
||
|
return
|
||
|
}
|
||
|
if mem.readonly {
|
||
|
log.Fatalf("Read-only memory Set at %04x", addr)
|
||
|
}
|
||
|
mem.data[addr-mem.start] = value
|
||
|
}
|