Practice

Fertigation Frame Guard

Vela Growers runs a fertigation system: a computer doses fertilizer and acid into the greenhouse irrigation water. Recipe frames travel to the dosing engine over 300 m of noisy serial cable, past 200 lamp igniters. Last April a corrupted frame told the acid pump to run 9 times longer than intended. The dosing hardware obeyed, and the acid overdose killed three rows of seedlings. The corrective action lands on your desk.

Two habits of the sending computer matter. Its watchdog restarts transmissions in the middle of anything. And every few seconds it sends a heartbeat: a frame with LEN of 0. The old guard prototype locked up on the first heartbeat of the season. That is why the greenhouse still runs unguarded.

Your task: build a guard block between the line decoder and the dosing engine, so that no frame reaches the engine without the guard's approval. The decoder hands you the framing: sof_i pulses at the start of a frame, and dv_i pulses once for each received byte on d_i. Check each frame's checksum as the bytes stream past. Pulse one verdict per frame: ok_o when the sum matches, bad_o when it does not.

Interface

PortDirectionTypeDescription
clk_iin1 bitClock
rst_iin1 bitSynchronous reset (active high)
sof_iin1 bitStart-of-frame marker, 1 cycle wide
dv_iin1 bitByte strobe, 1 cycle wide per byte
d_iin8-bit vectorDecoded byte from the line
ok_oout1 bitFrame verdict good, 1-cycle pulse (registered)
bad_oout1 bitFrame verdict corrupt, 1-cycle pulse (registered)

Behavior

  • After sof_i, the first dv_i byte is LEN, the next LEN dv_i bytes are payload, and the following dv_i byte is the checksum
  • The checksum is valid when it equals (LEN + sum of payload bytes) mod 256; the length byte is inside the sum
  • The cycle after the checksum byte is sampled, exactly one of ok_o or bad_o pulses for exactly one cycle; both are 0 at all other times
  • LEN = 0 is legal (heartbeat): the checksum byte follows the length byte directly and must equal LEN
  • An sof_i at any point abandons the frame in progress with no verdict and starts a fresh frame
  • Nothing from the abandoned frame may leak into the new frame's sum
  • A dv_i coinciding with sof_i is ignored: the byte belongs to the marker, and the next dv_i byte is the new frame's LEN
  • dv_i bytes outside any frame are ignored; gaps of any length between bytes are legal
  • A new sof_i may arrive on the very cycle a verdict pulses
  • rst_i = 1 at a rising edge returns the guard to idle, verdict pulses low, frame in progress forgotten

What the bench checks

  • The testbench checks ok_o and bad_o on every cycle
  • Good and bad frames verify that the checksum includes LEN and that each verdict lasts one cycle
  • Valid frames cover arbitrary gaps, zero-length heartbeats, and an eight-byte payload
  • Wrapped checksum sums are accepted modulo 256, while an off-by-one checksum after the wrap is rejected
  • A new sof_i mid-payload or where a checksum was expected must abandon the old frame without a verdict
  • A byte arriving with sof_i and stray bytes outside a frame must be ignored
  • Reset mid-frame must cancel it, and a new sof_i during a verdict pulse must start the next frame cleanly

Constraints

TIMING: everything is synchronous to clk_i; ok_o and bad_o are registered one-cycle pulses.

SCOPE: this models the checksum guard between decoder and dosing engine. The line decoder, the noisy cable, and the dosing hardware are out of scope; framing arrives ready-made on sof_i and dv_i.

STREAMING: do not buffer whole frames. LEN can be up to 255, and the guard must judge the stream as it flows.

Do not add ports.

Loading editor...

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