From 48afaa471b64eb8b94a804e0a925d536b472fe93 Mon Sep 17 00:00:00 2001 From: Ivan Izaguirre Date: Sat, 6 Jun 2020 14:10:27 +0200 Subject: [PATCH] Support PO ProDOS ordered disk files --- README.md | 4 ++-- diskette.go | 20 ++++++++++------ fileNib.go | 69 ++++++++++++++++++++++++++++------------------------- 3 files changed, 51 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 83ce3af..4ea46c1 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,7 @@ Portable emulator of an Apple II+ or //e. Written in Go. - Apple //e enhanced with 128Kb of RAM - Base64A clone with 48Kb of base RAM and paginated ROM - Storage - - 16 Sector diskettes in NIB format - - 16 Sector diskettes in DSK format + - 16 Sector diskettes in NIB, DSK or PO format - 16 Sector diskettes in WOZ 1.0 or 2.0 format (read only) - Hard disk with ProDOS and SmartPort support - Emulated extension cards: @@ -46,6 +45,7 @@ Portable emulator of an Apple II+ or //e. Written in Go. - Adjustable speed. - Fast disk mode to set max speed while using the disks. - Single file executable with embedded ROMs and DOS 3.3 + - Pause (thanks a2geek) ## Running the emulator diff --git a/diskette.go b/diskette.go index 7fd0363..ba1f160 100644 --- a/diskette.go +++ b/diskette.go @@ -1,6 +1,9 @@ package apple2 -import "errors" +import ( + "errors" + "strings" +) type diskette interface { powerOn(cycle uint64) @@ -15,13 +18,16 @@ func loadDisquette(filename string) (diskette, error) { return nil, err } - if isFileNibOrDsk(data) { - f, err := newFileNibOrDsk(data) - if err != nil { - return nil, err - } + if isFileNib(data) { var d diskette16sector - d.nib = f + d.nib = newFileNib(data) + return &d, nil + } + + if isFileDsk(data) { + isPO := strings.HasSuffix(strings.ToLower(filename), "po") + var d diskette16sector + d.nib = newFileDsk(data, isPO) return &d, nil } diff --git a/fileNib.go b/fileNib.go index 70f8a42..7bcc7d6 100644 --- a/fileNib.go +++ b/fileNib.go @@ -1,7 +1,6 @@ package apple2 import ( - "errors" "os" ) @@ -27,41 +26,38 @@ type fileNib struct { track [numberOfTracks][]byte } -func loadFileNibOrDsk(filename string) (*fileNib, error) { - data, err := loadResource(filename) - if err != nil { - return nil, err - } - - return newFileNibOrDsk(data) +func isFileNib(data []uint8) bool { + return len(data) == nibImageSize } -func isFileNibOrDsk(data []uint8) bool { - size := len(data) - return size == nibImageSize || size == dskImageSize -} - -func newFileNibOrDsk(data []uint8) (*fileNib, error) { +func newFileNib(data []uint8) *fileNib { var f fileNib - size := len(data) - - if size == nibImageSize { - // Load file already in nib format - for i := 0; i < numberOfTracks; i++ { - f.track[i] = data[nibBytesPerTrack*i : nibBytesPerTrack*(i+1)] - } - } else if size == dskImageSize { - // Convert to nib - for i := 0; i < numberOfTracks; i++ { - trackData := data[i*bytesPerTrack : (i+1)*bytesPerTrack] - f.track[i] = nibEncodeTrack(trackData, defaultVolumeTag, byte(i)) - } - } else { - return nil, errors.New("Invalid disk size") + for i := 0; i < numberOfTracks; i++ { + f.track[i] = data[nibBytesPerTrack*i : nibBytesPerTrack*(i+1)] } - return &f, nil + return &f +} + +func isFileDsk(data []uint8) bool { + return len(data) == dskImageSize +} + +func newFileDsk(data []uint8, isPO bool) *fileNib { + var f fileNib + + logicalOrder := dos33SectorsLogicalOrder + if isPO { + logicalOrder = prodosSectorsLogicalOrder + } + + for i := 0; i < numberOfTracks; i++ { + trackData := data[i*bytesPerTrack : (i+1)*bytesPerTrack] + f.track[i] = nibEncodeTrack(trackData, defaultVolumeTag, byte(i), &logicalOrder) + } + + return &f } func (f *fileNib) saveNib(filename string) error { @@ -81,11 +77,18 @@ func (f *fileNib) saveNib(filename string) error { return nil } -var dos33SectorsLogicOrder = [16]int{ +// See Beneath Apple DOS, figure 3.24 +var dos33SectorsLogicalOrder = [16]int{ 0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4, 0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF, } +// See Beneath Apple ProDOS, figure 3.1 +var prodosSectorsLogicalOrder = [16]int{ + 0x0, 0x8, 0x1, 0x9, 0x2, 0xA, 0x3, 0xB, + 0x4, 0xC, 0x5, 0xD, 0x6, 0xE, 0x7, 0xF, +} + var sixAndTwoTranslateTable = [0x40]byte{ 0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6, 0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3, @@ -118,7 +121,7 @@ func oddEvenEncodeByte(b byte) []byte { return e } -func nibEncodeTrack(data []byte, volume byte, track byte) []byte { +func nibEncodeTrack(data []byte, volume byte, track byte, logicalOrder *[16]int) []byte { b := make([]byte, 0, nibBytesPerTrack) // Buffer slice with enough capacity // Initialize gaps to be copied for each sector gap1 := make([]byte, gap1Len) @@ -134,7 +137,7 @@ func nibEncodeTrack(data []byte, volume byte, track byte) []byte { but on the physical encoded track as well as in the nib files they are in phisical order. */ - logicalSector := dos33SectorsLogicOrder[physicalSector] + logicalSector := logicalOrder[physicalSector] sectorData := data[logicalSector*bytesPerSector : (logicalSector+1)*bytesPerSector] // 6and2 prenibbilizing.