| // 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 |