Asynchronous FIFO Memory Array
Clock domain crossing relies on asynchronous FIFOs to safely transfer data between independent clock domains. The core of this FIFO is a dual-port memory array. Unlike the read and write pointers which require careful Gray code synchronization, the memory array itself uses no synchronizers. It relies entirely on the external pointer logic to ensure that the read and write ports never access the same memory location simultaneously.
The module acts as a simple dual-port RAM with independent clocks. The write port operates exclusively in the write clock domain, storing data into the memory array when enabled. The read port operates exclusively in the read clock domain, fetching data from the memory array into an output register when enabled.
Timing and reset behaviour must strictly follow these rules: • Write clock edge: posedge wclk • Read clock edge: posedge rclk • Reset: rst_n is an asynchronous active-low reset applied only to the read domain. • On reset, the output register r_data must go to 0. The internal memory array contents remain uninitialized and are completely unaffected by reset. • Write behaviour: Writes occur on posedge wclk when w_en is 1. • Read behaviour: Reads occur on posedge rclk when r_en is 1. The data at r_addr is registered into r_data. If r_en is 0, r_data holds its previous value.
Worked Trace: Event 1: rst_n=0 asserted → r_data=8'h00 Event 2: posedge wclk (w_en=1, w_addr=4'h5, w_data=8'hFF) → mem[5]=8'hFF Event 3: posedge rclk (rst_n=1, r_en=1, r_addr=4'h5) → r_data=8'hFF Event 4: posedge rclk (r_en=0, r_addr=4'h0) → r_data=8'hFF (hold)
{ "signal": [
{ "name": "wclk", "wave": "p......." },
{ "name": "w_en", "wave": "010....." },
{ "name": "w_addr", "wave": "x=x.....", "data": ["5"] },
{ "name": "w_data", "wave": "x=x.....", "data": ["FF"] },
{},
{ "name": "rclk", "wave": "p......." },
{ "name": "rst_n", "wave": "01......" },
{ "name": "r_en", "wave": "0.10...." },
{ "name": "r_addr", "wave": "x.=x....", "data": ["5"] },
{ "name": "r_data", "wave": "=.=.....", "data": ["00", "FF"] }
], "head": { "text": "Independent write and read operations across two clock domains." } }| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | wclk | input | 1 | Write domain clock; positive-edge triggered | | w_en | input | 1 | Write enable; active-high | | w_addr | input | ADDR_WIDTH | Write address | | w_data | input | DATA_WIDTH | Write data | | rclk | input | 1 | Read domain clock; positive-edge triggered | | rst_n | input | 1 | Asynchronous active-low reset for the read data register | | r_en | input | 1 | Read enable; active-high | | r_addr | input | ADDR_WIDTH | Read address | | r_data | output | DATA_WIDTH | Registered read data; resets to 0 |
Constraints
- The module must be parameterized with
DATA_WIDTH(default 8) andADDR_WIDTH(default 4). - The internal memory array must be sized to hold $2^{ADDR\_WIDTH}$ elements of
DATA_WIDTHbits. - Output
r_datamust be registered on the positive edge ofrclk. - Output
r_datamust reset to 0 asynchronously whenrst_nis 0. - The internal memory array must not be reset.
- Write operations must occur on the positive edge of
wclk.
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.