diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..722d5e7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode diff --git a/apple2main.go b/apple2main.go index bb6dccf..813312d 100644 --- a/apple2main.go +++ b/apple2main.go @@ -59,6 +59,11 @@ func MainApple() *Apple2 { false, "shows the character map", ) + base64a := flag.Bool( + "base64a", + false, + "setup a Base64A clone", + ) flag.Parse() if *dumpChars { @@ -69,7 +74,11 @@ func MainApple() *Apple2 { } a := NewApple2(*charRomFile, *cpuClock, !*mono, *fastDisk, *panicSS) - a.LoadRom(*romFile) + if *base64a { + NewBase64a(a) + } else { + a.LoadRom(*romFile) + } if *languageCardSlot >= 0 { a.AddLanguageCard(*languageCardSlot) } diff --git a/base64a.go b/base64a.go new file mode 100644 index 0000000..35abb12 --- /dev/null +++ b/base64a.go @@ -0,0 +1,93 @@ +package apple2 + +import "fmt" + +/* + Copam BASE64A adaptation. +*/ + +// Base64a extends an Apple2 +type Base64a struct { + a *Apple2 + romBanks [4]*memoryRange + romBank uint8 +} + +// NewBase64a instantiates an apple2 +func NewBase64a(a *Apple2) *Base64a { + + var b Base64a + b.a = a + b.loadRom() + + return &b +} + +const ( + // There are 6 ROM chips. Each can have 4Kb or 8Kb. They can fill + // 2 or 4 banks with 2kb windows. + base64aRomBankSize = 12 * 1024 + base64aRomBankCount = 4 + base64aRomWindowSize = 2 * 1024 + base64aRomChipCount = 6 +) + +func (b *Base64a) loadRom() { + // Load the 6 PROM dumps + romBanksBytes := make([][]uint8, base64aRomBankCount) + for j := range romBanksBytes { + romBanksBytes[j] = make([]uint8, 0, base64aRomBankSize) + } + + for i := 0; i < base64aRomChipCount; i++ { + filename := fmt.Sprintf("/BASE64A_%X.BIN", 0xd0+i*0x08) + data := loadResource(filename) + for j := range romBanksBytes { + start := (j * base64aRomWindowSize) % len(data) + romBanksBytes[j] = append(romBanksBytes[j], data[start:start+base64aRomWindowSize]...) + } + } + + for j := range romBanksBytes { + b.romBanks[j] = newMemoryRange(0xd000, romBanksBytes[j]) + } + + // Start with first bank active + b.changeRomBank(0) + + // Add rom soft switches. They use the annunciator 0 and 1 + b.a.io.addSoftSwitchRW(0x58, func(*ioC0Page) uint8 { + b.changeRomBank(b.romBank & 2) + return 0 + }) + b.a.io.addSoftSwitchRW(0x59, func(*ioC0Page) uint8 { + b.changeRomBank(b.romBank | 1) + return 0 + }) + b.a.io.addSoftSwitchRW(0x5A, func(*ioC0Page) uint8 { + b.changeRomBank(b.romBank & 1) + return 0 + }) + b.a.io.addSoftSwitchRW(0x5B, func(*ioC0Page) uint8 { + b.changeRomBank(b.romBank | 2) + return 0 + }) + + // Other softswitches + b.a.io.addSoftSwitchW(0x0C, notImplementedSoftSwitchW) // 80 columns off? + b.a.io.addSoftSwitchW(0x0E, notImplementedSoftSwitchW) // Alt char off? + + // Write on the speaker. That is a double access and should do nothing + // but works somehow on the BASE64A + b.a.io.addSoftSwitchW(0x30, func(io *ioC0Page, value uint8) { + getSpeakerSoftSwitch(io) + }) + +} + +func (b *Base64a) changeRomBank(bank uint8) { + b.romBank = bank + fmt.Printf("Change to ROM bank #%v\n", b.romBank) + b.a.mmu.physicalROM = b.romBanks[b.romBank] + b.a.mmu.resetRomPaging() // If rom was not active. This is going to far? +} diff --git a/core6502/execute.go b/core6502/execute.go index 9c2e83f..a56b245 100644 --- a/core6502/execute.go +++ b/core6502/execute.go @@ -27,7 +27,7 @@ const ( type opcode struct { name string - bytes uint8 + bytes uint16 cycles int addressMode int action opFunc @@ -54,14 +54,14 @@ func (s *State) ExecuteInstruction(log bool) { } line := make([]uint8, opcode.bytes) - for i := uint8(0); i < opcode.bytes; i++ { + for i := uint16(0); i < opcode.bytes; i++ { line[i] = s.mem.Peek(pc) pc++ } s.reg.setPC(pc) if log { - fmt.Printf("%#04x %-12s: ", pc, lineString(line, opcode)) + fmt.Printf("%#04x %-12s: ", pc-opcode.bytes, lineString(line, opcode)) } opcode.action(s, line, opcode) s.cycles += uint64(opcode.cycles) diff --git a/ioC0Page.go b/ioC0Page.go index 136ad54..1c5b765 100644 --- a/ioC0Page.go +++ b/ioC0Page.go @@ -65,16 +65,16 @@ func (p *ioC0Page) addSoftSwitchRW(address uint8, ss softSwitchR) { } func (p *ioC0Page) addSoftSwitchR(address uint8, ss softSwitchR) { - if p.softSwitchesR[address] != nil { - fmt.Printf("Addresss 0x0c%02x is already assigned for read", address) - } + //if p.softSwitchesR[address] != nil { + // fmt.Printf("Addresss 0x0c%02x is already assigned for read\n", address) + //} p.softSwitchesR[address] = ss } func (p *ioC0Page) addSoftSwitchW(address uint8, ss softSwitchW) { - if p.softSwitchesW[address] != nil { - fmt.Printf("Addresss 0x0c%02x is already assigned for write", address) - } + //if p.softSwitchesW[address] != nil { + // fmt.Printf("Addresss 0x0c%02x is already assigned for write\n", address) + //} p.softSwitchesW[address] = ss } @@ -91,7 +91,6 @@ func (p *ioC0Page) setSpeakerProvider(s SpeakerProvider) { } func (p *ioC0Page) peek(address uint16) uint8 { - //fmt.Printf("Peek on $%02x\n", address) pageAddress := uint8(address) ss := p.softSwitchesR[pageAddress] if ss == nil { @@ -100,7 +99,9 @@ func (p *ioC0Page) peek(address uint16) uint8 { } return 0 } - return ss(p) + value := ss(p) + //fmt.Printf("Peek on $%02x: $%02x\n", address, value) + return value } func (p *ioC0Page) poke(address uint16, value uint8) { diff --git a/softSwitches2.go b/softSwitches2.go index eb562fd..5f35208 100644 --- a/softSwitches2.go +++ b/softSwitches2.go @@ -76,6 +76,10 @@ func addApple2SoftSwitches(io *ioC0Page) { func notImplementedSoftSwitchR(*ioC0Page) uint8 { return 0 } + +func notImplementedSoftSwitchW(*ioC0Page, uint8) { +} + func getStatusSoftSwitch(ioFlag uint8) softSwitchR { return func(io *ioC0Page) uint8 { return io.softSwitchesData[ioFlag] @@ -107,11 +111,15 @@ func getKeySoftSwitch(io *ioC0Page) uint8 { io.softSwitchesData[ioDataKeyboard] = key + (1 << 7) } } - return io.softSwitchesData[ioDataKeyboard] + value := io.softSwitchesData[ioDataKeyboard] + //fmt.Printf("Key $%02x, %v\n", value, strobed) + return value + } func strobeKeyboardSoftSwitch(io *ioC0Page) uint8 { result := io.softSwitchesData[ioDataKeyboard] + //fmt.Printf("Strobe $%02x\n", result) io.softSwitchesData[ioDataKeyboard] &^= 1 << 7 return result }