// Xilinx True Dual Port RAM Byte Write, Write First Dual Clock
RAM // This code implements a parameterizable true dual port memory (both ports can read and write). // The behavior of this RAM is when data is written, the new memory contents at the write // address are presented on the output port. `include “define_macro.sv” module xilinx_hdl_dpram #(
parameter NB_COL = 4, // Specify number of columns (number of bytes) parameter COL_WIDTH = 9, // Specify column width (byte width, typically 8 or 9) parameter RAM_DEPTH = 1024, // Specify RAM depth (number of entries) `parameter_longstring(512) RAM_PERFORMANCE = "HIGH_PERFORMANCE", // Select "HIGH_PERFORMANCE" or "LOW_LATENCY" parameter INIT_FILE = "" // Specify name/location of RAM initialization file if using one (leave blank if not)
) (
input [$clog2(RAM_DEPTH)-1:0] addra, // Port A address bus, width determined from RAM_DEPTH input [$clog2(RAM_DEPTH)-1:0] addrb, // Port B address bus, width determined from RAM_DEPTH input [(NB_COL*COL_WIDTH)-1:0] dina, // Port A RAM input data input [(NB_COL*COL_WIDTH)-1:0] dinb, // Port B RAM input data input clka, // Port A clock input clkb, // Port B clock input [NB_COL-1:0] wea, // Port A write enable input [NB_COL-1:0] web, // Port B write enable input ena, // Port A RAM Enable, for additional power savings, disable BRAM when not in use input enb, // Port B RAM Enable, for additional power savings, disable BRAM when not in use input rsta, // Port A output reset (does not affect memory contents) input rstb, // Port B output reset (does not affect memory contents) input regcea, // Port A output register enable input regceb, // Port B output register enable output [(NB_COL*COL_WIDTH)-1:0] douta, // Port A RAM output data output [(NB_COL*COL_WIDTH)-1:0] doutb // Port B RAM output data
);
// reg [(NB_COL*COL_WIDTH)-1:0] BRAM [RAM_DEPTH-1:0]; bit [(NB_COL*COL_WIDTH)-1:0] BRAM [RAM_DEPTH-1:0]; reg [(NB_COL*COL_WIDTH)-1:0] ram_data_a = {(NB_COL*COL_WIDTH){1'b0}}; reg [(NB_COL*COL_WIDTH)-1:0] ram_data_b = {(NB_COL*COL_WIDTH){1'b0}}; // The following code either initializes the memory values to a specified file or to all zeros to match hardware generate if (INIT_FILE != "") begin: use_init_file initial $readmemh(INIT_FILE, BRAM, 0, RAM_DEPTH-1); end else begin: init_bram_to_zero integer ram_index; initial for (ram_index = 0; ram_index < RAM_DEPTH; ram_index = ram_index + 1) BRAM[ram_index] = {(NB_COL*COL_WIDTH){1'b0}}; end endgenerate generate genvar i; for (i = 0; i < NB_COL; i = i+1) begin: byte_write always @(posedge clka) if (ena) if (wea[i]) begin BRAM[addra][(i+1)*COL_WIDTH-1:i*COL_WIDTH] <= dina[(i+1)*COL_WIDTH-1:i*COL_WIDTH]; ram_data_a[(i+1)*COL_WIDTH-1:i*COL_WIDTH] <= dina[(i+1)*COL_WIDTH-1:i*COL_WIDTH]; end else begin ram_data_a[(i+1)*COL_WIDTH-1:i*COL_WIDTH] <= BRAM[addra][(i+1)*COL_WIDTH-1:i*COL_WIDTH]; end always @(posedge clkb) if (enb) if (web[i]) begin BRAM[addrb][(i+1)*COL_WIDTH-1:i*COL_WIDTH] <= dinb[(i+1)*COL_WIDTH-1:i*COL_WIDTH]; ram_data_b[(i+1)*COL_WIDTH-1:i*COL_WIDTH] <= dinb[(i+1)*COL_WIDTH-1:i*COL_WIDTH]; end else begin ram_data_b[(i+1)*COL_WIDTH-1:i*COL_WIDTH] <= BRAM[addrb][(i+1)*COL_WIDTH-1:i*COL_WIDTH]; end end endgenerate // The following code generates HIGH_PERFORMANCE (use output register) or LOW_LATENCY (no output register) generate if (RAM_PERFORMANCE == "LOW_LATENCY") begin: no_output_register // The following is a 1 clock cycle read latency at the cost of a longer clock-to-out timing assign douta = ram_data_a; assign doutb = ram_data_b; end else begin: output_register // The following is a 2 clock cycle read latency with improve clock-to-out timing reg [(NB_COL*COL_WIDTH)-1:0] douta_reg = {(NB_COL*COL_WIDTH){1'b0}}; reg [(NB_COL*COL_WIDTH)-1:0] doutb_reg = {(NB_COL*COL_WIDTH){1'b0}}; always @(posedge clka) if (rsta) douta_reg <= {(NB_COL*COL_WIDTH){1'b0}}; else if (regcea) douta_reg <= ram_data_a; always @(posedge clkb) if (rstb) doutb_reg <= {(NB_COL*COL_WIDTH){1'b0}}; else if (regceb) doutb_reg <= ram_data_b; assign douta = douta_reg; assign doutb = doutb_reg; end endgenerate // The following function calculates the address width based on specified RAM depth // function integer clogb2; // input integer depth; // for (clogb2=0; depth>0; clogb2=clogb2+1) // depth = depth >> 1; // endfunction
endmodule
// The following is an instantiation template for xilinx_true_dual_port_write_first_byte_write_2_clock_ram /*
// Xilinx True Dual Port RAM Byte Write Write-First Dual Clock RAM xilinx_true_dual_port_write_first_byte_write_2_clock_ram #( .NB_COL(4), // Specify number of columns (number of bytes) .COL_WIDTH(9), // Specify column width (byte width, typically 8 or 9) .RAM_DEPTH(1024), // Specify RAM depth (number of entries) .RAM_PERFORMANCE("HIGH_PERFORMANCE"), // Select "HIGH_PERFORMANCE" or "LOW_LATENCY" .INIT_FILE("") // Specify name/location of RAM initialization file if using one (leave blank if not) ) your_instance_name ( .addra(addra), // Port A address bus, width determined from RAM_DEPTH .addrb(addrb), // Port B address bus, width determined from RAM_DEPTH .dina(dina), // Port A RAM input data, width determined from NB_COL*COL_WIDTH .dinb(dinb), // Port B RAM input data, width determined from NB_COL*COL_WIDTH .clka(clka), // Port A clock .clkb(clkb), // Port B clock .wea(wea), // Port A write enable, width determined from NB_COL .web(web), // Port B write enable, width determined from NB_COL .ena(ena), // Port A RAM Enable, for additional power savings, disable port when not in use .enb(enb), // Port B RAM Enable, for additional power savings, disable port when not in use .rsta(rsta), // Port A output reset (does not affect memory contents) .rstb(rstb), // Port B output reset (does not affect memory contents) .regcea(regcea), // Port A output register enable .regceb(regceb), // Port B output register enable .douta(douta), // Port A RAM output data, width determined from NB_COL*COL_WIDTH .doutb(doutb) // Port B RAM output data, width determined from NB_COL*COL_WIDTH );
*/