diff --git a/apple2Setup.go b/apple2Setup.go index ed802f4..735b31e 100644 --- a/apple2Setup.go +++ b/apple2Setup.go @@ -105,9 +105,7 @@ func (a *Apple2) AddDisk2(slot int, diskRomFile string, diskImage string) error a.insertCard(&c, slot) if diskImage != "" { - //diskette, err := loadDisquette(diskImage) - //diskette, err := loadDisquetteTimed(diskImage) - diskette, err := loadDisquetteWoz(diskImage) + diskette, err := loadDisquette(diskImage) if err != nil { return err } diff --git a/cardDisk2.go b/cardDisk2.go index 96343c2..cd7d186 100644 --- a/cardDisk2.go +++ b/cardDisk2.go @@ -39,13 +39,6 @@ type cardDisk2Drive struct { tracksStep int // Stepmotor for tracks position. 4 steps per track } -type diskette interface { - powerOn(cycle uint64) - powerOff(cycle uint64) - read(quarterTrack int, cycle uint64) uint8 - write(quarterTrack int, value uint8, cycle uint64) -} - const ( diskBitCycle = 4 // There is a dataLatch bit transferred every 4 cycles diskLatchReadCycles = 7 // Loaded data is available for a little more than 7ns diff --git a/diskette.go b/diskette.go new file mode 100644 index 0000000..7fd0363 --- /dev/null +++ b/diskette.go @@ -0,0 +1,38 @@ +package apple2 + +import "errors" + +type diskette interface { + powerOn(cycle uint64) + powerOff(cycle uint64) + read(quarterTrack int, cycle uint64) uint8 + write(quarterTrack int, value uint8, cycle uint64) +} + +func loadDisquette(filename string) (diskette, error) { + data, err := loadResource(filename) + if err != nil { + return nil, err + } + + if isFileNibOrDsk(data) { + f, err := newFileNibOrDsk(data) + if err != nil { + return nil, err + } + var d diskette16sector + d.nib = f + return &d, nil + } + + if isFileWoz(data) { + f, err := newFileWoz(data) + if err != nil { + return nil, err + } + + return newDisquetteWoz(f) + } + + return nil, errors.New("Diskette format not supported") +} diff --git a/diskette16sector.go b/diskette16sector.go index 9d2fc16..ada315c 100644 --- a/diskette16sector.go +++ b/diskette16sector.go @@ -11,6 +11,12 @@ type diskette16sector struct { position int } +func newDisquette16Sector(f *fileNib) *diskette16sector { + var d diskette16sector + d.nib = f + return &d +} + func (d *diskette16sector) powerOn(cycle uint64) { // Not used } @@ -31,14 +37,3 @@ func (d *diskette16sector) write(quarterTrack int, value uint8, _ uint64) { d.nib.track[track][d.position] = value d.position = (d.position + 1) % nibBytesPerTrack } - -func loadDisquette(filename string) (*diskette16sectorTimed, error) { - var d diskette16sectorTimed - - f, err := loadNibOrDsk(filename) - if err != nil { - return nil, err - } - d.nib = f - return &d, nil -} diff --git a/diskette16sectorTimed.go b/diskette16sectorTimed.go index c659c7d..a3df441 100644 --- a/diskette16sectorTimed.go +++ b/diskette16sectorTimed.go @@ -5,6 +5,12 @@ type diskette16sectorTimed struct { cycleOn uint64 // Cycle when the disk was last turned on } +func newDisquette16SectorTimed(f *fileNib) *diskette16sectorTimed { + var d diskette16sectorTimed + d.nib = f + return &d +} + func (d *diskette16sectorTimed) powerOn(cycle uint64) { d.cycleOn = cycle } @@ -38,15 +44,3 @@ func (d *diskette16sectorTimed) read(quarterTrack int, cycle uint64) uint8 { func (d *diskette16sectorTimed) write(quarterTrack int, value uint8, _ uint64) { panic("Write not implemented on time based disk implementation") } - -func loadDisquetteTimed(filename string) (*diskette16sectorTimed, error) { - var d diskette16sectorTimed - - f, err := loadNibOrDsk(filename) - if err != nil { - return nil, err - } - d.nib = f - - return &d, nil -} diff --git a/disketteWoz.go b/disketteWoz.go index 5cf6c87..418d326 100644 --- a/disketteWoz.go +++ b/disketteWoz.go @@ -1,6 +1,9 @@ package apple2 -import "math/rand" +import ( + "errors" + "math/rand" +) /* See: @@ -32,7 +35,10 @@ Emulation status for the disk used on the reference: - What is the lifespan of the data latch? - *** First Math Adventures - Understanding Word Problems - Reading Offset Data Streams - - Border Zone: Unknown, there is no UI to swap disks + - *** Wings of Fury: Not working + - Stickybear Town Builder: Working + - Optimal bit timing of WOZ 2,0 + - * Border Zone: Unknown, there is no UI to swap disks */ @@ -52,6 +58,20 @@ type disketteWoz struct { visibleLatchCountDown int8 // The visible latch stores a valid latch reading for 2 bit timings } +func newDisquetteWoz(f *fileWoz) (*disketteWoz, error) { + // Discard not supported features + if f.info.DiskType != 1 { + return nil, errors.New("Only 5.25 disks are supported") + } + if f.info.BootSectorFormat == 2 { // Info not available in WOZ 1.0 + return nil, errors.New("Woz 13 sector disks are not supported") + } + + var d disketteWoz + d.data = f + return &d, nil +} + func (d *disketteWoz) powerOn(cycle uint64) { d.turning = true d.cycleOn = cycle @@ -107,15 +127,3 @@ func (d *disketteWoz) read(quarterTrack int, cycle uint64) uint8 { func (d *disketteWoz) write(quarterTrack int, value uint8, _ uint64) { panic("Write not implemented on woz disk implementation") } - -func loadDisquetteWoz(filename string) (*disketteWoz, error) { - var d disketteWoz - - f, err := loadFileWoz(filename) - if err != nil { - return nil, err - } - d.data = f - - return &d, nil -} diff --git a/fileNib.go b/fileNib.go index af027fe..70f8a42 100644 --- a/fileNib.go +++ b/fileNib.go @@ -27,13 +27,23 @@ type fileNib struct { track [numberOfTracks][]byte } -func loadNibOrDsk(filename string) (*fileNib, error) { - var f fileNib - +func loadFileNibOrDsk(filename string) (*fileNib, error) { data, err := loadResource(filename) if err != nil { return nil, err } + + return newFileNibOrDsk(data) +} + +func isFileNibOrDsk(data []uint8) bool { + size := len(data) + return size == nibImageSize || size == dskImageSize +} + +func newFileNibOrDsk(data []uint8) (*fileNib, error) { + var f fileNib + size := len(data) if size == nibImageSize { diff --git a/fileWoz.go b/fileWoz.go index 6978d97..47a62d9 100644 --- a/fileWoz.go +++ b/fileWoz.go @@ -87,13 +87,28 @@ func (f *fileWoz) getBit(position uint32, quarterTrack int) uint8 { } func loadFileWoz(filename string) (*fileWoz, error) { - var f fileWoz - data, err := loadResource(filename) if err != nil { return nil, err } + return newFileWoz(data) +} + +func isFileWoz(data []uint8) bool { + header := data[:len(headerWoz2)] + if bytes.Equal(headerWoz1, header) { + return true + } + if bytes.Equal(headerWoz2, header) { + return true + } + return false +} + +func newFileWoz(data []uint8) (*fileWoz, error) { + var f fileWoz + // Verify header. Note, the CRC is not verified header := data[:len(headerWoz2)] if bytes.Equal(headerWoz1, header) { @@ -192,14 +207,6 @@ func loadFileWoz(filename string) (*fileWoz, error) { return nil, errors.New("Woz version not supported") } - // Discard not supported features - if f.info.DiskType != 1 { - return nil, errors.New("Only 5.25 disks are supported") - } - if f.info.BootSectorFormat == 2 { // Info not available in WOZ 1.0 - return nil, errors.New("Woz 13 sector disks are not supported") - } - return &f, nil }