SymbiFlow / yosys

SymbiFlow WIP changes for Yosys Open SYnthesis Suite
http://www.clifford.at/yosys/
ISC License
37 stars 9 forks source link

Add SRLC16E primitive. #37

Closed mkurc-ant closed 4 years ago

mkurc-ant commented 5 years ago

This is a cherry picked commit from YosysHQ which adds the simulation model of SRLC16E (with Q15 output) primitive.

https://github.com/YosysHQ/yosys/issues/1331

litghost commented 5 years ago

Any reason not to just merge with upstream master, versus the cherry pick?

mkurc-ant commented 5 years ago

Unclear. I will check whether the upstream Yosys works with Symbiflow. If it does then we can merge with upstream.

mkurc-ant commented 5 years ago

So unfortunately the upstream Yosys does not map carry of $alu to CARRY4 but rather to a chain of CARRY0 + 3x CARRY which we don't support in VPR.

litghost commented 5 years ago

So unfortunately the upstream Yosys does not map carry of $alu to CARRY4 but rather to a chain of CARRY0 + 3x CARRY which we don't support in VPR.

I meant merge master+wip with upstream master, which addresses your concern.

mithro commented 5 years ago

Current delta between upstream/master and master+wip after merging is the following;

diff --git a/Makefile b/Makefile
index 8e01ac13..25b95ff1 100644
--- a/Makefile
+++ b/Makefile
@@ -691,6 +691,7 @@ ABCOPT=""
 endif

 test: $(TARGETS) $(EXTRA_TARGETS)
+   +cd tests/round-trip && bash run-test.sh
    +cd tests/simple && bash run-test.sh $(SEEDOPT)
    +cd tests/simple_abc9 && bash run-test.sh $(SEEDOPT)
    +cd tests/hana && bash run-test.sh $(SEEDOPT)
diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc
index e0678622..9e1d1428 100644
--- a/backends/ilang/ilang_backend.cc
+++ b/backends/ilang/ilang_backend.cc
@@ -290,8 +290,19 @@ void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
        if (!module->avail_parameters.empty()) {
            if (only_selected)
                f << stringf("\n");
-           for (auto &p : module->avail_parameters)
+           for (auto &p : module->avail_parameters) {
+
+               if (module->parameter_attributes.count(p)) {
+                   f << stringf("\n");
+                   for (auto& attr : module->parameter_attributes.at(p)) {
+                       f << stringf("%s" "attribute %s ", (indent + "  ").c_str(), attr.first.c_str());
+                       dump_const(f, attr.second);
+                       f << stringf("\n");
+                   }
+               }
+
                f << stringf("%s" "  parameter %s\n", indent.c_str(), p.c_str());
+           }
        }
    }

diff --git a/backends/json/json.cc b/backends/json/json.cc
index 107009ee..a60e0be1 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -116,7 +116,7 @@ struct JsonWriter
    void write_parameters(const dict<IdString, Const> &parameters, bool for_module=false)
    {
        bool first = true;
-       for (auto &param : parameters) {
+       for (auto &attr : attributes) {
            f << stringf("%s\n", first ? "" : ",");
            f << stringf("        %s%s: ", for_module ? "" : "    ", get_name(param.first).c_str());
            write_parameter_value(param.second);
@@ -137,7 +137,11 @@ struct JsonWriter
        f << stringf("    %s: {\n", get_name(module->name).c_str());

        f << stringf("      \"attributes\": {");
-       write_parameters(module->attributes, /*for_module=*/true);
+       write_attributes(module->attributes, /*for_module=*/true);
+       f << stringf("\n      },\n");
+
+       f << stringf("      \"parameters\": {");
+       write_module_parameters(module);
        f << stringf("\n      },\n");

        f << stringf("      \"ports\": {");
@@ -176,10 +180,10 @@ struct JsonWriter
                }
            }
            f << stringf("          \"parameters\": {");
-           write_parameters(c->parameters);
+           write_attributes(c->parameters);
            f << stringf("\n          },\n");
            f << stringf("          \"attributes\": {");
-           write_parameters(c->attributes);
+           write_attributes(c->attributes);
            f << stringf("\n          },\n");
            if (c->known()) {
                f << stringf("          \"port_directions\": {");
@@ -221,7 +225,7 @@ struct JsonWriter
            if (w->upto)
                f << stringf("          \"upto\": 1,\n");
            f << stringf("          \"attributes\": {");
-           write_parameters(w->attributes);
+           write_attributes(w->attributes);
            f << stringf("\n          }\n");
            f << stringf("        }");
            first = false;
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index 7b1db477..ea225c3c 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -1629,6 +1629,36 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
    }
 }

