mirror of https://github.com/YosysHQ/yosys.git
Merge remote-tracking branch 'origin/master' into ice40dsp
This commit is contained in:
commit
42e40dbd0a
|
@ -78,7 +78,7 @@ Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies
|
|||
On FreeBSD use the following command to install all prerequisites:
|
||||
|
||||
# pkg install bison flex readline gawk libffi\
|
||||
git graphviz pkgconfig python3 python36 tcl-wrapper boost-libs
|
||||
git graphviz pkgconf python3 python36 tcl-wrapper boost-libs
|
||||
|
||||
On FreeBSD system use gmake instead of make. To run tests use:
|
||||
% MAKE=gmake CC=cc gmake test
|
||||
|
|
|
@ -43,7 +43,11 @@ if os.name == "posix":
|
|||
if current_rlimit_stack[1] != resource.RLIM_INFINITY:
|
||||
smtio_stacksize = min(smtio_stacksize, current_rlimit_stack[1])
|
||||
if current_rlimit_stack[0] < smtio_stacksize:
|
||||
resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, current_rlimit_stack[1]))
|
||||
try:
|
||||
resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, current_rlimit_stack[1]))
|
||||
except ValueError:
|
||||
# couldn't get more stack, just run with what we have
|
||||
pass
|
||||
|
||||
|
||||
# currently running solvers (so we can kill them)
|
||||
|
|
|
@ -189,7 +189,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
|
|||
if (width < 0)
|
||||
width = data.bits.size() - offset;
|
||||
if (width == 0) {
|
||||
f << "\"\"";
|
||||
// See IEEE 1364-2005 Clause 5.1.14.
|
||||
f << "{0{1'b0}}";
|
||||
return;
|
||||
}
|
||||
if (nostr)
|
||||
|
@ -788,7 +789,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == "$pmux" || cell->type == "$pmux_safe")
|
||||
if (cell->type == "$pmux")
|
||||
{
|
||||
int width = cell->parameters["\\WIDTH"].as_int();
|
||||
int s_width = cell->getPort("\\S").size();
|
||||
|
@ -800,18 +801,17 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
|
||||
|
||||
dump_attributes(f, indent + " ", cell->attributes);
|
||||
if (cell->type != "$pmux_safe" && !noattr)
|
||||
if (!noattr)
|
||||
f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
|
||||
f << stringf("%s" " casez (s)", indent.c_str());
|
||||
if (cell->type != "$pmux_safe")
|
||||
f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
|
||||
f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
|
||||
|
||||
for (int i = 0; i < s_width; i++)
|
||||
{
|
||||
f << stringf("%s" " %d'b", indent.c_str(), s_width);
|
||||
|
||||
for (int j = s_width-1; j >= 0; j--)
|
||||
f << stringf("%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?');
|
||||
f << stringf("%c", j == i ? '1' : '?');
|
||||
|
||||
f << stringf(":\n");
|
||||
f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width);
|
||||
|
|
|
@ -551,7 +551,7 @@ struct LibertyFrontend : public Frontend {
|
|||
if (design->has(cell_name)) {
|
||||
Module *existing_mod = design->module(cell_name);
|
||||
if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
|
||||
log_error("Re-definition of of cell/module %s!\n", log_id(cell_name));
|
||||
log_error("Re-definition of cell/module %s!\n", log_id(cell_name));
|
||||
} else if (flag_nooverwrite) {
|
||||
log("Ignoring re-definition of module %s.\n", log_id(cell_name));
|
||||
continue;
|
||||
|
|
|
@ -61,7 +61,7 @@ int log_force_debug = 0;
|
|||
int log_debug_suppressed = 0;
|
||||
|
||||
vector<int> header_count;
|
||||
pool<RTLIL::IdString> log_id_cache;
|
||||
vector<char*> log_id_cache;
|
||||
vector<shared_str> string_buf;
|
||||
int string_buf_index = -1;
|
||||
|
||||
|
@ -69,6 +69,13 @@ static struct timeval initial_tv = { 0, 0 };
|
|||
static bool next_print_log = false;
|
||||
static int log_newline_count = 0;
|
||||
|
||||
static void log_id_cache_clear()
|
||||
{
|
||||
for (auto p : log_id_cache)
|
||||
free(p);
|
||||
log_id_cache.clear();
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
// this will get time information and return it in timeval, simulating gettimeofday()
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
|
@ -414,7 +421,7 @@ void log_push()
|
|||
void log_pop()
|
||||
{
|
||||
header_count.pop_back();
|
||||
log_id_cache.clear();
|
||||
log_id_cache_clear();
|
||||
string_buf.clear();
|
||||
string_buf_index = -1;
|
||||
log_flush();
|
||||
|
@ -521,7 +528,7 @@ void log_reset_stack()
|
|||
{
|
||||
while (header_count.size() > 1)
|
||||
header_count.pop_back();
|
||||
log_id_cache.clear();
|
||||
log_id_cache_clear();
|
||||
string_buf.clear();
|
||||
string_buf_index = -1;
|
||||
log_flush();
|
||||
|
@ -580,8 +587,8 @@ const char *log_const(const RTLIL::Const &value, bool autoint)
|
|||
|
||||
const char *log_id(RTLIL::IdString str)
|
||||
{
|
||||
log_id_cache.insert(str);
|
||||
const char *p = str.c_str();
|
||||
log_id_cache.push_back(strdup(str.c_str()));
|
||||
const char *p = log_id_cache.back();
|
||||
if (p[0] != '\\')
|
||||
return p;
|
||||
if (p[1] == '$' || p[1] == '\\' || p[1] == 0)
|
||||
|
|
|
@ -68,6 +68,10 @@ struct rules_t
|
|||
if (groups != GetSize(transp)) log_error("Bram %s variant %d has %d groups but only %d entries in 'transp'.\n", log_id(name), variant, groups, GetSize(transp));
|
||||
if (groups != GetSize(clocks)) log_error("Bram %s variant %d has %d groups but only %d entries in 'clocks'.\n", log_id(name), variant, groups, GetSize(clocks));
|
||||
if (groups != GetSize(clkpol)) log_error("Bram %s variant %d has %d groups but only %d entries in 'clkpol'.\n", log_id(name), variant, groups, GetSize(clkpol));
|
||||
|
||||
int group = 0;
|
||||
for (auto e : enable)
|
||||
if (e > dbits) log_error("Bram %s variant %d group %d has %d enable bits but only %d dbits.\n", log_id(name), variant, group, e, dbits);
|
||||
}
|
||||
|
||||
vector<portinfo_t> make_portinfos() const
|
||||
|
|
|
@ -105,7 +105,7 @@ struct OptLutWorker
|
|||
SigSpec lut_input = cell->getPort("\\A");
|
||||
int lut_arity = 0;
|
||||
|
||||
log("Found $lut\\WIDTH=%d cell %s.%s.\n", lut_width, log_id(module), log_id(cell));
|
||||
log_debug("Found $lut\\WIDTH=%d cell %s.%s.\n", lut_width, log_id(module), log_id(cell));
|
||||
luts.insert(cell);
|
||||
|
||||
// First, find all dedicated logic we're connected to. This results in an overapproximation
|
||||
|
@ -147,15 +147,15 @@ struct OptLutWorker
|
|||
{
|
||||
if (lut_width <= dlogic_conn.first)
|
||||
{
|
||||
log(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
|
||||
log(" LUT input A[%d] not present.\n", dlogic_conn.first);
|
||||
log_debug(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
|
||||
log_debug(" LUT input A[%d] not present.\n", dlogic_conn.first);
|
||||
legal = false;
|
||||
break;
|
||||
}
|
||||
if (sigmap(lut_input[dlogic_conn.first]) != sigmap(lut_dlogic->getPort(dlogic_conn.second)))
|
||||
{
|
||||
log(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
|
||||
log(" LUT input A[%d] (wire %s) not connected to %s port %s (wire %s).\n", dlogic_conn.first, log_signal(lut_input[dlogic_conn.first]), lut_dlogic->type.c_str(), dlogic_conn.second.c_str(), log_signal(lut_dlogic->getPort(dlogic_conn.second)));
|
||||
log_debug(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
|
||||
log_debug(" LUT input A[%d] (wire %s) not connected to %s port %s (wire %s).\n", dlogic_conn.first, log_signal(lut_input[dlogic_conn.first]), lut_dlogic->type.c_str(), dlogic_conn.second.c_str(), log_signal(lut_dlogic->getPort(dlogic_conn.second)));
|
||||
legal = false;
|
||||
break;
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ struct OptLutWorker
|
|||
|
||||
if (legal)
|
||||
{
|
||||
log(" LUT has legal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
|
||||
log_debug(" LUT has legal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
|
||||
lut_legal_dlogics.insert(lut_dlogic);
|
||||
for (auto &dlogic_conn : dlogic_map)
|
||||
lut_dlogic_inputs.insert(dlogic_conn.first);
|
||||
|
@ -179,7 +179,7 @@ struct OptLutWorker
|
|||
lut_arity++;
|
||||
}
|
||||
|
||||
log(" Cell implements a %d-LUT.\n", lut_arity);
|
||||
log_debug(" Cell implements a %d-LUT.\n", lut_arity);
|
||||
luts_arity[cell] = lut_arity;
|
||||
luts_dlogics[cell] = lut_legal_dlogics;
|
||||
luts_dlogic_inputs[cell] = lut_dlogic_inputs;
|
||||
|
@ -239,28 +239,26 @@ struct OptLutWorker
|
|||
|
||||
if (const0_match || const1_match || input_match != -1)
|
||||
{
|
||||
log("Found redundant cell %s.%s.\n", log_id(module), log_id(lut));
|
||||
log_debug("Found redundant cell %s.%s.\n", log_id(module), log_id(lut));
|
||||
|
||||
SigBit value;
|
||||
if (const0_match)
|
||||
{
|
||||
log(" Cell evaluates constant 0.\n");
|
||||
log_debug(" Cell evaluates constant 0.\n");
|
||||
value = State::S0;
|
||||
}
|
||||
if (const1_match)
|
||||
{
|
||||
log(" Cell evaluates constant 1.\n");
|
||||
log_debug(" Cell evaluates constant 1.\n");
|
||||
value = State::S1;
|
||||
}
|
||||
if (input_match != -1) {
|
||||
log(" Cell evaluates signal %s.\n", log_signal(lut_inputs[input_match]));
|
||||
log_debug(" Cell evaluates signal %s.\n", log_signal(lut_inputs[input_match]));
|
||||
value = lut_inputs[input_match];
|
||||
}
|
||||
|
||||
if (lut_dlogic_inputs.size())
|
||||
{
|
||||
log(" Not eliminating cell (connected to dedicated logic).\n");
|
||||
}
|
||||
log_debug(" Not eliminating cell (connected to dedicated logic).\n");
|
||||
else
|
||||
{
|
||||
SigSpec lut_output = lut->getPort("\\Y");
|
||||
|
@ -323,11 +321,11 @@ struct OptLutWorker
|
|||
int lutB_arity = luts_arity[lutB];
|
||||
pool<int> &lutB_dlogic_inputs = luts_dlogic_inputs[lutB];
|
||||
|
||||
log("Found %s.%s (cell A) feeding %s.%s (cell B).\n", log_id(module), log_id(lutA), log_id(module), log_id(lutB));
|
||||
log_debug("Found %s.%s (cell A) feeding %s.%s (cell B).\n", log_id(module), log_id(lutA), log_id(module), log_id(lutB));
|
||||
|
||||
if (index.query_is_output(lutA->getPort("\\Y")))
|
||||
{
|
||||
log(" Not combining LUTs (cascade connection feeds module output).\n");
|
||||
log_debug(" Not combining LUTs (cascade connection feeds module output).\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -353,67 +351,51 @@ struct OptLutWorker
|
|||
|
||||
int lutM_arity = lutA_arity + lutB_arity - 1 - common_inputs.size();
|
||||
if (lutA_dlogic_inputs.size())
|
||||
log(" Cell A is a %d-LUT with %zu dedicated connections. ", lutA_arity, lutA_dlogic_inputs.size());
|
||||
log_debug(" Cell A is a %d-LUT with %zu dedicated connections. ", lutA_arity, lutA_dlogic_inputs.size());
|
||||
else
|
||||
log(" Cell A is a %d-LUT. ", lutA_arity);
|
||||
log_debug(" Cell A is a %d-LUT. ", lutA_arity);
|
||||
if (lutB_dlogic_inputs.size())
|
||||
log("Cell B is a %d-LUT with %zu dedicated connections.\n", lutB_arity, lutB_dlogic_inputs.size());
|
||||
log_debug("Cell B is a %d-LUT with %zu dedicated connections.\n", lutB_arity, lutB_dlogic_inputs.size());
|
||||
else
|
||||
log("Cell B is a %d-LUT.\n", lutB_arity);
|
||||
log(" Cells share %zu input(s) and can be merged into one %d-LUT.\n", common_inputs.size(), lutM_arity);
|
||||
log_debug("Cell B is a %d-LUT.\n", lutB_arity);
|
||||
log_debug(" Cells share %zu input(s) and can be merged into one %d-LUT.\n", common_inputs.size(), lutM_arity);
|
||||
|
||||
const int COMBINE_A = 1, COMBINE_B = 2, COMBINE_EITHER = COMBINE_A | COMBINE_B;
|
||||
int combine_mask = 0;
|
||||
if (lutM_arity > lutA_width)
|
||||
{
|
||||
log(" Not combining LUTs into cell A (combined LUT wider than cell A).\n");
|
||||
}
|
||||
log_debug(" Not combining LUTs into cell A (combined LUT wider than cell A).\n");
|
||||
else if (lutB_dlogic_inputs.size() > 0)
|
||||
{
|
||||
log(" Not combining LUTs into cell A (cell B is connected to dedicated logic).\n");
|
||||
}
|
||||
log_debug(" Not combining LUTs into cell A (cell B is connected to dedicated logic).\n");
|
||||
else if (lutB->get_bool_attribute("\\lut_keep"))
|
||||
{
|
||||
log(" Not combining LUTs into cell A (cell B has attribute \\lut_keep).\n");
|
||||
}
|
||||
log_debug(" Not combining LUTs into cell A (cell B has attribute \\lut_keep).\n");
|
||||
else
|
||||
{
|
||||
combine_mask |= COMBINE_A;
|
||||
}
|
||||
if (lutM_arity > lutB_width)
|
||||
{
|
||||
log(" Not combining LUTs into cell B (combined LUT wider than cell B).\n");
|
||||
}
|
||||
log_debug(" Not combining LUTs into cell B (combined LUT wider than cell B).\n");
|
||||
else if (lutA_dlogic_inputs.size() > 0)
|
||||
{
|
||||
log(" Not combining LUTs into cell B (cell A is connected to dedicated logic).\n");
|
||||
}
|
||||
log_debug(" Not combining LUTs into cell B (cell A is connected to dedicated logic).\n");
|
||||
else if (lutA->get_bool_attribute("\\lut_keep"))
|
||||
{
|
||||
log(" Not combining LUTs into cell B (cell A has attribute \\lut_keep).\n");
|
||||
}
|
||||
log_debug(" Not combining LUTs into cell B (cell A has attribute \\lut_keep).\n");
|
||||
else
|
||||
{
|
||||
combine_mask |= COMBINE_B;
|
||||
}
|
||||
|
||||
int combine = combine_mask;
|
||||
if (combine == COMBINE_EITHER)
|
||||
{
|
||||
log(" Can combine into either cell.\n");
|
||||
log_debug(" Can combine into either cell.\n");
|
||||
if (lutA_arity == 1)
|
||||
{
|
||||
log(" Cell A is a buffer or inverter, combining into cell B.\n");
|
||||
log_debug(" Cell A is a buffer or inverter, combining into cell B.\n");
|
||||
combine = COMBINE_B;
|
||||
}
|
||||
else if (lutB_arity == 1)
|
||||
{
|
||||
log(" Cell B is a buffer or inverter, combining into cell A.\n");
|
||||
log_debug(" Cell B is a buffer or inverter, combining into cell A.\n");
|
||||
combine = COMBINE_A;
|
||||
}
|
||||
else
|
||||
{
|
||||
log(" Arbitrarily combining into cell A.\n");
|
||||
log_debug(" Arbitrarily combining into cell A.\n");
|
||||
combine = COMBINE_A;
|
||||
}
|
||||
}
|
||||
|
@ -423,7 +405,7 @@ struct OptLutWorker
|
|||
pool<int> lutM_dlogic_inputs;
|
||||
if (combine == COMBINE_A)
|
||||
{
|
||||
log(" Combining LUTs into cell A.\n");
|
||||
log_debug(" Combining LUTs into cell A.\n");
|
||||
lutM = lutA;
|
||||
lutM_inputs = lutA_inputs;
|
||||
lutM_dlogic_inputs = lutA_dlogic_inputs;
|
||||
|
@ -432,7 +414,7 @@ struct OptLutWorker
|
|||
}
|
||||
else if (combine == COMBINE_B)
|
||||
{
|
||||
log(" Combining LUTs into cell B.\n");
|
||||
log_debug(" Combining LUTs into cell B.\n");
|
||||
lutM = lutB;
|
||||
lutM_inputs = lutB_inputs;
|
||||
lutM_dlogic_inputs = lutB_dlogic_inputs;
|
||||
|
@ -441,7 +423,7 @@ struct OptLutWorker
|
|||
}
|
||||
else
|
||||
{
|
||||
log(" Cannot combine LUTs.\n");
|
||||
log_debug(" Cannot combine LUTs.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -466,17 +448,17 @@ struct OptLutWorker
|
|||
if (input_unused && lutR_unique.size())
|
||||
{
|
||||
SigBit new_input = lutR_unique.pop();
|
||||
log(" Connecting input %d as %s.\n", i, log_signal(new_input));
|
||||
log_debug(" Connecting input %d as %s.\n", i, log_signal(new_input));
|
||||
lutM_new_inputs.push_back(new_input);
|
||||
}
|
||||
else if (sigmap(lutM_input[i]) == lutA_output)
|
||||
{
|
||||
log(" Disconnecting cascade input %d.\n", i);
|
||||
log_debug(" Disconnecting cascade input %d.\n", i);
|
||||
lutM_new_inputs.push_back(SigBit());
|
||||
}
|
||||
else
|
||||
{
|
||||
log(" Leaving input %d as %s.\n", i, log_signal(lutM_input[i]));
|
||||
log_debug(" Leaving input %d as %s.\n", i, log_signal(lutM_input[i]));
|
||||
lutM_new_inputs.push_back(lutM_input[i]);
|
||||
}
|
||||
}
|
||||
|
@ -494,9 +476,9 @@ struct OptLutWorker
|
|||
lutM_new_table[eval] = (RTLIL::State) evaluate_lut(lutB, eval_inputs);
|
||||
}
|
||||
|
||||
log(" Cell A truth table: %s.\n", lutA->getParam("\\LUT").as_string().c_str());
|
||||
log(" Cell B truth table: %s.\n", lutB->getParam("\\LUT").as_string().c_str());
|
||||
log(" Merged truth table: %s.\n", lutM_new_table.as_string().c_str());
|
||||
log_debug(" Cell A truth table: %s.\n", lutA->getParam("\\LUT").as_string().c_str());
|
||||
log_debug(" Cell B truth table: %s.\n", lutB->getParam("\\LUT").as_string().c_str());
|
||||
log_debug(" Merged truth table: %s.\n", lutM_new_table.as_string().c_str());
|
||||
|
||||
lutM->setParam("\\LUT", lutM_new_table);
|
||||
lutM->setPort("\\A", lutM_new_inputs);
|
||||
|
|
|
@ -1172,8 +1172,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
cell_stats[RTLIL::unescape_id(c->type)]++;
|
||||
else
|
||||
cell_stats[RTLIL::unescape_id(c->type)]++;
|
||||
|
||||
if (c->type == "\\_const0_" || c->type == "\\_const1_") {
|
||||
RTLIL::SigSig conn;
|
||||
|
|
|
@ -24,12 +24,13 @@
|
|||
|
||||
#if 0
|
||||
// Based on &flow3 - better QoR but more experimental
|
||||
#define ABC_COMMAND_LUT "&st; &ps -l; "/*"&sweep -v;"*/" &scorr; " \
|
||||
"&st; &if {W}; &save; &st; &syn2; &if {W}; &save; &load; "\
|
||||
"&st; &if -g -K 6; &dch -f; &if {W}; &save; &load; "\
|
||||
"&st; &if -g -K 6; &synch2; &if {W}; &save; &load"
|
||||
#define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \
|
||||
"&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\
|
||||
"&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\
|
||||
"&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\
|
||||
"&mfs; &ps -l"
|
||||
#else
|
||||
#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps -l; &if {W} {D} -v; &mfs; &ps -l"
|
||||
#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l"
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -53,6 +54,7 @@
|
|||
#endif
|
||||
|
||||
#include "frontends/aiger/aigerparse.h"
|
||||
#include "kernel/utils.h"
|
||||
|
||||
#ifdef YOSYS_LINK_ABC
|
||||
extern "C" int Abc_RealMain(int argc, char *argv[]);
|
||||
|
@ -570,13 +572,23 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
|||
boxes.emplace_back(cell);
|
||||
}
|
||||
|
||||
dict<SigBit, pool<IdString>> bit_drivers, bit_users;
|
||||
TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
|
||||
dict<RTLIL::Cell*,RTLIL::Cell*> not2drivers;
|
||||
dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;
|
||||
|
||||
std::map<std::string, int> cell_stats;
|
||||
for (auto c : mapped_mod->cells())
|
||||
{
|
||||
toposort.node(c->name);
|
||||
|
||||
RTLIL::Cell *cell = nullptr;
|
||||
if (c->type == "$_NOT_") {
|
||||
RTLIL::SigBit a_bit = c->getPort("\\A").as_bit();
|
||||
RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit();
|
||||
RTLIL::SigBit a_bit = c->getPort("\\A");
|
||||
RTLIL::SigBit y_bit = c->getPort("\\Y");
|
||||
bit_users[a_bit].insert(c->name);
|
||||
bit_drivers[y_bit].insert(c->name);
|
||||
|
||||
if (!a_bit.wire) {
|
||||
c->setPort("\\Y", module->addWire(NEW_ID));
|
||||
RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
|
||||
|
@ -584,11 +596,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
|||
module->connect(RTLIL::SigBit(wire, y_bit.offset), RTLIL::S1);
|
||||
}
|
||||
else if (!lut_costs.empty() || !lut_file.empty()) {
|
||||
RTLIL::Cell* driving_lut = nullptr;
|
||||
RTLIL::Cell* driver_lut = nullptr;
|
||||
// ABC can return NOT gates that drive POs
|
||||
if (!a_bit.wire->port_input) {
|
||||
// If it's not a NOT gate that that comes from a PI directly,
|
||||
// find the driving LUT and clone that to guarantee that we won't
|
||||
// find the driver LUT and clone that to guarantee that we won't
|
||||
// increase the max logic depth
|
||||
// (TODO: Optimise by not cloning unless will increase depth)
|
||||
RTLIL::IdString driver_name;
|
||||
|
@ -596,50 +608,38 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
|||
driver_name = stringf("%s$lut", a_bit.wire->name.c_str());
|
||||
else
|
||||
driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset);
|
||||
driving_lut = mapped_mod->cell(driver_name);
|
||||
driver_lut = mapped_mod->cell(driver_name);
|
||||
}
|
||||
|
||||
if (!driving_lut) {
|
||||
// If a driver couldn't be found (could be from PI,
|
||||
// or from a box) then implement using a LUT
|
||||
if (!driver_lut) {
|
||||
// If a driver couldn't be found (could be from PI or box CI)
|
||||
// then implement using a LUT
|
||||
cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
|
||||
RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset),
|
||||
RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
|
||||
1);
|
||||
}
|
||||
else {
|
||||
auto driver_a = driving_lut->getPort("\\A").chunks();
|
||||
for (auto &chunk : driver_a)
|
||||
chunk.wire = module->wires_[remap_name(chunk.wire->name)];
|
||||
RTLIL::Const driver_lut = driving_lut->getParam("\\LUT");
|
||||
for (auto &b : driver_lut.bits) {
|
||||
if (b == RTLIL::State::S0) b = RTLIL::State::S1;
|
||||
else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
|
||||
}
|
||||
cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
|
||||
driver_a,
|
||||
RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
|
||||
driver_lut);
|
||||
RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
|
||||
RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
|
||||
RTLIL::Const::from_string("01"));
|
||||
bit2sinks[cell->getPort("\\A")].push_back(cell);
|
||||
cell_stats["$lut"]++;
|
||||
}
|
||||
else
|
||||
not2drivers[c] = driver_lut;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
cell = module->addCell(remap_name(c->name), "$_NOT_");
|
||||
cell->setPort("\\A", RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset));
|
||||
cell->setPort("\\Y", RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset));
|
||||
cell_stats[RTLIL::unescape_id(c->type)]++;
|
||||
}
|
||||
else
|
||||
log_abort();
|
||||
if (cell && markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
|
||||
continue;
|
||||
}
|
||||
cell_stats[RTLIL::unescape_id(c->type)]++;
|
||||
|
||||
RTLIL::Cell *existing_cell = nullptr;
|
||||
RTLIL::Cell *existing_cell = nullptr;
|
||||
if (c->type == "$lut") {
|
||||
if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
|
||||
SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
|
||||
SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)];
|
||||
if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT") == RTLIL::Const::from_string("01")) {
|
||||
SigSpec my_a = module->wires_.at(remap_name(c->getPort("\\A").as_wire()->name));
|
||||
SigSpec my_y = module->wires_.at(remap_name(c->getPort("\\Y").as_wire()->name));
|
||||
module->connect(my_y, my_a);
|
||||
if (markgroups) c->attributes["\\abcgroup"] = map_autoidx;
|
||||
if (markgroups) c->attributes["\\abcgroup"] = map_autoidx;
|
||||
log_abort();
|
||||
continue;
|
||||
}
|
||||
cell = module->addCell(remap_name(c->name), c->type);
|
||||
|
@ -666,10 +666,20 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
|||
continue;
|
||||
//log_assert(c.width == 1);
|
||||
if (c.wire)
|
||||
c.wire = module->wires_[remap_name(c.wire->name)];
|
||||
c.wire = module->wires_.at(remap_name(c.wire->name));
|
||||
newsig.append(c);
|
||||
}
|
||||
cell->setPort(conn.first, newsig);
|
||||
|
||||
if (cell->input(conn.first)) {
|
||||
for (auto i : newsig)
|
||||
bit2sinks[i].push_back(cell);
|
||||
for (auto i : conn.second)
|
||||
bit_users[i].insert(c->name);
|
||||
}
|
||||
if (cell->output(conn.first))
|
||||
for (auto i : conn.second)
|
||||
bit_drivers[i].insert(c->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -681,14 +691,14 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
|||
if (!conn.first.is_fully_const()) {
|
||||
auto chunks = conn.first.chunks();
|
||||
for (auto &c : chunks)
|
||||
c.wire = module->wires_[remap_name(c.wire->name)];
|
||||
c.wire = module->wires_.at(remap_name(c.wire->name));
|
||||
conn.first = std::move(chunks);
|
||||
}
|
||||
if (!conn.second.is_fully_const()) {
|
||||
auto chunks = conn.second.chunks();
|
||||
for (auto &c : chunks)
|
||||
if (c.wire)
|
||||
c.wire = module->wires_[remap_name(c.wire->name)];
|
||||
c.wire = module->wires_.at(remap_name(c.wire->name));
|
||||
conn.second = std::move(chunks);
|
||||
}
|
||||
module->connect(conn);
|
||||
|
@ -725,6 +735,79 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
|||
}
|
||||
}
|
||||
|
||||
for (auto &it : bit_users)
|
||||
if (bit_drivers.count(it.first))
|
||||
for (auto driver_cell : bit_drivers.at(it.first))
|
||||
for (auto user_cell : it.second)
|
||||
toposort.edge(driver_cell, user_cell);
|
||||
bool no_loops = toposort.sort();
|
||||
log_assert(no_loops);
|
||||
|
||||
for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) {
|
||||
RTLIL::Cell *not_cell = mapped_mod->cell(*ii);
|
||||
log_assert(not_cell);
|
||||
if (not_cell->type != "$_NOT_")
|
||||
continue;
|
||||
auto it = not2drivers.find(not_cell);
|
||||
if (it == not2drivers.end())
|
||||
continue;
|
||||
RTLIL::Cell *driver_lut = it->second;
|
||||
RTLIL::SigBit a_bit = not_cell->getPort("\\A");
|
||||
RTLIL::SigBit y_bit = not_cell->getPort("\\Y");
|
||||
RTLIL::Const driver_mask;
|
||||
|
||||
a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name));
|
||||
y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name));
|
||||
|
||||
auto jt = bit2sinks.find(a_bit);
|
||||
if (jt == bit2sinks.end())
|
||||
goto clone_lut;
|
||||
|
||||
for (auto sink_cell : jt->second)
|
||||
if (sink_cell->type != "$lut")
|
||||
goto clone_lut;
|
||||
|
||||
// Push downstream LUTs past inverter
|
||||
for (auto sink_cell : jt->second) {
|
||||
SigSpec A = sink_cell->getPort("\\A");
|
||||
RTLIL::Const mask = sink_cell->getParam("\\LUT");
|
||||
int index = 0;
|
||||
for (; index < GetSize(A); index++)
|
||||
if (A[index] == a_bit)
|
||||
break;
|
||||
log_assert(index < GetSize(A));
|
||||
int i = 0;
|
||||
while (i < GetSize(mask)) {
|
||||
for (int j = 0; j < (1 << index); j++)
|
||||
std::swap(mask[i+j], mask[i+j+(1 << index)]);
|
||||
i += 1 << (index+1);
|
||||
}
|
||||
A[index] = y_bit;
|
||||
sink_cell->setPort("\\A", A);
|
||||
sink_cell->setParam("\\LUT", mask);
|
||||
}
|
||||
|
||||
// Since we have rewritten all sinks (which we know
|
||||
// to be only LUTs) to be after the inverter, we can
|
||||
// go ahead and clone the LUT with the expectation
|
||||
// that the original driving LUT will become dangling
|
||||
// and get cleaned away
|
||||
clone_lut:
|
||||
driver_mask = driver_lut->getParam("\\LUT");
|
||||
for (auto &b : driver_mask.bits) {
|
||||
if (b == RTLIL::State::S0) b = RTLIL::State::S1;
|
||||
else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
|
||||
}
|
||||
auto cell = module->addLut(NEW_ID,
|
||||
driver_lut->getPort("\\A"),
|
||||
y_bit,
|
||||
driver_mask);
|
||||
for (auto &bit : cell->connections_.at("\\A")) {
|
||||
bit.wire = module->wires_.at(remap_name(bit.wire->name));
|
||||
bit2sinks[bit].push_back(cell);
|
||||
}
|
||||
}
|
||||
|
||||
//log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
|
||||
log("ABC RESULTS: input signals: %8d\n", in_wires);
|
||||
log("ABC RESULTS: output signals: %8d\n", out_wires);
|
||||
|
|
|
@ -174,8 +174,10 @@ struct ExtractFaWorker
|
|||
|
||||
SigSpec sig = root;
|
||||
|
||||
if (!ce.eval(sig))
|
||||
log_abort();
|
||||
if (!ce.eval(sig)) {
|
||||
ce.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sig == State::S1)
|
||||
func |= 1 << i;
|
||||
|
@ -214,8 +216,10 @@ struct ExtractFaWorker
|
|||
|
||||
SigSpec sig = root;
|
||||
|
||||
if (!ce.eval(sig))
|
||||
log_abort();
|
||||
if (!ce.eval(sig)) {
|
||||
ce.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sig == State::S1)
|
||||
func |= 1 << i;
|
||||
|
|
|
@ -27,7 +27,7 @@ parameter _TECHMAP_CONSTVAL_A_ = 0;
|
|||
parameter _TECHMAP_CONSTMSK_B_ = 0;
|
||||
parameter _TECHMAP_CONSTVAL_B_ = 0;
|
||||
|
||||
function automatic integer gen_lut;
|
||||
function automatic [(1 << `LUT_WIDTH)-1:0] gen_lut;
|
||||
input integer width;
|
||||
input integer operation;
|
||||
input integer swap;
|
||||
|
|
|
@ -4,8 +4,8 @@ OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o
|
|||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
|
||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v))
|
||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_bb.v))
|
||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/drams_map.v))
|
||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dram.txt))
|
||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutrams_map.v))
|
||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutram.txt))
|
||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams_map.v))
|
||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram.txt))
|
||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))
|
||||
|
|
|
@ -71,10 +71,10 @@ struct SynthEcp5Pass : public ScriptPass
|
|||
log(" do not use flipflops with CE in output netlist\n");
|
||||
log("\n");
|
||||
log(" -nobram\n");
|
||||
log(" do not use BRAM cells in output netlist\n");
|
||||
log(" do not use block RAM cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -nodram\n");
|
||||
log(" do not use distributed RAM cells in output netlist\n");
|
||||
log(" -nolutram\n");
|
||||
log(" do not use LUT RAM cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -nowidelut\n");
|
||||
log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
|
||||
|
@ -99,7 +99,7 @@ struct SynthEcp5Pass : public ScriptPass
|
|||
}
|
||||
|
||||
string top_opt, blif_file, edif_file, json_file;
|
||||
bool noccu2, nodffe, nobram, nodram, nowidelut, flatten, retime, abc2, abc9, dsp, vpr;
|
||||
bool noccu2, nodffe, nobram, nolutram, nowidelut, flatten, retime, abc2, abc9, dsp, vpr;
|
||||
|
||||
void clear_flags() YS_OVERRIDE
|
||||
{
|
||||
|
@ -110,7 +110,7 @@ struct SynthEcp5Pass : public ScriptPass
|
|||
noccu2 = false;
|
||||
nodffe = false;
|
||||
nobram = false;
|
||||
nodram = false;
|
||||
nolutram = false;
|
||||
nowidelut = false;
|
||||
flatten = true;
|
||||
retime = false;
|
||||
|
@ -176,11 +176,11 @@ struct SynthEcp5Pass : public ScriptPass
|
|||
nobram = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nodram") {
|
||||
nodram = true;
|
||||
if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") {
|
||||
nolutram = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nowidelut" || args[argidx] == "-nomux") {
|
||||
if (args[argidx] == "-nowidelut" || /*deprecated alias*/ args[argidx] == "-nomux") {
|
||||
nowidelut = true;
|
||||
continue;
|
||||
}
|
||||
|
@ -260,23 +260,27 @@ struct SynthEcp5Pass : public ScriptPass
|
|||
run("opt_clean");
|
||||
}
|
||||
|
||||
if (!nobram && check_label("bram", "(skip if -nobram)"))
|
||||
if (!nobram && check_label("map_bram", "(skip if -nobram)"))
|
||||
{
|
||||
run("memory_bram -rules +/ecp5/bram.txt");
|
||||
run("techmap -map +/ecp5/brams_map.v");
|
||||
}
|
||||
|
||||
if (!nodram && check_label("dram", "(skip if -nodram)"))
|
||||
if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
|
||||
{
|
||||
run("memory_bram -rules +/ecp5/dram.txt");
|
||||
run("techmap -map +/ecp5/drams_map.v");
|
||||
run("memory_bram -rules +/ecp5/lutram.txt");
|
||||
run("techmap -map +/ecp5/lutrams_map.v");
|
||||
}
|
||||
|
||||
if (check_label("fine"))
|
||||
if (check_label("map_ffram"))
|
||||
{
|
||||
run("opt -fast -mux_undef -undriven -fine");
|
||||
run("memory_map");
|
||||
run("opt -undriven -fine");
|
||||
}
|
||||
|
||||
if (check_label("map_gates"))
|
||||
{
|
||||
if (noccu2)
|
||||
run("techmap");
|
||||
else
|
||||
|
|
|
@ -3,15 +3,11 @@
|
|||
# NB: Inputs/Outputs must be ordered alphabetically
|
||||
# (with exceptions for carry in/out)
|
||||
|
||||
# Inputs: I0 I1 CI
|
||||
# Outputs: CO
|
||||
# Inputs: A B CI
|
||||
# Outputs: O CO
|
||||
# (NB: carry chain input/output must be last
|
||||
# input/output and have been moved there
|
||||
# overriding the alphabetical ordering)
|
||||
SB_CARRY 1 1 3 1
|
||||
$__ICE40_FULL_ADDER 1 1 3 2
|
||||
400 379 316
|
||||
259 231 126
|
||||
|
||||
# Inputs: I0 I1 I2 I3
|
||||
# Outputs: O
|
||||
SB_LUT4 2 1 4 1
|
||||
449 400 379 316
|
||||
|
|
|
@ -3,15 +3,11 @@
|
|||
# NB: Inputs/Outputs must be ordered alphabetically
|
||||
# (with exceptions for carry in/out)
|
||||
|
||||
# Inputs: CI I0 I1
|
||||
# Outputs: CO
|
||||
# Inputs: A B CI
|
||||
# Outputs: O CO
|
||||
# (NB: carry chain input/output must be last
|
||||
# input/output and have been moved there
|
||||
# overriding the alphabetical ordering)
|
||||
SB_CARRY 1 1 3 1
|
||||
$__ICE40_FULL_ADDER 1 1 3 2
|
||||
589 558 465
|
||||
675 609 186
|
||||
|
||||
# Inputs: I0 I1 I2 I3
|
||||
# Outputs: O
|
||||
SB_LUT4 2 1 4 1
|
||||
661 589 558 465
|
||||
|
|
|
@ -3,15 +3,11 @@
|
|||
# NB: Inputs/Outputs must be ordered alphabetically
|
||||
# (with exceptions for carry in/out)
|
||||
|
||||
# Inputs: I0 I1 CI
|
||||
# Outputs: CO
|
||||
# Inputs: A B CI
|
||||
# Outputs: O CO
|
||||
# (NB: carry chain input/output must be last
|
||||
# input/output and have been moved there
|
||||
# overriding the alphabetical ordering)
|
||||
SB_CARRY 1 1 3 1
|
||||
675 609 278
|
||||
|
||||
# Inputs: I0 I1 I2 I3
|
||||
# Outputs: O
|
||||
SB_LUT4 2 1 4 1
|
||||
1285 1231 1205 874
|
||||
$__ICE40_FULL_ADDER 1 1 3 2
|
||||
1231 1205 874
|
||||
675 609 278
|
||||
|
|
|
@ -44,6 +44,15 @@ module _80_ice40_alu (A, B, CI, BI, X, Y, CO);
|
|||
|
||||
genvar i;
|
||||
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
|
||||
`ifdef _ABC
|
||||
\$__ICE40_FULL_ADDER carry (
|
||||
.A(AA[i]),
|
||||
.B(BB[i]),
|
||||
.CI(C[i]),
|
||||
.CO(CO[i]),
|
||||
.O(Y[i])
|
||||
);
|
||||
`else
|
||||
SB_CARRY carry (
|
||||
.I0(AA[i]),
|
||||
.I1(BB[i]),
|
||||
|
@ -63,6 +72,7 @@ module _80_ice40_alu (A, B, CI, BI, X, Y, CO);
|
|||
.I3(C[i]),
|
||||
.O(Y[i])
|
||||
);
|
||||
`endif
|
||||
end endgenerate
|
||||
|
||||
assign X = AA ^ BB;
|
||||
|
|
|
@ -61,3 +61,27 @@ module \$lut (A, Y);
|
|||
endgenerate
|
||||
endmodule
|
||||
`endif
|
||||
|
||||
`ifdef _ABC
|
||||
module \$__ICE40_FULL_ADDER (output CO, O, input A, B, CI);
|
||||
SB_CARRY carry (
|
||||
.I0(A),
|
||||
.I1(B),
|
||||
.CI(CI),
|
||||
.CO(CO)
|
||||
);
|
||||
SB_LUT4 #(
|
||||
// I0: 1010 1010 1010 1010
|
||||
// I1: 1100 1100 1100 1100
|
||||
// I2: 1111 0000 1111 0000
|
||||
// I3: 1111 1111 0000 0000
|
||||
.LUT_INIT(16'b 0110_1001_1001_0110)
|
||||
) adder (
|
||||
.I0(1'b0),
|
||||
.I1(A),
|
||||
.I2(B),
|
||||
.I3(CI),
|
||||
.O(O)
|
||||
);
|
||||
endmodule
|
||||
`endif
|
||||
|
|
|
@ -127,7 +127,7 @@ endmodule
|
|||
|
||||
// SiliconBlue Logic Cells
|
||||
|
||||
(* abc_box_id = 2, lib_whitebox *)
|
||||
(* lib_whitebox *)
|
||||
module SB_LUT4 (output O, input I0, I1, I2, I3);
|
||||
parameter [15:0] LUT_INIT = 0;
|
||||
wire [7:0] s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0];
|
||||
|
@ -136,11 +136,34 @@ module SB_LUT4 (output O, input I0, I1, I2, I3);
|
|||
assign O = I0 ? s1[1] : s1[0];
|
||||
endmodule
|
||||
|
||||
(* abc_box_id = 1, abc_carry="CI,CO", lib_whitebox *)
|
||||
(* lib_whitebox *)
|
||||
module SB_CARRY (output CO, input I0, I1, CI);
|
||||
assign CO = (I0 && I1) || ((I0 || I1) && CI);
|
||||
endmodule
|
||||
|
||||
(* abc_box_id = 1, abc_carry="CI,CO", lib_whitebox *)
|
||||
module \$__ICE40_FULL_ADDER (output CO, O, input A, B, CI);
|
||||
SB_CARRY carry (
|
||||
.I0(A),
|
||||
.I1(B),
|
||||
.CI(CI),
|
||||
.CO(CO)
|
||||
);
|
||||
SB_LUT4 #(
|
||||
// I0: 1010 1010 1010 1010
|
||||
// I1: 1100 1100 1100 1100
|
||||
// I2: 1111 0000 1111 0000
|
||||
// I3: 1111 1111 0000 0000
|
||||
.LUT_INIT(16'b 0110_1001_1001_0110)
|
||||
) adder (
|
||||
.I0(1'b0),
|
||||
.I1(A),
|
||||
.I2(B),
|
||||
.I3(CI),
|
||||
.O(O)
|
||||
);
|
||||
endmodule
|
||||
|
||||
// Positive Edge SiliconBlue FF Cells
|
||||
|
||||
module SB_DFF (output `SB_DFF_REG, input C, D);
|
||||
|
|
|
@ -83,6 +83,51 @@ static void run_ice40_opts(Module *module)
|
|||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cell->type == "$__ICE40_FULL_ADDER")
|
||||
{
|
||||
SigSpec non_const_inputs, replacement_output;
|
||||
int count_zeros = 0, count_ones = 0;
|
||||
|
||||
SigBit inbit[3] = {
|
||||
cell->getPort("\\A"),
|
||||
cell->getPort("\\B"),
|
||||
cell->getPort("\\CI")
|
||||
};
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (inbit[i].wire == nullptr) {
|
||||
if (inbit[i] == State::S1)
|
||||
count_ones++;
|
||||
else
|
||||
count_zeros++;
|
||||
} else
|
||||
non_const_inputs.append(inbit[i]);
|
||||
|
||||
if (count_zeros >= 2)
|
||||
replacement_output = State::S0;
|
||||
else if (count_ones >= 2)
|
||||
replacement_output = State::S1;
|
||||
else if (GetSize(non_const_inputs) == 1)
|
||||
replacement_output = non_const_inputs;
|
||||
|
||||
if (GetSize(replacement_output)) {
|
||||
optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
|
||||
module->connect(cell->getPort("\\CO")[0], replacement_output);
|
||||
module->design->scratchpad_set_bool("opt.did_something", true);
|
||||
log("Optimized $__ICE40_FULL_ADDER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n",
|
||||
log_id(module), log_id(cell), log_signal(replacement_output));
|
||||
cell->type = "$lut";
|
||||
cell->setPort("\\A", { RTLIL::S0, inbit[0], inbit[1], inbit[2] });
|
||||
cell->setPort("\\Y", cell->getPort("\\O"));
|
||||
cell->unsetPort("\\B");
|
||||
cell->unsetPort("\\CI");
|
||||
cell->unsetPort("\\CO");
|
||||
cell->unsetPort("\\O");
|
||||
cell->setParam("\\LUT", RTLIL::Const::from_string("0110100110010110"));
|
||||
cell->setParam("\\WIDTH", 4);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto cell : sb_lut_cells)
|
||||
|
|
|
@ -56,10 +56,10 @@ static void run_ice40_unlut(Module *module)
|
|||
cell->unsetParam("\\LUT_INIT");
|
||||
|
||||
cell->setPort("\\A", SigSpec({
|
||||
get_bit_or_zero(cell->getPort("\\I3")),
|
||||
get_bit_or_zero(cell->getPort("\\I2")),
|
||||
get_bit_or_zero(cell->getPort("\\I0")),
|
||||
get_bit_or_zero(cell->getPort("\\I1")),
|
||||
get_bit_or_zero(cell->getPort("\\I0"))
|
||||
get_bit_or_zero(cell->getPort("\\I2")),
|
||||
get_bit_or_zero(cell->getPort("\\I3"))
|
||||
}));
|
||||
cell->setPort("\\Y", cell->getPort("\\O")[0]);
|
||||
cell->unsetPort("\\I0");
|
||||
|
|
|
@ -238,7 +238,7 @@ struct SynthIce40Pass : public ScriptPass
|
|||
{
|
||||
if (check_label("begin"))
|
||||
{
|
||||
run("read_verilog -lib -D_ABC +/ice40/cells_sim.v");
|
||||
run("read_verilog -icells -lib -D_ABC +/ice40/cells_sim.v");
|
||||
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
|
||||
run("proc");
|
||||
}
|
||||
|
@ -277,14 +277,14 @@ struct SynthIce40Pass : public ScriptPass
|
|||
run("opt_clean");
|
||||
}
|
||||
|
||||
if (!nobram && check_label("bram", "(skip if -nobram)"))
|
||||
if (!nobram && check_label("map_bram", "(skip if -nobram)"))
|
||||
{
|
||||
run("memory_bram -rules +/ice40/brams.txt");
|
||||
run("techmap -map +/ice40/brams_map.v");
|
||||
run("ice40_braminit");
|
||||
}
|
||||
|
||||
if (check_label("map"))
|
||||
if (check_label("map_ffram"))
|
||||
{
|
||||
run("opt -fast -mux_undef -undriven -fine");
|
||||
run("memory_map");
|
||||
|
@ -296,7 +296,7 @@ struct SynthIce40Pass : public ScriptPass
|
|||
if (nocarry)
|
||||
run("techmap");
|
||||
else
|
||||
run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
|
||||
run("techmap -map +/techmap.v -map +/ice40/arith_map.v" + std::string(abc == "abc9" ? " -D _ABC" : ""));
|
||||
if (retime || help_mode)
|
||||
run(abc + " -dff", "(only if -retime)");
|
||||
run("ice40_opt");
|
||||
|
@ -340,13 +340,14 @@ struct SynthIce40Pass : public ScriptPass
|
|||
else
|
||||
wire_delay = 250;
|
||||
run(abc + stringf(" -W %d -lut +/ice40/abc_%s.lut -box +/ice40/abc_%s.box", wire_delay, device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)");
|
||||
run("techmap -D NO_LUT -D _ABC -map +/ice40/cells_map.v");
|
||||
}
|
||||
else
|
||||
run(abc + " -dress -lut 4", "(skip if -noabc)");
|
||||
}
|
||||
run("clean");
|
||||
run("ice40_unlut");
|
||||
run("opt_lut -dlogic SB_CARRY:I0=1:I1=2:CI=3");
|
||||
run("opt_lut -dlogic SB_CARRY:I0=2:I1=1:CI=0");
|
||||
}
|
||||
|
||||
if (check_label("map_cells"))
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
chparam -set LUT_WIDTH 6 top
|
||||
simplemap
|
||||
equiv_opt -assert techmap -D LUT_WIDTH=6 -map +/cmp2lut.v
|
||||
design -load postopt
|
||||
equiv_opt -assert techmap -D LUT_WIDTH=6 -map +/gate2lut.v
|
||||
design -load postopt
|
||||
select -assert-count 0 t:* t:$lut %d
|
|
@ -1,29 +1,30 @@
|
|||
module top(...);
|
||||
input [3:0] a;
|
||||
parameter LUT_WIDTH = 4; // Multiples of 2 only
|
||||
input [LUT_WIDTH-1:0] a;
|
||||
|
||||
output o1_1 = 4'b1010 <= a;
|
||||
output o1_2 = 4'b1010 < a;
|
||||
output o1_3 = 4'b1010 >= a;
|
||||
output o1_4 = 4'b1010 > a;
|
||||
output o1_5 = 4'b1010 == a;
|
||||
output o1_6 = 4'b1010 != a;
|
||||
output o1_1 = {(LUT_WIDTH/2){2'b10}} <= a;
|
||||
output o1_2 = {(LUT_WIDTH/2){2'b10}} < a;
|
||||
output o1_3 = {(LUT_WIDTH/2){2'b10}} >= a;
|
||||
output o1_4 = {(LUT_WIDTH/2){2'b10}} > a;
|
||||
output o1_5 = {(LUT_WIDTH/2){2'b10}} == a;
|
||||
output o1_6 = {(LUT_WIDTH/2){2'b10}} != a;
|
||||
|
||||
output o2_1 = a <= 4'b1010;
|
||||
output o2_2 = a < 4'b1010;
|
||||
output o2_3 = a >= 4'b1010;
|
||||
output o2_4 = a > 4'b1010;
|
||||
output o2_5 = a == 4'b1010;
|
||||
output o2_6 = a != 4'b1010;
|
||||
output o2_1 = a <= {(LUT_WIDTH/2){2'b10}};
|
||||
output o2_2 = a < {(LUT_WIDTH/2){2'b10}};
|
||||
output o2_3 = a >= {(LUT_WIDTH/2){2'b10}};
|
||||
output o2_4 = a > {(LUT_WIDTH/2){2'b10}};
|
||||
output o2_5 = a == {(LUT_WIDTH/2){2'b10}};
|
||||
output o2_6 = a != {(LUT_WIDTH/2){2'b10}};
|
||||
|
||||
output o3_1 = 4'sb0101 <= $signed(a);
|
||||
output o3_2 = 4'sb0101 < $signed(a);
|
||||
output o3_3 = 4'sb0101 >= $signed(a);
|
||||
output o3_4 = 4'sb0101 > $signed(a);
|
||||
output o3_5 = 4'sb0101 == $signed(a);
|
||||
output o3_6 = 4'sb0101 != $signed(a);
|
||||
output o3_1 = {(LUT_WIDTH/2){2'sb01}} <= $signed(a);
|
||||
output o3_2 = {(LUT_WIDTH/2){2'sb01}} < $signed(a);
|
||||
output o3_3 = {(LUT_WIDTH/2){2'sb01}} >= $signed(a);
|
||||
output o3_4 = {(LUT_WIDTH/2){2'sb01}} > $signed(a);
|
||||
output o3_5 = {(LUT_WIDTH/2){2'sb01}} == $signed(a);
|
||||
output o3_6 = {(LUT_WIDTH/2){2'sb01}} != $signed(a);
|
||||
|
||||
output o4_1 = $signed(a) <= 4'sb0000;
|
||||
output o4_2 = $signed(a) < 4'sb0000;
|
||||
output o4_3 = $signed(a) >= 4'sb0000;
|
||||
output o4_4 = $signed(a) > 4'sb0000;
|
||||
output o4_1 = $signed(a) <= {LUT_WIDTH{1'sb0}};
|
||||
output o4_2 = $signed(a) < {LUT_WIDTH{1'sb0}};
|
||||
output o4_3 = $signed(a) >= {LUT_WIDTH{1'sb0}};
|
||||
output o4_4 = $signed(a) > {LUT_WIDTH{1'sb0}};
|
||||
endmodule
|
||||
|
|
|
@ -4,3 +4,8 @@ for x in *.v; do
|
|||
echo "Running $x.."
|
||||
../../yosys -q -s check_map.ys -l ${x%.v}.log $x
|
||||
done
|
||||
|
||||
for x in map_cmp.v; do
|
||||
echo "Running $x.."
|
||||
../../yosys -q -s check_map_lut6.ys -l ${x%.v}_lut6.log $x
|
||||
done
|
||||
|
|
|
@ -19,6 +19,6 @@ hierarchy -top abc9_test028
|
|||
proc
|
||||
|
||||
abc9 -lut 4
|
||||
select -assert-count 1 t:$lut r:LUT=1 r:WIDTH=1 %i %i
|
||||
select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i
|
||||
select -assert-count 1 t:unknown
|
||||
select -assert-none t:$lut t:unknown %% t: %D
|
||||
|
|
Loading…
Reference in New Issue