| // 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 TDP18K_FIFO ( |
| RMODE_A_i, |
| RMODE_B_i, |
| WMODE_A_i, |
| WMODE_B_i, |
| WEN_A_i, |
| WEN_B_i, |
| REN_A_i, |
| REN_B_i, |
| CLK_A_i, |
| CLK_B_i, |
| BE_A_i, |
| BE_B_i, |
| ADDR_A_i, |
| ADDR_B_i, |
| WDATA_A_i, |
| WDATA_B_i, |
| RDATA_A_o, |
| RDATA_B_o, |
| EMPTY_o, |
| EPO_o, |
| EWM_o, |
| UNDERRUN_o, |
| FULL_o, |
| FMO_o, |
| FWM_o, |
| OVERRUN_o, |
| FLUSH_ni, |
| FMODE_i, |
| ); |
| parameter SYNC_FIFO_i = 1'b0; |
| parameter POWERDN_i = 1'b0; |
| parameter SLEEP_i = 1'b0; |
| parameter PROTECT_i = 1'b0; |
| parameter UPAF_i = 11'b0; |
| parameter UPAE_i = 11'b0; |
| |
| input wire [2:0] RMODE_A_i; |
| input wire [2:0] RMODE_B_i; |
| input wire [2:0] WMODE_A_i; |
| input wire [2:0] WMODE_B_i; |
| input wire WEN_A_i; |
| input wire WEN_B_i; |
| input wire REN_A_i; |
| input wire REN_B_i; |
| (* clkbuf_sink *) |
| input wire CLK_A_i; |
| (* clkbuf_sink *) |
| input wire CLK_B_i; |
| input wire [1:0] BE_A_i; |
| input wire [1:0] BE_B_i; |
| input wire [13:0] ADDR_A_i; |
| input wire [13:0] ADDR_B_i; |
| input wire [17:0] WDATA_A_i; |
| input wire [17:0] WDATA_B_i; |
| output reg [17:0] RDATA_A_o; |
| output reg [17:0] RDATA_B_o; |
| output wire EMPTY_o; |
| output wire EPO_o; |
| output wire EWM_o; |
| output wire UNDERRUN_o; |
| output wire FULL_o; |
| output wire FMO_o; |
| output wire FWM_o; |
| output wire OVERRUN_o; |
| input wire FLUSH_ni; |
| input wire FMODE_i; |
| reg [17:0] wmsk_a; |
| reg [17:0] wmsk_b; |
| wire [8:0] addr_a; |
| wire [8:0] addr_b; |
| reg [4:0] addr_a_d; |
| reg [4:0] addr_b_d; |
| wire [17:0] ram_rdata_a; |
| wire [17:0] ram_rdata_b; |
| reg [17:0] aligned_wdata_a; |
| reg [17:0] aligned_wdata_b; |
| wire ren_o; |
| wire [10:0] ff_raddr; |
| wire [10:0] ff_waddr; |
| wire [13:0] ram_addr_a; |
| wire [13:0] ram_addr_b; |
| wire [3:0] ram_waddr_a; |
| wire [3:0] ram_waddr_b; |
| wire initn; |
| wire smux_rclk; |
| wire smux_wclk; |
| wire real_fmode; |
| wire [3:0] raw_fflags; |
| reg [1:0] fifo_rmode; |
| reg [1:0] fifo_wmode; |
| wire smux_clk_a; |
| wire smux_clk_b; |
| wire ram_ren_a; |
| wire ram_ren_b; |
| wire ram_wen_a; |
| wire ram_wen_b; |
| wire cen_a; |
| wire cen_b; |
| wire cen_a_n; |
| wire cen_b_n; |
| wire ram_wen_a_n; |
| wire ram_wen_b_n; |
| localparam MODE_9 = 3'b001; |
| always @(*) begin |
| fifo_rmode = (RMODE_B_i == MODE_9 ? 2'b10 : 2'b01); |
| fifo_wmode = (WMODE_A_i == MODE_9 ? 2'b10 : 2'b01); |
| end |
| assign smux_clk_a = CLK_A_i; |
| assign smux_clk_b = CLK_B_i; |
| assign real_fmode = FMODE_i; |
| assign ram_ren_b = real_fmode ? ren_o : REN_B_i; |
| assign ram_wen_a = FMODE_i ? ~FULL_o & WEN_A_i : WEN_A_i; |
| assign ram_ren_a = FMODE_i ? 0 : REN_A_i; |
| assign ram_wen_b = FMODE_i ? 1'b0 : WEN_B_i; |
| assign cen_b = ram_ren_b | ram_wen_b; |
| assign cen_a = ram_ren_a | ram_wen_a; |
| assign ram_waddr_b = real_fmode ? {ff_raddr[0], 3'b000} : ADDR_B_i[3:0]; |
| assign ram_waddr_a = real_fmode ? {ff_waddr[0], 3'b000} : ADDR_A_i[3:0]; |
| assign ram_addr_b = real_fmode ? {ff_raddr[10:0], 3'h0} : {ADDR_B_i[13:4], addr_b_d[3:0]}; |
| assign ram_addr_a = real_fmode ? {ff_waddr[10:0], 3'h0} : {ADDR_A_i[13:4], addr_a_d[3:0]}; |
| always @(posedge CLK_A_i) addr_a_d[3:0] <= ADDR_A_i[3:0]; |
| always @(posedge CLK_B_i) addr_b_d[3:0] <= ADDR_B_i[3:0]; |
| assign cen_a_n = ~cen_a; |
| assign ram_wen_a_n = ~ram_wen_a; |
| assign cen_b_n = ~cen_b; |
| assign ram_wen_b_n = ~ram_wen_b; |
| |
| sram1024x18 uram( |
| .clk_a(smux_clk_a), |
| .cen_a(cen_a_n), |
| .wen_a(ram_wen_a_n), |
| .addr_a(ram_addr_a[13:4]), |
| .wmsk_a(wmsk_a), |
| .wdata_a(aligned_wdata_a), |
| .rdata_a(ram_rdata_a), |
| .clk_b(smux_clk_b), |
| .cen_b(cen_b_n), |
| .wen_b(ram_wen_b_n), |
| .addr_b(ram_addr_b[13:4]), |
| .wmsk_b(wmsk_b), |
| .wdata_b(aligned_wdata_b), |
| .rdata_b(ram_rdata_b) |
| ); |
| fifo_ctl #( |
| .ADDR_WIDTH(11), |
| .FIFO_WIDTH(2), |
| .DEPTH(6) |
| ) fifo_ctl( |
| .rclk(smux_clk_b), |
| .rst_R_n(FLUSH_ni), |
| .wclk(smux_clk_a), |
| .rst_W_n(FLUSH_ni), |
| .ren(REN_B_i), |
| .wen(ram_wen_a), |
| .sync(SYNC_FIFO_i), |
| .rmode(fifo_rmode), |
| .wmode(fifo_wmode), |
| .ren_o(ren_o), |
| .fflags({FULL_o, FMO_o, FWM_o, OVERRUN_o, EMPTY_o, EPO_o, EWM_o, UNDERRUN_o}), |
| .raddr(ff_raddr), |
| .waddr(ff_waddr), |
| .upaf(UPAF_i), |
| .upae(UPAE_i) |
| ); |
| localparam MODE_1 = 3'b101; |
| localparam MODE_18 = 3'b010; |
| localparam MODE_2 = 3'b110; |
| localparam MODE_4 = 3'b100; |
| always @(*) begin : WDATA_MODE_SEL |
| if (ram_wen_a == 1) begin |
| case (WMODE_A_i) |
| MODE_18: begin |
| aligned_wdata_a = WDATA_A_i; |
| {wmsk_a[17], wmsk_a[15:8]} = (FMODE_i ? 9'h000 : (BE_A_i[1] ? 9'h000 : 9'h1ff)); |
| {wmsk_a[16], wmsk_a[7:0]} = (FMODE_i ? 9'h000 : (BE_A_i[0] ? 9'h000 : 9'h1ff)); |
| end |
| MODE_9: begin |
| aligned_wdata_a = {{2 {WDATA_A_i[16]}}, {2 {WDATA_A_i[7:0]}}}; |
| {wmsk_a[17], wmsk_a[15:8]} = (ram_waddr_a[3] ? 9'h000 : 9'h1ff); |
| {wmsk_a[16], wmsk_a[7:0]} = (ram_waddr_a[3] ? 9'h1ff : 9'h000); |
| end |
| MODE_4: begin |
| aligned_wdata_a = {2'b00, {4 {WDATA_A_i[3:0]}}}; |
| wmsk_a[17:16] = 2'b00; |
| wmsk_a[15:12] = (ram_waddr_a[3:2] == 2'b11 ? 4'h0 : 4'hf); |
| wmsk_a[11:8] = (ram_waddr_a[3:2] == 2'b10 ? 4'h0 : 4'hf); |
| wmsk_a[7:4] = (ram_waddr_a[3:2] == 2'b01 ? 4'h0 : 4'hf); |
| wmsk_a[3:0] = (ram_waddr_a[3:2] == 2'b00 ? 4'h0 : 4'hf); |
| end |
| MODE_2: begin |
| aligned_wdata_a = {2'b00, {8 {WDATA_A_i[1:0]}}}; |
| wmsk_a[17:16] = 2'b00; |
| wmsk_a[15:14] = (ram_waddr_a[3:1] == 3'b111 ? 2'h0 : 2'h3); |
| wmsk_a[13:12] = (ram_waddr_a[3:1] == 3'b110 ? 2'h0 : 2'h3); |
| wmsk_a[11:10] = (ram_waddr_a[3:1] == 3'b101 ? 2'h0 : 2'h3); |
| wmsk_a[9:8] = (ram_waddr_a[3:1] == 3'b100 ? 2'h0 : 2'h3); |
| wmsk_a[7:6] = (ram_waddr_a[3:1] == 3'b011 ? 2'h0 : 2'h3); |
| wmsk_a[5:4] = (ram_waddr_a[3:1] == 3'b010 ? 2'h0 : 2'h3); |
| wmsk_a[3:2] = (ram_waddr_a[3:1] == 3'b001 ? 2'h0 : 2'h3); |
| wmsk_a[1:0] = (ram_waddr_a[3:1] == 3'b000 ? 2'h0 : 2'h3); |
| end |
| MODE_1: begin |
| aligned_wdata_a = {2'b00, {16 {WDATA_A_i[0]}}}; |
| wmsk_a = 18'h0ffff; |
| wmsk_a[{1'b0, ram_waddr_a[3:0]}] = 0; |
| end |
| default: wmsk_a = 18'h3ffff; |
| endcase |
| end |
| else begin |
| aligned_wdata_a = 18'h00000; |
| wmsk_a = 18'h3ffff; |
| end |
| if (ram_wen_b == 1) |
| case (WMODE_B_i) |
| MODE_18: begin |
| aligned_wdata_b = WDATA_B_i; |
| {wmsk_b[17], wmsk_b[15:8]} = (BE_B_i[1] ? 9'h000 : 9'h1ff); |
| {wmsk_b[16], wmsk_b[7:0]} = (BE_B_i[0] ? 9'h000 : 9'h1ff); |
| end |
| MODE_9: begin |
| aligned_wdata_b = {{2 {WDATA_B_i[16]}}, {2 {WDATA_B_i[7:0]}}}; |
| {wmsk_b[17], wmsk_b[15:8]} = (ram_waddr_b[3] ? 9'h000 : 9'h1ff); |
| {wmsk_b[16], wmsk_b[7:0]} = (ram_waddr_b[3] ? 9'h1ff : 9'h000); |
| end |
| MODE_4: begin |
| aligned_wdata_b = {2'b00, {4 {WDATA_B_i[3:0]}}}; |
| wmsk_b[17:16] = 2'b00; |
| wmsk_b[15:12] = (ram_waddr_b[3:2] == 2'b11 ? 4'h0 : 4'hf); |
| wmsk_b[11:8] = (ram_waddr_b[3:2] == 2'b10 ? 4'h0 : 4'hf); |
| wmsk_b[7:4] = (ram_waddr_b[3:2] == 2'b01 ? 4'h0 : 4'hf); |
| wmsk_b[3:0] = (ram_waddr_b[3:2] == 2'b00 ? 4'h0 : 4'hf); |
| end |
| MODE_2: begin |
| aligned_wdata_b = {2'b00, {8 {WDATA_B_i[1:0]}}}; |
| wmsk_b[17:16] = 2'b00; |
| wmsk_b[15:14] = (ram_waddr_b[3:1] == 3'b111 ? 2'h0 : 2'h3); |
| wmsk_b[13:12] = (ram_waddr_b[3:1] == 3'b110 ? 2'h0 : 2'h3); |
| wmsk_b[11:10] = (ram_waddr_b[3:1] == 3'b101 ? 2'h0 : 2'h3); |
| wmsk_b[9:8] = (ram_waddr_b[3:1] == 3'b100 ? 2'h0 : 2'h3); |
| wmsk_b[7:6] = (ram_waddr_b[3:1] == 3'b011 ? 2'h0 : 2'h3); |
| wmsk_b[5:4] = (ram_waddr_b[3:1] == 3'b010 ? 2'h0 : 2'h3); |
| wmsk_b[3:2] = (ram_waddr_b[3:1] == 3'b001 ? 2'h0 : 2'h3); |
| wmsk_b[1:0] = (ram_waddr_b[3:1] == 3'b000 ? 2'h0 : 2'h3); |
| end |
| MODE_1: begin |
| aligned_wdata_b = {2'b00, {16 {WDATA_B_i[0]}}}; |
| wmsk_b = 18'h0ffff; |
| wmsk_b[{1'b0, ram_waddr_b[3:0]}] = 0; |
| end |
| default: wmsk_b = 18'h3ffff; |
| endcase |
| else begin |
| aligned_wdata_b = 18'b000000000000000000; |
| wmsk_b = 18'h3ffff; |
| end |
| end |
| always @(*) begin : RDATA_A_MODE_SEL |
| case (RMODE_A_i) |
| default: RDATA_A_o = 18'h00000; |
| MODE_18: RDATA_A_o = ram_rdata_a; |
| MODE_9: begin |
| {RDATA_A_o[17], RDATA_A_o[15:8]} = 9'h000; |
| {RDATA_A_o[16], RDATA_A_o[7:0]} = (ram_addr_a[3] ? {ram_rdata_a[17], ram_rdata_a[15:8]} : {ram_rdata_a[16], ram_rdata_a[7:0]}); |
| end |
| MODE_4: begin |
| RDATA_A_o[17:4] = 14'h0000; |
| case (ram_addr_a[3:2]) |
| 3: RDATA_A_o[3:0] = ram_rdata_a[15:12]; |
| 2: RDATA_A_o[3:0] = ram_rdata_a[11:8]; |
| 1: RDATA_A_o[3:0] = ram_rdata_a[7:4]; |
| 0: RDATA_A_o[3:0] = ram_rdata_a[3:0]; |
| endcase |
| end |
| MODE_2: begin |
| RDATA_A_o[17:2] = 16'h0000; |
| case (ram_addr_a[3:1]) |
| 7: RDATA_A_o[1:0] = ram_rdata_a[15:14]; |
| 6: RDATA_A_o[1:0] = ram_rdata_a[13:12]; |
| 5: RDATA_A_o[1:0] = ram_rdata_a[11:10]; |
| 4: RDATA_A_o[1:0] = ram_rdata_a[9:8]; |
| 3: RDATA_A_o[1:0] = ram_rdata_a[7:6]; |
| 2: RDATA_A_o[1:0] = ram_rdata_a[5:4]; |
| 1: RDATA_A_o[1:0] = ram_rdata_a[3:2]; |
| 0: RDATA_A_o[1:0] = ram_rdata_a[1:0]; |
| endcase |
| end |
| MODE_1: begin |
| RDATA_A_o[17:1] = 17'h00000; |
| RDATA_A_o[0] = ram_rdata_a[ram_addr_a[3:0]]; |
| end |
| endcase |
| end |
| always @(*) |
| case (RMODE_B_i) |
| default: RDATA_B_o = 18'h15566; |
| MODE_18: RDATA_B_o = ram_rdata_b; |
| MODE_9: begin |
| {RDATA_B_o[17], RDATA_B_o[15:8]} = 9'b000000000; |
| {RDATA_B_o[16], RDATA_B_o[7:0]} = (ram_addr_b[3] ? {ram_rdata_b[17], ram_rdata_b[15:8]} : {ram_rdata_b[16], ram_rdata_b[7:0]}); |
| end |
| MODE_4: |
| case (ram_addr_b[3:2]) |
| 3: RDATA_B_o[3:0] = ram_rdata_b[15:12]; |
| 2: RDATA_B_o[3:0] = ram_rdata_b[11:8]; |
| 1: RDATA_B_o[3:0] = ram_rdata_b[7:4]; |
| 0: RDATA_B_o[3:0] = ram_rdata_b[3:0]; |
| endcase |
| MODE_2: |
| case (ram_addr_b[3:1]) |
| 7: RDATA_B_o[1:0] = ram_rdata_b[15:14]; |
| 6: RDATA_B_o[1:0] = ram_rdata_b[13:12]; |
| 5: RDATA_B_o[1:0] = ram_rdata_b[11:10]; |
| 4: RDATA_B_o[1:0] = ram_rdata_b[9:8]; |
| 3: RDATA_B_o[1:0] = ram_rdata_b[7:6]; |
| 2: RDATA_B_o[1:0] = ram_rdata_b[5:4]; |
| 1: RDATA_B_o[1:0] = ram_rdata_b[3:2]; |
| 0: RDATA_B_o[1:0] = ram_rdata_b[1:0]; |
| endcase |
| MODE_1: RDATA_B_o[0] = ram_rdata_b[{1'b0, ram_addr_b[3:0]}]; |
| endcase |
| endmodule |
| `default_nettype none |