Merge branch 'xaig' into xc7mux

This commit is contained in:
Eddie Hung 2019-06-14 12:46:52 -07:00
commit 691e145cda
37 changed files with 866 additions and 1744 deletions

13
.dockerignore Normal file
View File

@ -0,0 +1,13 @@
.editorconfig
.gitignore
.gitmodules
.github
.git
Dockerfile
README.md
manual
CodingReadme
CodeOfConduct
.travis
.travis.yml

View File

@ -17,9 +17,11 @@ Yosys 0.8 .. Yosys 0.8-dev
- Added "rename -src" - Added "rename -src"
- Added "equiv_opt" pass - Added "equiv_opt" pass
- Added "read_aiger" frontend - Added "read_aiger" frontend
- Added "muxpack" pass - Added "abc9" pass for timing-aware techmapping (experimental, FPGA only, no FFs)
- Added "synth_xilinx -abc9" (experimental)
- Added "synth_ice40 -abc9" (experimental)
- Added "synth -abc9" (experimental)
- "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx" - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx"
- "synth_xilinx" to now infer wide multiplexers
Yosys 0.7 .. Yosys 0.8 Yosys 0.7 .. Yosys 0.8

33
Dockerfile Normal file
View File

@ -0,0 +1,33 @@
FROM ubuntu:18.04 as builder
LABEL author="Abdelrahman Hosny <abdelrahman.hosny@hotmail.com>"
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y build-essential \
clang \
bison \
flex \
libreadline-dev \
gawk \
tcl-dev \
libffi-dev \
git \
pkg-config \
python3 && \
rm -rf /var/lib/apt/lists
COPY . /
RUN make && \
make install
FROM ubuntu:18.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y libreadline-dev tcl-dev
COPY --from=builder /yosys /build/yosys
COPY --from=builder /yosys-abc /build/yosys-abc
COPY --from=builder /yosys-config /build/yosys-config
COPY --from=builder /yosys-filterlib /build/yosys-filterlib
COPY --from=builder /yosys-smtbmc /build/yosys-smtbmc
ENV PATH /build:$PATH
RUN useradd -m yosys
USER yosys
ENTRYPOINT ["yosys"]

View File

@ -2,7 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite * yosys -- Yosys Open SYnthesis Suite
* *
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* Copyright (C) 2019 Eddie Hung <eddie@fpgeh.com> * 2019 Eddie Hung <eddie@fpgeh.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -18,14 +18,32 @@
* *
*/ */
// https://stackoverflow.com/a/46137633
#ifdef _MSC_VER
#include <stdlib.h>
#define __builtin_bswap32 _byteswap_ulong
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define __builtin_bswap32 OSSwapInt32
#endif
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/utils.h" #include "kernel/utils.h"
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
inline int32_t to_big_endian(int32_t i32) {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return __builtin_bswap32(i32);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
return i32;
#else
#error "Unknown endianness"
#endif
}
void aiger_encode(std::ostream &f, int x) void aiger_encode(std::ostream &f, int x)
{ {
log_assert(x >= 0); log_assert(x >= 0);
@ -105,7 +123,7 @@ struct XAigerWriter
return aig_map.at(bit); return aig_map.at(bit);
} }
XAigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode, bool holes_mode=false) : module(module), zinit_mode(zinit_mode), sigmap(module) XAigerWriter(Module *module, bool zinit_mode, bool holes_mode=false) : module(module), zinit_mode(zinit_mode), sigmap(module)
{ {
pool<SigBit> undriven_bits; pool<SigBit> undriven_bits;
pool<SigBit> unused_bits; pool<SigBit> unused_bits;
@ -142,16 +160,10 @@ struct XAigerWriter
SigBit wirebit(wire, i); SigBit wirebit(wire, i);
SigBit bit = sigmap(wirebit); SigBit bit = sigmap(wirebit);
if (bit.wire == nullptr) { if (bit.wire) {
if (wire->port_output) {
aig_map[wirebit] = (bit == State::S1) ? 1 : 0;
output_bits.insert(wirebit);
}
continue;
}
undriven_bits.insert(bit); undriven_bits.insert(bit);
unused_bits.insert(bit); unused_bits.insert(bit);
}
if (wire->port_input || keep) { if (wire->port_input || keep) {
if (bit != wirebit) if (bit != wirebit)
@ -169,57 +181,16 @@ struct XAigerWriter
for (auto bit : input_bits) for (auto bit : input_bits)
undriven_bits.erase(sigmap(bit)); undriven_bits.erase(sigmap(bit));
for (auto bit : output_bits) for (auto bit : output_bits)
if (!bit.wire->port_input) if (!bit.wire->port_input)
unused_bits.erase(bit); unused_bits.erase(bit);
dict<SigBit, pool<IdString>> bit_drivers, bit_users; SigMap topomap;
TopoSort<IdString, RTLIL::sort_by_id_str> toposort; topomap.database = sigmap.database;
bool abc_box_seen = false; bool abc_box_seen = false;
for (auto cell : module->cells()) for (auto cell : module->cells()) {
{
RTLIL::Module* inst_module = module->design->module(cell->type);
bool builtin_type = yosys_celltypes.cell_known(cell->type);
bool abc_type = inst_module && inst_module->attributes.count("\\abc_box_id");
if (!holes_mode) {
toposort.node(cell->name);
for (const auto &conn : cell->connections()) {
if (!builtin_type && !abc_type)
continue;
if (!cell->type.in("$_NOT_", "$_AND_")) {
if (builtin_type) {
if (conn.first.in("\\Q", "\\CTRL_OUT", "\\RD_DATA"))
continue;
if (cell->type == "$memrd" && conn.first == "\\DATA")
continue;
}
if (inst_module) {
RTLIL::Wire* inst_module_port = inst_module->wire(conn.first);
log_assert(inst_module_port);
if (inst_module_port->port_output && inst_module_port->attributes.count("\\abc_flop_q"))
continue;
}
}
if (cell->input(conn.first)) {
// Ignore inout for the sake of topographical ordering
if (cell->output(conn.first)) continue;
for (auto bit : sigmap(conn.second))
bit_users[bit].insert(cell->name);
}
if (cell->output(conn.first))
for (auto bit : sigmap(conn.second))
bit_drivers[bit].insert(cell->name);
}
}
if (cell->type == "$_NOT_") if (cell->type == "$_NOT_")
{ {
SigBit A = sigmap(cell->getPort("\\A").as_bit()); SigBit A = sigmap(cell->getPort("\\A").as_bit());
@ -227,6 +198,8 @@ struct XAigerWriter
unused_bits.erase(A); unused_bits.erase(A);
undriven_bits.erase(Y); undriven_bits.erase(Y);
not_map[Y] = A; not_map[Y] = A;
if (!holes_mode)
topomap.add(Y, A);
continue; continue;
} }
@ -249,6 +222,10 @@ struct XAigerWriter
unused_bits.erase(B); unused_bits.erase(B);
undriven_bits.erase(Y); undriven_bits.erase(Y);
and_map[Y] = make_pair(A, B); and_map[Y] = make_pair(A, B);
if (!holes_mode) {
topomap.add(Y, A);
topomap.add(Y, B);
}
continue; continue;
} }
@ -260,50 +237,52 @@ struct XAigerWriter
// continue; // continue;
//} //}
bool inst_flop = inst_module ? inst_module->attributes.count("\\abc_flop") : false; RTLIL::Module* inst_module = module->design->module(cell->type);
if (inst_flop) { //bool inst_flop = inst_module ? inst_module->attributes.count("\\abc_flop") : false;
SigBit d, q; //if (inst_flop) {
for (const auto &c : cell->connections()) { // SigBit d, q;
auto is_input = cell->input(c.first); // for (const auto &c : cell->connections()) {
auto is_output = cell->output(c.first); // auto is_input = cell->input(c.first);
log_assert(is_input || is_output); // auto is_output = cell->output(c.first);
RTLIL::Wire* port = inst_module->wire(c.first); // log_assert(is_input || is_output);
for (auto b : c.second.bits()) { // RTLIL::Wire* port = inst_module->wire(c.first);
if (is_input && port->attributes.count("\\abc_flop_d")) { // for (auto b : c.second.bits()) {
d = b; // if (is_input && port->attributes.count("\\abc_flop_d")) {
SigBit I = sigmap(d); // d = b;
if (I != d) // SigBit I = sigmap(d);
alias_map[I] = d; // if (I != d)
unused_bits.erase(d); // alias_map[I] = d;
} // unused_bits.erase(d);
if (is_output && port->attributes.count("\\abc_flop_q")) { // }
q = b; // if (is_output && port->attributes.count("\\abc_flop_q")) {
SigBit O = sigmap(q); // q = b;
if (O != q) // SigBit O = sigmap(q);
alias_map[O] = q; // if (O != q)
undriven_bits.erase(O); // alias_map[O] = q;
} // undriven_bits.erase(O);
} // }
} // }
if (!abc_box_seen) // }
abc_box_seen = inst_module->attributes.count("\\abc_box_id"); // if (!abc_box_seen)
// abc_box_seen = inst_module->attributes.count("\\abc_box_id");
ff_bits.emplace_back(d, q); // ff_bits.emplace_back(d, q);
} //}
else if (inst_module && inst_module->attributes.count("\\abc_box_id")) { /*else*/ if (inst_module && inst_module->attributes.count("\\abc_box_id")) {
abc_box_seen = true; abc_box_seen = true;
} }
else { else {
for (const auto &c : cell->connections()) { for (const auto &c : cell->connections()) {
if (c.second.is_fully_const()) continue; if (c.second.is_fully_const()) continue;
for (auto b : c.second.bits()) {
Wire *w = b.wire;
if (!w) continue;
auto is_input = cell->input(c.first); auto is_input = cell->input(c.first);
auto is_output = cell->output(c.first); auto is_output = cell->output(c.first);
log_assert(is_input || is_output); log_assert(is_input || is_output);
if (is_input) { if (is_input) {
if (!w->port_input) { for (auto b : c.second.bits()) {
Wire *w = b.wire;
if (!w) continue;
if (!w->port_output) {
SigBit I = sigmap(b); SigBit I = sigmap(b);
if (I != b) if (I != b)
alias_map[b] = I; alias_map[b] = I;
@ -311,7 +290,11 @@ struct XAigerWriter
unused_bits.erase(b); unused_bits.erase(b);
} }
} }
}
if (is_output) { if (is_output) {
for (auto b : c.second.bits()) {
Wire *w = b.wire;
if (!w) continue;
input_bits.insert(b); input_bits.insert(b);
SigBit O = sigmap(b); SigBit O = sigmap(b);
if (O != b) if (O != b)
@ -325,20 +308,46 @@ struct XAigerWriter
//log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell)); //log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
} }
if (abc_box_seen) { if (abc_box_seen && !holes_mode) {
TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
dict<SigBit, pool<IdString>> bit_drivers, bit_users;
for (auto cell : module->cells()) {
RTLIL::Module* inst_module = module->design->module(cell->type);
if (!inst_module || !inst_module->attributes.count("\\abc_box_id"))
continue;
toposort.node(cell->name);
for (const auto &conn : cell->connections()) {
if (cell->input(conn.first)) {
// Ignore inout for the sake of topographical ordering
if (cell->output(conn.first)) continue;
for (auto bit : topomap(conn.second))
if (bit.wire)
bit_users[bit].insert(cell->name);
}
if (cell->output(conn.first)) {
RTLIL::Wire* inst_module_port = inst_module->wire(conn.first);
log_assert(inst_module_port);
//if (inst_module_port->attributes.count("\\abc_flop_q"))
// continue;
for (auto bit : topomap(conn.second))
bit_drivers[bit].insert(cell->name);
}
}
}
for (auto &it : bit_users) for (auto &it : bit_users)
if (bit_drivers.count(it.first)) if (bit_drivers.count(it.first))
for (auto driver_cell : bit_drivers.at(it.first)) for (auto driver_cell : bit_drivers.at(it.first))
for (auto user_cell : it.second) for (auto user_cell : it.second)
toposort.edge(driver_cell, user_cell); toposort.edge(driver_cell, user_cell);
pool<RTLIL::Module*> abc_carry_modules; #if 1
#if 0
toposort.analyze_loops = true; toposort.analyze_loops = true;
#endif #endif
bool no_loops = toposort.sort(); bool no_loops = toposort.sort();
#if 0 #if 1
unsigned i = 0; unsigned i = 0;
for (auto &it : toposort.loops) { for (auto &it : toposort.loops) {
log(" loop %d", i++); log(" loop %d", i++);
@ -349,13 +358,14 @@ struct XAigerWriter
#endif #endif
log_assert(no_loops); log_assert(no_loops);
pool<RTLIL::Module*> abc_carry_modules;
for (auto cell_name : toposort.sorted) { for (auto cell_name : toposort.sorted) {
RTLIL::Cell *cell = module->cell(cell_name); RTLIL::Cell *cell = module->cell(cell_name);
RTLIL::Module* box_module = module->design->module(cell->type); RTLIL::Module* box_module = module->design->module(cell->type);
if (!box_module || !box_module->attributes.count("\\abc_box_id")) log_assert(box_module);
continue; log_assert(box_module->attributes.count("\\abc_box_id"));
if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) { if (!abc_carry_modules.count(box_module) && box_module->attributes.count("\\abc_carry")) {
RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr; RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr;
RTLIL::Wire* last_in = nullptr, *last_out = nullptr; RTLIL::Wire* last_in = nullptr, *last_out = nullptr;
for (const auto &port_name : box_module->ports) { for (const auto &port_name : box_module->ports) {
@ -451,8 +461,6 @@ struct XAigerWriter
} }
box_list.emplace_back(cell); box_list.emplace_back(cell);
} }
// TODO: Free memory from toposort, bit_drivers, bit_users
} }
for (auto bit : input_bits) { for (auto bit : input_bits) {
@ -483,10 +491,6 @@ struct XAigerWriter
} }
} }
// Erase all POs that are undriven
if (!holes_mode)
for (auto bit : undriven_bits)
output_bits.erase(bit);
for (auto bit : unused_bits) for (auto bit : unused_bits)
undriven_bits.erase(bit); undriven_bits.erase(bit);
@ -543,10 +547,6 @@ struct XAigerWriter
ff_aig_map[bit] = 2*aig_m; ff_aig_map[bit] = 2*aig_m;
} }
if (imode && input_bits.empty()) {
aig_m++, aig_i++;
}
//if (zinit_mode) //if (zinit_mode)
//{ //{
// for (auto it : ff_map) { // for (auto it : ff_map) {
@ -620,18 +620,9 @@ struct XAigerWriter
aig_outputs.push_back(ff_aig_map.at(bit)); aig_outputs.push_back(ff_aig_map.at(bit));
} }
if (omode && output_bits.empty()) {
aig_o++;
aig_outputs.push_back(0);
} }
if (bmode) { void write_aiger(std::ostream &f, bool ascii_mode)
//aig_b++;
aig_outputs.push_back(0);
}
}
void write_aiger(std::ostream &f, bool ascii_mode, bool miter_mode, bool symbols_mode, bool omode)
{ {
int aig_obc = aig_o; int aig_obc = aig_o;
int aig_obcj = aig_obc; int aig_obcj = aig_obc;
@ -708,98 +699,25 @@ struct XAigerWriter
} }
} }
if (symbols_mode)
{
dict<string, vector<string>> symbols;
bool output_seen = false;
for (auto wire : module->wires())
{
//if (wire->name[0] == '$')
// continue;
SigSpec sig = sigmap(wire);
for (int i = 0; i < GetSize(wire); i++)
{
RTLIL::SigBit b(wire, i);
if (input_bits.count(b)) {
int a = aig_map.at(sig[i]);
log_assert((a & 1) == 0);
if (GetSize(wire) != 1)
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s[%d]", log_id(wire), i));
else
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s", log_id(wire)));
}
if (output_bits.count(b)) {
int o = ordered_outputs.at(b);
output_seen = !miter_mode;
if (GetSize(wire) != 1)
symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s[%d]", log_id(wire), i));
else
symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s", log_id(wire)));
}
//if (init_inputs.count(sig[i])) {
// int a = init_inputs.at(sig[i]);
// log_assert((a & 1) == 0);
// if (GetSize(wire) != 1)
// symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s[%d]", log_id(wire), i));
// else
// symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s", log_id(wire)));
//}
if (ordered_latches.count(sig[i])) {
int l = ordered_latches.at(sig[i]);
const char *p = (zinit_mode && (aig_latchinit.at(l) == 1)) ? "!" : "";
if (GetSize(wire) != 1)
symbols[stringf("l%d", l)].push_back(stringf("%s%s[%d]", p, log_id(wire), i));
else
symbols[stringf("l%d", l)].push_back(stringf("%s%s", p, log_id(wire)));
}
}
}
if (omode && !output_seen)
symbols["o0"].push_back("__dummy_o__");
symbols.sort();
for (auto &sym : symbols) {
f << sym.first;
std::sort(sym.second.begin(), sym.second.end());
for (auto &s : sym.second)
f << " " << s;
f << std::endl;
}
}
f << "c"; f << "c";
if (!box_list.empty() || !ff_bits.empty()) { if (!box_list.empty() || !ff_bits.empty()) {
std::stringstream h_buffer; auto write_buffer = [](std::stringstream &buffer, int i32) {
auto write_h_buffer = [&h_buffer](int i32) { int32_t i32_be = to_big_endian(i32);
// TODO: Don't assume we're on little endian buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
#ifdef _WIN32
int i32_be = _byteswap_ulong(i32);
#else
int i32_be = __builtin_bswap32(i32);
#endif
h_buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
}; };
int num_outputs = output_bits.size();
if (omode && num_outputs == 0) std::stringstream h_buffer;
num_outputs = 1; auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1);
write_h_buffer(1); write_h_buffer(1);
log_debug("ciNum = %zu\n", input_bits.size() + ff_bits.size() + ci_bits.size()); log_debug("ciNum = %zu\n", input_bits.size() + ff_bits.size() + ci_bits.size());
write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size()); write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size());
log_debug("coNum = %zu\n", num_outputs + ff_bits.size() + co_bits.size()); log_debug("coNum = %zu\n", output_bits.size() + ff_bits.size() + co_bits.size());
write_h_buffer(num_outputs + ff_bits.size()+ co_bits.size()); write_h_buffer(output_bits.size() + ff_bits.size()+ co_bits.size());
log_debug("piNum = %zu\n", input_bits.size() + ff_bits.size()); log_debug("piNum = %zu\n", input_bits.size() + ff_bits.size());
write_h_buffer(input_bits.size()+ ff_bits.size()); write_h_buffer(input_bits.size()+ ff_bits.size());
log_debug("poNum = %zu\n", num_outputs + ff_bits.size()); log_debug("poNum = %zu\n", output_bits.size() + ff_bits.size());
write_h_buffer(num_outputs + ff_bits.size()); write_h_buffer(output_bits.size() + ff_bits.size());
log_debug("boxNum = %zu\n", box_list.size()); log_debug("boxNum = %zu\n", box_list.size());
write_h_buffer(box_list.size()); write_h_buffer(box_list.size());
@ -869,40 +787,22 @@ struct XAigerWriter
f << "h"; f << "h";
std::string buffer_str = h_buffer.str(); std::string buffer_str = h_buffer.str();
// TODO: Don't assume we're on little endian int32_t buffer_size_be = to_big_endian(buffer_str.size());
#ifdef _WIN32
int buffer_size_be = _byteswap_ulong(buffer_str.size());
#else
int buffer_size_be = __builtin_bswap32(buffer_str.size());
#endif
f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
f.write(buffer_str.data(), buffer_str.size()); f.write(buffer_str.data(), buffer_str.size());
/*if (!ff_bits.empty())*/ { /*if (!ff_bits.empty())*/ {
std::stringstream r_buffer; std::stringstream r_buffer;
auto write_r_buffer = [&r_buffer](int i32) { auto write_r_buffer = std::bind(write_buffer, std::ref(r_buffer), std::placeholders::_1);
// TODO: Don't assume we're on little endian
#ifdef _WIN32
int i32_be = _byteswap_ulong(i32);
#else
int i32_be = __builtin_bswap32(i32);
#endif
r_buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
};
log_debug("flopNum = %zu\n", ff_bits.size()); log_debug("flopNum = %zu\n", ff_bits.size());
write_r_buffer(ff_bits.size()); write_r_buffer(ff_bits.size());
int mergeability_class = 1; //int mergeability_class = 1;
for (auto cell : ff_bits) //for (auto cell : ff_bits)
write_r_buffer(mergeability_class++); // write_r_buffer(mergeability_class++);
f << "r"; f << "r";
std::string buffer_str = r_buffer.str(); std::string buffer_str = r_buffer.str();
// TODO: Don't assume we're on little endian int32_t buffer_size_be = to_big_endian(buffer_str.size());
#ifdef _WIN32
int buffer_size_be = _byteswap_ulong(buffer_str.size());
#else
int buffer_size_be = __builtin_bswap32(buffer_str.size());
#endif
f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
f.write(buffer_str.data(), buffer_str.size()); f.write(buffer_str.data(), buffer_str.size());
} }
@ -923,25 +823,19 @@ struct XAigerWriter
Pass::call(holes_module->design, "flatten -wb"); Pass::call(holes_module->design, "flatten -wb");
// TODO: Should techmap all lib_whitebox-es once // TODO: Should techmap all lib_whitebox-es once
//Pass::call(holes_module->design, "techmap"); Pass::call(holes_module->design, "techmap");
Pass::call(holes_module->design, "aigmap"); Pass::call(holes_module->design, "aigmap");
Pass::call(holes_module->design, "clean -purge"); Pass::call(holes_module->design, "clean -purge");
holes_module->design->selection_stack.pop_back(); holes_module->design->selection_stack.pop_back();
std::stringstream a_buffer; std::stringstream a_buffer;
XAigerWriter writer(holes_module, false /*zinit_mode*/, false /*imode*/, false /*omode*/, false /*bmode*/, true /* holes_mode */); XAigerWriter writer(holes_module, false /*zinit_mode*/, true /* holes_mode */);
writer.write_aiger(a_buffer, false /*ascii_mode*/, false /*miter_mode*/, false /*symbols_mode*/, false /*omode*/); writer.write_aiger(a_buffer, false /*ascii_mode*/);
f << "a"; f << "a";
std::string buffer_str = a_buffer.str(); std::string buffer_str = a_buffer.str();
// TODO: Don't assume we're on little endian int32_t buffer_size_be = to_big_endian(buffer_str.size());
#ifdef _WIN32
int buffer_size_be = _byteswap_ulong(buffer_str.size());
#else
int buffer_size_be = __builtin_bswap32(buffer_str.size());
#endif
f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
f.write(buffer_str.data(), buffer_str.size()); f.write(buffer_str.data(), buffer_str.size());
holes_module->design->remove(holes_module); holes_module->design->remove(holes_module);
@ -951,7 +845,7 @@ struct XAigerWriter
f << stringf("Generated by %s\n", yosys_version_str); f << stringf("Generated by %s\n", yosys_version_str);
} }
void write_map(std::ostream &f, bool verbose_map, bool omode) void write_map(std::ostream &f, bool verbose_map)
{ {
dict<int, string> input_lines; dict<int, string> input_lines;
dict<int, string> init_lines; dict<int, string> init_lines;
@ -1024,8 +918,6 @@ struct XAigerWriter
for (auto &it : output_lines) for (auto &it : output_lines)
f << it.second; f << it.second;
log_assert(output_lines.size() == output_bits.size()); log_assert(output_lines.size() == output_bits.size());
if (omode && output_bits.empty())
f << "output " << output_lines.size() << " 0 __dummy_o__\n";
latch_lines.sort(); latch_lines.sort();
for (auto &it : latch_lines) for (auto &it : latch_lines)
@ -1055,31 +947,18 @@ struct XAigerBackend : public Backend {
log(" convert FFs to zero-initialized FFs, adding additional inputs for\n"); log(" convert FFs to zero-initialized FFs, adding additional inputs for\n");
log(" uninitialized FFs.\n"); log(" uninitialized FFs.\n");
log("\n"); log("\n");
log(" -symbols\n");
log(" include a symbol table in the generated AIGER file\n");
log("\n");
log(" -map <filename>\n"); log(" -map <filename>\n");
log(" write an extra file with port and latch symbols\n"); log(" write an extra file with port and latch symbols\n");
log("\n"); log("\n");
log(" -vmap <filename>\n"); log(" -vmap <filename>\n");
log(" like -map, but more verbose\n"); log(" like -map, but more verbose\n");
log("\n"); log("\n");
log(" -I, -O, -B\n");
log(" If the design contains no input/output/assert then create one\n");
log(" dummy input/output/bad_state pin to make the tools reading the\n");
log(" AIGER file happy.\n");
log("\n");
} }
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{ {
bool ascii_mode = false; bool ascii_mode = false;
bool zinit_mode = false; bool zinit_mode = false;
bool miter_mode = false;
bool symbols_mode = false;
bool verbose_map = false; bool verbose_map = false;
bool imode = false;
bool omode = false;
bool bmode = false;
std::string map_filename; std::string map_filename;
log_header(design, "Executing XAIGER backend.\n"); log_header(design, "Executing XAIGER backend.\n");
@ -1095,10 +974,6 @@ struct XAigerBackend : public Backend {
zinit_mode = true; zinit_mode = true;
continue; continue;
} }
if (args[argidx] == "-symbols") {
symbols_mode = true;
continue;
}
if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) { if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
map_filename = args[++argidx]; map_filename = args[++argidx];
continue; continue;
@ -1108,18 +983,6 @@ struct XAigerBackend : public Backend {
verbose_map = true; verbose_map = true;
continue; continue;
} }
if (args[argidx] == "-I") {
imode = true;
continue;
}
if (args[argidx] == "-O") {
omode = true;
continue;
}
if (args[argidx] == "-B") {
bmode = true;
continue;
}
break; break;
} }
extra_args(f, filename, args, argidx); extra_args(f, filename, args, argidx);
@ -1129,15 +992,15 @@ struct XAigerBackend : public Backend {
if (top_module == nullptr) if (top_module == nullptr)
log_error("Can't find top module in current design!\n"); log_error("Can't find top module in current design!\n");
XAigerWriter writer(top_module, zinit_mode, imode, omode, bmode); XAigerWriter writer(top_module, zinit_mode);
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode, omode); writer.write_aiger(*f, ascii_mode);
if (!map_filename.empty()) { if (!map_filename.empty()) {
std::ofstream mapf; std::ofstream mapf;
mapf.open(map_filename.c_str(), std::ofstream::trunc); mapf.open(map_filename.c_str(), std::ofstream::trunc);
if (mapf.fail()) if (mapf.fail())
log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno)); log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno));
writer.write_map(mapf, verbose_map, omode); writer.write_map(mapf, verbose_map);
} }
} }
} XAigerBackend; } XAigerBackend;

