Merge branch 'master' into struct

This commit is contained in:
Peter Crozier 2020-06-03 17:19:28 +01:00 committed by GitHub
commit 0d3f7ea011
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
154 changed files with 4100 additions and 2459 deletions

View File

@ -66,6 +66,7 @@ Yosys 0.9 .. Yosys 0.9-dev
- Added "design -delete" - Added "design -delete"
- Added "select -unset" - Added "select -unset"
- Use YosysHQ/abc instead of upstream berkeley-abc/abc - Use YosysHQ/abc instead of upstream berkeley-abc/abc
- Added $divfloor and $modfloor cells
Yosys 0.8 .. Yosys 0.9 Yosys 0.8 .. Yosys 0.9
---------------------- ----------------------

View File

@ -717,7 +717,7 @@ ifneq ($(ABCREV),default)
echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \ echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
fi fi
# set a variable so the test fails if git fails to run - when comparing outputs directly, empty string would match empty string # set a variable so the test fails if git fails to run - when comparing outputs directly, empty string would match empty string
$(Q) if ! (cd abc && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \ $(Q) if ! (cd abc 2> /dev/null && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \
test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \ test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \
echo "Pulling ABC from $(ABCURL):"; set -x; \ echo "Pulling ABC from $(ABCURL):"; set -x; \
test -d abc || git clone $(ABCURL) abc; \ test -d abc || git clone $(ABCURL) abc; \
@ -780,6 +780,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT) +cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT)
+cd tests/rpc && bash run-test.sh +cd tests/rpc && bash run-test.sh
+cd tests/memfile && bash run-test.sh +cd tests/memfile && bash run-test.sh
+cd tests/verilog && bash run-test.sh
@echo "" @echo ""
@echo " Passed \"make test\"." @echo " Passed \"make test\"."
@echo "" @echo ""

View File

@ -76,9 +76,11 @@ void aiger_encode(std::ostream &f, int x)
struct XAigerWriter struct XAigerWriter
{ {
Design *design;
Module *module; Module *module;
SigMap sigmap; SigMap sigmap;
dict<SigBit, State> init_map;
pool<SigBit> input_bits, output_bits; pool<SigBit> input_bits, output_bits;
dict<SigBit, SigBit> not_map, alias_map; dict<SigBit, SigBit> not_map, alias_map;
dict<SigBit, pair<SigBit, SigBit>> and_map; dict<SigBit, pair<SigBit, SigBit>> and_map;
@ -137,7 +139,7 @@ struct XAigerWriter
return a; return a;
} }
XAigerWriter(Module *module, bool holes_mode=false) : module(module), sigmap(module) XAigerWriter(Module *module, bool dff_mode) : design(module->design), module(module), sigmap(module)
{ {
pool<SigBit> undriven_bits; pool<SigBit> undriven_bits;
pool<SigBit> unused_bits; pool<SigBit> unused_bits;
@ -157,7 +159,8 @@ struct XAigerWriter
if (wire->get_bool_attribute(ID::keep)) if (wire->get_bool_attribute(ID::keep))
sigmap.add(wire); sigmap.add(wire);
for (auto wire : module->wires()) for (auto wire : module->wires()) {
auto it = wire->attributes.find(ID::init);
for (int i = 0; i < GetSize(wire); i++) for (int i = 0; i < GetSize(wire); i++)
{ {
SigBit wirebit(wire, i); SigBit wirebit(wire, i);
@ -174,17 +177,27 @@ struct XAigerWriter
undriven_bits.insert(bit); undriven_bits.insert(bit);
unused_bits.insert(bit); unused_bits.insert(bit);
bool scc = wire->attributes.count(ID::abc9_scc); bool keep = wire->get_bool_attribute(ID::abc9_keep);
if (wire->port_input || scc) if (wire->port_input || keep)
input_bits.insert(bit); input_bits.insert(bit);
bool keep = wire->get_bool_attribute(ID::keep); keep = keep || wire->get_bool_attribute(ID::keep);
if (wire->port_output || keep || scc) { if (wire->port_output || keep) {
if (bit != wirebit) if (bit != wirebit)
alias_map[wirebit] = bit; alias_map[wirebit] = bit;
output_bits.insert(wirebit); output_bits.insert(wirebit);
} }
if (it != wire->attributes.end()) {
auto s = it->second[i];
if (s != State::Sx) {
auto r = init_map.insert(std::make_pair(bit, it->second[i]));
if (!r.second && r.first->second != it->second[i])
log_error("Bit '%s' has a conflicting (* init *) value.\n", log_signal(bit));
}
}
} }
}
TimingInfo timing; TimingInfo timing;
@ -212,10 +225,7 @@ struct XAigerWriter
continue; continue;
} }
if (cell->type == ID($__ABC9_FF_) && if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_)) && !cell->get_bool_attribute(ID::abc9_keep))
// The presence of an abc9_mergeability attribute indicates
// that we do want to pass this flop to ABC
cell->attributes.count(ID::abc9_mergeability))
{ {
SigBit D = sigmap(cell->getPort(ID::D).as_bit()); SigBit D = sigmap(cell->getPort(ID::D).as_bit());
SigBit Q = sigmap(cell->getPort(ID::Q).as_bit()); SigBit Q = sigmap(cell->getPort(ID::Q).as_bit());
@ -231,31 +241,29 @@ struct XAigerWriter
continue; continue;
} }
RTLIL::Module* inst_module = module->design->module(cell->type); RTLIL::Module* inst_module = design->module(cell->type);
if (inst_module) { if (inst_module && inst_module->get_blackbox_attribute()) {
IdString derived_type = inst_module->derive(module->design, cell->parameters);
inst_module = module->design->module(derived_type);
log_assert(inst_module);
bool abc9_flop = false; bool abc9_flop = false;
if (!cell->has_keep_attr()) {
auto it = cell->attributes.find(ID::abc9_box_seq); auto it = cell->attributes.find(ID::abc9_box_seq);
if (it != cell->attributes.end()) { if (it != cell->attributes.end()) {
int abc9_box_seq = it->second.as_int(); log_assert(!cell->has_keep_attr());
if (GetSize(box_list) <= abc9_box_seq) log_assert(cell->parameters.empty());
box_list.resize(abc9_box_seq+1); int abc9_box_seq = it->second.as_int();
box_list[abc9_box_seq] = cell; if (GetSize(box_list) <= abc9_box_seq)
// Only flop boxes may have arrival times box_list.resize(abc9_box_seq+1);
// (all others are combinatorial) box_list[abc9_box_seq] = cell;
abc9_flop = inst_module->get_bool_attribute(ID::abc9_flop); // Only flop boxes may have arrival times
if (!abc9_flop) // (all others are combinatorial)
continue; log_assert(cell->parameters.empty());
} abc9_flop = inst_module->get_bool_attribute(ID::abc9_flop);
if (!abc9_flop)
continue;
} }
if (!timing.count(derived_type)) if (!timing.count(inst_module->name))
timing.setup_module(inst_module); timing.setup_module(inst_module);
auto &t = timing.at(derived_type).arrival; auto &t = timing.at(inst_module->name).arrival;
for (const auto &conn : cell->connections()) { for (const auto &conn : cell->connections()) {
auto port_wire = inst_module->wire(conn.first); auto port_wire = inst_module->wire(conn.first);
if (!port_wire->port_output) if (!port_wire->port_output)
@ -269,7 +277,7 @@ struct XAigerWriter
#ifndef NDEBUG #ifndef NDEBUG
if (ys_debug(1)) { if (ys_debug(1)) {
static std::set<std::tuple<IdString,IdString,int>> seen; static std::set<std::tuple<IdString,IdString,int>> seen;
if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_arrival = %d\n", if (seen.emplace(inst_module->name, conn.first, i).second) log("%s.%s[%d] abc9_arrival = %d\n",
log_id(cell->type), log_id(conn.first), i, d); log_id(cell->type), log_id(conn.first), i, d);
} }
#endif #endif
@ -280,10 +288,6 @@ struct XAigerWriter
if (abc9_flop) if (abc9_flop)
continue; continue;
} }
else {
if (cell->type == ID($__ABC9_DELAY))
log_error("Cell type '%s' not recognised. Check that '+/abc9_model.v' has been read.\n", cell->type.c_str());
}
bool cell_known = inst_module || cell->known(); bool cell_known = inst_module || cell->known();
for (const auto &c : cell->connections()) { for (const auto &c : cell->connections()) {
@ -317,9 +321,9 @@ struct XAigerWriter
for (auto cell : box_list) { for (auto cell : box_list) {
log_assert(cell); log_assert(cell);
RTLIL::Module* box_module = module->design->module(cell->type); RTLIL::Module* box_module = design->module(cell->type);
log_assert(box_module); log_assert(box_module);
log_assert(box_module->attributes.count(ID::abc9_box_id) || box_module->get_bool_attribute(ID::abc9_flop)); log_assert(box_module->has_attribute(ID::abc9_box_id));
auto r = box_ports.insert(cell->type); auto r = box_ports.insert(cell->type);
if (r.second) { if (r.second) {
@ -383,27 +387,6 @@ struct XAigerWriter
undriven_bits.erase(O); undriven_bits.erase(O);
} }
} }
// Connect <cell>.abc9_ff.Q (inserted by abc9_map.v) as the last input to the flop box
if (box_module->get_bool_attribute(ID::abc9_flop)) {
SigSpec rhs = module->wire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
if (rhs.empty())
log_error("'%s.abc9_ff.Q' is not a wire present in module '%s'.\n", log_id(cell), log_id(module));
for (auto b : rhs) {
SigBit I = sigmap(b);
if (b == RTLIL::Sx)
b = State::S0;
else if (I != b) {
if (I == RTLIL::Sx)
alias_map[b] = State::S0;
else
alias_map[b] = I;
}
co_bits.emplace_back(b);
unused_bits.erase(I);
}
}
} }
for (auto bit : input_bits) for (auto bit : input_bits)
@ -419,16 +402,14 @@ struct XAigerWriter
undriven_bits.erase(bit); undriven_bits.erase(bit);
} }
if (holes_mode) { struct sort_by_port_id {
struct sort_by_port_id { bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const {
bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const { return a.wire->port_id < b.wire->port_id ||
return a.wire->port_id < b.wire->port_id || (a.wire->port_id == b.wire->port_id && a.offset < b.offset);
(a.wire->port_id == b.wire->port_id && a.offset < b.offset); }
} };
}; input_bits.sort(sort_by_port_id());
input_bits.sort(sort_by_port_id()); output_bits.sort(sort_by_port_id());
output_bits.sort(sort_by_port_id());
}
aig_map[State::S0] = 0; aig_map[State::S0] = 0;
aig_map[State::S1] = 1; aig_map[State::S1] = 1;
@ -589,17 +570,14 @@ struct XAigerWriter
int box_count = 0; int box_count = 0;
for (auto cell : box_list) { for (auto cell : box_list) {
log_assert(cell); log_assert(cell);
log_assert(cell->parameters.empty());
RTLIL::Module* box_module = module->design->module(cell->type); auto r = cell_cache.insert(cell->type);
log_assert(box_module);
IdString derived_type = box_module->derive(box_module->design, cell->parameters);
box_module = box_module->design->module(derived_type);
log_assert(box_module);
auto r = cell_cache.insert(derived_type);
auto &v = r.first->second; auto &v = r.first->second;
if (r.second) { if (r.second) {
RTLIL::Module* box_module = design->module(cell->type);
log_assert(box_module);
int box_inputs = 0, box_outputs = 0; int box_inputs = 0, box_outputs = 0;
for (auto port_name : box_module->ports) { for (auto port_name : box_module->ports) {
RTLIL::Wire *w = box_module->wire(port_name); RTLIL::Wire *w = box_module->wire(port_name);
@ -610,11 +588,6 @@ struct XAigerWriter
box_outputs += GetSize(w); box_outputs += GetSize(w);
} }
// For flops only, create an extra 1-bit input that drives a new wire
// called "<cell>.abc9_ff.Q" that is used below
if (box_module->get_bool_attribute(ID::abc9_flop))
box_inputs++;
std::get<0>(v) = box_inputs; std::get<0>(v) = box_inputs;
std::get<1>(v) = box_outputs; std::get<1>(v) = box_outputs;
std::get<2>(v) = box_module->attributes.at(ID::abc9_box_id).as_int(); std::get<2>(v) = box_module->attributes.at(ID::abc9_box_id).as_int();
@ -635,23 +608,27 @@ struct XAigerWriter
auto write_s_buffer = std::bind(write_buffer, std::ref(s_buffer), std::placeholders::_1); auto write_s_buffer = std::bind(write_buffer, std::ref(s_buffer), std::placeholders::_1);
write_s_buffer(ff_bits.size()); write_s_buffer(ff_bits.size());
dict<SigSpec, int> clk_to_mergeability;
for (const auto &i : ff_bits) { for (const auto &i : ff_bits) {
const SigBit &d = i.first; const SigBit &d = i.first;
const Cell *cell = i.second; const Cell *cell = i.second;
int mergeability = cell->attributes.at(ID::abc9_mergeability).as_int(); SigSpec clk_and_pol{sigmap(cell->getPort(ID::C)), cell->type[6] == 'P' ? State::S1 : State::S0};
auto r = clk_to_mergeability.insert(std::make_pair(clk_and_pol, clk_to_mergeability.size()+1));
int mergeability = r.first->second;
log_assert(mergeability > 0); log_assert(mergeability > 0);
write_r_buffer(mergeability); write_r_buffer(mergeability);
Const init = cell->attributes.at(ID::abc9_init, State::Sx); SigBit Q = sigmap(cell->getPort(ID::Q));
log_assert(GetSize(init) == 1); State init = init_map.at(Q, State::Sx);
log_debug("Cell '%s' (type %s) has (* init *) value '%s'.\n", log_id(cell), log_id(cell->type), log_signal(init));
if (init == State::S1) if (init == State::S1)
write_s_buffer(1); write_s_buffer(1);
else if (init == State::S0) else if (init == State::S0)
write_s_buffer(0); write_s_buffer(0);
else { else {
log_assert(init == State::Sx); log_assert(init == State::Sx);
write_s_buffer(0); write_s_buffer(2);
} }
// Use arrival time from output of flop box // Use arrival time from output of flop box
@ -671,10 +648,16 @@ struct XAigerWriter
f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
f.write(buffer_str.data(), buffer_str.size()); f.write(buffer_str.data(), buffer_str.size());
RTLIL::Module *holes_module = module->design->module(stringf("%s$holes", module->name.c_str())); RTLIL::Design *holes_design;
auto it = saved_designs.find("$abc9_holes");
if (it != saved_designs.end())
holes_design = it->second;
else
holes_design = nullptr;
RTLIL::Module *holes_module = holes_design ? holes_design->module(module->name) : nullptr;
if (holes_module) { if (holes_module) {
std::stringstream a_buffer; std::stringstream a_buffer;
XAigerWriter writer(holes_module, true /* holes_mode */); XAigerWriter writer(holes_module, false /* dff_mode */);
writer.write_aiger(a_buffer, false /*ascii_mode*/); writer.write_aiger(a_buffer, false /*ascii_mode*/);
f << "a"; f << "a";
@ -704,10 +687,10 @@ struct XAigerWriter
f << stringf("Generated by %s\n", yosys_version_str); f << stringf("Generated by %s\n", yosys_version_str);
module->design->scratchpad_set_int("write_xaiger.num_ands", and_map.size()); design->scratchpad_set_int("write_xaiger.num_ands", and_map.size());
module->design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size()); design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size());
module->design->scratchpad_set_int("write_xaiger.num_inputs", input_bits.size()); design->scratchpad_set_int("write_xaiger.num_inputs", input_bits.size());
module->design->scratchpad_set_int("write_xaiger.num_outputs", output_bits.size()); design->scratchpad_set_int("write_xaiger.num_outputs", output_bits.size());
} }
void write_map(std::ostream &f) void write_map(std::ostream &f)
@ -761,10 +744,10 @@ struct XAigerBackend : public Backend {
log(" write_xaiger [options] [filename]\n"); log(" write_xaiger [options] [filename]\n");
log("\n"); log("\n");
log("Write the top module (according to the (* top *) attribute or if only one module\n"); log("Write the top module (according to the (* top *) attribute or if only one module\n");
log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, $_ABC9_FF_, or"); log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, (optionally\n");
log("non (* abc9_box_id *) cells will be converted into psuedo-inputs and\n"); log("$_DFF_N_, $_DFF_P_), or non (* abc9_box *) cells will be converted into psuedo-\n");
log("pseudo-outputs. Whitebox contents will be taken from the '<module-name>$holes'\n"); log("inputs and pseudo-outputs. Whitebox contents will be taken from the equivalent\n");
log("module, if it exists.\n"); log("module in the '$abc9_holes' design, if it exists.\n");
log("\n"); log("\n");
log(" -ascii\n"); log(" -ascii\n");
log(" write ASCII version of AIGER format\n"); log(" write ASCII version of AIGER format\n");
@ -772,10 +755,13 @@ struct XAigerBackend : public Backend {
log(" -map <filename>\n"); log(" -map <filename>\n");
log(" write an extra file with port and box symbols\n"); log(" write an extra file with port and box symbols\n");
log("\n"); log("\n");
log(" -dff\n");
log(" write $_DFF_[NP]_ cells\n");
log("\n");
} }
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{ {
bool ascii_mode = false; bool ascii_mode = false, dff_mode = false;
std::string map_filename; std::string map_filename;
log_header(design, "Executing XAIGER backend.\n"); log_header(design, "Executing XAIGER backend.\n");
@ -791,6 +777,10 @@ struct XAigerBackend : public Backend {
map_filename = args[++argidx]; map_filename = args[++argidx];
continue; continue;
} }
if (args[argidx] == "-dff") {
dff_mode = true;
continue;
}
break; break;
} }
extra_args(f, filename, args, argidx, !ascii_mode); extra_args(f, filename, args, argidx, !ascii_mode);
@ -808,7 +798,7 @@ struct XAigerBackend : public Backend {
if (!top_module->memories.empty()) if (!top_module->memories.empty())
log_error("Found unmapped memories in module %s: unmapped memories are not supported in XAIGER backend!\n", log_id(top_module)); log_error("Found unmapped memories in module %s: unmapped memories are not supported in XAIGER backend!\n", log_id(top_module));
XAigerWriter writer(top_module); XAigerWriter writer(top_module, dff_mode);
writer.write_aiger(*f, ascii_mode); writer.write_aiger(*f, ascii_mode);
if (!map_filename.empty()) { if (!map_filename.empty()) {

View File

@ -266,20 +266,26 @@ struct BtorWorker
goto okay; goto okay;
} }
if (cell->type.in(ID($div), ID($mod))) if (cell->type.in(ID($div), ID($mod), ID($modfloor)))
{ {
bool a_signed = cell->hasParam(ID::A_SIGNED) ? cell->getParam(ID::A_SIGNED).as_bool() : false;
bool b_signed = cell->hasParam(ID::B_SIGNED) ? cell->getParam(ID::B_SIGNED).as_bool() : false;
string btor_op; string btor_op;
if (cell->type == ID($div)) btor_op = "div"; if (cell->type == ID($div)) btor_op = "div";
// "rem" = truncating modulo
if (cell->type == ID($mod)) btor_op = "rem"; if (cell->type == ID($mod)) btor_op = "rem";
// "mod" = flooring modulo
if (cell->type == ID($modfloor)) {
// "umod" doesn't exist because it's the same as "urem"
btor_op = a_signed || b_signed ? "mod" : "rem";
}
log_assert(!btor_op.empty()); log_assert(!btor_op.empty());
int width = GetSize(cell->getPort(ID::Y)); int width = GetSize(cell->getPort(ID::Y));
width = std::max(width, GetSize(cell->getPort(ID::A))); width = std::max(width, GetSize(cell->getPort(ID::A)));
width = std::max(width, GetSize(cell->getPort(ID::B))); width = std::max(width, GetSize(cell->getPort(ID::B)));
bool a_signed = cell->hasParam(ID::A_SIGNED) ? cell->getParam(ID::A_SIGNED).as_bool() : false;
bool b_signed = cell->hasParam(ID::B_SIGNED) ? cell->getParam(ID::B_SIGNED).as_bool() : false;
int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed); int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed);
int nid_b = get_sig_nid(cell->getPort(ID::B), width, b_signed); int nid_b = get_sig_nid(cell->getPort(ID::B), width, b_signed);

View File

@ -6,7 +6,7 @@ rm -rf test_cells.tmp
mkdir -p test_cells.tmp mkdir -p test_cells.tmp
cd test_cells.tmp cd test_cells.tmp
../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod' ../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod /$divfloor /$modfloor'
for fn in test_*.il; do for fn in test_*.il; do
../../../yosys -p " ../../../yosys -p "

View File

@ -513,7 +513,6 @@ struct CxxrtlWorker {
bool elide_public = false; bool elide_public = false;
bool localize_internal = false; bool localize_internal = false;
bool localize_public = false; bool localize_public = false;
bool run_opt_clean_purge = false;
bool run_proc_flatten = false; bool run_proc_flatten = false;
bool max_opt_level = false; bool max_opt_level = false;
@ -2009,6 +2008,7 @@ struct CxxrtlWorker {
log("Module `%s' contains feedback arcs through wires:\n", log_id(module)); log("Module `%s' contains feedback arcs through wires:\n", log_id(module));
for (auto wire : feedback_wires) for (auto wire : feedback_wires)
log(" %s\n", log_id(wire)); log(" %s\n", log_id(wire));
log("\n");
} }
for (auto wire : module->wires()) { for (auto wire : module->wires()) {
@ -2040,20 +2040,20 @@ struct CxxrtlWorker {
log("Module `%s' contains buffered combinatorial wires:\n", log_id(module)); log("Module `%s' contains buffered combinatorial wires:\n", log_id(module));
for (auto wire : buffered_wires) for (auto wire : buffered_wires)
log(" %s\n", log_id(wire)); log(" %s\n", log_id(wire));
log("\n");
} }
eval_converges[module] = feedback_wires.empty() && buffered_wires.empty(); eval_converges[module] = feedback_wires.empty() && buffered_wires.empty();
} }
if (has_feedback_arcs || has_buffered_wires) { if (has_feedback_arcs || has_buffered_wires) {
// Although both non-feedback buffered combinatorial wires and apparent feedback wires may be eliminated // Although both non-feedback buffered combinatorial wires and apparent feedback wires may be eliminated
// by optimizing the design, if after `opt_clean -purge` there are any feedback wires remaining, it is very // by optimizing the design, if after `proc; flatten` there are any feedback wires remaining, it is very
// likely that these feedback wires are indicative of a true logic loop, so they get emphasized in the message. // likely that these feedback wires are indicative of a true logic loop, so they get emphasized in the message.
const char *why_pessimistic = nullptr; const char *why_pessimistic = nullptr;
if (has_feedback_arcs) if (has_feedback_arcs)
why_pessimistic = "feedback wires"; why_pessimistic = "feedback wires";
else if (has_buffered_wires) else if (has_buffered_wires)
why_pessimistic = "buffered combinatorial wires"; why_pessimistic = "buffered combinatorial wires";
log("\n");
log_warning("Design contains %s, which require delta cycles during evaluation.\n", why_pessimistic); log_warning("Design contains %s, which require delta cycles during evaluation.\n", why_pessimistic);
if (!max_opt_level) if (!max_opt_level)
log("Increasing the optimization level may eliminate %s from the design.\n", why_pessimistic); log("Increasing the optimization level may eliminate %s from the design.\n", why_pessimistic);
@ -2087,34 +2087,39 @@ struct CxxrtlWorker {
void prepare_design(RTLIL::Design *design) void prepare_design(RTLIL::Design *design)
{ {
bool did_anything = false;
bool has_sync_init, has_packed_mem; bool has_sync_init, has_packed_mem;
log_push(); log_push();
check_design(design, has_sync_init, has_packed_mem); check_design(design, has_sync_init, has_packed_mem);
if (run_proc_flatten) { if (run_proc_flatten) {
Pass::call(design, "proc"); Pass::call(design, "proc");
Pass::call(design, "flatten"); Pass::call(design, "flatten");
did_anything = true;
} else if (has_sync_init) { } else if (has_sync_init) {
// We're only interested in proc_init, but it depends on proc_prune and proc_clean, so call those // We're only interested in proc_init, but it depends on proc_prune and proc_clean, so call those
// in case they weren't already. (This allows `yosys foo.v -o foo.cc` to work.) // in case they weren't already. (This allows `yosys foo.v -o foo.cc` to work.)
Pass::call(design, "proc_prune"); Pass::call(design, "proc_prune");
Pass::call(design, "proc_clean"); Pass::call(design, "proc_clean");
Pass::call(design, "proc_init"); Pass::call(design, "proc_init");
did_anything = true;
} }
if (has_packed_mem) if (has_packed_mem) {
Pass::call(design, "memory_unpack"); Pass::call(design, "memory_unpack");
did_anything = true;
}
// Recheck the design if it was modified. // Recheck the design if it was modified.
if (has_sync_init || has_packed_mem) if (has_sync_init || has_packed_mem)
check_design(design, has_sync_init, has_packed_mem); check_design(design, has_sync_init, has_packed_mem);
log_assert(!(has_sync_init || has_packed_mem)); log_assert(!(has_sync_init || has_packed_mem));
if (run_opt_clean_purge)
Pass::call(design, "opt_clean -purge");
log_pop(); log_pop();
if (did_anything)
log_spacer();
analyze_design(design); analyze_design(design);
} }
}; };
struct CxxrtlBackend : public Backend { struct CxxrtlBackend : public Backend {
static const int DEFAULT_OPT_LEVEL = 6; static const int DEFAULT_OPT_LEVEL = 5;
CxxrtlBackend() : Backend("cxxrtl", "convert design to C++ RTL simulation") { } CxxrtlBackend() : Backend("cxxrtl", "convert design to C++ RTL simulation") { }
void help() YS_OVERRIDE void help() YS_OVERRIDE
@ -2306,10 +2311,7 @@ struct CxxrtlBackend : public Backend {
log(" like -O3, and localize public wires not marked (*keep*) if possible.\n"); log(" like -O3, and localize public wires not marked (*keep*) if possible.\n");
log("\n"); log("\n");
log(" -O5\n"); log(" -O5\n");
log(" like -O4, and run `opt_clean -purge` first.\n"); log(" like -O4, and run `proc; flatten` first.\n");
log("\n");
log(" -O6\n");
log(" like -O5, and run `proc; flatten` first.\n");
log("\n"); log("\n");
} }
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@ -2343,13 +2345,11 @@ struct CxxrtlBackend : public Backend {
extra_args(f, filename, args, argidx); extra_args(f, filename, args, argidx);
switch (opt_level) { switch (opt_level) {
case 6: // the highest level here must match DEFAULT_OPT_LEVEL
case 5:
worker.max_opt_level = true; worker.max_opt_level = true;
worker.run_proc_flatten = true; worker.run_proc_flatten = true;
YS_FALLTHROUGH YS_FALLTHROUGH
case 5:
worker.run_opt_clean_purge = true;
YS_FALLTHROUGH
case 4: case 4:
worker.localize_public = true; worker.localize_public = true;
YS_FALLTHROUGH YS_FALLTHROUGH

View File

@ -392,7 +392,34 @@ struct FirrtlWorker
return result; return result;
} }
void run() void emit_extmodule()
{
std::string moduleFileinfo = getFileinfo(module);
f << stringf(" extmodule %s: %s\n", make_id(module->name), moduleFileinfo.c_str());
vector<std::string> port_decls;
for (auto wire : module->wires())
{
const auto wireName = make_id(wire->name);
std::string wireFileinfo = getFileinfo(wire);
if (wire->port_input && wire->port_output)
{
log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire));
}
port_decls.push_back(stringf(" %s %s: UInt<%d> %s\n", wire->port_input ? "input" : "output",
wireName, wire->width, wireFileinfo.c_str()));
}
for (auto &str : port_decls)
{
f << str;
}
f << stringf("\n");
}
void emit_module()
{ {
std::string moduleFileinfo = getFileinfo(module); std::string moduleFileinfo = getFileinfo(module);
f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo.c_str()); f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo.c_str());
@ -446,7 +473,7 @@ struct FirrtlWorker
string y_id = make_id(cell->name); string y_id = make_id(cell->name);
std::string cellFileinfo = getFileinfo(cell); std::string cellFileinfo = getFileinfo(cell);
if (cell->type.in(ID($not), ID($logic_not), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor))) if (cell->type.in(ID($not), ID($logic_not), ID($_NOT_), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor)))
{ {
string a_expr = make_expr(cell->getPort(ID::A)); string a_expr = make_expr(cell->getPort(ID::A));
wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), y_width, cellFileinfo.c_str())); wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), y_width, cellFileinfo.c_str()));
@ -462,7 +489,7 @@ struct FirrtlWorker
// Assume the FIRRTL width is a single bit. // Assume the FIRRTL width is a single bit.
firrtl_width = 1; firrtl_width = 1;
if (cell->type == ID($not)) primop = "not"; if (cell->type.in(ID($not), ID($_NOT_))) primop = "not";
else if (cell->type == ID($neg)) { else if (cell->type == ID($neg)) {
primop = "neg"; primop = "neg";
firrtl_is_signed = true; // Result of "neg" is signed (an SInt). firrtl_is_signed = true; // Result of "neg" is signed (an SInt).
@ -494,7 +521,7 @@ struct FirrtlWorker
continue; continue;
} }
if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($xnor), ID($and), ID($or), ID($eq), ID($eqx), if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_), ID($eq), ID($eqx),
ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($shr), ID($sshr), ID($sshl), ID($shl), ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($shr), ID($sshr), ID($sshl), ID($shl),
ID($logic_and), ID($logic_or), ID($pow))) ID($logic_and), ID($logic_or), ID($pow)))
{ {
@ -524,7 +551,7 @@ struct FirrtlWorker
// For the arithmetic ops, expand operand widths to result widths befor performing the operation. // For the arithmetic ops, expand operand widths to result widths befor performing the operation.
// This corresponds (according to iverilog) to what verilog compilers implement. // This corresponds (according to iverilog) to what verilog compilers implement.
if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($xnor), ID($and), ID($or))) if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_)))
{ {
if (a_width < y_width) { if (a_width < y_width) {
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
@ -558,19 +585,20 @@ struct FirrtlWorker
firrtl_is_signed = a_signed | b_signed; firrtl_is_signed = a_signed | b_signed;
firrtl_width = a_width; firrtl_width = a_width;
} else if (cell->type == ID($mod)) { } else if (cell->type == ID($mod)) {
// "rem" = truncating modulo
primop = "rem"; primop = "rem";
firrtl_width = min(a_width, b_width); firrtl_width = min(a_width, b_width);
} else if (cell->type == ID($and)) { } else if (cell->type.in(ID($and), ID($_AND_))) {
primop = "and"; primop = "and";
always_uint = true; always_uint = true;
firrtl_width = max(a_width, b_width); firrtl_width = max(a_width, b_width);
} }
else if (cell->type == ID($or) ) { else if (cell->type.in(ID($or), ID($_OR_))) {
primop = "or"; primop = "or";
always_uint = true; always_uint = true;
firrtl_width = max(a_width, b_width); firrtl_width = max(a_width, b_width);
} }
else if (cell->type == ID($xor)) { else if (cell->type.in(ID($xor), ID($_XOR_))) {
primop = "xor"; primop = "xor";
always_uint = true; always_uint = true;
firrtl_width = max(a_width, b_width); firrtl_width = max(a_width, b_width);
@ -694,7 +722,8 @@ struct FirrtlWorker
} }
} }
if (!cell->parameters.at(ID::B_SIGNED).as_bool()) { auto it = cell->parameters.find(ID::B_SIGNED);
if (it == cell->parameters.end() || !it->second.as_bool()) {
b_expr = "asUInt(" + b_expr + ")"; b_expr = "asUInt(" + b_expr + ")";
} }
@ -723,9 +752,10 @@ struct FirrtlWorker
continue; continue;
} }
if (cell->type.in(ID($mux))) if (cell->type.in(ID($mux), ID($_MUX_)))
{ {
int width = cell->parameters.at(ID::WIDTH).as_int(); auto it = cell->parameters.find(ID::WIDTH);
int width = it == cell->parameters.end()? 1 : it->second.as_int();
string a_expr = make_expr(cell->getPort(ID::A)); string a_expr = make_expr(cell->getPort(ID::A));
string b_expr = make_expr(cell->getPort(ID::B)); string b_expr = make_expr(cell->getPort(ID::B));
string s_expr = make_expr(cell->getPort(ID::S)); string s_expr = make_expr(cell->getPort(ID::S));
@ -1076,6 +1106,18 @@ struct FirrtlWorker
for (auto str : wire_exprs) for (auto str : wire_exprs)
f << str; f << str;
f << stringf("\n");
}
void run()
{
// Blackboxes should be emitted as `extmodule`s in firrtl. Only ports are
// emitted in such a case.
if (module->get_blackbox_attribute())
emit_extmodule();
else
emit_module();
} }
}; };

