2019-02-16 19:15:41 +00:00
|
|
|
package apple2
|
2019-02-16 16:32:06 +00:00
|
|
|
|
2019-02-17 23:01:48 +00:00
|
|
|
import (
|
2019-05-17 21:28:20 +00:00
|
|
|
"encoding/binary"
|
2019-02-17 23:01:48 +00:00
|
|
|
"fmt"
|
2019-05-17 21:28:20 +00:00
|
|
|
"io"
|
2019-02-17 23:01:48 +00:00
|
|
|
)
|
2019-02-16 16:32:06 +00:00
|
|
|
|
|
|
|
type ioC0Page struct {
|
2019-03-02 19:41:25 +00:00
|
|
|
softSwitchesR [256]softSwitchR
|
|
|
|
softSwitchesW [256]softSwitchW
|
2019-02-23 23:41:32 +00:00
|
|
|
softSwitchesData [128]uint8
|
2019-04-13 18:29:31 +00:00
|
|
|
keyboard KeyboardProvider
|
2019-05-09 22:09:15 +00:00
|
|
|
speaker SpeakerProvider
|
2019-03-02 17:33:50 +00:00
|
|
|
apple2 *Apple2
|
2019-02-20 22:51:47 +00:00
|
|
|
}
|
|
|
|
|
2019-02-24 22:54:13 +00:00
|
|
|
type softSwitchR func(io *ioC0Page) uint8
|
|
|
|
type softSwitchW func(io *ioC0Page, value uint8)
|
2019-02-23 23:41:32 +00:00
|
|
|
|
2019-04-21 19:04:02 +00:00
|
|
|
// KeyboardProvider declares the keyboard implementation requirements
|
2019-04-13 18:29:31 +00:00
|
|
|
type KeyboardProvider interface {
|
2019-04-14 18:46:40 +00:00
|
|
|
GetKey(strobe bool) (key uint8, ok bool)
|
2019-02-16 16:32:06 +00:00
|
|
|
}
|
|
|
|
|
2019-05-09 22:09:15 +00:00
|
|
|
// SpeakerProvider declares the speaker implementation requirements
|
|
|
|
type SpeakerProvider interface {
|
|
|
|
// Click receives a speaker click. The argument is the CPU cycle when it is generated
|
|
|
|
Click(cycle uint64)
|
|
|
|
}
|
|
|
|
|
2019-02-16 16:32:06 +00: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 13:37:10 +00:00
|
|
|
ssOn uint8 = 0x80
|
|
|
|
ssOff uint8 = 0x00
|
|
|
|
)
|
|
|
|
|
2019-03-02 17:33:50 +00:00
|
|
|
func newIoC0Page(a *Apple2) *ioC0Page {
|
2019-02-24 14:05:50 +00:00
|
|
|
var io ioC0Page
|
2019-03-02 17:33:50 +00:00
|
|
|
io.apple2 = a
|
2019-02-16 16:32:06 +00:00
|
|
|
|
2019-02-24 14:05:50 +00:00
|
|
|
addApple2SoftSwitches(&io)
|
2019-03-02 17:33:50 +00:00
|
|
|
if a.isApple2e {
|
2019-02-24 14:05:50 +00:00
|
|
|
addApple2ESoftSwitches(&io)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &io
|
2019-02-23 23:41:32 +00:00
|
|
|
}
|
|
|
|
|
2019-05-17 21:28:20 +00:00
|
|
|
func (p *ioC0Page) save(w io.Writer) {
|
|
|
|
binary.Write(w, binary.BigEndian, p.softSwitchesData)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *ioC0Page) load(r io.Reader) {
|
|
|
|
binary.Read(r, binary.BigEndian, &p.softSwitchesData)
|
|
|
|
}
|
|
|
|
|
2019-02-24 22:54:13 +00:00
|
|
|
func (p *ioC0Page) addSoftSwitchRW(address uint8, ss softSwitchR) {
|
|
|
|
p.addSoftSwitchR(address, ss)
|
|
|
|
p.addSoftSwitchW(address, func(p *ioC0Page, _ uint8) {
|
|
|
|
ss(p)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *ioC0Page) addSoftSwitchR(address uint8, ss softSwitchR) {
|
|
|
|
if p.softSwitchesR[address] != nil {
|
|
|
|
fmt.Printf("Addresss 0x0c%02x is already assigned for read", address)
|
|
|
|
}
|
|
|
|
p.softSwitchesR[address] = ss
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *ioC0Page) addSoftSwitchW(address uint8, ss softSwitchW) {
|
|
|
|
if p.softSwitchesW[address] != nil {
|
|
|
|
fmt.Printf("Addresss 0x0c%02x is already assigned for write", address)
|
|
|
|
}
|
|
|
|
p.softSwitchesW[address] = ss
|
|
|
|
}
|
|
|
|
|
2019-04-21 19:04:02 +00:00
|
|
|
func (p *ioC0Page) isSoftSwitchActive(ioFlag uint8) bool {
|
2019-02-24 14:05:50 +00:00
|
|
|
return (p.softSwitchesData[ioFlag] & ssOn) == ssOn
|
2019-02-16 16:32:06 +00:00
|
|
|
}
|
|
|
|
|
2019-04-13 18:29:31 +00:00
|
|
|
func (p *ioC0Page) setKeyboardProvider(kb KeyboardProvider) {
|
2019-02-23 23:41:32 +00:00
|
|
|
p.keyboard = kb
|
2019-02-16 16:32:06 +00:00
|
|
|
}
|
|
|
|
|
2019-05-09 22:09:15 +00:00
|
|
|
func (p *ioC0Page) setSpeakerProvider(s SpeakerProvider) {
|
|
|
|
p.speaker = s
|
|
|
|
}
|
|
|
|
|
2019-05-16 20:51:04 +00:00
|
|
|
func (p *ioC0Page) peek(address uint16) uint8 {
|
2019-05-16 20:55:19 +00:00
|
|
|
//fmt.Printf("Peek on $%02x\n", address)
|
2019-05-16 20:51:04 +00:00
|
|
|
pageAddress := uint8(address)
|
|
|
|
ss := p.softSwitchesR[pageAddress]
|
2019-02-24 22:54:13 +00:00
|
|
|
if ss == nil {
|
2019-04-15 21:13:05 +00:00
|
|
|
if p.apple2.panicSS {
|
2019-05-16 20:51:04 +00:00
|
|
|
panic(fmt.Sprintf("Unknown softswitch on read to 0xC0%02x", pageAddress))
|
2019-04-15 21:13:05 +00:00
|
|
|
}
|
2019-03-04 23:00:12 +00:00
|
|
|
return 0
|
2019-02-24 22:54:13 +00:00
|
|
|
}
|
|
|
|
return ss(p)
|
2019-02-16 16:32:06 +00:00
|
|
|
}
|
|
|
|
|
2019-05-16 20:51:04 +00:00
|
|
|
func (p *ioC0Page) poke(address uint16, value uint8) {
|
2019-05-16 20:55:19 +00:00
|
|
|
//fmt.Printf("Poke on $%02x with %02x\n", address, value)
|
2019-05-16 20:51:04 +00:00
|
|
|
pageAddress := uint8(address)
|
|
|
|
ss := p.softSwitchesW[pageAddress]
|
2019-02-23 23:41:32 +00:00
|
|
|
if ss == nil {
|
2019-04-15 21:13:05 +00:00
|
|
|
if p.apple2.panicSS {
|
2019-05-16 20:51:04 +00:00
|
|
|
panic(fmt.Sprintf("Unknown softswitch on write to 0xC0%02x", pageAddress))
|
2019-04-15 21:13:05 +00:00
|
|
|
}
|
2019-03-04 23:00:12 +00:00
|
|
|
return
|
2019-02-23 23:41:32 +00:00
|
|
|
}
|
2019-02-24 22:54:13 +00:00
|
|
|
ss(p, value)
|
2019-02-23 23:41:32 +00:00
|
|
|
}
|