mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-09-07 14:54:27 +00:00
Support for 13 sectors disks
This commit is contained in:
parent
ad720f0527
commit
20e18df2e7
@ -15,6 +15,9 @@ Portable emulator of an Apple II+ or //e. Written in Go.
|
||||
- DSK
|
||||
- PO
|
||||
- [WOZ 1.0 or 2.0](storage/WozSupportStatus.md) (read only)
|
||||
- 13 Sector 5 1/4 diskettes. Uncompressed or compressed witth gzip or zip. Supported formats:
|
||||
- NIB (read only)
|
||||
- [WOZ 2.0](storage/WozSupportStatus.md) (read only)
|
||||
- 3.5 disks in PO or 2MG format
|
||||
- Hard disk in HDV or 2MG format with ProDOS and SmartPort support
|
||||
- Emulated extension cards:
|
||||
@ -225,6 +228,7 @@ The available pre-configured models are:
|
||||
2enh: Apple //e
|
||||
2plus: Apple ][+
|
||||
base64a: Base 64A
|
||||
dos32: Apple ][+ with 13 sectors disk adapter and DOS 3.2x
|
||||
swyft: swyft
|
||||
|
||||
The available cards are:
|
||||
|
29
cardDisk2.go
29
cardDisk2.go
@ -25,6 +25,8 @@ NIB: 35 tracks 6656 bytes, 232960 bytes
|
||||
// CardDisk2 is a DiskII interface card
|
||||
type CardDisk2 struct {
|
||||
cardBase
|
||||
sectors13 bool
|
||||
|
||||
selected int // q5, Only 0 and 1 supported
|
||||
power bool // q4
|
||||
drive [2]cardDisk2Drive
|
||||
@ -57,13 +59,11 @@ func newCardDisk2Builder() *cardBuilder {
|
||||
{"disk2", "Diskette image for drive 2", ""},
|
||||
{"tracktracer", "Trace how the disk head moves between tracks", "false"},
|
||||
{"fast", "Enable CPU burst when accessing the disk", "true"},
|
||||
{"sectors13", "Use 13 sectors per track ROM", "false"},
|
||||
},
|
||||
buildFunc: func(params map[string]string) (Card, error) {
|
||||
var c CardDisk2
|
||||
err := c.loadRomFromResource("<internal>/DISK2.rom", cardRomSimple)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.sectors13 = paramsGetBool(params, "sectors13")
|
||||
|
||||
disk1 := paramsGetPath(params, "disk1")
|
||||
if disk1 != "" {
|
||||
@ -71,6 +71,10 @@ func newCardDisk2Builder() *cardBuilder {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.drive[0].diskette.Is13Sectors() && !c.sectors13 {
|
||||
// Auto configure for 13 sectors per track
|
||||
c.sectors13 = true
|
||||
}
|
||||
}
|
||||
disk2 := paramsGetPath(params, "disk2")
|
||||
if disk2 != "" {
|
||||
@ -79,6 +83,17 @@ func newCardDisk2Builder() *cardBuilder {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
P5RomFile := "<internal>/Apple Disk II 16 Sector Interface Card ROM P5 - 341-0027.bin"
|
||||
if c.sectors13 {
|
||||
P5RomFile = "<internal>/Apple Disk II 13 Sector Interface Card ROM P5 - 341-0009.bin"
|
||||
}
|
||||
|
||||
err := c.loadRomFromResource(P5RomFile, cardRomSimple)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
trackTracer := paramsGetBool(params, "tracktracer")
|
||||
if trackTracer {
|
||||
c.trackTracer = makeTrackTracerLogger()
|
||||
@ -92,7 +107,11 @@ func newCardDisk2Builder() *cardBuilder {
|
||||
// GetInfo returns smartPort info
|
||||
func (c *CardDisk2) GetInfo() map[string]string {
|
||||
info := make(map[string]string)
|
||||
info["rom"] = "16 sector"
|
||||
if c.sectors13 {
|
||||
info["rom"] = "13 sector"
|
||||
} else {
|
||||
info["rom"] = "16 sector"
|
||||
}
|
||||
info["power"] = strconv.FormatBool(c.power)
|
||||
|
||||
info["D1 name"] = c.drive[0].name
|
||||
|
@ -22,7 +22,9 @@ See:
|
||||
type CardDisk2Sequencer struct {
|
||||
cardBase
|
||||
|
||||
p6ROM []uint8
|
||||
sectors13 bool
|
||||
p6ROM []uint8
|
||||
|
||||
q [8]bool // 8-bit latch SN74LS259
|
||||
register uint8 // 8-bit shift/storage register SN74LS323
|
||||
sequence uint8 // 4 bits stored in an hex flip-flop SN74LS174
|
||||
@ -66,16 +68,6 @@ func newCardDisk2SequencerBuilder() *cardBuilder {
|
||||
},
|
||||
buildFunc: func(params map[string]string) (Card, error) {
|
||||
var c CardDisk2Sequencer
|
||||
err := c.loadRomFromResource("<internal>/DISK2.rom", cardRomSimple)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, _, err := LoadResource("<internal>/DISK2P6.rom")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.p6ROM = data
|
||||
|
||||
disk1 := paramsGetString(params, "disk1")
|
||||
if disk1 != "" {
|
||||
@ -83,7 +75,9 @@ func newCardDisk2SequencerBuilder() *cardBuilder {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.sectors13 = c.drive[0].data.Info.BootSectorFormat == 2 // Woz 13 sector disk
|
||||
}
|
||||
|
||||
disk2 := paramsGetString(params, "disk2")
|
||||
if disk2 != "" {
|
||||
err := c.drive[1].insertDiskette(disk2)
|
||||
@ -91,6 +85,26 @@ func newCardDisk2SequencerBuilder() *cardBuilder {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
P5RomFile := "<internal>/Apple Disk II 16 Sector Interface Card ROM P5 - 341-0027.bin"
|
||||
P6RomFile := "<internal>/Apple Disk II 16 Sector Interface Card ROM P6 - 341-0028.bin"
|
||||
if c.sectors13 {
|
||||
P5RomFile = "<internal>/Apple Disk II 13 Sector Interface Card ROM P5 - 341-0009.bin"
|
||||
// Buggy sequencer not need for 13 sectors disks to work
|
||||
//P6RomFile = "<internal>/Apple Disk II 13 Sector Interface Card ROM P6 - 341-0010.bin"
|
||||
}
|
||||
|
||||
err := c.loadRomFromResource(P5RomFile, cardRomSimple)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, _, err := LoadResource(P6RomFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.p6ROM = data
|
||||
|
||||
trackTracer := paramsGetBool(params, "tracktracer")
|
||||
if trackTracer {
|
||||
c.trackTracer = makeTrackTracerLogger()
|
||||
@ -103,7 +117,11 @@ func newCardDisk2SequencerBuilder() *cardBuilder {
|
||||
// GetInfo returns card info
|
||||
func (c *CardDisk2Sequencer) GetInfo() map[string]string {
|
||||
info := make(map[string]string)
|
||||
info["rom"] = "16 sector"
|
||||
if c.sectors13 {
|
||||
info["rom"] = "13 sector"
|
||||
} else {
|
||||
info["rom"] = "16 sector"
|
||||
}
|
||||
// TODO: add drives info
|
||||
return info
|
||||
}
|
||||
|
@ -34,9 +34,6 @@ func (d *cardDisk2SequencerDrive) insertDiskette(filename string) error {
|
||||
if f.Info.DiskType != 1 {
|
||||
return errors.New("only 5.25 disks are supported")
|
||||
}
|
||||
if f.Info.BootSectorFormat == 2 { // Info not available in WOZ 1.0
|
||||
return errors.New("woz 13 sector disks are not supported")
|
||||
}
|
||||
|
||||
d.data = f
|
||||
d.writeProtected = !writeable
|
||||
|
4
configs/dos32.cfg
Normal file
4
configs/dos32.cfg
Normal file
@ -0,0 +1,4 @@
|
||||
name: Apple ][ with 13 sectors disk adapter and DOS 3.2x
|
||||
parent: 2
|
||||
s0: multirom,bank=7,basic=0
|
||||
s6: diskii,sectors13,disk1=<internal>/dos32.nib
|
@ -63,9 +63,13 @@ func (c *configuration) getHas(key string) (string, bool) {
|
||||
return value, ok
|
||||
}
|
||||
|
||||
func (c *configuration) has(key string) bool {
|
||||
_, ok := c.getHas(key)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (c *configuration) get(key string) string {
|
||||
key = strings.ToLower(key)
|
||||
value, ok := c.data[key]
|
||||
value, ok := c.getHas(key)
|
||||
if !ok {
|
||||
// Should not happen
|
||||
panic(fmt.Errorf("key %s not found", key))
|
||||
|
@ -50,6 +50,7 @@ The available pre-configured models are:
|
||||
2enh: Apple //e
|
||||
2plus: Apple ][+
|
||||
base64a: Base 64A
|
||||
dos32: Apple ][+ with 13 sectors disk adapter and DOS 3.2x
|
||||
swyft: swyft
|
||||
|
||||
The available cards are:
|
||||
|
@ -5,11 +5,17 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testBoots(t *testing.T, model string, disk string, cycles uint64, banner string, prompt string, col80 bool) {
|
||||
overrides := newConfiguration()
|
||||
func testBoots(t *testing.T, model string, disk string, overrides *configuration, cycles uint64, banner string, prompt string, col80 bool) {
|
||||
if overrides == nil {
|
||||
overrides = newConfiguration()
|
||||
}
|
||||
|
||||
if disk != "" {
|
||||
if overrides.has(confS6) {
|
||||
t.Fatal("Do not set custom slot 6 configuration and custom disk")
|
||||
}
|
||||
overrides.set(confS6, "diskii,disk1=\""+disk+"\"")
|
||||
} else {
|
||||
} else if !overrides.has(confS6) {
|
||||
overrides.set(confS6, "empty")
|
||||
}
|
||||
|
||||
@ -36,29 +42,36 @@ func testBoots(t *testing.T, model string, disk string, cycles uint64, banner st
|
||||
}
|
||||
|
||||
func TestPlusBoots(t *testing.T) {
|
||||
testBoots(t, "2plus", "", 200_000, "APPLE ][", "\n]", false)
|
||||
testBoots(t, "2plus", "", nil, 200_000, "APPLE ][", "\n]", false)
|
||||
}
|
||||
|
||||
func Test2EBoots(t *testing.T) {
|
||||
testBoots(t, "2e", "", 200_000, "Apple ][", "\n]", false)
|
||||
testBoots(t, "2e", "", nil, 200_000, "Apple ][", "\n]", false)
|
||||
}
|
||||
|
||||
func Test2EnhancedBoots(t *testing.T) {
|
||||
testBoots(t, "2enh", "", 200_000, "Apple //e", "\n]", false)
|
||||
testBoots(t, "2enh", "", nil, 200_000, "Apple //e", "\n]", false)
|
||||
}
|
||||
|
||||
func TestBase64Boots(t *testing.T) {
|
||||
testBoots(t, "base64a", "", 1_000_000, "BASE 64A", "\n]", false)
|
||||
testBoots(t, "base64a", "", nil, 1_000_000, "BASE 64A", "\n]", false)
|
||||
}
|
||||
|
||||
func TestPlusDOS32Boots(t *testing.T) {
|
||||
overrides := newConfiguration()
|
||||
overrides.set(confS0, "multirom,bank=7,basic=0")
|
||||
overrides.set(confS6, "diskii,sectors13,disk1=<internal>/dos32.nib")
|
||||
testBoots(t, "2plus", "", overrides, 100_000_000, "MASTER DISKETTE VERSION 3.2 STANDARD", "\n>", false)
|
||||
}
|
||||
|
||||
func TestPlusDOS33Boots(t *testing.T) {
|
||||
testBoots(t, "2plus", "<internal>/dos33.dsk", 100_000_000, "DOS VERSION 3.3", "\n]", false)
|
||||
testBoots(t, "2plus", "<internal>/dos33.dsk", nil, 100_000_000, "DOS VERSION 3.3", "\n]", false)
|
||||
}
|
||||
|
||||
func TestProdDOSBoots(t *testing.T) {
|
||||
testBoots(t, "2enh", "<internal>/ProDOS_2_4_3.po", 100_000_000, "BITSY BYE", "NEW VOL", false)
|
||||
testBoots(t, "2enh", "<internal>/ProDOS_2_4_3.po", nil, 100_000_000, "BITSY BYE", "NEW VOL", false)
|
||||
}
|
||||
|
||||
func TestCPM65Boots(t *testing.T) {
|
||||
testBoots(t, "2enh", "<internal>/cpm65.po", 5_000_000, "CP/M-65 for the Apple II", "\nA>", true)
|
||||
testBoots(t, "2enh", "<internal>/cpm65.po", nil, 5_000_000, "CP/M-65 for the Apple II", "\nA>", true)
|
||||
}
|
||||
|
@ -55,9 +55,9 @@ func TestWoz(t *testing.T) {
|
||||
cycleLimit uint64
|
||||
expectedTracks []int
|
||||
}{
|
||||
// How to being
|
||||
// DOS 3.2, requires 13 sector disks
|
||||
{"DOS3.3", all, "DOS 3.3 System Master.woz", 11_000_000, []int{0, 8, 0, 76, 68, 84, 68, 84, 68, 92, 16, 24}},
|
||||
// How to begin
|
||||
{"DOS 3.2", all, "DOS 3.2 System Master.woz", 7_000_000, []int{0, 72}},
|
||||
{"DOS 3.3", all, "DOS 3.3 System Master.woz", 11_000_000, []int{0, 8, 0, 76, 68, 84, 68, 84, 68, 92, 16, 24}},
|
||||
|
||||
// Next choices
|
||||
{"Bouncing Kamungas", all, "Bouncing Kamungas - Disk 1, Side A.woz", 30_000_000, []int{0, 32, 0, 40, 0}},
|
||||
|
@ -53,7 +53,7 @@ const (
|
||||
nscStateEnabled = uint8(2)
|
||||
)
|
||||
|
||||
func newNoSlotClockDS1216(a *Apple2, memory memoryHandler) *noSlotClockDS1216 {
|
||||
func newNoSlotClockDS1216(_ *Apple2, memory memoryHandler) *noSlotClockDS1216 {
|
||||
var nsc noSlotClockDS1216
|
||||
nsc.memory = memory
|
||||
nsc.state = nscStateDisabled
|
||||
|
Binary file not shown.
@ -0,0 +1,65 @@
|
||||
ИИ<EFBFBD>Ш
|
||||
|
||||
|
||||
|
||||
<EFBFBD>Щ<EFBFBD>Щ<EFBFBD>Ы<EFBFBD>Ы<EFBFBD>ШШ
|
||||
|
||||
|
||||
|
||||
<EFBFBD>Щ<EFBFBD>Щ<EFBFBD>Ы<EFBFBD>ЫИ=ИИ
|
||||
|
||||
|
||||
|
||||
<EFBFBD>й<EFBFBD>й<EFBFBD>л<EFBFBD>л<EFBFBD>н<EFBFBD>и
|
||||
|
||||
|
||||
|
||||
<EFBFBD>й<EFBFBD>й<EFBFBD>л<EFBFBD>лИИИИ
|
||||
|
||||
|
||||
|
||||
ЈшЈшЈшЈшЈшЈш
|
||||
|
||||
|
||||
|
||||
ЈшЈшЈшЈшЙ§Иј
|
||||
|
||||
|
||||
|
||||
ИјИјИјИјЙ§Pј
|
||||
|
||||
|
||||
|
||||
ИјИјИјИјИИHИ
|
||||
|
||||
|
||||
|
||||
H(H(H(H(H(H(
|
||||
|
||||
|
||||
|
||||
H(H(H(H(ИЙИИ
|
||||
|
||||
|
||||
|
||||
X8X8X8X8 ЩX8
|
||||
|
||||
|
||||
|
||||
X8X8X8X8ИИИИ
|
||||
|
||||
|
||||
|
||||
hhhhhh
|
||||
|
||||
|
||||
|
||||
hhhh<18>Нxp
|
||||
|
||||
|
||||
|
||||
xxxx
-xp
|
||||
|
||||
|
||||
|
||||
xxxx
|
1
resources/dos32.nib
generated
Normal file
1
resources/dos32.nib
generated
Normal file
File diff suppressed because one or more lines are too long
@ -89,7 +89,7 @@ func buildNotImplementedSoftSwitchR(io *ioC0Page) softSwitchR {
|
||||
}
|
||||
}
|
||||
|
||||
func buildNotImplementedSoftSwitchW(io *ioC0Page) softSwitchW {
|
||||
func buildNotImplementedSoftSwitchW(_ *ioC0Page) softSwitchW {
|
||||
return func(uint8) {
|
||||
// Do nothing
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
## With the sequencer:
|
||||
- How to begin
|
||||
- DOS 3.3: Works
|
||||
- DOS 3.2: **Unknown, 13 sector disks boot not supported**
|
||||
- DOS 3.2: Works with 13 sectors ROM
|
||||
- Next choices
|
||||
- Bouncing Kamungas: Working
|
||||
- Commando: Working
|
||||
|
@ -10,6 +10,7 @@ type Diskette interface {
|
||||
PowerOff(cycle uint64)
|
||||
Read(quarterTrack int, cycle uint64) uint8
|
||||
Write(quarterTrack int, value uint8, cycle uint64)
|
||||
Is13Sectors() bool
|
||||
}
|
||||
|
||||
// IsDiskette returns true if the files looks like a 5 1/4 diskette
|
||||
@ -19,14 +20,18 @@ func IsDiskette(data []byte) bool {
|
||||
|
||||
// MakeDiskette returns a Diskette by detecting the format
|
||||
func MakeDiskette(data []byte, filename string, writeable bool) (Diskette, error) {
|
||||
if isFileD13(data) {
|
||||
return nil, errors.New("files with .d13 format not supported for 13 sectors disk, use .nib or .woz")
|
||||
}
|
||||
|
||||
if isFileNib(data) {
|
||||
var d diskette16sector
|
||||
var d disketteNib
|
||||
d.nib = newFileNib(data)
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
if isFileDsk(data) {
|
||||
var d diskette16sectorWritable
|
||||
var d disketteNibWritable
|
||||
d.nib = newFileDsk(data, filename)
|
||||
d.nib.supportsWrite = d.nib.supportsWrite && writeable
|
||||
return &d, nil
|
||||
|
@ -6,19 +6,19 @@ See:
|
||||
https://github.com/TomHarte/CLK/wiki/Apple-GCR-disk-encoding
|
||||
*/
|
||||
|
||||
type diskette16sector struct {
|
||||
type disketteNib struct {
|
||||
nib *fileNib
|
||||
position int
|
||||
}
|
||||
|
||||
func (d *diskette16sector) PowerOn(cycle uint64) {
|
||||
func (d *disketteNib) PowerOn(cycle uint64) {
|
||||
// Not used
|
||||
}
|
||||
func (d *diskette16sector) PowerOff(_ uint64) {
|
||||
func (d *disketteNib) PowerOff(_ uint64) {
|
||||
// Not used
|
||||
}
|
||||
|
||||
func (d *diskette16sector) Read(quarterTrack int, cycle uint64) uint8 {
|
||||
func (d *disketteNib) Read(quarterTrack int, cycle uint64) uint8 {
|
||||
track := d.nib.track[quarterTrack/4]
|
||||
value := track[d.position]
|
||||
d.position = (d.position + 1) % nibBytesPerTrack
|
||||
@ -26,8 +26,13 @@ func (d *diskette16sector) Read(quarterTrack int, cycle uint64) uint8 {
|
||||
return value
|
||||
}
|
||||
|
||||
func (d *diskette16sector) Write(quarterTrack int, value uint8, _ uint64) {
|
||||
func (d *disketteNib) Write(quarterTrack int, value uint8, _ uint64) {
|
||||
track := quarterTrack / 4
|
||||
d.nib.track[track][d.position] = value
|
||||
d.position = (d.position + 1) % nibBytesPerTrack
|
||||
}
|
||||
|
||||
func (d *disketteNib) Is13Sectors() bool {
|
||||
// It amy be 13 sectors but we don't know
|
||||
return false
|
||||
}
|
@ -1,18 +1,18 @@
|
||||
package storage
|
||||
|
||||
type diskette16sectorTimed struct {
|
||||
type disketteNibTimed struct {
|
||||
nib *fileNib
|
||||
cycleOn uint64 // Cycle when the disk was last turned on
|
||||
}
|
||||
|
||||
func (d *diskette16sectorTimed) PowerOn(cycle uint64) {
|
||||
func (d *disketteNibTimed) PowerOn(cycle uint64) {
|
||||
d.cycleOn = cycle
|
||||
}
|
||||
func (d *diskette16sectorTimed) PowerOff(_ uint64) {
|
||||
func (d *disketteNibTimed) PowerOff(_ uint64) {
|
||||
// Not needed
|
||||
}
|
||||
|
||||
func (d *diskette16sectorTimed) getBitPositionInTrack(cycle uint64) int {
|
||||
func (d *disketteNibTimed) getBitPositionInTrack(cycle uint64) int {
|
||||
// Calculate how long the disk has been spinning. We move one bit every 4 cycles.
|
||||
// In this implementation we don't take into account how long the motor takes to be at full speed.
|
||||
cycles := cycle - d.cycleOn
|
||||
@ -20,7 +20,7 @@ func (d *diskette16sectorTimed) getBitPositionInTrack(cycle uint64) int {
|
||||
return int(position % (8 * nibBytesPerTrack)) // Ignore full turns
|
||||
}
|
||||
|
||||
func (d *diskette16sectorTimed) Read(quarterTrack int, cycle uint64) uint8 {
|
||||
func (d *disketteNibTimed) Read(quarterTrack int, cycle uint64) uint8 {
|
||||
track := d.nib.track[quarterTrack/4]
|
||||
bitPosition := d.getBitPositionInTrack(cycle)
|
||||
bytePosition := bitPosition / 8
|
||||
@ -35,6 +35,11 @@ func (d *diskette16sectorTimed) Read(quarterTrack int, cycle uint64) uint8 {
|
||||
return value
|
||||
}
|
||||
|
||||
func (d *diskette16sectorTimed) Write(quarterTrack int, value uint8, _ uint64) {
|
||||
func (d *disketteNibTimed) Write(quarterTrack int, value uint8, _ uint64) {
|
||||
panic("Write not implemented on time based disk implementation")
|
||||
}
|
||||
|
||||
func (d *disketteNibTimed) Is13Sectors() bool {
|
||||
// It amy be 13 sectors but we don't know
|
||||
return false
|
||||
}
|
@ -6,7 +6,7 @@ See:
|
||||
https://github.com/TomHarte/CLK/wiki/Apple-GCR-disk-encoding
|
||||
*/
|
||||
|
||||
type diskette16sectorWritable struct {
|
||||
type disketteNibWritable struct {
|
||||
nib *fileNib
|
||||
position int
|
||||
|
||||
@ -15,21 +15,21 @@ type diskette16sectorWritable struct {
|
||||
dirtyTrack int
|
||||
}
|
||||
|
||||
func (d *diskette16sectorWritable) PowerOn(cycle uint64) {
|
||||
func (d *disketteNibWritable) PowerOn(cycle uint64) {
|
||||
// Not used
|
||||
}
|
||||
func (d *diskette16sectorWritable) PowerOff(_ uint64) {
|
||||
func (d *disketteNibWritable) PowerOff(_ uint64) {
|
||||
d.commit()
|
||||
}
|
||||
|
||||
func (d *diskette16sectorWritable) Read(quarterTrack int, cycle uint64) uint8 {
|
||||
func (d *disketteNibWritable) Read(quarterTrack int, cycle uint64) uint8 {
|
||||
track := d.nib.track[quarterTrack/4]
|
||||
value := track[d.position]
|
||||
d.position = (d.position + 1) % nibBytesPerTrack
|
||||
return value
|
||||
}
|
||||
|
||||
func (d *diskette16sectorWritable) Write(quarterTrack int, value uint8, _ uint64) {
|
||||
func (d *disketteNibWritable) Write(quarterTrack int, value uint8, _ uint64) {
|
||||
track := quarterTrack / 4
|
||||
|
||||
if d.hasDirtyTrack && track != d.dirtyTrack {
|
||||
@ -43,9 +43,14 @@ func (d *diskette16sectorWritable) Write(quarterTrack int, value uint8, _ uint64
|
||||
d.dirtyTrack = track
|
||||
}
|
||||
|
||||
func (d *diskette16sectorWritable) commit() {
|
||||
func (d *disketteNibWritable) commit() {
|
||||
if d.hasDirtyTrack {
|
||||
d.nib.saveTrack(d.dirtyTrack)
|
||||
d.hasDirtyTrack = false
|
||||
}
|
||||
}
|
||||
|
||||
func (d *disketteNibWritable) Is13Sectors() bool {
|
||||
// It amy be 13 sectors but we don't know
|
||||
return false
|
||||
}
|
@ -31,9 +31,6 @@ func newDisquetteWoz(f *FileWoz) (*disketteWoz, error) {
|
||||
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
|
||||
@ -98,3 +95,7 @@ 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 (d *disketteWoz) Is13Sectors() bool {
|
||||
return d.data.version == 2 && d.data.Info.BootSectorFormat == 2
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ const (
|
||||
nibBytesPerTrack = 6656
|
||||
nibImageSize = numberOfTracks * nibBytesPerTrack
|
||||
dskImageSize = numberOfTracks * numberOfSectors * bytesPerSector
|
||||
d13ImageSize = numberOfTracks * 13 * bytesPerSector
|
||||
defaultVolumeTag = 254
|
||||
cyclesPerBit = 4
|
||||
)
|
||||
@ -52,6 +53,10 @@ func isFileDsk(data []uint8) bool {
|
||||
return len(data) == dskImageSize
|
||||
}
|
||||
|
||||
func isFileD13(data []uint8) bool {
|
||||
return len(data) == d13ImageSize
|
||||
}
|
||||
|
||||
func newFileDsk(data []uint8, filename string) *fileNib {
|
||||
var f fileNib
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user