From 3e5e10b8ddb03e817c9d90a2d98330ca325e2fe2 Mon Sep 17 00:00:00 2001 From: Ivan Izaguirre Date: Sun, 25 Oct 2020 00:22:52 +0200 Subject: [PATCH] Experimental RomX --- apple2.go | 7 +++ apple2Setup.go | 6 ++ apple2main.go | 1 + core6502/execute.go | 5 ++ frontend/a2fyne/main.go | 2 +- noSlotClockDS1216.go | 1 - romX.go | 127 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 romX.go diff --git a/apple2.go b/apple2.go index 70ea0bd..91e240c 100644 --- a/apple2.go +++ b/apple2.go @@ -50,7 +50,14 @@ func (a *Apple2) Run() { // Run a 6502 step if !a.paused { for i := 0; i < cpuSpinLoops; i++ { + // Conditional tracing + //pc, _ := a.cpu.GetPCAndSP() + //a.cpu.SetTrace(pc >= 0x300 && pc <= 0x400) + + // Execution a.cpu.ExecuteInstruction() + + // Special tracing a.executionTrace() } } else { diff --git a/apple2Setup.go b/apple2Setup.go index 3722ae8..1b1e2c6 100644 --- a/apple2Setup.go +++ b/apple2Setup.go @@ -171,6 +171,12 @@ func (a *Apple2) AddNoSlotClock() { a.mmu.physicalROM[0] = nsc } +// AddRomX inserts a RomX. It intercepts all memory accesses +func (a *Apple2) AddRomX() { + rx := newRomX(a, a.mmu) + a.cpu.SetMemory(rx) +} + // AddNoSlotClockInCard inserts a DS1215 no slot clock under a card ROM func (a *Apple2) AddNoSlotClockInCard(slot int) error { cardRom := a.mmu.cardsROM[slot] diff --git a/apple2main.go b/apple2main.go index df1722c..784a634 100644 --- a/apple2main.go +++ b/apple2main.go @@ -288,6 +288,7 @@ func MainApple() *Apple2 { } + // a.AddRomX() // a.AddCardInOut(2) // a.AddCardLogger(4) diff --git a/core6502/execute.go b/core6502/execute.go index 25c5071..cef1c12 100644 --- a/core6502/execute.go +++ b/core6502/execute.go @@ -103,6 +103,11 @@ func (s *State) GetTrace() bool { return s.trace } +// SetMemory changes the memory provider +func (s *State) SetMemory(mem Memory) { + s.mem = mem +} + // GetPCAndSP returns the current program counter and stack pointer. Used to trace MLI calls func (s *State) GetPCAndSP() (uint16, uint8) { return s.reg.getPC(), s.reg.getSP() diff --git a/frontend/a2fyne/main.go b/frontend/a2fyne/main.go index 5b94391..507d1b0 100644 --- a/frontend/a2fyne/main.go +++ b/frontend/a2fyne/main.go @@ -55,7 +55,7 @@ func fyneRun(s *state) { toolbar := buildToolbar(s) display := canvas.NewImageFromImage(nil) display.ScaleMode = canvas.ImageScalePixels // Looks worst but loads less. - display.SetMinSize(fyne.NewSize(280*2, 192*2)) + display.SetMinSize(fyne.NewSize(280*2*2, 192*2*2)) container := fyne.NewContainerWithLayout( layout.NewBorderLayout(nil, toolbar, nil, s.devices.w), diff --git a/noSlotClockDS1216.go b/noSlotClockDS1216.go index 4b3bc8c..1f948cf 100644 --- a/noSlotClockDS1216.go +++ b/noSlotClockDS1216.go @@ -135,7 +135,6 @@ func (nsc *noSlotClockDS1216) peek(address uint16) uint8 { } func (nsc *noSlotClockDS1216) poke(address uint16, value uint8) { - // This should not happen as we are dealing with ROM nsc.memory.poke(address, value) } diff --git a/romX.go b/romX.go new file mode 100644 index 0000000..e00354a --- /dev/null +++ b/romX.go @@ -0,0 +1,127 @@ +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 +}