Bug fix in $mem verilog backend + changed tests/bram flow of make test.
[yosys.git] / backends / verilog / verilog_backend.cc
index 99430d04904511ff7d51ee80db47abd56394a750..c6a8792da1a6d41655b6463f299196a8abb30e2c 100644 (file)
@@ -29,6 +29,7 @@
 #include "kernel/register.h"
 #include "kernel/celltypes.h"
 #include "kernel/log.h"
+#include "kernel/sigtools.h"
 #include <string>
 #include <sstream>
 #include <set>
@@ -37,7 +38,7 @@
 USING_YOSYS_NAMESPACE
 PRIVATE_NAMESPACE_BEGIN
 
-bool norename, noattr, attr2comment, noexpr;
+bool norename, noattr, attr2comment, noexpr, nomem;
 int auto_name_counter, auto_name_offset, auto_name_digits;
 std::map<RTLIL::IdString, int> auto_name_map;
 std::set<RTLIL::IdString> reg_wires, reg_ct;
@@ -51,16 +52,17 @@ void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
        if (*str == '$' && may_rename && !norename)
                auto_name_map[id] = auto_name_counter++;
 
-       if (str[0] != '_' && str[1] != 0)
+       if (str[0] != '\\' || str[1] != '_' || str[2] == 0)
                return;
-       for (int i = 0; str[i] != 0; i++) {
-               if (str[i] == '_')
+
+       for (int i = 2; str[i] != 0; i++) {
+               if (str[i] == '_' && str[i+1] == 0)
                        continue;
                if (str[i] < '0' || str[i] > '9')
                        return;
        }
 
-       int num = atoi(str+1);
+       int num = atoi(str+2);
        if (num >= auto_name_offset)
                auto_name_offset = num + 1;
 }
@@ -73,35 +75,37 @@ void reset_auto_counter(RTLIL::Module *module)
 
        reset_auto_counter_id(module->name, false);
 
-       for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
+       for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
                reset_auto_counter_id(it->second->name, true);
 
-       for (auto it = module->cells_.begin(); it != module->cells_.end(); it++) {
+       for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it) {
                reset_auto_counter_id(it->second->name, true);
                reset_auto_counter_id(it->second->type, false);
        }
 
-       for (auto it = module->processes.begin(); it != module->processes.end(); it++)
+       for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
                reset_auto_counter_id(it->second->name, false);
 
        auto_name_digits = 1;
        for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10)
                auto_name_digits++;
 
-       for (auto it = auto_name_map.begin(); it != auto_name_map.end(); it++)
+       for (auto it = auto_name_map.begin(); it != auto_name_map.end(); ++it)
                log("  renaming `%s' to `_%0*d_'.\n", it->first.c_str(), auto_name_digits, auto_name_offset + it->second);
 }
 
+std::string next_auto_id()
+{
+       return stringf("_%0*d_", auto_name_digits, auto_name_offset + auto_name_counter++);
+}
+
 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) {
-               char buffer[100];
-               snprintf(buffer, 100, "_%0*d_", auto_name_digits, auto_name_offset + auto_name_map[internal_id]);
-               return std::string(buffer);
-       }
+       if (may_rename && auto_name_map.count(internal_id) != 0)
+               return stringf("_%0*d_", auto_name_digits, auto_name_offset + auto_name_map[internal_id]);
 
        if (*str == '\\')
                str++;
@@ -150,7 +154,7 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
        return true;
 }
 
-void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false)
+void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false)
 {
        if (width < 0)
                width = data.bits.size() - offset;
@@ -166,7 +170,7 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
                                if (data.bits[i] == RTLIL::S1)
                                        val |= 1 << (i - offset);
                        }
