Support classes in generate blocks

SystemVerilog allows class declarations as module and generate items.
Currently a class declaration in a generate block triggers an assert because
`pform_push_class_scope()` only records classes in `PScopeExtra` scopes.

Add class storage to `PGenerate` and elaborate those classes like module and
package classes. When registering task, function or class declarations, only
use the current `PGenerate` object as the target if it is also the current
lexical scope. This distinction matters for generated classes because
`pform_cur_generate` remains set while the class body is parsed, but the
current lexical scope has changed to the `PClass`. This records the class
declaration in the generate block while leaving methods and constructors in
the class scope.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2026-06-20 17:05:36 -07:00
parent daadc38f18
commit 7934ab9eeb
5 changed files with 27 additions and 10 deletions

View File

@ -26,10 +26,12 @@
# include <list>
# include <map>
# include <valarray>
# include <vector>
# include "pform_types.h"
class Design;
class NetScope;
class PClass;
class PExpr;
class PFunction;
class PProcess;
@ -92,9 +94,11 @@ class PGenerate : public PNamedItem, public LexicalScope {
std::list<PGate*> gates;
void add_gate(PGate*);
// Tasks instantiated within this scheme.
// Definitions instantiated within this scheme.
std::map<perm_string,PTask*> tasks;
std::map<perm_string,PFunction*>funcs;
std::map<perm_string,PClass*> classes;
std::vector<PClass*> classes_lexical;
// Generate schemes can contain further generate schemes.
std::list<PGenerate*> generate_schemes;

View File

@ -1324,6 +1324,8 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
elaborate_scope_enumerations(des, scope, enum_sets);
elaborate_scope_classes(des, scope, classes_lexical);
// Run through the defparams for this scope and save the result
// in a table for later final override.

View File

@ -607,6 +607,7 @@ bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const
elaborate_sig_funcs(des, scope, funcs);
elaborate_sig_tasks(des, scope, tasks);
elaborate_sig_classes(des, scope, classes);
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generate_schemes.begin()

View File

@ -7228,6 +7228,7 @@ bool PGenerate::elaborate_(Design*des, NetScope*scope) const
if (result_flag) {
elaborate_functions(des, scope, funcs);
elaborate_tasks(des, scope, tasks);
elaborate_classes(des, scope, classes);
for (const auto gt : gates) gt->elaborate(des, scope);

View File

@ -449,6 +449,11 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope)
return scopex;
}
static PGenerate* current_generate_scope()
{
return lexical_scope == pform_cur_generate ? pform_cur_generate : nullptr;
}
static void add_local_symbol(LexicalScope*scope, perm_string name, PNamedItem*item)
{
assert(scope);
@ -585,12 +590,16 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name)
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
ivl_assert(loc, scopex);
ivl_assert(loc, !pform_cur_generate);
pform_set_scope_timescale(class_scope, scopex);
scopex->classes[name] = class_scope;
scopex->classes_lexical .push_back(class_scope);
if (auto generate_scope = current_generate_scope()) {
generate_scope->classes[name] = class_scope;
generate_scope->classes_lexical.push_back(class_scope);
} else {
scopex->classes[name] = class_scope;
scopex->classes_lexical.push_back(class_scope);
}
lexical_scope = class_scope;
return class_scope;
@ -632,9 +641,9 @@ PTask* pform_push_task_scope(const struct vlltype&loc, const char*name,
pform_set_scope_timescale(task, scopex);
if (pform_cur_generate) {
add_local_symbol(pform_cur_generate, task_name, task);
pform_cur_generate->tasks[task_name] = task;
if (auto generate_scope = current_generate_scope()) {
add_local_symbol(generate_scope, task_name, task);
generate_scope->tasks[task_name] = task;
} else {
add_local_symbol(scopex, task_name, task);
scopex->tasks[task_name] = task;
@ -667,9 +676,9 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name,
pform_set_scope_timescale(func, scopex);
if (pform_cur_generate) {
add_local_symbol(pform_cur_generate, func_name, func);
pform_cur_generate->funcs[func_name] = func;
if (auto generate_scope = current_generate_scope()) {
add_local_symbol(generate_scope, func_name, func);
generate_scope->funcs[func_name] = func;
} else {
add_local_symbol(scopex, func_name, func);