我的项目如下:我想首先将通过UART传入的像素值保存到BRAM,然后将它们传递给图像处理过滤器,并通过UART将它们发送回。目前,我希望这个过滤器不用作图像处理过滤器,而是用于右移。也就是说,我希望它将传入的像素值除以 2 并将它们发送回来。我设法在不使用 BRAM 的情况下运行它。然而,当涉及到 BRAM 时,我不确定我的 FSM(有限状态机)和 BRAM 是否可以正常工作。
我通过阅读 Vivado Design Suite 用户指南综合创建了一个简单的双端口 BRAM。主要区别是使用单独的
always
块来写入和读取 BRAM。所以,我也做了同样的事情。
module imfilter
#(parameter D_BITS = 8, // RAM WIDTH
N = 400) // RAM DEPTH
(
input logic i_clk,
input logic reset,
//(*DONT_TOUCH = "true"*)
input logic [31:0] bleng, //byte length of array
input logic [D_BITS - 1:0] i_data,
input logic i_valid, // write en signal
input logic i_rdy, // read en signal
output logic [D_BITS - 1:0] o_data,
output logic o_send
);
localparam RAM_PERFORMANCE = "LOW_LATENCY"; // Select "HIGH_PERFORMANCE" or "LOW_LATENCY"
localparam INIT_FILE = "";
typedef enum logic [1:0] {
IDLE = 2'b00,
SAVE2MEM = 2'b01,
SEND = 2'b10
//STOP = 2'b10
} state_t;
/*(*DONT_TOUCH = "true"*)*/ //(* ram_style = "block" *)
logic [D_BITS - 1:0] img [0:N - 1];
logic [D_BITS - 1:0] img_data, dout;
logic [$clog2(N) - 1:0] addra = 0; // write address index
logic [$clog2(N) - 1:0] addrb = 0; // read address index
//(*DONT_TOUCH = "true"*)
state_t state_reg;
always_ff @(posedge i_clk) begin
if (i_valid) begin
img[addra] <= i_data; end
if(i_rdy) begin
dout <= img[addrb]; end
end
always_ff @(posedge i_clk) begin
if(reset) begin
state_reg <= SAVE2MEM;
o_send <= 0;;
addra <= 0;
addrb <= 0;
end else begin
o_send <= 0;
case(state_reg)
IDLE: begin
if(bleng) begin
state_reg <= SAVE2MEM; end
end
SAVE2MEM: begin
if(i_valid) begin
addra <= addra + 1;
if(addra == bleng - 1) begin
addra <= 0;
state_reg <= SEND; end
end
end
SEND: begin
if(i_rdy) begin
o_send <= 1;
addrb <= addrb + 1;
if(addrb == bleng - 1) begin
state_reg <= IDLE;
addrb <= 0; end
end else begin
o_send <= 0; end
end
default: begin
state_reg <= IDLE;
end
endcase end
end
assign o_data = (i_rdy)? dout : {D_BITS{1'bz}};
endmodule
现在,这是我的问题:
dout
这样分配给dout <= img[addrb] >> 1
变量时直接执行此操作吗?或者将其分配给 dout 并在 FSM 中执行此操作会更合适吗?验证代码的行为建议编写一个测试平台来验证代码的行为是否符合预期。如果没有,则将测试平台作为最小可重现示例的一部分添加到您的帖子中,并解释问题。
此语句
dout <= img[addrb] >> 1
对于右移 1 是有效的 Verilog。如果这就是您想要的,请使用它。
您不应该关心重置内存输出。从断言 read_en 到出现有效数据,应该有一个已知的(可能是 1 clk,需要查看模拟)延迟。在下游 RTL 模型中使用相同的读取启用捕获从 RAM 读取的数据(使用 read_en 作为下游有效数据)您还可以执行其他操作,例如使用 $readmemh() 的内存初始化文件,但不应该这样做必要的,除非您有一些有意义的模式(例如滤波器系数)来初始化 RAM。