Improve the expansion card abstraction

This commit is contained in:
Ivan Izaguirre 2019-05-18 16:43:51 +02:00
parent cb21a1fefc
commit 684c8f7172
7 changed files with 115 additions and 104 deletions

View File

@ -1,8 +1,12 @@
package apple2 package apple2
import ( import (
"bufio"
"encoding/binary"
"fmt" "fmt"
"go6502/core6502" "go6502/core6502"
"io"
"os"
"time" "time"
) )
@ -12,6 +16,7 @@ type Apple2 struct {
mmu *memoryManager mmu *memoryManager
io *ioC0Page io *ioC0Page
cg *CharacterGenerator cg *CharacterGenerator
cards [8]card
isApple2e bool isApple2e bool
panicSS bool panicSS bool
commandChannel chan int commandChannel chan int
@ -19,7 +24,6 @@ type Apple2 struct {
isColor bool isColor bool
fastMode bool fastMode bool
fastRequestsCounter int fastRequestsCounter int
persistance *persistance
} }
const ( const (
@ -97,10 +101,10 @@ func (a *Apple2) executeCommand(command int) {
a.isColor = !a.isColor a.isColor = !a.isColor
case CommandSaveState: case CommandSaveState:
fmt.Println("Saving state") fmt.Println("Saving state")
a.persistance.save("apple2.state") a.save("apple2.state")
case CommandLoadState: case CommandLoadState:
fmt.Println("Loading state") fmt.Println("Loading state")
a.persistance.load("apple2.state") a.load("apple2.state")
} }
} }
@ -116,3 +120,55 @@ func (a *Apple2) releaseFastMode() {
a.fastRequestsCounter-- a.fastRequestsCounter--
} }
} }
type persistent interface {
save(io.Writer)
load(io.Reader)
}
func (a *Apple2) save(filename string) {
f, err := os.Create(filename)
if err != nil {
panic(err)
}
defer f.Close()
w := bufio.NewWriter(f)
defer w.Flush()
a.cpu.Save(w)
a.mmu.save(w)
a.io.save(w)
binary.Write(w, binary.BigEndian, a.isColor)
binary.Write(w, binary.BigEndian, a.fastMode)
binary.Write(w, binary.BigEndian, a.fastRequestsCounter)
for _, c := range a.cards {
if c != nil {
c.save(w)
}
}
}
func (a *Apple2) 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)
a.cpu.Load(r)
a.mmu.load(r)
a.io.load(r)
binary.Read(r, binary.BigEndian, &a.isColor)
binary.Read(r, binary.BigEndian, &a.fastMode)
binary.Read(r, binary.BigEndian, &a.fastRequestsCounter)
for _, c := range a.cards {
if c != nil {
c.load(r)
}
}
}

View File

