gary/sim/DP16KD.v

799 lines
37 KiB
Verilog

// DP16KD__INTERNAL is a dual-port memory with equal width ports and
// read-before-write behavior (writes output the previous value at the
// write address).
module DP16KD__INTERNAL#(
parameter DATA_WIDTH = 18,
parameter ADDR_WIDTH = 10,
parameter RESETMODE = "SYNC",
parameter WRITEMODE_A = "NORMAL",
parameter WRITEMODE_B = "NORMAL"
) (
input CLKA,
input RSTA,
input CEA,
input WEA,
input [ADDR_WIDTH-1:0] ADA,
input [DATA_WIDTH-1:0] DIA,
output reg [DATA_WIDTH-1:0] DOA,
input CLKB,
input RSTB,
input CEB,
input WEB,
input [ADDR_WIDTH-1:0] ADB,
input [DATA_WIDTH-1:0] DIB,
output reg [DATA_WIDTH-1:0] DOB);
(* no_rw_check *)
reg [DATA_WIDTH-1:0] ram[(2**ADDR_WIDTH)-1:0];
wire [DATA_WIDTH-1:0] undef = {DATA_WIDTH{1'bx}};
if (RESETMODE == "SYNC") begin : sync_ram
always @(posedge CLKA) begin
if (RSTA)
DOA <= {DATA_WIDTH {1'b0}};
else if (CEA) begin
if (WEA) begin
ram[ADA] <= DIA;
case (WRITEMODE_A)
"NORMAL": DOA <= undef;
"WRITETHROUGH": DOA <= DIA;
"READBEFOREWRITE": DOA <= ram[ADA];
endcase
end
else
DOA <= ram[ADA];
end
end
always @(posedge CLKB) begin
if (RSTB)
DOB <= {DATA_WIDTH {1'b0}};
else if (CEB) begin
if (WEB) begin
ram[ADB] <= DIB;
case (WRITEMODE_B)
"NORMAL": DOB <= undef;
"WRITETHROUGH": DOB <= DIB;
"READBEFOREWRITE": DOB <= ram[ADB];
endcase
end
else
DOB <= ram[ADB];
end
end
end // if (RESETMODE == "SYNC")
else begin : async_ram
always @(posedge CLKA, posedge RSTA) begin
if (RSTA)
DOA <= {DATA_WIDTH {1'b0}};
else if (CEA) begin
if (WEA) begin
ram[ADA] <= DIA;
case (WRITEMODE_A)
"NORMAL": DOA <= undef;
"WRITETHROUGH": DOA <= DIA;
"READBEFOREWRITE": DOA <= ram[ADA];
endcase
end
else
DOA <= ram[ADA];
end
end
always @(posedge CLKB, posedge RSTB) begin
if (RSTB)
DOB <= {DATA_WIDTH {1'b0}};
else if (CEB) begin
if (WEB) begin
ram[ADB] <= DIB;
case (WRITEMODE_B)
"NORMAL": DOB <= undef;
"WRITETHROUGH": DOB <= DIB;
"READBEFOREWRITE": DOB <= ram[ADB];
endcase
end
else
DOB <= ram[ADB];
end
end
end // else: !if(RESETMODE == "SYNC")
endmodule
// DP16KD__SPLIT_MUL is a dual-port memory where port B's width is a
// multiple of port A (e.g. 2b and 4b, or 9b and 18b). The larger port
// effectively accesses multiple words from the smaller port in a
// single operation.
module DP16KD__SPLIT_MUL#(
parameter DATA_WIDTH_A = 1,
parameter ADDR_WIDTH_A = 14,
parameter DATA_WIDTH_B = 4,
parameter RESETMODE = "SYNC",
parameter WRITEMODE_A = "NORMAL",
parameter WRITEMODE_B = "NORMAL"
)(
input CLKA,
input RSTA,
input CEA,
input WEA,
input [ADDR_WIDTH_A-1:0] ADA,
input [DATA_WIDTH_A-1:0] DIA,
output [DATA_WIDTH_A-1:0] DOA,
input CLKB,
input RSTB,
input CEB,
input WEB,
input [ADDR_WIDTH_B-1:0] ADB,
input [DATA_WIDTH_B-1:0] DIB,
output [DATA_WIDTH_B-1:0] DOB
);
localparam ADDR_WIDTH_B = $clog2((DATA_WIDTH_A * (2**ADDR_WIDTH_A)) / DATA_WIDTH_B);
localparam CSA_WIDTH = ADDR_WIDTH_A - ADDR_WIDTH_B;
localparam NUM_MEMS = 2**CSA_WIDTH;
// Convert the lower bits of ADA into a one-hot signal to select one
// of the sub-memories. This stripes consecutive addresses across
// all sub-memories, which the wider port can then access in
// parallel and get the correct view of bits.
wire [CSA_WIDTH-1:0] CSA = ADA[CSA_WIDTH-1:0];
wire [NUM_MEMS-1:0] CSA_onehot = {NUM_MEMS { CEA }} & 1 << CSA;
wire [(DATA_WIDTH_A*NUM_MEMS)-1:0] DOA_SUB;
assign DOA = DOA_SUB[CSA*DATA_WIDTH_A +: DATA_WIDTH_A];
DP16KD__INTERNAL#(.DATA_WIDTH(DATA_WIDTH_A),
.ADDR_WIDTH(ADDR_WIDTH_B),
.RESETMODE(RESETMODE),
.WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B(WRITEMODE_B)) rams [NUM_MEMS-1:0]
(.CLKA(CLKA), .RSTA(RSTA), .CEA(CSA_onehot), .WEA(WEA),
.ADA(ADA[ADDR_WIDTH_A-1:CSA_WIDTH]), .DIA(DIA), .DOA(DOA_SUB),
.CLKB(CLKB), .RSTB(RSTB), .CEB(CEB), .WEB(WEB),
.ADB(ADB), .DIB(DIB), .DOB(DOB));
endmodule // DP16KD__SPLIT_MUL
// DP16KD__DECOMPOSE is a dual-port memory where the port widths are
// 1b, 2b, 4b, 9b or 18b, and port A's width is less than or equal to
// port B's width. The memory is implemented by mapping the two ports
// onto an internal memory with the same mapping as the ECP5 DP16KD:
// power of two words get packed into each other, 9b words get packed
// into 18b words, and a memory with a single 9b or 18b port gets
// treated like an 8b or 16b port, with the remaining ECC bits kept
// separate and invisible to the power-of-two port.
module DP16KD__DECOMPOSE#(
parameter RESETMODE = "SYNC",
parameter DATA_WIDTH_A = 18,
parameter DATA_WIDTH_B = 18,
parameter WRITEMODE_A = "NORMAL",
parameter WRITEMODE_B = "NORMAL"
)(
input CLKA,
input RSTA,
input CEA,
input WEA,
input [ADDR_WIDTH_A-1:0] ADA,
input [DATA_WIDTH_A-1:0] DIA,
output [DATA_WIDTH_A-1:0] DOA,
input CLKB,
input RSTB,
input CEB,
input WEB,
input [ADDR_WIDTH_B-1:0] ADB,
input [DATA_WIDTH_B-1:0] DIB,
output [DATA_WIDTH_B-1:0] DOB
);
localparam ADDR_WIDTH_A = (DATA_WIDTH_A == 18 ? 10 :
DATA_WIDTH_A == 9 ? 11 :
DATA_WIDTH_A == 4 ? 12 :
DATA_WIDTH_A == 2 ? 13 :
DATA_WIDTH_A == 1 ? 14 : -1);
localparam ADDR_WIDTH_B = (DATA_WIDTH_B == 18 ? 10 :
DATA_WIDTH_B == 9 ? 11 :
DATA_WIDTH_B == 4 ? 12 :
DATA_WIDTH_B == 2 ? 13 :
DATA_WIDTH_B == 1 ? 14 : -1);
localparam DATA_WIDTH_HYBRID = (DATA_WIDTH_A < 9 && DATA_WIDTH_B >= 9) || (DATA_WIDTH_A >= 9 && DATA_WIDTH_B < 9);
if (DATA_WIDTH_A == DATA_WIDTH_B) begin : equal_width_ports
DP16KD__INTERNAL#(.DATA_WIDTH(DATA_WIDTH_A),
.ADDR_WIDTH(ADDR_WIDTH_A),
.RESETMODE(RESETMODE),
.WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B(WRITEMODE_B)) ram
(.CLKA(CLKA), .RSTA(RSTA), .CEA(CEA), .WEA(WEA), .ADA(ADA), .DIA(DIA), .DOA(DOA),
.CLKB(CLKB), .RSTB(RSTB), .CEB(CEB), .WEB(WEB), .ADB(ADB), .DIB(DIB), .DOB(DOB));
end
else if (DATA_WIDTH_HYBRID) begin : one_ecc_port
if (DATA_WIDTH_B == 9) begin : one_ecc_bit
DP16KD__INTERNAL#(.DATA_WIDTH(1),
.ADDR_WIDTH(ADDR_WIDTH_B),
.RESETMODE(RESETMODE),
.WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B(WRITEMODE_B)) ecc
(.CLKA(1'b0), .RSTA(1'b0), .CEA(1'b0), .WEA(1'b0), .ADA({ADDR_WIDTH_B {1'b0}}), .DIA(1'b0), .DOA(),
.CLKB(CLKB), .RSTB(RSTB), .CEB(CEB), .WEB(WEB), .ADB(ADB), .DIB(DIB[8]), .DOB(DOB[8]));
DP16KD__SPLIT_MUL#(.DATA_WIDTH_A(DATA_WIDTH_A),
.ADDR_WIDTH_A(ADDR_WIDTH_A),
.DATA_WIDTH_B(DATA_WIDTH_B-1),
.RESETMODE(RESETMODE),
.WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B(WRITEMODE_B)) ram
(.CLKA(CLKA), .RSTA(RSTA), .CEA(CEA), .WEA(WEA), .ADA(ADA), .DIA(DIA), .DOA(DOA),
.CLKB(CLKB), .RSTB(RSTB), .CEB(CEB), .WEB(WEB), .ADB(ADB), .DIB(DIB[7:0]), .DOB(DOB[7:0]));
end // if (DATA_WIDTH_B == 9)
else begin : two_ecc_bits
DP16KD__INTERNAL#(.DATA_WIDTH(2),
.ADDR_WIDTH(ADDR_WIDTH_B),
.RESETMODE(RESETMODE),
.WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B(WRITEMODE_B)) ecc
(.CLKA(1'b0), .RSTA(1'b0), .CEA(1'b0), .WEA(1'b0), .ADA({ADDR_WIDTH_B {1'b0}}), .DIA(1'b0), .DOA(),
.CLKB(CLKB), .RSTB(RSTB), .CEB(CEB), .WEB(WEB), .ADB(ADB), .DIB({DIB[17], DIB[8]}), .DOB({DOB[17], DOB[8]}));
DP16KD__SPLIT_MUL#(.DATA_WIDTH_A(DATA_WIDTH_A),
.ADDR_WIDTH_A(ADDR_WIDTH_A),
.DATA_WIDTH_B(DATA_WIDTH_B-2),
.RESETMODE(RESETMODE),
.WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B(WRITEMODE_B)) ram
(.CLKA(CLKA), .RSTA(RSTA), .CEA(CEA), .WEA(WEA), .ADA(ADA), .DIA(DIA), .DOA(DOA),
.CLKB(CLKB), .RSTB(RSTB), .CEB(CEB), .WEB(WEB), .ADB(ADB), .DIB({DIB[16:9], DIB[7:0]}), .DOB({DOB[16:9], DOB[7:0]}));
end // else: !if(DATA_WIDTH_B == 9)
end // if (!DATA_WIDTH_HYBRID)
else begin : simple_multiple_ports
DP16KD__SPLIT_MUL#(.DATA_WIDTH_A(DATA_WIDTH_A),
.ADDR_WIDTH_A(ADDR_WIDTH_A),
.DATA_WIDTH_B(DATA_WIDTH_B),
.RESETMODE(RESETMODE),
.WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B(WRITEMODE_B)) ram
(.CLKA(CLKA), .RSTA(RSTA), .CEA(CEA), .WEA(WEA), .ADA(ADA), .DIA(DIA), .DOA(DOA),
.CLKB(CLKB), .RSTB(RSTB), .CEB(CEB), .WEB(WEB), .ADB(ADB), .DIB(DIB), .DOB(DOB));
end // else: !if(!DATA_WIDTH_HYBRID)
endmodule
module DP16KD(
input DIA17, DIA16, DIA15, DIA14, DIA13, DIA12, DIA11, DIA10, DIA9, DIA8, DIA7, DIA6, DIA5, DIA4, DIA3, DIA2, DIA1, DIA0,
input ADA13, ADA12, ADA11, ADA10, ADA9, ADA8, ADA7, ADA6, ADA5, ADA4, ADA3, ADA2, ADA1, ADA0,
input CEA, OCEA, CLKA, WEA, RSTA,
input CSA2, CSA1, CSA0,
output DOA17, DOA16, DOA15, DOA14, DOA13, DOA12, DOA11, DOA10, DOA9, DOA8, DOA7, DOA6, DOA5, DOA4, DOA3, DOA2, DOA1, DOA0,
input DIB17, DIB16, DIB15, DIB14, DIB13, DIB12, DIB11, DIB10, DIB9, DIB8, DIB7, DIB6, DIB5, DIB4, DIB3, DIB2, DIB1, DIB0,
input ADB13, ADB12, ADB11, ADB10, ADB9, ADB8, ADB7, ADB6, ADB5, ADB4, ADB3, ADB2, ADB1, ADB0,
input CEB, OCEB, CLKB, WEB, RSTB,
input CSB2, CSB1, CSB0,
output DOB17, DOB16, DOB15, DOB14, DOB13, DOB12, DOB11, DOB10, DOB9, DOB8, DOB7, DOB6, DOB5, DOB4, DOB3, DOB2, DOB1, DOB0
);
// Internal behavior of the RSTA/RSTB inputs. Regardless of mode,
// asserting RSTA/RSTB only clears the input/output registers for
// their respective port. The contents of the memory is unaffected.
//
// If RESETMODE=SYNC, RSTA and RSTB are only acted upon at
// positive-going edges of CLKA and CLKB, respectively. In this mode
// ASYNC_RESET_RELEASE is ignored.
//
// If RESETMODE=ASYNC and ASYNC_RESET_RELEASE=SYNC, asserting RSTA
// or RSTB is acted upon immediately, but release from reset is
// synchronized to positive-going edges of CLKA or CLKB,
// respectively. The caller must allow for a few clock cycles of
// settling time after release from reset, before the memory is
// ready for use.
//
// If RESETMODE=ASYNC and ASYNC_RESET_RELEASE=ASYNC, assertion and
// release of RSTA and RSTB are both acted upon immediately. In this
// mode, the caller is expected to explicitly sequence the reset to
// avoid metastable behavior: halt the port's clock, assert reset,
// wait for flops to settle, release reset, wait for flops to
// settle, re-enable port clock.
parameter RESETMODE = "SYNC";
parameter ASYNC_RESET_RELEASE = "SYNC";
// The width of the input/output data busses, one of 1, 2, 4, 9 or
// 18. When less than 18, the unused DIA inputs are ignored and the
// unused DOA outputs are undefined.
parameter DATA_WIDTH_A = 18;
parameter DATA_WIDTH_B = 18;
// Output registration. If "NOREG", only inputs are registered and
// operations have a latency of 1 cycle. If "OUTREG", an additional
// register is inserted on DOA, and operation latency is 2
// cycles. Adding an output register significantly shortens the RAM
// datapath, and may enable higher operating frequency.
parameter REGMODE_A = "NOREG";
parameter REGMODE_B = "NOREG";
// Chip select address. The memory only responds to inputs if the
// value of {CSA2, CSA1, CSA0} matches this address. This can be
// used to array DP16KD primitives into larger memories without
// needing external chip select circuitry.
parameter CSDECODE_A = "0b000";
parameter CSDECODE_B = "0b000";
// Output behavior on write cycles.
//
// If "NORMAL", the output value is undefined during a write.
//
// If "WRITETHROUGH", the memory mirrors the value being written to
// the output.
//
// If "READBEFOREWRITE", the memory outputs the value that was just
// replaced by the write.
parameter WRITEMODE_A = "NORMAL";
parameter WRITEMODE_B = "NORMAL";
// DP16KD has optional inverters on every input and output. Each
// *MUX parameter configures inversion of the corresponding
// input/output: a value of "<name of the input/output>" means use
// the signal as-is, "INV" means insert an inverter.
parameter DIA17MUX = "DIA17";
parameter DIA16MUX = "DIA16";
parameter DIA15MUX = "DIA15";
parameter DIA14MUX = "DIA14";
parameter DIA13MUX = "DIA13";
parameter DIA12MUX = "DIA12";
parameter DIA11MUX = "DIA11";
parameter DIA10MUX = "DIA10";
parameter DIA9MUX = "DIA9";
parameter DIA8MUX = "DIA8";
parameter DIA7MUX = "DIA7";
parameter DIA6MUX = "DIA6";
parameter DIA5MUX = "DIA5";
parameter DIA4MUX = "DIA4";
parameter DIA3MUX = "DIA3";
parameter DIA2MUX = "DIA2";
parameter DIA1MUX = "DIA1";
parameter DIA0MUX = "DIA0";
parameter ADA13MUX = "ADA13";
parameter ADA12MUX = "ADA12";
parameter ADA11MUX = "ADA11";
parameter ADA10MUX = "ADA10";
parameter ADA9MUX = "ADA9";
parameter ADA8MUX = "ADA8";
parameter ADA7MUX = "ADA7";
parameter ADA6MUX = "ADA6";
parameter ADA5MUX = "ADA5";
parameter ADA4MUX = "ADA4";
parameter ADA3MUX = "ADA3";
parameter ADA2MUX = "ADA2";
parameter ADA1MUX = "ADA1";
parameter ADA0MUX = "ADA0";
parameter DOA17MUX = "DOA17";
parameter DOA16MUX = "DOA16";
parameter DOA15MUX = "DOA15";
parameter DOA14MUX = "DOA14";
parameter DOA13MUX = "DOA13";
parameter DOA12MUX = "DOA12";
parameter DOA11MUX = "DOA11";
parameter DOA10MUX = "DOA10";
parameter DOA9MUX = "DOA9";
parameter DOA8MUX = "DOA8";
parameter DOA7MUX = "DOA7";
parameter DOA6MUX = "DOA6";
parameter DOA5MUX = "DOA5";
parameter DOA4MUX = "DOA4";
parameter DOA3MUX = "DOA3";
parameter DOA2MUX = "DOA2";
parameter DOA1MUX = "DOA1";
parameter DOA0MUX = "DOA0";
parameter CSA2MUX = "CSA2";
parameter CSA1MUX = "CSA1";
parameter CSA0MUX = "CSA0";
parameter CEAMUX = "CEA";
parameter OCEAMUX = "OCEA";
parameter CLKAMUX = "CLKA";
parameter WEAMUX = "WEA";
parameter RSTAMUX = "RSTA";
parameter DIB17MUX = "DIB17";
parameter DIB16MUX = "DIB16";
parameter DIB15MUX = "DIB15";
parameter DIB14MUX = "DIB14";
parameter DIB13MUX = "DIB13";
parameter DIB12MUX = "DIB12";
parameter DIB11MUX = "DIB11";
parameter DIB10MUX = "DIB10";
parameter DIB9MUX = "DIB9";
parameter DIB8MUX = "DIB8";
parameter DIB7MUX = "DIB7";
parameter DIB6MUX = "DIB6";
parameter DIB5MUX = "DIB5";
parameter DIB4MUX = "DIB4";
parameter DIB3MUX = "DIB3";
parameter DIB2MUX = "DIB2";
parameter DIB1MUX = "DIB1";
parameter DIB0MUX = "DIB0";
parameter ADB13MUX = "ADB13";
parameter ADB12MUX = "ADB12";
parameter ADB11MUX = "ADB11";
parameter ADB10MUX = "ADB10";
parameter ADB9MUX = "ADB9";
parameter ADB8MUX = "ADB8";
parameter ADB7MUX = "ADB7";
parameter ADB6MUX = "ADB6";
parameter ADB5MUX = "ADB5";
parameter ADB4MUX = "ADB4";
parameter ADB3MUX = "ADB3";
parameter ADB2MUX = "ADB2";
parameter ADB1MUX = "ADB1";
parameter ADB0MUX = "ADB0";
parameter DOB17MUX = "DOB17";
parameter DOB16MUX = "DOB16";
parameter DOB15MUX = "DOB15";
parameter DOB14MUX = "DOB14";
parameter DOB13MUX = "DOB13";
parameter DOB12MUX = "DOB12";
parameter DOB11MUX = "DOB11";
parameter DOB10MUX = "DOB10";
parameter DOB9MUX = "DOB9";
parameter DOB8MUX = "DOB8";
parameter DOB7MUX = "DOB7";
parameter DOB6MUX = "DOB6";
parameter DOB5MUX = "DOB5";
parameter DOB4MUX = "DOB4";
parameter DOB3MUX = "DOB3";
parameter DOB2MUX = "DOB2";
parameter DOB1MUX = "DOB1";
parameter DOB0MUX = "DOB0";
parameter CSB2MUX = "CSB2";
parameter CSB1MUX = "CSB1";
parameter CSB0MUX = "CSB0";
parameter CEBMUX = "CEB";
parameter OCEBMUX = "OCEB";
parameter CLKBMUX = "CLKB";
parameter WEBMUX = "WEB";
parameter RSTBMUX = "RSTB";
// WID is a RAM ID assigned during the synthesis process, so that
// the bitstream knows what data to load into each block RAM.
parameter WID = 0;
// GSR is whether this block RAM is connected to the global reset
// signal. If "ENABLED", asserting GSR will do the same as asserting
// both RSTA and RSTB. If "DISABLED", asserting GSR does not affect
// the state of this RAM.
parameter GSR = "ENABLED";
// Initial value to load into the RAM at FPGA configuration
// time. Each 20 bit chunk maps to 18 bits of the RAM. The final 2
// bits of each chunk are discarded.
parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
// Style of INITVAL encoding in the bitstream. "STATIC" means the
// initial value is inlined in the bitstream, "DYNAMIC" means the
// initial value is stored separately in the config flash and loaded
// by reference.
//
// This parameter only affects bitstream generation, and as such is
// ignored in this simulation model.
parameter INIT_DATA = "STATIC";
localparam ADDR_WIDTH_A = (DATA_WIDTH_A == 18 ? 10 :
DATA_WIDTH_A == 9 ? 11 :
DATA_WIDTH_A == 4 ? 12 :
DATA_WIDTH_A == 2 ? 13 :
DATA_WIDTH_A == 1 ? 14 : -1);
localparam ADDR_WIDTH_B = (DATA_WIDTH_B == 18 ? 10 :
DATA_WIDTH_B == 9 ? 11 :
DATA_WIDTH_B == 4 ? 12 :
DATA_WIDTH_B == 2 ? 13 :
DATA_WIDTH_B == 1 ? 14 : -1);
localparam ADD_RESET_SYNCHRONIZER = RESETMODE == "ASYNC" && ASYNC_RESET_RELEASE == "SYNC";
//////////////////////////////////////////////////////
// API cleanup
//
// For compatibility with Lattice Diamond, the shape of this
// primitive is pretty terrible: the input and output ports are
// exploded into individual bits, parameters that represent bit
// values are strings that need parsing, etc.
//
// Tidy things up in a separate section, so that the main logic of
// the module is hopefully easier to read. We convert string
// parameters into usable bit values, and reassemble the individual
// bits into ports of the correct widths, with inverters and X
// values inserted as appropriate.
//
// After this section, ADA, DIA, CSA, DOA are ports of the correct
// width, and {CLKA,RSTA,CEA,OCEA,WEA}_val are the single-bit inputs
// with optional inversion applied.
localparam CSADDR_A = ((CSDECODE_A == "0b000") ? 3'b000 :
(CSDECODE_A == "0b001") ? 3'b001 :
(CSDECODE_A == "0b010") ? 3'b010 :
(CSDECODE_A == "0b011") ? 3'b011 :
(CSDECODE_A == "0b100") ? 3'b100 :
(CSDECODE_A == "0b101") ? 3'b101 :
(CSDECODE_A == "0b110") ? 3'b110 :
(CSDECODE_A == "0b111") ? 3'b111 :
3'bxxx);
wire [ADDR_WIDTH_A-1:0] ADA_in = {ADA13, ADA12, ADA11, ADA10, ADA9, ADA8, ADA7,
ADA6, ADA5, ADA4, ADA3, ADA2, ADA1, ADA0};
wire [ADDR_WIDTH_A-1:0] ADA_invert = {ADA13MUX == "INV", ADA12MUX == "INV",
ADA11MUX == "INV", ADA10MUX == "INV",
ADA9MUX == "INV", ADA8MUX == "INV",
ADA7MUX == "INV", ADA6MUX == "INV",
ADA5MUX == "INV", ADA4MUX == "INV",
ADA3MUX == "INV", ADA2MUX == "INV",
ADA1MUX == "INV", ADA0MUX == "INV"};
wire [ADDR_WIDTH_A-1:0] ADA = ADA_in ^ ADA_invert;
wire [DATA_WIDTH_A-1:0] DIA_in = {DIA17, DIA16, DIA15, DIA14, DIA13, DIA12, DIA11, DIA10, DIA9,
DIA8, DIA7, DIA6, DIA5, DIA4, DIA3, DIA2, DIA1, DIA0};
wire [DATA_WIDTH_A-1:0] DIA_invert = {DIA17MUX == "INV", DIA16MUX == "INV", DIA15MUX == "INV",
DIA14MUX == "INV", DIA13MUX == "INV", DIA12MUX == "INV",
DIA11MUX == "INV", DIA10MUX == "INV", DIA9MUX == "INV",
DIA8MUX == "INV", DIA7MUX == "INV", DIA6MUX == "INV",
DIA5MUX == "INV", DIA4MUX == "INV", DIA3MUX == "INV",
DIA2MUX == "INV", DIA1MUX == "INV", DIA0MUX == "INV"};
wire [DATA_WIDTH_A-1:0] DIA = DIA_in ^ DIA_invert;
wire [2:0] CSA_in = {CSA2, CSA1, CSA0};
wire [2:0] CSA_invert = {CSA2MUX == "INV", CSA1MUX == "INV", CSA0MUX == "INV"};
wire [2:0] CSA = CSA_in ^ CSA_invert;
wire [DATA_WIDTH_A-1:0] DOA;
wire [DATA_WIDTH_A-1:0] DOA_invert = {DOA17MUX == "INV", DOA16MUX == "INV", DOA15MUX == "INV",
DOA14MUX == "INV", DOA13MUX == "INV", DOA12MUX == "INV",
DOA11MUX == "INV", DOA10MUX == "INV", DOA9MUX == "INV",
DOA8MUX == "INV", DOA7MUX == "INV", DOA6MUX == "INV",
DOA5MUX == "INV", DOA4MUX == "INV", DOA3MUX == "INV",
DOA2MUX == "INV", DOA1MUX == "INV", DOA0MUX == "INV"};
wire [DATA_WIDTH_A-1:0] DOA_undef = ((DATA_WIDTH_A == 18) ? {18{1'b1}} :
(DATA_WIDTH_A == 9) ? {{9{1'bx}}, {9{1'b1}}} :
(DATA_WIDTH_A == 4) ? {{14{1'bx}}, {4{1'b1}}} :
(DATA_WIDTH_A == 2) ? {{16{1'bx}}, {2{1'b1}}} :
(DATA_WIDTH_A == 1) ? {{17{1'bx}}, 1'b1} :
{18{1'bx}});
wire [DATA_WIDTH_A-1:0] DOA_out = (DOA ^ DOA_invert) & DOA_undef;
assign DOA17 = DOA_out[17]; assign DOA16 = DOA_out[16]; assign DOA15 = DOA_out[15];
assign DOA14 = DOA_out[14]; assign DOA13 = DOA_out[13]; assign DOA12 = DOA_out[12];
assign DOA11 = DOA_out[11]; assign DOA10 = DOA_out[10]; assign DOA9 = DOA_out[9];
assign DOA8 = DOA_out[8]; assign DOA7 = DOA_out[7]; assign DOA6 = DOA_out[6];
assign DOA5 = DOA_out[5]; assign DOA4 = DOA_out[4]; assign DOA3 = DOA_out[3];
assign DOA2 = DOA_out[2]; assign DOA1 = DOA_out[1]; assign DOA0 = DOA_out[0];
wire CLK_A = CLKA ^ (CLKAMUX == "INV");
wire CE_A = CEA ^ (CEAMUX == "INV");
wire OCE_A = OCEA ^ (OCEAMUX == "INV");
wire WE_A = WEA ^ (WEAMUX == "INV");
wire RST_A_IN = RSTA ^ (RSTAMUX == "INV"); // Further modified by reset logic later
localparam CSADDR_B = ((CSDECODE_B == "0b000") ? 3'b000 :
(CSDECODE_B == "0b001") ? 3'b001 :
(CSDECODE_B == "0b010") ? 3'b010 :
(CSDECODE_B == "0b011") ? 3'b011 :
(CSDECODE_B == "0b100") ? 3'b100 :
(CSDECODE_B == "0b101") ? 3'b101 :
(CSDECODE_B == "0b110") ? 3'b110 :
(CSDECODE_B == "0b111") ? 3'b111 :
3'bxxx);
wire [ADDR_WIDTH_B-1:0] ADB_in = {ADB13, ADB12, ADB11, ADB10, ADB9, ADB8, ADB7,
ADB6, ADB5, ADB4, ADB3, ADB2, ADB1, ADB0};
wire [ADDR_WIDTH_B-1:0] ADB_invert = {ADB13MUX == "INV", ADB12MUX == "INV",
ADB11MUX == "INV", ADB10MUX == "INV",
ADB9MUX == "INV", ADB8MUX == "INV",
ADB7MUX == "INV", ADB6MUX == "INV",
ADB5MUX == "INV", ADB4MUX == "INV",
ADB3MUX == "INV", ADB2MUX == "INV",
ADB1MUX == "INV", ADB0MUX == "INV"};
wire [ADDR_WIDTH_B-1:0] ADB = ADB_in ^ ADB_invert;
wire [DATA_WIDTH_B-1:0] DIB_in = {DIB17, DIB16, DIB15, DIB14, DIB13, DIB12, DIB11, DIB10, DIB9,
DIB8, DIB7, DIB6, DIB5, DIB4, DIB3, DIB2, DIB1, DIB0};
wire [DATA_WIDTH_B-1:0] DIB_invert = {DIB17MUX == "INV", DIB16MUX == "INV", DIB15MUX == "INV",
DIB14MUX == "INV", DIB13MUX == "INV", DIB12MUX == "INV",
DIB11MUX == "INV", DIB10MUX == "INV", DIB9MUX == "INV",
DIB8MUX == "INV", DIB7MUX == "INV", DIB6MUX == "INV",
DIB5MUX == "INV", DIB4MUX == "INV", DIB3MUX == "INV",
DIB2MUX == "INV", DIB1MUX == "INV", DIB0MUX == "INV"};
wire [DATA_WIDTH_B-1:0] DIB = DIB_in ^ DIB_invert;
wire [2:0] CSB_in = {CSB2, CSB1, CSB0};
wire [2:0] CSB_invert = {CSB2MUX == "INV", CSB1MUX == "INV", CSB0MUX == "INV"};
wire [2:0] CSB = CSB_in ^ CSB_invert;
wire [DATA_WIDTH_B-1:0] DOB; // Assigned to by main logic, not here.
wire [DATA_WIDTH_B-1:0] DOB_invert = {DOB17MUX == "INV", DOB16MUX == "INV", DOB15MUX == "INV",
DOB14MUX == "INV", DOB13MUX == "INV", DOB12MUX == "INV",
DOB11MUX == "INV", DOB10MUX == "INV", DOB9MUX == "INV",
DOB8MUX == "INV", DOB7MUX == "INV", DOB6MUX == "INV",
DOB5MUX == "INV", DOB4MUX == "INV", DOB3MUX == "INV",
DOB2MUX == "INV", DOB1MUX == "INV", DOB0MUX == "INV"};
wire [DATA_WIDTH_B-1:0] DOB_undef = ((DATA_WIDTH_B == 18) ? {18{1'b1}} :
(DATA_WIDTH_B == 9) ? {{9{1'b1}}, {9{1'b1}}} :
(DATA_WIDTH_B == 4) ? {{14{1'bx}}, {4{1'b1}}} :
(DATA_WIDTH_B == 2) ? {{16{1'bx}}, {2{1'b1}}} :
(DATA_WIDTH_B == 1) ? {{17{1'bx}}, 1'b1} :
{18{1'bx}});
wire [DATA_WIDTH_B-1:0] DOB_out = (DOB ^ DOB_invert) & DOB_undef;
assign DOB17 = DOB_out[17]; assign DOB16 = DOB_out[16]; assign DOB15 = DOB_out[15];
assign DOB14 = DOB_out[14]; assign DOB13 = DOB_out[13]; assign DOB12 = DOB_out[12];
assign DOB11 = DOB_out[11]; assign DOB10 = DOB_out[10]; assign DOB9 = DOB_out[9];
assign DOB8 = DOB_out[8]; assign DOB7 = DOB_out[7]; assign DOB6 = DOB_out[6];
assign DOB5 = DOB_out[5]; assign DOB4 = DOB_out[4]; assign DOB3 = DOB_out[3];
assign DOB2 = DOB_out[2]; assign DOB1 = DOB_out[1]; assign DOB0 = DOB_out[0];
wire CLK_B = CLKB ^ (CLKBMUX == "INV");
wire CE_B = CEB ^ (CEBMUX == "INV");
wire OCE_B = OCEB ^ (OCEBMUX == "INV");
wire WE_B = WEB ^ (WEBMUX == "INV");
wire RST_B_IN = RSTB ^ (RSTBMUX == "INV"); // Further modified by reset logic later
//////////////////////////////////////////////////////
// Reset control
//
// Sync vs. async reset assertion is handled inside sub-RAMs. If
// async assert with sync release was requested, insert a
// synchronizer here.
wire RST_A;
wire RST_B;
if (ADD_RESET_SYNCHRONIZER) begin
reg RSTA_sync_1, RSTA_sync_2;
always @(posedge CLK_A, posedge RST_A_IN) begin
if (RST_A_IN) begin
RSTA_sync_1 <= 1'b1;
RSTA_sync_2 <= 1'b1;
end
else begin
RSTA_sync_1 <= 1'b0;
RSTA_sync_2 <= RSTA_sync_1;
end
end
assign RST_A = RSTA_sync_2;
reg RSTB_sync_1, RSTB_sync_2;
always @(posedge CLK_B, posedge RST_B_IN) begin
if (RST_B_IN) begin
RSTB_sync_1 <= 1'b1;
RSTB_sync_2 <= 1'b1;
end
else begin
RSTB_sync_1 <= 1'b0;
RSTB_sync_2 <= RSTA_sync_1;
end
end
assign RST_B = RSTB_sync_2;
end // if (ADD_RESET_SYNCHRONIZER)
else begin
assign RST_A = RST_A_IN;
assign RST_B = RST_B_IN;
end
//////////////////////////////////////////////////////
// Main logic
//
// Now that we have clean signals, we can build the overall RAM up
// out of simple memories with equal size ports.
// "unreg" is a bit of a misnomer, they are the values of the output
// registers in the elaborated __INTERNAL rams. Those registers
// represent DP16KD's _input_ latches, and thus these signals are
// unregistered outputs.
wire [DATA_WIDTH_A-1:0] DOA_unreg;
wire [DATA_WIDTH_B-1:0] DOB_unreg;
if (DATA_WIDTH_A > DATA_WIDTH_B) begin
DP16KD__DECOMPOSE#(.DATA_WIDTH_A(DATA_WIDTH_B),
.DATA_WIDTH_B(DATA_WIDTH_A),
.RESETMODE(RESETMODE),
.WRITEMODE_A(WRITEMODE_B),
.WRITEMODE_B(WRITEMODE_A)) ram
(.CLKA(CLK_B), .RSTA(RST_B), .CEA(CE_B && CSB == CSADDR_B), .WEA(WE_B), .ADA(ADB), .DIA(DIB), .DOA(DOB_unreg),
.CLKB(CLK_A), .RSTB(RST_A), .CEB(CE_A && CSA == CSADDR_A), .WEB(WE_A), .ADB(ADA), .DIB(DIA), .DOB(DOA_unreg));
end
else begin
DP16KD__DECOMPOSE#(.DATA_WIDTH_A(DATA_WIDTH_A),
.DATA_WIDTH_B(DATA_WIDTH_B),
.RESETMODE(RESETMODE),
.WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B(WRITEMODE_B)) ram
(.CLKA(CLK_A), .RSTA(RST_A), .CEA(CE_A && CSA == CSADDR_A), .WEA(WE_A), .ADA(ADA), .DIA(DIA), .DOA(DOA_unreg),
.CLKB(CLK_B), .RSTB(RST_B), .CEB(CE_B && CSB == CSADDR_B), .WEB(WE_B), .ADB(ADB), .DIB(DIB), .DOB(DOB_unreg));
end
//////////////////////////////////////////////////////
// Output mapping
if (REGMODE_A == "OUTREG") begin
reg [DATA_WIDTH_A-1:0] DOA_reg;
always @(posedge CLK_A) begin
if (OCE_A)
DOA_reg <= DOA_unreg;
end
assign DOA = DOA_reg;
end
else begin
assign DOA = DOA_unreg;
end
if (REGMODE_B == "OUTREG") begin
reg [DATA_WIDTH_B-1:0] DOB_reg;
always @(posedge CLK_B) begin
if (OCE_B)
DOB_reg <= DOB_unreg;
end
assign DOB = DOB_reg;
end
else begin
assign DOB = DOB_unreg;
end
endmodule