View File

@ -590,7 +590,17 @@ struct Smt2Worker
if (cell->type == ID($sub)) return export_bvop(cell, "(bvsub A B)"); if (cell->type == ID($sub)) return export_bvop(cell, "(bvsub A B)");
if (cell->type == ID($mul)) return export_bvop(cell, "(bvmul A B)"); if (cell->type == ID($mul)) return export_bvop(cell, "(bvmul A B)");
if (cell->type == ID($div)) return export_bvop(cell, "(bvUdiv A B)", 'd'); if (cell->type == ID($div)) return export_bvop(cell, "(bvUdiv A B)", 'd');
// "rem" = truncating modulo
if (cell->type == ID($mod)) return export_bvop(cell, "(bvUrem A B)", 'd'); if (cell->type == ID($mod)) return export_bvop(cell, "(bvUrem A B)", 'd');
// "mod" = flooring modulo
if (cell->type == ID($modfloor)) {
// bvumod doesn't exist because it's the same as bvurem
if (cell->getParam(ID::A_SIGNED).as_bool()) {
return export_bvop(cell, "(bvsmod A B)", 'd');
} else {
return export_bvop(cell, "(bvurem A B)", 'd');
}
}
if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool)) && if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool)) &&
2*GetSize(cell->getPort(ID::A).chunks()) < GetSize(cell->getPort(ID::A))) { 2*GetSize(cell->getPort(ID::A).chunks()) < GetSize(cell->getPort(ID::A))) {

View File

@ -1511,7 +1511,7 @@ else: # not tempind, covermode
smt_assert_consequent(get_constr_expr(constr_assumes, i)) smt_assert_consequent(get_constr_expr(constr_assumes, i))
print_msg("Re-solving with appended steps..") print_msg("Re-solving with appended steps..")
if smt_check_sat() == "unsat": if smt_check_sat() == "unsat":
print("%s Cannot appended steps without violating assumptions!" % smt.timestamp()) print("%s Cannot append steps without violating assumptions!" % smt.timestamp())
retstatus = "FAILED" retstatus = "FAILED"
break break
print_anyconsts(step) print_anyconsts(step)
@ -1548,7 +1548,7 @@ else: # not tempind, covermode
break break
smt_pop() smt_pop()
if not retstatus: if retstatus == "FAILED" or retstatus == "PREUNSAT":
break break
else: # gentrace else: # gentrace
@ -1557,8 +1557,9 @@ else: # not tempind, covermode
smt_assert(get_constr_expr(constr_asserts, i)) smt_assert(get_constr_expr(constr_asserts, i))
print_msg("Solving for step %d.." % (last_check_step)) print_msg("Solving for step %d.." % (last_check_step))
if smt_check_sat() != "sat": status = smt_check_sat()
print("%s No solution found!" % smt.timestamp()) if status != "sat":
print("%s No solution found! (%s)" % (smt.timestamp(), status))
retstatus = "FAILED" retstatus = "FAILED"
break break
@ -1568,7 +1569,7 @@ else: # not tempind, covermode
step += step_size step += step_size
if gentrace and retstatus: if gentrace and retstatus == "PASSED":
print_anyconsts(0) print_anyconsts(0)
write_trace(0, num_steps, '%') write_trace(0, num_steps, '%')

View File

@ -121,6 +121,7 @@ class SmtIo:
self.logic_bv = True self.logic_bv = True
self.logic_dt = False self.logic_dt = False
self.forall = False self.forall = False
self.timeout = 0
self.produce_models = True self.produce_models = True
self.smt2cache = [list()] self.smt2cache = [list()]
self.p = None self.p = None
@ -135,6 +136,7 @@ class SmtIo:
self.debug_file = opts.debug_file self.debug_file = opts.debug_file
self.dummy_file = opts.dummy_file self.dummy_file = opts.dummy_file
self.timeinfo = opts.timeinfo self.timeinfo = opts.timeinfo
self.timeout = opts.timeout
self.unroll = opts.unroll self.unroll = opts.unroll
self.noincr = opts.noincr self.noincr = opts.noincr
self.info_stmts = opts.info_stmts self.info_stmts = opts.info_stmts
@ -147,6 +149,7 @@ class SmtIo:
self.debug_file = None self.debug_file = None
self.dummy_file = None self.dummy_file = None
self.timeinfo = os.name != "nt" self.timeinfo = os.name != "nt"
self.timeout = 0
self.unroll = False self.unroll = False
self.noincr = False self.noincr = False
self.info_stmts = list() self.info_stmts = list()
@ -172,22 +175,32 @@ class SmtIo:
self.unroll = False self.unroll = False
if self.solver == "yices": if self.solver == "yices":
if self.noincr: if self.noincr or self.forall:
self.popen_vargs = ['yices-smt2'] + self.solver_opts self.popen_vargs = ['yices-smt2'] + self.solver_opts
else: else:
self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts
if self.timeout != 0:
self.popen_vargs.append('-t')
self.popen_vargs.append('%d' % self.timeout);
if self.solver == "z3": if self.solver == "z3":
self.popen_vargs = ['z3', '-smt2', '-in'] + self.solver_opts self.popen_vargs = ['z3', '-smt2', '-in'] + self.solver_opts
if self.timeout != 0:
self.popen_vargs.append('-T:%d' % self.timeout);
if self.solver == "cvc4": if self.solver == "cvc4":
if self.noincr: if self.noincr:
self.popen_vargs = ['cvc4', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts self.popen_vargs = ['cvc4', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
else: else:
self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
if self.timeout != 0:
self.popen_vargs.append('--tlimit=%d000' % self.timeout);
if self.solver == "mathsat": if self.solver == "mathsat":
self.popen_vargs = ['mathsat'] + self.solver_opts self.popen_vargs = ['mathsat'] + self.solver_opts
if self.timeout != 0:
print('timeout option is not supported for mathsat.')
sys.exit(1)
if self.solver == "boolector": if self.solver == "boolector":
if self.noincr: if self.noincr:
@ -195,6 +208,9 @@ class SmtIo:
else: else:
self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts
self.unroll = True self.unroll = True
if self.timeout != 0:
print('timeout option is not supported for boolector.')
sys.exit(1)
if self.solver == "abc": if self.solver == "abc":
if len(self.solver_opts) > 0: if len(self.solver_opts) > 0:
@ -204,6 +220,9 @@ class SmtIo:
self.logic_ax = False self.logic_ax = False
self.unroll = True self.unroll = True
self.noincr = True self.noincr = True
if self.timeout != 0:
print('timeout option is not supported for abc.')
sys.exit(1)
if self.solver == "dummy": if self.solver == "dummy":
assert self.dummy_file is not None assert self.dummy_file is not None
@ -232,12 +251,16 @@ class SmtIo:
if self.logic_uf: self.logic += "UF" if self.logic_uf: self.logic += "UF"
if self.logic_bv: self.logic += "BV" if self.logic_bv: self.logic += "BV"
if self.logic_dt: self.logic = "ALL" if self.logic_dt: self.logic = "ALL"
if self.solver == "yices" and self.forall: self.logic = "BV"
self.setup_done = True self.setup_done = True
for stmt in self.info_stmts: for stmt in self.info_stmts:
self.write(stmt) self.write(stmt)
if self.forall and self.solver == "yices":
self.write("(set-option :yices-ef-max-iters 1000000000)")
if self.produce_models: if self.produce_models:
self.write("(set-option :produce-models true)") self.write("(set-option :produce-models true)")
@ -706,7 +729,7 @@ class SmtIo:
if self.forall: if self.forall:
result = self.read() result = self.read()
while result not in ["sat", "unsat", "unknown"]: while result not in ["sat", "unsat", "unknown", "timeout", "interrupted", ""]:
print("%s %s: %s" % (self.timestamp(), self.solver, result)) print("%s %s: %s" % (self.timestamp(), self.solver, result))
result = self.read() result = self.read()
else: else:
@ -717,7 +740,7 @@ class SmtIo:
print("(check-sat)", file=self.debug_file) print("(check-sat)", file=self.debug_file)
self.debug_file.flush() self.debug_file.flush()
if result not in ["sat", "unsat"]: if result not in ["sat", "unsat", "unknown", "timeout", "interrupted"]:
if result == "": if result == "":
print("%s Unexpected EOF response from solver." % (self.timestamp()), flush=True) print("%s Unexpected EOF response from solver." % (self.timestamp()), flush=True)
else: else:
@ -927,7 +950,7 @@ class SmtIo:
class SmtOpts: class SmtOpts:
def __init__(self): def __init__(self):
self.shortopts = "s:S:v" self.shortopts = "s:S:v"
self.longopts = ["unroll", "noincr", "noprogress", "dump-smt2=", "logic=", "dummy=", "info=", "nocomments"] self.longopts = ["unroll", "noincr", "noprogress", "timeout=", "dump-smt2=", "logic=", "dummy=", "info=", "nocomments"]
self.solver = "yices" self.solver = "yices"
self.solver_opts = list() self.solver_opts = list()
self.debug_print = False self.debug_print = False
@ -936,6 +959,7 @@ class SmtOpts:
self.unroll = False self.unroll = False
self.noincr = False self.noincr = False
self.timeinfo = os.name != "nt" self.timeinfo = os.name != "nt"
self.timeout = 0
self.logic = None self.logic = None
self.info_stmts = list() self.info_stmts = list()
self.nocomments = False self.nocomments = False
@ -945,6 +969,8 @@ class SmtOpts:
self.solver = a self.solver = a
elif o == "-S": elif o == "-S":
self.solver_opts.append(a) self.solver_opts.append(a)
elif o == "--timeout":
self.timeout = int(a)
elif o == "-v": elif o == "-v":
self.debug_print = True self.debug_print = True
elif o == "--unroll": elif o == "--unroll":
@ -976,6 +1002,9 @@ class SmtOpts:
-S <opt> -S <opt>
pass <opt> as command line argument to the solver pass <opt> as command line argument to the solver
--timeout <value>
set the solver timeout to the specified value (in seconds).
--logic <smt2_logic> --logic <smt2_logic>
use the specified SMT2 logic (e.g. QF_AUFBV) use the specified SMT2 logic (e.g. QF_AUFBV)

View File

@ -358,7 +358,8 @@ struct SmvWorker
continue; continue;
} }
if (cell->type.in(ID($div), ID($mod))) // SMV has a "mod" operator, but its semantics don't seem to be well-defined - to be safe, don't generate it at all
if (cell->type.in(ID($div)/*, ID($mod), ID($modfloor)*/))
{ {
int width_y = GetSize(cell->getPort(ID::Y)); int width_y = GetSize(cell->getPort(ID::Y));
int width = max(width_y, GetSize(cell->getPort(ID::A))); int width = max(width_y, GetSize(cell->getPort(ID::A)));
@ -366,7 +367,7 @@ struct SmvWorker
string expr_a, expr_b, op; string expr_a, expr_b, op;
if (cell->type == ID($div)) op = "/"; if (cell->type == ID($div)) op = "/";
if (cell->type == ID($mod)) op = "mod"; //if (cell->type == ID($mod)) op = "mod";
if (cell->getParam(ID::A_SIGNED).as_bool()) if (cell->getParam(ID::A_SIGNED).as_bool())
{ {

View File

@ -7,8 +7,8 @@ mkdir -p test_cells.tmp
cd test_cells.tmp cd test_cells.tmp
# don't test $mul to reduce runtime # don't test $mul to reduce runtime
# don't test $div and $mod to reduce runtime and avoid "div by zero" message # don't test $div/$mod/$divfloor/$modfloor to reduce runtime and avoid "div by zero" message
../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$macc /$mul /$div /$mod' ../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$macc /$mul /$div /$mod /$divfloor /$modfloor'
cat > template.txt << "EOT" cat > template.txt << "EOT"
%module main %module main

View File

@ -740,6 +740,95 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
#undef HANDLE_UNIOP #undef HANDLE_UNIOP
#undef HANDLE_BINOP #undef HANDLE_BINOP
if (cell->type == ID($divfloor))
{
// wire [MAXLEN+1:0] _0_, _1_, _2_;
// assign _0_ = $signed(A);
// assign _1_ = $signed(B);
// assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1));
// assign Y = $signed(_2_) / $signed(_1_);
if (cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) {
SigSpec sig_a = cell->getPort(ID::A);
SigSpec sig_b = cell->getPort(ID::B);
std::string buf_a = next_auto_id();
std::string buf_b = next_auto_id();
std::string buf_num = next_auto_id();
int size_a = GetSize(sig_a);
int size_b = GetSize(sig_b);
int size_y = GetSize(cell->getPort(ID::Y));
int size_max = std::max(size_a, std::max(size_b, size_y));
// intentionally one wider than maximum width
f << stringf("%s" "wire [%d:0] %s, %s, %s;\n", indent.c_str(), size_max, buf_a.c_str(), buf_b.c_str(), buf_num.c_str());
f << stringf("%s" "assign %s = ", indent.c_str(), buf_a.c_str());
dump_cell_expr_port(f, cell, "A", true);
f << stringf(";\n");
f << stringf("%s" "assign %s = ", indent.c_str(), buf_b.c_str());
dump_cell_expr_port(f, cell, "B", true);
f << stringf(";\n");
f << stringf("%s" "assign %s = ", indent.c_str(), buf_num.c_str());
f << stringf("(");
dump_sigspec(f, sig_a.extract(sig_a.size()-1));
f << stringf(" == ");
dump_sigspec(f, sig_b.extract(sig_b.size()-1));
f << stringf(") || ");
dump_sigspec(f, sig_a);
f << stringf(" == 0 ? %s : ", buf_a.c_str());
f << stringf("$signed(%s - (", buf_a.c_str());
dump_sigspec(f, sig_b.extract(sig_b.size()-1));
f << stringf(" ? %s + 1 : %s - 1));\n", buf_b.c_str(), buf_b.c_str());
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, cell->getPort(ID::Y));
f << stringf(" = $signed(%s) / ", buf_num.c_str());
dump_attributes(f, "", cell->attributes, ' ');
f << stringf("$signed(%s);\n", buf_b.c_str());
return true;
} else {
// same as truncating division
dump_cell_expr_binop(f, indent, cell, "/");
return true;
}
}
if (cell->type == ID($modfloor))
{
// wire truncated = $signed(A) % $signed(B);
// assign Y = (A[-1] == B[-1]) || truncated == 0 ? truncated : $signed(B) + $signed(truncated);
if (cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) {
SigSpec sig_a = cell->getPort(ID::A);
SigSpec sig_b = cell->getPort(ID::B);
std::string temp_id = next_auto_id();
f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort(ID::A))-1, temp_id.c_str());
dump_cell_expr_port(f, cell, "A", true);
f << stringf(" %% ");
dump_attributes(f, "", cell->attributes, ' ');
dump_cell_expr_port(f, cell, "B", true);
f << stringf(";\n");
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, cell->getPort(ID::Y));
f << stringf(" = (");
dump_sigspec(f, sig_a.extract(sig_a.size()-1));
f << stringf(" == ");
dump_sigspec(f, sig_b.extract(sig_b.size()-1));
f << stringf(") || %s == 0 ? %s : ", temp_id.c_str(), temp_id.c_str());
dump_cell_expr_port(f, cell, "B", true);
f << stringf(" + $signed(%s);\n", temp_id.c_str());
return true;
} else {
// same as truncating modulo
dump_cell_expr_binop(f, indent, cell, "%");
return true;
}
}
if (cell->type == ID($shift)) if (cell->type == ID($shift))
{ {
f << stringf("%s" "assign ", indent.c_str()); f << stringf("%s" "assign ", indent.c_str());

View File

@ -454,6 +454,14 @@ void AigerReader::parse_xaiger()
for (unsigned i = 0; i < flopNum; i++) for (unsigned i = 0; i < flopNum; i++)
mergeability.emplace_back(parse_xaiger_literal(f)); mergeability.emplace_back(parse_xaiger_literal(f));
} }
else if (c == 's') {
uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
flopNum = parse_xaiger_literal(f);
log_assert(dataSize == (flopNum+1) * sizeof(uint32_t));
initial_state.reserve(flopNum);
for (unsigned i = 0; i < flopNum; i++)
initial_state.emplace_back(parse_xaiger_literal(f));
}
else if (c == 'n') { else if (c == 'n') {
parse_xaiger_literal(f); parse_xaiger_literal(f);
f >> s; f >> s;
@ -767,6 +775,7 @@ void AigerReader::post_process()
} }
} }
dict<int, Wire*> mergeability_to_clock;
for (uint32_t i = 0; i < flopNum; i++) { for (uint32_t i = 0; i < flopNum; i++) {
RTLIL::Wire *d = outputs[outputs.size() - flopNum + i]; RTLIL::Wire *d = outputs[outputs.size() - flopNum + i];
log_assert(d); log_assert(d);
@ -778,10 +787,9 @@ void AigerReader::post_process()
log_assert(q->port_input); log_assert(q->port_input);
q->port_input = false; q->port_input = false;
auto ff = module->addCell(NEW_ID, ID($__ABC9_FF_)); Cell* ff = module->addFfGate(NEW_ID, d, q);
ff->setPort(ID::D, d);
ff->setPort(ID::Q, q);
ff->attributes[ID::abc9_mergeability] = mergeability[i]; ff->attributes[ID::abc9_mergeability] = mergeability[i];
q->attributes[ID::init] = initial_state[i];
} }
dict<RTLIL::IdString, std::pair<int,int>> wideports_cache; dict<RTLIL::IdString, std::pair<int,int>> wideports_cache;

View File

@ -45,7 +45,7 @@ struct AigerReader
std::vector<RTLIL::Wire*> outputs; std::vector<RTLIL::Wire*> outputs;
std::vector<RTLIL::Wire*> bad_properties; std::vector<RTLIL::Wire*> bad_properties;
std::vector<RTLIL::Cell*> boxes; std::vector<RTLIL::Cell*> boxes;
std::vector<int> mergeability; std::vector<int> mergeability, initial_state;
AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports); AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports);
void parse_aiger(); void parse_aiger();

View File

@ -1057,7 +1057,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (!range_valid) if (!range_valid)
log_file_error(filename, location.first_line, "Signal `%s' with non-constant width!\n", str.c_str()); log_file_error(filename, location.first_line, "Signal `%s' with non-constant width!\n", str.c_str());
if (!(range_left >= range_right || (range_left == -1 && range_right == 0))) if (!(range_left + 1 >= range_right))
log_file_error(filename, location.first_line, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1); log_file_error(filename, location.first_line, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1);
RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1); RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1);

View File

@ -1256,7 +1256,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
} }
if (old_range_valid != range_valid) if (old_range_valid != range_valid)
did_something = true; did_something = true;
if (range_valid && range_left >= 0 && range_right > range_left) { if (range_valid && range_right > range_left) {
int tmp = range_right; int tmp = range_right;
range_right = range_left; range_right = range_left;
range_left = tmp; range_left = tmp;
@ -1274,6 +1274,25 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
range_swapped = children[0]->range_swapped; range_swapped = children[0]->range_swapped;
range_left = children[0]->range_left; range_left = children[0]->range_left;
range_right = children[0]->range_right; range_right = children[0]->range_right;
bool force_upto = false, force_downto = false;
if (attributes.count(ID::force_upto)) {
AstNode *val = attributes[ID::force_upto];
if (val->type != AST_CONSTANT)
log_file_error(filename, location.first_line, "Attribute `force_upto' with non-constant value!\n");
force_upto = val->asAttrConst().as_bool();
}
if (attributes.count(ID::force_downto)) {
AstNode *val = attributes[ID::force_downto];
if (val->type != AST_CONSTANT)
log_file_error(filename, location.first_line, "Attribute `force_downto' with non-constant value!\n");
force_downto = val->asAttrConst().as_bool();
}
if (force_upto && force_downto)
log_file_error(filename, location.first_line, "Attributes `force_downto' and `force_upto' cannot be both set!\n");
if ((force_upto && !range_swapped) || (force_downto && range_swapped)) {
std::swap(range_left, range_right);
range_swapped = force_upto;
}
} }
} else { } else {
if (!range_valid) if (!range_valid)
@ -3719,8 +3738,8 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
} }
} }
// also activate if requested, either by using mem2reg attribute or by declaring array as 'wire' instead of 'reg' // also activate if requested, either by using mem2reg attribute or by declaring array as 'wire' instead of 'reg' or 'logic'
if (type == AST_MEMORY && (get_bool_attribute(ID::mem2reg) || (flags & AstNode::MEM2REG_FL_ALL) || !is_reg)) if (type == AST_MEMORY && (get_bool_attribute(ID::mem2reg) || (flags & AstNode::MEM2REG_FL_ALL) || !(is_reg || is_logic)))
mem2reg_candidates[this] |= AstNode::MEM2REG_FL_FORCED; mem2reg_candidates[this] |= AstNode::MEM2REG_FL_FORCED;
if (type == AST_MODULE && get_bool_attribute(ID::mem2reg)) if (type == AST_MODULE && get_bool_attribute(ID::mem2reg))

View File

@ -91,8 +91,10 @@ USING_YOSYS_NAMESPACE
[0-9]+'[01xzm-]* { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_VALUE; } [0-9]+'[01xzm-]* { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_VALUE; }
-?[0-9]+ { -?[0-9]+ {
char *end = nullptr; char *end = nullptr;
errno = 0;
long value = strtol(yytext, &end, 10); long value = strtol(yytext, &end, 10);
if (end != yytext + strlen(yytext)) log_assert(end == yytext + strlen(yytext));
if (errno == ERANGE)
return TOK_INVALID; // literal out of range of long return TOK_INVALID; // literal out of range of long
if (value < INT_MIN || value > INT_MAX) if (value < INT_MIN || value > INT_MAX)
return TOK_INVALID; // literal out of range of int (relevant mostly for LP64 platforms) return TOK_INVALID; // literal out of range of int (relevant mostly for LP64 platforms)

View File

@ -974,6 +974,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
module->memories[memory->name] = memory; module->memories[memory->name] = memory;
int number_of_bits = net->Size(); int number_of_bits = net->Size();
number_of_bits = 1 << ceil_log2(number_of_bits);
int bits_in_word = number_of_bits; int bits_in_word = number_of_bits;
FOREACH_PORTREF_OF_NET(net, si, pr) { FOREACH_PORTREF_OF_NET(net, si, pr) {
if (pr->GetInst()->Type() == OPER_READ_PORT) { if (pr->GetInst()->Type() == OPER_READ_PORT) {
@ -1265,9 +1266,6 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
int numchunks = int(inst->OutputSize()) / memory->width; int numchunks = int(inst->OutputSize()) / memory->width;
int chunksbits = ceil_log2(numchunks); int chunksbits = ceil_log2(numchunks);
if ((numchunks * memory->width) != int(inst->OutputSize()) || (numchunks & (numchunks - 1)) != 0)
log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
for (int i = 0; i < numchunks; i++) for (int i = 0; i < numchunks; i++)
{ {
RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)};
@ -1295,9 +1293,6 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
int numchunks = int(inst->Input2Size()) / memory->width; int numchunks = int(inst->Input2Size()) / memory->width;
int chunksbits = ceil_log2(numchunks); int chunksbits = ceil_log2(numchunks);
if ((numchunks * memory->width) != int(inst->Input2Size()) || (numchunks & (numchunks - 1)) != 0)
log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetOutput()->Name());
for (int i = 0; i < numchunks; i++) for (int i = 0; i < numchunks; i++)
{ {
RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)};

View File

@ -48,16 +48,18 @@ USING_YOSYS_NAMESPACE
using namespace AST; using namespace AST;
using namespace VERILOG_FRONTEND; using namespace VERILOG_FRONTEND;
#define YYSTYPE FRONTEND_VERILOG_YYSTYPE
#define YYLTYPE FRONTEND_VERILOG_YYLTYPE
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND { namespace VERILOG_FRONTEND {
std::vector<std::string> fn_stack; std::vector<std::string> fn_stack;
std::vector<int> ln_stack; std::vector<int> ln_stack;
YYLTYPE real_location;
YYLTYPE old_location;
} }
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END
#define YYSTYPE FRONTEND_VERILOG_YYSTYPE
#define YYLTYPE FRONTEND_VERILOG_YYLTYPE
#define SV_KEYWORD(_tok) \ #define SV_KEYWORD(_tok) \
if (sv_mode) return _tok; \ if (sv_mode) return _tok; \
log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\ log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\
@ -73,9 +75,6 @@ YOSYS_NAMESPACE_END
#define YY_INPUT(buf,result,max_size) \ #define YY_INPUT(buf,result,max_size) \
result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size) result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
YYLTYPE real_location;
YYLTYPE old_location;
#define YY_USER_ACTION \ #define YY_USER_ACTION \
old_location = real_location; \ old_location = real_location; \
real_location.first_line = real_location.last_line; \ real_location.first_line = real_location.last_line; \
@ -128,7 +127,9 @@ static bool isUserType(std::string &s)
%x BASED_CONST %x BASED_CONST
%% %%
int comment_caller; // Initialise comment_caller to something to avoid a "maybe undefined"
// warning from GCC.
int comment_caller = INITIAL;
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* { <INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* {
fn_stack.push_back(current_filename); fn_stack.push_back(current_filename);

View File

@ -886,7 +886,19 @@ task_func_port:
albuf = $1; albuf = $1;
astbuf1 = $2; astbuf1 = $2;
astbuf2 = checkRange(astbuf1, $3); astbuf2 = checkRange(astbuf1, $3);
} wire_name | wire_name; } wire_name |
{
if (!astbuf1) {
if (!sv_mode)
frontend_verilog_yyerror("task/function argument direction missing");
albuf = new dict<IdString, AstNode*>;
astbuf1 = new AstNode(AST_WIRE);
current_wire_rand = false;
current_wire_const = false;
astbuf1->is_input = true;
astbuf2 = NULL;
}
} wire_name;
task_func_body: task_func_body:
task_func_body behavioral_stmt | task_func_body behavioral_stmt |
@ -2299,49 +2311,56 @@ assert_property:
}; };
simple_behavioral_stmt: simple_behavioral_stmt:
lvalue '=' delay expr { attr lvalue '=' delay expr {
AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4); AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $5);
ast_stack.back()->children.push_back(node); ast_stack.back()->children.push_back(node);
SET_AST_NODE_LOC(node, @1, @4); SET_AST_NODE_LOC(node, @2, @5);
append_attr(node, $1);
} | } |
lvalue TOK_INCREMENT { attr lvalue TOK_INCREMENT {
AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_ADD, $1->clone(), AstNode::mkconst_int(1, true))); AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_ADD, $2->clone(), AstNode::mkconst_int(1, true)));
ast_stack.back()->children.push_back(node); ast_stack.back()->children.push_back(node);
SET_AST_NODE_LOC(node, @1, @2); SET_AST_NODE_LOC(node, @2, @3);
append_attr(node, $1);
} | } |
lvalue TOK_DECREMENT { attr lvalue TOK_DECREMENT {
AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_SUB, $1->clone(), AstNode::mkconst_int(1, true))); AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_SUB, $2->clone(), AstNode::mkconst_int(1, true)));
ast_stack.back()->children.push_back(node); ast_stack.back()->children.push_back(node);
SET_AST_NODE_LOC(node, @1, @2); SET_AST_NODE_LOC(node, @2, @3);
append_attr(node, $1);
} | } |
lvalue OP_LE delay expr { attr lvalue OP_LE delay expr {
AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4); AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5);
ast_stack.back()->children.push_back(node); ast_stack.back()->children.push_back(node);
SET_AST_NODE_LOC(node, @1, @4); SET_AST_NODE_LOC(node, @2, @5);
append_attr(node, $1);
}; };
// this production creates the obligatory if-else shift/reduce conflict // this production creates the obligatory if-else shift/reduce conflict
behavioral_stmt: behavioral_stmt:
defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl | defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl |
non_opt_delay behavioral_stmt | non_opt_delay behavioral_stmt |
simple_behavioral_stmt ';' | ';' | simple_behavioral_stmt ';' |
hierarchical_id attr { attr ';' {
free_attr($1);
} |
attr hierarchical_id {
AstNode *node = new AstNode(AST_TCALL); AstNode *node = new AstNode(AST_TCALL);
node->str = *$1; node->str = *$2;
delete $1; delete $2;
ast_stack.back()->children.push_back(node); ast_stack.back()->children.push_back(node);
ast_stack.push_back(node); ast_stack.push_back(node);
append_attr(node, $2); append_attr(node, $1);
} opt_arg_list ';'{ } opt_arg_list ';'{
ast_stack.pop_back(); ast_stack.pop_back();
} | } |
TOK_MSG_TASKS attr { attr TOK_MSG_TASKS {
AstNode *node = new AstNode(AST_TCALL); AstNode *node = new AstNode(AST_TCALL);
node->str = *$1; node->str = *$2;
delete $1; delete $2;
ast_stack.back()->children.push_back(node); ast_stack.back()->children.push_back(node);
ast_stack.push_back(node); ast_stack.push_back(node);
append_attr(node, $2); append_attr(node, $1);
} opt_arg_list ';'{ } opt_arg_list ';'{
ast_stack.pop_back(); ast_stack.pop_back();
} | } |
@ -2438,8 +2457,6 @@ behavioral_stmt:
ast_stack.pop_back(); ast_stack.pop_back();
}; };
;
unique_case_attr: unique_case_attr:
/* empty */ { /* empty */ {
$$ = false; $$ = false;
@ -2534,7 +2551,7 @@ gen_case_item:
} case_select { } case_select {
case_type_stack.push_back(0); case_type_stack.push_back(0);
SET_AST_NODE_LOC(ast_stack.back(), @2, @2); SET_AST_NODE_LOC(ast_stack.back(), @2, @2);
} gen_stmt_or_null { } gen_stmt_block {
case_type_stack.pop_back(); case_type_stack.pop_back();
ast_stack.pop_back(); ast_stack.pop_back();
}; };
@ -2626,7 +2643,10 @@ module_gen_body:
/* empty */; /* empty */;
gen_stmt_or_module_body_stmt: gen_stmt_or_module_body_stmt:
gen_stmt | module_body_stmt; gen_stmt | module_body_stmt |
attr ';' {
free_attr($1);
};
// this production creates the obligatory if-else shift/reduce conflict // this production creates the obligatory if-else shift/reduce conflict
gen_stmt: gen_stmt:
@ -2648,7 +2668,7 @@ gen_stmt:
AstNode *block = new AstNode(AST_GENBLOCK); AstNode *block = new AstNode(AST_GENBLOCK);
ast_stack.back()->children.push_back(block); ast_stack.back()->children.push_back(block);
ast_stack.push_back(block); ast_stack.push_back(block);
} gen_stmt_or_null { } gen_stmt_block {
ast_stack.pop_back(); ast_stack.pop_back();
} opt_gen_else { } opt_gen_else {
SET_AST_NODE_LOC(ast_stack.back(), @1, @7); SET_AST_NODE_LOC(ast_stack.back(), @1, @7);
@ -2698,11 +2718,8 @@ gen_stmt_block:
ast_stack.pop_back(); ast_stack.pop_back();
}; };
gen_stmt_or_null:
gen_stmt_block | ';';
opt_gen_else: opt_gen_else:
TOK_ELSE gen_stmt_or_null | /* empty */ %prec FAKE_THEN; TOK_ELSE gen_stmt_block | /* empty */ %prec FAKE_THEN;
expr: expr:
basic_expr { basic_expr {

View File

@ -489,6 +489,7 @@ RTLIL::Const RTLIL::const_mul(const RTLIL::Const &arg1, const RTLIL::Const &arg2
return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0));
} }
// truncating division
RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{ {
int undef_bit_pos = -1; int undef_bit_pos = -1;
@ -502,6 +503,7 @@ RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2
return big2const(result_neg ? -(a / b) : (a / b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); return big2const(result_neg ? -(a / b) : (a / b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0));
} }
// truncating modulo
RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{ {
int undef_bit_pos = -1; int undef_bit_pos = -1;
@ -515,6 +517,51 @@ RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2
return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0));
} }
RTLIL::Const RTLIL::const_divfloor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
int undef_bit_pos = -1;
BigInteger a = const2big(arg1, signed1, undef_bit_pos);
BigInteger b = const2big(arg2, signed2, undef_bit_pos);
if (b.isZero())
return RTLIL::Const(RTLIL::State::Sx, result_len);
bool result_pos = (a.getSign() == BigInteger::negative) == (b.getSign() == BigInteger::negative);
a = a.getSign() == BigInteger::negative ? -a : a;
b = b.getSign() == BigInteger::negative ? -b : b;
BigInteger result;
if (result_pos || a == 0) {
result = a / b;
} else {
// bigint division with negative numbers is wonky, make sure we only negate at the very end
result = -((a + b - 1) / b);
}
return big2const(result, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0));
}
RTLIL::Const RTLIL::const_modfloor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
int undef_bit_pos = -1;
BigInteger a = const2big(arg1, signed1, undef_bit_pos);
BigInteger b = const2big(arg2, signed2, undef_bit_pos);
if (b.isZero())
return RTLIL::Const(RTLIL::State::Sx, result_len);
BigInteger::Sign a_sign = a.getSign();
BigInteger::Sign b_sign = b.getSign();
a = a_sign == BigInteger::negative ? -a : a;
b = b_sign == BigInteger::negative ? -b : b;
BigInteger truncated = a_sign == BigInteger::negative ? -(a % b) : (a % b);
BigInteger modulo;
if (truncated == 0 || (a_sign == b_sign)) {
modulo = truncated;
} else {
modulo = b_sign == BigInteger::negative ? truncated - b : truncated + b;
}
return big2const(modulo, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0));
}
RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{ {
int undef_bit_pos = -1; int undef_bit_pos = -1;

View File

@ -187,7 +187,7 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL
return true; return true;
} }
// FIXME: $mul $div $mod $slice $concat // FIXME: $mul $div $mod $divfloor $modfloor $slice $concat
// FIXME: $lut $sop $alu $lcu $macc $fa // FIXME: $lut $sop $alu $lcu $macc $fa
return false; return false;

