Merge branch 'master' into xaig

This commit is contained in:
Eddie Hung 2019-04-08 16:31:59 -07:00
commit bca3cf6843
115 changed files with 5852 additions and 720 deletions

View File

@ -4,6 +4,17 @@
all necessary source files. (You can simply drag&drop a .zip file into all necessary source files. (You can simply drag&drop a .zip file into
the issue editor.)* the issue editor.)*
Also, make sure that the issue is actually reproducable in current git
master of Yosys.
See https://stackoverflow.com/help/mcve for some information on how to
create a Minimal, Complete, and Verifiable example (MCVE).
Please do not waste our time with issues that lack sufficient information
to reproduce the issue easily. We will simply close those issues.
Contact https://www.symbioticeda.com/ if you need commercial support for Yosys.
## Expected behavior ## Expected behavior
*Please describe the behavior you would have expected from the tool.* *Please describe the behavior you would have expected from the tool.*
@ -11,6 +22,3 @@ the issue editor.)*
## Actual behavior ## Actual behavior
*Please describe how the behavior you see differs from the expected behavior.* *Please describe how the behavior you see differs from the expected behavior.*
**Important Note:** Nobody will be able to help you and/or fix the issue if you
do not provide sufficient information for reproducing the problem.

2
.gitignore vendored
View File

@ -24,6 +24,8 @@
/yosys-abc.exe /yosys-abc.exe
/yosys-config /yosys-config
/yosys-smtbmc /yosys-smtbmc
/yosys-smtbmc.exe
/yosys-smtbmc-script.py
/yosys-filterlib /yosys-filterlib
/yosys-filterlib.exe /yosys-filterlib.exe
/kernel/version_*.cc /kernel/version_*.cc

View File

@ -132,11 +132,11 @@ matrix:
env: env:
- MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0" - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0"
# Latest clang on Mac OS X # # Latest clang on Mac OS X
- os: osx # - os: osx
osx_image: xcode9.4 # osx_image: xcode9.4
env: # env:
- MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++" # - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++"
before_install: before_install:
- ./.travis/setup.sh - ./.travis/setup.sh

View File

@ -10,6 +10,7 @@ CONFIG := clang
# features (the more the better) # features (the more the better)
ENABLE_TCL := 1 ENABLE_TCL := 1
ENABLE_ABC := 1 ENABLE_ABC := 1
ENABLE_GLOB := 1
ENABLE_PLUGINS := 1 ENABLE_PLUGINS := 1
ENABLE_READLINE := 1 ENABLE_READLINE := 1
ENABLE_EDITLINE := 0 ENABLE_EDITLINE := 0
@ -298,6 +299,10 @@ LDLIBS += -ldl
endif endif
endif endif
ifeq ($(ENABLE_GLOB),1)
CXXFLAGS += -DYOSYS_ENABLE_GLOB
endif
ifeq ($(ENABLE_TCL),1) ifeq ($(ENABLE_TCL),1)
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
ifeq ($(OS), FreeBSD) ifeq ($(OS), FreeBSD)
@ -571,7 +576,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/simple && bash run-test.sh $(SEEDOPT) +cd tests/simple && bash run-test.sh $(SEEDOPT)
+cd tests/hana && bash run-test.sh $(SEEDOPT) +cd tests/hana && bash run-test.sh $(SEEDOPT)
+cd tests/asicworld && bash run-test.sh $(SEEDOPT) +cd tests/asicworld && bash run-test.sh $(SEEDOPT)
+cd tests/realmath && bash run-test.sh $(SEEDOPT) # +cd tests/realmath && bash run-test.sh $(SEEDOPT)
+cd tests/share && bash run-test.sh $(SEEDOPT) +cd tests/share && bash run-test.sh $(SEEDOPT)
+cd tests/fsm && bash run-test.sh $(SEEDOPT) +cd tests/fsm && bash run-test.sh $(SEEDOPT)
+cd tests/techmap && bash run-test.sh +cd tests/techmap && bash run-test.sh

View File

@ -34,11 +34,24 @@ compatible license that is similar in terms to the MIT license
or the 2-clause BSD license). or the 2-clause BSD license).
Web Site Web Site and Other Resources
======== ============================
More information and documentation can be found on the Yosys web site: More information and documentation can be found on the Yosys web site:
http://www.clifford.at/yosys/ - http://www.clifford.at/yosys/
The "Documentation" page on the web site contains links to more resources,
including a manual that even describes some of the Yosys internals:
- http://www.clifford.at/yosys/documentation.html
The file `CodingReadme` in this directory contains additional information
for people interested in using the Yosys C++ APIs.
Users interested in formal verification might want to use the formal verification
front-end for Yosys, SymbiYosys:
- https://symbiyosys.readthedocs.io/en/latest/
- https://github.com/YosysHQ/SymbiYosys
Setup Setup
====== ======
@ -92,12 +105,15 @@ Makefile.
To build Yosys simply type 'make' in this directory. To build Yosys simply type 'make' in this directory.
$ make $ make
$ make test
$ sudo make install $ sudo make install
Note that this also downloads, builds and installs ABC (using yosys-abc Note that this also downloads, builds and installs ABC (using yosys-abc
as executable name). as executable name).
Tests are located in the tests subdirectory and can be executed using the test target. Note that you need gawk as well as a recent version of iverilog (i.e. build from git). Then, execute tests via:
$ make test
Getting Started Getting Started
=============== ===============
@ -296,6 +312,12 @@ Verilog Attributes and non-standard features
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.
- The ``dynports'' attribute is used by the Verilog front-end to mark modules
that have ports with a width that depends on a parameter.
- The ``hdlname'' attribute is used by some passes to document the original
(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
never be removed by the optimizer. This is used for example for cells that never be removed by the optimizer. This is used for example for cells that
have hidden connections that are not part of the netlist, such as IO pads. have hidden connections that are not part of the netlist, such as IO pads.

View File

@ -615,6 +615,7 @@ struct BtorWorker
{ {
int abits = cell->getParam("\\ABITS").as_int(); int abits = cell->getParam("\\ABITS").as_int();
int width = cell->getParam("\\WIDTH").as_int(); int width = cell->getParam("\\WIDTH").as_int();
int nwords = cell->getParam("\\SIZE").as_int();
int rdports = cell->getParam("\\RD_PORTS").as_int(); int rdports = cell->getParam("\\RD_PORTS").as_int();
int wrports = cell->getParam("\\WR_PORTS").as_int(); int wrports = cell->getParam("\\WR_PORTS").as_int();
@ -641,6 +642,52 @@ struct BtorWorker
int data_sid = get_bv_sid(width); int data_sid = get_bv_sid(width);
int bool_sid = get_bv_sid(1); int bool_sid = get_bv_sid(1);
int sid = get_mem_sid(abits, width); int sid = get_mem_sid(abits, width);
Const initdata = cell->getParam("\\INIT");
initdata.exts(nwords*width);
int nid_init_val = -1;
if (!initdata.is_fully_undef())
{
bool constword = true;
Const firstword = initdata.extract(0, width);
for (int i = 1; i < nwords; i++) {
Const thisword = initdata.extract(i*width, width);
if (thisword != firstword) {
constword = false;
break;
}
}
if (constword)
{
if (verbose)
btorf("; initval = %s\n", log_signal(firstword));
nid_init_val = get_sig_nid(firstword);
}
else
{
int nid_init_val = next_nid++;
btorf("%d state %d\n", nid_init_val, sid);
for (int i = 0; i < nwords; i++) {
Const thisword = initdata.extract(i*width, width);
if (thisword.is_fully_undef())
continue;
Const thisaddr(i, abits);
int nid_thisword = get_sig_nid(thisword);
int nid_thisaddr = get_sig_nid(thisaddr);
int last_nid_init_val = nid_init_val;
nid_init_val = next_nid++;
if (verbose)
btorf("; initval[%d] = %s\n", i, log_signal(thisword));
btorf("%d write %d %d %d %d\n", nid_init_val, sid, last_nid_init_val, nid_thisaddr, nid_thisword);
}
}
}
int nid = next_nid++; int nid = next_nid++;
int nid_head = nid; int nid_head = nid;
@ -649,6 +696,12 @@ struct BtorWorker
else else
btorf("%d state %d %s\n", nid, sid, log_id(cell)); btorf("%d state %d %s\n", nid, sid, log_id(cell));
if (nid_init_val >= 0)
{
int nid_init = next_nid++;
btorf("%d init %d %d %d\n", nid_init, sid, nid, nid_init_val);
}
if (asyncwr) if (asyncwr)
{ {
for (int port = 0; port < wrports; port++) for (int port = 0; port < wrports; port++)
@ -932,9 +985,8 @@ struct BtorWorker
btorf_push(stringf("output %s", log_id(wire))); btorf_push(stringf("output %s", log_id(wire)));
int sid = get_bv_sid(GetSize(wire));
int nid = get_sig_nid(wire); int nid = get_sig_nid(wire);
btorf("%d output %d %d %s\n", next_nid++, sid, nid, log_id(wire)); btorf("%d output %d %s\n", next_nid++, nid, log_id(wire));
btorf_pop(stringf("output %s", log_id(wire))); btorf_pop(stringf("output %s", log_id(wire)));
} }

View File

@ -130,7 +130,7 @@ struct EdifBackend : public Backend {
bool port_rename = false; bool port_rename = false;
bool attr_properties = false; bool attr_properties = false;
std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports; std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
bool nogndvcc = false, gndvccy = true; bool nogndvcc = false, gndvccy = false;
CellTypes ct(design); CellTypes ct(design);
EdifNames edif_names; EdifNames edif_names;

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;
@ -165,11 +254,9 @@ struct FirrtlWorker
std::string fid(RTLIL::IdString internal_id) std::string fid(RTLIL::IdString internal_id)
{ {
const char *str = internal_id.c_str(); return make_id(internal_id);
return *str == '\\' ? str + 1 : str;
} }
std::string cellname(RTLIL::Cell *cell) std::string cellname(RTLIL::Cell *cell)
{ {
return fid(cell->name).c_str(); return fid(cell->name).c_str();
@ -219,29 +306,42 @@ struct FirrtlWorker
if (it->second.size() > 0) { if (it->second.size() > 0) {
const SigSpec &secondSig = it->second; const SigSpec &secondSig = it->second;
const std::string firstName = cell_name + "." + make_id(it->first); const std::string firstName = cell_name + "." + make_id(it->first);
const std::string secondName = make_expr(secondSig); const std::string secondExpr = make_expr(secondSig);
// Find the direction for this port. // Find the direction for this port.
FDirection dir = getPortFDirection(it->first, instModule); FDirection dir = getPortFDirection(it->first, instModule);
std::string source, sink; std::string sourceExpr, sinkExpr;
const SigSpec *sinkSig = nullptr;
switch (dir) { switch (dir) {
case FD_INOUT: case FD_INOUT:
log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
case FD_OUT: case FD_OUT:
source = firstName; sourceExpr = firstName;
sink = secondName; sinkExpr = secondExpr;
sinkSig = &secondSig;
break; break;
case FD_NODIRECTION: case FD_NODIRECTION:
log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
/* FALL_THROUGH */ /* FALL_THROUGH */
case FD_IN: case FD_IN:
source = secondName; sourceExpr = secondExpr;
sink = firstName; sinkExpr = firstName;
break; break;
default: default:
log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir); log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir);
break; break;
} }
wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sink.c_str(), source.c_str())); // Check for subfield assignment.
std::string bitsString = "bits(";
if (sinkExpr.substr(0, bitsString.length()) == bitsString ) {
if (sinkSig == nullptr)
log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str());
// Don't generate the assignment here.
// Add the source and sink to the "reverse_wire_map" and we'll output the assignment
// as part of the coalesced subfield assignments for this wire.
register_reverse_wire_map(sourceExpr, *sinkSig);
} else {
wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str()));
}
} }
} }
wire_exprs.push_back(stringf("\n")); wire_exprs.push_back(stringf("\n"));
@ -504,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();
@ -520,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++)
@ -557,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]);
@ -568,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;
} }
@ -752,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

@ -204,7 +204,7 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
f << stringf("%s case ", indent.c_str()); f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) { for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0) if (i > 0)
f << stringf(", "); f << stringf(" , ");
dump_sigspec(f, (*it)->compare[i]); dump_sigspec(f, (*it)->compare[i]);
} }
f << stringf("\n"); f << stringf("\n");

View File

@ -48,7 +48,7 @@ struct ProtobufDesignSerializer
ProtobufDesignSerializer(bool use_selection, bool aig_mode) : ProtobufDesignSerializer(bool use_selection, bool aig_mode) :
aig_mode_(aig_mode), use_selection_(use_selection) { } aig_mode_(aig_mode), use_selection_(use_selection) { }
string get_name(IdString name) string get_name(IdString name)
{ {
return RTLIL::unescape_id(name); return RTLIL::unescape_id(name);
@ -60,7 +60,7 @@ struct ProtobufDesignSerializer
{ {
for (auto &param : parameters) { for (auto &param : parameters) {
std::string key = get_name(param.first); std::string key = get_name(param.first);
yosys::pb::Parameter pb_param; yosys::pb::Parameter pb_param;
@ -207,7 +207,7 @@ struct ProtobufDesignSerializer
(*models)[aig.name] = pb_model; (*models)[aig.name] = pb_model;
} }
} }
void serialize_design(yosys::pb::Design *pb, Design *design) void serialize_design(yosys::pb::Design *pb, Design *design)
{ {
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;

View File

@ -3,14 +3,30 @@ OBJS += backends/smt2/smt2.o
ifneq ($(CONFIG),mxe) ifneq ($(CONFIG),mxe)
ifneq ($(CONFIG),emcc) ifneq ($(CONFIG),emcc)
# MSYS targets support yosys-smtbmc, but require a launcher script
ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64))
TARGETS += yosys-smtbmc.exe yosys-smtbmc-script.py
# Needed to find the Python interpreter for yosys-smtbmc scripts.
# Override if necessary, it is only used for msys2 targets.
PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3)
yosys-smtbmc-script.py: backends/smt2/smtbmc.py
$(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' \
-e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py
$(P) gcc -DGUI=0 -O -s -o $@ $<
# Other targets
else
TARGETS += yosys-smtbmc TARGETS += yosys-smtbmc
yosys-smtbmc: backends/smt2/smtbmc.py yosys-smtbmc: backends/smt2/smtbmc.py
$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
$(Q) chmod +x $@.new $(Q) chmod +x $@.new
$(Q) mv $@.new $@ $(Q) mv $@.new $@
endif
$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py)) $(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
endif endif
endif endif

View File

@ -416,6 +416,7 @@ struct Smt2Worker
for (char ch : expr) { for (char ch : expr) {
if (ch == 'A') processed_expr += get_bv(sig_a); if (ch == 'A') processed_expr += get_bv(sig_a);
else if (ch == 'B') processed_expr += get_bv(sig_b); else if (ch == 'B') processed_expr += get_bv(sig_b);
else if (ch == 'P') processed_expr += get_bv(cell->getPort("\\B"));
else if (ch == 'L') processed_expr += is_signed ? "a" : "l"; else if (ch == 'L') processed_expr += is_signed ? "a" : "l";
else if (ch == 'U') processed_expr += is_signed ? "s" : "u"; else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
else processed_expr += ch; else processed_expr += ch;
@ -554,7 +555,7 @@ struct Smt2Worker
if (cell->type.in("$shift", "$shiftx")) { if (cell->type.in("$shift", "$shiftx")) {
if (cell->getParam("\\B_SIGNED").as_bool()) { if (cell->getParam("\\B_SIGNED").as_bool()) {
return export_bvop(cell, stringf("(ite (bvsge B #b%0*d) " return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) "
"(bvlshr A B) (bvlshr A (bvneg B)))", "(bvlshr A B) (bvlshr A (bvneg B)))",
GetSize(cell->getPort("\\B")), 0), 's'); GetSize(cell->getPort("\\B")), 0), 's');
} else { } else {
@ -887,8 +888,8 @@ struct Smt2Worker
string name_a = get_bool(cell->getPort("\\A")); string name_a = get_bool(cell->getPort("\\A"));
string name_en = get_bool(cell->getPort("\\EN")); string name_en = get_bool(cell->getPort("\\EN"));
decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, string infostr = (cell->name[0] == '$' && cell->attributes.count("\\src")) ? cell->attributes.at("\\src").decode_string() : get_id(cell);
cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell))); decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, infostr.c_str()));
if (cell->type == "$cover") if (cell->type == "$cover")
decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n", decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n",
@ -1103,20 +1104,27 @@ struct Smt2Worker
break; break;
Const initword = init_data.extract(i*width, width, State::Sx); Const initword = init_data.extract(i*width, width, State::Sx);
Const initmask = initword;
bool gen_init_constr = false; bool gen_init_constr = false;
for (auto bit : initword.bits) for (int k = 0; k < GetSize(initword); k++) {
if (bit == State::S0 || bit == State::S1) if (initword[k] == State::S0 || initword[k] == State::S1) {
gen_init_constr = true; gen_init_constr = true;
initmask[k] = State::S1;
} else {
initmask[k] = State::S0;
initword[k] = State::S0;
}
}
if (gen_init_constr) if (gen_init_constr)
{ {
if (statebv) if (statebv)
/* FIXME */; /* FIXME */;
else else
init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]", init_list.push_back(stringf("(= (bvand (select (|%s#%d#0| state) #b%s) #b%s) #b%s) ; %s[%d]",
get_id(module), arrayid, Const(i, abits).as_string().c_str(), get_id(module), arrayid, Const(i, abits).as_string().c_str(),
initword.as_string().c_str(), get_id(cell), i)); initmask.as_string().c_str(), initword.as_string().c_str(), get_id(cell), i));
} }
} }
} }

View File

@ -1484,11 +1484,11 @@ else: # not tempind, covermode
smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i)) smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i))
smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i)) smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
smt_assert_consequent(get_constr_expr(constr_assumes, i)) smt_assert_consequent(get_constr_expr(constr_assumes, i))
print_msg("Re-solving with appended steps..") print_msg("Re-solving with appended steps..")
if smt_check_sat() == "unsat": if smt_check_sat() == "unsat":
print("%s Cannot appended steps without violating assumptions!" % smt.timestamp()) print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
retstatus = False retstatus = False
break break
print_anyconsts(step) print_anyconsts(step)
for i in range(step, last_check_step+1): for i in range(step, last_check_step+1):
print_failed_asserts(i) print_failed_asserts(i)

View File

@ -33,7 +33,7 @@
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal; bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit;
int auto_name_counter, auto_name_offset, auto_name_digits; int auto_name_counter, auto_name_offset, auto_name_digits;
std::map<RTLIL::IdString, int> auto_name_map; std::map<RTLIL::IdString, int> auto_name_map;
std::set<RTLIL::IdString> reg_wires, reg_ct; std::set<RTLIL::IdString> reg_wires, reg_ct;
@ -1310,7 +1310,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
} }
} }
if (reg_ct.count(cell->type) && cell->hasPort("\\Q")) { if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) {
std::stringstream ss; std::stringstream ss;
dump_reg_init(ss, cell->getPort("\\Q")); dump_reg_init(ss, cell->getPort("\\Q"));
if (!ss.str().empty()) { if (!ss.str().empty()) {
@ -1607,6 +1607,10 @@ struct VerilogBackend : public Backend {
log(" without this option all internal cells are converted to Verilog\n"); log(" without this option all internal cells are converted to Verilog\n");
log(" expressions.\n"); log(" expressions.\n");
log("\n"); log("\n");
log(" -siminit\n");
log(" add initial statements with hierarchical refs to initialize FFs when\n");
log(" in -noexpr mode.\n");
log("\n");
log(" -nodec\n"); log(" -nodec\n");
log(" 32-bit constant values are by default dumped as decimal numbers,\n"); log(" 32-bit constant values are by default dumped as decimal numbers,\n");
log(" not bit pattern. This option deactivates this feature and instead\n"); log(" not bit pattern. This option deactivates this feature and instead\n");
@ -1663,11 +1667,14 @@ struct VerilogBackend : public Backend {
nostr = false; nostr = false;
defparam = false; defparam = false;
decimal = false; decimal = false;
siminit = false;
auto_prefix = ""; auto_prefix = "";
bool blackboxes = false; bool blackboxes = false;
bool selected = false; bool selected = false;
auto_name_map.clear();
reg_wires.clear();
reg_ct.clear(); reg_ct.clear();
reg_ct.insert("$dff"); reg_ct.insert("$dff");
@ -1739,6 +1746,10 @@ struct VerilogBackend : public Backend {
decimal = true; decimal = true;
continue; continue;
} }
if (arg == "-siminit") {
siminit = true;
continue;
}
if (arg == "-blackboxes") { if (arg == "-blackboxes") {
blackboxes = true; blackboxes = true;
continue; continue;
@ -1770,6 +1781,8 @@ struct VerilogBackend : public Backend {
dump_module(*f, "", it->second); dump_module(*f, "", it->second);
} }
auto_name_map.clear();
reg_wires.clear();
reg_ct.clear(); reg_ct.clear();
} }
} VerilogBackend; } VerilogBackend;

7
examples/anlogic/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
demo.bit
demo_phy.area
full.v
*.log
*.h
*.tde
*.svf

12
examples/anlogic/README Normal file
View File

@ -0,0 +1,12 @@
LED Blink project for Anlogic Lichee Tang board.
Follow the install instructions for the Tang Dynasty IDE from given link below.
https://tang.sipeed.com/en/getting-started/installing-td-ide/linux/
set TD_HOME env variable to the full path to the TD <TD Install Directory> as follow.
export TD_HOME=<TD Install Directory>
then run "bash build.sh" in this directory.

4
examples/anlogic/build.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
set -ex
yosys demo.ys
$TD_HOME/bin/td build.tcl

View File

@ -0,0 +1,11 @@
import_device eagle_s20.db -package BG256
read_verilog full.v -top demo
read_adc demo.adc
optimize_rtl
map_macro
map
pack
place
route
report_area -io_info -file demo_phy.area
bitgen -bit demo.bit -version 0X0000 -svf demo.svf -svf_comment_on -g ucode:00000000000000000000000000000000

View File

@ -0,0 +1,2 @@
set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ
set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED

18
examples/anlogic/demo.v Normal file
View File

@ -0,0 +1,18 @@
module demo (
input wire CLK_IN,
output wire R_LED
);
parameter time1 = 30'd12_000_000;
reg led_state;
reg [29:0] count;
always @(posedge CLK_IN)begin
if(count == time1)begin
count<= 30'd0;
led_state <= ~led_state;
end
else
count <= count + 1'b1;
end
assign R_LED = led_state;
endmodule

3
examples/anlogic/demo.ys Normal file
View File

@ -0,0 +1,3 @@
read_verilog demo.v
synth_anlogic -top demo
write_verilog full.v

View File

@ -1,3 +1,4 @@
/netlist.edn /netlist.edn
/netlist.vm /netlist.vm
/example.stp
/proj /proj

View File

@ -1 +1,20 @@
# Add placement constraints here # Add placement constraints here
set_io clk -pinname H16 -fixed yes -DIRECTION INPUT
set_io SW1 -pinname H12 -fixed yes -DIRECTION INPUT
set_io SW2 -pinname H13 -fixed yes -DIRECTION INPUT
set_io LED1 -pinname J16 -fixed yes -DIRECTION OUTPUT
set_io LED2 -pinname M16 -fixed yes -DIRECTION OUTPUT
set_io LED3 -pinname K16 -fixed yes -DIRECTION OUTPUT
set_io LED4 -pinname N16 -fixed yes -DIRECTION OUTPUT
set_io AA -pinname L12 -fixed yes -DIRECTION OUTPUT
set_io AB -pinname L13 -fixed yes -DIRECTION OUTPUT
set_io AC -pinname M13 -fixed yes -DIRECTION OUTPUT
set_io AD -pinname N15 -fixed yes -DIRECTION OUTPUT
set_io AE -pinname L11 -fixed yes -DIRECTION OUTPUT
set_io AF -pinname L14 -fixed yes -DIRECTION OUTPUT
set_io AG -pinname N14 -fixed yes -DIRECTION OUTPUT
set_io CA -pinname M15 -fixed yes -DIRECTION OUTPUT

View File

@ -1 +1,2 @@
# Add timing constraints here # Add timing constraints here
create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]

View File

@ -1,23 +1,64 @@
module example ( module example (
input clk, input clk,
input EN, input SW1,
input SW2,
output LED1, output LED1,
output LED2, output LED2,
output LED3, output LED3,
output LED4, output LED4,
output LED5
output AA, AB, AC, AD,
output AE, AF, AG, CA
); );
localparam BITS = 5; localparam BITS = 8;
localparam LOG2DELAY = 22; localparam LOG2DELAY = 22;
reg [BITS+LOG2DELAY-1:0] counter = 0; reg [BITS+LOG2DELAY-1:0] counter = 0;
reg [BITS-1:0] outcnt; reg [BITS-1:0] outcnt;
always @(posedge clk) begin always @(posedge clk) begin
counter <= counter + EN; counter <= counter + SW1 + SW2 + 1;
outcnt <= counter >> LOG2DELAY; outcnt <= counter >> LOG2DELAY;
end end
assign {LED1, LED2, LED3, LED4, LED5} = outcnt ^ (outcnt >> 1); assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1);
// assign CA = counter[10];
// seg7enc seg7encinst (
// .seg({AA, AB, AC, AD, AE, AF, AG}),
// .dat(CA ? outcnt[3:0] : outcnt[7:4])
// );
assign {AA, AB, AC, AD, AE, AF, AG} = ~(7'b 100_0000 >> outcnt[6:4]);
assign CA = outcnt[7];
endmodule
module seg7enc (
input [3:0] dat,
output [6:0] seg
);
reg [6:0] seg_inv;
always @* begin
seg_inv = 0;
case (dat)
4'h0: seg_inv = 7'b 0111111;
4'h1: seg_inv = 7'b 0000110;
4'h2: seg_inv = 7'b 1011011;
4'h3: seg_inv = 7'b 1001111;
4'h4: seg_inv = 7'b 1100110;
4'h5: seg_inv = 7'b 1101101;
4'h6: seg_inv = 7'b 1111101;
4'h7: seg_inv = 7'b 0000111;
4'h8: seg_inv = 7'b 1111111;
4'h9: seg_inv = 7'b 1101111;
4'hA: seg_inv = 7'b 1110111;
4'hB: seg_inv = 7'b 1111100;
4'hC: seg_inv = 7'b 0111001;
4'hD: seg_inv = 7'b 1011110;
4'hE: seg_inv = 7'b 1111001;
4'hF: seg_inv = 7'b 1110001;
endcase
end
assign seg = ~seg_inv;
endmodule endmodule

View File

@ -8,13 +8,14 @@ new_project \
-block_mode 0 \ -block_mode 0 \
-hdl "VERILOG" \ -hdl "VERILOG" \
-family IGLOO2 \ -family IGLOO2 \
-die PA4MGL500 \ -die PA4MGL2500 \
-package tq144 \ -package vf256 \
-speed -1 -speed -1
import_files -hdl_source {netlist.vm} import_files -hdl_source {netlist.vm}
import_files -sdc {example.sdc} import_files -sdc {example.sdc}
import_files -io_pdc {example.pdc} import_files -io_pdc {example.pdc}
build_design_hierarchy
set_option -synth 0 set_option -synth 0
organize_tool_files -tool PLACEROUTE \ organize_tool_files -tool PLACEROUTE \
@ -32,22 +33,25 @@ configure_tool -name PLACEROUTE \
-params EFFORT_LEVEL:false \ -params EFFORT_LEVEL:false \
-params REPAIR_MIN_DELAY:false -params REPAIR_MIN_DELAY:false
puts ""
puts "**> COMPILE" puts "**> COMPILE"
run_tool -name {COMPILE} run_tool -name {COMPILE}
puts "<** COMPILE" puts "<** COMPILE"
puts ""
puts "**> PLACEROUTE" puts "**> PLACEROUTE"
run_tool -name {PLACEROUTE} run_tool -name {PLACEROUTE}
puts "<** PLACEROUTE" puts "<** PLACEROUTE"
puts ""
puts "**> VERIFYTIMING" puts "**> VERIFYTIMING"
run_tool -name {VERIFYTIMING} run_tool -name {VERIFYTIMING}
puts "<** VERIFYTIMING" puts "<** VERIFYTIMING"
save_project puts ""
puts "**> BITSTREAM"
# puts "**> export_bitstream" export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC}
# export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC} puts "<** BITSTREAM"
# puts "<** export_bitstream"
puts ""
exit 0 exit 0

View File

@ -1,4 +1,6 @@
#!/bin/bash #!/bin/bash
set -ex set -ex
yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v
LM_LICENSE_FILE=1702@`hostname` /opt/microsemi/Libero_SoC_v11.9/Libero/bin/libero SCRIPT:libero.tcl export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost}
/opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl
cp proj/designer/example/export/example.stp .

