}
// activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.)
- if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX || type == AST_TYPEDEF)
+ if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_ENUM_ITEM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX || type == AST_TYPEDEF)
const_fold = true;
- if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM))
+ if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM || current_scope[str]->type == AST_ENUM_ITEM))
const_fold = true;
// in certain cases a function must be evaluated constant. this is what in_param controls.
- if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX)
+ if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_LOCALPARAM || type == AST_ENUM_ITEM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX)
in_param = true;
std::map<std::string, AstNode*> backup_scope;
}
this_wire_scope[node->str] = node;
}
+ // these nodes appear at the top level in a module and can define names
if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR ||
node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION || node->type == AST_CELL ||
node->type == AST_TYPEDEF) {
backup_scope[node->str] = current_scope[node->str];
current_scope[node->str] = node;
}
+ if (node->type == AST_ENUM) {
+ for (auto enode : node->children) {
+ log_assert(enode->type==AST_ENUM_ITEM);
+ if (current_scope.count(enode->str) == 0) {
+ current_scope[enode->str] = enode;
+ }
+ // while (enode->simplify(true, false, false, 1, -1, false, true))
+ // did_something = true;
+ }
+ }
}
for (size_t i = 0; i < children.size(); i++) {
AstNode *node = children[i];
}
break;
+ case AST_ENUM:
+ // log("\nENUM %d child %d\n", basic_prep, children[0]->basic_prep);
+ if (!basic_prep) {
+ for (auto item_node : children) {
+ while (!item_node->basic_prep && item_node->simplify(false, false, false, stage, -1, false, true) == true)
+ did_something = true;
+ }
+ // allocate values (called more than once)
+ allocateDefaultEnumValues();
+ }
+ break;
+
case AST_PARAMETER:
case AST_LOCALPARAM:
+ case AST_ENUM_ITEM:
while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, true) == true)
did_something = true;
children[0]->detectSignWidth(width_hint, sign_hint);
// Insert clones children from template at beginning
for (int i = 0; i < GetSize(templ->children); i++)
children.insert(children.begin() + i, templ->children[i]->clone());
-
+
if (type == AST_MEMORY && GetSize(children) == 1) {
// Single-bit memories must have [0:0] range
AstNode *rng = new AstNode(AST_RANGE);
did_something = true;
}
log_assert(!is_custom_type);
- }
+ }
// resolve constant prefixes
if (type == AST_PREFIX) {
}
// trim/extend parameters
- if (type == AST_PARAMETER || type == AST_LOCALPARAM) {
+ if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_ENUM_ITEM) {
if (children.size() > 1 && children[1]->type == AST_RANGE) {
if (!children[1]->range_valid)
log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n");
if (type == AST_IDENTIFIER) {
if (current_scope.count(str) == 0) {
for (auto node : current_ast_mod->children) {
- if ((node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR ||
- node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION) && str == node->str) {
+ //log("looking at mod scope child %s\n", type2str(node->type).c_str());
+ switch (node->type) {
+ case AST_PARAMETER:
+ case AST_LOCALPARAM:
+ case AST_WIRE:
+ case AST_AUTOWIRE:
+ case AST_GENVAR:
+ case AST_MEMORY:
+ case AST_FUNCTION:
+ case AST_TASK:
+ case AST_DPI_FUNCTION:
+ //log("found child %s, %s\n", type2str(node->type).c_str(), node->str.c_str());
+ log("add %s, type %s to scope\n", str.c_str(), type2str(node->type).c_str());
current_scope[node->str] = node;
break;
+ case AST_ENUM:
+ for (auto enum_node : node->children) {
+ log_assert(enum_node->type==AST_ENUM_ITEM);
+ if (str == enum_node->str) {
+ log("\nadding enum %s to scope\n", str.c_str());
+ current_scope[str] = enum_node;
+ }
+ }
+ break;
+ default:
+ break;
}
}
}
}
for (auto child : decl->children)
- if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
+ if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_ENUM_ITEM)
{
AstNode *wire = nullptr;
switch (type)
{
case AST_IDENTIFIER:
- if (current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM)) {
+ if (current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM || current_scope[str]->type == AST_ENUM_ITEM)) {
if (current_scope[str]->children[0]->type == AST_CONSTANT) {
if (children.size() != 0 && children[0]->type == AST_RANGE && children[0]->range_valid) {
std::vector<RTLIL::State> data;
for (size_t i = 0; i < children.size(); i++) {
AstNode *child = children[i];
if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM ||
- child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL || child->type == AST_TYPEDEF) {
+ child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL || child->type == AST_TYPEDEF || child->type == AST_ENUM_ITEM) {
if (backup_name_map.size() == 0)
backup_name_map = name_map;
std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix;
return AstNode::mkconst_bits(variables.at(str).val.bits, variables.at(str).is_signed);
}
+void AstNode::allocateDefaultEnumValues()
+{
+ log_assert(type==AST_ENUM);
+ int last_enum_int = -1;
+ for (auto node : children) {
+ log_assert(node->type==AST_ENUM_ITEM);
+ for (size_t i = 0; i < node->children.size(); i++) {
+ switch (node->children[i]->type) {
+ case AST_NONE:
+ // replace with auto-incremented constant
+ delete node->children[i];
+ node->children[i] = AstNode::mkconst_int(++last_enum_int, true);
+ break;
+ case AST_CONSTANT:
+ // explicit constant (or folded expression)
+ // TODO: can't extend 'x or 'z item
+ last_enum_int = node->children[i]->integer;
+ break;
+ default:
+ // ignore ranges
+ break;
+ }
+ // TODO: range check
+ }
+ }
+}
+
YOSYS_NAMESPACE_END
specify_triple fall;
};
+static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true)
+{
+ auto range = new AstNode(AST_RANGE);
+ range->children.push_back(AstNode::mkconst_int(msb, true));
+ range->children.push_back(AstNode::mkconst_int(lsb, true));
+ range->is_signed = isSigned;
+ return range;
+}
+
+static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = true)
+{
+ auto range = makeRange(msb, lsb, isSigned);
+ parent->children.push_back(range);
+}
%}
%define api.prefix {frontend_verilog_yy}
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id
+%type <ast> opt_enum_init
%type <boolean> opt_signed opt_property unique_case_attr always_comb_or_latch always_or_always_ff
%type <al> attr case_attr
};
package_body:
- package_body package_body_stmt |;
+ package_body package_body_stmt
+ | // optional
+ ;
package_body_stmt:
typedef_decl |
module_body_stmt:
task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
+ enum_decl |
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl:
ast_stack.back()->children.push_back(node);
};
+enum_type: TOK_ENUM {
+ // create parent node for the enum
+ astbuf2 = new AstNode(AST_ENUM);
+ ast_stack.back()->children.push_back(astbuf2);
+ // create the template for the names
+ astbuf1 = new AstNode(AST_ENUM_ITEM);
+ astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ } param_signed enum_base_type '{' enum_name_list '}' { // create template for the enum vars
+ auto tnode = astbuf1->clone();
+ delete astbuf1;
+ astbuf1 = tnode;
+ tnode->type = AST_WIRE;
+ // drop constant but keep any range
+ delete tnode->children[0];
+ tnode->children.erase(tnode->children.begin()); }
+ ;
+
+enum_base_type: int_vec param_range
+ | int_atom
+ | /* nothing */ { addRange(astbuf1); }
+ ;
+
+int_atom: TOK_INTEGER { addRange(astbuf1); } // probably should do byte, range [7:0] here
+ ;
+
+int_vec: TOK_REG { astbuf1->is_reg = true; } // lexer returns this for logic|bit too
+ ;
+
+enum_name_list:
+ enum_name_decl
+ | enum_name_list ',' enum_name_decl
+ ;
+
+enum_name_decl:
+ TOK_ID opt_enum_init {
+ // put in fn
+ log_assert(astbuf1);
+ log_assert(astbuf2);
+ auto node = astbuf1->clone();
+ node->str = *$1;
+ delete $1;
+ delete node->children[0];
+ node->children[0] = $2 ?: new AstNode(AST_NONE);
+ astbuf2->children.push_back(node);
+ }
+ ;
+
+opt_enum_init:
+ '=' basic_expr { $$ = $2; } // TODO: restrict this
+ | /* optional */ { $$ = NULL; }
+ ;
+
+enum_var_list:
+ enum_var
+ | enum_var_list ',' enum_var
+ ;
+
+enum_var: TOK_ID {
+ log_assert(astbuf1);
+ log_assert(astbuf2);
+ auto node = astbuf1->clone();
+ ast_stack.back()->children.push_back(node);
+ node->str = *$1;
+ delete $1;
+ node->is_enum = true;
+ }
+ ;
+
+enum_decl: enum_type enum_var_list ';' { delete astbuf1; }
+ ;
+
wire_decl:
attr wire_type range {
albuf = $1;