View File

@ -114,7 +114,7 @@ struct CellTypes
ID($and), ID($or), ID($xor), ID($xnor), ID($and), ID($or), ID($xor), ID($xnor),
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow),
ID($logic_and), ID($logic_or), ID($concat), ID($macc) ID($logic_and), ID($logic_or), ID($concat), ID($macc)
}; };
@ -304,6 +304,8 @@ struct CellTypes
HANDLE_CELL_TYPE(mul) HANDLE_CELL_TYPE(mul)
HANDLE_CELL_TYPE(div) HANDLE_CELL_TYPE(div)
HANDLE_CELL_TYPE(mod) HANDLE_CELL_TYPE(mod)
HANDLE_CELL_TYPE(divfloor)
HANDLE_CELL_TYPE(modfloor)
HANDLE_CELL_TYPE(pow) HANDLE_CELL_TYPE(pow)
HANDLE_CELL_TYPE(pos) HANDLE_CELL_TYPE(pos)
HANDLE_CELL_TYPE(neg) HANDLE_CELL_TYPE(neg)

View File

@ -2,13 +2,12 @@ X(A)
X(abc9_box) X(abc9_box)
X(abc9_box_id) X(abc9_box_id)
X(abc9_box_seq) X(abc9_box_seq)
X(abc9_bypass)
X(abc9_carry) X(abc9_carry)
X(abc9_flop) X(abc9_flop)
X(abc9_holes) X(abc9_keep)
X(abc9_init)
X(abc9_lut) X(abc9_lut)
X(abc9_mergeability) X(abc9_mergeability)
X(abc9_scc)
X(abc9_scc_id) X(abc9_scc_id)
X(abcgroup) X(abcgroup)
X(ABITS) X(ABITS)
@ -80,6 +79,8 @@ X(equiv_merged)
X(equiv_region) X(equiv_region)
X(extract_order) X(extract_order)
X(F) X(F)
X(force_downto)
X(force_upto)
X(fsm_encoding) X(fsm_encoding)
X(fsm_export) X(fsm_export)
X(FULL) X(FULL)
@ -170,6 +171,7 @@ X(techmap_autopurge)
X(_TECHMAP_BITS_CONNMAP_) X(_TECHMAP_BITS_CONNMAP_)
X(_TECHMAP_CELLTYPE_) X(_TECHMAP_CELLTYPE_)
X(techmap_celltype) X(techmap_celltype)
X(_TECHMAP_FAIL_)
X(techmap_maccmap) X(techmap_maccmap)
X(_TECHMAP_REPLACE_) X(_TECHMAP_REPLACE_)
X(techmap_simplemap) X(techmap_simplemap)

View File

@ -207,6 +207,7 @@ class dict
entry_t() { } entry_t() { }
entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { } entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { }
entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { } entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { }
bool operator<(const entry_t &other) const { return udata.first < other.udata.first; }
}; };
std::vector<int> hashtable; std::vector<int> hashtable;
@ -615,6 +616,15 @@ public:
return !operator==(other); return !operator==(other);
} }
unsigned int hash() const {
unsigned int h = mkhash_init;
for (auto &entry : entries) {
h ^= hash_ops<K>::hash(entry.udata.first);
h ^= hash_ops<T>::hash(entry.udata.second);
}
return h;
}
void reserve(size_t n) { entries.reserve(n); } void reserve(size_t n) { entries.reserve(n); }
size_t size() const { return entries.size(); } size_t size() const { return entries.size(); }
bool empty() const { return entries.empty(); } bool empty() const { return entries.empty(); }

View File

@ -42,7 +42,7 @@ std::vector<FILE*> log_files;
std::vector<std::ostream*> log_streams; std::vector<std::ostream*> log_streams;
std::map<std::string, std::set<std::string>> log_hdump; std::map<std::string, std::set<std::string>> log_hdump;
std::vector<YS_REGEX_TYPE> log_warn_regexes, log_nowarn_regexes, log_werror_regexes; std::vector<YS_REGEX_TYPE> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
std::vector<std::pair<YS_REGEX_TYPE,LogExpectedItem>> log_expect_log, log_expect_warning, log_expect_error; dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error;
std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored; std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored;
int log_warnings_count = 0; int log_warnings_count = 0;
int log_warnings_count_noexpect = 0; int log_warnings_count_noexpect = 0;
@ -181,7 +181,7 @@ void logv(const char *format, va_list ap)
log_warning("Found log message matching -W regex:\n%s", str.c_str()); log_warning("Found log message matching -W regex:\n%s", str.c_str());
for (auto &item : log_expect_log) for (auto &item : log_expect_log)
if (YS_REGEX_NS::regex_search(linebuffer, item.first)) if (YS_REGEX_NS::regex_search(linebuffer, item.second.pattern))
item.second.current_count++; item.second.current_count++;
linebuffer.clear(); linebuffer.clear();
@ -256,7 +256,7 @@ static void logv_warning_with_prefix(const char *prefix,
bool warning_match = false; bool warning_match = false;
for (auto &item : log_expect_warning) for (auto &item : log_expect_warning)
if (YS_REGEX_NS::regex_search(message, item.first)) { if (YS_REGEX_NS::regex_search(message, item.second.pattern)) {
item.second.current_count++; item.second.current_count++;
warning_match = true; warning_match = true;
} }
@ -349,7 +349,7 @@ static void logv_error_with_prefix(const char *prefix,
log_error_atexit(); log_error_atexit();
for (auto &item : log_expect_error) for (auto &item : log_expect_error)
if (YS_REGEX_NS::regex_search(log_last_error, item.first)) if (YS_REGEX_NS::regex_search(log_last_error, item.second.pattern))
item.second.current_count++; item.second.current_count++;
if (check_expected_logs) if (check_expected_logs)
@ -672,31 +672,31 @@ void log_check_expected()
for (auto &item : log_expect_warning) { for (auto &item : log_expect_warning) {
if (item.second.current_count == 0) { if (item.second.current_count == 0) {
log_warn_regexes.clear(); log_warn_regexes.clear();
log_error("Expected warning pattern '%s' not found !\n", item.second.pattern.c_str()); log_error("Expected warning pattern '%s' not found !\n", item.first.c_str());
} }
if (item.second.current_count != item.second.expected_count) { if (item.second.current_count != item.second.expected_count) {
log_warn_regexes.clear(); log_warn_regexes.clear();
log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n", log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n",
item.second.pattern.c_str(), item.second.current_count, item.second.expected_count); item.first.c_str(), item.second.current_count, item.second.expected_count);
} }
} }
for (auto &item : log_expect_log) { for (auto &item : log_expect_log) {
if (item.second.current_count == 0) { if (item.second.current_count == 0) {
log_warn_regexes.clear(); log_warn_regexes.clear();
log_error("Expected log pattern '%s' not found !\n", item.second.pattern.c_str()); log_error("Expected log pattern '%s' not found !\n", item.first.c_str());
} }
if (item.second.current_count != item.second.expected_count) { if (item.second.current_count != item.second.expected_count) {
log_warn_regexes.clear(); log_warn_regexes.clear();
log_error("Expected log pattern '%s' found %d time(s), instead of %d time(s) !\n", log_error("Expected log pattern '%s' found %d time(s), instead of %d time(s) !\n",
item.second.pattern.c_str(), item.second.current_count, item.second.expected_count); item.first.c_str(), item.second.current_count, item.second.expected_count);
} }
} }
for (auto &item : log_expect_error) for (auto &item : log_expect_error)
if (item.second.current_count == item.second.expected_count) { if (item.second.current_count == item.second.expected_count) {
log_warn_regexes.clear(); log_warn_regexes.clear();
log("Expected error pattern '%s' found !!!\n", item.second.pattern.c_str()); log("Expected error pattern '%s' found !!!\n", item.first.c_str());
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
throw 0; throw 0;
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
@ -707,7 +707,7 @@ void log_check_expected()
} else { } else {
display_error_log_msg = false; display_error_log_msg = false;
log_warn_regexes.clear(); log_warn_regexes.clear();
log_error("Expected error pattern '%s' not found !\n", item.second.pattern.c_str()); log_error("Expected error pattern '%s' not found !\n", item.first.c_str());
} }
} }

View File

@ -86,7 +86,7 @@ YOSYS_NAMESPACE_BEGIN
# endif # endif
# if __has_builtin(__builtin_debugtrap) # if __has_builtin(__builtin_debugtrap)
# define YS_DEBUGTRAP __builtin_debugtrap() # define YS_DEBUGTRAP __builtin_debugtrap()
# elif defined(__unix__) # elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
# define YS_DEBUGTRAP raise(SIGTRAP) # define YS_DEBUGTRAP raise(SIGTRAP)
# else # else
# define YS_DEBUGTRAP do {} while(0) # define YS_DEBUGTRAP do {} while(0)
@ -97,11 +97,11 @@ YOSYS_NAMESPACE_BEGIN
// if a debugger is attached, and does nothing otherwise. // if a debugger is attached, and does nothing otherwise.
#if defined(_WIN32) #if defined(_WIN32)
# define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0) # define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0)
#elif defined(__unix__) # elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
// There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However, // There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However,
// debuggers will stop when SIGTRAP is raised, even if the action is set to ignore. // debuggers will stop when SIGTRAP is raised, even if the action is set to ignore.
# define YS_DEBUGTRAP_IF_DEBUGGING do { \ # define YS_DEBUGTRAP_IF_DEBUGGING do { \
sighandler_t old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \ auto old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \
} while(0) } while(0)
#else #else
# define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0) # define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0)
@ -202,19 +202,16 @@ void log_flush();
struct LogExpectedItem struct LogExpectedItem
{ {
LogExpectedItem(std::string pattern, int expected) : LogExpectedItem(const YS_REGEX_TYPE &pat, int expected) :
expected_count(expected), pattern(pat), expected_count(expected), current_count(0) {}
current_count(0), LogExpectedItem() : expected_count(0), current_count(0) {}
pattern(pattern)
{
}
YS_REGEX_TYPE pattern;
int expected_count; int expected_count;
int current_count; int current_count;
std::string pattern;
}; };
extern std::vector<std::pair<YS_REGEX_TYPE,LogExpectedItem>> log_expect_log, log_expect_warning, log_expect_error; extern dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error;
void log_check_expected(); void log_check_expected();
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);

View File

@ -948,7 +948,7 @@ namespace {
return; return;
} }
if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow))) { if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow))) {
param_bool(ID::A_SIGNED); param_bool(ID::A_SIGNED);
param_bool(ID::B_SIGNED); param_bool(ID::B_SIGNED);
port(ID::A, param(ID::A_WIDTH)); port(ID::A, param(ID::A_WIDTH));
@ -1949,6 +1949,8 @@ DEF_METHOD(Sub, max(sig_a.size(), sig_b.size()), ID($sub))
DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), ID($mul)) DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), ID($mul))
DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), ID($div)) DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), ID($div))
DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), ID($mod)) DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), ID($mod))
DEF_METHOD(DivFloor, max(sig_a.size(), sig_b.size()), ID($divfloor))
DEF_METHOD(ModFloor, max(sig_a.size(), sig_b.size()), ID($modfloor))
DEF_METHOD(LogicAnd, 1, ID($logic_and)) DEF_METHOD(LogicAnd, 1, ID($logic_and))
DEF_METHOD(LogicOr, 1, ID($logic_or)) DEF_METHOD(LogicOr, 1, ID($logic_or))
#undef DEF_METHOD #undef DEF_METHOD

View File

@ -150,9 +150,6 @@ namespace RTLIL
if (!p[0]) if (!p[0])
return 0; return 0;
log_assert(p[0] == '$' || p[0] == '\\');
log_assert(p[1] != 0);
auto it = global_id_index_.find((char*)p); auto it = global_id_index_.find((char*)p);
if (it != global_id_index_.end()) { if (it != global_id_index_.end()) {
#ifndef YOSYS_NO_IDS_REFCNT #ifndef YOSYS_NO_IDS_REFCNT
@ -165,6 +162,11 @@ namespace RTLIL
return it->second; return it->second;
} }
log_assert(p[0] == '$' || p[0] == '\\');
log_assert(p[1] != 0);
for (const char *c = p; *c; c++)
log_assert((unsigned)*c > (unsigned)' ');
#ifndef YOSYS_NO_IDS_REFCNT #ifndef YOSYS_NO_IDS_REFCNT
if (global_free_idx_list_.empty()) { if (global_free_idx_list_.empty()) {
if (global_id_storage_.empty()) { if (global_id_storage_.empty()) {
@ -296,8 +298,8 @@ namespace RTLIL
// The methods below are just convenience functions for better compatibility with std::string. // The methods below are just convenience functions for better compatibility with std::string.
bool operator==(const std::string &rhs) const { return str() == rhs; } bool operator==(const std::string &rhs) const { return c_str() == rhs; }
bool operator!=(const std::string &rhs) const { return str() != rhs; } bool operator!=(const std::string &rhs) const { return c_str() != rhs; }
bool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; } bool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; }
bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }
@ -466,6 +468,8 @@ namespace RTLIL
RTLIL::Const const_sub (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_sub (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_mul (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_mul (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_div (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_div (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_divfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_modfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_mod (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_mod (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
@ -721,7 +725,7 @@ struct RTLIL::SigBit
SigBit(const RTLIL::SigChunk &chunk); SigBit(const RTLIL::SigChunk &chunk);
SigBit(const RTLIL::SigChunk &chunk, int index); SigBit(const RTLIL::SigChunk &chunk, int index);
SigBit(const RTLIL::SigSpec &sig); SigBit(const RTLIL::SigSpec &sig);
SigBit(const RTLIL::SigBit &sigbit); SigBit(const RTLIL::SigBit &sigbit) = default;
RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default; RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default;
bool operator <(const RTLIL::SigBit &other) const; bool operator <(const RTLIL::SigBit &other) const;
@ -1134,8 +1138,14 @@ public:
return design->selected_member(name, member->name); return design->selected_member(name, member->name);
} }
RTLIL::Wire* wire(RTLIL::IdString id) { return wires_.count(id) ? wires_.at(id) : nullptr; } RTLIL::Wire* wire(RTLIL::IdString id) {
RTLIL::Cell* cell(RTLIL::IdString id) { return cells_.count(id) ? cells_.at(id) : nullptr; } auto it = wires_.find(id);
return it == wires_.end() ? nullptr : it->second;
}
RTLIL::Cell* cell(RTLIL::IdString id) {
auto it = cells_.find(id);
return it == cells_.end() ? nullptr : it->second;
}
RTLIL::ObjRange<RTLIL::Wire*> wires() { return RTLIL::ObjRange<RTLIL::Wire*>(&wires_, &refcount_wires_); } RTLIL::ObjRange<RTLIL::Wire*> wires() { return RTLIL::ObjRange<RTLIL::Wire*>(&wires_, &refcount_wires_); }
RTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); } RTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); }
@ -1196,8 +1206,12 @@ public:
RTLIL::Cell* addAdd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addAdd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
RTLIL::Cell* addSub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addSub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
RTLIL::Cell* addMul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addMul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
// truncating division
RTLIL::Cell* addDiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addDiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
// truncating modulo
RTLIL::Cell* addMod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addMod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
RTLIL::Cell* addDivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
RTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
RTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = ""); RTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = "");
RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
@ -1295,8 +1309,12 @@ public:
RTLIL::SigSpec Add (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Add (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
RTLIL::SigSpec Sub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Sub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
RTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
// truncating division
RTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
// truncating modulo
RTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
RTLIL::SigSpec DivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
RTLIL::SigSpec ModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
RTLIL::SigSpec Pow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool a_signed = false, bool b_signed = false, const std::string &src = ""); RTLIL::SigSpec Pow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool a_signed = false, bool b_signed = false, const std::string &src = "");
RTLIL::SigSpec LogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec LogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
@ -1494,7 +1512,6 @@ inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_as
inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); } inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); }
inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; } inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }
inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; } inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }
inline RTLIL::SigBit::SigBit(const RTLIL::SigBit &sigbit) : wire(sigbit.wire), data(sigbit.data){ if (wire) offset = sigbit.offset; }
inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const { inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
if (wire == other.wire) if (wire == other.wire)

View File

@ -279,7 +279,7 @@ struct SatGen
bool arith_undef_handled = false; bool arith_undef_handled = false;
bool is_arith_compare = cell->type.in(ID($lt), ID($le), ID($ge), ID($gt)); bool is_arith_compare = cell->type.in(ID($lt), ID($le), ID($ge), ID($gt));
if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod)) || is_arith_compare)) if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor)) || is_arith_compare))
{ {
std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
@ -293,7 +293,7 @@ struct SatGen
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
int undef_y_bit = ez->OR(undef_any_a, undef_any_b); int undef_y_bit = ez->OR(undef_any_a, undef_any_b);
if (cell->type.in(ID($div), ID($mod))) { if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) {
std::vector<int> b = importSigSpec(cell->getPort(ID::B), timestep); std::vector<int> b = importSigSpec(cell->getPort(ID::B), timestep);
undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b))); undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b)));
} }
@ -935,7 +935,7 @@ struct SatGen
return true; return true;
} }
if (cell->type.in(ID($div), ID($mod))) if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor)))
{ {
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
@ -970,23 +970,48 @@ struct SatGen
} }
std::vector<int> y_tmp = ignore_div_by_zero ? yy : ez->vec_var(y.size()); std::vector<int> y_tmp = ignore_div_by_zero ? yy : ez->vec_var(y.size());
// modulo calculation
std::vector<int> modulo_trunc;
int floored_eq_trunc;
if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) {
modulo_trunc = ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf);
// floor == trunc when sgn(a) == sgn(b) or trunc == 0
floored_eq_trunc = ez->OR(ez->IFF(a.back(), b.back()), ez->NOT(ez->expression(ezSAT::OpOr, modulo_trunc)));
} else {
modulo_trunc = chain_buf;
floored_eq_trunc = ez->CONST_TRUE;
}
if (cell->type == ID($div)) { if (cell->type == ID($div)) {
if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool())
ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(ez->XOR(a.back(), b.back()), ez->vec_neg(y_u), y_u))); ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(ez->XOR(a.back(), b.back()), ez->vec_neg(y_u), y_u)));
else else
ez->assume(ez->vec_eq(y_tmp, y_u)); ez->assume(ez->vec_eq(y_tmp, y_u));
} else { } else if (cell->type == ID($mod)) {
ez->assume(ez->vec_eq(y_tmp, modulo_trunc));
} else if (cell->type == ID($divfloor)) {
if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool())
ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf))); ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(
ez->XOR(a.back(), b.back()),
ez->vec_neg(ez->vec_ite(
ez->vec_reduce_or(modulo_trunc),
ez->vec_add(y_u, ez->vec_const_unsigned(1, y_u.size())),
y_u
)),
y_u
)));
else else
ez->assume(ez->vec_eq(y_tmp, chain_buf)); ez->assume(ez->vec_eq(y_tmp, y_u));
} else if (cell->type == ID($modfloor)) {
ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(floored_eq_trunc, modulo_trunc, ez->vec_add(modulo_trunc, b))));
} }
if (ignore_div_by_zero) { if (ignore_div_by_zero) {
ez->assume(ez->expression(ezSAT::OpOr, b)); ez->assume(ez->expression(ezSAT::OpOr, b));
} else { } else {
std::vector<int> div_zero_result; std::vector<int> div_zero_result;
if (cell->type == ID($div)) { if (cell->type.in(ID($div), ID($divfloor))) {
if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) {
std::vector<int> all_ones(y.size(), ez->CONST_TRUE); std::vector<int> all_ones(y.size(), ez->CONST_TRUE);
std::vector<int> only_first_one(y.size(), ez->CONST_FALSE); std::vector<int> only_first_one(y.size(), ez->CONST_FALSE);
@ -996,7 +1021,8 @@ struct SatGen
div_zero_result.insert(div_zero_result.end(), cell->getPort(ID::A).size(), ez->CONST_TRUE); div_zero_result.insert(div_zero_result.end(), cell->getPort(ID::A).size(), ez->CONST_TRUE);
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE);
} }
} else { } else if (cell->type.in(ID($mod), ID($modfloor))) {
// a mod 0 = a
int copy_a_bits = min(cell->getPort(ID::A).size(), cell->getPort(ID::B).size()); int copy_a_bits = min(cell->getPort(ID::A).size(), cell->getPort(ID::B).size());
div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits); div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits);
if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool())

View File

@ -82,6 +82,9 @@ struct TimingInfo
for (auto cell : module->cells()) { for (auto cell : module->cells()) {
if (cell->type == ID($specify2)) { if (cell->type == ID($specify2)) {
auto en = cell->getPort(ID::EN);
if (en.is_fully_const() && !en.as_bool())
continue;
auto src = cell->getPort(ID::SRC); auto src = cell->getPort(ID::SRC);
auto dst = cell->getPort(ID::DST); auto dst = cell->getPort(ID::DST);
for (const auto &c : src.chunks()) for (const auto &c : src.chunks())
@ -128,11 +131,9 @@ struct TimingInfo
int rise_max = cell->getParam(ID::T_RISE_MAX).as_int(); int rise_max = cell->getParam(ID::T_RISE_MAX).as_int();
int fall_max = cell->getParam(ID::T_FALL_MAX).as_int(); int fall_max = cell->getParam(ID::T_FALL_MAX).as_int();
int max = std::max(rise_max,fall_max); int max = std::max(rise_max,fall_max);
if (max < 0) if (max < 0) {
log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell));
if (max <= 0) { max = 0;
log_debug("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX <= 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell));
continue;
} }
for (const auto &d : dst) { for (const auto &d : dst) {
auto &v = t.arrival[NameBit(d)]; auto &v = t.arrival[NameBit(d)];
@ -152,11 +153,9 @@ struct TimingInfo
if (!c.wire->port_input) if (!c.wire->port_input)
log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst)); log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst));
int max = cell->getParam(ID::T_LIMIT_MAX).as_int(); int max = cell->getParam(ID::T_LIMIT_MAX).as_int();
if (max < 0) if (max < 0) {
log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell));
if (max <= 0) { max = 0;
log_debug("Module '%s' contains specify cell '%s' with T_LIMIT_MAX <= 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell));
continue;
} }
for (const auto &s : src) { for (const auto &s : src) {
auto &v = t.required[NameBit(s)]; auto &v = t.required[NameBit(s)];

View File

@ -139,6 +139,8 @@ Verilog & Cell Type \\
\lstinline[language=Verilog]; Y = A * B; & {\tt \$mul} \\ \lstinline[language=Verilog]; Y = A * B; & {\tt \$mul} \\
\lstinline[language=Verilog]; Y = A / B; & {\tt \$div} \\ \lstinline[language=Verilog]; Y = A / B; & {\tt \$div} \\
\lstinline[language=Verilog]; Y = A % B; & {\tt \$mod} \\ \lstinline[language=Verilog]; Y = A % B; & {\tt \$mod} \\
\multicolumn{1}{c}{\tt [N/A]} & {\tt \$divfloor} \\
\multicolumn{1}{c}{\tt [N/A]} & {\tt \$modfoor} \\
\lstinline[language=Verilog]; Y = A ** B; & {\tt \$pow} \\ \lstinline[language=Verilog]; Y = A ** B; & {\tt \$pow} \\
\end{tabular} \end{tabular}
\caption{Cell types for binary operators with their corresponding Verilog expressions.} \caption{Cell types for binary operators with their corresponding Verilog expressions.}
@ -161,6 +163,27 @@ For the binary cells that output a logical value ({\tt \$logic\_and}, {\tt \$log
{\tt \$gt}), when the \B{Y\_WIDTH} parameter is greater than 1, the output is zero-extended, {\tt \$gt}), when the \B{Y\_WIDTH} parameter is greater than 1, the output is zero-extended,
and only the least significant bit varies. and only the least significant bit varies.
Division and modulo cells are available in two rounding modes. The original {\tt \$div} and {\tt \$mod}
cells are based on truncating division, and correspond to the semantics of the verilog {\tt /} and
{\tt \%} operators. The {\tt \$divfloor} and {\tt \$modfloor} cells represent flooring division and
flooring modulo, the latter of which is also known as ``remainder'' in several languages. See
table~\ref{tab:CellLib_divmod} for a side-by-side comparison between the different semantics.
\begin{table}[h]
\hfil
\begin{tabular}{lr|rr|rr}
\multirow{2}{*}{Division} & \multirow{2}{*}{Result} & \multicolumn{2}{c|}{Truncating} & \multicolumn{2}{c}{Flooring} \\
& & {\tt \$div} & {\tt \$mod} & {\tt \$divfloor} & {\tt \$modfloor} \\
\hline
{\tt -10 / 3} & {\tt -3.3} & {\tt -3} & {\tt -1} & {\tt -4} & {\tt 2} \\
{\tt 10 / -3} & {\tt -3.3} & {\tt -3} & {\tt 1} & {\tt -4} & {\tt -2} \\
{\tt -10 / -3} & {\tt 3.3} & {\tt 3} & {\tt -1} & {\tt 3} & {\tt -1} \\
{\tt 10 / 3} & {\tt 3.3} & {\tt 3} & {\tt 1} & {\tt 3} & {\tt 1} \\
\end{tabular}
\caption{Comparison between different rounding modes for division and modulo cells.}
\label{tab:CellLib_divmod}
\end{table}
\subsection{Multiplexers} \subsection{Multiplexers}
Multiplexers are generated by the Verilog HDL frontend for {\tt Multiplexers are generated by the Verilog HDL frontend for {\tt

View File

@ -184,9 +184,12 @@ may hold important information for Yosys developers can be used without
disturbing external tools. For example the Verilog backend assigns names in the form {\tt \_{\it integer}\_}. disturbing external tools. For example the Verilog backend assigns names in the form {\tt \_{\it integer}\_}.
\end{itemize} \end{itemize}
In order to avoid programming errors, the RTLIL data structures check if all Whitespace and control characters (any character with an ASCII code 32 or less) are not allowed
identifiers start with either a backslash or a dollar sign and generate a in RTLIL identifiers; most frontends and backends cannot support these characters in identifiers.
runtime error if this rule is violated.
In order to avoid programming errors, the RTLIL data structures check if all identifiers start
with either a backslash or a dollar sign, and contain no whitespace or control characters.
Violating these rules results in a runtime error.
All RTLIL identifiers are case sensitive. All RTLIL identifiers are case sensitive.

View File

@ -307,7 +307,7 @@ cell name from the internal cell library:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont] \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont]
$not $pos $neg $and $or $xor $xnor $reduce_and $reduce_or $reduce_xor $reduce_xnor $not $pos $neg $and $or $xor $xnor $reduce_and $reduce_or $reduce_xor $reduce_xnor
$reduce_bool $shl $shr $sshl $sshr $lt $le $eq $ne $eqx $nex $ge $gt $add $sub $mul $div $mod $reduce_bool $shl $shr $sshl $sshr $lt $le $eq $ne $eqx $nex $ge $gt $add $sub $mul $div $mod
$pow $logic_not $logic_and $logic_or $mux $pmux $slice $concat $lut $assert $sr $dff $divfloor $modfloor $pow $logic_not $logic_and $logic_or $mux $pmux $slice $concat $lut $assert $sr $dff
$dffsr $adff $dlatch $dlatchsr $memrd $memwr $mem $fsm $_NOT_ $_AND_ $_OR_ $_XOR_ $_MUX_ $_SR_NN_ $dffsr $adff $dlatch $dlatchsr $memrd $memwr $mem $fsm $_NOT_ $_AND_ $_OR_ $_XOR_ $_MUX_ $_SR_NN_
$_SR_NP_ $_SR_PN_ $_SR_PP_ $_DFF_N_ $_DFF_P_ $_DFF_NN0_ $_DFF_NN1_ $_DFF_NP0_ $_DFF_NP1_ $_DFF_PN0_ $_SR_NP_ $_SR_PN_ $_SR_PP_ $_DFF_N_ $_DFF_P_ $_DFF_NN0_ $_DFF_NN1_ $_DFF_NP0_ $_DFF_NP1_ $_DFF_PN0_
$_DFF_PN1_ $_DFF_PP0_ $_DFF_PP1_ $_DFFSR_NNN_ $_DFFSR_NNP_ $_DFFSR_NPN_ $_DFFSR_NPP_ $_DFFSR_PNN_ $_DFF_PN1_ $_DFF_PP0_ $_DFF_PP1_ $_DFFSR_NNN_ $_DFFSR_NNP_ $_DFFSR_NPN_ $_DFFSR_NPP_ $_DFFSR_PNN_

View File

@ -39,3 +39,4 @@ OBJS += passes/cmds/bugpoint.o
endif endif
OBJS += passes/cmds/scratchpad.o OBJS += passes/cmds/scratchpad.o
OBJS += passes/cmds/logger.o OBJS += passes/cmds/logger.o
OBJS += passes/cmds/printattrs.o

View File

@ -48,31 +48,7 @@ struct BlackboxPass : public Pass {
for (auto module : design->selected_whole_modules_warn()) for (auto module : design->selected_whole_modules_warn())
{ {
pool<Cell*> remove_cells; module->makeblackbox();
pool<Wire*> remove_wires;
for (auto cell : module->cells())
remove_cells.insert(cell);
for (auto wire : module->wires())
if (wire->port_id == 0)
remove_wires.insert(wire);
for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
delete it->second;
module->memories.clear();
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
delete it->second;
module->processes.clear();
module->new_connections(std::vector<RTLIL::SigSig>());
for (auto cell : remove_cells)
module->remove(cell);
module->remove(remove_wires);
module->set_bool_attribute(ID::blackbox); module->set_bool_attribute(ID::blackbox);
} }
} }

View File

@ -58,7 +58,8 @@ struct LoggerPass : public Pass {
log(" do not print warnings for the specified experimental feature\n"); log(" do not print warnings for the specified experimental feature\n");
log("\n"); log("\n");
log(" -expect <type> <regex> <expected_count>\n"); log(" -expect <type> <regex> <expected_count>\n");
log(" expect log,warning or error to appear. In case of error return code is 0.\n"); log(" expect log, warning or error to appear. matched errors will terminate\n");
log(" with exit code 0.\n");
log("\n"); log("\n");
log(" -expect-no-warnings\n"); log(" -expect-no-warnings\n");
log(" gives error in case there is at least one warning that is not expected.\n"); log(" gives error in case there is at least one warning that is not expected.\n");
@ -158,12 +159,13 @@ struct LoggerPass : public Pass {
log_cmd_error("Expected error message occurrences must be 1 !\n"); log_cmd_error("Expected error message occurrences must be 1 !\n");
log("Added regex '%s' for warnings to expected %s list.\n", pattern.c_str(), type.c_str()); log("Added regex '%s' for warnings to expected %s list.\n", pattern.c_str(), type.c_str());
try { try {
if (type=="error") if (type == "error")
log_expect_error.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); log_expect_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
else if (type=="warning") else if (type == "warning")
log_expect_warning.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); log_expect_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
else else if (type == "log")
log_expect_log.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); log_expect_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
else log_abort();
} }
catch (const YS_REGEX_NS::regex_error& e) { catch (const YS_REGEX_NS::regex_error& e) {
log_cmd_error("Error in regex expression '%s' !\n", pattern.c_str()); log_cmd_error("Error in regex expression '%s' !\n", pattern.c_str());

90
passes/cmds/printattrs.cc Normal file
View File

@ -0,0 +1,90 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2020 Alberto Gonzalez <boqwxp@airmail.cc>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct PrintAttrsPass : public Pass {
PrintAttrsPass() : Pass("printattrs", "print attributes of selected objects") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" printattrs [selection]\n");
log("\n");
log("Print all attributes of the selected objects.\n");
log("\n");
log("\n");
}
static std::string get_indent_str(const unsigned int indent) {
return stringf("%*s", indent, "");
}
static void log_const(const RTLIL::IdString &s, const RTLIL::Const &x, const unsigned int indent) {
if (x.flags == RTLIL::CONST_FLAG_STRING)
log("%s(* %s=\"%s\" *)\n", get_indent_str(indent).c_str(), log_id(s), x.decode_string().c_str());
else if (x.flags == RTLIL::CONST_FLAG_NONE)
log("%s(* %s=%s *)\n", get_indent_str(indent).c_str(), log_id(s), x.as_string().c_str());
else
log_assert(x.flags == RTLIL::CONST_FLAG_STRING || x.flags == RTLIL::CONST_FLAG_NONE); //intended to fail
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx = 1;
extra_args(args, argidx, design);
unsigned int indent = 0;
for (auto mod : design->selected_modules())
{
if (design->selected_whole_module(mod)) {
log("%s%s\n", get_indent_str(indent).c_str(), log_id(mod->name));
indent += 2;
for (auto &it : mod->attributes)
log_const(it.first, it.second, indent);
}
for (auto cell : mod->selected_cells()) {
log("%s%s\n", get_indent_str(indent).c_str(), log_id(cell->name));
indent += 2;
for (auto &it : cell->attributes)
log_const(it.first, it.second, indent);
indent -= 2;
}
for (auto wire : mod->selected_wires()) {
log("%s%s\n", get_indent_str(indent).c_str(), log_id(wire->name));
indent += 2;
for (auto &it : wire->attributes)
log_const(it.first, it.second, indent);
indent -= 2;
}
if (design->selected_whole_module(mod))
indent -= 2;
}
log("\n");
}
} PrintAttrsPass;
PRIVATE_NAMESPACE_END

