Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 49 additions & 15 deletions frontends/ast/simplify.cc
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,52 @@ static void check_auto_nosync(AstNode *node)
check_auto_nosync(child.get());
}

class PackageImporter {
std::set<std::string> import_items;
bool is_wildcard;
const AstNode* node;
public:
PackageImporter(const AstNode* n, const AstNode* child) : node(n) {
is_wildcard = child->children.empty();
// For specific imports, collect the list of items to import
if (!is_wildcard) {
for (auto& item : child->children) {
import_items.insert(item->str);
}
}
}

void import(std::map<std::string, AstNode*>& scope, AstNode* to_import) const {
// Check if this is a specific import and if this item should be imported
if (!is_wildcard && import_items.count(to_import->str) == 0)
return;

if (to_import->type == AST_PARAMETER || to_import->type == AST_LOCALPARAM ||
to_import->type == AST_TYPEDEF || to_import->type == AST_FUNCTION ||
to_import->type == AST_TASK || to_import->type == AST_ENUM) {
// For wildcard imports, check if item already exists (from specific import)
if (is_wildcard && scope.count(to_import->str) > 0)
return;
scope[to_import->str] = to_import;
}
if (to_import->type == AST_ENUM) {
for (auto& enode : to_import->children) {
log_assert(enode->type==AST_ENUM_ITEM);
// Check if this enum item should be imported
if (!is_wildcard && import_items.count(enode->str) == 0)
continue;
// For wildcard imports, check if item already exists (from specific import)
if (is_wildcard && scope.count(enode->str) > 0)
continue;
if (scope.count(enode->str) == 0)
scope[enode->str] = enode.get();
else
node->input_error("enum item %s already exists in current scope\n", enode->str);
}
}
}
};

// convert the AST into a simpler AST that has all parameters substituted by their
// values, unrolled for-loops, expanded generate blocks, etc. when this function
// is done with an AST it can be converted into RTLIL using genRTLIL().
Expand Down Expand Up @@ -1123,22 +1169,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
}

if (package_node) {
// Import all names from the package into current scope
PackageImporter importer(this, child);
// Import names from the package into current scope
for (auto& pkg_child : package_node->children) {
if (pkg_child->type == AST_PARAMETER || pkg_child->type == AST_LOCALPARAM ||
pkg_child->type == AST_TYPEDEF || pkg_child->type == AST_FUNCTION ||
pkg_child->type == AST_TASK || pkg_child->type == AST_ENUM) {
current_scope[pkg_child->str] = pkg_child.get();
}
if (pkg_child->type == AST_ENUM) {
for (auto& enode : pkg_child->children) {
log_assert(enode->type==AST_ENUM_ITEM);
if (current_scope.count(enode->str) == 0)
current_scope[enode->str] = enode.get();
else
input_error("enum item %s already exists in current scope\n", enode->str);
}
}
importer.import(current_scope, pkg_child.get());
}
// Remove the import node since it's been processed
children.erase(children.begin() + i);
Expand Down
24 changes: 22 additions & 2 deletions frontends/verilog/verilog_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -829,11 +829,31 @@ package_body_stmt:
typedef_decl | localparam_decl | param_decl | task_func_decl;

import_stmt:
TOK_IMPORT hierarchical_id TOK_PACKAGESEP TOK_ASTER TOK_SEMICOL {
// Create an import node to track package imports
TOK_IMPORT TOK_ID TOK_PACKAGESEP TOK_ASTER TOK_SEMICOL {
// Create an import node to track wildcard package imports
auto import_node = std::make_unique<AstNode>(@$, AST_IMPORT);
import_node->str = *$2;
extra->ast_stack.back()->children.push_back(std::move(import_node));
} |
TOK_IMPORT TOK_ID TOK_PACKAGESEP {
// Start a specific import: create and push the AST_IMPORT node
AstNode* import_node = extra->pushChild(std::make_unique<AstNode>(@$, AST_IMPORT));
import_node->str = *$2;
} import_item_list TOK_SEMICOL {
// Done collecting specific items, pop the AST_IMPORT node
extra->ast_stack.pop_back();
};

import_item_list:
import_item |
import_item_list TOK_COMMA import_item ;

import_item:
TOK_ID {
// Append this specific import name under the current AST_IMPORT
auto item_node = std::make_unique<AstNode>(@$, AST_NONE);
item_node->str = *$1;
extra->ast_stack.back()->children.push_back(std::move(item_node));
};

interface:
Expand Down
14 changes: 14 additions & 0 deletions tests/verilog/package_import_specific.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package package_import_specific;

localparam integer
DATA_WIDTH = 8,
ADDR_WIDTH = 4;

localparam logic [2:0]
IDLE = 3'b000,
START = 3'b001,
DATA = 3'b010,
STOP = 3'b100,
DONE = 3'b101;

endpackage
5 changes: 5 additions & 0 deletions tests/verilog/package_import_specific.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
read_verilog -sv package_import_specific.sv
read_verilog -sv package_import_specific_module.sv
hierarchy -check
proc
opt -full
16 changes: 16 additions & 0 deletions tests/verilog/package_import_specific_module.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import package_import_specific::DATA_WIDTH;
import package_import_specific::IDLE;

module package_import_specific_module;
logic [DATA_WIDTH-1:0] data;
logic [3:0] addr;
logic [2:0] state;

always_comb begin
case (state)
IDLE: data = 8'h00;
default: data = 8'hFF;
endcase
end

endmodule
Loading