Rework of the memory manager. No longer based on pages, but on bigger go byte ranges

This commit is contained in:
Ivan Izaguirre 2019-05-16 22:51:04 +02:00
parent 51c7a8cb57
commit c4f7a7e709
13 changed files with 155 additions and 312 deletions

View File

@ -21,27 +21,17 @@ type ansiConsoleFrontend struct {
apple2 *Apple2 apple2 *Apple2
keyChannel chan uint8 keyChannel chan uint8
extraLineFeeds chan int extraLineFeeds chan int
textUpdated bool
stdinKeyboard bool stdinKeyboard bool
lastContent string
} }
func newAnsiConsoleFrontend(a *Apple2, stdinKeyboard bool) *ansiConsoleFrontend { func newAnsiConsoleFrontend(a *Apple2, stdinKeyboard bool) *ansiConsoleFrontend {
var fe ansiConsoleFrontend var fe ansiConsoleFrontend
fe.apple2 = a fe.apple2 = a
fe.stdinKeyboard = stdinKeyboard fe.stdinKeyboard = stdinKeyboard
fe.subscribeToTextPages()
return &fe return &fe
} }
func (fe *ansiConsoleFrontend) subscribeToTextPages() {
observer := func(_ uint8, _ bool) {
fe.textUpdated = true
}
for i := 0x04; i < 0x08; i++ {
fe.apple2.mmu.physicalMainRAM[i].observer = observer
}
}
const refreshDelayMs = 100 const refreshDelayMs = 100
func (fe *ansiConsoleFrontend) GetKey(strobed bool) (key uint8, ok bool) { func (fe *ansiConsoleFrontend) GetKey(strobed bool) (key uint8, ok bool) {
@ -85,101 +75,53 @@ func (fe *ansiConsoleFrontend) GetKey(strobed bool) (key uint8, ok bool) {
return return
} }
func ansiCursorUp(steps int) { func ansiCursorUp(steps int) string {
fmt.Printf("\033[%vA", steps) return fmt.Sprintf("\033[%vA", steps)
}
func (fe *ansiConsoleFrontend) textModeGoRoutineFast() {
fe.extraLineFeeds = make(chan int, 100)
fmt.Printf(strings.Repeat("\n", 26))
for {
if fe.textUpdated {
fe.textUpdated = false
// Go up
ansiCursorUp(26)
done := false
for !done {
select {
case lineFeeds := <-fe.extraLineFeeds:
ansiCursorUp(lineFeeds)
default:
done = true
}
}
fmt.Println(strings.Repeat("#", 44))
// See "Understand the Apple II", page 5-10
// http://www.applelogic.org/files/UNDERSTANDINGTHEAII.pdf
isAltText := fe.apple2.isApple2e && fe.apple2.io.isSoftSwitchActive(ioFlagAltChar)
var i, j, h, c uint8
// Top, middle and botton screen
for i = 0; i < 120; i = i + 40 {
// Memory pages
for j = 0x04; j < 0x08; j++ {
p := fe.apple2.mmu.physicalMainRAM[j]
// The two half pages
for _, h = range []uint8{0, 128} {
line := ""
for c = i + h; c < i+h+40; c++ {
line += textMemoryByteToString(p.internalPeek(c), isAltText)
}
fmt.Printf("# %v #\n", line)
}
}
}
fmt.Println(strings.Repeat("#", 44))
if fe.stdinKeyboard {
fmt.Print("\033[KLine: ")
}
}
time.Sleep(refreshDelayMs * time.Millisecond)
}
} }
func (fe *ansiConsoleFrontend) textModeGoRoutine() { func (fe *ansiConsoleFrontend) textModeGoRoutine() {
fe.extraLineFeeds = make(chan int, 100) fe.extraLineFeeds = make(chan int, 100)
fmt.Printf(strings.Repeat("\n", 26)) fmt.Printf(strings.Repeat("\n", textLines+3))
for { for {
if fe.textUpdated { // Go up
fe.textUpdated = false content := ansiCursorUp(textLines + 3)
// Go up done := false
ansiCursorUp(26) for !done {
done := false select {
for !done { case lineFeeds := <-fe.extraLineFeeds:
select { content += ansiCursorUp(lineFeeds)
case lineFeeds := <-fe.extraLineFeeds: default:
ansiCursorUp(lineFeeds) done = true
default:
done = true
}
} }
}
pageIndex := 0 content += "\n"
if fe.apple2.io.isSoftSwitchActive(ioFlagSecondPage) { content += fmt.Sprintln(strings.Repeat("#", textColumns+4))
pageIndex = 1
pageIndex := 0
if fe.apple2.io.isSoftSwitchActive(ioFlagSecondPage) {
pageIndex = 1
}
isAltText := fe.apple2.isApple2e && fe.apple2.io.isSoftSwitchActive(ioFlagAltChar)
for l := 0; l < textLines; l++ {
line := ""
for c := 0; c < textColumns; c++ {
char := getTextChar(fe.apple2, c, l, pageIndex)
line += textMemoryByteToString(char, isAltText)
} }
isAltText := fe.apple2.isApple2e && fe.apple2.io.isSoftSwitchActive(ioFlagAltChar) content += fmt.Sprintf("# %v #\n", line)
}
fmt.Println(strings.Repeat("#", 44)) content += fmt.Sprintln(strings.Repeat("#", textColumns+4))
for line := 0; line < 24; line++ { if fe.stdinKeyboard {
text := "" content += "\033[KLine: "
for col := 0; col < 40; col++ { }
value := getTextChar(fe.apple2, col, line, pageIndex)
text += textMemoryByteToString(value, isAltText)
}
fmt.Printf("# %v #\n", text)
}
fmt.Println(strings.Repeat("#", 44)) if content != fe.lastContent {
if fe.stdinKeyboard { fmt.Print(content)
fmt.Print("\033[KLine: ") fe.lastContent = content
}
//saveSnapshot(fe.apple2)
} }
time.Sleep(refreshDelayMs * time.Millisecond) time.Sleep(refreshDelayMs * time.Millisecond)
} }

View File

@ -3,7 +3,6 @@ package apple2
import ( import (
"fmt" "fmt"
"go6502/core6502" "go6502/core6502"
"io/ioutil"
"time" "time"
) )
@ -36,11 +35,10 @@ func NewApple2(romFile string, charRomFile string, clockMhz float64,
var a Apple2 var a Apple2
a.mmu = newMemoryManager(&a) a.mmu = newMemoryManager(&a)
a.cpu = core6502.NewNMOS6502(a.mmu) a.cpu = core6502.NewNMOS6502(a.mmu)
a.loadRom(romFile) a.mmu.loadRom(romFile)
if charRomFile != "" { if charRomFile != "" {
a.cg = NewCharacterGenerator(charRomFile) a.cg = NewCharacterGenerator(charRomFile)
} }
a.mmu.resetRomPaging()
a.commandChannel = make(chan int, 100) a.commandChannel = make(chan int, 100)
a.isColor = isColor a.isColor = isColor
a.fastMode = fastMode a.fastMode = fastMode
@ -182,32 +180,3 @@ func (a *Apple2) releaseFastMode() {
a.fastRequestsCounter-- a.fastRequestsCounter--
} }
} }
func (a *Apple2) loadRom(filename string) {
bytes, err := ioutil.ReadFile(filename)
if err != nil {
panic(err)
}
size := len(bytes)
if size != apple2RomSize && size != apple2eRomSize {
panic("Rom size not supported")
}
romStart := 0
if size == apple2eRomSize {
// The extra 4kb ROM is first in the rom file.
// It starts with 256 unused bytes not mapped to 0xc000.
a.isApple2e = true
extraRomSize := apple2eRomSize - apple2RomSize
a.mmu.physicalROMe = make([]romPage, extraRomSize>>8)
for i := 0; i < extraRomSize; i++ {
a.mmu.physicalROMe[i>>8].burn(uint8(i), bytes[i])
}
romStart = extraRomSize
}
a.mmu.physicalROM = make([]romPage, apple2RomSize>>8)
for i := 0; i < apple2RomSize; i++ {
a.mmu.physicalROM[i>>8].burn(uint8(i), bytes[i+romStart])
}
}

View File

@ -2,7 +2,7 @@ package apple2
type cardBase struct { type cardBase struct {
a *Apple2 a *Apple2
rom []memoryPage rom *memoryRange
slot int slot int
ssr [16]softSwitchR ssr [16]softSwitchR
ssw [16]softSwitchW ssw [16]softSwitchW
@ -11,8 +11,9 @@ type cardBase struct {
func (c *cardBase) insert(a *Apple2, slot int) { func (c *cardBase) insert(a *Apple2, slot int) {
c.a = a c.a = a
c.slot = slot c.slot = slot
if slot != 0 && c.rom[0] != nil { if slot != 0 && c.rom != nil {
a.mmu.setPage(uint8(0xC0+slot), c.rom[0]) c.rom.base = uint16(0xC000 + slot*0x100)
a.mmu.setPage(uint8(0xC0+slot), c.rom)
} }
for i := 0; i < 0x10; i++ { for i := 0; i < 0x10; i++ {

View File

@ -30,7 +30,7 @@ type cardDisk2Drive struct {
func newCardDisk2(filename string) *cardDisk2 { func newCardDisk2(filename string) *cardDisk2 {
var c cardDisk2 var c cardDisk2
c.rom = loadCardRom(filename) c.rom = newMemoryRange(0, loadCardRom(filename))
// Phase control soft switches // Phase control soft switches
// Lazy emulation. It only checks for phases on and move the head // Lazy emulation. It only checks for phases on and move the head
@ -137,29 +137,12 @@ func newCardDisk2(filename string) *cardDisk2 {
return &c return &c
} }
func loadCardRom(filename string) []memoryPage { func loadCardRom(filename string) []uint8 {
bytes, err := ioutil.ReadFile(filename) data, err := ioutil.ReadFile(filename)
if err != nil { if err != nil {
panic(err) panic(err)
} }
return data
size := len(bytes)
pages := size / 256
if (size % 256) > 0 {
pages++
}
rom := make([]romPage, pages)
for i := 0; i < size; i++ {
rom[i>>8].burn(uint8(i), bytes[i])
}
memPages := make([]memoryPage, pages)
for i := range rom {
memPages[i] = &rom[i]
}
return memPages
} }
func (d *cardDisk2Drive) insertDiskette(dt *diskette16sector) { func (d *cardDisk2Drive) insertDiskette(dt *diskette16sector) {

View File

@ -1,6 +1,7 @@
package apple2 package apple2
import ( import (
"io/ioutil"
"os" "os"
) )
@ -33,41 +34,25 @@ func (d *diskette16sector) read(track int, position int) (value uint8, newPositi
func loadDisquette(filename string) *diskette16sector { func loadDisquette(filename string) *diskette16sector {
var d diskette16sector var d diskette16sector
f, err := os.Open(filename) data, err := ioutil.ReadFile(filename)
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer f.Close() size := len(data)
stats, statsErr := f.Stat()
if statsErr != nil {
panic(err)
}
size := stats.Size()
if size == nibImageSize { if size == nibImageSize {
// Load file already in nib format // Load file already in nib format
for i := 0; i < numberOfTracks; i++ { for i := 0; i < numberOfTracks; i++ {
d.track[i] = make([]byte, nibBytesPerTrack) d.track[i] = data[nibBytesPerTrack*i : nibBytesPerTrack*(i+1)]
n, err := f.Read(d.track[i])
if err != nil || n != nibBytesPerTrack {
panic("Error loading file")
}
} }
} else if size == dskImageSize { } else if size == dskImageSize {
// Load file in dsk format
data := make([]byte, dskImageSize)
n, err := f.Read(data)
if err != nil || n != dskImageSize {
panic("Error loading file")
}
// Convert to nib // Convert to nib
for i := 0; i < numberOfTracks; i++ { for i := 0; i < numberOfTracks; i++ {
trackData := data[i*bytesPerTrack : (i+1)*bytesPerTrack] trackData := data[i*bytesPerTrack : (i+1)*bytesPerTrack]
d.track[i] = nibEncodeTrack(trackData, defaultVolumeTag, byte(i)) d.track[i] = nibEncodeTrack(trackData, defaultVolumeTag, byte(i))
} }
} else { } else {
panic("Disk size with nib format has to be 232960 bytes") panic("Invalid disk size")
} }
return &d return &d

View File

@ -80,32 +80,26 @@ func (p *ioC0Page) setSpeakerProvider(s SpeakerProvider) {
p.speaker = s p.speaker = s
} }
func (p *ioC0Page) Peek(address uint8) uint8 { func (p *ioC0Page) peek(address uint16) uint8 {
//fmt.Printf("Peek on $C0%02x ", address) //fmt.Printf("Peek on $C0%02x ", address)
ss := p.softSwitchesR[address] pageAddress := uint8(address)
ss := p.softSwitchesR[pageAddress]
if ss == nil { if ss == nil {
if p.apple2.panicSS { if p.apple2.panicSS {
panic(fmt.Sprintf("Unknown softswitch on read to 0xC0%02x", address)) panic(fmt.Sprintf("Unknown softswitch on read to 0xC0%02x", pageAddress))
} }
return 0 return 0
} }
return ss(p) return ss(p)
} }
func (p *ioC0Page) internalPeek(address uint8) uint8 { func (p *ioC0Page) poke(address uint16, value uint8) {
return 0
}
func (p *ioC0Page) all() []uint8 {
return nil
}
func (p *ioC0Page) Poke(address uint8, value uint8) {
//fmt.Printf("Poke on $C0%02x with %02x ", address, value) //fmt.Printf("Poke on $C0%02x with %02x ", address, value)
ss := p.softSwitchesW[address] pageAddress := uint8(address)
ss := p.softSwitchesW[pageAddress]
if ss == nil { if ss == nil {
if p.apple2.panicSS { if p.apple2.panicSS {
panic(fmt.Sprintf("Unknown softswitch on write to 0xC0%02x", address)) panic(fmt.Sprintf("Unknown softswitch on write to 0xC0%02x", pageAddress))
} }
return return
} }

View File

@ -1,26 +1,25 @@
package apple2 package apple2
import "io/ioutil"
// See https://fabiensanglard.net/fd_proxy/prince_of_persia/Inside%20the%20Apple%20IIe.pdf // See https://fabiensanglard.net/fd_proxy/prince_of_persia/Inside%20the%20Apple%20IIe.pdf
// See https://i.stack.imgur.com/yn21s.gif // See https://i.stack.imgur.com/yn21s.gif
type memoryManager struct { type memoryManager struct {
apple2 *Apple2 apple2 *Apple2
// Map of assigned pages // Map of assigned pages
activeMemory [256]memoryPage activeMemoryRead [256]memoryHandler
activeMemoryWrite [256]memoryHandler
// Pages prepared to be paged in and out // Pages prepared to be paged in and out
physicalMainRAM []ramPage // 0x0000 to 0xbfff, Up to 48 Kb physicalMainRAM *memoryRange // 0x0000 to 0xbfff, Up to 48 Kb
physicalROM []romPage // 0xd000 to 0xffff, 12 Kb physicalROM *memoryRange // 0xd000 to 0xffff, 12 Kb
physicalROMe []romPage // 0xc000 to 0xcfff, Zero or 4bk in the Apple2e physicalROMe *memoryRange // 0xc000 to 0xcfff, Zero or 4bk in the Apple2e
unassignedExpansionROM []unassignedPage // 0xc000 to 0xcfff
} }
// memoryPage is a data page of 256 bytes type memoryHandler interface {
type memoryPage interface { peek(uint16) uint8
Peek(uint8) uint8 poke(uint16, uint8)
Poke(uint8, uint8)
internalPeek(uint8) uint8
all() []uint8
} }
const ( const (
@ -34,18 +33,11 @@ func (mmu *memoryManager) Peek(address uint16) uint8 {
} }
hi := uint8(address >> 8) hi := uint8(address >> 8)
lo := uint8(address) mh := mmu.activeMemoryRead[hi]
return mmu.activeMemory[hi].Peek(lo) if mh == nil {
} return 0xf4 // Or some random number
}
func (mmu *memoryManager) internalPeek(address uint16) uint8 { return mh.peek(address)
hi := uint8(address >> 8)
lo := uint8(address)
return mmu.activeMemory[hi].internalPeek(lo)
}
func (mmu *memoryManager) internalPage(hi uint8) []uint8 {
return mmu.activeMemory[hi].all()
} }
// Poke sets the data at the given address // Poke sets the data at the given address
@ -54,15 +46,24 @@ func (mmu *memoryManager) Poke(address uint16, value uint8) {
mmu.resetSlotExpansionRoms() mmu.resetSlotExpansionRoms()
} }
hi := uint8(address >> 8) hi := uint8(address >> 8)
lo := uint8(address) mh := mmu.activeMemoryWrite[hi]
mmu.activeMemory[hi].Poke(lo, value) if mh == nil {
return
}
mh.poke(address, value)
} }
// SetPage assigns a MemoryPage implementation on the page given func (mmu *memoryManager) setPage(index uint8, mh memoryHandler) {
func (mmu *memoryManager) setPage(index uint8, page memoryPage) { mmu.setPageRead(index, mh)
//fmt.Printf("Assigning page 0x%02x type %s\n", index, reflect.TypeOf(page)) mmu.setPageWrite(index, mh)
mmu.activeMemory[index] = page }
func (mmu *memoryManager) setPageRead(index uint8, mh memoryHandler) {
mmu.activeMemoryRead[index] = mh
}
func (mmu *memoryManager) setPageWrite(index uint8, mh memoryHandler) {
mmu.activeMemoryWrite[index] = mh
} }
// When 0xcfff is accessed the card expansion rom is unassigned // When 0xcfff is accessed the card expansion rom is unassigned
@ -71,9 +72,8 @@ func (mmu *memoryManager) resetSlotExpansionRoms() {
// Ignore if the Apple2 shadow ROM is active // Ignore if the Apple2 shadow ROM is active
return return
} }
for i := 8; i < 16; i++ { for i := uint8(0xc8); i < 0xd0; i++ {
p := mmu.unassignedExpansionROM[i] mmu.setPage(i, nil)
mmu.setPage(uint8(i+0xc0), &p)
} }
} }
@ -82,25 +82,43 @@ func newMemoryManager(a *Apple2) *memoryManager {
mmu.apple2 = a mmu.apple2 = a
// Assign RAM from 0x0000 to 0xbfff, 48kb // Assign RAM from 0x0000 to 0xbfff, 48kb
mmu.physicalMainRAM = make([]ramPage, 0xc0) ram := make([]uint8, 0xc000)
for i := 0; i <= 0xbf; i++ { mmu.physicalMainRAM = newMemoryRange(0, ram)
mmu.setPage(uint8(i), &(mmu.physicalMainRAM[i])) for i := 0; i < 0xc000; i = i + 0x100 {
mmu.setPage(uint8(i>>8), mmu.physicalMainRAM)
} }
// Set the 0xc100 to 0xcfff as unasigned, 4kb. It wil be taken by slot cards.
mmu.unassignedExpansionROM = make([]unassignedPage, 0x10)
for i := 1; i < 0x10; i++ {
page := uint8(i + 0xc0)
p := &mmu.unassignedExpansionROM[i]
p.page = page
mmu.setPage(page, p)
}
return &mmu return &mmu
} }
func (mmu *memoryManager) loadRom(filename string) {
data, err := ioutil.ReadFile(filename)
if err != nil {
panic(err)
}
size := len(data)
if size != apple2RomSize && size != apple2eRomSize {
panic("Rom size not supported")
}
a := mmu.apple2
romStart := 0
if size == apple2eRomSize {
// The extra 4kb ROM is first in the rom file.
// It starts with 256 unused bytes not mapped to 0xc000.
a.isApple2e = true
extraRomSize := apple2eRomSize - apple2RomSize
a.mmu.physicalROMe = newMemoryRange(0xc000, data[0:extraRomSize])
romStart = extraRomSize
}
a.mmu.physicalROM = newMemoryRange(0xd000, data[romStart:])
mmu.resetRomPaging()
}
func (mmu *memoryManager) resetRomPaging() { func (mmu *memoryManager) resetRomPaging() {
// Assign the first 12kb of ROM from 0xd000 to 0xfff // Assign the first 12kb of ROM from 0xd000 to 0xfff
for i := 0xd0; i <= 0xff; i++ { for i := 0x0000; i < 0x3000; i = i + 0x100 {
mmu.setPage(uint8(i), &(mmu.physicalROM[i-0xd0])) mmu.setPageRead(uint8(0xd0+(i>>8)), mmu.physicalROM)
} }
} }

25
apple2/memoryRange.go Normal file
View File

@ -0,0 +1,25 @@
package apple2
type memoryRange struct {
base uint16
data []uint8
}
func newMemoryRange(base uint16, data []uint8) *memoryRange {
var m memoryRange
m.base = base
m.data = data
return &m
}
func (m *memoryRange) peek(address uint16) uint8 {
return m.data[address-m.base]
}
func (m *memoryRange) poke(address uint16, value uint8) {
m.data[address-m.base] = value
}
func (m *memoryRange) subRange(a, b uint16) []uint8 {
return m.data[a-m.base : b-m.base]
}

View File

@ -1,46 +0,0 @@
package apple2
type rxmPage struct {
data [256]uint8
observer func(address uint8, isWrite bool)
}
type ramPage struct {
rxmPage
}
type romPage struct {
rxmPage
}
func (p *rxmPage) Peek(address uint8) uint8 {
p.touch(address, false)
return p.data[address]
}
func (p *rxmPage) internalPeek(address uint8) uint8 {
return p.data[address]
}
func (p *rxmPage) all() []uint8 {
return p.data[:]
}
func (p *rxmPage) Poke(address uint8, value uint8) {
p.touch(address, true)
p.data[address] = value
}
func (p *rxmPage) touch(address uint8, isWrite bool) {
if p.observer != nil {
p.observer(address, isWrite)
}
}
func (p *romPage) Poke(address uint8, value uint8) {
// Do nothing
}
func (p *romPage) burn(address uint8, value uint8) {
p.data[address] = value
}

View File

@ -30,11 +30,7 @@ func getHiResLine(a *Apple2, line int, page int) []uint8 {
} }
address += getHiResLineOffset(line) address += getHiResLineOffset(line)
hi := uint8(address >> 8) return a.mmu.physicalMainRAM.subRange(address, address+40)
lo := uint8(address)
memPage := a.mmu.internalPage(hi)
return memPage[lo : lo+40]
} }
func snapshotHiResModeMonoShift(a *Apple2, page int, mixedMode bool, light color.Color) *image.RGBA { func snapshotHiResModeMonoShift(a *Apple2, page int, mixedMode bool, light color.Color) *image.RGBA {

View File

@ -31,7 +31,7 @@ func getTextChar(a *Apple2, col int, line int, page int) uint8 {
address = textPage2Address address = textPage2Address
} }
address += getTextCharOffset(col, line) address += getTextCharOffset(col, line)
return a.mmu.internalPeek(address) return a.mmu.physicalMainRAM.subRange(address, address+1)[0]
} }
func snapshotTextMode(a *Apple2, page int, mixMode bool, light color.Color) *image.RGBA { func snapshotTextMode(a *Apple2, page int, mixMode bool, light color.Color) *image.RGBA {

View File

@ -46,8 +46,8 @@ func getSoftSwitchExt(ioFlag uint8, dstValue uint8, action softSwitchExtAction)
func softSwitchIntCxRomOn(io *ioC0Page) { func softSwitchIntCxRomOn(io *ioC0Page) {
mmu := io.apple2.mmu mmu := io.apple2.mmu
for i := uint8(1); i < 16; i++ { for i := 0x100; i < 0x1000; i = i + 0x100 {
mmu.setPage(uint8(0xc0+i), &mmu.physicalROMe[i]) mmu.setPage(uint8(i>>8), mmu.physicalROMe)
} }
} }
@ -55,7 +55,7 @@ func softSwitchIntCxRomOff(io *ioC0Page) {
// TODO restore all the ROM from the slot for 0xc1 to 0xc7 // TODO restore all the ROM from the slot for 0xc1 to 0xc7
mmu := io.apple2.mmu mmu := io.apple2.mmu
for i := 1; i < 16; i++ { for i := 1; i < 16; i++ {
mmu.setPage(uint8(0xc0+i), &mmu.unassignedExpansionROM[i]) mmu.setPage(uint8(0xc0+i), nil)
} }
} }
@ -65,13 +65,13 @@ func softSwitchSlotC3RomOn(io *ioC0Page) {
} }
// TODO restore the slot 3 ROM // TODO restore the slot 3 ROM
mmu := io.apple2.mmu mmu := io.apple2.mmu
mmu.setPage(0xC3, &mmu.unassignedExpansionROM[3]) mmu.setPage(0xC3, nil)
} }
func softSwitchSlotC3RomOff(io *ioC0Page) { func softSwitchSlotC3RomOff(io *ioC0Page) {
if io.isSoftSwitchActive(ioFlagIntCxRom) { if io.isSoftSwitchActive(ioFlagIntCxRom) {
return // Ignore if allt the Apple2 shadow ROM is active return // Ignore if alt the Apple2 shadow ROM is active
} }
mmu := io.apple2.mmu mmu := io.apple2.mmu
mmu.setPage(0xC3, &mmu.physicalROMe[3]) mmu.setPageRead(0xC3, mmu.physicalROMe)
} }

View File

@ -1,24 +0,0 @@
package apple2
type unassignedPage struct {
page uint8
}
func (p *unassignedPage) Peek(address uint8) uint8 {
//fmt.Printf("Read on address 0x%02x%02x\n", p.page, address)
//panic(address)
return 0xdd
}
func (p *unassignedPage) internalPeek(address uint8) uint8 {
return 0xdd
}
func (p *unassignedPage) all() []uint8 {
return nil
}
func (p *unassignedPage) Poke(address uint8, value uint8) {
//fmt.Printf("Write on address 0x%02x%02x\n", p.page, address)
//panic(address)
}