ADD: SPI core
diff --git a/verilog/dv/wb_spi/Makefile b/verilog/dv/wb_spi/Makefile
new file mode 100644
index 0000000..b07bb75
--- /dev/null
+++ b/verilog/dv/wb_spi/Makefile
@@ -0,0 +1,31 @@
+# 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
+
+
+ 
+PWDD := $(shell pwd)
+BLOCKS := $(shell basename $(PWDD))
+
+# ---- Include Partitioned Makefiles ----
+CARAVEL_PATH = $(CARAVEL_ROOT)
+CARAVEL_VERILOG_PATH = $(CARAVEL_ROOT)/verilog
+CONFIG = caravel_user_project
+
+
+include $(MCW_ROOT)/verilog/dv/make/env.makefile
+include $(MCW_ROOT)/verilog/dv/make/var.makefile
+include $(MCW_ROOT)/verilog/dv/make/cpu.makefile
+include $(MCW_ROOT)/verilog/dv/make/sim.makefile
diff --git a/verilog/dv/wb_spi/seed.h b/verilog/dv/wb_spi/seed.h
new file mode 100644
index 0000000..7c5f14f
--- /dev/null
+++ b/verilog/dv/wb_spi/seed.h
@@ -0,0 +1 @@
+#define seed 57893
\ No newline at end of file
diff --git a/verilog/dv/wb_spi/wb_spi.c b/verilog/dv/wb_spi/wb_spi.c
new file mode 100644
index 0000000..c4b94c3
--- /dev/null
+++ b/verilog/dv/wb_spi/wb_spi.c
@@ -0,0 +1,154 @@
+/*
+ * 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
+ */
+
+// This include is relative to $CARAVEL_PATH (see Makefile)
+#include <defs.h>
+#include "seed.h"
+#include <stub.c>
+
+/*
+    Wishbone Test:
+        - Configures MPRJ lower 8-IO pins as outputs
+        - Checks counter value through the wishbone port
+*/
+
+#define reg_SRAM ((volatile uint32_t *)0x30000000)
+
+#define reg_SPI_shiftReg (*(volatile uint32_t *)0x30003000)
+#define reg_SPI_buffReg (*(volatile uint32_t *)0x30003004)
+#define reg_SPI_statusReg (*(volatile uint32_t *)0x30003008)
+#define reg_SPI_confReg (*(volatile uint32_t *)0x3000300C)
+
+
+
+void main()
+{
+
+    /*
+    IO Control Registers
+    | DM     | VTRIP | SLOW  | AN_POL | AN_SEL | AN_EN | MOD_SEL | INP_DIS | HOLDH | OEB_N | MGMT_EN |
+    | 3-bits | 1-bit | 1-bit | 1-bit  | 1-bit  | 1-bit | 1-bit   | 1-bit   | 1-bit | 1-bit | 1-bit   |
+    Output: 0000_0110_0000_1110  (0x1808) = GPIO_MODE_USER_STD_OUTPUT
+    | DM     | VTRIP | SLOW  | AN_POL | AN_SEL | AN_EN | MOD_SEL | INP_DIS | HOLDH | OEB_N | MGMT_EN |
+    | 110    | 0     | 0     | 0      | 0      | 0     | 0       | 1       | 0     | 0     | 0       |
+
+
+    Input: 0000_0001_0000_1111 (0x0402) = GPIO_MODE_USER_STD_INPUT_NOPULL
+    | DM     | VTRIP | SLOW  | AN_POL | AN_SEL | AN_EN | MOD_SEL | INP_DIS | HOLDH | OEB_N | MGMT_EN |
+    | 001    | 0     | 0     | 0      | 0      | 0     | 0       | 0       | 0     | 1     | 0       |
+    */
+
+    /* Set up the housekeeping SPI to be connected internally so	*/
+    /* that external pin changes don't affect it.			*/
+
+    reg_spi_enable = 1;
+    reg_wb_enable = 1;
+    // reg_spimaster_config = 0xa002;	// Enable, prescaler = 2,
+    // connect to housekeeping SPI
+
+    // Connect the housekeeping SPI to the SPI master
+    // so that the CSB line is not left floating.  This allows
+    // all of the GPIO pins to be used for user functions.
+
+    reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_16 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_15 = GPIO_MODE_USER_STD_INPUT_NOPULL; //UART_RX
+    reg_mprj_io_14 = GPIO_MODE_USER_STD_INPUT_NOPULL; //MISO
+    reg_mprj_io_13 = GPIO_MODE_USER_STD_OUTPUT; //SCK
+    reg_mprj_io_12 = GPIO_MODE_USER_STD_OUTPUT; //MOSI
+
+
+    // //Verify SRAM
+    // for (int i = 0; i < 32; i++)
+    // {
+    //    *(reg_SRAM+(i*4)) = i*1024;
+    // }
+
+    // for (int i = 0; i < 32; i++)
+    // {
+    //    if(*(reg_SRAM+(i*4)) != i * 1024 )
+    //     reg_mprj_datal = 0xAB800000;
+    // }
+    
+
+
+    /* Apply configuration */
+    reg_mprj_xfer = 1;
+    while (reg_mprj_xfer == 1)
+        ;
+
+    reg_la2_oenb = reg_la2_iena = 0x00000000; // [95:64]
+
+    // Flag start of the test
+    reg_mprj_datal = 0xAB600000;
+
+    /* UART Setup: */
+    /* 8-N-1 115200B for 50Mhz System Clock */
+    int i = 0;
+    bool error = false;
+    unsigned baud, data, data_prev;
+    unsigned lfsr = seed;
+    unsigned bit;
+    unsigned period = 0;
+
+    unsigned rx_status = 0;
+    
+    do
+    {
+        rx_status = 0;
+        /* taps: 16 14 13 11; characteristic polynomial: x^16 + x^14 + x^13 + x^11 + 1 */
+        bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5)) & 1;
+        lfsr = (lfsr >> 1) | (bit << 15);
+        
+        data = lfsr % 256;     
+        reg_SPI_buffReg = data;
+        
+        int i = 0;
+        while(rx_status == 0 )
+            rx_status = reg_SPI_statusReg;
+        if(period % 2 == 1)
+            if(reg_SPI_shiftReg != data_prev)
+            {
+                error = true;
+                break;
+            }
+        data_prev = data;
+        ++period;
+    } while (period < 10 && lfsr != seed);
+    if(error)
+        reg_mprj_datal = 0xAB800000;
+    else
+        reg_mprj_datal = 0xAB700000;
+    
+
+
+}
+
diff --git a/verilog/dv/wb_spi/wb_spi_tb.v b/verilog/dv/wb_spi/wb_spi_tb.v
new file mode 100644
index 0000000..95cb373
--- /dev/null
+++ b/verilog/dv/wb_spi/wb_spi_tb.v
@@ -0,0 +1,236 @@
+// 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
+
+`default_nettype none
+
+`timescale 1 ns / 1 ps
+
+`define PER 25 // period
+
+
+module wb_spi_tb ();
+  reg clock ;
+  reg RSTB  ;
+  reg CSB   ;
+  reg power1, power2;
+  reg power3, power4;
+
+  wire        gpio     ;
+  wire [37:0] mprj_io  ;
+  wire [ 7:0] mprj_io_0;
+  wire [15:0] checkbits;
+
+
+  integer fd ;
+  integer tmp;
+
+  reg [8*10:0] uart_data_in = "de 1b2";
+
+  reg [23:0] dec_baud;
+  reg [ 7:0] dec_data;
+
+
+  reg [7:0] tx_data;
+
+  wire sck_pin;
+  wire mosi_pin;
+  reg miso_pin;
+
+  task  spi_transaction;
+    begin : task_block
+      integer i;
+      miso_pin = 1'b0;
+      for ( i=7 ;i > -1; i=i-1 )
+        begin : for_block
+          @(posedge sck_pin);
+          miso_pin = tx_data[i];
+          rx_data = {rx_data[6:0],mosi_pin}; 
+        end
+        @(negedge sck_pin);
+        miso_pin = 1'b0;
+    end
+  endtask
+
+  wire        rx                ;
+  reg  [23:0] baud_clk =  8; // clk_freq is divided by for 
+  reg  [ 7:0] rx_data  = 8'd0   ;
+
+  // task spi_receive;
+  //   begin : rx_block
+  //     repeat(8)
+  //     begin
+  //       @(posedge sck_pin); 
+  //       rx_data = {rx_data[6:0],mosi_pin};
+  //     end
+  //   end
+  // endtask
+
+
+
+
+  assign checkbits = mprj_io[31:16];
+
+  assign mprj_io[3] = 1'b1;
+  assign mosi_pin = mprj_io[12];
+  assign sck_pin = mprj_io[13];
+  assign mprj_io[14] = miso_pin;
+
+  // External clock is used by default.  Make this artificially fast for the
+  // simulation.  Normally this would be a slow clock and the digital PLL
+  // would be the fast clock.
+
+  //50MHz
+  always #(`PER/2) clock <= (clock === 1'b0);
+
+  initial
+    begin
+      clock = 0;
+    end
+
+  initial
+    begin
+      $dumpfile("wb_spi.vcd");
+      $dumpvars(0, wb_spi_tb);
+
+      // Repeat cycles of 1000 clock edges as needed to complete testbench
+      repeat (70)
+        begin
+          repeat (10000) @(posedge clock);
+          // $display("+1000 cycles");
+        end
+      $display("%c[1;31m",27);
+`ifdef GL
+
+      $display ("Monitor: Timeout, Test Mega-Project WB Port (GL) Failed");
+`else
+      $display ("Monitor: Timeout, Test Mega-Project WB Port (RTL) Failed");
+`endif
+
+      $display("%c[0m",27);
+      $finish;
+    end
+
+  assign rx = uut.mprj.io_out[16];
+
+  initial
+    begin
+      tx_data = 8'd0;
+      wait(checkbits[15:4] == 12'hAB6);
+      $display("Monitor: MPRJ-Logic WB Started");
+      while(checkbits[15:4] != 12'hAB7)
+        begin
+          spi_transaction();
+          tx_data = rx_data;
+        end
+
+    end
+
+
+  initial
+    begin
+      wait(checkbits[15:4] == 12'hAB7 || checkbits[15:4] == 12'hAB8 );
+
+      if(checkbits[15:4] == 12'hAB8)
+        begin
+          $display("SPI failed!");
+          $finish;
+        end
+        else
+          begin
+    `ifdef GL
+            $display("Monitor: Mega-Project WB (GL) Passed");
+    `else
+            $display("Monitor: Mega-Project WB (RTL) Passed");
+    `endif
+            $finish;
+          end
+    end
+
+  initial
+    begin
+      RSTB <= 1'b0;
+      CSB  <= 1'b1;		// Force CSB high
+      #2000;
+      RSTB <= 1'b1;	    	// Release reset
+      #100000;
+      CSB = 1'b0;		// CSB can be released
+    end
+
+  initial
+    begin		// Power-up sequence
+      power1 <= 1'b0;
+      power2 <= 1'b0;
+      #200;
+      power1 <= 1'b1;
+      #200;
+      power2 <= 1'b1;
+    end
+
+
+
+  wire flash_csb;
+  wire flash_clk;
+  wire flash_io0;
+  wire flash_io1;
+
+  wire VDD3V3      = power1;
+  wire VDD1V8      = power2;
+  wire USER_VDD3V3 = power3;
+  wire USER_VDD1V8 = power4;
+  wire VSS         = 1'b0  ;
+
+  caravel uut (
+    .vddio    (VDD3V3   ),
+    .vddio_2  (VDD3V3   ),
+    .vssio    (VSS      ),
+    .vssio_2  (VSS      ),
+    .vdda     (VDD3V3   ),
+    .vssa     (VSS      ),
+    .vccd     (VDD1V8   ),
+    .vssd     (VSS      ),
+    .vdda1    (VDD3V3   ),
+    .vdda1_2  (VDD3V3   ),
+    .vdda2    (VDD3V3   ),
+    .vssa1    (VSS      ),
+    .vssa1_2  (VSS      ),
+    .vssa2    (VSS      ),
+    .vccd1    (VDD1V8   ),
+    .vccd2    (VDD1V8   ),
+    .vssd1    (VSS      ),
+    .vssd2    (VSS      ),
+    .clock    (clock    ),
+    .gpio     (gpio     ),
+    .mprj_io  (mprj_io  ),
+    .flash_csb(flash_csb),
+    .flash_clk(flash_clk),
+    .flash_io0(flash_io0),
+    .flash_io1(flash_io1),
+    .resetb   (RSTB     )
+  );
+
+  spiflash #(.FILENAME("wb_spi.hex")) spiflash (
+    .csb(flash_csb),
+    .clk(flash_clk),
+    .io0(flash_io0),
+    .io1(flash_io1),
+    .io2(         ), // not used
+    .io3(         )  // not used
+  );
+
+
+
+endmodule
+
+`default_nettype wire
diff --git a/verilog/dv/wb_spi/wb_uart.elf b/verilog/dv/wb_spi/wb_uart.elf
new file mode 100755
index 0000000..eaaca29
--- /dev/null
+++ b/verilog/dv/wb_spi/wb_uart.elf
Binary files differ
diff --git a/verilog/includes/includes.rtl.caravel_user_project b/verilog/includes/includes.rtl.caravel_user_project
index 032b622..f473d82 100644
--- a/verilog/includes/includes.rtl.caravel_user_project
+++ b/verilog/includes/includes.rtl.caravel_user_project
@@ -2,6 +2,7 @@
 -v $(USER_PROJECT_VERILOG)/rtl/user_project_wrapper.v
 -v $(USER_PROJECT_VERILOG)/rtl/user_proj_example.v
 -v $(USER_PROJECT_VERILOG)/rtl/sram/sram_wb_wrapper.sv
+-v $(USER_PROJECT_VERILOG)/rtl/spi/tiny_spi.v
 -v $(USER_PROJECT_VERILOG)/rtl/wb_interconnect/wb_interconnect.sv
 -v $(USER_PROJECT_VERILOG)/rtl/wbuart32/rxuart.v
 -v $(USER_PROJECT_VERILOG)/rtl/wbuart32/txuart.v
diff --git a/verilog/rtl/spi/tiny_spi.v b/verilog/rtl/spi/tiny_spi.v
new file mode 100644
index 0000000..450276d
--- /dev/null
+++ b/verilog/rtl/spi/tiny_spi.v
@@ -0,0 +1,261 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  tiny_spi.v                                                  ////
+////                                                              ////
+////  This file is part of the TINY SPI IP core project           ////
+////  http://www.opencores.org/projects/tiny_spi/                 ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Thomas Chou <thomas@wytron.com.tw>                    ////
+////                                                              ////
+////  All additional information is avaliable in the README       ////
+////  file.                                                       ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2010 Authors                                   ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+
+module tiny_spi (
+`ifdef USE_POWER_PINS
+  input  wire        vccd1, // User area 1 1.8V supply
+  input  wire        vssd1, // User area 1 digital ground
+    `endif
+  // system
+  input    wire          rst_i,
+  input    wire          clk_i,
+  // memory mapped
+  input    wire          stb_i,
+  input    wire          we_i ,
+  output   wire   [31:0] dat_o,
+  input    wire   [31:0] dat_i,
+  output   wire          int_o,
+  input    wire   [ 2:0] adr_i,
+  input    wire          cyc_i, // comment out for avalon
+  output   wire          ack_o, // comment out for avalon
+  // spi
+  output   wire          MOSI ,
+  output   wire          SCLK ,
+  input    wire          MISO
+);
+
+  parameter BAUD_WIDTH = 8;
+  parameter BAUD_DIV   = 8;
+  parameter SPI_MODE   = 0;
+  parameter BC_WIDTH   = 3;
+  //parameter DIV_WIDTH = BAUD_DIV ? $clog2(BAUD_DIV / 2 - 1) : BAUD_WIDTH;
+  parameter DIV_WIDTH = $clog2(BAUD_DIV / 2 - 1);
+
+  reg  [          7:0] sr8, bb8;
+  wire [          7:0] sr8_sf;
+  reg  [ BC_WIDTH-1:0] bc, bc_next;
+  reg  [DIV_WIDTH-1:0] ccr   ;
+  reg  [DIV_WIDTH-1:0] cc, cc_next;
+  wire                 misod ;
+  wire                 cstb, wstb, bstb, istb;
+  reg                  sck   ;
+  reg                  sf, ld;
+  reg                  bba   ; // buffer flag
+  reg                  txren, txeen;
+  wire                 txr, txe;
+  wire                 cpol, cpha;
+  reg                  cpolr, cphar;
+  wire                 wr    ;
+  // wire 	  cyc_i; // comment out for wishbone
+  // wire 	  ack_o; // comment out for wishbone
+  // assign cyc_i = 1'b1;  // comment out for wishbone
+  
+  assign ack_o  = stb_i & cyc_i; // zero wait
+  assign wr     = stb_i & cyc_i & we_i & ack_o;
+  assign wstb   = wr & (adr_i == 1);
+  assign istb   = wr & (adr_i == 2);
+  assign cstb   = wr & (adr_i == 3);
+  assign bstb   = wr & (adr_i == 4);
+  assign sr8_sf = { sr8[6:0],misod };
+  assign dat_o  =
+    (sr8 & {8{(adr_i == 0)}})
+    | (bb8 & {8{(adr_i == 1)}})
+    | ({ txr, txe } & {8{(adr_i == 2)}})
+    ;
+
+  parameter
+    IDLE = 0,
+    PHASE1 = 1,
+    PHASE2 = 2
+    ;
+
+  reg [1:0] spi_seq, spi_seq_next;
+  always @(posedge clk_i )
+    if (rst_i)
+      spi_seq <= IDLE;
+    else
+      spi_seq <= spi_seq_next;
+
+  wire high_val, low_val;
+  assign high_val = 1'b1;
+  assign low_val  = 1'b0;
+  always @(posedge clk_i)
+    begin
+      if(rst_i)
+        begin
+          cc <= {2{1'b0}};
+          bc <= {3{1'b0}};
+        end
+      else
+        begin
+          cc <= cc_next;
+          bc <= bc_next;
+        end
+
+    end
+
+  always @(/*AS*/bba or bc or cc or ccr or cpha or cpol or spi_seq)
+    begin
+      sck     = cpol;
+      cc_next = BAUD_DIV ? (BAUD_DIV / 2 - 1) : ccr;
+      bc_next = bc;
+      ld      = 1'b0;
+      sf      = 1'b0;
+
+      case (spi_seq)
+        IDLE :
+          begin
+            if (bba)
+              begin
+                bc_next      = 7;
+                ld           = 1'b1;
+                spi_seq_next = PHASE2;
+              end
+            else
+              spi_seq_next = IDLE;
+          end
+        PHASE2 :
+          begin
+            sck = (cpol ^ cpha);
+            if (cc == 0)
+              spi_seq_next = PHASE1;
+            else
+              begin
+                cc_next      = cc - 1;
+                spi_seq_next = PHASE2;
+              end
+          end
+        PHASE1 :
+          begin
+            sck = ~(cpol ^ cpha);
+            if (cc == 0)
+              begin
+                bc_next = bc -1;
+                sf      = 1'b1;
+                if (bc == 0)
+                  begin
+                    if (bba)
+                      begin
+                        bc_next      = 7;
+                        ld           = 1'b1;
+                        spi_seq_next = PHASE2;
+                      end
+                    else
+                      spi_seq_next = IDLE;
+                  end
+                else
+                  spi_seq_next = PHASE2;
+              end
+            else
+              begin
+                cc_next      = cc - 1;
+                spi_seq_next = PHASE1;
+              end
+          end
+      endcase
+    end // always @ (...
+
+  always @(posedge clk_i)
+    begin
+      if(rst_i)
+        begin
+          { cpolr, cphar } <= 2'b0;
+          { txren, txeen } <= 2'b0;
+          ccr <= 8'd0;
+          sr8 <= 8'd0;
+          bb8 <= 8'd0;
+        end
+
+      else
+        begin
+          if (cstb) // control reg
+            { cpolr, cphar } <= dat_i;
+          else
+            { cpolr, cphar } <= { cpolr, cphar };
+
+          if (istb) // irq enable reg
+            { txren, txeen } <= dat_i;
+          else
+            { txren, txeen } <= { txren, txeen };
+
+          if (bstb) // baud reg
+            ccr <= dat_i;
+          else
+            ccr <= ccr;
+
+          if (ld)   // shift reg
+            sr8 <= bb8;
+          else if (sf)
+            sr8 <= sr8_sf;
+          else
+            sr8 <= sr8;
+
+          if (wstb) // buffer reg
+            bb8 <= dat_i;
+          else if (ld)
+            bb8 <= (spi_seq == IDLE) ? sr8 : sr8_sf;
+          else
+            bb8 <= bb8;
+        end
+
+    end // always @ (posedge clk_i)
+
+  always @(posedge clk_i)
+    begin
+      if (rst_i)
+        bba <= 1'b0;
+      else if (wstb)
+        bba <= 1'b1;
+      else if (ld)
+        bba <= 1'b0;
+      else
+        bba <= bba;
+    end
+
+  assign { cpol, cpha } = ((SPI_MODE >= 0) & (SPI_MODE < 4)) ?
+    SPI_MODE : { cpolr, cphar };
+  assign txe   = (spi_seq == IDLE);
+  assign txr   = ~bba;
+  assign int_o = (txr & txren) | (txe & txeen);
+  assign SCLK  = sck;
+  assign MOSI  = sr8[7];
+  assign misod = MISO;
+
+endmodule
diff --git a/verilog/rtl/user_proj_example.v b/verilog/rtl/user_proj_example.v
index f473a98..952b2cd 100644
--- a/verilog/rtl/user_proj_example.v
+++ b/verilog/rtl/user_proj_example.v
@@ -109,13 +109,27 @@
   wire                      s1_wb_stb_i;
   wire [               8:0] s1_wb_adr_o;
   wire                      s1_wb_we_i ;
-  wire [  UART_DATA_WD-1:0] s1_wb_dat_i;
+  wire [  WB_WIDTH-1:0] s1_wb_dat_i;
   wire [UART_DATA_WD/8-1:0] s1_wb_sel_i;
-  wire [  UART_DATA_WD-1:0] s1_wb_dat_o;
+  wire [  WB_WIDTH-1:0] s1_wb_dat_o;
   wire                      s1_wb_ack_o;
 
 
 
+  //---------------------------------------------------------------------
+  // SPI
+  //---------------------------------------------------------------------
+  wire                s3_wb_cyc_i;
+  wire                s3_wb_stb_i;
+  wire [         8:0] s3_wb_adr_o;
+  wire                s3_wb_we_i ;
+  wire [WB_WIDTH-1:0] s3_wb_dat_i;
+  //wire [UART_DATA_WD/8-1:0] s3_wb_sel_i;
+  wire [WB_WIDTH-1:0] s3_wb_dat_o;
+  wire                s3_wb_ack_o;
+
+
+
   wire [8:0] concat_s0_addr;
   wire [8:0] concat_s1_addr;
 
@@ -156,7 +170,7 @@
     .s1_wb_sel_o(s1_wb_sel_i),
     .s1_wb_we_o (s1_wb_we_i ),
     .s1_wb_cyc_o(s1_wb_cyc_i),
-    .s1_wb_stb_o(s1_wb_stb_i)
+    .s1_wb_stb_o(s1_wb_stb_i),
     
     // Slave 2 Interface
     // .s2_wb_dat_i(),
@@ -169,14 +183,14 @@
     // .s2_wb_stb_o(),
     
     // Slave 3 Interface
-    // .s3_wb_dat_i(),
-    // .s3_wb_ack_i(),
-    // .s3_wb_dat_o(),
-    // .s3_wb_adr_o(),
-    // .s3_wb_sel_o(),
-    // .s3_wb_we_o (),
-    // .s3_wb_cyc_o(),
-    // .s3_wb_stb_o()
+    .s3_wb_dat_i(s3_wb_dat_o),
+    .s3_wb_ack_i(s3_wb_ack_o),
+    .s3_wb_dat_o(s3_wb_dat_i),
+    .s3_wb_adr_o(s3_wb_adr_o),
+    .s3_wb_sel_o(),
+    .s3_wb_we_o (s3_wb_we_i ),
+    .s3_wb_cyc_o(s3_wb_cyc_i),
+    .s3_wb_stb_o(s3_wb_stb_i)
   );
 
 
@@ -218,7 +232,7 @@
 
 
 
-  wbuart wbuart_dut (
+  wbuart wbuart_inst (
     `ifdef USE_POWER_PINS
     .vccd1            (vccd1           ), // User area 1 1.8V supply
     .vssd1            (vssd1           ), // User area 1 digital ground