+void dump_parameters(std::ostream &f, std::string indent, RTLIL::Module *module)
+{
+   for (auto& param : module->avail_parameters) {
+       std::string paramName;
+
+       RTLIL::ParameterInfo& info = module->parameter_information.at(param);
+
+       if (module->parameter_attributes.count(param)) {
+           dump_attributes(f, indent, module->parameter_attributes.at(param), '\n');
+       }
+
+       // Prefix the parameter name if needed
+       if (param.str().find("$") == 0) {
+           paramName = std::string("\\") + std::string(param.c_str());
+       }
+       else {
+           paramName = std::string(param.c_str());
+       }
+
+       f << stringf("%s" "parameter %s = ", indent.c_str(), paramName.c_str());
+       if (info.isReal) {
+           f << stringf("%f", info.defaultValueReal);
+       }
+       else {
+           dump_const(f, info.defaultValue);
+       }
+       f << stringf(";\n");
+   }
+}
+
 void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
 {
    reg_wires.clear();
@@ -1704,6 +1734,8 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
    }
    f << stringf(");\n");

+   dump_parameters(f, indent + "  ", module);
+
    for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
        dump_wire(f, indent + "  ", it->second);

diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index a3a78e41..49add93b 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -1053,7 +1053,6 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
                if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
                    new_children.push_back(child);
                } else if (child->type == AST_PARAMETER) {
-                   child->delete_children();
                    child->children.push_back(AstNode::mkconst_int(0, false, 0));
                    new_children.push_back(child);
                } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 407a3447..68792b1c 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -892,27 +892,42 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
    case AST_INTERFACEPORTTYPE:
        break;

-   // remember the parameter, needed for example in techmap
-   case AST_PARAMETER:
-       current_module->avail_parameters.insert(str);
-       /* fall through */
-   case AST_LOCALPARAM:
-       if (flag_pwires)
-       {
-           if (GetSize(children) < 1 || children[0]->type != AST_CONSTANT)
-               log_file_error(filename, linenum, "Parameter `%s' with non-constant value!\n", str.c_str());
+   // create an RTLIL::Parameter for an AST_PARAMETER node
+   case AST_PARAMETER: {
+           current_module->avail_parameters.insert(str);

-           RTLIL::Const val = children[0]->bitsAsConst();
-           RTLIL::Wire *wire = current_module->addWire(str, GetSize(val));
-           current_module->connect(wire, val);
+           // Add parameter information
+           log_assert(children.size() >= 1);

-           wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
-           wire->attributes[type == AST_PARAMETER ? "\\parameter" : "\\localparam"] = 1;
+           AstNode* child = children[0];
+           log_assert(child->type == AST_CONSTANT || child->type == AST_REALVALUE);

-           for (auto &attr : attributes) {
-               if (attr.second->type != AST_CONSTANT)
-                   log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
-               wire->attributes[attr.first] = attr.second->asAttrConst();
+           RTLIL::ParameterInfo info;
+
+           if (child->type == AST_CONSTANT) {
+               info.defaultValue = child->asAttrConst();
+           }
+           else {
+               info.defaultValueReal = child->realvalue;
+               info.isReal = true;
+           }
+
+#ifdef WITH_PYTHON
+           info.name = str;
+#endif
+           current_module->parameter_information.insert(std::pair<RTLIL::IdString, RTLIL::ParameterInfo>(str, info));
+
+           // Add parameter attributes (if any)
+           if (!attributes.empty()) {
+               dict<RTLIL::IdString,RTLIL::Const> param_attrs;
+
+               for (auto &attr : attributes) {
+                   if (attr.second->type != AST_CONSTANT)
+                       log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
+                   param_attrs[attr.first] = attr.second->asAttrConst();
+               }
+
+               current_module->parameter_attributes[str] = param_attrs;
            }
        }
        break;
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 52fcf3ee..fa62ce32 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -2409,7 +2409,7 @@ skip_dynamic_range_lvalue_expansion:;
                    wire->is_input = false;
                    wire->is_output = false;
                    wire->is_reg = true;
-                   wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
+                       wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
                    wire_cache[child->str] = wire;

                    current_ast_mod->children.push_back(wire);
@@ -2457,9 +2457,9 @@ skip_dynamic_range_lvalue_expansion:;
            log_assert(it != current_block->children.end());
            if (*it == current_block_child) {
                current_block->children.insert(it, new_stmts.begin(), new_stmts.end());
-               break;
+                   break;
+               }
            }
-       }

    replace_fcall_with_id:
        if (type == AST_FCALL) {
diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y
index b4b9693d..e33d30a4 100644
--- a/frontends/ilang/ilang_parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -148,6 +148,22 @@ module_stmt:
 param_stmt:
    TOK_PARAMETER TOK_ID EOL {
        current_module->avail_parameters.insert($2);
+
+       // Assume that a parameter has default value of 0
+       RTLIL::ParameterInfo info;
+       info.defaultValue = 0;
+#ifdef WITH_PYTHON     
+       info.name = $2;
+#endif
+
+       current_module->parameter_information.insert(std::pair<RTLIL::IdString,RTLIL::ParameterInfo>($2, info));
+       
+       // Append attributes
+       if (!attrbuf.empty()) {
+           current_module->parameter_attributes[$2] = attrbuf;
+           attrbuf.clear();
+       }
+       
        free($2);
    };

diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 1d380135..cfc5a929 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -1446,6 +1446,17 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const

    new_mod->avail_parameters = avail_parameters;

+   for (auto &info : parameter_information)
+       new_mod->parameter_information.insert(info);
+
+   for (auto &attrs : parameter_attributes)
+   {
+       dict<RTLIL::IdString,RTLIL::Const> attrs_copy;
+       for (auto &attr : attrs.second)
+           attrs_copy[attr.first] = attr.second;
+       new_mod->parameter_attributes[attrs.first] = attrs_copy;
+   }
+
    for (auto &conn : connections_)
        new_mod->connect(conn);

@@ -2352,6 +2363,32 @@ RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string
    return sig;
 }

