Merge branch 'master' into struct

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

View File

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

View File

@ -717,7 +717,7 @@ ifneq ($(ABCREV),default)
echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
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 ""

View File

@ -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()) {

View File

@ -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);

View File

@ -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 "

View File

@ -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

View File

@ -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();
}
};

View File

@ -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))) {

View File

@ -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, '%')

View File

@ -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)

View File

@ -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())
{

View File

@ -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

View File

@ -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());

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -1256,7 +1256,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
if (old_range_valid != range_valid)
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))

View File

@ -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)

View File

@ -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)};

View File

@ -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);

View File

@ -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 {

View File

@ -489,6 +489,7 @@ RTLIL::Const RTLIL::const_mul(const RTLIL::Const &arg1, const RTLIL::Const &arg2
return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0));
}
// 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;

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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(); }

View File

@ -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());
}
}

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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())

View File

@ -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)];

View File

@ -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

View File

@ -184,9 +184,12 @@ may hold important information for Yosys developers can be used without
disturbing external tools. For example the Verilog backend assigns names in the form {\tt \_{\it integer}\_}.
\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.

View File

@ -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_

View File

@ -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

View File

@ -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);
}
}

View File

@ -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());

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

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

View File

@ -109,7 +109,7 @@ struct statdata_t
ID($lut), ID($and), ID($or), ID($xor), ID($xnor),
ID($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;

View File

@ -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");

View File

@ -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));

View File

@ -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();

View File

@ -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($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 (cell->type == ID($and) && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0))
bit_a = bit_b = RTLIL::State::S0;
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);

View File

@ -103,7 +103,7 @@ bool cell_supported(RTLIL::Cell *cell)
if (sig_bi.is_fully_const() && sig_ci.is_fully_const() && sig_bi == sig_ci)
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 "";

View File

@ -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));

View File

@ -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);

View File

