aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Crozier <peter@crozier.com>2020-06-03 17:19:28 +0100
committerGitHub <noreply@github.com>2020-06-03 17:19:28 +0100
commit0d3f7ea011288e1a1fadd4ae27f1e8a57d729053 (patch)
tree07bde0d9f492233728070234aed2abd45fbd464d
parent17f050d3c6b8934141c42f96a3418de67a687b2c (diff)
parent46ed0db2ec883a4ce330c81f321511e36e35c0b3 (diff)
downloadyosys-0d3f7ea011288e1a1fadd4ae27f1e8a57d729053.tar.gz
yosys-0d3f7ea011288e1a1fadd4ae27f1e8a57d729053.tar.bz2
yosys-0d3f7ea011288e1a1fadd4ae27f1e8a57d729053.zip
Merge branch 'master' into struct
-rw-r--r--CHANGELOG1
-rw-r--r--Makefile3
-rw-r--r--backends/aiger/xaiger.cc186
-rw-r--r--backends/btor/btor.cc14
-rw-r--r--backends/btor/test_cells.sh2
-rw-r--r--backends/cxxrtl/cxxrtl.cc30
-rw-r--r--backends/firrtl/firrtl.cc64
-rw-r--r--backends/smt2/smt2.cc10
-rw-r--r--backends/smt2/smtbmc.py11
-rw-r--r--backends/smt2/smtio.py37
-rw-r--r--backends/smv/smv.cc5
-rw-r--r--backends/smv/test_cells.sh4
-rw-r--r--backends/verilog/verilog_backend.cc89
-rw-r--r--frontends/aiger/aigerparse.cc14
-rw-r--r--frontends/aiger/aigerparse.h2
-rw-r--r--frontends/ast/genrtlil.cc2
-rw-r--r--frontends/ast/simplify.cc25
-rw-r--r--frontends/ilang/ilang_lexer.l4
-rw-r--r--frontends/verific/verific.cc7
-rw-r--r--frontends/verilog/verilog_lexer.l15
-rw-r--r--frontends/verilog/verilog_parser.y79
-rw-r--r--kernel/calc.cc47
-rw-r--r--kernel/celledges.cc2
-rw-r--r--kernel/celltypes.h4
-rw-r--r--kernel/constids.inc8
-rw-r--r--kernel/hashlib.h10
-rw-r--r--kernel/log.cc20
-rw-r--r--kernel/log.h19
-rw-r--r--kernel/rtlil.cc4
-rw-r--r--kernel/rtlil.h35
-rw-r--r--kernel/satgen.h42
-rw-r--r--kernel/timinginfo.h19
-rw-r--r--manual/CHAPTER_CellLib.tex23
-rw-r--r--manual/CHAPTER_Overview.tex9
-rw-r--r--manual/PRESENTATION_Prog.tex2
-rw-r--r--passes/cmds/Makefile.inc1
-rw-r--r--passes/cmds/blackbox.cc26
-rw-r--r--passes/cmds/logger.cc16
-rw-r--r--passes/cmds/printattrs.cc90
-rw-r--r--passes/cmds/stat.cc2
-rw-r--r--passes/hierarchy/hierarchy.cc4
-rw-r--r--passes/memory/memory_share.cc2
-rw-r--r--passes/opt/opt_clean.cc31
-rw-r--r--passes/opt/opt_expr.cc194
-rw-r--r--passes/opt/opt_share.cc4
-rw-r--r--passes/opt/share.cc6
-rw-r--r--passes/opt/wreduce.cc4
-rw-r--r--passes/sat/qbfsat.cc410
-rw-r--r--passes/techmap/.gitignore1
-rw-r--r--passes/techmap/Makefile.inc12
-rw-r--r--passes/techmap/abc9.cc125
-rw-r--r--passes/techmap/abc9_ops.cc1144
-rw-r--r--passes/techmap/simplemap.cc6
-rw-r--r--passes/techmap/simplemap.h2
-rw-r--r--passes/techmap/techmap.cc338
-rw-r--r--passes/tests/test_cell.cc4
-rw-r--r--techlibs/achronix/speedster22i/cells_arith.v6
-rw-r--r--techlibs/achronix/speedster22i/cells_map.v1
-rw-r--r--techlibs/anlogic/arith_map.v9
-rw-r--r--techlibs/anlogic/cells_map.v1
-rw-r--r--techlibs/common/Makefile.inc2
-rw-r--r--techlibs/common/abc9_map.v27
-rw-r--r--techlibs/common/abc9_model.v23
-rw-r--r--techlibs/common/abc9_unmap.v11
-rw-r--r--techlibs/common/adff2dff.v3
-rw-r--r--techlibs/common/cmp2lcu.v20
-rw-r--r--techlibs/common/cmp2lut.v3
-rw-r--r--techlibs/common/dff2ff.v2
-rw-r--r--techlibs/common/mul2dsp.v18
-rw-r--r--techlibs/common/simlib.v91
-rw-r--r--techlibs/common/techmap.v159
-rw-r--r--techlibs/coolrunner2/cells_counter_map.v1
-rw-r--r--techlibs/ecp5/Makefile.inc4
-rw-r--r--techlibs/ecp5/abc9_map.v27
-rw-r--r--techlibs/ecp5/abc9_model.v12
-rw-r--r--techlibs/ecp5/abc9_unmap.v5
-rw-r--r--techlibs/ecp5/arith_map.v10
-rw-r--r--techlibs/ecp5/cells_bb.v4
-rw-r--r--techlibs/ecp5/cells_map.v1
-rw-r--r--techlibs/ecp5/cells_sim.v46
-rw-r--r--techlibs/ecp5/synth_ecp5.cc48
-rw-r--r--techlibs/efinix/arith_map.v11
-rw-r--r--techlibs/efinix/cells_map.v1
-rw-r--r--techlibs/gowin/arith_map.v8
-rw-r--r--techlibs/gowin/cells_map.v1
-rw-r--r--techlibs/greenpak4/cells_map.v2
-rw-r--r--techlibs/ice40/Makefile.inc1
-rw-r--r--techlibs/ice40/arith_map.v8
-rw-r--r--techlibs/ice40/cells_map.v32
-rw-r--r--techlibs/ice40/cells_sim.v168
-rw-r--r--techlibs/ice40/ff_map.v28
-rw-r--r--techlibs/ice40/synth_ice40.cc59
-rw-r--r--techlibs/intel/arria10gx/cells_arith.v6
-rw-r--r--techlibs/intel/arria10gx/cells_map.v1
-rw-r--r--techlibs/intel/cyclone10lp/cells_arith.v6
-rw-r--r--techlibs/intel/cyclone10lp/cells_map.v1
-rw-r--r--techlibs/intel/cycloneiv/cells_arith.v6
-rw-r--r--techlibs/intel/cycloneiv/cells_map.v1
-rw-r--r--techlibs/intel/cycloneive/arith_map.v6
-rw-r--r--techlibs/intel/cycloneive/cells_map.v1
-rw-r--r--techlibs/intel/cyclonev/cells_arith.v6
-rw-r--r--techlibs/intel/cyclonev/cells_map.v1
-rw-r--r--techlibs/intel/max10/cells_arith.v6
-rw-r--r--techlibs/intel/max10/cells_map.v1
-rw-r--r--techlibs/intel_alm/common/alm_map.v1
-rw-r--r--techlibs/intel_alm/common/arith_alm_map.v7
-rw-r--r--techlibs/intel_alm/synth_intel_alm.cc1
-rw-r--r--techlibs/sf2/cells_map.v1
-rw-r--r--techlibs/xilinx/Makefile.inc2
-rw-r--r--techlibs/xilinx/abc9_map.v786
-rw-r--r--techlibs/xilinx/abc9_model.v171
-rw-r--r--techlibs/xilinx/abc9_unmap.v61
-rw-r--r--techlibs/xilinx/arith_map.v23
-rw-r--r--techlibs/xilinx/cells_map.v6
-rw-r--r--techlibs/xilinx/cells_sim.v300
-rw-r--r--techlibs/xilinx/lut_map.v1
-rw-r--r--techlibs/xilinx/mux_map.v3
-rw-r--r--techlibs/xilinx/synth_xilinx.cc27
-rw-r--r--tests/arch/ice40/mux.ys3
-rw-r--r--tests/arch/xilinx/abc9_dff.ys89
-rw-r--r--tests/arch/xilinx/abc9_map.ys91
-rw-r--r--tests/arch/xilinx/macc.v12
-rw-r--r--tests/arch/xilinx/macc.ys4
-rw-r--r--tests/arch/xilinx/mux.ys6
-rw-r--r--tests/arch/xilinx/pmgen_xilinx_srl.ys2
-rw-r--r--tests/arch/xilinx/xilinx_srl.v2
-rw-r--r--tests/fsm/generate.py8
-rw-r--r--tests/opt/bug1758.ys21
-rw-r--r--tests/opt/opt_clean_init.ys13
-rw-r--r--tests/opt/opt_expr_alu.ys3
-rw-r--r--tests/opt/opt_expr_and.ys85
-rw-r--r--tests/opt/opt_expr_consumex.ys35
-rw-r--r--tests/opt/opt_expr_or.ys85
-rw-r--r--tests/opt/opt_expr_xnor.ys131
-rw-r--r--tests/opt/opt_expr_xor.ys88
-rw-r--r--tests/simple/constmuldivmod.v42
-rw-r--r--tests/simple_abc9/abc9.box3
-rw-r--r--tests/simple_abc9/abc9.v2
-rwxr-xr-xtests/simple_abc9/run-test.sh2
-rw-r--r--tests/svtypes/logic_rom.sv6
-rw-r--r--tests/svtypes/logic_rom.ys3
-rw-r--r--tests/various/abc9.ys38
-rw-r--r--tests/various/attrib07_func_call.v2
-rw-r--r--tests/various/constmsk_testmap.v2
-rw-r--r--tests/various/printattr.ys14
-rw-r--r--tests/various/shregmap.v4
-rw-r--r--tests/various/xaiger.ys13
-rw-r--r--tests/verilog/.gitignore3
-rw-r--r--tests/verilog/bug2037.ys58
-rw-r--r--tests/verilog/bug2042-sv.ys59
-rw-r--r--tests/verilog/bug2042.ys11
-rwxr-xr-xtests/verilog/run-test.sh20
-rw-r--r--tests/verilog/task_attr.ys28
-rw-r--r--tests/verilog/upto.ys4
154 files changed, 4094 insertions, 2453 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 3b36c3182..638ce558b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -66,6 +66,7 @@ Yosys 0.9 .. Yosys 0.9-dev
- Added "design -delete"
- Added "select -unset"
- Use YosysHQ/abc instead of upstream berkeley-abc/abc
+ - Added $divfloor and $modfloor cells
Yosys 0.8 .. Yosys 0.9
----------------------
diff --git a/Makefile b/Makefile
index a481dd92b..e589b2b67 100644
--- a/Makefile
+++ b/Makefile
@@ -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; \
fi
# 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; }; \
echo "Pulling ABC from $(ABCURL):"; set -x; \
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/rpc && bash run-test.sh
+cd tests/memfile && bash run-test.sh
+ +cd tests/verilog && bash run-test.sh
@echo ""
@echo " Passed \"make test\"."
@echo ""
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index 1fb7210cb..6b910eecd 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -76,9 +76,11 @@ void aiger_encode(std::ostream &f, int x)
struct XAigerWriter
{
+ Design *design;
Module *module;
SigMap sigmap;
+ dict<SigBit, State> init_map;
pool<SigBit> input_bits, output_bits;
dict<SigBit, SigBit> not_map, alias_map;
dict<SigBit, pair<SigBit, SigBit>> and_map;
@@ -137,7 +139,7 @@ struct XAigerWriter
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> unused_bits;
@@ -157,7 +159,8 @@ struct XAigerWriter
if (wire->get_bool_attribute(ID::keep))
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++)
{
SigBit wirebit(wire, i);
@@ -174,17 +177,27 @@ struct XAigerWriter
undriven_bits.insert(bit);
unused_bits.insert(bit);
- bool scc = wire->attributes.count(ID::abc9_scc);
- if (wire->port_input || scc)
+ bool keep = wire->get_bool_attribute(ID::abc9_keep);
+ if (wire->port_input || keep)
input_bits.insert(bit);
- bool keep = wire->get_bool_attribute(ID::keep);
- if (wire->port_output || keep || scc) {
+ keep = keep || wire->get_bool_attribute(ID::keep);
+ if (wire->port_output || keep) {
if (bit != wirebit)
alias_map[wirebit] = bit;
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;
@@ -212,10 +225,7 @@ struct XAigerWriter
continue;
}
- if (cell->type == ID($__ABC9_FF_) &&
- // The presence of an abc9_mergeability attribute indicates
- // that we do want to pass this flop to ABC
- cell->attributes.count(ID::abc9_mergeability))
+ if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_)) && !cell->get_bool_attribute(ID::abc9_keep))
{
SigBit D = sigmap(cell->getPort(ID::D).as_bit());
SigBit Q = sigmap(cell->getPort(ID::Q).as_bit());
@@ -231,31 +241,29 @@ struct XAigerWriter
continue;
}
- RTLIL::Module* inst_module = module->design->module(cell->type);
- if (inst_module) {
- IdString derived_type = inst_module->derive(module->design, cell->parameters);
- inst_module = module->design->module(derived_type);
- log_assert(inst_module);
-
+ RTLIL::Module* inst_module = design->module(cell->type);
+ if (inst_module && inst_module->get_blackbox_attribute()) {
bool abc9_flop = false;
- if (!cell->has_keep_attr()) {
- auto it = cell->attributes.find(ID::abc9_box_seq);
- if (it != cell->attributes.end()) {
- int abc9_box_seq = it->second.as_int();
- if (GetSize(box_list) <= abc9_box_seq)
- box_list.resize(abc9_box_seq+1);
- box_list[abc9_box_seq] = cell;
- // Only flop boxes may have arrival times
- // (all others are combinatorial)
- abc9_flop = inst_module->get_bool_attribute(ID::abc9_flop);
- if (!abc9_flop)
- continue;
- }
+
+ auto it = cell->attributes.find(ID::abc9_box_seq);
+ if (it != cell->attributes.end()) {
+ log_assert(!cell->has_keep_attr());
+ log_assert(cell->parameters.empty());
+ int abc9_box_seq = it->second.as_int();
+ if (GetSize(box_list) <= abc9_box_seq)
+ box_list.resize(abc9_box_seq+1);
+ box_list[abc9_box_seq] = cell;
+ // Only flop boxes may have arrival times
+ // (all others are combinatorial)
+ 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);
- auto &t = timing.at(derived_type).arrival;
+ auto &t = timing.at(inst_module->name).arrival;
for (const auto &conn : cell->connections()) {
auto port_wire = inst_module->wire(conn.first);
if (!port_wire->port_output)
@@ -269,7 +277,7 @@ struct XAigerWriter
#ifndef NDEBUG
if (ys_debug(1)) {
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);
}
#endif
@@ -280,10 +288,6 @@ struct XAigerWriter
if (abc9_flop)
continue;
}
- else {
- if (cell->type == ID($__ABC9_DELAY))
- log_error("Cell type '%s' not recognised. Check that '+/abc9_model.v' has been read.\n", cell->type.c_str());
- }
bool cell_known = inst_module || cell->known();
for (const auto &c : cell->connections()) {
@@ -317,9 +321,9 @@ struct XAigerWriter
for (auto cell : box_list) {
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->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);
if (r.second) {
@@ -383,27 +387,6 @@ struct XAigerWriter
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)
@@ -419,16 +402,14 @@ struct XAigerWriter
undriven_bits.erase(bit);
}
- if (holes_mode) {
- struct sort_by_port_id {
- bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const {
- return a.wire->port_id < b.wire->port_id ||
- (a.wire->port_id == b.wire->port_id && a.offset < b.offset);
- }
- };
- input_bits.sort(sort_by_port_id());
- output_bits.sort(sort_by_port_id());
- }
+ struct sort_by_port_id {
+ bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const {
+ return a.wire->port_id < b.wire->port_id ||
+ (a.wire->port_id == b.wire->port_id && a.offset < b.offset);
+ }
+ };
+ input_bits.sort(sort_by_port_id());
+ output_bits.sort(sort_by_port_id());
aig_map[State::S0] = 0;
aig_map[State::S1] = 1;
@@ -589,17 +570,14 @@ struct XAigerWriter
int box_count = 0;
for (auto cell : box_list) {
log_assert(cell);
+ log_assert(cell->parameters.empty());
- RTLIL::Module* box_module = module->design->module(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 r = cell_cache.insert(cell->type);
auto &v = r.first->second;
if (r.second) {
+ RTLIL::Module* box_module = design->module(cell->type);
+ log_assert(box_module);
+
int box_inputs = 0, box_outputs = 0;
for (auto port_name : box_module->ports) {
RTLIL::Wire *w = box_module->wire(port_name);
@@ -610,11 +588,6 @@ struct XAigerWriter
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<1>(v) = box_outputs;
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);
write_s_buffer(ff_bits.size());
+ dict<SigSpec, int> clk_to_mergeability;
for (const auto &i : ff_bits) {
const SigBit &d = i.first;
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);
write_r_buffer(mergeability);
- Const init = cell->attributes.at(ID::abc9_init, State::Sx);
- log_assert(GetSize(init) == 1);
+ SigBit Q = sigmap(cell->getPort(ID::Q));
+ 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)
write_s_buffer(1);
else if (init == State::S0)
write_s_buffer(0);
else {
log_assert(init == State::Sx);
- write_s_buffer(0);
+ write_s_buffer(2);
}
// 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(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) {
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*/);
f << "a";
@@ -704,10 +687,10 @@ struct XAigerWriter
f << stringf("Generated by %s\n", yosys_version_str);
- module->design->scratchpad_set_int("write_xaiger.num_ands", and_map.size());
- module->design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size());
- module->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_ands", and_map.size());
+ design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size());
+ design->scratchpad_set_int("write_xaiger.num_inputs", input_bits.size());
+ design->scratchpad_set_int("write_xaiger.num_outputs", output_bits.size());
}
void write_map(std::ostream &f)
@@ -761,10 +744,10 @@ struct XAigerBackend : public Backend {
log(" write_xaiger [options] [filename]\n");
log("\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("non (* abc9_box_id *) cells will be converted into psuedo-inputs and\n");
- log("pseudo-outputs. Whitebox contents will be taken from the '<module-name>$holes'\n");
- log("module, if it exists.\n");
+ log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, (optionally\n");
+ log("$_DFF_N_, $_DFF_P_), or non (* abc9_box *) cells will be converted into psuedo-\n");
+ log("inputs and pseudo-outputs. Whitebox contents will be taken from the equivalent\n");
+ log("module in the '$abc9_holes' design, if it exists.\n");
log("\n");
log(" -ascii\n");
log(" write ASCII version of AIGER format\n");
@@ -772,10 +755,13 @@ struct XAigerBackend : public Backend {
log(" -map <filename>\n");
log(" write an extra file with port and box symbols\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
{
- bool ascii_mode = false;
+ bool ascii_mode = false, dff_mode = false;
std::string map_filename;
log_header(design, "Executing XAIGER backend.\n");
@@ -791,6 +777,10 @@ struct XAigerBackend : public Backend {
map_filename = args[++argidx];
continue;
}
+ if (args[argidx] == "-dff") {
+ dff_mode = true;
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx, !ascii_mode);
@@ -808,7 +798,7 @@ struct XAigerBackend : public Backend {
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));
- XAigerWriter writer(top_module);
+ XAigerWriter writer(top_module, dff_mode);
writer.write_aiger(*f, ascii_mode);
if (!map_filename.empty()) {
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index 14c8484e8..2816d3246 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -266,20 +266,26 @@ struct BtorWorker
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;
if (cell->type == ID($div)) btor_op = "div";
+ // "rem" = truncating modulo
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());
int width = GetSize(cell->getPort(ID::Y));
width = std::max(width, GetSize(cell->getPort(ID::A)));
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_b = get_sig_nid(cell->getPort(ID::B), width, b_signed);
diff --git a/backends/btor/test_cells.sh b/backends/btor/test_cells.sh
index e0f1a0514..3f077201a 100644
--- a/backends/btor/test_cells.sh
+++ b/backends/btor/test_cells.sh
@@ -6,7 +6,7 @@ rm -rf test_cells.tmp
mkdir -p 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
../../../yosys -p "
diff --git a/backends/cxxrtl/cxxrtl.cc b/backends/cxxrtl/cxxrtl.cc
index f3ed3f623..0cceecbba 100644
--- a/backends/cxxrtl/cxxrtl.cc
+++ b/backends/cxxrtl/cxxrtl.cc
@@ -513,7 +513,6 @@ struct CxxrtlWorker {
bool elide_public = false;
bool localize_internal = false;
bool localize_public = false;
- bool run_opt_clean_purge = false;
bool run_proc_flatten = false;
bool max_opt_level = false;
@@ -2009,6 +2008,7 @@ struct CxxrtlWorker {
log("Module `%s' contains feedback arcs through wires:\n", log_id(module));
for (auto wire : feedback_wires)
log(" %s\n", log_id(wire));
+ log("\n");
}
for (auto wire : module->wires()) {
@@ -2040,20 +2040,20 @@ struct CxxrtlWorker {
log("Module `%s' contains buffered combinatorial wires:\n", log_id(module));
for (auto wire : buffered_wires)
log(" %s\n", log_id(wire));
+ log("\n");
}
eval_converges[module] = feedback_wires.empty() && buffered_wires.empty();
}
if (has_feedback_arcs || has_buffered_wires) {
// 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.
const char *why_pessimistic = nullptr;
if (has_feedback_arcs)
why_pessimistic = "feedback wires";
else if (has_buffered_wires)
why_pessimistic = "buffered combinatorial wires";
- log("\n");
log_warning("Design contains %s, which require delta cycles during evaluation.\n", why_pessimistic);
if (!max_opt_level)
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)
{
+ bool did_anything = false;
bool has_sync_init, has_packed_mem;
log_push();
check_design(design, has_sync_init, has_packed_mem);
if (run_proc_flatten) {
Pass::call(design, "proc");
Pass::call(design, "flatten");
+ did_anything = true;
} else if (has_sync_init) {
// 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.)
Pass::call(design, "proc_prune");
Pass::call(design, "proc_clean");
Pass::call(design, "proc_init");
+ did_anything = true;
}
- if (has_packed_mem)
+ if (has_packed_mem) {
Pass::call(design, "memory_unpack");
+ did_anything = true;
+ }
// Recheck the design if it was modified.
if (has_sync_init || has_packed_mem)
check_design(design, 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();
+ if (did_anything)
+ log_spacer();
analyze_design(design);
}
};
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") { }
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("\n");
log(" -O5\n");
- log(" like -O4, and run `opt_clean -purge` first.\n");
- log("\n");
- log(" -O6\n");
- log(" like -O5, and run `proc; flatten` first.\n");
+ log(" like -O4, and run `proc; flatten` first.\n");
log("\n");
}
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);
switch (opt_level) {
- case 6:
+ // the highest level here must match DEFAULT_OPT_LEVEL
+ case 5:
worker.max_opt_level = true;
worker.run_proc_flatten = true;
YS_FALLTHROUGH
- case 5:
- worker.run_opt_clean_purge = true;
- YS_FALLTHROUGH
case 4:
worker.localize_public = true;
YS_FALLTHROUGH
diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc
index f6dae1d8c..b1d8500bb 100644
--- a/backends/firrtl/firrtl.cc
+++ b/backends/firrtl/firrtl.cc
@@ -392,7 +392,34 @@ struct FirrtlWorker
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);
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);
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));
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.
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)) {
primop = "neg";
firrtl_is_signed = true; // Result of "neg" is signed (an SInt).
@@ -494,7 +521,7 @@ struct FirrtlWorker
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($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.
// 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) {
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_width = a_width;
} else if (cell->type == ID($mod)) {
+ // "rem" = truncating modulo
primop = "rem";
firrtl_width = min(a_width, b_width);
- } else if (cell->type == ID($and)) {
+ } else if (cell->type.in(ID($and), ID($_AND_))) {
primop = "and";
always_uint = true;
firrtl_width = max(a_width, b_width);
}
- else if (cell->type == ID($or) ) {
+ else if (cell->type.in(ID($or), ID($_OR_))) {
primop = "or";
always_uint = true;
firrtl_width = max(a_width, b_width);
}
- else if (cell->type == ID($xor)) {
+ else if (cell->type.in(ID($xor), ID($_XOR_))) {
primop = "xor";
always_uint = true;
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 + ")";
}
@@ -723,9 +752,10 @@ struct FirrtlWorker
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 b_expr = make_expr(cell->getPort(ID::B));
string s_expr = make_expr(cell->getPort(ID::S));
@@ -1076,6 +1106,18 @@ struct FirrtlWorker
for (auto str : wire_exprs)
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();
}
};
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index 3e67e55f2..26f17bcb3 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -590,7 +590,17 @@ struct Smt2Worker
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($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');
+ // "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)) &&
2*GetSize(cell->getPort(ID::A).chunks()) < GetSize(cell->getPort(ID::A))) {
diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py
index d3015b066..03f001bfd 100644
--- a/backends/smt2/smtbmc.py
+++ b/backends/smt2/smtbmc.py
@@ -1511,7 +1511,7 @@ else: # not tempind, covermode
smt_assert_consequent(get_constr_expr(constr_assumes, i))
print_msg("Re-solving with appended steps..")
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"
break
print_anyconsts(step)
@@ -1548,7 +1548,7 @@ else: # not tempind, covermode
break
smt_pop()
- if not retstatus:
+ if retstatus == "FAILED" or retstatus == "PREUNSAT":
break
else: # gentrace
@@ -1557,8 +1557,9 @@ else: # not tempind, covermode
smt_assert(get_constr_expr(constr_asserts, i))
print_msg("Solving for step %d.." % (last_check_step))
- if smt_check_sat() != "sat":
- print("%s No solution found!" % smt.timestamp())
+ status = smt_check_sat()
+ if status != "sat":
+ print("%s No solution found! (%s)" % (smt.timestamp(), status))
retstatus = "FAILED"
break
@@ -1568,7 +1569,7 @@ else: # not tempind, covermode
step += step_size
- if gentrace and retstatus:
+ if gentrace and retstatus == "PASSED":
print_anyconsts(0)
write_trace(0, num_steps, '%')
diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py
index 69f59df79..9f7c8c6d9 100644
--- a/backends/smt2/smtio.py
+++ b/backends/smt2/smtio.py
@@ -121,6 +121,7 @@ class SmtIo:
self.logic_bv = True
self.logic_dt = False
self.forall = False
+ self.timeout = 0
self.produce_models = True
self.smt2cache = [list()]
self.p = None
@@ -135,6 +136,7 @@ class SmtIo:
self.debug_file = opts.debug_file
self.dummy_file = opts.dummy_file
self.timeinfo = opts.timeinfo
+ self.timeout = opts.timeout
self.unroll = opts.unroll
self.noincr = opts.noincr
self.info_stmts = opts.info_stmts
@@ -147,6 +149,7 @@ class SmtIo:
self.debug_file = None
self.dummy_file = None
self.timeinfo = os.name != "nt"
+ self.timeout = 0
self.unroll = False
self.noincr = False
self.info_stmts = list()
@@ -172,22 +175,32 @@ class SmtIo:
self.unroll = False
if self.solver == "yices":
- if self.noincr:
+ if self.noincr or self.forall:
self.popen_vargs = ['yices-smt2'] + self.solver_opts
else:
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":
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.noincr:
self.popen_vargs = ['cvc4', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
else:
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":
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.noincr:
@@ -195,6 +208,9 @@ class SmtIo:
else:
self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts
self.unroll = True
+ if self.timeout != 0:
+ print('timeout option is not supported for boolector.')
+ sys.exit(1)
if self.solver == "abc":
if len(self.solver_opts) > 0:
@@ -204,6 +220,9 @@ class SmtIo:
self.logic_ax = False
self.unroll = True
self.noincr = True
+ if self.timeout != 0:
+ print('timeout option is not supported for abc.')
+ sys.exit(1)
if self.solver == "dummy":
assert self.dummy_file is not None
@@ -232,12 +251,16 @@ class SmtIo:
if self.logic_uf: self.logic += "UF"
if self.logic_bv: self.logic += "BV"
if self.logic_dt: self.logic = "ALL"
+ if self.solver == "yices" and self.forall: self.logic = "BV"
self.setup_done = True
for stmt in self.info_stmts:
self.write(stmt)
+ if self.forall and self.solver == "yices":
+ self.write("(set-option :yices-ef-max-iters 1000000000)")
+
if self.produce_models:
self.write("(set-option :produce-models true)")
@@ -706,7 +729,7 @@ class SmtIo:
if self.forall:
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))
result = self.read()
else:
@@ -717,7 +740,7 @@ class SmtIo:
print("(check-sat)", file=self.debug_file)
self.debug_file.flush()
- if result not in ["sat", "unsat"]:
+ if result not in ["sat", "unsat", "unknown", "timeout", "interrupted"]:
if result == "":
print("%s Unexpected EOF response from solver." % (self.timestamp()), flush=True)
else:
@@ -927,7 +950,7 @@ class SmtIo:
class SmtOpts:
def __init__(self):
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_opts = list()
self.debug_print = False
@@ -936,6 +959,7 @@ class SmtOpts:
self.unroll = False
self.noincr = False
self.timeinfo = os.name != "nt"
+ self.timeout = 0
self.logic = None
self.info_stmts = list()
self.nocomments = False
@@ -945,6 +969,8 @@ class SmtOpts:
self.solver = a
elif o == "-S":
self.solver_opts.append(a)
+ elif o == "--timeout":
+ self.timeout = int(a)
elif o == "-v":
self.debug_print = True
elif o == "--unroll":
@@ -976,6 +1002,9 @@ class SmtOpts:
-S <opt>
pass <opt> as command line argument to the solver
+ --timeout <value>
+ set the solver timeout to the specified value (in seconds).
+
--logic <smt2_logic>
use the specified SMT2 logic (e.g. QF_AUFBV)
diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc
index 7113ebc97..2fc7099f4 100644
--- a/backends/smv/smv.cc
+++ b/backends/smv/smv.cc
@@ -358,7 +358,8 @@ struct SmvWorker
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 = max(width_y, GetSize(cell->getPort(ID::A)));
@@ -366,7 +367,7 @@ struct SmvWorker
string expr_a, expr_b, 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())
{
diff --git a/backends/smv/test_cells.sh b/backends/smv/test_cells.sh
index 63de465c0..145b9c33b 100644
--- a/backends/smv/test_cells.sh
+++ b/backends/smv/test_cells.sh
@@ -7,8 +7,8 @@ mkdir -p test_cells.tmp
cd test_cells.tmp
# don't test $mul to reduce runtime
-# don't test $div and $mod 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'
+# 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 /$divfloor /$modfloor'
cat > template.txt << "EOT"
%module main
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index 11b2ae10f..4f44a053a 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -740,6 +740,95 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
#undef HANDLE_UNIOP
#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))
{
f << stringf("%s" "assign ", indent.c_str());
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index 6fda92d73..d25587e48 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -454,6 +454,14 @@ void AigerReader::parse_xaiger()
for (unsigned i = 0; i < flopNum; i++)
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') {
parse_xaiger_literal(f);
f >> s;
@@ -767,6 +775,7 @@ void AigerReader::post_process()
}
}
+ dict<int, Wire*> mergeability_to_clock;
for (uint32_t i = 0; i < flopNum; i++) {
RTLIL::Wire *d = outputs[outputs.size() - flopNum + i];
log_assert(d);
@@ -778,10 +787,9 @@ void AigerReader::post_process()
log_assert(q->port_input);
q->port_input = false;
- auto ff = module->addCell(NEW_ID, ID($__ABC9_FF_));
- ff->setPort(ID::D, d);
- ff->setPort(ID::Q, q);
+ Cell* ff = module->addFfGate(NEW_ID, d, q);
ff->attributes[ID::abc9_mergeability] = mergeability[i];
+ q->attributes[ID::init] = initial_state[i];
}
dict<RTLIL::IdString, std::pair<int,int>> wideports_cache;
diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h
index 46ac81212..251a24977 100644
--- a/frontends/aiger/aigerparse.h
+++ b/frontends/aiger/aigerparse.h
@@ -45,7 +45,7 @@ struct AigerReader
std::vector<RTLIL::Wire*> outputs;
std::vector<RTLIL::Wire*> bad_properties;
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);
void parse_aiger();
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 83f34c9e1..fa16b2f2f 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -1057,7 +1057,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (!range_valid)
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);
RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1);
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index e8ac4b2f2..e88331621 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -1256,7 +1256,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
if (old_range_valid != range_valid)
did_something = true;
- if (range_valid && range_left >= 0 && range_right > range_left) {
+ if (range_valid && range_right > range_left) {
int tmp = range_right;
range_right = range_left;
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_left = children[0]->range_left;
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 {
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'
- if (type == AST_MEMORY && (get_bool_attribute(ID::mem2reg) || (flags & AstNode::MEM2REG_FL_ALL) || !is_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 || is_logic)))
mem2reg_candidates[this] |= AstNode::MEM2REG_FL_FORCED;
if (type == AST_MODULE && get_bool_attribute(ID::mem2reg))
diff --git a/frontends/ilang/ilang_lexer.l b/frontends/ilang/ilang_lexer.l
index 62f53d18e..3362ed641 100644
--- a/frontends/ilang/ilang_lexer.l
+++ b/frontends/ilang/ilang_lexer.l
@@ -91,8 +91,10 @@ USING_YOSYS_NAMESPACE
[0-9]+'[01xzm-]* { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_VALUE; }
-?[0-9]+ {
char *end = nullptr;
+ errno = 0;
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
if (value < INT_MIN || value > INT_MAX)
return TOK_INVALID; // literal out of range of int (relevant mostly for LP64 platforms)
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index fe4bda68e..cb0368fd5 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -974,6 +974,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
module->memories[memory->name] = memory;
int number_of_bits = net->Size();
+ number_of_bits = 1 << ceil_log2(number_of_bits);
int bits_in_word = number_of_bits;
FOREACH_PORTREF_OF_NET(net, si, pr) {
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 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++)
{
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 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++)
{
RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)};
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 6217b5728..e6fa6361e 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -48,16 +48,18 @@ USING_YOSYS_NAMESPACE
using namespace AST;
using namespace VERILOG_FRONTEND;
+#define YYSTYPE FRONTEND_VERILOG_YYSTYPE
+#define YYLTYPE FRONTEND_VERILOG_YYLTYPE
+
YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND {
std::vector<std::string> fn_stack;
std::vector<int> ln_stack;
+ YYLTYPE real_location;
+ YYLTYPE old_location;
}
YOSYS_NAMESPACE_END
-#define YYSTYPE FRONTEND_VERILOG_YYSTYPE
-#define YYLTYPE FRONTEND_VERILOG_YYLTYPE
-
#define SV_KEYWORD(_tok) \
if (sv_mode) return _tok; \
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) \
result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
-YYLTYPE real_location;
-YYLTYPE old_location;
-
#define YY_USER_ACTION \
old_location = real_location; \
real_location.first_line = real_location.last_line; \
@@ -128,7 +127,9 @@ static bool isUserType(std::string &s)
%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]* {
fn_stack.push_back(current_filename);
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index e72d09524..c4867356c 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -886,7 +886,19 @@ task_func_port:
albuf = $1;
astbuf1 = $2;
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 behavioral_stmt |
@@ -2299,49 +2311,56 @@ assert_property:
};
simple_behavioral_stmt:
- lvalue '=' delay expr {
- AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4);
+ attr lvalue '=' delay expr {
+ AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $5);
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 {
- AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_ADD, $1->clone(), AstNode::mkconst_int(1, true)));
+ attr lvalue TOK_INCREMENT {
+ 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);
- SET_AST_NODE_LOC(node, @1, @2);
+ SET_AST_NODE_LOC(node, @2, @3);
+ append_attr(node, $1);
} |
- lvalue TOK_DECREMENT {
- AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_SUB, $1->clone(), AstNode::mkconst_int(1, true)));
+ attr lvalue TOK_DECREMENT {
+ 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);
- SET_AST_NODE_LOC(node, @1, @2);
+ SET_AST_NODE_LOC(node, @2, @3);
+ append_attr(node, $1);
} |
- lvalue OP_LE delay expr {
- AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4);
+ attr lvalue OP_LE delay expr {
+ AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5);
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
behavioral_stmt:
defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl |
non_opt_delay behavioral_stmt |
- simple_behavioral_stmt ';' | ';' |
- hierarchical_id attr {
+ simple_behavioral_stmt ';' |
+ attr ';' {
+ free_attr($1);
+ } |
+ attr hierarchical_id {
AstNode *node = new AstNode(AST_TCALL);
- node->str = *$1;
- delete $1;
+ node->str = *$2;
+ delete $2;
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
- append_attr(node, $2);
+ append_attr(node, $1);
} opt_arg_list ';'{
ast_stack.pop_back();
} |
- TOK_MSG_TASKS attr {
+ attr TOK_MSG_TASKS {
AstNode *node = new AstNode(AST_TCALL);
- node->str = *$1;
- delete $1;
+ node->str = *$2;
+ delete $2;
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
- append_attr(node, $2);
+ append_attr(node, $1);
} opt_arg_list ';'{
ast_stack.pop_back();
} |
@@ -2438,8 +2457,6 @@ behavioral_stmt:
ast_stack.pop_back();
};
- ;
-
unique_case_attr:
/* empty */ {
$$ = false;
@@ -2534,7 +2551,7 @@ gen_case_item:
} case_select {
case_type_stack.push_back(0);
SET_AST_NODE_LOC(ast_stack.back(), @2, @2);
- } gen_stmt_or_null {
+ } gen_stmt_block {
case_type_stack.pop_back();
ast_stack.pop_back();
};
@@ -2626,7 +2643,10 @@ module_gen_body:
/* empty */;
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
gen_stmt:
@@ -2648,7 +2668,7 @@ gen_stmt:
AstNode *block = new AstNode(AST_GENBLOCK);
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
- } gen_stmt_or_null {
+ } gen_stmt_block {
ast_stack.pop_back();
} opt_gen_else {
SET_AST_NODE_LOC(ast_stack.back(), @1, @7);
@@ -2698,11 +2718,8 @@ gen_stmt_block:
ast_stack.pop_back();
};
-gen_stmt_or_null:
- gen_stmt_block | ';';
-
opt_gen_else:
- TOK_ELSE gen_stmt_or_null | /* empty */ %prec FAKE_THEN;
+ TOK_ELSE gen_stmt_block | /* empty */ %prec FAKE_THEN;
expr:
basic_expr {
diff --git a/kernel/calc.cc b/kernel/calc.cc
index 4a4840771..ae18809d3 100644
--- a/kernel/calc.cc
+++ b/kernel/calc.cc
@@ -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));
}
+// truncating division
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;
@@ -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));
}
+// truncating modulo
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;
@@ -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));
}
+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)
{
int undef_bit_pos = -1;
diff --git a/kernel/celledges.cc b/kernel/celledges.cc
index 54e0168e2..314e7c77e 100644
--- a/kernel/celledges.cc
+++ b/kernel/celledges.cc
@@ -187,7 +187,7 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL
return true;
}
- // FIXME: $mul $div $mod $slice $concat
+ // FIXME: $mul $div $mod $divfloor $modfloor $slice $concat
// FIXME: $lut $sop $alu $lcu $macc $fa
return false;
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index 450865ce9..db54436cb 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -114,7 +114,7 @@ struct CellTypes
ID($and), ID($or), ID($xor), ID($xnor),
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($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)
};
@@ -304,6 +304,8 @@ struct CellTypes
HANDLE_CELL_TYPE(mul)
HANDLE_CELL_TYPE(div)
HANDLE_CELL_TYPE(mod)
+ HANDLE_CELL_TYPE(divfloor)
+ HANDLE_CELL_TYPE(modfloor)
HANDLE_CELL_TYPE(pow)
HANDLE_CELL_TYPE(pos)
HANDLE_CELL_TYPE(neg)
diff --git a/kernel/constids.inc b/kernel/constids.inc
index 6b40a5908..383d7c615 100644
--- a/kernel/constids.inc
+++ b/kernel/constids.inc
@@ -2,13 +2,12 @@ X(A)
X(abc9_box)
X(abc9_box_id)
X(abc9_box_seq)
+X(abc9_bypass)
X(abc9_carry)
X(abc9_flop)
-X(abc9_holes)
-X(abc9_init)
+X(abc9_keep)
X(abc9_lut)
X(abc9_mergeability)
-X(abc9_scc)
X(abc9_scc_id)
X(abcgroup)
X(ABITS)
@@ -80,6 +79,8 @@ X(equiv_merged)
X(equiv_region)
X(extract_order)
X(F)
+X(force_downto)
+X(force_upto)
X(fsm_encoding)
X(fsm_export)
X(FULL)
@@ -170,6 +171,7 @@ X(techmap_autopurge)
X(_TECHMAP_BITS_CONNMAP_)
X(_TECHMAP_CELLTYPE_)
X(techmap_celltype)
+X(_TECHMAP_FAIL_)
X(techmap_maccmap)
X(_TECHMAP_REPLACE_)
X(techmap_simplemap)
diff --git a/kernel/hashlib.h b/kernel/hashlib.h
index 592d6e577..5c87b55f5 100644
--- a/kernel/hashlib.h
+++ b/kernel/hashlib.h
@@ -207,6 +207,7 @@ class dict
entry_t() { }
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) { }
+ bool operator<(const entry_t &other) const { return udata.first < other.udata.first; }
};
std::vector<int> hashtable;
@@ -615,6 +616,15 @@ public:
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); }
size_t size() const { return entries.size(); }
bool empty() const { return entries.empty(); }
diff --git a/kernel/log.cc b/kernel/log.cc
index a21ba480a..104bee078 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -42,7 +42,7 @@ std::vector<FILE*> log_files;
std::vector<std::ostream*> log_streams;
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<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;
int log_warnings_count = 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());
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++;
linebuffer.clear();
@@ -256,7 +256,7 @@ static void logv_warning_with_prefix(const char *prefix,
bool warning_match = false;
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++;
warning_match = true;
}
@@ -349,7 +349,7 @@ static void logv_error_with_prefix(const char *prefix,
log_error_atexit();
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++;
if (check_expected_logs)
@@ -672,31 +672,31 @@ void log_check_expected()
for (auto &item : log_expect_warning) {
if (item.second.current_count == 0) {
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) {
log_warn_regexes.clear();
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) {
if (item.second.current_count == 0) {
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) {
log_warn_regexes.clear();
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)
if (item.second.current_count == item.second.expected_count) {
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
throw 0;
#elif defined(_MSC_VER)
@@ -707,7 +707,7 @@ void log_check_expected()
} else {
display_error_log_msg = false;
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());
}
}
diff --git a/kernel/log.h b/kernel/log.h
index dee5d44d7..516744b50 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -86,7 +86,7 @@ YOSYS_NAMESPACE_BEGIN
# endif
# if __has_builtin(__builtin_debugtrap)
# define YS_DEBUGTRAP __builtin_debugtrap()
-# elif defined(__unix__)
+# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
# define YS_DEBUGTRAP raise(SIGTRAP)
# else
# define YS_DEBUGTRAP do {} while(0)
@@ -97,11 +97,11 @@ YOSYS_NAMESPACE_BEGIN
// if a debugger is attached, and does nothing otherwise.
#if defined(_WIN32)
# 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,
// debuggers will stop when SIGTRAP is raised, even if the action is set to ignore.
# 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)
#else
# define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0)
@@ -202,19 +202,16 @@ void log_flush();
struct LogExpectedItem
{
- LogExpectedItem(std::string pattern, int expected) :
- expected_count(expected),
- current_count(0),
- pattern(pattern)
- {
- }
+ LogExpectedItem(const YS_REGEX_TYPE &pat, int expected) :
+ pattern(pat), expected_count(expected), current_count(0) {}
+ LogExpectedItem() : expected_count(0), current_count(0) {}
+ YS_REGEX_TYPE pattern;
int expected_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();
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 196e301b6..ca4201b53 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -948,7 +948,7 @@ namespace {
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::B_SIGNED);
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(Div, max(sig_a.size(), sig_b.size()), ID($div))
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(LogicOr, 1, ID($logic_or))
#undef DEF_METHOD
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 11c45bbec..8228523d5 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -150,9 +150,6 @@ namespace RTLIL
if (!p[0])
return 0;
- log_assert(p[0] == '$' || p[0] == '\\');
- log_assert(p[1] != 0);
-
auto it = global_id_index_.find((char*)p);
if (it != global_id_index_.end()) {
#ifndef YOSYS_NO_IDS_REFCNT
@@ -165,6 +162,11 @@ namespace RTLIL
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
if (global_free_idx_list_.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.
- bool operator==(const std::string &rhs) const { return 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 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; }
@@ -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_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_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_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, int index);
SigBit(const RTLIL::SigSpec &sig);
- SigBit(const RTLIL::SigBit &sigbit);
+ SigBit(const RTLIL::SigBit &sigbit) = default;
RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default;
bool operator <(const RTLIL::SigBit &other) const;
@@ -1134,8 +1138,14 @@ public:
return design->selected_member(name, member->name);
}
- RTLIL::Wire* wire(RTLIL::IdString id) { return wires_.count(id) ? wires_.at(id) : nullptr; }
- RTLIL::Cell* cell(RTLIL::IdString id) { return cells_.count(id) ? cells_.at(id) : nullptr; }
+ RTLIL::Wire* wire(RTLIL::IdString id) {
+ 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::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* 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 = "");
+ // 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 = "");
+ // 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* 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* 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 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 = "");
+ // 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 = "");
+ // 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 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 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(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::SigBit &sigbit) : wire(sigbit.wire), data(sigbit.data){ if (wire) offset = sigbit.offset; }
inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
if (wire == other.wire)
diff --git a/kernel/satgen.h b/kernel/satgen.h
index 88b84b7e6..3929a8708 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -279,7 +279,7 @@ struct SatGen
bool arith_undef_handled = false;
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_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_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);
undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b)));
}
@@ -935,7 +935,7 @@ struct SatGen
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> 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());
+
+ // 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->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)));
else
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())
- 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
- 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) {
ez->assume(ez->expression(ezSAT::OpOr, b));
} else {
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()) {
std::vector<int> all_ones(y.size(), ez->CONST_TRUE);
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(), 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());
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())
diff --git a/kernel/timinginfo.h b/kernel/timinginfo.h
index fb4e0930d..d818e580b 100644
--- a/kernel/timinginfo.h
+++ b/kernel/timinginfo.h
@@ -82,6 +82,9 @@ struct TimingInfo
for (auto cell : module->cells()) {
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 dst = cell->getPort(ID::DST);
for (const auto &c : src.chunks())
@@ -128,11 +131,9 @@ struct TimingInfo
int rise_max = cell->getParam(ID::T_RISE_MAX).as_int();
int fall_max = cell->getParam(ID::T_FALL_MAX).as_int();
int max = std::max(rise_max,fall_max);
- 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));
- if (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;
+ if (max < 0) {
+ 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));
+ max = 0;
}
for (const auto &d : dst) {
auto &v = t.arrival[NameBit(d)];
@@ -152,11 +153,9 @@ struct TimingInfo
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));
int max = cell->getParam(ID::T_LIMIT_MAX).as_int();
- 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));
- if (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;
+ if (max < 0) {
+ 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));
+ max = 0;
}
for (const auto &s : src) {
auto &v = t.required[NameBit(s)];
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index 55abd9b96..32c530582 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -139,6 +139,8 @@ Verilog & Cell Type \\
\lstinline[language=Verilog]; Y = A * B; & {\tt \$mul} \\
\lstinline[language=Verilog]; Y = A / B; & {\tt \$div} \\
\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} \\
\end{tabular}
\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,
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}
Multiplexers are generated by the Verilog HDL frontend for {\tt
diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex
index be37d8d39..ac0f48e47 100644
--- a/manual/CHAPTER_Overview.tex
+++ b/manual/CHAPTER_Overview.tex
@@ -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}\_}.
\end{itemize}
-In order to avoid programming errors, the RTLIL data structures check if all
-identifiers start with either a backslash or a dollar sign and generate a
-runtime error if this rule is violated.
+Whitespace and control characters (any character with an ASCII code 32 or less) are not allowed
+in RTLIL identifiers; most frontends and backends cannot support these characters in identifiers.
+
+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.
diff --git a/manual/PRESENTATION_Prog.tex b/manual/PRESENTATION_Prog.tex
index b85eda892..a9416f82a 100644
--- a/manual/PRESENTATION_Prog.tex
+++ b/manual/PRESENTATION_Prog.tex
@@ -307,7 +307,7 @@ cell name from the internal cell library:
\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
$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_
$_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_
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index a88980eaf..53bfd40c6 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -39,3 +39,4 @@ OBJS += passes/cmds/bugpoint.o
endif
OBJS += passes/cmds/scratchpad.o
OBJS += passes/cmds/logger.o
+OBJS += passes/cmds/printattrs.o
diff --git a/passes/cmds/blackbox.cc b/passes/cmds/blackbox.cc
index 5c0405f15..b8297cd77 100644
--- a/passes/cmds/blackbox.cc
+++ b/passes/cmds/blackbox.cc
@@ -48,31 +48,7 @@ struct BlackboxPass : public Pass {
for (auto module : design->selected_whole_modules_warn())
{
- pool<Cell*> remove_cells;
- 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->makeblackbox();
module->set_bool_attribute(ID::blackbox);
}
}
diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc
index 9a27952d4..c9532eced 100644
--- a/passes/cmds/logger.cc
+++ b/passes/cmds/logger.cc
@@ -58,7 +58,8 @@ struct LoggerPass : public Pass {
log(" do not print warnings for the specified experimental feature\n");
log("\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(" -expect-no-warnings\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("Added regex '%s' for warnings to expected %s list.\n", pattern.c_str(), type.c_str());
try {
- if (type=="error")
- log_expect_error.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)));
- else if (type=="warning")
- log_expect_warning.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)));
- else
- log_expect_log.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)));
+ if (type == "error")
+ log_expect_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
+ else if (type == "warning")
+ log_expect_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
+ else if (type == "log")
+ log_expect_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
+ else log_abort();
}
catch (const YS_REGEX_NS::regex_error& e) {
log_cmd_error("Error in regex expression '%s' !\n", pattern.c_str());
diff --git a/passes/cmds/printattrs.cc b/passes/cmds/printattrs.cc
new file mode 100644
index 000000000..80dbfa259
--- /dev/null
+++ b/passes/cmds/printattrs.cc
@@ -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
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 6c4bc0e5b..30436d829 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -109,7 +109,7 @@ struct statdata_t
ID($lut), ID($and), ID($or), ID($xor), ID($xnor),
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($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_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0;
int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0;
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 95d74d1eb..f99d1509d 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -574,9 +574,9 @@ struct HierarchyPass : public Pass {
log("\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("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("resolves positional module parameters, unroll array instances, and more.\n");
+ log("resolves positional module parameters, unrolls array instances, and more.\n");
log("\n");
log(" -check\n");
log(" also check the design hierarchy. this generates an error when\n");
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
index 477246687..e11958bd6 100644
--- a/passes/memory/memory_share.cc
+++ b/passes/memory/memory_share.cc
@@ -715,6 +715,8 @@ struct MemoryShareWorker
cone_ct.cell_types.erase(ID($mul));
cone_ct.cell_types.erase(ID($mod));
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($shl));
cone_ct.cell_types.erase(ID($shr));
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 6271376f1..f7de02164 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -412,7 +412,7 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
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;
CellTypes fftypes;
@@ -445,9 +445,6 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
for (auto wire : module->wires())
{
- if (!purge_mode && wire->name[0] == '\\')
- continue;
-
if (wire->attributes.count(ID::init) == 0)
continue;
@@ -464,11 +461,22 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
if (wire_bit == mapped_wire_bit)
goto next_wire;
- if (qbits.count(sigmap(SigBit(wire, i))) == 0)
- goto next_wire;
+ if (mapped_wire_bit.wire) {
+ if (qbits.count(mapped_wire_bit) == 0)
+ goto next_wire;
- if (qbits.at(sigmap(SigBit(wire, i))) != init[i])
- goto next_wire;
+ if (qbits.at(mapped_wire_bit) != init[i])
+ 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)
@@ -512,7 +520,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
rmunused_module_cells(module, 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)) { }
}
@@ -611,8 +619,7 @@ struct CleanPass : public Pass {
}
break;
}
- if (argidx < args.size())
- extra_args(args, argidx, design);
+ extra_args(args, argidx, design);
keep_cache.reset(design);
@@ -627,7 +634,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) {
if (module->has_processes())
continue;
- rmunused_module(module, purge_mode, ys_debug(), false);
+ rmunused_module(module, purge_mode, ys_debug(), true);
}
log_suppressed();
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 0f5bff680..e5b8bda95 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -132,7 +132,7 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell,
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;
@@ -156,20 +156,36 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
int group_idx = GRP_DYN;
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))
- bit_a = bit_b = RTLIL::State::S1;
-
- if (cell->type == ID($and) && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0))
- bit_a = bit_b = RTLIL::State::S0;
+ if (cell->type == ID($or)) {
+ 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 (bit_a.wire == NULL && bit_b.wire == NULL)
- group_idx = GRP_CONST_AB;
- else if (bit_a.wire == NULL)
- group_idx = GRP_CONST_A;
- else if (bit_b.wire == NULL && commutative)
- group_idx = GRP_CONST_A, std::swap(bit_a, bit_b);
- else if (bit_b.wire == NULL)
- group_idx = GRP_CONST_B;
+ bool def = (bit_a != State::Sx && bit_a != State::Sz && bit_b != State::Sx && bit_b != State::Sz);
+ if (def || !keepdc) {
+ if (bit_a.wire == NULL && bit_b.wire == NULL)
+ group_idx = GRP_CONST_AB;
+ else if (bit_a.wire == NULL)
+ group_idx = GRP_CONST_A;
+ else if (bit_b.wire == NULL && commutative)
+ group_idx = GRP_CONST_A, std::swap(bit_a, bit_b);
+ else if (bit_b.wire == NULL)
+ group_idx = GRP_CONST_B;
+ }
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())
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::SigSig new_conn;
for (auto &it : grouped_bits[i]) {
for (auto &bit : it.second) {
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_b.append(it.first.second);
}
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));
module->connect(new_y, new_b);
module->connect(new_conn);
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);
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->parameters[ID::Y_WIDTH] = new_y->width;
+ c->parameters[ID::Y_WIDTH] = GetSize(new_y);
c->check();
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");
replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0);
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");
replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1);
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_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)
std::swap(sig_a, sig_b);
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 (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;
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:
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_b = cell->hasPort(ID::B) ? assign_map(cell->getPort(ID::B)) : RTLIL::SigSpec();
@@ -800,7 +883,7 @@ skip_fine_alu:
if (0) {
found_the_x_bit:
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)))
replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx);
else
@@ -904,8 +987,10 @@ skip_fine_alu:
if (input.match("01")) ACTION_DO_Y(1);
if (input.match("10")) ACTION_DO_Y(1);
if (input.match("11")) ACTION_DO_Y(0);
- if (input.match(" *")) ACTION_DO_Y(x);
- if (input.match("* ")) ACTION_DO_Y(x);
+ if (consume_x) {
+ if (input.match(" *")) ACTION_DO_Y(0);
+ if (input.match("* ")) ACTION_DO_Y(0);
+ }
}
if (cell->type == ID($_MUX_)) {
@@ -1088,7 +1173,7 @@ skip_fine_alu:
goto next_cell;
}
- if (!keepdc)
+ if (consume_x)
{
bool identity_wrt_a = false;
bool identity_wrt_b = false;
@@ -1384,6 +1469,8 @@ skip_identity:
FOLD_2ARG_CELL(mul)
FOLD_2ARG_CELL(div)
FOLD_2ARG_CELL(mod)
+ FOLD_2ARG_CELL(divfloor)
+ FOLD_2ARG_CELL(modfloor)
FOLD_2ARG_CELL(pow)
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();
+ SigSpec sig_a = assign_map(cell->getPort(ID::A));
SigSpec sig_b = assign_map(cell->getPort(ID::B));
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++)
if (b_val == (1 << i))
{
- if (cell->type == ID($div))
+ if (cell->type.in(ID($div), ID($divfloor)))
{
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);
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)
new_b.pop_back();
- cell->type = ID($shr);
+ cell->type = ID($sshr);
cell->parameters[ID::B_WIDTH] = GetSize(new_b);
cell->parameters[ID::B_SIGNED] = false;
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();
}
- else
+ else if (cell->type.in(ID($mod), ID($modfloor)))
{
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());
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i);
@@ -1558,6 +1667,24 @@ skip_identity:
cell->type = ID($and);
cell->parameters[ID::B_WIDTH] = GetSize(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();
}
@@ -1980,11 +2107,12 @@ struct OptExprPass : public Pass {
do {
do {
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)
design->scratchpad_set_bool("opt.did_something", true);
} 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)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index 1f69c98f4..cbace7bac 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -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)
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;
}
@@ -130,7 +130,7 @@ bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b)
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 "";
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 2839507b0..988253edf 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -376,7 +376,7 @@ struct ShareWorker
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)
shareable_cells.insert(cell);
continue;
@@ -1133,6 +1133,8 @@ struct ShareWorker
cone_ct.cell_types.erase(ID($mul));
cone_ct.cell_types.erase(ID($mod));
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($shl));
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($div));
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_uni_ops.insert(ID($logic_not));
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 195400bf0..f60f2f8a8 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -37,7 +37,7 @@ struct WreduceConfig
ID($and), ID($or), ID($xor), ID($xnor),
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($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($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);
int original_a_width = GetSize(A);
diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc
index d99ca1b53..d6dbf8ef4 100644
--- a/passes/sat/qbfsat.cc
+++ b/passes/sat/qbfsat.cc
@@ -19,22 +19,12 @@
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
+#include "kernel/consteval.h"
#include "kernel/log.h"
#include "kernel/rtlil.h"
#include "kernel/register.h"
-#include <cstdio>
#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
PRIVATE_NAMESPACE_BEGIN
@@ -43,26 +33,47 @@ struct QbfSolutionType {
dict<std::string, std::string> hole_to_value;
bool sat;
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 {
bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs, assume_neg;
+ bool nooptimize, nobisection;
bool sat, unsat, show_smtbmc;
+ enum Solver{Z3, Yices, CVC4} solver;
+ int timeout;
std::string specialize_soln_file;
std::string write_soln_soln_file;
std::string dump_final_smt2_file;
size_t argidx;
QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(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) {
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_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_]* \\(([^:]*:[^\\)]*)\\): (.*)");
#ifndef NDEBUG
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
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;
- 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;
+ 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
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;
}
+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) {
std::ofstream fout(file.c_str());
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);
pool<RTLIL::Cell *> anyconsts_to_remove;
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);
#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;
value_bv.reserve(wire->width);
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);
std::reverse(value_bv.begin(), value_bv.end());
}
-
}
void allconstify_inputs(RTLIL::Module *module, const pool<std::string> &input_wires) {
@@ -280,84 +355,145 @@ void assume_miter_outputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
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;
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 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);
+
+ 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");
+ 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>]`
- {
- 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());
- int retval = run_command(cmd, process_line);
- if (retval == 0) {
- ret.sat = true;
- ret.unknown = false;
- } else if (retval == 1) {
- ret.sat = false;
- ret.unknown = false;
- }
+ recover_solution(ret);
+ return ret;
+}
+
+QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) {
+ QbfSolutionType ret, best_soln;
+ const std::string tempdir_name = make_temp_dir("/tmp/yosys-z3-XXXXXX");
+ RTLIL::Module *module = mod;
+ RTLIL::Design *design = module->design;
+ std::string module_name = module->name.str();
+ RTLIL::Wire *wire_to_optimize = nullptr;
+ 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.nocleanup)
- remove_directory(tempdir_name);
+ 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");
- recover_solution(ret);
+ 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);
- return ret;
-}
+ 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);
+ }
-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());
+ 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 (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;
+ if(!opt.nocleanup)
+ remove_directory(tempdir_name);
+
+ Pass::call(design, "design -pop");
+
+ return ret;
}
QbfSolveOptions parse_args(const std::vector<std::string> &args) {
@@ -379,6 +515,43 @@ QbfSolveOptions parse_args(const std::vector<std::string> &args) {
opt.assume_neg = true;
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") {
opt.sat = true;
continue;
@@ -456,27 +629,43 @@ struct QbfSatPass : public Pass {
log("\n");
log(" qbfsat [options] [selection]\n");
log("\n");
- log("This command solves a 2QBF-SAT problem defined over the currently selected module.\n");
- log("Existentially-quantified variables are declared by assigning a wire \"$anyconst\".\n");
- log("Universally-quantified variables may be explicitly declared by assigning a wire\n");
- log("\"$allconst\", but module inputs will be treated as universally-quantified variables\n");
- log("by default.\n");
+ log("This command solves an \"exists-forall\" 2QBF-SAT problem defined over the currently\n");
+ log("selected module. Existentially-quantified variables are declared by assigning a wire\n");
+ log("\"$anyconst\". Universally-quantified variables may be explicitly declared by assigning\n");
+ log("a wire \"$allconst\", but module inputs will be treated as universally-quantified\n");
+ log("variables by default.\n");
log("\n");
log(" -nocleanup\n");
- log(" Do not delete temporary files and directories. Useful for\n");
- log(" debugging.\n");
+ log(" Do not delete temporary files and directories. Useful for debugging.\n");
log("\n");
log(" -dump-final-smt2 <file>\n");
log(" Pass the --dump-smt2 option to yosys-smtbmc.\n");
log("\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(" -assume-negative-polarity\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(" miters created with the `miter` command.\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(" Generate an error if the solver does not return \"sat\".\n");
log("\n");
@@ -487,15 +676,16 @@ struct QbfSatPass : public Pass {
log(" Print the output from yosys-smtbmc.\n");
log("\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(" -specialize-from-file <solution file>\n");
- log(" Do not run the solver, but instead only attempt to replace all \"$anyconst\"\n");
- log(" cells in the current module with values provided by the specified file.\n");
+ log(" Do not run the solver, but instead only attempt to replace each \"$anyconst\"\n");
+ log(" cell in the current module with a constant value provided by the specified file.\n");
log("\n");
log(" -write-solution <solution file>\n");
- log(" Write the assignments discovered by the solver for all \"$anyconst\" cells\n");
- log(" to the specified file.");
+ log(" If the problem is satisfiable, write the corresponding constant value for each\n");
+ log(" \"$anyconst\" cell from the model produced by the solver to the specified file.");
log("\n");
log("\n");
}
@@ -519,26 +709,15 @@ struct QbfSatPass : public Pass {
if (!opt.specialize_from_file) {
//Save the design to restore after modiyfing the current module.
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);
- Pass::call(design, "design -pop");
module = design->module(module_name);
-
- if (ret.unknown)
- log_warning("solver did not give an answer\n");
- else if (ret.sat)
+ if (ret.unknown) {
+ if (opt.sat || opt.unsat)
+ log_cmd_error("expected problem to be %s\n", opt.sat? "SAT" : "UNSAT");
+ }
+ else if (ret.sat) {
print_qed();
- else
- print_proof_failed();
-
- if(!ret.unknown && ret.sat) {
if (opt.write_solution) {
write_solution(module, ret, opt.write_soln_soln_file);
}
@@ -550,10 +729,11 @@ struct QbfSatPass : public Pass {
if (opt.unsat)
log_cmd_error("expected problem to be UNSAT\n");
}
- else if (!ret.unknown && !ret.sat && opt.sat)
- log_cmd_error("expected problem to be SAT\n");
- else if (ret.unknown && (opt.sat || opt.unsat))
- log_cmd_error("expected problem to be %s\n", opt.sat? "SAT" : "UNSAT");
+ else {
+ print_proof_failed();
+ if (opt.sat)
+ log_cmd_error("expected problem to be SAT\n");
+ }
} else
specialize_from_file(module, opt.specialize_soln_file);
log_pop();
diff --git a/passes/techmap/.gitignore b/passes/techmap/.gitignore
deleted file mode 100644
index e6dcc6bc0..000000000
--- a/passes/techmap/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-techmap.inc
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 1802ba0de..873286608 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -45,18 +45,6 @@ OBJS += passes/techmap/flowmap.o
OBJS += passes/techmap/extractinv.o
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)
TARGETS += $(PROGRAM_PREFIX)yosys-filterlib$(EXE)
EXTRA_OBJS += passes/techmap/filterlib.o
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 1b3d5ff06..06097a6f7 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -151,8 +151,8 @@ struct Abc9Pass : public ScriptPass
log(" specified).\n");
log("\n");
log(" -dff\n");
- log(" also pass $_ABC9_FF_ cells through to ABC. modules with many clock\n");
- log(" domains are marked as such and automatically partitioned by ABC.\n");
+ log(" also pass $_DFF_[NP]_ cells through to ABC. modules with many clock\n");
+ log(" domains are supported and automatically partitioned by ABC.\n");
log("\n");
log(" -nocleanup\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
{
+ 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")) {
- run("abc9_ops -check");
+ run("read_verilog -icells -lib -specify +/abc9_model.v");
run("scc -set_attr abc9_scc_id {}");
if (help_mode)
run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)");
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)
run("abc9_ops -prep_lut <maxlut>", "(skip if -lut or -luts)");
else if (!lut_mode)
run(stringf("abc9_ops -prep_lut %d", maxlut));
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())
- run(stringf("abc9_ops -prep_box %s", dff_mode ? "-dff" : ""));
- run("select -set abc9_holes A:abc9_holes");
- run("flatten -wb @abc9_holes");
- run("techmap @abc9_holes");
- if (dff_mode || help_mode)
- run("abc9_ops -prep_dff", "(only if -dff)");
- run("opt -purge @abc9_holes");
- run("aigmap");
- run("wbflip @abc9_holes");
+ run("abc9_ops -prep_box");
+ if (saved_designs.count("$abc9_holes") || help_mode) {
+ run("design -stash $abc9");
+ run("design -load $abc9_holes");
+ run("techmap -wb -map %$abc9 -map +/techmap.v");
+ run("opt -purge");
+ run("aigmap");
+ run("design -stash $abc9_holes");
+ run("design -load $abc9");
+ run("design -delete $abc9");
+ }
}
- if (check_label("map")) {
+ if (check_label("exe")) {
+ run("aigmap");
if (help_mode) {
run("foreach module in selection");
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(" write_xaiger -map <abc-temp-dir>/input.sym <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_ops -write_box <abc-temp-dir>/input.box", "(skip if '-box')");
+ 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(" 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 {
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));
continue;
}
- log_assert(!mod->attributes.count(ID::abc9_box_id));
log_push();
active_design->selection().select(mod);
@@ -333,8 +398,9 @@ struct Abc9Pass : public ScriptPass
if (!lut_mode)
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()));
- run_nocheck(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));
+ if (box_file.empty())
+ 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");
@@ -349,10 +415,13 @@ struct Abc9Pass : public ScriptPass
abc9_exe_cmd += stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str());
if (!lut_mode)
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(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
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();
}
}
+
+ 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;
diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc
index 1345188a4..8d55b18a0 100644
--- a/passes/techmap/abc9_ops.cc
+++ b/passes/techmap/abc9_ops.cc
@@ -34,13 +34,10 @@ inline std::string remap_name(RTLIL::IdString abc9_name)
return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1);
}
-void check(RTLIL::Design *design)
+void check(RTLIL::Design *design, bool dff_mode)
{
dict<IdString,IdString> box_lookup;
for (auto m : design->modules()) {
- if (m->name.begins_with("$paramod"))
- continue;
-
auto flop = m->get_bool_attribute(ID::abc9_flop);
auto it = m->attributes.find(ID::abc9_box_id);
if (!flop) {
@@ -88,6 +85,461 @@ void check(RTLIL::Design *design)
log_error("Module '%s' with (* abc9_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs);
}
}
+
+ if (dff_mode) {
+ static pool<IdString> unsupported{
+ ID($adff), ID($dlatch), ID($dlatchsr), ID($sr),
+ ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
+ ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_),
+ ID($_DLATCH_N_), ID($_DLATCH_P_),
+ ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_),
+ ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_),
+ ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_)
+ };
+ pool<IdString> processed;
+ for (auto module : design->selected_modules())
+ for (auto cell : module->cells()) {
+ auto inst_module = design->module(cell->type);
+ if (!inst_module)
+ continue;
+ if (!inst_module->get_blackbox_attribute())
+ continue;
+ IdString derived_type;
+ Module *derived_module;
+ if (cell->parameters.empty()) {
+ derived_type = cell->type;
+ derived_module = inst_module;
+ }
+ else {
+ derived_type = inst_module->derive(design, cell->parameters);
+ derived_module = design->module(derived_type);
+ log_assert(derived_module);
+ }
+ if (!derived_module->get_bool_attribute(ID::abc9_flop))
+ continue;
+ if (derived_module->get_blackbox_attribute(true /* ignore_wb */))
+ log_error("Module '%s' with (* abc9_flop *) is a blackbox.\n", log_id(derived_type));
+
+ if (derived_module->has_processes())
+ Pass::call_on_module(design, derived_module, "proc");
+
+ bool found = false;
+ for (auto derived_cell : derived_module->cells()) {
+ if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) {
+ if (found)
+ log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(derived_module));
+ found = true;
+
+ SigBit Q = derived_cell->getPort(ID::Q);
+ log_assert(GetSize(Q.wire) == 1);
+
+ if (!Q.wire->port_output)
+ log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(derived_module), log_id(derived_cell->type));
+
+ Const init = Q.wire->attributes.at(ID::init, State::Sx);
+ log_assert(GetSize(init) == 1);
+ }
+ else if (unsupported.count(derived_cell->type))
+ log_error("Module '%s' with (* abc9_flop *) contains a %s cell, which is not supported for sequential synthesis.\n", log_id(derived_module), log_id(derived_cell->type));
+ }
+ }
+ }
+}
+
+void prep_hier(RTLIL::Design *design, bool dff_mode)
+{
+ auto r = saved_designs.emplace("$abc9_unmap", nullptr);
+ if (r.second)
+ r.first->second = new Design;
+ Design *unmap_design = r.first->second;
+
+ static const pool<IdString> seq_types{
+ ID($dff), ID($dffsr), ID($adff),
+ ID($dlatch), ID($dlatchsr), ID($sr),
+ ID($mem),
+ ID($_DFF_N_), ID($_DFF_P_),
+ ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
+ ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_),
+ ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
+ ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_),
+ ID($_DLATCH_N_), ID($_DLATCH_P_),
+ ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_),
+ ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_),
+ ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_)
+ };
+
+ for (auto module : design->selected_modules())
+ for (auto cell : module->cells()) {
+ auto inst_module = design->module(cell->type);
+ if (!inst_module)
+ continue;
+ if (!inst_module->get_blackbox_attribute())
+ continue;
+ IdString derived_type;
+ Module *derived_module;
+ if (cell->parameters.empty()) {
+ derived_type = cell->type;
+ derived_module = inst_module;
+ }
+ else {
+ derived_type = inst_module->derive(design, cell->parameters);
+ derived_module = design->module(derived_type);
+ }
+ if (derived_module->get_blackbox_attribute(true /* ignore_wb */))
+ continue;
+
+ if (derived_module->get_bool_attribute(ID::abc9_flop)) {
+ if (!dff_mode)
+ continue;
+ }
+ else {
+ if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_bypass))
+ continue;
+ }
+
+ if (!unmap_design->module(derived_type)) {
+ if (derived_module->has_processes())
+ Pass::call_on_module(design, derived_module, "proc");
+
+ if (derived_module->get_bool_attribute(ID::abc9_flop)) {
+ for (auto derived_cell : derived_module->cells())
+ if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) {
+ SigBit Q = derived_cell->getPort(ID::Q);
+ Const init = Q.wire->attributes.at(ID::init, State::Sx);
+ log_assert(GetSize(init) == 1);
+
+ // Block sequential synthesis on cells with (* init *) != 1'b0
+ // because ABC9 doesn't support them
+ if (init != State::S0) {
+ log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(derived_module), log_id(derived_cell->type));
+ derived_module->set_bool_attribute(ID::abc9_flop, false);
+ }
+ break;
+ }
+ }
+ else if (derived_module->get_bool_attribute(ID::abc9_box)) {
+ for (auto derived_cell : derived_module->cells())
+ if (seq_types.count(derived_cell->type)) {
+ derived_module->set_bool_attribute(ID::abc9_box, false);
+ derived_module->set_bool_attribute(ID::abc9_bypass);
+ break;
+ }
+ }
+
+ if (derived_type != cell->type) {
+ auto unmap_module = unmap_design->addModule(derived_type);
+ for (auto port : derived_module->ports) {
+ auto w = unmap_module->addWire(port, derived_module->wire(port));
+ // Do not propagate (* init *) values into the box,
+ // in fact, remove it from outside too
+ if (w->port_output && w->attributes.erase(ID::init)) {
+ auto r = unmap_module->addWire(stringf("\\_TECHMAP_REMOVEINIT_%s_", log_id(port)));
+ unmap_module->connect(r, State::S1);
+ }
+ }
+ unmap_module->ports = derived_module->ports;
+ unmap_module->check();
+
+ auto replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, cell->type);
+ for (const auto &conn : cell->connections()) {
+ auto w = unmap_module->wire(conn.first);
+ log_assert(w);
+ replace_cell->setPort(conn.first, w);
+ }
+ replace_cell->parameters = cell->parameters;
+ }
+ }
+
+ cell->type = derived_type;
+ cell->parameters.clear();
+ }
+}
+
+void prep_bypass(RTLIL::Design *design)
+{
+ auto r = saved_designs.emplace("$abc9_map", nullptr);
+ if (r.second)
+ r.first->second = new Design;
+ Design *map_design = r.first->second;
+
+ r = saved_designs.emplace("$abc9_unmap", nullptr);
+ if (r.second)
+ r.first->second = new Design;
+ Design *unmap_design = r.first->second;
+
+ pool<IdString> processed;
+ for (auto module : design->selected_modules())
+ for (auto cell : module->cells()) {
+ if (!processed.insert(cell->type).second)
+ continue;
+ auto inst_module = design->module(cell->type);
+ if (!inst_module)
+ continue;
+ if (!inst_module->get_bool_attribute(ID::abc9_bypass))
+ continue;
+ log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */));
+ log_assert(cell->parameters.empty());
+
+
+ // The idea is to create two techmap designs, one which maps:
+ //
+ // box u0 (.i(i), .o(o));
+ //
+ // to
+ //
+ // wire $abc9$o;
+ // box u0 (.i(i), .o($abc9_byp$o));
+ // box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o));
+ //
+ // the purpose being to move the (* abc9_box *) status from 'box'
+ // (which is stateful) to 'box_$abc9_byp' (which becomes a new
+ // combinatorial black- (not white-) box with all state elements
+ // removed). This has the effect of preserving any combinatorial
+ // paths through an otherwise sequential primitive -- e.g. LUTRAMs.
+ //
+ // The unmap design performs the reverse:
+ //
+ // wire $abc9$o;
+ // box u0 (.i(i), .o($abc9_byp$o));
+ // box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o));
+ //
+ // to:
+ //
+ // wire $abc9$o;
+ // box u0 (.i(i), .o($abc9_byp$o));
+ // assign o = $abc9_byp$o;
+
+
+ // Copy inst_module into map_design, with the same interface
+ // and duplicate $abc9$* wires for its output ports
+ auto map_module = map_design->addModule(cell->type);
+ for (auto port_name : inst_module->ports) {
+ auto w = map_module->addWire(port_name, inst_module->wire(port_name));
+ if (w->port_output)
+ w->attributes.erase(ID::init);
+ }
+ map_module->ports = inst_module->ports;
+ map_module->check();
+ map_module->set_bool_attribute(ID::whitebox);
+
+ // Create the bypass module in the user design, which has the same
+ // interface as the derived module but with additional input
+ // ports driven by the outputs of the replaced cell
+ auto bypass_module = design->addModule(cell->type.str() + "_$abc9_byp");
+ for (auto port_name : inst_module->ports) {
+ auto port = inst_module->wire(port_name);
+ if (!port->port_output)
+ continue;
+ auto dst = bypass_module->addWire(port_name, port);
+ auto src = bypass_module->addWire("$abc9byp$" + port_name.str(), GetSize(port));
+ src->port_input = true;
+ // For these new input ports driven by the replaced
+ // cell, then create a new simple-path specify entry:
+ // (input => output) = 0
+ auto specify = bypass_module->addCell(NEW_ID, ID($specify2));
+ specify->setPort(ID::EN, State::S1);
+ specify->setPort(ID::SRC, src);
+ specify->setPort(ID::DST, dst);
+ specify->setParam(ID::FULL, 0);
+ specify->setParam(ID::SRC_WIDTH, GetSize(src));
+ specify->setParam(ID::DST_WIDTH, GetSize(dst));
+ specify->setParam(ID::SRC_DST_PEN, 0);
+ specify->setParam(ID::SRC_DST_POL, 0);
+ specify->setParam(ID::T_RISE_MIN, 0);
+ specify->setParam(ID::T_RISE_TYP, 0);
+ specify->setParam(ID::T_RISE_MAX, 0);
+ specify->setParam(ID::T_FALL_MIN, 0);
+ specify->setParam(ID::T_FALL_TYP, 0);
+ specify->setParam(ID::T_FALL_MAX, 0);
+ }
+ bypass_module->set_bool_attribute(ID::blackbox);
+ bypass_module->set_bool_attribute(ID::abc9_box);
+
+ // Copy any 'simple' (combinatorial) specify paths from
+ // the derived module into the bypass module, if EN
+ // is not false and SRC/DST are driven only by
+ // module ports; create new input port if one doesn't
+ // already exist
+ for (auto cell : inst_module->cells()) {
+ if (cell->type != ID($specify2))
+ continue;
+ auto EN = cell->getPort(ID::EN).as_bit();
+ SigBit newEN;
+ if (!EN.wire && EN != State::S1)
+ continue;
+ auto SRC = cell->getPort(ID::SRC);
+ for (const auto &c : SRC.chunks())
+ if (c.wire && !c.wire->port_input) {
+ SRC = SigSpec();
+ break;
+ }
+ if (SRC.empty())
+ continue;
+ auto DST = cell->getPort(ID::DST);
+ for (const auto &c : DST.chunks())
+ if (c.wire && !c.wire->port_output) {
+ DST = SigSpec();
+ break;
+ }
+ if (DST.empty())
+ continue;
+ auto rw = [bypass_module](RTLIL::SigSpec &sig)
+ {
+ SigSpec new_sig;
+ for (auto c : sig.chunks()) {
+ if (c.wire) {
+ auto port = bypass_module->wire(c.wire->name);
+ if (!port)
+ port = bypass_module->addWire(c.wire->name, c.wire);
+ c.wire = port;
+ }
+ new_sig.append(std::move(c));
+ }
+ sig = std::move(new_sig);
+ };
+ auto specify = bypass_module->addCell(NEW_ID, cell);
+ specify->rewrite_sigspecs(rw);
+ }
+ bypass_module->fixup_ports();
+
+ // Create an _TECHMAP_REPLACE_ cell identical to the original cell,
+ // and a bypass cell that has the same inputs/outputs as the
+ // original cell, but with additional inputs taken from the
+ // replaced cell
+ auto replace_cell = map_module->addCell(ID::_TECHMAP_REPLACE_, cell->type);
+ auto bypass_cell = map_module->addCell(NEW_ID, cell->type.str() + "_$abc9_byp");
+ for (const auto &conn : cell->connections()) {
+ auto port = map_module->wire(conn.first);
+ if (cell->input(conn.first)) {
+ replace_cell->setPort(conn.first, port);
+ if (bypass_module->wire(conn.first))
+ bypass_cell->setPort(conn.first, port);
+ }
+ if (cell->output(conn.first)) {
+ bypass_cell->setPort(conn.first, port);
+ auto n = "$abc9byp$" + conn.first.str();
+ auto w = map_module->addWire(n, GetSize(conn.second));
+ replace_cell->setPort(conn.first, w);
+ bypass_cell->setPort(n, w);
+ }
+ }
+
+
+ // Lastly, create a new module in the unmap_design that shorts
+ // out the bypass cell back to leave the replace cell behind
+ // driving the outputs
+ auto unmap_module = unmap_design->addModule(cell->type.str() + "_$abc9_byp");
+ for (auto port_name : inst_module->ports) {
+ auto w = unmap_module->addWire(port_name, inst_module->wire(port_name));
+ if (w->port_output) {
+ w->attributes.erase(ID::init);
+ auto w2 = unmap_module->addWire("$abc9byp$" + port_name.str(), GetSize(w));
+ w2->port_input = true;
+ unmap_module->connect(w, w2);
+ }
+ }
+ unmap_module->fixup_ports();
+ }
+}
+
+void prep_dff(RTLIL::Design *design)
+{
+ auto r = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false)));
+ auto &modules_sel = r.first->second;
+
+ for (auto module : design->selected_modules())
+ for (auto cell : module->cells()) {
+ if (modules_sel.selected_whole_module(cell->type))
+ continue;
+ auto inst_module = design->module(cell->type);
+ if (!inst_module)
+ continue;
+ if (!inst_module->get_bool_attribute(ID::abc9_flop))
+ continue;
+ log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */));
+ log_assert(cell->parameters.empty());
+ modules_sel.select(inst_module);
+ }
+}
+
+void prep_dff_submod(RTLIL::Design *design)
+{
+ for (auto module : design->modules()) {
+ vector<Cell*> specify_cells;
+ SigBit Q;
+ Cell* dff_cell = nullptr;
+
+ if (!module->get_bool_attribute(ID::abc9_flop))
+ continue;
+
+ for (auto cell : module->cells())
+ if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) {
+ log_assert(!dff_cell);
+ dff_cell = cell;
+ Q = cell->getPort(ID::Q);
+ log_assert(GetSize(Q.wire) == 1);
+ }
+ else if (cell->type.in(ID($specify3), ID($specrule)))
+ specify_cells.emplace_back(cell);
+ log_assert(dff_cell);
+
+ // Add an always-enabled CE mux that drives $_DFF_[NP]_.D so that:
+ // (a) flop box will have an output
+ // (b) $_DFF_[NP]_.Q will be present as an input
+ SigBit D = module->addWire(NEW_ID);
+ module->addMuxGate(NEW_ID, dff_cell->getPort(ID::D), Q, State::S0, D);
+ dff_cell->setPort(ID::D, D);
+
+ // Rewrite $specify cells that end with $_DFF_[NP]_.Q
+ // to $_DFF_[NP]_.D since it will be moved into
+ // the submodule
+ for (auto cell : specify_cells) {
+ auto DST = cell->getPort(ID::DST);
+ DST.replace(Q, D);
+ cell->setPort(ID::DST, DST);
+ }
+
+ design->scratchpad_set_bool("abc9_ops.prep_dff_submod.did_something", true);
+ }
+}
+
+void prep_dff_unmap(RTLIL::Design *design)
+{
+ Design *unmap_design = saved_designs.at("$abc9_unmap");
+
+ for (auto module : design->modules()) {
+ if (!module->get_bool_attribute(ID::abc9_flop) || module->get_bool_attribute(ID::abc9_box))
+ continue;
+
+ // Make sure the box module has all the same ports present on flop cell
+ auto replace_cell = module->cell(ID::_TECHMAP_REPLACE_);
+ log_assert(replace_cell);
+ auto box_module = design->module(module->name.str() + "_$abc9_flop");
+ log_assert(box_module);
+ for (auto port_name : module->ports) {
+ auto port = module->wire(port_name);
+ auto box_port = box_module->wire(port_name);
+ if (box_port) {
+ // Do not propagate init -- already captured by box
+ box_port->attributes.erase(ID::init);
+ continue;
+ }
+ log_assert(port->port_input);
+ box_module->addWire(port_name, port);
+ replace_cell->setPort(port_name, port);
+ }
+ box_module->fixup_ports();
+
+ auto unmap_module = unmap_design->addModule(box_module->name);
+ replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, module->name);
+ for (auto port_name : box_module->ports) {
+ auto w = unmap_module->addWire(port_name, box_module->wire(port_name));
+ if (module->wire(port_name))
+ replace_cell->setPort(port_name, w);
+ }
+ unmap_module->ports = box_module->ports;
+ unmap_module->check();
+ }
}
void mark_scc(RTLIL::Module *module)
@@ -95,7 +547,7 @@ void mark_scc(RTLIL::Module *module)
// For every unique SCC found, (arbitrarily) find the first
// cell in the component, and replace its output connections
// with a new wire driven by the old connection but with a
- // special (* abc9_scc *) attribute set (which is used by
+ // special (* abc9_keep *) attribute set (which is used by
// write_xaiger to break this wire into PI and POs)
pool<RTLIL::Const> ids_seen;
for (auto cell : module->cells()) {
@@ -111,7 +563,7 @@ void mark_scc(RTLIL::Module *module)
if (c.second.is_fully_const()) continue;
if (cell->output(c.first)) {
Wire *w = module->addWire(NEW_ID, GetSize(c.second));
- w->set_bool_attribute(ID::abc9_scc);
+ w->set_bool_attribute(ID::abc9_keep);
module->connect(w, c.second);
c.second = w;
}
@@ -119,80 +571,94 @@ void mark_scc(RTLIL::Module *module)
}
}
-void prep_dff(RTLIL::Module *module)
+void prep_delays(RTLIL::Design *design, bool dff_mode)
{
- auto design = module->design;
- log_assert(design);
+ TimingInfo timing;
- SigMap assign_map(module);
+ // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes
+ // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations
+ std::vector<Cell*> cells;
+ for (auto module : design->selected_modules()) {
+ if (module->processes.size() > 0) {
+ log("Skipping module %s as it contains processes.\n", log_id(module));
+ continue;
+ }
- typedef SigSpec clkdomain_t;
- dict<clkdomain_t, int> clk_to_mergeability;
+ for (auto cell : module->cells()) {
+ if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_)))
+ continue;
+ log_assert(!cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY="));
- for (auto cell : module->cells()) {
- if (cell->type != ID($__ABC9_FF_))
- continue;
+ RTLIL::Module* inst_module = design->module(cell->type);
+ if (!inst_module)
+ continue;
+ if (!inst_module->get_blackbox_attribute())
+ continue;
+ if (!cell->parameters.empty())
+ continue;
- Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str()));
- if (abc9_clock_wire == NULL)
- log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
- SigSpec abc9_clock = assign_map(abc9_clock_wire);
+ if (inst_module->get_bool_attribute(ID::abc9_box))
+ continue;
+ if (inst_module->get_bool_attribute(ID::abc9_bypass))
+ continue;
+
+ if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) {
+ continue; // do not add $__ABC9_DELAY boxes to flops
+ // as delays will be captured in the flop box
+ }
- clkdomain_t key(abc9_clock);
+ if (!timing.count(cell->type))
+ timing.setup_module(inst_module);
- auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1));
- auto r2 = cell->attributes.insert(ID::abc9_mergeability);
- log_assert(r2.second);
- r2.first->second = r.first->second;
+ cells.emplace_back(cell);
+ }
}
- RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str()));
- if (holes_module) {
- SigMap sigmap(holes_module);
+ // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes
+ // (or bypassed white-boxes with required times)
+ dict<int, IdString> box_cache;
+ Module *delay_module = design->module(ID($__ABC9_DELAY));
+ log_assert(delay_module);
+ for (auto cell : cells) {
+ auto module = cell->module;
+ auto inst_module = design->module(cell->type);
+ log_assert(inst_module);
- dict<SigSpec, SigSpec> replace;
- for (auto cell : holes_module->cells().to_vector()) {
- if (!cell->type.in(ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
- ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1), ID($_DFF_PP0_), ID($_DFF_PP1_)))
+ auto &t = timing.at(cell->type).required;
+ for (auto &conn : cell->connections_) {
+ auto port_wire = inst_module->wire(conn.first);
+ if (!port_wire)
+ log_error("Port %s in cell %s (type %s) from module %s does not actually exist",
+ log_id(conn.first), log_id(cell), log_id(cell->type), log_id(module));
+ if (!port_wire->port_input)
continue;
- SigBit D = cell->getPort(ID::D);
- SigBit Q = cell->getPort(ID::Q);
- // Emulate async control embedded inside $_DFF_* cell with mux in front of D
- if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_PN0_)))
- D = holes_module->MuxGate(NEW_ID, State::S0, D, cell->getPort(ID::R));
- else if (cell->type.in(ID($_DFF_NN1_), ID($_DFF_PN1_)))
- D = holes_module->MuxGate(NEW_ID, State::S1, D, cell->getPort(ID::R));
- else if (cell->type.in(ID($_DFF_NP0_), ID($_DFF_PP0_)))
- D = holes_module->MuxGate(NEW_ID, D, State::S0, cell->getPort(ID::R));
- else if (cell->type.in(ID($_DFF_NP1_), ID($_DFF_PP1_)))
- D = holes_module->MuxGate(NEW_ID, D, State::S1, cell->getPort(ID::R));
- // Remove the $_DFF_* cell from what needs to be a combinatorial box
- holes_module->remove(cell);
- Wire *port;
- if (GetSize(Q.wire) == 1)
- port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str()));
- else
- port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset));
- log_assert(port);
- // Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
- // in order to extract just the combinatorial control logic that feeds the box
- // (i.e. clock enable, synchronous reset, etc.)
- replace.insert(std::make_pair(Q,D));
- // Since `flatten` above would have created wires named "<cell>.Q",
- // extract the pre-techmap cell name
- auto pos = Q.wire->name.str().rfind(".");
- log_assert(pos != std::string::npos);
- IdString driver = Q.wire->name.substr(0, pos);
- // And drive the signal that was previously driven by "DFF.Q" (typically
- // used to implement clock-enable functionality) with the "<cell>.$abc9_currQ"
- // wire (which itself is driven an by input port) we inserted above
- Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str()));
- log_assert(currQ);
- holes_module->connect(Q, currQ);
- }
+ if (conn.second.is_fully_const())
+ continue;
+
+ SigSpec O = module->addWire(NEW_ID, GetSize(conn.second));
+ for (int i = 0; i < GetSize(conn.second); i++) {
+ auto d = t.at(TimingInfo::NameBit(conn.first,i), 0);
+ if (d == 0)
+ continue;
- for (auto &conn : holes_module->connections_)
- conn.second = replace.at(sigmap(conn.second), conn.second);
+#ifndef NDEBUG
+ if (ys_debug(1)) {
+ static std::set<std::tuple<IdString,IdString,int>> seen;
+ if (seen.emplace(cell->type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n",
+ log_id(cell->type), log_id(conn.first), i, d);
+ }
+#endif
+ auto r = box_cache.insert(d);
+ if (r.second) {
+ r.first->second = delay_module->derive(design, {{ID::DELAY, d}});
+ log_assert(r.first->second.begins_with("$paramod$__ABC9_DELAY\\DELAY="));
+ }
+ auto box = module->addCell(NEW_ID, r.first->second);
+ box->setPort(ID::I, conn.second[i]);
+ box->setPort(ID::O, O[i]);
+ conn.second[i] = O[i];
+ }
+ }
}
}
@@ -208,17 +674,17 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
dict<IdString, std::vector<IdString>> box_ports;
for (auto cell : module->cells()) {
- if (cell->type == ID($__ABC9_FF_))
+ if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
continue;
if (cell->has_keep_attr())
continue;
- auto inst_module = module->design->module(cell->type);
+ auto inst_module = design->module(cell->type);
bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop);
if (abc9_flop && !dff)
continue;
- if ((inst_module && inst_module->get_bool_attribute(ID::abc9_box)) || abc9_flop) {
+ if (inst_module && inst_module->get_bool_attribute(ID::abc9_box)) {
auto r = box_ports.insert(cell->type);
if (r.second) {
// Make carry in the last PI, and carry out the last PO
@@ -287,9 +753,13 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
log_assert(no_loops);
- RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str()));
+ auto r = saved_designs.emplace("$abc9_holes", nullptr);
+ if (r.second)
+ r.first->second = new Design;
+ RTLIL::Design *holes_design = r.first->second;
+ log_assert(holes_design);
+ RTLIL::Module *holes_module = holes_design->addModule(module->name);
log_assert(holes_module);
- holes_module->set_bool_attribute(ID::abc9_holes);
dict<IdString, Cell*> cell_cache;
TimingInfo timing;
@@ -300,22 +770,20 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
log_assert(cell);
RTLIL::Module* box_module = design->module(cell->type);
- if (!box_module || (!box_module->get_bool_attribute(ID::abc9_box) && !box_module->get_bool_attribute(ID::abc9_flop)))
+ if (!box_module)
+ continue;
+ if (!box_module->get_bool_attribute(ID::abc9_box))
continue;
+ log_assert(cell->parameters.empty());
+ log_assert(box_module->get_blackbox_attribute());
cell->attributes[ID::abc9_box_seq] = box_count++;
- IdString derived_type = box_module->derive(design, cell->parameters);
- box_module = design->module(derived_type);
-
- auto r = cell_cache.insert(derived_type);
+ auto r = cell_cache.insert(cell->type);
auto &holes_cell = r.first->second;
if (r.second) {
- if (box_module->has_processes())
- Pass::call_on_module(design, box_module, "proc");
-
if (box_module->get_bool_attribute(ID::whitebox)) {
- holes_cell = holes_module->addCell(cell->name, derived_type);
+ holes_cell = holes_module->addCell(cell->name, cell->type);
if (box_module->has_processes())
Pass::call_on_module(design, box_module, "proc");
@@ -340,22 +808,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
}
}
else if (w->port_output)
- conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), 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++;
- Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
- if (!holes_wire) {
- holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
- holes_wire->port_input = true;
- holes_wire->port_id = port_id++;
- holes_module->ports.push_back(holes_wire->name);
- }
- Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
- holes_module->connect(Q, holes_wire);
+ conn = holes_module->addWire(stringf("%s.%s", cell->type.c_str(), log_id(port_name)), GetSize(w));
}
}
else // box_module is a blackbox
@@ -379,90 +832,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
}
}
-void prep_delays(RTLIL::Design *design, bool dff_mode)
-{
- TimingInfo timing;
-
- // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes
- // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations
- pool<Module*> flops;
- std::vector<Cell*> cells;
- for (auto module : design->selected_modules()) {
- if (module->processes.size() > 0) {
- log("Skipping module %s as it contains processes.\n", log_id(module));
- continue;
- }
-
- for (auto cell : module->cells()) {
- if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY)))
- continue;
-
- RTLIL::Module* inst_module = module->design->module(cell->type);
- if (!inst_module)
- continue;
- if (!inst_module->get_blackbox_attribute())
- continue;
- if (inst_module->attributes.count(ID::abc9_box))
- continue;
- IdString derived_type = inst_module->derive(design, cell->parameters);
- inst_module = design->module(derived_type);
- log_assert(inst_module);
-
- if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) {
- flops.insert(inst_module);
- continue; // do not add $__ABC9_DELAY boxes to flops
- // as delays will be captured in the flop box
- }
-
- if (!timing.count(derived_type))
- timing.setup_module(inst_module);
-
- cells.emplace_back(cell);
- }
- }
-
- // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes
- // with required times
- for (auto cell : cells) {
- auto module = cell->module;
- RTLIL::Module* inst_module = module->design->module(cell->type);
- log_assert(inst_module);
- IdString derived_type = inst_module->derive(design, cell->parameters);
- inst_module = design->module(derived_type);
- log_assert(inst_module);
-
- auto &t = timing.at(derived_type).required;
- for (auto &conn : cell->connections_) {
- auto port_wire = inst_module->wire(conn.first);
- if (!port_wire)
- log_error("Port %s in cell %s (type %s) of module %s does not actually exist",
- log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name));
- if (!port_wire->port_input)
- continue;
-
- SigSpec O = module->addWire(NEW_ID, GetSize(conn.second));
- for (int i = 0; i < GetSize(conn.second); i++) {
- auto d = t.at(TimingInfo::NameBit(conn.first,i), 0);
- if (d == 0)
- continue;
-
-#ifndef NDEBUG
- if (ys_debug(1)) {
- static std::set<std::tuple<IdString,IdString,int>> seen;
- if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n",
- log_id(cell->type), log_id(conn.first), i, d);
- }
-#endif
- auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY));
- box->setPort(ID::I, conn.second[i]);
- box->setPort(ID::O, O[i]);
- box->setParam(ID::DELAY, d);
- conn.second[i] = O[i];
- }
- }
- }
-}
-
void prep_lut(RTLIL::Design *design, int maxlut)
{
TimingInfo timing;
@@ -540,7 +909,7 @@ void write_lut(RTLIL::Module *module, const std::string &dst) {
ofs.close();
}
-void prep_box(RTLIL::Design *design, bool dff_mode)
+void prep_box(RTLIL::Design *design)
{
TimingInfo timing;
@@ -555,165 +924,162 @@ void prep_box(RTLIL::Design *design, bool dff_mode)
dict<IdString,std::vector<IdString>> box_ports;
for (auto module : design->modules()) {
- auto abc9_flop = module->get_bool_attribute(ID::abc9_flop);
- if (abc9_flop) {
- auto r = module->attributes.insert(ID::abc9_box_id);
- if (!r.second)
- continue;
- r.first->second = abc9_box_id++;
-
- if (dff_mode) {
- int num_inputs = 0, num_outputs = 0;
- for (auto port_name : module->ports) {
- auto wire = module->wire(port_name);
- log_assert(GetSize(wire) == 1);
- if (wire->port_input) num_inputs++;
- if (wire->port_output) num_outputs++;
- }
- log_assert(num_outputs == 1);
+ auto it = module->attributes.find(ID::abc9_box);
+ if (it == module->attributes.end())
+ continue;
+ bool box = it->second.as_bool();
+ module->attributes.erase(it);
+ if (!box)
+ continue;
- ss << log_id(module) << " " << r.first->second.as_int();
- ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
- ss << " " << num_inputs+1 << " " << num_outputs << std::endl;
+ auto r = module->attributes.insert(ID::abc9_box_id);
+ if (!r.second)
+ continue;
+ r.first->second = abc9_box_id++;
+
+ if (module->get_bool_attribute(ID::abc9_flop)) {
+ int num_inputs = 0, num_outputs = 0;
+ for (auto port_name : module->ports) {
+ auto wire = module->wire(port_name);
+ log_assert(GetSize(wire) == 1);
+ if (wire->port_input) num_inputs++;
+ if (wire->port_output) num_outputs++;
+ }
+ log_assert(num_outputs == 1);
+
+ ss << log_id(module) << " " << r.first->second.as_int();
+ log_assert(module->get_bool_attribute(ID::whitebox));
+ ss << " " << "1";
+ ss << " " << num_inputs << " " << num_outputs << std::endl;
+
+ ss << "#";
+ bool first = true;
+ for (auto port_name : module->ports) {
+ auto wire = module->wire(port_name);
+ if (!wire->port_input)
+ continue;
+ if (first)
+ first = false;
+ else
+ ss << " ";
+ ss << log_id(wire);
+ }
+ ss << std::endl;
- ss << "#";
- bool first = true;
- for (auto port_name : module->ports) {
- auto wire = module->wire(port_name);
- if (!wire->port_input)
- continue;
- if (first)
- first = false;
- else
- ss << " ";
- ss << log_id(wire);
- }
- ss << " abc9_ff.Q" << std::endl;
+ auto &t = timing.setup_module(module).required;
+ if (t.empty())
+ log_error("Module '%s' with (* abc9_flop *) has no clk-to-q timing (and thus no connectivity) information.\n", log_id(module));
- auto &t = timing.setup_module(module).required;
- first = true;
- for (auto port_name : module->ports) {
- auto wire = module->wire(port_name);
- if (!wire->port_input)
- continue;
- if (first)
- first = false;
- else
- ss << " ";
- log_assert(GetSize(wire) == 1);
- auto it = t.find(TimingInfo::NameBit(port_name,0));
- if (it == t.end())
- // Assume that no setup time means zero
- ss << 0;
- else {
- ss << it->second;
+ first = true;
+ for (auto port_name : module->ports) {
+ auto wire = module->wire(port_name);
+ if (!wire->port_input)
+ continue;
+ if (first)
+ first = false;
+ else
+ ss << " ";
+ log_assert(GetSize(wire) == 1);
+ auto it = t.find(TimingInfo::NameBit(port_name,0));
+ if (it == t.end())
+ // Assume no connectivity if no setup time
+ ss << "-";
+ else {
+ ss << it->second;
#ifndef NDEBUG
- if (ys_debug(1)) {
- static std::set<std::pair<IdString,IdString>> seen;
- if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module),
- log_id(port_name), it->second);
- }
-#endif
+ if (ys_debug(1)) {
+ static std::set<std::pair<IdString,IdString>> seen;
+ if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module),
+ log_id(port_name), it->second);
}
-
+#endif
}
- // Last input is 'abc9_ff.Q'
- ss << " 0" << std::endl << std::endl;
- continue;
}
+ ss << " # $_DFF_[NP]_.D" << std::endl;
+ ss << std::endl;
}
else {
- if (!module->attributes.erase(ID::abc9_box))
- continue;
-
- auto r = module->attributes.insert(ID::abc9_box_id);
- if (!r.second)
- continue;
- r.first->second = abc9_box_id++;
- }
+ auto r2 = box_ports.insert(module->name);
+ if (r2.second) {
+ // Make carry in the last PI, and carry out the last PO
+ // since ABC requires it this way
+ IdString carry_in, carry_out;
+ for (const auto &port_name : module->ports) {
+ auto w = module->wire(port_name);
+ log_assert(w);
+ if (w->get_bool_attribute(ID::abc9_carry)) {
+ log_assert(w->port_input != w->port_output);
+ if (w->port_input)
+ carry_in = port_name;
+ else if (w->port_output)
+ carry_out = port_name;
+ }
+ else
+ r2.first->second.push_back(port_name);
+ }
- auto r = box_ports.insert(module->name);
- if (r.second) {
- // Make carry in the last PI, and carry out the last PO
- // since ABC requires it this way
- IdString carry_in, carry_out;
- for (const auto &port_name : module->ports) {
- auto w = module->wire(port_name);
- log_assert(w);
- if (w->get_bool_attribute(ID::abc9_carry)) {
- log_assert(w->port_input != w->port_output);
- if (w->port_input)
- carry_in = port_name;
- else if (w->port_output)
- carry_out = port_name;
+ if (carry_in != IdString()) {
+ r2.first->second.push_back(carry_in);
+ r2.first->second.push_back(carry_out);
}
- else
- r.first->second.push_back(port_name);
}
- if (carry_in != IdString()) {
- r.first->second.push_back(carry_in);
- r.first->second.push_back(carry_out);
+ std::vector<SigBit> inputs, outputs;
+ for (auto port_name : r2.first->second) {
+ auto wire = module->wire(port_name);
+ if (wire->port_input)
+ for (int i = 0; i < GetSize(wire); i++)
+ inputs.emplace_back(wire, i);
+ if (wire->port_output)
+ for (int i = 0; i < GetSize(wire); i++)
+ outputs.emplace_back(wire, i);
}
- }
-
- std::vector<SigBit> inputs;
- std::vector<SigBit> outputs;
- for (auto port_name : r.first->second) {
- auto wire = module->wire(port_name);
- if (wire->port_input)
- for (int i = 0; i < GetSize(wire); i++)
- inputs.emplace_back(wire, i);
- if (wire->port_output)
- for (int i = 0; i < GetSize(wire); i++)
- outputs.emplace_back(wire, i);
- }
-
- ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int();
- ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
- ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
-
- bool first = true;
- ss << "#";
- for (const auto &i : inputs) {
- if (first)
- first = false;
- else
- ss << " ";
- if (GetSize(i.wire) == 1)
- ss << log_id(i.wire);
- else
- ss << log_id(i.wire) << "[" << i.offset << "]";
- }
- ss << std::endl;
- auto &t = timing.setup_module(module).comb;
- if (!abc9_flop && t.empty())
- log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module));
+ ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int();
+ ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
+ ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
- for (const auto &o : outputs) {
- first = true;
+ bool first = true;
+ ss << "#";
for (const auto &i : inputs) {
if (first)
first = false;
else
ss << " ";
- auto jt = t.find(TimingInfo::BitBit(i,o));
- if (jt == t.end())
- ss << "-";
+ if (GetSize(i.wire) == 1)
+ ss << log_id(i.wire);
else
- ss << jt->second;
+ ss << log_id(i.wire) << "[" << i.offset << "]";
}
- ss << " # ";
- if (GetSize(o.wire) == 1)
- ss << log_id(o.wire);
- else
- ss << log_id(o.wire) << "[" << o.offset << "]";
ss << std::endl;
+ auto &t = timing.setup_module(module);
+ if (t.comb.empty())
+ log_error("Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information.\n", log_id(module));
+
+ for (const auto &o : outputs) {
+ first = true;
+ for (const auto &i : inputs) {
+ if (first)
+ first = false;
+ else
+ ss << " ";
+ auto jt = t.comb.find(TimingInfo::BitBit(i,o));
+ if (jt == t.comb.end())
+ ss << "-";
+ else
+ ss << jt->second;
+ }
+ ss << " # ";
+ if (GetSize(o.wire) == 1)
+ ss << log_id(o.wire);
+ else
+ ss << log_id(o.wire) << "[" << o.offset << "]";
+ ss << std::endl;
+ }
+ ss << std::endl;
}
- ss << std::endl;
}
// ABC expects at least one box
@@ -730,7 +1096,7 @@ void write_box(RTLIL::Module *module, const std::string &dst) {
ofs.close();
}
-void reintegrate(RTLIL::Module *module)
+void reintegrate(RTLIL::Module *module, bool dff_mode)
{
auto design = module->design;
log_assert(design);
@@ -744,6 +1110,8 @@ void reintegrate(RTLIL::Module *module)
for (auto w : mapped_mod->wires()) {
auto nw = module->addWire(remap_name(w->name), GetSize(w));
nw->start_offset = w->start_offset;
+ // Remove all (* init *) since they only existon $_DFF_[NP]_
+ w->attributes.erase(ID::init);
}
dict<IdString,std::vector<IdString>> box_ports;
@@ -783,7 +1151,14 @@ void reintegrate(RTLIL::Module *module)
for (auto cell : module->cells().to_vector()) {
if (cell->has_keep_attr())
continue;
- if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_)))
+
+ // Short out $_DFF_[NP]_ cells since the flop box already has
+ // all the information we need to reconstruct cell
+ if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_)) && !cell->get_bool_attribute(ID::abc9_keep)) {
+ module->connect(cell->getPort(ID::Q), cell->getPort(ID::D));
+ module->remove(cell);
+ }
+ else if (cell->type.in(ID($_AND_), ID($_NOT_)))
module->remove(cell);
else if (cell->attributes.erase(ID::abc9_box_seq))
boxes.emplace_back(cell);
@@ -797,6 +1172,18 @@ void reintegrate(RTLIL::Module *module)
std::map<IdString, int> cell_stats;
for (auto mapped_cell : mapped_mod->cells())
{
+ // Short out $_FF_ cells since the flop box already has
+ // all the information we need to reconstruct cell
+ if (dff_mode && mapped_cell->type == ID($_FF_)) {
+ SigBit D = mapped_cell->getPort(ID::D);
+ SigBit Q = mapped_cell->getPort(ID::Q);
+ if (D.wire)
+ D.wire = module->wires_.at(remap_name(D.wire->name));
+ Q.wire = module->wires_.at(remap_name(Q.wire->name));
+ module->connect(Q, D);
+ continue;
+ }
+
// TODO: Speed up toposort -- we care about NOT ordering only
toposort.node(mapped_cell->name);
@@ -846,7 +1233,7 @@ void reintegrate(RTLIL::Module *module)
continue;
}
- if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) {
+ if (mapped_cell->type == ID($lut)) {
RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
cell->parameters = mapped_cell->parameters;
cell->attributes = mapped_cell->attributes;
@@ -881,7 +1268,7 @@ void reintegrate(RTLIL::Module *module)
if (!existing_cell)
log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_cell));
- if (existing_cell->type == ID($__ABC9_DELAY)) {
+ if (existing_cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) {
SigBit I = mapped_cell->getPort(ID(i));
SigBit O = mapped_cell->getPort(ID(o));
if (I.wire)
@@ -893,10 +1280,8 @@ void reintegrate(RTLIL::Module *module)
}
RTLIL::Module* box_module = design->module(existing_cell->type);
- IdString derived_type = box_module->derive(design, existing_cell->parameters);
- RTLIL::Module* derived_module = design->module(derived_type);
- log_assert(derived_module);
- log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at(ID::abc9_box_id).as_int()));
+ log_assert(existing_cell->parameters.empty());
+ log_assert(mapped_cell->type == stringf("$__boxid%d", box_module->attributes.at(ID::abc9_box_id).as_int()));
mapped_cell->type = existing_cell->type;
RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
@@ -913,7 +1298,7 @@ void reintegrate(RTLIL::Module *module)
SigSpec outputs = std::move(jt->second);
mapped_cell->connections_.erase(jt);
- auto abc9_flop = box_module->attributes.count(ID::abc9_flop);
+ auto abc9_flop = box_module->get_bool_attribute(ID::abc9_flop);
if (!abc9_flop) {
for (const auto &i : inputs)
bit_users[i].insert(mapped_cell->name);
@@ -924,7 +1309,7 @@ void reintegrate(RTLIL::Module *module)
}
int input_count = 0, output_count = 0;
- for (const auto &port_name : box_ports.at(derived_type)) {
+ for (const auto &port_name : box_ports.at(existing_cell->type)) {
RTLIL::Wire *w = box_module->wire(port_name);
log_assert(w);
@@ -988,7 +1373,7 @@ void reintegrate(RTLIL::Module *module)
RTLIL::Wire *mapped_wire = mapped_mod->wire(port);
RTLIL::Wire *wire = module->wire(port);
log_assert(wire);
- wire->attributes.erase(ID::abc9_scc);
+ wire->attributes.erase(ID::abc9_keep);
RTLIL::Wire *remap_wire = module->wire(remap_name(port));
RTLIL::SigSpec signal(wire, remap_wire->start_offset-wire->start_offset, GetSize(remap_wire));
@@ -1116,6 +1501,37 @@ struct Abc9OpsPass : public Pass {
log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n");
log(" (* abc9_carry *) is only given for one input/output port, etc.\n");
log("\n");
+ log(" -prep_hier\n");
+ log(" derive all used (* abc9_box *) or (* abc9_flop *) (if -dff option)\n");
+ log(" whitebox modules. with (* abc9_flop *) modules, only those containing\n");
+ log(" $dff/$_DFF_[NP]_ cells with zero initial state -- due to an ABC limitation\n");
+ log(" -- will be derived.\n");
+ log("\n");
+ log(" -prep_bypass\n");
+ log(" create techmap rules in the '$abc9_map' and '$abc9_unmap' designs for\n");
+ log(" bypassing sequential (* abc9_box *) modules using a combinatorial box\n");
+ log(" (named *_$abc9_byp). bypassing is necessary if sequential elements (e.g.\n");
+ log(" $dff, $mem, etc.) are discovered inside so that any combinatorial paths\n");
+ log(" will be correctly captured. this bypass box will only contain ports that\n");
+ log(" are referenced by a simple path declaration ($specify2 cell) inside a\n");
+ log(" specify block.\n");
+ log("\n");
+ log(" -prep_dff\n");
+ log(" select all (* abc9_flop *) modules instantiated in the design and store\n");
+ log(" in the named selection '$abc9_flops'.\n");
+ log("\n");
+ log(" -prep_dff_submod\n");
+ log(" within (* abc9_flop *) modules, rewrite all edge-sensitive path\n");
+ log(" declarations and $setup() timing checks ($specify3 and $specrule cells)\n");
+ log(" that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to\n");
+ log(" the DFF's 'D' port. this is to prepare such specify cells to be moved\n");
+ log(" into the flop box.\n");
+ log("\n");
+ log(" -prep_dff_unmap\n");
+ log(" populate the '$abc9_unmap' design with techmap rules for mapping *_$abc9_flop\n");
+ log(" cells back into their derived cell types (where the rules created by\n");
+ log(" -prep_hier will then map back to the original cell with parameters).\n");
+ log("\n");
log(" -prep_delays\n");
log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n");
log(" certain required times.\n");
@@ -1128,18 +1544,13 @@ struct Abc9OpsPass : public Pass {
log("\n");
log(" -prep_xaiger\n");
log(" prepare the design for XAIGER output. this includes computing the\n");
- log(" topological ordering of ABC9 boxes, as well as preparing the\n");
- log(" '<module-name>$holes' module that contains the logic behaviour of ABC9\n");
- log(" whiteboxes.\n");
+ log(" topological ordering of ABC9 boxes, as well as preparing the '$abc9_holes'\n");
+ log(" design that contains the logic behaviour of ABC9 whiteboxes.\n");
log("\n");
log(" -dff\n");
log(" consider flop cells (those instantiating modules marked with (* abc9_flop *))\n");
log(" during -prep_{delays,xaiger,box}.\n");
log("\n");
- log(" -prep_dff\n");
- log(" compute the clock domain and initial value of each flop in the design.\n");
- log(" process the '$holes' module to support clock-enable functionality.\n");
- log("\n");
log(" -prep_lut <maxlut>\n");
log(" pre-compute the lut library by analysing all modules marked with\n");
log(" (* abc9_lut=<area> *).\n");
@@ -1167,7 +1578,9 @@ struct Abc9OpsPass : public Pass {
bool check_mode = false;
bool prep_delays_mode = false;
bool mark_scc_mode = false;
- bool prep_dff_mode = false;
+ bool prep_hier_mode = false;
+ bool prep_bypass_mode = false;
+ bool prep_dff_mode = false, prep_dff_submod_mode = false, prep_dff_unmap_mode = false;
bool prep_xaiger_mode = false;
bool prep_lut_mode = false;
bool prep_box_mode = false;
@@ -1177,53 +1590,81 @@ struct Abc9OpsPass : public Pass {
int maxlut = 0;
std::string write_box_dst;
+ bool valid = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-check") {
check_mode = true;
+ valid = true;
continue;
}
if (arg == "-mark_scc") {
mark_scc_mode = true;
+ valid = true;
+ continue;
+ }
+ if (arg == "-prep_hier") {
+ prep_hier_mode = true;
+ valid = true;
+ continue;
+ }
+ if (arg == "-prep_bypass") {
+ prep_bypass_mode = true;
+ valid = true;
continue;
}
if (arg == "-prep_dff") {
prep_dff_mode = true;
+ valid = true;
+ continue;
+ }
+ if (arg == "-prep_dff_submod") {
+ prep_dff_submod_mode = true;
+ valid = true;
+ continue;
+ }
+ if (arg == "-prep_dff_unmap") {
+ prep_dff_unmap_mode = true;
+ valid = true;
continue;
}
if (arg == "-prep_xaiger") {
prep_xaiger_mode = true;
+ valid = true;
continue;
}
if (arg == "-prep_delays") {
prep_delays_mode = true;
+ valid = true;
continue;
}
if (arg == "-prep_lut" && argidx+1 < args.size()) {
prep_lut_mode = true;
maxlut = atoi(args[++argidx].c_str());
- continue;
- }
- if (arg == "-maxlut" && argidx+1 < args.size()) {
+ valid = true;
continue;
}
if (arg == "-write_lut" && argidx+1 < args.size()) {
write_lut_dst = args[++argidx];
rewrite_filename(write_lut_dst);
+ valid = true;
continue;
}
if (arg == "-prep_box") {
prep_box_mode = true;
+ valid = true;
continue;
}
if (arg == "-write_box" && argidx+1 < args.size()) {
write_box_dst = args[++argidx];
rewrite_filename(write_box_dst);
+ valid = true;
continue;
}
if (arg == "-reintegrate") {
reintegrate_mode = true;
+ valid = true;
continue;
}
if (arg == "-dff") {
@@ -1234,25 +1675,32 @@ struct Abc9OpsPass : public Pass {
}
extra_args(args, argidx, design);
- if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || prep_lut_mode || prep_box_mode || !write_lut_dst.empty() || !write_box_dst.empty() || reintegrate_mode))
- log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
+ if (!valid)
+ log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
- if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !prep_box_mode)
- log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger,box}.\n");
+ if (dff_mode && !check_mode && !prep_hier_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode)
+ log_cmd_error("'-dff' option is only relevant for -prep_{hier,delay,xaiger} or -reintegrate.\n");
if (check_mode)
- check(design);
+ check(design, dff_mode);
+ if (prep_hier_mode)
+ prep_hier(design, dff_mode);
+ if (prep_bypass_mode)
+ prep_bypass(design);
+ if (prep_dff_mode)
+ prep_dff(design);
+ if (prep_dff_submod_mode)
+ prep_dff_submod(design);
+ if (prep_dff_unmap_mode)
+ prep_dff_unmap(design);
if (prep_delays_mode)
prep_delays(design, dff_mode);
if (prep_lut_mode)
prep_lut(design, maxlut);
if (prep_box_mode)
- prep_box(design, dff_mode);
+ prep_box(design);
for (auto mod : design->selected_modules()) {
- if (mod->get_bool_attribute(ID::abc9_holes))
- continue;
-
if (mod->processes.size() > 0) {
log("Skipping module %s as it contains processes.\n", log_id(mod));
continue;
@@ -1267,12 +1715,10 @@ struct Abc9OpsPass : public Pass {
write_box(mod, write_box_dst);
if (mark_scc_mode)
mark_scc(mod);
- if (prep_dff_mode)
- prep_dff(mod);
if (prep_xaiger_mode)
prep_xaiger(mod, dff_mode);
if (reintegrate_mode)
- reintegrate(mod);
+ reintegrate(mod, dff_mode);
}
}
} Abc9OpsPass;
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index b65b3e972..214157a64 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -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($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)
{
- 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;
if (!initialized_mappers) {
@@ -595,7 +595,7 @@ struct SimplemapPass : public Pass {
log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
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);
for (auto mod : design->modules()) {
diff --git a/passes/techmap/simplemap.h b/passes/techmap/simplemap.h
index c2d73ea79..5091050a1 100644
--- a/passes/techmap/simplemap.h
+++ b/passes/techmap/simplemap.h
@@ -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(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
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index a554be257..c88f7bd0a 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -27,7 +27,6 @@
#include <string.h>
#include "simplemap.h"
-#include "passes/techmap/techmap.inc"
YOSYS_NAMESPACE_BEGIN
@@ -51,21 +50,21 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
{
vector<SigChunk> chunks = sig;
for (auto &chunk : chunks)
- if (chunk.wire != NULL) {
+ if (chunk.wire != nullptr) {
IdString wire_name = chunk.wire->name;
apply_prefix(prefix, wire_name);
- log_assert(module->wires_.count(wire_name) > 0);
- chunk.wire = module->wires_[wire_name];
+ log_assert(module->wire(wire_name) != nullptr);
+ chunk.wire = module->wire(wire_name);
}
sig = chunks;
}
struct TechmapWorker
{
- std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers;
- std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
- std::map<RTLIL::Module*, bool> techmap_do_cache;
- std::set<RTLIL::Module*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Module>> module_queue;
+ dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers;
+ dict<std::pair<IdString, dict<IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
+ dict<RTLIL::Module*, bool> techmap_do_cache;
+ pool<RTLIL::Module*> module_queue;
dict<Module*, SigMap> sigmaps;
pool<IdString> flatten_do_list;
@@ -79,31 +78,21 @@ struct TechmapWorker
RTLIL::SigSpec value;
};
- typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires;
+ typedef dict<IdString, std::vector<TechmapWireData>> TechmapWires;
- bool extern_mode;
- bool assert_mode;
- bool flatten_mode;
- bool recursive_mode;
- bool autoproc_mode;
- bool ignore_wb;
-
- TechmapWorker()
- {
- extern_mode = false;
- assert_mode = false;
- flatten_mode = false;
- recursive_mode = false;
- autoproc_mode = false;
- ignore_wb = false;
- }
+ bool extern_mode = false;
+ bool assert_mode = false;
+ bool flatten_mode = false;
+ bool recursive_mode = false;
+ bool autoproc_mode = false;
+ bool ignore_wb = false;
std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose)
{
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++) {
RTLIL::SigBit bit = sigmap(conn.second[i]);
if (bit.wire == nullptr) {
@@ -117,7 +106,7 @@ struct TechmapWorker
constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i,
log_id(connbits_map.at(bit).first), connbits_map.at(bit).second);
} 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);
}
}
@@ -129,24 +118,25 @@ struct TechmapWorker
{
TechmapWires result;
- if (module == NULL)
+ if (module == nullptr)
return result;
- for (auto &it : module->wires_) {
- const char *p = it.first.c_str();
+ for (auto w : module->wires()) {
+ const char *p = w->name.c_str();
if (*p == '$')
continue;
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;
- record.wire = it.second;
- record.value = it.second;
+ record.wire = w;
+ record.value = w;
result[p].push_back(record);
- it.second->attributes[ID::keep] = RTLIL::Const(1);
- it.second->attributes[ID::_techmap_special_] = RTLIL::Const(1);
+ w->set_bool_attribute(ID::keep);
+ w->set_bool_attribute(ID::_techmap_special_);
}
}
@@ -165,7 +155,7 @@ struct TechmapWorker
if (tpl->processes.size() != 0) {
log("Technology map yielded processes:");
for (auto &it : tpl->processes)
- log(" %s",RTLIL::id2cstr(it.first));
+ log(" %s",log_id(it.first));
log("\n");
if (autoproc_mode) {
Pass::call_on_module(tpl->design, tpl, "proc");
@@ -179,8 +169,8 @@ struct TechmapWorker
orig_cell_name = cell->name.str();
if (!flatten_mode) {
- for (auto &it : tpl->cells_)
- if (it.first == ID::_TECHMAP_REPLACE_) {
+ for (auto tpl_cell : tpl->cells())
+ if (tpl_cell->name == ID::_TECHMAP_REPLACE_) {
module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str());
break;
}
@@ -204,30 +194,30 @@ struct TechmapWorker
design->select(module, m);
}
- std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
+ dict<IdString, IdString> positional_ports;
dict<Wire*, IdString> temp_renamed_wires;
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);
- positional_ports[posportname] = it.first;
+ IdString posportname = stringf("$%d", tpl_w->port_id);
+ positional_ports.emplace(posportname, tpl_w->name);
- if (!flatten_mode && it.second->get_bool_attribute(ID::techmap_autopurge) &&
- (!cell->hasPort(it.second->name) || !GetSize(cell->getPort(it.second->name))) &&
+ if (!flatten_mode && tpl_w->get_bool_attribute(ID::techmap_autopurge) &&
+ (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) &&
(!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname))))
{
if (sigmaps.count(tpl) == 0)
sigmaps[tpl].set(tpl);
- for (auto bit : sigmaps.at(tpl)(it.second))
+ for (auto bit : sigmaps.at(tpl)(tpl_w))
if (bit.wire != nullptr)
autopurge_tpl_bits.insert(bit);
}
}
- IdString w_name = it.second->name;
+ IdString w_name = tpl_w->name;
apply_prefix(cell->name, w_name);
RTLIL::Wire *w = module->wire(w_name);
if (w != nullptr) {
@@ -237,30 +227,30 @@ struct TechmapWorker
w = nullptr;
} else {
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_id(tpl), log_id(it.second), log_id(module), log_id(cell));
- w->width = GetSize(it.second);
+ log_id(tpl), log_id(tpl_w), log_id(module), log_id(cell));
+ w->width = GetSize(tpl_w);
}
}
}
if (w == nullptr) {
- w = module->addWire(w_name, it.second);
+ w = module->addWire(w_name, tpl_w);
w->port_input = false;
w->port_output = false;
w->port_id = 0;
if (!flatten_mode)
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();
if (w->attributes.count(ID::src))
w->add_strpool_attribute(ID::src, extra_src_attrs);
}
design->select(module, w);
- if (it.second->name.begins_with("\\_TECHMAP_REPLACE_.")) {
- IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), it.second->name.c_str() + strlen("\\_TECHMAP_REPLACE_"));
- Wire *replace_w = module->addWire(replace_name, it.second);
+ if (tpl_w->name.begins_with("\\_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, tpl_w);
module->connect(replace_w, w);
}
}
@@ -268,24 +258,23 @@ struct TechmapWorker
SigMap tpl_sigmap(tpl);
pool<SigBit> tpl_written_bits;
- for (auto &it1 : tpl->cells_)
- for (auto &it2 : it1.second->connections_)
- if (it1.second->output(it2.first))
- for (auto bit : tpl_sigmap(it2.second))
+ for (auto tpl_cell : tpl->cells())
+ for (auto &conn : tpl_cell->connections())
+ if (tpl_cell->output(conn.first))
+ for (auto bit : tpl_sigmap(conn.second))
tpl_written_bits.insert(bit);
- for (auto &it1 : tpl->connections_)
- for (auto bit : tpl_sigmap(it1.first))
+ for (auto &conn : tpl->connections())
+ for (auto bit : tpl_sigmap(conn.first))
tpl_written_bits.insert(bit);
SigMap port_signal_map;
- SigSig port_signal_assign;
for (auto &it : cell->connections())
{
- RTLIL::IdString portname = it.first;
+ IdString portname = it.first;
if (positional_ports.count(portname) > 0)
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("$"))
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;
@@ -294,7 +283,7 @@ struct TechmapWorker
if (GetSize(it.second) == 0)
continue;
- RTLIL::Wire *w = tpl->wires_.at(portname);
+ RTLIL::Wire *w = tpl->wire(portname);
RTLIL::SigSig c, extra_connect;
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_);
if (techmap_replace_cell)
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_"));
else
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);
if (!flatten_mode && c->type.begins_with("\\$"))
@@ -397,12 +386,12 @@ struct TechmapWorker
vector<IdString> autopurge_ports;
- for (auto &it2 : c->connections_)
+ for (auto &conn : c->connections())
{
bool autopurge = false;
if (!autopurge_tpl_bits.empty()) {
- autopurge = GetSize(it2.second) != 0;
- for (auto &bit : sigmaps.at(tpl)(it2.second))
+ autopurge = GetSize(conn.second) != 0;
+ for (auto &bit : sigmaps.at(tpl)(conn.second))
if (!autopurge_tpl_bits.count(bit)) {
autopurge = false;
break;
@@ -410,10 +399,12 @@ struct TechmapWorker
}
if (autopurge) {
- autopurge_ports.push_back(it2.first);
+ autopurge_ports.push_back(conn.first);
} else {
- apply_prefix(cell->name, it2.second, module);
- port_signal_map.apply(it2.second);
+ RTLIL::SigSpec new_conn = conn.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,
- const std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> &celltypeMap, bool in_recursion)
+ bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool<RTLIL::Cell*> &handled_cells,
+ const dict<IdString, pool<IdString>> &celltypeMap, bool in_recursion)
{
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;
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
- std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
+ TopoSort<RTLIL::Cell*, IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
+ dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_inbit;
+ 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;
std::string cell_type = cell->type.str();
@@ -511,7 +502,7 @@ struct TechmapWorker
if (flatten_mode) {
bool keepit = cell->get_bool_attribute(ID::keep_hierarchy);
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;
if (keepit) {
if (!flatten_keep_list[cell]) {
@@ -533,7 +524,7 @@ struct TechmapWorker
continue;
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);
if (port && port->port_input)
cell_to_inbit[cell].insert(sig.begin(), sig.end());
@@ -566,9 +557,9 @@ struct TechmapWorker
for (auto &tpl_name : celltypeMap.at(cell_type))
{
- RTLIL::IdString derived_name = tpl_name;
- RTLIL::Module *tpl = map->modules_[tpl_name];
- std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end());
+ IdString derived_name = tpl_name;
+ RTLIL::Module *tpl = map->module(tpl_name);
+ dict<IdString, RTLIL::Const> parameters(cell->parameters);
if (tpl->get_blackbox_attribute(ignore_wb))
continue;
@@ -675,7 +666,7 @@ struct TechmapWorker
if (extmapper_name == "simplemap") {
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);
}
@@ -686,7 +677,7 @@ struct TechmapWorker
}
module->remove(cell);
- cell = NULL;
+ cell = nullptr;
}
did_something = true;
@@ -694,10 +685,10 @@ struct TechmapWorker
break;
}
- for (auto conn : cell->connections()) {
+ for (auto &conn : cell->connections()) {
if (conn.first.begins_with("$"))
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;
if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0)
goto next_tpl;
@@ -710,23 +701,23 @@ struct TechmapWorker
}
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()) {
- if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ for (auto &conn : cell->connections()) {
+ 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();
for (auto &bit : v)
- bit = RTLIL::SigBit(bit.wire == NULL ? RTLIL::State::S1 : RTLIL::State::S0);
- parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
+ bit = RTLIL::SigBit(bit.wire == nullptr ? RTLIL::State::S1 : RTLIL::State::S0);
+ 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();
for (auto &bit : v)
- if (bit.wire != NULL)
+ if (bit.wire != nullptr)
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);
RTLIL::Const value(State::Sx, sig.size());
for (int i = 0; i < sig.size(); i++) {
@@ -735,20 +726,20 @@ struct TechmapWorker
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;
- 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::S1] = unique_bit_id_counter++;
unique_bit_id[RTLIL::State::Sx] = unique_bit_id_counter++;
unique_bit_id[RTLIL::State::Sz] = unique_bit_id_counter++;
- for (auto conn : cell->connections())
- if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) {
- for (auto &bit : sigmap(conn.second).to_sigbit_vector())
+ for (auto &conn : cell->connections())
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))) != 0) {
+ for (auto &bit : sigmap(conn.second))
if (unique_bit_id.count(bit) == 0)
unique_bit_id[bit] = unique_bit_id_counter++;
}
@@ -763,14 +754,17 @@ struct TechmapWorker
if (tpl->avail_parameters.count(ID::_TECHMAP_BITS_CONNMAP_))
parameters[ID::_TECHMAP_BITS_CONNMAP_] = bits;
- for (auto conn : cell->connections())
- if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ for (auto &conn : cell->connections())
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))) != 0) {
RTLIL::Const value;
- for (auto &bit : sigmap(conn.second).to_sigbit_vector()) {
- RTLIL::Const chunk(unique_bit_id.at(bit), bits);
- value.bits.insert(value.bits.end(), chunk.bits.begin(), chunk.bits.end());
+ for (auto &bit : sigmap(conn.second)) {
+ int val = unique_bit_id.at(bit);
+ 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:;
// do not register techmap_wrap modules with techmap_cache
} else {
- std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters);
- if (techmap_cache.count(key) > 0) {
- tpl = techmap_cache[key];
+ std::pair<IdString, dict<IdString, RTLIL::Const>> key(tpl_name, parameters);
+ auto it = techmap_cache.find(key);
+ if (it != techmap_cache.end()) {
+ tpl = it->second;
} else {
if (parameters.size() != 0) {
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);
log_continue = true;
}
- techmap_cache[key] = tpl;
+ techmap_cache.emplace(std::move(key), tpl);
}
}
@@ -805,7 +800,7 @@ struct TechmapWorker
bool keep_running = true;
techmap_do_cache[tpl] = true;
- std::set<std::string> techmap_wire_names;
+ pool<IdString> techmap_wire_names;
while (keep_running)
{
@@ -815,11 +810,11 @@ struct TechmapWorker
for (auto &it : twd)
techmap_wire_names.insert(it.first);
- for (auto &it : twd["_TECHMAP_FAIL_"]) {
+ for (auto &it : twd[ID::_TECHMAP_FAIL_]) {
RTLIL::SigSpec value = it.value;
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",
- 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;
}
}
@@ -829,13 +824,13 @@ struct TechmapWorker
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;
auto &data = it.second.front();
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);
@@ -851,7 +846,7 @@ struct TechmapWorker
cmd_string = cmd_string.substr(strlen("CONSTMAP; "));
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_assert(map->module(new_tpl_name) == nullptr);
@@ -862,16 +857,16 @@ struct TechmapWorker
techmap_do_cache[new_tpl] = true;
tpl = new_tpl;
- std::map<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map;
- std::map<RTLIL::SigBit, RTLIL::SigBit> port_connmap;
- std::map<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits;
+ dict<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map;
+ dict<RTLIL::SigBit, RTLIL::SigBit> port_connmap;
+ dict<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits;
for (auto wire : tpl->wires().to_vector())
{
if (!wire->port_input || wire->port_output)
continue;
- RTLIL::IdString port_name = wire->name;
+ IdString port_name = wire->name;
tpl->rename(wire, NEW_ID);
RTLIL::Wire *new_wire = tpl->addWire(port_name, wire);
@@ -879,12 +874,12 @@ struct TechmapWorker
wire->port_id = 0;
for (int i = 0; i < wire->width; i++) {
- port_new2old_map[RTLIL::SigBit(new_wire, i)] = RTLIL::SigBit(wire, i);
- port_connmap[RTLIL::SigBit(wire, i)] = RTLIL::SigBit(new_wire, i);
+ port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), RTLIL::SigBit(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++)
{
RTLIL::SigBit bit = sigmap(conn.second[i]);
@@ -926,7 +921,7 @@ struct TechmapWorker
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);
- while (tpl->wires_.count(new_name))
+ while (tpl->wire(new_name) != nullptr)
new_name += "_";
tpl->rename(data.wire->name, new_name);
@@ -937,17 +932,17 @@ struct TechmapWorker
TechmapWires twd = techmap_find_special_wires(tpl);
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_")
- log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str());
+ 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", log_id(it.first));
if (techmap_do_cache[tpl])
for (auto &it2 : it.second)
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);
}
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 (log_continue) {
@@ -970,10 +965,10 @@ struct TechmapWorker
TechmapWires twd = techmap_find_special_wires(tpl);
for (auto &it : twd) {
- if (it.first.substr(0, 20) == "_TECHMAP_REMOVEINIT_") {
+ if (it.first.begins_with("\\_TECHMAP_REMOVEINIT_")) {
for (auto &it2 : it.second) {
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);
if (it != cell->connections().end()) {
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));
techmap_module_worker(design, module, cell, tpl);
- cell = NULL;
+ cell = nullptr;
}
did_something = true;
mapped_cell = true;
@@ -1275,8 +1270,7 @@ struct TechmapPass : public Pass {
RTLIL::Design *map = new RTLIL::Design;
if (map_files.empty()) {
- std::istringstream f(stdcells_code);
- Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend);
+ Frontend::frontend_call(map, nullptr, "+/techmap.v", verilog_frontend);
} else {
for (auto &fn : map_files)
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);
}
for (auto mod : saved_designs.at(fn.substr(1))->modules())
- if (!map->has(mod->name))
+ if (!map->module(mod->name))
map->add(mod->clone());
} else {
- std::ifstream f;
- 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));
+ Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend));
}
}
log_header(design, "Continuing TECHMAP pass.\n");
- std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
- for (auto &it : map->modules_) {
- if (it.second->attributes.count(ID::techmap_celltype) && !it.second->attributes.at(ID::techmap_celltype).bits.empty()) {
- char *p = strdup(it.second->attributes.at(ID::techmap_celltype).decode_string().c_str());
- for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n"))
- celltypeMap[RTLIL::escape_id(q)].insert(it.first);
+ dict<IdString, pool<IdString>> celltypeMap;
+ for (auto module : map->modules()) {
+ if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) {
+ char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str());
+ for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n"))
+ celltypeMap[RTLIL::escape_id(q)].insert(module->name);
free(p);
} else {
- string module_name = it.first.str();
- if (it.first.begins_with("\\$"))
- module_name = module_name.substr(1);
- celltypeMap[module_name].insert(it.first);
+ IdString module_name = module->name.begins_with("\\$") ?
+ module->name.substr(1) : module->name.str();
+ celltypeMap[module_name].insert(module->name);
}
}
+ for (auto &i : celltypeMap)
+ i.second.sort(RTLIL::sort_by_id_str());
for (auto module : design->modules())
worker.module_queue.insert(module);
@@ -1325,7 +1314,7 @@ struct TechmapPass : public Pass {
int module_max_iter = max_iter;
bool did_something = true;
- std::set<RTLIL::Cell*> handled_cells;
+ pool<RTLIL::Cell*> handled_cells;
while (did_something) {
did_something = 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);
- std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
+ dict<IdString, pool<IdString>> celltypeMap;
for (auto module : design->modules())
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())
for (auto mod : design->modules())
if (mod->get_bool_attribute(ID::top))
top_mod = mod;
- std::set<RTLIL::Cell*> handled_cells;
- if (top_mod != NULL) {
+ pool<RTLIL::Cell*> handled_cells;
+ if (top_mod != nullptr) {
worker.flatten_do_list.insert(top_mod->name);
while (!worker.flatten_do_list.empty()) {
auto mod = design->module(*worker.flatten_do_list.begin());
@@ -1402,20 +1393,19 @@ struct FlattenPass : public Pass {
worker.flatten_do_list.erase(mod->name);
}
} 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)) { }
- }
}
log_suppressed();
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);
while (!new_used_modules.empty()) {
- pool<RTLIL::IdString> queue;
+ pool<IdString> queue;
queue.swap(new_used_modules);
for (auto modname : queue)
used_modules.insert(modname);
@@ -1425,15 +1415,11 @@ struct FlattenPass : public Pass {
new_used_modules.insert(cell->type);
}
- dict<RTLIL::IdString, RTLIL::Module*> new_modules;
- for (auto mod : vector<Module*>(design->modules()))
- if (used_modules[mod->name] || mod->get_blackbox_attribute(worker.ignore_wb)) {
- new_modules[mod->name] = mod;
- } else {
+ for (auto mod : design->modules().to_vector())
+ if (!used_modules[mod->name] && !mod->get_blackbox_attribute(worker.ignore_wb)) {
log("Deleting now unused module %s.\n", log_id(mod));
- delete mod;
+ design->remove(mod);
}
- design->modules_.swap(new_modules);
}
log_pop();
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
index cdbe922b2..c6801007d 100644
--- a/passes/tests/test_cell.cc
+++ b/passes/tests/test_cell.cc
@@ -264,7 +264,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
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 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));
@@ -839,6 +839,8 @@ struct TestCellPass : public Pass {
cell_types[ID($mul)] = "ABSY";
cell_types[ID($div)] = "ABSY";
cell_types[ID($mod)] = "ABSY";
+ cell_types[ID($divfloor)] = "ABSY";
+ cell_types[ID($modfloor)] = "ABSY";
// cell_types[ID($pow)] = "ABsY";
cell_types[ID($logic_not)] = "ASY";
diff --git a/techlibs/achronix/speedster22i/cells_arith.v b/techlibs/achronix/speedster22i/cells_arith.v
index e2194cbd7..8529706a7 100644
--- a/techlibs/achronix/speedster22i/cells_arith.v
+++ b/techlibs/achronix/speedster22i/cells_arith.v
@@ -26,8 +26,11 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
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;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
//wire [Y_WIDTH:0] C = {CO, CI};
wire [Y_WIDTH+1:0] COx;
diff --git a/techlibs/achronix/speedster22i/cells_map.v b/techlibs/achronix/speedster22i/cells_map.v
index 9f647cbef..a19e53f49 100644
--- a/techlibs/achronix/speedster22i/cells_map.v
+++ b/techlibs/achronix/speedster22i/cells_map.v
@@ -38,6 +38,7 @@ endmodule
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
generate
diff --git a/techlibs/anlogic/arith_map.v b/techlibs/anlogic/arith_map.v
index 1186543da..23e190bcb 100644
--- a/techlibs/anlogic/arith_map.v
+++ b/techlibs/anlogic/arith_map.v
@@ -26,24 +26,33 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
input CI, BI;
+ (* force_downto *)
output [Y_WIDTH-1:0] CO;
wire CIx;
+ (* force_downto *)
wire [Y_WIDTH-1:0] COx;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* 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] C = { COx, CIx };
wire dummy;
diff --git a/techlibs/anlogic/cells_map.v b/techlibs/anlogic/cells_map.v
index 8ac087d9d..0bcea9856 100644
--- a/techlibs/anlogic/cells_map.v
+++ b/techlibs/anlogic/cells_map.v
@@ -32,6 +32,7 @@ module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc
index 7b1e4b430..607e772a2 100644
--- a/techlibs/common/Makefile.inc
+++ b/techlibs/common/Makefile.inc
@@ -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/mul2dsp.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))
diff --git a/techlibs/common/abc9_map.v b/techlibs/common/abc9_map.v
new file mode 100644
index 000000000..6ed90b5f5
--- /dev/null
+++ b/techlibs/common/abc9_map.v
@@ -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
diff --git a/techlibs/common/abc9_model.v b/techlibs/common/abc9_model.v
index c0c5dc2fd..4fee60f75 100644
--- a/techlibs/common/abc9_model.v
+++ b/techlibs/common/abc9_model.v
@@ -1,10 +1,25 @@
-module \$__ABC9_FF_ (input D, output Q);
-endmodule
-
(* abc9_box *)
-module \$__ABC9_DELAY (input I, output O);
+module $__ABC9_DELAY (input I, output O);
parameter DELAY = 0;
specify
(I => O) = DELAY;
endspecify
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
diff --git a/techlibs/common/abc9_unmap.v b/techlibs/common/abc9_unmap.v
new file mode 100644
index 000000000..bcbe91477
--- /dev/null
+++ b/techlibs/common/abc9_unmap.v
@@ -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
diff --git a/techlibs/common/adff2dff.v b/techlibs/common/adff2dff.v
index 86744d415..eca0110eb 100644
--- a/techlibs/common/adff2dff.v
+++ b/techlibs/common/adff2dff.v
@@ -6,8 +6,11 @@ module adff2dff (CLK, ARST, D, Q);
parameter ARST_VALUE = 0;
input CLK, ARST;
+ (* force_downto *)
input [WIDTH-1:0] D;
+ (* force_downto *)
output reg [WIDTH-1:0] Q;
+ (* force_downto *)
wire reg [WIDTH-1:0] NEXT_Q;
wire [1023:0] _TECHMAP_DO_ = "proc;;";
diff --git a/techlibs/common/cmp2lcu.v b/techlibs/common/cmp2lcu.v
index b6f4aeed6..a221727e7 100644
--- a/techlibs/common/cmp2lcu.v
+++ b/techlibs/common/cmp2lcu.v
@@ -12,8 +12,11 @@ parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
+(* force_downto *)
input [A_WIDTH-1:0] A;
+(* force_downto *)
input [B_WIDTH-1:0] B;
+(* force_downto *)
output [Y_WIDTH-1:0] Y;
parameter _TECHMAP_CELLTYPE_ = "";
@@ -32,7 +35,9 @@ generate
else begin
// Perform sign extension on A and B
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};
+ (* force_downto *)
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
// 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 CI = 0;
+(* force_downto *)
input [AB_WIDTH-1:0] A; // A from original $gt/$ge
+(* force_downto *)
input [AB_WIDTH-1:0] B; // B from original $gt/$ge
+(* force_downto *)
input [LCU_WIDTH-1:0] P; // P of $lcu
+(* force_downto *)
input [LCU_WIDTH-1:0] G; // G of $lcu
output Y;
@@ -66,6 +75,7 @@ parameter [LCU_WIDTH-1:0] _TECHMAP_CONSTMSK_P_ = 0;
generate
if (AB_WIDTH == 0) begin
+ (* force_downto *)
wire [LCU_WIDTH-1:0] CO;
$lcu #(.WIDTH(LCU_WIDTH)) _TECHMAP_REPLACE_ (.P(P), .G(G), .CI(CI), .CO(CO));
assign Y = CO[LCU_WIDTH-1];
@@ -104,12 +114,18 @@ generate
else begin
// Propagate only if all pairs are equal
// (inconclusive evidence to say A >= B)
+ (* force_downto *)
wire [LCU_WIDTH-1:0] P_ = {P[LCU_WIDTH-1:1], P[0] & PP};
// Generate if any comparisons call for it
+ (* force_downto *)
wire [LCU_WIDTH-1:0] G_ = {G[LCU_WIDTH-1:1], G[0] | GG};
end
- $__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));
+ if (AB_WIDTH == 1)
+ $__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
endgenerate
diff --git a/techlibs/common/cmp2lut.v b/techlibs/common/cmp2lut.v
index 8ecd356cc..ec8f98e8d 100644
--- a/techlibs/common/cmp2lut.v
+++ b/techlibs/common/cmp2lut.v
@@ -16,8 +16,11 @@ parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
+(* force_downto *)
input [A_WIDTH-1:0] A;
+(* force_downto *)
input [B_WIDTH-1:0] B;
+(* force_downto *)
output [Y_WIDTH-1:0] Y;
parameter _TECHMAP_CELLTYPE_ = "";
diff --git a/techlibs/common/dff2ff.v b/techlibs/common/dff2ff.v
index 2dc4d20d3..33a79ffff 100644
--- a/techlibs/common/dff2ff.v
+++ b/techlibs/common/dff2ff.v
@@ -4,7 +4,9 @@ module dff2ff (CLK, D, Q);
parameter CLK_POLARITY = 1;
input CLK;
+ (* force_downto *)
input [WIDTH-1:0] D;
+ (* force_downto *)
output reg [WIDTH-1:0] Q;
wire [1023:0] _TECHMAP_DO_ = "proc;;";
diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v
index 4cabb4453..bec47d01f 100644
--- a/techlibs/common/mul2dsp.v
+++ b/techlibs/common/mul2dsp.v
@@ -57,8 +57,11 @@ module _80_mul (A, B, Y);
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;
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_Y_WIDTH = B_WIDTH+last_A_WIDTH;
if (A_SIGNED && B_SIGNED) begin
+ (* force_downto *)
wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire signed [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end
else begin
+ (* force_downto *)
wire [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire [Y_WIDTH-1:0] partial_sum [n:0];
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_Y_WIDTH = A_WIDTH+last_B_WIDTH;
if (A_SIGNED && B_SIGNED) begin
+ (* force_downto *)
wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire signed [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end
else begin
+ (* force_downto *)
wire [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire [Y_WIDTH-1:0] partial_sum [n:0];
end
@@ -249,8 +264,11 @@ module _90_soft_mul (A, B, Y);
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;
// Indirection necessary since mapping
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index 2cdddeabb..125b8e013 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -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);
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);
parameter A_SIGNED = 0;
@@ -1044,6 +1058,83 @@ endgenerate
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
module \$pow (A, B, Y);
diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v
index ecf4d5dc5..eafe8d4da 100644
--- a/techlibs/common/techmap.v
+++ b/techlibs/common/techmap.v
@@ -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 sign_extend = A_SIGNED && _TECHMAP_CELLTYPE_ == "$sshr";
+ (* force_downto *)
input [A_WIDTH-1:0] A;
+ (* force_downto *)
input [B_WIDTH-1:0] B;
+ (* force_downto *)
output [Y_WIDTH-1:0] Y;
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;;;";
integer i;
+ (* force_downto *)
reg [WIDTH-1:0] buffer;
reg overflow;
@@ -125,8 +129,11 @@ module _90_shift_shiftx (A, B, Y);
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;
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;;;";
integer i;
+ (* force_downto *)
reg [WIDTH-1:0] buffer;
reg overflow;
@@ -216,9 +224,12 @@ endmodule
module _90_fa (A, B, C, X, Y);
parameter WIDTH = 1;
+ (* force_downto *)
input [WIDTH-1:0] A, B, C;
+ (* force_downto *)
output [WIDTH-1:0] X, Y;
+ (* force_downto *)
wire [WIDTH-1:0] t1, t2, t3;
assign t1 = A ^ B, t2 = A & B, t3 = C & t1;
@@ -229,12 +240,15 @@ endmodule
module _90_lcu (P, G, CI, CO);
parameter WIDTH = 2;
+ (* force_downto *)
input [WIDTH-1:0] P, G;
input CI;
+ (* force_downto *)
output [WIDTH-1:0] CO;
integer i, j;
+ (* force_downto *)
reg [WIDTH-1:0] p, g;
wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast";
@@ -278,20 +292,27 @@ module _90_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
input CI, BI;
+ (* force_downto *)
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;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
- wire [Y_WIDTH-1:0] AA = A_buf;
- wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
-
\$lcu #(.WIDTH(Y_WIDTH)) lcu (.P(X), .G(AA & BB), .CI(CI), .CO(CO));
assign X = AA ^ BB;
@@ -316,15 +337,19 @@ endmodule
module \$__div_mod_u (A, B, Y, R);
parameter WIDTH = 1;
+ (* force_downto *)
input [WIDTH-1:0] A, B;
+ (* force_downto *)
output [WIDTH-1:0] Y, R;
+ (* force_downto *)
wire [WIDTH*WIDTH-1:0] chaindata;
assign R = chaindata[WIDTH*WIDTH-1:WIDTH*(WIDTH-1)];
genvar i;
generate begin
for (i = 0; i < WIDTH; i=i+1) begin:stage
+ (* force_downto *)
wire [WIDTH-1:0] stage_in;
if (i == 0) begin:cp
@@ -339,7 +364,8 @@ module \$__div_mod_u (A, B, Y, R);
end endgenerate
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 B_SIGNED = 0;
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 :
B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
+ (* force_downto *)
input [A_WIDTH-1:0] A;
+ (* force_downto *)
input [B_WIDTH-1:0] B;
+ (* force_downto *)
output [Y_WIDTH-1:0] Y, R;
+ (* force_downto *)
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));
+ (* force_downto *)
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 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 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 #(
+ \$__div_mod_trunc #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH),
@@ -408,11 +442,114 @@ module _90_mod (A, B, Y);
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_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 #(
+ \$__div_mod_floor #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH),
@@ -438,8 +575,11 @@ module _90_pow (A, B, Y);
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;
wire _TECHMAP_FAIL_ = 1;
@@ -455,20 +595,27 @@ module _90_pmux (A, B, S, Y);
parameter WIDTH = 1;
parameter S_WIDTH = 1;
+ (* force_downto *)
input [WIDTH-1:0] A;
+ (* force_downto *)
input [WIDTH*S_WIDTH-1:0] B;
+ (* force_downto *)
input [S_WIDTH-1:0] S;
+ (* force_downto *)
output [WIDTH-1:0] Y;
+ (* force_downto *)
wire [WIDTH-1:0] Y_B;
genvar i, j;
generate
+ (* force_downto *)
wire [WIDTH*S_WIDTH-1:0] B_AND_S;
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]}};
end:B_AND
for (i = 0; i < WIDTH; i = i + 1) begin:B_OR
+ (* force_downto *)
wire [S_WIDTH-1:0] B_AND_BITS;
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];
diff --git a/techlibs/coolrunner2/cells_counter_map.v b/techlibs/coolrunner2/cells_counter_map.v
index b474fa522..f9c44c80f 100644
--- a/techlibs/coolrunner2/cells_counter_map.v
+++ b/techlibs/coolrunner2/cells_counter_map.v
@@ -3,6 +3,7 @@ module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP);
input wire CE;
input wire CLK;
output wire OUT;
+ (* force_downto *)
output wire[WIDTH-1:0] POUT;
input wire RST;
input wire UP;
diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc
index 217151e96..9d564c78c 100644
--- a/techlibs/ecp5/Makefile.inc
+++ b/techlibs/ecp5/Makefile.inc
@@ -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/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
.SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
diff --git a/techlibs/ecp5/abc9_map.v b/techlibs/ecp5/abc9_map.v
deleted file mode 100644
index 113a35b91..000000000
--- a/techlibs/ecp5/abc9_map.v
+++ /dev/null
@@ -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
diff --git a/techlibs/ecp5/abc9_model.v b/techlibs/ecp5/abc9_model.v
deleted file mode 100644
index b7ecd7358..000000000
--- a/techlibs/ecp5/abc9_model.v
+++ /dev/null
@@ -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
diff --git a/techlibs/ecp5/abc9_unmap.v b/techlibs/ecp5/abc9_unmap.v
deleted file mode 100644
index cbdffdaf1..000000000
--- a/techlibs/ecp5/abc9_unmap.v
+++ /dev/null
@@ -1,5 +0,0 @@
-// ---------------------------------------
-
-module \$__ABC9_DPR16X4_COMB (input [3:0] $DO, RAD, output [3:0] DO);
- assign DO = $DO;
-endmodule
diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v
index 17bde0497..ffd42469c 100644
--- a/techlibs/ecp5/arith_map.v
+++ b/techlibs/ecp5/arith_map.v
@@ -26,15 +26,20 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
input CI, BI;
+ (* force_downto *)
output [Y_WIDTH-1:0] CO;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
@@ -48,10 +53,15 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO);
localparam Y_WIDTH2 = round_up2(Y_WIDTH);
+ (* force_downto *)
wire [Y_WIDTH2-1:0] AA = A_buf;
+ (* force_downto *)
wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf;
+ (* force_downto *)
wire [Y_WIDTH2-1:0] BX = B_buf;
+ (* force_downto *)
wire [Y_WIDTH2-1:0] C = {CO, CI};
+ (* force_downto *)
wire [Y_WIDTH2-1:0] FCO, Y1;
genvar i;
diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v
index ae124e7a3..756f05366 100644
--- a/techlibs/ecp5/cells_bb.v
+++ b/techlibs/ecp5/cells_bb.v
@@ -652,6 +652,10 @@ module DCUA(
parameter CH1_PROTOCOL = "8B10B";
parameter CH0_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
(* blackbox *)
diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v
index c031703a9..e19ac9ab9 100644
--- a/techlibs/ecp5/cells_map.v
+++ b/techlibs/ecp5/cells_map.v
@@ -70,6 +70,7 @@ module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v
index 12b33e925..357fd9173 100644
--- a/techlibs/ecp5/cells_sim.v
+++ b/techlibs/ecp5/cells_sim.v
@@ -186,6 +186,7 @@ module PFUMX (input ALUT, BLUT, C0, output Z);
endmodule
// ---------------------------------------
+(* abc9_box, lib_whitebox *)
module TRELLIS_DPR16X4 (
input [3:0] DI,
input [3:0] WAD,
@@ -222,10 +223,16 @@ module TRELLIS_DPR16X4 (
mem[WAD] <= DI;
assign DO = mem[RAD];
+
+ specify
+ // TODO
+ (RAD *> DO) = 0;
+ endspecify
endmodule
// ---------------------------------------
+(* abc9_box, lib_whitebox *)
module DPR16X4C (
input [3:0] DI,
input WCK, WRE,
@@ -281,6 +288,10 @@ module DPR16X4C (
assign DO = ram[RAD];
+ specify
+ // TODO
+ (RAD *> DO) = 0;
+ endspecify
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);
parameter GSR = "ENABLED";
parameter [127:0] CEMUX = "1";
@@ -340,6 +354,38 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
Q <= DI;
end
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
// ---------------------------------------
diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc
index b9b236a0c..aceb36abc 100644
--- a/techlibs/ecp5/synth_ecp5.cc
+++ b/techlibs/ecp5/synth_ecp5.cc
@@ -66,6 +66,9 @@ struct SynthEcp5Pass : public ScriptPass
log(" -noflatten\n");
log(" do not flatten design before synthesis\n");
log("\n");
+ log(" -dff\n");
+ log(" run 'abc'/'abc9' with -dff option\n");
+ log("\n");
log(" -retime\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
@@ -107,7 +110,7 @@ struct SynthEcp5Pass : public ScriptPass
}
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
{
@@ -122,6 +125,7 @@ struct SynthEcp5Pass : public ScriptPass
nowidelut = false;
asyncprld = false;
flatten = true;
+ dff = false;
retime = false;
abc2 = false;
vpr = false;
@@ -169,6 +173,10 @@ struct SynthEcp5Pass : public ScriptPass
flatten = false;
continue;
}
+ if (args[argidx] == "-dff") {
+ dff = true;
+ continue;
+ }
if (args[argidx] == "-retime") {
retime = true;
continue;
@@ -307,6 +315,8 @@ struct SynthEcp5Pass : public ScriptPass
run("opt_clean");
if (!nodffe)
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("opt_expr -undriven -mux_undef");
run("simplemap");
@@ -318,17 +328,12 @@ struct SynthEcp5Pass : public ScriptPass
if (check_label("map_luts"))
{
- if (abc2 || help_mode) {
+ if (abc2 || help_mode)
run("abc", " (only if -abc2)");
- }
- std::string techmap_args = asyncprld ? "" : "-map +/ecp5/latches_map.v";
- if (abc9)
- techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1";
- if (!asyncprld || abc9)
- run("techmap " + techmap_args);
+ if (!asyncprld || help_mode)
+ run("techmap -map +/ecp5/latches_map.v", "(skip if -asyncprld)");
if (abc9) {
- run("read_verilog -icells -lib -specify +/abc9_model.v +/ecp5/abc9_model.v");
std::string abc9_opts;
if (nowidelut)
abc9_opts += " -maxlut 4";
@@ -338,26 +343,29 @@ struct SynthEcp5Pass : public ScriptPass
else
abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str());
if (nowidelut)
- run("abc9 -maxlut 4 -W 200");
- else
- run("abc9 -W 200");
- run("techmap -map +/ecp5/abc9_unmap.v");
+ abc9_opts += " -maxlut 4";
+ if (dff)
+ abc9_opts += " -dff";
+ run("abc9" + abc9_opts);
} else {
+ std::string abc_args = " -dress";
if (nowidelut)
- run("abc -lut 4 -dress");
+ abc_args += " -lut 4";
else
- run("abc -lut 4:7 -dress");
+ abc_args += " -lut 4:7";
+ if (dff)
+ abc_args += " -dff";
+ run("abc" + abc_args);
}
run("clean");
}
if (check_label("map_cells"))
{
- if (vpr)
- run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
- else
- run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)");
-
+ if (help_mode)
+ run("techmap -map +/ecp5/cells_map.v", "(skip if -vpr)");
+ else if (!vpr)
+ run("techmap -map +/ecp5/cells_map.v");
run("opt_lut_ins -tech ecp5");
run("clean");
}
diff --git a/techlibs/efinix/arith_map.v b/techlibs/efinix/arith_map.v
index 178f57bc5..4dac360b9 100644
--- a/techlibs/efinix/arith_map.v
+++ b/techlibs/efinix/arith_map.v
@@ -26,24 +26,33 @@ module _80_efinix_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
input CI, BI;
+ (* force_downto *)
output [Y_WIDTH-1:0] CO;
wire CIx;
+ (* force_downto *)
wire [Y_WIDTH-1:0] COx;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* 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] C = { COx, CIx };
EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))
@@ -76,4 +85,4 @@ module _80_efinix_alu (A, B, CI, BI, X, Y, CO);
/* End implementation */
assign X = AA ^ BB;
-endmodule \ No newline at end of file
+endmodule
diff --git a/techlibs/efinix/cells_map.v b/techlibs/efinix/cells_map.v
index 3ecec3bac..1090f8b27 100644
--- a/techlibs/efinix/cells_map.v
+++ b/techlibs/efinix/cells_map.v
@@ -34,6 +34,7 @@ module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
diff --git a/techlibs/gowin/arith_map.v b/techlibs/gowin/arith_map.v
index b6f9e8c38..42aaba870 100644
--- a/techlibs/gowin/arith_map.v
+++ b/techlibs/gowin/arith_map.v
@@ -26,21 +26,29 @@ module _80_gw1n_alu(A, B, CI, BI, X, Y, CO);
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] X, Y;
input CI, BI;
+ (* force_downto *)
output [Y_WIDTH-1:0] CO;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
wire [Y_WIDTH-1:0] BB = B_buf;
+ (* force_downto *)
wire [Y_WIDTH-1:0] C = {CO, CI};
genvar i;
diff --git a/techlibs/gowin/cells_map.v b/techlibs/gowin/cells_map.v
index aee912256..b44350616 100644
--- a/techlibs/gowin/cells_map.v
+++ b/techlibs/gowin/cells_map.v
@@ -232,6 +232,7 @@ module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
diff --git a/techlibs/greenpak4/cells_map.v b/techlibs/greenpak4/cells_map.v
index 51c85183d..316be3f73 100644
--- a/techlibs/greenpak4/cells_map.v
+++ b/techlibs/greenpak4/cells_map.v
@@ -115,6 +115,7 @@ module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
@@ -150,6 +151,7 @@ module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP);
input wire CE;
input wire CLK;
output reg OUT;
+ (* force_downto *)
output reg[WIDTH-1:0] POUT;
input wire RST;
input wire UP;
diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc
index b9e504a9d..1a8caf9a9 100644
--- a/techlibs/ice40/Makefile.inc
+++ b/techlibs/ice40/Makefile.inc
@@ -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/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/latches_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt))
diff --git a/techlibs/ice40/arith_map.v b/techlibs/ice40/arith_map.v
index ed4140e44..3950e882b 100644
--- a/techlibs/ice40/arith_map.v
+++ b/techlibs/ice40/arith_map.v
@@ -25,21 +25,29 @@ module _80_ice40_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
input CI, BI;
+ (* force_downto *)
output [Y_WIDTH-1:0] CO;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* 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] C = {CO, CI};
genvar i;
diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v
index d5362eb83..7e5c07879 100644
--- a/techlibs/ice40/cells_map.v
+++ b/techlibs/ice40/cells_map.v
@@ -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);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
@@ -59,4 +30,3 @@ module \$lut (A, Y);
end
endgenerate
endmodule
-`endif
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index 6a0e3031e..ad572c877 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -245,6 +245,7 @@ endmodule
// Positive Edge SiliconBlue FF Cells
+(* abc9_flop, lib_whitebox *)
module SB_DFF (
output `SB_DFF_REG,
input C, D
@@ -280,6 +281,7 @@ module SB_DFF (
`endif
endmodule
+(* abc9_flop, lib_whitebox *)
module SB_DFFE (
output `SB_DFF_REG,
input C, E, D
@@ -322,6 +324,7 @@ module SB_DFFE (
`endif
endmodule
+(* abc9_flop, lib_whitebox *)
module SB_DFFSR (
output `SB_DFF_REG,
input C, R, D
@@ -369,6 +372,7 @@ module SB_DFFSR (
`endif
endmodule
+(* abc9_box, lib_whitebox *)
module SB_DFFR (
output `SB_DFF_REG,
input C, R, D
@@ -386,7 +390,13 @@ module SB_DFFR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge R, posedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
+`ifndef YOSYS
(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
if (!R) (posedge C => (Q : D)) = 540;
endspecify
@@ -399,7 +409,13 @@ module SB_DFFR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge R, posedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
+`ifndef YOSYS
(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
if (!R) (posedge C => (Q : D)) = 796;
endspecify
@@ -412,13 +428,20 @@ module SB_DFFR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge R, posedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
+`ifndef YOSYS
(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
if (!R) (posedge C => (Q : D)) = 1391;
endspecify
`endif
endmodule
+(* abc9_flop, lib_whitebox *)
module SB_DFFSS (
output `SB_DFF_REG,
input C, S, D
@@ -466,6 +489,7 @@ module SB_DFFSS (
`endif
endmodule
+(* abc9_box, lib_whitebox *)
module SB_DFFS (
output `SB_DFF_REG,
input C, S, D
@@ -483,7 +507,13 @@ module SB_DFFS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge S, posedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
+`ifndef YOSYS
(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
if (!S) (posedge C => (Q : D)) = 540;
endspecify
@@ -496,7 +526,13 @@ module SB_DFFS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge S, posedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
+`ifndef YOSYS
(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
if (!S) (posedge C => (Q : D)) = 796;
endspecify
@@ -509,13 +545,20 @@ module SB_DFFS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge S, posedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
+`ifndef YOSYS
(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
if (!S) (posedge C => (Q : D)) = 1391;
endspecify
`endif
endmodule
+(* abc9_flop, lib_whitebox *)
module SB_DFFESR (
output `SB_DFF_REG,
input C, E, R, D
@@ -571,6 +614,7 @@ module SB_DFFESR (
`endif
endmodule
+(* abc9_box, lib_whitebox *)
module SB_DFFER (
output `SB_DFF_REG,
input C, E, R, D
@@ -590,7 +634,13 @@ module SB_DFFER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge R, posedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
+`ifndef YOSYS
(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
if (E && !R) (posedge C => (Q : D)) = 540;
endspecify
@@ -605,7 +655,13 @@ module SB_DFFER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge R, posedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
+`ifndef YOSYS
(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
if (E && !R) (posedge C => (Q : D)) = 796;
endspecify
@@ -620,13 +676,20 @@ module SB_DFFER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge R, posedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
+`ifndef YOSYS
(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
if (E && !R) (posedge C => (Q : D)) = 1391;
endspecify
`endif
endmodule
+(* abc9_flop, lib_whitebox *)
module SB_DFFESS (
output `SB_DFF_REG,
input C, E, S, D
@@ -682,6 +745,7 @@ module SB_DFFESS (
`endif
endmodule
+(* abc9_box, lib_whitebox *)
module SB_DFFES (
output `SB_DFF_REG,
input C, E, S, D
@@ -701,7 +765,13 @@ module SB_DFFES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(posedge S, posedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
+`ifndef YOSYS
(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
if (E && !S) (posedge C => (Q : D)) = 540;
endspecify
@@ -716,7 +786,13 @@ module SB_DFFES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(posedge S, posedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
+`ifndef YOSYS
(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
if (E && !S) (posedge C => (Q : D)) = 796;
endspecify
@@ -731,7 +807,13 @@ module SB_DFFES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(posedge S, posedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
+`ifndef YOSYS
(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
if (E && !S) (posedge C => (Q : D)) = 1391;
endspecify
@@ -740,6 +822,7 @@ endmodule
// Negative Edge SiliconBlue FF Cells
+(* abc9_flop, lib_whitebox *)
module SB_DFFN (
output `SB_DFF_REG,
input C, D
@@ -775,6 +858,7 @@ module SB_DFFN (
`endif
endmodule
+(* abc9_flop, lib_whitebox *)
module SB_DFFNE (
output `SB_DFF_REG,
input C, E, D
@@ -817,6 +901,7 @@ module SB_DFFNE (
`endif
endmodule
+(* abc9_flop, lib_whitebox *)
module SB_DFFNSR (
output `SB_DFF_REG,
input C, R, D
@@ -864,6 +949,7 @@ module SB_DFFNSR (
`endif
endmodule
+(* abc9_flop, lib_whitebox *)
module SB_DFFNR (
output `SB_DFF_REG,
input C, R, D
@@ -881,7 +967,13 @@ module SB_DFFNR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge R, negedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
+`ifndef YOSYS
(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
if (!R) (negedge C => (Q : D)) = 540;
endspecify
@@ -894,7 +986,13 @@ module SB_DFFNR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge R, negedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
+`ifndef YOSYS
(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
if (!R) (negedge C => (Q : D)) = 796;
endspecify
@@ -907,13 +1005,20 @@ module SB_DFFNR (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge R, negedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
+`ifndef YOSYS
(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
if (!R) (negedge C => (Q : D)) = 1391;
endspecify
`endif
endmodule
+(* abc9_flop, lib_whitebox *)
module SB_DFFNSS (
output `SB_DFF_REG,
input C, S, D
@@ -961,6 +1066,7 @@ module SB_DFFNSS (
`endif
endmodule
+(* abc9_box, lib_whitebox *)
module SB_DFFNS (
output `SB_DFF_REG,
input C, S, D
@@ -978,7 +1084,13 @@ module SB_DFFNS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge S, negedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
+`ifndef YOSYS
(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
if (!S) (negedge C => (Q : D)) = 540;
endspecify
@@ -991,7 +1103,13 @@ module SB_DFFNS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge S, negedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
+`ifndef YOSYS
(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
if (!S) (negedge C => (Q : D)) = 796;
endspecify
@@ -1004,13 +1122,20 @@ module SB_DFFNS (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge S, negedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
+`ifndef YOSYS
(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
if (!S) (negedge C => (Q : D)) = 1391;
endspecify
`endif
endmodule
+(* abc9_flop, lib_whitebox *)
module SB_DFFNESR (
output `SB_DFF_REG,
input C, E, R, D
@@ -1066,6 +1191,7 @@ module SB_DFFNESR (
`endif
endmodule
+(* abc9_box, lib_whitebox *)
module SB_DFFNER (
output `SB_DFF_REG,
input C, E, R, D
@@ -1085,7 +1211,13 @@ module SB_DFFNER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(R, negedge C, 2160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
+`ifndef YOSYS
(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
if (E && !R) (negedge C => (Q : D)) = 540;
endspecify
@@ -1100,7 +1232,13 @@ module SB_DFFNER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(R, negedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
+`ifndef YOSYS
(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
if (E && !R) (negedge C => (Q : D)) = 796;
endspecify
@@ -1115,13 +1253,20 @@ module SB_DFFNER (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge R, negedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
+`ifndef YOSYS
(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
if (E && !R) (negedge C => (Q : D)) = 1391;
endspecify
`endif
endmodule
+(* abc9_flop, lib_whitebox *)
module SB_DFFNESS (
output `SB_DFF_REG,
input C, E, S, D
@@ -1177,6 +1322,7 @@ module SB_DFFNESS (
`endif
endmodule
+(* abc9_box, lib_whitebox *)
module SB_DFFNES (
output `SB_DFF_REG,
input C, E, S, D
@@ -1196,7 +1342,14 @@ module SB_DFFNES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63
$setup(negedge S, negedge C, 160);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91
+`ifndef YOSYS
(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
if (E && !S) (negedge C => (Q : D)) = 540;
endspecify
@@ -1211,7 +1364,13 @@ module SB_DFFNES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63
$setup(negedge S, negedge C, 235);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91
+`ifndef YOSYS
(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
if (E && !S) (negedge C => (Q : D)) = 796;
endspecify
@@ -1226,7 +1385,13 @@ module SB_DFFNES (
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75
$setup(negedge S, negedge C, 424);
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103
+`ifndef YOSYS
(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
if (E && !S) (negedge C => (Q : D)) = 1391;
endspecify
@@ -1908,7 +2073,7 @@ module ICESTORM_LC (
o_reg <= SR_pd ? SET_NORESET : lut_o;
reg o_reg_async = 1'b0;
- always @(posedge polarized_clk, posedge SR)
+ always @(posedge polarized_clk, posedge SR_pd)
if (SR_pd)
o_reg_async <= SET_NORESET;
else if (CEN_pu)
@@ -2723,6 +2888,7 @@ module SB_IO_OD (
`endif
endmodule
+//(* abc9_box, lib_whitebox *) // TODO
module SB_MAC16 (
input CLK, CE,
input [15:0] C, A, B, D,
diff --git a/techlibs/ice40/ff_map.v b/techlibs/ice40/ff_map.v
new file mode 100644
index 000000000..e8807e0bd
--- /dev/null
+++ b/techlibs/ice40/ff_map.v
@@ -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
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
index 2b211572d..27850b075 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -71,6 +71,9 @@ struct SynthIce40Pass : public ScriptPass
log(" -noflatten\n");
log(" do not flatten design before synthesis\n");
log("\n");
+ log(" -dff\n");
+ log(" run 'abc'/'abc9' with -dff option\n");
+ log("\n");
log(" -retime\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
@@ -113,7 +116,7 @@ struct SynthIce40Pass : public ScriptPass
}
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;
void clear_flags() YS_OVERRIDE
@@ -221,14 +224,18 @@ struct SynthIce40Pass : public ScriptPass
abc9 = true;
continue;
}
+ if (args[argidx] == "-dff") {
+ dff = true;
+ continue;
+ }
if (args[argidx] == "-device" && argidx+1 < args.size()) {
device_opt = args[++argidx];
continue;
}
- if (args[argidx] == "-flowmap") {
- flowmap = true;
- continue;
- }
+ if (args[argidx] == "-flowmap") {
+ flowmap = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -240,13 +247,12 @@ struct SynthIce40Pass : public ScriptPass
if (abc9 && retime)
log_cmd_error("-retime option not currently compatible with -abc9!\n");
-
- if (abc9 && noabc)
- log_cmd_error("-abc9 is incompatible with -noabc!\n");
- if (abc9 && flowmap)
- log_cmd_error("-abc9 is incompatible with -flowmap!\n");
- if (flowmap && noabc)
- log_cmd_error("-flowmap is incompatible with -noabc!\n");
+ if (abc9 && noabc)
+ log_cmd_error("-abc9 is incompatible with -noabc!\n");
+ if (abc9 && flowmap)
+ log_cmd_error("-abc9 is incompatible with -flowmap!\n");
+ if (flowmap && noabc)
+ log_cmd_error("-flowmap is incompatible with -noabc!\n");
log_header(design, "Executing SYNTH_ICE40 pass.\n");
log_push();
@@ -355,7 +361,9 @@ struct SynthIce40Pass : public ScriptPass
run(stringf("dff2dffe -unmap-mince %d", min_ce_use));
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("simplemap");
run("ice40_ffinit");
@@ -372,14 +380,14 @@ struct SynthIce40Pass : public ScriptPass
run("techmap -map +/ice40/latches_map.v");
if (noabc || flowmap || help_mode) {
run("simplemap", " (if -noabc or -flowmap)");
- if (noabc || help_mode)
- run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
- if (flowmap || help_mode)
- run("flowmap -maxlut 4", "(only if -flowmap)");
+ if (noabc || help_mode)
+ run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
+ if (flowmap || help_mode)
+ run("flowmap -maxlut 4", "(only if -flowmap)");
}
if (!noabc) {
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 k = "synth_ice40.abc9.W";
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());
abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str());
}
+ if (dff)
+ abc9_opts += " -dff";
run("abc9 " + abc9_opts);
}
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("techmap -D NO_LUT -map +/ice40/cells_map.v");
+ run("techmap -map +/ice40/ff_map.v");
run("clean");
run("opt_lut -dlogic SB_CARRY:I0=2:I1=1:CI=0");
}
if (check_label("map_cells"))
{
- if (vpr)
- run("techmap -D NO_LUT -map +/ice40/cells_map.v");
- else
- run("techmap -map +/ice40/cells_map.v", "(with -D NO_LUT in vpr mode)");
-
+ if (help_mode)
+ run("techmap -map +/ice40/cells_map.v", "(skip if -vpr)");
+ else if (!vpr)
+ run("techmap -map +/ice40/cells_map.v");
run("clean");
}
diff --git a/techlibs/intel/arria10gx/cells_arith.v b/techlibs/intel/arria10gx/cells_arith.v
index 89fb4561f..6a52a0f95 100644
--- a/techlibs/intel/arria10gx/cells_arith.v
+++ b/techlibs/intel/arria10gx/cells_arith.v
@@ -26,8 +26,11 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
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;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
//wire [Y_WIDTH:0] C = {CO, CI};
wire [Y_WIDTH+1:0] COx;
diff --git a/techlibs/intel/arria10gx/cells_map.v b/techlibs/intel/arria10gx/cells_map.v
index 1430e8551..83f5881da 100644
--- a/techlibs/intel/arria10gx/cells_map.v
+++ b/techlibs/intel/arria10gx/cells_map.v
@@ -30,6 +30,7 @@ endmodule
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
generate
diff --git a/techlibs/intel/cyclone10lp/cells_arith.v b/techlibs/intel/cyclone10lp/cells_arith.v
index 5ae8d6cea..d8c46e865 100644
--- a/techlibs/intel/cyclone10lp/cells_arith.v
+++ b/techlibs/intel/cyclone10lp/cells_arith.v
@@ -26,8 +26,11 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
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;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
//wire [Y_WIDTH:0] C = {CO, CI};
wire [Y_WIDTH+1:0] COx;
diff --git a/techlibs/intel/cyclone10lp/cells_map.v b/techlibs/intel/cyclone10lp/cells_map.v
index c2f6f403c..2a80ea678 100644
--- a/techlibs/intel/cyclone10lp/cells_map.v
+++ b/techlibs/intel/cyclone10lp/cells_map.v
@@ -71,6 +71,7 @@ endmodule
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
generate
diff --git a/techlibs/intel/cycloneiv/cells_arith.v b/techlibs/intel/cycloneiv/cells_arith.v
index 010a4b5da..f7bc3cd65 100644
--- a/techlibs/intel/cycloneiv/cells_arith.v
+++ b/techlibs/intel/cycloneiv/cells_arith.v
@@ -70,8 +70,11 @@ module _80_cycloneiv_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
input CI, BI;
@@ -79,11 +82,14 @@ module _80_cycloneiv_alu (A, B, CI, BI, X, Y, CO);
wire _TECHMAP_FAIL_ = Y_WIDTH < 6;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH:0] C = {CO, CI};
diff --git a/techlibs/intel/cycloneiv/cells_map.v b/techlibs/intel/cycloneiv/cells_map.v
index 191488430..9d8a5a2b7 100644
--- a/techlibs/intel/cycloneiv/cells_map.v
+++ b/techlibs/intel/cycloneiv/cells_map.v
@@ -71,6 +71,7 @@ endmodule
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
generate
diff --git a/techlibs/intel/cycloneive/arith_map.v b/techlibs/intel/cycloneive/arith_map.v
index 49e36aa25..a755e10db 100644
--- a/techlibs/intel/cycloneive/arith_map.v
+++ b/techlibs/intel/cycloneive/arith_map.v
@@ -66,8 +66,11 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
input CI, BI;
@@ -75,11 +78,14 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO);
wire _TECHMAP_FAIL_ = Y_WIDTH < 5;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH:0] C = {CO, CI};
diff --git a/techlibs/intel/cycloneive/cells_map.v b/techlibs/intel/cycloneive/cells_map.v
index abeb92eef..fead2837b 100644
--- a/techlibs/intel/cycloneive/cells_map.v
+++ b/techlibs/intel/cycloneive/cells_map.v
@@ -71,6 +71,7 @@ endmodule
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
generate
diff --git a/techlibs/intel/cyclonev/cells_arith.v b/techlibs/intel/cyclonev/cells_arith.v
index 89fb4561f..6a52a0f95 100644
--- a/techlibs/intel/cyclonev/cells_arith.v
+++ b/techlibs/intel/cyclonev/cells_arith.v
@@ -26,8 +26,11 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
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;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
//wire [Y_WIDTH:0] C = {CO, CI};
wire [Y_WIDTH+1:0] COx;
diff --git a/techlibs/intel/cyclonev/cells_map.v b/techlibs/intel/cyclonev/cells_map.v
index f8d142bc9..eb4cd54d1 100644
--- a/techlibs/intel/cyclonev/cells_map.v
+++ b/techlibs/intel/cyclonev/cells_map.v
@@ -71,6 +71,7 @@ endmodule
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
wire VCC;
diff --git a/techlibs/intel/max10/cells_arith.v b/techlibs/intel/max10/cells_arith.v
index e2194cbd7..8529706a7 100644
--- a/techlibs/intel/max10/cells_arith.v
+++ b/techlibs/intel/max10/cells_arith.v
@@ -26,8 +26,11 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
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;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
//wire [Y_WIDTH:0] C = {CO, CI};
wire [Y_WIDTH+1:0] COx;
diff --git a/techlibs/intel/max10/cells_map.v b/techlibs/intel/max10/cells_map.v
index 6d604e072..6a4072049 100644
--- a/techlibs/intel/max10/cells_map.v
+++ b/techlibs/intel/max10/cells_map.v
@@ -71,6 +71,7 @@ endmodule
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
generate
diff --git a/techlibs/intel_alm/common/alm_map.v b/techlibs/intel_alm/common/alm_map.v
index fe646c5d6..6697b2e78 100644
--- a/techlibs/intel_alm/common/alm_map.v
+++ b/techlibs/intel_alm/common/alm_map.v
@@ -3,6 +3,7 @@ module \$lut (A, Y);
parameter WIDTH = 1;
parameter LUT = 0;
+(* force_downto *)
input [WIDTH-1:0] A;
output Y;
diff --git a/techlibs/intel_alm/common/arith_alm_map.v b/techlibs/intel_alm/common/arith_alm_map.v
index ddf81d9d0..8515eeb56 100644
--- a/techlibs/intel_alm/common/arith_alm_map.v
+++ b/techlibs/intel_alm/common/arith_alm_map.v
@@ -11,17 +11,24 @@ parameter Y_WIDTH = 1;
parameter _TECHMAP_CONSTMSK_CI_ = 0;
parameter _TECHMAP_CONSTVAL_CI_ = 0;
+(* force_downto *)
input [A_WIDTH-1:0] A;
+(* force_downto *)
input [B_WIDTH-1:0] B;
input CI, BI;
+(* force_downto *)
output [Y_WIDTH-1:0] X, Y, CO;
+(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+(* 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] BX = B_buf;
wire [Y_WIDTH:0] ALM_CARRY;
diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc
index bf9e746b8..0f844961e 100644
--- a/techlibs/intel_alm/synth_intel_alm.cc
+++ b/techlibs/intel_alm/synth_intel_alm.cc
@@ -209,7 +209,6 @@ struct SynthIntelALMPass : public ScriptPass {
}
if (check_label("map_luts")) {
- run("read_verilog -icells -specify -lib +/abc9_model.v");
run("abc9 -maxlut 6 -W 200");
run("techmap -map +/intel_alm/common/alm_map.v");
run("opt -fast");
diff --git a/techlibs/sf2/cells_map.v b/techlibs/sf2/cells_map.v
index 6ad7807d2..9fddc0f41 100644
--- a/techlibs/sf2/cells_map.v
+++ b/techlibs/sf2/cells_map.v
@@ -59,6 +59,7 @@ module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index 9984290a6..d4d863831 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -54,8 +54,6 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc5v_dsp_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_dsp_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_dsp_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_unmap.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_model.v))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
diff --git a/techlibs/xilinx/abc9_map.v b/techlibs/xilinx/abc9_map.v
deleted file mode 100644
index 81f8a1d42..000000000
--- a/techlibs/xilinx/abc9_map.v
+++ /dev/null
@@ -1,786 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * 2019 Eddie Hung <eddie@fpgeh.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-// The following techmapping rules are intended to be run (with -max_iter 1)
-// before invoking the `abc9` pass in order to transform the design into
-// a format that it understands.
-
-`ifdef DFF_MODE
-// For example, (complex) flip-flops are expected to be described as an
-// combinatorial box (containing all control logic such as clock enable
-// or synchronous resets) followed by a basic D-Q flop.
-// Yosys will automatically analyse the simulation model (described in
-// cells_sim.v) and detach any $_DFF_P_ or $_DFF_N_ cells present in
-// order to extract the combinatorial control logic left behind.
-// Specifically, a simulation model similar to the one below:
-//
-// ++===================================++
-// || Sim model ||
-// || /\/\/\/\ ||
-// D -->>-----< > +------+ ||
-// R -->>-----< Comb. > |$_DFF_| ||
-// CE -->>-----< logic >-----| [NP]_|---+---->>-- Q
-// || +--< > +------+ | ||
-// || | \/\/\/\/ | ||
-// || | | ||
-// || +----------------------------+ ||
-// || ||
-// ++===================================++
-//
-// is transformed into:
-//
-// ++==================++
-// || Comb box ||
-// || ||
-// || /\/\/\/\ ||
-// D -->>-----< > ||
-// R -->>-----< Comb. > || +-----------+
-// CE -->>-----< logic >--->>-- $Q --|$__ABC9_FF_|--+-->> Q
-// abc9_ff.Q +-->>-----< > || +-----------+ |
-// | || \/\/\/\/ || |
-// | || || |
-// | ++==================++ |
-// | |
-// +-----------------------------------------------+
-//
-// The purpose of the following FD* rules are to wrap the flop with:
-// (a) a special $__ABC9_FF_ in front of the FD*'s output, indicating to abc9
-// the connectivity of its basic D-Q flop
-// (b) an optional $__ABC9_ASYNC_ cell in front of $__ABC_FF_'s output to
-// capture asynchronous behaviour
-// (c) a special abc9_ff.clock wire to capture its clock domain and polarity
-// (indicated to `abc9' so that it only performs sequential synthesis
-// (with reachability analysis) correctly on one domain at a time)
-// (d) an (* abc9_init *) attribute on the $__ABC9_FF_ cell capturing its
-// initial state
-// NOTE: in order to perform sequential synthesis, `abc9' requires that
-// the initial value of all flops be zero
-// (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback
-// into the (combinatorial) FD* cell to facilitate clock-enable behaviour
-
-module FDRE (output Q, (* techmap_autopurge *) input C, CE, D, R);
- parameter [0:0] INIT = 1'b0;
- parameter [0:0] IS_C_INVERTED = 1'b0;
- parameter [0:0] IS_D_INVERTED = 1'b0;
- parameter [0:0] IS_R_INVERTED = 1'b0;
- wire QQ, $Q;
- generate if (INIT == 1'b1) begin
- assign Q = ~QQ;
- FDSE #(
- .INIT(1'b0),
- .IS_C_INVERTED(IS_C_INVERTED),
- .IS_D_INVERTED(IS_D_INVERTED),
- .IS_S_INVERTED(IS_R_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .D(~D), .Q($Q), .C(C), .CE(CE), .S(R)
- );
- end
- else begin
- assign Q = QQ;
- FDRE #(
- .INIT(1'b0),
- .IS_C_INVERTED(IS_C_INVERTED),
- .IS_D_INVERTED(IS_D_INVERTED),
- .IS_R_INVERTED(IS_R_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .D(D), .Q($Q), .C(C), .CE(CE), .R(R)
- );
- end
- endgenerate
- (* abc9_init = 1'b0 *)
- $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
-
- // Special signals
- wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
-endmodule
-module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R);
- parameter [0:0] INIT = 1'b0;
- wire QQ, $Q;
- generate if (INIT == 1'b1) begin
- assign Q = ~QQ;
- FDSE_1 #(
- .INIT(1'b0)
- ) _TECHMAP_REPLACE_ (
- .D(~D), .Q($Q), .C(C), .CE(CE), .S(R)
- );
- end
- else begin
- assign Q = QQ;
- FDRE_1 #(
- .INIT(1'b0)
- ) _TECHMAP_REPLACE_ (
- .D(D), .Q($Q), .C(C), .CE(CE), .R(R)
- );
- end
- endgenerate
- (* abc9_init = 1'b0 *)
- $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
-
- // Special signals
- wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
-endmodule
-
-module FDSE (output Q, (* techmap_autopurge *) input C, CE, D, S);
- parameter [0:0] INIT = 1'b1;
- parameter [0:0] IS_C_INVERTED = 1'b0;
- parameter [0:0] IS_D_INVERTED = 1'b0;
- parameter [0:0] IS_S_INVERTED = 1'b0;
- wire QQ, $Q;
- generate if (INIT == 1'b1) begin
- assign Q = ~QQ;
- FDRE #(
- .INIT(1'b0),
- .IS_C_INVERTED(IS_C_INVERTED),
- .IS_D_INVERTED(IS_D_INVERTED),
- .IS_R_INVERTED(IS_S_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .D(~D), .Q($Q), .C(C), .CE(CE), .R(S)
- );
- end
- else begin
- assign Q = QQ;
- FDSE #(
- .INIT(1'b0),
- .IS_C_INVERTED(IS_C_INVERTED),
- .IS_D_INVERTED(IS_D_INVERTED),
- .IS_S_INVERTED(IS_S_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .D(D), .Q($Q), .C(C), .CE(CE), .S(S)
- );
- end endgenerate
- (* abc9_init = 1'b0 *)
- $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
-
- // Special signals
- wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
-endmodule
-module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S);
- parameter [0:0] INIT = 1'b1;
- wire QQ, $Q;
- generate if (INIT == 1'b1) begin
- assign Q = ~QQ;
- FDRE_1 #(
- .INIT(1'b0)
- ) _TECHMAP_REPLACE_ (
- .D(~D), .Q($Q), .C(C), .CE(CE), .R(S)
- );
- end
- else begin
- assign Q = QQ;
- FDSE_1 #(
- .INIT(1'b0)
- ) _TECHMAP_REPLACE_ (
- .D(D), .Q($Q), .C(C), .CE(CE), .S(S)
- );
- end endgenerate
- (* abc9_init = 1'b0 *)
- $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
-
- // Special signals
- wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
-endmodule
-
-module FDCE (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
- parameter [0:0] INIT = 1'b0;
- parameter [0:0] IS_C_INVERTED = 1'b0;
- parameter [0:0] IS_D_INVERTED = 1'b0;
- parameter [0:0] IS_CLR_INVERTED = 1'b0;
- wire QQ, $Q, $QQ;
- generate if (INIT == 1'b1) begin
- assign Q = ~QQ;
- FDPE #(
- .INIT(1'b0),
- .IS_C_INVERTED(IS_C_INVERTED),
- .IS_D_INVERTED(IS_D_INVERTED),
- .IS_PRE_INVERTED(IS_CLR_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC1 below
- );
- // Since this is an async flop, async behaviour is dealt with here
- $__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
- end
- else begin
- assign Q = QQ;
- FDCE #(
- .INIT(1'b0),
- .IS_C_INVERTED(IS_C_INVERTED),
- .IS_D_INVERTED(IS_D_INVERTED),
- .IS_CLR_INVERTED(IS_CLR_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC0 below
- );
- // Since this is an async flop, async behaviour is dealt with here
- $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
- end endgenerate
- (* abc9_init = 1'b0 *)
- $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
-
- // Special signals
- wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
-endmodule
-module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
- parameter [0:0] INIT = 1'b0;
- wire QQ, $Q, $QQ;
- generate if (INIT == 1'b1) begin
- assign Q = ~QQ;
- FDPE_1 #(
- .INIT(1'b0)
- ) _TECHMAP_REPLACE_ (
- .D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC1 below
- );
- $__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR), .Y(QQ));
- end
- else begin
- assign Q = QQ;
- FDCE_1 #(
- .INIT(1'b0)
- ) _TECHMAP_REPLACE_ (
- .D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC0 below
- );
- $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR), .Y(QQ));
- end endgenerate
- (* abc9_init = 1'b0 *)
- $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
-
- // Special signals
- wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
-endmodule
-
-module FDPE (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
- parameter [0:0] INIT = 1'b1;
- parameter [0:0] IS_C_INVERTED = 1'b0;
- parameter [0:0] IS_D_INVERTED = 1'b0;
- parameter [0:0] IS_PRE_INVERTED = 1'b0;
- wire QQ, $Q, $QQ;
- generate if (INIT == 1'b1) begin
- assign Q = ~QQ;
- FDCE #(
- .INIT(1'b0),
- .IS_C_INVERTED(IS_C_INVERTED),
- .IS_D_INVERTED(IS_D_INVERTED),
- .IS_CLR_INVERTED(IS_PRE_INVERTED),
- ) _TECHMAP_REPLACE_ (
- .D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC0 below
- );
- $__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
- end
- else begin
- assign Q = QQ;
- FDPE #(
- .INIT(1'b0),
- .IS_C_INVERTED(IS_C_INVERTED),
- .IS_D_INVERTED(IS_D_INVERTED),
- .IS_PRE_INVERTED(IS_PRE_INVERTED),
- ) _TECHMAP_REPLACE_ (
- .D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC1 below
- );
- $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
- end endgenerate
- (* abc9_init = 1'b0 *)
- $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
-
- // Special signals
- wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
-endmodule
-module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
- parameter [0:0] INIT = 1'b1;
- wire QQ, $Q, $QQ;
- generate if (INIT == 1'b1) begin
- assign Q = ~QQ;
- FDCE_1 #(
- .INIT(1'b0)
- ) _TECHMAP_REPLACE_ (
- .D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC0 below
- );
- $__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE), .Y(QQ));
- end
- else begin
- assign Q = QQ;
- FDPE_1 #(
- .INIT(1'b0)
- ) _TECHMAP_REPLACE_ (
- .D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC1 below
- );
- $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE), .Y(QQ));
- end endgenerate
- (* abc9_init = 1'b0 *)
- $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
-
- // Special signals
- wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
-endmodule
-`endif
-
-// Attach a (combinatorial) black-box onto the output
-// of thes LUTRAM primitives to capture their
-// asynchronous read behaviour
-module RAM32X1D (
- output DPO, SPO,
- (* techmap_autopurge *) input D,
- (* techmap_autopurge *) input WCLK,
- (* techmap_autopurge *) input WE,
- (* techmap_autopurge *) input A0, A1, A2, A3, A4,
- (* techmap_autopurge *) input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
-);
- parameter INIT = 32'h0;
- parameter IS_WCLK_INVERTED = 1'b0;
- wire $DPO, $SPO;
- RAM32X1D #(
- .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .DPO($DPO), .SPO($SPO),
- .D(D), .WCLK(WCLK), .WE(WE),
- .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4),
- .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4)
- );
- $__ABC9_RAM6 spo (.A($SPO), .S({1'b1, A4, A3, A2, A1, A0}), .Y(SPO));
- $__ABC9_RAM6 dpo (.A($DPO), .S({1'b1, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO));
-endmodule
-
-module RAM64X1D (
- output DPO, SPO,
- (* techmap_autopurge *) input D,
- (* techmap_autopurge *) input WCLK,
- (* techmap_autopurge *) input WE,
- (* techmap_autopurge *) input A0, A1, A2, A3, A4, A5,
- (* techmap_autopurge *) input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
-);
- parameter INIT = 64'h0;
- parameter IS_WCLK_INVERTED = 1'b0;
- wire $DPO, $SPO;
- RAM64X1D #(
- .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .DPO($DPO), .SPO($SPO),
- .D(D), .WCLK(WCLK), .WE(WE),
- .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5),
- .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5)
- );
- $__ABC9_RAM6 spo (.A($SPO), .S({A5, A4, A3, A2, A1, A0}), .Y(SPO));
- $__ABC9_RAM6 dpo (.A($DPO), .S({DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO));
-endmodule
-
-module RAM128X1D (
- output DPO, SPO,
- (* techmap_autopurge *) input D,
- (* techmap_autopurge *) input WCLK,
- (* techmap_autopurge *) input WE,
- (* techmap_autopurge *) input [6:0] A, DPRA
-);
- parameter INIT = 128'h0;
- parameter IS_WCLK_INVERTED = 1'b0;
- wire $DPO, $SPO;
- RAM128X1D #(
- .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .DPO($DPO), .SPO($SPO),
- .D(D), .WCLK(WCLK), .WE(WE),
- .A(A),
- .DPRA(DPRA)
- );
- $__ABC9_RAM7 spo (.A($SPO), .S(A), .Y(SPO));
- $__ABC9_RAM7 dpo (.A($DPO), .S(DPRA), .Y(DPO));
-endmodule
-
-module RAM32M (
- output [1:0] DOA,
- output [1:0] DOB,
- output [1:0] DOC,
- output [1:0] DOD,
- (* techmap_autopurge *) input [4:0] ADDRA,
- (* techmap_autopurge *) input [4:0] ADDRB,
- (* techmap_autopurge *) input [4:0] ADDRC,
- (* techmap_autopurge *) input [4:0] ADDRD,
- (* techmap_autopurge *) input [1:0] DIA,
- (* techmap_autopurge *) input [1:0] DIB,
- (* techmap_autopurge *) input [1:0] DIC,
- (* techmap_autopurge *) input [1:0] DID,
- (* techmap_autopurge *) input WCLK,
- (* techmap_autopurge *) input WE
-);
- parameter [63:0] INIT_A = 64'h0000000000000000;
- parameter [63:0] INIT_B = 64'h0000000000000000;
- parameter [63:0] INIT_C = 64'h0000000000000000;
- parameter [63:0] INIT_D = 64'h0000000000000000;
- parameter [0:0] IS_WCLK_INVERTED = 1'b0;
- wire [1:0] $DOA, $DOB, $DOC, $DOD;
- RAM32M #(
- .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D),
- .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .DOA($DOA), .DOB($DOB), .DOC($DOC), .DOD($DOD),
- .WCLK(WCLK), .WE(WE),
- .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD),
- .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID)
- );
- $__ABC9_RAM6 doa0 (.A($DOA[0]), .S({1'b1, ADDRA}), .Y(DOA[0]));
- $__ABC9_RAM6 doa1 (.A($DOA[1]), .S({1'b1, ADDRA}), .Y(DOA[1]));
- $__ABC9_RAM6 dob0 (.A($DOB[0]), .S({1'b1, ADDRB}), .Y(DOB[0]));
- $__ABC9_RAM6 dob1 (.A($DOB[1]), .S({1'b1, ADDRB}), .Y(DOB[1]));
- $__ABC9_RAM6 doc0 (.A($DOC[0]), .S({1'b1, ADDRC}), .Y(DOC[0]));
- $__ABC9_RAM6 doc1 (.A($DOC[1]), .S({1'b1, ADDRC}), .Y(DOC[1]));
- $__ABC9_RAM6 dod0 (.A($DOD[0]), .S({1'b1, ADDRD}), .Y(DOD[0]));
- $__ABC9_RAM6 dod1 (.A($DOD[1]), .S({1'b1, ADDRD}), .Y(DOD[1]));
-endmodule
-
-module RAM64M (
- output DOA,
- output DOB,
- output DOC,
- output DOD,
- (* techmap_autopurge *) input [5:0] ADDRA,
- (* techmap_autopurge *) input [5:0] ADDRB,
- (* techmap_autopurge *) input [5:0] ADDRC,
- (* techmap_autopurge *) input [5:0] ADDRD,
- (* techmap_autopurge *) input DIA,
- (* techmap_autopurge *) input DIB,
- (* techmap_autopurge *) input DIC,
- (* techmap_autopurge *) input DID,
- (* techmap_autopurge *) input WCLK,
- (* techmap_autopurge *) input WE
-);
- parameter [63:0] INIT_A = 64'h0000000000000000;
- parameter [63:0] INIT_B = 64'h0000000000000000;
- parameter [63:0] INIT_C = 64'h0000000000000000;
- parameter [63:0] INIT_D = 64'h0000000000000000;
- parameter [0:0] IS_WCLK_INVERTED = 1'b0;
- wire $DOA, $DOB, $DOC, $DOD;
- RAM64M #(
- .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D),
- .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .DOA($DOA), .DOB($DOB), .DOC($DOC), .DOD($DOD),
- .WCLK(WCLK), .WE(WE),
- .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD),
- .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID)
- );
- $__ABC9_RAM6 doa (.A($DOA), .S(ADDRA), .Y(DOA));
- $__ABC9_RAM6 dob (.A($DOB), .S(ADDRB), .Y(DOB));
- $__ABC9_RAM6 doc (.A($DOC), .S(ADDRC), .Y(DOC));
- $__ABC9_RAM6 dod (.A($DOD), .S(ADDRD), .Y(DOD));
-endmodule
-
-module SRL16 (
- output Q,
- (* techmap_autopurge *) input A0, A1, A2, A3, CLK, D
-);
- parameter [15:0] INIT = 16'h0000;
- wire $Q;
- SRL16 #(
- .INIT(INIT),
- ) _TECHMAP_REPLACE_ (
- .Q($Q),
- .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CLK(CLK), .D(D)
- );
- $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q));
-endmodule
-
-module SRL16E (
- output Q,
- (* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D
-);
- parameter [15:0] INIT = 16'h0000;
- parameter [0:0] IS_CLK_INVERTED = 1'b0;
- wire $Q;
- SRL16E #(
- .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .Q($Q),
- .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D)
- );
- $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q));
-endmodule
-
-module SRLC16 (
- output Q, Q15,
- (* techmap_autopurge *) input A0, A1, A2, A3, CLK, D
-);
- parameter [15:0] INIT = 16'h0000;
- wire $Q;
- SRLC16 #(
- .INIT(INIT),
- ) _TECHMAP_REPLACE_ (
- .Q($Q), .Q(Q15),
- .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CLK(CLK), .D(D)
- );
- $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q));
-endmodule
-
-module SRLC16E (
- output Q, Q15,
- (* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D
-);
- parameter [15:0] INIT = 16'h0000;
- parameter [0:0] IS_CLK_INVERTED = 1'b0;
- wire $Q;
- SRLC16E #(
- .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .Q($Q), .Q(Q15),
- .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D)
- );
- $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q));
-endmodule
-
-module SRLC32E (
- output Q,
- output Q31,
- (* techmap_autopurge *) input [4:0] A,
- (* techmap_autopurge *) input CE, CLK, D
-);
- parameter [31:0] INIT = 32'h00000000;
- parameter [0:0] IS_CLK_INVERTED = 1'b0;
- wire $Q;
- SRLC32E #(
- .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .Q($Q), .Q31(Q31),
- .A(A), .CE(CE), .CLK(CLK), .D(D)
- );
- $__ABC9_RAM6 q (.A($Q), .S({1'b1, A}), .Y(Q));
-endmodule
-
-module DSP48E1 (
- (* techmap_autopurge *) output [29:0] ACOUT,
- (* techmap_autopurge *) output [17:0] BCOUT,
- (* techmap_autopurge *) output reg CARRYCASCOUT,
- (* techmap_autopurge *) output reg [3:0] CARRYOUT,
- (* techmap_autopurge *) output reg MULTSIGNOUT,
- (* techmap_autopurge *) output OVERFLOW,
- (* techmap_autopurge *) output reg signed [47:0] P,
- (* techmap_autopurge *) output PATTERNBDETECT,
- (* techmap_autopurge *) output PATTERNDETECT,
- (* techmap_autopurge *) output [47:0] PCOUT,
- (* techmap_autopurge *) output UNDERFLOW,
- (* techmap_autopurge *) input signed [29:0] A,
- (* techmap_autopurge *) input [29:0] ACIN,
- (* techmap_autopurge *) input [3:0] ALUMODE,
- (* techmap_autopurge *) input signed [17:0] B,
- (* techmap_autopurge *) input [17:0] BCIN,
- (* techmap_autopurge *) input [47:0] C,
- (* techmap_autopurge *) input CARRYCASCIN,
- (* techmap_autopurge *) input CARRYIN,
- (* techmap_autopurge *) input [2:0] CARRYINSEL,
- (* techmap_autopurge *) input CEA1,
- (* techmap_autopurge *) input CEA2,
- (* techmap_autopurge *) input CEAD,
- (* techmap_autopurge *) input CEALUMODE,
- (* techmap_autopurge *) input CEB1,
- (* techmap_autopurge *) input CEB2,
- (* techmap_autopurge *) input CEC,
- (* techmap_autopurge *) input CECARRYIN,
- (* techmap_autopurge *) input CECTRL,
- (* techmap_autopurge *) input CED,
- (* techmap_autopurge *) input CEINMODE,
- (* techmap_autopurge *) input CEM,
- (* techmap_autopurge *) input CEP,
- (* techmap_autopurge *) input CLK,
- (* techmap_autopurge *) input [24:0] D,
- (* techmap_autopurge *) input [4:0] INMODE,
- (* techmap_autopurge *) input MULTSIGNIN,
- (* techmap_autopurge *) input [6:0] OPMODE,
- (* techmap_autopurge *) input [47:0] PCIN,
- (* techmap_autopurge *) input RSTA,
- (* techmap_autopurge *) input RSTALLCARRYIN,
- (* techmap_autopurge *) input RSTALUMODE,
- (* techmap_autopurge *) input RSTB,
- (* techmap_autopurge *) input RSTC,
- (* techmap_autopurge *) input RSTCTRL,
- (* techmap_autopurge *) input RSTD,
- (* techmap_autopurge *) input RSTINMODE,
- (* techmap_autopurge *) input RSTM,
- (* techmap_autopurge *) input RSTP
-);
- parameter integer ACASCREG = 1;
- parameter integer ADREG = 1;
- parameter integer ALUMODEREG = 1;
- parameter integer AREG = 1;
- parameter AUTORESET_PATDET = "NO_RESET";
- parameter A_INPUT = "DIRECT";
- parameter integer BCASCREG = 1;
- parameter integer BREG = 1;
- parameter B_INPUT = "DIRECT";
- parameter integer CARRYINREG = 1;
- parameter integer CARRYINSELREG = 1;
- parameter integer CREG = 1;
- parameter integer DREG = 1;
- parameter integer INMODEREG = 1;
- parameter integer MREG = 1;
- parameter integer OPMODEREG = 1;
- parameter integer PREG = 1;
- parameter SEL_MASK = "MASK";
- parameter SEL_PATTERN = "PATTERN";
- parameter USE_DPORT = "FALSE";
- parameter USE_MULT = "MULTIPLY";
- parameter USE_PATTERN_DETECT = "NO_PATDET";
- parameter USE_SIMD = "ONE48";
- parameter [47:0] MASK = 48'h3FFFFFFFFFFF;
- parameter [47:0] PATTERN = 48'h000000000000;
- parameter [3:0] IS_ALUMODE_INVERTED = 4'b0;
- parameter [0:0] IS_CARRYIN_INVERTED = 1'b0;
- parameter [0:0] IS_CLK_INVERTED = 1'b0;
- parameter [4:0] IS_INMODE_INVERTED = 5'b0;
- parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
-
- wire [47:0] $P, $PCOUT;
-
- DSP48E1 #(
- .ACASCREG(ACASCREG),
- .ADREG(ADREG),
- .ALUMODEREG(ALUMODEREG),
- .AREG(AREG),
- .AUTORESET_PATDET(AUTORESET_PATDET),
- .A_INPUT(A_INPUT),
- .BCASCREG(BCASCREG),
- .BREG(BREG),
- .B_INPUT(B_INPUT),
- .CARRYINREG(CARRYINREG),
- .CARRYINSELREG(CARRYINSELREG),
- .CREG(CREG),
- .DREG(DREG),
- .INMODEREG(INMODEREG),
- .MREG(MREG),
- .OPMODEREG(OPMODEREG),
- .PREG(PREG),
- .SEL_MASK(SEL_MASK),
- .SEL_PATTERN(SEL_PATTERN),
- .USE_DPORT(USE_DPORT),
- .USE_MULT(USE_MULT),
- .USE_PATTERN_DETECT(USE_PATTERN_DETECT),
- .USE_SIMD(USE_SIMD),
- .MASK(MASK),
- .PATTERN(PATTERN),
- .IS_ALUMODE_INVERTED(IS_ALUMODE_INVERTED),
- .IS_CARRYIN_INVERTED(IS_CARRYIN_INVERTED),
- .IS_CLK_INVERTED(IS_CLK_INVERTED),
- .IS_INMODE_INVERTED(IS_INMODE_INVERTED),
- .IS_OPMODE_INVERTED(IS_OPMODE_INVERTED)
- ) _TECHMAP_REPLACE_ (
- .ACOUT(ACOUT),
- .BCOUT(BCOUT),
- .CARRYCASCOUT(CARRYCASCOUT),
- .CARRYOUT(CARRYOUT),
- .MULTSIGNOUT(MULTSIGNOUT),
- .OVERFLOW(OVERFLOW),
- .P($P),
- .PATTERNBDETECT(PATTERNBDETECT),
- .PATTERNDETECT(PATTERNDETECT),
- .PCOUT($PCOUT),
- .UNDERFLOW(UNDERFLOW),
- .A(A),
- .ACIN(ACIN),
- .ALUMODE(ALUMODE),
- .B(B),
- .BCIN(BCIN),
- .C(C),
- .CARRYCASCIN(CARRYCASCIN),
- .CARRYIN(CARRYIN),
- .CARRYINSEL(CARRYINSEL),
- .CEA1(CEA1),
- .CEA2(CEA2),
- .CEAD(CEAD),
- .CEALUMODE(CEALUMODE),
- .CEB1(CEB1),
- .CEB2(CEB2),
- .CEC(CEC),
- .CECARRYIN(CECARRYIN),
- .CECTRL(CECTRL),
- .CED(CED),
- .CEINMODE(CEINMODE),
- .CEM(CEM),
- .CEP(CEP),
- .CLK(CLK),
- .D(D),
- .INMODE(INMODE),
- .MULTSIGNIN(MULTSIGNIN),
- .OPMODE(OPMODE),
- .PCIN(PCIN),
- .RSTA(RSTA),
- .RSTALLCARRYIN(RSTALLCARRYIN),
- .RSTALUMODE(RSTALUMODE),
- .RSTB(RSTB),
- .RSTC(RSTC),
- .RSTCTRL(RSTCTRL),
- .RSTD(RSTD),
- .RSTINMODE(RSTINMODE),
- .RSTM(RSTM),
- .RSTP(RSTP)
- );
- $__ABC9_DSP48E1 #(
- .ADREG(ADREG),
- .AREG(AREG),
- .BREG(BREG),
- .CREG(CREG),
- .DREG(DREG),
- .MREG(MREG),
- .PREG(PREG),
- .USE_DPORT(USE_DPORT),
- .USE_MULT(USE_MULT)
- ) dsp_comb (
- .$A(A), .$B(B), .$C(C), .$D(D), .$P($P), .$PCIN(PCIN), .$PCOUT($PCOUT), .P(P), .PCOUT(PCOUT));
-endmodule
diff --git a/techlibs/xilinx/abc9_model.v b/techlibs/xilinx/abc9_model.v
index 2d109ef8a..db44ff00b 100644
--- a/techlibs/xilinx/abc9_model.v
+++ b/techlibs/xilinx/abc9_model.v
@@ -37,174 +37,3 @@ module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1);
(S1 => O) = 273;
endspecify
endmodule
-
-// Box to emulate async behaviour of FDC*
-(* abc9_box, lib_whitebox *)
-module \$__ABC9_ASYNC0 (input A, S, output Y);
- assign Y = S ? 1'b0 : A;
- specify
- (A => Y) = 0;
- // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270
- (S => Y) = 764;
- endspecify
-endmodule
-
-// Box to emulate async behaviour of FDP*
-(* abc9_box, lib_whitebox *)
-module \$__ABC9_ASYNC1 (input A, S, output Y);
- assign Y = S ? 1'b1 : A;
- specify
- (A => Y) = 0;
- // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270
- (S => Y) = 764;
- endspecify
-endmodule
-
-// Box to emulate comb/seq behaviour of RAM{32,64} and SRL{16,32}
-// Necessary since RAMD* and SRL* have both combinatorial (i.e.
-// same-cycle read operation) and sequential (write operation
-// is only committed on the next clock edge).
-// To model the combinatorial path, such cells have to be split
-// into comb and seq parts, with this box modelling only the former.
-(* abc9_box *)
-module \$__ABC9_RAM6 (input A, input [5:0] S, output Y);
- specify
- (A => Y) = 0;
- (S[0] => Y) = 642;
- (S[1] => Y) = 631;
- (S[2] => Y) = 472;
- (S[3] => Y) = 407;
- (S[4] => Y) = 238;
- (S[5] => Y) = 127;
- endspecify
-endmodule
-// Box to emulate comb/seq behaviour of RAM128
-(* abc9_box *)
-module \$__ABC9_RAM7 (input A, input [6:0] S, output Y);
- specify
- (A => Y) = 0;
- // https://github.com/SymbiFlow/prjxray-db/blob/1c85daf1b115da4d27ca83c6b89f53a94de39748/artix7/timings/slicel.sdf#L867
- (S[0] => Y) = 642 + 223 /* to cross F7BMUX */ + 174 /* CMUX */;
- (S[1] => Y) = 631 + 223 /* to cross F7BMUX */ + 174 /* CMUX */;
- (S[2] => Y) = 472 + 223 /* to cross F7BMUX */ + 174 /* CMUX */;
- (S[3] => Y) = 407 + 223 /* to cross F7BMUX */ + 174 /* CMUX */;
- (S[4] => Y) = 238 + 223 /* to cross F7BMUX */ + 174 /* CMUX */;
- (S[5] => Y) = 127 + 223 /* to cross F7BMUX */ + 174 /* CMUX */;
- (S[6] => Y) = 0 + 296 /* to select F7BMUX */ + 174 /* CMUX */;
- endspecify
-endmodule
-
-// Boxes used to represent the comb behaviour of DSP48E1
-(* abc9_box *)
-module $__ABC9_DSP48E1 (
- input [29:0] $A,
- input [17:0] $B,
- input [47:0] $C,
- input [24:0] $D,
- input [47:0] $P,
- input [47:0] $PCIN,
- input [47:0] $PCOUT,
- output [47:0] P,
- output [47:0] PCOUT
-);
- parameter integer ADREG = 1;
- parameter integer AREG = 1;
- parameter integer BREG = 1;
- parameter integer CREG = 1;
- parameter integer DREG = 1;
- parameter integer MREG = 1;
- parameter integer PREG = 1;
- parameter USE_DPORT = "FALSE";
- parameter USE_MULT = "MULTIPLY";
-
- function integer \A.P.comb ;
- begin
- if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \A.P.comb = 2823;
- else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \A.P.comb = 3806;
- else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \A.P.comb = 1523;
- end
- endfunction
- function integer \A.PCOUT.comb ;
- begin
- if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \A.PCOUT.comb = 2970;
- else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \A.PCOUT.comb = 3954;
- else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \A.PCOUT.comb = 1671;
- end
- endfunction
- function integer \B.P.comb ;
- begin
- if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \B.P.comb = 2690;
- else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \B.P.comb = 2690;
- else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \B.P.comb = 1509;
- end
- endfunction
- function integer \B.PCOUT.comb ;
- begin
- if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \B.PCOUT.comb = 2838;
- else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \B.PCOUT.comb = 2838;
- else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \B.PCOUT.comb = 1658;
- end
- endfunction
- function integer \C.P.comb ;
- begin
- if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \C.P.comb = 1325;
- else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \C.P.comb = 1325;
- else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \C.P.comb = 1325;
- end
- endfunction
- function integer \C.PCOUT.comb ;
- begin
- if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \C.PCOUT.comb = 1474;
- else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \C.PCOUT.comb = 1474;
- else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \C.PCOUT.comb = 1474;
- end
- endfunction
- function integer \D.P.comb ;
- begin
- if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \D.P.comb = 3717;
- end
- endfunction
- function integer \D.PCOUT.comb ;
- begin
- if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \D.PCOUT.comb = 3700;
- end
- endfunction
-
- specify
- ($P *> P) = 0;
- ($PCOUT *> PCOUT) = 0;
- endspecify
-
- // Identical comb delays to DSP48E1 in cells_sim.v
- generate
- if (PREG == 0 && MREG == 0 && AREG == 0 && ADREG == 0)
- specify
- ($A *> P) = \A.P.comb ();
- ($A *> PCOUT) = \A.PCOUT.comb ();
- endspecify
-
- if (PREG == 0 && MREG == 0 && BREG == 0)
- specify
- ($B *> P) = \B.P.comb ();
- ($B *> PCOUT) = \B.PCOUT.comb ();
- endspecify
-
- if (PREG == 0 && CREG == 0)
- specify
- ($C *> P) = \C.P.comb ();
- ($C *> PCOUT) = \C.PCOUT.comb ();
- endspecify
-
- if (PREG == 0 && MREG == 0 && ADREG == 0 && DREG == 0)
- specify
- ($D *> P) = \D.P.comb ();
- ($D *> PCOUT) = \D.PCOUT.comb ();
- endspecify
-
- if (PREG == 0)
- specify
- ($PCIN *> P) = 1107;
- ($PCIN *> PCOUT) = 1255;
- endspecify
- endgenerate
-endmodule
diff --git a/techlibs/xilinx/abc9_unmap.v b/techlibs/xilinx/abc9_unmap.v
deleted file mode 100644
index 5604ceb0a..000000000
--- a/techlibs/xilinx/abc9_unmap.v
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * 2019 Eddie Hung <eddie@fpgeh.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-// ============================================================================
-
-(* techmap_celltype = "$__ABC9_ASYNC0 $__ABC9_ASYNC1" *)
-module $__ABC9_ASYNC01(input A, S, output Y);
- assign Y = A;
-endmodule
-
-module $__ABC9_FF_(input D, output Q);
- assign Q = D;
-endmodule
-
-module $__ABC9_RAM6(input A, input [5:0] S, output Y);
- assign Y = A;
-endmodule
-module $__ABC9_RAM7(input A, input [6:0] S, output Y);
- assign Y = A;
-endmodule
-
-module $__ABC9_DSP48E1(
- input [29:0] $A,
- input [17:0] $B,
- input [47:0] $C,
- input [24:0] $D,
- input [47:0] $P,
- input [47:0] $PCIN,
- input [47:0] $PCOUT,
- output [47:0] P,
- output [47:0] PCOUT
-);
- parameter integer ADREG = 1;
- parameter integer AREG = 1;
- parameter integer BREG = 1;
- parameter integer CREG = 1;
- parameter integer DREG = 1;
- parameter integer MREG = 1;
- parameter integer PREG = 1;
- parameter USE_DPORT = "FALSE";
- parameter USE_MULT = "MULTIPLY";
-
- assign P = $P, PCOUT = $PCOUT;
-endmodule
diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v
index 2b8b0dcc1..2fc216908 100644
--- a/techlibs/xilinx/arith_map.v
+++ b/techlibs/xilinx/arith_map.v
@@ -24,9 +24,11 @@
module _80_xilinx_lcu (P, G, CI, CO);
parameter WIDTH = 2;
+ (* force_downto *)
input [WIDTH-1:0] P, G;
input CI;
+ (* force_downto *)
output [WIDTH-1:0] CO;
wire _TECHMAP_FAIL_ = WIDTH <= 2;
@@ -41,7 +43,9 @@ module _80_xilinx_lcu (P, G, CI, CO);
generate if (EXPLICIT_CARRY || `LUT_SIZE == 4) begin
+ (* force_downto *)
wire [WIDTH-1:0] C = {CO, CI};
+ (* force_downto *)
wire [WIDTH-1:0] S = P & ~G;
generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
@@ -59,8 +63,11 @@ end else begin
localparam MAX_WIDTH = CARRY4_COUNT * 4;
localparam PAD_WIDTH = MAX_WIDTH - WIDTH;
+ (* force_downto *)
wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G};
+ (* force_downto *)
wire [MAX_WIDTH-1:0] GG = {{PAD_WIDTH{1'b0}}, G};
+ (* force_downto *)
wire [MAX_WIDTH-1:0] C;
assign CO = C;
@@ -103,20 +110,27 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
parameter _TECHMAP_CONSTVAL_CI_ = 0;
parameter _TECHMAP_CONSTMSK_CI_ = 0;
+ (* force_downto *)
input [A_WIDTH-1:0] A;
+ (* force_downto *)
input [B_WIDTH-1:0] B;
+ (* force_downto *)
output [Y_WIDTH-1:0] X, Y;
input CI, BI;
+ (* force_downto *)
output [Y_WIDTH-1:0] CO;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
genvar i;
@@ -129,7 +143,9 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
generate if (`LUT_SIZE == 4) begin
+ (* force_downto *)
wire [Y_WIDTH-1:0] C = {CO, CI};
+ (* force_downto *)
wire [Y_WIDTH-1:0] S = {AA ^ BB};
genvar i;
@@ -149,6 +165,7 @@ generate if (`LUT_SIZE == 4) begin
end else if (EXPLICIT_CARRY) begin
+ (* force_downto *)
wire [Y_WIDTH-1:0] S = AA ^ BB;
wire CINIT;
@@ -161,7 +178,9 @@ end else if (EXPLICIT_CARRY) begin
// So we maintain two wire sets, CO_CHAIN is the carry that is for VPR,
// e.g. off fabric dedicated chain. CO is the carry outputs that are
// available to the fabric.
+ (* force_downto *)
wire [Y_WIDTH-1:0] CO_CHAIN;
+ (* force_downto *)
wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT};
// If carry chain is being initialized to a constant, techmap the constant
@@ -250,10 +269,14 @@ end else begin
localparam MAX_WIDTH = CARRY4_COUNT * 4;
localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH;
+ (* force_downto *)
wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB};
+ (* force_downto *)
wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA};
+ (* force_downto *)
wire [MAX_WIDTH-1:0] O;
+ (* force_downto *)
wire [MAX_WIDTH-1:0] C;
assign Y = O, CO = C;
diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
index cc180f2b9..801949d22 100644
--- a/techlibs/xilinx/cells_map.v
+++ b/techlibs/xilinx/cells_map.v
@@ -184,8 +184,11 @@ module \$__XILINX_SHIFTX (A, B, Y);
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;
parameter [A_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0;
@@ -321,8 +324,11 @@ module _90__XILINX_SHIFTX (A, B, Y);
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;
\$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y));
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index 63223afbf..f5850d8a2 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -36,6 +36,9 @@ module IBUF(
parameter IOSTANDARD = "default";
parameter IBUF_LOW_PWR = 0;
assign O = I;
+ specify
+ (I => O) = 0;
+ endspecify
endmodule
module IBUFG(
@@ -57,6 +60,9 @@ module OBUF(
parameter DRIVE = 12;
parameter SLEW = "SLOW";
assign O = I;
+ specify
+ (I => O) = 0;
+ endspecify
endmodule
module IOBUF (
@@ -72,6 +78,10 @@ module IOBUF (
parameter SLEW = "SLOW";
assign IO = T ? 1'bz : I;
assign O = IO;
+ specify
+ (I => IO) = 0;
+ (IO => O) = 0;
+ endspecify
endmodule
module OBUFT (
@@ -85,14 +95,20 @@ module OBUFT (
parameter IOSTANDARD = "DEFAULT";
parameter SLEW = "SLOW";
assign O = T ? 1'bz : I;
+ specify
+ (I => O) = 0;
+ endspecify
endmodule
module BUFG(
(* clkbuf_driver *)
output O,
input I);
-
assign O = I;
+ specify
+ // https://github.com/SymbiFlow/prjxray-db/blob/4bc6385ab300b1819848371f508185f57b649a0e/artix7/timings/CLK_BUFG_TOP_R.sdf#L11
+ (I => O) = 96;
+ endspecify
endmodule
module BUFGCTRL(
@@ -499,8 +515,8 @@ module FDRE (
endgenerate
specify
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249
- //$setup(D , posedge C &&& CE && !IS_C_INVERTED , -46); // Negative times not currently supported
- //$setup(D , negedge C &&& CE && IS_C_INVERTED , -46); // Negative times not currently supported
+ $setup(D , posedge C &&& CE && !IS_C_INVERTED , /*-46*/ 0); // Negative times not currently supported
+ $setup(D , negedge C &&& CE && IS_C_INVERTED , /*-46*/ 0); // Negative times not currently supported
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248
$setup(CE, posedge C &&& !IS_C_INVERTED, 109);
$setup(CE, negedge C &&& IS_C_INVERTED, 109);
@@ -508,10 +524,10 @@ module FDRE (
$setup(R , posedge C &&& !IS_C_INVERTED, 404);
$setup(R , negedge C &&& IS_C_INVERTED, 404);
// https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L243
- if (!IS_C_INVERTED && R ^ IS_R_INVERTED) (posedge C => (Q : 1'b0)) = 303;
- if ( IS_C_INVERTED && R ^ IS_R_INVERTED) (negedge C => (Q : 1'b0)) = 303;
- if (!IS_C_INVERTED && R ~^ IS_R_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303;
- if ( IS_C_INVERTED && R ~^ IS_R_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303;
+ if (!IS_C_INVERTED && R != IS_R_INVERTED) (posedge C => (Q : 1'b0)) = 303;
+ if ( IS_C_INVERTED && R != IS_R_INVERTED) (negedge C => (Q : 1'b0)) = 303;
+ if (!IS_C_INVERTED && R == IS_R_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303;
+ if ( IS_C_INVERTED && R == IS_R_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303;
endspecify
endmodule
@@ -529,7 +545,7 @@ module FDRE_1 (
always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D;
specify
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249
- //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported
+ $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248
$setup(CE, negedge C, 109);
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274
@@ -564,8 +580,8 @@ module FDSE (
endgenerate
specify
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249
- //$setup(D , posedge C &&& !IS_C_INVERTED && CE, -46); // Negative times not currently supported
- //$setup(D , negedge C &&& IS_C_INVERTED && CE, -46); // Negative times not currently supported
+ $setup(D , posedge C &&& !IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported
+ $setup(D , negedge C &&& IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248
$setup(CE, posedge C &&& !IS_C_INVERTED, 109);
$setup(CE, negedge C &&& IS_C_INVERTED, 109);
@@ -573,10 +589,10 @@ module FDSE (
$setup(S , posedge C &&& !IS_C_INVERTED, 404);
$setup(S , negedge C &&& IS_C_INVERTED, 404);
// https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L243
- if (!IS_C_INVERTED && S ^ IS_S_INVERTED) (posedge C => (Q : 1'b1)) = 303;
- if ( IS_C_INVERTED && S ^ IS_S_INVERTED) (negedge C => (Q : 1'b1)) = 303;
- if (!IS_C_INVERTED && S ~^ IS_S_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303;
- if ( IS_C_INVERTED && S ~^ IS_S_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303;
+ if (!IS_C_INVERTED && S != IS_S_INVERTED) (posedge C => (Q : 1'b1)) = 303;
+ if ( IS_C_INVERTED && S != IS_S_INVERTED) (negedge C => (Q : 1'b1)) = 303;
+ if (!IS_C_INVERTED && S == IS_S_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303;
+ if ( IS_C_INVERTED && S == IS_S_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303;
endspecify
endmodule
@@ -594,7 +610,7 @@ module FDSE_1 (
always @(negedge C) if (S) Q <= 1'b1; else if (CE) Q <= D;
specify
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249
- //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported
+ $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248
$setup(CE, negedge C, 109);
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274
@@ -640,7 +656,7 @@ module FDRSE (
Q <= d;
endmodule
-(* abc9_flop, lib_whitebox *)
+(* abc9_box, lib_whitebox *)
module FDCE (
output reg Q,
(* clkbuf_sink *)
@@ -667,8 +683,8 @@ module FDCE (
endgenerate
specify
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249
- //$setup(D , posedge C &&& !IS_C_INVERTED && CE, -46); // Negative times not currently supported
- //$setup(D , negedge C &&& IS_C_INVERTED && CE, -46); // Negative times not currently supported
+ $setup(D , posedge C &&& !IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported
+ $setup(D , negedge C &&& IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248
$setup(CE , posedge C &&& !IS_C_INVERTED, 109);
$setup(CE , negedge C &&& IS_C_INVERTED, 109);
@@ -676,14 +692,20 @@ module FDCE (
$setup(CLR, posedge C &&& !IS_C_INVERTED, 404);
$setup(CLR, negedge C &&& IS_C_INVERTED, 404);
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270
- //if (!IS_CLR_INVERTED) (posedge CLR => (Q : 1'b0)) = 764; // Captured by $__ABC9_ASYNC0
- //if ( IS_CLR_INVERTED) (negedge CLR => (Q : 1'b0)) = 764; // Captured by $__ABC9_ASYNC0
- if (!IS_C_INVERTED && CLR ~^ IS_CLR_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303;
- if ( IS_C_INVERTED && CLR ~^ IS_CLR_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303;
+`ifndef YOSYS
+ if (!IS_CLR_INVERTED) (posedge CLR => (Q : 1'b0)) = 764;
+ if ( IS_CLR_INVERTED) (negedge CLR => (Q : 1'b0)) = 764;
+`else
+ if (IS_CLR_INVERTED != CLR) (CLR => Q) = 764; // Technically, this should be an edge sensitive path
+ // but for facilitating a bypass box, let's pretend it's
+ // a simple path
+`endif
+ if (!IS_C_INVERTED && CLR == IS_CLR_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303;
+ if ( IS_C_INVERTED && CLR == IS_CLR_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303;
endspecify
endmodule
-(* abc9_flop, lib_whitebox *)
+(* abc9_box, lib_whitebox *)
module FDCE_1 (
output reg Q,
(* clkbuf_sink *)
@@ -697,18 +719,24 @@ module FDCE_1 (
always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
specify
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249
- //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported
+ $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248
$setup(CE , negedge C, 109);
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274
$setup(CLR, negedge C, 404);
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270
- //(posedge CLR => (Q : 1'b0)) = 764; // Captured by $__ABC9_ASYNC0
+`ifndef YOSYS
+ (posedge CLR => (Q : 1'b0)) = 764;
+`else
+ if (CLR) (CLR => Q) = 764; // Technically, this should be an edge sensitive path
+ // but for facilitating a bypass box, let's pretend it's
+ // a simple path
+`endif
if (!CLR && CE) (negedge C => (Q : D)) = 303;
endspecify
endmodule
-(* abc9_flop, lib_whitebox *)
+(* abc9_box, lib_whitebox *)
module FDPE (
output reg Q,
(* clkbuf_sink *)
@@ -734,8 +762,8 @@ module FDPE (
endgenerate
specify
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249
- //$setup(D , posedge C &&& !IS_C_INVERTED && CE, -46); // Negative times not currently supported
- //$setup(D , negedge C &&& IS_C_INVERTED && CE, -46); // Negative times not currently supported
+ $setup(D , posedge C &&& !IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported
+ $setup(D , negedge C &&& IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248
$setup(CE , posedge C &&& !IS_C_INVERTED, 109);
$setup(CE , negedge C &&& IS_C_INVERTED, 109);
@@ -743,14 +771,20 @@ module FDPE (
$setup(PRE, posedge C &&& !IS_C_INVERTED, 404);
$setup(PRE, negedge C &&& IS_C_INVERTED, 404);
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270
- //if (!IS_PRE_INVERTED) (posedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1
- //if ( IS_PRE_INVERTED) (negedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1
- if (!IS_C_INVERTED && PRE ~^ IS_PRE_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303;
- if ( IS_C_INVERTED && PRE ~^ IS_PRE_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303;
+`ifndef YOSYS
+ if (!IS_PRE_INVERTED) (posedge PRE => (Q : 1'b1)) = 764;
+ if ( IS_PRE_INVERTED) (negedge PRE => (Q : 1'b1)) = 764;
+`else
+ if (IS_PRE_INVERTED != PRE) (PRE => Q) = 764; // Technically, this should be an edge sensitive path
+ // but for facilitating a bypass box, let's pretend it's
+ // a simple path
+`endif
+ if (!IS_C_INVERTED && PRE == IS_PRE_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303;
+ if ( IS_C_INVERTED && PRE == IS_PRE_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303;
endspecify
endmodule
-(* abc9_flop, lib_whitebox *)
+(* abc9_box, lib_whitebox *)
module FDPE_1 (
output reg Q,
(* clkbuf_sink *)
@@ -764,14 +798,19 @@ module FDPE_1 (
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
specify
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249
- //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported
+ $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248
$setup(CE , negedge C, 109);
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274
$setup(PRE, negedge C, 404);
// https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270
- //if (!IS_PRE_INVERTED) (posedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1
- //if (IS_PRE_INVERTED) (negedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1
+`ifndef YOSYS
+ (posedge PRE => (Q : 1'b1)) = 764;
+`else
+ if (PRE) (PRE => Q) = 764; // Technically, this should be an edge sensitive path
+ // but for facilitating a bypass box, let's pretend it's
+ // a simple path
+`endif
if (!PRE && CE) (negedge C => (Q : D)) = 303;
endspecify
endmodule
@@ -1383,6 +1422,7 @@ module RAM16X1D_1 (
always @(negedge clk) if (WE) mem[a] <= D;
endmodule
+(* abc9_box, lib_whitebox *)
module RAM32X1D (
output DPO, SPO,
input D,
@@ -1429,15 +1469,15 @@ module RAM32X1D (
if (!IS_WCLK_INVERTED) (posedge WCLK => (DPO : 1'bx)) = 1153;
if ( IS_WCLK_INVERTED) (posedge WCLK => (SPO : D)) = 1153;
if ( IS_WCLK_INVERTED) (negedge WCLK => (DPO : 1'bx)) = 1153;
- // Captured by $__ABC9_RAM6
- //({A0,DPRA0} => {SPO,DPO}) = 642;
- //({A1,DPRA1} => {SPO,DPO}) = 631;
- //({A2,DPRA2} => {SPO,DPO}) = 472;
- //({A3,DPRA3} => {SPO,DPO}) = 407;
- //({A4,DPRA4} => {SPO,DPO}) = 238;
+ (A0 => SPO) = 642; (DPRA0 => DPO) = 642;
+ (A1 => SPO) = 632; (DPRA1 => DPO) = 631;
+ (A2 => SPO) = 472; (DPRA2 => DPO) = 472;
+ (A3 => SPO) = 407; (DPRA3 => DPO) = 407;
+ (A4 => SPO) = 238; (DPRA4 => DPO) = 238;
endspecify
endmodule
+(* abc9_box, lib_whitebox *)
module RAM32X1D_1 (
output DPO, SPO,
input D,
@@ -1479,15 +1519,15 @@ module RAM32X1D_1 (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
if (WE) (negedge WCLK => (SPO : D)) = 1153;
if (WE) (negedge WCLK => (DPO : 1'bx)) = 1153;
- // Captured by $__ABC9_RAM6
- //({A0,DPRA0} => {SPO,DPO}) = 642;
- //({A1,DPRA1} => {SPO,DPO}) = 631;
- //({A2,DPRA2} => {SPO,DPO}) = 472;
- //({A3,DPRA3} => {SPO,DPO}) = 407;
- //({A4,DPRA4} => {SPO,DPO}) = 238;
+ (A0 => SPO) = 642; (DPRA0 => DPO) = 642;
+ (A1 => SPO) = 632; (DPRA1 => DPO) = 631;
+ (A2 => SPO) = 472; (DPRA2 => DPO) = 472;
+ (A3 => SPO) = 407; (DPRA3 => DPO) = 407;
+ (A4 => SPO) = 238; (DPRA4 => DPO) = 238;
endspecify
endmodule
+(* abc9_box, lib_whitebox *)
module RAM64X1D (
output DPO, SPO,
input D,
@@ -1537,13 +1577,12 @@ module RAM64X1D (
if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (DPO : 1'bx)) = 1153;
if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (SPO : D)) = 1153;
if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DPO : 1'bx)) = 1153;
- // Captured by $__ABC9_RAM6
- //({A0,DPRA0} => {SPO,DPO}) = 642;
- //({A1,DPRA1} => {SPO,DPO}) = 631;
- //({A2,DPRA2} => {SPO,DPO}) = 472;
- //({A3,DPRA3} => {SPO,DPO}) = 407;
- //({A4,DPRA4} => {SPO,DPO}) = 238;
- //({A5,DPRA5} => {SPO,DPO}) = 127;
+ (A0 => SPO) = 642; (DPRA0 => DPO) = 642;
+ (A1 => SPO) = 632; (DPRA1 => DPO) = 631;
+ (A2 => SPO) = 472; (DPRA2 => DPO) = 472;
+ (A3 => SPO) = 407; (DPRA3 => DPO) = 407;
+ (A4 => SPO) = 238; (DPRA4 => DPO) = 238;
+ (A5 => SPO) = 127; (DPRA5 => DPO) = 127;
endspecify
endmodule
@@ -1586,9 +1625,16 @@ module RAM64X1D_1 (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
if (WE) (negedge WCLK => (SPO : D)) = 1153;
if (WE) (negedge WCLK => (DPO : 1'bx)) = 1153;
+ (A0 => SPO) = 642; (DPRA0 => DPO) = 642;
+ (A1 => SPO) = 632; (DPRA1 => DPO) = 631;
+ (A2 => SPO) = 472; (DPRA2 => DPO) = 472;
+ (A3 => SPO) = 407; (DPRA3 => DPO) = 407;
+ (A4 => SPO) = 238; (DPRA4 => DPO) = 238;
+ (A5 => SPO) = 127; (DPRA5 => DPO) = 127;
endspecify
endmodule
+(* abc9_box, lib_whitebox *)
module RAM128X1D (
output DPO, SPO,
input D,
@@ -1632,22 +1678,21 @@ module RAM128X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (SPO : D)) = 1153 + 217 /* to cross F7AMUX */ + 175 /* AMUX */;
if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DPO : 1'bx)) = 1153 + 223 /* to cross F7BMUX */ + 174 /* CMUX */;
+ (A[0] => SPO) = 642 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
+ (A[1] => SPO) = 631 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
+ (A[2] => SPO) = 472 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
+ (A[3] => SPO) = 407 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
+ (A[4] => SPO) = 238 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
+ (A[5] => SPO) = 127 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
+ (A[6] => SPO) = 0 + 276 /* to select F7AMUX */ + 175 /* AMUX */;
+ (DPRA[0] => DPO) = 642 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
+ (DPRA[1] => DPO) = 631 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
+ (DPRA[2] => DPO) = 472 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
+ (DPRA[3] => DPO) = 407 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
+ (DPRA[4] => DPO) = 238 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
+ (DPRA[5] => DPO) = 127 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
+ (DPRA[6] => DPO) = 0 + 296 /* to select MUXF7 */ + 174 /* CMUX */;
`endif
- // Captured by $__ABC9_RAM7
- //(A[0] => SPO) = 642 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
- //(A[1] => SPO) = 631 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
- //(A[2] => SPO) = 472 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
- //(A[3] => SPO) = 407 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
- //(A[4] => SPO) = 238 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
- //(A[5] => SPO) = 127 + 193 /* to cross F7AMUX */ + 175 /* AMUX */;
- //(A[6] => SPO) = 0 + 276 /* to select F7AMUX */ + 175 /* AMUX */;
- //(DPRA[0] => DPO) = 642 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
- //(DPRA[1] => DPO) = 631 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
- //(DPRA[2] => DPO) = 472 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
- //(DPRA[3] => DPO) = 407 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
- //(DPRA[4] => DPO) = 238 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
- //(DPRA[5] => DPO) = 127 + 223 /* to cross MUXF7 */ + 174 /* CMUX */;
- //(DPRA[6] => DPO) = 0 + 296 /* to select MUXF7 */ + 174 /* CMUX */;
endspecify
endmodule
@@ -1671,6 +1716,7 @@ endmodule
// Multi port.
+(* abc9_box, lib_whitebox *)
module RAM32M (
output [1:0] DOA,
output [1:0] DOB,
@@ -1767,12 +1813,11 @@ module RAM32M (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061
if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (DOD[1] : DID[1])) = 1190;
if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DOD[1] : DID[1])) = 1190;
- // Captured by $__ABC9_RAM6
- //({{2{ADDRA[0]}},{2{ADDRB[0]}},{2{ADDRC[0]}},{2{ADDRD[0]}}} => {DOA,DOB,DOC,DOD}) = 642;
- //({{2{ADDRA[1]}},{2{ADDRB[1]}},{2{ADDRC[1]}},{2{ADDRD[1]}}} => {DOA,DOB,DOC,DOD}) = 631;
- //({{2{ADDRA[2]}},{2{ADDRB[2]}},{2{ADDRC[2]}},{2{ADDRD[2]}}} => {DOA,DOB,DOC,DOD}) = 472;
- //({{2{ADDRA[3]}},{2{ADDRB[3]}},{2{ADDRC[3]}},{2{ADDRD[3]}}} => {DOA,DOB,DOC,DOD}) = 407;
- //({{2{ADDRA[4]}},{2{ADDRB[4]}},{2{ADDRC[4]}},{2{ADDRD[4]}}} => {DOA,DOB,DOC,DOD}) = 238;
+ (ADDRA[0] *> DOA) = 642; (ADDRB[0] *> DOB) = 642; (ADDRC[0] *> DOC) = 642; (ADDRD[0] *> DOD) = 642;
+ (ADDRA[1] *> DOA) = 631; (ADDRB[1] *> DOB) = 631; (ADDRC[1] *> DOC) = 631; (ADDRD[1] *> DOD) = 631;
+ (ADDRA[2] *> DOA) = 472; (ADDRB[2] *> DOB) = 472; (ADDRC[2] *> DOC) = 472; (ADDRD[2] *> DOD) = 472;
+ (ADDRA[3] *> DOA) = 407; (ADDRB[3] *> DOB) = 407; (ADDRC[3] *> DOC) = 407; (ADDRD[3] *> DOD) = 407;
+ (ADDRA[4] *> DOA) = 238; (ADDRB[4] *> DOB) = 238; (ADDRC[4] *> DOC) = 238; (ADDRD[4] *> DOD) = 238;
endspecify
endmodule
@@ -1845,6 +1890,7 @@ module RAM32M16 (
end
endmodule
+(* abc9_box, lib_whitebox *)
module RAM64M (
output DOA,
output DOB,
@@ -1923,12 +1969,11 @@ module RAM64M (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (DOD : DID)) = 1163;
if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DOD : DID)) = 1163;
- // Captured by $__ABC9_RAM6
- //({ADDRA[0],ADDRB[0],ADDRC[0],ADDRD[0]} => {DOA,DOB,DOC,DOD}) = 642;
- //({ADDRA[1],ADDRB[1],ADDRC[1],ADDRD[1]} => {DOA,DOB,DOC,DOD}) = 631;
- //({ADDRA[2],ADDRB[2],ADDRC[2],ADDRD[2]} => {DOA,DOB,DOC,DOD}) = 472;
- //({ADDRA[3],ADDRB[3],ADDRC[3],ADDRD[3]} => {DOA,DOB,DOC,DOD}) = 407;
- //({ADDRA[4],ADDRB[4],ADDRC[4],ADDRD[4]} => {DOA,DOB,DOC,DOD}) = 238;
+ (ADDRA[0] => DOA) = 642; (ADDRB[0] => DOB) = 642; (ADDRC[0] => DOC) = 642; (ADDRD[0] => DOD) = 642;
+ (ADDRA[1] => DOA) = 631; (ADDRB[1] => DOB) = 631; (ADDRC[1] => DOC) = 631; (ADDRD[1] => DOD) = 631;
+ (ADDRA[2] => DOA) = 472; (ADDRB[2] => DOB) = 472; (ADDRC[2] => DOC) = 472; (ADDRD[2] => DOD) = 472;
+ (ADDRA[3] => DOA) = 407; (ADDRB[3] => DOB) = 407; (ADDRC[3] => DOC) = 407; (ADDRD[3] => DOD) = 407;
+ (ADDRA[4] => DOA) = 238; (ADDRB[4] => DOB) = 238; (ADDRC[4] => DOC) = 238; (ADDRD[4] => DOD) = 238;
endspecify
endmodule
@@ -2045,6 +2090,7 @@ endmodule
// Shift registers.
+(* abc9_box, lib_whitebox *)
module SRL16 (
output Q,
input A0, A1, A2, A3,
@@ -2063,14 +2109,14 @@ module SRL16 (
(posedge CLK => (Q : 1'bx)) = 1472;
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912
$setup(D , posedge CLK, 173);
- // Captured by $__ABC9_RAM6
- //(A0 => Q) = 631;
- //(A1 => Q) = 472;
- //(A2 => Q) = 407;
- //(A3 => Q) = 238;
+ (A0 => Q) = 631;
+ (A1 => Q) = 472;
+ (A2 => Q) = 407;
+ (A3 => Q) = 238;
endspecify
endmodule
+(* abc9_box, lib_whitebox *)
module SRL16E (
output Q,
input A0, A1, A2, A3, CE,
@@ -2096,16 +2142,19 @@ module SRL16E (
$setup(D , posedge CLK &&& !IS_CLK_INVERTED, 173);
$setup(D , negedge CLK &&& IS_CLK_INVERTED, 173);
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905
+ if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : D)) = 1472;
+ if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : D)) = 1472;
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905
if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : 1'bx)) = 1472;
if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : 1'bx)) = 1472;
- // Captured by $__ABC9_RAM6
- //(A0 => Q) = 631;
- //(A1 => Q) = 472;
- //(A2 => Q) = 407;
- //(A3 => Q) = 238;
+ (A0 => Q) = 631;
+ (A1 => Q) = 472;
+ (A2 => Q) = 407;
+ (A3 => Q) = 238;
endspecify
endmodule
+(* abc9_box, lib_whitebox *)
module SRLC16 (
output Q,
output Q15,
@@ -2122,18 +2171,20 @@ module SRLC16 (
always @(posedge CLK) r <= { r[14:0], D };
specify
- // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905
- (posedge CLK => (Q : 1'bx)) = 1472;
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912
$setup(D , posedge CLK, 173);
- // Captured by $__ABC9_RAM6
- //(A0 => Q) = 631;
- //(A1 => Q) = 472;
- //(A2 => Q) = 407;
- //(A3 => Q) = 238;
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905
+ (posedge CLK => (Q : 1'bx)) = 1472;
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904
+ (posedge CLK => (Q15 : 1'bx)) = 1114;
+ (A0 => Q) = 631;
+ (A1 => Q) = 472;
+ (A2 => Q) = 407;
+ (A3 => Q) = 238;
endspecify
endmodule
+(* abc9_box, lib_whitebox *)
module SRLC16E (
output Q,
output Q15,
@@ -2160,18 +2211,23 @@ module SRLC16E (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912
$setup(D , posedge CLK &&& !IS_CLK_INVERTED, 173);
$setup(D , negedge CLK &&& IS_CLK_INVERTED, 173);
+ // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248
+ $setup(CE, posedge CLK &&& !IS_CLK_INVERTED, 109);
+ $setup(CE, negedge CLK &&& IS_CLK_INVERTED, 109);
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905
if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : D)) = 1472;
if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : D)) = 1472;
- // Captured by $__ABC9_RAM6
- //(A0 => Q) = 642;
- //(A1 => Q) = 631;
- //(A2 => Q) = 472;
- //(A3 => Q) = 407;
- //(A4 => Q) = 238;
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904
+ if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q15 : 1'bx)) = 1114;
+ if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q15 : 1'bx)) = 1114;
+ (A0 => Q) = 631;
+ (A1 => Q) = 472;
+ (A2 => Q) = 407;
+ (A3 => Q) = 238;
endspecify
endmodule
+(* abc9_box, lib_whitebox *)
module SRLC32E (
output Q,
output Q31,
@@ -2199,18 +2255,20 @@ module SRLC32E (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912
$setup(D , posedge CLK &&& !IS_CLK_INVERTED, 173);
$setup(D , negedge CLK &&& IS_CLK_INVERTED, 173);
+ // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248
+ $setup(CE, posedge CLK &&& !IS_CLK_INVERTED, 109);
+ $setup(CE, negedge CLK &&& IS_CLK_INVERTED, 109);
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905
if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : 1'bx)) = 1472;
if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : 1'bx)) = 1472;
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904
- if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : 1'bx)) = 1114;
- if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : 1'bx)) = 1114;
- // Captured by $__ABC9_RAM6
- //(A0 => Q) = 642;
- //(A1 => Q) = 631;
- //(A2 => Q) = 472;
- //(A3 => Q) = 407;
- //(A4 => Q) = 238;
+ if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q31 : 1'bx)) = 1114;
+ if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q31 : 1'bx)) = 1114;
+ (A[0] => Q) = 642;
+ (A[1] => Q) = 631;
+ (A[2] => Q) = 472;
+ (A[3] => Q) = 407;
+ (A[4] => Q) = 238;
endspecify
endmodule
@@ -2978,6 +3036,10 @@ endmodule
// Virtex 6, Series 7.
+`ifdef YOSYS
+(* abc9_box=!(PREG || AREG || ADREG || BREG || CREG || DREG || MREG),
+ lib_whitebox=!(PREG || AREG || ADREG || BREG || CREG || DREG || MREG) *)
+`endif
module DSP48E1 (
output [29:0] ACOUT,
output [17:0] BCOUT,
@@ -3325,10 +3387,10 @@ module DSP48E1 (
reg signed [24:0] Dr;
reg signed [17:0] Br1, Br2;
reg signed [47:0] Cr;
- reg [4:0] INMODEr = 5'b0;
- reg [6:0] OPMODEr = 7'b0;
- reg [3:0] ALUMODEr = 4'b0;
- reg [2:0] CARRYINSELr = 3'b0;
+ reg [4:0] INMODEr;
+ reg [6:0] OPMODEr;
+ reg [3:0] ALUMODEr;
+ reg [2:0] CARRYINSELr;
generate
// Configurable A register
@@ -3510,11 +3572,13 @@ module DSP48E1 (
// Carry in
wire A24_xnor_B17d = A_MULT[24] ~^ B_MULT[17];
- reg CARRYINr = 1'b0, A24_xnor_B17 = 1'b0;
+ reg CARRYINr, A24_xnor_B17;
generate
+ if (CARRYINREG == 1) initial CARRYINr = 1'b0;
if (CARRYINREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) CARRYINr <= 1'b0; else if (CECARRYIN) CARRYINr <= CARRYIN; end
else always @* CARRYINr = CARRYIN;
+ if (MREG == 1) initial A24_xnor_B17 = 1'b0;
if (MREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) A24_xnor_B17 <= 1'b0; else if (CEM) A24_xnor_B17 <= A24_xnor_B17d; end
else always @* A24_xnor_B17 = A24_xnor_B17d;
endgenerate
diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v
index ec2e3b234..2ab6075f1 100644
--- a/techlibs/xilinx/lut_map.v
+++ b/techlibs/xilinx/lut_map.v
@@ -26,6 +26,7 @@ module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
+ (* force_downto *)
input [WIDTH-1:0] A;
output Y;
diff --git a/techlibs/xilinx/mux_map.v b/techlibs/xilinx/mux_map.v
index 91aaf2118..bb31d21ec 100644
--- a/techlibs/xilinx/mux_map.v
+++ b/techlibs/xilinx/mux_map.v
@@ -30,8 +30,11 @@ module \$shiftx (A, B, Y);
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;
parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0;
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 229ffcb3d..d0de73f83 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -143,7 +143,7 @@ struct SynthXilinxPass : public ScriptPass
std::string top_opt, edif_file, blif_file, family;
bool flatten, retime, vpr, ise, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram;
- bool abc9, dff_mode;
+ bool abc9, dff;
bool flatten_before_abc;
int widemux;
int lut_size;
@@ -170,7 +170,7 @@ struct SynthXilinxPass : public ScriptPass
nodsp = false;
uram = false;
abc9 = false;
- dff_mode = false;
+ dff = false;
flatten_before_abc = false;
widemux = 0;
lut_size = 6;
@@ -217,7 +217,7 @@ struct SynthXilinxPass : public ScriptPass
continue;
}
if (args[argidx] == "-retime") {
- dff_mode = true;
+ dff = true;
retime = true;
continue;
}
@@ -281,7 +281,7 @@ struct SynthXilinxPass : public ScriptPass
continue;
}
if (args[argidx] == "-dff") {
- dff_mode = true;
+ dff = true;
continue;
}
break;
@@ -595,9 +595,11 @@ struct SynthXilinxPass : public ScriptPass
run("clean");
}
- if (check_label("map_ffs")) {
+ if (check_label("map_ffs", "('-abc9' only)")) {
if (abc9 || help_mode) {
- run("techmap -map " + ff_map_file, "('-abc9' only)");
+ if (dff || help_mode)
+ run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "('-dff' only)");
+ run("techmap -map " + ff_map_file);
}
}
@@ -606,18 +608,14 @@ struct SynthXilinxPass : public ScriptPass
if (flatten_before_abc)
run("flatten");
if (help_mode)
- run("abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1]", "(option for 'nowidelut', '-dff', '-retime')");
+ run("abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1]", "(option for '-nowidelut', '-dff', '-retime')");
else if (abc9) {
if (lut_size != 6)
log_error("'synth_xilinx -abc9' not currently supported for LUT4-based devices.\n");
if (family != "xc7")
log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, "
"will use timing for 'xc7' instead.\n", family.c_str());
- std::string techmap_args = "-map +/xilinx/abc9_map.v -max_iter 1";
- if (dff_mode)
- techmap_args += " -D DFF_MODE";
- run("techmap " + techmap_args);
- run("read_verilog -icells -lib -specify +/abc9_model.v +/xilinx/abc9_model.v");
+ run("read_verilog -icells -lib -specify +/xilinx/abc9_model.v");
std::string abc9_opts;
std::string k = "synth_xilinx.abc9.W";
if (active_design && active_design->scratchpad.count(k))
@@ -628,10 +626,9 @@ struct SynthXilinxPass : public ScriptPass
}
if (nowidelut)
abc9_opts += stringf(" -maxlut %d", lut_size);
- if (dff_mode)
+ if (dff)
abc9_opts += " -dff";
run("abc9" + abc9_opts);
- run("techmap -map +/xilinx/abc9_unmap.v");
}
else {
std::string abc_opts;
@@ -648,7 +645,7 @@ struct SynthXilinxPass : public ScriptPass
else
abc_opts += " -luts 2:2,3,6:5,10,20,40";
}
- if (dff_mode)
+ if (dff)
abc_opts += " -dff";
if (retime)
abc_opts += " -D 1";
diff --git a/tests/arch/ice40/mux.ys b/tests/arch/ice40/mux.ys
index 99822391d..2b661fd6b 100644
--- a/tests/arch/ice40/mux.ys
+++ b/tests/arch/ice40/mux.ys
@@ -35,6 +35,7 @@ proc
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux16 # Constrain all select calls below inside the top module
-select -assert-count 11 t:SB_LUT4
+select -assert-min 11 t:SB_LUT4
+select -assert-max 12 t:SB_LUT4
select -assert-none t:SB_LUT4 %% t:* %D
diff --git a/tests/arch/xilinx/abc9_dff.ys b/tests/arch/xilinx/abc9_dff.ys
index b457cefce..fd343969b 100644
--- a/tests/arch/xilinx/abc9_dff.ys
+++ b/tests/arch/xilinx/abc9_dff.ys
@@ -1,32 +1,85 @@
+logger -nowarn "Yosys has only limited support for tri-state logic at the moment\. .*"
+
+read_verilog <<EOT
+module top(input C, D, output [7:0] Q);
+FDRE /*#(.INIT(0))*/ fd1(.C(C), .CE(1'b1), .D(D), .R(1'b1), .Q(Q[0]));
+FDSE #(.INIT(0)) fd2(.C(C), .CE(1'b1), .D(D), .S(1'b1), .Q(Q[1]));
+FDCE #(.INIT(0)) fd3(.C(C), .CE(1'b1), .D(D), .CLR(1'b1), .Q(Q[2]));
+FDPE #(.INIT(0)) fd4(.C(C), .CE(1'b1), .D(D), .PRE(1'b1), .Q(Q[3]));
+FDRE_1 #(.INIT(0)) fd5(.C(C), .CE(1'b1), .D(D), .R(1'b1), .Q(Q[4]));
+FDSE_1 #(.INIT(0)) fd6(.C(C), .CE(1'b1), .D(D), .S(1'b1), .Q(Q[5]));
+FDCE_1 #(.INIT(0)) fd7(.C(C), .CE(1'b1), .D(D), .CLR(1'b1), .Q(Q[6]));
+FDPE_1 #(.INIT(0)) fd8(.C(C), .CE(1'b1), .D(D), .PRE(1'b1), .Q(Q[7]));
+endmodule
+EOT
+equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf
+design -load postopt
+select -assert-count 6 t:FD*
+select -assert-count 6 c:fd2 c:fd3 c:fd4 c:fd6 c:fd7 c:fd8
+
+
+design -reset
read_verilog <<EOT
module top(input C, D, output [7:0] Q);
-FDRE fd1(.C(C), .CE(1'b1), .D(D), .R(1'b1), .Q(Q[0]));
-FDSE fd2(.C(C), .CE(1'b1), .D(D), .S(1'b1), .Q(Q[1]));
-FDCE fd3(.C(C), .CE(1'b1), .D(D), .CLR(1'b1), .Q(Q[2]));
-FDPE fd4(.C(C), .CE(1'b1), .D(D), .PRE(1'b1), .Q(Q[3]));
-FDRE_1 fd5(.C(C), .CE(1'b1), .D(D), .R(1'b1), .Q(Q[4]));
-FDSE_1 fd6(.C(C), .CE(1'b1), .D(D), .S(1'b1), .Q(Q[5]));
-FDCE_1 fd7(.C(C), .CE(1'b1), .D(D), .CLR(1'b1), .Q(Q[6]));
-FDPE_1 fd8(.C(C), .CE(1'b1), .D(D), .PRE(1'b1), .Q(Q[7]));
+FDRE #(.INIT(0)) fd1(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[0]));
+FDSE #(.INIT(0)) fd2(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[1]));
+FDCE #(.INIT(0)) fd3(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[2]));
+FDPE #(.INIT(0)) fd4(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[3]));
+FDRE_1 /*#(.INIT(0))*/ fd5(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[4]));
+FDSE_1 #(.INIT(0)) fd6(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[5]));
+FDCE_1 #(.INIT(0)) fd7(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[6]));
+FDPE_1 #(.INIT(0)) fd8(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[7]));
endmodule
EOT
equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf
design -load postopt
-select -assert-none t:FD*
+select -assert-count 4 t:FD*
+select -assert-count 4 c:fd3 c:fd4 c:fd7 c:fd8
+
design -reset
read_verilog <<EOT
module top(input C, D, output [7:0] Q);
-FDRE fd1(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[0]));
-FDSE fd2(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[1]));
-FDCE fd3(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[2]));
-FDPE fd4(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[3]));
-FDRE_1 fd5(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[4]));
-FDSE_1 fd6(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[5]));
-FDCE_1 fd7(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[6]));
-FDPE_1 fd8(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[7]));
+FDRE #(.INIT(1)) fd1(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[0]));
+FDSE /*#(.INIT(1))*/ fd2(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[1]));
+FDCE #(.INIT(1)) fd3(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[2]));
+FDPE #(.INIT(1)) fd4(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[3]));
+FDRE_1 #(.INIT(1)) fd5(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[4]));
+FDSE_1 #(.INIT(1)) fd6(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[5]));
+FDCE_1 /*#(.INIT(1))*/ fd7(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[6]));
+FDPE_1 #(.INIT(1)) fd8(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[7]));
+endmodule
+EOT
+logger -expect warning "Module '\$paramod\\FDRE\\INIT=1' contains a \$dff cell .*" 1
+logger -expect warning "Module '\$paramod\\FDRE_1\\INIT=1' contains a \$dff cell .*" 1
+logger -expect warning "Module 'FDSE' contains a \$dff cell .*" 1
+logger -expect warning "Module '\$paramod\\FDSE_1\\INIT=1' contains a \$dff cell .*" 1
+equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf
+design -load postopt
+select -assert-count 8 t:FD*
+
+
+design -reset
+read_verilog <<EOT
+module top(input clk, clr, pre, output reg q0 = 1'b0, output reg q1 = 1'b1);
+always @(posedge clk or posedge clr)
+ if (clr)
+ q0 <= 1'b0;
+ else
+ q0 <= ~q0;
+always @(posedge clk or posedge pre)
+ if (pre)
+ q1 <= 1'b1;
+ else
+ q1 <= ~q1;
endmodule
EOT
+proc
equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf
design -load postopt
-select -assert-none t:FD*
+select -assert-count 1 t:FDCE
+select -assert-count 1 t:FDPE
+select -assert-count 2 t:INV
+select -assert-count 0 t:FD* t:INV %% t:* %D
+
+logger -expect-no-warnings
diff --git a/tests/arch/xilinx/abc9_map.ys b/tests/arch/xilinx/abc9_map.ys
deleted file mode 100644
index 4a7b9384a..000000000
--- a/tests/arch/xilinx/abc9_map.ys
+++ /dev/null
@@ -1,91 +0,0 @@
-read_verilog <<EOT
-module top(input C, CE, D, R, output [1:0] Q);
-FDRE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .R(R), .Q(Q[0]));
-FDRE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .R(R), .Q(Q[1]));
-endmodule
-EOT
-design -save gold
-
-techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE
-techmap -map +/xilinx/abc9_unmap.v
-select -assert-count 1 t:FDSE
-select -assert-count 1 t:FDSE_1
-techmap -autoproc -map +/xilinx/cells_sim.v
-design -stash gate
-
-design -import gold -as gold
-design -import gate -as gate
-techmap -autoproc -map +/xilinx/cells_sim.v
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -seq 2 -verify -prove-asserts -show-ports miter
-
-design -reset
-read_verilog <<EOT
-module top(input C, CE, D, S, output [1:0] Q);
-FDSE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .S(S), .Q(Q[0]));
-FDSE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .S(S), .Q(Q[1]));
-endmodule
-EOT
-design -save gold
-
-techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE
-techmap -map +/xilinx/abc9_unmap.v
-select -assert-count 1 t:FDRE
-select -assert-count 1 t:FDRE_1
-techmap -autoproc -map +/xilinx/cells_sim.v
-design -stash gate
-
-design -import gold -as gold
-design -import gate -as gate
-techmap -autoproc -map +/xilinx/cells_sim.v
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter
-
-design -reset
-read_verilog <<EOT
-module top(input C, CE, D, PRE, output [1:0] Q);
-FDPE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .PRE(PRE), .Q(Q[0]));
-FDPE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .PRE(PRE), .Q(Q[1]));
-endmodule
-EOT
-design -save gold
-
-techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE
-techmap -map +/xilinx/abc9_unmap.v
-select -assert-count 1 t:FDCE
-select -assert-count 1 t:FDCE_1
-techmap -autoproc -map +/xilinx/cells_sim.v
-design -stash gate
-
-design -import gold -as gold
-design -import gate -as gate
-techmap -autoproc -map +/xilinx/cells_sim.v
-clk2fflogic
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter
-
-design -reset
-read_verilog <<EOT
-module top(input C, CE, D, CLR, output [1:0] Q);
-FDCE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .CLR(CLR), .Q(Q[0]));
-FDCE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .CLR(CLR), .Q(Q[1]));
-endmodule
-EOT
-design -save gold
-
-techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE
-techmap -map +/xilinx/abc9_unmap.v
-select -assert-count 1 t:FDPE
-techmap -autoproc -map +/xilinx/cells_sim.v
-design -stash gate
-
-design -import gold -as gold
-design -import gate -as gate
-techmap -autoproc -map +/xilinx/cells_sim.v
-clk2fflogic
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter
diff --git a/tests/arch/xilinx/macc.v b/tests/arch/xilinx/macc.v
index e36b2bab1..1645537fd 100644
--- a/tests/arch/xilinx/macc.v
+++ b/tests/arch/xilinx/macc.v
@@ -10,10 +10,10 @@ module macc # (parameter SIZEIN = 16, SIZEOUT = 40) (
output signed [SIZEOUT-1:0] accum_out
);
// Declare registers for intermediate values
-reg signed [SIZEIN-1:0] a_reg, b_reg;
-reg sload_reg;
-reg signed [2*SIZEIN-1:0] mult_reg;
-reg signed [SIZEOUT-1:0] adder_out, old_result;
+reg signed [SIZEIN-1:0] a_reg = 0, b_reg = 0;
+reg sload_reg = 0;
+reg signed [2*SIZEIN-1:0] mult_reg = 0;
+reg signed [SIZEOUT-1:0] adder_out = 0, old_result;
always @* /*(adder_out or sload_reg)*/ begin // Modification necessary to fix sim/synth mismatch
if (sload_reg)
old_result <= 0;
@@ -50,10 +50,10 @@ module macc2 # (parameter SIZEIN = 16, SIZEOUT = 40) (
output overflow
);
// Declare registers for intermediate values
-reg signed [SIZEIN-1:0] a_reg, b_reg, a_reg2, b_reg2;
+reg signed [SIZEIN-1:0] a_reg = 0, b_reg = 0, a_reg2 = 0, b_reg2 = 0;
reg signed [2*SIZEIN-1:0] mult_reg = 0;
reg signed [SIZEOUT:0] adder_out = 0;
-reg overflow_reg;
+reg overflow_reg = 0;
always @(posedge clk) begin
//if (ce)
begin
diff --git a/tests/arch/xilinx/macc.ys b/tests/arch/xilinx/macc.ys
index bf2b36320..61a570f48 100644
--- a/tests/arch/xilinx/macc.ys
+++ b/tests/arch/xilinx/macc.ys
@@ -6,7 +6,7 @@ proc
#equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad ### TODO
equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx -noiopad
miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -verify -prove-asserts -seq 10 -show-inputs -show-outputs miter
+sat -verify -prove-asserts -seq 3 -show-inputs -show-outputs miter
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd macc # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
@@ -20,7 +20,7 @@ proc
#equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad ### TODO
equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx -noiopad
miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -verify -prove-asserts -seq 10 -show-inputs -show-outputs miter
+sat -verify -prove-asserts -seq 4 -show-inputs -show-outputs miter
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd macc2 # Constrain all select calls below inside the top module
diff --git a/tests/arch/xilinx/mux.ys b/tests/arch/xilinx/mux.ys
index 99817738d..1b2788448 100644
--- a/tests/arch/xilinx/mux.ys
+++ b/tests/arch/xilinx/mux.ys
@@ -40,8 +40,10 @@ proc
equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux16 # Constrain all select calls below inside the top module
-select -assert-min 5 t:LUT6
+select -assert-max 2 t:LUT4
+select -assert-min 4 t:LUT6
select -assert-max 7 t:LUT6
select -assert-max 2 t:MUXF7
+dump
-select -assert-none t:LUT6 t:MUXF7 %% t:* %D
+select -assert-none t:LUT6 t:LUT4 t:MUXF7 %% t:* %D
diff --git a/tests/arch/xilinx/pmgen_xilinx_srl.ys b/tests/arch/xilinx/pmgen_xilinx_srl.ys
index ea2f20487..e76fb20ab 100644
--- a/tests/arch/xilinx/pmgen_xilinx_srl.ys
+++ b/tests/arch/xilinx/pmgen_xilinx_srl.ys
@@ -1,6 +1,6 @@
read_verilog -icells <<EOT
module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO);
- parameter DEPTH = 1;
+ parameter DEPTH = 2;
parameter [DEPTH-1:0] INIT = 0;
parameter CLKPOL = 1;
parameter ENPOL = 2;
diff --git a/tests/arch/xilinx/xilinx_srl.v b/tests/arch/xilinx/xilinx_srl.v
index bc2a15ab2..29920da41 100644
--- a/tests/arch/xilinx/xilinx_srl.v
+++ b/tests/arch/xilinx/xilinx_srl.v
@@ -29,7 +29,7 @@ endmodule
module $__XILINX_SHREG_(input C, D, E, input [1:0] L, output Q);
parameter CLKPOL = 1;
parameter ENPOL = 1;
-parameter DEPTH = 1;
+parameter DEPTH = 2;
parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}};
reg [DEPTH-1:0] r = INIT;
wire clk = C ^ CLKPOL;
diff --git a/tests/fsm/generate.py b/tests/fsm/generate.py
index c8eda0cd1..784e5a054 100644
--- a/tests/fsm/generate.py
+++ b/tests/fsm/generate.py
@@ -36,9 +36,11 @@ parser.add_argument('-S', '--seed', type = int, help = 'seed for PRNG')
parser.add_argument('-c', '--count', type = int, default = 50, help = 'number of test cases to generate')
args = parser.parse_args()
-if args.seed is not None:
- print("PRNG seed: %d" % args.seed)
- random.seed(args.seed)
+seed = args.seed
+if seed is None:
+ seed = random.randrange(sys.maxsize)
+print("PRNG seed: %d" % seed)
+random.seed(seed)
for idx in range(args.count):
with open('temp/uut_%05d.v' % idx, 'w') as f:
diff --git a/tests/opt/bug1758.ys b/tests/opt/bug1758.ys
new file mode 100644
index 000000000..85dfaceb8
--- /dev/null
+++ b/tests/opt/bug1758.ys
@@ -0,0 +1,21 @@
+read_verilog -noopt <<EOT
+module gold(input i, output o);
+assign o = 1'bx | i;
+endmodule
+EOT
+copy gold coarse
+copy gold fine
+
+cd coarse
+opt_expr
+select -assert-none c:*
+
+cd fine
+opt_expr
+select -assert-none c:*
+
+cd
+miter -equiv -flatten -make_assert -make_outputs coarse fine miter
+sat -verify -prove-asserts -show-ports miter
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter2
+sat -verify -prove-asserts -show-ports -enable_undef miter2
diff --git a/tests/opt/opt_clean_init.ys b/tests/opt/opt_clean_init.ys
new file mode 100644
index 000000000..0d567608d
--- /dev/null
+++ b/tests/opt/opt_clean_init.ys
@@ -0,0 +1,13 @@
+logger -expect warning "Initial value conflict for \\y resolving to 1'0 but with init 1'1" 1
+logger -expect-no-warnings
+read_verilog <<EOT
+module top;
+(* init=1'b0 *) wire w = 1'b0;
+(* init=1'bx *) wire x = 1'b0;
+(* init=1'b1 *) wire y = 1'b0;
+(* init=1'b0 *) wire z = 1'bx;
+endmodule
+EOT
+clean
+select -assert-count 1 a:init
+select -assert-count 1 w:y a:init %i
diff --git a/tests/opt/opt_expr_alu.ys b/tests/opt/opt_expr_alu.ys
index 9121c0096..477555da9 100644
--- a/tests/opt/opt_expr_alu.ys
+++ b/tests/opt/opt_expr_alu.ys
@@ -59,9 +59,8 @@ EOT
alumacc
equiv_opt -assert opt_expr -fine
design -load postopt
-select -assert-count 1 t:$pos
select -assert-count 1 t:$not
-select -assert-none t:$pos t:$not %% t:* %D
+select -assert-none t:$not %% t:* %D
design -reset
diff --git a/tests/opt/opt_expr_and.ys b/tests/opt/opt_expr_and.ys
new file mode 100644
index 000000000..a7676a1df
--- /dev/null
+++ b/tests/opt/opt_expr_and.ys
@@ -0,0 +1,85 @@
+# Single-bit $and
+read_verilog -noopt <<EOT
+module gold(input i, output o);
+assign o = 1'bx & i;
+endmodule
+EOT
+select -assert-count 1 t:$and
+copy gold coarse
+copy gold fine
+copy gold coarse_keepdc
+copy gold fine_keepdc
+
+cd coarse
+opt_expr
+select -assert-none c:*
+
+cd fine
+simplemap
+opt_expr
+select -assert-none c:*
+
+cd
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
+sat -verify -prove-asserts -show-ports -enable_undef miter
+miter -equiv -flatten -make_assert -make_outputs coarse fine miter2
+sat -verify -prove-asserts -show-ports -enable_undef miter2
+
+cd coarse_keepdc
+opt_expr -keepdc
+select -assert-count 1 c:*
+
+cd fine_keepdc
+simplemap
+opt_expr -keepdc
+select -assert-count 1 c:*
+
+cd
+miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3
+sat -verify -prove-asserts -show-ports -enable_undef miter3
+miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4
+sat -verify -prove-asserts -show-ports -enable_undef miter4
+
+
+# Multi-bit $and
+design -reset
+read_verilog -noopt <<EOT
+module gold(input i, output [6:0] o);
+assign o = {1'bx, 1'b0, 1'b0, 1'b1, 1'bx, 1'b1, i} & {7{i}};
+endmodule
+EOT
+select -assert-count 1 t:$and
+copy gold coarse
+copy gold fine
+copy gold coarse_keepdc
+copy gold fine_keepdc
+
+cd coarse
+opt_expr -fine
+select -assert-none c:*
+
+cd fine
+simplemap
+opt_expr
+select -assert-none c:*
+
+cd
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
+sat -verify -prove-asserts -show-ports -enable_undef miter
+miter -equiv -flatten -make_assert -make_outputs coarse fine miter2
+sat -verify -prove-asserts -show-ports -enable_undef miter2
+
+cd coarse_keepdc
+opt_expr -fine -keepdc
+select -assert-count 1 c:*
+
+cd fine_keepdc
+simplemap
+opt_expr -keepdc
+select -assert-count 2 c:*
+
+cd
+miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3
+sat -verify -prove-asserts -show-ports -enable_undef miter3
+miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4
+sat -verify -prove-asserts -show-ports -enable_undef miter4
diff --git a/tests/opt/opt_expr_consumex.ys b/tests/opt/opt_expr_consumex.ys
new file mode 100644
index 000000000..d4af10f22
--- /dev/null
+++ b/tests/opt/opt_expr_consumex.ys
@@ -0,0 +1,35 @@
+read_verilog <<EOT
+module top(input a, b, output o);
+wire tmp;
+assign o = tmp | 1'bx;
+assign tmp = a & 1'b0;
+endmodule
+EOT
+design -save read
+select -assert-count 1 t:$and
+select -assert-count 1 t:$or
+
+
+opt_expr
+select -assert-none t:$and t:$or
+sat -verify -enable_undef -prove o 1'bx
+
+
+design -load read
+opt_expr -keepdc
+select -assert-none t:$and t:$or
+sat -verify -enable_undef -prove o 1'bx
+
+
+design -load read
+simplemap
+opt_expr -keepdc
+select -assert-none t:$_AND_ t:$_OR_
+sat -verify -enable_undef -prove o 1'bx
+
+
+design -load read
+simplemap
+opt_expr -keepdc
+select -assert-none t:$_AND_ t:$_OR_
+sat -verify -enable_undef -prove o 1'bx
diff --git a/tests/opt/opt_expr_or.ys b/tests/opt/opt_expr_or.ys
new file mode 100644
index 000000000..f86da0d46
--- /dev/null
+++ b/tests/opt/opt_expr_or.ys
@@ -0,0 +1,85 @@
+# Single-bit $or
+read_verilog -noopt <<EOT
+module gold(input i, output o);
+assign o = 1'bx | i;
+endmodule
+EOT
+select -assert-count 1 t:$or
+copy gold coarse
+copy gold fine
+copy gold coarse_keepdc
+copy gold fine_keepdc
+
+cd coarse
+opt_expr
+select -assert-none c:*
+
+cd fine
+simplemap
+opt_expr
+select -assert-none c:*
+
+cd
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
+sat -verify -prove-asserts -show-ports -enable_undef miter
+miter -equiv -flatten -make_assert -make_outputs coarse fine miter2
+sat -verify -prove-asserts -show-ports -enable_undef miter2
+
+cd coarse_keepdc
+opt_expr -keepdc
+select -assert-count 1 c:*
+
+cd fine_keepdc
+simplemap
+opt_expr -keepdc
+select -assert-count 1 c:*
+
+cd
+miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3
+sat -verify -prove-asserts -show-ports -enable_undef miter3
+miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4
+sat -verify -prove-asserts -show-ports -enable_undef miter4
+
+
+# Multi-bit $or
+design -reset
+read_verilog -noopt <<EOT
+module gold(input i, output [6:0] o);
+assign o = {1'bx, 1'b0, 1'b0, 1'b1, 1'bx, 1'b1, i} | {7{i}};
+endmodule
+EOT
+select -assert-count 1 t:$or
+copy gold coarse
+copy gold fine
+copy gold coarse_keepdc
+copy gold fine_keepdc
+
+cd coarse
+opt_expr -fine
+select -assert-none c:*
+
+cd fine
+simplemap
+opt_expr
+select -assert-none c:*
+
+cd
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
+sat -verify -prove-asserts -show-ports -enable_undef miter
+miter -equiv -flatten -make_assert -make_outputs coarse fine miter2
+sat -verify -prove-asserts -show-ports -enable_undef miter2
+
+cd coarse_keepdc
+opt_expr -fine -keepdc
+select -assert-count 1 c:*
+
+cd fine_keepdc
+simplemap
+opt_expr -keepdc
+select -assert-count 2 c:*
+
+cd
+miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3
+sat -verify -prove-asserts -show-ports -enable_undef miter3
+miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4
+sat -verify -prove-asserts -show-ports -enable_undef miter4
diff --git a/tests/opt/opt_expr_xnor.ys b/tests/opt/opt_expr_xnor.ys
new file mode 100644
index 000000000..f8ef0d352
--- /dev/null
+++ b/tests/opt/opt_expr_xnor.ys
@@ -0,0 +1,131 @@
+# Single-bit $xnor
+read_verilog -noopt <<EOT
+module gold(input i, output o);
+assign o = 1'bx ~^ i;
+endmodule
+EOT
+select -assert-count 1 t:$xnor
+copy gold coarse
+copy gold fine
+copy gold coarse_keepdc
+copy gold fine_keepdc
+
+cd coarse
+opt_expr
+select -assert-none t:$xnor
+
+cd fine
+simplemap
+opt_expr
+select -assert-none c:t$_XNOR_
+
+cd
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
+sat -verify -prove-asserts -show-ports -enable_undef miter
+miter -equiv -flatten -make_assert -make_outputs coarse fine miter2
+sat -verify -prove-asserts -show-ports -enable_undef miter2
+
+cd coarse_keepdc
+opt_expr -keepdc
+select -assert-count 1 c:*
+
+cd fine_keepdc
+simplemap
+opt_expr -keepdc
+select -assert-count 1 t:$_XOR_
+
+cd
+miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3
+sat -verify -prove-asserts -show-ports -enable_undef miter3
+miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4
+sat -verify -prove-asserts -show-ports -enable_undef miter4
+
+
+# Multi-bit $xnor
+design -reset
+read_verilog -noopt <<EOT
+module gold(input i, output [6:0] o);
+assign o = {1'bx, 1'b0, 1'b0, 1'b1, 1'bx, 1'b1, i} ~^ {7{i}};
+endmodule
+EOT
+select -assert-count 1 t:$xnor
+copy gold coarse
+copy gold fine
+copy gold coarse_keepdc
+copy gold fine_keepdc
+
+cd coarse
+opt_expr -fine
+select -assert-none t:$xnor
+
+cd fine
+simplemap
+opt_expr
+select -assert-none t:$_XNOR_
+
+cd
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
+sat -verify -prove-asserts -show-ports -enable_undef miter
+miter -equiv -flatten -make_assert -make_outputs coarse fine miter2
+sat -verify -prove-asserts -show-ports -enable_undef miter2
+
+cd coarse_keepdc
+opt_expr -keepdc -fine
+select -assert-count 1 t:$xnor
+
+cd fine_keepdc
+simplemap
+opt_expr -keepdc
+select -assert-count 0 c:$_XOR_
+
+cd
+miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3
+sat -verify -prove-asserts -show-ports -enable_undef miter3
+miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4
+sat -verify -prove-asserts -show-ports -enable_undef miter4
+
+
+# Single-bit $xnor extension
+design -reset
+read_verilog -noopt <<EOT
+module gold(input i, output [1:0] o, p, q);
+assign o = i ~^ i;
+assign p = 1'b0 ~^ i;
+assign q = 1'b1 ~^ i;
+endmodule
+EOT
+select -assert-count 3 t:$xnor
+copy gold coarse
+copy gold fine
+copy gold coarse_keepdc
+copy gold fine_keepdc
+
+cd coarse
+opt_expr -fine
+select -assert-none t:$xnor
+
+cd fine
+simplemap
+opt_expr
+select -assert-none t:$_XNOR_
+
+cd
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
+sat -verify -prove-asserts -show-ports -enable_undef miter
+miter -equiv -flatten -make_assert -make_outputs coarse fine miter2
+sat -verify -prove-asserts -show-ports -enable_undef miter2
+
+cd coarse_keepdc
+opt_expr -keepdc -fine
+select -assert-count 1 t:$xnor
+
+cd fine_keepdc
+simplemap
+opt_expr -keepdc
+select -assert-count 0 c:$_XNOR_
+
+cd
+miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3
+sat -verify -prove-asserts -show-ports -enable_undef miter3
+miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4
+sat -verify -prove-asserts -show-ports -enable_undef miter4
diff --git a/tests/opt/opt_expr_xor.ys b/tests/opt/opt_expr_xor.ys
index 21439fd53..a879f3ec9 100644
--- a/tests/opt/opt_expr_xor.ys
+++ b/tests/opt/opt_expr_xor.ys
@@ -50,3 +50,91 @@ assign z = a~^1'b1;
endmodule
EOT
equiv_opt opt_expr
+
+
+# Single-bit $xor
+design -reset
+read_verilog -noopt <<EOT
+module gold(input i, output o);
+assign o = 1'bx ^ i;
+endmodule
+EOT
+select -assert-count 1 t:$xor
+copy gold coarse
+copy gold fine
+copy gold coarse_keepdc
+copy gold fine_keepdc
+
+cd coarse
+opt_expr
+select -assert-none c:*
+
+cd fine
+simplemap
+opt_expr
+select -assert-none c:*
+
+cd
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
+sat -verify -prove-asserts -show-ports -enable_undef miter
+miter -equiv -flatten -make_assert -make_outputs coarse fine miter2
+sat -verify -prove-asserts -show-ports -enable_undef miter2
+
+cd coarse_keepdc
+opt_expr -keepdc
+select -assert-count 1 c:*
+
+cd fine_keepdc
+simplemap
+opt_expr -keepdc
+select -assert-count 1 c:*
+
+cd
+miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3
+sat -verify -prove-asserts -show-ports -enable_undef miter3
+miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4
+sat -verify -prove-asserts -show-ports -enable_undef miter4
+
+
+# Multi-bit $xor
+design -reset
+read_verilog -noopt <<EOT
+module gold(input i, output [6:0] o);
+assign o = {1'bx, 1'b0, 1'b0, 1'b1, 1'bx, 1'b1, i} ^ {7{i}};
+endmodule
+EOT
+select -assert-count 1 t:$xor
+copy gold coarse
+copy gold fine
+copy gold coarse_keepdc
+copy gold fine_keepdc
+
+cd coarse
+opt_expr -fine
+select -assert-count 0 t:$xor
+
+cd fine
+simplemap
+opt_expr
+select -assert-none t:$_XOR_
+
+cd
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
+sat -verify -prove-asserts -show-ports -enable_undef miter
+miter -equiv -flatten -make_assert -make_outputs coarse fine miter2
+sat -verify -prove-asserts -show-ports -enable_undef miter2
+
+cd coarse_keepdc
+opt_expr -keepdc -fine
+select -assert-count 1 t:$xor
+
+cd fine_keepdc
+simplemap
+opt_expr -keepdc
+select -assert-count 3 t:$_XOR_
+
+cd
+miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3
+sat -verify -prove-asserts -show-ports -enable_undef miter3
+miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4
+sat -verify -prove-asserts -show-ports -enable_undef miter4
diff --git a/tests/simple/constmuldivmod.v b/tests/simple/constmuldivmod.v
index d1d8be862..5dd8f9295 100644
--- a/tests/simple/constmuldivmod.v
+++ b/tests/simple/constmuldivmod.v
@@ -1,4 +1,4 @@
-module constmuldivmod(input [7:0] A, input [2:0] mode, output reg [7:0] Y);
+module constmuldivmod(input [7:0] A, input [5:0] mode, output reg [7:0] Y);
always @* begin
case (mode)
0: Y = A / 8'd0;
@@ -21,6 +21,46 @@ module constmuldivmod(input [7:0] A, input [2:0] mode, output reg [7:0] Y);
13: Y = A % 8'd8;
14: Y = A * 8'd8;
+ 15: Y = $signed(A) / $signed(8'd0);
+ 16: Y = $signed(A) % $signed(8'd0);
+ 17: Y = $signed(A) * $signed(8'd0);
+
+ 18: Y = $signed(A) / $signed(8'd1);
+ 19: Y = $signed(A) % $signed(8'd1);
+ 20: Y = $signed(A) * $signed(8'd1);
+
+ 21: Y = $signed(A) / $signed(8'd2);
+ 22: Y = $signed(A) % $signed(8'd2);
+ 23: Y = $signed(A) * $signed(8'd2);
+
+ 24: Y = $signed(A) / $signed(8'd4);
+ 25: Y = $signed(A) % $signed(8'd4);
+ 26: Y = $signed(A) * $signed(8'd4);
+
+ 27: Y = $signed(A) / $signed(8'd8);
+ 28: Y = $signed(A) % $signed(8'd8);
+ 29: Y = $signed(A) * $signed(8'd8);
+
+ 30: Y = $signed(A) / $signed(-8'd0);
+ 31: Y = $signed(A) % $signed(-8'd0);
+ 32: Y = $signed(A) * $signed(-8'd0);
+
+ 33: Y = $signed(A) / $signed(-8'd1);
+ 34: Y = $signed(A) % $signed(-8'd1);
+ 35: Y = $signed(A) * $signed(-8'd1);
+
+ 36: Y = $signed(A) / $signed(-8'd2);
+ 37: Y = $signed(A) % $signed(-8'd2);
+ 38: Y = $signed(A) * $signed(-8'd2);
+
+ 39: Y = $signed(A) / $signed(-8'd4);
+ 40: Y = $signed(A) % $signed(-8'd4);
+ 41: Y = $signed(A) * $signed(-8'd4);
+
+ 42: Y = $signed(A) / $signed(-8'd8);
+ 43: Y = $signed(A) % $signed(-8'd8);
+ 44: Y = $signed(A) * $signed(-8'd8);
+
default: Y = 8'd16 * A;
endcase
end
diff --git a/tests/simple_abc9/abc9.box b/tests/simple_abc9/abc9.box
new file mode 100644
index 000000000..b3c88437c
--- /dev/null
+++ b/tests/simple_abc9/abc9.box
@@ -0,0 +1,3 @@
+MUXF8 1 0 3 1
+#I0 I1 S
+0 0 0 # O
diff --git a/tests/simple_abc9/abc9.v b/tests/simple_abc9/abc9.v
index 688b47586..5e969c614 100644
--- a/tests/simple_abc9/abc9.v
+++ b/tests/simple_abc9/abc9.v
@@ -213,7 +213,7 @@ module arbiter (clk, rst, request, acknowledge, grant, grant_valid, grant_encode
input rst;
endmodule
-(* abc9_box, blackbox *)
+(* abc9_box_id=1, blackbox *)
module MUXF8(input I0, I1, S, output O);
specify
(I0 => O) = 0;
diff --git a/tests/simple_abc9/run-test.sh b/tests/simple_abc9/run-test.sh
index 424d8f417..650e42fca 100755
--- a/tests/simple_abc9/run-test.sh
+++ b/tests/simple_abc9/run-test.sh
@@ -25,7 +25,7 @@ exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v *.sv EXTRA_FLAGS="-n 300 -p
synth -run coarse; \
opt -full; \
techmap; \
- abc9 -lut 4; \
+ abc9 -lut 4 -box ../abc9.box; \
clean; \
check -assert; \
select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%; \
diff --git a/tests/svtypes/logic_rom.sv b/tests/svtypes/logic_rom.sv
new file mode 100644
index 000000000..45fe0a4ca
--- /dev/null
+++ b/tests/svtypes/logic_rom.sv
@@ -0,0 +1,6 @@
+module top(input [3:0] addr, output [7:0] data);
+ logic [7:0] mem[0:15];
+ assign data = mem[addr];
+ integer i;
+ initial for(i = 0; i < 16; i = i + 1) mem[i] = i;
+endmodule
diff --git a/tests/svtypes/logic_rom.ys b/tests/svtypes/logic_rom.ys
new file mode 100644
index 000000000..7b079c136
--- /dev/null
+++ b/tests/svtypes/logic_rom.ys
@@ -0,0 +1,3 @@
+read_verilog -sv logic_rom.sv
+prep -top top
+select -assert-count 1 t:$mem r:SIZE=16 %i r:WIDTH=8 %i
diff --git a/tests/various/abc9.ys b/tests/various/abc9.ys
index 6e2415ad7..ac714665f 100644
--- a/tests/various/abc9.ys
+++ b/tests/various/abc9.ys
@@ -45,14 +45,16 @@ sat -seq 10 -verify -prove-asserts -show-ports miter
design -reset
read_verilog -icells <<EOT
module abc9_test036(input clk, d, output q);
-(* keep *) reg w;
-$__ABC9_FF_ ff(.D(d), .Q(w));
-wire \ff.clock = clk;
-wire \ff.init = 1'b0;
+(* keep, init=1'b0 *) wire w;
+$_DFF_P_ ff(.C(clk), .D(d), .Q(w));
assign q = w;
endmodule
EOT
-abc9 -lut 4 -dff
+equiv_opt -assert abc9 -lut 4 -dff
+design -load postopt
+cd abc9_test036
+select -assert-count 1 t:$_DFF_P_
+select -assert-none t:* t:$_DFF_P_ %d
design -reset
@@ -67,8 +69,32 @@ specify
endspecify
endmodule
-module top(input [1:0] i, output o);
+module abc9_test037(input [1:0] i, output o);
LUT2 #(.mask(4'b0)) lut (.i(i), .o(o));
endmodule
EOT
abc9
+
+
+design -reset
+read_verilog -icells <<EOT
+module abc9_test038(input clk, output w, x, y, z);
+(* init=1'b1 *) wire w;
+$_DFF_N_ ff1(.C(clk), .D(1'b1), .Q(w));
+(* init=1'bx *) wire x;
+$_DFF_N_ ff2(.C(clk), .D(1'b0), .Q(x));
+(* init=1'b0 *) wire y;
+$_DFF_N_ ff3(.C(clk), .D(1'b0), .Q(y));
+(* init=1'b0 *) wire z;
+$_DFF_N_ ff4(.C(clk), .D(1'b1), .Q(z));
+endmodule
+EOT
+simplemap
+equiv_opt abc9 -lut 4 -dff
+design -load postopt
+cd abc9_test038
+select -assert-count 3 t:$_DFF_N_
+select -assert-none c:ff1 c:ff2 c:ff4 %% c:* %D
+clean
+select -assert-count 2 a:init
+select -assert-none w:w w:z %% a:init %D
diff --git a/tests/various/attrib07_func_call.v b/tests/various/attrib07_func_call.v
index f55ef2316..8c9fb2926 100644
--- a/tests/various/attrib07_func_call.v
+++ b/tests/various/attrib07_func_call.v
@@ -11,7 +11,7 @@ module foo(clk, rst, inp_a, inp_b, out);
input wire rst;
input wire [7:0] inp_a;
input wire [7:0] inp_b;
- output wire [7:0] out;
+ output reg [7:0] out;
always @(posedge clk)
if (rst) out <= 0;
diff --git a/tests/various/constmsk_testmap.v b/tests/various/constmsk_testmap.v
index fab1b1bbc..b6809c7c0 100644
--- a/tests/various/constmsk_testmap.v
+++ b/tests/various/constmsk_testmap.v
@@ -1,7 +1,7 @@
(* techmap_celltype = "$reduce_or" *)
module my_opt_reduce_or(...);
parameter A_SIGNED = 0;
- parameter A_WIDTH = 1;
+ parameter A_WIDTH = 2;
parameter Y_WIDTH = 1;
input [A_WIDTH-1:0] A;
diff --git a/tests/various/printattr.ys b/tests/various/printattr.ys
new file mode 100644
index 000000000..afc6d8eb6
--- /dev/null
+++ b/tests/various/printattr.ys
@@ -0,0 +1,14 @@
+logger -expect log ".*cells_not_processed=[01]* .*" 1
+logger -expect log ".*src=.<<EOT:1\.1-9\.10. .*" 1
+read_verilog <<EOT
+module mux2(a, b, s, y);
+ input a, b, s;
+ output y;
+
+ wire s_n = ~s;
+ wire t0 = s & a;
+ wire t1 = s_n & b;
+ assign y = t0 | t1;
+endmodule
+EOT
+printattrs
diff --git a/tests/various/shregmap.v b/tests/various/shregmap.v
index 604c2c976..dc828eda7 100644
--- a/tests/various/shregmap.v
+++ b/tests/various/shregmap.v
@@ -13,7 +13,7 @@ assign q = {shift2[3], shift1[3]};
endmodule
module $__SHREG_DFF_P_(input C, D, output Q);
-parameter DEPTH = 1;
+parameter DEPTH = 2;
parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}};
reg [DEPTH-1:0] r = INIT;
always @(posedge C)
@@ -38,7 +38,7 @@ endmodule
module $__XILINX_SHREG_(input C, D, input [1:0] L, output Q);
parameter CLKPOL = 1;
parameter ENPOL = 1;
-parameter DEPTH = 1;
+parameter DEPTH = 2;
parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}};
reg [DEPTH-1:0] r = INIT;
wire clk = C ^ CLKPOL;
diff --git a/tests/various/xaiger.ys b/tests/various/xaiger.ys
new file mode 100644
index 000000000..f612d2e18
--- /dev/null
+++ b/tests/various/xaiger.ys
@@ -0,0 +1,13 @@
+read_verilog <<EOT
+module top(input a, b, output c);
+bb #(1) bb();
+endmodule
+
+module bb(input a, b, output c);
+parameter p = 0;
+assign c = a ^ b;
+endmodule
+EOT
+blackbox bb
+hierarchy
+write_xaiger /dev/null
diff --git a/tests/verilog/.gitignore b/tests/verilog/.gitignore
new file mode 100644
index 000000000..b48f808a1
--- /dev/null
+++ b/tests/verilog/.gitignore
@@ -0,0 +1,3 @@
+/*.log
+/*.out
+/run-test.mk
diff --git a/tests/verilog/bug2037.ys b/tests/verilog/bug2037.ys
new file mode 100644
index 000000000..4b629ba92
--- /dev/null
+++ b/tests/verilog/bug2037.ys
@@ -0,0 +1,58 @@
+logger -expect-no-warnings
+read_verilog <<EOT
+module test ();
+ localparam y = 1;
+ always @(*)
+ if (y) (* foo *) ;
+endmodule
+EOT
+select -assert-none a:* a:src %d
+
+
+design -reset
+logger -expect-no-warnings
+read_verilog <<EOT
+module test ();
+ localparam y = 1;
+ always @(*)
+ if (y) (* foo *) ; else (* bar *) ;
+endmodule
+EOT
+select -assert-none a:* a:src %d
+
+
+design -reset
+logger -expect-no-warnings
+read_verilog <<EOT
+module test ();
+ localparam y = 1;
+ generate if (y) (* foo *) ; endgenerate
+endmodule
+EOT
+select -assert-none a:*
+
+
+design -reset
+logger -expect-no-warnings
+read_verilog <<EOT
+module test ();
+ localparam y = 1;
+ generate if (y) (* foo *) ; else (* bar *); endgenerate
+endmodule
+EOT
+select -assert-none a:*
+
+
+design -reset
+read_verilog <<EOT
+module test ();
+ localparam y = 1;
+ reg x = 1'b0;
+ always @(*) begin
+ if (y)
+ (* foo *) x <= 1'b1;
+ else
+ (* bar *) x = 1'b0;
+ end
+endmodule
+EOT
diff --git a/tests/verilog/bug2042-sv.ys b/tests/verilog/bug2042-sv.ys
new file mode 100644
index 000000000..91989f412
--- /dev/null
+++ b/tests/verilog/bug2042-sv.ys
@@ -0,0 +1,59 @@
+read_verilog -sv <<EOT
+module Task_Test_Top
+(
+input a,
+output reg b
+);
+
+ task SomeTaskName(a);
+ b = ~a;
+ endtask
+
+ always @*
+ SomeTaskName(a);
+
+ assert property (b == ~a);
+
+endmodule
+EOT
+proc
+sat -verify -prove-asserts
+
+
+design -reset
+read_verilog -sv <<EOT
+module Task_Test_Top
+(
+input a,
+output b, c
+);
+
+ task SomeTaskName(x, output y, z);
+ y = ~x;
+ z = x;
+ endtask
+
+ always @*
+ SomeTaskName(a, b, c);
+
+ assert property (b == ~a);
+ assert property (c == a);
+
+endmodule
+EOT
+proc
+sat -verify -prove-asserts
+
+
+design -reset
+logger -expect error "syntax error, unexpected TOK_ENDTASK, expecting ';'" 1
+read_verilog -sv <<EOT
+module Task_Test_Top
+(
+);
+
+ task SomeTaskName(a)
+ endtask
+
+endmodule
+EOT
diff --git a/tests/verilog/bug2042.ys b/tests/verilog/bug2042.ys
new file mode 100644
index 000000000..f9d8e2837
--- /dev/null
+++ b/tests/verilog/bug2042.ys
@@ -0,0 +1,11 @@
+logger -expect error "task/function argument direction missing" 1
+read_verilog <<EOT
+module Task_Test_Top
+(
+);
+
+ task SomeTaskName(a)
+ endtask
+
+endmodule
+EOT
diff --git a/tests/verilog/run-test.sh b/tests/verilog/run-test.sh
new file mode 100755
index 000000000..ea56b70f0
--- /dev/null
+++ b/tests/verilog/run-test.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+set -e
+{
+echo "all::"
+for x in *.ys; do
+ echo "all:: run-$x"
+ echo "run-$x:"
+ echo " @echo 'Running $x..'"
+ echo " @../../yosys -ql ${x%.ys}.log $x"
+done
+for s in *.sh; do
+ if [ "$s" != "run-test.sh" ]; then
+ echo "all:: run-$s"
+ echo "run-$s:"
+ echo " @echo 'Running $s..'"
+ echo " @bash $s"
+ fi
+done
+} > run-test.mk
+exec ${MAKE:-make} -f run-test.mk
diff --git a/tests/verilog/task_attr.ys b/tests/verilog/task_attr.ys
new file mode 100644
index 000000000..d6e75f85f
--- /dev/null
+++ b/tests/verilog/task_attr.ys
@@ -0,0 +1,28 @@
+read_verilog <<EOT
+module top;
+ task foo;
+ endtask
+
+ always @*
+ (* foo *) foo;
+
+ initial
+ if (0) $info("bar");
+endmodule
+EOT
+# Since task enables are not an RTLIL object,
+# any attributes on their AST get dropped
+select -assert-none a:* a:src %d
+
+
+logger -expect error "syntax error, unexpected ATTR_BEGIN" 1
+design -reset
+read_verilog <<EOT
+module top;
+ task foo;
+ endtask
+
+ always @*
+ foo (* foo *);
+endmodule
+EOT
diff --git a/tests/verilog/upto.ys b/tests/verilog/upto.ys
new file mode 100644
index 000000000..2f3394761
--- /dev/null
+++ b/tests/verilog/upto.ys
@@ -0,0 +1,4 @@
+read_verilog <<EOT
+module top(input [-128:-65] a);
+endmodule
+EOT