View File

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

View File

@ -45,7 +45,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_vlog, 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_lib, 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;
@ -431,9 +431,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
break; break;
case AST_RANGE: case AST_RANGE:
if (range_valid) if (range_valid) {
fprintf(f, "[%d:%d]", range_left, range_right); if (range_swapped)
else { fprintf(f, "[%d:%d]", range_right, range_left);
else
fprintf(f, "[%d:%d]", range_left, range_right);
} else {
for (auto child : children) { for (auto child : children) {
fprintf(f, "%c", first ? '[' : ':'); fprintf(f, "%c", first ? '[' : ':');
child->dumpVlog(f, ""); child->dumpVlog(f, "");
@ -562,7 +565,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
case AST_CONCAT: case AST_CONCAT:
fprintf(f, "{"); fprintf(f, "{");
for (auto child : children) { for (int i = GetSize(children)-1; i >= 0; i--) {
auto child = children[i];
if (!first) if (!first)
fprintf(f, ", "); fprintf(f, ", ");
child->dumpVlog(f, ""); child->dumpVlog(f, "");
@ -926,23 +930,28 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
ast_before_simplify = ast->clone(); ast_before_simplify = ast->clone();
if (flag_dump_ast1) { if (flag_dump_ast1) {
log("Dumping Verilog AST before simplification:\n"); log("Dumping AST before simplification:\n");
ast->dumpAst(NULL, " "); ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n"); log("--- END OF AST DUMP ---\n");
} }
if (flag_dump_vlog1) {
log("Dumping Verilog AST before simplification:\n");
ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
if (!defer) if (!defer)
{ {
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) {
log("Dumping Verilog AST after simplification:\n"); log("Dumping AST after simplification:\n");
ast->dumpAst(NULL, " "); ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n"); log("--- END OF AST DUMP ---\n");
} }
if (flag_dump_vlog) { if (flag_dump_vlog2) {
log("Dumping Verilog AST (as requested by dump_vlog option):\n"); log("Dumping Verilog AST after simplification:\n");
ast->dumpVlog(NULL, " "); ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n"); log("--- END OF AST DUMP ---\n");
} }
@ -1016,14 +1025,15 @@ 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_vlog, 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 lib, 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;
flag_dump_ast2 = dump_ast2; flag_dump_ast2 = dump_ast2;
flag_no_dump_ptr = no_dump_ptr; flag_no_dump_ptr = no_dump_ptr;
flag_dump_vlog = dump_vlog; flag_dump_vlog1 = dump_vlog1;
flag_dump_vlog2 = dump_vlog2;
flag_dump_rtlil = dump_rtlil; flag_dump_rtlil = dump_rtlil;
flag_nolatches = nolatches; flag_nolatches = nolatches;
flag_nomeminit = nomeminit; flag_nomeminit = nomeminit;
@ -1357,7 +1367,8 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
current_ast = NULL; current_ast = NULL;
flag_dump_ast1 = false; flag_dump_ast1 = false;
flag_dump_ast2 = false; flag_dump_ast2 = false;
flag_dump_vlog = false; flag_dump_vlog1 = false;
flag_dump_vlog2 = false;
flag_nolatches = nolatches; flag_nolatches = nolatches;
flag_nomeminit = nomeminit; flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg; flag_nomem2reg = nomem2reg;

View File

@ -214,6 +214,8 @@ namespace AST
MEM2REG_FL_SET_ASYNC = 0x00000800, MEM2REG_FL_SET_ASYNC = 0x00000800,
MEM2REG_FL_EQ2 = 0x00001000, MEM2REG_FL_EQ2 = 0x00001000,
MEM2REG_FL_CMPLX_LHS = 0x00002000, MEM2REG_FL_CMPLX_LHS = 0x00002000,
MEM2REG_FL_CONST_LHS = 0x00004000,
MEM2REG_FL_VAR_LHS = 0x00008000,
/* proc flags */ /* proc flags */
MEM2REG_FL_EQ1 = 0x01000000, MEM2REG_FL_EQ1 = 0x01000000,
@ -237,6 +239,7 @@ namespace AST
bool has_const_only_constructs(bool &recommend_const_eval); bool has_const_only_constructs(bool &recommend_const_eval);
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall); void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
AstNode *eval_const_function(AstNode *fcall); AstNode *eval_const_function(AstNode *fcall);
bool is_simple_const_expr();
// create a human-readable text representation of the AST (for debugging) // create a human-readable text representation of the AST (for debugging)
void dumpAst(FILE *f, std::string indent) const; void dumpAst(FILE *f, std::string indent) const;
@ -279,7 +282,7 @@ 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_vlog, 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 lib, 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

View File

@ -525,7 +525,16 @@ struct AST_INTERNAL::ProcessGenerator
} }
if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) { if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) {
#if 0
// this is a valid transformation, but as optimization it is premature.
// better: add a default case that assigns 'x' to everything, and let later
// optimizations take care of the rest
last_generated_case->compare.clear(); last_generated_case->compare.clear();
#else
default_case = new RTLIL::CaseRule;
addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue)));
sw->cases.push_back(default_case);
#endif
} else { } else {
if (default_case == NULL) { if (default_case == NULL) {
default_case = new RTLIL::CaseRule; default_case = new RTLIL::CaseRule;
@ -544,7 +553,11 @@ struct AST_INTERNAL::ProcessGenerator
break; break;
case AST_WIRE: case AST_WIRE:
log_file_error(ast->filename, ast->linenum, "Found wire declaration in block without label!\n"); log_file_error(ast->filename, ast->linenum, "Found reg declaration in block without label!\n");
break;
case AST_ASSIGN:
log_file_error(ast->filename, ast->linenum, "Found continous assignment in always/initial block!\n");
break; break;
case AST_PARAMETER: case AST_PARAMETER:
@ -1409,10 +1422,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (GetSize(en) != 1) if (GetSize(en) != 1)
en = current_module->ReduceBool(NEW_ID, en); en = current_module->ReduceBool(NEW_ID, en);
std::stringstream sstr; IdString cellname;
sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++); if (str.empty()) {
std::stringstream sstr;
sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
cellname = sstr.str();
} else {
cellname = str;
}
RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype); RTLIL::Cell *cell = current_module->addCell(cellname, celltype);
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
for (auto &attr : attributes) { for (auto &attr : attributes) {

View File

@ -50,7 +50,6 @@ using namespace AST_INTERNAL;
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param) bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
{ {
static int recursion_counter = 0; static int recursion_counter = 0;
static pair<string, int> last_blocking_assignment_warn;
static bool deep_recursion_warning = false; static bool deep_recursion_warning = false;
if (recursion_counter++ == 1000 && deep_recursion_warning) { if (recursion_counter++ == 1000 && deep_recursion_warning) {
@ -72,7 +71,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (stage == 0) if (stage == 0)
{ {
log_assert(type == AST_MODULE || type == AST_INTERFACE); log_assert(type == AST_MODULE || type == AST_INTERFACE);
last_blocking_assignment_warn = pair<string, int>();
deep_recursion_warning = true; deep_recursion_warning = true;
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { } while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
@ -113,6 +111,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS) if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
goto verbose_activate; goto verbose_activate;
if ((memflags & AstNode::MEM2REG_FL_CONST_LHS) && !(memflags & AstNode::MEM2REG_FL_VAR_LHS))
goto verbose_activate;
// log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags)); // log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags));
continue; continue;
@ -137,9 +138,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int mem_width, mem_size, addr_bits; int mem_width, mem_size, addr_bits;
node->meminfo(mem_width, mem_size, addr_bits); node->meminfo(mem_width, mem_size, addr_bits);
int data_range_left = node->children[0]->range_left;
int data_range_right = node->children[0]->range_right;
if (node->children[0]->range_swapped)
std::swap(data_range_left, data_range_right);
for (int i = 0; i < mem_size; i++) { for (int i = 0; i < mem_size; i++) {
AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,
mkconst_int(mem_width-1, true), mkconst_int(0, true))); mkconst_int(data_range_left, true), mkconst_int(data_range_right, true)));
reg->str = stringf("%s[%d]", node->str.c_str(), i); reg->str = stringf("%s[%d]", node->str.c_str(), i);
reg->is_reg = true; reg->is_reg = true;
reg->is_signed = node->is_signed; reg->is_signed = node->is_signed;
@ -325,6 +332,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
for (size_t i = 0; i < children.size(); i++) { for (size_t i = 0; i < children.size(); i++) {
AstNode *node = children[i]; AstNode *node = children[i];
if (node->type == AST_WIRE) { if (node->type == AST_WIRE) {
if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
for (auto c : node->children[0]->children) {
if (!c->is_simple_const_expr()) {
if (attributes.count("\\dynports"))
delete attributes.at("\\dynports");
attributes["\\dynports"] = AstNode::mkconst_int(1, true);
}
}
}
if (this_wire_scope.count(node->str) > 0) { if (this_wire_scope.count(node->str) > 0) {
AstNode *first_node = this_wire_scope[node->str]; AstNode *first_node = this_wire_scope[node->str];
if (first_node->is_input && node->is_reg) if (first_node->is_input && node->is_reg)
@ -938,7 +954,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
} }
} }
if (current_scope.count(str) == 0) { if (current_scope.count(str) == 0) {
if (flag_autowire) { if (flag_autowire || str == "\\$global_clock") {
AstNode *auto_wire = new AstNode(AST_AUTOWIRE); AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
auto_wire->str = str; auto_wire->str = str;
current_ast_mod->children.push_back(auto_wire); current_ast_mod->children.push_back(auto_wire);
@ -966,6 +982,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int data_range_left = id2ast->children[0]->range_left; int data_range_left = id2ast->children[0]->range_left;
int data_range_right = id2ast->children[0]->range_right; int data_range_right = id2ast->children[0]->range_right;
if (id2ast->children[0]->range_swapped)
std::swap(data_range_left, data_range_right);
std::stringstream sstr; std::stringstream sstr;
sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string wire_id = sstr.str(); std::string wire_id = sstr.str();
@ -1499,6 +1518,7 @@ skip_dynamic_range_lvalue_expansion:;
newNode->children.push_back(assign_en); newNode->children.push_back(assign_en);
AstNode *assertnode = new AstNode(type); AstNode *assertnode = new AstNode(type);
assertnode->str = str;
assertnode->children.push_back(new AstNode(AST_IDENTIFIER)); assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children.push_back(new AstNode(AST_IDENTIFIER)); assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children[0]->str = id_check; assertnode->children[0]->str = id_check;
@ -1579,14 +1599,6 @@ skip_dynamic_range_lvalue_expansion:;
sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
if (type == AST_ASSIGN_EQ) {
pair<string, int> this_blocking_assignment_warn(filename, linenum);
if (this_blocking_assignment_warn != last_blocking_assignment_warn)
log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
filename.c_str(), linenum);
last_blocking_assignment_warn = this_blocking_assignment_warn;
}
int mem_width, mem_size, addr_bits; int mem_width, mem_size, addr_bits;
bool mem_signed = children[0]->id2ast->is_signed; bool mem_signed = children[0]->id2ast->is_signed;
children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
@ -2169,6 +2181,8 @@ skip_dynamic_range_lvalue_expansion:;
} }
newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init); newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init);
delete node_filename;
delete node_memory;
goto apply_newNode; goto apply_newNode;
} }
@ -2210,6 +2224,8 @@ skip_dynamic_range_lvalue_expansion:;
std::map<std::string, std::string> replace_rules; std::map<std::string, std::string> replace_rules;
vector<AstNode*> added_mod_children; vector<AstNode*> added_mod_children;
dict<std::string, AstNode*> wire_cache; dict<std::string, AstNode*> wire_cache;
vector<AstNode*> new_stmts;
vector<AstNode*> output_assignments;
if (current_block == NULL) if (current_block == NULL)
{ {
@ -2334,8 +2350,8 @@ skip_dynamic_range_lvalue_expansion:;
wire->port_id = 0; wire->port_id = 0;
wire->is_input = false; wire->is_input = false;
wire->is_output = false; wire->is_output = false;
if (!child->is_output) wire->is_reg = true;
wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
wire_cache[child->str] = wire; wire_cache[child->str] = wire;
current_ast_mod->children.push_back(wire); current_ast_mod->children.push_back(wire);
@ -2357,13 +2373,10 @@ skip_dynamic_range_lvalue_expansion:;
new AstNode(AST_ASSIGN_EQ, wire_id, arg) : new AstNode(AST_ASSIGN_EQ, wire_id, arg) :
new AstNode(AST_ASSIGN_EQ, arg, wire_id); new AstNode(AST_ASSIGN_EQ, arg, wire_id);
assign->children[0]->was_checked = true; assign->children[0]->was_checked = true;
if (child->is_input)
for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { new_stmts.push_back(assign);
if (*it != current_block_child) else
continue; output_assignments.push_back(assign);
current_block->children.insert(it, assign);
break;
}
} }
} }
@ -2377,15 +2390,19 @@ skip_dynamic_range_lvalue_expansion:;
{ {
AstNode *stmt = child->clone(); AstNode *stmt = child->clone();
stmt->replace_ids(prefix, replace_rules); stmt->replace_ids(prefix, replace_rules);
new_stmts.push_back(stmt);
for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
if (*it != current_block_child)
continue;
current_block->children.insert(it, stmt);
break;
}
} }
new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end());
for (auto it = current_block->children.begin(); ; it++) {
log_assert(it != current_block->children.end());
if (*it == current_block_child) {
current_block->children.insert(it, new_stmts.begin(), new_stmts.end());
break;
}
}
replace_fcall_with_id: replace_fcall_with_id:
if (type == AST_FCALL) { if (type == AST_FCALL) {
delete_children(); delete_children();
@ -2855,7 +2872,11 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
for (size_t i = 0; i < children.size(); i++) { for (size_t i = 0; i < children.size(); i++) {
AstNode *child = children[i]; AstNode *child = children[i];
if (child->type != AST_FUNCTION && child->type != AST_TASK && child->type != AST_PREFIX) // AST_PREFIX member names should not be prefixed; a nested AST_PREFIX
// still needs to recursed-into
if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER)
continue;
if (child->type != AST_FUNCTION && child->type != AST_TASK)
child->expand_genblock(index_var, prefix, name_map); child->expand_genblock(index_var, prefix, name_map);
} }
@ -2910,7 +2931,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags) dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
{ {
uint32_t children_flags = 0; uint32_t children_flags = 0;
int ignore_children_counter = 0; int lhs_children_counter = 0;
if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
{ {
@ -2936,6 +2957,16 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
} }
// for proper (non-init) writes: remember if this is a constant index or not
if ((flags & MEM2REG_FL_INIT) == 0) {
if (children[0]->children.size() && children[0]->children[0]->type == AST_RANGE && children[0]->children[0]->children.size()) {
if (children[0]->children[0]->children[0]->type == AST_CONSTANT)
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS;
else
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS;
}
}
// remember where this is // remember where this is
if (flags & MEM2REG_FL_INIT) { if (flags & MEM2REG_FL_INIT) {
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT))
@ -2948,7 +2979,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
} }
} }
ignore_children_counter = 1; lhs_children_counter = 1;
} }
if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY) if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY)
@ -2991,12 +3022,23 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
log_assert((flags & ~0x000000ff) == 0); log_assert((flags & ~0x000000ff) == 0);
for (auto child : children) for (auto child : children)
if (ignore_children_counter > 0) {
ignore_children_counter--; if (lhs_children_counter > 0) {
else if (proc_flags_p) lhs_children_counter--;
if (child->children.size() && child->children[0]->type == AST_RANGE && child->children[0]->children.size()) {
for (auto c : child->children[0]->children) {
if (proc_flags_p)
c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
else
c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
}
}
} else
if (proc_flags_p)
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags); child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
else else
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags); child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
}
flags &= ~children_flags | backup_flags; flags &= ~children_flags | backup_flags;
@ -3048,6 +3090,39 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
if (type == AST_FUNCTION || type == AST_TASK) if (type == AST_FUNCTION || type == AST_TASK)
return false; return false;
if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast))
{
log_assert(children[0]->type == AST_CONSTANT);
log_assert(children[1]->type == AST_CONSTANT);
log_assert(children[2]->type == AST_CONSTANT);
int cursor = children[0]->asInt(false);
Const data = children[1]->bitsAsConst();
int length = children[2]->asInt(false);
if (length != 0)
{
AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK));
mod->children.push_back(block);
block = block->children[0];
int wordsz = GetSize(data) / length;
for (int i = 0; i < length; i++) {
block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false))), mkconst_bits(data.extract(i*wordsz, wordsz).bits, false)));
block->children.back()->children[0]->str = str;
block->children.back()->children[0]->id2ast = id2ast;
block->children.back()->children[0]->was_checked = true;
}
}
AstNode *newNode = new AstNode(AST_NONE);
newNode->cloneInto(this);
delete newNode;
did_something = true;
}
if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set)) if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set))
{ {
if (async_block == NULL) { if (async_block == NULL) {
@ -3277,6 +3352,16 @@ bool AstNode::has_const_only_constructs(bool &recommend_const_eval)
return false; return false;
} }
bool AstNode::is_simple_const_expr()
{
if (type == AST_IDENTIFIER)
return false;
for (auto child : children)
if (!child->is_simple_const_expr())
return false;
return true;
}
// helper function for AstNode::eval_const_function() // helper function for AstNode::eval_const_function()
void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall) void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)
{ {

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

@ -21,7 +21,7 @@ Then run in the following command in this directory:
sby -f example.sby sby -f example.sby
This will generate approximately one page of text outpout. The last lines This will generate approximately one page of text output. The last lines
should be something like this: should be something like this:
SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0) SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0)

View File

@ -1619,30 +1619,35 @@ struct VerificExtNets
int portname_cnt = 0; int portname_cnt = 0;
// a map from Net to the same Net one level up in the design hierarchy // a map from Net to the same Net one level up in the design hierarchy
std::map<Net*, Net*> net_level_up; std::map<Net*, Net*> net_level_up_drive_up;
std::map<Net*, Net*> net_level_up_drive_down;
Net *get_net_level_up(Net *net) Net *route_up(Net *net, bool drive_up, Net *final_net = nullptr)
{ {
auto &net_level_up = drive_up ? net_level_up_drive_up : net_level_up_drive_down;
if (net_level_up.count(net) == 0) if (net_level_up.count(net) == 0)
{ {
Netlist *nl = net->Owner(); Netlist *nl = net->Owner();
// Simply return if Netlist is not unique // Simply return if Netlist is not unique
if (nl->NumOfRefs() != 1) log_assert(nl->NumOfRefs() == 1);
return net;
Instance *up_inst = (Instance*)nl->GetReferences()->GetLast(); Instance *up_inst = (Instance*)nl->GetReferences()->GetLast();
Netlist *up_nl = up_inst->Owner(); Netlist *up_nl = up_inst->Owner();
// create new Port // create new Port
string name = stringf("___extnets_%d", portname_cnt++); string name = stringf("___extnets_%d", portname_cnt++);
Port *new_port = new Port(name.c_str(), DIR_OUT); Port *new_port = new Port(name.c_str(), drive_up ? DIR_OUT : DIR_IN);
nl->Add(new_port); nl->Add(new_port);
net->Connect(new_port); net->Connect(new_port);
// create new Net in up Netlist // create new Net in up Netlist
Net *new_net = new Net(name.c_str()); Net *new_net = final_net;
up_nl->Add(new_net); if (new_net == nullptr || new_net->Owner() != up_nl) {
new_net = new Net(name.c_str());
up_nl->Add(new_net);
}
up_inst->Connect(new_port, new_net); up_inst->Connect(new_port, new_net);
net_level_up[net] = new_net; net_level_up[net] = new_net;
@ -1651,6 +1656,39 @@ struct VerificExtNets
return net_level_up.at(net); return net_level_up.at(net);
} }
Net *route_up(Net *net, bool drive_up, Netlist *dest, Net *final_net = nullptr)
{
while (net->Owner() != dest)
net = route_up(net, drive_up, final_net);
if (final_net != nullptr)
log_assert(net == final_net);
return net;
}
Netlist *find_common_ancestor(Netlist *A, Netlist *B)
{
std::set<Netlist*> ancestors_of_A;
Netlist *cursor = A;
while (1) {
ancestors_of_A.insert(cursor);
if (cursor->NumOfRefs() != 1)
break;
cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
}
cursor = B;
while (1) {
if (ancestors_of_A.count(cursor))
return cursor;
if (cursor->NumOfRefs() != 1)
break;
cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
}
log_error("No common ancestor found between %s and %s.\n", get_full_netlist_name(A).c_str(), get_full_netlist_name(B).c_str());
}
void run(Netlist *nl) void run(Netlist *nl)
{ {
MapIter mi, mi2; MapIter mi, mi2;
@ -1674,19 +1712,37 @@ struct VerificExtNets
if (verific_verbose) if (verific_verbose)
log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name()); log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name());
while (net->IsExternalTo(nl)) Netlist *ext_nl = net->Owner();
{
Net *newnet = get_net_level_up(net);
if (newnet == net) break;
if (verific_verbose)
log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str());
Netlist *ca_nl = find_common_ancestor(nl, ext_nl);
if (verific_verbose)
log(" common ancestor: %s\n", get_full_netlist_name(ca_nl).c_str());
Net *ca_net = route_up(net, !port->IsOutput(), ca_nl);
Net *new_net = ca_net;
if (ca_nl != nl)
{
if (verific_verbose) if (verific_verbose)
log(" external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name()); log(" net in common ancestor: %s\n", ca_net->Name());
net = newnet;
string name = stringf("___extnets_%d", portname_cnt++);
new_net = new Net(name.c_str());
nl->Add(new_net);
Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
log_assert(n == ca_net);
} }
if (verific_verbose) if (verific_verbose)
log(" final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : ""); log(" new local net: %s\n", new_net->Name());
todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, net));
log_assert(!new_net->IsExternalTo(nl));
todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, new_net));
} }
for (auto it : todo_connect) { for (auto it : todo_connect) {
@ -1855,6 +1911,13 @@ struct VerificPass : public Pass {
log(" -autocover\n"); log(" -autocover\n");
log(" Generate automatic cover statements for all asserts\n"); log(" Generate automatic cover statements for all asserts\n");
log("\n"); log("\n");
log(" -chparam name value \n");
log(" Elaborate the specified top modules (all modules when -all given) using\n");
log(" this parameter value. Modules on which this parameter does not exist will\n");
log(" cause Verific to produce a VERI-1928 or VHDL-1676 message. This option\n");
log(" can be specified multiple times to override multiple parameters.\n");
log(" String values must be passed in double quotes (\").\n");
log("\n");
log(" -v, -vv\n"); log(" -v, -vv\n");
log(" Verbose log messages. (-vv is even more verbose than -v.)\n"); log(" Verbose log messages. (-vv is even more verbose than -v.)\n");
log("\n"); log("\n");
@ -2109,6 +2172,7 @@ struct VerificPass : public Pass {
bool mode_autocover = false; bool mode_autocover = false;
bool flatten = false, extnets = false; bool flatten = false, extnets = false;
string dumpfile; string dumpfile;
Map parameters(STRING_HASH);
for (argidx++; argidx < GetSize(args); argidx++) { for (argidx++; argidx < GetSize(args); argidx++) {
if (args[argidx] == "-all") { if (args[argidx] == "-all") {
@ -2147,6 +2211,15 @@ struct VerificPass : public Pass {
mode_autocover = true; mode_autocover = true;
continue; continue;
} }
if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
const std::string &key = args[++argidx];
const std::string &value = args[++argidx];
unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
1 /* force_overwrite */);
if (!new_insertion)
log_warning_noprefix("-chparam %s already specified: overwriting.\n", key.c_str());
continue;
}
if (args[argidx] == "-V") { if (args[argidx] == "-V") {
mode_verific = true; mode_verific = true;
continue; continue;
@ -2180,7 +2253,7 @@ struct VerificPass : public Pass {
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
if (veri_lib) veri_libs.InsertLast(veri_lib); if (veri_lib) veri_libs.InsertLast(veri_lib);
Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs); Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &parameters);
Netlist *nl; Netlist *nl;
int i; int i;
@ -2217,7 +2290,7 @@ struct VerificPass : public Pass {
} }
log("Running hier_tree::Elaborate().\n"); log("Running hier_tree::Elaborate().\n");
Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units); Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &parameters);
Netlist *nl; Netlist *nl;
int i; int i;
@ -2313,21 +2386,43 @@ struct ReadPass : public Pass {
log("\n"); log("\n");
log("Add directory to global Verilog/SystemVerilog include directories.\n"); log("Add directory to global Verilog/SystemVerilog include directories.\n");
log("\n"); log("\n");
log("\n");
log(" read -verific\n");
log(" read -noverific\n");
log("\n");
log("Subsequent calls to 'read' will either use or not use Verific. Calling 'read'\n");
log("with -verific will result in an error on Yosys binaries that are built without\n");
log("Verific support. The default is to use Verific if it is available.\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
{ {
if (args.size() < 2) #ifdef YOSYS_ENABLE_VERIFIC
static bool verific_available = !check_noverific_env();
#else
static bool verific_available = false;
#endif
static bool use_verific = verific_available;
if (args.size() < 2 || args[1][0] != '-')
log_cmd_error("Missing mode parameter.\n"); log_cmd_error("Missing mode parameter.\n");
if (args[1] == "-verific" || args[1] == "-noverific") {
if (args.size() != 2)
log_cmd_error("Additional arguments to -verific/-noverific.\n");
if (args[1] == "-verific") {
if (!verific_available)
log_cmd_error("This version of Yosys is built without Verific support.\n");
use_verific = true;
} else {
use_verific = false;
}
return;
}
if (args.size() < 3) if (args.size() < 3)
log_cmd_error("Missing file name parameter.\n"); log_cmd_error("Missing file name parameter.\n");
#ifdef YOSYS_ENABLE_VERIFIC
bool use_verific = !check_noverific_env();
#else
bool use_verific = false;
#endif
if (args[1] == "-vlog95" || args[1] == "-vlog2k") { if (args[1] == "-vlog95" || args[1] == "-vlog2k") {
if (use_verific) { if (use_verific) {
args[0] = "verific"; args[0] = "verific";

View File

@ -1666,7 +1666,20 @@ struct VerificSvaImporter
log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(), log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(),
LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile())); LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile()));
RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID); bool is_user_declared = root->IsUserDeclared();
// FIXME
if (!is_user_declared) {
const char *name = root->Name();
for (int i = 0; name[i]; i++) {
if (i ? (name[i] < '0' || name[i] > '9') : (name[i] != 'i')) {
is_user_declared = true;
break;
}
}
}
RTLIL::IdString root_name = module->uniquify(importer->mode_names || is_user_declared ? RTLIL::escape_id(root->Name()) : NEW_ID);
// parse SVA sequence into trigger signal // parse SVA sequence into trigger signal

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

@ -81,6 +81,9 @@ struct VerilogFrontend : public Frontend {
log(" -assert-assumes\n"); log(" -assert-assumes\n");
log(" treat all assume() statements like assert() statements\n"); log(" treat all assume() statements like assert() statements\n");
log("\n"); log("\n");
log(" -debug\n");
log(" alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2 -yydebug\n");
log("\n");
log(" -dump_ast1\n"); log(" -dump_ast1\n");
log(" dump abstract syntax tree (before simplification)\n"); log(" dump abstract syntax tree (before simplification)\n");
log("\n"); log("\n");
@ -90,7 +93,10 @@ struct VerilogFrontend : public Frontend {
log(" -no_dump_ptr\n"); log(" -no_dump_ptr\n");
log(" do not include hex memory addresses in dump (easier to diff dumps)\n"); log(" do not include hex memory addresses in dump (easier to diff dumps)\n");
log("\n"); log("\n");
log(" -dump_vlog\n"); log(" -dump_vlog1\n");
log(" dump ast as Verilog code (before simplification)\n");
log("\n");
log(" -dump_vlog2\n");
log(" dump ast as Verilog code (after simplification)\n"); log(" dump ast as Verilog code (after simplification)\n");
log("\n"); log("\n");
log(" -dump_rtlil\n"); log(" -dump_rtlil\n");
@ -197,7 +203,8 @@ struct VerilogFrontend : public Frontend {
bool flag_dump_ast1 = false; bool flag_dump_ast1 = false;
bool flag_dump_ast2 = false; bool flag_dump_ast2 = false;
bool flag_no_dump_ptr = false; bool flag_no_dump_ptr = false;
bool flag_dump_vlog = false; bool flag_dump_vlog1 = false;
bool flag_dump_vlog2 = false;
bool flag_dump_rtlil = false; bool flag_dump_rtlil = false;
bool flag_nolatches = false; bool flag_nolatches = false;
bool flag_nomeminit = false; bool flag_nomeminit = false;
@ -258,6 +265,14 @@ struct VerilogFrontend : public Frontend {
assert_assumes_mode = true; assert_assumes_mode = true;
continue; continue;
} }
if (arg == "-debug") {
flag_dump_ast1 = true;
flag_dump_ast2 = true;
flag_dump_vlog1 = true;
flag_dump_vlog2 = true;
frontend_verilog_yydebug = true;
continue;
}
if (arg == "-dump_ast1") { if (arg == "-dump_ast1") {
flag_dump_ast1 = true; flag_dump_ast1 = true;
continue; continue;
@ -270,8 +285,12 @@ struct VerilogFrontend : public Frontend {
flag_no_dump_ptr = true; flag_no_dump_ptr = true;
continue; continue;
} }
if (arg == "-dump_vlog") { if (arg == "-dump_vlog1") {
flag_dump_vlog = true; flag_dump_vlog1 = true;
continue;
}
if (arg == "-dump_vlog2") {
flag_dump_vlog2 = true;
continue; continue;
} }
if (arg == "-dump_rtlil") { if (arg == "-dump_rtlil") {
@ -410,7 +429,7 @@ 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_vlog, 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, lib_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

@ -189,6 +189,14 @@ YOSYS_NAMESPACE_END
"always_ff" { SV_KEYWORD(TOK_ALWAYS); } "always_ff" { SV_KEYWORD(TOK_ALWAYS); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS); } "always_latch" { SV_KEYWORD(TOK_ALWAYS); }
/* use special token for labels on assert, assume, cover, and restrict because it's insanley complex
to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some
global state.. its a mess) */
[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] {
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
return TOK_SVA_LABEL;
}
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } "assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } "assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } "cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
@ -303,7 +311,7 @@ supply1 { return TOK_SUPPLY1; }
[a-zA-Z_$][a-zA-Z0-9_$\.]* { [a-zA-Z_$][a-zA-Z0-9_$\.]* {
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
return TOK_ID; return TOK_ID;
} }
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {

View File

@ -105,7 +105,8 @@ static void free_attr(std::map<std::string, AstNode*> *al)
bool boolean; bool boolean;
} }
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
@ -119,14 +120,13 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME %token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY %token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY %token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
%type <string> opt_label tok_prim_wrapper hierarchical_id %type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id
%type <boolean> opt_signed opt_property unique_case_attr %type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr %type <al> attr case_attr
@ -1329,6 +1329,14 @@ opt_label:
$$ = NULL; $$ = NULL;
}; };
opt_sva_label:
TOK_SVA_LABEL ':' {
$$ = $1;
} |
/* empty */ {
$$ = NULL;
};
opt_property: opt_property:
TOK_PROPERTY { TOK_PROPERTY {
$$ = true; $$ = true;
@ -1337,9 +1345,6 @@ opt_property:
$$ = false; $$ = false;
}; };
opt_stmt_label:
TOK_ID ':' | /* empty */;
modport_stmt: modport_stmt:
TOK_MODPORT TOK_ID { TOK_MODPORT TOK_ID {
AstNode *modport = new AstNode(AST_MODPORT); AstNode *modport = new AstNode(AST_MODPORT);
@ -1376,83 +1381,164 @@ modport_type_token:
TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;} TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
assert: assert:
opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' { opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' {
if (noassert_mode) if (noassert_mode) {
delete $5; delete $5;
else } else {
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} | } |
opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' { opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' {
if (noassume_mode) if (noassume_mode) {
delete $5; delete $5;
else } else {
ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5)); AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} | } |
opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (noassert_mode) if (noassert_mode) {
delete $6; delete $6;
else } else {
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6)); AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} | } |
opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (noassume_mode) if (noassume_mode) {
delete $6; delete $6;
else } else {
ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6)); AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} | } |
opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' { opt_sva_label TOK_COVER opt_property '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5)); AstNode *node = new AstNode(AST_COVER, $5);
if ($1 != nullptr) {
node->str = *$1;
delete $1;
}
ast_stack.back()->children.push_back(node);
} | } |
opt_stmt_label TOK_COVER opt_property '(' ')' ';' { opt_sva_label TOK_COVER opt_property '(' ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false))); AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
if ($1 != nullptr) {
node->str = *$1;
delete $1;
}
ast_stack.back()->children.push_back(node);
} | } |
opt_stmt_label TOK_COVER ';' { opt_sva_label TOK_COVER ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false))); AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
if ($1 != nullptr) {
node->str = *$1;
delete $1;
}
ast_stack.back()->children.push_back(node);
} | } |
opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' { opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' {
if (norestrict_mode) if (norestrict_mode) {
delete $5; delete $5;
else } else {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); AstNode *node = new AstNode(AST_ASSUME, $5);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if (!$3) if (!$3)
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
if ($1 != nullptr)
delete $1;
} | } |
opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (norestrict_mode) if (norestrict_mode) {
delete $6; delete $6;
else } else {
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); AstNode *node = new AstNode(AST_FAIR, $6);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if (!$3) if (!$3)
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
if ($1 != nullptr)
delete $1;
}; };
assert_property: assert_property:
TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4)); ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} | } |
TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} | } |
TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5)); ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} | } |
TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5)); ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} | } |
TOK_COVER TOK_PROPERTY '(' expr ')' ';' { opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4)); ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} | } |
TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
if (norestrict_mode) if (norestrict_mode) {
delete $4;
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
} |
TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
if (norestrict_mode)
delete $5; delete $5;
else } else {
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5)); ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
}
} |
opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
if (norestrict_mode) {
delete $6;
} else {
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
}
}; };
simple_behavioral_stmt: simple_behavioral_stmt:
@ -1670,6 +1756,11 @@ case_expr_list:
TOK_DEFAULT { TOK_DEFAULT {
ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT)); ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT));
} | } |
TOK_SVA_LABEL {
ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER));
ast_stack.back()->children.back()->str = *$1;
delete $1;
} |
expr { expr {
ast_stack.back()->children.push_back($1); ast_stack.back()->children.push_back($1);
} | } |