View File

@ -2,7 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite * yosys -- Yosys Open SYnthesis Suite
* *
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* Copyright (C) 2019 Eddie Hung <eddie@fpgeh.com> * 2019 Eddie Hung <eddie@fpgeh.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -24,17 +24,179 @@
#ifdef _WIN32 #ifdef _WIN32
#include <libgen.h> #include <libgen.h>
#include <stdlib.h>
#endif #endif
#include <array> // https://stackoverflow.com/a/46137633
#ifdef _MSC_VER
#include <stdlib.h>
#define __builtin_bswap32 _byteswap_ulong
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define __builtin_bswap32 OSSwapInt32
#endif
#include <inttypes.h>
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
#include "kernel/consteval.h" #include "kernel/celltypes.h"
#include "aigerparse.h" #include "aigerparse.h"
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
inline int32_t from_big_endian(int32_t i32) {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return __builtin_bswap32(i32);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
return i32;
#else
#error "Unknown endianness"
#endif
}
struct ConstEvalAig
{
RTLIL::Module *module;
dict<RTLIL::SigBit, RTLIL::State> values_map;
dict<RTLIL::SigBit, RTLIL::Cell*> sig2driver;
dict<SigBit, pool<RTLIL::SigBit>> sig2deps;
ConstEvalAig(RTLIL::Module *module) : module(module)
{
for (auto &it : module->cells_) {
if (!yosys_celltypes.cell_known(it.second->type))
continue;
for (auto &it2 : it.second->connections())
if (yosys_celltypes.cell_output(it.second->type, it2.first)) {
auto r = sig2driver.insert(std::make_pair(it2.second, it.second));
log_assert(r.second);
}
}
}
void clear()
{
values_map.clear();
sig2deps.clear();
}
void set(RTLIL::SigBit sig, RTLIL::State value)
{
auto it = values_map.find(sig);
#ifndef NDEBUG
if (it != values_map.end()) {
RTLIL::State current_val = it->second;
log_assert(current_val == value);
}
#endif
if (it != values_map.end())
it->second = value;
else
values_map[sig] = value;
}
void set_incremental(RTLIL::SigSpec sig, RTLIL::Const value)
{
log_assert(GetSize(sig) == GetSize(value));
for (int i = 0; i < GetSize(sig); i++) {
auto it = values_map.find(sig[i]);
if (it != values_map.end()) {
RTLIL::State current_val = it->second;
if (current_val != value[i])
for (auto dep : sig2deps[sig[i]])
values_map.erase(dep);
it->second = value[i];
}
else
values_map[sig[i]] = value[i];
}
}
void compute_deps(RTLIL::SigBit output, const pool<RTLIL::SigBit> &inputs)
{
sig2deps[output].insert(output);
RTLIL::Cell *cell = sig2driver.at(output);
RTLIL::SigBit sig_a = cell->getPort("\\A");
sig2deps[sig_a].insert(sig2deps[output].begin(), sig2deps[output].end());
if (!inputs.count(sig_a))
compute_deps(sig_a, inputs);
if (cell->type == "$_AND_") {
RTLIL::SigSpec sig_b = cell->getPort("\\B");
sig2deps[sig_b].insert(sig2deps[output].begin(), sig2deps[output].end());
if (!inputs.count(sig_b))
compute_deps(sig_b, inputs);
}
else if (cell->type == "$_NOT_") {
}
else log_abort();
}
bool eval(RTLIL::Cell *cell)
{
RTLIL::SigBit sig_y = cell->getPort("\\Y");
if (values_map.count(sig_y))
return true;
RTLIL::SigBit sig_a = cell->getPort("\\A");
if (!eval(sig_a))
return false;
RTLIL::State eval_ret = RTLIL::Sx;
if (cell->type == "$_NOT_") {
if (sig_a == RTLIL::S0) eval_ret = RTLIL::S1;
else if (sig_a == RTLIL::S1) eval_ret = RTLIL::S0;
}
else if (cell->type == "$_AND_") {
if (sig_a == RTLIL::S0) {
eval_ret = RTLIL::S0;
goto eval_end;
}
{
RTLIL::SigBit sig_b = cell->getPort("\\B");
if (!eval(sig_b))
return false;
if (sig_b == RTLIL::S0) {
eval_ret = RTLIL::S0;
goto eval_end;
}
if (sig_a != RTLIL::S1 || sig_b != RTLIL::S1)
goto eval_end;
eval_ret = RTLIL::S1;
}
}
else log_abort();
eval_end:
set(sig_y, eval_ret);
return true;
}
bool eval(RTLIL::SigBit &sig)
{
auto it = values_map.find(sig);
if (it != values_map.end()) {
sig = it->second;
return true;
}
RTLIL::Cell *cell = sig2driver.at(sig);
if (!eval(cell))
return false;
it = values_map.find(sig);
if (it != values_map.end()) {
sig = it->second;
return true;
}
return false;
}
};
AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports) AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports)
: design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports) : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports)
{ {
@ -132,20 +294,15 @@ static uint32_t parse_xaiger_literal(std::istream &f)
uint32_t l; uint32_t l;
f.read(reinterpret_cast<char*>(&l), sizeof(l)); f.read(reinterpret_cast<char*>(&l), sizeof(l));
if (f.gcount() != sizeof(l)) if (f.gcount() != sizeof(l))
log_error("Offset %ld: unable to read literal!\n", static_cast<int64_t>(f.tellg())); log_error("Offset %" PRId64 ": unable to read literal!\n", static_cast<int64_t>(f.tellg()));
// TODO: Don't assume we're on little endian return from_big_endian(l);
#ifdef _WIN32
return _byteswap_ulong(l);
#else
return __builtin_bswap32(l);
#endif
} }
static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal) static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal)
{ {
const unsigned variable = literal >> 1; const unsigned variable = literal >> 1;
const bool invert = literal & 1; const bool invert = literal & 1;
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix? RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : ""));
RTLIL::Wire *wire = module->wire(wire_name); RTLIL::Wire *wire = module->wire(wire_name);
if (wire) return wire; if (wire) return wire;
log_debug("Creating %s\n", wire_name.c_str()); log_debug("Creating %s\n", wire_name.c_str());
@ -164,7 +321,7 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera
} }
log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str()); log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire); // FIXME: is "$not" the right suffix? module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire);
return wire; return wire;
} }
@ -210,7 +367,8 @@ void AigerReader::parse_xaiger()
auto it = m->attributes.find("\\abc_box_id"); auto it = m->attributes.find("\\abc_box_id");
if (it == m->attributes.end()) if (it == m->attributes.end())
continue; continue;
if (m->name[0] == '$') continue; if (m->name.begins_with("$paramod"))
continue;
auto r = box_lookup.insert(std::make_pair(it->second.as_int(), m->name)); auto r = box_lookup.insert(std::make_pair(it->second.as_int(), m->name));
log_assert(r.second); log_assert(r.second);
} }
@ -234,7 +392,7 @@ void AigerReader::parse_xaiger()
uint32_t lutNum = parse_xaiger_literal(f); uint32_t lutNum = parse_xaiger_literal(f);
uint32_t lutSize = parse_xaiger_literal(f); uint32_t lutSize = parse_xaiger_literal(f);
log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize); log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize);
ConstEval ce(module); ConstEvalAig ce(module);
for (unsigned i = 0; i < lutNum; ++i) { for (unsigned i = 0; i < lutNum; ++i) {
uint32_t rootNodeID = parse_xaiger_literal(f); uint32_t rootNodeID = parse_xaiger_literal(f);
uint32_t cutLeavesM = parse_xaiger_literal(f); uint32_t cutLeavesM = parse_xaiger_literal(f);
@ -249,14 +407,18 @@ void AigerReader::parse_xaiger()
log_assert(wire); log_assert(wire);
input_sig.append(wire); input_sig.append(wire);
} }
// 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()); RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size());
for (int j = 0; j < (1 << cutLeavesM); ++j) { for (int j = 0; j < (1 << cutLeavesM); ++j) {
ce.push(); int gray = j ^ (j >> 1);
ce.set(input_sig, RTLIL::Const{j, static_cast<int>(cutLeavesM)}); ce.set_incremental(input_sig, RTLIL::Const{gray, static_cast<int>(cutLeavesM)});
RTLIL::SigSpec o(output_sig); RTLIL::SigBit o(output_sig);
ce.eval(o); bool success = ce.eval(o);
lut_mask[j] = o.as_const()[0]; log_assert(success);
ce.pop(); log_assert(o.wire == nullptr);
lut_mask[gray] = o.data;
} }
RTLIL::Cell *output_cell = module->cell(stringf("\\__%d__$and", rootNodeID)); RTLIL::Cell *output_cell = module->cell(stringf("\\__%d__$and", rootNodeID));
log_assert(output_cell); log_assert(output_cell);
@ -346,7 +508,7 @@ void AigerReader::parse_aiger_ascii()
if (!(f >> l1 >> l2)) if (!(f >> l1 >> l2))
log_error("Line %u cannot be interpreted as a latch!\n", line_count); log_error("Line %u cannot be interpreted as a latch!\n", line_count);
log_debug("%d %d is a latch\n", l1, l2); log_debug("%d %d is a latch\n", l1, l2);
log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted? log_assert(!(l1 & 1));
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
@ -696,10 +858,6 @@ void AigerReader::post_process()
RTLIL::Wire* wire = outputs[variable + co_count]; RTLIL::Wire* wire = outputs[variable + co_count];
log_assert(wire); log_assert(wire);
log_assert(wire->port_output); log_assert(wire->port_output);
if (escaped_s.in("\\__dummy_o__", "\\__const0__", "\\__const1__")) {
wire->port_output = false;
continue;
}
if (index == 0) { if (index == 0) {
// Cope with the fact that a CO might be identical // Cope with the fact that a CO might be identical
@ -797,8 +955,6 @@ void AigerReader::post_process()
port_output = port_output || other_wire->port_output; port_output = port_output || other_wire->port_output;
} }
} }
if ((port_input && port_output) || (!port_input && !port_output))
continue;
wire = module->addWire(name, width); wire = module->addWire(name, width);
wire->port_input = port_input; wire->port_input = port_input;

