// 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_sim #(
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)
parameter FNUM = 8
)(
input [FNUM-1:0] load_files, input [512*8-1:0] init_files[FNUM-1:0], 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
);
test_write_mem test_write_mem_inst();
// reg [(NB_COL*COL_WIDTH)-1:0] BRAM [RAM_DEPTH-1:0]; logic [(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 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}}; endgenerate
genvar KK; integer fid [FNUM-1:0]; int faddr [FNUM-1:0]; logic[ ( (NB_COL*COL_WIDTH)/32 + ((NB_COL*COL_WIDTH)%32 != 0)) * 32 -1 :0] fdata; logic Fbram [RAM_DEPTH-1:0][0:( (NB_COL*COL_WIDTH)/32 + ((NB_COL*COL_WIDTH)%32 != 0))-1]; int ii [FNUM-1:0]; generate
for(KK=0;KK<FNUM;KK++)begin always@(posedge load_files[KK])begin $readmemh(init_files[KK], BRAM, 0, RAM_DEPTH-1); // $readmemh(init_files[KK], Fbram, 0, RAM_DEPTH-1); // for(ii[KK]=0;ii[KK]<RAM_DEPTH;ii[KK]++)begin // fdata = {>>{Fbram[ii[KK]][0:( (NB_COL*COL_WIDTH)/32 + ((NB_COL*COL_WIDTH)%32 != 0))-1]}}; // BRAM[ii[KK]] = fdata[0 +: (NB_COL*COL_WIDTH)]; // end // fid[KK] = $fopen(init_files[KK],"r"); // if(fid[KK] != 0)begin // for(ii[KK]=0;ii[KK]<RAM_DEPTH;ii[KK]++)begin // if($feof(fid[KK]))begin // $display("EOF<%0d>:%0s\n",ii[KK],init_files[KK]); // $fclose(fid[KK]); // break; // end // $fscanf(fid[KK],"@%h %16h\n",faddr[KK],fdata[KK]); // // $display("SCAN DONE<%0d>:%0s\n",ii[KK],init_files[KK]); // // $fclose(fid[KK]); // // break; // BRAM[faddr[KK]] = fdata[KK]; // end // end end 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 );
*/