View File

@ -109,7 +109,7 @@ struct statdata_t
ID($lut), ID($and), ID($or), ID($xor), ID($xnor), ID($lut), ID($and), ID($or), ID($xor), ID($xnor),
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow), ID($alu))) { ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($alu))) {
int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0; int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0;
int width_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0; int width_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0;
int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0; int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0;

View File

@ -574,9 +574,9 @@ struct HierarchyPass : public Pass {
log("\n"); log("\n");
log("In parametric designs, a module might exists in several variations with\n"); log("In parametric designs, a module might exists in several variations with\n");
log("different parameter values. This pass looks at all modules in the current\n"); log("different parameter values. This pass looks at all modules in the current\n");
log("design an re-runs the language frontends for the parametric modules as\n"); log("design and re-runs the language frontends for the parametric modules as\n");
log("needed. It also resolves assignments to wired logic data types (wand/wor),\n"); log("needed. It also resolves assignments to wired logic data types (wand/wor),\n");
log("resolves positional module parameters, unroll array instances, and more.\n"); log("resolves positional module parameters, unrolls array instances, and more.\n");
log("\n"); log("\n");
log(" -check\n"); log(" -check\n");
log(" also check the design hierarchy. this generates an error when\n"); log(" also check the design hierarchy. this generates an error when\n");

View File

@ -715,6 +715,8 @@ struct MemoryShareWorker
cone_ct.cell_types.erase(ID($mul)); cone_ct.cell_types.erase(ID($mul));
cone_ct.cell_types.erase(ID($mod)); cone_ct.cell_types.erase(ID($mod));
cone_ct.cell_types.erase(ID($div)); cone_ct.cell_types.erase(ID($div));
cone_ct.cell_types.erase(ID($modfloor));
cone_ct.cell_types.erase(ID($divfloor));
cone_ct.cell_types.erase(ID($pow)); cone_ct.cell_types.erase(ID($pow));
cone_ct.cell_types.erase(ID($shl)); cone_ct.cell_types.erase(ID($shl));
cone_ct.cell_types.erase(ID($shr)); cone_ct.cell_types.erase(ID($shr));

View File

@ -412,7 +412,7 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
return !del_wires_queue.empty(); return !del_wires_queue.empty();
} }
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) bool rmunused_module_init(RTLIL::Module *module, bool verbose)
{ {
bool did_something = false; bool did_something = false;
CellTypes fftypes; CellTypes fftypes;
@ -445,9 +445,6 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
if (!purge_mode && wire->name[0] == '\\')
continue;
if (wire->attributes.count(ID::init) == 0) if (wire->attributes.count(ID::init) == 0)
continue; continue;
@ -464,11 +461,22 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
if (wire_bit == mapped_wire_bit) if (wire_bit == mapped_wire_bit)
goto next_wire; goto next_wire;
if (qbits.count(sigmap(SigBit(wire, i))) == 0) if (mapped_wire_bit.wire) {
goto next_wire; if (qbits.count(mapped_wire_bit) == 0)
goto next_wire;
if (qbits.at(sigmap(SigBit(wire, i))) != init[i]) if (qbits.at(mapped_wire_bit) != init[i])
goto next_wire; goto next_wire;
}
else {
if (mapped_wire_bit == State::Sx || mapped_wire_bit == State::Sz)
goto next_wire;
if (mapped_wire_bit != init[i]) {
log_warning("Initial value conflict for %s resolving to %s but with init %s.\n", log_signal(wire_bit), log_signal(mapped_wire_bit), log_signal(init[i]));
goto next_wire;
}
}
} }
if (verbose) if (verbose)
@ -512,7 +520,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
rmunused_module_cells(module, verbose); rmunused_module_cells(module, verbose);
while (rmunused_module_signals(module, purge_mode, verbose)) { } while (rmunused_module_signals(module, purge_mode, verbose)) { }
if (rminit && rmunused_module_init(module, purge_mode, verbose)) if (rminit && rmunused_module_init(module, verbose))
while (rmunused_module_signals(module, purge_mode, verbose)) { } while (rmunused_module_signals(module, purge_mode, verbose)) { }
} }
@ -611,8 +619,7 @@ struct CleanPass : public Pass {
} }
break; break;
} }
if (argidx < args.size()) extra_args(args, argidx, design);
extra_args(args, argidx, design);
keep_cache.reset(design); keep_cache.reset(design);
@ -627,7 +634,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) { for (auto module : design->selected_whole_modules()) {
if (module->has_processes()) if (module->has_processes())
continue; continue;
rmunused_module(module, purge_mode, ys_debug(), false); rmunused_module(module, purge_mode, ys_debug(), true);
} }
log_suppressed(); log_suppressed();

View File

@ -132,7 +132,7 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell,
did_something = true; did_something = true;
} }
bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap) bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap, bool keepdc)
{ {
IdString b_name = cell->hasPort(ID::B) ? ID::B : ID::A; IdString b_name = cell->hasPort(ID::B) ? ID::B : ID::A;
@ -156,20 +156,36 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
int group_idx = GRP_DYN; int group_idx = GRP_DYN;
RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i]; RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i];
if (cell->type == ID($or) && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1)) if (cell->type == ID($or)) {
bit_a = bit_b = RTLIL::State::S1; if (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1)
bit_a = bit_b = RTLIL::State::S1;
}
else if (cell->type == ID($and)) {
if (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0)
bit_a = bit_b = RTLIL::State::S0;
}
else if (!keepdc) {
if (cell->type == ID($xor)) {
if (bit_a == bit_b)
bit_a = bit_b = RTLIL::State::S0;
}
else if (cell->type == ID($xnor)) {
if (bit_a == bit_b)
bit_a = bit_b = RTLIL::State::S1; // For consistency with gate-level which does $xnor -> $_XOR_ + $_NOT_
}
}
if (cell->type == ID($and) && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0)) bool def = (bit_a != State::Sx && bit_a != State::Sz && bit_b != State::Sx && bit_b != State::Sz);
bit_a = bit_b = RTLIL::State::S0; if (def || !keepdc) {
if (bit_a.wire == NULL && bit_b.wire == NULL)
if (bit_a.wire == NULL && bit_b.wire == NULL) group_idx = GRP_CONST_AB;
group_idx = GRP_CONST_AB; else if (bit_a.wire == NULL)
else if (bit_a.wire == NULL) group_idx = GRP_CONST_A;
group_idx = GRP_CONST_A; else if (bit_b.wire == NULL && commutative)
else if (bit_b.wire == NULL && commutative) group_idx = GRP_CONST_A, std::swap(bit_a, bit_b);
group_idx = GRP_CONST_A, std::swap(bit_a, bit_b); else if (bit_b.wire == NULL)
else if (bit_b.wire == NULL) group_idx = GRP_CONST_B;
group_idx = GRP_CONST_B; }
grouped_bits[group_idx][std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit_a, bit_b)].insert(bits_y[i]); grouped_bits[group_idx][std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit_a, bit_b)].insert(bits_y[i]);
} }
@ -186,26 +202,77 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
if (grouped_bits[i].empty()) if (grouped_bits[i].empty())
continue; continue;
RTLIL::Wire *new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i])); RTLIL::SigSpec new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i]));
RTLIL::SigSpec new_a, new_b; RTLIL::SigSpec new_a, new_b;
RTLIL::SigSig new_conn; RTLIL::SigSig new_conn;
for (auto &it : grouped_bits[i]) { for (auto &it : grouped_bits[i]) {
for (auto &bit : it.second) { for (auto &bit : it.second) {
new_conn.first.append(bit); new_conn.first.append(bit);
new_conn.second.append(RTLIL::SigBit(new_y, new_a.size())); new_conn.second.append(new_y[new_a.size()]);
} }
new_a.append(it.first.first); new_a.append(it.first.first);
new_b.append(it.first.second); new_b.append(it.first.second);
} }
if (cell->type.in(ID($and), ID($or)) && i == GRP_CONST_A) { if (cell->type.in(ID($and), ID($or)) && i == GRP_CONST_A) {
if (!keepdc) {
if (cell->type == ID($and))
new_a.replace(dict<SigBit,SigBit>{{State::Sx, State::S0}, {State::Sz, State::S0}}, &new_b);
else if (cell->type == ID($or))
new_a.replace(dict<SigBit,SigBit>{{State::Sx, State::S1}, {State::Sz, State::S1}}, &new_b);
else log_abort();
}
log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a)); log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a));
module->connect(new_y, new_b); module->connect(new_y, new_b);
module->connect(new_conn); module->connect(new_conn);
continue; continue;
} }
if (cell->type.in(ID($xor), ID($xnor)) && i == GRP_CONST_A) {
SigSpec undef_a, undef_y, undef_b;
SigSpec def_y, def_a, def_b;
for (int i = 0; i < GetSize(new_y); i++) {
bool undef = new_a[i] == State::Sx || new_a[i] == State::Sz;
if (!keepdc && (undef || new_a[i] == new_b[i])) {
undef_a.append(new_a[i]);
if (cell->type == ID($xor))
undef_b.append(State::S0);
// For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_
else if (cell->type == ID($xnor))
undef_b.append(State::S1);
else log_abort();
undef_y.append(new_y[i]);
}
else if (new_a[i] == State::S0 || new_a[i] == State::S1) {
undef_a.append(new_a[i]);
if (cell->type == ID($xor))
undef_b.append(new_a[i] == State::S1 ? module->Not(NEW_ID, new_b[i]).as_bit() : new_b[i]);
else if (cell->type == ID($xnor))
undef_b.append(new_a[i] == State::S1 ? new_b[i] : module->Not(NEW_ID, new_b[i]).as_bit());
else log_abort();
undef_y.append(new_y[i]);
}
else {
def_a.append(new_a[i]);
def_b.append(new_b[i]);
def_y.append(new_y[i]);
}
}
if (!undef_y.empty()) {
log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(undef_b), log_id(cell->type), log_signal(undef_a));
module->connect(undef_y, undef_b);
if (def_y.empty()) {
module->connect(new_conn);
continue;
}
}
new_a = std::move(def_a);
new_b = std::move(def_b);
new_y = std::move(def_y);
}
RTLIL::Cell *c = module->addCell(NEW_ID, cell->type); RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
c->setPort(ID::A, new_a); c->setPort(ID::A, new_a);
@ -219,7 +286,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
} }
c->setPort(ID::Y, new_y); c->setPort(ID::Y, new_y);
c->parameters[ID::Y_WIDTH] = new_y->width; c->parameters[ID::Y_WIDTH] = GetSize(new_y);
c->check(); c->check();
module->connect(new_conn); module->connect(new_conn);
@ -476,13 +543,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
} }
if (detect_const_and && (found_zero || found_inv)) { if (detect_const_and && (found_zero || found_inv || (found_undef && consume_x))) {
cover("opt.opt_expr.const_and"); cover("opt.opt_expr.const_and");
replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0); replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0);
goto next_cell; goto next_cell;
} }
if (detect_const_or && (found_one || found_inv)) { if (detect_const_or && (found_one || found_inv || (found_undef && consume_x))) {
cover("opt.opt_expr.const_or"); cover("opt.opt_expr.const_or");
replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1); replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1);
goto next_cell; goto next_cell;
@ -499,6 +566,22 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{ {
SigBit sig_a = assign_map(cell->getPort(ID::A)); SigBit sig_a = assign_map(cell->getPort(ID::A));
SigBit sig_b = assign_map(cell->getPort(ID::B)); SigBit sig_b = assign_map(cell->getPort(ID::B));
if (!keepdc && (sig_a == sig_b || sig_a == State::Sx || sig_a == State::Sz || sig_b == State::Sx || sig_b == State::Sz)) {
if (cell->type.in(ID($xor), ID($_XOR_))) {
cover("opt.opt_expr.const_xor");
replace_cell(assign_map, module, cell, "const_xor", ID::Y, RTLIL::State::S0);
goto next_cell;
}
if (cell->type.in(ID($xnor), ID($_XNOR_))) {
cover("opt.opt_expr.const_xnor");
// For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_
int width = cell->getParam(ID::Y_WIDTH).as_int();
replace_cell(assign_map, module, cell, "const_xnor", ID::Y, SigSpec(RTLIL::State::S1, width));
goto next_cell;
}
log_abort();
}
if (!sig_a.wire) if (!sig_a.wire)
std::swap(sig_a, sig_b); std::swap(sig_a, sig_b);
if (sig_b == State::S0 || sig_b == State::S1) { if (sig_b == State::S0 || sig_b == State::S1) {
@ -550,7 +633,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (do_fine) if (do_fine)
{ {
if (cell->type.in(ID($not), ID($pos), ID($and), ID($or), ID($xor), ID($xnor))) if (cell->type.in(ID($not), ID($pos), ID($and), ID($or), ID($xor), ID($xnor)))
if (group_cell_inputs(module, cell, true, assign_map)) if (group_cell_inputs(module, cell, true, assign_map, keepdc))
goto next_cell; goto next_cell;
if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_and), ID($reduce_bool))) if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_and), ID($reduce_bool)))
@ -781,7 +864,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
skip_fine_alu: skip_fine_alu:
if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr), if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr),
ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow))) ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow)))
{ {
RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
RTLIL::SigSpec sig_b = cell->hasPort(ID::B) ? assign_map(cell->getPort(ID::B)) : RTLIL::SigSpec(); RTLIL::SigSpec sig_b = cell->hasPort(ID::B) ? assign_map(cell->getPort(ID::B)) : RTLIL::SigSpec();
@ -800,7 +883,7 @@ skip_fine_alu:
if (0) { if (0) {
found_the_x_bit: found_the_x_bit:
cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
"$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str()); "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$divfloor", "$modfloor", "$pow", cell->type.str());
if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt))) if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt)))
replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx); replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx);
else else
@ -904,8 +987,10 @@ skip_fine_alu:
if (input.match("01")) ACTION_DO_Y(1); if (input.match("01")) ACTION_DO_Y(1);
if (input.match("10")) ACTION_DO_Y(1); if (input.match("10")) ACTION_DO_Y(1);
if (input.match("11")) ACTION_DO_Y(0); if (input.match("11")) ACTION_DO_Y(0);
if (input.match(" *")) ACTION_DO_Y(x); if (consume_x) {
if (input.match("* ")) ACTION_DO_Y(x); if (input.match(" *")) ACTION_DO_Y(0);
if (input.match("* ")) ACTION_DO_Y(0);
}
} }
if (cell->type == ID($_MUX_)) { if (cell->type == ID($_MUX_)) {
@ -1088,7 +1173,7 @@ skip_fine_alu:
goto next_cell; goto next_cell;
} }
if (!keepdc) if (consume_x)
{ {
bool identity_wrt_a = false; bool identity_wrt_a = false;
bool identity_wrt_b = false; bool identity_wrt_b = false;
@ -1384,6 +1469,8 @@ skip_identity:
FOLD_2ARG_CELL(mul) FOLD_2ARG_CELL(mul)
FOLD_2ARG_CELL(div) FOLD_2ARG_CELL(div)
FOLD_2ARG_CELL(mod) FOLD_2ARG_CELL(mod)
FOLD_2ARG_CELL(divfloor)
FOLD_2ARG_CELL(modfloor)
FOLD_2ARG_CELL(pow) FOLD_2ARG_CELL(pow)
FOLD_1ARG_CELL(pos) FOLD_1ARG_CELL(pos)
@ -1498,9 +1585,11 @@ skip_identity:
} }
} }
if (!keepdc && cell->type.in(ID($div), ID($mod))) if (!keepdc && cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor)))
{ {
bool a_signed = cell->parameters[ID::A_SIGNED].as_bool();
bool b_signed = cell->parameters[ID::B_SIGNED].as_bool(); bool b_signed = cell->parameters[ID::B_SIGNED].as_bool();
SigSpec sig_a = assign_map(cell->getPort(ID::A));
SigSpec sig_b = assign_map(cell->getPort(ID::B)); SigSpec sig_b = assign_map(cell->getPort(ID::B));
SigSpec sig_y = assign_map(cell->getPort(ID::Y)); SigSpec sig_y = assign_map(cell->getPort(ID::Y));
@ -1525,11 +1614,13 @@ skip_identity:
for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++) for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++)
if (b_val == (1 << i)) if (b_val == (1 << i))
{ {
if (cell->type == ID($div)) if (cell->type.in(ID($div), ID($divfloor)))
{ {
cover("opt.opt_expr.div_shift"); cover("opt.opt_expr.div_shift");
log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", bool is_truncating = cell->type == ID($div);
log_debug("Replacing %s-divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
is_truncating ? "truncating" : "flooring",
b_val, cell->name.c_str(), module->name.c_str(), i); b_val, cell->name.c_str(), module->name.c_str(), i);
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6); std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
@ -1537,17 +1628,35 @@ skip_identity:
while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0) while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0)
new_b.pop_back(); new_b.pop_back();
cell->type = ID($shr); cell->type = ID($sshr);
cell->parameters[ID::B_WIDTH] = GetSize(new_b); cell->parameters[ID::B_WIDTH] = GetSize(new_b);
cell->parameters[ID::B_SIGNED] = false; cell->parameters[ID::B_SIGNED] = false;
cell->setPort(ID::B, new_b); cell->setPort(ID::B, new_b);
// Truncating division is the same as flooring division, except when
// the result is negative and there is a remainder - then trunc = floor + 1
if (is_truncating && a_signed) {
Wire *flooring = module->addWire(NEW_ID, sig_y.size());
cell->setPort(ID::Y, flooring);
Wire *result_neg = module->addWire(NEW_ID);
module->addXor(NEW_ID, sig_a[sig_a.size()-1], sig_b[sig_b.size()-1], result_neg);
Wire *rem_nonzero = module->addWire(NEW_ID);
module->addReduceOr(NEW_ID, sig_a.extract(0, i), rem_nonzero);
Wire *should_add = module->addWire(NEW_ID);
module->addAnd(NEW_ID, result_neg, rem_nonzero, should_add);
module->addAdd(NEW_ID, flooring, should_add, sig_y);
}
cell->check(); cell->check();
} }
else else if (cell->type.in(ID($mod), ID($modfloor)))
{ {
cover("opt.opt_expr.mod_mask"); cover("opt.opt_expr.mod_mask");
log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", bool is_truncating = cell->type == ID($mod);
log_debug("Replacing %s-modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
is_truncating ? "truncating" : "flooring",
b_val, cell->name.c_str(), module->name.c_str()); b_val, cell->name.c_str(), module->name.c_str());
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i); std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i);
@ -1558,6 +1667,24 @@ skip_identity:
cell->type = ID($and); cell->type = ID($and);
cell->parameters[ID::B_WIDTH] = GetSize(new_b); cell->parameters[ID::B_WIDTH] = GetSize(new_b);
cell->setPort(ID::B, new_b); cell->setPort(ID::B, new_b);
// truncating modulo has the same masked bits as flooring modulo, but
// the sign bits are those of A (except when R=0)
if (is_truncating && a_signed) {
Wire *flooring = module->addWire(NEW_ID, sig_y.size());
cell->setPort(ID::Y, flooring);
SigSpec truncating = SigSpec(flooring).extract(0, i);
Wire *rem_nonzero = module->addWire(NEW_ID);
module->addReduceOr(NEW_ID, truncating, rem_nonzero);
SigSpec a_sign = sig_a[sig_a.size()-1];
Wire *extend_bit = module->addWire(NEW_ID);
module->addAnd(NEW_ID, a_sign, rem_nonzero, extend_bit);
truncating.append(extend_bit);
module->addPos(NEW_ID, truncating, sig_y, true);
}
cell->check(); cell->check();
} }
@ -1980,11 +2107,12 @@ struct OptExprPass : public Pass {
do { do {
do { do {
did_something = false; did_something = false;
replace_const_cells(design, module, false, mux_undef, mux_bool, do_fine, keepdc, clkinv); replace_const_cells(design, module, false /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv);
if (did_something) if (did_something)
design->scratchpad_set_bool("opt.did_something", true); design->scratchpad_set_bool("opt.did_something", true);
} while (did_something); } while (did_something);
replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv); if (!keepdc)
replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv);
if (did_something) if (did_something)
design->scratchpad_set_bool("opt.did_something", true); design->scratchpad_set_bool("opt.did_something", true);
} while (did_something); } while (did_something);

View File

@ -103,7 +103,7 @@ bool cell_supported(RTLIL::Cell *cell)
if (sig_bi.is_fully_const() && sig_ci.is_fully_const() && sig_bi == sig_ci) if (sig_bi.is_fully_const() && sig_ci.is_fully_const() && sig_bi == sig_ci)
return true; return true;
} else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($concat))) { } else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($concat))) {
return true; return true;
} }
@ -130,7 +130,7 @@ bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b)
RTLIL::IdString decode_port_semantics(RTLIL::Cell *cell, RTLIL::IdString port_name) RTLIL::IdString decode_port_semantics(RTLIL::Cell *cell, RTLIL::IdString port_name)
{ {
if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt), ID($div), ID($mod), ID($concat), SHIFT_OPS) && port_name == ID::B) if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($concat), SHIFT_OPS) && port_name == ID::B)
return port_name; return port_name;
return ""; return "";

View File