View File

@ -81,6 +81,27 @@ struct CellTypes
} }
void setup_internals() void setup_internals()
{
setup_internals_eval();
IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
setup_type("$tribuf", {A, EN}, {Y}, true);
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$equiv", {A, B}, {Y}, true);
}
void setup_internals_eval()
{ {
std::vector<RTLIL::IdString> unary_ops = { std::vector<RTLIL::IdString> unary_ops = {
"$not", "$pos", "$neg", "$not", "$pos", "$neg",
@ -111,20 +132,6 @@ struct CellTypes
setup_type("$lcu", {P, G, CI}, {CO}, true); setup_type("$lcu", {P, G, CI}, {CO}, true);
setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true); setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true);
setup_type("$fa", {A, B, C}, {X, Y}, true); setup_type("$fa", {A, B, C}, {X, Y}, true);
setup_type("$tribuf", {A, EN}, {Y}, true);
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$equiv", {A, B}, {Y}, true);
} }
void setup_internals_mem() void setup_internals_mem()
@ -153,6 +160,15 @@ struct CellTypes
} }
void setup_stdcells() void setup_stdcells()
{
setup_stdcells_eval();
IdString A = "\\A", E = "\\E", Y = "\\Y";
setup_type("$_TBUF_", {A, E}, {Y}, true);
}
void setup_stdcells_eval()
{ {
IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D"; IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D";
IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H"; IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H";
@ -179,7 +195,6 @@ struct CellTypes
setup_type("$_OAI3_", {A, B, C}, {Y}, true); setup_type("$_OAI3_", {A, B, C}, {Y}, true);
setup_type("$_AOI4_", {A, B, C, D}, {Y}, true); setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
setup_type("$_OAI4_", {A, B, C, D}, {Y}, true); setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
setup_type("$_TBUF_", {A, E}, {Y}, true);
} }
void setup_stdcells_mem() void setup_stdcells_mem()

View File

@ -557,9 +557,11 @@ public:
void clear() { hashtable.clear(); entries.clear(); } void clear() { hashtable.clear(); entries.clear(); }
iterator begin() { return iterator(this, int(entries.size())-1); } iterator begin() { return iterator(this, int(entries.size())-1); }
iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
iterator end() { return iterator(nullptr, -1); } iterator end() { return iterator(nullptr, -1); }
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); } const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
const_iterator end() const { return const_iterator(nullptr, -1); } const_iterator end() const { return const_iterator(nullptr, -1); }
}; };
@ -881,9 +883,11 @@ public:
void clear() { hashtable.clear(); entries.clear(); } void clear() { hashtable.clear(); entries.clear(); }
iterator begin() { return iterator(this, int(entries.size())-1); } iterator begin() { return iterator(this, int(entries.size())-1); }
iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
iterator end() { return iterator(nullptr, -1); } iterator end() { return iterator(nullptr, -1); }
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); } const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
const_iterator end() const { return const_iterator(nullptr, -1); } const_iterator end() const { return const_iterator(nullptr, -1); }
}; };
@ -952,6 +956,7 @@ public:
void clear() { database.clear(); } void clear() { database.clear(); }
const_iterator begin() const { return database.begin(); } const_iterator begin() const { return database.begin(); }
const_iterator element(int n) const { return database.element(n); }
const_iterator end() const { return database.end(); } const_iterator end() const { return database.end(); }
}; };
@ -1051,6 +1056,7 @@ public:
void clear() { database.clear(); parents.clear(); } void clear() { database.clear(); parents.clear(); }
const_iterator begin() const { return database.begin(); } const_iterator begin() const { return database.begin(); }
const_iterator element(int n) const { return database.element(n); }
const_iterator end() const { return database.end(); } const_iterator end() const { return database.end(); }
}; };

View File

@ -196,7 +196,11 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap)
if (log_hdump.count(header_id) && design != nullptr) if (log_hdump.count(header_id) && design != nullptr)
for (auto &filename : log_hdump.at(header_id)) { for (auto &filename : log_hdump.at(header_id)) {
log("Dumping current design to '%s'.\n", filename.c_str()); log("Dumping current design to '%s'.\n", filename.c_str());
if (yosys_xtrace)
IdString::xtrace_db_dump();
Pass::call(design, {"dump", "-o", filename}); Pass::call(design, {"dump", "-o", filename});
if (yosys_xtrace)
log("#X# -- end of dump --\n");
} }
if (pop_errfile) if (pop_errfile)

View File

@ -86,6 +86,8 @@ 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();
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;
current_pass = state.parent_pass; current_pass = state.parent_pass;

View File

@ -33,6 +33,8 @@ std::vector<int> RTLIL::IdString::global_refcount_storage_;
std::vector<char*> RTLIL::IdString::global_id_storage_; std::vector<char*> RTLIL::IdString::global_id_storage_;
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_; dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
std::vector<int> RTLIL::IdString::global_free_idx_list_; std::vector<int> RTLIL::IdString::global_free_idx_list_;
int RTLIL::IdString::last_created_idx_[8];
int RTLIL::IdString::last_created_idx_ptr_;
RTLIL::Const::Const() RTLIL::Const::Const()
{ {
@ -639,6 +641,30 @@ RTLIL::Module::~Module()
delete it->second; delete it->second;
} }
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));
@ -758,7 +784,7 @@ namespace {
void check() void check()
{ {
if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || cell->type.substr(0,10) == "$fmcombine" ||
cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:") cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
return; return;
@ -2358,7 +2384,7 @@ void RTLIL::Cell::check()
void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
{ {
if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || type.substr(0,10) == "$fmcombine" ||
type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:") type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:")
return; return;
@ -3235,7 +3261,7 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed)
remove(width, width_ - width); remove(width, width_ - width);
if (width_ < width) { if (width_ < width) {
RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::S0; RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx;
if (!is_signed) if (!is_signed)
padding = RTLIL::State::S0; padding = RTLIL::State::S0;
while (width_ < width) while (width_ < width)

View File

@ -76,6 +76,9 @@ namespace RTLIL
struct IdString struct IdString
{ {
#undef YOSYS_XTRACE_GET_PUT
#undef YOSYS_SORT_ID_FREE_LIST
// the global id string cache // the global id string cache
static struct destruct_guard_t { static struct destruct_guard_t {
@ -89,9 +92,43 @@ namespace RTLIL
static dict<char*, int, hash_cstr_ops> global_id_index_; static dict<char*, int, hash_cstr_ops> global_id_index_;
static std::vector<int> global_free_idx_list_; static std::vector<int> global_free_idx_list_;
static int last_created_idx_ptr_;
static int last_created_idx_[8];
static inline void xtrace_db_dump()
{
#ifdef YOSYS_XTRACE_GET_PUT
for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
{
if (global_id_storage_.at(idx) == nullptr)
log("#X# DB-DUMP index %d: FREE\n", idx);
else
log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
}
#endif
}
static inline void checkpoint()
{
last_created_idx_ptr_ = 0;
for (int i = 0; i < 8; i++) {
if (last_created_idx_[i])
put_reference(last_created_idx_[i]);
last_created_idx_[i] = 0;
}
#ifdef YOSYS_SORT_ID_FREE_LIST
std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
#endif
}
static inline int get_reference(int idx) static inline int get_reference(int idx)
{ {
global_refcount_storage_.at(idx)++; global_refcount_storage_.at(idx)++;
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace) {
log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
}
#endif
return idx; return idx;
} }
@ -107,6 +144,11 @@ namespace RTLIL
auto it = global_id_index_.find((char*)p); auto it = global_id_index_.find((char*)p);
if (it != global_id_index_.end()) { if (it != global_id_index_.end()) {
global_refcount_storage_.at(it->second)++; global_refcount_storage_.at(it->second)++;
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace) {
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));
}
#endif
return it->second; return it->second;
} }
@ -124,16 +166,22 @@ namespace RTLIL
global_refcount_storage_.at(idx)++; global_refcount_storage_.at(idx)++;
// Avoid Create->Delete->Create pattern // Avoid Create->Delete->Create pattern
static IdString last_created_id; if (last_created_idx_[last_created_idx_ptr_])
put_reference(last_created_id.index_); put_reference(last_created_idx_[last_created_idx_ptr_]);
last_created_id.index_ = idx; last_created_idx_[last_created_idx_ptr_] = idx;
get_reference(last_created_id.index_); get_reference(last_created_idx_[last_created_idx_ptr_]);
last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;
if (yosys_xtrace) { if (yosys_xtrace) {
log("#X# New IdString '%s' with index %d.\n", p, idx); log("#X# New IdString '%s' with index %d.\n", p, idx);
log_backtrace("-X- ", yosys_xtrace-1); log_backtrace("-X- ", yosys_xtrace-1);
} }
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace) {
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
}
#endif
return idx; return idx;
} }
@ -144,6 +192,12 @@ namespace RTLIL
if (!destruct_guard.ok) if (!destruct_guard.ok)
return; return;
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace) {
log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
}
#endif
log_assert(global_refcount_storage_.at(idx) > 0); log_assert(global_refcount_storage_.at(idx) > 0);
if (--global_refcount_storage_.at(idx) != 0) if (--global_refcount_storage_.at(idx) != 0)
@ -498,6 +552,14 @@ struct RTLIL::Const
return ret; return ret;
} }
void extu(int width) {
bits.resize(width, RTLIL::State::S0);
}
void exts(int width) {
bits.resize(width, bits.empty() ? RTLIL::State::Sx : bits.back());
}
inline unsigned int hash() const { inline unsigned int hash() const {
unsigned int h = mkhash_init; unsigned int h = mkhash_init;
for (auto b : bits) for (auto b : bits)
@ -920,6 +982,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);
@ -1288,7 +1351,7 @@ inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
return wire ? (offset < other.offset) : (data < other.data); return wire ? (offset < other.offset) : (data < other.data);
if (wire != nullptr && other.wire != nullptr) if (wire != nullptr && other.wire != nullptr)
return wire->name < other.wire->name; return wire->name < other.wire->name;
return wire < other.wire; return (wire != nullptr) < (other.wire != nullptr);
} }
inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const { inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {

View File

@ -33,7 +33,7 @@
# include <dlfcn.h> # include <dlfcn.h>
#endif #endif
#ifdef _WIN32 #if defined(_WIN32)
# include <windows.h> # include <windows.h>
# include <io.h> # include <io.h>
#elif defined(__APPLE__) #elif defined(__APPLE__)
@ -41,13 +41,15 @@
# include <unistd.h> # include <unistd.h>
# include <dirent.h> # include <dirent.h>
# include <sys/stat.h> # include <sys/stat.h>
# include <glob.h>
#else #else
# include <unistd.h> # include <unistd.h>
# include <dirent.h> # include <dirent.h>
# include <sys/types.h> # include <sys/types.h>
# include <sys/wait.h> # include <sys/wait.h>
# include <sys/stat.h> # include <sys/stat.h>
#endif
#if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB)
# include <glob.h> # include <glob.h>
#endif #endif
@ -216,12 +218,18 @@ std::string next_token(std::string &text, const char *sep, bool long_strings)
if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') { if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') {
string sep_string = sep; string sep_string = sep;
for (size_t i = pos_begin+1; i < text.size(); i++) for (size_t i = pos_begin+1; i < text.size(); i++) {
if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) { if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) {
std::string token = text.substr(pos_begin, i-pos_begin+1); std::string token = text.substr(pos_begin, i-pos_begin+1);
text = text.substr(i+1); text = text.substr(i+1);
return token; return token;
} }
if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) {
std::string token = text.substr(pos_begin, i-pos_begin+1);
text = text.substr(i+2);
return token + ";";
}
}
} }
size_t pos_end = text.find_first_of(sep, pos_begin); size_t pos_end = text.find_first_of(sep, pos_begin);
@ -564,7 +572,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern)
{ {
std::vector<std::string> results; std::vector<std::string> results;
#ifdef _WIN32 #if defined(_WIN32) || !defined(YOSYS_ENABLE_GLOB)
results.push_back(filename_pattern); results.push_back(filename_pattern);
#else #else
glob_t globbuf; glob_t globbuf;

358
misc/launcher.c Normal file
View File

@ -0,0 +1,358 @@
/* This file comes from the PyPA Setuptools repository, commit 16e452a:
https://github.com/pypa/setuptools
Modifications include this comment and inline inclusion of the LICENSE text. */
/* Copyright (C) 2016 Jason R Coombs <jaraco@jaraco.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. */
/* Setuptools Script Launcher for Windows
This is a stub executable for Windows that functions somewhat like
Effbot's "exemaker", in that it runs a script with the same name but
a .py extension, using information from a #! line. It differs in that
it spawns the actual Python executable, rather than attempting to
hook into the Python DLL. This means that the script will run with
sys.executable set to the Python executable, where exemaker ends up with
sys.executable pointing to itself. (Which means it won't work if you try
to run another Python process using sys.executable.)
To build/rebuild with mingw32, do this in the setuptools project directory:
gcc -DGUI=0 -mno-cygwin -O -s -o setuptools/cli.exe launcher.c
gcc -DGUI=1 -mwindows -mno-cygwin -O -s -o setuptools/gui.exe launcher.c
To build for Windows RT, install both Visual Studio Express for Windows 8
and for Windows Desktop (both freeware), create "win32" application using
"Windows Desktop" version, create new "ARM" target via
"Configuration Manager" menu and modify ".vcxproj" file by adding
"<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>" tag
as child of "PropertyGroup" tags that has "Debug|ARM" and "Release|ARM"
properties.
It links to msvcrt.dll, but this shouldn't be a problem since it doesn't
actually run Python in the same process. Note that using 'exec' instead
of 'spawn' doesn't work, because on Windows this leads to the Python
executable running in the *background*, attached to the same console
window, meaning you get a command prompt back *before* Python even finishes
starting. So, we have to use spawnv() and wait for Python to exit before
continuing. :(
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <tchar.h>
#include <fcntl.h>
int child_pid=0;
int fail(char *format, char *data) {
/* Print error message to stderr and return 2 */
fprintf(stderr, format, data);
return 2;
}
char *quoted(char *data) {
int i, ln = strlen(data), nb;
/* We allocate twice as much space as needed to deal with worse-case
of having to escape everything. */
char *result = calloc(ln*2+3, sizeof(char));
char *presult = result;
*presult++ = '"';
for (nb=0, i=0; i < ln; i++)
{
if (data[i] == '\\')
nb += 1;
else if (data[i] == '"')
{
for (; nb > 0; nb--)
*presult++ = '\\';
*presult++ = '\\';
}
else
nb = 0;
*presult++ = data[i];
}
for (; nb > 0; nb--) /* Deal w trailing slashes */
*presult++ = '\\';
*presult++ = '"';
*presult++ = 0;
return result;
}
char *loadable_exe(char *exename) {
/* HINSTANCE hPython; DLL handle for python executable */
char *result;
/* hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (!hPython) return NULL; */
/* Return the absolute filename for spawnv */
result = calloc(MAX_PATH, sizeof(char));
strncpy(result, exename, MAX_PATH);
/*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
FreeLibrary(hPython); */
return result;
}
char *find_exe(char *exename, char *script) {
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
char path[_MAX_PATH], c, *result;
/* convert slashes to backslashes for uniform search below */
result = exename;
while (c = *result++) if (c=='/') result[-1] = '\\';
_splitpath(exename, drive, dir, fname, ext);
if (drive[0] || dir[0]=='\\') {
return loadable_exe(exename); /* absolute path, use directly */
}
/* Use the script's parent directory, which should be the Python home
(This should only be used for bdist_wininst-installed scripts, because
easy_install-ed scripts use the absolute path to python[w].exe
*/
_splitpath(script, drive, dir, fname, ext);
result = dir + strlen(dir) -1;
if (*result == '\\') result--;
while (*result != '\\' && result>=dir) *result-- = 0;
_makepath(path, drive, dir, exename, NULL);
return loadable_exe(path);
}
char **parse_argv(char *cmdline, int *argc)
{
/* Parse a command line in-place using MS C rules */
char **result = calloc(strlen(cmdline), sizeof(char *));
char *output = cmdline;
char c;
int nb = 0;
int iq = 0;
*argc = 0;
result[0] = output;
while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
do {
c = *cmdline++;
if (!c || (isspace(c) && !iq)) {
while (nb) {*output++ = '\\'; nb--; }
*output++ = 0;
result[++*argc] = output;
if (!c) return result;
while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
if (!*cmdline) return result; /* avoid empty arg if trailing ws */
continue;
}
if (c == '\\')
++nb; /* count \'s */
else {
if (c == '"') {
if (!(nb & 1)) { iq = !iq; c = 0; } /* skip " unless odd # of \ */
nb = nb >> 1; /* cut \'s in half */
}
while (nb) {*output++ = '\\'; nb--; }
if (c) *output++ = c;
}
} while (1);
}
void pass_control_to_child(DWORD control_type) {
/*
* distribute-issue207
* passes the control event to child process (Python)
*/
if (!child_pid) {
return;
}
GenerateConsoleCtrlEvent(child_pid,0);
}
BOOL control_handler(DWORD control_type) {
/*
* distribute-issue207
* control event handler callback function
*/
switch (control_type) {
case CTRL_C_EVENT:
pass_control_to_child(0);
break;
}
return TRUE;
}
int create_and_wait_for_subprocess(char* command) {
/*
* distribute-issue207
* launches child process (Python)
*/
DWORD return_value = 0;
LPSTR commandline = command;
STARTUPINFOA s_info;
PROCESS_INFORMATION p_info;
ZeroMemory(&p_info, sizeof(p_info));
ZeroMemory(&s_info, sizeof(s_info));
s_info.cb = sizeof(STARTUPINFO);
// set-up control handler callback funciotn
SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE);
if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) {
fprintf(stderr, "failed to create process.\n");
return 0;
}
child_pid = p_info.dwProcessId;
// wait for Python to exit
WaitForSingleObject(p_info.hProcess, INFINITE);
if (!GetExitCodeProcess(p_info.hProcess, &return_value)) {
fprintf(stderr, "failed to get exit code from process.\n");
return 0;
}
return return_value;
}
char* join_executable_and_args(char *executable, char **args, int argc)
{
/*
* distribute-issue207
* CreateProcess needs a long string of the executable and command-line arguments,
* so we need to convert it from the args that was built
*/
int len,counter;
char* cmdline;
len=strlen(executable)+2;
for (counter=1; counter<argc; counter++) {
len+=strlen(args[counter])+1;
}
cmdline = (char*)calloc(len, sizeof(char));
sprintf(cmdline, "%s", executable);
len=strlen(executable);
for (counter=1; counter<argc; counter++) {
sprintf(cmdline+len, " %s", args[counter]);
len+=strlen(args[counter])+1;
}
return cmdline;
}
int run(int argc, char **argv, int is_gui) {
char python[256]; /* python executable's filename*/
char *pyopt; /* Python option */
char script[256]; /* the script's filename */
int scriptf; /* file descriptor for script file */
char **newargs, **newargsp, **parsedargs; /* argument array for exec */
char *ptr, *end; /* working pointers for string manipulation */
char *cmdline;
int i, parsedargc; /* loop counter */
/* compute script name from our .exe name*/
GetModuleFileNameA(NULL, script, sizeof(script));
end = script + strlen(script);
while( end>script && *end != '.')
*end-- = '\0';
*end-- = '\0';
strcat(script, (GUI ? "-script.pyw" : "-script.py"));
/* figure out the target python executable */
scriptf = open(script, O_RDONLY);
if (scriptf == -1) {
return fail("Cannot open %s\n", script);
}
end = python + read(scriptf, python, sizeof(python));
close(scriptf);
ptr = python-1;
while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {;}
*ptr-- = '\0';
if (strncmp(python, "#!", 2)) {
/* default to python.exe if no #! header */
strcpy(python, "#!python.exe");
}
parsedargs = parse_argv(python+2, &parsedargc);
/* Using spawnv() can fail strangely if you e.g. find the Cygwin
Python, so we'll make sure Windows can find and load it */
ptr = find_exe(parsedargs[0], script);
if (!ptr) {
return fail("Cannot find Python executable %s\n", parsedargs[0]);
}
/* printf("Python executable: %s\n", ptr); */
/* Argument array needs to be
parsedargc + argc, plus 1 for null sentinel */
newargs = (char **)calloc(parsedargc + argc + 1, sizeof(char *));
newargsp = newargs;
*newargsp++ = quoted(ptr);
for (i = 1; i<parsedargc; i++) *newargsp++ = quoted(parsedargs[i]);
*newargsp++ = quoted(script);
for (i = 1; i < argc; i++) *newargsp++ = quoted(argv[i]);
*newargsp++ = NULL;
/* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */
if (is_gui) {
/* Use exec, we don't need to wait for the GUI to finish */
execv(ptr, (const char * const *)(newargs));
return fail("Could not exec %s", ptr); /* shouldn't get here! */
}
/*
* distribute-issue207: using CreateProcessA instead of spawnv
*/
cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc);
return create_and_wait_for_subprocess(cmdline);
}
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
return run(__argc, __argv, GUI);
}
int main(int argc, char** argv) {
return run(argc, argv, GUI);
}

View File

