Reputation: 33
I am trying to understand how writing and reading take place in BRAM memory under certain controlling situations. Please tell me if there is any conceptual mistake in my code:
module bram_dual(wrt_data,addr_w,rst,clk,wr_en,read_data,rd_en);
input [17:0]wrt_data;
input clk,rst,wr_en;
input [4:0]addr_w;
output [17:0]read_data;
output rd_en;
reg [17:0]ram[0:23];
integer i;
always@(posedge clk) begin
if(rst)begin
for (i=0;i<23;i=i+1)begin
ram[i]<={24{1'b0}};
end
end
else
if(wr_en) begin
ram[addr_w]<=wrt_data;
end
end
assign read_data=rd_en ? ram[addr_w]:0;
endmodule
TESTBENCH :
module tb_bram;
reg [17:0]wrt_data;
reg clk,rst,wr_en;
reg [4:0]addr_w;
wire [17:0]read_data;
wire rd_en;
integer j;
bram_dual dut1 (.wrt_data(wrt_data),
.clk(clk),
.rst(rst),
.wr_en(wr_en),
.addr_w(addr_w),
.read_data(read_data),
.rd_en(rd_en)
);
initial begin
rst<=1;
clk<=0;
#20;
rst <=0;
end
always@(posedge clk) begin
if (rst) begin
wr_en<=0;
wrt_data<=0;
addr_w<=0;
end
else begin
if (wr_en) begin
for (j=0;j<23;j=j+1) begin
wrt_data<=j;
addr_w<=j;
end
end
else begin
wrt_data<=0;
end
end
end
always #10 clk=~clk;
endmodule
I have questions related to writing data into bram memroy and reading data from bram memory.
Can I use two signals for writing data into bram and reading data from bram?
Like during writing operation: writing data into bram through this signal -> write_enable , address_write
reading operation : read_enable , address_read
Can I use individual enable signal for write and read operation? similarly, can we also do for address?
Theoretically I knew I can, but logically when I try to do it in Verilog coding, I am failed to do it.
Upvotes: 0
Views: 2447
Reputation: 499
always@(posedge clk) begin
if(wr_en) ram[addr_w]<=wrt_data;
if (rd_en) read_data <= ram[addr_w];
end
That's it, that's your BRAM, you should look into the synthesis results to see the tool has inferred the memory as BRAM. If the tool doesn't recognize this as BRAM, you can instruct the tool using a primitive in verilog whille declaring the RAM register, like this:
(* ram_style = "bram" *) reg [data_size-1:0] myram [2**addr_size-1:0];
Much more details here: https://docs.xilinx.com/r/en-US/ug901-vivado-synthesis/Single-Port-RAM-with-Read-First-VHDL
NOTE: Memories do not have reset pins. If you want a memory with reset, use registers.
Upvotes: 0
Reputation: 2510
This answer is supplemental to the answer provided by @toolic, and pertains to the inference of block memory in an RTL synthesis flow. I am adding this because the question title contained the term 'bram' which usually means block ram, and uses the Xilinx tag which is physical hardware.
Block ram is a specific type of memory found in many physical FPGA devices.
Block ram's do not have reset pins (they do not provide any way to clear the RAM contents using an input pin).
This bit of code models a reset using a reset input (a reset pin), therefore a block ram will not be inferred by this code.
if(rst)begin
for (i=0;i<23;i=i+1)begin
ram[i]<={24{1'b0}};
end
The posted code containing this snip, models memory very generally, however it will be composed of registers and combinational logic not block ram. This structure is referred to as a register file rather than a memory. The read side is just a mux of all the registers in this case.
To correctly model and infer block ram in FPGA synthesis with initial values, remove or comment the if(rst)
block and use
initial
$readmemh("file_with_initial_values.txt",ram);
to initialize memory based on the contents of the file specified as an argument to the system task. This is a one time only initialization of the bram, which occurs (WRT time) near the end of the physical devices configuration which usually happens when the board hosting the fpga is first powered on. The task $readmemh() is described in the SystemVerilog standard
IEEE SV 1800-2017 section 21.4 Loading memory array data from a file.
Alternately, if you need to write hard coded values (like 0) dynamically triggered by a reset input, and want block ram, then comment or remove the reset block, and design a state machine (SM) controller which generates as many synchronous write transactions as needed to write the values to each location, when the reset input is asserted. Note that it takes n clocks to perform n writes (its not a single clock operation). In your case this would involve the SM clocking in 24 0's into the data, while the write enable is held active, and incrementing the address 23 times, starting at 0, when the reset input goes true. After the SM finishes return the write data, write enable, and write address to their normal behavior.
Chapter 4 of this Xilinx document UG901 Synthesis Guide contains coding style recommendations for modeling memories including coding style for block ram inference. There are several examples which can be cut and paste then customized according to contextual needs.
Upvotes: -1