mirror of https://github.com/YosysHQ/yosys.git
Merge branch 'master' into struct
This commit is contained in:
commit
0d3f7ea011
|
@ -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
|
||||
----------------------
|
||||
|
|
3
Makefile
3
Makefile
|
@ -717,7 +717,7 @@ ifneq ($(ABCREV),default)
|
|||
echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
|
||||
fi
|
||||
# set a variable so the test fails if git fails to run - when comparing outputs directly, empty string would match empty string
|
||||
$(Q) if ! (cd abc && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \
|
||||
$(Q) if ! (cd abc 2> /dev/null && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \
|
||||
test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \
|
||||
echo "Pulling ABC from $(ABCURL):"; set -x; \
|
||||
test -d abc || git clone $(ABCURL) abc; \
|
||||
|
@ -780,6 +780,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
|
|||
+cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/rpc && bash run-test.sh
|
||||
+cd tests/memfile && bash run-test.sh
|
||||
+cd tests/verilog && bash run-test.sh
|
||||
@echo ""
|
||||
@echo " Passed \"make test\"."
|
||||
@echo ""
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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))) {
|
||||
|
|
|
@ -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, '%')
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
19
kernel/log.h
19
kernel/log.h
|
@ -86,7 +86,7 @@ YOSYS_NAMESPACE_BEGIN
|
|||
# endif
|
||||
# if __has_builtin(__builtin_debugtrap)
|
||||
# define YS_DEBUGTRAP __builtin_debugtrap()
|
||||
# elif defined(__unix__)
|
||||
# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
# define YS_DEBUGTRAP raise(SIGTRAP)
|
||||
# else
|
||||
# define YS_DEBUGTRAP do {} while(0)
|
||||
|
@ -97,11 +97,11 @@ YOSYS_NAMESPACE_BEGIN
|
|||
// if a debugger is attached, and does nothing otherwise.
|
||||
#if defined(_WIN32)
|
||||
# define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0)
|
||||
#elif defined(__unix__)
|
||||
# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
// There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However,
|
||||
// debuggers will stop when SIGTRAP is raised, even if the action is set to ignore.
|
||||
# define YS_DEBUGTRAP_IF_DEBUGGING do { \
|
||||
sighandler_t old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \
|
||||
auto old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \
|
||||
} while(0)
|
||||
#else
|
||||
# define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0)
|
||||
|
@ -202,19 +202,16 @@ void log_flush();
|
|||
|
||||
struct LogExpectedItem
|
||||
{
|
||||
LogExpectedItem(std::string pattern, int expected) :
|
||||
expected_count(expected),
|
||||
current_count(0),
|
||||
pattern(pattern)
|
||||
{
|
||||
}
|
||||
LogExpectedItem(const YS_REGEX_TYPE &pat, int expected) :
|
||||
pattern(pat), expected_count(expected), current_count(0) {}
|
||||
LogExpectedItem() : expected_count(0), current_count(0) {}
|
||||
|
||||
YS_REGEX_TYPE pattern;
|
||||
int expected_count;
|
||||
int current_count;
|
||||
std::string pattern;
|
||||
};
|
||||
|
||||
extern std::vector<std::pair<YS_REGEX_TYPE,LogExpectedItem>> log_expect_log, log_expect_warning, log_expect_error;
|
||||
extern dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error;
|
||||
void log_check_expected();
|
||||
|
||||
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 "";
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
techmap.inc
|
|
@ -45,18 +45,6 @@ OBJS += passes/techmap/flowmap.o
|
|||
OBJS += passes/techmap/extractinv.o
|
||||
endif
|
||||
|
||||
GENFILES += passes/techmap/techmap.inc
|
||||
|
||||
passes/techmap/techmap.inc: techlibs/common/techmap.v
|
||||
$(Q) mkdir -p $(dir $@)
|
||||
$(P) echo "// autogenerated from $<" > $@.new
|
||||
$(Q) echo "static char stdcells_code[] = {" >> $@.new
|
||||
$(Q) od -v -td1 -An $< | $(SED) -e 's/[0-9][0-9]*/&,/g' >> $@.new
|
||||
$(Q) echo "0};" >> $@.new
|
||||
$(Q) mv $@.new $@
|
||||
|
||||
passes/techmap/techmap.o: passes/techmap/techmap.inc
|
||||
|
||||
ifeq ($(DISABLE_SPAWN),0)
|
||||
TARGETS += $(PROGRAM_PREFIX)yosys-filterlib$(EXE)
|
||||
EXTRA_OBJS += passes/techmap/filterlib.o
|
||||
|
|
|
@ -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
|
@ -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()) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -32,6 +32,7 @@ module \$lut (A, Y);
|
|||
parameter WIDTH = 0;
|
||||
parameter LUT = 0;
|
||||
|
||||
(* force_downto *)
|
||||
input [WIDTH-1:0] A;
|
||||
output Y;
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;;";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ = "";
|
||||
|
|
|
@ -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;;";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -1,5 +0,0 @@
|
|||
// ---------------------------------------
|
||||
|
||||
module \$__ABC9_DPR16X4_COMB (input [3:0] $DO, RAD, output [3:0] DO);
|
||||
assign DO = $DO;
|
||||
endmodule
|
|
@ -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;
|
||||
|
|
|
@ -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 *)
|
||||
|
|
|
@ -70,6 +70,7 @@ module \$lut (A, Y);
|
|||
parameter WIDTH = 0;
|
||||
parameter LUT = 0;
|
||||
|
||||
(* force_downto *)
|
||||
input [WIDTH-1:0] A;
|
||||
output Y;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
// ---------------------------------------
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -34,6 +34,7 @@ module \$lut (A, Y);
|
|||
parameter WIDTH = 0;
|
||||
parameter LUT = 0;
|
||||
|
||||
(* force_downto *)
|
||||
input [WIDTH-1:0] A;
|
||||
output Y;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -232,6 +232,7 @@ module \$lut (A, Y);
|
|||
parameter WIDTH = 0;
|
||||
parameter LUT = 0;
|
||||
|
||||
(* force_downto *)
|
||||
input [WIDTH-1:0] A;
|
||||
output Y;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue