goapple2/goapple2.go

95 lines
1.7 KiB
Go
Raw Normal View History

package goapple2
import (
"github.com/zellyn/go6502/cpu"
"github.com/zellyn/goapple2/videoscan"
)
// Memory for the tests. Satisfies the cpu.Memory interface.
type Apple2 struct {
mem [65536]byte
cpu cpu.Cpu
key byte // BUG(zellyn): make reads/writes atomic
keys chan byte
plotter videoscan.Plotter
scanner *videoscan.Scanner
done bool
tw TickWaiter
}
// Cycle counter. Satisfies the cpu.Ticker interface.
type TickWaiter struct {
Wait chan byte
}
func (t TickWaiter) Tick() {
<-t.Wait
}
func NewTickWaiter() TickWaiter {
return TickWaiter{Wait: make(chan byte)}
}
func NewApple2(p videoscan.Plotter, rom []byte, charRom [2048]byte) *Apple2 {
tw := NewTickWaiter()
a2 := Apple2{
keys: make(chan byte, 16),
tw: tw,
}
copy(a2.mem[len(a2.mem)-len(rom):len(a2.mem)], rom)
a2.scanner = videoscan.NewScanner(&a2, p, charRom)
a2.cpu = cpu.NewCPU(&a2, tw, cpu.VERSION_6502)
a2.cpu.Reset()
go func() {
tw.Tick()
for !a2.done {
a2.cpu.Step()
}
}()
return &a2
}
func (a2 *Apple2) Read(address uint16) byte {
// Keyboard read
if address == 0xC000 {
if a2.key&0x80 == 0 {
select {
case key := <-a2.keys:
a2.key = key
default:
}
}
return a2.key
}
if address == 0xC010 {
a2.key &= 0x7F
return 0 // BUG(zellyn): return proper value (keydown on IIe, not sure on II+)
}
return a2.mem[address]
}
func (a2 *Apple2) Write(address uint16, value byte) {
if address >= 0xD000 {
return
}
if address == 0xC010 {
// Clear keyboard strobe
a2.key &= 0x7F
}
a2.mem[address] = value
}
func (a2 *Apple2) Keypress(key byte) {
a2.keys <- key | 0x80
}
func (a2 *Apple2) Step() error {
a2.tw.Wait <- 0
a2.scanner.Scan1()
return nil
}
func (a2 *Apple2) Quit() {
a2.done = true
}