如何将 FSM 与 BRAM 结合?

问题描述 投票:0回答:1

我的项目如下:我想首先将通过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

现在,这是我的问题:

  1. 您认为这段代码有什么问题吗?我是否正确地将 FSM 与 BRAM 结合起来?
  2. 我不想直接将BRAM中的值发送到UART,但我想对其进行特定的操作。我可以在像
    dout
    这样分配给
    dout <= img[addrb] >> 1
    变量时直接执行此操作吗?或者将其分配给 dout 并在 FSM 中执行此操作会更合适吗?
  3. 我查看了Vivado的示例代码,但是没有任何东西可以在不使用输出寄存器时重置输出数据。这就是为什么我决定在未启用读取操作时让它进入高阻抗。你认为这是正确的吗?如何在按下重置按钮时重置输出数据?
system-verilog fpga xilinx vivado fsm
1个回答
0
投票
  1. 验证代码的行为建议编写一个测试平台来验证代码的行为是否符合预期。如果没有,则将测试平台作为最小可重现示例的一部分添加到您的帖子中,并解释问题。

  2. 此语句

    dout <= img[addrb] >> 1
    对于右移 1 是有效的 Verilog。如果这就是您想要的,请使用它。

  3. 您不应该关心重置内存输出。从断言 read_en 到出现有效数据,应该有一个已知的(可能是 1 clk,需要查看模拟)延迟。在下游 RTL 模型中使用相同的读取启用捕获从 RAM 读取的数据(使用 read_en 作为下游有效数据)您还可以执行其他操作,例如使用 $readmemh() 的内存初始化文件,但不应该这样做必要的,除非您有一些有意义的模式(例如滤波器系数)来初始化 RAM。

© www.soinside.com 2019 - 2024. All rights reserved.