diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 997740a7c..1cef7be60 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -28,12 +28,71 @@ #include "kernel/ff.h" #include "kernel/mem.h" #include "kernel/fmt.h" +#include "backends/verilog/verilog_backend.h" #include #include #include #include USING_YOSYS_NAMESPACE + +using namespace VERILOG_BACKEND; + +const pool VERILOG_BACKEND::verilog_keywords() { + static const pool res = { + // IEEE 1800-2017 Annex B + "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before", + "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle", + "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint", + "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker", + "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage", + "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually", + "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function", + "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies", + "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface", + "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint", + "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor", + "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive", + "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent", + "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat", + "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until", + "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify", + "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on", + "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1", + "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with", + "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while", + "wildcard", "wire", "with", "within", "wor", "xnor", "xor", + }; + return res; +} + +bool VERILOG_BACKEND::char_is_verilog_escaped(char c) { + if ('0' <= c && c <= '9') + return false; + if ('a' <= c && c <= 'z') + return false; + if ('A' <= c && c <= 'Z') + return false; + if (c == '_') + return false; + + return true; +} + +bool VERILOG_BACKEND::id_is_verilog_escaped(const std::string &str) { + if ('0' <= str[0] && str[0] <= '9') + return true; + + for (int i = 0; str[i]; i++) + if (char_is_verilog_escaped(str[i])) + return true; + + if (verilog_keywords().count(str)) + return true; + + return false; +} + PRIVATE_NAMESPACE_BEGIN bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, extmem, defparam, decimal, siminit, systemverilog, simple_lhs, noparallelcase; @@ -105,7 +164,6 @@ std::string next_auto_id() std::string id(RTLIL::IdString internal_id, bool may_rename = true) { const char *str = internal_id.c_str(); - bool do_escape = false; if (may_rename && auto_name_map.count(internal_id) != 0) return stringf("%s_%0*d_", auto_prefix.c_str(), auto_name_digits, auto_name_offset + auto_name_map[internal_id]); @@ -113,51 +171,7 @@ std::string id(RTLIL::IdString internal_id, bool may_rename = true) if (*str == '\\') str++; - if ('0' <= *str && *str <= '9') - do_escape = true; - - for (int i = 0; str[i]; i++) - { - if ('0' <= str[i] && str[i] <= '9') - continue; - if ('a' <= str[i] && str[i] <= 'z') - continue; - if ('A' <= str[i] && str[i] <= 'Z') - continue; - if (str[i] == '_') - continue; - do_escape = true; - break; - } - - static const pool keywords = { - // IEEE 1800-2017 Annex B - "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before", - "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle", - "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint", - "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker", - "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage", - "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually", - "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function", - "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies", - "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface", - "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint", - "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor", - "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive", - "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent", - "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat", - "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until", - "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify", - "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on", - "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1", - "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with", - "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while", - "wildcard", "wire", "with", "within", "wor", "xnor", "xor", - }; - if (keywords.count(str)) - do_escape = true; - - if (do_escape) + if (id_is_verilog_escaped(str)) return "\\" + std::string(str) + " "; return std::string(str); } diff --git a/backends/verilog/verilog_backend.h b/backends/verilog/verilog_backend.h new file mode 100644 index 000000000..7e550a37c --- /dev/null +++ b/backends/verilog/verilog_backend.h @@ -0,0 +1,39 @@ +/* + * 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 simple and straightforward Verilog backend. + * + */ + +#ifndef VERILOG_BACKEND_H +#define VERILOG_BACKEND_H + +#include + +YOSYS_NAMESPACE_BEGIN +namespace VERILOG_BACKEND { + + const pool verilog_keywords(); + bool char_is_verilog_escaped(char c); + bool id_is_verilog_escaped(const std::string &str); + +}; /* namespace VERILOG_BACKEND */ +YOSYS_NAMESPACE_END + +#endif /* VERILOG_BACKEND_H */ diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index fe8b4a444..e0586ec7e 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -20,6 +20,7 @@ #include "kernel/register.h" #include "kernel/rtlil.h" #include "kernel/log.h" +#include "backends/verilog/verilog_backend.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -186,6 +187,26 @@ static bool rename_witness(RTLIL::Design *design, dict &ca return has_witness_signals; } +static std::string renamed_unescaped(const std::string& str) +{ + std::string new_str = ""; + + if ('0' <= str[0] && str[0] <= '9') + new_str = '_' + new_str; + + for (char c : str) { + if (VERILOG_BACKEND::char_is_verilog_escaped(c)) + new_str += '_'; + else + new_str += c; + } + + if (VERILOG_BACKEND::verilog_keywords().count(str)) + new_str += "_"; + + return new_str; +} + struct RenamePass : public Pass { RenamePass() : Pass("rename", "rename object in the design") { } void help() override @@ -252,6 +273,12 @@ struct RenamePass : public Pass { log("can be used to change the random number generator seed from the default, but it\n"); log("must be non-zero.\n"); log("\n"); + log("\n"); + log(" rename -unescape [selection]\n"); + log("\n"); + log("Rename all selected public wires and cells that have to be escaped in Verilog.\n"); + log("Replaces characters with underscores or adds additional underscores and numbers.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { @@ -265,6 +292,7 @@ struct RenamePass : public Pass { bool flag_top = false; bool flag_output = false; bool flag_scramble_name = false; + bool flag_unescape = false; bool got_mode = false; unsigned int seed = 1; @@ -312,6 +340,11 @@ struct RenamePass : public Pass { got_mode = true; continue; } + if (arg == "-unescape" && !got_mode) { + flag_unescape = true; + got_mode = true; + continue; + } if (arg == "-pattern" && argidx+1 < args.size() && args[argidx+1].find('%') != std::string::npos) { int pos = args[++argidx].find('%'); pattern_prefix = args[argidx].substr(0, pos); @@ -491,6 +524,48 @@ struct RenamePass : public Pass { module->rename(it.first, it.second); } } + else if (flag_unescape) + { + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + dict new_wire_names; + dict new_cell_names; + + for (auto wire : module->selected_wires()) { + auto name = wire->name.str(); + if (name[0] != '\\') + continue; + name = name.substr(1); + if (!VERILOG_BACKEND::id_is_verilog_escaped(name)) + continue; + new_wire_names[wire] = module->uniquify("\\" + renamed_unescaped(name)); + auto new_name = new_wire_names[wire].str().substr(1); + if (VERILOG_BACKEND::id_is_verilog_escaped(new_name)) + log_error("Failed to rename wire %s -> %s\n", name.c_str(), new_name.c_str()); + } + + for (auto cell : module->selected_cells()) { + auto name = cell->name.str(); + if (name[0] != '\\') + continue; + name = name.substr(1); + if (!VERILOG_BACKEND::id_is_verilog_escaped(name)) + continue; + new_cell_names[cell] = module->uniquify("\\" + renamed_unescaped(name)); + auto new_name = new_cell_names[cell].str().substr(1); + if (VERILOG_BACKEND::id_is_verilog_escaped(new_name)) + log_error("Failed to rename cell %s -> %s\n", name.c_str(), new_name.c_str()); + } + + for (auto &it : new_wire_names) + module->rename(it.first, it.second); + + for (auto &it : new_cell_names) + module->rename(it.first, it.second); + } + } else { if (argidx+2 != args.size()) diff --git a/tests/various/rename_unescape.ys b/tests/various/rename_unescape.ys new file mode 100644 index 000000000..546d97357 --- /dev/null +++ b/tests/various/rename_unescape.ys @@ -0,0 +1,41 @@ +read_verilog <