Asynchronous FIFO with Asymmetric Widths
Multi-clock systems frequently require data width conversion when passing information between domains. A common scenario is a 32-bit processor operating on a high-speed clock domain that needs to transmit data to an 8-bit peripheral (like a UART or SPI controller) operating on a slower, asynchronous clock domain.
The module is an asynchronous FIFO that accepts 32-bit writes and provides 8-bit reads. The write port operates on the wclk domain and writes entire 32-bit words into memory. The read port operates on the rclk domain and reads 8-bit bytes. The FIFO must enforce little-endian byte ordering: when a 32-bit word is read, the least significant byte (bits 7:0) is output first, followed by bits 15:8, 23:16, and finally the most significant byte (bits 31:24).
The FIFO must have a capacity of exactly 8 words (which equals 32 bytes). The wfull flag must be synchronized and evaluated in the wclk domain to prevent write overflow. The rempty flag must be synchronized and evaluated in the rclk domain to prevent read underflow. The read data rdata should asynchronously reflect the memory contents at the current read pointer; it does not require an additional register stage after the memory array.
| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | wclk | input | 1 | Write clock, positive-edge triggered | | wrst_n | input | 1 | Write reset, asynchronous active-low | | winc | input | 1 | Write enable; writes wdata on wclk posedge if not full | | wdata | input | 32 | Write data word | | wfull | output | 1 | Write full flag; 1 when FIFO cannot accept another 32-bit word | | rclk | input | 1 | Read clock, positive-edge triggered | | rrst_n | input | 1 | Read reset, asynchronous active-low | | rinc | input | 1 | Read enable; advances read pointer on rclk posedge if not empty | | rdata | output | 8 | Read data byte; combinationally reflects current read pointer | | rempty | output | 1 | Read empty flag; 1 when FIFO contains no unread bytes |
Worked Trace
Cycle 1: wrst_n=0, rrst_n=0 → wfull=0, rempty=1. Cycle 2: wrst_n=1, rrst_n=1, winc=1, wdata=32'hAABBCCDD. Cycle 3: winc=0. Write pointer advances. Cycle 4: Synchronization cycle 1. Cycle 5: Synchronization cycle 2 → rempty becomes 0, rdata combinationally outputs 8'hDD. Cycle 6: rinc=1 → rdata holds 8'hDD. Cycle 7: rinc=1 → Read pointer advances, rdata outputs 8'hCC. Cycle 8: rinc=1 → Read pointer advances, rdata outputs 8'hBB. Cycle 9: rinc=0 → Read pointer advances, rdata outputs 8'hAA. Cycle 10: rempty becomes 1.
{ "signal": [
{ "name": "wclk", "wave": "p........." },
{ "name": "wrst_n", "wave": "01........" },
{ "name": "winc", "wave": "010......." },
{ "name": "wdata", "wave": "x=x.......", "data": ["AABBCCDD"] },
{},
{ "name": "rclk", "wave": "p........." },
{ "name": "rempty", "wave": "1...0....1" },
{ "name": "rinc", "wave": "0....11110" },
{ "name": "rdata", "wave": "x...=====x", "data": ["DD", "DD", "CC", "BB", "AA"] }
], "head": { "text": "Writing one 32-bit word and reading four 8-bit bytes." } }Constraints
- The FIFO depth must be exactly 8 words (equivalent to 32 bytes).
- Byte extraction must strictly follow little-endian ordering.
- You must use standard 2-stage flip-flop synchronizers for crossing clock domains.
- Pointers must be converted to Gray code before crossing clock domains to prevent multi-bit synchronization hazards.
- The
rdataoutput must be combinationally driven based on the current read pointer (First-Word Fall-Through style for the data bus). wfullmust assert when there is no space for a complete 32-bit word.
Topics
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.
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.