diff --git a/docs/source/appendix/rtlil_text.rst b/docs/source/appendix/rtlil_text.rst index b1bc9c582..352b1af2e 100644 --- a/docs/source/appendix/rtlil_text.rst +++ b/docs/source/appendix/rtlil_text.rst @@ -63,6 +63,10 @@ significant bit first. Bits may be any of: - ``m``: A marked bit (internal use only) - ``-``: A don't care value +When the bit representation has fewer bits than the width, it is padded to the width with +the most significant explicit bit, or ``0`` if the most significant explicit bit is ``1``, +or ``x`` if there are no explicit bits. + An *integer* is simply a signed integer value in decimal format. **Warning:** Integer constants are limited to 32 bits. That is, they may only be in the range :math:`[-2147483648, 2147483648)`. Integers outside this range will result in an @@ -133,6 +137,7 @@ wires, memories, cells, processes, and connections. ::= * ::= module ::= ( + | | | | @@ -170,6 +175,11 @@ See :ref:`sec:rtlil_sigspec` for an overview of signal specifications. | [ (:)? ] | { * } +When a ```` is specified, the wire must have been previously declared. + +When a signal slice is specified, the left-hand integer must be greather than or +equal to the right-hand integer. + Connections ^^^^^^^^^^^ @@ -268,7 +278,7 @@ may have zero or more attributes. .. code:: BNF ::= * - := * switch + ::= * switch ::= * ::= case ? ::= (, )* @@ -295,3 +305,4 @@ be: | sync always ::= low | high | posedge | negedge | edge ::= update + | * memwr diff --git a/frontends/rtlil/Makefile.inc b/frontends/rtlil/Makefile.inc index d0c0cfcf8..4649507f7 100644 --- a/frontends/rtlil/Makefile.inc +++ b/frontends/rtlil/Makefile.inc @@ -1,19 +1 @@ - -GENFILES += frontends/rtlil/rtlil_parser.tab.cc -GENFILES += frontends/rtlil/rtlil_parser.tab.hh -GENFILES += frontends/rtlil/rtlil_parser.output -GENFILES += frontends/rtlil/rtlil_lexer.cc - -frontends/rtlil/rtlil_parser.tab.cc: frontends/rtlil/rtlil_parser.y - $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -o $@ -d -r all -b frontends/rtlil/rtlil_parser $< - -frontends/rtlil/rtlil_parser.tab.hh: frontends/rtlil/rtlil_parser.tab.cc - -frontends/rtlil/rtlil_lexer.cc: frontends/rtlil/rtlil_lexer.l - $(Q) mkdir -p $(dir $@) - $(P) flex -o frontends/rtlil/rtlil_lexer.cc $< - -OBJS += frontends/rtlil/rtlil_parser.tab.o frontends/rtlil/rtlil_lexer.o OBJS += frontends/rtlil/rtlil_frontend.o - diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index e8d6ac9c9..b54cd8f14 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -17,27 +17,768 @@ * * --- * - * A very simple and straightforward frontend for the RTLIL text - * representation. + * A handwritten recursive-descent parser for the RTLIL text representation. * */ -#include "rtlil_frontend.h" #include "kernel/register.h" #include "kernel/log.h" - -void rtlil_frontend_yyerror(char const *s) -{ - YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_yyget_lineno(), s); -} - -void rtlil_frontend_yywarning(char const *s) -{ - YOSYS_NAMESPACE_PREFIX log_warning("In line %d: %s\n", rtlil_frontend_yyget_lineno(), s); -} +#include "kernel/utils.h" +#include +#include +#include YOSYS_NAMESPACE_BEGIN +struct RTLILFrontendWorker { + // Forbid constants of more than 1 Gb. + // This will help us not explode on malicious RTLIL. + static constexpr int MAX_CONST_WIDTH = 1024 * 1024 * 1024; + + std::istream *f = nullptr; + RTLIL::Design *design; + bool flag_nooverwrite = false; + bool flag_overwrite = false; + bool flag_lib = false; + + int line_num; + std::string line_buf; + // Substring of line_buf. Always newline-terminated, thus never empty. + std::string_view line; + + RTLIL::Module *current_module; + dict attrbuf; + std::vector*> switch_stack; + std::vector case_stack; + + template + [[noreturn]] + void error(FmtString...> fmt, const Args &... args) + { + log_error("Parser error in line %d: %s\n", line_num, fmt.format(args...)); + } + + template + void warning(FmtString...> fmt, const Args &... args) + { + log_warning("In line %d: %s\n", line_num, fmt.format(args...)); + } + + // May return an empty line if the stream is not good(). + void advance_to_next_nonempty_line() + { + if (!f->good()) { + line = "\n"; + return; + } + while (true) { + std::getline(*f, line_buf); + line_num++; + if (line_buf.empty() || line_buf[line_buf.size() - 1] != '\n') + line_buf += '\n'; + line = line_buf; + consume_whitespace_and_comments(); + if (line[0] != '\n' || !f->good()) + break; + } + } + + void consume_whitespace_and_comments() + { + while (true) { + switch (line[0]) { + case ' ': + case '\t': + line = line.substr(1); + break; + case '#': + line = "\n"; + return; + default: + return; + } + } + } + + bool try_parse_keyword(std::string_view keyword) + { + int keyword_size = keyword.size(); + if (keyword != line.substr(0, keyword_size)) + return false; + // This index is safe because `line` is always newline-terminated + // and `keyword` never contains a newline. + char ch = line[keyword_size]; + if (ch >= 'a' && ch <= 'z') + return false; + line = line.substr(keyword_size); + consume_whitespace_and_comments(); + return true; + } + + std::string error_token() + { + std::string result; + for (char ch : line) { + if (ch == '\n' || ch == ' ' || ch == '\t') + break; + result += ch; + } + return result; + } + + void expect_keyword(std::string_view keyword) + { + if (!try_parse_keyword(keyword)) + error("Expected token `%s', got `%s'.", keyword, error_token()); + } + + bool try_parse_char(char ch) + { + if (line[0] != ch) + return false; + line = line.substr(1); + consume_whitespace_and_comments(); + return true; + } + + void expect_char(char ch) + { + if (!try_parse_char(ch)) + error("Expected `%c', got `%s'.", ch, error_token()); + } + + bool try_parse_eol() + { + if (line[0] != '\n') + return false; + advance_to_next_nonempty_line(); + return true; + } + + void expect_eol() + { + if (!try_parse_eol()) + error("Expected EOL, got `%s'.", error_token()); + } + + std::optional try_parse_id() + { + char ch = line[0]; + if (ch != '\\' && ch != '$') + return std::nullopt; + int idx = 1; + while (true) { + ch = line[idx]; + if (ch <= ' ' && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) + break; + ++idx; + } + IdString result(line.substr(0, idx)); + line = line.substr(idx); + consume_whitespace_and_comments(); + return result; + } + + RTLIL::IdString parse_id() + { + std::optional id = try_parse_id(); + if (!id.has_value()) + error("Expected ID, got `%s'.", error_token()); + return std::move(*id); + } + + long long parse_integer() + { + long long result = parse_integer_alone(); + consume_whitespace_and_comments(); + return result; + } + + long long parse_integer_alone() + { + int idx = 0; + if (line[idx] == '-') + ++idx; + while (true) { + char ch = line[idx]; + if (ch < '0' || ch > '9') + break; + ++idx; + } + long long result; + if (std::from_chars(line.data(), line.data() + idx, result, 10).ec != std::errc{}) + error("Invalid integer `%s'.", error_token()); + line = line.substr(idx); + return result; + } + + std::string parse_string() + { + if (line[0] != '\"') + error("Expected string, got `%s'.", error_token()); + std::string str; + int idx = 1; + while (true) { + int start_idx = idx; + char ch; + while (true) { + ch = line[idx]; + if (ch == '"' || ch == '\n' || ch == '\\' || ch == 0) + break; + ++idx; + } + str.append(line.data() + start_idx, line.data() + idx); + ++idx; + if (ch == '"') + break; + if (ch == 0) + error("Null byte in string literal: `%s'.", line); + if (ch == '\n') + error("Unterminated string literal: `%s'.", line); + ch = line[idx++]; + if (ch == 'n') { + ch = '\n'; + } else if (ch == 't') { + ch = '\t'; + } else if (ch >= '0' && ch <= '7') { + int v = ch - '0'; + char next_ch = line[idx + 1]; + if (next_ch >= '0' && next_ch <= '7') { + ++idx; + v = v*8 + (next_ch - '0'); + next_ch = line[idx + 1]; + if (next_ch >= '0' && next_ch <= '7') { + ++idx; + v = v*8 + (next_ch - '0'); + } + } + ch = v; + } + str += ch; + } + line = line.substr(idx); + consume_whitespace_and_comments(); + return str; + } + + RTLIL::Const parse_const() + { + if (line[0] == '"') + return RTLIL::Const(parse_string()); + + bool negative_value = line[0] == '-'; + long long width = parse_integer_alone(); + // Can't test value<0 here because we need to stop parsing after '-0' + if (negative_value || line[0] != '\'') { + if (width < INT_MIN || width > INT_MAX) + error("Integer %lld out of range before `%s'.", width, error_token()); + consume_whitespace_and_comments(); + return RTLIL::Const(width); + } + + int idx = 1; + bool is_signed = line[1] == 's'; + if (is_signed) + ++idx; + + std::vector bits; + if (width > MAX_CONST_WIDTH) + error("Constant width %lld out of range before `%s`.", width, error_token()); + bits.reserve(width); + while (true) { + RTLIL::State bit; + switch (line[idx]) { + case '0': bit = RTLIL::S0; break; + case '1': bit = RTLIL::S1; break; + case 'x': bit = RTLIL::Sx; break; + case 'z': bit = RTLIL::Sz; break; + case 'm': bit = RTLIL::Sm; break; + case '-': bit = RTLIL::Sa; break; + default: goto done; + } + bits.push_back(bit); + ++idx; + } + done: + std::reverse(bits.begin(), bits.end()); + + if (GetSize(bits) > width) + bits.resize(width); + else if (GetSize(bits) < width) { + RTLIL::State extbit = RTLIL::Sx; + if (!bits.empty()) { + extbit = bits.back(); + if (extbit == RTLIL::S1) + extbit = RTLIL::S0; + } + bits.resize(width, extbit); + } + + RTLIL::Const val(std::move(bits)); + if (is_signed) + val.flags |= RTLIL::CONST_FLAG_SIGNED; + line = line.substr(idx); + consume_whitespace_and_comments(); + return val; + } + + RTLIL::SigSpec parse_sigspec() + { + if (try_parse_char('{')) { + std::vector parts; + while (!try_parse_char('}')) + parts.push_back(parse_sigspec()); + RTLIL::SigSpec sig; + for (auto it = parts.rbegin(); it != parts.rend(); ++it) + sig.append(std::move(*it)); + return sig; + } + + RTLIL::SigSpec sig; + + // We could add a special path for parsing IdStrings that must already exist, + // as here. + // We don't need to addref/release in this case. + std::optional id = try_parse_id(); + if (id.has_value()) { + RTLIL::Wire *wire = current_module->wire(*id); + if (wire == nullptr) + error("Wire `%s' not found.", *id); + sig = RTLIL::SigSpec(wire); + } else { + sig = RTLIL::SigSpec(parse_const()); + } + + while (try_parse_char('[')) { + int left = parse_integer(); + if (left >= sig.size() || left < 0) + error("bit index %d out of range", left); + if (try_parse_char(':')) { + int right = parse_integer(); + if (right < 0) + error("bit index %d out of range", right); + if (left < right) + error("invalid slice [%d:%d]", left, right); + sig = sig.extract(right, left-right+1); + } else { + sig = sig.extract(left); + } + expect_char(']'); + } + + return sig; + } + + void parse_module() + { + RTLIL::IdString module_name = parse_id(); + expect_eol(); + + bool delete_current_module = false; + if (design->has(module_name)) { + RTLIL::Module *existing_mod = design->module(module_name); + if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::blackbox).as_bool()))) { + log("Ignoring blackbox re-definition of module %s.\n", module_name); + delete_current_module = true; + } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) { + error("RTLIL error: redefinition of module %s.", module_name); + } else if (flag_nooverwrite) { + log("Ignoring re-definition of module %s.\n", module_name); + delete_current_module = true; + } else { + log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", module_name); + design->remove(existing_mod); + } + } + + current_module = new RTLIL::Module; + current_module->name = std::move(module_name); + current_module->attributes = std::move(attrbuf); + if (!delete_current_module) + design->add(current_module); + + while (true) + { + if (try_parse_keyword("attribute")) { + parse_attribute(); + continue; + } + if (try_parse_keyword("parameter")) { + parse_parameter(); + continue; + } + if (try_parse_keyword("connect")) { + parse_connect(); + continue; + } + if (try_parse_keyword("wire")) { + parse_wire(); + continue; + } + if (try_parse_keyword("cell")) { + parse_cell(); + continue; + } + if (try_parse_keyword("memory")) { + parse_memory(); + continue; + } + if (try_parse_keyword("process")) { + parse_process(); + continue; + } + if (try_parse_keyword("end")) { + expect_eol(); + break; + } + error("Unexpected token in module body: %s", error_token()); + } + + if (attrbuf.size() != 0) + error("dangling attribute"); + current_module->fixup_ports(); + if (delete_current_module) + delete current_module; + else if (flag_lib) + current_module->makeblackbox(); + current_module = nullptr; + } + + void parse_attribute() + { + RTLIL::IdString id = parse_id(); + RTLIL::Const c = parse_const(); + attrbuf.insert({std::move(id), std::move(c)}); + expect_eol(); + } + + void parse_parameter() + { + RTLIL::IdString id = parse_id(); + current_module->avail_parameters(id); + if (try_parse_eol()) + return; + RTLIL::Const c = parse_const(); + current_module->parameter_default_values.insert({std::move(id), std::move(c)}); + expect_eol(); + } + + void parse_wire() + { + RTLIL::Wire *wire; + int width = 1; + int start_offset = 0; + int port_id = 0; + bool port_input = false; + bool port_output = false; + bool upto = false; + bool is_signed = false; + + while (true) + { + std::optional id = try_parse_id(); + if (id.has_value()) { + if (current_module->wire(*id) != nullptr) + error("RTLIL error: redefinition of wire %s.", *id); + wire = current_module->addWire(std::move(*id)); + break; + } + if (try_parse_keyword("width")) + width = parse_integer(); + else if (try_parse_keyword("upto")) + upto = true; + else if (try_parse_keyword("signed")) + is_signed = true; + else if (try_parse_keyword("offset")) + start_offset = parse_integer(); + else if (try_parse_keyword("input")) { + port_id = parse_integer(); + port_input = true; + } else if (try_parse_keyword("output")) { + port_id = parse_integer(); + port_output = true; + } else if (try_parse_keyword("inout")) { + port_id = parse_integer(); + port_input = true; + port_output = true; + } else if (try_parse_eol()) + error("Missing wire ID"); + else + error("Unexpected wire option: %s", error_token()); + } + + wire->attributes = std::move(attrbuf); + wire->width = width; + wire->upto = upto; + wire->start_offset = start_offset; + wire->is_signed = is_signed; + wire->port_id = port_id; + wire->port_input = port_input; + wire->port_output = port_output; + expect_eol(); + } + + void parse_memory() + { + RTLIL::Memory *memory = new RTLIL::Memory; + memory->attributes = std::move(attrbuf); + + int width = 1; + int start_offset = 0; + int size = 0; + while (true) + { + std::optional id = try_parse_id(); + if (id.has_value()) { + if (current_module->memories.count(*id) != 0) + error("RTLIL error: redefinition of memory %s.", *id); + memory->name = std::move(*id); + break; + } + if (try_parse_keyword("width")) + width = parse_integer(); + else if (try_parse_keyword("size")) + size = parse_integer(); + else if (try_parse_keyword("offset")) + start_offset = parse_integer(); + else if (try_parse_eol()) + error("Missing memory ID"); + else + error("Unexpected memory option: %s", error_token()); + } + memory->width = width; + memory->start_offset = start_offset; + memory->size = size; + current_module->memories.insert({memory->name, memory}); + expect_eol(); + } + + void parse_cell() + { + RTLIL::IdString cell_type = parse_id(); + RTLIL::IdString cell_name = parse_id(); + expect_eol(); + + if (current_module->cell(cell_name) != nullptr) + error("RTLIL error: redefinition of cell %s.", cell_name); + RTLIL::Cell *cell = current_module->addCell(cell_name, cell_type); + cell->attributes = std::move(attrbuf); + + while (true) + { + if (try_parse_keyword("parameter")) { + bool is_signed = false; + bool is_real = false; + if (try_parse_keyword("signed")) { + is_signed = true; + } else if (try_parse_keyword("real")) { + is_real = true; + } + RTLIL::IdString param_name = parse_id(); + RTLIL::Const val = parse_const(); + if (is_signed) + val.flags |= RTLIL::CONST_FLAG_SIGNED; + if (is_real) + val.flags |= RTLIL::CONST_FLAG_REAL; + cell->parameters.insert({std::move(param_name), std::move(val)}); + expect_eol(); + } else if (try_parse_keyword("connect")) { + RTLIL::IdString port_name = parse_id(); + if (cell->hasPort(port_name)) + error("RTLIL error: redefinition of cell port %s.", port_name); + cell->setPort(std::move(port_name), parse_sigspec()); + expect_eol(); + } else if (try_parse_keyword("end")) { + expect_eol(); + break; + } else { + error("Unexpected token in cell body: %s", error_token()); + } + } + } + + void parse_connect() + { + if (attrbuf.size() != 0) + error("dangling attribute"); + RTLIL::SigSpec s1 = parse_sigspec(); + RTLIL::SigSpec s2 = parse_sigspec(); + current_module->connect(std::move(s1), std::move(s2)); + expect_eol(); + } + + void parse_case_body(RTLIL::CaseRule *current_case) + { + while (true) + { + if (try_parse_keyword("attribute")) + parse_attribute(); + else if (try_parse_keyword("switch")) + parse_switch(); + else if (try_parse_keyword("assign")) { + if (attrbuf.size() != 0) + error("dangling attribute"); + // See https://github.com/YosysHQ/yosys/pull/4765 for discussion on this + // warning + if (!switch_stack.back()->empty()) + warning("case rule assign statements after switch statements may cause unexpected behaviour. " + "The assign statement is reordered to come before all switch statements."); + RTLIL::SigSpec s1 = parse_sigspec(); + RTLIL::SigSpec s2 = parse_sigspec(); + current_case->actions.push_back(RTLIL::SigSig(std::move(s1), std::move(s2))); + expect_eol(); + } else + return; + } + } + + void parse_switch() + { + RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; + rule->signal = parse_sigspec(); + rule->attributes = std::move(attrbuf); + switch_stack.back()->push_back(rule); + expect_eol(); + + while (true) { + if (try_parse_keyword("attribute")) { + parse_attribute(); + continue; + } + + if (try_parse_keyword("end")) { + expect_eol(); + break; + } + + expect_keyword("case"); + RTLIL::CaseRule *case_rule = new RTLIL::CaseRule; + case_rule->attributes = std::move(attrbuf); + rule->cases.push_back(case_rule); + switch_stack.push_back(&case_rule->switches); + case_stack.push_back(case_rule); + + if (!try_parse_eol()) { + while (true) { + case_rule->compare.push_back(parse_sigspec()); + if (try_parse_eol()) + break; + expect_char(','); + } + } + + parse_case_body(case_rule); + + switch_stack.pop_back(); + case_stack.pop_back(); + } + } + + void parse_process() + { + RTLIL::IdString proc_name = parse_id(); + expect_eol(); + + if (current_module->processes.count(proc_name) != 0) + error("RTLIL error: redefinition of process %s.", proc_name); + RTLIL::Process *proc = current_module->addProcess(std::move(proc_name)); + proc->attributes = std::move(attrbuf); + + switch_stack.clear(); + switch_stack.push_back(&proc->root_case.switches); + case_stack.clear(); + case_stack.push_back(&proc->root_case); + + parse_case_body(&proc->root_case); + + while (try_parse_keyword("sync")) + { + RTLIL::SyncRule *rule = new RTLIL::SyncRule; + + if (try_parse_keyword("low")) rule->type = RTLIL::ST0; + else if (try_parse_keyword("high")) rule->type = RTLIL::ST1; + else if (try_parse_keyword("posedge")) rule->type = RTLIL::STp; + else if (try_parse_keyword("negedge")) rule->type = RTLIL::STn; + else if (try_parse_keyword("edge")) rule->type = RTLIL::STe; + else if (try_parse_keyword("always")) rule->type = RTLIL::STa; + else if (try_parse_keyword("global")) rule->type = RTLIL::STg; + else if (try_parse_keyword("init")) rule->type = RTLIL::STi; + else error("Unexpected sync type: %s", error_token()); + + if (rule->type != RTLIL::STa && rule->type != RTLIL::STg && rule->type != RTLIL::STi) + rule->signal = parse_sigspec(); + proc->syncs.push_back(rule); + expect_eol(); + + bool attributes_in_update_list = false; + while (true) + { + if (try_parse_keyword("update")) { + RTLIL::SigSpec s1 = parse_sigspec(); + RTLIL::SigSpec s2 = parse_sigspec(); + rule->actions.push_back(RTLIL::SigSig(std::move(s1), std::move(s2))); + expect_eol(); + continue; + } + + if (try_parse_keyword("attribute")) { + attributes_in_update_list = true; + parse_attribute(); + continue; + } + + if (!try_parse_keyword("memwr")) + break; + + RTLIL::MemWriteAction act; + act.attributes = std::move(attrbuf); + act.memid = parse_id(); + act.address = parse_sigspec(); + act.data = parse_sigspec(); + act.enable = parse_sigspec(); + act.priority_mask = parse_const(); + rule->mem_write_actions.push_back(std::move(act)); + expect_eol(); + } + // The old parser allowed dangling attributes before a "sync" to carry through + // the "sync", so we will too, for now. + if (attributes_in_update_list && attrbuf.size() > 0) + error("dangling attribute"); + } + + expect_keyword("end"); + expect_eol(); + } + + RTLILFrontendWorker(RTLIL::Design *design) : design(design) {} + + void parse(std::istream *f) + { + this->f = f; + line_num = 0; + advance_to_next_nonempty_line(); + while (f->good()) + { + if (try_parse_keyword("attribute")) { + parse_attribute(); + continue; + } + if (try_parse_keyword("module")) { + parse_module(); + continue; + } + if (try_parse_keyword("autoidx")) { + autoidx = std::max(autoidx, parse_integer()); + expect_eol(); + continue; + } + error("Unexpected token: %s", error_token()); + } + if (attrbuf.size() != 0) + error("dangling attribute"); + } +}; + struct RTLILFrontend : public Frontend { RTLILFrontend() : Frontend("rtlil", "read modules from RTLIL file") { } void help() override @@ -63,9 +804,7 @@ struct RTLILFrontend : public Frontend { } void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) override { - RTLIL_FRONTEND::flag_nooverwrite = false; - RTLIL_FRONTEND::flag_overwrite = false; - RTLIL_FRONTEND::flag_lib = false; + RTLILFrontendWorker worker(design); log_header(design, "Executing RTLIL frontend.\n"); @@ -73,17 +812,17 @@ struct RTLILFrontend : public Frontend { for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-nooverwrite") { - RTLIL_FRONTEND::flag_nooverwrite = true; - RTLIL_FRONTEND::flag_overwrite = false; + worker.flag_nooverwrite = true; + worker.flag_overwrite = false; continue; } if (arg == "-overwrite") { - RTLIL_FRONTEND::flag_nooverwrite = false; - RTLIL_FRONTEND::flag_overwrite = true; + worker.flag_nooverwrite = false; + worker.flag_overwrite = true; continue; } if (arg == "-lib") { - RTLIL_FRONTEND::flag_lib = true; + worker.flag_lib = true; continue; } break; @@ -92,14 +831,8 @@ struct RTLILFrontend : public Frontend { log("Input filename: %s\n", filename); - RTLIL_FRONTEND::lexin = f; - RTLIL_FRONTEND::current_design = design; - rtlil_frontend_yydebug = false; - rtlil_frontend_yyrestart(NULL); - rtlil_frontend_yyparse(); - rtlil_frontend_yylex_destroy(); + worker.parse(f); } } RTLILFrontend; YOSYS_NAMESPACE_END - diff --git a/frontends/rtlil/rtlil_frontend.h b/frontends/rtlil/rtlil_frontend.h deleted file mode 100644 index 31cfb80b4..000000000 --- a/frontends/rtlil/rtlil_frontend.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation. - * - */ - -#ifndef RTLIL_FRONTEND_H -#define RTLIL_FRONTEND_H - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -namespace RTLIL_FRONTEND { - extern std::istream *lexin; - extern RTLIL::Design *current_design; - extern bool flag_nooverwrite; - extern bool flag_overwrite; - extern bool flag_lib; -} - -YOSYS_NAMESPACE_END - -extern int rtlil_frontend_yydebug; -int rtlil_frontend_yylex(void); -void rtlil_frontend_yyerror(char const *s); -void rtlil_frontend_yywarning(char const *s); -void rtlil_frontend_yyrestart(FILE *f); -int rtlil_frontend_yyparse(void); -int rtlil_frontend_yylex_destroy(void); -int rtlil_frontend_yyget_lineno(void); - -#endif - diff --git a/frontends/rtlil/rtlil_lexer.l b/frontends/rtlil/rtlil_lexer.l deleted file mode 100644 index c374dd395..000000000 --- a/frontends/rtlil/rtlil_lexer.l +++ /dev/null @@ -1,150 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation. - * - */ - -%{ - -#ifdef __clang__ -// bison generates code using the 'register' storage class specifier -#pragma clang diagnostic ignored "-Wdeprecated-register" -#endif - -#include -#include "frontends/rtlil/rtlil_frontend.h" -#include "rtlil_parser.tab.hh" - -USING_YOSYS_NAMESPACE - -#define YY_INPUT(buf,result,max_size) \ - result = readsome(*RTLIL_FRONTEND::lexin, buf, max_size) - -%} - -%option yylineno -%option noyywrap -%option nounput -%option prefix="rtlil_frontend_yy" - -%x STRING - -%% - -"autoidx" { return TOK_AUTOIDX; } -"module" { return TOK_MODULE; } -"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; } -"upto" { return TOK_UPTO; } -"offset" { return TOK_OFFSET; } -"size" { return TOK_SIZE; } -"input" { return TOK_INPUT; } -"output" { return TOK_OUTPUT; } -"inout" { return TOK_INOUT; } -"cell" { return TOK_CELL; } -"connect" { return TOK_CONNECT; } -"switch" { return TOK_SWITCH; } -"case" { return TOK_CASE; } -"assign" { return TOK_ASSIGN; } -"sync" { return TOK_SYNC; } -"low" { return TOK_LOW; } -"high" { return TOK_HIGH; } -"posedge" { return TOK_POSEDGE; } -"negedge" { return TOK_NEGEDGE; } -"edge" { return TOK_EDGE; } -"always" { return TOK_ALWAYS; } -"global" { return TOK_GLOBAL; } -"init" { return TOK_INIT; } -"update" { return TOK_UPDATE; } -"memwr" { return TOK_MEMWR; } -"process" { return TOK_PROCESS; } -"end" { return TOK_END; } - -[a-z]+ { return TOK_INVALID; } - -"\\"[^ \t\r\n]+ { rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } -"$"[^ \t\r\n]+ { rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } - -[0-9]+'s?[01xzm-]* { rtlil_frontend_yylval.string = strdup(yytext); return TOK_VALUE; } --?[0-9]+ { - char *end = nullptr; - errno = 0; - long value = strtol(yytext, &end, 10); - log_assert(end == yytext + strlen(yytext)); - if (errno == ERANGE) - return TOK_INVALID; // literal out of range of long - if (value < INT_MIN || value > INT_MAX) - return TOK_INVALID; // literal out of range of int (relevant mostly for LP64 platforms) - rtlil_frontend_yylval.integer = value; - return TOK_INT; -} - -\" { BEGIN(STRING); } -\\. { yymore(); } -\" { - BEGIN(0); - char *yystr = strdup(yytext); - yystr[strlen(yytext) - 1] = 0; - int i = 0, j = 0; - while (yystr[i]) { - if (yystr[i] == '\\' && yystr[i + 1]) { - i++; - if (yystr[i] == 'n') - yystr[i] = '\n'; - else if (yystr[i] == 't') - yystr[i] = '\t'; - else if ('0' <= yystr[i] && yystr[i] <= '7') { - yystr[i] = yystr[i] - '0'; - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - } - } - yystr[j++] = yystr[i++]; - } - yystr[j] = 0; - rtlil_frontend_yylval.string = yystr; - return TOK_STRING; -} -. { yymore(); } - -"#"[^\n]* /* ignore comments */ -[ \t] /* ignore non-newline whitespaces */ -[\r\n]+ { return TOK_EOL; } - -. { return *yytext; } - -%% - -// this is a hack to avoid the 'yyinput defined but not used' error msgs -void *rtlil_frontend_avoid_input_warnings() { - return (void*)&yyinput; -} diff --git a/frontends/rtlil/rtlil_parser.y b/frontends/rtlil/rtlil_parser.y deleted file mode 100644 index 2b8d7b7ab..000000000 --- a/frontends/rtlil/rtlil_parser.y +++ /dev/null @@ -1,525 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation. - * - */ - -%require "3.0" - -%{ -#include -#include "frontends/rtlil/rtlil_frontend.h" -YOSYS_NAMESPACE_BEGIN -namespace RTLIL_FRONTEND { - std::istream *lexin; - RTLIL::Design *current_design; - RTLIL::Module *current_module; - RTLIL::Wire *current_wire; - RTLIL::Memory *current_memory; - RTLIL::Cell *current_cell; - RTLIL::Process *current_process; - std::vector*> switch_stack; - std::vector case_stack; - dict attrbuf; - bool flag_nooverwrite, flag_overwrite, flag_lib; - bool delete_current_module; -} -using namespace RTLIL_FRONTEND; -YOSYS_NAMESPACE_END -USING_YOSYS_NAMESPACE -%} - -%define api.prefix {rtlil_frontend_yy} - -/* The union is defined in the header, so we need to provide all the - * includes it requires - */ -%code requires { -#include -#include -#include "frontends/rtlil/rtlil_frontend.h" -} - -%union { - char *string; - int integer; - YOSYS_NAMESPACE_PREFIX RTLIL::Const *data; - YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec; - std::vector *rsigspec; -} - -%token TOK_ID TOK_VALUE TOK_STRING -%token TOK_INT -%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT -%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_MEMWR TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET -%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO - -%type sigspec_list_reversed -%type sigspec sigspec_list -%type sync_type -%type constant - -%expect 0 -%debug - -%% - -input: - optional_eol { - attrbuf.clear(); - } design { - if (attrbuf.size() != 0) - rtlil_frontend_yyerror("dangling attribute"); - }; - -EOL: - optional_eol TOK_EOL; - -optional_eol: - optional_eol TOK_EOL | /* empty */; - -design: - design module | - design attr_stmt | - design autoidx_stmt | - /* empty */; - -module: - TOK_MODULE TOK_ID EOL { - delete_current_module = false; - if (current_design->has($2)) { - RTLIL::Module *existing_mod = current_design->module($2); - if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::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(ID::blackbox)) { - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of module %s.", $2).c_str()); - } else if (flag_nooverwrite) { - log("Ignoring re-definition of module %s.\n", $2); - delete_current_module = true; - } else { - log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", $2); - current_design->remove(existing_mod); - } - } - current_module = new RTLIL::Module; - current_module->name = $2; - current_module->attributes = attrbuf; - if (!delete_current_module) - current_design->add(current_module); - attrbuf.clear(); - free($2); - } module_body TOK_END { - if (attrbuf.size() != 0) - rtlil_frontend_yyerror("dangling attribute"); - current_module->fixup_ports(); - if (delete_current_module) - delete current_module; - else if (flag_lib) - current_module->makeblackbox(); - current_module = nullptr; - } EOL; - -module_body: - module_body module_stmt | - /* empty */; - -module_stmt: - param_stmt | param_defval_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; - -param_stmt: - TOK_PARAMETER TOK_ID EOL { - current_module->avail_parameters($2); - free($2); - }; - -param_defval_stmt: - TOK_PARAMETER TOK_ID constant EOL { - current_module->avail_parameters($2); - current_module->parameter_default_values[$2] = *$3; - delete $3; - free($2); - }; - -attr_stmt: - TOK_ATTRIBUTE TOK_ID constant EOL { - attrbuf[$2] = *$3; - delete $3; - free($2); - }; - -autoidx_stmt: - TOK_AUTOIDX TOK_INT EOL { - autoidx = max(autoidx, $2); - }; - -wire_stmt: - TOK_WIRE { - current_wire = current_module->addWire("$__rtlil_frontend_tmp__"); - current_wire->attributes = attrbuf; - attrbuf.clear(); - } wire_options TOK_ID EOL { - if (current_module->wire($4) != nullptr) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of wire %s.", $4).c_str()); - current_module->rename(current_wire, $4); - free($4); - }; - -wire_options: - wire_options TOK_WIDTH TOK_INT { - current_wire->width = $3; - } | - wire_options TOK_WIDTH TOK_INVALID { - rtlil_frontend_yyerror("RTLIL error: invalid wire width"); - } | - wire_options TOK_UPTO { - current_wire->upto = true; - } | - wire_options TOK_SIGNED { - current_wire->is_signed = true; - } | - wire_options TOK_OFFSET TOK_INT { - current_wire->start_offset = $3; - } | - wire_options TOK_INPUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = true; - current_wire->port_output = false; - } | - wire_options TOK_OUTPUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = false; - current_wire->port_output = true; - } | - wire_options TOK_INOUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = true; - current_wire->port_output = true; - } | - /* empty */; - -memory_stmt: - TOK_MEMORY { - current_memory = new RTLIL::Memory; - current_memory->attributes = attrbuf; - attrbuf.clear(); - } memory_options TOK_ID EOL { - if (current_module->memories.count($4) != 0) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of memory %s.", $4).c_str()); - current_memory->name = $4; - current_module->memories[$4] = current_memory; - free($4); - }; - -memory_options: - memory_options TOK_WIDTH TOK_INT { - current_memory->width = $3; - } | - memory_options TOK_SIZE TOK_INT { - current_memory->size = $3; - } | - memory_options TOK_OFFSET TOK_INT { - current_memory->start_offset = $3; - } | - /* empty */; - -cell_stmt: - TOK_CELL TOK_ID TOK_ID EOL { - if (current_module->cell($3) != nullptr) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell %s.", $3).c_str()); - current_cell = current_module->addCell($3, $2); - current_cell->attributes = attrbuf; - attrbuf.clear(); - free($2); - free($3); - } cell_body TOK_END EOL; - -cell_body: - cell_body TOK_PARAMETER TOK_ID constant EOL { - current_cell->parameters[$3] = *$4; - free($3); - delete $4; - } | - cell_body TOK_PARAMETER TOK_SIGNED TOK_ID constant EOL { - current_cell->parameters[$4] = *$5; - current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_SIGNED; - 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_yyerror(stringf("RTLIL error: redefinition of cell port %s.", $3).c_str()); - current_cell->setPort($3, *$4); - delete $4; - free($3); - } | - /* empty */; - -proc_stmt: - TOK_PROCESS TOK_ID EOL { - if (current_module->processes.count($2) != 0) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of process %s.", $2).c_str()); - current_process = current_module->addProcess($2); - current_process->attributes = attrbuf; - switch_stack.clear(); - switch_stack.push_back(¤t_process->root_case.switches); - case_stack.clear(); - case_stack.push_back(¤t_process->root_case); - attrbuf.clear(); - free($2); - } case_body sync_list TOK_END EOL; - -switch_stmt: - TOK_SWITCH sigspec EOL { - RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; - rule->signal = *$2; - rule->attributes = attrbuf; - switch_stack.back()->push_back(rule); - attrbuf.clear(); - delete $2; - } attr_list switch_body TOK_END EOL; - -attr_list: - /* empty */ | - attr_list attr_stmt; - -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(); - } | - /* empty */; - -compare_list: - sigspec { - case_stack.back()->compare.push_back(*$1); - delete $1; - } | - compare_list ',' sigspec { - case_stack.back()->compare.push_back(*$3); - delete $3; - } | - /* 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_yyerror("dangling attribute"); - - // See https://github.com/YosysHQ/yosys/pull/4765 for discussion on this - // warning - if (!switch_stack.back()->empty()) { - rtlil_frontend_yywarning( - "case rule assign statements after switch statements may cause unexpected behaviour. " - "The assign statement is reordered to come before all switch statements." - ); - } - - case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3)); - delete $2; - delete $3; - }; - -sync_list: - sync_list TOK_SYNC sync_type sigspec EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType($3); - rule->signal = *$4; - current_process->syncs.push_back(rule); - delete $4; - } update_list | - sync_list TOK_SYNC TOK_ALWAYS EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STa; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - sync_list TOK_SYNC TOK_GLOBAL EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STg; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - sync_list TOK_SYNC TOK_INIT EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STi; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - /* empty */; - -sync_type: - TOK_LOW { $$ = RTLIL::ST0; } | - TOK_HIGH { $$ = RTLIL::ST1; } | - TOK_POSEDGE { $$ = RTLIL::STp; } | - TOK_NEGEDGE { $$ = RTLIL::STn; } | - TOK_EDGE { $$ = RTLIL::STe; }; - -update_list: - update_list TOK_UPDATE sigspec sigspec EOL { - current_process->syncs.back()->actions.push_back(RTLIL::SigSig(*$3, *$4)); - delete $3; - delete $4; - } | - update_list attr_list TOK_MEMWR TOK_ID sigspec sigspec sigspec constant EOL { - RTLIL::MemWriteAction act; - act.attributes = attrbuf; - act.memid = $4; - act.address = *$5; - act.data = *$6; - act.enable = *$7; - act.priority_mask = *$8; - current_process->syncs.back()->mem_write_actions.push_back(std::move(act)); - attrbuf.clear(); - free($4); - delete $5; - delete $6; - delete $7; - delete $8; - } | - /* empty */; - -constant: - TOK_VALUE { - char *ep; - int width = strtol($1, &ep, 10); - bool is_signed = false; - if (*ep == '\'') { - ep++; - } - if (*ep == 's') { - is_signed = true; - ep++; - } - std::list bits; - while (*ep != 0) { - RTLIL::State bit = RTLIL::Sx; - switch (*ep) { - case '0': bit = RTLIL::S0; break; - case '1': bit = RTLIL::S1; break; - case 'x': bit = RTLIL::Sx; break; - case 'z': bit = RTLIL::Sz; break; - case '-': bit = RTLIL::Sa; break; - case 'm': bit = RTLIL::Sm; break; - } - bits.push_front(bit); - ep++; - } - - if (bits.size() == 0) - bits.push_back(RTLIL::Sx); - while ((int)bits.size() < width) { - RTLIL::State bit = bits.back(); - if (bit == RTLIL::S1) - bit = RTLIL::S0; - bits.push_back(bit); - } - while ((int)bits.size() > width) - bits.pop_back(); - RTLIL::Const::Builder builder(bits.size()); - for (RTLIL::State bit : bits) - builder.push_back(bit); - $$ = new RTLIL::Const(builder.build()); - if (is_signed) { - $$->flags |= RTLIL::CONST_FLAG_SIGNED; - } - free($1); - } | - TOK_INT { - $$ = new RTLIL::Const($1); - } | - TOK_STRING { - $$ = new RTLIL::Const($1); - free($1); - }; - -sigspec: - constant { - $$ = new RTLIL::SigSpec(*$1); - delete $1; - } | - TOK_ID { - if (current_module->wire($1) == nullptr) - rtlil_frontend_yyerror(stringf("RTLIL error: wire %s not found", $1).c_str()); - $$ = new RTLIL::SigSpec(current_module->wire($1)); - free($1); - } | - sigspec '[' TOK_INT ']' { - if ($3 >= $1->size() || $3 < 0) - rtlil_frontend_yyerror("bit index out of range"); - $$ = new RTLIL::SigSpec($1->extract($3)); - delete $1; - } | - sigspec '[' TOK_INT ':' TOK_INT ']' { - if ($3 >= $1->size() || $3 < 0 || $3 < $5) - rtlil_frontend_yyerror("invalid slice"); - $$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1)); - delete $1; - } | - '{' sigspec_list '}' { - $$ = $2; - }; - -sigspec_list_reversed: - sigspec_list_reversed sigspec { - $$->push_back(*$2); - delete $2; - } | - /* empty */ { - $$ = new std::vector; - }; - -sigspec_list: sigspec_list_reversed { - $$ = new RTLIL::SigSpec; - for (auto it = $1->rbegin(); it != $1->rend(); it++) - $$->append(*it); - delete $1; - }; - -conn_stmt: - TOK_CONNECT sigspec sigspec EOL { - if (attrbuf.size() != 0) - rtlil_frontend_yyerror("dangling attribute"); - current_module->connect(*$2, *$3); - delete $2; - delete $3; - }; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a594d2da3..aa4743a87 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -264,10 +264,10 @@ std::string& Const::get_str() { return *get_if_str(); } -RTLIL::Const::Const(const std::string &str) +RTLIL::Const::Const(std::string str) { flags = RTLIL::CONST_FLAG_STRING; - new ((void*)&str_) std::string(str); + new ((void*)&str_) std::string(std::move(str)); tag = backing_tag::string; } @@ -3050,7 +3050,7 @@ void RTLIL::Module::fixup_ports() RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, int width) { RTLIL::Wire *wire = new RTLIL::Wire; - wire->name = name; + wire->name = std::move(name); wire->width = width; add(wire); return wire; @@ -3058,7 +3058,7 @@ RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, int width) RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, const RTLIL::Wire *other) { - RTLIL::Wire *wire = addWire(name); + RTLIL::Wire *wire = addWire(std::move(name)); wire->width = other->width; wire->start_offset = other->start_offset; wire->port_id = other->port_id; @@ -3073,7 +3073,7 @@ RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, const RTLIL::Wire *oth RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, RTLIL::IdString type) { RTLIL::Cell *cell = new RTLIL::Cell; - cell->name = name; + cell->name = std::move(name); cell->type = type; add(cell); return cell; @@ -3081,7 +3081,7 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, RTLIL::IdString type) RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *other) { - RTLIL::Cell *cell = addCell(name, other->type); + RTLIL::Cell *cell = addCell(std::move(name), other->type); cell->connections_ = other->connections_; cell->parameters = other->parameters; cell->attributes = other->attributes; @@ -3091,7 +3091,7 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memory *other) { RTLIL::Memory *mem = new RTLIL::Memory; - mem->name = name; + mem->name = std::move(name); mem->width = other->width; mem->start_offset = other->start_offset; mem->size = other->size; @@ -3103,7 +3103,7 @@ RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memor RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name) { RTLIL::Process *proc = new RTLIL::Process; - proc->name = name; + proc->name = std::move(name); add(proc); return proc; } @@ -3111,7 +3111,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name) RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Process *other) { RTLIL::Process *proc = other->clone(); - proc->name = name; + proc->name = std::move(name); add(proc); return proc; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 01f8abdb2..394c6f25d 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -209,10 +209,15 @@ struct RTLIL::IdString } static int get_reference(const char *p) + { + return get_reference(std::string_view(p)); + } + + static int get_reference(std::string_view p) { log_assert(destruct_guard_ok); - auto it = global_id_index_.find((char*)p); + auto it = global_id_index_.find(p); if (it != global_id_index_.end()) { #ifndef YOSYS_NO_IDS_REFCNT global_refcount_storage_.at(it->second)++; @@ -226,14 +231,13 @@ struct RTLIL::IdString ensure_prepopulated(); - if (!p[0]) + if (p.empty()) return 0; log_assert(p[0] == '$' || p[0] == '\\'); - log_assert(p[1] != 0); - for (const char *c = p; *c; c++) - if ((unsigned)*c <= (unsigned)' ') - log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p); + for (char ch : p) + if ((unsigned)ch <= (unsigned)' ') + log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", ch, std::string(p).c_str()); #ifndef YOSYS_NO_IDS_REFCNT if (global_free_idx_list_.empty()) { @@ -245,8 +249,11 @@ struct RTLIL::IdString int idx = global_free_idx_list_.back(); global_free_idx_list_.pop_back(); - global_id_storage_.at(idx) = strdup(p); - global_id_index_[global_id_storage_.at(idx)] = idx; + char* buf = static_cast(malloc(p.size() + 1)); + memcpy(buf, p.data(), p.size()); + buf[p.size()] = 0; + global_id_storage_.at(idx) = buf; + global_id_index_.insert(it, {std::string_view(buf, p.size()), idx}); global_refcount_storage_.at(idx)++; #else int idx = global_id_storage_.size(); @@ -255,7 +262,7 @@ struct RTLIL::IdString #endif if (yosys_xtrace) { - log("#X# New IdString '%s' with index %d.\n", p, idx); + log("#X# New IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx); log_backtrace("-X- ", yosys_xtrace-1); } @@ -322,7 +329,8 @@ struct RTLIL::IdString inline IdString(const char *str) : index_(get_reference(str)) { } inline IdString(const IdString &str) : index_(get_reference(str.index_)) { } inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; } - inline IdString(const std::string &str) : index_(get_reference(str.c_str())) { } + inline IdString(const std::string &str) : index_(get_reference(std::string_view(str))) { } + inline IdString(std::string_view str) : index_(get_reference(str)) { } inline IdString(StaticId id) : index_(static_cast(id)) {} inline ~IdString() { put_reference(index_); } @@ -331,6 +339,12 @@ struct RTLIL::IdString index_ = get_reference(rhs.index_); } + inline void operator=(IdString &&rhs) { + put_reference(index_); + index_ = rhs.index_; + rhs.index_ = 0; + } + inline void operator=(const char *rhs) { IdString id(rhs); *this = id; @@ -859,7 +873,7 @@ private: public: Const() : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(std::vector()) {} - Const(const std::string &str); + Const(std::string str); Const(long long val); // default width is 32 Const(long long val, int width); Const(RTLIL::State bit, int width = 1);