1`timescale 1ns / 1ps 2/* 3 * This software is Copyright (c) 2016 Denis Burykin 4 * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] 5 * and it is hereby released to the general public under the following terms: 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted. 8 * 9 * 10 * Output Limit FIFO (high-speed output). 11 * 12 * Features: 13 * 14 * - Configurable width and depth 15 * - 1st word Fall-Through 16 * - Does not output on its own (reports EMPTY) when mode_limit == 1. 17 * 18 * - When reg_output_limit asserted: 19 * -- Reports amount ready for output (output_limit) in WIDTH-bit words 20 * -- Starts output of that amount, asserts output_limit_not_done 21 * -- Deasserts output_limit_not_done when finished 22 * 23 * - Does not require extra components from IP Coregen 24 * - The design is unable for asynchronous operation 25 * - Size equals to RAM size minus 1 word. 26 * 27 */ 28 29module output_limit_fifo #( 30 // ADDR_MSB==11 : 8 Kbytes 31 parameter ADDR_MSB = 11, 32 parameter WIDTH = 16 33 )( 34 input rst, 35 input CLK, 36 37 input [WIDTH-1:0] din, 38 input wr_en, 39 output full, 40 41 output [WIDTH-1:0] dout, 42 input rd_en, 43 output empty, 44 45 input mode_limit, // turn on output limit 46 input reg_output_limit, 47 output [15:0] output_limit, 48 output reg output_limit_not_done 49 ); 50 51 reg [ADDR_MSB:0] addra = 0; 52 reg [ADDR_MSB:0] output_limit_addr = 0; 53 reg [ADDR_MSB:0] output_limit_r = 0; 54 reg [ADDR_MSB:0] addrb = 0; 55 56 // 1st Word Fall-Through 57 reg wft = 0; 58 assign empty = rst || ~wft; 59 60 assign output_limit = { {15-ADDR_MSB{1'b0}}, output_limit_r }; 61 62 assign full = rst || (addra + 1'b1 == addrb); 63 wire ena = wr_en && !full; 64 65 always @(posedge CLK) begin 66 if (rst) begin 67 addra <= 0; 68 output_limit_addr <= 0; 69 output_limit_r <= 0; 70 end 71 else begin 72 if (ena) begin 73 addra <= addra + 1'b1; 74 end 75 76 if (!mode_limit || reg_output_limit) begin 77 output_limit_addr <= addra; 78 output_limit_r <= addra - output_limit_addr; 79 end 80 end // ~rst 81 end 82 83 wire ram_empty_or_limit = (output_limit_addr == addrb); 84 85 wire enb = (!ram_empty_or_limit && (empty || rd_en)); 86 reg enb_r = 0; 87 88 wire [15:0] ram_out; 89 reg [15:0] dout_r; 90 assign dout = dout_r; 91 92 always @(posedge CLK) begin 93 if (rst) begin 94 addrb <= 0; 95 wft <= 0; 96 enb_r <= 0; 97 end 98 else begin 99 if (empty || rd_en) 100 enb_r <= enb; 101 102 if (enb) begin 103 addrb <= addrb + 1'b1; 104 end 105 106 if (enb_r) begin 107 if (!wft || rd_en) begin 108 wft <= 1; 109 dout_r <= ram_out; 110 end 111 end // enb_r 112 else if (rd_en) 113 wft <= 0; 114 end // ~rst 115 116 output_limit_not_done <= ~ram_empty_or_limit; 117 end 118 119 120 (* RAM_STYLE = "BLOCK" *) 121 reg [WIDTH-1:0] ram [2**(ADDR_MSB+1)-1:0]; 122 reg [WIDTH-1:0] ram_out_r; 123 assign ram_out = ram_out_r; 124 125 always @(posedge CLK) begin 126 if (ena) 127 ram[addra] <= din; 128 if (enb) 129 ram_out_r <= ram[addrb]; 130 end 131/* 132 // IP Coregen -> Block RAM 133 // Simple Dual-Port mode 134 // Port A: write width 16 (8K = depth 4096, ADDR_MSB 11) 135 // Port B: width 16 136 // Use pins: ena, enb 137 bram_sdp16_output_fifo bram0( 138 .clka(CLK), 139 .ena(ena), 140 .wea(1'b1), 141 .addra(addra), 142 .dina(din), 143 .clkb(CLK), 144 .enb(enb), 145 .addrb(addrb), 146 .doutb(ram_out) 147 ); 148*/ 149endmodule 150