View File

@ -2,7 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite * yosys -- Yosys Open SYnthesis Suite
* *
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* Eddie Hung <eddie@fpgeh.com> * 2019 Eddie Hung <eddie@fpgeh.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above

View File

@ -276,6 +276,12 @@ namespace RTLIL
return std::string(c_str() + pos, len); return std::string(c_str() + pos, len);
} }
bool begins_with(const char* prefix) const {
size_t len = strlen(prefix);
if (size() < len) return false;
return substr(0, len) == prefix;
}
bool ends_with(const char* suffix) const { bool ends_with(const char* suffix) const {
size_t len = strlen(suffix); size_t len = strlen(suffix);
if (size() < len) return false; if (size() < len) return false;

View File

@ -339,9 +339,6 @@ struct StatPass : public Pass {
if (mod->get_bool_attribute("\\top")) if (mod->get_bool_attribute("\\top"))
top_mod = mod; top_mod = mod;
if (mod->attributes.count("\\abc_box_id"))
continue;
statdata_t data(design, mod, width_mode, cell_area, techname); statdata_t data(design, mod, width_mode, cell_area, techname);
mod_stat[mod->name] = data; mod_stat[mod->name] = data;

View File

@ -14,6 +14,5 @@ OBJS += passes/opt/opt_demorgan.o
OBJS += passes/opt/rmports.o OBJS += passes/opt/rmports.o
OBJS += passes/opt/opt_lut.o OBJS += passes/opt/opt_lut.o
OBJS += passes/opt/pmux2shiftx.o OBJS += passes/opt/pmux2shiftx.o
OBJS += passes/opt/muxpack.o
endif endif

View File

@ -1,270 +0,0 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 2019 Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct MuxpackWorker
{
Module *module;
SigMap sigmap;
int mux_count, pmux_count;
pool<Cell*> remove_cells;
dict<SigSpec, Cell*> sig_chain_next;
dict<SigSpec, Cell*> sig_chain_prev;
pool<SigBit> sigbit_with_non_chain_users;
pool<Cell*> chain_start_cells;
pool<Cell*> candidate_cells;
void make_sig_chain_next_prev()
{
for (auto wire : module->wires())
{
if (wire->port_output || wire->get_bool_attribute("\\keep")) {
for (auto bit : sigmap(wire))
sigbit_with_non_chain_users.insert(bit);
}
}
for (auto cell : module->cells())
{
if (cell->type.in("$mux", "$pmux") && !cell->get_bool_attribute("\\keep"))
{
SigSpec a_sig = sigmap(cell->getPort("\\A"));
SigSpec b_sig;
if (cell->type == "$mux")
b_sig = sigmap(cell->getPort("\\B"));
SigSpec y_sig = sigmap(cell->getPort("\\Y"));
if (sig_chain_next.count(a_sig))
for (auto a_bit : a_sig.bits())
sigbit_with_non_chain_users.insert(a_bit);
else {
sig_chain_next[a_sig] = cell;
candidate_cells.insert(cell);
}
if (!b_sig.empty()) {
if (sig_chain_next.count(b_sig))
for (auto b_bit : b_sig.bits())
sigbit_with_non_chain_users.insert(b_bit);
else {
sig_chain_next[b_sig] = cell;
candidate_cells.insert(cell);
}
}
sig_chain_prev[y_sig] = cell;
continue;
}
for (auto conn : cell->connections())
if (cell->input(conn.first))
for (auto bit : sigmap(conn.second))
sigbit_with_non_chain_users.insert(bit);
}
}
void find_chain_start_cells()
{
for (auto cell : candidate_cells)
{
log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type));
SigSpec a_sig = cell->getPort("\\A");
if (cell->type == "$mux") {
SigSpec b_sig = cell->getPort("\\B");
if (sig_chain_prev.count(a_sig) + sig_chain_prev.count(b_sig) != 1)
goto start_cell;
if (!sig_chain_prev.count(a_sig))
a_sig = b_sig;
}
else if (cell->type == "$pmux") {
if (!sig_chain_prev.count(a_sig))
goto start_cell;
}
else log_abort();
{
for (auto bit : a_sig.bits())
if (sigbit_with_non_chain_users.count(bit))
goto start_cell;
Cell *c1 = sig_chain_prev.at(a_sig);
Cell *c2 = cell;
if (c1->getParam("\\WIDTH") != c2->getParam("\\WIDTH"))
goto start_cell;
}
continue;
start_cell:
chain_start_cells.insert(cell);
}
}
vector<Cell*> create_chain(Cell *start_cell)
{
vector<Cell*> chain;
Cell *c = start_cell;
while (c != nullptr)
{
chain.push_back(c);
SigSpec y_sig = sigmap(c->getPort("\\Y"));
if (sig_chain_next.count(y_sig) == 0)
break;
c = sig_chain_next.at(y_sig);
if (chain_start_cells.count(c) != 0)
break;
}
return chain;
}
void process_chain(vector<Cell*> &chain)
{
if (GetSize(chain) < 2)
return;
int cursor = 0;
while (cursor < GetSize(chain))
{
int cases = GetSize(chain) - cursor;
Cell *first_cell = chain[cursor];
dict<int, SigBit> taps_dict;
if (cases < 2) {
cursor++;
continue;
}
Cell *last_cell = chain[cursor+cases-1];
log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n",
log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), cases);
mux_count += cases;
pmux_count += 1;
first_cell->type = "$pmux";
SigSpec b_sig = first_cell->getPort("\\B");
SigSpec s_sig = first_cell->getPort("\\S");
for (int i = 1; i < cases; i++) {
Cell* prev_cell = chain[cursor+i-1];
Cell* cursor_cell = chain[cursor+i];
if (sigmap(prev_cell->getPort("\\Y")) == sigmap(cursor_cell->getPort("\\A"))) {
b_sig.append(cursor_cell->getPort("\\B"));
s_sig.append(cursor_cell->getPort("\\S"));
}
else {
b_sig.append(cursor_cell->getPort("\\A"));
s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort("\\S")));
}
remove_cells.insert(cursor_cell);
}
first_cell->setPort("\\B", b_sig);
first_cell->setPort("\\S", s_sig);
first_cell->setParam("\\S_WIDTH", GetSize(s_sig));
first_cell->setPort("\\Y", last_cell->getPort("\\Y"));
cursor += cases;
}
}
void cleanup()
{
for (auto cell : remove_cells)
module->remove(cell);
remove_cells.clear();
sig_chain_next.clear();
sig_chain_prev.clear();
chain_start_cells.clear();
candidate_cells.clear();
}
MuxpackWorker(Module *module) :
module(module), sigmap(module), mux_count(0), pmux_count(0)
{
make_sig_chain_next_prev();
find_chain_start_cells();
for (auto c : chain_start_cells) {
vector<Cell*> chain = create_chain(c);
process_chain(chain);
}
cleanup();
}
};
struct MuxpackPass : public Pass {
MuxpackPass() : Pass("muxpack", "$mux/$pmux cascades to $pmux") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" muxpack [selection]\n");
log("\n");
log("This pass converts cascaded chains of $pmux cells (e.g. those create from case\n");
log("constructs) and $mux cells (e.g. those created by if-else constructs) into \n");
log("into $pmux cells.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
break;
}
extra_args(args, argidx, design);
int mux_count = 0;
int pmux_count = 0;
for (auto module : design->selected_modules()) {
MuxpackWorker worker(module);
mux_count += worker.mux_count;
pmux_count += worker.pmux_count;
}
log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count);
}
} MuxpackPass;
PRIVATE_NAMESPACE_END

View File