@ -8,9 +8,7 @@ import (
func NewApple2(romFile string, charRomFile string, clockMhz float64, func NewApple2(romFile string, charRomFile string, clockMhz float64,
isColor bool, fastMode bool, panicSS bool) *Apple2 { isColor bool, fastMode bool, panicSS bool) *Apple2 {
var a Apple2 var a Apple2
a.persistance = newPersistance(&a)
a.mmu = newMemoryManager(&a, romFile) a.mmu = newMemoryManager(&a, romFile)
a.persistance.register(a.mmu)
a.cpu = core6502.NewNMOS6502(a.mmu) a.cpu = core6502.NewNMOS6502(a.mmu)
if charRomFile != "" { if charRomFile != "" {
a.cg = NewCharacterGenerator(charRomFile) a.cg = NewCharacterGenerator(charRomFile)
@ -29,39 +27,37 @@ func NewApple2(romFile string, charRomFile string, clockMhz float64,
// Set the io in 0xc000 // Set the io in 0xc000
a.io = newIoC0Page(&a) a.io = newIoC0Page(&a)
a.persistance.register(a.io)
a.mmu.setPages(0xc0, 0xc0, a.io) a.mmu.setPages(0xc0, 0xc0, a.io)
return &a return &a
} }
func (a *Apple2) insertCard(c card, slot int) {
c.assign(a, slot)
a.cards[slot] = c
}
// AddDisk2 insterts a DiskII controller // AddDisk2 insterts a DiskII controller
func (a *Apple2) AddDisk2(slot int, diskRomFile string, diskImage string) { func (a *Apple2) AddDisk2(slot int, diskRomFile string, diskImage string) {
d := newCardDisk2(diskRomFile) var c cardDisk2
d.cardBase.insert(a, slot) c.loadRom(diskRomFile)
a.persistance.register(d) a.insertCard(&c, slot)
if diskImage != "" { if diskImage != "" {
diskette := loadDisquette(diskImage) diskette := loadDisquette(diskImage)
//diskette.saveNib(diskImage + "bak") //diskette.saveNib(diskImage + "bak")
d.drive[0].insertDiskette(diskette) c.drive[0].insertDiskette(diskette)
} }
} }
// AddLanguageCard inserts a 16Kb card // AddLanguageCard inserts a 16Kb card
func (a *Apple2) AddLanguageCard(slot int) { func (a *Apple2) AddLanguageCard(slot int) {
d := newCardLanguage() a.insertCard(&cardLanguage{}, slot)
d.cardBase.insert(a, slot)
d.applyState()
a.persistance.register(d)
} }
// AddSaturnCard inserts a 128Kb card // AddSaturnCard inserts a 128Kb card
func (a *Apple2) AddSaturnCard(slot int) { func (a *Apple2) AddSaturnCard(slot int) {
d := newCardSaturn() a.insertCard(&cardSaturn{}, slot)
d.cardBase.insert(a, slot)
d.applyState()
a.persistance.register(d)
} }
// ConfigureStdConsole uses stdin and stdout to interface with the Apple2 // ConfigureStdConsole uses stdin and stdout to interface with the Apple2

View File

@ -1,5 +1,16 @@
package apple2 package apple2
import (
"io"
"io/ioutil"
)
type card interface {
loadRom(filename string)
assign(a *Apple2, slot int)
persistent
}
type cardBase struct { type cardBase struct {
a *Apple2 a *Apple2
rom *memoryRange rom *memoryRange
@ -8,7 +19,18 @@ type cardBase struct {
ssw [16]softSwitchW ssw [16]softSwitchW
} }
func (c *cardBase) insert(a *Apple2, slot int) { func (c *cardBase) loadRom(filename string) {
if c.a != nil {
panic("Rom must be loaded before inserting the card in the slot")
}
data, err := ioutil.ReadFile(filename)
if err != nil {
panic(err)
}
c.rom = newMemoryRange(0, data)
}
func (c *cardBase) assign(a *Apple2, slot int) {
c.a = a c.a = a
c.slot = slot c.slot = slot
if slot != 0 && c.rom != nil { if slot != 0 && c.rom != nil {
@ -21,3 +43,11 @@ func (c *cardBase) insert(a *Apple2, slot int) {
a.io.addSoftSwitchW(uint8(0xC80+slot*0x10+i), c.ssw[i]) a.io.addSoftSwitchW(uint8(0xC80+slot*0x10+i), c.ssw[i])
} }
} }
func (c *cardBase) save(w io.Writer) {
// Empty
}
func (c *cardBase) load(r io.Reader) {
// Empty
}

View File

@ -3,7 +3,6 @@ package apple2
import ( import (
"encoding/binary" "encoding/binary"
"io" "io"
"io/ioutil"
) )
/* /*
@ -32,10 +31,7 @@ type cardDisk2Drive struct {
position int position int
} }
func newCardDisk2(filename string) *cardDisk2 { func (c *cardDisk2) assign(a *Apple2, slot int) {
var c cardDisk2
c.rom = newMemoryRange(0, loadCardRom(filename))
// Phase control soft switches // Phase control soft switches
// Lazy emulation. It only checks for phases on and move the head // Lazy emulation. It only checks for phases on and move the head
// up or down depending on the previous phase. // up or down depending on the previous phase.
@ -138,15 +134,8 @@ func newCardDisk2(filename string) *cardDisk2 {
//fmt.Printf("DISKII: Set write mode\n") //fmt.Printf("DISKII: Set write mode\n")
return 0 return 0
} }
return &c
}
func loadCardRom(filename string) []uint8 { c.cardBase.assign(a, slot)
data, err := ioutil.ReadFile(filename)
if err != nil {
panic(err)
}
return data
} }
func (d *cardDisk2Drive) insertDiskette(dt *diskette16sector) { func (d *cardDisk2Drive) insertDiskette(dt *diskette16sector) {

View File

@ -45,8 +45,7 @@ const (
lcWriteEnabled = 2 lcWriteEnabled = 2
) )
func newCardLanguage() *cardLanguage { func (c *cardLanguage) assign(a *Apple2, slot int) {
var c cardLanguage
c.readState = false c.readState = false
c.writeState = lcWriteEnabled c.writeState = lcWriteEnabled
c.activeBank = 1 c.activeBank = 1
@ -66,7 +65,9 @@ func newCardLanguage() *cardLanguage {
c.writeState = lcWriteDisabled c.writeState = lcWriteDisabled
} }
} }
return &c
c.cardBase.assign(a, slot)
c.applyState()
} }
func (c *cardLanguage) ssAction(ss int) { func (c *cardLanguage) ssAction(ss int) {
@ -131,6 +132,8 @@ func (c *cardLanguage) save(w io.Writer) {
c.ramBankA.save(w) c.ramBankA.save(w)
c.ramBankB.save(w) c.ramBankB.save(w)
c.ramUpper.save(w) c.ramUpper.save(w)
c.cardBase.save(w)
} }
func (c *cardLanguage) load(r io.Reader) { func (c *cardLanguage) load(r io.Reader) {
@ -142,4 +145,5 @@ func (c *cardLanguage) load(r io.Reader) {
c.ramUpper.load(r) c.ramUpper.load(r)
c.applyState() c.applyState()
c.cardBase.load(r)
} }

View File

@ -35,8 +35,7 @@ const (
saturnBlocks = 8 saturnBlocks = 8
) )
func newCardSaturn() *cardSaturn { func (c *cardSaturn) assign(a *Apple2, slot int) {
var c cardSaturn
c.readState = false c.readState = false
c.writeState = lcWriteEnabled c.writeState = lcWriteEnabled
c.activeBank = 1 c.activeBank = 1
@ -57,7 +56,8 @@ func newCardSaturn() *cardSaturn {
c.writeState = lcWriteDisabled c.writeState = lcWriteDisabled
} }
} }
return &c c.cardBase.assign(a, slot)
c.applyState()
} }
func (c *cardSaturn) ssAction(ss int) { func (c *cardSaturn) ssAction(ss int) {
@ -163,6 +163,7 @@ func (c *cardSaturn) save(w io.Writer) {
c.ramBankB[i].save(w) c.ramBankB[i].save(w)
c.ramUpper[i].save(w) c.ramUpper[i].save(w)
} }
c.cardBase.save(w)
} }
func (c *cardSaturn) load(r io.Reader) { func (c *cardSaturn) load(r io.Reader) {
@ -177,4 +178,5 @@ func (c *cardSaturn) load(r io.Reader) {
c.applyState() c.applyState()
} }
c.cardBase.load(r)
} }

View File

@ -1,66 +0,0 @@
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)
}
}