Design the pointer half of an asynchronous FIFO side: a binary count, its Gray copy in a register of its own, and the decode of the far side's Gray pointer.
Hardware context: The pointers of an asynchronous FIFO, counted in binary and sent across in Gray code. Design the pointer half of a FIFO side: a binary count, its registered Gray copy, and the far decode.
Each side of an asynchronous FIFO keeps a pointer that counts in binary and sends a Gray copy of it across, one bit changing per step, so the far side reads the old position or the new one and never a mix (lesson R6.4). It decodes the far side's Gray pointer back to binary to compute its flag.
Write gray_ptr, the pointer half of one side. At every edge where inc is 1 the count bin_q steps by one and wraps from 2^W - 1 to 0. gray_q is a register of its own that holds the Gray code of bin_q at all times: it is loaded with the code of the next count at the same edge. far_bin is the binary value of far_gray, decoded with no clock.
Brief: parameter W from 2 to 8; ports clk, rst_n (asynchronous, active-low), inc and far_gray[W-1:0] in; bin_q, gray_q and far_bin [W-1:0] out. bin_q and gray_q are 0 after reset and change only at a rising edge, together. Binary to Gray is b ^ (b >> 1); in Gray to binary, bit i is the XOR of Gray bits W-1 down to i. The tests run copies with W = 4 and 6. Synthesis check: the design must build on the site's synthesis flow with no latch.
Signals in the timeline
| Signal | Width | Role |
|---|---|---|
clk | 1 | stimulus, the same for every design |
inc | 1 | stimulus, the same for every design |
bin_q | 8 | stimulus, the same for every design |
gray_q | 8 | stimulus, the same for every design |
Full specification
module gray_ptr #(parameter int W = 4) (
input logic clk,
input logic rst_n, // asynchronous, active-low
input logic inc, // 1: count one at this edge
output logic [W-1:0] bin_q, // the count, in binary, for this side's own use
output logic [W-1:0] gray_q, // the same count in Gray code: the copy that crosses
input logic [W-1:0] far_gray, // the other side's Gray pointer, after its synchronizer
output logic [W-1:0] far_bin // far_gray as a binary count
);
// your design
endmodule
| Output | Definition |
|---|---|
| bin_q | Register. Reset: 0. At a rising edge: bin_q + inc, modulo 2^W. |
| gray_q | Register. Reset: 0. At a rising edge: the Gray code of the new bin_q, so gray_q = bin_q ^ (bin_q >> 1) after every edge. |
| far_bin | Combinational: far_bin[i] = far_gray[W-1] ^ ... ^ far_gray[i]. |
| Count | Gray (W = 4) | Count | Gray (W = 4) |
|---|---|---|---|
| 0 | 0000 | 8 | 1100 |
| 1 | 0001 | 9 | 1101 |
| 2 | 0011 | 10 | 1111 |
| 3 | 0010 | 11 | 1110 |
| 4 | 0110 | 12 | 1010 |
| 5 | 0111 | 13 | 1011 |
| 6 | 0101 | 14 | 1001 |
| 7 | 0100 | 15 | 1000 |
Each case resets the copy at 1 ns, then runs 72 rising edges of a 10 ns clock (edges 0 to 71) with inc set 1 ns after each edge for the next. The result is gray_q after eight chosen edges in a row, bin_q after edge 71, and far_bin for the far_gray value held through the case, each shown zero-extended to 8 bits.
Examples
Example 1
Through the wrap, W = 4- Input
W = 4, inc = 1 at 72 of 72 edges (all), gray_q after edges 12 to 19, far_gray = 0110
- Output
gray_q_1 = 'b00001011, gray_q_2 = 'b00001001, gray_q_3 = 'b00001000, gray_q_4 = 'b00000000, gray_q_5 = 'b00000001, gray_q_6 = 'b00000011, gray_q_7 = 'b00000010, gray_q_8 = 'b00000110, bin_q_after_edge_71 = 8, far_bin = 4
inc is 1 at every edge, so bin_q is 13 after edge 12 and gray_q runs 1011, 1001, 1000, then 0000 at the wrap from 15 to 0: one bit changes at every step, the wrap included. far_gray 0110 decodes to 4.
Example 2
An enable with gaps- Input
W = 4, inc = 1 at 11 of 72 edges, gray_q after edges 0 to 7, far_gray = 1000
- Output
gray_q_1 = 'b00000001, gray_q_2 = 'b00000011, gray_q_3 = 'b00000010, gray_q_4 = 'b00000010, gray_q_5 = 'b00000010, gray_q_6 = 'b00000110, gray_q_7 = 'b00000111, gray_q_8 = 'b00000111, bin_q_after_edge_71 = 11, far_bin = 15
Where inc is 0, both registers hold, so gray_q repeats its value. Eleven steps in all leave bin_q at 11. far_gray 1000 is the Gray code of 15.
Example 3
Through the wrap, W = 6- Input
W = 6, inc = 1 at 72 of 72 edges (all), gray_q after edges 60 to 67, far_gray = 100000
- Output
gray_q_1 = 'b00100011, gray_q_2 = 'b00100001, gray_q_3 = 'b00100000, gray_q_4 = 'b00000000, gray_q_5 = 'b00000001, gray_q_6 = 'b00000011, gray_q_7 = 'b00000010, gray_q_8 = 'b00000110, bin_q_after_edge_71 = 8, far_bin = 63
bin_q is 61 after edge 60; gray_q steps 100011, 100001, 100000, then 000000 at the wrap from 63 to 0. far_gray 100000 decodes to 63: the top bit set alone is the last count, not half way.
Constraints and contract
- inc and far_gray are known 0/1 values; far_gray does not change during a case.
- Keep the module name, the parameter W and the ports.
Hints
Hint 1
Two registers move together. Compute the next count once, as a signal, and load both registers from it at the same edge.
Hint 2
gray_q must equal the code of bin_q after every edge. If you code bin_q itself, which value do you get after an edge where the count stepped?
Hint 3
The decode is a running XOR from the top bit down: a for loop where bit i is the XOR reduction of far_gray shifted right by i.
What the grader checks: Ten directed and twelve seeded inc scripts run 72 edges each on copies with W = 4 and 6, through the wrap; gray_q after eight edges in a row, bin_q at the end and the decode of one far pointer per case are compared with an independent model. A gray_q decoded from bin_q with gates instead of a register gives the same values in a zero-delay simulation: the tests cannot tell them apart, and the brief asks for the register because gates can glitch on the wires that cross. The synthesis check adds the latch count.
The submitted design must synthesize with 0 latches and no combinational loop. Counts come from the pinned open-source synthesis flow. They are proxies for logic size and depth, not physical area or timing.
22 checks on Icarus Verilog + Yosys · server. Run the examples first, then check the full regression. The suite is local and inspectable. A passing result establishes the tested cases, not a proof for all possible inputs.
See all 2 steps and the final capstone