@ -1453,7 +1453,7 @@ struct AbcPass : public Pass {
log("internally. This is not going to \"run ABC on your design\". It will instead run\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("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("output when passing an ABC script that writes a file. Instead write your full\n");
log("design as BLIF file with write_blif and the load that into ABC externally if\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("you want to use ABC to convert your design into another format.\n");
log("\n"); log("\n");
log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");

View File

@ -2,7 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite * yosys -- Yosys Open SYnthesis Suite
* *
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* Copyright (C) 2019 Eddie Hung <eddie@fpgeh.com> * 2019 Eddie Hung <eddie@fpgeh.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -22,18 +22,18 @@
// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification // Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
// http://www.eecs.berkeley.edu/~alanmi/abc/ // http://www.eecs.berkeley.edu/~alanmi/abc/
#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" #if 0
#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p" // Based on &flow3 - better QoR but more experimental
//#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2" #define ABC_COMMAND_LUT "&st; &ps -l; "/*"&sweep -v;"*/" &scorr; " \
#define ABC_COMMAND_LUT "&st; &sweep; &scorr; "/*"&dc2; */"&retime; &dch -f; &ps -l; &if {W} -v; &ps -l" "&st; &if {W}; &save; &st; &syn2; &if {W}; &save; &load; "\
#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}" "&st; &if -g -K 6; &dch -f; &if {W}; &save; &load; "\
#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" "&st; &if -g -K 6; &synch2; &if {W}; &save; &load"
#else
#define ABC_COMMAND_LUT "&st; &sweep; &scorr; "/*"&dc2; "*/"&retime; &dch -f; &ps -l; &if {W} {D} -v; "/*"&mfs; "*/"&ps -l"
#endif
#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" #define ABC_FAST_COMMAND_LUT "&st; &retime; &if {W}"
#define ABC_FAST_COMMAND_LUT "&st; &retime; &if"
#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}"
#define ABC_FAST_COMMAND_DFL "strash; dretime; map"
#include "kernel/register.h" #include "kernel/register.h"
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
@ -61,17 +61,12 @@ extern "C" int Abc_RealMain(int argc, char *argv[]);
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
bool map_mux4;
bool map_mux8;
bool map_mux16;
bool markgroups; bool markgroups;
int map_autoidx; int map_autoidx;
SigMap assign_map; SigMap assign_map;
RTLIL::Module *module; RTLIL::Module *module;
std::map<RTLIL::SigBit, int> signal_map; std::map<RTLIL::SigBit, int> signal_map;
std::map<RTLIL::SigBit, RTLIL::State> signal_init; std::map<RTLIL::SigBit, RTLIL::State> signal_init;
pool<std::string> enabled_gates;
bool recover_init; bool recover_init;
bool clk_polarity, en_polarity; bool clk_polarity, en_polarity;
@ -246,32 +241,9 @@ struct abc_output_filter
} }
}; };
static std::pair<RTLIL::IdString, int> wideports_split(std::string name)
{
int pos = -1;
if (name.empty() || name.back() != ']')
goto failed;
for (int i = 0; i+1 < GetSize(name); i++) {
if (name[i] == '[')
pos = i;
else if (name[i] < '0' || name[i] > '9')
pos = -1;
else if (i == pos+1 && name[i] == '0' && name[i+1] != ']')
pos = -1;
}
if (pos >= 0)
return std::pair<RTLIL::IdString, int>(RTLIL::escape_id(name.substr(0, pos)), atoi(name.c_str() + pos+1));
failed:
return std::pair<RTLIL::IdString, int>(name, 0);
}
void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, bool keepff, std::string delay_target, std::string lutin_shared, bool fast_mode,
const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, std::string box_file, std::string lut_file, const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, std::string box_file, std::string lut_file,
std::string wire_delay) std::string wire_delay)
{ {
@ -325,11 +297,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
std::string abc_script; std::string abc_script;
if (!liberty_file.empty()) {
abc_script += stringf("read_lib -w %s; ", liberty_file.c_str());
if (!constr_file.empty())
abc_script += stringf("read_constr -v %s; ", constr_file.c_str());
} else
if (!lut_costs.empty()) { if (!lut_costs.empty()) {
abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
if (!box_file.empty()) if (!box_file.empty())
@ -342,7 +309,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
abc_script += stringf("read_box -v %s; ", box_file.c_str()); abc_script += stringf("read_box -v %s; ", box_file.c_str());
} }
else else
abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str()); log_abort();
abc_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); abc_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str());
@ -365,28 +332,18 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
//if (all_luts_cost_same && !fast_mode) //if (all_luts_cost_same && !fast_mode)
// abc_script += "; lutpack {S}"; // abc_script += "; lutpack {S}";
} else if (!liberty_file.empty()) } else
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR); log_abort();
else if (sop_mode)
abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP;
else
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
if (script_file.empty() && !delay_target.empty()) //if (script_file.empty() && !delay_target.empty())
for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1)) // for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8); // abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8);
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3); abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
for (size_t pos = abc_script.find("{I}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) //for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
abc_script = abc_script.substr(0, pos) + sop_inputs + abc_script.substr(pos+3); // abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3);
for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
for (size_t pos = abc_script.find("{W}"); pos != std::string::npos; pos = abc_script.find("{W}", pos)) for (size_t pos = abc_script.find("{W}"); pos != std::string::npos; pos = abc_script.find("{W}", pos))
abc_script = abc_script.substr(0, pos) + wire_delay + abc_script.substr(pos+3); abc_script = abc_script.substr(0, pos) + wire_delay + abc_script.substr(pos+3);
@ -414,6 +371,20 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
} }
} }
bool count_output = false;
for (auto port_name : module->ports) {
RTLIL::Wire *port_wire = module->wire(port_name);
log_assert(port_wire);
if (port_wire->port_output) {
count_output = true;
break;
}
}
log_push();
if (count_output)
{
design->selection_stack.emplace_back(false); design->selection_stack.emplace_back(false);
RTLIL::Selection& sel = design->selection_stack.back(); RTLIL::Selection& sel = design->selection_stack.back();
sel.select(module); sel.select(module);
@ -425,18 +396,24 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
handle_loops(design); handle_loops(design);
Pass::call(design, stringf("write_xaiger -O -map %s/input.sym %s/input.xaig; ", tempdir_name.c_str(), tempdir_name.c_str())); //log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
// count_gates, GetSize(signal_list), count_input, count_output);
#if 0 Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));
std::string buffer = stringf("%s/%s", tempdir_name.c_str(), "input.xaig");
std::string buffer;
std::ifstream ifs; std::ifstream ifs;
#if 0
buffer = stringf("%s/%s", tempdir_name.c_str(), "input.xaig");
ifs.open(buffer); ifs.open(buffer);
if (ifs.fail()) if (ifs.fail())
log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym");
log_assert(!design->module("$__abc9__")); log_assert(!design->module("$__abc9__"));
AigerReader reader(design, ifs, "$__abc9__", "" /* clk_name */, buffer.c_str() /* map_filename */, false /* wideports */); {
AigerReader reader(design, ifs, "$__abc9__", "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */);
reader.parse_xaiger(); reader.parse_xaiger();
}
ifs.close(); ifs.close();
Pass::call(design, stringf("write_verilog -noexpr -norename %s/%s", tempdir_name.c_str(), "input.v")); Pass::call(design, stringf("write_verilog -noexpr -norename %s/%s", tempdir_name.c_str(), "input.v"));
design->remove(design->module("$__abc9__")); design->remove(design->module("$__abc9__"));
@ -462,16 +439,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
} }
module->fixup_ports(); module->fixup_ports();
//log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
// count_gates, GetSize(signal_list), count_input, count_output);
log_push();
//if (count_output > 0)
{
log_header(design, "Executing ABC9.\n"); log_header(design, "Executing ABC9.\n");
std::string buffer;
if (!lut_costs.empty()) { if (!lut_costs.empty()) {
buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str());
f = fopen(buffer.c_str(), "wt"); f = fopen(buffer.c_str(), "wt");
@ -507,16 +477,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig"); buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig");
std::ifstream ifs;
ifs.open(buffer); ifs.open(buffer);
if (ifs.fail()) if (ifs.fail())
log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
bool builtin_lib = liberty_file.empty();
//parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_", false, sop_mode);
buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym");
log_assert(!design->module("$__abc9__")); log_assert(!design->module("$__abc9__"));
AigerReader reader(design, ifs, "$__abc9__", "" /* clk_name */, buffer.c_str() /* map_filename */, false /* wideports */); AigerReader reader(design, ifs, "$__abc9__", "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */);
reader.parse_xaiger(); reader.parse_xaiger();
ifs.close(); ifs.close();
@ -536,22 +503,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (markgroups) remap_wire->attributes["\\abcgroup"] = map_autoidx; if (markgroups) remap_wire->attributes["\\abcgroup"] = map_autoidx;
if (w->port_output) { if (w->port_output) {
RTLIL::Wire *wire = module->wire(w->name); RTLIL::Wire *wire = module->wire(w->name);
if (wire) { log_assert(wire);
for (int i = 0; i < GetSize(wire); i++) for (int i = 0; i < GetSize(wire); i++)
output_bits.insert({wire, i}); output_bits.insert({wire, i});
} }
else {
// Attempt another wideports_split here because there
// exists the possibility that different bits of a port
// could be an input and output, therefore parse_xaiger()
// could not combine it into a wideport
auto r = wideports_split(w->name.str());
wire = module->wire(r.first);
log_assert(wire);
int i = r.second;
output_bits.insert({wire, i});
}
}
} }
// Remove all AND, NOT, and ABC box instances // Remove all AND, NOT, and ABC box instances
@ -583,8 +538,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
std::map<std::string, int> cell_stats; std::map<std::string, int> cell_stats;
for (auto c : mapped_mod->cells()) for (auto c : mapped_mod->cells())
{
if (builtin_lib)
{ {
if (c->type == "$_NOT_") { if (c->type == "$_NOT_") {
RTLIL::Cell *cell; RTLIL::Cell *cell;
@ -592,7 +545,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit(); RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit();
if (!a_bit.wire) { if (!a_bit.wire) {
c->setPort("\\Y", module->addWire(NEW_ID)); c->setPort("\\Y", module->addWire(NEW_ID));
module->connect(module->wires_[remap_name(y_bit.wire->name)], RTLIL::S1); RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
log_assert(wire);
module->connect(RTLIL::SigBit(wire, y_bit.offset), RTLIL::S1);
} }
else if (!lut_costs.empty() || !lut_file.empty()) { else if (!lut_costs.empty() || !lut_file.empty()) {
RTLIL::Cell* driving_lut = nullptr; RTLIL::Cell* driving_lut = nullptr;
@ -642,7 +597,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
continue; continue;
} }
}
cell_stats[RTLIL::unescape_id(c->type)]++; cell_stats[RTLIL::unescape_id(c->type)]++;
if (c->type == "$lut") { if (c->type == "$lut") {
@ -713,22 +667,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (!w->port_input && !w->port_output) if (!w->port_input && !w->port_output)
continue; continue;
RTLIL::Wire *wire = module->wire(w->name); RTLIL::Wire *wire = module->wire(w->name);
RTLIL::Wire *remap_wire = module->wire(remap_name(w->name));
RTLIL::SigSpec signal;
if (wire) {
signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire));
}
else {
// Attempt another wideports_split here because there
// exists the possibility that different bits of a port
// could be an input and output, therefore parse_xaiger()
// could not combine it into a wideport
auto r = wideports_split(w->name.str());
wire = module->wire(r.first);
log_assert(wire); log_assert(wire);
int i = r.second; RTLIL::Wire *remap_wire = module->wire(remap_name(w->name));
signal = RTLIL::SigSpec(wire, i); RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire));
}
log_assert(GetSize(signal) >= GetSize(remap_wire)); log_assert(GetSize(signal) >= GetSize(remap_wire));
log_assert(w->port_input || w->port_output); log_assert(w->port_input || w->port_output);
@ -753,10 +694,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
design->remove(mapped_mod); design->remove(mapped_mod);
} }
//else else
//{ {
// log("Don't call ABC as there is nothing to map.\n"); log("Don't call ABC as there is nothing to map.\n");
//} }
if (cleanup) if (cleanup)
{ {
@ -768,7 +709,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
} }
struct Abc9Pass : public Pass { struct Abc9Pass : public Pass {
Abc9Pass() : Pass("abc9", "use ABC for technology mapping") { } Abc9Pass() : Pass("abc9", "use ABC9 for technology mapping") { }
void help() YS_OVERRIDE void help() YS_OVERRIDE
{ {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@ -796,76 +737,30 @@ struct Abc9Pass : public Pass {
log("\n"); log("\n");
log(" if no -script parameter is given, the following scripts are used:\n"); log(" if no -script parameter is given, the following scripts are used:\n");
log("\n"); log("\n");
log(" for -liberty without -constr:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_LIB).c_str());
log("\n");
log(" for -liberty with -constr:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
log("\n");
log(" for -lut/-luts (only one LUT size):\n"); log(" for -lut/-luts (only one LUT size):\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack {S}").c_str()); log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str());
log("\n"); log("\n");
log(" for -lut/-luts (different LUT sizes):\n"); log(" for -lut/-luts (different LUT sizes):\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str()); log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str());
log("\n"); log("\n");
log(" for -sop:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_SOP).c_str());
log("\n");
log(" otherwise:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_DFL).c_str());
log("\n");
log(" -fast\n"); log(" -fast\n");
log(" use different default scripts that are slightly faster (at the cost\n"); log(" use different default scripts that are slightly faster (at the cost\n");
log(" of output quality):\n"); log(" of output quality):\n");
log("\n"); log("\n");
log(" for -liberty without -constr:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LIB).c_str());
log("\n");
log(" for -liberty with -constr:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_CTR).c_str());
log("\n");
log(" for -lut/-luts:\n"); log(" for -lut/-luts:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT).c_str()); log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT).c_str());
log("\n"); log("\n");
log(" for -sop:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_SOP).c_str());
log("\n");
log(" otherwise:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_DFL).c_str());
log("\n");
log(" -liberty <file>\n");
log(" generate netlists for the specified cell library (using the liberty\n");
log(" file format).\n");
log("\n");
log(" -constr <file>\n");
log(" pass this file with timing constraints to ABC. Use with -liberty.\n");
log("\n");
log(" a constr file contains two lines:\n");
log(" set_driving_cell <cell_name>\n");
log(" set_load <floating_point_number>\n");
log("\n");
log(" the set_driving_cell statement defines which cell type is assumed to\n");
log(" drive the primary inputs and the set_load statement sets the load in\n");
log(" femtofarads for each primary output.\n");
log("\n");
log(" -D <picoseconds>\n"); log(" -D <picoseconds>\n");
log(" set delay target. the string {D} in the default scripts above is\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(" replaced by this option when used, and an empty string otherwise\n");
log(" this also replaces 'dretime' with 'dretime; retime -o {D}' in the\n"); log(" (indicating best possible delay).\n");
log(" default scripts above.\n"); // log(" This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n");
log("\n"); // log(" default scripts above.\n");
log(" -I <num>\n");
log(" maximum number of SOP inputs.\n");
log(" (replaces {I} in the default scripts above)\n");
log("\n");
log(" -P <num>\n");
log(" maximum number of SOP products.\n");
log(" (replaces {P} in the default scripts above)\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("\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(" -lut <width>\n");
log(" generate netlist using luts of (max) the specified width.\n"); log(" generate netlist using luts of (max) the specified width.\n");
log("\n"); log("\n");
@ -882,42 +777,19 @@ struct Abc9Pass : public Pass {
log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); log(" generate netlist using luts. Use the specified costs for luts with 1,\n");
log(" 2, 3, .. inputs.\n"); log(" 2, 3, .. inputs.\n");
log("\n"); log("\n");
log(" -sop\n"); // log(" -dff\n");
log(" map to sum-of-product cells and inverters\n"); // log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
log("\n"); // log(" clock domains are automatically partitioned in clock domains and each\n");
// log(" -mux4, -mux8, -mux16\n"); // log(" domain is passed through ABC independently.\n");
// log(" try to extract 4-input, 8-input, and/or 16-input muxes\n"); // log("\n");
// log(" (ignored when used with -liberty or -lut)\n"); // log(" -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]\n");
// log(" use only the specified clock domain. this is like -dff, but only FF\n");
// log(" cells that belong to the specified clock domain are used.\n");
// log("\n");
// log(" -keepff\n");
// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
// log(" them, for example for equivalence checking.)\n");
// log("\n"); // log("\n");
log(" -g type1,type2,...\n");
log(" Map to the specified list of gate types. Supported gates types are:\n");
log(" AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX, AOI3, OAI3, AOI4, OAI4.\n");
log(" (The NOT gate is always added to this list automatically.)\n");
log("\n");
log(" The following aliases can be used to reference common sets of gate types:\n");
log(" simple: AND OR XOR MUX\n");
log(" cmos2: NAND NOR\n");
log(" cmos3: NAND NOR AOI3 OAI3\n");
log(" cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n");
log(" gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n");
log(" aig: AND NAND OR NOR ANDNOT ORNOT\n");
log("\n");
log(" Prefix a gate type with a '-' to remove it from the list. For example\n");
log(" the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent.\n");
log("\n");
log(" -dff\n");
log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
log(" clock domains are automatically partitioned in clock domains and each\n");
log(" domain is passed through ABC independently.\n");
log("\n");
log(" -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]\n");
log(" use only the specified clock domain. this is like -dff, but only FF\n");
log(" cells that belong to the specified clock domain are used.\n");
log("\n");
log(" -keepff\n");
log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
log(" them, for example for equivalence checking.)\n");
log("\n");
log(" -nocleanup\n"); log(" -nocleanup\n");
log(" when this option is used, the temporary files created by this pass\n"); log(" when this option is used, the temporary files created by this pass\n");
log(" are not removed. this is useful for debugging.\n"); log(" are not removed. this is useful for debugging.\n");
@ -934,14 +806,11 @@ struct Abc9Pass : public Pass {
log(" -box <file>\n"); log(" -box <file>\n");
log(" pass this file with box library to ABC. Use with -lut.\n"); log(" pass this file with box library to ABC. Use with -lut.\n");
log("\n"); log("\n");
log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n");
log("loaded into ABC before the ABC script is executed.\n");
log("\n");
log("Note that this is a logic optimization pass within Yosys that is calling ABC\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("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("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("output when passing an ABC script that writes a file. Instead write your full\n");
log("design as BLIF file with write_blif and the load that into ABC externally if\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("you want to use ABC to convert your design into another format.\n");
log("\n"); log("\n");
log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
@ -949,7 +818,7 @@ struct Abc9Pass : public Pass {
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{ {
log_header(design, "Executing ABC9 pass (technology mapping using ABC).\n"); log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n");
log_push(); log_push();
assign_map.clear(); assign_map.clear();
@ -963,8 +832,8 @@ struct Abc9Pass : public Pass {
#else #else
std::string exe_file = proc_self_dirname() + "yosys-abc"; std::string exe_file = proc_self_dirname() + "yosys-abc";
#endif #endif
std::string script_file, liberty_file, constr_file, clk_str, box_file, lut_file; std::string script_file, clk_str, box_file, lut_file;
std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1", wire_delay; std::string delay_target, lutin_shared = "-S 1", wire_delay;
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
bool show_tempdir = false, sop_mode = false; bool show_tempdir = false, sop_mode = false;
vector<int> lut_costs; vector<int> lut_costs;
@ -975,11 +844,6 @@ struct Abc9Pass : public Pass {
show_tempdir = true; show_tempdir = true;
#endif #endif
map_mux4 = false;
map_mux8 = false;
map_mux16 = false;
enabled_gates.clear();
#ifdef _WIN32 #ifdef _WIN32
#ifndef ABCEXTERNAL #ifndef ABCEXTERNAL
if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe")) if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe"))
@ -1006,36 +870,14 @@ struct Abc9Pass : public Pass {
script_file = std::string(pwd) + "/" + script_file; script_file = std::string(pwd) + "/" + script_file;
continue; continue;
} }
if (arg == "-liberty" && argidx+1 < args.size()) {
liberty_file = args[++argidx];
rewrite_filename(liberty_file);
if (!liberty_file.empty() && !is_absolute_path(liberty_file))
liberty_file = std::string(pwd) + "/" + liberty_file;
continue;
}
if (arg == "-constr" && argidx+1 < args.size()) {
constr_file = args[++argidx];
rewrite_filename(constr_file);
if (!constr_file.empty() && !is_absolute_path(constr_file))
constr_file = std::string(pwd) + "/" + constr_file;
continue;
}
if (arg == "-D" && argidx+1 < args.size()) { if (arg == "-D" && argidx+1 < args.size()) {
delay_target = "-D " + args[++argidx]; delay_target = "-D " + args[++argidx];
continue; continue;
} }
if (arg == "-I" && argidx+1 < args.size()) { //if (arg == "-S" && argidx+1 < args.size()) {
sop_inputs = "-I " + args[++argidx]; // lutin_shared = "-S " + args[++argidx];
continue; // continue;
} //}
if (arg == "-P" && argidx+1 < args.size()) {
sop_products = "-P " + args[++argidx];
continue;
}
if (arg == "-S" && argidx+1 < args.size()) {
lutin_shared = "-S " + args[++argidx];
continue;
}
if (arg == "-lut" && argidx+1 < args.size()) { if (arg == "-lut" && argidx+1 < args.size()) {
string arg = args[++argidx]; string arg = args[++argidx];
size_t pos = arg.find_first_of(':'); size_t pos = arg.find_first_of(':');
@ -1079,126 +921,23 @@ struct Abc9Pass : public Pass {
} }
continue; continue;
} }
if (arg == "-sop") {
sop_mode = true;
continue;
}
if (arg == "-mux4") {
map_mux4 = true;
continue;
}
if (arg == "-mux8") {
map_mux8 = true;
continue;
}
if (arg == "-mux16") {
map_mux16 = true;
continue;
}
if (arg == "-dress") {
// TODO
//abc_dress = true;
continue;
}
if (arg == "-g" && argidx+1 < args.size()) {
for (auto g : split_tokens(args[++argidx], ",")) {
vector<string> gate_list;
bool remove_gates = false;
if (GetSize(g) > 0 && g[0] == '-') {
remove_gates = true;
g = g.substr(1);
}
if (g == "AND") goto ok_gate;
if (g == "NAND") goto ok_gate;
if (g == "OR") goto ok_gate;
if (g == "NOR") goto ok_gate;
if (g == "XOR") goto ok_gate;
if (g == "XNOR") goto ok_gate;
if (g == "ANDNOT") goto ok_gate;
if (g == "ORNOT") goto ok_gate;
if (g == "MUX") goto ok_gate;
if (g == "AOI3") goto ok_gate;
if (g == "OAI3") goto ok_gate;
if (g == "AOI4") goto ok_gate;
if (g == "OAI4") goto ok_gate;
if (g == "simple") {
gate_list.push_back("AND");
gate_list.push_back("OR");
gate_list.push_back("XOR");
gate_list.push_back("MUX");
goto ok_alias;
}
if (g == "cmos2") {
gate_list.push_back("NAND");
gate_list.push_back("NOR");
goto ok_alias;
}
if (g == "cmos3") {
gate_list.push_back("NAND");
gate_list.push_back("NOR");
gate_list.push_back("AOI3");
gate_list.push_back("OAI3");
goto ok_alias;
}
if (g == "cmos4") {
gate_list.push_back("NAND");
gate_list.push_back("NOR");
gate_list.push_back("AOI3");
gate_list.push_back("OAI3");
gate_list.push_back("AOI4");
gate_list.push_back("OAI4");
goto ok_alias;
}
if (g == "gates") {
gate_list.push_back("AND");
gate_list.push_back("NAND");
gate_list.push_back("OR");
gate_list.push_back("NOR");
gate_list.push_back("XOR");
gate_list.push_back("XNOR");
gate_list.push_back("ANDNOT");
gate_list.push_back("ORNOT");
goto ok_alias;
}
if (g == "aig") {
gate_list.push_back("AND");
gate_list.push_back("NAND");
gate_list.push_back("OR");
gate_list.push_back("NOR");
gate_list.push_back("ANDNOT");
gate_list.push_back("ORNOT");
goto ok_alias;
}
cmd_error(args, argidx, stringf("Unsupported gate type: %s", g.c_str()));
ok_gate:
gate_list.push_back(g);
ok_alias:
for (auto gate : gate_list) {
if (remove_gates)
enabled_gates.erase(gate);
else
enabled_gates.insert(gate);
}
}
continue;
}
if (arg == "-fast") { if (arg == "-fast") {
fast_mode = true; fast_mode = true;
continue; continue;
} }
if (arg == "-dff") { //if (arg == "-dff") {
dff_mode = true; // dff_mode = true;
continue; // continue;
} //}
if (arg == "-clk" && argidx+1 < args.size()) { //if (arg == "-clk" && argidx+1 < args.size()) {
clk_str = args[++argidx]; // clk_str = args[++argidx];
dff_mode = true; // dff_mode = true;
continue; // continue;
} //}
if (arg == "-keepff") { //if (arg == "-keepff") {
keepff = true; // keepff = true;
continue; // continue;
} //}
if (arg == "-nocleanup") { if (arg == "-nocleanup") {
cleanup = false; cleanup = false;
continue; continue;
@ -1226,11 +965,6 @@ struct Abc9Pass : public Pass {
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
if ((!lut_costs.empty() || !lut_file.empty()) && !liberty_file.empty())
log_cmd_error("Got -lut and -liberty! This two options are exclusive.\n");
if (!constr_file.empty() && liberty_file.empty())
log_cmd_error("Got -constr but no -liberty!\n");
for (auto mod : design->selected_modules()) for (auto mod : design->selected_modules())
{ {
if (mod->attributes.count("\\abc_box_id")) if (mod->attributes.count("\\abc_box_id"))
@ -1262,8 +996,8 @@ struct Abc9Pass : public Pass {
} }
if (!dff_mode || !clk_str.empty()) { if (!dff_mode || !clk_str.empty()) {
abc9_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, delay_target, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode,
box_file, lut_file, wire_delay); box_file, lut_file, wire_delay);
continue; continue;
} }
@ -1408,8 +1142,8 @@ struct Abc9Pass : public Pass {
clk_sig = assign_map(std::get<1>(it.first)); clk_sig = assign_map(std::get<1>(it.first));
en_polarity = std::get<2>(it.first); en_polarity = std::get<2>(it.first);
en_sig = assign_map(std::get<3>(it.first)); en_sig = assign_map(std::get<3>(it.first));
abc9_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$",
keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, keepff, delay_target, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode,
box_file, lut_file, wire_delay); box_file, lut_file, wire_delay);
assign_map.set(mod); assign_map.set(mod);
} }

View File

@ -293,13 +293,10 @@ struct ShregmapWorker
if (opts.init || sigbit_init.count(q_bit) == 0) if (opts.init || sigbit_init.count(q_bit) == 0)
{ {
auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell)); if (sigbit_chain_next.count(d_bit)) {
if (!r.second) {
sigbit_with_non_chain_users.insert(d_bit); sigbit_with_non_chain_users.insert(d_bit);
Wire *wire = module->addWire(NEW_ID); } else
module->connect(wire, d_bit); sigbit_chain_next[d_bit] = cell;
sigbit_chain_next.insert(std::make_pair(wire, cell));
}
sigbit_chain_prev[q_bit] = cell; sigbit_chain_prev[q_bit] = cell;
continue; continue;

View File

@ -76,7 +76,7 @@ struct SynthPass : public ScriptPass
log(" synonymous to the end of the command list.\n"); log(" synonymous to the end of the command list.\n");
log("\n"); log("\n");
log(" -abc9\n"); log(" -abc9\n");
log(" use abc9 instead of abc\n"); log(" use new ABC9 flow (EXPERIMENTAL)\n");
log("\n"); log("\n");
log("\n"); log("\n");
log("The following commands are executed by this synthesis command:\n"); log("The following commands are executed by this synthesis command:\n");
@ -174,6 +174,9 @@ struct SynthPass : public ScriptPass
if (!design->full_selection()) if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n"); log_cmd_error("This command only operates on fully selected designs!\n");
if (abc == "abc9" && !lut)
log_cmd_error("ABC9 flow only supported for FPGA synthesis (using '-lut' option)");
log_header(design, "Executing SYNTH pass.\n"); log_header(design, "Executing SYNTH pass.\n");
log_push(); log_push();

View File

@ -11,6 +11,9 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram.txt))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.box))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.lut))
EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
.SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk .SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk

36
techlibs/ecp5/abc_5g.box Normal file
View File

@ -0,0 +1,36 @@
# Box 1 : CCU2C (2xCARRY + 2xLUT4)
# Outputs: S0, S1, COUT
# name ID w/b ins outs
CCU2C 1 1 9 3
#A0 A1 B0 B1 C0 C1 D0 D1 CIN
379 - 379 - 275 - 141 - 257
630 379 630 379 526 275 392 141 273
516 516 516 516 412 412 278 278 43
# Box 2 : TRELLIS_DPR16X4 (16x4 dist ram)
# Outputs: DO0, DO1, DO2, DO3, DO4
# name ID w/b ins outs
TRELLIS_DPR16X4 2 0 14 4
#DI0 DI1 DI2 DI3 RAD0 RAD1 RAD2 RAD3 WAD0 WAD1 WAD2 WAD3 WCK WRE
- - - - 141 379 275 379 - - - - - -
- - - - 141 379 275 379 - - - - - -
- - - - 141 379 275 379 - - - - - -
- - - - 141 379 275 379 - - - - - -
# Box 3 : PFUMX (MUX2)
# Outputs: Z
# name ID w/b ins outs
PFUMX 3 1 3 1
#ALUT BLUT C0
98 98 151
# Box 4 : L6MUX21 (MUX2)
# Outputs: Z
# name ID w/b ins outs
L6MUX21 4 1 3 1
#D0 D1 SD
140 141 148

25
techlibs/ecp5/abc_5g.lut Normal file
View File

@ -0,0 +1,25 @@
# ECP5-5G LUT library for ABC
# Note that ECP5 architecture assigns difference
# in LUT input delay to interconnect, so this is
# considered too
# Simple LUTs
# area D C B A
1 1 141
2 1 141 275
3 1 141 275 379
4 1 141 275 379 379
# LUT5 = 2x LUT4 + PFUMX
# area M0 D C B A
5 2 151 239 373 477 477
# LUT6 = 2x LUT5 + MUX2
# area M1 M0 D C B A
6 4 148 292 380 514 618 618
# LUT7 = 2x LUT6 + MUX2
# area M2 M1 M0 D C B A
7 8 148 289 433 521 655 759 759

View File

@ -70,80 +70,107 @@ module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;
parameter LUT = 0; parameter LUT = 0;
// 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;
input [2**P_WIDTH-1:0] orig;
integer i;
begin
permute_init = 0;
for (i = 0; i < 2**P_WIDTH; i = i + 1)
permute_init[i] = orig[permute_index(i)];
end
endfunction
parameter [2**P_WIDTH-1:0] P_LUT = permute_init(LUT);
input [WIDTH-1:0] A; input [WIDTH-1:0] A;
output Y; output Y;
generate generate
if (WIDTH == 1) begin if (WIDTH == 1) begin
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y), LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
.A(A[0]), .B(1'b0), .C(1'b0), .D(1'b0)); .A(1'b0), .B(1'b0), .C(1'b0), .D(A[0]));
end else end else
if (WIDTH == 2) begin if (WIDTH == 2) begin
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y), LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
.A(A[0]), .B(A[1]), .C(1'b0), .D(1'b0)); .A(1'b0), .B(1'b0), .C(A[1]), .D(A[0]));
end else end else
if (WIDTH == 3) begin if (WIDTH == 3) begin
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y), LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
.A(A[0]), .B(A[1]), .C(A[2]), .D(1'b0)); .A(1'b0), .B(A[2]), .C(A[1]), .D(A[0]));
end else end else
if (WIDTH == 4) begin if (WIDTH == 4) begin
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y), LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[3]), .B(A[2]), .C(A[1]), .D(A[0]));
`ifndef NO_PFUMUX `ifndef NO_PFUMUX
end else end else
if (WIDTH == 5) begin if (WIDTH == 5) begin
wire f0, f1; wire f0, f1;
LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1]));
LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1]));
PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(Y)); PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[0]), .Z(Y));
end else end else
if (WIDTH == 6) begin if (WIDTH == 6) begin
wire f0, f1, f2, f3, g0, g1; wire f0, f1, f2, f3, g0, g1;
LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2), LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3), LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0)); PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[1]), .Z(g0));
PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1)); PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[1]), .Z(g1));
L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[5]), .Z(Y)); L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[0]), .Z(Y));
end else end else
if (WIDTH == 7) begin if (WIDTH == 7) begin
wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1; wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1;
LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2), LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3), LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
LUT4 #(.INIT(LUT[79:64])) lut4 (.Z(f4), LUT4 #(.INIT(P_LUT[79:64])) lut4 (.Z(f4),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
LUT4 #(.INIT(LUT[95:80])) lut5 (.Z(f5), LUT4 #(.INIT(P_LUT[95:80])) lut5 (.Z(f5),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
LUT4 #(.INIT(LUT[111: 96])) lut6 (.Z(f6), LUT4 #(.INIT(P_LUT[111: 96])) lut6 (.Z(f6),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
LUT4 #(.INIT(LUT[127:112])) lut7 (.Z(f7), LUT4 #(.INIT(P_LUT[127:112])) lut7 (.Z(f7),
.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0)); PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[2]), .Z(g0));
PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1)); PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[2]), .Z(g1));
PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[4]), .Z(g2)); PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[2]), .Z(g2));
PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[4]), .Z(g3)); PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[2]), .Z(g3));
L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[5]), .Z(h0)); L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[1]), .Z(h0));
L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[5]), .Z(h1)); L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[1]), .Z(h1));
L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[6]), .Z(Y)); L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[0]), .Z(Y));
`endif `endif
end else begin end else begin
wire _TECHMAP_FAIL_ = 1; wire _TECHMAP_FAIL_ = 1;

