// // dcpktfifo.sv // // Dual-clock RAM-based FIFO with transaction support (commit/abort) // // Parametric synchronous RAM module, dual clock, // one read and one write port; output data not // registered module dcqram #( parameter wbits, // log2(size in words) parameter width = 8 ) ( input wclk, input wstb, input [wbits-1:0] waddr, input [width-1:0] wdata, input rclk, input [wbits-1:0] raddr, output [width-1:0] rdata ); `ifdef ALTERA_RESERVED_QIS (* ramstyle = "no_rw_check" *) `endif reg [width-1:0] mem[0:(1 << wbits)-1]; always @(posedge wclk) if (wstb) mem[waddr] <= wdata; reg [wbits-1:0] raddr_q; assign rdata = mem[raddr_q]; always @(posedge rclk) raddr_q <= raddr; endmodule // dcqram module dcpktfifo #( parameter wbits = 10, parameter width = 8, parameter [0:0] wtrans = 1'b1, // Support transactions on write side parameter [0:0] rtrans = 1'b1 // Support transactions on read side ) ( input rst_n, input wclk, input wstb, input wcommit, input wabort, input [width-1:0] wdata, output reg [wbits-1:0] wnfree, output reg wempty, output reg wfull, input rclk, input rstb, input rcommit, input rabort, output [width-1:0] rdata, output reg [wbits-1:0] rnavail, output reg rempty, output reg rlast, output reg remptyh, // Cleared only on abort/commit output reg rlasth, // Cleared only on abort/commit output reg rfull ); reg [wbits-1:0] wtaddr; // Transient write address reg [wbits-1:0] wcaddr; // Committed write address wire [wbits-1:0] w_rcaddr; // rcaddr latched in the wclk domain wire wcommit_w = wtrans ? wcommit : 1'b1; wire wabort_w = wtrans ? wabort : 1'b0; wire [wbits-1:0] wcaddr_w = wtrans ? wcaddr : wtaddr; wire wstb_w = wstb & ~wfull; wire [wbits-1:0] wnused = wtaddr + wstb_w - w_rcaddr; always @(negedge rst_n or posedge wclk) if (~rst_n) begin wtaddr <= 'b0; wcaddr <= 'b0; wempty <= 1'b1; wfull <= 1'b0; end else begin if (wabort_w) wtaddr <= wcaddr_w; else begin wtaddr <= wtaddr + wstb_w; if (wcommit_w) wcaddr <= wtaddr + wstb_w; end wnfree <= ~wnused; wempty <= ~|wnused; wfull <= &wnused; end // else: !if(~rst_n) reg [wbits-1:0] rtaddr; // Transient read address reg [wbits-1:0] rcaddr; // Committed read address wire [wbits-1:0] r_wcaddr; // wcaddr latched in the rclk domain wire rcommit_w = rtrans ? rcommit : 1'b1; wire rabort_w = rtrans ? rabort : 1'b0; wire [wbits-1:0] rcaddr_w = rtrans ? rcaddr : rtaddr; wire rstb_w = rstb & ~rempty; wire [wbits-1:0] rtaddr_next = (rabort_w & ~rcommit_w) ? rcaddr : rtaddr + rstb_w; wire [wbits-1:0] rnused_w = r_wcaddr - rtaddr_next; always @(negedge rst_n or posedge rclk) if (~rst_n) begin rtaddr <= 'b0; rcaddr <= 'b0; rnavail <= 'b0; rempty <= 1'b1; rlast <= 1'b1; rfull <= 1'b0; end else begin rtaddr <= rtaddr_next; if (rcommit_w) rcaddr <= rtaddr_next; rnavail <= rnused_w; rempty <= ~|rnused_w; remptyh <= ~|rnused_w | (remptyh & ~(rcommit_w|rabort_w)); rlast <= ~|rnused_w[wbits-1:1]; rlasth <= ~|rnused_w[wbits-1:1] | (rlasth & ~(rcommit_w|rabort_w)); rfull <= &rnused_w; end // else: !if(~rst_n) // Address pointer synchronizers. synchronizer #(.width(wbits)) syncrcaddr ( .rst_n (rst_n), .clk (wclk), .d (rcaddr_w), .q (w_rcaddr) ); synchronizer #(.width(wbits)) syncwcaddr ( .rst_n (rst_n), .clk (rclk), .d (wcaddr_w), .q (r_wcaddr) ); // // Memory array // dcqram #(.wbits(wbits), .width(width)) ram ( .wclk (wclk), .wstb (wstb), .waddr (wtaddr), .wdata (wdata), .rclk (rclk), .raddr (rtaddr_next), .rdata (rdata) ); // For debugging (* preserve, noprune *) reg wflag; always @(posedge wclk) wflag <= (wflag | wstb_w) & ~(wcommit|wabort); (* preserve, noprune *) reg rflag; always @(posedge rclk) rflag <= (rflag | rstb) & ~(rcommit|rabort); endmodule // dcpktfifo