diff options
Diffstat (limited to 'frontends')
-rw-r--r-- | frontends/ast/ast.cc | 10 | ||||
-rw-r--r-- | frontends/ast/ast.h | 4 | ||||
-rw-r--r-- | frontends/ast/genrtlil.cc | 136 | ||||
-rw-r--r-- | frontends/ast/simplify.cc | 128 | ||||
-rw-r--r-- | frontends/ilang/ilang_parser.y | 11 | ||||
-rw-r--r-- | frontends/rpc/rpc_frontend.cc | 2 | ||||
-rw-r--r-- | frontends/verilog/verilog_parser.y | 6 |
7 files changed, 269 insertions, 28 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 245a53611..733556621 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -218,6 +218,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch realvalue = 0; id2ast = NULL; basic_prep = false; + lookahead = false; if (child1) children.push_back(child1); @@ -310,6 +311,10 @@ void AstNode::dumpAst(FILE *f, std::string indent) const fprintf(f, " reg"); if (is_signed) fprintf(f, " signed"); + if (basic_prep) + fprintf(f, " basic_prep"); + if (lookahead) + fprintf(f, " lookahead"); if (port_id > 0) fprintf(f, " port=%d", port_id); if (range_valid || range_left != -1 || range_right != 0) @@ -1069,8 +1074,6 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast if (child->type == AST_WIRE && (child->is_input || child->is_output)) { new_children.push_back(child); } else if (child->type == AST_PARAMETER) { - child->delete_children(); - child->children.push_back(AstNode::mkconst_int(0, false, 0)); new_children.push_back(child); } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE && (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) { @@ -1565,6 +1568,9 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id rewritten.reserve(GetSize(parameters)); AstNode *new_ast = ast->clone(); + if (!new_ast->attributes.count(ID::hdlname)) + new_ast->attributes[ID::hdlname] = AstNode::mkconst_str(stripped_name); + para_counter = 0; for (auto child : new_ast->children) { if (child->type != AST_PARAMETER) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 3dd40238f..3f6329112 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -202,6 +202,9 @@ namespace AST // this is used by simplify to detect if basic analysis has been performed already on the node bool basic_prep; + // this is used for ID references in RHS expressions that should use the "new" value for non-blocking assignments + bool lookahead; + // this is the original sourcecode location that resulted in this AST node // it is automatically set by the constructor using AST::current_filename and // the AST::get_line_num() callback function. @@ -352,6 +355,7 @@ namespace AST_INTERNAL extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child; extern AST::AstModule *current_module; extern bool current_always_clocked; + struct LookaheadRewriter; struct ProcessGenerator; } diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index ab368fdb0..d35335747 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -157,6 +157,126 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const return wire; } +// helper class for rewriting simple lookahead references in AST always blocks +struct AST_INTERNAL::LookaheadRewriter +{ + dict<IdString, pair<AstNode*, AstNode*>> lookaheadids; + + void collect_lookaheadids(AstNode *node) + { + if (node->lookahead) { + log_assert(node->type == AST_IDENTIFIER); + if (!lookaheadids.count(node->str)) { + AstNode *wire = new AstNode(AST_WIRE); + for (auto c : node->id2ast->children) + wire->children.push_back(c->clone()); + wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); + wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire->is_logic = true; + while (wire->simplify(true, false, false, 1, -1, false, false)) { } + current_ast_mod->children.push_back(wire); + lookaheadids[node->str] = make_pair(node->id2ast, wire); + wire->genRTLIL(); + } + } + + for (auto child : node->children) + collect_lookaheadids(child); + } + + bool has_lookaheadids(AstNode *node) + { + if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) != 0) + return true; + + for (auto child : node->children) + if (has_lookaheadids(child)) + return true; + + return false; + } + + bool has_nonlookaheadids(AstNode *node) + { + if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) == 0) + return true; + + for (auto child : node->children) + if (has_nonlookaheadids(child)) + return true; + + return false; + } + + void rewrite_lookaheadids(AstNode *node, bool lhs = false) + { + if (node->type == AST_ASSIGN_LE) + { + if (has_lookaheadids(node->children[0])) + { + if (has_nonlookaheadids(node->children[0])) + log_error("incompatible mix of lookahead and non-lookahead IDs in LHS expression.\n"); + + rewrite_lookaheadids(node->children[0], true); + node->type = AST_ASSIGN_EQ; + } + + rewrite_lookaheadids(node->children[1], lhs); + return; + } + + if (node->type == AST_IDENTIFIER && (node->lookahead || lhs)) { + AstNode *newwire = lookaheadids.at(node->str).second; + node->str = newwire->str; + node->id2ast = newwire; + lhs = false; + } + + for (auto child : node->children) + rewrite_lookaheadids(child, lhs); + } + + LookaheadRewriter(AstNode *top) + { + // top->dumpAst(NULL, "REWRITE-BEFORE> "); + // top->dumpVlog(NULL, "REWRITE-BEFORE> "); + + AstNode *block = nullptr; + + for (auto c : top->children) + if (c->type == AST_BLOCK) { + log_assert(block == nullptr); + block = c; + } + log_assert(block != nullptr); + + collect_lookaheadids(block); + rewrite_lookaheadids(block); + + for (auto it : lookaheadids) + { + AstNode *ref_orig = new AstNode(AST_IDENTIFIER); + ref_orig->str = it.second.first->str; + ref_orig->id2ast = it.second.first; + ref_orig->was_checked = true; + + AstNode *ref_temp = new AstNode(AST_IDENTIFIER); + ref_temp->str = it.second.second->str; + ref_temp->id2ast = it.second.second; + ref_temp->was_checked = true; + + AstNode *init_assign = new AstNode(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone()); + AstNode *final_assign = new AstNode(AST_ASSIGN_LE, ref_orig, ref_temp); + + block->children.insert(block->children.begin(), init_assign); + block->children.push_back(final_assign); + } + + // top->dumpAst(NULL, "REWRITE-AFTER> "); + // top->dumpVlog(NULL, "REWRITE-AFTER> "); + } +}; + // helper class for converting AST always nodes to RTLIL processes struct AST_INTERNAL::ProcessGenerator { @@ -191,6 +311,9 @@ struct AST_INTERNAL::ProcessGenerator ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg) { + // rewrite lookahead references + LookaheadRewriter la_rewriter(always); + // generate process and simple root case proc = new RTLIL::Process; proc->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", always->filename.c_str(), always->location.first_line, always->location.first_column, always->location.last_line, always->location.last_column); @@ -338,7 +461,7 @@ struct AST_INTERNAL::ProcessGenerator return chunks; } - // recursively traverse the AST an collect all assigned signals + // recursively traverse the AST and collect all assigned signals void collect_lvalues(RTLIL::SigSpec ®, AstNode *ast, bool type_eq, bool type_le, bool run_sort_and_unify = true) { switch (ast->type) @@ -892,7 +1015,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // remember the parameter, needed for example in techmap case AST_PARAMETER: - current_module->avail_parameters.insert(str); + current_module->avail_parameters(str); + if (GetSize(children) >= 1 && children[0]->type == AST_CONSTANT) { + current_module->parameter_default_values[str] = children[0]->asParaConst(); + } /* fall through */ case AST_LOCALPARAM: if (flag_pwires) @@ -1010,7 +1136,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int add_undef_bits_msb = 0; int add_undef_bits_lsb = 0; - if (id2ast && id2ast->type == AST_AUTOWIRE && current_module->wires_.count(str) == 0) { + log_assert(id2ast != nullptr); + + if (id2ast->type == AST_AUTOWIRE && current_module->wires_.count(str) == 0) { RTLIL::Wire *wire = current_module->addWire(str); wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); wire->name = str; @@ -1025,7 +1153,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk = RTLIL::Const(id2ast->children[0]->bits); goto use_const_chunk; } - else if (id2ast && (id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE || id2ast->type == AST_MEMORY) && current_module->wires_.count(str) != 0) { + else if ((id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE || id2ast->type == AST_MEMORY) && current_module->wires_.count(str) != 0) { RTLIL::Wire *current_wire = current_module->wire(str); if (current_wire->get_bool_attribute(ID::is_interface)) is_interface = true; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 372dcf95c..837c14ad7 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -64,6 +64,21 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg continue; } + bool got_len = false; + bool got_zlen = false; + int len_value = 0; + + while ('0' <= cformat && cformat <= '9') + { + if (!got_len && cformat == '0') + got_zlen = true; + + got_len = true; + len_value = 10*len_value + (cformat - '0'); + + cformat = sformat[++i]; + } + // Simplify the argument AstNode *node_arg = nullptr; @@ -74,6 +89,9 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg case 'S': case 'd': case 'D': + if (got_len) + goto unsupported_format; + /* fall through */ case 'x': case 'X': if (next_arg >= GetSize(children)) @@ -88,9 +106,12 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg case 'm': case 'M': + if (got_len) + goto unsupported_format; break; default: + unsupported_format: log_file_error(filename, location.first_line, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str()); break; } @@ -104,19 +125,28 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg case 'd': case 'D': - { - char tmp[128]; - snprintf(tmp, sizeof(tmp), "%d", node_arg->bitsAsConst().as_int()); - sout += tmp; - } + sout += stringf("%d", node_arg->bitsAsConst().as_int()); break; case 'x': case 'X': { - char tmp[128]; - snprintf(tmp, sizeof(tmp), "%x", node_arg->bitsAsConst().as_int()); - sout += tmp; + Const val = node_arg->bitsAsConst(); + + while (GetSize(val) % 4 != 0) + val.bits.push_back(State::S0); + + int len = GetSize(val) / 4; + for (int i = len; i < len_value; i++) + sout += got_zlen ? '0' : ' '; + + for (int i = len-1; i >= 0; i--) { + Const digit = val.extract(4*i, 4); + if (digit.is_fully_def()) + sout += stringf(cformat == 'x' ? "%x" : "%X", digit.as_int()); + else + sout += cformat == 'x' ? "x" : "X"; + } } break; @@ -1724,8 +1754,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } // replace dynamic ranges in left-hand side expressions (e.g. "foo[bar] <= 1'b1;") with - // a big case block that selects the correct single-bit assignment. - if (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) { + // either a big case block that selects the correct single-bit assignment, or mask and + // shift operations. + if (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) + { if (children[0]->type != AST_IDENTIFIER || children[0]->children.size() == 0) goto skip_dynamic_range_lvalue_expansion; if (children[0]->children[0]->range_valid || did_something) @@ -1734,10 +1766,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, goto skip_dynamic_range_lvalue_expansion; if (!children[0]->id2ast->range_valid) goto skip_dynamic_range_lvalue_expansion; + int source_width = children[0]->id2ast->range_left - children[0]->id2ast->range_right + 1; int result_width = 1; + AstNode *shift_expr = NULL; AstNode *range = children[0]->children[0]; + if (range->children.size() == 1) { shift_expr = range->children[0]->clone(); } else { @@ -1750,19 +1785,72 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, log_file_error(filename, location.first_line, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; } - did_something = true; - newNode = new AstNode(AST_CASE, shift_expr); - for (int i = 0; i < source_width; i++) { - int start_bit = children[0]->id2ast->range_right + i; - AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true)); + + if (0) + { + // big case block + + did_something = true; + newNode = new AstNode(AST_CASE, shift_expr); + for (int i = 0; i < source_width; i++) { + int start_bit = children[0]->id2ast->range_right + i; + AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true)); + AstNode *lvalue = children[0]->clone(); + lvalue->delete_children(); + int end_bit = std::min(start_bit+result_width,source_width) - 1; + lvalue->children.push_back(new AstNode(AST_RANGE, + mkconst_int(end_bit, true), mkconst_int(start_bit, true))); + cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); + newNode->children.push_back(cond); + } + } + else + { + // mask and shift operations, disabled for now + + AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); + wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", filename.c_str(), location.first_line, autoidx++); + wire_mask->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire_mask->is_logic = true; + while (wire_mask->simplify(true, false, false, 1, -1, false, false)) { } + current_ast_mod->children.push_back(wire_mask); + + AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); + wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", filename.c_str(), location.first_line, autoidx++); + wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire_data->is_logic = true; + while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } + current_ast_mod->children.push_back(wire_data); + + did_something = true; + newNode = new AstNode(AST_BLOCK); + AstNode *lvalue = children[0]->clone(); lvalue->delete_children(); - int end_bit = std::min(start_bit+result_width,source_width) - 1; - lvalue->children.push_back(new AstNode(AST_RANGE, - mkconst_int(end_bit, true), mkconst_int(start_bit, true))); - cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); - newNode->children.push_back(cond); + + AstNode *ref_mask = new AstNode(AST_IDENTIFIER); + ref_mask->str = wire_mask->str; + ref_mask->id2ast = wire_mask; + ref_mask->was_checked = true; + + AstNode *ref_data = new AstNode(AST_IDENTIFIER); + ref_data->str = wire_data->str; + ref_data->id2ast = wire_data; + ref_data->was_checked = true; + + AstNode *old_data = lvalue->clone(); + if (type == AST_ASSIGN_LE) + old_data->lookahead = true; + + AstNode *shamt = shift_expr; + + newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), + new AstNode(AST_SHIFT_LEFT, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), shamt->clone()))); + newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_data->clone(), + new AstNode(AST_SHIFT_LEFT, new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()), shamt))); + newNode->children.push_back(new AstNode(type, lvalue, new AstNode(AST_BIT_OR, new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)), ref_data))); } + goto apply_newNode; } skip_dynamic_range_lvalue_expansion:; diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y index 0522fa72a..8e21fb176 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/ilang/ilang_parser.y @@ -143,11 +143,18 @@ module_body: /* empty */; module_stmt: - param_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; + param_stmt | param_defval_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; param_stmt: TOK_PARAMETER TOK_ID EOL { - current_module->avail_parameters.insert($2); + current_module->avail_parameters($2); + free($2); + }; + +param_defval_stmt: + TOK_PARAMETER TOK_ID constant EOL { + current_module->avail_parameters($2); + current_module->parameter_default_values[$2] = *$3; free($2); }; diff --git a/frontends/rpc/rpc_frontend.cc b/frontends/rpc/rpc_frontend.cc index a23f7548e..46ee6a733 100644 --- a/frontends/rpc/rpc_frontend.cc +++ b/frontends/rpc/rpc_frontend.cc @@ -217,6 +217,8 @@ struct RpcModule : RTLIL::Module { module.second->name = mangled_name; module.second->design = design; module.second->attributes.erase(ID::top); + if (!module.second->has_attribute(ID::hdlname)) + module.second->set_string_attribute(ID::hdlname, module.first.str()); design->modules_[mangled_name] = module.second; derived_design->modules_.erase(module.first); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 76373c2e4..4a5aba79e 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1924,11 +1924,13 @@ always_events: always_event: TOK_POSEDGE expr { AstNode *node = new AstNode(AST_POSEDGE); + SET_AST_NODE_LOC(node, @1, @1); ast_stack.back()->children.push_back(node); node->children.push_back($2); } | TOK_NEGEDGE expr { AstNode *node = new AstNode(AST_NEGEDGE); + SET_AST_NODE_LOC(node, @1, @1); ast_stack.back()->children.push_back(node); node->children.push_back($2); } | @@ -2244,6 +2246,7 @@ behavioral_stmt: exitTypeScope(); if ($4 != NULL && $8 != NULL && *$4 != *$8) frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $4->c_str()+1, $8->c_str()+1); + SET_AST_NODE_LOC(ast_stack.back(), @2, @8); delete $4; delete $8; ast_stack.pop_back(); @@ -2618,6 +2621,7 @@ basic_expr: bits->str = *$1; SET_AST_NODE_LOC(bits, @1, @1); AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); + SET_AST_NODE_LOC(val, @2, @2); if (val == NULL) log_error("Value conversion failed: `%s'\n", $2->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); @@ -2626,6 +2630,7 @@ basic_expr: } | integral_number { $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); + SET_AST_NODE_LOC($$, @1, @1); if ($$ == NULL) log_error("Value conversion failed: `%s'\n", $1->c_str()); delete $1; @@ -2644,6 +2649,7 @@ basic_expr: } | TOK_STRING { $$ = AstNode::mkconst_str(*$1); + SET_AST_NODE_LOC($$, @1, @1); delete $1; } | hierarchical_id attr { |