Reputation: 51
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?
Upvotes: 2
Views: 23297
Reputation: 19104
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.
Upvotes: 1
Reputation: 3
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
Upvotes: 0
Reputation: 20514
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.
Upvotes: 1