-                       f << stringf("32'%sd%d", set_signed ? "s" : "", val);
+                       f << stringf("32'%sd %d", set_signed ? "s" : "", val);
                } else {
        dump_bits:
                        f << stringf("%d'%sb", width, set_signed ? "s" : "");
@@ -198,6 +202,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
                                f << stringf("\\\"");
                        else if (str[i] == '\\')
                                f << stringf("\\\\");
+                       else if (str[i] == '/' && escape_comment && i > 0 && str[i-1] == '*')
+                               f << stringf("\\/");
                        else
                                f << str[i];
                }
@@ -236,7 +242,7 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
                dump_sigchunk(f, sig.as_chunk());
        } else {
                f << stringf("{ ");
-               for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); it++) {
+               for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
                        if (it != sig.chunks().rbegin())
                                f << stringf(", ");
                        dump_sigchunk(f, *it, true);
@@ -245,14 +251,19 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
        }
 }
 
-void dump_attributes(std::ostream &f, std::string indent, std::map<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n')
+void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false)
 {
        if (noattr)
                return;
-       for (auto it = attributes.begin(); it != attributes.end(); it++) {
+       for (auto it = attributes.begin(); it != attributes.end(); ++it) {
                f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
                f << stringf(" = ");
-               dump_const(f, it->second);
+               if (modattr && (it->second == Const(0, 1) || it->second == Const(0)))
+                       f << stringf(" 0 ");
+               else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
+                       f << stringf(" 1 ");
+               else
+                       dump_const(f, it->second, -1, 0, false, false, attr2comment);
                f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
        }
 }
@@ -287,9 +298,14 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
                f << stringf("%s" "output%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
        if (wire->port_input && wire->port_output)
                f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
-       if (reg_wires.count(wire->name))
+       if (reg_wires.count(wire->name)) {
                f << stringf("%s" "reg%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
-       else if (!wire->port_input && !wire->port_output)
+               if (wire->attributes.count("\\init")) {
+                       f << stringf("%s" "initial %s = ", indent.c_str(), id(wire->name).c_str());
+                       dump_const(f, wire->attributes.at("\\init"));
+                       f << stringf(";\n");
+               }
+       } else if (!wire->port_input && !wire->port_output)
                f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
 #endif
 }
@@ -315,7 +331,7 @@ std::string cellname(RTLIL::Cell *cell)
        if (!norename && cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q"))
        {
                RTLIL::SigSpec sig = cell->getPort("\\Q");
-               if (SIZE(sig) != 1 || sig.is_fully_const())
+               if (GetSize(sig) != 1 || sig.is_fully_const())
                        goto no_special_reg_name;
 
                RTLIL::Wire *wire = sig[0].wire;
@@ -663,10 +679,60 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                return true;
        }
 
-       if (cell->type == "$dff" || cell->type == "$adff")
+       if (cell->type == "$dffsr")
+       {
+               SigSpec sig_clk = cell->getPort("\\CLK");
+               SigSpec sig_set = cell->getPort("\\SET");
+               SigSpec sig_clr = cell->getPort("\\CLR");
+               SigSpec sig_d = cell->getPort("\\D");
+               SigSpec sig_q = cell->getPort("\\Q");
+
+               int width = cell->parameters["\\WIDTH"].as_int();
+               bool pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
+               bool pol_set = cell->parameters["\\SET_POLARITY"].as_bool();
+               bool pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool();
+
+               std::string reg_name = cellname(cell);
+               bool out_is_reg_wire = is_reg_wire(sig_q, reg_name);
+
+               if (!out_is_reg_wire)
+                       f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), width-1, reg_name.c_str());
+
+               for (int i = 0; i < width; i++) {
+                       f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
+                       dump_sigspec(f, sig_clk);
+                       f << stringf(", %sedge ", pol_set ? "pos" : "neg");
+                       dump_sigspec(f, sig_set);
+                       f << stringf(", %sedge ", pol_clr ? "pos" : "neg");
+                       dump_sigspec(f, sig_clr);
+                       f << stringf(")\n");
+
+                       f << stringf("%s" "  if (%s", indent.c_str(), pol_clr ? "" : "!");
+                       dump_sigspec(f, sig_clr);
+                       f << stringf(") %s[%d] <= 1'b0;\n", reg_name.c_str(), i);
+
+                       f << stringf("%s" "  else if (%s", indent.c_str(), pol_set ? "" : "!");
+                       dump_sigspec(f, sig_set);
+                       f << stringf(") %s[%d] <= 1'b1;\n", reg_name.c_str(), i);
+
+                       f << stringf("%s" "  else  %s[%d] <= ", indent.c_str(), reg_name.c_str(), i);
+                       dump_sigspec(f, sig_d[i]);
+                       f << stringf(";\n");
+               }
+
+               if (!out_is_reg_wire) {
+                       f << stringf("%s" "assign ", indent.c_str());
+                       dump_sigspec(f, sig_q);
+                       f << stringf(" = %s;\n", reg_name.c_str());
+               }
+
+               return true;
+       }
+
+       if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe")
        {
-               RTLIL::SigSpec sig_clk, sig_arst, val_arst;
-               bool pol_clk, pol_arst = false;
+               RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst;
+               bool pol_clk, pol_arst = false, pol_en = false;
 
                sig_clk = cell->getPort("\\CLK");
                pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
@@ -677,6 +743,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                        val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
                }
 
+               if (cell->type == "$dffe") {
+                       sig_en = cell->getPort("\\EN");
+                       pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
+               }
+
                std::string reg_name = cellname(cell);
                bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
 
@@ -701,6 +772,12 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                        f << stringf("%s" "  else\n", indent.c_str());
                }
 
