CodiodeCodiode
Home
Problem Solving
Skill Tracks
My Assignments
Contests
Leaderboard
Community
Settings
Codiode/Problems/Sequential Logic

Bit Stream Cast to Packed Struct

MediumVerilog / SystemVerilogBuild

Network interfaces receive packet data as a continuous serial bitstream. Once the physical layer detects a packet boundary, the raw bits must be grouped and interpreted as structured headers for routing and filtering. Casting raw bit vectors directly into SystemVerilog packed structs avoids dozens of manual bit-slicing assignments and prevents common off-by-one indexing errors.

The solution module receives a serial data stream via rx_bit. While rx_valid is high, bits are shifted into a 48-bit internal register (MSB first). When a sync pulse arrives, the accumulated 48-bit vector must be cast into a packed structure representing a miniature MAC header. This header consists of a 24-bit destination address followed by a 24-bit source address. These fields are immediately registered to the output ports along with a valid flag.

Timing and Reset Rules

  • Clock edge: posedge clk
  • Reset type: Asynchronous, active-low (rst_n)
  • Reset behavior: All internal registers and outputs reset to 0.
  • Priority: sync and rx_valid are independent. If sync is asserted, the outputs capture the shift register's state *before* any shift occurring on that exact same clock edge.
  • Hold behavior: dest_addr and src_addr must hold their values until the next sync pulse. header_valid is strictly a one-cycle pulse per sync.

Worked Trace

Assume the shift register has already accumulated 44 bits, and we are receiving the final 4 bits to form 48'hAAAAAA_BBBBBB.

Cycle 1: rst_n=0, rx_valid=0, sync=0 → dest_addr=0, src_addr=0, header_valid=0 Cycle 2: rst_n=1, rx_valid=1, rx_bit=1, sync=0 → dest_addr=0, src_addr=0, header_valid=0 Cycle 3: rst_n=1, rx_valid=1, rx_bit=0, sync=0 → dest_addr=0, src_addr=0, header_valid=0 Cycle 4: rst_n=1, rx_valid=1, rx_bit=1, sync=0 → dest_addr=0, src_addr=0, header_valid=0 Cycle 5: rst_n=1, rx_valid=1, rx_bit=1, sync=0 → dest_addr=0, src_addr=0, header_valid=0 (shift_reg reaches 48'hAAAAAA_BBBBBB) Cycle 6: rst_n=1, rx_valid=0, rx_bit=0, sync=1 → dest_addr=24'hAAAAAA, src_addr=24'hBBBBBB, header_valid=1 Cycle 7: rst_n=1, rx_valid=0, rx_bit=0, sync=0 → dest_addr=24'hAAAAAA, src_addr=24'hBBBBBB, header_valid=0 Cycle 8: rst_n=1, rx_valid=0, rx_bit=0, sync=1 → dest_addr=24'hAAAAAA, src_addr=24'hBBBBBB, header_valid=1

Timing Diagram

{ "signal": [
  { "name": "clk",          "wave": "p......." },
  { "name": "rst_n",        "wave": "01......" },
  { "name": "rx_valid",     "wave": "01.0..0." },
  { "name": "rx_bit",       "wave": "x1.x..x." },
  { "name": "sync",         "wave": "0...10.1" },
  {},
  { "name": "dest_addr",    "wave": "0...=..=", "data": ["24'hAAAAAA", "24'hAAAAAA"] },
  { "name": "src_addr",     "wave": "0...=..=", "data": ["24'hBBBBBB", "24'hBBBBBB"] },
  { "name": "header_valid", "wave": "0...10.1" }
], "head": { "text": "Sync asserts, capturing the 48-bit shift register into struct fields." } }

Port Table

| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | clk | input | 1 | Positive-edge triggered clock | | rst_n | input | 1 | Asynchronous active-low reset; all outputs go to 0 when asserted | | rx_bit | input | 1 | Serial data input | | rx_valid | input | 1 | Shift enable; shifts rx_bit into the LSB of the register when high | | sync | input | 1 | Synchronization pulse; casts register to struct and updates outputs | | dest_addr | output | 24 | Destination address field extracted from the struct | | src_addr | output | 24 | Source address field extracted from the struct | | header_valid | output | 1 | Asserted for exactly one cycle when outputs are updated |

Constraints

  • Clock is posedge, reset is asynchronous active-low.
  • All outputs must reset to 0.
  • The shift register must shift left (MSB first), meaning the first bit received becomes bit 47.
  • dest_addr occupies the upper 24 bits (47:24) and src_addr occupies the lower 24 bits (23:0).
  • sync evaluates the shift register state before any shifts happen on that same clock edge.
  • dest_addr and src_addr must hold their values until the next sync pulse. header_valid is strictly a one-cycle pulse per sync.

Topics

Shift RegisterSystemVerilogStructsDeserialization

Solve this problem

Write the module in Verilog, SystemVerilog or VHDL. Your submission is compiled and simulated against a real testbench — you get the waveform back, not a stored answer.

This problem is part of Codiode Pro. The statement above is free to read.

Sign in to solveSee what Pro unlocks

The circuit builder and code editor need a desktop screen. On a phone, read the problem here and open it on a laptop to solve.

Related problems

  • Basic D Flip FlopEasy
  • Debug: Missing Edge in Sensitivity ListMedium
  • Read After Write Hazard DetectionEasy
  • Parameterized Interface with ModportsHard
  • Struct Array PipelineHard
  • T Flip Flop from D Flip Flop TemplateEasy
  • Recursive Generate Reduction TreeHard
  • Four Stage Shift RegisterEasy

Browse all problems · Learning tracks