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

PortDirectionTypeDescription
clkin1 bitClock
rstin1 bitSynchronous reset (active high), dock holds a bike
tapin1 bitValid card tap, 1 cycle wide
removedin1 bitBike lifted out of the jaw, 1 cycle wide
dockedin1 bitBike pushed back into the jaw, 1 cycle wide
unlockout1 bitJaw solenoid drive, changes only at clock edges
occupiedout1 bitBike-present status to the app, changes only at clock edges

Behavior

  • After reset the dock is HOLDING: occupied = 1, unlock = 0
  • A tap sampled while HOLDING starts the pull: unlock is high for exactly the next four cycles
  • If removed was high during any of those four cycles, the dock goes straight to EMPTY when the window ends
  • Straight to EMPTY means unlock and occupied both low from the fifth cycle after the tap, with no open-jaw wait
  • If removed did not arrive during the window, the jaw stays open (unlock high, occupied high) until the cycle removed is sampled
  • In that case unlock and occupied drop together on the next cycle
  • In EMPTY, a docked pulse returns the dock to HOLDING (occupied high the next cycle); tap and removed are ignored
  • tap is ignored outside HOLDING
  • removed is ignored in HOLDING and in EMPTY; docked is ignored outside EMPTY
  • rst = 1 at any rising edge returns the dock to HOLDING, whatever was in flight

What the bench checks

  • The testbench checks unlock and occupied on every cycle
  • A slow rental must keep the jaw open after the four-cycle pull window until removed arrives
  • 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

TIMING

everything is synchronous to clk; both outputs are decoded from state held in registers and change only at clock edges.

SCOPE

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.

PULL WINDOW

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.

Loading editor...

Click Run to execute your code. Output will appear here.