Initial implementation of split SLICE bels

Signed-off-by: David Shah <dave@ds0.me>
diff --git a/libtrellis/include/Bels.hpp b/libtrellis/include/Bels.hpp
index cb4b5ea..c1801d1 100644
--- a/libtrellis/include/Bels.hpp
+++ b/libtrellis/include/Bels.hpp
@@ -8,6 +8,12 @@
 namespace Bels {
 
 void add_lc(RoutingGraph &graph, int x, int y, int z);
+
+// Split SLICE Bels
+void add_logic_comb(RoutingGraph &graph, int x, int y, int z);
+void add_ff(RoutingGraph &graph, int x, int y, int z);
+void add_ramw(RoutingGraph &graph, int x, int y);
+
 void add_pio(RoutingGraph &graph, int x, int y, int z);
 void add_dcc(RoutingGraph &graph, int x, int y, string side, string z);
 void add_bram(RoutingGraph &graph, int x, int y, int z);
diff --git a/libtrellis/include/Chip.hpp b/libtrellis/include/Chip.hpp
index 1c12c3b..70dafe0 100644
--- a/libtrellis/include/Chip.hpp
+++ b/libtrellis/include/Chip.hpp
@@ -150,6 +150,11 @@
 
     // Globals data
     GlobalsInfo global_data;
+
+    void set_split_slice_mode(bool mode);
+
+private:
+    bool split_slice_flag = false; // for routing graph gen
 };
 
 ChipDelta operator-(const Chip &a, const Chip &b);
diff --git a/libtrellis/src/Bels.cpp b/libtrellis/src/Bels.cpp
index bbcd7d8..f77908c 100644
--- a/libtrellis/src/Bels.cpp
+++ b/libtrellis/src/Bels.cpp
@@ -83,6 +83,136 @@
     graph.add_bel(bel);
 }
 
