Practice
Ghost Bike Dock
Dock 7 at the Riverside bike-share station jams a few times a week. The app shows a bike present, and the locking jaw's solenoid (the electromagnet that drives the jaw) buzzes at full current. But there is no bike in the dock at all. The operations team calls them ghost bikes. Maintenance has replaced two burned-out solenoids this season. The station logs show the jam always follows a rental by one of the fast regulars: commuters who pull the bike out before the buzz has finished.
The block in your editor is the jaw controller as it shipped. Slow customers run the intended cycle a thousand times a day without trouble, and the test rig only ever tried that path. The fast regulars free the bike a couple of cycles into the pull, so removed pulses while the solenoid is still in its 4-cycle window. Follow the shipped state machine with a pulse arriving there, and you will see exactly how dock 7 gets stuck.
Your task: fix the controller in place, so that a fast pull ends the same way a slow one does. Bike gone, jaw released, app showing an empty dock.
Interface
| Port | Direction | Type | Description |
|---|---|---|---|
clk | in | 1 bit | Clock |
rst | in | 1 bit | Synchronous reset (active high), dock holds a bike |
tap | in | 1 bit | Valid card tap, 1 cycle wide |
removed | in | 1 bit | Bike lifted out of the jaw, 1 cycle wide |
docked | in | 1 bit | Bike pushed back into the jaw, 1 cycle wide |
unlock | out | 1 bit | Jaw solenoid drive, changes only at clock edges |
occupied | out | 1 bit | Bike-present status to the app, changes only at clock edges |
Behavior
- After reset the dock is HOLDING:
occupied = 1,unlock = 0 - A
tapsampled while HOLDING starts the pull:unlockis high for exactly the next four cycles - If
removedwas high during any of those four cycles, the dock goes straight to EMPTY when the window ends - Straight to EMPTY means
unlockandoccupiedboth low from the fifth cycle after the tap, with no open-jaw wait - If
removeddid not arrive during the window, the jaw stays open (unlockhigh,occupiedhigh) until the cycleremovedis sampled - In that case
unlockandoccupieddrop together on the next cycle - In EMPTY, a
dockedpulse returns the dock to HOLDING (occupiedhigh the next cycle);tapandremovedare ignored tapis ignored outside HOLDINGremovedis ignored in HOLDING and in EMPTY;dockedis ignored outside EMPTYrst = 1at any rising edge returns the dock to HOLDING, whatever was in flight
What the bench checks
- The testbench checks
unlockandoccupiedon every cycle - A slow rental must keep the jaw open after the four-cycle pull window until
removedarrives - Removals on the first, middle, and final pull cycles must be remembered while the full window finishes
- Returns must restore occupancy, while taps, removals, and dock events in the wrong states must be ignored
- Reset during either the pull window or open-jaw wait must return the controller to occupied holding state
Constraints
everything is synchronous to clk; both outputs are decoded from state held in registers and change only at clock edges.
this models the jaw controller's state machine. The solenoid electronics, the card reader, and the app are out of scope; tap, removed, and docked arrive as clean one-cycle pulses.
the four-cycle pull is a mechanical requirement and must not shrink.
The template contains the shipped controller: fix it in place rather than starting over.
Do not add ports.
Click Run to execute your code. Output will appear here.