diff options
Diffstat (limited to 'backends')
-rw-r--r-- | backends/aiger/xaiger.cc | 315 | ||||
-rw-r--r-- | backends/blif/blif.cc | 26 | ||||
-rw-r--r-- | backends/btor/btor.cc | 8 | ||||
-rw-r--r-- | backends/firrtl/firrtl.cc | 100 | ||||
-rw-r--r-- | backends/ilang/ilang_backend.cc | 5 | ||||
-rw-r--r-- | backends/json/json.cc | 115 | ||||
-rw-r--r-- | backends/verilog/verilog_backend.cc | 132 |
7 files changed, 502 insertions, 199 deletions
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 7126002f6..7a139f68f 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -49,7 +49,8 @@ struct XAigerWriter dict<SigBit, SigBit> not_map, ff_map, alias_map; dict<SigBit, pair<SigBit, SigBit>> and_map; //pool<SigBit> initstate_bits; - vector<std::pair<SigBit,int>> ci_bits, co_bits; + vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int>> ci_bits; + vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int,int>> co_bits; vector<std::pair<SigBit,SigBit>> ff_bits; vector<pair<int, int>> aig_gates; @@ -152,10 +153,11 @@ struct XAigerWriter undriven_bits.insert(bit); unused_bits.insert(bit); - if (wire->port_input) - input_bits.insert(bit); - else if (keep) + if (wire->port_input || keep) { + if (bit != wirebit) + alias_map[bit] = wirebit; input_bits.insert(wirebit); + } if (wire->port_output || keep) { if (bit != wirebit) @@ -166,7 +168,7 @@ struct XAigerWriter } for (auto bit : input_bits) - undriven_bits.erase(bit); + undriven_bits.erase(sigmap(bit)); for (auto bit : output_bits) if (!bit.wire->port_input) @@ -303,8 +305,10 @@ struct XAigerWriter } } if (is_output) { + input_bits.insert(b); SigBit O = sigmap(b); - input_bits.insert(O); + if (O != b) + alias_map[O] = b; undriven_bits.erase(O); } } @@ -321,46 +325,109 @@ struct XAigerWriter for (auto user_cell : it.second) toposort.edge(driver_cell, user_cell); -#ifndef NDEBUG - toposort.analyze_loops = true; -#endif - toposort.sort(); -#ifndef NDEBUG - for (auto &it : toposort.loops) { - log(" loop"); - for (auto cell : it) - log(" %s", log_id(cell)); - log("\n"); - } -#endif - log_assert(!toposort.found_loops); + pool<RTLIL::Module*> abc_carry_modules; + toposort.sort(); for (auto cell_name : toposort.sorted) { RTLIL::Cell *cell = module->cell(cell_name); RTLIL::Module* box_module = module->design->module(cell->type); if (!box_module || !box_module->attributes.count("\\abc_box_id")) continue; - // Box ordering is alphabetical - cell->connections_.sort(RTLIL::sort_by_id_str()); - for (const auto &c : cell->connections()) { - for (auto b : c.second.bits()) { - auto is_input = cell->input(c.first); - auto is_output = cell->output(c.first); - log_assert(is_input || is_output); - if (is_input) { + 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) { + RTLIL::Wire* w = box_module->wire(port_name); + log_assert(w); + if (w->port_input) { + if (w->attributes.count("\\abc_carry_in")) { + log_assert(!carry_in); + carry_in = w; + } + log_assert(!last_in || last_in->port_id < w->port_id); + last_in = w; + } + if (w->port_output) { + if (w->attributes.count("\\abc_carry_out")) { + log_assert(!carry_out); + carry_out = w; + } + log_assert(!last_out || last_out->port_id < w->port_id); + last_out = w; + } + } + + if (carry_in) { + log_assert(last_in); + std::swap(box_module->ports[carry_in->port_id-1], box_module->ports[last_in->port_id-1]); + std::swap(carry_in->port_id, last_in->port_id); + } + if (carry_out) { + log_assert(last_out); + std::swap(box_module->ports[carry_out->port_id-1], box_module->ports[last_out->port_id-1]); + std::swap(carry_out->port_id, last_out->port_id); + } + } + + // Fully pad all unused input connections of this box cell with S0 + // Fully pad all undriven output connections of this box cell with anonymous wires + // NB: Assume box_module->ports are sorted alphabetically + // (as RTLIL::Module::fixup_ports() would do) + for (const auto &port_name : box_module->ports) { + RTLIL::Wire* w = box_module->wire(port_name); + log_assert(w); + auto it = cell->connections_.find(port_name); + if (w->port_input) { + RTLIL::SigSpec rhs; + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(RTLIL::SigSpec(RTLIL::S0, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + rhs = RTLIL::SigSpec(RTLIL::S0, GetSize(w)); + cell->setPort(port_name, rhs); + } + + int offset = 0; + for (const auto &b : rhs.bits()) { SigBit I = sigmap(b); if (I != b) alias_map[b] = I; - co_bits.emplace_back(b, 0); + co_bits.emplace_back(b, cell, port_name, offset++, 0); + unused_bits.erase(b); } - if (is_output) { + } + if (w->port_output) { + RTLIL::SigSpec rhs; + auto it = cell->connections_.find(w->name); + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + rhs = module->addWire(NEW_ID, GetSize(w)); + cell->setPort(port_name, rhs); + } + + int offset = 0; + for (const auto &b : rhs.bits()) { + ci_bits.emplace_back(b, cell, port_name, offset++); SigBit O = sigmap(b); - ci_bits.emplace_back(O, 0); + if (O != b) + alias_map[O] = b; + undriven_bits.erase(O); + + auto jt = input_bits.find(b); + if (jt != input_bits.end()) { + log_assert(b.wire->attributes.count("\\keep")); + input_bits.erase(b); + } } } } - box_list.emplace_back(cell); } @@ -375,9 +442,10 @@ struct XAigerWriter if ((wire->port_input && wire->port_output && !undriven_bits.count(bit)) || wire->attributes.count("\\keep")) { log_assert(input_bits.count(bit) && output_bits.count(bit)); - RTLIL::Wire *new_wire = module->wire(wire->name.str() + "$inout.out"); + RTLIL::IdString wire_name = wire->name.str() + "$inout.out"; + RTLIL::Wire *new_wire = module->wire(wire_name); if (!new_wire) - new_wire = module->addWire(wire->name.str() + "$inout.out", GetSize(wire)); + new_wire = module->addWire(wire_name, GetSize(wire)); SigBit new_bit(new_wire, bit.offset); module->connect(new_bit, bit); if (not_map.count(bit)) @@ -394,13 +462,10 @@ struct XAigerWriter } } - // Do some CI/CO post-processing: // Erase all POs that are undriven - for (auto bit : undriven_bits) - output_bits.erase(bit); - // CIs cannot be undriven - for (const auto &c : ci_bits) - undriven_bits.erase(c.first); + if (!holes_mode) + for (auto bit : undriven_bits) + output_bits.erase(bit); for (auto bit : unused_bits) undriven_bits.erase(bit); @@ -414,8 +479,20 @@ struct XAigerWriter } init_map.sort(); - input_bits.sort(); - output_bits.sort(); + if (holes_mode) { + struct sort_by_port_id { + bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const { + return a.wire->port_id < b.wire->port_id; + } + }; + input_bits.sort(sort_by_port_id()); + output_bits.sort(sort_by_port_id()); + } + else { + input_bits.sort(); + output_bits.sort(); + } + not_map.sort(); ff_map.sort(); and_map.sort(); @@ -425,6 +502,7 @@ struct XAigerWriter for (auto bit : input_bits) { aig_m++, aig_i++; + log_assert(!aig_map.count(bit)); aig_map[bit] = 2*aig_m; } @@ -436,12 +514,14 @@ struct XAigerWriter dict<SigBit, int> ff_aig_map; for (auto &c : ci_bits) { + RTLIL::SigBit bit = std::get<0>(c); aig_m++, aig_i++; - c.second = 2*aig_m; - auto r = aig_map.insert(std::make_pair(c.first, c.second)); - if (!r.second) { - ff_aig_map[c.first] = c.second; - } + log_assert(!aig_map.count(bit)); + aig_map[bit] = 2*aig_m; + //auto r = aig_map.insert(std::make_pair(c.first, c.second)); + //if (!r.second) { + // ff_aig_map[std::get<0>(c)] = 2*aig_m; + //} } if (imode && input_bits.empty()) { @@ -505,9 +585,8 @@ struct XAigerWriter // aig_latchin.push_back(1); for (auto &c : co_bits) { - RTLIL::SigBit bit = c.first; - c.second = aig_o++; - ordered_outputs[bit] = c.second; + RTLIL::SigBit bit = std::get<0>(c); + std::get<4>(c) = ordered_outputs[bit] = aig_o++; aig_outputs.push_back(bit2aig(bit)); } @@ -693,49 +772,77 @@ struct XAigerWriter if (omode && num_outputs == 0) num_outputs = 1; write_h_buffer(1); + log_debug("ciNum = %zu\n", input_bits.size() + ff_bits.size() + ci_bits.size()); write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size()); - write_h_buffer(num_outputs + ff_bits.size() + co_bits.size()); - write_h_buffer(input_bits.size() + ff_bits.size()); - write_h_buffer(num_outputs + ff_bits.size()); + log_debug("coNum = %zu\n", num_outputs + ff_bits.size() + co_bits.size()); + write_h_buffer(num_outputs + ff_bits.size()+ co_bits.size()); + log_debug("piNum = %zu\n", input_bits.size() + ff_bits.size()); + write_h_buffer(input_bits.size()+ ff_bits.size()); + log_debug("poNum = %d\n", num_outputs); + write_h_buffer(num_outputs); + log_debug("boxNum = %zu\n", box_list.size()); write_h_buffer(box_list.size()); RTLIL::Module *holes_module = nullptr; holes_module = module->design->addModule("\\__holes__"); + log_assert(holes_module); + int port_id = 1; + int box_count = 0; for (auto cell : box_list) { + RTLIL::Module* box_module = module->design->module(cell->type); int box_inputs = 0, box_outputs = 0; - int box_id = module->design->module(cell->type)->attributes.at("\\abc_box_id").as_int(); Cell *holes_cell = nullptr; - if (holes_module && !holes_module->cell(stringf("\\u%d", box_id))) - holes_cell = holes_module->addCell(stringf("\\u%d", box_id), cell->type); - RTLIL::Wire *holes_wire; - // NB: cell->connections_ already sorted from before - for (const auto &c : cell->connections()) { - log_assert(c.second.size() == 1); - if (cell->input(c.first)) { - box_inputs += c.second.size(); - if (holes_cell) { + if (box_module->get_bool_attribute("\\whitebox")) + holes_cell = holes_module->addCell(cell->name, cell->type); + + // NB: Assume box_module->ports are sorted alphabetically + // (as RTLIL::Module::fixup_ports() would do) + for (const auto &port_name : box_module->ports) { + RTLIL::Wire *w = box_module->wire(port_name); + log_assert(w); + RTLIL::Wire *holes_wire; + RTLIL::SigSpec port_wire; + if (w->port_input) { + for (int i = 0; i < GetSize(w); i++) { + box_inputs++; holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); if (!holes_wire) { holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs)); holes_wire->port_input = true; + holes_wire->port_id = port_id++; + holes_module->ports.push_back(holes_wire->name); } - holes_cell->setPort(c.first, holes_wire); + if (holes_cell) + port_wire.append(holes_wire); } + if (!port_wire.empty()) + holes_cell->setPort(w->name, port_wire); } - if (cell->output(c.first)) { - box_outputs += c.second.size(); - if (holes_cell) { - holes_wire = holes_module->addWire(stringf("\\%s.%s", cell->type.c_str(), c.first.c_str())); + if (w->port_output) { + box_outputs += GetSize(w); + for (int i = 0; i < GetSize(w); i++) { + if (GetSize(w) == 1) + holes_wire = holes_module->addWire(stringf("%s.%s", cell->name.c_str(), w->name.c_str())); + else + holes_wire = holes_module->addWire(stringf("%s.%s[%d]", cell->name.c_str(), w->name.c_str(), i)); holes_wire->port_output = true; - holes_cell->setPort(c.first, holes_wire); + holes_wire->port_id = port_id++; + holes_module->ports.push_back(holes_wire->name); + if (holes_cell) + port_wire.append(holes_wire); + else + holes_module->connect(holes_wire, RTLIL::S0); } + if (!port_wire.empty()) + holes_cell->setPort(w->name, port_wire); } } + write_h_buffer(box_inputs); write_h_buffer(box_outputs); - write_h_buffer(box_id); - write_h_buffer(0 /* OldBoxNum */); + write_h_buffer(box_module->attributes.at("\\abc_box_id").as_int()); + write_h_buffer(box_count++); } f << "h"; @@ -778,13 +885,25 @@ struct XAigerWriter } if (holes_module) { - holes_module->fixup_ports(); + // NB: fixup_ports() will sort ports by name + //holes_module->fixup_ports(); + holes_module->check(); holes_module->design->selection_stack.emplace_back(false); RTLIL::Selection& sel = holes_module->design->selection_stack.back(); sel.select(holes_module); - Pass::call(holes_module->design, "flatten -wb; aigmap; clean -purge"); + // TODO: Should not need to opt_merge if we only instantiate + // each box type once... + Pass::call(holes_module->design, "opt_merge -share_all"); + + Pass::call(holes_module->design, "flatten -wb"); + + // TODO: Should techmap all lib_whitebox-es once + //Pass::call(holes_module->design, "techmap"); + + Pass::call(holes_module->design, "aigmap"); + Pass::call(holes_module->design, "clean -purge"); holes_module->design->selection_stack.pop_back(); @@ -804,6 +923,29 @@ struct XAigerWriter f.write(buffer_str.data(), buffer_str.size()); holes_module->design->remove(holes_module); } + + std::stringstream r_buffer; + auto write_r_buffer = [&r_buffer](int i32) { + // TODO: Don't assume we're on little endian +#ifdef _WIN32 + int i32_be = _byteswap_ulong(i32); +#else + int i32_be = __builtin_bswap32(i32); +#endif + r_buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be)); + }; + write_r_buffer(0); + + f << "r"; + buffer_str = r_buffer.str(); + // TODO: Don't assume we're on little endian +#ifdef _WIN32 + buffer_size_be = _byteswap_ulong(buffer_str.size()); +#else + buffer_size_be = __builtin_bswap32(buffer_str.size()); +#endif + f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); + f.write(buffer_str.data(), buffer_str.size()); } f << stringf("Generated by %s\n", yosys_version_str); @@ -835,7 +977,7 @@ struct XAigerWriter if (output_bits.count(b)) { int o = ordered_outputs.at(b); - output_lines[o] += stringf("output %d %d %s\n", o, i, log_id(wire)); + output_lines[o] += stringf("output %lu %d %s\n", o - co_bits.size(), i, log_id(wire)); continue; } @@ -865,38 +1007,23 @@ struct XAigerWriter } } - for (const auto &c : ci_bits) { - RTLIL::SigBit b = c.first; - RTLIL::Wire *wire = b.wire; - int i = b.offset; - int a = bit2aig(b); - log_assert((a & 1) == 0); - input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire)); - } - - for (const auto &c : co_bits) { - RTLIL::SigBit b = c.first; - RTLIL::Wire *wire = b.wire; - int o = c.second; - if (wire) - output_lines[o] += stringf("output %d %d %s\n", o, b.offset, log_id(wire)); - else - output_lines[o] += stringf("output %d %d __const%d__\n", o, 0, b.data); - } - input_lines.sort(); for (auto &it : input_lines) f << it.second; - log_assert(input_lines.size() == input_bits.size() + ci_bits.size()); + log_assert(input_lines.size() == input_bits.size()); init_lines.sort(); for (auto &it : init_lines) f << it.second; + int box_count = 0; + for (auto cell : box_list) + f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name)); + output_lines.sort(); for (auto &it : output_lines) f << it.second; - log_assert(output_lines.size() == output_bits.size() + co_bits.size()); + log_assert(output_lines.size() == output_bits.size()); if (omode && output_bits.empty()) f << "output " << output_lines.size() << " 0 __dummy_o__\n"; diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc index b6dbd84cb..a1761b662 100644 --- a/backends/blif/blif.cc +++ b/backends/blif/blif.cc @@ -409,12 +409,26 @@ struct BlifDumper f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type)); for (auto &conn : cell->connections()) - for (int i = 0; i < conn.second.size(); i++) { - if (conn.second.size() == 1) - f << stringf(" %s", cstr(conn.first)); - else - f << stringf(" %s[%d]", cstr(conn.first), i); - f << stringf("=%s", cstr(conn.second.extract(i, 1))); + { + if (conn.second.size() == 1) { + f << stringf(" %s=%s", cstr(conn.first), cstr(conn.second[0])); + continue; + } + + Module *m = design->module(cell->type); + Wire *w = m ? m->wire(conn.first) : nullptr; + + if (w == nullptr) { + for (int i = 0; i < GetSize(conn.second); i++) + f << stringf(" %s[%d]=%s", cstr(conn.first), i, cstr(conn.second[i])); + } else { + for (int i = 0; i < std::min(GetSize(conn.second), GetSize(w)); i++) { + SigBit sig(w, i); + f << stringf(" %s[%d]=%s", cstr(conn.first), sig.wire->upto ? + sig.wire->start_offset+sig.wire->width-sig.offset-1 : + sig.wire->start_offset+sig.offset, cstr(conn.second[i])); + } + } } f << stringf("\n"); diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 91f238fa5..511a11942 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -129,7 +129,13 @@ struct BtorWorker void export_cell(Cell *cell) { - log_assert(cell_recursion_guard.count(cell) == 0); + if (cell_recursion_guard.count(cell)) { + string cell_list; + for (auto c : cell_recursion_guard) + cell_list += stringf("\n %s", log_id(c)); + log_error("Found topological loop while processing cell %s. Active cells:%s\n", log_id(cell), cell_list.c_str()); + } + cell_recursion_guard.insert(cell); btorf_push(log_id(cell)); diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index ed6e9f8ee..1c7a7351f 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -146,7 +146,7 @@ struct FirrtlWorker if (!mask.is_fully_def()) this->ena = SigSpec(RTLIL::Const(1)); } - string gen_read(const char * /* indent */) { + string gen_read(const char * /* indent */) { log_error("gen_read called on write_port: %s\n", name.c_str()); return stringf("gen_read called on write_port: %s\n", name.c_str()); } @@ -163,31 +163,61 @@ struct FirrtlWorker } }; /* Memories defined within this module. */ - struct memory { - string name; // memory name - int abits; // number of address bits - int size; // size (in units) of the memory - int width; // size (in bits) of each element - int read_latency; - int write_latency; - vector<read_port> read_ports; - vector<write_port> write_ports; - std::string init_file; - std::string init_file_srcFileSpec; - memory(string name, int abits, int size, int width) : name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {} - memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} - void add_memory_read_port(read_port &rp) { - read_ports.push_back(rp); - } - void add_memory_write_port(write_port &wp) { - write_ports.push_back(wp); - } - void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) { - this->init_file = init_file; - this->init_file_srcFileSpec = init_file_srcFileSpec; + struct memory { + Cell *pCell; // for error reporting + string name; // memory name + int abits; // number of address bits + int size; // size (in units) of the memory + int width; // size (in bits) of each element + int read_latency; + int write_latency; + vector<read_port> read_ports; + vector<write_port> write_ports; + std::string init_file; + std::string init_file_srcFileSpec; + string srcLine; + memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") { + // Provide defaults for abits or size if one (but not the other) is specified. + if (this->abits == 0 && this->size != 0) { + this->abits = ceil_log2(this->size); + } else if (this->abits != 0 && this->size == 0) { + this->size = 1 << this->abits; + } + // Sanity-check this construction. + if (this->name == "") { + log_error("Nameless memory%s\n", this->atLine()); + } + if (this->abits == 0 && this->size == 0) { + log_error("Memory %s has zero address bits and size%s\n", this->name.c_str(), this->atLine()); + } + if (this->width == 0) { + log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine()); + } } + // We need a default constructor for the dict insert. + memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} + + const char *atLine() { + if (srcLine == "") { + if (pCell) { + auto p = pCell->attributes.find("\\src"); + srcLine = " at " + p->second.decode_string(); + } + } + return srcLine.c_str(); + } + void add_memory_read_port(read_port &rp) { + read_ports.push_back(rp); + } + void add_memory_write_port(write_port &wp) { + write_ports.push_back(wp); + } + void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) { + this->init_file = init_file; + this->init_file_srcFileSpec = init_file_srcFileSpec; + } - }; + }; dict<string, memory> memories; void register_memory(memory &m) @@ -314,6 +344,7 @@ struct FirrtlWorker switch (dir) { case FD_INOUT: log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); + /* FALLTHRU */ case FD_OUT: sourceExpr = firstName; sinkExpr = secondExpr; @@ -321,7 +352,7 @@ struct FirrtlWorker break; case FD_NODIRECTION: log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); - /* FALL_THROUGH */ + /* FALLTHRU */ case FD_IN: sourceExpr = secondExpr; sinkExpr = firstName; @@ -418,8 +449,10 @@ struct FirrtlWorker string primop; bool always_uint = false; if (cell->type == "$not") primop = "not"; - else if (cell->type == "$neg") primop = "neg"; - else if (cell->type == "$logic_not") { + else if (cell->type == "$neg") { + primop = "neg"; + is_signed = true; // Result of "neg" is signed (an SInt). + } else if (cell->type == "$logic_not") { primop = "eq"; a_expr = stringf("%s, UInt(0)", a_expr.c_str()); } @@ -531,6 +564,7 @@ struct FirrtlWorker auto b_sig = cell->getPort("\\B"); if (b_sig.is_fully_const()) { primop = "shl"; + b_expr = std::to_string(b_sig.as_int()); } else { primop = "dshl"; // Convert from FIRRTL left shift semantics. @@ -544,6 +578,7 @@ struct FirrtlWorker auto b_sig = cell->getPort("\\B"); if (b_sig.is_fully_const()) { primop = "shr"; + b_expr = std::to_string(b_sig.as_int()); } else { primop = "dshr"; } @@ -604,7 +639,7 @@ struct FirrtlWorker int abits = cell->parameters.at("\\ABITS").as_int(); int width = cell->parameters.at("\\WIDTH").as_int(); int size = cell->parameters.at("\\SIZE").as_int(); - memory m(mem_id, abits, size, width); + memory m(cell, mem_id, abits, size, width); int rd_ports = cell->parameters.at("\\RD_PORTS").as_int(); int wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); @@ -681,6 +716,8 @@ struct FirrtlWorker { std::string cell_type = fid(cell->type); std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string()); + int abits = cell->parameters.at("\\ABITS").as_int(); + int width = cell->parameters.at("\\WIDTH").as_int(); memory *mp = nullptr; if (cell->type == "$meminit" ) { log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str()); @@ -693,6 +730,11 @@ struct FirrtlWorker Const clk_enable = cell->parameters.at("\\CLK_ENABLE"); Const clk_polarity = cell->parameters.at("\\CLK_POLARITY"); + // Do we already have an entry for this memory? + if (memories.count(mem_id) == 0) { + memory m(cell, mem_id, abits, 0, width); + register_memory(m); + } mp = &memories.at(mem_id); int portNum = 0; bool transparency = false; @@ -890,7 +932,7 @@ struct FirrtlWorker // If we have any memory definitions, output them. for (auto kv : memories) { - memory m = kv.second; + memory &m = kv.second; f << stringf(" mem %s:\n", m.name.c_str()); f << stringf(" data-type => UInt<%d>\n", m.width); f << stringf(" depth => %d\n", m.size); diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc index dc39e5e08..04d1ee311 100644 --- a/backends/ilang/ilang_backend.cc +++ b/backends/ilang/ilang_backend.cc @@ -160,7 +160,10 @@ void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL:: } f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str()); for (auto &it : cell->parameters) { - f << stringf("%s parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str()); + f << stringf("%s parameter%s%s %s ", indent.c_str(), + (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", + (it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "", + it.first.c_str()); dump_const(f, it.second); f << stringf("\n"); } diff --git a/backends/json/json.cc b/backends/json/json.cc index b4f82a3fe..f5c687981 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -130,75 +130,72 @@ struct JsonWriter f << stringf(" }"); first = false; } - f << stringf("\n }"); + f << stringf("\n },\n"); - if (!module->get_blackbox_attribute()) { - f << stringf(",\n \"cells\": {"); - first = true; - for (auto c : module->cells()) { - if (use_selection && !module->selected(c)) - continue; - f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s: {\n", get_name(c->name).c_str()); - f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0"); - f << stringf(" \"type\": %s,\n", get_name(c->type).c_str()); - if (aig_mode) { - Aig aig(c); - if (!aig.name.empty()) { - f << stringf(" \"model\": \"%s\",\n", aig.name.c_str()); - aig_models.insert(aig); - } - } - f << stringf(" \"parameters\": {"); - write_parameters(c->parameters); - f << stringf("\n },\n"); - f << stringf(" \"attributes\": {"); - write_parameters(c->attributes); - f << stringf("\n },\n"); - if (c->known()) { - f << stringf(" \"port_directions\": {"); - bool first2 = true; - for (auto &conn : c->connections()) { - string direction = "output"; - if (c->input(conn.first)) - direction = c->output(conn.first) ? "inout" : "input"; - f << stringf("%s\n", first2 ? "" : ","); - f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str()); - first2 = false; - } - f << stringf("\n },\n"); + f << stringf(" \"cells\": {"); + first = true; + for (auto c : module->cells()) { + if (use_selection && !module->selected(c)) + continue; + f << stringf("%s\n", first ? "" : ","); + f << stringf(" %s: {\n", get_name(c->name).c_str()); + f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0"); + f << stringf(" \"type\": %s,\n", get_name(c->type).c_str()); + if (aig_mode) { + Aig aig(c); + if (!aig.name.empty()) { + f << stringf(" \"model\": \"%s\",\n", aig.name.c_str()); + aig_models.insert(aig); } - f << stringf(" \"connections\": {"); + } + f << stringf(" \"parameters\": {"); + write_parameters(c->parameters); + f << stringf("\n },\n"); + f << stringf(" \"attributes\": {"); + write_parameters(c->attributes); + f << stringf("\n },\n"); + if (c->known()) { + f << stringf(" \"port_directions\": {"); bool first2 = true; for (auto &conn : c->connections()) { + string direction = "output"; + if (c->input(conn.first)) + direction = c->output(conn.first) ? "inout" : "input"; f << stringf("%s\n", first2 ? "" : ","); - f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str()); + f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str()); first2 = false; } - f << stringf("\n }\n"); - f << stringf(" }"); - first = false; + f << stringf("\n },\n"); } - f << stringf("\n },\n"); - - f << stringf(" \"netnames\": {"); - first = true; - for (auto w : module->wires()) { - if (use_selection && !module->selected(w)) - continue; - f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s: {\n", get_name(w->name).c_str()); - f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0"); - f << stringf(" \"bits\": %s,\n", get_bits(w).c_str()); - f << stringf(" \"attributes\": {"); - write_parameters(w->attributes); - f << stringf("\n }\n"); - f << stringf(" }"); - first = false; + f << stringf(" \"connections\": {"); + bool first2 = true; + for (auto &conn : c->connections()) { + f << stringf("%s\n", first2 ? "" : ","); + f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str()); + first2 = false; } - f << stringf("\n }"); + f << stringf("\n }\n"); + f << stringf(" }"); + first = false; + } + f << stringf("\n },\n"); + + f << stringf(" \"netnames\": {"); + first = true; + for (auto w : module->wires()) { + if (use_selection && !module->selected(w)) + continue; + f << stringf("%s\n", first ? "" : ","); + f << stringf(" %s: {\n", get_name(w->name).c_str()); + f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0"); + f << stringf(" \"bits\": %s,\n", get_bits(w).c_str()); + f << stringf(" \"attributes\": {"); + write_parameters(w->attributes); + f << stringf("\n }\n"); + f << stringf(" }"); + first = false; } - f << stringf("\n"); + f << stringf("\n }\n"); f << stringf(" }"); } diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 9967482d6..827af5d85 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -183,8 +183,9 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name) return true; } -void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false) +void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool escape_comment = false) { + bool set_signed = (data.flags & RTLIL::CONST_FLAG_SIGNED) != 0; if (width < 0) width = data.bits.size() - offset; if (width == 0) { @@ -275,7 +276,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o } } } else { - f << stringf("\""); + if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0) + f << stringf("\""); std::string str = data.decode_string(); for (size_t i = 0; i < str.size(); i++) { if (str[i] == '\n') @@ -293,7 +295,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o else f << str[i]; } - f << stringf("\""); + if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0) + f << stringf("\""); } } @@ -373,7 +376,7 @@ void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, else if (modattr && (it->second == Const(1, 1) || it->second == Const(1))) f << stringf(" 1 "); else - dump_const(f, it->second, -1, 0, false, false, attr2comment); + dump_const(f, it->second, -1, 0, false, attr2comment); f << stringf(" %s%c", attr2comment ? "*/" : "*)", term); } } @@ -1242,6 +1245,118 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } + if (cell->type.in("$assert", "$assume", "$cover")) + { + f << stringf("%s" "always @* if (", indent.c_str()); + dump_sigspec(f, cell->getPort("\\EN")); + f << stringf(") %s(", cell->type.c_str()+1); + dump_sigspec(f, cell->getPort("\\A")); + f << stringf(");\n"); + return true; + } + + if (cell->type.in("$specify2", "$specify3")) + { + f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str()); + + SigSpec en = cell->getPort("\\EN"); + if (en != State::S1) { + f << stringf("if ("); + dump_sigspec(f, cell->getPort("\\EN")); + f << stringf(") "); + } + + f << "("; + if (cell->type == "$specify3" && cell->getParam("\\EDGE_EN").as_bool()) + f << (cell->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge "); + + dump_sigspec(f, cell->getPort("\\SRC")); + + f << " "; + if (cell->getParam("\\SRC_DST_PEN").as_bool()) + f << (cell->getParam("\\SRC_DST_POL").as_bool() ? "+": "-"); + f << (cell->getParam("\\FULL").as_bool() ? "*> ": "=> "); + + if (cell->type == "$specify3") { + f << "("; + dump_sigspec(f, cell->getPort("\\DST")); + f << " "; + if (cell->getParam("\\DAT_DST_PEN").as_bool()) + f << (cell->getParam("\\DAT_DST_POL").as_bool() ? "+": "-"); + f << ": "; + dump_sigspec(f, cell->getPort("\\DAT")); + f << ")"; + } else { + dump_sigspec(f, cell->getPort("\\DST")); + } + + bool bak_decimal = decimal; + decimal = 1; + + f << ") = ("; + dump_const(f, cell->getParam("\\T_RISE_MIN")); + f << ":"; + dump_const(f, cell->getParam("\\T_RISE_TYP")); + f << ":"; + dump_const(f, cell->getParam("\\T_RISE_MAX")); + f << ", "; + dump_const(f, cell->getParam("\\T_FALL_MIN")); + f << ":"; + dump_const(f, cell->getParam("\\T_FALL_TYP")); + f << ":"; + dump_const(f, cell->getParam("\\T_FALL_MAX")); + f << ");\n"; + + decimal = bak_decimal; + + f << stringf("%s" "endspecify\n", indent.c_str()); + return true; + } + + if (cell->type == "$specrule") + { + f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str()); + + string spec_type = cell->getParam("\\TYPE").decode_string(); + f << stringf("%s(", spec_type.c_str()); + + if (cell->getParam("\\SRC_PEN").as_bool()) + f << (cell->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge "); + dump_sigspec(f, cell->getPort("\\SRC")); + + if (cell->getPort("\\SRC_EN") != State::S1) { + f << " &&& "; + dump_sigspec(f, cell->getPort("\\SRC_EN")); + } + + f << ", "; + if (cell->getParam("\\DST_PEN").as_bool()) + f << (cell->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge "); + dump_sigspec(f, cell->getPort("\\DST")); + + if (cell->getPort("\\DST_EN") != State::S1) { + f << " &&& "; + dump_sigspec(f, cell->getPort("\\DST_EN")); + } + + bool bak_decimal = decimal; + decimal = 1; + + f << ", "; + dump_const(f, cell->getParam("\\T_LIMIT")); + + if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") { + f << ", "; + dump_const(f, cell->getParam("\\T_LIMIT2")); + } + + f << ");\n"; + decimal = bak_decimal; + + f << stringf("%s" "endspecify\n", indent.c_str()); + return true; + } + // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_ // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm @@ -1264,8 +1379,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) if (it != cell->parameters.begin()) f << stringf(","); f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str()); - bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; - dump_const(f, it->second, -1, 0, false, is_signed); + dump_const(f, it->second); f << stringf(")"); } f << stringf("\n%s" ")", indent.c_str()); @@ -1312,8 +1426,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) if (defparam && cell->parameters.size() > 0) { for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str()); - bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; - dump_const(f, it->second, -1, 0, false, is_signed); + dump_const(f, it->second); f << stringf(";\n"); } } @@ -1505,7 +1618,8 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) SigSpec sig = active_sigmap(wire); Const val = wire->attributes.at("\\init"); for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++) - active_initdata[sig[i]] = val.bits.at(i); + if (val[i] == State::S0 || val[i] == State::S1) + active_initdata[sig[i]] = val[i]; } if (!module->processes.empty()) |