@ -1,12 +1,12 @@
// //
// yosys -- Yosys Open SYnthesis Suite // yosys -- Yosys Open SYnthesis Suite
// //
// Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com> // Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
// //
// Permission to use, copy, modify, and/or distribute this software for any // Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above // purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies. // copyright notice and this permission notice appear in all copies.
// //
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@ -73,7 +73,7 @@ message Module {
BitVector bits = 2; BitVector bits = 2;
} }
map<string, Port> port = 2; map<string, Port> port = 2;
// Named cells in this module. // Named cells in this module.
message Cell { message Cell {
// Set to true when the name of this cell is automatically created and // Set to true when the name of this cell is automatically created and
@ -129,7 +129,7 @@ message Model {
TYPE_FALSE = 6; TYPE_FALSE = 6;
}; };
Type type = 1; Type type = 1;
message Port { message Port {
// Name of port. // Name of port.
string portname = 1; string portname = 1;
@ -148,7 +148,7 @@ message Model {
// Set for AND, NAND. // Set for AND, NAND.
Gate gate = 3; Gate gate = 3;
} }
// Set when the node drives given output port(s). // Set when the node drives given output port(s).
message OutPort { message OutPort {
// Name of port. // Name of port.

View File

@ -24,7 +24,7 @@
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name) static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name, bool flag_output)
{ {
from_name = RTLIL::escape_id(from_name); from_name = RTLIL::escape_id(from_name);
to_name = RTLIL::escape_id(to_name); to_name = RTLIL::escape_id(to_name);
@ -37,13 +37,18 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
Wire *w = it.second; Wire *w = it.second;
log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module)); log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module));
module->rename(w, to_name); module->rename(w, to_name);
if (w->port_id) if (w->port_id || flag_output) {
if (flag_output)
w->port_output = true;
module->fixup_ports(); module->fixup_ports();
}
return; return;
} }
for (auto &it : module->cells_) for (auto &it : module->cells_)
if (it.first == from_name) { if (it.first == from_name) {
if (flag_output)
log_cmd_error("Called with -output but the specified object is a cell.\n");
log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module)); log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
module->rename(it.second, to_name); module->rename(it.second, to_name);
return; return;
@ -108,15 +113,26 @@ struct RenamePass : public Pass {
log("Rename the specified object. Note that selection patterns are not supported\n"); log("Rename the specified object. Note that selection patterns are not supported\n");
log("by this command.\n"); log("by this command.\n");
log("\n"); log("\n");
log("\n");
log("\n");
log(" rename -output old_name new_name\n");
log("\n");
log("Like above, but also make the wire an output. This will fail if the object is\n");
log("not a wire.\n");
log("\n");
log("\n");
log(" rename -src [selection]\n"); log(" rename -src [selection]\n");
log("\n"); log("\n");
log("Assign names auto-generated from the src attribute to all selected wires and\n"); log("Assign names auto-generated from the src attribute to all selected wires and\n");
log("cells with private names.\n"); log("cells with private names.\n");
log("\n"); log("\n");
log("\n");
log(" rename -wire [selection]\n"); log(" rename -wire [selection]\n");
log("\n");
log("Assign auto-generated names based on the wires they drive to all selected\n"); log("Assign auto-generated names based on the wires they drive to all selected\n");
log("cells with private names. Ignores cells driving privatly named wires.\n"); log("cells with private names. Ignores cells driving privatly named wires.\n");
log("\n"); log("\n");
log("\n");
log(" rename -enumerate [-pattern <pattern>] [selection]\n"); log(" rename -enumerate [-pattern <pattern>] [selection]\n");
log("\n"); log("\n");
log("Assign short auto-generated names to all selected wires and cells with private\n"); log("Assign short auto-generated names to all selected wires and cells with private\n");
@ -124,11 +140,13 @@ struct RenamePass : public Pass {
log("The character %% in the pattern is replaced with a integer number. The default\n"); log("The character %% in the pattern is replaced with a integer number. The default\n");
log("pattern is '_%%_'.\n"); log("pattern is '_%%_'.\n");
log("\n"); log("\n");
log("\n");
log(" rename -hide [selection]\n"); log(" rename -hide [selection]\n");
log("\n"); log("\n");
log("Assign private names (the ones with $-prefix) to all selected wires and cells\n"); log("Assign private names (the ones with $-prefix) to all selected wires and cells\n");
log("with public names. This ignores all selected ports.\n"); log("with public names. This ignores all selected ports.\n");
log("\n"); log("\n");
log("\n");
log(" rename -top new_name\n"); log(" rename -top new_name\n");
log("\n"); log("\n");
log("Rename top module.\n"); log("Rename top module.\n");
@ -142,6 +160,7 @@ struct RenamePass : public Pass {
bool flag_enumerate = false; bool flag_enumerate = false;
bool flag_hide = false; bool flag_hide = false;
bool flag_top = false; bool flag_top = false;
bool flag_output = false;
bool got_mode = false; bool got_mode = false;
size_t argidx; size_t argidx;
@ -153,6 +172,11 @@ struct RenamePass : public Pass {
got_mode = true; got_mode = true;
continue; continue;
} }
if (arg == "-output" && !got_mode) {
flag_output = true;
got_mode = true;
continue;
}
if (arg == "-wire" && !got_mode) { if (arg == "-wire" && !got_mode) {
flag_wire = true; flag_wire = true;
got_mode = true; got_mode = true;
@ -322,10 +346,12 @@ struct RenamePass : public Pass {
if (!design->selected_active_module.empty()) if (!design->selected_active_module.empty())
{ {
if (design->modules_.count(design->selected_active_module) > 0) if (design->modules_.count(design->selected_active_module) > 0)
rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name); rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name, flag_output);
} }
else else
{ {
if (flag_output)
log_cmd_error("Mode -output requires that there is an active module selected.\n");
for (auto &mod : design->modules_) { for (auto &mod : design->modules_) {
if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) { if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) {
to_name = RTLIL::escape_id(to_name); to_name = RTLIL::escape_id(to_name);

View File

@ -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()) { if (m->get_bool_attribute("\\blackbox") && !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

@ -87,6 +87,8 @@ struct UniquifyPass : public Pass {
smod->name = newname; smod->name = newname;
cell->type = newname; cell->type = newname;
smod->set_bool_attribute("\\unique"); smod->set_bool_attribute("\\unique");
if (smod->attributes.count("\\hdlname") == 0)
smod->attributes["\\hdlname"] = string(log_id(tmod->name));
design->add(smod); design->add(smod);
did_something = true; did_something = true;

View File

@ -542,7 +542,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
} }
// assign write ports // assign write ports
pair<SigBit, bool> wr_clkdom;
for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++) for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++)
{ {
bool clken = wr_clken[cell_port_i] == State::S1; bool clken = wr_clken[cell_port_i] == State::S1;
@ -552,7 +552,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
pair<SigBit, bool> clkdom(clksig, clkpol); pair<SigBit, bool> clkdom(clksig, clkpol);
if (!clken) if (!clken)
clkdom = pair<SigBit, bool>(State::S1, false); clkdom = pair<SigBit, bool>(State::S1, false);
wr_clkdom = clkdom;
log(" Write port #%d is in clock domain %s%s.\n", log(" Write port #%d is in clock domain %s%s.\n",
cell_port_i, clkdom.second ? "" : "!", cell_port_i, clkdom.second ? "" : "!",
clken ? log_signal(clkdom.first) : "~async~"); clken ? log_signal(clkdom.first) : "~async~");
@ -641,6 +641,7 @@ grow_read_ports:;
pi.sig_data = SigSpec(); pi.sig_data = SigSpec();
pi.sig_en = SigSpec(); pi.sig_en = SigSpec();
pi.make_outreg = false; pi.make_outreg = false;
pi.make_transp = false;
} }
new_portinfos.push_back(pi); new_portinfos.push_back(pi);
if (pi.dupidx == dup_count-1) { if (pi.dupidx == dup_count-1) {
@ -718,7 +719,13 @@ grow_read_ports:;
if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) { if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) {
if (match.make_transp && wr_ports <= 1) { if (match.make_transp && wr_ports <= 1) {
pi.make_transp = true; pi.make_transp = true;
enable_make_transp = true; if (pi.clocks != 0) {
if (wr_ports == 1 && wr_clkdom != clkdom) {
log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
}
enable_make_transp = true;
}
} else { } else {
log(" Bram port %c%d.%d has incompatible read transparency.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); log(" Bram port %c%d.%d has incompatible read transparency.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport; goto skip_bram_rport;
@ -737,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;
@ -913,17 +921,18 @@ grow_read_ports:;
} else { } else {
SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits); SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits);
c->setPort(stringf("\\%sDATA", pf), bram_dout); c->setPort(stringf("\\%sDATA", pf), bram_dout);
if (pi.make_outreg && pi.make_transp) {
if (pi.make_outreg) { log(" Moving output register to address for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
SigSpec sig_addr_q = module->addWire(NEW_ID, bram.abits);
module->addDff(NEW_ID, pi.sig_clock, sig_addr, sig_addr_q, pi.effective_clkpol);
c->setPort(stringf("\\%sADDR", pf), sig_addr_q);
} else if (pi.make_outreg) {
SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits); SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits);
if (!pi.sig_en.empty()) if (!pi.sig_en.empty())
bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en); bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en);
module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol); module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol);
bram_dout = bram_dout_q; bram_dout = bram_dout_q;
} } else if (pi.make_transp) {
if (pi.make_transp)
{
log(" Adding extra logic for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); log(" Adding extra logic for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
SigSpec transp_en_d = module->Mux(NEW_ID, SigSpec(0, make_transp_enbits), SigSpec transp_en_d = module->Mux(NEW_ID, SigSpec(0, make_transp_enbits),
@ -949,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

@ -155,6 +155,13 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
new_b.append_bit(it.first.second); new_b.append_bit(it.first.second);
} }
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));
module->connect(new_y, new_b);
module->connect(new_conn);
continue;
}
RTLIL::Cell *c = module->addCell(NEW_ID, cell->type); RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
c->setPort("\\A", new_a); c->setPort("\\A", new_a);

View File

@ -53,6 +53,8 @@ struct WreduceWorker
std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells; std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
std::set<SigBit> work_queue_bits; std::set<SigBit> work_queue_bits;
pool<SigBit> keep_bits; pool<SigBit> keep_bits;
dict<SigBit, State> init_bits;
pool<SigBit> remove_init_bits;
WreduceWorker(WreduceConfig *config, Module *module) : WreduceWorker(WreduceConfig *config, Module *module) :
config(config), module(module), mi(module) { } config(config), module(module), mi(module) { }
@ -141,6 +143,7 @@ struct WreduceWorker
SigSpec sig_d = mi.sigmap(cell->getPort("\\D")); SigSpec sig_d = mi.sigmap(cell->getPort("\\D"));
SigSpec sig_q = mi.sigmap(cell->getPort("\\Q")); SigSpec sig_q = mi.sigmap(cell->getPort("\\Q"));
Const initval;
int width_before = GetSize(sig_q); int width_before = GetSize(sig_q);
@ -150,24 +153,35 @@ struct WreduceWorker
bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0; bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0;
bool sign_ext = !zero_ext; bool sign_ext = !zero_ext;
for (int i = 0; i < GetSize(sig_q); i++) {
SigBit bit = sig_q[i];
if (init_bits.count(bit))
initval.bits.push_back(init_bits.at(bit));
else
initval.bits.push_back(State::Sx);
}
for (int i = GetSize(sig_q)-1; i >= 0; i--) for (int i = GetSize(sig_q)-1; i >= 0; i--)
{ {
if (zero_ext && sig_d[i] == State::S0) { if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) {
module->connect(sig_q[i], State::S0); module->connect(sig_q[i], State::S0);
remove_init_bits.insert(sig_q[i]);
sig_d.remove(i); sig_d.remove(i);
sig_q.remove(i); sig_q.remove(i);
continue; continue;
} }
if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1]) { if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) {
module->connect(sig_q[i], sig_q[i-1]); module->connect(sig_q[i], sig_q[i-1]);
remove_init_bits.insert(sig_q[i]);
sig_d.remove(i); sig_d.remove(i);
sig_q.remove(i); sig_q.remove(i);
continue; continue;
} }
auto info = mi.query(sig_q[i]); auto info = mi.query(sig_q[i]);
if (!info->is_output && GetSize(info->ports) <= 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) { if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
remove_init_bits.insert(sig_q[i]);
sig_d.remove(i); sig_d.remove(i);
sig_q.remove(i); sig_q.remove(i);
zero_ext = false; zero_ext = false;
@ -183,10 +197,11 @@ struct WreduceWorker
if (GetSize(sig_q) == 0) { if (GetSize(sig_q) == 0) {
log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type)); log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
module->remove(cell);
return; return;
} }
log("Removed top %d bits (of %d) from mux cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before, log("Removed top %d bits (of %d) from FF cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before,
log_id(module), log_id(cell), log_id(cell->type)); log_id(module), log_id(cell), log_id(cell->type));
for (auto bit : sig_d) for (auto bit : sig_d)
@ -376,10 +391,21 @@ struct WreduceWorker
void run() void run()
{ {
for (auto w : module->wires()) // create a copy as mi.sigmap will be updated as we process the module
SigMap init_attr_sigmap = mi.sigmap;
for (auto w : module->wires()) {
if (w->get_bool_attribute("\\keep")) if (w->get_bool_attribute("\\keep"))
for (auto bit : mi.sigmap(w)) for (auto bit : mi.sigmap(w))
keep_bits.insert(bit); keep_bits.insert(bit);
if (w->attributes.count("\\init")) {
Const initval = w->attributes.at("\\init");
SigSpec initsig = init_attr_sigmap(w);
int width = std::min(GetSize(initval), GetSize(initsig));
for (int i = 0; i < width; i++)
init_bits[initsig[i]] = initval[i];
}
}
for (auto c : module->selected_cells()) for (auto c : module->selected_cells())
work_queue_cells.insert(c); work_queue_cells.insert(c);
@ -427,6 +453,24 @@ struct WreduceWorker
module->connect(nw, SigSpec(w).extract(0, GetSize(nw))); module->connect(nw, SigSpec(w).extract(0, GetSize(nw)));
module->swap_names(w, nw); module->swap_names(w, nw);
} }
if (!remove_init_bits.empty()) {
for (auto w : module->wires()) {
if (w->attributes.count("\\init")) {
Const initval = w->attributes.at("\\init");
Const new_initval(State::Sx, GetSize(w));
SigSpec initsig = init_attr_sigmap(w);
int width = std::min(GetSize(initval), GetSize(initsig));
for (int i = 0; i < width; i++) {
log_dump(initsig[i], remove_init_bits.count(initsig[i]));
if (!remove_init_bits.count(initsig[i]))
new_initval[i] = initval[i];
}
w->attributes.at("\\init") = new_initval;
log_dump(w->name, initval, new_initval);
}
}
}
} }
}; };

View File

@ -4,5 +4,5 @@ passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h
.SECONDARY: passes/pmgen/ice40_dsp_pm.h .SECONDARY: passes/pmgen/ice40_dsp_pm.h
passes/pmgen/ice40_dsp_pm.h: passes/pmgen/ice40_dsp.pmg passes/pmgen/pmgen.py passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg
$(P) cd passes/pmgen && python3 pmgen.py ice40_dsp $(P) mkdir -p passes/pmgen && python3 $^ $@

View File

@ -16,7 +16,7 @@ API of Generated Matcher
======================== ========================
When `pmgen.py` reads a `foobar.pmg` file, it writes `foobar_pm.h` containing When `pmgen.py` reads a `foobar.pmg` file, it writes `foobar_pm.h` containing
a class `foobar_pm`. That class is instanciated with an RTLIL module and a a class `foobar_pm`. That class is instantiated with an RTLIL module and a
list of cells from that module: list of cells from that module:
foobar_pm pm(module, module->selected_cells()); foobar_pm pm(module, module->selected_cells());
@ -142,7 +142,7 @@ The `select` lines are evaluated once for each cell when the matcher is
initialized. A `match` block will only consider cells for which all `select` initialized. A `match` block will only consider cells for which all `select`
expressions evaluated to `true`. Note that the state variable corresponding to expressions evaluated to `true`. Note that the state variable corresponding to
the match (in the example `mul`) is the only state variable that may be used the match (in the example `mul`) is the only state variable that may be used
`select` lines. in `select` lines.
Index lines are using the `index <type> expr1 === expr2` syntax. `expr1` is Index lines are using the `index <type> expr1 === expr2` syntax. `expr1` is
evaluated during matcher initialization and the same restrictions apply as for evaluated during matcher initialization and the same restrictions apply as for

View File

@ -6,7 +6,11 @@ import pprint
pp = pprint.PrettyPrinter(indent=4) pp = pprint.PrettyPrinter(indent=4)
prefix = sys.argv[1] pmgfile = sys.argv[1]
assert pmgfile.endswith(".pmg")
prefix = pmgfile[0:-4]
prefix = prefix.split('/')[-1]
outfile = sys.argv[2]
state_types = dict() state_types = dict()
udata_types = dict() udata_types = dict()
@ -73,7 +77,7 @@ def rewrite_cpp(s):
return "".join(t) return "".join(t)
with open("%s.pmg" % prefix, "r") as f: with open(pmgfile, "r") as f:
while True: while True:
line = f.readline() line = f.readline()
if line == "": break if line == "": break
@ -82,7 +86,7 @@ with open("%s.pmg" % prefix, "r") as f:
cmd = line.split() cmd = line.split()
if len(cmd) == 0 or cmd[0].startswith("//"): continue if len(cmd) == 0 or cmd[0].startswith("//"): continue
cmd = cmd[0] cmd = cmd[0]
if cmd == "state": if cmd == "state":
m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line)
assert m assert m
@ -176,7 +180,7 @@ with open("%s.pmg" % prefix, "r") as f:
blocks.append(block) blocks.append(block)
with open("%s_pm.h" % prefix, "w") as f: with open(outfile, "w") as f:
print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f)
print("", file=f) print("", file=f)

View File

@ -340,6 +340,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
// 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;
bool shiftx = initial_val.is_fully_undef();
for (size_t i = 0; i < sw->cases.size(); i++) { for (size_t i = 0; i < sw->cases.size(); i++) {
int case_idx = sw->cases.size() - i - 1; int case_idx = sw->cases.size() - i - 1;
RTLIL::CaseRule *cs2 = sw->cases[case_idx]; RTLIL::CaseRule *cs2 = sw->cases[case_idx];
@ -348,6 +349,33 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode); append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode);
else else
result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode); result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode);
// Ignore output values which are entirely don't care
if (shiftx && !value.is_fully_undef()) {
// Keep checking if case condition is the same as the current case index
if (cs2->compare.size() == 1 && cs2->compare.front().is_fully_const())
shiftx = (cs2->compare.front().as_int() == case_idx);
else
shiftx = false;
}
}
// Transform into a $shiftx where possible
if (shiftx && last_mux_cell && last_mux_cell->type == "$pmux") {
// Create bit-blasted $shiftx-es that shifts by the address line used in the case statement
auto pmux_b_port = last_mux_cell->getPort("\\B");
auto pmux_y_port = last_mux_cell->getPort("\\Y");
int width = last_mux_cell->getParam("\\WIDTH").as_int();
for (int i = 0; i < width; ++i) {
RTLIL::SigSpec a_port;
// Because we went in reverse order above, un-reverse $pmux's B port here
for (int j = pmux_b_port.size()/width-1; j >= 0; --j)
a_port.append(pmux_b_port.extract(j*width+i, 1));
// Create a $shiftx that shifts by the address line used in the case statement
mod->addShiftx(NEW_ID, a_port, sw->signal, pmux_y_port.extract(i, 1));
}
// Disconnect $pmux by replacing its output port with a floating wire
last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, width));
} }
} }

View File

@ -8,4 +8,8 @@ OBJS += passes/sat/expose.o
OBJS += passes/sat/assertpmux.o OBJS += passes/sat/assertpmux.o
OBJS += passes/sat/clk2fflogic.o OBJS += passes/sat/clk2fflogic.o
OBJS += passes/sat/async2sync.o OBJS += passes/sat/async2sync.o
OBJS += passes/sat/supercover.o
OBJS += passes/sat/fmcombine.o
OBJS += passes/sat/mutate.o
OBJS += passes/sat/cutpoint.o

View File

@ -39,7 +39,7 @@ struct Async2syncPass : public Pass {
log("reset value in the next cycle regardless of the data-in value at the time of\n"); log("reset value in the next cycle regardless of the data-in value at the time of\n");
log("the clock edge.\n"); log("the clock edge.\n");
log("\n"); log("\n");
log("Currently only $adff cells are supported by this pass.\n"); log("Currently only $adff and $dffsr cells are supported by this pass.\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
@ -84,7 +84,7 @@ struct Async2syncPass : public Pass {
bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool(); bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool();
Const arst_val = cell->parameters["\\ARST_VALUE"]; Const arst_val = cell->parameters["\\ARST_VALUE"];
SigSpec sig_clk = cell->getPort("\\CLK"); // SigSpec sig_clk = cell->getPort("\\CLK");
SigSpec sig_arst = cell->getPort("\\ARST"); SigSpec sig_arst = cell->getPort("\\ARST");
SigSpec sig_d = cell->getPort("\\D"); SigSpec sig_d = cell->getPort("\\D");
SigSpec sig_q = cell->getPort("\\Q"); SigSpec sig_q = cell->getPort("\\Q");
@ -120,6 +120,55 @@ struct Async2syncPass : public Pass {
cell->type = "$dff"; cell->type = "$dff";
continue; continue;
} }
if (cell->type.in("$dffsr"))
{
// bool clk_pol = cell->parameters["\\CLK_POLARITY"].as_bool();
bool set_pol = cell->parameters["\\SET_POLARITY"].as_bool();
bool clr_pol = cell->parameters["\\CLR_POLARITY"].as_bool();
// SigSpec sig_clk = cell->getPort("\\CLK");
SigSpec sig_set = cell->getPort("\\SET");
SigSpec sig_clr = cell->getPort("\\CLR");
SigSpec sig_d = cell->getPort("\\D");
SigSpec sig_q = cell->getPort("\\Q");
log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
log_id(module), log_id(cell), log_id(cell->type),
log_signal(sig_set), log_signal(sig_clr), log_signal(sig_d), log_signal(sig_q));
Const init_val;
for (int i = 0; i < GetSize(sig_q); i++) {
SigBit bit = sigmap(sig_q[i]);
init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx);
del_initbits.insert(bit);
}
Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d));
Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
new_q->attributes["\\init"] = init_val;
if (!set_pol)
sig_set = module->Not(NEW_ID, sig_set);
if (clr_pol)
sig_clr = module->Not(NEW_ID, sig_clr);
SigSpec tmp = module->Or(NEW_ID, sig_d, sig_set);
module->addAnd(NEW_ID, tmp, sig_clr, new_d);
tmp = module->Or(NEW_ID, new_q, sig_set);
module->addAnd(NEW_ID, tmp, sig_clr, sig_q);
cell->setPort("\\D", new_d);
cell->setPort("\\Q", new_q);
cell->unsetPort("\\SET");
cell->unsetPort("\\CLR");
cell->unsetParam("\\SET_POLARITY");
cell->unsetParam("\\CLR_POLARITY");
cell->type = "$dff";
continue;
}
} }
for (auto wire : module->wires()) for (auto wire : module->wires())

168
passes/sat/cutpoint.cc Normal file
View File

@ -0,0 +1,168 @@
/*
* 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 CutpointPass : public Pass {
CutpointPass() : Pass("cutpoint", "add hi/lo cover cells for each wire bit") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" cutpoint [options] [selection]\n");
log("\n");
log("This command adds formal cut points to the design.\n");
log("\n");
log(" -undef\n");
log(" set cupoint nets to undef (x). the default behavior is to create a\n");
log(" $anyseq cell and drive the cutpoint net from that\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_undef = false;
log_header(design, "Executing CUTPOINT pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-undef") {
flag_undef = true;
continue;
}
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
if (design->selected_whole_module(module->name)) {
log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module));
module->new_connections(std::vector<RTLIL::SigSig>());
for (auto cell : vector<Cell*>(module->cells()))
module->remove(cell);
vector<Wire*> output_wires;
for (auto wire : module->wires())
if (wire->port_output)
output_wires.push_back(wire);
for (auto wire : output_wires)
module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire)));
continue;
}
SigMap sigmap(module);
pool<SigBit> cutpoint_bits;
for (auto cell : module->selected_cells()) {
if (cell->type == "$anyseq")
continue;
log("Removing cell %s.%s, making all cell outputs cutpoints.\n", log_id(module), log_id(cell));
for (auto &conn : cell->connections()) {
if (cell->output(conn.first))
module->connect(conn.second, flag_undef ? Const(State::Sx, GetSize(conn.second)) : module->Anyseq(NEW_ID, GetSize(conn.second)));
}
module->remove(cell);
}
for (auto wire : module->selected_wires()) {
if (wire->port_output) {
log("Making output wire %s.%s a cutpoint.\n", log_id(module), log_id(wire));
Wire *new_wire = module->addWire(NEW_ID, wire);
module->swap_names(wire, new_wire);
module->connect(new_wire, flag_undef ? Const(State::Sx, GetSize(new_wire)) : module->Anyseq(NEW_ID, GetSize(new_wire)));
wire->port_id = 0;
wire->port_input = false;
wire->port_output = false;
continue;
}
log("Making wire %s.%s a cutpoint.\n", log_id(module), log_id(wire));
for (auto bit : sigmap(wire))
cutpoint_bits.insert(bit);
}
if (!cutpoint_bits.empty())
{
for (auto cell : module->cells()) {
for (auto &conn : cell->connections()) {
if (!cell->output(conn.first))
continue;
SigSpec sig = sigmap(conn.second);
int bit_count = 0;
for (auto &bit : sig) {
if (cutpoint_bits.count(bit))
bit_count++;
}
if (bit_count == 0)
continue;
SigSpec dummy = module->addWire(NEW_ID, bit_count);
bit_count = 0;
for (auto &bit : sig) {
if (cutpoint_bits.count(bit))
bit = dummy[bit_count++];
}
cell->setPort(conn.first, sig);
}
}
vector<Wire*> rewrite_wires;
for (auto wire : module->wires()) {
if (!wire->port_input)
continue;
int bit_count = 0;
for (auto &bit : sigmap(wire))
if (cutpoint_bits.count(bit))
bit_count++;
if (bit_count)
rewrite_wires.push_back(wire);
}
for (auto wire : rewrite_wires) {
Wire *new_wire = module->addWire(NEW_ID, wire);
SigSpec lhs, rhs, sig = sigmap(wire);
for (int i = 0; i < GetSize(sig); i++)
if (!cutpoint_bits.count(sig[i])) {
lhs.append(SigBit(wire, i));
rhs.append(SigBit(new_wire, i));
}
if (GetSize(lhs))
module->connect(lhs, rhs);
module->swap_names(wire, new_wire);
wire->port_id = 0;
wire->port_input = false;
wire->port_output = false;
}
SigSpec sig(cutpoint_bits);
sig.sort_and_unify();
for (auto chunk : sig.chunks()) {
SigSpec s(chunk);
module->connect(s, flag_undef ? Const(State::Sx, GetSize(s)) : module->Anyseq(NEW_ID, GetSize(s)));
}
}
}
}
} CutpointPass;
PRIVATE_NAMESPACE_END

341
passes/sat/fmcombine.cc Normal file
View File

@ -0,0 +1,341 @@
/*
* 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"
#include "kernel/celltypes.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct opts_t
{
bool fwd = false;
bool bwd = false;
bool nop = false;
};
struct FmcombineWorker
{
const opts_t &opts;
Design *design;
Module *original = nullptr;
Module *module = nullptr;
IdString orig_type, combined_type;
FmcombineWorker(Design *design, IdString orig_type, const opts_t &opts) :
opts(opts), design(design), original(design->module(orig_type)),
orig_type(orig_type), combined_type("$fmcombine" + orig_type.str())
{
}
SigSpec import_sig(SigSpec sig, const string &suffix)
{
SigSpec newsig;
for (auto chunk : sig.chunks()) {
if (chunk.wire != nullptr)
chunk.wire = module->wire(chunk.wire->name.str() + suffix);
newsig.append(chunk);
}
return newsig;
}
void import_prim_cell(Cell *cell, const string &suffix)
{
Cell *c = module->addCell(cell->name.str() + suffix, cell->type);
c->parameters = cell->parameters;
c->attributes = cell->attributes;
for (auto &conn : cell->connections())
c->setPort(conn.first, import_sig(conn.second, suffix));
}
void import_hier_cell(Cell *cell)
{
if (!cell->parameters.empty())
log_cmd_error("Cell %s.%s has unresolved instance parameters.\n", log_id(original), log_id(cell));
FmcombineWorker sub_worker(design, cell->type, opts);
sub_worker.generate();
Cell *c = module->addCell(cell->name.str() + "_combined", sub_worker.combined_type);
// c->parameters = cell->parameters;
c->attributes = cell->attributes;
for (auto &conn : cell->connections()) {
c->setPort(conn.first.str() + "_gold", import_sig(conn.second, "_gold"));
c->setPort(conn.first.str() + "_gate", import_sig(conn.second, "_gate"));
}
}
void generate()
{
if (design->module(combined_type)) {
// log("Combined module %s already exists.\n", log_id(combined_type));
return;
}
log("Generating combined module %s from module %s.\n", log_id(combined_type), log_id(orig_type));
module = design->addModule(combined_type);
for (auto wire : original->wires()) {
module->addWire(wire->name.str() + "_gold", wire);
module->addWire(wire->name.str() + "_gate", wire);
}
module->fixup_ports();
for (auto cell : original->cells()) {
if (design->module(cell->type) == nullptr) {
import_prim_cell(cell, "_gold");
import_prim_cell(cell, "_gate");
} else {
import_hier_cell(cell);
}
}
for (auto &conn : original->connections()) {
module->connect(import_sig(conn.first, "_gold"), import_sig(conn.second, "_gold"));
module->connect(import_sig(conn.first, "_gate"), import_sig(conn.second, "_gate"));
}
if (opts.nop)
return;
CellTypes ct;
ct.setup_internals_eval();
ct.setup_stdcells_eval();
SigMap sigmap(module);
dict<SigBit, SigBit> data_bit_to_eq_net;
dict<Cell*, SigSpec> cell_to_eq_nets;
dict<SigSpec, SigSpec> reduce_db;
dict<SigSpec, SigSpec> invert_db;
for (auto cell : original->cells())
{
if (!ct.cell_known(cell->type))
continue;
for (auto &conn : cell->connections())
{
if (!cell->output(conn.first))
continue;
SigSpec A = import_sig(conn.second, "_gold");
SigSpec B = import_sig(conn.second, "_gate");
SigBit EQ = module->Eq(NEW_ID, A, B);
for (auto bit : sigmap({A, B}))
data_bit_to_eq_net[bit] = EQ;
cell_to_eq_nets[cell].append(EQ);
}
}
for (auto cell : original->cells())
{
if (!ct.cell_known(cell->type))
continue;
bool skip_cell = !cell_to_eq_nets.count(cell);
pool<SigBit> src_eq_bits;
for (auto &conn : cell->connections())
{
if (skip_cell)
break;
if (cell->output(conn.first))
continue;
SigSpec A = import_sig(conn.second, "_gold");
SigSpec B = import_sig(conn.second, "_gate");
for (auto bit : sigmap({A, B})) {
if (data_bit_to_eq_net.count(bit))
src_eq_bits.insert(data_bit_to_eq_net.at(bit));
else
skip_cell = true;
}
}
if (!skip_cell) {
SigSpec antecedent = SigSpec(src_eq_bits);
antecedent.sort_and_unify();
if (GetSize(antecedent) > 1) {
if (reduce_db.count(antecedent) == 0)
reduce_db[antecedent] = module->ReduceAnd(NEW_ID, antecedent);
antecedent = reduce_db.at(antecedent);
}
SigSpec consequent = cell_to_eq_nets.at(cell);
consequent.sort_and_unify();
if (GetSize(consequent) > 1) {
if (reduce_db.count(consequent) == 0)
reduce_db[consequent] = module->ReduceAnd(NEW_ID, consequent);
consequent = reduce_db.at(consequent);
}
if (opts.fwd)
module->addAssume(NEW_ID, consequent, antecedent);
if (opts.bwd)
{
if (invert_db.count(antecedent) == 0)
invert_db[antecedent] = module->Not(NEW_ID, antecedent);
if (invert_db.count(consequent) == 0)
invert_db[consequent] = module->Not(NEW_ID, consequent);
module->addAssume(NEW_ID, invert_db.at(antecedent), invert_db.at(consequent));
}
}
}
}
};
struct FmcombinePass : public Pass {
FmcombinePass() : Pass("fmcombine", "combine two instances of a cell into one") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" fmcombine [options] module_name gold_cell gate_cell\n");
// log(" fmcombine [options] @gold_cell @gate_cell\n");
log("\n");
log("This pass takes two cells, which are instances of the same module, and replaces\n");
log("them with one instance of a special 'combined' module, that effectively\n");
log("contains two copies of the original module, plus some formal properties.\n");
log("\n");
log("This is useful for formal test benches that check what differences in behavior\n");
log("a slight difference in input causes in a module.\n");
log("\n");
log(" -fwd\n");
log(" Insert forward hint assumptions into the combined module.\n");
log("\n");
log(" -bwd\n");
log(" Insert backward hint assumptions into the combined module.\n");
log(" (Backward hints are logically equivalend to fordward hits, but\n");
log(" some solvers are faster with bwd hints, or even both -bwd and -fwd.)\n");
log("\n");
log(" -nop\n");
log(" Don't insert hint assumptions into the combined module.\n");
log(" (This should not provide any speedup over the original design, but\n");
log(" strangely sometimes it does.)\n");
log("\n");
log("If none of -fwd, -bwd, and -nop is given, then -fwd is used as default.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
opts_t opts;
Module *module = nullptr;
Cell *gold_cell = nullptr;
Cell *gate_cell = nullptr;
log_header(design, "Executing FMCOMBINE pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-o" && argidx+1 < args.size()) {
// filename = args[++argidx];
// continue;
// }
if (args[argidx] == "-fwd") {
opts.fwd = true;
continue;
}
if (args[argidx] == "-bwd") {
opts.bwd = true;
continue;
}
if (args[argidx] == "-nop") {
opts.nop = true;
continue;
}
break;
}
if (argidx+2 == args.size())
{
string gold_name = args[argidx++];
string gate_name = args[argidx++];
log_cmd_error("fmcombine @gold_cell @gate_cell call style is not implemented yet.");
}
else if (argidx+3 == args.size())
{
IdString module_name = RTLIL::escape_id(args[argidx++]);
IdString gold_name = RTLIL::escape_id(args[argidx++]);
IdString gate_name = RTLIL::escape_id(args[argidx++]);
module = design->module(module_name);
if (module == nullptr)
log_cmd_error("Module %s not found.\n", log_id(module_name));
gold_cell = module->cell(gold_name);
if (gold_cell == nullptr)
log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gold_name), log_id(module));
gate_cell = module->cell(gate_name);
if (gate_cell == nullptr)
log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gate_name), log_id(module));
}
else
{
log_cmd_error("Invalid number of arguments.\n");
}
// extra_args(args, argidx, design);
if (opts.nop && (opts.fwd || opts.bwd))
log_cmd_error("Option -nop can not be combined with -fwd and/or -bwd.\n");
if (!opts.nop && !opts.fwd && !opts.bwd)
opts.fwd = true;
if (gold_cell->type != gate_cell->type)
log_cmd_error("Types of gold and gate cells do not match.\n");
if (!gold_cell->parameters.empty())
log_cmd_error("Gold cell has unresolved instance parameters.\n");
if (!gate_cell->parameters.empty())
log_cmd_error("Gold cell has unresolved instance parameters.\n");
FmcombineWorker worker(design, gold_cell->type, opts);
worker.generate();
IdString combined_cell_name = module->uniquify(stringf("\\%s_%s", log_id(gold_cell), log_id(gate_cell)));
Cell *cell = module->addCell(combined_cell_name, worker.combined_type);
cell->attributes = gold_cell->attributes;
cell->add_strpool_attribute("\\src", gate_cell->get_strpool_attribute("\\src"));
log("Combining cells %s and %s in module %s into new cell %s.\n", log_id(gold_cell), log_id(gate_cell), log_id(module), log_id(cell));
for (auto &conn : gold_cell->connections())
cell->setPort(conn.first.str() + "_gold", conn.second);
module->remove(gold_cell);
for (auto &conn : gate_cell->connections())
cell->setPort(conn.first.str() + "_gate", conn.second);
module->remove(gate_cell);
}
} FmcombinePass;
PRIVATE_NAMESPACE_END

988
passes/sat/mutate.cc Normal file
View File

@ -0,0 +1,988 @@
/*
* 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 mutate_t {
string mode;
pool<string> src;
IdString module, cell;
IdString port, wire;
int portbit = -1;
int ctrlbit = -1;
int wirebit = -1;
bool used = false;
};
struct mutate_opts_t {
int seed = 0;
std::string mode;
pool<string> src;
IdString module, cell, port, wire;
int portbit = -1;
int ctrlbit = -1;
int wirebit = -1;
IdString ctrl_name;
int ctrl_width = -1, ctrl_value = -1;
bool none = false;
int pick_cover_prcnt = 80;
int weight_cover = 500;
int weight_pq_w = 100;
int weight_pq_b = 100;
int weight_pq_c = 100;
int weight_pq_s = 100;
int weight_pq_mw = 100;
int weight_pq_mb = 100;
int weight_pq_mc = 100;
int weight_pq_ms = 100;
};
void database_add(std::vector<mutate_t> &database, const mutate_opts_t &opts, const mutate_t &entry)
{
if (!opts.mode.empty() && opts.mode != entry.mode)
return;
if (!opts.src.empty()) {
bool found_match = false;
for (auto &s : opts.src) {
if (entry.src.count(s))
found_match = true;
}
if (!found_match)
return;
}
if (!opts.module.empty() && opts.module != entry.module)
return;
if (!opts.cell.empty() && opts.cell != entry.cell)
return;
if (!opts.port.empty() && opts.port != entry.port)
return;
if (opts.portbit >= 0 && opts.portbit != entry.portbit)
return;
if (opts.ctrlbit >= 0 && opts.ctrlbit != entry.ctrlbit)
return;
if (!opts.wire.empty() && opts.wire != entry.wire)
return;
if (opts.wirebit >= 0 && opts.wirebit != entry.wirebit)
return;
database.push_back(entry);
}
struct xs128_t
{
uint32_t x = 123456789;
uint32_t y = 0, z = 0, w = 0;
xs128_t(int seed = 0) : w(seed) {
next();
next();
next();
}
void next() {
uint32_t t = x ^ (x << 11);
x = y, y = z, z = w;
w ^= (w >> 19) ^ t ^ (t >> 8);
}
int operator()() {
next();
return w & 0x3fffffff;
}
int operator()(int n) {
if (n < 2)
return 0;
while (1) {
int k = (*this)(), p = k % n;
if ((k - p + n) <= 0x40000000)
return p;
}
}
};
struct coverdb_t
{
dict<string, int> src_db;
dict<tuple<IdString, IdString>, int> wire_db;
dict<tuple<IdString, IdString, int>, int> wirebit_db;
void insert(const mutate_t &m) {
if (!m.wire.empty()) {
wire_db[tuple<IdString, IdString>(m.module, m.wire)] = 0;
wirebit_db[tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)] = 0;
}
for (auto &s : m.src) {
src_db[s] = 0;
}
}
void update(const mutate_t &m) {
if (!m.wire.empty()) {
wire_db.at(tuple<IdString, IdString>(m.module, m.wire))++;
wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit))++;
}
for (auto &s : m.src) {
src_db.at(s)++;
}
}
int score(const mutate_t &m) {
int this_score = m.src.empty() ? 0 : 1;
if (!m.wire.empty()) {
this_score += wire_db.at(tuple<IdString, IdString>(m.module, m.wire)) ? 0 : 5;
this_score += wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)) ? 0 : 1;
}
for (auto &s : m.src) {
this_score += src_db.at(s) ? 0 : 5;
}
return this_score;
}
};
struct mutate_queue_t
{
pool<mutate_t*, hash_ptr_ops> db;
mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
mutate_t *m = nullptr;
if (rng(100) < opts.pick_cover_prcnt) {
vector<mutate_t*> candidates, rmqueue;
int best_score = -1;
for (auto p : db) {
if (p->used) {
rmqueue.push_back(p);
continue;
}
int this_score = coverdb.score(*p);
if (this_score > best_score) {
best_score = this_score;
candidates.clear();
}
if (best_score == this_score)
candidates.push_back(p);
}
for (auto p : rmqueue)
db.erase(p);
if (!candidates.empty())
m = candidates[rng(GetSize(candidates))];
}
if (m == nullptr) {
while (!db.empty()) {
int i = rng(GetSize(db));
auto it = db.element(i);
mutate_t *p = *it;
db.erase(it);
if (p->used == false) {
m = p;
break;
}
}
}
return m;
}
void add(mutate_t *m) {
db.insert(m);
}
};
template <typename K, typename T>
struct mutate_chain_queue_t
{
dict<K, T> db;
mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
while (!db.empty()) {
int i = rng(GetSize(db));
auto it = db.element(i);
mutate_t *m = it->second.pick(rng, coverdb, opts);
if (m != nullptr)
return m;
db.erase(it);
}
return nullptr;
}
template<typename... Args>
void add(mutate_t *m, K key, Args... args) {
db[key].add(m, args...);
}
};
template <typename K, typename T>
struct mutate_once_queue_t
{
dict<K, T> db;
mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
while (!db.empty()) {
int i = rng(GetSize(db));
auto it = db.element(i);
mutate_t *m = it->second.pick(rng, coverdb, opts);
db.erase(it);
if (m != nullptr)
return m;
}
return nullptr;
}
template<typename... Args>
void add(mutate_t *m, K key, Args... args) {
db[key].add(m, args...);
}
};
void database_reduce(std::vector<mutate_t> &database, const mutate_opts_t &opts, int N, xs128_t &rng)
{
std::vector<mutate_t> new_database;
coverdb_t coverdb;
int total_weight = opts.weight_cover + opts.weight_pq_w + opts.weight_pq_b + opts.weight_pq_c + opts.weight_pq_s;
total_weight += opts.weight_pq_mw + opts.weight_pq_mb + opts.weight_pq_mc + opts.weight_pq_ms;
if (N >= GetSize(database))
return;
mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_wire;
mutate_once_queue_t<tuple<IdString, IdString, int>, mutate_queue_t> primary_queue_bit;
mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_cell;
mutate_once_queue_t<string, mutate_queue_t> primary_queue_src;
mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_wire;
mutate_chain_queue_t<IdString, mutate_once_queue_t<pair<IdString, int>, mutate_queue_t>> primary_queue_module_bit;
mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_cell;
mutate_chain_queue_t<IdString, mutate_once_queue_t<string, mutate_queue_t>> primary_queue_module_src;
for (auto &m : database)
{
coverdb.insert(m);
if (!m.wire.empty()) {
primary_queue_wire.add(&m, tuple<IdString, IdString>(m.module, m.wire));
primary_queue_bit.add(&m, tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit));
primary_queue_module_wire.add(&m, m.module, m.wire);
primary_queue_module_bit.add(&m, m.module, pair<IdString, int>(m.wire, m.wirebit));
}
primary_queue_cell.add(&m, tuple<IdString, IdString>(m.module, m.cell));
primary_queue_module_cell.add(&m, m.module, m.cell);
for (auto &s : m.src) {
primary_queue_src.add(&m, s);
primary_queue_module_src.add(&m, m.module, s);
}
}
vector<mutate_t*> cover_candidates;
int best_cover_score = -1;
bool skip_cover = false;
while (GetSize(new_database) < N)
{
int k = rng(total_weight);
k -= opts.weight_cover;
if (k < 0) {
while (!skip_cover) {
if (cover_candidates.empty()) {
best_cover_score = -1;
for (auto &m : database) {
if (m.used || m.src.empty())
continue;
int this_score = -1;
for (auto &s : m.src) {
if (this_score == -1 || this_score > coverdb.src_db.at(s))
this_score = coverdb.src_db.at(s);
}
log_assert(this_score != -1);
if (best_cover_score == -1 || this_score < best_cover_score) {
cover_candidates.clear();
best_cover_score = this_score;
}
if (best_cover_score == this_score)
cover_candidates.push_back(&m);
}
if (best_cover_score == -1) {
skip_cover = true;
break;
}
}
mutate_t *m = nullptr;
while (!cover_candidates.empty())
{
int idx = rng(GetSize(cover_candidates));
mutate_t *p = cover_candidates[idx];
cover_candidates[idx] = cover_candidates.back();
cover_candidates.pop_back();
if (p->used)
continue;
int this_score = -1;
for (auto &s : p->src) {
if (this_score == -1 || this_score > coverdb.src_db.at(s))
this_score = coverdb.src_db.at(s);
}
if (this_score != best_cover_score)
continue;
m = p;
break;
}
if (m != nullptr) {
m->used = true;
coverdb.update(*m);
new_database.push_back(*m);
break;
}
}
continue;
}
#define X(__wght, __queue) \
k -= __wght; \
if (k < 0) { \
mutate_t *m = __queue.pick(rng, coverdb, opts); \
if (m != nullptr) { \
m->used = true; \
coverdb.update(*m); \
new_database.push_back(*m); \
}; \
continue; \
}
X(opts.weight_pq_w, primary_queue_wire)
X(opts.weight_pq_b, primary_queue_bit)
X(opts.weight_pq_c, primary_queue_cell)
X(opts.weight_pq_s, primary_queue_src)
X(opts.weight_pq_mw, primary_queue_module_wire)
X(opts.weight_pq_mb, primary_queue_module_bit)
X(opts.weight_pq_mc, primary_queue_module_cell)
X(opts.weight_pq_ms, primary_queue_module_src)
#undef X
}
std::swap(new_database, database);
int covered_src_cnt = 0;
int covered_wire_cnt = 0;
int covered_wirebit_cnt = 0;
for (auto &it : coverdb.src_db)
if (it.second)
covered_src_cnt++;
for (auto &it : coverdb.wire_db)
if (it.second)
covered_wire_cnt++;
for (auto &it : coverdb.wirebit_db)
if (it.second)
covered_wirebit_cnt++;
log("Covered %d/%d src attributes (%.2f%%).\n", covered_src_cnt, GetSize(coverdb.src_db), 100.0 * covered_src_cnt / GetSize(coverdb.src_db));
log("Covered %d/%d wires (%.2f%%).\n", covered_wire_cnt, GetSize(coverdb.wire_db), 100.0 * covered_wire_cnt / GetSize(coverdb.wire_db));
log("Covered %d/%d wire bits (%.2f%%).\n", covered_wirebit_cnt, GetSize(coverdb.wirebit_db), 100.0 * covered_wirebit_cnt / GetSize(coverdb.wirebit_db));
}
void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, const string &srcsfile, int N)
{
pool<string> sources;
std::vector<mutate_t> database;
xs128_t rng(opts.seed);
for (auto module : design->selected_modules())
{
if (!opts.module.empty() && module->name != opts.module)
continue;
SigMap sigmap(module);
dict<SigBit, int> bit_user_cnt;
for (auto wire : module->wires()) {
if (wire->name[0] == '\\' && wire->attributes.count("\\src"))
sigmap.add(wire);
}
for (auto cell : module->cells()) {
for (auto &conn : cell->connections()) {
if (cell->output(conn.first))
continue;
for (auto bit : sigmap(conn.second))
bit_user_cnt[bit]++;
}
}
for (auto wire : module->selected_wires())
{
for (SigBit bit : SigSpec(wire))
{
SigBit sigbit = sigmap(bit);
if (bit.wire == nullptr || sigbit.wire == nullptr)
continue;
if (!bit.wire->port_id != !sigbit.wire->port_id) {
if (bit.wire->port_id)
sigmap.add(bit);
continue;
}
if (!bit.wire->name[0] != !sigbit.wire->name[0]) {
if (bit.wire->name[0] == '\\')
sigmap.add(bit);
continue;
}
}
}
for (auto cell : module->selected_cells())
{
if (!opts.cell.empty() && cell->name != opts.cell)
continue;
for (auto &conn : cell->connections())
{
for (int i = 0; i < GetSize(conn.second); i++) {
mutate_t entry;
entry.module = module->name;
entry.cell = cell->name;
entry.port = conn.first;
entry.portbit = i;
for (auto &s : cell->get_strpool_attribute("\\src"))
entry.src.insert(s);
SigBit bit = sigmap(conn.second[i]);
if (bit.wire && bit.wire->name[0] == '\\' && (cell->output(conn.first) || bit_user_cnt[bit] == 1)) {
for (auto &s : bit.wire->get_strpool_attribute("\\src"))
entry.src.insert(s);
entry.wire = bit.wire->name;
entry.wirebit = bit.offset;
}
if (!srcsfile.empty())
sources.insert(entry.src.begin(), entry.src.end());
entry.mode = "inv";
database_add(database, opts, entry);
entry.mode = "const0";
database_add(database, opts, entry);
entry.mode = "const1";
database_add(database, opts, entry);
entry.mode = "cnot0";
entry.ctrlbit = rng(GetSize(conn.second));
if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire)
database_add(database, opts, entry);
entry.mode = "cnot1";
entry.ctrlbit = rng(GetSize(conn.second));
if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire)
database_add(database, opts, entry);
}
}
}
}
log("Raw database size: %d\n", GetSize(database));
if (N != 0) {
database_reduce(database, opts, opts.none ? N-1 : N, rng);
log("Reduced database size: %d\n", GetSize(database));
}
if (!srcsfile.empty()) {
std::ofstream sout;
sout.open(srcsfile, std::ios::out | std::ios::trunc);
if (!sout.is_open())
log_error("Could not open file \"%s\" with write access.\n", srcsfile.c_str());
sources.sort();
for (auto &s : sources)
sout << s << std::endl;
}
std::ofstream fout;
if (!filename.empty()) {
fout.open(filename, std::ios::out | std::ios::trunc);
if (!fout.is_open())
log_error("Could not open file \"%s\" with write access.\n", filename.c_str());
}
int ctrl_value = opts.ctrl_value;
if (opts.none) {
string str = "mutate";
if (!opts.ctrl_name.empty())
str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++);
str += " -mode none";
if (filename.empty())
log("%s\n", str.c_str());
else
fout << str << std::endl;
}
for (auto &entry : database) {
string str = "mutate";
if (!opts.ctrl_name.empty())
str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++);
str += stringf(" -mode %s", entry.mode.c_str());
if (!entry.module.empty())
str += stringf(" -module %s", log_id(entry.module));
if (!entry.cell.empty())
str += stringf(" -cell %s", log_id(entry.cell));
if (!entry.port.empty())
str += stringf(" -port %s", log_id(entry.port));
if (entry.portbit >= 0)
str += stringf(" -portbit %d", entry.portbit);
if (entry.ctrlbit >= 0)
str += stringf(" -ctrlbit %d", entry.ctrlbit);
if (!entry.wire.empty())
str += stringf(" -wire %s", log_id(entry.wire));
if (entry.wirebit >= 0)
str += stringf(" -wirebit %d", entry.wirebit);
for (auto &s : entry.src)
str += stringf(" -src %s", s.c_str());
if (filename.empty())
log("%s\n", str.c_str());
else
fout << str << std::endl;
}
}
SigSpec mutate_ctrl_sig(Module *module, IdString name, int width)
{
Wire *ctrl_wire = module->wire(name);
if (ctrl_wire == nullptr)
{
log("Adding ctrl port %s to module %s.\n", log_id(name), log_id(module));
ctrl_wire = module->addWire(name, width);
ctrl_wire->port_input = true;
module->fixup_ports();
for (auto mod : module->design->modules())
for (auto cell : mod->cells())
{
if (cell->type != module->name)
continue;
SigSpec ctrl = mutate_ctrl_sig(mod, name, width);
log("Connecting ctrl port to cell %s in module %s.\n", log_id(cell), log_id(mod));
cell->setPort(name, ctrl);
}
}
log_assert(GetSize(ctrl_wire) == width);
return ctrl_wire;
}
SigBit mutate_ctrl(Module *module, const mutate_opts_t &opts)
{
if (opts.ctrl_name.empty())
return State::S1;
SigSpec sig = mutate_ctrl_sig(module, opts.ctrl_name, opts.ctrl_width);
return module->Eq(NEW_ID, sig, Const(opts.ctrl_value, GetSize(sig)));
}
SigSpec mutate_ctrl_mux(Module *module, const mutate_opts_t &opts, SigSpec unchanged_sig, SigSpec changed_sig)
{
SigBit ctrl_bit = mutate_ctrl(module, opts);
if (ctrl_bit == State::S0)
return unchanged_sig;
if (ctrl_bit == State::S1)
return changed_sig;
return module->Mux(NEW_ID, unchanged_sig, changed_sig, ctrl_bit);
}
void mutate_inv(Design *design, const mutate_opts_t &opts)
{
Module *module = design->module(opts.module);
Cell *cell = module->cell(opts.cell);
SigBit bit = cell->getPort(opts.port)[opts.portbit];
SigBit inbit, outbit;
if (cell->input(opts.port))
{
log("Add input inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
SigBit outbit = module->Not(NEW_ID, bit);
bit = mutate_ctrl_mux(module, opts, bit, outbit);
}
else
{
log("Add output inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
SigBit inbit = module->addWire(NEW_ID);
SigBit outbit = module->Not(NEW_ID, inbit);
module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
bit = inbit;
}
SigSpec s = cell->getPort(opts.port);
s[opts.portbit] = bit;
cell->setPort(opts.port, s);
}
void mutate_const(Design *design, const mutate_opts_t &opts, bool one)
{
Module *module = design->module(opts.module);
Cell *cell = module->cell(opts.cell);
SigBit bit = cell->getPort(opts.port)[opts.portbit];
SigBit inbit, outbit;
if (cell->input(opts.port))
{
log("Add input constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
SigBit outbit = one ? State::S1 : State::S0;
bit = mutate_ctrl_mux(module, opts, bit, outbit);
}
else
{
log("Add output constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
SigBit inbit = module->addWire(NEW_ID);
SigBit outbit = one ? State::S1 : State::S0;
module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
bit = inbit;
}
SigSpec s = cell->getPort(opts.port);
s[opts.portbit] = bit;
cell->setPort(opts.port, s);
}
void mutate_cnot(Design *design, const mutate_opts_t &opts, bool one)
{
Module *module = design->module(opts.module);
Cell *cell = module->cell(opts.cell);
SigBit bit = cell->getPort(opts.port)[opts.portbit];
SigBit ctrl = cell->getPort(opts.port)[opts.ctrlbit];
SigBit inbit, outbit;
if (cell->input(opts.port))
{
log("Add input cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit);
SigBit outbit = one ? module->Xor(NEW_ID, bit, ctrl) : module->Xnor(NEW_ID, bit, ctrl);
bit = mutate_ctrl_mux(module, opts, bit, outbit);
}
else
{
log("Add output cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit);
SigBit inbit = module->addWire(NEW_ID);
SigBit outbit = one ? module->Xor(NEW_ID, inbit, ctrl) : module->Xnor(NEW_ID, inbit, ctrl);
module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
bit = inbit;
}
SigSpec s = cell->getPort(opts.port);
s[opts.portbit] = bit;
cell->setPort(opts.port, s);
}
struct MutatePass : public Pass {
MutatePass() : Pass("mutate", "generate or apply design mutations") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" mutate -list N [options] [selection]\n");
log("\n");
log("Create a list of N mutations using an even sampling.\n");
log("\n");
log(" -o filename\n");
log(" Write list to this file instead of console output\n");
log("\n");
log(" -s filename\n");
log(" Write a list of all src tags found in the design to the specified file\n");
log("\n");
log(" -seed N\n");
log(" RNG seed for selecting mutations\n");
log("\n");
log(" -none\n");
log(" Include a \"none\" mutation in the output\n");
log("\n");
log(" -ctrl name width value\n");
log(" Add -ctrl options to the output. Use 'value' for first mutation, then\n");
log(" simply count up from there.\n");
log("\n");
log(" -mode name\n");
log(" -module name\n");
log(" -cell name\n");
log(" -port name\n");
log(" -portbit int\n");
log(" -ctrlbit int\n");
log(" -wire name\n");
log(" -wirebit int\n");
log(" -src string\n");
log(" Filter list of mutation candidates to those matching\n");
log(" the given parameters.\n");
log("\n");
log(" -cfg option int\n");
log(" Set a configuration option. Options available:\n");
log(" weight_pq_w weight_pq_b weight_pq_c weight_pq_s\n");
log(" weight_pq_mw weight_pq_mb weight_pq_mc weight_pq_ms\n");
log(" weight_cover pick_cover_prcnt\n");
log("\n");
log("\n");
log(" mutate -mode MODE [options]\n");
log("\n");
log("Apply the given mutation.\n");
log("\n");
log(" -ctrl name width value\n");
log(" Add a control signal with the given name and width. The mutation is\n");
log(" activated if the control signal equals the given value.\n");
log("\n");
log(" -module name\n");
log(" -cell name\n");
log(" -port name\n");
log(" -portbit int\n");
log(" -ctrlbit int\n");
log(" Mutation parameters, as generated by 'mutate -list N'.\n");
log("\n");
log(" -wire name\n");
log(" -wirebit int\n");
log(" -src string\n");
log(" Ignored. (They are generated by -list for documentation purposes.)\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
mutate_opts_t opts;
string filename;
string srcsfile;
int N = -1;
log_header(design, "Executing MUTATE pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-list" && argidx+1 < args.size()) {
N = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-o" && argidx+1 < args.size()) {
filename = args[++argidx];
continue;
}
if (args[argidx] == "-s" && argidx+1 < args.size()) {
srcsfile = args[++argidx];
continue;
}
if (args[argidx] == "-seed" && argidx+1 < args.size()) {
opts.seed = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-none") {
opts.none = true;
continue;
}
if (args[argidx] == "-mode" && argidx+1 < args.size()) {
opts.mode = args[++argidx];
continue;
}
if (args[argidx] == "-ctrl" && argidx+3 < args.size()) {
opts.ctrl_name = RTLIL::escape_id(args[++argidx]);
opts.ctrl_width = atoi(args[++argidx].c_str());
opts.ctrl_value = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-module" && argidx+1 < args.size()) {
opts.module = RTLIL::escape_id(args[++argidx]);
continue;
}
if (args[argidx] == "-cell" && argidx+1 < args.size()) {
opts.cell = RTLIL::escape_id(args[++argidx]);
continue;
}
if (args[argidx] == "-port" && argidx+1 < args.size()) {
opts.port = RTLIL::escape_id(args[++argidx]);
continue;
}
if (args[argidx] == "-portbit" && argidx+1 < args.size()) {
opts.portbit = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-ctrlbit" && argidx+1 < args.size()) {
opts.ctrlbit = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-wire" && argidx+1 < args.size()) {
opts.wire = RTLIL::escape_id(args[++argidx]);
continue;
}
if (args[argidx] == "-wirebit" && argidx+1 < args.size()) {
opts.wirebit = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-src" && argidx+1 < args.size()) {
opts.src.insert(args[++argidx]);
continue;
}
if (args[argidx] == "-cfg" && argidx+2 < args.size()) {
if (args[argidx+1] == "pick_cover_prcnt") {
opts.pick_cover_prcnt = atoi(args[argidx+2].c_str());
argidx += 2;
continue;
}
if (args[argidx+1] == "weight_cover") {
opts.weight_cover = atoi(args[argidx+2].c_str());
argidx += 2;
continue;
}
if (args[argidx+1] == "weight_pq_w") {
opts.weight_pq_w = atoi(args[argidx+2].c_str());
argidx += 2;
continue;
}
if (args[argidx+1] == "weight_pq_b") {
opts.weight_pq_b = atoi(args[argidx+2].c_str());
argidx += 2;
continue;
}
if (args[argidx+1] == "weight_pq_c") {
opts.weight_pq_c = atoi(args[argidx+2].c_str());
argidx += 2;
continue;
}
if (args[argidx+1] == "weight_pq_s") {
opts.weight_pq_s = atoi(args[argidx+2].c_str());
argidx += 2;
continue;
}
if (args[argidx+1] == "weight_pq_mw") {
opts.weight_pq_mw = atoi(args[argidx+2].c_str());
argidx += 2;
continue;
}
if (args[argidx+1] == "weight_pq_mb") {
opts.weight_pq_mb = atoi(args[argidx+2].c_str());
argidx += 2;
continue;
}
if (args[argidx+1] == "weight_pq_mc") {
opts.weight_pq_mc = atoi(args[argidx+2].c_str());
argidx += 2;
continue;
}
if (args[argidx+1] == "weight_pq_ms") {
opts.weight_pq_ms = atoi(args[argidx+2].c_str());
argidx += 2;
continue;
}
}
break;
}
extra_args(args, argidx, design);
if (N >= 0) {
mutate_list(design, opts, filename, srcsfile, N);
return;
}
if (opts.mode == "none") {
if (!opts.ctrl_name.empty()) {
Module *topmod = opts.module.empty() ? design->top_module() : design->module(opts.module);
if (topmod)
mutate_ctrl_sig(topmod, opts.ctrl_name, opts.ctrl_width);
}
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") {
mutate_inv(design, opts);
return;
}
if (opts.mode == "const0" || opts.mode == "const1") {
mutate_const(design, opts, opts.mode == "const1");
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") {
mutate_cnot(design, opts, opts.mode == "cnot1");
return;
}
log_cmd_error("Invalid mode: %s\n", opts.mode.c_str());
}
} MutatePass;
PRIVATE_NAMESPACE_END

92
passes/sat/supercover.cc Normal file
View File

@ -0,0 +1,92 @@
/*
* 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 SupercoverPass : public Pass {
SupercoverPass() : Pass("supercover", "add hi/lo cover cells for each wire bit") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" supercover [options] [selection]\n");
log("\n");
log("This command adds two cover cells for each bit of each selected wire, one\n");
log("checking for a hi signal level and one checking for lo level.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
// bool flag_noinit = false;
log_header(design, "Executing SUPERCOVER pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-noinit") {
// flag_noinit = true;
// continue;
// }
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
pool<SigBit> handled_bits;
int cnt_wire = 0, cnt_bits = 0;
log("Adding cover cells to module %s.\n", log_id(module));
for (auto wire : module->selected_wires())
{
bool counted_wire = false;
std::string src = wire->get_src_attribute();
for (auto bit : sigmap(SigSpec(wire)))
{
if (bit.wire == nullptr)
continue;
if (handled_bits.count(bit))
continue;
SigSpec inv = module->Not(NEW_ID, bit);
module->addCover(NEW_ID, bit, State::S1, src);
module->addCover(NEW_ID, inv, State::S1, src);
handled_bits.insert(bit);
if (!counted_wire) {
counted_wire = false;
cnt_wire++;
}
cnt_bits++;
}
}
log(" added cover cells to %d wires, %d bits.\n", cnt_wire, cnt_bits);
}
}
} SupercoverPass;
PRIVATE_NAMESPACE_END

View File

@ -24,6 +24,7 @@
#include <istream> #include <istream>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <sstream>
#ifndef FILTERLIB #ifndef FILTERLIB
#include "kernel/log.h" #include "kernel/log.h"
@ -86,15 +87,17 @@ int LibertyParser::lexer(std::string &str)
{ {
int c; int c;
// eat whitespace
do { do {
c = f.get(); c = f.get();
} while (c == ' ' || c == '\t' || c == '\r'); } while (c == ' ' || c == '\t' || c == '\r');
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']') { // search for identifiers, numbers, plus or minus.
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
str = c; str = c;
while (1) { while (1) {
c = f.get(); c = f.get();
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']') if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
str += c; str += c;
else else
break; break;
@ -111,6 +114,8 @@ int LibertyParser::lexer(std::string &str)
} }
} }
// if it wasn't an identifer, number of array range,
// maybe it's a string?
if (c == '"') { if (c == '"') {
str = ""; str = "";
while (1) { while (1) {
@ -125,9 +130,10 @@ int LibertyParser::lexer(std::string &str)
return 'v'; return 'v';
} }
// if it wasn't a string, perhaps it's a comment or a forward slash?
if (c == '/') { if (c == '/') {
c = f.get(); c = f.get();
if (c == '*') { if (c == '*') { // start of '/*' block comment
int last_c = 0; int last_c = 0;
while (c > 0 && (last_c != '*' || c != '/')) { while (c > 0 && (last_c != '*' || c != '/')) {
last_c = c; last_c = c;
@ -136,7 +142,7 @@ int LibertyParser::lexer(std::string &str)
line++; line++;
} }
return lexer(str); return lexer(str);
} else if (c == '/') { } else if (c == '/') { // start of '//' line comment
while (c > 0 && c != '\n') while (c > 0 && c != '\n')
c = f.get(); c = f.get();
line++; line++;
@ -144,24 +150,31 @@ int LibertyParser::lexer(std::string &str)
} }
f.unget(); f.unget();
// fprintf(stderr, "LEX: char >>/<<\n"); // fprintf(stderr, "LEX: char >>/<<\n");
return '/'; return '/'; // a single '/' charater.
} }
// check for a backslash
if (c == '\\') { if (c == '\\') {
c = f.get(); c = f.get();
if (c == '\r') if (c == '\r')
c = f.get(); c = f.get();
if (c == '\n') if (c == '\n') {
line++;
return lexer(str); return lexer(str);
}
f.unget(); f.unget();
return '\\'; return '\\';
} }
// check for a new line
if (c == '\n') { if (c == '\n') {
line++; line++;
return 'n'; return 'n';
} }
// anything else, such as ';' will get passed
// through as literal items.
// if (c >= 32 && c < 255) // if (c >= 32 && c < 255)
// fprintf(stderr, "LEX: char >>%c<<\n", c); // fprintf(stderr, "LEX: char >>%c<<\n", c);
// else // else
@ -175,14 +188,39 @@ LibertyAst *LibertyParser::parse()
int tok = lexer(str); int tok = lexer(str);
while (tok == 'n') // there are liberty files in the wild that
// have superfluous ';' at the end of
// a { ... }. We simply ignore a ';' here.
// and get to the next statement.
while ((tok == 'n') || (tok == ';'))
tok = lexer(str); tok = lexer(str);
if (tok == '}' || tok < 0) if (tok == '}' || tok < 0)
return NULL; return NULL;
if (tok != 'v') if (tok != 'v') {
error(); std::string eReport;
switch(tok)
{
case 'n':
error("Unexpected newline.");
break;
case '[':
case ']':
case '}':
case '{':
case '\"':
case ':':
eReport = "Unexpected '";
eReport += static_cast<char>(tok);
eReport += "'.";
error(eReport);
break;
default:
error();
}
}
LibertyAst *ast = new LibertyAst; LibertyAst *ast = new LibertyAst;
ast->id = str; ast->id = str;
@ -191,12 +229,11 @@ LibertyAst *LibertyParser::parse()
{ {
tok = lexer(str); tok = lexer(str);
if (tok == ';') // allow both ';' and new lines to
// terminate a statement.
if ((tok == ';') || (tok == 'n'))
break; break;
if (tok == 'n')
continue;
if (tok == ':' && ast->value.empty()) { if (tok == ':' && ast->value.empty()) {
tok = lexer(ast->value); tok = lexer(ast->value);
if (tok != 'v') if (tok != 'v')
@ -210,7 +247,12 @@ LibertyAst *LibertyParser::parse()
ast->value += str; ast->value += str;
tok = lexer(str); tok = lexer(str);
} }
if (tok == ';')
// In a liberty file, all key : value pairs should end in ';'
// However, there are some liberty files in the wild that
// just have a newline. We'll be kind and accept a newline
// instead of the ';' too..
if ((tok == ';') || (tok == 'n'))
break; break;
else else
error(); error();
@ -225,8 +267,70 @@ LibertyAst *LibertyParser::parse()
continue; continue;
if (tok == ')') if (tok == ')')
break; break;
if (tok != 'v')
error(); // FIXME: the AST needs to be extended to store
// these vector ranges.
if (tok == '[')
{
// parse vector range [A] or [A:B]
std::string arg;
tok = lexer(arg);
if (tok != 'v')
{
// expected a vector array index
error("Expected a number.");
}
else
{
// fixme: check for number A
}
tok = lexer(arg);
// optionally check for : in case of [A:B]
// if it isn't we just expect ']'
// as we have [A]
if (tok == ':')
{
tok = lexer(arg);
if (tok != 'v')
{
// expected a vector array index
error("Expected a number.");
}
else
{
// fixme: check for number B
tok = lexer(arg);
}
}
// expect a closing bracket of array range
if (tok != ']')
{
error("Expected ']' on array range.");
}
continue;
}
if (tok != 'v') {
std::string eReport;
switch(tok)
{
case 'n':
error("Unexpected newline.");
break;
case '[':
case ']':
case '}':
case '{':
case '\"':
case ':':
eReport = "Unexpected '";
eReport += static_cast<char>(tok);
eReport += "'.";
error(eReport);
break;
default:
error();
}
}
ast->args.push_back(arg); ast->args.push_back(arg);
} }
continue; continue;
@ -255,6 +359,14 @@ void LibertyParser::error()
log_error("Syntax error in liberty file on line %d.\n", line); log_error("Syntax error in liberty file on line %d.\n", line);
} }
void LibertyParser::error(const std::string &str)
{
std::stringstream ss;
ss << "Syntax error in liberty file on line " << line << ".\n";
ss << " " << str << "\n";
log_error("%s", ss.str().c_str());
}
#else #else
void LibertyParser::error() void LibertyParser::error()
@ -263,25 +375,34 @@ void LibertyParser::error()
exit(1); exit(1);
} }
void LibertyParser::error(const std::string &str)
{
std::stringstream ss;
ss << "Syntax error in liberty file on line " << line << ".\n";
ss << " " << str << "\n";
printf("%s", ss.str().c_str());
exit(1);
}
/**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/ /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
#define CHECK_NV(result, check) \ #define CHECK_NV(result, check) \
do { \ do { \
auto _R = (result); \ auto _R = (result); \
if (!(_R check)) { \ if (!(_R check)) { \
fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \ fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
#result, (long int)_R, #check, __FILE__, __LINE__); \ #result, (long int)_R, #check, __FILE__, __LINE__); \
abort(); \ abort(); \
} \ } \
} while(0) } while(0)
#define CHECK_COND(result) \ #define CHECK_COND(result) \
do { \ do { \
if (!(result)) { \ if (!(result)) { \
fprintf(stderr, "Error from '%s' in %s:%d.\n", \ fprintf(stderr, "Error from '%s' in %s:%d.\n", \
#result, __FILE__, __LINE__); \ #result, __FILE__, __LINE__); \
abort(); \ abort(); \
} \ } \
} while(0) } while(0)
/**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/ /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/

View File

@ -46,9 +46,17 @@ namespace Yosys
LibertyAst *ast; LibertyAst *ast;
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {} LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
~LibertyParser() { if (ast) delete ast; } ~LibertyParser() { if (ast) delete ast; }
/* lexer return values:
'v': identifier, string, array range [...] -> str holds the token string
'n': newline
anything else is a single character.
*/
int lexer(std::string &str); int lexer(std::string &str);
LibertyAst *parse();
LibertyAst *parse();
void error(); void error();
void error(const std::string &str);
}; };
} }

View File

@ -30,7 +30,7 @@ endmodule
module PADOUT (output padout, input padin, input oe); module PADOUT (output padout, input padin, input oe);
assign padout = padin; assign padout = padin;
assign oe = oe; assign oe = oe;
endmodule endmodule
module LUT4 (output dout, module LUT4 (output dout,
input din0, din1, din2, din3); input din0, din1, din2, din3);
@ -66,14 +66,14 @@ always @(dataa_w or datab_w or datac_w or datad_w) begin
datac_w, datad_w); datac_w, datad_w);
end end
assign dout = combout_rt & 1'b1; assign dout = combout_rt & 1'b1;
endmodule endmodule
module DFF (output q, module DFF (output q,
input d, ck); input d, ck);
reg q; reg q;
always @(posedge ck) always @(posedge ck)
q <= d; q <= d;
endmodule endmodule

View File

@ -52,13 +52,13 @@ struct AnlogicEqnPass : public Pass {
eqn += names[j]; eqn += names[j];
else else
eqn += std::string("~") + names[j]; eqn += std::string("~") + names[j];
if (j!=(inputs-1)) eqn += "*"; if (j!=(inputs-1)) eqn += "*";
} }
eqn += ")+"; eqn += ")+";
} }
} }
if (eqn.empty()) return Const("0"); if (eqn.empty()) return Const("0");
eqn = eqn.substr(0, eqn.length()-1); eqn = eqn.substr(0, eqn.length()-1);
return Const(eqn); return Const(eqn);
} }

View File

@ -1,5 +1,5 @@
OBJS += techlibs/ecp5/synth_ecp5.o OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v))

View File

@ -33,7 +33,7 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO);
input CI, BI; input CI, BI;
output [Y_WIDTH-1:0] CO; output [Y_WIDTH-1:0] CO;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));

View File

@ -156,6 +156,41 @@ module OSCG(
parameter DIV = 128; parameter DIV = 128;
endmodule endmodule
(* blackbox *) (* keep *)
module USRMCLK(
input USRMCLKI, USRMCLKTS,
output USRMCLKO
);
endmodule
(* blackbox *) (* keep *)
module JTAGG(
input TCK, TMS, TDI, JTDO2, JTDO1,
output TDO, JTDI, JTCK, JRTI2, JRTI1,
output JSHIFT, JUPDATE, JRSTN, JCE2, JCE1
);
parameter ER1 = "ENABLED";
parameter ER2 = "ENABLED";
endmodule
(* blackbox *)
module DELAYF(
input A, LOADN, MOVE, DIRECTION,
output Z, CFLAG
);
parameter DEL_MODE = "USER_DEFINED";
parameter DEL_VALUE = 0;
endmodule
(* blackbox *)
module DELAYG(
input A,
output Z
);
parameter DEL_MODE = "USER_DEFINED";
parameter DEL_VALUE = 0;
endmodule
(* blackbox *) (* blackbox *)
module IDDRX1F( module IDDRX1F(
input D, SCLK, RST, input D, SCLK, RST,
@ -164,6 +199,31 @@ module IDDRX1F(
parameter GSR = "ENABLED"; parameter GSR = "ENABLED";
endmodule endmodule
(* blackbox *)
module IDDRX2F(
input D, SCLK, ECLK, RST,
output Q0, Q1, Q2, Q3
);
parameter GSR = "ENABLED";
endmodule
(* blackbox *)
module IDDR71B(
input D, SCLK, ECLK, RST, ALIGNWD,
output Q0, Q1, Q2, Q3, Q4, Q5, Q6
);
parameter GSR = "ENABLED";
endmodule
(* blackbox *)
module IDDRX2DQA(
input D, DQSR90, ECLK, SCLK, RST,
input RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0,
output Q0, Q1, Q2, Q3, QWL
);
parameter GSR = "ENABLED";
endmodule
(* blackbox *) (* blackbox *)
module ODDRX1F( module ODDRX1F(
input SCLK, RST, D0, D1, input SCLK, RST, D0, D1,
@ -172,6 +232,91 @@ module ODDRX1F(
parameter GSR = "ENABLED"; parameter GSR = "ENABLED";
endmodule endmodule
(* blackbox *)
module ODDRX2F(
input SCLK, ECLK, RST, D0, D1, D2, D3,
output Q
);
parameter GSR = "ENABLED";
endmodule
(* blackbox *)
module ODDR71B(
input SCLK, ECLK, RST, D0, D1, D2, D3, D4, D5, D6,
output Q
);
parameter GSR = "ENABLED";
endmodule
(* blackbox *)
module OSHX2A(
input D0, D1, RST, ECLK, SCLK,
output Q
);
parameter GSR = "ENABLED";
endmodule
(* blackbox *)
module ODDRX2DQA(
input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW270,
output Q
);
parameter GSR = "ENABLED";
endmodule
(* blackbox *)
module ODDRX2DQSB(
input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW,
output Q
);
parameter GSR = "ENABLED";
endmodule
(* blackbox *)
module TSHX2DQA(
input T0, T1, SCLK, ECLK, DQSW270, RST,
output Q
);
parameter GSR = "ENABLED";
parameter REGSET = "SET";
endmodule
(* blackbox *)
module TSHX2DQSA(
input T0, T1, SCLK, ECLK, DQSW, RST,
output Q
);
parameter GSR = "ENABLED";
parameter REGSET = "SET";
endmodule
(* blackbox *)
module DQSBUFM(
input DQSI, READ1, READ0, READCLKSEL2, READCLKSEL1, READCLKSEL0, DDRDEL,
input ECLK, SCLK,
input DYNDELAY7, DYNDELAY6, DYNDELAY5, DYNDELAY4,
input DYNDELAY3, DYNDELAY2, DYNDELAY1, DYNDELAY0,
input RST, RDLOADN, RDMOVE, RDDIRECTION, WRLOADN, WRMOVE, WRDIRECTION, PAUSE,
output DQSR90, DQSW, DQSW270,
output RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0,
output DATAVALID, BURSTDET, RDCFLAG, WRCFLAG
);
parameter DQS_LI_DEL_ADJ = "FACTORYONLY";
parameter DQS_LI_DEL_VAL = 0;
parameter DQS_LO_DEL_ADJ = "FACTORYONLY";
parameter DQS_LO_DEL_VAL = 0;
parameter GSR = "ENABLED";
endmodule
(* blackbox *)
module DDRDLLA(
input CLK, RST, UDDCNTLN, FREEZE,
output LOCK, DDRDEL, DCNTL7, DCNTL6, DCNTL5, DCNTL4, DCNTL3, DCNTL2, DCNTL1, DCNTL0
);
parameter FORCE_MAX_DELAY = "NO";
parameter GSR = "ENABLED";
endmodule
(* blackbox *) (* blackbox *)
module CLKDIVF( module CLKDIVF(
input CLKI, RST, ALIGNWD, input CLKI, RST, ALIGNWD,
@ -181,6 +326,13 @@ module CLKDIVF(
parameter DIV = "2.0"; parameter DIV = "2.0";
endmodule endmodule
(* blackbox *)
module ECLKSYNCB(
input ECLKI, STOP,
output ECLKO
);
endmodule
(* blackbox *) (* blackbox *)
module DCCA( module DCCA(
input CLKI, CE, input CLKI, CE,

View File

@ -47,6 +47,9 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"
module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
// For Diamond compatibility, FIXME: add all Diamond flipflop mappings
module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
`ifndef NO_LUT `ifndef NO_LUT
module \$lut (A, Y); module \$lut (A, Y);
parameter WIDTH = 0; parameter WIDTH = 0;

View File

@ -203,13 +203,14 @@ endmodule
// --------------------------------------- // ---------------------------------------
module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q); module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
parameter GSR = "ENABLED"; parameter GSR = "ENABLED";
parameter [127:0] CEMUX = "1"; parameter [127:0] CEMUX = "1";
parameter CLKMUX = "CLK"; parameter CLKMUX = "CLK";
parameter LSRMUX = "LSR"; parameter LSRMUX = "LSR";
parameter SRMODE = "LSR_OVER_CE"; parameter SRMODE = "LSR_OVER_CE";
parameter REGSET = "RESET"; parameter REGSET = "RESET";
parameter [127:0] LSRMODE = "LSR";
reg muxce; reg muxce;
always @(*) always @(*)
@ -222,8 +223,13 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q);
wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR; wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR;
wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK; wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK;
wire srval;
localparam srval = (REGSET == "SET") ? 1'b1 : 1'b0; generate
if (LSRMODE == "PRLD")
assign srval = M;
else
assign srval = (REGSET == "SET") ? 1'b1 : 1'b0;
endgenerate
initial Q = srval; initial Q = srval;
@ -339,6 +345,8 @@ module TRELLIS_SLICE(
parameter REG1_SD = "0"; parameter REG1_SD = "0";
parameter REG0_REGSET = "RESET"; parameter REG0_REGSET = "RESET";
parameter REG1_REGSET = "RESET"; parameter REG1_REGSET = "RESET";
parameter REG0_LSRMODE = "LSR";
parameter REG1_LSRMODE = "LSR";
parameter [127:0] CCU2_INJECT1_0 = "NO"; parameter [127:0] CCU2_INJECT1_0 = "NO";
parameter [127:0] CCU2_INJECT1_1 = "NO"; parameter [127:0] CCU2_INJECT1_1 = "NO";
parameter WREMUX = "WRE"; parameter WREMUX = "WRE";
@ -428,10 +436,11 @@ module TRELLIS_SLICE(
.CLKMUX(CLKMUX), .CLKMUX(CLKMUX),
.LSRMUX(LSRMUX), .LSRMUX(LSRMUX),
.SRMODE(SRMODE), .SRMODE(SRMODE),
.REGSET(REG0_REGSET) .REGSET(REG0_REGSET),
.LSRMODE(REG0_LSRMODE)
) ff_0 ( ) ff_0 (
.CLK(CLK), .LSR(LSR), .CE(CE), .CLK(CLK), .LSR(LSR), .CE(CE),
.DI(muxdi0), .DI(muxdi0), .M(M0),
.Q(Q0) .Q(Q0)
); );
TRELLIS_FF #( TRELLIS_FF #(
@ -440,10 +449,11 @@ module TRELLIS_SLICE(
.CLKMUX(CLKMUX), .CLKMUX(CLKMUX),
.LSRMUX(LSRMUX), .LSRMUX(LSRMUX),
.SRMODE(SRMODE), .SRMODE(SRMODE),
.REGSET(REG1_REGSET) .REGSET(REG1_REGSET),
.LSRMODE(REG1_LSRMODE)
) ff_1 ( ) ff_1 (
.CLK(CLK), .LSR(LSR), .CE(CE), .CLK(CLK), .LSR(LSR), .CE(CE),
.DI(muxdi1), .DI(muxdi1), .M(M1),
.Q(Q1) .Q(Q1)
); );
endmodule endmodule
@ -547,3 +557,20 @@ module DP16KD(
parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
endmodule endmodule
// For Diamond compatibility, FIXME: add all Diamond flipflop mappings
module FD1S3BX(input PD, D, CK, output Q);
TRELLIS_FF #(
.GSR("DISABLED"),
.CEMUX("1"),
.CLKMUX("CLK"),
.LSRMUX("LSR"),
.REGSET("SET"),
.SRMODE("ASYNC")
) tff_i (
.CLK(CK),
.LSR(PD),
.DI(D),
.Q(Q)
);
endmodule

View File

@ -0,0 +1,203 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* Copyright (C) 2018-19 David Shah <david@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct Ecp5FfinitPass : public Pass {
Ecp5FfinitPass() : Pass("ecp5_ffinit", "ECP5: handle FF init values") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" ecp5_ffinit [options] [selection]\n");
log("\n");
log("Remove init values for FF output signals when equal to reset value.\n");
log("If reset is not used, set the reset value to the init value, otherwise\n");
log("unmap out the reset (if not an async reset).\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ECP5_FFINIT pass (implement FF init values).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-singleton") {
// singleton_mode = true;
// continue;
// }
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
log("Handling FF init values in %s.\n", log_id(module));
SigMap sigmap(module);
pool<Wire*> init_wires;
dict<SigBit, State> initbits;
dict<SigBit, SigBit> initbit_to_wire;
pool<SigBit> handled_initbits;
for (auto wire : module->selected_wires())
{
if (wire->attributes.count("\\init") == 0)
continue;
SigSpec wirebits = sigmap(wire);
Const initval = wire->attributes.at("\\init");
init_wires.insert(wire);
for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)
{
SigBit bit = wirebits[i];
State val = initval[i];
if (val != State::S0 && val != State::S1)
continue;
if (initbits.count(bit)) {
if (initbits.at(bit) != val) {
log_warning("Conflicting init values for signal %s (%s = %s, %s = %s).\n",
log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val),
log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit)));
initbits.at(bit) = State::Sx;
}
continue;
}
initbits[bit] = val;
initbit_to_wire[bit] = SigBit(wire, i);
}
}
for (auto cell : module->selected_cells())
{
if (cell->type != "\\TRELLIS_FF")
continue;
SigSpec sig_d = cell->getPort("\\DI");
SigSpec sig_q = cell->getPort("\\Q");
SigSpec sig_lsr = cell->getPort("\\LSR");
if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1)
continue;
SigBit bit_d = sigmap(sig_d[0]);
SigBit bit_q = sigmap(sig_q[0]);
std::string regset = "RESET";
if (cell->hasParam("\\REGSET"))
regset = cell->getParam("\\REGSET").decode_string();
State resetState;
if (regset == "SET")
resetState = State::S1;
else if (regset == "RESET")
resetState = State::S0;
else
log_error("FF cell %s has illegal REGSET value %s.\n",
log_id(cell), regset.c_str());
if (!initbits.count(bit_q))
continue;
State val = initbits.at(bit_q);
if (val == State::Sx)
continue;
log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type),
log_signal(bit_q), val != State::S0 ? '1' : '0');
// Initval is the same as the reset state. Matches hardware, nowt more to do
if (val == resetState) {
handled_initbits.insert(bit_q);
continue;
}
if (GetSize(sig_lsr) >= 1 && sig_lsr[0] != State::S0) {
std::string srmode = "LSR_OVER_CE";
if (cell->hasParam("\\SRMODE"))
srmode = cell->getParam("\\SRMODE").decode_string();
if (srmode == "ASYNC") {
log("Async reset value %c for FF cell %s inconsistent with init value %c.\n",
resetState != State::S0 ? '1' : '0', log_id(cell), val != State::S0 ? '1' : '0');
} else {
SigBit bit_lsr = sigmap(sig_lsr[0]);
Wire *new_bit_d = module->addWire(NEW_ID);
if (resetState == State::S0) {
module->addAndnotGate(NEW_ID, bit_d, bit_lsr, new_bit_d);
} else {
module->addOrGate(NEW_ID, bit_d, bit_lsr, new_bit_d);
}
cell->setPort("\\DI", new_bit_d);
cell->setPort("\\LSR", State::S0);
if(cell->hasPort("\\CE")) {
std::string cemux = "CE";
if (cell->hasParam("\\CEMUX"))
cemux = cell->getParam("\\CEMUX").decode_string();
SigSpec sig_ce = cell->getPort("\\CE");
if (GetSize(sig_ce) >= 1) {
SigBit bit_ce = sigmap(sig_ce[0]);
Wire *new_bit_ce = module->addWire(NEW_ID);
if (cemux == "INV")
module->addAndnotGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce);
else
module->addOrGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce);
cell->setPort("\\CE", new_bit_ce);
}
}
cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET"));
handled_initbits.insert(bit_q);
}
} else {
cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET"));
handled_initbits.insert(bit_q);
}
}
for (auto wire : init_wires)
{
if (wire->attributes.count("\\init") == 0)
continue;
SigSpec wirebits = sigmap(wire);
Const &initval = wire->attributes.at("\\init");
bool remove_attribute = true;
for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) {
if (handled_initbits.count(wirebits[i]))
initval[i] = State::Sx;
else if (initval[i] != State::Sx)
remove_attribute = false;
}
if (remove_attribute)
wire->attributes.erase("\\init");
}
}
}
} Ecp5FfinitPass;
PRIVATE_NAMESPACE_END

