Add source files
diff --git a/.gitignore b/.gitignore
index f4e486c..b2a927b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-precheck_results
\ No newline at end of file
+precheck_results
+*~
diff --git a/openlane/user_project/config.tcl b/openlane/user_project/config.tcl
index 7ac305c..82334ea 100755
--- a/openlane/user_project/config.tcl
+++ b/openlane/user_project/config.tcl
@@ -19,21 +19,27 @@
 
 set ::env(VERILOG_FILES) "\
 	$::env(CARAVEL_ROOT)/verilog/rtl/defines.v \
+	$script_dir/../../verilog/rtl/defines.v \
+	$script_dir/../../verilog/rtl/logic_cell.v \
+	$script_dir/../../verilog/rtl/logic_grid.v \
 	$script_dir/../../verilog/rtl/user_project.v"
 
 set ::env(DESIGN_IS_CORE) 0
 
-set ::env(CLOCK_PORT) "wb_clk_i"
-set ::env(CLOCK_NET) "counter.clk"
+set ::env(SYNTH_NO_FLAT) 1
+
+set ::env(CLOCK_PORT) ""
+set ::env(CLOCK_NET) "wb_clk_i"
 set ::env(CLOCK_PERIOD) "10"
+#set ::env(BASE_SDC_FILE) "$::env(DESIGN_DIR)/base.sdc"
 
 set ::env(FP_SIZING) absolute
-set ::env(DIE_AREA) "0 0 900 600"
+set ::env(DIE_AREA) "0 0 1200 1200"
 
 set ::env(FP_PIN_ORDER_CFG) $script_dir/pin_order.cfg
 
 set ::env(PL_BASIC_PLACEMENT) 1
-set ::env(PL_TARGET_DENSITY) 0.05
+set ::env(PL_TARGET_DENSITY) 0.02
 
 # Maximum layer used for routing is metal 4.
 # This is because this macro will be inserted in a top level (user_project_wrapper) 
