gateware

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit ef96b8504ef3ab3e48cc7edbc4d8b94edc4fa825
parent 50dbc5c91d1662050253fd27377e6a74106d6c43
Author: Brian Swetland <swetland@frotz.net>
Date:   Sun, 26 Jan 2020 04:35:57 -0800

async_fifo_one_deep: initial version (untested)

Diffstat:
Ahdl/async_fifo_one_deep.sv | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+), 0 deletions(-)

diff --git a/hdl/async_fifo_one_deep.sv b/hdl/async_fifo_one_deep.sv @@ -0,0 +1,74 @@ +// Copyright 2020, Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0. + +`default_nettype none + +// Based on the design described in +// "5.8.2 Multi-bit CDC signal passing using 1-deep / 2-register FIFO synchronizer" +// Clock Domain Crossing (CDC) Design & Verification Techniques +// http://www.sunburst-design.com/papers/CummingsSNUG2008Boston_CDC.pdf + +module async_fifo_one_deep #( + parameter WIDTH = 16 + )( + input wire wr_clk, + input wire wr_valid, + input wire [WIDTH-1:0]wr_data, + output wire wr_ready, + input wire rd_clk, + input wire rd_ready, + output wire rd_valid, + output wire [WIDTH-1:0]rd_data +); + +// 2 register deep fifo storage +reg [WIDTH-1:0]fifo_reg_0 = 0; +reg [WIDTH-1:0]fifo_reg_1 = 0; + +// wr domain registers +reg wr_ptr = 0; +reg wr_rd_ptr = 0; +reg wr_rd_ptr_sync = 0; + +// writable (empty) when read and write pointers are the same +assign wr_ready = ~(wr_rd_ptr ^ wr_ptr); + +always_ff @(posedge wr_clk) begin + // sync rd_ptr into wr_ domain + wr_rd_ptr_sync <= rd_ptr; + wr_rd_ptr <= wr_rd_ptr_sync; + + // wr_ptr state machine + wr_ptr <= (wr_valid & wr_ready) ^ wr_ptr; + + // fifo registers write control + if (wr_valid & wr_ready) begin + if (wr_ptr) begin + fifo_reg_1 <= wr_data; + end else begin + fifo_reg_0 <= wr_data; + end + end +end + +// fifo registers read control +assign rd_data = rd_ptr ? fifo_reg_1 : fifo_reg_0; + +// rd domain registers +reg rd_ptr = 0; +reg rd_wr_ptr = 0; +reg rd_wr_ptr_sync = 0; + +// readable (full) when read and write pointers are different +assign rd_ready = (rd_wr_ptr ^ rd_ptr); + +always_ff @(posedge rd_clk) begin + // sync wr_ptr into rd_ domain + rd_wr_ptr_sync <= wr_ptr; + rd_wr_ptr <= rd_wr_ptr_sync; + + // rd_ptr state machine + rd_ptr <= (rd_valid & rd_ready) ^ rd_ptr; +end + +endmodule