@@ -244,5 +258,34 @@
     .o_uart_txfifo_int(                )
   );
 
+
+  tiny_spi #(
+    .BAUD_WIDTH(0),
+    .BAUD_DIV  (8),
+    .SPI_MODE  (0),
+    .BC_WIDTH  (3),
+    .DIV_WIDTH (2),
+    .IDLE      (0)
+  ) tiny_spi_inst (
+    `ifdef USE_POWER_PINS
+    .vccd1(vccd1           ), // User area 1 1.8V supply
+    .vssd1(vssd1           ), // User area 1 digital ground
+    `endif
+    .rst_i(wb_rst_i        ),
+    .clk_i(wb_clk_i        ),
+    .stb_i(s3_wb_stb_i     ),
+    .we_i (s3_wb_we_i      ),
+    .dat_o(s3_wb_dat_o     ),
+    .dat_i(s3_wb_dat_i     ),
+    .int_o(                ),
+    .adr_i(s3_wb_adr_o[2:0]),
+    .cyc_i(s3_wb_cyc_i     ),
+    .ack_o(s3_wb_ack_o     ),
+    .MOSI (io_out[12]      ),
+    .SCLK (io_out[13]      ),
+    .MISO (io_in[14]       )
+  );
+
+
 endmodule
 `default_nettype wire
diff --git a/verilog/rtl/wb_interconnect/wb_interconnect.sv b/verilog/rtl/wb_interconnect/wb_interconnect.sv
index 9de2f75..ae1cbff 100644
--- a/verilog/rtl/wb_interconnect/wb_interconnect.sv
+++ b/verilog/rtl/wb_interconnect/wb_interconnect.sv
@@ -56,7 +56,7 @@
   output wire [ 3:0] s1_wb_sel_o,
   output wire        s1_wb_we_o ,
   output wire        s1_wb_cyc_o,
-  output wire        s1_wb_stb_o
+  output wire        s1_wb_stb_o,
   // Slave 2 Interface
   // input	logic [31:0]   s2_wb_dat_i,
   // input	logic 	       s2_wb_ack_i,
@@ -67,14 +67,16 @@
   // output	wire  	       s2_wb_cyc_o,
   // output	wire  	       s2_wb_stb_o,
   // Slave 3 Interface
-  // input	logic [31:0]   s3_wb_dat_i,
-  // input	logic 	       s3_wb_ack_i,
-  // output	wire  [31:0]   s3_wb_dat_o,
-  // output	wire  [8:0]    s3_wb_adr_o,
-  // output	wire  [3:0]    s3_wb_sel_o,
-  // output	wire  	       s3_wb_we_o,
-  // output	wire  	       s3_wb_cyc_o,
-  // output	wire  	       s3_wb_stb_o
+  input	logic [31:0]   s3_wb_dat_i,
+  input	logic 	       s3_wb_ack_i,
+  output	wire  [31:0]   s3_wb_dat_o,
+  output	wire  [8:0]    s3_wb_adr_o,
+  output	wire  [3:0]    s3_wb_sel_o,
+  output	wire  	       s3_wb_we_o,
+  output	wire  	       s3_wb_cyc_o,
+  output	wire  	       s3_wb_stb_o
+  
+  
 );
 
 
@@ -90,12 +92,12 @@
 
 
   wire [31:0] s_bus_rd_wb_dat = (m0_wb_adr_i[13:12] == 2'b00) ? s0_wb_dat_i :
-    (m0_wb_adr_i[13:12] == 2'b01) ? s1_wb_dat_i : 32'd0 ;// :
-  //(m0_wb_adr_i[13:12] == 2'b10) ? s2_wb_dat_i :
+    (m0_wb_adr_i[13:12] == 2'b01) ? s1_wb_dat_i :  
+    (m0_wb_adr_i[13:12] == 2'b11) ? s3_wb_dat_i : 32'd0;
   //s3_wb_dat_i;
   wire        s_bus_rd_wb_ack = (m0_wb_adr_i[13:12] == 2'b00) ? s0_wb_ack_i :
-    (m0_wb_adr_i[13:12] == 2'b01) ? s1_wb_ack_i : 1'b0 ; // :
-  //(m0_wb_adr_i[13:12] == 2'b10) ? s2_wb_ack_i :
+    (m0_wb_adr_i[13:12] == 2'b01) ? s1_wb_ack_i :
+    (m0_wb_adr_i[13:12] == 2'b11) ? s3_wb_ack_i : 1'b0 ; // :
   //s3_wb_ack_i;
 
   //wire [31:0] s_bus_rd_wb_dat = s0_wb_dat_i;
@@ -141,12 +143,12 @@
   // assign s2_wb_cyc_o = (m0_wb_tid_reg == 2'b10) ? m0_wb_cyc_reg : 2'b00;
   // assign s2_wb_stb_o = (m0_wb_tid_reg == 2'b10) ? m0_wb_stb_reg : 2'b00;
 
-  // assign s3_wb_dat_o = (m0_wb_tid_reg == 2'b11) ? m0_wb_dat_i_reg : 2'b00;
-  // assign s3_wb_adr_o = (m0_wb_tid_reg == 2'b11) ? m0_wb_adr_reg : 2'b00;
-  // assign s3_wb_sel_o = (m0_wb_tid_reg == 2'b11) ? m0_wb_sel_reg : 2'b00;
-  // assign s3_wb_we_o  = (m0_wb_tid_reg == 2'b11) ? m0_wb_we_reg  : 2'b00;
-  // assign s3_wb_cyc_o = (m0_wb_tid_reg == 2'b11) ? m0_wb_cyc_reg : 2'b00;
-  // assign s3_wb_stb_o = (m0_wb_tid_reg == 2'b11) ? m0_wb_stb_reg : 2'b00;
+  assign s3_wb_dat_o = (m0_wb_tid_reg == 2'b11) ? m0_wb_dat_i_reg : 2'b00;
+  assign s3_wb_adr_o = (m0_wb_tid_reg == 2'b11) ? m0_wb_adr_reg : 2'b00;
+  assign s3_wb_sel_o = (m0_wb_tid_reg == 2'b11) ? m0_wb_sel_reg : 2'b00;
+  assign s3_wb_we_o  = (m0_wb_tid_reg == 2'b11) ? m0_wb_we_reg  : 2'b00;
+  assign s3_wb_cyc_o = (m0_wb_tid_reg == 2'b11) ? m0_wb_cyc_reg : 2'b00;
+  assign s3_wb_stb_o = (m0_wb_tid_reg == 2'b11) ? m0_wb_stb_reg : 2'b00;
 
   assign m0_wb_dat_o = s_bus_rd_wb_dat;
   assign m0_wb_ack_o = s_bus_rd_wb_ack;