@ -376,7 +376,7 @@ struct ShareWorker
continue; continue;
} }
if (cell->type.in(ID($mul), ID($div), ID($mod))) { if (cell->type.in(ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor))) {
if (config.opt_aggressive || cell->parameters.at(ID::Y_WIDTH).as_int() >= 4) if (config.opt_aggressive || cell->parameters.at(ID::Y_WIDTH).as_int() >= 4)
shareable_cells.insert(cell); shareable_cells.insert(cell);
continue; continue;
@ -1133,6 +1133,8 @@ struct ShareWorker
cone_ct.cell_types.erase(ID($mul)); cone_ct.cell_types.erase(ID($mul));
cone_ct.cell_types.erase(ID($mod)); cone_ct.cell_types.erase(ID($mod));
cone_ct.cell_types.erase(ID($div)); cone_ct.cell_types.erase(ID($div));
cone_ct.cell_types.erase(ID($modfloor));
cone_ct.cell_types.erase(ID($divfloor));
cone_ct.cell_types.erase(ID($pow)); cone_ct.cell_types.erase(ID($pow));
cone_ct.cell_types.erase(ID($shl)); cone_ct.cell_types.erase(ID($shl));
cone_ct.cell_types.erase(ID($shr)); cone_ct.cell_types.erase(ID($shr));
@ -1512,6 +1514,8 @@ struct SharePass : public Pass {
config.generic_bin_ops.insert(ID($sub)); config.generic_bin_ops.insert(ID($sub));
config.generic_bin_ops.insert(ID($div)); config.generic_bin_ops.insert(ID($div));
config.generic_bin_ops.insert(ID($mod)); config.generic_bin_ops.insert(ID($mod));
config.generic_bin_ops.insert(ID($divfloor));
config.generic_bin_ops.insert(ID($modfloor));
// config.generic_bin_ops.insert(ID($pow)); // config.generic_bin_ops.insert(ID($pow));
config.generic_uni_ops.insert(ID($logic_not)); config.generic_uni_ops.insert(ID($logic_not));

View File

@ -37,7 +37,7 @@ struct WreduceConfig
ID($and), ID($or), ID($xor), ID($xnor), ID($and), ID($or), ID($xor), ID($xnor),
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
ID($add), ID($sub), ID($mul), // ID($div), ID($mod), ID($pow), ID($add), ID($sub), ID($mul), // ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow),
ID($mux), ID($pmux), ID($mux), ID($pmux),
ID($dff), ID($adff) ID($dff), ID($adff)
}); });
@ -545,7 +545,7 @@ struct WreducePass : public Pass {
} }
} }
if (c->type.in(ID($div), ID($mod), ID($pow))) if (c->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow)))
{ {
SigSpec A = c->getPort(ID::A); SigSpec A = c->getPort(ID::A);
int original_a_width = GetSize(A); int original_a_width = GetSize(A);

View File

@ -19,22 +19,12 @@
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/celltypes.h" #include "kernel/celltypes.h"
#include "kernel/consteval.h"
#include "kernel/log.h" #include "kernel/log.h"
#include "kernel/rtlil.h" #include "kernel/rtlil.h"
#include "kernel/register.h" #include "kernel/register.h"
#include <cstdio>
#include <algorithm> #include <algorithm>
#if defined(_WIN32)
# define WIFEXITED(x) 1
# define WIFSIGNALED(x) 0
# define WIFSTOPPED(x) 0
# define WEXITSTATUS(x) ((x) & 0xff)
# define WTERMSIG(x) SIGTERM
#else
# include <sys/wait.h>
#endif
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
@ -43,26 +33,47 @@ struct QbfSolutionType {
dict<std::string, std::string> hole_to_value; dict<std::string, std::string> hole_to_value;
bool sat; bool sat;
bool unknown; //true if neither 'sat' nor 'unsat' bool unknown; //true if neither 'sat' nor 'unsat'
bool success; //true if exit code 0
QbfSolutionType() : sat(false), unknown(true), success(false) {} QbfSolutionType() : sat(false), unknown(true) {}
}; };
struct QbfSolveOptions { struct QbfSolveOptions {
bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs, assume_neg; bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs, assume_neg;
bool nooptimize, nobisection;
bool sat, unsat, show_smtbmc; bool sat, unsat, show_smtbmc;
enum Solver{Z3, Yices, CVC4} solver;
int timeout;
std::string specialize_soln_file; std::string specialize_soln_file;
std::string write_soln_soln_file; std::string write_soln_soln_file;
std::string dump_final_smt2_file; std::string dump_final_smt2_file;
size_t argidx; size_t argidx;
QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(false), QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(false),
nocleanup(false), dump_final_smt2(false), assume_outputs(false), assume_neg(false), nocleanup(false), dump_final_smt2(false), assume_outputs(false), assume_neg(false),
sat(false), unsat(false), show_smtbmc(false), argidx(0) {}; nooptimize(false), nobisection(false), sat(false), unsat(false), show_smtbmc(false),
solver(Yices), timeout(0), argidx(0) {};
}; };
std::string get_solver_name(const QbfSolveOptions &opt) {
if (opt.solver == opt.Solver::Z3)
return "z3";
else if (opt.solver == opt.Solver::Yices)
return "yices";
else if (opt.solver == opt.Solver::CVC4)
return "cvc4";
else
log_cmd_error("unknown solver specified.\n");
return "";
}
void recover_solution(QbfSolutionType &sol) { void recover_solution(QbfSolutionType &sol) {
YS_REGEX_TYPE sat_regex = YS_REGEX_COMPILE("Status: PASSED"); YS_REGEX_TYPE sat_regex = YS_REGEX_COMPILE("Status: PASSED");
YS_REGEX_TYPE unsat_regex = YS_REGEX_COMPILE("Solver Error.*model is not available"); YS_REGEX_TYPE unsat_regex = YS_REGEX_COMPILE("Solver Error.*model is not available");
YS_REGEX_TYPE unsat_regex2 = YS_REGEX_COMPILE("Status: FAILED");
YS_REGEX_TYPE timeout_regex = YS_REGEX_COMPILE("No solution found! \\(timeout\\)");
YS_REGEX_TYPE timeout_regex2 = YS_REGEX_COMPILE("No solution found! \\(interrupted\\)");
YS_REGEX_TYPE unknown_regex = YS_REGEX_COMPILE("No solution found! \\(unknown\\)");
YS_REGEX_TYPE unknown_regex2 = YS_REGEX_COMPILE("Unexpected EOF response from solver");
YS_REGEX_TYPE memout_regex = YS_REGEX_COMPILE("Solver Error:.*error \"out of memory\"");
YS_REGEX_TYPE hole_value_regex = YS_REGEX_COMPILE_WITH_SUBS("Value for anyconst in [a-zA-Z0-9_]* \\(([^:]*:[^\\)]*)\\): (.*)"); YS_REGEX_TYPE hole_value_regex = YS_REGEX_COMPILE_WITH_SUBS("Value for anyconst in [a-zA-Z0-9_]* \\(([^:]*:[^\\)]*)\\): (.*)");
#ifndef NDEBUG #ifndef NDEBUG
YS_REGEX_TYPE hole_loc_regex = YS_REGEX_COMPILE("[^:]*:[0-9]+.[0-9]+-[0-9]+.[0-9]+"); YS_REGEX_TYPE hole_loc_regex = YS_REGEX_COMPILE("[^:]*:[0-9]+.[0-9]+-[0-9]+.[0-9]+");
@ -82,10 +93,40 @@ void recover_solution(QbfSolutionType &sol) {
#endif #endif
sol.hole_to_value[loc] = val; sol.hole_to_value[loc] = val;
} }
else if (YS_REGEX_NS::regex_search(x, sat_regex)) else if (YS_REGEX_NS::regex_search(x, sat_regex)) {
sat_regex_found = true; sat_regex_found = true;
else if (YS_REGEX_NS::regex_search(x, unsat_regex)) sol.sat = true;
sol.unknown = false;
}
else if (YS_REGEX_NS::regex_search(x, unsat_regex)) {
unsat_regex_found = true; unsat_regex_found = true;
sol.sat = false;
sol.unknown = false;
}
else if (YS_REGEX_NS::regex_search(x, memout_regex)) {
sol.unknown = true;
log_warning("solver ran out of memory\n");
}
else if (YS_REGEX_NS::regex_search(x, timeout_regex)) {
sol.unknown = true;
log_warning("solver timed out\n");
}
else if (YS_REGEX_NS::regex_search(x, timeout_regex2)) {
sol.unknown = true;
log_warning("solver timed out\n");
}
else if (YS_REGEX_NS::regex_search(x, unknown_regex)) {
sol.unknown = true;
log_warning("solver returned \"unknown\"\n");
}
else if (YS_REGEX_NS::regex_search(x, unsat_regex2)) {
unsat_regex_found = true;
sol.sat = false;
sol.unknown = false;
}
else if (YS_REGEX_NS::regex_search(x, unknown_regex2)) {
sol.unknown = true;
}
} }
#ifndef NDEBUG #ifndef NDEBUG
log_assert(!sol.unknown && sol.sat? sat_regex_found : true); log_assert(!sol.unknown && sol.sat? sat_regex_found : true);
@ -107,6 +148,40 @@ dict<std::string, std::string> get_hole_loc_name_map(RTLIL::Module *module, cons
return hole_loc_to_name; return hole_loc_to_name;
} }
pool<std::string> validate_design_and_get_inputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
bool found_input = false;
bool found_hole = false;
bool found_1bit_output = false;
bool found_assert_assume = false;
pool<std::string> input_wires;
for (auto wire : module->wires()) {
if (wire->port_input) {
found_input = true;
input_wires.insert(wire->name.str());
}
if (wire->port_output && wire->width == 1)
found_1bit_output = true;
}
for (auto cell : module->cells()) {
if (cell->type == "$allconst")
found_input = true;
if (cell->type == "$anyconst")
found_hole = true;
if (cell->type.in("$assert", "$assume"))
found_assert_assume = true;
}
if (!found_input)
log_cmd_error("Can't perform QBF-SAT on a miter with no inputs!\n");
if (!found_hole)
log_cmd_error("Did not find any existentially-quantified variables. Use 'sat' instead.\n");
if (!found_1bit_output && !found_assert_assume)
log_cmd_error("Did not find any single-bit outputs or $assert/$assume cells. Is this a miter circuit?\n");
if (!found_assert_assume && !opt.assume_outputs)
log_cmd_error("Did not find any $assert/$assume cells. Single-bit outputs were found, but `-assume-outputs` was not specified.\n");
return input_wires;
}
void write_solution(RTLIL::Module *module, const QbfSolutionType &sol, const std::string &file) { void write_solution(RTLIL::Module *module, const QbfSolutionType &sol, const std::string &file) {
std::ofstream fout(file.c_str()); std::ofstream fout(file.c_str());
if (!fout) if (!fout)
@ -164,7 +239,7 @@ void specialize_from_file(RTLIL::Module *module, const std::string &file) {
} }
} }
void specialize(RTLIL::Module *module, const QbfSolutionType &sol) { void specialize(RTLIL::Module *module, const QbfSolutionType &sol, bool quiet = false) {
dict<std::string, std::string> hole_loc_to_name = get_hole_loc_name_map(module, sol); dict<std::string, std::string> hole_loc_to_name = get_hole_loc_name_map(module, sol);
pool<RTLIL::Cell *> anyconsts_to_remove; pool<RTLIL::Cell *> anyconsts_to_remove;
for (auto cell : module->cells()) for (auto cell : module->cells())
@ -189,7 +264,8 @@ void specialize(RTLIL::Module *module, const QbfSolutionType &sol) {
log_assert(wire->width > 0 && GetSize(hole_value) == wire->width); log_assert(wire->width > 0 && GetSize(hole_value) == wire->width);
#endif #endif
log("Specializing %s with %s = %d'b%s.\n", module->name.c_str(), hole_name.c_str(), wire->width, hole_value.c_str()); if (!quiet)
log("Specializing %s with %s = %d'b%s.\n", module->name.c_str(), hole_name.c_str(), wire->width, hole_value.c_str());
std::vector<RTLIL::SigBit> value_bv; std::vector<RTLIL::SigBit> value_bv;
value_bv.reserve(wire->width); value_bv.reserve(wire->width);
for (char c : hole_value) for (char c : hole_value)
@ -219,7 +295,6 @@ void dump_model(RTLIL::Module *module, const QbfSolutionType &sol) {
value_bv.emplace_back(c == '1'? RTLIL::S1 : RTLIL::S0); value_bv.emplace_back(c == '1'? RTLIL::S1 : RTLIL::S0);
std::reverse(value_bv.begin(), value_bv.end()); std::reverse(value_bv.begin(), value_bv.end());
} }
} }
void allconstify_inputs(RTLIL::Module *module, const pool<std::string> &input_wires) { void allconstify_inputs(RTLIL::Module *module, const pool<std::string> &input_wires) {
@ -280,86 +355,147 @@ void assume_miter_outputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
module->addAssume("$assume_qbfsat_miter_outputs", wires_to_assume[0], RTLIL::S1); module->addAssume("$assume_qbfsat_miter_outputs", wires_to_assume[0], RTLIL::S1);
} }
QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) { QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt, const std::string &tempdir_name, const bool quiet = false, const int iter_num = 0) {
//Execute and capture stdout from `yosys-smtbmc -s z3 -t 1 -g --binary [--dump-smt2 <file>]`
QbfSolutionType ret; QbfSolutionType ret;
const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc"; const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc";
const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2";
const std::string smtbmc_warning = "z3: WARNING:"; const std::string smtbmc_warning = "z3: WARNING:";
const bool show_smtbmc = opt.show_smtbmc; const std::string smtbmc_cmd = yosys_smtbmc_exe + " -s " + (get_solver_name(opt)) + (opt.timeout != 0? stringf(" --timeout %d", opt.timeout) : "") + " -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2 2>&1";
const std::string tempdir_name = make_temp_dir("/tmp/yosys-z3-XXXXXX");
const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem.smt2";
#ifndef NDEBUG
log_assert(mod->design != nullptr);
#endif
Pass::call(mod->design, smt2_command); Pass::call(mod->design, smt2_command);
auto process_line = [&ret, &smtbmc_warning, &opt, &quiet](const std::string &line) {
ret.stdout_lines.push_back(line.substr(0, line.size()-1)); //don't include trailing newline
auto warning_pos = line.find(smtbmc_warning);
if (warning_pos != std::string::npos)
log_warning("%s", line.substr(warning_pos + smtbmc_warning.size() + 1).c_str());
else
if (opt.show_smtbmc && !quiet)
log("smtbmc output: %s", line.c_str());
};
log_header(mod->design, "Solving QBF-SAT problem.\n"); log_header(mod->design, "Solving QBF-SAT problem.\n");
if (!quiet) log("Launching \"%s\".\n", smtbmc_cmd.c_str());
run_command(smtbmc_cmd, process_line);
//Execute and capture stdout from `yosys-smtbmc -s z3 -t 1 -g --binary [--dump-smt2 <file>]` recover_solution(ret);
{ return ret;
const std::string cmd = yosys_smtbmc_exe + " -s z3 -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem.smt2 2>&1"; }
auto process_line = [&ret, &smtbmc_warning, &show_smtbmc](const std::string &line) {
ret.stdout_lines.push_back(line.substr(0, line.size()-1)); //don't include trailing newline
auto warning_pos = line.find(smtbmc_warning);
if (warning_pos != std::string::npos)
log_warning("%s", line.substr(warning_pos + smtbmc_warning.size() + 1).c_str());
else
if (show_smtbmc)
log("smtbmc output: %s", line.c_str());
};
log("Launching \"%s\".\n", cmd.c_str()); QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) {
int retval = run_command(cmd, process_line); QbfSolutionType ret, best_soln;
if (retval == 0) { const std::string tempdir_name = make_temp_dir("/tmp/yosys-z3-XXXXXX");
ret.sat = true; RTLIL::Module *module = mod;
ret.unknown = false; RTLIL::Design *design = module->design;
} else if (retval == 1) { std::string module_name = module->name.str();
ret.sat = false; RTLIL::Wire *wire_to_optimize = nullptr;
ret.unknown = false; RTLIL::IdString wire_to_optimize_name;
bool maximize = false;
log_assert(module->design != nullptr);
Pass::call(design, "design -push-copy");
//Replace input wires with wires assigned $allconst cells:
pool<std::string> input_wires = validate_design_and_get_inputs(module, opt);
allconstify_inputs(module, input_wires);
if (opt.assume_outputs)
assume_miter_outputs(module, opt);
//Find the wire to be optimized, if any:
for (auto wire : module->wires())
if (wire->get_bool_attribute("\\maximize") || wire->get_bool_attribute("\\minimize"))
wire_to_optimize = wire;
if (wire_to_optimize != nullptr) {
wire_to_optimize_name = wire_to_optimize->name;
maximize = wire_to_optimize->get_bool_attribute("\\maximize");
}
if (opt.nobisection || opt.nooptimize) {
if (wire_to_optimize != nullptr && opt.nooptimize) {
wire_to_optimize->set_bool_attribute("\\maximize", false);
wire_to_optimize->set_bool_attribute("\\minimize", false);
}
ret = call_qbf_solver(module, opt, tempdir_name, false, 0);
} else {
//Do the iterated bisection method:
unsigned int iter_num = 1;
unsigned int success = 0;
unsigned int failure = 0;
unsigned int cur_thresh = 0;
log_assert(wire_to_optimize != nullptr);
log("%s wire \"%s\".\n", (maximize? "Maximizing" : "Minimizing"), log_signal(wire_to_optimize));
//If maximizing, grow until we get a failure. Then bisect success and failure.
while (failure == 0 || success - failure > 1) {
Pass::call(design, "design -push-copy");
log_header(design, "Preparing QBF-SAT problem.\n");
if (cur_thresh != 0) {
//Add thresholding logic (but not on the initial run when we don't have a sense of where to start):
RTLIL::SigSpec comparator = maximize? module->Ge(NEW_ID, module->wire(wire_to_optimize_name), RTLIL::Const(cur_thresh), false)
: module->Le(NEW_ID, module->wire(wire_to_optimize_name), RTLIL::Const(cur_thresh), false);
module->addAssume(wire_to_optimize_name.str() + "__threshold", comparator, RTLIL::Const(1, 1));
log("Trying to solve with %s %s %d.\n", wire_to_optimize_name.c_str(), (maximize? ">=" : "<="), cur_thresh);
}
ret = call_qbf_solver(module, opt, tempdir_name, false, iter_num);
Pass::call(design, "design -pop");
module = design->module(module_name);
if (!ret.unknown && ret.sat) {
Pass::call(design, "design -push-copy");
specialize(module, ret, true);
RTLIL::SigSpec wire, value, undef;
RTLIL::SigSpec::parse_sel(wire, design, module, wire_to_optimize_name.str());
ConstEval ce(module);
value = wire;
if (!ce.eval(value, undef))
log_cmd_error("Failed to evaluate signal %s: Missing value for %s.\n", log_signal(wire), log_signal(undef));
log_assert(value.is_fully_const());
success = value.as_const().as_int();
best_soln = ret;
log("Problem is satisfiable with %s = %d.\n", wire_to_optimize_name.c_str(), success);
Pass::call(design, "design -pop");
module = design->module(module_name);
//sometimes this happens if we get an 'unknown' or timeout
if (!maximize && success < failure)
break;
else if (maximize && success > failure)
break;
} else {
//Treat 'unknown' as UNSAT
failure = cur_thresh;
if (failure == 0) {
log("Problem is NOT satisfiable.\n");
break;
}
else
log("Problem is NOT satisfiable with %s %s %d.\n", wire_to_optimize_name.c_str(), (maximize? ">=" : "<="), failure);
}
iter_num++;
cur_thresh = (maximize && failure == 0)? 2 * success //growth
: (success + failure) / 2; //bisection
}
if (success != 0 || failure != 0) {
log("Wire %s is %s at %d.\n", wire_to_optimize_name.c_str(), (maximize? "maximized" : "minimized"), success);
ret = best_soln;
} }
} }
if(!opt.nocleanup) if(!opt.nocleanup)
remove_directory(tempdir_name); remove_directory(tempdir_name);
recover_solution(ret); Pass::call(design, "design -pop");
return ret; return ret;
} }
pool<std::string> validate_design_and_get_inputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
bool found_input = false;
bool found_hole = false;
bool found_1bit_output = false;
bool found_assert_assume = false;
pool<std::string> input_wires;
for (auto wire : module->wires()) {
if (wire->port_input) {
found_input = true;
input_wires.insert(wire->name.str());
}
if (wire->port_output && wire->width == 1)
found_1bit_output = true;
}
for (auto cell : module->cells()) {
if (cell->type == "$allconst")
found_input = true;
if (cell->type == "$anyconst")
found_hole = true;
if (cell->type.in("$assert", "$assume"))
found_assert_assume = true;
}
if (!found_input)
log_cmd_error("Can't perform QBF-SAT on a miter with no inputs!\n");
if (!found_hole)
log_cmd_error("Did not find any existentially-quantified variables. Use 'sat' instead.\n");
if (!found_1bit_output && !found_assert_assume)
log_cmd_error("Did not find any single-bit outputs or $assert/$assume cells. Is this a miter circuit?\n");
if (!found_assert_assume && !opt.assume_outputs)
log_cmd_error("Did not find any $assert/$assume cells. Single-bit outputs were found, but `-assume-outputs` was not specified.\n");
return input_wires;
}
QbfSolveOptions parse_args(const std::vector<std::string> &args) { QbfSolveOptions parse_args(const std::vector<std::string> &args) {
QbfSolveOptions opt; QbfSolveOptions opt;
for (opt.argidx = 1; opt.argidx < args.size(); opt.argidx++) { for (opt.argidx = 1; opt.argidx < args.size(); opt.argidx++) {
@ -379,6 +515,43 @@ QbfSolveOptions parse_args(const std::vector<std::string> &args) {
opt.assume_neg = true; opt.assume_neg = true;
continue; continue;
} }
else if (args[opt.argidx] == "-nooptimize") {
opt.nooptimize = true;
continue;
}
else if (args[opt.argidx] == "-nobisection") {
opt.nobisection = true;
continue;
}
else if (args[opt.argidx] == "-solver") {
if (args.size() <= opt.argidx + 1)
log_cmd_error("solver not specified.\n");
else {
if (args[opt.argidx+1] == "z3")
opt.solver = opt.Solver::Z3;
else if (args[opt.argidx+1] == "yices")
opt.solver = opt.Solver::Yices;
else if (args[opt.argidx+1] == "cvc4")
opt.solver = opt.Solver::CVC4;
else
log_cmd_error("Unknown solver \"%s\".\n", args[opt.argidx+1].c_str());
opt.argidx++;
}
continue;
}
else if (args[opt.argidx] == "-timeout") {
if (args.size() <= opt.argidx + 1)
log_cmd_error("timeout not specified.\n");
else {
int timeout = atoi(args[opt.argidx+1].c_str());
if (timeout > 0)
opt.timeout = timeout;
else
log_cmd_error("timeout must be greater than 0.\n");
opt.argidx++;
}
continue;
}
else if (args[opt.argidx] == "-sat") { else if (args[opt.argidx] == "-sat") {
opt.sat = true; opt.sat = true;
continue; continue;
@ -456,27 +629,43 @@ struct QbfSatPass : public Pass {
log("\n"); log("\n");
log(" qbfsat [options] [selection]\n"); log(" qbfsat [options] [selection]\n");
log("\n"); log("\n");
log("This command solves a 2QBF-SAT problem defined over the currently selected module.\n"); log("This command solves an \"exists-forall\" 2QBF-SAT problem defined over the currently\n");
log("Existentially-quantified variables are declared by assigning a wire \"$anyconst\".\n"); log("selected module. Existentially-quantified variables are declared by assigning a wire\n");
log("Universally-quantified variables may be explicitly declared by assigning a wire\n"); log("\"$anyconst\". Universally-quantified variables may be explicitly declared by assigning\n");
log("\"$allconst\", but module inputs will be treated as universally-quantified variables\n"); log("a wire \"$allconst\", but module inputs will be treated as universally-quantified\n");
log("by default.\n"); log("variables by default.\n");
log("\n"); log("\n");
log(" -nocleanup\n"); log(" -nocleanup\n");
log(" Do not delete temporary files and directories. Useful for\n"); log(" Do not delete temporary files and directories. Useful for debugging.\n");
log(" debugging.\n");
log("\n"); log("\n");
log(" -dump-final-smt2 <file>\n"); log(" -dump-final-smt2 <file>\n");
log(" Pass the --dump-smt2 option to yosys-smtbmc.\n"); log(" Pass the --dump-smt2 option to yosys-smtbmc.\n");
log("\n"); log("\n");
log(" -assume-outputs\n"); log(" -assume-outputs\n");
log(" Add an $assume cell for the conjunction of all one-bit module output wires.\n"); log(" Add an \"$assume\" cell for the conjunction of all one-bit module output wires.\n");
log("\n"); log("\n");
log(" -assume-negative-polarity\n"); log(" -assume-negative-polarity\n");
log(" When adding $assume cells for one-bit module output wires, assume they are\n"); log(" When adding $assume cells for one-bit module output wires, assume they are\n");
log(" negative polarity signals and should always be low, for example like the\n"); log(" negative polarity signals and should always be low, for example like the\n");
log(" miters created with the `miter` command.\n"); log(" miters created with the `miter` command.\n");
log("\n"); log("\n");
log(" -nooptimize\n");
log(" Ignore \"\\minimize\" and \"\\maximize\" attributes, do not emit \"(maximize)\" or\n");
log(" \"(minimize)\" in the SMT-LIBv2, and generally make no attempt to optimize anything.\n");
log("\n");
log(" -nobisection\n");
log(" If a wire is marked with the \"\\minimize\" or \"\\maximize\" attribute, do not\n");
log(" attempt to optimize that value with the default iterated solving and threshold\n");
log(" bisection approach. Instead, have yosys-smtbmc emit a \"(minimize)\" or \"(maximize)\"\n");
log(" command in the SMT-LIBv2 output and hope that the solver supports optimizing\n");
log(" quantified bitvector problems.\n");
log("\n");
log(" -solver <solver>\n");
log(" Use a particular solver. Choose one of: \"z3\", \"yices\", and \"cvc4\".\n");
log("\n");
log(" -timeout <value>\n");
log(" Set the per-iteration timeout in seconds.\n");
log("\n");
log(" -sat\n"); log(" -sat\n");
log(" Generate an error if the solver does not return \"sat\".\n"); log(" Generate an error if the solver does not return \"sat\".\n");
log("\n"); log("\n");
@ -487,15 +676,16 @@ struct QbfSatPass : public Pass {
log(" Print the output from yosys-smtbmc.\n"); log(" Print the output from yosys-smtbmc.\n");
log("\n"); log("\n");
log(" -specialize\n"); log(" -specialize\n");
log(" Replace all \"$anyconst\" cells with constant values determined by the solver.\n"); log(" If the problem is satisfiable, replace each \"$anyconst\" cell with its\n");
log(" corresponding constant value from the model produced by the solver.\n");
log("\n"); log("\n");
log(" -specialize-from-file <solution file>\n"); log(" -specialize-from-file <solution file>\n");
log(" Do not run the solver, but instead only attempt to replace all \"$anyconst\"\n"); log(" Do not run the solver, but instead only attempt to replace each \"$anyconst\"\n");
log(" cells in the current module with values provided by the specified file.\n"); log(" cell in the current module with a constant value provided by the specified file.\n");
log("\n"); log("\n");
log(" -write-solution <solution file>\n"); log(" -write-solution <solution file>\n");
log(" Write the assignments discovered by the solver for all \"$anyconst\" cells\n"); log(" If the problem is satisfiable, write the corresponding constant value for each\n");
log(" to the specified file."); log(" \"$anyconst\" cell from the model produced by the solver to the specified file.");
log("\n"); log("\n");
log("\n"); log("\n");
} }
@ -519,26 +709,15 @@ struct QbfSatPass : public Pass {
if (!opt.specialize_from_file) { if (!opt.specialize_from_file) {
//Save the design to restore after modiyfing the current module. //Save the design to restore after modiyfing the current module.
std::string module_name = module->name.str(); std::string module_name = module->name.str();
Pass::call(design, "design -push-copy");
//Replace input wires with wires assigned $allconst cells.
pool<std::string> input_wires = validate_design_and_get_inputs(module, opt);
allconstify_inputs(module, input_wires);
if (opt.assume_outputs)
assume_miter_outputs(module, opt);
QbfSolutionType ret = qbf_solve(module, opt); QbfSolutionType ret = qbf_solve(module, opt);
Pass::call(design, "design -pop");
module = design->module(module_name); module = design->module(module_name);
if (ret.unknown) {
if (ret.unknown) if (opt.sat || opt.unsat)
log_warning("solver did not give an answer\n"); log_cmd_error("expected problem to be %s\n", opt.sat? "SAT" : "UNSAT");
else if (ret.sat) }
else if (ret.sat) {
print_qed(); print_qed();
else
print_proof_failed();
if(!ret.unknown && ret.sat) {
if (opt.write_solution) { if (opt.write_solution) {
write_solution(module, ret, opt.write_soln_soln_file); write_solution(module, ret, opt.write_soln_soln_file);
} }
@ -550,10 +729,11 @@ struct QbfSatPass : public Pass {
if (opt.unsat) if (opt.unsat)
log_cmd_error("expected problem to be UNSAT\n"); log_cmd_error("expected problem to be UNSAT\n");
} }
else if (!ret.unknown && !ret.sat && opt.sat) else {
log_cmd_error("expected problem to be SAT\n"); print_proof_failed();
else if (ret.unknown && (opt.sat || opt.unsat)) if (opt.sat)
log_cmd_error("expected problem to be %s\n", opt.sat? "SAT" : "UNSAT"); log_cmd_error("expected problem to be SAT\n");
}
} else } else
specialize_from_file(module, opt.specialize_soln_file); specialize_from_file(module, opt.specialize_soln_file);
log_pop(); log_pop();

View File

@ -1 +0,0 @@
techmap.inc

View File

@ -45,18 +45,6 @@ OBJS += passes/techmap/flowmap.o
OBJS += passes/techmap/extractinv.o OBJS += passes/techmap/extractinv.o
endif endif
GENFILES += passes/techmap/techmap.inc
passes/techmap/techmap.inc: techlibs/common/techmap.v
$(Q) mkdir -p $(dir $@)
$(P) echo "// autogenerated from $<" > $@.new
$(Q) echo "static char stdcells_code[] = {" >> $@.new
$(Q) od -v -td1 -An $< | $(SED) -e 's/[0-9][0-9]*/&,/g' >> $@.new
$(Q) echo "0};" >> $@.new
$(Q) mv $@.new $@
passes/techmap/techmap.o: passes/techmap/techmap.inc
ifeq ($(DISABLE_SPAWN),0) ifeq ($(DISABLE_SPAWN),0)
TARGETS += $(PROGRAM_PREFIX)yosys-filterlib$(EXE) TARGETS += $(PROGRAM_PREFIX)yosys-filterlib$(EXE)
EXTRA_OBJS += passes/techmap/filterlib.o EXTRA_OBJS += passes/techmap/filterlib.o

View File

@ -151,8 +151,8 @@ struct Abc9Pass : public ScriptPass
log(" specified).\n"); log(" specified).\n");
log("\n"); log("\n");
log(" -dff\n"); log(" -dff\n");
log(" also pass $_ABC9_FF_ cells through to ABC. modules with many clock\n"); log(" also pass $_DFF_[NP]_ cells through to ABC. modules with many clock\n");
log(" domains are marked as such and automatically partitioned by ABC.\n"); log(" domains are supported and automatically partitioned by ABC.\n");
log("\n"); log("\n");
log(" -nocleanup\n"); log(" -nocleanup\n");
log(" when this option is used, the temporary files created by this pass\n"); log(" when this option is used, the temporary files created by this pass\n");
@ -274,40 +274,106 @@ struct Abc9Pass : public ScriptPass
void script() YS_OVERRIDE void script() YS_OVERRIDE
{ {
if (check_label("check")) {
if (help_mode)
run("abc9_ops -check [-dff]", "(option if -dff)");
else
run(stringf("abc9_ops -check %s", dff_mode ? "-dff" : ""));
}
if (check_label("map")) {
if (help_mode)
run("abc9_ops -prep_hier -prep_bypass [-prep_dff -dff]", "(option if -dff)");
else
run(stringf("abc9_ops -prep_hier -prep_bypass %s", dff_mode ? "-prep_dff -dff" : ""));
if (dff_mode) {
run("design -copy-to $abc9_map @$abc9_flops", "(only if -dff)");
run("select -unset $abc9_flops", " (only if -dff)");
}
run("design -stash $abc9");
run("design -load $abc9_map");
run("proc");
run("wbflip");
run("techmap");
run("opt");
if (dff_mode || help_mode) {
if (!help_mode)
active_design->scratchpad_unset("abc9_ops.prep_dff_submod.did_something");
run("abc9_ops -prep_dff_submod", " (only if -dff)"); // rewrite specify
bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_submod.did_something");
if (did_something) {
// select all $_DFF_[NP]_
// then select all its fanins
// then select all fanouts of all that
// lastly remove $_DFF_[NP]_ cells
run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d", " (only if -dff)");
run("submod", " (only if -dff)");
run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop", "(only if -dff)");
if (help_mode) {
run("foreach module in design");
run(" rename <module-name>_$abc9_flop _TECHMAP_REPLACE_", " (only if -dff)");
}
else {
// Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs
for (auto module : active_design->selected_modules()) {
active_design->selected_active_module = module->name.str();
if (module->cell(stringf("%s_$abc9_flop", module->name.c_str())))
run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str()));
}
active_design->selected_active_module.clear();
}
run("abc9_ops -prep_dff_unmap", " (only if -dff)");
run("design -copy-to $abc9 =*_$abc9_flop", " (only if -dff)"); // copy submod out
run("delete =*_$abc9_flop", " (only if -dff)");
}
}
run("design -stash $abc9_map");
run("design -load $abc9");
run("design -delete $abc9");
if (help_mode)
run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v [-D DFF]", "(option if -dff)");
else
run(stringf("techmap -wb -max_iter 1 -map %%$abc9_map -map +/abc9_map.v %s", dff_mode ? "-D DFF" : ""));
run("design -delete $abc9_map");
}
if (check_label("pre")) { if (check_label("pre")) {
run("abc9_ops -check"); run("read_verilog -icells -lib -specify +/abc9_model.v");
run("scc -set_attr abc9_scc_id {}"); run("scc -set_attr abc9_scc_id {}");
if (help_mode) if (help_mode)
run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)"); run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)");
else else
run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""));
if (help_mode) if (help_mode)
run("abc9_ops -prep_lut <maxlut>", "(skip if -lut or -luts)"); run("abc9_ops -prep_lut <maxlut>", "(skip if -lut or -luts)");
else if (!lut_mode) else if (!lut_mode)
run(stringf("abc9_ops -prep_lut %d", maxlut)); run(stringf("abc9_ops -prep_lut %d", maxlut));
if (help_mode) if (help_mode)
run("abc9_ops -prep_box [-dff]", "(skip if -box)"); run("abc9_ops -prep_box", "(skip if -box)");
else if (box_file.empty()) else if (box_file.empty())
run(stringf("abc9_ops -prep_box %s", dff_mode ? "-dff" : "")); run("abc9_ops -prep_box");
run("select -set abc9_holes A:abc9_holes"); if (saved_designs.count("$abc9_holes") || help_mode) {
run("flatten -wb @abc9_holes"); run("design -stash $abc9");
run("techmap @abc9_holes"); run("design -load $abc9_holes");
if (dff_mode || help_mode) run("techmap -wb -map %$abc9 -map +/techmap.v");
run("abc9_ops -prep_dff", "(only if -dff)"); run("opt -purge");
run("opt -purge @abc9_holes"); run("aigmap");
run("aigmap"); run("design -stash $abc9_holes");
run("wbflip @abc9_holes"); run("design -load $abc9");
run("design -delete $abc9");
}
} }
if (check_label("map")) { if (check_label("exe")) {
run("aigmap");
if (help_mode) { if (help_mode) {
run("foreach module in selection"); run("foreach module in selection");
run(" abc9_ops -write_lut <abc-temp-dir>/input.lut", "(skip if '-lut' or '-luts')"); run(" abc9_ops -write_lut <abc-temp-dir>/input.lut", "(skip if '-lut' or '-luts')");
run(" abc9_ops -write_box <abc-temp-dir>/input.box"); run(" abc9_ops -write_box <abc-temp-dir>/input.box", "(skip if '-box')");
run(" write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig"); run(" write_xaiger -map <abc-temp-dir>/input.sym [-dff] <abc-temp-dir>/input.xaig");
run(" abc9_exe [options] -cwd <abc-temp-dir> [-lut <abc-temp-dir>/input.lut] -box <abc-temp-dir>/input.box"); run(" abc9_exe [options] -cwd <abc-temp-dir> -lut [<abc-temp-dir>/input.lut] -box [<abc-temp-dir>/input.box]");
run(" read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig"); run(" read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig");
run(" abc9_ops -reintegrate"); run(" abc9_ops -reintegrate [-dff]");
} }
else { else {
auto selected_modules = active_design->selected_modules(); auto selected_modules = active_design->selected_modules();
@ -318,7 +384,6 @@ struct Abc9Pass : public ScriptPass
log("Skipping module %s as it contains processes.\n", log_id(mod)); log("Skipping module %s as it contains processes.\n", log_id(mod));
continue; continue;
} }
log_assert(!mod->attributes.count(ID::abc9_box_id));
log_push(); log_push();
active_design->selection().select(mod); active_design->selection().select(mod);
@ -333,8 +398,9 @@ struct Abc9Pass : public ScriptPass
if (!lut_mode) if (!lut_mode)
run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str())); run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str()));
run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str())); if (box_file.empty())
run_nocheck(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str()));
run_nocheck(stringf("write_xaiger -map %s/input.sym %s %s/input.xaig", tempdir_name.c_str(), dff_mode ? "-dff" : "", tempdir_name.c_str()));
int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs"); int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs");
@ -349,10 +415,13 @@ struct Abc9Pass : public ScriptPass
abc9_exe_cmd += stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()); abc9_exe_cmd += stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str());
if (!lut_mode) if (!lut_mode)
abc9_exe_cmd += stringf(" -lut %s/input.lut", tempdir_name.c_str()); abc9_exe_cmd += stringf(" -lut %s/input.lut", tempdir_name.c_str());
abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str()); if (box_file.empty())
abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str());
else
abc9_exe_cmd += stringf(" -box %s", box_file.c_str());
run_nocheck(abc9_exe_cmd); run_nocheck(abc9_exe_cmd);
run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str())); run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str()));
run_nocheck("abc9_ops -reintegrate"); run_nocheck(stringf("abc9_ops -reintegrate %s", dff_mode ? "-dff" : ""));
} }
else else
log("Don't call ABC as there is nothing to map.\n"); log("Don't call ABC as there is nothing to map.\n");
@ -369,6 +438,14 @@ struct Abc9Pass : public ScriptPass
active_design->selection_stack.pop_back(); active_design->selection_stack.pop_back();
} }
} }
if (check_label("unmap")) {
run("techmap -wb -map %$abc9_unmap -map +/abc9_unmap.v"); // techmap user design from submod back to original cell
// ($_DFF_[NP]_ already shorted by -reintegrate)
run("design -delete $abc9_unmap");
if (saved_designs.count("$abc9_holes") || help_mode)
run("design -delete $abc9_holes");
}
} }
} Abc9Pass; } Abc9Pass;

File diff suppressed because it is too large Load Diff

View File

