izapple2/romX.go

128 lines
3.4 KiB
Go
Raw Normal View History

2020-10-24 22:22:52 +00:00
package izapple2
import (
"fmt"
"github.com/ivanizag/izapple2/core6502"
)
/*
RomX from https://theromexchange.com/
This complement uses the RomX API spec to switch main ROM and character generator ROM
See:
https://theromexchange.com/documentation/ROM%20X%20API%20Reference.pdf
https://theromexchange.com/downloads/ROM%20X%2020-10-22.zip
It is not enough to intercept the ROM accesses. RomX intercept the 74LS138 in
position F12, that has access to the full 0xc000-0xf000 on the Apple II+
*/
type romX struct {
a *Apple2
memory core6502.Memory
activationStep int
systemBank uint8
textBank uint8
}
var romXActivationSequence = []uint16{0xcaca, 0xcaca, 0xcafe}
const (
setupBank = uint8(0)
romXSetSystemBankBaseAddress = uint16(0xcef0)
romXSetTextBankBaseAddress = uint16(0xcfd0)
romXDefaultSystemBankAddress = uint16(0xd034)
romXDefaultTextBankAddress = uint16(0xd02e)
// Unknown
romXFirmwareMark0Address = uint16(0xdffe)
romXFirmwareMark0Value = uint8(0x4a)
romXFirmwareMark1Address = uint16(0xdfff)
romXFirmwareMark1Value = uint8(0xcd)
)
func newRomX(a *Apple2, memory core6502.Memory) *romX {
var rx romX
rx.a = a
rx.memory = memory
rx.systemBank = 0
rx.textBank = 0
return &rx
}
func (rx *romX) Peek(address uint16) uint8 {
intercepted, value := rx.interceptAccess(address)
if intercepted {
return value
}
return rx.memory.Peek(address)
}
func (rx *romX) PeekCode(address uint16) uint8 {
//intercepted, value := rx.interceptAccess(address)
//if intercepted {
// return value
//}
return rx.memory.PeekCode(address)
}
func (rx *romX) Poke(address uint16, value uint8) {
rx.interceptAccess(address)
rx.memory.Poke(address, value)
}
func (rx *romX) interceptAccess(address uint16) (bool, uint8) {
// Intercept only $C080 to $FFFF as seen by the F12 chip
if address < 0xc080 {
return false, 0
}
// Setup mode when the setup bank is active
if rx.systemBank == setupBank {
switch address {
case romXDefaultSystemBankAddress:
fmt.Printf("[romX]Peek in $%04x, current system bank %v\n", address, rx.systemBank)
return true, 0xe0 + rx.systemBank
case romXDefaultTextBankAddress:
fmt.Printf("[romX]PeeK in $%04x, current text bank %v\n", address, rx.textBank)
return true, 0xd0 + rx.textBank
case romXFirmwareMark0Address:
fmt.Printf("[romX]Peek in $%04x, ???\n", address)
return true, romXFirmwareMark0Value
case romXFirmwareMark1Address:
fmt.Printf("[romX]Peek in $%04x, ???\n", address)
return true, romXFirmwareMark1Value
}
if address&0xfff0 == romXSetSystemBankBaseAddress {
rx.systemBank = uint8(address & 0xf)
fmt.Printf("[romX]System bank set to %v\n", rx.systemBank)
} else if address&0xfff0 == romXSetTextBankBaseAddress {
rx.textBank = uint8(address & 0xf)
fmt.Printf("[romX]Text bank set to %v\n", rx.textBank)
} else if address < 0xe000 {
fmt.Printf("[romX]Peek in $%04x\n", address)
}
return false, 0
}
// Activation sequence detection
if address == romXActivationSequence[rx.activationStep] {
rx.activationStep++
//fmt.Printf("[romX]Activation step %v\n", rx.activationStep)
if rx.activationStep == len(romXActivationSequence) {
// Activation sequence completed
rx.systemBank = setupBank
rx.activationStep = 0
// rx.a.cpu.SetTrace(true)
fmt.Printf("[romX]System bank set to 0, %v\n", rx.systemBank)
}
} else {
rx.activationStep = 0
}
return false, 0
}