// Copyright 2020-2022 F4PGA Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 `default_nettype wire module fifo_ctl ( raddr, waddr, fflags, ren_o, sync, rmode, wmode, rclk, rst_R_n, wclk, rst_W_n, ren, wen, upaf, upae ); parameter ADDR_WIDTH = 11; parameter FIFO_WIDTH = 3'd2; parameter DEPTH = 6; output wire [ADDR_WIDTH - 1:0] raddr; output wire [ADDR_WIDTH - 1:0] waddr; output wire [7:0] fflags; output wire ren_o; input wire sync; input wire [1:0] rmode; input wire [1:0] wmode; (* clkbuf_sink *) input wire rclk; input wire rst_R_n; (* clkbuf_sink *) input wire wclk; input wire rst_W_n; input wire ren; input wire wen; input wire [ADDR_WIDTH - 1:0] upaf; input wire [ADDR_WIDTH - 1:0] upae; localparam ADDR_PLUS_ONE = ADDR_WIDTH + 1; reg [ADDR_WIDTH:0] pushtopop1; reg [ADDR_WIDTH:0] pushtopop2; reg [ADDR_WIDTH:0] poptopush1; reg [ADDR_WIDTH:0] poptopush2; wire [ADDR_WIDTH:0] pushtopop0; wire [ADDR_WIDTH:0] poptopush0; wire [ADDR_WIDTH:0] smux_poptopush; wire [ADDR_WIDTH:0] smux_pushtopop; assign smux_poptopush = (sync ? poptopush0 : poptopush2); assign smux_pushtopop = (sync ? pushtopop0 : pushtopop2); always @(posedge rclk or negedge rst_R_n) if (~rst_R_n) begin pushtopop1 <= 'h0; pushtopop2 <= 'h0; end else begin pushtopop1 = pushtopop0; pushtopop2 = pushtopop1; end always @(posedge wclk or negedge rst_W_n) if (~rst_W_n) begin poptopush1 <= 'h0; poptopush2 <= 'h0; end else begin poptopush1 <= poptopush0; poptopush2 <= poptopush1; end fifo_push #( .ADDR_WIDTH(ADDR_WIDTH), .DEPTH(DEPTH) ) u_fifo_push( .wclk(wclk), .wen(wen), .rst_n(rst_W_n), .rmode(rmode), .wmode(wmode), .gcout(pushtopop0), .gcin(smux_poptopush), .ff_waddr(waddr), .pushflags(fflags[7:4]), .upaf(upaf) ); fifo_pop #( .ADDR_WIDTH(ADDR_WIDTH), .FIFO_WIDTH(FIFO_WIDTH), .DEPTH(DEPTH) ) u_fifo_pop( .rclk(rclk), .ren_in(ren), .rst_n(rst_R_n), .rmode(rmode), .wmode(wmode), .ren_o(ren_o), .gcout(poptopush0), .gcin(smux_pushtopop), .out_raddr(raddr), .popflags(fflags[3:0]), .upae(upae) ); endmodule module fifo_push ( pushflags, gcout, ff_waddr, rst_n, wclk, wen, rmode, wmode, gcin, upaf ); parameter ADDR_WIDTH = 11; parameter DEPTH = 6; output wire [3:0] pushflags; output wire [ADDR_WIDTH:0] gcout; output wire [ADDR_WIDTH - 1:0] ff_waddr; input rst_n; (* clkbuf_sink *) input wclk; input wen; input [1:0] rmode; input [1:0] wmode; input [ADDR_WIDTH:0] gcin; input [ADDR_WIDTH - 1:0] upaf; localparam ADDR_PLUS_ONE = ADDR_WIDTH + 1; reg full_next; reg full; reg paf_next; reg paf; reg fmo; reg fmo_next; reg overflow; reg p1; reg p2; reg f1; reg f2; reg q1; reg q2; reg [1:0] gmode; reg [ADDR_WIDTH:0] waddr; reg [ADDR_WIDTH:0] raddr; reg [ADDR_WIDTH:0] gcout_reg; reg [ADDR_WIDTH:0] gcout_next; reg [ADDR_WIDTH:0] raddr_next; reg [ADDR_WIDTH - 1:0] paf_thresh; wire overflow_next; wire [ADDR_WIDTH:0] waddr_next; wire [ADDR_WIDTH:0] gc8out_next; wire [ADDR_WIDTH - 1:0] gc16out_next; wire [ADDR_WIDTH - 2:0] gc32out_next; wire [ADDR_WIDTH:0] tmp; wire [ADDR_WIDTH:0] next_count; wire [ADDR_WIDTH:0] count; wire [ADDR_WIDTH:0] fbytes; genvar i; assign next_count = fbytes - (waddr_next >= raddr_next ? waddr_next - raddr_next : (~raddr_next + waddr_next) + 1); assign count = fbytes - (waddr >= raddr ? waddr - raddr : (~raddr + waddr) + 1); assign fbytes = 1 << (DEPTH + 5); always @(*) begin paf_thresh = wmode[1] ? upaf : (wmode[0] ? upaf << 1 : upaf << 2); end always @(*) case (wmode) 2'h0, 2'h1, 2'h2: begin full_next = (wen ? f1 : f2); fmo_next = (wen ? p1 : p2); paf_next = (wen ? q1 : q2); end default: begin full_next = 1'b0; fmo_next = 1'b0; paf_next = 1'b0; end endcase always @(*) begin : PUSH_FULL_FLAGS f1 = 1'b0; f2 = 1'b0; p1 = 1'b0; p2 = 1'b0; q1 = next_count < {1'b0, paf_thresh}; q2 = count < {1'b0, paf_thresh}; case (wmode) 2'h0: case (DEPTH) 3'h6: begin f1 = {~waddr_next[11], waddr_next[10:2]} == raddr_next[11:2]; f2 = {~waddr[11], waddr[10:2]} == raddr_next[11:2]; p1 = ((waddr_next[10:2] + 1) & 9'h1ff) == raddr_next[10:2]; p2 = ((waddr[10:2] + 1) & 9'h1ff) == raddr_next[10:2]; end 3'h5: begin f1 = {~waddr_next[10], waddr_next[9:2]} == raddr_next[10:2]; f2 = {~waddr[10], waddr[9:2]} == raddr_next[10:2]; p1 = ((waddr_next[9:2] + 1) & 8'hff) == raddr_next[9:2]; p2 = ((waddr[9:2] + 1) & 8'hff) == raddr_next[9:2]; end 3'h4: begin f1 = {~waddr_next[9], waddr_next[8:2]} == raddr_next[9:2]; f2 = {~waddr[9], waddr[8:2]} == raddr_next[9:2]; p1 = ((waddr_next[8:2] + 1) & 7'h7f) == raddr_next[8:2]; p2 = ((waddr[8:2] + 1) & 7'h7f) == raddr_next[8:2]; end 3'h3: begin f1 = {~waddr_next[8], waddr_next[7:2]} == raddr_next[8:2]; f2 = {~waddr[8], waddr[7:2]} == raddr_next[8:2]; p1 = ((waddr_next[7:2] + 1) & 6'h3f) == raddr_next[7:2]; p2 = ((waddr[7:2] + 1) & 6'h3f) == raddr_next[7:2]; end 3'h2: begin f1 = {~waddr_next[7], waddr_next[6:2]} == raddr_next[7:2]; f2 = {~waddr[7], waddr[6:2]} == raddr_next[7:2]; p1 = ((waddr_next[6:2] + 1) & 5'h1f) == raddr_next[6:2]; p2 = ((waddr[6:2] + 1) & 5'h1f) == raddr_next[6:2]; end 3'h1: begin f1 = {~waddr_next[6], waddr_next[5:2]} == raddr_next[6:2]; f2 = {~waddr[6], waddr[5:2]} == raddr_next[6:2]; p1 = ((waddr_next[5:2] + 1) & 4'hf) == raddr_next[5:2]; p2 = ((waddr[5:2] + 1) & 4'hf) == raddr_next[5:2]; end 3'h0: begin f1 = {~waddr_next[5], waddr_next[4:2]} == raddr_next[5:2]; f2 = {~waddr[5], waddr[4:2]} == raddr_next[5:2]; p1 = ((waddr_next[4:2] + 1) & 3'h7) == raddr_next[4:2]; p2 = ((waddr[4:2] + 1) & 3'h7) == raddr_next[4:2]; end 3'h7: begin f1 = {~waddr_next[ADDR_WIDTH], waddr_next[ADDR_WIDTH - 1:2]} == raddr_next[ADDR_WIDTH:2]; f2 = {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH - 1:2]} == raddr_next[ADDR_WIDTH:2]; p1 = ((waddr_next[ADDR_WIDTH - 1:2] + 1) & {ADDR_WIDTH - 2 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:2]; p2 = ((waddr[ADDR_WIDTH - 1:2] + 1) & {ADDR_WIDTH - 2 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:2]; end endcase 2'h1: case (DEPTH) 3'h6: begin f1 = {~waddr_next[11], waddr_next[10:1]} == raddr_next[11:1]; f2 = {~waddr[11], waddr[10:1]} == raddr_next[11:1]; p1 = ((waddr_next[10:1] + 1) & 10'h3ff) == raddr_next[10:1]; p2 = ((waddr[10:1] + 1) & 10'h3ff) == raddr_next[10:1]; end 3'h5: begin f1 = {~waddr_next[10], waddr_next[9:1]} == raddr_next[10:1]; f2 = {~waddr[10], waddr[9:1]} == raddr_next[10:1]; p1 = ((waddr_next[9:1] + 1) & 9'h1ff) == raddr_next[9:1]; p2 = ((waddr[9:1] + 1) & 9'h1ff) == raddr_next[9:1]; end 3'h4: begin f1 = {~waddr_next[9], waddr_next[8:1]} == raddr_next[9:1]; f2 = {~waddr[9], waddr[8:1]} == raddr_next[9:1]; p1 = ((waddr_next[8:1] + 1) & 8'hff) == raddr_next[8:1]; p2 = ((waddr[8:1] + 1) & 8'hff) == raddr_next[8:1]; end 3'h3: begin f1 = {~waddr_next[8], waddr_next[7:1]} == raddr_next[8:1]; f2 = {~waddr[8], waddr[7:1]} == raddr_next[8:1]; p1 = ((waddr_next[7:1] + 1) & 7'h7f) == raddr_next[7:1]; p2 = ((waddr[7:1] + 1) & 7'h7f) == raddr_next[7:1]; end 3'h2: begin f1 = {~waddr_next[7], waddr_next[6:1]} == raddr_next[7:1]; f2 = {~waddr[7], waddr[6:1]} == raddr_next[7:1]; p1 = ((waddr_next[6:1] + 1) & 6'h3f) == raddr_next[6:1]; p2 = ((waddr[6:1] + 1) & 6'h3f) == raddr_next[6:1]; end 3'h1: begin f1 = {~waddr_next[6], waddr_next[5:1]} == raddr_next[6:1]; f2 = {~waddr[6], waddr[5:1]} == raddr_next[6:1]; p1 = ((waddr_next[5:1] + 1) & 5'h1f) == raddr_next[5:1]; p2 = ((waddr[5:1] + 1) & 5'h1f) == raddr_next[5:1]; end 3'h0: begin f1 = {~waddr_next[5], waddr_next[4:1]} == raddr_next[5:1]; f2 = {~waddr[5], waddr[4:1]} == raddr_next[5:1]; p1 = ((waddr_next[4:1] + 1) & 4'hf) == raddr_next[4:1]; p2 = ((waddr[4:1] + 1) & 4'hf) == raddr_next[4:1]; end 3'h7: begin f1 = {~waddr_next[ADDR_WIDTH], waddr_next[ADDR_WIDTH - 1:1]} == raddr_next[ADDR_WIDTH:1]; f2 = {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH - 1:1]} == raddr_next[ADDR_WIDTH:1]; p1 = ((waddr_next[ADDR_WIDTH - 1:1] + 1) & {ADDR_WIDTH - 1 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:1]; p2 = ((waddr[ADDR_WIDTH - 1:1] + 1) & {ADDR_WIDTH - 1 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:1]; end endcase 2'h2: case (DEPTH) 3'h6: begin f1 = {~waddr_next[11], waddr_next[10:0]} == raddr_next[11:0]; f2 = {~waddr[11], waddr[10:0]} == raddr_next[11:0]; p1 = ((waddr_next[10:0] + 1) & 11'h7ff) == raddr_next[10:0]; p2 = ((waddr[10:0] + 1) & 11'h7ff) == raddr_next[10:0]; end 3'h5: begin f1 = {~waddr_next[10], waddr_next[9:0]} == raddr_next[10:0]; f2 = {~waddr[10], waddr[9:0]} == raddr_next[10:0]; p1 = ((waddr_next[9:0] + 1) & 10'h3ff) == raddr_next[9:0]; p2 = ((waddr[9:0] + 1) & 10'h3ff) == raddr_next[9:0]; end 3'h4: begin f1 = {~waddr_next[9], waddr_next[8:0]} == raddr_next[9:0]; f2 = {~waddr[9], waddr[8:0]} == raddr_next[9:0]; p1 = ((waddr_next[8:0] + 1) & 9'h1ff) == raddr_next[8:0]; p2 = ((waddr[8:0] + 1) & 9'h1ff) == raddr_next[8:0]; end 3'h3: begin f1 = {~waddr_next[8], waddr_next[7:0]} == raddr_next[8:0]; f2 = {~waddr[8], waddr[7:0]} == raddr_next[8:0]; p1 = ((waddr_next[7:0] + 1) & 8'hff) == raddr_next[7:0]; p2 = ((waddr[7:0] + 1) & 8'hff) == raddr_next[7:0]; end 3'h2: begin f1 = {~waddr_next[7], waddr_next[6:0]} == raddr_next[7:0]; f2 = {~waddr[7], waddr[6:0]} == raddr_next[7:0]; p1 = ((waddr_next[6:0] + 1) & 7'h7f) == raddr_next[6:0]; p2 = ((waddr[6:0] + 1) & 7'h7f) == raddr_next[6:0]; end 3'h1: begin f1 = {~waddr_next[6], waddr_next[5:0]} == raddr_next[6:0]; f2 = {~waddr[6], waddr[5:0]} == raddr_next[6:0]; p1 = ((waddr_next[5:0] + 1) & 6'h3f) == raddr_next[5:0]; p2 = ((waddr[5:0] + 1) & 6'h3f) == raddr_next[5:0]; end 3'h0: begin f1 = {~waddr_next[5], waddr_next[4:0]} == raddr_next[5:0]; f2 = {~waddr[5], waddr[4:0]} == raddr_next[5:0]; p1 = ((waddr_next[4:0] + 1) & 5'h1f) == raddr_next[4:0]; p2 = ((waddr[4:0] + 1) & 5'h1f) == raddr_next[4:0]; end 3'h7: begin f1 = {~waddr_next[ADDR_WIDTH], waddr_next[ADDR_WIDTH - 1:0]} == raddr_next[ADDR_WIDTH:0]; f2 = {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH - 1:0]} == raddr_next[ADDR_WIDTH:0]; p1 = ((waddr_next[ADDR_WIDTH - 1:0] + 1) & {ADDR_WIDTH {1'b1}}) == raddr_next[ADDR_WIDTH - 1:0]; p2 = ((waddr[ADDR_WIDTH - 1:0] + 1) & {ADDR_WIDTH {1'b1}}) == raddr_next[ADDR_WIDTH - 1:0]; end endcase 2'h3: begin f1 = 1'b0; f2 = 1'b0; p1 = 1'b0; p2 = 1'b0; end endcase end always @(*) case (wmode) 2'h0: gmode = 2'h0; 2'h1: gmode = (rmode == 2'h0 ? 2'h0 : 2'h1); 2'h2: gmode = (rmode == 2'h2 ? 2'h2 : rmode); 2'h3: gmode = 2'h3; endcase assign gc8out_next = (waddr_next >> 1) ^ waddr_next; assign gc16out_next = (waddr_next >> 2) ^ (waddr_next >> 1); assign gc32out_next = (waddr_next >> 3) ^ (waddr_next >> 2); always @(*) if (wen) case (gmode) 2'h2: gcout_next = gc8out_next; 2'h1: gcout_next = {1'b0, gc16out_next}; 2'h0: gcout_next = {2'b00, gc32out_next}; default: gcout_next = {ADDR_PLUS_ONE {1'b0}}; endcase else gcout_next = {ADDR_PLUS_ONE {1'b0}}; always @(posedge wclk or negedge rst_n) if (~rst_n) begin full <= 1'b0; fmo <= 1'b0; paf <= 1'b0; raddr <= {ADDR_PLUS_ONE {1'b0}}; end else begin full <= full_next; fmo <= fmo_next; paf <= paf_next; case (gmode) 0: raddr <= raddr_next & {{ADDR_WIDTH - 1 {1'b1}}, 2'b00}; 1: raddr <= raddr_next & {{ADDR_WIDTH {1'b1}}, 1'b0}; 2: raddr <= raddr_next & {ADDR_WIDTH + 1 {1'b1}}; 3: raddr <= 12'h000; endcase end assign overflow_next = full & wen; always @(posedge wclk or negedge rst_n) if (~rst_n) overflow <= 1'b0; else if (wen == 1'b1) overflow <= overflow_next; always @(posedge wclk or negedge rst_n) if (~rst_n) begin waddr <= {ADDR_WIDTH + 1 {1'b0}}; gcout_reg <= {ADDR_WIDTH + 1 {1'b0}}; end else if (wen == 1'b1) begin waddr <= waddr_next; gcout_reg <= gcout_next; end assign gcout = gcout_reg; generate for (i = 0; i < (ADDR_WIDTH + 1); i = i + 1) begin : genblk1 assign tmp[i] = ^(gcin >> i); end endgenerate always @(*) case (gmode) 2'h0: raddr_next = {tmp[ADDR_WIDTH - 2:0], 2'b00} & {{ADDR_WIDTH - 1 {1'b1}}, 2'b00}; 2'h1: raddr_next = {tmp[ADDR_WIDTH - 1:0], 1'b0} & {{ADDR_WIDTH {1'b1}}, 1'b0}; 2'h2: raddr_next = {tmp[ADDR_WIDTH:0]} & {ADDR_WIDTH + 1 {1'b1}}; default: raddr_next = {ADDR_WIDTH + 1 {1'b0}}; endcase assign ff_waddr = waddr[ADDR_WIDTH - 1:0]; assign pushflags = {full, fmo, paf, overflow}; assign waddr_next = waddr + (wmode == 2'h0 ? 'h4 : (wmode == 2'h1 ? 'h2 : 'h1)); endmodule module fifo_pop ( ren_o, popflags, out_raddr, gcout, rst_n, rclk, ren_in, rmode, wmode, gcin, upae ); parameter ADDR_WIDTH = 11; parameter FIFO_WIDTH = 3'd2; parameter DEPTH = 6; output wire ren_o; output wire [3:0] popflags; output reg [ADDR_WIDTH - 1:0] out_raddr; output wire [ADDR_WIDTH:0] gcout; input rst_n; (* clkbuf_sink *) input rclk; input ren_in; input [1:0] rmode; input [1:0] wmode; input [ADDR_WIDTH:0] gcin; input [ADDR_WIDTH - 1:0] upae; localparam ADDR_PLUS_ONE = ADDR_WIDTH + 1; reg empty; reg epo; reg pae; reg underflow; reg e1; reg e2; reg o1; reg o2; reg q1; reg q2; reg [1:0] bwl_sel; reg [1:0] gmode; reg [ADDR_WIDTH - 1:0] ff_raddr; reg [ADDR_WIDTH:0] waddr; reg [ADDR_WIDTH:0] raddr; reg [ADDR_WIDTH:0] gcout_reg; reg [ADDR_WIDTH:0] gcout_next; reg [ADDR_WIDTH:0] waddr_next; reg [ADDR_WIDTH - 1:0] pae_thresh; wire ren_out; wire empty_next; wire pae_next; wire epo_next; wire [ADDR_WIDTH - 2:0] gc32out_next; wire [ADDR_WIDTH - 1:0] gc16out_next; wire [ADDR_WIDTH:0] gc8out_next; wire [ADDR_WIDTH:0] raddr_next; wire [ADDR_WIDTH - 1:0] ff_raddr_next; wire [ADDR_WIDTH:0] tmp; wire [ADDR_PLUS_ONE:0] next_count; wire [ADDR_PLUS_ONE:0] count; wire [ADDR_PLUS_ONE:0] fbytes; genvar i; assign next_count = waddr - raddr_next; assign count = waddr - raddr; assign fbytes = 1 << (DEPTH + 5); always @(*) pae_thresh = rmode[1] ? upae : (rmode[0] ? upae << 1 : upae << 2); assign ren_out = (empty ? 1'b1 : ren_in); always @(*) case (rmode) 2'h0: gmode = 2'h0; 2'h1: gmode = (wmode == 2'h0 ? 2'h0 : 2'h1); 2'h2: gmode = (wmode == 2'h2 ? 2'h2 : wmode); 2'h3: gmode = 2'h3; endcase always @(*) begin e1 = 1'b0; e2 = 1'b0; o1 = 1'b0; o2 = 1'b0; q1 = next_count < {1'b0, pae_thresh}; q2 = count < {1'b0, pae_thresh}; case (rmode) 2'h0: begin e1 = raddr_next[ADDR_WIDTH:2] == waddr_next[ADDR_WIDTH:2]; e2 = raddr[ADDR_WIDTH:2] == waddr_next[ADDR_WIDTH:2]; o1 = (raddr_next[ADDR_WIDTH:2] + 1) == waddr_next[ADDR_WIDTH:2]; o2 = (raddr[ADDR_WIDTH:2] + 1) == waddr_next[ADDR_WIDTH:2]; end 2'h1: begin e1 = raddr_next[ADDR_WIDTH:1] == waddr_next[ADDR_WIDTH:1]; e2 = raddr[ADDR_WIDTH:1] == waddr_next[ADDR_WIDTH:1]; o1 = (raddr_next[ADDR_WIDTH:1] + 1) == waddr_next[ADDR_WIDTH:1]; o2 = (raddr[ADDR_WIDTH:1] + 1) == waddr_next[ADDR_WIDTH:1]; end 2'h2: begin e1 = raddr_next[ADDR_WIDTH:0] == waddr_next[ADDR_WIDTH:0]; e2 = raddr[ADDR_WIDTH:0] == waddr_next[ADDR_WIDTH:0]; o1 = (raddr_next[ADDR_WIDTH:0] + 1) == waddr_next[ADDR_WIDTH:0]; o2 = (raddr[ADDR_WIDTH:0] + 1) == waddr_next[11:0]; end 2'h3: begin e1 = 1'b0; e2 = 1'b0; o1 = 1'b0; o2 = 1'b0; end endcase end assign empty_next = (ren_in & !empty ? e1 : e2); assign epo_next = (ren_in & !empty ? o1 : o2); assign pae_next = (ren_in & !empty ? q1 : q2); always @(posedge rclk or negedge rst_n) if (~rst_n) begin empty <= 1'b1; pae <= 1'b1; epo <= 1'b0; end else begin empty <= empty_next; pae <= pae_next; epo <= epo_next; end assign gc8out_next = (raddr_next >> 1) ^ raddr_next; assign gc16out_next = (raddr_next >> 2) ^ (raddr_next >> 1); assign gc32out_next = (raddr_next >> 3) ^ (raddr_next >> 2); always @(*) if (ren_in) case (gmode) 2'h2: gcout_next = gc8out_next; 2'h1: gcout_next = {1'b0, gc16out_next}; 2'h0: gcout_next = {2'b00, gc32out_next}; default: gcout_next = 'h0; endcase else gcout_next = 'h0; always @(posedge rclk or negedge rst_n) if (~rst_n) waddr <= 12'h000; else waddr <= waddr_next; always @(posedge rclk or negedge rst_n) if (~rst_n) begin underflow <= 1'b0; bwl_sel <= 2'h0; gcout_reg <= 12'h000; end else if (ren_in) begin underflow <= empty; if (!empty) begin bwl_sel <= raddr_next[1:0]; gcout_reg <= gcout_next; end end generate for (i = 0; i < (ADDR_WIDTH + 1); i = i + 1) begin : genblk1 assign tmp[i] = ^(gcin >> i); end endgenerate always @(*) case (gmode) 2'h0: waddr_next = {tmp[ADDR_WIDTH - 2:0], 2'b00} & {{ADDR_WIDTH - 1 {1'b1}}, 2'b00}; 2'h1: waddr_next = {tmp[ADDR_WIDTH - 1:0], 1'b0} & {{ADDR_WIDTH {1'b1}}, 1'b0}; 2'h2: waddr_next = {tmp[ADDR_WIDTH:0]} & {ADDR_PLUS_ONE {1'b1}}; default: waddr_next = {ADDR_PLUS_ONE {1'b0}}; endcase assign ff_raddr_next = ff_raddr + (rmode == 2'h0 ? 'h4 : (rmode == 2'h1 ? 'h2 : 'h1)); assign raddr_next = raddr + (rmode == 2'h0 ? 'h4 : (rmode == 2'h1 ? 'h2 : 'h1)); always @(posedge rclk or negedge rst_n) if (~rst_n) ff_raddr <= 1'sb0; else if (empty & ~empty_next) ff_raddr <= raddr_next[ADDR_WIDTH - 1:0]; else if ((ren_in & !empty) & ~empty_next) ff_raddr <= ff_raddr_next; always @(posedge rclk or negedge rst_n) if (~rst_n) raddr <= 12'h000; else if (ren_in & !empty) raddr <= raddr_next; always @(*) case (FIFO_WIDTH) 3'h2: out_raddr = {ff_raddr[ADDR_WIDTH - 1:1], bwl_sel[0]}; 3'h4: out_raddr = {ff_raddr[ADDR_WIDTH - 1:2], bwl_sel}; default: out_raddr = ff_raddr[ADDR_WIDTH - 1:0]; endcase assign ren_o = ren_out; assign gcout = gcout_reg; assign popflags = {empty, epo, pae, underflow}; endmodule `default_nettype none