I have attemted to write a Minimal, Complete, and Verifiable example below.
I want to write 10 values to the first 10 addresses of the BRAM (single port Block RAM) and then read the values. After inspecting the results I find that
Can you give an explanation to this behaviour and how to get the desired result (write 10 values in the 10 addresses). I'm more interested in solving the second problem (reading the values from the first 10 addresses).
Below is my verilog testbench and snapshot of the waveguide.
module BRAM_tb;
// Inputs
reg clk;
reg [3:0] wea; // write enable signal
reg [31:0] addra; // address
reg signed [31:0] dina; // data in
// Outputs
wire [31:0] douta; // data out
// Instantiate the Unit Under Test (UUT)
BLOCK_MEM uut (
.clka(clk),
.wea(wea),
.addra(addra),
.dina(dina),
.douta(douta)
);
always begin
#15 clk =~clk;
end
task writeStuff; //write to address
begin
addra <= addra + 1;
dina <= dina+1;
end
endtask
task readStuff; // read the at address
begin
addra <= addra + 1;
end
endtask
reg [1:0] writing;
integer counter;
initial begin
// Initialize Inputs
clk = 0;
addra = 0;
dina = 16;
counter = 0;
writing = 2'b10; //idle state
// Wait 100 ns for global reset to finish
#100;
wea <= 1;
writing <=1;
end
always @(posedge clk)begin
case(writing)
1: if(counter<10) begin
writeStuff;
counter <=counter+1;
end else begin
writing <=0; // change state to reading
counter <=0;
addra <= 0;
wea <=0; // stop writing
end
0: if(counter<10) begin
readStuff;
counter <=counter+1;
end else begin // change addra to zero and do nothing
addra <= 0;
writing <=2'b10; //goto idle state
end
2: if(1) begin
//do nothing
end
endcase
end
- The gray line is where the write operation begins. The blue line is where the read operation begins.
BLOCK_MEM is an IP-CORE that is generated by Xilinx.
I'm going to take some guesses as to how you've configured your BRAM (I'm using Vivado 2015.4 and http://www.xilinx.com/support/documentation/ip_documentation/blk_mem_gen/v8_3/pg058-blk-mem-gen.pdf as references). Looks like you've opted for the always-enable (since the ENA signal isn't present), 32-bit data, and the 32-bit address interface. Note that if you use the 32-bit address interface, WEA changes from a 1-bit signal to a 4-bit signal. This is to allow for byte-addressable writes.
Given this, we know that for a wea
of 0b0001
, only the least-significant byte will be written. Also, from the timing diagram on pg 46 of the above guide, we know we can expect the written data to be available after the write on douta
. We can verify this on your first image - for example, at 200ns, douta = 0xfff75c13
, with the 0x13
byte having come from dina
on the previous clock edge (the other bytes are what was previously in the memory). So, this confirms the writes are working as expected.
As for the reads in image two, if you count again, you'll see that douta
changes every 4 clock cycles. Again, remember that the memory is addressed per byte, but you're returning 4 bytes, so the lowest two bits of the address are ignored (address 0x07 == 0x06 == 0x05 == 0x04
).
In short, the BRAM is working as intended, which might not be the way you expected. To move to the next 32-bit/4-byte word in memory, you need to increment the address by 4, not by 1. To write the whole word, (not just the lowest byte) set wea='b1111
.