+RTLIL::ParameterInfo::ParameterInfo()
+{
+   static unsigned int hashidx_count = 123456789;
+   hashidx_count = mkhash_xorshift(hashidx_count);
+   hashidx_ = hashidx_count;
+
+#ifdef WITH_PYTHON
+   RTLIL::ParameterInfo::get_all_parameterinfos()->insert(std::pair<unsigned int, RTLIL::ParameterInfo*>(hashidx_, this));
+#endif
+}
+
+RTLIL::ParameterInfo::~ParameterInfo()
+{
+#ifdef WITH_PYTHON
+   RTLIL::ParameterInfo::get_all_parameterinfos()->erase(hashidx_);
+#endif
+}
+
+#ifdef WITH_PYTHON
+static std::map<unsigned int, RTLIL::ParameterInfo*> all_parameter_infos;
+std::map<unsigned int, RTLIL::ParameterInfo*> *RTLIL::ParameterInfo::get_all_parameterinfos(void)
+{
+   return &all_parameter_infos;
+}
+#endif
+
 RTLIL::Wire::Wire()
 {
    static unsigned int hashidx_count = 123456789;
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index c08653b6..8a132d42 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -59,6 +59,7 @@ namespace RTLIL
    struct Monitor;
    struct Design;
    struct Module;
+   struct ParameterInfo;
    struct Wire;
    struct Memory;
    struct Cell;
@@ -1048,6 +1049,7 @@ public:
    RTLIL::Design *design;
    pool<RTLIL::Monitor*> monitors;

+   int refcount_parameters_;
    int refcount_wires_;
    int refcount_cells_;

@@ -1057,6 +1059,8 @@ public:

    RTLIL::IdString name;
    pool<RTLIL::IdString> avail_parameters;
+   dict<RTLIL::IdString, RTLIL::ParameterInfo> parameter_information;
+   dict<RTLIL::IdString, dict<RTLIL::IdString,RTLIL::Const>> parameter_attributes;
    dict<RTLIL::IdString, RTLIL::Memory*> memories;
    dict<RTLIL::IdString, RTLIL::Process*> processes;

@@ -1298,6 +1302,27 @@ public:
 #endif
 };

