Xilinx:Reading 来自 BRAM
Xilinx:Reading from BRAM
我已经尝试在下面编写一个最小的、完整的和可验证的示例。
我想将10个值写入BRAM(单端口Block RAM)的前10个地址,然后读取这些值。检查结果后,我发现
- 写操作前10个地址没有变化。
- 读取时,输出在 3 个时钟周期后发生变化,并在 'address' 信号停止变化时保持不变。
您能否解释一下这种行为以及如何获得所需的结果(在 10 个地址中写入 10 个值)。我对解决第二个问题(读取前 10 个地址的值)更感兴趣。
下面是我的 verilog 测试平台和波导的快照。
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
- 灰线是写操作开始的地方。
蓝线是读取操作开始的地方。
BLOCK_MEM是Xilinx生成的IP-CORE
我将对您如何配置 BRAM 进行一些猜测(我使用 Vivado 2015.4 和 http://www.xilinx.com/support/documentation/ip_documentation/blk_mem_gen/v8_3/pg058-blk-mem-gen.pdf 作为参考)。看起来您选择了始终启用(因为 ENA 信号不存在)、32 位数据和 32 位地址接口。请注意,如果您使用 32 位地址接口,则 WEA 从 1 位信号变为 4 位信号。这是为了允许字节寻址写入。
鉴于此,我们知道对于 0b0001
的 wea
,只会写入最低有效字节。此外,根据上述指南第 46 页的时序图,我们知道我们可以预期写入的数据在 douta
上写入后可用。我们可以在您的第一张图像上验证这一点 - 例如,在 200ns,douta = 0xfff75c13
,0x13
字节来自前一个时钟边沿的 dina
(其他字节是之前的在内存中)。因此,这证实了写入正在按预期工作。
至于图二中的读数,如果您再次计算,您会看到 douta
每 4 个时钟周期发生变化。同样,请记住内存是按字节寻址的,但您返回的是 4 个字节,因此地址的最低两位将被忽略 (address 0x07 == 0x06 == 0x05 == 0x04
)。
简而言之,BRAM 正在按预期工作,这可能不是您预期的方式。要移动到内存中的下一个 32-bit/4-byte 字,您需要将地址递增 4,而不是递增 1。要写入整个字,(不仅仅是最低字节)设置 wea='b1111
.
我已经尝试在下面编写一个最小的、完整的和可验证的示例。
我想将10个值写入BRAM(单端口Block RAM)的前10个地址,然后读取这些值。检查结果后,我发现
- 写操作前10个地址没有变化。
- 读取时,输出在 3 个时钟周期后发生变化,并在 'address' 信号停止变化时保持不变。
您能否解释一下这种行为以及如何获得所需的结果(在 10 个地址中写入 10 个值)。我对解决第二个问题(读取前 10 个地址的值)更感兴趣。
下面是我的 verilog 测试平台和波导的快照。
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
BLOCK_MEM是Xilinx生成的IP-CORE
我将对您如何配置 BRAM 进行一些猜测(我使用 Vivado 2015.4 和 http://www.xilinx.com/support/documentation/ip_documentation/blk_mem_gen/v8_3/pg058-blk-mem-gen.pdf 作为参考)。看起来您选择了始终启用(因为 ENA 信号不存在)、32 位数据和 32 位地址接口。请注意,如果您使用 32 位地址接口,则 WEA 从 1 位信号变为 4 位信号。这是为了允许字节寻址写入。
鉴于此,我们知道对于 0b0001
的 wea
,只会写入最低有效字节。此外,根据上述指南第 46 页的时序图,我们知道我们可以预期写入的数据在 douta
上写入后可用。我们可以在您的第一张图像上验证这一点 - 例如,在 200ns,douta = 0xfff75c13
,0x13
字节来自前一个时钟边沿的 dina
(其他字节是之前的在内存中)。因此,这证实了写入正在按预期工作。
至于图二中的读数,如果您再次计算,您会看到 douta
每 4 个时钟周期发生变化。同样,请记住内存是按字节寻址的,但您返回的是 4 个字节,因此地址的最低两位将被忽略 (address 0x07 == 0x06 == 0x05 == 0x04
)。
简而言之,BRAM 正在按预期工作,这可能不是您预期的方式。要移动到内存中的下一个 32-bit/4-byte 字,您需要将地址递增 4,而不是递增 1。要写入整个字,(不仅仅是最低字节)设置 wea='b1111
.