blob: 696c2a7951885034a441f8f567d416d25e9688f4 [file] [log] [blame]
// Copyright (C) 2022 The SymbiFlow Authors.
//
// Use of this source code is governed by a ISC-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/ISC
//
// SPDX-License-Identifier:ISC
module TDP18K_FIFO (
RMODE_A,
RMODE_B,
WMODE_A,
WMODE_B,
WEN_A,
WEN_B,
REN_A,
REN_B,
CLK_A,
CLK_B,
BE_A,
BE_B,
ADDR_A,
ADDR_B,
WDATA_A,
WDATA_B,
RDATA_A,
RDATA_B,
EMPTY,
EPO,
EWM,
UNDERRUN,
FULL,
FMO,
FWM,
OVERRUN,
FLUSH,
RAM_ID,
FMODE,
PL_INIT,
PL_ENA,
PL_WEN,
PL_REN,
PL_CLK,
PL_ADDR,
PL_DATA_IN,
PL_DATA_OUT
);
parameter SYNC_FIFO = 1'b0;
parameter POWERDN = 1'b0;
parameter SLEEP = 1'b0;
parameter PROTECT = 1'b0;
parameter UPAF = 11'b0;
parameter UPAE = 11'b0;
input wire [2:0] RMODE_A;
input wire [2:0] RMODE_B;
input wire [2:0] WMODE_A;
input wire [2:0] WMODE_B;
input wire WEN_A;
input wire WEN_B;
input wire REN_A;
input wire REN_B;
(* clkbuf_sink *)
input wire CLK_A;
(* clkbuf_sink *)
input wire CLK_B;
input wire [1:0] BE_A;
input wire [1:0] BE_B;
input wire [13:0] ADDR_A;
input wire [13:0] ADDR_B;
input wire [17:0] WDATA_A;
input wire [17:0] WDATA_B;
output reg [17:0] RDATA_A;
output reg [17:0] RDATA_B;
output wire EMPTY;
output wire EPO;
output wire EWM;
output wire UNDERRUN;
output wire FULL;
output wire FMO;
output wire FWM;
output wire OVERRUN;
input wire FLUSH;
input wire [15:0] RAM_ID;
input wire FMODE;
input PL_INIT;
input PL_ENA;
input PL_WEN;
input PL_REN;
input PL_CLK;
input [31:0] PL_ADDR;
input [17:0] PL_DATA_IN;
output reg [17:0] PL_DATA_OUT;
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 preload;
wire my_id;
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;
localparam MODE_9 = 3'b101;
always @(*) begin
fifo_rmode = (RMODE_B == MODE_9 ? 2'b10 : 2'b01);
fifo_wmode = (WMODE_A == MODE_9 ? 2'b10 : 2'b01);
end
assign my_id = (PL_ADDR[31:16] == RAM_ID) | PL_INIT;
assign preload = (PROTECT ? 1'b0 : my_id & PL_ENA);
assign smux_clk_a = (preload ? PL_CLK : CLK_A);
assign smux_clk_b = (preload ? 0 : (FMODE ? (SYNC_FIFO ? CLK_A : CLK_B) : CLK_B));
assign real_fmode = (preload ? 1'b0 : FMODE);
assign ram_ren_b = (preload ? PL_REN : (real_fmode ? ren_o : REN_B));
assign ram_wen_a = (preload ? PL_WEN : (FMODE ? ~FULL & WEN_A : WEN_A));
assign ram_ren_a = (preload ? 1'b1 : (FMODE ? 0 : REN_A));
assign ram_wen_b = (preload ? 1'b1 : (FMODE ? 1'b0 : WEN_B));
assign cen_b = ram_ren_b | ram_wen_b;
assign cen_a = ram_ren_a | ram_wen_a;
assign ram_waddr_b = (preload ? 4'b0000 : (real_fmode ? {ff_raddr[0], 3'b000} : ADDR_B[3:0]));
assign ram_waddr_a = (preload ? 4'b0000 : (real_fmode ? {ff_waddr[0], 3'b000} : ADDR_A[3:0]));
assign ram_addr_b = (preload ? {PL_ADDR[10:0], 3'h0} : (real_fmode ? {ff_raddr[10:0], 3'h0} : {ADDR_B[13:4], addr_b_d[3:0]}));
assign ram_addr_a = (preload ? {PL_ADDR[10:0], 3'h0} : (real_fmode ? {ff_waddr[10:0], 3'b000} : {ADDR_A[13:4], addr_a_d[3:0]}));
always @(posedge CLK_A) addr_a_d[3:0] <= ADDR_A[3:0];
always @(posedge CLK_B) addr_b_d[3:0] <= ADDR_B[3:0];
sram1024x18 uram(
.clk_a(smux_clk_a),
.cen_a(~cen_a),
.wen_a(~ram_wen_a),
.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),
.wen_b(~ram_wen_b),
.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)
) fifo_ctl(
.rclk(smux_clk_b),
.rst_R_n(~FLUSH),
.wclk(smux_clk_a),
.rst_W_n(~FLUSH),
.ren(REN_B),
.wen(ram_wen_a),
.depth(3'b000),
.sync(SYNC_FIFO),
.rmode(fifo_rmode),
.wmode(fifo_wmode),
.ren_o(ren_o),
.fflags({FULL, FMO, FWM, OVERRUN, EMPTY, EPO, EWM, UNDERRUN}),
.raddr(ff_raddr),
.waddr(ff_waddr),
.upaf(UPAF),
.upae(UPAE)
);
always @(*) begin : PRELOAD_DATA
if (preload & ram_ren_a)
PL_DATA_OUT = ram_rdata_a;
else
PL_DATA_OUT = PL_DATA_IN;
end
localparam MODE_1 = 3'b001;
localparam MODE_18 = 3'b110;
localparam MODE_2 = 3'b010;
localparam MODE_4 = 3'b100;
always @(*) begin : WDATA_MODE_SEL
if (ram_wen_a == 1) begin
if (preload) begin
aligned_wdata_a = PL_DATA_IN;
wmsk_a = 18'h00000;
end
else
case (WMODE_A)
MODE_18: begin
aligned_wdata_a = WDATA_A;
{wmsk_a[17], wmsk_a[15:8]} = (FMODE ? 9'h000 : (BE_A[1] ? 9'h000 : 9'h1ff));
{wmsk_a[16], wmsk_a[7:0]} = (FMODE ? 9'h000 : (BE_A[0] ? 9'h000 : 9'h1ff));
end
MODE_9: begin
aligned_wdata_a = {{2 {WDATA_A[8]}}, {2 {WDATA_A[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[3:0]}}};
wmsk_a[17:16] = 2'b11;
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[1:0]}}};
wmsk_a[17:16] = 2'b11;
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[0]}}};
wmsk_a = 18'h3ffff;
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)
MODE_18: begin
aligned_wdata_b = WDATA_B;
{wmsk_b[17], wmsk_b[15:8]} = (BE_B[1] ? 9'h000 : 9'h1ff);
{wmsk_b[16], wmsk_b[7:0]} = (BE_B[0] ? 9'h000 : 9'h1ff);
end
MODE_9: begin
aligned_wdata_b = {{2 {WDATA_B[8]}}, {2 {WDATA_B[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[3:0]}}};
wmsk_b[17:16] = 2'b11;
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[1:0]}}};
wmsk_b[17:16] = 2'b11;
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[0]}}};
wmsk_b = 18'h3ffff;
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)
default: RDATA_A = 18'h00000;
MODE_18: RDATA_A = ram_rdata_a;
MODE_9: begin
RDATA_A[17:9] = 9'h000;
RDATA_A[8: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[17:4] = 14'h0000;
case (ram_addr_a[3:2])
3: RDATA_A[3:0] = ram_rdata_a[15:12];
2: RDATA_A[3:0] = ram_rdata_a[11:8];
1: RDATA_A[3:0] = ram_rdata_a[7:4];
0: RDATA_A[3:0] = ram_rdata_a[3:0];
endcase
end
MODE_2: begin
RDATA_A[17:2] = 16'h0000;
case (ram_addr_a[3:1])
7: RDATA_A[1:0] = ram_rdata_a[15:14];
6: RDATA_A[1:0] = ram_rdata_a[13:12];
5: RDATA_A[1:0] = ram_rdata_a[11:10];
4: RDATA_A[1:0] = ram_rdata_a[9:8];
3: RDATA_A[1:0] = ram_rdata_a[7:6];
2: RDATA_A[1:0] = ram_rdata_a[5:4];
1: RDATA_A[1:0] = ram_rdata_a[3:2];
0: RDATA_A[1:0] = ram_rdata_a[1:0];
endcase
end
MODE_1: begin
RDATA_A[17:1] = 17'h00000;
RDATA_A[0] = ram_rdata_a[ram_addr_a[3:0]];
end
endcase
end
always @(*)
case (RMODE_B)
default: RDATA_B = 18'h15566;
MODE_18: RDATA_B = ram_rdata_b;
MODE_9: begin
RDATA_B[17:9] = 1'sb1;
RDATA_B[8: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[3:0] = ram_rdata_b[15:12];
2: RDATA_B[3:0] = ram_rdata_b[11:8];
1: RDATA_B[3:0] = ram_rdata_b[7:4];
0: RDATA_B[3:0] = ram_rdata_b[3:0];
endcase
MODE_2:
case (ram_addr_b[3:1])
7: RDATA_B[1:0] = ram_rdata_b[15:14];
6: RDATA_B[1:0] = ram_rdata_b[13:12];
5: RDATA_B[1:0] = ram_rdata_b[11:10];
4: RDATA_B[1:0] = ram_rdata_b[9:8];
3: RDATA_B[1:0] = ram_rdata_b[7:6];
2: RDATA_B[1:0] = ram_rdata_b[5:4];
1: RDATA_B[1:0] = ram_rdata_b[3:2];
0: RDATA_B[1:0] = ram_rdata_b[1:0];
endcase
MODE_1: RDATA_B[0] = ram_rdata_b[ram_addr_b[3:0]];
endcase
endmodule