@ -522,7 +522,7 @@ void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
} }
} }
void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers) void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
{ {
mappers[ID($not)] = simplemap_not; mappers[ID($not)] = simplemap_not;
mappers[ID($pos)] = simplemap_pos; mappers[ID($pos)] = simplemap_pos;
@ -559,7 +559,7 @@ void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTL
void simplemap(RTLIL::Module *module, RTLIL::Cell *cell) void simplemap(RTLIL::Module *module, RTLIL::Cell *cell)
{ {
static std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers; static dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
static bool initialized_mappers = false; static bool initialized_mappers = false;
if (!initialized_mappers) { if (!initialized_mappers) {
@ -595,7 +595,7 @@ struct SimplemapPass : public Pass {
log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n"); log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
extra_args(args, 1, design); extra_args(args, 1, design);
std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers; dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
simplemap_get_mappers(mappers); simplemap_get_mappers(mappers);
for (auto mod : design->modules()) { for (auto mod : design->modules()) {

View File

@ -42,7 +42,7 @@ extern void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell); extern void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap(RTLIL::Module *module, RTLIL::Cell *cell); extern void simplemap(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers); extern void simplemap_get_mappers(dict<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View File

@ -27,7 +27,6 @@
#include <string.h> #include <string.h>
#include "simplemap.h" #include "simplemap.h"
#include "passes/techmap/techmap.inc"
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
@ -51,21 +50,21 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
{ {
vector<SigChunk> chunks = sig; vector<SigChunk> chunks = sig;
for (auto &chunk : chunks) for (auto &chunk : chunks)
if (chunk.wire != NULL) { if (chunk.wire != nullptr) {
IdString wire_name = chunk.wire->name; IdString wire_name = chunk.wire->name;
apply_prefix(prefix, wire_name); apply_prefix(prefix, wire_name);
log_assert(module->wires_.count(wire_name) > 0); log_assert(module->wire(wire_name) != nullptr);
chunk.wire = module->wires_[wire_name]; chunk.wire = module->wire(wire_name);
} }
sig = chunks; sig = chunks;
} }
struct TechmapWorker struct TechmapWorker
{ {
std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers; dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers;
std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache; dict<std::pair<IdString, dict<IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
std::map<RTLIL::Module*, bool> techmap_do_cache; dict<RTLIL::Module*, bool> techmap_do_cache;
std::set<RTLIL::Module*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Module>> module_queue; pool<RTLIL::Module*> module_queue;
dict<Module*, SigMap> sigmaps; dict<Module*, SigMap> sigmaps;
pool<IdString> flatten_do_list; pool<IdString> flatten_do_list;
@ -79,31 +78,21 @@ struct TechmapWorker
RTLIL::SigSpec value; RTLIL::SigSpec value;
}; };
typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires; typedef dict<IdString, std::vector<TechmapWireData>> TechmapWires;
bool extern_mode; bool extern_mode = false;
bool assert_mode; bool assert_mode = false;
bool flatten_mode; bool flatten_mode = false;
bool recursive_mode; bool recursive_mode = false;
bool autoproc_mode; bool autoproc_mode = false;
bool ignore_wb; bool ignore_wb = false;
TechmapWorker()
{
extern_mode = false;
assert_mode = false;
flatten_mode = false;
recursive_mode = false;
autoproc_mode = false;
ignore_wb = false;
}
std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose) std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose)
{ {
std::string constmap_info; std::string constmap_info;
std::map<RTLIL::SigBit, std::pair<RTLIL::IdString, int>> connbits_map; dict<RTLIL::SigBit, std::pair<IdString, int>> connbits_map;
for (auto conn : cell->connections()) for (auto &conn : cell->connections())
for (int i = 0; i < GetSize(conn.second); i++) { for (int i = 0; i < GetSize(conn.second); i++) {
RTLIL::SigBit bit = sigmap(conn.second[i]); RTLIL::SigBit bit = sigmap(conn.second[i]);
if (bit.wire == nullptr) { if (bit.wire == nullptr) {
@ -117,7 +106,7 @@ struct TechmapWorker
constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i,
log_id(connbits_map.at(bit).first), connbits_map.at(bit).second); log_id(connbits_map.at(bit).first), connbits_map.at(bit).second);
} else { } else {
connbits_map[bit] = std::pair<RTLIL::IdString, int>(conn.first, i); connbits_map.emplace(bit, std::make_pair(conn.first, i));
constmap_info += stringf("|%s %d", log_id(conn.first), i); constmap_info += stringf("|%s %d", log_id(conn.first), i);
} }
} }
@ -129,24 +118,25 @@ struct TechmapWorker
{ {
TechmapWires result; TechmapWires result;
if (module == NULL) if (module == nullptr)
return result; return result;
for (auto &it : module->wires_) { for (auto w : module->wires()) {
const char *p = it.first.c_str(); const char *p = w->name.c_str();
if (*p == '$') if (*p == '$')
continue; continue;
const char *q = strrchr(p+1, '.'); const char *q = strrchr(p+1, '.');
p = q ? q+1 : p+1; if (q)
p = q;
if (!strncmp(p, "_TECHMAP_", 9)) { if (!strncmp(p, "\\_TECHMAP_", 10)) {
TechmapWireData record; TechmapWireData record;
record.wire = it.second; record.wire = w;
record.value = it.second; record.value = w;
result[p].push_back(record); result[p].push_back(record);
it.second->attributes[ID::keep] = RTLIL::Const(1); w->set_bool_attribute(ID::keep);
it.second->attributes[ID::_techmap_special_] = RTLIL::Const(1); w->set_bool_attribute(ID::_techmap_special_);
} }
} }
@ -165,7 +155,7 @@ struct TechmapWorker
if (tpl->processes.size() != 0) { if (tpl->processes.size() != 0) {
log("Technology map yielded processes:"); log("Technology map yielded processes:");
for (auto &it : tpl->processes) for (auto &it : tpl->processes)
log(" %s",RTLIL::id2cstr(it.first)); log(" %s",log_id(it.first));
log("\n"); log("\n");
if (autoproc_mode) { if (autoproc_mode) {
Pass::call_on_module(tpl->design, tpl, "proc"); Pass::call_on_module(tpl->design, tpl, "proc");
@ -179,8 +169,8 @@ struct TechmapWorker
orig_cell_name = cell->name.str(); orig_cell_name = cell->name.str();
if (!flatten_mode) { if (!flatten_mode) {
for (auto &it : tpl->cells_) for (auto tpl_cell : tpl->cells())
if (it.first == ID::_TECHMAP_REPLACE_) { if (tpl_cell->name == ID::_TECHMAP_REPLACE_) {
module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str()); module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str());
break; break;
} }
@ -204,30 +194,30 @@ struct TechmapWorker
design->select(module, m); design->select(module, m);
} }
std::map<RTLIL::IdString, RTLIL::IdString> positional_ports; dict<IdString, IdString> positional_ports;
dict<Wire*, IdString> temp_renamed_wires; dict<Wire*, IdString> temp_renamed_wires;
pool<SigBit> autopurge_tpl_bits; pool<SigBit> autopurge_tpl_bits;
for (auto &it : tpl->wires_) for (auto tpl_w : tpl->wires())
{ {
if (it.second->port_id > 0) if (tpl_w->port_id > 0)
{ {
IdString posportname = stringf("$%d", it.second->port_id); IdString posportname = stringf("$%d", tpl_w->port_id);
positional_ports[posportname] = it.first; positional_ports.emplace(posportname, tpl_w->name);
if (!flatten_mode && it.second->get_bool_attribute(ID::techmap_autopurge) && if (!flatten_mode && tpl_w->get_bool_attribute(ID::techmap_autopurge) &&
(!cell->hasPort(it.second->name) || !GetSize(cell->getPort(it.second->name))) && (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) &&
(!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname))))
{ {
if (sigmaps.count(tpl) == 0) if (sigmaps.count(tpl) == 0)
sigmaps[tpl].set(tpl); sigmaps[tpl].set(tpl);
for (auto bit : sigmaps.at(tpl)(it.second)) for (auto bit : sigmaps.at(tpl)(tpl_w))
if (bit.wire != nullptr) if (bit.wire != nullptr)
autopurge_tpl_bits.insert(bit); autopurge_tpl_bits.insert(bit);
} }
} }
IdString w_name = it.second->name; IdString w_name = tpl_w->name;
apply_prefix(cell->name, w_name); apply_prefix(cell->name, w_name);
RTLIL::Wire *w = module->wire(w_name); RTLIL::Wire *w = module->wire(w_name);
if (w != nullptr) { if (w != nullptr) {
@ -237,30 +227,30 @@ struct TechmapWorker
w = nullptr; w = nullptr;
} else { } else {
w->attributes.erase(ID::hierconn); w->attributes.erase(ID::hierconn);
if (GetSize(w) < GetSize(it.second)) { if (GetSize(w) < GetSize(tpl_w)) {
log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", log_id(module), log_id(w), log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", log_id(module), log_id(w),
log_id(tpl), log_id(it.second), log_id(module), log_id(cell)); log_id(tpl), log_id(tpl_w), log_id(module), log_id(cell));
w->width = GetSize(it.second); w->width = GetSize(tpl_w);
} }
} }
} }
if (w == nullptr) { if (w == nullptr) {
w = module->addWire(w_name, it.second); w = module->addWire(w_name, tpl_w);
w->port_input = false; w->port_input = false;
w->port_output = false; w->port_output = false;
w->port_id = 0; w->port_id = 0;
if (!flatten_mode) if (!flatten_mode)
w->attributes.erase(ID::techmap_autopurge); w->attributes.erase(ID::techmap_autopurge);
if (it.second->get_bool_attribute(ID::_techmap_special_)) if (tpl_w->get_bool_attribute(ID::_techmap_special_))
w->attributes.clear(); w->attributes.clear();
if (w->attributes.count(ID::src)) if (w->attributes.count(ID::src))
w->add_strpool_attribute(ID::src, extra_src_attrs); w->add_strpool_attribute(ID::src, extra_src_attrs);
} }
design->select(module, w); design->select(module, w);
if (it.second->name.begins_with("\\_TECHMAP_REPLACE_.")) { if (tpl_w->name.begins_with("\\_TECHMAP_REPLACE_.")) {
IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), it.second->name.c_str() + strlen("\\_TECHMAP_REPLACE_")); IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), tpl_w->name.c_str() + strlen("\\_TECHMAP_REPLACE_"));
Wire *replace_w = module->addWire(replace_name, it.second); Wire *replace_w = module->addWire(replace_name, tpl_w);
module->connect(replace_w, w); module->connect(replace_w, w);
} }
} }
@ -268,24 +258,23 @@ struct TechmapWorker
SigMap tpl_sigmap(tpl); SigMap tpl_sigmap(tpl);
pool<SigBit> tpl_written_bits; pool<SigBit> tpl_written_bits;
for (auto &it1 : tpl->cells_) for (auto tpl_cell : tpl->cells())
for (auto &it2 : it1.second->connections_) for (auto &conn : tpl_cell->connections())
if (it1.second->output(it2.first)) if (tpl_cell->output(conn.first))
for (auto bit : tpl_sigmap(it2.second)) for (auto bit : tpl_sigmap(conn.second))
tpl_written_bits.insert(bit); tpl_written_bits.insert(bit);
for (auto &it1 : tpl->connections_) for (auto &conn : tpl->connections())
for (auto bit : tpl_sigmap(it1.first)) for (auto bit : tpl_sigmap(conn.first))
tpl_written_bits.insert(bit); tpl_written_bits.insert(bit);
SigMap port_signal_map; SigMap port_signal_map;
SigSig port_signal_assign;
for (auto &it : cell->connections()) for (auto &it : cell->connections())
{ {
RTLIL::IdString portname = it.first; IdString portname = it.first;
if (positional_ports.count(portname) > 0) if (positional_ports.count(portname) > 0)
portname = positional_ports.at(portname); portname = positional_ports.at(portname);
if (tpl->wires_.count(portname) == 0 || tpl->wires_.at(portname)->port_id == 0) { if (tpl->wire(portname) == nullptr || tpl->wire(portname)->port_id == 0) {
if (portname.begins_with("$")) if (portname.begins_with("$"))
log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str()); log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str());
continue; continue;
@ -294,7 +283,7 @@ struct TechmapWorker
if (GetSize(it.second) == 0) if (GetSize(it.second) == 0)
continue; continue;
RTLIL::Wire *w = tpl->wires_.at(portname); RTLIL::Wire *w = tpl->wire(portname);
RTLIL::SigSig c, extra_connect; RTLIL::SigSig c, extra_connect;
if (w->port_output && !w->port_input) { if (w->port_output && !w->port_input) {
@ -377,19 +366,19 @@ struct TechmapWorker
} }
} }
for (auto &it : tpl->cells_) for (auto tpl_cell : tpl->cells())
{ {
IdString c_name = it.second->name.str(); IdString c_name = tpl_cell->name;
bool techmap_replace_cell = (!flatten_mode) && (c_name == ID::_TECHMAP_REPLACE_); bool techmap_replace_cell = (!flatten_mode) && (c_name == ID::_TECHMAP_REPLACE_);
if (techmap_replace_cell) if (techmap_replace_cell)
c_name = orig_cell_name; c_name = orig_cell_name;
else if (it.second->name.begins_with("\\_TECHMAP_REPLACE_.")) else if (tpl_cell->name.begins_with("\\_TECHMAP_REPLACE_."))
c_name = stringf("%s%s", orig_cell_name.c_str(), c_name.c_str() + strlen("\\_TECHMAP_REPLACE_")); c_name = stringf("%s%s", orig_cell_name.c_str(), c_name.c_str() + strlen("\\_TECHMAP_REPLACE_"));
else else
apply_prefix(cell->name, c_name); apply_prefix(cell->name, c_name);
RTLIL::Cell *c = module->addCell(c_name, it.second); RTLIL::Cell *c = module->addCell(c_name, tpl_cell);
design->select(module, c); design->select(module, c);
if (!flatten_mode && c->type.begins_with("\\$")) if (!flatten_mode && c->type.begins_with("\\$"))
@ -397,12 +386,12 @@ struct TechmapWorker
vector<IdString> autopurge_ports; vector<IdString> autopurge_ports;
for (auto &it2 : c->connections_) for (auto &conn : c->connections())
{ {
bool autopurge = false; bool autopurge = false;
if (!autopurge_tpl_bits.empty()) { if (!autopurge_tpl_bits.empty()) {
autopurge = GetSize(it2.second) != 0; autopurge = GetSize(conn.second) != 0;
for (auto &bit : sigmaps.at(tpl)(it2.second)) for (auto &bit : sigmaps.at(tpl)(conn.second))
if (!autopurge_tpl_bits.count(bit)) { if (!autopurge_tpl_bits.count(bit)) {
autopurge = false; autopurge = false;
break; break;
@ -410,10 +399,12 @@ struct TechmapWorker
} }
if (autopurge) { if (autopurge) {
autopurge_ports.push_back(it2.first); autopurge_ports.push_back(conn.first);
} else { } else {
apply_prefix(cell->name, it2.second, module); RTLIL::SigSpec new_conn = conn.second;
port_signal_map.apply(it2.second); apply_prefix(cell->name, new_conn, module);
port_signal_map.apply(new_conn);
c->setPort(conn.first, std::move(new_conn));
} }
} }
@ -463,8 +454,8 @@ struct TechmapWorker
} }
} }
bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells, bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool<RTLIL::Cell*> &handled_cells,
const std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> &celltypeMap, bool in_recursion) const dict<IdString, pool<IdString>> &celltypeMap, bool in_recursion)
{ {
std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping";
@ -489,13 +480,13 @@ struct TechmapWorker
} }
} }
TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells; TopoSort<RTLIL::Cell*, IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit; dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_inbit;
std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell; dict<RTLIL::SigBit, pool<RTLIL::Cell*>> outbit_to_cell;
for (auto cell : module->cells()) for (auto cell : module->selected_cells())
{ {
if (!design->selected(module, cell) || handled_cells.count(cell) > 0) if (handled_cells.count(cell) > 0)
continue; continue;
std::string cell_type = cell->type.str(); std::string cell_type = cell->type.str();
@ -511,7 +502,7 @@ struct TechmapWorker
if (flatten_mode) { if (flatten_mode) {
bool keepit = cell->get_bool_attribute(ID::keep_hierarchy); bool keepit = cell->get_bool_attribute(ID::keep_hierarchy);
for (auto &tpl_name : celltypeMap.at(cell_type)) for (auto &tpl_name : celltypeMap.at(cell_type))
if (map->modules_[tpl_name]->get_bool_attribute(ID::keep_hierarchy)) if (map->module(tpl_name)->get_bool_attribute(ID::keep_hierarchy))
keepit = true; keepit = true;
if (keepit) { if (keepit) {
if (!flatten_keep_list[cell]) { if (!flatten_keep_list[cell]) {
@ -533,7 +524,7 @@ struct TechmapWorker
continue; continue;
for (auto &tpl_name : celltypeMap.at(cell_type)) { for (auto &tpl_name : celltypeMap.at(cell_type)) {
RTLIL::Module *tpl = map->modules_[tpl_name]; RTLIL::Module *tpl = map->module(tpl_name);
RTLIL::Wire *port = tpl->wire(conn.first); RTLIL::Wire *port = tpl->wire(conn.first);
if (port && port->port_input) if (port && port->port_input)
cell_to_inbit[cell].insert(sig.begin(), sig.end()); cell_to_inbit[cell].insert(sig.begin(), sig.end());
@ -566,9 +557,9 @@ struct TechmapWorker
for (auto &tpl_name : celltypeMap.at(cell_type)) for (auto &tpl_name : celltypeMap.at(cell_type))
{ {
RTLIL::IdString derived_name = tpl_name; IdString derived_name = tpl_name;
RTLIL::Module *tpl = map->modules_[tpl_name]; RTLIL::Module *tpl = map->module(tpl_name);
std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end()); dict<IdString, RTLIL::Const> parameters(cell->parameters);
if (tpl->get_blackbox_attribute(ignore_wb)) if (tpl->get_blackbox_attribute(ignore_wb))
continue; continue;
@ -675,7 +666,7 @@ struct TechmapWorker
if (extmapper_name == "simplemap") { if (extmapper_name == "simplemap") {
if (simplemap_mappers.count(cell->type) == 0) if (simplemap_mappers.count(cell->type) == 0)
log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type)); log_error("No simplemap mapper for cell type %s found!\n", log_id(cell->type));
simplemap_mappers.at(cell->type)(module, cell); simplemap_mappers.at(cell->type)(module, cell);
} }
@ -686,7 +677,7 @@ struct TechmapWorker
} }
module->remove(cell); module->remove(cell);
cell = NULL; cell = nullptr;
} }
did_something = true; did_something = true;
@ -694,10 +685,10 @@ struct TechmapWorker
break; break;
} }
for (auto conn : cell->connections()) { for (auto &conn : cell->connections()) {
if (conn.first.begins_with("$")) if (conn.first.begins_with("$"))
continue; continue;
if (tpl->wires_.count(conn.first) > 0 && tpl->wires_.at(conn.first)->port_id > 0) if (tpl->wire(conn.first) != nullptr && tpl->wire(conn.first)->port_id > 0)
continue; continue;
if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0) if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0)
goto next_tpl; goto next_tpl;
@ -710,23 +701,23 @@ struct TechmapWorker
} }
if (tpl->avail_parameters.count(ID::_TECHMAP_CELLTYPE_) != 0) if (tpl->avail_parameters.count(ID::_TECHMAP_CELLTYPE_) != 0)
parameters[ID::_TECHMAP_CELLTYPE_] = RTLIL::unescape_id(cell->type); parameters.emplace(ID::_TECHMAP_CELLTYPE_, RTLIL::unescape_id(cell->type));
for (auto conn : cell->connections()) { for (auto &conn : cell->connections()) {
if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) { if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))) != 0) {
std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector(); std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
for (auto &bit : v) for (auto &bit : v)
bit = RTLIL::SigBit(bit.wire == NULL ? RTLIL::State::S1 : RTLIL::State::S0); bit = RTLIL::SigBit(bit.wire == nullptr ? RTLIL::State::S1 : RTLIL::State::S0);
parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); parameters.emplace(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const());
} }
if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))) != 0) { if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))) != 0) {
std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector(); std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
for (auto &bit : v) for (auto &bit : v)
if (bit.wire != NULL) if (bit.wire != nullptr)
bit = RTLIL::SigBit(RTLIL::State::Sx); bit = RTLIL::SigBit(RTLIL::State::Sx);
parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const());
} }
if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))) != 0) { if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) {
auto sig = sigmap(conn.second); auto sig = sigmap(conn.second);
RTLIL::Const value(State::Sx, sig.size()); RTLIL::Const value(State::Sx, sig.size());
for (int i = 0; i < sig.size(); i++) { for (int i = 0; i < sig.size(); i++) {
@ -735,20 +726,20 @@ struct TechmapWorker
value[i] = it->second; value[i] = it->second;
} }
} }
parameters[stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))] = value; parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), value);
} }
} }
int unique_bit_id_counter = 0; int unique_bit_id_counter = 0;
std::map<RTLIL::SigBit, int> unique_bit_id; dict<RTLIL::SigBit, int> unique_bit_id;
unique_bit_id[RTLIL::State::S0] = unique_bit_id_counter++; unique_bit_id[RTLIL::State::S0] = unique_bit_id_counter++;
unique_bit_id[RTLIL::State::S1] = unique_bit_id_counter++; unique_bit_id[RTLIL::State::S1] = unique_bit_id_counter++;
unique_bit_id[RTLIL::State::Sx] = unique_bit_id_counter++; unique_bit_id[RTLIL::State::Sx] = unique_bit_id_counter++;
unique_bit_id[RTLIL::State::Sz] = unique_bit_id_counter++; unique_bit_id[RTLIL::State::Sz] = unique_bit_id_counter++;
for (auto conn : cell->connections()) for (auto &conn : cell->connections())
if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) { if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))) != 0) {
for (auto &bit : sigmap(conn.second).to_sigbit_vector()) for (auto &bit : sigmap(conn.second))
if (unique_bit_id.count(bit) == 0) if (unique_bit_id.count(bit) == 0)
unique_bit_id[bit] = unique_bit_id_counter++; unique_bit_id[bit] = unique_bit_id_counter++;
} }
@ -763,14 +754,17 @@ struct TechmapWorker
if (tpl->avail_parameters.count(ID::_TECHMAP_BITS_CONNMAP_)) if (tpl->avail_parameters.count(ID::_TECHMAP_BITS_CONNMAP_))
parameters[ID::_TECHMAP_BITS_CONNMAP_] = bits; parameters[ID::_TECHMAP_BITS_CONNMAP_] = bits;
for (auto conn : cell->connections()) for (auto &conn : cell->connections())
if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) { if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))) != 0) {
RTLIL::Const value; RTLIL::Const value;
for (auto &bit : sigmap(conn.second).to_sigbit_vector()) { for (auto &bit : sigmap(conn.second)) {
RTLIL::Const chunk(unique_bit_id.at(bit), bits); int val = unique_bit_id.at(bit);
value.bits.insert(value.bits.end(), chunk.bits.begin(), chunk.bits.end()); for (int i = 0; i < bits; i++) {
value.bits.push_back((val & 1) != 0 ? State::S1 : State::S0);
val = val >> 1;
}
} }
parameters[stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))] = value; parameters.emplace(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first)), value);
} }
} }
@ -778,17 +772,18 @@ struct TechmapWorker
use_wrapper_tpl:; use_wrapper_tpl:;
// do not register techmap_wrap modules with techmap_cache // do not register techmap_wrap modules with techmap_cache
} else { } else {
std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters); std::pair<IdString, dict<IdString, RTLIL::Const>> key(tpl_name, parameters);
if (techmap_cache.count(key) > 0) { auto it = techmap_cache.find(key);
tpl = techmap_cache[key]; if (it != techmap_cache.end()) {
tpl = it->second;
} else { } else {
if (parameters.size() != 0) { if (parameters.size() != 0) {
mkdebug.on(); mkdebug.on();
derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end())); derived_name = tpl->derive(map, parameters);
tpl = map->module(derived_name); tpl = map->module(derived_name);
log_continue = true; log_continue = true;
} }
techmap_cache[key] = tpl; techmap_cache.emplace(std::move(key), tpl);
} }
} }
@ -805,7 +800,7 @@ struct TechmapWorker
bool keep_running = true; bool keep_running = true;
techmap_do_cache[tpl] = true; techmap_do_cache[tpl] = true;
std::set<std::string> techmap_wire_names; pool<IdString> techmap_wire_names;
while (keep_running) while (keep_running)
{ {
@ -815,11 +810,11 @@ struct TechmapWorker
for (auto &it : twd) for (auto &it : twd)
techmap_wire_names.insert(it.first); techmap_wire_names.insert(it.first);
for (auto &it : twd["_TECHMAP_FAIL_"]) { for (auto &it : twd[ID::_TECHMAP_FAIL_]) {
RTLIL::SigSpec value = it.value; RTLIL::SigSpec value = it.value;
if (value.is_fully_const() && value.as_bool()) { if (value.is_fully_const() && value.as_bool()) {
log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n",
derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value)); derived_name.c_str(), log_id(it.wire->name), log_signal(value));
techmap_do_cache[tpl] = false; techmap_do_cache[tpl] = false;
} }
} }
@ -829,13 +824,13 @@ struct TechmapWorker
for (auto &it : twd) for (auto &it : twd)
{ {
if (it.first.compare(0, 12, "_TECHMAP_DO_") != 0 || it.second.empty()) if (!it.first.begins_with("\\_TECHMAP_DO_") || it.second.empty())
continue; continue;
auto &data = it.second.front(); auto &data = it.second.front();
if (!data.value.is_fully_const()) if (!data.value.is_fully_const())
log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value)); log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(data.wire->name), log_signal(data.value));
techmap_wire_names.erase(it.first); techmap_wire_names.erase(it.first);
@ -851,7 +846,7 @@ struct TechmapWorker
cmd_string = cmd_string.substr(strlen("CONSTMAP; ")); cmd_string = cmd_string.substr(strlen("CONSTMAP; "));
log("Analyzing pattern of constant bits for this cell:\n"); log("Analyzing pattern of constant bits for this cell:\n");
RTLIL::IdString new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true); IdString new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true);
log("Creating constmapped module `%s'.\n", log_id(new_tpl_name)); log("Creating constmapped module `%s'.\n", log_id(new_tpl_name));
log_assert(map->module(new_tpl_name) == nullptr); log_assert(map->module(new_tpl_name) == nullptr);
@ -862,16 +857,16 @@ struct TechmapWorker
techmap_do_cache[new_tpl] = true; techmap_do_cache[new_tpl] = true;
tpl = new_tpl; tpl = new_tpl;
std::map<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map; dict<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map;
std::map<RTLIL::SigBit, RTLIL::SigBit> port_connmap; dict<RTLIL::SigBit, RTLIL::SigBit> port_connmap;
std::map<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits; dict<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits;
for (auto wire : tpl->wires().to_vector()) for (auto wire : tpl->wires().to_vector())
{ {
if (!wire->port_input || wire->port_output) if (!wire->port_input || wire->port_output)
continue; continue;
RTLIL::IdString port_name = wire->name; IdString port_name = wire->name;
tpl->rename(wire, NEW_ID); tpl->rename(wire, NEW_ID);
RTLIL::Wire *new_wire = tpl->addWire(port_name, wire); RTLIL::Wire *new_wire = tpl->addWire(port_name, wire);
@ -879,12 +874,12 @@ struct TechmapWorker
wire->port_id = 0; wire->port_id = 0;
for (int i = 0; i < wire->width; i++) { for (int i = 0; i < wire->width; i++) {
port_new2old_map[RTLIL::SigBit(new_wire, i)] = RTLIL::SigBit(wire, i); port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), RTLIL::SigBit(wire, i));
port_connmap[RTLIL::SigBit(wire, i)] = RTLIL::SigBit(new_wire, i); port_connmap.emplace(RTLIL::SigBit(wire, i), RTLIL::SigBit(new_wire, i));
} }
} }
for (auto conn : cell->connections()) for (auto &conn : cell->connections())
for (int i = 0; i < GetSize(conn.second); i++) for (int i = 0; i < GetSize(conn.second); i++)
{ {
RTLIL::SigBit bit = sigmap(conn.second[i]); RTLIL::SigBit bit = sigmap(conn.second[i]);
@ -926,7 +921,7 @@ struct TechmapWorker
log_assert(!strncmp(q, "_TECHMAP_DO_", 12)); log_assert(!strncmp(q, "_TECHMAP_DO_", 12));
std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12); std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12);
while (tpl->wires_.count(new_name)) while (tpl->wire(new_name) != nullptr)
new_name += "_"; new_name += "_";
tpl->rename(data.wire->name, new_name); tpl->rename(data.wire->name, new_name);
@ -937,17 +932,17 @@ struct TechmapWorker
TechmapWires twd = techmap_find_special_wires(tpl); TechmapWires twd = techmap_find_special_wires(tpl);
for (auto &it : twd) { for (auto &it : twd) {
if (it.first != "_TECHMAP_FAIL_" && (it.first.substr(0, 20) != "_TECHMAP_REMOVEINIT_" || it.first[it.first.size()-1] != '_') && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") if (it.first != ID::_TECHMAP_FAIL_ && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.begins_with("\\_TECHMAP_DO_") && !it.first.begins_with("\\_TECHMAP_DONE_"))
log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str()); log_error("Techmap yielded unknown config wire %s.\n", log_id(it.first));
if (techmap_do_cache[tpl]) if (techmap_do_cache[tpl])
for (auto &it2 : it.second) for (auto &it2 : it.second)
if (!it2.value.is_fully_const()) if (!it2.value.is_fully_const())
log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value)); log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(it2.wire->name), log_signal(it2.value));
techmap_wire_names.erase(it.first); techmap_wire_names.erase(it.first);
} }
for (auto &it : techmap_wire_names) for (auto &it : techmap_wire_names)
log_error("Techmap special wire %s disappeared. This is considered a fatal error.\n", RTLIL::id2cstr(it)); log_error("Techmap special wire %s disappeared. This is considered a fatal error.\n", log_id(it));
if (recursive_mode) { if (recursive_mode) {
if (log_continue) { if (log_continue) {
@ -970,10 +965,10 @@ struct TechmapWorker
TechmapWires twd = techmap_find_special_wires(tpl); TechmapWires twd = techmap_find_special_wires(tpl);
for (auto &it : twd) { for (auto &it : twd) {
if (it.first.substr(0, 20) == "_TECHMAP_REMOVEINIT_") { if (it.first.begins_with("\\_TECHMAP_REMOVEINIT_")) {
for (auto &it2 : it.second) { for (auto &it2 : it.second) {
auto val = it2.value.as_const(); auto val = it2.value.as_const();
auto wirename = RTLIL::escape_id(it.first.substr(20, it.first.size() - 20 - 1)); auto wirename = RTLIL::escape_id(it.first.substr(21, it.first.size() - 21 - 1));
auto it = cell->connections().find(wirename); auto it = cell->connections().find(wirename);
if (it != cell->connections().end()) { if (it != cell->connections().end()) {
auto sig = sigmap(it->second); auto sig = sigmap(it->second);
@ -1015,7 +1010,7 @@ struct TechmapWorker
} }
log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl)); log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl));
techmap_module_worker(design, module, cell, tpl); techmap_module_worker(design, module, cell, tpl);
cell = NULL; cell = nullptr;
} }
did_something = true; did_something = true;
mapped_cell = true; mapped_cell = true;
@ -1275,8 +1270,7 @@ struct TechmapPass : public Pass {
RTLIL::Design *map = new RTLIL::Design; RTLIL::Design *map = new RTLIL::Design;
if (map_files.empty()) { if (map_files.empty()) {
std::istringstream f(stdcells_code); Frontend::frontend_call(map, nullptr, "+/techmap.v", verilog_frontend);
Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend);
} else { } else {
for (auto &fn : map_files) for (auto &fn : map_files)
if (fn.compare(0, 1, "%") == 0) { if (fn.compare(0, 1, "%") == 0) {
@ -1285,35 +1279,30 @@ struct TechmapPass : public Pass {
log_cmd_error("Can't open saved design `%s'.\n", fn.c_str()+1); log_cmd_error("Can't open saved design `%s'.\n", fn.c_str()+1);
} }
for (auto mod : saved_designs.at(fn.substr(1))->modules()) for (auto mod : saved_designs.at(fn.substr(1))->modules())
if (!map->has(mod->name)) if (!map->module(mod->name))
map->add(mod->clone()); map->add(mod->clone());
} else { } else {
std::ifstream f; Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend));
rewrite_filename(fn);
f.open(fn.c_str());
yosys_input_files.insert(fn);
if (f.fail())
log_cmd_error("Can't open map file `%s'\n", fn.c_str());
Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend));
} }
} }
log_header(design, "Continuing TECHMAP pass.\n"); log_header(design, "Continuing TECHMAP pass.\n");
std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; dict<IdString, pool<IdString>> celltypeMap;
for (auto &it : map->modules_) { for (auto module : map->modules()) {
if (it.second->attributes.count(ID::techmap_celltype) && !it.second->attributes.at(ID::techmap_celltype).bits.empty()) { if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) {
char *p = strdup(it.second->attributes.at(ID::techmap_celltype).decode_string().c_str()); char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str());
for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n")) for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n"))
celltypeMap[RTLIL::escape_id(q)].insert(it.first); celltypeMap[RTLIL::escape_id(q)].insert(module->name);
free(p); free(p);
} else { } else {
string module_name = it.first.str(); IdString module_name = module->name.begins_with("\\$") ?
if (it.first.begins_with("\\$")) module->name.substr(1) : module->name.str();
module_name = module_name.substr(1); celltypeMap[module_name].insert(module->name);
celltypeMap[module_name].insert(it.first);
} }
} }
for (auto &i : celltypeMap)
i.second.sort(RTLIL::sort_by_id_str());
for (auto module : design->modules()) for (auto module : design->modules())
worker.module_queue.insert(module); worker.module_queue.insert(module);
@ -1325,7 +1314,7 @@ struct TechmapPass : public Pass {
int module_max_iter = max_iter; int module_max_iter = max_iter;
bool did_something = true; bool did_something = true;
std::set<RTLIL::Cell*> handled_cells; pool<RTLIL::Cell*> handled_cells;
while (did_something) { while (did_something) {
did_something = false; did_something = false;
if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false))
@ -1382,18 +1371,20 @@ struct FlattenPass : public Pass {
extra_args(args, argidx, design); extra_args(args, argidx, design);
std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; dict<IdString, pool<IdString>> celltypeMap;
for (auto module : design->modules()) for (auto module : design->modules())
celltypeMap[module->name].insert(module->name); celltypeMap[module->name].insert(module->name);
for (auto &i : celltypeMap)
i.second.sort(RTLIL::sort_by_id_str());
RTLIL::Module *top_mod = NULL; RTLIL::Module *top_mod = nullptr;
if (design->full_selection()) if (design->full_selection())
for (auto mod : design->modules()) for (auto mod : design->modules())
if (mod->get_bool_attribute(ID::top)) if (mod->get_bool_attribute(ID::top))
top_mod = mod; top_mod = mod;
std::set<RTLIL::Cell*> handled_cells; pool<RTLIL::Cell*> handled_cells;
if (top_mod != NULL) { if (top_mod != nullptr) {
worker.flatten_do_list.insert(top_mod->name); worker.flatten_do_list.insert(top_mod->name);
while (!worker.flatten_do_list.empty()) { while (!worker.flatten_do_list.empty()) {
auto mod = design->module(*worker.flatten_do_list.begin()); auto mod = design->module(*worker.flatten_do_list.begin());
@ -1402,20 +1393,19 @@ struct FlattenPass : public Pass {
worker.flatten_do_list.erase(mod->name); worker.flatten_do_list.erase(mod->name);
} }
} else { } else {
for (auto mod : vector<Module*>(design->modules())) { for (auto mod : design->modules().to_vector())
while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { } while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { }
}
} }
log_suppressed(); log_suppressed();
log("No more expansions possible.\n"); log("No more expansions possible.\n");
if (top_mod != NULL) if (top_mod != nullptr)
{ {
pool<RTLIL::IdString> used_modules, new_used_modules; pool<IdString> used_modules, new_used_modules;
new_used_modules.insert(top_mod->name); new_used_modules.insert(top_mod->name);
while (!new_used_modules.empty()) { while (!new_used_modules.empty()) {
pool<RTLIL::IdString> queue; pool<IdString> queue;
queue.swap(new_used_modules); queue.swap(new_used_modules);
for (auto modname : queue) for (auto modname : queue)
used_modules.insert(modname); used_modules.insert(modname);
@ -1425,15 +1415,11 @@ struct FlattenPass : public Pass {
new_used_modules.insert(cell->type); new_used_modules.insert(cell->type);
} }
dict<RTLIL::IdString, RTLIL::Module*> new_modules; for (auto mod : design->modules().to_vector())
for (auto mod : vector<Module*>(design->modules())) if (!used_modules[mod->name] && !mod->get_blackbox_attribute(worker.ignore_wb)) {
if (used_modules[mod->name] || mod->get_blackbox_attribute(worker.ignore_wb)) {
new_modules[mod->name] = mod;
} else {
log("Deleting now unused module %s.\n", log_id(mod)); log("Deleting now unused module %s.\n", log_id(mod));
delete mod; design->remove(mod);
} }
design->modules_.swap(new_modules);
} }
log_pop(); log_pop();

View File

@ -264,7 +264,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
cell->setPort(ID::Y, wire); cell->setPort(ID::Y, wire);
} }
if (muxdiv && cell_type.in(ID($div), ID($mod))) { if (muxdiv && cell_type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) {
auto b_not_zero = module->ReduceBool(NEW_ID, cell->getPort(ID::B)); auto b_not_zero = module->ReduceBool(NEW_ID, cell->getPort(ID::B));
auto div_out = module->addWire(NEW_ID, GetSize(cell->getPort(ID::Y))); auto div_out = module->addWire(NEW_ID, GetSize(cell->getPort(ID::Y)));
module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(div_out)), div_out, b_not_zero, cell->getPort(ID::Y)); module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(div_out)), div_out, b_not_zero, cell->getPort(ID::Y));
@ -839,6 +839,8 @@ struct TestCellPass : public Pass {
cell_types[ID($mul)] = "ABSY"; cell_types[ID($mul)] = "ABSY";
cell_types[ID($div)] = "ABSY"; cell_types[ID($div)] = "ABSY";
cell_types[ID($mod)] = "ABSY"; cell_types[ID($mod)] = "ABSY";
cell_types[ID($divfloor)] = "ABSY";
cell_types[ID($modfloor)] = "ABSY";
// cell_types[ID($pow)] = "ABsY"; // cell_types[ID($pow)] = "ABsY";
cell_types[ID($logic_not)] = "ASY"; cell_types[ID($logic_not)] = "ASY";

View File

@ -26,8 +26,11 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
@ -36,11 +39,14 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, CO);
wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
(* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
//wire [Y_WIDTH:0] C = {CO, CI}; //wire [Y_WIDTH:0] C = {CO, CI};
wire [Y_WIDTH+1:0] COx; wire [Y_WIDTH+1:0] COx;

View File

@ -38,6 +38,7 @@ endmodule
module \$lut (A, Y); module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;
generate generate

View File

@ -26,24 +26,33 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
(* force_downto *)
output [Y_WIDTH-1:0] CO; output [Y_WIDTH-1:0] CO;
wire CIx; wire CIx;
(* force_downto *)
wire [Y_WIDTH-1:0] COx; wire [Y_WIDTH-1:0] COx;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
(* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] C = { COx, CIx }; wire [Y_WIDTH-1:0] C = { COx, CIx };
wire dummy; wire dummy;

View File

@ -32,6 +32,7 @@ module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;

View File

@ -30,4 +30,6 @@ $(eval $(call add_share_file,share,techlibs/common/cmp2lut.v))
$(eval $(call add_share_file,share,techlibs/common/cells.lib)) $(eval $(call add_share_file,share,techlibs/common/cells.lib))
$(eval $(call add_share_file,share,techlibs/common/mul2dsp.v)) $(eval $(call add_share_file,share,techlibs/common/mul2dsp.v))
$(eval $(call add_share_file,share,techlibs/common/abc9_model.v)) $(eval $(call add_share_file,share,techlibs/common/abc9_model.v))
$(eval $(call add_share_file,share,techlibs/common/abc9_map.v))
$(eval $(call add_share_file,share,techlibs/common/abc9_unmap.v))
$(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v)) $(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v))