+               if (cell->type == "$dffe") {
+                       f << stringf("%s" "  if (%s", indent.c_str(), pol_en ? "" : "!");
+                       dump_sigspec(f, sig_en);
+                       f << stringf(")\n");
+               }
+
                f << stringf("%s" "    %s <= ", indent.c_str(), reg_name.c_str());
                dump_cell_expr_port(f, cell, "D", false);
                f << stringf(";\n");
@@ -714,8 +791,166 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                return true;
        }
 
+       if (cell->type == "$mem" && nomem == false)
+       {
+               RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string();
+               std::string mem_id = id(cell->parameters["\\MEMID"].decode_string());
+               int abits = cell->parameters["\\ABITS"].as_int();
+               int size = cell->parameters["\\SIZE"].as_int();
+               int width = cell->parameters["\\WIDTH"].as_int();
+               bool use_init = !(RTLIL::SigSpec(cell->parameters["\\INIT"]).is_fully_undef());
+
+               // for memory block make something like:
+               //  reg [7:0] memid [3:0];
+               //  initial begin
+               //    memid[0] <= ...
+               //  end
+               int mem_val;
+               f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size-1, 0);
+               if (use_init)
+               {
+                       f << stringf("%s" "initial begin\n", indent.c_str());
+                       for (int i=0; i<size; i++)
+                       {
+                               mem_val = cell->parameters["\\INIT"].extract(i*width, width).as_int();
+                               f << stringf("%s" "  %s[%d] <= %d'd%d;\n", indent.c_str(), mem_id.c_str(), i, width, mem_val);
+                       }
+                       f << stringf("%s" "end\n", indent.c_str());
+               }
+
+               int nread_ports = cell->parameters["\\RD_PORTS"].as_int();
+               RTLIL::SigSpec sig_rd_clk, sig_rd_data, sig_rd_addr;
+               bool use_rd_clk, rd_clk_posedge, rd_transparent;
+               // read ports
+               for (int i=0; i < nread_ports; i++)
+               {
+                       sig_rd_clk = cell->getPort("\\RD_CLK").extract(i);
+                       sig_rd_data = cell->getPort("\\RD_DATA").extract(i*width, width);
+                       sig_rd_addr = cell->getPort("\\RD_ADDR").extract(i*abits, abits);
+                       use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool();
+                       rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool();
+                       rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool();
+                       if (use_rd_clk && !rd_transparent)
+                       {
+                               // for clocked read ports make something like:
+                               //   reg [..] temp_id;
+                               //   always @(posedge clk)
+                               //      temp_id <= array_reg[r_addr];
+                               //   assign r_data = temp_id;
+                               std::string temp_id = next_auto_id();
+                               f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), sig_rd_data.size() - 1, temp_id.c_str());
+                               f << stringf("%s" "always @(%sedge ", indent.c_str(), rd_clk_posedge ? "pos" : "neg");
+                               dump_sigspec(f, sig_rd_clk);
+                               f << stringf(")\n");
+                               f << stringf("%s" "  %s <= %s[", indent.c_str(), temp_id.c_str(), mem_id.c_str());
+                               dump_sigspec(f, sig_rd_addr);
+                               f << stringf("];\n");
+                               f << stringf("%s" "assign ", indent.c_str());
+                               dump_sigspec(f, sig_rd_data);
+                               f << stringf(" = %s;\n", temp_id.c_str());
+                       } else {
+                               if (rd_transparent) {
+                                       // for rd-transparent read-ports make something like:
+                                       //   reg [..] temp_id;
+                                       //   always @(posedge clk)
+                                       //     temp_id <= r_addr;
+                                       //   assign r_data = array_reg[temp_id];
+                                       std::string temp_id = next_auto_id();
+                                       f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), sig_rd_addr.size() - 1, temp_id.c_str());
+                                       f << stringf("%s" "always @(%sedge ", indent.c_str(), rd_clk_posedge ? "pos" : "neg");
+                                       dump_sigspec(f, sig_rd_clk);
+                                       f << stringf(")\n");
+                                       f << stringf("%s" "  %s <= ", indent.c_str(), temp_id.c_str());
+                                       dump_sigspec(f, sig_rd_addr);
+                                       f << stringf(";\n");
+                                       f << stringf("%s" "assign ", indent.c_str());
+                                       dump_sigspec(f, sig_rd_data);
+                                       f << stringf(" = %s[%s];\n", mem_id.c_str(), temp_id.c_str());
+                               } else {
+                                       // for non-clocked read-ports make something like:
+                                       //   assign r_data = array_reg[r_addr];
+                                       f << stringf("%s" "assign ", indent.c_str());
+                                       dump_sigspec(f, sig_rd_data);
+                                       f << stringf(" = %s[", mem_id.c_str());
+                                       dump_sigspec(f, sig_rd_addr);
+                                       f << stringf("];\n");
+                               }
+                       }
+               }
+
+               int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int();
+               RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en, sig_wr_en_bit;
+               RTLIL::SigBit last_bit;
+               bool wr_clk_posedge;
+               RTLIL::SigSpec lof_wen;
+               dict<RTLIL::SigSpec, int> wen_to_width;
+               SigMap sigmap(active_module);
+               int n, wen_width;
+               // write ports
+               for (int i=0; i < nwrite_ports; i++)
+               {
+                       // for write-ports make something like:
+                       //   always @(posedge clk)
+                       //      if (wr_en)
+                       //         memid[w_addr] <= w_data;
+                       sig_wr_clk = cell->getPort("\\WR_CLK").extract(i);
+                       sig_wr_data = cell->getPort("\\WR_DATA").extract(i*width, width);
+                       sig_wr_addr = cell->getPort("\\WR_ADDR").extract(i*abits, abits);
+                       sig_wr_en = cell->getPort("\\WR_EN").extract(i*width, width);
+                       sig_wr_en_bit = sig_wr_en.extract(0);
+                       wr_clk_posedge = cell->parameters["\\WR_CLK_POLARITY"].extract(i).as_bool();
+                       // group the wen bits
+                       last_bit = sig_wr_en.extract(0);
+                       lof_wen = RTLIL::SigSpec(last_bit);
+                       wen_to_width.clear();
+                       wen_to_width[last_bit] = 0;
+                       for (auto &current_bit : sig_wr_en.bits())
+                       {
+                               if (sigmap(current_bit) == sigmap(last_bit)){
+                                       wen_to_width[current_bit] += 1;
+                               } else {
+                                       lof_wen.append_bit(current_bit);
+                                       wen_to_width[current_bit] = 1;
+                               }
+                               last_bit = current_bit;
+                       }
+                       //   make something like:
+                       //   always @(posedge clk)
+                       //      if (wr_en_bit)
+                       //         memid[w_addr][??] <= w_data[??];
+                       //   ...
+                       n = 0;
+                       for (auto &wen_bit : lof_wen) {
+                               wen_width = wen_to_width[wen_bit];
+                               if (!(wen_bit == RTLIL::SigBit(false)))
+                               {
+                                       f << stringf("%s" "always @(%sedge ", indent.c_str(), wr_clk_posedge ? "pos" : "neg");
+                                       dump_sigspec(f, sig_wr_clk);
+                                       f << stringf(")\n");
+                                       if (!(wen_bit == RTLIL::SigBit(true)))
+                                       {
+                                               f << stringf("%s" "  if (", indent.c_str());
+                                               dump_sigspec(f, wen_bit);
+                                               f << stringf(")\n  ");
+                                       }
+                                       f << stringf("%s" "  %s[", indent.c_str(), mem_id.c_str());
+                                       dump_sigspec(f, sig_wr_addr);
+                                       if (wen_width == width)
+                                               f << stringf("] <= ");
+                                       else
+                                               f << stringf("][%d:%d] <= ", n+wen_width-1, n);
+                                       dump_sigspec(f, sig_wr_data.extract(n, wen_width));
+                                       f << stringf(";\n");
+                               }
+                               n += wen_width;
+                       }
+               }
+
+               return true;
+       }
+       
        // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
