2020-10-03 23:38:26 +02:00
|
|
|
package izapple2
|
2019-02-16 17:32:06 +01:00
|
|
|
|
2019-02-18 00:01:48 +01:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
)
|
2019-02-16 17:32:06 +01:00
|
|
|
|
|
|
|
type ioC0Page struct {
|
2019-09-24 23:32:03 +02:00
|
|
|
softSwitchesR [256]softSwitchR
|
|
|
|
softSwitchesW [256]softSwitchW
|
2019-10-21 00:00:42 +02:00
|
|
|
softSwitchesRName [256]string
|
|
|
|
softSwitchesWName [256]string
|
2019-09-24 23:32:03 +02:00
|
|
|
softSwitchesData [128]uint8
|
|
|
|
keyboard KeyboardProvider
|
|
|
|
speaker SpeakerProvider
|
|
|
|
paddlesStrobeCycle uint64
|
|
|
|
joysticks JoysticksProvider
|
2021-01-24 23:25:52 +01:00
|
|
|
mouse MouseProvider
|
2019-09-24 23:32:03 +02:00
|
|
|
apple2 *Apple2
|
|
|
|
trace bool
|
2020-08-30 21:11:43 +02:00
|
|
|
traceRegistrations bool
|
2019-09-24 23:32:03 +02:00
|
|
|
panicNotImplemented bool
|
2019-02-20 23:51:47 +01:00
|
|
|
}
|
|
|
|
|
2022-08-05 19:43:17 +02:00
|
|
|
type softSwitchR func() uint8
|
|
|
|
type softSwitchW func(value uint8)
|
2019-02-24 00:41:32 +01:00
|
|
|
|
2019-08-06 00:37:27 +02:00
|
|
|
// SpeakerProvider provides a speaker implementation
|
2019-05-10 00:09:15 +02:00
|
|
|
type SpeakerProvider interface {
|
|
|
|
// Click receives a speaker click. The argument is the CPU cycle when it is generated
|
|
|
|
Click(cycle uint64)
|
|
|
|
}
|
|
|
|
|
2021-01-24 23:25:52 +01:00
|
|
|
// JoysticksProvider abstracts the joysticks
|
2019-08-06 00:37:27 +02:00
|
|
|
type JoysticksProvider interface {
|
|
|
|
ReadButton(i int) bool
|
2019-11-20 23:28:51 +01:00
|
|
|
ReadPaddle(i int) (uint8, bool)
|
2019-08-06 00:37:27 +02:00
|
|
|
}
|
|
|
|
|
2021-01-24 23:25:52 +01:00
|
|
|
// MouseProvider abstracts the mouse
|
|
|
|
type MouseProvider interface {
|
|
|
|
ReadMouse() (x uint16, y uint16, pressed bool)
|
|
|
|
}
|
|
|
|
|
2019-02-16 17:32:06 +01:00
|
|
|
// See https://www.kreativekorp.com/miscpages/a2info/iomemory.shtml
|
|
|
|
// See https://stason.org/TULARC/pc/apple2/programmer/004-I-d-like-to-do-some-serious-Apple-II-programming-Whe.html
|
|
|
|
|
|
|
|
const (
|
2019-02-24 14:37:10 +01:00
|
|
|
ssOn uint8 = 0x80
|
|
|
|
ssOff uint8 = 0x00
|
|
|
|
)
|
|
|
|
|
2019-03-02 18:33:50 +01:00
|
|
|
func newIoC0Page(a *Apple2) *ioC0Page {
|
2019-02-24 15:05:50 +01:00
|
|
|
var io ioC0Page
|
2019-03-02 18:33:50 +01:00
|
|
|
io.apple2 = a
|
2019-02-24 15:05:50 +01:00
|
|
|
return &io
|
2019-02-24 00:41:32 +01:00
|
|
|
}
|
|
|
|
|
2019-09-24 23:32:03 +02:00
|
|
|
func (p *ioC0Page) setTrace(trace bool) {
|
|
|
|
p.trace = trace
|
|
|
|
}
|
|
|
|
|
2020-08-30 21:11:43 +02:00
|
|
|
func (p *ioC0Page) setTraceRegistrations(traceRegistrations bool) {
|
|
|
|
p.traceRegistrations = traceRegistrations
|
|
|
|
}
|
|
|
|
|
2019-09-24 23:32:03 +02:00
|
|
|
func (p *ioC0Page) setPanicNotImplemented(value bool) {
|
|
|
|
p.panicNotImplemented = value
|
|
|
|
}
|
|
|
|
|
2019-10-21 00:00:42 +02:00
|
|
|
func (p *ioC0Page) addSoftSwitchRW(address uint8, ss softSwitchR, name string) {
|
|
|
|
p.addSoftSwitchR(address, ss, name)
|
2022-08-05 19:43:17 +02:00
|
|
|
p.addSoftSwitchW(address, func(uint8) {
|
|
|
|
ss()
|
2019-10-21 00:00:42 +02:00
|
|
|
}, name)
|
2019-02-24 23:54:13 +01:00
|
|
|
}
|
|
|
|
|
2019-10-21 00:00:42 +02:00
|
|
|
func (p *ioC0Page) addSoftSwitchR(address uint8, ss softSwitchR, name string) {
|
2020-08-30 21:11:43 +02:00
|
|
|
if p.traceRegistrations {
|
|
|
|
fmt.Printf("Softswitch registered in $c0%02x for reads as %s\n", address, name)
|
|
|
|
}
|
2019-02-24 23:54:13 +01:00
|
|
|
p.softSwitchesR[address] = ss
|
2019-10-21 00:00:42 +02:00
|
|
|
p.softSwitchesRName[address] = name
|
2019-02-24 23:54:13 +01:00
|
|
|
}
|
|
|
|
|
2019-10-21 00:00:42 +02:00
|
|
|
func (p *ioC0Page) addSoftSwitchW(address uint8, ss softSwitchW, name string) {
|
2020-08-30 21:11:43 +02:00
|
|
|
if p.traceRegistrations {
|
|
|
|
fmt.Printf("Softswitch registered in $c0%02x for writes as %s\n", address, name)
|
|
|
|
}
|
2019-02-24 23:54:13 +01:00
|
|
|
p.softSwitchesW[address] = ss
|
2019-10-21 00:00:42 +02:00
|
|
|
p.softSwitchesWName[address] = name
|
2019-02-24 23:54:13 +01:00
|
|
|
}
|
|
|
|
|
2019-04-21 21:04:02 +02:00
|
|
|
func (p *ioC0Page) isSoftSwitchActive(ioFlag uint8) bool {
|
2019-02-24 15:05:50 +01:00
|
|
|
return (p.softSwitchesData[ioFlag] & ssOn) == ssOn
|
2019-02-16 17:32:06 +01:00
|
|
|
}
|
|
|
|
|
2019-04-13 20:29:31 +02:00
|
|
|
func (p *ioC0Page) setKeyboardProvider(kb KeyboardProvider) {
|
2019-02-24 00:41:32 +01:00
|
|
|
p.keyboard = kb
|
2019-02-16 17:32:06 +01:00
|
|
|
}
|
|
|
|
|
2019-05-10 00:09:15 +02:00
|
|
|
func (p *ioC0Page) setSpeakerProvider(s SpeakerProvider) {
|
|
|
|
p.speaker = s
|
|
|
|
}
|
|
|
|
|
2019-08-06 00:37:27 +02:00
|
|
|
func (p *ioC0Page) setJoysticksProvider(j JoysticksProvider) {
|
|
|
|
p.joysticks = j
|
|
|
|
}
|
|
|
|
|
2021-01-24 23:25:52 +01:00
|
|
|
func (p *ioC0Page) setMouseProvider(m MouseProvider) {
|
|
|
|
p.mouse = m
|
|
|
|
}
|
|
|
|
|
2019-05-16 22:51:04 +02:00
|
|
|
func (p *ioC0Page) peek(address uint16) uint8 {
|
|
|
|
pageAddress := uint8(address)
|
|
|
|
ss := p.softSwitchesR[pageAddress]
|
2019-02-24 23:54:13 +01:00
|
|
|
if ss == nil {
|
2019-11-03 18:22:10 +01:00
|
|
|
if p.trace {
|
|
|
|
fmt.Printf("Unknown softswitch on read to $%04x\n", address)
|
|
|
|
}
|
2019-09-24 23:32:03 +02:00
|
|
|
if p.panicNotImplemented {
|
|
|
|
panic(fmt.Sprintf("Unknown softswitch on read to $%04x", address))
|
2019-04-15 23:13:05 +02:00
|
|
|
}
|
2019-03-05 00:00:12 +01:00
|
|
|
return 0
|
2019-02-24 23:54:13 +01:00
|
|
|
}
|
2022-08-05 19:43:17 +02:00
|
|
|
value := ss()
|
2019-10-21 00:00:42 +02:00
|
|
|
if p.trace && address != 0xc000 {
|
|
|
|
name := p.softSwitchesRName[pageAddress]
|
|
|
|
fmt.Printf("Softswitch peek on $%04x %v: $%02x\n", address, name, value)
|
2019-09-24 23:32:03 +02:00
|
|
|
}
|
2019-06-09 17:36:29 +02:00
|
|
|
return value
|
2019-02-16 17:32:06 +01:00
|
|
|
}
|
|
|
|
|
2019-05-16 22:51:04 +02:00
|
|
|
func (p *ioC0Page) poke(address uint16, value uint8) {
|
|
|
|
pageAddress := uint8(address)
|
|
|
|
ss := p.softSwitchesW[pageAddress]
|
2019-02-24 00:41:32 +01:00
|
|
|
if ss == nil {
|
2019-11-03 18:22:10 +01:00
|
|
|
if p.trace {
|
|
|
|
fmt.Printf("Unknown softswitch on write to $%04x\n", address)
|
|
|
|
}
|
2019-09-24 23:32:03 +02:00
|
|
|
if p.panicNotImplemented {
|
|
|
|
panic(fmt.Sprintf("Unknown softswitch on write to $%04x", address))
|
2019-04-15 23:13:05 +02:00
|
|
|
}
|
2019-03-05 00:00:12 +01:00
|
|
|
return
|
2019-02-24 00:41:32 +01:00
|
|
|
}
|
2019-10-21 00:00:42 +02:00
|
|
|
if p.trace && address != 0xc000 {
|
|
|
|
name := p.softSwitchesWName[pageAddress]
|
|
|
|
fmt.Printf("Softswitch poke on $%04x %v with $%02x\n", address, name, value)
|
|
|
|
}
|
2022-08-05 19:43:17 +02:00
|
|
|
ss(value)
|
2019-02-24 00:41:32 +01:00
|
|
|
}
|
2019-11-06 00:02:03 +01:00
|
|
|
|
2021-03-14 18:46:52 +01:00
|
|
|
func (p *ioC0Page) setBase(_ uint16) {
|
|
|
|
// Ignore
|
|
|
|
}
|
|
|
|
|
2019-11-06 00:02:03 +01:00
|
|
|
func ssFromBool(value bool) uint8 {
|
|
|
|
if value {
|
|
|
|
return ssOn
|
|
|
|
}
|
|
|
|
return ssOff
|
|
|
|
}
|