View File

@ -0,0 +1,27 @@
`ifdef DFF
(* techmap_celltype = "$_DFF_N_ $_DFF_P_" *)
module $_DFF_x_(input C, D, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
parameter _TECHMAP_CELLTYPE_ = "";
wire D_;
generate if (_TECHMAP_CELLTYPE_ == "$_DFF_N_") begin
if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin
$__DFF_N__$abc9_flop _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_));
$_DFF_N_ ff (.C(C), .D(D_), .Q(Q));
end
else
(* abc9_keep *) $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q));
end
else if (_TECHMAP_CELLTYPE_ == "$_DFF_P_") begin
if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin
$__DFF_P__$abc9_flop _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_));
$_DFF_P_ ff (.C(C), .D(D_), .Q(Q));
end
else
(* abc9_keep *) $_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q));
end
else if (_TECHMAP_CELLTYPE_ != "")
$error("Unrecognised _TECHMAP_CELLTYPE_");
endgenerate
endmodule
`endif

View File

@ -1,10 +1,25 @@
module \$__ABC9_FF_ (input D, output Q);
endmodule
(* abc9_box *) (* abc9_box *)
module \$__ABC9_DELAY (input I, output O); module $__ABC9_DELAY (input I, output O);
parameter DELAY = 0; parameter DELAY = 0;
specify specify
(I => O) = DELAY; (I => O) = DELAY;
endspecify endspecify
endmodule endmodule
(* abc9_flop, abc9_box, lib_whitebox *)
module $__DFF_N__$abc9_flop (input C, D, Q, output n1);
assign n1 = D;
specify
$setup(D, posedge C, 0);
(posedge C => (n1:D)) = 0;
endspecify
endmodule
(* abc9_flop, abc9_box, lib_whitebox *)
module $__DFF_P__$abc9_flop (input C, D, Q, output n1);
assign n1 = D;
specify
$setup(D, posedge C, 0);
(posedge C => (n1:D)) = 0;
endspecify
endmodule

View File

@ -0,0 +1,11 @@
(* techmap_celltype = "$__DFF_N__$abc9_flop $__DFF_P__$abc9_flop" *)
module $__DFF_x__$abc9_flop (input C, D, Q, output n1);
parameter _TECHMAP_CELLTYPE_ = "";
generate if (_TECHMAP_CELLTYPE_ == "$__DFF_N__$abc9_flop")
$_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q));
else if (_TECHMAP_CELLTYPE_ == "$__DFF_P__$abc9_flop")
$_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q));
else if (_TECHMAP_CELLTYPE_ != "")
$error("Unrecognised _TECHMAP_CELLTYPE_");
endgenerate
endmodule

View File

@ -6,8 +6,11 @@ module adff2dff (CLK, ARST, D, Q);
parameter ARST_VALUE = 0; parameter ARST_VALUE = 0;
input CLK, ARST; input CLK, ARST;
(* force_downto *)
input [WIDTH-1:0] D; input [WIDTH-1:0] D;
(* force_downto *)
output reg [WIDTH-1:0] Q; output reg [WIDTH-1:0] Q;
(* force_downto *)
wire reg [WIDTH-1:0] NEXT_Q; wire reg [WIDTH-1:0] NEXT_Q;
wire [1023:0] _TECHMAP_DO_ = "proc;;"; wire [1023:0] _TECHMAP_DO_ = "proc;;";

View File

@ -12,8 +12,11 @@ parameter A_WIDTH = 0;
parameter B_WIDTH = 0; parameter B_WIDTH = 0;
parameter Y_WIDTH = 0; parameter Y_WIDTH = 0;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y; output [Y_WIDTH-1:0] Y;
parameter _TECHMAP_CELLTYPE_ = ""; parameter _TECHMAP_CELLTYPE_ = "";
@ -32,7 +35,9 @@ generate
else begin else begin
// Perform sign extension on A and B // Perform sign extension on A and B
localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
(* force_downto *)
wire [WIDTH-1:0] AA = {{(WIDTH-A_WIDTH){A_SIGNED ? A[A_WIDTH-1] : 1'b0}}, A}; wire [WIDTH-1:0] AA = {{(WIDTH-A_WIDTH){A_SIGNED ? A[A_WIDTH-1] : 1'b0}}, A};
(* force_downto *)
wire [WIDTH-1:0] BB = {{(WIDTH-B_WIDTH){B_SIGNED ? B[B_WIDTH-1] : 1'b0}}, B}; wire [WIDTH-1:0] BB = {{(WIDTH-B_WIDTH){B_SIGNED ? B[B_WIDTH-1] : 1'b0}}, B};
// For $ge operation, start with the assumption that A and B are // For $ge operation, start with the assumption that A and B are
// equal (propagating this equality if A and B turn out to be so) // equal (propagating this equality if A and B turn out to be so)
@ -54,9 +59,13 @@ parameter LCU_WIDTH = 1;
parameter BUDGET = 0; parameter BUDGET = 0;
parameter CI = 0; parameter CI = 0;
(* force_downto *)
input [AB_WIDTH-1:0] A; // A from original $gt/$ge input [AB_WIDTH-1:0] A; // A from original $gt/$ge
(* force_downto *)
input [AB_WIDTH-1:0] B; // B from original $gt/$ge input [AB_WIDTH-1:0] B; // B from original $gt/$ge
(* force_downto *)
input [LCU_WIDTH-1:0] P; // P of $lcu input [LCU_WIDTH-1:0] P; // P of $lcu
(* force_downto *)
input [LCU_WIDTH-1:0] G; // G of $lcu input [LCU_WIDTH-1:0] G; // G of $lcu
output Y; output Y;
@ -66,6 +75,7 @@ parameter [LCU_WIDTH-1:0] _TECHMAP_CONSTMSK_P_ = 0;
generate generate
if (AB_WIDTH == 0) begin if (AB_WIDTH == 0) begin
(* force_downto *)
wire [LCU_WIDTH-1:0] CO; wire [LCU_WIDTH-1:0] CO;
$lcu #(.WIDTH(LCU_WIDTH)) _TECHMAP_REPLACE_ (.P(P), .G(G), .CI(CI), .CO(CO)); $lcu #(.WIDTH(LCU_WIDTH)) _TECHMAP_REPLACE_ (.P(P), .G(G), .CI(CI), .CO(CO));
assign Y = CO[LCU_WIDTH-1]; assign Y = CO[LCU_WIDTH-1];
@ -104,12 +114,18 @@ generate
else begin else begin
// Propagate only if all pairs are equal // Propagate only if all pairs are equal
// (inconclusive evidence to say A >= B) // (inconclusive evidence to say A >= B)
(* force_downto *)
wire [LCU_WIDTH-1:0] P_ = {P[LCU_WIDTH-1:1], P[0] & PP}; wire [LCU_WIDTH-1:0] P_ = {P[LCU_WIDTH-1:1], P[0] & PP};
// Generate if any comparisons call for it // Generate if any comparisons call for it
(* force_downto *)
wire [LCU_WIDTH-1:0] G_ = {G[LCU_WIDTH-1:1], G[0] | GG}; wire [LCU_WIDTH-1:0] G_ = {G[LCU_WIDTH-1:1], G[0] | GG};
end end
$__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) if (AB_WIDTH == 1)
_TECHMAP_REPLACE_ (.A(A[AB_WIDTH-2:0]), .B(B[AB_WIDTH-2:0]), .P(P_), .G(G_), .Y(Y)); $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI))
_TECHMAP_REPLACE_ (.A(), .B(), .P(P_), .G(G_), .Y(Y));
else
$__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI))
_TECHMAP_REPLACE_ (.A(A[AB_WIDTH-2:0]), .B(B[AB_WIDTH-2:0]), .P(P_), .G(G_), .Y(Y));
end end
end end
endgenerate endgenerate

View File

@ -16,8 +16,11 @@ parameter A_WIDTH = 0;
parameter B_WIDTH = 0; parameter B_WIDTH = 0;
parameter Y_WIDTH = 0; parameter Y_WIDTH = 0;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y; output [Y_WIDTH-1:0] Y;
parameter _TECHMAP_CELLTYPE_ = ""; parameter _TECHMAP_CELLTYPE_ = "";

View File

@ -4,7 +4,9 @@ module dff2ff (CLK, D, Q);
parameter CLK_POLARITY = 1; parameter CLK_POLARITY = 1;
input CLK; input CLK;
(* force_downto *)
input [WIDTH-1:0] D; input [WIDTH-1:0] D;
(* force_downto *)
output reg [WIDTH-1:0] Q; output reg [WIDTH-1:0] Q;
wire [1023:0] _TECHMAP_DO_ = "proc;;"; wire [1023:0] _TECHMAP_DO_ = "proc;;";

View File

@ -57,8 +57,11 @@ module _80_mul (A, B, Y);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y; output [Y_WIDTH-1:0] Y;
parameter _TECHMAP_CELLTYPE_ = ""; parameter _TECHMAP_CELLTYPE_ = "";
@ -119,13 +122,19 @@ module _80_mul (A, B, Y);
localparam last_A_WIDTH = A_WIDTH-n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom); localparam last_A_WIDTH = A_WIDTH-n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom);
localparam last_Y_WIDTH = B_WIDTH+last_A_WIDTH; localparam last_Y_WIDTH = B_WIDTH+last_A_WIDTH;
if (A_SIGNED && B_SIGNED) begin if (A_SIGNED && B_SIGNED) begin
(* force_downto *)
wire signed [partial_Y_WIDTH-1:0] partial [n-1:0]; wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
(* force_downto *)
wire signed [last_Y_WIDTH-1:0] last_partial; wire signed [last_Y_WIDTH-1:0] last_partial;
(* force_downto *)
wire signed [Y_WIDTH-1:0] partial_sum [n:0]; wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end end
else begin else begin
(* force_downto *)
wire [partial_Y_WIDTH-1:0] partial [n-1:0]; wire [partial_Y_WIDTH-1:0] partial [n-1:0];
(* force_downto *)
wire [last_Y_WIDTH-1:0] last_partial; wire [last_Y_WIDTH-1:0] last_partial;
(* force_downto *)
wire [Y_WIDTH-1:0] partial_sum [n:0]; wire [Y_WIDTH-1:0] partial_sum [n:0];
end end
@ -170,13 +179,19 @@ module _80_mul (A, B, Y);
localparam last_B_WIDTH = B_WIDTH-n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom); localparam last_B_WIDTH = B_WIDTH-n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom);
localparam last_Y_WIDTH = A_WIDTH+last_B_WIDTH; localparam last_Y_WIDTH = A_WIDTH+last_B_WIDTH;
if (A_SIGNED && B_SIGNED) begin if (A_SIGNED && B_SIGNED) begin
(* force_downto *)
wire signed [partial_Y_WIDTH-1:0] partial [n-1:0]; wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
(* force_downto *)
wire signed [last_Y_WIDTH-1:0] last_partial; wire signed [last_Y_WIDTH-1:0] last_partial;
(* force_downto *)
wire signed [Y_WIDTH-1:0] partial_sum [n:0]; wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end end
else begin else begin
(* force_downto *)
wire [partial_Y_WIDTH-1:0] partial [n-1:0]; wire [partial_Y_WIDTH-1:0] partial [n-1:0];
(* force_downto *)
wire [last_Y_WIDTH-1:0] last_partial; wire [last_Y_WIDTH-1:0] last_partial;
(* force_downto *)
wire [Y_WIDTH-1:0] partial_sum [n:0]; wire [Y_WIDTH-1:0] partial_sum [n:0];
end end
@ -249,8 +264,11 @@ module _90_soft_mul (A, B, Y);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y; output [Y_WIDTH-1:0] Y;
// Indirection necessary since mapping // Indirection necessary since mapping

View File

@ -997,6 +997,12 @@ endmodule
// -------------------------------------------------------- // --------------------------------------------------------
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
//-
//- $div (A, B, Y)
//-
//- Division with truncated result (rounded towards 0).
//-
module \$div (A, B, Y); module \$div (A, B, Y);
parameter A_SIGNED = 0; parameter A_SIGNED = 0;
@ -1021,6 +1027,14 @@ endmodule
// -------------------------------------------------------- // --------------------------------------------------------
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
//-
//- $mod (A, B, Y)
//-
//- Modulo/remainder of division with truncated result (rounded towards 0).
//-
//- Invariant: $div(A, B) * B + $mod(A, B) == A
//-
module \$mod (A, B, Y); module \$mod (A, B, Y);
parameter A_SIGNED = 0; parameter A_SIGNED = 0;
@ -1043,6 +1057,83 @@ endgenerate
endmodule endmodule
// --------------------------------------------------------
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
//-
//- $divfloor (A, B, Y)
//-
//- Division with floored result (rounded towards negative infinity).
//-
module \$divfloor (A, B, Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B;
output [Y_WIDTH-1:0] Y;
generate
if (A_SIGNED && B_SIGNED) begin:BLOCK1
localparam WIDTH =
A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH :
B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
wire [WIDTH:0] A_buf, B_buf, N_buf;
assign A_buf = $signed(A);
assign B_buf = $signed(B);
assign N_buf = (A[A_WIDTH-1] == B[B_WIDTH-1]) || A == 0 ? A_buf : $signed(A_buf - (B[B_WIDTH-1] ? B_buf+1 : B_buf-1));
assign Y = $signed(N_buf) / $signed(B_buf);
end else begin:BLOCK2
assign Y = A / B;
end
endgenerate
endmodule
// --------------------------------------------------------
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
//-
//- $modfloor (A, B, Y)
//-
//- Modulo/remainder of division with floored result (rounded towards negative infinity).
//-
//- Invariant: $divfloor(A, B) * B + $modfloor(A, B) == A
//-
module \$modfloor (A, B, Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B;
output [Y_WIDTH-1:0] Y;
generate
if (A_SIGNED && B_SIGNED) begin:BLOCK1
localparam WIDTH = B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
wire [WIDTH-1:0] B_buf, Y_trunc;
assign B_buf = $signed(B);
assign Y_trunc = $signed(A) % $signed(B);
// flooring mod is the same as truncating mod for positive division results (A and B have
// the same sign), as well as when there's no remainder.
// For all other cases, they behave as `floor - trunc = B`
assign Y = (A[A_WIDTH-1] == B[B_WIDTH-1]) || Y_trunc == 0 ? Y_trunc : $signed(B_buf) + $signed(Y_trunc);
end else begin:BLOCK2
// no difference between truncating and flooring for unsigned
assign Y = A % B;
end
endgenerate
endmodule
// -------------------------------------------------------- // --------------------------------------------------------
`ifndef SIMLIB_NOPOW `ifndef SIMLIB_NOPOW

View File

@ -85,8 +85,11 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y);
localparam shift_left = _TECHMAP_CELLTYPE_ == "$shl" || _TECHMAP_CELLTYPE_ == "$sshl"; localparam shift_left = _TECHMAP_CELLTYPE_ == "$shl" || _TECHMAP_CELLTYPE_ == "$sshl";
localparam sign_extend = A_SIGNED && _TECHMAP_CELLTYPE_ == "$sshr"; localparam sign_extend = A_SIGNED && _TECHMAP_CELLTYPE_ == "$sshr";
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y; output [Y_WIDTH-1:0] Y;
localparam WIDTH = `MAX(A_WIDTH, Y_WIDTH); localparam WIDTH = `MAX(A_WIDTH, Y_WIDTH);
@ -96,6 +99,7 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y);
wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;"; wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;";
integer i; integer i;
(* force_downto *)
reg [WIDTH-1:0] buffer; reg [WIDTH-1:0] buffer;
reg overflow; reg overflow;
@ -125,8 +129,11 @@ module _90_shift_shiftx (A, B, Y);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y; output [Y_WIDTH-1:0] Y;
parameter _TECHMAP_CELLTYPE_ = ""; parameter _TECHMAP_CELLTYPE_ = "";
@ -173,6 +180,7 @@ module _90_shift_shiftx (A, B, Y);
wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;"; wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;";
integer i; integer i;
(* force_downto *)
reg [WIDTH-1:0] buffer; reg [WIDTH-1:0] buffer;
reg overflow; reg overflow;
@ -216,9 +224,12 @@ endmodule
module _90_fa (A, B, C, X, Y); module _90_fa (A, B, C, X, Y);
parameter WIDTH = 1; parameter WIDTH = 1;
(* force_downto *)
input [WIDTH-1:0] A, B, C; input [WIDTH-1:0] A, B, C;
(* force_downto *)
output [WIDTH-1:0] X, Y; output [WIDTH-1:0] X, Y;
(* force_downto *)
wire [WIDTH-1:0] t1, t2, t3; wire [WIDTH-1:0] t1, t2, t3;
assign t1 = A ^ B, t2 = A & B, t3 = C & t1; assign t1 = A ^ B, t2 = A & B, t3 = C & t1;
@ -229,12 +240,15 @@ endmodule
module _90_lcu (P, G, CI, CO); module _90_lcu (P, G, CI, CO);
parameter WIDTH = 2; parameter WIDTH = 2;
(* force_downto *)
input [WIDTH-1:0] P, G; input [WIDTH-1:0] P, G;
input CI; input CI;
(* force_downto *)
output [WIDTH-1:0] CO; output [WIDTH-1:0] CO;
integer i, j; integer i, j;
(* force_downto *)
reg [WIDTH-1:0] p, g; reg [WIDTH-1:0] p, g;
wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast"; wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast";
@ -278,20 +292,27 @@ module _90_alu (A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
(* force_downto *)
output [Y_WIDTH-1:0] CO; output [Y_WIDTH-1:0] CO;
(* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
wire [Y_WIDTH-1:0] AA = A_buf;
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
\$lcu #(.WIDTH(Y_WIDTH)) lcu (.P(X), .G(AA & BB), .CI(CI), .CO(CO)); \$lcu #(.WIDTH(Y_WIDTH)) lcu (.P(X), .G(AA & BB), .CI(CI), .CO(CO));
assign X = AA ^ BB; assign X = AA ^ BB;
@ -316,15 +337,19 @@ endmodule
module \$__div_mod_u (A, B, Y, R); module \$__div_mod_u (A, B, Y, R);
parameter WIDTH = 1; parameter WIDTH = 1;
(* force_downto *)
input [WIDTH-1:0] A, B; input [WIDTH-1:0] A, B;
(* force_downto *)
output [WIDTH-1:0] Y, R; output [WIDTH-1:0] Y, R;
(* force_downto *)
wire [WIDTH*WIDTH-1:0] chaindata; wire [WIDTH*WIDTH-1:0] chaindata;
assign R = chaindata[WIDTH*WIDTH-1:WIDTH*(WIDTH-1)]; assign R = chaindata[WIDTH*WIDTH-1:WIDTH*(WIDTH-1)];
genvar i; genvar i;
generate begin generate begin
for (i = 0; i < WIDTH; i=i+1) begin:stage for (i = 0; i < WIDTH; i=i+1) begin:stage
(* force_downto *)
wire [WIDTH-1:0] stage_in; wire [WIDTH-1:0] stage_in;
if (i == 0) begin:cp if (i == 0) begin:cp
@ -339,7 +364,8 @@ module \$__div_mod_u (A, B, Y, R);
end endgenerate end endgenerate
endmodule endmodule
module \$__div_mod (A, B, Y, R); // truncating signed division/modulo
module \$__div_mod_trunc (A, B, Y, R);
parameter A_SIGNED = 0; parameter A_SIGNED = 0;
parameter B_SIGNED = 0; parameter B_SIGNED = 0;
parameter A_WIDTH = 1; parameter A_WIDTH = 1;
@ -350,14 +376,19 @@ module \$__div_mod (A, B, Y, R);
A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH : A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH :
B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH; B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y, R; output [Y_WIDTH-1:0] Y, R;
(* force_downto *)
wire [WIDTH-1:0] A_buf, B_buf; wire [WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
(* force_downto *)
wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u; wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u;
assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf; assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf;
assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf; assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf;
@ -383,11 +414,14 @@ module _90_div (A, B, Y);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y; output [Y_WIDTH-1:0] Y;
\$__div_mod #( \$__div_mod_trunc #(
.A_SIGNED(A_SIGNED), .A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED), .B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH), .A_WIDTH(A_WIDTH),
@ -408,11 +442,114 @@ module _90_mod (A, B, Y);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y; output [Y_WIDTH-1:0] Y;
\$__div_mod #( \$__div_mod_trunc #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH),
.B_WIDTH(B_WIDTH),
.Y_WIDTH(Y_WIDTH)
) div_mod (
.A(A),
.B(B),
.R(Y)
);
endmodule
// flooring signed division/modulo
module \$__div_mod_floor (A, B, Y, R);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
localparam WIDTH =
A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH :
B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B;
output [Y_WIDTH-1:0] Y, R;
wire [WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u, R_s;
assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf;
assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf;
\$__div_mod_u #(
.WIDTH(WIDTH)
) div_mod_u (
.A(A_buf_u),
.B(B_buf_u),
.Y(Y_u),
.R(R_u)
);
// For negative results, if there was a remainder, subtract one to turn
// the round towards 0 into a round towards -inf
assign Y = A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? (R_u == 0 ? -Y_u : -Y_u-1) : Y_u;
// truncating modulo
assign R_s = A_SIGNED && B_SIGNED && A_buf[WIDTH-1] ? -R_u : R_u;
// Flooring modulo differs from truncating modulo only if it is nonzero and
// A and B have different signs - then `floor - trunc = B`
assign R = (R_s != 0) && A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? $signed(B_buf) + $signed(R_s) : R_s;
endmodule
(* techmap_celltype = "$divfloor" *)
module _90_divfloor (A, B, Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y;
\$__div_mod_floor #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH),
.B_WIDTH(B_WIDTH),
.Y_WIDTH(Y_WIDTH)
) div_mod (
.A(A),
.B(B),
.Y(Y)
);
endmodule
(* techmap_celltype = "$modfloor" *)
module _90_modfloor (A, B, Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y;
\$__div_mod_floor #(
.A_SIGNED(A_SIGNED), .A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED), .B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH), .A_WIDTH(A_WIDTH),
@ -438,8 +575,11 @@ module _90_pow (A, B, Y);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y; output [Y_WIDTH-1:0] Y;
wire _TECHMAP_FAIL_ = 1; wire _TECHMAP_FAIL_ = 1;
@ -455,20 +595,27 @@ module _90_pmux (A, B, S, Y);
parameter WIDTH = 1; parameter WIDTH = 1;
parameter S_WIDTH = 1; parameter S_WIDTH = 1;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
(* force_downto *)
input [WIDTH*S_WIDTH-1:0] B; input [WIDTH*S_WIDTH-1:0] B;
(* force_downto *)
input [S_WIDTH-1:0] S; input [S_WIDTH-1:0] S;
(* force_downto *)
output [WIDTH-1:0] Y; output [WIDTH-1:0] Y;
(* force_downto *)
wire [WIDTH-1:0] Y_B; wire [WIDTH-1:0] Y_B;
genvar i, j; genvar i, j;
generate generate
(* force_downto *)
wire [WIDTH*S_WIDTH-1:0] B_AND_S; wire [WIDTH*S_WIDTH-1:0] B_AND_S;
for (i = 0; i < S_WIDTH; i = i + 1) begin:B_AND for (i = 0; i < S_WIDTH; i = i + 1) begin:B_AND
assign B_AND_S[WIDTH*(i+1)-1:WIDTH*i] = B[WIDTH*(i+1)-1:WIDTH*i] & {WIDTH{S[i]}}; assign B_AND_S[WIDTH*(i+1)-1:WIDTH*i] = B[WIDTH*(i+1)-1:WIDTH*i] & {WIDTH{S[i]}};
end:B_AND end:B_AND
for (i = 0; i < WIDTH; i = i + 1) begin:B_OR for (i = 0; i < WIDTH; i = i + 1) begin:B_OR
(* force_downto *)
wire [S_WIDTH-1:0] B_AND_BITS; wire [S_WIDTH-1:0] B_AND_BITS;
for (j = 0; j < S_WIDTH; j = j + 1) begin:B_AND_BITS_COLLECT for (j = 0; j < S_WIDTH; j = j + 1) begin:B_AND_BITS_COLLECT
assign B_AND_BITS[j] = B_AND_S[WIDTH*j+i]; assign B_AND_BITS[j] = B_AND_S[WIDTH*j+i];

View File

@ -3,6 +3,7 @@ module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP);
input wire CE; input wire CE;
input wire CLK; input wire CLK;
output wire OUT; output wire OUT;
(* force_downto *)
output wire[WIDTH-1:0] POUT; output wire[WIDTH-1:0] POUT;
input wire RST; input wire RST;
input wire UP; input wire UP;

View File

@ -24,10 +24,6 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dsp_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dsp_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_unmap.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_model.v))
EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
.SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk .SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk

View File

@ -1,27 +0,0 @@
// ---------------------------------------
// Attach a (combinatorial) black-box onto the output
// of this LUTRAM primitive to capture its
// asynchronous read behaviour
module TRELLIS_DPR16X4 (
(* techmap_autopurge *) input [3:0] DI,
(* techmap_autopurge *) input [3:0] WAD,
(* techmap_autopurge *) input WRE,
(* techmap_autopurge *) input WCK,
(* techmap_autopurge *) input [3:0] RAD,
output [3:0] DO
);
parameter WCKMUX = "WCK";
parameter WREMUX = "WRE";
parameter [63:0] INITVAL = 64'h0000000000000000;
wire [3:0] $DO;
TRELLIS_DPR16X4 #(
.WCKMUX(WCKMUX), .WREMUX(WREMUX), .INITVAL(INITVAL)
) _TECHMAP_REPLACE_ (
.DI(DI), .WAD(WAD), .WRE(WRE), .WCK(WCK),
.RAD(RAD), .DO($DO)
);
$__ABC9_DPR16X4_COMB do (.$DO($DO), .RAD(RAD), .DO(DO));
endmodule