View File

@ -9,15 +9,17 @@ module LUT4(input A, B, C, D, output Z);
endmodule endmodule
// --------------------------------------- // ---------------------------------------
(* abc_box_id=4, lib_whitebox *)
module L6MUX21 (input D0, D1, SD, output Z); module L6MUX21 (input D0, D1, SD, output Z);
assign Z = SD ? D1 : D0; assign Z = SD ? D1 : D0;
endmodule endmodule
// --------------------------------------- // ---------------------------------------
(* abc_box_id=1, abc_carry, lib_whitebox *)
module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1, module CCU2C((* abc_carry_in *) input CIN,
output S0, S1, COUT); input A0, B0, C0, D0, A1, B1, C1, D1,
output S0, S1,
(* abc_carry_out *) output COUT);
parameter [15:0] INIT0 = 16'h0000; parameter [15:0] INIT0 = 16'h0000;
parameter [15:0] INIT1 = 16'h0000; parameter [15:0] INIT1 = 16'h0000;
@ -26,9 +28,13 @@ module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1,
// First half // First half
wire LUT4_0, LUT2_0; wire LUT4_0, LUT2_0;
`ifdef _ABC
assign LUT4_0 = INIT0[{D0, C0, B0, A0}];
assign LUT2_0 = INIT0[{2'b00, B0, A0}];
`else
LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0)); LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0));
LUT2 #(.INIT(INIT0[3:0])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0)); LUT2 #(.INIT(INIT0[3:0])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0));
`endif
wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN; wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN;
assign S0 = LUT4_0 ^ gated_cin_0; assign S0 = LUT4_0 ^ gated_cin_0;
@ -37,9 +43,13 @@ module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1,
// Second half // Second half
wire LUT4_1, LUT2_1; wire LUT4_1, LUT2_1;
`ifdef _ABC
assign LUT4_1 = INIT1[{D1, C1, B1, A1}];
assign LUT2_1 = INIT1[{2'b00, B1, A1}];
`else
LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1)); LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1));
LUT2 #(.INIT(INIT1[3:0])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1)); LUT2 #(.INIT(INIT1[3:0])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1));
`endif
wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0; wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0;
assign S1 = LUT4_1 ^ gated_cin_1; assign S1 = LUT4_1 ^ gated_cin_1;
@ -90,13 +100,13 @@ module TRELLIS_RAM16X2 (
endmodule endmodule
// --------------------------------------- // ---------------------------------------
(* abc_box_id=3, lib_whitebox *)
module PFUMX (input ALUT, BLUT, C0, output Z); module PFUMX (input ALUT, BLUT, C0, output Z);
assign Z = C0 ? ALUT : BLUT; assign Z = C0 ? ALUT : BLUT;
endmodule endmodule
// --------------------------------------- // ---------------------------------------
//(* abc_box_id=2 *)
module TRELLIS_DPR16X4 ( module TRELLIS_DPR16X4 (
input [3:0] DI, input [3:0] DI,
input [3:0] WAD, input [3:0] WAD,

View File

@ -82,6 +82,9 @@ struct SynthEcp5Pass : public ScriptPass
log(" -abc2\n"); log(" -abc2\n");
log(" run two passes of 'abc' for slightly improved logic density\n"); log(" run two passes of 'abc' for slightly improved logic density\n");
log("\n"); log("\n");
log(" -abc9\n");
log(" use new ABC9 flow (EXPERIMENTAL)\n");
log("\n");
log(" -vpr\n"); log(" -vpr\n");
log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" generate an output netlist (and BLIF file) suitable for VPR\n");
log(" (this feature is experimental and incomplete)\n"); log(" (this feature is experimental and incomplete)\n");
@ -93,7 +96,7 @@ struct SynthEcp5Pass : public ScriptPass
} }
string top_opt, blif_file, edif_file, json_file; string top_opt, blif_file, edif_file, json_file;
bool noccu2, nodffe, nobram, nodram, nomux, flatten, retime, abc2, vpr; bool noccu2, nodffe, nobram, nodram, nomux, flatten, retime, abc2, abc9, vpr;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
@ -110,6 +113,7 @@ struct SynthEcp5Pass : public ScriptPass
retime = false; retime = false;
abc2 = false; abc2 = false;
vpr = false; vpr = false;
abc9 = false;
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@ -184,6 +188,10 @@ struct SynthEcp5Pass : public ScriptPass
vpr = true; vpr = true;
continue; continue;
} }
if (args[argidx] == "-abc9") {
abc9 = true;
continue;
}
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
@ -203,7 +211,7 @@ struct SynthEcp5Pass : public ScriptPass
{ {
if (check_label("begin")) if (check_label("begin"))
{ {
run("read_verilog -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v"); run("read_verilog -D_ABC -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
} }
@ -264,10 +272,15 @@ struct SynthEcp5Pass : public ScriptPass
run("abc", " (only if -abc2)"); run("abc", " (only if -abc2)");
} }
run("techmap -map +/ecp5/latches_map.v"); run("techmap -map +/ecp5/latches_map.v");
if (abc9) {
run("abc9 -lut +/ecp5/abc_5g.lut -box +/ecp5/abc_5g.box -W 200");
} else {
if (nomux) if (nomux)
run("abc -lut 4 -dress"); run("abc -lut 4 -dress");
else else
run("abc -lut 4:7 -dress"); run("abc -lut 4:7 -dress");
}
run("clean"); run("clean");
} }

