I would like to ask a couple of question related to generate construct and its utilization with uvm_config_db set in the module hierarchy. In my test bench top-level module there are the following contents
module top;
typedef enum {
AMBA_BUS1,
AMBA_BUS2,
AMBA_BUS_QUANTITY} amba_bus_t;
amba_bus_t amba_buses = amba_buses.first();
// Actual interface (amba_interface) array instance named “i_amba_interface”
amba_interface i_amba_interface[AMBA_BUS_QUANTITY}]();
for (genvar i = 0; i < AMBA_BUS_QUANTITY; i++) begin // <-- Do we need to name this block if used for uvm_config_db?
initial begin
uvm_config_db#(virtual amba_interface)::set(uvm_root::get(), "uvm_test_top", amba_buses.name(), top.i_amba_interface[i]);
amba_buses = amba_buses.next(); // <-- Is this illegal to assign variable/field in generate loop in that way?
end
end
endmodule : top
The questions are (pointed also with “// <–” comments in code):
If we are doing uvm_config_db set within generate loop, whether it is recommended or not to name the generate loop block? If yes, what is the reason to name the block including just uvm_config_db? I think some of simulators raise warnings if you have unnamed generate blocks
Is it legal to assign variable/field within generate loop as shown in the code? In the code, there is used enum built-in methods name() and next() to set proper field string per interface instance for uvm_config_db entries. In simulator, I can see with uvm_config_db_trace that uvm_config_db is configured with those enum names as expected, but I am still wondering if that kind variable assignment is done correctly. If it is legal to assign variables in that way within generate block, are those variables (amba_buses in this example) implicitly defined as a localparam in each instance of the generate block like genvars are?
You only need to name a generate block if you plan to reference things (ie. variables or instances) declared inside the generate block from outside the generate block.
It’s not illegal to assign
amba_buses in the generate loop. However, it is not a good programming practice to have multiple processes simultaneously writing and reading to the same global variable. A better approach would be using the argument to next() to specify the position of the enum label.
const amba_bus_t amba_bus_first;
// Actual interface (amba_interface) array instance named “i_amba_interface”
amba_interface i_amba_interface[AMBA_BUS_QUANTITY}]();
for (genvar i = 0; i < AMBA_BUS_QUANTITY; i++) begin
initial begin
automatic amba_bus_t local_label = amba_bus_first.next(i);
uvm_config_db#(virtual amba_interface)::set(uvm_root::get(), "uvm_test_top", local_label.name(), top.i_amba_interface[i]);
end
end
You only need to name a generate block if you plan to reference things (ie. variables or instances) declared inside the generate block from outside the generate block.
It’s not illegal to assign
amba_buses in the generate loop. However, it is not a good programming practice to have multiple processes simultaneously writing and reading to the same global variable. A better approach would be using the argument to next() to specify the position of the enum label.
const amba_bus_t amba_bus_first;
// Actual interface (amba_interface) array instance named “i_amba_interface”
amba_interface i_amba_interface[AMBA_BUS_QUANTITY}]();
for (genvar i = 0; i < AMBA_BUS_QUANTITY; i++) begin
initial begin
automatic amba_bus_t local_label = amba_bus_first.next(i);
uvm_config_db#(virtual amba_interface)::set(uvm_root::get(), "uvm_test_top", local_label.name(), top.i_amba_interface[i]);
end
end
Thanks for clarifying. Could you still explain with a couple of more words the following things:
By declaring amba_bus_first as a const constant, can it be assigned once somewhere within the module?
Why automatic word is used, to get local copy of amba_bus_first for each generate block? What is the fundamental difference to declare local_label variable with/without automatic in this context? I think with automatic keyword local_label is initialized when execution enters the initial process?
*In reply to Vaino:*Sorry for introducing a few extra concepts without explaining. I am making sure that amba_bus_first gets initialized with its default initial value before any reference to that variable occurs. As a general programming rule, you should never rely on the initial state of a static variable. Although static variables get initialized before any always or initial blocks, there is no guaranteed order of initialization between static variables.
A const variable that is not a class member can only be initialized as part of its declaration. A const variable that is a class member can be initialized as part of its declaration or once as an assignment inside the class constructor.
Yes, the key reason I made local_label, an automatic variable was so that the initialization occurs when executing the initial process. I could also made local_label a static variable (which is the default outside of a class declaration), by added a separate assignment statement that write to local_label when executing the initial process.
I think I am now ok with your original code proposal, thanks! I definitely see your proposal as a good programming practice.
As you stated, the const variable that is not a class member can only be initialized as part of its declaration, but I am a little annoyed because the same explanation cannot be found from IEEE Std 1800-2012. I can only find the const class member initialization explanation, but nothing about outside class const variable initialization. Could you point me a section within IEEE Std 1800-2012 which explains that? Or does it exist at all? Maybe it is kind of implicit rule.
In reply to Vaino:
Section 6.20.6 Const constants explains it, but it uses the word “set” instead of “assigned” or initialized. Those words have the same meaning in this context.