xilinx_dffopt: Keep order of LUT inputs.
authorMarcin Kościelnicki <mwk@0x04.net>
Thu, 19 Dec 2019 07:49:21 +0000 (08:49 +0100)
committerMarcin Kościelnicki <mwk@0x04.net>
Thu, 19 Dec 2019 17:01:43 +0000 (18:01 +0100)
See rationale at https://github.com/YosysHQ/yosys/pull/1557#discussion_r359196549

techlibs/xilinx/xilinx_dffopt.cc

index 1256a08cbe9ce654a1288ab28f4d2f07c97984f9..13a0b9b8308c408358c574b7c5ed9297d4efb0ca 100644 (file)
@@ -27,20 +27,13 @@ typedef std::pair<Const, std::vector<SigBit>> LutData;
 
 // Compute a LUT implementing (select ^ select_inv) ? alt_data : data.  Returns true if successful.
 bool merge_lut(LutData &result, const LutData &data, const LutData select, bool select_inv, SigBit alt_data, int max_lut_size) {
-       // First, gather input signals.
+       // First, gather input signals -- insert new signals at the beginning
+       // of the vector, so they don't disturb the likely-critical D LUT input
+       // timings.
        result.second = data.second;
-       int idx_alt = -1;
-       if (alt_data.wire) {
-               // Check if we already have it.
-               for (int i = 0; i < GetSize(result.second); i++)
-                       if (result.second[i] == alt_data)
-                               idx_alt = i;
-               // If not, add it.
-               if (idx_alt == -1) {
-                       idx_alt = GetSize(result.second);
-                       result.second.push_back(alt_data);
-               }
-       }
+       // D lut inputs initially start at 0.
+       int idx_data = 0;
+       // Now add the control input LUT inputs.
        std::vector<int> idx_sel;
        for (auto bit : select.second) {
                int idx = -1;
@@ -48,11 +41,32 @@ bool merge_lut(LutData &result, const LutData &data, const LutData select, bool
                        if (result.second[i] == bit)
                                idx = i;
                if (idx == -1) {
-                       idx = GetSize(result.second);
-                       result.second.push_back(bit);
+                       idx = 0;
+                       // Insert new signal at the beginning and bump all indices.
+                       result.second.insert(result.second.begin(), bit);
+                       idx_data++;
+                       for (int &sidx : idx_sel)
+                               sidx++;
                }
                idx_sel.push_back(idx);
        }
+       // Insert the Q signal, if any, to the slowest input -- it will have
+       // no problem meeting timing.
+       int idx_alt = -1;
+       if (alt_data.wire) {
+               // Check if we already have it.
+               for (int i = 0; i < GetSize(result.second); i++)
+                       if (result.second[i] == alt_data)
+                               idx_alt = i;
+               // If not, add it.
+               if (idx_alt == -1) {
+                       idx_alt = 0;
+                       result.second.insert(result.second.begin(), alt_data);
+                       idx_data++;
+                       for (int &sidx : idx_sel)
+                               sidx++;
+               }
+       }
 
        // If LUT would be too large, bail.
        if (GetSize(result.second) > max_lut_size)
@@ -75,7 +89,7 @@ bool merge_lut(LutData &result, const LutData &data, const LutData select, bool
                                new_bit = alt_data.data == State::S1;
                } else {
                        // Use original LUT.
-                       int lut_idx = i & ((1 << GetSize(data.second)) - 1);
+                       int lut_idx = i >> idx_data & ((1 << GetSize(data.second)) - 1);
                        new_bit = data.first.bits[lut_idx] == State::S1;
                }
                result.first.bits[i] = new_bit ? State::S1 : State::S0;