mirror of https://github.com/YosysHQ/yosys.git
Merge remote-tracking branch 'origin/master' into eddie/shiftx2mux
This commit is contained in:
commit
b6a1f627b5
|
@ -55,10 +55,12 @@ Yosys 0.9 .. Yosys 0.9-dev
|
|||
- Added "check -mapped"
|
||||
- Added checking of SystemVerilog always block types (always_comb,
|
||||
always_latch and always_ff)
|
||||
- Added support for SystemVerilog wildcard port connections (.*)
|
||||
- Added "xilinx_dffopt" pass
|
||||
- Added "scratchpad" pass
|
||||
- Added "abc9 -dff"
|
||||
- Added "synth_xilinx -dff"
|
||||
- Added "opt_lut_ins" pass
|
||||
|
||||
Yosys 0.8 .. Yosys 0.9
|
||||
----------------------
|
||||
|
|
17
README.md
17
README.md
|
@ -373,10 +373,15 @@ Verilog Attributes and non-standard features
|
|||
`abc9` to preserve the integrity of carry-chains. Specifying this attribute
|
||||
onto a bus port will affect only its most significant bit.
|
||||
|
||||
- The port attribute ``abc9_arrival`` specifies an integer (for output ports
|
||||
only) to be used as the arrival time of this sequential port. It can be used,
|
||||
for example, to specify the clk-to-Q delay of a flip-flop for consideration
|
||||
during `abc9` techmapping.
|
||||
- The output port attribute ``abc9_arrival`` specifies an integer, or a string
|
||||
of space-separated integers to be used as the arrival time of this blackbox
|
||||
port. It can be used, for example, to specify the clk-to-Q delay of a flip-
|
||||
flop output for consideration during `abc9` techmapping.
|
||||
|
||||
- The input port attribute ``abc9_required`` specifies an integer, or a string
|
||||
of space-separated integers to be used as the required time of this blackbox
|
||||
port. It can be used, for example, to specify the setup-time of a flip-flop
|
||||
input for consideration during `abc9` techmapping.
|
||||
|
||||
- The module attribute ``abc9_flop`` is a boolean marking the module as a
|
||||
flip-flop. This allows `abc9` to analyse its contents in order to perform
|
||||
|
@ -387,6 +392,10 @@ Verilog Attributes and non-standard features
|
|||
according to the type of the always. These are checked for correctness in
|
||||
``proc_dlatch``.
|
||||
|
||||
- The cell attribute ``wildcard_port_conns`` represents wildcard port
|
||||
connections (SystemVerilog ``.*``). These are resolved to concrete
|
||||
connections to matching wires in ``hierarchy``.
|
||||
|
||||
- In addition to the ``(* ... *)`` attribute syntax, Yosys supports
|
||||
the non-standard ``{* ... *}`` attribute syntax to set default attributes
|
||||
for everything that comes after the ``{* ... *}`` statement. (Reset
|
||||
|
|
|
@ -93,7 +93,6 @@ struct XAigerWriter
|
|||
dict<SigBit, int> ordered_outputs;
|
||||
|
||||
vector<Cell*> box_list;
|
||||
dict<IdString, std::vector<IdString>> box_ports;
|
||||
|
||||
int mkgate(int a0, int a1)
|
||||
{
|
||||
|
@ -157,7 +156,6 @@ struct XAigerWriter
|
|||
if (wire->get_bool_attribute(ID::keep))
|
||||
sigmap.add(wire);
|
||||
|
||||
|
||||
for (auto wire : module->wires())
|
||||
for (int i = 0; i < GetSize(wire); i++)
|
||||
{
|
||||
|
@ -175,108 +173,117 @@ struct XAigerWriter
|
|||
undriven_bits.insert(bit);
|
||||
unused_bits.insert(bit);
|
||||
|
||||
if (wire->port_input)
|
||||
bool keep = wire->get_bool_attribute(ID::keep);
|
||||
if (wire->port_input || keep)
|
||||
input_bits.insert(bit);
|
||||
|
||||
if (wire->port_output) {
|
||||
if (wire->port_output || keep) {
|
||||
if (bit != wirebit)
|
||||
alias_map[wirebit] = bit;
|
||||
output_bits.insert(wirebit);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Speed up toposort -- ultimately we care about
|
||||
// box ordering, but not individual AIG cells
|
||||
dict<SigBit, pool<IdString>> bit_drivers, bit_users;
|
||||
TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
|
||||
bool abc9_box_seen = false;
|
||||
|
||||
for (auto cell : module->selected_cells()) {
|
||||
if (cell->type == "$_NOT_")
|
||||
{
|
||||
SigBit A = sigmap(cell->getPort("\\A").as_bit());
|
||||
SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
|
||||
unused_bits.erase(A);
|
||||
undriven_bits.erase(Y);
|
||||
not_map[Y] = A;
|
||||
toposort.node(cell->name);
|
||||
bit_users[A].insert(cell->name);
|
||||
bit_drivers[Y].insert(cell->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cell->type == "$_AND_")
|
||||
{
|
||||
SigBit A = sigmap(cell->getPort("\\A").as_bit());
|
||||
SigBit B = sigmap(cell->getPort("\\B").as_bit());
|
||||
SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
|
||||
unused_bits.erase(A);
|
||||
unused_bits.erase(B);
|
||||
undriven_bits.erase(Y);
|
||||
and_map[Y] = make_pair(A, B);
|
||||
toposort.node(cell->name);
|
||||
bit_users[A].insert(cell->name);
|
||||
bit_users[B].insert(cell->name);
|
||||
bit_drivers[Y].insert(cell->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cell->type == "$__ABC9_FF_" &&
|
||||
// The presence of an abc9_mergeability attribute indicates
|
||||
// that we do want to pass this flop to ABC
|
||||
cell->attributes.count("\\abc9_mergeability"))
|
||||
{
|
||||
SigBit D = sigmap(cell->getPort("\\D").as_bit());
|
||||
SigBit Q = sigmap(cell->getPort("\\Q").as_bit());
|
||||
unused_bits.erase(D);
|
||||
undriven_bits.erase(Q);
|
||||
alias_map[Q] = D;
|
||||
auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell));
|
||||
log_assert(r.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
dict<IdString,dict<IdString,std::vector<int>>> arrivals_cache;
|
||||
for (auto cell : module->cells()) {
|
||||
RTLIL::Module* inst_module = module->design->module(cell->type);
|
||||
if (inst_module) {
|
||||
bool abc9_box = inst_module->attributes.count("\\abc9_box_id");
|
||||
bool abc9_flop = inst_module->get_bool_attribute("\\abc9_flop");
|
||||
if (abc9_box && cell->get_bool_attribute("\\abc9_keep"))
|
||||
abc9_box = false;
|
||||
if (!cell->has_keep_attr()) {
|
||||
if (cell->type == "$_NOT_")
|
||||
{
|
||||
SigBit A = sigmap(cell->getPort("\\A").as_bit());
|
||||
SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
|
||||
unused_bits.erase(A);
|
||||
undriven_bits.erase(Y);
|
||||
not_map[Y] = A;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto &conn : cell->connections()) {
|
||||
auto port_wire = inst_module->wire(conn.first);
|
||||
if (cell->type == "$_AND_")
|
||||
{
|
||||
SigBit A = sigmap(cell->getPort("\\A").as_bit());
|
||||
SigBit B = sigmap(cell->getPort("\\B").as_bit());
|
||||
SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
|
||||
unused_bits.erase(A);
|
||||
unused_bits.erase(B);
|
||||
undriven_bits.erase(Y);
|
||||
and_map[Y] = make_pair(A, B);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (abc9_box) {
|
||||
// Ignore inout for the sake of topographical ordering
|
||||
if (port_wire->port_input && !port_wire->port_output)
|
||||
for (auto bit : sigmap(conn.second))
|
||||
bit_users[bit].insert(cell->name);
|
||||
if (port_wire->port_output)
|
||||
for (auto bit : sigmap(conn.second))
|
||||
bit_drivers[bit].insert(cell->name);
|
||||
if (cell->type == "$__ABC9_FF_" &&
|
||||
// The presence of an abc9_mergeability attribute indicates
|
||||
// that we do want to pass this flop to ABC
|
||||
cell->attributes.count("\\abc9_mergeability"))
|
||||
{
|
||||
SigBit D = sigmap(cell->getPort("\\D").as_bit());
|
||||
SigBit Q = sigmap(cell->getPort("\\Q").as_bit());
|
||||
unused_bits.erase(D);
|
||||
undriven_bits.erase(Q);
|
||||
alias_map[Q] = D;
|
||||
auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell));
|
||||
log_assert(r.second);
|
||||
if (input_bits.erase(Q))
|
||||
log_assert(Q.wire->attributes.count(ID::keep));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst_module) {
|
||||
bool abc9_flop = false;
|
||||
auto it = cell->attributes.find("\\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("\\abc9_flop");
|
||||
if (!abc9_flop)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (port_wire->port_output) {
|
||||
int arrival = 0;
|
||||
auto it = port_wire->attributes.find("\\abc9_arrival");
|
||||
if (it != port_wire->attributes.end()) {
|
||||
if (it->second.flags != 0)
|
||||
log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type));
|
||||
arrival = it->second.as_int();
|
||||
}
|
||||
if (arrival)
|
||||
for (auto bit : sigmap(conn.second))
|
||||
arrival_times[bit] = arrival;
|
||||
}
|
||||
}
|
||||
auto &cell_arrivals = arrivals_cache[cell->type];
|
||||
for (const auto &conn : cell->connections()) {
|
||||
auto port_wire = inst_module->wire(conn.first);
|
||||
if (!port_wire->port_output)
|
||||
continue;
|
||||
|
||||
if (abc9_box) {
|
||||
abc9_box_seen = true;
|
||||
toposort.node(cell->name);
|
||||
continue;
|
||||
auto r = cell_arrivals.insert(conn.first);
|
||||
auto &arrivals = r.first->second;
|
||||
if (r.second) {
|
||||
auto it = port_wire->attributes.find("\\abc9_arrival");
|
||||
if (it == port_wire->attributes.end())
|
||||
continue;
|
||||
if (it->second.flags == 0)
|
||||
arrivals.emplace_back(it->second.as_int());
|
||||
else
|
||||
for (const auto &tok : split_tokens(it->second.decode_string()))
|
||||
arrivals.push_back(atoi(tok.c_str()));
|
||||
}
|
||||
|
||||
if (arrivals.empty())
|
||||
continue;
|
||||
|
||||
if (GetSize(arrivals) > 1 && GetSize(arrivals) != GetSize(port_wire))
|
||||
log_error("%s.%s is %d bits wide but abc9_arrival = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first),
|
||||
GetSize(port_wire), log_signal(it->second), GetSize(arrivals));
|
||||
|
||||
auto jt = arrivals.begin();
|
||||
#ifndef NDEBUG
|
||||
if (ys_debug(1)) {
|
||||
static std::set<std::pair<IdString,IdString>> seen;
|
||||
if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_arrival = %d\n", log_id(cell->type), log_id(conn.first), *jt);
|
||||
}
|
||||
#endif
|
||||
for (auto bit : sigmap(conn.second)) {
|
||||
arrival_times[bit] = *jt;
|
||||
if (arrivals.size() > 1)
|
||||
jt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (abc9_flop)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,6 +300,9 @@ struct XAigerWriter
|
|||
for (auto b : c.second) {
|
||||
Wire *w = b.wire;
|
||||
if (!w) continue;
|
||||
// Do not add as PO if bit is already a PI
|
||||
if (input_bits.count(b))
|
||||
continue;
|
||||
if (!w->port_output || !cell_known) {
|
||||
SigBit I = sigmap(b);
|
||||
if (I != b)
|
||||
|
@ -305,138 +315,54 @@ struct XAigerWriter
|
|||
//log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
|
||||
}
|
||||
|
||||
if (abc9_box_seen) {
|
||||
for (auto &it : bit_users)
|
||||
if (bit_drivers.count(it.first))
|
||||
for (auto driver_cell : bit_drivers.at(it.first))
|
||||
for (auto user_cell : it.second)
|
||||
toposort.edge(driver_cell, user_cell);
|
||||
dict<IdString, std::vector<IdString>> box_ports;
|
||||
for (auto cell : box_list) {
|
||||
log_assert(cell);
|
||||
|
||||
#if 0
|
||||
toposort.analyze_loops = true;
|
||||
#endif
|
||||
bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
|
||||
#if 0
|
||||
unsigned i = 0;
|
||||
for (auto &it : toposort.loops) {
|
||||
log(" loop %d\n", i++);
|
||||
for (auto cell_name : it) {
|
||||
auto cell = module->cell(cell_name);
|
||||
log_assert(cell);
|
||||
log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
log_assert(no_loops);
|
||||
RTLIL::Module* box_module = module->design->module(cell->type);
|
||||
log_assert(box_module);
|
||||
log_assert(box_module->attributes.count("\\abc9_box_id") || box_module->get_bool_attribute("\\abc9_flop"));
|
||||
|
||||
for (auto cell_name : toposort.sorted) {
|
||||
RTLIL::Cell *cell = module->cell(cell_name);
|
||||
log_assert(cell);
|
||||
|
||||
RTLIL::Module* box_module = module->design->module(cell->type);
|
||||
if (!box_module || !box_module->attributes.count("\\abc9_box_id"))
|
||||
continue;
|
||||
|
||||
bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */);
|
||||
|
||||
auto r = box_ports.insert(cell->type);
|
||||
if (r.second) {
|
||||
// Make carry in the last PI, and carry out the last PO
|
||||
// since ABC requires it this way
|
||||
IdString carry_in, carry_out;
|
||||
for (const auto &port_name : box_module->ports) {
|
||||
auto w = box_module->wire(port_name);
|
||||
log_assert(w);
|
||||
if (w->get_bool_attribute("\\abc9_carry")) {
|
||||
if (w->port_input) {
|
||||
if (carry_in != IdString())
|
||||
log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module));
|
||||
carry_in = port_name;
|
||||
}
|
||||
if (w->port_output) {
|
||||
if (carry_out != IdString())
|
||||
log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module));
|
||||
carry_out = port_name;
|
||||
}
|
||||
}
|
||||
else
|
||||
r.first->second.push_back(port_name);
|
||||
}
|
||||
|
||||
if (carry_in != IdString() && carry_out == IdString())
|
||||
log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module));
|
||||
if (carry_in == IdString() && carry_out != IdString())
|
||||
log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module));
|
||||
if (carry_in != IdString()) {
|
||||
r.first->second.push_back(carry_in);
|
||||
r.first->second.push_back(carry_out);
|
||||
}
|
||||
}
|
||||
|
||||
// Fully pad all unused input connections of this box cell with S0
|
||||
// Fully pad all undriven output connections of this box cell with anonymous wires
|
||||
for (auto port_name : r.first->second) {
|
||||
auto r = box_ports.insert(cell->type);
|
||||
if (r.second) {
|
||||
// Make carry in the last PI, and carry out the last PO
|
||||
// since ABC requires it this way
|
||||
IdString carry_in, carry_out;
|
||||
for (const auto &port_name : box_module->ports) {
|
||||
auto w = box_module->wire(port_name);
|
||||
log_assert(w);
|
||||
auto it = cell->connections_.find(port_name);
|
||||
if (w->port_input) {
|
||||
RTLIL::SigSpec rhs;
|
||||
if (it != cell->connections_.end()) {
|
||||
if (GetSize(it->second) < GetSize(w))
|
||||
it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second)));
|
||||
rhs = it->second;
|
||||
if (w->get_bool_attribute("\\abc9_carry")) {
|
||||
if (w->port_input) {
|
||||
if (carry_in != IdString())
|
||||
log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module));
|
||||
carry_in = port_name;
|
||||
}
|
||||
else {
|
||||
rhs = RTLIL::SigSpec(State::S0, GetSize(w));
|
||||
cell->setPort(port_name, rhs);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (w->port_output) {
|
||||
RTLIL::SigSpec rhs;
|
||||
auto it = cell->connections_.find(port_name);
|
||||
if (it != cell->connections_.end()) {
|
||||
if (GetSize(it->second) < GetSize(w))
|
||||
it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second)));
|
||||
rhs = it->second;
|
||||
}
|
||||
else {
|
||||
Wire *wire = module->addWire(NEW_ID, GetSize(w));
|
||||
if (blackbox)
|
||||
wire->set_bool_attribute(ID(abc9_padding));
|
||||
rhs = wire;
|
||||
cell->setPort(port_name, rhs);
|
||||
}
|
||||
|
||||
for (const auto &b : rhs.bits()) {
|
||||
SigBit O = sigmap(b);
|
||||
if (O != b)
|
||||
alias_map[O] = b;
|
||||
ci_bits.emplace_back(b);
|
||||
undriven_bits.erase(O);
|
||||
if (w->port_output) {
|
||||
if (carry_out != IdString())
|
||||
log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module));
|
||||
carry_out = port_name;
|
||||
}
|
||||
}
|
||||
else
|
||||
r.first->second.push_back(port_name);
|
||||
}
|
||||
|
||||
// Connect <cell>.abc9_ff.Q (inserted by abc9_map.v) as the last input to the flop box
|
||||
if (box_module->get_bool_attribute("\\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));
|
||||
if (carry_in != IdString() && carry_out == IdString())
|
||||
log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module));
|
||||
if (carry_in == IdString() && carry_out != IdString())
|
||||
log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module));
|
||||
if (carry_in != IdString()) {
|
||||
r.first->second.push_back(carry_in);
|
||||
r.first->second.push_back(carry_out);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto port_name : r.first->second) {
|
||||
auto w = box_module->wire(port_name);
|
||||
log_assert(w);
|
||||
auto rhs = cell->connections_.at(port_name, SigSpec());
|
||||
rhs.append(Const(State::Sx, GetSize(w)-GetSize(rhs)));
|
||||
if (w->port_input)
|
||||
for (auto b : rhs) {
|
||||
SigBit I = sigmap(b);
|
||||
if (b == RTLIL::Sx)
|
||||
|
@ -450,12 +376,41 @@ struct XAigerWriter
|
|||
co_bits.emplace_back(b);
|
||||
unused_bits.erase(I);
|
||||
}
|
||||
}
|
||||
|
||||
box_list.emplace_back(cell);
|
||||
if (w->port_output)
|
||||
for (const auto &b : rhs) {
|
||||
SigBit O = sigmap(b);
|
||||
if (O != b)
|
||||
alias_map[O] = b;
|
||||
ci_bits.emplace_back(b);
|
||||
undriven_bits.erase(O);
|
||||
// If PI and CI, then must be a (* keep *) wire
|
||||
if (input_bits.erase(O)) {
|
||||
log_assert(output_bits.count(O));
|
||||
log_assert(O.wire->get_bool_attribute(ID::keep));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Free memory from toposort, bit_drivers, bit_users
|
||||
// Connect <cell>.abc9_ff.Q (inserted by abc9_map.v) as the last input to the flop box
|
||||
if (box_module->get_bool_attribute("\\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)
|
||||
|
@ -501,6 +456,10 @@ struct XAigerWriter
|
|||
|
||||
for (auto &bit : ci_bits) {
|
||||
aig_m++, aig_i++;
|
||||
// 1'bx may exist here due to a box output
|
||||
// that has been padded to its full width
|
||||
if (bit == State::Sx)
|
||||
continue;
|
||||
log_assert(!aig_map.count(bit));
|
||||
aig_map[bit] = 2*aig_m;
|
||||
}
|
||||
|
@ -512,7 +471,27 @@ struct XAigerWriter
|
|||
|
||||
for (const auto &bit : output_bits) {
|
||||
ordered_outputs[bit] = aig_o++;
|
||||
aig_outputs.push_back(bit2aig(bit));
|
||||
int aig;
|
||||
// Unlike bit2aig() which checks aig_map first, for
|
||||
// inout/keep bits, since aig_map will point to
|
||||
// the PI, first attempt to find the NOT/AND driver
|
||||
// before resorting to an aig_map lookup (which
|
||||
// could be another PO)
|
||||
if (input_bits.count(bit)) {
|
||||
if (not_map.count(bit)) {
|
||||
aig = bit2aig(not_map.at(bit)) ^ 1;
|
||||
} else if (and_map.count(bit)) {
|
||||
auto args = and_map.at(bit);
|
||||
int a0 = bit2aig(args.first);
|
||||
int a1 = bit2aig(args.second);
|
||||
aig = mkgate(a0, a1);
|
||||
}
|
||||
else
|
||||
aig = aig_map.at(bit);
|
||||
}
|
||||
else
|
||||
aig = bit2aig(bit);
|
||||
aig_outputs.push_back(aig);
|
||||
}
|
||||
|
||||
for (auto &i : ff_bits) {
|
||||
|
@ -612,106 +591,45 @@ struct XAigerWriter
|
|||
// write_o_buffer(0);
|
||||
|
||||
if (!box_list.empty() || !ff_bits.empty()) {
|
||||
RTLIL::Module *holes_module = module->design->addModule("$__holes__");
|
||||
log_assert(holes_module);
|
||||
dict<IdString, std::tuple<int,int,int>> cell_cache;
|
||||
|
||||
dict<IdString, std::tuple<Cell*,int,int,int>> cell_cache;
|
||||
|
||||
int port_id = 1;
|
||||
int box_count = 0;
|
||||
for (auto cell : box_list) {
|
||||
RTLIL::Module* orig_box_module = module->design->module(cell->type);
|
||||
log_assert(orig_box_module);
|
||||
IdString derived_name = orig_box_module->derive(module->design, cell->parameters);
|
||||
RTLIL::Module* box_module = module->design->module(derived_name);
|
||||
log_assert(cell);
|
||||
|
||||
auto r = cell_cache.insert(derived_name);
|
||||
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 &v = r.first->second;
|
||||
if (r.second) {
|
||||
if (box_module->has_processes())
|
||||
Pass::call_on_module(module->design, box_module, "proc");
|
||||
|
||||
int box_inputs = 0, box_outputs = 0;
|
||||
if (box_module->get_bool_attribute("\\whitebox")) {
|
||||
auto holes_cell = holes_module->addCell(cell->name, derived_name);
|
||||
for (auto port_name : box_ports.at(cell->type)) {
|
||||
RTLIL::Wire *w = box_module->wire(port_name);
|
||||
log_assert(w);
|
||||
log_assert(!w->port_input || !w->port_output);
|
||||
auto &conn = holes_cell->connections_[port_name];
|
||||
if (w->port_input) {
|
||||
for (int i = 0; i < GetSize(w); i++) {
|
||||
box_inputs++;
|
||||
RTLIL::Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
|
||||
if (!holes_wire) {
|
||||
holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
|
||||
holes_wire->port_input = true;
|
||||
holes_wire->port_id = port_id++;
|
||||
holes_module->ports.push_back(holes_wire->name);
|
||||
}
|
||||
conn.append(holes_wire);
|
||||
}
|
||||
}
|
||||
else if (w->port_output) {
|
||||
box_outputs += GetSize(w);
|
||||
conn = holes_module->addWire(stringf("%s.%s", derived_name.c_str(), log_id(port_name)), GetSize(w));
|
||||
}
|
||||
}
|
||||
|
||||
// For flops only, create an extra 1-bit input that drives a new wire
|
||||
// called "<cell>.abc9_ff.Q" that is used below
|
||||
if (box_module->get_bool_attribute("\\abc9_flop")) {
|
||||
box_inputs++;
|
||||
Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
|
||||
if (!holes_wire) {
|
||||
holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
|
||||
holes_wire->port_input = true;
|
||||
holes_wire->port_id = port_id++;
|
||||
holes_module->ports.push_back(holes_wire->name);
|
||||
}
|
||||
Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
|
||||
holes_module->connect(Q, holes_wire);
|
||||
}
|
||||
|
||||
std::get<0>(v) = holes_cell;
|
||||
}
|
||||
else {
|
||||
for (auto port_name : box_ports.at(cell->type)) {
|
||||
RTLIL::Wire *w = box_module->wire(port_name);
|
||||
log_assert(w);
|
||||
log_assert(!w->port_input || !w->port_output);
|
||||
if (w->port_input)
|
||||
box_inputs += GetSize(w);
|
||||
else if (w->port_output)
|
||||
box_outputs += GetSize(w);
|
||||
}
|
||||
log_assert(std::get<0>(v) == nullptr);
|
||||
for (auto port_name : box_module->ports) {
|
||||
RTLIL::Wire *w = box_module->wire(port_name);
|
||||
log_assert(w);
|
||||
if (w->port_input)
|
||||
box_inputs += GetSize(w);
|
||||
if (w->port_output)
|
||||
box_outputs += GetSize(w);
|
||||
}
|
||||
|
||||
std::get<1>(v) = box_inputs;
|
||||
std::get<2>(v) = box_outputs;
|
||||
std::get<3>(v) = box_module->attributes.at("\\abc9_box_id").as_int();
|
||||
}
|
||||
|
||||
auto holes_cell = std::get<0>(v);
|
||||
for (auto port_name : box_ports.at(cell->type)) {
|
||||
RTLIL::Wire *w = box_module->wire(port_name);
|
||||
log_assert(w);
|
||||
if (!w->port_output)
|
||||
continue;
|
||||
Wire *holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(port_name)), GetSize(w));
|
||||
holes_wire->port_output = true;
|
||||
holes_wire->port_id = port_id++;
|
||||
holes_module->ports.push_back(holes_wire->name);
|
||||
if (holes_cell) // whitebox
|
||||
holes_module->connect(holes_wire, holes_cell->getPort(port_name));
|
||||
else // blackbox
|
||||
holes_module->connect(holes_wire, Const(State::S0, 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("\\abc9_flop"))
|
||||
box_inputs++;
|
||||
|
||||
std::get<0>(v) = box_inputs;
|
||||
std::get<1>(v) = box_outputs;
|
||||
std::get<2>(v) = box_module->attributes.at("\\abc9_box_id").as_int();
|
||||
}
|
||||
|
||||
write_h_buffer(std::get<0>(v));
|
||||
write_h_buffer(std::get<1>(v));
|
||||
write_h_buffer(std::get<2>(v));
|
||||
write_h_buffer(std::get<3>(v));
|
||||
write_h_buffer(box_count++);
|
||||
}
|
||||
|
||||
|
@ -759,82 +677,17 @@ 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()));
|
||||
if (holes_module) {
|
||||
log_push();
|
||||
|
||||
// NB: fixup_ports() will sort ports by name
|
||||
//holes_module->fixup_ports();
|
||||
holes_module->check();
|
||||
|
||||
// Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger
|
||||
// since boxes may contain parameters in which case `flatten` would have
|
||||
// created a new $paramod ...
|
||||
Pass::call_on_module(holes_module->design, holes_module, "flatten -wb; techmap; aigmap");
|
||||
|
||||
SigMap holes_sigmap(holes_module);
|
||||
|
||||
dict<SigSpec, SigSpec> replace;
|
||||
for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) {
|
||||
auto cell = it->second;
|
||||
if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
|
||||
"$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) {
|
||||
SigBit D = cell->getPort("\\D");
|
||||
SigBit Q = cell->getPort("\\Q");
|
||||
// Remove the $_DFF_* cell from what needs to be a combinatorial box
|
||||
it = holes_module->cells_.erase(it);
|
||||
Wire *port;
|
||||
if (GetSize(Q.wire) == 1)
|
||||
port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str()));
|
||||
else
|
||||
port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset));
|
||||
log_assert(port);
|
||||
// Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
|
||||
// in order to extract just the combinatorial control logic that feeds the box
|
||||
// (i.e. clock enable, synchronous reset, etc.)
|
||||
replace.insert(std::make_pair(Q,D));
|
||||
// Since `flatten` above would have created wires named "<cell>.Q",
|
||||
// extract the pre-techmap cell name
|
||||
auto pos = Q.wire->name.str().rfind(".");
|
||||
log_assert(pos != std::string::npos);
|
||||
IdString driver = Q.wire->name.substr(0, pos);
|
||||
// And drive the signal that was previously driven by "DFF.Q" (typically
|
||||
// used to implement clock-enable functionality) with the "<cell>.abc9_ff.Q"
|
||||
// wire (which itself is driven by an input port) we inserted above
|
||||
Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str()));
|
||||
log_assert(currQ);
|
||||
holes_module->connect(Q, currQ);
|
||||
continue;
|
||||
}
|
||||
else if (!cell->type.in("$_NOT_", "$_AND_"))
|
||||
log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n");
|
||||
++it;
|
||||
}
|
||||
|
||||
for (auto &conn : holes_module->connections_) {
|
||||
auto it = replace.find(sigmap(conn.second));
|
||||
if (it != replace.end())
|
||||
conn.second = it->second;
|
||||
}
|
||||
|
||||
// Move into a new (temporary) design so that "clean" will only
|
||||
// operate (and run checks on) this one module
|
||||
RTLIL::Design *holes_design = new RTLIL::Design;
|
||||
module->design->modules_.erase(holes_module->name);
|
||||
holes_design->add(holes_module);
|
||||
Pass::call(holes_design, "opt -purge");
|
||||
|
||||
std::stringstream a_buffer;
|
||||
XAigerWriter writer(holes_module, true /* holes_mode */);
|
||||
writer.write_aiger(a_buffer, false /*ascii_mode*/);
|
||||
delete holes_design;
|
||||
|
||||
f << "a";
|
||||
std::string buffer_str = a_buffer.str();
|
||||
int32_t buffer_size_be = to_big_endian(buffer_str.size());
|
||||
f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
|
||||
f.write(buffer_str.data(), buffer_str.size());
|
||||
|
||||
log_pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -917,7 +770,8 @@ struct XAigerBackend : public Backend {
|
|||
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.\n");
|
||||
log("pseudo-outputs. Whitebox contents will be taken from the '<module-name>$holes'\n");
|
||||
log("module, if it exists.\n");
|
||||
log("\n");
|
||||
log(" -ascii\n");
|
||||
log(" write ASCII version of AIGER format\n");
|
||||
|
|
|
@ -326,7 +326,7 @@ struct EdifBackend : public Backend {
|
|||
continue;
|
||||
|
||||
SigMap sigmap(module);
|
||||
std::map<RTLIL::SigSpec, std::set<std::string>> net_join_db;
|
||||
std::map<RTLIL::SigSpec, std::set<std::pair<std::string, bool>>> net_join_db;
|
||||
|
||||
*f << stringf(" (cell %s\n", EDIF_DEF(module->name));
|
||||
*f << stringf(" (cellType GENERIC)\n");
|
||||
|
@ -349,7 +349,7 @@ struct EdifBackend : public Backend {
|
|||
add_prop(p.first, p.second);
|
||||
*f << ")\n";
|
||||
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire));
|
||||
net_join_db[sig].insert(stringf("(portRef %s)", EDIF_REF(wire->name)));
|
||||
net_join_db[sig].insert(make_pair(stringf("(portRef %s)", EDIF_REF(wire->name)), wire->port_input));
|
||||
} else {
|
||||
int b[2];
|
||||
b[wire->upto ? 0 : 1] = wire->start_offset;
|
||||
|
@ -362,7 +362,7 @@ struct EdifBackend : public Backend {
|
|||
*f << ")\n";
|
||||
for (int i = 0; i < wire->width; i++) {
|
||||
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, i));
|
||||
net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), GetSize(wire)-i-1));
|
||||
net_join_db[sig].insert(make_pair(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), GetSize(wire)-i-1), wire->port_input));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -391,7 +391,7 @@ struct EdifBackend : public Backend {
|
|||
log_warning("Bit %d of cell port %s.%s.%s driven by %s will be left unconnected in EDIF output.\n",
|
||||
i, log_id(module), log_id(cell), log_id(p.first), log_signal(sig[i]));
|
||||
else if (sig.size() == 1)
|
||||
net_join_db[sig[i]].insert(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)));
|
||||
net_join_db[sig[i]].insert(make_pair(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)), cell->output(p.first)));
|
||||
else {
|
||||
int member_idx = GetSize(sig)-i-1;
|
||||
auto m = design->module(cell->type);
|
||||
|
@ -400,8 +400,8 @@ struct EdifBackend : public Backend {
|
|||
if (w)
|
||||
member_idx = GetSize(w)-i-1;
|
||||
}
|
||||
net_join_db[sig[i]].insert(stringf("(portRef (member %s %d) (instanceRef %s))",
|
||||
EDIF_REF(p.first), member_idx, EDIF_REF(cell->name)));
|
||||
net_join_db[sig[i]].insert(make_pair(stringf("(portRef (member %s %d) (instanceRef %s))",
|
||||
EDIF_REF(p.first), member_idx, EDIF_REF(cell->name)), cell->output(p.first)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -410,11 +410,13 @@ struct EdifBackend : public Backend {
|
|||
if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1) {
|
||||
if (sig == RTLIL::State::Sx) {
|
||||
for (auto &ref : it.second)
|
||||
log_warning("Exporting x-bit on %s as zero bit.\n", ref.c_str());
|
||||
log_warning("Exporting x-bit on %s as zero bit.\n", ref.first.c_str());
|
||||
sig = RTLIL::State::S0;
|
||||
} else if (sig == RTLIL::State::Sz) {
|
||||
continue;
|
||||
} else {
|
||||
for (auto &ref : it.second)
|
||||
log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.c_str());
|
||||
log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.first.c_str());
|
||||
log_abort();
|
||||
}
|
||||
}
|
||||
|
@ -431,7 +433,7 @@ struct EdifBackend : public Backend {
|
|||
}
|
||||
*f << stringf(" (net %s (joined\n", EDIF_DEF(netname));
|
||||
for (auto &ref : it.second)
|
||||
*f << stringf(" %s\n", ref.c_str());
|
||||
*f << stringf(" %s\n", ref.first.c_str());
|
||||
if (sig.wire == NULL) {
|
||||
if (nogndvcc)
|
||||
log_error("Design contains constant nodes (map with \"hilomap\" first).\n");
|
||||
|
@ -446,6 +448,31 @@ struct EdifBackend : public Backend {
|
|||
add_prop(p.first, p.second);
|
||||
*f << stringf("\n )\n");
|
||||
}
|
||||
for (auto &wire_it : module->wires_) {
|
||||
RTLIL::Wire *wire = wire_it.second;
|
||||
if (!wire->get_bool_attribute(ID::keep))
|
||||
continue;
|
||||
for(int i = 0; i < wire->width; i++) {
|
||||
SigBit raw_sig = RTLIL::SigSpec(wire, i);
|
||||
SigBit mapped_sig = sigmap(raw_sig);
|
||||
if (raw_sig == mapped_sig || net_join_db.count(mapped_sig) == 0)
|
||||
continue;
|
||||
std::string netname = log_signal(raw_sig);
|
||||
for (size_t i = 0; i < netname.size(); i++)
|
||||
if (netname[i] == ' ' || netname[i] == '\\')
|
||||
netname.erase(netname.begin() + i--);
|
||||
*f << stringf(" (net %s (joined\n", EDIF_DEF(netname));
|
||||
auto &refs = net_join_db.at(mapped_sig);
|
||||
for (auto &ref : refs)
|
||||
if (ref.second)
|
||||
*f << stringf(" %s\n", ref.first.c_str());
|
||||
*f << stringf(" )");
|
||||
if (attr_properties && raw_sig.wire != NULL)
|
||||
for (auto &p : raw_sig.wire->attributes)
|
||||
add_prop(p.first, p.second);
|
||||
*f << stringf("\n )\n");
|
||||
}
|
||||
}
|
||||
*f << stringf(" )\n");
|
||||
*f << stringf(" )\n");
|
||||
*f << stringf(" )\n");
|
||||
|
|
|
@ -33,6 +33,7 @@ struct JsonWriter
|
|||
std::ostream &f;
|
||||
bool use_selection;
|
||||
bool aig_mode;
|
||||
bool compat_int_mode;
|
||||
|
||||
Design *design;
|
||||
Module *module;
|
||||
|
@ -42,8 +43,9 @@ struct JsonWriter
|
|||
dict<SigBit, string> sigids;
|
||||
pool<Aig> aig_models;
|
||||
|
||||
JsonWriter(std::ostream &f, bool use_selection, bool aig_mode) :
|
||||
f(f), use_selection(use_selection), aig_mode(aig_mode) { }
|
||||
JsonWriter(std::ostream &f, bool use_selection, bool aig_mode, bool compat_int_mode) :
|
||||
f(f), use_selection(use_selection), aig_mode(aig_mode),
|
||||
compat_int_mode(compat_int_mode) { }
|
||||
|
||||
string get_string(string str)
|
||||
{
|
||||
|
@ -102,8 +104,7 @@ struct JsonWriter
|
|||
if (state < 2)
|
||||
str += " ";
|
||||
f << get_string(str);
|
||||
} else
|
||||
if (GetSize(value) == 32 && value.is_fully_def()) {
|
||||
} else if (compat_int_mode && GetSize(value) == 32 && value.is_fully_def()) {
|
||||
if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
|
||||
f << stringf("%d", value.as_int());
|
||||
else
|
||||
|
@ -294,6 +295,10 @@ struct JsonBackend : public Backend {
|
|||
log(" -aig\n");
|
||||
log(" include AIG models for the different gate types\n");
|
||||
log("\n");
|
||||
log(" -compat-int\n");
|
||||
log(" emit 32-bit fully-defined parameter values directly\n");
|
||||
log(" as JSON numbers (for compatibility with old parsers)\n");
|
||||
log("\n");
|
||||
log("\n");
|
||||
log("The general syntax of the JSON output created by this command is as follows:\n");
|
||||
log("\n");
|
||||
|
@ -368,10 +373,9 @@ struct JsonBackend : public Backend {
|
|||
log("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n");
|
||||
log("\"z\" instead of a number.\n");
|
||||
log("\n");
|
||||
log("Numeric 32-bit parameter and attribute values are written as decimal values.\n");
|
||||
log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n");
|
||||
log("as string holding the binary representation of the value. Strings are written\n");
|
||||
log("as strings, with an appended blank in cases of strings of the form /[01xz]* */.\n");
|
||||
log("Bit vectors (including integers) are written as string holding the binary");
|
||||
log("representation of the value. Strings are written as strings, with an appended");
|
||||
log("blank in cases of strings of the form /[01xz]* */.\n");
|
||||
log("\n");
|
||||
log("For example the following Verilog code:\n");
|
||||
log("\n");
|
||||
|
@ -495,6 +499,7 @@ struct JsonBackend : public Backend {
|
|||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
bool aig_mode = false;
|
||||
bool compat_int_mode = false;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
@ -503,13 +508,17 @@ struct JsonBackend : public Backend {
|
|||
aig_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-compat-int") {
|
||||
compat_int_mode = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
log_header(design, "Executing JSON backend.\n");
|
||||
|
||||
JsonWriter json_writer(*f, false, aig_mode);
|
||||
JsonWriter json_writer(*f, false, aig_mode, compat_int_mode);
|
||||
json_writer.write_design(design);
|
||||
}
|
||||
} JsonBackend;
|
||||
|
@ -530,6 +539,10 @@ struct JsonPass : public Pass {
|
|||
log(" -aig\n");
|
||||
log(" also include AIG models for the different gate types\n");
|
||||
log("\n");
|
||||
log(" -compat-int\n");
|
||||
log(" emit 32-bit fully-defined parameter values directly\n");
|
||||
log(" as JSON numbers (for compatibility with old parsers)\n");
|
||||
log("\n");
|
||||
log("See 'help write_json' for a description of the JSON format used.\n");
|
||||
log("\n");
|
||||
}
|
||||
|
@ -537,6 +550,7 @@ struct JsonPass : public Pass {
|
|||
{
|
||||
std::string filename;
|
||||
bool aig_mode = false;
|
||||
bool compat_int_mode = false;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
@ -549,6 +563,10 @@ struct JsonPass : public Pass {
|
|||
aig_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-compat-int") {
|
||||
compat_int_mode = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
@ -569,7 +587,7 @@ struct JsonPass : public Pass {
|
|||
f = &buf;
|
||||
}
|
||||
|
||||
JsonWriter json_writer(*f, true, aig_mode);
|
||||
JsonWriter json_writer(*f, true, aig_mode, compat_int_mode);
|
||||
json_writer.write_design(design);
|
||||
|
||||
if (!filename.empty()) {
|
||||
|
|
|
@ -304,7 +304,11 @@ class SmtIo:
|
|||
|
||||
def p_open(self):
|
||||
assert self.p is None
|
||||
self.p = subprocess.Popen(self.popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
try:
|
||||
self.p = subprocess.Popen(self.popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
except FileNotFoundError:
|
||||
print("%s SMT Solver '%s' not found in path." % (self.timestamp(), self.popen_vargs[0]), flush=True)
|
||||
sys.exit(1)
|
||||
running_solvers[self.p_index] = self.p
|
||||
self.p_running = True
|
||||
self.p_next = None
|
||||
|
|
|
@ -393,21 +393,6 @@ void AigerReader::parse_xaiger()
|
|||
if (f.peek() == '\n')
|
||||
f.get();
|
||||
|
||||
dict<int,IdString> box_lookup;
|
||||
for (auto m : design->modules()) {
|
||||
auto it = m->attributes.find(ID(abc9_box_id));
|
||||
if (it == m->attributes.end())
|
||||
continue;
|
||||
if (m->name.begins_with("$paramod"))
|
||||
continue;
|
||||
auto id = it->second.as_int();
|
||||
auto r = box_lookup.insert(std::make_pair(id, m->name));
|
||||
if (!r.second)
|
||||
log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n",
|
||||
log_id(m), id, log_id(r.first->second));
|
||||
log_assert(r.second);
|
||||
}
|
||||
|
||||
// Parse footer (symbol table, comments, etc.)
|
||||
std::string s;
|
||||
for (int c = f.get(); c != EOF; c = f.get()) {
|
||||
|
@ -429,17 +414,23 @@ void AigerReader::parse_xaiger()
|
|||
for (unsigned j = 0; j < cutLeavesM; ++j) {
|
||||
nodeID = parse_xaiger_literal(f);
|
||||
log_debug2("\t%u\n", nodeID);
|
||||
if (nodeID == 0) {
|
||||
log_debug("\tLUT '$lut$aiger%d$%d' input %d is constant!\n", aiger_autoidx, rootNodeID, cutLeavesM);
|
||||
continue;
|
||||
}
|
||||
RTLIL::Wire *wire = module->wire(stringf("$aiger%d$%d", aiger_autoidx, nodeID));
|
||||
log_assert(wire);
|
||||
input_sig.append(wire);
|
||||
}
|
||||
// Reverse input order as fastest input is returned first
|
||||
input_sig.reverse();
|
||||
// TODO: Compute LUT mask from AIG in less than O(2 ** input_sig.size())
|
||||
ce.clear();
|
||||
ce.compute_deps(output_sig, input_sig.to_sigbit_pool());
|
||||
RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size());
|
||||
for (int j = 0; j < (1 << cutLeavesM); ++j) {
|
||||
RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << GetSize(input_sig));
|
||||
for (int j = 0; j < GetSize(lut_mask); ++j) {
|
||||
int gray = j ^ (j >> 1);
|
||||
ce.set_incremental(input_sig, RTLIL::Const{gray, static_cast<int>(cutLeavesM)});
|
||||
ce.set_incremental(input_sig, RTLIL::Const{gray, GetSize(input_sig)});
|
||||
RTLIL::SigBit o(output_sig);
|
||||
bool success YS_ATTRIBUTE(unused) = ce.eval(o);
|
||||
log_assert(success);
|
||||
|
@ -453,11 +444,13 @@ void AigerReader::parse_xaiger()
|
|||
}
|
||||
}
|
||||
else if (c == 'r') {
|
||||
uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
|
||||
uint32_t dataSize = parse_xaiger_literal(f);
|
||||
flopNum = parse_xaiger_literal(f);
|
||||
log_debug("flopNum = %u\n", flopNum);
|
||||
log_assert(dataSize == (flopNum+1) * sizeof(uint32_t));
|
||||
f.ignore(flopNum * sizeof(uint32_t));
|
||||
mergeability.reserve(flopNum);
|
||||
for (unsigned i = 0; i < flopNum; i++)
|
||||
mergeability.emplace_back(parse_xaiger_literal(f));
|
||||
}
|
||||
else if (c == 'n') {
|
||||
parse_xaiger_literal(f);
|
||||
|
@ -479,11 +472,15 @@ void AigerReader::parse_xaiger()
|
|||
uint32_t boxNum = parse_xaiger_literal(f);
|
||||
log_debug("boxNum = %u\n", boxNum);
|
||||
for (unsigned i = 0; i < boxNum; i++) {
|
||||
f.ignore(2*sizeof(uint32_t));
|
||||
uint32_t boxInputs = parse_xaiger_literal(f);
|
||||
uint32_t boxOutputs = parse_xaiger_literal(f);
|
||||
uint32_t boxUniqueId = parse_xaiger_literal(f);
|
||||
log_assert(boxUniqueId > 0);
|
||||
uint32_t oldBoxNum = parse_xaiger_literal(f);
|
||||
RTLIL::Cell* cell = module->addCell(stringf("$box%u", oldBoxNum), box_lookup.at(boxUniqueId));
|
||||
RTLIL::Cell* cell = module->addCell(stringf("$box%u", oldBoxNum), stringf("$__boxid%u", boxUniqueId));
|
||||
cell->setPort("\\i", SigSpec(State::S0, boxInputs));
|
||||
cell->setPort("\\o", SigSpec(State::S0, boxOutputs));
|
||||
cell->attributes["\\abc9_box_seq"] = oldBoxNum;
|
||||
boxes.emplace_back(cell);
|
||||
}
|
||||
}
|
||||
|
@ -568,25 +565,18 @@ void AigerReader::parse_aiger_ascii()
|
|||
}
|
||||
|
||||
// Parse outputs
|
||||
digits = ceil(log10(O));
|
||||
for (unsigned i = 0; i < O; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
||||
|
||||
log_debug2("%d is an output\n", l1);
|
||||
const unsigned variable = l1 >> 1;
|
||||
const bool invert = l1 & 1;
|
||||
RTLIL::IdString wire_name(stringf("$%d%s", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
|
||||
RTLIL::Wire *wire = module->wire(wire_name);
|
||||
if (!wire)
|
||||
wire = createWireIfNotExists(module, l1);
|
||||
else if (wire->port_input || wire->port_output) {
|
||||
RTLIL::Wire *new_wire = module->addWire(NEW_ID);
|
||||
module->connect(new_wire, wire);
|
||||
wire = new_wire;
|
||||
}
|
||||
RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i));
|
||||
wire->port_output = true;
|
||||
module->connect(wire, createWireIfNotExists(module, l1));
|
||||
outputs.push_back(wire);
|
||||
}
|
||||
//std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// Parse bad properties
|
||||
for (unsigned i = 0; i < B; ++i, ++line_count) {
|
||||
|
@ -598,6 +588,8 @@ void AigerReader::parse_aiger_ascii()
|
|||
wire->port_output = true;
|
||||
bad_properties.push_back(wire);
|
||||
}
|
||||
//if (B > 0)
|
||||
// std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse invariant constraints
|
||||
for (unsigned i = 0; i < C; ++i, ++line_count)
|
||||
|
@ -753,84 +745,41 @@ void AigerReader::parse_aiger_binary()
|
|||
|
||||
void AigerReader::post_process()
|
||||
{
|
||||
dict<IdString, std::vector<IdString>> box_ports;
|
||||
unsigned ci_count = 0, co_count = 0, flop_count = 0;
|
||||
unsigned ci_count = 0, co_count = 0;
|
||||
for (auto cell : boxes) {
|
||||
RTLIL::Module* box_module = design->module(cell->type);
|
||||
log_assert(box_module);
|
||||
|
||||
auto r = box_ports.insert(cell->type);
|
||||
if (r.second) {
|
||||
// Make carry in the last PI, and carry out the last PO
|
||||
// since ABC requires it this way
|
||||
IdString carry_in, carry_out;
|
||||
for (const auto &port_name : box_module->ports) {
|
||||
auto w = box_module->wire(port_name);
|
||||
log_assert(w);
|
||||
if (w->get_bool_attribute("\\abc9_carry")) {
|
||||
if (w->port_input)
|
||||
carry_in = port_name;
|
||||
if (w->port_output)
|
||||
carry_out = port_name;
|
||||
}
|
||||
else
|
||||
r.first->second.push_back(port_name);
|
||||
}
|
||||
if (carry_in != IdString()) {
|
||||
log_assert(carry_out != IdString());
|
||||
r.first->second.push_back(carry_in);
|
||||
r.first->second.push_back(carry_out);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto port_name : box_ports.at(cell->type)) {
|
||||
RTLIL::Wire* port = box_module->wire(port_name);
|
||||
log_assert(port);
|
||||
RTLIL::SigSpec rhs;
|
||||
for (int i = 0; i < GetSize(port); i++) {
|
||||
RTLIL::Wire* wire = nullptr;
|
||||
if (port->port_input) {
|
||||
log_assert(co_count < outputs.size());
|
||||
wire = outputs[co_count++];
|
||||
log_assert(wire);
|
||||
log_assert(wire->port_output);
|
||||
wire->port_output = false;
|
||||
}
|
||||
if (port->port_output) {
|
||||
log_assert((piNum + ci_count) < inputs.size());
|
||||
wire = inputs[piNum + ci_count++];
|
||||
log_assert(wire);
|
||||
log_assert(wire->port_input);
|
||||
wire->port_input = false;
|
||||
}
|
||||
rhs.append(wire);
|
||||
}
|
||||
cell->setPort(port_name, rhs);
|
||||
}
|
||||
|
||||
if (box_module->attributes.count("\\abc9_flop")) {
|
||||
for (auto &bit : cell->connections_.at("\\i")) {
|
||||
log_assert(bit == State::S0);
|
||||
log_assert(co_count < outputs.size());
|
||||
Wire *wire = outputs[co_count++];
|
||||
log_assert(wire);
|
||||
log_assert(wire->port_output);
|
||||
wire->port_output = false;
|
||||
|
||||
RTLIL::Wire *d = outputs[outputs.size() - flopNum + flop_count];
|
||||
log_assert(d);
|
||||
log_assert(d->port_output);
|
||||
d->port_output = false;
|
||||
|
||||
RTLIL::Wire *q = inputs[piNum - flopNum + flop_count];
|
||||
log_assert(q);
|
||||
log_assert(q->port_input);
|
||||
q->port_input = false;
|
||||
|
||||
auto ff = module->addCell(NEW_ID, "$__ABC9_FF_");
|
||||
ff->setPort("\\D", d);
|
||||
ff->setPort("\\Q", q);
|
||||
flop_count++;
|
||||
continue;
|
||||
bit = outputs[co_count++];
|
||||
log_assert(bit.wire && GetSize(bit.wire) == 1);
|
||||
log_assert(bit.wire->port_output);
|
||||
bit.wire->port_output = false;
|
||||
}
|
||||
for (auto &bit : cell->connections_.at("\\o")) {
|
||||
log_assert(bit == State::S0);
|
||||
log_assert((piNum + ci_count) < inputs.size());
|
||||
bit = inputs[piNum + ci_count++];
|
||||
log_assert(bit.wire && GetSize(bit.wire) == 1);
|
||||
log_assert(bit.wire->port_input);
|
||||
bit.wire->port_input = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < flopNum; i++) {
|
||||
RTLIL::Wire *d = outputs[outputs.size() - flopNum + i];
|
||||
log_assert(d);
|
||||
log_assert(d->port_output);
|
||||
d->port_output = false;
|
||||
|
||||
RTLIL::Wire *q = inputs[piNum - flopNum + i];
|
||||
log_assert(q);
|
||||
log_assert(q->port_input);
|
||||
q->port_input = false;
|
||||
|
||||
auto ff = module->addCell(NEW_ID, "$__ABC9_FF_");
|
||||
ff->setPort("\\D", d);
|
||||
ff->setPort("\\Q", q);
|
||||
ff->attributes["\\abc9_mergeability"] = mergeability[i];
|
||||
}
|
||||
|
||||
dict<RTLIL::IdString, int> wideports_cache;
|
||||
|
@ -859,6 +808,7 @@ void AigerReader::post_process()
|
|||
wire->port_input = false;
|
||||
module->connect(wire, existing);
|
||||
}
|
||||
log_debug(" -> %s\n", log_id(escaped_s));
|
||||
}
|
||||
else if (index > 0) {
|
||||
std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
|
||||
|
@ -872,18 +822,14 @@ void AigerReader::post_process()
|
|||
module->connect(wire, existing);
|
||||
wire->port_input = false;
|
||||
}
|
||||
log_debug(" -> %s\n", log_id(indexed_name));
|
||||
}
|
||||
log_debug(" -> %s\n", log_id(wire));
|
||||
}
|
||||
else if (type == "output") {
|
||||
log_assert(static_cast<unsigned>(variable + co_count) < outputs.size());
|
||||
RTLIL::Wire* wire = outputs[variable + co_count];
|
||||
log_assert(wire);
|
||||
log_assert(wire->port_output);
|
||||
if (escaped_s == "$__dummy__") {
|
||||
wire->port_output = false;
|
||||
continue;
|
||||
}
|
||||
log_debug("Renaming output %s", log_id(wire));
|
||||
|
||||
if (index == 0) {
|
||||
|
@ -896,9 +842,11 @@ void AigerReader::post_process()
|
|||
}
|
||||
else {
|
||||
wire->port_output = false;
|
||||
existing->port_output = true;
|
||||
module->connect(wire, existing);
|
||||
wire = existing;
|
||||
}
|
||||
log_debug(" -> %s\n", log_id(escaped_s));
|
||||
}
|
||||
else if (index > 0) {
|
||||
std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
|
||||
|
@ -909,11 +857,12 @@ void AigerReader::post_process()
|
|||
wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
|
||||
}
|
||||
else {
|
||||
module->connect(wire, existing);
|
||||
wire->port_output = false;
|
||||
existing->port_output = true;
|
||||
module->connect(wire, existing);
|
||||
}
|
||||
log_debug(" -> %s\n", log_id(indexed_name));
|
||||
}
|
||||
log_debug(" -> %s\n", log_id(wire));
|
||||
int init;
|
||||
mf >> init;
|
||||
if (init < 2)
|
||||
|
@ -921,26 +870,8 @@ void AigerReader::post_process()
|
|||
}
|
||||
else if (type == "box") {
|
||||
RTLIL::Cell* cell = module->cell(stringf("$box%d", variable));
|
||||
if (cell) { // ABC could have optimised this box away
|
||||
if (cell) // ABC could have optimised this box away
|
||||
module->rename(cell, escaped_s);
|
||||
for (const auto &i : cell->connections()) {
|
||||
RTLIL::IdString port_name = i.first;
|
||||
RTLIL::SigSpec rhs = i.second;
|
||||
int index = 0;
|
||||
for (auto bit : rhs.bits()) {
|
||||
RTLIL::Wire* wire = bit.wire;
|
||||
RTLIL::IdString escaped_s = RTLIL::escape_id(stringf("%s.%s", log_id(cell), log_id(port_name)));
|
||||
if (index == 0)
|
||||
module->rename(wire, escaped_s);
|
||||
else if (index > 0) {
|
||||
module->rename(wire, stringf("%s[%d]", escaped_s.c_str(), index));
|
||||
if (wideports)
|
||||
wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log_error("Symbol type '%s' not recognised.\n", type.c_str());
|
||||
|
@ -1018,18 +949,21 @@ struct AigerFrontend : public Frontend {
|
|||
log("Load module from an AIGER file into the current design.\n");
|
||||
log("\n");
|
||||
log(" -module_name <module_name>\n");
|
||||
log(" Name of module to be created (default: <filename>)\n");
|
||||
log(" name of module to be created (default: <filename>)\n");
|
||||
log("\n");
|
||||
log(" -clk_name <wire_name>\n");
|
||||
log(" If specified, AIGER latches to be transformed into $_DFF_P_ cells\n");
|
||||
log(" clocked by wire of this name. Otherwise, $_FF_ cells will be used.\n");
|
||||
log(" if specified, AIGER latches to be transformed into $_DFF_P_ cells\n");
|
||||
log(" clocked by wire of this name. otherwise, $_FF_ cells will be used\n");
|
||||
log("\n");
|
||||
log(" -map <filename>\n");
|
||||
log(" read file with port and latch symbols\n");
|
||||
log("\n");
|
||||
log(" -wideports\n");
|
||||
log(" Merge ports that match the pattern 'name[int]' into a single\n");
|
||||
log(" multi-bit port 'name'.\n");
|
||||
log(" merge ports that match the pattern 'name[int]' into a single\n");
|
||||
log(" multi-bit port 'name'\n");
|
||||
log("\n");
|
||||
log(" -xaiger\n");
|
||||
log(" read XAIGER extensions\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
|
@ -1039,7 +973,7 @@ struct AigerFrontend : public Frontend {
|
|||
RTLIL::IdString clk_name;
|
||||
RTLIL::IdString module_name;
|
||||
std::string map_filename;
|
||||
bool wideports = false;
|
||||
bool wideports = false, xaiger = false;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
|
@ -1060,6 +994,10 @@ struct AigerFrontend : public Frontend {
|
|||
wideports = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-xaiger") {
|
||||
xaiger = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(f, filename, args, argidx, true);
|
||||
|
@ -1079,7 +1017,10 @@ struct AigerFrontend : public Frontend {
|
|||
}
|
||||
|
||||
AigerReader reader(design, *f, module_name, clk_name, map_filename, wideports);
|
||||
reader.parse_aiger();
|
||||
if (xaiger)
|
||||
reader.parse_xaiger();
|
||||
else
|
||||
reader.parse_aiger();
|
||||
}
|
||||
} AigerFrontend;
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ struct AigerReader
|
|||
std::vector<RTLIL::Wire*> outputs;
|
||||
std::vector<RTLIL::Wire*> bad_properties;
|
||||
std::vector<RTLIL::Cell*> boxes;
|
||||
std::vector<int> mergeability;
|
||||
|
||||
AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports);
|
||||
void parse_aiger();
|
||||
|
|
|
@ -244,6 +244,7 @@ namespace AST
|
|||
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
|
||||
AstNode *eval_const_function(AstNode *fcall);
|
||||
bool is_simple_const_expr();
|
||||
std::string process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint);
|
||||
|
||||
// create a human-readable text representation of the AST (for debugging)
|
||||
void dumpAst(FILE *f, std::string indent) const;
|
||||
|
|
|
@ -41,6 +41,103 @@ YOSYS_NAMESPACE_BEGIN
|
|||
using namespace AST;
|
||||
using namespace AST_INTERNAL;
|
||||
|
||||
// Process a format string and arguments for $display, $write, $sprintf, etc
|
||||
|
||||
std::string AstNode::process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint) {
|
||||
// Other arguments are placeholders. Process the string as we go through it
|
||||
std::string sout;
|
||||
for (size_t i = 0; i < sformat.length(); i++)
|
||||
{
|
||||
// format specifier
|
||||
if (sformat[i] == '%')
|
||||
{
|
||||
// If there's no next character, that's a problem
|
||||
if (i+1 >= sformat.length())
|
||||
log_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str());
|
||||
|
||||
char cformat = sformat[++i];
|
||||
|
||||
// %% is special, does not need a matching argument
|
||||
if (cformat == '%')
|
||||
{
|
||||
sout += '%';
|
||||
continue;
|
||||
}
|
||||
|
||||
// Simplify the argument
|
||||
AstNode *node_arg = nullptr;
|
||||
|
||||
// Everything from here on depends on the format specifier
|
||||
switch (cformat)
|
||||
{
|
||||
case 's':
|
||||
case 'S':
|
||||
case 'd':
|
||||
case 'D':
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (next_arg >= GetSize(children))
|
||||
log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n",
|
||||
cformat, str.c_str());
|
||||
|
||||
node_arg = children[next_arg++];
|
||||
while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
|
||||
if (node_arg->type != AST_CONSTANT)
|
||||
log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str());
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
break;
|
||||
|
||||
default:
|
||||
log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cformat)
|
||||
{
|
||||
case 's':
|
||||
case 'S':
|
||||
sout += node_arg->bitsAsConst().decode_string();
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'D':
|
||||
{
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof(tmp), "%d", node_arg->bitsAsConst().as_int());
|
||||
sout += tmp;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
{
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof(tmp), "%x", node_arg->bitsAsConst().as_int());
|
||||
sout += tmp;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
sout += log_id(current_module->name);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_abort();
|
||||
}
|
||||
}
|
||||
|
||||
// not a format specifier
|
||||
else
|
||||
sout += sformat[i];
|
||||
}
|
||||
return sout;
|
||||
}
|
||||
|
||||
|
||||
// convert the AST into a simpler AST that has all parameters substituted by their
|
||||
// values, unrolled for-loops, expanded generate blocks, etc. when this function
|
||||
// is done with an AST it can be converted into RTLIL using genRTLIL().
|
||||
|
@ -216,99 +313,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
if (node_string->type != AST_CONSTANT)
|
||||
log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str());
|
||||
std::string sformat = node_string->bitsAsConst().decode_string();
|
||||
|
||||
// Other arguments are placeholders. Process the string as we go through it
|
||||
std::string sout;
|
||||
int next_arg = 1;
|
||||
for (size_t i = 0; i < sformat.length(); i++)
|
||||
{
|
||||
// format specifier
|
||||
if (sformat[i] == '%')
|
||||
{
|
||||
// If there's no next character, that's a problem
|
||||
if (i+1 >= sformat.length())
|
||||
log_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str());
|
||||
|
||||
char cformat = sformat[++i];
|
||||
|
||||
// %% is special, does not need a matching argument
|
||||
if (cformat == '%')
|
||||
{
|
||||
sout += '%';
|
||||
continue;
|
||||
}
|
||||
|
||||
// Simplify the argument
|
||||
AstNode *node_arg = nullptr;
|
||||
|
||||
// Everything from here on depends on the format specifier
|
||||
switch (cformat)
|
||||
{
|
||||
case 's':
|
||||
case 'S':
|
||||
case 'd':
|
||||
case 'D':
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (next_arg >= GetSize(children))
|
||||
log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n",
|
||||
cformat, str.c_str());
|
||||
|
||||
node_arg = children[next_arg++];
|
||||
while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
|
||||
if (node_arg->type != AST_CONSTANT)
|
||||
log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str());
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
break;
|
||||
|
||||
default:
|
||||
log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cformat)
|
||||
{
|
||||
case 's':
|
||||
case 'S':
|
||||
sout += node_arg->bitsAsConst().decode_string();
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'D':
|
||||
{
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof(tmp), "%d", node_arg->bitsAsConst().as_int());
|
||||
sout += tmp;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
{
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof(tmp), "%x", node_arg->bitsAsConst().as_int());
|
||||
sout += tmp;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
sout += log_id(current_module->name);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_abort();
|
||||
}
|
||||
}
|
||||
|
||||
// not a format specifier
|
||||
else
|
||||
sout += sformat[i];
|
||||
}
|
||||
|
||||
std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint);
|
||||
// Finally, print the message (only include a \n for $display, not for $write)
|
||||
log("%s", sout.c_str());
|
||||
if (str == "$display")
|
||||
|
@ -2244,6 +2249,17 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
goto apply_newNode;
|
||||
}
|
||||
|
||||
if (str == "\\$sformatf") {
|
||||
AstNode *node_string = children[0];
|
||||
while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
|
||||
if (node_string->type != AST_CONSTANT)
|
||||
log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str());
|
||||
std::string sformat = node_string->bitsAsConst().decode_string();
|
||||
std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint);
|
||||
newNode = AstNode::mkconst_str(sout);
|
||||
goto apply_newNode;
|
||||
}
|
||||
|
||||
if (current_scope.count(str) != 0 && current_scope[str]->type == AST_DPI_FUNCTION)
|
||||
{
|
||||
AstNode *dpi_decl = current_scope[str];
|
||||
|
|
|
@ -539,6 +539,14 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
|
|||
return true;
|
||||
}
|
||||
|
||||
if (inst->Type() == OPER_REDUCE_NAND) {
|
||||
Wire *tmp = module->addWire(NEW_ID);
|
||||
cell = module->addReduceAnd(inst_name, IN, tmp, SIGNED);
|
||||
module->addNot(NEW_ID, tmp, net_map_at(inst->GetOutput()));
|
||||
import_attributes(cell->attributes, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inst->Type() == OPER_REDUCE_OR) {
|
||||
cell = module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
|
||||
import_attributes(cell->attributes, inst);
|
||||
|
@ -1891,6 +1899,9 @@ void verific_import(Design *design, const std::map<std::string,std::string> &par
|
|||
if (!verific_error_msg.empty())
|
||||
log_error("%s\n", verific_error_msg.c_str());
|
||||
|
||||
for (auto nl : nl_todo)
|
||||
nl->ChangePortBusStructures(1 /* hierarchical */);
|
||||
|
||||
VerificExtNets worker;
|
||||
for (auto nl : nl_todo)
|
||||
worker.run(nl);
|
||||
|
@ -2408,7 +2419,7 @@ struct VerificPass : public Pass {
|
|||
else
|
||||
{
|
||||
if (argidx == GetSize(args))
|
||||
log_cmd_error("No top module specified.\n");
|
||||
cmd_error(args, argidx, "No top module specified.\n");
|
||||
|
||||
Array veri_modules, vhdl_units;
|
||||
for (; argidx < GetSize(args); argidx++)
|
||||
|
@ -2470,6 +2481,9 @@ struct VerificPass : public Pass {
|
|||
worker.run(nl);
|
||||
}
|
||||
|
||||
for (auto nl : nl_todo)
|
||||
nl->ChangePortBusStructures(1 /* hierarchical */);
|
||||
|
||||
if (!dumpfile.empty()) {
|
||||
VeriWrite veri_writer;
|
||||
veri_writer.WriteFile(dumpfile.c_str(), Netlist::PresentDesign());
|
||||
|
@ -2495,7 +2509,7 @@ struct VerificPass : public Pass {
|
|||
goto check_error;
|
||||
}
|
||||
|
||||
log_cmd_error("Missing or unsupported mode parameter.\n");
|
||||
cmd_error(args, argidx, "Missing or unsupported mode parameter.\n");
|
||||
|
||||
check_error:
|
||||
if (!verific_error_msg.empty())
|
||||
|
@ -2568,14 +2582,14 @@ struct ReadPass : public Pass {
|
|||
static bool use_verific = verific_available;
|
||||
|
||||
if (args.size() < 2 || args[1][0] != '-')
|
||||
log_cmd_error("Missing mode parameter.\n");
|
||||
cmd_error(args, 1, "Missing mode parameter.\n");
|
||||
|
||||
if (args[1] == "-verific" || args[1] == "-noverific") {
|
||||
if (args.size() != 2)
|
||||
log_cmd_error("Additional arguments to -verific/-noverific.\n");
|
||||
cmd_error(args, 1, "Additional arguments to -verific/-noverific.\n");
|
||||
if (args[1] == "-verific") {
|
||||
if (!verific_available)
|
||||
log_cmd_error("This version of Yosys is built without Verific support.\n");
|
||||
cmd_error(args, 1, "This version of Yosys is built without Verific support.\n");
|
||||
use_verific = true;
|
||||
} else {
|
||||
use_verific = false;
|
||||
|
@ -2584,7 +2598,7 @@ struct ReadPass : public Pass {
|
|||
}
|
||||
|
||||
if (args.size() < 3)
|
||||
log_cmd_error("Missing file name parameter.\n");
|
||||
cmd_error(args, 3, "Missing file name parameter.\n");
|
||||
|
||||
if (args[1] == "-vlog95" || args[1] == "-vlog2k") {
|
||||
if (use_verific) {
|
||||
|
@ -2616,7 +2630,7 @@ struct ReadPass : public Pass {
|
|||
args[0] = "verific";
|
||||
Pass::call(design, args);
|
||||
} else {
|
||||
log_cmd_error("This version of Yosys is built without Verific support.\n");
|
||||
cmd_error(args, 1, "This version of Yosys is built without Verific support.\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -2663,7 +2677,7 @@ struct ReadPass : public Pass {
|
|||
return;
|
||||
}
|
||||
|
||||
log_cmd_error("Missing or unsupported mode parameter.\n");
|
||||
cmd_error(args, 1, "Missing or unsupported mode parameter.\n");
|
||||
}
|
||||
} ReadPass;
|
||||
|
||||
|
|
|
@ -431,6 +431,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
|
|||
"+:" { return TOK_POS_INDEXED; }
|
||||
"-:" { return TOK_NEG_INDEXED; }
|
||||
|
||||
".*" { return TOK_WILDCARD_CONNECT; }
|
||||
|
||||
[-+]?[=*]> {
|
||||
if (!specify_mode) REJECT;
|
||||
frontend_verilog_yylval.string = new std::string(yytext);
|
||||
|
|
|
@ -138,7 +138,7 @@ struct specify_rise_fall {
|
|||
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
||||
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
|
||||
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
|
||||
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR TOK_WILDCARD_CONNECT
|
||||
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC
|
||||
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
|
||||
%token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH
|
||||
|
@ -1580,6 +1580,11 @@ cell_port:
|
|||
node->children.back()->str = *$3;
|
||||
delete $3;
|
||||
free_attr($1);
|
||||
} |
|
||||
attr TOK_WILDCARD_CONNECT {
|
||||
if (!sv_mode)
|
||||
frontend_verilog_yyerror("Wildcard port connections are only supported in SystemVerilog mode.");
|
||||
astbuf2->attributes[ID(wildcard_port_conns)] = AstNode::mkconst_int(1, false);
|
||||
};
|
||||
|
||||
always_comb_or_latch:
|
||||
|
|
|
@ -295,6 +295,9 @@ int main(int argc, char **argv)
|
|||
printf(" -E <depsfile>\n");
|
||||
printf(" write a Makefile dependencies file with in- and output file names\n");
|
||||
printf("\n");
|
||||
printf(" -x <feature>\n");
|
||||
printf(" do not print warnings for the specified experimental feature\n");
|
||||
printf("\n");
|
||||
printf(" -g\n");
|
||||
printf(" globally enable debug log messages\n");
|
||||
printf("\n");
|
||||
|
@ -317,8 +320,14 @@ int main(int argc, char **argv)
|
|||
exit(0);
|
||||
}
|
||||
|
||||
if (argc == 2 && (!strcmp(argv[1], "-V") || !strcmp(argv[1], "-version") || !strcmp(argv[1], "--version")))
|
||||
{
|
||||
printf("%s\n", yosys_version_str);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1)
|
||||
while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:x:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
|
@ -449,6 +458,9 @@ int main(int argc, char **argv)
|
|||
case 'E':
|
||||
depsfile = optarg;
|
||||
break;
|
||||
case 'x':
|
||||
log_experimentals_ignored.insert(optarg);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Run '%s -h' for help.\n", argv[0]);
|
||||
exit(1);
|
||||
|
@ -561,6 +573,10 @@ int main(int argc, char **argv)
|
|||
|
||||
if (log_warnings_count)
|
||||
log("Warnings: %d unique messages, %d total\n", GetSize(log_warnings), log_warnings_count);
|
||||
|
||||
if (!log_experimentals.empty())
|
||||
log("Warnings: %d experimental features used (not excluded with -x).\n", GetSize(log_experimentals));
|
||||
|
||||
#ifdef _WIN32
|
||||
log("End of script. Logfile hash: %s\n", hash.c_str());
|
||||
#else
|
||||
|
|
|
@ -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<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
|
||||
std::set<std::string> log_warnings;
|
||||
std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored;
|
||||
int log_warnings_count = 0;
|
||||
bool log_hdump_all = false;
|
||||
FILE *log_errfile = NULL;
|
||||
|
@ -377,6 +377,19 @@ void log_warning(const char *format, ...)
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
void log_experimental(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
string s = vstringf(format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (log_experimentals_ignored.count(s) == 0 && log_experimentals.count(s) == 0) {
|
||||
log_warning("Feature '%s' is experimental.\n", s.c_str());
|
||||
log_experimentals.insert(s);
|
||||
}
|
||||
}
|
||||
|
||||
void log_warning_noprefix(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
|
|
@ -50,7 +50,7 @@ extern std::vector<FILE*> log_files;
|
|||
extern std::vector<std::ostream*> log_streams;
|
||||
extern std::map<std::string, std::set<std::string>> log_hdump;
|
||||
extern std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
|
||||
extern std::set<std::string> log_warnings;
|
||||
extern std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored;
|
||||
extern int log_warnings_count;
|
||||
extern bool log_hdump_all;
|
||||
extern FILE *log_errfile;
|
||||
|
@ -77,6 +77,7 @@ YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noretur
|
|||
void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3));
|
||||
void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
void log_experimental(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
|
||||
// Log with filename to report a problem in a source file.
|
||||
void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));
|
||||
|
|
|
@ -304,6 +304,9 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
|
|||
if (pass_register.count(args[0]) == 0)
|
||||
log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0].c_str());
|
||||
|
||||
if (pass_register[args[0]]->experimental_flag)
|
||||
log_experimental("%s", args[0].c_str());
|
||||
|
||||
size_t orig_sel_stack_pos = design->selection_stack.size();
|
||||
auto state = pass_register[args[0]]->pre_execute();
|
||||
pass_register[args[0]]->execute(args, design);
|
||||
|
@ -824,6 +827,11 @@ struct HelpPass : public Pass {
|
|||
log("=");
|
||||
log("\n");
|
||||
it.second->help();
|
||||
if (it.second->experimental_flag) {
|
||||
log("\n");
|
||||
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str());
|
||||
log("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (args[1] == "-cells") {
|
||||
|
@ -846,6 +854,11 @@ struct HelpPass : public Pass {
|
|||
std::ostringstream buf;
|
||||
log_streams.push_back(&buf);
|
||||
it.second->help();
|
||||
if (it.second->experimental_flag) {
|
||||
log("\n");
|
||||
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str());
|
||||
log("\n");
|
||||
}
|
||||
log_streams.pop_back();
|
||||
write_tex(f, it.first, it.second->short_help, buf.str());
|
||||
}
|
||||
|
@ -858,6 +871,11 @@ struct HelpPass : public Pass {
|
|||
std::ostringstream buf;
|
||||
log_streams.push_back(&buf);
|
||||
it.second->help();
|
||||
if (it.second->experimental_flag) {
|
||||
log("\n");
|
||||
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str());
|
||||
log("\n");
|
||||
}
|
||||
log_streams.pop_back();
|
||||
write_html(f, it.first, it.second->short_help, buf.str());
|
||||
}
|
||||
|
@ -865,6 +883,11 @@ struct HelpPass : public Pass {
|
|||
}
|
||||
else if (pass_register.count(args[1])) {
|
||||
pass_register.at(args[1])->help();
|
||||
if (pass_register.at(args[1])->experimental_flag) {
|
||||
log("\n");
|
||||
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", args[1].c_str());
|
||||
log("\n");
|
||||
}
|
||||
}
|
||||
else if (cell_help_messages.cell_help.count(args[1])) {
|
||||
log("%s", cell_help_messages.cell_help.at(args[1]).c_str());
|
||||
|
|
|
@ -36,6 +36,11 @@ struct Pass
|
|||
|
||||
int call_counter;
|
||||
int64_t runtime_ns;
|
||||
bool experimental_flag = false;
|
||||
|
||||
void experimental() {
|
||||
experimental_flag = true;
|
||||
}
|
||||
|
||||
struct pre_post_exec_state_t {
|
||||
Pass *parent_pass;
|
||||
|
|
|
@ -851,6 +851,8 @@ public:
|
|||
|
||||
RTLIL::SigSpec repeat(int num) const;
|
||||
|
||||
void reverse() { inline_unpack(); std::reverse(bits_.begin(), bits_.end()); }
|
||||
|
||||
bool operator <(const RTLIL::SigSpec &other) const;
|
||||
bool operator ==(const RTLIL::SigSpec &other) const;
|
||||
inline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); }
|
||||
|
|
|
@ -198,8 +198,8 @@ calculated signal and a constant zero with an {\tt \$and} gate).
|
|||
|
||||
\subsection{Registers}
|
||||
|
||||
D-Type Flip-Flops are represented by {\tt \$dff} cells. These cells have a clock port \B{CLK},
|
||||
an input port \B{D} and an output port \B{Q}. The following parameters are available for \$dff
|
||||
D-type flip-flops are represented by {\tt \$dff} cells. These cells have a clock port \B{CLK},
|
||||
an input port \B{D} and an output port \B{Q}. The following parameters are available for {\tt \$dff}
|
||||
cells:
|
||||
|
||||
\begin{itemize}
|
||||
|
@ -211,13 +211,23 @@ Clock is active on the positive edge if this parameter has the value {\tt 1'b1}
|
|||
edge if this parameter is {\tt 1'b0}.
|
||||
\end{itemize}
|
||||
|
||||
D-Type Flip-Flops with asynchronous resets are represented by {\tt \$adff} cells. As the {\tt \$dff}
|
||||
D-type flip-flops with enable are represented by {\tt \$dffe} cells. As the {\tt \$dff}
|
||||
cells they have \B{CLK}, \B{D} and \B{Q} ports. In addition they also have a single-bit \B{EN}
|
||||
input port for the enable pin and the following parameter:
|
||||
|
||||
\begin{itemize}
|
||||
\item \B{EN\_POLARITY} \\
|
||||
The enable input is active-high if this parameter has the value {\tt 1'b1} and active-low
|
||||
if this parameter is {\tt 1'b0}.
|
||||
\end{itemize}
|
||||
|
||||
D-type flip-flops with asynchronous reset are represented by {\tt \$adff} cells. As the {\tt \$dff}
|
||||
cells they have \B{CLK}, \B{D} and \B{Q} ports. In addition they also have a single-bit \B{ARST}
|
||||
input port for the reset pin and the following additional two parameters:
|
||||
|
||||
\begin{itemize}
|
||||
\item \B{ARST\_POLARITY} \\
|
||||
The asynchronous reset is high-active if this parameter has the value {\tt 1'b1} and low-active
|
||||
The asynchronous reset is active-high if this parameter has the value {\tt 1'b1} and active-low
|
||||
if this parameter is {\tt 1'b0}.
|
||||
|
||||
\item \B{ARST\_VALUE} \\
|
||||
|
@ -231,8 +241,27 @@ Usually these cells are generated by the {\tt proc} pass using the information
|
|||
in the designs RTLIL::Process objects.
|
||||
\end{sloppypar}
|
||||
|
||||
D-type flip-flops with asynchronous set and reset are represented by {\tt \$dffsr} cells.
|
||||
As the {\tt \$dff} cells they have \B{CLK}, \B{D} and \B{Q} ports. In addition they also have
|
||||
a single-bit \B{SET} input port for the set pin, a single-bit \B{CLR} input port for the reset pin,
|
||||
and the following two parameters:
|
||||
|
||||
\begin{itemize}
|
||||
\item \B{SET\_POLARITY} \\
|
||||
The set input is active-high if this parameter has the value {\tt 1'b1} and active-low
|
||||
if this parameter is {\tt 1'b0}.
|
||||
|
||||
\item \B{CLR\_POLARITY} \\
|
||||
The reset input is active-high if this parameter has the value {\tt 1'b1} and active-low
|
||||
if this parameter is {\tt 1'b0}.
|
||||
\end{itemize}
|
||||
|
||||
When both the set and reset inputs of a {\tt \$dffsr} cell are active, the reset input takes
|
||||
precedence.
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$sr} cells (set-reset flip-flops) and d-type latches.
|
||||
Add information about {\tt \$sr} cells (set-reset flip-flops), {\tt \$dlatch} cells (d-type latches),
|
||||
and {\tt \$dlatchsr} cells (d-type latches with set/reset).
|
||||
\end{fixme}
|
||||
|
||||
\subsection{Memories}
|
||||
|
@ -451,6 +480,30 @@ $ClkEdge$ & $RstLvl$ & $RstVal$ & Cell Type \\
|
|||
\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DFF\_PP0\_} \\
|
||||
\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DFF\_PP1\_} \\
|
||||
\end{tabular}
|
||||
% FIXME: the layout of this is broken and I have no idea how to fix it
|
||||
\hfil
|
||||
\begin{tabular}[t]{lll}
|
||||
$ClkEdge$ & $EnLvl$ & Cell Type \\
|
||||
\hline
|
||||
\lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];0; & {\tt \$\_DFFE\_NN\_} \\
|
||||
\lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];1; & {\tt \$\_DFFE\_NP\_} \\
|
||||
\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];0; & {\tt \$\_DFFE\_PN\_} \\
|
||||
\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & {\tt \$\_DFFE\_PP\_} \\
|
||||
\end{tabular}
|
||||
% FIXME: the layout of this is broken too
|
||||
\hfil
|
||||
\begin{tabular}[t]{llll}
|
||||
$ClkEdge$ & $SetLvl$ & $RstLvl$ & Cell Type \\
|
||||
\hline
|
||||
\lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & {\tt \$\_DFFSR\_NNN\_} \\
|
||||
\lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & {\tt \$\_DFFSR\_NNP\_} \\
|
||||
\lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DFFSR\_NPN\_} \\
|
||||
\lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DFFSR\_NPP\_} \\
|
||||
\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & {\tt \$\_DFFSR\_PNN\_} \\
|
||||
\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & {\tt \$\_DFFSR\_PNP\_} \\
|
||||
\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DFFSR\_PPN\_} \\
|
||||
\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DFFSR\_PPP\_} \\
|
||||
\end{tabular}
|
||||
\caption{Cell types for gate level logic networks}
|
||||
\label{tab:CellLib_gates}
|
||||
\end{table}
|
||||
|
@ -459,11 +512,22 @@ Table~\ref{tab:CellLib_gates} lists all cell types used for gate level logic. Th
|
|||
{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_NAND\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_OR\_}, {\tt \$\_NOR\_},
|
||||
{\tt \$\_ORNOT\_}, {\tt \$\_XOR\_}, {\tt \$\_XNOR\_} and {\tt \$\_MUX\_} are used to model combinatorial logic.
|
||||
The cell type {\tt \$\_TBUF\_} is used to model tristate logic.
|
||||
|
||||
The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_} represent d-type flip-flops.
|
||||
|
||||
The cell types {\tt \$\_DFFE\_NN\_}, {\tt \$\_DFFE\_NP\_}, {\tt \$\_DFFE\_PN\_} and {\tt \$\_DFFE\_PP\_}
|
||||
implement d-type flip-flops with enable. The values in the table for these cell types relate to the
|
||||
following Verilog code template.
|
||||
|
||||
\begin{lstlisting}[mathescape,language=Verilog]
|
||||
always @($ClkEdge$ C)
|
||||
if (EN == $EnLvl$)
|
||||
Q <= D;
|
||||
\end{lstlisting}
|
||||
|
||||
The cell types {\tt \$\_DFF\_NN0\_}, {\tt \$\_DFF\_NN1\_}, {\tt \$\_DFF\_NP0\_}, {\tt \$\_DFF\_NP1\_},
|
||||
{\tt \$\_DFF\_PN0\_}, {\tt \$\_DFF\_PN1\_}, {\tt \$\_DFF\_PP0\_} and {\tt \$\_DFF\_PP1\_} implement
|
||||
d-type flip-flops with asynchronous resets. The values in the table for these cell types relate to the
|
||||
d-type flip-flops with asynchronous reset. The values in the table for these cell types relate to the
|
||||
following Verilog code template, where \lstinline[mathescape,language=Verilog];$RstEdge$; is \lstinline[language=Verilog];posedge;
|
||||
if \lstinline[mathescape,language=Verilog];$RstLvl$; if \lstinline[language=Verilog];1;, and \lstinline[language=Verilog];negedge;
|
||||
otherwise.
|
||||
|
@ -476,6 +540,25 @@ otherwise.
|
|||
Q <= D;
|
||||
\end{lstlisting}
|
||||
|
||||
The cell types {\tt \$\_DFFSR\_NNN\_}, {\tt \$\_DFFSR\_NNP\_}, {\tt \$\_DFFSR\_NPN\_}, {\tt \$\_DFFSR\_NPP\_},
|
||||
{\tt \$\_DFFSR\_PNN\_}, {\tt \$\_DFFSR\_PNP\_}, {\tt \$\_DFFSR\_PPN\_} and {\tt \$\_DFFSR\_PPP\_} implement
|
||||
d-type flip-flops with asynchronous set and reset. The values in the table for these cell types relate to the
|
||||
following Verilog code template, where \lstinline[mathescape,language=Verilog];$RstEdge$; is \lstinline[language=Verilog];posedge;
|
||||
if \lstinline[mathescape,language=Verilog];$RstLvl$; if \lstinline[language=Verilog];1;, \lstinline[language=Verilog];negedge;
|
||||
otherwise, and \lstinline[mathescape,language=Verilog];$SetEdge$; is \lstinline[language=Verilog];posedge;
|
||||
if \lstinline[mathescape,language=Verilog];$SetLvl$; if \lstinline[language=Verilog];1;, \lstinline[language=Verilog];negedge;
|
||||
otherwise.
|
||||
|
||||
\begin{lstlisting}[mathescape,language=Verilog]
|
||||
always @($ClkEdge$ C, $RstEdge$ R, $SetEdge$ S)
|
||||
if (R == $RstLvl$)
|
||||
Q <= 0;
|
||||
else if (S == $SetLvl$)
|
||||
Q <= 1;
|
||||
else
|
||||
Q <= D;
|
||||
\end{lstlisting}
|
||||
|
||||
In most cases gate level logic networks are created from RTL networks using the {\tt techmap} pass. The flip-flop cells
|
||||
from the gate level logic network can be mapped to physical flip-flop cells from a Liberty file using the {\tt dfflibmap}
|
||||
pass. The combinatorial logic cells can be mapped to physical cells from a Liberty file via ABC \citeweblink{ABC}
|
||||
|
@ -507,11 +590,7 @@ Add information about {\tt \$ff} and {\tt \$\_FF\_} cells.
|
|||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$dffe}, {\tt \$dffsr}, {\tt \$dlatch}, and {\tt \$dlatchsr} cells.
|
||||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLATCH\_?\_}, and {\tt \$\_DLATCHSR\_???\_} cells.
|
||||
Add information about {\tt \$\_DLATCH\_?\_}, and {\tt \$\_DLATCHSR\_???\_} cells.
|
||||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
|
|
|
@ -1935,6 +1935,19 @@ def parse_header(source):
|
|||
line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }")
|
||||
ugly_line = unpretty_string(line)
|
||||
|
||||
# for anonymous unions, ignore union enclosure by skipping start line and replacing end line with new line
|
||||
if 'union {' in line:
|
||||
j = i+1
|
||||
while j < len(source_text):
|
||||
union_line = source_text[j]
|
||||
if '};' in union_line:
|
||||
source_text[j] = '\n'
|
||||
break
|
||||
j += 1
|
||||
if j != len(source_text):
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if str.startswith(ugly_line, "namespace "):# and ugly_line.find("std") == -1 and ugly_line.find("__") == -1:
|
||||
namespace_name = ugly_line[10:].replace("{","").strip()
|
||||
namespaces.append((namespace_name, ugly_line.count("{")))
|
||||
|
|
|
@ -873,7 +873,7 @@ struct ShowPass : public Pass {
|
|||
#ifdef __APPLE__
|
||||
std::string cmd = stringf("ps -fu %d | grep -q '[ ]%s' || xdot '%s' &", getuid(), dot_file.c_str(), dot_file.c_str());
|
||||
#else
|
||||
std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid'; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str());
|
||||
std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid' 2> /dev/null; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str());
|
||||
#endif
|
||||
log("Exec: %s\n", cmd.c_str());
|
||||
if (run_command(cmd) != 0)
|
||||
|
|
|
@ -34,13 +34,20 @@ static SigSet<sig2driver_entry_t> sig2driver, sig2user;
|
|||
static std::set<RTLIL::Cell*> muxtree_cells;
|
||||
static SigPool sig_at_port;
|
||||
|
||||
static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, pool<Cell*> &recursion_monitor)
|
||||
static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, pool<Cell*> &recursion_monitor, dict<RTLIL::SigSpec, bool> &mux_tree_cache)
|
||||
{
|
||||
if (mux_tree_cache.find(sig) != mux_tree_cache.end())
|
||||
return mux_tree_cache.at(sig);
|
||||
|
||||
if (sig.is_fully_const() || old_sig == sig) {
|
||||
ret_true:
|
||||
mux_tree_cache[sig] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sig_at_port.check_any(assign_map(sig))) {
|
||||
ret_false:
|
||||
mux_tree_cache[sig] = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -49,13 +56,13 @@ static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, poo
|
|||
for (auto &cellport : cellport_list)
|
||||
{
|
||||
if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y") {
|
||||
return false;
|
||||
goto ret_false;
|
||||
}
|
||||
|
||||
if (recursion_monitor.count(cellport.first)) {
|
||||
log_warning("logic loop in mux tree at signal %s in module %s.\n",
|
||||
log_signal(sig), RTLIL::id2cstr(module->name));
|
||||
return false;
|
||||
goto ret_false;
|
||||
}
|
||||
|
||||
recursion_monitor.insert(cellport.first);
|
||||
|
@ -63,22 +70,22 @@ static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, poo
|
|||
RTLIL::SigSpec sig_a = assign_map(cellport.first->getPort("\\A"));
|
||||
RTLIL::SigSpec sig_b = assign_map(cellport.first->getPort("\\B"));
|
||||
|
||||
if (!check_state_mux_tree(old_sig, sig_a, recursion_monitor)) {
|
||||
if (!check_state_mux_tree(old_sig, sig_a, recursion_monitor, mux_tree_cache)) {
|
||||
recursion_monitor.erase(cellport.first);
|
||||
return false;
|
||||
goto ret_false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sig_b.size(); i += sig_a.size())
|
||||
if (!check_state_mux_tree(old_sig, sig_b.extract(i, sig_a.size()), recursion_monitor)) {
|
||||
if (!check_state_mux_tree(old_sig, sig_b.extract(i, sig_a.size()), recursion_monitor, mux_tree_cache)) {
|
||||
recursion_monitor.erase(cellport.first);
|
||||
return false;
|
||||
goto ret_false;
|
||||
}
|
||||
|
||||
recursion_monitor.erase(cellport.first);
|
||||
muxtree_cells.insert(cellport.first);
|
||||
}
|
||||
|
||||
return true;
|
||||
goto ret_true;
|
||||
}
|
||||
|
||||
static bool check_state_users(RTLIL::SigSpec sig)
|
||||
|
@ -143,11 +150,12 @@ static void detect_fsm(RTLIL::Wire *wire)
|
|||
pool<Cell*> recursion_monitor;
|
||||
RTLIL::SigSpec sig_q = assign_map(cellport.first->getPort("\\Q"));
|
||||
RTLIL::SigSpec sig_d = assign_map(cellport.first->getPort("\\D"));
|
||||
dict<RTLIL::SigSpec, bool> mux_tree_cache;
|
||||
|
||||
if (sig_q != assign_map(wire))
|
||||
continue;
|
||||
|
||||
looks_like_state_reg = check_state_mux_tree(sig_q, sig_d, recursion_monitor);
|
||||
looks_like_state_reg = check_state_mux_tree(sig_q, sig_d, recursion_monitor, mux_tree_cache);
|
||||
looks_like_good_state_reg = check_state_users(sig_q);
|
||||
|
||||
if (!looks_like_state_reg)
|
||||
|
|
|
@ -548,6 +548,19 @@ RTLIL::Module *check_if_top_has_changed(Design *design, Module *top_mod)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// Find a matching wire for an implicit port connection; traversing generate block scope
|
||||
RTLIL::Wire *find_implicit_port_wire(Module *module, Cell *cell, const std::string& port)
|
||||
{
|
||||
const std::string &cellname = cell->name.str();
|
||||
size_t idx = cellname.size();
|
||||
while ((idx = cellname.find_last_of('.', idx-1)) != std::string::npos) {
|
||||
Wire *found = module->wire(cellname.substr(0, idx+1) + port.substr(1));
|
||||
if (found != nullptr)
|
||||
return found;
|
||||
}
|
||||
return module->wire(port);
|
||||
}
|
||||
|
||||
struct HierarchyPass : public Pass {
|
||||
HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
|
||||
void help() YS_OVERRIDE
|
||||
|
@ -970,15 +983,71 @@ struct HierarchyPass : public Pass {
|
|||
}
|
||||
}
|
||||
|
||||
// Determine default values
|
||||
dict<IdString, dict<IdString, Const>> defaults_db;
|
||||
if (!nodefaults)
|
||||
{
|
||||
dict<IdString, dict<IdString, Const>> defaults_db;
|
||||
|
||||
for (auto module : design->modules())
|
||||
for (auto wire : module->wires())
|
||||
if (wire->port_input && wire->attributes.count("\\defaultvalue"))
|
||||
defaults_db[module->name][wire->name] = wire->attributes.at("\\defaultvalue");
|
||||
}
|
||||
// Process SV implicit wildcard port connections
|
||||
std::set<Module*> blackbox_derivatives;
|
||||
std::vector<Module*> design_modules = design->modules();
|
||||
|
||||
for (auto module : design_modules)
|
||||
{
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
if (!cell->get_bool_attribute(ID(wildcard_port_conns)))
|
||||
continue;
|
||||
Module *m = design->module(cell->type);
|
||||
|
||||
if (m == nullptr)
|
||||
log_error("Cell %s.%s (%s) has implicit port connections but the module it instantiates is unknown.\n",
|
||||
RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
|
||||
|
||||
// Need accurate port widths for error checking; so must derive blackboxes with dynamic port widths
|
||||
if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
|
||||
IdString new_m_name = m->derive(design, cell->parameters, true);
|
||||
if (new_m_name.empty())
|
||||
continue;
|
||||
if (new_m_name != m->name) {
|
||||
m = design->module(new_m_name);
|
||||
blackbox_derivatives.insert(m);
|
||||
}
|
||||
}
|
||||
|
||||
auto old_connections = cell->connections();
|
||||
for (auto wire : m->wires()) {
|
||||
// Find ports of the module that aren't explicitly connected
|
||||
if (!wire->port_input && !wire->port_output)
|
||||
continue;
|
||||
if (old_connections.count(wire->name))
|
||||
continue;
|
||||
// Make sure a wire of correct name exists in the parent
|
||||
Wire* parent_wire = find_implicit_port_wire(module, cell, wire->name.str());
|
||||
|
||||
// Missing wires are OK when a default value is set
|
||||
if (!nodefaults && parent_wire == nullptr && defaults_db.count(cell->type) && defaults_db.at(cell->type).count(wire->name))
|
||||
continue;
|
||||
|
||||
if (parent_wire == nullptr)
|
||||
log_error("No matching wire for implicit port connection `%s' of cell %s.%s (%s).\n",
|
||||
RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
|
||||
if (parent_wire->width != wire->width)
|
||||
log_error("Width mismatch between wire (%d bits) and port (%d bits) for implicit port connection `%s' of cell %s.%s (%s).\n",
|
||||
parent_wire->width, wire->width,
|
||||
RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
|
||||
cell->setPort(wire->name, parent_wire);
|
||||
}
|
||||
cell->attributes.erase(ID(wildcard_port_conns));
|
||||
}
|
||||
}
|
||||
|
||||
if (!nodefaults)
|
||||
{
|
||||
for (auto module : design->modules())
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
|
@ -1000,9 +1069,6 @@ struct HierarchyPass : public Pass {
|
|||
}
|
||||
}
|
||||
|
||||
std::set<Module*> blackbox_derivatives;
|
||||
std::vector<Module*> design_modules = design->modules();
|
||||
|
||||
for (auto module : design_modules)
|
||||
{
|
||||
pool<Wire*> wand_wor_index;
|
||||
|
|
|
@ -15,6 +15,7 @@ OBJS += passes/opt/wreduce.o
|
|||
OBJS += passes/opt/opt_demorgan.o
|
||||
OBJS += passes/opt/rmports.o
|
||||
OBJS += passes/opt/opt_lut.o
|
||||
OBJS += passes/opt/opt_lut_ins.o
|
||||
OBJS += passes/opt/pmux2shiftx.o
|
||||
OBJS += passes/opt/muxpack.o
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
*
|
||||
* 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"
|
||||
#include "kernel/sigtools.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct OptLutInsPass : public Pass {
|
||||
OptLutInsPass() : Pass("opt_lut_ins", "discard unused LUT inputs") { }
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" opt_lut_ins [options] [selection]\n");
|
||||
log("\n");
|
||||
log("This pass removes unused inputs from LUT cells (that is, inputs that can not\n");
|
||||
log("influence the output signal given this LUT's value). While such LUTs cannot\n");
|
||||
log("be directly emitted by ABC, they can be a result of various post-ABC\n");
|
||||
log("transformations, such as mapping wide LUTs (not all sub-LUTs will use the\n");
|
||||
log("full set of inputs) or optimizations such as xilinx_dffopt.\n");
|
||||
log("\n");
|
||||
log(" -tech <technology>\n");
|
||||
log(" Instead of generic $lut cells, operate on LUT cells specific\n");
|
||||
log(" to the given technology. Valid values are: xilinx, ecp5, gowin.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
log_header(design, "Executing OPT_LUT_INS pass (discard unused LUT inputs).\n");
|
||||
string techname;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
if (args[argidx] == "-tech" && argidx+1 < args.size()) {
|
||||
techname = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
if (techname != "" && techname != "xilinx" && techname != "ecp5" && techname != "gowin")
|
||||
log_cmd_error("Unsupported technology: '%s'\n", techname.c_str());
|
||||
|
||||
for (auto module : design->selected_modules())
|
||||
{
|
||||
log("Optimizing LUTs in %s.\n", log_id(module));
|
||||
|
||||
std::vector<Cell *> remove_cells;
|
||||
// Gather LUTs.
|
||||
for (auto cell : module->selected_cells())
|
||||
{
|
||||
if (cell->get_bool_attribute(ID::keep))
|
||||
continue;
|
||||
Const lut;
|
||||
std::vector<SigBit> inputs;
|
||||
std::vector<SigBit> output;
|
||||
bool ignore_const = false;
|
||||
if (techname == "") {
|
||||
if (cell->type != ID($lut))
|
||||
continue;
|
||||
inputs = cell->getPort(ID::A).bits();
|
||||
output = cell->getPort(ID::Y);
|
||||
lut = cell->getParam(ID(LUT));
|
||||
} else if (techname == "xilinx" || techname == "gowin") {
|
||||
if (cell->type == ID(LUT1)) {
|
||||
inputs = {
|
||||
cell->getPort(ID(I0)),
|
||||
};
|
||||
} else if (cell->type == ID(LUT2)) {
|
||||
inputs = {
|
||||
cell->getPort(ID(I0)),
|
||||
cell->getPort(ID(I1)),
|
||||
};
|
||||
} else if (cell->type == ID(LUT3)) {
|
||||
inputs = {
|
||||
cell->getPort(ID(I0)),
|
||||
cell->getPort(ID(I1)),
|
||||
cell->getPort(ID(I2)),
|
||||
};
|
||||
} else if (cell->type == ID(LUT4)) {
|
||||
inputs = {
|
||||
cell->getPort(ID(I0)),
|
||||
cell->getPort(ID(I1)),
|
||||
cell->getPort(ID(I2)),
|
||||
cell->getPort(ID(I3)),
|
||||
};
|
||||
} else if (cell->type == ID(LUT5)) {
|
||||
inputs = {
|
||||
cell->getPort(ID(I0)),
|
||||
cell->getPort(ID(I1)),
|
||||
cell->getPort(ID(I2)),
|
||||
cell->getPort(ID(I3)),
|
||||
cell->getPort(ID(I4)),
|
||||
};
|
||||
} else if (cell->type == ID(LUT6)) {
|
||||
inputs = {
|
||||
cell->getPort(ID(I0)),
|
||||
cell->getPort(ID(I1)),
|
||||
cell->getPort(ID(I2)),
|
||||
cell->getPort(ID(I3)),
|
||||
cell->getPort(ID(I4)),
|
||||
cell->getPort(ID(I5)),
|
||||
};
|
||||
} else {
|
||||
// Not a LUT.
|
||||
continue;
|
||||
}
|
||||
lut = cell->getParam(ID(INIT));
|
||||
if (techname == "xilinx")
|
||||
output = cell->getPort(ID(O));
|
||||
else
|
||||
output = cell->getPort(ID(F));
|
||||
} else if (techname == "ecp5") {
|
||||
if (cell->type == ID(LUT4)) {
|
||||
inputs = {
|
||||
cell->getPort(ID::A),
|
||||
cell->getPort(ID::B),
|
||||
cell->getPort(ID(C)),
|
||||
cell->getPort(ID(D)),
|
||||
};
|
||||
lut = cell->getParam(ID(INIT));
|
||||
output = cell->getPort(ID(Z));
|
||||
ignore_const = true;
|
||||
} else {
|
||||
// Not a LUT.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
std::vector<int> swizzle;
|
||||
std::vector<SigBit> new_inputs;
|
||||
bool doit = false;
|
||||
for (int i = 0; i < GetSize(inputs); i++) {
|
||||
SigBit input = inputs[i];
|
||||
if (!input.wire) {
|
||||
if (input.data == State::S1)
|
||||
swizzle.push_back(-2);
|
||||
else
|
||||
swizzle.push_back(-1);
|
||||
// For ECP5, smaller LUTs are
|
||||
// implemented as LUT4s with
|
||||
// extra const inputs. Do not
|
||||
// consider that to be a reason
|
||||
// to redo a LUT.
|
||||
if (!ignore_const)
|
||||
doit = true;
|
||||
} else {
|
||||
bool redundant = true;
|
||||
for (int j = 0; j < GetSize(lut); j++) {
|
||||
if (lut[j] != lut[j ^ 1 << i])
|
||||
redundant = false;
|
||||
}
|
||||
if (redundant) {
|
||||
swizzle.push_back(-1);
|
||||
doit = true;
|
||||
} else {
|
||||
swizzle.push_back(GetSize(new_inputs));
|
||||
new_inputs.push_back(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!doit)
|
||||
continue;
|
||||
log(" Optimizing lut %s (%d -> %d)\n", log_id(cell), GetSize(inputs), GetSize(new_inputs));
|
||||
if (techname == "ecp5") {
|
||||
// Pad the LUT to 4 inputs, adding consts from the front.
|
||||
int extra = 4 - GetSize(new_inputs);
|
||||
log_assert(extra >= 0);
|
||||
if (extra) {
|
||||
for (int i = 0; i < extra; i++)
|
||||
new_inputs.insert(new_inputs.begin(), State::S0);
|
||||
for (auto &swz : swizzle)
|
||||
if (swz >= 0)
|
||||
swz += extra;
|
||||
}
|
||||
}
|
||||
Const new_lut(0, 1 << GetSize(new_inputs));
|
||||
for (int i = 0; i < GetSize(new_lut); i++) {
|
||||
int lidx = 0;
|
||||
for (int j = 0; j < GetSize(inputs); j++) {
|
||||
int val;
|
||||
if (swizzle[j] == -2) {
|
||||
val = 1;
|
||||
} else if (swizzle[j] == -1) {
|
||||
val = 0;
|
||||
} else {
|
||||
val = (i >> swizzle[j]) & 1;
|
||||
}
|
||||
lidx |= val << j;
|
||||
}
|
||||
new_lut[i] = lut[lidx];
|
||||
}
|
||||
// For ecp5, do not replace with a const driver — the nextpnr
|
||||
// packer requires a complete set of LUTs for wide LUT muxes.
|
||||
if (new_inputs.empty() && techname != "ecp5") {
|
||||
// const driver.
|
||||
remove_cells.push_back(cell);
|
||||
module->connect(output, new_lut[0]);
|
||||
} else {
|
||||
if (techname == "") {
|
||||
cell->setParam(ID(LUT), new_lut);
|
||||
cell->setParam(ID(WIDTH), GetSize(new_inputs));
|
||||
cell->setPort(ID::A, new_inputs);
|
||||
} else if (techname == "ecp5") {
|
||||
log_assert(GetSize(new_inputs) == 4);
|
||||
cell->setParam(ID(INIT), new_lut);
|
||||
cell->setPort(ID::A, new_inputs[0]);
|
||||
cell->setPort(ID::B, new_inputs[1]);
|
||||
cell->setPort(ID(C), new_inputs[2]);
|
||||
cell->setPort(ID(D), new_inputs[3]);
|
||||
} else {
|
||||
// xilinx, gowin
|
||||
cell->setParam(ID(INIT), new_lut);
|
||||
if (techname == "xilinx")
|
||||
log_assert(GetSize(new_inputs) <= 6);
|
||||
else
|
||||
log_assert(GetSize(new_inputs) <= 4);
|
||||
if (GetSize(new_inputs) == 1)
|
||||
cell->type = ID(LUT1);
|
||||
else if (GetSize(new_inputs) == 2)
|
||||
cell->type = ID(LUT2);
|
||||
else if (GetSize(new_inputs) == 3)
|
||||
cell->type = ID(LUT3);
|
||||
else if (GetSize(new_inputs) == 4)
|
||||
cell->type = ID(LUT4);
|
||||
else if (GetSize(new_inputs) == 5)
|
||||
cell->type = ID(LUT5);
|
||||
else if (GetSize(new_inputs) == 6)
|
||||
cell->type = ID(LUT6);
|
||||
else
|
||||
log_assert(0);
|
||||
cell->unsetPort(ID(I0));
|
||||
cell->unsetPort(ID(I1));
|
||||
cell->unsetPort(ID(I2));
|
||||
cell->unsetPort(ID(I3));
|
||||
cell->unsetPort(ID(I4));
|
||||
cell->unsetPort(ID(I5));
|
||||
cell->setPort(ID(I0), new_inputs[0]);
|
||||
if (GetSize(new_inputs) >= 2)
|
||||
cell->setPort(ID(I1), new_inputs[1]);
|
||||
if (GetSize(new_inputs) >= 3)
|
||||
cell->setPort(ID(I2), new_inputs[2]);
|
||||
if (GetSize(new_inputs) >= 4)
|
||||
cell->setPort(ID(I3), new_inputs[3]);
|
||||
if (GetSize(new_inputs) >= 5)
|
||||
cell->setPort(ID(I4), new_inputs[4]);
|
||||
if (GetSize(new_inputs) >= 6)
|
||||
cell->setPort(ID(I5), new_inputs[5]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto cell : remove_cells)
|
||||
module->remove(cell);
|
||||
}
|
||||
}
|
||||
} XilinxDffOptPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
@ -44,9 +44,10 @@ struct OptReduceWorker
|
|||
cells.erase(cell);
|
||||
|
||||
RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
|
||||
sig_a.sort_and_unify();
|
||||
pool<RTLIL::SigBit> new_sig_a_bits;
|
||||
|
||||
for (auto &bit : sig_a.to_sigbit_set())
|
||||
for (auto &bit : sig_a)
|
||||
{
|
||||
if (bit == RTLIL::State::S0) {
|
||||
if (cell->type == ID($reduce_and)) {
|
||||
|
@ -86,6 +87,7 @@ struct OptReduceWorker
|
|||
}
|
||||
|
||||
RTLIL::SigSpec new_sig_a(new_sig_a_bits);
|
||||
new_sig_a.sort_and_unify();
|
||||
|
||||
if (new_sig_a != sig_a || sig_a.size() != cell->getPort(ID::A).size()) {
|
||||
log(" New input vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_a));
|
||||
|
@ -235,7 +237,6 @@ struct OptReduceWorker
|
|||
log(" New connections: %s = %s\n", log_signal(old_sig_conn.first), log_signal(old_sig_conn.second));
|
||||
|
||||
module->connect(old_sig_conn);
|
||||
module->check();
|
||||
|
||||
did_something = true;
|
||||
total_count++;
|
||||
|
@ -324,6 +325,8 @@ struct OptReduceWorker
|
|||
opt_mux(cell);
|
||||
}
|
||||
}
|
||||
|
||||
module->check();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -42,11 +42,19 @@ void create_ice40_wrapcarry(ice40_wrapcarry_pm &pm)
|
|||
|
||||
cell->setPort("\\A", st.carry->getPort("\\I0"));
|
||||
cell->setPort("\\B", st.carry->getPort("\\I1"));
|
||||
cell->setPort("\\CI", st.carry->getPort("\\CI"));
|
||||
auto CI = st.carry->getPort("\\CI");
|
||||
cell->setPort("\\CI", CI);
|
||||
cell->setPort("\\CO", st.carry->getPort("\\CO"));
|
||||
|
||||
cell->setPort("\\I0", st.lut->getPort("\\I0"));
|
||||
cell->setPort("\\I3", st.lut->getPort("\\I3"));
|
||||
auto I3 = st.lut->getPort("\\I3");
|
||||
if (pm.sigmap(CI) == pm.sigmap(I3)) {
|
||||
cell->setParam("\\I3_IS_CI", State::S1);
|
||||
I3 = State::Sx;
|
||||
}
|
||||
else
|
||||
cell->setParam("\\I3_IS_CI", State::S0);
|
||||
cell->setPort("\\I3", I3);
|
||||
cell->setPort("\\O", st.lut->getPort("\\O"));
|
||||
cell->setParam("\\LUT", st.lut->getParam("\\LUT_INIT"));
|
||||
|
||||
|
@ -118,7 +126,8 @@ struct Ice40WrapCarryPass : public Pass {
|
|||
auto lut = module->addCell(lut_name, ID($lut));
|
||||
lut->setParam(ID(WIDTH), 4);
|
||||
lut->setParam(ID(LUT), cell->getParam(ID(LUT)));
|
||||
lut->setPort(ID(A), {cell->getPort(ID(I0)), cell->getPort(ID(A)), cell->getPort(ID(B)), cell->getPort(ID(I3)) });
|
||||
auto I3 = cell->getPort(cell->getParam(ID(I3_IS_CI)).as_bool() ? ID(CI) : ID(I3));
|
||||
lut->setPort(ID(A), { I3, cell->getPort(ID(B)), cell->getPort(ID(A)), cell->getPort(ID(I0)) });
|
||||
lut->setPort(ID(Y), cell->getPort(ID(O)));
|
||||
|
||||
Const src;
|
||||
|
|
|
@ -767,6 +767,9 @@ struct XilinxDspPass : public Pass {
|
|||
log("to a maximum length of 20 cells, corresponding to the smallest Xilinx 7 Series\n");
|
||||
log("device.\n");
|
||||
log("\n");
|
||||
log("This pass is a no-op if the scratchpad variable 'xilinx_dsp.multonly' is set\n");
|
||||
log("to 1.\n");
|
||||
log("\n");
|
||||
log("\n");
|
||||
log("Experimental feature: addition/subtractions less than 12 or 24 bits with the\n");
|
||||
log("'(* use_dsp=\"simd\" *)' attribute attached to the output wire or attached to\n");
|
||||
|
@ -805,6 +808,10 @@ struct XilinxDspPass : public Pass {
|
|||
family = "xcu";
|
||||
|
||||
for (auto module : design->selected_modules()) {
|
||||
|
||||
if (design->scratchpad_get_bool("xilinx_dsp.multonly"))
|
||||
continue;
|
||||
|
||||
// Experimental feature: pack $add/$sub cells with
|
||||
// (* use_dsp48="simd" *) into DSP48E1's using its
|
||||
// SIMD feature
|
||||
|
|
|
@ -214,14 +214,38 @@ struct Clk2fflogicPass : public Pass {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (cell->type.in("$dff", "$adff", "$dffsr"))
|
||||
bool word_dff = cell->type.in("$dff", "$adff", "$dffsr");
|
||||
if (word_dff || cell->type.in(ID($_DFF_N_), ID($_DFF_P_),
|
||||
ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
|
||||
ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_),
|
||||
ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
|
||||
ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
|
||||
{
|
||||
bool clkpol = cell->parameters["\\CLK_POLARITY"].as_bool();
|
||||
bool clkpol;
|
||||
SigSpec clk;
|
||||
if (word_dff) {
|
||||
clkpol = cell->parameters["\\CLK_POLARITY"].as_bool();
|
||||
clk = cell->getPort("\\CLK");
|
||||
}
|
||||
else {
|
||||
if (cell->type.in(ID($_DFF_P_), ID($_DFF_N_),
|
||||
ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
|
||||
ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_)))
|
||||
clkpol = cell->type[6] == 'P';
|
||||
else if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
|
||||
ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
|
||||
clkpol = cell->type[8] == 'P';
|
||||
else log_abort();
|
||||
clk = cell->getPort("\\C");
|
||||
}
|
||||
|
||||
SigSpec clk = cell->getPort("\\CLK");
|
||||
Wire *past_clk = module->addWire(NEW_ID);
|
||||
past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0;
|
||||
module->addFf(NEW_ID, clk, past_clk);
|
||||
|
||||
if (word_dff)
|
||||
module->addFf(NEW_ID, clk, past_clk);
|
||||
else
|
||||
module->addFfGate(NEW_ID, clk, past_clk);
|
||||
|
||||
SigSpec sig_d = cell->getPort("\\D");
|
||||
SigSpec sig_q = cell->getPort("\\Q");
|
||||
|
@ -244,8 +268,14 @@ struct Clk2fflogicPass : public Pass {
|
|||
|
||||
Wire *past_d = module->addWire(NEW_ID, GetSize(sig_d));
|
||||
Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
|
||||
module->addFf(NEW_ID, sig_d, past_d);
|
||||
module->addFf(NEW_ID, sig_q, past_q);
|
||||
if (word_dff) {
|
||||
module->addFf(NEW_ID, sig_d, past_d);
|
||||
module->addFf(NEW_ID, sig_q, past_q);
|
||||
}
|
||||
else {
|
||||
module->addFfGate(NEW_ID, sig_d, past_d);
|
||||
module->addFfGate(NEW_ID, sig_q, past_q);
|
||||
}
|
||||
|
||||
if (cell->type == "$adff")
|
||||
{
|
||||
|
@ -266,6 +296,26 @@ struct Clk2fflogicPass : public Pass {
|
|||
module->addMux(NEW_ID, rstval, qval, arst, sig_q);
|
||||
}
|
||||
else
|
||||
if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
|
||||
ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_)))
|
||||
{
|
||||
SigSpec arst = cell->getPort("\\R");
|
||||
SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
|
||||
SigBit rstval = (cell->type[8] == '1');
|
||||
|
||||
Wire *past_arst = module->addWire(NEW_ID);
|
||||
module->addFfGate(NEW_ID, arst, past_arst);
|
||||
if (cell->type[7] == 'P')
|
||||
arst = module->OrGate(NEW_ID, arst, past_arst);
|
||||
else
|
||||
arst = module->AndGate(NEW_ID, arst, past_arst);
|
||||
|
||||
if (cell->type[7] == 'P')
|
||||
module->addMuxGate(NEW_ID, qval, rstval, arst, sig_q);
|
||||
else
|
||||
module->addMuxGate(NEW_ID, rstval, qval, arst, sig_q);
|
||||
}
|
||||
else
|
||||
if (cell->type == "$dffsr")
|
||||
{
|
||||
SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
|
||||
|
@ -282,9 +332,30 @@ struct Clk2fflogicPass : public Pass {
|
|||
module->addAnd(NEW_ID, qval, clrval, sig_q);
|
||||
}
|
||||
else
|
||||
if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
|
||||
ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
|
||||
{
|
||||
SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
|
||||
SigSpec setval = cell->getPort("\\S");
|
||||
SigSpec clrval = cell->getPort("\\R");
|
||||
|
||||
if (cell->type[9] != 'P')
|
||||
setval = module->Not(NEW_ID, setval);
|
||||
|
||||
if (cell->type[10] == 'P')
|
||||
clrval = module->Not(NEW_ID, clrval);
|
||||
|
||||
qval = module->OrGate(NEW_ID, qval, setval);
|
||||
module->addAndGate(NEW_ID, qval, clrval, sig_q);
|
||||
}
|
||||
else if (cell->type == "$dff")
|
||||
{
|
||||
module->addMux(NEW_ID, past_q, past_d, clock_edge, sig_q);
|
||||
}
|
||||
else
|
||||
{
|
||||
module->addMuxGate(NEW_ID, past_q, past_d, clock_edge, sig_q);
|
||||
}
|
||||
|
||||
Const initval;
|
||||
bool assign_initval = false;
|
||||
|
|
|
@ -269,7 +269,8 @@ struct SatHelper
|
|||
for (int i = 0; i < lhs.size(); i++) {
|
||||
RTLIL::SigSpec bit = lhs.extract(i, 1);
|
||||
if (rhs[i] == State::Sx || !satgen.initial_state.check_all(bit)) {
|
||||
removed_bits.append(bit);
|
||||
if (rhs[i] != State::Sx)
|
||||
removed_bits.append(bit);
|
||||
lhs.remove(i, 1);
|
||||
rhs.remove(i, 1);
|
||||
i--;
|
||||
|
|
|
@ -8,9 +8,12 @@ OBJS += passes/techmap/libparse.o
|
|||
ifeq ($(ENABLE_ABC),1)
|
||||
OBJS += passes/techmap/abc.o
|
||||
OBJS += passes/techmap/abc9.o
|
||||
OBJS += passes/techmap/abc9_exe.o
|
||||
OBJS += passes/techmap/abc9_ops.o
|
||||
ifneq ($(ABCEXTERNAL),)
|
||||
passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
||||
passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
||||
passes/techmap/abc9_exe.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,530 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* 2019 Eddie Hung <eddie@fpgeh.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
// [[CITE]] ABC
|
||||
// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
|
||||
// http://www.eecs.berkeley.edu/~alanmi/abc/
|
||||
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/log.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
#endif
|
||||
|
||||
#ifdef YOSYS_LINK_ABC
|
||||
extern "C" int Abc_RealMain(int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
std::string fold_abc9_cmd(std::string str)
|
||||
{
|
||||
std::string token, new_str = " ";
|
||||
int char_counter = 10;
|
||||
|
||||
for (size_t i = 0; i <= str.size(); i++) {
|
||||
if (i < str.size())
|
||||
token += str[i];
|
||||
if (i == str.size() || str[i] == ';') {
|
||||
if (char_counter + token.size() > 75)
|
||||
new_str += "\n ", char_counter = 14;
|
||||
new_str += token, char_counter += token.size();
|
||||
token.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
std::string add_echos_to_abc9_cmd(std::string str)
|
||||
{
|
||||
std::string new_str, token;
|
||||
for (size_t i = 0; i < str.size(); i++) {
|
||||
token += str[i];
|
||||
if (str[i] == ';') {
|
||||
while (i+1 < str.size() && str[i+1] == ' ')
|
||||
i++;
|
||||
new_str += "echo + " + token + " " + token + " ";
|
||||
token.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!token.empty()) {
|
||||
if (!new_str.empty())
|
||||
new_str += "echo + " + token + "; ";
|
||||
new_str += token;
|
||||
}
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir)
|
||||
{
|
||||
if (show_tempdir)
|
||||
return text;
|
||||
|
||||
while (1) {
|
||||
size_t pos = text.find(tempdir_name);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(tempdir_name));
|
||||
}
|
||||
|
||||
std::string selfdir_name = proc_self_dirname();
|
||||
if (selfdir_name != "/") {
|
||||
while (1) {
|
||||
size_t pos = text.find(selfdir_name);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name));
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
struct abc9_output_filter
|
||||
{
|
||||
bool got_cr;
|
||||
int escape_seq_state;
|
||||
std::string linebuf;
|
||||
std::string tempdir_name;
|
||||
bool show_tempdir;
|
||||
|
||||
abc9_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir)
|
||||
{
|
||||
got_cr = false;
|
||||
escape_seq_state = 0;
|
||||
}
|
||||
|
||||
void next_char(char ch)
|
||||
{
|
||||
if (escape_seq_state == 0 && ch == '\033') {
|
||||
escape_seq_state = 1;
|
||||
return;
|
||||
}
|
||||
if (escape_seq_state == 1) {
|
||||
escape_seq_state = ch == '[' ? 2 : 0;
|
||||
return;
|
||||
}
|
||||
if (escape_seq_state == 2) {
|
||||
if ((ch < '0' || '9' < ch) && ch != ';')
|
||||
escape_seq_state = 0;
|
||||
return;
|
||||
}
|
||||
escape_seq_state = 0;
|
||||
if (ch == '\r') {
|
||||
got_cr = true;
|
||||
return;
|
||||
}
|
||||
if (ch == '\n') {
|
||||
log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str());
|
||||
got_cr = false, linebuf.clear();
|
||||
return;
|
||||
}
|
||||
if (got_cr)
|
||||
got_cr = false, linebuf.clear();
|
||||
linebuf += ch;
|
||||
}
|
||||
|
||||
void next_line(const std::string &line)
|
||||
{
|
||||
//int pi, po;
|
||||
//if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) {
|
||||
// log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n",
|
||||
// pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???",
|
||||
// po, po_map.count(po) ? po_map.at(po).c_str() : "???");
|
||||
// return;
|
||||
//}
|
||||
|
||||
for (char ch : line)
|
||||
next_char(ch);
|
||||
}
|
||||
};
|
||||
|
||||
void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe_file,
|
||||
vector<int> lut_costs, bool dff_mode, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
|
||||
bool show_tempdir, std::string box_file, std::string lut_file,
|
||||
std::string wire_delay, std::string tempdir_name
|
||||
)
|
||||
{
|
||||
std::string abc9_script;
|
||||
|
||||
if (!lut_costs.empty())
|
||||
abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
|
||||
else if (!lut_file.empty())
|
||||
abc9_script += stringf("read_lut %s; ", lut_file.c_str());
|
||||
else
|
||||
log_abort();
|
||||
|
||||
log_assert(!box_file.empty());
|
||||
abc9_script += stringf("read_box %s; ", box_file.c_str());
|
||||
abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str());
|
||||
|
||||
if (!script_file.empty()) {
|
||||
if (script_file[0] == '+') {
|
||||
for (size_t i = 1; i < script_file.size(); i++)
|
||||
if (script_file[i] == '\'')
|
||||
abc9_script += "'\\''";
|
||||
else if (script_file[i] == ',')
|
||||
abc9_script += " ";
|
||||
else
|
||||
abc9_script += script_file[i];
|
||||
} else
|
||||
abc9_script += stringf("source %s", script_file.c_str());
|
||||
} else if (!lut_costs.empty() || !lut_file.empty()) {
|
||||
abc9_script += fast_mode ? RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)
|
||||
: RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos);
|
||||
} else
|
||||
log_abort();
|
||||
|
||||
for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos))
|
||||
abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3);
|
||||
|
||||
//for (size_t pos = abc9_script.find("{S}"); pos != std::string::npos; pos = abc9_script.find("{S}", pos))
|
||||
// abc9_script = abc9_script.substr(0, pos) + lutin_shared + abc9_script.substr(pos+3);
|
||||
|
||||
for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos))
|
||||
abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3);
|
||||
|
||||
std::string C;
|
||||
if (design->scratchpad.count("abc9.if.C"))
|
||||
C = "-C " + design->scratchpad_get_string("abc9.if.C");
|
||||
for (size_t pos = abc9_script.find("{C}"); pos != std::string::npos; pos = abc9_script.find("{C}", pos))
|
||||
abc9_script = abc9_script.substr(0, pos) + C + abc9_script.substr(pos+3);
|
||||
|
||||
std::string R;
|
||||
if (design->scratchpad.count("abc9.if.R"))
|
||||
R = "-R " + design->scratchpad_get_string("abc9.if.R");
|
||||
for (size_t pos = abc9_script.find("{R}"); pos != std::string::npos; pos = abc9_script.find("{R}", pos))
|
||||
abc9_script = abc9_script.substr(0, pos) + R + abc9_script.substr(pos+3);
|
||||
|
||||
abc9_script += stringf("; &ps -l; &write -n %s/output.aig", tempdir_name.c_str());
|
||||
if (design->scratchpad_get_bool("abc9.verify")) {
|
||||
if (dff_mode)
|
||||
abc9_script += "; verify -s";
|
||||
else
|
||||
abc9_script += "; verify";
|
||||
}
|
||||
abc9_script += "; time";
|
||||
abc9_script = add_echos_to_abc9_cmd(abc9_script);
|
||||
|
||||
for (size_t i = 0; i+1 < abc9_script.size(); i++)
|
||||
if (abc9_script[i] == ';' && abc9_script[i+1] == ' ')
|
||||
abc9_script[i+1] = '\n';
|
||||
|
||||
FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt");
|
||||
fprintf(f, "%s\n", abc9_script.c_str());
|
||||
fclose(f);
|
||||
|
||||
std::string buffer;
|
||||
|
||||
log_header(design, "Executing ABC9.\n");
|
||||
|
||||
if (!lut_costs.empty()) {
|
||||
buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str());
|
||||
f = fopen(buffer.c_str(), "wt");
|
||||
if (f == NULL)
|
||||
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
|
||||
for (int i = 0; i < GetSize(lut_costs); i++)
|
||||
fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i));
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
|
||||
log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
|
||||
|
||||
#ifndef YOSYS_LINK_ABC
|
||||
abc9_output_filter filt(tempdir_name, show_tempdir);
|
||||
int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1));
|
||||
#else
|
||||
// These needs to be mutable, supposedly due to getopt
|
||||
char *abc9_argv[5];
|
||||
string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str());
|
||||
abc9_argv[0] = strdup(exe_file.c_str());
|
||||
abc9_argv[1] = strdup("-s");
|
||||
abc9_argv[2] = strdup("-f");
|
||||
abc9_argv[3] = strdup(tmp_script_name.c_str());
|
||||
abc9_argv[4] = 0;
|
||||
int ret = Abc_RealMain(4, abc9_argv);
|
||||
free(abc9_argv[0]);
|
||||
free(abc9_argv[1]);
|
||||
free(abc9_argv[2]);
|
||||
free(abc9_argv[3]);
|
||||
#endif
|
||||
if (ret != 0)
|
||||
log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
|
||||
}
|
||||
|
||||
struct Abc9ExePass : public Pass {
|
||||
Abc9ExePass() : Pass("abc9_exe", "use ABC9 for technology mapping") { }
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" abc9_exe [options]\n");
|
||||
log("\n");
|
||||
log(" \n");
|
||||
log("This pass uses the ABC tool [1] for technology mapping of the top module\n");
|
||||
log("(according to the (* top *) attribute or if only one module is currently selected)\n");
|
||||
log("to a target FPGA architecture.\n");
|
||||
log("\n");
|
||||
log(" -exe <command>\n");
|
||||
#ifdef ABCEXTERNAL
|
||||
log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
|
||||
#else
|
||||
log(" use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n");
|
||||
#endif
|
||||
log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n");
|
||||
log("\n");
|
||||
log(" -script <file>\n");
|
||||
log(" use the specified ABC script file instead of the default script.\n");
|
||||
log("\n");
|
||||
log(" if <file> starts with a plus sign (+), then the rest of the filename\n");
|
||||
log(" string is interpreted as the command string to be passed to ABC. The\n");
|
||||
log(" leading plus sign is removed and all commas (,) in the string are\n");
|
||||
log(" replaced with blanks before the string is passed to ABC.\n");
|
||||
log("\n");
|
||||
log(" if no -script parameter is given, the following scripts are used:\n");
|
||||
log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos)).c_str());
|
||||
log("\n");
|
||||
log(" -fast\n");
|
||||
log(" use different default scripts that are slightly faster (at the cost\n");
|
||||
log(" of output quality):\n");
|
||||
log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)).c_str());
|
||||
log("\n");
|
||||
log(" -D <picoseconds>\n");
|
||||
log(" set delay target. the string {D} in the default scripts above is\n");
|
||||
log(" replaced by this option when used, and an empty string otherwise\n");
|
||||
log(" (indicating best possible delay).\n");
|
||||
log("\n");
|
||||
// log(" -S <num>\n");
|
||||
// log(" maximum number of LUT inputs shared.\n");
|
||||
// log(" (replaces {S} in the default scripts above, default: -S 1)\n");
|
||||
// log("\n");
|
||||
log(" -lut <width>\n");
|
||||
log(" generate netlist using luts of (max) the specified width.\n");
|
||||
log("\n");
|
||||
log(" -lut <w1>:<w2>\n");
|
||||
log(" generate netlist using luts of (max) the specified width <w2>. All\n");
|
||||
log(" luts with width <= <w1> have constant cost. for luts larger than <w1>\n");
|
||||
log(" the area cost doubles with each additional input bit. the delay cost\n");
|
||||
log(" is still constant for all lut widths.\n");
|
||||
log("\n");
|
||||
log(" -lut <file>\n");
|
||||
log(" pass this file with lut library to ABC.\n");
|
||||
log("\n");
|
||||
log(" -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..\n");
|
||||
log(" generate netlist using luts. Use the specified costs for luts with 1,\n");
|
||||
log(" 2, 3, .. inputs.\n");
|
||||
log("\n");
|
||||
log(" -showtmp\n");
|
||||
log(" print the temp dir name in log. usually this is suppressed so that the\n");
|
||||
log(" command output is identical across runs.\n");
|
||||
log("\n");
|
||||
log(" -box <file>\n");
|
||||
log(" pass this file with box library to ABC.\n");
|
||||
log("\n");
|
||||
log(" -cwd <dir>\n");
|
||||
log(" use this as the current working directory, inside which the 'input.xaig'\n");
|
||||
log(" file is expected. temporary files will be created in this directory, and\n");
|
||||
log(" the mapped result will be written to 'output.aig'.\n");
|
||||
log("\n");
|
||||
log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
|
||||
log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
|
||||
log("ABC on logic snippets extracted from your design. You will not get any useful\n");
|
||||
log("output when passing an ABC script that writes a file. Instead write your full\n");
|
||||
log("design as BLIF file with write_blif and then load that into ABC externally if\n");
|
||||
log("you want to use ABC to convert your design into another format.\n");
|
||||
log("\n");
|
||||
log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
log_header(design, "Executing ABC9_MAP pass (technology mapping using ABC9).\n");
|
||||
|
||||
#ifdef ABCEXTERNAL
|
||||
std::string exe_file = ABCEXTERNAL;
|
||||
#else
|
||||
std::string exe_file = proc_self_dirname() + "yosys-abc";
|
||||
#endif
|
||||
std::string script_file, clk_str, box_file, lut_file;
|
||||
std::string delay_target, lutin_shared = "-S 1", wire_delay;
|
||||
std::string tempdir_name;
|
||||
bool fast_mode = false, dff_mode = false;
|
||||
bool show_tempdir = false;
|
||||
vector<int> lut_costs;
|
||||
|
||||
#if 0
|
||||
cleanup = false;
|
||||
show_tempdir = true;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef ABCEXTERNAL
|
||||
if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe"))
|
||||
exe_file = proc_self_dirname() + "..\\yosys-abc";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
std::string lut_arg, luts_arg;
|
||||
exe_file = design->scratchpad_get_string("abc9.exe", exe_file /* inherit default value if not set */);
|
||||
script_file = design->scratchpad_get_string("abc9.script", script_file);
|
||||
if (design->scratchpad.count("abc9.D")) {
|
||||
delay_target = "-D " + design->scratchpad_get_string("abc9.D");
|
||||
}
|
||||
lut_arg = design->scratchpad_get_string("abc9.lut", lut_arg);
|
||||
luts_arg = design->scratchpad_get_string("abc9.luts", luts_arg);
|
||||
fast_mode = design->scratchpad_get_bool("abc9.fast", fast_mode);
|
||||
dff_mode = design->scratchpad_get_bool("abc9.dff", dff_mode);
|
||||
show_tempdir = design->scratchpad_get_bool("abc9.showtmp", show_tempdir);
|
||||
box_file = design->scratchpad_get_string("abc9.box", box_file);
|
||||
if (design->scratchpad.count("abc9.W")) {
|
||||
wire_delay = "-W " + design->scratchpad_get_string("abc9.W");
|
||||
}
|
||||
|
||||
size_t argidx;
|
||||
char pwd [PATH_MAX];
|
||||
if (!getcwd(pwd, sizeof(pwd))) {
|
||||
log_cmd_error("getcwd failed: %s\n", strerror(errno));
|
||||
log_abort();
|
||||
}
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
std::string arg = args[argidx];
|
||||
if (arg == "-exe" && argidx+1 < args.size()) {
|
||||
exe_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-script" && argidx+1 < args.size()) {
|
||||
script_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-D" && argidx+1 < args.size()) {
|
||||
delay_target = "-D " + args[++argidx];
|
||||
continue;
|
||||
}
|
||||
//if (arg == "-S" && argidx+1 < args.size()) {
|
||||
// lutin_shared = "-S " + args[++argidx];
|
||||
// continue;
|
||||
//}
|
||||
if (arg == "-lut" && argidx+1 < args.size()) {
|
||||
lut_arg = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-luts" && argidx+1 < args.size()) {
|
||||
lut_arg = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-fast") {
|
||||
fast_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-dff") {
|
||||
dff_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-showtmp") {
|
||||
show_tempdir = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-box" && argidx+1 < args.size()) {
|
||||
box_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-W" && argidx+1 < args.size()) {
|
||||
wire_delay = "-W " + args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-cwd" && argidx+1 < args.size()) {
|
||||
tempdir_name = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
rewrite_filename(script_file);
|
||||
if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
|
||||
script_file = std::string(pwd) + "/" + script_file;
|
||||
|
||||
// handle -lut / -luts args
|
||||
if (!lut_arg.empty()) {
|
||||
string arg = lut_arg;
|
||||
if (arg.find_first_not_of("0123456789:") == std::string::npos) {
|
||||
size_t pos = arg.find_first_of(':');
|
||||
int lut_mode = 0, lut_mode2 = 0;
|
||||
if (pos != string::npos) {
|
||||
lut_mode = atoi(arg.substr(0, pos).c_str());
|
||||
lut_mode2 = atoi(arg.substr(pos+1).c_str());
|
||||
} else {
|
||||
lut_mode = atoi(arg.c_str());
|
||||
lut_mode2 = lut_mode;
|
||||
}
|
||||
lut_costs.clear();
|
||||
for (int i = 0; i < lut_mode; i++)
|
||||
lut_costs.push_back(1);
|
||||
for (int i = lut_mode; i < lut_mode2; i++)
|
||||
lut_costs.push_back(2 << (i - lut_mode));
|
||||
}
|
||||
else {
|
||||
lut_file = arg;
|
||||
rewrite_filename(lut_file);
|
||||
if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+')
|
||||
lut_file = std::string(pwd) + "/" + lut_file;
|
||||
}
|
||||
}
|
||||
if (!luts_arg.empty()) {
|
||||
lut_costs.clear();
|
||||
for (auto &tok : split_tokens(luts_arg, ",")) {
|
||||
auto parts = split_tokens(tok, ":");
|
||||
if (GetSize(parts) == 0 && !lut_costs.empty())
|
||||
lut_costs.push_back(lut_costs.back());
|
||||
else if (GetSize(parts) == 1)
|
||||
lut_costs.push_back(atoi(parts.at(0).c_str()));
|
||||
else if (GetSize(parts) == 2)
|
||||
while (GetSize(lut_costs) < atoi(parts.at(0).c_str()))
|
||||
lut_costs.push_back(atoi(parts.at(1).c_str()));
|
||||
else
|
||||
log_cmd_error("Invalid -luts syntax.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (box_file.empty())
|
||||
log_cmd_error("abc9_exe '-box' option is mandatory.\n");
|
||||
|
||||
rewrite_filename(box_file);
|
||||
if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+')
|
||||
box_file = std::string(pwd) + "/" + box_file;
|
||||
|
||||
if (tempdir_name.empty())
|
||||
log_cmd_error("abc9_exe '-cwd' option is mandatory.\n");
|
||||
|
||||
|
||||
abc9_module(design, script_file, exe_file, lut_costs, dff_mode,
|
||||
delay_target, lutin_shared, fast_mode, show_tempdir,
|
||||
box_file, lut_file, wire_delay, tempdir_name);
|
||||
}
|
||||
} Abc9ExePass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
File diff suppressed because it is too large
Load Diff
|
@ -86,6 +86,7 @@ struct TribufWorker {
|
|||
cell->unsetPort(ID(S));
|
||||
cell->type = tri_type;
|
||||
tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell);
|
||||
module->design->scratchpad_set_bool("tribuf.added_something", true);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -95,6 +96,7 @@ struct TribufWorker {
|
|||
cell->unsetPort(ID(S));
|
||||
cell->type = tri_type;
|
||||
tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell);
|
||||
module->design->scratchpad_set_bool("tribuf.added_something", true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -130,8 +132,10 @@ struct TribufWorker {
|
|||
|
||||
if (no_tribuf)
|
||||
module->connect(it.first, muxout);
|
||||
else
|
||||
else {
|
||||
module->addTribuf(NEW_ID, muxout, module->ReduceOr(NEW_ID, pmux_s), it.first);
|
||||
module->design->scratchpad_set_bool("tribuf.added_something", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,4 +29,3 @@ $(eval $(call add_share_file,share,techlibs/common/gate2lut.v))
|
|||
$(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/dummy.box))
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
(dummy) 1 0 0 0
|
|
@ -73,102 +73,80 @@ module \$lut (A, Y);
|
|||
input [WIDTH-1:0] A;
|
||||
output Y;
|
||||
|
||||
// Need to swap input ordering, and fix init accordingly,
|
||||
// to match ABC's expectation of LUT inputs in non-decreasing
|
||||
// delay order
|
||||
localparam P_WIDTH = WIDTH < 4 ? 4 : WIDTH;
|
||||
function [P_WIDTH-1:0] permute_index;
|
||||
input [P_WIDTH-1:0] i;
|
||||
integer j;
|
||||
begin
|
||||
permute_index = 0;
|
||||
for (j = 0; j < P_WIDTH; j = j + 1)
|
||||
permute_index[P_WIDTH-1 - j] = i[j];
|
||||
end
|
||||
endfunction
|
||||
|
||||
function [2**P_WIDTH-1:0] permute_init;
|
||||
integer i;
|
||||
begin
|
||||
permute_init = 0;
|
||||
for (i = 0; i < 2**P_WIDTH; i = i + 1)
|
||||
permute_init[i] = LUT[permute_index(i)];
|
||||
end
|
||||
endfunction
|
||||
|
||||
parameter [2**P_WIDTH-1:0] P_LUT = permute_init();
|
||||
|
||||
generate
|
||||
if (WIDTH == 1) begin
|
||||
LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
|
||||
localparam [15:0] INIT = {{8{LUT[1]}}, {8{LUT[0]}}};
|
||||
LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y),
|
||||
.A(1'b0), .B(1'b0), .C(1'b0), .D(A[0]));
|
||||
end else
|
||||
if (WIDTH == 2) begin
|
||||
LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
|
||||
.A(1'b0), .B(1'b0), .C(A[1]), .D(A[0]));
|
||||
localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[2]}}, {4{LUT[1]}}, {4{LUT[0]}}};
|
||||
LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y),
|
||||
.A(1'b0), .B(1'b0), .C(A[0]), .D(A[1]));
|
||||
end else
|
||||
if (WIDTH == 3) begin
|
||||
LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
|
||||
.A(1'b0), .B(A[2]), .C(A[1]), .D(A[0]));
|
||||
localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[6]}}, {2{LUT[5]}}, {2{LUT[4]}}, {2{LUT[3]}}, {2{LUT[2]}}, {2{LUT[1]}}, {2{LUT[0]}}};
|
||||
LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y),
|
||||
.A(1'b0), .B(A[0]), .C(A[1]), .D(A[2]));
|
||||
end else
|
||||
if (WIDTH == 4) begin
|
||||
LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
|
||||
.A(A[3]), .B(A[2]), .C(A[1]), .D(A[0]));
|
||||
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
`ifndef NO_PFUMUX
|
||||
end else
|
||||
if (WIDTH == 5) begin
|
||||
wire f0, f1;
|
||||
LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
|
||||
.A(A[4]), .B(A[3]), .C(A[2]), .D(A[1]));
|
||||
LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
|
||||
.A(A[4]), .B(A[3]), .C(A[2]), .D(A[1]));
|
||||
PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[0]), .Z(Y));
|
||||
LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(Y));
|
||||
end else
|
||||
if (WIDTH == 6) begin
|
||||
wire f0, f1, f2, f3, g0, g1;
|
||||
LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
|
||||
.A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
|
||||
LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
|
||||
.A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
|
||||
LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
|
||||
LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2),
|
||||
.A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
|
||||
LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3),
|
||||
.A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
|
||||
LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
|
||||
PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[1]), .Z(g0));
|
||||
PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[1]), .Z(g1));
|
||||
L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[0]), .Z(Y));
|
||||
PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0));
|
||||
PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1));
|
||||
L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[5]), .Z(Y));
|
||||
end else
|
||||
if (WIDTH == 7) begin
|
||||
wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1;
|
||||
LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
|
||||
.A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
|
||||
LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
|
||||
.A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
|
||||
LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
|
||||
LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2),
|
||||
.A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
|
||||
LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3),
|
||||
.A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
|
||||
LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
|
||||
LUT4 #(.INIT(P_LUT[79:64])) lut4 (.Z(f4),
|
||||
.A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
|
||||
LUT4 #(.INIT(P_LUT[95:80])) lut5 (.Z(f5),
|
||||
.A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
|
||||
LUT4 #(.INIT(LUT[79:64])) lut4 (.Z(f4),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
LUT4 #(.INIT(LUT[95:80])) lut5 (.Z(f5),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
|
||||
LUT4 #(.INIT(P_LUT[111: 96])) lut6 (.Z(f6),
|
||||
.A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
|
||||
LUT4 #(.INIT(P_LUT[127:112])) lut7 (.Z(f7),
|
||||
.A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
|
||||
LUT4 #(.INIT(LUT[111: 96])) lut6 (.Z(f6),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
LUT4 #(.INIT(LUT[127:112])) lut7 (.Z(f7),
|
||||
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
|
||||
PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[2]), .Z(g0));
|
||||
PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[2]), .Z(g1));
|
||||
PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[2]), .Z(g2));
|
||||
PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[2]), .Z(g3));
|
||||
L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[1]), .Z(h0));
|
||||
L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[1]), .Z(h1));
|
||||
L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[0]), .Z(Y));
|
||||
PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0));
|
||||
PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1));
|
||||
PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[4]), .Z(g2));
|
||||
PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[4]), .Z(g3));
|
||||
L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[5]), .Z(h0));
|
||||
L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[5]), .Z(h1));
|
||||
L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[6]), .Z(Y));
|
||||
`endif
|
||||
end else begin
|
||||
wire _TECHMAP_FAIL_ = 1;
|
||||
|
|
|
@ -343,6 +343,7 @@ struct SynthEcp5Pass : public ScriptPass
|
|||
else
|
||||
run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)");
|
||||
|
||||
run("opt_lut_ins -tech ecp5");
|
||||
run("clean");
|
||||
}
|
||||
|
||||
|
|
|
@ -246,6 +246,7 @@ struct SynthGowinPass : public ScriptPass
|
|||
if (check_label("map_cells"))
|
||||
{
|
||||
run("techmap -map +/gowin/cells_map.v");
|
||||
run("opt_lut_ins -tech gowin");
|
||||
run("setundef -undriven -params -zero");
|
||||
run("hilomap -singleton -hicell VCC V -locell GND G");
|
||||
if (!noiopads || help_mode)
|
||||
|
|
|
@ -9,6 +9,8 @@ module \$__ICE40_CARRY_WRAPPER (
|
|||
input I0, I3
|
||||
);
|
||||
parameter LUT = 0;
|
||||
parameter I3_IS_CI = 0;
|
||||
wire I3_OR_CI = I3_IS_CI ? CI : I3;
|
||||
SB_CARRY carry (
|
||||
.I0(A),
|
||||
.I1(B),
|
||||
|
@ -21,7 +23,7 @@ module \$__ICE40_CARRY_WRAPPER (
|
|||
.I0(I0),
|
||||
.I1(A),
|
||||
.I2(B),
|
||||
.I3(I3),
|
||||
.I3(I3_OR_CI),
|
||||
.O(O)
|
||||
);
|
||||
endmodule
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
|
||||
# Box 1 : $__ICE40_CARRY_WRAPPER (private cell used to preserve
|
||||
# SB_LUT4+SB_CARRY)
|
||||
# Outputs: O, CO
|
||||
# (Exception: carry chain input/output must be the
|
||||
# last input and output and the entire bus has been
|
||||
# moved there overriding the otherwise
|
||||
# alphabetical ordering)
|
||||
# name ID w/b ins outs
|
||||
$__ICE40_CARRY_WRAPPER 1 1 5 2
|
||||
#A B I0 I3 CI
|
||||
#A B I0 I3 CI
|
||||
1231 1205 1285 874 874 # O
|
||||
675 609 - - 278 # CO
|
||||
|
|
|
@ -49,13 +49,14 @@ module _80_ice40_alu (A, B, CI, BI, X, Y, CO);
|
|||
// A[1]: 1100 1100 1100 1100
|
||||
// A[2]: 1111 0000 1111 0000
|
||||
// A[3]: 1111 1111 0000 0000
|
||||
.LUT(16'b 0110_1001_1001_0110)
|
||||
.LUT(16'b 0110_1001_1001_0110),
|
||||
.I3_IS_CI(1'b1)
|
||||
) carry (
|
||||
.A(AA[i]),
|
||||
.B(BB[i]),
|
||||
.CI(C[i]),
|
||||
.I0(1'b0),
|
||||
.I3(C[i]),
|
||||
.I3(1'bx),
|
||||
.CO(CO[i]),
|
||||
.O(Y[i])
|
||||
);
|
||||
|
|
|
@ -42,19 +42,18 @@ module \$lut (A, Y);
|
|||
.I0(1'b0), .I1(1'b0), .I2(1'b0), .I3(A[0]));
|
||||
end else
|
||||
if (WIDTH == 2) begin
|
||||
localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[1]}}, {4{LUT[2]}}, {4{LUT[0]}}};
|
||||
localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[2]}}, {4{LUT[1]}}, {4{LUT[0]}}};
|
||||
SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(1'b0), .I1(1'b0), .I2(A[1]), .I3(A[0]));
|
||||
.I0(1'b0), .I1(1'b0), .I2(A[0]), .I3(A[1]));
|
||||
end else
|
||||
if (WIDTH == 3) begin
|
||||
localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[3]}}, {2{LUT[5]}}, {2{LUT[1]}}, {2{LUT[6]}}, {2{LUT[2]}}, {2{LUT[4]}}, {2{LUT[0]}}};
|
||||
localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[6]}}, {2{LUT[5]}}, {2{LUT[4]}}, {2{LUT[3]}}, {2{LUT[2]}}, {2{LUT[1]}}, {2{LUT[0]}}};
|
||||
SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(1'b0), .I1(A[2]), .I2(A[1]), .I3(A[0]));
|
||||
.I0(1'b0), .I1(A[0]), .I2(A[1]), .I3(A[2]));
|
||||
end else
|
||||
if (WIDTH == 4) begin
|
||||
localparam [15:0] INIT = {LUT[15], LUT[7], LUT[11], LUT[3], LUT[13], LUT[5], LUT[9], LUT[1], LUT[14], LUT[6], LUT[10], LUT[2], LUT[12], LUT[4], LUT[8], LUT[0]};
|
||||
SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[3]), .I1(A[2]), .I2(A[1]), .I3(A[0]));
|
||||
SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3]));
|
||||
end else begin
|
||||
wire _TECHMAP_FAIL_ = 1;
|
||||
end
|
||||
|
|
|
@ -1126,6 +1126,7 @@ module SB_SPRAM256KA (
|
|||
input [15:0] DATAIN,
|
||||
input [3:0] MASKWREN,
|
||||
input WREN, CHIPSELECT, CLOCK, STANDBY, SLEEP, POWEROFF,
|
||||
`ABC9_ARRIVAL_U(1821) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13207
|
||||
output reg [15:0] DATAOUT
|
||||
);
|
||||
`ifndef BLACKBOX
|
||||
|
|
|
@ -139,7 +139,8 @@ static void run_ice40_opts(Module *module)
|
|||
log("Optimized $__ICE40_CARRY_WRAPPER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n",
|
||||
log_id(module), log_id(cell), log_signal(replacement_output));
|
||||
cell->type = "$lut";
|
||||
cell->setPort("\\A", { cell->getPort("\\I0"), inbit[0], inbit[1], cell->getPort("\\I3") });
|
||||
auto I3 = get_bit_or_zero(cell->getPort(cell->getParam(ID(I3_IS_CI)).as_bool() ? ID(CI) : ID(I3)));
|
||||
cell->setPort("\\A", { I3, inbit[1], inbit[0], get_bit_or_zero(cell->getPort("\\I0")) });
|
||||
cell->setPort("\\Y", cell->getPort("\\O"));
|
||||
cell->unsetPort("\\B");
|
||||
cell->unsetPort("\\CI");
|
||||
|
@ -148,6 +149,7 @@ static void run_ice40_opts(Module *module)
|
|||
cell->unsetPort("\\CO");
|
||||
cell->unsetPort("\\O");
|
||||
cell->setParam("\\WIDTH", 4);
|
||||
cell->unsetParam("\\I3_IS_CI");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ USING_YOSYS_NAMESPACE
|
|||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct SynthIntelPass : public ScriptPass {
|
||||
SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") {}
|
||||
SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") { experimental(); }
|
||||
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
// (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback
|
||||
// into the (combinatorial) FD* cell to facilitate clock-enable behaviour
|
||||
|
||||
module FDRE (output Q, input C, CE, D, R);
|
||||
module FDRE (output Q, (* techmap_autopurge *) input C, CE, D, R);
|
||||
parameter [0:0] INIT = 1'b0;
|
||||
parameter [0:0] IS_C_INVERTED = 1'b0;
|
||||
parameter [0:0] IS_D_INVERTED = 1'b0;
|
||||
|
@ -110,7 +110,7 @@ module FDRE (output Q, input C, CE, D, R);
|
|||
wire [0:0] abc9_ff.init = 1'b0;
|
||||
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
|
||||
endmodule
|
||||
module FDRE_1 (output Q, input C, CE, D, R);
|
||||
module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R);
|
||||
parameter [0:0] INIT = 1'b0;
|
||||
wire QQ, $Q;
|
||||
generate if (INIT == 1'b1) begin
|
||||
|
@ -138,7 +138,7 @@ module FDRE_1 (output Q, input C, CE, D, R);
|
|||
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
|
||||
endmodule
|
||||
|
||||
module FDSE (output Q, input C, CE, D, S);
|
||||
module FDSE (output Q, (* techmap_autopurge *) input C, CE, D, S);
|
||||
parameter [0:0] INIT = 1'b1;
|
||||
parameter [0:0] IS_C_INVERTED = 1'b0;
|
||||
parameter [0:0] IS_D_INVERTED = 1'b0;
|
||||
|
@ -173,7 +173,7 @@ module FDSE (output Q, input C, CE, D, S);
|
|||
wire [0:0] abc9_ff.init = 1'b0;
|
||||
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
|
||||
endmodule
|
||||
module FDSE_1 (output Q, input C, CE, D, S);
|
||||
module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S);
|
||||
parameter [0:0] INIT = 1'b1;
|
||||
wire QQ, $Q;
|
||||
generate if (INIT == 1'b1) begin
|
||||
|
@ -200,7 +200,7 @@ module FDSE_1 (output Q, input C, CE, D, S);
|
|||
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
|
||||
endmodule
|
||||
|
||||
module FDCE (output Q, input C, CE, D, CLR);
|
||||
module FDCE (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
|
||||
parameter [0:0] INIT = 1'b0;
|
||||
parameter [0:0] IS_C_INVERTED = 1'b0;
|
||||
parameter [0:0] IS_D_INVERTED = 1'b0;
|
||||
|
@ -249,7 +249,7 @@ module FDCE (output Q, input C, CE, D, CLR);
|
|||
wire [0:0] abc9_ff.init = 1'b0;
|
||||
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
|
||||
endmodule
|
||||
module FDCE_1 (output Q, input C, CE, D, CLR);
|
||||
module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
|
||||
parameter [0:0] INIT = 1'b0;
|
||||
wire QQ, $Q, $QQ;
|
||||
generate if (INIT == 1'b1) begin
|
||||
|
@ -288,7 +288,7 @@ module FDCE_1 (output Q, input C, CE, D, CLR);
|
|||
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
|
||||
endmodule
|
||||
|
||||
module FDPE (output Q, input C, CE, D, PRE);
|
||||
module FDPE (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
|
||||
parameter [0:0] INIT = 1'b1;
|
||||
parameter [0:0] IS_C_INVERTED = 1'b0;
|
||||
parameter [0:0] IS_D_INVERTED = 1'b0;
|
||||
|
@ -335,7 +335,7 @@ module FDPE (output Q, input C, CE, D, PRE);
|
|||
wire [0:0] abc9_ff.init = 1'b0;
|
||||
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
|
||||
endmodule
|
||||
module FDPE_1 (output Q, input C, CE, D, PRE);
|
||||
module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
|
||||
parameter [0:0] INIT = 1'b1;
|
||||
wire QQ, $Q, $QQ;
|
||||
generate if (INIT == 1'b1) begin
|
||||
|
|
|
@ -33,6 +33,11 @@ endmodule
|
|||
module \$__ABC9_FF_ (input D, output Q);
|
||||
endmodule
|
||||
|
||||
(* abc9_box_id = (9000+DELAY) *)
|
||||
module \$__ABC9_DELAY (input I, output O);
|
||||
parameter DELAY = 0;
|
||||
endmodule
|
||||
|
||||
// Box to emulate async behaviour of FDC*
|
||||
(* abc9_box_id = 1000, lib_whitebox *)
|
||||
module \$__ABC9_ASYNC0 (input A, S, output Y);
|
||||
|
@ -42,7 +47,7 @@ endmodule
|
|||
// Box to emulate async behaviour of FDP*
|
||||
(* abc9_box_id = 1001, lib_whitebox *)
|
||||
module \$__ABC9_ASYNC1 (input A, S, output Y);
|
||||
assign Y = S ? 1'b0 : A;
|
||||
assign Y = S ? 1'b1 : A;
|
||||
endmodule
|
||||
|
||||
// Box to emulate comb/seq behaviour of RAM{32,64} and SRL{16,32}
|
||||
|
|
|
@ -62,67 +62,6 @@ $__ABC9_ASYNC1 1001 1 2 1
|
|||
#A S
|
||||
0 764 # Y
|
||||
|
||||
# Flop boxes:
|
||||
# * Max delays from https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L237-L251
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L265-L277
|
||||
# * Exception: $abc9_currQ is a special input (located last) necessary for clock-enable functionality
|
||||
|
||||
# Box 1100 : FDRE
|
||||
# name ID w/b ins outs
|
||||
FDRE 1100 1 5 1
|
||||
#C CE D R $abc9_currQ
|
||||
#0 109 -46 404 0
|
||||
0 109 0 404 0 # Q (-46ps Tsu clamped to 0)
|
||||
|
||||
# Box 1101 : FDRE_1
|
||||
# name ID w/b ins outs
|
||||
FDRE_1 1101 1 5 1
|
||||
#C CE D R $abc9_currQ
|
||||
#0 109 -46 404 0
|
||||
0 109 0 404 0 # Q (-46ps Tsu clamped to 0)
|
||||
|
||||
# Box 1102 : FDSE
|
||||
# name ID w/b ins outs
|
||||
FDSE 1102 1 5 1
|
||||
#C CE D R $abc9_currQ
|
||||
#0 109 -46 404 0
|
||||
0 109 0 404 0 # Q (-46ps Tsu clamped to 0)
|
||||
|
||||
# Box 1103 : FDSE_1
|
||||
# name ID w/b ins outs
|
||||
FDSE_1 1103 1 5 1
|
||||
#C CE D R $abc9_currQ
|
||||
#0 109 -46 404 0
|
||||
0 109 0 404 0 # Q (-46ps Tsu clamped to 0)
|
||||
|
||||
# Box 1104 : FDCE
|
||||
# name ID w/b ins outs
|
||||
FDCE 1104 1 5 1
|
||||
#C CE CLR D $abc9_currQ
|
||||
#0 109 764 -46 0
|
||||
0 109 764 0 0 # Q (-46ps Tsu clamped to 0)
|
||||
|
||||
# Box 1105 : FDCE_1
|
||||
# name ID w/b ins outs
|
||||
FDCE_1 1105 1 5 1
|
||||
#C CE CLR D $abc9_currQ
|
||||
#0 109 764 -46 0
|
||||
0 109 764 0 0 # Q (-46ps Tsu clamped to 0)
|
||||
|
||||
# Box 1106 : FDPE
|
||||
# name ID w/b ins outs
|
||||
FDPE 1106 1 5 1
|
||||
#C CE D PRE $abc9_currQ
|
||||
#0 109 -46 764 0
|
||||
0 109 0 764 0 # Q (-46ps Tsu clamped to 0)
|
||||
|
||||
# Box 1107 : FDPE_1
|
||||
# name ID w/b ins outs
|
||||
FDPE_1 1107 1 5 1
|
||||
#C CE D PRE $abc9_currQ
|
||||
#0 109 -46 764 0
|
||||
0 109 0 764 0 # Q (-46ps Tsu clamped to 0)
|
||||
|
||||
# Box 2000 : $__ABC9_LUT6
|
||||
# (private cell to emulate async behaviour of LUTRAMs)
|
||||
# SLICEM/A6LUT
|
||||
|
|
|
@ -325,17 +325,20 @@ endmodule
|
|||
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250
|
||||
|
||||
(* abc9_box_id=1100, lib_whitebox, abc9_flop *)
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module FDRE (
|
||||
(* abc9_arrival=303 *)
|
||||
output reg Q,
|
||||
(* clkbuf_sink *)
|
||||
(* invertible_pin = "IS_C_INVERTED" *)
|
||||
input C,
|
||||
(* abc9_required=109 *)
|
||||
input CE,
|
||||
(* invertible_pin = "IS_D_INVERTED" *)
|
||||
//(* abc9_required=-46 *) // Negative required times not currently supported
|
||||
input D,
|
||||
(* invertible_pin = "IS_R_INVERTED" *)
|
||||
(* abc9_required=404 *)
|
||||
input R
|
||||
);
|
||||
parameter [0:0] INIT = 1'b0;
|
||||
|
@ -349,30 +352,38 @@ module FDRE (
|
|||
endcase endgenerate
|
||||
endmodule
|
||||
|
||||
(* abc9_box_id=1101, lib_whitebox, abc9_flop *)
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module FDRE_1 (
|
||||
(* abc9_arrival=303 *)
|
||||
output reg Q,
|
||||
(* clkbuf_sink *)
|
||||
input C,
|
||||
input CE, D, R
|
||||
(* abc9_required=109 *)
|
||||
input CE,
|
||||
//(* abc9_required=-46 *) // Negative required times not currently supported
|
||||
input D,
|
||||
(* abc9_required=404 *)
|
||||
input R
|
||||
);
|
||||
parameter [0:0] INIT = 1'b0;
|
||||
initial Q <= INIT;
|
||||
always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D;
|
||||
endmodule
|
||||
|
||||
(* abc9_box_id=1102, lib_whitebox, abc9_flop *)
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module FDSE (
|
||||
(* abc9_arrival=303 *)
|
||||
output reg Q,
|
||||
(* clkbuf_sink *)
|
||||
(* invertible_pin = "IS_C_INVERTED" *)
|
||||
input C,
|
||||
(* abc9_required=109 *)
|
||||
input CE,
|
||||
(* invertible_pin = "IS_D_INVERTED" *)
|
||||
//(* abc9_required=-46 *) // Negative required times not currently supported
|
||||
input D,
|
||||
(* invertible_pin = "IS_S_INVERTED" *)
|
||||
(* abc9_required=404 *)
|
||||
input S
|
||||
);
|
||||
parameter [0:0] INIT = 1'b1;
|
||||
|
@ -386,13 +397,18 @@ module FDSE (
|
|||
endcase endgenerate
|
||||
endmodule
|
||||
|
||||
(* abc9_box_id=1103, lib_whitebox, abc9_flop *)
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module FDSE_1 (
|
||||
(* abc9_arrival=303 *)
|
||||
output reg Q,
|
||||
(* clkbuf_sink *)
|
||||
input C,
|
||||
input CE, D, S
|
||||
(* abc9_required=109 *)
|
||||
input CE,
|
||||
//(* abc9_required=-46 *) // Negative required times not currently supported
|
||||
input D,
|
||||
(* abc9_required=404 *)
|
||||
input S
|
||||
);
|
||||
parameter [0:0] INIT = 1'b1;
|
||||
initial Q <= INIT;
|
||||
|
@ -405,6 +421,7 @@ module FDRSE (
|
|||
(* invertible_pin = "IS_C_INVERTED" *)
|
||||
input C,
|
||||
(* invertible_pin = "IS_CE_INVERTED" *)
|
||||
(* abc9_required=109 *)
|
||||
input CE,
|
||||
(* invertible_pin = "IS_D_INVERTED" *)
|
||||
input D,
|
||||
|
@ -434,17 +451,20 @@ module FDRSE (
|
|||
Q <= d;
|
||||
endmodule
|
||||
|
||||
(* abc9_box_id=1104, lib_whitebox, abc9_flop *)
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module FDCE (
|
||||
(* abc9_arrival=303 *)
|
||||
output reg Q,
|
||||
(* clkbuf_sink *)
|
||||
(* invertible_pin = "IS_C_INVERTED" *)
|
||||
input C,
|
||||
(* abc9_required=109 *)
|
||||
input CE,
|
||||
(* invertible_pin = "IS_CLR_INVERTED" *)
|
||||
(* abc9_required=764 *)
|
||||
input CLR,
|
||||
(* invertible_pin = "IS_D_INVERTED" *)
|
||||
//(* abc9_required=-46 *) // Negative required times not currently supported
|
||||
input D
|
||||
);
|
||||
parameter [0:0] INIT = 1'b0;
|
||||
|
@ -460,30 +480,38 @@ module FDCE (
|
|||
endcase endgenerate
|
||||
endmodule
|
||||
|
||||
(* abc9_box_id=1105, lib_whitebox, abc9_flop *)
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module FDCE_1 (
|
||||
(* abc9_arrival=303 *)
|
||||
output reg Q,
|
||||
(* clkbuf_sink *)
|
||||
input C,
|
||||
input CE, D, CLR
|
||||
(* abc9_required=109 *)
|
||||
input CE,
|
||||
(* abc9_required=764 *)
|
||||
input CLR,
|
||||
//(* abc9_required=-46 *) // Negative required times not currently supported
|
||||
input D
|
||||
);
|
||||
parameter [0:0] INIT = 1'b0;
|
||||
initial Q <= INIT;
|
||||
always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
|
||||
endmodule
|
||||
|
||||
(* abc9_box_id=1106, lib_whitebox, abc9_flop *)
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module FDPE (
|
||||
(* abc9_arrival=303 *)
|
||||
output reg Q,
|
||||
(* clkbuf_sink *)
|
||||
(* invertible_pin = "IS_C_INVERTED" *)
|
||||
input C,
|
||||
(* abc9_required=109 *)
|
||||
input CE,
|
||||
(* invertible_pin = "IS_D_INVERTED" *)
|
||||
//(* abc9_required=-46 *) // Negative required times not currently supported
|
||||
input D,
|
||||
(* invertible_pin = "IS_PRE_INVERTED" *)
|
||||
(* abc9_required=764 *)
|
||||
input PRE
|
||||
);
|
||||
parameter [0:0] INIT = 1'b1;
|
||||
|
@ -499,13 +527,18 @@ module FDPE (
|
|||
endcase endgenerate
|
||||
endmodule
|
||||
|
||||
(* abc9_box_id=1107, lib_whitebox, abc9_flop *)
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module FDPE_1 (
|
||||
(* abc9_arrival=303 *)
|
||||
output reg Q,
|
||||
(* clkbuf_sink *)
|
||||
input C,
|
||||
input CE, D, PRE
|
||||
(* abc9_required=109 *)
|
||||
input CE,
|
||||
//(* abc9_required=-46 *) // Negative required times not currently supported
|
||||
input D,
|
||||
(* abc9_required=764 *)
|
||||
input PRE
|
||||
);
|
||||
parameter [0:0] INIT = 1'b1;
|
||||
initial Q <= INIT;
|
||||
|
@ -1120,15 +1153,33 @@ module RAM16X1D_1 (
|
|||
endmodule
|
||||
|
||||
module RAM32X1D (
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
|
||||
(* abc9_arrival=1188 *)
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
|
||||
(* abc9_arrival=1153 *)
|
||||
output DPO, SPO,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
|
||||
(* abc9_required=453 *)
|
||||
input D,
|
||||
(* clkbuf_sink *)
|
||||
(* invertible_pin = "IS_WCLK_INVERTED" *)
|
||||
input WCLK,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
|
||||
(* abc9_required=654 *)
|
||||
input WE,
|
||||
input A0, A1, A2, A3, A4,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800
|
||||
(* abc9_required=245 *)
|
||||
input A0,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/clBLM_R.sdf#L798
|
||||
(* abc9_required=208 *)
|
||||
input A1,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796
|
||||
(* abc9_required=147 *)
|
||||
input A2,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794
|
||||
(* abc9_required=68 *)
|
||||
input A3,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792
|
||||
(* abc9_required=66 *)
|
||||
input A4,
|
||||
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
|
||||
);
|
||||
parameter INIT = 32'h0;
|
||||
|
@ -1143,15 +1194,33 @@ module RAM32X1D (
|
|||
endmodule
|
||||
|
||||
module RAM32X1D_1 (
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
|
||||
(* abc9_arrival=1188 *)
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
|
||||
(* abc9_arrival=1153 *)
|
||||
output DPO, SPO,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
|
||||
(* abc9_required=453 *)
|
||||
input D,
|
||||
(* clkbuf_sink *)
|
||||
(* invertible_pin = "IS_WCLK_INVERTED" *)
|
||||
input WCLK,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
|
||||
(* abc9_required=654 *)
|
||||
input WE,
|
||||
input A0, A1, A2, A3, A4,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800
|
||||
(* abc9_required=245 *)
|
||||
input A0,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/clBLM_R.sdf#L798
|
||||
(* abc9_required=208 *)
|
||||
input A1,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796
|
||||
(* abc9_required=147 *)
|
||||
input A2,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794
|
||||
(* abc9_required=68 *)
|
||||
input A3,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792
|
||||
(* abc9_required=66 *)
|
||||
input A4,
|
||||
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
|
||||
);
|
||||
parameter INIT = 32'h0;
|
||||
|
@ -1166,15 +1235,36 @@ module RAM32X1D_1 (
|
|||
endmodule
|
||||
|
||||
module RAM64X1D (
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
|
||||
(* abc9_arrival=1153 *)
|
||||
output DPO, SPO,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
|
||||
(* abc9_required=453 *)
|
||||
input D,
|
||||
(* clkbuf_sink *)
|
||||
(* invertible_pin = "IS_WCLK_INVERTED" *)
|
||||
input WCLK,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
|
||||
(* abc9_required=654 *)
|
||||
input WE,
|
||||
input A0, A1, A2, A3, A4, A5,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828
|
||||
(* abc9_required=362 *)
|
||||
input A0,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826
|
||||
(* abc9_required=245 *)
|
||||
input A1,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824
|
||||
(* abc9_required=208 *)
|
||||
input A2,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822
|
||||
(* abc9_required=147 *)
|
||||
input A3,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820
|
||||
(* abc9_required=68 *)
|
||||
input A4,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818
|
||||
(* abc9_required=66 *)
|
||||
input A5,
|
||||
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
|
||||
);
|
||||
parameter INIT = 64'h0;
|
||||
|
@ -1189,15 +1279,36 @@ module RAM64X1D (
|
|||
endmodule
|
||||
|
||||
module RAM64X1D_1 (
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
|
||||
(* abc9_arrival=1153 *)
|
||||
output DPO, SPO,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
|
||||
(* abc9_required=453 *)
|
||||
input D,
|
||||
(* clkbuf_sink *)
|
||||
(* invertible_pin = "IS_WCLK_INVERTED" *)
|
||||
input WCLK,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
|
||||
(* abc9_required=654 *)
|
||||
input WE,
|
||||
input A0, A1, A2, A3, A4, A5,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828
|
||||
(* abc9_required=362 *)
|
||||
input A0,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826
|
||||
(* abc9_required=245 *)
|
||||
input A1,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824
|
||||
(* abc9_required=208 *)
|
||||
input A2,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822
|
||||
(* abc9_required=147 *)
|
||||
input A3,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820
|
||||
(* abc9_required=68 *)
|
||||
input A4,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818
|
||||
(* abc9_required=66 *)
|
||||
input A5,
|
||||
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
|
||||
);
|
||||
parameter INIT = 64'h0;
|
||||
|
@ -1212,16 +1323,23 @@ module RAM64X1D_1 (
|
|||
endmodule
|
||||
|
||||
module RAM128X1D (
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
|
||||
// plus 204ps to cross MUXF7
|
||||
(* abc9_arrival=1357 *)
|
||||
output DPO, SPO,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
|
||||
// plus 208ps to cross MUXF7
|
||||
(* abc9_arrival=1359 *)
|
||||
output DPO, SPO,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
|
||||
(* abc9_required=453 *)
|
||||
input D,
|
||||
(* clkbuf_sink *)
|
||||
(* invertible_pin = "IS_WCLK_INVERTED" *)
|
||||
input WCLK,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
|
||||
(* abc9_required=654 *)
|
||||
input WE,
|
||||
input [6:0] A, DPRA
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-830
|
||||
(* abc9_required="616 362 245 208 147 68 66" *)
|
||||
input [6:0] A,
|
||||
input [6:0] DPRA
|
||||
);
|
||||
parameter INIT = 128'h0;
|
||||
parameter IS_WCLK_INVERTED = 1'b0;
|
||||
|
@ -1253,24 +1371,44 @@ endmodule
|
|||
// Multi port.
|
||||
|
||||
module RAM32M (
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
|
||||
(* abc9_arrival=1188 *)
|
||||
(* abc9_arrival="1153 1188" *)
|
||||
output [1:0] DOA,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L925
|
||||
(* abc9_arrival=1187 *)
|
||||
(* abc9_arrival="1161 1187" *)
|
||||
output [1:0] DOB,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L993
|
||||
(* abc9_arrival=1180 *)
|
||||
(* abc9_arrival="1158 1180" *)
|
||||
output [1:0] DOC,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061
|
||||
(* abc9_arrival=1190 *)
|
||||
(* abc9_arrival="1163 1190" *)
|
||||
output [1:0] DOD,
|
||||
input [4:0] ADDRA, ADDRB, ADDRC, ADDRD,
|
||||
input [1:0] DIA, DIB, DIC, DID,
|
||||
input [4:0] ADDRA, ADDRB, ADDRC,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792-L802
|
||||
(* abc9_required="245 208 147 68 66" *)
|
||||
input [4:0] ADDRD,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988
|
||||
(* abc9_required="453 384" *)
|
||||
input [1:0] DIA,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056
|
||||
(* abc9_required="461 354" *)
|
||||
input [1:0] DIB,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124
|
||||
(* abc9_required="457 375" *)
|
||||
input [1:0] DIC,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192
|
||||
(* abc9_required="310 334" *)
|
||||
input [1:0] DID,
|
||||
(* clkbuf_sink *)
|
||||
(* invertible_pin = "IS_WCLK_INVERTED" *)
|
||||
input WCLK,
|
||||
input WE
|
||||
input WCLK,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
|
||||
(* abc9_required=654 *)
|
||||
input WE
|
||||
);
|
||||
parameter [63:0] INIT_A = 64'h0000000000000000;
|
||||
parameter [63:0] INIT_B = 64'h0000000000000000;
|
||||
|
@ -1367,22 +1505,38 @@ endmodule
|
|||
module RAM64M (
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
|
||||
(* abc9_arrival=1153 *)
|
||||
output DOA,
|
||||
output DOA,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
|
||||
(* abc9_arrival=1161 *)
|
||||
output DOB,
|
||||
output DOB,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
|
||||
(* abc9_arrival=1158 *)
|
||||
output DOC,
|
||||
output DOC,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
|
||||
(* abc9_arrival=1163 *)
|
||||
output DOD,
|
||||
input [5:0] ADDRA, ADDRB, ADDRC, ADDRD,
|
||||
input DIA, DIB, DIC, DID,
|
||||
output DOD,
|
||||
input [5:0] ADDRA, ADDRB, ADDRC,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-L830
|
||||
(* abc9_required="362 245 208 147 68 66" *)
|
||||
input [5:0] ADDRD,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988
|
||||
(* abc9_required=384 *)
|
||||
input DIA,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056
|
||||
(* abc9_required=354 *)
|
||||
input DIB,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124
|
||||
(* abc9_required=375 *)
|
||||
input DIC,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192
|
||||
(* abc9_required=310 *)
|
||||
input DID,
|
||||
(* clkbuf_sink *)
|
||||
(* invertible_pin = "IS_WCLK_INVERTED" *)
|
||||
input WCLK,
|
||||
input WE
|
||||
input WCLK,
|
||||
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
|
||||
(* abc9_required=654 *)
|
||||
input WE
|
||||
);
|
||||
parameter [63:0] INIT_A = 64'h0000000000000000;
|
||||
parameter [63:0] INIT_B = 64'h0000000000000000;
|
||||
|
@ -2155,7 +2309,235 @@ assign PCOUT = P;
|
|||
|
||||
endmodule
|
||||
|
||||
// TODO: DSP48 (Virtex 4).
|
||||
module DSP48 (
|
||||
input signed [17:0] A,
|
||||
input signed [17:0] B,
|
||||
input signed [47:0] C,
|
||||
input signed [17:0] BCIN,
|
||||
input signed [47:0] PCIN,
|
||||
input CARRYIN,
|
||||
input [6:0] OPMODE,
|
||||
input SUBTRACT,
|
||||
input [1:0] CARRYINSEL,
|
||||
output signed [47:0] P,
|
||||
output signed [17:0] BCOUT,
|
||||
output signed [47:0] PCOUT,
|
||||
(* clkbuf_sink *)
|
||||
input CLK,
|
||||
input CEA,
|
||||
input CEB,
|
||||
input CEC,
|
||||
input CEM,
|
||||
input CECARRYIN,
|
||||
input CECINSUB,
|
||||
input CECTRL,
|
||||
input CEP,
|
||||
input RSTA,
|
||||
input RSTB,
|
||||
input RSTC,
|
||||
input RSTM,
|
||||
input RSTCARRYIN,
|
||||
input RSTCTRL,
|
||||
input RSTP
|
||||
);
|
||||
|
||||
parameter integer AREG = 1;
|
||||
parameter integer BREG = 1;
|
||||
parameter integer CREG = 1;
|
||||
parameter integer MREG = 1;
|
||||
parameter integer PREG = 1;
|
||||
parameter integer CARRYINREG = 1;
|
||||
parameter integer CARRYINSELREG = 1;
|
||||
parameter integer OPMODEREG = 1;
|
||||
parameter integer SUBTRACTREG = 1;
|
||||
parameter B_INPUT = "DIRECT";
|
||||
parameter LEGACY_MODE = "MULT18X18S";
|
||||
|
||||
wire signed [17:0] A_OUT;
|
||||
wire signed [17:0] B_OUT;
|
||||
wire signed [47:0] C_OUT;
|
||||
wire signed [35:0] M_MULT;
|
||||
wire signed [35:0] M_OUT;
|
||||
wire signed [47:0] P_IN;
|
||||
wire [6:0] OPMODE_OUT;
|
||||
wire [1:0] CARRYINSEL_OUT;
|
||||
wire CARRYIN_OUT;
|
||||
wire SUBTRACT_OUT;
|
||||
reg INT_CARRYIN_XY;
|
||||
reg INT_CARRYIN_Z;
|
||||
reg signed [47:0] XMUX;
|
||||
reg signed [47:0] YMUX;
|
||||
wire signed [47:0] XYMUX;
|
||||
reg signed [47:0] ZMUX;
|
||||
reg CIN;
|
||||
|
||||
// The B input multiplexer.
|
||||
wire signed [17:0] B_MUX;
|
||||
assign B_MUX = (B_INPUT == "DIRECT") ? B : BCIN;
|
||||
|
||||
// The cascade output.
|
||||
assign BCOUT = B_OUT;
|
||||
assign PCOUT = P;
|
||||
|
||||
// The registers.
|
||||
reg signed [17:0] A0_REG;
|
||||
reg signed [17:0] A1_REG;
|
||||
reg signed [17:0] B0_REG;
|
||||
reg signed [17:0] B1_REG;
|
||||
reg signed [47:0] C_REG;
|
||||
reg signed [35:0] M_REG;
|
||||
reg signed [47:0] P_REG;
|
||||
reg [6:0] OPMODE_REG;
|
||||
reg [1:0] CARRYINSEL_REG;
|
||||
reg SUBTRACT_REG;
|
||||
reg CARRYIN_REG;
|
||||
reg INT_CARRYIN_XY_REG;
|
||||
|
||||
initial begin
|
||||
A0_REG = 0;
|
||||
A1_REG = 0;
|
||||
B0_REG = 0;
|
||||
B1_REG = 0;
|
||||
C_REG = 0;
|
||||
M_REG = 0;
|
||||
P_REG = 0;
|
||||
OPMODE_REG = 0;
|
||||
CARRYINSEL_REG = 0;
|
||||
SUBTRACT_REG = 0;
|
||||
CARRYIN_REG = 0;
|
||||
INT_CARRYIN_XY_REG = 0;
|
||||
end
|
||||
|
||||
always @(posedge CLK) begin
|
||||
if (RSTA) begin
|
||||
A0_REG <= 0;
|
||||
A1_REG <= 0;
|
||||
end else if (CEA) begin
|
||||
A0_REG <= A;
|
||||
A1_REG <= A0_REG;
|
||||
end
|
||||
if (RSTB) begin
|
||||
B0_REG <= 0;
|
||||
B1_REG <= 0;
|
||||
end else if (CEB) begin
|
||||
B0_REG <= B_MUX;
|
||||
B1_REG <= B0_REG;
|
||||
end
|
||||
if (RSTC) begin
|
||||
C_REG <= 0;
|
||||
end else if (CEC) begin
|
||||
C_REG <= C;
|
||||
end
|
||||
if (RSTM) begin
|
||||
M_REG <= 0;
|
||||
end else if (CEM) begin
|
||||
M_REG <= M_MULT;
|
||||
end
|
||||
if (RSTP) begin
|
||||
P_REG <= 0;
|
||||
end else if (CEP) begin
|
||||
P_REG <= P_IN;
|
||||
end
|
||||
if (RSTCTRL) begin
|
||||
OPMODE_REG <= 0;
|
||||
CARRYINSEL_REG <= 0;
|
||||
SUBTRACT_REG <= 0;
|
||||
end else begin
|
||||
if (CECTRL) begin
|
||||
OPMODE_REG <= OPMODE;
|
||||
CARRYINSEL_REG <= CARRYINSEL;
|
||||
end
|
||||
if (CECINSUB)
|
||||
SUBTRACT_REG <= SUBTRACT;
|
||||
end
|
||||
if (RSTCARRYIN) begin
|
||||
CARRYIN_REG <= 0;
|
||||
INT_CARRYIN_XY_REG <= 0;
|
||||
end else begin
|
||||
if (CECINSUB)
|
||||
CARRYIN_REG <= CARRYIN;
|
||||
if (CECARRYIN)
|
||||
INT_CARRYIN_XY_REG <= INT_CARRYIN_XY;
|
||||
end
|
||||
end
|
||||
|
||||
// The register enables.
|
||||
assign A_OUT = (AREG == 2) ? A1_REG : (AREG == 1) ? A0_REG : A;
|
||||
assign B_OUT = (BREG == 2) ? B1_REG : (BREG == 1) ? B0_REG : B_MUX;
|
||||
assign C_OUT = (CREG == 1) ? C_REG : C;
|
||||
assign M_OUT = (MREG == 1) ? M_REG : M_MULT;
|
||||
assign P = (PREG == 1) ? P_REG : P_IN;
|
||||
assign OPMODE_OUT = (OPMODEREG == 1) ? OPMODE_REG : OPMODE;
|
||||
assign SUBTRACT_OUT = (SUBTRACTREG == 1) ? SUBTRACT_REG : SUBTRACT;
|
||||
assign CARRYINSEL_OUT = (CARRYINSELREG == 1) ? CARRYINSEL_REG : CARRYINSEL;
|
||||
assign CARRYIN_OUT = (CARRYINREG == 1) ? CARRYIN_REG : CARRYIN;
|
||||
|
||||
// The multiplier.
|
||||
assign M_MULT = A_OUT * B_OUT;
|
||||
|
||||
// The post-adder inputs.
|
||||
always @* begin
|
||||
case (OPMODE_OUT[1:0])
|
||||
2'b00: XMUX <= 0;
|
||||
2'b10: XMUX <= P;
|
||||
2'b11: XMUX <= {{12{A_OUT[17]}}, A_OUT, B_OUT};
|
||||
default: XMUX <= 48'hxxxxxxxxxxxx;
|
||||
endcase
|
||||
case (OPMODE_OUT[1:0])
|
||||
2'b01: INT_CARRYIN_XY <= A_OUT[17] ~^ B_OUT[17];
|
||||
2'b11: INT_CARRYIN_XY <= ~A_OUT[17];
|
||||
// TODO: not tested in hardware.
|
||||
default: INT_CARRYIN_XY <= A_OUT[17] ~^ B_OUT[17];
|
||||
endcase
|
||||
end
|
||||
|
||||
always @* begin
|
||||
case (OPMODE_OUT[3:2])
|
||||
2'b00: YMUX <= 0;
|
||||
2'b11: YMUX <= C_OUT;
|
||||
default: YMUX <= 48'hxxxxxxxxxxxx;
|
||||
endcase
|
||||
end
|
||||
|
||||
assign XYMUX = (OPMODE_OUT[3:0] == 4'b0101) ? M_OUT : (XMUX + YMUX);
|
||||
|
||||
always @* begin
|
||||
case (OPMODE_OUT[6:4])
|
||||
3'b000: ZMUX <= 0;
|
||||
3'b001: ZMUX <= PCIN;
|
||||
3'b010: ZMUX <= P;
|
||||
3'b011: ZMUX <= C_OUT;
|
||||
3'b101: ZMUX <= {{17{PCIN[47]}}, PCIN[47:17]};
|
||||
3'b110: ZMUX <= {{17{P[47]}}, P[47:17]};
|
||||
default: ZMUX <= 48'hxxxxxxxxxxxx;
|
||||
endcase
|
||||
// TODO: check how all this works on actual hw.
|
||||
if (OPMODE_OUT[1:0] == 2'b10)
|
||||
INT_CARRYIN_Z <= ~P[47];
|
||||
else
|
||||
case (OPMODE_OUT[6:4])
|
||||
3'b001: INT_CARRYIN_Z <= ~PCIN[47];
|
||||
3'b010: INT_CARRYIN_Z <= ~P[47];
|
||||
3'b101: INT_CARRYIN_Z <= ~PCIN[47];
|
||||
3'b110: INT_CARRYIN_Z <= ~P[47];
|
||||
default: INT_CARRYIN_Z <= 1'bx;
|
||||
endcase
|
||||
end
|
||||
|
||||
always @* begin
|
||||
case (CARRYINSEL_OUT)
|
||||
2'b00: CIN <= CARRYIN_OUT;
|
||||
2'b01: CIN <= INT_CARRYIN_Z;
|
||||
2'b10: CIN <= INT_CARRYIN_XY;
|
||||
2'b11: CIN <= INT_CARRYIN_XY_REG;
|
||||
default: CIN <= 1'bx;
|
||||
endcase
|
||||
end
|
||||
|
||||
// The post-adder.
|
||||
assign P_IN = SUBTRACT_OUT ? (ZMUX - (XYMUX + CIN)) : (ZMUX + XYMUX + CIN);
|
||||
|
||||
endmodule
|
||||
|
||||
// TODO: DSP48E (Virtex 5).
|
||||
|
||||
|
@ -2169,21 +2551,30 @@ module DSP48E1 (
|
|||
output reg MULTSIGNOUT,
|
||||
output OVERFLOW,
|
||||
`ifdef YOSYS
|
||||
(* abc9_arrival = \DSP48E1.P_arrival () *)
|
||||
(* abc9_arrival = \P.abc9_arrival () *)
|
||||
`endif
|
||||
output reg signed [47:0] P,
|
||||
output reg PATTERNBDETECT,
|
||||
output reg PATTERNDETECT,
|
||||
`ifdef YOSYS
|
||||
(* abc9_arrival = \DSP48E1.PCOUT_arrival () *)
|
||||
(* abc9_arrival = \PCOUT.abc9_arrival () *)
|
||||
`endif
|
||||
output [47:0] PCOUT,
|
||||
output UNDERFLOW,
|
||||
`ifdef YOSYS
|
||||
(* abc9_required = \A.abc9_required () *)
|
||||
`endif
|
||||
input signed [29:0] A,
|
||||
input [29:0] ACIN,
|
||||
input [3:0] ALUMODE,
|
||||
`ifdef YOSYS
|
||||
(* abc9_required = \B.abc9_required () *)
|
||||
`endif
|
||||
input signed [17:0] B,
|
||||
input [17:0] BCIN,
|
||||
`ifdef YOSYS
|
||||
(* abc9_required = \C.abc9_required () *)
|
||||
`endif
|
||||
input [47:0] C,
|
||||
input CARRYCASCIN,
|
||||
input CARRYIN,
|
||||
|
@ -2202,10 +2593,16 @@ module DSP48E1 (
|
|||
input CEM,
|
||||
input CEP,
|
||||
(* clkbuf_sink *) input CLK,
|
||||
`ifdef YOSYS
|
||||
(* abc9_required = \D.abc9_required () *)
|
||||
`endif
|
||||
input [24:0] D,
|
||||
input [4:0] INMODE,
|
||||
input MULTSIGNIN,
|
||||
input [6:0] OPMODE,
|
||||
`ifdef YOSYS
|
||||
(* abc9_required = \PCIN.abc9_required () *)
|
||||
`endif
|
||||
input [47:0] PCIN,
|
||||
input RSTA,
|
||||
input RSTALLCARRYIN,
|
||||
|
@ -2250,69 +2647,133 @@ module DSP48E1 (
|
|||
parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
|
||||
|
||||
`ifdef YOSYS
|
||||
function integer \DSP48E1.P_arrival ;
|
||||
function integer \A.abc9_required ;
|
||||
begin
|
||||
\DSP48E1.P_arrival = 0;
|
||||
if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
|
||||
if (PREG != 0) \DSP48E1.P_arrival = 329;
|
||||
// Worst-case from CREG and MREG
|
||||
else if (CREG != 0) \DSP48E1.P_arrival = 1687;
|
||||
else if (MREG != 0) \DSP48E1.P_arrival = 1671;
|
||||
// Worst-case from AREG and BREG
|
||||
else if (AREG != 0) \DSP48E1.P_arrival = 2952;
|
||||
else if (BREG != 0) \DSP48E1.P_arrival = 2813;
|
||||
\A.abc9_required = 0;
|
||||
if (AREG != 0) \A.abc9_required = 254;
|
||||
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
|
||||
if (MREG != 0) \A.abc9_required = 1416;
|
||||
else if (PREG != 0) \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 3030 : 2739) ;
|
||||
end
|
||||
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
|
||||
if (PREG != 0) \DSP48E1.P_arrival = 329;
|
||||
// Worst-case from CREG and MREG
|
||||
else if (CREG != 0) \DSP48E1.P_arrival = 1687;
|
||||
else if (MREG != 0) \DSP48E1.P_arrival = 1671;
|
||||
// Worst-case from AREG, ADREG, BREG, DREG
|
||||
else if (AREG != 0) \DSP48E1.P_arrival = 3935;
|
||||
else if (DREG != 0) \DSP48E1.P_arrival = 3908;
|
||||
else if (ADREG != 0) \DSP48E1.P_arrival = 2958;
|
||||
else if (BREG != 0) \DSP48E1.P_arrival = 2813;
|
||||
// Worst-case from ADREG and MREG
|
||||
if (MREG != 0) \A.abc9_required = 2400;
|
||||
else if (ADREG != 0) \A.abc9_required = 1283;
|
||||
else if (PREG != 0) \A.abc9_required = 3723;
|
||||
else if (PREG != 0) \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 4014 : 3723) ;
|
||||
end
|
||||
else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
|
||||
if (PREG != 0) \DSP48E1.P_arrival = 329;
|
||||
if (PREG != 0) \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1730 : 1441) ;
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
function integer \B.abc9_required ;
|
||||
begin
|
||||
\B.abc9_required = 0;
|
||||
if (BREG != 0) \B.abc9_required = 324;
|
||||
else if (MREG != 0) \B.abc9_required = 1285;
|
||||
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
|
||||
if (PREG != 0) \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 2898 : 2608) ;
|
||||
end
|
||||
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
|
||||
if (PREG != 0) \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 2898 : 2608) ;
|
||||
end
|
||||
else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
|
||||
if (PREG != 0) \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1718 : 1428) ;
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
function integer \C.abc9_required ;
|
||||
begin
|
||||
\C.abc9_required = 0;
|
||||
if (CREG != 0) \C.abc9_required = 168;
|
||||
else if (PREG != 0) \C.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1534 : 1244) ;
|
||||
end
|
||||
endfunction
|
||||
function integer \D.abc9_required ;
|
||||
begin
|
||||
\D.abc9_required = 0;
|
||||
if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
|
||||
end
|
||||
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
|
||||
if (DREG != 0) \D.abc9_required = 248;
|
||||
else if (ADREG != 0) \D.abc9_required = 1195;
|
||||
else if (MREG != 0) \D.abc9_required = 2310;
|
||||
else if (PREG != 0) \D.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 3925 : 3635) ;
|
||||
end
|
||||
else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
function integer \PCIN.abc9_required ;
|
||||
begin
|
||||
\PCIN.abc9_required = 0;
|
||||
if (PREG != 0) \PCIN.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1315 : 1025) ;
|
||||
end
|
||||
endfunction
|
||||
function integer \P.abc9_arrival ;
|
||||
begin
|
||||
\P.abc9_arrival = 0;
|
||||
if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
|
||||
if (PREG != 0) \P.abc9_arrival = 329;
|
||||
// Worst-case from CREG and MREG
|
||||
else if (CREG != 0) \P.abc9_arrival = 1687;
|
||||
else if (MREG != 0) \P.abc9_arrival = 1671;
|
||||
// Worst-case from AREG and BREG
|
||||
else if (AREG != 0) \P.abc9_arrival = 2952;
|
||||
else if (BREG != 0) \P.abc9_arrival = 2813;
|
||||
end
|
||||
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
|
||||
if (PREG != 0) \P.abc9_arrival = 329;
|
||||
// Worst-case from CREG and MREG
|
||||
else if (CREG != 0) \P.abc9_arrival = 1687;
|
||||
else if (MREG != 0) \P.abc9_arrival = 1671;
|
||||
// Worst-case from AREG, ADREG, BREG, DREG
|
||||
else if (AREG != 0) \P.abc9_arrival = 3935;
|
||||
else if (DREG != 0) \P.abc9_arrival = 3908;
|
||||
else if (ADREG != 0) \P.abc9_arrival = 2958;
|
||||
else if (BREG != 0) \P.abc9_arrival = 2813;
|
||||
end
|
||||
else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
|
||||
if (PREG != 0) \P.abc9_arrival = 329;
|
||||
// Worst-case from AREG, BREG, CREG
|
||||
else if (CREG != 0) \DSP48E1.P_arrival = 1687;
|
||||
else if (AREG != 0) \DSP48E1.P_arrival = 1632;
|
||||
else if (BREG != 0) \DSP48E1.P_arrival = 1616;
|
||||
else if (CREG != 0) \P.abc9_arrival = 1687;
|
||||
else if (AREG != 0) \P.abc9_arrival = 1632;
|
||||
else if (BREG != 0) \P.abc9_arrival = 1616;
|
||||
end
|
||||
//else
|
||||
// $error("Invalid DSP48E1 configuration");
|
||||
end
|
||||
endfunction
|
||||
function integer \DSP48E1.PCOUT_arrival ;
|
||||
function integer \PCOUT.abc9_arrival ;
|
||||
begin
|
||||
\DSP48E1.PCOUT_arrival = 0;
|
||||
\PCOUT.abc9_arrival = 0;
|
||||
if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
|
||||
if (PREG != 0) \DSP48E1.PCOUT_arrival = 435;
|
||||
if (PREG != 0) \PCOUT.abc9_arrival = 435;
|
||||
// Worst-case from CREG and MREG
|
||||
else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835;
|
||||
else if (MREG != 0) \DSP48E1.PCOUT_arrival = 1819;
|
||||
else if (CREG != 0) \PCOUT.abc9_arrival = 1835;
|
||||
else if (MREG != 0) \PCOUT.abc9_arrival = 1819;
|
||||
// Worst-case from AREG and BREG
|
||||
else if (AREG != 0) \DSP48E1.PCOUT_arrival = 3098;
|
||||
else if (BREG != 0) \DSP48E1.PCOUT_arrival = 2960;
|
||||
else if (AREG != 0) \PCOUT.abc9_arrival = 3098;
|
||||
else if (BREG != 0) \PCOUT.abc9_arrival = 2960;
|
||||
end
|
||||
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
|
||||
if (PREG != 0) \DSP48E1.PCOUT_arrival = 435;
|
||||
if (PREG != 0) \PCOUT.abc9_arrival = 435;
|
||||
// Worst-case from CREG and MREG
|
||||
else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835;
|
||||
else if (MREG != 0) \DSP48E1.PCOUT_arrival = 1819;
|
||||
else if (CREG != 0) \PCOUT.abc9_arrival = 1835;
|
||||
else if (MREG != 0) \PCOUT.abc9_arrival = 1819;
|
||||
// Worst-case from AREG, ADREG, BREG, DREG
|
||||
else if (AREG != 0) \DSP48E1.PCOUT_arrival = 4083;
|
||||
else if (DREG != 0) \DSP48E1.PCOUT_arrival = 4056;
|
||||
else if (BREG != 0) \DSP48E1.PCOUT_arrival = 2960;
|
||||
else if (ADREG != 0) \DSP48E1.PCOUT_arrival = 2859;
|
||||
else if (AREG != 0) \PCOUT.abc9_arrival = 4083;
|
||||
else if (DREG != 0) \PCOUT.abc9_arrival = 4056;
|
||||
else if (BREG != 0) \PCOUT.abc9_arrival = 2960;
|
||||
else if (ADREG != 0) \PCOUT.abc9_arrival = 2859;
|
||||
end
|
||||
else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
|
||||
if (PREG != 0) \DSP48E1.PCOUT_arrival = 435;
|
||||
if (PREG != 0) \PCOUT.abc9_arrival = 435;
|
||||
// Worst-case from AREG, BREG, CREG
|
||||
else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835;
|
||||
else if (AREG != 0) \DSP48E1.PCOUT_arrival = 1780;
|
||||
else if (BREG != 0) \DSP48E1.PCOUT_arrival = 1765;
|
||||
else if (CREG != 0) \PCOUT.abc9_arrival = 1835;
|
||||
else if (AREG != 0) \PCOUT.abc9_arrival = 1780;
|
||||
else if (BREG != 0) \PCOUT.abc9_arrival = 1765;
|
||||
end
|
||||
//else
|
||||
// $error("Invalid DSP48E1 configuration");
|
||||
|
|
|
@ -180,18 +180,58 @@ CELLS = [
|
|||
Cell('RAMB18E1', port_attrs={
|
||||
'CLKARDCLK': ['clkbuf_sink'],
|
||||
'CLKBWRCLK': ['clkbuf_sink'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L143
|
||||
'DOADO': ['abc9_arrival=2454'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L163
|
||||
'DOBDO': ['abc9_arrival=2454'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L144
|
||||
'DOPADOP': ['abc9_arrival=2454'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L164
|
||||
'DOPBDOP': ['abc9_arrival=2454'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L13
|
||||
'ADDRARDADDR': ['abc9_required=566'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L17
|
||||
'ADDRBWRADDR': ['abc9_required=566'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L19
|
||||
'WEA': ['abc9_required=532'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L21
|
||||
'WEBWE': ['abc9_required=532'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L123
|
||||
'DIADI': ['abc9_required=737'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L133
|
||||
'DIBDI': ['abc9_required=737'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L125
|
||||
'DIPADIP': ['abc9_required=737'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L135
|
||||
'DIPBDIP': ['abc9_required=737'],
|
||||
}),
|
||||
Cell('RAMB36E1', port_attrs={
|
||||
'CLKARDCLK': ['clkbuf_sink'],
|
||||
'CLKBWRCLK': ['clkbuf_sink'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L143
|
||||
'DOADO': ['abc9_arrival=2454'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L163
|
||||
'DOBDO': ['abc9_arrival=2454'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L144
|
||||
'DOPADOP': ['abc9_arrival=2454'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L164
|
||||
'DOPBDOP': ['abc9_arrival=2454'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L13
|
||||
'ADDRARDADDR': ['abc9_required=566'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L17
|
||||
'ADDRBWRADDR': ['abc9_required=566'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L19
|
||||
'WEA': ['abc9_required=532'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L21
|
||||
'WEBWE': ['abc9_required=532'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L123
|
||||
'DIADI': ['abc9_required=737'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L133
|
||||
'DIBDI': ['abc9_required=737'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L125
|
||||
'DIPADIP': ['abc9_required=737'],
|
||||
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L135
|
||||
'DIPBDIP': ['abc9_required=737'],
|
||||
}),
|
||||
# Ultrascale.
|
||||
Cell('FIFO18E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
|
||||
|
@ -209,7 +249,7 @@ CELLS = [
|
|||
# Cell('MULT18X18SIO', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3E
|
||||
# Cell('DSP48A', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3A DSP
|
||||
# Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 6
|
||||
Cell('DSP48', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 4
|
||||
# Cell('DSP48', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 4
|
||||
Cell('DSP48E', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 5
|
||||
#Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 6 / Series 7
|
||||
Cell('DSP48E2', port_attrs={'CLK': ['clkbuf_sink']}), # Ultrascale
|
||||
|
|
|
@ -4518,13 +4518,21 @@ module RAMB18E1 (...);
|
|||
input RSTREGARSTREG;
|
||||
(* invertible_pin = "IS_RSTREGB_INVERTED" *)
|
||||
input RSTREGB;
|
||||
(* abc9_required=566 *)
|
||||
input [13:0] ADDRARDADDR;
|
||||
(* abc9_required=566 *)
|
||||
input [13:0] ADDRBWRADDR;
|
||||
(* abc9_required=737 *)
|
||||
input [15:0] DIADI;
|
||||
(* abc9_required=737 *)
|
||||
input [15:0] DIBDI;
|
||||
(* abc9_required=737 *)
|
||||
input [1:0] DIPADIP;
|
||||
(* abc9_required=737 *)
|
||||
input [1:0] DIPBDIP;
|
||||
(* abc9_required=532 *)
|
||||
input [1:0] WEA;
|
||||
(* abc9_required=532 *)
|
||||
input [3:0] WEBWE;
|
||||
endmodule
|
||||
|
||||
|
@ -4742,13 +4750,21 @@ module RAMB36E1 (...);
|
|||
input REGCEB;
|
||||
input INJECTDBITERR;
|
||||
input INJECTSBITERR;
|
||||
(* abc9_required=566 *)
|
||||
input [15:0] ADDRARDADDR;
|
||||
(* abc9_required=566 *)
|
||||
input [15:0] ADDRBWRADDR;
|
||||
(* abc9_required=737 *)
|
||||
input [31:0] DIADI;
|
||||
(* abc9_required=737 *)
|
||||
input [31:0] DIBDI;
|
||||
(* abc9_required=737 *)
|
||||
input [3:0] DIPADIP;
|
||||
(* abc9_required=737 *)
|
||||
input [3:0] DIPBDIP;
|
||||
(* abc9_required=532 *)
|
||||
input [3:0] WEA;
|
||||
(* abc9_required=532 *)
|
||||
input [7:0] WEBWE;
|
||||
endmodule
|
||||
|
||||
|
@ -5476,49 +5492,6 @@ module URAM288_BASE (...);
|
|||
input SLEEP;
|
||||
endmodule
|
||||
|
||||
module DSP48 (...);
|
||||
parameter integer AREG = 1;
|
||||
parameter integer BREG = 1;
|
||||
parameter B_INPUT = "DIRECT";
|
||||
parameter integer CARRYINREG = 1;
|
||||
parameter integer CARRYINSELREG = 1;
|
||||
parameter integer CREG = 1;
|
||||
parameter LEGACY_MODE = "MULT18X18S";
|
||||
parameter integer MREG = 1;
|
||||
parameter integer OPMODEREG = 1;
|
||||
parameter integer PREG = 1;
|
||||
parameter integer SUBTRACTREG = 1;
|
||||
output [17:0] BCOUT;
|
||||
output [47:0] P;
|
||||
output [47:0] PCOUT;
|
||||
input [17:0] A;
|
||||
input [17:0] B;
|
||||
input [17:0] BCIN;
|
||||
input [47:0] C;
|
||||
input CARRYIN;
|
||||
input [1:0] CARRYINSEL;
|
||||
input CEA;
|
||||
input CEB;
|
||||
input CEC;
|
||||
input CECARRYIN;
|
||||
input CECINSUB;
|
||||
input CECTRL;
|
||||
input CEM;
|
||||
input CEP;
|
||||
(* clkbuf_sink *)
|
||||
input CLK;
|
||||
input [6:0] OPMODE;
|
||||
input [47:0] PCIN;
|
||||
input RSTA;
|
||||
input RSTB;
|
||||
input RSTC;
|
||||
input RSTCARRYIN;
|
||||
input RSTCTRL;
|
||||
input RSTM;
|
||||
input RSTP;
|
||||
input SUBTRACT;
|
||||
endmodule
|
||||
|
||||
module DSP48E (...);
|
||||
parameter SIM_MODE = "SAFE";
|
||||
parameter integer ACASCREG = 1;
|
||||
|
|
|
@ -29,90 +29,65 @@ module \$lut (A, Y);
|
|||
input [WIDTH-1:0] A;
|
||||
output Y;
|
||||
|
||||
// Need to swap input ordering, and fix init accordingly,
|
||||
// to match ABC's expectation of LUT inputs in non-decreasing
|
||||
// delay order
|
||||
function [WIDTH-1:0] permute_index;
|
||||
input [WIDTH-1:0] i;
|
||||
integer j;
|
||||
begin
|
||||
permute_index = 0;
|
||||
for (j = 0; j < WIDTH; j = j + 1)
|
||||
permute_index[WIDTH-1 - j] = i[j];
|
||||
end
|
||||
endfunction
|
||||
|
||||
function [2**WIDTH-1:0] permute_init;
|
||||
input [2**WIDTH-1:0] orig;
|
||||
integer i;
|
||||
begin
|
||||
permute_init = 0;
|
||||
for (i = 0; i < 2**WIDTH; i = i + 1)
|
||||
permute_init[i] = orig[permute_index(i)];
|
||||
end
|
||||
endfunction
|
||||
|
||||
parameter [2**WIDTH-1:0] P_LUT = permute_init(LUT);
|
||||
|
||||
generate
|
||||
if (WIDTH == 1) begin
|
||||
if (P_LUT == 2'b01) begin
|
||||
if (LUT == 2'b01) begin
|
||||
INV _TECHMAP_REPLACE_ (.O(Y), .I(A[0]));
|
||||
end else begin
|
||||
LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]));
|
||||
end
|
||||
end else
|
||||
if (WIDTH == 2) begin
|
||||
LUT2 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[1]), .I1(A[0]));
|
||||
LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]), .I1(A[1]));
|
||||
end else
|
||||
if (WIDTH == 3) begin
|
||||
LUT3 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[2]), .I1(A[1]), .I2(A[0]));
|
||||
LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]));
|
||||
end else
|
||||
if (WIDTH == 4) begin
|
||||
LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[3]), .I1(A[2]), .I2(A[1]),
|
||||
.I3(A[0]));
|
||||
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]));
|
||||
end else
|
||||
if (WIDTH == 5) begin
|
||||
LUT5 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[4]), .I1(A[3]), .I2(A[2]),
|
||||
.I3(A[1]), .I4(A[0]));
|
||||
LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]));
|
||||
end else
|
||||
if (WIDTH == 6) begin
|
||||
LUT6 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[5]), .I1(A[4]), .I2(A[3]),
|
||||
.I3(A[2]), .I4(A[1]), .I5(A[0]));
|
||||
LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
end else
|
||||
if (WIDTH == 7) begin
|
||||
wire T0, T1;
|
||||
LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||
.I0(A[6]), .I1(A[5]), .I2(A[4]),
|
||||
.I3(A[3]), .I4(A[2]), .I5(A[1]));
|
||||
LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||
.I0(A[6]), .I1(A[5]), .I2(A[4]),
|
||||
.I3(A[3]), .I4(A[2]), .I5(A[1]));
|
||||
MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[0]));
|
||||
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6]));
|
||||
end else
|
||||
if (WIDTH == 8) begin
|
||||
wire T0, T1, T2, T3, T4, T5;
|
||||
LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||
LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||
LUT6 #(.INIT(P_LUT[191:128])) fpga_lut_2 (.O(T2),
|
||||
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||
LUT6 #(.INIT(P_LUT[255:192])) fpga_lut_3 (.O(T3),
|
||||
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||
MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[1]));
|
||||
MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[1]));
|
||||
MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[0]));
|
||||
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6]));
|
||||
MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6]));
|
||||
MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7]));
|
||||
end else begin
|
||||
wire _TECHMAP_FAIL_ = 1;
|
||||
end
|
||||
|
|
|
@ -153,7 +153,7 @@ endmatch
|
|||
|
||||
match $__XILINX_RAM32X2Q
|
||||
min bits 5
|
||||
min rports 3
|
||||
min rports 2
|
||||
min wports 1
|
||||
make_outreg
|
||||
or_next_if_better
|
||||
|
@ -161,7 +161,7 @@ endmatch
|
|||
|
||||
match $__XILINX_RAM64X1Q
|
||||
min bits 5
|
||||
min rports 3
|
||||
min rports 2
|
||||
min wports 1
|
||||
make_outreg
|
||||
endmatch
|
||||
|
|
|
@ -316,7 +316,11 @@ struct SynthXilinxPass : public ScriptPass
|
|||
run("proc");
|
||||
if (flatten || help_mode)
|
||||
run("flatten", "(with '-flatten')");
|
||||
if (active_design)
|
||||
active_design->scratchpad_unset("tribuf.added_something");
|
||||
run("tribuf -logic");
|
||||
if (noiopad && active_design && active_design->scratchpad_get_bool("tribuf.added_something"))
|
||||
log_error("Tristate buffers are unsupported without the '-iopad' option.\n");
|
||||
run("deminout");
|
||||
run("opt_expr");
|
||||
run("opt_clean");
|
||||
|
@ -526,7 +530,7 @@ struct SynthXilinxPass : public ScriptPass
|
|||
if (check_label("map_cells")) {
|
||||
// Needs to be done before logic optimization, so that inverters (OE vs T) are handled.
|
||||
if (help_mode || !noiopad)
|
||||
run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top", "(only if not '-noiopad')");
|
||||
run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top", "(skip if '-noiopad')");
|
||||
std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v";
|
||||
if (widemux > 0)
|
||||
techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
|
||||
|
@ -589,17 +593,16 @@ struct SynthXilinxPass : public ScriptPass
|
|||
if (!nosrl || help_mode)
|
||||
run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')");
|
||||
std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v";
|
||||
if (help_mode)
|
||||
techmap_args += stringf("[-map %s]", ff_map_file.c_str());
|
||||
else if (!abc9)
|
||||
if (help_mode || !abc9)
|
||||
techmap_args += stringf(" -map %s", ff_map_file.c_str());
|
||||
run("techmap " + techmap_args, "(only if '-abc9')");
|
||||
run("techmap " + techmap_args);
|
||||
run("xilinx_dffopt");
|
||||
run("opt_lut_ins -tech xilinx");
|
||||
}
|
||||
|
||||
if (check_label("finalize")) {
|
||||
if (help_mode || !noclkbuf)
|
||||
run("clkbufmap -buf BUFG O:I ", "(skip if '-noclkbuf')");
|
||||
run("clkbufmap -buf BUFG O:I", "(skip if '-noclkbuf')");
|
||||
if (help_mode || ise)
|
||||
run("extractinv -inv INV O:I", "(only if '-ise')");
|
||||
run("clean");
|
||||
|
|
|
@ -12,4 +12,7 @@ test_dsp48a_model_ref.v
|
|||
test_dsp48a1_model_ref.v
|
||||
test_dsp48a1_model_uut.v
|
||||
test_dsp48a1_model
|
||||
test_dsp48_model_ref.v
|
||||
test_dsp48_model_uut.v
|
||||
test_dsp48_model
|
||||
*.vcd
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
set -ex
|
||||
if [ -z $ISE_DIR ]; then
|
||||
ISE_DIR=/opt/Xilinx/ISE/14.7
|
||||
fi
|
||||
sed 's/DSP48 /DSP48_UUT /; /DSP48_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp48_model_uut.v
|
||||
if [ ! -f "test_dsp48_model_ref.v" ]; then
|
||||
cp $ISE_DIR/ISE_DS/ISE/verilog/src/unisims/DSP48.v test_dsp48_model_ref.v
|
||||
fi
|
||||
for tb in mult_allreg mult_noreg mult_inreg
|
||||
do
|
||||
iverilog -s $tb -s glbl -o test_dsp48_model test_dsp48_model.v test_dsp48_model_uut.v test_dsp48_model_ref.v $ISE_DIR/ISE_DS/ISE/verilog/src/glbl.v
|
||||
vvp -N ./test_dsp48_model
|
||||
done
|
|
@ -0,0 +1,287 @@
|
|||
`timescale 1ns / 1ps
|
||||
|
||||
module testbench;
|
||||
parameter integer AREG = 1;
|
||||
parameter integer BREG = 1;
|
||||
parameter integer CREG = 1;
|
||||
parameter integer MREG = 1;
|
||||
parameter integer PREG = 1;
|
||||
parameter integer CARRYINREG = 1;
|
||||
parameter integer CARRYINSELREG = 1;
|
||||
parameter integer OPMODEREG = 1;
|
||||
parameter integer SUBTRACTREG = 1;
|
||||
parameter B_INPUT = "DIRECT";
|
||||
parameter LEGACY_MODE = "NONE";
|
||||
|
||||
reg CLK;
|
||||
reg CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL;
|
||||
reg RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL;
|
||||
reg [17:0] A;
|
||||
reg [17:0] B;
|
||||
reg [47:0] C;
|
||||
reg [17:0] BCIN;
|
||||
reg [47:0] PCIN;
|
||||
reg CARRYIN;
|
||||
reg [6:0] OPMODE;
|
||||
reg SUBTRACT;
|
||||
reg [1:0] CARRYINSEL;
|
||||
|
||||
output [47:0] P, REF_P;
|
||||
output [17:0] BCOUT, REF_BCOUT;
|
||||
output [47:0] PCOUT, REF_PCOUT;
|
||||
|
||||
integer errcount = 0;
|
||||
|
||||
reg ERROR_FLAG = 0;
|
||||
|
||||
task clkcycle;
|
||||
begin
|
||||
#5;
|
||||
CLK = ~CLK;
|
||||
#10;
|
||||
CLK = ~CLK;
|
||||
#2;
|
||||
ERROR_FLAG = 0;
|
||||
if (REF_BCOUT !== BCOUT) begin
|
||||
$display("ERROR at %1t: REF_BCOUT=%b UUT_BCOUT=%b DIFF=%b", $time, REF_BCOUT, BCOUT, REF_BCOUT ^ BCOUT);
|
||||
errcount = errcount + 1;
|
||||
ERROR_FLAG = 1;
|
||||
end
|
||||
if (REF_P !== P) begin
|
||||
$display("ERROR at %1t: REF_P=%b UUT_P=%b DIFF=%b", $time, REF_P, P, REF_P ^ P);
|
||||
errcount = errcount + 1;
|
||||
ERROR_FLAG = 1;
|
||||
end
|
||||
if (REF_PCOUT !== PCOUT) begin
|
||||
$display("ERROR at %1t: REF_PCOUT=%b UUT_PCOUT=%b DIFF=%b", $time, REF_PCOUT, PCOUT, REF_PCOUT ^ PCOUT);
|
||||
errcount = errcount + 1;
|
||||
ERROR_FLAG = 1;
|
||||
end
|
||||
#3;
|
||||
end
|
||||
endtask
|
||||
|
||||
reg config_valid = 0;
|
||||
task drc;
|
||||
begin
|
||||
config_valid = 1;
|
||||
|
||||
if (OPMODE[1:0] == 2'b10 && PREG != 1) config_valid = 0;
|
||||
if (OPMODE[1:0] == 2'b00 && CARRYINSEL == 2'b10) config_valid = 0;
|
||||
if (OPMODE[1:0] == 2'b10 && CARRYINSEL == 2'b10) config_valid = 0;
|
||||
if (OPMODE[1:0] == 2'b00 && CARRYINSEL == 2'b11) config_valid = 0;
|
||||
if (OPMODE[1:0] == 2'b10 && CARRYINSEL == 2'b11) config_valid = 0;
|
||||
if (OPMODE[3:2] == 2'b10) config_valid = 0;
|
||||
if ((OPMODE[3:2] == 2'b01) ^ (OPMODE[1:0] == 2'b01) == 1'b1) config_valid = 0;
|
||||
if ((OPMODE[6:4] == 3'b010 || OPMODE[6:4] == 3'b110) && PREG != 1) config_valid = 0;
|
||||
if (OPMODE[6:4] == 3'b100) config_valid = 0;
|
||||
if (OPMODE[6:4] == 3'b111) config_valid = 0;
|
||||
if (OPMODE[6:4] == 3'b000 && CARRYINSEL == 2'b01) config_valid = 0;
|
||||
if (OPMODE[6:4] == 3'b011 && CARRYINSEL == 2'b01) config_valid = 0;
|
||||
|
||||
// Xilinx models consider these combinations invalid for an unknown reason.
|
||||
if (CARRYINSEL == 2'b01 && OPMODE[3:2] == 2'b00) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b10 && OPMODE == 7'b0000011) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b10 && OPMODE == 7'b0000101) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b10 && OPMODE == 7'b0100011) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b10 && OPMODE == 7'b0111111) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b10 && OPMODE == 7'b1100011) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b0000011) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b0000101) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b0011111) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b0010011) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b0100011) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b0100101) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b0101111) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b0110011) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b0111111) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b1010011) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b1011111) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b1100011) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b1100101) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE == 7'b1101111) config_valid = 0;
|
||||
|
||||
if (CARRYINSEL == 2'b10 && OPMODE[3:0] == 4'b0101 && MREG == 1) config_valid = 0;
|
||||
if (CARRYINSEL == 2'b11 && OPMODE[3:0] == 4'b0101 && MREG == 0) config_valid = 0;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
$dumpfile("test_dsp48_model.vcd");
|
||||
$dumpvars(0, testbench);
|
||||
|
||||
#2;
|
||||
CLK = 1'b0;
|
||||
{CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL} = 8'b11111111;
|
||||
{A, B, C, PCIN, OPMODE, SUBTRACT, CARRYIN, CARRYINSEL} = 0;
|
||||
{RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = 7'b1111111;
|
||||
repeat (10) begin
|
||||
#10;
|
||||
CLK = 1'b1;
|
||||
#10;
|
||||
CLK = 1'b0;
|
||||
#10;
|
||||
CLK = 1'b1;
|
||||
#10;
|
||||
CLK = 1'b0;
|
||||
end
|
||||
{RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = 0;
|
||||
|
||||
repeat (100000) begin
|
||||
clkcycle;
|
||||
config_valid = 0;
|
||||
while (!config_valid) begin
|
||||
A = $urandom;
|
||||
B = $urandom;
|
||||
C = {$urandom, $urandom};
|
||||
BCIN = $urandom;
|
||||
PCIN = {$urandom, $urandom};
|
||||
|
||||
{CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL} = $urandom | $urandom | $urandom;
|
||||
{RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = $urandom & $urandom & $urandom & $urandom & $urandom & $urandom;
|
||||
{CARRYIN, CARRYINSEL, OPMODE, SUBTRACT} = $urandom;
|
||||
|
||||
drc;
|
||||
end
|
||||
end
|
||||
|
||||
if (errcount == 0) begin
|
||||
$display("All tests passed.");
|
||||
$finish;
|
||||
end else begin
|
||||
$display("Caught %1d errors.", errcount);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
DSP48 #(
|
||||
.AREG (AREG),
|
||||
.BREG (BREG),
|
||||
.CREG (CREG),
|
||||
.MREG (MREG),
|
||||
.PREG (PREG),
|
||||
.CARRYINREG (CARRYINREG),
|
||||
.CARRYINSELREG (CARRYINSELREG),
|
||||
.OPMODEREG (OPMODEREG),
|
||||
.SUBTRACTREG (SUBTRACTREG),
|
||||
.B_INPUT (B_INPUT),
|
||||
.LEGACY_MODE (LEGACY_MODE)
|
||||
) ref (
|
||||
.A (A),
|
||||
.B (B),
|
||||
.C (C),
|
||||
.BCIN (BCIN),
|
||||
.PCIN (PCIN),
|
||||
.CARRYIN (CARRYIN),
|
||||
.OPMODE (OPMODE),
|
||||
.SUBTRACT (SUBTRACT),
|
||||
.CARRYINSEL (CARRYINSEL),
|
||||
.BCOUT (REF_BCOUT),
|
||||
.P (REF_P),
|
||||
.PCOUT (REF_PCOUT),
|
||||
.CEA (CEA),
|
||||
.CEB (CEB),
|
||||
.CEC (CEC),
|
||||
.CEM (CEM),
|
||||
.CEP (CEP),
|
||||
.CECARRYIN (CECARRYIN),
|
||||
.CECINSUB (CECINSUB),
|
||||
.CECTRL (CECTRL),
|
||||
.CLK (CLK),
|
||||
.RSTA (RSTA),
|
||||
.RSTB (RSTB),
|
||||
.RSTC (RSTC),
|
||||
.RSTM (RSTM),
|
||||
.RSTP (RSTP),
|
||||
.RSTCARRYIN (RSTCARRYIN),
|
||||
.RSTCTRL (RSTCTRL)
|
||||
);
|
||||
|
||||
DSP48_UUT #(
|
||||
.AREG (AREG),
|
||||
.BREG (BREG),
|
||||
.CREG (CREG),
|
||||
.MREG (MREG),
|
||||
.PREG (PREG),
|
||||
.CARRYINREG (CARRYINREG),
|
||||
.CARRYINSELREG (CARRYINSELREG),
|
||||
.OPMODEREG (OPMODEREG),
|
||||
.SUBTRACTREG (SUBTRACTREG),
|
||||
.B_INPUT (B_INPUT),
|
||||
.LEGACY_MODE (LEGACY_MODE)
|
||||
) uut (
|
||||
.A (A),
|
||||
.B (B),
|
||||
.C (C),
|
||||
.BCIN (BCIN),
|
||||
.PCIN (PCIN),
|
||||
.CARRYIN (CARRYIN),
|
||||
.OPMODE (OPMODE),
|
||||
.SUBTRACT (SUBTRACT),
|
||||
.CARRYINSEL (CARRYINSEL),
|
||||
.BCOUT (BCOUT),
|
||||
.P (P),
|
||||
.PCOUT (PCOUT),
|
||||
.CEA (CEA),
|
||||
.CEB (CEB),
|
||||
.CEC (CEC),
|
||||
.CEM (CEM),
|
||||
.CEP (CEP),
|
||||
.CECARRYIN (CECARRYIN),
|
||||
.CECINSUB (CECINSUB),
|
||||
.CECTRL (CECTRL),
|
||||
.CLK (CLK),
|
||||
.RSTA (RSTA),
|
||||
.RSTB (RSTB),
|
||||
.RSTC (RSTC),
|
||||
.RSTM (RSTM),
|
||||
.RSTP (RSTP),
|
||||
.RSTCARRYIN (RSTCARRYIN),
|
||||
.RSTCTRL (RSTCTRL)
|
||||
);
|
||||
endmodule
|
||||
|
||||
module mult_noreg;
|
||||
testbench #(
|
||||
.AREG (0),
|
||||
.BREG (0),
|
||||
.CREG (0),
|
||||
.MREG (0),
|
||||
.PREG (0),
|
||||
.CARRYINREG (0),
|
||||
.CARRYINSELREG (0),
|
||||
.OPMODEREG (0),
|
||||
.SUBTRACTREG (0),
|
||||
.B_INPUT ("DIRECT")
|
||||
) testbench ();
|
||||
endmodule
|
||||
|
||||
module mult_allreg;
|
||||
testbench #(
|
||||
.AREG (1),
|
||||
.BREG (1),
|
||||
.CREG (1),
|
||||
.MREG (1),
|
||||
.PREG (1),
|
||||
.CARRYINREG (1),
|
||||
.CARRYINSELREG (1),
|
||||
.OPMODEREG (1),
|
||||
.SUBTRACTREG (1),
|
||||
.B_INPUT ("CASCADE")
|
||||
) testbench ();
|
||||
endmodule
|
||||
|
||||
module mult_inreg;
|
||||
testbench #(
|
||||
.AREG (1),
|
||||
.BREG (1),
|
||||
.CREG (1),
|
||||
.MREG (0),
|
||||
.PREG (0),
|
||||
.CARRYINREG (1),
|
||||
.CARRYINSELREG (0),
|
||||
.OPMODEREG (0),
|
||||
.SUBTRACTREG (0),
|
||||
.B_INPUT ("DIRECT")
|
||||
) testbench ();
|
||||
endmodule
|
|
@ -0,0 +1,32 @@
|
|||
read_ilang << EOF
|
||||
|
||||
module \top
|
||||
|
||||
wire input 1 \A
|
||||
wire input 2 \B
|
||||
wire input 3 \C
|
||||
wire input 4 \D
|
||||
|
||||
wire output 5 \Z
|
||||
|
||||
cell \LUT4 $0
|
||||
parameter \INIT 16'1111110011000000
|
||||
connect \A \A
|
||||
connect \B \B
|
||||
connect \C \C
|
||||
connect \D \D
|
||||
connect \Z \Z
|
||||
end
|
||||
end
|
||||
|
||||
EOF
|
||||
|
||||
read_verilog -lib +/ecp5/cells_sim.v
|
||||
|
||||
equiv_opt -assert -map +/ecp5/cells_sim.v opt_lut_ins -tech ecp5
|
||||
|
||||
design -load postopt
|
||||
|
||||
select -assert-count 1 top/t:LUT4
|
||||
select -assert-count 0 top/w:A %co top/t:LUT4 %i
|
||||
select -assert-count 1 top/w:B %co top/t:LUT4 %i
|
|
@ -36,6 +36,6 @@ proc
|
|||
equiv_opt -assert -map +/efinix/cells_sim.v synth_efinix # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd mux16 # Constrain all select calls below inside the top module
|
||||
select -assert-count 11 t:EFX_LUT4
|
||||
select -assert-max 12 t:EFX_LUT4
|
||||
|
||||
select -assert-none t:EFX_LUT4 %% t:* %D
|
||||
|
|
|
@ -18,13 +18,13 @@ proc
|
|||
equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd mux4 # Constrain all select calls below inside the top module
|
||||
select -assert-count 4 t:LUT4
|
||||
select -assert-count 4 t:LUT*
|
||||
select -assert-count 2 t:MUX2_LUT5
|
||||
select -assert-count 1 t:MUX2_LUT6
|
||||
select -assert-count 6 t:IBUF
|
||||
select -assert-count 1 t:OBUF
|
||||
|
||||
select -assert-none t:LUT4 t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D
|
||||
select -assert-none t:LUT* t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D
|
||||
|
||||
design -load read
|
||||
hierarchy -top mux8
|
||||
|
@ -35,7 +35,7 @@ cd mux8 # Constrain all select calls below inside the top module
|
|||
select -assert-count 11 t:IBUF
|
||||
select -assert-count 1 t:OBUF
|
||||
|
||||
select -assert-none t:LUT4 t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D
|
||||
select -assert-none t:LUT* t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D
|
||||
|
||||
design -load read
|
||||
hierarchy -top mux16
|
||||
|
@ -46,4 +46,4 @@ cd mux16 # Constrain all select calls below inside the top module
|
|||
select -assert-count 20 t:IBUF
|
||||
select -assert-count 1 t:OBUF
|
||||
|
||||
select -assert-none t:LUT4 t:MUX2_LUT6 t:MUX2_LUT5 t:MUX2_LUT6 t:MUX2_LUT7 t:MUX2_LUT8 t:IBUF t:OBUF %% t:* %D
|
||||
select -assert-none t:GND t:VCC t:LUT* t:MUX2_LUT6 t:MUX2_LUT5 t:MUX2_LUT6 t:MUX2_LUT7 t:MUX2_LUT8 t:IBUF t:OBUF %% t:* %D
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
read_verilog <<EOT
|
||||
module top (
|
||||
input CLK, PIN_1, PIN_2, PIN_3, PIN_4, PIN_5,
|
||||
PIN_6, PIN_7, PIN_8, PIN_9, PIN_10, PIN_11, PIN_12, PIN_13, PIN_25,
|
||||
output USBPU, PIN_14, PIN_15, PIN_16, PIN_17, PIN_18,
|
||||
PIN_19, PIN_20, PIN_21, PIN_22, PIN_23, PIN_24,
|
||||
);
|
||||
assign USBPU = 0;
|
||||
|
||||
wire[5:0] parOut;
|
||||
wire[5:0] chrg;
|
||||
|
||||
assign PIN_14 = parOut[0];
|
||||
assign PIN_15 = parOut[1];
|
||||
assign PIN_16 = parOut[2];
|
||||
assign PIN_17 = parOut[3];
|
||||
assign PIN_18 = parOut[4];
|
||||
assign PIN_19 = parOut[5];
|
||||
assign chrg[0] = PIN_3;
|
||||
assign chrg[1] = PIN_4;
|
||||
assign chrg[2] = PIN_5;
|
||||
assign chrg[3] = PIN_6;
|
||||
assign chrg[4] = PIN_7;
|
||||
assign chrg[5] = PIN_8;
|
||||
|
||||
SSCounter6o sc6(PIN_1, CLK, PIN_2, PIN_9, chrg, parOut);
|
||||
|
||||
endmodule
|
||||
|
||||
module SSCounter6 (input wire rst, clk, adv, jmp, input wire [5:0] in, output reg[5:0] out);
|
||||
always @(posedge clk, posedge rst)
|
||||
if (rst) out <= 0;
|
||||
else if (adv || jmp) out <= jmp ? in : out + 1;
|
||||
endmodule
|
||||
|
||||
// Optimized 6 bit counter, it should takes 7 cells.
|
||||
/* b[5:1] /* b[0]
|
||||
1010101010101010 in 1010101010101010 in
|
||||
1100110011001100 jmp 1100110011001100 jmp
|
||||
1111000011110000 loop 1111000011110000 loop
|
||||
1111111100000000 carry 1111111100000000 -
|
||||
---------------------- ----------------------
|
||||
1000101110111000 out 1000101110001011 out
|
||||
8 B B 8 8 B 8 B
|
||||
*/
|
||||
module SSCounter6o (input wire rst, clk, adv, jmp, input wire [5:0] in, output wire[5:0] out);
|
||||
wire[4:0] co;
|
||||
wire[5:0] lo;
|
||||
wire ien;
|
||||
SB_LUT4 #(.LUT_INIT(16'hFFF0)) lien (ien, 0, 0, adv, jmp);
|
||||
SB_CARRY c0 (co[0], jmp, out[0], 1),
|
||||
c1 (co[1], jmp, out[1], co[0]),
|
||||
c2 (co[2], jmp, out[2], co[1]),
|
||||
c3 (co[3], jmp, out[3], co[2]),
|
||||
c4 (co[4], jmp, out[4], co[3]);
|
||||
SB_DFFER d0 (out[0], clk, ien, rst, lo[0]),
|
||||
d1 (out[1], clk, ien, rst, lo[1]),
|
||||
d2 (out[2], clk, ien, rst, lo[2]),
|
||||
d3 (out[3], clk, ien, rst, lo[3]),
|
||||
d4 (out[4], clk, ien, rst, lo[4]),
|
||||
d5 (out[5], clk, ien, rst, lo[5]);
|
||||
SB_LUT4 #(.LUT_INIT(16'h8B8B)) l0 (lo[0], in[0], jmp, out[0], 0);
|
||||
SB_LUT4 #(.LUT_INIT(16'h8BB8)) l1 (lo[1], in[1], jmp, out[1], co[0]);
|
||||
SB_LUT4 #(.LUT_INIT(16'h8BB8)) l2 (lo[2], in[2], jmp, out[2], co[1]);
|
||||
SB_LUT4 #(.LUT_INIT(16'h8BB8)) l3 (lo[3], in[3], jmp, out[3], co[2]);
|
||||
SB_LUT4 #(.LUT_INIT(16'h8BB8)) l4 (lo[4], in[4], jmp, out[4], co[3]);
|
||||
SB_LUT4 #(.LUT_INIT(16'h8BB8)) l5 (lo[5], in[5], jmp, out[5], co[4]);
|
||||
endmodule
|
||||
EOT
|
||||
hierarchy -top top
|
||||
flatten
|
||||
equiv_opt -multiclock -map +/ice40/cells_sim.v synth_ice40
|
|
@ -1,23 +1,3 @@
|
|||
read_verilog -icells -formal <<EOT
|
||||
module \$__ICE40_CARRY_WRAPPER (output CO, O, input A, B, CI, I0, I3);
|
||||
parameter LUT = 0;
|
||||
SB_CARRY carry (
|
||||
.I0(A),
|
||||
.I1(B),
|
||||
.CI(CI),
|
||||
.CO(CO)
|
||||
);
|
||||
\$lut #(
|
||||
.WIDTH(4),
|
||||
.LUT(LUT)
|
||||
) lut (
|
||||
.A({I0,A,B,I3}),
|
||||
.Y(O)
|
||||
);
|
||||
endmodule
|
||||
EOT
|
||||
design -stash unmap
|
||||
|
||||
read_verilog -icells -formal <<EOT
|
||||
module top(input CI, I0, output [1:0] CO, output O);
|
||||
wire A = 1'b0, B = 1'b0;
|
||||
|
@ -26,13 +6,14 @@ module top(input CI, I0, output [1:0] CO, output O);
|
|||
// A[1]: 1100 1100 1100 1100
|
||||
// A[2]: 1111 0000 1111 0000
|
||||
// A[3]: 1111 1111 0000 0000
|
||||
.LUT(~16'b 0110_1001_1001_0110)
|
||||
.LUT(~16'b 0110_1001_1001_0110),
|
||||
.I3_IS_CI(1'b1)
|
||||
) u0 (
|
||||
.A(A),
|
||||
.B(B),
|
||||
.CI(CI),
|
||||
.I0(I0),
|
||||
.I3(CI),
|
||||
.I3(1'bx),
|
||||
.CO(CO[0]),
|
||||
.O(O)
|
||||
);
|
||||
|
@ -40,7 +21,7 @@ module top(input CI, I0, output [1:0] CO, output O);
|
|||
endmodule
|
||||
EOT
|
||||
|
||||
equiv_opt -assert -map %unmap -map +/ice40/cells_sim.v ice40_opt
|
||||
equiv_opt -assert -map +/ice40/abc9_model.v -map +/ice40/cells_sim.v ice40_opt
|
||||
design -load postopt
|
||||
select -assert-count 1 t:*
|
||||
select -assert-count 1 t:$lut
|
||||
|
@ -105,3 +86,33 @@ select -assert-count 1 t:SB_LUT4
|
|||
select -assert-count 1 t:SB_CARRY
|
||||
select -assert-count 1 t:SB_CARRY a:keep %i
|
||||
select -assert-count 1 t:SB_CARRY c:carry %i
|
||||
|
||||
|
||||
design -reset
|
||||
read_verilog -icells <<EOT
|
||||
module top(input I3, I2, I1, I0, output O, O2);
|
||||
SB_LUT4 #(
|
||||
.LUT_INIT(8'b 1001_0110)
|
||||
) u0 (
|
||||
.I0(I0),
|
||||
.I1(I1),
|
||||
.I2(I2),
|
||||
.I3(),
|
||||
.O(O)
|
||||
);
|
||||
wire CO;
|
||||
\$__ICE40_CARRY_WRAPPER #(
|
||||
.LUT(~8'b 1001_0110),
|
||||
.I3_IS_CI(1'b0)
|
||||
) u1 (
|
||||
.A(1'b0),
|
||||
.B(1'b0),
|
||||
.CI(1'b0),
|
||||
.I0(),
|
||||
.I3(),
|
||||
.CO(CO),
|
||||
.O(O2)
|
||||
);
|
||||
endmodule
|
||||
EOT
|
||||
ice40_opt
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
read_ilang << EOF
|
||||
|
||||
module \top
|
||||
|
||||
wire width 4 input 1 \A
|
||||
|
||||
wire output 2 \O
|
||||
|
||||
cell \LUT4 $0
|
||||
parameter \INIT 16'1111110011000000
|
||||
connect \I0 \A [0]
|
||||
connect \I1 \A [1]
|
||||
connect \I2 \A [2]
|
||||
connect \I3 \A [3]
|
||||
connect \O \O
|
||||
end
|
||||
end
|
||||
|
||||
EOF
|
||||
|
||||
equiv_opt -assert -map +/xilinx/cells_sim.v opt_lut_ins -tech xilinx
|
||||
|
||||
design -load postopt
|
||||
|
||||
select -assert-count 1 t:LUT3
|
|
@ -0,0 +1,5 @@
|
|||
! ../../../yosys ../common/tribuf.v -qp "synth_xilinx"
|
||||
../../../yosys ../common/tribuf.v -qp "synth_xilinx -iopad; \
|
||||
select -assert-count 2 t:IBUF; \
|
||||
select -assert-count 1 t:INV; \
|
||||
select -assert-count 1 t:OBUFT"
|
|
@ -0,0 +1,23 @@
|
|||
read_ilang << EOF
|
||||
|
||||
module \top
|
||||
|
||||
wire width 4 input 1 \A
|
||||
|
||||
wire output 2 \Y
|
||||
|
||||
cell $lut \lut
|
||||
parameter \LUT 16'1111110011000000
|
||||
parameter \WIDTH 4
|
||||
connect \A \A
|
||||
connect \Y \Y
|
||||
end
|
||||
end
|
||||
|
||||
EOF
|
||||
|
||||
equiv_opt -assert opt_lut_ins
|
||||
|
||||
design -load postopt
|
||||
|
||||
select -assert-count 1 t:$lut r:WIDTH=3 %i
|
|
@ -0,0 +1,66 @@
|
|||
read_verilog -icells <<EOT
|
||||
module top(input clk, d, s, r, output reg [17:0] q);
|
||||
always @(posedge clk or posedge s) if ( s) q[ 0] <= 1'b1; else q[ 0] <= d;
|
||||
always @(posedge clk or negedge s) if (!s) q[ 1] <= 1'b1; else q[ 1] <= d;
|
||||
always @(posedge clk or posedge r) if ( r) q[ 2] <= 1'b0; else q[ 2] <= d;
|
||||
always @(posedge clk or negedge r) if (!r) q[ 3] <= 1'b0; else q[ 3] <= d;
|
||||
always @(negedge clk or posedge s) if ( s) q[ 4] <= 1'b1; else q[ 4] <= d;
|
||||
always @(negedge clk or negedge s) if (!s) q[ 5] <= 1'b1; else q[ 5] <= d;
|
||||
always @(negedge clk or posedge r) if ( r) q[ 6] <= 1'b0; else q[ 6] <= d;
|
||||
always @(negedge clk or negedge r) if (!r) q[ 7] <= 1'b0; else q[ 7] <= d;
|
||||
|
||||
// Seems like proc_dlatch always sets {SET,CLR}_POLARITY to true
|
||||
always @(posedge clk or posedge s or posedge r) if ( r) q[ 8] <= 1'b0; else if ( s) q[ 8] <= 1'b1; else q[ 8] <= d;
|
||||
//always @(posedge clk or posedge s or negedge r) if (!r) q[ 9] <= 1'b0; else if ( s) q[ 9] <= 1'b1; else q[ 9] <= d;
|
||||
//always @(posedge clk or negedge s or posedge r) if ( r) q[10] <= 1'b0; else if (!s) q[10] <= 1'b1; else q[10] <= d;
|
||||
//always @(posedge clk or negedge s or negedge r) if (!r) q[11] <= 1'b0; else if (!s) q[11] <= 1'b1; else q[11] <= d;
|
||||
$dffsr #(.CLK_POLARITY(1'h1), .CLR_POLARITY(1'h0), .SET_POLARITY(1'h1), .WIDTH(32'd1)) ppn (.CLK(clk), .CLR(r), .D(d), .Q(q[ 9]), .SET(s));
|
||||
$dffsr #(.CLK_POLARITY(1'h1), .CLR_POLARITY(1'h1), .SET_POLARITY(1'h0), .WIDTH(32'd1)) pnp (.CLK(clk), .CLR(r), .D(d), .Q(q[10]), .SET(s));
|
||||
$dffsr #(.CLK_POLARITY(1'h1), .CLR_POLARITY(1'h0), .SET_POLARITY(1'h0), .WIDTH(32'd1)) pnn (.CLK(clk), .CLR(r), .D(d), .Q(q[11]), .SET(s));
|
||||
|
||||
always @(negedge clk or posedge s or posedge r) if ( r) q[12] <= 1'b0; else if ( s) q[12] <= 1'b1; else q[12] <= d;
|
||||
//always @(negedge clk or posedge s or negedge r) if (!r) q[13] <= 1'b0; else if ( s) q[13] <= 1'b1; else q[13] <= d;
|
||||
//always @(negedge clk or negedge s or posedge r) if ( r) q[14] <= 1'b0; else if (!s) q[14] <= 1'b1; else q[14] <= d;
|
||||
//always @(negedge clk or negedge s or negedge r) if (!r) q[15] <= 1'b0; else if (!s) q[15] <= 1'b1; else q[15] <= d;
|
||||
$dffsr #(.CLK_POLARITY(1'h0), .CLR_POLARITY(1'h0), .SET_POLARITY(1'h1), .WIDTH(32'd1)) npn (.CLK(clk), .CLR(r), .D(d), .Q(q[13]), .SET(s));
|
||||
$dffsr #(.CLK_POLARITY(1'h0), .CLR_POLARITY(1'h1), .SET_POLARITY(1'h0), .WIDTH(32'd1)) nnp (.CLK(clk), .CLR(r), .D(d), .Q(q[14]), .SET(s));
|
||||
$dffsr #(.CLK_POLARITY(1'h0), .CLR_POLARITY(1'h0), .SET_POLARITY(1'h0), .WIDTH(32'd1)) nnn (.CLK(clk), .CLR(r), .D(d), .Q(q[15]), .SET(s));
|
||||
|
||||
always @(posedge clk) q[16] <= d;
|
||||
always @(negedge clk) q[17] <= d;
|
||||
endmodule
|
||||
EOT
|
||||
proc
|
||||
select -assert-count 8 t:$adff
|
||||
select -assert-count 8 t:$dffsr
|
||||
select -assert-count 2 t:$dff
|
||||
design -save gold
|
||||
|
||||
simplemap
|
||||
select -assert-count 1 t:$_DFF_NN0_
|
||||
select -assert-count 1 t:$_DFF_NN1_
|
||||
select -assert-count 1 t:$_DFF_NP0_
|
||||
select -assert-count 1 t:$_DFF_NP1_
|
||||
select -assert-count 1 t:$_DFF_PN0_
|
||||
select -assert-count 1 t:$_DFF_PN1_
|
||||
select -assert-count 1 t:$_DFF_PP0_
|
||||
select -assert-count 1 t:$_DFF_PP1_
|
||||
stat
|
||||
select -assert-count 1 t:$_DFFSR_NNN_
|
||||
select -assert-count 1 t:$_DFFSR_NNP_
|
||||
select -assert-count 1 t:$_DFFSR_NPN_
|
||||
select -assert-count 1 t:$_DFFSR_NPP_
|
||||
select -assert-count 1 t:$_DFFSR_PNN_
|
||||
select -assert-count 1 t:$_DFFSR_PNP_
|
||||
select -assert-count 1 t:$_DFFSR_PPN_
|
||||
select -assert-count 1 t:$_DFFSR_PPP_
|
||||
select -assert-count 1 t:$_DFF_N_
|
||||
select -assert-count 1 t:$_DFF_P_
|
||||
design -stash gate
|
||||
|
||||
design -import gold -as gold
|
||||
design -import gate -as gate
|
||||
clk2fflogic
|
||||
|
||||
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||
sat -verify -prove-asserts -show-ports -set-init-undef -seq 10 miter
|
|
@ -2,3 +2,14 @@ read_verilog -sv initval.v
|
|||
proc;;
|
||||
|
||||
sat -seq 10 -prove-asserts
|
||||
|
||||
design -reset
|
||||
read_verilog -icells <<EOT
|
||||
module top(input clk, i, output [1:0] o);
|
||||
(* init = 2'bx0 *)
|
||||
wire [1:0] o;
|
||||
assign o[1] = o[0];
|
||||
$_DFF_P_ dff (.C(clk), .D(i), .Q(o[0]));
|
||||
endmodule
|
||||
EOT
|
||||
sat -seq 1
|
||||
|
|
|
@ -213,7 +213,7 @@ module arbiter (clk, rst, request, acknowledge, grant, grant_valid, grant_encode
|
|||
input rst;
|
||||
endmodule
|
||||
|
||||
(* abc_box_id=1 *)
|
||||
(* abc9_box_id=1, whitebox *)
|
||||
module MUXF8(input I0, I1, S, output O);
|
||||
endmodule
|
||||
|
||||
|
@ -291,3 +291,19 @@ module abc9_test035(input clk, d, output reg [1:0] q);
|
|||
always @(posedge clk) q[0] <= d;
|
||||
always @(negedge clk) q[1] <= q[0];
|
||||
endmodule
|
||||
|
||||
module abc9_test036(input A, B, S, output [1:0] O);
|
||||
(* keep *)
|
||||
MUXF8 m (
|
||||
.I0(I0),
|
||||
.I1(I1),
|
||||
.O(O[0]),
|
||||
.S(S)
|
||||
);
|
||||
MUXF8 m2 (
|
||||
.I0(I0),
|
||||
.I1(I1),
|
||||
.O(O[1]),
|
||||
.S(S)
|
||||
);
|
||||
endmodule
|
||||
|
|
|
@ -28,4 +28,5 @@ exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v *.sv EXTRA_FLAGS="-n 300 -p
|
|||
abc9 -lut 4 -box ../abc.box; \
|
||||
clean; \
|
||||
check -assert; \
|
||||
select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"
|
||||
select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%; \
|
||||
setattr -mod -unset whitebox'"
|
||||
|
|
|
@ -39,6 +39,35 @@ design -load gold
|
|||
scratchpad -copy abc9.script.flow3 abc9.script
|
||||
abc9 -lut 4
|
||||
|
||||
design -reset
|
||||
read_verilog <<EOT
|
||||
module top(input a, b, output o);
|
||||
(* keep *) wire w = a & b;
|
||||
assign o = ~w;
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
simplemap
|
||||
equiv_opt -assert abc9 -lut 4
|
||||
design -load postopt
|
||||
select -assert-count 2 t:$lut
|
||||
|
||||
|
||||
design -reset
|
||||
read_verilog -icells <<EOT
|
||||
module top(input a, b, output o);
|
||||
wire w;
|
||||
(* keep *) $_AND_ gate (.Y(w), .A(a), .B(b));
|
||||
assign o = ~w;
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
simplemap
|
||||
equiv_opt -assert abc9 -lut 4
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$lut
|
||||
select -assert-count 1 t:$_AND_
|
||||
|
||||
|
||||
design -reset
|
||||
read_verilog -icells <<EOT
|
||||
|
|
|
@ -14,6 +14,7 @@ design -import gate -as gate
|
|||
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||
sat -verify -prove-asserts -show-ports miter
|
||||
|
||||
|
||||
design -load read
|
||||
hierarchy -top abc9_test028
|
||||
proc
|
||||
|
@ -23,6 +24,7 @@ select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i
|
|||
select -assert-count 1 t:unknown
|
||||
select -assert-none t:$lut t:unknown %% t: %D
|
||||
|
||||
|
||||
design -load read
|
||||
hierarchy -top abc9_test032
|
||||
proc
|
||||
|
@ -38,3 +40,16 @@ design -import gate -as gate
|
|||
|
||||
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||
sat -seq 10 -verify -prove-asserts -show-ports miter
|
||||
|
||||
|
||||
design -reset
|
||||
read_verilog -icells <<EOT
|
||||
module abc9_test036(input clk, d, output q);
|
||||
(* keep *) reg w;
|
||||
$__ABC9_FF_ ff(.D(d), .Q(w));
|
||||
wire \ff.clock = clk;
|
||||
wire \ff.init = 1'b0;
|
||||
assign q = w;
|
||||
endmodule
|
||||
EOT
|
||||
abc9 -lut 4 -dff
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
help -all
|
||||
help -celltypes
|
|
@ -0,0 +1,12 @@
|
|||
read_verilog <<EOT
|
||||
|
||||
module top;
|
||||
localparam a = $sformatf("0x%x", 8'h5A);
|
||||
localparam b = $sformatf("%d", 4'b011);
|
||||
generate
|
||||
if (a != "0x5a") $error("a incorrect!");
|
||||
if (b != "3") $error("b incorrect!");
|
||||
endgenerate
|
||||
endmodule
|
||||
|
||||
EOT
|
|
@ -0,0 +1,124 @@
|
|||
#!/bin/bash
|
||||
|
||||
trap 'echo "ERROR in sv_implicit_ports.sh" >&2; exit 1' ERR
|
||||
|
||||
# Simple case
|
||||
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||
assign q = a + b;
|
||||
endmodule
|
||||
|
||||
module top(input [7:0] a, output [7:0] q);
|
||||
wire [7:0] b = 8'd42;
|
||||
add add_i(.*);
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
# Generate block
|
||||
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||
assign q = a + b;
|
||||
endmodule
|
||||
|
||||
module top(input [7:0] a, output [7:0] q);
|
||||
generate
|
||||
if (1) begin:ablock
|
||||
wire [7:0] b = 8'd42;
|
||||
add add_i(.*);
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
# Missing wire
|
||||
((../../yosys -f "verilog -sv" -qp "hierarchy -top top" - || true) <<EOT
|
||||
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||
assign q = a + b;
|
||||
endmodule
|
||||
|
||||
module top(input [7:0] a, output [7:0] q);
|
||||
add add_i(.*);
|
||||
endmodule
|
||||
EOT
|
||||
) 2>&1 | grep -F "ERROR: No matching wire for implicit port connection \`b' of cell top.add_i (add)." > /dev/null
|
||||
|
||||
# Incorrectly sized wire
|
||||
((../../yosys -f "verilog -sv" -qp "hierarchy -top top" - || true) <<EOT
|
||||
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||
assign q = a + b;
|
||||
endmodule
|
||||
|
||||
module top(input [7:0] a, output [7:0] q);
|
||||
wire [6:0] b = 6'd42;
|
||||
add add_i(.*);
|
||||
endmodule
|
||||
EOT
|
||||
) 2>&1 | grep -F "ERROR: Width mismatch between wire (7 bits) and port (8 bits) for implicit port connection \`b' of cell top.add_i (add)." > /dev/null
|
||||
|
||||
# Defaults
|
||||
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||
module add(input [7:0] a = 8'd00, input [7:0] b = 8'd01, output [7:0] q);
|
||||
assign q = a + b;
|
||||
endmodule
|
||||
|
||||
module top(input [7:0] a, output [7:0] q);
|
||||
add add_i(.*);
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
# Parameterised module
|
||||
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||
module add #(parameter N=3) (input [N-1:0] a = 8'd00, input [N-1:0] b = 8'd01, output [N-1:0] q);
|
||||
assign q = a + b;
|
||||
endmodule
|
||||
|
||||
module top(input [7:0] a, output [7:0] q);
|
||||
add #(.N(8)) add_i(.*);
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
# Parameterised blackbox module
|
||||
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:add" - <<EOT
|
||||
(* blackbox *)
|
||||
module add #(parameter N=3) (input [N-1:0] a, b, output [N-1:0] q);
|
||||
endmodule
|
||||
|
||||
module top(input [7:0] a, b, output [7:0] q);
|
||||
add #(.N(8)) add_i(.*);
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
# Parameterised blackbox module - incorrect width
|
||||
((../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:add" - || true) <<EOT
|
||||
(* blackbox *)
|
||||
module add #(parameter N=3) (input [N-1:0] a, b, output [N-1:0] q);
|
||||
endmodule
|
||||
|
||||
module top(input [7:0] a, b, output [7:0] q);
|
||||
add #(.N(6)) add_i(.*);
|
||||
endmodule
|
||||
EOT
|
||||
) 2>&1 | grep -F "ERROR: Width mismatch between wire (8 bits) and port (6 bits) for implicit port connection \`q' of cell top.add_i (add)." > /dev/null
|
||||
|
||||
# Mixed implicit and explicit 1
|
||||
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||
assign q = a + b;
|
||||
endmodule
|
||||
|
||||
module top(input [7:0] a, output [7:0] q);
|
||||
add add_i(.b(8'd42), .*);
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
# Mixed implicit and explicit 2
|
||||
(../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||
assign q = a + b;
|
||||
endmodule
|
||||
|
||||
module top(input [7:0] a, input [9:0] b, output [7:0] q);
|
||||
add add_i(.b, .*);
|
||||
endmodule
|
||||
EOT
|
||||
) 2>&1 | grep -F "Warning: Resizing cell port top.add_i.b from 10 bits to 8 bits." > /dev/null
|
Loading…
Reference in New Issue