diff options
46 files changed, 2101 insertions, 77 deletions
@@ -737,6 +737,7 @@ test: $(TARGETS) $(EXTRA_TARGETS) +cd tests/arch/efinix && bash run-test.sh $(SEEDOPT) +cd tests/arch/anlogic && bash run-test.sh $(SEEDOPT) +cd tests/arch/gowin && bash run-test.sh $(SEEDOPT) + +cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT) +cd tests/rpc && bash run-test.sh +cd tests/memfile && bash run-test.sh @echo "" diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 3b51d8685..3c7c745fe 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -280,6 +280,10 @@ struct XAigerWriter if (abc9_flop) continue; } + else { + if (cell->type == ID($__ABC9_DELAY)) + log_error("Cell type '%s' not recognised. Check that '+/abc9_model.v' has been read.\n", cell->type.c_str()); + } bool cell_known = inst_module || cell->known(); for (const auto &c : cell->connections()) { diff --git a/backends/cxxrtl/cxxrtl.cc b/backends/cxxrtl/cxxrtl.cc index 465882858..d1a855bf0 100644 --- a/backends/cxxrtl/cxxrtl.cc +++ b/backends/cxxrtl/cxxrtl.cc @@ -357,13 +357,19 @@ struct FlowGraph { }; struct CxxrtlWorker { + bool split_intf = false; + std::string intf_filename; + std::string design_ns = "cxxrtl_design"; + std::ostream *impl_f = nullptr; + std::ostream *intf_f = nullptr; + bool elide_internal = false; bool elide_public = false; bool localize_internal = false; bool localize_public = false; bool run_splitnets = false; - std::ostream &f; + std::ostringstream f; std::string indent; int temporary = 0; @@ -377,8 +383,6 @@ struct CxxrtlWorker { dict<const RTLIL::Module*, std::vector<FlowGraph::Node>> schedule; pool<const RTLIL::Wire*> localized_wires; - CxxrtlWorker(std::ostream &f) : f(f) {} - void inc_indent() { indent += "\t"; } @@ -867,7 +871,8 @@ struct CxxrtlWorker { dump_sigspec_rhs(cell->getPort(ID(ADDR))); f << ", " << memory->start_offset << ", " << memory->size << ");\n"; if (cell->type == ID($memrd)) { - if (!cell->getPort(ID(EN)).is_fully_ones()) { + bool has_enable = cell->getParam(ID(CLK_ENABLE)).as_bool() && !cell->getPort(ID(EN)).is_fully_ones(); + if (has_enable) { f << indent << "if ("; dump_sigspec_rhs(cell->getPort(ID(EN))); f << ") {\n"; @@ -926,7 +931,7 @@ struct CxxrtlWorker { f << " = value<" << memory->width << "> {};\n"; dec_indent(); f << indent << "}\n"; - if (!cell->getPort(ID(EN)).is_fully_ones()) { + if (has_enable) { dec_indent(); f << indent << "}\n"; } @@ -970,6 +975,8 @@ struct CxxrtlWorker { continue; } if (cell->output(conn.first)) { + if (conn.second.empty()) + continue; // ignore disconnected ports f << indent; dump_sigspec_lhs(conn.second); f << " = " << mangle(cell) << "." << mangle_wire_name(conn.first) << ".curr;\n"; @@ -1191,7 +1198,7 @@ struct CxxrtlWorker { } } - void dump_module(RTLIL::Module *module) + void dump_module_intf(RTLIL::Module *module) { dump_attrs(module); f << "struct " << mangle(module) << " : public module {\n"; @@ -1220,7 +1227,10 @@ struct CxxrtlWorker { dec_indent(); f << "}; // struct " << mangle(module) << "\n"; f << "\n"; + } + void dump_module_impl(RTLIL::Module *module) + { f << "void " << mangle(module) << "::eval() {\n"; inc_indent(); for (auto wire : module->wires()) @@ -1323,18 +1333,49 @@ struct CxxrtlWorker { } log_assert(topo_design.sort()); - f << "#include <cxxrtl.h>\n"; + if (split_intf) { + // The only thing more depraved than include guards, is mangling filenames to turn them into include guards. + std::string include_guard = design_ns + "_header"; + std::transform(include_guard.begin(), include_guard.end(), include_guard.begin(), ::toupper); + + f << "#ifndef " << include_guard << "\n"; + f << "#define " << include_guard << "\n"; + f << "\n"; + f << "#include <backends/cxxrtl/cxxrtl.h>\n"; + f << "\n"; + f << "using namespace cxxrtl;\n"; + f << "\n"; + f << "namespace " << design_ns << " {\n"; + f << "\n"; + for (auto module : topo_design.sorted) { + if (!design->selected_module(module)) + continue; + dump_module_intf(module); + } + f << "} // namespace " << design_ns << "\n"; + f << "\n"; + f << "#endif\n"; + *intf_f << f.str(); f.str(""); + } + + if (split_intf) + f << "#include \"" << intf_filename << "\"\n"; + else + f << "#include <backends/cxxrtl/cxxrtl.h>\n"; f << "\n"; f << "using namespace cxxrtl_yosys;\n"; f << "\n"; - f << "namespace cxxrtl_design {\n"; + f << "namespace " << design_ns << " {\n"; f << "\n"; for (auto module : topo_design.sorted) { if (!design->selected_module(module)) continue; - dump_module(module); + if (!split_intf) + dump_module_intf(module); + dump_module_impl(module); } - f << "} // namespace cxxrtl_design\n"; + f << "} // namespace " << design_ns << "\n"; + *impl_f << f.str(); f.str(""); } // Edge-type sync rules require us to emit edge detectors, which require coordination between @@ -1618,6 +1659,16 @@ struct CxxrtlBackend : public Backend { log("\n"); log("The following options are supported by this backend:\n"); log("\n"); + log(" -header\n"); + log(" generate separate interface (.h) and implementation (.cc) files.\n"); + log(" if specified, the backend must be called with a filename, and filename\n"); + log(" of the interface is derived from filename of the implementation.\n"); + log(" otherwise, interface and implementation are generated together.\n"); + log("\n"); + log(" -namespace <ns-name>\n"); + log(" place the generated code into namespace <ns-name>. if not specified,\n"); + log(" \"cxxrtl_design\" is used.\n"); + log("\n"); log(" -O <level>\n"); log(" set the optimization level. the default is -O%d. higher optimization\n", DEFAULT_OPT_LEVEL); log(" levels dramatically decrease compile and run time, and highest level\n"); @@ -1645,6 +1696,7 @@ struct CxxrtlBackend : public Backend { void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { int opt_level = DEFAULT_OPT_LEVEL; + CxxrtlWorker worker; log_header(design, "Executing CXXRTL backend.\n"); @@ -1659,11 +1711,18 @@ struct CxxrtlBackend : public Backend { opt_level = std::stoi(args[argidx].substr(2)); continue; } + if (args[argidx] == "-header") { + worker.split_intf = true; + continue; + } + if (args[argidx] == "-namespace" && argidx+1 < args.size()) { + worker.design_ns = args[++argidx]; + continue; + } break; } extra_args(f, filename, args, argidx); - CxxrtlWorker worker(*f); switch (opt_level) { case 5: worker.run_splitnets = true; @@ -1680,6 +1739,22 @@ struct CxxrtlBackend : public Backend { default: log_cmd_error("Invalid optimization level %d.\n", opt_level); } + + std::ofstream intf_f; + if (worker.split_intf) { + if (filename == "<stdout>") + log_cmd_error("Option -header must be used with a filename.\n"); + + worker.intf_filename = filename.substr(0, filename.rfind('.')) + ".h"; + intf_f.open(worker.intf_filename, std::ofstream::trunc); + if (intf_f.fail()) + log_cmd_error("Can't open file `%s' for writing: %s\n", + worker.intf_filename.c_str(), strerror(errno)); + + worker.intf_f = &intf_f; + } + worker.impl_f = f; + worker.prepare_design(design); worker.dump_design(design); } diff --git a/backends/json/json.cc b/backends/json/json.cc index 6c924ff99..1da23bb7d 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -303,8 +303,13 @@ struct JsonBackend : public Backend { log("The general syntax of the JSON output created by this command is as follows:\n"); log("\n"); log(" {\n"); + log(" \"creator\": \"Yosys <version info>\",\n"); log(" \"modules\": {\n"); log(" <module_name>: {\n"); + log(" \"attributes\": {\n"); + log(" <attribute_name>: <attribute_value>,\n"); + log(" ...\n"); + log(" },\n"); log(" \"ports\": {\n"); log(" <port_name>: <port_details>,\n"); log(" ...\n"); @@ -329,13 +334,19 @@ struct JsonBackend : public Backend { log(" {\n"); log(" \"direction\": <\"input\" | \"output\" | \"inout\">,\n"); log(" \"bits\": <bit_vector>\n"); + log(" \"offset\": <the lowest bit index in use, if non-0>\n"); + log(" \"upto\": <1 if the port bit indexing is MSB-first>\n"); log(" }\n"); log("\n"); + log("The \"offset\" and \"upto\" fields are skipped if their value would be 0."); + log("They don't affect connection semantics, and are only used to preserve original"); + log("HDL bit indexing."); log("And <cell_details> is:\n"); log("\n"); log(" {\n"); log(" \"hide_name\": <1 | 0>,\n"); log(" \"type\": <cell_type>,\n"); + log(" \"model\": <AIG model name, if -aig option used>,\n"); log(" \"parameters\": {\n"); log(" <parameter_name>: <parameter_value>,\n"); log(" ...\n"); @@ -359,6 +370,8 @@ struct JsonBackend : public Backend { log(" {\n"); log(" \"hide_name\": <1 | 0>,\n"); log(" \"bits\": <bit_vector>\n"); + log(" \"offset\": <the lowest bit index in use, if non-0>\n"); + log(" \"upto\": <1 if the port bit indexing is MSB-first>\n"); log(" }\n"); log("\n"); log("The \"hide_name\" fields are set to 1 when the name of this cell or net is\n"); @@ -386,9 +399,15 @@ struct JsonBackend : public Backend { log("\n"); log("Translates to the following JSON output:\n"); log("\n"); + log(" {\n"); + log(" \"creator\": \"Yosys 0.9+2406 (git sha1 fb1168d8, clang 9.0.1 -fPIC -Os)\",\n"); log(" \"modules\": {\n"); log(" \"test\": {\n"); + log(" \"attributes\": {\n"); + log(" \"cells_not_processed\": \"00000000000000000000000000000001\",\n"); + log(" \"src\": \"test.v:1.1-4.10\"\n"); + log(" },\n"); log(" \"ports\": {\n"); log(" \"x\": {\n"); log(" \"direction\": \"input\",\n"); @@ -404,33 +423,34 @@ struct JsonBackend : public Backend { log(" \"hide_name\": 0,\n"); log(" \"type\": \"foo\",\n"); log(" \"parameters\": {\n"); - log(" \"Q\": 1337,\n"); - log(" \"P\": 42\n"); + log(" \"P\": \"00000000000000000000000000101010\",\n"); + log(" \"Q\": \"00000000000000000000010100111001\"\n"); log(" },\n"); log(" \"attributes\": {\n"); - log(" \"keep\": 1,\n"); - log(" \"src\": \"test.v:2\"\n"); + log(" \"keep\": \"00000000000000000000000000000001\",\n"); + log(" \"module_not_derived\": \"00000000000000000000000000000001\",\n"); + log(" \"src\": \"test.v:3.1-3.55\"\n"); log(" },\n"); log(" \"connections\": {\n"); - log(" \"C\": [ 2, 2, 2, 2, \"0\", \"1\", \"0\", \"1\" ],\n"); + log(" \"A\": [ 3, 2 ],\n"); log(" \"B\": [ 2, 3 ],\n"); - log(" \"A\": [ 3, 2 ]\n"); + log(" \"C\": [ 2, 2, 2, 2, \"0\", \"1\", \"0\", \"1\" ]\n"); log(" }\n"); log(" }\n"); log(" },\n"); log(" \"netnames\": {\n"); - log(" \"y\": {\n"); + log(" \"x\": {\n"); log(" \"hide_name\": 0,\n"); - log(" \"bits\": [ 3 ],\n"); + log(" \"bits\": [ 2 ],\n"); log(" \"attributes\": {\n"); - log(" \"src\": \"test.v:1\"\n"); + log(" \"src\": \"test.v:1.19-1.20\"\n"); log(" }\n"); log(" },\n"); - log(" \"x\": {\n"); + log(" \"y\": {\n"); log(" \"hide_name\": 0,\n"); - log(" \"bits\": [ 2 ],\n"); + log(" \"bits\": [ 3 ],\n"); log(" \"attributes\": {\n"); - log(" \"src\": \"test.v:1\"\n"); + log(" \"src\": \"test.v:1.22-1.23\"\n"); log(" }\n"); log(" }\n"); log(" }\n"); diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 5467e250b..11b2ae10f 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1984,7 +1984,7 @@ struct VerilogBackend : public Backend { extra_args(f, filename, args, argidx); if (extmem) { - if (filename.empty()) + if (filename == "<stdout>") log_cmd_error("Option -extmem must be used with a filename.\n"); extmem_prefix = filename.substr(0, filename.rfind('.')); } diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index c0539252c..ab368fdb0 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1326,20 +1326,25 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) { if (width_hint < 0) detectSignWidth(width_hint, sign_hint); + is_signed = sign_hint; RTLIL::SigSpec cond = children[0]->genRTLIL(); RTLIL::SigSpec sig; - if (cond.is_fully_const()) { + + if (cond.is_fully_def()) + { if (cond.as_bool()) { sig = children[1]->genRTLIL(width_hint, sign_hint); - widthExtend(this, sig, sig.size(), children[1]->is_signed); - } - else { + log_assert(is_signed == children[1]->is_signed); + } else { sig = children[2]->genRTLIL(width_hint, sign_hint); - widthExtend(this, sig, sig.size(), children[2]->is_signed); + log_assert(is_signed == children[2]->is_signed); } + + widthExtend(this, sig, sig.size(), is_signed); } - else { + else + { RTLIL::SigSpec val1 = children[1]->genRTLIL(width_hint, sign_hint); RTLIL::SigSpec val2 = children[2]->genRTLIL(width_hint, sign_hint); @@ -1347,7 +1352,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) cond = uniop2rtlil(this, ID($reduce_bool), 1, cond, false); int width = max(val1.size(), val2.size()); - is_signed = children[1]->is_signed && children[2]->is_signed; + log_assert(is_signed == children[1]->is_signed); + log_assert(is_signed == children[2]->is_signed); widthExtend(this, val1, width, is_signed); widthExtend(this, val2, width, is_signed); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 5e7518f68..cb89f58ba 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -420,9 +420,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, current_scope[node->str] = node; for (auto enode : node->children) { log_assert(enode->type==AST_ENUM_ITEM); - if (current_scope.count(enode->str) == 0) { + if (current_scope.count(enode->str) == 0) current_scope[enode->str] = enode; - } + else + log_file_error(filename, location.first_line, "enum item %s already exists\n", enode->str.c_str()); } } } @@ -441,6 +442,29 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } + // create name resolution entries for all objects with names + if (type == AST_PACKAGE) { + //add names to package scope + for (size_t i = 0; i < children.size(); i++) { + AstNode *node = children[i]; + // these nodes appear at the top level in a package and can define names + if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_TYPEDEF) { + current_scope[node->str] = node; + } + if (node->type == AST_ENUM) { + current_scope[node->str] = node; + for (auto enode : node->children) { + log_assert(enode->type==AST_ENUM_ITEM); + if (current_scope.count(enode->str) == 0) + current_scope[enode->str] = enode; + else + log_file_error(filename, location.first_line, "enum item %s already exists in package\n", enode->str.c_str()); + } + } + } + } + + auto backup_current_block = current_block; auto backup_current_block_child = current_block_child; auto backup_current_top_block = current_top_block; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index bd51aa12b..76373c2e4 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -521,7 +521,8 @@ package_body: package_body_stmt: typedef_decl | - localparam_decl; + localparam_decl | + param_decl; interface: TOK_INTERFACE { diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc index 2556d188a..8d973869e 100644 --- a/passes/cmds/setundef.cc +++ b/passes/cmds/setundef.cc @@ -149,7 +149,7 @@ struct SetundefPass : public Pass { } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - bool got_value = false; + int got_value = 0; bool undriven_mode = false; bool expose_mode = false; bool init_mode = false; @@ -170,31 +170,31 @@ struct SetundefPass : public Pass { continue; } if (args[argidx] == "-zero") { - got_value = true; + got_value++; worker.next_bit_mode = MODE_ZERO; worker.next_bit_state = 0; continue; } if (args[argidx] == "-one") { - got_value = true; + got_value++; worker.next_bit_mode = MODE_ONE; worker.next_bit_state = 0; continue; } if (args[argidx] == "-anyseq") { - got_value = true; + got_value++; worker.next_bit_mode = MODE_ANYSEQ; worker.next_bit_state = 0; continue; } if (args[argidx] == "-anyconst") { - got_value = true; + got_value++; worker.next_bit_mode = MODE_ANYCONST; worker.next_bit_state = 0; continue; } if (args[argidx] == "-undef") { - got_value = true; + got_value++; worker.next_bit_mode = MODE_UNDEF; worker.next_bit_state = 0; continue; @@ -207,8 +207,8 @@ struct SetundefPass : public Pass { params_mode = true; continue; } - if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) { - got_value = true; + if (args[argidx] == "-random" && argidx+1 < args.size()) { + got_value++; worker.next_bit_mode = MODE_RANDOM; worker.next_bit_state = atoi(args[++argidx].c_str()) + 1; for (int i = 0; i < 10; i++) @@ -221,7 +221,7 @@ struct SetundefPass : public Pass { if (!got_value && expose_mode) { log("Using default as -undef with -expose.\n"); - got_value = true; + got_value++; worker.next_bit_mode = MODE_UNDEF; worker.next_bit_state = 0; } @@ -229,7 +229,9 @@ struct SetundefPass : public Pass { if (expose_mode && !undriven_mode) log_cmd_error("Option -expose must be used with option -undriven.\n"); if (!got_value) - log_cmd_error("One of the options -zero, -one, -anyseq, -anyconst, or -random <seed> must be specified.\n"); + log_cmd_error("One of the options -zero, -one, -anyseq, -anyconst, -random <seed>, or -expose must be specified.\n"); + else if (got_value > 1) + log_cmd_error("Only one of the options -zero, -one, -anyseq, -anyconst, or -random <seed> can be specified.\n"); if (init_mode && (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST)) log_cmd_error("The options -init and -anyseq / -anyconst are exclusive.\n"); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 0222df38a..3229dd1b2 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -717,31 +717,27 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons RTLIL::SigSpec sig_y = cell->getPort(ID::Y); RTLIL::SigSpec sig_co = cell->getPort(ID::CO); - bool sub = (sig_ci == State::S1 && sig_bi == State::S1); + if (sig_bi != State::S0 && sig_bi != State::S1) + goto skip_fine_alu; + if (sig_ci != State::S0 && sig_ci != State::S1) + goto skip_fine_alu; - // If not a subtraction, yet there is a carry or B is inverted - // then no optimisation is possible as carry will not be constant - if (!sub && (sig_ci != State::S0 || sig_bi != State::S0)) - goto next_cell; + bool bi = sig_bi == State::S1; + bool ci = sig_ci == State::S1; int i; for (i = 0; i < GetSize(sig_y); i++) { RTLIL::SigBit b = sig_b.at(i, State::Sx); RTLIL::SigBit a = sig_a.at(i, State::Sx); - if (b == State::S0 && a != State::Sx) { - module->connect(sig_y[i], sig_a[i]); - module->connect(sig_x[i], sub ? module->Not(NEW_ID, a).as_bit() : a); - module->connect(sig_co[i], sub ? State::S1 : State::S0); - } - else if (sub && b == State::S1 && a == State::S1) { - module->connect(sig_y[i], State::S0); - module->connect(sig_x[i], module->Not(NEW_ID, a)); - module->connect(sig_co[i], State::S0); + if (b == ((bi ^ ci) ? State::S1 : State::S0) && a != State::Sx) { + module->connect(sig_y[i], a); + module->connect(sig_x[i], ci ? module->Not(NEW_ID, a).as_bit() : a); + module->connect(sig_co[i], ci ? State::S1 : State::S0); } - else if (!sub && a == State::S0 && b != State::Sx) { - module->connect(sig_y[i], b); - module->connect(sig_x[i], b); - module->connect(sig_co[i], State::S0); + else if (a == (ci ? State::S1 : State::S0) && b != State::Sx) { + module->connect(sig_y[i], bi ? module->Not(NEW_ID, b).as_bit() : b); + module->connect(sig_x[i], (bi ^ ci) ? module->Not(NEW_ID, b).as_bit() : b); + module->connect(sig_co[i], ci ? State::S1 : State::S0); } else break; @@ -758,6 +754,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } } +skip_fine_alu: if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow))) @@ -1089,7 +1086,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons // If not a subtraction, yet there is a carry or B is inverted // then no optimisation is possible as carry will not be constant if (!sub && (sig_ci != State::S0 || sig_bi != State::S0)) - goto next_cell; + goto skip_identity; } if (!sub && a.is_fully_const() && a.as_bool() == false) @@ -1163,6 +1160,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons goto next_cell; } } +skip_identity: if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == State::S0 && cell->getPort(ID::B) == State::S1) { @@ -1530,6 +1528,99 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } + // Find places in $alu cell where the carry is constant, and split it at these points. + if (do_fine && !keepdc && cell->type == ID($alu)) + { + bool a_signed = cell->parameters[ID::A_SIGNED].as_bool(); + bool b_signed = cell->parameters[ID::B_SIGNED].as_bool(); + bool is_signed = a_signed && b_signed; + + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B)); + RTLIL::SigSpec sig_y = assign_map(cell->getPort(ID::Y)); + RTLIL::SigSpec sig_bi = assign_map(cell->getPort(ID::BI)); + if (GetSize(sig_a) == 0) + sig_a = State::S0; + if (GetSize(sig_b) == 0) + sig_b = State::S0; + sig_a.extend_u0(GetSize(sig_y), is_signed); + sig_b.extend_u0(GetSize(sig_y), is_signed); + + if (sig_bi != State::S0 && sig_bi != State::S1) + goto skip_alu_split; + + std::vector<std::pair<int, State>> split_points; + + for (int i = 0; i < GetSize(sig_y); i++) { + SigBit bit_a = sig_a[i]; + SigBit bit_b = sig_b[i]; + if (bit_a != State::S0 && bit_a != State::S1) + continue; + if (bit_b != State::S0 && bit_b != State::S1) + continue; + if (sig_bi == State::S1) { + if (bit_b == State::S0) + bit_b = State::S1; + else + bit_b = State::S0; + } + if (bit_a != bit_b) + continue; + split_points.push_back(std::make_pair(i + 1, bit_a.data)); + } + + if (split_points.empty() || split_points[0].first == GetSize(sig_y)) + goto skip_alu_split; + + for (auto &p : split_points) + log_debug("Splitting $alu cell `%s' in module `%s' at const-carry point %d.\n", + cell->name.c_str(), module->name.c_str(), p.first); + + if (split_points.back().first != GetSize(sig_y)) + split_points.push_back(std::make_pair(GetSize(sig_y), State::Sx)); + + RTLIL::SigSpec sig_ci = assign_map(cell->getPort(ID::CI)); + int prev = 0; + RTLIL::SigSpec sig_x = assign_map(cell->getPort(ID::X)); + RTLIL::SigSpec sig_co = assign_map(cell->getPort(ID::CO)); + + for (auto &p : split_points) { + int cur = p.first; + int sz = cur - prev; + bool last = cur == GetSize(sig_y); + + RTLIL::Cell *c = module->addCell(NEW_ID, cell->type); + c->setPort(ID::A, sig_a.extract(prev, sz)); + c->setPort(ID::B, sig_b.extract(prev, sz)); + c->setPort(ID::BI, sig_bi); + c->setPort(ID::CI, sig_ci); + c->setPort(ID::Y, sig_y.extract(prev, sz)); + c->setPort(ID::X, sig_x.extract(prev, sz)); + RTLIL::SigSpec new_co = sig_co.extract(prev, sz); + if (p.second != State::Sx) { + module->connect(new_co[sz-1], p.second); + RTLIL::Wire *dummy = module->addWire(NEW_ID); + new_co[sz-1] = dummy; + } + c->setPort(ID::CO, new_co); + c->parameters[ID::A_WIDTH] = sz; + c->parameters[ID::B_WIDTH] = sz; + c->parameters[ID::Y_WIDTH] = sz; + c->parameters[ID::A_SIGNED] = last ? a_signed : false; + c->parameters[ID::B_SIGNED] = last ? b_signed : false; + + prev = p.first; + sig_ci = p.second; + } + + cover("opt.opt_expr.alu_split"); + module->remove(cell); + + did_something = true; + goto next_cell; + } +skip_alu_split: + // remove redundant pairs of bits in ==, ===, !=, and !== // replace cell with const driver if inputs can't be equal if (do_fine && cell->type.in(ID($eq), ID($ne), ID($eqx), ID($nex))) diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index 303b04402..18618ff91 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -222,9 +222,9 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe abc9_script += stringf("; &ps -l; &write -n %s/output.aig", tempdir_name.c_str()); if (design->scratchpad_get_bool("abc9.verify")) { if (dff_mode) - abc9_script += "; verify -s"; + abc9_script += "; &verify -s"; else - abc9_script += "; verify"; + abc9_script += "; &verify"; } abc9_script += "; time"; abc9_script = add_echos_to_abc9_cmd(abc9_script); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 00af36615..8ae1b51ff 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -434,6 +434,9 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) auto &t = timing.at(derived_type).required; for (auto &conn : cell->connections_) { auto port_wire = inst_module->wire(conn.first); + if (!port_wire) + log_error("Port %s in cell %s (type %s) of module %s does not actually exist", + log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name)); if (!port_wire->port_input) continue; diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc index 0424ce434..35645582b 100644 --- a/passes/techmap/dffinit.cc +++ b/passes/techmap/dffinit.cc @@ -154,9 +154,11 @@ struct DffinitPass : public Pass { value = Const(low_string); } - log("Setting %s.%s.%s (port=%s, net=%s) to %s.\n", log_id(module), log_id(cell), log_id(it.second), - log_id(it.first), log_signal(sig), log_signal(value)); - cell->setParam(it.second, value); + if (value.size() != 0) { + log("Setting %s.%s.%s (port=%s, net=%s) to %s.\n", log_id(module), log_id(cell), log_id(it.second), + log_id(it.first), log_signal(sig), log_signal(value)); + cell->setParam(it.second, value); + } } } diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 518afa1a7..a554be257 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -1282,7 +1282,7 @@ struct TechmapPass : public Pass { if (fn.compare(0, 1, "%") == 0) { if (!saved_designs.count(fn.substr(1))) { delete map; - log_cmd_error("Can't saved design `%s'.\n", fn.c_str()+1); + log_cmd_error("Can't open saved design `%s'.\n", fn.c_str()+1); } for (auto mod : saved_designs.at(fn.substr(1))->modules()) if (!map->has(mod->name)) diff --git a/techlibs/intel/Makefile.inc b/techlibs/intel/Makefile.inc index d97a9b58f..f751e341f 100644 --- a/techlibs/intel/Makefile.inc +++ b/techlibs/intel/Makefile.inc @@ -11,4 +11,3 @@ families := max10 arria10gx cyclonev cyclone10lp cycloneiv cycloneive $(foreach family,$(families), $(eval $(call add_share_file,share/intel/$(family),techlibs/intel/$(family)/cells_sim.v))) $(foreach family,$(families), $(eval $(call add_share_file,share/intel/$(family),techlibs/intel/$(family)/cells_map.v))) #$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/arith_map.v)) - diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc new file mode 100644 index 000000000..66204c8fc --- /dev/null +++ b/techlibs/intel_alm/Makefile.inc @@ -0,0 +1,23 @@ + +OBJS += techlibs/intel_alm/synth_intel_alm.o + +# Techmap +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/alm_map.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/alm_sim.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/arith_alm_map.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_map.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_sim.v)) + +# RAM +bramtypes := m10k m20k +$(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype).txt))) +$(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype)_map.v))) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab_map.v)) + +families := cyclonev cyclone10gx + +# Miscellaneous +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/megafunction_bb.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/quartus_rename.v)) +$(foreach family, $(families), $(eval $(call add_share_file,share/intel_alm/$(family),techlibs/intel_alm/$(family)/quartus_rename.v))) diff --git a/techlibs/intel_alm/common/alm_map.v b/techlibs/intel_alm/common/alm_map.v new file mode 100644 index 000000000..fe646c5d6 --- /dev/null +++ b/techlibs/intel_alm/common/alm_map.v @@ -0,0 +1,56 @@ +module \$lut (A, Y); + +parameter WIDTH = 1; +parameter LUT = 0; + +input [WIDTH-1:0] A; +output Y; + +generate + if (WIDTH == 1) begin + generate + if (LUT == 2'b00) begin + assign Y = 1'b0; + end + else if (LUT == 2'b01) begin + MISTRAL_NOT _TECHMAP_REPLACE_( + .A(A[0]), .Q(Y) + ); + end + else if (LUT == 2'b10) begin + assign Y = A; + end + else if (LUT == 2'b11) begin + assign Y = 1'b1; + end + endgenerate + end else + if (WIDTH == 2) begin + MISTRAL_ALUT2 #(.LUT(LUT)) _TECHMAP_REPLACE_( + .A(A[0]), .B(A[1]), .Q(Y) + ); + end else + if (WIDTH == 3) begin + MISTRAL_ALUT3 #(.LUT(LUT)) _TECHMAP_REPLACE_( + .A(A[0]), .B(A[1]), .C(A[2]), .Q(Y) + ); + end else + if (WIDTH == 4) begin + MISTRAL_ALUT4 #(.LUT(LUT)) _TECHMAP_REPLACE_( + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .Q(Y) + ); + end else + if (WIDTH == 5) begin + MISTRAL_ALUT5 #(.LUT(LUT)) _TECHMAP_REPLACE_ ( + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .E(A[4]), .Q(Y) + ); + end else + if (WIDTH == 6) begin + MISTRAL_ALUT6 #(.LUT(LUT)) _TECHMAP_REPLACE_ ( + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .E(A[4]), .F(A[5]), .Q(Y) + ); + end else begin + wire _TECHMAP_FAIL_ = 1'b1; + end +endgenerate +endmodule diff --git a/techlibs/intel_alm/common/alm_sim.v b/techlibs/intel_alm/common/alm_sim.v new file mode 100644 index 000000000..69768d9f7 --- /dev/null +++ b/techlibs/intel_alm/common/alm_sim.v @@ -0,0 +1,482 @@ +`default_nettype none + +(* abc9_lut=2, lib_whitebox *) +module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); + +parameter [63:0] LUT = 64'h0000_0000_0000_0000; + +`ifdef cyclonev +specify + (A => Q) = 602; + (B => Q) = 584; + (C => Q) = 510; + (D => Q) = 510; + (E => Q) = 339; + (F => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 275; + (B => Q) = 272; + (C => Q) = 175; + (D => Q) = 165; + (E => Q) = 162; + (F => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {F, E, D, C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT5(input A, B, C, D, E, output Q); + +parameter [31:0] LUT = 32'h0000_0000; + +`ifdef cyclonev +specify + (A => Q) = 584; + (B => Q) = 510; + (C => Q) = 510; + (D => Q) = 339; + (E => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 272; + (B => Q) = 175; + (C => Q) = 165; + (D => Q) = 162; + (E => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {E, D, C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT4(input A, B, C, D, output Q); + +parameter [15:0] LUT = 16'h0000; + +`ifdef cyclonev +specify + (A => Q) = 510; + (B => Q) = 510; + (C => Q) = 339; + (D => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 175; + (B => Q) = 165; + (C => Q) = 162; + (D => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {D, C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT3(input A, B, C, output Q); + +parameter [7:0] LUT = 8'h00; + +`ifdef cyclonev +specify + (A => Q) = 510; + (B => Q) = 339; + (C => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 165; + (B => Q) = 162; + (C => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT2(input A, B, output Q); + +parameter [3:0] LUT = 4'h0; + +`ifdef cyclonev +specify + (A => Q) = 339; + (B => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 162; + (B => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_NOT(input A, output Q); + +`ifdef cyclonev +specify + (A => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 53; +endspecify +`endif + +assign Q = ~A; + +endmodule + +(* abc9_box, lib_whitebox *) +module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, (* abc9_carry *) input CI, output SO, (* abc9_carry *) output CO); + +parameter LUT0 = 16'h0000; +parameter LUT1 = 16'h0000; + +`ifdef cyclonev +specify + (A => SO) = 1283; + (B => SO) = 1167; + (C => SO) = 866; + (D0 => SO) = 756; + (D1 => SO) = 756; + (CI => SO) = 355; + (A => CO) = 950; + (B => CO) = 1039; + (C => CO) = 820; + (D0 => CO) = 1006; + (D1 => CO) = 1006; + (CI => CO) = 23; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => SO) = 644; + (B => SO) = 477; + (C => SO) = 416; + (D0 => SO) = 380; + (D1 => SO) = 431; + (CI => SO) = 276; + (A => CO) = 525; + (B => CO) = 433; + (C => CO) = 712; + (D0 => CO) = 653; + (D1 => CO) = 593; + (CI => CO) = 16; +endspecify +`endif + +wire q0, q1; + +assign q0 = LUT0 >> {D0, C, B, A}; +assign q1 = LUT1 >> {D1, C, B, A}; + +assign {CO, SO} = q0 + !q1 + CI; + +endmodule + + +/* +// A, B, C0, C1, E0, E1, F0, F1: data inputs +// CARRYIN: carry input +// SHAREIN: shared-arithmetic input +// CLK0, CLK1, CLK2: clock inputs +// +// COMB0, COMB1: combinational outputs +// FF0, FF1, FF2, FF3: DFF outputs +// SUM0, SUM1: adder outputs +// CARRYOUT: carry output +// SHAREOUT: shared-arithmetic output +module MISTRAL_ALM( + input A, B, C0, C1, E0, E1, F0, F1, CARRYIN, SHAREIN, // LUT path + input CLK0, CLK1, CLK2, AC0, AC1, // FF path + output COMB0, COMB1, SUM0, SUM1, CARRYOUT, SHAREOUT, + output FF0, FF1, FF2, FF3 +); + +parameter LUT0 = 16'b0000; +parameter LUT1 = 16'b0000; +parameter LUT2 = 16'b0000; +parameter LUT3 = 16'b0000; + +parameter INIT0 = 1'b0; +parameter INIT1 = 1'b0; +parameter INIT2 = 1'b0; +parameter INIT3 = 1'b0; + +parameter C0_MUX = "C0"; +parameter C1_MUX = "C1"; + +parameter F0_MUX = "VCC"; +parameter F1_MUX = "GND"; + +parameter FEEDBACK0 = "FF0"; +parameter FEEDBACK1 = "FF2"; + +parameter ADD_MUX = "LUT"; + +parameter DFF01_DATA_MUX = "COMB"; +parameter DFF23_DATA_MUX = "COMB"; + +parameter DFF0_CLK = "CLK0"; +parameter DFF1_CLK = "CLK0"; +parameter DFF2_CLK = "CLK0"; +parameter DFF3_CLK = "CLK0"; + +parameter DFF0_AC = "AC0"; +parameter DFF1_AC = "AC0"; +parameter DFF2_AC = "AC0"; +parameter DFF3_AC = "AC0"; + +// Feedback muxes from the flip-flop outputs. +wire ff_feedback_mux0, ff_feedback_mux1; + +// C-input muxes which can be set to also use the F-input. +wire c0_input_mux, c1_input_mux; + +// F-input muxes which can be set to a constant to allow LUT5 use. +wire f0_input_mux, f1_input_mux; + +// Adder input muxes to select between shared-arithmetic mode and arithmetic mode. +wire add0_input_mux, add1_input_mux; + +// Combinational-output muxes for LUT #1 and LUT #3 +wire lut1_comb_mux, lut3_comb_mux; + +// Sum-output muxes for LUT #1 and LUT #3 +wire lut1_sum_mux, lut3_sum_mux; + +// DFF data-input muxes +wire dff01_data_mux, dff23_data_mux; + +// DFF clock selectors +wire dff0_clk, dff1_clk, dff2_clk, dff3_clk; + +// DFF asynchronous-clear selectors +wire dff0_ac, dff1_ac, dff2_ac, dff3_ac; + +// LUT, DFF and adder output wires for routing. +wire lut0_out, lut1a_out, lut1b_out, lut2_out, lut3a_out, lut3b_out; +wire dff0_out, dff1_out, dff2_out, dff3_out; +wire add0_sum, add1_sum, add0_carry, add1_carry; + +generate + if (FEEDBACK0 === "FF0") + assign ff_feedback_mux0 = dff0_out; + else if (FEEDBACK0 === "FF1") + assign ff_feedback_mux0 = dff1_out; + else + $error("Invalid FEEDBACK0 setting!"); + + if (FEEDBACK1 == "FF2") + assign ff_feedback_mux1 = dff2_out; + else if (FEEDBACK1 == "FF3") + assign ff_feedback_mux1 = dff3_out; + else + $error("Invalid FEEDBACK1 setting!"); + + if (C0_MUX === "C0") + assign c0_input_mux = C0; + else if (C0_MUX === "F1") + assign c0_input_mux = F1; + else if (C0_MUX === "FEEDBACK1") + assign c0_input_mux = ff_feedback_mux1; + else + $error("Invalid C0_MUX setting!"); + + if (C1_MUX === "C1") + assign c1_input_mux = C1; + else if (C1_MUX === "F0") + assign c1_input_mux = F0; + else if (C1_MUX === "FEEDBACK0") + assign c1_input_mux = ff_feedback_mux0; + else + $error("Invalid C1_MUX setting!"); + + // F0 == VCC is LUT5 + // F0 == F0 is LUT6 + // F0 == FEEDBACK is unknown + if (F0_MUX === "VCC") + assign f0_input_mux = 1'b1; + else if (F0_MUX === "F0") + assign f0_input_mux = F0; + else if (F0_MUX === "FEEDBACK0") + assign f0_input_mux = ff_feedback_mux0; + else + $error("Invalid F0_MUX setting!"); + + // F1 == GND is LUT5 + // F1 == F1 is LUT6 + // F1 == FEEDBACK is unknown + if (F1_MUX === "GND") + assign f1_input_mux = 1'b0; + else if (F1_MUX === "F1") + assign f1_input_mux = F1; + else if (F1_MUX === "FEEDBACK1") + assign f1_input_mux = ff_feedback_mux1; + else + $error("Invalid F1_MUX setting!"); + + if (ADD_MUX === "LUT") begin + assign add0_input_mux = ~lut1_sum_mux; + assign add1_input_mux = ~lut3_sum_mux; + end else if (ADD_MUX === "SHARE") begin + assign add0_input_mux = SHAREIN; + assign add1_input_mux = lut1_comb_mux; + end else + $error("Invalid ADD_MUX setting!"); + + if (DFF01_DATA_MUX === "COMB") + assign dff01_data_mux = COMB0; + else if (DFF01_DATA_MUX === "SUM") + assign dff01_data_mux = SUM0; + else + $error("Invalid DFF01_DATA_MUX setting!"); + + if (DFF23_DATA_MUX === "COMB") + assign dff23_data_mux = COMB0; + else if (DFF23_DATA_MUX === "SUM") + assign dff23_data_mux = SUM0; + else + $error("Invalid DFF23_DATA_MUX setting!"); + + if (DFF0_CLK === "CLK0") + assign dff0_clk = CLK0; + else if (DFF0_CLK === "CLK1") + assign dff0_clk = CLK1; + else if (DFF0_CLK === "CLK2") + assign dff0_clk = CLK2; + else + $error("Invalid DFF0_CLK setting!"); + + if (DFF1_CLK === "CLK0") + assign dff1_clk = CLK0; + else if (DFF1_CLK === "CLK1") + assign dff1_clk = CLK1; + else if (DFF1_CLK === "CLK2") + assign dff1_clk = CLK2; + else + $error("Invalid DFF1_CLK setting!"); + + if (DFF2_CLK === "CLK0") + assign dff2_clk = CLK0; + else if (DFF2_CLK === "CLK1") + assign dff2_clk = CLK1; + else if (DFF2_CLK === "CLK2") + assign dff2_clk = CLK2; + else + $error("Invalid DFF2_CLK setting!"); + + if (DFF3_CLK === "CLK0") + assign dff3_clk = CLK0; + else if (DFF3_CLK === "CLK1") + assign dff3_clk = CLK1; + else if (DFF3_CLK === "CLK2") + assign dff3_clk = CLK2; + else + $error("Invalid DFF3_CLK setting!"); + + if (DFF0_AC === "AC0") + assign dff0_ac = AC0; + else if (DFF0_AC === "AC1") + assign dff0_ac = AC1; + else + $error("Invalid DFF0_AC setting!"); + + if (DFF1_AC === "AC0") + assign dff1_ac = AC0; + else if (DFF1_AC === "AC1") + assign dff1_ac = AC1; + else + $error("Invalid DFF1_AC setting!"); + + if (DFF2_AC === "AC0") + assign dff2_ac = AC0; + else if (DFF2_AC === "AC1") + assign dff2_ac = AC1; + else + $error("Invalid DFF2_AC setting!"); + + if (DFF3_AC === "AC0") + assign dff3_ac = AC0; + else if (DFF3_AC === "AC1") + assign dff3_ac = AC1; + else + $error("Invalid DFF3_AC setting!"); + +endgenerate + +// F0 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT0)) lut0 (.A(A), .B(B), .C(C0), .D(c1_input_mux), .Q(lut0_out)); + +// F2 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT1)) lut1_comb (.A(A), .B(B), .C(C0), .D(c1_input_mux), .Q(lut1_comb_mux)); +MISTRAL_ALUT4 #(.LUT(LUT1)) lut1_sum (.A(A), .B(B), .C(C0), .D(E0), .Q(lut1_sum_mux)); + +// F1 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT2)) lut2 (.A(A), .B(B), .C(C1), .D(c0_input_mux), .Q(lut2_out)); + +// F3 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT3)) lut3_comb (.A(A), .B(B), .C(C1), .D(c0_input_mux), .Q(lut3_comb_mux)); +MISTRAL_ALUT4 #(.LUT(LUT3)) lut3_sum (.A(A), .B(B), .C(C1), .D(E1), .Q(lut3_sum_mux)); + +MISTRAL_FF #(.INIT(INIT0)) dff0 (.D(dff01_data_mux), .CLK(dff0_clk), .ACn(dff0_ac), .Q(dff0_out)); +MISTRAL_FF #(.INIT(INIT1)) dff1 (.D(dff01_data_mux), .CLK(dff1_clk), .ACn(dff1_ac), .Q(dff1_out)); +MISTRAL_FF #(.INIT(INIT2)) dff2 (.D(dff23_data_mux), .CLK(dff2_clk), .ACn(dff2_ac), .Q(dff2_out)); +MISTRAL_FF #(.INIT(INIT3)) dff3 (.D(dff23_data_mux), .CLK(dff3_clk), .ACn(dff3_ac), .Q(dff3_out)); + +// Adders +assign {add0_carry, add0_sum} = CARRYIN + lut0_out + lut1_sum_mux; +assign {add1_carry, add1_sum} = add0_carry + lut2_out + lut3_sum_mux; + +// COMBOUT outputs on the Quartus diagram +assign COMB0 = E0 ? (f0_input_mux ? lut3_comb_mux : lut1_comb_mux) + : (f0_input_mux ? lut2_out : lut0_out); + +assign COMB1 = E1 ? (f1_input_mux ? lut3_comb_mux : lut1_comb_mux) + : (f1_input_mux ? lut2_out : lut0_out); + +// SUMOUT output on the Quartus diagram +assign SUM0 = add0_sum; +assign SUM1 = add1_sum; + +// COUT output on the Quartus diagram +assign CARRYOUT = add1_carry; + +// SHAREOUT output on the Quartus diagram +assign SHAREOUT = lut3_comb_mux; + +// REGOUT outputs on the Quartus diagram +assign FF0 = dff0_out; +assign FF1 = dff1_out; +assign FF2 = dff2_out; +assign FF3 = dff3_out; + +endmodule +*/ diff --git a/techlibs/intel_alm/common/arith_alm_map.v b/techlibs/intel_alm/common/arith_alm_map.v new file mode 100644 index 000000000..ddf81d9d0 --- /dev/null +++ b/techlibs/intel_alm/common/arith_alm_map.v @@ -0,0 +1,64 @@ +`default_nettype none + +module \$alu (A, B, CI, BI, X, Y, CO); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 1; +parameter B_WIDTH = 1; +parameter Y_WIDTH = 1; + +parameter _TECHMAP_CONSTMSK_CI_ = 0; +parameter _TECHMAP_CONSTVAL_CI_ = 0; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +input CI, BI; +output [Y_WIDTH-1:0] X, Y, CO; + +wire [Y_WIDTH-1:0] A_buf, B_buf; +\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); +\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + +wire [Y_WIDTH-1:0] AA = A_buf; +wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; +wire [Y_WIDTH-1:0] BX = B_buf; +wire [Y_WIDTH:0] ALM_CARRY; + +// Start of carry chain +generate + if (_TECHMAP_CONSTMSK_CI_ == 1) begin + assign ALM_CARRY[0] = _TECHMAP_CONSTVAL_CI_; + end else begin + MISTRAL_ALUT_ARITH #( + .LUT0(16'b1010_1010_1010_1010), // Q = A + .LUT1(16'b0000_0000_0000_0000), // Q = 0 (LUT1's input to the adder is inverted) + ) alm_start ( + .A(CI), .B(1'b1), .C(1'b1), .D0(1'b1), .D1(1'b1), + .CI(1'b0), + .CO(ALM_CARRY[0]) + ); + end +endgenerate + +// Carry chain +genvar i; +generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice + // TODO: mwk suggests that a pass could merge pre-adder logic into this. + MISTRAL_ALUT_ARITH #( + .LUT0(16'b1010_1010_1010_1010), // Q = A + .LUT1(16'b1100_0011_1100_0011), // Q = C ? B : ~B (LUT1's input to the adder is inverted) + ) alm_i ( + .A(AA[i]), .B(BX[i]), .C(BI), .D0(1'b1), .D1(1'b1), + .CI(ALM_CARRY[i]), + .SO(Y[i]), + .CO(ALM_CARRY[i+1]) + ); + + // ALM carry chain is not directly accessible, so calculate the carry through soft logic if really needed. + assign CO[i] = (AA[i] && BB[i]) || ((Y[i] ^ AA[i] ^ BB[i]) && (AA[i] || BB[i])); +end endgenerate + +assign X = AA ^ BB; + +endmodule diff --git a/techlibs/intel_alm/common/bram_m10k.txt b/techlibs/intel_alm/common/bram_m10k.txt new file mode 100644 index 000000000..837e3a330 --- /dev/null +++ b/techlibs/intel_alm/common/bram_m10k.txt @@ -0,0 +1,33 @@ +bram __MISTRAL_M10K_SDP + init 0 # TODO: Re-enable when I figure out how BRAM init works + abits 13 @D8192x1 + dbits 1 @D8192x1 + abits 12 @D4096x2 + dbits 2 @D4096x2 + abits 11 @D2048x4 @D2048x5 + dbits 4 @D2048x4 + dbits 5 @D2048x5 + abits 10 @D1024x8 @D1024x10 + dbits 8 @D1024x8 + dbits 10 @D1024x10 + abits 9 @D512x16 @D512x20 + dbits 16 @D512x16 + dbits 20 @D512x20 + abits 8 @D256x32 @D256x40 + dbits 32 @D256x32 + dbits 40 @D256x40 + groups 2 + ports 1 1 + wrmode 1 0 + # read enable; write enable + byte enables (only for multiples of 8) + enable 1 1 + transp 0 0 + clocks 1 1 + clkpol 1 1 +endbram + + +match __MISTRAL_M10K_SDP + min efficiency 5 + make_transp +endmatch diff --git a/techlibs/intel_alm/common/bram_m10k_map.v b/techlibs/intel_alm/common/bram_m10k_map.v new file mode 100644 index 000000000..e5566010d --- /dev/null +++ b/techlibs/intel_alm/common/bram_m10k_map.v @@ -0,0 +1,31 @@ +module __MISTRAL_M10K_SDP(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+
+parameter CFG_ABITS = 10;
+parameter CFG_DBITS = 10;
+parameter CFG_ENABLE_A = 1;
+parameter CFG_ENABLE_B = 1;
+
+input CLK1;
+input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
+input [CFG_DBITS-1:0] A1DATA;
+output [CFG_DBITS-1:0] B1DATA;
+input [CFG_ENABLE_A-1:0] A1EN, B1EN;
+
+altsyncram #(
+ .operation_mode("dual_port"),
+ .ram_block_type("m10k"),
+ .widthad_a(CFG_ABITS),
+ .width_a(CFG_DBITS),
+ .widthad_b(CFG_ABITS),
+ .width_b(CFG_DBITS),
+) _TECHMAP_REPLACE_ (
+ .address_a(A1ADDR),
+ .data_a(A1DATA),
+ .wren_a(A1EN),
+ .address_b(B1ADDR),
+ .q_b(B1DATA),
+ .clock0(CLK1),
+ .clock1(CLK1)
+);
+
+endmodule diff --git a/techlibs/intel_alm/common/bram_m20k.txt b/techlibs/intel_alm/common/bram_m20k.txt new file mode 100644 index 000000000..b4c5a5372 --- /dev/null +++ b/techlibs/intel_alm/common/bram_m20k.txt @@ -0,0 +1,33 @@ +bram __MISTRAL_M20K_SDP + init 1 # TODO: Re-enable when I figure out how BRAM init works + abits 14 @D16384x1 + dbits 1 @D16384x1 + abits 13 @D8192x2 + dbits 2 @D8192x2 + abits 12 @D4096x4 @D4096x5 + dbits 4 @D4096x4 + dbits 5 @D4096x5 + abits 11 @D2048x8 @D2048x10 + dbits 8 @D2048x8 + dbits 10 @D2048x10 + abits 10 @D1024x16 @D1024x20 + dbits 16 @D1024x16 + dbits 20 @D1024x20 + abits 9 @D512x32 @D512x40 + dbits 32 @D512x32 + dbits 40 @D512x40 + groups 2 + ports 1 1 + wrmode 1 0 + # read enable; write enable + byte enables (only for multiples of 8) + enable 1 1 + transp 0 0 + clocks 1 1 + clkpol 1 1 +endbram + + +match __MISTRAL_M20K_SDP + min efficiency 5 + make_transp +endmatch diff --git a/techlibs/intel_alm/common/bram_m20k_map.v b/techlibs/intel_alm/common/bram_m20k_map.v new file mode 100644 index 000000000..92f41310f --- /dev/null +++ b/techlibs/intel_alm/common/bram_m20k_map.v @@ -0,0 +1,31 @@ +module __MISTRAL_M20K_SDP(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+
+parameter CFG_ABITS = 10;
+parameter CFG_DBITS = 20;
+parameter CFG_ENABLE_A = 1;
+parameter CFG_ENABLE_B = 1;
+
+input CLK1;
+input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
+input [CFG_DBITS-1:0] A1DATA;
+output [CFG_DBITS-1:0] B1DATA;
+input [CFG_ENABLE_A-1:0] A1EN, B1EN;
+
+altsyncram #(
+ .operation_mode("dual_port"),
+ .ram_block_type("m20k"),
+ .widthad_a(CFG_ABITS),
+ .width_a(CFG_DBITS),
+ .widthad_b(CFG_ABITS),
+ .width_b(CFG_DBITS),
+) _TECHMAP_REPLACE_ (
+ .address_a(A1ADDR),
+ .data_a(A1DATA),
+ .wren_a(A1EN),
+ .address_b(B1ADDR),
+ .q_b(B1DATA),
+ .clock0(CLK1),
+ .clock1(CLK1)
+);
+
+endmodule
diff --git a/techlibs/intel_alm/common/dff_map.v b/techlibs/intel_alm/common/dff_map.v new file mode 100644 index 000000000..f7f2fe3c3 --- /dev/null +++ b/techlibs/intel_alm/common/dff_map.v @@ -0,0 +1,124 @@ +`default_nettype none + +// D flip-flops +module \$_DFF_P_ (input D, C, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_P_ with INIT=1"); +endmodule + +module \$_DFF_N_ (input D, C, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_N_ with INIT=1"); +endmodule + +// D flip-flops with reset +module \$_DFF_PP0_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_PP0_ with INIT=1"); +endmodule + +module \$_DFF_PN0_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_PN0_ with INIT=1"); +endmodule + +module \$_DFF_NP0_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_NP0_ with INIT=1"); +endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_NN0_ with INIT=1"); +endmodule + +// D flip-flops with set +module \$_DFF_PP1_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b1; +if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + wire Q_tmp; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); + assign Q = ~Q_tmp; +end else $error("Unsupported flop: $_DFF_PP1_ with INIT=0"); +endmodule + +module \$_DFF_PN1_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b1; +if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + wire Q_tmp; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); +end else $error("Unsupported flop: $_DFF_PN1_ with INIT=0"); +endmodule + +module \$_DFF_NP1_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b1; +if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + wire Q_tmp; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); + assign Q = ~Q_tmp; +end else $error("Unsupported flop: $_DFF_NP1_ with INIT=0"); +endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b1; +if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + wire Q_tmp; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); + assign Q = ~Q_tmp; +end else $error("Unsupported flop: $_DFF_NN1_ with INIT=0"); +endmodule + +// D flip-flops with clock enable +module \$_DFFE_PP_ (input D, C, E, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFFE_PP_ with INIT=1"); +endmodule + +module \$_DFFE_PN_ (input D, C, E, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFFE_PN_ with INIT=1"); +endmodule + +module \$_DFFE_NP_ (input D, C, E, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFFE_NP_ with INIT=1"); +endmodule + +module \$_DFFE_NN_ (input D, C, E, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFFE_NN_ with INIT=1"); +endmodule diff --git a/techlibs/intel_alm/common/dff_sim.v b/techlibs/intel_alm/common/dff_sim.v new file mode 100644 index 000000000..07865905f --- /dev/null +++ b/techlibs/intel_alm/common/dff_sim.v @@ -0,0 +1,48 @@ +// DATAIN: synchronous data input +// CLK: clock input (positive edge) +// ACLR: asynchronous clear (negative-true) +// ENA: clock-enable +// SCLR: synchronous clear +// SLOAD: synchronous load +// SDATA: synchronous load data +// +// Q: data output +// +// Note: the DFFEAS primitive is mostly emulated; it does not reflect what the hardware implements. +module MISTRAL_FF( + input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, + output reg Q +); + +`ifdef cyclonev +specify + (posedge CLK => (Q : DATAIN)) = 262; + $setup(DATAIN, posedge CLK, 522); +endspecify +`endif +`ifdef cyclone10gx +specify + (posedge CLK => (Q : DATAIN)) = 219; + $setup(DATAIN, posedge CLK, 268); +endspecify +`endif + +initial begin + // Altera flops initialise to zero. + Q = 0; +end + +always @(posedge CLK, negedge ACLR) begin + // Asynchronous clear + if (!ACLR) Q <= 0; + // Clock-enable + else if (ENA) begin + // Synchronous clear + if (SCLR) Q <= 0; + // Synchronous load + else if (SLOAD) Q <= SDATA; + else Q <= DATAIN; + end +end + +endmodule diff --git a/techlibs/intel_alm/common/lutram_mlab.txt b/techlibs/intel_alm/common/lutram_mlab.txt new file mode 100644 index 000000000..1d6174d85 --- /dev/null +++ b/techlibs/intel_alm/common/lutram_mlab.txt @@ -0,0 +1,20 @@ +bram __MISTRAL_MLAB
+ init 0 # TODO: Re-enable when I figure out how LUTRAM init works
+ abits 5
+ dbits 16 @D32x16
+ dbits 18 @D32x18
+ dbits 20 @D32x20
+ groups 2
+ ports 1 1
+ wrmode 1 0
+ # read enable
+ enable 1 0
+ transp 1 0
+ clocks 1 2
+ clkpol 1 1
+endbram
+
+match __MISTRAL_MLAB
+ min efficiency 5
+ make_outreg
+endmatch
diff --git a/techlibs/intel_alm/common/lutram_mlab_map.v b/techlibs/intel_alm/common/lutram_mlab_map.v new file mode 100644 index 000000000..3a9c8590e --- /dev/null +++ b/techlibs/intel_alm/common/lutram_mlab_map.v @@ -0,0 +1,29 @@ +module __MISTRAL_MLAB(CLK1, CLK2, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA);
+
+parameter CFG_ABITS = 5;
+parameter CFG_DBITS = 20;
+
+input CLK1, CLK2;
+input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
+input [CFG_DBITS-1:0] A1DATA;
+input A1EN;
+output [CFG_DBITS-1:0] B1DATA;
+
+altsyncram #(
+ .operation_mode("dual_port"),
+ .ram_block_type("mlab"),
+ .widthad_a(CFG_ABITS),
+ .width_a(CFG_DBITS),
+ .widthad_b(CFG_ABITS),
+ .width_b(CFG_DBITS),
+) _TECHMAP_REPLACE_ (
+ .address_a(A1ADDR),
+ .data_a(A1DATA),
+ .wren_a(A1EN),
+ .address_b(B1ADDR),
+ .q_b(B1DATA),
+ .clock0(CLK1),
+ .clock1(CLK1),
+);
+
+endmodule
diff --git a/techlibs/intel_alm/common/megafunction_bb.v b/techlibs/intel_alm/common/megafunction_bb.v new file mode 100644 index 000000000..21ba73a09 --- /dev/null +++ b/techlibs/intel_alm/common/megafunction_bb.v @@ -0,0 +1,108 @@ +// Intel megafunction declarations, to avoid Yosys complaining. +`default_nettype none + +(* blackbox *) +module altera_std_synchronizer(clk, din, dout, reset_n); + +parameter depth = 2; + +input clk; +input reset_n; +input din; +output dout; + +endmodule + +(* blackbox *) +module altiobuf_in(datain, dataout); + +parameter enable_bus_hold = "FALSE"; +parameter use_differential_mode = "FALSE"; +parameter number_of_channels = 1; + +input [number_of_channels-1:0] datain; +output [number_of_channels-1:0] dataout; + +endmodule + +(* blackbox *) +module altiobuf_out(datain, dataout); + +parameter enable_bus_hold = "FALSE"; +parameter use_differential_mode = "FALSE"; +parameter use_oe = "FALSE"; +parameter number_of_channels = 1; + +input [number_of_channels-1:0] datain; +output [number_of_channels-1:0] dataout; + +endmodule + +(* blackbox *) +module altiobuf_bidir(dataio, oe, datain, dataout); + +parameter number_of_channels = 1; +parameter enable_bus_hold = "OFF"; + +inout [number_of_channels-1:0] dataio; +input [number_of_channels-1:0] datain; +output [number_of_channels-1:0] dataout; +input [number_of_channels-1:0] oe; + +endmodule + +(* blackbox *) +module altsyncram(clock0, clock1, address_a, data_a, rden_a, wren_a, byteena_a, q_a, addressstall_a, address_b, data_b, rden_b, wren_b, byteena_b, q_b, addressstall_b, clocken0, clocken1, clocken2, clocken3, aclr0, aclr1, eccstatus); + +parameter lpm_type = "altsyncram"; +parameter operation_mode = "dual_port"; +parameter ram_block_type = "auto"; +parameter intended_device_family = "auto"; +parameter power_up_uninitialized = "false"; +parameter read_during_write_mode_mixed_ports = "dontcare"; +parameter byte_size = 8; +parameter widthad_a = 1; +parameter width_a = 1; +parameter width_byteena_a = 1; +parameter numwords_a = 1; +parameter clock_enable_input_a = "clocken0"; +parameter widthad_b = 1; +parameter width_b = 1; +parameter numwords_b = 1; +parameter address_aclr_b = "aclr0"; +parameter address_reg_b = ""; +parameter outdata_aclr_b = "aclr0"; +parameter outdata_reg_b = ""; +parameter clock_enable_input_b = "clocken0"; +parameter clock_enable_output_b = "clocken0"; + +input clock0, clock1; +input [widthad_a-1:0] address_a; +input [width_a-1:0] data_a; +input rden_a; +input wren_a; +input [(width_a/8)-1:0] byteena_a; +input addressstall_a; + +output [width_a-1:0] q_a; + +input wren_b; +input rden_b; +input [widthad_b-1:0] address_b; +input [width_b-1:0] data_b; +input [(width_b/8)-1:0] byteena_b; +input addressstall_b; + +output [width_b-1:0] q_b; + +input clocken0; +input clocken1; +input clocken2; +input clocken3; + +input aclr0; +input aclr1; + +output eccstatus; + +endmodule diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v new file mode 100644 index 000000000..d9961c174 --- /dev/null +++ b/techlibs/intel_alm/common/quartus_rename.v @@ -0,0 +1,19 @@ +module __MISTRAL_VCC(output Q); + +MISTRAL_ALUT2 #(.LUT(4'b1111)) _TECHMAP_REPLACE_ (.A(1'b1), .B(1'b1), .Q(Q)); + +endmodule + + +module __MISTRAL_GND(output Q); + +MISTRAL_ALUT2 #(.LUT(4'b0000)) _TECHMAP_REPLACE_ (.A(1'b1), .B(1'b1), .Q(Q)); + +endmodule + + +module MISTRAL_FF(input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, output reg Q); + +dffeas #(.power_up("low"), .is_wysiwyg("true")) _TECHMAP_REPLACE_ (.d(DATAIN), .clk(CLK), .clrn(ACLR), .ena(ENA), .sclr(SCLR), .sload(SLOAD), .asdata(SDATA), .q(Q)); + +endmodule diff --git a/techlibs/intel_alm/cyclone10gx/quartus_rename.v b/techlibs/intel_alm/cyclone10gx/quartus_rename.v new file mode 100644 index 000000000..3fbc508ed --- /dev/null +++ b/techlibs/intel_alm/cyclone10gx/quartus_rename.v @@ -0,0 +1,54 @@ +module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); +parameter LUT = 64'h0000_0000_0000_0000; + +cyclone10gx_lcell_comb #(.lut_mask(LUT)) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .dataf(F), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT5(input A, B, C, D, E, output Q); +parameter LUT = 32'h0000_0000; + +cyclone10gx_lcell_comb #(.lut_mask({2{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT4(input A, B, C, D, output Q); +parameter LUT = 16'h0000; + +cyclone10gx_lcell_comb #(.lut_mask({4{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT3(input A, B, C, output Q); +parameter LUT = 8'h00; + +cyclone10gx_lcell_comb #(.lut_mask({8{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT2(input A, B, output Q); +parameter LUT = 4'h0; + +cyclone10gx_lcell_comb #(.lut_mask({16{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .combout(Q)); + +endmodule + + +module MISTRAL_NOT(input A, output Q); + +NOT _TECHMAP_REPLACE_ (.IN(A), .OUT(Q)); + +endmodule + + +module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, CI, output SO, CO); +parameter LUT0 = 16'h0000; +parameter LUT1 = 16'h0000; + +cyclone10gx_lcell_comb #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO)); + +endmodule diff --git a/techlibs/intel_alm/cyclonev/quartus_rename.v b/techlibs/intel_alm/cyclonev/quartus_rename.v new file mode 100644 index 000000000..6eff375e1 --- /dev/null +++ b/techlibs/intel_alm/cyclonev/quartus_rename.v @@ -0,0 +1,54 @@ +module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); +parameter LUT = 64'h0000_0000_0000_0000; + +cyclonev_lcell_comb #(.lut_mask(LUT)) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .dataf(F), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT5(input A, B, C, D, E, output Q); +parameter LUT = 32'h0000_0000; + +cyclonev_lcell_comb #(.lut_mask({2{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT4(input A, B, C, D, output Q); +parameter LUT = 16'h0000; + +cyclonev_lcell_comb #(.lut_mask({4{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT3(input A, B, C, output Q); +parameter LUT = 8'h00; + +cyclonev_lcell_comb #(.lut_mask({8{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT2(input A, B, output Q); +parameter LUT = 4'h0; + +cyclonev_lcell_comb #(.lut_mask({16{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .combout(Q)); + +endmodule + + +module MISTRAL_NOT(input A, output Q); + +NOT _TECHMAP_REPLACE_ (.IN(A), .OUT(Q)); + +endmodule + + +module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, CI, output SO, CO); +parameter LUT0 = 16'h0000; +parameter LUT1 = 16'h0000; + +cyclonev_lcell_comb #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO)); + +endmodule diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc new file mode 100644 index 000000000..47aa11500 --- /dev/null +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -0,0 +1,241 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Wolf <claire@symbioticeda.com> + * Copyright (C) 2019 Dan Ravensloft <dan.ravensloft@gmail.com> + * + * 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 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/celltypes.h" +#include "kernel/log.h" +#include "kernel/register.h" +#include "kernel/rtlil.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SynthIntelALMPass : public ScriptPass { + SynthIntelALMPass() : ScriptPass("synth_intel_alm", "synthesis for ALM-based Intel (Altera) FPGAs.") {} + + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_intel_alm [options]\n"); + log("\n"); + log("This command runs synthesis for ALM-based Intel FPGAs.\n"); + log("\n"); + log(" -top <module>\n"); + log(" use the specified module as top module (default='top')\n"); + log("\n"); + log(" -family <family>\n"); + log(" target one of:\n"); + log(" \"cyclonev\" - Cyclone V (default)\n"); + log(" \"cyclone10gx\" - Cyclone 10GX\n"); + log("\n"); + log(" -quartus\n"); + log(" output a netlist using Quartus cells instead of MISTRAL_* cells\n"); + log("\n"); + log(" -vqm <file>\n"); + log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n"); + log(" output file is omitted if this parameter is not specified. Implies -quartus.\n"); + log("\n"); + log(" -run <from_label>:<to_label>\n"); + log(" only run the commands between the labels (see below). an empty\n"); + log(" from label is synonymous to 'begin', and empty to label is\n"); + log(" synonymous to the end of the command list.\n"); + log("\n"); + log(" -nolutram\n"); + log(" do not use LUT RAM cells in output netlist\n"); + log("\n"); + log(" -nobram\n"); + log(" do not use block RAM cells in output netlist\n"); + log("\n"); + log(" -noflatten\n"); + log(" do not flatten design before synthesis\n"); + log("\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); + log("\n"); + } + + string top_opt, family_opt, bram_type, vout_file; + bool flatten, quartus, nolutram, nobram; + + void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + family_opt = "cyclonev"; + bram_type = "m10k"; + vout_file = ""; + flatten = true; + quartus = false; + nolutram = false; + nobram = false; + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + string run_from, run_to; + clear_flags(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-family" && argidx + 1 < args.size()) { + family_opt = args[++argidx]; + continue; + } + if (args[argidx] == "-top" && argidx + 1 < args.size()) { + top_opt = "-top " + args[++argidx]; + continue; + } + if (args[argidx] == "-vqm" && argidx + 1 < args.size()) { + quartus = true; + vout_file = args[++argidx]; + continue; + } + if (args[argidx] == "-run" && argidx + 1 < args.size()) { + size_t pos = args[argidx + 1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos + 1); + continue; + } + if (args[argidx] == "-quartus") { + quartus = true; + continue; + } + if (args[argidx] == "-nolutram") { + nolutram = true; + continue; + } + if (args[argidx] == "-nobram") { + nobram = true; + continue; + } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + + if (family_opt == "cyclonev") { + bram_type = "m10k"; + } else if (family_opt == "cyclone10gx") { + bram_type = "m20k"; + } else { + log_cmd_error("Invalid family specified: '%s'\n", family_opt.c_str()); + } + + log_header(design, "Executing SYNTH_INTEL_ALM pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() YS_OVERRIDE + { + if (help_mode) { + family_opt = "<family>"; + bram_type = "<bram_type>"; + } + + if (check_label("begin")) { + run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/alm_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dff_sim.v", family_opt.c_str())); + + // Misc and common cells + run("read_verilog -lib +/intel/common/altpll_bb.v"); + run("read_verilog -lib +/intel_alm/common/megafunction_bb.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); + } + + if (flatten && check_label("flatten", "(unless -noflatten)")) { + run("proc"); + run("flatten"); + run("tribuf -logic"); + run("deminout"); + } + + if (check_label("coarse")) { + run("synth -run coarse -lut 6"); + run("techmap -map +/intel_alm/common/arith_alm_map.v"); + } + + if (!nobram && check_label("map_bram", "(skip if -nobram)")) { + run(stringf("memory_bram -rules +/intel_alm/common/bram_%s.txt", bram_type.c_str())); + run(stringf("techmap -map +/intel_alm/common/bram_%s_map.v", bram_type.c_str())); + } + + if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { + run("memory_bram -rules +/intel_alm/common/lutram_mlab.txt", "(for Cyclone V / Cyclone 10GX)"); + run("techmap -map +/intel_alm/common/lutram_mlab_map.v", "(for Cyclone V / Cyclone 10GX)"); + } + + if (check_label("map_ffram")) { + run("memory_map"); + run("opt -full"); + } + + if (check_label("map_ffs")) { + run("dff2dffe -direct-match $_DFF_*"); + run("zinit"); + run("techmap -map +/techmap.v -map +/intel_alm/common/dff_map.v"); + run("opt -full -undriven -mux_undef"); + run("clean -purge"); + } + + if (check_label("map_luts")) { + run("read_verilog -icells -specify -lib +/abc9_model.v"); + run("abc9 -maxlut 6 -W 200"); + run("techmap -map +/intel_alm/common/alm_map.v"); + run("opt -fast"); + run("autoname"); + run("clean"); + } + + if (check_label("check")) { + run("hierarchy -check"); + run("stat"); + run("check"); + } + + if (check_label("quartus")) { + if (quartus || help_mode) { + run("setundef -zero"); + run("hilomap -singleton -hicell __MISTRAL_VCC Q -locell __MISTRAL_GND Q"); + run("techmap -map +/intel_alm/common/quartus_rename.v"); + run(stringf("techmap -map +/intel_alm/%s/quartus_rename.v", family_opt.c_str())); + } + } + + if (check_label("vqm")) { + if (!vout_file.empty() || help_mode) { + run(stringf("write_verilog -attr2comment -defparam -nohex -decimal %s", help_mode ? "<file-name>" : vout_file.c_str())); + } + } + } +} SynthIntelALMPass; + +PRIVATE_NAMESPACE_END diff --git a/tests/arch/intel_alm/add_sub.ys b/tests/arch/intel_alm/add_sub.ys new file mode 100644 index 000000000..4cb2c2e0d --- /dev/null +++ b/tests/arch/intel_alm/add_sub.ys @@ -0,0 +1,8 @@ +read_verilog ../common/add_sub.v +hierarchy -top top +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +stat +select -assert-count 8 t:MISTRAL_ALUT_ARITH +select -assert-none t:MISTRAL_ALUT_ARITH %% t:* %D diff --git a/tests/arch/intel_alm/adffs.ys b/tests/arch/intel_alm/adffs.ys new file mode 100644 index 000000000..5d8d3a220 --- /dev/null +++ b/tests/arch/intel_alm/adffs.ys @@ -0,0 +1,48 @@ +read_verilog ../common/adffs.v +design -save read + +hierarchy -top adff +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd adff # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 1 t:MISTRAL_NOT + +select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D + + +design -load read +hierarchy -top adffn +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd adffn # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D + + +design -load read +hierarchy -top dffs +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd dffs # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 1 t:MISTRAL_ALUT2 + +select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 %% t:* %D + + +design -load read +hierarchy -top ndffnr +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd ndffnr # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 1 t:MISTRAL_ALUT2 + +select -assert-none t:MISTRAL_FF t:MISTRAL_NOT t:MISTRAL_ALUT2 %% t:* %D diff --git a/tests/arch/intel_alm/counter.ys b/tests/arch/intel_alm/counter.ys new file mode 100644 index 000000000..945c318d8 --- /dev/null +++ b/tests/arch/intel_alm/counter.ys @@ -0,0 +1,13 @@ +read_verilog ../common/counter.v +hierarchy -top top +proc +flatten +equiv_opt -async2sync -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module + +select -assert-count 2 t:MISTRAL_NOT +select -assert-count 8 t:MISTRAL_ALUT_ARITH +select -assert-count 8 t:MISTRAL_FF + +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT_ARITH t:MISTRAL_FF %% t:* %D diff --git a/tests/arch/intel_alm/dffs.ys b/tests/arch/intel_alm/dffs.ys new file mode 100644 index 000000000..cf29ad8e0 --- /dev/null +++ b/tests/arch/intel_alm/dffs.ys @@ -0,0 +1,22 @@ +read_verilog ../common/dffs.v +design -save read + +hierarchy -top dff +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd dff # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D + +design -load read +hierarchy -top dffe +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd dffe # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 1 t:MISTRAL_ALUT3 + +select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT3 %% t:* %D diff --git a/tests/arch/intel_alm/fsm.ys b/tests/arch/intel_alm/fsm.ys new file mode 100644 index 000000000..8bb0ebab2 --- /dev/null +++ b/tests/arch/intel_alm/fsm.ys @@ -0,0 +1,18 @@ +read_verilog ../common/fsm.v +hierarchy -top fsm +proc +flatten + +equiv_opt -run :prove -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev +async2sync +miter -equiv -make_assert -flatten gold gate miter +sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip 1 miter + +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd fsm # Constrain all select calls below inside the top module + +select -assert-count 6 t:MISTRAL_FF +select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1 +select -assert-count 5 t:MISTRAL_ALUT5 +select -assert-count 1 t:MISTRAL_ALUT6 +select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D diff --git a/tests/arch/intel_alm/logic.ys b/tests/arch/intel_alm/logic.ys new file mode 100644 index 000000000..fad45db74 --- /dev/null +++ b/tests/arch/intel_alm/logic.ys @@ -0,0 +1,11 @@ +read_verilog ../common/logic.v +hierarchy -top top +proc +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module + +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 6 t:MISTRAL_ALUT2 +select -assert-count 2 t:MISTRAL_ALUT4 +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT4 %% t:* %D diff --git a/tests/arch/intel_alm/mux.ys b/tests/arch/intel_alm/mux.ys new file mode 100644 index 000000000..308e45268 --- /dev/null +++ b/tests/arch/intel_alm/mux.ys @@ -0,0 +1,45 @@ +read_verilog ../common/mux.v +design -save read + +hierarchy -top mux2 +proc +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux2 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 + +select -assert-none t:MISTRAL_ALUT3 %% t:* %D + +design -load read +hierarchy -top mux4 +proc +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux4 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT6 + +select -assert-none t:MISTRAL_ALUT6 %% t:* %D + +design -load read +hierarchy -top mux8 +proc +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux8 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 +select -assert-count 1 t:MISTRAL_ALUT5 +select -assert-count 2 t:MISTRAL_ALUT6 + +select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D + +design -load read +hierarchy -top mux16 +proc +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux16 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 +select -assert-count 2 t:MISTRAL_ALUT5 +select -assert-count 4 t:MISTRAL_ALUT6 + +select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D diff --git a/tests/arch/intel_alm/run-test.sh b/tests/arch/intel_alm/run-test.sh new file mode 100755 index 000000000..bf19b887d --- /dev/null +++ b/tests/arch/intel_alm/run-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e +{ +echo "all::" +for x in *.ys; do + echo "all:: run-$x" + echo "run-$x:" + echo " @echo 'Running $x..'" + echo " @../../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x" +done +for s in *.sh; do + if [ "$s" != "run-test.sh" ]; then + echo "all:: run-$s" + echo "run-$s:" + echo " @echo 'Running $s..'" + echo " @bash $s" + fi +done +} > run-test.mk +exec ${MAKE:-make} -f run-test.mk diff --git a/tests/arch/intel_alm/shifter.ys b/tests/arch/intel_alm/shifter.ys new file mode 100644 index 000000000..014dbd1a8 --- /dev/null +++ b/tests/arch/intel_alm/shifter.ys @@ -0,0 +1,10 @@ +read_verilog ../common/shifter.v +hierarchy -top top +proc +flatten +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 8 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D diff --git a/tests/arch/intel_alm/tribuf.ys b/tests/arch/intel_alm/tribuf.ys new file mode 100644 index 000000000..71b05a747 --- /dev/null +++ b/tests/arch/intel_alm/tribuf.ys @@ -0,0 +1,13 @@ +read_verilog ../common/tribuf.v +hierarchy -top tristate +proc +tribuf +flatten +synth +equiv_opt -assert -map +/simcells.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd tristate # Constrain all select calls below inside the top module +#Internal cell type used. Need support it. +select -assert-count 1 t:$_TBUF_ + +select -assert-none t:$_TBUF_ %% t:* %D diff --git a/tests/opt/opt_expr_alu.ys b/tests/opt/opt_expr_alu.ys index a3361ca43..e288bcea6 100644 --- a/tests/opt/opt_expr_alu.ys +++ b/tests/opt/opt_expr_alu.ys @@ -5,7 +5,7 @@ endmodule EOT alumacc -equiv_opt opt_expr -fine +equiv_opt -assert opt_expr -fine design -load postopt select -assert-count 1 t:$pos select -assert-count none t:$pos t:* %D @@ -30,7 +30,7 @@ assign y = {a,1'b1} - 1'b1; endmodule EOT -equiv_opt opt_expr -fine +equiv_opt -assert opt_expr -fine design -load postopt select -assert-count 1 t:$pos select -assert-count none t:$pos t:* %D @@ -43,7 +43,7 @@ assign y = {a,3'b101} - 1'b1; endmodule EOT -equiv_opt opt_expr -fine +equiv_opt -assert opt_expr -fine design -load postopt select -assert-count 1 t:$pos select -assert-count none t:$pos t:* %D @@ -57,7 +57,55 @@ endmodule EOT alumacc -equiv_opt opt_expr -fine +equiv_opt -assert opt_expr -fine design -load postopt select -assert-count 1 t:$pos select -assert-count none t:$pos t:* %D + + +design -reset +read_verilog <<EOT +module test(input [1:0] a, output [3:0] y); +assign y = -{a[1], 2'b10, a[0]}; +endmodule +EOT + +alumacc +equiv_opt -assert opt -fine +design -load postopt +select -assert-count 1 t:$alu +select -assert-count 1 t:$alu r:Y_WIDTH=3 %i +select -assert-count 1 t:$not +select -assert-count none t:$alu t:$not t:* %D %D + + +design -reset +read_verilog <<EOT +module test(input [3:0] a, input [2:0] b, output [5:0] y); +assign y = {a[3:2], 1'b1, a[1:0]} + {b[2], 2'b11, b[1:0]}; +endmodule +EOT + +alumacc +equiv_opt -assert opt -fine +design -load postopt +dump +select -assert-count 2 t:$alu +select -assert-count 1 t:$alu r:Y_WIDTH=2 %i +select -assert-count 1 t:$alu r:Y_WIDTH=3 %i +select -assert-count none t:$alu t:* %D + + +design -reset +read_verilog <<EOT +module test(input [3:0] a, input [3:0] b, output [5:0] y); +assign y = {a[3:2], 1'b0, a[1:0]} + {b[3:2], 1'b0, b[1:0]}; +endmodule +EOT + +alumacc +equiv_opt -assert opt -fine +design -load postopt +select -assert-count 2 t:$alu +select -assert-count 2 t:$alu r:Y_WIDTH=3 %i +select -assert-count none t:$alu t:* %D diff --git a/tests/svtypes/typedef_package.sv b/tests/svtypes/typedef_package.sv index 57a78c53a..2d83742c5 100644 --- a/tests/svtypes/typedef_package.sv +++ b/tests/svtypes/typedef_package.sv @@ -1,6 +1,9 @@ package pkg; typedef logic [7:0] uint8_t; - typedef enum logic [7:0] {bb=8'hBB} enum8_t; + typedef enum logic [7:0] {bb=8'hBB, cc=8'hCC} enum8_t; + + localparam uint8_t PCONST = cc; + parameter uint8_t PCONST_COPY = PCONST; endpackage module top; @@ -8,7 +11,9 @@ module top; (* keep *) pkg::uint8_t a = 8'hAA; (* keep *) pkg::enum8_t b_enum = pkg::bb; - always @* assert(a == 8'hAA); - always @* assert(b_enum == 8'hBB); + always_comb assert(a == 8'hAA); + always_comb assert(b_enum == 8'hBB); + always_comb assert(pkg::PCONST == pkg::cc); + always_comb assert(pkg::PCONST_COPY == pkg::cc); endmodule diff --git a/tests/techmap/dffinit.ys b/tests/techmap/dffinit.ys new file mode 100644 index 000000000..218d411f8 --- /dev/null +++ b/tests/techmap/dffinit.ys @@ -0,0 +1,25 @@ +read_verilog <<EOT + +module ff(...); +input d; +output q; + +endmodule + +module top(...); +input d; +output q1; +(* init = 1'b1 *) +output q2; + +ff my_ff1(.d(d), .q(q1)); +ff my_ff2(.d(d), .q(q2)); + +endmodule + +EOT + +dffinit -ff ff q init +select -assert-count 2 t:ff +select -assert-count 1 t:ff r:init %i +select -assert-count 1 t:ff r:init=1'b1 %i diff --git a/tests/various/bug1876.ys b/tests/various/bug1876.ys new file mode 100644 index 000000000..7995eedcf --- /dev/null +++ b/tests/various/bug1876.ys @@ -0,0 +1,60 @@ +read_verilog <<EOT +module expression_00032(b5, y15); + input signed [5:0] b5; + output [3:0] y15; + assign y15 = (0 ? b5 : b5) > 0; +endmodule +EOT + + +design -reset +read_verilog <<EOT +module expression_00057(a0, a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5, y8); + input [3:0] a0; + input [4:0] a1; + input [5:0] a2; + input signed [3:0] a3; + input signed [4:0] a4; + input signed [5:0] a5; + + input [3:0] b0; + input [4:0] b1; + input [5:0] b2; + input signed [3:0] b3; + input signed [4:0] b4; + input signed [5:0] b5; + + output [5:0] y8; + + localparam signed [4:0] p4 = ((2'd3)||(-4'sd1)); + localparam signed [3:0] p9 = {3{(((2'sd0)^~(5'd20))>((-3'sd0)>>(4'sd2)))}}; + + assign y8 = (-(!($signed({3{p9}})<(p4?b4:b5)))); +endmodule +EOT + + +design -reset +read_verilog <<EOT +module expression_00354(a0, a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5, y4); + input [3:0] a0; + input [4:0] a1; + input [5:0] a2; + input signed [3:0] a3; + input signed [4:0] a4; + input signed [5:0] a5; + + input [3:0] b0; + input [4:0] b1; + input [5:0] b2; + input signed [3:0] b3; + input signed [4:0] b4; + input signed [5:0] b5; + + output wire signed [4:0] y4; + + localparam signed [4:0] p10 = ((3'd0)?(2'd1):(-2'sd1)); + + assign y4 = ((p10?a4:b4)&$signed(b3)); +endmodule +EOT |