View File

@ -110,4 +110,4 @@ SB_CARRY 21 1 3 1
# Inputs: I0 I1 I2 I3 # Inputs: I0 I1 I2 I3
# Outputs: O # Outputs: O
SB_LUT4 22 1 4 1 SB_LUT4 22 1 4 1
465 558 589 661 661 589 558 465

View File

@ -143,8 +143,7 @@ endmodule
// Positive Edge SiliconBlue FF Cells // Positive Edge SiliconBlue FF Cells
(* abc_box_id = 1, abc_flop, lib_whitebox *) module SB_DFF (output `SB_DFF_REG, input C, D);
module SB_DFF ((* abc_flop_q *) output `SB_DFF_REG, input C, (* abc_flop_d *) input D);
`ifndef _ABC `ifndef _ABC
always @(posedge C) always @(posedge C)
Q <= D; Q <= D;
@ -153,15 +152,13 @@ module SB_DFF ((* abc_flop_q *) output `SB_DFF_REG, input C, (* abc_flop_d *) in
`endif `endif
endmodule endmodule
//(* abc_box_id = 2, abc_flop *) module SB_DFFE (output `SB_DFF_REG, input C, E, D);
module SB_DFFE ((* abc_flop_q *) output `SB_DFF_REG, input C, E, (* abc_flop_d *) input D);
always @(posedge C) always @(posedge C)
if (E) if (E)
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 3, abc_flop *) module SB_DFFSR (output `SB_DFF_REG, input C, R, D);
module SB_DFFSR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
always @(posedge C) always @(posedge C)
if (R) if (R)
Q <= 0; Q <= 0;
@ -169,8 +166,7 @@ module SB_DFFSR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 4, abc_flop *) module SB_DFFR (output `SB_DFF_REG, input C, R, D);
module SB_DFFR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
always @(posedge C, posedge R) always @(posedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -178,8 +174,7 @@ module SB_DFFR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 5, abc_flop *) module SB_DFFSS (output `SB_DFF_REG, input C, S, D);
module SB_DFFSS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
always @(posedge C) always @(posedge C)
if (S) if (S)
Q <= 1; Q <= 1;
@ -187,8 +182,7 @@ module SB_DFFSS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 6, abc_flop *) module SB_DFFS (output `SB_DFF_REG, input C, S, D);
module SB_DFFS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
always @(posedge C, posedge S) always @(posedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -196,8 +190,7 @@ module SB_DFFS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 7, abc_flop *) module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D);
module SB_DFFESR ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
always @(posedge C) always @(posedge C)
if (E) begin if (E) begin
if (R) if (R)
@ -207,8 +200,7 @@ module SB_DFFESR ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flo
end end
endmodule endmodule
//(* abc_box_id = 8, abc_flop *) module SB_DFFER (output `SB_DFF_REG, input C, E, R, D);
module SB_DFFER ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
always @(posedge C, posedge R) always @(posedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -216,8 +208,7 @@ module SB_DFFER ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 9, abc_flop *) module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D);
module SB_DFFESS ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
always @(posedge C) always @(posedge C)
if (E) begin if (E) begin
if (S) if (S)
@ -227,8 +218,7 @@ module SB_DFFESS ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flo
end end
endmodule endmodule
//(* abc_box_id = 10, abc_flop *) module SB_DFFES (output `SB_DFF_REG, input C, E, S, D);
module SB_DFFES ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
always @(posedge C, posedge S) always @(posedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -238,21 +228,18 @@ endmodule
// Negative Edge SiliconBlue FF Cells // Negative Edge SiliconBlue FF Cells
//(* abc_box_id = 11, abc_flop *) module SB_DFFN (output `SB_DFF_REG, input C, D);
module SB_DFFN ((* abc_flop_q *) output `SB_DFF_REG, input C, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 12, abc_flop *) module SB_DFFNE (output `SB_DFF_REG, input C, E, D);
module SB_DFFNE ((* abc_flop_q *) output `SB_DFF_REG, input C, E, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
if (E) if (E)
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 13, abc_flop *) module SB_DFFNSR (output `SB_DFF_REG, input C, R, D);
module SB_DFFNSR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
if (R) if (R)
Q <= 0; Q <= 0;
@ -260,8 +247,7 @@ module SB_DFFNSR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 14, abc_flop *) module SB_DFFNR (output `SB_DFF_REG, input C, R, D);
module SB_DFFNR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
always @(negedge C, posedge R) always @(negedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -269,8 +255,7 @@ module SB_DFFNR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 15, abc_flop *) module SB_DFFNSS (output `SB_DFF_REG, input C, S, D);
module SB_DFFNSS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
if (S) if (S)
Q <= 1; Q <= 1;
@ -278,8 +263,7 @@ module SB_DFFNSS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 16, abc_flop *) module SB_DFFNS (output `SB_DFF_REG, input C, S, D);
module SB_DFFNS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
always @(negedge C, posedge S) always @(negedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -287,8 +271,7 @@ module SB_DFFNS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 17, abc_flop *) module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D);
module SB_DFFNESR ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
if (E) begin if (E) begin
if (R) if (R)
@ -298,8 +281,7 @@ module SB_DFFNESR ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_fl
end end
endmodule endmodule
//(* abc_box_id = 18, abc_flop *) module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D);
module SB_DFFNER ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
always @(negedge C, posedge R) always @(negedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -307,8 +289,7 @@ module SB_DFFNER ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flo
Q <= D; Q <= D;
endmodule endmodule
//(* abc_box_id = 19, abc_flop *) module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D);
module SB_DFFNESS ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
if (E) begin if (E) begin
if (S) if (S)
@ -318,8 +299,7 @@ module SB_DFFNESS ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_fl
end end
endmodule endmodule
//(* abc_box_id = 20, abc_flop *) module SB_DFFNES (output `SB_DFF_REG, input C, E, S, D);
module SB_DFFNES ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
always @(negedge C, posedge S) always @(negedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -330,7 +310,7 @@ endmodule
// SiliconBlue RAM Cells // SiliconBlue RAM Cells
module SB_RAM40_4K ( module SB_RAM40_4K (
(* abc_flop_q *) output [15:0] RDATA, output [15:0] RDATA,
input RCLK, RCLKE, RE, input RCLK, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
input WCLK, WCLKE, WE, input WCLK, WCLKE, WE,
@ -498,7 +478,7 @@ module SB_RAM40_4K (
endmodule endmodule
module SB_RAM40_4KNR ( module SB_RAM40_4KNR (
(* abc_flop_q *) output [15:0] RDATA, output [15:0] RDATA,
input RCLKN, RCLKE, RE, input RCLKN, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
input WCLK, WCLKE, WE, input WCLK, WCLKE, WE,
@ -563,7 +543,7 @@ module SB_RAM40_4KNR (
endmodule endmodule
module SB_RAM40_4KNW ( module SB_RAM40_4KNW (
(* abc_flop_q *) output [15:0] RDATA, output [15:0] RDATA,
input RCLK, RCLKE, RE, input RCLK, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
input WCLKN, WCLKE, WE, input WCLKN, WCLKE, WE,
@ -628,7 +608,7 @@ module SB_RAM40_4KNW (
endmodule endmodule
module SB_RAM40_4KNRNW ( module SB_RAM40_4KNRNW (
(* abc_flop_q *) output [15:0] RDATA, output [15:0] RDATA,
input RCLKN, RCLKE, RE, input RCLKN, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
input WCLKN, WCLKE, WE, input WCLKN, WCLKE, WE,
@ -922,7 +902,7 @@ module SB_SPRAM256KA (
input [15:0] DATAIN, input [15:0] DATAIN,
input [3:0] MASKWREN, input [3:0] MASKWREN,
input WREN, CHIPSELECT, CLOCK, STANDBY, SLEEP, POWEROFF, input WREN, CHIPSELECT, CLOCK, STANDBY, SLEEP, POWEROFF,
(* abc_flop_q *) output reg [15:0] DATAOUT output reg [15:0] DATAOUT
); );
`ifndef BLACKBOX `ifndef BLACKBOX
`ifndef EQUIV `ifndef EQUIV

View File

@ -97,7 +97,7 @@ struct SynthIce40Pass : public ScriptPass
log(" (this feature is experimental and incomplete)\n"); log(" (this feature is experimental and incomplete)\n");
log("\n"); log("\n");
log(" -abc9\n"); log(" -abc9\n");
log(" use abc9 instead of abc\n"); log(" use new ABC9 flow (EXPERIMENTAL)\n");
log("\n"); log("\n");
log("\n"); log("\n");
log("The following commands are executed by this synthesis command:\n"); log("The following commands are executed by this synthesis command:\n");
@ -332,7 +332,7 @@ struct SynthIce40Pass : public ScriptPass
} }
if (!noabc) { if (!noabc) {
if (abc == "abc9") if (abc == "abc9")
run(abc + stringf(" -dress -lut +/ice40/abc_%s.lut -box +/ice40/abc_%s.box", device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)"); run(abc + stringf(" -lut +/ice40/abc_%s.lut -box +/ice40/abc_%s.box", device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)");
else else
run(abc + " -dress -lut 4", "(skip if -noabc)"); run(abc + " -dress -lut 4", "(skip if -noabc)");
} }

View File

@ -30,9 +30,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.box))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc.box)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.lut))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc.lut))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))