diff --git a/openlane/user_project_wrapper/config.tcl b/openlane/user_project_wrapper/config.tcl
index 36c664e..39f574b 100755
--- a/openlane/user_project_wrapper/config.tcl
+++ b/openlane/user_project_wrapper/config.tcl
@@ -51,6 +51,9 @@
 ### Black-box verilog and views
 set ::env(VERILOG_FILES_BLACKBOX) "\
 	$::env(CARAVEL_ROOT)/verilog/rtl/defines.v \
+	$script_dir/../../verilog/rtl/defines.v \
+	$script_dir/../../verilog/rtl/logic_cell.v \
+	$script_dir/../../verilog/rtl/logic_grid.v \
 	$script_dir/../../verilog/rtl/user_project.v"
 
 set ::env(EXTRA_LEFS) "\
diff --git a/verilog/rtl/defines.v b/verilog/rtl/defines.v
new file mode 100644
index 0000000..699b764
--- /dev/null
+++ b/verilog/rtl/defines.v
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: MIT
+// SPDX-FileCopyrightText: 2021 Tamas Hubai
+
+`default_nettype none
+
+// width of cell grid
+`define WIDTH 8
+
+// height of cell grid
+`define HEIGHT 8
+
+// size of width/height field, i.e. clog2(max(WIDTH, HEIGHT))
+`define ADDRSIZE 3
+
+// number of input pins = number of output pins
+`define IOPAIRS 8
+
+// x coordinate of input pins
+`define X_IN 0
+
+// x coordinate of output pins
+`define X_OUT (`WIDTH-1)
+
+// y coordinate of first input/output pin pair
+`define Y_FIRST 0
+
+// y coordinate difference of successive input/output pin pairs
+`define Y_STEP 1
+
+`default_nettype wire
+
diff --git a/verilog/rtl/logic_cell.v b/verilog/rtl/logic_cell.v
new file mode 100644
index 0000000..1370f2c
--- /dev/null
+++ b/verilog/rtl/logic_cell.v
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: MIT
+// SPDX-FileCopyrightText: 2021 Tamas Hubai
+
+`default_nettype none
+
+/*
+Rotatable primitive logic cell
+
+In upright position it implements:
+- a buffer from left input to right & bottom outputs
+- a NAND gate from right & bottom inputs to top output
+- a D flip-flop from top input to left output
+
+Any logic circuit can be built from this cell and its rotations arranged in a grid.
+The cell can be rotated counterclockwise using the programming trigger at a clock edge,
+affecting both input and output orientation.
+
+        A     V
+  +-----|-----|-----+
+  |  /==:=====/     |
+  |  |  |           |
+>====:==:=====+=======>
+  |  |  |     |     |
+  |  D  ~&    |     |
+<====/  |\====:=======<
+  |     |     |     |
+  |     |     |     |
+  +-----|-----|-----+
+        A     V
+
+A few logic cells are designated as IO cells, these have their flip-flop
+connected to an input and/or output pin.
+*/
+
+module logic_cell(
+   input clk,     // clock
+   input rst_n,   // reset, active low
+   input trig,    // programming trigger
+   input in_t,    // top input
+   input in_r,    // right input
+   input in_b,    // bottom input
+   input in_l,    // left input
+   input in_i,    // io cell input pin
+   input en_i,    // is the input pin enabled
+   output out_t,  // top output
+   output out_r,  // right output
+   output out_b,  // bottom output
+   output out_l,  // left output
+   output out_o   // io cell output pin
+);
+
+reg [1:0] rot;    // current rotation
+reg ff;           // flip-flop status
+
+wire inx_t, inx_r, inx_b, inx_l;       // inputs after rotation
+wire outx_t, outx_r, outx_b, outx_l;   // outputs before rotation
+
+wire inr_t, inr_r, inr_b, inr_l;       // temporary values used during rotation
+wire outr_t, outr_r, outr_b, outr_l;
+
+// rotations
+
+assign inr_t = rot[1] ? in_b : in_t;
+assign inr_r = rot[1] ? in_l : in_r;
+assign inr_b = rot[1] ? in_t : in_b;
+assign inr_l = rot[1] ? in_r : in_l;
+
+assign inx_t = rot[0] ? inr_l : inr_t;
+assign inx_r = rot[0] ? inr_t : inr_r;
+assign inx_b = rot[0] ? inr_r : inr_b;
+assign inx_l = rot[0] ? inr_b : inr_l;
+
+assign outr_t = rot[1] ? outx_b : outx_t;
+assign outr_r = rot[1] ? outx_l : outx_r;
+assign outr_b = rot[1] ? outx_t : outx_b;
+assign outr_l = rot[1] ? outx_r : outx_l;
+
+assign out_t = rot[0] ? outr_r : outr_t;
+assign out_r = rot[0] ? outr_b : outr_r;
+assign out_b = rot[0] ? outr_l : outr_b;
+assign out_l = rot[0] ? outr_t : outr_l;
+
+// outputs of the unrotated tile
+
+assign outx_t = ~(inx_r & inx_b);
+assign outx_r = inx_l;
+assign outx_b = inx_l;
+assign outx_l = ff;
+assign out_o = ff;
+
+always @ (posedge clk) begin
+   if (!rst_n) begin
+      rot <= 0;
+      ff <= 0;
+   end else begin
+      if (trig) rot <= rot + 1;
+      ff <= en_i ? in_i : inx_t;
+   end
+end
+
+endmodule
+
+`default_nettype wire
+
diff --git a/verilog/rtl/logic_grid.v b/verilog/rtl/logic_grid.v
new file mode 100644
index 0000000..3d160c3
--- /dev/null
+++ b/verilog/rtl/logic_grid.v
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: MIT
+// SPDX-FileCopyrightText: 2021 Tamas Hubai
+
+`default_nettype none
+
+module logic_grid (
+   input clk,
+   input rst_n,
+   input trig_en,
+   input [`ADDRSIZE-1:0] trig_x,
+   input [`ADDRSIZE-1:0] trig_y,
+   input [`IOPAIRS-1:0] in_pins,
+   output [`IOPAIRS-1:0] out_pins
+);
+
+wire ic_u[`HEIGHT-1:0][`WIDTH-1:0];   // interconnect for data going upwards
+wire ic_d[`HEIGHT-1:0][`WIDTH-1:0];   // ~ downwards
+wire ic_r[`HEIGHT-1:0][`WIDTH-1:0];   // ~ to the right
+wire ic_l[`HEIGHT-1:0][`WIDTH-1:0];   // ~ to the left
+wire trig_h[`HEIGHT-1:0];            // horizontal trigger lines
+wire trig_v[`WIDTH-1:0];             // vertical trigger lines
+
+generate genvar x, y;
+for (y=0; y<`HEIGHT; y=y+1) begin:g_y
+   for (x=0; x<`WIDTH; x=x+1) begin:g_x
+      wire trig = trig_h[y] & trig_v[x];
+      wire in_i;
+      wire en_i;
+      wire out_o;
+      
+      if (y >= `Y_FIRST && y <= `Y_FIRST+`Y_STEP*(`IOPAIRS-1) && (y-`Y_FIRST)%`Y_STEP == 0) begin
+         if (x == `X_IN) begin
+            assign en_i = 1;
+            assign in_i = in_pins[(y-`Y_FIRST)/`Y_STEP];
+         end else begin
+            assign en_i = 0;
+            assign in_i = 0;
+         end
+         if (x == `X_OUT) begin
+            assign out_pins[(y-`Y_FIRST)/`Y_STEP] = out_o;
+         end
+      end else begin
+         assign en_i = 0;
+         assign in_i = 0;
+      end
+
+      logic_cell lc (
+         .clk(clk),
+         .rst_n(rst_n),
+         .trig(trig),
+         .in_t(ic_d[y][x]),
+         .in_r(ic_l[y][(x+1)%`WIDTH]),
+         .in_b(ic_u[(y+1)%`HEIGHT][x]),
+         .in_l(ic_r[y][x]),
+         .in_i(in_i),
+         .en_i(en_i),
+         .out_t(ic_u[y][x]),
+         .out_r(ic_r[y][(x+1)%`WIDTH]),
+         .out_b(ic_d[(y+1)%`HEIGHT][x]),
+         .out_l(ic_l[y][x]),
+         .out_o(out_o)     
+      );
+   end
+end
+
+for (x=0; x<`WIDTH; x=x+1) begin:g_vt
+   assign trig_v[x] = trig_en & (trig_x == x);
+end
+
+for (y=0; y<`HEIGHT; y=y+1) begin:g_ht
+   assign trig_h[y] = trig_en & (trig_y == y);
+end
+endgenerate
+
+endmodule
+
+`default_nettype wire
+
diff --git a/verilog/rtl/user_project.v b/verilog/rtl/user_project.v
index 8174ffd..db163fe 100644
--- a/verilog/rtl/user_project.v
+++ b/verilog/rtl/user_project.v
@@ -1,43 +1,9 @@
-// SPDX-FileCopyrightText: 2020 Efabless Corporation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+// SPDX-FileCopyrightText: 2021 Tamas Hubai
 
 `default_nettype none
-/*
- *-------------------------------------------------------------
- *
- * user_project
- *
- * This is an example of a (trivially simple) user project,
- * showing how the user project can connect to the logic
- * analyzer, the wishbone bus, and the I/O pads.
- *
- * This project generates an integer count, which is output
- * on the user area GPIO pads (digital output only).  The
- * wishbone connection allows the project to be controlled
- * (start and stop) from the management SoC program.
- *
- * See the testbenches in directory "mprj_counter" for the
- * example programs that drive this user project.  The three
- * testbenches are "io_ports", "la_test1", and "la_test2".
- *
- *-------------------------------------------------------------
- */
 
-module user_project #(
-    parameter BITS = 32
-)(
+module user_project (
 `ifdef USE_POWER_PINS
     inout vccd1,	// User area 1 1.8V supply
     inout vssd1,	// User area 1 digital ground
@@ -68,98 +34,56 @@
     // IRQ
     output [2:0] irq
 );
-    wire clk;
-    wire rst;
 
-    wire [`MPRJ_IO_PADS-1:0] io_in;
-    wire [`MPRJ_IO_PADS-1:0] io_out;
-    wire [`MPRJ_IO_PADS-1:0] io_oeb;
+// clock & reset
+wire clk = wb_clk_i;
+wire rst_n = ~wb_rst_i;
 
-    wire [31:0] rdata; 
-    wire [31:0] wdata;
-    wire [BITS-1:0] count;
+// single cycle input only wishbone logic
+wire valid = wbs_stb_i && wbs_cyc_i;
+assign wbs_ack_o = valid;
+wire trig_en = valid && wbs_we_i;
+wire [15:0] trig_x = trig_en ? wbs_adr_i[15:0] : 0;
+wire [15:0] trig_y = trig_en ? wbs_adr_i[31:16] : 0;
+assign wbs_dat_o = 32'b0;
 
-    wire valid;
-    wire [3:0] wstrb;
-    wire [31:0] la_write;
-
-    // WB MI A
-    assign valid = wbs_cyc_i && wbs_stb_i; 
-    assign wstrb = wbs_sel_i & {4{wbs_we_i}};
-    assign wbs_dat_o = rdata;
-    assign wdata = wbs_dat_i;
-
-    // IO
-    assign io_out = count;
-    assign io_oeb = {(`MPRJ_IO_PADS-1){rst}};
-
-    // IRQ
-    assign irq = 3'b000;	// Unused
-
-    // LA
-    assign la_data_out = {{(127-BITS){1'b0}}, count};
-    // Assuming LA probes [63:32] are for controlling the count register  
-    assign la_write = ~la_oenb[63:32] & ~{BITS{valid}};
-    // Assuming LA probes [65:64] are for controlling the count clk & reset  
-    assign clk = (~la_oenb[64]) ? la_data_in[64]: wb_clk_i;
-    assign rst = (~la_oenb[65]) ? la_data_in[65]: wb_rst_i;
-
-    counter #(
-        .BITS(BITS)
-    ) counter(
-        .clk(clk),
-        .reset(rst),
-        .ready(wbs_ack_o),
-        .valid(valid),
-        .rdata(rdata),
-        .wdata(wbs_dat_i),
-        .wstrb(wstrb),
-        .la_write(la_write),
-        .la_input(la_data_in[63:32]),
-        .count(count)
-    );
-
-endmodule
-
-module counter #(
-    parameter BITS = 32
-)(
-    input clk,
-    input reset,
-    input valid,
-    input [3:0] wstrb,
-    input [BITS-1:0] wdata,
-    input [BITS-1:0] la_write,
-    input [BITS-1:0] la_input,
-    output ready,
-    output [BITS-1:0] rdata,
-    output [BITS-1:0] count
-);
-    reg ready;
-    reg [BITS-1:0] count;
-    reg [BITS-1:0] rdata;
-
-    always @(posedge clk) begin
-        if (reset) begin
-            count <= 0;
-            ready <= 0;
-        end else begin
-            ready <= 1'b0;
-            if (~|la_write) begin
-                count <= count + 1;
-            end
-            if (valid && !ready) begin
-                ready <= 1'b1;
-                rdata <= count;
-                if (wstrb[0]) count[7:0]   <= wdata[7:0];
-                if (wstrb[1]) count[15:8]  <= wdata[15:8];
-                if (wstrb[2]) count[23:16] <= wdata[23:16];
-                if (wstrb[3]) count[31:24] <= wdata[31:24];
-            end else if (|la_write) begin
-                count <= la_write & la_input;
-            end
-        end
+// trigger debugging
+reg parity;
+always @ (posedge clk) begin
+    if (!rst_n) begin
+        parity <= 0;
+    end else begin
+        parity <= parity ^ trig_en;
     end
+end
+
+// pin assignment
+wire [11:0] in_pins = io_in[23:12];
+wire [11:0] out_pins;
+assign io_out[23:0] = 24'b0;
+assign io_out[35:24] = out_pins;
+assign io_out[36] = clk;
+assign io_out[37] = parity;
+assign io_oeb[23:0] = 24'b1; // input
+assign io_oeb[37:24] = 14'b0; // output
+
+// logic analyzer is unused
+assign la_data_out = 128'b0;
+
+// irq is unused
+assign irq = 3'b0;
+
+logic_grid lg (
+    .clk(clk),
+    .rst_n(rst),
+    .trig_en(trig_en),
+    .trig_x(trig_x),
+    .trig_y(trig_y),
+    .in_pins(in_pins),
+    .out_pins(out_pins)
+);
 
 endmodule
+
 `default_nettype wire
+
diff --git a/verilog/rtl/user_project_wrapper.v b/verilog/rtl/user_project_wrapper.v
index b47c807..5057915 100644
--- a/verilog/rtl/user_project_wrapper.v
+++ b/verilog/rtl/user_project_wrapper.v
@@ -29,9 +29,7 @@
  *-------------------------------------------------------------
  */
 
-module user_project_wrapper #(
-    parameter BITS = 32
-) (
+module user_project_wrapper (
 `ifdef USE_POWER_PINS
     inout vdda1,	// User area 1 3.3V supply
     inout vdda2,	// User area 2 3.3V supply
@@ -121,3 +119,4 @@
 endmodule	// user_project_wrapper
 
 `default_nettype wire
+