Practice

Loft Clock Wire

A pigeon racing club times every returning bird with an electronic loft clock. When a bird lands, the clock stamps its ring number and arrival time. It sends each stamp, one byte at a time, over a serial wire to the logger in the clubhouse.

The old clock's transmitter board was built wrong. It sent every byte highest bit first. UART receivers expect the lowest bit first, so the logger recorded garbage ring numbers. Two race results were voided before anyone traced the fault.

Your task: build the clock's UART transmitter. When send_i pulses while the line is idle, capture the byte on data_i. Then drive tx_o with a start bit, the 8 data bits lowest bit first, and a stop bit, each lasting 8 clock cycles. Hold busy_o high while the frame is on the wire, and ignore send_i until the frame is done.

Interface

PortDirectionTypeDescription
clk_iin1 bitSystem clock
rst_iin1 bitSynchronous reset (active high)
send_iin1 bitTransmit request (one-cycle pulse)
data_iin8-bit vectorByte to transmit
tx_oout1 bitSerial line to the logger (idle high)
busy_oout1 bitHigh while a frame is on the wire

Behavior

  • When idle, tx_o is high and busy_o is low
  • While idle, send_i high at a rising clock edge accepts the byte on data_i: busy_o rises and the start bit begins on that same edge
  • Cycle numbering: cycle 0 is the first full cycle with busy_o high
  • A frame is 10 bits: a start bit 0, the 8 data bits LSB first (bit 0 of the byte first), and a stop bit 1
  • Each bit lasts exactly 8 clock cycles: the baud divisor is fixed, not a parameter
  • tx_o drives the start bit during cycles 0 to 7 and the stop bit during cycles 72 to 79
  • Data bit 0 is on the wire during cycles 8 to 15
  • Each next data bit takes the next 8 cycles, ending with data bit 7 during cycles 64 to 71
  • At cycle 80 the frame is over: busy_o returns low and tx_o stays high
  • busy_o is high during cycles 0 through 79 and low at every other time
  • The byte is captured when send_i is accepted; later changes on data_i do not affect the frame
  • A send_i pulse while busy_o is high is ignored: nothing is queued and nothing extra is sent later
  • send_i high during the first idle cycle after a frame begins a new frame on the next cycle
  • rst_i = 1 at a rising clock edge cancels any frame: tx_o returns high and busy_o low on the next cycle

What the bench checks

  • The testbench checks tx_o and busy_o against the fixed timeline on every cycle of every frame
  • The testbench decodes the wire like a receiver: it samples each data bit mid-slot and compares the rebuilt byte
  • The testbench sends byte values that expose reversed bit order, a missing start bit, and a broken stop bit
  • The testbench changes data_i right after acceptance and checks the wire still carries the captured byte
  • The testbench pulses send_i with a decoy byte in the middle of one frame and checks that no extra frame follows
  • The testbench pulses send_i with a decoy byte on the last busy cycle of one frame and checks the line stays idle after it
  • The testbench starts one frame with send_i high during the first idle cycle after the previous frame
  • The testbench asserts rst_i in the middle of one frame and checks tx_o and busy_o are idle on the next cycle

Constraints

TIMING: everything is synchronous to clk_i; all outputs are registered.

SCOPE: this models the transmitter side of the wire at a fixed 8-cycle bit time. The ring reading, the time stamping, and the logger's receiver are out of scope.

Do not add ports.

Loading editor...

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