Proper Go error management
This commit is contained in:
parent
b1b55f4c0b
commit
f92bc2b08e
96
apple2.go
96
apple2.go
|
@ -109,10 +109,16 @@ func (a *Apple2) executeCommand(command int) {
|
|||
a.isColor = !a.isColor
|
||||
case CommandSaveState:
|
||||
fmt.Println("Saving state")
|
||||
a.save("apple2.state")
|
||||
err := a.save("apple2.state")
|
||||
if err != nil {
|
||||
fmt.Printf("Error loadind state: %v.", err)
|
||||
}
|
||||
case CommandLoadState:
|
||||
fmt.Println("Loading state")
|
||||
a.load("apple2.state")
|
||||
err := a.load("apple2.state")
|
||||
if err != nil {
|
||||
fmt.Printf("Error loadind state: %v.", err)
|
||||
}
|
||||
case CommandDumpDebugInfo:
|
||||
a.dumpDebugInfo()
|
||||
case CommandNextCharGenPage:
|
||||
|
@ -137,55 +143,99 @@ func (a *Apple2) releaseFastMode() {
|
|||
}
|
||||
|
||||
type persistent interface {
|
||||
save(io.Writer)
|
||||
load(io.Reader)
|
||||
save(io.Writer) error
|
||||
load(io.Reader) error
|
||||
}
|
||||
|
||||
func (a *Apple2) save(filename string) {
|
||||
func (a *Apple2) save(filename string) error {
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return 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)
|
||||
err = a.cpu.Save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = a.mmu.save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = a.io.save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, a.isColor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, a.fastMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, a.fastRequestsCounter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, c := range a.cards {
|
||||
if c != nil {
|
||||
c.save(w)
|
||||
err = c.save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Apple2) load(filename string) {
|
||||
func (a *Apple2) load(filename string) error {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
// Ignore error if can't load the file
|
||||
return
|
||||
return err
|
||||
}
|
||||
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)
|
||||
err = a.cpu.Load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = a.mmu.load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = a.io.load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &a.isColor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &a.fastMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &a.fastRequestsCounter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, c := range a.cards {
|
||||
if c != nil {
|
||||
c.load(r)
|
||||
err = c.load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Apple2) dumpDebugInfo() {
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
package apple2
|
||||
|
||||
import "github.com/ivanizag/apple2/core6502"
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/ivanizag/apple2/core6502"
|
||||
)
|
||||
|
||||
// NewApple2 instantiates an apple2
|
||||
func NewApple2(charRomFile string, clockMhz float64,
|
||||
isColor bool, fastMode bool) *Apple2 {
|
||||
func NewApple2(clockMhz float64, isColor bool, fastMode bool) *Apple2 {
|
||||
|
||||
var a Apple2
|
||||
a.Name = "Apple ][+"
|
||||
a.mmu = newMemoryManager(&a)
|
||||
a.cpu = core6502.NewNMOS6502(a.mmu)
|
||||
if charRomFile != "" {
|
||||
a.cg = NewCharacterGenerator(charRomFile)
|
||||
}
|
||||
a.commandChannel = make(chan int, 100)
|
||||
a.isColor = isColor
|
||||
a.fastMode = fastMode
|
||||
|
@ -42,11 +42,15 @@ const (
|
|||
)
|
||||
|
||||
// LoadRom loads a standard Apple2+ or 2e ROM
|
||||
func (a *Apple2) LoadRom(filename string) {
|
||||
data := loadResource(filename)
|
||||
func (a *Apple2) LoadRom(filename string) error {
|
||||
data, err := loadResource(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
size := len(data)
|
||||
if size != apple2RomSize && size != apple2eRomSize {
|
||||
panic("Rom size not supported")
|
||||
return errors.New("Rom size not supported")
|
||||
}
|
||||
|
||||
romStart := 0
|
||||
|
@ -62,29 +66,42 @@ func (a *Apple2) LoadRom(filename string) {
|
|||
|
||||
mmu.physicalROM = newMemoryRange(0xd000, data[romStart:])
|
||||
mmu.resetRomPaging()
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddDisk2 inserts a DiskII controller
|
||||
func (a *Apple2) AddDisk2(slot int, diskRomFile string, diskImage string) {
|
||||
func (a *Apple2) AddDisk2(slot int, diskRomFile string, diskImage string) error {
|
||||
var c cardDisk2
|
||||
c.loadRom(loadResource(diskRomFile))
|
||||
data, err := loadResource(diskRomFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.loadRom(data)
|
||||
a.insertCard(&c, slot)
|
||||
|
||||
if diskImage != "" {
|
||||
diskette := loadDisquette(diskImage)
|
||||
//diskette.saveNib(diskImage + "bak")
|
||||
diskette, err := loadDisquette(diskImage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.drive[0].insertDiskette(diskette)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddHardDisk adds a ProDos hard dirve with a 2MG image
|
||||
func (a *Apple2) AddHardDisk(slot int, hdImage string) {
|
||||
func (a *Apple2) AddHardDisk(slot int, hdImage string) error {
|
||||
var c cardHardDisk
|
||||
c.loadRom(buildHardDiskRom(slot))
|
||||
a.insertCard(&c, slot)
|
||||
|
||||
hd := openHardDisk2mg(hdImage)
|
||||
hd, err := openHardDisk2mg(hdImage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.addDisk(hd)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddLanguageCard inserts a 16Kb card
|
||||
|
@ -98,10 +115,15 @@ func (a *Apple2) AddSaturnCard(slot int) {
|
|||
}
|
||||
|
||||
// AddThunderClockPlusCard inserts a ThunderClock Plus clock card
|
||||
func (a *Apple2) AddThunderClockPlusCard(slot int, romFile string) {
|
||||
func (a *Apple2) AddThunderClockPlusCard(slot int, romFile string) error {
|
||||
var c cardThunderClockPlus
|
||||
c.loadRom(loadResource(romFile))
|
||||
data, err := loadResource(romFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.loadRom(data)
|
||||
a.insertCard(&c, slot)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddCardLogger inserts a fake card that logs accesses
|
||||
|
|
|
@ -88,16 +88,27 @@ func MainApple() *Apple2 {
|
|||
)
|
||||
flag.Parse()
|
||||
|
||||
a := NewApple2(*charRomFile, *cpuClock, !*mono, *fastDisk)
|
||||
a := NewApple2(*cpuClock, !*mono, *fastDisk)
|
||||
|
||||
a.cpu.SetTrace(*traceCPU)
|
||||
a.io.setTrace(*traceSS)
|
||||
a.io.setPanicNotImplemented(*panicSS)
|
||||
|
||||
if *charRomFile != "" {
|
||||
cg, err := NewCharacterGenerator(*charRomFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
a.cg = cg
|
||||
}
|
||||
|
||||
if *base64a {
|
||||
NewBase64a(a)
|
||||
} else {
|
||||
a.LoadRom(*romFile)
|
||||
err := a.LoadRom(*romFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
if *languageCardSlot >= 0 {
|
||||
a.AddLanguageCard(*languageCardSlot)
|
||||
|
@ -106,17 +117,26 @@ func MainApple() *Apple2 {
|
|||
a.AddSaturnCard(*saturnCardSlot)
|
||||
}
|
||||
if *thunderClockCardSlot > 0 {
|
||||
a.AddThunderClockPlusCard(*thunderClockCardSlot, "<internal>/ThunderclockPlusROM.bin")
|
||||
err := a.AddThunderClockPlusCard(*thunderClockCardSlot, "<internal>/ThunderclockPlusROM.bin")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
if *disk2Slot > 0 {
|
||||
a.AddDisk2(*disk2Slot, *disk2RomFile, *diskImage)
|
||||
err := a.AddDisk2(*disk2Slot, *disk2RomFile, *diskImage)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
if *hardDiskImage != "" {
|
||||
if *hardDiskSlot <= 0 {
|
||||
// If there is a hard disk image, but no slot assigned, use slot 7.
|
||||
*hardDiskSlot = 7
|
||||
}
|
||||
a.AddHardDisk(*hardDiskSlot, *hardDiskImage)
|
||||
err := a.AddHardDisk(*hardDiskSlot, *hardDiskImage)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
//a.AddCardInOut(2)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/ivanizag/apple2"
|
||||
|
@ -106,7 +107,12 @@ func (k *sdlKeyboard) putKey(keyEvent *sdl.KeyboardEvent) {
|
|||
case sdl.K_F11:
|
||||
k.a.SendCommand(apple2.CommandToggleCPUTrace)
|
||||
case sdl.K_F12:
|
||||
apple2.SaveSnapshot(k.a, "snapshot.png")
|
||||
err := apple2.SaveSnapshot(k.a, "snapshot.png")
|
||||
if err != nil {
|
||||
fmt.Printf("Error saving snapshoot: %v.\n.", err)
|
||||
} else {
|
||||
fmt.Println("Saving snapshot")
|
||||
}
|
||||
}
|
||||
|
||||
// Missing values 91 to 95. Usually control for [\]^_
|
||||
|
|
22
base64a.go
22
base64a.go
|
@ -14,20 +14,26 @@ type Base64a struct {
|
|||
}
|
||||
|
||||
// NewBase64a instantiates an apple2
|
||||
func NewBase64a(a *Apple2) *Base64a {
|
||||
func NewBase64a(a *Apple2) (*Base64a, error) {
|
||||
var b Base64a
|
||||
b.a = a
|
||||
a.Name = "Base 64A"
|
||||
b.loadRom()
|
||||
err := b.loadRom()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Configure the character generator
|
||||
if !a.cg.customRom {
|
||||
a.cg.load("<internal>/BASE64A_ROM7_CharGen.BIN")
|
||||
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
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
func base64aCharGenColumnsMap(column int) int {
|
||||
|
@ -50,7 +56,7 @@ const (
|
|||
base64aRomChipCount = 6
|
||||
)
|
||||
|
||||
func (b *Base64a) loadRom() {
|
||||
func (b *Base64a) loadRom() error {
|
||||
// Load the 6 PROM dumps
|
||||
romBanksBytes := make([][]uint8, base64aRomBankCount)
|
||||
for j := range romBanksBytes {
|
||||
|
@ -59,7 +65,10 @@ func (b *Base64a) loadRom() {
|
|||
|
||||
for i := 0; i < base64aRomChipCount; i++ {
|
||||
filename := fmt.Sprintf("<internal>/BASE64A_%X.BIN", 0xd0+i*0x08)
|
||||
data := loadResource(filename)
|
||||
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]...)
|
||||
|
@ -101,6 +110,7 @@ func (b *Base64a) loadRom() {
|
|||
speakerSoftSwitch(io)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Base64a) changeRomBank(bank uint8) {
|
||||
|
|
|
@ -21,7 +21,7 @@ type cardBase struct {
|
|||
|
||||
func (c *cardBase) loadRom(data []uint8) {
|
||||
if c.a != nil {
|
||||
panic("Rom must be loaded before inserting the card in the slot")
|
||||
panic("Assert failed. Rom must be loaded before inserting the card in the slot")
|
||||
}
|
||||
if len(data) >= 0x100 {
|
||||
c.rom = newMemoryRange(0, data)
|
||||
|
@ -50,10 +50,12 @@ func (c *cardBase) assign(a *Apple2, slot int) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *cardBase) save(w io.Writer) {
|
||||
func (c *cardBase) save(w io.Writer) error {
|
||||
// Empty
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *cardBase) load(r io.Reader) {
|
||||
func (c *cardBase) load(r io.Reader) error {
|
||||
// Empty
|
||||
return nil
|
||||
}
|
||||
|
|
112
cardDisk2.go
112
cardDisk2.go
|
@ -169,34 +169,98 @@ func (d *cardDisk2Drive) insertDiskette(dt *diskette16sector) {
|
|||
d.diskette = dt
|
||||
}
|
||||
|
||||
func (c *cardDisk2) save(w io.Writer) {
|
||||
binary.Write(w, binary.BigEndian, c.selected)
|
||||
binary.Write(w, binary.BigEndian, c.dataLatch)
|
||||
binary.Write(w, binary.BigEndian, c.q6)
|
||||
binary.Write(w, binary.BigEndian, c.q7)
|
||||
c.drive[0].save(w)
|
||||
c.drive[1].save(w)
|
||||
func (c *cardDisk2) save(w io.Writer) error {
|
||||
err := binary.Write(w, binary.BigEndian, c.selected)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, c.dataLatch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, c.q6)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, c.q7)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.drive[0].save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.drive[1].save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.cardBase.save(w)
|
||||
}
|
||||
|
||||
func (c *cardDisk2) load(r io.Reader) {
|
||||
binary.Read(r, binary.BigEndian, &c.selected)
|
||||
binary.Read(r, binary.BigEndian, &c.dataLatch)
|
||||
binary.Read(r, binary.BigEndian, &c.q6)
|
||||
binary.Read(r, binary.BigEndian, &c.q7)
|
||||
c.drive[0].load(r)
|
||||
c.drive[1].load(r)
|
||||
func (c *cardDisk2) load(r io.Reader) error {
|
||||
err := binary.Read(r, binary.BigEndian, &c.selected)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &c.dataLatch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &c.q6)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &c.q7)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.drive[0].load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.drive[1].load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.cardBase.load(r)
|
||||
}
|
||||
|
||||
func (d *cardDisk2Drive) save(w io.Writer) {
|
||||
binary.Write(w, binary.BigEndian, d.currentPhase)
|
||||
binary.Write(w, binary.BigEndian, d.power)
|
||||
binary.Write(w, binary.BigEndian, d.halfTrack)
|
||||
binary.Write(w, binary.BigEndian, d.position)
|
||||
func (d *cardDisk2Drive) save(w io.Writer) error {
|
||||
err := binary.Write(w, binary.BigEndian, d.currentPhase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, d.power)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, d.halfTrack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, d.position)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *cardDisk2Drive) load(r io.Reader) {
|
||||
binary.Read(r, binary.BigEndian, &d.currentPhase)
|
||||
binary.Read(r, binary.BigEndian, &d.power)
|
||||
binary.Read(r, binary.BigEndian, &d.halfTrack)
|
||||
binary.Read(r, binary.BigEndian, &d.position)
|
||||
func (d *cardDisk2Drive) load(r io.Reader) error {
|
||||
err := binary.Read(r, binary.BigEndian, &d.currentPhase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &d.power)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &d.halfTrack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &d.position)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -96,7 +96,8 @@ func (c *cardHardDisk) assign(a *Apple2, slot int) {
|
|||
case proDosDeviceCommandWrite:
|
||||
return c.writeBlock(block, address)
|
||||
default:
|
||||
panic("Prodos device command not supported.")
|
||||
// Prodos device command not supported
|
||||
return proDosDeviceErrorIO
|
||||
}
|
||||
}
|
||||
c.ssr[1] = func(*ioC0Page) uint8 {
|
||||
|
|
|
@ -75,7 +75,7 @@ func (c *cardInOut) assign(a *Apple2, slot int) {
|
|||
|
||||
if slot != 2 {
|
||||
// To make ifwork on other slots, patch C2, A0 and A1
|
||||
panic("Only slot 2 supported for the InOut card")
|
||||
panic("Assert failed. Only slot 2 supported for the InOut card")
|
||||
}
|
||||
c.cardBase.assign(a, slot)
|
||||
}
|
||||
|
|
|
@ -128,25 +128,61 @@ func (c *cardLanguage) applyState() {
|
|||
|
||||
}
|
||||
|
||||
func (c *cardLanguage) save(w io.Writer) {
|
||||
binary.Write(w, binary.BigEndian, c.readState)
|
||||
binary.Write(w, binary.BigEndian, c.writeState)
|
||||
binary.Write(w, binary.BigEndian, c.activeBank)
|
||||
c.ramBankA.save(w)
|
||||
c.ramBankB.save(w)
|
||||
c.ramUpper.save(w)
|
||||
func (c *cardLanguage) save(w io.Writer) error {
|
||||
err := binary.Write(w, binary.BigEndian, c.readState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, c.writeState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, c.activeBank)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramBankA.save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramBankB.save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramUpper.save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.cardBase.save(w)
|
||||
return c.cardBase.save(w)
|
||||
}
|
||||
|
||||
func (c *cardLanguage) load(r io.Reader) {
|
||||
binary.Read(r, binary.BigEndian, &c.readState)
|
||||
binary.Read(r, binary.BigEndian, &c.writeState)
|
||||
binary.Read(r, binary.BigEndian, &c.activeBank)
|
||||
c.ramBankA.load(r)
|
||||
c.ramBankB.load(r)
|
||||
c.ramUpper.load(r)
|
||||
func (c *cardLanguage) load(r io.Reader) error {
|
||||
err := binary.Read(r, binary.BigEndian, &c.readState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &c.writeState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &c.activeBank)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramBankA.load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramBankB.load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramUpper.load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.applyState()
|
||||
c.cardBase.load(r)
|
||||
return c.cardBase.load(r)
|
||||
}
|
||||
|
|
|
@ -153,30 +153,69 @@ func (c *cardSaturn) applyState() {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *cardSaturn) save(w io.Writer) {
|
||||
func (c *cardSaturn) save(w io.Writer) error {
|
||||
for i := 0; i < saturnBlocks; i++ {
|
||||
binary.Write(w, binary.BigEndian, c.readState)
|
||||
binary.Write(w, binary.BigEndian, c.writeState)
|
||||
binary.Write(w, binary.BigEndian, c.activeBank)
|
||||
binary.Write(w, binary.BigEndian, c.activeBlock)
|
||||
c.ramBankA[i].save(w)
|
||||
c.ramBankB[i].save(w)
|
||||
c.ramUpper[i].save(w)
|
||||
err := binary.Write(w, binary.BigEndian, c.readState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, c.writeState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, c.activeBank)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, c.activeBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramBankA[i].save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramBankB[i].save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramUpper[i].save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.cardBase.save(w)
|
||||
return c.cardBase.save(w)
|
||||
}
|
||||
|
||||
func (c *cardSaturn) load(r io.Reader) {
|
||||
func (c *cardSaturn) load(r io.Reader) error {
|
||||
for i := 0; i < saturnBlocks; i++ {
|
||||
binary.Read(r, binary.BigEndian, &c.readState)
|
||||
binary.Read(r, binary.BigEndian, &c.writeState)
|
||||
binary.Read(r, binary.BigEndian, &c.activeBank)
|
||||
binary.Read(r, binary.BigEndian, &c.activeBlock)
|
||||
c.ramBankA[i].load(r)
|
||||
c.ramBankB[i].load(r)
|
||||
c.ramUpper[i].load(r)
|
||||
err := binary.Read(r, binary.BigEndian, &c.readState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &c.writeState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &c.activeBank)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &c.activeBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramBankA[i].load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramBankB[i].load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ramUpper[i].load(r)
|
||||
|
||||
c.applyState()
|
||||
}
|
||||
c.cardBase.load(r)
|
||||
return c.cardBase.load(r)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package apple2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
|
@ -25,20 +26,27 @@ const (
|
|||
)
|
||||
|
||||
// NewCharacterGenerator instantiates a new Character Generator with the rom on the file given
|
||||
func NewCharacterGenerator(filename string) *CharacterGenerator {
|
||||
func NewCharacterGenerator(filename string) (*CharacterGenerator, error) {
|
||||
var cg CharacterGenerator
|
||||
cg.load(filename)
|
||||
return &cg
|
||||
err := cg.load(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cg, nil
|
||||
}
|
||||
|
||||
func (cg *CharacterGenerator) load(filename string) {
|
||||
func (cg *CharacterGenerator) load(filename string) error {
|
||||
cg.customRom = !isInternalResource(filename)
|
||||
bytes := loadResource(filename)
|
||||
bytes, err := loadResource(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
size := len(bytes)
|
||||
if size < rev7CharGenSize {
|
||||
panic("Character ROM size not supported")
|
||||
return errors.New("Character ROM size not supported")
|
||||
}
|
||||
cg.data = bytes
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cg *CharacterGenerator) setColumnMap(columnMap charColumnMap) {
|
||||
|
|
|
@ -96,7 +96,7 @@ func resolve(s *State, line []uint8, opcode opcode) (getValue func() uint8, setV
|
|||
} else if register != regNone {
|
||||
s.reg.setRegister(register, value)
|
||||
} else {
|
||||
panic("Should never happen")
|
||||
panic("Assert failed. Should never happen")
|
||||
}
|
||||
}
|
||||
return
|
||||
|
|
|
@ -85,15 +85,29 @@ func (s *State) GetCycles() uint64 {
|
|||
}
|
||||
|
||||
// Save saves the CPU state (registers and cycle counter)
|
||||
func (s *State) Save(w io.Writer) {
|
||||
binary.Write(w, binary.BigEndian, s.cycles)
|
||||
func (s *State) Save(w io.Writer) error {
|
||||
err := binary.Write(w, binary.BigEndian, s.cycles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
binary.Write(w, binary.BigEndian, s.reg.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load loads the CPU state (registers and cycle counter)
|
||||
func (s *State) Load(r io.Reader) {
|
||||
binary.Read(r, binary.BigEndian, &s.cycles)
|
||||
binary.Read(r, binary.BigEndian, &s.reg.data)
|
||||
func (s *State) Load(r io.Reader) error {
|
||||
err := binary.Read(r, binary.BigEndian, &s.cycles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &s.reg.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lineString(line []uint8, opcode opcode) string {
|
||||
|
|
|
@ -31,13 +31,15 @@ func (m *FlatMemory) Poke(address uint16, value uint8) {
|
|||
m.data[address] = value
|
||||
}
|
||||
|
||||
func (m *FlatMemory) loadBinary(filename string) {
|
||||
func (m *FlatMemory) loadBinary(filename string) error {
|
||||
bytes, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
|
||||
for i, v := range bytes {
|
||||
m.Poke(uint16(i), uint8(v))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package apple2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
|
@ -36,10 +37,13 @@ func (d *diskette16sector) write(track int, position int, value uint8) int {
|
|||
return (position + 1) % nibBytesPerTrack
|
||||
}
|
||||
|
||||
func loadDisquette(filename string) *diskette16sector {
|
||||
func loadDisquette(filename string) (*diskette16sector, error) {
|
||||
var d diskette16sector
|
||||
|
||||
data := loadResource(filename)
|
||||
data, err := loadResource(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
size := len(data)
|
||||
|
||||
if size == nibImageSize {
|
||||
|
@ -54,25 +58,27 @@ func loadDisquette(filename string) *diskette16sector {
|
|||
d.track[i] = nibEncodeTrack(trackData, defaultVolumeTag, byte(i))
|
||||
}
|
||||
} else {
|
||||
panic("Invalid disk size")
|
||||
return nil, errors.New("Invalid disk size")
|
||||
}
|
||||
|
||||
return &d
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
func (d *diskette16sector) saveNib(filename string) {
|
||||
func (d *diskette16sector) saveNib(filename string) error {
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
for _, v := range d.track {
|
||||
_, err := f.Write(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var dos33SectorsLogicOrder = [16]int{
|
||||
|
|
29
hardDisk.go
29
hardDisk.go
|
@ -76,7 +76,7 @@ func (hd *hardDisk) write(block uint32, data []uint8) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func openHardDisk2mg(filename string) *hardDisk {
|
||||
func openHardDisk2mg(filename string) (*hardDisk, error) {
|
||||
var hd hardDisk
|
||||
|
||||
hd.readOnly = false
|
||||
|
@ -87,44 +87,49 @@ func openHardDisk2mg(filename string) *hardDisk {
|
|||
file, err = os.OpenFile(filename, os.O_RDONLY, 0)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
hd.file = file
|
||||
|
||||
fileInfo, err := hd.file.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
minHeaderSize := binary.Size(&hd.header)
|
||||
if fileInfo.Size() < int64(minHeaderSize) {
|
||||
panic("Invalid 2MG file")
|
||||
return nil, errors.New("Invalid 2MG file")
|
||||
}
|
||||
|
||||
readHeader(hd.file, &hd.header)
|
||||
err = readHeader(hd.file, &hd.header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if fileInfo.Size() < int64(hd.header.OffsetData+hd.header.Blocks*proDosBlockSize) {
|
||||
panic("Thr 2MG file is too small")
|
||||
return nil, errors.New("Thr 2MG file is too small")
|
||||
}
|
||||
|
||||
return &hd
|
||||
return &hd, nil
|
||||
}
|
||||
|
||||
func readHeader(buf io.Reader, header *hardDisk2mgHeader) {
|
||||
func readHeader(buf io.Reader, header *hardDisk2mgHeader) error {
|
||||
err := binary.Read(buf, binary.LittleEndian, header)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if header.Preamble != hardDisk2mgPreamble {
|
||||
panic("2mg file must start with '2IMG'")
|
||||
return errors.New("2mg file must start with '2IMG'")
|
||||
}
|
||||
|
||||
if header.Format != hardDisk2mgFormatProdos {
|
||||
panic("Only prodos hard disks are supported")
|
||||
return errors.New("Only prodos hard disks are supported")
|
||||
}
|
||||
|
||||
if header.Version != hardDisk2mgVersion {
|
||||
panic("Version of 2MG image not supported")
|
||||
return errors.New("Version of 2MG image not supported")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -67,12 +67,12 @@ func (p *ioC0Page) setPanicNotImplemented(value bool) {
|
|||
p.panicNotImplemented = value
|
||||
}
|
||||
|
||||
func (p *ioC0Page) save(w io.Writer) {
|
||||
binary.Write(w, binary.BigEndian, p.softSwitchesData)
|
||||
func (p *ioC0Page) save(w io.Writer) error {
|
||||
return binary.Write(w, binary.BigEndian, p.softSwitchesData)
|
||||
}
|
||||
|
||||
func (p *ioC0Page) load(r io.Reader) {
|
||||
binary.Read(r, binary.BigEndian, &p.softSwitchesData)
|
||||
func (p *ioC0Page) load(r io.Reader) error {
|
||||
return binary.Read(r, binary.BigEndian, &p.softSwitchesData)
|
||||
}
|
||||
|
||||
func (p *ioC0Page) addSoftSwitchRW(address uint8, ss softSwitchR) {
|
||||
|
|
|
@ -141,16 +141,29 @@ func newMemoryManager(a *Apple2) *memoryManager {
|
|||
return &mmu
|
||||
}
|
||||
|
||||
func (mmu *memoryManager) save(w io.Writer) {
|
||||
mmu.physicalMainRAM.save(w)
|
||||
binary.Write(w, binary.BigEndian, mmu.activeSlot)
|
||||
|
||||
func (mmu *memoryManager) save(w io.Writer) error {
|
||||
err := mmu.physicalMainRAM.save(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, mmu.activeSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mmu *memoryManager) load(r io.Reader) {
|
||||
mmu.physicalMainRAM.load(r)
|
||||
binary.Read(r, binary.BigEndian, &mmu.activeSlot)
|
||||
func (mmu *memoryManager) load(r io.Reader) error {
|
||||
err := mmu.physicalMainRAM.load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &mmu.activeSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mmu.activateCardRomExtra(mmu.activeSlot)
|
||||
|
||||
mmu.resetBaseRamPaging()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -29,12 +29,26 @@ func (m *memoryRange) subRange(a, b uint16) []uint8 {
|
|||
return m.data[a-m.base : b-m.base]
|
||||
}
|
||||
|
||||
func (m *memoryRange) save(w io.Writer) {
|
||||
binary.Write(w, binary.BigEndian, m.base)
|
||||
binary.Write(w, binary.BigEndian, m.data)
|
||||
func (m *memoryRange) save(w io.Writer) error {
|
||||
err := binary.Write(w, binary.BigEndian, m.base)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, m.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryRange) load(r io.Reader) {
|
||||
binary.Read(r, binary.BigEndian, &m.base)
|
||||
binary.Read(r, binary.BigEndian, &m.data)
|
||||
func (m *memoryRange) load(r io.Reader) error {
|
||||
err := binary.Read(r, binary.BigEndian, &m.base)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &m.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
12
resources.go
12
resources.go
|
@ -25,14 +25,14 @@ func isHTTPResource(filename string) bool {
|
|||
strings.HasPrefix(filename, httpsPrefix)
|
||||
}
|
||||
|
||||
func loadResource(filename string) []uint8 {
|
||||
func loadResource(filename string) ([]uint8, error) {
|
||||
var file io.Reader
|
||||
if isInternalResource(filename) {
|
||||
// load from embedded resource
|
||||
resource := strings.TrimPrefix(filename, internalPrefix)
|
||||
resourceFile, err := romdumps.Assets.Open(resource)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
defer resourceFile.Close()
|
||||
file = resourceFile
|
||||
|
@ -40,7 +40,7 @@ func loadResource(filename string) []uint8 {
|
|||
} else if isHTTPResource(filename) {
|
||||
response, err := http.Get(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
file = response.Body
|
||||
|
@ -48,7 +48,7 @@ func loadResource(filename string) []uint8 {
|
|||
} else {
|
||||
diskFile, err := os.Open(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
defer diskFile.Close()
|
||||
file = diskFile
|
||||
|
@ -56,7 +56,7 @@ func loadResource(filename string) []uint8 {
|
|||
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
return data
|
||||
return data, nil
|
||||
}
|
||||
|
|
10
screen.go
10
screen.go
|
@ -96,22 +96,18 @@ func mixSnapshots(top, bottom *image.RGBA) *image.RGBA {
|
|||
}
|
||||
|
||||
// SaveSnapshot saves a snapshot of the screen to a png file
|
||||
func SaveSnapshot(a *Apple2, filename string) {
|
||||
func SaveSnapshot(a *Apple2, filename string) error {
|
||||
img := Snapshot(a)
|
||||
if img == nil {
|
||||
return
|
||||
}
|
||||
img = squarishPixelsFilter(img)
|
||||
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fmt.Println("Saving snapshot")
|
||||
|
||||
png.Encode(f, img)
|
||||
return nil
|
||||
}
|
||||
|
||||
func squarishPixelsFilter(in *image.RGBA) *image.RGBA {
|
||||
|
|
Loading…
Reference in New Issue