Proper Go error management

This commit is contained in:
Ivan Izaguirre 2019-10-06 01:26:00 +02:00
parent b1b55f4c0b
commit f92bc2b08e
22 changed files with 486 additions and 178 deletions

View File

@ -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() {

View File

@ -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

View File

@ -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)

View File

@ -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 [\]^_

View File

@ -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) {

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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) {

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

@ -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{

View File

@ -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
}

View File

@ -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) {

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {