Succesfully generated hard macro of user project and wrapper cell
diff --git a/verilog/rtl/gpioModule/gpioCtrl.v b/verilog/rtl/gpioModule/gpioCtrl.v
new file mode 100644
index 0000000..df5d8e1
--- /dev/null
+++ b/verilog/rtl/gpioModule/gpioCtrl.v
@@ -0,0 +1,327 @@
+// gpio control module
+//      address space:
+//          Ctrl Reg        0b00
+//          GPIO Input      0b01
+//          GPIO Output     0b10
+//          GPIO OutEnable  0b11
+
+module gpioCtrl (
+    // system
+    input   wire            CLK,
+    input   wire            RSTb,
+    // control interface
+    input   wire            CTRL_WE,
+    input   wire    [3:0]   CTRL_ADDR,
+    input   wire    [31:0]  CTRL_DATA_IN,
+    output  wire    [31:0]  CTRL_DATA_OUT,
+    // caravel gpio signaling
+    input   wire    [37:0]  GPIO_IN,
+    output  wire    [37:0]  GPIO_OUT,
+    output  wire    [37:0]  GPIO_OEb,
+    // RAM interface
+    output  wire            RAM_CSb,
+    output  wire            RAM_WEb,
+    output  wire    [7:0]   RAM_ADDR,
+    output  wire    [31:0]  RAM_DATA_IN,
+    input   wire    [31:0]  RAM_DATA_OUT
+);
+    // constants input fsm
+    parameter sFSM_IN_STOP      	= 2'b00;
+    parameter sFSM_IN_SHIFT     	= 2'b01;
+    parameter sFSM_IN_STORE     	= 2'b10;
+    // constants output fsm
+    parameter sFSM_OUT_STOP     	= 2'b00;
+    parameter sFSM_OUT_LOAD     	= 2'b01;
+    parameter sFSM_OUT_SHIFT    	= 2'b10;
+    parameter sFSM_OUT_LOAD_NEXT 	= 2'b11;
+
+    // internal output signals
+    reg [31:0]  CTRL_DATA_OUT_i;
+    reg         RAM_WEb_i;
+    reg [31:0]  RAM_ADDR_i;
+    reg [31:0]  RAM_DATA_IN_i;
+    // control register
+    reg [31:0]  CTRL_REG_Q;
+    reg [31:0]  CTRL_REG_D;
+    // control register aliases
+    wire        aSHIFT_IN_EN;
+    wire [4:0]  aINPUT_SEL;
+    wire        aSHIFT_OUT_EN;
+    wire [4:0]  aOUTPUT_SEL;
+    wire        aOUTPUT_LOOP;
+    wire [9:0]  aOUTPUT_LEN;
+    wire        aOUTPUT_LIMIT;
+    // data registers
+    reg [31:0]   DATA_IN_Q;
+    reg [31:0]   DATA_IN_D;
+    reg [31:0]   DATA_OUT_Q;
+    reg [31:0]   DATA_OUT_D;
+    reg [31:0]   DATA_OE_Q;
+    reg [31:0]   DATA_OE_D;
+    // Shift registers
+    reg [31:0]   SHIFT_IN_Q;
+    reg [31:0]   SHIFT_IN_D;
+    reg [31:0]   SHIFT_OUT_Q;
+    reg [31:0]   SHIFT_OUT_D;
+    // fsm registers
+    reg [1:0]   FSM_IN_Q;
+    reg [1:0]   FSM_IN_D;
+    reg [1:0]   FSM_OUT_Q;
+    reg [1:0]   FSM_OUT_D;
+    // fsm control signals
+    reg         SET_SHIFT_DATA;
+    reg         SET_OUT_DATA;
+    reg         RST_SHIFT_IN_EN;
+    reg         RST_SHIFT_OUT_EN;
+    reg         OVERRIDE_RAM_ADDR;
+    reg         RAM_CSb_IN;
+    reg         RAM_CSb_OUT;
+    // bit counters
+    reg [9:0]   BIT_IN_COUNT_Q;
+    reg [9:0]   BIT_IN_COUNT_D;
+    reg [9:0]   BIT_OUT_COUNT_Q;
+    reg [9:0]   BIT_OUT_COUNT_D;
+
+    // module output
+    assign CTRL_DATA_OUT = CTRL_DATA_OUT_i;
+    assign GPIO_OUT[31:0] = DATA_OUT_Q;
+    assign GPIO_OUT[37:32] = 6'b000000;
+    assign GPIO_OEb[31:0] = ~(DATA_OE_Q);
+    assign GPIO_OEb[37:32] = 6'b111111;
+    assign RAM_WEb = RAM_WEb_i;
+    assign RAM_ADDR = RAM_ADDR_i;
+    assign RAM_DATA_IN = RAM_DATA_IN_i;
+
+    // control register read aliases (...is there a way to define real aliases?)
+    assign aSHIFT_OUT_EN    = CTRL_REG_Q[0];
+    assign aOUTPUT_SEL      = CTRL_REG_Q[5:1];
+    assign aSHIFT_IN_EN     = CTRL_REG_Q[6];
+    assign aINPUT_SEL       = CTRL_REG_Q[11:7];
+    assign aOUTPUT_LOOP     = CTRL_REG_Q[12];
+    assign aOUTPUT_LEN      = CTRL_REG_Q[22:13];
+    assign aOUTPUT_LIMIT    = CTRL_REG_Q[23];
+    
+    // control interface read access
+    always @(*) begin : interface_read_access
+        case (CTRL_ADDR[3:2])
+            // control register
+            2'b00: CTRL_DATA_OUT_i <= CTRL_REG_Q;
+            // input data
+            2'b01: CTRL_DATA_OUT_i <= DATA_IN_Q;
+            // output data
+            2'b10: CTRL_DATA_OUT_i <= DATA_OUT_Q;
+            // output enable
+            2'b11: CTRL_DATA_OUT_i <= DATA_OE_Q;
+            // something's wrong
+            default: CTRL_DATA_OUT_i <= 8'b0000_0000;
+        endcase
+    end
+
+    // control interface write access
+    always @(*) begin : interface_write_access
+        // default
+        CTRL_REG_D   <= CTRL_REG_Q;
+        SET_OUT_DATA <= 1'b0;
+        DATA_OE_D   <= DATA_OE_Q;
+        // actual write request
+        if (CTRL_WE == 1'b1) begin
+            // address selection
+            case (CTRL_ADDR[3:2])
+                // control register
+                2'b00: begin
+                    CTRL_REG_D  <= CTRL_DATA_IN;
+                end
+                // output data
+                2'b10: SET_OUT_DATA <= 1'b1;
+                // output enable
+                2'b11: DATA_OE_D  <= CTRL_DATA_IN;
+            endcase
+        end
+        // auto set/reset shift enables
+        if (RST_SHIFT_IN_EN == 1'b1) CTRL_REG_D[6] <= 1'b0;
+        if (RST_SHIFT_OUT_EN == 1'b1) CTRL_REG_D[0] <= 1'b0;
+        //if (SET_SHIFT_OUT_EN == 1'b1)  CTRL_REG_D[0] <= 1'b1;
+    end
+
+    // fsm data in
+    always @(*) begin : fsm_data_in
+        // default
+        FSM_IN_D        <= FSM_IN_Q;
+        BIT_IN_COUNT_D  <= BIT_IN_COUNT_Q;
+        RST_SHIFT_IN_EN <= 1'b0;
+        //RAM_CSb_IN      <= 1'b1;
+        RAM_WEb_i       <= 1'b1;
+        // fsm logic
+        case (FSM_IN_Q)
+            // input sampling inactive
+            sFSM_IN_STOP: begin
+                BIT_IN_COUNT_D <= 10'b00_0000_0000;
+                if (aSHIFT_IN_EN == 1'b1) begin
+                    RST_SHIFT_IN_EN <= 1'b1;
+                    FSM_IN_D <= sFSM_IN_SHIFT;
+                end
+            end
+            // input sampling active
+            sFSM_IN_SHIFT: begin
+                BIT_IN_COUNT_D <= BIT_IN_COUNT_Q + 1;
+                if (BIT_IN_COUNT_Q[4:0] == 5'b1_1110) FSM_IN_D <= sFSM_IN_STORE;
+            end
+            // store 32bit input data to ram
+            sFSM_IN_STORE: begin
+                BIT_IN_COUNT_D  <= BIT_IN_COUNT_Q + 1;
+                //RAM_CSb_IN      <= 1'b0;
+                RAM_WEb_i       <= 1'b0;
+                if (BIT_IN_COUNT_Q[9:5] == 5'b1_1111) FSM_IN_D <= sFSM_IN_STOP;
+                else                                  FSM_IN_D <= sFSM_IN_SHIFT;
+            end
+            // error
+            default: FSM_IN_D <= sFSM_IN_STOP;
+        endcase
+    end
+
+    // fsm data out
+    always @(*) begin : fsm_data_out
+        // default
+        FSM_OUT_D         <= FSM_OUT_Q;
+        BIT_OUT_COUNT_D   <= BIT_OUT_COUNT_Q;
+        RST_SHIFT_OUT_EN  <= 1'b0;
+        SET_SHIFT_DATA    <= 1'b0;
+        //RAM_CSb_OUT       <= 1'b1;
+        OVERRIDE_RAM_ADDR <= 1'b0;
+        // fsm logic
+        case (FSM_OUT_Q)
+            // output generation inactive
+            sFSM_OUT_STOP: begin
+                BIT_OUT_COUNT_D <= 10'b11_1111_1111;
+                if (aSHIFT_OUT_EN == 1'b1) begin
+                    RST_SHIFT_OUT_EN <= 1'b1;
+                    //RAM_CSb_OUT      <= 1'b0;
+                    FSM_OUT_D        <= sFSM_OUT_LOAD;
+                end
+            end
+            // load first 32bit output data from ram
+            sFSM_OUT_LOAD: begin
+				BIT_OUT_COUNT_D <= 10'b00_0000_0000;
+                SET_SHIFT_DATA  <= 1'b1;
+                FSM_OUT_D       <= sFSM_OUT_SHIFT;
+            end
+            // output generation active
+            sFSM_OUT_SHIFT: begin
+                BIT_OUT_COUNT_D <= BIT_OUT_COUNT_Q + 1;
+                // single shot: configured length reached
+                if (   aOUTPUT_LOOP == 1'b0
+                    && (aOUTPUT_LIMIT == 1'b1 && BIT_OUT_COUNT_Q == aOUTPUT_LEN-1)) 
+                    FSM_OUT_D <= sFSM_OUT_STOP;
+                // loop mode: configured length reached
+                else if (   aOUTPUT_LOOP == 1'b1
+                         && (aOUTPUT_LIMIT == 1'b1 && BIT_OUT_COUNT_Q == (aOUTPUT_LEN-2))) begin
+                    OVERRIDE_RAM_ADDR <= 1'b1;
+                    //RAM_CSb_OUT      <= 1'b0;
+                    FSM_OUT_D <= sFSM_OUT_LOAD;
+                // need new 32-bit data
+                end else if (BIT_OUT_COUNT_Q[4:0] == 5'b1_1110) begin
+                    //RAM_CSb_OUT      <= 1'b0;
+                    FSM_OUT_D <= sFSM_OUT_LOAD_NEXT;
+                end
+            end 
+            // load next 32bit output data from ram
+            sFSM_OUT_LOAD_NEXT: begin
+                // single shot: max or configured length reached
+                if (   aOUTPUT_LOOP == 1'b0
+                    && (   BIT_OUT_COUNT_Q[9:5] == 5'b1_1111
+                        || (aOUTPUT_LIMIT == 1'b1 && BIT_OUT_COUNT_Q == aOUTPUT_LEN-1))) 
+                        FSM_OUT_D <= sFSM_OUT_STOP;
+                // loop mode: max or configured length reached
+                else if (   aOUTPUT_LOOP == 1'b1
+                    && (   BIT_OUT_COUNT_Q[9:5] == 5'b1_1111
+                        || (aOUTPUT_LIMIT == 1'b1 && BIT_OUT_COUNT_Q == aOUTPUT_LEN-2))) begin
+                        OVERRIDE_RAM_ADDR <= 1'b1;
+                        //RAM_CSb_OUT      <= 1'b0;
+                        FSM_OUT_D <= sFSM_OUT_LOAD;
+                 // continue generating data bits
+                end else begin
+                    SET_SHIFT_DATA  <= 1'b1;
+                    BIT_OUT_COUNT_D <= BIT_OUT_COUNT_Q + 1;
+                    FSM_OUT_D <= sFSM_OUT_SHIFT;
+                end
+            end
+            // error
+            default: FSM_OUT_D <= sFSM_OUT_STOP;
+        endcase
+    end
+
+    // input data path
+    always @(*) begin : input_data_path
+        reg vDataInMux;
+        // input registers
+        DATA_IN_D <= GPIO_IN[31:0];
+        // input multiplexer
+        vDataInMux = DATA_IN_Q[aINPUT_SEL];
+        // input shift register
+        SHIFT_IN_D <= {SHIFT_IN_Q[30:0], vDataInMux};
+        // ram data input
+        RAM_DATA_IN_i <= SHIFT_IN_Q;
+    end
+
+    // output data path
+    always @(*) begin : output_data_path
+        // default: output shift register
+        SHIFT_OUT_D <= {SHIFT_OUT_Q[30:0], 1'b0};
+        // set shift data
+        if(SET_SHIFT_DATA == 1'b1) SHIFT_OUT_D <= RAM_DATA_OUT;
+        // default: hold output data
+        DATA_OUT_D <= DATA_OUT_Q;
+        // bus write access
+        if (SET_OUT_DATA == 1'b1) DATA_OUT_D <= CTRL_DATA_IN;
+        // shift register input
+        if (FSM_OUT_Q != sFSM_OUT_STOP) DATA_OUT_D[aOUTPUT_SEL] <= SHIFT_OUT_Q[31];
+    end
+
+    // logic for ram access
+    always @(*) begin
+        // default
+        RAM_CSb_IN  <= 1'b1;
+        RAM_CSb_OUT <= 1'b1;
+        RAM_ADDR_i  <= 32'h00_00_00_00;
+        if (OVERRIDE_RAM_ADDR == 1'b1) begin
+            RAM_CSb_OUT <= 1'b0;
+            RAM_ADDR_i  <= 32'h00_00_00_00;
+        end else if (FSM_IN_Q != sFSM_IN_STOP) begin
+            RAM_CSb_IN <= 1'b0; 
+            RAM_ADDR_i <= {BIT_IN_COUNT_Q[9:5], 2'b00};
+        end else if (FSM_OUT_Q != sFSM_OUT_STOP) begin
+            RAM_CSb_OUT <= 1'b0;
+            RAM_ADDR_i  <= {BIT_OUT_COUNT_Q[9:5] + 1, 2'b00};
+        end
+    end
+    //assign RAM_ADDR = (FSM_IN_Q != sFSM_IN_STOP) ? {BIT_IN_COUNT_Q[9:5], 2'b00} : {BIT_OUT_COUNT_Q[9:5] + 1, 2'b00};
+    assign RAM_CSb = RAM_CSb_IN & RAM_CSb_OUT;
+
+    // flip flops
+    always @(posedge CLK, negedge RSTb) begin : flip_flops
+        if(RSTb == 1'b0) begin
+            CTRL_REG_Q      <= 32'h00_00_00_00;
+            DATA_IN_Q       <= 32'h00_00_00_00;
+            DATA_OUT_Q      <= 32'h00_00_00_00;
+            DATA_OE_Q       <= 32'h00_00_00_00;
+            SHIFT_IN_Q      <= 32'h00_00_00_00;
+            SHIFT_OUT_Q     <= 32'h00_00_00_00;
+            FSM_IN_Q        <= sFSM_IN_STOP;
+            FSM_OUT_Q       <= sFSM_OUT_STOP;
+            BIT_IN_COUNT_Q  <= 10'b00_0000_0000;
+            BIT_OUT_COUNT_Q <= 10'b00_0000_0000;
+        end else begin
+            CTRL_REG_Q  <= CTRL_REG_D;
+            DATA_IN_Q   <= DATA_IN_D;
+            DATA_OUT_Q  <= DATA_OUT_D; 
+            DATA_OE_Q   <= DATA_OE_D; 
+            SHIFT_IN_Q  <= SHIFT_IN_D;
+            SHIFT_OUT_Q <= SHIFT_OUT_D;
+            FSM_IN_Q    <= FSM_IN_D;
+            FSM_OUT_Q   <= FSM_OUT_D;
+            BIT_IN_COUNT_Q  <= BIT_IN_COUNT_D;
+            BIT_OUT_COUNT_Q <= BIT_OUT_COUNT_D;
+        end
+    end
+
+endmodule
\ No newline at end of file
diff --git a/verilog/rtl/ramInterface/openRam.v b/verilog/rtl/ramInterface/openRam.v
new file mode 100644
index 0000000..8acdb3f
--- /dev/null
+++ b/verilog/rtl/ramInterface/openRam.v
@@ -0,0 +1,44 @@
+// open RAM implemented as flip flops (fall back solution)
+
+module openRam (
+    input   wire            CLK,
+    input   wire            CSb,
+    input   wire            WEb,
+    input   wire    [4:0]   ADDR,
+    input   wire    [7:0]   DATA_IN,
+    output  wire    [7:0]   DATA_OUT
+);
+    
+    // control signal flip flops
+    reg       CSb_Q;
+    reg       WEb_Q;
+    reg [4:0] ADDR_Q;
+    reg [7:0] DATA_IN_Q;
+    // "RAM" flip flops (32 x 8bit = 256bit)
+    reg [7:0] RAM_Q [31:0];
+    reg [7:0] RAM_OUT_Q;
+
+    // module output
+    assign DATA_OUT = RAM_OUT_Q;
+
+    // latch control signals first
+    always @(posedge(CLK)) begin
+        CSb_Q       <= CSb;
+        WEb_Q       <= WEb;
+        ADDR_Q      <= ADDR;
+        DATA_IN_Q   <= DATA_IN;
+    end
+
+    // actual ram cell access
+    always @(negedge(CLK)) begin
+        // new ram access
+        if (CSb_Q == 1'b0) begin
+            // valid write access
+            if (WEb_Q == 1'b0) begin
+                RAM_Q[ADDR_Q] <= DATA_IN_Q;
+                RAM_OUT_Q     <= DATA_IN_Q;
+            // valid read access
+            end else RAM_OUT_Q <= RAM_Q[ADDR_Q];
+        end
+    end
+endmodule
\ No newline at end of file
diff --git a/verilog/rtl/ramInterface/ramArbiter.v b/verilog/rtl/ramInterface/ramArbiter.v
new file mode 100644
index 0000000..37e1bc2
--- /dev/null
+++ b/verilog/rtl/ramInterface/ramArbiter.v
@@ -0,0 +1,110 @@
+// RAM Arbiter for dual port access
+
+module ramArbiter (
+    // system
+    input   wire            CLK,
+    input   wire            RSTb,
+    // ctrl interfaces 1
+    input   wire            CTRL_CSb1,
+    input   wire            CTRL_WEb1,
+    input   wire    [7:0]   CTRL_ADDR1,
+    input   wire    [31:0]  CTRL_DATA_IN1,
+    output  wire    [31:0]  CTRL_DATA_OUT1,
+    // ctrl interface 2
+    input   wire            CTRL_CSb2,
+    input   wire            CTRL_WEb2,
+    input   wire    [7:0]   CTRL_ADDR2,
+    input   wire    [31:0]  CTRL_DATA_IN2,
+    output  wire    [31:0]  CTRL_DATA_OUT2,
+    // RAM interface byte0
+    output   wire            RAM_CSb0,
+    output   wire            RAM_WEb0,
+    output   wire    [4:0]   RAM_ADDR0,
+    output   wire    [7:0]   RAM_DATA_IN0,
+    input    wire    [7:0]   RAM_DATA_OUT0,
+    // RAM interface byte1
+    output   wire            RAM_CSb1,
+    output   wire            RAM_WEb1,
+    output   wire    [4:0]   RAM_ADDR1,
+    output   wire    [7:0]   RAM_DATA_IN1,
+    input    wire    [7:0]   RAM_DATA_OUT1,
+    // RAM interface byte2
+    output   wire            RAM_CSb2,
+    output   wire            RAM_WEb2,
+    output   wire    [4:0]   RAM_ADDR2,
+    output   wire    [7:0]   RAM_DATA_IN2,
+    input    wire    [7:0]   RAM_DATA_OUT2,
+    // RAM interface byte3
+    output   wire            RAM_CSb3,
+    output   wire            RAM_WEb3,
+    output   wire    [4:0]   RAM_ADDR3,
+    output   wire    [7:0]   RAM_DATA_IN3,
+    input    wire    [7:0]   RAM_DATA_OUT3
+);
+    // internal output signals
+    reg         RAM_WEb_i;
+    reg [4:0]   RAM_ADDR_i;
+    reg [31:0]  RAM_DATA_IN_i;
+    // interface read data
+    reg [31:0]  READ_DATA1_Q;
+    reg [31:0]  READ_DATA1_D;
+    reg [31:0]  READ_DATA2_Q;
+    reg [31:0]  READ_DATA2_D;
+
+    // module outputs
+    assign RAM_CSb0     = 1'b0;
+    assign RAM_WEb0     = RAM_WEb_i;
+    assign RAM_ADDR0    = RAM_ADDR_i;
+    assign RAM_DATA_IN0 = RAM_DATA_IN_i[7:0];   
+    assign RAM_CSb1     = 1'b0;
+    assign RAM_WEb1     = RAM_WEb_i;
+    assign RAM_ADDR1    = RAM_ADDR_i;
+    assign RAM_DATA_IN1 = RAM_DATA_IN_i[15:8];   
+    assign RAM_CSb2     = 1'b0;
+    assign RAM_WEb2     = RAM_WEb_i;
+    assign RAM_ADDR2    = RAM_ADDR_i;
+    assign RAM_DATA_IN2 = RAM_DATA_IN_i[23:16];   
+    assign RAM_CSb3     = 1'b0;
+    assign RAM_WEb3     = RAM_WEb_i;
+    assign RAM_ADDR3    = RAM_ADDR_i;
+    assign RAM_DATA_IN3 = RAM_DATA_IN_i[31:24];
+
+    // interface read access (if1 always wins)
+    always @(*) begin : if_read_access
+        reg [31:0] vRamDataOut;
+        // default
+        READ_DATA1_D <= READ_DATA1_Q;
+        READ_DATA2_D <= READ_DATA2_Q;
+        // concatenate RAM data
+        vRamDataOut = {RAM_DATA_OUT3, RAM_DATA_OUT2, RAM_DATA_OUT1, RAM_DATA_OUT0};
+        // interface selection
+        if(CTRL_CSb1 == 1'b0) READ_DATA1_D <= vRamDataOut;
+        else if(CTRL_CSb2 == 1'b0 ) READ_DATA2_D <= vRamDataOut;
+    end
+    assign CTRL_DATA_OUT1 = (CTRL_CSb1 == 1'b0) ? {RAM_DATA_OUT3, RAM_DATA_OUT2, RAM_DATA_OUT1, RAM_DATA_OUT0} : READ_DATA1_Q;
+    assign CTRL_DATA_OUT2 = (CTRL_CSb2 == 1'b0) ? {RAM_DATA_OUT3, RAM_DATA_OUT2, RAM_DATA_OUT1, RAM_DATA_OUT0} : READ_DATA2_Q;
+
+    // interface multiplexer (if1 always wins)
+    always @(*) begin
+        if(CTRL_CSb1 == 1'b0) begin
+            RAM_WEb_i = CTRL_WEb1;
+            RAM_ADDR_i = CTRL_ADDR1[7:2];
+            RAM_DATA_IN_i = CTRL_DATA_IN1;
+        end else begin
+            RAM_WEb_i = CTRL_WEb2;
+            RAM_ADDR_i = CTRL_ADDR2[7:2];
+            RAM_DATA_IN_i = CTRL_DATA_IN2;
+        end
+    end
+    
+    // flip flops
+    always @(posedge CLK, negedge RSTb) begin
+        if(RSTb == 1'b0) begin
+            READ_DATA1_Q <= 32'h00_00_00_00;
+            READ_DATA2_Q <= 32'h00_00_00_00;
+        end else begin
+            READ_DATA1_Q <= READ_DATA1_D;
+            READ_DATA2_Q <= READ_DATA2_D;
+        end
+    end
+endmodule
\ No newline at end of file
diff --git a/verilog/rtl/user_proj_example.v b/verilog/rtl/user_proj_example.v
index 26081e9..880e693 100644
--- a/verilog/rtl/user_proj_example.v
+++ b/verilog/rtl/user_proj_example.v
@@ -13,7 +13,8 @@
 // limitations under the License.
 // SPDX-License-Identifier: Apache-2.0
 
-`default_nettype none
+//`default_nettype none
+`default_nettype wire
 /*
  *-------------------------------------------------------------
  *
@@ -68,98 +69,162 @@
     // 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;
-
-    wire [31:0] rdata; 
-    wire [31:0] wdata;
-    wire [BITS-1:0] count;
-
-    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}};
+    // gpio interface
+    wire            GPIO_WE;
+    wire   [3:0]    GPIO_ADDR;
+    wire   [31:0]   GPIO_DATA_IN;
+    wire   [31:0]   GPIO_DATA_OUT;
+    // RAM interface 1 (wishbone bus)
+    wire            WB_RAM_CSb;
+    wire            WB_RAM_WEb;
+    wire    [7:0]   WB_RAM_ADDR;
+    wire    [31:0]  WB_RAM_DATA_IN;
+    wire    [31:0]  WB_RAM_DATA_OUT;
+    // RAM interface 2 (gpio control)
+    wire            GPIO_RAM_CSb;
+    wire            GPIO_RAM_WEb;
+    wire    [7:0]   GPIO_RAM_ADDR;
+    wire    [31:0]  GPIO_RAM_DATA_IN;
+    wire    [31:0]  GPIO_RAM_DATA_OUT;
+    // open RAM
+    wire            RAM_CSb[3:0];
+    wire            RAM_WEb[3:0];
+    wire    [4:0]   RAM_ADDR[3:0];
+    wire    [7:0]   RAM_DATA_IN[3:0];
+    wire    [7:0]   RAM_DATA_OUT[3:0];
 
     // 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;
+    // logic analyzer output signals
+    assign la_data_out[0]       = GPIO_WE;
+    assign la_data_out[1+:2]    = GPIO_ADDR[3:2];
+    assign la_data_out[3+:32]   = GPIO_DATA_IN;
+    assign la_data_out[35]      = RAM_CSb[0];
+    assign la_data_out[36]      = RAM_WEb[0];
+    assign la_data_out[37+:5]   = RAM_ADDR[0];
+    assign la_data_out[42+:8]   = RAM_DATA_IN[0];
+    assign la_data_out[50+:8]   = RAM_DATA_OUT[0];
+    assign la_data_out[58]      = RAM_CSb[0];
+    assign la_data_out[59]      = RAM_WEb[0];
+    assign la_data_out[60+:5]   = RAM_ADDR[0];
+    assign la_data_out[65+:8]   = RAM_DATA_IN[0];
+    assign la_data_out[73+:8]  = RAM_DATA_OUT[0];
+    assign la_data_out[81]     = RAM_CSb[0];
+    assign la_data_out[82]     = RAM_WEb[0];
+    assign la_data_out[83+:5]  = RAM_ADDR[0];
+    assign la_data_out[88+:8]   = RAM_DATA_IN[0];
+    assign la_data_out[96+:8]   = RAM_DATA_OUT[0];
+    assign la_data_out[104]      = RAM_CSb[0];
+    assign la_data_out[105]      = RAM_WEb[0];
+    assign la_data_out[106+:5]   = RAM_ADDR[0];
+    assign la_data_out[111+:8]   = RAM_DATA_IN[0];
+    assign la_data_out[119+:8]   = RAM_DATA_OUT[0];
+    // logic analyter input signals (unused)
+    //la_data_in
+    //la_oenb
 
-    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)
+    // wishbone slave interface
+    wbSlave wbSlave_inst (
+        // wishbone slave interface
+        .CLK_I          (wb_clk_i),  // bus clock signal
+        .RST_I          (wb_rst_i),  // bus reset signal
+        .STB_I          (wbs_stb_i),  // bus transaction request
+        .CYC_I          (wbs_cyc_i),  // active transaction
+        .WE_I           (wbs_we_i),   // write request
+        .SEL_I          (wbs_sel_i),  // byte select for request
+        .DAT_I          (wbs_dat_i),  // data for request
+        .ADR_I          (wbs_adr_i),  // address for request
+        .ACK_O          (wbs_ack_o),  // request acknowledge, read data valid
+        .DAT_O          (wbs_dat_o),  // requested read data
+        .CTRL_WE        (GPIO_WE),
+        .CTRL_ADDR      (GPIO_ADDR),
+        .CTRL_DATA_IN   (GPIO_DATA_IN),
+        .CTRL_DATA_OUT  (GPIO_DATA_OUT),
+        .RAM_CSb        (WB_RAM_CSb),
+        .RAM_WEb        (WB_RAM_WEb),
+        .RAM_ADDR       (WB_RAM_ADDR),
+        .RAM_DATA_IN    (WB_RAM_DATA_IN),
+        .RAM_DATA_OUT   (WB_RAM_DATA_OUT)
     );
 
-endmodule
+    // gpio control module
+    gpioCtrl gpioCtrl_inst (
+        // system
+        .CLK            (wb_clk_i), 
+        .RSTb           (!wb_rst_i),
+        // control interface
+        .CTRL_WE        (GPIO_WE),
+        .CTRL_ADDR      (GPIO_ADDR),
+        .CTRL_DATA_IN   (GPIO_DATA_IN),
+        .CTRL_DATA_OUT  (GPIO_DATA_OUT),
+        // caravel gpio signaling
+        .GPIO_IN        (io_in),
+        .GPIO_OUT       (io_out),
+        .GPIO_OEb       (io_oeb),
+        // RAM interface
+        .RAM_CSb        (GPIO_RAM_CSb),
+        .RAM_WEb        (GPIO_RAM_WEb),
+        .RAM_ADDR       (GPIO_RAM_ADDR),
+        .RAM_DATA_IN    (GPIO_RAM_DATA_IN),
+        .RAM_DATA_OUT   (GPIO_RAM_DATA_OUT)
+    );
 
-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;
+    // ram arbiter
+    ramArbiter ramArbiter_inst (
+        // system
+        .CLK            (CLK_I_tb),
+        .RSTb           (!RST_I_tb),
+        // ctrl interface 1
+        .CTRL_CSb1      (WB_RAM_CSb),
+        .CTRL_WEb1      (WB_RAM_WEb),
+        .CTRL_ADDR1     (WB_RAM_ADDR),
+        .CTRL_DATA_IN1  (WB_RAM_DATA_IN),
+        .CTRL_DATA_OUT1 (WB_RAM_DATA_OUT),
+        // ctrl interface 2
+        .CTRL_CSb2      (GPIO_RAM_CSb),
+        .CTRL_WEb2      (GPIO_RAM_WEb),
+        .CTRL_ADDR2     (GPIO_RAM_ADDR),
+        .CTRL_DATA_IN2  (GPIO_RAM_DATA_IN),
+        .CTRL_DATA_OUT2 (GPIO_RAM_DATA_OUT),
+        // RAM interface byte0
+        .RAM_CSb0       (RAM_CSb[0]),
+        .RAM_WEb0       (RAM_WEb[0]),
+        .RAM_ADDR0      (RAM_ADDR[0]),
+        .RAM_DATA_IN0   (RAM_DATA_IN[0]),
+        .RAM_DATA_OUT0  (RAM_DATA_OUT[0]),
+        // RAM interface byte1
+        .RAM_CSb1       (RAM_CSb[1]),
+        .RAM_WEb1       (RAM_WEb[1]),
+        .RAM_ADDR1      (RAM_ADDR[1]),
+        .RAM_DATA_IN1   (RAM_DATA_IN[1]),
+        .RAM_DATA_OUT1  (RAM_DATA_OUT[1]),
+        // RAM interface byte2
+        .RAM_CSb2       (RAM_CSb[2]),
+        .RAM_WEb2       (RAM_WEb[2]),
+        .RAM_ADDR2      (RAM_ADDR[2]),
+        .RAM_DATA_IN2   (RAM_DATA_IN[2]),
+        .RAM_DATA_OUT2  (RAM_DATA_OUT[2]),
+        // RAM interface byte3
+        .RAM_CSb3       (RAM_CSb[3]),
+        .RAM_WEb3       (RAM_WEb[3]),
+        .RAM_ADDR3      (RAM_ADDR[3]),
+        .RAM_DATA_IN3   (RAM_DATA_IN[3]),
+        .RAM_DATA_OUT3  (RAM_DATA_OUT[3])
+    );
 
-    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
+    // 32-bit open RAM instanciation
+    generate
+        genvar vRamByte;
+        for (vRamByte=0; vRamByte<4; vRamByte=vRamByte+1) begin
+            openRam openRam_inst (
+                .CLK        (CLK_I_tb),
+                .CSb        (RAM_CSb[vRamByte]),
+                .WEb        (RAM_WEb[vRamByte]),
+                .ADDR       (RAM_ADDR[vRamByte]),
+                .DATA_IN    (RAM_DATA_IN[vRamByte]),
+                .DATA_OUT   (RAM_DATA_OUT[vRamByte])
+            );
         end
-    end
-
-endmodule
-`default_nettype wire
+    endgenerate
+endmodule
\ No newline at end of file
diff --git a/verilog/rtl/wishboneSlave/wbSlave.v b/verilog/rtl/wishboneSlave/wbSlave.v
new file mode 100644
index 0000000..7d8a6bd
--- /dev/null
+++ b/verilog/rtl/wishboneSlave/wbSlave.v
@@ -0,0 +1,76 @@
+// wishbone slave module
+//      address space:
+//          caraval user block:  0x30000000 to 0x7FFFFFFFF
+//            GPIO user block:   0x30000000 to 0x30000000F
+//            RAM user block:    0x30000080 to 0x3000000FF
+
+module wbSlave (
+    // wishbone slave interface
+    input   wire            CLK_I,  // bus clock signal
+    input   wire            RST_I,  // bus reset signal
+    input   wire            STB_I,  // bus transaction request
+    input   wire            CYC_I,  // active transaction
+    input   wire            WE_I,   // write request
+    input   wire    [3:0]   SEL_I,  // byte select for request
+    input   wire    [31:0]  DAT_I,  // data for request
+    input   wire    [31:0]  ADR_I,  // address for request
+    output  wire            ACK_O,  // request acknowledge, read data valid
+    output  wire    [31:0]  DAT_O,  // requested read data
+    // gpio interface
+    output  wire            CTRL_WE,
+    output  wire    [3:0]   CTRL_ADDR,
+    output  wire    [31:0]  CTRL_DATA_IN,
+    input   wire    [31:0]  CTRL_DATA_OUT,
+    // RAM interface
+    output  wire            RAM_CSb,
+    output  wire            RAM_WEb,
+    output  wire    [7:0]   RAM_ADDR,
+    output  wire    [31:0]  RAM_DATA_IN,
+    input   wire    [31:0]  RAM_DATA_OUT
+);
+
+    // acknowledge shift register
+    reg     [1:0]   ACK_O_Q;
+    // ram write enable edge detection 
+    wire            RAM_WE_i;
+    reg             RAM_WE_Q;
+    // control write enable edge detection
+    wire            CTRL_WE_i;
+    reg             CTRL_WE_Q;
+
+    // module output
+    assign DAT_O = DAT_O_i;
+
+    // ram access
+    assign RAM_CSb      = (ADR_I[7] == 1'b1) ? 1'b0 : 1'b1;
+    assign RAM_WE_i     = (ADR_I[7] == 1'b1) ? CYC_I & STB_I & WE_I : 1'b0;
+    assign RAM_WEb      = !(!RAM_WE_Q & RAM_WE_i);
+    assign RAM_ADDR     = ADR_I[7:0];
+    assign RAM_DATA_IN  = DAT_I;
+
+    // gpio access
+    assign CTRL_WE_i    = (ADR_I[7] == 1'b0) ? CYC_I & STB_I & WE_I : 1'b0;
+    assign CTRL_WE      = !CTRL_WE_Q & CTRL_WE_i;
+    assign CTRL_ADDR    = ADR_I[3:0];
+    assign CTRL_DATA_IN = DAT_I;
+
+    // read multiplexer
+    assign DAT_O = (ADR_I[7] == 1'b1) ? RAM_DATA_OUT : CTRL_DATA_OUT;
+
+    // acknowledge
+    assign ACK_O = ((CYC_I & STB_I) == 1'b0) ? 1'b0 : ACK_O_Q[1];
+
+    // flip flops
+    always @(posedge CLK_I, posedge RST_I) begin
+        if (RST_I == 1'b1) begin
+            ACK_O_Q     <= 1'b0;
+            RAM_WE_Q    <= 1'b0;
+            CTRL_WE_Q   <= 1'b0;
+        end else begin
+            ACK_O_Q         <= {ACK_O_Q[0], CYC_I & STB_I}; 
+            RAM_WE_Q    <= RAM_WE_i;
+            CTRL_WE_Q   <= CTRL_WE_i;
+        end
+    end
+    
+endmodule
\ No newline at end of file
diff --git a/verilog/rtl/wishboneSlave/wbSlaveTb.v b/verilog/rtl/wishboneSlave/wbSlaveTb.v
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/verilog/rtl/wishboneSlave/wbSlaveTb.v
@@ -0,0 +1,2 @@
+
+