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