sim: implementation of a simulation model DP16KD
Not fully verified with tests yet, WIP
This commit is contained in:
parent
e57f7e05b0
commit
0b384c6619
|
@ -0,0 +1,798 @@
|
|||
// 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
|
|
@ -0,0 +1,106 @@
|
|||
module tb_DP16KD_18b_sync_nowriteout_unregistered();
|
||||
reg CLKA=0, RSTA=0, CEA=0, OCEA=0, WEA=0;
|
||||
reg CLKB=0, RSTB=0, CEB=0, OCEB=0, WEB=0;
|
||||
reg [2:0] CSA=0, CSB=0;
|
||||
reg [13:0] ADA, ADB;
|
||||
reg [17:0] DIA, DIB;
|
||||
wire [17:0] DOA, DOB;
|
||||
reg [239:0] TESTNAME;
|
||||
|
||||
DP16KD ram(.CLKA(CLKA), .RSTA(RSTA), .CEA(CEA), .OCEA(OCEA), .WEA(WEA),
|
||||
.CSA2(CSA[2]), .CSA1(CSA[1]), .CSA0(CSA[0]),
|
||||
.ADA13(ADA[13]), .ADA12(ADA[12]), .ADA11(ADA[11]), .ADA10(ADA[10]), .ADA9(ADA[9]), .ADA8(ADA[8]), .ADA7(ADA[7]), .ADA6(ADA[6]), .ADA5(ADA[5]), .ADA4(ADA[4]), .ADA3(ADA[3]), .ADA2(ADA[2]), .ADA1(ADA[1]), .ADA0(ADA[0]),
|
||||
.DIA17(DIA[17]), .DIA16(DIA[16]), .DIA15(DIA[15]), .DIA14(DIA[14]), .DIA13(DIA[13]), .DIA12(DIA[12]), .DIA11(DIA[11]), .DIA10(DIA[10]), .DIA9(DIA[9]), .DIA8(DIA[8]), .DIA7(DIA[7]), .DIA6(DIA[6]), .DIA5(DIA[5]), .DIA4(DIA[4]), .DIA3(DIA[3]), .DIA2(DIA[2]), .DIA1(DIA[1]), .DIA0(DIA[0]),
|
||||
.DOA17(DOA[17]), .DOA16(DOA[16]), .DOA15(DOA[15]), .DOA14(DOA[14]), .DOA13(DOA[13]), .DOA12(DOA[12]), .DOA11(DOA[11]), .DOA10(DOA[10]), .DOA9(DOA[9]), .DOA8(DOA[8]), .DOA7(DOA[7]), .DOA6(DOA[6]), .DOA5(DOA[5]), .DOA4(DOA[4]), .DOA3(DOA[3]), .DOA2(DOA[2]), .DOA1(DOA[1]), .DOA0(DOA[0]),
|
||||
|
||||
.CLKB(CLKB), .RSTB(RSTB), .CEB(CEB), .OCEB(OCEB), .WEB(WEB),
|
||||
.CSB2(CSB[2]), .CSB1(CSB[1]), .CSB0(CSB[0]),
|
||||
.ADB13(ADB[13]), .ADB12(ADB[12]), .ADB11(ADB[11]), .ADB10(ADB[10]), .ADB9(ADB[9]), .ADB8(ADB[8]), .ADB7(ADB[7]), .ADB6(ADB[6]), .ADB5(ADB[5]), .ADB4(ADB[4]), .ADB3(ADB[3]), .ADB2(ADB[2]), .ADB1(ADB[1]), .ADB0(ADB[0]),
|
||||
.DIB17(DIB[17]), .DIB16(DIB[16]), .DIB15(DIB[15]), .DIB14(DIB[14]), .DIB13(DIB[13]), .DIB12(DIB[12]), .DIB11(DIB[11]), .DIB10(DIB[10]), .DIB9(DIB[9]), .DIB8(DIB[8]), .DIB7(DIB[7]), .DIB6(DIB[6]), .DIB5(DIB[5]), .DIB4(DIB[4]), .DIB3(DIB[3]), .DIB2(DIB[2]), .DIB1(DIB[1]), .DIB0(DIB[0]),
|
||||
.DOB17(DOB[17]), .DOB16(DOB[16]), .DOB15(DOB[15]), .DOB14(DOB[14]), .DOB13(DOB[13]), .DOB12(DOB[12]), .DOB11(DOB[11]), .DOB10(DOB[10]), .DOB9(DOB[9]), .DOB8(DOB[8]), .DOB7(DOB[7]), .DOB6(DOB[6]), .DOB5(DOB[5]), .DOB4(DOB[4]), .DOB3(DOB[3]), .DOB2(DOB[2]), .DOB1(DOB[1]), .DOB0(DOB[0]));
|
||||
|
||||
always begin
|
||||
#5
|
||||
CLKA <= !CLKA;
|
||||
CLKB <= !CLKB;
|
||||
end
|
||||
|
||||
initial begin
|
||||
$dumpfile("tb_DP16KD_18b_sync_nowriteout_unregistered");
|
||||
$dumpvars(0, tb_DP16KD_18b_sync_nowriteout_unregistered);
|
||||
#10
|
||||
// Write to lowest and highest addrs, read back from the other port.
|
||||
TESTNAME="SIMPLE WRITE/READ 1";
|
||||
ADA=0; DIA=42; CEA=1; WEA=1; // Write min addr
|
||||
ADB=1023; DIB=18'h3FFFF; CEB=1; WEB=1; // write max addr
|
||||
#10
|
||||
ADA=1023; DIA=0; CEA=1; WEA=0; // Read max addr
|
||||
ADB=0; DIB=0; CEB=1; WEB=0; // Read min addr
|
||||
#10
|
||||
// Swap values around, read back from other port.
|
||||
TESTNAME="SIMPLE WRITE/READ 2";
|
||||
ADA=1023; DIA=42; CEA=1; WEA=1; // Write max addr
|
||||
ADB=0; DIB=18'h3FFFF; CEB=1; WEB=1; // Write min addr
|
||||
#10
|
||||
ADA=0; DIA=0; CEA=1; WEA=0; // Read min addr
|
||||
ADB=1023; DIB=0; CEB=1; WEB=0; // Read max addr
|
||||
#10
|
||||
// No change when reading and not enabled
|
||||
TESTNAME="NOT ENABLED";
|
||||
ADA=1023; DIA=0; CEA=0; WEA=0;
|
||||
ADB=0; DIA=0; CEB=0; WEB=0;
|
||||
#10
|
||||
// Output changes again with chip enabled
|
||||
CEA=1;
|
||||
CEB=1;
|
||||
#10
|
||||
// Same if another chip is selected
|
||||
TESTNAME="NOT SELECTED";
|
||||
ADA=1023; DIA=0; WEA=0; CSA=3;
|
||||
ADB=0; DIB=0; WEB=0; CSB=2;
|
||||
#10
|
||||
// Output changes again with chip enabled
|
||||
CSA=0;
|
||||
CSB=0;
|
||||
#10
|
||||
// Reset clears regs, overrules input, doesn't affect other port,
|
||||
// doesn't affect memory contents.
|
||||
TESTNAME="RESET A";
|
||||
ADA=0; RSTA=1;
|
||||
#10
|
||||
RSTA=0;
|
||||
#10
|
||||
TESTNAME="RESET B";
|
||||
ADB=1023; RSTB=1;
|
||||
#10
|
||||
RSTB=0;
|
||||
#10
|
||||
// Write-write conflict writes undef value
|
||||
TESTNAME="WRITE/WRITE CONFLICT";
|
||||
ADA=0; DIA=0; WEA=1;
|
||||
ADB=0; DIB=18'h3FFFF; WEB=1;
|
||||
#10
|
||||
WEA=0;
|
||||
WEB=0;
|
||||
#10
|
||||
// Write-write conflict writes undef value
|
||||
TESTNAME="A READ/B WRITE CONFLICT";
|
||||
ADA=0; DIA=0; WEA=0;
|
||||
ADB=0; DIB=18'h3FFFF; WEB=1;
|
||||
#10
|
||||
WEA=0;
|
||||
WEB=0;
|
||||
#10
|
||||
// Write-write conflict writes undef value
|
||||
TESTNAME="A WRITE/B READ CONFLICT";
|
||||
ADA=0; DIA=0; WEA=1;
|
||||
ADB=0; DIB=18'h3FFFF; WEB=0;
|
||||
#10
|
||||
WEA=0;
|
||||
WEB=0;
|
||||
#10
|
||||
TESTNAME=240'bx;
|
||||
#10
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue