summaryrefslogtreecommitdiff
path: root/frontends
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2019-10-18 19:56:51 +0000
committerRuben Undheim <ruben.undheim@gmail.com>2019-10-18 19:56:51 +0000
commit1f6bb85359149a016811e7e7fef980c3d45211e7 (patch)
tree749672f9a104cbfb25bb02acad6cb731724b9d56 /frontends
parentff5734b20220e6fb4a3913cf5279ed94bb5156ea (diff)
New upstream version 0.9
Diffstat (limited to 'frontends')
-rw-r--r--frontends/aiger/aigerparse.cc691
-rw-r--r--frontends/aiger/aigerparse.h1
-rw-r--r--frontends/ast/ast.cc118
-rw-r--r--frontends/ast/ast.h13
-rw-r--r--frontends/ast/genrtlil.cc95
-rw-r--r--frontends/ast/simplify.cc50
-rw-r--r--frontends/ilang/ilang_frontend.cc10
-rw-r--r--frontends/ilang/ilang_frontend.h1
-rw-r--r--frontends/ilang/ilang_lexer.l1
-rw-r--r--frontends/ilang/ilang_parser.y39
-rw-r--r--frontends/json/jsonparse.cc24
-rw-r--r--frontends/verific/verific.cc106
-rw-r--r--frontends/verific/verific.h2
-rw-r--r--frontends/verilog/Makefile.inc2
-rw-r--r--frontends/verilog/const2ast.cc28
-rw-r--r--frontends/verilog/verilog_frontend.cc43
-rw-r--r--frontends/verilog/verilog_frontend.h3
-rw-r--r--frontends/verilog/verilog_lexer.l32
-rw-r--r--frontends/verilog/verilog_parser.y530
19 files changed, 1268 insertions, 521 deletions
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index cf7950c8..68552fd0 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -33,353 +33,390 @@
YOSYS_NAMESPACE_BEGIN
-#define log_debug log
-
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");
-
- // Parse rest of header
- if (!(f >> M >> I >> L >> O >> A))
- log_error("Invalid AIGER header\n");
-
- // Optional values
- B = C = J = F = 0;
- for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) {
- if (f.peek() != ' ') break;
- if (!(f >> i))
- log_error("Invalid AIGER header\n");
- }
-
- 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);
-
- line_count = 1;
-
- 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);
-
- 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);
-
- 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();
-
- 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
- }
-
- module->fixup_ports();
- design->add(module);
+ 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");
+
+ // 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
+
+ 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;
+
+ if (header == "aag")
+ parse_aiger_ascii();
+ else if (header == "aig")
+ parse_aiger_binary();
+ else
+ log_abort();
+
+ RTLIL::Wire* n0 = module->wire("\\n0");
+ if (n0)
+ module->connect(n0, RTLIL::S0);
+
+ 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;
+ }
+ }
+
+ // 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);
+
+ 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);
+
+ 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);
- }
-
- 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;
+ 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?
+
+ return wire;
}
void AigerReader::parse_aiger_ascii()
{
- std::string line;
- std::stringstream ss;
-
- 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 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);
-
- // 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);
- }
-
- // 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
-
- // 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
-
- // 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 justice properties
- for (unsigned i = 0; i < J; ++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
-
- // 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
+ std::string line;
+ std::stringstream ss;
+
+ unsigned l1, l2, l3;
+
+ // 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);
+
+ 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);
+
+ 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);
+
+ log_debug("%d is an output\n", l1);
+ RTLIL::Wire *wire = createWireIfNotExists(module, l1);
+ wire->port_output = true;
+ outputs.push_back(wire);
+ }
+
+ // 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);
+
+ 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 invariant constraints
+ for (unsigned i = 0; i < C; ++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
+
+ // TODO: Parse fairness constraints
+ for (unsigned i = 0; i < F; ++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);
+
+ 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;
-
- // 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);
-
- 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);
-
- 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);
- }
-
- // 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
-
- // 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
-
- // 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 justice properties
- for (unsigned i = 0; i < J; ++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
-
- // 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);
-
- 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);
- }
+ 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 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);
+
+ // 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)
+ 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);
+
+ 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
+
+ // 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);
+
+ 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 invariant constraints
+ for (unsigned i = 0; i < C; ++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
+
+ // TODO: Parse fairness constraints
+ for (unsigned i = 0; i < F; ++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);
+
+ 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");
-
- RTLIL::IdString clk_name = "\\clk";
- RTLIL::IdString module_name;
+ ")\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;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -396,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
diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h
index c49cd152..0e3719cc 100644
--- a/frontends/aiger/aigerparse.h
+++ b/frontends/aiger/aigerparse.h
@@ -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();
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index d4899616..3d066af5 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -46,7 +46,7 @@ namespace AST {
// instantiate global variables (private API)
namespace AST_INTERNAL {
bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
- bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+ bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_autowire;
AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope;
const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
@@ -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,9 @@ 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;
range_swapped = false;
@@ -722,7 +726,7 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
}
// create an AST node for a constant (using a bit vector as value)
-AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
+AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
{
AstNode *node = new AstNode(AST_CONSTANT);
node->is_signed = is_signed;
@@ -736,9 +740,15 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
node->range_valid = true;
node->range_left = node->bits.size()-1;
node->range_right = 0;
+ node->is_unsized = is_unsized;
return node;
}
+AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
+{
+ return mkconst_bits(v, is_signed, false);
+}
+
// create an AST node for a constant (using a string in bit vector form as value)
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
{
@@ -775,6 +785,14 @@ bool AstNode::bits_only_01() const
return true;
}
+RTLIL::Const AstNode::bitsAsUnsizedConst(int width)
+{
+ RTLIL::State extbit = bits.back();
+ while (width > int(bits.size()))
+ bits.push_back(extbit);
+ return RTLIL::Const(bits);
+}
+
RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed)
{
std::vector<RTLIL::State> bits = this->bits;
@@ -942,6 +960,23 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
if (!defer)
{
+ bool blackbox_module = flag_lib;
+
+ if (!blackbox_module && !flag_noblackbox) {
+ blackbox_module = true;
+ for (auto child : ast->children) {
+ if (child->type == AST_WIRE && (child->is_input || child->is_output))
+ continue;
+ if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
+ continue;
+ if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
+ (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule"))
+ continue;
+ blackbox_module = false;
+ break;
+ }
+ }
+
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
if (flag_dump_ast2) {
@@ -956,7 +991,63 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
log("--- END OF AST DUMP ---\n");
}
- if (flag_lib) {
+ if (flag_nowb && ast->attributes.count("\\whitebox")) {
+ delete ast->attributes.at("\\whitebox");
+ ast->attributes.erase("\\whitebox");
+ }
+
+ if (ast->attributes.count("\\lib_whitebox")) {
+ if (!flag_lib || flag_nowb) {
+ delete ast->attributes.at("\\lib_whitebox");
+ ast->attributes.erase("\\lib_whitebox");
+ } else {
+ if (ast->attributes.count("\\whitebox")) {
+ delete ast->attributes.at("\\whitebox");
+ ast->attributes.erase("\\whitebox");
+ }
+ AstNode *n = ast->attributes.at("\\lib_whitebox");
+ ast->attributes["\\whitebox"] = n;
+ ast->attributes.erase("\\lib_whitebox");
+ }
+ }
+
+ if (!blackbox_module && ast->attributes.count("\\blackbox")) {
+ AstNode *n = ast->attributes.at("\\blackbox");
+ if (n->type != AST_CONSTANT)
+ log_file_error(ast->filename, ast->linenum, "Got blackbox attribute with non-constant value!\n");
+ blackbox_module = n->asBool();
+ }
+
+ if (blackbox_module && ast->attributes.count("\\whitebox")) {
+ AstNode *n = ast->attributes.at("\\whitebox");
+ if (n->type != AST_CONSTANT)
+ log_file_error(ast->filename, ast->linenum, "Got whitebox attribute with non-constant value!\n");
+ blackbox_module = !n->asBool();
+ }
+
+ if (ast->attributes.count("\\noblackbox")) {
+ if (blackbox_module) {
+ AstNode *n = ast->attributes.at("\\noblackbox");
+ if (n->type != AST_CONSTANT)
+ log_file_error(ast->filename, ast->linenum, "Got noblackbox attribute with non-constant value!\n");
+ blackbox_module = !n->asBool();
+ }
+ delete ast->attributes.at("\\noblackbox");
+ ast->attributes.erase("\\noblackbox");
+ }
+
+ if (blackbox_module)
+ {
+ if (ast->attributes.count("\\whitebox")) {
+ delete ast->attributes.at("\\whitebox");
+ ast->attributes.erase("\\whitebox");
+ }
+
+ if (ast->attributes.count("\\lib_whitebox")) {
+ delete ast->attributes.at("\\lib_whitebox");
+ ast->attributes.erase("\\lib_whitebox");
+ }
+
std::vector<AstNode*> new_children;
for (auto child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
@@ -965,12 +1056,19 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
child->delete_children();
child->children.push_back(AstNode::mkconst_int(0, false, 0));
new_children.push_back(child);
+ } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
+ (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
+ new_children.push_back(child);
} else {
delete child;
}
}
+
ast->children.swap(new_children);
- ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
+
+ if (ast->attributes.count("\\blackbox") == 0) {
+ ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
+ }
}
ignoreThisSignalsInInitial = RTLIL::SigSpec();
@@ -1009,9 +1107,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
current_module->nomeminit = flag_nomeminit;
current_module->nomem2reg = flag_nomem2reg;
current_module->mem2reg = flag_mem2reg;
+ current_module->noblackbox = flag_noblackbox;
current_module->lib = flag_lib;
+ current_module->nowb = flag_nowb;
current_module->noopt = flag_noopt;
current_module->icells = flag_icells;
+ current_module->pwires = flag_pwires;
current_module->autowire = flag_autowire;
current_module->fixup_ports();
@@ -1026,7 +1127,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
// create AstModule instances for all modules in the AST tree and add them to 'design'
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil,
- bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
+ bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
@@ -1039,9 +1140,12 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
+ flag_noblackbox = noblackbox;
flag_lib = lib;
+ flag_nowb = nowb;
flag_noopt = noopt;
flag_icells = icells;
+ flag_pwires = pwires;
flag_autowire = autowire;
log_assert(current_ast->type == AST_DESIGN);
@@ -1373,9 +1477,12 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
+ flag_noblackbox = noblackbox;
flag_lib = lib;
+ flag_nowb = nowb;
flag_noopt = noopt;
flag_icells = icells;
+ flag_pwires = pwires;
flag_autowire = autowire;
use_internal_line_num();
@@ -1447,6 +1554,7 @@ RTLIL::Module *AstModule::clone() const
new_mod->lib = lib;
new_mod->noopt = noopt;
new_mod->icells = icells;
+ new_mod->pwires = pwires;
new_mod->autowire = autowire;
return new_mod;
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index ddd59d4b..54b2fb31 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -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;
+ 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;
@@ -262,6 +263,7 @@ namespace AST
// helper functions for creating AST nodes for constants
static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
+ static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
static AstNode *mkconst_str(const std::vector<RTLIL::State> &v);
static AstNode *mkconst_str(const std::string &str);
@@ -269,6 +271,7 @@ namespace AST
// helper function for creating sign-extended const objects
RTLIL::Const bitsAsConst(int width, bool is_signed);
RTLIL::Const bitsAsConst(int width = -1);
+ RTLIL::Const bitsAsUnsizedConst(int width);
RTLIL::Const asAttrConst();
RTLIL::Const asParaConst();
uint64_t asInt(bool is_signed);
@@ -283,13 +286,13 @@ namespace AST
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,
- bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
+ bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module {
AstNode *ast;
- bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
+ bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire;
~AstModule() YS_OVERRIDE;
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE;
@@ -322,7 +325,7 @@ namespace AST_INTERNAL
{
// internal state variables
extern bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
- extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+ extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_pwires, flag_autowire;
extern AST::AstNode *current_ast, *current_ast_mod;
extern std::map<std::string, AST::AstNode*> current_scope;
extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index b3a2a84b..571ddd98 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -504,6 +504,7 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::CaseRule *backup_case = current_case;
current_case = new RTLIL::CaseRule;
+ current_case->attributes["\\src"] = stringf("%s:%d", child->filename.c_str(), child->linenum);
last_generated_case = current_case;
addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
for (auto node : child->children) {
@@ -645,6 +646,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id_ast->children[0]->range_valid)
log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
+ if (children.size() > 1)
+ range = children[1];
} else
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
if (range) {
@@ -851,7 +854,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_FUNCTION:
case AST_DPI_FUNCTION:
case AST_AUTOWIRE:
- case AST_LOCALPARAM:
case AST_DEFPARAM:
case AST_GENVAR:
case AST_GENFOR:
@@ -893,6 +895,26 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// remember the parameter, needed for example in techmap
case AST_PARAMETER:
current_module->avail_parameters.insert(str);
+ /* fall through */
+ case AST_LOCALPARAM:
+ if (flag_pwires)
+ {
+ if (GetSize(children) < 1 || children[0]->type != AST_CONSTANT)
+ log_file_error(filename, linenum, "Parameter `%s' with non-constant value!\n", str.c_str());
+
+ RTLIL::Const val = children[0]->bitsAsConst();
+ RTLIL::Wire *wire = current_module->addWire(str, GetSize(val));
+ current_module->connect(wire, val);
+
+ wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+ wire->attributes[type == AST_PARAMETER ? "\\parameter" : "\\localparam"] = 1;
+
+ for (auto &attr : attributes) {
+ if (attr.second->type != AST_CONSTANT)
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
+ wire->attributes[attr.first] = attr.second->asAttrConst();
+ }
+ }
break;
// create an RTLIL::Wire for an AST_WIRE node
@@ -902,7 +924,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (!range_valid)
log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", str.c_str());
- log_assert(range_left >= range_right || (range_left == -1 && range_right == 0));
+ if (!(range_left >= range_right || (range_left == -1 && range_right == 0)))
+ log_file_error(filename, linenum, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1);
RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -917,6 +940,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;
@@ -961,8 +987,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
detectSignWidth(width_hint, sign_hint);
is_signed = sign_hint;
- if (type == AST_CONSTANT)
- return RTLIL::SigSpec(bitsAsConst());
+ if (type == AST_CONSTANT) {
+ if (is_unsized) {
+ return RTLIL::SigSpec(bitsAsUnsizedConst(width_hint));
+ } else {
+ return RTLIL::SigSpec(bitsAsConst());
+ }
+ }
RTLIL::SigSpec sig = realAsConst(width_hint);
log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
@@ -1490,10 +1521,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
continue;
}
if (child->type == AST_PARASET) {
+ int extra_const_flags = 0;
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
if (child->children[0]->type == AST_REALVALUE) {
log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n",
log_id(cell), log_id(paraname), child->children[0]->realvalue);
+ extra_const_flags = RTLIL::CONST_FLAG_REAL;
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
strnode->cloneInto(child->children[0]);
delete strnode;
@@ -1502,6 +1535,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n",
log_id(cell), log_id(paraname));
cell->parameters[paraname] = child->children[0]->asParaConst();
+ cell->parameters[paraname].flags |= extra_const_flags;
continue;
}
if (child->type == AST_ARGUMENT) {
@@ -1521,9 +1555,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
+ if (cell->type.in("$specify2", "$specify3")) {
+ int src_width = GetSize(cell->getPort("\\SRC"));
+ int dst_width = GetSize(cell->getPort("\\DST"));
+ bool full = cell->getParam("\\FULL").as_bool();
+ if (!full && src_width != dst_width)
+ log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n");
+ if (cell->type == "$specify3") {
+ int dat_width = GetSize(cell->getPort("\\DAT"));
+ if (dat_width != dst_width)
+ log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n");
+ }
+ cell->setParam("\\SRC_WIDTH", Const(src_width));
+ cell->setParam("\\DST_WIDTH", Const(dst_width));
+ }
+ if (cell->type == "$specrule") {
+ int src_width = GetSize(cell->getPort("\\SRC"));
+ int dst_width = GetSize(cell->getPort("\\DST"));
+ cell->setParam("\\SRC_WIDTH", Const(src_width));
+ cell->setParam("\\DST_WIDTH", Const(dst_width));
+ }
}
break;
@@ -1541,6 +1595,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")
{
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 63b71b80..e947125b 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -1030,7 +1030,26 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n");
if (type == AST_REPEAT)
- log_file_error(filename, linenum, "Repeat loops are only allowed in constant functions!\n");
+ {
+ AstNode *count = children[0];
+ AstNode *body = children[1];
+
+ // eval count expression
+ while (count->simplify(true, false, false, stage, 32, true, false)) { }
+
+ if (count->type != AST_CONSTANT)
+ log_file_error(filename, linenum, "Repeat loops outside must have constant repeat counts!\n");
+
+ // convert to a block with the body repeated n times
+ type = AST_BLOCK;
+ children.clear();
+ for (int i = 0; i < count->bitsAsConst().as_int(); i++)
+ children.insert(children.begin(), body->clone());
+
+ delete count;
+ delete body;
+ did_something = true;
+ }
// unroll for loops and generate-for blocks
if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0)
@@ -1066,7 +1085,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 1st expression
AstNode *varbuf = init_ast->children[1]->clone();
- while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
+ {
+ int expr_width_hint = -1;
+ bool expr_sign_hint = true;
+ varbuf->detectSignWidth(expr_width_hint, expr_sign_hint);
+ while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
+ }
if (varbuf->type != AST_CONSTANT)
log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n");
@@ -1088,7 +1112,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
// eval 2nd expression
AstNode *buf = while_ast->clone();
- while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ {
+ int expr_width_hint = -1;
+ bool expr_sign_hint = true;
+ buf->detectSignWidth(expr_width_hint, expr_sign_hint);
+ while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, false)) { }
+ }
if (buf->type != AST_CONSTANT)
log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n");
@@ -1129,7 +1158,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 3rd expression
buf = next_ast->children[1]->clone();
- while (buf->simplify(true, false, false, stage, 32, true, false)) { }
+ {
+ int expr_width_hint = -1;
+ bool expr_sign_hint = true;
+ buf->detectSignWidth(expr_width_hint, expr_sign_hint);
+ while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, true)) { }
+ }
if (buf->type != AST_CONSTANT)
log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n");
@@ -1138,6 +1172,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
varbuf->children[0] = buf;
}
+ if (type == AST_FOR) {
+ AstNode *buf = next_ast->clone();
+ delete buf->children[1];
+ buf->children[1] = varbuf->children[0]->clone();
+ current_block->children.insert(current_block->children.begin() + current_block_idx++, buf);
+ }
+
current_scope[varbuf->str] = backup_scope_varbuf;
delete varbuf;
delete_children();
@@ -1564,6 +1605,7 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_tmp->str] = wire_tmp;
wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { }
+ wire_tmp->is_logic = true;
AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER);
wire_tmp_id->str = wire_tmp->str;
diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc
index 6b302a79..30d9ff79 100644
--- a/frontends/ilang/ilang_frontend.cc
+++ b/frontends/ilang/ilang_frontend.cc
@@ -47,16 +47,20 @@ struct IlangFrontend : public Frontend {
log(" -nooverwrite\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(" 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(" -overwrite\n");
log(" overwrite existing modules with the same name\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
{
ILANG_FRONTEND::flag_nooverwrite = false;
ILANG_FRONTEND::flag_overwrite = false;
+ ILANG_FRONTEND::flag_lib = false;
log_header(design, "Executing ILANG frontend.\n");
@@ -73,6 +77,10 @@ struct IlangFrontend : public Frontend {
ILANG_FRONTEND::flag_overwrite = true;
continue;
}
+ if (arg == "-lib") {
+ ILANG_FRONTEND::flag_lib = true;
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
diff --git a/frontends/ilang/ilang_frontend.h b/frontends/ilang/ilang_frontend.h
index 052dd4cb..f8a15284 100644
--- a/frontends/ilang/ilang_frontend.h
+++ b/frontends/ilang/ilang_frontend.h
@@ -34,6 +34,7 @@ namespace ILANG_FRONTEND {
extern RTLIL::Design *current_design;
extern bool flag_nooverwrite;
extern bool flag_overwrite;
+ extern bool flag_lib;
}
YOSYS_NAMESPACE_END
diff --git a/frontends/ilang/ilang_lexer.l b/frontends/ilang/ilang_lexer.l
index d8e01ae4..4fd0ae85 100644
--- a/frontends/ilang/ilang_lexer.l
+++ b/frontends/ilang/ilang_lexer.l
@@ -53,6 +53,7 @@ USING_YOSYS_NAMESPACE
"attribute" { return TOK_ATTRIBUTE; }
"parameter" { return TOK_PARAMETER; }
"signed" { return TOK_SIGNED; }
+"real" { return TOK_REAL; }
"wire" { return TOK_WIRE; }
"memory" { return TOK_MEMORY; }
"width" { return TOK_WIDTH; }
diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y
index 5bcc01f4..b4b9693d 100644
--- a/frontends/ilang/ilang_parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -37,7 +37,7 @@ namespace ILANG_FRONTEND {
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
std::vector<RTLIL::CaseRule*> case_stack;
dict<RTLIL::IdString, RTLIL::Const> attrbuf;
- bool flag_nooverwrite, flag_overwrite;
+ bool flag_nooverwrite, flag_overwrite, flag_lib;
bool delete_current_module;
}
using namespace ILANG_FRONTEND;
@@ -45,7 +45,16 @@ YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE
%}
-%name-prefix "rtlil_frontend_ilang_yy"
+%define api.prefix {rtlil_frontend_ilang_yy}
+
+/* The union is defined in the header, so we need to provide all the
+ * includes it requires
+ */
+%code requires {
+#include <string>
+#include <vector>
+#include "frontends/ilang/ilang_frontend.h"
+}
%union {
char *string;
@@ -61,7 +70,7 @@ USING_YOSYS_NAMESPACE
%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
-%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO
+%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO
%type <rsigspec> sigspec_list_reversed
%type <sigspec> sigspec sigspec_list
@@ -98,7 +107,7 @@ module:
delete_current_module = false;
if (current_design->has($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);
delete_current_module = true;
} else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
@@ -124,6 +133,8 @@ module:
current_module->fixup_ports();
if (delete_current_module)
delete current_module;
+ else if (flag_lib)
+ current_module->makeblackbox();
current_module = nullptr;
} EOL;
@@ -239,6 +250,12 @@ cell_body:
free($4);
delete $5;
} |
+ cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL {
+ current_cell->parameters[$4] = *$5;
+ current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL;
+ free($4);
+ delete $5;
+ } |
cell_body TOK_CONNECT TOK_ID sigspec EOL {
if (current_cell->hasPort($3))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
@@ -265,14 +282,14 @@ proc_stmt:
} case_body sync_list TOK_END EOL;
switch_stmt:
- attr_list TOK_SWITCH sigspec EOL {
+ TOK_SWITCH sigspec EOL {
RTLIL::SwitchRule *rule = new RTLIL::SwitchRule;
- rule->signal = *$3;
+ rule->signal = *$2;
rule->attributes = attrbuf;
switch_stack.back()->push_back(rule);
attrbuf.clear();
- delete $3;
- } switch_body TOK_END EOL;
+ delete $2;
+ } attr_list switch_body TOK_END EOL;
attr_list:
/* empty */ |
@@ -281,9 +298,11 @@ attr_list:
switch_body:
switch_body TOK_CASE {
RTLIL::CaseRule *rule = new RTLIL::CaseRule;
+ rule->attributes = attrbuf;
switch_stack.back()->back()->cases.push_back(rule);
switch_stack.push_back(&rule->switches);
case_stack.push_back(rule);
+ attrbuf.clear();
} compare_list EOL case_body {
switch_stack.pop_back();
case_stack.pop_back();
@@ -302,12 +321,15 @@ compare_list:
/* empty */;
case_body:
+ case_body attr_stmt |
case_body switch_stmt |
case_body assign_stmt |
/* empty */;
assign_stmt:
TOK_ASSIGN sigspec sigspec EOL {
+ if (attrbuf.size() != 0)
+ rtlil_frontend_ilang_yyerror("dangling attribute");
case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));
delete $2;
delete $3;
@@ -443,4 +465,3 @@ conn_stmt:
delete $2;
delete $3;
};
-
diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc
index 82361ea9..f5ae8eb7 100644
--- a/frontends/json/jsonparse.cc
+++ b/frontends/json/jsonparse.cc
@@ -292,6 +292,18 @@ void json_import(Design *design, string &modname, JsonNode *node)
if (port_wire == nullptr)
port_wire = module->addWire(port_name, GetSize(port_bits_node->data_array));
+ if (port_node->data_dict.count("upto") != 0) {
+ JsonNode *val = port_node->data_dict.at("upto");
+ if (val->type == 'N')
+ port_wire->upto = val->data_number != 0;
+ }
+
+ if (port_node->data_dict.count("offset") != 0) {
+ JsonNode *val = port_node->data_dict.at("offset");
+ if (val->type == 'N')
+ port_wire->start_offset = val->data_number;
+ }
+
if (port_direction_node->data_string == "input") {
port_wire->port_input = true;
} else
@@ -372,6 +384,18 @@ void json_import(Design *design, string &modname, JsonNode *node)
if (wire == nullptr)
wire = module->addWire(net_name, GetSize(bits_node->data_array));
+ if (net_node->data_dict.count("upto") != 0) {
+ JsonNode *val = net_node->data_dict.at("upto");
+ if (val->type == 'N')
+ wire->upto = val->data_number != 0;
+ }
+
+ if (net_node->data_dict.count("offset") != 0) {
+ JsonNode *val = net_node->data_dict.at("offset");
+ if (val->type == 'N')
+ wire->start_offset = val->data_number;
+ }
+
for (int i = 0; i < GetSize(bits_node->data_array); i++)
{
JsonNode *bitval_node = bits_node->data_array.at(i);
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index ed9727b8..2bf99e58 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -46,7 +46,15 @@ USING_YOSYS_NAMESPACE
#include "VeriModule.h"
#include "VeriWrite.h"
#include "VhdlUnits.h"
-#include "Message.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
@@ -776,13 +784,14 @@ void VerificImporter::merge_past_ffs(pool<RTLIL::Cell*> &candidates)
void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo)
{
- std::string module_name = nl->IsOperator() ? std::string("$verific$") + nl->Owner()->Name() : RTLIL::escape_id(nl->Owner()->Name());
+ std::string netlist_name = nl->GetAtt(" \\top") ? nl->CellBaseName() : nl->Owner()->Name();
+ std::string module_name = nl->IsOperator() ? "$verific$" + netlist_name : RTLIL::escape_id(netlist_name);
netlist = nl;
if (design->has(module_name)) {
if (!nl->IsOperator() && !is_blackbox(nl))
- log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name());
+ log_cmd_error("Re-definition of module `%s'.\n", netlist_name.c_str());
return;
}
@@ -1752,32 +1761,64 @@ struct VerificExtNets
}
};
-void verific_import(Design *design, std::string top)
+void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top)
{
verific_sva_fsm_limit = 16;
std::set<Netlist*> nl_todo, nl_done;
- {
- VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
- VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
+ VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
+ VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
+ Array *netlists = NULL;
+ Array veri_libs, vhdl_libs;
+ if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
+ if (veri_lib) veri_libs.InsertLast(veri_lib);
- Array veri_libs, vhdl_libs;
- if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
- if (veri_lib) veri_libs.InsertLast(veri_lib);
+ Map verific_params(STRING_HASH);
+ for (const auto &i : parameters)
+ verific_params.Insert(i.first.c_str(), i.second.c_str());
- Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
- Netlist *nl;
- int i;
+ if (top.empty()) {
+ netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params);
+ }
+ else {
+ Array veri_modules, vhdl_units;
+
+ if (veri_lib) {
+ VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1);
+ if (veri_module) {
+ veri_modules.InsertLast(veri_module);
+ }
+
+ // Also elaborate all root modules since they may contain bind statements
+ MapIter mi;
+ FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
+ if (!veri_module->IsRootModule()) continue;
+ veri_modules.InsertLast(veri_module);
+ }
+ }
- FOREACH_ARRAY_ITEM(netlists, i, nl) {
- if (top.empty() || nl->Owner()->Name() == top)
- nl_todo.insert(nl);
+ if (vhdl_lib) {
+ VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str());
+ if (vhdl_unit)
+ vhdl_units.InsertLast(vhdl_unit);
}
- delete netlists;
+ netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params);
}
+ Netlist *nl;
+ int i;
+
+ FOREACH_ARRAY_ITEM(netlists, i, nl) {
+ if (top.empty() && nl->CellBaseName() != top)
+ continue;
+ nl->AddAtt(new Att(" \\top", NULL));
+ nl_todo.insert(nl);
+ }
+
+ delete netlists;
+
if (!verific_error_msg.empty())
log_error("%s\n", verific_error_msg.c_str());
@@ -1983,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
@@ -2212,8 +2256,8 @@ struct VerificPass : public Pass {
continue;
}
if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
- const std::string &key = args[++argidx];
- const std::string &value = args[++argidx];
+ 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)
@@ -2270,12 +2314,22 @@ struct VerificPass : public Pass {
for (; argidx < GetSize(args); argidx++)
{
const char *name = args[argidx].c_str();
+ VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1);
+
+ if (veri_lib) {
+ VeriModule *veri_module = veri_lib->GetModule(name, 1);
+ if (veri_module) {
+ log("Adding Verilog module '%s' to elaboration queue.\n", name);
+ veri_modules.InsertLast(veri_module);
+ continue;
+ }
- VeriModule *veri_module = veri_file::GetModule(name);
- if (veri_module) {
- log("Adding Verilog module '%s' to elaboration queue.\n", name);
- veri_modules.InsertLast(veri_module);
- continue;
+ // Also elaborate all root modules since they may contain bind statements
+ MapIter mi;
+ FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
+ if (!veri_module->IsRootModule()) continue;
+ veri_modules.InsertLast(veri_module);
+ }
}
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1);
@@ -2294,8 +2348,10 @@ struct VerificPass : public Pass {
Netlist *nl;
int i;
- FOREACH_ARRAY_ITEM(netlists, i, nl)
+ FOREACH_ARRAY_ITEM(netlists, i, nl) {
+ nl->AddAtt(new Att(" \\top", NULL));
nl_todo.insert(nl);
+ }
delete netlists;
}
diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h
index b331dd4b..88a6cc0b 100644
--- a/frontends/verific/verific.h
+++ b/frontends/verific/verific.h
@@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN
extern int verific_verbose;
extern bool verific_import_pending;
-extern void verific_import(Design *design, std::string top = std::string());
+extern void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top = std::string());
extern pool<int> verific_sva_prims;
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
index dbaace58..6a8462b4 100644
--- a/frontends/verilog/Makefile.inc
+++ b/frontends/verilog/Makefile.inc
@@ -14,6 +14,8 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $<
+frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=10000000
+
OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index 7848c626..f6a17b24 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -71,7 +71,7 @@ static int my_ilog2(int x)
}
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
-static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type)
+static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
{
// all digits in string (MSB at index 0)
std::vector<uint8_t> digits;
@@ -129,6 +129,9 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
return;
}
+ if (is_unsized && (len > len_in_bits))
+ log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len);
+
for (len = len - 1; len >= 0; len--)
if (data[len] == RTLIL::S1)
break;
@@ -150,7 +153,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
if (warn_z) {
AstNode *ret = const2ast(code, case_type);
- if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
+ if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
current_filename.c_str(), get_line_num());
return ret;
@@ -186,7 +189,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
// Simple base-10 integer
if (*endptr == 0) {
std::vector<RTLIL::State> data;
- my_strtobin(data, str, -1, 10, case_type);
+ my_strtobin(data, str, -1, 10, case_type, false);
if (data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
return AstNode::mkconst_bits(data, true);
@@ -201,6 +204,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
std::vector<RTLIL::State> data;
bool is_signed = false;
+ bool is_unsized = len_in_bits < 0;
if (*(endptr+1) == 's') {
is_signed = true;
endptr++;
@@ -209,28 +213,34 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
case 'b':
case 'B':
- my_strtobin(data, endptr+2, len_in_bits, 2, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 2, case_type, is_unsized);
break;
case 'o':
case 'O':
- my_strtobin(data, endptr+2, len_in_bits, 8, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 8, case_type, is_unsized);
break;
case 'd':
case 'D':
- my_strtobin(data, endptr+2, len_in_bits, 10, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 10, case_type, is_unsized);
break;
case 'h':
case 'H':
- my_strtobin(data, endptr+2, len_in_bits, 16, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 16, case_type, is_unsized);
break;
default:
- return NULL;
+ char next_char = char(tolower(*(endptr+1)));
+ if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') {
+ is_unsized = true;
+ my_strtobin(data, endptr+1, 1, 2, case_type, is_unsized);
+ } else {
+ return NULL;
+ }
}
if (len_in_bits < 0) {
if (is_signed && data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
}
- return AstNode::mkconst_bits(data, is_signed);
+ return AstNode::mkconst_bits(data, is_signed, is_unsized);
}
return NULL;
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index 504f8b3f..0e2bead6 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -145,8 +145,21 @@ struct VerilogFrontend : public Frontend {
log(" -nodpi\n");
log(" disable DPI-C support\n");
log("\n");
+ log(" -noblackbox\n");
+ log(" do not automatically add a (* blackbox *) attribute to an\n");
+ log(" empty module.\n");
+ log("\n");
log(" -lib\n");
log(" only create empty blackbox modules. This implies -DBLACKBOX.\n");
+ log(" modules with the (* whitebox *) attribute will be preserved.\n");
+ log(" (* lib_whitebox *) will be treated like (* whitebox *).\n");
+ log("\n");
+ log(" -nowb\n");
+ log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
+ log(" all modules.\n");
+ log("\n");
+ log(" -specify\n");
+ log(" parse and import specify blocks\n");
log("\n");
log(" -noopt\n");
log(" don't perform basic optimizations (such as const folding) in the\n");
@@ -155,6 +168,9 @@ struct VerilogFrontend : public Frontend {
log(" -icells\n");
log(" interpret cell types starting with '$' as internal cell types\n");
log("\n");
+ log(" -pwires\n");
+ log(" add a wire for each module parameter\n");
+ log("\n");
log(" -nooverwrite\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 black box\n");
@@ -215,9 +231,12 @@ struct VerilogFrontend : public Frontend {
bool flag_nodpi = false;
bool flag_noopt = false;
bool flag_icells = false;
+ bool flag_pwires = false;
bool flag_nooverwrite = false;
bool flag_overwrite = false;
bool flag_defer = false;
+ bool flag_noblackbox = false;
+ bool flag_nowb = false;
std::map<std::string, std::string> defines_map;
std::list<std::string> include_dirs;
std::list<std::string> attributes;
@@ -228,10 +247,9 @@ struct VerilogFrontend : public Frontend {
norestrict_mode = false;
assume_asserts_mode = false;
lib_mode = false;
+ specify_mode = false;
default_nettype_wire = true;
- log_header(design, "Executing Verilog-2005 frontend.\n");
-
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
size_t argidx;
@@ -329,11 +347,23 @@ struct VerilogFrontend : public Frontend {
flag_nodpi = true;
continue;
}
+ if (arg == "-noblackbox") {
+ flag_noblackbox = true;
+ continue;
+ }
if (arg == "-lib") {
lib_mode = true;
defines_map["BLACKBOX"] = string();
continue;
}
+ if (arg == "-nowb") {
+ flag_nowb = true;
+ continue;
+ }
+ if (arg == "-specify") {
+ specify_mode = true;
+ continue;
+ }
if (arg == "-noopt") {
flag_noopt = true;
continue;
@@ -342,6 +372,10 @@ struct VerilogFrontend : public Frontend {
flag_icells = true;
continue;
}
+ if (arg == "-pwires") {
+ flag_pwires = true;
+ continue;
+ }
if (arg == "-ignore_redef" || arg == "-nooverwrite") {
flag_nooverwrite = true;
flag_overwrite = false;
@@ -395,6 +429,8 @@ struct VerilogFrontend : public Frontend {
}
extra_args(f, filename, args, argidx);
+ log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str());
+
log("Parsing %s%s input from `%s' to AST representation.\n",
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
@@ -429,7 +465,8 @@ struct VerilogFrontend : public Frontend {
if (flag_nodpi)
error_on_dpi_function(current_ast);
- AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
+ AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
+ flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
index 523bbc89..a7c9b2fe 100644
--- a/frontends/verilog/verilog_frontend.h
+++ b/frontends/verilog/verilog_frontend.h
@@ -72,6 +72,9 @@ namespace VERILOG_FRONTEND
// running in -lib mode
extern bool lib_mode;
+ // running in -specify mode
+ extern bool specify_mode;
+
// lexer input stream
extern std::istream *lexin;
}
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 6ef38252..951d9c66 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -148,7 +148,7 @@ YOSYS_NAMESPACE_END
"endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; }
-"specify" { return TOK_SPECIFY; }
+"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
"endspecify" { return TOK_ENDSPECIFY; }
"specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); }
@@ -193,6 +193,8 @@ YOSYS_NAMESPACE_END
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_$\.] {
+ if (!strcmp(yytext, "default"))
+ return TOK_DEFAULT;
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
return TOK_SVA_LABEL;
}
@@ -206,7 +208,9 @@ YOSYS_NAMESPACE_END
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
+"final" { SV_KEYWORD(TOK_FINAL); }
"logic" { SV_KEYWORD(TOK_LOGIC); }
+"var" { SV_KEYWORD(TOK_VAR); }
"bit" { SV_KEYWORD(TOK_REG); }
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
@@ -216,6 +220,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; }
@@ -230,7 +236,7 @@ YOSYS_NAMESPACE_END
return TOK_CONSTVAL;
}
-[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
+[0-9]*[ \t]*\'s?[bodhBODH]*[ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONSTVAL;
}
@@ -301,6 +307,17 @@ supply1 { return TOK_SUPPLY1; }
return TOK_ID;
}
+"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) {
+ if (!specify_mode) REJECT;
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_ID;
+}
+
+"$"(info|warning|error|fatal) {
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_MSG_TASKS;
+}
+
"$signed" { return TOK_TO_SIGNED; }
"$unsigned" { return TOK_TO_UNSIGNED; }
@@ -411,6 +428,17 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
"+:" { return TOK_POS_INDEXED; }
"-:" { return TOK_NEG_INDEXED; }
+[-+]?[=*]> {
+ if (!specify_mode) REJECT;
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_SPECIFY_OPER;
+}
+
+"&&&" {
+ if (!specify_mode) REJECT;
+ return TOK_SPECIFY_AND;
+}
+
"/*" { BEGIN(COMMENT); }
<COMMENT>. /* ignore comment body */
<COMMENT>\n /* ignore comment body */
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 52685f63..0fec445f 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack;
bool do_not_require_port_stubs;
bool default_nettype_wire;
- bool sv_mode, formal_mode, lib_mode;
+ bool sv_mode, formal_mode, lib_mode, specify_mode;
bool noassert_mode, noassume_mode, norestrict_mode;
bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const;
@@ -94,29 +94,58 @@ static void free_attr(std::map<std::string, AstNode*> *al)
delete al;
}
+struct specify_target {
+ char polarity_op;
+ AstNode *dst, *dat;
+};
+
+struct specify_triple {
+ AstNode *t_min, *t_avg, *t_max;
+};
+
+struct specify_rise_fall {
+ specify_triple rise;
+ specify_triple fall;
+};
+
%}
-%name-prefix "frontend_verilog_yy"
+%define api.prefix {frontend_verilog_yy}
+
+/* The union is defined in the header, so we need to provide all the
+ * includes it requires
+ */
+%code requires {
+#include <map>
+#include <string>
+#include "frontends/verilog/verilog_frontend.h"
+}
%union {
std::string *string;
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
+ struct specify_target *specify_target_ptr;
+ struct specify_triple *specify_triple_ptr;
+ struct specify_rise_fall *specify_rise_fall_ptr;
bool boolean;
+ char ch;
}
-%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 <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
+%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS
+%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
-%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
+%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
+%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
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
-%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM
+%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
+%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
@@ -130,6 +159,12 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr
+%type <specify_target_ptr> specify_target
+%type <specify_triple_ptr> specify_triple
+%type <specify_rise_fall_ptr> specify_rise_fall
+%type <ast> specify_if specify_condition specify_opt_arg
+%type <ch> specify_edge
+
// operator precedence from low to high
%left OP_LOR
%left OP_LAND
@@ -284,15 +319,17 @@ module_para_list:
single_module_para:
/* empty */ |
- TOK_PARAMETER {
+ attr TOK_PARAMETER {
if (astbuf1) delete astbuf1;
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ append_attr(astbuf1, $1);
} param_signed param_integer param_range single_param_decl |
- TOK_LOCALPARAM {
+ attr TOK_LOCALPARAM {
if (astbuf1) delete astbuf1;
astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ append_attr(astbuf1, $1);
} param_signed param_integer param_range single_param_decl |
single_param_decl;
@@ -310,7 +347,13 @@ module_arg_opt_assignment:
if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) {
AstNode *wire = new AstNode(AST_IDENTIFIER);
wire->str = ast_stack.back()->children.back()->str;
- if (ast_stack.back()->children.back()->is_reg)
+ if (ast_stack.back()->children.back()->is_input) {
+ AstNode *n = ast_stack.back()->children.back();
+ if (n->attributes.count("\\defaultvalue"))
+ delete n->attributes.at("\\defaultvalue");
+ n->attributes["\\defaultvalue"] = $2;
+ } else
+ if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic)
ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2))));
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2));
@@ -450,12 +493,21 @@ 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;
} |
TOK_LOGIC {
astbuf3->is_logic = true;
} |
+ TOK_VAR {
+ astbuf3->is_logic = true;
+ } |
TOK_INTEGER {
astbuf3->is_reg = true;
astbuf3->range_left = 31;
@@ -465,6 +517,7 @@ wire_type_token:
TOK_GENVAR {
astbuf3->type = AST_GENVAR;
astbuf3->is_reg = true;
+ astbuf3->is_signed = true;
astbuf3->range_left = 31;
astbuf3->range_right = 0;
} |
@@ -539,7 +592,7 @@ module_body:
module_body_stmt:
task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
- always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl;
+ always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl:
TOK_CHECKER TOK_ID ';' {
@@ -697,15 +750,254 @@ task_func_body:
task_func_body behavioral_stmt |
/* empty */;
+/*************************** specify parser ***************************/
+
specify_block:
- TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY |
- TOK_SPECIFY TOK_ENDSPECIFY ;
+ TOK_SPECIFY specify_item_list TOK_ENDSPECIFY;
-specify_item_opt:
- specify_item_opt specify_item |
- specify_item ;
+specify_item_list:
+ specify_item specify_item_list |
+ /* empty */;
specify_item:
+ specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' {
+ AstNode *en_expr = $1;
+ char specify_edge = $3;
+ AstNode *src_expr = $4;
+ string *oper = $5;
+ specify_target *target = $6;
+ specify_rise_fall *timing = $9;
+
+ if (specify_edge != 0 && target->dat == nullptr)
+ frontend_verilog_yyerror("Found specify edge but no data spec.\n");
+
+ AstNode *cell = new AstNode(AST_CELL);
+ ast_stack.back()->children.push_back(cell);
+ cell->str = stringf("$specify$%d", autoidx++);
+ cell->children.push_back(new AstNode(AST_CELLTYPE));
+ cell->children.back()->str = target->dat ? "$specify3" : "$specify2";
+
+ char oper_polarity = 0;
+ char oper_type = oper->at(0);
+
+ if (oper->size() == 3) {
+ oper_polarity = oper->at(0);
+ oper_type = oper->at(1);
+ }
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1)));
+ cell->children.back()->str = "\\FULL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1)));
+ cell->children.back()->str = "\\SRC_DST_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1)));
+ cell->children.back()->str = "\\SRC_DST_POL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min));
+ cell->children.back()->str = "\\T_RISE_MIN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg));
+ cell->children.back()->str = "\\T_RISE_TYP";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max));
+ cell->children.back()->str = "\\T_RISE_MAX";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min));
+ cell->children.back()->str = "\\T_FALL_MIN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg));
+ cell->children.back()->str = "\\T_FALL_TYP";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max));
+ cell->children.back()->str = "\\T_FALL_MAX";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1)));
+ cell->children.back()->str = "\\EN";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
+ cell->children.back()->str = "\\SRC";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst));
+ cell->children.back()->str = "\\DST";
+
+ if (target->dat)
+ {
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1)));
+ cell->children.back()->str = "\\EDGE_EN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1)));
+ cell->children.back()->str = "\\EDGE_POL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1)));
+ cell->children.back()->str = "\\DAT_DST_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1)));
+ cell->children.back()->str = "\\DAT_DST_POL";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat));
+ cell->children.back()->str = "\\DAT";
+ }
+
+ delete oper;
+ delete target;
+ delete timing;
+ } |
+ TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' {
+ if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&
+ *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")
+ frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
+
+ AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1);
+ AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1);
+ AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1);
+
+ AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1);
+ AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
+ AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
+
+ AstNode *limit = $11;
+ AstNode *limit2 = $12;
+
+ AstNode *cell = new AstNode(AST_CELL);
+ ast_stack.back()->children.push_back(cell);
+ cell->str = stringf("$specify$%d", autoidx++);
+ cell->children.push_back(new AstNode(AST_CELLTYPE));
+ cell->children.back()->str = "$specrule";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1)));
+ cell->children.back()->str = "\\TYPE";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit));
+ cell->children.back()->str = "\\T_LIMIT";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true)));
+ cell->children.back()->str = "\\T_LIMIT2";
+
+ cell->children.push_back(new AstNode(AST_PARASET, src_pen));
+ cell->children.back()->str = "\\SRC_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, src_pol));
+ cell->children.back()->str = "\\SRC_POL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, dst_pen));
+ cell->children.back()->str = "\\DST_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, dst_pol));
+ cell->children.back()->str = "\\DST_POL";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, src_en));
+ cell->children.back()->str = "\\SRC_EN";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
+ cell->children.back()->str = "\\SRC";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en));
+ cell->children.back()->str = "\\DST_EN";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr));
+ cell->children.back()->str = "\\DST";
+
+ delete $1;
+ };
+
+specify_opt_arg:
+ ',' expr {
+ $$ = $2;
+ } |
+ /* empty */ {
+ $$ = nullptr;
+ };
+
+specify_if:
+ TOK_IF '(' expr ')' {
+ $$ = $3;
+ } |
+ /* empty */ {
+ $$ = nullptr;
+ };
+
+specify_condition:
+ TOK_SPECIFY_AND expr {
+ $$ = $2;
+ } |
+ /* empty */ {
+ $$ = nullptr;
+ };
+
+specify_target:
+ expr {
+ $$ = new specify_target;
+ $$->polarity_op = 0;
+ $$->dst = $1;
+ $$->dat = nullptr;
+ } |
+ '(' expr ':' expr ')'{
+ $$ = new specify_target;
+ $$->polarity_op = 0;
+ $$->dst = $2;
+ $$->dat = $4;
+ } |
+ '(' expr TOK_NEG_INDEXED expr ')'{
+ $$ = new specify_target;
+ $$->polarity_op = '-';
+ $$->dst = $2;
+ $$->dat = $4;
+ } |
+ '(' expr TOK_POS_INDEXED expr ')'{
+ $$ = new specify_target;
+ $$->polarity_op = '+';
+ $$->dst = $2;
+ $$->dat = $4;
+ };
+
+specify_edge:
+ TOK_POSEDGE { $$ = 'p'; } |
+ TOK_NEGEDGE { $$ = 'n'; } |
+ { $$ = 0; };
+
+specify_rise_fall:
+ specify_triple {
+ $$ = new specify_rise_fall;
+ $$->rise = *$1;
+ $$->fall.t_min = $1->t_min->clone();
+ $$->fall.t_avg = $1->t_avg->clone();
+ $$->fall.t_max = $1->t_max->clone();
+ delete $1;
+ } |
+ '(' specify_triple ',' specify_triple ')' {
+ $$ = new specify_rise_fall;
+ $$->rise = *$2;
+ $$->fall = *$4;
+ delete $2;
+ delete $4;
+ };
+
+specify_triple:
+ expr {
+ $$ = new specify_triple;
+ $$->t_min = $1;
+ $$->t_avg = $1->clone();
+ $$->t_max = $1->clone();
+ } |
+ expr ':' expr ':' expr {
+ $$ = new specify_triple;
+ $$->t_min = $1;
+ $$->t_avg = $3;
+ $$->t_max = $5;
+ };
+
+/******************** ignored specify parser **************************/
+
+ignored_specify_block:
+ TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY |
+ TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ;
+
+ignored_specify_item_opt:
+ ignored_specify_item_opt ignored_specify_item |
+ ignored_specify_item ;
+
+ignored_specify_item:
specparam_declaration
// | pulsestyle_declaration
// | showcancelled_declaration
@@ -721,21 +1013,16 @@ specparam_declaration:
// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005
// exxxxtending this for SV specparam would change this anyhow
specparam_range:
- '[' constant_expression ':' constant_expression ']' ;
+ '[' ignspec_constant_expression ':' ignspec_constant_expression ']' ;
list_of_specparam_assignments:
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
specparam_assignment:
- TOK_ID '=' constant_mintypmax_expression ;
-
-/*
-pulsestyle_declaration :
- ;
+ ignspec_id '=' constant_mintypmax_expression ;
-showcancelled_declaration :
- ;
-*/
+ignspec_opt_cond:
+ TOK_IF '(' ignspec_expr ')' | /* empty */;
path_declaration :
simple_path_declaration ';'
@@ -744,8 +1031,8 @@ path_declaration :
;
simple_path_declaration :
- parallel_path_description '=' path_delay_value |
- full_path_description '=' path_delay_value
+ ignspec_opt_cond parallel_path_description '=' path_delay_value |
+ ignspec_opt_cond full_path_description '=' path_delay_value
;
path_delay_value :
@@ -755,32 +1042,20 @@ path_delay_value :
;
list_of_path_delay_extra_expressions :
-/*
- t_path_delay_expression
- | trise_path_delay_expression ',' tfall_path_delay_expression
- | trise_path_delay_expression ',' tfall_path_delay_expression ',' tz_path_delay_expression
- | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ','
- tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression
- | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ','
- tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression ','
- t0x_path_delay_expression ',' tx1_path_delay_expression ',' t1x_path_delay_expression ','
- tx0_path_delay_expression ',' txz_path_delay_expression ',' tzx_path_delay_expression
-*/
- ',' path_delay_expression
- | ',' path_delay_expression ',' path_delay_expression
- | ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression
- | ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression
- ;
+ ',' path_delay_expression | ',' path_delay_expression list_of_path_delay_extra_expressions;
+
+specify_edge_identifier :
+ TOK_POSEDGE | TOK_NEGEDGE ;
parallel_path_description :
- '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' ;
+ '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' |
+ '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor opt_polarity_operator ':' ignspec_expr ')' ')' |
+ '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor TOK_POS_INDEXED ignspec_expr ')' ')' ;
full_path_description :
- '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' ;
+ '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' |
+ '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs opt_polarity_operator ':' ignspec_expr ')' ')' |
+ '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs TOK_POS_INDEXED ignspec_expr ')' ')' ;
// This was broken into 2 rules to solve shift/reduce conflicts
list_of_path_inputs :
@@ -802,88 +1077,46 @@ opt_polarity_operator :
// Good enough for the time being
specify_input_terminal_descriptor :
- TOK_ID ;
+ ignspec_id ;
// Good enough for the time being
specify_output_terminal_descriptor :
- TOK_ID ;
+ ignspec_id ;
system_timing_declaration :
- TOK_ID '(' system_timing_args ')' ';' ;
+ ignspec_id '(' system_timing_args ')' ';' ;
system_timing_arg :
- TOK_POSEDGE TOK_ID |
- TOK_NEGEDGE TOK_ID |
- expr ;
+ TOK_POSEDGE ignspec_id |
+ TOK_NEGEDGE ignspec_id |
+ ignspec_expr ;
system_timing_args :
system_timing_arg |
system_timing_args ',' system_timing_arg ;
-/*
-t_path_delay_expression :
- path_delay_expression;
-
-trise_path_delay_expression :
- path_delay_expression;
-
-tfall_path_delay_expression :
- path_delay_expression;
-
-tz_path_delay_expression :
- path_delay_expression;
-
-t01_path_delay_expression :
- path_delay_expression;
-
-t10_path_delay_expression :
- path_delay_expression;
-
-t0z_path_delay_expression :
- path_delay_expression;
-
-tz1_path_delay_expression :
- path_delay_expression;
-
-t1z_path_delay_expression :
- path_delay_expression;
-
-tz0_path_delay_expression :
- path_delay_expression;
-
-t0x_path_delay_expression :
- path_delay_expression;
-
-tx1_path_delay_expression :
- path_delay_expression;
-
-t1x_path_delay_expression :
- path_delay_expression;
-
-tx0_path_delay_expression :
- path_delay_expression;
-
-txz_path_delay_expression :
- path_delay_expression;
-
-tzx_path_delay_expression :
- path_delay_expression;
-*/
-
path_delay_expression :
- constant_expression;
+ ignspec_constant_expression;
constant_mintypmax_expression :
- constant_expression
- | constant_expression ':' constant_expression ':' constant_expression
+ ignspec_constant_expression
+ | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression
;
// for the time being this is OK, but we may write our own expr here.
// as I'm not sure it is legal to use a full expr here (probably not)
// On the other hand, other rules requiring constant expressions also use 'expr'
// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness
-constant_expression:
- expr ;
+ignspec_constant_expression:
+ expr { delete $1; };
+
+ignspec_expr:
+ expr { delete $1; };
+
+ignspec_id:
+ TOK_ID { delete $1; };
+
+/**********************************************************************/
param_signed:
TOK_SIGNED {
@@ -917,17 +1150,19 @@ param_range:
};
param_decl:
- TOK_PARAMETER {
+ attr TOK_PARAMETER {
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ append_attr(astbuf1, $1);
} param_signed param_integer param_real param_range param_decl_list ';' {
delete astbuf1;
};
localparam_decl:
- TOK_LOCALPARAM {
+ attr TOK_LOCALPARAM {
astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ append_attr(astbuf1, $1);
} param_signed param_integer param_real param_range param_decl_list ';' {
delete astbuf1;
};
@@ -1069,7 +1304,12 @@ wire_name_and_opt_assign:
wire_name '=' expr {
AstNode *wire = new AstNode(AST_IDENTIFIER);
wire->str = ast_stack.back()->children.back()->str;
- if (astbuf1->is_reg)
+ if (astbuf1->is_input) {
+ if (astbuf1->attributes.count("\\defaultvalue"))
+ delete astbuf1->attributes.at("\\defaultvalue");
+ astbuf1->attributes["\\defaultvalue"] = $3;
+ } else
+ if (astbuf1->is_reg || astbuf1->is_logic)
ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $3))));
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $3));
@@ -1094,7 +1334,13 @@ wire_name:
node->children.push_back(rng);
}
node->type = AST_MEMORY;
- node->children.push_back($2);
+ auto *rangeNode = $2;
+ if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) {
+ // SV array size [n], rewrite as [n-1:0]
+ rangeNode->children[0] = new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true));
+ rangeNode->children.push_back(AstNode::mkconst_int(0, false));
+ }
+ node->children.push_back(rangeNode);
}
if (current_function_or_task == NULL) {
if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) {
@@ -1241,27 +1487,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:
@@ -1341,6 +1600,9 @@ opt_property:
TOK_PROPERTY {
$$ = true;
} |
+ TOK_FINAL {
+ $$ = false;
+ } |
/* empty */ {
$$ = false;
};
@@ -1574,6 +1836,16 @@ behavioral_stmt:
} opt_arg_list ';'{
ast_stack.pop_back();
} |
+ TOK_MSG_TASKS attr {
+ AstNode *node = new AstNode(AST_TCALL);
+ node->str = *$1;
+ delete $1;
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ append_attr(node, $2);
+ } opt_arg_list ';'{
+ ast_stack.pop_back();
+ } |
attr TOK_BEGIN opt_label {
AstNode *node = new AstNode(AST_BLOCK);
ast_stack.back()->children.push_back(node);
@@ -1869,6 +2141,15 @@ gen_stmt:
if ($6 != NULL)
delete $6;
ast_stack.pop_back();
+ } |
+ TOK_MSG_TASKS {
+ 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:
@@ -2139,4 +2420,3 @@ concat_list:
$$ = $3;
$$->children.push_back($1);
};
-