View File

@ -1,14 +0,0 @@
# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf
# K area delay
1 1 124
2 2 124 235
3 3 124 235 399
4 3 124 235 399 490
5 3 124 235 399 490 620
6 5 124 235 399 490 620 632
# F7BMUX
7 10 296 420 531 695 756 916 928
# F8MUX
# F8MUX+F7BMUX
8 20 273 569 693 804 968 1029 1189 1201

View File

@ -54,9 +54,9 @@ FDSE 7 0 4 1
# Inputs: C CE CLR D # Inputs: C CE CLR D
# Outputs: Q # Outputs: Q
FDCE 8 0 4 1 FDCE 8 0 4 1
- - 404 - - - - -
# Inputs: C CE D PRE # Inputs: C CE D PRE
# Outputs: Q # Outputs: Q
FDPE 9 0 4 1 FDPE 9 0 4 1
- - - 404 - - - -

View File

@ -0,0 +1,15 @@
# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/timings/CLBLL_L.sdf
# and https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/tile_type_CLBLL_L.json
# K area delay
1 1 127
2 2 127 238
3 3 127 238 407
4 3 127 238 407 472
5 3 127 238 407 472 631
6 5 127 238 407 472 631 642
# F7AMUX + F7BMUX / 2
7 10 286 413 524 693 758 917 928
# F8MUX
# F8MUX+F7MUX
8 20 273 559 686 797 966 1031 1190 1201

View File

@ -19,10 +19,10 @@ module RAMB18E1 (
input [1:0] WEA, input [1:0] WEA,
input [3:0] WEBWE, input [3:0] WEBWE,
(* abc_flop_q *) output [15:0] DOADO, output [15:0] DOADO,
(* abc_flop_q *) output [15:0] DOBDO, output [15:0] DOBDO,
(* abc_flop_q *) output [1:0] DOPADOP, output [1:0] DOPADOP,
(* abc_flop_q *) output [1:0] DOPBDOP output [1:0] DOPBDOP
); );
parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
@ -143,10 +143,10 @@ module RAMB36E1 (
input [3:0] WEA, input [3:0] WEA,
input [7:0] WEBWE, input [7:0] WEBWE,
(* abc_flop_q *) output [31:0] DOADO, output [31:0] DOADO,
(* abc_flop_q *) output [31:0] DOBDO, output [31:0] DOBDO,
(* abc_flop_q *) output [3:0] DOPADOP, output [3:0] DOPADOP,
(* abc_flop_q *) output [3:0] DOPBDOP output [3:0] DOPBDOP
); );
parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;

View File

@ -18,6 +18,18 @@
* *
*/ */
// Convert negative-polarity reset to positive-polarity
(* techmap_celltype = "$_DFF_NN0_" *)
module _90_dff_nn0_to_np0(input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$_DFF_PN0_" *)
module _90_dff_pn0_to_pp0(input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$_DFF_NN1_" *)
module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$_DFF_PN1_" *)
module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$__SHREG_ (input C, input D, input E, output Q); module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0; parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0; parameter [DEPTH-1:0] INIT = 0;
@ -142,123 +154,3 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
end end
endgenerate endgenerate
endmodule endmodule
module \$__XILINX_SHIFTX (A, B, Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B;
output [Y_WIDTH-1:0] Y;
parameter [A_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0;
parameter [A_WIDTH-1:0] _TECHMAP_CONSTVAL_A_ = 0;
parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0;
parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
function integer compute_num_leading_X_in_A;
integer i, c;
begin
compute_num_leading_X_in_A = 0;
c = 1;
for (i = A_WIDTH-1; i >= 0; i=i-1) begin
if (!_TECHMAP_CONSTMSK_A_[i] || _TECHMAP_CONSTVAL_A_[i] !== 1'bx)
c = 0;
compute_num_leading_X_in_A = compute_num_leading_X_in_A + c;
end
end
endfunction
localparam num_leading_X_in_A = compute_num_leading_X_in_A();
generate
genvar i, j;
// Bit-blast
if (Y_WIDTH > 1) begin
for (i = 0; i < Y_WIDTH; i++)
\$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH-Y_WIDTH+1), .B_WIDTH(B_WIDTH), .Y_WIDTH(1'd1)) bitblast (.A(A[A_WIDTH-Y_WIDTH+i:i]), .B(B), .Y(Y[i]));
end
// If the LSB of B is constant zero (and Y_WIDTH is 1) then
// we can optimise by removing every other entry from A
// and popping the constant zero from B
else if (_TECHMAP_CONSTMSK_B_[0] && !_TECHMAP_CONSTVAL_B_[0]) begin
wire [(A_WIDTH+1)/2-1:0] A_i;
for (i = 0; i < (A_WIDTH+1)/2; i++)
assign A_i[i] = A[i*2];
\$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH((A_WIDTH+1'd1)/2'd2), .B_WIDTH(B_WIDTH-1'd1), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A_i), .B(B[B_WIDTH-1:1]), .Y(Y));
end
// Trim off any leading 1'bx -es in A, and resize B accordingly
else if (num_leading_X_in_A > 0) begin
localparam A_WIDTH_new = A_WIDTH - num_leading_X_in_A;
localparam B_WIDTH_new = $clog2(A_WIDTH_new);
\$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH_new), .B_WIDTH(B_WIDTH_new), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A[A_WIDTH_new-1:0]), .B(B[B_WIDTH_new-1:0]), .Y(Y));
end
else if (B_WIDTH < 3 || A_WIDTH <= 4) begin
\$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y));
end
else if (B_WIDTH == 3) begin
localparam a_width0 = 2 ** 2;
localparam a_widthN = A_WIDTH - a_width0;
wire T0, T1;
\$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux (.A(A[a_width0-1:0]), .B(B[2-1:0]), .Y(T0));
if (a_widthN > 1)
\$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T1));
else
assign T1 = A[A_WIDTH-1];
MUXF7 fpga_hard_mux (.I0(T0), .I1(T1), .S(B[B_WIDTH-1]), .O(Y));
end
else if (B_WIDTH == 4) begin
localparam a_width0 = 2 ** 2;
localparam num_mux8 = A_WIDTH / a_width0;
localparam a_widthN = A_WIDTH - num_mux8*a_width0;
wire [4-1:0] T;
wire T0, T1;
for (i = 0; i < 4; i++)
if (i < num_mux8)
\$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux (.A(A[i*a_width0+:a_width0]), .B(B[2-1:0]), .Y(T[i]));
else if (i == num_mux8 && a_widthN > 0) begin
if (a_widthN > 1)
\$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:i*a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[i]));
else
assign T[i] = A[A_WIDTH-1];
end
else
assign T[i] = 1'bx;
MUXF7 fpga_hard_mux_0 (.I0(T[0]), .I1(T[1]), .S(B[2]), .O(T0));
MUXF7 fpga_hard_mux_1 (.I0(T[2]), .I1(T[3]), .S(B[2]), .O(T1));
MUXF8 fpga_hard_mux_2 (.I0(T0), .I1(T1), .S(B[3]), .O(Y));
end
else begin
localparam a_width0 = 2 ** 4;
localparam num_mux16 = A_WIDTH / a_width0;
localparam a_widthN = A_WIDTH - num_mux16*a_width0;
wire [(2**(B_WIDTH-4))-1:0] T;
for (i = 0; i < 2 ** (B_WIDTH-4); i++)
if (i < num_mux16)
\$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(4), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux (.A(A[i*a_width0+:a_width0]), .B(B[4-1:0]), .Y(T[i]));
else if (i == num_mux16 && a_widthN > 0) begin
if (a_widthN > 1)
\$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:i*a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[i]));
else
assign T[i] = A[A_WIDTH-1];
end
else
assign T[i] = 1'bx;
\$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(2**(B_WIDTH-4)), .B_WIDTH(B_WIDTH-4), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(T), .B(B[B_WIDTH-1:4]), .Y(Y));
end
endgenerate
endmodule
module \$_MUX8_ (A, B, C, D, E, F, G, H, S, T, U, Y);
input A, B, C, D, E, F, G, H, S, T, U;
output Y;
\$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(3), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({H,G,F,E,D,C,B,A}), .B({U,T,S}), .Y(Y));
endmodule
module \$_MUX16_ (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V, Y);
input A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V;
output Y;
\$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(16), .B_WIDTH(4), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A}), .B({V,U,T,S}), .Y(Y));
endmodule

View File