View File

@ -255,10 +255,7 @@ struct SynthEcp5Pass : public ScriptPass
run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
run("opt_expr -mux_undef"); run("opt_expr -mux_undef");
run("simplemap"); run("simplemap");
// TODO
#if 0
run("ecp5_ffinit"); run("ecp5_ffinit");
#endif
} }
if (check_label("map_luts")) if (check_label("map_luts"))

View File

@ -25,24 +25,24 @@ module _80_gw1n_alu(A, B, CI, BI, X, Y, CO);
parameter A_WIDTH = 1; parameter A_WIDTH = 1;
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
output [Y_WIDTH-1:0] CO; output [Y_WIDTH-1:0] CO;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
wire [Y_WIDTH-1:0] A_buf, B_buf; wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH-1:0] C = {CO, CI}; wire [Y_WIDTH-1:0] C = {CO, CI};
genvar i; genvar i;
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
ALU #(.ALU_MODE(32'b0)) ALU #(.ALU_MODE(32'b0))

View File

@ -111,7 +111,7 @@ struct SynthGowinPass : public ScriptPass
if (args[argidx] == "-noflatten") { if (args[argidx] == "-noflatten") {
flatten = false; flatten = false;
continue; continue;
} }
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);

View File

@ -1,5 +1,6 @@
OBJS += techlibs/ice40/synth_ice40.o OBJS += techlibs/ice40/synth_ice40.o
OBJS += techlibs/ice40/ice40_braminit.o
OBJS += techlibs/ice40/ice40_ffssr.o OBJS += techlibs/ice40/ice40_ffssr.o
OBJS += techlibs/ice40/ice40_ffinit.o OBJS += techlibs/ice40/ice40_ffinit.o
OBJS += techlibs/ice40/ice40_opt.o OBJS += techlibs/ice40/ice40_opt.o

View File

@ -7,8 +7,8 @@ module \$__ICE40_RAM4K (
input [10:0] WADDR, input [10:0] WADDR,
input [15:0] MASK, WDATA input [15:0] MASK, WDATA
); );
parameter integer READ_MODE = 0; parameter [1:0] READ_MODE = 0;
parameter integer WRITE_MODE = 0; parameter [1:0] WRITE_MODE = 0;
parameter [0:0] NEGCLK_R = 0; parameter [0:0] NEGCLK_R = 0;
parameter [0:0] NEGCLK_W = 0; parameter [0:0] NEGCLK_W = 0;

View File

