From 2ef2aa997cbe75732535946b25c35dcb3fe5eec4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 09:07:53 -0700 Subject: read_aiger to not require clk_name for latches, plus debug --- frontends/aiger/aigerparse.cc | 58 +++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 21 deletions(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index d378a07b7..281e1cc9d 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -495,8 +495,7 @@ void AigerReader::parse_aiger_ascii() // Parse latches RTLIL::Wire *clk_wire = nullptr; - if (L > 0) { - log_assert(clk_name != ""); + if (L > 0 && !clk_name.empty()) { clk_wire = module->wire(clk_name); log_assert(!clk_wire); log_debug("Creating %s\n", clk_name.c_str()); @@ -512,7 +511,10 @@ void AigerReader::parse_aiger_ascii() RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); - module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire); + if (clk_wire) + module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire); + else + module->addFfGate(NEW_ID, d_wire, q_wire); // Reset logic is optional in AIGER 1.9 if (f.peek() == ' ') { @@ -620,8 +622,7 @@ void AigerReader::parse_aiger_binary() // Parse latches RTLIL::Wire *clk_wire = nullptr; - if (L > 0) { - log_assert(clk_name != ""); + if (L > 0 && !clk_name.empty()) { clk_wire = module->wire(clk_name); log_assert(!clk_wire); log_debug("Creating %s\n", clk_name.c_str()); @@ -637,7 +638,10 @@ void AigerReader::parse_aiger_binary() RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); - module->addDff(NEW_ID, clk_wire, d_wire, q_wire); + if (clk_wire) + module->addDff(NEW_ID, clk_wire, d_wire, q_wire); + else + module->addFf(NEW_ID, d_wire, q_wire); // Reset logic is optional in AIGER 1.9 if (f.peek() == ' ') { @@ -731,7 +735,14 @@ void AigerReader::post_process() RTLIL::Module* box_module = design->module(cell->type); log_assert(box_module); - if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) { + RTLIL::Module* flop_module = nullptr; + if (box_module->attributes.count("\\abc_flop")) { + log_assert(flop_count < flopNum); + log_assert(box_module->name.begins_with("$__ABC_")); + flop_module = design->module("\\" + box_module->name.substr(7)); + log_assert(flop_module); + } + else if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) { RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr; RTLIL::Wire* last_in = nullptr, *last_out = nullptr; for (const auto &port_name : box_module->ports) { @@ -766,39 +777,36 @@ void AigerReader::post_process() } } - bool flop = box_module->attributes.count("\\abc_flop"); - log_assert(!flop || flop_count < flopNum); - // NB: Assume box_module->ports are sorted alphabetically // (as RTLIL::Module::fixup_ports() would do) for (auto port_name : box_module->ports) { - RTLIL::Wire* w = box_module->wire(port_name); - log_assert(w); + RTLIL::Wire* port = box_module->wire(port_name); + log_assert(port); RTLIL::SigSpec rhs; RTLIL::Wire* wire = nullptr; - for (int i = 0; i < GetSize(w); i++) { - if (w->port_input) { + for (int i = 0; i < GetSize(port); i++) { + if (port->port_input) { log_assert(co_count < outputs.size()); wire = outputs[co_count++]; log_assert(wire); log_assert(wire->port_output); wire->port_output = false; - if (flop && w->attributes.count("\\abc_flop_d")) { + if (flop_module && port->attributes.count("\\abc_flop_d")) { RTLIL::Wire* d = outputs[outputs.size() - flopNum + flop_count]; log_assert(d); log_assert(d->port_output); d->port_output = false; } } - if (w->port_output) { + if (port->port_output) { log_assert((piNum + ci_count) < inputs.size()); wire = inputs[piNum + ci_count++]; log_assert(wire); log_assert(wire->port_input); wire->port_input = false; - if (flop && w->attributes.count("\\abc_flop_q")) { + if (flop_module && port->attributes.count("\\abc_flop_q")) { wire = inputs[piNum - flopNum + flop_count]; log_assert(wire); log_assert(wire->port_input); @@ -807,10 +815,14 @@ void AigerReader::post_process() } rhs.append(wire); } - cell->setPort(port_name, rhs); + if (!flop_module || !port->attributes.count("\\abc_discard")) + cell->setPort(port_name, rhs); } - if (flop) flop_count++; + if (flop_module) { + flop_count++; + cell->type = flop_module->name; + } } dict wideports_cache; @@ -826,6 +838,7 @@ void AigerReader::post_process() RTLIL::Wire* wire = inputs[variable]; log_assert(wire); log_assert(wire->port_input); + log_debug("Renaming input %s", log_id(wire)); if (index == 0) { // Cope with the fact that a CI might be identical @@ -852,12 +865,14 @@ void AigerReader::post_process() wire->port_input = false; } } + log_debug(" -> %s\n", log_id(wire)); } else if (type == "output") { log_assert(static_cast(variable + co_count) < outputs.size()); RTLIL::Wire* wire = outputs[variable + co_count]; log_assert(wire); log_assert(wire->port_output); + log_debug("Renaming output %s", log_id(wire)); if (index == 0) { // Cope with the fact that a CO might be identical @@ -904,6 +919,7 @@ void AigerReader::post_process() wire->port_output = false; } } + log_debug(" -> %s\n", log_id(wire)); } else if (type == "box") { RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable)); @@ -1009,8 +1025,8 @@ struct AigerFrontend : public Frontend { log(" Name of module to be created (default: )\n"); log("\n"); log(" -clk_name \n"); - log(" AIGER latches to be transformed into posedge DFFs clocked by wire of"); - log(" this name (default: clk)\n"); + log(" If specified, AIGER latches to be transformed into $_DFF_P_ cells\n" + log(" clocked by wire of this name. Otherwise, $_FF_ cells will be used.\n"); log("\n"); log(" -map \n"); log(" read file with port and latch symbols\n"); -- cgit v1.2.3 From 7a3c403ba0e411c990be59da44e1decb6aafc8f8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 09:10:01 -0700 Subject: Missing close bracket --- frontends/aiger/aigerparse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 281e1cc9d..d0d2ffdba 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -1025,7 +1025,7 @@ struct AigerFrontend : public Frontend { log(" Name of module to be created (default: )\n"); log("\n"); log(" -clk_name \n"); - log(" If specified, AIGER latches to be transformed into $_DFF_P_ cells\n" + log(" If specified, AIGER latches to be transformed into $_DFF_P_ cells\n"); log(" clocked by wire of this name. Otherwise, $_FF_ cells will be used.\n"); log("\n"); log(" -map \n"); -- cgit v1.2.3 From b706ae82de2fa82b68c327740820c03cc203a217 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 12:42:18 -0700 Subject: Fix log_debug messages --- frontends/aiger/aigerparse.cc | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index d0d2ffdba..833c0023b 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -429,6 +429,7 @@ void AigerReader::parse_xaiger() else if (c == 'r') { uint32_t dataSize = parse_xaiger_literal(f); flopNum = parse_xaiger_literal(f); + log_debug("flopNum: %u\n", flopNum); log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); f.ignore(flopNum * sizeof(uint32_t)); } @@ -450,7 +451,7 @@ void AigerReader::parse_xaiger() uint32_t poNum = parse_xaiger_literal(f); log_debug("poNum = %u\n", poNum); uint32_t boxNum = parse_xaiger_literal(f); - log_debug("boxNum = %u\n", poNum); + log_debug("boxNum = %u\n", boxNum); for (unsigned i = 0; i < boxNum; i++) { f.ignore(2*sizeof(uint32_t)); uint32_t boxUniqueId = parse_xaiger_literal(f); @@ -777,51 +778,56 @@ void AigerReader::post_process() } } + RTLIL::Wire *d = nullptr; + RTLIL::Wire *q = nullptr; // NB: Assume box_module->ports are sorted alphabetically // (as RTLIL::Module::fixup_ports() would do) for (auto port_name : box_module->ports) { RTLIL::Wire* port = box_module->wire(port_name); log_assert(port); RTLIL::SigSpec rhs; - RTLIL::Wire* wire = nullptr; for (int i = 0; i < GetSize(port); i++) { + RTLIL::Wire* wire = nullptr; if (port->port_input) { - log_assert(co_count < outputs.size()); - wire = outputs[co_count++]; - log_assert(wire); - log_assert(wire->port_output); - wire->port_output = false; - if (flop_module && port->attributes.count("\\abc_flop_d")) { - RTLIL::Wire* d = outputs[outputs.size() - flopNum + flop_count]; + log_assert(!d); + d = outputs[outputs.size() - flopNum + flop_count]; log_assert(d); log_assert(d->port_output); d->port_output = false; } + + log_assert(co_count < outputs.size()); + wire = outputs[co_count++]; + log_assert(wire); + log_assert(wire->port_output); + wire->port_output = false; } if (port->port_output) { + if (flop_module && port->attributes.count("\\abc_flop_q")) { + log_assert(!q); + q = inputs[piNum - flopNum + flop_count]; + log_assert(q); + log_assert(q->port_input); + q->port_input = false; + } + log_assert((piNum + ci_count) < inputs.size()); wire = inputs[piNum + ci_count++]; log_assert(wire); log_assert(wire->port_input); wire->port_input = false; - - if (flop_module && port->attributes.count("\\abc_flop_q")) { - wire = inputs[piNum - flopNum + flop_count]; - log_assert(wire); - log_assert(wire->port_input); - wire->port_input = false; - } } rhs.append(wire); } if (!flop_module || !port->attributes.count("\\abc_discard")) cell->setPort(port_name, rhs); } - if (flop_module) { flop_count++; cell->type = flop_module->name; + //module->addFfGate(NEW_ID, d1 q); + module->connect(q, d); } } -- cgit v1.2.3 From c04921c3a8391d2335fab42ef354bb2bb2f3ac2a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 18:13:44 -0700 Subject: Fix debug message --- frontends/aiger/aigerparse.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 833c0023b..d2657c9da 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -900,6 +900,7 @@ void AigerReader::post_process() else { wire->port_output = false; module->connect(wire, existing); + wire = existing; } } else if (index > 0) { -- cgit v1.2.3 From 3d1185b835e16cc0613aa7a31e810dd6da69599f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 22:41:42 -0700 Subject: Read init from outputs --- frontends/aiger/aigerparse.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index d2657c9da..5a6db8481 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -927,6 +927,10 @@ void AigerReader::post_process() } } log_debug(" -> %s\n", log_id(wire)); + int init; + mf >> init; + if (init < 2) + wire->attributes["\\init"] = init; } else if (type == "box") { RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable)); -- cgit v1.2.3 From 0c59bc0b75ba2985e6ae0806d410fe2fa1c94e37 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 16 Jun 2019 10:42:00 -0700 Subject: Cleanup --- frontends/aiger/aigerparse.cc | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 5a6db8481..60cbde857 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -737,11 +737,13 @@ void AigerReader::post_process() log_assert(box_module); RTLIL::Module* flop_module = nullptr; - if (box_module->attributes.count("\\abc_flop")) { + auto flop_module_name = box_module->attributes.at("\\abc_flop", RTLIL::Const()); + RTLIL::IdString flop_past_q; + if (flop_module_name.size() > 0) { log_assert(flop_count < flopNum); - log_assert(box_module->name.begins_with("$__ABC_")); - flop_module = design->module("\\" + box_module->name.substr(7)); + flop_module = design->module(RTLIL::escape_id(flop_module_name.decode_string())); log_assert(flop_module); + flop_past_q = box_module->attributes.at("\\abc_flop_past_q").decode_string(); } else if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) { RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr; @@ -778,8 +780,6 @@ void AigerReader::post_process() } } - RTLIL::Wire *d = nullptr; - RTLIL::Wire *q = nullptr; // NB: Assume box_module->ports are sorted alphabetically // (as RTLIL::Module::fixup_ports() would do) for (auto port_name : box_module->ports) { @@ -789,14 +789,6 @@ void AigerReader::post_process() for (int i = 0; i < GetSize(port); i++) { RTLIL::Wire* wire = nullptr; if (port->port_input) { - if (flop_module && port->attributes.count("\\abc_flop_d")) { - log_assert(!d); - d = outputs[outputs.size() - flopNum + flop_count]; - log_assert(d); - log_assert(d->port_output); - d->port_output = false; - } - log_assert(co_count < outputs.size()); wire = outputs[co_count++]; log_assert(wire); @@ -804,14 +796,6 @@ void AigerReader::post_process() wire->port_output = false; } if (port->port_output) { - if (flop_module && port->attributes.count("\\abc_flop_q")) { - log_assert(!q); - q = inputs[piNum - flopNum + flop_count]; - log_assert(q); - log_assert(q->port_input); - q->port_input = false; - } - log_assert((piNum + ci_count) < inputs.size()); wire = inputs[piNum + ci_count++]; log_assert(wire); @@ -820,13 +804,24 @@ void AigerReader::post_process() } rhs.append(wire); } - if (!flop_module || !port->attributes.count("\\abc_discard")) + + if (!flop_module || port_name != flop_past_q) cell->setPort(port_name, rhs); } + if (flop_module) { + RTLIL::Wire *d = outputs[outputs.size() - flopNum + flop_count]; + log_assert(d); + log_assert(d->port_output); + d->port_output = false; + + RTLIL::Wire *q = inputs[piNum - flopNum + flop_count]; + log_assert(q); + log_assert(q->port_input); + q->port_input = false; + flop_count++; cell->type = flop_module->name; - //module->addFfGate(NEW_ID, d1 q); module->connect(q, d); } } -- cgit v1.2.3 From ac5f3d500db46a4312d77f43fded2feb25545a3a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 1 Jul 2019 11:10:44 -0700 Subject: Fix spacing --- frontends/aiger/aigerparse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 7f81a4c89..57a164f1b 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -756,7 +756,7 @@ void AigerReader::post_process() log_assert(flop_module); flop_past_q = box_module->attributes.at("\\abc_flop_past_q").decode_string(); } - else if (seen_boxes.insert(cell->type).second) { + else if (seen_boxes.insert(cell->type).second) { auto it = box_module->attributes.find("\\abc_carry"); if (it != box_module->attributes.end()) { RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; -- cgit v1.2.3 From a31e17182d7f9437fb78f5018dfccbd66d9704ea Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 1 Jul 2019 11:50:34 -0700 Subject: Refactor and cope with new abc_flop format --- frontends/aiger/aigerparse.cc | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 57a164f1b..30e35da01 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -742,22 +742,29 @@ void AigerReader::parse_aiger_binary() void AigerReader::post_process() { pool seen_boxes; + dict> flop_data; unsigned ci_count = 0, co_count = 0, flop_count = 0; for (auto cell : boxes) { RTLIL::Module* box_module = design->module(cell->type); log_assert(box_module); RTLIL::Module* flop_module = nullptr; - auto flop_module_name = box_module->attributes.at("\\abc_flop", RTLIL::Const()); RTLIL::IdString flop_past_q; - if (flop_module_name.size() > 0) { - log_assert(flop_count < flopNum); - flop_module = design->module(RTLIL::escape_id(flop_module_name.decode_string())); - log_assert(flop_module); - flop_past_q = box_module->attributes.at("\\abc_flop_past_q").decode_string(); - } - else if (seen_boxes.insert(cell->type).second) { - auto it = box_module->attributes.find("\\abc_carry"); + if (seen_boxes.insert(cell->type).second) { + auto it = box_module->attributes.find("\\abc_flop"); + if (it != box_module->attributes.end()) { + log_assert(flop_count < flopNum); + std::string abc_flop = it->second.decode_string(); + auto pos = abc_flop.find(','); + log_assert(pos != std::string::npos); + flop_module = design->module(RTLIL::escape_id(abc_flop.substr(0, pos))); + log_assert(flop_module); + pos = abc_flop.rfind(','); + log_assert(pos != std::string::npos); + flop_past_q = RTLIL::escape_id(abc_flop.substr(pos+1)); + flop_data[cell->type] = std::make_pair(flop_module, flop_past_q); + } + it = box_module->attributes.find("\\abc_carry"); if (it != box_module->attributes.end()) { RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; auto carry_in_out = it->second.decode_string(); @@ -796,6 +803,11 @@ void AigerReader::post_process() carry_out->port_id = ports.size(); } } + else { + auto it = flop_data.find(cell->type); + if (it != flop_data.end()) + std::tie(flop_module,flop_past_q) = it->second; + } // NB: Assume box_module->ports are sorted alphabetically // (as RTLIL::Module::fixup_ports() would do) -- cgit v1.2.3 From a092c48f036b71cc4014ec6f2865297d49589d40 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 10 Jul 2019 17:34:51 -0700 Subject: Use split_tokens() --- frontends/aiger/aigerparse.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 30e35da01..35b7f6a97 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -754,14 +754,14 @@ void AigerReader::post_process() auto it = box_module->attributes.find("\\abc_flop"); if (it != box_module->attributes.end()) { log_assert(flop_count < flopNum); - std::string abc_flop = it->second.decode_string(); - auto pos = abc_flop.find(','); - log_assert(pos != std::string::npos); - flop_module = design->module(RTLIL::escape_id(abc_flop.substr(0, pos))); - log_assert(flop_module); - pos = abc_flop.rfind(','); - log_assert(pos != std::string::npos); - flop_past_q = RTLIL::escape_id(abc_flop.substr(pos+1)); + auto abc_flop = it->second.decode_string(); + auto tokens = split_tokens(abc_flop, ","); + if (tokens.size() != 4) + log_error("'abc_flop' attribute on module '%s' does not contain exactly four comma-separated tokens.\n", log_id(cell->type)); + flop_module = design->module(RTLIL::escape_id(tokens[0])); + if (!flop_module) + log_error("First token '%s' in 'abc_flop' attribute on module '%s' is not a valid module.\n", tokens[0].c_str(), log_id(cell->type)); + flop_past_q = RTLIL::escape_id(tokens[3]); flop_data[cell->type] = std::make_pair(flop_module, flop_past_q); } it = box_module->attributes.find("\\abc_carry"); -- cgit v1.2.3 From 4a995c5d80735baf1431a088c2faf81eb75fdaf6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 10 Jul 2019 17:54:56 -0700 Subject: Change how to specify flops to ABC again --- frontends/aiger/aigerparse.cc | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 35b7f6a97..11c5e3570 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -742,27 +742,23 @@ void AigerReader::parse_aiger_binary() void AigerReader::post_process() { pool seen_boxes; - dict> flop_data; + dict flop_data; unsigned ci_count = 0, co_count = 0, flop_count = 0; for (auto cell : boxes) { RTLIL::Module* box_module = design->module(cell->type); log_assert(box_module); RTLIL::Module* flop_module = nullptr; - RTLIL::IdString flop_past_q; + const RTLIL::IdString flop_past_q = RTLIL::escape_id("\\$pastQ"); if (seen_boxes.insert(cell->type).second) { auto it = box_module->attributes.find("\\abc_flop"); if (it != box_module->attributes.end()) { log_assert(flop_count < flopNum); auto abc_flop = it->second.decode_string(); - auto tokens = split_tokens(abc_flop, ","); - if (tokens.size() != 4) - log_error("'abc_flop' attribute on module '%s' does not contain exactly four comma-separated tokens.\n", log_id(cell->type)); - flop_module = design->module(RTLIL::escape_id(tokens[0])); + flop_module = design->module(RTLIL::escape_id(abc_flop)); if (!flop_module) - log_error("First token '%s' in 'abc_flop' attribute on module '%s' is not a valid module.\n", tokens[0].c_str(), log_id(cell->type)); - flop_past_q = RTLIL::escape_id(tokens[3]); - flop_data[cell->type] = std::make_pair(flop_module, flop_past_q); + log_error("'abc_flop' attribute value '%s' on module '%s' is not a valid module.\n", abc_flop.c_str(), log_id(cell->type)); + flop_data[cell->type] = flop_module; } it = box_module->attributes.find("\\abc_carry"); if (it != box_module->attributes.end()) { @@ -806,7 +802,7 @@ void AigerReader::post_process() else { auto it = flop_data.find(cell->type); if (it != flop_data.end()) - std::tie(flop_module,flop_past_q) = it->second; + flop_module = it->second; } // NB: Assume box_module->ports are sorted alphabetically -- cgit v1.2.3 From f8f0ffe786eabd016e0f9a0e4f4de10743638cdf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 10 Jul 2019 18:56:50 -0700 Subject: Small opt --- frontends/aiger/aigerparse.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 11c5e3570..b599160cf 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -749,7 +749,6 @@ void AigerReader::post_process() log_assert(box_module); RTLIL::Module* flop_module = nullptr; - const RTLIL::IdString flop_past_q = RTLIL::escape_id("\\$pastQ"); if (seen_boxes.insert(cell->type).second) { auto it = box_module->attributes.find("\\abc_flop"); if (it != box_module->attributes.end()) { @@ -830,7 +829,7 @@ void AigerReader::post_process() rhs.append(wire); } - if (!flop_module || port_name != flop_past_q) + if (!flop_module || port_name != "\\$pastQ") cell->setPort(port_name, rhs); } -- cgit v1.2.3 From bd198aa803bdfc3b21bfa920822805df992e3120 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Jul 2019 10:07:14 -0700 Subject: Missing debug message --- frontends/aiger/aigerparse.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index b599160cf..77ef75cd5 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -901,6 +901,7 @@ void AigerReader::post_process() wire->port_output = false; continue; } + log_debug("Renaming output %s", log_id(wire)); if (index == 0) { // Cope with the fact that a CO might be identical -- cgit v1.2.3 From a314565ad448c1d5a76604bbd25ac2c901c08f8f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Jul 2019 10:52:45 -0700 Subject: Short out async box --- frontends/aiger/aigerparse.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 77ef75cd5..b984e846a 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -741,6 +741,9 @@ void AigerReader::parse_aiger_binary() void AigerReader::post_process() { + const RTLIL::Wire* n0 = module->wire("\\__0__"); + const RTLIL::Wire* n1 = module->wire("\\__1__"); + pool seen_boxes; dict flop_data; unsigned ci_count = 0, co_count = 0, flop_count = 0; @@ -847,6 +850,17 @@ void AigerReader::post_process() flop_count++; cell->type = flop_module->name; module->connect(q, d); + continue; + } + + // Remove the async mux by shorting out its input and output + if (cell->type == "$__ABC_ASYNC") { + RTLIL::Wire* A = cell->getPort("\\A").as_wire(); + if (A == n0 || A == n1) A = nullptr; + auto it = cell->connections_.find("\\Y"); + log_assert(it != cell->connections_.end()); + module->connect(it->second, A); + cell->connections_.erase(it); } } -- cgit v1.2.3 From 9bfe924e17a87fac8a35fcb7ff5e067f6c520e07 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 19 Aug 2019 09:40:01 -0700 Subject: Set abc_flop and use it in toposort --- frontends/aiger/aigerparse.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index f2b38da67..6fd9e0432 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -840,6 +840,7 @@ void AigerReader::post_process() flop_count++; cell->type = flop_module->name; module->connect(q, d); + cell->set_bool_attribute("\\abc_flop"); continue; } -- cgit v1.2.3 From be9e4f1b674ef4fb3f02e99efcfda04ea27b2a68 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Aug 2019 12:39:11 -0700 Subject: Use abc_{map,unmap,model}.v --- frontends/aiger/aigerparse.cc | 41 ++++++++++------------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index cb4ec6183..7a467b91e 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -731,28 +731,21 @@ void AigerReader::parse_aiger_binary() void AigerReader::post_process() { - const RTLIL::Wire* n0 = module->wire("\\__0__"); - const RTLIL::Wire* n1 = module->wire("\\__1__"); - pool seen_boxes; - dict flop_data; + pool flops; unsigned ci_count = 0, co_count = 0, flop_count = 0; for (auto cell : boxes) { RTLIL::Module* box_module = design->module(cell->type); log_assert(box_module); - RTLIL::Module* flop_module = nullptr; + bool is_flop = false; if (seen_boxes.insert(cell->type).second) { - auto it = box_module->attributes.find("\\abc_flop"); - if (it != box_module->attributes.end()) { + if (box_module->attributes.count("\\abc_flop")) { log_assert(flop_count < flopNum); - auto abc_flop = it->second.decode_string(); - flop_module = design->module(RTLIL::escape_id(abc_flop)); - if (!flop_module) - log_error("'abc_flop' attribute value '%s' on module '%s' is not a valid module.\n", abc_flop.c_str(), log_id(cell->type)); - flop_data[cell->type] = flop_module; + flops.insert(cell->type); + is_flop = true; } - it = box_module->attributes.find("\\abc_carry"); + auto it = box_module->attributes.find("\\abc_carry"); if (it != box_module->attributes.end()) { RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; auto carry_in_out = it->second.decode_string(); @@ -791,11 +784,8 @@ void AigerReader::post_process() carry_out->port_id = ports.size(); } } - else { - auto it = flop_data.find(cell->type); - if (it != flop_data.end()) - flop_module = it->second; - } + else + is_flop = flops.count(cell->type); // NB: Assume box_module->ports are sorted alphabetically // (as RTLIL::Module::fixup_ports() would do) @@ -822,11 +812,11 @@ void AigerReader::post_process() rhs.append(wire); } - if (!flop_module || port_name != "\\$pastQ") + if (!is_flop || port_name != "\\$pastQ") cell->setPort(port_name, rhs); } - if (flop_module) { + if (is_flop) { RTLIL::Wire *d = outputs[outputs.size() - flopNum + flop_count]; log_assert(d); log_assert(d->port_output); @@ -838,21 +828,10 @@ void AigerReader::post_process() q->port_input = false; flop_count++; - cell->type = flop_module->name; module->connect(q, d); cell->set_bool_attribute("\\abc_flop"); continue; } - - // Remove the async mux by shorting out its input and output - if (cell->type == "$__ABC_ASYNC") { - RTLIL::Wire* A = cell->getPort("\\A").as_wire(); - if (A == n0 || A == n1) A = nullptr; - auto it = cell->connections_.find("\\Y"); - log_assert(it != cell->connections_.end()); - module->connect(it->second, A); - cell->connections_.erase(it); - } } dict wideports_cache; -- cgit v1.2.3 From 091bf4a18b2f4bf84fe62b61577c88d961468b3c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Aug 2019 18:16:37 -0700 Subject: Remove sequential extension --- frontends/aiger/aigerparse.cc | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 7a467b91e..e8ee487e5 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -732,19 +732,12 @@ void AigerReader::parse_aiger_binary() void AigerReader::post_process() { pool seen_boxes; - pool flops; - unsigned ci_count = 0, co_count = 0, flop_count = 0; + unsigned ci_count = 0, co_count = 0; for (auto cell : boxes) { RTLIL::Module* box_module = design->module(cell->type); log_assert(box_module); - bool is_flop = false; if (seen_boxes.insert(cell->type).second) { - if (box_module->attributes.count("\\abc_flop")) { - log_assert(flop_count < flopNum); - flops.insert(cell->type); - is_flop = true; - } auto it = box_module->attributes.find("\\abc_carry"); if (it != box_module->attributes.end()) { RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; @@ -784,8 +777,6 @@ void AigerReader::post_process() carry_out->port_id = ports.size(); } } - else - is_flop = flops.count(cell->type); // NB: Assume box_module->ports are sorted alphabetically // (as RTLIL::Module::fixup_ports() would do) @@ -812,25 +803,7 @@ void AigerReader::post_process() rhs.append(wire); } - if (!is_flop || port_name != "\\$pastQ") - cell->setPort(port_name, rhs); - } - - if (is_flop) { - RTLIL::Wire *d = outputs[outputs.size() - flopNum + flop_count]; - log_assert(d); - log_assert(d->port_output); - d->port_output = false; - - RTLIL::Wire *q = inputs[piNum - flopNum + flop_count]; - log_assert(q); - log_assert(q->port_input); - q->port_input = false; - - flop_count++; - module->connect(q, d); - cell->set_bool_attribute("\\abc_flop"); - continue; + cell->setPort(port_name, rhs); } } @@ -934,10 +907,6 @@ void AigerReader::post_process() } } log_debug(" -> %s\n", log_id(wire)); - int init; - mf >> init; - if (init < 2) - wire->attributes["\\init"] = init; } else if (type == "box") { RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable)); -- cgit v1.2.3 From 34ae29295db53289e786c0279ed00474cf0294d3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 28 Aug 2019 19:59:09 -0700 Subject: read_verilog -defer should still populate module attributes --- frontends/ast/ast.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 82283fb5b..6a91c418b 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1073,11 +1073,6 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast ignoreThisSignalsInInitial = RTLIL::SigSpec(); - for (auto &attr : ast->attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - current_module->attributes[attr.first] = attr.second->asAttrConst(); - } for (size_t i = 0; i < ast->children.size(); i++) { AstNode *node = ast->children[i]; if (node->type == AST_WIRE || node->type == AST_MEMORY) @@ -1100,6 +1095,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast ignoreThisSignalsInInitial = RTLIL::SigSpec(); } + for (auto &attr : ast->attributes) { + if (attr.second->type != AST_CONSTANT) + log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); + current_module->attributes[attr.first] = attr.second->asAttrConst(); + } + if (ast->type == AST_INTERFACE) current_module->set_bool_attribute("\\is_interface"); current_module->ast = ast_before_simplify; -- cgit v1.2.3 From 6510297712729f9742d00f6a4cd4fc3a0e530758 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 29 Aug 2019 09:02:10 -0700 Subject: Restore non-deferred code, deferred case to ignore non constant attr --- frontends/ast/ast.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 6a91c418b..01e865557 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1073,6 +1073,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast ignoreThisSignalsInInitial = RTLIL::SigSpec(); + for (auto &attr : ast->attributes) { + if (attr.second->type != AST_CONSTANT) + log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); + current_module->attributes[attr.first] = attr.second->asAttrConst(); + } + for (size_t i = 0; i < ast->children.size(); i++) { AstNode *node = ast->children[i]; if (node->type == AST_WIRE || node->type == AST_MEMORY) @@ -1094,11 +1100,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast ignoreThisSignalsInInitial = RTLIL::SigSpec(); } - - for (auto &attr : ast->attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - current_module->attributes[attr.first] = attr.second->asAttrConst(); + else { + for (auto &attr : ast->attributes) { + if (attr.second->type != AST_CONSTANT) + continue; + current_module->attributes[attr.first] = attr.second->asAttrConst(); + } } if (ast->type == AST_INTERFACE) -- cgit v1.2.3 From 83ffec26cbda434b31a2bbd004213a538bf3e6e6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 29 Aug 2019 09:08:58 -0700 Subject: Remove newline --- frontends/ast/ast.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 01e865557..a3a78e414 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1078,7 +1078,6 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); current_module->attributes[attr.first] = attr.second->asAttrConst(); } - for (size_t i = 0; i < ast->children.size(); i++) { AstNode *node = ast->children[i]; if (node->type == AST_WIRE || node->type == AST_MEMORY) -- cgit v1.2.3 From 25e5fbac9096a872f7be1a481e6798103f40ccf5 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 2 Sep 2019 22:56:38 +0200 Subject: Properly construct $live and $fair cells from "if (...) assume/assert (s_eventually ...)" Fixes https://github.com/YosysHQ/SymbiYosys/issues/59 Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 86dd80c65..52fcf3ee7 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1530,10 +1530,16 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire_en->str] = wire_en; while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } - std::vector x_bit; - x_bit.push_back(RTLIL::State::Sx); + AstNode *check_defval; + if (type == AST_LIVE || type == AST_FAIR) { + check_defval = new AstNode(AST_REDUCE_BOOL, children[0]->clone()); + } else { + std::vector x_bit; + x_bit.push_back(RTLIL::State::Sx); + check_defval = mkconst_bits(x_bit, false); + } - AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bit, false)); + AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), check_defval); assign_check->children[0]->str = id_check; assign_check->children[0]->was_checked = true; @@ -1546,9 +1552,13 @@ skip_dynamic_range_lvalue_expansion:; default_signals->children.push_back(assign_en); current_top_block->children.insert(current_top_block->children.begin(), default_signals); - assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); - assign_check->children[0]->str = id_check; - assign_check->children[0]->was_checked = true; + if (type == AST_LIVE || type == AST_FAIR) { + assign_check = nullptr; + } else { + assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); + assign_check->children[0]->str = id_check; + assign_check->children[0]->was_checked = true; + } if (current_always == nullptr || current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); @@ -1560,7 +1570,8 @@ skip_dynamic_range_lvalue_expansion:; assign_en->children[0]->was_checked = true; newNode = new AstNode(AST_BLOCK); - newNode->children.push_back(assign_check); + if (assign_check != nullptr) + newNode->children.push_back(assign_check); newNode->children.push_back(assign_en); AstNode *assertnode = new AstNode(type); -- cgit v1.2.3 From d3eea82bc27f6e54b6c1e05a73be8456344ec8b7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 4 Sep 2019 15:21:39 -0700 Subject: Revert "parse_xaiger() to do "clean -purge"" This reverts commit 5d16bf831688ff665b0ec2abd6835b71320b2db5. --- frontends/aiger/aigerparse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 2e1fb8fad..06522939f 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -974,7 +974,7 @@ void AigerReader::post_process() // operate (and run checks on) this one module RTLIL::Design *mapped_design = new RTLIL::Design; mapped_design->add(module); - Pass::call(mapped_design, "clean -purge"); + Pass::call(mapped_design, "clean"); mapped_design->modules_.erase(module->name); delete mapped_design; -- cgit v1.2.3 From 7eb593829f62476598bb15c2fb903d50108e5274 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 12 Sep 2019 09:43:19 +0200 Subject: Fix lexing of integer literals, fixes #1364 Signed-off-by: Clifford Wolf --- frontends/verilog/const2ast.cc | 4 ++-- frontends/verilog/verilog_lexer.l | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 4bf5b1cf5..5da88a93f 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -199,13 +199,13 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn if (str == endptr) len_in_bits = -1; - // The "'s?[bodhBODH]" syntax + // The "'[sS]?[bodhBODH]" syntax if (*endptr == '\'') { std::vector data; bool is_signed = false; bool is_unsized = len_in_bits < 0; - if (*(endptr+1) == 's') { + if (*(endptr+1) == 's' || *(endptr+1) == 'S') { is_signed = true; endptr++; } diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 57e55b1f4..e344ffd4f 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -239,7 +239,7 @@ YOSYS_NAMESPACE_END return TOK_CONSTVAL; } -[0-9]*[ \t]*\'s?[bodhBODH]*[ \t\r\n]*[0-9a-fA-FzxZX?_]+ { +[0-9]*[ \t]*\'[sS]?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ { frontend_verilog_yylval.string = new std::string(yytext); return TOK_CONSTVAL; } -- cgit v1.2.3 From 855e6a9b9172e6817c9ff57f7041b09a1cc0367e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 13 Sep 2019 10:19:58 +0200 Subject: Fix lexing of integer literals without radix Signed-off-by: Clifford Wolf --- frontends/verilog/verilog_lexer.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index e344ffd4f..4acfb414d 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -239,7 +239,7 @@ YOSYS_NAMESPACE_END return TOK_CONSTVAL; } -[0-9]*[ \t]*\'[sS]?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ { +[0-9]*[ \t]*\'[sS]?[bodhBODH]?[ \t\r\n]*[0-9a-fA-FzxZX?_]+ { frontend_verilog_yylval.string = new std::string(yytext); return TOK_CONSTVAL; } -- cgit v1.2.3 From a67d63714be52e4a4f789c2a82b6283748db8902 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 13 Sep 2019 13:39:39 +0200 Subject: Fix handling of z_digit "?" and fix optimization of cmp with "z" Signed-off-by: Clifford Wolf --- frontends/verilog/const2ast.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 5da88a93f..49281f7e7 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -85,10 +85,8 @@ static void my_strtobin(std::vector &data, const char *str, int le digits.push_back(10 + *str - 'A'); else if (*str == 'x' || *str == 'X') digits.push_back(0xf0); - else if (*str == 'z' || *str == 'Z') + else if (*str == 'z' || *str == 'Z' || *str == '?') digits.push_back(0xf1); - else if (*str == '?') - digits.push_back(0xf2); str++; } @@ -112,8 +110,6 @@ static void my_strtobin(std::vector &data, const char *str, int le data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx); else if (*it == 0xf1) data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz); - else if (*it == 0xf2) - data.push_back(RTLIL::Sa); else data.push_back((*it & bitmask) ? State::S1 : State::S0); } -- cgit v1.2.3 From 25b08b1afd87f6c2e6a6c1318bc790b4a929b7f5 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 16 Sep 2019 11:25:16 +0200 Subject: Fix handling of range selects on loop variables, fixes #1372 Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 52fcf3ee7..b1ee22f42 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2895,8 +2895,15 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map &name_map) { if (!index_var.empty() && type == AST_IDENTIFIER && str == index_var) { - current_scope[index_var]->children[0]->cloneInto(this); - return; + if (children.empty()) { + current_scope[index_var]->children[0]->cloneInto(this); + } else { + AstNode *p = new AstNode(AST_LOCALPARAM, current_scope[index_var]->children[0]->clone()); + p->str = stringf("$genval$%d", autoidx++); + current_ast_mod->children.push_back(p); + str = p->str; + id2ast = p; + } } if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL) && name_map.count(str) > 0) -- cgit v1.2.3 From 8da0888bf6ae4c975c6d3b0c9a656bc10e1283e4 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 20 Sep 2019 12:16:20 +0200 Subject: Fix handling of read_verilog config in AstModule::reprocess_module(), fixes #1360 Signed-off-by: Clifford Wolf --- frontends/ast/ast.cc | 47 +++++++++++++++++++++++++++++------------------ frontends/ast/ast.h | 1 + 2 files changed, 30 insertions(+), 18 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index a3a78e414..21279cbfa 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -158,6 +158,11 @@ std::string AST::type2str(AstNodeType type) X(AST_POSEDGE) X(AST_NEGEDGE) X(AST_EDGE) + X(AST_INTERFACE) + X(AST_INTERFACEPORT) + X(AST_INTERFACEPORTTYPE) + X(AST_MODPORT) + X(AST_MODPORTMEMBER) X(AST_PACKAGE) #undef X default: @@ -1291,6 +1296,8 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule // from AST. The interface members are copied into the AST module with the prefix of the interface. void AstModule::reprocess_module(RTLIL::Design *design, dict local_interfaces) { + loadconfig(); + bool is_top = false; AstNode *new_ast = ast->clone(); for (auto &intf : local_interfaces) { @@ -1474,24 +1481,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, dictclone(); @@ -1572,6 +1562,27 @@ RTLIL::Module *AstModule::clone() const return new_mod; } +void AstModule::loadconfig() const +{ + current_ast = NULL; + flag_dump_ast1 = false; + flag_dump_ast2 = false; + flag_dump_vlog1 = false; + flag_dump_vlog2 = false; + flag_nolatches = nolatches; + flag_nomeminit = nomeminit; + flag_nomem2reg = nomem2reg; + flag_mem2reg = mem2reg; + flag_noblackbox = noblackbox; + flag_lib = lib; + flag_nowb = nowb; + flag_noopt = noopt; + flag_icells = icells; + flag_pwires = pwires; + flag_autowire = autowire; + use_internal_line_num(); +} + // internal dummy line number callbacks namespace { int internal_line_num; diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 54b2fb319..93fee913e 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -299,6 +299,7 @@ namespace AST std::string derive_common(RTLIL::Design *design, dict parameters, AstNode **new_ast_out, bool mayfail); void reprocess_module(RTLIL::Design *design, dict local_interfaces) YS_OVERRIDE; RTLIL::Module *clone() const YS_OVERRIDE; + void loadconfig() const; }; // this must be set by the language frontend before parsing the sources -- cgit v1.2.3 From c340fbfab23c582103402bbd812d9bca4510dc41 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 23 Sep 2019 21:58:04 -0700 Subject: Force $inout.out ports to begin with '$' to indicate internal --- frontends/aiger/aigerparse.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index e8ee487e5..986d34fb3 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -868,7 +868,7 @@ void AigerReader::post_process() if (!existing) { if (escaped_s.ends_with("$inout.out")) { wire->port_output = false; - RTLIL::Wire *in_wire = module->wire(escaped_s.substr(0, escaped_s.size()-10)); + RTLIL::Wire *in_wire = module->wire(escaped_s.substr(1, escaped_s.size()-11)); log_assert(in_wire); log_assert(in_wire->port_input && !in_wire->port_output); in_wire->port_output = true; @@ -889,7 +889,7 @@ void AigerReader::post_process() if (!existing) { if (escaped_s.ends_with("$inout.out")) { wire->port_output = false; - RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(0, escaped_s.size()-10).c_str(), index)); + RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(1, escaped_s.size()-11).c_str(), index)); log_assert(in_wire); log_assert(in_wire->port_input && !in_wire->port_output); in_wire->port_output = true; -- cgit v1.2.3 From 3f70c1fd26eb109c2c4d899cce55f24bbf04acc1 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 29 Sep 2019 13:22:11 +0200 Subject: Open aig frontend as binary file --- frontends/aiger/aigerparse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index e8ee487e5..b0a04749c 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -1056,7 +1056,7 @@ struct AigerFrontend : public Frontend { } break; } - extra_args(f, filename, args, argidx); + extra_args(f, filename, args, argidx, true); if (module_name.empty()) { #ifdef _WIN32 -- cgit v1.2.3 From 9e55b234b47b01dc396e793b7f31236c9e87c185 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 29 Sep 2019 15:40:37 +0200 Subject: Fix reading aig files on windows --- frontends/aiger/aigerparse.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index b0a04749c..ad35e9d76 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -285,6 +285,8 @@ end_of_header: } else if (c == 'c') { f.ignore(1); + if (f.peek() == '\r') + f.ignore(1); if (f.peek() == '\n') break; // Else constraint (TODO) @@ -1062,7 +1064,9 @@ struct AigerFrontend : public Frontend { #ifdef _WIN32 char fname[_MAX_FNAME]; _splitpath(filename.c_str(), NULL /* drive */, NULL /* dir */, fname, NULL /* ext */); - module_name = fname; + char* bn = strdup(fname); + module_name = RTLIL::escape_id(bn); + free(bn); #else char* bn = strdup(filename.c_str()); module_name = RTLIL::escape_id(bn); -- cgit v1.2.3 From 99a7f39084cf4b9cd21e2a1e4f4a842993dfd147 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 26 Sep 2019 03:57:16 +0000 Subject: rpc: new frontend. A new pass, connect_rpc, allows any HDL frontend that can read/write JSON from/to stdin/stdout or an unix socket or a named pipe to participate in elaboration as a first class citizen, such that any other HDL supported by Yosys directly or indirectly can transparently instantiate modules handled by this frontend. Recognizing that many HDL frontends emit Verilog, it allows the RPC frontend to direct Yosys to process the result of instantiation via any built-in Yosys frontend. The resulting RTLIL is then hygienically integrated into the overall design. --- frontends/rpc/Makefile.inc | 2 + frontends/rpc/rpc_frontend.cc | 589 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 591 insertions(+) create mode 100644 frontends/rpc/Makefile.inc create mode 100644 frontends/rpc/rpc_frontend.cc (limited to 'frontends') diff --git a/frontends/rpc/Makefile.inc b/frontends/rpc/Makefile.inc new file mode 100644 index 000000000..9af505098 --- /dev/null +++ b/frontends/rpc/Makefile.inc @@ -0,0 +1,2 @@ + +OBJS += frontends/rpc/rpc_frontend.o diff --git a/frontends/rpc/rpc_frontend.cc b/frontends/rpc/rpc_frontend.cc new file mode 100644 index 000000000..b4b2fa3a2 --- /dev/null +++ b/frontends/rpc/rpc_frontend.cc @@ -0,0 +1,589 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2019 whitequark + * + * 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. + * + */ + +// The reason the -path mode of connect_rpc uses byte-oriented and not message-oriented sockets, even though +// it is a message-oriented interface, is that the system can place various limits on the message size, which +// are not always transparent or easy to change. Given that generated HDL code get be extremely large, it is +// unwise to rely on those limits being large enough, and using byte-oriented sockets is guaranteed to work. + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#endif + +#include "libs/json11/json11.hpp" +#include "libs/sha1/sha1.h" +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN + +#if defined(_WIN32) +static std::wstring str2wstr(const std::string &in) { + if(in == "") return L""; + std::wstring out; + out.resize(MultiByteToWideChar(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpMultiByteStr=*/&in[0], /*cbMultiByte=*/(int)in.length(), /*lpWideCharStr=*/NULL, /*cchWideChar=*/0)); + int written = MultiByteToWideChar(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpMultiByteStr=*/&in[0], /*cbMultiByte=*/(int)in.length(), /*lpWideCharStr=*/&out[0], /*cchWideChar=*/(int)out.length()); + log_assert(written == (int)out.length()); + return out; +} + +static std::string wstr2str(const std::wstring &in) { + if(in == L"") return ""; + std::string out; + out.resize(WideCharToMultiByte(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpWideCharStr=*/&in[0], /*cchWideChar=*/(int)in.length(), /*lpMultiByteStr=*/NULL, /*cbMultiByte=*/0, /*lpDefaultChar=*/NULL, /*lpUsedDefaultChar=*/NULL)); + int written = WideCharToMultiByte(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpWideCharStr=*/&in[0], /*cchWideChar=*/(int)in.length(), /*lpMultiByteStr=*/&out[0], /*cbMultiByte=*/(int)out.length(), /*lpDefaultChar=*/NULL, /*lpUsedDefaultChar=*/NULL); + log_assert(written == (int)out.length()); + return out; +} + +static std::string get_last_error_str() { + DWORD last_error = GetLastError(); + LPWSTR out_w; + DWORD size_w = FormatMessageW(/*dwFlags=*/FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS, /*lpSource=*/NULL, /*dwMessageId=*/last_error, /*dwLanguageId=*/0, /*lpBuffer=*/(LPWSTR)&out_w, /*nSize=*/0, /*Arguments=*/NULL); + if (size_w == 0) + return std::to_string(last_error); + std::string out = wstr2str(std::wstring(out_w, size_w)); + LocalFree(out_w); + return out; +} +#endif + +using json11::Json; + +struct RpcServer { + std::string name; + + RpcServer(const std::string &name) : name(name) { } + virtual ~RpcServer() { } + + virtual void write(const std::string &data) = 0; + virtual std::string read() = 0; + + Json call(const Json &json_request) { + std::string request; + json_request.dump(request); + request += '\n'; + log_debug("RPC frontend request: %s", request.c_str()); + write(request); + + std::string response = read(); + log_debug("RPC frontend response: %s", response.c_str()); + std::string error; + Json json_response = Json::parse(response, error); + if (json_response.is_null()) + log_cmd_error("parsing JSON failed: %s\n", error.c_str()); + if (json_response["error"].is_string()) + log_cmd_error("RPC frontend returned an error: %s\n", json_response["error"].string_value().c_str()); + return json_response; + } + + std::vector get_module_names() { + Json response = call(Json::object { + { "method", "modules" }, + }); + bool is_valid = true; + std::vector modules; + if (response["modules"].is_array()) { + for (auto &json_module : response["modules"].array_items()) { + if (json_module.is_string()) + modules.push_back(json_module.string_value()); + else is_valid = false; + } + } else is_valid = false; + if (!is_valid) + log_cmd_error("RPC frontend returned malformed response: %s\n", response.dump().c_str()); + return modules; + } + + std::pair derive_module(const std::string &module, const dict ¶meters) { + Json::object json_parameters; + for (auto ¶m : parameters) { + std::string type, value; + if (param.second.flags & RTLIL::CONST_FLAG_REAL) { + type = "real"; + value = param.second.decode_string(); + } else if (param.second.flags & RTLIL::CONST_FLAG_STRING) { + type = "string"; + value = param.second.decode_string(); + } else if ((param.second.flags & ~RTLIL::CONST_FLAG_SIGNED) == RTLIL::CONST_FLAG_NONE) { + type = (param.second.flags & RTLIL::CONST_FLAG_SIGNED) ? "signed" : "unsigned"; + value = param.second.as_string(); + } else + log_cmd_error("Unserializable constant flags 0x%x\n", param.second.flags); + json_parameters[param.first.str()] = Json::object { + { "type", type }, + { "value", value }, + }; + } + Json response = call(Json::object { + { "method", "derive" }, + { "module", module }, + { "parameters", json_parameters }, + }); + bool is_valid = true; + std::string frontend, source; + if (response["frontend"].is_string()) + frontend = response["frontend"].string_value(); + else is_valid = false; + if (response["source"].is_string()) + source = response["source"].string_value(); + else is_valid = false; + if (!is_valid) + log_cmd_error("RPC frontend returned malformed response: %s\n", response.dump().c_str()); + return std::make_pair(frontend, source); + } +}; + +struct RpcModule : RTLIL::Module { + std::shared_ptr server; + + RTLIL::IdString derive(RTLIL::Design *design, dict parameters, bool /*mayfail*/) YS_OVERRIDE { + std::string stripped_name = name.str(); + if (stripped_name.compare(0, 9, "$abstract") == 0) + stripped_name = stripped_name.substr(9); + log_assert(stripped_name[0] == '\\'); + + log_header(design, "Executing RPC frontend `%s' for module `%s'.\n", server->name.c_str(), stripped_name.c_str()); + + std::string parameter_info; + for (auto ¶m : parameters) { + log("Parameter %s = %s\n", param.first.c_str(), log_signal(RTLIL::SigSpec(param.second))); + parameter_info += stringf("%s=%s", param.first.c_str(), log_signal(RTLIL::SigSpec(param.second))); + } + + std::string derived_name; + if (parameters.empty()) + derived_name = stripped_name; + else if (parameter_info.size() > 60) + derived_name = "$paramod$" + sha1(parameter_info) + stripped_name; + else + derived_name = "$paramod" + stripped_name + parameter_info; + + if (design->has(derived_name)) { + log("Found cached RTLIL representation for module `%s'.\n", derived_name.c_str()); + } else { + std::string command, input; + std::tie(command, input) = server->derive_module(stripped_name.substr(1), parameters); + + std::istringstream input_stream(input); + RTLIL::Design *derived_design = new RTLIL::Design; + Frontend::frontend_call(derived_design, &input_stream, "" + derived_name.substr(8), command); + derived_design->check(); + + dict name_mangling; + bool found_derived_top = false; + for (auto module : derived_design->modules()) { + std::string original_name = module->name.str(); + if (original_name == stripped_name) { + found_derived_top = true; + name_mangling[original_name] = derived_name; + } else { + name_mangling[original_name] = derived_name + module->name.str(); + } + } + if (!found_derived_top) + log_cmd_error("RPC frontend did not return requested module `%s`!\n", stripped_name.c_str()); + + for (auto module : derived_design->modules()) + for (auto cell : module->cells()) + if (name_mangling.count(cell->type.str())) + cell->type = name_mangling[cell->type.str()]; + + for (auto module : derived_design->modules_) { + std::string mangled_name = name_mangling[module.first.str()]; + + log("Importing `%s' as `%s'.\n", log_id(module.first), log_id(mangled_name)); + + module.second->name = mangled_name; + module.second->design = design; + module.second->attributes.erase("\\top"); + design->modules_[mangled_name] = module.second; + derived_design->modules_.erase(module.first); + } + + delete derived_design; + } + + return derived_name; + } + + RTLIL::Module *clone() const YS_OVERRIDE { + RpcModule *new_mod = new RpcModule; + new_mod->server = server; + cloneInto(new_mod); + return new_mod; + } +}; + +#if defined(_WIN32) + +struct HandleRpcServer : RpcServer { + HANDLE hsend, hrecv; + + HandleRpcServer(const std::string &name, HANDLE hsend, HANDLE hrecv) + : RpcServer(name), hsend(hsend), hrecv(hrecv) { } + + void write(const std::string &data) YS_OVERRIDE { + log_assert(data.length() >= 1 && data.find('\n') == data.length() - 1); + ssize_t offset = 0; + do { + DWORD data_written; + if (!WriteFile(hsend, &data[offset], data.length() - offset, &data_written, /*lpOverlapped=*/NULL)) + log_cmd_error("WriteFile failed: %s\n", get_last_error_str().c_str()); + offset += data_written; + } while(offset < (ssize_t)data.length()); + } + + std::string read() YS_OVERRIDE { + std::string data; + ssize_t offset = 0; + while (data.length() == 0 || data[data.length() - 1] != '\n') { + data.resize(data.length() + 1024); + DWORD data_read; + if (!ReadFile(hrecv, &data[offset], data.length() - offset, &data_read, /*lpOverlapped=*/NULL)) + log_cmd_error("ReadFile failed: %s\n", get_last_error_str().c_str()); + offset += data_read; + data.resize(offset); + size_t term_pos = data.find('\n', offset); + if (term_pos != data.length() - 1 && term_pos != std::string::npos) + log_cmd_error("read failed: more than one response\n"); + } + return data; + } + + ~HandleRpcServer() { + CloseHandle(hsend); + if (hrecv != hsend) + CloseHandle(hrecv); + } +}; + +#else + +struct FdRpcServer : RpcServer { + int fdsend, fdrecv; + pid_t pid; + + FdRpcServer(const std::string &name, int fdsend, int fdrecv, pid_t pid = -1) + : RpcServer(name), fdsend(fdsend), fdrecv(fdrecv), pid(pid) { } + + void check_pid() { + if (pid == -1) return; + // If we're communicating with a process, check that it's still running, or we may get killed with SIGPIPE. + pid_t wait_result = ::waitpid(pid, NULL, WNOHANG); + if (wait_result == -1) + log_cmd_error("waitpid failed: %s\n", strerror(errno)); + if (wait_result == pid) + log_cmd_error("RPC frontend terminated unexpectedly\n"); + } + + void write(const std::string &data) YS_OVERRIDE { + log_assert(data.length() >= 1 && data.find('\n') == data.length() - 1); + ssize_t offset = 0; + do { + check_pid(); + ssize_t result = ::write(fdsend, &data[offset], data.length() - offset); + if (result == -1) + log_cmd_error("write failed: %s\n", strerror(errno)); + offset += result; + } while(offset < (ssize_t)data.length()); + } + + std::string read() YS_OVERRIDE { + std::string data; + ssize_t offset = 0; + while (data.length() == 0 || data[data.length() - 1] != '\n') { + data.resize(data.length() + 1024); + check_pid(); + ssize_t result = ::read(fdrecv, &data[offset], data.length() - offset); + if (result == -1) + log_cmd_error("read failed: %s\n", strerror(errno)); + offset += result; + data.resize(offset); + size_t term_pos = data.find('\n', offset); + if (term_pos != data.length() - 1 && term_pos != std::string::npos) + log_cmd_error("read failed: more than one response\n"); + } + return data; + } + + ~FdRpcServer() { + close(fdsend); + if (fdrecv != fdsend) + close(fdrecv); + } +}; + +#endif + +// RpcFrontend does not inherit from Frontend since it does not read files. +struct RpcFrontend : public Pass { + RpcFrontend() : Pass("connect_rpc", "connect to RPC frontend") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" connect_rpc -exec [args...]\n"); + log(" connect_rpc -path \n"); + log("\n"); + log("Load modules using an out-of-process frontend.\n"); + log("\n"); + log(" -exec [args...]\n"); + log(" run with arguments [args...]. send requests on stdin, read\n"); + log(" responses from stdout.\n"); + log("\n"); + log(" -path \n"); + log(" connect to Unix domain socket at . (Unix)\n"); + log(" connect to bidirectional byte-type named pipe at . (Windows)\n"); + log("\n"); + log("A simple JSON-based, newline-delimited protocol is used for communicating with\n"); + log("the frontend. Yosys requests data from the frontend by sending exactly 1 line\n"); + log("of JSON. Frontend responds with data or error message by replying with exactly\n"); + log("1 line of JSON as well.\n"); + log("\n"); + log(" -> {\"method\": \"modules\"}\n"); + log(" <- {\"modules\": [\"\", ...]}\n"); + log(" <- {\"error\": \"\"}\n"); + log(" request for the list of modules that can be derived by this frontend.\n"); + log(" the 'hierarchy' command will call back into this frontend if a cell\n"); + log(" with type is instantiated in the design.\n"); + log("\n"); + log(" -> {\"method\": \"derive\", \"module\": \", \"parameters\": {\n"); + log(" \"\": {\"type\": \"[unsigned|signed|string|real]\",\n"); + log(" \"value\": \"\"}, ...}}\n"); + log(" <- {\"frontend\": \"[ilang|verilog|...]\",\"source\": \"\"}}\n"); + log(" <- {\"error\": \"\"}\n"); + log(" request for the module to be derived for a specific set of\n"); + log(" parameters. starts with \\ for named parameters, and with $\n"); + log(" for unnamed parameters, which are numbered starting at 1.\n"); + log(" for integer parameters is always specified as a binary string of unlimited\n"); + log(" precision. the returned by the frontend is hygienically parsed\n"); + log(" by a built-in Yosys , allowing the RPC frontend to return any\n"); + log(" convenient representation of the module. the derived module is cached,\n"); + log(" so the response should be the same whenever the same set of parameters\n"); + log(" is provided.\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Connecting to RPC frontend.\n"); + + std::vector command; + std::string path; + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-exec" && argidx+1 < args.size()) { + command.insert(command.begin(), args.begin() + argidx + 1, args.end()); + continue; + } + if (arg == "-path" && argidx+1 < args.size()) { + path = args[argidx+1]; + continue; + } + break; + } + extra_args(args, argidx, design); + + if ((!command.empty()) + (!path.empty()) != 1) + log_cmd_error("Exactly one of -exec, -unix must be specified.\n"); + + std::shared_ptr server; + if (!command.empty()) { + std::string command_line; + bool first = true; + for (auto &arg : command) { + if (!first) command_line += ' '; + command_line += arg; + first = false; + } + +#ifdef _WIN32 + std::wstring command_w = str2wstr(command[0]); + std::wstring command_path_w; + std::wstring command_line_w = str2wstr(command_line); + DWORD command_path_len_w; + SECURITY_ATTRIBUTES pipe_attr = {}; + HANDLE send_r = NULL, send_w = NULL, recv_r = NULL, recv_w = NULL; + STARTUPINFOW startup_info = {}; + PROCESS_INFORMATION proc_info = {}; + + command_path_len_w = SearchPathW(/*lpPath=*/NULL, /*lpFileName=*/command_w.c_str(), /*lpExtension=*/L".exe", /*nBufferLength=*/0, /*lpBuffer=*/NULL, /*lpFilePart=*/NULL); + if (command_path_len_w == 0) { + log_error("SearchPathW failed: %s\n", get_last_error_str().c_str()); + goto cleanup_exec; + } + command_path_w.resize(command_path_len_w - 1); + command_path_len_w = SearchPathW(/*lpPath=*/NULL, /*lpFileName=*/command_w.c_str(), /*lpExtension=*/L".exe", /*nBufferLength=*/command_path_len_w, /*lpBuffer=*/&command_path_w[0], /*lpFilePart=*/NULL); + log_assert(command_path_len_w == command_path_w.length()); + + pipe_attr.nLength = sizeof(pipe_attr); + pipe_attr.bInheritHandle = TRUE; + pipe_attr.lpSecurityDescriptor = NULL; + if (!CreatePipe(&send_r, &send_w, &pipe_attr, /*nSize=*/0)) { + log_error("CreatePipe failed: %s\n", get_last_error_str().c_str()); + goto cleanup_exec; + } + if (!SetHandleInformation(send_w, HANDLE_FLAG_INHERIT, 0)) { + log_error("SetHandleInformation failed: %s\n", get_last_error_str().c_str()); + goto cleanup_exec; + } + if (!CreatePipe(&recv_r, &recv_w, &pipe_attr, /*nSize=*/0)) { + log_error("CreatePipe failed: %s\n", get_last_error_str().c_str()); + goto cleanup_exec; + } + if (!SetHandleInformation(recv_r, HANDLE_FLAG_INHERIT, 0)) { + log_error("SetHandleInformation failed: %s\n", get_last_error_str().c_str()); + goto cleanup_exec; + } + + startup_info.cb = sizeof(startup_info); + startup_info.hStdInput = send_r; + startup_info.hStdOutput = recv_w; + startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); + startup_info.dwFlags |= STARTF_USESTDHANDLES; + if (!CreateProcessW(/*lpApplicationName=*/command_path_w.c_str(), /*lpCommandLine=*/&command_line_w[0], /*lpProcessAttributes=*/NULL, /*lpThreadAttributes=*/NULL, /*bInheritHandles=*/TRUE, /*dwCreationFlags=*/0, /*lpEnvironment=*/NULL, /*lpCurrentDirectory=*/NULL, &startup_info, &proc_info)) { + log_error("CreateProcessW failed: %s\n", get_last_error_str().c_str()); + goto cleanup_exec; + } + CloseHandle(proc_info.hProcess); + CloseHandle(proc_info.hThread); + + server = std::make_shared(path, send_w, recv_r); + send_w = NULL; + recv_r = NULL; + +cleanup_exec: + if (send_r != NULL) CloseHandle(send_r); + if (send_w != NULL) CloseHandle(send_w); + if (recv_r != NULL) CloseHandle(recv_r); + if (recv_w != NULL) CloseHandle(recv_w); +#else + std::vector argv; + int send[2] = {-1,-1}, recv[2] = {-1,-1}; + posix_spawn_file_actions_t file_actions, *file_actions_p = NULL; + pid_t pid; + + for (auto &arg : command) + argv.push_back(&arg[0]); + argv.push_back(nullptr); + + if (pipe(send) != 0) { + log_error("pipe failed: %s\n", strerror(errno)); + goto cleanup_exec; + } + if (pipe(recv) != 0) { + log_error("pipe failed: %s\n", strerror(errno)); + goto cleanup_exec; + } + + if (posix_spawn_file_actions_init(&file_actions) != 0) { + log_error("posix_spawn_file_actions_init failed: %s\n", strerror(errno)); + goto cleanup_exec; + } + file_actions_p = &file_actions; + if (posix_spawn_file_actions_adddup2(file_actions_p, send[0], STDIN_FILENO) != 0) { + log_error("posix_spawn_file_actions_adddup2 failed: %s\n", strerror(errno)); + goto cleanup_exec; + } + if (posix_spawn_file_actions_addclose(file_actions_p, send[1]) != 0) { + log_error("posix_spawn_file_actions_addclose failed: %s\n", strerror(errno)); + goto cleanup_exec; + } + if (posix_spawn_file_actions_adddup2(file_actions_p, recv[1], STDOUT_FILENO) != 0) { + log_error("posix_spawn_file_actions_adddup2 failed: %s\n", strerror(errno)); + goto cleanup_exec; + } + if (posix_spawn_file_actions_addclose(file_actions_p, recv[0]) != 0) { + log_error("posix_spawn_file_actions_addclose failed: %s\n", strerror(errno)); + goto cleanup_exec; + } + + if (posix_spawnp(&pid, argv[0], file_actions_p, /*attrp=*/NULL, argv.data(), environ) != 0) { + log_error("posix_spawnp failed: %s\n", strerror(errno)); + goto cleanup_exec; + } + + server = std::make_shared(command_line, send[1], recv[0], pid); + send[1] = -1; + recv[0] = -1; + +cleanup_exec: + if (send[0] != -1) close(send[0]); + if (send[1] != -1) close(send[1]); + if (recv[0] != -1) close(recv[0]); + if (recv[1] != -1) close(recv[1]); + if (file_actions_p != NULL) + posix_spawn_file_actions_destroy(file_actions_p); +#endif + } else if (!path.empty()) { +#ifdef _WIN32 + std::wstring path_w = str2wstr(path); + HANDLE h; + + h = CreateFileW(path_w.c_str(), GENERIC_READ|GENERIC_WRITE, /*dwShareMode=*/0, /*lpSecurityAttributes=*/NULL, /*dwCreationDisposition=*/OPEN_EXISTING, /*dwFlagsAndAttributes=*/0, /*hTemplateFile=*/NULL); + if (h == INVALID_HANDLE_VALUE) { + log_error("CreateFileW failed: %s\n", get_last_error_str().c_str()); + goto cleanup_path; + } + + server = std::make_shared(path, h, h); + +cleanup_path: + ; +#else + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1); + + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + log_error("socket failed: %s\n", strerror(errno)); + goto cleanup_path; + } + + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { + log_error("connect failed: %s\n", strerror(errno)); + goto cleanup_path; + } + + server = std::make_shared(path, fd, fd); + fd = -1; + +cleanup_path: + if (fd != -1) close(fd); +#endif + } + + if (!server) + log_cmd_error("Failed to connect to RPC frontend.\n"); + + for (auto &module_name : server->get_module_names()) { + log("Linking module `%s'.\n", module_name.c_str()); + RpcModule *module = new RpcModule; + module->name = "$abstract\\" + module_name; + module->server = server; + design->add(module); + } + } +} RpcFrontend; + +YOSYS_NAMESPACE_END -- cgit v1.2.3