aboutsummaryrefslogtreecommitdiffstats
path: root/frontends
diff options
context:
space:
mode:
Diffstat (limited to 'frontends')
-rw-r--r--frontends/ast/ast.cc2
-rw-r--r--frontends/ast/ast.h1
-rw-r--r--frontends/ast/genrtlil.cc2
-rw-r--r--frontends/ast/simplify.cc86
-rw-r--r--frontends/json/jsonparse.cc34
-rw-r--r--frontends/verific/verific.cc69
-rw-r--r--frontends/verilog/verilog_lexer.l15
-rw-r--r--frontends/verilog/verilog_parser.y5
8 files changed, 161 insertions, 53 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 7be8ab565..6097f02f5 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -344,7 +344,7 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
}
if (!multirange_swapped.empty()) {
fprintf(f, " multirange_swapped=[");
- for (auto v : multirange_swapped)
+ for (bool v : multirange_swapped)
fprintf(f, " %d", v);
fprintf(f, " ]");
}
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 48ec9a063..80497c131 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -268,6 +268,7 @@ namespace AST
struct varinfo_t {
RTLIL::Const val;
int offset;
+ bool range_swapped;
bool is_signed;
AstNode *arg = nullptr;
bool explicitly_sized;
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 4c25287ad..020b4e5e8 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -877,7 +877,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
if (children.size() > 1)
range = children[1];
- } else if (id_ast->type == AST_STRUCT_ITEM) {
+ } else if (id_ast->type == AST_STRUCT_ITEM || id_ast->type == AST_STRUCT) {
AstNode *tmp_range = make_struct_member_range(this, id_ast);
this_width = tmp_range->range_left - tmp_range->range_right + 1;
delete tmp_range;
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 18b1e1e11..565025d3a 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -307,6 +307,10 @@ static int size_packed_struct(AstNode *snode, int base_offset)
if (node->type == AST_STRUCT || node->type == AST_UNION) {
// embedded struct or union
width = size_packed_struct(node, base_offset + offset);
+ // set range of struct
+ node->range_right = base_offset + offset;
+ node->range_left = base_offset + offset + width - 1;
+ node->range_valid = true;
}
else {
log_assert(node->type == AST_STRUCT_ITEM);
@@ -493,14 +497,12 @@ static void add_members_to_scope(AstNode *snode, std::string name)
// in case later referenced in assignments
log_assert(snode->type==AST_STRUCT || snode->type==AST_UNION);
for (auto *node : snode->children) {
+ auto member_name = name + "." + node->str;
+ current_scope[member_name] = node;
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;
- }
}
}
@@ -1341,6 +1343,16 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
case AST_PARAMETER:
case AST_LOCALPARAM:
+ // if parameter is implicit type which is the typename of a struct or union,
+ // save information about struct in wiretype attribute
+ if (children[0]->type == AST_IDENTIFIER && current_scope.count(children[0]->str) > 0) {
+ auto item_node = current_scope[children[0]->str];
+ if (item_node->type == AST_STRUCT || item_node->type == AST_UNION) {
+ attributes[ID::wiretype] = item_node->clone();
+ size_packed_struct(attributes[ID::wiretype], 0);
+ add_members_to_scope(attributes[ID::wiretype], str);
+ }
+ }
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);
@@ -2018,7 +2030,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (name_has_dot(str, sname)) {
if (current_scope.count(str) > 0) {
auto item_node = current_scope[str];
- if (item_node->type == AST_STRUCT_ITEM) {
+ if (item_node->type == AST_STRUCT_ITEM || item_node->type == AST_STRUCT) {
// structure member, rewrite this node to reference the packed struct wire
auto range = make_struct_member_range(this, item_node);
newNode = new AstNode(AST_IDENTIFIER, range);
@@ -2704,6 +2716,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
current_ast_mod->children.push_back(wire_data);
+ int shamt_width_hint = -1;
+ bool shamt_sign_hint = true;
+ shift_expr->detectSignWidth(shamt_width_hint, shamt_sign_hint);
+
+ AstNode *wire_sel = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(shamt_width_hint-1, true), mkconst_int(0, true)));
+ wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", filename.c_str(), location.first_line, autoidx++);
+ wire_sel->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
+ wire_sel->is_logic = true;
+ wire_sel->is_signed = shamt_sign_hint;
+ while (wire_sel->simplify(true, false, false, 1, -1, false, false)) { }
+ current_ast_mod->children.push_back(wire_sel);
+
did_something = true;
newNode = new AstNode(AST_BLOCK);
@@ -2720,39 +2744,44 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
ref_data->id2ast = wire_data;
ref_data->was_checked = true;
+ AstNode *ref_sel = new AstNode(AST_IDENTIFIER);
+ ref_sel->str = wire_sel->str;
+ ref_sel->id2ast = wire_sel;
+ ref_sel->was_checked = true;
+
AstNode *old_data = lvalue->clone();
if (type == AST_ASSIGN_LE)
old_data->lookahead = true;
- AstNode *shamt = shift_expr;
+ AstNode *s = new AstNode(AST_ASSIGN_EQ, ref_sel->clone(), shift_expr);
+ newNode->children.push_back(s);
- int shamt_width_hint = 0;
- bool shamt_sign_hint = true;
- shamt->detectSignWidth(shamt_width_hint, shamt_sign_hint);
+ AstNode *shamt = ref_sel;
+
+ // convert to signed while preserving the sign and value
+ shamt = new AstNode(AST_CAST_SIZE, mkconst_int(shamt_width_hint + 1, true), shamt);
+ shamt = new AstNode(AST_TO_SIGNED, shamt);
+ // offset the shift amount by the lower bound of the dimension
int start_bit = children[0]->id2ast->range_right;
- bool use_shift = shamt_sign_hint;
+ shamt = new AstNode(AST_SUB, shamt, mkconst_int(start_bit, true));
- if (start_bit != 0) {
- shamt = new AstNode(AST_SUB, shamt, mkconst_int(start_bit, true));
- use_shift = true;
- }
+ // reflect the shift amount if the dimension is swapped
+ if (children[0]->id2ast->range_swapped)
+ shamt = new AstNode(AST_SUB, mkconst_int(source_width - result_width, true), shamt);
+
+ // AST_SHIFT uses negative amounts for shifting left
+ shamt = new AstNode(AST_NEG, shamt);
AstNode *t;
t = mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false);
- if (use_shift)
- t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt->clone()));
- else
- t = new AstNode(AST_SHIFT_LEFT, t, shamt->clone());
+ t = new AstNode(AST_SHIFT, t, shamt->clone());
t = new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), t);
newNode->children.push_back(t);
t = new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone());
- if (use_shift)
- t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt));
- else
- t = new AstNode(AST_SHIFT_LEFT, t, shamt);
+ t = new AstNode(AST_SHIFT, t, shamt);
t = new AstNode(AST_ASSIGN_EQ, ref_data->clone(), t);
newNode->children.push_back(t);
@@ -5134,6 +5163,8 @@ bool AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia
width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
}
offset -= variables.at(str).offset;
+ if (variables.at(str).range_swapped)
+ offset = -offset;
std::vector<RTLIL::State> &var_bits = variables.at(str).val.bits;
std::vector<RTLIL::State> new_bits(var_bits.begin() + offset, var_bits.begin() + offset + width);
AstNode *newNode = mkconst_bits(new_bits, variables.at(str).is_signed);
@@ -5191,7 +5222,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
log_file_error(filename, location.first_line, "Incompatible re-declaration of constant function wire %s.\n", stmt->str.c_str());
}
variable.val = RTLIL::Const(RTLIL::State::Sx, width);
- variable.offset = min(stmt->range_left, stmt->range_right);
+ variable.offset = stmt->range_swapped ? stmt->range_left : stmt->range_right;
+ variable.range_swapped = stmt->range_swapped;
variable.is_signed = stmt->is_signed;
variable.explicitly_sized = stmt->children.size() &&
stmt->children.back()->type == AST_RANGE;
@@ -5276,8 +5308,12 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
int width = std::abs(range->range_left - range->range_right) + 1;
varinfo_t &v = variables[stmt->children.at(0)->str];
RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size());
- for (int i = 0; i < width; i++)
- v.val.bits.at(i+offset-v.offset) = r.bits.at(i);
+ for (int i = 0; i < width; i++) {
+ int index = i + offset - v.offset;
+ if (v.range_swapped)
+ index = -index;
+ v.val.bits.at(index) = r.bits.at(i);
+ }
}
delete block->children.front();
diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc
index 50c25abda..1aab81015 100644
--- a/frontends/json/jsonparse.cc
+++ b/frontends/json/jsonparse.cc
@@ -60,10 +60,38 @@ struct JsonNode
break;
if (ch == '\\') {
- int ch = f.get();
+ ch = f.get();
- if (ch == EOF)
- log_error("Unexpected EOF in JSON string.\n");
+ switch (ch) {
+ case EOF: log_error("Unexpected EOF in JSON string.\n"); break;
+ case '"':
+ case '/':
+ case '\\': break;
+ case 'b': ch = '\b'; break;
+ case 'f': ch = '\f'; break;
+ case 'n': ch = '\n'; break;
+ case 'r': ch = '\r'; break;
+ case 't': ch = '\t'; break;
+ case 'u':
+ int val = 0;
+ for (int i = 0; i < 4; i++) {
+ ch = f.get();
+ val <<= 4;
+ if (ch >= '0' && '9' >= ch) {
+ val += ch - '0';
+ } else if (ch >= 'A' && 'F' >= ch) {
+ val += 10 + ch - 'A';
+ } else if (ch >= 'a' && 'f' >= ch) {
+ val += 10 + ch - 'a';
+ } else
+ log_error("Unexpected non-digit character in \\uXXXX sequence: %c.\n", ch);
+ }
+ if (val < 128)
+ ch = val;
+ else
+ log_error("Unsupported \\uXXXX sequence in JSON string: %04X.\n", val);
+ break;
+ }
}
data_string += ch;
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index d5574f95a..8c2f7f0da 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -169,7 +169,10 @@ void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &att
FOREACH_ATTRIBUTE(obj, mi, attr) {
if (attr->Key()[0] == ' ' || attr->Value() == nullptr)
continue;
- attributes[RTLIL::escape_id(attr->Key())] = RTLIL::Const(std::string(attr->Value()));
+ std::string val = std::string(attr->Value());
+ if (val.size()>1 && val[0]=='\"' && val.back()=='\"')
+ val = val.substr(1,val.size()-2);
+ attributes[RTLIL::escape_id(attr->Key())] = RTLIL::Const(val);
}
if (nl) {
@@ -798,28 +801,14 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
}
if (inst->Type() == OPER_NTO1MUX) {
- cell = module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput()));
+ cell = module->addBmux(inst_name, IN2, IN1, net_map_at(inst->GetOutput()));
import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_NTO1MUX)
{
- SigSpec data = IN2, out = OUT;
-
- int wordsize_bits = ceil_log2(GetSize(out));
- int wordsize = 1 << wordsize_bits;
-
- SigSpec sel = {IN1, SigSpec(State::S0, wordsize_bits)};
-
- SigSpec padded_data;
- for (int i = 0; i < GetSize(data); i += GetSize(out)) {
- SigSpec d = data.extract(i, GetSize(out));
- d.extend_u0(wordsize);
- padded_data.append(d);
- }
-
- cell = module->addShr(inst_name, padded_data, sel, out);
+ cell = module->addBmux(inst_name, IN2, IN1, OUT);
import_attributes(cell->attributes, inst);
return true;
}
@@ -2310,9 +2299,11 @@ struct VerificPass : public Pass {
log("\n");
log("\n");
#endif
- log(" verific {-f|-F} <command-file>\n");
+ log(" verific {-f|-F} [-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv|-formal] <command-file>\n");
log("\n");
log("Load and execute the specified command file.\n");
+ log("Override verilog parsing mode can be set.\n");
+ log("The macros YOSYS, SYNTHESIS/FORMAL, and VERIFIC are defined implicitly.\n");
log("\n");
log("Command file parser supports following commands:\n");
log(" +define - defines macro\n");
@@ -2678,11 +2669,51 @@ struct VerificPass : public Pass {
if (GetSize(args) > argidx && (args[argidx] == "-f" || args[argidx] == "-F"))
{
unsigned verilog_mode = veri_file::VERILOG_95; // default recommended by Verific
+ bool is_formal = false;
+ const char* filename = nullptr;
Verific::veri_file::f_file_flags flags = (args[argidx] == "-f") ? veri_file::F_FILE_NONE : veri_file::F_FILE_CAPITAL;
- Array *file_names = veri_file::ProcessFFile(args[++argidx].c_str(), flags, verilog_mode);
+ for (argidx++; argidx < GetSize(args); argidx++) {
+ if (args[argidx] == "-vlog95") {
+ verilog_mode = veri_file::VERILOG_95;
+ continue;
+ } else if (args[argidx] == "-vlog2k") {
+ verilog_mode = veri_file::VERILOG_2K;
+ continue;
+ } else if (args[argidx] == "-sv2005") {
+ verilog_mode = veri_file::SYSTEM_VERILOG_2005;
+ continue;
+ } else if (args[argidx] == "-sv2009") {
+ verilog_mode = veri_file::SYSTEM_VERILOG_2009;
+ continue;
+ } else if (args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal") {
+ verilog_mode = veri_file::SYSTEM_VERILOG;
+ if (args[argidx] == "-formal") is_formal = true;
+ continue;
+ } else if (args[argidx].compare(0, 1, "-") == 0) {
+ cmd_error(args, argidx, "unknown option");
+ goto check_error;
+ }
+
+ if (!filename) {
+ filename = args[argidx].c_str();
+ continue;
+ } else {
+ log_cmd_error("Only one filename can be specified.\n");
+ }
+ }
+ if (!filename)
+ log_cmd_error("Filname must be specified.\n");
+
+ unsigned analysis_mode = verilog_mode; // keep default as provided by user if not defined in file
+ Array *file_names = veri_file::ProcessFFile(filename, flags, analysis_mode);
+ if (analysis_mode != verilog_mode)
+ log_warning("Provided verilog mode differs from one specified in file.\n");
+
+ veri_file::DefineMacro("YOSYS");
veri_file::DefineMacro("VERIFIC");
+ veri_file::DefineMacro(is_formal ? "FORMAL" : "SYNTHESIS");
if (!veri_file::AnalyzeMultipleFiles(file_names, verilog_mode, work.c_str(), veri_file::MFCU)) {
verific_error_msg.clear();
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 89c1aa895..958809319 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -128,6 +128,11 @@ static bool isUserType(std::string &s)
%x IMPORT_DPI
%x BASED_CONST
+UNSIGNED_NUMBER [0-9][0-9_]*
+FIXED_POINT_NUMBER_DEC [0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)?
+FIXED_POINT_NUMBER_NO_DEC [0-9][0-9_]*[eE][-+]?[0-9_]+
+TIME_SCALE_SUFFIX [munpf]?s
+
%%
// Initialise comment_caller to something to avoid a "maybe undefined"
// warning from GCC.
@@ -297,7 +302,7 @@ static bool isUserType(std::string &s)
"union" { SV_KEYWORD(TOK_UNION); }
"packed" { SV_KEYWORD(TOK_PACKED); }
-[0-9][0-9_]* {
+{UNSIGNED_NUMBER} {
yylval->string = new std::string(yytext);
return TOK_CONSTVAL;
}
@@ -319,12 +324,12 @@ static bool isUserType(std::string &s)
return TOK_BASED_CONSTVAL;
}
-[0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)? {
+{FIXED_POINT_NUMBER_DEC} {
yylval->string = new std::string(yytext);
return TOK_REALVAL;
}
-[0-9][0-9_]*[eE][-+]?[0-9_]+ {
+{FIXED_POINT_NUMBER_NO_DEC} {
yylval->string = new std::string(yytext);
return TOK_REALVAL;
}
@@ -574,6 +579,10 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
return TOK_SPECIFY_AND;
}
+{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
+{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
+{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
+
<INITIAL,BASED_CONST>"/*" { comment_caller=YY_START; BEGIN(COMMENT); }
<COMMENT>. /* ignore comment body */
<COMMENT>\n /* ignore comment body */
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 171e098a5..c533b0c40 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -369,7 +369,7 @@ static void rewriteGenForDeclInit(AstNode *loop)
%token TOK_BIT_OR_ASSIGN TOK_BIT_AND_ASSIGN TOK_BIT_XOR_ASSIGN TOK_ADD_ASSIGN
%token TOK_SUB_ASSIGN TOK_DIV_ASSIGN TOK_MOD_ASSIGN TOK_MUL_ASSIGN
%token TOK_SHL_ASSIGN TOK_SHR_ASSIGN TOK_SSHL_ASSIGN TOK_SSHR_ASSIGN
-%token TOK_BIND
+%token TOK_BIND TOK_TIME_SCALE
%type <ast> range range_or_multirange non_opt_range non_opt_multirange
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type
@@ -779,6 +779,9 @@ non_opt_delay:
'#' TOK_ID { delete $2; } |
'#' TOK_CONSTVAL { delete $2; } |
'#' TOK_REALVAL { delete $2; } |
+ // our `expr` doesn't have time_scale, so we need the parenthesized variant
+ '#' TOK_TIME_SCALE |
+ '#' '(' TOK_TIME_SCALE ')' |
'#' '(' mintypmax_expr ')' |
'#' '(' mintypmax_expr ',' mintypmax_expr ')' |
'#' '(' mintypmax_expr ',' mintypmax_expr ',' mintypmax_expr ')';