Merge branch 'master' of https://github.com/YosysHQ/yosys into feature/python_bindings

This commit is contained in:
Benedikt Tutzer 2019-04-30 13:22:33 +02:00
commit dc06e3a28b
88 changed files with 2798 additions and 321 deletions

View File

@ -16,6 +16,7 @@ Yosys 0.8 .. Yosys 0.8-dev
- Added "gate2lut.v" techmap rule - Added "gate2lut.v" techmap rule
- Added "rename -src" - Added "rename -src"
- Added "equiv_opt" pass - Added "equiv_opt" pass
- "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx"
Yosys 0.7 .. Yosys 0.8 Yosys 0.7 .. Yosys 0.8

View File

@ -16,11 +16,11 @@ ENABLE_READLINE := 1
ENABLE_EDITLINE := 0 ENABLE_EDITLINE := 0
ENABLE_VERIFIC := 0 ENABLE_VERIFIC := 0
ENABLE_COVER := 1 ENABLE_COVER := 1
ENABLE_LIBYOSYS := 1 ENABLE_LIBYOSYS := 0
ENABLE_PROTOBUF := 0 ENABLE_PROTOBUF := 0
# python wrappers # python wrappers
ENABLE_PYOSYS := 1 ENABLE_PYOSYS := 0
PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)" PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi) PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"") PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
@ -119,7 +119,7 @@ OBJS = kernel/version_$(GIT_REV).o
# is just a symlink to your actual ABC working directory, as 'make mrproper' # is just a symlink to your actual ABC working directory, as 'make mrproper'
# will remove the 'abc' directory and you do not want to accidentally # will remove the 'abc' directory and you do not want to accidentally
# delete your work on ABC.. # delete your work on ABC..
ABCREV = 2ddc57d ABCREV = 3709744
ABCPULL = 1 ABCPULL = 1
ABCURL ?= https://github.com/berkeley-abc/abc ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1

View File