+void add_logic_comb(RoutingGraph &graph, int x, int y, int z) {
+    char l = "ABCD"[z/2];
+    char i = "01"[z%2];
+    string name = string("SLICE") + l + string(".K") + i;
+    RoutingBel bel;
+    bel.name = graph.ident(name);
+    bel.type = graph.ident("TRELLIS_COMB");
+    bel.loc.x = x;
+    bel.loc.y = y;
+    bel.z = z * 4;
+    // LUT inputs
+    graph.add_bel_input(bel, graph.ident("A"), x, y, graph.ident(fmt("A" << z << "_SLICE")));
+    graph.add_bel_input(bel, graph.ident("B"), x, y, graph.ident(fmt("B" << z << "_SLICE")));
+    graph.add_bel_input(bel, graph.ident("C"), x, y, graph.ident(fmt("C" << z << "_SLICE")));
+    graph.add_bel_input(bel, graph.ident("D"), x, y, graph.ident(fmt("D" << z << "_SLICE")));
+    // MUX select input
+    graph.add_bel_input(bel, graph.ident("M"), x, y, graph.ident(fmt("M" << z << "_SLICE")));
+
+    // Distributed RAM inputs
+    if (z < 4) {
+        // Write address 
+        graph.add_bel_input(bel, graph.ident("WAD0"), x, y, graph.ident(fmt("WAD0" << l << "_SLICE")));
+        graph.add_bel_input(bel, graph.ident("WAD1"), x, y, graph.ident(fmt("WAD1" << l << "_SLICE")));
+        graph.add_bel_input(bel, graph.ident("WAD2"), x, y, graph.ident(fmt("WAD2" << l << "_SLICE")));
+        graph.add_bel_input(bel, graph.ident("WAD3"), x, y, graph.ident(fmt("WAD3" << l << "_SLICE")));
+        // Write data
+        graph.add_bel_input(bel, graph.ident("WD"), x, y, graph.ident(fmt("WD" << i << l << "_SLICE")));
+        // Write enable and clock
+        graph.add_bel_input(bel, graph.ident("WRE"), x, y, graph.ident(fmt("WRE" << (z/2) << "_SLICE")));
+        graph.add_bel_input(bel, graph.ident("WCK"), x, y, graph.ident(fmt("WCK" << (z/2) << "_SLICE")));
+    }
+
+    // Carry input
+    if (z == 0)
+        graph.add_bel_input(bel, graph.ident("FCI"), x, y, graph.ident("FCI_SLICE"));
+    else if ((z % 2) == 0)
+        graph.add_bel_input(bel, graph.ident("FCI"), x, y, graph.ident(fmt("FCI" << l << "_SLICE")));
+    else
+        graph.add_bel_input(bel, graph.ident("FCI"), x, y, graph.ident(fmt("FCI" << l << "1_SLICE")));
+
+    // LUT output
+    graph.add_bel_output(bel, graph.ident("F"), x, y, graph.ident(fmt("F" << z << "_SLICE")));
+    if ((z % 2) == 0) {
+        // Loopback from F1 side to LUT5 mux 'B' input
+        graph.add_bel_input(bel, graph.ident("F1"), x, y, graph.ident(fmt("F" << (z + 1) << "_SLICE")));
+        // LUT5 mux output
+        graph.add_bel_output(bel, graph.ident("OFX"), x, y, graph.ident(fmt("F5" << l << "_SLICE")));
+    } else {
+        // LUT[678] mux inputs
+        graph.add_bel_input(bel, graph.ident("FXA"), x, y, graph.ident(fmt("FXA" << l << "_SLICE")));
+        graph.add_bel_input(bel, graph.ident("FXB"), x, y, graph.ident(fmt("FXB" << l << "_SLICE")));
+        // LUT[678] mux outputs
+        graph.add_bel_output(bel, graph.ident("OFX"), x, y, graph.ident(fmt("FX" << l << "_SLICE")));
+    }
+
+    // Carry output
+    if (z == 7)
+        graph.add_bel_output(bel, graph.ident("FCO"), x, y, graph.ident("FCO_SLICE"));
+    else if ((z % 2) == 1)
+        graph.add_bel_output(bel, graph.ident("FCO"), x, y, graph.ident(fmt("FCO" << l << "_SLICE")));
+    else
+        graph.add_bel_output(bel, graph.ident("FCO"), x, y, graph.ident(fmt("FCI" << l << "1_SLICE")));
+
+    graph.add_bel(bel);
+}
+
+void add_ff(RoutingGraph &graph, int x, int y, int z) {
+    char l = "ABCD"[z/2];
+    char i = "01"[z%2];
+    string name = string("SLICE") + l + string(".FF") + i;
+    RoutingBel bel;
+    bel.name = graph.ident(name);
+    bel.type = graph.ident("TRELLIS_FF");
+    bel.loc.x = x;
+    bel.loc.y = y;
+    bel.z = z * 4 + 1;
+    // DI from COMB
+    graph.add_bel_input(bel, graph.ident("DI"), x, y, graph.ident(fmt("DI" << z << "_SLICE")));
+    // DI from fabric
+    graph.add_bel_input(bel, graph.ident("M"), x, y, graph.ident(fmt("M" << z << "_SLICE")));
+
+    // Control set
+    graph.add_bel_input(bel, graph.ident("CLK"), x, y, graph.ident(fmt("CLK" << (z/2) << "_SLICE")));
+    graph.add_bel_input(bel, graph.ident("LSR"), x, y, graph.ident(fmt("LSR" << (z/2) << "_SLICE")));
+    graph.add_bel_input(bel, graph.ident("CE"), x, y, graph.ident(fmt("CE" << (z/2) << "_SLICE")));
+
+    // Output
+    graph.add_bel_output(bel, graph.ident("Q"), x, y, graph.ident(fmt("Q" << z << "_SLICE")));
+
+    graph.add_bel(bel);
+}
+
+
+void add_ramw(RoutingGraph &graph, int x, int y) {
+    string name = string("SLICEC.RAMW");
+    RoutingBel bel;
+    bel.name = graph.ident(name);
+    bel.type = graph.ident("TRELLIS_RAMW");
+    bel.loc.x = x;
+    bel.loc.y = y;
+    bel.z = 4 * 4 + 2;
+
+    int lc0 = 4;
+    int lc1 = 5;
+
+    // Input
+    graph.add_bel_input(bel, graph.ident("A0"), x, y, graph.ident(fmt("A" << lc0 << "_SLICE")));
+    graph.add_bel_input(bel, graph.ident("B0"), x, y, graph.ident(fmt("B" << lc0 << "_SLICE")));
+    graph.add_bel_input(bel, graph.ident("C0"), x, y, graph.ident(fmt("C" << lc0 << "_SLICE")));
+    graph.add_bel_input(bel, graph.ident("D0"), x, y, graph.ident(fmt("D" << lc0 << "_SLICE")));
+
+    graph.add_bel_input(bel, graph.ident("A1"), x, y, graph.ident(fmt("A" << lc1 << "_SLICE")));
+    graph.add_bel_input(bel, graph.ident("B1"), x, y, graph.ident(fmt("B" << lc1 << "_SLICE")));
+    graph.add_bel_input(bel, graph.ident("C1"), x, y, graph.ident(fmt("C" << lc1 << "_SLICE")));
+    graph.add_bel_input(bel, graph.ident("D1"), x, y, graph.ident(fmt("D" << lc1 << "_SLICE")));
+
+    // Output
+    graph.add_bel_output(bel, graph.ident("WDO0"), x, y, graph.ident("WDO0C_SLICE"));
+    graph.add_bel_output(bel, graph.ident("WDO1"), x, y, graph.ident("WDO1C_SLICE"));
+    graph.add_bel_output(bel, graph.ident("WDO2"), x, y, graph.ident("WDO2C_SLICE"));
+    graph.add_bel_output(bel, graph.ident("WDO3"), x, y, graph.ident("WDO3C_SLICE"));
+
+    graph.add_bel_output(bel, graph.ident("WADO0"), x, y, graph.ident("WADO0C_SLICE"));
+    graph.add_bel_output(bel, graph.ident("WADO1"), x, y, graph.ident("WADO1C_SLICE"));
+    graph.add_bel_output(bel, graph.ident("WADO2"), x, y, graph.ident("WADO2C_SLICE"));
+    graph.add_bel_output(bel, graph.ident("WADO3"), x, y, graph.ident("WADO3C_SLICE"));
+    graph.add_bel(bel);
+}
+
+
 void add_pio(RoutingGraph &graph, int x, int y, int z) {
     char l = "ABCD"[z];
     string name = string("PIO") + l;
@@ -634,4 +764,4 @@
 
 
 }
