Search code examples
veriloghdl

Verilog - Getting immediate response from external memory


I'm trying to write a Verilog module which iterates over elements of an external memory in each cycle. The problem I'm facing right now, is that changing the address of the memory during the cycle will not cause the input data be changed, in that same cycle.i.e: changing the address will not cause the input data to be changed in one cycle.I'll illustrate the problem with some code:

module r(input rst, ..., output reg [MEMORY_ADDR_WIDTH-1:0] addr, input memory_value);

//...
always @(posedge clk) begin
    //...
    for(addr = 0; addr < MEMORY_SIZE; addr = addr+1) begin        
        if (memory_value) //...
        // PROBLEM: changing addr in this loop doesn't cause memory_value to change
    end
end
endmodule

And here is how I instantiate the module

module top;

 reg mem[MEMORY_SIZE-1:0];
    wire [MEMORY_ADD_WIDTH-1:0] addr;
    //...
    r r( rst, ..., addr, mem[addr]);
endmodule

I'm using Modelsim to simulate the design. First of all, is this expected behaviour, and if it is what's a common workaround?


Solution

  • for loops in Verilog are used to create several copies of an assignment. The loop is automatically unrolled (which is why it needs constant bounds).

    For example

    always@(posedge clk)
    for (i=1; i<4; i=i+1)
        foo[i] <= foo[i-1]*foo[i-1];
    

    is equivalent to

    always@(posedge clk) begin
        foo[1] <= foo[0]*foo[0];
        foo[2] <= foo[1]*foo[1];
        foo[3] <= foo[2]*foo[2];
    end
    

    So, the code you provided never assigns a value to addr, which is likely why you aren't see any change. (In the same way that i doesn't appear in the second part of my example)


    Consider instead splitting these up.:

    always@(posedge clk)
        addr<=(addr+1)%ADDR_MAX;
    
    always@(*)begin
        if (memory_value) // mem[addr]
        //...
    end