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

Valid and Acknowledge Data Synchronizer

MediumVerilog / SystemVerilogBuild

Independent clock domains cannot share wide data buses directly because routing skew guarantees that different bits will arrive at different times, violating setup and hold constraints. A valid-acknowledge handshake synchronizer solves this by passing a single control signal across the boundary while holding the data bus perfectly stable.

The module bridges a source domain (clk_a) and a destination domain (clk_b). When valid_a is asserted and the synchronizer is ready, the source domain latches data_a into an internal holding register and asserts an internal request signal. This request is passed through a 2-flop synchronizer into the destination domain. Upon detecting the synchronized request going high, the destination domain captures the held data into data_b, emits a single-cycle valid_b pulse, and asserts an acknowledge signal back to the source. The source domain synchronizes this acknowledge, deasserts the request, and waits for the acknowledge to fall before becoming ready for a new transaction.

Timing and Reset Rules: • Clock edges: posedge clk_a and posedge clk_b. • Resets: Asynchronous, active-low resets rst_n_a and rst_n_b for their respective domains. • On reset, all registers and outputs reset to 0, except ready_a which resets to 1. • data_b retains its previous value between valid transfers. • If valid_a is asserted while ready_a is 0, the input must be ignored. • The internal request and acknowledge signals must be synchronized using exactly two flip-flops in the receiving domain.

Worked Trace (Logical Sequence): • Step 1 (clk_a): rst_n_a=0, rst_n_b=0. ready_a=1, data_b=0. • Step 2 (clk_a): valid_a=1, data_a=0x55. Module latches data, sets internal req_a=1, ready_a=0. • Step 3 (clk_b): req_a passes through 2-flop synchronizer in clk_b domain. • Step 4 (clk_b): Synchronized request goes high. valid_b=1, data_b=0x55, internal ack_b=1. • Step 5 (clk_b): valid_b=0 (pulse ends). ack_b remains 1. • Step 6 (clk_a): ack_b passes through 2-flop synchronizer in clk_a domain. • Step 7 (clk_a): Synchronized acknowledge goes high. Module sets internal req_a=0. • Step 8 (clk_b): req_a=0 passes through 2-flop synchronizer in clk_b domain. • Step 9 (clk_b): Synchronized request goes low. Module sets internal ack_b=0. • Step 10 (clk_a): ack_b=0 passes through 2-flop synchronizer in clk_a domain. • Step 11 (clk_a): Synchronized acknowledge goes low. Module sets ready_a=1.

{ "signal": [
  { "name": "clk_a", "wave": "p..................." },
  { "name": "valid_a", "wave": "010................." },
  { "name": "data_a", "wave": "x=x.................", "data": ["D1"] },
  { "name": "ready_a", "wave": "10.................1" },
  { "name": "req_a (internal)", "wave": "01.........0........" },
  {},
  { "name": "clk_b", "wave": "p..................." },
  { "name": "req_sync (clk_b)", "wave": "0...1.........0....." },
  { "name": "valid_b", "wave": "0...10.............." },
  { "name": "data_b", "wave": "=...=...............", "data": ["0", "D1"] },
  { "name": "ack_b (internal)", "wave": "0...1.........0....." },
  {},
  { "name": "ack_sync (clk_a)", "wave": "0......1.........0.." }
], "head": { "text": "4-phase handshake synchronizing data across clock domains." } }

| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | clk_a | input | 1 | Clock for the source domain | | rst_n_a | input | 1 | Asynchronous active-low reset for the source domain | | valid_a | input | 1 | High when data_a is valid; initiates a transfer | | data_a | input | 8 | Data to be transferred | | ready_a | output | 1 | High when the synchronizer can accept a new transfer | | clk_b | input | 1 | Clock for the destination domain | | rst_n_b | input | 1 | Asynchronous active-low reset for the destination domain | | valid_b | output | 1 | 1-cycle pulse in clk_b domain when data_b is newly updated | | data_b | output | 8 | Synchronized data |

Constraints

  • The synchronizers must use exactly two flip-flops for both the request and acknowledge signals.
  • The data bus must not be synchronized through flip-flops directly; it must be captured using the synchronized control signal.
  • valid_b must be exactly a 1-cycle pulse in the clk_b domain.
  • ready_a must remain low until the entire 4-phase handshake completes (acknowledge returns to 0).

Topics

CDCSynchronizationHandshake

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