mirror of https://github.com/YosysHQ/yosys.git
Generalise structs and add support for packed unions.
This commit is contained in:
parent
0b6b47ca67
commit
f482c9c016
|
@ -556,7 +556,7 @@ from SystemVerilog:
|
||||||
- enums are supported (including inside packages)
|
- enums are supported (including inside packages)
|
||||||
- but are currently not strongly typed
|
- but are currently not strongly typed
|
||||||
|
|
||||||
- structs are supported
|
- packed structs and unions are supported.
|
||||||
|
|
||||||
- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
|
- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
|
||||||
ports are inputs or outputs are supported.
|
ports are inputs or outputs are supported.
|
||||||
|
|
|
@ -172,6 +172,7 @@ std::string AST::type2str(AstNodeType type)
|
||||||
X(AST_WIRETYPE)
|
X(AST_WIRETYPE)
|
||||||
X(AST_TYPEDEF)
|
X(AST_TYPEDEF)
|
||||||
X(AST_STRUCT)
|
X(AST_STRUCT)
|
||||||
|
X(AST_UNION)
|
||||||
X(AST_STRUCT_ITEM)
|
X(AST_STRUCT_ITEM)
|
||||||
#undef X
|
#undef X
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -158,6 +158,7 @@ namespace AST
|
||||||
AST_WIRETYPE,
|
AST_WIRETYPE,
|
||||||
AST_TYPEDEF,
|
AST_TYPEDEF,
|
||||||
AST_STRUCT,
|
AST_STRUCT,
|
||||||
|
AST_UNION,
|
||||||
AST_STRUCT_ITEM
|
AST_STRUCT_ITEM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -992,6 +992,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||||
case AST_MODPORTMEMBER:
|
case AST_MODPORTMEMBER:
|
||||||
case AST_TYPEDEF:
|
case AST_TYPEDEF:
|
||||||
case AST_STRUCT:
|
case AST_STRUCT:
|
||||||
|
case AST_UNION:
|
||||||
break;
|
break;
|
||||||
case AST_INTERFACEPORT: {
|
case AST_INTERFACEPORT: {
|
||||||
// If a port in a module with unknown type is found, mark it with the attribute 'is_interface'
|
// If a port in a module with unknown type is found, mark it with the attribute 'is_interface'
|
||||||
|
|
|
@ -250,6 +250,97 @@ static AstNode *make_range(int left, int right, bool is_signed = false)
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int size_packed_struct(AstNode *snode, int base_offset)
|
||||||
|
{
|
||||||
|
// Struct members will be laid out in the structure contiguously from left to right.
|
||||||
|
// Union members all have zero offset from the start of the union.
|
||||||
|
// Determine total packed size and assign offsets. Store these in the member node.
|
||||||
|
bool is_union = (snode->type == AST_UNION);
|
||||||
|
int offset = 0;
|
||||||
|
int packed_width = -1;
|
||||||
|
// examine members from last to first
|
||||||
|
for (auto it = snode->children.rbegin(); it != snode->children.rend(); ++it) {
|
||||||
|
auto node = *it;
|
||||||
|
int width;
|
||||||
|
if (node->type == AST_STRUCT || node->type == AST_UNION) {
|
||||||
|
// embedded struct or union
|
||||||
|
width = size_packed_struct(node, base_offset + offset);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log_assert(node->type == AST_STRUCT_ITEM);
|
||||||
|
if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
|
||||||
|
auto rnode = node->children[0];
|
||||||
|
width = (rnode->range_swapped ? rnode->range_right - rnode->range_left :
|
||||||
|
rnode->range_left - rnode->range_right) + 1;
|
||||||
|
// range nodes are now redundant
|
||||||
|
node->children.clear();
|
||||||
|
}
|
||||||
|
else if (node->range_left < 0) {
|
||||||
|
// 1 bit signal: bit, logic or reg
|
||||||
|
width = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// already resolved and compacted
|
||||||
|
width = node->range_left - node->range_right + 1;
|
||||||
|
}
|
||||||
|
if (is_union) {
|
||||||
|
node->range_right = base_offset;
|
||||||
|
node->range_left = base_offset + width - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->range_right = base_offset + offset;
|
||||||
|
node->range_left = base_offset + offset + width - 1;
|
||||||
|
}
|
||||||
|
node->range_valid = true;
|
||||||
|
}
|
||||||
|
if (is_union) {
|
||||||
|
// check that all members have the same size
|
||||||
|
if (packed_width == -1) {
|
||||||
|
// first member
|
||||||
|
packed_width = width;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (packed_width != width) {
|
||||||
|
|
||||||
|
log_file_error(node->filename, node->location.first_line, "member %s of a packed union has %d bits, expecting %d\n", node->str.c_str(), width, packed_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
offset += width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (is_union ? packed_width : offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_members_to_scope(AstNode *snode, std::string name)
|
||||||
|
{
|
||||||
|
// add all the members in a struct or union to local scope
|
||||||
|
// in case later referenced in assignments
|
||||||
|
log_assert(snode->type==AST_STRUCT || snode->type==AST_UNION);
|
||||||
|
for (auto *node : snode->children) {
|
||||||
|
if (node->type != AST_STRUCT_ITEM) {
|
||||||
|
// embedded struct or union
|
||||||
|
add_members_to_scope(node, name + "." + node->str);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto member_name = name + "." + node->str;
|
||||||
|
current_scope[member_name] = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_max_offset(AstNode *node)
|
||||||
|
{
|
||||||
|
// get the width from the MS member in the struct
|
||||||
|
// as members are laid out from left to right in the packed wire
|
||||||
|
log_assert(node->type==AST_STRUCT || node->type==AST_UNION);
|
||||||
|
while (node->type != AST_STRUCT_ITEM) {
|
||||||
|
node = node->children[0];
|
||||||
|
}
|
||||||
|
return node->range_left;
|
||||||
|
}
|
||||||
|
|
||||||
static AstNode *make_packed_struct(AstNode *template_node, std::string &name)
|
static AstNode *make_packed_struct(AstNode *template_node, std::string &name)
|
||||||
{
|
{
|
||||||
// create a wire for the packed struct
|
// create a wire for the packed struct
|
||||||
|
@ -257,18 +348,14 @@ static AstNode *make_packed_struct(AstNode *template_node, std::string &name)
|
||||||
wnode->str = name;
|
wnode->str = name;
|
||||||
wnode->is_logic = true;
|
wnode->is_logic = true;
|
||||||
wnode->range_valid = true;
|
wnode->range_valid = true;
|
||||||
// get the width from the MS member in the template
|
wnode->is_signed = template_node->is_signed;
|
||||||
// as members are laid out from left to right
|
int offset = get_max_offset(template_node);
|
||||||
int offset = template_node->children[0]->range_left;
|
|
||||||
auto range = make_range(offset, 0);
|
auto range = make_range(offset, 0);
|
||||||
wnode->children.push_back(range);
|
wnode->children.push_back(range);
|
||||||
// make sure this node is the one in scope for this name
|
// make sure this node is the one in scope for this name
|
||||||
current_scope[name] = wnode;
|
current_scope[name] = wnode;
|
||||||
// add members to scope
|
// add all the struct members to scope under the wire's name
|
||||||
for (auto *node : template_node->children) {
|
add_members_to_scope(template_node, name);
|
||||||
auto member_name = name + "." + node->str;
|
|
||||||
current_scope[member_name] = node;
|
|
||||||
}
|
|
||||||
return wnode;
|
return wnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,46 +759,25 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_STRUCT:
|
case AST_STRUCT:
|
||||||
//log("STRUCT %d %d %d\n", stage, basic_prep, in_param);
|
case AST_UNION:
|
||||||
if (!basic_prep) {
|
if (!basic_prep) {
|
||||||
//dumpAst(NULL, "1> ");
|
|
||||||
for (auto *node : children) {
|
for (auto *node : children) {
|
||||||
// resolve any ranges
|
// resolve any ranges
|
||||||
while (!node->basic_prep && node->simplify(true, false, false, stage, -1, false, false)) {
|
while (!node->basic_prep && node->simplify(true, false, false, stage, -1, false, false)) {
|
||||||
did_something = true;
|
did_something = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
basic_prep = true;
|
// determine member offsets and widths
|
||||||
// The members will be laid out in the structure contiguously from left to right.
|
size_packed_struct(this, 0);
|
||||||
// Determine total packed size and assign offsets. Store these in the member node.
|
|
||||||
// dumpAst(NULL, "2> ");
|
// instance rather than just a type in a typedef or outer struct?
|
||||||
int offset = 0;
|
if (!str.empty() && str[0] == '\\') {
|
||||||
for (auto it = children.rbegin(); it != children.rend(); ++it) {
|
// instance so add a wire for the packed structure
|
||||||
auto node = *it;
|
|
||||||
if (is_signed)
|
|
||||||
node->is_signed = true;
|
|
||||||
int width;
|
|
||||||
if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
|
|
||||||
auto rnode = node->children[0];
|
|
||||||
width = (rnode->range_swapped ? rnode->range_right - rnode->range_left :
|
|
||||||
rnode->range_left - rnode->range_right) + 1;
|
|
||||||
// range nodes are now redundant
|
|
||||||
node->children.clear();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
width = 1;
|
|
||||||
}
|
|
||||||
node->range_right = offset;
|
|
||||||
node->range_left = offset + width - 1;
|
|
||||||
node->range_valid = true;
|
|
||||||
offset += width;
|
|
||||||
}
|
|
||||||
if (!str.empty()) {
|
|
||||||
// instance rather than just a type in a typedef
|
|
||||||
// so add a wire for the packed structure
|
|
||||||
auto wnode = make_packed_struct(this, str);
|
auto wnode = make_packed_struct(this, str);
|
||||||
|
log_assert(current_ast_mod);
|
||||||
current_ast_mod->children.push_back(wnode);
|
current_ast_mod->children.push_back(wnode);
|
||||||
}
|
}
|
||||||
|
basic_prep = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1036,7 +1102,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
if (type == AST_TYPEDEF) {
|
if (type == AST_TYPEDEF) {
|
||||||
log_assert(children.size() == 1);
|
log_assert(children.size() == 1);
|
||||||
auto type_node = children[0];
|
auto type_node = children[0];
|
||||||
log_assert(type_node->type == AST_WIRE || type_node->type == AST_MEMORY || type_node->type == AST_STRUCT);
|
log_assert(type_node->type == AST_WIRE || type_node->type == AST_MEMORY || type_node->type == AST_STRUCT || type_node->type == AST_UNION);
|
||||||
while (type_node->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {
|
while (type_node->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {
|
||||||
did_something = true;
|
did_something = true;
|
||||||
}
|
}
|
||||||
|
@ -1061,7 +1127,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
// Ensure typedef itself is fully simplified
|
// Ensure typedef itself is fully simplified
|
||||||
while (template_node->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};
|
while (template_node->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};
|
||||||
|
|
||||||
if (template_node->type == AST_STRUCT) {
|
if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) {
|
||||||
// replace with wire representing the packed structure
|
// replace with wire representing the packed structure
|
||||||
newNode = make_packed_struct(template_node, str);
|
newNode = make_packed_struct(template_node, str);
|
||||||
current_scope[str] = this;
|
current_scope[str] = this;
|
||||||
|
|
|
@ -265,6 +265,7 @@ static bool isUserType(std::string &s)
|
||||||
"bit" { SV_KEYWORD(TOK_LOGIC); }
|
"bit" { SV_KEYWORD(TOK_LOGIC); }
|
||||||
"int" { SV_KEYWORD(TOK_INT); }
|
"int" { SV_KEYWORD(TOK_INT); }
|
||||||
"byte" { SV_KEYWORD(TOK_BYTE); }
|
"byte" { SV_KEYWORD(TOK_BYTE); }
|
||||||
|
"shortint" { SV_KEYWORD(TOK_SHORTINT); }
|
||||||
|
|
||||||
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
||||||
"s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
"s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
||||||
|
@ -284,8 +285,9 @@ static bool isUserType(std::string &s)
|
||||||
|
|
||||||
"enum" { SV_KEYWORD(TOK_ENUM); }
|
"enum" { SV_KEYWORD(TOK_ENUM); }
|
||||||
"typedef" { SV_KEYWORD(TOK_TYPEDEF); }
|
"typedef" { SV_KEYWORD(TOK_TYPEDEF); }
|
||||||
"struct" { SV_KEYWORD(TOK_STRUCT); }
|
"struct" { SV_KEYWORD(TOK_STRUCT); }
|
||||||
"packed" { SV_KEYWORD(TOK_PACKED); }
|
"union" { SV_KEYWORD(TOK_UNION); }
|
||||||
|
"packed" { SV_KEYWORD(TOK_PACKED); }
|
||||||
|
|
||||||
[0-9][0-9_]* {
|
[0-9][0-9_]* {
|
||||||
yylval->string = new std::string(yytext);
|
yylval->string = new std::string(yytext);
|
||||||
|
|
|
@ -238,6 +238,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode)
|
||||||
%union {
|
%union {
|
||||||
std::string *string;
|
std::string *string;
|
||||||
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
|
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
|
||||||
|
YOSYS_NAMESPACE_PREFIX AST::AstNodeType type;
|
||||||
YOSYS_NAMESPACE_PREFIX dict<YOSYS_NAMESPACE_PREFIX RTLIL::IdString, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
|
YOSYS_NAMESPACE_PREFIX dict<YOSYS_NAMESPACE_PREFIX RTLIL::IdString, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
|
||||||
struct specify_target *specify_target_ptr;
|
struct specify_target *specify_target_ptr;
|
||||||
struct specify_triple *specify_triple_ptr;
|
struct specify_triple *specify_triple_ptr;
|
||||||
|
@ -269,7 +270,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode)
|
||||||
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
|
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
|
||||||
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
|
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
|
||||||
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
|
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
|
||||||
%token TOK_STRUCT TOK_PACKED TOK_UNSIGNED TOK_INT TOK_BYTE
|
%token TOK_STRUCT TOK_PACKED TOK_UNSIGNED TOK_INT TOK_BYTE TOK_SHORTINT TOK_UNION
|
||||||
|
|
||||||
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
|
%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 <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
|
||||||
|
@ -278,6 +279,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode)
|
||||||
%type <ast> opt_enum_init enum_type struct_type non_wire_data_type
|
%type <ast> opt_enum_init enum_type struct_type non_wire_data_type
|
||||||
%type <boolean> opt_signed opt_property unique_case_attr always_comb_or_latch always_or_always_ff
|
%type <boolean> opt_signed opt_property unique_case_attr always_comb_or_latch always_or_always_ff
|
||||||
%type <al> attr case_attr
|
%type <al> attr case_attr
|
||||||
|
%type <type> struct_union
|
||||||
|
|
||||||
%type <specify_target_ptr> specify_target
|
%type <specify_target_ptr> specify_target
|
||||||
%type <specify_triple_ptr> specify_triple specify_opt_triple
|
%type <specify_triple_ptr> specify_triple specify_opt_triple
|
||||||
|
@ -328,7 +330,6 @@ design:
|
||||||
param_decl design |
|
param_decl design |
|
||||||
localparam_decl design |
|
localparam_decl design |
|
||||||
typedef_decl design |
|
typedef_decl design |
|
||||||
struct_decl design |
|
|
||||||
package design |
|
package design |
|
||||||
interface design |
|
interface design |
|
||||||
/* empty */;
|
/* empty */;
|
||||||
|
@ -568,8 +569,7 @@ package_body:
|
||||||
;
|
;
|
||||||
|
|
||||||
package_body_stmt:
|
package_body_stmt:
|
||||||
typedef_decl
|
typedef_decl
|
||||||
| struct_decl
|
|
||||||
| localparam_decl
|
| localparam_decl
|
||||||
| param_decl
|
| param_decl
|
||||||
;
|
;
|
||||||
|
@ -601,7 +601,7 @@ interface_body:
|
||||||
interface_body interface_body_stmt |;
|
interface_body interface_body_stmt |;
|
||||||
|
|
||||||
interface_body_stmt:
|
interface_body_stmt:
|
||||||
param_decl | localparam_decl | typedef_decl | struct_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
|
param_decl | localparam_decl | typedef_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
|
||||||
modport_stmt;
|
modport_stmt;
|
||||||
|
|
||||||
non_opt_delay:
|
non_opt_delay:
|
||||||
|
@ -1442,6 +1442,7 @@ enum_base_type: type_atom type_signing
|
||||||
|
|
||||||
type_atom: TOK_INTEGER { astbuf1->is_reg = true; addRange(astbuf1); } // 4-state signed
|
type_atom: TOK_INTEGER { astbuf1->is_reg = true; addRange(astbuf1); } // 4-state signed
|
||||||
| TOK_INT { astbuf1->is_reg = true; addRange(astbuf1); } // 2-state signed
|
| TOK_INT { astbuf1->is_reg = true; addRange(astbuf1); } // 2-state signed
|
||||||
|
| TOK_SHORTINT { astbuf1->is_reg = true; addRange(astbuf1, 15, 0); } // 2-state signed
|
||||||
| TOK_BYTE { astbuf1->is_reg = true; addRange(astbuf1, 7, 0); } // 2-state signed
|
| TOK_BYTE { astbuf1->is_reg = true; addRange(astbuf1, 7, 0); } // 2-state signed
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -1467,6 +1468,7 @@ enum_name_decl:
|
||||||
auto node = astbuf1->clone();
|
auto node = astbuf1->clone();
|
||||||
node->str = *$1;
|
node->str = *$1;
|
||||||
delete $1;
|
delete $1;
|
||||||
|
SET_AST_NODE_LOC(node, @1, @1);
|
||||||
delete node->children[0];
|
delete node->children[0];
|
||||||
node->children[0] = $2 ?: new AstNode(AST_NONE);
|
node->children[0] = $2 ?: new AstNode(AST_NONE);
|
||||||
astbuf2->children.push_back(node);
|
astbuf2->children.push_back(node);
|
||||||
|
@ -1490,6 +1492,7 @@ enum_var: TOK_ID {
|
||||||
ast_stack.back()->children.push_back(node);
|
ast_stack.back()->children.push_back(node);
|
||||||
node->str = *$1;
|
node->str = *$1;
|
||||||
delete $1;
|
delete $1;
|
||||||
|
SET_AST_NODE_LOC(node, @1, @1);
|
||||||
node->is_enum = true;
|
node->is_enum = true;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -1497,23 +1500,29 @@ enum_var: TOK_ID {
|
||||||
enum_decl: enum_type enum_var_list ';' { delete $1; }
|
enum_decl: enum_type enum_var_list ';' { delete $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
/////////
|
//////////////////
|
||||||
// struct
|
// struct or union
|
||||||
/////////
|
//////////////////
|
||||||
|
|
||||||
struct_decl: struct_type struct_var_list ';' { delete astbuf2; }
|
struct_decl: struct_type struct_var_list ';' { delete astbuf2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
struct_type: TOK_STRUCT { astbuf2 = new AstNode(AST_STRUCT); } opt_packed '{' struct_member_list '}' { $$ = astbuf2; }
|
struct_type: struct_union { astbuf2 = new AstNode($1); } opt_packed '{' struct_member_list '}' { $$ = astbuf2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
struct_union:
|
||||||
|
TOK_STRUCT { $$ = AST_STRUCT; }
|
||||||
|
| TOK_UNION { $$ = AST_UNION; }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
opt_packed: TOK_PACKED opt_signed_struct
|
opt_packed: TOK_PACKED opt_signed_struct
|
||||||
| { frontend_verilog_yyerror("Only STRUCT PACKED supported at this time"); }
|
| { frontend_verilog_yyerror("Only PACKED supported at this time"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
opt_signed_struct:
|
opt_signed_struct:
|
||||||
TOK_SIGNED { astbuf2->is_signed = true; }
|
TOK_SIGNED { astbuf2->is_signed = true; }
|
||||||
| TOK_UNSIGNED
|
| TOK_UNSIGNED { astbuf2->is_signed = false; }
|
||||||
| // default is unsigned
|
| // default is unsigned
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -1532,11 +1541,13 @@ member_name_list:
|
||||||
member_name: TOK_ID {
|
member_name: TOK_ID {
|
||||||
astbuf1->str = $1->substr(1);
|
astbuf1->str = $1->substr(1);
|
||||||
delete $1;
|
delete $1;
|
||||||
astbuf2->children.push_back(astbuf1->clone());
|
auto member_node = astbuf1->clone();
|
||||||
|
SET_AST_NODE_LOC(member_node, @1, @1);
|
||||||
|
astbuf2->children.push_back(member_node);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
struct_member_type: { astbuf1 = new AstNode(AST_STRUCT_ITEM); } member_type_token_list { SET_RULE_LOC(@$, @2, @$); }
|
struct_member_type: { astbuf1 = new AstNode(AST_STRUCT_ITEM); } member_type_token_list
|
||||||
;
|
;
|
||||||
|
|
||||||
member_type_token_list:
|
member_type_token_list:
|
||||||
|
@ -1544,12 +1555,18 @@ member_type_token_list:
|
||||||
| hierarchical_type_id {
|
| hierarchical_type_id {
|
||||||
// use a clone of the typedef definition nodes
|
// use a clone of the typedef definition nodes
|
||||||
auto template_node = copyTypeDefinition(*$1);
|
auto template_node = copyTypeDefinition(*$1);
|
||||||
if (template_node->type != AST_WIRE) {
|
delete $1;
|
||||||
|
switch (template_node->type) {
|
||||||
|
case AST_WIRE:
|
||||||
|
template_node->type = AST_STRUCT_ITEM;
|
||||||
|
break;
|
||||||
|
case AST_STRUCT:
|
||||||
|
case AST_UNION:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
frontend_verilog_yyerror("Invalid type for struct member: %s", type2str(template_node->type).c_str());
|
frontend_verilog_yyerror("Invalid type for struct member: %s", type2str(template_node->type).c_str());
|
||||||
}
|
}
|
||||||
template_node->type = AST_STRUCT_ITEM;
|
|
||||||
delete astbuf1;
|
delete astbuf1;
|
||||||
delete $1;
|
|
||||||
astbuf1 = template_node;
|
astbuf1 = template_node;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -1565,6 +1582,7 @@ struct_var_list: struct_var
|
||||||
struct_var: TOK_ID { auto *var_node = astbuf2->clone();
|
struct_var: TOK_ID { auto *var_node = astbuf2->clone();
|
||||||
var_node->str = *$1;
|
var_node->str = *$1;
|
||||||
delete $1;
|
delete $1;
|
||||||
|
SET_AST_NODE_LOC(var_node, @1, @1);
|
||||||
ast_stack.back()->children.push_back(var_node);
|
ast_stack.back()->children.push_back(var_node);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
module top;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
byte a,b,c,d;
|
||||||
|
} byte4_t;
|
||||||
|
|
||||||
|
typedef union packed {
|
||||||
|
int x;
|
||||||
|
byte4_t y;
|
||||||
|
} w_t;
|
||||||
|
|
||||||
|
w_t w;
|
||||||
|
|
||||||
|
assign w.x = 'h42;
|
||||||
|
always_comb begin
|
||||||
|
assert(w.y.d == 8'h42);
|
||||||
|
end
|
||||||
|
|
||||||
|
typedef logic[4:0] reg_addr_t;
|
||||||
|
typedef logic[6:0] opcode_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
bit [6:0] func7;
|
||||||
|
reg_addr_t rs2;
|
||||||
|
reg_addr_t rs1;
|
||||||
|
bit [2:0] func3;
|
||||||
|
reg_addr_t rd;
|
||||||
|
opcode_t opcode;
|
||||||
|
} R_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
bit[11:0] imm;
|
||||||
|
reg_addr_t rs1;
|
||||||
|
bit[2:0] func3;
|
||||||
|
reg_addr_t rd;
|
||||||
|
opcode_t opcode;
|
||||||
|
} I_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
bit[19:0] imm;
|
||||||
|
reg_addr_t rd;
|
||||||
|
opcode_t opcode;
|
||||||
|
} U_t;
|
||||||
|
|
||||||
|
typedef union packed {
|
||||||
|
R_t r;
|
||||||
|
I_t i;
|
||||||
|
U_t u;
|
||||||
|
} instruction_t;
|
||||||
|
|
||||||
|
instruction_t ir1;
|
||||||
|
assign ir1 = 32'h0AA01EB7; // lui t4,0xAA01
|
||||||
|
always_comb begin
|
||||||
|
assert(ir1.u.opcode == 'h37);
|
||||||
|
assert(ir1.r.opcode == 'h37);
|
||||||
|
assert(ir1.u.rd == 'd29);
|
||||||
|
assert(ir1.r.rd == 'd29);
|
||||||
|
assert(ir1.u.imm == 'hAA01);
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
Loading…
Reference in New Issue