-       // FIXME: $sr, $dffsr, $dlatch, $memrd, $memwr, $mem, $fsm
+       // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
 
        return false;
 }
@@ -732,12 +967,12 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
 
        if (cell->parameters.size() > 0) {
                f << stringf(" #(");
-               for (auto it = cell->parameters.begin(); it != cell->parameters.end(); it++) {
+               for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
                        if (it != cell->parameters.begin())
                                f << stringf(",");
                        f << stringf("\n%s  .%s(", indent.c_str(), id(it->first).c_str());
                        bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
-                       dump_const(f, it->second, -1, 0, !is_signed, is_signed);
+                       dump_const(f, it->second, -1, 0, false, is_signed);
                        f << stringf(")");
                }
                f << stringf("\n%s" ")", indent.c_str());
@@ -754,7 +989,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
        for (int i = 1; true; i++) {
                char str[16];
                snprintf(str, 16, "$%d", i);
-               for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
+               for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
                        if (it->first != str)
                                continue;
                        if (!first_arg)
@@ -768,7 +1003,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                break;
        found_numbered_port:;
        }
-       for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
+       for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
                if (numbered_ports.count(it->first))
                        continue;
                if (!first_arg)
@@ -800,7 +1035,7 @@ void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bo
        if (!omit_trailing_begin && number_of_stmts >= 2)
                f << stringf("%s" "begin\n", indent.c_str());
 
-       for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
+       for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
                if (it->first.size() == 0)
                        continue;
                f << stringf("%s  ", indent.c_str());
@@ -810,7 +1045,7 @@ void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bo
                f << stringf(";\n");
        }
 
