From 9c27175f86747129eb0b3075c765bf385c93d707 Mon Sep 17 00:00:00 2001 From: Ivan Izaguirre Date: Mon, 22 Jan 2024 23:09:35 +0100 Subject: [PATCH] ROM can be paged, refactor the Base64A ROM --- base64a.go | 40 ++++++++++++++++++++++++---------------- cardThunderClockPlus.go | 8 +++----- memoryManager.go | 23 ++++++----------------- memoryRange.go | 24 ++++++++++++++++++++++++ noSlotClockDS1216.go | 4 ++-- setup.go | 2 +- 6 files changed, 60 insertions(+), 41 deletions(-) diff --git a/base64a.go b/base64a.go index 732a564..a0eb8d8 100644 --- a/base64a.go +++ b/base64a.go @@ -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") diff --git a/cardThunderClockPlus.go b/cardThunderClockPlus.go index ce99c70..b99aa13 100644 --- a/cardThunderClockPlus.go +++ b/cardThunderClockPlus.go @@ -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", "/ThunderclockPlusROM.bin"}, - }, + name: "ThunderClock+ Card", + description: "Clock card", + defaultParams: &[]paramSpec{}, buildFunc: func(params map[string]string) (Card, error) { var c CardThunderClockPlus err := c.loadRomFromResource("/ThunderclockPlusROM.bin") diff --git a/memoryManager.go b/memoryManager.go index f40a63f..7fb146e 100644 --- a/memoryManager.go +++ b/memoryManager.go @@ -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 diff --git a/memoryRange.go b/memoryRange.go index b362aba..3467747 100644 --- a/memoryRange.go +++ b/memoryRange.go @@ -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) diff --git a/noSlotClockDS1216.go b/noSlotClockDS1216.go index d3ee138..0b3deed 100644 --- a/noSlotClockDS1216.go +++ b/noSlotClockDS1216.go @@ -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 { diff --git a/setup.go b/setup.go index 51554f3..709fb54 100644 --- a/setup.go +++ b/setup.go @@ -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 }