mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-06-07 16:46:34 +00:00
Improve the expansion card abstraction
This commit is contained in:
parent
cb21a1fefc
commit
684c8f7172
|
@ -1,8 +1,12 @@
|
|||
package apple2
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go6502/core6502"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -12,6 +16,7 @@ type Apple2 struct {
|
|||
mmu *memoryManager
|
||||
io *ioC0Page
|
||||
cg *CharacterGenerator
|
||||
cards [8]card
|
||||
isApple2e bool
|
||||
panicSS bool
|
||||
commandChannel chan int
|
||||
|
@ -19,7 +24,6 @@ type Apple2 struct {
|
|||
isColor bool
|
||||
fastMode bool
|
||||
fastRequestsCounter int
|
||||
persistance *persistance
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -97,10 +101,10 @@ func (a *Apple2) executeCommand(command int) {
|
|||
a.isColor = !a.isColor
|
||||
case CommandSaveState:
|
||||
fmt.Println("Saving state")
|
||||
a.persistance.save("apple2.state")
|
||||
a.save("apple2.state")
|
||||
case CommandLoadState:
|
||||
fmt.Println("Loading state")
|
||||
a.persistance.load("apple2.state")
|
||||
a.load("apple2.state")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,3 +120,55 @@ func (a *Apple2) releaseFastMode() {
|
|||
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)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,7 @@ import (
|
|||
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)
|
||||
|
@ -29,39 +27,37 @@ func NewApple2(romFile string, charRomFile string, clockMhz float64,
|
|||
|
||||
// Set the io in 0xc000
|
||||
a.io = newIoC0Page(&a)
|
||||
a.persistance.register(a.io)
|
||||
a.mmu.setPages(0xc0, 0xc0, a.io)
|
||||
|
||||
return &a
|
||||
}
|
||||
|
||||
func (a *Apple2) insertCard(c card, slot int) {
|
||||
c.assign(a, slot)
|
||||
a.cards[slot] = c
|
||||
}
|
||||
|
||||
// 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)
|
||||
var c cardDisk2
|
||||
c.loadRom(diskRomFile)
|
||||
a.insertCard(&c, slot)
|
||||
|
||||
if diskImage != "" {
|
||||
diskette := loadDisquette(diskImage)
|
||||
//diskette.saveNib(diskImage + "bak")
|
||||
d.drive[0].insertDiskette(diskette)
|
||||
c.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)
|
||||
a.insertCard(&cardLanguage{}, slot)
|
||||
}
|
||||
|
||||
// AddSaturnCard inserts a 128Kb card
|
||||
func (a *Apple2) AddSaturnCard(slot int) {
|
||||
d := newCardSaturn()
|
||||
d.cardBase.insert(a, slot)
|
||||
d.applyState()
|
||||
a.persistance.register(d)
|
||||
a.insertCard(&cardSaturn{}, slot)
|
||||
}
|
||||
|
||||
// ConfigureStdConsole uses stdin and stdout to interface with the Apple2
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
package apple2
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type card interface {
|
||||
loadRom(filename string)
|
||||
assign(a *Apple2, slot int)
|
||||
persistent
|
||||
}
|
||||
|
||||
type cardBase struct {
|
||||
a *Apple2
|
||||
rom *memoryRange
|
||||
|
@ -8,7 +19,18 @@ type cardBase struct {
|
|||
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.slot = slot
|
||||
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])
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cardBase) save(w io.Writer) {
|
||||
// Empty
|
||||
}
|
||||
|
||||
func (c *cardBase) load(r io.Reader) {
|
||||
// Empty
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package apple2
|
|||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
/*
|
||||
|
@ -32,10 +31,7 @@ type cardDisk2Drive struct {
|
|||
position int
|
||||
}
|
||||
|
||||
func newCardDisk2(filename string) *cardDisk2 {
|
||||
var c cardDisk2
|
||||
c.rom = newMemoryRange(0, loadCardRom(filename))
|
||||
|
||||
func (c *cardDisk2) assign(a *Apple2, slot int) {
|
||||
// Phase control soft switches
|
||||
// Lazy emulation. It only checks for phases on and move the head
|
||||
// up or down depending on the previous phase.
|
||||
|
@ -138,15 +134,8 @@ func newCardDisk2(filename string) *cardDisk2 {
|
|||
//fmt.Printf("DISKII: Set write mode\n")
|
||||
return 0
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
||||
func loadCardRom(filename string) []uint8 {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return data
|
||||
c.cardBase.assign(a, slot)
|
||||
}
|
||||
|
||||
func (d *cardDisk2Drive) insertDiskette(dt *diskette16sector) {
|
||||
|
|
|
@ -45,8 +45,7 @@ const (
|
|||
lcWriteEnabled = 2
|
||||
)
|
||||
|
||||
func newCardLanguage() *cardLanguage {
|
||||
var c cardLanguage
|
||||
func (c *cardLanguage) assign(a *Apple2, slot int) {
|
||||
c.readState = false
|
||||
c.writeState = lcWriteEnabled
|
||||
c.activeBank = 1
|
||||
|
@ -66,7 +65,9 @@ func newCardLanguage() *cardLanguage {
|
|||
c.writeState = lcWriteDisabled
|
||||
}
|
||||
}
|
||||
return &c
|
||||
|
||||
c.cardBase.assign(a, slot)
|
||||
c.applyState()
|
||||
}
|
||||
|
||||
func (c *cardLanguage) ssAction(ss int) {
|
||||
|
@ -131,6 +132,8 @@ func (c *cardLanguage) save(w io.Writer) {
|
|||
c.ramBankA.save(w)
|
||||
c.ramBankB.save(w)
|
||||
c.ramUpper.save(w)
|
||||
|
||||
c.cardBase.save(w)
|
||||
}
|
||||
|
||||
func (c *cardLanguage) load(r io.Reader) {
|
||||
|
@ -142,4 +145,5 @@ func (c *cardLanguage) load(r io.Reader) {
|
|||
c.ramUpper.load(r)
|
||||
|
||||
c.applyState()
|
||||
c.cardBase.load(r)
|
||||
}
|
||||
|
|
|
@ -35,8 +35,7 @@ const (
|
|||
saturnBlocks = 8
|
||||
)
|
||||
|
||||
func newCardSaturn() *cardSaturn {
|
||||
var c cardSaturn
|
||||
func (c *cardSaturn) assign(a *Apple2, slot int) {
|
||||
c.readState = false
|
||||
c.writeState = lcWriteEnabled
|
||||
c.activeBank = 1
|
||||
|
@ -57,7 +56,8 @@ func newCardSaturn() *cardSaturn {
|
|||
c.writeState = lcWriteDisabled
|
||||
}
|
||||
}
|
||||
return &c
|
||||
c.cardBase.assign(a, slot)
|
||||
c.applyState()
|
||||
}
|
||||
|
||||
func (c *cardSaturn) ssAction(ss int) {
|
||||
|
@ -163,6 +163,7 @@ func (c *cardSaturn) save(w io.Writer) {
|
|||
c.ramBankB[i].save(w)
|
||||
c.ramUpper[i].save(w)
|
||||
}
|
||||
c.cardBase.save(w)
|
||||
}
|
||||
|
||||
func (c *cardSaturn) load(r io.Reader) {
|
||||
|
@ -177,4 +178,5 @@ func (c *cardSaturn) load(r io.Reader) {
|
|||
|
||||
c.applyState()
|
||||
}
|
||||
c.cardBase.load(r)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user