diff --git a/apple2Setup.go b/apple2Setup.go index 2689a02..879b7c6 100644 --- a/apple2Setup.go +++ b/apple2Setup.go @@ -92,8 +92,8 @@ func (a *Apple2) LoadRom(filename string) error { } // AddDisk2 inserts a DiskII controller -func (a *Apple2) AddDisk2(slot int, diskImage, diskBImage string) error { - c := NewCardDisk2() +func (a *Apple2) AddDisk2(slot int, diskImage, diskBImage string, trackTracer trackTracer) error { + c := NewCardDisk2(trackTracer) a.insertCard(c, slot) if diskImage != "" { @@ -116,8 +116,8 @@ func (a *Apple2) AddDisk2(slot int, diskImage, diskBImage string) error { } // AddDisk2 inserts a DiskII controller -func (a *Apple2) AddDisk2Sequencer(slot int, diskImage, diskBImage string) error { - c := NewCardDisk2Sequencer() +func (a *Apple2) AddDisk2Sequencer(slot int, diskImage, diskBImage string, trackTracer trackTracer) error { + c := NewCardDisk2Sequencer(trackTracer) a.insertCard(c, slot) if diskImage != "" { diff --git a/apple2main.go b/apple2main.go index 3d3e708..b25b5ee 100644 --- a/apple2main.go +++ b/apple2main.go @@ -245,12 +245,12 @@ func MainApple() *Apple2 { } if *disk2Slot > 0 { if *sequencerDisk2 { - err := a.AddDisk2Sequencer(*disk2Slot, diskImageFinal, *diskBImage) + err := a.AddDisk2Sequencer(*disk2Slot, diskImageFinal, *diskBImage, nil) if err != nil { panic(err) } } else { - err := a.AddDisk2(*disk2Slot, diskImageFinal, *diskBImage) + err := a.AddDisk2(*disk2Slot, diskImageFinal, *diskBImage, nil) if err != nil { panic(err) } diff --git a/cardDisk2.go b/cardDisk2.go index 4dd8d24..db38b4b 100644 --- a/cardDisk2.go +++ b/cardDisk2.go @@ -32,19 +32,22 @@ type CardDisk2 struct { dataLatch uint8 q6 bool q7 bool + + trackTracer trackTracer } type cardDisk2Drive struct { - name string - diskette storage.Diskette - phases uint8 // q3, q2, q1 and q0 with q0 on the LSB. Magnets that are active on the stepper motor - tracksStep int // Stepmotor for tracks position. 4 steps per track + name string + diskette storage.Diskette + phases uint8 // q3, q2, q1 and q0 with q0 on the LSB. Magnets that are active on the stepper motor + trackStep int // Stepmotor for tracks position. 4 steps per track } // NewCardDisk2 creates a new CardDisk2 -func NewCardDisk2() *CardDisk2 { +func NewCardDisk2(trackTracer trackTracer) *CardDisk2 { var c CardDisk2 c.name = "Disk II" + c.trackTracer = trackTracer c.loadRomFromResource("/DISK2.rom") return &c } @@ -56,10 +59,10 @@ func (c *CardDisk2) GetInfo() map[string]string { info["power"] = strconv.FormatBool(c.power) info["D1 name"] = c.drive[0].name - info["D1 track"] = strconv.FormatFloat(float64(c.drive[0].tracksStep)/4, 'f', 2, 64) + info["D1 track"] = strconv.FormatFloat(float64(c.drive[0].trackStep)/4, 'f', 2, 64) info["D2 name"] = c.drive[1].name - info["D2 track"] = strconv.FormatFloat(float64(c.drive[1].tracksStep)/4, 'f', 2, 64) + info["D2 track"] = strconv.FormatFloat(float64(c.drive[1].trackStep)/4, 'f', 2, 64) return info } @@ -81,7 +84,11 @@ func (c *CardDisk2) assign(a *Apple2, slot int) { // Update magnets and position drive := &c.drive[c.selected] drive.phases &^= (1 << phase) - drive.tracksStep = moveDriveStepper(drive.phases, drive.tracksStep) + drive.trackStep = moveDriveStepper(drive.phases, drive.trackStep) + + if c.trackTracer != nil { + c.trackTracer.traceTrack(drive.trackStep) + } return c.dataLatch // All even addresses return the last dataLatch }, fmt.Sprintf("PHASE%vOFF", phase)) @@ -90,7 +97,11 @@ func (c *CardDisk2) assign(a *Apple2, slot int) { // Update magnets and position drive := &c.drive[c.selected] drive.phases |= (1 << phase) - drive.tracksStep = moveDriveStepper(drive.phases, drive.tracksStep) + drive.trackStep = moveDriveStepper(drive.phases, drive.trackStep) + + if c.trackTracer != nil { + c.trackTracer.traceTrack(drive.trackStep) + } return 0 }, fmt.Sprintf("PHASE%vON", phase)) @@ -194,9 +205,9 @@ func (c *CardDisk2) processQ6Q7(in uint8) { } if !c.q6 { // shift if !c.q7 { // Q6L-Q7L: Read - c.dataLatch = d.diskette.Read(d.tracksStep, c.a.cpu.GetCycles()) + c.dataLatch = d.diskette.Read(d.trackStep, c.a.cpu.GetCycles()) } else { // Q6L-Q7H: Write the dataLatch value to disk. Shift data out - d.diskette.Write(d.tracksStep, c.dataLatch, c.a.cpu.GetCycles()) + d.diskette.Write(d.trackStep, c.dataLatch, c.a.cpu.GetCycles()) } } else { // load if !c.q7 { // Q6H-Q7L: Sense write protect / prewrite state diff --git a/cardDisk2Sequencer.go b/cardDisk2Sequencer.go index 4d18641..b7c6959 100644 --- a/cardDisk2Sequencer.go +++ b/cardDisk2Sequencer.go @@ -33,6 +33,8 @@ type CardDisk2Sequencer struct { lastPulseCycles uint8 // There is a new pulse every 4ms, that's 8 cycles of 2Mhz lastCycle uint64 // 2 Mhz cycles + + trackTracer trackTracer } const ( @@ -48,9 +50,10 @@ const ( ) // NewCardDisk2Sequencer creates a new CardDisk2Sequencer -func NewCardDisk2Sequencer() *CardDisk2Sequencer { +func NewCardDisk2Sequencer(trackTracer trackTracer) *CardDisk2Sequencer { var c CardDisk2Sequencer c.name = "Disk II" + c.trackTracer = trackTracer c.loadRomFromResource("/DISK2.rom") data, _, err := LoadResource("/DISK2P6.rom") @@ -172,8 +175,8 @@ func (c *CardDisk2Sequencer) step(data uint8, firstStep bool) bool { q1 := c.q[1] q2 := c.q[2] q3 := c.q[3] - c.drive[0].moveHead(q0, q1, q2, q3) - c.drive[1].moveHead(q0, q1, q2, q3) + c.drive[0].moveHead(q0, q1, q2, q3, c.trackTracer) + c.drive[1].moveHead(q0, q1, q2, q3, c.trackTracer) } /* diff --git a/cardDisk2SequencerDrive.go b/cardDisk2SequencerDrive.go index 0117c1f..966f826 100644 --- a/cardDisk2SequencerDrive.go +++ b/cardDisk2SequencerDrive.go @@ -48,7 +48,7 @@ func (d *cardDisk2SequencerDrive) enable(enabled bool) { d.enabled = enabled } -func (d *cardDisk2SequencerDrive) moveHead(q0, q1, q2, q3 bool) { +func (d *cardDisk2SequencerDrive) moveHead(q0, q1, q2, q3 bool, trackTracer trackTracer) { if !d.enabled { return } @@ -58,6 +58,10 @@ func (d *cardDisk2SequencerDrive) moveHead(q0, q1, q2, q3 bool) { false, false, false, false, }) d.currentQuarterTrack = moveDriveStepper(phases, d.currentQuarterTrack) + + if trackTracer != nil { + trackTracer.traceTrack(d.currentQuarterTrack) + } } func (d *cardDisk2SequencerDrive) readPulse() bool { diff --git a/apple2_test.go b/e2e_boot_test.go similarity index 97% rename from apple2_test.go rename to e2e_boot_test.go index a7d95e3..a8f0fd5 100644 --- a/apple2_test.go +++ b/e2e_boot_test.go @@ -72,7 +72,7 @@ func TestBase64Boots(t *testing.T) { func TestPlusDOS33Boots(t *testing.T) { at := makeApple2Tester("2plus") - err := at.a.AddDisk2(6, "/dos33.dsk", "") + err := at.a.AddDisk2(6, "/dos33.dsk", "", nil) if err != nil { panic(err) } diff --git a/e2e_woz_test.go b/e2e_woz_test.go new file mode 100644 index 0000000..f906f25 --- /dev/null +++ b/e2e_woz_test.go @@ -0,0 +1,116 @@ +package izapple2 + +import ( + "testing" +) + +func testWoz(t *testing.T, sequencer bool, file string, expectedTracks []int, cycleLimit uint64) { + at := makeApple2Tester("2enh") + tt := makeTrackTracerSummary() + + var err error + if sequencer { + err = at.a.AddDisk2Sequencer(6, "woz_test_images/"+file, "", tt) + } else { + err = at.a.AddDisk2(6, "woz_test_images/"+file, "", tt) + } + if err != nil { + panic(err) + } + + expectedLen := len(expectedTracks) + + at.terminateCondition = func(a *Apple2) bool { + tracksMayMatch := len(tt.quarterTracks) >= expectedLen && + tt.quarterTracks[expectedLen-1] == expectedTracks[expectedLen-1] + + return tracksMayMatch || a.cpu.GetCycles() > cycleLimit + } + at.run() + + if !tt.isTraceAsExpected(expectedTracks) { + t.Errorf("Quarter tracks, expected %#v, got %#v", expectedTracks, tt.quarterTracks) + } + + //t.Errorf("Cycles: %d vs %d", at.a.cpu.GetCycles(), cycleLimit) +} + +const ( + all = 0 + seq = 1 // Passes only with the sequencer implementation + none = 2 // Fails also with the sequencer implementation +) + +func TestWoz(t *testing.T) { + testCases := []struct { + name string + skip int + disk string + 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}}, + + // Next choices + {"Bouncing Kamungas", all, "Bouncing Kamungas - Disk 1, Side A.woz", 30_000_000, []int{0, 32, 0, 40, 0}}, + {"Commando", seq, "Commando - Disk 1, Side A.woz", 14_000_000, []int{0, 136, 68, 128, 68, 128, 68, 124, 12, 116, 108}}, + {"Planetfall", all, "Planetfall - Disk 1, Side A.woz", 4_000_000, []int{0, 8}}, + {"Rescue Raiders", all, "Rescue Raiders - Disk 1, Side B.woz", 80_000_000, []int{ + 0, 84, 44, 46, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, + 84, 44, 116, 4, 8, 4, 12, 8, 84, 44, 132, 0, 120, 44, 84, 44, 124, 0, 120, 44}}, + {"Sammy Lightfoot", all, "Sammy Lightfoot - Disk 1, Side A.woz", 80_000_000, []int{0, 64, 8, 20}}, + {"Stargate", all, "Stargate - Disk 1, Side A.woz", 50_000_000, []int{0, 8, 0, 72, 68, 80, 68, 80, 12, 44}}, + + // Cross track sync + {"Blazing Paddles", all, "Blazing Paddles (Baudville).woz", 6_000_000, []int{0, 28, 0, 16, 12, 56, 52, 80}}, + {"Take 1", all, "Take 1 (Baudville).woz", 8_000_000, []int{0, 28, 0, 4, 0, 72, 0, 20, 0}}, + {"Hard Hat Mack", all, "Hard Hat Mack - Disk 1, Side A.woz", 10_000_000, []int{0, 134, 132}}, + + // Half tracks + {"The Bilestoad", all, "The Bilestoad - Disk 1, Side A.woz", 6_000_000, []int{0, 24}}, + + // Even more bit fiddling + {"Dino Eggs", all, "Dino Eggs - Disk 1, Side A.woz", 9_000_000, []int{0, 78, 60, 108, 32}}, + {"Crisis Mountain", all, "Crisis Mountain - Disk 1, Side A.woz", 20_000_000, []int{0, 32, 8, 32, 20, 76, 20, 36, 32, 84, 52, 64}}, + {"Miner 2049er II", all, "Miner 2049er II - Disk 1, Side A.woz", 11_000_000, []int{0, 12, 8, 32, 12, 136, 132}}, + + // When bits aren't really bits + {"The Print Shop Companion", all, "The Print Shop Companion - Disk 1, Side A.woz", 14_000_000, []int{0, 68, 44, 68, 40, 68, 40, 136, 60}}, + + // What is the lifepsan of the data latch? + {"First Math Adventures", seq, "First Math Adventures - Understanding Word Problems.woz", 6_000_000, []int{0, 8, 0, 68, 12, 20}}, + + // Reading Offset Data Streams + {"Wings of Fury", seq, "Wings of Fury - Disk 1, Side A.woz", 410_000_000, []int{0, 4, 0, 136, 124, 128, 24, 136, 124, 128, 24, 136, 124, 128, 24, 136, 124, 128, 24, 104}}, + {"Stickybear Town Builder", all, "Stickybear Town Builder - Disk 1, Side A.woz", 8_000_000, []int{0, 16, 12, 112, 80, 100, 8}}, + + // Optimal bit timing + // Requires disk change {"Border Zone", "Border Zone - Disk 1, Side A.woz", 500_000_000, []int{1,1,1,1,1,1}}, + + // Extra + {"Mr. Do", seq, "Mr. Do.woz", 95_000_000, []int{0, 108, 48, 104, 72, 84, 0, 4}}, + {"Wavy Navy", all, "Wavy Navy.woz", 9_000_000, []int{0, 136}}, + // SAGA6 requires disk change, + // Note that Congo Bongo works with the non sequencer implementation but the test is unstable + {"Congo Bongo", seq, "Congo Bongo.woz", 8_000_000, []int{0, 4, 2, 40, 20, 40, 16, 124, 116}}, + // Wizardry III requires disk change, + + } + + for _, tc := range testCases { + if tc.skip == all { + t.Run(tc.name, func(t *testing.T) { + testWoz(t, false, tc.disk, tc.expectedTracks, tc.cycleLimit) + }) + } + if tc.skip == all || tc.skip == seq { + t.Run(tc.name+" SEQ", func(t *testing.T) { + testWoz(t, true, tc.disk, tc.expectedTracks, tc.cycleLimit) + }) + } + + } +} diff --git a/storage/WozSupportStatus.md b/storage/WozSupportStatus.md index 5cb4047..763adc6 100644 --- a/storage/WozSupportStatus.md +++ b/storage/WozSupportStatus.md @@ -1,43 +1,6 @@ # WOZ emulation status: -## Using the behavioral implementation -- How to begin - - DOS 3.3: Works - - DOS 3.2: **Unknown, 13 sector disks boot not supported** -- Next choices - - Bouncing Kamungas: Works - - Commando: ***Not working*** - - Planetfall: Working - - Rescue Raiders: Working - - Sammy Lightfoot: Working - - Stargate: Working -- Cross track sync - - Blazing Paddles: Working - - Take 1: Working - - Hard Hat Mack: Working -- Half tracks - - The Bilestoad: Working -- Even more bit fiddling - - Dino Eggs: Working - - Crisis Mountain: Working - - Miner 2049er II: Working -- When bits aren't really bits - - The Print Shop Companion: Working -- What is the lifespan of the data latch? - - First Math Adventures: ***Not working*** -- Reading Offset Data Streams - - 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** -- 4am on Slack (2021-06-29) - - Mr Do: ***Not working*** - - Wavy Navy: Working - - SAGA 6 Strange Odyssey: **Unknown, there is no UI to swap disks** - - Congo Bongo: Working - - Wizardry II: ***Not working*** - ## With the sequencer: - How to begin - DOS 3.3: Works @@ -73,6 +36,43 @@ - Wavy Navy: Working - SAGA 6 Strange Odyssey: **Unknown, there is no UI to swap disks** - Congo Bongo: Working - - Wizardry II: Working + - Wizardry III: Working +## Using the behavioral implementation +- How to begin + - DOS 3.3: Works + - DOS 3.2: **Unknown, 13 sector disks boot not supported** +- Next choices + - Bouncing Kamungas: Works + - Commando: ***Not working*** + - Planetfall: Working + - Rescue Raiders: Working + - Sammy Lightfoot: Working + - Stargate: Working +- Cross track sync + - Blazing Paddles: Working + - Take 1: Working + - Hard Hat Mack: Working +- Half tracks + - The Bilestoad: Working +- Even more bit fiddling + - Dino Eggs: Working + - Crisis Mountain: Working + - Miner 2049er II: Working +- When bits aren't really bits + - The Print Shop Companion: Working +- What is the lifespan of the data latch? + - First Math Adventures: ***Not working*** +- Reading Offset Data Streams + - 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** +- 4am on Slack (2021-06-29) + - Mr Do: ***Not working*** + - Wavy Navy: Working + - SAGA 6 Strange Odyssey: **Unknown, there is no UI to swap disks** + - Congo Bongo: Working + - Wizardry III: ***Not working*** + diff --git a/trackTracer.go b/trackTracer.go new file mode 100644 index 0000000..6298632 --- /dev/null +++ b/trackTracer.go @@ -0,0 +1,71 @@ +package izapple2 + +type trackTracer interface { + traceTrack(quarterTrack int) +} + +type trackTracerSummary struct { + quarterTracks []int +} + +func makeTrackTracerSummary() *trackTracerSummary { + var tt trackTracerSummary + tt.quarterTracks = make([]int, 0, 100) + return &tt +} + +func (tt *trackTracerSummary) traceTrack(quarterTrack int) { + if tt == nil { + return + } + + length := len(tt.quarterTracks) + if length == 0 { + // Second change, just record + tt.quarterTracks = append(tt.quarterTracks, quarterTrack) + return + } + + last := tt.quarterTracks[length-1] + if quarterTrack == last { + // No changes + return + } + + if length == 1 { + // Second change, just record + tt.quarterTracks = append(tt.quarterTracks, quarterTrack) + return + } + + // We don't want to registers the initial jumps around 0 seen when initializing the disk to track 0 + prevToLast := tt.quarterTracks[length-2] + if length == 2 && prevToLast == 0 && (last == 1 || last == 2) && quarterTrack == 0 { + tt.quarterTracks = tt.quarterTracks[0:0] + } + + // We don't want to track each increment. If tracks goes from 1 to 14, we just want 1 and 14. + wasGoingUp := last > prevToLast + isGoingUp := quarterTrack > last + if isGoingUp == wasGoingUp { + // Same direction, update the last registry + tt.quarterTracks[length-1] = quarterTrack + } else { + // Change direction, add a new registry + tt.quarterTracks = append(tt.quarterTracks, quarterTrack) + } +} + +func (tt *trackTracerSummary) isTraceAsExpected(expected []int) bool { + if len(tt.quarterTracks) != len(expected) { + return false + } + + for i, v := range tt.quarterTracks { + if v != expected[i] { + return false + } + } + + return true +} diff --git a/woz_test_images/Blazing Paddles (Baudville).woz b/woz_test_images/Blazing Paddles (Baudville).woz new file mode 100644 index 0000000..6353f92 Binary files /dev/null and b/woz_test_images/Blazing Paddles (Baudville).woz differ diff --git a/woz_test_images/Border Zone - Disk 1, Side A.woz b/woz_test_images/Border Zone - Disk 1, Side A.woz new file mode 100644 index 0000000..cebf399 Binary files /dev/null and b/woz_test_images/Border Zone - Disk 1, Side A.woz differ diff --git a/woz_test_images/Border Zone - Disk 1, Side B.woz b/woz_test_images/Border Zone - Disk 1, Side B.woz new file mode 100644 index 0000000..a53be1e Binary files /dev/null and b/woz_test_images/Border Zone - Disk 1, Side B.woz differ diff --git a/woz_test_images/Bouncing Kamungas - Disk 1, Side A.woz b/woz_test_images/Bouncing Kamungas - Disk 1, Side A.woz new file mode 100644 index 0000000..4f3d7d6 Binary files /dev/null and b/woz_test_images/Bouncing Kamungas - Disk 1, Side A.woz differ diff --git a/woz_test_images/Commando - Disk 1, Side A.woz b/woz_test_images/Commando - Disk 1, Side A.woz new file mode 100644 index 0000000..5899d3a Binary files /dev/null and b/woz_test_images/Commando - Disk 1, Side A.woz differ diff --git a/woz_test_images/Congo Bongo.woz b/woz_test_images/Congo Bongo.woz new file mode 100644 index 0000000..914b4b9 Binary files /dev/null and b/woz_test_images/Congo Bongo.woz differ diff --git a/woz_test_images/Crisis Mountain - Disk 1, Side A.woz b/woz_test_images/Crisis Mountain - Disk 1, Side A.woz new file mode 100644 index 0000000..64d0344 Binary files /dev/null and b/woz_test_images/Crisis Mountain - Disk 1, Side A.woz differ diff --git a/woz_test_images/DOS 3.2 System Master.woz b/woz_test_images/DOS 3.2 System Master.woz new file mode 100644 index 0000000..1ec6226 Binary files /dev/null and b/woz_test_images/DOS 3.2 System Master.woz differ diff --git a/woz_test_images/DOS 3.3 System Master.woz b/woz_test_images/DOS 3.3 System Master.woz new file mode 100644 index 0000000..2f09782 Binary files /dev/null and b/woz_test_images/DOS 3.3 System Master.woz differ diff --git a/woz_test_images/Dino Eggs - Disk 1, Side A.woz b/woz_test_images/Dino Eggs - Disk 1, Side A.woz new file mode 100644 index 0000000..5cbff67 Binary files /dev/null and b/woz_test_images/Dino Eggs - Disk 1, Side A.woz differ diff --git a/woz_test_images/First Math Adventures - Understanding Word Problems.woz b/woz_test_images/First Math Adventures - Understanding Word Problems.woz new file mode 100644 index 0000000..f7c3d76 Binary files /dev/null and b/woz_test_images/First Math Adventures - Understanding Word Problems.woz differ diff --git a/woz_test_images/Hard Hat Mack - Disk 1, Side A.woz b/woz_test_images/Hard Hat Mack - Disk 1, Side A.woz new file mode 100644 index 0000000..4ed7d20 Binary files /dev/null and b/woz_test_images/Hard Hat Mack - Disk 1, Side A.woz differ diff --git a/woz_test_images/Miner 2049er II - Disk 1, Side A.woz b/woz_test_images/Miner 2049er II - Disk 1, Side A.woz new file mode 100644 index 0000000..cd9a562 Binary files /dev/null and b/woz_test_images/Miner 2049er II - Disk 1, Side A.woz differ diff --git a/woz_test_images/Mr. Do.woz b/woz_test_images/Mr. Do.woz new file mode 100644 index 0000000..2a29e04 Binary files /dev/null and b/woz_test_images/Mr. Do.woz differ diff --git a/woz_test_images/Planetfall - Disk 1, Side A.woz b/woz_test_images/Planetfall - Disk 1, Side A.woz new file mode 100644 index 0000000..e429419 Binary files /dev/null and b/woz_test_images/Planetfall - Disk 1, Side A.woz differ diff --git a/woz_test_images/Rescue Raiders - Disk 1, Side B.woz b/woz_test_images/Rescue Raiders - Disk 1, Side B.woz new file mode 100644 index 0000000..1e03888 Binary files /dev/null and b/woz_test_images/Rescue Raiders - Disk 1, Side B.woz differ diff --git a/woz_test_images/S.A.G.A. 6 - Strange Odyssey side A.woz b/woz_test_images/S.A.G.A. 6 - Strange Odyssey side A.woz new file mode 100644 index 0000000..bd5905b Binary files /dev/null and b/woz_test_images/S.A.G.A. 6 - Strange Odyssey side A.woz differ diff --git a/woz_test_images/S.A.G.A. 6 - Strange Odyssey side B (boot).woz b/woz_test_images/S.A.G.A. 6 - Strange Odyssey side B (boot).woz new file mode 100644 index 0000000..5dd2518 Binary files /dev/null and b/woz_test_images/S.A.G.A. 6 - Strange Odyssey side B (boot).woz differ diff --git a/woz_test_images/Sammy Lightfoot - Disk 1, Side A.woz b/woz_test_images/Sammy Lightfoot - Disk 1, Side A.woz new file mode 100644 index 0000000..e063344 Binary files /dev/null and b/woz_test_images/Sammy Lightfoot - Disk 1, Side A.woz differ diff --git a/woz_test_images/Stargate - Disk 1, Side A.woz b/woz_test_images/Stargate - Disk 1, Side A.woz new file mode 100644 index 0000000..e6dc928 Binary files /dev/null and b/woz_test_images/Stargate - Disk 1, Side A.woz differ diff --git a/woz_test_images/Stickybear Town Builder - Disk 1, Side A.woz b/woz_test_images/Stickybear Town Builder - Disk 1, Side A.woz new file mode 100644 index 0000000..835c575 Binary files /dev/null and b/woz_test_images/Stickybear Town Builder - Disk 1, Side A.woz differ diff --git a/woz_test_images/Take 1 (Baudville).woz b/woz_test_images/Take 1 (Baudville).woz new file mode 100644 index 0000000..f535aee Binary files /dev/null and b/woz_test_images/Take 1 (Baudville).woz differ diff --git a/woz_test_images/The Apple at Play.woz b/woz_test_images/The Apple at Play.woz new file mode 100644 index 0000000..3e209d5 Binary files /dev/null and b/woz_test_images/The Apple at Play.woz differ diff --git a/woz_test_images/The Bilestoad - Disk 1, Side A.woz b/woz_test_images/The Bilestoad - Disk 1, Side A.woz new file mode 100644 index 0000000..4c00f2d Binary files /dev/null and b/woz_test_images/The Bilestoad - Disk 1, Side A.woz differ diff --git a/woz_test_images/The Print Shop Companion - Disk 1, Side A.woz b/woz_test_images/The Print Shop Companion - Disk 1, Side A.woz new file mode 100644 index 0000000..c7d6fa2 Binary files /dev/null and b/woz_test_images/The Print Shop Companion - Disk 1, Side A.woz differ diff --git a/woz_test_images/Wavy Navy.woz b/woz_test_images/Wavy Navy.woz new file mode 100644 index 0000000..ba892d1 Binary files /dev/null and b/woz_test_images/Wavy Navy.woz differ diff --git a/woz_test_images/Wings of Fury - Disk 1, Side A.woz b/woz_test_images/Wings of Fury - Disk 1, Side A.woz new file mode 100644 index 0000000..70de823 Binary files /dev/null and b/woz_test_images/Wings of Fury - Disk 1, Side A.woz differ diff --git a/woz_test_images/Wings of Fury - Disk 1, Side B.woz b/woz_test_images/Wings of Fury - Disk 1, Side B.woz new file mode 100644 index 0000000..959de37 Binary files /dev/null and b/woz_test_images/Wings of Fury - Disk 1, Side B.woz differ diff --git a/woz_test_images/Wizardry III side A - master scenario disk.woz b/woz_test_images/Wizardry III side A - master scenario disk.woz new file mode 100644 index 0000000..48acb10 Binary files /dev/null and b/woz_test_images/Wizardry III side A - master scenario disk.woz differ diff --git a/woz_test_images/Wizardry III side B - boot.woz b/woz_test_images/Wizardry III side B - boot.woz new file mode 100644 index 0000000..4e3b8f2 Binary files /dev/null and b/woz_test_images/Wizardry III side B - boot.woz differ diff --git a/woz_test_images/notes.txt b/woz_test_images/notes.txt new file mode 100644 index 0000000..06aeb55 --- /dev/null +++ b/woz_test_images/notes.txt @@ -0,0 +1,21 @@ +[From Apple II Slack, 4am (2021-06-29)] + +On the subject of "tricky woz images beyond the official test suite," I would recommend + + https://archive.org/details/wozaday_Mr_Do (success = boot to joystick calibration) + https://archive.org/details/wozaday_Wavy_Navy (success = boot to game) + https://archive.org/details/wozaday_SAGA_6_Strange_Odyssey (success = begin game, climb down ladder, take shovel) + https://archive.org/details/wozaday_CongoBongo (success = boot to game) + https://archive.org/details/wozaday_Wizardry_III (success = boot to title screen, press a key, boot to main menu) + + + +Mr. Do relies on weakbits on track 0. Also, the protection check uses LDA $C088,X to fetch nibbles and expects the entire check to complete before the drive motor turns off. + +Wavy Navy relies on weakbits on track $22 + +Strange Odyssey relies on both track length and weakbits on track $22 + +Congo Bongo relies on weakbits on track 1, to a much greater degree than others. There is only one small sequence of valid nibbles, surrounded by an entire track of weakbits. This has flummoxed many emulators. + +Wizardry III relies on track length, and it is extremely sensitive to the precise timing of when the data latch "sees" bits and how long it holds on to a full nibble before resetting itself.