The Problem
Days 2-5 showed single-bit and multi-bit synchronizers. But real systems need data + control. How do you send a packet from one clock domain to another?
Handshake Protocol
A handshake synchronizes a data transfer with a request-acknowledge sequence:
// Sender (clock domain A)
always @(posedge clk_a) begin
if (have_data) begin
data_a <= packet;
req_a <= 1;
end
if (ack_sync_a) req_a <= 0; // Wait for ack
end
// Receiver (clock domain B)
always @(posedge clk_b) begin
if (req_sync_b) begin
captured_data <= data_sync;
ack_b <= 1;
end else begin
ack_b <= 0;
end
end
// Synchronizers
sync_2ff req_sync_inst (.in(req_a), .out(req_sync_b), .clk(clk_b));
sync_2ff ack_sync_inst (.in(ack_b), .out(ack_sync_a), .clk(clk_a));
sync_bus data_sync_inst (.in(data_a), .out(data_sync), .req(req_sync_b));Stability Requirement
Critical: Data must be stable for 2+ clock cycles (clk_b) after req_sync goes high. This allows proper sampling and return handshake.
Key Takeaways
- ✅ Handshake = req/ack pulse synchronization
- ✅ Data stable while req_sync high
- ✅ Works for any size packet
Day 7: Reset synchronization—the overlooked problem.