2

I'd like to set a parameter based on a parameter which is set when the module is instantiated. I have the following.

module foo #(WORDS = 8);

parameter P00 = 33;
logic [7:0] tmp;

generate
  case (WORDS)
    4: begin : A
         assign tmp = 8'haa;
         parameter P00 = 4;
       end
    8: begin : B
         assign tmp = 8'hbb;
         parameter P00 = 8;
       end
   16: begin : C
         assign tmp = 8'hcc;
         parameter P00 = 16;
       end
   default: begin : D
              assign tmp = 8'hdd;
              parameter P00 = 8;
            end
  endcase
endgenerate

initial begin
  $display ("WORDS = %d", WORDS);
  $display ("tmp   = %h", tmp);
  $display ("P00   = %d", P00);
end

endmodule

I expected to get an error for redefining P00 but it compiled and ran and displayed the following instead.

WORDS =       8
tmp    = bb
P00    = 33

If I comment the "parameter P00 = 33" assignment, I get a "Identifier P00 has not been declared yet." error.

It seems that the generate block is being ignored. What is wrong here?

3
  • 1
    If I'm reading the language spec correctly, you're actually creating a new parameter in a different scope when you use the parameter type in a generate block. It states, "In [generate blocks], the parameter keyword shall be a synonym for the localparam keyword." Also, "Local parameters are identical to parameters except that they cannot directly be modified by... instance parameter value assignments." Check out section 6.20.4 if you have a copy of the language reference and want to know more. It looks to me like you need a different approach to solve this problem. Commented Jul 18, 2013 at 23:32
  • @Dan - Thank you. I did read the manual section above but I did not get that the generate block actually created a different scope from that of the module. I tried displaying C.P00 but that did not work either. If a new scope is created, how do I access it? Commented Jul 19, 2013 at 12:48
  • I'm not really clear on that. I'm just starting to learn the language myself, but @Morgan seems to have a pretty good answer below. Commented Jul 19, 2013 at 16:43

3 Answers 3

1

There has been quite a few questions on here recently using generates and assigns inappropriately not sure if a new tutorial has been written which is not teaching these things correctly.

Parameters or Localparams should not be defined more than once, and they are constants so can not have the value changed. I think you are also missing the parameter keyword from module foo.

module foo #(
  parameter WORDS = 8
);

localparam P00 = WORD;

It is common to use as scaling factors:

module foo #(
  parameter WIDTH = 8
  parameter MAX_VALUE = 2**WIDTH
);

What you have defined looks like you should just be using a logic not parameter to hold the value;

I would rewrite the whole thing as:

module foo #(WORDS = 8);

logic [31:0] P00 = 33;
logic [7:0]  tmp;

always @* begin
  case (WORDS)
    4: begin : A
         tmp = 8'haa;
         P00 = 4;
       end
    8: begin : B
         tmp = 8'hbb;
         P00 = 8;
       end
   16: begin : C
         tmp = 8'hcc;
         P00 = 16;
       end
   default: begin : D
            tmp = 8'hdd;
            P00 = 8;
      end
  endcase
end

The use of generate is unnecessary for what you are trying to achieve here.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. Your comment is nice and does work but it's not exactly what I need. I used the generate block because I want only one case to be synthesized based on the number of WORDS. The example is a simplified version of the module. The number of parameters increases with the number of WORDS. Maybe I'm misunderstanding the use of generate as you say. Also, the parameter declaration at the top - setting P00=33 - was added just to see if any parameters were being set in the generate block. I added it to cause an error but it did not cause one.
@user2382841 I would check your warnings quite closely as well as errors. Generates are useful for creating hierarchy (multiple instances) based on parameters, or inter-wiring blocks together. If the input is constant, the output is constant the the synthesis tool will do a good job of creating minimal hardware. If P00 is a constant makes no difference if logic (reg) or parameter.
1

Placing a parameter definition inside a generate block generates a new local parameter relative to the hierarchical scope within the generate block. defparam is the usually the way to override a parameter value. However the IEEE std 1800-2012 explicitly states a defparam cannot effect its parent scope in §23.10.1:

a defparam statement in a hierarchy in or under a generate block instance (see Clause 27) or an array of instances (see 28.3.5 and 23.3.2) shall not change a parameter value outside that hierarchy.

For complex derived parameter assignments you can use functions. For example:

parameter P01 = FUNC01(WORDS,P00);
function byte FUNC01(input byte w,p);
/* ... */
endfunction

This is also legal: module foo #(parameter WORDS, P00=FUNC00(WORDS));

A challenge could be that each parameter may need its own function. Using a parameter with a struct data type is a potential work around to group the assignments into a single function. This approach needs to be evaluated by your simulator, synthesizer and other tools. Example:

typedef struct packed {
  int sub00;
  byte sub01;
  /* ... */
 bit [13:0] subNN
} param_t;
paramter param_t P = FUNC_P(/* inputs */);

function param_t FUNC_P(/* inputs */);
  param_t rtn;
  /* assign all rtn.sub* */
  return rtn;
endfunction

logic [P.sub01-1:0] tmpvar;

As Morgan has stated, you could define most of the parameters as logic and use a combination block. However I would strongly insist on using an always_comb block instead of a always @* to guarantee the values are calculation. As stated in the LRM §9.2.2.2.2:

always_comb automatically executes once at time zero, whereas always @* waits until a change occurs on a signal in the inferred sensitivity list.

Comments

0

This works (generally say you need to make all 4 generate blocks name as the same):

module foo #(WORDS = 8);

parameter P00 = 33;
logic [7:0] tmp;

generate
  case (WORDS)
    4: begin : B
         assign tmp = 8'haa;
         parameter P00 = 4;
       end
    8: begin : B
         assign tmp = 8'hbb;
         parameter P00 = 8;
       end
   16: begin : B
         assign tmp = 8'hcc;
         parameter P00 = 16;
       end
   default: begin : B
              assign tmp = 8'hdd;
              parameter P00 = 8;
            end
  endcase
endgenerate

initial begin
  $display ("WORDS = %d", WORDS);
  $display ("tmp   = %h", tmp);
  $display ("P00   = %d", B.P00);
end

endmodule

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.