Practice

Workshop PS2 Keyboard

Marlow Toolroom still runs its CNC console from an old PS/2 keyboard with a space bar worn smooth. Operators use it to send jog commands while setting up each job.

The keyboard sends each bit on two slow wires and supplies its own clock.

One winter morning, a damaged frame passed through the console reader without a check. The bad scan code was read as "jog left, fast."

The steel table struck its end stop, and coolant sloshed from the tray before the operator could react.

Your task: build a PS/2 receiver that checks each start bit, parity bit, and stop bit. Quietly discard broken or incomplete frames. Only a complete, correct frame may update the saved scan code.

Interface

PortDirectionTypeDescription
clkin1 bitConsole system clock, much faster than the keyboard clock
rstin1 bitSynchronous reset (active high)
ps2_clkin1 bitKeyboard clock line
ps2_datain1 bitKeyboard data line
scanout8-bit vectorLast good scan code, held
validout1 bitOne-clock pulse for each good frame
parity_errout1 bitOne-clock pulse on a parity failure
frame_errout1 bitOne-clock pulse on a bad start, bad stop, or mid-frame timeout

Behavior

  • Each PS/2 input passes through its own two-flop synchronizer before any receiver logic examines it
  • Data is captured on each detected falling edge of the synchronized ps2_clk
  • Each frame contains exactly 11 captured bits
  • The first bit is the start bit, and it must be 0
  • A bad start bit makes frame_err pulse on the clock that detects its falling edge
  • A bad start bit is not treated as a frame, and the receiver remains idle
  • The next eight bits form the scan code, least significant bit first
  • The tenth bit is the odd-parity bit
  • The eight data bits and parity bit together must contain an odd number of ones
  • The eleventh bit is the stop bit, and it must be 1
  • For a good frame, scan updates one clock after the stop bit's captured edge
  • valid pulses on that same update clock
  • For a completed frame with bad parity, parity_err pulses instead, and scan does not change
  • A bad stop bit makes frame_err pulse, and scan does not change
  • If 128 system clocks pass mid-frame without the next captured falling edge, frame_err pulses
  • A timeout discards the partial frame and returns the receiver to idle
  • valid, parity_err, and frame_err are one-clock pulses and never overlap
  • scan holds its last good value through every failed or incomplete frame
  • rst high at a rising edge clears all outputs, clears scan to zero, and returns the receiver to idle
  • All outputs are registers

What the bench checks

  • The testbench drives keyboard lines with irregular but legal timing and checks every output on every clock against a model with both synchronizer chains
  • It sends good frames whose codes reveal the least significant bit first order
  • It completes a frame with bad parity and checks a parity_err pulse with scan untouched
  • It sends a bad stop bit and a bad start bit and checks the right frame_err pulse for each
  • It silences the keyboard mid-frame and checks one frame_err pulse after 128 quiet clocks, with the partial frame discarded
  • It checks that scan holds its last good value through every failure and updates only on valid
  • It resets while idle and mid-frame and checks cleared outputs and an idle receiver

Constraints

TIMING

receiver behavior is synchronous to clk after two-flop input synchronization. Keyboard edges arrive far slower than clk in this bench. All outputs are registered.

SCOPE

the two-flop chain is the required discipline for a foreign clock line. An RTL run does not prove metastability safety.

Do not add ports.

Loading editor...

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