@ -326,6 +326,8 @@ module SB_RAM40_4K (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_FILE = "";
`ifndef BLACKBOX `ifndef BLACKBOX
wire [15:0] WMASK_I; wire [15:0] WMASK_I;
wire [15:0] RMASK_I; wire [15:0] RMASK_I;
@ -408,43 +410,27 @@ module SB_RAM40_4K (
reg [15:0] memory [0:255]; reg [15:0] memory [0:255];
initial begin initial begin
for (i=0; i<16; i=i+1) begin if (INIT_FILE != "")
`ifdef YOSYS $readmemh(INIT_FILE, memory);
memory[ 0*16 + i] <= INIT_0[16*i +: 16]; else
memory[ 1*16 + i] <= INIT_1[16*i +: 16]; for (i=0; i<16; i=i+1) begin
memory[ 2*16 + i] <= INIT_2[16*i +: 16]; memory[ 0*16 + i] = INIT_0[16*i +: 16];
memory[ 3*16 + i] <= INIT_3[16*i +: 16]; memory[ 1*16 + i] = INIT_1[16*i +: 16];
memory[ 4*16 + i] <= INIT_4[16*i +: 16]; memory[ 2*16 + i] = INIT_2[16*i +: 16];
memory[ 5*16 + i] <= INIT_5[16*i +: 16]; memory[ 3*16 + i] = INIT_3[16*i +: 16];
memory[ 6*16 + i] <= INIT_6[16*i +: 16]; memory[ 4*16 + i] = INIT_4[16*i +: 16];
memory[ 7*16 + i] <= INIT_7[16*i +: 16]; memory[ 5*16 + i] = INIT_5[16*i +: 16];
memory[ 8*16 + i] <= INIT_8[16*i +: 16]; memory[ 6*16 + i] = INIT_6[16*i +: 16];
memory[ 9*16 + i] <= INIT_9[16*i +: 16]; memory[ 7*16 + i] = INIT_7[16*i +: 16];
memory[10*16 + i] <= INIT_A[16*i +: 16]; memory[ 8*16 + i] = INIT_8[16*i +: 16];
memory[11*16 + i] <= INIT_B[16*i +: 16]; memory[ 9*16 + i] = INIT_9[16*i +: 16];
memory[12*16 + i] <= INIT_C[16*i +: 16]; memory[10*16 + i] = INIT_A[16*i +: 16];
memory[13*16 + i] <= INIT_D[16*i +: 16]; memory[11*16 + i] = INIT_B[16*i +: 16];
memory[14*16 + i] <= INIT_E[16*i +: 16]; memory[12*16 + i] = INIT_C[16*i +: 16];
memory[15*16 + i] <= INIT_F[16*i +: 16]; memory[13*16 + i] = INIT_D[16*i +: 16];
`else memory[14*16 + i] = INIT_E[16*i +: 16];
memory[ 0*16 + i] = INIT_0[16*i +: 16]; memory[15*16 + i] = INIT_F[16*i +: 16];
memory[ 1*16 + i] = INIT_1[16*i +: 16]; end
memory[ 2*16 + i] = INIT_2[16*i +: 16];
memory[ 3*16 + i] = INIT_3[16*i +: 16];
memory[ 4*16 + i] = INIT_4[16*i +: 16];
memory[ 5*16 + i] = INIT_5[16*i +: 16];
memory[ 6*16 + i] = INIT_6[16*i +: 16];
memory[ 7*16 + i] = INIT_7[16*i +: 16];
memory[ 8*16 + i] = INIT_8[16*i +: 16];
memory[ 9*16 + i] = INIT_9[16*i +: 16];
memory[10*16 + i] = INIT_A[16*i +: 16];
memory[11*16 + i] = INIT_B[16*i +: 16];
memory[12*16 + i] = INIT_C[16*i +: 16];
memory[13*16 + i] = INIT_D[16*i +: 16];
memory[14*16 + i] = INIT_E[16*i +: 16];
memory[15*16 + i] = INIT_F[16*i +: 16];
`endif
end
end end
always @(posedge WCLK) begin always @(posedge WCLK) begin
@ -504,6 +490,8 @@ module SB_RAM40_4KNR (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_FILE = "";
SB_RAM40_4K #( SB_RAM40_4K #(
.WRITE_MODE(WRITE_MODE), .WRITE_MODE(WRITE_MODE),
.READ_MODE (READ_MODE ), .READ_MODE (READ_MODE ),
@ -522,7 +510,8 @@ module SB_RAM40_4KNR (
.INIT_C (INIT_C ), .INIT_C (INIT_C ),
.INIT_D (INIT_D ), .INIT_D (INIT_D ),
.INIT_E (INIT_E ), .INIT_E (INIT_E ),
.INIT_F (INIT_F ) .INIT_F (INIT_F ),
.INIT_FILE (INIT_FILE )
) RAM ( ) RAM (
.RDATA(RDATA), .RDATA(RDATA),
.RCLK (~RCLKN), .RCLK (~RCLKN),
@ -566,6 +555,8 @@ module SB_RAM40_4KNW (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_FILE = "";
SB_RAM40_4K #( SB_RAM40_4K #(
.WRITE_MODE(WRITE_MODE), .WRITE_MODE(WRITE_MODE),
.READ_MODE (READ_MODE ), .READ_MODE (READ_MODE ),
@ -584,7 +575,8 @@ module SB_RAM40_4KNW (
.INIT_C (INIT_C ), .INIT_C (INIT_C ),
.INIT_D (INIT_D ), .INIT_D (INIT_D ),
.INIT_E (INIT_E ), .INIT_E (INIT_E ),
.INIT_F (INIT_F ) .INIT_F (INIT_F ),
.INIT_FILE (INIT_FILE )
) RAM ( ) RAM (
.RDATA(RDATA), .RDATA(RDATA),
.RCLK (RCLK ), .RCLK (RCLK ),
@ -628,6 +620,8 @@ module SB_RAM40_4KNRNW (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_FILE = "";
SB_RAM40_4K #( SB_RAM40_4K #(
.WRITE_MODE(WRITE_MODE), .WRITE_MODE(WRITE_MODE),
.READ_MODE (READ_MODE ), .READ_MODE (READ_MODE ),
@ -646,7 +640,8 @@ module SB_RAM40_4KNRNW (
.INIT_C (INIT_C ), .INIT_C (INIT_C ),
.INIT_D (INIT_D ), .INIT_D (INIT_D ),
.INIT_E (INIT_E ), .INIT_E (INIT_E ),
.INIT_F (INIT_F ) .INIT_F (INIT_F ),
.INIT_FILE (INIT_FILE )
) RAM ( ) RAM (
.RDATA(RDATA), .RDATA(RDATA),
.RCLK (~RCLKN), .RCLK (~RCLKN),

View File

@ -0,0 +1,159 @@
/*
* 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"
#include <stdlib.h>
#include <stdio.h>
#include <bitset>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static void run_ice40_braminit(Module *module)
{
for (auto cell : module->selected_cells())
{
uint16_t mem[256];
/* Only consider cells we're interested in */
if (cell->type != "\\SB_RAM40_4K" &&
cell->type != "\\SB_RAM40_4KNR" &&
cell->type != "\\SB_RAM40_4KNW" &&
cell->type != "\\SB_RAM40_4KNRNW")
continue;
if (!cell->hasParam("\\INIT_FILE"))
continue;
std::string init_file = cell->getParam("\\INIT_FILE").decode_string();
cell->unsetParam("\\INIT_FILE");
if (init_file == "")
continue;
/* Open file */
log("Processing %s : %s\n", RTLIL::id2cstr(cell->name), init_file.c_str());
std::ifstream f;
f.open(init_file.c_str());
if (f.fail()) {
log("Can not open file `%s`.\n", init_file.c_str());
continue;
}
/* Defaults to 0 */
memset(mem, 0x00, sizeof(mem));
/* Process each line */
bool in_comment = false;
int cursor = 0;
while (!f.eof())
{
std::string line, token;
std::getline(f, line);
for (int i = 0; i < GetSize(line); i++)
{
if (in_comment && line.substr(i, 2) == "*/") {
line[i] = ' ';
line[i+1] = ' ';
in_comment = false;
continue;
}
if (!in_comment && line.substr(i, 2) == "/*")
in_comment = true;
if (in_comment)
line[i] = ' ';
}
while (1)
{
bool set_cursor = false;
long value;
token = next_token(line, " \t\r\n");
if (token.empty() || token.substr(0, 2) == "//")
break;
if (token[0] == '@') {
token = token.substr(1);
set_cursor = true;
}
const char *nptr = token.c_str();
char *endptr;
value = strtol(nptr, &endptr, 16);
if (!*nptr || *endptr) {
log("Can not parse %s `%s` for %s.\n",
set_cursor ? "address" : "value",
nptr, token.c_str()
);
continue;
}
if (set_cursor)
cursor = value;
else if (cursor >= 0 && cursor < 256)
mem[cursor++] = value;
else
log("Attempt to initialize non existent address %d\n", cursor);
}
}
/* Set attributes */
const char *hex = "0123456789ABCDEF";
for (int i=0; i<16; i++) {
std::string val = "";
for (int j=15; j>=0; j--)
val += std::bitset<16>(mem[i*16+j]).to_string();
cell->setParam("\\INIT_" + std::string(1, hex[i]), RTLIL::Const::from_string(val));
}
}
}
struct Ice40BRAMInitPass : public Pass {
Ice40BRAMInitPass() : Pass("ice40_braminit", "iCE40: perform SB_RAM40_4K initialization from file") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" ice40_braminit\n");
log("\n");
log("This command processes all SB_RAM40_4K blocks with a non-empty INIT_FILE\n");
log("parameter and converts it into the required INIT_x attributes\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ICE40_BRAMINIT pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
// if (args[argidx] == "-???") {
// continue;
// }
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
run_ice40_braminit(module);
}
} Ice40BRAMInitPass;
PRIVATE_NAMESPACE_END

View File

@ -266,6 +266,7 @@ struct SynthIce40Pass : public ScriptPass
{ {
run("memory_bram -rules +/ice40/brams.txt"); run("memory_bram -rules +/ice40/brams.txt");
run("techmap -map +/ice40/brams_map.v"); run("techmap -map +/ice40/brams_map.v");
run("ice40_braminit");
} }
if (check_label("map")) if (check_label("map"))

View File

@ -32,7 +32,7 @@ module fa
wire VCC; wire VCC;
assign VCC = 1'b1; assign VCC = 1'b1;
cycloneiv_lcell_comb gen_sum_0 (.combout(sum_x), cycloneiv_lcell_comb gen_sum_0 (.combout(sum_x),
.dataa(a_c), .dataa(a_c),
.datab(b_c), .datab(b_c),
@ -40,7 +40,7 @@ module fa
.datad(VCC)); .datad(VCC));
defparam syn__05_.lut_mask = 16'b1001011010010110; defparam syn__05_.lut_mask = 16'b1001011010010110;
defparam syn__05_.sum_lutc_input = "datac"; defparam syn__05_.sum_lutc_input = "datac";
cycloneiv_lcell_comb gen_cout_0 (.combout(cout_t), cycloneiv_lcell_comb gen_cout_0 (.combout(cout_t),
.dataa(cin_c), .dataa(cin_c),
.datab(b_c), .datab(b_c),
@ -48,11 +48,11 @@ module fa
.datad(VCC)); .datad(VCC));
defparam syn__06_.lut_mask = 16'b1110000011100000; defparam syn__06_.lut_mask = 16'b1110000011100000;
defparam syn__06_.sum_lutc_input = "datac"; defparam syn__06_.sum_lutc_input = "datac";
endmodule // fa endmodule // fa
module f_stage(); module f_stage();
endmodule // f_stage endmodule // f_stage
module f_end(); module f_end();
@ -88,7 +88,7 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO);
.cin_c(C[0]), .cin_c(C[0]),
.cout_t(C0[1]), .cout_t(C0[1]),
.sum_x(Y[0])); .sum_x(Y[0]));
genvar i; genvar i;
generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice
cycloneive_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i])); cycloneive_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i]));

View File

@ -76,7 +76,7 @@ module \$lut (A, Y);
wire VCC; wire VCC;
wire GND; wire GND;
assign {VCC,GND} = {1'b1,1'b0}; assign {VCC,GND} = {1'b1,1'b0};
generate generate
if (WIDTH == 1) begin if (WIDTH == 1) begin
assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
@ -151,7 +151,7 @@ module \$lut (A, Y);
TODO: There's not a just 7-input function on Cyclone V, see the following note: TODO: There's not a just 7-input function on Cyclone V, see the following note:
**Extended LUT Mode** **Extended LUT Mode**
Use extended LUT mode to implement a specific set of 7-input functions. The set must Use extended LUT mode to implement a specific set of 7-input functions. The set must
be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs. be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs.
[source](Device Interfaces and Integration Basics for Cyclone V Devices). [source](Device Interfaces and Integration Basics for Cyclone V Devices).
end*/ end*/
else else

View File

@ -1,40 +1,54 @@
// module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule module \$_DFF_N_ (input D, C, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
endmodule
module \$_DFF_P_ (input D, C, output Q); module \$_DFF_P_ (input D, C, output Q);
SLE _TECHMAP_REPLACE_ ( SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
.D(D), endmodule
.CLK(C),
.EN(1'b1), module \$_DFF_NN0_ (input D, C, R, output Q);
.ALn(1'b1), SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
.ADn(1'b1), endmodule
.SLn(1'b1),
.SD(1'b0), module \$_DFF_NN1_ (input D, C, R, output Q);
.LAT(1'b0), SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
.Q(Q) endmodule
);
module \$_DFF_NP0_ (input D, C, R, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
endmodule
module \$_DFF_NP1_ (input D, C, R, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
endmodule
module \$_DFF_PN0_ (input D, C, R, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
endmodule
module \$_DFF_PN1_ (input D, C, R, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
endmodule
module \$_DFF_PP0_ (input D, C, R, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
endmodule
module \$_DFF_PP1_ (input D, C, R, output Q);
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
endmodule endmodule
// module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule // module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
// module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule // module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
// //
// module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule // module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
// module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule // module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
// //
// module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
// module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
// module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
// module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
//
// module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
// module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
// module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
// module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
//
// module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule // module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
// module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule // module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
// module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule // module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
// module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule // module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
// //
// module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule // module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
// module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule // module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
// module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule // module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule

View File

@ -1,39 +1,25 @@
module SLE ( // https://coredocs.s3.amazonaws.com/Libero/12_0_0/Tool/sf2_mlg.pdf
output Q,
input ADn, module ADD2 (
input ALn,
input CLK, input A, B,
input D, output Y
input LAT,
input SD,
input EN,
input SLn
); );
reg q_latch, q_ff; assign Y = A & B;
endmodule
always @(posedge CLK, negedge ALn) begin module ADD3 (
if (!ALn) begin input A, B, C,
q_ff <= !ADn; output Y
end else if (EN) begin );
if (!SLn) assign Y = A & B & C;
q_ff <= SD; endmodule
else
q_ff <= D;
end
end
always @* begin module ADD4 (
if (!ALn) begin input A, B, C, D,
q_latch <= !ADn; output Y
end else if (CLK && EN) begin );
if (!SLn) assign Y = A & B & C & D;
q_ff <= SD;
else
q_ff <= D;
end
end
assign Q = LAT ? q_latch : q_ff;
endmodule endmodule
module CFG1 ( module CFG1 (
@ -74,6 +60,238 @@ module CFG4 (
assign Y = INIT >> {D, C, B, A}; assign Y = INIT >> {D, C, B, A};
endmodule endmodule
module BUFF (
input A,
output Y
);
assign Y = A;
endmodule
module BUFD (
input A,
output Y
);
assign Y = A;
endmodule
module CLKINT (
input A,
output Y
);
assign Y = A;
endmodule
module CLKINT_PRESERVE (
input A,
output Y
);
assign Y = A;
endmodule
module GCLKINT (
input A, EN,
output Y
);
assign Y = A & EN;
endmodule
module RCLKINT (
input A,
output Y
);
assign Y = A;
endmodule
module RGCLKINT (
input A, EN,
output Y
);
assign Y = A & EN;
endmodule
module SLE (
output Q,
input ADn,
input ALn,
input CLK,
input D,
input LAT,
input SD,
input EN,
input SLn
);
reg q_latch, q_ff;
always @(posedge CLK, negedge ALn) begin
if (!ALn) begin
q_ff <= !ADn;
end else if (EN) begin
if (!SLn)
q_ff <= SD;
else
q_ff <= D;
end
end
always @* begin
if (!ALn) begin
q_latch <= !ADn;
end else if (CLK && EN) begin
if (!SLn)
q_ff <= SD;
else
q_ff <= D;
end
end
assign Q = LAT ? q_latch : q_ff;
endmodule
// module AR1
// module FCEND_BUFF
// module FCINIT_BUFF
// module FLASH_FREEZE
// module OSCILLATOR
// module SYSRESET
// module SYSCTRL_RESET_STATUS
// module LIVE_PROBE_FB
// module GCLKBUF
// module GCLKBUF_DIFF
// module GCLKBIBUF
// module DFN1
// module DFN1C0
// module DFN1E1
// module DFN1E1C0
// module DFN1E1P0
// module DFN1P0
// module DLN1
// module DLN1C0
// module DLN1P0
module INV (
input A,
output Y
);
assign Y = !A;
endmodule
module INVD (
input A,
output Y
);
assign Y = !A;
endmodule
module MX2 (
input A, B, S,
output Y
);
assign Y = S ? B : A;
endmodule
module MX4 (
input D0, D1, D2, D3, S0, S1,
output Y
);
assign Y = S1 ? (S0 ? D3 : D2) : (S0 ? D1 : D0);
endmodule
module NAND2 (
input A, B,
output Y
);
assign Y = !(A & B);
endmodule
module NAND3 (
input A, B, C,
output Y
);
assign Y = !(A & B & C);
endmodule
module NAND4 (
input A, B, C, D,
output Y
);
assign Y = !(A & B & C & D);
endmodule
module NOR2 (
input A, B,
output Y
);
assign Y = !(A | B);
endmodule
module NOR3 (
input A, B, C,
output Y
);
assign Y = !(A | B | C);
endmodule
module NOR4 (
input A, B, C, D,
output Y
);
assign Y = !(A | B | C | D);
endmodule
module OR2 (
input A, B,
output Y
);
assign Y = A | B;
endmodule
module OR3 (
input A, B, C,
output Y
);
assign Y = A | B | C;
endmodule
module OR4 (
input A, B, C, D,
output Y
);
assign Y = A | B | C | D;
endmodule
module XOR2 (
input A, B,
output Y
);
assign Y = A ^ B;
endmodule
module XOR3 (
input A, B, C,
output Y
);
assign Y = A ^ B ^ C;
endmodule
module XOR4 (
input A, B, C, D,
output Y
);
assign Y = A ^ B ^ C ^ D;
endmodule
module XOR8 (
input A, B, C, D, E, F, G, H,
output Y
);
assign Y = A ^ B ^ C ^ D ^ E ^ F ^ G ^ H;
endmodule
// module UJTAG
// module BIBUF
// module BIBUF_DIFF
// module CLKBIBUF
module CLKBUF ( module CLKBUF (
input PAD, input PAD,
output Y output Y
@ -81,6 +299,8 @@ module CLKBUF (
assign Y = PAD; assign Y = PAD;
endmodule endmodule
// module CLKBUF_DIFF
module INBUF ( module INBUF (
input PAD, input PAD,
output Y output Y
@ -88,9 +308,20 @@ module INBUF (
assign Y = PAD; assign Y = PAD;
endmodule endmodule
// module INBUF_DIFF
module OUTBUF ( module OUTBUF (
input D, input D,
output PAD output PAD
); );
assign PAD = D; assign PAD = D;
endmodule endmodule
// module OUTBUF_DIFF
// module TRIBUFF
// module TRIBUFF_DIFF
// module DDR_IN
// module DDR_OUT
// module RAM1K18
// module RAM64x18
// module MACC

View File

@ -23,6 +23,136 @@
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
static void handle_iobufs(Module *module, bool clkbuf_mode)
{
SigMap sigmap(module);
pool<SigBit> clk_bits;
pool<SigBit> handled_io_bits;
dict<SigBit, SigBit> rewrite_bits;
vector<pair<Cell*, SigBit>> pad_bits;
for (auto cell : module->cells())
{
if (clkbuf_mode && cell->type == "\\SLE") {
for (auto bit : sigmap(cell->getPort("\\CLK")))
clk_bits.insert(bit);
}
if (cell->type.in("\\INBUF", "\\OUTBUF", "\\TRIBUFF", "\\BIBUF", "\\CLKBUF", "\\CLKBIBUF",
"\\INBUF_DIFF", "\\OUTBUF_DIFF", "\\BIBUFF_DIFF", "\\TRIBUFF_DIFF", "\\CLKBUF_DIFF",
"\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF")) {
for (auto bit : sigmap(cell->getPort("\\PAD")))
handled_io_bits.insert(bit);
}
}
for (auto wire : vector<Wire*>(module->wires()))
{
if (!wire->port_input && !wire->port_output)
continue;
for (int index = 0; index < GetSize(wire); index++)
{
SigBit bit(wire, index);
SigBit canonical_bit = sigmap(bit);
if (handled_io_bits.count(canonical_bit))
continue;
if (wire->port_input && wire->port_output)
log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit));
IdString buf_type, buf_port;
if (wire->port_output) {
buf_type = "\\OUTBUF";
buf_port = "\\D";
} else if (clkbuf_mode && clk_bits.count(canonical_bit)) {
buf_type = "\\CLKBUF";
buf_port = "\\Y";
} else {
buf_type = "\\INBUF";
buf_port = "\\Y";
}
Cell *c = module->addCell(NEW_ID, buf_type);
SigBit new_bit = module->addWire(NEW_ID);
c->setPort(buf_port, new_bit);
pad_bits.push_back(make_pair(c, bit));
rewrite_bits[canonical_bit] = new_bit;
log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit));
}
}
auto rewrite_function = [&](SigSpec &s) {
for (auto &bit : s) {
SigBit canonical_bit = sigmap(bit);
if (rewrite_bits.count(canonical_bit))
bit = rewrite_bits.at(canonical_bit);
}
};
module->rewrite_sigspecs(rewrite_function);
for (auto &it : pad_bits)
it.first->setPort("\\PAD", it.second);
}
static void handle_clkint(Module *module)
{
SigMap sigmap(module);
pool<SigBit> clk_bits;
vector<SigBit> handled_clk_bits;
for (auto cell : module->cells())
{
if (cell->type == "\\SLE") {
for (auto bit : sigmap(cell->getPort("\\CLK")))
clk_bits.insert(bit);
}
if (cell->type.in("\\CLKBUF", "\\CLKBIBUF", "\\CLKBUF_DIFF", "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF",
"\\CLKINT", "\\CLKINT_PRESERVE", "\\GCLKINT", "\\RCLKINT", "\\RGCLKINT")) {
for (auto bit : sigmap(cell->getPort("\\Y")))
handled_clk_bits.push_back(bit);
}
}
for (auto bit : handled_clk_bits)
clk_bits.erase(bit);
for (auto cell : vector<Cell*>(module->cells()))
for (auto &conn : cell->connections())
{
if (!cell->output(conn.first))
continue;
SigSpec sig = conn.second;
bool did_something = false;
for (auto &bit : sig) {
SigBit canonical_bit = sigmap(bit);
if (clk_bits.count(canonical_bit)) {
Cell *c = module->addCell(NEW_ID, "\\CLKINT");
SigBit new_bit = module->addWire(NEW_ID);
c->setPort("\\A", new_bit);
c->setPort("\\Y", bit);
log("Added %s cell %s for clock signal %s.\n", log_id(c->type), log_id(c), log_signal(bit));
clk_bits.erase(canonical_bit);
did_something = true;
bit = new_bit;
}
}
if (did_something)
cell->setPort(conn.first, sig);
}
for (auto bit : clk_bits)
log_error("Failed to insert CLKINT for clock signal %s.\n", log_signal(bit));
}
struct Sf2IobsPass : public Pass { struct Sf2IobsPass : public Pass {
Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { } Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { }
void help() YS_OVERRIDE void help() YS_OVERRIDE
@ -31,20 +161,25 @@ struct Sf2IobsPass : public Pass {
log("\n"); log("\n");
log(" sf2_iobs [options] [selection]\n"); log(" sf2_iobs [options] [selection]\n");
log("\n"); log("\n");
log("Add SF2 I/O buffers to top module IOs as needed.\n"); log("Add SF2 I/O buffers and global buffers to top module as needed.\n");
log("\n");
log(" -clkbuf\n");
log(" Insert PAD->global_net clock buffers\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
{ {
bool clkbuf_mode = false;
log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n"); log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n");
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
{ {
// if (args[argidx] == "-singleton") { if (args[argidx] == "-clkbuf") {
// singleton_mode = true; clkbuf_mode = true;
// continue; continue;
// } }
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
@ -54,76 +189,8 @@ struct Sf2IobsPass : public Pass {
if (module == nullptr) if (module == nullptr)
log_cmd_error("No top module found.\n"); log_cmd_error("No top module found.\n");
SigMap sigmap(module); handle_iobufs(module, clkbuf_mode);
handle_clkint(module);
pool<SigBit> clk_bits;
pool<SigBit> handled_io_bits;
dict<SigBit, SigBit> rewrite_bits;
vector<pair<Cell*, SigBit>> pad_bits;
for (auto cell : module->cells())
{
if (cell->type == "\\SLE") {
for (auto bit : sigmap(cell->getPort("\\CLK")))
clk_bits.insert(bit);
}
if (cell->type.in("\\INBUF", "\\OUTBUF", "\\CLKBUF")) {
for (auto bit : sigmap(cell->getPort("\\PAD")))
handled_io_bits.insert(bit);
}
}
for (auto wire : vector<Wire*>(module->wires()))
{
if (!wire->port_input && !wire->port_output)
continue;
for (int index = 0; index < GetSize(wire); index++)
{
SigBit bit(wire, index);
SigBit canonical_bit = sigmap(bit);
if (handled_io_bits.count(canonical_bit))
continue;
if (wire->port_input && wire->port_output)
log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit));
IdString buf_type, buf_port;
if (wire->port_output) {
buf_type = "\\OUTBUF";
buf_port = "\\D";
} else if (clk_bits.count(canonical_bit)) {
buf_type = "\\CLKBUF";
buf_port = "\\Y";
} else {
buf_type = "\\INBUF";
buf_port = "\\Y";
}
Cell *c = module->addCell(NEW_ID, buf_type);
SigBit new_bit = module->addWire(NEW_ID);
c->setPort(buf_port, new_bit);
pad_bits.push_back(make_pair(c, bit));
rewrite_bits[canonical_bit] = new_bit;
log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit));
}
}
auto rewrite_function = [&](SigSpec &s) {
for (auto &bit : s) {
SigBit canonical_bit = sigmap(bit);
if (rewrite_bits.count(canonical_bit))
bit = rewrite_bits.at(canonical_bit);
}
};
module->rewrite_sigspecs(rewrite_function);
for (auto &it : pad_bits)
it.first->setPort("\\PAD", it.second);
} }
} Sf2IobsPass; } Sf2IobsPass;

View File

@ -63,6 +63,9 @@ struct SynthSf2Pass : public ScriptPass
log(" -noiobs\n"); log(" -noiobs\n");
log(" run synthesis in \"block mode\", i.e. do not insert IO buffers\n"); log(" run synthesis in \"block mode\", i.e. do not insert IO buffers\n");
log("\n"); log("\n");
log(" -clkbuf\n");
log(" insert direct PAD->global_net buffers\n");
log("\n");
log(" -retime\n"); log(" -retime\n");
log(" run 'abc' with -dff option\n"); log(" run 'abc' with -dff option\n");
log("\n"); log("\n");
@ -73,7 +76,7 @@ struct SynthSf2Pass : public ScriptPass
} }
string top_opt, edif_file, vlog_file, json_file; string top_opt, edif_file, vlog_file, json_file;
bool flatten, retime, iobs; bool flatten, retime, iobs, clkbuf;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
@ -84,6 +87,7 @@ struct SynthSf2Pass : public ScriptPass
flatten = true; flatten = true;
retime = false; retime = false;
iobs = true; iobs = true;
clkbuf = 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
@ -130,6 +134,10 @@ struct SynthSf2Pass : public ScriptPass
iobs = false; iobs = false;
continue; continue;
} }
if (args[argidx] == "-clkbuf") {
clkbuf = true;
continue;
}
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
@ -201,8 +209,10 @@ struct SynthSf2Pass : public ScriptPass
if (check_label("map_iobs")) if (check_label("map_iobs"))
{ {
if (iobs || help_mode) if (help_mode)
run("sf2_iobs", "(unless -noiobs)"); run("sf2_iobs [-clkbuf]", "(unless -noiobs)");
else if (iobs)
run(clkbuf ? "sf2_iobs -clkbuf" : "sf2_iobs");
run("clean"); run("clean");
} }

View File

@ -28,7 +28,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_bb.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut2lut.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))

View File

@ -17,6 +17,9 @@
* *
*/ */
// ============================================================================
// LCU
(* techmap_celltype = "$lcu" *) (* techmap_celltype = "$lcu" *)
module _80_xilinx_lcu (P, G, CI, CO); module _80_xilinx_lcu (P, G, CI, CO);
parameter WIDTH = 2; parameter WIDTH = 2;
@ -28,10 +31,78 @@ module _80_xilinx_lcu (P, G, CI, CO);
wire _TECHMAP_FAIL_ = WIDTH <= 2; wire _TECHMAP_FAIL_ = WIDTH <= 2;
genvar i;
`ifdef _CLB_CARRY
localparam CARRY4_COUNT = (WIDTH + 3) / 4;
localparam MAX_WIDTH = CARRY4_COUNT * 4;
localparam PAD_WIDTH = MAX_WIDTH - WIDTH;
wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G};
wire [MAX_WIDTH-1:0] C = CO;
generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
// Partially occupied CARRY4
if ((i+1)*4 > WIDTH) begin
// First one
if (i == 0) begin
CARRY4 carry4_1st_part
(
.CYINIT(CI),
.CI (1'd0),
.DI (G [(Y_WIDTH - 1):i*4]),
.S (S [(Y_WIDTH - 1):i*4]),
.CO (CO[(Y_WIDTH - 1):i*4]),
);
// Another one
end else begin
CARRY4 carry4_part
(
.CYINIT(1'd0),
.CI (C [i*4 - 1]),
.DI (G [(Y_WIDTH - 1):i*4]),
.S (S [(Y_WIDTH - 1):i*4]),
.CO (CO[(Y_WIDTH - 1):i*4]),
);
end
// Fully occupied CARRY4
end else begin
// First one
if (i == 0) begin
CARRY4 carry4_1st_full
(
.CYINIT(CI),
.CI (1'd0),
.DI (G [((i+1)*4 - 1):i*4]),
.S (S [((i+1)*4 - 1):i*4]),
.CO (CO[((i+1)*4 - 1):i*4]),
);
// Another one
end else begin
CARRY4 carry4_full
(
.CYINIT(1'd0),
.CI (C [i*4 - 1]),
.DI (G [((i+1)*4 - 1):i*4]),
.S (S [((i+1)*4 - 1):i*4]),
.CO (CO[((i+1)*4 - 1):i*4]),
);
end
end
end endgenerate
`elsif _EXPLICIT_CARRY
wire [WIDTH-1:0] C = {CO, CI}; wire [WIDTH-1:0] C = {CO, CI};
wire [WIDTH-1:0] S = P & ~G; wire [WIDTH-1:0] S = P & ~G;
genvar i;
generate for (i = 0; i < WIDTH; i = i + 1) begin:slice generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
MUXCY muxcy ( MUXCY muxcy (
.CI(C[i]), .CI(C[i]),
@ -40,8 +111,28 @@ module _80_xilinx_lcu (P, G, CI, CO);
.O(CO[i]) .O(CO[i])
); );
end endgenerate end endgenerate
`else
wire [WIDTH-1:0] C = {CO, CI};
wire [WIDTH-1:0] S = P & ~G;
generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
MUXCY muxcy (
.CI(C[i]),
.DI(G[i]),
.S(S[i]),
.O(CO[i])
);
end endgenerate
`endif
endmodule endmodule
// ============================================================================
// ALU
(* techmap_celltype = "$alu" *) (* techmap_celltype = "$alu" *)
module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
parameter A_SIGNED = 0; parameter A_SIGNED = 0;
@ -49,6 +140,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
parameter A_WIDTH = 1; parameter A_WIDTH = 1;
parameter B_WIDTH = 1; parameter B_WIDTH = 1;
parameter Y_WIDTH = 1; parameter Y_WIDTH = 1;
parameter _TECHMAP_CONSTVAL_CI_ = 0;
parameter _TECHMAP_CONSTMSK_CI_ = 0;
input [A_WIDTH-1:0] A; input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B; input [B_WIDTH-1:0] B;
@ -66,16 +159,189 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH-1:0] P = AA ^ BB; genvar i;
wire [Y_WIDTH-1:0] G = AA & BB;
wire [Y_WIDTH-1:0] C = {CO, CI}; `ifdef _CLB_CARRY
wire [Y_WIDTH-1:0] S = P & ~G;
localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4;
localparam MAX_WIDTH = CARRY4_COUNT * 4;
localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH;
wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB};
wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB};
wire [MAX_WIDTH-1:0] C = CO;
genvar i; genvar i;
generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
// Partially occupied CARRY4
if ((i+1)*4 > Y_WIDTH) begin
// First one
if (i == 0) begin
CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_part
(
.CYINIT(CI),
.CI (1'd0),
.DI (DI[(Y_WIDTH - 1):i*4]),
.S (S [(Y_WIDTH - 1):i*4]),
.O (Y [(Y_WIDTH - 1):i*4]),
.CO (CO[(Y_WIDTH - 1):i*4])
);
// Another one
end else begin
CARRY4 carry4_part
(
.CYINIT(1'd0),
.CI (C [i*4 - 1]),
.DI (DI[(Y_WIDTH - 1):i*4]),
.S (S [(Y_WIDTH - 1):i*4]),
.O (Y [(Y_WIDTH - 1):i*4]),
.CO (CO[(Y_WIDTH - 1):i*4])
);
end
// Fully occupied CARRY4
end else begin
// First one
if (i == 0) begin
CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_full
(
.CYINIT(CI),
.CI (1'd0),
.DI (DI[((i+1)*4 - 1):i*4]),
.S (S [((i+1)*4 - 1):i*4]),
.O (Y [((i+1)*4 - 1):i*4]),
.CO (CO[((i+1)*4 - 1):i*4])
);
// Another one
end else begin
CARRY4 carry4_full
(
.CYINIT(1'd0),
.CI (C [i*4 - 1]),
.DI (DI[((i+1)*4 - 1):i*4]),
.S (S [((i+1)*4 - 1):i*4]),
.O (Y [((i+1)*4 - 1):i*4]),
.CO (CO[((i+1)*4 - 1):i*4])
);
end
end
end endgenerate
`elsif _EXPLICIT_CARRY
wire [Y_WIDTH-1:0] S = AA ^ BB;
wire [Y_WIDTH-1:0] DI = AA & BB;
wire CINIT;
// Carry chain.
//
// VPR requires that the carry chain never hit the fabric. The CO input
// to this techmap is the carry outputs for synthesis, e.g. might hit the
// fabric.
//
// So we maintain two wire sets, CO_CHAIN is the carry that is for VPR,
// e.g. off fabric dedicated chain. CO is the carry outputs that are
// available to the fabric.
wire [Y_WIDTH-1:0] CO_CHAIN;
wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT};
// If carry chain is being initialized to a constant, techmap the constant
// source. Otherwise techmap the fabric source.
generate for (i = 0; i < 1; i = i + 1) begin:slice
CARRY0 #(.CYINIT_FABRIC(1)) carry(
.CI_INIT(CI),
.DI(DI[0]),
.S(S[0]),
.CO_CHAIN(CO_CHAIN[0]),
.CO_FABRIC(CO[0]),
.O(Y[0])
);
end endgenerate
generate for (i = 1; i < Y_WIDTH-1; i = i + 1) begin:slice
if(i % 4 == 0) begin
CARRY0 carry (
.CI(C[i]),
.DI(DI[i]),
.S(S[i]),
.CO_CHAIN(CO_CHAIN[i]),
.CO_FABRIC(CO[i]),
.O(Y[i])
);
end
else
begin
CARRY carry (
.CI(C[i]),
.DI(DI[i]),
.S(S[i]),
.CO_CHAIN(CO_CHAIN[i]),
.CO_FABRIC(CO[i]),
.O(Y[i])
);
end
end endgenerate
generate for (i = Y_WIDTH-1; i < Y_WIDTH; i = i + 1) begin:slice
if(i % 4 == 0) begin
CARRY0 top_of_carry (
.CI(C[i]),
.DI(DI[i]),
.S(S[i]),
.CO_CHAIN(CO_CHAIN[i]),
.O(Y[i])
);
end
else
begin
CARRY top_of_carry (
.CI(C[i]),
.DI(DI[i]),
.S(S[i]),
.CO_CHAIN(CO_CHAIN[i]),
.O(Y[i])
);
end
// Turns out CO_FABRIC and O both use [ABCD]MUX, so provide
// a non-congested path to output the top of the carry chain.
// Registering the output of the CARRY block would solve this, but not
// all designs do that.
if((i+1) % 4 == 0) begin
CARRY0 carry_output (
.CI(CO_CHAIN[i]),
.DI(0),
.S(0),
.O(CO[i])
);
end
else
begin
CARRY carry_output (
.CI(CO_CHAIN[i]),
.DI(0),
.S(0),
.O(CO[i])
);
end
end endgenerate
`else
wire [Y_WIDTH-1:0] S = AA ^ BB;
wire [Y_WIDTH-1:0] DI = AA & BB;
wire [Y_WIDTH-1:0] C = {CO, CI};
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
MUXCY muxcy ( MUXCY muxcy (
.CI(C[i]), .CI(C[i]),
.DI(G[i]), .DI(DI[i]),
.S(S[i]), .S(S[i]),
.O(CO[i]) .O(CO[i])
); );
@ -86,6 +352,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
); );
end endgenerate end endgenerate
assign X = P; `endif
assign X = S;
endmodule endmodule

View File

@ -1,86 +1,20 @@
/*
* 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.
*
*/
module \$_DFF_N_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule // Empty for now
module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|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 #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|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), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|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 #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|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), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _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), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|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 #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|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), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _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), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
`ifndef NO_LUT
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
input [WIDTH-1:0] A;
output Y;
generate
if (WIDTH == 1) begin
LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]));
end else
if (WIDTH == 2) begin
LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]), .I1(A[1]));
end else
if (WIDTH == 3) begin
LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]), .I1(A[1]), .I2(A[2]));
end else
if (WIDTH == 4) begin
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]));
end else
if (WIDTH == 5) begin
LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]));
end else
if (WIDTH == 6) begin
LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
end else
if (WIDTH == 7) begin
wire T0, T1;
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6]));
end else
if (WIDTH == 8) begin
wire T0, T1, T2, T3, T4, T5;
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6]));
MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6]));
MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7]));
end else begin
wire _TECHMAP_FAIL_ = 1;
end
endgenerate
endmodule
`endif

View File

@ -1,3 +1,21 @@
/*
* 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.
*
*/
// See Xilinx UG953 and UG474 for a description of the cell types below. // See Xilinx UG953 and UG474 for a description of the cell types below.
// http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf // http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf
@ -104,6 +122,29 @@ module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
assign CO[3] = S[3] ? CO[2] : DI[3]; assign CO[3] = S[3] ? CO[2] : DI[3];
endmodule endmodule
`ifdef _EXPLICIT_CARRY
module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S);
parameter CYINIT_FABRIC = 0;
wire CI_COMBINE;
if(CYINIT_FABRIC) begin
assign CI_COMBINE = CI_INIT;
end else begin
assign CI_COMBINE = CI;
end
assign CO_CHAIN = S ? CI_COMBINE : DI;
assign CO_FABRIC = S ? CI_COMBINE : DI;
assign O = S ^ CI_COMBINE;
endmodule
module CARRY(output CO_CHAIN, CO_FABRIC, O, input CI, DI, S);
assign CO_CHAIN = S ? CI : DI;
assign CO_FABRIC = S ? CI : DI;
assign O = S ^ CI;
endmodule
`endif
module FDRE (output reg Q, input C, CE, D, R); module FDRE (output reg Q, input C, CE, D, R);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0;
@ -156,6 +197,30 @@ module FDPE (output reg Q, input C, CE, D, PRE);
endcase endgenerate endcase endgenerate
endmodule endmodule
module FDRE_1 (output reg Q, input C, CE, D, R);
parameter [0:0] INIT = 1'b0;
initial Q <= INIT;
always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
endmodule
module FDSE_1 (output reg Q, input C, CE, D, S);
parameter [0:0] INIT = 1'b1;
initial Q <= INIT;
always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
endmodule
module FDCE_1 (output reg Q, input C, CE, D, CLR);
parameter [0:0] INIT = 1'b0;
initial Q <= INIT;
always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
endmodule
module FDPE_1 (output reg Q, input C, CE, D, PRE);
parameter [0:0] INIT = 1'b1;
initial Q <= INIT;
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
endmodule
module RAM64X1D ( module RAM64X1D (
output DPO, SPO, output DPO, SPO,
input D, WCLK, WE, input D, WCLK, WE,

View File

@ -7,6 +7,7 @@ function xtract_cell_decl()
{ {
for dir in $libdir/xeclib $libdir/retarget; do for dir in $libdir/xeclib $libdir/retarget; do
[ -f $dir/$1.v ] || continue [ -f $dir/$1.v ] || continue
[ -z "$2" ] || echo $2
egrep '^\s*((end)?module|parameter|input|inout|output|(end)?function|(end)?task)' $dir/$1.v | egrep '^\s*((end)?module|parameter|input|inout|output|(end)?function|(end)?task)' $dir/$1.v |
sed -re '/UNPLACED/ d; /^\s*function/,/endfunction/ d; /^\s*task/,/endtask/ d; sed -re '/UNPLACED/ d; /^\s*function/,/endfunction/ d; /^\s*task/,/endtask/ d;
s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/; s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/;
@ -37,10 +38,10 @@ function xtract_cell_decl()
xtract_cell_decl BUFMR xtract_cell_decl BUFMR
xtract_cell_decl BUFMRCE xtract_cell_decl BUFMRCE
xtract_cell_decl BUFR xtract_cell_decl BUFR
xtract_cell_decl CAPTUREE2 xtract_cell_decl CAPTUREE2 "(* keep *)"
# xtract_cell_decl CARRY4 # xtract_cell_decl CARRY4
xtract_cell_decl CFGLUT5 xtract_cell_decl CFGLUT5
xtract_cell_decl DCIRESET xtract_cell_decl DCIRESET "(* keep *)"
xtract_cell_decl DNA_PORT xtract_cell_decl DNA_PORT
xtract_cell_decl DSP48E1 xtract_cell_decl DSP48E1
xtract_cell_decl EFUSE_USR xtract_cell_decl EFUSE_USR
@ -67,10 +68,10 @@ function xtract_cell_decl()
xtract_cell_decl IBUFDS_GTE2 xtract_cell_decl IBUFDS_GTE2
xtract_cell_decl IBUFDS_IBUFDISABLE xtract_cell_decl IBUFDS_IBUFDISABLE
xtract_cell_decl IBUFDS_INTERMDISABLE xtract_cell_decl IBUFDS_INTERMDISABLE
xtract_cell_decl ICAPE2 xtract_cell_decl ICAPE2 "(* keep *)"
xtract_cell_decl IDDR xtract_cell_decl IDDR
xtract_cell_decl IDDR_2CLK xtract_cell_decl IDDR_2CLK
xtract_cell_decl IDELAYCTRL xtract_cell_decl IDELAYCTRL "(* keep *)"
xtract_cell_decl IDELAYE2 xtract_cell_decl IDELAYE2
xtract_cell_decl IN_FIFO xtract_cell_decl IN_FIFO
xtract_cell_decl IOBUF xtract_cell_decl IOBUF
@ -112,10 +113,10 @@ function xtract_cell_decl()
xtract_cell_decl PHY_CONTROL xtract_cell_decl PHY_CONTROL
xtract_cell_decl PLLE2_ADV xtract_cell_decl PLLE2_ADV
xtract_cell_decl PLLE2_BASE xtract_cell_decl PLLE2_BASE
xtract_cell_decl PS7 xtract_cell_decl PS7 "(* keep *)"
xtract_cell_decl PULLDOWN xtract_cell_decl PULLDOWN
xtract_cell_decl PULLUP xtract_cell_decl PULLUP
# xtract_cell_decl RAM128X1D xtract_cell_decl RAM128X1D
xtract_cell_decl RAM128X1S xtract_cell_decl RAM128X1S
xtract_cell_decl RAM256X1S xtract_cell_decl RAM256X1S
xtract_cell_decl RAM32M xtract_cell_decl RAM32M
@ -124,7 +125,7 @@ function xtract_cell_decl()
xtract_cell_decl RAM32X1S_1 xtract_cell_decl RAM32X1S_1
xtract_cell_decl RAM32X2S xtract_cell_decl RAM32X2S
xtract_cell_decl RAM64M xtract_cell_decl RAM64M
# xtract_cell_decl RAM64X1D xtract_cell_decl RAM64X1D
xtract_cell_decl RAM64X1S xtract_cell_decl RAM64X1S
xtract_cell_decl RAM64X1S_1 xtract_cell_decl RAM64X1S_1
xtract_cell_decl RAM64X2S xtract_cell_decl RAM64X2S
@ -136,7 +137,7 @@ function xtract_cell_decl()
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 xtract_cell_decl STARTUPE2 "(* keep *)"
xtract_cell_decl USR_ACCESSE2 xtract_cell_decl USR_ACCESSE2
xtract_cell_decl XADC xtract_cell_decl XADC
} > cells_xtra.new } > cells_xtra.new

View File

@ -114,6 +114,7 @@ module BUFR (...);
parameter SIM_DEVICE = "7SERIES"; parameter SIM_DEVICE = "7SERIES";
endmodule endmodule
(* keep *)
module CAPTUREE2 (...); module CAPTUREE2 (...);
parameter ONESHOT = "TRUE"; parameter ONESHOT = "TRUE";
input CAP; input CAP;
@ -130,6 +131,7 @@ module CFGLUT5 (...);
input CDI, CE, CLK; input CDI, CE, CLK;
endmodule endmodule
(* keep *)
module DCIRESET (...); module DCIRESET (...);
output LOCKED; output LOCKED;
input RST; input RST;
@ -2102,6 +2104,7 @@ module IBUFDS_INTERMDISABLE (...);
input INTERMDISABLE; input INTERMDISABLE;
endmodule endmodule
(* keep *)
module ICAPE2 (...); module ICAPE2 (...);
parameter [31:0] DEVICE_ID = 32'h04244093; parameter [31:0] DEVICE_ID = 32'h04244093;
parameter ICAP_WIDTH = "X32"; parameter ICAP_WIDTH = "X32";
@ -2149,6 +2152,7 @@ module IDDR_2CLK (...);
input S; input S;
endmodule endmodule
(* keep *)
module IDELAYCTRL (...); module IDELAYCTRL (...);
parameter SIM_DEVICE = "7SERIES"; parameter SIM_DEVICE = "7SERIES";
output RDY; output RDY;
@ -3057,6 +3061,7 @@ module PLLE2_BASE (...);
input RST; input RST;
endmodule endmodule
(* keep *)
module PS7 (...); module PS7 (...);
output DMA0DAVALID; output DMA0DAVALID;
output DMA0DRREADY; output DMA0DRREADY;
@ -3688,6 +3693,17 @@ module PULLUP (...);
output O; output O;
endmodule endmodule
module RAM128X1D (...);
parameter [127:0] INIT = 128'h00000000000000000000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
output DPO, SPO;
input [6:0] A;
input [6:0] DPRA;
input D;
input WCLK;
input WE;
endmodule
module RAM128X1S (...); module RAM128X1S (...);
parameter [127:0] INIT = 128'h00000000000000000000000000000000; parameter [127:0] INIT = 128'h00000000000000000000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0; parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@ -3778,6 +3794,13 @@ module RAM64M (...);
input WE; input WE;
endmodule endmodule
module RAM64X1D (...);
parameter [63:0] INIT = 64'h0000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
output DPO, SPO;
input A0, A1, A2, A3, A4, A5, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5, WCLK, WE;
endmodule
module RAM64X1S (...); module RAM64X1S (...);
parameter [63:0] INIT = 64'h0000000000000000; parameter [63:0] INIT = 64'h0000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0; parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@ -3840,6 +3863,7 @@ module SRLC32E (...);
input CE, CLK, D; input CE, CLK, D;
endmodule endmodule
(* keep *)
module STARTUPE2 (...); module STARTUPE2 (...);
parameter PROG_USR = "FALSE"; parameter PROG_USR = "FALSE";
parameter real SIM_CCLK_FREQ = 0.0; parameter real SIM_CCLK_FREQ = 0.0;

42
techlibs/xilinx/ff_map.v Normal file
View File

@ -0,0 +1,42 @@
/*
* 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.
*
*/
// ============================================================================
// FF mapping
`ifndef _NO_FFS
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 \$_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 \$_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_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_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_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
`endif

View File

@ -1,65 +0,0 @@
module LUT1(output O, input I0);
parameter [1:0] INIT = 0;
\$lut #(
.WIDTH(1),
.LUT(INIT)
) _TECHMAP_REPLACE_ (
.A(I0),
.Y(O)
);
endmodule
module LUT2(output O, input I0, I1);
parameter [3:0] INIT = 0;
\$lut #(
.WIDTH(2),
.LUT(INIT)
) _TECHMAP_REPLACE_ (
.A({I1, I0}),
.Y(O)
);
endmodule
module LUT3(output O, input I0, I1, I2);
parameter [7:0] INIT = 0;
\$lut #(
.WIDTH(3),
.LUT(INIT)
) _TECHMAP_REPLACE_ (
.A({I2, I1, I0}),
.Y(O)
);
endmodule
module LUT4(output O, input I0, I1, I2, I3);
parameter [15:0] INIT = 0;
\$lut #(
.WIDTH(4),
.LUT(INIT)
) _TECHMAP_REPLACE_ (
.A({I3, I2, I1, I0}),
.Y(O)
);
endmodule
module LUT5(output O, input I0, I1, I2, I3, I4);
parameter [31:0] INIT = 0;
\$lut #(
.WIDTH(5),
.LUT(INIT)
) _TECHMAP_REPLACE_ (
.A({I4, I3, I2, I1, I0}),
.Y(O)
);
endmodule
module LUT6(output O, input I0, I1, I2, I3, I4, I5);
parameter [63:0] INIT = 0;
\$lut #(
.WIDTH(6),
.LUT(INIT)
) _TECHMAP_REPLACE_ (
.A({I5, I4, I3, I2, I1, I0}),
.Y(O)
);
endmodule

94
techlibs/xilinx/lut_map.v Normal file
View File

@ -0,0 +1,94 @@
/*
* 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.
*
*/
// ============================================================================
// LUT mapping
`ifndef _NO_LUTS
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
input [WIDTH-1:0] A;
output Y;
generate
if (WIDTH == 1) begin
LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]));
end else
if (WIDTH == 2) begin
LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]), .I1(A[1]));
end else
if (WIDTH == 3) begin
LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]), .I1(A[1]), .I2(A[2]));
end else
if (WIDTH == 4) begin
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]));
end else
if (WIDTH == 5) begin
LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]));
end else
if (WIDTH == 6) begin
LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
end else
if (WIDTH == 7) begin
wire T0, T1;
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6]));
end else
if (WIDTH == 8) begin
wire T0, T1, T2, T3, T4, T5;
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3),
.I0(A[0]), .I1(A[1]), .I2(A[2]),
.I3(A[3]), .I4(A[4]), .I5(A[5]));
MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6]));
MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6]));
MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7]));
end else begin
wire _TECHMAP_FAIL_ = 1;
end
endgenerate
endmodule
`endif

Some files were not shown because too many files have changed in this diff Show More