View File

@ -1,12 +0,0 @@
// ---------------------------------------
(* abc9_box *)
module \$__ABC9_DPR16X4_COMB (input [3:0] $DO, RAD, output [3:0] DO);
specify
($DO => DO) = 0;
(RAD[0] *> DO) = 141;
(RAD[1] *> DO) = 379;
(RAD[2] *> DO) = 275;
(RAD[3] *> DO) = 379;
endspecify
endmodule

View File

@ -1,5 +0,0 @@
// ---------------------------------------
module \$__ABC9_DPR16X4_COMB (input [3:0] $DO, RAD, output [3:0] DO);
assign DO = $DO;
endmodule

View File

@ -26,15 +26,20 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
(* force_downto *)
output [Y_WIDTH-1:0] CO; output [Y_WIDTH-1:0] CO;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
@ -48,10 +53,15 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO);
localparam Y_WIDTH2 = round_up2(Y_WIDTH); localparam Y_WIDTH2 = round_up2(Y_WIDTH);
(* force_downto *)
wire [Y_WIDTH2-1:0] AA = A_buf; wire [Y_WIDTH2-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf;
(* force_downto *)
wire [Y_WIDTH2-1:0] BX = B_buf; wire [Y_WIDTH2-1:0] BX = B_buf;
(* force_downto *)
wire [Y_WIDTH2-1:0] C = {CO, CI}; wire [Y_WIDTH2-1:0] C = {CO, CI};
(* force_downto *)
wire [Y_WIDTH2-1:0] FCO, Y1; wire [Y_WIDTH2-1:0] FCO, Y1;
genvar i; genvar i;

View File

@ -652,6 +652,10 @@ module DCUA(
parameter CH1_PROTOCOL = "8B10B"; parameter CH1_PROTOCOL = "8B10B";
parameter CH0_CDR_MAX_RATE = "2.5"; parameter CH0_CDR_MAX_RATE = "2.5";
parameter CH1_CDR_MAX_RATE = "2.5"; parameter CH1_CDR_MAX_RATE = "2.5";
parameter CH0_TXDEPRE = "DISABLED";
parameter CH1_TXDEPRE = "DISABLED";
parameter CH0_TXDEPOST = "DISABLED";
parameter CH1_TXDEPOST = "DISABLED";
endmodule endmodule
(* blackbox *) (* blackbox *)

View File

@ -70,6 +70,7 @@ module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;

View File

@ -186,6 +186,7 @@ module PFUMX (input ALUT, BLUT, C0, output Z);
endmodule endmodule
// --------------------------------------- // ---------------------------------------
(* abc9_box, lib_whitebox *)
module TRELLIS_DPR16X4 ( module TRELLIS_DPR16X4 (
input [3:0] DI, input [3:0] DI,
input [3:0] WAD, input [3:0] WAD,
@ -222,10 +223,16 @@ module TRELLIS_DPR16X4 (
mem[WAD] <= DI; mem[WAD] <= DI;
assign DO = mem[RAD]; assign DO = mem[RAD];
specify
// TODO
(RAD *> DO) = 0;
endspecify
endmodule endmodule
// --------------------------------------- // ---------------------------------------
(* abc9_box, lib_whitebox *)
module DPR16X4C ( module DPR16X4C (
input [3:0] DI, input [3:0] DI,
input WCK, WRE, input WCK, WRE,
@ -281,6 +288,10 @@ module DPR16X4C (
assign DO = ram[RAD]; assign DO = ram[RAD];
specify
// TODO
(RAD *> DO) = 0;
endspecify
endmodule endmodule
// --------------------------------------- // ---------------------------------------
@ -294,6 +305,9 @@ endmodule
// --------------------------------------- // ---------------------------------------
`ifdef YOSYS
(* abc9_flop=(SRMODE != "ASYNC"), abc9_box=(SRMODE == "ASYNC"), lib_whitebox *)
`endif
module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
parameter GSR = "ENABLED"; parameter GSR = "ENABLED";
parameter [127:0] CEMUX = "1"; parameter [127:0] CEMUX = "1";
@ -340,6 +354,38 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
Q <= DI; Q <= DI;
end end
endgenerate endgenerate
generate
// TODO
if (CLKMUX == "INV")
specify
$setup(DI, negedge CLK, 0);
$setup(CE, negedge CLK, 0);
$setup(LSR, negedge CLK, 0);
`ifndef YOSYS
if (SRMODE == "ASYNC" && muxlsr) (negedge CLK => (Q : srval)) = 0;
`else
if (SRMODE == "ASYNC" && muxlsr) (LSR => Q) = 0; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
if (!muxlsr && muxce) (negedge CLK => (Q : DI)) = 0;
endspecify
else
specify
$setup(DI, posedge CLK, 0);
$setup(CE, posedge CLK, 0);
$setup(LSR, posedge CLK, 0);
`ifndef YOSYS
if (SRMODE == "ASYNC" && muxlsr) (posedge CLK => (Q : srval)) = 0;
`else
if (SRMODE == "ASYNC" && muxlsr) (LSR => Q) = 0; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
if (!muxlsr && muxce) (posedge CLK => (Q : DI)) = 0;
endspecify
endgenerate
endmodule endmodule
// --------------------------------------- // ---------------------------------------

View File

@ -66,6 +66,9 @@ struct SynthEcp5Pass : public ScriptPass
log(" -noflatten\n"); log(" -noflatten\n");
log(" do not flatten design before synthesis\n"); log(" do not flatten design before synthesis\n");
log("\n"); log("\n");
log(" -dff\n");
log(" run 'abc'/'abc9' with -dff option\n");
log("\n");
log(" -retime\n"); log(" -retime\n");
log(" run 'abc' with '-dff -D 1' options\n"); log(" run 'abc' with '-dff -D 1' options\n");
log("\n"); log("\n");
@ -107,7 +110,7 @@ struct SynthEcp5Pass : public ScriptPass
} }
string top_opt, blif_file, edif_file, json_file; string top_opt, blif_file, edif_file, json_file;
bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, retime, abc2, abc9, nodsp, vpr; bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, dff, retime, abc2, abc9, nodsp, vpr;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
@ -122,6 +125,7 @@ struct SynthEcp5Pass : public ScriptPass
nowidelut = false; nowidelut = false;
asyncprld = false; asyncprld = false;
flatten = true; flatten = true;
dff = false;
retime = false; retime = false;
abc2 = false; abc2 = false;
vpr = false; vpr = false;
@ -169,6 +173,10 @@ struct SynthEcp5Pass : public ScriptPass
flatten = false; flatten = false;
continue; continue;
} }
if (args[argidx] == "-dff") {
dff = true;
continue;
}
if (args[argidx] == "-retime") { if (args[argidx] == "-retime") {
retime = true; retime = true;
continue; continue;
@ -307,6 +315,8 @@ struct SynthEcp5Pass : public ScriptPass
run("opt_clean"); run("opt_clean");
if (!nodffe) if (!nodffe)
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
if ((abc9 && dff) || help_mode)
run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "(only if -abc9 and -dff");
run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : ""))); run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : "")));
run("opt_expr -undriven -mux_undef"); run("opt_expr -undriven -mux_undef");
run("simplemap"); run("simplemap");
@ -318,17 +328,12 @@ struct SynthEcp5Pass : public ScriptPass
if (check_label("map_luts")) if (check_label("map_luts"))
{ {
if (abc2 || help_mode) { if (abc2 || help_mode)
run("abc", " (only if -abc2)"); run("abc", " (only if -abc2)");
} if (!asyncprld || help_mode)
std::string techmap_args = asyncprld ? "" : "-map +/ecp5/latches_map.v"; run("techmap -map +/ecp5/latches_map.v", "(skip if -asyncprld)");
if (abc9)
techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1";
if (!asyncprld || abc9)
run("techmap " + techmap_args);
if (abc9) { if (abc9) {
run("read_verilog -icells -lib -specify +/abc9_model.v +/ecp5/abc9_model.v");
std::string abc9_opts; std::string abc9_opts;
if (nowidelut) if (nowidelut)
abc9_opts += " -maxlut 4"; abc9_opts += " -maxlut 4";
@ -338,26 +343,29 @@ struct SynthEcp5Pass : public ScriptPass
else else
abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str());
if (nowidelut) if (nowidelut)
run("abc9 -maxlut 4 -W 200"); abc9_opts += " -maxlut 4";
else if (dff)
run("abc9 -W 200"); abc9_opts += " -dff";
run("techmap -map +/ecp5/abc9_unmap.v"); run("abc9" + abc9_opts);
} else { } else {
std::string abc_args = " -dress";
if (nowidelut) if (nowidelut)
run("abc -lut 4 -dress"); abc_args += " -lut 4";
else else
run("abc -lut 4:7 -dress"); abc_args += " -lut 4:7";
if (dff)
abc_args += " -dff";
run("abc" + abc_args);
} }
run("clean"); run("clean");
} }
if (check_label("map_cells")) if (check_label("map_cells"))
{ {
if (vpr) if (help_mode)
run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); run("techmap -map +/ecp5/cells_map.v", "(skip if -vpr)");
else else if (!vpr)
run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)"); run("techmap -map +/ecp5/cells_map.v");
run("opt_lut_ins -tech ecp5"); run("opt_lut_ins -tech ecp5");
run("clean"); run("clean");
} }

View File

@ -26,24 +26,33 @@ module _80_efinix_alu (A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
(* force_downto *)
output [Y_WIDTH-1:0] CO; output [Y_WIDTH-1:0] CO;
wire CIx; wire CIx;
(* force_downto *)
wire [Y_WIDTH-1:0] COx; wire [Y_WIDTH-1:0] COx;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
(* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] C = { COx, CIx }; wire [Y_WIDTH-1:0] C = { COx, CIx };
EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1)) EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))

View File

@ -34,6 +34,7 @@ module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;

View File

@ -26,21 +26,29 @@ module _80_gw1n_alu(A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
(* force_downto *)
output [Y_WIDTH-1:0] CO; output [Y_WIDTH-1:0] CO;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
(* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BB = B_buf; wire [Y_WIDTH-1:0] BB = B_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] C = {CO, CI}; wire [Y_WIDTH-1:0] C = {CO, CI};
genvar i; genvar i;

View File

@ -232,6 +232,7 @@ module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;

View File

@ -115,6 +115,7 @@ module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;
@ -150,6 +151,7 @@ module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP);
input wire CE; input wire CE;
input wire CLK; input wire CLK;
output reg OUT; output reg OUT;
(* force_downto *)
output reg[WIDTH-1:0] POUT; output reg[WIDTH-1:0] POUT;
input wire RST; input wire RST;
input wire UP; input wire UP;

View File

@ -23,6 +23,7 @@ techlibs/ice40/brams_init3.vh: techlibs/ice40/brams_init.mk
$(eval $(call add_share_file,share/ice40,techlibs/ice40/arith_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/arith_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/ff_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt))

View File

@ -25,21 +25,29 @@ module _80_ice40_alu (A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
(* force_downto *)
output [Y_WIDTH-1:0] CO; output [Y_WIDTH-1:0] CO;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
(* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] C = {CO, CI}; wire [Y_WIDTH-1:0] C = {CO, CI};
genvar i; genvar i;

View File

@ -1,37 +1,8 @@
module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule
module \$_DFF_P_ (input D, C, output Q); SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule
module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
`ifndef NO_LUT
module \$lut (A, Y); module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;
@ -59,4 +30,3 @@ module \$lut (A, Y);
end end
endgenerate endgenerate
endmodule endmodule
`endif

View File

@ -245,6 +245,7 @@ endmodule
// Positive Edge SiliconBlue FF Cells // Positive Edge SiliconBlue FF Cells
(* abc9_flop, lib_whitebox *)
module SB_DFF ( module SB_DFF (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, D input C, D
@ -280,6 +281,7 @@ module SB_DFF (
`endif `endif
endmodule endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFE ( module SB_DFFE (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, D input C, E, D
@ -322,6 +324,7 @@ module SB_DFFE (
`endif `endif
endmodule endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFSR ( module SB_DFFSR (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, R, D input C, R, D
@ -369,6 +372,7 @@ module SB_DFFSR (
`endif `endif
endmodule endmodule
(* abc9_box, lib_whitebox *)
module SB_DFFR ( module SB_DFFR (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, R, D input C, R, D
@ -386,7 +390,13 @@ module SB_DFFR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge R, posedge C, 160); $setup(negedge R, posedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 599; (posedge R => (Q : 1'b0)) = 599;
`else
if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90
if (!R) (posedge C => (Q : D)) = 540; if (!R) (posedge C => (Q : D)) = 540;
endspecify endspecify
@ -399,7 +409,13 @@ module SB_DFFR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge R, posedge C, 235); $setup(negedge R, posedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 883; (posedge R => (Q : 1'b0)) = 883;
`else
if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90
if (!R) (posedge C => (Q : D)) = 796; if (!R) (posedge C => (Q : D)) = 796;
endspecify endspecify
@ -412,13 +428,20 @@ module SB_DFFR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge R, posedge C, 424); $setup(negedge R, posedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 1589; (posedge R => (Q : 1'b0)) = 1589;
`else
if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102
if (!R) (posedge C => (Q : D)) = 1391; if (!R) (posedge C => (Q : D)) = 1391;
endspecify endspecify
`endif `endif
endmodule endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFSS ( module SB_DFFSS (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, S, D input C, S, D
@ -466,6 +489,7 @@ module SB_DFFSS (
`endif `endif
endmodule endmodule
(* abc9_box, lib_whitebox *)
module SB_DFFS ( module SB_DFFS (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, S, D input C, S, D
@ -483,7 +507,13 @@ module SB_DFFS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge S, posedge C, 160); $setup(negedge S, posedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 599; (posedge S => (Q : 1'b1)) = 599;
`else
if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90
if (!S) (posedge C => (Q : D)) = 540; if (!S) (posedge C => (Q : D)) = 540;
endspecify endspecify
@ -496,7 +526,13 @@ module SB_DFFS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge S, posedge C, 235); $setup(negedge S, posedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 883; (posedge S => (Q : 1'b1)) = 883;
`else
if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90
if (!S) (posedge C => (Q : D)) = 796; if (!S) (posedge C => (Q : D)) = 796;
endspecify endspecify
@ -509,13 +545,20 @@ module SB_DFFS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge S, posedge C, 424); $setup(negedge S, posedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 1589; (posedge S => (Q : 1'b1)) = 1589;
`else
if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102
if (!S) (posedge C => (Q : D)) = 1391; if (!S) (posedge C => (Q : D)) = 1391;
endspecify endspecify
`endif `endif
endmodule endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFESR ( module SB_DFFESR (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, R, D input C, E, R, D
@ -571,6 +614,7 @@ module SB_DFFESR (
`endif `endif
endmodule endmodule
(* abc9_box, lib_whitebox *)
module SB_DFFER ( module SB_DFFER (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, R, D input C, E, R, D
@ -590,7 +634,13 @@ module SB_DFFER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge R, posedge C, 160); $setup(negedge R, posedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 599; (posedge R => (Q : 1'b0)) = 599;
`else
if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90
if (E && !R) (posedge C => (Q : D)) = 540; if (E && !R) (posedge C => (Q : D)) = 540;
endspecify endspecify
@ -605,7 +655,13 @@ module SB_DFFER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge R, posedge C, 235); $setup(negedge R, posedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 883; (posedge R => (Q : 1'b0)) = 883;
`else
if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90
if (E && !R) (posedge C => (Q : D)) = 796; if (E && !R) (posedge C => (Q : D)) = 796;
endspecify endspecify
@ -620,13 +676,20 @@ module SB_DFFER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge R, posedge C, 424); $setup(negedge R, posedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 1589; (posedge R => (Q : 1'b0)) = 1589;
`else
if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102
if (E && !R) (posedge C => (Q : D)) = 1391; if (E && !R) (posedge C => (Q : D)) = 1391;
endspecify endspecify
`endif `endif
endmodule endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFESS ( module SB_DFFESS (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, S, D input C, E, S, D
@ -682,6 +745,7 @@ module SB_DFFESS (
`endif `endif
endmodule endmodule
(* abc9_box, lib_whitebox *)
module SB_DFFES ( module SB_DFFES (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, S, D input C, E, S, D
@ -701,7 +765,13 @@ module SB_DFFES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(posedge S, posedge C, 160); $setup(posedge S, posedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 599; (posedge S => (Q : 1'b1)) = 599;
`else
if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90
if (E && !S) (posedge C => (Q : D)) = 540; if (E && !S) (posedge C => (Q : D)) = 540;
endspecify endspecify
@ -716,7 +786,13 @@ module SB_DFFES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(posedge S, posedge C, 235); $setup(posedge S, posedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 883; (posedge S => (Q : 1'b1)) = 883;
`else
if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90
if (E && !S) (posedge C => (Q : D)) = 796; if (E && !S) (posedge C => (Q : D)) = 796;
endspecify endspecify
@ -731,7 +807,13 @@ module SB_DFFES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(posedge S, posedge C, 424); $setup(posedge S, posedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 1589; (posedge S => (Q : 1'b1)) = 1589;
`else
if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102
if (E && !S) (posedge C => (Q : D)) = 1391; if (E && !S) (posedge C => (Q : D)) = 1391;
endspecify endspecify
@ -740,6 +822,7 @@ endmodule
// Negative Edge SiliconBlue FF Cells // Negative Edge SiliconBlue FF Cells
(* abc9_flop, lib_whitebox *)
module SB_DFFN ( module SB_DFFN (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, D input C, D
@ -775,6 +858,7 @@ module SB_DFFN (
`endif `endif
endmodule endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFNE ( module SB_DFFNE (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, D input C, E, D
@ -817,6 +901,7 @@ module SB_DFFNE (
`endif `endif
endmodule endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFNSR ( module SB_DFFNSR (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, R, D input C, R, D
@ -864,6 +949,7 @@ module SB_DFFNSR (
`endif `endif
endmodule endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFNR ( module SB_DFFNR (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, R, D input C, R, D
@ -881,7 +967,13 @@ module SB_DFFNR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge R, negedge C, 160); $setup(negedge R, negedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 599; (posedge R => (Q : 1'b0)) = 599;
`else
if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90
if (!R) (negedge C => (Q : D)) = 540; if (!R) (negedge C => (Q : D)) = 540;
endspecify endspecify
@ -894,7 +986,13 @@ module SB_DFFNR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge R, negedge C, 235); $setup(negedge R, negedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 883; (posedge R => (Q : 1'b0)) = 883;
`else
if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90
if (!R) (negedge C => (Q : D)) = 796; if (!R) (negedge C => (Q : D)) = 796;
endspecify endspecify
@ -907,13 +1005,20 @@ module SB_DFFNR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge R, negedge C, 424); $setup(negedge R, negedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 1589; (posedge R => (Q : 1'b0)) = 1589;
`else
if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102
if (!R) (negedge C => (Q : D)) = 1391; if (!R) (negedge C => (Q : D)) = 1391;
endspecify endspecify
`endif `endif
endmodule endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFNSS ( module SB_DFFNSS (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, S, D input C, S, D
@ -961,6 +1066,7 @@ module SB_DFFNSS (
`endif `endif
endmodule endmodule
(* abc9_box, lib_whitebox *)
module SB_DFFNS ( module SB_DFFNS (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, S, D input C, S, D
@ -978,7 +1084,13 @@ module SB_DFFNS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge S, negedge C, 160); $setup(negedge S, negedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 599; (posedge S => (Q : 1'b1)) = 599;
`else
if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90
if (!S) (negedge C => (Q : D)) = 540; if (!S) (negedge C => (Q : D)) = 540;
endspecify endspecify
@ -991,7 +1103,13 @@ module SB_DFFNS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge S, negedge C, 235); $setup(negedge S, negedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 883; (posedge S => (Q : 1'b1)) = 883;
`else
if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90
if (!S) (negedge C => (Q : D)) = 796; if (!S) (negedge C => (Q : D)) = 796;
endspecify endspecify
@ -1004,13 +1122,20 @@ module SB_DFFNS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge S, negedge C, 424); $setup(negedge S, negedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 1589; (posedge S => (Q : 1'b1)) = 1589;
`else
if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102
if (!S) (negedge C => (Q : D)) = 1391; if (!S) (negedge C => (Q : D)) = 1391;
endspecify endspecify
`endif `endif
endmodule endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFNESR ( module SB_DFFNESR (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, R, D input C, E, R, D
@ -1066,6 +1191,7 @@ module SB_DFFNESR (
`endif `endif
endmodule endmodule
(* abc9_box, lib_whitebox *)
module SB_DFFNER ( module SB_DFFNER (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, R, D input C, E, R, D
@ -1085,7 +1211,13 @@ module SB_DFFNER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(R, negedge C, 2160); $setup(R, negedge C, 2160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 599; (posedge R => (Q : 1'b0)) = 599;
`else
if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90
if (E && !R) (negedge C => (Q : D)) = 540; if (E && !R) (negedge C => (Q : D)) = 540;
endspecify endspecify
@ -1100,7 +1232,13 @@ module SB_DFFNER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(R, negedge C, 235); $setup(R, negedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 883; (posedge R => (Q : 1'b0)) = 883;
`else
if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90
if (E && !R) (negedge C => (Q : D)) = 796; if (E && !R) (negedge C => (Q : D)) = 796;
endspecify endspecify
@ -1115,13 +1253,20 @@ module SB_DFFNER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge R, negedge C, 424); $setup(negedge R, negedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
`ifndef YOSYS
(posedge R => (Q : 1'b0)) = 1589; (posedge R => (Q : 1'b0)) = 1589;
`else
if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102
if (E && !R) (negedge C => (Q : D)) = 1391; if (E && !R) (negedge C => (Q : D)) = 1391;
endspecify endspecify
`endif `endif
endmodule endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFNESS ( module SB_DFFNESS (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, S, D input C, E, S, D
@ -1177,6 +1322,7 @@ module SB_DFFNESS (
`endif `endif
endmodule endmodule
(* abc9_box, lib_whitebox *)
module SB_DFFNES ( module SB_DFFNES (
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, S, D input C, E, S, D
@ -1196,7 +1342,14 @@ module SB_DFFNES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge S, negedge C, 160); $setup(negedge S, negedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 599; (posedge S => (Q : 1'b1)) = 599;
`else
if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90
if (E && !S) (negedge C => (Q : D)) = 540; if (E && !S) (negedge C => (Q : D)) = 540;
endspecify endspecify
@ -1211,7 +1364,13 @@ module SB_DFFNES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge S, negedge C, 235); $setup(negedge S, negedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 883; (posedge S => (Q : 1'b1)) = 883;
`else
if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90
if (E && !S) (negedge C => (Q : D)) = 796; if (E && !S) (negedge C => (Q : D)) = 796;
endspecify endspecify
@ -1226,7 +1385,13 @@ module SB_DFFNES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge S, negedge C, 424); $setup(negedge S, negedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
`ifndef YOSYS
(posedge S => (Q : 1'b1)) = 1589; (posedge S => (Q : 1'b1)) = 1589;
`else
if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path
// but for facilitating a bypass box, let's pretend it's
// a simple path
`endif
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102
if (E && !S) (negedge C => (Q : D)) = 1391; if (E && !S) (negedge C => (Q : D)) = 1391;
endspecify endspecify
@ -1908,7 +2073,7 @@ module ICESTORM_LC (
o_reg <= SR_pd ? SET_NORESET : lut_o; o_reg <= SR_pd ? SET_NORESET : lut_o;
reg o_reg_async = 1'b0; reg o_reg_async = 1'b0;
always @(posedge polarized_clk, posedge SR) always @(posedge polarized_clk, posedge SR_pd)
if (SR_pd) if (SR_pd)
o_reg_async <= SET_NORESET; o_reg_async <= SET_NORESET;
else if (CEN_pu) else if (CEN_pu)
@ -2723,6 +2888,7 @@ module SB_IO_OD (
`endif `endif
endmodule endmodule
//(* abc9_box, lib_whitebox *) // TODO
module SB_MAC16 ( module SB_MAC16 (
input CLK, CE, input CLK, CE,
input [15:0] C, A, B, D, input [15:0] C, A, B, D,

28
techlibs/ice40/ff_map.v Normal file
View File

@ -0,0 +1,28 @@
module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule
module \$_DFF_P_ (input D, C, output Q); SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule
module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule

View File

@ -71,6 +71,9 @@ struct SynthIce40Pass : public ScriptPass
log(" -noflatten\n"); log(" -noflatten\n");
log(" do not flatten design before synthesis\n"); log(" do not flatten design before synthesis\n");
log("\n"); log("\n");
log(" -dff\n");
log(" run 'abc'/'abc9' with -dff option\n");
log("\n");
log(" -retime\n"); log(" -retime\n");
log(" run 'abc' with '-dff -D 1' options\n"); log(" run 'abc' with '-dff -D 1' options\n");
log("\n"); log("\n");
@ -113,7 +116,7 @@ struct SynthIce40Pass : public ScriptPass
} }
string top_opt, blif_file, edif_file, json_file, device_opt; string top_opt, blif_file, edif_file, json_file, device_opt;
bool nocarry, nodffe, nobram, dsp, flatten, retime, noabc, abc2, vpr, abc9, flowmap; bool nocarry, nodffe, nobram, dsp, flatten, retime, noabc, abc2, vpr, abc9, dff, flowmap;
int min_ce_use; int min_ce_use;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
@ -221,14 +224,18 @@ struct SynthIce40Pass : public ScriptPass
abc9 = true; abc9 = true;
continue; continue;
} }
if (args[argidx] == "-dff") {
dff = true;
continue;
}
if (args[argidx] == "-device" && argidx+1 < args.size()) { if (args[argidx] == "-device" && argidx+1 < args.size()) {
device_opt = args[++argidx]; device_opt = args[++argidx];
continue; continue;
} }
if (args[argidx] == "-flowmap") { if (args[argidx] == "-flowmap") {
flowmap = true; flowmap = true;
continue; continue;
} }
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
@ -240,13 +247,12 @@ struct SynthIce40Pass : public ScriptPass
if (abc9 && retime) if (abc9 && retime)
log_cmd_error("-retime option not currently compatible with -abc9!\n"); log_cmd_error("-retime option not currently compatible with -abc9!\n");
if (abc9 && noabc)
if (abc9 && noabc) log_cmd_error("-abc9 is incompatible with -noabc!\n");
log_cmd_error("-abc9 is incompatible with -noabc!\n"); if (abc9 && flowmap)
if (abc9 && flowmap) log_cmd_error("-abc9 is incompatible with -flowmap!\n");
log_cmd_error("-abc9 is incompatible with -flowmap!\n"); if (flowmap && noabc)
if (flowmap && noabc) log_cmd_error("-flowmap is incompatible with -noabc!\n");
log_cmd_error("-flowmap is incompatible with -noabc!\n");
log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_header(design, "Executing SYNTH_ICE40 pass.\n");
log_push(); log_push();
@ -355,7 +361,9 @@ struct SynthIce40Pass : public ScriptPass
run(stringf("dff2dffe -unmap-mince %d", min_ce_use)); run(stringf("dff2dffe -unmap-mince %d", min_ce_use));
run("simplemap t:$dff"); run("simplemap t:$dff");
} }
run("techmap -D NO_LUT -D NO_ADDER -map +/ice40/cells_map.v"); if ((abc9 && dff) || help_mode)
run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "(only if -abc9 and -dff");
run("techmap -map +/ice40/ff_map.v");
run("opt_expr -mux_undef"); run("opt_expr -mux_undef");
run("simplemap"); run("simplemap");
run("ice40_ffinit"); run("ice40_ffinit");
@ -372,14 +380,14 @@ struct SynthIce40Pass : public ScriptPass
run("techmap -map +/ice40/latches_map.v"); run("techmap -map +/ice40/latches_map.v");
if (noabc || flowmap || help_mode) { if (noabc || flowmap || help_mode) {
run("simplemap", " (if -noabc or -flowmap)"); run("simplemap", " (if -noabc or -flowmap)");
if (noabc || help_mode) if (noabc || help_mode)
run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
if (flowmap || help_mode) if (flowmap || help_mode)
run("flowmap -maxlut 4", "(only if -flowmap)"); run("flowmap -maxlut 4", "(only if -flowmap)");
} }
if (!noabc) { if (!noabc) {
if (abc9) { if (abc9) {
run("read_verilog " + define + " -icells -lib -specify +/abc9_model.v +/ice40/abc9_model.v"); run("read_verilog " + define + " -icells -lib -specify +/ice40/abc9_model.v");
std::string abc9_opts; std::string abc9_opts;
std::string k = "synth_ice40.abc9.W"; std::string k = "synth_ice40.abc9.W";
if (active_design && active_design->scratchpad.count(k)) if (active_design && active_design->scratchpad.count(k))
@ -388,24 +396,25 @@ struct SynthIce40Pass : public ScriptPass
k = stringf("synth_ice40.abc9.%s.W", device_opt.c_str()); k = stringf("synth_ice40.abc9.%s.W", device_opt.c_str());
abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str());
} }
if (dff)
abc9_opts += " -dff";
run("abc9 " + abc9_opts); run("abc9 " + abc9_opts);
} }
else else
run("abc -dress -lut 4", "(skip if -noabc)"); run(stringf("abc -dress -lut 4 %s", dff ? "-dff" : ""), "(skip if -noabc)");
} }
run("ice40_wrapcarry -unwrap"); run("ice40_wrapcarry -unwrap");
run("techmap -D NO_LUT -map +/ice40/cells_map.v"); run("techmap -map +/ice40/ff_map.v");
run("clean"); run("clean");
run("opt_lut -dlogic SB_CARRY:I0=2:I1=1:CI=0"); run("opt_lut -dlogic SB_CARRY:I0=2:I1=1:CI=0");
} }
if (check_label("map_cells")) if (check_label("map_cells"))
{ {
if (vpr) if (help_mode)
run("techmap -D NO_LUT -map +/ice40/cells_map.v"); run("techmap -map +/ice40/cells_map.v", "(skip if -vpr)");
else else if (!vpr)
run("techmap -map +/ice40/cells_map.v", "(with -D NO_LUT in vpr mode)"); run("techmap -map +/ice40/cells_map.v");
run("clean"); run("clean");
} }

View File

@ -26,8 +26,11 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
@ -36,11 +39,14 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO);
wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
(* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
//wire [Y_WIDTH:0] C = {CO, CI}; //wire [Y_WIDTH:0] C = {CO, CI};
wire [Y_WIDTH+1:0] COx; wire [Y_WIDTH+1:0] COx;

View File

@ -30,6 +30,7 @@ endmodule
module \$lut (A, Y); module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;
generate generate

View File

@ -26,8 +26,11 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
@ -36,11 +39,14 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO);
wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
(* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
//wire [Y_WIDTH:0] C = {CO, CI}; //wire [Y_WIDTH:0] C = {CO, CI};
wire [Y_WIDTH+1:0] COx; wire [Y_WIDTH+1:0] COx;

View File

@ -71,6 +71,7 @@ endmodule
module \$lut (A, Y); module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;
generate generate

View File

@ -70,8 +70,11 @@ module _80_cycloneiv_alu (A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
@ -79,11 +82,14 @@ module _80_cycloneiv_alu (A, B, CI, BI, X, Y, CO);
wire _TECHMAP_FAIL_ = Y_WIDTH < 6; wire _TECHMAP_FAIL_ = Y_WIDTH < 6;
(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
(* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH:0] C = {CO, CI};

View File

@ -71,6 +71,7 @@ endmodule
module \$lut (A, Y); module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;
generate generate

View File

@ -66,8 +66,11 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
@ -75,11 +78,14 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO);
wire _TECHMAP_FAIL_ = Y_WIDTH < 5; wire _TECHMAP_FAIL_ = Y_WIDTH < 5;
(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
(* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH:0] C = {CO, CI};

View File

@ -71,6 +71,7 @@ endmodule
module \$lut (A, Y); module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
(* force_downto *)
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;
generate generate

Some files were not shown because too many files have changed in this diff Show More