mirror of https://github.com/YosysHQ/yosys.git
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
fe651922cb
|
@ -0,0 +1,13 @@
|
|||
.editorconfig
|
||||
.gitignore
|
||||
.gitmodules
|
||||
.github
|
||||
.git
|
||||
Dockerfile
|
||||
README.md
|
||||
manual
|
||||
CodingReadme
|
||||
CodeOfConduct
|
||||
.travis
|
||||
.travis.yml
|
||||
|
|
@ -16,6 +16,7 @@ Yosys 0.8 .. Yosys 0.8-dev
|
|||
- Added "gate2lut.v" techmap rule
|
||||
- Added "rename -src"
|
||||
- Added "equiv_opt" pass
|
||||
- Added "read_aiger" frontend
|
||||
- "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx"
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
FROM ubuntu:18.04 as builder
|
||||
LABEL author="Abdelrahman Hosny <abdelrahman.hosny@hotmail.com>"
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get install -y build-essential \
|
||||
clang \
|
||||
bison \
|
||||
flex \
|
||||
libreadline-dev \
|
||||
gawk \
|
||||
tcl-dev \
|
||||
libffi-dev \
|
||||
git \
|
||||
pkg-config \
|
||||
python3 && \
|
||||
rm -rf /var/lib/apt/lists
|
||||
COPY . /
|
||||
RUN make && \
|
||||
make install
|
||||
|
||||
FROM ubuntu:18.04
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get install -y libreadline-dev tcl-dev
|
||||
|
||||
COPY --from=builder /yosys /build/yosys
|
||||
COPY --from=builder /yosys-abc /build/yosys-abc
|
||||
COPY --from=builder /yosys-config /build/yosys-config
|
||||
COPY --from=builder /yosys-filterlib /build/yosys-filterlib
|
||||
COPY --from=builder /yosys-smtbmc /build/yosys-smtbmc
|
||||
|
||||
ENV PATH /build:$PATH
|
||||
RUN useradd -m yosys
|
||||
USER yosys
|
||||
ENTRYPOINT ["yosys"]
|
27
Makefile
27
Makefile
|
@ -22,14 +22,6 @@ ENABLE_PROTOBUF := 0
|
|||
|
||||
# python wrappers
|
||||
ENABLE_PYOSYS := 0
|
||||
ifeq ($(ENABLE_PYOSYS),1)
|
||||
PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
|
||||
PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
|
||||
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
|
||||
PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
|
||||
PYTHON_PREFIX := $(shell $(PYTHON_EXECUTABLE)-config --prefix)
|
||||
PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages
|
||||
endif
|
||||
|
||||
# other configuration flags
|
||||
ENABLE_GCOV := 0
|
||||
|
@ -54,6 +46,10 @@ OS := $(shell uname -s)
|
|||
PREFIX ?= /usr/local
|
||||
INSTALL_SUDO :=
|
||||
|
||||
ifneq ($(wildcard Makefile.conf),)
|
||||
include Makefile.conf
|
||||
endif
|
||||
|
||||
BINDIR := $(PREFIX)/bin
|
||||
LIBDIR := $(PREFIX)/lib
|
||||
DATDIR := $(PREFIX)/share/yosys
|
||||
|
@ -145,6 +141,21 @@ $(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$
|
|||
include Makefile.conf
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_PYOSYS),1)
|
||||
PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
|
||||
PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
|
||||
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
|
||||
PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
|
||||
PYTHON_PREFIX := $(shell $(PYTHON_EXECUTABLE)-config --prefix)
|
||||
PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages
|
||||
|
||||
# Reload Makefile.conf to override python specific variables if defined
|
||||
ifneq ($(wildcard Makefile.conf),)
|
||||
include Makefile.conf
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG),clang)
|
||||
CXX = clang
|
||||
LD = clang++
|
||||
|
|
|
@ -257,7 +257,7 @@ for them:
|
|||
- Non-synthesizable language features as defined in
|
||||
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
|
||||
|
||||
- The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types
|
||||
- The ``tri``, ``triand`` and ``trior`` net types
|
||||
|
||||
- The ``config`` and ``disable`` keywords and library map files
|
||||
|
||||
|
@ -413,7 +413,7 @@ Verilog Attributes and non-standard features
|
|||
$ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v'
|
||||
|
||||
- Sized constants (the syntax ``<size>'s?[bodh]<value>``) support constant
|
||||
expressions as <size>. If the expression is not a simple identifier, it
|
||||
expressions as ``<size>``. If the expression is not a simple identifier, it
|
||||
must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010``
|
||||
|
||||
- The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in
|
||||
|
|
|
@ -34,354 +34,389 @@
|
|||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name)
|
||||
: design(design), f(f), clk_name(clk_name)
|
||||
: design(design), f(f), clk_name(clk_name)
|
||||
{
|
||||
module = new RTLIL::Module;
|
||||
module->name = module_name;
|
||||
if (design->module(module->name))
|
||||
log_error("Duplicate definition of module %s!\n", log_id(module->name));
|
||||
module = new RTLIL::Module;
|
||||
module->name = module_name;
|
||||
if (design->module(module->name))
|
||||
log_error("Duplicate definition of module %s!\n", log_id(module->name));
|
||||
}
|
||||
|
||||
void AigerReader::parse_aiger()
|
||||
{
|
||||
std::string header;
|
||||
f >> header;
|
||||
if (header != "aag" && header != "aig")
|
||||
log_error("Unsupported AIGER file!\n");
|
||||
std::string header;
|
||||
f >> header;
|
||||
if (header != "aag" && header != "aig")
|
||||
log_error("Unsupported AIGER file!\n");
|
||||
|
||||
// Parse rest of header
|
||||
if (!(f >> M >> I >> L >> O >> A))
|
||||
log_error("Invalid AIGER header\n");
|
||||
// Parse rest of header
|
||||
if (!(f >> M >> I >> L >> O >> A))
|
||||
log_error("Invalid AIGER header\n");
|
||||
|
||||
// Optional values
|
||||
B = C = J = F = 0;
|
||||
if (f.peek() != ' ') goto end_of_header;
|
||||
if (!(f >> B)) log_error("Invalid AIGER header\n");
|
||||
if (f.peek() != ' ') goto end_of_header;
|
||||
if (!(f >> C)) log_error("Invalid AIGER header\n");
|
||||
if (f.peek() != ' ') goto end_of_header;
|
||||
if (!(f >> J)) log_error("Invalid AIGER header\n");
|
||||
if (f.peek() != ' ') goto end_of_header;
|
||||
if (!(f >> F)) log_error("Invalid AIGER header\n");
|
||||
// Optional values
|
||||
B = C = J = F = 0;
|
||||
if (f.peek() != ' ') goto end_of_header;
|
||||
if (!(f >> B)) log_error("Invalid AIGER header\n");
|
||||
if (f.peek() != ' ') goto end_of_header;
|
||||
if (!(f >> C)) log_error("Invalid AIGER header\n");
|
||||
if (f.peek() != ' ') goto end_of_header;
|
||||
if (!(f >> J)) log_error("Invalid AIGER header\n");
|
||||
if (f.peek() != ' ') goto end_of_header;
|
||||
if (!(f >> F)) log_error("Invalid AIGER header\n");
|
||||
end_of_header:
|
||||
|
||||
std::string line;
|
||||
std::getline(f, line); // Ignore up to start of next line, as standard
|
||||
// says anything that follows could be used for
|
||||
// optional sections
|
||||
std::string line;
|
||||
std::getline(f, line); // Ignore up to start of next line, as standard
|
||||
// says anything that follows could be used for
|
||||
// optional sections
|
||||
|
||||
log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);
|
||||
log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);
|
||||
|
||||
line_count = 1;
|
||||
line_count = 1;
|
||||
|
||||
if (header == "aag")
|
||||
parse_aiger_ascii();
|
||||
else if (header == "aig")
|
||||
parse_aiger_binary();
|
||||
else
|
||||
log_abort();
|
||||
if (header == "aag")
|
||||
parse_aiger_ascii();
|
||||
else if (header == "aig")
|
||||
parse_aiger_binary();
|
||||
else
|
||||
log_abort();
|
||||
|
||||
// Parse footer (symbol table, comments, etc.)
|
||||
unsigned l1;
|
||||
std::string s;
|
||||
for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) {
|
||||
if (c == 'i' || c == 'l' || c == 'o') {
|
||||
f.ignore(1);
|
||||
if (!(f >> l1 >> s))
|
||||
log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);
|
||||
RTLIL::Wire* n0 = module->wire("\\n0");
|
||||
if (n0)
|
||||
module->connect(n0, RTLIL::S0);
|
||||
|
||||
if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size()))
|
||||
log_error("Line %u has invalid symbol position!\n", line_count);
|
||||
for (unsigned i = 0; i < outputs.size(); ++i) {
|
||||
RTLIL::Wire *wire = outputs[i];
|
||||
if (wire->port_input) {
|
||||
RTLIL::Wire *o_wire = module->addWire(wire->name.str() + "_o");
|
||||
o_wire->port_output = true;
|
||||
wire->port_output = false;
|
||||
module->connect(o_wire, wire);
|
||||
outputs[i] = o_wire;
|
||||
}
|
||||
}
|
||||
|
||||
RTLIL::Wire* wire;
|
||||
if (c == 'i') wire = inputs[l1];
|
||||
else if (c == 'l') wire = latches[l1];
|
||||
else if (c == 'o') wire = outputs[l1];
|
||||
else log_abort();
|
||||
// Parse footer (symbol table, comments, etc.)
|
||||
unsigned l1;
|
||||
std::string s;
|
||||
for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) {
|
||||
if (c == 'i' || c == 'l' || c == 'o' || c == 'b') {
|
||||
f.ignore(1);
|
||||
if (!(f >> l1 >> s))
|
||||
log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);
|
||||
|
||||
module->rename(wire, stringf("\\%s", s.c_str()));
|
||||
}
|
||||
else if (c == 'b' || c == 'j' || c == 'f') {
|
||||
// TODO
|
||||
}
|
||||
else if (c == 'c') {
|
||||
f.ignore(1);
|
||||
if (f.peek() == '\n')
|
||||
break;
|
||||
// Else constraint (TODO)
|
||||
}
|
||||
else
|
||||
log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
}
|
||||
if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size()))
|
||||
log_error("Line %u has invalid symbol position!\n", line_count);
|
||||
|
||||
module->fixup_ports();
|
||||
design->add(module);
|
||||
RTLIL::Wire* wire;
|
||||
if (c == 'i') wire = inputs[l1];
|
||||
else if (c == 'l') wire = latches[l1];
|
||||
else if (c == 'o') wire = outputs[l1];
|
||||
else if (c == 'b') wire = bad_properties[l1];
|
||||
else log_abort();
|
||||
|
||||
module->rename(wire, stringf("\\%s", s.c_str()));
|
||||
}
|
||||
else if (c == 'j' || c == 'f') {
|
||||
// TODO
|
||||
}
|
||||
else if (c == 'c') {
|
||||
f.ignore(1);
|
||||
if (f.peek() == '\n')
|
||||
break;
|
||||
// Else constraint (TODO)
|
||||
}
|
||||
else
|
||||
log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
}
|
||||
|
||||
module->fixup_ports();
|
||||
design->add(module);
|
||||
}
|
||||
|
||||
static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal)
|
||||
{
|
||||
const unsigned variable = literal >> 1;
|
||||
const bool invert = literal & 1;
|
||||
RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix?
|
||||
RTLIL::Wire *wire = module->wire(wire_name);
|
||||
if (wire) return wire;
|
||||
log_debug("Creating %s\n", wire_name.c_str());
|
||||
wire = module->addWire(wire_name);
|
||||
if (!invert) return wire;
|
||||
RTLIL::IdString wire_inv_name(stringf("\\n%d", variable));
|
||||
RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
|
||||
if (wire_inv) {
|
||||
if (module->cell(wire_inv_name)) return wire;
|
||||
}
|
||||
else {
|
||||
log_debug("Creating %s\n", wire_inv_name.c_str());
|
||||
wire_inv = module->addWire(wire_inv_name);
|
||||
}
|
||||
const unsigned variable = literal >> 1;
|
||||
const bool invert = literal & 1;
|
||||
RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix?
|
||||
RTLIL::Wire *wire = module->wire(wire_name);
|
||||
if (wire) return wire;
|
||||
log_debug("Creating %s\n", wire_name.c_str());
|
||||
wire = module->addWire(wire_name);
|
||||
if (!invert) return wire;
|
||||
RTLIL::IdString wire_inv_name(stringf("\\n%d", variable));
|
||||
RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
|
||||
if (wire_inv) {
|
||||
if (module->cell(wire_inv_name)) return wire;
|
||||
}
|
||||
else {
|
||||
log_debug("Creating %s\n", wire_inv_name.c_str());
|
||||
wire_inv = module->addWire(wire_inv_name);
|
||||
}
|
||||
|
||||
log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
|
||||
module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix?
|
||||
log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
|
||||
module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix?
|
||||
|
||||
return wire;
|
||||
return wire;
|
||||
}
|
||||
|
||||
void AigerReader::parse_aiger_ascii()
|
||||
{
|
||||
std::string line;
|
||||
std::stringstream ss;
|
||||
std::string line;
|
||||
std::stringstream ss;
|
||||
|
||||
unsigned l1, l2, l3;
|
||||
unsigned l1, l2, l3;
|
||||
|
||||
// Parse inputs
|
||||
for (unsigned i = 0; i < I; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as an input!\n", line_count);
|
||||
log_debug("%d is an input\n", l1);
|
||||
log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted?
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_input = true;
|
||||
inputs.push_back(wire);
|
||||
}
|
||||
// Parse inputs
|
||||
for (unsigned i = 1; i <= I; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as an input!\n", line_count);
|
||||
log_debug("%d is an input\n", l1);
|
||||
log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted?
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_input = true;
|
||||
inputs.push_back(wire);
|
||||
}
|
||||
|
||||
// Parse latches
|
||||
RTLIL::Wire *clk_wire = nullptr;
|
||||
if (L > 0) {
|
||||
clk_wire = module->wire(clk_name);
|
||||
log_assert(!clk_wire);
|
||||
log_debug("Creating %s\n", clk_name.c_str());
|
||||
clk_wire = module->addWire(clk_name);
|
||||
clk_wire->port_input = true;
|
||||
}
|
||||
for (unsigned i = 0; i < L; ++i, ++line_count) {
|
||||
if (!(f >> l1 >> l2))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
log_debug("%d %d is a latch\n", l1, l2);
|
||||
log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted?
|
||||
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
|
||||
// Parse latches
|
||||
RTLIL::Wire *clk_wire = nullptr;
|
||||
if (L > 0) {
|
||||
clk_wire = module->wire(clk_name);
|
||||
log_assert(!clk_wire);
|
||||
log_debug("Creating %s\n", clk_name.c_str());
|
||||
clk_wire = module->addWire(clk_name);
|
||||
clk_wire->port_input = true;
|
||||
}
|
||||
for (unsigned i = 0; i < L; ++i, ++line_count) {
|
||||
if (!(f >> l1 >> l2))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
log_debug("%d %d is a latch\n", l1, l2);
|
||||
log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted?
|
||||
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
|
||||
|
||||
module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire);
|
||||
module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire);
|
||||
|
||||
// Reset logic is optional in AIGER 1.9
|
||||
if (f.peek() == ' ') {
|
||||
if (!(f >> l3))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
// Reset logic is optional in AIGER 1.9
|
||||
if (f.peek() == ' ') {
|
||||
if (!(f >> l3))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
|
||||
if (l3 == 0 || l3 == 1)
|
||||
q_wire->attributes["\\init"] = RTLIL::Const(l3);
|
||||
else if (l3 == l1) {
|
||||
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
|
||||
}
|
||||
else
|
||||
log_error("Line %u has invalid reset literal for latch!\n", line_count);
|
||||
}
|
||||
else {
|
||||
// AIGER latches are assumed to be initialized to zero
|
||||
q_wire->attributes["\\init"] = RTLIL::Const(0);
|
||||
}
|
||||
latches.push_back(q_wire);
|
||||
}
|
||||
if (l3 == 0)
|
||||
q_wire->attributes["\\init"] = RTLIL::S0;
|
||||
else if (l3 == 1)
|
||||
q_wire->attributes["\\init"] = RTLIL::S1;
|
||||
else if (l3 == l1) {
|
||||
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
|
||||
}
|
||||
else
|
||||
log_error("Line %u has invalid reset literal for latch!\n", line_count);
|
||||
}
|
||||
else {
|
||||
// AIGER latches are assumed to be initialized to zero
|
||||
q_wire->attributes["\\init"] = RTLIL::S0;
|
||||
}
|
||||
latches.push_back(q_wire);
|
||||
}
|
||||
|
||||
// Parse outputs
|
||||
for (unsigned i = 0; i < O; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
||||
// Parse outputs
|
||||
for (unsigned i = 0; i < O; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
||||
|
||||
log_debug("%d is an output\n", l1);
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_output = true;
|
||||
outputs.push_back(wire);
|
||||
}
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
log_debug("%d is an output\n", l1);
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_output = true;
|
||||
outputs.push_back(wire);
|
||||
}
|
||||
|
||||
// TODO: Parse bad state properties
|
||||
for (unsigned i = 0; i < B; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
// Parse bad properties
|
||||
for (unsigned i = 0; i < B; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
|
||||
|
||||
// TODO: Parse invariant constraints
|
||||
for (unsigned i = 0; i < C; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
log_debug("%d is a bad state property\n", l1);
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_output = true;
|
||||
bad_properties.push_back(wire);
|
||||
}
|
||||
|
||||
// TODO: Parse justice properties
|
||||
for (unsigned i = 0; i < J; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
// TODO: Parse invariant constraints
|
||||
for (unsigned i = 0; i < C; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse fairness constraints
|
||||
for (unsigned i = 0; i < F; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
// TODO: Parse justice properties
|
||||
for (unsigned i = 0; i < J; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// Parse AND
|
||||
for (unsigned i = 0; i < A; ++i) {
|
||||
if (!(f >> l1 >> l2 >> l3))
|
||||
log_error("Line %u cannot be interpreted as an AND!\n", line_count);
|
||||
// TODO: Parse fairness constraints
|
||||
for (unsigned i = 0; i < F; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
log_debug("%d %d %d is an AND\n", l1, l2, l3);
|
||||
log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
|
||||
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
|
||||
module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire);
|
||||
}
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
// Parse AND
|
||||
for (unsigned i = 0; i < A; ++i) {
|
||||
if (!(f >> l1 >> l2 >> l3))
|
||||
log_error("Line %u cannot be interpreted as an AND!\n", line_count);
|
||||
|
||||
log_debug("%d %d %d is an AND\n", l1, l2, l3);
|
||||
log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
|
||||
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
|
||||
module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire);
|
||||
}
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
}
|
||||
|
||||
static unsigned parse_next_delta_literal(std::istream &f, unsigned ref)
|
||||
{
|
||||
unsigned x = 0, i = 0;
|
||||
unsigned char ch;
|
||||
while ((ch = f.get()) & 0x80)
|
||||
x |= (ch & 0x7f) << (7 * i++);
|
||||
return ref - (x | (ch << (7 * i)));
|
||||
unsigned x = 0, i = 0;
|
||||
unsigned char ch;
|
||||
while ((ch = f.get()) & 0x80)
|
||||
x |= (ch & 0x7f) << (7 * i++);
|
||||
return ref - (x | (ch << (7 * i)));
|
||||
}
|
||||
|
||||
void AigerReader::parse_aiger_binary()
|
||||
{
|
||||
unsigned l1, l2, l3;
|
||||
std::string line;
|
||||
unsigned l1, l2, l3;
|
||||
std::string line;
|
||||
|
||||
// Parse inputs
|
||||
for (unsigned i = 1; i <= I; ++i) {
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
|
||||
wire->port_input = true;
|
||||
inputs.push_back(wire);
|
||||
}
|
||||
// Parse inputs
|
||||
for (unsigned i = 1; i <= I; ++i) {
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
|
||||
wire->port_input = true;
|
||||
inputs.push_back(wire);
|
||||
}
|
||||
|
||||
// Parse latches
|
||||
RTLIL::Wire *clk_wire = nullptr;
|
||||
if (L > 0) {
|
||||
clk_wire = module->wire(clk_name);
|
||||
log_assert(!clk_wire);
|
||||
log_debug("Creating %s\n", clk_name.c_str());
|
||||
clk_wire = module->addWire(clk_name);
|
||||
clk_wire->port_input = true;
|
||||
}
|
||||
l1 = (I+1) * 2;
|
||||
for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) {
|
||||
if (!(f >> l2))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
log_debug("%d %d is a latch\n", l1, l2);
|
||||
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
|
||||
// Parse latches
|
||||
RTLIL::Wire *clk_wire = nullptr;
|
||||
if (L > 0) {
|
||||
clk_wire = module->wire(clk_name);
|
||||
log_assert(!clk_wire);
|
||||
log_debug("Creating %s\n", clk_name.c_str());
|
||||
clk_wire = module->addWire(clk_name);
|
||||
clk_wire->port_input = true;
|
||||
}
|
||||
l1 = (I+1) * 2;
|
||||
for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) {
|
||||
if (!(f >> l2))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
log_debug("%d %d is a latch\n", l1, l2);
|
||||
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
|
||||
|
||||
module->addDff(NEW_ID, clk_wire, d_wire, q_wire);
|
||||
module->addDff(NEW_ID, clk_wire, d_wire, q_wire);
|
||||
|
||||
// Reset logic is optional in AIGER 1.9
|
||||
if (f.peek() == ' ') {
|
||||
if (!(f >> l3))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
// Reset logic is optional in AIGER 1.9
|
||||
if (f.peek() == ' ') {
|
||||
if (!(f >> l3))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
|
||||
if (l3 == 0 || l3 == 1)
|
||||
q_wire->attributes["\\init"] = RTLIL::Const(l3);
|
||||
else if (l3 == l1) {
|
||||
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
|
||||
}
|
||||
else
|
||||
log_error("Line %u has invalid reset literal for latch!\n", line_count);
|
||||
}
|
||||
else {
|
||||
// AIGER latches are assumed to be initialized to zero
|
||||
q_wire->attributes["\\init"] = RTLIL::Const(0);
|
||||
}
|
||||
latches.push_back(q_wire);
|
||||
}
|
||||
if (l3 == 0)
|
||||
q_wire->attributes["\\init"] = RTLIL::S0;
|
||||
else if (l3 == 1)
|
||||
q_wire->attributes["\\init"] = RTLIL::S1;
|
||||
else if (l3 == l1) {
|
||||
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
|
||||
}
|
||||
else
|
||||
log_error("Line %u has invalid reset literal for latch!\n", line_count);
|
||||
}
|
||||
else {
|
||||
// AIGER latches are assumed to be initialized to zero
|
||||
q_wire->attributes["\\init"] = RTLIL::S0;
|
||||
}
|
||||
latches.push_back(q_wire);
|
||||
}
|
||||
|
||||
// Parse outputs
|
||||
for (unsigned i = 0; i < O; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
||||
// Parse outputs
|
||||
for (unsigned i = 0; i < O; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
||||
|
||||
log_debug("%d is an output\n", l1);
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_output = true;
|
||||
outputs.push_back(wire);
|
||||
}
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
log_debug("%d is an output\n", l1);
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_output = true;
|
||||
outputs.push_back(wire);
|
||||
}
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse bad state properties
|
||||
for (unsigned i = 0; i < B; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
// Parse bad properties
|
||||
for (unsigned i = 0; i < B; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
|
||||
|
||||
// TODO: Parse invariant constraints
|
||||
for (unsigned i = 0; i < C; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
log_debug("%d is a bad state property\n", l1);
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_output = true;
|
||||
bad_properties.push_back(wire);
|
||||
}
|
||||
if (B > 0)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse justice properties
|
||||
for (unsigned i = 0; i < J; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
// TODO: Parse invariant constraints
|
||||
for (unsigned i = 0; i < C; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse fairness constraints
|
||||
for (unsigned i = 0; i < F; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
// TODO: Parse justice properties
|
||||
for (unsigned i = 0; i < J; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// Parse AND
|
||||
l1 = (I+L+1) << 1;
|
||||
for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) {
|
||||
l2 = parse_next_delta_literal(f, l1);
|
||||
l3 = parse_next_delta_literal(f, l2);
|
||||
// TODO: Parse fairness constraints
|
||||
for (unsigned i = 0; i < F; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
log_debug("%d %d %d is an AND\n", l1, l2, l3);
|
||||
log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
|
||||
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
|
||||
// Parse AND
|
||||
l1 = (I+L+1) << 1;
|
||||
for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) {
|
||||
l2 = parse_next_delta_literal(f, l1);
|
||||
l3 = parse_next_delta_literal(f, l2);
|
||||
|
||||
RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_");
|
||||
and_cell->setPort("\\A", i1_wire);
|
||||
and_cell->setPort("\\B", i2_wire);
|
||||
and_cell->setPort("\\Y", o_wire);
|
||||
}
|
||||
log_debug("%d %d %d is an AND\n", l1, l2, l3);
|
||||
log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
|
||||
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
|
||||
|
||||
RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_");
|
||||
and_cell->setPort("\\A", i1_wire);
|
||||
and_cell->setPort("\\B", i2_wire);
|
||||
and_cell->setPort("\\Y", o_wire);
|
||||
}
|
||||
}
|
||||
|
||||
struct AigerFrontend : public Frontend {
|
||||
AigerFrontend() : Frontend("aiger", "read AIGER file") { }
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" read_aiger [options] [filename]\n");
|
||||
log("\n");
|
||||
log("Load module from an AIGER file into the current design.\n");
|
||||
log("\n");
|
||||
log(" -module_name <module_name>\n");
|
||||
log(" Name of module to be created (default: <filename>)"
|
||||
AigerFrontend() : Frontend("aiger", "read AIGER file") { }
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" read_aiger [options] [filename]\n");
|
||||
log("\n");
|
||||
log("Load module from an AIGER file into the current design.\n");
|
||||
log("\n");
|
||||
log(" -module_name <module_name>\n");
|
||||
log(" Name of module to be created (default: "
|
||||
#ifdef _WIN32
|
||||
"top" // FIXME
|
||||
"top" // FIXME
|
||||
#else
|
||||
"<filename>"
|
||||
"<filename>"
|
||||
#endif
|
||||
")\n");
|
||||
log("\n");
|
||||
log(" -clk_name <wire_name>\n");
|
||||
log(" AIGER latches to be transformed into posedge DFFs clocked by wire of");
|
||||
log(" this name (default: clk)\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
log_header(design, "Executing AIGER frontend.\n");
|
||||
")\n");
|
||||
log("\n");
|
||||
log(" -clk_name <wire_name>\n");
|
||||
log(" AIGER latches to be transformed into posedge DFFs clocked by wire of");
|
||||
log(" this name (default: clk)\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
log_header(design, "Executing AIGER frontend.\n");
|
||||
|
||||
RTLIL::IdString clk_name = "\\clk";
|
||||
RTLIL::IdString module_name;
|
||||
RTLIL::IdString clk_name = "\\clk";
|
||||
RTLIL::IdString module_name;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
|
@ -398,19 +433,19 @@ struct AigerFrontend : public Frontend {
|
|||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
if (module_name.empty()) {
|
||||
if (module_name.empty()) {
|
||||
#ifdef _WIN32
|
||||
module_name = "top"; // FIXME: basename equivalent on Win32?
|
||||
module_name = "top"; // FIXME: basename equivalent on Win32?
|
||||
#else
|
||||
char* bn = strdup(filename.c_str());
|
||||
module_name = RTLIL::escape_id(bn);
|
||||
free(bn);
|
||||
char* bn = strdup(filename.c_str());
|
||||
module_name = RTLIL::escape_id(bn);
|
||||
free(bn);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
AigerReader reader(design, *f, module_name, clk_name);
|
||||
AigerReader reader(design, *f, module_name, clk_name);
|
||||
reader.parse_aiger();
|
||||
}
|
||||
}
|
||||
} AigerFrontend;
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
@ -39,6 +39,7 @@ struct AigerReader
|
|||
std::vector<RTLIL::Wire*> inputs;
|
||||
std::vector<RTLIL::Wire*> latches;
|
||||
std::vector<RTLIL::Wire*> outputs;
|
||||
std::vector<RTLIL::Wire*> bad_properties;
|
||||
|
||||
AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name);
|
||||
void parse_aiger();
|
||||
|
|
|
@ -154,6 +154,7 @@ std::string AST::type2str(AstNodeType type)
|
|||
X(AST_GENIF)
|
||||
X(AST_GENCASE)
|
||||
X(AST_GENBLOCK)
|
||||
X(AST_TECALL)
|
||||
X(AST_POSEDGE)
|
||||
X(AST_NEGEDGE)
|
||||
X(AST_EDGE)
|
||||
|
@ -194,6 +195,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
|
|||
is_logic = false;
|
||||
is_signed = false;
|
||||
is_string = false;
|
||||
is_wand = false;
|
||||
is_wor = false;
|
||||
is_unsized = false;
|
||||
was_checked = false;
|
||||
range_valid = false;
|
||||
|
|
|
@ -137,7 +137,8 @@ namespace AST
|
|||
AST_GENIF,
|
||||
AST_GENCASE,
|
||||
AST_GENBLOCK,
|
||||
|
||||
AST_TECALL,
|
||||
|
||||
AST_POSEDGE,
|
||||
AST_NEGEDGE,
|
||||
AST_EDGE,
|
||||
|
@ -173,7 +174,7 @@ namespace AST
|
|||
// node content - most of it is unused in most node types
|
||||
std::string str;
|
||||
std::vector<RTLIL::State> bits;
|
||||
bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped, was_checked, is_unsized;
|
||||
bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized;
|
||||
int port_id, range_left, range_right;
|
||||
uint32_t integer;
|
||||
double realvalue;
|
||||
|
|
|
@ -920,6 +920,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
wire->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
|
||||
if (is_wand) wire->set_bool_attribute("\\wand");
|
||||
if (is_wor) wire->set_bool_attribute("\\wor");
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1572,6 +1575,37 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
delete always;
|
||||
} break;
|
||||
|
||||
case AST_TECALL: {
|
||||
int sz = children.size();
|
||||
if (str == "$info") {
|
||||
if (sz > 0)
|
||||
log_file_info(filename, linenum, "%s.\n", children[0]->str.c_str());
|
||||
else
|
||||
log_file_info(filename, linenum, "\n");
|
||||
} else if (str == "$warning") {
|
||||
if (sz > 0)
|
||||
log_file_warning(filename, linenum, "%s.\n", children[0]->str.c_str());
|
||||
else
|
||||
log_file_warning(filename, linenum, "\n");
|
||||
} else if (str == "$error") {
|
||||
if (sz > 0)
|
||||
log_file_error(filename, linenum, "%s.\n", children[0]->str.c_str());
|
||||
else
|
||||
log_file_error(filename, linenum, "\n");
|
||||
} else if (str == "$fatal") {
|
||||
// TODO: 1st parameter, if exists, is 0,1 or 2, and passed to $finish()
|
||||
// if no parameter is given, default value is 1
|
||||
// dollar_finish(sz ? children[0] : 1);
|
||||
// perhaps create & use log_file_fatal()
|
||||
if (sz > 0)
|
||||
log_file_error(filename, linenum, "FATAL: %s.\n", children[0]->str.c_str());
|
||||
else
|
||||
log_file_error(filename, linenum, "FATAL.\n");
|
||||
} else {
|
||||
log_file_error(filename, linenum, "Unknown elabortoon system task '%s'.\n", str.c_str());
|
||||
}
|
||||
} break;
|
||||
|
||||
case AST_FCALL: {
|
||||
if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq")
|
||||
{
|
||||
|
|
|
@ -48,6 +48,14 @@ USING_YOSYS_NAMESPACE
|
|||
#include "VhdlUnits.h"
|
||||
#include "VeriLibrary.h"
|
||||
|
||||
#ifndef SYMBIOTIC_VERIFIC_API_VERSION
|
||||
# error "Only Symbiotic EDA flavored Verific is supported. Please contact office@symbioticeda.com for commercial support for Yosys+Verific."
|
||||
#endif
|
||||
|
||||
#if SYMBIOTIC_VERIFIC_API_VERSION < 1
|
||||
# error "Please update your version of Symbiotic EDA flavored Verific."
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
@ -2016,6 +2024,9 @@ struct VerificPass : public Pass {
|
|||
// WARNING: instantiating unknown module 'XYZ' (VERI-1063)
|
||||
Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
|
||||
|
||||
// https://github.com/YosysHQ/yosys/issues/1055
|
||||
RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ;
|
||||
|
||||
#ifndef DB_PRESERVE_INITIAL_VALUE
|
||||
# warning Verific was built without DB_PRESERVE_INITIAL_VALUE.
|
||||
#endif
|
||||
|
|
|
@ -218,6 +218,8 @@ YOSYS_NAMESPACE_END
|
|||
"output" { return TOK_OUTPUT; }
|
||||
"inout" { return TOK_INOUT; }
|
||||
"wire" { return TOK_WIRE; }
|
||||
"wor" { return TOK_WOR; }
|
||||
"wand" { return TOK_WAND; }
|
||||
"reg" { return TOK_REG; }
|
||||
"integer" { return TOK_INTEGER; }
|
||||
"signed" { return TOK_SIGNED; }
|
||||
|
@ -309,6 +311,11 @@ supply1 { return TOK_SUPPLY1; }
|
|||
return TOK_ID;
|
||||
}
|
||||
|
||||
"$"(info|warning|error|fatal) {
|
||||
frontend_verilog_yylval.string = new std::string(yytext);
|
||||
return TOK_ELAB_TASK;
|
||||
}
|
||||
|
||||
"$signed" { return TOK_TO_SIGNED; }
|
||||
"$unsigned" { return TOK_TO_UNSIGNED; }
|
||||
|
||||
|
|
|
@ -133,13 +133,13 @@ struct specify_rise_fall {
|
|||
}
|
||||
|
||||
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
|
||||
%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER
|
||||
%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_ELAB_TASK
|
||||
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
|
||||
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
||||
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
|
||||
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
|
||||
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
|
||||
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC
|
||||
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
|
||||
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
|
||||
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
|
||||
|
@ -485,6 +485,12 @@ wire_type_token_io:
|
|||
wire_type_token:
|
||||
TOK_WIRE {
|
||||
} |
|
||||
TOK_WOR {
|
||||
astbuf3->is_wor = true;
|
||||
} |
|
||||
TOK_WAND {
|
||||
astbuf3->is_wand = true;
|
||||
} |
|
||||
TOK_REG {
|
||||
astbuf3->is_reg = true;
|
||||
} |
|
||||
|
@ -1526,27 +1532,40 @@ cell_port_list_rules:
|
|||
cell_port | cell_port_list_rules ',' cell_port;
|
||||
|
||||
cell_port:
|
||||
/* empty */ {
|
||||
attr {
|
||||
AstNode *node = new AstNode(AST_ARGUMENT);
|
||||
astbuf2->children.push_back(node);
|
||||
free_attr($1);
|
||||
} |
|
||||
expr {
|
||||
attr expr {
|
||||
AstNode *node = new AstNode(AST_ARGUMENT);
|
||||
astbuf2->children.push_back(node);
|
||||
node->children.push_back($1);
|
||||
node->children.push_back($2);
|
||||
free_attr($1);
|
||||
} |
|
||||
'.' TOK_ID '(' expr ')' {
|
||||
attr '.' TOK_ID '(' expr ')' {
|
||||
AstNode *node = new AstNode(AST_ARGUMENT);
|
||||
node->str = *$2;
|
||||
node->str = *$3;
|
||||
astbuf2->children.push_back(node);
|
||||
node->children.push_back($4);
|
||||
delete $2;
|
||||
node->children.push_back($5);
|
||||
delete $3;
|
||||
free_attr($1);
|
||||
} |
|
||||
'.' TOK_ID '(' ')' {
|
||||
attr '.' TOK_ID '(' ')' {
|
||||
AstNode *node = new AstNode(AST_ARGUMENT);
|
||||
node->str = *$2;
|
||||
node->str = *$3;
|
||||
astbuf2->children.push_back(node);
|
||||
delete $2;
|
||||
delete $3;
|
||||
free_attr($1);
|
||||
} |
|
||||
attr '.' TOK_ID {
|
||||
AstNode *node = new AstNode(AST_ARGUMENT);
|
||||
node->str = *$3;
|
||||
astbuf2->children.push_back(node);
|
||||
node->children.push_back(new AstNode(AST_IDENTIFIER));
|
||||
node->children.back()->str = *$3;
|
||||
delete $3;
|
||||
free_attr($1);
|
||||
};
|
||||
|
||||
always_stmt:
|
||||
|
@ -2157,6 +2176,15 @@ gen_stmt:
|
|||
if ($6 != NULL)
|
||||
delete $6;
|
||||
ast_stack.pop_back();
|
||||
} |
|
||||
TOK_ELAB_TASK {
|
||||
AstNode *node = new AstNode(AST_TECALL);
|
||||
node->str = *$1;
|
||||
delete $1;
|
||||
ast_stack.back()->children.push_back(node);
|
||||
ast_stack.push_back(node);
|
||||
} opt_arg_list ';'{
|
||||
ast_stack.pop_back();
|
||||
};
|
||||
|
||||
gen_stmt_block:
|
||||
|
|
|
@ -277,11 +277,22 @@ void log_file_warning(const std::string &filename, int lineno,
|
|||
va_list ap;
|
||||
va_start(ap, format);
|
||||
std::string prefix = stringf("%s:%d: Warning: ",
|
||||
filename.c_str(), lineno);
|
||||
filename.c_str(), lineno);
|
||||
logv_warning_with_prefix(prefix.c_str(), format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void log_file_info(const std::string &filename, int lineno,
|
||||
const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
std::string fmt = stringf("%s:%d: Info: %s",
|
||||
filename.c_str(), lineno, format);
|
||||
logv(fmt.c_str(), ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
YS_ATTRIBUTE(noreturn)
|
||||
static void logv_error_with_prefix(const char *prefix,
|
||||
const char *format, va_list ap)
|
||||
|
|
|
@ -80,6 +80,7 @@ void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
|||
|
||||
// Log with filename to report a problem in a source file.
|
||||
void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));
|
||||
void log_file_info(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));
|
||||
|
||||
void log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
|
||||
|
|
|
@ -601,6 +601,7 @@ struct RTLIL::SigChunk
|
|||
RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default;
|
||||
|
||||
RTLIL::SigChunk extract(int offset, int length) const;
|
||||
inline int size() const { return width; }
|
||||
|
||||
bool operator <(const RTLIL::SigChunk &other) const;
|
||||
bool operator ==(const RTLIL::SigChunk &other) const;
|
||||
|
|
|
@ -2026,7 +2026,6 @@ def gen_wrappers(filename, debug_level_ = 0):
|
|||
#include <boost/python/wrapper.hpp>
|
||||
#include <boost/python/call.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/log/exceptions.hpp>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
|
@ -2060,7 +2059,6 @@ namespace YOSYS_PYTHON {
|
|||
Yosys::log_streams.push_back(&std::cout);
|
||||
Yosys::log_error_stderr = true;
|
||||
Yosys::yosys_setup();
|
||||
Yosys::yosys_banner();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -393,44 +393,112 @@ struct SetundefPass : public Pass {
|
|||
ffbits.insert(bit);
|
||||
}
|
||||
|
||||
for (auto wire : module->wires())
|
||||
auto process_initwires = [&]()
|
||||
{
|
||||
if (!wire->attributes.count("\\init"))
|
||||
continue;
|
||||
dict<Wire*, int> wire_weights;
|
||||
|
||||
for (auto bit : sigmap(wire))
|
||||
ffbits.erase(bit);
|
||||
|
||||
initwires.insert(wire);
|
||||
}
|
||||
|
||||
for (int wire_types = 0; wire_types < 2; wire_types++)
|
||||
for (auto wire : module->wires())
|
||||
for (auto wire : initwires)
|
||||
{
|
||||
if (wire->name[0] == (wire_types ? '\\' : '$'))
|
||||
next_wire:
|
||||
continue;
|
||||
int weight = 0;
|
||||
|
||||
for (auto bit : sigmap(wire))
|
||||
if (!ffbits.count(bit))
|
||||
goto next_wire;
|
||||
weight += ffbits.count(bit) ? +1 : -1;
|
||||
|
||||
for (auto bit : sigmap(wire))
|
||||
ffbits.erase(bit);
|
||||
|
||||
initwires.insert(wire);
|
||||
wire_weights[wire] = weight;
|
||||
}
|
||||
|
||||
for (auto wire : initwires)
|
||||
{
|
||||
Const &initval = wire->attributes["\\init"];
|
||||
initwires.sort([&](Wire *a, Wire *b) { return wire_weights.at(a) > wire_weights.at(b); });
|
||||
|
||||
for (int i = 0; i < GetSize(wire); i++)
|
||||
if (GetSize(initval) <= i)
|
||||
initval.bits.push_back(worker.next_bit());
|
||||
else if (initval.bits[i] == State::Sx)
|
||||
initval.bits[i] = worker.next_bit();
|
||||
for (auto wire : initwires)
|
||||
{
|
||||
Const &initval = wire->attributes["\\init"];
|
||||
initval.bits.resize(GetSize(wire), State::Sx);
|
||||
|
||||
for (int i = 0; i < GetSize(wire); i++) {
|
||||
SigBit bit = sigmap(SigBit(wire, i));
|
||||
if (initval[i] == State::Sx && ffbits.count(bit)) {
|
||||
initval[i] = worker.next_bit();
|
||||
ffbits.erase(bit);
|
||||
}
|
||||
}
|
||||
|
||||
if (initval.is_fully_undef())
|
||||
wire->attributes.erase("\\init");
|
||||
}
|
||||
|
||||
initwires.clear();
|
||||
};
|
||||
|
||||
for (int wire_types = 0; wire_types < 2; wire_types++)
|
||||
{
|
||||
// prioritize wires that already have an init attribute
|
||||
if (!ffbits.empty())
|
||||
{
|
||||
for (auto wire : module->wires())
|
||||
{
|
||||
if (wire->name[0] == (wire_types ? '\\' : '$'))
|
||||
continue;
|
||||
|
||||
if (!wire->attributes.count("\\init"))
|
||||
continue;
|
||||
|
||||
Const &initval = wire->attributes["\\init"];
|
||||
initval.bits.resize(GetSize(wire), State::Sx);
|
||||
|
||||
if (initval.is_fully_undef()) {
|
||||
wire->attributes.erase("\\init");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < GetSize(wire); i++)
|
||||
if (initval[i] != State::Sx)
|
||||
ffbits.erase(sigmap(SigBit(wire, i)));
|
||||
|
||||
initwires.insert(wire);
|
||||
}
|
||||
|
||||
process_initwires();
|
||||
}
|
||||
|
||||
// next consider wires that completely contain bits to be initialized
|
||||
if (!ffbits.empty())
|
||||
{
|
||||
for (auto wire : module->wires())
|
||||
{
|
||||
if (wire->name[0] == (wire_types ? '\\' : '$'))
|
||||
continue;
|
||||
|
||||
for (auto bit : sigmap(wire))
|
||||
if (!ffbits.count(bit))
|
||||
goto next_wire;
|
||||
|
||||
initwires.insert(wire);
|
||||
|
||||
next_wire:
|
||||
continue;
|
||||
}
|
||||
|
||||
process_initwires();
|
||||
}
|
||||
|
||||
// finally use whatever wire we can find.
|
||||
if (!ffbits.empty())
|
||||
{
|
||||
for (auto wire : module->wires())
|
||||
{
|
||||
if (wire->name[0] == (wire_types ? '\\' : '$'))
|
||||
continue;
|
||||
|
||||
for (auto bit : sigmap(wire))
|
||||
if (ffbits.count(bit))
|
||||
initwires.insert(wire);
|
||||
}
|
||||
|
||||
process_initwires();
|
||||
}
|
||||
}
|
||||
|
||||
log_assert(ffbits.empty());
|
||||
}
|
||||
|
||||
module->rewrite_sigspecs(worker);
|
||||
|
|
|
@ -52,7 +52,9 @@ struct TeePass : public Pass {
|
|||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
std::vector<FILE*> backup_log_files, files_to_close;
|
||||
std::vector<std::ostream*> backup_log_streams;
|
||||
int backup_log_verbose_level = log_verbose_level;
|
||||
backup_log_streams = log_streams;
|
||||
backup_log_files = log_files;
|
||||
|
||||
size_t argidx;
|
||||
|
@ -60,6 +62,7 @@ struct TeePass : public Pass {
|
|||
{
|
||||
if (args[argidx] == "-q" && files_to_close.empty()) {
|
||||
log_files.clear();
|
||||
log_streams.clear();
|
||||
continue;
|
||||
}
|
||||
if ((args[argidx] == "-o" || args[argidx] == "-a") && argidx+1 < args.size()) {
|
||||
|
@ -89,6 +92,7 @@ struct TeePass : public Pass {
|
|||
for (auto cf : files_to_close)
|
||||
fclose(cf);
|
||||
log_files = backup_log_files;
|
||||
log_streams = backup_log_streams;
|
||||
throw;
|
||||
}
|
||||
|
||||
|
@ -97,6 +101,7 @@ struct TeePass : public Pass {
|
|||
|
||||
log_verbose_level = backup_log_verbose_level;
|
||||
log_files = backup_log_files;
|
||||
log_streams = backup_log_streams;
|
||||
}
|
||||
} TeePass;
|
||||
|
||||
|
|
|
@ -562,7 +562,8 @@ struct HierarchyPass : public Pass {
|
|||
log("In parametric designs, a module might exists in several variations with\n");
|
||||
log("different parameter values. This pass looks at all modules in the current\n");
|
||||
log("design an re-runs the language frontends for the parametric modules as\n");
|
||||
log("needed.\n");
|
||||
log("needed. It also resolves assignments to wired logic data types (wand/wor),\n");
|
||||
log("resolves positional module parameters, unroll array instances, and more.\n");
|
||||
log("\n");
|
||||
log(" -check\n");
|
||||
log(" also check the design hierarchy. this generates an error when\n");
|
||||
|
@ -943,62 +944,178 @@ struct HierarchyPass : public Pass {
|
|||
std::vector<Module*> design_modules = design->modules();
|
||||
|
||||
for (auto module : design_modules)
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
Module *m = design->module(cell->type);
|
||||
pool<Wire*> wand_wor_index;
|
||||
dict<Wire*, SigSpec> wand_map, wor_map;
|
||||
vector<SigSig> new_connections;
|
||||
|
||||
if (m == nullptr)
|
||||
continue;
|
||||
|
||||
if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
|
||||
IdString new_m_name = m->derive(design, cell->parameters, true);
|
||||
if (new_m_name.empty())
|
||||
continue;
|
||||
if (new_m_name != m->name) {
|
||||
m = design->module(new_m_name);
|
||||
blackbox_derivatives.insert(m);
|
||||
for (auto wire : module->wires())
|
||||
{
|
||||
if (wire->get_bool_attribute("\\wand")) {
|
||||
wand_map[wire] = SigSpec();
|
||||
wand_wor_index.insert(wire);
|
||||
}
|
||||
if (wire->get_bool_attribute("\\wor")) {
|
||||
wor_map[wire] = SigSpec();
|
||||
wand_wor_index.insert(wire);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &conn : cell->connections())
|
||||
for (auto &conn : module->connections())
|
||||
{
|
||||
Wire *w = m->wire(conn.first);
|
||||
SigSig new_conn;
|
||||
int cursor = 0;
|
||||
|
||||
if (w == nullptr || w->port_id == 0)
|
||||
continue;
|
||||
|
||||
if (GetSize(conn.second) == 0)
|
||||
continue;
|
||||
|
||||
SigSpec sig = conn.second;
|
||||
|
||||
if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
|
||||
for (auto c : conn.first.chunks())
|
||||
{
|
||||
if (GetSize(w) < GetSize(conn.second))
|
||||
{
|
||||
int n = GetSize(conn.second) - GetSize(w);
|
||||
if (!w->port_input && w->port_output)
|
||||
module->connect(sig.extract(GetSize(w), n), Const(0, n));
|
||||
sig.remove(GetSize(w), n);
|
||||
Wire *w = c.wire;
|
||||
SigSpec rhs = conn.second.extract(cursor, GetSize(c));
|
||||
|
||||
if (wand_wor_index.count(w) == 0) {
|
||||
new_conn.first.append(c);
|
||||
new_conn.second.append(rhs);
|
||||
} else {
|
||||
if (wand_map.count(w)) {
|
||||
SigSpec sig = SigSpec(State::S1, GetSize(w));
|
||||
sig.replace(c.offset, rhs);
|
||||
wand_map.at(w).append(sig);
|
||||
} else {
|
||||
SigSpec sig = SigSpec(State::S0, GetSize(w));
|
||||
sig.replace(c.offset, rhs);
|
||||
wor_map.at(w).append(sig);
|
||||
}
|
||||
}
|
||||
else
|
||||
cursor += GetSize(c);
|
||||
}
|
||||
new_connections.push_back(new_conn);
|
||||
}
|
||||
module->new_connections(new_connections);
|
||||
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
if (!cell->known())
|
||||
continue;
|
||||
|
||||
for (auto &conn : cell->connections())
|
||||
{
|
||||
if (!cell->output(conn.first))
|
||||
continue;
|
||||
|
||||
SigSpec new_sig;
|
||||
bool update_port = false;
|
||||
|
||||
for (auto c : conn.second.chunks())
|
||||
{
|
||||
int n = GetSize(w) - GetSize(conn.second);
|
||||
if (w->port_input && !w->port_output)
|
||||
sig.append(Const(0, n));
|
||||
else
|
||||
sig.append(module->addWire(NEW_ID, n));
|
||||
Wire *w = c.wire;
|
||||
|
||||
if (wand_wor_index.count(w) == 0) {
|
||||
new_sig.append(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
Wire *t = module->addWire(NEW_ID, GetSize(c));
|
||||
new_sig.append(t);
|
||||
update_port = true;
|
||||
|
||||
if (wand_map.count(w)) {
|
||||
SigSpec sig = SigSpec(State::S1, GetSize(w));
|
||||
sig.replace(c.offset, t);
|
||||
wand_map.at(w).append(sig);
|
||||
} else {
|
||||
SigSpec sig = SigSpec(State::S0, GetSize(w));
|
||||
sig.replace(c.offset, t);
|
||||
wor_map.at(w).append(sig);
|
||||
}
|
||||
}
|
||||
|
||||
if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
|
||||
log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
|
||||
log_id(conn.first), GetSize(conn.second), GetSize(sig));
|
||||
cell->setPort(conn.first, sig);
|
||||
if (update_port)
|
||||
cell->setPort(conn.first, new_sig);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto w : wand_wor_index)
|
||||
{
|
||||
bool wand = wand_map.count(w);
|
||||
SigSpec sigs = wand ? wand_map.at(w) : wor_map.at(w);
|
||||
|
||||
if (GetSize(sigs) == 0)
|
||||
continue;
|
||||
|
||||
if (GetSize(w) == 1) {
|
||||
if (wand)
|
||||
module->addReduceAnd(NEW_ID, sigs, w);
|
||||
else
|
||||
module->addReduceOr(NEW_ID, sigs, w);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (w->port_output && !w->port_input && sig.has_const())
|
||||
log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
|
||||
log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
|
||||
SigSpec s = sigs.extract(0, GetSize(w));
|
||||
for (int i = GetSize(w); i < GetSize(sigs); i += GetSize(w)) {
|
||||
if (wand)
|
||||
s = module->And(NEW_ID, s, sigs.extract(i, GetSize(w)));
|
||||
else
|
||||
s = module->Or(NEW_ID, s, sigs.extract(i, GetSize(w)));
|
||||
}
|
||||
module->connect(w, s);
|
||||
}
|
||||
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
Module *m = design->module(cell->type);
|
||||
|
||||
if (m == nullptr)
|
||||
continue;
|
||||
|
||||
if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
|
||||
IdString new_m_name = m->derive(design, cell->parameters, true);
|
||||
if (new_m_name.empty())
|
||||
continue;
|
||||
if (new_m_name != m->name) {
|
||||
m = design->module(new_m_name);
|
||||
blackbox_derivatives.insert(m);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &conn : cell->connections())
|
||||
{
|
||||
Wire *w = m->wire(conn.first);
|
||||
|
||||
if (w == nullptr || w->port_id == 0)
|
||||
continue;
|
||||
|
||||
if (GetSize(conn.second) == 0)
|
||||
continue;
|
||||
|
||||
SigSpec sig = conn.second;
|
||||
|
||||
if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
|
||||
{
|
||||
if (GetSize(w) < GetSize(conn.second))
|
||||
{
|
||||
int n = GetSize(conn.second) - GetSize(w);
|
||||
if (!w->port_input && w->port_output)
|
||||
module->connect(sig.extract(GetSize(w), n), Const(0, n));
|
||||
sig.remove(GetSize(w), n);
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = GetSize(w) - GetSize(conn.second);
|
||||
if (w->port_input && !w->port_output)
|
||||
sig.append(Const(0, n));
|
||||
else
|
||||
sig.append(module->addWire(NEW_ID, n));
|
||||
}
|
||||
|
||||
if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
|
||||
log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
|
||||
log_id(conn.first), GetSize(conn.second), GetSize(sig));
|
||||
cell->setPort(conn.first, sig);
|
||||
}
|
||||
|
||||
if (w->port_output && !w->port_input && sig.has_const())
|
||||
log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
|
||||
log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ void rmunused_module_cells(Module *module, bool verbose)
|
|||
if (raw_bit.wire == nullptr)
|
||||
continue;
|
||||
auto bit = sigmap(raw_bit);
|
||||
if (bit.wire == nullptr)
|
||||
if (bit.wire == nullptr && ct_all.cell_known(cell->type))
|
||||
driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict "
|
||||
"for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
|
||||
log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
|
||||
|
|
|
@ -299,8 +299,8 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
|
|||
sig_q = dff->getPort("\\Q");
|
||||
sig_c = dff->getPort("\\C");
|
||||
sig_e = dff->getPort("\\E");
|
||||
val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
|
||||
val_ep = RTLIL::Const(dff->type[7] == 'P', 1);
|
||||
val_cp = RTLIL::Const(dff->type[7] == 'P', 1);
|
||||
val_ep = RTLIL::Const(dff->type[8] == 'P', 1);
|
||||
}
|
||||
else if (dff->type == "$ff") {
|
||||
sig_d = dff->getPort("\\D");
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
pattern shiftmul
|
||||
//
|
||||
// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W]
|
||||
//
|
||||
|
||||
state <SigSpec> shamt
|
||||
|
||||
|
@ -49,12 +52,16 @@ code
|
|||
if (GetSize(port(shift, \Y)) > const_factor)
|
||||
reject;
|
||||
|
||||
int factor_bits = ceil_log2(const_factor);
|
||||
SigSpec mul_din = port(mul, const_factor_port == \A ? \B : \A);
|
||||
|
||||
if (GetSize(shamt) < factor_bits+GetSize(mul_din))
|
||||
reject;
|
||||
|
||||
did_something = true;
|
||||
log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul));
|
||||
|
||||
int new_const_factor_log2 = ceil_log2(const_factor);
|
||||
int new_const_factor = 1 << new_const_factor_log2;
|
||||
|
||||
int new_const_factor = 1 << factor_bits;
|
||||
SigSpec padding(State::Sx, new_const_factor-const_factor);
|
||||
SigSpec old_a = port(shift, \A), new_a;
|
||||
int trunc = 0;
|
||||
|
@ -73,7 +80,7 @@ code
|
|||
if (trunc > 0)
|
||||
new_a.remove(GetSize(new_a)-trunc, trunc);
|
||||
|
||||
SigSpec new_b = {port(mul, const_factor_port == \A ? \B : \A), SigSpec(State::S0, new_const_factor_log2)};
|
||||
SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)};
|
||||
if (param(shift, \B_SIGNED).as_bool())
|
||||
new_b.append(State::S0);
|
||||
|
||||
|
|
|
@ -332,7 +332,7 @@ struct FmcombinePass : public Pass {
|
|||
|
||||
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));
|
||||
log_cmd_error("Gate cell %s not found in module %s.\n", log_id(gate_name), log_id(module));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -351,7 +351,7 @@ struct FmcombinePass : public Pass {
|
|||
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");
|
||||
log_cmd_error("Gate cell has unresolved instance parameters.\n");
|
||||
|
||||
FmcombineWorker worker(design, gold_cell->type, opts);
|
||||
worker.generate();
|
||||
|
|
|
@ -88,6 +88,8 @@ struct SimInstance
|
|||
SimInstance(SimShared *shared, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
|
||||
shared(shared), module(module), instance(instance), parent(parent), sigmap(module)
|
||||
{
|
||||
log_assert(module);
|
||||
|
||||
if (parent) {
|
||||
log_assert(parent->children.count(instance) == 0);
|
||||
parent->children[instance] = this;
|
||||
|
@ -848,6 +850,9 @@ struct SimPass : public Pass {
|
|||
|
||||
if (design->full_selection()) {
|
||||
top_mod = design->top_module();
|
||||
|
||||
if (!top_mod)
|
||||
log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
|
||||
} else {
|
||||
auto mods = design->selected_whole_modules();
|
||||
if (GetSize(mods) != 1)
|
||||
|
|
|
@ -58,12 +58,21 @@ struct MuxcoverWorker
|
|||
bool use_mux16;
|
||||
bool nodecode;
|
||||
|
||||
int cost_mux2;
|
||||
int cost_mux4;
|
||||
int cost_mux8;
|
||||
int cost_mux16;
|
||||
|
||||
MuxcoverWorker(Module *module) : module(module), sigmap(module)
|
||||
{
|
||||
use_mux4 = false;
|
||||
use_mux8 = false;
|
||||
use_mux16 = false;
|
||||
nodecode = false;
|
||||
cost_mux2 = COST_MUX2;
|
||||
cost_mux4 = COST_MUX4;
|
||||
cost_mux8 = COST_MUX8;
|
||||
cost_mux16 = COST_MUX16;
|
||||
decode_mux_counter = 0;
|
||||
}
|
||||
|
||||
|
@ -157,7 +166,7 @@ struct MuxcoverWorker
|
|||
if (std::get<2>(entry))
|
||||
return 0;
|
||||
|
||||
return COST_MUX2 / GetSize(std::get<1>(entry));
|
||||
return cost_mux2 / GetSize(std::get<1>(entry));
|
||||
}
|
||||
|
||||
void implement_decode_mux(SigBit ctrl_bit)
|
||||
|
@ -209,7 +218,7 @@ struct MuxcoverWorker
|
|||
mux.inputs.push_back(B);
|
||||
mux.selects.push_back(S1);
|
||||
|
||||
mux.cost += COST_MUX2;
|
||||
mux.cost += cost_mux2;
|
||||
mux.cost += find_best_cover(tree, A);
|
||||
mux.cost += find_best_cover(tree, B);
|
||||
|
||||
|
@ -247,7 +256,7 @@ struct MuxcoverWorker
|
|||
mux.selects.push_back(S1);
|
||||
mux.selects.push_back(T1);
|
||||
|
||||
mux.cost += COST_MUX4;
|
||||
mux.cost += cost_mux4;
|
||||
mux.cost += find_best_cover(tree, A);
|
||||
mux.cost += find_best_cover(tree, B);
|
||||
mux.cost += find_best_cover(tree, C);
|
||||
|
@ -310,7 +319,7 @@ struct MuxcoverWorker
|
|||
mux.selects.push_back(T1);
|
||||
mux.selects.push_back(U1);
|
||||
|
||||
mux.cost += COST_MUX8;
|
||||
mux.cost += cost_mux8;
|
||||
mux.cost += find_best_cover(tree, A);
|
||||
mux.cost += find_best_cover(tree, B);
|
||||
mux.cost += find_best_cover(tree, C);
|
||||
|
@ -414,7 +423,7 @@ struct MuxcoverWorker
|
|||
mux.selects.push_back(U1);
|
||||
mux.selects.push_back(V1);
|
||||
|
||||
mux.cost += COST_MUX16;
|
||||
mux.cost += cost_mux16;
|
||||
mux.cost += find_best_cover(tree, A);
|
||||
mux.cost += find_best_cover(tree, B);
|
||||
mux.cost += find_best_cover(tree, C);
|
||||
|
@ -569,9 +578,11 @@ struct MuxcoverPass : public Pass {
|
|||
log("\n");
|
||||
log("Cover trees of $_MUX_ cells with $_MUX{4,8,16}_ cells\n");
|
||||
log("\n");
|
||||
log(" -mux4, -mux8, -mux16\n");
|
||||
log(" Use the specified types of MUXes. If none of those options are used,\n");
|
||||
log(" the effect is the same as if all of them where used.\n");
|
||||
log(" -mux4[=cost], -mux8[=cost], -mux16[=cost]\n");
|
||||
log(" Use the specified types of MUXes (with optional integer costs). If none\n");
|
||||
log(" of these options are given, the effect is the same as if all of them are.\n");
|
||||
log(" Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4);
|
||||
log(" $_MUX8_ = %d, $_MUX16_ = %d\n", COST_MUX8, COST_MUX16);
|
||||
log("\n");
|
||||
log(" -nodecode\n");
|
||||
log(" Do not insert decoder logic. This reduces the number of possible\n");
|
||||
|
@ -587,23 +598,39 @@ struct MuxcoverPass : public Pass {
|
|||
bool use_mux8 = false;
|
||||
bool use_mux16 = false;
|
||||
bool nodecode = false;
|
||||
int cost_mux4 = COST_MUX4;
|
||||
int cost_mux8 = COST_MUX8;
|
||||
int cost_mux16 = COST_MUX16;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
if (args[argidx] == "-mux4") {
|
||||
const auto &arg = args[argidx];
|
||||
if (arg.size() >= 5 && arg.substr(0,5) == "-mux4") {
|
||||
use_mux4 = true;
|
||||
if (arg.size() > 5) {
|
||||
if (arg[5] != '=') break;
|
||||
cost_mux4 = atoi(arg.substr(5).c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-mux8") {
|
||||
if (arg.size() >= 5 && arg.substr(0,5) == "-mux8") {
|
||||
use_mux8 = true;
|
||||
if (arg.size() > 5) {
|
||||
if (arg[5] != '=') break;
|
||||
cost_mux8 = atoi(arg.substr(5).c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-mux16") {
|
||||
if (arg.size() >= 6 && arg.substr(0,6) == "-mux16") {
|
||||
use_mux16 = true;
|
||||
if (arg.size() > 6) {
|
||||
if (arg[6] != '=') break;
|
||||
cost_mux16 = atoi(arg.substr(6).c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nodecode") {
|
||||
if (arg == "-nodecode") {
|
||||
nodecode = true;
|
||||
continue;
|
||||
}
|
||||
|
@ -623,6 +650,9 @@ struct MuxcoverPass : public Pass {
|
|||
worker.use_mux4 = use_mux4;
|
||||
worker.use_mux8 = use_mux8;
|
||||
worker.use_mux16 = use_mux16;
|
||||
worker.cost_mux4 = cost_mux4;
|
||||
worker.cost_mux8 = cost_mux8;
|
||||
worker.cost_mux16 = cost_mux16;
|
||||
worker.nodecode = nodecode;
|
||||
worker.run();
|
||||
}
|
||||
|
|
|
@ -606,6 +606,9 @@ struct ShregmapPass : public Pass {
|
|||
log(" -tech greenpak4\n");
|
||||
log(" map to greenpak4 shift registers.\n");
|
||||
log("\n");
|
||||
log(" -tech xilinx\n");
|
||||
log(" map to xilinx dynamic-length shift registers.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
|
|
|
@ -47,6 +47,21 @@ 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_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
|
||||
|
||||
// Diamond I/O buffers
|
||||
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
||||
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
||||
module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
||||
module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule
|
||||
module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
|
||||
module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
|
||||
module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
|
||||
module OBCO (input I, output OT, OC); OLVDS _TECHMAP_REPLACE_ (.A(I), .Z(OT), .ZN(OC)); endmodule
|
||||
module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
|
||||
module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
|
||||
module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
|
||||
module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
|
||||
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); 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
|
||||
|
||||
|
|
|
@ -973,6 +973,30 @@ parameter RGB1_CURRENT = "0b000000";
|
|||
parameter RGB2_CURRENT = "0b000000";
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module SB_LED_DRV_CUR(
|
||||
input EN,
|
||||
output LEDPU
|
||||
);
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module SB_RGB_DRV(
|
||||
input RGBLEDEN,
|
||||
input RGB0PWM,
|
||||
input RGB1PWM,
|
||||
input RGB2PWM,
|
||||
input RGBPU,
|
||||
output RGB0,
|
||||
output RGB1,
|
||||
output RGB2
|
||||
);
|
||||
parameter CURRENT_MODE = "0b0";
|
||||
parameter RGB0_CURRENT = "0b000000";
|
||||
parameter RGB1_CURRENT = "0b000000";
|
||||
parameter RGB2_CURRENT = "0b000000";
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module SB_I2C(
|
||||
input SBCLKI,
|
||||
|
|
|
@ -229,11 +229,6 @@ struct SynthXilinxPass : public ScriptPass
|
|||
run("dff2dffe");
|
||||
run("opt -full");
|
||||
|
||||
if (!vpr || help_mode)
|
||||
run("techmap -map +/xilinx/arith_map.v");
|
||||
else
|
||||
run("techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
|
||||
|
||||
if (!nosrl || help_mode) {
|
||||
// shregmap operates on bit-level flops, not word-level,
|
||||
// so break those down here
|
||||
|
@ -242,7 +237,11 @@ struct SynthXilinxPass : public ScriptPass
|
|||
run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
|
||||
}
|
||||
|
||||
run("techmap");
|
||||
if (!vpr || help_mode)
|
||||
run("techmap -map +/techmap.v -map +/xilinx/arith_map.v");
|
||||
else
|
||||
run("techmap -map +/techmap.v +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
|
||||
|
||||
run("opt -fast");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
aig 3 2 0 1 1
|
||||
6
|
||||
|
|
@ -3,3 +3,6 @@ aag 3 2 0 1 1
|
|||
4
|
||||
6
|
||||
6 2 4
|
||||
i0 pi0
|
||||
i1 pi1
|
||||
o0 po0
|
|
@ -0,0 +1,5 @@
|
|||
aig 3 2 0 1 1
|
||||
6
|
||||
i0 pi0
|
||||
i1 pi1
|
||||
o0 po0
|
|
@ -1,3 +1,5 @@
|
|||
aag 1 1 0 1 0
|
||||
2
|
||||
2
|
||||
i0 pi0
|
||||
o0 po0
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
aig 1 1 0 1 0
|
||||
2
|
||||
i0 pi0
|
||||
o0 po0
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
aag 1 0 1 0 0 1
|
||||
2 3
|
||||
2
|
||||
b0 po0
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
aig 1 0 1 0 0 1
|
||||
3
|
||||
2
|
||||
b0 po0
|
||||
|
|
|
@ -6,3 +6,4 @@ aag 5 1 1 0 3 1
|
|||
8 4 2
|
||||
10 9 7
|
||||
b0 AIGER_NEVER
|
||||
i0 po0
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
aig 5 1 1 0 3 1
|
||||
10
|
||||
4
|
||||
b0 AIGER_NEVER
|
||||
i0 po0
|
||||
b0 AIGER_NEVER
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
aag 0 0 0 1 0
|
||||
0
|
||||
o0 po0
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
aig 0 0 0 1 0
|
||||
0
|
||||
o0 po0
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
aag 1 1 0 1 0
|
||||
2
|
||||
3
|
||||
i0 pi0
|
||||
o0 po0
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
aig 1 1 0 1 0
|
||||
3
|
||||
i0 pi0
|
||||
o0 po0
|
||||
|
|
|
@ -6,3 +6,4 @@ aag 5 1 1 0 3 1
|
|||
8 4 2
|
||||
10 9 7
|
||||
b0 AIGER_NEVER
|
||||
i0 pi0
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
aig 5 1 1 0 3 1
|
||||
10
|
||||
5
|
||||
b0 AIGER_NEVER
|
||||
i0 pi0
|
||||
b0 AIGER_NEVER
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
aig 3 2 0 1 1
|
||||
7
|
||||
|
|
@ -3,3 +3,6 @@ aag 3 2 0 1 1
|
|||
4
|
||||
7
|
||||
6 3 5
|
||||
i0 pi0
|
||||
i1 pi1
|
||||
o0 po0
|
|
@ -0,0 +1,5 @@
|
|||
aig 3 2 0 1 1
|
||||
7
|
||||
i0 pi0
|
||||
i1 pi1
|
||||
o0 po0
|
|
@ -1,24 +1,42 @@
|
|||
#!/bin/bash
|
||||
|
||||
OPTIND=1
|
||||
seed="" # default to no seed specified
|
||||
while getopts "S:" opt
|
||||
do
|
||||
case "$opt" in
|
||||
S) arg="${OPTARG#"${OPTARG%%[![:space:]]*}"}" # remove leading space
|
||||
seed="SEED=$arg" ;;
|
||||
esac
|
||||
set -e
|
||||
|
||||
# NB: *.aag and *.aig must contain a symbol table naming the primary
|
||||
# inputs and outputs, otherwise ABC and Yosys will name them
|
||||
# arbitrarily (and inconsistently with each other).
|
||||
|
||||
for aag in *.aag; do
|
||||
# Since ABC cannot read *.aag, read the *.aig instead
|
||||
# (which would have been created by the reference aig2aig utility,
|
||||
# available from http://fmv.jku.at/aiger/)
|
||||
../../yosys-abc -c "read -c ${aag%.*}.aig; write ${aag%.*}_ref.v"
|
||||
../../yosys -p "
|
||||
read_verilog ${aag%.*}_ref.v
|
||||
prep
|
||||
design -stash gold
|
||||
read_aiger -clk_name clock $aag
|
||||
prep
|
||||
design -stash gate
|
||||
design -import gold -as gold
|
||||
design -import gate -as gate
|
||||
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||
sat -verify -prove-asserts -show-ports -seq 16 miter
|
||||
"
|
||||
done
|
||||
shift "$((OPTIND-1))"
|
||||
|
||||
# check for Icarus Verilog
|
||||
if ! which iverilog > /dev/null ; then
|
||||
echo "$0: Error: Icarus Verilog 'iverilog' not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "===== AAG ======"
|
||||
${MAKE:-make} -f ../tools/autotest.mk $seed *.aag EXTRA_FLAGS="-f aiger"
|
||||
|
||||
echo "===== AIG ======"
|
||||
exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.aig EXTRA_FLAGS="-f aiger"
|
||||
for aig in *.aig; do
|
||||
../../yosys-abc -c "read -c $aig; write ${aig%.*}_ref.v"
|
||||
../../yosys -p "
|
||||
read_verilog ${aig%.*}_ref.v
|
||||
prep
|
||||
design -stash gold
|
||||
read_aiger -clk_name clock $aig
|
||||
prep
|
||||
design -stash gate
|
||||
design -import gold -as gold
|
||||
design -import gate -as gate
|
||||
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||
sat -verify -prove-asserts -show-ports -seq 16 miter
|
||||
"
|
||||
done
|
||||
|
|
|
@ -2,3 +2,5 @@ aag 1 0 1 2 0
|
|||
2 3
|
||||
2
|
||||
3
|
||||
o0 po0
|
||||
o1 po1
|
||||
|
|
|
@ -2,3 +2,5 @@ aig 1 0 1 2 0
|
|||
3
|
||||
2
|
||||
3
|
||||
o0 po0
|
||||
o1 po1
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
aag 0 0 0 1 0
|
||||
1
|
||||
o0 po0
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
aig 0 0 0 1 0
|
||||
1
|
||||
o0 po0
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
module bar(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
output reg out;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) out <= 1'd0;
|
||||
else out <= ~inp;
|
||||
|
||||
endmodule
|
||||
|
||||
module foo(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
output wire out;
|
||||
|
||||
bar bar_instance (clk, rst, inp, out);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
module bar(clk, rst, inp, out);
|
||||
(* this_is_clock = 1 *)
|
||||
input wire clk;
|
||||
(* this_is_reset = 1 *)
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
(* an_output_register = 1*)
|
||||
output reg out;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) out <= 1'd0;
|
||||
else out <= ~inp;
|
||||
|
||||
endmodule
|
||||
|
||||
module foo(clk, rst, inp, out);
|
||||
(* this_is_the_master_clock *)
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
output wire out;
|
||||
|
||||
bar bar_instance (clk, rst, inp, out);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
module bar(clk, rst, inp, out);
|
||||
|
||||
(* bus_width *)
|
||||
parameter WIDTH = 2;
|
||||
|
||||
(* an_attribute_on_localparam = 55 *)
|
||||
localparam INCREMENT = 5;
|
||||
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire [WIDTH-1:0] inp;
|
||||
output reg [WIDTH-1:0] out;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) out <= 0;
|
||||
else out <= inp + INCREMENT;
|
||||
|
||||
endmodule
|
||||
|
||||
module foo(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire [7:0] inp;
|
||||
output wire [7:0] out;
|
||||
|
||||
bar # (.WIDTH(8)) bar_instance (clk, rst, inp, out);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
module bar(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
output reg out;
|
||||
|
||||
(* this_is_a_prescaler *)
|
||||
reg [7:0] counter;
|
||||
|
||||
(* temp_wire *)
|
||||
wire out_val;
|
||||
|
||||
always @(posedge clk)
|
||||
counter <= counter + 1;
|
||||
|
||||
assign out_val = inp ^ counter[4];
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) out <= 1'd0;
|
||||
else out <= out_val;
|
||||
|
||||
endmodule
|
||||
|
||||
module foo(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
output wire out;
|
||||
|
||||
bar bar_instance (clk, rst, inp, out);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
module bar(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
output reg out;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) out <= 1'd0;
|
||||
else out <= ~inp;
|
||||
|
||||
endmodule
|
||||
|
||||
module foo(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
output wire out;
|
||||
|
||||
bar bar_instance ( (* clock_connected *) clk, rst, (* this_is_the_input *) inp, out);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
module bar(clk, rst, inp_a, inp_b, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire [7:0] inp_a;
|
||||
input wire [7:0] inp_b;
|
||||
output reg [7:0] out;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) out <= 0;
|
||||
else out <= inp_a + (* ripple_adder *) inp_b;
|
||||
|
||||
endmodule
|
||||
|
||||
module foo(clk, rst, inp_a, inp_b, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire [7:0] inp_a;
|
||||
input wire [7:0] inp_b;
|
||||
output wire [7:0] out;
|
||||
|
||||
bar bar_instance (clk, rst, inp_a, inp_b, out);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
function [7:0] do_add;
|
||||
input [7:0] inp_a;
|
||||
input [7:0] inp_b;
|
||||
|
||||
do_add = inp_a + inp_b;
|
||||
|
||||
endfunction
|
||||
|
||||
module foo(clk, rst, inp_a, inp_b, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire [7:0] inp_a;
|
||||
input wire [7:0] inp_b;
|
||||
output wire [7:0] out;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) out <= 0;
|
||||
else out <= do_add (* combinational_adder *) (inp_a, inp_b);
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
module bar(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
output reg out;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) out <= 1'd0;
|
||||
else out <= ~inp;
|
||||
|
||||
endmodule
|
||||
|
||||
module foo(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
output wire out;
|
||||
|
||||
(* my_module_instance = 99 *)
|
||||
bar bar_instance (clk, rst, inp, out);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
module bar(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire [1:0] inp;
|
||||
output reg [1:0] out;
|
||||
|
||||
always @(inp)
|
||||
(* full_case, parallel_case *)
|
||||
case(inp)
|
||||
2'd0: out <= 2'd3;
|
||||
2'd1: out <= 2'd2;
|
||||
2'd2: out <= 2'd1;
|
||||
2'd3: out <= 2'd0;
|
||||
endcase
|
||||
|
||||
endmodule
|
||||
|
||||
module foo(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire [1:0] inp;
|
||||
output wire [1:0] out;
|
||||
|
||||
bar bar_instance (clk, rst, inp, out);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Test implicit port connections
|
||||
module alu (input [2:0] a, input [2:0] b, input cin, output cout, output [2:0] result);
|
||||
assign cout = cin;
|
||||
assign result = a + b;
|
||||
endmodule
|
||||
|
||||
module named_ports(input [2:0] a, b, output [2:0] alu_result, output cout);
|
||||
wire cin = 1;
|
||||
alu alu (
|
||||
.a(a),
|
||||
.b, // Implicit connection is equivalent to .b(b)
|
||||
.cin(), // Explicitely unconnected
|
||||
.cout(cout),
|
||||
.result(alu_result)
|
||||
);
|
||||
endmodule
|
|
@ -2,6 +2,10 @@ module peepopt_shiftmul_0 #(parameter N=3, parameter W=3) (input [N*W-1:0] i, in
|
|||
assign o = i[s*W+:W];
|
||||
endmodule
|
||||
|
||||
module peepopt_shiftmul_1 (output y, input [2:0] w);
|
||||
assign y = 1'b1 >> (w * (3'b110));
|
||||
endmodule
|
||||
|
||||
module peepopt_muldiv_0(input [1:0] i, output [1:0] o);
|
||||
wire [3:0] t;
|
||||
assign t = i * 3;
|
||||
|
|
|
@ -17,4 +17,5 @@ if ! which iverilog > /dev/null ; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v
|
||||
shopt -s nullglob
|
||||
exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.{sv,v}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
module wandwor_test0 (A, B, C, D, X, Y, Z);
|
||||
input A, B, C, D;
|
||||
output wor X;
|
||||
output wand Y;
|
||||
output Z;
|
||||
|
||||
assign X = A, X = B, Y = C, Y = D;
|
||||
foo foo_0 (C, D, X);
|
||||
foo foo_1 (A, B, Y);
|
||||
foo foo_2 (X, Y, Z);
|
||||
endmodule
|
||||
|
||||
module wandwor_test1 (A, B, C, D, X, Y, Z);
|
||||
input [3:0] A, B, C, D;
|
||||
output wor [3:0] X;
|
||||
output wand [3:0] Y;
|
||||
output Z;
|
||||
|
||||
bar bar_inst (
|
||||
.I0({A, B}),
|
||||
.I1({B, A}),
|
||||
.O({X, Y})
|
||||
);
|
||||
|
||||
assign X = C, X = D;
|
||||
assign Y = C, Y = D;
|
||||
assign Z = ^{X,Y};
|
||||
endmodule
|
||||
|
||||
module foo(input I0, I1, output O);
|
||||
assign O = I0 ^ I1;
|
||||
endmodule
|
||||
|
||||
module bar(input [7:0] I0, I1, output [7:0] O);
|
||||
assign O = I0 + I1;
|
||||
endmodule
|
|
@ -89,6 +89,13 @@ done
|
|||
|
||||
compile_and_run() {
|
||||
exe="$1"; output="$2"; shift 2
|
||||
ext=${1##*.}
|
||||
if [ "$ext" == "sv" ]; then
|
||||
language_gen="-g2012"
|
||||
else
|
||||
language_gen="-g2005"
|
||||
fi
|
||||
|
||||
if $use_modelsim; then
|
||||
altver=$( ls -v /opt/altera/ | grep '^[0-9]' | tail -n1; )
|
||||
/opt/altera/$altver/modelsim_ase/bin/vlib work
|
||||
|
@ -99,7 +106,7 @@ compile_and_run() {
|
|||
/opt/Xilinx/Vivado/$xilver/bin/xvlog $xinclude_opts -d outfile=\"$output\" "$@"
|
||||
/opt/Xilinx/Vivado/$xilver/bin/xelab -R work.testbench
|
||||
else
|
||||
iverilog $include_opts -Doutfile=\"$output\" -s testbench -o "$exe" "$@"
|
||||
iverilog $language_gen $include_opts -Doutfile=\"$output\" -s testbench -o "$exe" "$@"
|
||||
vvp -n "$exe"
|
||||
fi
|
||||
}
|
||||
|
@ -110,7 +117,7 @@ for fn
|
|||
do
|
||||
bn=${fn%.*}
|
||||
ext=${fn##*.}
|
||||
if [[ "$ext" != "v" ]] && [[ "$ext" != "aag" ]] && [[ "$ext" != "aig" ]]; then
|
||||
if [[ "$ext" != "v" ]] && [[ "$ext" != "sv" ]] && [[ "$ext" != "aag" ]] && [[ "$ext" != "aig" ]]; then
|
||||
echo "Invalid argument: $fn" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
@ -123,6 +130,10 @@ do
|
|||
echo -n "Test: $bn "
|
||||
fi
|
||||
|
||||
if [ "$ext" == sv ]; then
|
||||
frontend="$frontend -sv"
|
||||
fi
|
||||
|
||||
rm -f ${bn}.{err,log,skip}
|
||||
mkdir -p ${bn}.out
|
||||
rm -rf ${bn}.out/*
|
||||
|
@ -135,9 +146,10 @@ do
|
|||
rm -f ${bn}_ref.fir
|
||||
if [[ "$ext" == "v" ]]; then
|
||||
egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext}
|
||||
elif [[ "$ext" == "aig" ]] || [[ "$ext" == "aag" ]]; then
|
||||
"$toolsdir"/../../yosys-abc -c "read_aiger ../${fn}; write ${bn}_ref.v"
|
||||
else
|
||||
"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn}
|
||||
frontend="verilog -noblackbox"
|
||||
cp ../${fn} ${bn}_ref.${ext}
|
||||
fi
|
||||
|
||||
if [ ! -f ../${bn}_tb.v ]; then
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
module bar(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
output reg out;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) out <= 1'd0;
|
||||
else out <= ~inp;
|
||||
|
||||
endmodule
|
||||
|
||||
module foo(clk, rst, inp, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire inp;
|
||||
output wire out;
|
||||
|
||||
bar bar_instance ( (* clock_connected *) clk, rst, (* this_is_the_input *) inp, out);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# Read and parse Verilog file
|
||||
read_verilog attrib05_port_conn.v
|
|
@ -0,0 +1,21 @@
|
|||
function [7:0] do_add;
|
||||
input [7:0] inp_a;
|
||||
input [7:0] inp_b;
|
||||
|
||||
do_add = inp_a + inp_b;
|
||||
|
||||
endfunction
|
||||
|
||||
module foo(clk, rst, inp_a, inp_b, out);
|
||||
input wire clk;
|
||||
input wire rst;
|
||||
input wire [7:0] inp_a;
|
||||
input wire [7:0] inp_b;
|
||||
output wire [7:0] out;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) out <= 0;
|
||||
else out <= do_add (* combinational_adder *) (inp_a, inp_b);
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# Read and parse Verilog file
|
||||
read_verilog attrib07_func_call.v
|
|
@ -0,0 +1,30 @@
|
|||
module test;
|
||||
localparam X=1;
|
||||
genvar i;
|
||||
generate
|
||||
if (X == 1)
|
||||
$info("X is 1");
|
||||
if (X == 1)
|
||||
$warning("X is 1");
|
||||
else
|
||||
$error("X is not 1");
|
||||
case (X)
|
||||
1: $info("X is 1 in a case statement");
|
||||
endcase
|
||||
//case (X-1)
|
||||
// 1: $warn("X is 2");
|
||||
// default: $warn("X might be anything in a case statement");
|
||||
//endcase
|
||||
for (i = 0; i < 3; i = i + 1)
|
||||
begin
|
||||
case(i)
|
||||
0: $info;
|
||||
1: $warning;
|
||||
default: $info("default case statemnent");
|
||||
endcase
|
||||
end
|
||||
|
||||
$info("This is a standalone $info(). Next $info has no parameters");
|
||||
$info;
|
||||
endgenerate
|
||||
endmodule
|
|
@ -0,0 +1 @@
|
|||
read_verilog -sv elab_sys_tasks.sv
|
Loading…
Reference in New Issue