-       for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
+       for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
                dump_proc_switch(f, indent + "  ", *it);
 
        if (!omit_trailing_begin && number_of_stmts == 0)
@@ -824,7 +1059,7 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
 {
        if (sw->signal.size() == 0) {
                f << stringf("%s" "begin\n", indent.c_str());
-               for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
+               for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
                        if ((*it)->compare.size() == 0)
                                dump_case_body(f, indent + "  ", *it);
                }
@@ -836,7 +1071,7 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
        dump_sigspec(f, sw->signal);
        f << stringf(")\n");
 
-       for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
+       for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
                f << stringf("%s  ", indent.c_str());
                if ((*it)->compare.size() == 0)
                        f << stringf("default");
@@ -856,11 +1091,11 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
 
 void case_body_find_regs(RTLIL::CaseRule *cs)
 {
-       for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
+       for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
        for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
                case_body_find_regs(*it2);
 
-       for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
+       for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
                for (auto &c : it->first.chunks())
                        if (c.wire != NULL)
                                reg_wires.insert(c.wire->name);
@@ -871,7 +1106,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
 {
        if (find_regs) {
                case_body_find_regs(&proc->root_case);
-               for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
+               for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
                for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
                        for (auto &c : it2->first.chunks())
                                if (c.wire != NULL)
@@ -925,7 +1160,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
                        }
                }
 
-               for (auto it = sync->actions.begin(); it != sync->actions.end(); it++) {
+               for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
                        if (it->first.size() == 0)
                                continue;
                        f << stringf("%s  ", indent.c_str());
@@ -946,7 +1181,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
        active_module = module;
 
        f << stringf("\n");
-       for (auto it = module->processes.begin(); it != module->processes.end(); it++)
+       for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
                dump_process(f, indent + "  ", it->second, true);
 
        if (!noexpr)
@@ -979,12 +1214,12 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
                }
        }
 
-       dump_attributes(f, indent, module->attributes);
+       dump_attributes(f, indent, module->attributes, '\n', true);
        f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
        bool keep_running = true;
        for (int port_id = 1; keep_running; port_id++) {
                keep_running = false;
-               for (auto it = module->wires_.begin(); it != module->wires_.end(); it++) {
+               for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) {
                        RTLIL::Wire *wire = it->second;
                        if (wire->port_id == port_id) {
                                if (port_id != 1)
@@ -997,19 +1232,19 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
        }
        f << stringf(");\n");
 
-       for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
+       for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
                dump_wire(f, indent + "  ", it->second);
 
-       for (auto it = module->memories.begin(); it != module->memories.end(); it++)
+       for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
                dump_memory(f, indent + "  ", it->second);
 
-       for (auto it = module->cells_.begin(); it != module->cells_.end(); it++)
+       for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
                dump_cell(f, indent + "  ", it->second);
 
-       for (auto it = module->processes.begin(); it != module->processes.end(); it++)
+       for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
                dump_process(f, indent + "  ", it->second);
 
-       for (auto it = module->connections().begin(); it != module->connections().end(); it++)
+       for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
                dump_conn(f, indent + "  ", it->first, it->second);
 
        f << stringf("%s" "endmodule\n", indent.c_str());
@@ -1050,6 +1285,10 @@ struct VerilogBackend : public Backend {
                log("        only write selected modules. modules must be selected entirely or\n");
                log("        not at all.\n");
                log("\n");
+               log("    -nomem\n");
+               log("        do not create verilog code for $mem cells. This is only used for\n");
+               log("        testing.\n");
+               log("\n");
        }
        virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
        {
@@ -1059,6 +1298,7 @@ struct VerilogBackend : public Backend {
                noattr = false;
                attr2comment = false;
                noexpr = false;
+               nomem = false;
 
                bool blackboxes = false;
                bool selected = false;
@@ -1116,12 +1356,18 @@ struct VerilogBackend : public Backend {
                                selected = true;
                                continue;
                        }
+                       if (arg == "-nomem") {
+                               nomem = true;
+                               continue;
+                       }
                        break;
                }
                extra_args(f, filename, args, argidx);
 
+               design->sort();
+
                *f << stringf("/* Generated by %s */\n", yosys_version_str);
-               for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
+               for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
                        if (it->second->get_bool_attribute("\\blackbox") != blackboxes)
                                continue;
                        if (selected && !design->selected_whole_module(it->first)) {