From cb21a1fefc7e5c58f80283e949c3932e8de8dabb Mon Sep 17 00:00:00 2001 From: Ivan Izaguirre Date: Fri, 17 May 2019 23:28:20 +0200 Subject: [PATCH] Support for state snapshots. F7 to save, F8 to load --- apple2/apple2.go | 154 ++++++++++----------------------------- apple2/apple2Setup.go | 91 +++++++++++++++++++++++ apple2/cardDisk2.go | 34 ++++++++- apple2/cardLanguage.go | 25 +++++++ apple2/cardSaturn.go | 52 ++++++++++--- apple2/ioC0Page.go | 10 +++ apple2/memoryManager.go | 43 ++++++++--- apple2/memoryRange.go | 15 ++++ apple2/persistance.go | 66 +++++++++++++++++ apple2/softSwitches2e.go | 2 + apple2sdl/sdlKeyboard.go | 4 + core6502/execute.go | 18 ++++- core6502/registers.go | 13 ++-- main.go | 21 +++++- 14 files changed, 399 insertions(+), 149 deletions(-) create mode 100644 apple2/apple2Setup.go create mode 100644 apple2/persistance.go diff --git a/apple2/apple2.go b/apple2/apple2.go index 62e6b15..fd1f367 100644 --- a/apple2/apple2.go +++ b/apple2/apple2.go @@ -12,15 +12,14 @@ type Apple2 struct { mmu *memoryManager io *ioC0Page cg *CharacterGenerator - cards []cardBase isApple2e bool panicSS bool - activeSlot int // Slot that has the addressing 0xc800 to 0ccfff commandChannel chan int - cycleDurationNs float64 // Inverse of the cpu clock in Ghz + cycleDurationNs float64 // Current speed. Inverse of the cpu clock in Ghz isColor bool fastMode bool fastRequestsCounter int + persistance *persistance } const ( @@ -29,114 +28,6 @@ const ( cpuClockEuroMhz = 14.238 / 14 ) -// NewApple2 instantiates an apple2 -func NewApple2(romFile string, charRomFile string, clockMhz float64, - isColor bool, fastMode bool, panicSS bool) *Apple2 { - var a Apple2 - a.mmu = newMemoryManager(&a) - a.cpu = core6502.NewNMOS6502(a.mmu) - a.mmu.loadRom(romFile) - if charRomFile != "" { - a.cg = NewCharacterGenerator(charRomFile) - } - a.commandChannel = make(chan int, 100) - a.isColor = isColor - a.fastMode = fastMode - a.panicSS = panicSS - - if clockMhz <= 0 { - // Full speed - a.cycleDurationNs = 0 - } else { - a.cycleDurationNs = 1000.0 / clockMhz - } - - // Set the io in 0xc000 - a.io = newIoC0Page(&a) - a.mmu.setPages(0xc0, 0xc0, a.io) - - return &a -} - -// AddDisk2 insterts a DiskII controller -func (a *Apple2) AddDisk2(slot int, diskRomFile string, diskImage string) { - d := newCardDisk2(diskRomFile) - d.cardBase.insert(a, slot) - - if diskImage != "" { - diskette := loadDisquette(diskImage) - //diskette.saveNib(diskImage + "bak") - d.drive[0].insertDiskette(diskette) - } -} - -// AddLanguageCard inserts a 16Kb card -func (a *Apple2) AddLanguageCard(slot int) { - d := newCardLanguage() - d.cardBase.insert(a, slot) - d.applyState() -} - -// AddSaturnCard inserts a 128Kb card -func (a *Apple2) AddSaturnCard(slot int) { - d := newCardSaturn() - d.cardBase.insert(a, slot) - d.applyState() -} - -// ConfigureStdConsole uses stdin and stdout to interface with the Apple2 -func (a *Apple2) ConfigureStdConsole(stdinKeyboard bool, stdoutScreen bool) { - if !stdinKeyboard && !stdoutScreen { - return - } - - // Init frontend - fe := newAnsiConsoleFrontend(a, stdinKeyboard) - if stdinKeyboard { - a.io.setKeyboardProvider(fe) - } - if stdoutScreen { - go fe.textModeGoRoutine() - } -} - -// SetKeyboardProvider attaches an external keyboard provider -func (a *Apple2) SetKeyboardProvider(kb KeyboardProvider) { - a.io.setKeyboardProvider(kb) -} - -// SetSpeakerProvider attaches an external keyboard provider -func (a *Apple2) SetSpeakerProvider(s SpeakerProvider) { - a.io.setSpeakerProvider(s) -} - -const ( - // CommandToggleSpeed toggles cpu speed between full speed and actual Apple II speed - CommandToggleSpeed = iota + 1 - // CommandToggleColor toggles between NTSC color TV and Green phospor monitor - CommandToggleColor -) - -// SendCommand enqueues a command to the emulator thread -func (a *Apple2) SendCommand(command int) { - a.commandChannel <- command -} - -func (a *Apple2) executeCommand(command int) { - switch command { - case CommandToggleSpeed: - if a.cycleDurationNs == 0 { - fmt.Println("Slow") - a.cycleDurationNs = 1000.0 / CpuClockMhz - } else { - fmt.Println("Fast") - a.cycleDurationNs = 0 - } - case CommandToggleColor: - a.isColor = !a.isColor - } -} - const maxWaitDuration = 100 * time.Millisecond // Run starts the Apple2 emulation @@ -164,8 +55,8 @@ func (a *Apple2) Run(log bool) { clockDuration := time.Since(referenceTime) simulatedDuration := time.Duration(float64(a.cpu.GetCycles()) * a.cycleDurationNs) waitDuration := simulatedDuration - clockDuration - if waitDuration > maxWaitDuration { - // We have to wait too long. Let's fast forward + if waitDuration > maxWaitDuration || -waitDuration > maxWaitDuration { + // We have to wait too long or are too much behind. Let's fast forward referenceTime = referenceTime.Add(-waitDuration) waitDuration = 0 } @@ -176,12 +67,43 @@ func (a *Apple2) Run(log bool) { } } -// LoadRom loads a binary file to the top of the memory. const ( - apple2RomSize = 12 * 1024 - apple2eRomSize = 16 * 1024 + // CommandToggleSpeed toggles cpu speed between full speed and actual Apple II speed + CommandToggleSpeed = iota + 1 + // CommandToggleColor toggles between NTSC color TV and Green phospor monitor + CommandToggleColor + // CommandSaveState stores the state to file + CommandSaveState + // CommandLoadState reload the last state + CommandLoadState ) +// SendCommand enqueues a command to the emulator thread +func (a *Apple2) SendCommand(command int) { + a.commandChannel <- command +} + +func (a *Apple2) executeCommand(command int) { + switch command { + case CommandToggleSpeed: + if a.cycleDurationNs == 0 { + fmt.Println("Slow") + a.cycleDurationNs = 1000.0 / CpuClockMhz + } else { + fmt.Println("Fast") + a.cycleDurationNs = 0 + } + case CommandToggleColor: + a.isColor = !a.isColor + case CommandSaveState: + fmt.Println("Saving state") + a.persistance.save("apple2.state") + case CommandLoadState: + fmt.Println("Loading state") + a.persistance.load("apple2.state") + } +} + func (a *Apple2) requestFastMode() { // Note: if the fastMode is shorter than maxWaitDuration, there won't be any gain. if a.fastMode { diff --git a/apple2/apple2Setup.go b/apple2/apple2Setup.go new file mode 100644 index 0000000..b477cb3 --- /dev/null +++ b/apple2/apple2Setup.go @@ -0,0 +1,91 @@ +package apple2 + +import ( + "go6502/core6502" +) + +// NewApple2 instantiates an apple2 +func NewApple2(romFile string, charRomFile string, clockMhz float64, + isColor bool, fastMode bool, panicSS bool) *Apple2 { + var a Apple2 + a.persistance = newPersistance(&a) + a.mmu = newMemoryManager(&a, romFile) + a.persistance.register(a.mmu) + a.cpu = core6502.NewNMOS6502(a.mmu) + if charRomFile != "" { + a.cg = NewCharacterGenerator(charRomFile) + } + a.commandChannel = make(chan int, 100) + a.isColor = isColor + a.fastMode = fastMode + a.panicSS = panicSS + + if clockMhz <= 0 { + // Full speed + a.cycleDurationNs = 0 + } else { + a.cycleDurationNs = 1000.0 / clockMhz + } + + // Set the io in 0xc000 + a.io = newIoC0Page(&a) + a.persistance.register(a.io) + a.mmu.setPages(0xc0, 0xc0, a.io) + + return &a +} + +// AddDisk2 insterts a DiskII controller +func (a *Apple2) AddDisk2(slot int, diskRomFile string, diskImage string) { + d := newCardDisk2(diskRomFile) + d.cardBase.insert(a, slot) + a.persistance.register(d) + + if diskImage != "" { + diskette := loadDisquette(diskImage) + //diskette.saveNib(diskImage + "bak") + d.drive[0].insertDiskette(diskette) + } +} + +// AddLanguageCard inserts a 16Kb card +func (a *Apple2) AddLanguageCard(slot int) { + d := newCardLanguage() + d.cardBase.insert(a, slot) + d.applyState() + a.persistance.register(d) +} + +// AddSaturnCard inserts a 128Kb card +func (a *Apple2) AddSaturnCard(slot int) { + d := newCardSaturn() + d.cardBase.insert(a, slot) + d.applyState() + a.persistance.register(d) +} + +// ConfigureStdConsole uses stdin and stdout to interface with the Apple2 +func (a *Apple2) ConfigureStdConsole(stdinKeyboard bool, stdoutScreen bool) { + if !stdinKeyboard && !stdoutScreen { + return + } + + // Init frontend + fe := newAnsiConsoleFrontend(a, stdinKeyboard) + if stdinKeyboard { + a.io.setKeyboardProvider(fe) + } + if stdoutScreen { + go fe.textModeGoRoutine() + } +} + +// SetKeyboardProvider attaches an external keyboard provider +func (a *Apple2) SetKeyboardProvider(kb KeyboardProvider) { + a.io.setKeyboardProvider(kb) +} + +// SetSpeakerProvider attaches an external keyboard provider +func (a *Apple2) SetSpeakerProvider(s SpeakerProvider) { + a.io.setSpeakerProvider(s) +} diff --git a/apple2/cardDisk2.go b/apple2/cardDisk2.go index fb29fb7..4f404be 100644 --- a/apple2/cardDisk2.go +++ b/apple2/cardDisk2.go @@ -1,6 +1,10 @@ package apple2 -import "io/ioutil" +import ( + "encoding/binary" + "io" + "io/ioutil" +) /* https://applesaucefdc.com/woz/reference2/ @@ -148,3 +152,31 @@ func loadCardRom(filename string) []uint8 { func (d *cardDisk2Drive) insertDiskette(dt *diskette16sector) { d.diskette = dt } + +func (c *cardDisk2) save(w io.Writer) { + binary.Write(w, binary.BigEndian, c.selected) + c.drive[0].save(w) + c.drive[1].save(w) +} + +func (c *cardDisk2) load(r io.Reader) { + binary.Read(r, binary.BigEndian, &c.selected) + c.drive[0].load(r) + c.drive[1].load(r) +} + +func (d *cardDisk2Drive) save(w io.Writer) { + binary.Write(w, binary.BigEndian, d.currentPhase) + binary.Write(w, binary.BigEndian, d.power) + binary.Write(w, binary.BigEndian, d.writeMode) + binary.Write(w, binary.BigEndian, d.halfTrack) + binary.Write(w, binary.BigEndian, d.position) +} + +func (d *cardDisk2Drive) load(r io.Reader) { + binary.Read(r, binary.BigEndian, &d.currentPhase) + binary.Read(r, binary.BigEndian, &d.power) + binary.Read(r, binary.BigEndian, &d.writeMode) + binary.Read(r, binary.BigEndian, &d.halfTrack) + binary.Read(r, binary.BigEndian, &d.position) +} diff --git a/apple2/cardLanguage.go b/apple2/cardLanguage.go index 87a11f9..02e011a 100644 --- a/apple2/cardLanguage.go +++ b/apple2/cardLanguage.go @@ -1,5 +1,10 @@ package apple2 +import ( + "encoding/binary" + "io" +) + /* Language card with 16 extra kb for the Apple ][ and ][+ Manual: http://www.applelogic.org/files/LANGCARDMAN.pdf @@ -118,3 +123,23 @@ func (c *cardLanguage) applyState() { } } + +func (c *cardLanguage) save(w io.Writer) { + binary.Write(w, binary.BigEndian, c.readState) + binary.Write(w, binary.BigEndian, c.writeState) + binary.Write(w, binary.BigEndian, c.activeBank) + c.ramBankA.save(w) + c.ramBankB.save(w) + c.ramUpper.save(w) +} + +func (c *cardLanguage) load(r io.Reader) { + binary.Read(r, binary.BigEndian, &c.readState) + binary.Read(r, binary.BigEndian, &c.writeState) + binary.Read(r, binary.BigEndian, &c.activeBank) + c.ramBankA.load(r) + c.ramBankB.load(r) + c.ramUpper.load(r) + + c.applyState() +} diff --git a/apple2/cardSaturn.go b/apple2/cardSaturn.go index 3ed7e73..03f08f3 100644 --- a/apple2/cardSaturn.go +++ b/apple2/cardSaturn.go @@ -1,5 +1,10 @@ package apple2 +import ( + "encoding/binary" + "io" +) + /* RAM card with 128Kb. It's like 8 language cards. @@ -14,9 +19,9 @@ type cardSaturn struct { writeState int activeBank int activeBlock int - ramBankA [8]*memoryRange // First 4kb to map in 0xD000-0xDFFF - ramBankB [8]*memoryRange // Second 4kb to map in 0xD000-0xDFFF - ramUpper [8]*memoryRange // Upper 8kb to map in 0xE000-0xFFFF + ramBankA [saturnBlocks]*memoryRange // First 4kb to map in 0xD000-0xDFFF + ramBankB [saturnBlocks]*memoryRange // Second 4kb to map in 0xD000-0xDFFF + ramUpper [saturnBlocks]*memoryRange // Upper 8kb to map in 0xE000-0xFFFF } const ( @@ -26,13 +31,17 @@ const ( saturnWriteEnabled = 2 ) +const ( + saturnBlocks = 8 +) + func newCardSaturn() *cardSaturn { var c cardSaturn c.readState = false c.writeState = lcWriteEnabled c.activeBank = 1 - for i := 0; i < 8; i++ { + for i := 0; i < saturnBlocks; i++ { c.ramBankA[i] = newMemoryRange(0xd000, make([]uint8, 0x1000)) c.ramBankB[i] = newMemoryRange(0xd000, make([]uint8, 0x1000)) c.ramUpper[i] = newMemoryRange(0xe000, make([]uint8, 0x2000)) @@ -102,13 +111,13 @@ func (c *cardSaturn) ssAction(ss int) { c.readState = true c.writeState++ case 12: - c.activeBlock = 0 + c.activeBlock = 4 case 13: - c.activeBlock = 1 + c.activeBlock = 5 case 14: - c.activeBlock = 2 + c.activeBlock = 6 case 15: - c.activeBlock = 3 + c.activeBlock = 7 } if c.writeState > lcWriteEnabled { @@ -142,5 +151,30 @@ func (c *cardSaturn) applyState() { } else { mmu.setPagesWrite(0xd0, 0xff, nil) } - +} + +func (c *cardSaturn) save(w io.Writer) { + for i := 0; i < saturnBlocks; i++ { + binary.Write(w, binary.BigEndian, c.readState) + binary.Write(w, binary.BigEndian, c.writeState) + binary.Write(w, binary.BigEndian, c.activeBank) + binary.Write(w, binary.BigEndian, c.activeBlock) + c.ramBankA[i].save(w) + c.ramBankB[i].save(w) + c.ramUpper[i].save(w) + } +} + +func (c *cardSaturn) load(r io.Reader) { + for i := 0; i < saturnBlocks; i++ { + binary.Read(r, binary.BigEndian, &c.readState) + binary.Read(r, binary.BigEndian, &c.writeState) + binary.Read(r, binary.BigEndian, &c.activeBank) + binary.Read(r, binary.BigEndian, &c.activeBlock) + c.ramBankA[i].load(r) + c.ramBankB[i].load(r) + c.ramUpper[i].load(r) + + c.applyState() + } } diff --git a/apple2/ioC0Page.go b/apple2/ioC0Page.go index cdce9e5..136ad54 100644 --- a/apple2/ioC0Page.go +++ b/apple2/ioC0Page.go @@ -1,7 +1,9 @@ package apple2 import ( + "encoding/binary" "fmt" + "io" ) type ioC0Page struct { @@ -47,6 +49,14 @@ func newIoC0Page(a *Apple2) *ioC0Page { return &io } +func (p *ioC0Page) save(w io.Writer) { + binary.Write(w, binary.BigEndian, p.softSwitchesData) +} + +func (p *ioC0Page) load(r io.Reader) { + binary.Read(r, binary.BigEndian, &p.softSwitchesData) +} + func (p *ioC0Page) addSoftSwitchRW(address uint8, ss softSwitchR) { p.addSoftSwitchR(address, ss) p.addSoftSwitchW(address, func(p *ioC0Page, _ uint8) { diff --git a/apple2/memoryManager.go b/apple2/memoryManager.go index 6884246..1d279b3 100644 --- a/apple2/memoryManager.go +++ b/apple2/memoryManager.go @@ -1,6 +1,7 @@ package apple2 import ( + "io" "io/ioutil" ) @@ -91,18 +92,35 @@ func (mmu *memoryManager) resetSlotExpansionRoms() { mmu.setPagesRead(0xc8, 0xcf, nil) } -func newMemoryManager(a *Apple2) *memoryManager { +func (mmu *memoryManager) resetRomPaging() { + // Assign the first 12kb of ROM from 0xd000 to 0xffff + mmu.setPagesRead(0xd0, 0xff, mmu.physicalROM) +} + +func (mmu *memoryManager) resetBaseRamPaging() { + // Assign the base RAM from 0x0000 to 0xbfff + mmu.setPages(0x00, 0xbf, mmu.physicalMainRAM) +} + +func newMemoryManager(a *Apple2, romFile string) *memoryManager { var mmu memoryManager mmu.apple2 = a - // Assign RAM from 0x0000 to 0xbfff, 48kb - ram := make([]uint8, 0xc000) + ram := make([]uint8, 0xc000) // Reserve 48kb mmu.physicalMainRAM = newMemoryRange(0, ram) - mmu.setPages(0x00, 0xc0, mmu.physicalMainRAM) + + mmu.loadRom(romFile) + mmu.resetBaseRamPaging() + mmu.resetRomPaging() return &mmu } +const ( + apple2RomSize = 12 * 1024 + apple2eRomSize = 16 * 1024 +) + func (mmu *memoryManager) loadRom(filename string) { data, err := ioutil.ReadFile(filename) if err != nil { @@ -120,17 +138,18 @@ func (mmu *memoryManager) loadRom(filename string) { // It starts with 256 unused bytes not mapped to 0xc000. a.isApple2e = true extraRomSize := apple2eRomSize - apple2RomSize - a.mmu.physicalROMe = newMemoryRange(0xc000, data[0:extraRomSize]) + mmu.physicalROMe = newMemoryRange(0xc000, data[0:extraRomSize]) romStart = extraRomSize } - a.mmu.physicalROM = newMemoryRange(0xd000, data[romStart:]) - mmu.resetRomPaging() + mmu.physicalROM = newMemoryRange(0xd000, data[romStart:]) } -func (mmu *memoryManager) resetRomPaging() { - // Assign the first 12kb of ROM from 0xd000 to 0xfff - for i := 0x0000; i < 0x3000; i = i + 0x100 { - mmu.setPagesRead(0xd0, 0xff, mmu.physicalROM) - } +func (mmu *memoryManager) save(w io.Writer) { + mmu.physicalMainRAM.save(w) +} + +func (mmu *memoryManager) load(r io.Reader) { + mmu.physicalMainRAM.load(r) + mmu.resetBaseRamPaging() } diff --git a/apple2/memoryRange.go b/apple2/memoryRange.go index 95285e1..c8f24eb 100644 --- a/apple2/memoryRange.go +++ b/apple2/memoryRange.go @@ -1,5 +1,10 @@ package apple2 +import ( + "encoding/binary" + "io" +) + type memoryRange struct { base uint16 data []uint8 @@ -23,3 +28,13 @@ func (m *memoryRange) poke(address uint16, value uint8) { func (m *memoryRange) subRange(a, b uint16) []uint8 { return m.data[a-m.base : b-m.base] } + +func (m *memoryRange) save(w io.Writer) { + binary.Write(w, binary.BigEndian, m.base) + binary.Write(w, binary.BigEndian, m.data) +} + +func (m *memoryRange) load(r io.Reader) { + binary.Read(r, binary.BigEndian, &m.base) + binary.Read(r, binary.BigEndian, &m.data) +} diff --git a/apple2/persistance.go b/apple2/persistance.go new file mode 100644 index 0000000..c2d5596 --- /dev/null +++ b/apple2/persistance.go @@ -0,0 +1,66 @@ +package apple2 + +import ( + "bufio" + "encoding/binary" + "io" + "os" +) + +type persistent interface { + save(w io.Writer) + load(r io.Reader) +} + +type persistance struct { + a *Apple2 + items []persistent +} + +func newPersistance(a *Apple2) *persistance { + var p persistance + p.a = a + return &p +} + +func (p *persistance) register(i persistent) { + p.items = append(p.items, i) +} + +func (p *persistance) save(filename string) { + f, err := os.Create(filename) + if err != nil { + panic(err) + } + defer f.Close() + w := bufio.NewWriter(f) + defer w.Flush() + + binary.Write(w, binary.BigEndian, p.a.isColor) + binary.Write(w, binary.BigEndian, p.a.fastMode) + binary.Write(w, binary.BigEndian, p.a.fastRequestsCounter) + p.a.cpu.Save(w) + + for _, v := range p.items { + v.save(w) + } +} + +func (p *persistance) load(filename string) { + f, err := os.Open(filename) + if err != nil { + // Ignore error if can't load the file + return + } + defer f.Close() + r := bufio.NewReader(f) + + binary.Read(r, binary.BigEndian, &p.a.isColor) + binary.Read(r, binary.BigEndian, &p.a.fastMode) + binary.Read(r, binary.BigEndian, &p.a.fastRequestsCounter) + p.a.cpu.Load(r) + + for _, v := range p.items { + v.load(r) + } +} diff --git a/apple2/softSwitches2e.go b/apple2/softSwitches2e.go index 4e1dffa..5b8f797 100644 --- a/apple2/softSwitches2e.go +++ b/apple2/softSwitches2e.go @@ -61,3 +61,5 @@ func softSwitchSlotC3RomOn(io *ioC0Page) { func softSwitchSlotC3RomOff(io *ioC0Page) { io.apple2.mmu.setPagesRead(0xc3, 0xc3, io.apple2.mmu.physicalROMe) } + +// TODO: apply state after persistance load diff --git a/apple2sdl/sdlKeyboard.go b/apple2sdl/sdlKeyboard.go index ab80bf4..9b5146a 100644 --- a/apple2sdl/sdlKeyboard.go +++ b/apple2sdl/sdlKeyboard.go @@ -93,6 +93,10 @@ func (k *sdlKeyboard) putKey(keyEvent *sdl.KeyboardEvent) { k.a.SendCommand(apple2.CommandToggleSpeed) case sdl.K_F6: k.a.SendCommand(apple2.CommandToggleColor) + case sdl.K_F7: + k.a.SendCommand(apple2.CommandSaveState) + case sdl.K_F8: + k.a.SendCommand(apple2.CommandLoadState) } // Missing values 91 to 95. Usually control for [\]^_ diff --git a/core6502/execute.go b/core6502/execute.go index 38a3018..9c2e83f 100644 --- a/core6502/execute.go +++ b/core6502/execute.go @@ -1,6 +1,10 @@ package core6502 -import "fmt" +import ( + "encoding/binary" + "fmt" + "io" +) // https://www.masswerk.at/6502/6502_instruction_set.html // http://www.emulator101.com/reference/6502-reference.html @@ -78,6 +82,18 @@ func (s *State) GetCycles() uint64 { return s.cycles } +// Save saves the CPU state (registers and cycle counter) +func (s *State) Save(w io.Writer) { + binary.Write(w, binary.BigEndian, s.cycles) + binary.Write(w, binary.BigEndian, s.reg.data) +} + +// Load loads the CPU state (registers and cycle counter) +func (s *State) Load(r io.Reader) { + binary.Read(r, binary.BigEndian, &s.cycles) + binary.Read(r, binary.BigEndian, &s.reg.data) +} + func lineString(line []uint8, opcode opcode) string { t := opcode.name switch opcode.addressMode { diff --git a/core6502/registers.go b/core6502/registers.go index b207578..0eccee6 100644 --- a/core6502/registers.go +++ b/core6502/registers.go @@ -6,9 +6,10 @@ const ( regA = 0 regX = 1 regY = 2 - regP = 4 - regSP = 5 - regPC = 6 // 2 bytes + regP = 3 + regSP = 4 + regPC = 5 // 2 bytes + regPC2 = 6 regNone = -1 ) @@ -24,7 +25,7 @@ const ( ) type registers struct { - data [8]uint8 + data [7]uint8 } func (r *registers) getRegister(i int) uint8 { return r.data[i] } @@ -45,12 +46,12 @@ func (r *registers) setP(v uint8) { r.setRegister(regP, v) } func (r *registers) setSP(v uint8) { r.setRegister(regSP, v) } func (r *registers) getPC() uint16 { - return uint16(r.data[regPC])*256 + uint16(r.data[regPC+1]) + return uint16(r.data[regPC])*256 + uint16(r.data[regPC2]) } func (r *registers) setPC(v uint16) { r.data[regPC] = uint8(v >> 8) - r.data[regPC+1] = uint8(v) + r.data[regPC2] = uint8(v) } func (r *registers) getFlagBit(i uint8) uint8 { diff --git a/main.go b/main.go index dd4ebe6..47c06e0 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,7 @@ func main() { disk2Slot := flag.Int( "disk2Slot", 6, - "slot for the disk driver. 0 for none.") + "slot for the disk driver. -1 for none.") diskImage := flag.String( "disk", "../dos33.dsk", @@ -31,6 +31,15 @@ func main() { "charRom", "apple2/romdumps/Apple2rev7CharGen.rom", "rom file for the disk drive controller") + languageCardSlot := flag.Int( + "languageCardSlot", + 0, + "slot for the 16kb language card. -1 for none") + saturnCardSlot := flag.Int( + "saturnCardSlot", + -1, + "slot for the 256kb Saturn card. -1 for none") + useSdl := flag.Bool( "sdl", true, @@ -69,9 +78,13 @@ func main() { log := false a := apple2.NewApple2(*romFile, *charRomFile, *cpuClock, !*mono, *fastDisk, *panicSS) - //a.AddLanguageCard(0) - a.AddSaturnCard(0) - if *disk2Slot > 0 { + if *languageCardSlot >= 0 { + a.AddLanguageCard(*languageCardSlot) + } + if *saturnCardSlot >= 0 { + a.AddSaturnCard(*saturnCardSlot) + } + if *disk2Slot >= 0 { a.AddDisk2(*disk2Slot, *disk2RomFile, *diskImage) } if *useSdl {