0
votes

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?

1
"memory_value" is an input to the "r" module and so "r" module, itself won't change the value of "memory_value". So, what do you mean, by "changing addr in this loop doesn't cause memory_value to change" ? - Karan Shah
@KaranShah as the OP specified that they're talking to memory, they're likely expecting the memory_value to change when they provide a new value on addr(which isn't happening; see my answer) - wilcroft

1 Answers

1
votes

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