-}
\ No newline at end of file
+}
diff --git a/libtrellis/src/Chip.cpp b/libtrellis/src/Chip.cpp
index e983fa4..c846233 100644
--- a/libtrellis/src/Chip.cpp
+++ b/libtrellis/src/Chip.cpp
@@ -107,6 +107,11 @@
     return delta;
 }
 
+void Chip::set_split_slice_mode(bool mode)
+{
+    split_slice_flag = mode;
+}
+
 shared_ptr<RoutingGraph> Chip::get_routing_graph()
 {
     shared_ptr<RoutingGraph> rg(new RoutingGraph(*this));
@@ -120,8 +125,16 @@
         tie(y, x) = tile->info.get_row_col();
         // SLICE Bels
         if (tile->info.type == "PLC2") {
-            for (int z = 0; z < 4; z++)
-                Bels::add_lc(*rg, x, y, z);
+            if (split_slice_flag) {
+                for (int z = 0; z < 8; z++) {
+                    Bels::add_logic_comb(*rg, x, y, z);
+                    Bels::add_ff(*rg, x, y, z);
+                }
+                Bels::add_ramw(*rg, x, y);
+            } else {
+                for (int z = 0; z < 4; z++)
+                    Bels::add_lc(*rg, x, y, z);
+            }
         }
         // PIO Bels
         if (tile->info.type.find("PICL0") != string::npos || tile->info.type.find("PICR0") != string::npos)
diff --git a/libtrellis/src/PyTrellis.cpp b/libtrellis/src/PyTrellis.cpp
index ac07c35..a8a5ade 100644
--- a/libtrellis/src/PyTrellis.cpp
+++ b/libtrellis/src/PyTrellis.cpp
@@ -143,6 +143,7 @@
             .def("get_max_row", &Chip::get_max_row)
             .def("get_max_col", &Chip::get_max_col)
             .def("get_routing_graph", &Chip::get_routing_graph)
+            .def("set_split_slice_mode", &Chip::set_split_slice_mode)
             .def_readonly("info", &Chip::info)
             .def_readwrite("cram", &Chip::cram)
             .def_readwrite("tiles", &Chip::tiles)