ROM can be paged, refactor the Base64A ROM

This commit is contained in:
Ivan Izaguirre 2024-01-22 23:09:35 +01:00
parent 63c982d976
commit 9c27175f86
6 changed files with 60 additions and 41 deletions

View File

@ -1,8 +1,6 @@
package izapple2
import (
"fmt"
)
import "fmt"
/*
Copam BASE64A adaptation.
@ -36,14 +34,16 @@ func loadBase64aRom(a *Apple2) error {
}
}
// Create banks
for j := range romBanksBytes {
a.mmu.physicalROM[j] = newMemoryRange(0xd000, romBanksBytes[j], fmt.Sprintf("Base64 ROM page %v", j))
// Create paged ROM
romData := make([]uint8, 0, base64aRomBankSize*base64aRomBankCount)
for _, bank := range romBanksBytes {
romData = append(romData, bank...)
}
rom := newMemoryRangePagedROM(0xd000, romData, "Base64 ROM", base64aRomBankCount)
// Start with first bank active
a.mmu.setActiveROMPage(0)
rom.setPage(0)
a.mmu.physicalROM = rom
return nil
}
@ -55,23 +55,31 @@ func addBase64aSoftSwitches(io *ioC0Page) {
// ROM pagination softswitches. They use the annunciator 0 and 1
mmu := io.apple2.mmu
io.addSoftSwitchRW(0x58, func() uint8 {
p := mmu.getActiveROMPage()
mmu.setActiveROMPage(p & 2)
if rom, ok := mmu.physicalROM.(*memoryRangeROM); ok {
p := rom.getPage()
rom.setPage(p & 2)
}
return 0
}, "ANN0OFF-ROM")
io.addSoftSwitchRW(0x59, func() uint8 {
p := mmu.getActiveROMPage()
mmu.setActiveROMPage(p | 1)
if rom, ok := mmu.physicalROM.(*memoryRangeROM); ok {
p := rom.getPage()
rom.setPage(p | 1)
}
return 0
}, "ANN0ON-ROM")
io.addSoftSwitchRW(0x5A, func() uint8 {
p := mmu.getActiveROMPage()
mmu.setActiveROMPage(p & 1)
if rom, ok := mmu.physicalROM.(*memoryRangeROM); ok {
p := rom.getPage()
rom.setPage(p & 1)
}
return 0
}, "ANN1OFF-ROM")
io.addSoftSwitchRW(0x5B, func() uint8 {
p := mmu.getActiveROMPage()
mmu.setActiveROMPage(p | 2)
if rom, ok := mmu.physicalROM.(*memoryRangeROM); ok {
p := rom.getPage()
rom.setPage(p | 2)
}
return 0
}, "ANN1ON-ROM")

View File

@ -29,11 +29,9 @@ type CardThunderClockPlus struct {
func newCardThunderClockPlusBuilder() *cardBuilder {
return &cardBuilder{
name: "ThunderClock+ Card",
description: "Clock card",
defaultParams: &[]paramSpec{
{"rom", "ROM file to load", "<internal>/ThunderclockPlusROM.bin"},
},
name: "ThunderClock+ Card",
description: "Clock card",
defaultParams: &[]paramSpec{},
buildFunc: func(params map[string]string) (Card, error) {
var c CardThunderClockPlus
err := c.loadRomFromResource("<internal>/ThunderclockPlusROM.bin")

View File

@ -16,7 +16,7 @@ type memoryManager struct {
cardsROMExtra [8]memoryHandler // 0xc800 to 0xcfff. 2048 bytes for each card
// Upper area ROM: 0xc000 to 0xffff (or 0xd000 to 0xffff on the II+)
physicalROM [4]memoryHandler // 0xc000 (or 0xd000) to 0xffff, 16 (or 12) Kb. Up to four banks
physicalROM memoryHandler // 0xc000 (or 0xd000) to 0xffff, 16 (or 12) Kb. Up to four banks
// Language card upper area RAM: 0xd000 to 0xffff. One bank for regular LC cards, up to 8 with Saturn
physicalLangRAM []*memoryRange // 0xd000 to 0xffff, 12KB. Up to 8 banks.
@ -44,9 +44,6 @@ type memoryManager struct {
extendedRAMBlock uint8 // Block used for entended memory for RAMWorks cards
mainROMinhibited memoryHandler // Alternative ROM from 0xd000 to 0xffff provided by a card with the INH signal.
// Configuration switches, Base64A
romPage uint8 // Active ROM page
// Resolution cache
lastAddressPage uint16 // The first byte is the page. The second is zero when the cached is valid.
lastAddressHandler memoryHandler
@ -90,12 +87,12 @@ func (mmu *memoryManager) accessCArea(address uint16) memoryHandler {
// Internal IIe slot 3
if (address <= addressLimitSlots) && !mmu.slotC3ROMActive && (slot == 3) {
mmu.intC8ROMActive = true
return mmu.physicalROM[mmu.romPage]
return mmu.physicalROM
}
// Internal IIe CxROM
if mmu.intCxROMActive {
return mmu.physicalROM[mmu.romPage]
return mmu.physicalROM
}
// First slot area
@ -114,7 +111,7 @@ func (mmu *memoryManager) accessCArea(address uint16) memoryHandler {
// Extra slot area
if mmu.intC8ROMActive {
return mmu.physicalROM[mmu.romPage]
return mmu.physicalROM
}
return mmu.cardsROMExtra[mmu.activeSlot]
}
@ -188,7 +185,7 @@ func (mmu *memoryManager) accessRead(address uint16) memoryHandler {
if mmu.lcActiveRead {
return mmu.accessUpperRAMArea(address)
}
return mmu.physicalROM[mmu.romPage]
return mmu.physicalROM
}
func (mmu *memoryManager) accessWrite(address uint16) memoryHandler {
@ -221,7 +218,7 @@ func (mmu *memoryManager) accessWrite(address uint16) memoryHandler {
if mmu.lcActiveWrite {
return mmu.accessUpperRAMArea(address)
}
return mmu.physicalROM[mmu.romPage]
return mmu.physicalROM
}
func (mmu *memoryManager) peekWord(address uint16) uint16 {
@ -318,14 +315,6 @@ func (mmu *memoryManager) initExtendedRAM(groups int) {
}
// Memory configuration
func (mmu *memoryManager) setActiveROMPage(page uint8) {
mmu.romPage = page
}
func (mmu *memoryManager) getActiveROMPage() uint8 {
return mmu.romPage
}
func (mmu *memoryManager) setLanguageRAM(readActive bool, writeActive bool, altBank bool) {
mmu.lcActiveRead = readActive
mmu.lcActiveWrite = writeActive

View File

@ -12,6 +12,8 @@ type memoryRange struct {
type memoryRangeROM struct {
memoryRange
pageOffset uint16
pages uint8
}
func newMemoryRange(base uint16, data []uint8, name string) *memoryRange {
@ -25,10 +27,15 @@ func newMemoryRange(base uint16, data []uint8, name string) *memoryRange {
}
func newMemoryRangeROM(base uint16, data []uint8, name string) *memoryRangeROM {
return newMemoryRangePagedROM(base, data, name, 1)
}
func newMemoryRangePagedROM(base uint16, data []uint8, name string, pages uint8) *memoryRangeROM {
var m memoryRangeROM
m.base = base
m.data = data
m.name = name
m.pages = pages
return &m
}
@ -48,10 +55,27 @@ func (m *memoryRange) subRange(a, b uint16) []uint8 {
return m.data[a-m.base : b-m.base]
}
func (m *memoryRangeROM) setPage(page uint8) {
pageSize := len(m.data) / int(m.pages)
m.pageOffset = uint16(int(page%m.pages) * pageSize)
}
func (m *memoryRangeROM) getPage() uint8 {
pageSize := len(m.data) / int(m.pages)
return uint8(m.pageOffset / uint16(pageSize))
}
func (m *memoryRangeROM) peek(address uint16) uint8 {
return m.data[address-m.base+m.pageOffset]
}
func (m *memoryRangeROM) poke(address uint16, value uint8) {
// Ignore
}
func (m *memoryRangeROM) subRange(a, b uint16) []uint8 {
return m.data[a-m.base+m.pageOffset : b-m.base+m.pageOffset]
}
//lint:ignore U1000 this is used to write debug code
func identifyMemory(m memoryHandler) string {
ram, ok := m.(*memoryRange)

View File

@ -204,8 +204,8 @@ func (nsc *noSlotClockDS1216) loadTime() {
func setupNoSlotClock(a *Apple2, arg string) error {
if arg == "main" {
nsc := newNoSlotClockDS1216(a, a.mmu.physicalROM[0])
a.mmu.physicalROM[0] = nsc
nsc := newNoSlotClockDS1216(a, a.mmu.physicalROM)
a.mmu.physicalROM = nsc
} else {
slot, err := strconv.ParseUint(arg, 10, 8)
if err != nil || slot < 1 || slot > 7 {

View File

@ -150,7 +150,7 @@ func (a *Apple2) loadRom(filename string) error {
size := len(data)
romBase := 0x10000 - size
a.mmu.physicalROM[0] = newMemoryRangeROM(uint16(romBase), data, "Main ROM")
a.mmu.physicalROM = newMemoryRangeROM(uint16(romBase), data, "Main ROM")
return nil
}