izapple2/base64a.go
2019-10-06 01:26:00 +02:00

122 lines
2.8 KiB
Go

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, error) {
var b Base64a
b.a = a
a.Name = "Base 64A"
err := b.loadRom()
if err != nil {
return nil, err
}
// Configure the character generator
if !a.cg.customRom {
err := a.cg.load("<internal>/BASE64A_ROM7_CharGen.BIN")
if err != nil {
return nil, err
}
}
a.cg.setColumnMap(base64aCharGenColumnsMap)
a.cg.setPage(1)
return &b, nil
}
func base64aCharGenColumnsMap(column int) int {
bit := column + 2
// Weird positions
if column == 6 {
bit = 2
} else if column == 0 {
bit = 1
}
return bit
}
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() error {
// 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("<internal>/BASE64A_%X.BIN", 0xd0+i*0x08)
data, err := loadResource(filename)
if err != nil {
return err
}
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) {
speakerSoftSwitch(io)
})
return nil
}
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?
}