Initial Apple 2e enhanced support
This commit is contained in:
parent
1d0a3e0b34
commit
eeebf1bb0f
|
@ -6,13 +6,39 @@ import (
|
||||||
"github.com/ivanizag/apple2/core6502"
|
"github.com/ivanizag/apple2/core6502"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewApple2 instantiates an apple2
|
// newApple2 instantiates an apple2
|
||||||
func NewApple2(clockMhz float64, isColor bool, fastMode bool) *Apple2 {
|
func newApple2plus() *Apple2 {
|
||||||
|
|
||||||
var a Apple2
|
var a Apple2
|
||||||
a.Name = "Apple ][+"
|
a.Name = "Apple ][+"
|
||||||
a.mmu = newMemoryManager(&a)
|
a.mmu = newMemoryManager(&a)
|
||||||
a.cpu = core6502.NewNMOS6502(a.mmu)
|
a.cpu = core6502.NewNMOS6502(a.mmu)
|
||||||
|
|
||||||
|
// Set the io in 0xc000
|
||||||
|
a.io = newIoC0Page(&a)
|
||||||
|
a.mmu.setPages(0xc0, 0xc0, a.io)
|
||||||
|
addApple2SoftSwitches(a.io)
|
||||||
|
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
func newApple2eEnhanced() *Apple2 {
|
||||||
|
|
||||||
|
var a Apple2
|
||||||
|
a.Name = "Apple //e"
|
||||||
|
a.mmu = newMemoryManager(&a)
|
||||||
|
a.cpu = core6502.NewCMOS65c02(a.mmu)
|
||||||
|
|
||||||
|
// Set the io in 0xc000
|
||||||
|
a.io = newIoC0Page(&a)
|
||||||
|
a.mmu.setPages(0xc0, 0xc0, a.io)
|
||||||
|
addApple2SoftSwitches(a.io)
|
||||||
|
addApple2ESoftSwitches(a.io)
|
||||||
|
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Apple2) setup(isColor bool, clockMhz float64, fastMode bool) {
|
||||||
a.commandChannel = make(chan int, 100)
|
a.commandChannel = make(chan int, 100)
|
||||||
a.isColor = isColor
|
a.isColor = isColor
|
||||||
a.fastMode = fastMode
|
a.fastMode = fastMode
|
||||||
|
@ -23,12 +49,6 @@ func NewApple2(clockMhz float64, isColor bool, fastMode bool) *Apple2 {
|
||||||
} else {
|
} else {
|
||||||
a.cycleDurationNs = 1000.0 / clockMhz
|
a.cycleDurationNs = 1000.0 / clockMhz
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the io in 0xc000
|
|
||||||
a.io = newIoC0Page(&a)
|
|
||||||
a.mmu.setPages(0xc0, 0xc0, a.io)
|
|
||||||
|
|
||||||
return &a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Apple2) insertCard(c card, slot int) {
|
func (a *Apple2) insertCard(c card, slot int) {
|
||||||
|
|
|
@ -5,11 +5,13 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const defaultInternal = "<default>"
|
||||||
|
|
||||||
// MainApple is a device independant main. Video, keyboard and speaker won't be defined
|
// MainApple is a device independant main. Video, keyboard and speaker won't be defined
|
||||||
func MainApple() *Apple2 {
|
func MainApple() *Apple2 {
|
||||||
romFile := flag.String(
|
romFile := flag.String(
|
||||||
"rom",
|
"rom",
|
||||||
"<internal>/Apple2_Plus.rom",
|
defaultInternal,
|
||||||
"main rom file")
|
"main rom file")
|
||||||
disk2RomFile := flag.String(
|
disk2RomFile := flag.String(
|
||||||
"diskRom",
|
"diskRom",
|
||||||
|
@ -37,7 +39,7 @@ func MainApple() *Apple2 {
|
||||||
"cpu speed in Mhz, use 0 for full speed. Use F5 to toggle.")
|
"cpu speed in Mhz, use 0 for full speed. Use F5 to toggle.")
|
||||||
charRomFile := flag.String(
|
charRomFile := flag.String(
|
||||||
"charRom",
|
"charRom",
|
||||||
"<internal>/Apple2rev7CharGen.rom",
|
defaultInternal,
|
||||||
"rom file for the character generator")
|
"rom file for the character generator")
|
||||||
languageCardSlot := flag.Int(
|
languageCardSlot := flag.Int(
|
||||||
"languageCardSlot",
|
"languageCardSlot",
|
||||||
|
@ -81,10 +83,10 @@ func MainApple() *Apple2 {
|
||||||
false,
|
false,
|
||||||
"shows the character map",
|
"shows the character map",
|
||||||
)
|
)
|
||||||
base64a := flag.Bool(
|
model := flag.String(
|
||||||
"base64a",
|
"model",
|
||||||
false,
|
"2plus",
|
||||||
"setup a Base64A clone",
|
"set base model. Models available 2plus, 2e, base64a",
|
||||||
)
|
)
|
||||||
profile := flag.Bool(
|
profile := flag.Bool(
|
||||||
"profile",
|
"profile",
|
||||||
|
@ -93,29 +95,73 @@ func MainApple() *Apple2 {
|
||||||
)
|
)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
a := NewApple2(*cpuClock, !*mono, *fastDisk)
|
var a *Apple2
|
||||||
|
var charGenMap charColumnMap
|
||||||
|
initialCharGenPage := 0
|
||||||
|
switch *model {
|
||||||
|
case "2plus":
|
||||||
|
a = newApple2plus()
|
||||||
|
if *romFile == defaultInternal {
|
||||||
|
*romFile = "<internal>/Apple2_Plus.rom"
|
||||||
|
}
|
||||||
|
if *charRomFile == defaultInternal {
|
||||||
|
*charRomFile = "<internal>/Apple2rev7CharGen.rom"
|
||||||
|
}
|
||||||
|
charGenMap = charGenColumnsMap2Plus
|
||||||
|
|
||||||
|
case "2e":
|
||||||
|
a = newApple2eEnhanced()
|
||||||
|
if *romFile == defaultInternal {
|
||||||
|
*romFile = "<internal>/Apple2e_Enhanced.rom"
|
||||||
|
}
|
||||||
|
if *charRomFile == defaultInternal {
|
||||||
|
*charRomFile = "<internal>/Apple IIe Video Enhanced - 342-0265-A - 2732.bin"
|
||||||
|
}
|
||||||
|
a.isApple2e = true
|
||||||
|
charGenMap = charGenColumnsMap2e
|
||||||
|
|
||||||
|
case "base64a":
|
||||||
|
a = newBase64a()
|
||||||
|
if *romFile == defaultInternal {
|
||||||
|
err := loadBase64aRom(a)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
*romFile = ""
|
||||||
|
}
|
||||||
|
if *charRomFile == defaultInternal {
|
||||||
|
*charRomFile = "<internal>/BASE64A_ROM7_CharGen.BIN"
|
||||||
|
initialCharGenPage = 1
|
||||||
|
}
|
||||||
|
charGenMap = charGenColumnsMapBase64a
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("Model not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
a.setup(!*mono, *cpuClock, *fastDisk)
|
||||||
a.cpu.SetTrace(*traceCPU)
|
a.cpu.SetTrace(*traceCPU)
|
||||||
a.io.setTrace(*traceSS)
|
a.io.setTrace(*traceSS)
|
||||||
a.io.setPanicNotImplemented(*panicSS)
|
a.io.setPanicNotImplemented(*panicSS)
|
||||||
a.setProfile(*profile)
|
a.setProfile(*profile)
|
||||||
|
|
||||||
if *charRomFile != "" {
|
// Load ROM if not loaded already
|
||||||
cg, err := NewCharacterGenerator(*charRomFile)
|
if *romFile != "" {
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
a.cg = cg
|
|
||||||
}
|
|
||||||
|
|
||||||
if *base64a {
|
|
||||||
NewBase64a(a)
|
|
||||||
} else {
|
|
||||||
err := a.LoadRom(*romFile)
|
err := a.LoadRom(*romFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load character generator if it loaded already
|
||||||
|
cg, err := newCharacterGenerator(*charRomFile, charGenMap)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
cg.setPage(initialCharGenPage)
|
||||||
|
a.cg = cg
|
||||||
|
|
||||||
|
// Externsion cards
|
||||||
if *languageCardSlot >= 0 {
|
if *languageCardSlot >= 0 {
|
||||||
a.AddLanguageCard(*languageCardSlot)
|
a.AddLanguageCard(*languageCardSlot)
|
||||||
}
|
}
|
||||||
|
|
126
base64a.go
126
base64a.go
|
@ -1,42 +1,43 @@
|
||||||
package apple2
|
package apple2
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"github.com/ivanizag/apple2/core6502"
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copam BASE64A adaptation.
|
Copam BASE64A adaptation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Base64a extends an Apple2
|
// newBase64a instantiates an apple2
|
||||||
type Base64a struct {
|
func newBase64a() *Apple2 {
|
||||||
a *Apple2
|
var 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"
|
a.Name = "Base 64A"
|
||||||
err := b.loadRom()
|
a.mmu = newMemoryManager(&a)
|
||||||
if err != nil {
|
a.cpu = core6502.NewNMOS6502(a.mmu)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the character generator
|
// Set the io in 0xc000
|
||||||
if !a.cg.customRom {
|
a.io = newIoC0Page(&a)
|
||||||
err := a.cg.load("<internal>/BASE64A_ROM7_CharGen.BIN")
|
a.mmu.setPages(0xc0, 0xc0, a.io)
|
||||||
if err != nil {
|
addApple2SoftSwitches(a.io)
|
||||||
return nil, err
|
addBase64aSoftSwitches(a.io)
|
||||||
}
|
|
||||||
}
|
|
||||||
a.cg.setColumnMap(base64aCharGenColumnsMap)
|
|
||||||
a.cg.setPage(1)
|
|
||||||
|
|
||||||
return &b, nil
|
return &a
|
||||||
}
|
}
|
||||||
|
|
||||||
func base64aCharGenColumnsMap(column int) int {
|
func addBase64aSoftSwitches(io *ioC0Page) {
|
||||||
|
// Other softswitches
|
||||||
|
io.addSoftSwitchW(0x0C, notImplementedSoftSwitchW) // 80 columns off?
|
||||||
|
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
|
||||||
|
io.addSoftSwitchW(0x30, func(io *ioC0Page, value uint8) {
|
||||||
|
speakerSoftSwitch(io)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func charGenColumnsMapBase64a(column int) int {
|
||||||
bit := column + 2
|
bit := column + 2
|
||||||
// Weird positions
|
// Weird positions
|
||||||
if column == 6 {
|
if column == 6 {
|
||||||
|
@ -46,76 +47,3 @@ func base64aCharGenColumnsMap(column int) int {
|
||||||
}
|
}
|
||||||
return bit
|
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?
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package apple2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copam BASE64A uses paginated ROM
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Base64aROM Models the paginated ROM on a BASE64A clone
|
||||||
|
type base64aROM struct {
|
||||||
|
romBanks [4]*memoryRange
|
||||||
|
romBank uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
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 loadBase64aRom(a *Apple2) 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]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create banks
|
||||||
|
var r base64aROM
|
||||||
|
for j := range romBanksBytes {
|
||||||
|
r.romBanks[j] = newMemoryRange(0xd000, romBanksBytes[j])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with first bank active
|
||||||
|
r.changeBank(a.mmu, 0)
|
||||||
|
|
||||||
|
// Add rom soft switches. They use the annunciator 0 and 1
|
||||||
|
a.io.addSoftSwitchRW(0x58, func(*ioC0Page) uint8 {
|
||||||
|
r.changeBank(a.mmu, r.romBank&2)
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
a.io.addSoftSwitchRW(0x59, func(*ioC0Page) uint8 {
|
||||||
|
r.changeBank(a.mmu, r.romBank|1)
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
a.io.addSoftSwitchRW(0x5A, func(*ioC0Page) uint8 {
|
||||||
|
r.changeBank(a.mmu, r.romBank&1)
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
a.io.addSoftSwitchRW(0x5B, func(*ioC0Page) uint8 {
|
||||||
|
r.changeBank(a.mmu, r.romBank|2)
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *base64aROM) changeBank(mmu *memoryManager, bank uint8) {
|
||||||
|
r.romBank = bank
|
||||||
|
//fmt.Printf("Change to ROM bank #%v\n", r.romBank)
|
||||||
|
mmu.physicalROM = r.romBanks[r.romBank]
|
||||||
|
mmu.resetRomPaging() // If rom was not active. This is going too far?
|
||||||
|
}
|
|
@ -7,56 +7,57 @@ import (
|
||||||
|
|
||||||
/*
|
/*
|
||||||
See:
|
See:
|
||||||
hhttps://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Companies/Apple/Documentation/Apple%20Technical%20Information%20Library/a2til041.txt
|
https://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Companies/Apple/Documentation/Apple%20Technical%20Information%20Library/a2til041.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// CharacterGenerator represents the ROM wth the characters bitmaps
|
// CharacterGenerator represents the ROM wth the characters bitmaps
|
||||||
type CharacterGenerator struct {
|
type CharacterGenerator struct {
|
||||||
data []uint8
|
data []uint8
|
||||||
customRom bool
|
|
||||||
columnMap charColumnMap
|
columnMap charColumnMap
|
||||||
page int
|
page int
|
||||||
}
|
}
|
||||||
|
|
||||||
type charColumnMap func(column int) int
|
type charColumnMap func(column int) int
|
||||||
|
|
||||||
|
func charGenColumnsMap2Plus(column int) int {
|
||||||
|
return 6 - column
|
||||||
|
}
|
||||||
|
|
||||||
|
func charGenColumnsMap2e(column int) int {
|
||||||
|
return column
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
rev7CharGenSize = 2048
|
charGenPageSize = 2048
|
||||||
defaultCharGenROM = "<internal>/Apple2rev7CharGen.rom"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCharacterGenerator instantiates a new Character Generator with the rom on the file given
|
// NewCharacterGenerator instantiates a new Character Generator with the rom on the file given
|
||||||
func NewCharacterGenerator(filename string) (*CharacterGenerator, error) {
|
func newCharacterGenerator(filename string, order charColumnMap) (*CharacterGenerator, error) {
|
||||||
var cg CharacterGenerator
|
var cg CharacterGenerator
|
||||||
err := cg.load(filename)
|
err := cg.load(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
cg.columnMap = order
|
||||||
return &cg, nil
|
return &cg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cg *CharacterGenerator) load(filename string) error {
|
func (cg *CharacterGenerator) load(filename string) error {
|
||||||
cg.customRom = !isInternalResource(filename)
|
|
||||||
bytes, err := loadResource(filename)
|
bytes, err := loadResource(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
size := len(bytes)
|
size := len(bytes)
|
||||||
if size < rev7CharGenSize {
|
if size < charGenPageSize {
|
||||||
return errors.New("Character ROM size not supported")
|
return errors.New("Character ROM size not supported")
|
||||||
}
|
}
|
||||||
cg.data = bytes
|
cg.data = bytes
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cg *CharacterGenerator) setColumnMap(columnMap charColumnMap) {
|
|
||||||
// Regular Apple II uses bits 6 to 0 but some clones have other mappings
|
|
||||||
cg.columnMap = columnMap
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cg *CharacterGenerator) setPage(page int) {
|
func (cg *CharacterGenerator) setPage(page int) {
|
||||||
// Some clones had a switch to change codepage with extra characters
|
// Some clones had a switch to change codepage with extra characters
|
||||||
pages := len(cg.data) / rev7CharGenSize
|
pages := len(cg.data) / charGenPageSize
|
||||||
cg.page = page % pages
|
cg.page = page % pages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,14 +66,8 @@ func (cg *CharacterGenerator) nextPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cg *CharacterGenerator) getPixel(char uint8, row int, column int) bool {
|
func (cg *CharacterGenerator) getPixel(char uint8, row int, column int) bool {
|
||||||
bits := cg.data[int(char)*8+row+cg.page*rev7CharGenSize]
|
bits := cg.data[int(char)*8+row+cg.page*charGenPageSize]
|
||||||
var bit int
|
bit := cg.columnMap(column)
|
||||||
if cg.columnMap != nil {
|
|
||||||
bit = cg.columnMap(column)
|
|
||||||
} else {
|
|
||||||
// Standard Apple 2 mapping
|
|
||||||
bit = 6 - column
|
|
||||||
}
|
|
||||||
value := bits >> uint(bit) & 1
|
value := bits >> uint(bit) & 1
|
||||||
return value == 1
|
return value == 1
|
||||||
}
|
}
|
||||||
|
@ -113,7 +108,7 @@ func (cg *CharacterGenerator) dumpChar(char uint8) {
|
||||||
|
|
||||||
// Dump to sdtout all the character maps
|
// Dump to sdtout all the character maps
|
||||||
func (cg *CharacterGenerator) Dump() {
|
func (cg *CharacterGenerator) Dump() {
|
||||||
pages := len(cg.data) / rev7CharGenSize
|
pages := len(cg.data) / charGenPageSize
|
||||||
for p := 0; p < pages; p++ {
|
for p := 0; p < pages; p++ {
|
||||||
cg.setPage(p)
|
cg.setPage(p)
|
||||||
for i := 0; i < 256; i++ {
|
for i := 0; i < 256; i++ {
|
||||||
|
|
|
@ -50,12 +50,6 @@ const (
|
||||||
func newIoC0Page(a *Apple2) *ioC0Page {
|
func newIoC0Page(a *Apple2) *ioC0Page {
|
||||||
var io ioC0Page
|
var io ioC0Page
|
||||||
io.apple2 = a
|
io.apple2 = a
|
||||||
|
|
||||||
addApple2SoftSwitches(&io)
|
|
||||||
if a.isApple2e {
|
|
||||||
addApple2ESoftSwitches(&io)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &io
|
return &io
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -9,24 +9,37 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func addApple2ESoftSwitches(io *ioC0Page) {
|
func addApple2ESoftSwitches(io *ioC0Page) {
|
||||||
|
// New MMU read softswithes
|
||||||
io.addSoftSwitchW(0x00, getSoftSwitchExt(ioFlag80Store, ssOff, nil))
|
|
||||||
io.addSoftSwitchW(0x01, getSoftSwitchExt(ioFlag80Store, ssOn, nil))
|
|
||||||
io.addSoftSwitchW(0x06, getSoftSwitchExt(ioFlagIntCxRom, ssOff, softSwitchIntCxRomOff))
|
io.addSoftSwitchW(0x06, getSoftSwitchExt(ioFlagIntCxRom, ssOff, softSwitchIntCxRomOff))
|
||||||
io.addSoftSwitchW(0x07, getSoftSwitchExt(ioFlagIntCxRom, ssOn, softSwitchIntCxRomOn))
|
io.addSoftSwitchW(0x07, getSoftSwitchExt(ioFlagIntCxRom, ssOn, softSwitchIntCxRomOn))
|
||||||
|
io.addSoftSwitchR(0x15, getStatusSoftSwitch(ioFlagIntCxRom))
|
||||||
io.addSoftSwitchW(0x0A, getSoftSwitchExt(ioFlagSlotC3Rom, ssOff, softSwitchSlotC3RomOff))
|
io.addSoftSwitchW(0x0A, getSoftSwitchExt(ioFlagSlotC3Rom, ssOff, softSwitchSlotC3RomOff))
|
||||||
io.addSoftSwitchW(0x0B, getSoftSwitchExt(ioFlagSlotC3Rom, ssOn, softSwitchSlotC3RomOn))
|
io.addSoftSwitchW(0x0B, getSoftSwitchExt(ioFlagSlotC3Rom, ssOn, softSwitchSlotC3RomOn))
|
||||||
|
io.addSoftSwitchR(0x17, getStatusSoftSwitch(ioFlagSlotC3Rom))
|
||||||
|
|
||||||
|
// Previous read softswithes
|
||||||
|
io.addSoftSwitchR(0x1A, getStatusSoftSwitch(ioFlagText))
|
||||||
|
io.addSoftSwitchR(0x1B, getStatusSoftSwitch(ioFlagMixed))
|
||||||
|
io.addSoftSwitchR(0x1C, getStatusSoftSwitch(ioFlagSecondPage))
|
||||||
|
io.addSoftSwitchR(0x1D, getStatusSoftSwitch(ioFlagHiRes))
|
||||||
|
|
||||||
|
// New IOU read softswithes
|
||||||
|
io.addSoftSwitchW(0x00, getSoftSwitchExt(ioFlag80Store, ssOff, nil))
|
||||||
|
io.addSoftSwitchW(0x01, getSoftSwitchExt(ioFlag80Store, ssOn, nil))
|
||||||
|
io.addSoftSwitchR(0x18, getStatusSoftSwitch(ioFlag80Store))
|
||||||
io.addSoftSwitchW(0x0C, getSoftSwitchExt(ioFlag80Col, ssOff, nil))
|
io.addSoftSwitchW(0x0C, getSoftSwitchExt(ioFlag80Col, ssOff, nil))
|
||||||
io.addSoftSwitchW(0x0D, getSoftSwitchExt(ioFlag80Col, ssOn, nil))
|
io.addSoftSwitchW(0x0D, getSoftSwitchExt(ioFlag80Col, ssOn, nil))
|
||||||
|
io.addSoftSwitchR(0x1F, getStatusSoftSwitch(ioFlag80Col))
|
||||||
io.addSoftSwitchW(0x0E, getSoftSwitchExt(ioFlagAltChar, ssOff, nil))
|
io.addSoftSwitchW(0x0E, getSoftSwitchExt(ioFlagAltChar, ssOff, nil))
|
||||||
io.addSoftSwitchW(0x0F, getSoftSwitchExt(ioFlagAltChar, ssOn, nil))
|
io.addSoftSwitchW(0x0F, getSoftSwitchExt(ioFlagAltChar, ssOn, nil))
|
||||||
io.softSwitchesData[ioFlagAltChar] = ssOn // Not sure about this.
|
io.addSoftSwitchR(0x1E, getStatusSoftSwitch(ioFlagAltChar))
|
||||||
|
|
||||||
|
// TOOD:
|
||||||
|
// AKD read on 0x10
|
||||||
|
// VBL read on 0x19
|
||||||
|
|
||||||
|
//io.softSwitchesData[ioFlagAltChar] = ssOn // Not sure about this.
|
||||||
|
|
||||||
io.addSoftSwitchR(0x15, getStatusSoftSwitch(ioFlagIntCxRom))
|
|
||||||
io.addSoftSwitchR(0x17, getStatusSoftSwitch(ioFlagSlotC3Rom))
|
|
||||||
io.addSoftSwitchR(0x18, getStatusSoftSwitch(ioFlag80Store))
|
|
||||||
io.addSoftSwitchR(0x1C, getStatusSoftSwitch(ioFlagSecondPage))
|
|
||||||
io.addSoftSwitchR(0x1F, getStatusSoftSwitch(ioFlag80Col))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type softSwitchExtAction func(io *ioC0Page)
|
type softSwitchExtAction func(io *ioC0Page)
|
||||||
|
|
Loading…
Reference in New Issue