1

I want to use generate statement inside a task. The following code is giving compile errors (iverilog).

task write_mem; //for generic use with 8, 16 and 32 bit mem writes
      input [WIDTH-1:0] data;
      input [WIDTH-1:0] addr;
      output [WIDTH-1:0] MEM;
      integer i;

      begin
         generate
            genvar j;
            for(j=0; j<i;j++)
            MEM[addr+(i-j-1)] = data[(j*8):((j*8) + 8)-1];
         endgenerate
      end
endtask // write_mem

I also tried putting generate just after the line integer i, but still its producing errors. Any thoughts?

EDIT: I also tried putting genvar declaration between begin and generate statement in the above code. Its still producing compiler errors

Thanks in advance,

Jay Aurabind

Jay Aurabind
  • 261
  • 1
  • 4
  • 14

2 Answers2

5

What you are trying is not possible - a generate region (generate..endgenerate block) is only allowed in the module description (aka "top level"), i.e. the same level where you have parameters, wires, always- and inital-regions, etc. (see Syntax 12-5 in the IEEE Std. 1364-2005). Within a task a generate region is e.g. as invalid as an assign statement.

However, you can use a non-generate for-loop in a task (this is also synthesizeable).

Either way, you can not count from 0 to i-1 in synthesizeable code as 'i' is not constant. Also note that j++ is not valid verilog, you must write j=j+1 instead. Finally you probably want to use a nonblocking assignment (<=) instead of a blocking assignment (=), but this depends on how you intent to use this task.

CliffordVienna
  • 7,995
  • 1
  • 37
  • 57
  • @CliffodVienna point taken regarding j++. Also, I am calling this task from within an `always` block. So a blocking assignment should be able to produce synthesizable code, right ? – Jay Aurabind May 29 '13 at 07:11
  • @JayAurabind the type of assignment used should reflect where the task is to be called from. `always @*` combinatorial use `=` blocking. `always @(posedge clk)` Sequential use `<=` non-blocking. – Morgan May 29 '13 at 08:55
  • 1
    @Morgan If the difference between blocking and nonblocking would be that easy, the synthesis tool would be able to do it for you. In Verilog you always have two meanings for each construct: The simulation semantics and the synthesis semantics. When used correctly, both semantics yield the same behavior in those two domains. When used incorrectly, a simulation-synthesis mismatch can be the result. See e.g. http://stackoverflow.com/a/4774450/2213720 and http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf for further details and definitions of blocking and nonblocking semantics. – CliffordVienna May 29 '13 at 10:31
  • @Morgan, The synthesis tool _does_ handle blocking and non-blocking assignments differently, i.e. when a variable is accessed in an always block after it was assigned to. The simulation also handles blocking and non-blocking assignment differently: blocking assignments are executed immediately and non-blocking assignments at the end of the time slot. When used correctly this yields identical behavior in simulation and synthesis. But in order to use it correctly one has to understand the semantics. Per-use-case guidelines are imho not helping anyone understand (also (at)Cummings ;-). – CliffordVienna May 29 '13 at 17:00
1

genvars should be defined before the generate statement:

genvar j;
generate
  for(j=0; j<i;j++)
    MEM[addr+(i-j-1)] = data[(j*8):((j*8) + 8)-1];
endgenerate

Although your usage here does not look like it needs a generate statement a for loop would have done.

As pointed out by @CliffordVienna generate statements are for building hierarchy and wiring based on compile time constants. ie parameters can be changed for reusable code but are constant in a given simulation. Tasks do not contain hierarchy and therefore the use of a generate is invalid.

Any for loop that can be unrolled is synthesizable, some thing like:

task write_mem; //for generic use with 8, 16 and 32 bit mem writes
  input  [WIDTH-1:0] data;
  input  [WIDTH-1:0] addr;
  output [WIDTH-1:0] mem;
  integer i = WIDTH / 8; // CONSTANT   

  begin
    for(j=0; j<i;j++) begin
      mem[addr+(i-j-1)] = data[(j*8):((j*8) + 8)-1];
    end
  end
endtask // write_mem

Tasks are synthesizable as long as they do not contain any timing control, which yours does not. From the information given this should be synthesizable.

NB: I would separate data width and addr width, they might be the same now but you might want to move to 8 bit addressing and 16 bit data.

Morgan
  • 19,934
  • 8
  • 58
  • 84
  • declaring `genvar` before `generate` is also producing compiler errors. For a tasks, it is mandatory that all variables be defined first and the start then main statements within a `begin...end` block, right ? If thats the case, then a `genvar` inside `begin..end` declaration violates that rule, doesnt it? – Jay Aurabind May 27 '13 at 18:08
  • My real code actually had the statement ` i = WIDTH / 8;` which would make `i` constant, right? Also this task is called from within `always` block. so this would be synthesizable, isnt it? – Jay Aurabind May 29 '13 at 07:08