diff options
Diffstat (limited to 'frontends/ast/genrtlil.cc')
-rw-r--r-- | frontends/ast/genrtlil.cc | 167 |
1 files changed, 102 insertions, 65 deletions
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 71248663e..3e359170b 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -2,11 +2,11 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * + * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -176,13 +176,13 @@ struct AST_INTERNAL::ProcessGenerator RTLIL::Process *proc; RTLIL::SigSpec outputSignals; - // This always points to the RTLIL::CaseRule beeing filled at the moment + // This always points to the RTLIL::CaseRule being filled at the moment RTLIL::CaseRule *current_case; // This map contains the replacement pattern to be used in the right hand side // of an assignment. E.g. in the code "foo = bar; foo = func(foo);" the foo in the right // hand side of the 2nd assignment needs to be replace with the temporary signal holding - // the value assigned in the first assignment. So when the first assignement is processed + // the value assigned in the first assignment. So when the first assignment is processed // the according information is appended to subst_rvalue_from and subst_rvalue_to. stackmap<RTLIL::SigBit, RTLIL::SigBit> subst_rvalue_map; @@ -192,7 +192,7 @@ struct AST_INTERNAL::ProcessGenerator // signal that is used as input for the register that drives the signal foo. stackmap<RTLIL::SigBit, RTLIL::SigBit> subst_lvalue_map; - // The code here generates a number of temprorary signal for each output register. This + // The code here generates a number of temporary signal for each output register. This // map helps generating nice numbered names for all this temporary signals. std::map<RTLIL::Wire*, int> new_temp_count; @@ -338,12 +338,14 @@ struct AST_INTERNAL::ProcessGenerator case AST_CASE: for (auto child : ast->children) if (child != ast->children[0]) { - log_assert(child->type == AST_COND); + log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); collect_lvalues(reg, child, type_eq, type_le, false); } break; case AST_COND: + case AST_CONDX: + case AST_CONDZ: case AST_ALWAYS: case AST_INITIAL: for (auto child : ast->children) @@ -379,7 +381,7 @@ struct AST_INTERNAL::ProcessGenerator // e.g. when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this // function is called to clean up the first two assignments as they are overwritten by // the third assignment. - void removeSignalFromCaseTree(const std::set<RTLIL::SigBit> &pattern, RTLIL::CaseRule *cs) + void removeSignalFromCaseTree(const RTLIL::SigSpec &pattern, RTLIL::CaseRule *cs) { for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) it->first.remove2(pattern, &it->second); @@ -427,6 +429,17 @@ struct AST_INTERNAL::ProcessGenerator { RTLIL::SigSpec unmapped_lvalue = ast->children[0]->genRTLIL(), lvalue = unmapped_lvalue; RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.size(), &subst_rvalue_map.stdmap()); + + pool<SigBit> lvalue_sigbits; + for (int i = 0; i < GetSize(lvalue); i++) { + if (lvalue_sigbits.count(lvalue[i]) > 0) { + unmapped_lvalue.remove(i); + lvalue.remove(i); + rvalue.remove(i--); + } else + lvalue_sigbits.insert(lvalue[i]); + } + lvalue.replace(subst_lvalue_map.stdmap()); if (ast->type == AST_ASSIGN_EQ) { @@ -434,7 +447,7 @@ struct AST_INTERNAL::ProcessGenerator subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]); } - removeSignalFromCaseTree(lvalue.to_sigbit_set(), current_case); + removeSignalFromCaseTree(lvalue, current_case); remove_unwanted_lvalue_bits(lvalue, rvalue); current_case->actions.push_back(RTLIL::SigSig(lvalue, rvalue)); } @@ -467,7 +480,7 @@ struct AST_INTERNAL::ProcessGenerator { if (child == ast->children[0]) continue; - log_assert(child->type == AST_COND); + log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); subst_lvalue_map.save(); subst_rvalue_map.save(); @@ -511,7 +524,7 @@ struct AST_INTERNAL::ProcessGenerator subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]); this_case_eq_lvalue.replace(subst_lvalue_map.stdmap()); - removeSignalFromCaseTree(this_case_eq_lvalue.to_sigbit_set(), current_case); + removeSignalFromCaseTree(this_case_eq_lvalue, current_case); addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp); } break; @@ -520,6 +533,11 @@ struct AST_INTERNAL::ProcessGenerator log_error("Found wire declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum); break; + case AST_PARAMETER: + case AST_LOCALPARAM: + log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum); + break; + case AST_TCALL: case AST_FOR: break; @@ -547,14 +565,14 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun switch (type) { case AST_CONSTANT: - width_hint = std::max(width_hint, int(bits.size())); + width_hint = max(width_hint, int(bits.size())); if (!is_signed) sign_hint = false; break; case AST_REALVALUE: *found_real = true; - width_hint = std::max(width_hint, 32); + width_hint = max(width_hint, 32); break; case AST_IDENTIFIER: @@ -567,9 +585,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) { this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1; } else - if (id_ast->children[0]->type == AST_CONSTANT) { + if (id_ast->children[0]->type != AST_CONSTANT) + while (id_ast->simplify(true, false, false, 1, -1, false, true)) { } + if (id_ast->children[0]->type == AST_CONSTANT) this_width = id_ast->children[0]->bits.size(); - } else + else log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum); if (children.size() != 0) range = children[0]; @@ -582,7 +602,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun // log("---\n"); // id_ast->dumpAst(NULL, "decl> "); // dumpAst(NULL, "ref> "); - log_error("Failed to detect with of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_error("Failed to detect width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); } } else { this_width = id_ast->range_left - id_ast->range_right + 1; @@ -593,7 +613,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun this_width = 32; } else if (id_ast->type == AST_MEMORY) { if (!id_ast->children[0]->range_valid) - log_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; } else log_error("Failed to detect width for identifier %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum); @@ -615,7 +635,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun this_width = range->range_left - range->range_right + 1; sign_hint = false; } - width_hint = std::max(width_hint, this_width); + width_hint = max(width_hint, this_width); if (!id_ast->is_signed) sign_hint = false; break; @@ -625,7 +645,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (children[0]->type != AST_CONSTANT) log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum); children[1]->detectSignWidthWorker(sub_width_hint, sign_hint); - width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int()); + width_hint = max(width_hint, children[0]->bitsAsConst().as_int()); break; case AST_TO_SIGNED: @@ -644,7 +664,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun child->detectSignWidthWorker(sub_width_hint, sub_sign_hint); this_width += sub_width_hint; } - width_hint = std::max(width_hint, this_width); + width_hint = max(width_hint, this_width); sign_hint = false; break; @@ -653,7 +673,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (children[0]->type != AST_CONSTANT) log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum); children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint); - width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint); + width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint); sign_hint = false; break; @@ -676,7 +696,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_REDUCE_XOR: case AST_REDUCE_XNOR: case AST_REDUCE_BOOL: - width_hint = std::max(width_hint, 1); + width_hint = max(width_hint, 1); sign_hint = false; break; @@ -696,7 +716,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_NEX: case AST_GE: case AST_GT: - width_hint = std::max(width_hint, 1); + width_hint = max(width_hint, 1); sign_hint = false; break; @@ -712,7 +732,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_LOGIC_AND: case AST_LOGIC_OR: case AST_LOGIC_NOT: - width_hint = std::max(width_hint, 1); + width_hint = max(width_hint, 1); sign_hint = false; break; @@ -725,9 +745,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (!id2ast->is_signed) sign_hint = false; if (!id2ast->children[0]->range_valid) - log_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1; - width_hint = std::max(width_hint, this_width); + width_hint = max(width_hint, this_width); break; // everything should have been handled above -> print error if not. @@ -764,7 +784,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // in the following big switch() statement there are some uses of // Clifford's Device (http://www.clifford.at/cfun/cliffdev/). In this // cases this variable is used to hold the type of the cell that should - // be instanciated for this type of AST node. + // be instantiated for this type of AST node. std::string type_name; current_filename = filename; @@ -773,7 +793,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) switch (type) { // simply ignore this nodes. - // they are eighter leftovers from simplify() or are referenced by other nodes + // they are either leftovers from simplify() or are referenced by other nodes // and are only accessed here thru this references case AST_TASK: case AST_FUNCTION: @@ -786,6 +806,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_GENBLOCK: case AST_GENIF: case AST_GENCASE: + case AST_PACKAGE: break; // remember the parameter, needed for example in techmap @@ -1052,7 +1073,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) detectSignWidth(width_hint, sign_hint); RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint); RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint); - int width = std::max(left.size(), right.size()); + int width = max(left.size(), right.size()); if (width_hint > 0) width = width_hint; is_signed = children[0]->is_signed && children[1]->is_signed; @@ -1066,16 +1087,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (0) { case AST_REDUCE_XNOR: type_name = "$reduce_xnor"; } { RTLIL::SigSpec arg = children[0]->genRTLIL(); - RTLIL::SigSpec sig = uniop2rtlil(this, type_name, std::max(width_hint, 1), arg); + RTLIL::SigSpec sig = uniop2rtlil(this, type_name, max(width_hint, 1), arg); return sig; } // generate cells for unary operations: $reduce_bool - // (this is actually just an $reduce_or, but for clearity a different cell type is used) + // (this is actually just an $reduce_or, but for clarity a different cell type is used) if (0) { case AST_REDUCE_BOOL: type_name = "$reduce_bool"; } { RTLIL::SigSpec arg = children[0]->genRTLIL(); - RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, std::max(width_hint, 1), arg) : arg; + RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, max(width_hint, 1), arg) : arg; return sig; } @@ -1121,7 +1142,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (0) { case AST_GE: type_name = "$ge"; } if (0) { case AST_GT: type_name = "$gt"; } { - int width = std::max(width_hint, 1); + int width = max(width_hint, 1); width_hint = -1, sign_hint = true; children[0]->detectSignWidthWorker(width_hint, sign_hint); children[1]->detectSignWidthWorker(width_hint, sign_hint); @@ -1143,7 +1164,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint); RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint); #if 0 - int width = std::max(left.size(), right.size()); + int width = max(left.size(), right.size()); if (width > width_hint && width_hint > 0) width = width_hint; if (width < width_hint) { @@ -1152,10 +1173,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (type == AST_SUB && (!children[0]->is_signed || !children[1]->is_signed)) width = width_hint; if (type == AST_MUL) - width = std::min(left.size() + right.size(), width_hint); + width = min(left.size() + right.size(), width_hint); } #else - int width = std::max(std::max(left.size(), right.size()), width_hint); + int width = max(max(left.size(), right.size()), width_hint); #endif is_signed = children[0]->is_signed && children[1]->is_signed; return binop2rtlil(this, type_name, width, left, right); @@ -1167,14 +1188,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) { RTLIL::SigSpec left = children[0]->genRTLIL(); RTLIL::SigSpec right = children[1]->genRTLIL(); - return binop2rtlil(this, type_name, std::max(width_hint, 1), left, right); + return binop2rtlil(this, type_name, max(width_hint, 1), left, right); } // generate cells for unary operations: $logic_not case AST_LOGIC_NOT: { RTLIL::SigSpec arg = children[0]->genRTLIL(); - return uniop2rtlil(this, "$logic_not", std::max(width_hint, 1), arg); + return uniop2rtlil(this, "$logic_not", max(width_hint, 1), arg); } // generate multiplexer for ternary operator (aka ?:-operator) @@ -1190,7 +1211,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (cond.size() > 1) cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false); - int width = std::max(val1.size(), val2.size()); + int width = max(val1.size(), val2.size()); is_signed = children[1]->is_signed && children[2]->is_signed; widthExtend(this, val1, width, is_signed); widthExtend(this, val2, width, is_signed); @@ -1214,11 +1235,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_DATA", current_module->memories[str]->width); wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - int addr_bits = 1; - while ((1 << addr_bits) < current_module->memories[str]->size) - addr_bits++; + int mem_width, mem_size, addr_bits; + id2ast->meminfo(mem_width, mem_size, addr_bits); cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1)); + cell->setPort("\\EN", RTLIL::SigSpec(RTLIL::State::Sx, 1)); cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits)); cell->setPort("\\DATA", RTLIL::SigSpec(wire)); @@ -1235,28 +1256,38 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // generate $memwr cells for memory write ports case AST_MEMWR: + case AST_MEMINIT: { std::stringstream sstr; - sstr << "$memwr$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); + sstr << (type == AST_MEMWR ? "$memwr$" : "$meminit$") << str << "$" << filename << ":" << linenum << "$" << (autoidx++); - RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$memwr"); + RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_MEMWR ? "$memwr" : "$meminit"); cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - int addr_bits = 1; - while ((1 << addr_bits) < current_module->memories[str]->size) - addr_bits++; + int mem_width, mem_size, addr_bits; + id2ast->meminfo(mem_width, mem_size, addr_bits); + + int num_words = 1; + if (type == AST_MEMINIT) { + if (children[2]->type != AST_CONSTANT) + log_error("Memory init with non-constant word count at %s:%d!\n", filename.c_str(), linenum); + num_words = int(children[2]->asInt(false)); + cell->parameters["\\WORDS"] = RTLIL::Const(num_words); + } - cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1)); cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits)); - cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width)); - cell->setPort("\\EN", children[2]->genRTLIL()); + cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words)); cell->parameters["\\MEMID"] = RTLIL::Const(str); cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits); cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width); - cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0); - cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0); + if (type == AST_MEMWR) { + cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1)); + cell->setPort("\\EN", children[2]->genRTLIL()); + cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0); + cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0); + } cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1); } @@ -1264,19 +1295,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // generate $assert cells case AST_ASSERT: + case AST_ASSUME: { log_assert(children.size() == 2); RTLIL::SigSpec check = children[0]->genRTLIL(); - log_assert(check.size() == 1); + if (GetSize(check) != 1) + check = current_module->ReduceBool(NEW_ID, check); RTLIL::SigSpec en = children[1]->genRTLIL(); - log_assert(en.size() == 1); + if (GetSize(en) != 1) + en = current_module->ReduceBool(NEW_ID, en); std::stringstream sstr; - sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++); + sstr << (type == AST_ASSERT ? "$assert$" : "$assume$") << filename << ":" << linenum << "$" << (autoidx++); - RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$assert"); + RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_ASSERT ? "$assert" : "$assume"); cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); for (auto &attr : attributes) { @@ -1335,16 +1369,19 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) continue; } if (child->type == AST_PARASET) { - if (child->children[0]->type != AST_CONSTANT) - log_error("Parameter `%s' with non-constant value at %s:%d!\n", - child->str.c_str(), filename.c_str(), linenum); - if (child->str.size() == 0) { - char buf[100]; - snprintf(buf, 100, "$%d", ++para_counter); - cell->parameters[buf] = child->children[0]->asParaConst(); - } else { - cell->parameters[child->str] = child->children[0]->asParaConst(); + IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; + if (child->children[0]->type == AST_REALVALUE) { + log_warning("Replacing floating point parameter %s.%s = %f with string at %s:%d.\n", + log_id(cell), log_id(paraname), child->children[0]->realvalue, + filename.c_str(), linenum); + auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue)); + strnode->cloneInto(child->children[0]); + delete strnode; } + if (child->children[0]->type != AST_CONSTANT) + log_error("Parameter %s.%s with non-constant value at %s:%d!\n", + log_id(cell), log_id(paraname), filename.c_str(), linenum); + cell->parameters[paraname] = child->children[0]->asParaConst(); continue; } if (child->type == AST_ARGUMENT) { @@ -1398,7 +1435,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } // this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or -// signals must be substituted before beeing used as input values (used by ProcessGenerator) +// signals must be substituted before being used as input values (used by ProcessGenerator) // note that this is using some global variables to communicate this special settings to AstNode::genRTLIL(). RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr) { |