@ -311,12 +311,24 @@ Verilog Attributes and non-standard features
that have the same ports as the real thing but do not contain information that have the same ports as the real thing but do not contain information
on the internal configuration. This modules are only used by the synthesis on the internal configuration. This modules are only used by the synthesis
passes to identify input and output ports of cells. The Verilog backend passes to identify input and output ports of cells. The Verilog backend
also does not output blackbox modules on default. also does not output blackbox modules on default. ``read_verilog``, unless
called with ``-noblackbox`` will automatically set the blackbox attribute
on any empty module it reads.
- The ``dynports'' attribute is used by the Verilog front-end to mark modules - The ``noblackbox`` attribute set on an empty module prevents ``read_verilog``
from automatically setting the blackbox attribute on the module.
- The ``whitebox`` attribute on modules triggers the same behavior as
``blackbox``, but is for whitebox modules, i.e. library modules that
contain a behavioral model of the cell type.
- The ``lib_whitebox`` attribute overwrites ``whitebox`` when ``read_verilog``
is run in `-lib` mode. Otherwise it's automatically removed.
- The ``dynports`` attribute is used by the Verilog front-end to mark modules
that have ports with a width that depends on a parameter. that have ports with a width that depends on a parameter.
- The ``hdlname'' attribute is used by some passes to document the original - The ``hdlname`` attribute is used by some passes to document the original
(HDL) name of a module when renaming a module. (HDL) name of a module when renaming a module.
- The ``keep`` attribute on cells and wires is used to mark objects that should - The ``keep`` attribute on cells and wires is used to mark objects that should
@ -358,7 +370,7 @@ Verilog Attributes and non-standard features
- When defining a macro with `define, all text between triple double quotes - When defining a macro with `define, all text between triple double quotes
is interpreted as macro body, even if it contains unescaped newlines. The is interpreted as macro body, even if it contains unescaped newlines. The
tipple double quotes are removed from the macro body. For example: triple double quotes are removed from the macro body. For example:
`define MY_MACRO(a, b) """ `define MY_MACRO(a, b) """
assign a = 23; assign a = 23;
@ -445,7 +457,7 @@ Non-standard or SystemVerilog features for formal verification
supported in any clocked block. supported in any clocked block.
- The syntax ``@($global_clock)`` can be used to create FFs that have no - The syntax ``@($global_clock)`` can be used to create FFs that have no
explicit clock input ($ff cells). The same can be achieved by using explicit clock input (``$ff`` cells). The same can be achieved by using
``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>`` ``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>``
is marked with the ``(* gclk *)`` Verilog attribute. is marked with the ``(* gclk *)`` Verilog attribute.
@ -458,7 +470,7 @@ from SystemVerilog:
- The ``assert`` statement from SystemVerilog is supported in its most basic - The ``assert`` statement from SystemVerilog is supported in its most basic
form. In module context: ``assert property (<expression>);`` and within an form. In module context: ``assert property (<expression>);`` and within an
always block: ``assert(<expression>);``. It is transformed to a $assert cell. always block: ``assert(<expression>);``. It is transformed to an ``$assert`` cell.
- The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are - The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are
also supported. The same limitations as with the ``assert`` statement apply. also supported. The same limitations as with the ``assert`` statement apply.

View File

@ -140,7 +140,7 @@ struct BlifDumper
return "subckt"; return "subckt";
if (!design->modules_.count(RTLIL::escape_id(cell_type))) if (!design->modules_.count(RTLIL::escape_id(cell_type)))
return "gate"; return "gate";
if (design->modules_.at(RTLIL::escape_id(cell_type))->get_bool_attribute("\\blackbox")) if (design->modules_.at(RTLIL::escape_id(cell_type))->get_blackbox_attribute())
return "gate"; return "gate";
return "subckt"; return "subckt";
} }
@ -196,7 +196,7 @@ struct BlifDumper
} }
f << stringf("\n"); f << stringf("\n");
if (module->get_bool_attribute("\\blackbox")) { if (module->get_blackbox_attribute()) {
f << stringf(".blackbox\n"); f << stringf(".blackbox\n");
f << stringf(".end\n"); f << stringf(".end\n");
return; return;
@ -640,7 +640,7 @@ struct BlifBackend : public Backend {
for (auto module_it : design->modules_) for (auto module_it : design->modules_)
{ {
RTLIL::Module *module = module_it.second; RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox") && !config.blackbox_mode) if (module->get_blackbox_attribute() && !config.blackbox_mode)
continue; continue;
if (module->processes.size() != 0) if (module->processes.size() != 0)

View File

@ -340,7 +340,7 @@ struct BtorWorker
if (cell->type == "$lt") btor_op = "lt"; if (cell->type == "$lt") btor_op = "lt";
if (cell->type == "$le") btor_op = "lte"; if (cell->type == "$le") btor_op = "lte";
if (cell->type.in("$eq", "$eqx")) btor_op = "eq"; if (cell->type.in("$eq", "$eqx")) btor_op = "eq";
if (cell->type.in("$ne", "$nex")) btor_op = "ne"; if (cell->type.in("$ne", "$nex")) btor_op = "neq";
if (cell->type == "$ge") btor_op = "gte"; if (cell->type == "$ge") btor_op = "gte";
if (cell->type == "$gt") btor_op = "gt"; if (cell->type == "$gt") btor_op = "gt";
log_assert(!btor_op.empty()); log_assert(!btor_op.empty());

View File

@ -178,7 +178,7 @@ struct EdifBackend : public Backend {
for (auto module_it : design->modules_) for (auto module_it : design->modules_)
{ {
RTLIL::Module *module = module_it.second; RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox")) if (module->get_blackbox_attribute())
continue; continue;
if (top_module_name.empty()) if (top_module_name.empty())
@ -192,7 +192,7 @@ struct EdifBackend : public Backend {
for (auto cell_it : module->cells_) for (auto cell_it : module->cells_)
{ {
RTLIL::Cell *cell = cell_it.second; RTLIL::Cell *cell = cell_it.second;
if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) { if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_blackbox_attribute()) {
lib_cell_ports[cell->type]; lib_cell_ports[cell->type];
for (auto p : cell->connections()) for (auto p : cell->connections())
lib_cell_ports[cell->type][p.first] = GetSize(p.second); lib_cell_ports[cell->type][p.first] = GetSize(p.second);
@ -302,7 +302,7 @@ struct EdifBackend : public Backend {
*f << stringf(" (technology (numberDefinition))\n"); *f << stringf(" (technology (numberDefinition))\n");
for (auto module : sorted_modules) for (auto module : sorted_modules)
{ {
if (module->get_bool_attribute("\\blackbox")) if (module->get_blackbox_attribute())
continue; continue;
SigMap sigmap(module); SigMap sigmap(module);

View File

@ -106,6 +106,95 @@ struct FirrtlWorker
RTLIL::Design *design; RTLIL::Design *design;
std::string indent; std::string indent;
// Define read/write ports and memories.
// We'll collect their definitions and emit the corresponding FIRRTL definitions at the appropriate point in module construction.
// For the moment, we don't handle $readmemh or $readmemb.
// These will be part of a subsequent PR.
struct read_port {
string name;
bool clk_enable;
bool clk_parity;
bool transparent;
RTLIL::SigSpec clk;
RTLIL::SigSpec ena;
RTLIL::SigSpec addr;
read_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr) : name(name), clk_enable(clk_enable), clk_parity(clk_parity), transparent(transparent), clk(clk), ena(ena), addr(addr) {
// Current (3/13/2019) conventions:
// generate a constant 0 for clock and a constant 1 for enable if they are undefined.
if (!clk.is_fully_def())
this->clk = SigSpec(RTLIL::Const(0, 1));
if (!ena.is_fully_def())
this->ena = SigSpec(RTLIL::Const(1, 1));
}
string gen_read(const char * indent) {
string addr_expr = make_expr(addr);
string ena_expr = make_expr(ena);
string clk_expr = make_expr(clk);
string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str());
string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str());
string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str());
return addr_str + ena_str + clk_str;
}
};
struct write_port : read_port {
RTLIL::SigSpec mask;
write_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr, RTLIL::SigSpec mask) : read_port(name, clk_enable, clk_parity, transparent, clk, ena, addr), mask(mask) {
if (!clk.is_fully_def())
this->clk = SigSpec(RTLIL::Const(0));
if (!ena.is_fully_def())
this->ena = SigSpec(RTLIL::Const(0));
if (!mask.is_fully_def())
this->ena = SigSpec(RTLIL::Const(1));
}
string gen_read(const char * /* indent */) {
log_error("gen_read called on write_port: %s\n", name.c_str());
return stringf("gen_read called on write_port: %s\n", name.c_str());
}
string gen_write(const char * indent) {
string addr_expr = make_expr(addr);
string ena_expr = make_expr(ena);
string clk_expr = make_expr(clk);
string mask_expr = make_expr(mask);
string mask_str = stringf("%s%s.mask <= %s\n", indent, name.c_str(), mask_expr.c_str());
string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str());
string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str());
string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str());
return addr_str + ena_str + clk_str + mask_str;
}
};
/* Memories defined within this module. */
struct memory {
string name; // memory name
int abits; // number of address bits
int size; // size (in units) of the memory
int width; // size (in bits) of each element
int read_latency;
int write_latency;
vector<read_port> read_ports;
vector<write_port> write_ports;
std::string init_file;
std::string init_file_srcFileSpec;
memory(string name, int abits, int size, int width) : name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {}
memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
void add_memory_read_port(read_port &rp) {
read_ports.push_back(rp);
}
void add_memory_write_port(write_port &wp) {
write_ports.push_back(wp);
}
void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) {
this->init_file = init_file;
this->init_file_srcFileSpec = init_file_srcFileSpec;
}
};
dict<string, memory> memories;
void register_memory(memory &m)
{
memories[m.name] = m;
}
void register_reverse_wire_map(string id, SigSpec sig) void register_reverse_wire_map(string id, SigSpec sig)
{ {
for (int i = 0; i < GetSize(sig); i++) for (int i = 0; i < GetSize(sig); i++)
@ -116,7 +205,7 @@ struct FirrtlWorker
{ {
} }
string make_expr(const SigSpec &sig) static string make_expr(const SigSpec &sig)
{ {
string expr; string expr;
@ -515,6 +604,7 @@ struct FirrtlWorker
int abits = cell->parameters.at("\\ABITS").as_int(); int abits = cell->parameters.at("\\ABITS").as_int();
int width = cell->parameters.at("\\WIDTH").as_int(); int width = cell->parameters.at("\\WIDTH").as_int();
int size = cell->parameters.at("\\SIZE").as_int(); int size = cell->parameters.at("\\SIZE").as_int();
memory m(mem_id, abits, size, width);
int rd_ports = cell->parameters.at("\\RD_PORTS").as_int(); int rd_ports = cell->parameters.at("\\RD_PORTS").as_int();
int wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); int wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
@ -531,33 +621,24 @@ struct FirrtlWorker
if (offset != 0) if (offset != 0)
log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(cell)); log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(cell));
cell_exprs.push_back(stringf(" mem %s:\n", mem_id.c_str()));
cell_exprs.push_back(stringf(" data-type => UInt<%d>\n", width));
cell_exprs.push_back(stringf(" depth => %d\n", size));
for (int i = 0; i < rd_ports; i++)
cell_exprs.push_back(stringf(" reader => r%d\n", i));
for (int i = 0; i < wr_ports; i++)
cell_exprs.push_back(stringf(" writer => w%d\n", i));
cell_exprs.push_back(stringf(" read-latency => 0\n"));
cell_exprs.push_back(stringf(" write-latency => 1\n"));
cell_exprs.push_back(stringf(" read-under-write => undefined\n"));
for (int i = 0; i < rd_ports; i++) for (int i = 0; i < rd_ports; i++)
{ {
if (rd_clk_enable[i] != State::S0) if (rd_clk_enable[i] != State::S0)
log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(i*abits, abits);
SigSpec data_sig = cell->getPort("\\RD_DATA").extract(i*width, width); SigSpec data_sig = cell->getPort("\\RD_DATA").extract(i*width, width);
string addr_expr = make_expr(cell->getPort("\\RD_ADDR").extract(i*abits, abits)); string addr_expr = make_expr(addr_sig);
string name(stringf("%s.r%d", m.name.c_str(), i));
cell_exprs.push_back(stringf(" %s.r%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str())); bool clk_enable = false;
cell_exprs.push_back(stringf(" %s.r%d.en <= UInt<1>(1)\n", mem_id.c_str(), i)); bool clk_parity = true;
cell_exprs.push_back(stringf(" %s.r%d.clk <= asClock(UInt<1>(0))\n", mem_id.c_str(), i)); bool transparency = false;
SigSpec ena_sig = RTLIL::SigSpec(RTLIL::State::S1, 1);
register_reverse_wire_map(stringf("%s.r%d.data", mem_id.c_str(), i), data_sig); SigSpec clk_sig = RTLIL::SigSpec(RTLIL::State::S0, 1);
read_port rp(name, clk_enable, clk_parity, transparency, clk_sig, ena_sig, addr_sig);
m.add_memory_read_port(rp);
cell_exprs.push_back(rp.gen_read(indent.c_str()));
register_reverse_wire_map(stringf("%s.data", name.c_str()), data_sig);
} }
for (int i = 0; i < wr_ports; i++) for (int i = 0; i < wr_ports; i++)
@ -568,9 +649,16 @@ struct FirrtlWorker
if (wr_clk_polarity[i] != State::S1) if (wr_clk_polarity[i] != State::S1)
log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
string addr_expr = make_expr(cell->getPort("\\WR_ADDR").extract(i*abits, abits)); string name(stringf("%s.w%d", m.name.c_str(), i));
string data_expr = make_expr(cell->getPort("\\WR_DATA").extract(i*width, width)); bool clk_enable = true;
string clk_expr = make_expr(cell->getPort("\\WR_CLK").extract(i)); bool clk_parity = true;
bool transparency = false;
SigSpec addr_sig =cell->getPort("\\WR_ADDR").extract(i*abits, abits);
string addr_expr = make_expr(addr_sig);
SigSpec data_sig =cell->getPort("\\WR_DATA").extract(i*width, width);
string data_expr = make_expr(data_sig);
SigSpec clk_sig = cell->getPort("\\WR_CLK").extract(i);
string clk_expr = make_expr(clk_sig);
SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width); SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width);
string wen_expr = make_expr(wen_sig[0]); string wen_expr = make_expr(wen_sig[0]);
@ -579,13 +667,50 @@ struct FirrtlWorker
if (wen_sig[0] != wen_sig[i]) if (wen_sig[0] != wen_sig[i])
log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
cell_exprs.push_back(stringf(" %s.w%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str())); SigSpec mask_sig = RTLIL::SigSpec(RTLIL::State::S1, 1);
cell_exprs.push_back(stringf(" %s.w%d.data <= %s\n", mem_id.c_str(), i, data_expr.c_str())); write_port wp(name, clk_enable, clk_parity, transparency, clk_sig, wen_sig[0], addr_sig, mask_sig);
cell_exprs.push_back(stringf(" %s.w%d.en <= %s\n", mem_id.c_str(), i, wen_expr.c_str())); m.add_memory_write_port(wp);
cell_exprs.push_back(stringf(" %s.w%d.mask <= UInt<1>(1)\n", mem_id.c_str(), i)); cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), name.c_str(), data_expr.c_str()));
cell_exprs.push_back(stringf(" %s.w%d.clk <= asClock(%s)\n", mem_id.c_str(), i, clk_expr.c_str())); cell_exprs.push_back(wp.gen_write(indent.c_str()));
} }
register_memory(m);
continue;
}
if (cell->type.in("$memwr", "$memrd", "$meminit"))
{
std::string cell_type = fid(cell->type);
std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string());
memory *mp = nullptr;
if (cell->type == "$meminit" ) {
log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str());
} else {
// It's a $memwr or $memrd. Remember the read/write port parameters for the eventual FIRRTL memory definition.
auto addrSig = cell->getPort("\\ADDR");
auto dataSig = cell->getPort("\\DATA");
auto enableSig = cell->getPort("\\EN");
auto clockSig = cell->getPort("\\CLK");
Const clk_enable = cell->parameters.at("\\CLK_ENABLE");
Const clk_polarity = cell->parameters.at("\\CLK_POLARITY");
mp = &memories.at(mem_id);
int portNum = 0;
bool transparency = false;
string data_expr = make_expr(dataSig);
if (cell->type.in("$memwr")) {
portNum = (int) mp->write_ports.size();
write_port wp(stringf("%s.w%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig, dataSig);
mp->add_memory_write_port(wp);
cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), wp.name.c_str(), data_expr.c_str()));
cell_exprs.push_back(wp.gen_write(indent.c_str()));
} else if (cell->type.in("$memrd")) {
portNum = (int) mp->read_ports.size();
read_port rp(stringf("%s.r%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig);
mp->add_memory_read_port(rp);
cell_exprs.push_back(rp.gen_read(indent.c_str()));
register_reverse_wire_map(stringf("%s.data", rp.name.c_str()), dataSig);
}
}
continue; continue;
} }
@ -763,6 +888,24 @@ struct FirrtlWorker
f << stringf("\n"); f << stringf("\n");
// If we have any memory definitions, output them.
for (auto kv : memories) {
memory m = kv.second;
f << stringf(" mem %s:\n", m.name.c_str());
f << stringf(" data-type => UInt<%d>\n", m.width);
f << stringf(" depth => %d\n", m.size);
for (int i = 0; i < (int) m.read_ports.size(); i += 1) {
f << stringf(" reader => r%d\n", i);
}
for (int i = 0; i < (int) m.write_ports.size(); i += 1) {
f << stringf(" writer => w%d\n", i);
}
f << stringf(" read-latency => %d\n", m.read_latency);
f << stringf(" write-latency => %d\n", m.write_latency);
f << stringf(" read-under-write => undefined\n");
}
f << stringf("\n");
for (auto str : cell_exprs) for (auto str : cell_exprs)
f << str; f << str;

View File

@ -127,7 +127,7 @@ struct IntersynthBackend : public Backend {
RTLIL::Module *module = module_it.second; RTLIL::Module *module = module_it.second;
SigMap sigmap(module); SigMap sigmap(module);
if (module->get_bool_attribute("\\blackbox")) if (module->get_blackbox_attribute())
continue; continue;
if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0) if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0)
continue; continue;

View File

@ -1543,7 +1543,7 @@ struct Smt2Backend : public Backend {
for (auto module : sorted_modules) for (auto module : sorted_modules)
{ {
if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn()) if (module->get_blackbox_attribute() || module->has_memories_warn() || module->has_processes_warn())
continue; continue;
log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module)); log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module));

View File

@ -739,7 +739,7 @@ struct SmvBackend : public Backend {
pool<Module*> modules; pool<Module*> modules;
for (auto module : design->modules()) for (auto module : design->modules())
if (!module->get_bool_attribute("\\blackbox") && !module->has_memories_warn() && !module->has_processes_warn()) if (!module->get_blackbox_attribute() && !module->has_memories_warn() && !module->has_processes_warn())
modules.insert(module); modules.insert(module);
if (template_f.is_open()) if (template_f.is_open())

View File

@ -212,7 +212,7 @@ struct SpiceBackend : public Backend {
for (auto module_it : design->modules_) for (auto module_it : design->modules_)
{ {
RTLIL::Module *module = module_it.second; RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox")) if (module->get_blackbox_attribute())
continue; continue;
if (module->processes.size() != 0) if (module->processes.size() != 0)

View File

@ -67,7 +67,7 @@ struct TableBackend : public Backend {
for (auto module : design->modules()) for (auto module : design->modules())
{ {
if (module->get_bool_attribute("\\blackbox")) if (module->get_blackbox_attribute())
continue; continue;
SigMap sigmap(module); SigMap sigmap(module);

View File

@ -187,6 +187,10 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
{ {
if (width < 0) if (width < 0)
width = data.bits.size() - offset; width = data.bits.size() - offset;
if (width == 0) {
f << "\"\"";
return;
}
if (nostr) if (nostr)
goto dump_hex; goto dump_hex;
if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) { if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
@ -340,6 +344,10 @@ void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decima
void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
{ {
if (GetSize(sig) == 0) {
f << "\"\"";
return;
}
if (sig.is_chunk()) { if (sig.is_chunk()) {
dump_sigchunk(f, sig.as_chunk()); dump_sigchunk(f, sig.as_chunk());
} else { } else {
@ -1770,7 +1778,7 @@ struct VerilogBackend : public Backend {
*f << stringf("/* Generated by %s */\n", yosys_version_str); *f << stringf("/* Generated by %s */\n", yosys_version_str);
for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) { for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
if (it->second->get_bool_attribute("\\blackbox") != blackboxes) if (it->second->get_blackbox_attribute() != blackboxes)
continue; continue;
if (selected && !design->selected_whole_module(it->first)) { if (selected && !design->selected_whole_module(it->first)) {
if (design->selected_module(it->first)) if (design->selected_module(it->first))

View File

@ -33,8 +33,6 @@
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
#define log_debug log
AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name) AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name)
: design(design), f(f), clk_name(clk_name) : design(design), f(f), clk_name(clk_name)
{ {

View File

@ -46,7 +46,7 @@ namespace AST {
// instantiate global variables (private API) // instantiate global variables (private API)
namespace AST_INTERNAL { namespace AST_INTERNAL {
bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit; bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_autowire;
AstNode *current_ast, *current_ast_mod; AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope; std::map<std::string, AstNode*> current_scope;
const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL; const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
@ -942,6 +942,20 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
if (!defer) if (!defer)
{ {
bool blackbox_module = flag_lib;
if (!blackbox_module && !flag_noblackbox) {
blackbox_module = true;
for (auto child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output))
continue;
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
continue;
blackbox_module = false;
break;
}
}
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { } while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
if (flag_dump_ast2) { if (flag_dump_ast2) {
@ -956,7 +970,63 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
log("--- END OF AST DUMP ---\n"); log("--- END OF AST DUMP ---\n");
} }
if (flag_lib) { if (flag_nowb && ast->attributes.count("\\whitebox")) {
delete ast->attributes.at("\\whitebox");
ast->attributes.erase("\\whitebox");
}
if (ast->attributes.count("\\lib_whitebox")) {
if (!flag_lib || flag_nowb) {
delete ast->attributes.at("\\lib_whitebox");
ast->attributes.erase("\\lib_whitebox");
} else {
if (ast->attributes.count("\\whitebox")) {
delete ast->attributes.at("\\whitebox");
ast->attributes.erase("\\whitebox");
}
AstNode *n = ast->attributes.at("\\lib_whitebox");
ast->attributes["\\whitebox"] = n;
ast->attributes.erase("\\lib_whitebox");
}
}
if (!blackbox_module && ast->attributes.count("\\blackbox")) {
AstNode *n = ast->attributes.at("\\blackbox");
if (n->type != AST_CONSTANT)
log_file_error(ast->filename, ast->linenum, "Got blackbox attribute with non-constant value!\n");
blackbox_module = n->asBool();
}
if (blackbox_module && ast->attributes.count("\\whitebox")) {
AstNode *n = ast->attributes.at("\\whitebox");
if (n->type != AST_CONSTANT)
log_file_error(ast->filename, ast->linenum, "Got whitebox attribute with non-constant value!\n");
blackbox_module = !n->asBool();
}
if (ast->attributes.count("\\noblackbox")) {
if (blackbox_module) {
AstNode *n = ast->attributes.at("\\noblackbox");
if (n->type != AST_CONSTANT)
log_file_error(ast->filename, ast->linenum, "Got noblackbox attribute with non-constant value!\n");
blackbox_module = !n->asBool();
}
delete ast->attributes.at("\\noblackbox");
ast->attributes.erase("\\noblackbox");
}
if (blackbox_module)
{
if (ast->attributes.count("\\whitebox")) {
delete ast->attributes.at("\\whitebox");
ast->attributes.erase("\\whitebox");
}
if (ast->attributes.count("\\lib_whitebox")) {
delete ast->attributes.at("\\lib_whitebox");
ast->attributes.erase("\\lib_whitebox");
}
std::vector<AstNode*> new_children; std::vector<AstNode*> new_children;
for (auto child : ast->children) { for (auto child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output)) { if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
@ -969,8 +1039,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
delete child; delete child;
} }
} }
ast->children.swap(new_children); ast->children.swap(new_children);
ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
if (ast->attributes.count("\\blackbox") == 0) {
ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
}
} }
ignoreThisSignalsInInitial = RTLIL::SigSpec(); ignoreThisSignalsInInitial = RTLIL::SigSpec();
@ -1009,7 +1083,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
current_module->nomeminit = flag_nomeminit; current_module->nomeminit = flag_nomeminit;
current_module->nomem2reg = flag_nomem2reg; current_module->nomem2reg = flag_nomem2reg;
current_module->mem2reg = flag_mem2reg; current_module->mem2reg = flag_mem2reg;
current_module->noblackbox = flag_noblackbox;
current_module->lib = flag_lib; current_module->lib = flag_lib;
current_module->nowb = flag_nowb;
current_module->noopt = flag_noopt; current_module->noopt = flag_noopt;
current_module->icells = flag_icells; current_module->icells = flag_icells;
current_module->autowire = flag_autowire; current_module->autowire = flag_autowire;
@ -1026,7 +1102,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
// create AstModule instances for all modules in the AST tree and add them to 'design' // create AstModule instances for all modules in the AST tree and add them to 'design'
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil,
bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire) bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
{ {
current_ast = ast; current_ast = ast;
flag_dump_ast1 = dump_ast1; flag_dump_ast1 = dump_ast1;
@ -1039,7 +1115,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
flag_nomeminit = nomeminit; flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg; flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg; flag_mem2reg = mem2reg;
flag_noblackbox = noblackbox;
flag_lib = lib; flag_lib = lib;
flag_nowb = nowb;
flag_noopt = noopt; flag_noopt = noopt;
flag_icells = icells; flag_icells = icells;
flag_autowire = autowire; flag_autowire = autowire;
@ -1373,7 +1451,9 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
flag_nomeminit = nomeminit; flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg; flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg; flag_mem2reg = mem2reg;
flag_noblackbox = noblackbox;
flag_lib = lib; flag_lib = lib;
flag_nowb = nowb;
flag_noopt = noopt; flag_noopt = noopt;
flag_icells = icells; flag_icells = icells;
flag_autowire = autowire; flag_autowire = autowire;

View File

@ -283,13 +283,13 @@ namespace AST
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code // process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit, void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,
bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire); bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
// parametric modules are supported directly by the AST library // parametric modules are supported directly by the AST library
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions // therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module { struct AstModule : RTLIL::Module {
AstNode *ast; AstNode *ast;
bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire; bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, autowire;
~AstModule() YS_OVERRIDE; ~AstModule() YS_OVERRIDE;
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE; RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE; RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE;

View File

@ -1030,7 +1030,26 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n"); log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n");
if (type == AST_REPEAT) if (type == AST_REPEAT)
log_file_error(filename, linenum, "Repeat loops are only allowed in constant functions!\n"); {
AstNode *count = children[0];
AstNode *body = children[1];
// eval count expression
while (count->simplify(true, false, false, stage, 32, true, false)) { }
if (count->type != AST_CONSTANT)
log_file_error(filename, linenum, "Repeat loops outside must have constant repeat counts!\n");
// convert to a block with the body repeated n times
type = AST_BLOCK;
children.clear();
for (int i = 0; i < count->bitsAsConst().as_int(); i++)
children.insert(children.begin(), body->clone());
delete count;
delete body;
did_something = true;
}
// unroll for loops and generate-for blocks // unroll for loops and generate-for blocks
if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0)
@ -1066,7 +1085,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 1st expression // eval 1st expression
AstNode *varbuf = init_ast->children[1]->clone(); AstNode *varbuf = init_ast->children[1]->clone();
while (varbuf->simplify(true, false, false, stage, 32, true, false)) { } {
int expr_width_hint = -1;
bool expr_sign_hint = true;
varbuf->detectSignWidth(expr_width_hint, expr_sign_hint);
while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
}
if (varbuf->type != AST_CONSTANT) if (varbuf->type != AST_CONSTANT)
log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n"); log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n");
@ -1088,7 +1112,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{ {
// eval 2nd expression // eval 2nd expression
AstNode *buf = while_ast->clone(); AstNode *buf = while_ast->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } {
int expr_width_hint = -1;
bool expr_sign_hint = true;
buf->detectSignWidth(expr_width_hint, expr_sign_hint);
while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, false)) { }
}
if (buf->type != AST_CONSTANT) if (buf->type != AST_CONSTANT)
log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n"); log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n");
@ -1129,7 +1158,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 3rd expression // eval 3rd expression
buf = next_ast->children[1]->clone(); buf = next_ast->children[1]->clone();
while (buf->simplify(true, false, false, stage, 32, true, false)) { } {
int expr_width_hint = -1;
bool expr_sign_hint = true;
buf->detectSignWidth(expr_width_hint, expr_sign_hint);
while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, true)) { }
}
if (buf->type != AST_CONSTANT) if (buf->type != AST_CONSTANT)
log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n"); log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n");

View File

@ -47,16 +47,20 @@ struct IlangFrontend : public Frontend {
log(" -nooverwrite\n"); log(" -nooverwrite\n");
log(" ignore re-definitions of modules. (the default behavior is to\n"); log(" ignore re-definitions of modules. (the default behavior is to\n");
log(" create an error message if the existing module is not a blackbox\n"); log(" create an error message if the existing module is not a blackbox\n");
log(" module, and overwrite the existing module if it is a blackbox module.)\n"); log(" module, and overwrite the existing module if it is a blackbox module.)\n");
log("\n"); log("\n");
log(" -overwrite\n"); log(" -overwrite\n");
log(" overwrite existing modules with the same name\n"); log(" overwrite existing modules with the same name\n");
log("\n"); log("\n");
log(" -lib\n");
log(" only create empty blackbox modules\n");
log("\n");
} }
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{ {
ILANG_FRONTEND::flag_nooverwrite = false; ILANG_FRONTEND::flag_nooverwrite = false;
ILANG_FRONTEND::flag_overwrite = false; ILANG_FRONTEND::flag_overwrite = false;
ILANG_FRONTEND::flag_lib = false;
log_header(design, "Executing ILANG frontend.\n"); log_header(design, "Executing ILANG frontend.\n");
@ -73,6 +77,10 @@ struct IlangFrontend : public Frontend {
ILANG_FRONTEND::flag_overwrite = true; ILANG_FRONTEND::flag_overwrite = true;
continue; continue;
} }
if (arg == "-lib") {
ILANG_FRONTEND::flag_lib = true;
continue;
}
break; break;
} }
extra_args(f, filename, args, argidx); extra_args(f, filename, args, argidx);

View File

@ -34,6 +34,7 @@ namespace ILANG_FRONTEND {
extern RTLIL::Design *current_design; extern RTLIL::Design *current_design;
extern bool flag_nooverwrite; extern bool flag_nooverwrite;
extern bool flag_overwrite; extern bool flag_overwrite;
extern bool flag_lib;
} }
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View File

@ -37,7 +37,7 @@ namespace ILANG_FRONTEND {
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack; std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
std::vector<RTLIL::CaseRule*> case_stack; std::vector<RTLIL::CaseRule*> case_stack;
dict<RTLIL::IdString, RTLIL::Const> attrbuf; dict<RTLIL::IdString, RTLIL::Const> attrbuf;
bool flag_nooverwrite, flag_overwrite; bool flag_nooverwrite, flag_overwrite, flag_lib;
bool delete_current_module; bool delete_current_module;
} }
using namespace ILANG_FRONTEND; using namespace ILANG_FRONTEND;
@ -98,7 +98,7 @@ module:
delete_current_module = false; delete_current_module = false;
if (current_design->has($2)) { if (current_design->has($2)) {
RTLIL::Module *existing_mod = current_design->module($2); RTLIL::Module *existing_mod = current_design->module($2);
if (!flag_overwrite && attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()) { if (!flag_overwrite && (flag_lib || (attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()))) {
log("Ignoring blackbox re-definition of module %s.\n", $2); log("Ignoring blackbox re-definition of module %s.\n", $2);
delete_current_module = true; delete_current_module = true;
} else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
@ -124,6 +124,8 @@ module:
current_module->fixup_ports(); current_module->fixup_ports();
if (delete_current_module) if (delete_current_module)
delete current_module; delete current_module;
else if (flag_lib)
current_module->makeblackbox();
current_module = nullptr; current_module = nullptr;
} EOL; } EOL;

View File

@ -14,6 +14,8 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(Q) mkdir -p $(dir $@) $(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $< $(P) flex -o frontends/verilog/verilog_lexer.cc $<
frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=100000
OBJS += frontends/verilog/verilog_parser.tab.o OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o OBJS += frontends/verilog/preproc.o

View File

@ -145,8 +145,18 @@ struct VerilogFrontend : public Frontend {
log(" -nodpi\n"); log(" -nodpi\n");
log(" disable DPI-C support\n"); log(" disable DPI-C support\n");
log("\n"); log("\n");
log(" -noblackbox\n");
log(" do not automatically add a (* blackbox *) attribute to an\n");
log(" empty module.\n");
log("\n");
log(" -lib\n"); log(" -lib\n");
log(" only create empty blackbox modules. This implies -DBLACKBOX.\n"); log(" only create empty blackbox modules. This implies -DBLACKBOX.\n");
log(" modules with the (* whitebox *) attribute will be preserved.\n");
log(" (* lib_whitebox *) will be treated like (* whitebox *).\n");
log("\n");
log(" -nowb\n");
log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
log(" all modules.\n");
log("\n"); log("\n");
log(" -noopt\n"); log(" -noopt\n");
log(" don't perform basic optimizations (such as const folding) in the\n"); log(" don't perform basic optimizations (such as const folding) in the\n");
@ -227,7 +237,9 @@ struct VerilogFrontend : public Frontend {
formal_mode = false; formal_mode = false;
norestrict_mode = false; norestrict_mode = false;
assume_asserts_mode = false; assume_asserts_mode = false;
noblackbox_mode = false;
lib_mode = false; lib_mode = false;
nowb_mode = false;
default_nettype_wire = true; default_nettype_wire = true;
log_header(design, "Executing Verilog-2005 frontend.\n"); log_header(design, "Executing Verilog-2005 frontend.\n");
@ -329,11 +341,19 @@ struct VerilogFrontend : public Frontend {
flag_nodpi = true; flag_nodpi = true;
continue; continue;
} }
if (arg == "-noblackbox") {
noblackbox_mode = true;
continue;
}
if (arg == "-lib") { if (arg == "-lib") {
lib_mode = true; lib_mode = true;
defines_map["BLACKBOX"] = string(); defines_map["BLACKBOX"] = string();
continue; continue;
} }
if (arg == "-nowb") {
nowb_mode = true;
continue;
}
if (arg == "-noopt") { if (arg == "-noopt") {
flag_noopt = true; flag_noopt = true;
continue; continue;
@ -429,7 +449,8 @@ struct VerilogFrontend : public Frontend {
if (flag_nodpi) if (flag_nodpi)
error_on_dpi_function(current_ast); error_on_dpi_function(current_ast);
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
flag_nomeminit, flag_nomem2reg, flag_mem2reg, noblackbox_mode, lib_mode, nowb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp) if (!flag_nopp)
delete lexin; delete lexin;

View File

@ -69,9 +69,15 @@ namespace VERILOG_FRONTEND
// running in -assert-assumes mode // running in -assert-assumes mode
extern bool assert_assumes_mode; extern bool assert_assumes_mode;
// running in -noblackbox mode
extern bool noblackbox_mode;
// running in -lib mode // running in -lib mode
extern bool lib_mode; extern bool lib_mode;
// running in -nowb mode
extern bool nowb_mode;
// lexer input stream // lexer input stream
extern std::istream *lexin; extern std::istream *lexin;
} }

View File

@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack; std::vector<char> case_type_stack;
bool do_not_require_port_stubs; bool do_not_require_port_stubs;
bool default_nettype_wire; bool default_nettype_wire;
bool sv_mode, formal_mode, lib_mode; bool sv_mode, formal_mode, noblackbox_mode, lib_mode, nowb_mode;
bool noassert_mode, noassume_mode, norestrict_mode; bool noassert_mode, noassume_mode, norestrict_mode;
bool assume_asserts_mode, assert_assumes_mode; bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const; bool current_wire_rand, current_wire_const;

View File

@ -453,7 +453,7 @@ Aig::Aig(Cell *cell)
int B = mk.inport("\\B"); int B = mk.inport("\\B");
int C = mk.inport("\\C"); int C = mk.inport("\\C");
int D = mk.inport("\\D"); int D = mk.inport("\\D");
int Y = mk.nand_gate(mk.nor_gate(A, B), mk.nor_gate(C, D)); int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D));
mk.outport(Y, "\\Y"); mk.outport(Y, "\\Y");
goto optimize; goto optimize;
} }

View File

@ -464,7 +464,7 @@ struct CellTypes
if (cell->type == "$_AOI4_") if (cell->type == "$_AOI4_")
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1)); return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
if (cell->type == "$_OAI4_") if (cell->type == "$_OAI4_")
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1)); return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1));
log_assert(arg4.bits.size() == 0); log_assert(arg4.bits.size() == 0);
return eval(cell, arg1, arg2, arg3, errp); return eval(cell, arg1, arg2, arg3, errp);

View File

@ -295,6 +295,9 @@ int main(int argc, char **argv)
printf(" -E <depsfile>\n"); printf(" -E <depsfile>\n");
printf(" write a Makefile dependencies file with in- and output file names\n"); printf(" write a Makefile dependencies file with in- and output file names\n");
printf("\n"); printf("\n");
printf(" -g\n");
printf(" globally enable debug log messages\n");
printf("\n");
printf(" -V\n"); printf(" -V\n");
printf(" print version information and exit\n"); printf(" print version information and exit\n");
printf("\n"); printf("\n");
@ -315,7 +318,7 @@ int main(int argc, char **argv)
} }
int opt; int opt;
while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1) while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1)
{ {
switch (opt) switch (opt)
{ {
@ -340,6 +343,9 @@ int main(int argc, char **argv)
case 'S': case 'S':
passes_commands.push_back("synth"); passes_commands.push_back("synth");
break; break;
case 'g':
log_force_debug++;
break;
case 'm': case 'm':
plugin_filenames.push_back(optarg); plugin_filenames.push_back(optarg);
break; break;
@ -523,13 +529,13 @@ int main(int argc, char **argv)
log_error("Can't open dependencies file for writing: %s\n", strerror(errno)); log_error("Can't open dependencies file for writing: %s\n", strerror(errno));
bool first = true; bool first = true;
for (auto fn : yosys_output_files) { for (auto fn : yosys_output_files) {
fprintf(f, "%s%s", first ? "" : " ", fn.c_str()); fprintf(f, "%s%s", first ? "" : " ", escape_filename_spaces(fn).c_str());
first = false; first = false;
} }
fprintf(f, ":"); fprintf(f, ":");
for (auto fn : yosys_input_files) { for (auto fn : yosys_input_files) {
if (yosys_output_files.count(fn) == 0) if (yosys_output_files.count(fn) == 0)
fprintf(f, " %s", fn.c_str()); fprintf(f, " %s", escape_filename_spaces(fn).c_str());
} }
fprintf(f, "\n"); fprintf(f, "\n");
} }

View File

@ -56,6 +56,10 @@ int log_verbose_level;
string log_last_error; string log_last_error;
void (*log_error_atexit)() = NULL; void (*log_error_atexit)() = NULL;
int log_make_debug = 0;
int log_force_debug = 0;
int log_debug_suppressed = 0;
vector<int> header_count; vector<int> header_count;
pool<RTLIL::IdString> log_id_cache; pool<RTLIL::IdString> log_id_cache;
vector<shared_str> string_buf; vector<shared_str> string_buf;
@ -92,6 +96,9 @@ void logv(const char *format, va_list ap)
format++; format++;
} }
if (log_make_debug && !ys_debug(1))
return;
std::string str = vstringf(format, ap); std::string str = vstringf(format, ap);
if (str.empty()) if (str.empty())

View File

@ -64,6 +64,10 @@ extern int log_verbose_level;
extern string log_last_error; extern string log_last_error;
extern void (*log_error_atexit)(); extern void (*log_error_atexit)();
extern int log_make_debug;
extern int log_force_debug;
extern int log_debug_suppressed;
void logv(const char *format, va_list ap); void logv(const char *format, va_list ap);
void logv_header(RTLIL::Design *design, const char *format, va_list ap); void logv_header(RTLIL::Design *design, const char *format, va_list ap);
void logv_warning(const char *format, va_list ap); void logv_warning(const char *format, va_list ap);
@ -82,6 +86,45 @@ YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf,
void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn); void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn);
YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
#ifndef NDEBUG
static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; }
# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)
#else
static inline bool ys_debug(int n = 0) { return false; }
# define log_debug(_fmt, ...) do { } while (0)
#endif
static inline void log_suppressed() {
if (log_debug_suppressed && !log_make_debug) {
log("<suppressed ~%d debug messages>\n", log_debug_suppressed);
log_debug_suppressed = 0;
}
}
struct LogMakeDebugHdl {
bool status = false;
LogMakeDebugHdl(bool start_on = false) {
if (start_on)
on();
}
~LogMakeDebugHdl() {
off();
}
void on() {
if (status) return;
status=true;
log_make_debug++;
}
void off_silent() {
if (!status) return;
status=false;
log_make_debug--;
}
void off() {
off_silent();
}
};
void log_spacer(); void log_spacer();
void log_push(); void log_push();
void log_pop(); void log_pop();

View File

@ -87,6 +87,7 @@ Pass::pre_post_exec_state_t Pass::pre_execute()
void Pass::post_execute(Pass::pre_post_exec_state_t state) void Pass::post_execute(Pass::pre_post_exec_state_t state)
{ {
IdString::checkpoint(); IdString::checkpoint();
log_suppressed();
int64_t time_ns = PerformanceTimer::query() - state.begin_ns; int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
runtime_ns += time_ns; runtime_ns += time_ns;

View File

@ -214,9 +214,12 @@ bool RTLIL::Const::is_fully_undef() const
return true; return true;
} }
void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id) void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
{ {
attributes[id] = RTLIL::Const(1); if (value)
attributes[id] = RTLIL::Const(1);
else if (attributes.count(id))
attributes.erase(id);
} }
bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
@ -611,7 +614,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_modules() const
std::vector<RTLIL::Module*> result; std::vector<RTLIL::Module*> result;
result.reserve(modules_.size()); result.reserve(modules_.size());
for (auto &it : modules_) for (auto &it : modules_)
if (selected_module(it.first) && !it.second->get_bool_attribute("\\blackbox")) if (selected_module(it.first) && !it.second->get_blackbox_attribute())
result.push_back(it.second); result.push_back(it.second);
return result; return result;
} }
@ -621,7 +624,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const
std::vector<RTLIL::Module*> result; std::vector<RTLIL::Module*> result;
result.reserve(modules_.size()); result.reserve(modules_.size());
for (auto &it : modules_) for (auto &it : modules_)
if (selected_whole_module(it.first) && !it.second->get_bool_attribute("\\blackbox")) if (selected_whole_module(it.first) && !it.second->get_blackbox_attribute())
result.push_back(it.second); result.push_back(it.second);
return result; return result;
} }
@ -631,7 +634,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const
std::vector<RTLIL::Module*> result; std::vector<RTLIL::Module*> result;
result.reserve(modules_.size()); result.reserve(modules_.size());
for (auto &it : modules_) for (auto &it : modules_)
if (it.second->get_bool_attribute("\\blackbox")) if (it.second->get_blackbox_attribute())
continue; continue;
else if (selected_whole_module(it.first)) else if (selected_whole_module(it.first))
result.push_back(it.second); result.push_back(it.second);
@ -678,6 +681,30 @@ std::map<unsigned int, RTLIL::Module*> *RTLIL::Module::get_all_modules(void)
} }
#endif #endif
void RTLIL::Module::makeblackbox()
{
pool<RTLIL::Wire*> delwires;
for (auto it = wires_.begin(); it != wires_.end(); ++it)
if (!it->second->port_input && !it->second->port_output)
delwires.insert(it->second);
for (auto it = memories.begin(); it != memories.end(); ++it)
delete it->second;
memories.clear();
for (auto it = cells_.begin(); it != cells_.end(); ++it)
delete it->second;
cells_.clear();
for (auto it = processes.begin(); it != processes.end(); ++it)
delete it->second;
processes.clear();
remove(delwires);
set_bool_attribute("\\blackbox");
}
void RTLIL::Module::reprocess_module(RTLIL::Design *, dict<RTLIL::IdString, RTLIL::Module *>) void RTLIL::Module::reprocess_module(RTLIL::Design *, dict<RTLIL::IdString, RTLIL::Module *>)
{ {
log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name)); log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name));

View File

@ -567,9 +567,13 @@ struct RTLIL::AttrObject
{ {
dict<RTLIL::IdString, RTLIL::Const> attributes; dict<RTLIL::IdString, RTLIL::Const> attributes;
void set_bool_attribute(RTLIL::IdString id); void set_bool_attribute(RTLIL::IdString id, bool value=true);
bool get_bool_attribute(RTLIL::IdString id) const; bool get_bool_attribute(RTLIL::IdString id) const;
bool get_blackbox_attribute(bool ignore_wb=false) const {
return get_bool_attribute("\\blackbox") || (!ignore_wb && get_bool_attribute("\\whitebox"));
}
void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data); void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
void add_strpool_attribute(RTLIL::IdString id, const pool<string> &data); void add_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
pool<string> get_strpool_attribute(RTLIL::IdString id) const; pool<string> get_strpool_attribute(RTLIL::IdString id) const;
@ -983,6 +987,7 @@ public:
virtual void sort(); virtual void sort();
virtual void check(); virtual void check();
virtual void optimize(); virtual void optimize();
virtual void makeblackbox();
void connect(const RTLIL::SigSig &conn); void connect(const RTLIL::SigSig &conn);
void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs); void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs);

View File

@ -482,6 +482,20 @@ void remove_directory(std::string dirname)
#endif #endif
} }
std::string escape_filename_spaces(const std::string& filename)
{
std::string out;
out.reserve(filename.size());
for (auto c : filename)
{
if (c == ' ')
out += "\\ ";
else
out.push_back(c);
}
return out;
}
int GetSize(RTLIL::Wire *wire) int GetSize(RTLIL::Wire *wire)
{ {
return wire->width; return wire->width;

View File

@ -257,6 +257,7 @@ std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX");
bool check_file_exists(std::string filename, bool is_exec = false); bool check_file_exists(std::string filename, bool is_exec = false);
bool is_absolute_path(std::string filename); bool is_absolute_path(std::string filename);
void remove_directory(std::string dirname); void remove_directory(std::string dirname);
std::string escape_filename_spaces(const std::string& filename);
template<typename T> int GetSize(const T &obj) { return obj.size(); } template<typename T> int GetSize(const T &obj) { return obj.size(); }
int GetSize(RTLIL::Wire *wire); int GetSize(RTLIL::Wire *wire);

View File

@ -71,7 +71,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
RTLIL::Module *mod = design->modules_.at(it.second->type); RTLIL::Module *mod = design->modules_.at(it.second->type);
if (!design->selected_whole_module(mod->name)) if (!design->selected_whole_module(mod->name))
continue; continue;
if (mod->get_bool_attribute("\\blackbox")) if (mod->get_blackbox_attribute())
continue; continue;
if (it.second->hasPort(name)) if (it.second->hasPort(name))
continue; continue;

View File

@ -128,7 +128,7 @@ struct BugpointPass : public Pass {
{ {
for (auto &it : design_copy->modules_) for (auto &it : design_copy->modules_)
{ {
if (it.second->get_bool_attribute("\\blackbox")) if (it.second->get_blackbox_attribute())
continue; continue;
if (index++ == seed) if (index++ == seed)
@ -143,7 +143,7 @@ struct BugpointPass : public Pass {
{ {
for (auto mod : design_copy->modules()) for (auto mod : design_copy->modules())
{ {
if (mod->get_bool_attribute("\\blackbox")) if (mod->get_blackbox_attribute())
continue; continue;
for (auto wire : mod->wires()) for (auto wire : mod->wires())
@ -168,7 +168,7 @@ struct BugpointPass : public Pass {
{ {
for (auto mod : design_copy->modules()) for (auto mod : design_copy->modules())
{ {
if (mod->get_bool_attribute("\\blackbox")) if (mod->get_blackbox_attribute())
continue; continue;
for (auto &it : mod->cells_) for (auto &it : mod->cells_)
@ -186,7 +186,7 @@ struct BugpointPass : public Pass {
{ {
for (auto mod : design_copy->modules()) for (auto mod : design_copy->modules())
{ {
if (mod->get_bool_attribute("\\blackbox")) if (mod->get_blackbox_attribute())
continue; continue;
for (auto cell : mod->cells()) for (auto cell : mod->cells())

View File

@ -128,6 +128,45 @@ struct SetattrPass : public Pass {
} }
} SetattrPass; } SetattrPass;
struct WbflipPass : public Pass {
WbflipPass() : Pass("wbflip", "flip the whitebox attribute") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" wbflip [selection]\n");
log("\n");
log("Flip the whitebox attribute on selected cells. I.e. if it's set, unset it, and\n");
log("vice-versa. Blackbox cells are not effected by this command.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
// if (arg == "-mod") {
// flag_mod = true;
// continue;
// }
break;
}
extra_args(args, argidx, design);
for (Module *module : design->modules())
{
if (!design->selected(module))
continue;
if (module->get_bool_attribute("\\blackbox"))
continue;
module->set_bool_attribute("\\whitebox", !module->get_bool_attribute("\\whitebox"));
}
}
} WbflipPass;
struct SetparamPass : public Pass { struct SetparamPass : public Pass {
SetparamPass() : Pass("setparam", "set/unset parameters on objects") { } SetparamPass() : Pass("setparam", "set/unset parameters on objects") { }
void help() YS_OVERRIDE void help() YS_OVERRIDE

View File

@ -237,15 +237,34 @@ struct ShowWorker
int idx = single_idx_count++; int idx = single_idx_count++;
for (int rep, i = int(sig.chunks().size())-1; i >= 0; i -= rep) { for (int rep, i = int(sig.chunks().size())-1; i >= 0; i -= rep) {
const RTLIL::SigChunk &c = sig.chunks().at(i); const RTLIL::SigChunk &c = sig.chunks().at(i);
net = gen_signode_simple(c, false); if (!driver && c.wire == nullptr) {
log_assert(!net.empty()); RTLIL::State s1 = c.data.front();
for (auto s2 : c.data)
if (s1 != s2)
goto not_const_stream;
net.clear();
} else {
not_const_stream:
net = gen_signode_simple(c, false);
log_assert(!net.empty());
}
for (rep = 1; i-rep >= 0 && c == sig.chunks().at(i-rep); rep++) {} for (rep = 1; i-rep >= 0 && c == sig.chunks().at(i-rep); rep++) {}
std::string repinfo = rep > 1 ? stringf("%dx ", rep) : ""; std::string repinfo = rep > 1 ? stringf("%dx ", rep) : "";
if (driver) { if (driver) {
log_assert(!net.empty());
label_string += stringf("<s%d> %d:%d - %s%d:%d |", i, pos, pos-c.width+1, repinfo.c_str(), c.offset+c.width-1, c.offset); label_string += stringf("<s%d> %d:%d - %s%d:%d |", i, pos, pos-c.width+1, repinfo.c_str(), c.offset+c.width-1, c.offset);
net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i)); net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i));
net_conn_map[net].bits = rep*c.width; net_conn_map[net].bits = rep*c.width;
net_conn_map[net].color = nextColor(c, net_conn_map[net].color); net_conn_map[net].color = nextColor(c, net_conn_map[net].color);
} else
if (net.empty()) {
log_assert(rep == 1);
label_string += stringf("%c -&gt; %d:%d |",
c.data.front() == State::S0 ? '0' :
c.data.front() == State::S1 ? '1' :
c.data.front() == State::Sx ? 'X' :
c.data.front() == State::Sz ? 'Z' : '?',
pos, pos-rep*c.width+1);
} else { } else {
label_string += stringf("<s%d> %s%d:%d - %d:%d |", i, repinfo.c_str(), c.offset+c.width-1, c.offset, pos, pos-rep*c.width+1); label_string += stringf("<s%d> %s%d:%d - %d:%d |", i, repinfo.c_str(), c.offset+c.width-1, c.offset, pos, pos-rep*c.width+1);
net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i)); net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i));
@ -555,7 +574,7 @@ struct ShowWorker
if (!design->selected_module(module->name)) if (!design->selected_module(module->name))
continue; continue;
if (design->selected_whole_module(module->name)) { if (design->selected_whole_module(module->name)) {
if (module->get_bool_attribute("\\blackbox")) { if (module->get_blackbox_attribute()) {
// log("Skipping blackbox module %s.\n", id2cstr(module->name)); // log("Skipping blackbox module %s.\n", id2cstr(module->name));
continue; continue;
} else } else
@ -771,7 +790,7 @@ struct ShowPass : public Pass {
if (format != "ps" && format != "dot") { if (format != "ps" && format != "dot") {
int modcount = 0; int modcount = 0;
for (auto &mod_it : design->modules_) { for (auto &mod_it : design->modules_) {
if (mod_it.second->get_bool_attribute("\\blackbox")) if (mod_it.second->get_blackbox_attribute())
continue; continue;
if (mod_it.second->cells_.empty() && mod_it.second->connections().empty()) if (mod_it.second->cells_.empty() && mod_it.second->connections().empty())
continue; continue;

View File

@ -94,4 +94,38 @@ struct TracePass : public Pass {
} }
} TracePass; } TracePass;
struct DebugPass : public Pass {
DebugPass() : Pass("debug", "run command with debug log messages enabled") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" debug cmd\n");
log("\n");
log("Execute the specified command with debug log messages enabled\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// .. parse options ..
break;
}
log_force_debug++;
try {
std::vector<std::string> new_args(args.begin() + argidx, args.end());
Pass::call(design, new_args);
} catch (...) {
log_force_debug--;
throw;
}
log_force_debug--;
}
} DebugPass;
PRIVATE_NAMESPACE_END PRIVATE_NAMESPACE_END

View File

@ -44,7 +44,10 @@ struct EquivOptPass:public ScriptPass
log(" useful for handling architecture-specific primitives.\n"); log(" useful for handling architecture-specific primitives.\n");
log("\n"); log("\n");
log(" -assert\n"); log(" -assert\n");
log(" produce an error if the circuits are not equivalent\n"); log(" produce an error if the circuits are not equivalent.\n");
log("\n");
log(" -undef\n");
log(" enable modelling of undef states during equiv_induct.\n");
log("\n"); log("\n");
log("The following commands are executed by this verification command:\n"); log("The following commands are executed by this verification command:\n");
help_script(); help_script();
@ -52,13 +55,14 @@ struct EquivOptPass:public ScriptPass
} }
std::string command, techmap_opts; std::string command, techmap_opts;
bool assert; bool assert, undef;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
command = ""; command = "";
techmap_opts = ""; techmap_opts = "";
assert = false; assert = false;
undef = 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
@ -84,6 +88,10 @@ struct EquivOptPass:public ScriptPass
assert = true; assert = true;
continue; continue;
} }
if (args[argidx] == "-undef") {
undef = true;
continue;
}
break; break;
} }
@ -134,12 +142,17 @@ struct EquivOptPass:public ScriptPass
opts = " -map <filename> ..."; opts = " -map <filename> ...";
else else
opts = techmap_opts; opts = techmap_opts;
run("techmap -D EQUIV -autoproc" + opts); run("techmap -wb -D EQUIV -autoproc" + opts);
} }
if (check_label("prove")) { if (check_label("prove")) {
run("equiv_make gold gate equiv"); run("equiv_make gold gate equiv");
run("equiv_induct equiv"); if (help_mode)
run("equiv_induct [-undef] equiv");
else if (undef)
run("equiv_induct -undef equiv");
else
run("equiv_induct equiv");
if (help_mode) if (help_mode)
run("equiv_status [-assert] equiv"); run("equiv_status [-assert] equiv");
else if (assert) else if (assert)

View File

@ -346,9 +346,9 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
} }
RTLIL::Module *mod = design->modules_[cell->type]; RTLIL::Module *mod = design->modules_[cell->type];
if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) { if (design->modules_.at(cell->type)->get_blackbox_attribute()) {
if (flag_simcheck) if (flag_simcheck)
log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n", log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n",
cell->type.c_str(), module->name.c_str(), cell->name.c_str()); cell->type.c_str(), module->name.c_str(), cell->name.c_str());
continue; continue;
} }
@ -451,7 +451,7 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::
if (indent == 0) if (indent == 0)
log("Top module: %s\n", mod->name.c_str()); log("Top module: %s\n", mod->name.c_str());
else if (!mod->get_bool_attribute("\\blackbox")) else if (!mod->get_blackbox_attribute())
log("Used module: %*s%s\n", indent, "", mod->name.c_str()); log("Used module: %*s%s\n", indent, "", mod->name.c_str());
used.insert(mod); used.insert(mod);
@ -491,7 +491,7 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
int del_counter = 0; int del_counter = 0;
for (auto mod : del_modules) { for (auto mod : del_modules) {
if (!purge_lib && mod->get_bool_attribute("\\blackbox")) if (!purge_lib && mod->get_blackbox_attribute())
continue; continue;
log("Removing unused module `%s'.\n", mod->name.c_str()); log("Removing unused module `%s'.\n", mod->name.c_str());
design->modules_.erase(mod->name); design->modules_.erase(mod->name);
@ -910,7 +910,7 @@ struct HierarchyPass : public Pass {
if (m == nullptr) if (m == nullptr)
continue; continue;
if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) { if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
IdString new_m_name = m->derive(design, cell->parameters, true); IdString new_m_name = m->derive(design, cell->parameters, true);
if (new_m_name.empty()) if (new_m_name.empty())
continue; continue;

View File

@ -75,7 +75,7 @@ struct UniquifyPass : public Pass {
if (tmod == nullptr) if (tmod == nullptr)
continue; continue;
if (tmod->get_bool_attribute("\\blackbox")) if (tmod->get_blackbox_attribute())
continue; continue;
if (tmod->get_bool_attribute("\\unique") && newname == tmod->name) if (tmod->get_bool_attribute("\\unique") && newname == tmod->name)

View File

@ -744,7 +744,8 @@ grow_read_ports:;
if (clken) { if (clken) {
clock_domains[pi.clocks] = clkdom; clock_domains[pi.clocks] = clkdom;
clock_polarities[pi.clkpol] = clkdom.second; clock_polarities[pi.clkpol] = clkdom.second;
read_transp[pi.transp] = transp; if (!pi.make_transp)
read_transp[pi.transp] = transp;
pi.sig_clock = clkdom.first; pi.sig_clock = clkdom.first;
pi.sig_en = rd_en[cell_port_i]; pi.sig_en = rd_en[cell_port_i];
pi.effective_clkpol = clkdom.second; pi.effective_clkpol = clkdom.second;
@ -957,6 +958,8 @@ grow_read_ports:;
SigSpec addr_ok_q = addr_ok; SigSpec addr_ok_q = addr_ok;
if ((pi.clocks || pi.make_outreg) && !addr_ok.empty()) { if ((pi.clocks || pi.make_outreg) && !addr_ok.empty()) {
addr_ok_q = module->addWire(NEW_ID); addr_ok_q = module->addWire(NEW_ID);
if (!pi.sig_en.empty())
addr_ok = module->Mux(NEW_ID, addr_ok_q, addr_ok, pi.sig_en);
module->addDff(NEW_ID, pi.sig_clock, addr_ok, addr_ok_q, pi.effective_clkpol); module->addDff(NEW_ID, pi.sig_clock, addr_ok, addr_ok_q, pi.effective_clkpol);
} }

View File

@ -13,5 +13,6 @@ OBJS += passes/opt/wreduce.o
OBJS += passes/opt/opt_demorgan.o 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
endif endif

View File

@ -137,7 +137,7 @@ void rmunused_module_cells(Module *module, bool verbose)
for (auto cell : unused) { for (auto cell : unused) {
if (verbose) if (verbose)
log(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str()); log_debug(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
module->design->scratchpad_set_bool("opt.did_something", true); module->design->scratchpad_set_bool("opt.did_something", true);
module->remove(cell); module->remove(cell);
count_rm_cells++; count_rm_cells++;
@ -326,7 +326,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
for (auto wire : maybe_del_wires) for (auto wire : maybe_del_wires)
if (!used_signals.check_any(RTLIL::SigSpec(wire))) { if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
if (check_public_name(wire->name) && verbose) { if (check_public_name(wire->name) && verbose) {
log(" removing unused non-port wire %s.\n", wire->name.c_str()); log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
} }
del_wires.insert(wire); del_wires.insert(wire);
del_wires_count++; del_wires_count++;
@ -336,7 +336,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
count_rm_wires += del_wires.size(); count_rm_wires += del_wires.size();
if (verbose && del_wires_count > 0) if (verbose && del_wires_count > 0)
log(" removed %d unused temporary wires.\n", del_wires_count); log_debug(" removed %d unused temporary wires.\n", del_wires_count);
} }
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@ -399,7 +399,7 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
} }
if (verbose) if (verbose)
log(" removing redundant init attribute on %s.\n", log_id(wire)); log_debug(" removing redundant init attribute on %s.\n", log_id(wire));
wire->attributes.erase("\\init"); wire->attributes.erase("\\init");
did_something = true; did_something = true;
@ -426,7 +426,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
} }
for (auto cell : delcells) { for (auto cell : delcells) {
if (verbose) if (verbose)
log(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(), log_debug(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(),
log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A"))); log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A")));
module->remove(cell); module->remove(cell);
} }
@ -551,6 +551,7 @@ struct CleanPass : public Pass {
rmunused_module(module, purge_mode, false, false); rmunused_module(module, purge_mode, false, false);
} }
log_suppressed();
if (count_rm_cells > 0 || count_rm_wires > 0) if (count_rm_cells > 0 || count_rm_wires > 0)
log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires); log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires);

View File

@ -67,7 +67,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
if (sig.size() == 0) if (sig.size() == 0)
continue; continue;
log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c)); log_debug("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c));
module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width))); module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width)));
did_something = true; did_something = true;
} }
@ -78,7 +78,7 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell,
RTLIL::SigSpec Y = cell->getPort(out_port); RTLIL::SigSpec Y = cell->getPort(out_port);
out_val.extend_u0(Y.size(), false); out_val.extend_u0(Y.size(), false);
log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", log_debug("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
cell->type.c_str(), cell->name.c_str(), info.c_str(), cell->type.c_str(), cell->name.c_str(), info.c_str(),
module->name.c_str(), log_signal(Y), log_signal(out_val)); module->name.c_str(), log_signal(Y), log_signal(out_val));
// log_cell(cell); // log_cell(cell);
@ -134,7 +134,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
if (GetSize(grouped_bits[i]) == GetSize(bits_y)) if (GetSize(grouped_bits[i]) == GetSize(bits_y))
return false; return false;
log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n", log_debug("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
log_id(cell->type), log_id(cell), log_id(module)); log_id(cell->type), log_id(cell), log_id(module));
for (int i = 0; i < GRP_N; i++) for (int i = 0; i < GRP_N; i++)
@ -156,7 +156,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
} }
if (cell->type.in("$and", "$or") && i == GRP_CONST_A) { if (cell->type.in("$and", "$or") && i == GRP_CONST_A) {
log(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a)); log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a));
module->connect(new_y, new_b); module->connect(new_y, new_b);
module->connect(new_conn); module->connect(new_conn);
continue; continue;
@ -180,10 +180,10 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
module->connect(new_conn); module->connect(new_conn);
log(" New cell `%s': A=%s", log_id(c), log_signal(new_a)); log_debug(" New cell `%s': A=%s", log_id(c), log_signal(new_a));
if (b_name == "\\B") if (b_name == "\\B")
log(", B=%s", log_signal(new_b)); log_debug(", B=%s", log_signal(new_b));
log("\n"); log_debug("\n");
} }
cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
@ -197,7 +197,7 @@ void handle_polarity_inv(Cell *cell, IdString port, IdString param, const SigMap
{ {
SigSpec sig = assign_map(cell->getPort(port)); SigSpec sig = assign_map(cell->getPort(port));
if (invert_map.count(sig)) { if (invert_map.count(sig)) {
log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module),
log_signal(sig), log_signal(invert_map.at(sig))); log_signal(sig), log_signal(invert_map.at(sig)));
cell->setPort(port, (invert_map.at(sig))); cell->setPort(port, (invert_map.at(sig)));
@ -226,7 +226,7 @@ void handle_clkpol_celltype_swap(Cell *cell, string type1, string type2, IdStrin
if (cell->type.in(type1, type2)) { if (cell->type.in(type1, type2)) {
SigSpec sig = assign_map(cell->getPort(port)); SigSpec sig = assign_map(cell->getPort(port));
if (invert_map.count(sig)) { if (invert_map.count(sig)) {
log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module),
log_signal(sig), log_signal(invert_map.at(sig))); log_signal(sig), log_signal(invert_map.at(sig)));
cell->setPort(port, (invert_map.at(sig))); cell->setPort(port, (invert_map.at(sig)));
@ -455,9 +455,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{ {
if (cell->type == "$reduce_xnor") { if (cell->type == "$reduce_xnor") {
cover("opt.opt_expr.reduce_xnor_not"); cover("opt.opt_expr.reduce_xnor_not");
log("Replacing %s cell `%s' in module `%s' with $not cell.\n", log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n",
log_id(cell->type), log_id(cell->name), log_id(module)); log_id(cell->type), log_id(cell->name), log_id(module));
cell->type = "$not"; cell->type = "$not";
did_something = true;
} else { } else {
cover("opt.opt_expr.unary_buffer"); cover("opt.opt_expr.unary_buffer");
replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A")); replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A"));
@ -488,7 +489,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (GetSize(new_sig_a) < GetSize(sig_a)) { if (GetSize(new_sig_a) < GetSize(sig_a)) {
cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str()); cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str());
log("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a));
cell->setPort("\\A", new_sig_a); cell->setPort("\\A", new_sig_a);
cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a); cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a);
@ -511,7 +512,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (GetSize(new_sig_b) < GetSize(sig_b)) { if (GetSize(new_sig_b) < GetSize(sig_b)) {
cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str()); cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str());
log("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b));
cell->setPort("\\B", new_sig_b); cell->setPort("\\B", new_sig_b);
cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b); cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b);
@ -537,7 +538,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
cover("opt.opt_expr.fine.$reduce_and"); cover("opt.opt_expr.fine.$reduce_and");
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a); cell->setPort("\\A", sig_a = new_a);
cell->parameters.at("\\A_WIDTH") = 1; cell->parameters.at("\\A_WIDTH") = 1;
@ -563,7 +564,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str()); cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a); cell->setPort("\\A", sig_a = new_a);
cell->parameters.at("\\A_WIDTH") = 1; cell->parameters.at("\\A_WIDTH") = 1;
@ -589,7 +590,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) {
cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str()); cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str());
log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b));
cell->setPort("\\B", sig_b = new_b); cell->setPort("\\B", sig_b = new_b);
cell->parameters.at("\\B_WIDTH") = 1; cell->parameters.at("\\B_WIDTH") = 1;
@ -640,7 +641,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) { if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) {
cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str()); cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
RTLIL::SigSpec tmp = cell->getPort("\\A"); RTLIL::SigSpec tmp = cell->getPort("\\A");
cell->setPort("\\A", cell->getPort("\\B")); cell->setPort("\\A", cell->getPort("\\B"));
cell->setPort("\\B", tmp); cell->setPort("\\B", tmp);
@ -750,7 +751,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
ACTION_DO("\\Y", cell->getPort("\\A")); ACTION_DO("\\Y", cell->getPort("\\A"));
if (input == State::S0 && !a.is_fully_undef()) { if (input == State::S0 && !a.is_fully_undef()) {
cover("opt.opt_expr.action_" S__LINE__); cover("opt.opt_expr.action_" S__LINE__);
log("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n", log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str()); cell->type.c_str(), cell->name.c_str(), module->name.c_str());
cell->setPort("\\A", SigSpec(State::Sx, GetSize(a))); cell->setPort("\\A", SigSpec(State::Sx, GetSize(a)));
did_something = true; did_something = true;
@ -822,7 +823,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
ACTION_DO("\\Y", cell->getPort("\\A")); ACTION_DO("\\Y", cell->getPort("\\A"));
} else { } else {
cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str()); cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->type = "$not"; cell->type = "$not";
cell->parameters.erase("\\B_WIDTH"); cell->parameters.erase("\\B_WIDTH");
cell->parameters.erase("\\B_SIGNED"); cell->parameters.erase("\\B_SIGNED");
@ -837,7 +838,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
(assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero())) (assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero()))
{ {
cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str()); cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
log_id(module), "$eq" ? "$logic_not" : "$reduce_bool"); log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool"; cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool";
if (assign_map(cell->getPort("\\A")).is_fully_zero()) { if (assign_map(cell->getPort("\\A")).is_fully_zero()) {
@ -876,7 +877,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str()); cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y)); log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y));
module->connect(cell->getPort("\\Y"), sig_y); module->connect(cell->getPort("\\Y"), sig_y);
@ -939,7 +940,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (identity_wrt_b) if (identity_wrt_b)
cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B'); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
if (!identity_wrt_a) { if (!identity_wrt_a) {
@ -969,7 +970,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) { cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str()); cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S")); cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\B"); cell->unsetPort("\\B");
cell->unsetPort("\\S"); cell->unsetPort("\\S");
@ -988,7 +989,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) { if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str()); cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S")); cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\S"); cell->unsetPort("\\S");
if (cell->type == "$mux") { if (cell->type == "$mux") {
@ -1008,7 +1009,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str()); cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\B", cell->getPort("\\S")); cell->setPort("\\B", cell->getPort("\\S"));
cell->unsetPort("\\S"); cell->unsetPort("\\S");
if (cell->type == "$mux") { if (cell->type == "$mux") {
@ -1061,7 +1062,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
if (cell->getPort("\\S").size() != new_s.size()) { if (cell->getPort("\\S").size() != new_s.size()) {
cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str()); cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str());
log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module)); GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", new_a); cell->setPort("\\A", new_a);
cell->setPort("\\B", new_b); cell->setPort("\\B", new_b);
@ -1179,7 +1180,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{ {
cover("opt.opt_expr.mul_shift.zero"); cover("opt.opt_expr.mul_shift.zero");
log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
cell->name.c_str(), module->name.c_str()); cell->name.c_str(), module->name.c_str());
module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
@ -1197,7 +1198,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
else else
cover("opt.opt_expr.mul_shift.unswapped"); cover("opt.opt_expr.mul_shift.unswapped");
log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", log_debug("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
a_val, cell->name.c_str(), module->name.c_str(), i); a_val, cell->name.c_str(), module->name.c_str(), i);
if (!swapped_ab) { if (!swapped_ab) {
@ -1237,7 +1238,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{ {
cover("opt.opt_expr.divmod_zero"); cover("opt.opt_expr.divmod_zero");
log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
cell->name.c_str(), module->name.c_str()); cell->name.c_str(), module->name.c_str());
module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size()))); module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size())));
@ -1254,7 +1255,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{ {
cover("opt.opt_expr.div_shift"); cover("opt.opt_expr.div_shift");
log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
b_val, cell->name.c_str(), module->name.c_str(), i); b_val, cell->name.c_str(), module->name.c_str(), i);
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6); std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
@ -1272,7 +1273,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{ {
cover("opt.opt_expr.mod_mask"); cover("opt.opt_expr.mod_mask");
log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
b_val, cell->name.c_str(), module->name.c_str()); b_val, cell->name.c_str(), module->name.c_str());
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i); std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i);
@ -1342,7 +1343,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
SigSpec y_sig = cell->getPort("\\Y"); SigSpec y_sig = cell->getPort("\\Y");
Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig)); Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig));
log("Replacing cell `%s' in module `%s' with constant driver %s.\n", log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n",
log_id(cell), log_id(module), log_signal(y_value)); log_id(cell), log_id(module), log_signal(y_value));
module->connect(y_sig, y_value); module->connect(y_sig, y_value);
@ -1354,7 +1355,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (redundant_bits) if (redundant_bits)
{ {
log("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n", log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
redundant_bits, log_id(cell->type), log_id(cell), log_id(module)); redundant_bits, log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", sig_a); cell->setPort("\\A", sig_a);
@ -1493,7 +1494,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (replace || remove) if (replace || remove)
{ {
log("Replacing %s cell `%s' (implementing %s) with %s.\n", log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n",
log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str()); log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str());
if (replace) if (replace)
module->connect(cell->getPort("\\Y"), replace_sig); module->connect(cell->getPort("\\Y"), replace_sig);
@ -1599,8 +1600,14 @@ struct OptExprPass : public Pass {
for (auto module : design->selected_modules()) for (auto module : design->selected_modules())
{ {
if (undriven) log("Optimizing module %s.\n", log_id(module));
if (undriven) {
did_something = false;
replace_undriven(design, module); replace_undriven(design, module);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
}
do { do {
do { do {
@ -1610,7 +1617,11 @@ struct OptExprPass : public Pass {
design->scratchpad_set_bool("opt.did_something", true); design->scratchpad_set_bool("opt.did_something", true);
} while (did_something); } while (did_something);
replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv); replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something); } while (did_something);
log_suppressed();
} }
log_pop(); log_pop();

View File

@ -315,17 +315,17 @@ struct OptMergeWorker
{ {
if (sharemap.count(cell) > 0) { if (sharemap.count(cell) > 0) {
did_something = true; did_something = true;
log(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str()); log_debug(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str());
for (auto &it : cell->connections()) { for (auto &it : cell->connections()) {
if (cell->output(it.first)) { if (cell->output(it.first)) {
RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first); RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first);
log(" Redirecting output %s: %s = %s\n", it.first.c_str(), log_debug(" Redirecting output %s: %s = %s\n", it.first.c_str(),
log_signal(it.second), log_signal(other_sig)); log_signal(it.second), log_signal(other_sig));
module->connect(RTLIL::SigSig(it.second, other_sig)); module->connect(RTLIL::SigSig(it.second, other_sig));
assign_map.add(it.second, other_sig); assign_map.add(it.second, other_sig);
} }
} }
log(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); log_debug(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str());
#ifdef USE_CELL_HASH_CACHE #ifdef USE_CELL_HASH_CACHE
cell_hash_cache.erase(cell); cell_hash_cache.erase(cell);
#endif #endif
@ -336,6 +336,8 @@ struct OptMergeWorker
} }
} }
} }
log_suppressed();
} }
}; };

View File

@ -181,14 +181,14 @@ struct OptMuxtreeWorker
for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++) for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++)
if (root_muxes.at(mux_idx)) { if (root_muxes.at(mux_idx)) {
log(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
root_mux_rerun.erase(mux_idx); root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx); eval_root_mux(mux_idx);
} }
while (!root_mux_rerun.empty()) { while (!root_mux_rerun.empty()) {
int mux_idx = *root_mux_rerun.begin(); int mux_idx = *root_mux_rerun.begin();
log(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell)); log_debug(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell));
log_assert(root_enable_muxes.at(mux_idx)); log_assert(root_enable_muxes.at(mux_idx));
root_mux_rerun.erase(mux_idx); root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx); eval_root_mux(mux_idx);
@ -326,7 +326,7 @@ struct OptMuxtreeWorker
if (abort_count == 0) { if (abort_count == 0) {
root_mux_rerun.insert(m); root_mux_rerun.insert(m);
root_enable_muxes.at(m) = true; root_enable_muxes.at(m) = true;
log(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell)); log_debug(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell));
} else } else
eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1); eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1);
} else } else

852
passes/opt/pmux2shiftx.cc Normal file
View File

@ -0,0 +1,852 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct OnehotDatabase
{
Module *module;
const SigMap &sigmap;
bool verbose = false;
bool initialized = false;
pool<SigBit> init_ones;
dict<SigSpec, pool<SigSpec>> sig_sources_db;
dict<SigSpec, bool> sig_onehot_cache;
pool<SigSpec> recursion_guard;
OnehotDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap)
{
}
void initialize()
{
log_assert(!initialized);
initialized = true;
for (auto wire : module->wires())
{
auto it = wire->attributes.find("\\init");
if (it == wire->attributes.end())
continue;
auto &val = it->second;
int width = std::max(GetSize(wire), GetSize(val));
for (int i = 0; i < width; i++)
if (val[i] == State::S1)
init_ones.insert(sigmap(SigBit(wire, i)));
}
for (auto cell : module->cells())
{
vector<SigSpec> inputs;
SigSpec output;
if (cell->type.in("$adff", "$dff", "$dffe", "$dlatch", "$ff"))
{
output = cell->getPort("\\Q");
if (cell->type == "$adff")
inputs.push_back(cell->getParam("\\ARST_VALUE"));
inputs.push_back(cell->getPort("\\D"));
}
if (cell->type.in("$mux", "$pmux"))
{
output = cell->getPort("\\Y");
inputs.push_back(cell->getPort("\\A"));
SigSpec B = cell->getPort("\\B");
for (int i = 0; i < GetSize(B); i += GetSize(output))
inputs.push_back(B.extract(i, GetSize(output)));
}
if (!output.empty())
{
output = sigmap(output);
auto &srcs = sig_sources_db[output];
for (auto src : inputs) {
while (!src.empty() && src[GetSize(src)-1] == State::S0)
src.remove(GetSize(src)-1);
srcs.insert(sigmap(src));
}
}
}
}
void query_worker(const SigSpec &sig, bool &retval, bool &cache, int indent)
{
if (verbose)
log("%*s %s\n", indent, "", log_signal(sig));
log_assert(retval);
if (recursion_guard.count(sig)) {
if (verbose)
log("%*s - recursion\n", indent, "");
cache = false;
return;
}
auto it = sig_onehot_cache.find(sig);
if (it != sig_onehot_cache.end()) {
if (verbose)
log("%*s - cached (%s)\n", indent, "", it->second ? "true" : "false");
if (!it->second)
retval = false;
return;
}
bool found_init_ones = false;
for (auto bit : sig) {
if (init_ones.count(bit)) {
if (found_init_ones) {
if (verbose)
log("%*s - non-onehot init value\n", indent, "");
retval = false;
break;
}
found_init_ones = true;
}
}
if (retval)
{
if (sig.is_fully_const())
{
bool found_ones = false;
for (auto bit : sig) {
if (bit == State::S1) {
if (found_ones) {
if (verbose)
log("%*s - non-onehot constant\n", indent, "");
retval = false;
break;
}
found_ones = true;
}
}
}
else
{
auto srcs = sig_sources_db.find(sig);
if (srcs == sig_sources_db.end()) {
if (verbose)
log("%*s - no sources for non-const signal\n", indent, "");
retval = false;
} else {
for (auto &src : srcs->second) {
bool child_cache = true;
recursion_guard.insert(sig);
query_worker(src, retval, child_cache, indent+4);
recursion_guard.erase(sig);
if (!child_cache)
cache = false;
if (!retval)
break;
}
}
}
}
// it is always safe to cache a negative result
if (cache || !retval)
sig_onehot_cache[sig] = retval;
}
bool query(const SigSpec &sig)
{
bool retval = true;
bool cache = true;
if (verbose)
log("** ONEHOT QUERY START (%s)\n", log_signal(sig));
if (!initialized)
initialize();
query_worker(sig, retval, cache, 3);
if (verbose)
log("** ONEHOT QUERY RESULT = %s\n", retval ? "true" : "false");
// it is always safe to cache the root result of a query
if (!cache)
sig_onehot_cache[sig] = retval;
return retval;
}
};
struct Pmux2ShiftxPass : public Pass {
Pmux2ShiftxPass() : Pass("pmux2shiftx", "transform $pmux cells to $shiftx cells") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" pmux2shiftx [options] [selection]\n");
log("\n");
log("This pass transforms $pmux cells to $shiftx cells.\n");
log("\n");
log(" -v, -vv\n");
log(" verbose output\n");
log("\n");
log(" -min_density <percentage>\n");
log(" specifies the minimum density for the shifter\n");
log(" default: 50\n");
log("\n");
log(" -min_choices <int>\n");
log(" specified the minimum number of choices for a control signal\n");
log(" default: 3\n");
log("\n");
log(" -onehot ignore|pmux|shiftx\n");
log(" select strategy for one-hot encoded control signals\n");
log(" default: pmux\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
int min_density = 50;
int min_choices = 3;
bool allow_onehot = false;
bool optimize_onehot = true;
bool verbose = false;
bool verbose_onehot = false;
log_header(design, "Executing PMUX2SHIFTX pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-min_density" && argidx+1 < args.size()) {
min_density = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-min_choices" && argidx+1 < args.size()) {
min_choices = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "ignore") {
argidx++;
allow_onehot = false;
optimize_onehot = false;
continue;
}
if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "pmux") {
argidx++;
allow_onehot = false;
optimize_onehot = true;
continue;
}
if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "shiftx") {
argidx++;
allow_onehot = true;
optimize_onehot = false;
continue;
}
if (args[argidx] == "-v") {
verbose = true;
continue;
}
if (args[argidx] == "-vv") {
verbose = true;
verbose_onehot = true;
continue;
}
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
OnehotDatabase onehot_db(module, sigmap);
onehot_db.verbose = verbose_onehot;
dict<SigBit, pair<SigSpec, Const>> eqdb;
for (auto cell : module->cells())
{
if (cell->type == "$eq")
{
dict<SigBit, State> bits;
SigSpec A = sigmap(cell->getPort("\\A"));
SigSpec B = sigmap(cell->getPort("\\B"));
int a_width = cell->getParam("\\A_WIDTH").as_int();
int b_width = cell->getParam("\\B_WIDTH").as_int();
if (a_width < b_width) {
bool a_signed = cell->getParam("\\A_SIGNED").as_int();
A.extend_u0(b_width, a_signed);
}
if (b_width < a_width) {
bool b_signed = cell->getParam("\\B_SIGNED").as_int();
B.extend_u0(a_width, b_signed);
}
for (int i = 0; i < GetSize(A); i++) {
SigBit a_bit = A[i], b_bit = B[i];
if (b_bit.wire && !a_bit.wire) {
std::swap(a_bit, b_bit);
}
if (!a_bit.wire || b_bit.wire)
goto next_cell;
if (bits.count(a_bit))
goto next_cell;
bits[a_bit] = b_bit.data;
}
if (GetSize(bits) > 20)
goto next_cell;
bits.sort();
pair<SigSpec, Const> entry;
for (auto it : bits) {
entry.first.append_bit(it.first);
entry.second.bits.push_back(it.second);
}
eqdb[sigmap(cell->getPort("\\Y")[0])] = entry;
goto next_cell;
}
if (cell->type == "$logic_not")
{
dict<SigBit, State> bits;
SigSpec A = sigmap(cell->getPort("\\A"));
for (int i = 0; i < GetSize(A); i++)
bits[A[i]] = State::S0;
bits.sort();
pair<SigSpec, Const> entry;
for (auto it : bits) {
entry.first.append_bit(it.first);
entry.second.bits.push_back(it.second);
}
eqdb[sigmap(cell->getPort("\\Y")[0])] = entry;
goto next_cell;
}
next_cell:;
}
for (auto cell : module->selected_cells())
{
if (cell->type != "$pmux")
continue;
string src = cell->get_src_attribute();
int width = cell->getParam("\\WIDTH").as_int();
int width_bits = ceil_log2(width);
int extwidth = width;
while (extwidth & (extwidth-1))
extwidth++;
dict<SigSpec, pool<int>> seldb;
SigSpec A = cell->getPort("\\A");
SigSpec B = cell->getPort("\\B");
SigSpec S = sigmap(cell->getPort("\\S"));
for (int i = 0; i < GetSize(S); i++)
{
if (!eqdb.count(S[i]))
continue;
auto &entry = eqdb.at(S[i]);
seldb[entry.first].insert(i);
}
if (seldb.empty())
continue;
bool printed_pmux_header = false;
if (verbose) {
printed_pmux_header = true;
log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell));
log(" data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits);
}
SigSpec updated_S = cell->getPort("\\S");
SigSpec updated_B = cell->getPort("\\B");
while (!seldb.empty())
{
// pick the largest entry in seldb
SigSpec sig = seldb.begin()->first;
for (auto &it : seldb) {
if (GetSize(sig) < GetSize(it.first))
sig = it.first;
else if (GetSize(seldb.at(sig)) < GetSize(it.second))
sig = it.first;
}
// find the relevant choices
bool is_onehot = GetSize(sig) > 2;
dict<Const, int> choices;
for (int i : seldb.at(sig)) {
Const val = eqdb.at(S[i]).second;
int onebits = 0;
for (auto b : val.bits)
if (b == State::S1)
onebits++;
if (onebits > 1)
is_onehot = false;
choices[val] = i;
}
bool full_pmux = GetSize(choices) == GetSize(S);
// TBD: also find choices that are using signals that are subsets of the bits in "sig"
if (!verbose)
{
if (is_onehot && !allow_onehot && !optimize_onehot) {
seldb.erase(sig);
continue;
}
if (GetSize(choices) < min_choices) {
seldb.erase(sig);
continue;
}
}
if (!printed_pmux_header) {
printed_pmux_header = true;
log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell));
log(" data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits);
}
log(" checking ctrl signal %s\n", log_signal(sig));
auto print_choices = [&]() {
log(" table of choices:\n");
for (auto &it : choices)
log(" %3d: %s: %s\n", it.second, log_signal(it.first),
log_signal(B.extract(it.second*width, width)));
};
if (verbose)
{
if (is_onehot && !allow_onehot && !optimize_onehot) {
print_choices();
log(" ignoring one-hot encoding.\n");
seldb.erase(sig);
continue;
}
if (GetSize(choices) < min_choices) {
print_choices();
log(" insufficient choices.\n");
seldb.erase(sig);
continue;
}
}
if (is_onehot && optimize_onehot)
{
print_choices();
if (!onehot_db.query(sig))
{
log(" failed to detect onehot driver. do not optimize.\n");
}
else
{
log(" optimizing one-hot encoding.\n");
for (auto &it : choices)
{
const Const &val = it.first;
int index = -1;
for (int i = 0; i < GetSize(val); i++)
if (val[i] == State::S1) {
log_assert(index < 0);
index = i;
}
if (index < 0) {
log(" %3d: zero encoding.\n", it.second);
continue;
}
SigBit new_ctrl = sig[index];
log(" %3d: new crtl signal is %s.\n", it.second, log_signal(new_ctrl));
updated_S[it.second] = new_ctrl;
}
}
seldb.erase(sig);
continue;
}
// find the best permutation
vector<int> perm_new_from_old(GetSize(sig));
Const perm_xormask(State::S0, GetSize(sig));
{
vector<int> values(GetSize(choices));
vector<bool> used_src_columns(GetSize(sig));
vector<vector<bool>> columns(GetSize(sig), vector<bool>(GetSize(values)));
for (int i = 0; i < GetSize(choices); i++) {
Const val = choices.element(i)->first;
for (int k = 0; k < GetSize(val); k++)
if (val[k] == State::S1)
columns[k][i] = true;
}
for (int dst_col = GetSize(sig)-1; dst_col >= 0; dst_col--)
{
int best_src_col = -1;
bool best_inv = false;
int best_maxval = 0;
int best_delta = 0;
// find best src column for this dst column
for (int src_col = 0; src_col < GetSize(sig); src_col++)
{
if (used_src_columns[src_col])
continue;
int this_maxval = 0;
int this_minval = 1 << 30;
int this_inv_maxval = 0;
int this_inv_minval = 1 << 30;
for (int i = 0; i < GetSize(values); i++)
{
int val = values[i];
int inv_val = val;
if (columns[src_col][i])
val |= 1 << dst_col;
else
inv_val |= 1 << dst_col;
this_maxval = std::max(this_maxval, val);
this_minval = std::min(this_minval, val);
this_inv_maxval = std::max(this_inv_maxval, inv_val);
this_inv_minval = std::min(this_inv_minval, inv_val);
}
int this_delta = this_maxval - this_minval;
int this_inv_delta = this_maxval - this_minval;
bool this_inv = false;
if (this_delta != this_inv_delta)
this_inv = this_inv_delta < this_delta;
else if (this_maxval != this_inv_maxval)
this_inv = this_inv_maxval < this_maxval;
if (this_inv) {
this_delta = this_inv_delta;
this_maxval = this_inv_maxval;
this_minval = this_inv_minval;
}
bool this_is_better = false;
if (best_src_col < 0)
this_is_better = true;
else if (this_delta != best_delta)
this_is_better = this_delta < best_delta;
else if (this_maxval != best_maxval)
this_is_better = this_maxval < best_maxval;
else
this_is_better = sig[best_src_col] < sig[src_col];
if (this_is_better) {
best_src_col = src_col;
best_inv = this_inv;
best_maxval = this_maxval;
best_delta = this_delta;
}
}
used_src_columns[best_src_col] = true;
perm_new_from_old[dst_col] = best_src_col;
perm_xormask[dst_col] = best_inv ? State::S1 : State::S0;
}
}
// permutated sig
SigSpec perm_sig(State::S0, GetSize(sig));
for (int i = 0; i < GetSize(sig); i++)
perm_sig[i] = sig[perm_new_from_old[i]];
log(" best permutation: %s\n", log_signal(perm_sig));
log(" best xor mask: %s\n", log_signal(perm_xormask));
// permutated choices
int min_choice = 1 << 30;
int max_choice = -1;
dict<Const, int> perm_choices;
for (auto &it : choices)
{
Const &old_c = it.first;
Const new_c(State::S0, GetSize(old_c));
for (int i = 0; i < GetSize(old_c); i++)
new_c[i] = old_c[perm_new_from_old[i]];
Const new_c_before_xor = new_c;
new_c = const_xor(new_c, perm_xormask, false, false, GetSize(new_c));
perm_choices[new_c] = it.second;
min_choice = std::min(min_choice, new_c.as_int());
max_choice = std::max(max_choice, new_c.as_int());
log(" %3d: %s -> %s -> %s: %s\n", it.second, log_signal(old_c), log_signal(new_c_before_xor),
log_signal(new_c), log_signal(B.extract(it.second*width, width)));
}
int range_density = 100*GetSize(choices) / (max_choice-min_choice+1);
int absolute_density = 100*GetSize(choices) / (max_choice+1);
log(" choices: %d\n", GetSize(choices));
log(" min choice: %d\n", min_choice);
log(" max choice: %d\n", max_choice);
log(" range density: %d%%\n", range_density);
log(" absolute density: %d%%\n", absolute_density);
if (full_pmux) {
int full_density = 100*GetSize(choices) / (1 << GetSize(sig));
log(" full density: %d%%\n", full_density);
if (full_density < min_density) {
full_pmux = false;
} else {
min_choice = 0;
max_choice = (1 << GetSize(sig))-1;
log(" update to full case.\n");
log(" new min choice: %d\n", min_choice);
log(" new max choice: %d\n", max_choice);
}
}
bool full_case = (min_choice == 0) && (max_choice == (1 << GetSize(sig))-1) && (full_pmux || max_choice+1 == GetSize(choices));
log(" full case: %s\n", full_case ? "true" : "false");
// check density percentages
Const offset(State::S0, GetSize(sig));
if (absolute_density < min_density && range_density >= min_density)
{
offset = Const(min_choice, GetSize(sig));
log(" offset: %s\n", log_signal(offset));
min_choice -= offset.as_int();
max_choice -= offset.as_int();
dict<Const, int> new_perm_choices;
for (auto &it : perm_choices)
new_perm_choices[const_sub(it.first, offset, false, false, GetSize(sig))] = it.second;
perm_choices.swap(new_perm_choices);
} else
if (absolute_density < min_density) {
log(" insufficient density.\n");
seldb.erase(sig);
continue;
}
// creat cmp signal
SigSpec cmp = perm_sig;
if (perm_xormask.as_bool())
cmp = module->Xor(NEW_ID, cmp, perm_xormask, false, src);
if (offset.as_bool())
cmp = module->Sub(NEW_ID, cmp, offset, false, src);
// create enable signal
SigBit en = State::S1;
if (!full_case) {
Const enable_mask(State::S0, max_choice+1);
for (auto &it : perm_choices)
enable_mask[it.first.as_int()] = State::S1;
en = module->addWire(NEW_ID);
module->addShift(NEW_ID, enable_mask, cmp, en, false, src);
}
// create data signal
SigSpec data(State::Sx, (max_choice+1)*extwidth);
if (full_pmux) {
for (int i = 0; i <= max_choice; i++)
data.replace(i*extwidth, A);
}
for (auto &it : perm_choices) {
int position = it.first.as_int()*extwidth;
int data_index = it.second;
data.replace(position, B.extract(data_index*width, width));
updated_S[data_index] = State::S0;
updated_B.replace(data_index*width, SigSpec(State::Sx, width));
}
// create shiftx cell
SigSpec shifted_cmp = {cmp, SigSpec(State::S0, width_bits)};
SigSpec outsig = module->addWire(NEW_ID, width);
Cell *c = module->addShiftx(NEW_ID, data, shifted_cmp, outsig, false, src);
updated_S.append(en);
updated_B.append(outsig);
log(" created $shiftx cell %s.\n", log_id(c));
// remove this sig and continue with the next block
seldb.erase(sig);
}
// update $pmux cell
cell->setPort("\\S", updated_S);
cell->setPort("\\B", updated_B);
cell->setParam("\\S_WIDTH", GetSize(updated_S));
}
}
}
} Pmux2ShiftxPass;
struct OnehotPass : public Pass {
OnehotPass() : Pass("onehot", "optimize $eq cells for onehot signals") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" onehot [options] [selection]\n");
log("\n");
log("This pass optimizes $eq cells that compare one-hot signals against constants\n");
log("\n");
log(" -v, -vv\n");
log(" verbose output\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool verbose = false;
bool verbose_onehot = false;
log_header(design, "Executing ONEHOT pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-v") {
verbose = true;
continue;
}
if (args[argidx] == "-vv") {
verbose = true;
verbose_onehot = true;
continue;
}
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
OnehotDatabase onehot_db(module, sigmap);
onehot_db.verbose = verbose_onehot;
for (auto cell : module->selected_cells())
{
if (cell->type != "$eq")
continue;
SigSpec A = sigmap(cell->getPort("\\A"));
SigSpec B = sigmap(cell->getPort("\\B"));
int a_width = cell->getParam("\\A_WIDTH").as_int();
int b_width = cell->getParam("\\B_WIDTH").as_int();
if (a_width < b_width) {
bool a_signed = cell->getParam("\\A_SIGNED").as_int();
A.extend_u0(b_width, a_signed);
}
if (b_width < a_width) {
bool b_signed = cell->getParam("\\B_SIGNED").as_int();
B.extend_u0(a_width, b_signed);
}
if (A.is_fully_const())
std::swap(A, B);
if (!B.is_fully_const())
continue;
if (verbose)
log("Checking $eq(%s, %s) cell %s/%s.\n", log_signal(A), log_signal(B), log_id(module), log_id(cell));
if (!onehot_db.query(A)) {
if (verbose)
log(" onehot driver test on %s failed.\n", log_signal(A));
continue;
}
int index = -1;
bool not_onehot = false;
for (int i = 0; i < GetSize(B); i++) {
if (B[i] != State::S1)
continue;
if (index >= 0)
not_onehot = true;
index = i;
}
if (index < 0) {
if (verbose)
log(" not optimizing the zero pattern.\n");
continue;
}
SigSpec Y = cell->getPort("\\Y");
if (not_onehot)
{
if (verbose)
log(" replacing with constant 0 driver.\n");
else
log("Replacing one-hot $eq(%s, %s) cell %s/%s with constant 0 driver.\n", log_signal(A), log_signal(B), log_id(module), log_id(cell));
module->connect(Y, SigSpec(1, GetSize(Y)));
}
else
{
SigSpec sig = A[index];
if (verbose)
log(" replacing with signal %s.\n", log_signal(sig));
else
log("Replacing one-hot $eq(%s, %s) cell %s/%s with signal %s.\n",log_signal(A), log_signal(B), log_id(module), log_id(cell), log_signal(sig));
sig.extend_u0(GetSize(Y));
module->connect(Y, sig);
}
module->remove(cell);
}
}
}
} OnehotPass;
PRIVATE_NAMESPACE_END

View File

@ -462,12 +462,10 @@ struct WreduceWorker
SigSpec initsig = init_attr_sigmap(w); SigSpec initsig = init_attr_sigmap(w);
int width = std::min(GetSize(initval), GetSize(initsig)); int width = std::min(GetSize(initval), GetSize(initsig));
for (int i = 0; i < width; i++) { for (int i = 0; i < width; i++) {
log_dump(initsig[i], remove_init_bits.count(initsig[i]));
if (!remove_init_bits.count(initsig[i])) if (!remove_init_bits.count(initsig[i]))
new_initval[i] = initval[i]; new_initval[i] = initval[i];
} }
w->attributes.at("\\init") = new_initval; w->attributes.at("\\init") = new_initval;
log_dump(w->name, initval, new_initval);
} }
} }
} }

View File

@ -83,8 +83,8 @@ They are declared like state variables, just using the `udata` statement:
udata <int> min_data_width max_data_width udata <int> min_data_width max_data_width
udata <IdString> data_port_name udata <IdString> data_port_name
They are atomatically initialzed to the default constructed value of their type They are automatically initialized to the default constructed value of their type
when ther pattern matcher object is constructed. when the pattern matcher object is constructed.
Embedded C++ code Embedded C++ code
----------------- -----------------
@ -158,7 +158,7 @@ Finally, `filter <expression>` narrows down the remaining list of cells. For
performance reasons `filter` statements should only be used for things that performance reasons `filter` statements should only be used for things that
can't be done using `select` and `index`. can't be done using `select` and `index`.
The `optional` statement marks optional matches. I.e. the matcher will also The `optional` statement marks optional matches. That is, the matcher will also
explore the case where `mul` is set to `nullptr`. Without the `optional` explore the case where `mul` is set to `nullptr`. Without the `optional`
statement a match may only be assigned nullptr when one of the `if` expressions statement a match may only be assigned nullptr when one of the `if` expressions
evaluates to `false`. evaluates to `false`.
@ -220,5 +220,5 @@ But in some cases it is more natural to utilize the implicit branch statement:
portAB = \B; portAB = \B;
endcode endcode
There is an implicit `code..endcode` block at the end of each `.pgm` file There is an implicit `code..endcode` block at the end of each `.pmg` file
that just accepts everything that gets all the way there. that just accepts everything that gets all the way there.

View File

@ -108,6 +108,7 @@ struct SigSnippets
struct SnippetSwCache struct SnippetSwCache
{ {
dict<RTLIL::SwitchRule*, pool<RTLIL::SigBit>, hash_ptr_ops> full_case_bits_cache;
dict<RTLIL::SwitchRule*, pool<int>, hash_ptr_ops> cache; dict<RTLIL::SwitchRule*, pool<int>, hash_ptr_ops> cache;
const SigSnippets *snippets; const SigSnippets *snippets;
int current_snippet; int current_snippet;
@ -268,6 +269,49 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve
last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size(); last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size();
} }
const pool<SigBit> &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRule *sw)
{
if (!swcache.full_case_bits_cache.count(sw))
{
pool<SigBit> bits;
if (sw->get_bool_attribute("\\full_case"))
{
bool first_case = true;
for (auto cs : sw->cases)
{
pool<SigBit> case_bits;
for (auto it : cs->actions) {
for (auto bit : it.first)
case_bits.insert(bit);
}
for (auto it : cs->switches) {
for (auto bit : get_full_case_bits(swcache, it))
case_bits.insert(bit);
}
if (first_case) {
first_case = false;
bits = case_bits;
} else {
pool<SigBit> new_bits;
for (auto bit : bits)
if (case_bits.count(bit))
new_bits.insert(bit);
bits.swap(new_bits);
}
}
}
bits.swap(swcache.full_case_bits_cache[sw]);
}
return swcache.full_case_bits_cache.at(sw);
}
RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara, RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara,
RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode) RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode)
{ {
@ -337,6 +381,12 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
} }
} }
// mask default bits that are irrelevant because the output is driven by a full case
const pool<SigBit> &full_case_bits = get_full_case_bits(swcache, sw);
for (int i = 0; i < GetSize(sig); i++)
if (full_case_bits.count(sig[i]))
result[i] = State::Sx;
// evaluate in reverse order to give the first entry the top priority // evaluate in reverse order to give the first entry the top priority
RTLIL::SigSpec initial_val = result; RTLIL::SigSpec initial_val = result;
RTLIL::Cell *last_mux_cell = NULL; RTLIL::Cell *last_mux_cell = NULL;

View File

@ -28,7 +28,7 @@
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
void proc_rmdead(RTLIL::SwitchRule *sw, int &counter) void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
{ {
BitPatternPool pool(sw->signal); BitPatternPool pool(sw->signal);
@ -56,11 +56,16 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
} }
for (auto switch_it : sw->cases[i]->switches) for (auto switch_it : sw->cases[i]->switches)
proc_rmdead(switch_it, counter); proc_rmdead(switch_it, counter, full_case_counter);
if (is_default) if (is_default)
pool.take_all(); pool.take_all();
} }
if (pool.empty() && !sw->get_bool_attribute("\\full_case")) {
sw->set_bool_attribute("\\full_case");
full_case_counter++;
}
} }
struct ProcRmdeadPass : public Pass { struct ProcRmdeadPass : public Pass {
@ -87,12 +92,15 @@ struct ProcRmdeadPass : public Pass {
for (auto &proc_it : mod->processes) { for (auto &proc_it : mod->processes) {
if (!design->selected(mod, proc_it.second)) if (!design->selected(mod, proc_it.second))
continue; continue;
int counter = 0; int counter = 0, full_case_counter = 0;
for (auto switch_it : proc_it.second->root_case.switches) for (auto switch_it : proc_it.second->root_case.switches)
proc_rmdead(switch_it, counter); proc_rmdead(switch_it, counter, full_case_counter);
if (counter > 0) if (counter > 0)
log("Removed %d dead cases from process %s in module %s.\n", counter, log("Removed %d dead cases from process %s in module %s.\n", counter,
proc_it.first.c_str(), log_id(mod)); log_id(proc_it.first), log_id(mod));
if (full_case_counter > 0)
log("Marked %d switch rules as full_case in process %s in module %s.\n",
full_case_counter, log_id(proc_it.first), log_id(mod));
total_counter += counter; total_counter += counter;
} }
} }

View File

@ -254,7 +254,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL:
if (flag_flatten) { if (flag_flatten) {
log_push(); log_push();
Pass::call_on_module(design, miter_module, "flatten; opt_expr -keepdc -undriven;;"); Pass::call_on_module(design, miter_module, "flatten -wb; opt_expr -keepdc -undriven;;");
log_pop(); log_pop();
} }
} }
@ -308,7 +308,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
if (flag_flatten) { if (flag_flatten) {
log_push(); log_push();
Pass::call_on_module(design, module, "flatten;;"); Pass::call_on_module(design, module, "flatten -wb;;");
log_pop(); log_pop();
} }
@ -385,7 +385,7 @@ struct MiterPass : public Pass {
log(" also create an 'assert' cell that checks if trigger is always low.\n"); log(" also create an 'assert' cell that checks if trigger is always low.\n");
log("\n"); log("\n");
log(" -flatten\n"); log(" -flatten\n");
log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); log(" call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n"); log("\n");
log("\n"); log("\n");
log(" miter -assert [options] module [miter_name]\n"); log(" miter -assert [options] module [miter_name]\n");
@ -399,7 +399,7 @@ struct MiterPass : public Pass {
log(" keep module output ports.\n"); log(" keep module output ports.\n");
log("\n"); log("\n");
log(" -flatten\n"); log(" -flatten\n");
log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); log(" call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n"); log("\n");
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE

View File

@ -934,6 +934,32 @@ struct MutatePass : public Pass {
return; return;
} }
if (opts.module.empty())
log_cmd_error("Missing -module argument.\n");
Module *module = design->module(opts.module);
if (module == nullptr)
log_cmd_error("Module %s not found.\n", log_id(opts.module));
if (opts.cell.empty())
log_cmd_error("Missing -cell argument.\n");
Cell *cell = module->cell(opts.cell);
if (cell == nullptr)
log_cmd_error("Cell %s not found in module %s.\n", log_id(opts.cell), log_id(opts.module));
if (opts.port.empty())
log_cmd_error("Missing -port argument.\n");
if (!cell->hasPort(opts.port))
log_cmd_error("Port %s not found on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell));
if (opts.portbit < 0)
log_cmd_error("Missing -portbit argument.\n");
if (GetSize(cell->getPort(opts.port)) <= opts.portbit)
log_cmd_error("Out-of-range -portbit argument for port %s on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell));
if (opts.mode == "inv") { if (opts.mode == "inv") {
mutate_inv(design, opts); mutate_inv(design, opts);
return; return;
@ -944,6 +970,12 @@ struct MutatePass : public Pass {
return; return;
} }
if (opts.ctrlbit < 0)
log_cmd_error("Missing -ctrlbit argument.\n");
if (GetSize(cell->getPort(opts.port)) <= opts.ctrlbit)
log_cmd_error("Out-of-range -ctrlbit argument for port %s on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell));
if (opts.mode == "cnot0" || opts.mode == "cnot1") { if (opts.mode == "cnot0" || opts.mode == "cnot1") {
mutate_cnot(design, opts, opts.mode == "cnot1"); mutate_cnot(design, opts, opts.mode == "cnot1");
return; return;

View File

@ -29,17 +29,17 @@
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025 // Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
// http://en.wikipedia.org/wiki/Topological_sorting // http://en.wikipedia.org/wiki/Topological_sorting
#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" #define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p" #define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2" #define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; if; mfs2"
#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}" #define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; cover {I} {P}"
#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" #define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}" #define ABC_FAST_COMMAND_LIB "strash; dretime; retime {D}; map {D}"
#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" #define ABC_FAST_COMMAND_CTR "strash; dretime; retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_FAST_COMMAND_LUT "strash; dretime; if" #define ABC_FAST_COMMAND_LUT "strash; dretime; retime {D}; if"
#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}" #define ABC_FAST_COMMAND_SOP "strash; dretime; retime {D}; cover -I {I} -P {P}"
#define ABC_FAST_COMMAND_DFL "strash; dretime; map" #define ABC_FAST_COMMAND_DFL "strash; dretime; retime {D}; map"
#include "kernel/register.h" #include "kernel/register.h"
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
@ -331,19 +331,23 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp
{ {
std::string abc_sname = abc_name.substr(1); std::string abc_sname = abc_name.substr(1);
if (abc_sname.substr(0, 5) == "ys__n") { if (abc_sname.substr(0, 5) == "ys__n") {
int sid = std::stoi(abc_sname.substr(5));
bool inv = abc_sname.back() == 'v'; bool inv = abc_sname.back() == 'v';
for (auto sig : signal_list) { if (inv) abc_sname.pop_back();
if (sig.id == sid && sig.bit.wire != nullptr) { abc_sname.erase(0, 5);
std::stringstream sstr; if (abc_sname.find_last_not_of("012345689") == std::string::npos) {
sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); int sid = std::stoi(abc_sname);
if (sig.bit.wire->width != 1) for (auto sig : signal_list) {
sstr << "[" << sig.bit.offset << "]"; if (sig.id == sid && sig.bit.wire != nullptr) {
if (inv) std::stringstream sstr;
sstr << "_inv"; sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
if (orig_wire != nullptr) if (sig.bit.wire->width != 1)
*orig_wire = sig.bit.wire; sstr << "[" << sig.bit.offset << "]";
return sstr.str(); if (inv)
sstr << "_inv";
if (orig_wire != nullptr)
*orig_wire = sig.bit.wire;
return sstr.str();
}
} }
} }
} }
@ -731,10 +735,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
else else
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
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))
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);
@ -1726,7 +1726,7 @@ struct AbcPass : public Pass {
signal_init[initsig[i]] = State::S0; signal_init[initsig[i]] = State::S0;
break; break;
case State::S1: case State::S1:
signal_init[initsig[i]] = State::S0; signal_init[initsig[i]] = State::S1;
break; break;
default: default:
break; break;

View File

@ -111,9 +111,10 @@ struct AttrmapMap : AttrmapAction {
}; };
struct AttrmapRemove : AttrmapAction { struct AttrmapRemove : AttrmapAction {
bool has_value;
string name, value; string name, value;
bool apply(IdString &id, Const &val) YS_OVERRIDE { bool apply(IdString &id, Const &val) YS_OVERRIDE {
return !(match_name(name, id) && match_value(value, val)); return !(match_name(name, id) && (!has_value || match_value(value, val)));
} }
}; };
@ -235,6 +236,7 @@ struct AttrmapPass : public Pass {
} }
auto action = new AttrmapRemove; auto action = new AttrmapRemove;
action->name = arg1; action->name = arg1;
action->has_value = (p != string::npos);
action->value = val1; action->value = val1;
actions.push_back(std::unique_ptr<AttrmapAction>(action)); actions.push_back(std::unique_ptr<AttrmapAction>(action));
continue; continue;

View File

@ -664,7 +664,7 @@ struct DfflibmapPass : public Pass {
logmap_all(); logmap_all();
for (auto &it : design->modules_) for (auto &it : design->modules_)
if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox")) if (design->selected(it.second) && !it.second->get_blackbox_attribute())
dfflibmap(design, it.second, prepare_mode); dfflibmap(design, it.second, prepare_mode);
cell_mappings.clear(); cell_mappings.clear();

View File

@ -71,9 +71,9 @@ struct PmuxtreePass : public Pass {
{ {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n"); log("\n");
log(" pmuxtree [options] [selection]\n"); log(" pmuxtree [selection]\n");
log("\n"); log("\n");
log("This pass transforms $pmux cells to a trees of $mux cells.\n"); log("This pass transforms $pmux cells to trees of $mux cells.\n");
log("\n"); log("\n");
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE

View File

@ -26,7 +26,9 @@ PRIVATE_NAMESPACE_BEGIN
struct ShregmapTech struct ShregmapTech
{ {
virtual ~ShregmapTech() { } virtual ~ShregmapTech() { }
virtual bool analyze(vector<int> &taps) = 0; virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {}
virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {}
virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) = 0;
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0; virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
}; };
@ -54,7 +56,7 @@ struct ShregmapOptions
struct ShregmapTechGreenpak4 : ShregmapTech struct ShregmapTechGreenpak4 : ShregmapTech
{ {
bool analyze(vector<int> &taps) bool analyze(vector<int> &taps, const vector<SigBit> &/*qbits*/)
{ {
if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) { if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
taps.clear(); taps.clear();
@ -91,6 +93,145 @@ struct ShregmapTechGreenpak4 : ShregmapTech
} }
}; };
struct ShregmapTechXilinx7 : ShregmapTech
{
dict<SigBit, std::tuple<Cell*,int,int>> sigbit_to_shiftx_offset;
const ShregmapOptions &opts;
ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {}
virtual void init(const Module* module, const SigMap &sigmap) override
{
for (const auto &i : module->cells_) {
auto cell = i.second;
if (cell->type == "$shiftx") {
if (cell->getParam("\\Y_WIDTH") != 1) continue;
int j = 0;
for (auto bit : sigmap(cell->getPort("\\A")))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0);
log_assert(j == cell->getParam("\\A_WIDTH").as_int());
}
else if (cell->type == "$mux") {
int j = 0;
for (auto bit : sigmap(cell->getPort("\\A")))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
j = 0;
for (auto bit : sigmap(cell->getPort("\\B")))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++);
}
}
}
virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override
{
auto it = sigbit_to_shiftx_offset.find(bit);
if (it == sigbit_to_shiftx_offset.end())
return;
if (cell) {
if (cell->type == "$shiftx" && port == "\\A")
return;
if (cell->type == "$mux" && (port == "\\A" || port == "\\B"))
return;
}
sigbit_to_shiftx_offset.erase(it);
}
virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) override
{
if (GetSize(taps) == 1)
return taps[0] >= opts.minlen-1 && sigbit_to_shiftx_offset.count(qbits[0]);
if (taps.back() < opts.minlen-1)
return false;
Cell *shiftx = nullptr;
int group = 0;
for (int i = 0; i < GetSize(taps); ++i) {
auto it = sigbit_to_shiftx_offset.find(qbits[i]);
if (it == sigbit_to_shiftx_offset.end())
return false;
// Check taps are sequential
if (i != taps[i])
return false;
// Check taps are not connected to a shift register,
// or sequential to the same shift register
if (i == 0) {
int offset;
std::tie(shiftx,offset,group) = it->second;
if (offset != i)
return false;
}
else {
Cell *shiftx_ = std::get<0>(it->second);
if (shiftx_ != shiftx)
return false;
int offset = std::get<1>(it->second);
if (offset != i)
return false;
int group_ = std::get<2>(it->second);
if (group_ != group)
return false;
}
}
log_assert(shiftx);
// Only map if $shiftx exclusively covers the shift register
if (shiftx->type == "$shiftx") {
if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int())
return false;
}
else if (shiftx->type == "$mux") {
if (GetSize(taps) != 2)
return false;
}
else log_abort();
return true;
}
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) override
{
const auto &tap = *taps.begin();
auto bit = tap.second;
auto it = sigbit_to_shiftx_offset.find(bit);
log_assert(it != sigbit_to_shiftx_offset.end());
auto newcell = cell->module->addCell(NEW_ID, "$__XILINX_SHREG_");
newcell->set_src_attribute(cell->get_src_attribute());
newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH"));
newcell->setParam("\\INIT", cell->getParam("\\INIT"));
newcell->setParam("\\CLKPOL", cell->getParam("\\CLKPOL"));
newcell->setParam("\\ENPOL", cell->getParam("\\ENPOL"));
newcell->setPort("\\C", cell->getPort("\\C"));
newcell->setPort("\\D", cell->getPort("\\D"));
if (cell->hasPort("\\E"))
newcell->setPort("\\E", cell->getPort("\\E"));
Cell* shiftx = std::get<0>(it->second);
RTLIL::SigSpec l_wire, q_wire;
if (shiftx->type == "$shiftx") {
l_wire = shiftx->getPort("\\B");
q_wire = shiftx->getPort("\\Y");
shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
}
else if (shiftx->type == "$mux") {
l_wire = shiftx->getPort("\\S");
q_wire = shiftx->getPort("\\Y");
shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
}
else log_abort();
newcell->setPort("\\Q", q_wire);
newcell->setPort("\\L", l_wire);
return false;
}
};
struct ShregmapWorker struct ShregmapWorker
{ {
Module *module; Module *module;
@ -113,8 +254,10 @@ struct ShregmapWorker
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
if (wire->port_output || wire->get_bool_attribute("\\keep")) { if (wire->port_output || wire->get_bool_attribute("\\keep")) {
for (auto bit : sigmap(wire)) for (auto bit : sigmap(wire)) {
sigbit_with_non_chain_users.insert(bit); sigbit_with_non_chain_users.insert(bit);
if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {});
}
} }
if (wire->attributes.count("\\init")) { if (wire->attributes.count("\\init")) {
@ -152,8 +295,10 @@ struct ShregmapWorker
for (auto conn : cell->connections()) for (auto conn : cell->connections())
if (cell->input(conn.first)) if (cell->input(conn.first))
for (auto bit : sigmap(conn.second)) for (auto bit : sigmap(conn.second)) {
sigbit_with_non_chain_users.insert(bit); sigbit_with_non_chain_users.insert(bit);
if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first);
}
} }
} }
@ -258,7 +403,7 @@ struct ShregmapWorker
if (taps.empty() || taps.back() < depth-1) if (taps.empty() || taps.back() < depth-1)
taps.push_back(depth-1); taps.push_back(depth-1);
if (opts.tech->analyze(taps)) if (opts.tech->analyze(taps, qbits))
break; break;
taps.pop_back(); taps.pop_back();
@ -377,6 +522,9 @@ struct ShregmapWorker
ShregmapWorker(Module *module, const ShregmapOptions &opts) : ShregmapWorker(Module *module, const ShregmapOptions &opts) :
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
{ {
if (opts.tech)
opts.tech->init(module, sigmap);
make_sigbit_chain_next_prev(); make_sigbit_chain_next_prev();
find_chain_start_cells(); find_chain_start_cells();
@ -501,6 +649,12 @@ struct ShregmapPass : public Pass {
clkpol = "pos"; clkpol = "pos";
opts.zinit = true; opts.zinit = true;
opts.tech = new ShregmapTechGreenpak4; opts.tech = new ShregmapTechGreenpak4;
}
else if (tech == "xilinx") {
opts.init = true;
opts.params = true;
enpol = "any_or_none";
opts.tech = new ShregmapTechXilinx7(opts);
} else { } else {
argidx--; argidx--;
break; break;

View File

@ -599,7 +599,7 @@ struct SimplemapPass : public Pass {
simplemap_get_mappers(mappers); simplemap_get_mappers(mappers);
for (auto mod : design->modules()) { for (auto mod : design->modules()) {
if (!design->selected(mod)) if (!design->selected(mod) || mod->get_blackbox_attribute())
continue; continue;
std::vector<RTLIL::Cell*> cells = mod->cells(); std::vector<RTLIL::Cell*> cells = mod->cells();
for (auto cell : cells) { for (auto cell : cells) {

View File

@ -72,6 +72,8 @@ struct TechmapWorker
pool<IdString> flatten_done_list; pool<IdString> flatten_done_list;
pool<Cell*> flatten_keep_list; pool<Cell*> flatten_keep_list;
pool<string> log_msg_cache;
struct TechmapWireData { struct TechmapWireData {
RTLIL::Wire *wire; RTLIL::Wire *wire;
RTLIL::SigSpec value; RTLIL::SigSpec value;
@ -84,6 +86,7 @@ struct TechmapWorker
bool flatten_mode; bool flatten_mode;
bool recursive_mode; bool recursive_mode;
bool autoproc_mode; bool autoproc_mode;
bool ignore_wb;
TechmapWorker() TechmapWorker()
{ {
@ -92,6 +95,7 @@ struct TechmapWorker
flatten_mode = false; flatten_mode = false;
recursive_mode = false; recursive_mode = false;
autoproc_mode = false; autoproc_mode = false;
ignore_wb = false;
} }
std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose) std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose)
@ -383,11 +387,12 @@ struct TechmapWorker
{ {
std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping";
if (!design->selected(module)) if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb))
return false; return false;
bool log_continue = false; bool log_continue = false;
bool did_something = false; bool did_something = false;
LogMakeDebugHdl mkdebug;
SigMap sigmap(module); SigMap sigmap(module);
@ -472,7 +477,7 @@ struct TechmapWorker
RTLIL::Module *tpl = map->modules_[tpl_name]; RTLIL::Module *tpl = map->modules_[tpl_name];
std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end()); std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end());
if (tpl->get_bool_attribute("\\blackbox")) if (tpl->get_blackbox_attribute(ignore_wb))
continue; continue;
if (!flatten_mode) if (!flatten_mode)
@ -545,6 +550,7 @@ struct TechmapWorker
if (extmapper_name == "wrap") { if (extmapper_name == "wrap") {
std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string(); std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string();
log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module)); log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module));
mkdebug.on();
Pass::call_on_module(extmapper_design, extmapper_module, cmd_string); Pass::call_on_module(extmapper_design, extmapper_module, cmd_string);
log_continue = true; log_continue = true;
} }
@ -558,11 +564,21 @@ struct TechmapWorker
goto use_wrapper_tpl; goto use_wrapper_tpl;
} }
log("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); auto msg = stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type));
if (!log_msg_cache.count(msg)) {
log_msg_cache.insert(msg);
log("%s\n", msg.c_str());
}
log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module));
} }
else else
{ {
log("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); auto msg = stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type));
if (!log_msg_cache.count(msg)) {
log_msg_cache.insert(msg);
log("%s\n", msg.c_str());
}
log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str());
if (extmapper_name == "simplemap") { if (extmapper_name == "simplemap") {
if (simplemap_mappers.count(cell->type) == 0) if (simplemap_mappers.count(cell->type) == 0)
@ -660,6 +676,7 @@ struct TechmapWorker
tpl = techmap_cache[key]; tpl = techmap_cache[key];
} else { } else {
if (parameters.size() != 0) { if (parameters.size() != 0) {
mkdebug.on();
derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end())); derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end()));
tpl = map->module(derived_name); tpl = map->module(derived_name);
log_continue = true; log_continue = true;
@ -829,6 +846,7 @@ struct TechmapWorker
if (log_continue) { if (log_continue) {
log_header(design, "Continuing TECHMAP pass.\n"); log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false; log_continue = false;
mkdebug.off();
} }
while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { }
} }
@ -840,6 +858,7 @@ struct TechmapWorker
if (log_continue) { if (log_continue) {
log_header(design, "Continuing TECHMAP pass.\n"); log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false; log_continue = false;
mkdebug.off();
} }
if (extern_mode && !in_recursion) if (extern_mode && !in_recursion)
@ -859,13 +878,18 @@ struct TechmapWorker
module_queue.insert(m); module_queue.insert(m);
} }
log("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); log_debug("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name));
cell->type = m_name; cell->type = m_name;
cell->parameters.clear(); cell->parameters.clear();
} }
else else
{ {
log("%s %s.%s using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(tpl)); auto msg = stringf("Using template %s for cells of type %s.", log_id(tpl), log_id(cell->type));
if (!log_msg_cache.count(msg)) {
log_msg_cache.insert(msg);
log("%s\n", msg.c_str());
}
log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl));
techmap_module_worker(design, module, cell, tpl); techmap_module_worker(design, module, cell, tpl);
cell = NULL; cell = NULL;
} }
@ -883,6 +907,7 @@ struct TechmapWorker
if (log_continue) { if (log_continue) {
log_header(design, "Continuing TECHMAP pass.\n"); log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false; log_continue = false;
mkdebug.off();
} }
return did_something; return did_something;
@ -925,6 +950,9 @@ struct TechmapPass : public Pass {
log(" -autoproc\n"); log(" -autoproc\n");
log(" Automatically call \"proc\" on implementations that contain processes.\n"); log(" Automatically call \"proc\" on implementations that contain processes.\n");
log("\n"); log("\n");
log(" -wb\n");
log(" Ignore the 'whitebox' attribute on cell implementations.\n");
log("\n");
log(" -assert\n"); log(" -assert\n");
log(" this option will cause techmap to exit with an error if it can't map\n"); log(" this option will cause techmap to exit with an error if it can't map\n");
log(" a selected cell. only cell types that end on an underscore are accepted\n"); log(" a selected cell. only cell types that end on an underscore are accepted\n");
@ -1031,7 +1059,7 @@ struct TechmapPass : public Pass {
simplemap_get_mappers(worker.simplemap_mappers); simplemap_get_mappers(worker.simplemap_mappers);
std::vector<std::string> map_files; std::vector<std::string> map_files;
std::string verilog_frontend = "verilog -nooverwrite"; std::string verilog_frontend = "verilog -nooverwrite -noblackbox";
int max_iter = -1; int max_iter = -1;
size_t argidx; size_t argidx;
@ -1068,6 +1096,10 @@ struct TechmapPass : public Pass {
worker.autoproc_mode = true; worker.autoproc_mode = true;
continue; continue;
} }
if (args[argidx] == "-wb") {
worker.ignore_wb = true;
continue;
}
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
@ -1076,7 +1108,7 @@ struct TechmapPass : public Pass {
if (map_files.empty()) { if (map_files.empty()) {
std::istringstream f(stdcells_code); std::istringstream f(stdcells_code);
Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend); Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend);
} else } else {
for (auto &fn : map_files) for (auto &fn : map_files)
if (fn.substr(0, 1) == "%") { if (fn.substr(0, 1) == "%") {
if (!saved_designs.count(fn.substr(1))) { if (!saved_designs.count(fn.substr(1))) {
@ -1095,6 +1127,9 @@ struct TechmapPass : public Pass {
log_cmd_error("Can't open map file `%s'\n", fn.c_str()); log_cmd_error("Can't open map file `%s'\n", fn.c_str());
Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend); Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
} }
}
log_header(design, "Continuing TECHMAP pass.\n");
std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
for (auto &it : map->modules_) { for (auto &it : map->modules_) {
@ -1145,7 +1180,7 @@ struct FlattenPass : public Pass {
{ {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n"); log("\n");
log(" flatten [selection]\n"); log(" flatten [options] [selection]\n");
log("\n"); log("\n");
log("This pass flattens the design by replacing cells by their implementation. This\n"); log("This pass flattens the design by replacing cells by their implementation. This\n");
log("pass is very similar to the 'techmap' pass. The only difference is that this\n"); log("pass is very similar to the 'techmap' pass. The only difference is that this\n");
@ -1154,17 +1189,29 @@ struct FlattenPass : public Pass {
log("Cells and/or modules with the 'keep_hierarchy' attribute set will not be\n"); log("Cells and/or modules with the 'keep_hierarchy' attribute set will not be\n");
log("flattened by this command.\n"); log("flattened by this command.\n");
log("\n"); log("\n");
log(" -wb\n");
log(" Ignore the 'whitebox' attribute on cell implementations.\n");
log("\n");
} }
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 FLATTEN pass (flatten design).\n"); log_header(design, "Executing FLATTEN pass (flatten design).\n");
log_push(); log_push();
extra_args(args, 1, design);
TechmapWorker worker; TechmapWorker worker;
worker.flatten_mode = true; worker.flatten_mode = true;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-wb") {
worker.ignore_wb = true;
continue;
}
break;
}
extra_args(args, argidx, design);
std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
for (auto module : design->modules()) for (auto module : design->modules())
celltypeMap[module->name].insert(module->name); celltypeMap[module->name].insert(module->name);
@ -1190,6 +1237,7 @@ struct FlattenPass : public Pass {
} }
} }
log_suppressed();
log("No more expansions possible.\n"); log("No more expansions possible.\n");
if (top_mod != NULL) if (top_mod != NULL)
@ -1209,7 +1257,7 @@ struct FlattenPass : public Pass {
dict<RTLIL::IdString, RTLIL::Module*> new_modules; dict<RTLIL::IdString, RTLIL::Module*> new_modules;
for (auto mod : vector<Module*>(design->modules())) for (auto mod : vector<Module*>(design->modules()))
if (used_modules[mod->name] || mod->get_bool_attribute("\\blackbox")) { if (used_modules[mod->name] || mod->get_blackbox_attribute(worker.ignore_wb)) {
new_modules[mod->name] = mod; new_modules[mod->name] = mod;
} else { } else {
log("Deleting now unused module %s.\n", log_id(mod)); log("Deleting now unused module %s.\n", log_id(mod));

View File

@ -1,7 +1,17 @@
OBJS += techlibs/gowin/synth_gowin.o OBJS += techlibs/gowin/synth_gowin.o
OBJS += techlibs/gowin/determine_init.o
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/bram.txt))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/drams_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/dram.txt))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_init3.vh))

29
techlibs/gowin/bram.txt Normal file
View File

@ -0,0 +1,29 @@
bram $__GW1NR_SDP
# uncomment when done
# init 1
abits 10 @a10d18
dbits 16 @a10d18
abits 11 @a11d9
dbits 8 @a11d9
abits 12 @a12d4
dbits 4 @a12d4
abits 13 @a13d2
dbits 2 @a13d2
abits 14 @a14d1
dbits 1 @a14d1
groups 2
ports 1 1
wrmode 1 0
enable 1 1 @a10d18
enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1
transp 0 0
clocks 2 3
clkpol 2 3
endbram
match $__GW1NR_SDP
min bits 2048
min efficiency 5
shuffle_enable B
make_transp
endmatch

View File

@ -0,0 +1,12 @@
localparam [15:0] INIT_0 = {
INIT[ 60], INIT[ 56], INIT[ 52], INIT[ 48], INIT[ 44], INIT[ 40], INIT[ 36], INIT[ 32], INIT[ 28], INIT[ 24], INIT[ 20], INIT[ 16], INIT[ 12], INIT[ 8], INIT[ 4], INIT[ 0]
};
localparam [15:0] INIT_1 = {
INIT[ 61], INIT[ 57], INIT[ 53], INIT[ 49], INIT[ 45], INIT[ 41], INIT[ 37], INIT[ 33], INIT[ 29], INIT[ 25], INIT[ 21], INIT[ 17], INIT[ 13], INIT[ 9], INIT[ 5], INIT[ 1]
};
localparam [15:0] INIT_2 = {
INIT[ 62], INIT[ 58], INIT[ 54], INIT[ 50], INIT[ 46], INIT[ 42], INIT[ 38], INIT[ 34], INIT[ 30], INIT[ 26], INIT[ 22], INIT[ 18], INIT[ 14], INIT[ 10], INIT[ 6], INIT[ 2]
};
localparam [15:0] INIT_3 = {
INIT[ 63], INIT[ 59], INIT[ 55], INIT[ 51], INIT[ 47], INIT[ 43], INIT[ 39], INIT[ 35], INIT[ 31], INIT[ 27], INIT[ 23], INIT[ 19], INIT[ 15], INIT[ 11], INIT[ 7], INIT[ 3]
};

103
techlibs/gowin/brams_map.v Normal file
View File

@ -0,0 +1,103 @@
/* Semi Dual Port (SDP) memory have the following configurations:
* Memory Config RAM(BIT) Port Mode Memory Depth Data Depth
* ----------------|---------| ----------|--------------|------------|
* B-SRAM_16K_SD1 16K 16Kx1 16,384 1
* B-SRAM_8K_SD2 16K 8Kx2 8,192 2
* B-SRAM_4K_SD4 16K 4Kx2 4,096 4
*/
module \$__GW1NR_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
parameter CFG_ABITS = 10;
parameter CFG_DBITS = 16;
parameter CFG_ENABLE_A = 3;
parameter [16383:0] INIT = 16384'hx;
parameter CLKPOL2 = 1;
parameter CLKPOL3 = 1;
input CLK2;
input CLK3;
input [CFG_ABITS-1:0] A1ADDR;
input [CFG_DBITS-1:0] A1DATA;
input [CFG_ENABLE_A-1:0] A1EN;
input [CFG_ABITS-1:0] B1ADDR;
output [CFG_DBITS-1:0] B1DATA;
input B1EN;
generate if (CFG_DBITS == 1) begin
SDP #(
.READ_MODE(0),
.BIT_WIDTH_0(1),
.BIT_WIDTH_1(1),
.BLK_SEL(3'b000),
.RESET_MODE("SYNC")
) _TECHMAP_REPLACE_ (
.CLKA(CLK2), .CLKB(CLK3),
.WREA(A1EN), .OCE(1'b0), .CEA(1'b1),
.WREB(1'b0), .CEB(B1EN),
.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
);
end else if (CFG_DBITS == 2) begin
SDP #(
.READ_MODE(0),
.BIT_WIDTH_0(2),
.BIT_WIDTH_1(2),
.BLK_SEL(3'b000),
.RESET_MODE("SYNC")
) _TECHMAP_REPLACE_ (
.CLKA(CLK2), .CLKB(CLK3),
.WREA(A1EN), .OCE(1'b0), .CEA(1'b1),
.WREB(1'b0), .CEB(B1EN),
.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
);
end else if (CFG_DBITS <= 4) begin
SDP #(
.READ_MODE(0),
.BIT_WIDTH_0(4),
.BIT_WIDTH_1(4),
.BLK_SEL(3'b000),
.RESET_MODE("SYNC")
) _TECHMAP_REPLACE_ (
.CLKA(CLK2), .CLKB(CLK3),
.WREA(A1EN), .OCE(1'b0),
.WREB(1'b0), .CEB(B1EN), .CEA(1'b1),
.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
);
end else if (CFG_DBITS <= 8) begin
SDP #(
.READ_MODE(0),
.BIT_WIDTH_0(8),
.BIT_WIDTH_1(8),
.BLK_SEL(3'b000),
.RESET_MODE("SYNC")
) _TECHMAP_REPLACE_ (
.CLKA(CLK2), .CLKB(CLK3),
.WREA(A1EN), .OCE(1'b0), .CEA(1'b1),
.WREB(1'b0), .CEB(B1EN),
.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
);
end else if (CFG_DBITS <= 16) begin
SDP #(
.READ_MODE(0),
.BIT_WIDTH_0(16),
.BIT_WIDTH_1(16),
.BLK_SEL(3'b000),
.RESET_MODE("SYNC")
) _TECHMAP_REPLACE_ (
.CLKA(CLK2), .CLKB(CLK3),
.WREA(A1EN), .OCE(1'b0),
.WREB(1'b0), .CEB(B1EN), .CEA(1'b1),
.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
);
end else begin
wire TECHMAP_FAIL = 1'b1;
end endgenerate
endmodule

View File

@ -1,5 +1,9 @@
module \$_DFF_N_ (input D, C, output Q); DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule module \$_DFF_N_ (input D, C, output Q); DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule
module \$_DFF_P_ (input D, C, output Q); DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule module \$_DFF_P_ #(parameter INIT = 1'b0) (input D, C, output Q); DFF #(.INIT(INIT)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule
module \$__DFFS_PN0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R)); endmodule
module \$__DFFS_PP0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule
module \$__DFFS_PP1_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule
module \$lut (A, Y); module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;

View File

@ -38,6 +38,17 @@ module DFFN (output reg Q, input CLK, D);
Q <= D; Q <= D;
endmodule endmodule
module DFFR (output reg Q, input D, CLK, RESET);
parameter [0:0] INIT = 1'b0;
initial Q = INIT;
always @(posedge CLK) begin
if (RESET)
Q <= 1'b0;
else
Q <= D;
end
endmodule // DFFR (positive clock edge; synchronous reset)
module VCC(output V); module VCC(output V);
assign V = 1; assign V = 1;
endmodule endmodule
@ -63,3 +74,126 @@ module ALU (input I0, input I1, input I3, input CIN, output COUT, output SUM);
assign {COUT, SUM} = CIN + I1 + I0; assign {COUT, SUM} = CIN + I1 + I0;
endmodule // alu endmodule // alu
module RAM16S4 (DO, DI, AD, WRE, CLK);
parameter WIDTH = 4;
parameter INIT_0 = 16'h0000;
parameter INIT_1 = 16'h0000;
parameter INIT_2 = 16'h0000;
parameter INIT_3 = 16'h0000;
input [WIDTH-1:0] AD;
input [WIDTH-1:0] DI;
output [WIDTH-1:0] DO;
input CLK;
input WRE;
reg [15:0] mem0, mem1, mem2, mem3;
initial begin
mem0 = INIT_0;
mem1 = INIT_1;
mem2 = INIT_2;
mem3 = INIT_3;
end
assign DO[0] = mem0[AD];
assign DO[1] = mem1[AD];
assign DO[2] = mem2[AD];
assign DO[3] = mem3[AD];
always @(posedge CLK) begin
if (WRE) begin
mem0[AD] <= DI[0];
mem1[AD] <= DI[1];
mem2[AD] <= DI[2];
mem3[AD] <= DI[3];
end
end
endmodule // RAM16S4
(* blackbox *)
module SDP (DO, DI, BLKSEL, ADA, ADB, WREA, WREB, CLKA, CLKB, CEA, CEB, OCE, RESETA, RESETB);
//1'b0: Bypass mode; 1'b1 Pipeline mode
parameter READ_MODE = 1'b0;
parameter BIT_WIDTH_0 = 32; // 1, 2, 4, 8, 16, 32
parameter BIT_WIDTH_1 = 32; // 1, 2, 4, 8, 16, 32
parameter BLK_SEL = 3'b000;
parameter RESET_MODE = "SYNC";
parameter INIT_RAM_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_20 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_21 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_22 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_23 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_24 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_25 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_26 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_27 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_28 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_29 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_30 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_31 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_32 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_33 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_34 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_35 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_36 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_37 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_38 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_39 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
input CLKA, CEA, CLKB, CEB;
input OCE; // clock enable of memory output register
input RESETA, RESETB; // resets output registers, not memory contents
input WREA, WREB; // 1'b0: read enabled; 1'b1: write enabled
input [13:0] ADA, ADB;
input [31:0] DI;
input [2:0] BLKSEL;
output [31:0] DO;
endmodule

View File

@ -0,0 +1,72 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
*
* 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 DetermineInitPass : public Pass {
DetermineInitPass() : Pass("determine_init", "Determine the init value of cells") { }
void help() YS_OVERRIDE
{
log("\n");
log(" determine_init [selection]\n");
log("\n");
log("Determine the init value of cells that doesn't allow unknown init value.\n");
log("\n");
}
Const determine_init(Const init)
{
for (int i = 0; i < GetSize(init); i++) {
if (init[i] != State::S0 && init[i] != State::S1)
init[i] = State::S0;
}
return init;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DETERMINE_INIT pass (determine init value for cells).\n");
extra_args(args, args.size(), design);
size_t cnt = 0;
for (auto module : design->selected_modules())
{
for (auto cell : module->selected_cells())
{
if (cell->type == "\\RAM16S4")
{
cell->setParam("\\INIT_0", determine_init(cell->getParam("\\INIT_0")));
cell->setParam("\\INIT_1", determine_init(cell->getParam("\\INIT_1")));
cell->setParam("\\INIT_2", determine_init(cell->getParam("\\INIT_2")));
cell->setParam("\\INIT_3", determine_init(cell->getParam("\\INIT_3")));
cnt++;
}
}
}
log_header(design, "Updated %lu cells with determined init value.\n", cnt);
}
} DetermineInitPass;
PRIVATE_NAMESPACE_END

17
techlibs/gowin/dram.txt Normal file
View File

@ -0,0 +1,17 @@
bram $__GW1NR_RAM16S4
init 1
abits 4
dbits 4
groups 2
ports 1 1
wrmode 0 1
enable 0 1
transp 0 1
clocks 0 1
clkpol 0 1
endbram
match $__GW1NR_RAM16S4
make_outreg
min wports 1
endmatch

View File

@ -0,0 +1,31 @@
module \$__GW1NR_RAM16S4 (CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
parameter CFG_ABITS = 4;
parameter CFG_DBITS = 4;
parameter [63:0] INIT = 64'bx;
input CLK1;
input [CFG_ABITS-1:0] A1ADDR;
output [CFG_DBITS-1:0] A1DATA;
input A1EN;
input [CFG_ABITS-1:0] B1ADDR;
input [CFG_DBITS-1:0] B1DATA;
input B1EN;
`include "brams_init3.vh"
RAM16S4
#(.INIT_0(INIT_0),
.INIT_1(INIT_1),
.INIT_2(INIT_2),
.INIT_3(INIT_3))
_TECHMAP_REPLACE_
(.AD(B1ADDR),
.DI(B1DATA),
.DO(A1DATA),
.CLK(CLK1),
.WRE(B1EN));
endmodule

View File

@ -49,9 +49,15 @@ struct SynthGowinPass : public ScriptPass
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");
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(" -nodffe\n");
log(" do not use flipflops with CE in output netlist\n");
log("\n");
log(" -nobram\n"); log(" -nobram\n");
log(" do not use BRAM cells in output netlist\n"); log(" do not use BRAM cells in output netlist\n");
log("\n"); log("\n");
log(" -nodram\n");
log(" do not use distributed RAM cells in output netlist\n");
log("\n");
log(" -noflatten\n"); log(" -noflatten\n");
log(" do not flatten design before synthesis\n"); log(" do not flatten design before synthesis\n");
log("\n"); log("\n");
@ -65,7 +71,7 @@ struct SynthGowinPass : public ScriptPass
} }
string top_opt, vout_file; string top_opt, vout_file;
bool retime, flatten, nobram; bool retime, nobram, nodram, flatten, nodffe;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
@ -73,7 +79,9 @@ struct SynthGowinPass : public ScriptPass
vout_file = ""; vout_file = "";
retime = false; retime = false;
flatten = true; flatten = true;
nobram = true; nobram = false;
nodffe = false;
nodram = 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
@ -108,6 +116,14 @@ struct SynthGowinPass : public ScriptPass
nobram = true; nobram = true;
continue; continue;
} }
if (args[argidx] == "-nodram") {
nodram = true;
continue;
}
if (args[argidx] == "-nodffe") {
nodffe = true;
continue;
}
if (args[argidx] == "-noflatten") { if (args[argidx] == "-noflatten") {
flatten = false; flatten = false;
continue; continue;
@ -147,25 +163,43 @@ struct SynthGowinPass : public ScriptPass
{ {
run("synth -run coarse"); run("synth -run coarse");
} }
if (!nobram && check_label("bram", "(skip if -nobram)"))
if (!nobram && check_label("bram", "(skip if -nobram)"))
{ {
run("memory_bram -rules +/gowin/bram.txt"); run("memory_bram -rules +/gowin/bram.txt");
run("techmap -map +/gowin/brams_map.v"); run("techmap -map +/gowin/brams_map.v -map +/gowin/cells_sim.v");
} }
if (!nodram && check_label("dram", "(skip if -nodram)"))
{
run("memory_bram -rules +/gowin/dram.txt");
run("techmap -map +/gowin/drams_map.v");
run("determine_init");
}
if (check_label("fine")) if (check_label("fine"))
{ {
run("opt -fast -mux_undef -undriven -fine"); run("opt -fast -mux_undef -undriven -fine");
run("memory_map"); run("memory_map");
run("opt -undriven -fine"); run("opt -undriven -fine");
run("techmap -map +/techmap.v -map +/gowin/arith_map.v"); run("techmap -map +/techmap.v -map +/gowin/arith_map.v");
run("opt -fine"); run("techmap -map +/techmap.v");
run("clean -purge");
run("splitnets -ports");
run("setundef -undriven -zero");
if (retime || help_mode) if (retime || help_mode)
run("abc -dff", "(only if -retime)"); run("abc -dff", "(only if -retime)");
} }
if (check_label("map_ffs"))
{
run("dffsr2dff");
run("dff2dffs");
run("opt_clean");
if (!nodffe)
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
run("techmap -map +/gowin/cells_map.v");
run("opt_expr -mux_undef");
run("simplemap");
}
if (check_label("map_luts")) if (check_label("map_luts"))
{ {
run("abc -lut 4"); run("abc -lut 4");
@ -176,8 +210,10 @@ struct SynthGowinPass : public ScriptPass
{ {
run("techmap -map +/gowin/cells_map.v"); run("techmap -map +/gowin/cells_map.v");
run("hilomap -hicell VCC V -locell GND G"); run("hilomap -hicell VCC V -locell GND G");
run("iopadmap -inpad IBUF O:I -outpad OBUF I:O"); run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O", "(unless -noiopads)");
run("clean -purge"); run("dffinit -ff DFF Q INIT");
run("clean");
} }
if (check_label("check")) if (check_label("check"))

View File

@ -27,18 +27,27 @@ module SB_IO (
reg dout_q_0, dout_q_1; reg dout_q_0, dout_q_1;
reg outena_q; reg outena_q;
// IO tile generates a constant 1'b1 internally if global_cen is not connected
wire clken_pulled = CLOCK_ENABLE || CLOCK_ENABLE === 1'bz;
reg clken_pulled_ri;
reg clken_pulled_ro;
generate if (!NEG_TRIGGER) begin generate if (!NEG_TRIGGER) begin
always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN; always @(posedge INPUT_CLK) clken_pulled_ri <= clken_pulled;
always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN; always @(posedge INPUT_CLK) if (clken_pulled) din_q_0 <= PACKAGE_PIN;
always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; always @(negedge INPUT_CLK) if (clken_pulled_ri) din_q_1 <= PACKAGE_PIN;
always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; always @(posedge OUTPUT_CLK) clken_pulled_ro <= clken_pulled;
always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; always @(posedge OUTPUT_CLK) if (clken_pulled) dout_q_0 <= D_OUT_0;
always @(negedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1 <= D_OUT_1;
always @(posedge OUTPUT_CLK) if (clken_pulled) outena_q <= OUTPUT_ENABLE;
end else begin end else begin
always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN; always @(negedge INPUT_CLK) clken_pulled_ri <= clken_pulled;
always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN; always @(negedge INPUT_CLK) if (clken_pulled) din_q_0 <= PACKAGE_PIN;
always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; always @(posedge INPUT_CLK) if (clken_pulled_ri) din_q_1 <= PACKAGE_PIN;
always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; always @(negedge OUTPUT_CLK) clken_pulled_ro <= clken_pulled;
always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; always @(negedge OUTPUT_CLK) if (clken_pulled) dout_q_0 <= D_OUT_0;
always @(posedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1 <= D_OUT_1;
always @(negedge OUTPUT_CLK) if (clken_pulled) outena_q <= OUTPUT_ENABLE;
end endgenerate end endgenerate
always @* begin always @* begin

View File

@ -85,7 +85,7 @@ module cyclonev_lcell_comb
begin begin
upper_lut_value = lut4(mask[31:16], dataa, datab, datac, datad); upper_lut_value = lut4(mask[31:16], dataa, datab, datac, datad);
lower_lut_value = lut4(mask[15:0], dataa, datab, datac, datad); lower_lut_value = lut4(mask[15:0], dataa, datab, datac, datad);
lut5 = (datae) ? upper_mask_value : lower_mask_value; lut5 = (datae) ? upper_lut_value : lower_lut_value;
end end
endfunction // lut5 endfunction // lut5
@ -95,15 +95,16 @@ module cyclonev_lcell_comb
input dataa, datab, datac, datad, datae, dataf; input dataa, datab, datac, datad, datae, dataf;
reg upper_lut_value; reg upper_lut_value;
reg lower_lut_value; reg lower_lut_value;
reg out_0, out_1, out_2, out_3;
begin begin
upper_lut_value = lut5(mask[63:32], dataa, datab, datac, datad, datae); upper_lut_value = lut5(mask[63:32], dataa, datab, datac, datad, datae);
lower_lut_value = lut5(mask[31:0], dataa, datab, datac, datad, datae); lower_lut_value = lut5(mask[31:0], dataa, datab, datac, datad, datae);
lut6 = (dataf) ? upper_mask_value : lower_mask_value; lut6 = (dataf) ? upper_lut_value : lower_lut_value;
end end
endfunction // lut6 endfunction // lut6
assign {mask_a, mask_b, mask_c, mask_d} = {lut_mask[15:0], lut_mask[31:16], lut_mask[47:32], lut_mask[63:48]}; assign {mask_a, mask_b, mask_c, mask_d} = {lut_mask[15:0], lut_mask[31:16], lut_mask[47:32], lut_mask[63:48]};
`ifdef ADVANCED_ALM
always @(*) begin always @(*) begin
if(extended_lut == "on") if(extended_lut == "on")
shared_lut_alm = datag; shared_lut_alm = datag;
@ -115,6 +116,11 @@ module cyclonev_lcell_comb
out_2 = lut4(mask_c, dataa, datab, datac, datad); out_2 = lut4(mask_c, dataa, datab, datac, datad);
out_3 = lut4(mask_d, dataa, datab, shared_lut_alm, datad); out_3 = lut4(mask_d, dataa, datab, shared_lut_alm, datad);
end end
`else
`ifdef DEBUG
initial $display("Advanced ALM lut combine is not implemented yet");
`endif
`endif
endmodule // cyclonev_lcell_comb endmodule // cyclonev_lcell_comb

View File

@ -17,4 +17,130 @@
* *
*/ */
// Empty for now module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0;
parameter CLKPOL = 1;
parameter ENPOL = 2;
\$__XILINX_SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(DEPTH-1), .E(E), .Q(Q));
endmodule
module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO);
parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0;
parameter CLKPOL = 1;
parameter ENPOL = 2;
// shregmap's INIT parameter shifts out LSB first;
// however Xilinx expects MSB first
function [DEPTH-1:0] brev;
input [DEPTH-1:0] din;
integer i;
begin
for (i = 0; i < DEPTH; i=i+1)
brev[i] = din[DEPTH-1-i];
end
endfunction
localparam [DEPTH-1:0] INIT_R = brev(INIT);
parameter _TECHMAP_CONSTMSK_L_ = 0;
parameter _TECHMAP_CONSTVAL_L_ = 0;
wire CE;
generate
if (ENPOL == 0)
assign CE = ~E;
else if (ENPOL == 1)
assign CE = E;
else
assign CE = 1'b1;
if (DEPTH == 1) begin
if (CLKPOL)
FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0));
else
FDRE_1 #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0));
end else
if (DEPTH <= 16) begin
SRL16E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(L[0]), .A1(L[1]), .A2(L[2]), .A3(L[3]), .CE(CE), .CLK(C), .D(D), .Q(Q));
end else
if (DEPTH > 17 && DEPTH <= 32) begin
SRLC32E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(Q));
end else
if (DEPTH > 33 && DEPTH <= 64) begin
wire T0, T1, T2;
SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-32-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L), .E(E), .Q(T2));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T2;
else
MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(L[5]));
end else
if (DEPTH > 65 && DEPTH <= 96) begin
wire T0, T1, T2, T3, T4, T5, T6;
SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T4;
else begin
MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(L[5]));
MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(L[5]));
MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(L[6]));
end
end else
if (DEPTH > 97 && DEPTH < 128) begin
wire T0, T1, T2, T3, T4, T5, T6, T7, T8;
SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T6;
else begin
MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5]));
MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5]));
MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6]));
end
end
else if (DEPTH == 128) begin
wire T0, T1, T2, T3, T4, T5, T6;
SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
SRLC32E #(.INIT(INIT_R[128-1:96]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_3 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T5), .Q(T6), .Q31(SO));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T6;
else begin
wire T7, T8;
MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5]));
MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5]));
MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6]));
end
end
else if (DEPTH <= 129 && ~&_TECHMAP_CONSTMSK_L_) begin
// Handle cases where fixed-length depth is
// just 1 over a convenient value
\$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q));
end
else begin
localparam lower_clog2 = $clog2((DEPTH+1)/2);
localparam lower_depth = 2 ** lower_clog2;
wire T0, T1, T2, T3;
if (&_TECHMAP_CONSTMSK_L_) begin
\$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(lower_depth-1), .E(E), .Q(T0));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(DEPTH-lower_depth-1), .E(E), .Q(Q), .SO(T3));
end
else begin
\$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2), .SO(T3));
assign Q = L[lower_clog2] ? T2 : T0;
end
if (DEPTH == 2 * lower_depth)
assign SO = T3;
end
endgenerate
endmodule
`ifndef SRL_ONLY
`endif

View File

@ -30,10 +30,15 @@ module GND(output G);
endmodule endmodule
module IBUF(output O, input I); module IBUF(output O, input I);
parameter IOSTANDARD = "default";
parameter IBUF_LOW_PWR = 0;
assign O = I; assign O = I;
endmodule endmodule
module OBUF(output O, input I); module OBUF(output O, input I);
parameter IOSTANDARD = "default";
parameter DRIVE = 12;
parameter SLEW = "SLOW";
assign O = I; assign O = I;
endmodule endmodule
@ -41,6 +46,42 @@ module BUFG(output O, input I);
assign O = I; assign O = I;
endmodule endmodule
module BUFGCTRL(
output O,
input I0, input I1,
input S0, input S1,
input CE0, input CE1,
input IGNORE0, input IGNORE1);
parameter [0:0] INIT_OUT = 1'b0;
parameter PRESELECT_I0 = "FALSE";
parameter PRESELECT_I1 = "FALSE";
parameter [0:0] IS_CE0_INVERTED = 1'b0;
parameter [0:0] IS_CE1_INVERTED = 1'b0;
parameter [0:0] IS_S0_INVERTED = 1'b0;
parameter [0:0] IS_S1_INVERTED = 1'b0;
parameter [0:0] IS_IGNORE0_INVERTED = 1'b0;
parameter [0:0] IS_IGNORE1_INVERTED = 1'b0;
wire I0_internal = ((CE0 ^ IS_CE0_INVERTED) ? I0 : INIT_OUT);
wire I1_internal = ((CE1 ^ IS_CE1_INVERTED) ? I1 : INIT_OUT);
wire S0_true = (S0 ^ IS_S0_INVERTED);
wire S1_true = (S1 ^ IS_S1_INVERTED);
assign O = S0_true ? I0_internal : (S1_true ? I1_internal : INIT_OUT);
endmodule
module BUFHCE(output O, input I, input CE);
parameter [0:0] INIT_OUT = 1'b0;
parameter CE_TYPE = "SYNC";
parameter [0:0] IS_CE_INVERTED = 1'b0;
assign O = ((CE ^ IS_CE_INVERTED) ? I : INIT_OUT);
endmodule
// module OBUFT(output O, input I, T); // module OBUFT(output O, input I, T);
// assign O = T ? 1'bz : I; // assign O = T ? 1'bz : I;
// endmodule // endmodule
@ -98,6 +139,22 @@ module LUT6(output O, input I0, I1, I2, I3, I4, I5);
assign O = I0 ? s1[1] : s1[0]; assign O = I0 ? s1[1] : s1[0];
endmodule endmodule
module LUT6_2(output O6, output O5, input I0, I1, I2, I3, I4, I5);
parameter [63:0] INIT = 0;
wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0];
wire [15: 0] s4 = I4 ? s5[31:16] : s5[15: 0];
wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0];
wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
assign O6 = I0 ? s1[1] : s1[0];
wire [15: 0] s5_4 = I4 ? INIT[31:16] : INIT[15: 0];
wire [ 7: 0] s5_3 = I3 ? s5_4[15: 8] : s5_4[ 7: 0];
wire [ 3: 0] s5_2 = I2 ? s5_3[ 7: 4] : s5_3[ 3: 0];
wire [ 1: 0] s5_1 = I1 ? s5_2[ 3: 2] : s5_2[ 1: 0];
assign O5 = I0 ? s5_1[1] : s5_1[0];
endmodule
module MUXCY(output O, input CI, DI, S); module MUXCY(output O, input CI, DI, S);
assign O = S ? CI : DI; assign O = S ? CI : DI;
endmodule endmodule
@ -251,3 +308,42 @@ module RAM128X1D (
wire clk = WCLK ^ IS_WCLK_INVERTED; wire clk = WCLK ^ IS_WCLK_INVERTED;
always @(posedge clk) if (WE) mem[A] <= D; always @(posedge clk) if (WE) mem[A] <= D;
endmodule endmodule
module SRL16E (
output Q,
input A0, A1, A2, A3, CE, CLK, D
);
parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
reg [15:0] r = INIT;
assign Q = r[{A3,A2,A1,A0}];
generate
if (IS_CLK_INVERTED) begin
always @(negedge CLK) if (CE) r <= { r[14:0], D };
end
else
always @(posedge CLK) if (CE) r <= { r[14:0], D };
endgenerate
endmodule
module SRLC32E (
output Q,
output Q31,
input [4:0] A,
input CE, CLK, D
);
parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
reg [31:0] r = INIT;
assign Q31 = r[31];
assign Q = r[A];
generate
if (IS_CLK_INVERTED) begin
always @(negedge CLK) if (CE) r <= { r[30:0], D };
end
else
always @(posedge CLK) if (CE) r <= { r[30:0], D };
endgenerate
endmodule

View File

@ -28,12 +28,12 @@ function xtract_cell_decl()
# xtract_cell_decl BUFG # xtract_cell_decl BUFG
xtract_cell_decl BUFGCE xtract_cell_decl BUFGCE
xtract_cell_decl BUFGCE_1 xtract_cell_decl BUFGCE_1
xtract_cell_decl BUFGCTRL #xtract_cell_decl BUFGCTRL
xtract_cell_decl BUFGMUX xtract_cell_decl BUFGMUX
xtract_cell_decl BUFGMUX_1 xtract_cell_decl BUFGMUX_1
xtract_cell_decl BUFGMUX_CTRL xtract_cell_decl BUFGMUX_CTRL
xtract_cell_decl BUFH xtract_cell_decl BUFH
xtract_cell_decl BUFHCE #xtract_cell_decl BUFHCE
xtract_cell_decl BUFIO xtract_cell_decl BUFIO
xtract_cell_decl BUFMR xtract_cell_decl BUFMR
xtract_cell_decl BUFMRCE xtract_cell_decl BUFMRCE
@ -92,7 +92,7 @@ function xtract_cell_decl()
# xtract_cell_decl LUT4 # xtract_cell_decl LUT4
# xtract_cell_decl LUT5 # xtract_cell_decl LUT5
# xtract_cell_decl LUT6 # xtract_cell_decl LUT6
xtract_cell_decl LUT6_2 #xtract_cell_decl LUT6_2
xtract_cell_decl MMCME2_ADV xtract_cell_decl MMCME2_ADV
xtract_cell_decl MMCME2_BASE xtract_cell_decl MMCME2_BASE
# xtract_cell_decl MUXF7 # xtract_cell_decl MUXF7
@ -135,8 +135,8 @@ function xtract_cell_decl()
xtract_cell_decl ROM256X1 xtract_cell_decl ROM256X1
xtract_cell_decl ROM32X1 xtract_cell_decl ROM32X1
xtract_cell_decl ROM64X1 xtract_cell_decl ROM64X1
xtract_cell_decl SRL16E #xtract_cell_decl SRL16E
xtract_cell_decl SRLC32E #xtract_cell_decl SRLC32E
xtract_cell_decl STARTUPE2 "(* keep *)" xtract_cell_decl STARTUPE2 "(* keep *)"
xtract_cell_decl USR_ACCESSE2 xtract_cell_decl USR_ACCESSE2
xtract_cell_decl XADC xtract_cell_decl XADC

View File

@ -30,29 +30,6 @@ module BUFGCE_1 (...);
input CE, I; input CE, I;
endmodule endmodule
module BUFGCTRL (...);
output O;
input CE0;
input CE1;
input I0;
input I1;
input IGNORE0;
input IGNORE1;
input S0;
input S1;
parameter integer INIT_OUT = 0;
parameter PRESELECT_I0 = "FALSE";
parameter PRESELECT_I1 = "FALSE";
parameter [0:0] IS_CE0_INVERTED = 1'b0;
parameter [0:0] IS_CE1_INVERTED = 1'b0;
parameter [0:0] IS_I0_INVERTED = 1'b0;
parameter [0:0] IS_I1_INVERTED = 1'b0;
parameter [0:0] IS_IGNORE0_INVERTED = 1'b0;
parameter [0:0] IS_IGNORE1_INVERTED = 1'b0;
parameter [0:0] IS_S0_INVERTED = 1'b0;
parameter [0:0] IS_S1_INVERTED = 1'b0;
endmodule
module BUFGMUX (...); module BUFGMUX (...);
parameter CLK_SEL_TYPE = "SYNC"; parameter CLK_SEL_TYPE = "SYNC";
output O; output O;
@ -77,15 +54,6 @@ module BUFH (...);
input I; input I;
endmodule endmodule
module BUFHCE (...);
parameter CE_TYPE = "SYNC";
parameter integer INIT_OUT = 0;
parameter [0:0] IS_CE_INVERTED = 1'b0;
output O;
input CE;
input I;
endmodule
module BUFIO (...); module BUFIO (...);
output O; output O;
input I; input I;
@ -2420,12 +2388,6 @@ module LDPE (...);
input D, G, GE, PRE; input D, G, GE, PRE;
endmodule endmodule
module LUT6_2 (...);
parameter [63:0] INIT = 64'h0000000000000000;
input I0, I1, I2, I3, I4, I5;
output O5, O6;
endmodule
module MMCME2_ADV (...); module MMCME2_ADV (...);
parameter BANDWIDTH = "OPTIMIZED"; parameter BANDWIDTH = "OPTIMIZED";
parameter real CLKFBOUT_MULT_F = 5.000; parameter real CLKFBOUT_MULT_F = 5.000;
@ -3847,22 +3809,6 @@ module ROM64X1 (...);
input A0, A1, A2, A3, A4, A5; input A0, A1, A2, A3, A4, A5;
endmodule endmodule
module SRL16E (...);
parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
output Q;
input A0, A1, A2, A3, CE, CLK, D;
endmodule
module SRLC32E (...);
parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
output Q;
output Q31;
input [4:0] A;
input CE, CLK, D;
endmodule
(* keep *) (* keep *)
module STARTUPE2 (...); module STARTUPE2 (...);
parameter PROG_USR = "FALSE"; parameter PROG_USR = "FALSE";

View File

@ -22,21 +22,26 @@
`ifndef _NO_FFS `ifndef _NO_FFS
`ifndef _NO_POS_SR
module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
`endif
module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
`endif
`endif `endif

View File

@ -64,10 +64,13 @@ struct SynthXilinxPass : public Pass
log(" (this feature is experimental and incomplete)\n"); log(" (this feature is experimental and incomplete)\n");
log("\n"); log("\n");
log(" -nobram\n"); log(" -nobram\n");
log(" disable infering of block rams\n"); log(" disable inference of block rams\n");
log("\n"); log("\n");
log(" -nodram\n"); log(" -nodram\n");
log(" disable infering of distributed rams\n"); log(" disable inference of distributed rams\n");
log("\n");
log(" -nosrl\n");
log(" disable inference of shift registers\n");
log("\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");
@ -105,21 +108,28 @@ struct SynthXilinxPass : public Pass
log(" techmap -map +/xilinx/drams_map.v\n"); log(" techmap -map +/xilinx/drams_map.v\n");
log("\n"); log("\n");
log(" fine:\n"); log(" fine:\n");
log(" opt -fast -full\n"); log(" opt -fast\n");
log(" memory_map\n"); log(" memory_map\n");
log(" dffsr2dff\n"); log(" dffsr2dff\n");
log(" dff2dffe\n"); log(" dff2dffe\n");
log(" opt -full\n"); log(" techmap -map +/xilinx/arith_map.v\n");
log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n");
log(" opt -fast\n"); log(" opt -fast\n");
log("\n"); log("\n");
log(" map_luts:\n"); log(" map_cells:\n");
log(" abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!)\n"); log(" simplemap t:$dff t:$dffe (without '-nosrl' only)\n");
log(" abc -lut 5 [-dff] (with '-vpr' only!)\n"); log(" pmux2shiftx (without '-nosrl' only)\n");
log(" opt_expr -mux_undef (without '-nosrl' only)\n");
log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n");
log(" techmap -map +/xilinx/cells_map.v\n");
log(" clean\n"); log(" clean\n");
log("\n"); log("\n");
log(" map_cells:\n"); log(" map_luts:\n");
log(" techmap -map +/xilinx/cells_map.v\n"); log(" opt -full\n");
log(" techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v\n");
log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n");
log(" clean\n");
log(" shregmap -minlen 3 -init -params -enpol any_or_none (without '-nosrl' only)\n");
log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n"); log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n");
log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n"); log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n");
log(" clean\n"); log(" clean\n");
@ -147,6 +157,7 @@ struct SynthXilinxPass : public Pass
bool vpr = false; bool vpr = false;
bool nobram = false; bool nobram = false;
bool nodram = false; bool nodram = false;
bool nosrl = false;
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
@ -191,6 +202,10 @@ struct SynthXilinxPass : public Pass
nodram = true; nodram = true;
continue; continue;
} }
if (args[argidx] == "-nosrl") {
nosrl = true;
continue;
}
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
@ -249,32 +264,52 @@ struct SynthXilinxPass : public Pass
if (check_label(active, run_from, run_to, "fine")) if (check_label(active, run_from, run_to, "fine"))
{ {
Pass::call(design, "opt -fast -full"); Pass::call(design, "opt -fast");
Pass::call(design, "memory_map"); Pass::call(design, "memory_map");
Pass::call(design, "dffsr2dff"); Pass::call(design, "dffsr2dff");
Pass::call(design, "dff2dffe"); Pass::call(design, "dff2dffe");
Pass::call(design, "opt -full");
if (vpr) { if (vpr) {
Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v -D _EXPLICIT_CARRY"); Pass::call(design, "techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
} else { } else {
Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v"); Pass::call(design, "techmap -map +/xilinx/arith_map.v");
} }
Pass::call(design, "hierarchy -check");
Pass::call(design, "opt -fast"); Pass::call(design, "opt -fast");
} }
if (check_label(active, run_from, run_to, "map_luts"))
{
Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
Pass::call(design, "clean");
Pass::call(design, "techmap -map +/xilinx/lut_map.v");
}
if (check_label(active, run_from, run_to, "map_cells")) if (check_label(active, run_from, run_to, "map_cells"))
{ {
if (!nosrl) {
// shregmap operates on bit-level flops, not word-level,
// so break those down here
Pass::call(design, "simplemap t:$dff t:$dffe");
// shregmap -tech xilinx can cope with $shiftx and $mux
// cells for identifiying variable-length shift registers,
// so attempt to convert $pmux-es to the former
Pass::call(design, "pmux2shiftx");
// pmux2shiftx can leave behind a $pmux with a single entry
// -- need this to clean that up before shregmap
Pass::call(design, "opt_expr -mux_undef");
// shregmap with '-tech xilinx' infers variable length shift regs
Pass::call(design, "shregmap -tech xilinx -minlen 3");
}
Pass::call(design, "techmap -map +/xilinx/cells_map.v"); Pass::call(design, "techmap -map +/xilinx/cells_map.v");
Pass::call(design, "clean");
}
if (check_label(active, run_from, run_to, "map_luts"))
{
Pass::call(design, "opt -full");
Pass::call(design, "techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v");
Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
Pass::call(design, "clean");
// This shregmap call infers fixed length shift registers after abc
// has performed any necessary retiming
if (!nosrl)
Pass::call(design, "shregmap -minlen 3 -init -params -enpol any_or_none");
Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " Pass::call(design, "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");
Pass::call(design, "clean"); Pass::call(design, "clean");

2
tests/aiger/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.log
*.out

View File

@ -0,0 +1,38 @@
// coverage for repeat loops outside of constant functions
module counter1(clk, rst, ping);
input clk, rst;
output ping;
reg [31:0] count;
always @(posedge clk) begin
if (rst)
count <= 0;
else
count <= count + 1;
end
assign ping = &count;
endmodule
module counter2(clk, rst, ping);
input clk, rst;
output ping;
reg [31:0] count;
integer i;
reg carry;
always @(posedge clk) begin
carry = 1;
i = 0;
repeat (32) begin
count[i] <= !rst & (count[i] ^ carry);
carry = count[i] & carry;
i = i+1;
end
end
assign ping = &count;
endmodule

View File

@ -0,0 +1,10 @@
read_verilog counters-repeat.v
proc; opt
expose -shared counter1 counter2
miter -equiv -make_assert -make_outputs counter1 counter2 miter
cd miter; flatten; opt
sat -verify -prove-asserts -tempinduct -set-at 1 in_rst 1 -seq 1 -show-inputs -show-outputs

6
tests/simple/retime.v Normal file
View File

@ -0,0 +1,6 @@
module retime_test(input clk, input [7:0] a, output z);
reg [7:0] ff = 8'hF5;
always @(posedge clk)
ff <= {ff[6:0], ^a};
assign z = ff[7];
endmodule

View File

@ -7,7 +7,7 @@ use_modelsim=false
verbose=false verbose=false
keeprunning=false keeprunning=false
makejmode=false makejmode=false
frontend="verilog" frontend="verilog -noblackbox"
backend_opts="-noattr -noexpr -siminit" backend_opts="-noattr -noexpr -siminit"
autotb_opts="" autotb_opts=""
include_opts="" include_opts=""
@ -137,7 +137,7 @@ do
egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext} egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext}
else else
"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn} "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn}
frontend="verilog" frontend="verilog -noblackbox"
fi fi
if [ ! -f ../${bn}_tb.v ]; then if [ ! -f ../${bn}_tb.v ]; then

View File

@ -53,6 +53,7 @@ echo -n " no explicit top - "
module noTop(a, y); module noTop(a, y);
input a; input a;
output [31:0] y; output [31:0] y;
assign y = a;
endmodule endmodule
EOV EOV
hierarchy -auto-top hierarchy -auto-top

View File

@ -0,0 +1,34 @@
module pmux2shiftx_test (
input [2:0] S1,
input [5:0] S2,
input [1:0] S3,
input [9:0] A, B, C, D, D, E, F, G, H,
input [9:0] I, J, K, L, M, N, O, P, Q,
output reg [9:0] X
);
always @* begin
case (S1)
3'd 0: X = A;
3'd 1: X = B;
3'd 2: X = C;
3'd 3: X = D;
3'd 4: X = E;
3'd 5: X = F;
3'd 6: X = G;
3'd 7: X = H;
endcase
case (S2)
6'd 45: X = I;
6'd 47: X = J;
6'd 49: X = K;
6'd 55: X = L;
6'd 57: X = M;
6'd 59: X = N;
endcase
case (S3)
2'd 1: X = O;
2'd 2: X = P;
2'd 3: X = Q;
endcase
end
endmodule

View File

@ -0,0 +1,28 @@
read_verilog pmux2shiftx.v
prep
design -save gold
pmux2shiftx -min_density 70
opt
stat
# show -width
select -assert-count 1 t:$sub
select -assert-count 1 t:$mux
select -assert-count 1 t:$shift
select -assert-count 3 t:$shiftx
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 gold
stat
design -load gate
stat