@ -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,86 +355,147 @@ void assume_miter_outputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
module->addAssume("$assume_qbfsat_miter_outputs", wires_to_assume[0], RTLIL::S1);
}
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());
};
recover_solution(ret);
return ret;
}
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;
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.nobisection || opt.nooptimize) {
if (wire_to_optimize != nullptr && opt.nooptimize) {
wire_to_optimize->set_bool_attribute("\\maximize", false);
wire_to_optimize->set_bool_attribute("\\minimize", false);
}
ret = call_qbf_solver(module, opt, tempdir_name, false, 0);
} else {
//Do the iterated bisection method:
unsigned int iter_num = 1;
unsigned int success = 0;
unsigned int failure = 0;
unsigned int cur_thresh = 0;
log_assert(wire_to_optimize != nullptr);
log("%s wire \"%s\".\n", (maximize? "Maximizing" : "Minimizing"), log_signal(wire_to_optimize));
//If maximizing, grow until we get a failure. Then bisect success and failure.
while (failure == 0 || success - failure > 1) {
Pass::call(design, "design -push-copy");
log_header(design, "Preparing QBF-SAT problem.\n");
if (cur_thresh != 0) {
//Add thresholding logic (but not on the initial run when we don't have a sense of where to start):
RTLIL::SigSpec comparator = maximize? module->Ge(NEW_ID, module->wire(wire_to_optimize_name), RTLIL::Const(cur_thresh), false)
: module->Le(NEW_ID, module->wire(wire_to_optimize_name), RTLIL::Const(cur_thresh), false);
module->addAssume(wire_to_optimize_name.str() + "__threshold", comparator, RTLIL::Const(1, 1));
log("Trying to solve with %s %s %d.\n", wire_to_optimize_name.c_str(), (maximize? ">=" : "<="), cur_thresh);
}
ret = call_qbf_solver(module, opt, tempdir_name, false, iter_num);
Pass::call(design, "design -pop");
module = design->module(module_name);
if (!ret.unknown && ret.sat) {
Pass::call(design, "design -push-copy");
specialize(module, ret, true);
RTLIL::SigSpec wire, value, undef;
RTLIL::SigSpec::parse_sel(wire, design, module, wire_to_optimize_name.str());
ConstEval ce(module);
value = wire;
if (!ce.eval(value, undef))
log_cmd_error("Failed to evaluate signal %s: Missing value for %s.\n", log_signal(wire), log_signal(undef));
log_assert(value.is_fully_const());
success = value.as_const().as_int();
best_soln = ret;
log("Problem is satisfiable with %s = %d.\n", wire_to_optimize_name.c_str(), success);
Pass::call(design, "design -pop");
module = design->module(module_name);
//sometimes this happens if we get an 'unknown' or timeout
if (!maximize && success < failure)
break;
else if (maximize && success > failure)
break;
} else {
//Treat 'unknown' as UNSAT
failure = cur_thresh;
if (failure == 0) {
log("Problem is NOT satisfiable.\n");
break;
}
else
log("Problem is NOT satisfiable with %s %s %d.\n", wire_to_optimize_name.c_str(), (maximize? ">=" : "<="), failure);
}
iter_num++;
cur_thresh = (maximize && failure == 0)? 2 * success //growth
: (success + failure) / 2; //bisection
}
if (success != 0 || failure != 0) {
log("Wire %s is %s at %d.\n", wire_to_optimize_name.c_str(), (maximize? "maximized" : "minimized"), success);
ret = best_soln;
}
}
if(!opt.nocleanup)
remove_directory(tempdir_name);
recover_solution(ret);
Pass::call(design, "design -pop");
return ret;
}
pool<std::string> validate_design_and_get_inputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
bool found_input = false;
bool found_hole = false;
bool found_1bit_output = false;
bool found_assert_assume = false;
pool<std::string> input_wires;
for (auto wire : module->wires()) {
if (wire->port_input) {
found_input = true;
input_wires.insert(wire->name.str());
}
if (wire->port_output && wire->width == 1)
found_1bit_output = true;
}
for (auto cell : module->cells()) {
if (cell->type == "$allconst")
found_input = true;
if (cell->type == "$anyconst")
found_hole = true;
if (cell->type.in("$assert", "$assume"))
found_assert_assume = true;
}
if (!found_input)
log_cmd_error("Can't perform QBF-SAT on a miter with no inputs!\n");
if (!found_hole)
log_cmd_error("Did not find any existentially-quantified variables. Use 'sat' instead.\n");
if (!found_1bit_output && !found_assert_assume)
log_cmd_error("Did not find any single-bit outputs or $assert/$assume cells. Is this a miter circuit?\n");
if (!found_assert_assume && !opt.assume_outputs)
log_cmd_error("Did not find any $assert/$assume cells. Single-bit outputs were found, but `-assume-outputs` was not specified.\n");
return input_wires;
}
QbfSolveOptions parse_args(const std::vector<std::string> &args) {
QbfSolveOptions opt;
for (opt.argidx = 1; opt.argidx < args.size(); opt.argidx++) {
@ -379,6 +515,43 @@ QbfSolveOptions parse_args(const std::vector<std::string> &args) {
opt.assume_neg = true;
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();

View File

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

View File

@ -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

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -522,7 +522,7 @@ void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
{
mappers[ID($not)] = simplemap_not;
mappers[ID($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()) {

View File

@ -42,7 +42,7 @@ extern void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap(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

View File

@ -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();

View File

@ -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";

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

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

View File

@ -30,4 +30,6 @@ $(eval $(call add_share_file,share,techlibs/common/cmp2lut.v))
$(eval $(call add_share_file,share,techlibs/common/cells.lib))
$(eval $(call add_share_file,share,techlibs/common/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))

View File

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

View File

@ -1,10 +1,25 @@
module \$__ABC9_FF_ (input D, output Q);
endmodule
(* abc9_box *)
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

View File

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

View File

@ -6,8 +6,11 @@ module adff2dff (CLK, ARST, D, Q);
parameter ARST_VALUE = 0;
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;;";

View File

@ -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

View File

@ -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_ = "";

View File

@ -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;;";

View File

@ -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

View File

@ -997,6 +997,12 @@ endmodule
// --------------------------------------------------------
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
//-
//- $div (A, B, Y)
//-
//- Division with truncated result (rounded towards 0).
//-
module \$div (A, B, Y);
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;
@ -1043,6 +1057,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

View File

@ -85,8 +85,11 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y);
localparam shift_left = _TECHMAP_CELLTYPE_ == "$shl" || _TECHMAP_CELLTYPE_ == "$sshl";
localparam 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 #(
\$__div_mod_trunc #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH),
.B_WIDTH(B_WIDTH),
.Y_WIDTH(Y_WIDTH)
) div_mod (
.A(A),
.B(B),
.R(Y)
);
endmodule
// flooring signed division/modulo
module \$__div_mod_floor (A, B, Y, R);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
localparam WIDTH =
A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH :
B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B;
output [Y_WIDTH-1:0] Y, R;
wire [WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u, R_s;
assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf;
assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf;
\$__div_mod_u #(
.WIDTH(WIDTH)
) div_mod_u (
.A(A_buf_u),
.B(B_buf_u),
.Y(Y_u),
.R(R_u)
);
// For negative results, if there was a remainder, subtract one to turn
// the round towards 0 into a round towards -inf
assign Y = A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? (R_u == 0 ? -Y_u : -Y_u-1) : Y_u;
// truncating modulo
assign R_s = A_SIGNED && B_SIGNED && A_buf[WIDTH-1] ? -R_u : R_u;
// Flooring modulo differs from truncating modulo only if it is nonzero and
// A and B have different signs - then `floor - trunc = B`
assign R = (R_s != 0) && A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? $signed(B_buf) + $signed(R_s) : R_s;
endmodule
(* techmap_celltype = "$divfloor" *)
module _90_divfloor (A, B, Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y;
\$__div_mod_floor #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH),
.B_WIDTH(B_WIDTH),
.Y_WIDTH(Y_WIDTH)
) div_mod (
.A(A),
.B(B),
.Y(Y)
);
endmodule
(* techmap_celltype = "$modfloor" *)
module _90_modfloor (A, B, Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
(* force_downto *)
input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y;
\$__div_mod_floor #(
.A_SIGNED(A_SIGNED),
.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];

View File

@ -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;

View File

@ -24,10 +24,6 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/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

View File

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

View File

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

View File

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

View File

@ -26,15 +26,20 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO);
parameter B_WIDTH = 1;
parameter 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;

View File

@ -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 *)

View File

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

View File

@ -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
// ---------------------------------------

View File

@ -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");
}

View File

@ -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
endmodule

View File

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

View File

@ -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;

View File

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

View File

@ -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;

View File

@ -23,6 +23,7 @@ techlibs/ice40/brams_init3.vh: techlibs/ice40/brams_init.mk
$(eval $(call add_share_file,share/ice40,techlibs/ice40/arith_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/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))

View File

@ -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;

View File

@ -1,37 +1,8 @@
module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule
module \$_DFF_P_ (input D, C, output Q); SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule
module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
`ifndef NO_LUT
module \$lut (A, Y);
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

View File

@ -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,

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

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

View File

@ -71,6 +71,9 @@ struct SynthIce40Pass : public ScriptPass
log(" -noflatten\n");
log(" 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");
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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};

View File

@ -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

View File

@ -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};

View File

@ -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

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