+struct RTLIL::ParameterInfo
+{
+   unsigned int hashidx_;
+   unsigned int hash() const { return hashidx_; }
+
+   ParameterInfo ();
+   ~ParameterInfo ();
+
+#ifdef WITH_PYTHON
+   RTLIL::IdString name;
+#endif
+   RTLIL::Const    defaultValue = 0;
+
+   double          defaultValueReal = 0.0;
+   bool            isReal = false;
+
+#ifdef WITH_PYTHON
+   static std::map<unsigned int, RTLIL::ParameterInfo*> *get_all_parameterinfos(void);
+#endif
+};
+
 struct RTLIL::Wire : public RTLIL::AttrObject
 {
    unsigned int hashidx_;
diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py
index 2bf36447..cb90a940 100644
--- a/misc/py_wrap_generator.py
+++ b/misc/py_wrap_generator.py
@@ -947,7 +947,8 @@ sources = [
        WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
        WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
        WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
-       WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "hash()")
+       WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "hash()"),
+       WClass("ParameterInfo", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
        ]
        ),
    #Source("kernel/satgen",[
diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v
index 5c848d4e..4e64e6b0 100644
--- a/techlibs/xilinx/arith_map.v
+++ b/techlibs/xilinx/arith_map.v
@@ -52,7 +52,6 @@ module _80_xilinx_lcu (P, G, CI, CO);
                CARRY4 carry4_1st_part
                (
                .CYINIT(CI),
-               .CI    (1'd0),
                .DI    (G [(Y_WIDTH - 1):i*4]),
                .S     (S [(Y_WIDTH - 1):i*4]),
                .CO    (CO[(Y_WIDTH - 1):i*4]),
@@ -61,7 +60,6 @@ module _80_xilinx_lcu (P, G, CI, CO);
            end else begin
                CARRY4 carry4_part
                (
-               .CYINIT(1'd0),
                .CI    (C [i*4 - 1]),
                .DI    (G [(Y_WIDTH - 1):i*4]),
                .S     (S [(Y_WIDTH - 1):i*4]),
@@ -77,7 +75,6 @@ module _80_xilinx_lcu (P, G, CI, CO);
                CARRY4 carry4_1st_full
                (
                .CYINIT(CI),
-               .CI    (1'd0),
                .DI    (G [((i+1)*4 - 1):i*4]),
                .S     (S [((i+1)*4 - 1):i*4]),
                .CO    (CO[((i+1)*4 - 1):i*4]),
@@ -86,7 +83,6 @@ module _80_xilinx_lcu (P, G, CI, CO);
            end else begin
                CARRY4 carry4_full
                (
-               .CYINIT(1'd0),
                .CI    (C [i*4 - 1]),
                .DI    (G [((i+1)*4 - 1):i*4]),
                .S     (S [((i+1)*4 - 1):i*4]),
@@ -183,7 +179,6 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
                CARRY4 carry4_1st_part
                (
                .CYINIT(CI),
-               .CI    (1'd0),
                .DI    (DI[(Y_WIDTH - 1):i*4]),
                .S     (S [(Y_WIDTH - 1):i*4]),
                .O     (Y [(Y_WIDTH - 1):i*4]),
@@ -193,7 +188,6 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
            end else begin
                CARRY4 carry4_part
                (
-               .CYINIT(1'd0),
                .CI    (C [i*4 - 1]),
                .DI    (DI[(Y_WIDTH - 1):i*4]),
                .S     (S [(Y_WIDTH - 1):i*4]),
@@ -210,7 +204,6 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
                CARRY4 carry4_1st_full
                (
                .CYINIT(CI),
-               .CI    (1'd0),
                .DI    (DI[((i+1)*4 - 1):i*4]),
                .S     (S [((i+1)*4 - 1):i*4]),
                .O     (Y [((i+1)*4 - 1):i*4]),
@@ -220,7 +213,6 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
            end else begin
                CARRY4 carry4_full
                (
-               .CYINIT(1'd0),
                .CI    (C [i*4 - 1]),
                .DI    (DI[((i+1)*4 - 1):i*4]),
                .S     (S [((i+1)*4 - 1):i*4]),
@@ -235,100 +227,98 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);

 `elsif _EXPLICIT_CARRY

-   wire [Y_WIDTH-1:0] S = AA ^ BB;
-   wire [Y_WIDTH-1:0] DI = AA & BB;
+   // Turns out CO and O both use [ABCD]MUX, so provide a non-congested path
+   // to output the top of the carry chain is required.
+   //
+   // Registering the output of the CARRY block would solve this, but not
+   // all designs do that.
+   //
+   // To ensure that PAD_WIDTH > 0, add 1 to Y_WIDTH.
+   localparam Y_PAD_WIDTH  = Y_WIDTH + 1;
+   localparam CARRY4_COUNT = (Y_PAD_WIDTH + 3) / 4;
+   localparam MAX_WIDTH    = CARRY4_COUNT * 4;
+   localparam PAD_WIDTH    = MAX_WIDTH - Y_WIDTH;
+
+   wire [Y_PAD_WIDTH-1:0] O;
+   wire [MAX_WIDTH-1:0] S  = {{PAD_WIDTH{1'b0}}, AA ^ BB};
+   wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB};

-   wire CINIT;
-   // Carry chain.
+   // Carry chain between CARRY4 blocks.
    //
-   // VPR requires that the carry chain never hit the fabric.  The CO input
+   // VPR requires that the carry chain never hit the fabric. The CO input
    // to this techmap is the carry outputs for synthesis, e.g. might hit the
    // fabric.
    //
    // So we maintain two wire sets, CO_CHAIN is the carry that is for VPR,
    // e.g. off fabric dedicated chain.  CO is the carry outputs that are
    // available to the fabric.
-   wire [Y_WIDTH-1:0] CO_CHAIN;
-   wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT};
-
-   // If carry chain is being initialized to a constant, techmap the constant
-   // source.  Otherwise techmap the fabric source.
-   generate for (i = 0; i < 1; i = i + 1) begin:slice
-       CARRY0 #(.CYINIT_FABRIC(1)) carry(
-           .CI_INIT(CI),
-           .DI(DI[0]),
-           .S(S[0]),
-           .CO_CHAIN(CO_CHAIN[0]),
-           .CO_FABRIC(CO[0]),
-           .O(Y[0])
-       );
-   end endgenerate
+   wire [CARRY4_COUNT-1:0] CO_CHAIN;
+   wire [MAX_WIDTH-1:0] CO_FABRIC;

-   generate for (i = 1; i < Y_WIDTH-1; i = i + 1) begin:slice
-       if(i % 4 == 0) begin
-           CARRY0 carry (
-               .CI(C[i]),
-               .DI(DI[i]),
-               .S(S[i]),
-               .CO_CHAIN(CO_CHAIN[i]),
-               .CO_FABRIC(CO[i]),
-               .O(Y[i])
-           );
-       end
-       else
-       begin
-           CARRY carry (
-               .CI(C[i]),
-               .DI(DI[i]),
-               .S(S[i]),
-               .CO_CHAIN(CO_CHAIN[i]),
-               .CO_FABRIC(CO[i]),
-               .O(Y[i])
-           );
-       end
-   end endgenerate
+   assign Y[Y_WIDTH-1:0] = O[Y_WIDTH-1:0];
+   assign CO[Y_WIDTH-2:0] = CO_FABRIC[Y_WIDTH-2:0];
+
+   // Use a dedicated CO pin (e.g. no O pin) to avoid [ABCD]MUX congestion
+   // for top of carry.
+   assign CO[Y_WIDTH-1] = CO_FABRIC[Y_WIDTH];
+
+   genvar i;
+   generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
+
+       // Partially occupied CARRY4
+       if ((i+1)*4 > Y_PAD_WIDTH) begin
+
+           // First one
+           if (i == 0) begin
+               CARRY4_COUT carry4_1st_part
+               (
+               .CYINIT(CI),
+               .DI    (DI[(Y_PAD_WIDTH - 1):i*4]),
+               .S     (S [(Y_PAD_WIDTH - 1):i*4]),
+               .O     (O [(Y_PAD_WIDTH - 1):i*4]),
+               .CO    (CO_FABRIC[(Y_PAD_WIDTH - 1):i*4]),
+               );
+           // Another one
+           end else begin
+               CARRY4_COUT carry4_part
+               (
+               .CI    (CO_CHAIN [i-1]),
+               .DI    (DI[(Y_PAD_WIDTH - 1):i*4]),
+               .S     (S [(Y_PAD_WIDTH - 1):i*4]),
+               .O     (O [(Y_PAD_WIDTH - 1):i*4]),
+               .CO    (CO_FABRIC[(Y_PAD_WIDTH - 1):i*4])
+               );
+           end
+
+       // Fully occupied CARRY4
+       end else begin
+
+           // First one
+           if (i == 0) begin
+               CARRY4_COUT carry4_1st_full
+               (
+               .CYINIT(CI),
+               .DI    (DI[((i+1)*4 - 1):i*4]),
+               .S     (S [((i+1)*4 - 1):i*4]),
+               .O     (O [((i+1)*4 - 1):i*4]),
+               .CO    (CO_FABRIC[((i+1)*4 - 1):i*4]),
+               .COUT(CO_CHAIN[i])
+               );
+           // Another one
+           end else begin
+               CARRY4_COUT carry4_full
+               (
+               .CI    (CO_CHAIN[i-1]),
+               .DI    (DI[((i+1)*4 - 1):i*4]),
+               .S     (S [((i+1)*4 - 1):i*4]),
+               .O     (O [((i+1)*4 - 1):i*4]),
+               .CO    (CO_FABRIC[((i+1)*4 - 1):i*4]),
+               .COUT(CO_CHAIN[i])
+               );
+           end

-   generate for (i = Y_WIDTH-1; i < Y_WIDTH; i = i + 1) begin:slice
-       if(i % 4 == 0) begin
-           CARRY0 top_of_carry (
-               .CI(C[i]),
-               .DI(DI[i]),
-               .S(S[i]),
-               .CO_CHAIN(CO_CHAIN[i]),
-               .O(Y[i])
-           );
-       end
-       else
-       begin
-           CARRY top_of_carry (
-               .CI(C[i]),
-               .DI(DI[i]),
-               .S(S[i]),
-               .CO_CHAIN(CO_CHAIN[i]),
-               .O(Y[i])
-           );
-       end
-       // Turns out CO_FABRIC and O both use [ABCD]MUX, so provide
-       // a non-congested path to output the top of the carry chain.
-       // Registering the output of the CARRY block would solve this, but not
-       // all designs do that.
-       if((i+1) % 4 == 0) begin
-           CARRY0 carry_output (
-               .CI(CO_CHAIN[i]),
-               .DI(0),
-               .S(0),
-               .O(CO[i])
-           );
-       end
-       else
-       begin
-           CARRY carry_output (
-               .CI(CO_CHAIN[i]),
-               .DI(0),
-               .S(0),
-               .O(CO[i])
-           );
        end
+
    end endgenerate

 `else
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index e12b77c0..fc0f5edf 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -215,23 +215,14 @@ endmodule

 `ifdef _EXPLICIT_CARRY

-module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S);
-  parameter CYINIT_FABRIC = 0;
-  wire CI_COMBINE;
-  if(CYINIT_FABRIC) begin
-    assign CI_COMBINE = CI_INIT;
-  end else begin
-    assign CI_COMBINE = CI;
-  end
-  assign CO_CHAIN = S ? CI_COMBINE : DI;
-  assign CO_FABRIC = S ? CI_COMBINE : DI;
-  assign O = S ^ CI_COMBINE;
-endmodule
-
-module CARRY(output CO_CHAIN, CO_FABRIC, O, input CI, DI, S);
-  assign CO_CHAIN = S ? CI : DI;
-  assign CO_FABRIC = S ? CI : DI;
-  assign O = S ^ CI;
+module CARRY4_COUT(output [3:0] CO, O, output COUT, input CI, CYINIT, input [3:0] DI, S);
+  assign O = S ^ {CO[2:0], CI | CYINIT};
+  assign CO[0] = S[0] ? CI | CYINIT : DI[0];
+  assign CO[1] = S[1] ? CO[0] : DI[1];
+  assign CO[2] = S[2] ? CO[1] : DI[2];
+  wire CO_TOP  = S[3] ? CO[2] : DI[3];
+  assign CO[3] = CO_TOP;
+  assign COUT = CO_TOP;
 endmodule

 `endif
diff --git a/techlibs/xilinx/xc7_brams.txt b/techlibs/xilinx/xc7_brams.txt
index f1161114..138540b2 100644
--- a/techlibs/xilinx/xc7_brams.txt
+++ b/techlibs/xilinx/xc7_brams.txt
@@ -72,13 +72,15 @@ bram $__XILINX_RAMB18_TDP
   clkpol 2 3
 endbram

-match $__XILINX_RAMB36_SDP
-  min bits 4096
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
+# Disable RAMB36 synthesis until https://github.com/SymbiFlow/symbiflow-arch-defs/issues/438
+# is solved.
+#match $__XILINX_RAMB36_SDP
+#  min bits 4096
+#  min efficiency 5
+#  shuffle_enable B
+#  make_transp
+#  or_next_if_better
+#endmatch

 match $__XILINX_RAMB18_SDP
   min bits 4096
@@ -88,13 +90,13 @@ match $__XILINX_RAMB18_SDP
   or_next_if_better
 endmatch

-match $__XILINX_RAMB36_TDP
-  min bits 4096
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
+#match $__XILINX_RAMB36_TDP
+#  min bits 4096
+#  min efficiency 5
+#  shuffle_enable B
+#  make_transp
+#  or_next_if_better
+#endmatch

 match $__XILINX_RAMB18_TDP
   min bits 4096
diff --git a/tests/round-trip/parameter_types.v b/tests/round-trip/parameter_types.v
new file mode 100644
index 00000000..db6a198b
--- /dev/null
+++ b/tests/round-trip/parameter_types.v
@@ -0,0 +1,11 @@
+module box (I, O);
+  input  wire I;
+  output wire O;
+
+  parameter PARAM_STRING  = "A string.";
+  parameter PARAM_INTEGER = 10;
+  parameter PARAM_REAL    = 3.14;
+
+  assign O = I;
+
+endmodule
diff --git a/tests/round-trip/parameters.v b/tests/round-trip/parameters.v
new file mode 100644
index 00000000..76699c6c
--- /dev/null
+++ b/tests/round-trip/parameters.v
@@ -0,0 +1,34 @@
+module child_no_params (I, O);
+ input wire I;
+ output wire O;
+ 
+ assign O = I[0];
+endmodule
+
+module child (I, O);
+ (* CHILD_ATTR = 1 *)
+ parameter CHILD_WIDTH = 1;
+ (* CHILD_ATTR2 = 0 *)
+ localparam CHILD_LOCALPARAM = CHILD_WIDTH;
+
+ input  wire [CHILD_LOCALPARAM-1:0] I;
+ output wire O;
+
+ assign O = I[0];
+endmodule
+
+module parent (I, O1, O2);
+ (* PARENT_ATTR = "parent_attr" *)
+ parameter PARENT_WIDTH = 1;
+ parameter PARENT_MODE = "MODE_NAME";
+ parameter [7:0] PARENT_STUFF = 0;
+
+ input  wire [PARENT_WIDTH-1:0] I;
+ output wire O1;
+ output wire O2;
+
+ child #(.CHILD_WIDTH(PARENT_WIDTH)) child_inst1 (I, O1);
+
+ child child_inst2 (I[0], O2);
+
+endmodule
diff --git a/tests/round-trip/run-test.sh b/tests/round-trip/run-test.sh
new file mode 100644
index 00000000..4a1f54fc
--- /dev/null
+++ b/tests/round-trip/run-test.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+# Single round-trip test
+run_single_test () {
+    set -e
+
+    # Frontent options
+    if [ "$LANG" == "verilog" ]; then
+        FRONTEND_OPTS="-nolatches -nomem2reg -nopp -noopt -noautowire -icells"
+    else
+        FRONTEND_OPTS=""
+    fi
+
+    # Initial run
+    ../../../yosys -ql yosys.log -p "read_verilog "../${SOURCE}"; write_"${LANG}" round_trip.1"
+    # Round-trip run
+    ../../../yosys -ql yosys.log -p "read_"${LANG}" ""${FRONTEND_OPTS}"" round_trip.1; write_"${LANG}" round_trip.2"
+
+    # Sort output lines
+    sort round_trip.1 > round_trip.1.sorted
+    sort round_trip.2 > round_trip.2.sorted
+
+    # Check
+    set +e
+    diff -q -B -y round_trip.2.sorted round_trip.1.sorted
+    if [ $? -ne 0 ]; then
+        echo "Test failed! Output after round-trip differs!"
+        exit -1
+    fi
+}
+
+# Run tests
+for SOURCE in *.v; do
+    for LANG in verilog ilang; do
+        WORKDIR=work_$(basename ${SOURCE%.*})_${LANG}
+        mkdir -p ${WORKDIR}
+        cd ${WORKDIR}
+        run_single_test
+        cd ..
+    done
+done
+
litghost commented 4 years ago

With the new master+wip, this has been merged in already