From 23c9828d7015ba9811e1dba08e2194fdf58e9497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 9 Jan 2024 12:05:15 +0100 Subject: [PATCH 001/184] opt_clean: Remove dead branch --- passes/opt/opt_clean.cc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 8b56895fe..19056e7e1 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -436,13 +436,6 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos if (!raw_used_signals.check_any(s1)) { // delete wires that aren't used by anything directly goto delete_this_wire; - } else - if (!used_signals.check_any(s2)) { - // this path shouldn't be possible: this wire is used directly (otherwise it would get cleaned up above), and indirectly - // used wires are a superset of those used directly - log_assert(false); - // delete wires that aren't used by anything indirectly, even though other wires may alias it - goto delete_this_wire; } if (0) From 158fbf881e0ba514e659e0e948491b045eab9f61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 6 Mar 2024 15:15:37 +0100 Subject: [PATCH 002/184] memory_map: Explain `-iattr` better --- passes/memory/memory_map.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index cafc0aaf3..d1dd0fd88 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -415,7 +415,7 @@ struct MemoryMapPass : public Pass { log(" to any of the values.\n"); log("\n"); log(" -iattr\n"); - log(" for -attr, ignore case of .\n"); + log(" for -attr, suppress case sensitivity in matching of .\n"); log("\n"); log(" -rom-only\n"); log(" only perform conversion for ROMs (memories with no write ports).\n"); From 858eae5572375fac376f6c2bb43e976abe73af0d Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 8 Nov 2023 17:10:40 +0100 Subject: [PATCH 003/184] verific_const: convert VHDL values to RTLIL consts --- frontends/verific/verific.cc | 64 +++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index faa0e1bcd..6fc87ced6 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -223,7 +223,7 @@ RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj) // // Note: For signed values, verific uses 'sb and decimal values can // also be negative. -static const RTLIL::Const verific_const(const char *value, bool allow_string = true, bool output_signed = false) +static const RTLIL::Const verific_const(const char *value, bool from_vhdl, bool allow_string = true, bool output_signed = false) { size_t found; char *end; @@ -231,26 +231,44 @@ static const RTLIL::Const verific_const(const char *value, bool allow_string = t bool is_signed = false; RTLIL::Const c; std::string val = std::string(value); - if (allow_string && val.size()>1 && val[0]=='\"' && val.back()=='\"') { - c = RTLIL::Const(val.substr(1,val.size()-2)); - } else if ((found = val.find("'sb")) != std::string::npos) { - is_signed = output_signed; - c = RTLIL::Const::from_string(val.substr(found + 3)); - } else if ((found = val.find("'b")) != std::string::npos) { - c = RTLIL::Const::from_string(val.substr(found + 2)); - } else if ((value[0] == '-' || (value[0] >= '0' && value[0] <= '9')) && - ((decimal = std::strtol(value, &end, 10)), !end[0])) { - is_signed = output_signed; - c = RTLIL::Const((int)decimal, 32); - } else if (allow_string) { - c = RTLIL::Const(val); + if (from_vhdl) { + if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { + std::string data = val.substr(1,val.size()-2); + bool isBinary = std::all_of(data.begin(), data.end(), [](char c) {return c=='1' || c=='0'; }); + if (isBinary) + c = RTLIL::Const::from_string(data); + else + c = RTLIL::Const(data); + } else if (val.size()==3 && val[0]=='\'' && val.back()=='\'') { + c = RTLIL::Const::from_string(val.substr(1,val.size()-2)); + } else if ((value[0] == '-' || (value[0] >= '0' && value[0] <= '9')) && + ((decimal = std::strtol(value, &end, 10)), !end[0])) { + is_signed = output_signed; + c = RTLIL::Const((int)decimal, 32); + } else { + log_error("non-expected '%s' constant found", value); + } } else { - log_error("expected numeric constant but found '%s'", value); + if (allow_string && val.size()>1 && val[0]=='\"' && val.back()=='\"') { + c = RTLIL::Const(val.substr(1,val.size()-2)); + } else if ((found = val.find("'sb")) != std::string::npos) { + is_signed = output_signed; + c = RTLIL::Const::from_string(val.substr(found + 3)); + } else if ((found = val.find("'b")) != std::string::npos) { + c = RTLIL::Const::from_string(val.substr(found + 2)); + } else if ((value[0] == '-' || (value[0] >= '0' && value[0] <= '9')) && + ((decimal = std::strtol(value, &end, 10)), !end[0])) { + is_signed = output_signed; + c = RTLIL::Const((int)decimal, 32); + } else if (allow_string) { + c = RTLIL::Const(val); + } else { + log_error("expected numeric constant but found '%s'", value); + } + + if (is_signed) + c.flags |= RTLIL::CONST_FLAG_SIGNED; } - - if (is_signed) - c.flags |= RTLIL::CONST_FLAG_SIGNED; - return c; } @@ -276,7 +294,7 @@ void VerificImporter::import_attributes(dict &att FOREACH_ATTRIBUTE(obj, mi, attr) { if (attr->Key()[0] == ' ' || attr->Value() == nullptr) continue; - attributes[RTLIL::escape_id(attr->Key())] = verific_const(attr->Value()); + attributes[RTLIL::escape_id(attr->Key())] = verific_const(attr->Value(), obj->IsFromVhdl()); } if (nl) { @@ -298,7 +316,7 @@ void VerificImporter::import_attributes(dict &att const char *k, *v; FOREACH_MAP_ITEM(type_range->GetEnumIdMap(), mi, &k, &v) { if (nl->IsFromVerilog()) { - auto const value = verific_const(v, false); + auto const value = verific_const(v, nl->IsFromVhdl(), false); attributes.emplace(stringf("\\enum_value_%s", value.as_string().c_str()), RTLIL::escape_id(k)); } @@ -1304,7 +1322,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma MapIter mi; FOREACH_PARAMETER_OF_NETLIST(nl, mi, param_name, param_value) { module->avail_parameters(RTLIL::escape_id(param_name)); - module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(param_value); + module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(param_value, nl->IsFromVhdl()); } SetIter si; @@ -2004,7 +2022,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma const char *param_value ; if (is_blackbox(inst->View())) { FOREACH_PARAMETER_OF_INST(inst, mi2, param_name, param_value) { - cell->setParam(RTLIL::escape_id(param_name), verific_const(param_value)); + cell->setParam(RTLIL::escape_id(param_name), verific_const(param_value, nl->IsFromVhdl())); } } From 4279cea33a91aa934f65072e7b6c34830f55b037 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 11 Mar 2024 09:30:58 +0100 Subject: [PATCH 004/184] improve handling VHDL constants --- frontends/verific/verific.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 6fc87ced6..6dbad4c2a 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -223,7 +223,7 @@ RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj) // // Note: For signed values, verific uses 'sb and decimal values can // also be negative. -static const RTLIL::Const verific_const(const char *value, bool from_vhdl, bool allow_string = true, bool output_signed = false) +static const RTLIL::Const verific_const(const char *value, DesignObj *obj, bool allow_string = true, bool output_signed = false) { size_t found; char *end; @@ -231,7 +231,7 @@ static const RTLIL::Const verific_const(const char *value, bool from_vhdl, bool bool is_signed = false; RTLIL::Const c; std::string val = std::string(value); - if (from_vhdl) { + if (obj->IsFromVhdl()) { if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { std::string data = val.substr(1,val.size()-2); bool isBinary = std::all_of(data.begin(), data.end(), [](char c) {return c=='1' || c=='0'; }); @@ -245,6 +245,10 @@ static const RTLIL::Const verific_const(const char *value, bool from_vhdl, bool ((decimal = std::strtol(value, &end, 10)), !end[0])) { is_signed = output_signed; c = RTLIL::Const((int)decimal, 32); + } else if (val == "false") { + c = RTLIL::Const::from_string("0"); + } else if (val == "true") { + c = RTLIL::Const::from_string("1"); } else { log_error("non-expected '%s' constant found", value); } @@ -294,7 +298,7 @@ void VerificImporter::import_attributes(dict &att FOREACH_ATTRIBUTE(obj, mi, attr) { if (attr->Key()[0] == ' ' || attr->Value() == nullptr) continue; - attributes[RTLIL::escape_id(attr->Key())] = verific_const(attr->Value(), obj->IsFromVhdl()); + attributes[RTLIL::escape_id(attr->Key())] = verific_const(attr->Value(), obj); } if (nl) { @@ -316,7 +320,7 @@ void VerificImporter::import_attributes(dict &att const char *k, *v; FOREACH_MAP_ITEM(type_range->GetEnumIdMap(), mi, &k, &v) { if (nl->IsFromVerilog()) { - auto const value = verific_const(v, nl->IsFromVhdl(), false); + auto const value = verific_const(v, nl, false); attributes.emplace(stringf("\\enum_value_%s", value.as_string().c_str()), RTLIL::escape_id(k)); } @@ -1322,7 +1326,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma MapIter mi; FOREACH_PARAMETER_OF_NETLIST(nl, mi, param_name, param_value) { module->avail_parameters(RTLIL::escape_id(param_name)); - module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(param_value, nl->IsFromVhdl()); + module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(param_value, nl); } SetIter si; @@ -2022,7 +2026,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma const char *param_value ; if (is_blackbox(inst->View())) { FOREACH_PARAMETER_OF_INST(inst, mi2, param_name, param_value) { - cell->setParam(RTLIL::escape_id(param_name), verific_const(param_value, nl->IsFromVhdl())); + cell->setParam(RTLIL::escape_id(param_name), verific_const(param_value, inst->View())); } } From 7c09fa572e2eb4cce2cfdfcfdbc7ca327382ad2a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 14 Mar 2024 10:37:11 +0100 Subject: [PATCH 005/184] real number handling and default to string --- frontends/verific/verific.cc | 50 +++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 6dbad4c2a..a5bcd44c4 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -214,6 +214,22 @@ RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj) return s; } +RTLIL::Const mkconst_str(const std::string &str) +{ + RTLIL::Const val; + std::vector data; + data.reserve(str.size() * 8); + for (size_t i = 0; i < str.size(); i++) { + unsigned char ch = str[str.size() - i - 1]; + for (int j = 0; j < 8; j++) { + data.push_back((ch & 1) ? State::S1 : State::S0); + ch = ch >> 1; + } + } + val.bits = data; + val.flags |= RTLIL::CONST_FLAG_STRING; + return val; +} // When used as attributes or parameter values Verific constants come already processed. // - Real string values are already under quotes // - Numeric values with specified width are always converted to binary @@ -223,7 +239,7 @@ RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj) // // Note: For signed values, verific uses 'sb and decimal values can // also be negative. -static const RTLIL::Const verific_const(const char *value, DesignObj *obj, bool allow_string = true, bool output_signed = false) +static const RTLIL::Const verific_const(const char* type_name, const char *value, DesignObj *obj, bool allow_string = true, bool output_signed = false) { size_t found; char *end; @@ -232,7 +248,10 @@ static const RTLIL::Const verific_const(const char *value, DesignObj *obj, bool RTLIL::Const c; std::string val = std::string(value); if (obj->IsFromVhdl()) { - if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { + if (type_name && strcmp(type_name, "real")==0) { + c = mkconst_str(val); + c.flags |= RTLIL::CONST_FLAG_REAL; + } else if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { std::string data = val.substr(1,val.size()-2); bool isBinary = std::all_of(data.begin(), data.end(), [](char c) {return c=='1' || c=='0'; }); if (isBinary) @@ -250,10 +269,14 @@ static const RTLIL::Const verific_const(const char *value, DesignObj *obj, bool } else if (val == "true") { c = RTLIL::Const::from_string("1"); } else { - log_error("non-expected '%s' constant found", value); + c = mkconst_str(val); + log_warning("encoding value '%s' of type '%s' as string found", value, type_name ? type_name : "unknown"); } } else { - if (allow_string && val.size()>1 && val[0]=='\"' && val.back()=='\"') { + if (type_name && strcmp(type_name, "real")==0) { + c = mkconst_str(val); + c.flags |= RTLIL::CONST_FLAG_REAL; + } else if (allow_string && val.size()>1 && val[0]=='\"' && val.back()=='\"') { c = RTLIL::Const(val.substr(1,val.size()-2)); } else if ((found = val.find("'sb")) != std::string::npos) { is_signed = output_signed; @@ -267,12 +290,13 @@ static const RTLIL::Const verific_const(const char *value, DesignObj *obj, bool } else if (allow_string) { c = RTLIL::Const(val); } else { - log_error("expected numeric constant but found '%s'", value); + c = mkconst_str(val); + log_warning("encoding value '%s' of type '%s' as string found", value, type_name ? type_name : "unknown"); } - - if (is_signed) - c.flags |= RTLIL::CONST_FLAG_SIGNED; } + + if (is_signed) + c.flags |= RTLIL::CONST_FLAG_SIGNED; return c; } @@ -298,7 +322,7 @@ void VerificImporter::import_attributes(dict &att FOREACH_ATTRIBUTE(obj, mi, attr) { if (attr->Key()[0] == ' ' || attr->Value() == nullptr) continue; - attributes[RTLIL::escape_id(attr->Key())] = verific_const(attr->Value(), obj); + attributes[RTLIL::escape_id(attr->Key())] = verific_const(nullptr, attr->Value(), obj); } if (nl) { @@ -320,7 +344,7 @@ void VerificImporter::import_attributes(dict &att const char *k, *v; FOREACH_MAP_ITEM(type_range->GetEnumIdMap(), mi, &k, &v) { if (nl->IsFromVerilog()) { - auto const value = verific_const(v, nl, false); + auto const value = verific_const(type_name, v, nl, false); attributes.emplace(stringf("\\enum_value_%s", value.as_string().c_str()), RTLIL::escape_id(k)); } @@ -1326,7 +1350,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma MapIter mi; FOREACH_PARAMETER_OF_NETLIST(nl, mi, param_name, param_value) { module->avail_parameters(RTLIL::escape_id(param_name)); - module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(param_value, nl); + const TypeRange *tr = nl->GetTypeRange(param_name) ; + module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(tr->GetTypeName(), param_value, nl); } SetIter si; @@ -2026,7 +2051,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma const char *param_value ; if (is_blackbox(inst->View())) { FOREACH_PARAMETER_OF_INST(inst, mi2, param_name, param_value) { - cell->setParam(RTLIL::escape_id(param_name), verific_const(param_value, inst->View())); + const TypeRange *tr = inst->View()->GetTypeRange(param_name) ; + cell->setParam(RTLIL::escape_id(param_name), verific_const(tr->GetTypeName(), param_value, inst->View())); } } From 3eeefd23e38a53b28923749feaa9f57670e07d5c Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:08:13 +1300 Subject: [PATCH 006/184] Typo fixup(s) --- frontends/ast/genrtlil.cc | 2 +- kernel/driver.cc | 2 +- passes/pmgen/ice40_dsp.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index fe67f00c6..e1cf6fb57 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -2224,7 +2224,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) else input_error("FATAL.\n"); } else { - input_error("Unknown elabortoon system task '%s'.\n", str.c_str()); + input_error("Unknown elaboration system task '%s'.\n", str.c_str()); } } break; diff --git a/kernel/driver.cc b/kernel/driver.cc index 58da1bc32..79dff7dda 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -356,7 +356,7 @@ int main(int argc, char **argv) printf(" -V\n"); printf(" print version information and exit\n"); printf("\n"); - printf("The option -S is an shortcut for calling the \"synth\" command, a default\n"); + printf("The option -S is a shortcut for calling the \"synth\" command, a default\n"); printf("script for transforming the Verilog input to a gate-level netlist. For example:\n"); printf("\n"); printf(" yosys -o output.blif -S input.v\n"); diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 24134b1fb..5720c9b1e 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -289,7 +289,7 @@ struct Ice40DspPass : public Pass { log("\n"); log("Pack input registers (A, B, {C,D}; with optional hold), pipeline registers\n"); log("({F,J,K,G}, H), output registers (O -- full 32-bits or lower 16-bits only; with\n"); - log("optional hold), and post-adder into into the SB_MAC16 resource.\n"); + log("optional hold), and post-adder into the SB_MAC16 resource.\n"); log("\n"); log("Multiply-accumulate operations using the post-adder with feedback on the {C,D}\n"); log("input will be folded into the DSP. In this scenario only, resetting the\n"); From ff10aeebd68a1906703cc4a63b70ca0f30474c0d Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:33:18 +1300 Subject: [PATCH 007/184] Fix some synth_* help messages Mostly memory_libmap arg checks; puts the checks into an else block on the `if (help_mode)` check to avoid cases like `synth_ice40` listing `-no-auto-huge [-no-auto-huge]`. Also fix `map_iopad` section being empty in `synth_fabulous`. --- techlibs/anlogic/synth_anlogic.cc | 10 ++++++---- techlibs/ecp5/synth_ecp5.cc | 10 ++++++---- techlibs/efinix/synth_efinix.cc | 10 +++++++--- techlibs/fabulous/synth_fabulous.cc | 4 ++-- techlibs/gowin/synth_gowin.cc | 10 ++++++---- techlibs/ice40/synth_ice40.cc | 10 ++++++---- techlibs/lattice/synth_lattice.cc | 10 ++++++---- techlibs/nexus/synth_nexus.cc | 10 ++++++---- 8 files changed, 45 insertions(+), 29 deletions(-) diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc index a3c1e0434..c72e7f2a1 100644 --- a/techlibs/anlogic/synth_anlogic.cc +++ b/techlibs/anlogic/synth_anlogic.cc @@ -169,12 +169,14 @@ struct SynthAnlogicPass : public ScriptPass if (check_label("map_ram")) { std::string args = ""; - if (nobram) - args += " -no-auto-block"; - if (nolutram) - args += " -no-auto-distributed"; if (help_mode) args += " [-no-auto-block] [-no-auto-distributed]"; + else { + if (nobram) + args += " -no-auto-block"; + if (nolutram) + args += " -no-auto-distributed"; + } run("memory_libmap -lib +/anlogic/lutrams.txt -lib +/anlogic/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); run("techmap -map +/anlogic/lutrams_map.v -map +/anlogic/brams_map.v"); } diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index f6215987f..6e518f5d1 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -308,12 +308,14 @@ struct SynthEcp5Pass : public ScriptPass if (check_label("map_ram")) { std::string args = ""; - if (nobram) - args += " -no-auto-block"; - if (nolutram) - args += " -no-auto-distributed"; if (help_mode) args += " [-no-auto-block] [-no-auto-distributed]"; + else { + if (nobram) + args += " -no-auto-block"; + if (nolutram) + args += " -no-auto-distributed"; + } run("memory_libmap -lib +/ecp5/lutrams.txt -lib +/ecp5/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); run("techmap -map +/ecp5/lutrams_map.v -map +/ecp5/brams_map.v"); } diff --git a/techlibs/efinix/synth_efinix.cc b/techlibs/efinix/synth_efinix.cc index bbc389444..419bc2f88 100644 --- a/techlibs/efinix/synth_efinix.cc +++ b/techlibs/efinix/synth_efinix.cc @@ -161,9 +161,13 @@ struct SynthEfinixPass : public ScriptPass if (check_label("map_ram")) { std::string args = ""; - if (nobram) - args += " -no-auto-block"; - run("memory_libmap -lib +/efinix/brams.txt" + args); + if (help_mode) + args += " [-no-auto-block]"; + else { + if (nobram) + args += " -no-auto-block"; + } + run("memory_libmap -lib +/efinix/brams.txt" + args, "(-no-auto-block if -nobram)"); run("techmap -map +/efinix/brams_map.v"); } diff --git a/techlibs/fabulous/synth_fabulous.cc b/techlibs/fabulous/synth_fabulous.cc index b4a7ab2dc..8d2fb1471 100644 --- a/techlibs/fabulous/synth_fabulous.cc +++ b/techlibs/fabulous/synth_fabulous.cc @@ -320,7 +320,7 @@ struct SynthPass : public ScriptPass run("opt_clean"); } - if (check_label("map_ram")) { + if (check_label("map_ram", "(unless -noregfile)")) { // RegFile extraction if (!noregfile) { run("memory_libmap -lib +/fabulous/ram_regfile.txt"); @@ -342,7 +342,7 @@ struct SynthPass : public ScriptPass } if (check_label("map_iopad", "(if -iopad)")) { - if (iopad) { + if (iopad || help_mode) { run("opt -full"); run("iopadmap -bits -outpad $__FABULOUS_OBUF I:PAD -inpad $__FABULOUS_IBUF O:PAD " "-toutpad IO_1_bidirectional_frame_config_pass ~T:I:PAD " diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 85022c1cf..48b7563b1 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -230,12 +230,14 @@ struct SynthGowinPass : public ScriptPass if (check_label("map_ram")) { std::string args = ""; - if (nobram) - args += " -no-auto-block"; - if (nolutram) - args += " -no-auto-distributed"; if (help_mode) args += " [-no-auto-block] [-no-auto-distributed]"; + else { + if (nobram) + args += " -no-auto-block"; + if (nolutram) + args += " -no-auto-distributed"; + } run("memory_libmap -lib +/gowin/lutrams.txt -lib +/gowin/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); run("techmap -map +/gowin/lutrams_map.v -map +/gowin/brams_map.v"); } diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 4c691c7a5..818323892 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -353,12 +353,14 @@ struct SynthIce40Pass : public ScriptPass if (check_label("map_ram")) { std::string args = ""; - if (!spram) - args += " -no-auto-huge"; - if (nobram) - args += " -no-auto-block"; if (help_mode) args += " [-no-auto-huge] [-no-auto-block]"; + else { + if (!spram) + args += " -no-auto-huge"; + if (nobram) + args += " -no-auto-block"; + } run("memory_libmap -lib +/ice40/brams.txt -lib +/ice40/spram.txt" + args, "(-no-auto-huge unless -spram, -no-auto-block if -nobram)"); run("techmap -map +/ice40/brams_map.v -map +/ice40/spram_map.v"); run("ice40_braminit"); diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index cc5821ad8..16a068b07 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -373,12 +373,14 @@ struct SynthLatticePass : public ScriptPass if (check_label("map_ram")) { std::string args = ""; - if (nobram) - args += " -no-auto-block"; - if (nolutram) - args += " -no-auto-distributed"; if (help_mode) args += " [-no-auto-block] [-no-auto-distributed]"; + else { + if (nobram) + args += " -no-auto-block"; + if (nolutram) + args += " -no-auto-distributed"; + } run("memory_libmap -lib +/lattice/lutrams.txt -lib +/lattice/brams" + brams_map + ".txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); run("techmap -map +/lattice/lutrams_map.v -map +/lattice/brams_map" + brams_map + ".v"); } diff --git a/techlibs/nexus/synth_nexus.cc b/techlibs/nexus/synth_nexus.cc index 6fd15ba55..2935fbd3b 100644 --- a/techlibs/nexus/synth_nexus.cc +++ b/techlibs/nexus/synth_nexus.cc @@ -300,12 +300,14 @@ struct SynthNexusPass : public ScriptPass { std::string args = ""; args += " -no-auto-huge"; - if (nobram) - args += " -no-auto-block"; - if (nolutram) - args += " -no-auto-distributed"; if (help_mode) args += " [-no-auto-block] [-no-auto-distributed]"; + else { + if (nobram) + args += " -no-auto-block"; + if (nolutram) + args += " -no-auto-distributed"; + } run("memory_libmap -lib +/nexus/lutrams.txt -lib +/nexus/brams.txt -lib +/nexus/lrams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); run("techmap -map +/nexus/lutrams_map.v -map +/nexus/brams_map.v -map +/nexus/lrams_map.v"); } From 9eebc801705c6f7c179f354774b9d87174b3ec3f Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 18 Mar 2024 10:35:01 +0100 Subject: [PATCH 008/184] handle standard types --- frontends/verific/verific.cc | 47 +++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index a5bcd44c4..62c070db5 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -248,9 +248,50 @@ static const RTLIL::Const verific_const(const char* type_name, const char *value RTLIL::Const c; std::string val = std::string(value); if (obj->IsFromVhdl()) { - if (type_name && strcmp(type_name, "real")==0) { - c = mkconst_str(val); - c.flags |= RTLIL::CONST_FLAG_REAL; + if (type_name) { + if (strcmp(type_name, "integer")==0 || strcmp(type_name, "natural")==0 || strcmp(type_name, "positive")==0) { + decimal = std::strtol(value, &end, 10); + c = RTLIL::Const((int)decimal, 32); + } else if (strcmp(type_name, "boolean")==0) { + if (val == "false") { + c = RTLIL::Const::from_string("0"); + } else if (val == "true") { + c = RTLIL::Const::from_string("1"); + } else + log_error("Error parsing boolean\n"); + } else if (strcmp(type_name, "bit")==0 || strcmp(type_name, "STD_LOGIC")==0 || strcmp(type_name, "STD_ULOGIC")==0) { + if (val.size()==3 && val[0]=='\'' && val.back()=='\'') { + c = RTLIL::Const::from_string(val.substr(1,val.size()-2)); + } else + log_error("Error parsing %s\n", type_name); + } else if (strcmp(type_name, "character")==0) { + if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { + c = RTLIL::Const((int)val[1], 32); + } else + log_error("Error parsing character\n"); + } else if (strcmp(type_name, "bit_vector")==0 || strcmp(type_name, "STD_LOGIC_VECTOR")==0 || strcmp(type_name, "STD_ULOGIC_VECTOR")==0 || + strcmp(type_name, "UNSIGNED")==0 || strcmp(type_name, "SIGNED")==0) { + if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { + c = RTLIL::Const::from_string(val.substr(1,val.size()-2)); + } else + log_error("Error parsing %s\n", type_name); + if (strcmp(type_name, "SIGNED")==0) + is_signed = true; + } else if (strcmp(type_name, "real")==0) { + c = mkconst_str(val); + c.flags |= RTLIL::CONST_FLAG_REAL; + } else if (strcmp(type_name, "string")==0) { + if (!(val.size()>1 && val[0]=='\"' && val.back()=='\"')) + log_error("Error parsing string\n"); + c = RTLIL::Const(val.substr(1,val.size()-2)); + } else { + if (val.size()>1 && val[0]=='\"' && val.back()=='\"') + c = RTLIL::Const(val.substr(1,val.size()-2)); + else if (val.size()==3 && val[0]=='\'' && val.back()=='\'') + c = RTLIL::Const(val.substr(1,val.size()-2)); + else + c = RTLIL::Const(val); + } } else if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { std::string data = val.substr(1,val.size()-2); bool isBinary = std::all_of(data.begin(), data.end(), [](char c) {return c=='1' || c=='0'; }); From 4367e176fbfcfc3722dfa4a7a12c66cd430e3bf5 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 19 Mar 2024 09:15:04 +0100 Subject: [PATCH 009/184] code split and cleanup --- frontends/verific/verific.cc | 231 +++++++++++++++++++++-------------- 1 file changed, 141 insertions(+), 90 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 62c070db5..96e0469f6 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -230,6 +230,126 @@ RTLIL::Const mkconst_str(const std::string &str) val.flags |= RTLIL::CONST_FLAG_STRING; return val; } + +static const RTLIL::Const extract_vhdl_boolean(std::string &val) +{ + if (val == "false") + return RTLIL::Const::from_string("0"); + if (val == "true") + return RTLIL::Const::from_string("1"); + log_error("Expecting VHDL boolean value.\n"); +} + +static const RTLIL::Const extract_vhdl_bit(std::string &val, std::string &typ) +{ + if (val.size()==3 && val[0]=='\'' && val.back()=='\'') + return RTLIL::Const::from_string(val.substr(1,val.size()-2)); + log_error("Error parsing VHDL %s.\n", typ.c_str()); +} + +static const RTLIL::Const extract_vhdl_bit_vector(std::string &val, std::string &typ) +{ + if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { + RTLIL::Const c = RTLIL::Const::from_string(val.substr(1,val.size()-2)); + if (typ == "signed") + c.flags |= RTLIL::CONST_FLAG_SIGNED; + return c; + } + log_error("Error parsing VHDL %s.\n", typ.c_str()); +} + +static const RTLIL::Const extract_vhdl_integer(std::string &val) +{ + char *end; + return RTLIL::Const((int)std::strtol(val.c_str(), &end, 10), 32); +} + +static const RTLIL::Const extract_vhdl_char(std::string &val) +{ + if (val.size()==3 && val[0]=='\"' && val.back()=='\"') + return RTLIL::Const((int)val[1], 32); + log_error("Error parsing VHDL character.\n"); +} + +static const RTLIL::Const extract_real_value(std::string &val) +{ + RTLIL::Const c = mkconst_str(val); + c.flags |= RTLIL::CONST_FLAG_REAL; + return c; +} + +static const RTLIL::Const extract_vhdl_string(std::string &val) +{ + if (!(val.size()>1 && val[0]=='\"' && val.back()=='\"')) + log_error("Error parsing VHDL string.\n"); + return RTLIL::Const(val.substr(1,val.size()-2)); +} + +static const RTLIL::Const extract_vhdl_const(const char *value, bool output_signed) +{ + RTLIL::Const c; + char *end; + int decimal; + bool is_signed = false; + std::string val = std::string(value); + + if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { + std::string data = val.substr(1,val.size()-2); + bool isBinary = std::all_of(data.begin(), data.end(), [](char c) {return c=='1' || c=='0'; }); + if (isBinary) + c = RTLIL::Const::from_string(data); + else + c = RTLIL::Const(data); + } else if (val.size()==3 && val[0]=='\'' && val.back()=='\'') { + c = RTLIL::Const::from_string(val.substr(1,val.size()-2)); + } else if ((value[0] == '-' || (value[0] >= '0' && value[0] <= '9')) && + ((decimal = std::strtol(value, &end, 10)), !end[0])) { + is_signed = output_signed; + c = RTLIL::Const((int)decimal, 32); + } else if (val == "false") { + c = RTLIL::Const::from_string("0"); + } else if (val == "true") { + c = RTLIL::Const::from_string("1"); + } else { + c = mkconst_str(val); + log_warning("encoding value '%s' as string.\n", value); + } + if (is_signed) + c.flags |= RTLIL::CONST_FLAG_SIGNED; + return c; +} + +static const RTLIL::Const extract_verilog_const(const char *value, bool allow_string, bool output_signed) +{ + RTLIL::Const c; + char *end; + int decimal; + bool is_signed = false; + size_t found; + std::string val = std::string(value); + + if (allow_string && val.size()>1 && val[0]=='\"' && val.back()=='\"') { + c = RTLIL::Const(val.substr(1,val.size()-2)); + } else if ((found = val.find("'sb")) != std::string::npos) { + is_signed = output_signed; + c = RTLIL::Const::from_string(val.substr(found + 3)); + } else if ((found = val.find("'b")) != std::string::npos) { + c = RTLIL::Const::from_string(val.substr(found + 2)); + } else if ((value[0] == '-' || (value[0] >= '0' && value[0] <= '9')) && + ((decimal = std::strtol(value, &end, 10)), !end[0])) { + is_signed = output_signed; + c = RTLIL::Const((int)decimal, 32); + } else if (allow_string) { + c = RTLIL::Const(val); + } else { + c = mkconst_str(val); + log_warning("encoding value '%s' as string.\n", value); + } + if (is_signed) + c.flags |= RTLIL::CONST_FLAG_SIGNED; + return c; +} + // When used as attributes or parameter values Verific constants come already processed. // - Real string values are already under quotes // - Numeric values with specified width are always converted to binary @@ -241,104 +361,35 @@ RTLIL::Const mkconst_str(const std::string &str) // also be negative. static const RTLIL::Const verific_const(const char* type_name, const char *value, DesignObj *obj, bool allow_string = true, bool output_signed = false) { - size_t found; - char *end; - int decimal; - bool is_signed = false; - RTLIL::Const c; std::string val = std::string(value); + // VHDL if (obj->IsFromVhdl()) { if (type_name) { - if (strcmp(type_name, "integer")==0 || strcmp(type_name, "natural")==0 || strcmp(type_name, "positive")==0) { - decimal = std::strtol(value, &end, 10); - c = RTLIL::Const((int)decimal, 32); - } else if (strcmp(type_name, "boolean")==0) { - if (val == "false") { - c = RTLIL::Const::from_string("0"); - } else if (val == "true") { - c = RTLIL::Const::from_string("1"); - } else - log_error("Error parsing boolean\n"); - } else if (strcmp(type_name, "bit")==0 || strcmp(type_name, "STD_LOGIC")==0 || strcmp(type_name, "STD_ULOGIC")==0) { - if (val.size()==3 && val[0]=='\'' && val.back()=='\'') { - c = RTLIL::Const::from_string(val.substr(1,val.size()-2)); - } else - log_error("Error parsing %s\n", type_name); - } else if (strcmp(type_name, "character")==0) { - if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { - c = RTLIL::Const((int)val[1], 32); - } else - log_error("Error parsing character\n"); - } else if (strcmp(type_name, "bit_vector")==0 || strcmp(type_name, "STD_LOGIC_VECTOR")==0 || strcmp(type_name, "STD_ULOGIC_VECTOR")==0 || - strcmp(type_name, "UNSIGNED")==0 || strcmp(type_name, "SIGNED")==0) { - if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { - c = RTLIL::Const::from_string(val.substr(1,val.size()-2)); - } else - log_error("Error parsing %s\n", type_name); - if (strcmp(type_name, "SIGNED")==0) - is_signed = true; - } else if (strcmp(type_name, "real")==0) { - c = mkconst_str(val); - c.flags |= RTLIL::CONST_FLAG_REAL; - } else if (strcmp(type_name, "string")==0) { - if (!(val.size()>1 && val[0]=='\"' && val.back()=='\"')) - log_error("Error parsing string\n"); - c = RTLIL::Const(val.substr(1,val.size()-2)); - } else { + std::string typ = std::string(type_name); + transform(typ.begin(), typ.end(), typ.begin(), ::tolower); + if (typ == "integer" || typ == "natural" || typ=="positive") return extract_vhdl_integer(val); + else if (typ =="boolean") return extract_vhdl_boolean(val); + else if (typ == "bit" || typ =="std_logic" || typ == "std_ulogic") return extract_vhdl_bit(val,typ); + else if (typ == "character") return extract_vhdl_char(val); + else if (typ == "bit_vector" || typ == "std_logic_vector" || typ == "std_ulogic_vector" || + typ == "unsigned" || typ == "signed") return extract_vhdl_bit_vector(val,typ); + else if (typ == "real") return extract_real_value(val); + else if (typ == "string") return extract_vhdl_string(val); + else { if (val.size()>1 && val[0]=='\"' && val.back()=='\"') - c = RTLIL::Const(val.substr(1,val.size()-2)); + return RTLIL::Const(val.substr(1,val.size()-2)); else if (val.size()==3 && val[0]=='\'' && val.back()=='\'') - c = RTLIL::Const(val.substr(1,val.size()-2)); + return RTLIL::Const(val.substr(1,val.size()-2)); else - c = RTLIL::Const(val); + return RTLIL::Const(val); } - } else if (val.size()>1 && val[0]=='\"' && val.back()=='\"') { - std::string data = val.substr(1,val.size()-2); - bool isBinary = std::all_of(data.begin(), data.end(), [](char c) {return c=='1' || c=='0'; }); - if (isBinary) - c = RTLIL::Const::from_string(data); - else - c = RTLIL::Const(data); - } else if (val.size()==3 && val[0]=='\'' && val.back()=='\'') { - c = RTLIL::Const::from_string(val.substr(1,val.size()-2)); - } else if ((value[0] == '-' || (value[0] >= '0' && value[0] <= '9')) && - ((decimal = std::strtol(value, &end, 10)), !end[0])) { - is_signed = output_signed; - c = RTLIL::Const((int)decimal, 32); - } else if (val == "false") { - c = RTLIL::Const::from_string("0"); - } else if (val == "true") { - c = RTLIL::Const::from_string("1"); - } else { - c = mkconst_str(val); - log_warning("encoding value '%s' of type '%s' as string found", value, type_name ? type_name : "unknown"); - } - } else { - if (type_name && strcmp(type_name, "real")==0) { - c = mkconst_str(val); - c.flags |= RTLIL::CONST_FLAG_REAL; - } else if (allow_string && val.size()>1 && val[0]=='\"' && val.back()=='\"') { - c = RTLIL::Const(val.substr(1,val.size()-2)); - } else if ((found = val.find("'sb")) != std::string::npos) { - is_signed = output_signed; - c = RTLIL::Const::from_string(val.substr(found + 3)); - } else if ((found = val.find("'b")) != std::string::npos) { - c = RTLIL::Const::from_string(val.substr(found + 2)); - } else if ((value[0] == '-' || (value[0] >= '0' && value[0] <= '9')) && - ((decimal = std::strtol(value, &end, 10)), !end[0])) { - is_signed = output_signed; - c = RTLIL::Const((int)decimal, 32); - } else if (allow_string) { - c = RTLIL::Const(val); - } else { - c = mkconst_str(val); - log_warning("encoding value '%s' of type '%s' as string found", value, type_name ? type_name : "unknown"); - } + } else extract_vhdl_const(value, output_signed); } - - if (is_signed) - c.flags |= RTLIL::CONST_FLAG_SIGNED; - return c; + // SystemVerilog + if (type_name && strcmp(type_name, "real")==0) { + return extract_real_value(val); + } else + return extract_verilog_const(value, allow_string, output_signed); } static const std::string verific_unescape(const char *value) From 160e3e089a14b79fa76de7c303140d3d4c0fd1da Mon Sep 17 00:00:00 2001 From: Peter Gadfort Date: Fri, 22 Mar 2024 09:20:08 -0400 Subject: [PATCH 010/184] add port statistics to stat command --- passes/cmds/stat.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 85107b68f..c2bb72f3b 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -36,7 +36,8 @@ struct cell_area_t { struct statdata_t { #define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \ - X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes) + X(num_ports) X(num_port_bits) X(num_memories) X(num_memory_bits) X(num_cells) \ + X(num_processes) #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area) @@ -90,6 +91,11 @@ struct statdata_t for (auto wire : mod->selected_wires()) { + if (wire->port_input || wire->port_output) { + num_ports++; + num_port_bits += wire->width; + } + if (wire->name.isPublic()) { num_pub_wires++; num_pub_wire_bits += wire->width; @@ -239,6 +245,8 @@ struct statdata_t log(" Number of wire bits: %6u\n", num_wire_bits); log(" Number of public wires: %6u\n", num_pub_wires); log(" Number of public wire bits: %6u\n", num_pub_wire_bits); + log(" Number of ports: %6u\n", num_ports); + log(" Number of port bits: %6u\n", num_port_bits); log(" Number of memories: %6u\n", num_memories); log(" Number of memory bits: %6u\n", num_memory_bits); log(" Number of processes: %6u\n", num_processes); @@ -284,6 +292,8 @@ struct statdata_t log(" \"num_wire_bits\": %u,\n", num_wire_bits); log(" \"num_pub_wires\": %u,\n", num_pub_wires); log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits); + log(" \"num_ports\": %u,\n", num_ports); + log(" \"num_port_bits\": %u,\n", num_port_bits); log(" \"num_memories\": %u,\n", num_memories); log(" \"num_memory_bits\": %u,\n", num_memory_bits); log(" \"num_processes\": %u,\n", num_processes); @@ -494,6 +504,8 @@ struct StatPass : public Pass { design->scratchpad_set_int("stat.num_wire_bits", data.num_wire_bits); design->scratchpad_set_int("stat.num_pub_wires", data.num_pub_wires); design->scratchpad_set_int("stat.num_pub_wire_bits", data.num_pub_wire_bits); + design->scratchpad_set_int("stat.num_ports", data.num_ports); + design->scratchpad_set_int("stat.num_port_bits", data.num_port_bits); design->scratchpad_set_int("stat.num_memories", data.num_memories); design->scratchpad_set_int("stat.num_memory_bits", data.num_memory_bits); design->scratchpad_set_int("stat.num_processes", data.num_processes); From c38201e15d457388b26d712df4aa10266015c22d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 25 Mar 2024 14:56:17 +0100 Subject: [PATCH 011/184] techmap: Add a Kogge-Stone option for `$lcu` mapping --- techlibs/common/techmap.v | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index 7fb8173b0..38ca33cb9 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -230,6 +230,7 @@ module _90_lcu (P, G, CI, CO); // in almost all cases CI will be constant zero g[0] = g[0] | (p[0] & CI); +`ifndef KOGGE_STONE // [[CITE]] Brent Kung Adder // R. P. Brent and H. T. Kung, "A Regular Layout for Parallel Adders", // IEEE Transaction on Computers, Vol. C-31, No. 3, p. 260-264, March, 1982 @@ -249,6 +250,14 @@ module _90_lcu (P, G, CI, CO); p[j] = p[j] & p[j - 2**(i-1)]; end end +`else + for (i = 0; i < $clog2(WIDTH); i = i + 1) begin + for (j = 2**i; j < WIDTH; j = j + 1) begin + g[j] = g[j] | p[j] & g[j - 2**i]; + p[j] = p[j] & p[j - 2**i]; + end + end +`endif end assign CO = g; From 4570d064e5bac128f4057874457e306d4e275eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 25 Mar 2024 18:39:55 +0100 Subject: [PATCH 012/184] techmap: Split out Kogge-Stone into a separate file --- techlibs/common/Makefile.inc | 1 + techlibs/common/choices/kogge-stone.v | 53 +++++++++++++++++++++++++++ techlibs/common/techmap.v | 11 +----- 3 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 techlibs/common/choices/kogge-stone.v diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index 6b377855e..fa5c2a825 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc @@ -35,3 +35,4 @@ $(eval $(call add_share_file,share,techlibs/common/abc9_map.v)) $(eval $(call add_share_file,share,techlibs/common/abc9_unmap.v)) $(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v)) $(eval $(call add_share_file,share,techlibs/common/cmp2softlogic.v)) +$(eval $(call add_share_file,share/choices,techlibs/common/choices/kogge-stone.v)) diff --git a/techlibs/common/choices/kogge-stone.v b/techlibs/common/choices/kogge-stone.v new file mode 100644 index 000000000..eb97a75d8 --- /dev/null +++ b/techlibs/common/choices/kogge-stone.v @@ -0,0 +1,53 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Martin Povišer + * + * 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. + * + */ + +(* techmap_celltype = "$lcu" *) +module _80_lcu_kogge_stone (P, G, CI, CO); + parameter WIDTH = 2; + + (* force_downto *) + input [WIDTH-1:0] P, G; + input CI; + + (* force_downto *) + output [WIDTH-1:0] CO; + + integer i, j; + (* force_downto *) + reg [WIDTH-1:0] p, g; + + wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast"; + + always @* begin + p = P; + g = G; + + // in almost all cases CI will be constant zero + g[0] = g[0] | (p[0] & CI); + + for (i = 0; i < $clog2(WIDTH); i = i + 1) begin + for (j = 2**i; j < WIDTH; j = j + 1) begin + g[j] = g[j] | p[j] & g[j - 2**i]; + p[j] = p[j] & p[j - 2**i]; + end + end + end + + assign CO = g; +endmodule diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index 38ca33cb9..68b276588 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -207,7 +207,7 @@ module _90_fa (A, B, C, X, Y); endmodule (* techmap_celltype = "$lcu" *) -module _90_lcu (P, G, CI, CO); +module _90_lcu_brent_kung (P, G, CI, CO); parameter WIDTH = 2; (* force_downto *) @@ -230,7 +230,6 @@ module _90_lcu (P, G, CI, CO); // in almost all cases CI will be constant zero g[0] = g[0] | (p[0] & CI); -`ifndef KOGGE_STONE // [[CITE]] Brent Kung Adder // R. P. Brent and H. T. Kung, "A Regular Layout for Parallel Adders", // IEEE Transaction on Computers, Vol. C-31, No. 3, p. 260-264, March, 1982 @@ -250,14 +249,6 @@ module _90_lcu (P, G, CI, CO); p[j] = p[j] & p[j - 2**(i-1)]; end end -`else - for (i = 0; i < $clog2(WIDTH); i = i + 1) begin - for (j = 2**i; j < WIDTH; j = j + 1) begin - g[j] = g[j] | p[j] & g[j - 2**i]; - p[j] = p[j] & p[j - 2**i]; - end - end -`endif end assign CO = g; From c49d6e78743fb51335c0640af9d4dc8b6c9407cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 27 Mar 2024 11:08:26 +0100 Subject: [PATCH 013/184] techmap: Add Kogge-Stone test --- tests/techmap/kogge-stone.ys | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/techmap/kogge-stone.ys diff --git a/tests/techmap/kogge-stone.ys b/tests/techmap/kogge-stone.ys new file mode 100644 index 000000000..fc3637f10 --- /dev/null +++ b/tests/techmap/kogge-stone.ys @@ -0,0 +1 @@ +test_cell -s 1711533949 -n 10 -map +/techmap.v -map +/choices/kogge-stone.v $lcu From bc087f91ed2779fec32c94d99f56cebca3c6a4b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 27 Mar 2024 18:32:25 +0100 Subject: [PATCH 014/184] techmap: Fix using overwritten results in Kogge-Stone --- techlibs/common/choices/kogge-stone.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/common/choices/kogge-stone.v b/techlibs/common/choices/kogge-stone.v index eb97a75d8..0e25fe860 100644 --- a/techlibs/common/choices/kogge-stone.v +++ b/techlibs/common/choices/kogge-stone.v @@ -42,7 +42,7 @@ module _80_lcu_kogge_stone (P, G, CI, CO); g[0] = g[0] | (p[0] & CI); for (i = 0; i < $clog2(WIDTH); i = i + 1) begin - for (j = 2**i; j < WIDTH; j = j + 1) begin + for (j = WIDTH - 1; j >= 2**i; j = j - 1) begin g[j] = g[j] | p[j] & g[j - 2**i]; p[j] = p[j] & p[j - 2**i]; end From f536de0e0e585fe3c6146bc7e8f1a4d3b0e14bc4 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 28 Mar 2024 13:21:55 +0100 Subject: [PATCH 015/184] Verific support for VHDL 2019 --- frontends/verific/Makefile.inc | 1 + frontends/verific/verific.cc | 29 ++++++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/frontends/verific/Makefile.inc b/frontends/verific/Makefile.inc index c82428613..df3ac8d2d 100644 --- a/frontends/verific/Makefile.inc +++ b/frontends/verific/Makefile.inc @@ -14,6 +14,7 @@ ifneq ($(DISABLE_VERIFIC_VHDL),1) $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1987/. share/verific.new/vhdl_vdbs_1987 $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1993/. share/verific.new/vhdl_vdbs_1993 $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008/. share/verific.new/vhdl_vdbs_2008 + $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2019/. share/verific.new/vhdl_vdbs_2019 endif $(Q) chmod -R a+rX share/verific.new $(Q) mv share/verific.new share/verific diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index faa0e1bcd..a65fde42f 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2699,7 +2699,7 @@ struct VerificPass : public Pass { log("\n"); log("\n"); #ifdef VERIFIC_VHDL_SUPPORT - log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} ..\n"); + log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl2019|-vhdl} ..\n"); log("\n"); log("Load the specified VHDL files into Verific.\n"); log("\n"); @@ -3436,6 +3436,29 @@ struct VerificPass : public Pass { goto check_error; } + if (GetSize(args) > argidx && (args[argidx] == "-vhdl2019")) { + vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2019").c_str()); + bool flag_lib = false; + for (argidx++; argidx < GetSize(args); argidx++) { + if (args[argidx] == "-lib") { + flag_lib = true; + continue; + } + if (args[argidx].compare(0, 1, "-") == 0) { + cmd_error(args, argidx, "unknown option"); + goto check_error; + } + Map map(POINTER_HASH); + add_units_to_map(map, work, flag_lib); + std::string filename = frontent_rewrite(args, argidx, tmp_files); + if (!vhdl_file::Analyze(filename.c_str(), work.c_str(), vhdl_file::VHDL_2019)) + log_cmd_error("Reading `%s' in VHDL_2019 mode failed.\n", filename.c_str()); + set_units_to_blackbox(map, work, flag_lib); + } + verific_import_pending = true; + goto check_error; + } + if (GetSize(args) > argidx && (args[argidx] == "-vhdl2008" || args[argidx] == "-vhdl")) { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str()); bool flag_lib = false; @@ -3979,7 +4002,7 @@ struct ReadPass : public Pass { log("\n"); log("\n"); #ifdef VERIFIC_VHDL_SUPPORT - log(" read {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} ..\n"); + log(" read {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl2019|-vhdl} ..\n"); log("\n"); log("Load the specified VHDL files. (Requires Verific.)\n"); log("\n"); @@ -4083,7 +4106,7 @@ struct ReadPass : public Pass { } #ifdef VERIFIC_VHDL_SUPPORT - if (args[1] == "-vhdl87" || args[1] == "-vhdl93" || args[1] == "-vhdl2k" || args[1] == "-vhdl2008" || args[1] == "-vhdl") { + if (args[1] == "-vhdl87" || args[1] == "-vhdl93" || args[1] == "-vhdl2k" || args[1] == "-vhdl2008" || args[1] == "-vhdl2019" || args[1] == "-vhdl") { if (use_verific) { args[0] = "verific"; Pass::call(design, args); From d07a55a852e3e9430daba9068878b1ac10605f0a Mon Sep 17 00:00:00 2001 From: Merry <8682882+merryhime@users.noreply.github.com> Date: Fri, 29 Mar 2024 20:53:26 +0000 Subject: [PATCH 016/184] cxxrtl: Fix sdivmod x = x.neg(); results in the subsequent x.is_neg() always being false. Ditto for the dividend.is_neg() != divisor.is_neg() test. --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 8 +- tests/cxxrtl/test_value_fuzz.cc | 105 ++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 4 deletions(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index b834cd120..16aa900f1 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -625,11 +625,11 @@ struct value : public expr_base> { value remainder; value dividend = sext(); value divisor = other.template sext(); - if (dividend.is_neg()) dividend = dividend.neg(); - if (divisor.is_neg()) divisor = divisor.neg(); + if (is_neg()) dividend = dividend.neg(); + if (other.is_neg()) divisor = divisor.neg(); std::tie(quotient, remainder) = dividend.udivmod(divisor); - if (dividend.is_neg() != divisor.is_neg()) quotient = quotient.neg(); - if (dividend.is_neg()) remainder = remainder.neg(); + if (is_neg() != other.is_neg()) quotient = quotient.neg(); + if (is_neg()) remainder = remainder.neg(); return {quotient.template trunc(), remainder.template trunc()}; } }; diff --git a/tests/cxxrtl/test_value_fuzz.cc b/tests/cxxrtl/test_value_fuzz.cc index 4428e9f6e..a7bbb293a 100644 --- a/tests/cxxrtl/test_value_fuzz.cc +++ b/tests/cxxrtl/test_value_fuzz.cc @@ -25,6 +25,11 @@ T rand_int(T min = std::numeric_limits::min(), T max = std::numeric_limits return dist(generator); } +int64_t sext(size_t bits, uint64_t value) +{ + return (int64_t)(value << (64 - bits)) >> (64 - bits); +} + struct BinaryOperationBase { void tweak_input(uint64_t &a, uint64_t &b) {} @@ -246,6 +251,106 @@ struct CtlzTest } } ctlz; +struct UdivTest : BinaryOperationBase +{ + UdivTest() + { + std::printf("Randomized tests for value::udivmod (div):\n"); + test_binary_operation(*this); + } + + uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b) + { + return a / b; + } + + template + cxxrtl::value testing_impl(cxxrtl::value a, cxxrtl::value b) + { + return std::get<0>(a.udivmod(b)); + } + + void tweak_input(uint64_t &, uint64_t &b) + { + if (b == 0) b = 1; // Avoid divide by zero + } +} udiv; + +struct UmodTest : BinaryOperationBase +{ + UmodTest() + { + std::printf("Randomized tests for value::udivmod (mod):\n"); + test_binary_operation(*this); + } + + uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b) + { + return a % b; + } + + template + cxxrtl::value testing_impl(cxxrtl::value a, cxxrtl::value b) + { + return std::get<1>(a.udivmod(b)); + } + + void tweak_input(uint64_t &, uint64_t &b) + { + if (b == 0) b = 1; // Avoid divide by zero + } +} umod; + +struct SdivTest : BinaryOperationBase +{ + SdivTest() + { + std::printf("Randomized tests for value::sdivmod (div):\n"); + test_binary_operation(*this); + } + + uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b) + { + return (uint64_t)(sext(bits, a) / sext(bits, b)); + } + + template + cxxrtl::value testing_impl(cxxrtl::value a, cxxrtl::value b) + { + return std::get<0>(a.sdivmod(b)); + } + + void tweak_input(uint64_t &, uint64_t &b) + { + if (b == 0) b = 1; // Avoid divide by zero + } +} sdiv; + +struct SmodTest : BinaryOperationBase +{ + SmodTest() + { + std::printf("Randomized tests for value::sdivmod (mod):\n"); + test_binary_operation(*this); + } + + uint64_t reference_impl(size_t bits, uint64_t a, uint64_t b) + { + return (uint64_t)(sext(bits, a) % sext(bits, b)); + } + + template + cxxrtl::value testing_impl(cxxrtl::value a, cxxrtl::value b) + { + return std::get<1>(a.sdivmod(b)); + } + + void tweak_input(uint64_t &, uint64_t &b) + { + if (b == 0) b = 1; // Avoid divide by zero + } +} smod; + int main() { } From b9d3bffda5abcbc5356936a7192c4a3c2b427c3e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 31 Mar 2024 00:18:11 +0000 Subject: [PATCH 017/184] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 391fb7288..ca229ca4a 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.39+147 +YOSYS_VER := 0.39+149 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 73cacd543c98ab29b9ea23104339c5405ce1f6ef Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 2 Apr 2024 11:23:56 +0200 Subject: [PATCH 018/184] docs: Update linux kernel coding style link --- guidelines/CodingStyle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guidelines/CodingStyle b/guidelines/CodingStyle index ee1e1a2b6..8a3df2d62 100644 --- a/guidelines/CodingStyle +++ b/guidelines/CodingStyle @@ -19,7 +19,7 @@ Formatting of code blank lines. - Otherwise stick to the Linux Kernel Coding Style: - https://www.kernel.org/doc/Documentation/CodingStyle + https://www.kernel.org/doc/Documentation/process/coding-style.rst C++ Language From a5441bc00c957c268279b35924d055418eb79446 Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 28 Mar 2024 06:30:16 +0000 Subject: [PATCH 019/184] =?UTF-8?q?fmt:=20`FmtPart::{STRING=E2=86=92LITERA?= =?UTF-8?q?L},{CHARACTER=E2=86=92STRING}`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this commit, the `STRING` variant inserted a literal string; the `CHARACTER` variant inserted a string. This commit renames them to `LITERAL` and `STRING` respectively. --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 14 ++++---- frontends/ast/genrtlil.cc | 2 +- frontends/ast/simplify.cc | 2 +- kernel/fmt.cc | 44 ++++++++++++------------- kernel/fmt.h | 12 +++---- 5 files changed, 37 insertions(+), 37 deletions(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index 16aa900f1..b1fc7e05c 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -1010,19 +1010,19 @@ struct observer { // Default member initializers would make this a non-aggregate-type in C++11, so they are commented out. struct fmt_part { enum { - STRING = 0, + LITERAL = 0, INTEGER = 1, - CHARACTER = 2, + STRING = 2, VLOG_TIME = 3, } type; - // STRING type + // LITERAL type std::string str; - // INTEGER/CHARACTER types + // INTEGER/STRING types // + value val; - // INTEGER/CHARACTER/VLOG_TIME types + // INTEGER/STRING/VLOG_TIME types enum { RIGHT = 0, LEFT = 1, @@ -1050,10 +1050,10 @@ struct fmt_part { // chunk access if it turns out to be slow enough to matter. std::string buf; switch (type) { - case STRING: + case LITERAL: return str; - case CHARACTER: { + case STRING: { buf.reserve(Bits/8); for (int i = 0; i < Bits; i += 8) { char ch = 0; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index fe67f00c6..bc7f1ddd1 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -790,7 +790,7 @@ struct AST_INTERNAL::ProcessGenerator Fmt fmt; fmt.parse_verilog(args, /*sformat_like=*/false, default_base, /*task_name=*/ast->str, current_module->name); if (ast->str.substr(0, 8) == "$display") - fmt.append_string("\n"); + fmt.append_literal("\n"); fmt.emit_rtlil(cell); } else if (!ast->str.empty()) { log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 43a4e03a2..3d8478ef1 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1079,7 +1079,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // when $display()/$write() functions are used in an initial block, print them during synthesis Fmt fmt = processFormat(stage, /*sformat_like=*/false, default_base, /*first_arg_at=*/0, /*may_fail=*/true); if (str.substr(0, 8) == "$display") - fmt.append_string("\n"); + fmt.append_literal("\n"); log("%s", fmt.render().c_str()); } diff --git a/kernel/fmt.cc b/kernel/fmt.cc index 18eb7cb71..336e3e2ab 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -22,9 +22,9 @@ USING_YOSYS_NAMESPACE -void Fmt::append_string(const std::string &str) { +void Fmt::append_literal(const std::string &str) { FmtPart part = {}; - part.type = FmtPart::STRING; + part.type = FmtPart::LITERAL; part.str = str; parts.push_back(part); } @@ -46,7 +46,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { log_assert(false && "Unexpected '}' in format string"); else if (fmt[i] == '{') { if (!part.str.empty()) { - part.type = FmtPart::STRING; + part.type = FmtPart::LITERAL; parts.push_back(part); part = {}; } @@ -108,7 +108,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { part.type = FmtPart::INTEGER; part.base = 16; } else if (fmt[i] == 'c') { - part.type = FmtPart::CHARACTER; + part.type = FmtPart::STRING; } else if (fmt[i] == 't') { part.type = FmtPart::VLOG_TIME; } else if (fmt[i] == 'r') { @@ -150,7 +150,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { } } if (!part.str.empty()) { - part.type = FmtPart::STRING; + part.type = FmtPart::LITERAL; parts.push_back(part); } } @@ -161,7 +161,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const { for (auto &part : parts) { switch (part.type) { - case FmtPart::STRING: + case FmtPart::LITERAL: for (char c : part.str) { if (c == '{') fmt += "{{"; @@ -175,7 +175,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const { case FmtPart::VLOG_TIME: log_assert(part.sig.size() == 0); YS_FALLTHROUGH - case FmtPart::CHARACTER: + case FmtPart::STRING: log_assert(part.sig.size() % 8 == 0); YS_FALLTHROUGH case FmtPart::INTEGER: @@ -203,7 +203,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const { if (part.plus) fmt += '+'; fmt += part.signed_ ? 's' : 'u'; - } else if (part.type == FmtPart::CHARACTER) { + } else if (part.type == FmtPart::STRING) { fmt += 'c'; } else if (part.type == FmtPart::VLOG_TIME) { if (part.realtime) @@ -299,12 +299,12 @@ void Fmt::apply_verilog_automatic_sizing_and_add(FmtPart &part) part.width = places; if (part.justify == FmtPart::RIGHT) { - append_string(gap); + append_literal(gap); parts.push_back(part); } else { part.justify = FmtPart::RIGHT; parts.push_back(part); - append_string(gap); + append_literal(gap); } } } @@ -355,7 +355,7 @@ void Fmt::parse_verilog(const std::vector &args, bool sformat_lik part.str += module_name.str(); } else { if (!part.str.empty()) { - part.type = FmtPart::STRING; + part.type = FmtPart::LITERAL; parts.push_back(part); part = {}; } @@ -408,11 +408,11 @@ void Fmt::parse_verilog(const std::vector &args, bool sformat_lik part.type = FmtPart::INTEGER; part.base = 16; } else if (fmt[i] == 'c' || fmt[i] == 'C') { - part.type = FmtPart::CHARACTER; + part.type = FmtPart::STRING; part.sig.extend_u0(8); // %10c and %010c not fully defined in IEEE 1800-2017 and do different things in iverilog } else if (fmt[i] == 's' || fmt[i] == 'S') { - part.type = FmtPart::CHARACTER; + part.type = FmtPart::STRING; if ((part.sig.size() % 8) != 0) part.sig.extend_u0((part.sig.size() + 7) / 8 * 8); // %10s and %010s not fully defined in IEEE 1800-2017 and do the same thing in iverilog @@ -449,12 +449,12 @@ void Fmt::parse_verilog(const std::vector &args, bool sformat_lik } } if (!part.str.empty()) { - part.type = FmtPart::STRING; + part.type = FmtPart::LITERAL; parts.push_back(part); } } else { FmtPart part = {}; - part.type = FmtPart::STRING; + part.type = FmtPart::LITERAL; part.str = arg->str; parts.push_back(part); } @@ -474,7 +474,7 @@ std::vector Fmt::emit_verilog() const for (auto &part : parts) { switch (part.type) { - case FmtPart::STRING: + case FmtPart::LITERAL: for (char c : part.str) { if (c == '%') fmt.str += "%%"; @@ -513,7 +513,7 @@ std::vector Fmt::emit_verilog() const break; } - case FmtPart::CHARACTER: { + case FmtPart::STRING: { VerilogFmtArg arg; arg.type = VerilogFmtArg::INTEGER; arg.sig = part.sig; @@ -599,9 +599,9 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function parts; - void append_string(const std::string &str); + void append_literal(const std::string &str); void parse_rtlil(const RTLIL::Cell *cell); void emit_rtlil(RTLIL::Cell *cell) const; From 8388846e3a727f42aa6086226863e530c22f07f6 Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 28 Mar 2024 06:13:35 +0000 Subject: [PATCH 020/184] fmt,cxxrtl: add support for uppercase hex format. This is necessary for translating Python format strings in Amaranth. --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 3 ++- kernel/fmt.cc | 11 ++++++++--- kernel/fmt.h | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index b1fc7e05c..b3a537435 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -1034,6 +1034,7 @@ struct fmt_part { unsigned base; // = 10; bool signed_; // = false; bool plus; // = false; + bool hex_upper; // = false; // VLOG_TIME type bool realtime; // = false; @@ -1085,7 +1086,7 @@ struct fmt_part { uint8_t value = val.bit(index) | (val.bit(index + 1) << 1) | (val.bit(index + 2) << 2); if (step == 4) value |= val.bit(index + 3) << 3; - buf += "0123456789abcdef"[value]; + buf += (hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[value]; } std::reverse(buf.begin(), buf.end()); } else if (base == 10) { diff --git a/kernel/fmt.cc b/kernel/fmt.cc index 336e3e2ab..6fdc18ad0 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -107,6 +107,10 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { } else if (fmt[i] == 'h') { part.type = FmtPart::INTEGER; part.base = 16; + } else if (fmt[i] == 'H') { + part.type = FmtPart::INTEGER; + part.base = 16; + part.hex_upper = true; } else if (fmt[i] == 'c') { part.type = FmtPart::STRING; } else if (fmt[i] == 't') { @@ -197,7 +201,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const { case 2: fmt += 'b'; break; case 8: fmt += 'o'; break; case 10: fmt += 'd'; break; - case 16: fmt += 'h'; break; + case 16: fmt += part.hex_upper ? 'H' : 'h'; break; default: log_abort(); } if (part.plus) @@ -507,7 +511,7 @@ std::vector Fmt::emit_verilog() const case 2: fmt.str += 'b'; break; case 8: fmt.str += 'o'; break; case 10: fmt.str += 'd'; break; - case 16: fmt.str += 'h'; break; + case 16: fmt.str += 'h'; break; // treat uppercase hex as lowercase default: log_abort(); } break; @@ -617,6 +621,7 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function Date: Thu, 28 Mar 2024 06:59:23 +0000 Subject: [PATCH 021/184] fmt,cxxrtl: support `{,PLUS_,SPACE_}MINUS` integer formats. The first two were already supported with the `plus` boolean flag. The third one is a new specifier, which is allocated the ` ` character. In addition, `MINUS` is now allocated the `-` character, but old format where there is no `+`, `-`, or `-` in the respective position is also accepted for compatibility. --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 13 +++++-- kernel/fmt.cc | 47 ++++++++++++++++++------- kernel/fmt.h | 6 +++- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index b3a537435..02050df58 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -1033,7 +1033,11 @@ struct fmt_part { // INTEGER type unsigned base; // = 10; bool signed_; // = false; - bool plus; // = false; + enum { + MINUS = 0, + PLUS_MINUS = 1, + SPACE_MINUS = 2, + } sign; // = MINUS; bool hex_upper; // = false; // VLOG_TIME type @@ -1105,8 +1109,11 @@ struct fmt_part { buf += '0' + remainder.template trunc<4>().template get(); xval = quotient; } - if (negative || plus) - buf += negative ? '-' : '+'; + switch (sign) { + case MINUS: buf += negative ? "-" : ""; break; + case PLUS_MINUS: buf += negative ? "-" : "+"; break; + case SPACE_MINUS: buf += negative ? "-" : " "; break; + } std::reverse(buf.begin(), buf.end()); } else assert(false && "Unsupported base for fmt_part"); break; diff --git a/kernel/fmt.cc b/kernel/fmt.cc index 6fdc18ad0..342b508d9 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -128,10 +128,20 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { log_assert(false && "Unexpected end in format substitution"); if (part.type == FmtPart::INTEGER) { - if (fmt[i] == '+') { - part.plus = true; + if (fmt[i] == '-') { + part.sign = FmtPart::MINUS; if (++i == fmt.size()) log_assert(false && "Unexpected end in format substitution"); + } else if (fmt[i] == '+') { + part.sign = FmtPart::PLUS_MINUS; + if (++i == fmt.size()) + log_assert(false && "Unexpected end in format substitution"); + } else if (fmt[i] == ' ') { + part.sign = FmtPart::SPACE_MINUS; + if (++i == fmt.size()) + log_assert(false && "Unexpected end in format substitution"); + } else { + // also accept no sign character and treat like MINUS for compatibility } if (fmt[i] == 'u') @@ -204,8 +214,11 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const { case 16: fmt += part.hex_upper ? 'H' : 'h'; break; default: log_abort(); } - if (part.plus) - fmt += '+'; + switch (part.sign) { + case FmtPart::MINUS: fmt += '-'; break; + case FmtPart::PLUS_MINUS: fmt += '+'; break; + case FmtPart::SPACE_MINUS: fmt += ' '; break; + } fmt += part.signed_ ? 's' : 'u'; } else if (part.type == FmtPart::STRING) { fmt += 'c'; @@ -379,7 +392,7 @@ void Fmt::parse_verilog(const std::vector &args, bool sformat_lik part.justify = FmtPart::LEFT; } else if (fmt[i] == '+') { // always show sign; not in IEEE 1800-2017 or verilator but iverilog has it - part.plus = true; + part.sign = FmtPart::PLUS_MINUS; } else break; } if (i == fmt.size()) { @@ -442,7 +455,7 @@ void Fmt::parse_verilog(const std::vector &args, bool sformat_lik if (part.padding == '\0') part.padding = (has_leading_zero && part.justify == FmtPart::RIGHT) ? '0' : ' '; - if (part.type == FmtPart::INTEGER && part.base != 10 && part.plus) + if (part.type == FmtPart::INTEGER && part.base != 10 && part.sign != FmtPart::MINUS) log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with invalid format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1); if (part.type == FmtPart::INTEGER && !has_leading_zero) @@ -495,8 +508,8 @@ std::vector Fmt::emit_verilog() const args.push_back(arg); fmt.str += '%'; - if (part.plus) - fmt.str += '+'; + if (part.sign == FmtPart::PLUS_MINUS || part.sign == FmtPart::SPACE_MINUS) + fmt.str += '+'; // treat space/minus as plus/minus if (part.justify == FmtPart::LEFT) fmt.str += '-'; if (part.width == 0) { @@ -553,7 +566,8 @@ std::vector Fmt::emit_verilog() const args.push_back(arg); fmt.str += '%'; - if (part.plus) + log_assert(part.sign == FmtPart::MINUS || part.sign == FmtPart::PLUS_MINUS); + if (part.sign == FmtPart::PLUS_MINUS) fmt.str += '+'; if (part.justify == FmtPart::LEFT) fmt.str += '-'; @@ -620,7 +634,13 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function Date: Thu, 28 Mar 2024 07:23:09 +0000 Subject: [PATCH 022/184] fmt,cxxrtl: add support for `NUMERIC` justification. Before this commit, the existing alignments were `LEFT` and `RIGHT`, which added the `padding` character to the right and left just before finishing formatting. However, if `padding == '0'` and the alignment is to the right, then the padding character (digit zero) was added after the sign, if one is present. After this commit, the special case for `padding == '0'` is removed, and the new justification `NUMERIC` adds the padding character like the justification `RIGHT`, except after the sign, if one is present. (Space, for the `SPACE_MINUS` sign mode, counts as the sign.) --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 5 +++-- kernel/fmt.cc | 23 +++++++++++++++++------ kernel/fmt.h | 1 + 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index 02050df58..a98736012 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -1026,6 +1026,7 @@ struct fmt_part { enum { RIGHT = 0, LEFT = 1, + NUMERIC = 2, } justify; // = RIGHT; char padding; // = '\0'; size_t width; // = 0; @@ -1131,9 +1132,9 @@ struct fmt_part { std::string str; assert(width == 0 || padding != '\0'); - if (justify == RIGHT && buf.size() < width) { + if (justify != LEFT && buf.size() < width) { size_t pad_width = width - buf.size(); - if (padding == '0' && (buf.front() == '+' || buf.front() == '-')) { + if (justify == NUMERIC && (buf.front() == '+' || buf.front() == '-' || buf.front() == ' ')) { str += buf.front(); buf.erase(0, 1); } diff --git a/kernel/fmt.cc b/kernel/fmt.cc index 342b508d9..43f60b1d8 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -78,6 +78,8 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { part.justify = FmtPart::RIGHT; else if (fmt[i] == '<') part.justify = FmtPart::LEFT; + else if (fmt[i] == '=') + part.justify = FmtPart::NUMERIC; else log_assert(false && "Unexpected justification in format substitution"); if (++i == fmt.size()) @@ -201,6 +203,8 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const { fmt += '>'; else if (part.justify == FmtPart::LEFT) fmt += '<'; + else if (part.justify == FmtPart::NUMERIC) + fmt += '='; else log_abort(); log_assert(part.width == 0 || part.padding != '\0'); fmt += part.padding != '\0' ? part.padding : ' '; @@ -452,8 +456,14 @@ void Fmt::parse_verilog(const std::vector &args, bool sformat_lik log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1); } - if (part.padding == '\0') - part.padding = (has_leading_zero && part.justify == FmtPart::RIGHT) ? '0' : ' '; + if (part.padding == '\0') { + if (has_leading_zero && part.justify == FmtPart::RIGHT) { + part.padding = '0'; + part.justify = FmtPart::NUMERIC; + } else { + part.padding = ' '; + } + } if (part.type == FmtPart::INTEGER && part.base != 10 && part.sign != FmtPart::MINUS) log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with invalid format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1); @@ -626,8 +636,9 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function Date: Thu, 28 Mar 2024 07:55:46 +0000 Subject: [PATCH 023/184] fmt,cxxrtl: add `UNICHAR` format type. This format type is used to print an Unicode character (code point) as its UTF-8 serialization. To this end, two UTF-8 decoders (one for fmt, one for cxxrtl) are added for rendering. When converted to a Verilog format specifier, `UNICHAR` degrades to `%c` with the low 7 bits of the code point, which has equivalent behavior for inputs not exceeding ASCII. (SystemVerilog leaves source and display encodings completely undefined.) --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 24 +++++++++++-- kernel/fmt.cc | 47 +++++++++++++++++++++++-- kernel/fmt.h | 5 +-- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index a98736012..a67915346 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -1013,13 +1013,14 @@ struct fmt_part { LITERAL = 0, INTEGER = 1, STRING = 2, - VLOG_TIME = 3, + UNICHAR = 3, + VLOG_TIME = 4, } type; // LITERAL type std::string str; - // INTEGER/STRING types + // INTEGER/STRING/UNICHAR types // + value val; // INTEGER/STRING/VLOG_TIME types @@ -1073,6 +1074,25 @@ struct fmt_part { break; } + case UNICHAR: { + uint32_t codepoint = val.template get(); + if (codepoint >= 0x10000) + buf += (char)(0xf0 | (codepoint >> 18)); + else if (codepoint >= 0x800) + buf += (char)(0xe0 | (codepoint >> 12)); + else if (codepoint >= 0x80) + buf += (char)(0xc0 | (codepoint >> 6)); + else + buf += (char)codepoint; + if (codepoint >= 0x10000) + buf += (char)(0x80 | ((codepoint >> 12) & 0x3f)); + if (codepoint >= 0x800) + buf += (char)(0x80 | ((codepoint >> 6) & 0x3f)); + if (codepoint >= 0x80) + buf += (char)(0x80 | ((codepoint >> 0) & 0x3f)); + break; + } + case INTEGER: { size_t width = Bits; if (base != 10) { diff --git a/kernel/fmt.cc b/kernel/fmt.cc index 43f60b1d8..5bd4fd9c8 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -42,9 +42,9 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { } else if (fmt.substr(i, 2) == "{{") { part.str += '{'; ++i; - } else if (fmt[i] == '}') + } else if (fmt[i] == '}') { log_assert(false && "Unexpected '}' in format string"); - else if (fmt[i] == '{') { + } else if (fmt[i] == '{') { if (!part.str.empty()) { part.type = FmtPart::LITERAL; parts.push_back(part); @@ -74,6 +74,12 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { part.sig = args.extract(0, arg_size); args.remove(0, arg_size); + if (fmt[i] == 'U') { + part.type = FmtPart::UNICHAR; + ++i; + goto success; + } + if (fmt[i] == '>') part.justify = FmtPart::RIGHT; else if (fmt[i] == '<') @@ -156,6 +162,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { log_assert(false && "Unexpected end in format substitution"); } + success: if (fmt[i] != '}') log_assert(false && "Expected '}' after format substitution"); @@ -188,6 +195,11 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const { } break; + case FmtPart::UNICHAR: + log_assert(part.sig.size() <= 32); + fmt += "{U}"; + break; + case FmtPart::VLOG_TIME: log_assert(part.sig.size() == 0); YS_FALLTHROUGH @@ -568,6 +580,16 @@ std::vector Fmt::emit_verilog() const break; } + case FmtPart::UNICHAR: { + VerilogFmtArg arg; + arg.type = VerilogFmtArg::INTEGER; + arg.sig = part.sig.extract(0, 7); // only ASCII + args.push_back(arg); + + fmt.str += "%c"; + break; + } + case FmtPart::VLOG_TIME: { VerilogFmtArg arg; arg.type = VerilogFmtArg::TIME; @@ -630,6 +652,7 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function= 0x10000) + str += (char)(0xf0 | (codepoint >> 18)); + else if (codepoint >= 0x800) + str += (char)(0xe0 | (codepoint >> 12)); + else if (codepoint >= 0x80) + str += (char)(0xc0 | (codepoint >> 6)); + else + str += (char)codepoint; + if (codepoint >= 0x10000) + str += (char)(0x80 | ((codepoint >> 12) & 0x3f)); + if (codepoint >= 0x800) + str += (char)(0x80 | ((codepoint >> 6) & 0x3f)); + if (codepoint >= 0x80) + str += (char)(0x80 | ((codepoint >> 0) & 0x3f)); + break; + } + case FmtPart::INTEGER: case FmtPart::STRING: case FmtPart::VLOG_TIME: { diff --git a/kernel/fmt.h b/kernel/fmt.h index 9dc6341ba..7fe6fd55e 100644 --- a/kernel/fmt.h +++ b/kernel/fmt.h @@ -56,13 +56,14 @@ struct FmtPart { LITERAL = 0, INTEGER = 1, STRING = 2, - VLOG_TIME = 3, + UNICHAR = 3, + VLOG_TIME = 4, } type; // LITERAL type std::string str; - // INTEGER/STRING types + // INTEGER/STRING/UNICHAR types RTLIL::SigSpec sig; // INTEGER/STRING/VLOG_TIME types From 7b94599162cf11713299ed1263b4723211d084d9 Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 28 Mar 2024 08:33:29 +0000 Subject: [PATCH 024/184] fmt,cxxrtl: add option to print numeric base (`0x`, etc). The option is serialized to RTLIL as `#` (to match Python's and Rust's option with the same symbol), and sets the `show_base` flag. Because the flag is called `show_base` and not e.g. `alternate_format` (which is what Python and Rust call it), in addition to the prefixes `0x`, `0X`, `0o`, `0b`, the RTLIL option also prints the `0d` prefix. --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 7 +++++++ kernel/fmt.cc | 13 +++++++++++++ kernel/fmt.h | 1 + 3 files changed, 21 insertions(+) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index a67915346..008401232 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -1041,6 +1041,7 @@ struct fmt_part { SPACE_MINUS = 2, } sign; // = MINUS; bool hex_upper; // = false; + bool show_base; // = false; // VLOG_TIME type bool realtime; // = false; @@ -1103,6 +1104,8 @@ struct fmt_part { } if (base == 2) { + if (show_base) + buf += "0b"; for (size_t i = width; i > 0; i--) buf += (val.bit(i - 1) ? '1' : '0'); } else if (base == 8 || base == 16) { @@ -1113,6 +1116,8 @@ struct fmt_part { value |= val.bit(index + 3) << 3; buf += (hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[value]; } + if (show_base) + buf += (base == 16) ? (hex_upper ? "X0" : "x0") : "o0"; std::reverse(buf.begin(), buf.end()); } else if (base == 10) { bool negative = signed_ && val.is_neg(); @@ -1130,6 +1135,8 @@ struct fmt_part { buf += '0' + remainder.template trunc<4>().template get(); xval = quotient; } + if (show_base) + buf += "d0"; switch (sign) { case MINUS: buf += negative ? "-" : ""; break; case PLUS_MINUS: buf += negative ? "-" : "+"; break; diff --git a/kernel/fmt.cc b/kernel/fmt.cc index 5bd4fd9c8..8f4e61722 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -152,6 +152,11 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { // also accept no sign character and treat like MINUS for compatibility } + if (fmt[i] == '#') { + part.show_base = true; + ++i; + } + if (fmt[i] == 'u') part.signed_ = false; else if (fmt[i] == 's') @@ -235,6 +240,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const { case FmtPart::PLUS_MINUS: fmt += '+'; break; case FmtPart::SPACE_MINUS: fmt += ' '; break; } + fmt += part.show_base ? "#" : ""; fmt += part.signed_ ? 's' : 'u'; } else if (part.type == FmtPart::STRING) { fmt += 'c'; @@ -676,6 +682,7 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function Date: Thu, 28 Mar 2024 08:55:26 +0000 Subject: [PATCH 025/184] fmt,cxxrtl: add option to group digits in numbers. The option is serialized to RTLIL as `_` (to match Python's option with the same symbol), and sets the `group` flag. This flag inserts an `_` symbol between each group of 3 digits (for decimal) or four digits (for binary, hex, and octal). --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 17 ++++++++++++--- kernel/fmt.cc | 29 +++++++++++++++++++++++-- kernel/fmt.h | 1 + 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index 008401232..31085b745 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -1042,6 +1042,7 @@ struct fmt_part { } sign; // = MINUS; bool hex_upper; // = false; bool show_base; // = false; + bool group; // = false; // VLOG_TIME type bool realtime; // = false; @@ -1104,13 +1105,19 @@ struct fmt_part { } if (base == 2) { + for (size_t index = 0; index < width; index++) { + if (group && index > 0 && index % 4 == 0) + buf += '_'; + buf += (val.bit(index) ? '1' : '0'); + } if (show_base) - buf += "0b"; - for (size_t i = width; i > 0; i--) - buf += (val.bit(i - 1) ? '1' : '0'); + buf += "b0"; + std::reverse(buf.begin(), buf.end()); } else if (base == 8 || base == 16) { size_t step = (base == 16) ? 4 : 3; for (size_t index = 0; index < width; index += step) { + if (group && index > 0 && index % (4 * step) == 0) + buf += '_'; uint8_t value = val.bit(index) | (val.bit(index + 1) << 1) | (val.bit(index + 2) << 2); if (step == 4) value |= val.bit(index + 3) << 3; @@ -1126,7 +1133,10 @@ struct fmt_part { if (val.is_zero()) buf += '0'; value<(Bits > 4 ? Bits : 4)> xval = val.template zext<(Bits > 4 ? Bits : 4)>(); + size_t index = 0; while (!xval.is_zero()) { + if (group && index > 0 && index % 3 == 0) + buf += '_'; value<(Bits > 4 ? Bits : 4)> quotient, remainder; if (Bits >= 4) std::tie(quotient, remainder) = xval.udivmod(value<(Bits > 4 ? Bits : 4)>{10u}); @@ -1134,6 +1144,7 @@ struct fmt_part { std::tie(quotient, remainder) = std::make_pair(value<(Bits > 4 ? Bits : 4)>{0u}, xval); buf += '0' + remainder.template trunc<4>().template get(); xval = quotient; + index++; } if (show_base) buf += "d0"; diff --git a/kernel/fmt.cc b/kernel/fmt.cc index 8f4e61722..f5793d796 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -156,6 +156,10 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { part.show_base = true; ++i; } + if (fmt[i] == '_') { + part.group = true; + ++i; + } if (fmt[i] == 'u') part.signed_ = false; @@ -241,6 +245,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const { case FmtPart::SPACE_MINUS: fmt += ' '; break; } fmt += part.show_base ? "#" : ""; + fmt += part.group ? "_" : ""; fmt += part.signed_ ? 's' : 'u'; } else if (part.type == FmtPart::STRING) { fmt += 'c'; @@ -683,6 +688,7 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function 0 && index % 4 == 0) + buf += '_'; + RTLIL::State bit = value[index]; + if (bit == State::Sx) + buf += 'x'; + else if (bit == State::Sz) + buf += 'z'; + else if (bit == State::S1) + buf += '1'; + else /* if (bit == State::S0) */ + buf += '0'; + } if (part.show_base) - buf += "0b"; - buf = value.as_string(); + buf += "b0"; + std::reverse(buf.begin(), buf.end()); } else if (part.base == 8 || part.base == 16) { size_t step = (part.base == 16) ? 4 : 3; for (size_t index = 0; index < (size_t)value.size(); index += step) { + if (part.group && index > 0 && index % (4 * step) == 0) + buf += '_'; RTLIL::Const subvalue = value.extract(index, min(step, value.size() - index)); bool has_x = false, all_x = true, has_z = false, all_z = true; for (State bit : subvalue) { @@ -799,9 +820,13 @@ std::string Fmt::render() const log_assert(absvalue.is_fully_def()); if (absvalue.is_fully_zero()) buf += '0'; + size_t index = 0; while (!absvalue.is_fully_zero()) { + if (part.group && index > 0 && index % 3 == 0) + buf += '_'; buf += '0' + RTLIL::const_mod(absvalue, 10, false, false, 4).as_int(); absvalue = RTLIL::const_div(absvalue, 10, false, false, absvalue.size()); + index++; } if (part.show_base) buf += "d0"; diff --git a/kernel/fmt.h b/kernel/fmt.h index 10b1711f1..2d4b24979 100644 --- a/kernel/fmt.h +++ b/kernel/fmt.h @@ -85,6 +85,7 @@ struct FmtPart { } sign = MINUS; bool hex_upper = false; bool show_base = false; + bool group = false; // VLOG_TIME type bool realtime = false; From ddf7b469559b976225fc35bea340383bcf5c5097 Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 28 Mar 2024 09:45:10 +0000 Subject: [PATCH 026/184] fmt,cxxrtl: fix printing of non-decimal signed numbers. Also fix interaction of `NUMERIC` justification with `show_base`. --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 67 ++++++++++------ kernel/fmt.cc | 101 ++++++++++++++---------- 2 files changed, 100 insertions(+), 68 deletions(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index 31085b745..da107e037 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -1058,6 +1058,7 @@ struct fmt_part { // We might want to replace some of these bit() calls with direct // chunk access if it turns out to be slow enough to matter. std::string buf; + std::string prefix; switch (type) { case LITERAL: return str; @@ -1096,24 +1097,38 @@ struct fmt_part { } case INTEGER: { + bool negative = signed_ && val.is_neg(); + if (negative) { + prefix = "-"; + val = val.neg(); + } else { + switch (sign) { + case MINUS: break; + case PLUS_MINUS: prefix = "+"; break; + case SPACE_MINUS: prefix = " "; break; + } + } + size_t width = Bits; if (base != 10) { - width = 0; + width = 1; for (size_t index = 0; index < Bits; index++) if (val.bit(index)) width = index + 1; } if (base == 2) { + if (show_base) + prefix += "0b"; for (size_t index = 0; index < width; index++) { if (group && index > 0 && index % 4 == 0) buf += '_'; buf += (val.bit(index) ? '1' : '0'); } - if (show_base) - buf += "b0"; std::reverse(buf.begin(), buf.end()); } else if (base == 8 || base == 16) { + if (show_base) + prefix += (base == 16) ? (hex_upper ? "0X" : "0x") : "0o"; size_t step = (base == 16) ? 4 : 3; for (size_t index = 0; index < width; index += step) { if (group && index > 0 && index % (4 * step) == 0) @@ -1123,13 +1138,10 @@ struct fmt_part { value |= val.bit(index + 3) << 3; buf += (hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[value]; } - if (show_base) - buf += (base == 16) ? (hex_upper ? "X0" : "x0") : "o0"; std::reverse(buf.begin(), buf.end()); } else if (base == 10) { - bool negative = signed_ && val.is_neg(); - if (negative) - val = val.neg(); + if (show_base) + prefix += "0d"; if (val.is_zero()) buf += '0'; value<(Bits > 4 ? Bits : 4)> xval = val.template zext<(Bits > 4 ? Bits : 4)>(); @@ -1146,13 +1158,6 @@ struct fmt_part { xval = quotient; index++; } - if (show_base) - buf += "d0"; - switch (sign) { - case MINUS: buf += negative ? "-" : ""; break; - case PLUS_MINUS: buf += negative ? "-" : "+"; break; - case SPACE_MINUS: buf += negative ? "-" : " "; break; - } std::reverse(buf.begin(), buf.end()); } else assert(false && "Unsupported base for fmt_part"); break; @@ -1170,17 +1175,29 @@ struct fmt_part { std::string str; assert(width == 0 || padding != '\0'); - if (justify != LEFT && buf.size() < width) { - size_t pad_width = width - buf.size(); - if (justify == NUMERIC && (buf.front() == '+' || buf.front() == '-' || buf.front() == ' ')) { - str += buf.front(); - buf.erase(0, 1); - } - str += std::string(pad_width, padding); + if (prefix.size() + buf.size() < width) { + size_t pad_width = width - prefix.size() - buf.size(); + switch (justify) { + case LEFT: + str += prefix; + str += buf; + str += std::string(pad_width, padding); + break; + case RIGHT: + str += std::string(pad_width, padding); + str += prefix; + str += buf; + break; + case NUMERIC: + str += prefix; + str += std::string(pad_width, padding); + str += buf; + break; + } + } else { + str += prefix; + str += buf; } - str += buf; - if (justify == LEFT && buf.size() < width) - str += std::string(width - buf.size(), padding); return str; } }; diff --git a/kernel/fmt.cc b/kernel/fmt.cc index f5793d796..f70f6d390 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -491,6 +491,8 @@ void Fmt::parse_verilog(const std::vector &args, bool sformat_lik if (part.type == FmtPart::INTEGER && part.base != 10 && part.sign != FmtPart::MINUS) log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with invalid format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1); + if (part.base != 10) + part.signed_ = false; if (part.type == FmtPart::INTEGER && !has_leading_zero) apply_verilog_automatic_sizing_and_add(part); else @@ -731,11 +733,34 @@ std::string Fmt::render() const case FmtPart::STRING: case FmtPart::VLOG_TIME: { std::string buf; + std::string prefix; if (part.type == FmtPart::INTEGER) { RTLIL::Const value = part.sig.as_const(); + bool has_x = false, all_x = true, has_z = false, all_z = true; + for (State bit : value) { + if (bit == State::Sx) + has_x = true; + else + all_x = false; + if (bit == State::Sz) + has_z = true; + else + all_z = false; + } + + if (!has_z && !has_x && part.signed_ && value[value.size() - 1]) { + prefix = "-"; + value = RTLIL::const_neg(value, {}, part.signed_, {}, value.size() + 1); + } else { + switch (part.sign) { + case FmtPart::MINUS: break; + case FmtPart::PLUS_MINUS: prefix = "+"; break; + case FmtPart::SPACE_MINUS: prefix = " "; break; + } + } if (part.base != 10) { - size_t minimum_size = 0; + size_t minimum_size = 1; for (size_t index = 0; index < (size_t)value.size(); index++) if (value[index] != State::S0) minimum_size = index + 1; @@ -743,6 +768,8 @@ std::string Fmt::render() const } if (part.base == 2) { + if (part.show_base) + prefix += "0b"; for (size_t index = 0; index < (size_t)value.size(); index++) { if (part.group && index > 0 && index % 4 == 0) buf += '_'; @@ -756,10 +783,10 @@ std::string Fmt::render() const else /* if (bit == State::S0) */ buf += '0'; } - if (part.show_base) - buf += "b0"; std::reverse(buf.begin(), buf.end()); } else if (part.base == 8 || part.base == 16) { + if (part.show_base) + prefix += (part.base == 16) ? (part.hex_upper ? "0X" : "0x") : "0o"; size_t step = (part.base == 16) ? 4 : 3; for (size_t index = 0; index < (size_t)value.size(); index += step) { if (part.group && index > 0 && index % (4 * step) == 0) @@ -787,21 +814,10 @@ std::string Fmt::render() const else buf += (part.hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[subvalue.as_int()]; } - if (part.show_base) - buf += (part.base == 16) ? (part.hex_upper ? "X0" : "x0") : "o0"; std::reverse(buf.begin(), buf.end()); } else if (part.base == 10) { - bool has_x = false, all_x = true, has_z = false, all_z = true; - for (State bit : value) { - if (bit == State::Sx) - has_x = true; - else - all_x = false; - if (bit == State::Sz) - has_z = true; - else - all_z = false; - } + if (part.show_base) + prefix += "0d"; if (all_x) buf += 'x'; else if (all_z) @@ -811,30 +827,17 @@ std::string Fmt::render() const else if (has_z) buf += 'Z'; else { - bool negative = part.signed_ && value[value.size() - 1]; - RTLIL::Const absvalue; - if (negative) - absvalue = RTLIL::const_neg(value, {}, part.signed_, {}, value.size() + 1); - else - absvalue = value; - log_assert(absvalue.is_fully_def()); - if (absvalue.is_fully_zero()) + log_assert(value.is_fully_def()); + if (value.is_fully_zero()) buf += '0'; size_t index = 0; - while (!absvalue.is_fully_zero()) { + while (!value.is_fully_zero()) { if (part.group && index > 0 && index % 3 == 0) buf += '_'; - buf += '0' + RTLIL::const_mod(absvalue, 10, false, false, 4).as_int(); - absvalue = RTLIL::const_div(absvalue, 10, false, false, absvalue.size()); + buf += '0' + RTLIL::const_mod(value, 10, false, false, 4).as_int(); + value = RTLIL::const_div(value, 10, false, false, value.size()); index++; } - if (part.show_base) - buf += "d0"; - switch (part.sign) { - case FmtPart::MINUS: buf += negative ? "-" : ""; break; - case FmtPart::PLUS_MINUS: buf += negative ? "-" : "+"; break; - case FmtPart::SPACE_MINUS: buf += negative ? "-" : " "; break; - } std::reverse(buf.begin(), buf.end()); } } else log_abort(); @@ -846,17 +849,29 @@ std::string Fmt::render() const } log_assert(part.width == 0 || part.padding != '\0'); - if (part.justify != FmtPart::LEFT && buf.size() < part.width) { - size_t pad_width = part.width - buf.size(); - if (part.justify == FmtPart::NUMERIC && (!buf.empty() && (buf.front() == '+' || buf.front() == '-' || buf.front() == ' '))) { - str += buf.front(); - buf.erase(0, 1); + if (prefix.size() + buf.size() < part.width) { + size_t pad_width = part.width - prefix.size() - buf.size(); + switch (part.justify) { + case FmtPart::LEFT: + str += prefix; + str += buf; + str += std::string(pad_width, part.padding); + break; + case FmtPart::RIGHT: + str += std::string(pad_width, part.padding); + str += prefix; + str += buf; + break; + case FmtPart::NUMERIC: + str += prefix; + str += std::string(pad_width, part.padding); + str += buf; + break; } - str += std::string(pad_width, part.padding); + } else { + str += prefix; + str += buf; } - str += buf; - if (part.justify == FmtPart::LEFT && buf.size() < part.width) - str += std::string(part.width - buf.size(), part.padding); break; } } From 27cb4c52b4cffd049dc825865852af75867fce11 Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 28 Mar 2024 09:52:59 +0000 Subject: [PATCH 027/184] fmt: allow padding characters other than `'0'` and `' '`. When converted to Verilog, padding characters are replaced with one of these two. Otherwise padding is performed with exactly that character. --- kernel/fmt.cc | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/kernel/fmt.cc b/kernel/fmt.cc index f70f6d390..43d8feddf 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -91,10 +91,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) { if (++i == fmt.size()) log_assert(false && "Unexpected end in format substitution"); - if (fmt[i] == '0' || fmt[i] == ' ') - part.padding = fmt[i]; - else - log_assert(false && "Unexpected padding in format substitution"); + part.padding = fmt[i]; if (++i == fmt.size()) log_assert(false && "Unexpected end in format substitution"); @@ -550,7 +547,6 @@ std::vector Fmt::emit_verilog() const if (part.width == 0) { fmt.str += '0'; } else if (part.width > 0) { - log_assert(part.padding == ' ' || part.padding == '0'); if (part.base != 10 || part.padding == '0') fmt.str += '0'; fmt.str += std::to_string(part.width); @@ -576,7 +572,6 @@ std::vector Fmt::emit_verilog() const fmt.str += '-'; if (part.sig.size() == 8) { if (part.width > 0) { - log_assert(part.padding == '0' || part.padding == ' '); if (part.padding == '0') fmt.str += part.padding; fmt.str += std::to_string(part.width); @@ -585,7 +580,6 @@ std::vector Fmt::emit_verilog() const } else { log_assert(part.sig.size() % 8 == 0); if (part.width > 0) { - log_assert(part.padding == ' '); // no zero padding fmt.str += std::to_string(part.width); } fmt.str += 's'; @@ -616,7 +610,6 @@ std::vector Fmt::emit_verilog() const fmt.str += '+'; if (part.justify == FmtPart::LEFT) fmt.str += '-'; - log_assert(part.padding == ' ' || part.padding == '0'); if (part.padding == '0' && part.width > 0) fmt.str += '0'; fmt.str += std::to_string(part.width); From 94170388a9acd639474387de14dfe7145d8436ee Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 28 Mar 2024 10:06:18 +0000 Subject: [PATCH 028/184] fmt: if enabled, group padding zeroes. Before this commit, the combination of `_` and `0` format characters would produce a result like `000000001010_1010`. After this commit, it would be `0000_0000_1010_1010`. This has a slight quirk where a format like `{:020_b}` results in the output `0_0000_0000_1010_1010`, which is one character longer than requested. Python has the same behavior, and it's not clear what would be strictly speaking correct, so Python behavior is implemented. --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 22 ++++++++++++++-------- kernel/fmt.cc | 12 +++++++++--- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index da107e037..8546a8411 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -1109,28 +1109,27 @@ struct fmt_part { } } - size_t width = Bits; + size_t val_width = Bits; if (base != 10) { - width = 1; + val_width = 1; for (size_t index = 0; index < Bits; index++) if (val.bit(index)) - width = index + 1; + val_width = index + 1; } if (base == 2) { if (show_base) prefix += "0b"; - for (size_t index = 0; index < width; index++) { + for (size_t index = 0; index < val_width; index++) { if (group && index > 0 && index % 4 == 0) buf += '_'; buf += (val.bit(index) ? '1' : '0'); } - std::reverse(buf.begin(), buf.end()); } else if (base == 8 || base == 16) { if (show_base) prefix += (base == 16) ? (hex_upper ? "0X" : "0x") : "0o"; size_t step = (base == 16) ? 4 : 3; - for (size_t index = 0; index < width; index += step) { + for (size_t index = 0; index < val_width; index += step) { if (group && index > 0 && index % (4 * step) == 0) buf += '_'; uint8_t value = val.bit(index) | (val.bit(index + 1) << 1) | (val.bit(index + 2) << 2); @@ -1138,7 +1137,6 @@ struct fmt_part { value |= val.bit(index + 3) << 3; buf += (hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[value]; } - std::reverse(buf.begin(), buf.end()); } else if (base == 10) { if (show_base) prefix += "0d"; @@ -1158,8 +1156,16 @@ struct fmt_part { xval = quotient; index++; } - std::reverse(buf.begin(), buf.end()); } else assert(false && "Unsupported base for fmt_part"); + if (justify == NUMERIC && group && padding == '0') { + int group_size = base == 10 ? 3 : 4; + while (prefix.size() + buf.size() < width) { + if (buf.size() % (group_size + 1) == group_size) + buf += '_'; + buf += '0'; + } + } + std::reverse(buf.begin(), buf.end()); break; } diff --git a/kernel/fmt.cc b/kernel/fmt.cc index 43d8feddf..cbf2d12e9 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -776,7 +776,6 @@ std::string Fmt::render() const else /* if (bit == State::S0) */ buf += '0'; } - std::reverse(buf.begin(), buf.end()); } else if (part.base == 8 || part.base == 16) { if (part.show_base) prefix += (part.base == 16) ? (part.hex_upper ? "0X" : "0x") : "0o"; @@ -807,7 +806,6 @@ std::string Fmt::render() const else buf += (part.hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[subvalue.as_int()]; } - std::reverse(buf.begin(), buf.end()); } else if (part.base == 10) { if (part.show_base) prefix += "0d"; @@ -831,9 +829,17 @@ std::string Fmt::render() const value = RTLIL::const_div(value, 10, false, false, value.size()); index++; } - std::reverse(buf.begin(), buf.end()); } } else log_abort(); + if (part.justify == FmtPart::NUMERIC && part.group && part.padding == '0') { + int group_size = part.base == 10 ? 3 : 4; + while (prefix.size() + buf.size() < part.width) { + if (buf.size() % (group_size + 1) == group_size) + buf += '_'; + buf += '0'; + } + } + std::reverse(buf.begin(), buf.end()); } else if (part.type == FmtPart::STRING) { buf = part.sig.as_const().decode_string(); } else if (part.type == FmtPart::VLOG_TIME) { From cb077101622683716c93707be4c89106ae161359 Mon Sep 17 00:00:00 2001 From: Catherine Date: Tue, 2 Apr 2024 11:26:58 +0000 Subject: [PATCH 029/184] write_verilog: only warn on processes with sync rules. Processes without sync rules correspond to simple decision trees that directly correspond to `always @*` or `always_comb` blocks in Verilog, and do not need a warning. This removes the need to suppress warnings during the RTLIL-to-Verilog conversion performed by Amaranth. --- backends/verilog/verilog_backend.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 05b7c6c40..a09ae984b 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1070,7 +1070,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) f << stringf(";\n"); return true; } - + if (cell->type == ID($_BUF_)) { f << stringf("%s" "assign ", indent.c_str()); dump_sigspec(f, cell->getPort(ID::Y)); @@ -2276,11 +2276,15 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) active_initdata[sig[i]] = val[i]; } - if (!module->processes.empty()) - log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n" - "can't always be mapped directly to Verilog always blocks. Unintended\n" - "changes in simulation behavior are possible! Use \"proc\" to convert\n" - "processes to logic networks and registers.\n", log_id(module)); + bool has_sync_rules = false; + for (auto process : module->processes) + if (!process.second->syncs.empty()) + has_sync_rules = true; + if (has_sync_rules) + log_warning("Module %s contains RTLIL processes with sync rules. Such RTLIL " + "processes can't always be mapped directly to Verilog always blocks. " + "unintended changes in simulation behavior are possible! Use \"proc\" " + "to convert processes to logic networks and registers.\n", log_id(module)); f << stringf("\n"); for (auto it = module->processes.begin(); it != module->processes.end(); ++it) From d8687e87b1f7286636d50c42dd281eb3e93e4898 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Apr 2024 15:58:06 +0200 Subject: [PATCH 030/184] kernel: Avoid including files outside include guards This adjusts the way the headers kernel/{yosys,rtlil,register,log}.h include each other to avoid the need of including headers outside of include guards as well as avoiding the inclusion of rtlil.h in the middle of yosys.h with rtlil.h depending on the prefix of yosys.h, and the suffix of yosys.h depending on rtlil.h. To do this I moved some of the declaration in yosys.h into a new header yosys_common.h. I'm not sure if that is strictly necessary. Including any of these files still results in the declarations of all these headers being included, so this shouldn't be a breaking change for any passes or external plugins. My main motivation for this is that ccls's (clang based language server) include guard handling gets confused by the previous way the includes were done. It often ends up treating the include guard as a generic disabled preprocessor conditional, breaking navigation and highlighting for the core RTLIL data structures. Additionally I think avoiding cyclic includes in the middle of header files that depend on includes being outside of include guards will also be less confusing for developers reading the code, not only for tools like ccls. --- Makefile | 1 + kernel/log.h | 6 +- kernel/register.h | 5 +- kernel/rtlil.h | 5 +- kernel/yosys.h | 346 +------------------------------------- kernel/yosys_common.h | 379 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 391 insertions(+), 351 deletions(-) create mode 100644 kernel/yosys_common.h diff --git a/Makefile b/Makefile index ca229ca4a..b62b78fb1 100644 --- a/Makefile +++ b/Makefile @@ -629,6 +629,7 @@ $(eval $(call add_include_file,kernel/sigtools.h)) $(eval $(call add_include_file,kernel/timinginfo.h)) $(eval $(call add_include_file,kernel/utils.h)) $(eval $(call add_include_file,kernel/yosys.h)) +$(eval $(call add_include_file,kernel/yosys_common.h)) $(eval $(call add_include_file,kernel/yw.h)) $(eval $(call add_include_file,libs/ezsat/ezsat.h)) $(eval $(call add_include_file,libs/ezsat/ezminisat.h)) diff --git a/kernel/log.h b/kernel/log.h index e4f06c69d..53aae58c6 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -17,11 +17,11 @@ * */ -#include "kernel/yosys.h" - #ifndef LOG_H #define LOG_H +#include "kernel/yosys_common.h" + #include #include @@ -449,4 +449,6 @@ void log_dump_args_worker(const char *p, T first, Args ... args) YOSYS_NAMESPACE_END +#include "kernel/yosys.h" + #endif diff --git a/kernel/register.h b/kernel/register.h index 08ce4b287..25ea9f232 100644 --- a/kernel/register.h +++ b/kernel/register.h @@ -17,11 +17,12 @@ * */ -#include "kernel/yosys.h" - #ifndef REGISTER_H #define REGISTER_H +#include "kernel/yosys_common.h" +#include "kernel/yosys.h" + YOSYS_NAMESPACE_BEGIN struct Pass diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 40422dce5..f9da29495 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -17,11 +17,12 @@ * */ -#include "kernel/yosys.h" - #ifndef RTLIL_H #define RTLIL_H +#include "kernel/yosys_common.h" +#include "kernel/yosys.h" + YOSYS_NAMESPACE_BEGIN namespace RTLIL diff --git a/kernel/yosys.h b/kernel/yosys.h index 0a4641d18..5922d9ab7 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -39,323 +39,7 @@ #ifndef YOSYS_H #define YOSYS_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef WITH_PYTHON -#include -#endif - -#ifndef _YOSYS_ -# error It looks like you are trying to build Yosys without the config defines set. \ - When building Yosys with a custom make system, make sure you set all the \ - defines the Yosys Makefile would set for your build configuration. -#endif - -#ifdef YOSYS_ENABLE_TCL -# include -# ifdef YOSYS_MXE_HACKS -extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); -extern Tcl_Interp *Tcl_CreateInterp(void); -extern void Tcl_Preserve(ClientData data); -extern void Tcl_Release(ClientData clientData); -extern int Tcl_InterpDeleted(Tcl_Interp *interp); -extern void Tcl_DeleteInterp(Tcl_Interp *interp); -extern int Tcl_Eval(Tcl_Interp *interp, const char *script); -extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName); -extern void Tcl_Finalize(void); -extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); -extern const char *Tcl_GetStringResult(Tcl_Interp *interp); -extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length); -extern Tcl_Obj *Tcl_NewIntObj(int intValue); -extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]); -extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); -# endif -# undef CONST -# undef INLINE -#endif - -#ifdef _WIN32 -# undef NOMINMAX -# define NOMINMAX 1 -# undef YY_NO_UNISTD_H -# define YY_NO_UNISTD_H 1 - -# include -# include -# include - -# define strtok_r strtok_s -# define strdup _strdup -# define snprintf _snprintf -# define getcwd _getcwd -# define mkdir _mkdir -# define popen _popen -# define pclose _pclose - -# ifndef __MINGW32__ -# define PATH_MAX MAX_PATH -# define isatty _isatty -# define fileno _fileno -# endif - -// The following defines conflict with our identifiers: -# undef CONST -// `wingdi.h` defines a TRANSPARENT macro that conflicts with X(TRANSPARENT) entry in kernel/constids.inc -# undef TRANSPARENT -#endif - -#ifndef PATH_MAX -# define PATH_MAX 4096 -#endif - -#define YOSYS_NAMESPACE Yosys -#define PRIVATE_NAMESPACE_BEGIN namespace { -#define PRIVATE_NAMESPACE_END } -#define YOSYS_NAMESPACE_BEGIN namespace Yosys { -#define YOSYS_NAMESPACE_END } -#define YOSYS_NAMESPACE_PREFIX Yosys:: -#define USING_YOSYS_NAMESPACE using namespace Yosys; - -#if defined(__GNUC__) || defined(__clang__) -# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__)) -#elif defined(_MSC_VER) -# define YS_ATTRIBUTE(...) -#else -# define YS_ATTRIBUTE(...) -#endif - -#if defined(__GNUC__) || defined(__clang__) -# define YS_MAYBE_UNUSED __attribute__((__unused__)) -#else -# define YS_MAYBE_UNUSED -#endif - -#if __cplusplus >= 201703L -# define YS_FALLTHROUGH [[fallthrough]]; -#elif defined(__clang__) -# define YS_FALLTHROUGH [[clang::fallthrough]]; -#elif defined(__GNUC__) -# define YS_FALLTHROUGH [[gnu::fallthrough]]; -#else -# define YS_FALLTHROUGH -#endif - -YOSYS_NAMESPACE_BEGIN - -// Note: All headers included in hashlib.h must be included -// outside of YOSYS_NAMESPACE before this or bad things will happen. -#ifdef HASHLIB_H -# undef HASHLIB_H -# include "kernel/hashlib.h" -#else -# include "kernel/hashlib.h" -# undef HASHLIB_H -#endif - -using std::vector; -using std::string; -using std::tuple; -using std::pair; - -using std::make_tuple; -using std::make_pair; -using std::get; -using std::min; -using std::max; - -// A primitive shared string implementation that does not -// move its .c_str() when the object is copied or moved. -struct shared_str { - std::shared_ptr content; - shared_str() { } - shared_str(string s) { content = std::shared_ptr(new string(s)); } - shared_str(const char *s) { content = std::shared_ptr(new string(s)); } - const char *c_str() const { return content->c_str(); } - const string &str() const { return *content; } - bool operator==(const shared_str &other) const { return *content == *other.content; } - unsigned int hash() const { return hashlib::hash_ops::hash(*content); } -}; - -using hashlib::mkhash; -using hashlib::mkhash_init; -using hashlib::mkhash_add; -using hashlib::mkhash_xorshift; -using hashlib::hash_ops; -using hashlib::hash_cstr_ops; -using hashlib::hash_ptr_ops; -using hashlib::hash_obj_ops; -using hashlib::dict; -using hashlib::idict; -using hashlib::pool; -using hashlib::mfp; - -namespace RTLIL { - struct IdString; - struct Const; - struct SigBit; - struct SigSpec; - struct Wire; - struct Cell; - struct Memory; - struct Process; - struct Module; - struct Design; - struct Monitor; - enum State : unsigned char; -} - -namespace AST { - struct AstNode; -} - -using RTLIL::IdString; -using RTLIL::Const; -using RTLIL::SigBit; -using RTLIL::SigSpec; -using RTLIL::Wire; -using RTLIL::Cell; -using RTLIL::Module; -using RTLIL::Design; - -namespace hashlib { - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; -} - -void memhasher_on(); -void memhasher_off(); -void memhasher_do(); - -extern bool memhasher_active; -inline void memhasher() { if (memhasher_active) memhasher_do(); } - -void yosys_banner(); -int ceil_log2(int x) YS_ATTRIBUTE(const); - -inline std::string vstringf(const char *fmt, va_list ap) -{ - // For the common case of strings shorter than 128, save a heap - // allocation by using a stack allocated buffer. - const int kBufSize = 128; - char buf[kBufSize]; - buf[0] = '\0'; - va_list apc; - va_copy(apc, ap); - int n = vsnprintf(buf, kBufSize, fmt, apc); - va_end(apc); - if (n < kBufSize) - return std::string(buf); - - std::string string; - char *str = NULL; -#if defined(_WIN32 )|| defined(__CYGWIN__) - int sz = 2 * kBufSize, rc; - while (1) { - va_copy(apc, ap); - str = (char*)realloc(str, sz); - rc = vsnprintf(str, sz, fmt, apc); - va_end(apc); - if (rc >= 0 && rc < sz) - break; - sz *= 2; - } - if (str != NULL) { - string = str; - free(str); - } - return string; -#else - if (vasprintf(&str, fmt, ap) < 0) - str = NULL; - if (str != NULL) { - string = str; - free(str); - } - return string; -#endif -} - -std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); - -inline std::string stringf(const char *fmt, ...) -{ - std::string string; - va_list ap; - - va_start(ap, fmt); - string = vstringf(fmt, ap); - va_end(ap); - - return string; -} - -int readsome(std::istream &f, char *s, int n); -std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false); -std::vector split_tokens(const std::string &text, const char *sep = " \t\r\n"); -bool patmatch(const char *pattern, const char *string); -#if !defined(YOSYS_DISABLE_SPAWN) -int run_command(const std::string &command, std::function process_line = std::function()); -#endif -std::string get_base_tmpdir(); -std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX"); -std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX"); -bool check_file_exists(std::string filename, bool is_exec = false); -bool check_directory_exists(const std::string& dirname); -bool is_absolute_path(std::string filename); -void remove_directory(std::string dirname); -bool create_directory(const std::string& dirname); -std::string escape_filename_spaces(const std::string& filename); - -template int GetSize(const T &obj) { return obj.size(); } -inline int GetSize(RTLIL::Wire *wire); - -extern int autoidx; -extern int yosys_xtrace; - -YOSYS_NAMESPACE_END +#include "kernel/yosys_common.h" #include "kernel/log.h" #include "kernel/rtlil.h" @@ -363,14 +47,6 @@ YOSYS_NAMESPACE_END YOSYS_NAMESPACE_BEGIN -using RTLIL::State; -using RTLIL::SigChunk; -using RTLIL::SigSig; - -namespace hashlib { - template<> struct hash_ops : hash_ops {}; -} - void yosys_setup(); #ifdef WITH_PYTHON @@ -385,26 +61,6 @@ Tcl_Interp *yosys_get_tcl_interp(); extern RTLIL::Design *yosys_design; -RTLIL::IdString new_id(std::string file, int line, std::string func); -RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix); - -#define NEW_ID \ - YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__) -#define NEW_ID_SUFFIX(suffix) \ - YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix) - -// Create a statically allocated IdString object, using for example ID::A or ID($add). -// -// Recipe for Converting old code that is using conversion of strings like ID::A and -// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for -// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary. -// -// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' -// -#define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \ - static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })() -namespace ID = RTLIL::ID; - RTLIL::Design *yosys_get_design(); std::string proc_self_dirname(); std::string proc_share_dirname(); diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h new file mode 100644 index 000000000..9f1bc2f58 --- /dev/null +++ b/kernel/yosys_common.h @@ -0,0 +1,379 @@ +/* -*- c++ -*- + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * 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. + * + */ + +#ifndef YOSYS_COMMON_H +#define YOSYS_COMMON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WITH_PYTHON +#include +#endif + +#ifndef _YOSYS_ +# error It looks like you are trying to build Yosys without the config defines set. \ + When building Yosys with a custom make system, make sure you set all the \ + defines the Yosys Makefile would set for your build configuration. +#endif + +#ifdef YOSYS_ENABLE_TCL +# include +# ifdef YOSYS_MXE_HACKS +extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); +extern Tcl_Interp *Tcl_CreateInterp(void); +extern void Tcl_Preserve(ClientData data); +extern void Tcl_Release(ClientData clientData); +extern int Tcl_InterpDeleted(Tcl_Interp *interp); +extern void Tcl_DeleteInterp(Tcl_Interp *interp); +extern int Tcl_Eval(Tcl_Interp *interp, const char *script); +extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName); +extern void Tcl_Finalize(void); +extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); +extern const char *Tcl_GetStringResult(Tcl_Interp *interp); +extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length); +extern Tcl_Obj *Tcl_NewIntObj(int intValue); +extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]); +extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); +# endif +# undef CONST +# undef INLINE +#endif + +#ifdef _WIN32 +# undef NOMINMAX +# define NOMINMAX 1 +# undef YY_NO_UNISTD_H +# define YY_NO_UNISTD_H 1 + +# include +# include +# include + +# define strtok_r strtok_s +# define strdup _strdup +# define snprintf _snprintf +# define getcwd _getcwd +# define mkdir _mkdir +# define popen _popen +# define pclose _pclose + +# ifndef __MINGW32__ +# define PATH_MAX MAX_PATH +# define isatty _isatty +# define fileno _fileno +# endif + +// The following defines conflict with our identifiers: +# undef CONST +// `wingdi.h` defines a TRANSPARENT macro that conflicts with X(TRANSPARENT) entry in kernel/constids.inc +# undef TRANSPARENT +#endif + +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif + + +#define YOSYS_NAMESPACE Yosys +#define PRIVATE_NAMESPACE_BEGIN namespace { +#define PRIVATE_NAMESPACE_END } +#define YOSYS_NAMESPACE_BEGIN namespace Yosys { +#define YOSYS_NAMESPACE_END } +#define YOSYS_NAMESPACE_PREFIX Yosys:: +#define USING_YOSYS_NAMESPACE using namespace Yosys; + +#if defined(__GNUC__) || defined(__clang__) +# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__)) +#elif defined(_MSC_VER) +# define YS_ATTRIBUTE(...) +#else +# define YS_ATTRIBUTE(...) +#endif + +#if defined(__GNUC__) || defined(__clang__) +# define YS_MAYBE_UNUSED __attribute__((__unused__)) +#else +# define YS_MAYBE_UNUSED +#endif + +#if __cplusplus >= 201703L +# define YS_FALLTHROUGH [[fallthrough]]; +#elif defined(__clang__) +# define YS_FALLTHROUGH [[clang::fallthrough]]; +#elif defined(__GNUC__) +# define YS_FALLTHROUGH [[gnu::fallthrough]]; +#else +# define YS_FALLTHROUGH +#endif + + +YOSYS_NAMESPACE_BEGIN + +// Note: All headers included in hashlib.h must be included +// outside of YOSYS_NAMESPACE before this or bad things will happen. +#ifdef HASHLIB_H +# undef HASHLIB_H +# include "kernel/hashlib.h" +#else +# include "kernel/hashlib.h" +# undef HASHLIB_H +#endif + + +using std::vector; +using std::string; +using std::tuple; +using std::pair; + +using std::make_tuple; +using std::make_pair; +using std::get; +using std::min; +using std::max; + +// A primitive shared string implementation that does not +// move its .c_str() when the object is copied or moved. +struct shared_str { + std::shared_ptr content; + shared_str() { } + shared_str(string s) { content = std::shared_ptr(new string(s)); } + shared_str(const char *s) { content = std::shared_ptr(new string(s)); } + const char *c_str() const { return content->c_str(); } + const string &str() const { return *content; } + bool operator==(const shared_str &other) const { return *content == *other.content; } + unsigned int hash() const { return hashlib::hash_ops::hash(*content); } +}; + +using hashlib::mkhash; +using hashlib::mkhash_init; +using hashlib::mkhash_add; +using hashlib::mkhash_xorshift; +using hashlib::hash_ops; +using hashlib::hash_cstr_ops; +using hashlib::hash_ptr_ops; +using hashlib::hash_obj_ops; +using hashlib::dict; +using hashlib::idict; +using hashlib::pool; +using hashlib::mfp; + +namespace RTLIL { + struct IdString; + struct Const; + struct SigBit; + struct SigSpec; + struct Wire; + struct Cell; + struct Memory; + struct Process; + struct Module; + struct Design; + struct Monitor; + struct Selection; + struct SigChunk; + enum State : unsigned char; + + typedef std::pair SigSig; + + namespace ID {} +} + +namespace AST { + struct AstNode; +} + +using RTLIL::IdString; +using RTLIL::Const; +using RTLIL::SigBit; +using RTLIL::SigSpec; +using RTLIL::Wire; +using RTLIL::Cell; +using RTLIL::Module; +using RTLIL::Design; + +using RTLIL::State; +using RTLIL::SigChunk; +using RTLIL::SigSig; + +namespace hashlib { + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; + template<> struct hash_ops : hash_obj_ops {}; +} + +void memhasher_on(); +void memhasher_off(); +void memhasher_do(); + +extern bool memhasher_active; +inline void memhasher() { if (memhasher_active) memhasher_do(); } + +void yosys_banner(); +int ceil_log2(int x) YS_ATTRIBUTE(const); + +inline std::string vstringf(const char *fmt, va_list ap) +{ + // For the common case of strings shorter than 128, save a heap + // allocation by using a stack allocated buffer. + const int kBufSize = 128; + char buf[kBufSize]; + buf[0] = '\0'; + va_list apc; + va_copy(apc, ap); + int n = vsnprintf(buf, kBufSize, fmt, apc); + va_end(apc); + if (n < kBufSize) + return std::string(buf); + + std::string string; + char *str = NULL; +#if defined(_WIN32 )|| defined(__CYGWIN__) + int sz = 2 * kBufSize, rc; + while (1) { + va_copy(apc, ap); + str = (char*)realloc(str, sz); + rc = vsnprintf(str, sz, fmt, apc); + va_end(apc); + if (rc >= 0 && rc < sz) + break; + sz *= 2; + } + if (str != NULL) { + string = str; + free(str); + } + return string; +#else + if (vasprintf(&str, fmt, ap) < 0) + str = NULL; + if (str != NULL) { + string = str; + free(str); + } + return string; +#endif +} + +std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); + +inline std::string stringf(const char *fmt, ...) +{ + std::string string; + va_list ap; + + va_start(ap, fmt); + string = vstringf(fmt, ap); + va_end(ap); + + return string; +} + +int readsome(std::istream &f, char *s, int n); +std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false); +std::vector split_tokens(const std::string &text, const char *sep = " \t\r\n"); +bool patmatch(const char *pattern, const char *string); +#if !defined(YOSYS_DISABLE_SPAWN) +int run_command(const std::string &command, std::function process_line = std::function()); +#endif +std::string get_base_tmpdir(); +std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX"); +std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX"); +bool check_file_exists(std::string filename, bool is_exec = false); +bool check_directory_exists(const std::string& dirname); +bool is_absolute_path(std::string filename); +void remove_directory(std::string dirname); +bool create_directory(const std::string& dirname); +std::string escape_filename_spaces(const std::string& filename); + +template int GetSize(const T &obj) { return obj.size(); } +inline int GetSize(RTLIL::Wire *wire); + +extern int autoidx; +extern int yosys_xtrace; + +RTLIL::IdString new_id(std::string file, int line, std::string func); +RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix); + +#define NEW_ID \ + YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__) +#define NEW_ID_SUFFIX(suffix) \ + YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix) + +// Create a statically allocated IdString object, using for example ID::A or ID($add). +// +// Recipe for Converting old code that is using conversion of strings like ID::A and +// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for +// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary. +// +// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' +// +#define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \ + static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })() +namespace ID = RTLIL::ID; + +namespace hashlib { + template<> struct hash_ops : hash_ops {}; +} + + +YOSYS_NAMESPACE_END + +#endif From 040605b047e425341a484df3f2f986977834be10 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 00:15:49 +0000 Subject: [PATCH 031/184] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ca229ca4a..e31b72261 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.39+149 +YOSYS_VER := 0.39+163 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 4bb3b099d23b07e0b4f8cf85e7b426be1538fafa Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 3 Apr 2024 10:02:53 +0200 Subject: [PATCH 032/184] opt_demorgan: fix extra args warning --- passes/opt/opt_demorgan.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/opt_demorgan.cc b/passes/opt/opt_demorgan.cc index 1464c4177..4db3a8101 100644 --- a/passes/opt/opt_demorgan.cc +++ b/passes/opt/opt_demorgan.cc @@ -183,7 +183,7 @@ struct OptDemorganPass : public Pass { { log_header(design, "Executing OPT_DEMORGAN pass (push inverters through $reduce_* cells).\n"); - int argidx = 0; + int argidx = 1; extra_args(args, argidx, design); unsigned int cells_changed = 0; From d9a4a423899d8c3d90304440761e47d4664211db Mon Sep 17 00:00:00 2001 From: Catherine Date: Wed, 3 Apr 2024 08:01:58 +0000 Subject: [PATCH 033/184] write_verilog: don't `assign` to a `reg`. Fixes #2035. --- backends/verilog/verilog_backend.cc | 23 +++++++++++++++-------- tests/simple/.gitignore | 1 + tests/verilog/.gitignore | 4 ++++ tests/verilog/assign_to_reg.ys | 22 ++++++++++++++++++++++ 4 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 tests/verilog/assign_to_reg.ys diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index a09ae984b..31bbc996f 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -2014,22 +2014,29 @@ void dump_sync_effect(std::ostream &f, std::string indent, const RTLIL::SigSpec void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) { - if (simple_lhs) { + bool all_chunks_wires = true; + for (auto &chunk : left.chunks()) + if (chunk.is_wire() && reg_wires.count(chunk.wire->name)) + all_chunks_wires = false; + if (!simple_lhs && all_chunks_wires) { + f << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(f, left); + f << stringf(" = "); + dump_sigspec(f, right); + f << stringf(";\n"); + } else { int offset = 0; for (auto &chunk : left.chunks()) { - f << stringf("%s" "assign ", indent.c_str()); + if (chunk.is_wire() && reg_wires.count(chunk.wire->name)) + f << stringf("%s" "always%s\n%s ", indent.c_str(), systemverilog ? "_comb" : " @*", indent.c_str()); + else + f << stringf("%s" "assign ", indent.c_str()); dump_sigspec(f, chunk); f << stringf(" = "); dump_sigspec(f, right.extract(offset, GetSize(chunk))); f << stringf(";\n"); offset += GetSize(chunk); } - } else { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, left); - f << stringf(" = "); - dump_sigspec(f, right); - f << stringf(";\n"); } } diff --git a/tests/simple/.gitignore b/tests/simple/.gitignore index 073f46157..5daaadbd7 100644 --- a/tests/simple/.gitignore +++ b/tests/simple/.gitignore @@ -1,2 +1,3 @@ *.log *.out +*.err diff --git a/tests/verilog/.gitignore b/tests/verilog/.gitignore index 96ebe20ba..cfd72076e 100644 --- a/tests/verilog/.gitignore +++ b/tests/verilog/.gitignore @@ -1,6 +1,10 @@ /*.log /*.out +/*.err /run-test.mk /const_arst.v /const_sr.v /doubleslash.v +/roundtrip_proc_1.v +/roundtrip_proc_2.v +/assign_to_reg.v diff --git a/tests/verilog/assign_to_reg.ys b/tests/verilog/assign_to_reg.ys new file mode 100644 index 000000000..80080e9f3 --- /dev/null +++ b/tests/verilog/assign_to_reg.ys @@ -0,0 +1,22 @@ +# https://github.com/yosyshq/yosys/issues/2035 + +read_ilang < Date: Wed, 3 Apr 2024 20:37:54 +0200 Subject: [PATCH 034/184] docs: Document $macc --- .../yosys_internals/formats/cell_library.rst | 48 ++++++++++++++++- techlibs/common/simlib.v | 51 +++++++++++++++++-- 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/docs/source/yosys_internals/formats/cell_library.rst b/docs/source/yosys_internals/formats/cell_library.rst index c80b07402..a4e5adfb7 100644 --- a/docs/source/yosys_internals/formats/cell_library.rst +++ b/docs/source/yosys_internals/formats/cell_library.rst @@ -619,6 +619,52 @@ Finite state machines Add a brief description of the ``$fsm`` cell type. +Coarse arithmetics +~~~~~~~~~~~~~~~~~~~~~ + +The ``$macc`` cell type represents a multiply and accumulate block, for summing any number of negated and unnegated signals and arithmetic products of pairs of signals. Cell port A concatenates pairs of signals to be multiplied together. When the second signal in a pair is zero length, a constant 1 is used instead as the second factor. Cell port B concatenates 1-bit-wide signals to also be summed, such as "carry in" in adders. + +The cell's ``CONFIG`` parameter determines the layout of cell port ``A``. +In the terms used for this cell, there's mixed meanings for the term "port". To disambiguate: +A cell port is for example the A input (it is constructed in C++ as ``cell->setPort(ID::A, ...))`` +Multiplier ports are pairs of multiplier inputs ("factors"). +If the second signal in such a pair is zero length, no multiplication is necessary, and the first signal is just added to the sum. + +In this pseudocode, ``u(foo)`` means an unsigned int that's foo bits long. +The CONFIG parameter carries the following information: +.. code-block:: + :force: + struct CONFIG { + u4 num_bits; + struct port_field { + bool is_signed; + bool is_subtract; + u(num_bits) factor1_len; + u(num_bits) factor2_len; + }[num_ports]; + }; + +The A cell port carries the following information: +.. code-block:: + :force: + struct A { + u(CONFIG.port_field[0].factor1_len) port0factor1; + u(CONFIG.port_field[0].factor2_len) port0factor2; + u(CONFIG.port_field[1].factor1_len) port1factor1; + u(CONFIG.port_field[1].factor2_len) port1factor2; + ... + }; + +No factor1 may have a zero length. +A factor2 having a zero length implies factor2 is replaced with a constant 1. + +Additionally, B is an array of 1-bit-wide unsigned integers to also be summed up. +Finally, we have: +.. code-block:: + :force: + Y = port0factor1 * port0factor2 + port1factor1 * port1factor2 + ... + * B[0] + B[1] + ... + Specify rules ~~~~~~~~~~~~~ @@ -1152,4 +1198,4 @@ file via ABC using the abc pass. .. todo:: Add information about ``$lut`` and ``$sop`` cells. -.. todo:: Add information about ``$alu``, ``$macc``, ``$fa``, and ``$lcu`` cells. +.. todo:: Add information about ``$alu``, ``$fa``, and ``$lcu`` cells. diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 489281f26..1383a2a13 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -902,18 +902,29 @@ endgenerate endmodule // -------------------------------------------------------- - +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $macc (A, B, Y) +//- +//- Multiply and accumulate. +//- A building block for summing any number of negated and unnegated signals and arithmetic products of pairs of signals. Cell port A concatenates pairs of signals to be multiplied together. When the second signal in a pair is zero length, a constant 1 is used instead as the second factor. Cell port B concatenates 1-bit-wide signals to also be summed, such as "carry in" in adders. +//- Typically created by the `alumacc` pass, which transforms $add and $mul into $macc cells. module \$macc (A, B, Y); parameter A_WIDTH = 0; parameter B_WIDTH = 0; parameter Y_WIDTH = 0; +// CONFIG determines the layout of A, as explained below parameter CONFIG = 4'b0000; parameter CONFIG_WIDTH = 4; -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output reg [Y_WIDTH-1:0] Y; +// In the terms used for this cell, there's mixed meanings for the term "port". To disambiguate: +// A cell port is for example the A input (it is constructed in C++ as cell->setPort(ID::A, ...)) +// Multiplier ports are pairs of multiplier inputs ("factors"). +// If the second signal in such a pair is zero length, no multiplication is necessary, and the first signal is just added to the sum. +input [A_WIDTH-1:0] A; // Cell port A is the concatenation of all arithmetic ports +input [B_WIDTH-1:0] B; // Cell port B is the concatenation of single-bit unsigned signals to be also added to the sum +output reg [Y_WIDTH-1:0] Y; // Output sum // Xilinx XSIM does not like $clog2() below.. function integer my_clog2; @@ -929,10 +940,42 @@ function integer my_clog2; end endfunction +// Bits that a factor's length field in CONFIG per factor in cell port A localparam integer num_bits = CONFIG[3:0] > 0 ? CONFIG[3:0] : 1; +// Number of multiplier ports localparam integer num_ports = (CONFIG_WIDTH-4) / (2 + 2*num_bits); +// Minium bit width of an induction variable to iterate over all bits of cell port A localparam integer num_abits = my_clog2(A_WIDTH) > 0 ? my_clog2(A_WIDTH) : 1; +// In this pseudocode, u(foo) means an unsigned int that's foo bits long. +// The CONFIG parameter carries the following information: +// struct CONFIG { +// u4 num_bits; +// struct port_field { +// bool is_signed; +// bool is_subtract; +// u(num_bits) factor1_len; +// u(num_bits) factor2_len; +// }[num_ports]; +// }; + +// The A cell port carries the following information: +// struct A { +// u(CONFIG.port_field[0].factor1_len) port0factor1; +// u(CONFIG.port_field[0].factor2_len) port0factor2; +// u(CONFIG.port_field[1].factor1_len) port1factor1; +// u(CONFIG.port_field[1].factor2_len) port1factor2; +// ... +// }; +// and log(sizeof(A)) is num_abits. +// No factor1 may have a zero length. +// A factor2 having a zero length implies factor2 is replaced with a constant 1. + +// Additionally, B is an array of 1-bit-wide unsigned integers to also be summed up. +// Finally, we have: +// Y = port0factor1 * port0factor2 + port1factor1 * port1factor2 + ... +// * B[0] + B[1] + ... + function [2*num_ports*num_abits-1:0] get_port_offsets; input [CONFIG_WIDTH-1:0] cfg; integer i, cursor; From 22c5ab90d1580b6d515a58cf1c8be380d188b989 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 00:16:37 +0000 Subject: [PATCH 035/184] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e31b72261..998347002 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.39+163 +YOSYS_VER := 0.39+165 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 9510293a9472a239f448cc7dc7b1bed7f1a35e36 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 4 Apr 2024 18:16:58 +0200 Subject: [PATCH 036/184] fixup --- docs/source/yosys_internals/formats/cell_library.rst | 11 +++++++---- techlibs/common/simlib.v | 9 +++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/source/yosys_internals/formats/cell_library.rst b/docs/source/yosys_internals/formats/cell_library.rst index a4e5adfb7..1e0012f46 100644 --- a/docs/source/yosys_internals/formats/cell_library.rst +++ b/docs/source/yosys_internals/formats/cell_library.rst @@ -632,8 +632,9 @@ If the second signal in such a pair is zero length, no multiplication is necessa In this pseudocode, ``u(foo)`` means an unsigned int that's foo bits long. The CONFIG parameter carries the following information: + .. code-block:: - :force: + struct CONFIG { u4 num_bits; struct port_field { @@ -645,8 +646,9 @@ The CONFIG parameter carries the following information: }; The A cell port carries the following information: + .. code-block:: - :force: + struct A { u(CONFIG.port_field[0].factor1_len) port0factor1; u(CONFIG.port_field[0].factor2_len) port0factor2; @@ -660,10 +662,11 @@ A factor2 having a zero length implies factor2 is replaced with a constant 1. Additionally, B is an array of 1-bit-wide unsigned integers to also be summed up. Finally, we have: + .. code-block:: - :force: + Y = port0factor1 * port0factor2 + port1factor1 * port1factor2 + ... - * B[0] + B[1] + ... + + B[0] + B[1] + ... Specify rules ~~~~~~~~~~~~~ diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 1383a2a13..7dc03da6d 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -907,8 +907,13 @@ endmodule //- $macc (A, B, Y) //- //- Multiply and accumulate. -//- A building block for summing any number of negated and unnegated signals and arithmetic products of pairs of signals. Cell port A concatenates pairs of signals to be multiplied together. When the second signal in a pair is zero length, a constant 1 is used instead as the second factor. Cell port B concatenates 1-bit-wide signals to also be summed, such as "carry in" in adders. -//- Typically created by the `alumacc` pass, which transforms $add and $mul into $macc cells. +//- A building block for summing any number of negated and unnegated signals +//- and arithmetic products of pairs of signals. Cell port A concatenates pairs +//- of signals to be multiplied together. When the second signal in a pair is zero +//- length, a constant 1 is used instead as the second factor. Cell port B +//- concatenates 1-bit-wide signals to also be summed, such as "carry in" in adders. +//- Typically created by the `alumacc` pass, which transforms $add and $mul +//- into $macc cells. module \$macc (A, B, Y); parameter A_WIDTH = 0; From 43ef916f8683e68bbaee9f2358f3719d5000bf1a Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 5 Apr 2024 14:01:25 +0200 Subject: [PATCH 037/184] Restructure rst --- .../yosys_internals/formats/cell_library.rst | 51 ++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/docs/source/yosys_internals/formats/cell_library.rst b/docs/source/yosys_internals/formats/cell_library.rst index 1e0012f46..2b8dc3001 100644 --- a/docs/source/yosys_internals/formats/cell_library.rst +++ b/docs/source/yosys_internals/formats/cell_library.rst @@ -622,22 +622,36 @@ Add a brief description of the ``$fsm`` cell type. Coarse arithmetics ~~~~~~~~~~~~~~~~~~~~~ -The ``$macc`` cell type represents a multiply and accumulate block, for summing any number of negated and unnegated signals and arithmetic products of pairs of signals. Cell port A concatenates pairs of signals to be multiplied together. When the second signal in a pair is zero length, a constant 1 is used instead as the second factor. Cell port B concatenates 1-bit-wide signals to also be summed, such as "carry in" in adders. +The ``$macc`` cell type represents a generalized multiply and accumulate operation. The cell is purely combinational. It outputs the result of summing up a sequence of products and other injected summands. -The cell's ``CONFIG`` parameter determines the layout of cell port ``A``. -In the terms used for this cell, there's mixed meanings for the term "port". To disambiguate: -A cell port is for example the A input (it is constructed in C++ as ``cell->setPort(ID::A, ...))`` -Multiplier ports are pairs of multiplier inputs ("factors"). -If the second signal in such a pair is zero length, no multiplication is necessary, and the first signal is just added to the sum. +.. code-block:: + + Y = 0 +- a0factor1 * a0factor2 +- a1factor1 * a1factor2 +- ... + + B[0] + B[1] + ... + +The A port consists of concatenated pairs of multiplier inputs ("factors"). +A zero length factor2 acts as a constant 1, turning factor1 into a simple summand. In this pseudocode, ``u(foo)`` means an unsigned int that's foo bits long. + +.. code-block:: + + struct A { + u(CONFIG.mul_info[0].factor1_len) a0factor1; + u(CONFIG.mul_info[0].factor2_len) a0factor2; + u(CONFIG.mul_info[1].factor1_len) a1factor1; + u(CONFIG.mul_info[1].factor2_len) a1factor2; + ... + }; + +The cell's ``CONFIG`` parameter determines the layout of cell port ``A``. The CONFIG parameter carries the following information: .. code-block:: struct CONFIG { u4 num_bits; - struct port_field { + struct mul_info { bool is_signed; bool is_subtract; u(num_bits) factor1_len; @@ -645,28 +659,7 @@ The CONFIG parameter carries the following information: }[num_ports]; }; -The A cell port carries the following information: - -.. code-block:: - - struct A { - u(CONFIG.port_field[0].factor1_len) port0factor1; - u(CONFIG.port_field[0].factor2_len) port0factor2; - u(CONFIG.port_field[1].factor1_len) port1factor1; - u(CONFIG.port_field[1].factor2_len) port1factor2; - ... - }; - -No factor1 may have a zero length. -A factor2 having a zero length implies factor2 is replaced with a constant 1. - -Additionally, B is an array of 1-bit-wide unsigned integers to also be summed up. -Finally, we have: - -.. code-block:: - - Y = port0factor1 * port0factor2 + port1factor1 * port1factor2 + ... - + B[0] + B[1] + ... +B is an array of concatenated 1-bit-wide unsigned integers to also be summed up. Specify rules ~~~~~~~~~~~~~ From 91e41d8c803562d43e2debe30677a86d55035357 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 8 Apr 2024 12:44:37 +0200 Subject: [PATCH 038/184] Move parameters to module declaration --- tests/memlib/memlib_9b1B.v | 20 +++++++++++--------- tests/memlib/memlib_wren.v | 16 ++++++++-------- tests/memories/issue00335.v | 6 ++++-- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/tests/memlib/memlib_9b1B.v b/tests/memlib/memlib_9b1B.v index 55545ebd4..9a8246c9f 100644 --- a/tests/memlib/memlib_9b1B.v +++ b/tests/memlib/memlib_9b1B.v @@ -1,4 +1,14 @@ -module RAM_9b1B ( +module RAM_9b1B +#( + parameter INIT = 0, + parameter OPTION_INIT = "UNDEFINED", + parameter PORT_R_WIDTH = 9, + parameter PORT_W_WIDTH = 9, + parameter PORT_R_CLK_POL = 0, + parameter PORT_W_CLK_POL = 0, + parameter PORT_W_WR_EN_WIDTH = 1 +) +( input PORT_R_CLK, input [6:0] PORT_R_ADDR, output reg [PORT_R_WIDTH-1:0] PORT_R_RD_DATA, @@ -8,14 +18,6 @@ module RAM_9b1B ( input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA ); -parameter INIT = 0; -parameter OPTION_INIT = "UNDEFINED"; -parameter PORT_R_WIDTH = 9; -parameter PORT_W_WIDTH = 9; -parameter PORT_R_CLK_POL = 0; -parameter PORT_W_CLK_POL = 0; -parameter PORT_W_WR_EN_WIDTH = 1; - reg [8:0] mem [0:15]; integer i; diff --git a/tests/memlib/memlib_wren.v b/tests/memlib/memlib_wren.v index b9433d42e..c687184bd 100644 --- a/tests/memlib/memlib_wren.v +++ b/tests/memlib/memlib_wren.v @@ -1,4 +1,11 @@ -module RAM_WREN ( +module RAM_WREN #( + parameter ABITS=4, + parameter WIDTH=8, + parameter PORT_A_WR_EN_WIDTH=1, + parameter PORT_A_WR_BE_WIDTH=0, + parameter OPTION_BYTESIZE=WIDTH, + parameter WB=OPTION_BYTESIZE +)( input PORT_A_CLK, input [ABITS-1:0] PORT_A_ADDR, input [WIDTH-1:0] PORT_A_WR_DATA, @@ -7,13 +14,6 @@ module RAM_WREN ( input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE ); -parameter ABITS=4; -parameter WIDTH=8; -parameter PORT_A_WR_EN_WIDTH=1; -parameter PORT_A_WR_BE_WIDTH=0; -parameter OPTION_BYTESIZE=WIDTH; -parameter WB=OPTION_BYTESIZE; - reg [WIDTH-1:0] mem [0:2**ABITS-1]; integer i; diff --git a/tests/memories/issue00335.v b/tests/memories/issue00335.v index f3b6e5dfe..305339dd9 100644 --- a/tests/memories/issue00335.v +++ b/tests/memories/issue00335.v @@ -2,13 +2,15 @@ // expect-rd-ports 1 // expect-rd-clk \clk -module ram2 (input clk, +module ram2 #( + parameter SIZE = 5 // Address size + ) (input clk, input sel, input we, input [SIZE-1:0] adr, input [63:0] dat_i, output reg [63:0] dat_o); - parameter SIZE = 5; // Address size + reg [63:0] mem [0:(1 << SIZE)-1]; integer i; From 4ac10040ce79b2d17f3f72c2c61d6e8558b8dab3 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 8 Apr 2024 12:45:43 +0200 Subject: [PATCH 039/184] Enable SV for localparam use by Efinix cell_sim --- techlibs/efinix/cells_sim.v | 49 +++++++++++++++++++------------------ tests/arch/run-test.sh | 2 +- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/techlibs/efinix/cells_sim.v b/techlibs/efinix/cells_sim.v index 22c7bc776..26e454646 100644 --- a/techlibs/efinix/cells_sim.v +++ b/techlibs/efinix/cells_sim.v @@ -113,7 +113,31 @@ module EFX_GBUFCE( endmodule -module EFX_RAM_5K( +module EFX_RAM_5K +# ( + parameter READ_WIDTH = 20, + parameter WRITE_WIDTH = 20, + localparam READ_ADDR_WIDTH = + (READ_WIDTH == 16) ? 8 : // 256x16 + (READ_WIDTH == 8) ? 9 : // 512x8 + (READ_WIDTH == 4) ? 10 : // 1024x4 + (READ_WIDTH == 2) ? 11 : // 2048x2 + (READ_WIDTH == 1) ? 12 : // 4096x1 + (READ_WIDTH == 20) ? 8 : // 256x20 + (READ_WIDTH == 10) ? 9 : // 512x10 + (READ_WIDTH == 5) ? 10 : -1, // 1024x5 + + localparam WRITE_ADDR_WIDTH = + (WRITE_WIDTH == 16) ? 8 : // 256x16 + (WRITE_WIDTH == 8) ? 9 : // 512x8 + (WRITE_WIDTH == 4) ? 10 : // 1024x4 + (WRITE_WIDTH == 2) ? 11 : // 2048x2 + (WRITE_WIDTH == 1) ? 12 : // 4096x1 + (WRITE_WIDTH == 20) ? 8 : // 256x20 + (WRITE_WIDTH == 10) ? 9 : // 512x10 + (WRITE_WIDTH == 5) ? 10 : -1 // 1024x5 +) +( input [WRITE_WIDTH-1:0] WDATA, input [WRITE_ADDR_WIDTH-1:0] WADDR, input WE, @@ -126,8 +150,6 @@ module EFX_RAM_5K( (* clkbuf_sink *) input RCLK ); - parameter READ_WIDTH = 20; - parameter WRITE_WIDTH = 20; parameter OUTPUT_REG = 1'b0; parameter RCLK_POLARITY = 1'b1; parameter RE_POLARITY = 1'b1; @@ -155,25 +177,4 @@ module EFX_RAM_5K( parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; - - localparam READ_ADDR_WIDTH = - (READ_WIDTH == 16) ? 8 : // 256x16 - (READ_WIDTH == 8) ? 9 : // 512x8 - (READ_WIDTH == 4) ? 10 : // 1024x4 - (READ_WIDTH == 2) ? 11 : // 2048x2 - (READ_WIDTH == 1) ? 12 : // 4096x1 - (READ_WIDTH == 20) ? 8 : // 256x20 - (READ_WIDTH == 10) ? 9 : // 512x10 - (READ_WIDTH == 5) ? 10 : -1; // 1024x5 - - localparam WRITE_ADDR_WIDTH = - (WRITE_WIDTH == 16) ? 8 : // 256x16 - (WRITE_WIDTH == 8) ? 9 : // 512x8 - (WRITE_WIDTH == 4) ? 10 : // 1024x4 - (WRITE_WIDTH == 2) ? 11 : // 2048x2 - (WRITE_WIDTH == 1) ? 12 : // 4096x1 - (WRITE_WIDTH == 20) ? 8 : // 256x20 - (WRITE_WIDTH == 10) ? 9 : // 512x10 - (WRITE_WIDTH == 5) ? 10 : -1; // 1024x5 - endmodule diff --git a/tests/arch/run-test.sh b/tests/arch/run-test.sh index a14b79509..68f925b34 100755 --- a/tests/arch/run-test.sh +++ b/tests/arch/run-test.sh @@ -16,7 +16,7 @@ for arch in ../../techlibs/*; do done else echo -n "Test $path ->" - iverilog -t null -I$arch $path + iverilog -t null -I$arch -g2005-sv $path echo " ok" fi done From 5f4d13ee3fdf49d371fe29712b95c07eba9f7f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 8 Apr 2024 16:44:43 +0200 Subject: [PATCH 040/184] techmap: Note down iteration in Kogge-Stone --- techlibs/common/choices/kogge-stone.v | 1 + 1 file changed, 1 insertion(+) diff --git a/techlibs/common/choices/kogge-stone.v b/techlibs/common/choices/kogge-stone.v index 0e25fe860..ad2e2b169 100644 --- a/techlibs/common/choices/kogge-stone.v +++ b/techlibs/common/choices/kogge-stone.v @@ -42,6 +42,7 @@ module _80_lcu_kogge_stone (P, G, CI, CO); g[0] = g[0] | (p[0] & CI); for (i = 0; i < $clog2(WIDTH); i = i + 1) begin + // iterate in reverse so we don't confuse a result from this stage and the previous for (j = WIDTH - 1; j >= 2**i; j = j - 1) begin g[j] = g[j] | p[j] & g[j - 2**i]; p[j] = p[j] & p[j - 2**i]; From bc1499928779bae5b6483e96c2a3db2c8202cf64 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 00:16:14 +0000 Subject: [PATCH 041/184] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6396d57af..f8d628010 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.39+165 +YOSYS_VER := 0.39+183 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From a1bb0255d654ffd0d8503577274f24b349a42995 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 10 Apr 2024 08:17:27 +0200 Subject: [PATCH 042/184] Release version 0.40 --- CHANGELOG | 13 ++++++++++++- Makefile | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b172988d5..ba734fb35 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,19 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.39 .. Yosys 0.40-dev +Yosys 0.39 .. Yosys 0.40 -------------------------- + * New commands and options + - Added option "-vhdl2019" to "read" and "verific" pass. + + * Various + - Major documentation overhaul. + - Added port statistics to "stat" command. + - Added new formatting features to cxxrtl backend. + + * Verific support + - Added better support for VHDL constants import. + - Added support for VHDL 2009. Yosys 0.38 .. Yosys 0.39 -------------------------- diff --git a/Makefile b/Makefile index f8d628010..e7ed6c9fe 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.39+183 +YOSYS_VER := 0.40 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -158,7 +158,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 0033808.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 0033808.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # From e01e942f81bee11ff5f000cde9970f08f97b12b6 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 10 Apr 2024 08:21:35 +0200 Subject: [PATCH 043/184] Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ba734fb35..f42eaca27 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.40 .. Yosys 0.41-dev +-------------------------- + Yosys 0.39 .. Yosys 0.40 -------------------------- * New commands and options diff --git a/Makefile b/Makefile index e7ed6c9fe..6d81b627f 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.40 +YOSYS_VER := 0.40+0 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -158,7 +158,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 0033808.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline a1bb025.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # From e2cfcbcf25afc9062d0f85748ab908c7ced71d81 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 10 Apr 2024 10:12:05 +0200 Subject: [PATCH 044/184] fix .gitignore --- docs/source/code_examples/extensions/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/code_examples/extensions/.gitignore b/docs/source/code_examples/extensions/.gitignore index ccdd6bd5c..675a532ed 100644 --- a/docs/source/code_examples/extensions/.gitignore +++ b/docs/source/code_examples/extensions/.gitignore @@ -1,2 +1,3 @@ my_cmd.so my_cmd.d +*.log From b00abe4a26ca24d22c822e5400e2f3aede93df48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 10 Apr 2024 11:45:12 +0200 Subject: [PATCH 045/184] Extend `log` command with `-push`, `-pop`, `-header` options --- passes/cmds/logcmd.cc | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/passes/cmds/logcmd.cc b/passes/cmds/logcmd.cc index 20cbd8943..8e51af4b3 100644 --- a/passes/cmds/logcmd.cc +++ b/passes/cmds/logcmd.cc @@ -31,7 +31,8 @@ struct LogPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" log string\n"); + log(" log [options] string\n"); + log(" log [ -push | -pop ]\n"); log("\n"); log("Print the given string to the screen and/or the log file. This is useful for TCL\n"); log("scripts, because the TCL command \"puts\" only goes to stdout but not to\n"); @@ -52,14 +53,26 @@ struct LogPass : public Pass { log(" -n\n"); log(" do not append a newline\n"); log("\n"); + log(" -header\n"); + log(" log a pass header\n"); + log("\n"); + log(" -push\n"); + log(" push a new level on the pass counter\n"); + log("\n"); + log(" -push\n"); + log(" pop from the pass counter\n"); + log("\n"); } - void execute(std::vector args, RTLIL::Design*) override + void execute(std::vector args, RTLIL::Design* design) override { size_t argidx; bool to_stdout = false; bool to_stderr = false; bool to_log = true; bool newline = true; + bool header = false; + bool push = false; + bool pop = false; std::string text; for (argidx = 1; argidx < args.size(); argidx++) @@ -68,15 +81,30 @@ struct LogPass : public Pass { else if (args[argidx] == "-stderr") to_stderr = true; else if (args[argidx] == "-nolog") to_log = false; else if (args[argidx] == "-n") newline = false; + else if (args[argidx] == "-header") header = true; + else if (args[argidx] == "-push") push = true; + else if (args[argidx] == "-pop") pop = true; else break; } + + if ((push || pop) && args.size() != 2) + log_cmd_error("Bad usage: 'log -push' or 'log -pop' must be used without other arguments.\n"); + + if (push) { log_push(); return; } + if (pop) { log_pop(); return; } + for (; argidx < args.size(); argidx++) text += args[argidx] + ' '; if (!text.empty()) text.resize(text.size()-1); - if (to_stdout) fprintf(stdout, (newline ? "%s\n" : "%s"), text.c_str()); - if (to_stderr) fprintf(stderr, (newline ? "%s\n" : "%s"), text.c_str()); - if (to_log) log ( (newline ? "%s\n" : "%s"), text.c_str()); + const char *fmtline = newline ? "%s\n" : "%s"; + + if (to_stdout) fprintf(stdout, fmtline, text.c_str()); + if (to_stderr) fprintf(stderr, fmtline, text.c_str()); + if (to_log) { + if (!header) log(fmtline, text.c_str()); + else log_header(design, fmtline, text.c_str()); + } } } LogPass; From 47bdb3e32f71add7a48ec6215e9838048d52609a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 11 Apr 2024 00:16:34 +0000 Subject: [PATCH 046/184] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6d81b627f..6d7bb2cec 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.40+0 +YOSYS_VER := 0.40+4 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 0c7ac36dcf18ed1afcb2ef5a3011c2a47b8d4118 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 11 Apr 2024 14:56:00 +0200 Subject: [PATCH 047/184] Add workflows and CODEOWNERS and fixed gitignore --- CODEOWNERS | 3 ++- tests/arch/quicklogic/.gitignore | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 7d680e9f2..879bb8dee 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -10,6 +10,7 @@ # PATH (can use glob) USERNAME(S) +CODEOWNERS @nakengelhardt passes/cmds/scratchpad.cc @nakengelhardt frontends/rpc/ @whitequark backends/cxxrtl/ @whitequark @@ -19,7 +20,7 @@ passes/opt/opt_lut.cc @whitequark passes/techmap/abc9*.cc @eddiehung @Ravenslofty backends/aiger/xaiger.cc @eddiehung docs/ @KrystalDelusion - +.github/workflows/*.yml @mmicko ## External Contributors # Only users with write permission to the repository get review diff --git a/tests/arch/quicklogic/.gitignore b/tests/arch/quicklogic/.gitignore index 9a71dca69..ae20ed342 100644 --- a/tests/arch/quicklogic/.gitignore +++ b/tests/arch/quicklogic/.gitignore @@ -1,4 +1,4 @@ *.log -/run-test.mk +run-test.mk +*_synth.v +*_testbench From b87327d1b9a0ec0c8b62694cb3697dcda1665ee2 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Fri, 12 Apr 2024 13:38:33 +0200 Subject: [PATCH 048/184] fix hierarchy -generate mode handling of cells --- passes/hierarchy/hierarchy.cc | 2 +- tests/various/hierarchy_generate.ys | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/various/hierarchy_generate.ys diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 6fcda5d76..3ef04616f 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -47,7 +47,7 @@ void generate(RTLIL::Design *design, const std::vector &celltypes, { if (design->module(cell->type) != nullptr) continue; - if (cell->type.begins_with("$__")) + if (cell->type.begins_with("$") && !cell->type.begins_with("$__")) continue; for (auto &pattern : celltypes) if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str())) diff --git a/tests/various/hierarchy_generate.ys b/tests/various/hierarchy_generate.ys new file mode 100644 index 000000000..a4dc87a86 --- /dev/null +++ b/tests/various/hierarchy_generate.ys @@ -0,0 +1,19 @@ +read_verilog -icells < Date: Fri, 12 Apr 2024 13:51:06 +0200 Subject: [PATCH 049/184] add command that should not have any effect to hierarchy -generate test (this documents the current behavior, not sure if it is desired functionality) --- tests/various/hierarchy_generate.ys | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/various/hierarchy_generate.ys b/tests/various/hierarchy_generate.ys index a4dc87a86..9c01afb64 100644 --- a/tests/various/hierarchy_generate.ys +++ b/tests/various/hierarchy_generate.ys @@ -15,5 +15,6 @@ endmodule EOF hierarchy -generate unknown_sub i:a i:b o:y hierarchy -generate $__dunder_sub i:a i:b o:y +hierarchy -generate $xor i:A i:B o:Y # this one is ignored hierarchy -top top -check check -assert From a48825a604d776becc85ad147d7a767029364cf6 Mon Sep 17 00:00:00 2001 From: Peter Gadfort Date: Fri, 12 Apr 2024 13:57:29 -0400 Subject: [PATCH 050/184] add support for using ABCs library merging when providing multiple liberty files --- passes/techmap/abc.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 422879662..b33e1a17d 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -804,8 +804,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin for (std::string dont_use_cell : dont_use_cells) { dont_use_args += stringf("-X \"%s\" ", dont_use_cell.c_str()); } + bool first_lib = true; for (std::string liberty_file : liberty_files) { - abc_script += stringf("read_lib %s -w \"%s\" ; ", dont_use_args.c_str(), liberty_file.c_str()); + abc_script += stringf("read_lib %s %s -w \"%s\" ; ", dont_use_args.c_str(), first_lib ? "" : "-m", liberty_file.c_str()); + first_lib = false; } for (std::string liberty_file : genlib_files) abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str()); From d4b6042e439f2e8c8059820501c0bcaad7576155 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 13 Apr 2024 11:20:36 +1200 Subject: [PATCH 051/184] Makefile: Separate docs/usage stderr and stdout --- Makefile | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 6d7bb2cec..5e9f2163d 100644 --- a/Makefile +++ b/Makefile @@ -985,16 +985,27 @@ docs/gen_images: $(Q) $(MAKE) -C docs images DOCS_GUIDELINE_FILES := GettingStarted CodingStyle -docs/guidelines: +docs/guidelines docs/source/temp: $(Q) mkdir -p docs/source/temp $(Q) cp -f $(addprefix guidelines/,$(DOCS_GUIDELINE_FILES)) docs/source/temp -# many of these will return an error which can be safely ignored, so we prefix -# the command with a '-' -DOCS_USAGE_PROGS := yosys yosys-config yosys-filterlib yosys-abc yosys-smtbmc yosys-witness -docs/usage: $(addprefix docs/source/temp/,$(DOCS_USAGE_PROGS)) -docs/source/temp/%: docs/guidelines - -$(Q) ./$(PROGRAM_PREFIX)$* --help > $@ 2>&1 +# some commands return an error and print the usage text to stderr +define DOC_USAGE_STDERR +docs/source/temp/$(1): $(PROGRAM_PREFIX)$(1) docs/source/temp + -$(Q) ./$$< --help 2> $$@ +endef +DOCS_USAGE_STDERR := yosys-config yosys-filterlib yosys-abc +$(foreach usage,$(DOCS_USAGE_STDERR),$(eval $(call DOC_USAGE_STDERR,$(usage)))) + +# others print to stdout +define DOC_USAGE_STDOUT +docs/source/temp/$(1): $(PROGRAM_PREFIX)$(1) docs/source/temp + $(Q) ./$$< --help > $$@ +endef +DOCS_USAGE_STDOUT := yosys yosys-smtbmc yosys-witness +$(foreach usage,$(DOCS_USAGE_STDOUT),$(eval $(call DOC_USAGE_STDOUT,$(usage)))) + +docs/usage: $(addprefix docs/source/temp/,$(DOCS_USAGE_STDOUT) $(DOCS_USAGE_STDERR)) docs/reqs: $(Q) $(MAKE) -C docs reqs From 1d7b7ddfd7c7b1322bb5ab0ec98eeaf184f410ce Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 13 Apr 2024 11:29:11 +1200 Subject: [PATCH 052/184] Docs: Skip footer in logs --- docs/source/code_examples/extensions/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/code_examples/extensions/Makefile b/docs/source/code_examples/extensions/Makefile index 288983ed3..5a7994874 100644 --- a/docs/source/code_examples/extensions/Makefile +++ b/docs/source/code_examples/extensions/Makefile @@ -13,18 +13,18 @@ my_cmd.so: my_cmd.cc $(YOSYS)-config --exec --cxx $(subst $(DATDIR),../../../../share,$(CXXFLAGS)) --ldflags -o my_cmd.so -shared my_cmd.cc --ldlibs test0.log: my_cmd.so - $(YOSYS) -Ql test0.log_new -m ./my_cmd.so -p 'my_cmd foo bar' absval_ref.v + $(YOSYS) -QTl test0.log_new -m ./my_cmd.so -p 'my_cmd foo bar' absval_ref.v mv test0.log_new test0.log test1.log: my_cmd.so - $(YOSYS) -Ql test1.log_new -m ./my_cmd.so -p 'clean; test1; dump' absval_ref.v + $(YOSYS) -QTl test1.log_new -m ./my_cmd.so -p 'clean; test1; dump' absval_ref.v mv test1.log_new test1.log test1.dot: my_cmd.so $(YOSYS) -m ./my_cmd.so -p 'test1; show -format dot -prefix test1' test2.log: my_cmd.so - $(YOSYS) -Ql test2.log_new -m ./my_cmd.so -p 'hierarchy -top test; test2' sigmap_test.v + $(YOSYS) -QTl test2.log_new -m ./my_cmd.so -p 'hierarchy -top test; test2' sigmap_test.v mv test2.log_new test2.log .PHONY: clean From b3024289c6e6984cbc4111e42901dce9e01bdc0a Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 13 Apr 2024 11:33:04 +1200 Subject: [PATCH 053/184] Docs: Force read_verilog to avoid verific header --- docs/source/code_examples/extensions/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/code_examples/extensions/Makefile b/docs/source/code_examples/extensions/Makefile index 5a7994874..8b5fa106a 100644 --- a/docs/source/code_examples/extensions/Makefile +++ b/docs/source/code_examples/extensions/Makefile @@ -13,18 +13,18 @@ my_cmd.so: my_cmd.cc $(YOSYS)-config --exec --cxx $(subst $(DATDIR),../../../../share,$(CXXFLAGS)) --ldflags -o my_cmd.so -shared my_cmd.cc --ldlibs test0.log: my_cmd.so - $(YOSYS) -QTl test0.log_new -m ./my_cmd.so -p 'my_cmd foo bar' absval_ref.v + $(YOSYS) -QTl test0.log_new -m ./my_cmd.so -p 'my_cmd foo bar' -f verilog absval_ref.v mv test0.log_new test0.log test1.log: my_cmd.so - $(YOSYS) -QTl test1.log_new -m ./my_cmd.so -p 'clean; test1; dump' absval_ref.v + $(YOSYS) -QTl test1.log_new -m ./my_cmd.so -p 'clean; test1; dump' -f verilog absval_ref.v mv test1.log_new test1.log test1.dot: my_cmd.so $(YOSYS) -m ./my_cmd.so -p 'test1; show -format dot -prefix test1' test2.log: my_cmd.so - $(YOSYS) -QTl test2.log_new -m ./my_cmd.so -p 'hierarchy -top test; test2' sigmap_test.v + $(YOSYS) -QTl test2.log_new -m ./my_cmd.so -p 'hierarchy -top test; test2' -f verilog sigmap_test.v mv test2.log_new test2.log .PHONY: clean From ed46453cfc3032d28246e81d93bfb8a8c65f826e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 00:14:07 +0000 Subject: [PATCH 054/184] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6d7bb2cec..04cb5edc2 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.40+4 +YOSYS_VER := 0.40+7 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 953f5bbe6ca8ce8b4612383482e42f6b7978fd85 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 15 Apr 2024 09:50:46 +1200 Subject: [PATCH 055/184] Docs: Remove end-before tag for yosys-abc --- docs/source/appendix/auxprogs.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/appendix/auxprogs.rst b/docs/source/appendix/auxprogs.rst index b6defbe80..05a2c646d 100644 --- a/docs/source/appendix/auxprogs.rst +++ b/docs/source/appendix/auxprogs.rst @@ -38,7 +38,6 @@ two. .. literalinclude:: /temp/yosys-abc :start-at: usage - :end-before: UC Berkeley yosys-smtbmc ------------ From 73d021562f57ab9217a65ee2c7c6e21909378ba3 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 15 Apr 2024 10:13:22 +1200 Subject: [PATCH 056/184] Docs: Rename source/temp to source/generated --- Makefile | 12 ++++++------ docs/.gitignore | 2 +- docs/Makefile | 1 + docs/source/appendix/auxprogs.rst | 10 +++++----- docs/source/cmd_ref.rst | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 5e9f2163d..acd9e18fa 100644 --- a/Makefile +++ b/Makefile @@ -985,13 +985,13 @@ docs/gen_images: $(Q) $(MAKE) -C docs images DOCS_GUIDELINE_FILES := GettingStarted CodingStyle -docs/guidelines docs/source/temp: - $(Q) mkdir -p docs/source/temp - $(Q) cp -f $(addprefix guidelines/,$(DOCS_GUIDELINE_FILES)) docs/source/temp +docs/guidelines docs/source/generated: + $(Q) mkdir -p docs/source/generated + $(Q) cp -f $(addprefix guidelines/,$(DOCS_GUIDELINE_FILES)) docs/source/generated # some commands return an error and print the usage text to stderr define DOC_USAGE_STDERR -docs/source/temp/$(1): $(PROGRAM_PREFIX)$(1) docs/source/temp +docs/source/generated/$(1): $(PROGRAM_PREFIX)$(1) docs/source/generated -$(Q) ./$$< --help 2> $$@ endef DOCS_USAGE_STDERR := yosys-config yosys-filterlib yosys-abc @@ -999,13 +999,13 @@ $(foreach usage,$(DOCS_USAGE_STDERR),$(eval $(call DOC_USAGE_STDERR,$(usage)))) # others print to stdout define DOC_USAGE_STDOUT -docs/source/temp/$(1): $(PROGRAM_PREFIX)$(1) docs/source/temp +docs/source/generated/$(1): $(PROGRAM_PREFIX)$(1) docs/source/generated $(Q) ./$$< --help > $$@ endef DOCS_USAGE_STDOUT := yosys yosys-smtbmc yosys-witness $(foreach usage,$(DOCS_USAGE_STDOUT),$(eval $(call DOC_USAGE_STDOUT,$(usage)))) -docs/usage: $(addprefix docs/source/temp/,$(DOCS_USAGE_STDOUT) $(DOCS_USAGE_STDERR)) +docs/usage: $(addprefix docs/source/generated/,$(DOCS_USAGE_STDOUT) $(DOCS_USAGE_STDERR)) docs/reqs: $(Q) $(MAKE) -C docs reqs diff --git a/docs/.gitignore b/docs/.gitignore index d7bfd8e95..65bbcdeae 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,6 +1,6 @@ /build/ /source/cmd -/source/temp +/source/generated /source/_images/**/*.log /source/_images/**/*.aux /source/_images/**/*.pdf diff --git a/docs/Makefile b/docs/Makefile index a5b2fed6b..701157ee6 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -48,6 +48,7 @@ help: clean: clean-examples rm -rf $(BUILDDIR)/* rm -rf source/cmd util/__pycache__ + rm -rf source/generated $(MAKE) -C source/_images clean .PHONY: html diff --git a/docs/source/appendix/auxprogs.rst b/docs/source/appendix/auxprogs.rst index 05a2c646d..c239136b6 100644 --- a/docs/source/appendix/auxprogs.rst +++ b/docs/source/appendix/auxprogs.rst @@ -11,7 +11,7 @@ The ``yosys-config`` tool (an auto-generated shell-script) can be used to query compiler options and other information needed for building loadable modules for Yosys. See :doc:`/yosys_internals/extending_yosys/extensions` for details. -.. literalinclude:: /temp/yosys-config +.. literalinclude:: /generated/yosys-config :start-at: Usage .. _sec:filterlib: @@ -25,7 +25,7 @@ The ``yosys-filterlib`` tool is a small utility that can be used to strip or extract information from a Liberty file. This can be useful for removing sensitive or proprietary information such as timing or other trade secrets. -.. literalinclude:: /temp/yosys-filterlib +.. literalinclude:: /generated/yosys-filterlib :start-at: Usage yosys-abc @@ -36,7 +36,7 @@ been accepted upstream. Not all versions of Yosys work with all versions of ABC. So Yosys comes with its own yosys-abc to avoid compatibility issues between the two. -.. literalinclude:: /temp/yosys-abc +.. literalinclude:: /generated/yosys-abc :start-at: usage yosys-smtbmc @@ -45,7 +45,7 @@ yosys-smtbmc The ``yosys-smtbmc`` tool is a utility used by SBY for interacting with smt solvers. -.. literalinclude:: /temp/yosys-smtbmc +.. literalinclude:: /generated/yosys-smtbmc yosys-witness ------------- @@ -54,7 +54,7 @@ yosys-witness This is used in SBY and SCY for producing traces in a consistent format independent of the solver. -.. literalinclude:: /temp/yosys-witness +.. literalinclude:: /generated/yosys-witness :start-at: Usage .. note:: ``yosys-witness`` requires `click`_ Python package for use. diff --git a/docs/source/cmd_ref.rst b/docs/source/cmd_ref.rst index f0c4eaaf9..acf2d1d41 100644 --- a/docs/source/cmd_ref.rst +++ b/docs/source/cmd_ref.rst @@ -4,7 +4,7 @@ Command line reference ================================================================================ -.. literalinclude:: /temp/yosys +.. literalinclude:: /generated/yosys :start-at: Usage .. toctree:: From 2bd889a59a07a2ce057fa0c941234fb8e521edcc Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 15 Apr 2024 11:53:30 +0200 Subject: [PATCH 057/184] formalff -setundef: Fix handling for has_srst FFs The `has_srst`` case was checking `sig_ce` instead of `sig_srst` due to a copy and paste error. This would crash when `has_ce` was false and could incorrectly determine that an initial value is unused when `has_ce` and `has_srst` are both set. --- passes/sat/formalff.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/sat/formalff.cc b/passes/sat/formalff.cc index 264a9fb3b..0eadb69e0 100644 --- a/passes/sat/formalff.cc +++ b/passes/sat/formalff.cc @@ -237,7 +237,7 @@ struct InitValWorker return true; if (ff.has_ce && initconst(ff.sig_ce.as_bit()) == (ff.pol_ce ? State::S0 : State::S1)) continue; - if (ff.has_srst && initconst(ff.sig_ce.as_bit()) == (ff.pol_srst ? State::S1 : State::S0)) + if (ff.has_srst && initconst(ff.sig_srst.as_bit()) == (ff.pol_srst ? State::S1 : State::S0)) continue; return true; From af94123730c13ca5e48b231031873b270542ecba Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 15 Apr 2024 17:01:07 +0200 Subject: [PATCH 058/184] verific: expose library name as module attribute --- frontends/verific/verific.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index e6c5865b7..81e79f749 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1430,6 +1430,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma } import_attributes(module->attributes, nl, nl); module->set_string_attribute(ID::hdlname, nl->CellBaseName()); + module->set_string_attribute(ID(library), nl->Owner()->Owner()->Name()); #ifdef VERIFIC_VHDL_SUPPORT if (nl->IsFromVhdl()) { NameSpace name_space(0); From 40e8f5b69de5063cd2adb6565a00992be83b5515 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 00:15:48 +0000 Subject: [PATCH 059/184] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 87c19786d..32ca398c2 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.40+7 +YOSYS_VER := 0.40+22 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From c38bbd7824edee850c328d8798c78494733fd1ef Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 16 Apr 2024 07:50:50 +0200 Subject: [PATCH 060/184] Add new verific testing environment CI --- .github/workflows/test-verific.yml | 77 ++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 .github/workflows/test-verific.yml diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml new file mode 100644 index 000000000..b4383eba4 --- /dev/null +++ b/.github/workflows/test-verific.yml @@ -0,0 +1,77 @@ +name: Build and run tests with Verific (Linux) + +on: [push, pull_request] + +jobs: + test-verific: + runs-on: [self-hosted, linux, x64] + steps: + - name: Checkout Yosys + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Runtime environment + run: | + echo "procs=$(nproc)" >> $GITHUB_ENV + + - name: Build Yosys + run: | + make config-clang + echo "ENABLE_VERIFIC := 1" >> Makefile.conf + echo "ENABLE_VERIFIC_EDIF := 1" >> Makefile.conf + echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf + echo "ENABLE_CCACHE := 1" >> Makefile.conf + make -j${{ env.procs }} + + - name: Install Yosys + run: | + make install DESTDIR=${GITHUB_WORKSPACE}/.local PREFIX= + + - name: Checkout Documentation + if: ${{ github.ref == 'refs/heads/main' }} + uses: actions/checkout@v4 + with: + path: 'yosys-cmd-ref' + repository: 'YosysHQ-Docs/yosys-cmd-ref' + fetch-depth: 0 + token: ${{ secrets.CI_DOCS_UPDATE_PAT }} + persist-credentials: true + + - name: Update documentation + if: ${{ github.ref == 'refs/heads/main' }} + run: | + make docs + rm -rf docs/build + cd yosys-cmd-ref + rm -rf * + git checkout README.md + cp -R ../docs/* . + rm -rf util/__pycache__ + git add -A . + git diff-index --quiet HEAD || git commit -m "Update" + git push + + - name: Checkout SBY + uses: actions/checkout@v4 + with: + repository: 'YosysHQ/sby' + path: 'sby' + + - name: Build SBY + run: | + make -C sby install DESTDIR=${GITHUB_WORKSPACE}/.local PREFIX= + + - name: Run Yosys tests + run: | + make -j${{ env.procs }} test + + - name: Run Verific specific Yosys tests + run: | + make -C tests/sva + cd tests/svtypes && bash run-test.sh + + - name: Run SBY tests + if: ${{ github.ref == 'refs/heads/main' }} + run: | + make -C sby run_ci From 4897e89547d2e53ebc015052d1b3cad2727ff9a9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 17 Apr 2024 00:16:15 +0000 Subject: [PATCH 061/184] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 32ca398c2..95a982874 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.40+22 +YOSYS_VER := 0.40+25 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 0d30a4d479b4c5ac931610d019b053815e943cca Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 22 Apr 2024 13:26:17 +0200 Subject: [PATCH 062/184] rtlil: Add packed `extract` implementation for `SigSpec` Previously `extract` on a `SigSpec` would always unpack it. Since a significant amount of `SigSpec`s have one or few chunks, it's worth having a dedicated implementation. This is especially true, since the RTLIL frontend calls into this for every `wire [lhs:rhs]` slice, making this `extract` take up 40% when profiling `read_rtlil` with one of the largest coarse grained RTLIL designs I had on hand. With this change the `read_rtlil` profile looks like I would expect it to look like, but I noticed that a lot of the other core RTLIL methods also are a bit too eager with unpacking or implementing `SigChunk`/`Const` overloads that just convert to a single chunk `SigSpec` and forward to the implementation for that, when a direct implementation would avoid temporary std::vector allocations. While not relevant for `read_rtlil`, to me it looks like there might be a few easy overall performance gains to be had by addressing this more generally. --- kernel/rtlil.cc | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 8781b6a89..bafafb57b 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4435,8 +4435,39 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const log_assert(offset >= 0); log_assert(length >= 0); log_assert(offset + length <= width_); - unpack(); + cover("kernel.rtlil.sigspec.extract_pos"); + + if (packed()) + { + if (chunks_.size() == 1) + return chunks_[0].extract(offset, length); + + SigSpec extracted; + int end = offset + length; + int chunk_end = 0; + + for (auto const &chunk : chunks_) + { + int chunk_begin = chunk_end; + chunk_end += chunk.width; + int extract_begin = std::max(chunk_begin, offset); + int extract_end = std::min(chunk_end, end); + if (extract_begin >= extract_end) + continue; + int extract_offset = extract_begin - chunk_begin; + int extract_len = extract_end - extract_begin; + if (extract_offset == 0 && extract_len == chunk.width) + extracted.chunks_.emplace_back(chunk); + else + extracted.chunks_.emplace_back( + chunk.extract(extract_offset, extract_len)); + } + + extracted.width_ = length; + return extracted; + } + return std::vector(bits_.begin() + offset, bits_.begin() + offset + length); } From 178eceb32d9e6d5e36077347ac452f6e10ae7aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 22 Apr 2024 16:23:51 +0200 Subject: [PATCH 063/184] rtlil: Replace the packed `SigSpec::extract` impl --- kernel/rtlil.cc | 46 +++++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index bafafb57b..a6aebaa42 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4438,37 +4438,33 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const cover("kernel.rtlil.sigspec.extract_pos"); - if (packed()) - { - if (chunks_.size() == 1) - return chunks_[0].extract(offset, length); - + if (packed()) { SigSpec extracted; - int end = offset + length; - int chunk_end = 0; + extracted.width_ = length; - for (auto const &chunk : chunks_) - { - int chunk_begin = chunk_end; - chunk_end += chunk.width; - int extract_begin = std::max(chunk_begin, offset); - int extract_end = std::min(chunk_end, end); - if (extract_begin >= extract_end) - continue; - int extract_offset = extract_begin - chunk_begin; - int extract_len = extract_end - extract_begin; - if (extract_offset == 0 && extract_len == chunk.width) - extracted.chunks_.emplace_back(chunk); - else - extracted.chunks_.emplace_back( - chunk.extract(extract_offset, extract_len)); + auto it = chunks_.begin(); + for (; offset; offset -= it->width, it++) { + if (offset < it->width) { + int chunk_length = min(it->width - offset, length); + extracted.chunks_.emplace_back(it->extract(offset, chunk_length)); + length -= chunk_length; + it++; + break; + } + } + for (; length; length -= it->width, it++) { + if (length >= it->width) { + extracted.chunks_.emplace_back(*it); + } else { + extracted.chunks_.emplace_back(it->extract(0, length)); + break; + } } - extracted.width_ = length; return extracted; + } else { + return std::vector(bits_.begin() + offset, bits_.begin() + offset + length); } - - return std::vector(bits_.begin() + offset, bits_.begin() + offset + length); } void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) From 4a666d3ba860f5d43f118c058b79a4ed6fce5b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 22 Apr 2024 16:36:47 +0200 Subject: [PATCH 064/184] Bump abc --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 95a982874..72adfe972 100644 --- a/Makefile +++ b/Makefile @@ -166,7 +166,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = 0cd90d0 +ABCREV = 208b486 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From 6d6aa4d35e43ac58cedef07326e45eb63890bf2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 22 Apr 2024 17:43:41 +0200 Subject: [PATCH 065/184] Bump abc to cherry-pick a WASM build fix --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 72adfe972..b426522b8 100644 --- a/Makefile +++ b/Makefile @@ -166,7 +166,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = 208b486 +ABCREV = b502f00 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From c167d9b76ec1f5cdacad0675185dad8d05a98fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 23 Apr 2024 11:41:20 +0200 Subject: [PATCH 066/184] Bump abc for one more fix --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b426522b8..afa76b6c9 100644 --- a/Makefile +++ b/Makefile @@ -166,7 +166,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = b502f00 +ABCREV = bc45604 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From 67c7062fb8d6e90e38954324c616d17d3b1d638f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 23 Apr 2024 13:50:45 +0200 Subject: [PATCH 067/184] Bump abc for a fix once more --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index afa76b6c9..f19ac04b5 100644 --- a/Makefile +++ b/Makefile @@ -166,7 +166,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = bc45604 +ABCREV = 03da96f ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From cf02f86c28ceb7f9bba041493663da3198c0fabc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 24 Apr 2024 00:16:06 +0000 Subject: [PATCH 068/184] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f19ac04b5..22fe373a6 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.40+25 +YOSYS_VER := 0.40+33 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From f2ebc3f7b14e1847798fecdf1c12cd3311cb214e Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Thu, 25 Apr 2024 09:39:23 +1200 Subject: [PATCH 069/184] github: Add template for documentation issues --- .github/ISSUE_TEMPLATE/docs_report.yml | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/docs_report.yml diff --git a/.github/ISSUE_TEMPLATE/docs_report.yml b/.github/ISSUE_TEMPLATE/docs_report.yml new file mode 100644 index 000000000..aa65c63b9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/docs_report.yml @@ -0,0 +1,55 @@ +name: Documentation Report +description: Report a problem with the Yosys documentation +labels: ["pending-verification"] +body: + - type: markdown + attributes: + value: > + + If you have a general question, please ask it in the [Discussions](https://github.com/YosysHQ/yosys/discussions) area + or join our [IRC Channel](https://web.libera.chat/#yosys) or [Community Slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA). + + + If you have found a bug in Yosys, or in building the documentation, + please fill out the Bug Report issue form, this form is for problems + with the live documentation on [Read the + Docs](https://yosyshq.readthedocs.io/projects/yosys/). Please only + report problems that appear on the latest version of the documentation. + + + Please contact [YosysHQ GmbH](https://www.yosyshq.com/) if you need + commercial support for Yosys. + + - type: input + id: docs_url + attributes: + label: Link to page + description: "Please provide a link to the page where the problem was found." + placeholder: "e.g. https://yosyshq.readthedocs.io/projects/yosys/" + validations: + required: true + + - type: input + id: build_number + attributes: + label: Build number + description: "If possible, please provide the latest build number from https://readthedocs.org/projects/yosys/builds/." + placeholder: "e.g. Build #24078236" + validations: + required: false + + - type: textarea + id: problem + attributes: + label: Issue + description: "Please describe what is incorrect, invalid, or missing." + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected + description: "If applicable, please describe what should appear instead." + validations: + required: false From 374cd3966d65cf8dda4cdfd2563462211ab3216f Mon Sep 17 00:00:00 2001 From: Jason Wu Date: Mon, 29 Apr 2024 10:04:34 +0800 Subject: [PATCH 070/184] export define marco to qtcreator.config --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 22fe373a6..d77cacd54 100644 --- a/Makefile +++ b/Makefile @@ -92,7 +92,7 @@ YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) VPATH := $(YOSYS_SRC) CXXSTD ?= c++11 -CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include +CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include LIBS := $(LIBS) -lstdc++ -lm PLUGIN_LINKFLAGS := PLUGIN_LIBS := @@ -1045,11 +1045,12 @@ coverage: genhtml coverage.info --output-directory coverage_html qtcreator: + echo "$(CXXFLAGS)" | grep -o '\-D[^ ]*' | tr ' ' '\n' | sed 's/-D/#define /' | sed 's/=/ /'> qtcreator.config { for file in $(basename $(OBJS)); do \ for prefix in cc y l; do if [ -f $${file}.$${prefix} ]; then echo $$file.$${prefix}; fi; done \ done; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \); } > qtcreator.files { echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes - touch qtcreator.config qtcreator.creator + touch qtcreator.creator vcxsrc: $(GENFILES) $(EXTRA_TARGETS) rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip} From f1672b2f14cbf4aac89bd2e922bbd6919f808c6d Mon Sep 17 00:00:00 2001 From: Jason Wu <41063703+offline3@users.noreply.github.com> Date: Mon, 29 Apr 2024 10:16:22 +0800 Subject: [PATCH 071/184] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d77cacd54..296d66d0d 100644 --- a/Makefile +++ b/Makefile @@ -92,7 +92,7 @@ YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) VPATH := $(YOSYS_SRC) CXXSTD ?= c++11 -CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include +CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include LIBS := $(LIBS) -lstdc++ -lm PLUGIN_LINKFLAGS := PLUGIN_LIBS := From 4e6deb53b64d4acd2046d2826ede02c5cd35d22f Mon Sep 17 00:00:00 2001 From: George Rennie Date: Fri, 26 Apr 2024 19:16:01 +0100 Subject: [PATCH 072/184] read_aiger: Fix incorrect read of binary Aiger without outputs * Also makes all ascii parsing finish reading lines and adds a small test --- frontends/aiger/aigerparse.cc | 12 +++++------- tests/aiger/and_to_bad_out.aag | 8 ++++++++ tests/aiger/and_to_bad_out.aig | 5 +++++ 3 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 tests/aiger/and_to_bad_out.aag create mode 100644 tests/aiger/and_to_bad_out.aig diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index cb19b8413..0178514e1 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -590,6 +590,7 @@ void AigerReader::parse_aiger_ascii() for (unsigned i = 0; i < O; ++i, ++line_count) { if (!(f >> l1)) log_error("Line %u cannot be interpreted as an output!\n", line_count); + std::getline(f, line); // Ignore up to start of next line log_debug2("%d is an output\n", l1); RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i)); @@ -597,20 +598,18 @@ void AigerReader::parse_aiger_ascii() module->connect(wire, createWireIfNotExists(module, l1)); outputs.push_back(wire); } - //std::getline(f, line); // Ignore up to start of next line // Parse bad properties for (unsigned i = 0; i < B; ++i, ++line_count) { if (!(f >> l1)) log_error("Line %u cannot be interpreted as a bad state property!\n", line_count); + std::getline(f, line); // Ignore up to start of next line log_debug2("%d is a bad state property\n", l1); RTLIL::Wire *wire = createWireIfNotExists(module, l1); wire->port_output = true; bad_properties.push_back(wire); } - //if (B > 0) - // std::getline(f, line); // Ignore up to start of next line // TODO: Parse invariant constraints for (unsigned i = 0; i < C; ++i, ++line_count) @@ -628,6 +627,7 @@ void AigerReader::parse_aiger_ascii() for (unsigned i = 0; i < A; ++i) { if (!(f >> l1 >> l2 >> l3)) log_error("Line %u cannot be interpreted as an AND!\n", line_count); + std::getline(f, line); // Ignore up to start of next line log_debug2("%d %d %d is an AND\n", l1, l2, l3); log_assert(!(l1 & 1)); @@ -636,7 +636,6 @@ void AigerReader::parse_aiger_ascii() RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); module->addAndGate("$and" + o_wire->name.str(), i1_wire, i2_wire, o_wire); } - std::getline(f, line); // Ignore up to start of next line } static unsigned parse_next_delta_literal(std::istream &f, unsigned ref) @@ -715,6 +714,7 @@ void AigerReader::parse_aiger_binary() for (unsigned i = 0; i < O; ++i, ++line_count) { if (!(f >> l1)) log_error("Line %u cannot be interpreted as an output!\n", line_count); + std::getline(f, line); // Ignore up to start of next line log_debug2("%d is an output\n", l1); RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i)); @@ -722,20 +722,18 @@ void AigerReader::parse_aiger_binary() module->connect(wire, createWireIfNotExists(module, l1)); outputs.push_back(wire); } - std::getline(f, line); // Ignore up to start of next line // Parse bad properties for (unsigned i = 0; i < B; ++i, ++line_count) { if (!(f >> l1)) log_error("Line %u cannot be interpreted as a bad state property!\n", line_count); + std::getline(f, line); // Ignore up to start of next line log_debug2("%d is a bad state property\n", l1); RTLIL::Wire *wire = createWireIfNotExists(module, l1); wire->port_output = true; bad_properties.push_back(wire); } - if (B > 0) - std::getline(f, line); // Ignore up to start of next line // TODO: Parse invariant constraints for (unsigned i = 0; i < C; ++i, ++line_count) diff --git a/tests/aiger/and_to_bad_out.aag b/tests/aiger/and_to_bad_out.aag new file mode 100644 index 000000000..96f1e7cad --- /dev/null +++ b/tests/aiger/and_to_bad_out.aag @@ -0,0 +1,8 @@ +aag 3 2 0 0 1 1 0 0 0 +2 +4 +6 +6 2 4 +i0 pi0 +i1 pi1 +b0 b0 diff --git a/tests/aiger/and_to_bad_out.aig b/tests/aiger/and_to_bad_out.aig new file mode 100644 index 000000000..3be65ae89 --- /dev/null +++ b/tests/aiger/and_to_bad_out.aig @@ -0,0 +1,5 @@ +aig 3 2 0 0 1 1 +6 +i0 pi0 +i1 pi1 +b0 b0 From dd2195543b095cce108dcd9b94fe2f0a80660491 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Apr 2024 00:17:14 +0000 Subject: [PATCH 073/184] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 22fe373a6..2dbce272d 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.40+33 +YOSYS_VER := 0.40+45 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 8cc9aa7fc6a4d9008e68a4e146358a191cb854c4 Mon Sep 17 00:00:00 2001 From: Lofty Date: Fri, 3 May 2024 11:16:34 +0100 Subject: [PATCH 074/184] intel_alm: drop quartus support --- techlibs/intel_alm/Makefile.inc | 3 - techlibs/intel_alm/common/alm_sim.v | 414 +-------------------- techlibs/intel_alm/common/bram_m20k.txt | 33 -- techlibs/intel_alm/common/bram_m20k_map.v | 31 -- techlibs/intel_alm/common/dff_sim.v | 32 -- techlibs/intel_alm/common/mem_sim.v | 56 +-- techlibs/intel_alm/common/quartus_rename.v | 311 ---------------- techlibs/intel_alm/synth_intel_alm.cc | 81 +--- tests/arch/intel_alm/add_sub.ys | 9 - tests/arch/intel_alm/adffs.ys | 46 --- tests/arch/intel_alm/blockram.ys | 1 + tests/arch/intel_alm/counter.ys | 14 - tests/arch/intel_alm/dffs.ys | 22 -- tests/arch/intel_alm/fsm.ys | 22 -- tests/arch/intel_alm/logic.ys | 13 - tests/arch/intel_alm/lutram.ys | 1 + tests/arch/intel_alm/mul.ys | 25 -- tests/arch/intel_alm/mux.ys | 43 --- tests/arch/intel_alm/quartus_ice.ys | 26 -- tests/arch/intel_alm/shifter.ys | 11 - tests/arch/intel_alm/tribuf.ys | 14 - 21 files changed, 18 insertions(+), 1190 deletions(-) delete mode 100644 techlibs/intel_alm/common/bram_m20k.txt delete mode 100644 techlibs/intel_alm/common/bram_m20k_map.v delete mode 100644 techlibs/intel_alm/common/quartus_rename.v delete mode 100644 tests/arch/intel_alm/quartus_ice.ys diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc index b5f279a92..9e24d695e 100644 --- a/techlibs/intel_alm/Makefile.inc +++ b/techlibs/intel_alm/Makefile.inc @@ -20,10 +20,7 @@ $(eval $(call add_share_file,share/intel_alm/cyclonev,techlibs/intel_alm/cyclone # RAM $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m10k.txt)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m10k_map.v)) -$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m20k.txt)) -$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m20k_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt)) # 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)) diff --git a/techlibs/intel_alm/common/alm_sim.v b/techlibs/intel_alm/common/alm_sim.v index d3bd67390..858e43c76 100644 --- a/techlibs/intel_alm/common/alm_sim.v +++ b/techlibs/intel_alm/common/alm_sim.v @@ -1,4 +1,4 @@ -// The core logic primitive of the Cyclone V/10GX is the Adaptive Logic Module +// The core logic primitive of the Cyclone V is the Adaptive Logic Module // (ALM). Each ALM is made up of an 8-input, 2-output look-up table, covered // in this file, connected to combinational outputs, a carry chain, and four // D flip-flops (which are covered as MISTRAL_FF in dff_sim.v). @@ -77,14 +77,6 @@ // SUMOUT 368 1342 1323 887 927 - 785 - // CARRYOUT 71 1082 1062 866 813 - 1198 - -// Arria V LUT output timings (picoseconds): -// -// CARRY A B C D E F G -// COMBOUT - 387 375 316 317 - 76 319 (LUT6) -// COMBOUT - 387 375 316 317 218 76 319 (LUT7) -// SUMOUT 249 744 732 562 576 - 511 - -// CARRYOUT 19 629 623 530 514 - 696 - - (* abc9_lut=2, lib_whitebox *) module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); @@ -100,26 +92,6 @@ specify (F => Q) = 97; endspecify `endif -`ifdef arriav -specify - (A => Q) = 387; - (B => Q) = 375; - (C => Q) = 316; - (D => Q) = 317; - (E => Q) = 319; - (F => Q) = 76; -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}; @@ -140,24 +112,6 @@ specify (E => Q) = 97; endspecify `endif -`ifdef arriav -specify - (A => Q) = 375; - (B => Q) = 316; - (C => Q) = 317; - (D => Q) = 319; - (E => Q) = 76; -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}; @@ -177,22 +131,6 @@ specify (D => Q) = 97; endspecify `endif -`ifdef arriav -specify - (A => Q) = 316; - (B => Q) = 317; - (C => Q) = 319; - (D => Q) = 76; -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}; @@ -211,20 +149,6 @@ specify (C => Q) = 97; endspecify `endif -`ifdef arriav -specify - (A => Q) = 316; - (B => Q) = 317; - (C => Q) = 76; -endspecify -`endif -`ifdef cyclone10gx -specify - (A => Q) = 165; - (B => Q) = 162; - (C => Q) = 53; -endspecify -`endif assign Q = LUT >> {C, B, A}; @@ -242,18 +166,6 @@ specify (B => Q) = 97; endspecify `endif -`ifdef arriav -specify - (A => Q) = 316; - (B => Q) = 76; -endspecify -`endif -`ifdef cyclone10gx -specify - (A => Q) = 162; - (B => Q) = 53; -endspecify -`endif assign Q = LUT >> {B, A}; @@ -268,16 +180,6 @@ specify (A => Q) = 97; endspecify `endif -`ifdef arriav -specify - (A => Q) = 76; -endspecify -`endif -`ifdef cyclone10gx -specify - (A => Q) = 53; -endspecify -`endif assign Q = ~A; @@ -306,40 +208,6 @@ specify (CI => CO) = 36; // Divided by 2 to account for there being two ALUT_ARITHs in an ALM) endspecify `endif -`ifdef arriav -specify - (A => SO) = 744; - (B => SO) = 732; - (C => SO) = 562; - (D0 => SO) = 576; - (D1 => SO) = 511; - (CI => SO) = 249; - - (A => CO) = 629; - (B => CO) = 623; - (C => CO) = 530; - (D0 => CO) = 514; - (D1 => CO) = 696; - (CI => CO) = 10; // Divided by 2 to account for there being two ALUT_ARITHs in an ALM) -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; @@ -349,283 +217,3 @@ 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/bram_m20k.txt b/techlibs/intel_alm/common/bram_m20k.txt deleted file mode 100644 index b4c5a5372..000000000 --- a/techlibs/intel_alm/common/bram_m20k.txt +++ /dev/null @@ -1,33 +0,0 @@ -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 deleted file mode 100644 index 15739d66a..000000000 --- a/techlibs/intel_alm/common/bram_m20k_map.v +++ /dev/null @@ -1,31 +0,0 @@ -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_sim.v b/techlibs/intel_alm/common/dff_sim.v index 8d58bf614..a558973f9 100644 --- a/techlibs/intel_alm/common/dff_sim.v +++ b/techlibs/intel_alm/common/dff_sim.v @@ -77,38 +77,6 @@ specify if (ACLR === 1'b0) (ACLR => Q) = 282; endspecify `endif -`ifdef arriav -specify - if (ENA && ACLR !== 1'b0 && !SCLR && !SLOAD) (posedge CLK => (Q : DATAIN)) = 470; - if (ENA && SCLR) (posedge CLK => (Q : 1'b0)) = 633; - if (ENA && !SCLR && SLOAD) (posedge CLK => (Q : SDATA)) = 439; - - $setup(DATAIN, posedge CLK, /* -170 */ 0); - $setup(ENA, posedge CLK, /* -170 */ 0); - $setup(SCLR, posedge CLK, /* -170 */ 0); - $setup(SLOAD, posedge CLK, /* -170 */ 0); - $setup(SDATA, posedge CLK, /* -170 */ 0); - - if (ACLR === 1'b0) (ACLR => Q) = 215; -endspecify -`endif -`ifdef cyclone10gx -specify - // TODO (long-term): investigate these numbers. - // It seems relying on the Quartus Timing Analyzer was not the best idea; it's too fiddly. - if (ENA && ACLR !== 1'b0 && !SCLR && !SLOAD) (posedge CLK => (Q : DATAIN)) = 219; - if (ENA && SCLR) (posedge CLK => (Q : 1'b0)) = 219; - if (ENA && !SCLR && SLOAD) (posedge CLK => (Q : SDATA)) = 219; - - $setup(DATAIN, posedge CLK, 268); - $setup(ENA, posedge CLK, 268); - $setup(SCLR, posedge CLK, 268); - $setup(SLOAD, posedge CLK, 268); - $setup(SDATA, posedge CLK, 268); - - if (ACLR === 1'b0) (ACLR => Q) = 0; -endspecify -`endif initial begin // Altera flops initialise to zero. diff --git a/techlibs/intel_alm/common/mem_sim.v b/techlibs/intel_alm/common/mem_sim.v index 563f1d241..5ab1b7326 100644 --- a/techlibs/intel_alm/common/mem_sim.v +++ b/techlibs/intel_alm/common/mem_sim.v @@ -1,7 +1,7 @@ // The MLAB // -------- // In addition to Logic Array Blocks (LABs) that contain ten Adaptive Logic -// Modules (ALMs, see alm_sim.v), the Cyclone V/10GX also contain +// Modules (ALMs, see alm_sim.v), the Cyclone V also contains // Memory/Logic Array Blocks (MLABs) that can act as either ten ALMs, or utilise // the memory the ALM uses to store the look-up table data for general usage, // producing a 32 address by 20-bit block of memory. MLABs are spread out @@ -14,11 +14,8 @@ // or shift registers (by using the output of the Nth bit as input for the N+1th // bit). // -// Oddly, instead of providing a block 32 address by 20-bit cell, Quartus asks -// synthesis tools to build MLABs out of 32 address by 1-bit cells, and tries -// to put these cells in the same MLAB during cell placement. Because of this -// a MISTRAL_MLAB cell represents one of these 32 address by 1-bit cells, and -// 20 of them represent a physical MLAB. +// For historical reasons a MISTRAL_MLAB cell represents a 32 address by 1-bit cell, +// and 20 of them represent a physical MLAB. // // How the MLAB works // ------------------ @@ -28,10 +25,7 @@ // by the Yosys `memory_bram` pass, and it doesn't make sense to me to use // `techmap` just for the sake of renaming the cell ports. // -// The MLAB can be initialised to any value, but unfortunately Quartus only -// allows memory initialisation from a file. Since Yosys doesn't preserve input -// file information, or write the contents of an `initial` block to a file, -// Yosys can't currently initialise the MLAB in a way Quartus will accept. +// The MLAB can be initialised to any value. // // The MLAB takes in data from A1DATA at the rising edge of CLK1, and if A1EN // is high, writes it to the address in A1ADDR. A1EN can therefore be used to @@ -39,9 +33,7 @@ // // Simultaneously, the MLAB reads data from B1ADDR, and outputs it to B1DATA, // asynchronous to CLK1 and ignoring A1EN. If a synchronous read is needed -// then the output can be fed to embedded flops. Presently, Yosys assumes -// Quartus will pack external flops into the MLAB, but this is an assumption -// that needs testing. +// then the output can be fed to embedded flops. // The vendor sim model outputs 'x for a very short period (a few // combinational delta cycles) after each write. This has been omitted from @@ -69,33 +61,6 @@ specify (B1ADDR[4] => B1DATA) = 96; endspecify `endif -`ifdef arriav -specify - $setup(A1ADDR, posedge CLK1, 62); - $setup(A1DATA, posedge CLK1, 62); - $setup(A1EN, posedge CLK1, 62); - - (B1ADDR[0] => B1DATA) = 370; - (B1ADDR[1] => B1DATA) = 292; - (B1ADDR[2] => B1DATA) = 218; - (B1ADDR[3] => B1DATA) = 74; - (B1ADDR[4] => B1DATA) = 177; -endspecify -`endif -`ifdef cyclone10gx -// TODO: Cyclone 10 GX timings; the below timings are for Cyclone V -specify - $setup(A1ADDR, posedge CLK1, 86); - $setup(A1DATA, posedge CLK1, 86); - $setup(A1EN, posedge CLK1, 86); - - (B1ADDR[0] => B1DATA) = 487; - (B1ADDR[1] => B1DATA) = 475; - (B1ADDR[2] => B1DATA) = 382; - (B1ADDR[3] => B1DATA) = 284; - (B1ADDR[4] => B1DATA) = 96; -endspecify -`endif always @(posedge CLK1) if (A1EN) mem[A1ADDR] <= A1DATA; @@ -134,17 +99,6 @@ specify if (B1EN) (posedge CLK1 => (B1DATA : A1DATA)) = 1004; endspecify `endif -`ifdef arriav -specify - $setup(A1ADDR, posedge CLK1, 97); - $setup(A1DATA, posedge CLK1, 74); - $setup(A1EN, posedge CLK1, 109); - $setup(B1ADDR, posedge CLK1, 97); - $setup(B1EN, posedge CLK1, 126); - - if (B1EN) (posedge CLK1 => (B1DATA : A1DATA)) = 787; -endspecify -`endif always @(posedge CLK1) begin if (!A1EN) diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v deleted file mode 100644 index 217dc5de9..000000000 --- a/techlibs/intel_alm/common/quartus_rename.v +++ /dev/null @@ -1,311 +0,0 @@ -`ifdef cyclonev -`define LCELL cyclonev_lcell_comb -`define MAC cyclonev_mac -`define MLAB cyclonev_mlab_cell -`define RAM_BLOCK cyclonev_ram_block -`define IBUF cyclonev_io_ibuf -`define OBUF cyclonev_io_obuf -`define CLKENA cyclonev_clkena -`endif -`ifdef arriav -`define LCELL arriav_lcell_comb -`define MAC arriav_mac -`define MLAB arriav_mlab_cell -`define RAM_BLOCK arriav_ram_block -`define IBUF arriav_io_ibuf -`define OBUF arriav_io_obuf -`define CLKENA arriav_clkena -`endif -`ifdef cyclone10gx -`define LCELL cyclone10gx_lcell_comb -`define MAC cyclone10gx_mac -`define MLAB cyclone10gx_mlab_cell -`define RAM_BLOCK cyclone10gx_ram_block -`define IBUF cyclone10gx_io_ibuf -`define OBUF cyclone10gx_io_obuf -`define CLKENA cyclone10gx_clkena -`endif - -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 - - -module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); -parameter [63:0] LUT = 64'h0000_0000_0000_0000; - -`LCELL #(.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 [31:0] LUT = 32'h0000_0000; - -`LCELL #(.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 [15:0] LUT = 16'h0000; - -`LCELL #(.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 [7:0] LUT = 8'h00; - -`LCELL #(.lut_mask({8{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .combout(Q)); - -endmodule - - -module MISTRAL_ALUT2(input A, B, output Q); -parameter [3:0] LUT = 4'h0; - -`LCELL #(.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; - -`LCELL #(.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 - - -module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1ADDR, output B1DATA); - -parameter _TECHMAP_CELLNAME_ = ""; - -// Here we get to an unfortunate situation. The cell has a mem_init0 parameter, -// which takes in a hexadecimal string that could be used to initialise RAM. -// In the vendor simulation models, this appears to work fine, but Quartus, -// either intentionally or not, forgets about this parameter and initialises the -// RAM to zero. -// -// Because of this, RAM initialisation is presently disabled, but the source -// used to generate mem_init0 is kept (commented out) in case this gets fixed -// or an undocumented way to get Quartus to initialise from mem_init0 is found. - -`MLAB #( - .logical_ram_name(_TECHMAP_CELLNAME_), - .logical_ram_depth(32), - .logical_ram_width(1), - .mixed_port_feed_through_mode("Dont Care"), - .first_bit_number(0), - .first_address(0), - .last_address(31), - .address_width(5), - .data_width(1), - .byte_enable_mask_width(1), - .port_b_data_out_clock("NONE"), - // .mem_init0($sformatf("%08x", INIT)) -) _TECHMAP_REPLACE_ ( - .portaaddr(A1ADDR), - .portadatain(A1DATA), - .portbaddr(B1ADDR), - .portbdataout(B1DATA), - .ena0(A1EN), - .clk0(CLK1) -); - -endmodule - - -module MISTRAL_M10K(A1ADDR, A1DATA, A1EN, CLK1, B1ADDR, B1DATA, B1EN); - -parameter CFG_ABITS = 10; -parameter CFG_DBITS = 10; - -parameter _TECHMAP_CELLNAME_ = ""; - -input [CFG_ABITS-1:0] A1ADDR, B1ADDR; -input [CFG_DBITS-1:0] A1DATA; -input CLK1, A1EN, B1EN; -output [CFG_DBITS-1:0] B1DATA; - -// Much like the MLAB, the M10K has mem_init[01234] parameters which would let -// you initialise the RAM cell via hex literals. If they were implemented. - -// Since the MISTRAL_M10K block has an inverted write-enable (like the real hardware) -// but the Quartus primitive expects a normal write-enable, we add an inverter. -wire A1EN_N; -NOT wren_inv (.IN(A1EN), .OUT(A1EN_N)); - -`RAM_BLOCK #( - .operation_mode("dual_port"), - .logical_ram_name(_TECHMAP_CELLNAME_), - .port_a_address_width(CFG_ABITS), - .port_a_data_width(CFG_DBITS), - .port_a_logical_ram_depth(2**CFG_ABITS), - .port_a_logical_ram_width(CFG_DBITS), - .port_a_first_address(0), - .port_a_last_address(2**CFG_ABITS - 1), - .port_a_first_bit_number(0), - .port_b_address_width(CFG_ABITS), - .port_b_data_width(CFG_DBITS), - .port_b_logical_ram_depth(2**CFG_ABITS), - .port_b_logical_ram_width(CFG_DBITS), - .port_b_first_address(0), - .port_b_last_address(2**CFG_ABITS - 1), - .port_b_first_bit_number(0), - .port_b_address_clock("clock0"), - .port_b_read_enable_clock("clock0") -) ram_block ( - .portaaddr(A1ADDR), - .portadatain(A1DATA), - .portawe(A1EN_N), - .portbaddr(B1ADDR), - .portbdataout(B1DATA), - .portbre(B1EN), - .clk0(CLK1) -); - -endmodule - - -module MISTRAL_MUL27X27(input [26:0] A, B, output [53:0] Y); - -parameter A_SIGNED = 1; -parameter B_SIGNED = 1; - -`MAC #( - .ax_width(27), - .signed_max(A_SIGNED ? "true" : "false"), - .ay_scan_in_width(27), - .signed_may(B_SIGNED ? "true" : "false"), - .result_a_width(54), - .operation_mode("M27x27") -) _TECHMAP_REPLACE_ ( - .ax(A), - .ay(B), - .resulta(Y) -); - -endmodule - - -module MISTRAL_MUL18X18(input [17:0] A, B, output [35:0] Y); - -parameter A_SIGNED = 1; -parameter B_SIGNED = 1; - -`MAC #( - .ax_width(18), - .signed_max(A_SIGNED ? "true" : "false"), - .ay_scan_in_width(18), - .signed_may(B_SIGNED ? "true" : "false"), - .result_a_width(36), - .operation_mode("M18x18_FULL") -) _TECHMAP_REPLACE_ ( - .ax(A), - .ay(B), - .resulta(Y) -); - -endmodule - - -module MISTRAL_MUL9X9(input [8:0] A, B, output [17:0] Y); - -parameter A_SIGNED = 1; -parameter B_SIGNED = 1; - -`MAC #( - .ax_width(9), - .signed_max(A_SIGNED ? "true" : "false"), - .ay_scan_in_width(9), - .signed_may(B_SIGNED ? "true" : "false"), - .result_a_width(18), - .operation_mode("M9x9") -) _TECHMAP_REPLACE_ ( - .ax(A), - .ay(B), - .resulta(Y) -); - -endmodule - -module MISTRAL_IB(input PAD, output O); -`IBUF #( - .bus_hold("false"), - .differential_mode("false") -) _TECHMAP_REPLACE_ ( - .i(PAD), - .o(O) -); -endmodule - -module MISTRAL_OB(output PAD, input I, OE); -`OBUF #( - .bus_hold("false"), - .differential_mode("false") -) _TECHMAP_REPLACE_ ( - .i(I), - .o(PAD), - .oe(OE) -); -endmodule - -module MISTRAL_IO(output PAD, input I, OE, output O); -`IBUF #( - .bus_hold("false"), - .differential_mode("false") -) ibuf ( - .i(PAD), - .o(O) -); - -`OBUF #( - .bus_hold("false"), - .differential_mode("false") -) obuf ( - .i(I), - .o(PAD), - .oe(OE) -); -endmodule - -module MISTRAL_CLKBUF (input A, output Q); -`CLKENA #( - .clock_type("auto"), - .ena_register_mode("always enabled"), - .ena_register_power_up("high"), - .disable_mode("low"), - .test_syn("high") -) _TECHMAP_REPLACE_ ( - .inclk(A), - .ena(1'b1), - .outclk(Q) -); -endmodule diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index c33eb43bf..cdae9586e 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -2,7 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Claire Xenia Wolf - * Copyright (C) 2019 Dan Ravensloft + * Copyright (C) 2019 Hannah Ravensloft * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -43,21 +43,11 @@ struct SynthIntelALMPass : public ScriptPass { log(" -family \n"); log(" target one of:\n"); log(" \"cyclonev\" - Cyclone V (default)\n"); - log(" \"arriav\" - Arria V (non-GZ)\n"); - log(" \"cyclone10gx\" - Cyclone 10GX\n"); - log("\n"); - log(" -vqm \n"); - log(" write the design to the specified Verilog Quartus Mapping File. Writing\n"); - log(" of an output file is omitted if this parameter is not specified. Implies\n"); - log(" -quartus.\n"); log("\n"); log(" -noflatten\n"); log(" do not flatten design before synthesis; useful for per-module area\n"); log(" statistics\n"); log("\n"); - log(" -quartus\n"); - log(" output a netlist using Quartus cells instead of MISTRAL_* cells\n"); - log("\n"); log(" -dff\n"); log(" pass DFFs to ABC to perform sequential logic optimisations\n"); log(" (EXPERIMENTAL)\n"); @@ -87,17 +77,15 @@ struct SynthIntelALMPass : public ScriptPass { log("\n"); } - string top_opt, family_opt, bram_type, vout_file; - bool flatten, quartus, nolutram, nobram, dff, nodsp, noiopad, noclkbuf; + string top_opt, family_opt, bram_type; + bool flatten, nolutram, nobram, dff, nodsp, noiopad, noclkbuf; void clear_flags() override { top_opt = "-auto-top"; family_opt = "cyclonev"; bram_type = "m10k"; - vout_file = ""; flatten = true; - quartus = false; nolutram = false; nobram = false; dff = false; @@ -121,11 +109,6 @@ struct SynthIntelALMPass : public ScriptPass { 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) @@ -134,10 +117,6 @@ struct SynthIntelALMPass : public ScriptPass { run_to = args[argidx].substr(pos + 1); continue; } - if (args[argidx] == "-quartus") { - quartus = true; - continue; - } if (args[argidx] == "-nolutram") { nolutram = true; continue; @@ -173,18 +152,6 @@ struct SynthIntelALMPass : public ScriptPass { if (!design->full_selection()) log_cmd_error("This command only operates on fully selected designs!\n"); - if (family_opt == "cyclonev" || family_opt == "arriav") { - bram_type = "m10k"; - } else if (family_opt == "cyclone10gx") { - bram_type = "m20k"; - } else if (family_opt == "arriva") { - // I have typoed "arriav" as "arriva" (a local bus company) - // so many times I thought it would be funny to have an easter egg. - log_cmd_error("synth_intel_alm cannot synthesize for bus companies. (did you mean '-family arriav'?)\n"); - } else { - log_cmd_error("Invalid family specified: '%s'\n", family_opt.c_str()); - } - log_header(design, "Executing SYNTH_INTEL_ALM pass.\n"); log_push(); @@ -237,22 +204,16 @@ struct SynthIntelALMPass : public ScriptPass { if (help_mode) { run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp)"); } else if (!nodsp) { - // Cyclone V/Arria V supports 9x9 multiplication, Cyclone 10 GX does not. run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=27 -D DSP_B_MAXWIDTH=27 -D DSP_A_MINWIDTH=19 -D DSP_B_MINWIDTH=4 -D DSP_NAME=__MUL27X27"); run("chtype -set $mul t:$__soft_mul"); run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=27 -D DSP_B_MAXWIDTH=27 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=19 -D DSP_NAME=__MUL27X27"); run("chtype -set $mul t:$__soft_mul"); - if (family_opt == "cyclonev" || family_opt == "arriav") { - run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=4 -D DSP_NAME=__MUL18X18"); - run("chtype -set $mul t:$__soft_mul"); - run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=10 -D DSP_NAME=__MUL18X18"); - run("chtype -set $mul t:$__soft_mul"); - run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=9 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=__MUL9X9"); - run("chtype -set $mul t:$__soft_mul"); - } else if (family_opt == "cyclone10gx") { - run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=__MUL18X18"); - run("chtype -set $mul t:$__soft_mul"); - } + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=4 -D DSP_NAME=__MUL18X18"); + run("chtype -set $mul t:$__soft_mul"); + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=10 -D DSP_NAME=__MUL18X18"); + run("chtype -set $mul t:$__soft_mul"); + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=9 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=__MUL9X9"); + run("chtype -set $mul t:$__soft_mul"); } run("alumacc"); if (!noiopad) @@ -269,7 +230,7 @@ struct SynthIntelALMPass : public ScriptPass { } 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("memory_bram -rules +/intel_alm/common/lutram_mlab.txt", "(for Cyclone V)"); } if (check_label("map_ffram")) { @@ -303,28 +264,6 @@ struct SynthIntelALMPass : public ScriptPass { run("check"); run("blackbox =A:whitebox"); } - - if (check_label("quartus")) { - if (quartus || help_mode) { - // Quartus ICEs if you have a wire which has `[]` in its name, - // which Yosys produces when building memories out of flops. - run("rename -hide w:*[* w:*]*"); - // VQM mode does not support 'x, so replace those with zero. - run("setundef -zero"); - // VQM mode does not support multi-bit constant assignments - // (e.g. 2'b00 is an error), so as a workaround use references - // to constant driver cells, which Quartus accepts. - run("hilomap -singleton -hicell __MISTRAL_VCC Q -locell __MISTRAL_GND Q"); - // Rename from Yosys-internal MISTRAL_* cells to Quartus cells. - run(stringf("techmap -D %s -map +/intel_alm/common/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 ? "" : vout_file.c_str())); - } - } } } SynthIntelALMPass; diff --git a/tests/arch/intel_alm/add_sub.ys b/tests/arch/intel_alm/add_sub.ys index 8f87adf27..6453da116 100644 --- a/tests/arch/intel_alm/add_sub.ys +++ b/tests/arch/intel_alm/add_sub.ys @@ -7,12 +7,3 @@ stat select -assert-count 9 t:MISTRAL_ALUT_ARITH select -assert-none t:MISTRAL_ALUT_ARITH %% t:* %D -design -reset -read_verilog ../common/add_sub.v -hierarchy -top top -equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx -noiopad -noclkbuf # 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 9 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 index d7487c40b..1f81902ec 100644 --- a/tests/arch/intel_alm/adffs.ys +++ b/tests/arch/intel_alm/adffs.ys @@ -12,18 +12,6 @@ select -assert-count 1 t:MISTRAL_NOT select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D -design -load 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 cyclone10gx -noiopad -noclkbuf # 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 @@ -35,17 +23,6 @@ select -assert-count 1 t:MISTRAL_FF select -assert-none t:MISTRAL_FF %% 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 cyclone10gx -noiopad -noclkbuf # 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 @@ -58,18 +35,6 @@ select -assert-count 1 t:MISTRAL_ALUT2 select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 %% 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 cyclone10gx -noiopad -noclkbuf # 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 @@ -81,14 +46,3 @@ select -assert-count 2 t:MISTRAL_NOT select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% 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 cyclone10gx -noiopad -noclkbuf # 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 2 t:MISTRAL_NOT - -select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D diff --git a/tests/arch/intel_alm/blockram.ys b/tests/arch/intel_alm/blockram.ys index 21b5ecbfb..4af59e7d4 100644 --- a/tests/arch/intel_alm/blockram.ys +++ b/tests/arch/intel_alm/blockram.ys @@ -5,3 +5,4 @@ cd sync_ram_sdp select -assert-count 1 t:MISTRAL_NOT select -assert-count 1 t:MISTRAL_M10K select -assert-none t:MISTRAL_NOT t:MISTRAL_M10K %% t:* %D + diff --git a/tests/arch/intel_alm/counter.ys b/tests/arch/intel_alm/counter.ys index 2b428fb3e..44e000814 100644 --- a/tests/arch/intel_alm/counter.ys +++ b/tests/arch/intel_alm/counter.ys @@ -11,17 +11,3 @@ 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 - -design -reset -read_verilog ../common/counter.v -hierarchy -top top -proc -flatten -equiv_opt -assert -async2sync -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx -noiopad -noclkbuf # 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 index 34b99f04c..aeaae4aa3 100644 --- a/tests/arch/intel_alm/dffs.ys +++ b/tests/arch/intel_alm/dffs.ys @@ -7,17 +7,6 @@ equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm 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 dff -proc -equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx -noiopad -noclkbuf # 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 @@ -28,16 +17,5 @@ equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm 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-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 cyclone10gx -noiopad -noclkbuf # 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-none t:MISTRAL_FF %% t:* %D diff --git a/tests/arch/intel_alm/fsm.ys b/tests/arch/intel_alm/fsm.ys index 0aeea450a..f3060684a 100644 --- a/tests/arch/intel_alm/fsm.ys +++ b/tests/arch/intel_alm/fsm.ys @@ -20,25 +20,3 @@ select -assert-max 6 t:MISTRAL_ALUT5 # Clang returns 5, GCC returns 4 select -assert-max 2 t:MISTRAL_ALUT6 # Clang returns 1, GCC returns 2 select -assert-none t:MISTRAL_FF t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D -design -reset -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 cyclone10gx -noiopad -noclkbuf -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 1 t:MISTRAL_NOT -select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1 -select -assert-max 2 t:MISTRAL_ALUT3 # Clang returns 2, GCC returns 1 -select -assert-max 2 t:MISTRAL_ALUT4 # Clang returns 0, GCC returns 1 -select -assert-max 6 t:MISTRAL_ALUT5 # Clang returns 5, GCC returns 4 -select -assert-max 2 t:MISTRAL_ALUT6 # Clang returns 1, GCC returns 2 -select -assert-none t:MISTRAL_FF t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D diff --git a/tests/arch/intel_alm/logic.ys b/tests/arch/intel_alm/logic.ys index d34d1bc65..831f9f174 100644 --- a/tests/arch/intel_alm/logic.ys +++ b/tests/arch/intel_alm/logic.ys @@ -10,16 +10,3 @@ 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 - -design -reset -read_verilog ../common/logic.v -hierarchy -top top -proc -equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx -noiopad -noclkbuf # 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 \ No newline at end of file diff --git a/tests/arch/intel_alm/lutram.ys b/tests/arch/intel_alm/lutram.ys index 9ddb1ec87..4e77afded 100644 --- a/tests/arch/intel_alm/lutram.ys +++ b/tests/arch/intel_alm/lutram.ys @@ -37,3 +37,4 @@ select -assert-count 2 t:MISTRAL_ALUT2 select -assert-count 8 t:MISTRAL_ALUT3 select -assert-count 8 t:MISTRAL_FF select -assert-none t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_FF t:MISTRAL_MLAB %% t:* %D + diff --git a/tests/arch/intel_alm/mul.ys b/tests/arch/intel_alm/mul.ys index e147d93ac..75b328463 100644 --- a/tests/arch/intel_alm/mul.ys +++ b/tests/arch/intel_alm/mul.ys @@ -9,8 +9,6 @@ cd top # Constrain all select calls below inside the top module select -assert-count 1 t:MISTRAL_MUL9X9 select -assert-none t:MISTRAL_MUL9X9 %% t:* %D -# Cyclone 10 GX does not have 9x9 multipliers. - design -reset read_verilog ../common/mul.v chparam -set X_WIDTH 17 -set Y_WIDTH 17 -set A_WIDTH 34 @@ -23,18 +21,6 @@ cd top # Constrain all select calls below inside the top module select -assert-count 1 t:MISTRAL_MUL18X18 select -assert-none t:MISTRAL_MUL18X18 %% t:* %D -design -reset -read_verilog ../common/mul.v -chparam -set X_WIDTH 17 -set Y_WIDTH 17 -set A_WIDTH 34 -hierarchy -top top -proc -equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclone10gx -noiopad -noclkbuf # 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_MUL18X18 -select -assert-none t:MISTRAL_MUL18X18 %% t:* %D - design -reset read_verilog ../common/mul.v chparam -set X_WIDTH 26 -set Y_WIDTH 26 -set A_WIDTH 52 @@ -47,14 +33,3 @@ cd top # Constrain all select calls below inside the top module select -assert-count 1 t:MISTRAL_MUL27X27 select -assert-none t:MISTRAL_MUL27X27 %% t:* %D -design -reset -read_verilog ../common/mul.v -chparam -set X_WIDTH 26 -set Y_WIDTH 26 -set A_WIDTH 52 -hierarchy -top top -proc -equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclone10gx -noiopad -noclkbuf # 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_MUL27X27 -select -assert-none t:MISTRAL_MUL27X27 %% t:* %D diff --git a/tests/arch/intel_alm/mux.ys b/tests/arch/intel_alm/mux.ys index 20969ead3..951b0eff6 100644 --- a/tests/arch/intel_alm/mux.ys +++ b/tests/arch/intel_alm/mux.ys @@ -11,16 +11,6 @@ select -assert-count 1 t:MISTRAL_ALUT3 select -assert-none t:MISTRAL_ALUT3 %% t:* %D -design -load read -hierarchy -top mux2 -proc -equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx -noiopad -noclkbuf # 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 @@ -31,16 +21,6 @@ select -assert-count 1 t:MISTRAL_ALUT6 select -assert-none t:MISTRAL_ALUT6 %% t:* %D -design -load read -hierarchy -top mux4 -proc -equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx -noiopad -noclkbuf # 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 @@ -52,17 +32,6 @@ select -assert-count 2 t:MISTRAL_ALUT6 select -assert-none t:MISTRAL_ALUT3 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 cyclone10gx -noiopad -noclkbuf # 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 2 t:MISTRAL_ALUT6 -select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT6 %% t:* %D - - design -load read hierarchy -top mux16 proc @@ -74,15 +43,3 @@ select -assert-max 2 t:MISTRAL_ALUT5 select -assert-max 5 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 cyclone10gx -noiopad -noclkbuf # 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-max 1 t:MISTRAL_ALUT3 -select -assert-max 2 t:MISTRAL_ALUT5 -select -assert-max 5 t:MISTRAL_ALUT6 - -select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D diff --git a/tests/arch/intel_alm/quartus_ice.ys b/tests/arch/intel_alm/quartus_ice.ys deleted file mode 100644 index 4e1896b82..000000000 --- a/tests/arch/intel_alm/quartus_ice.ys +++ /dev/null @@ -1,26 +0,0 @@ -read_verilog < Date: Wed, 10 Apr 2024 14:17:57 +0200 Subject: [PATCH 075/184] techmap: Support dynamic cell types --- kernel/constids.inc | 2 ++ passes/techmap/techmap.cc | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/kernel/constids.inc b/kernel/constids.inc index 7db21debb..00db94af4 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -222,6 +222,8 @@ X(_TECHMAP_REPLACE_) X(techmap_simplemap) X(_techmap_special_) X(techmap_wrap) +X(_TECHMAP_PLACEHOLDER_) +X(techmap_chtype) X(T_FALL_MAX) X(T_FALL_MIN) X(T_FALL_TYP) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index db395315c..eda7c2f6c 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -336,6 +336,9 @@ struct TechmapWorker if (c->type.begins_with("\\$")) c->type = c->type.substr(1); + + if (c->type == ID::_TECHMAP_PLACEHOLDER_ && tpl_cell->has_attribute(ID::techmap_chtype)) + c->type = RTLIL::escape_id(tpl_cell->get_string_attribute(ID::techmap_chtype)); vector autopurge_ports; @@ -1135,6 +1138,10 @@ struct TechmapPass : public Pass { log("new wire alias to be created and named as above but with the `_TECHMAP_REPLACE_'\n"); log("prefix also substituted.\n"); log("\n"); + log("A cell with the type _TECHMAP_PLACEHOLDER_ in the map file will have its type\n"); + log("changed to the content of the techmap_chtype attribute. This allows for choosing\n"); + log("the cell type dynamically.\n"); + log("\n"); log("See 'help extract' for a pass that does the opposite thing.\n"); log("\n"); log("See 'help flatten' for a pass that does flatten the design (which is\n"); From 6ff4ecb2b42b8df40c2c44051159d53bf9eea65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 10 Apr 2024 18:32:27 +0200 Subject: [PATCH 076/184] techmap: Remove `techmap_chtype` from the result --- passes/techmap/techmap.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index eda7c2f6c..64de3a1ca 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -337,8 +337,10 @@ struct TechmapWorker if (c->type.begins_with("\\$")) c->type = c->type.substr(1); - if (c->type == ID::_TECHMAP_PLACEHOLDER_ && tpl_cell->has_attribute(ID::techmap_chtype)) + if (c->type == ID::_TECHMAP_PLACEHOLDER_ && tpl_cell->has_attribute(ID::techmap_chtype)) { c->type = RTLIL::escape_id(tpl_cell->get_string_attribute(ID::techmap_chtype)); + c->attributes.erase(ID::techmap_chtype); + } vector autopurge_ports; From a833f050364c959c2eebc039c019a3df8d420825 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 2 May 2024 23:49:50 +0200 Subject: [PATCH 077/184] techmap: add dynamic cell type test --- tests/techmap/techmap_chtype.ys | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/techmap/techmap_chtype.ys diff --git a/tests/techmap/techmap_chtype.ys b/tests/techmap/techmap_chtype.ys new file mode 100644 index 000000000..7c3398420 --- /dev/null +++ b/tests/techmap/techmap_chtype.ys @@ -0,0 +1,33 @@ +read_verilog < Date: Wed, 27 Mar 2024 23:54:51 +0100 Subject: [PATCH 078/184] cellmatch: New pass --- passes/techmap/Makefile.inc | 1 + passes/techmap/cellmatch.cc | 340 ++++++++++++++++++++++++++++++++++++ 2 files changed, 341 insertions(+) create mode 100644 passes/techmap/cellmatch.cc diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 9d57e3d71..74813bca9 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -48,6 +48,7 @@ OBJS += passes/techmap/dfflegalize.o OBJS += passes/techmap/dffunmap.o OBJS += passes/techmap/flowmap.o OBJS += passes/techmap/extractinv.o +OBJS += passes/techmap/cellmatch.o endif ifeq ($(DISABLE_SPAWN),0) diff --git a/passes/techmap/cellmatch.cc b/passes/techmap/cellmatch.cc new file mode 100644 index 000000000..7c75418e3 --- /dev/null +++ b/passes/techmap/cellmatch.cc @@ -0,0 +1,340 @@ +#include "kernel/celltypes.h" +#include "kernel/register.h" +#include "kernel/rtlil.h" +#include "kernel/sigtools.h" +#include "kernel/utils.h" + +#include + +USING_YOSYS_NAMESPACE +YOSYS_NAMESPACE_BEGIN + +// return module's inputs in canonical order +SigSpec module_inputs(Module *m) +{ + SigSpec ret; + for (auto port : m->ports) { + Wire *w = m->wire(port); + if (!w->port_input) + continue; + if (w->width != 1) + log_error("Unsupported wide port (%s) of non-unit width found in module %s.\n", + log_id(w), log_id(m)); + ret.append(w); + } + return ret; +} + +// return module's outputs in canonical order +SigSpec module_outputs(Module *m) +{ + SigSpec ret; + for (auto port : m->ports) { + Wire *w = m->wire(port); + if (!w->port_output) + continue; + if (w->width != 1) + log_error("Unsupported wide port (%s) of non-unit width found in module %s.\n", + log_id(w), log_id(m)); + ret.append(w); + } + return ret; +} + +uint64_t permute_lut(uint64_t lut, const std::vector &varmap) +{ + int k = varmap.size(); + uint64_t ret = 0; + for (int j = 0; j < 1 << k; j++) { + int m = 0; + for (int l = 0; l < k; l++) + if (j & 1 << l) + m |= 1 << varmap[l]; + if (lut & 1 << m) + ret |= 1 << j; + } + return ret; +} + +uint64_t p_class(int k, uint64_t lut) +{ + std::vector map; + for (int j = 0; j < k; j++) + map.push_back(j); + + uint64_t repr = ~(uint64_t) 0; + std::vector repr_vars; + while (true) { + uint64_t perm = permute_lut(lut, map); + if (perm <= repr) { + repr = perm; + repr_vars = map; + } + if (!std::next_permutation(map.begin(), map.end())) + break; + } + return repr; +} + +bool derive_module_luts(Module *m, std::vector &luts) +{ + SigMap sigmap(m); + CellTypes ff_types; + ff_types.setup_stdcells_mem(); + + dict driver; + for (auto cell : m->selected_cells()) { + if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) + continue; + + if (ff_types.cell_known(cell->type)) { + log("Ignoring module '%s' which isn't purely combinational.\n", log_id(m)); + return false; + } + + if (!cell->type.in(ID($_NOT_), ID($_AND_))) + log_error("Unsupported cell in module '%s': %s of type %s\n", + log_id(m), log_id(cell), log_id(cell->type)); + + driver[sigmap(cell->getPort(ID::Y))] = cell; + } + + TopoSort sort; + for (auto cell : m->cells()) + if (cell->type.in(ID($_NOT_), ID($_AND_))) { + sort.node(cell); + SigSpec inputs = cell->type == ID($_AND_) + ? SigSpec({cell->getPort(ID::B), cell->getPort(ID::A)}) + : cell->getPort(ID::A); + for (auto bit : sigmap(inputs)) + if (driver.count(bit)) + sort.edge(driver.at(bit), cell); + } + + if (!sort.sort()) + log_error("Module %s contains combinational loops.\n", log_id(m)); + + dict states; + states[State::S0] = 0; + states[State::S1] = ~(uint64_t) 1; + + { + uint64_t sieves[6] = { + 0xaaaaaaaaaaaaaaaa, + 0xcccccccccccccccc, + 0xf0f0f0f0f0f0f0f0, + 0xff00ff00ff00ff00, + 0xffff0000ffff0000, + 0xffffffff00000000, + }; + + SigSpec inputs = sigmap(module_inputs(m)); + if (inputs.size() > 6) { + log_warning("Skipping module %s with more than 6 inputs bits.\n", log_id(m)); + return false; + } + + for (int i = 0; i < inputs.size(); i++) + states[inputs[i]] = sieves[i] & ((((uint64_t) 1) << (1 << inputs.size())) - 1); + } + + for (auto cell : sort.sorted) { + if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) + continue; + + if (cell->type == ID($_AND_)) { + SigSpec a = sigmap(cell->getPort(ID::A)); + SigSpec b = sigmap(cell->getPort(ID::B)); + if (!states.count(a) || !states.count(b)) + log_error("Cell %s in module %s sources an undriven wire!", + log_id(cell), log_id(m)); + states[sigmap(cell->getPort(ID::Y))] = \ + states.at(a) & states.at(b); + } else if (cell->type == ID($_NOT_)) { + SigSpec a = sigmap(cell->getPort(ID::A)); + if (!states.count(a)) + log_error("Cell %s in module %s sources an undriven wire!", + log_id(cell), log_id(m)); + states[sigmap(cell->getPort(ID::Y))] = ~states.at(a); + } else { + log_abort(); + } + } + + for (auto bit : module_outputs(m)) { + if (!states.count(sigmap(bit))) + log_error("Output port %s in module %s is undriven!", + log_signal(bit), log_id(m)); + luts.push_back(states.at(sigmap(bit))); + } + return true; +} + +struct CellmatchPass : Pass { + CellmatchPass() : Pass("cellmatch", "match cells to their targets in cell library") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" cellmatch -lib [module selection]\n"); + log("\n"); + log("This pass identifies functionally equivalent counterparts between each of the\n"); + log("selected modules and a module from the secondary design . For every such\n"); + log("correspondence found, a techmap rule is generated for mapping instances of the\n"); + log("former to instances of the latter. This techmap rule is saved in yet another\n"); + log("design called '$cellmatch_map', which is created if non-existent.\n"); + log("\n"); + log("This pass restricts itself to combinational modules which must be modeled with an\n"); + log("and-inverter graph. Run 'aigmap' first if necessary. Modules are functionally\n"); + log("equivalent as long as their truth tables are identical upto a permutation of\n"); + log("inputs and outputs. The number of inputs is limited to 6.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *d) override + { + log_header(d, "Executing CELLMATCH pass. (match cells)\n"); + + size_t argidx; + bool lut_attrs = false; + Design *lib = NULL; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-lut_attrs") { + // an undocumented debugging option + lut_attrs = true; + } else if (args[argidx] == "-lib" && argidx + 1 < args.size()) { + if (!saved_designs.count(args[++argidx])) + log_cmd_error("No design '%s' found!\n", args[argidx].c_str()); + lib = saved_designs.at(args[argidx]); + } else { + break; + } + } + extra_args(args, argidx, d); + + if (!lib && !lut_attrs) + log_cmd_error("Missing required -lib option.\n"); + + struct Target { + Module *module; + std::vector luts; + }; + + dict, std::vector> targets; + + if (lib) + for (auto m : lib->modules()) { + pool p_classes; + + // produce a fingerprint in p_classes + int ninputs = module_inputs(m).size(); + std::vector luts; + if (!derive_module_luts(m, luts)) + continue; + for (auto lut : luts) + p_classes.insert(p_class(ninputs, lut)); + + // save as a viable target + targets[p_classes].push_back(Target{m, luts}); + } + + auto r = saved_designs.emplace("$cellmatch_map", nullptr); + if (r.second) + r.first->second = new Design; + Design *map_design = r.first->second; + + for (auto m : d->selected_whole_modules_warn()) { + std::vector luts; + if (!derive_module_luts(m, luts)) + continue; + + SigSpec inputs = module_inputs(m); + SigSpec outputs = module_outputs(m); + + if (lut_attrs) { + int no = 0; + for (auto bit : outputs) { + log_assert(bit.is_wire()); + bit.wire->attributes[ID(p_class)] = p_class(inputs.size(), luts[no]); + bit.wire->attributes[ID(lut)] = luts[no++]; + } + } + + // fingerprint + pool p_classes; + for (auto lut : luts) + p_classes.insert(p_class(inputs.size(), lut)); + + for (auto target : targets[p_classes]) { + log_debug("Candidate %s for matching to %s\n", log_id(target.module), log_id(m)); + + SigSpec target_inputs = module_inputs(target.module); + SigSpec target_outputs = module_outputs(target.module); + + if (target_inputs.size() != inputs.size()) + continue; + + if (target_outputs.size() != outputs.size()) + continue; + + std::vector input_map; + for (int i = 0; i < inputs.size(); i++) + input_map.push_back(i); + + bool found_match = false; + while (!found_match) { + std::vector output_map; + for (int i = 0; i < outputs.size(); i++) + output_map.push_back(i); + + while (!found_match) { + int out_no = 0; + bool match = true; + for (auto lut : luts) { + if (permute_lut(target.luts[output_map[out_no++]], input_map) != lut) { + match = false; + break; + } + } + + if (match) { + log("Module %s matches %s\n", log_id(m), log_id(target.module)); + Module *map = map_design->addModule(stringf("\\_60_%s_%s", log_id(m), log_id(target.module))); + Cell *cell = map->addCell(ID::_TECHMAP_REPLACE_, target.module->name); + + map->attributes[ID(techmap_celltype)] = m->name.str(); + + for (int i = 0; i < outputs.size(); i++) { + log_assert(outputs[i].is_wire()); + Wire *w = map->addWire(outputs[i].wire->name, 1); + w->port_id = outputs[i].wire->port_id; + w->port_output = true; + log_assert(target_outputs[output_map[i]].is_wire()); + cell->setPort(target_outputs[output_map[i]].wire->name, w); + } + + for (int i = 0; i < inputs.size(); i++) { + log_assert(inputs[i].is_wire()); + Wire *w = map->addWire(inputs[i].wire->name, 1); + w->port_id = inputs[i].wire->port_id; + w->port_input = true; + log_assert(target_inputs[input_map[i]].is_wire()); + cell->setPort(target_inputs[input_map[i]].wire->name, w); + } + + map->fixup_ports(); + found_match = true; + } + + if (!std::next_permutation(output_map.begin(), output_map.end())) + break; + } + + if (!std::next_permutation(input_map.begin(), input_map.end())) + break; + } + } + } + } +} CellmatchPass; + +YOSYS_NAMESPACE_END From 6a9858cdad96322ddca73d50602ce643c82edc04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Sat, 13 Apr 2024 16:56:36 +0200 Subject: [PATCH 079/184] cellmatch: Delegate evaluation to `ConstEval` --- passes/techmap/cellmatch.cc | 103 ++++++++++-------------------------- 1 file changed, 28 insertions(+), 75 deletions(-) diff --git a/passes/techmap/cellmatch.cc b/passes/techmap/cellmatch.cc index 7c75418e3..9459c112f 100644 --- a/passes/techmap/cellmatch.cc +++ b/passes/techmap/cellmatch.cc @@ -2,6 +2,7 @@ #include "kernel/register.h" #include "kernel/rtlil.h" #include "kernel/sigtools.h" +#include "kernel/consteval.h" #include "kernel/utils.h" #include @@ -78,95 +79,48 @@ uint64_t p_class(int k, uint64_t lut) bool derive_module_luts(Module *m, std::vector &luts) { - SigMap sigmap(m); CellTypes ff_types; ff_types.setup_stdcells_mem(); - - dict driver; - for (auto cell : m->selected_cells()) { - if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) - continue; - + for (auto cell : m->cells()) { if (ff_types.cell_known(cell->type)) { log("Ignoring module '%s' which isn't purely combinational.\n", log_id(m)); return false; } - - if (!cell->type.in(ID($_NOT_), ID($_AND_))) - log_error("Unsupported cell in module '%s': %s of type %s\n", - log_id(m), log_id(cell), log_id(cell->type)); - - driver[sigmap(cell->getPort(ID::Y))] = cell; } - TopoSort sort; - for (auto cell : m->cells()) - if (cell->type.in(ID($_NOT_), ID($_AND_))) { - sort.node(cell); - SigSpec inputs = cell->type == ID($_AND_) - ? SigSpec({cell->getPort(ID::B), cell->getPort(ID::A)}) - : cell->getPort(ID::A); - for (auto bit : sigmap(inputs)) - if (driver.count(bit)) - sort.edge(driver.at(bit), cell); + SigSpec inputs = module_inputs(m); + SigSpec outputs = module_outputs(m); + int ninputs = inputs.size(), noutputs = outputs.size(); + + if (ninputs > 6) { + log_warning("Skipping module %s with more than 6 inputs bits.\n", log_id(m)); + return false; } - if (!sort.sort()) - log_error("Module %s contains combinational loops.\n", log_id(m)); + luts.clear(); + luts.resize(noutputs); - dict states; - states[State::S0] = 0; - states[State::S1] = ~(uint64_t) 1; + ConstEval ceval(m); + for (int i = 0; i < 1 << ninputs; i++) { + ceval.clear(); + for (int j = 0; j < ninputs; j++) + ceval.set(inputs[j], (i & (1 << j)) ? State::S1 : State::S0); + for (int j = 0; j < noutputs; j++) { + SigSpec bit = outputs[j]; - { - uint64_t sieves[6] = { - 0xaaaaaaaaaaaaaaaa, - 0xcccccccccccccccc, - 0xf0f0f0f0f0f0f0f0, - 0xff00ff00ff00ff00, - 0xffff0000ffff0000, - 0xffffffff00000000, - }; + if (!ceval.eval(bit)) { + log("Failed to evaluate output '%s' in module '%s'.\n", + log_signal(outputs[j]), log_id(m)); + return false; + } - SigSpec inputs = sigmap(module_inputs(m)); - if (inputs.size() > 6) { - log_warning("Skipping module %s with more than 6 inputs bits.\n", log_id(m)); - return false; - } + log_assert(ceval.eval(bit)); - for (int i = 0; i < inputs.size(); i++) - states[inputs[i]] = sieves[i] & ((((uint64_t) 1) << (1 << inputs.size())) - 1); - } - - for (auto cell : sort.sorted) { - if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) - continue; - - if (cell->type == ID($_AND_)) { - SigSpec a = sigmap(cell->getPort(ID::A)); - SigSpec b = sigmap(cell->getPort(ID::B)); - if (!states.count(a) || !states.count(b)) - log_error("Cell %s in module %s sources an undriven wire!", - log_id(cell), log_id(m)); - states[sigmap(cell->getPort(ID::Y))] = \ - states.at(a) & states.at(b); - } else if (cell->type == ID($_NOT_)) { - SigSpec a = sigmap(cell->getPort(ID::A)); - if (!states.count(a)) - log_error("Cell %s in module %s sources an undriven wire!", - log_id(cell), log_id(m)); - states[sigmap(cell->getPort(ID::Y))] = ~states.at(a); - } else { - log_abort(); + if (bit[0] == State::S1) + luts[j] |= 1 << i; } } - for (auto bit : module_outputs(m)) { - if (!states.count(sigmap(bit))) - log_error("Output port %s in module %s is undriven!", - log_signal(bit), log_id(m)); - luts.push_back(states.at(sigmap(bit))); - } return true; } @@ -184,10 +138,9 @@ struct CellmatchPass : Pass { log("former to instances of the latter. This techmap rule is saved in yet another\n"); log("design called '$cellmatch_map', which is created if non-existent.\n"); log("\n"); - log("This pass restricts itself to combinational modules which must be modeled with an\n"); - log("and-inverter graph. Run 'aigmap' first if necessary. Modules are functionally\n"); + log("This pass restricts itself to combinational modules. Modules are functionally\n"); log("equivalent as long as their truth tables are identical upto a permutation of\n"); - log("inputs and outputs. The number of inputs is limited to 6.\n"); + log("inputs and outputs. The supported number of inputs is limited to 6.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *d) override From c0e68dcc4d232542272d1ad436767175a6f04481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Sat, 13 Apr 2024 16:56:44 +0200 Subject: [PATCH 080/184] cellmatch: Add debug print --- passes/techmap/cellmatch.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/techmap/cellmatch.cc b/passes/techmap/cellmatch.cc index 9459c112f..5301cc99b 100644 --- a/passes/techmap/cellmatch.cc +++ b/passes/techmap/cellmatch.cc @@ -185,6 +185,8 @@ struct CellmatchPass : Pass { continue; for (auto lut : luts) p_classes.insert(p_class(ninputs, lut)); + + log_debug("Registered %s\n", log_id(m)); // save as a viable target targets[p_classes].push_back(Target{m, luts}); From 913bc87c4419303e32f4ca86ed437fe1e8ee015e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Sat, 13 Apr 2024 17:12:53 +0200 Subject: [PATCH 081/184] cellmatch: Add test --- tests/techmap/cellmatch.ys | 79 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/techmap/cellmatch.ys diff --git a/tests/techmap/cellmatch.ys b/tests/techmap/cellmatch.ys new file mode 100644 index 000000000..46960fc14 --- /dev/null +++ b/tests/techmap/cellmatch.ys @@ -0,0 +1,79 @@ +read_verilog < Date: Sat, 13 Apr 2024 17:20:32 +0200 Subject: [PATCH 082/184] cellmatch: Rename the special design to `$cellmatch` --- passes/techmap/cellmatch.cc | 4 ++-- tests/techmap/cellmatch.ys | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/techmap/cellmatch.cc b/passes/techmap/cellmatch.cc index 5301cc99b..d1da6babd 100644 --- a/passes/techmap/cellmatch.cc +++ b/passes/techmap/cellmatch.cc @@ -136,7 +136,7 @@ struct CellmatchPass : Pass { log("selected modules and a module from the secondary design . For every such\n"); log("correspondence found, a techmap rule is generated for mapping instances of the\n"); log("former to instances of the latter. This techmap rule is saved in yet another\n"); - log("design called '$cellmatch_map', which is created if non-existent.\n"); + log("design called '$cellmatch', which is created if non-existent.\n"); log("\n"); log("This pass restricts itself to combinational modules. Modules are functionally\n"); log("equivalent as long as their truth tables are identical upto a permutation of\n"); @@ -192,7 +192,7 @@ struct CellmatchPass : Pass { targets[p_classes].push_back(Target{m, luts}); } - auto r = saved_designs.emplace("$cellmatch_map", nullptr); + auto r = saved_designs.emplace("$cellmatch", nullptr); if (r.second) r.first->second = new Design; Design *map_design = r.first->second; diff --git a/tests/techmap/cellmatch.ys b/tests/techmap/cellmatch.ys index 46960fc14..bea2f598d 100644 --- a/tests/techmap/cellmatch.ys +++ b/tests/techmap/cellmatch.ys @@ -61,7 +61,7 @@ prep cellmatch -lib gatelib FA A:gate design -save gold -techmap -map %$cellmatch_map +techmap -map %$cellmatch design -save gate select -assert-none ripple_carry/t:FA From e939182e68edc26b4267f011f644067e29c7c25a Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 3 May 2024 12:11:55 +0200 Subject: [PATCH 083/184] cellmatch: add comments --- passes/techmap/cellmatch.cc | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/passes/techmap/cellmatch.cc b/passes/techmap/cellmatch.cc index d1da6babd..a21a4fbad 100644 --- a/passes/techmap/cellmatch.cc +++ b/passes/techmap/cellmatch.cc @@ -42,10 +42,16 @@ SigSpec module_outputs(Module *m) return ret; } +// Permute the inputs of a single-output k-LUT according to varmap uint64_t permute_lut(uint64_t lut, const std::vector &varmap) { int k = varmap.size(); uint64_t ret = 0; + // Index j iterates over all bits in lut. + // When (j & 1 << n) is true, + // (lut & 1 << j) represents an output value where input var n is set. + // We use this fact to permute the LUT such that + // every variable n is remapped to varmap[n]. for (int j = 0; j < 1 << k; j++) { int m = 0; for (int l = 0; l < k; l++) @@ -57,6 +63,10 @@ uint64_t permute_lut(uint64_t lut, const std::vector &varmap) return ret; } +// Find the LUT with the minimum integer representation +// such that it is a permutation of the given lut. +// The resulting LUT becomes the "fingerprint" of the "permutation class". +// This function checks all possible input permutations. uint64_t p_class(int k, uint64_t lut) { std::vector map; @@ -77,6 +87,9 @@ uint64_t p_class(int k, uint64_t lut) return repr; } +// Represent module m as N single-output k-LUTs +// where k is the number of module inputs, +// and N is the number of module outputs. bool derive_module_luts(Module *m, std::vector &luts) { CellTypes ff_types; @@ -185,7 +198,7 @@ struct CellmatchPass : Pass { continue; for (auto lut : luts) p_classes.insert(p_class(ninputs, lut)); - + log_debug("Registered %s\n", log_id(m)); // save as a viable target @@ -210,7 +223,7 @@ struct CellmatchPass : Pass { for (auto bit : outputs) { log_assert(bit.is_wire()); bit.wire->attributes[ID(p_class)] = p_class(inputs.size(), luts[no]); - bit.wire->attributes[ID(lut)] = luts[no++]; + bit.wire->attributes[ID(lut)] = luts[no++]; } } @@ -236,11 +249,13 @@ struct CellmatchPass : Pass { input_map.push_back(i); bool found_match = false; + // For each input_map while (!found_match) { std::vector output_map; for (int i = 0; i < outputs.size(); i++) output_map.push_back(i); + // For each output_map while (!found_match) { int out_no = 0; bool match = true; @@ -253,6 +268,8 @@ struct CellmatchPass : Pass { if (match) { log("Module %s matches %s\n", log_id(m), log_id(target.module)); + // Add target.module to map_design ("$cellmatch") + // as a techmap rule to match m and replace it with target.module Module *map = map_design->addModule(stringf("\\_60_%s_%s", log_id(m), log_id(target.module))); Cell *cell = map->addCell(ID::_TECHMAP_REPLACE_, target.module->name); @@ -281,7 +298,7 @@ struct CellmatchPass : Pass { } if (!std::next_permutation(output_map.begin(), output_map.end())) - break; + break; } if (!std::next_permutation(input_map.begin(), input_map.end())) From 0f9ee20ea2c9b377f9b28b862f77b197e6485e00 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 4 May 2024 00:16:00 +0000 Subject: [PATCH 084/184] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2dbce272d..56efaf5eb 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ LIBS += -lrt endif endif -YOSYS_VER := 0.40+45 +YOSYS_VER := 0.40+50 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From bb0be8c7a20335f8e03597cfcf052609f8a1f4a4 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 4 May 2024 16:51:29 +1200 Subject: [PATCH 085/184] Docs: Set release to YOSYS_VER If building from read the docs, and the current build is "latest", add `-dev` to the version string. Requires `YOSYS_VER` to be exported by .readthedocs.yaml. --- docs/source/conf.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index 29d36d9c4..aed3fddff 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -63,6 +63,14 @@ latex_elements = { extensions.append('sphinx.ext.todo') todo_include_todos = False +# attempt to get version +env_yosys_ver = os.getenv("YOSYS_VER") +if env_yosys_ver: + if os.getenv("READTHEDOCS") and os.getenv("READTHEDOCS_VERSION") == "latest": + release = env_yosys_ver + "-dev" + else: + release = env_yosys_ver + # custom cmd-ref parsing/linking sys.path += [os.path.dirname(__file__) + "/../"] extensions.append('util.cmdref') From fe27240b3a9c0be98dd16b3fc27cef61ddb50946 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 4 May 2024 16:51:38 +1200 Subject: [PATCH 086/184] Makefile: Export YOSYS_VER --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 56efaf5eb..2e93bcc8d 100644 --- a/Makefile +++ b/Makefile @@ -143,6 +143,7 @@ endif endif YOSYS_VER := 0.40+50 +export YOSYS_VER # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 6eb49ee9e830545e212f9aefe90d5bd130afa7a4 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 7 May 2024 10:23:22 +1200 Subject: [PATCH 087/184] Makefile: Export YOSYS_VER only for make docs --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2e93bcc8d..6711751b6 100644 --- a/Makefile +++ b/Makefile @@ -143,7 +143,6 @@ endif endif YOSYS_VER := 0.40+50 -export YOSYS_VER # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -1013,7 +1012,7 @@ docs/reqs: DOC_TARGET ?= html docs: docs/source/cmd/abc.rst docs/gen_examples docs/gen_images docs/guidelines docs/usage docs/reqs - $(Q) $(MAKE) -C docs $(DOC_TARGET) + $(Q) YOSYS_VER=$(YOSYS_VER) $(MAKE) -C docs $(DOC_TARGET) clean: rm -rf share From b4034a881e0cf476bbdc19e984a9762bb260ad39 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 7 May 2024 15:35:25 +0200 Subject: [PATCH 088/184] Keep docs version in conf.py --- Makefile | 2 +- docs/source/conf.py | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 6711751b6..56efaf5eb 100644 --- a/Makefile +++ b/Makefile @@ -1012,7 +1012,7 @@ docs/reqs: DOC_TARGET ?= html docs: docs/source/cmd/abc.rst docs/gen_examples docs/gen_images docs/guidelines docs/usage docs/reqs - $(Q) YOSYS_VER=$(YOSYS_VER) $(MAKE) -C docs $(DOC_TARGET) + $(Q) $(MAKE) -C docs $(DOC_TARGET) clean: rm -rf share diff --git a/docs/source/conf.py b/docs/source/conf.py index aed3fddff..4e46cfad1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -4,7 +4,8 @@ import os project = 'YosysHQ Yosys' author = 'YosysHQ GmbH' -copyright ='2022 YosysHQ GmbH' +copyright ='2024 YosysHQ GmbH' +yosys_ver = "0.40" # select HTML theme html_theme = 'furo' @@ -46,12 +47,18 @@ extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.bibtex'] autosectionlabel_prefix_document = True autosectionlabel_maxdepth = 1 +# set version +if os.getenv("READTHEDOCS") and os.getenv("READTHEDOCS_VERSION") == "latest": + release = yosys_ver + "-dev" +else: + release = yosys_ver + # assign figure numbers numfig = True bibtex_bibfiles = ['literature.bib'] - latex_elements = { + 'releasename': ' ', 'preamble': r''' \usepackage{lmodern} \usepackage{comment} @@ -63,14 +70,6 @@ latex_elements = { extensions.append('sphinx.ext.todo') todo_include_todos = False -# attempt to get version -env_yosys_ver = os.getenv("YOSYS_VER") -if env_yosys_ver: - if os.getenv("READTHEDOCS") and os.getenv("READTHEDOCS_VERSION") == "latest": - release = env_yosys_ver + "-dev" - else: - release = env_yosys_ver - # custom cmd-ref parsing/linking sys.path += [os.path.dirname(__file__) + "/../"] extensions.append('util.cmdref') From 71f2540cd840046499e1dd84c76ea64c437140d3 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 7 May 2024 15:55:52 +0200 Subject: [PATCH 089/184] docs conf.py change Release -> Version --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4e46cfad1..182d033f8 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -58,7 +58,7 @@ numfig = True bibtex_bibfiles = ['literature.bib'] latex_elements = { - 'releasename': ' ', + 'releasename': 'Version', 'preamble': r''' \usepackage{lmodern} \usepackage{comment} From a52088b6af5c4467835de173d83a00645546eddf Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 7 May 2024 17:57:37 +0200 Subject: [PATCH 090/184] smtbmc: Improvements for --incremental and .yw fixes This extends the experimental incremental JSON API to allow arbitrary smtlib subexpressions, defining smtlib constants and to allow access of signals by their .yw path. It also fixes a bug during .yw writing where values would be re-emitted in later cycles if they have no newer defined value and a potential crash when using --track-assumes. --- backends/smt2/smtbmc.py | 213 +++++++++++++++++----------- backends/smt2/smtbmc_incremental.py | 147 +++++++++++++++++-- backends/smt2/smtio.py | 21 ++- 3 files changed, 284 insertions(+), 97 deletions(-) diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index e6b4088db..995a714c9 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -199,7 +199,6 @@ def help(): --minimize-assumes when using --track-assumes, solve for a minimal set of sufficient assumptions. - """ + so.helpmsg()) def usage(): @@ -670,18 +669,12 @@ if aimfile is not None: ywfile_hierwitness_cache = None -def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False): +def ywfile_hierwitness(): global ywfile_hierwitness_cache - if map_steps is None: - map_steps = {} + if ywfile_hierwitness_cache is None: + ywfile_hierwitness = smt.hierwitness(topmod, allregs=True, blackbox=True) - with open(inywfile, "r") as f: - inyw = ReadWitness(f) - - if ywfile_hierwitness_cache is None: - ywfile_hierwitness_cache = smt.hierwitness(topmod, allregs=True, blackbox=True) - - inits, seqs, clocks, mems = ywfile_hierwitness_cache + inits, seqs, clocks, mems = ywfile_hierwitness smt_wires = defaultdict(list) smt_mems = defaultdict(list) @@ -692,9 +685,128 @@ def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False): for mem in mems: smt_mems[mem["path"]].append(mem) - addr_re = re.compile(r'\\\[[0-9]+\]$') - bits_re = re.compile(r'[01?]*$') + ywfile_hierwitness_cache = inits, seqs, clocks, mems, smt_wires, smt_mems + return ywfile_hierwitness_cache + +def_bits_re = re.compile(r'([01]+)') + +def smt_extract_mask(smt_expr, mask): + chunks = [] + def_bits = '' + + mask_index_order = mask[::-1] + + for matched in def_bits_re.finditer(mask_index_order): + chunks.append(matched.span()) + def_bits += matched[0] + + if not chunks: + return + + if len(chunks) == 1: + start, end = chunks[0] + if start == 0 and end == len(mask_index_order): + combined_chunks = smt_expr + else: + combined_chunks = '((_ extract %d %d) %s)' % (end - 1, start, smt_expr) + else: + combined_chunks = '(let ((x %s)) (concat %s))' % (smt_expr, ' '.join( + '((_ extract %d %d) x)' % (end - 1, start) + for start, end in reversed(chunks) + )) + + return combined_chunks, ''.join(mask_index_order[start:end] for start, end in chunks)[::-1] + +def smt_concat(exprs): + if not exprs: + return "" + if len(exprs) == 1: + return exprs[1] + return "(concat %s)" % ' '.join(exprs) + +def ywfile_signal(sig, step, mask=None): + assert sig.width > 0 + + inits, seqs, clocks, mems, smt_wires, smt_mems = ywfile_hierwitness() + sig_end = sig.offset + sig.width + + output = [] + + if sig.path in smt_wires: + for wire in smt_wires[sig.path]: + width, offset = wire["width"], wire["offset"] + + smt_bool = smt.net_width(topmod, wire["smtpath"]) == 1 + + offset = max(offset, 0) + + end = width + offset + common_offset = max(sig.offset, offset) + common_end = min(sig_end, end) + if common_end <= common_offset: + continue + + smt_expr = smt.witness_net_expr(topmod, f"s{step}", wire) + + if not smt_bool: + slice_high = common_end - offset - 1 + slice_low = common_offset - offset + smt_expr = "((_ extract %d %d) %s)" % (slice_high, slice_low, smt_expr) + else: + smt_expr = "(ite %s #b1 #b0)" % smt_expr + + output.append(((common_offset - sig.offset), (common_end - sig.offset), smt_expr)) + + if sig.memory_path: + if sig.memory_path in smt_mems: + for mem in smt_mems[sig.memory_path]: + width, size, bv = mem["width"], mem["size"], mem["statebv"] + + smt_expr = smt.net_expr(topmod, f"s{step}", mem["smtpath"]) + + if bv: + word_low = sig.memory_addr * width + word_high = word_low + width - 1 + smt_expr = "((_ extract %d %d) %s)" % (word_high, word_low, smt_expr) + else: + addr_width = (size - 1).bit_length() + addr_bits = f"{sig.memory_addr:0{addr_width}b}" + smt_expr = "(select %s #b%s )" % (smt_expr, addr_bits) + + if sig.width < width: + slice_high = sig.offset + sig.width - 1 + smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr) + + output.append((0, sig.width, smt_expr)) + + output.sort() + + output = [chunk for chunk in output if chunk[0] != chunk[1]] + + pos = 0 + + for start, end, smt_expr in output: + assert start == pos + pos = end + + assert pos == sig.width + + if len(output) == 1: + return output[0][-1] + return smt_concat(smt_expr for start, end, smt_expr in reversed(output)) + +def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False): + global ywfile_hierwitness_cache + if map_steps is None: + map_steps = {} + + with open(inywfile, "r") as f: + inyw = ReadWitness(f) + + inits, seqs, clocks, mems, smt_wires, smt_mems = ywfile_hierwitness() + + bits_re = re.compile(r'[01?]*$') max_t = -1 for t, step in inyw.steps(): @@ -706,77 +818,14 @@ def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False): if not bits_re.match(bits): raise ValueError("unsupported bit value in Yosys witness file") - sig_end = sig.offset + len(bits) - if sig.path in smt_wires: - for wire in smt_wires[sig.path]: - width, offset = wire["width"], wire["offset"] + smt_expr = ywfile_signal(sig, map_steps.get(t, t)) - smt_bool = smt.net_width(topmod, wire["smtpath"]) == 1 + smt_expr, bits = smt_extract_mask(smt_expr, bits) - offset = max(offset, 0) + smt_constr = "(= %s #b%s)" % (smt_expr, bits) + constr_assumes[t].append((inywfile, smt_constr)) - end = width + offset - common_offset = max(sig.offset, offset) - common_end = min(sig_end, end) - if common_end <= common_offset: - continue - - smt_expr = smt.witness_net_expr(topmod, f"s{map_steps.get(t, t)}", wire) - - if not smt_bool: - slice_high = common_end - offset - 1 - slice_low = common_offset - offset - smt_expr = "((_ extract %d %d) %s)" % (slice_high, slice_low, smt_expr) - - bit_slice = bits[len(bits) - (common_end - sig.offset):len(bits) - (common_offset - sig.offset)] - - if bit_slice.count("?") == len(bit_slice): - continue - - if smt_bool: - assert width == 1 - smt_constr = "(= %s %s)" % (smt_expr, "true" if bit_slice == "1" else "false") - else: - if "?" in bit_slice: - mask = bit_slice.replace("0", "1").replace("?", "0") - bit_slice = bit_slice.replace("?", "0") - smt_expr = "(bvand %s #b%s)" % (smt_expr, mask) - - smt_constr = "(= %s #b%s)" % (smt_expr, bit_slice) - - constr_assumes[t].append((inywfile, smt_constr)) - - if sig.memory_path: - if sig.memory_path in smt_mems: - for mem in smt_mems[sig.memory_path]: - width, size, bv = mem["width"], mem["size"], mem["statebv"] - - smt_expr = smt.net_expr(topmod, f"s{map_steps.get(t, t)}", mem["smtpath"]) - - if bv: - word_low = sig.memory_addr * width - word_high = word_low + width - 1 - smt_expr = "((_ extract %d %d) %s)" % (word_high, word_low, smt_expr) - else: - addr_width = (size - 1).bit_length() - addr_bits = f"{sig.memory_addr:0{addr_width}b}" - smt_expr = "(select %s #b%s )" % (smt_expr, addr_bits) - - if len(bits) < width: - slice_high = sig.offset + len(bits) - 1 - smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr) - - bit_slice = bits - - if "?" in bit_slice: - mask = bit_slice.replace("0", "1").replace("?", "0") - bit_slice = bit_slice.replace("?", "0") - smt_expr = "(bvand %s #b%s)" % (smt_expr, mask) - - smt_constr = "(= %s #b%s)" % (smt_expr, bit_slice) - constr_assumes[t].append((inywfile, smt_constr)) max_t = t - return max_t if inywfile is not None: @@ -1367,11 +1416,11 @@ def write_yw_trace(steps, index, allregs=False, filename=None): exprs.extend(smt.witness_net_expr(topmod, f"s{k}", sig) for sig in sigs) - all_sigs.append(sigs) + all_sigs.append((step_values, sigs)) bvs = iter(smt.get_list(exprs)) - for sigs in all_sigs: + for (step_values, sigs) in all_sigs: for sig in sigs: value = smt.bv2bin(next(bvs)) step_values[sig["sig"]] = value diff --git a/backends/smt2/smtbmc_incremental.py b/backends/smt2/smtbmc_incremental.py index f43e878f3..0bd280b4a 100644 --- a/backends/smt2/smtbmc_incremental.py +++ b/backends/smt2/smtbmc_incremental.py @@ -1,7 +1,7 @@ from collections import defaultdict import json import typing -from functools import partial +import ywio if typing.TYPE_CHECKING: import smtbmc @@ -34,6 +34,7 @@ class Incremental: self._witness_index = None self._yw_constraints = {} + self._define_sorts = {} def setup(self): generic_assert_map = smtbmc.get_assert_map( @@ -175,11 +176,7 @@ class Incremental: if len(expr) == 1: smt_out.push({"and": "true", "or": "false"}[expr[0]]) elif len(expr) == 2: - arg_sort = self.expr(expr[1], smt_out) - if arg_sort != "Bool": - raise InteractiveError( - f"arguments of {json.dumps(expr[0])} must have sort Bool" - ) + self.expr(expr[1], smt_out, required_sort="Bool") else: sep = f"({expr[0]} " for arg in expr[1:]: @@ -189,7 +186,51 @@ class Incremental: smt_out.append(")") return "Bool" + def expr_bv_binop(self, expr, smt_out): + self.expr_arg_len(expr, 2) + + smt_out.append(f"({expr[0]} ") + arg_sort = self.expr(expr[1], smt_out, required_sort=("BitVec", None)) + smt_out.append(" ") + self.expr(expr[2], smt_out, required_sort=arg_sort) + smt_out.append(")") + return arg_sort + + def expr_extract(self, expr, smt_out): + self.expr_arg_len(expr, 3) + + hi = expr[1] + lo = expr[2] + + smt_out.append(f"((_ extract {hi} {lo}) ") + + arg_sort = self.expr(expr[3], smt_out, required_sort=("BitVec", None)) + smt_out.append(")") + + if not (isinstance(hi, int) and 0 <= hi < arg_sort[1]): + raise InteractiveError( + f"high bit index must be 0 <= index < {arg_sort[1]}, is {hi!r}" + ) + if not (isinstance(lo, int) and 0 <= lo <= hi): + raise InteractiveError( + f"low bit index must be 0 <= index < {hi}, is {lo!r}" + ) + + return "BitVec", hi - lo + 1 + + def expr_bv(self, expr, smt_out): + self.expr_arg_len(expr, 1) + + arg = expr[1] + if not isinstance(arg, str) or arg.count("0") + arg.count("1") != len(arg): + raise InteractiveError("bv argument must contain only 0 or 1 bits") + + smt_out.append("#b" + arg) + + return "BitVec", len(arg) + def expr_yw(self, expr, smt_out): + self.expr_arg_len(expr, 1, 2) if len(expr) == 2: name = None step = expr[1] @@ -219,6 +260,40 @@ class Incremental: return "Bool" + def expr_yw_sig(self, expr, smt_out): + self.expr_arg_len(expr, 3, 4) + + step = expr[1] + path = expr[2] + offset = expr[3] + width = expr[4] if len(expr) == 5 else 1 + + if not isinstance(offset, int) or offset < 0: + raise InteractiveError( + f"offset must be a non-negative integer, got {json.dumps(offset)}" + ) + + if not isinstance(width, int) or width <= 0: + raise InteractiveError( + f"width must be a positive integer, got {json.dumps(width)}" + ) + + if not isinstance(path, list) or not all(isinstance(s, str) for s in path): + raise InteractiveError( + f"path must be a string list, got {json.dumps(path)}" + ) + + if step not in self.state_set: + raise InteractiveError(f"step {step} not declared") + + smt_expr = smtbmc.ywfile_signal( + ywio.WitnessSig(path=path, offset=offset, width=width), step + ) + + smt_out.append(smt_expr) + + return "BitVec", width + def expr_smtlib(self, expr, smt_out): self.expr_arg_len(expr, 2) @@ -231,10 +306,15 @@ class Incremental: f"got {json.dumps(smtlib_expr)}" ) - if not isinstance(sort, str): - raise InteractiveError( - f"raw SMT-LIB sort has to be a string, got {json.dumps(sort)}" - ) + if ( + isinstance(sort, list) + and len(sort) == 2 + and sort[0] == "BitVec" + and (sort[1] is None or isinstance(sort[1], int)) + ): + sort = tuple(sort) + elif not isinstance(sort, str): + raise InteractiveError(f"unsupported raw SMT-LIB sort {json.dumps(sort)}") smt_out.append(smtlib_expr) return sort @@ -258,6 +338,14 @@ class Incremental: return sort + def expr_def(self, expr, smt_out): + self.expr_arg_len(expr, 1) + sort = self._define_sorts.get(expr[1]) + if sort is None: + raise InteractiveError(f"unknown definition {json.dumps(expr)}") + smt_out.append(expr[1]) + return sort + expr_handlers = { "step": expr_step, "cell": expr_cell, @@ -270,8 +358,15 @@ class Incremental: "not": expr_not, "and": expr_andor, "or": expr_andor, + "bv": expr_bv, + "bvand": expr_bv_binop, + "bvor": expr_bv_binop, + "bvxor": expr_bv_binop, + "extract": expr_extract, + "def": expr_def, "=": expr_eq, "yw": expr_yw, + "yw_sig": expr_yw_sig, "smtlib": expr_smtlib, "!": expr_label, } @@ -305,10 +400,13 @@ class Incremental: raise InteractiveError(f"unknown expression {json.dumps(expr[0])}") def expr_smt(self, expr, required_sort): + return self.expr_smt_and_sort(expr, required_sort)[0] + + def expr_smt_and_sort(self, expr, required_sort=None): smt_out = [] - self.expr(expr, smt_out, required_sort=required_sort) + output_sort = self.expr(expr, smt_out, required_sort=required_sort) out = "".join(smt_out) - return out + return out, output_sort def cmd_new_step(self, cmd): step = self.arg_step(cmd, declare=True) @@ -338,7 +436,6 @@ class Incremental: expr = cmd.get("expr") key = cmd.get("key") - key = mkkey(key) result = smtbmc.smt.smt2_assumptions.pop(key, None) @@ -348,7 +445,7 @@ class Incremental: return result def cmd_get_unsat_assumptions(self, cmd): - return smtbmc.smt.get_unsat_assumptions(minimize=bool(cmd.get('minimize'))) + return smtbmc.smt.get_unsat_assumptions(minimize=bool(cmd.get("minimize"))) def cmd_push(self, cmd): smtbmc.smt_push() @@ -370,6 +467,27 @@ class Incremental: if response: return smtbmc.smt.read() + def cmd_define(self, cmd): + expr = cmd.get("expr") + if expr is None: + raise InteractiveError("'define' copmmand requires 'expr' parameter") + + expr, sort = self.expr_smt_and_sort(expr) + + if isinstance(sort, tuple) and sort[0] == "module": + raise InteractiveError("'define' does not support module sorts") + + define_name = f"|inc def {len(self._define_sorts)}|" + + self._define_sorts[define_name] = sort + + if isinstance(sort, tuple): + sort = f"(_ {' '.join(map(str, sort))})" + + smtbmc.smt.write(f"(define-const {define_name} {sort} {expr})") + + return {"name": define_name} + def cmd_design_hierwitness(self, cmd=None): allregs = (cmd is None) or bool(cmd.get("allreges", False)) if self._cached_hierwitness[allregs] is not None: @@ -451,6 +569,7 @@ class Incremental: "pop": cmd_pop, "check": cmd_check, "smtlib": cmd_smtlib, + "define": cmd_define, "design_hierwitness": cmd_design_hierwitness, "write_yw_trace": cmd_write_yw_trace, "read_yw_trace": cmd_read_yw_trace, diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index e32f43c60..5fc3ab5a4 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -160,6 +160,7 @@ class SmtIo: self.noincr = opts.noincr self.info_stmts = opts.info_stmts self.nocomments = opts.nocomments + self.smt2_options.update(opts.smt2_options) else: self.solver = "yices" @@ -959,6 +960,8 @@ class SmtIo: return int(self.bv2bin(v), 2) def get_raw_unsat_assumptions(self): + if not self.smt2_assumptions: + return [] self.write("(get-unsat-assumptions)") exprs = set(self.unparse(part) for part in self.parse(self.read())) unsat_assumptions = [] @@ -973,6 +976,10 @@ class SmtIo: def get_unsat_assumptions(self, minimize=False): if not minimize: return self.get_raw_unsat_assumptions() + orig_assumptions = self.smt2_assumptions + + self.smt2_assumptions = dict(orig_assumptions) + required_assumptions = {} while True: @@ -998,6 +1005,7 @@ class SmtIo: required_assumptions[candidate_key] = candidate_assume if candidate_assumptions is not None: + self.smt2_assumptions = orig_assumptions return list(required_assumptions) def get(self, expr): @@ -1146,7 +1154,7 @@ class SmtIo: class SmtOpts: def __init__(self): self.shortopts = "s:S:v" - self.longopts = ["unroll", "noincr", "noprogress", "timeout=", "dump-smt2=", "logic=", "dummy=", "info=", "nocomments"] + self.longopts = ["unroll", "noincr", "noprogress", "timeout=", "dump-smt2=", "logic=", "dummy=", "info=", "nocomments", "smt2-option="] self.solver = "yices" self.solver_opts = list() self.debug_print = False @@ -1159,6 +1167,7 @@ class SmtOpts: self.logic = None self.info_stmts = list() self.nocomments = False + self.smt2_options = {} def handle(self, o, a): if o == "-s": @@ -1185,6 +1194,13 @@ class SmtOpts: self.info_stmts.append(a) elif o == "--nocomments": self.nocomments = True + elif o == "--smt2-option": + args = a.split('=', 1) + if len(args) != 2: + print("--smt2-option expects an