Support PO ProDOS ordered disk files

This commit is contained in:
Ivan Izaguirre 2020-06-06 14:10:27 +02:00
parent 6e25111224
commit 48afaa471b
3 changed files with 51 additions and 42 deletions

View File

@ -12,8 +12,7 @@ Portable emulator of an Apple II+ or //e. Written in Go.
- Apple //e enhanced with 128Kb of RAM - Apple //e enhanced with 128Kb of RAM
- Base64A clone with 48Kb of base RAM and paginated ROM - Base64A clone with 48Kb of base RAM and paginated ROM
- Storage - Storage
- 16 Sector diskettes in NIB format - 16 Sector diskettes in NIB, DSK or PO format
- 16 Sector diskettes in DSK format
- 16 Sector diskettes in WOZ 1.0 or 2.0 format (read only) - 16 Sector diskettes in WOZ 1.0 or 2.0 format (read only)
- Hard disk with ProDOS and SmartPort support - Hard disk with ProDOS and SmartPort support
- Emulated extension cards: - Emulated extension cards:
@ -46,6 +45,7 @@ Portable emulator of an Apple II+ or //e. Written in Go.
- Adjustable speed. - Adjustable speed.
- Fast disk mode to set max speed while using the disks. - Fast disk mode to set max speed while using the disks.
- Single file executable with embedded ROMs and DOS 3.3 - Single file executable with embedded ROMs and DOS 3.3
- Pause (thanks a2geek)
## Running the emulator ## Running the emulator

View File

@ -1,6 +1,9 @@
package apple2 package apple2
import "errors" import (
"errors"
"strings"
)
type diskette interface { type diskette interface {
powerOn(cycle uint64) powerOn(cycle uint64)
@ -15,13 +18,16 @@ func loadDisquette(filename string) (diskette, error) {
return nil, err return nil, err
} }
if isFileNibOrDsk(data) { if isFileNib(data) {
f, err := newFileNibOrDsk(data)
if err != nil {
return nil, err
}
var d diskette16sector 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 return &d, nil
} }

View File

@ -1,7 +1,6 @@
package apple2 package apple2
import ( import (
"errors"
"os" "os"
) )
@ -27,41 +26,38 @@ type fileNib struct {
track [numberOfTracks][]byte track [numberOfTracks][]byte
} }
func loadFileNibOrDsk(filename string) (*fileNib, error) { func isFileNib(data []uint8) bool {
data, err := loadResource(filename) return len(data) == nibImageSize
if err != nil {
return nil, err
}
return newFileNibOrDsk(data)
} }
func isFileNibOrDsk(data []uint8) bool { func newFileNib(data []uint8) *fileNib {
size := len(data)
return size == nibImageSize || size == dskImageSize
}
func newFileNibOrDsk(data []uint8) (*fileNib, error) {
var f fileNib var f fileNib
size := len(data) for i := 0; i < numberOfTracks; i++ {
f.track[i] = data[nibBytesPerTrack*i : nibBytesPerTrack*(i+1)]
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")
} }
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 { func (f *fileNib) saveNib(filename string) error {
@ -81,11 +77,18 @@ func (f *fileNib) saveNib(filename string) error {
return nil 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, 0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4,
0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF, 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{ var sixAndTwoTranslateTable = [0x40]byte{
0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6, 0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6,
0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3, 0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3,
@ -118,7 +121,7 @@ func oddEvenEncodeByte(b byte) []byte {
return e 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 b := make([]byte, 0, nibBytesPerTrack) // Buffer slice with enough capacity
// Initialize gaps to be copied for each sector // Initialize gaps to be copied for each sector
gap1 := make([]byte, gap1Len) 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 but on the physical encoded track as well as in the nib
files they are in phisical order. files they are in phisical order.
*/ */
logicalSector := dos33SectorsLogicOrder[physicalSector] logicalSector := logicalOrder[physicalSector]
sectorData := data[logicalSector*bytesPerSector : (logicalSector+1)*bytesPerSector] sectorData := data[logicalSector*bytesPerSector : (logicalSector+1)*bytesPerSector]
// 6and2 prenibbilizing. // 6and2 prenibbilizing.