Skip to content

Model the Disk ][ drive: no class owns per-drive hardware state #136

Description

@relmer

The gap

There is no class for a Disk ][ drive. The card (Disk2Controller) and the sequencer (Disk2NibbleEngine) are both modeled, so every drive-level fact landed in whichever of those two was nearest.

The rule that sorts it: share the path, not the memory. A real card has one logic state sequencer and one shift register, so it can only talk to one drive at a time. That part is modeled correctly. What went wrong is that state which survives deselection got stored where the shared path lives, because it happens to be manipulated through shared latches.

Per-drive facts currently stored once, on the card

m_phase                  stepper detent
m_quarterTrack           head position          -> issue #135
m_motorSpinupRemaining   mechanism
m_motorSpindownCycles    mechanism

Card facts currently mirrored down into each engine

m_shiftLoadMode  = Q6    already Disk2Controller::m_q6
m_writeMode      = Q7    already Disk2Controller::m_q7

Copied into the selected engine on every drive select, so the same bit lives in three places.

Engine members that belong to a drive

m_disk           media binding
m_currentTrack   head position (quarter-tracks, see naming note below)
m_motorOn        spindle
m_bitPos         rotational position of the medium
m_headWindow     head and flux analog behavior; weak bits are a property
m_weakRngState   of the medium, not of the reader
m_readNibbles    per-drive activity counters
m_writeNibbles

Engine members that are genuinely card-level

m_lssState, m_lssClock                the P6 sequencer state machine
m_readLatch, m_bus, m_latchIsFresh    the 74LS323 shift register and data bus

Not modeled anywhere today

  • The drive, hence this issue.
  • Door state. Lives in DriveWidgetState, a UI struct, and in DiskImageStore / BayChange. The core does not know a door exists.
  • A port with no drive on it. kDriveCount = 2, and both DiskImage and Disk2NibbleEngine are always constructed, so "one drive attached" cannot be expressed. The //c's optional external drive is currently a shell predicate about whether to draw a widget.
  • The write-protect sensor. The guest can read the sense bit, but Disk2Controller reaches straight into DiskImage::IsWriteProtected(). The notch is on the medium; the sensor is in the drive; there is no drive in between.

Naming hazard found on the way

Disk2NibbleEngine::GetCurrentTrack() returns quarter-tracks, 0 to 139, not whole tracks. Disk2Controller::SetCurrentTrack(m_quarterTrack) feeds it a quarter-track, and both call sites do ResolveQuarterTrack(m_currentTrack). The neighbouring kMaxTrack = 159 makes it worse. Disk2Controller::GetCurrentTrack(), by contrast, does return whole tracks. Two methods, one name, different units. Rename as part of this.

Shape of the work

Mostly relocation, not new abstraction: four members move down off the card, eight move sideways out of the engine, two stop being mirrored. Genuinely new modeling is the door and the empty port.

Testing

Disk2Controller and CassoEmuCore/Devices/Disk/ are both scenario-suite trigger paths, so RunTests.ps1 -Build -Scenario is required. The timing-adjacent parts argue for Dormann and Harte as well.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestimpact: engineeringInternal only: testability, architecture, maintainabilitypriority: mediumReal value, niche or polish (end-user-value triage)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions