799 lines
37 KiB
Verilog
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
|