diff --git a/.gitignore b/.gitignore index 9e3347a..37b4dee 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ mem.prof mos6502go.test apple2e.rom dos33.dsk +prodos.dsk diff --git a/mmu/io.go b/mmu/io.go index 341436a..a136156 100644 --- a/mmu/io.go +++ b/mmu/io.go @@ -93,8 +93,8 @@ const ( var DriveState struct { Drive uint8 Spinning bool - Phase uint8 - ArmPosition uint8 + Phase int8 + Phases uint8 BytePosition int Q6 bool Q7 bool @@ -116,7 +116,6 @@ func InitIO() { DriveState.Drive = 1 DriveState.Spinning = false DriveState.Phase = 0 - DriveState.ArmPosition = 0 DriveState.BytePosition = 0 DriveState.Q6 = false DriveState.Q7 = false @@ -193,31 +192,41 @@ func readWrite(address uint16, isRead bool) bool { // Ignore not implemented memory management reg return true - // Drive stepper motor phase change + // Drive stepper motor phase change case S6CLRDRVP0, S6SETDRVP0, S6CLRDRVP1, S6SETDRVP1, S6CLRDRVP2, S6SETDRVP2, S6CLRDRVP3, S6SETDRVP3: - if ((address - S6CLRDRVP0) % 2) == 1 { - // When the magnet coil is energized, move the arm by half a track - phase := int8(address-S6CLRDRVP0) / 2 - change := int8(DriveState.Phase) - phase - if change < 0 { - change += 4 + magnet := (address - S6CLRDRVP0) / 2 + on := ((address - S6CLRDRVP0) % 2) == 1 + + if on { + DriveState.Phases |= (1 << magnet) + + // Move head if a neighboring magnet is on and all others are off + direction := int8(0) + if (DriveState.Phases & (1 << uint8((DriveState.Phase+1)&3))) != 0 { + direction += 1 + } + if (DriveState.Phases & (1 << uint8((DriveState.Phase+3)&3))) != 0 { + direction -= 1 } - if change == 1 { // Inward - if DriveState.ArmPosition > 0 { - DriveState.ArmPosition-- - } - } else if change == 3 { // Outward - if DriveState.ArmPosition < 79 { - DriveState.ArmPosition++ - } - } + if direction != 0 { + DriveState.Phase += direction - DriveState.Phase = uint8(phase) - MakeTrackData(DriveState.ArmPosition) - if audio.ClickWhenDriveHeadMoves { - audio.Click() + if DriveState.Phase < 0 { + DriveState.Phase = 0 + } + if DriveState.Phase == 80 { + DriveState.Phase = 79 + } + + MakeTrackData(uint8(DriveState.Phase)) + + if audio.ClickWhenDriveHeadMoves { + audio.Click() + } } + } else { + DriveState.Phases &= ^(1 << magnet) } return true diff --git a/prodos_boot_test.go b/prodos_boot_test.go new file mode 100644 index 0000000..04c76b6 --- /dev/null +++ b/prodos_boot_test.go @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" + "mos6502go/cpu" + "mos6502go/keyboard" + "mos6502go/mmu" + "mos6502go/system" + "mos6502go/utils" + "mos6502go/video" + "testing" + "time" +) + +const prodosDiskImage = "prodos.dsk" + +func TestProdosBoot(t *testing.T) { + cpu.InitInstructionDecoder() + mmu.InitRAM() + mmu.InitApple2eROM() + mmu.InitIO() + mmu.ReadDiskImage(prodosDiskImage) + cpu.Init() + keyboard.Init() + video.Init() + system.Init() + cpu.SetColdStartReset() + cpu.Reset() + + t0 := time.Now() + + utils.RunUntilBreakPoint(t, 0xc600, 2, false, "Boot ROM") + utils.RunUntilBreakPoint(t, 0x0801, 2, false, "Loader") + utils.RunUntilBreakPoint(t, 0x2000, 3, false, "Relocator") + utils.RunUntilBreakPoint(t, 0x0080, 1, false, "AUX RAM test") + utils.RunUntilBreakPoint(t, 0x2932, 1, false, "Relocation done") + utils.RunUntilBreakPoint(t, 0x21f3, 1, false, "The first JSR $bf00 - ONLINE - get names of one or all online volumes") + utils.RunUntilBreakPoint(t, 0xd000, 1, false, "First call to MLI kernel") + // utils.RunUntilBreakPoint(t, 0x0800, 1, false, "BI loader") + + elapsed := float64(time.Since(t0) / time.Millisecond) + fmt.Printf("CPU Cycles: %d\n", system.FrameCycles) + fmt.Printf("Time elapsed: %0.2f ms\n", elapsed) + fmt.Printf("Speed: %0.2f cycles/ms\n", float64(system.FrameCycles)/elapsed) +}