@ -205,7 +205,7 @@ endmodule
`endif `endif
module FDRE ((* abc_flop_q *) output reg Q, input C, CE, D, R); module FDRE (output reg Q, input C, CE, D, R);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0;
@ -217,7 +217,7 @@ module FDRE ((* abc_flop_q *) output reg Q, input C, CE, D, R);
endcase endgenerate endcase endgenerate
endmodule endmodule
module FDSE ((* abc_flop_q *) output reg Q, input C, CE, D, S); module FDSE (output reg Q, input C, CE, D, S);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0;
@ -229,7 +229,7 @@ module FDSE ((* abc_flop_q *) output reg Q, input C, CE, D, S);
endcase endgenerate endcase endgenerate
endmodule endmodule
module FDCE ((* abc_flop_q *) output reg Q, input C, CE, D, CLR); module FDCE (output reg Q, input C, CE, D, CLR);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0;
@ -243,7 +243,7 @@ module FDCE ((* abc_flop_q *) output reg Q, input C, CE, D, CLR);
endcase endgenerate endcase endgenerate
endmodule endmodule
module FDPE ((* abc_flop_q *) output reg Q, input C, CE, D, PRE); module FDPE (output reg Q, input C, CE, D, PRE);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0;
@ -257,25 +257,25 @@ module FDPE ((* abc_flop_q *) output reg Q, input C, CE, D, PRE);
endcase endgenerate endcase endgenerate
endmodule endmodule
module FDRE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, R); module FDRE_1 (output reg Q, input C, CE, D, R);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
initial Q <= INIT; initial Q <= INIT;
always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D; always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
endmodule endmodule
module FDSE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, S); module FDSE_1 (output reg Q, input C, CE, D, S);
parameter [0:0] INIT = 1'b1; parameter [0:0] INIT = 1'b1;
initial Q <= INIT; initial Q <= INIT;
always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D; always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
endmodule endmodule
module FDCE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, CLR); module FDCE_1 (output reg Q, input C, CE, D, CLR);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
initial Q <= INIT; initial Q <= INIT;
always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
endmodule endmodule
module FDPE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, PRE); module FDPE_1 (output reg Q, input C, CE, D, PRE);
parameter [0:0] INIT = 1'b1; parameter [0:0] INIT = 1'b1;
initial Q <= INIT; initial Q <= INIT;
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
@ -315,7 +315,7 @@ module RAM128X1D (
endmodule endmodule
module SRL16E ( module SRL16E (
(* abc_flop_q *) output Q, output Q,
input A0, A1, A2, A3, CE, CLK, D input A0, A1, A2, A3, CE, CLK, D
); );
parameter [15:0] INIT = 16'h0000; parameter [15:0] INIT = 16'h0000;
@ -333,7 +333,7 @@ module SRL16E (
endmodule endmodule
module SRLC32E ( module SRLC32E (
(* abc_flop_q *) output Q, output Q,
output Q31, output Q31,
input [4:0] A, input [4:0] A,
input CE, CLK, D input CE, CLK, D

View File

@ -1,52 +0,0 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 2019 Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
module \$shiftx (A, B, Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B;
output [Y_WIDTH-1:0] Y;
parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0;
parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
generate
genvar i, j;
// TODO: Check if this opt still necessary
if (B_SIGNED) begin
if (_TECHMAP_CONSTMSK_B_[B_WIDTH-1] && _TECHMAP_CONSTVAL_B_[B_WIDTH-1] == 1'b0)
// Optimisation to remove B_SIGNED if sign bit of B is constant-0
\$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(0), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH-1'd1), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B[B_WIDTH-2:0]), .Y(Y));
else
wire _TECHMAP_FAIL_ = 1;
end
else if (B_WIDTH < 3 || A_WIDTH <= 4) begin
wire _TECHMAP_FAIL_ = 1;
end
else begin
\$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y));
end
endgenerate
endmodule

View File

@ -25,6 +25,8 @@
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
#define XC7_WIRE_DELAY "160"
struct SynthXilinxPass : public ScriptPass struct SynthXilinxPass : public ScriptPass
{ {
SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { } SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
@ -70,9 +72,6 @@ struct SynthXilinxPass : public ScriptPass
log(" -nosrl\n"); log(" -nosrl\n");
log(" disable inference of shift registers\n"); log(" disable inference of shift registers\n");
log("\n"); log("\n");
log(" -nomux\n");
log(" disable inference of wide multiplexers\n");
log("\n");
log(" -run <from_label>:<to_label>\n"); log(" -run <from_label>:<to_label>\n");
log(" only run the commands between the labels (see below). an empty\n"); log(" only run the commands between the labels (see below). an empty\n");
log(" from label is synonymous to 'begin', and empty to label is\n"); log(" from label is synonymous to 'begin', and empty to label is\n");
@ -85,7 +84,7 @@ struct SynthXilinxPass : public ScriptPass
log(" run 'abc' with -dff option\n"); log(" run 'abc' with -dff option\n");
log("\n"); log("\n");
log(" -abc9\n"); log(" -abc9\n");
log(" use abc9 instead of abc\n"); log(" use new ABC9 flow (EXPERIMENTAL)\n");
log("\n"); log("\n");
log("\n"); log("\n");
log("The following commands are executed by this synthesis command:\n"); log("The following commands are executed by this synthesis command:\n");
@ -94,7 +93,7 @@ struct SynthXilinxPass : public ScriptPass
} }
std::string top_opt, edif_file, blif_file, abc, arch; std::string top_opt, edif_file, blif_file, abc, arch;
bool flatten, retime, vpr, nocarry, nobram, nodram, nosrl, nomux; bool flatten, retime, vpr, nocarry, nobram, nodram, nosrl;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
@ -109,7 +108,6 @@ struct SynthXilinxPass : public ScriptPass
nobram = false; nobram = false;
nodram = false; nodram = false;
nosrl = false; nosrl = false;
nomux = false;
arch = "xc7"; arch = "xc7";
} }
@ -173,10 +171,6 @@ struct SynthXilinxPass : public ScriptPass
nosrl = true; nosrl = true;
continue; continue;
} }
if (args[argidx] == "-nomux") {
nomux = true;
continue;
}
if (args[argidx] == "-abc9") { if (args[argidx] == "-abc9") {
abc = "abc9"; abc = "abc9";
continue; continue;
@ -225,15 +219,11 @@ struct SynthXilinxPass : public ScriptPass
if (check_label("coarse")) { if (check_label("coarse")) {
run("synth -run coarse"); run("synth -run coarse");
//if (!nomux || help_mode)
// run("muxpack", "(skip if '-nomux')");
// shregmap -tech xilinx can cope with $shiftx and $mux // shregmap -tech xilinx can cope with $shiftx and $mux
// cells for identifying variable-length shift registers, // cells for identifying variable-length shift registers,
// so attempt to convert $pmux-es to the former // so attempt to convert $pmux-es to the former
// Also: wide multiplexer inference benefits from this too if (!nosrl || help_mode)
if (!(nosrl && nomux) || help_mode) run("pmux2shiftx", "(skip if '-nosrl')");
run("pmux2shiftx", "(skip if '-nosrl' and '-nomux')");
// Run a number of peephole optimisations, including one // Run a number of peephole optimisations, including one
// that optimises $mul cells driving $shiftx's B input // that optimises $mul cells driving $shiftx's B input
@ -271,10 +261,6 @@ struct SynthXilinxPass : public ScriptPass
} }
std::string techmap_files = " -map +/techmap.v"; std::string techmap_files = " -map +/techmap.v";
if (help_mode)
techmap_files += " [-map +/xilinx/mux_map.v]";
else if (!nomux)
techmap_files += " -map +/xilinx/mux_map.v";
if (help_mode) if (help_mode)
techmap_files += " [-map +/xilinx/arith_map.v]"; techmap_files += " [-map +/xilinx/arith_map.v]";
else if (!nocarry) { else if (!nocarry) {
@ -289,15 +275,13 @@ struct SynthXilinxPass : public ScriptPass
} }
if (check_label("map_cells")) { if (check_label("map_cells")) {
if (!nomux || help_mode)
run("muxcover -mux8 -mux16", "(skip if '-nomux')");
run("techmap -map +/techmap.v -map +/xilinx/cells_map.v"); run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
run("clean"); run("clean");
} }
if (check_label("map_luts")) { if (check_label("map_luts")) {
if (abc == "abc9") if (abc == "abc9")
run(abc + " -lut +/xilinx/abc.lut -box +/xilinx/abc.box -W 160" + string(retime ? " -dff" : "")); run(abc + " -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + XC7_WIRE_DELAY + string(retime ? " -dff" : ""));
else if (help_mode) else if (help_mode)
run(abc + " -luts 2:2,3,6:5,10,20 [-dff]"); run(abc + " -luts 2:2,3,6:5,10,20 [-dff]");
else else
@ -308,7 +292,7 @@ struct SynthXilinxPass : public ScriptPass
// has performed any necessary retiming // has performed any necessary retiming
if (!nosrl || help_mode) if (!nosrl || help_mode)
run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')"); run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
run("techmap -map +/xilinx/lut_map.v -map +/xilinx/cells_map.v -map +/xilinx/ff_map.v"); run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
run("clean"); run("clean");

View File

@ -250,3 +250,15 @@ module abc9_test023 #(
wire [2*M-1:0] mask = {M{1'b1}}; wire [2*M-1:0] mask = {M{1'b1}};
assign dout = (mask << din[N-1:0]) >> M; assign dout = (mask << din[N-1:0]) >> M;
endmodule endmodule
module abc9_test024(input [3:0] i, output [3:0] o);
abc9_test024_sub a(i[1:0], o[1:0]);
endmodule
module abc9_test024_sub(input [1:0] i, output [1:0] o);
assign o = i;
endmodule
module abc9_test025(input [3:0] i, output [3:0] o);
abc9_test024_sub a(i[2:1], o[2:1]);
endmodule

View File

@ -1,138 +0,0 @@
module mux_if_unbal_4_1 #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
always @*
if (s == 0) o <= i[0*W+:W];
else if (s == 1) o <= i[1*W+:W];
else if (s == 2) o <= i[2*W+:W];
else if (s == 3) o <= i[3*W+:W];
else o <= {W{1'bx}};
endmodule
module mux_if_unbal_5_3 #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
always @* begin
o <= {W{1'bx}};
if (s == 0) o <= i[0*W+:W];
if (s == 1) o <= i[1*W+:W];
if (s == 2) o <= i[2*W+:W];
if (s == 3) o <= i[3*W+:W];
if (s == 4) o <= i[4*W+:W];
end
endmodule
module mux_if_unbal_5_3_invert #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
always @*
if (s != 0)
if (s != 1)
if (s != 2)
if (s != 3)
if (s != 4) o <= i[4*W+:W];
else o <= i[0*W+:W];
else o <= i[3*W+:W];
else o <= i[2*W+:W];
else o <= i[1*W+:W];
else o <= {W{1'bx}};
endmodule
module mux_if_unbal_5_3_width_mismatch #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
always @* begin
o <= {W{1'bx}};
if (s == 0) o <= i[0*W+:W];
if (s == 1) o <= i[1*W+:W];
if (s == 2) o[W-2:0] <= i[2*W+:W-1];
if (s == 3) o <= i[3*W+:W];
if (s == 4) o <= i[4*W+:W];
end
endmodule
module mux_if_unbal_4_1_missing #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
always @* begin
if (s == 0) o <= i[0*W+:W];
// else if (s == 1) o <= i[1*W+:W];
// else if (s == 2) o <= i[2*W+:W];
else if (s == 3) o <= i[3*W+:W];
else o <= {W{1'bx}};
end
endmodule
module mux_if_unbal_5_3_order #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
always @* begin
o <= {W{1'bx}};
if (s == 3) o <= i[3*W+:W];
if (s == 2) o <= i[2*W+:W];
if (s == 1) o <= i[1*W+:W];
if (s == 4) o <= i[4*W+:W];
if (s == 0) o <= i[0*W+:W];
end
endmodule
module mux_if_unbal_4_1_nonexcl #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
always @*
if (s == 0) o <= i[0*W+:W];
else if (s == 1) o <= i[1*W+:W];
else if (s == 2) o <= i[2*W+:W];
else if (s == 3) o <= i[3*W+:W];
else if (s == 0) o <= {W{1'b0}};
else o <= {W{1'bx}};
endmodule
module mux_if_unbal_5_3_nonexcl #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
always @* begin
o <= {W{1'bx}};
if (s == 0) o <= i[0*W+:W];
if (s == 1) o <= i[1*W+:W];
if (s == 2) o <= i[2*W+:W];
if (s == 3) o <= i[3*W+:W];
if (s == 4) o <= i[4*W+:W];
if (s == 0) o <= i[2*W+:W];
end
endmodule
module mux_case_unbal_8_7#(parameter N=8, parameter W=7) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
always @* begin
o <= {W{1'bx}};
case (s)
0: o <= i[0*W+:W];
default:
case (s)
1: o <= i[1*W+:W];
2: o <= i[2*W+:W];
default:
case (s)
3: o <= i[3*W+:W];
4: o <= i[4*W+:W];
5: o <= i[5*W+:W];
default:
case (s)
6: o <= i[6*W+:W];
default: o <= i[7*W+:W];
endcase
endcase
endcase
endcase
end
endmodule
module mux_if_bal_8_2 #(parameter N=8, parameter W=2) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
always @*
if (s[0] == 1'b0)
if (s[1] == 1'b0)
if (s[2] == 1'b0)
o <= i[0*W+:W];
else
o <= i[1*W+:W];
else
if (s[2] == 1'b0)
o <= i[2*W+:W];
else
o <= i[3*W+:W];
else
if (s[1] == 1'b0)
if (s[2] == 1'b0)
o <= i[4*W+:W];
else
o <= i[5*W+:W];
else
if (s[2] == 1'b0)
o <= i[6*W+:W];
else
o <= i[7*W+:W];
endmodule

View File

@ -1,150 +0,0 @@
read_verilog muxpack.v
design -save read
hierarchy -top mux_if_unbal_4_1
prep
design -save gold
muxpack
opt
stat
select -assert-count 0 t:$mux
select -assert-count 1 t:$pmux
design -stash gate
design -import gold -as gold
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 mux_if_unbal_5_3
prep
design -save gold
muxpack
opt
stat
select -assert-count 0 t:$mux
select -assert-count 1 t:$pmux
design -stash gate
design -import gold -as gold
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 mux_if_unbal_5_3_invert
prep
design -save gold
muxpack
opt
stat
select -assert-count 0 t:$mux
select -assert-count 1 t:$pmux
design -stash gate
design -import gold -as gold
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 mux_if_unbal_5_3_width_mismatch
prep
design -save gold
muxpack
opt
stat
select -assert-count 0 t:$mux
select -assert-count 2 t:$pmux
design -stash gate
design -import gold -as gold
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 mux_if_unbal_4_1_missing
prep
design -save gold
muxpack
opt
stat
select -assert-count 0 t:$mux
select -assert-count 1 t:$pmux
design -stash gate
design -import gold -as gold
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 mux_if_unbal_5_3_order
prep
design -save gold
muxpack
opt
stat
select -assert-count 0 t:$mux
select -assert-count 1 t:$pmux
design -stash gate
design -import gold -as gold
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 mux_if_unbal_4_1_nonexcl
prep
design -save gold
muxpack
opt
stat
select -assert-count 0 t:$mux
select -assert-count 1 t:$pmux
design -stash gate
design -import gold -as gold
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 mux_if_unbal_5_3_nonexcl
prep
design -save gold
muxpack
opt
stat
select -assert-count 0 t:$mux
select -assert-count 1 t:$pmux
design -stash gate
design -import gold -as gold
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 mux_case_unbal_8_7
prep
design -save gold
muxpack
opt
stat
select -assert-count 0 t:$mux
select -assert-count 1 t:$pmux
design -stash gate
design -import gold -as gold
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 mux_if_bal_8_2
prep
design -save gold
muxpack
opt
stat
select -assert-count 7 t:$mux
select -assert-count 0 t:$pmux
design -stash gate
design -import gold -as gold
design -import gate -as gate
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -verify -prove-asserts -show-ports miter

View File

@ -1,22 +0,0 @@
module shregmap_test(input i, clk, output [1:0] q);
reg head = 1'b0;
reg [3:0] shift1 = 4'b0000;
reg [3:0] shift2 = 4'b0000;
always @(posedge clk) begin
head <= i;
shift1 <= {shift1[2:0], head};
shift2 <= {shift2[2:0], head};
end
assign q = {shift2[3], shift1[3]};
endmodule
module $__SHREG_DFF_P_(input C, D, output Q);
parameter DEPTH = 1;
parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}};
reg [DEPTH-1:0] r = INIT;
always @(posedge C)
r <= { r[DEPTH-2:0], D };
assign Q = r[DEPTH-1];
endmodule

View File

@ -1,31 +0,0 @@
read_verilog shregmap.v
design -copy-to model $__SHREG_DFF_P_
hierarchy -top shregmap_test
prep
design -save gold
techmap
shregmap -init
opt
stat
# show -width
select -assert-count 1 t:$_DFF_P_
select -assert-count 2 t:$__SHREG_DFF_P_
design -stash gate
design -import gold -as gold
design -import gate -as gate
design -copy-from model -as $__SHREG_DFF_P_ \$__SHREG_DFF_P_
prep
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -verify -prove-asserts -show-ports -seq 5 miter
design -load gold
stat
design -load gate
stat