In spite of many errors that still need fixing, this is a major advance
over the previous commit.  All verilog modules are in place more or less
as intended, with various functions such as the housekeeping SPI placed
on user area pads, with the ability to switch to user control from the
configuration.  The pad control bits are local to the pads and loaded
via serial shift register, so that there are not hundreds of control wires
feeding into the user space.  The user has three basic controls over each
pad:  in, out, and outenb.  Two timer/counters and an SPI master have been
added to the SoC.  The SPI master shares I/O with the housekeeping SPI, so
that all housekeeping SPI registers can be accessed from the SoC directly.
diff --git a/verilog/dv/caravel/defs.h b/verilog/dv/caravel/defs.h
index 68ef6b0..559151d 100644
--- a/verilog/dv/caravel/defs.h
+++ b/verilog/dv/caravel/defs.h
@@ -34,59 +34,67 @@
 #define reg_la3_ena (*(volatile uint32_t*)0x2200001c)
 
 // Mega Project Control (0x2300_0000)
-#define reg_mprj_io_0 (*(volatile uint32_t*)0x23000000)
-#define reg_mprj_io_1 (*(volatile uint32_t*)0x23000004)
-#define reg_mprj_io_2 (*(volatile uint32_t*)0x23000008)
-#define reg_mprj_io_3 (*(volatile uint32_t*)0x2300000c)
-#define reg_mprj_io_4 (*(volatile uint32_t*)0x23000010)
-#define reg_mprj_io_5 (*(volatile uint32_t*)0x23000014)
-#define reg_mprj_io_6 (*(volatile uint32_t*)0x23000018)
+#define reg_mprj_data (*(volatile uint32_t*)0x23000000)
+#define reg_mprj_xfer (*(volatile uint32_t*)0x23000004)
 
-#define reg_mprj_io_7 (*(volatile uint32_t*)0x2300001c)
-#define reg_mprj_io_8 (*(volatile uint32_t*)0x23000020)
-#define reg_mprj_io_9 (*(volatile uint32_t*)0x23000024)
-#define reg_mprj_io_10 (*(volatile uint32_t*)0x23000028)
+#define reg_mprj_io_0 (*(volatile uint32_t*)0x23000008)
+#define reg_mprj_io_1 (*(volatile uint32_t*)0x2300000c)
+#define reg_mprj_io_2 (*(volatile uint32_t*)0x23000010)
+#define reg_mprj_io_3 (*(volatile uint32_t*)0x23000014)
+#define reg_mprj_io_4 (*(volatile uint32_t*)0x23000018)
+#define reg_mprj_io_5 (*(volatile uint32_t*)0x2300001c)
+#define reg_mprj_io_6 (*(volatile uint32_t*)0x23000020)
 
-#define reg_mprj_io_11 (*(volatile uint32_t*)0x2300002c)
-#define reg_mprj_io_12 (*(volatile uint32_t*)0x23000030)
-#define reg_mprj_io_13 (*(volatile uint32_t*)0x23000034)
-#define reg_mprj_io_14 (*(volatile uint32_t*)0x23000038)
+#define reg_mprj_io_7 (*(volatile uint32_t*)0x23000024)
+#define reg_mprj_io_8 (*(volatile uint32_t*)0x23000028)
+#define reg_mprj_io_9 (*(volatile uint32_t*)0x2300002c)
+#define reg_mprj_io_10 (*(volatile uint32_t*)0x23000030)
 
-#define reg_mprj_io_15 (*(volatile uint32_t*)0x2300003c)
-#define reg_mprj_io_16 (*(volatile uint32_t*)0x23000040)
-#define reg_mprj_io_17 (*(volatile uint32_t*)0x23000044)
-#define reg_mprj_io_18 (*(volatile uint32_t*)0x23000048)
+#define reg_mprj_io_11 (*(volatile uint32_t*)0x23000034)
+#define reg_mprj_io_12 (*(volatile uint32_t*)0x23000038)
+#define reg_mprj_io_13 (*(volatile uint32_t*)0x2300003c)
+#define reg_mprj_io_14 (*(volatile uint32_t*)0x23000040)
 
-#define reg_mprj_io_19 (*(volatile uint32_t*)0x2300004c)
-#define reg_mprj_io_20 (*(volatile uint32_t*)0x23000050)
-#define reg_mprj_io_21 (*(volatile uint32_t*)0x23000054)
-#define reg_mprj_io_22 (*(volatile uint32_t*)0x23000058)
+#define reg_mprj_io_15 (*(volatile uint32_t*)0x23000044)
+#define reg_mprj_io_16 (*(volatile uint32_t*)0x23000048)
+#define reg_mprj_io_17 (*(volatile uint32_t*)0x2300004c)
+#define reg_mprj_io_18 (*(volatile uint32_t*)0x23000050)
 
-#define reg_mprj_io_23 (*(volatile uint32_t*)0x2300005c)
-#define reg_mprj_io_24 (*(volatile uint32_t*)0x23000060)
-#define reg_mprj_io_25 (*(volatile uint32_t*)0x23000064)
-#define reg_mprj_io_26 (*(volatile uint32_t*)0x23000068)
+#define reg_mprj_io_19 (*(volatile uint32_t*)0x23000054)
+#define reg_mprj_io_20 (*(volatile uint32_t*)0x23000058)
+#define reg_mprj_io_21 (*(volatile uint32_t*)0x2300005c)
+#define reg_mprj_io_22 (*(volatile uint32_t*)0x23000060)
 
-#define reg_mprj_io_27 (*(volatile uint32_t*)0x2300006c)
-#define reg_mprj_io_28 (*(volatile uint32_t*)0x23000070)
-#define reg_mprj_io_29 (*(volatile uint32_t*)0x23000074)
-#define reg_mprj_io_30 (*(volatile uint32_t*)0x23000078)
-#define reg_mprj_io_31 (*(volatile uint32_t*)0x2300007c)
+#define reg_mprj_io_23 (*(volatile uint32_t*)0x23000064)
+#define reg_mprj_io_24 (*(volatile uint32_t*)0x23000068)
+#define reg_mprj_io_25 (*(volatile uint32_t*)0x2300006c)
+#define reg_mprj_io_26 (*(volatile uint32_t*)0x23000070)
+
+#define reg_mprj_io_27 (*(volatile uint32_t*)0x23000074)
+#define reg_mprj_io_28 (*(volatile uint32_t*)0x23000078)
+#define reg_mprj_io_29 (*(volatile uint32_t*)0x2300007c)
+#define reg_mprj_io_30 (*(volatile uint32_t*)0x23000080)
+#define reg_mprj_io_31 (*(volatile uint32_t*)0x23000084)
 
 // Mega Project Slaves (0x3000_0000)
 #define reg_mprj_slave (*(volatile uint32_t*)0x30000000)
 
 // Flash Control SPI Configuration (2D00_0000)
-#define reg_spictrl (*(volatile uint32_t*)0x2D000000)         
+#define reg_spictrl (*(volatile uint32_t*)0x2d000000)         
 
-// House-Keeping SPI Read-Only Registers (0x2E00_0000)
-#define reg_spi_config     (*(volatile uint32_t*)0x2E000000)
-#define reg_spi_enables    (*(volatile uint32_t*)0x2E000004)
-#define reg_spi_pll_config (*(volatile uint32_t*)0x2E000008)
-#define reg_spi_mfgr_id    (*(volatile uint32_t*)0x2E00000c)
-#define reg_spi_prod_id    (*(volatile uint32_t*)0x2E000010)
-#define reg_spi_mask_rev   (*(volatile uint32_t*)0x2E000014)
-#define reg_spi_pll_bypass (*(volatile uint32_t*)0x2E000018)
+// Counter-Timer 0 Configuration
+#define reg_timer0_config (*(volatile uint32_t*)0x21100000)
+#define reg_timer0_value  (*(volatile uint32_t*)0x21100004)
+#define reg_timer0_data   (*(volatile uint32_t*)0x21100008)
+
+// Counter-Timer 1 Configuration
+#define reg_timer1_config (*(volatile uint32_t*)0x21200000)
+#define reg_timer1_value  (*(volatile uint32_t*)0x21200004)
+#define reg_timer1_data   (*(volatile uint32_t*)0x21200008)
+
+// SPI Master Configuration
+#define reg_spimaster_config (*(volatile uint32_t*)0x21300000)
+#define reg_spimaster_data   (*(volatile uint32_t*)0x21300004)
 
 // System Area (0x2F00_0000)
 #define reg_pll_out_dest  (*(volatile uint32_t*)0x2F00000c)
@@ -94,11 +102,22 @@
 #define reg_irq7_source (*(volatile uint32_t*)0x2F000014)
 #define reg_irq8_source (*(volatile uint32_t*)0x2F000018)
 
-// Crosbbar Slave Addresses (0x8000_0000 - 0xB000_0000)
+// Crossbar Slave Addresses (0x8000_0000 - 0xB000_0000)
 #define qspi_ctrl_slave    (*(volatile uint32_t*)0x80000000)
 #define storage_area_slave (*(volatile uint32_t*)0x90000000)
 #define mega_any_slave1    (*(volatile uint32_t*)0xA0000000)
 #define mega_any_slave2    (*(volatile uint32_t*)0xB0000000)
 
+// Useful GPIO mode values
+#define GPIO_MODE_MGMT_STD_INPUT_NOPULL    0x0403
+#define GPIO_MODE_MGMT_STD_INPUT_PULLDOWN  0x0803
+#define GPIO_MODE_MGMT_STD_INPUT_PULLUP	   0x0c03
+#define GPIO_MODE_MGMT_STD_OUTPUT	   0x1801
+
+#define GPIO_MODE_USER_STD_INPUT_NOPULL	   0x0402
+#define GPIO_MODE_USER_STD_INPUT_PULLDOWN  0x0802
+#define GPIO_MODE_USER_STD_INPUT_PULLUP	   0x0c02
+#define GPIO_MODE_USER_STD_OUTPUT	   0x1800
+
 // --------------------------------------------------------
 #endif
diff --git a/verilog/dv/caravel/mgmt_soc/gpio/README b/verilog/dv/caravel/mgmt_soc/gpio/README
new file mode 100644
index 0000000..f1935dd
--- /dev/null
+++ b/verilog/dv/caravel/mgmt_soc/gpio/README
@@ -0,0 +1,27 @@
+------------------------------------------------
+Caravel
+gpio testbench
+------------------------------------------------
+
+This testbench exercises the fundamental use of the Caravel
+management SoC to drive the I/O in the user area as general
+purpose I/O on startup.
+
+On startup, all GPIO are configured as input to the management
+region (so as to be high impedence to the external world) and
+decoupled from the user project area.
+
+To configure any GPIO as output, the appropriate memory-mapped
+location for the I/O must be properly configured.  Since the
+I/O configuration is stored in two places, in the SoC, but
+also locally at each I/O pad, the "transfer" bit must be
+applied, which initiates a transfer of the configuration data
+around the padframe.
+
+The testbench takes 16 pins from the user area and checks
+functionality by applying input values on 8 of these pins from
+the testbench verilog, detecting them in the C program, then
+copying the values to the other 8 pins, and detecting those
+values in the testbench verilog.
+
+If any of that does not work, then the testbench will fail.
diff --git a/verilog/dv/caravel/mgmt_soc/gpio/gpio.c b/verilog/dv/caravel/mgmt_soc/gpio/gpio.c
index 4dbacc6..bd6a17c 100644
--- a/verilog/dv/caravel/mgmt_soc/gpio/gpio.c
+++ b/verilog/dv/caravel/mgmt_soc/gpio/gpio.c
@@ -3,37 +3,96 @@
 // --------------------------------------------------------
 
 /*
-	GPIO Test
-		Tests PU and PD on the lower 2 pins while being driven from outside
-		Tests Writing to the upper 2 pins
-		Tests reading from the lower 2 pins
-*/
+ *	GPIO Test
+ *		Tests PU and PD on the lower 8 pins while being driven from outside
+ *		Tests Writing to the upper 8 pins
+ *		Tests reading from the lower 8 pins
+ */
+
 void main()
 {
 	int i;
 
-	/* Lower 2 pins are input and upper 2 pins are o/p */
-	reg_gpio_data = 0;
-	reg_gpio_ena =  0x0003;
+	/* Set data out to zero */
+	reg_mprj_data = 0;
+
+	/* Lower 8 pins are input and upper 8 pins are output */
+	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_INPUT_NOPULL;
+	reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+
+	/* Apply configuration */
+	reg_mprj_xfer = 1;
+	reg_mprj_xfer = 0;
 
 	// change the pull up and pull down (checked by the TB)
-	reg_gpio_data = 0x0100;
-	reg_gpio_pu = 0x0001;
-	reg_gpio_pd = 0x0002;
+	reg_mprj_data = 0xa0000000;
 
-	reg_gpio_data = 0x0300;
-	reg_gpio_pu = 0x0002;
-	reg_gpio_pd = 0x0001;
+	reg_mprj_io_23 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
 
-	reg_gpio_pu = 0x0001;
-	reg_gpio_pd = 0x0002;
+	reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
 
-	// read the lower 2 pins, add 1 then o/p the result
+	/* Apply configuration */
+	reg_mprj_xfer = 1;
+	reg_mprj_xfer = 0;
+
+	reg_mprj_data = 0x0b000000;
+
+	reg_mprj_io_23 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+
+	reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+
+	/* Apply configuration */
+	reg_mprj_xfer = 1;
+	reg_mprj_xfer = 0;
+
+	reg_mprj_io_23 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+
+	reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+
+	/* Apply configuration */
+	reg_mprj_xfer = 1;
+	reg_mprj_xfer = 0;
+
+	// read the lower 8 pins, add 1 then o/p the result
 	// checked by the TB
-	reg_gpio_data = 0x0100;
+	reg_mprj_data = 0xab000000;
+
 	while (1){
-		int x = reg_gpio_data & 0x03;
-		reg_gpio_data = (x+1) << 8;
+		int x = reg_mprj_data & 0xff0000;
+		reg_mprj_data = (x+1) << 24;
 	}
 }
 
diff --git a/verilog/dv/caravel/mgmt_soc/gpio/gpio.hex b/verilog/dv/caravel/mgmt_soc/gpio/gpio.hex
index 667a214..adcdbdd 100755
--- a/verilog/dv/caravel/mgmt_soc/gpio/gpio.hex
+++ b/verilog/dv/caravel/mgmt_soc/gpio/gpio.hex
@@ -6,7 +6,7 @@
 13 09 00 00 93 09 00 00 13 0A 00 00 93 0A 00 00 

 13 0B 00 00 93 0B 00 00 13 0C 00 00 93 0C 00 00 

 13 0D 00 00 93 0D 00 00 13 0E 00 00 93 0E 00 00 

-13 0F 00 00 93 0F 00 00 17 05 00 00 13 05 45 16 

+13 0F 00 00 93 0F 00 00 17 05 00 00 13 05 45 3E 

 93 05 00 00 13 06 00 00 63 D8 C5 00 14 41 94 C1 

 11 05 91 05 E3 CC C5 FE 13 05 00 00 93 05 00 00 

 63 57 B5 00 23 20 05 00 11 05 E3 4D B5 FE 71 28 

@@ -20,12 +20,52 @@
 23 20 75 00 11 05 83 23 05 00 FD 1F E3 96 0F FC 

 FD 15 F1 F1 63 04 0F 00 23 20 75 00 13 03 00 08 

 A3 81 62 00 82 80 01 00 00 00 01 11 22 CE 00 10 

-B7 07 00 21 23 A0 07 00 B7 07 00 21 91 07 0D 47 

-98 C3 B7 07 00 21 13 07 00 10 98 C3 B7 07 00 21 

-A1 07 05 47 98 C3 B7 07 00 21 B1 07 09 47 98 C3 

-B7 07 00 21 13 07 00 30 98 C3 B7 07 00 21 A1 07 

-09 47 98 C3 B7 07 00 21 B1 07 05 47 98 C3 B7 07 

-00 21 A1 07 05 47 98 C3 B7 07 00 21 B1 07 09 47 

-98 C3 B7 07 00 21 13 07 00 10 98 C3 B7 07 00 21 

-9C 43 8D 8B 23 26 F4 FE 83 27 C4 FE 85 07 13 97 

-87 00 B7 07 00 21 98 C3 D5 B7 00 00 

+B7 07 00 23 23 A0 07 00 B7 07 00 23 93 87 47 08 

+09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 07 08 

+09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 C7 07 

+09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 87 07 

+09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 47 07 

+09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 07 07 

+09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 C7 06 

+09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 87 06 

+09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 47 06 

+13 07 30 40 98 C3 B7 07 00 23 93 87 07 06 13 07 

+30 40 98 C3 B7 07 00 23 93 87 C7 05 13 07 30 40 

+98 C3 B7 07 00 23 93 87 87 05 13 07 30 40 98 C3 

+B7 07 00 23 93 87 47 05 13 07 30 40 98 C3 B7 07 

+00 23 93 87 07 05 13 07 30 40 98 C3 B7 07 00 23 

+93 87 C7 04 13 07 30 40 98 C3 B7 07 00 23 93 87 

+87 04 13 07 30 40 98 C3 B7 07 00 23 91 07 05 47 

+98 C3 B7 07 00 23 91 07 23 A0 07 00 B7 07 00 23 

+37 07 00 A0 98 C3 B7 07 00 23 93 87 47 06 05 67 

+13 07 37 80 98 C3 B7 07 00 23 93 87 07 06 05 67 

+13 07 37 80 98 C3 B7 07 00 23 93 87 C7 05 05 67 

+13 07 37 80 98 C3 B7 07 00 23 93 87 87 05 05 67 

+13 07 37 80 98 C3 B7 07 00 23 93 87 47 05 05 67 

+13 07 37 C0 98 C3 B7 07 00 23 93 87 07 05 05 67 

+13 07 37 C0 98 C3 B7 07 00 23 93 87 C7 04 05 67 

+13 07 37 C0 98 C3 B7 07 00 23 93 87 87 04 05 67 

+13 07 37 C0 98 C3 B7 07 00 23 91 07 05 47 98 C3 

+B7 07 00 23 91 07 23 A0 07 00 B7 07 00 23 37 07 

+00 0B 98 C3 B7 07 00 23 93 87 47 06 05 67 13 07 

+37 C0 98 C3 B7 07 00 23 93 87 07 06 05 67 13 07 

+37 C0 98 C3 B7 07 00 23 93 87 C7 05 05 67 13 07 

+37 C0 98 C3 B7 07 00 23 93 87 87 05 05 67 13 07 

+37 C0 98 C3 B7 07 00 23 93 87 47 05 05 67 13 07 

+37 80 98 C3 B7 07 00 23 93 87 07 05 05 67 13 07 

+37 80 98 C3 B7 07 00 23 93 87 C7 04 05 67 13 07 

+37 80 98 C3 B7 07 00 23 93 87 87 04 05 67 13 07 

+37 80 98 C3 B7 07 00 23 91 07 05 47 98 C3 B7 07 

+00 23 91 07 23 A0 07 00 B7 07 00 23 93 87 47 06 

+05 67 13 07 37 80 98 C3 B7 07 00 23 93 87 07 06 

+05 67 13 07 37 80 98 C3 B7 07 00 23 93 87 C7 05 

+05 67 13 07 37 80 98 C3 B7 07 00 23 93 87 87 05 

+05 67 13 07 37 80 98 C3 B7 07 00 23 93 87 47 05 

+05 67 13 07 37 C0 98 C3 B7 07 00 23 93 87 07 05 

+05 67 13 07 37 C0 98 C3 B7 07 00 23 93 87 C7 04 

+05 67 13 07 37 C0 98 C3 B7 07 00 23 93 87 87 04 

+05 67 13 07 37 C0 98 C3 B7 07 00 23 91 07 05 47 

+98 C3 B7 07 00 23 91 07 23 A0 07 00 B7 07 00 23 

+37 07 00 AB 98 C3 B7 07 00 23 9C 43 3E 87 B7 07 

+FF 00 F9 8F 23 26 F4 FE 83 27 C4 FE 85 07 13 97 

+87 01 B7 07 00 23 98 C3 F9 BF 00 00 

diff --git a/verilog/dv/caravel/mgmt_soc/gpio/gpio_tb.v b/verilog/dv/caravel/mgmt_soc/gpio/gpio_tb.v
index f823737..56781da 100644
--- a/verilog/dv/caravel/mgmt_soc/gpio/gpio_tb.v
+++ b/verilog/dv/caravel/mgmt_soc/gpio/gpio_tb.v
@@ -32,7 +32,7 @@
 	always #10 clock <= (clock === 1'b0);
 
 	initial begin
-		clock = 0;
+		clock <= 0;
 	end
 
 	initial begin
@@ -64,7 +64,8 @@
 	wire flash_io1;
 
 	reg RSTB;
-	wire CSB, SCK, SDI, SDO;
+	reg CSB, SCK, SDI;
+	wire SDO;
 
 	// Transactor
 	initial begin
@@ -99,6 +100,9 @@
 	end
 
 	initial begin
+		CSB <= 1'b1;
+		SCK <= 1'b0;
+		SDI <= 1'b0;
 		RSTB <= 1'b0;
 		
 		#1000;
@@ -133,6 +137,9 @@
 	// apply {27'bz, SCK, CSB, SDI, SDO, 1'bz} to mprj_io (32 bits)
 
 	wire [11:0] noconnect;
+	wire [2:0] spi_sigs;
+
+	assign spi_sigs = 3'b010;
 
 	caravel uut (
 		.vdd3v3	  (VDD3V3),
@@ -141,7 +148,8 @@
 		.clock	  (clock),
 		.gpio     (gpio),
 		.mprj_io  ({checkbits, noconnect[11:1],
-				SCK, CSB, SDI, SDO, noconnect[0]}),
+				// SCK, CSB, SDI, SDO, noconnect[0]}),
+				spi_sigs, SDO, noconnect[0]}),
 		.flash_csb(flash_csb),
 		.flash_clk(flash_clk),
 		.flash_io0(flash_io0),
diff --git a/verilog/rtl/README b/verilog/rtl/README
new file mode 100644
index 0000000..ec44791
--- /dev/null
+++ b/verilog/rtl/README
@@ -0,0 +1,183 @@
+A quick documentation of the Caravel memory map and operation
+---------------------------------------------------------------
+
+Caravel pinout:
+---------------
+
+	vdd3v3
+	vdd1v8
+	vss
+	gpio	   1 bit, mainly used for external LDO control of user power supply
+	clock	   Master clock input
+	resetb	   Master reset (sense inverted) input
+	flash_csb  SPI flash controller chip select (sense inverted)
+	flash_clk  SPI flash controller clock
+	flash_io0  SPI flash controller data out
+	flash_io1  SPI flash controller data in
+	mprj_io	   32 bits general purpose programmable digital	or analog I/O
+
+Special-use pins for the management SoC:
+----------------------------------------
+
+    On power-up, the "mprj_io" GPIO are under complete control of the managment
+    SoC.  The first 8 user GPIO are special-purpose pads with dedicated functions
+    for the management SoC:
+
+	mprj_io[0]	JTAG I/O
+	mprj_io[1]	SDO, housekeeping SPI
+	mprj_io[2]	SDI, housekeeping SPI
+	mprj_io[3]	CSB, housekeeping SPI
+	mprj_io[4]	SCK, housekeeping SPI
+	mprj_io[5]	Rx, UART
+	mprj_io[6]	Tx, UART
+	mrpj_io[7]	IRQ
+
+    The next 4 user GPIO are designed to be used with an SPI flash controller in
+    the user space.  They allow the four pins to be overridden by the housekeeping
+    SPI to access the SPI flash in pass-through mode.
+
+	mprj_io[8]	user flash CSB
+	mprj_io[9]	user flash SCK
+	mprj_io[10]	user flash IO0
+	mprj_io[11]	user flash IO1
+
+    The user may additionally use any available GPIO for the SPI flash IO2 and IO3
+    lines;  the pass-through mode only uses the basic 4-pin SPI mode.
+
+    All of the special-use pins are configured through a memory-mapped region.  But
+    to avoid a large number of wires in the user space to reach all of the GPIO
+    pad controls, each user GPIO pad has a corresponding local control block.  The
+    control block holds the configuration data for the corresponding pad.  This
+    configuration data is a mirror of the data in the memory-mapped region, and is
+    loaded by a "transfer" bit in another memory-mapped register.  In addition to
+    all of the static control bits for the GPIO, each block contains a single bit
+    that specifies whether that pad is under the control of the user or the management
+    area.  All pins are configured from the management area.  However, the configuration
+    of static control bits leaves three dynamic signals:  input, output, and output
+    enable.  One set of these three signals is available to the user when the pad is
+    under user control.  The other set of these three signals is available to the
+    management SoC.  Again, to reduce wiring, only the two pads for JTAG and the
+    housekeeping SDO have all three pins under control of the SoC;  the remaining
+    pads have a single wire to the management SoC which is either an input wire
+    or an output wire, depending on how the control signals for the pad are set.
+
+    This setup gives a simplified view of the pad to the user:  For digital
+    applications, the user can treat the pad as a simple bidirectional digital
+    pad with an output enable to switch between output and input functions.
+    The user can set the output enable line high or low for a static input or
+    output function.  The user will also have access to the ESD-protected
+    pad connections for analog signals, and can connect to the VDDA domain
+    input digital signal if needed.
+
+Memory map:
+-----------
+
+    The Caravel memory map is as follows:
+
+	SRAM:				0000 0000
+
+	Flash:		Config:		1000 0000
+
+	UART:		Clock divider:	2000 0000
+			Data:		2000 0004
+
+	GPIO:		Data:		2100 0000
+			Output enable:	2100 0004
+			Pullup		2100 0008
+			Pulldown	2100 000c 
+
+	Counter 1:	Config:		2110 0000
+			Value:		2110 0004
+			Data:		2110 0008
+
+	Counter 2:	Config:		2120 0000
+			Value:		2120 0004
+			Data:		2120 0008
+
+	SPI master:	Config:		2130 0000
+			Data:		2130 0004
+
+	Logic analyzer:	Data 0:		2200 0000
+			Data 1:		2200 0004
+			Data 2:		2200 0008
+			Data 3:		2200 000c
+			Enable 0:	2200 0010
+			Enable 1:	2200 0014
+			Enable 2:	2200 0018
+			Enable 3:	2200 001c
+
+	Project ctrl:	Data:		2300 0000
+			Transfer:	2300 0004
+			I/O Config:	2300 0008
+			to		2300 0084
+			Power Config:	2300 0088
+			to		2300 0104
+
+	Flash ctrl:	Config:		2D00 0000
+
+	System:		PLL out:	2F00 0000
+			Trap out:	2F00 0004
+			IRQ7 source:	2F00 0008
+
+	User area base:			3000 0000
+
+	Crossbar:	QSPI control	8000 0000
+			Storage area	9000 0000
+			Any slave 1	a000 0000
+			Any slave 2	b000 0000
+
+Project I/O Control:
+---------------------
+
+	Configuration bits per I/O (13 bits for each GPIO pad):
+								Global Default
+		Bits 12-10:	digital mode (3 bits)		001
+		Bit   9:	voltage trip point select	  0
+		Bit   8:	slow slew select		  0
+		Bit   7:	analog bus polarity		  0
+		Bit   6:	analog bus select		  0
+		Bit   5:	analog bus enable		  0
+		Bit   4:	IB mode select			  0
+		Bit   3:	input disable			  0
+		Bit   2:	holdover value			  0
+		Bit   1:	output disable			  1
+		Bit   0:	management control enable	  1
+
+Default I/O modes:
+------------------
+	mprj_io[0]	JTAG I/O		110 0 0 0 0 0 0 0 0 0 1
+	mprj_io[1]	SDO, housekeeping SPI	110 0 0 0 0 0 0 0 0 0 1
+	all others:				001 0 0 0 0 0 0 0 0 1 1
+	
+
+    Standard GPIO output configuration:
+	mprj_io[6]	Tx, UART		110 0 0 0 0 0 0 0 0 0 1
+
+    Standard GPIO input configuration:
+	mprj_io[*]				001 0 0 0 0 0 0 0 0 1 1
+
+    Standard GPIO input configuration with pullup:
+	mprj_io[*]				010 0 0 0 0 0 0 0 0 1 1
+
+    Standard GPIO input configuration with pulldown:
+	mprj_io[*]				011 0 0 0 0 0 0 0 0 1 1
+
+    Specifically:
+	JTAG and SDO are set to output.  The output enable configure bit
+	is a don't-care, since the output enable line is directly controlled
+	by the module (JTAG or housekeeping SPI, respectively).
+
+	All other I/O are set as input mode only, with output disabled.
+	
+	Tx is set to input like the others;  before enabling the UART
+	from a program in flash, the I/O must be set to an output configuration.
+	
+	Note that the standard input configurations with pull-up and pull-down
+	require that "out" be set 1 or 0, respectively;  since the I/O are
+	designed with minimal wiring, there is only one wire for input and
+	output, so the wire is used for input in these cases, and special
+	signal handling is done locally to set the value of "out" equal to
+	~dm[0].  This is a (minor) restriction on the available I/O modes.
+
+	Other possible modes are open-drain (for I2C), weak drive strength
+	output (5k up + down), and analog mode (digital disabled)
diff --git a/verilog/rtl/caravel.v b/verilog/rtl/caravel.v
index abcbd8a..492712e 100644
--- a/verilog/rtl/caravel.v
+++ b/verilog/rtl/caravel.v
@@ -38,7 +38,7 @@
 `include "/home/tim/projects/efabless/tech/SW/sky130A/libs.ref/sky130_fd_sc_hvl/verilog/sky130_fd_sc_hvl.v"
 
 `include "mgmt_soc.v"
-`include "caravel_spi.v"
+`include "housekeeping_spi.v"
 `include "digital_pll.v"
 `include "caravel_clkrst.v"
 `include "mprj_counter.v"
@@ -47,6 +47,7 @@
 `include "chip_io.v"
 `include "user_id_programming.v"
 `include "gpio_control_block.v"
+`include "gpio_control_block2.v"
 
 `ifdef USE_OPENRAM
     `include "sram_1rw1r_32_8192_8_sky130.v"
@@ -102,10 +103,10 @@
     // can be accessed through the SPI slave even when the processor is in
     // reset.
 
-    // flash_csb = mprj_io[8]
-    // flash_sck = mprj_io[9]
-    // flash_io0 = mprj_io[10]
-    // flash_io1 = mprj_io[11]
+    // user_flash_csb = mprj_io[8]
+    // user_flash_sck = mprj_io[9]
+    // user_flash_io0 = mprj_io[10]
+    // user_flash_io1 = mprj_io[11]
 
     // One-bit GPIO dedicated to management SoC (outside of user control)
     wire gpio_out_core;
@@ -116,7 +117,6 @@
     wire gpio_inenb_core;
 
     // Mega-Project Control (pad-facing)
-    wire [`MPRJ_IO_PADS-1:0] mgmt_io_data;
     wire mprj_io_loader_resetn;
     wire mprj_io_loader_clock;
     wire mprj_io_loader_data;
@@ -124,7 +124,7 @@
     wire [`MPRJ_IO_PADS-1:0] mprj_io_hldh_n;
     wire [`MPRJ_IO_PADS-1:0] mprj_io_enh;
     wire [`MPRJ_IO_PADS-1:0] mprj_io_inp_dis;
-    wire [`MPRJ_IO_PADS-1:0] mprj_io_oeb_n;
+    wire [`MPRJ_IO_PADS-1:0] mprj_io_oeb;
     wire [`MPRJ_IO_PADS-1:0] mprj_io_ib_mode_sel;
     wire [`MPRJ_IO_PADS-1:0] mprj_io_vtrip_sel;
     wire [`MPRJ_IO_PADS-1:0] mprj_io_slow_sel;
@@ -137,7 +137,7 @@
     wire [`MPRJ_IO_PADS-1:0] mprj_io_out;
 
     // Mega-Project Control (user-facing)
-    wire [`MPRJ_IO_PADS-1:0] user_io_oeb_n;
+    wire [`MPRJ_IO_PADS-1:0] user_io_oeb;
     wire [`MPRJ_IO_PADS-1:0] user_io_in;
     wire [`MPRJ_IO_PADS-1:0] user_io_out;
 
@@ -146,6 +146,29 @@
     wire mgmt_serial_clock;
     wire mgmt_serial_resetn;
 
+    // Mega-Project Control management I/O
+    // There are two types of GPIO connections:
+    // (1) Full Bidirectional: Management connects to in, out, and oeb
+    //     Uses:  JTAG and SDO
+    // (2) Selectable bidirectional:  Management connects to in and out,
+    //	   which are tied together.  oeb is grounded (oeb from the
+    //	   configuration is used)
+
+    // SDI 	 = mprj_io[2]		(input)
+    // CSB 	 = mprj_io[3]		(input)
+    // SCK	 = mprj_io[4]		(input)
+    // ser_rx    = mprj_io[5]		(input)
+    // ser_tx    = mprj_io[6]		(output)
+    // irq 	 = mprj_io[7]		(input)
+
+    wire [`MPRJ_IO_PADS-1:0] mgmt_io_in;
+    wire jtag_out, sdo_out; 		
+    wire jtag_outenb, sdo_outenb; 
+
+    wire [`MPRJ_IO_PADS-3:0] mgmt_io_nc1;	/* no-connects */
+    wire [`MPRJ_IO_PADS-3:0] mgmt_io_nc3;	/* no-connects */
+    wire [1:0] mgmt_io_nc2;			/* no-connects */
+
     // Power-on-reset signal.  The reset pad generates the sense-inverted
     // reset at 3.3V.  The 1.8V signal and the inverted 1.8V signal are
     // derived.
@@ -153,6 +176,12 @@
     wire porb_h;
     wire porb_l;
 
+    // To be considered:  Master hold signal on all user pads (?)
+    // For now, set holdh_n to 1 (NOTE:  This is in the 3.3V domain)
+    // and setting enh to porb_h.
+    assign mprj_io_hldh_n = {`MPRJ_IO_PADS{vdd3v3}};
+    assign mprj_io_enh = {`MPRJ_IO_PADS{porb_h}};
+
     chip_io padframe(
 	// Package Pins
 	.vdd3v3(vdd3v3),
@@ -189,10 +218,10 @@
 	.flash_io1_do_core(flash_io1_do_core),
 	.flash_io0_di_core(flash_io0_di_core),
 	.flash_io1_di_core(flash_io1_di_core),
-	.pll_clk16(pll_clk16),
+	.por(~porb_l),
 	.mprj_io_in(mprj_io_in),
 	.mprj_io_out(mprj_io_out),
-	.mprj_io_oeb_n(mprj_io_oeb_n),
+	.mprj_io_oeb(mprj_io_oeb),
         .mprj_io_hldh_n(mprj_io_hldh_n),
 	.mprj_io_enh(mprj_io_enh),
         .mprj_io_inp_dis(mprj_io_inp_dis),
@@ -284,7 +313,10 @@
 		.mprj_io_loader_resetn(mprj_io_loader_resetn),
 		.mprj_io_loader_clock(mprj_io_loader_clock),
 		.mprj_io_loader_data(mprj_io_loader_data),
-		.mgmt_io_data(mgmt_io_data),
+		.mgmt_in_data(mgmt_io_in),
+		.mgmt_out_data({mgmt_io_nc1, sdo_out, jtag_out}),
+		.mgmt_outz_data({mgmt_io_in[(`MPRJ_IO_PADS-1):2], mgmt_io_nc2}),
+		.mgmt_oeb_data({mgmt_io_nc3, sdo_outenb, jtag_outenb}),
 		// Mega Project Slave ports (WB MI A)
 		.mprj_cyc_o(mprj_cyc_o_core),
 		.mprj_stb_o(mprj_stb_o_core),
@@ -338,13 +370,26 @@
 
     assign gpio_serial_link_shifted = {mprj_io_loader_data, gpio_serial_link[`MPRJ_IO_PADS-1:1]};
 
-    gpio_control_block gpio_control_inst [`MPRJ_IO_PADS-1:0] (
+    // NOTE:  The intention is to replace most of gpio_control_block2
+    // (3 management wires per pad) with gpio_control_block (1 management
+    // wire per pad).  However, the inout line on gpio_control_block is
+    // troublesome and so I am starting with the simpler interface.  Ultimately
+    // the JTAG and SDO lines will keep the 3-pin interface and these pads will
+    // be located closest to the management area.
+
+    gpio_control_block2 #(
+	.DM_INIT(3'b010),	// Test:  All pads set to pull-up
+	.OENB_INIT(1'b0)	// Test:  All pads set to pull-up
+    ) gpio_control_inst [`MPRJ_IO_PADS-1:0] (
+
     	// Management Soc-facing signals
 
     	.resetn(mprj_io_loader_resetn),
     	.serial_clock(mprj_io_loader_clock),
 
-    	.mgmt_gpio_io(mgmt_io_data),
+    	.mgmt_gpio_in(mgmt_io_in),    // For gpio_control_block2 only
+	.mgmt_gpio_out({mgmt_io_in[(`MPRJ_IO_PADS-1):2], sdo_out, jtag_out}),
+	.mgmt_gpio_oeb({{(`MPRJ_IO_PADS-2){1'b1}}, sdo_outenb, jtag_outenb}),
 
     	// Serial data chain for pad configuration
     	.serial_data_in(gpio_serial_link_shifted),
@@ -352,7 +397,7 @@
 
     	// User-facing signals
     	.user_gpio_out(user_io_out),
-    	.user_gpio_outenb(user_io_oeb_n),
+    	.user_gpio_oeb(user_io_oeb),
     	.user_gpio_in(user_io_in),
 
     	// Pad-facing signals (Pad GPIOv2)
@@ -365,7 +410,7 @@
     	.pad_gpio_ana_sel(mprj_io_analog_sel),
     	.pad_gpio_ana_pol(mprj_io_analog_pol),
     	.pad_gpio_dm(mprj_io_dm),
-    	.pad_gpio_outenb(mprj_io_oen_n),
+    	.pad_gpio_outenb(mprj_io_oeb),
     	.pad_gpio_out(mprj_io_out),
     	.pad_gpio_in(mprj_io_in)
     );
diff --git a/verilog/rtl/caravel_spi.v b/verilog/rtl/caravel_spi.v
deleted file mode 100644
index 3abd227..0000000
--- a/verilog/rtl/caravel_spi.v
+++ /dev/null
@@ -1,261 +0,0 @@
-//-------------------------------------
-// SPI controller for Caravel (PicoSoC)
-//-------------------------------------
-// Written by Tim Edwards
-// efabless, inc. September 27, 2020
-//-------------------------------------
-
-`include "caravel_spi_slave.v"
-
-//-----------------------------------------------------------
-// This is a standalone slave SPI for the caravel chip that is
-// intended to be independent of the picosoc and independent
-// of all IP blocks except the power-on-reset.  This SPI has
-// register outputs controlling the functions that critically
-// affect operation of the picosoc and so cannot be accessed
-// from the picosoc itself.  This includes the PLL enables
-// and trim, and the crystal oscillator enable.  It also has
-// a general reset for the picosoc, an IRQ input, a bypass for
-// the entire crystal oscillator and PLL chain, the
-// manufacturer and product IDs and product revision number.
-// To be independent of the 1.8V regulator, the slave SPI is
-// synthesized with the 3V digital library and runs off of
-// the 3V supply.
-//
-// This module is designed to be decoupled from the chip
-// padframe and redirected to the wishbone bus under
-// register control from the management SoC, such that the
-// contents can be accessed from the management core via the
-// SPI master.
-//
-//-----------------------------------------------------------
-
-//------------------------------------------------------------
-// Caravel defined registers:
-// Register 0:  SPI status and control (unused & reserved)
-// Register 1 and 2:  Manufacturer ID (0x0456) (readonly)
-// Register 3:  Product ID (= 2) (readonly)
-// Register 4-7: Mask revision (readonly) --- Externally programmed
-//	with via programming.  Via programmed with a script to match
-//	each customer ID.
-//
-// Register 8:   PLL enable (1 bit)
-// Register 9:   PLL bypass (1 bit)
-// Register 10:  IRQ (1 bit)
-// Register 11:  reset (1 bit)
-// Register 12:  trap (1 bit) (readonly)
-// Register 13-16:  PLL trim (26 bits)
-// Register 17:	 PLL output select (3 bits)
-// Register 18:	 PLL divider (5 bits)
-//------------------------------------------------------------
-
-module caravel_spi(
-`ifdef LVS
-    vdd, vss, 
-`endif
-    RSTB, SCK, SDI, CSB, SDO, sdo_enb,
-    mgmt_sck, mgmt_sdi, mgmt_csb, mgmt_sdo,
-    pll_dco_ena, pll_div, pll_sel,
-    pll_trim, pll_bypass, irq, reset, trap,
-    mask_rev_in, pass_thru_reset,
-    pass_thru_mgmt_sck, pass_thru_mgmt_csb,
-    pass_thru_mgmt_sdi, pass_thru_mgmt_sdo,
-    pass_thru_user_sck, pass_thru_user_csb,
-    pass_thru_user_sdi, pass_thru_user_sdo
-);
-
-`ifdef LVS
-    inout vdd;	    // 3.3V supply
-    inout vss;	    // common ground
-`endif
-    
-    input RSTB;	    // from padframe
-
-    input SCK;	    // from padframe
-    input SDI;	    // from padframe
-    input CSB;	    // from padframe
-    output SDO;	    // to padframe
-    output sdo_enb; // to padframe
-
-    input mgmt_sck;    // from management SoC
-    input mgmt_sdi;    // from management SoC
-    input mgmt_csb;    // from management SoC
-    output mgmt_sdo;   // to management SoC
-
-    output pll_dco_ena;
-    output [4:0] pll_div;
-    output [2:0] pll_sel;
-    output [25:0] pll_trim;
-    output pll_bypass;
-    output irq;
-    output reset;
-    input  trap;
-    input [31:0] mask_rev_in;	// metal programmed;  3.3V domain
-
-    // Pass-through programming mode for management area SPI flash
-    output pass_thru_reset;
-    output pass_thru_mgmt_sck;
-    output pass_thru_mgmt_csb;
-    output pass_thru_mgmt_sdi;
-    input  pass_thru_mgmt_sdo;
-
-    // Pass-through programming mode for user area SPI flash
-    output pass_thru_user_sck;
-    output pass_thru_user_csb;
-    output pass_thru_user_sdi;
-    input  pass_thru_user_sdo;
-
-    reg [25:0] pll_trim;
-    reg [4:0] pll_div;
-    reg [2:0] pll_sel;
-    reg pll_dco_ena;
-    reg pll_bypass;
-    reg reset_reg;
-    reg irq;
-
-    wire [7:0] odata;
-    wire [7:0] idata;
-    wire [7:0] iaddr;
-
-    wire trap;
-    wire rdstb;
-    wire wrstb;
-    wire pass_thru_mgmt;		// Mode detected by spi_slave
-    wire pass_thru_mgmt_delay;
-    wire pass_thru_user;		// Mode detected by spi_slave
-    wire pass_thru_user_delay;
-
-    // Connect to management SoC SPI master when mgmt_csb is low
-
-    wire loc_sck;
-    wire loc_csb;
-    wire loc_sdi;
-    wire loc_sdo;
-    wire loc_sdoenb;
-
-    assign loc_csb = (mgmt_csb == 1'b0) ? 1'b0 : CSB;
-    assign loc_sck = (mgmt_csb == 1'b0) ? mgmt_sck : SCK;
-    assign loc_sdi = (mgmt_csb == 1'b0) ? mgmt_sdi : SDI;
-
-    assign mgmt_sdo = (mgmt_csb == 1'b0) ? loc_sdo : 1'b0;
-    assign sdo_enb = (mgmt_csb == 1'b0) ? 1'b1 : loc_sdoenb;
-
-    // Pass-through mode handling
-
-    assign pass_thru_mgmt_csb = ~pass_thru_mgmt_delay;
-    assign pass_thru_mgmt_sck = pass_thru_mgmt ? SCK : 1'b0;
-    assign pass_thru_mgmt_sdi = pass_thru_mgmt ? SDI : 1'b0;
-
-    assign pass_thru_user_csb = ~pass_thru_user_delay;
-    assign pass_thru_user_sck = pass_thru_user ? SCK : 1'b0;
-    assign pass_thru_user_sdi = pass_thru_user ? SDI : 1'b0;
-
-    assign SDO = pass_thru_mgmt ? pass_thru_mgmt_sdo :
-		 pass_thru_user ? pass_thru_user_sdo : loc_sdo;
-    assign reset = pass_thru_reset ? 1'b1 : reset_reg;
-
-    // Instantiate the SPI slave module
-
-    caravel_spi_slave U1 (
-	.reset(~RSTB),
-    	.SCK(loc_sck),
-    	.SDI(loc_sdi),
-    	.CSB(loc_csb),
-    	.SDO(loc_sdo),
-    	.sdoenb(loc_sdoenb),
-    	.idata(odata),
-    	.odata(idata),
-    	.oaddr(iaddr),
-    	.rdstb(rdstb),
-    	.wrstb(wrstb),
-    	.pass_thru_mgmt(pass_thru_mgmt),
-    	.pass_thru_mgmt_delay(pass_thru_mgmt_delay),
-    	.pass_thru_user(pass_thru_user),
-    	.pass_thru_user_delay(pass_thru_user_delay),
-    	.pass_thru_reset(pass_thru_reset)
-    );
-
-    wire [11:0] mfgr_id;
-    wire [7:0]  prod_id;
-    wire [31:0] mask_rev;
-
-    assign mfgr_id = 12'h456;		// Hard-coded
-    assign prod_id = 8'h10;		// Hard-coded
-    assign mask_rev = mask_rev_in;	// Copy in to out.
-
-    // Send register contents to odata on SPI read command
-    // All values are 1-4 bits and no shadow registers are required.
-
-    assign odata = 
-    (iaddr == 8'h00) ? 8'h00 :	// SPI status (fixed)
-    (iaddr == 8'h01) ? {4'h0, mfgr_id[11:8]} :	// Manufacturer ID (fixed)
-    (iaddr == 8'h02) ? mfgr_id[7:0] :	// Manufacturer ID (fixed)
-    (iaddr == 8'h03) ? prod_id :	// Product ID (fixed)
-    (iaddr == 8'h04) ? mask_rev[31:24] :	// Mask rev (metal programmed)
-    (iaddr == 8'h05) ? mask_rev[23:16] :	// Mask rev (metal programmed)
-    (iaddr == 8'h06) ? mask_rev[15:8] :		// Mask rev (metal programmed)
-    (iaddr == 8'h07) ? mask_rev[7:0] :		// Mask rev (metal programmed)
-
-    (iaddr == 8'h08) ? {7'b0000000, pll_dco_ena} :
-    (iaddr == 8'h09) ? {7'b0000000, pll_bypass} :
-    (iaddr == 8'h0a) ? {7'b0000000, irq} :
-    (iaddr == 8'h0b) ? {7'b0000000, reset} :
-    (iaddr == 8'h0c) ? {7'b0000000, trap} :
-    (iaddr == 8'h0d) ? pll_trim[7:0] :
-    (iaddr == 8'h0e) ? pll_trim[15:8] :
-    (iaddr == 8'h0f) ? pll_trim[23:16] :
-    (iaddr == 8'h10) ? {6'b000000, pll_trim[25:24]} :
-    (iaddr == 8'h11) ? {5'b00000, pll_sel} :
-    (iaddr == 8'h12) ? {3'b000, pll_div} :
-               8'h00;	// Default
-
-    // Register mapping and I/O to slave module
-
-    always @(posedge SCK or negedge RSTB) begin
-    if (RSTB == 1'b0) begin
-        // Set trim for PLL at (almost) slowest rate (~90MHz).  However,
-        // pll_trim[12] must be set to zero for proper startup.
-        pll_trim <= 26'b11111111111110111111111111;
-        pll_sel <= 3'b000;
-        pll_div <= 5'b00100;	// Default divide-by-8
-        pll_dco_ena <= 1'b1;	// Default free-running PLL
-        pll_bypass <= 1'b1;		// NOTE: Default bypass mode (don't use PLL)
-        irq <= 1'b0;
-        reset_reg <= 1'b0;
-    end else if (wrstb == 1'b1) begin
-        case (iaddr)
-        8'h08: begin
-             pll_dco_ena <= idata[0];
-               end
-        8'h09: begin
-             pll_bypass <= idata[0];
-               end
-        8'h0a: begin
-             irq <= idata[0];
-               end
-        8'h0b: begin
-             reset_reg <= idata[0];
-               end
-        // Register 0xc is read-only
-        8'h0d: begin
-              pll_trim[7:0] <= idata;
-               end
-        8'h0e: begin
-              pll_trim[15:8] <= idata;
-               end
-        8'h0f: begin
-              pll_trim[23:16] <= idata;
-               end
-        8'h10: begin
-              pll_trim[25:24] <= idata[1:0];
-               end
-        8'h11: begin
-             pll_sel <= idata[2:0];
-               end
-        8'h12: begin
-             pll_div <= idata[4:0];
-               end
-        endcase	// (iaddr)
-    end
-    end
-endmodule	// caravel_spi
diff --git a/verilog/rtl/caravel_spi_slave.v b/verilog/rtl/caravel_spi_slave.v
deleted file mode 100644
index e8a6494..0000000
--- a/verilog/rtl/caravel_spi_slave.v
+++ /dev/null
@@ -1,221 +0,0 @@
-//------------------------------------------------------
-// caravel_spi_slave.v
-//------------------------------------------------------
-// General purpose SPI slave module for the Caravel chip
-//------------------------------------------------------
-// Written by Tim Edwards
-// efabless, inc., September 28, 2020
-//------------------------------------------------
-// This file is distributed free and open source
-//------------------------------------------------
-
-// SCK ---   Clock input
-// SDI ---   Data  input
-// SDO ---   Data  output
-// CSB ---   Chip  select (sense negative)
-// idata --- Data from chip to transmit out, in 8 bits
-// odata --- Input data to chip, in 8 bits
-// addr  --- Decoded address to upstream circuits
-// rdstb --- Read strobe, tells upstream circuit to supply next byte to idata
-// wrstb --- Write strobe, tells upstream circuit to latch odata.
-
-// Data format (general purpose):
-// 8 bit format
-// 1st byte:   Command word (see below)
-// 2nd byte:   Address word (register 0 to 255)
-// 3rd byte:   Data word    (value 0 to 255)
-
-// Command format:
-// 00000000  No operation
-// 10000000  Write until CSB raised
-// 01000000  Read  until CSB raised
-// 11000000  Simultaneous read/write until CSB raised
-// 11000100  Pass-through read/write to management area flash SPI until CSB raised
-// 11000101  Pass-through read/write to user area flash SPI until CSB raised
-// wrnnn000  Read/write as above, for nnn = 1 to 7 bytes, then terminate
-
-// Lower three bits are reserved for future use.
-// All serial bytes are read and written msb first.
-
-// Fixed control and status registers
-
-// Address 0 is reserved and contains flags for SPI mode.  This is
-// currently undefined and is always value 0.
-// Address 1 is reserved and contains manufacturer ID low 8 bits.
-// Address 2 is reserved and contains manufacturer ID high 4 bits.
-// Address 3 is reserved and contains product ID (8 bits).
-// Addresses 4 to 7 are reserved and contain the mask ID (32 bits).
-// Addresses 8 to 255 are available for general purpose use.
-
-`define COMMAND  3'b000
-`define ADDRESS  3'b001
-`define DATA     3'b010
-`define USERPASS 3'b100
-`define MGMTPASS 3'b101
-
-module caravel_spi_slave(reset, SCK, SDI, CSB, SDO,
-	sdoenb, idata, odata, oaddr, rdstb, wrstb,
-	pass_thru_mgmt, pass_thru_mgmt_delay,
-	pass_thru_user, pass_thru_user_delay, pass_thru_reset);
-
-    input reset;
-    input SCK;
-    input SDI;
-    input CSB;
-    output SDO;
-    output sdoenb;
-    input [7:0] idata;
-    output [7:0] odata;
-    output [7:0] oaddr;
-    output rdstb;
-    output wrstb; 
-    output pass_thru_mgmt;
-    output pass_thru_mgmt_delay;
-    output pass_thru_user;
-    output pass_thru_user_delay;
-    output pass_thru_reset;
-
-    reg  [7:0]  addr;
-    reg		wrstb;
-    reg		rdstb;
-    reg		sdoenb;
-    reg  [2:0]  state;
-    reg  [2:0]  count;
-    reg		writemode;
-    reg		readmode;
-    reg  [2:0]	fixed;
-    wire [7:0]  odata;
-    reg  [6:0]  predata;
-    wire [7:0]  oaddr;
-    reg  [7:0]  ldata;
-    reg		pass_thru_mgmt;
-    reg		pass_thru_mgmt_delay;
-    reg		pre_pass_thru_mgmt;
-    reg		pass_thru_user;
-    reg		pass_thru_user_delay;
-    reg		pre_pass_thru_user;
-    wire	csb_reset;
-
-    assign odata = {predata, SDI};
-    assign oaddr = (state == `ADDRESS) ? {addr[6:0], SDI} : addr;
-    assign SDO = ldata[7];
-    assign csb_reset = CSB | reset;
-    assign pass_thru_reset = pass_thru_mgmt_delay | pre_pass_thru_mgmt;
-
-    // Readback data is captured on the falling edge of SCK so that
-    // it is guaranteed valid at the next rising edge.
-    always @(negedge SCK or posedge CSB) begin
-        if (CSB == 1'b1) begin
-            wrstb <= 1'b0;
-            ldata  <= 8'b00000000;
-            sdoenb <= 1'b1;
-        end else begin
-
-            // After CSB low, 1st SCK starts command
-
-            if (state == `DATA) begin
-            	if (readmode == 1'b1) begin
-                    sdoenb <= 1'b0;
-                    if (count == 3'b000) begin
-                	ldata <= idata;
-                    end else begin
-                	ldata <= {ldata[6:0], 1'b0};	// Shift out
-                    end
-                end else begin
-                    sdoenb <= 1'b1;
-                end
-
-                // Apply write strobe on SCK negative edge on the next-to-last
-                // data bit so that it updates data on the rising edge of SCK
-                // on the last data bit.
- 
-                if (count == 3'b111) begin
-                    if (writemode == 1'b1) begin
-                        wrstb <= 1'b1;
-                    end
-                end else begin
-                    wrstb <= 1'b0;
-                end
-	    end else if (state == `MGMTPASS || state == `USERPASS) begin
-		wrstb <= 1'b0;
-		sdoenb <= 1'b0;
-            end else begin
-                wrstb <= 1'b0;
-                sdoenb <= 1'b1;
-            end		// ! state `DATA
-        end		// ! CSB
-    end			// always @ ~SCK
-
-    always @(posedge SCK or posedge CSB) begin
-        if (csb_reset == 1'b1) begin
-            // Default state on reset
-            addr <= 8'h00;
-            rdstb <= 1'b0;
-            predata <= 7'b0000000;
-            state  <= `COMMAND;
-            count  <= 3'b000;
-            readmode <= 1'b0;
-            writemode <= 1'b0;
-            fixed <= 3'b000;
-	    pass_thru_mgmt <= 1'b0;
-	    pass_thru_mgmt_delay <= 1'b0;
-	    pre_pass_thru_mgmt <= 1'b0;
-	    pass_thru_user = 1'b0;
-	    pass_thru_user_delay <= 1'b0;
-	    pre_pass_thru_user <= 1'b0;
-        end else begin
-            // After CSB low, 1st SCK starts command
-            if (state == `COMMAND) begin
-                rdstb <= 1'b0;
-                count <= count + 1;
-        	if (count == 3'b000) begin
-	            writemode <= SDI;
-	        end else if (count == 3'b001) begin
-	            readmode <= SDI;
-	        end else if (count < 3'b101) begin
-	            fixed <= {fixed[1:0], SDI}; 
-	        end else if (count < 3'b110) begin
-		    pass_thru_mgmt_delay <= pre_pass_thru_mgmt;
-		    pass_thru_user_delay <= pre_pass_thru_user;
-	        end else if (count == 3'b111) begin
-		    if (pre_pass_thru_mgmt == 1'b1) begin
-			state <= `MGMTPASS;
-			pre_pass_thru_mgmt <= 1'b0;
-		    end else if (pre_pass_thru_user == 1'b1) begin
-			state <= `USERPASS;
-			pre_pass_thru_user <= 1'b0;
-		    end else begin
-	                state <= `ADDRESS;
-		    end
-	        end
-            end else if (state == `ADDRESS) begin
-	        count <= count + 1;
-	        addr <= {addr[6:0], SDI};
-	        if (count == 3'b111) begin
-	            if (readmode == 1'b1) begin
-	            	rdstb <= 1'b1;
-	            end
-	            state <= `DATA;
-	        end else begin
-	            rdstb <= 1'b0;
-	        end
-            end else if (state == `DATA) begin
-	        predata <= {predata[6:0], SDI};
-	        count <= count + 1;
-	        if (count == 3'b111) begin
-	            if (fixed == 3'b001) begin
-	                state <= `COMMAND;
-	            end else if (fixed != 3'b000) begin
-	                fixed <= fixed - 1;
-	                addr <= addr + 1;	// Auto increment address (fixed)
-	            end else begin	
-	                addr <= addr + 1;	// Auto increment address (streaming)
-	            end
-	        end else begin
-	            rdstb <= 1'b0;
-	        end
-            end		// ! state `DATA
-        end		// ! CSB
-    end			// always @ SCK
-
-endmodule // caravel_spi_slave
diff --git a/verilog/rtl/chip_io.v b/verilog/rtl/chip_io.v
index 82df32d..dc46ebf 100644
--- a/verilog/rtl/chip_io.v
+++ b/verilog/rtl/chip_io.v
@@ -33,11 +33,12 @@
 	input  flash_io1_do_core,
 	output flash_io0_di_core,
 	output flash_io1_di_core,
-	input  pll_clk16,
+	// porbh, returned to the I/O level shifted down and inverted
+	input  por,
 	// Mega-project IOs
-	input [`MPRJ_IO_PADS-1:0] mprj_io,
+	inout [`MPRJ_IO_PADS-1:0] mprj_io,
 	input [`MPRJ_IO_PADS-1:0] mprj_io_out,
-	input [`MPRJ_IO_PADS-1:0] mprj_io_oeb_n,
+	input [`MPRJ_IO_PADS-1:0] mprj_io_oeb,
     	input [`MPRJ_IO_PADS-1:0] mprj_io_hldh_n,
 	input [`MPRJ_IO_PADS-1:0] mprj_io_enh,
     	input [`MPRJ_IO_PADS-1:0] mprj_io_inp_dis,
@@ -198,20 +199,25 @@
 	`endif
 
 	mprj_io mprj_pads(
-		.vdd(vdd3v3),
+		.vdd3v3(vdd3v3),
 		.vdd1v8(vdd1v8),
 		.vss(vss),
 		.vddio_q(vddio_q),
 		.vssio_q(vssio_q),
 		.analog_a(analog_a),
 		.analog_b(analog_b),
+		.porb_h(porb_h),
+		.por(por),
 		.io(mprj_io),
 		.io_out(mprj_io_out),
-		.oeb_n(mprj_io_oeb_n),
+		.oeb(mprj_io_oeb),
 		.hldh_n(mprj_io_hldh_n),
 		.enh(mprj_io_enh),
 		.inp_dis(mprj_io_inp_dis),
 		.ib_mode_sel(mprj_io_ib_mode_sel),
+		.vtrip_sel(mprj_io_vtrip_sel),
+		.holdover(mprj_io_holdover),
+		.slow_sel(mprj_io_slow_sel),
 		.analog_en(mprj_io_analog_en),
 		.analog_sel(mprj_io_analog_sel),
 		.analog_pol(mprj_io_analog_pol),
diff --git a/verilog/rtl/gpio_control_block.v b/verilog/rtl/gpio_control_block.v
index 1575841..2325b39 100644
--- a/verilog/rtl/gpio_control_block.v
+++ b/verilog/rtl/gpio_control_block.v
@@ -31,7 +31,21 @@
  */
 
 module gpio_control_block #(
-    parameter PAD_CTRL_BITS = 13
+    parameter PAD_CTRL_BITS = 13,
+    // Parameterized initial startup state of the pad.
+    // The default parameters if unspecified is for the pad to be
+    // an input with no pull-up or pull-down, so that it is disconnected
+    // from the outside world.
+    parameter HOLD_INIT = 1'b0,
+    parameter SLOW_INIT = 1'b0,
+    parameter TRIP_INIT = 1'b0,
+    parameter IB_INIT = 1'b0,
+    parameter IENB_INIT = 1'b0,
+    parameter OENB_INIT = 1'b1,
+    parameter DM_INIT = 3'b001,
+    parameter AENA_INIT = 1'b0,
+    parameter ASEL_INIT = 1'b0,
+    parameter APOL_INIT = 1'b0
 ) (
     // Management Soc-facing signals
     input  	 resetn,		// Global reset
@@ -45,7 +59,7 @@
 
     // User-facing signals
     input        user_gpio_out,		// User space to pad
-    input        user_gpio_outenb,	// Output enable (user)
+    input        user_gpio_oeb,		// Output enable (user)
     output	 user_gpio_in,		// Pad to user space
 
     // Pad-facing signals (Pad GPIOv2)
@@ -58,7 +72,7 @@
     output	 pad_gpio_ana_sel,
     output	 pad_gpio_ana_pol,
     output [2:0] pad_gpio_dm,
-    output       pad_gpio_outenb,
+    output       pad_gpio_oeb,
     output	 pad_gpio_out,
     input	 pad_gpio_in
 );
@@ -67,15 +81,14 @@
     localparam MGMT_EN = 0;
     localparam OEB = 1;
     localparam HLDH = 2;
-    localparam ENH  = 3;
-    localparam INP_DIS = 4;
-    localparam MOD_SEL = 5;
-    localparam AN_EN = 6;
-    localparam AN_SEL = 7;
-    localparam AN_POL = 8;
-    localparam SLOW = 9;
-    localparam TRIP = 10;
-    localparam DM = 11;
+    localparam INP_DIS = 2;
+    localparam MOD_SEL = 4;
+    localparam AN_EN = 5;
+    localparam AN_SEL = 6;
+    localparam AN_POL = 7;
+    localparam SLOW = 8;
+    localparam TRIP = 9;
+    localparam DM = 10;
 
     /* Internally registered signals */
     reg	 	mgmt_ena;		// Enable management SoC to access pad
@@ -129,17 +142,17 @@
     always @(posedge load_data or posedge int_reset) begin
 	if (int_reset == 1'b1) begin
 	    /* Initial state on reset:  Pad set to management input */
-	    mgmt_ena <= 1'b0;
-	    gpio_holdover <= 1'b0;	// All signals latched in hold mode
-	    gpio_slow_sel <= 1'b0;	// Fast slew rate
-	    gpio_vtrip_sel <= 1'b0;	// CMOS mode
-            gpio_ib_mode_sel <= 1'b0;	// CMOS mode
-	    gpio_inenb <= 1'b0;		// Input enabled
-	    gpio_outenb <= 1'b1;	// Output disabled
-	    gpio_dm <= 3'b001;		// Configured as input only
-	    gpio_ana_en <= 1'b0;	// Digital enabled
-	    gpio_ana_sel <= 1'b0;	// Don't-care when gpio_ana_en = 0
-	    gpio_ana_pol <= 1'b0;	// Don't-care when gpio_ana_en = 0
+	    mgmt_ena <= 1'b1;		// Management SoC has control over all I/O
+	    gpio_holdover <= HOLD_INIT;	 // All signals latched in hold mode
+	    gpio_slow_sel <= SLOW_INIT;	 // Fast slew rate
+	    gpio_vtrip_sel <= TRIP_INIT; // CMOS mode
+            gpio_ib_mode_sel <= IB_INIT; // CMOS mode
+	    gpio_inenb <= IENB_INIT;	 // Input enabled
+	    gpio_outenb <= OENB_INIT;	 // Output disabled
+	    gpio_dm <= DM_INIT;		 // Configured as input only
+	    gpio_ana_en <= AENA_INIT;	 // Digital enabled
+	    gpio_ana_sel <= ASEL_INIT;	 // Don't-care when gpio_ana_en = 0
+	    gpio_ana_pol <= APOL_INIT;	 // Don't-care when gpio_ana_en = 0
 	end else begin
 	    /* Load data */
 	    mgmt_ena 	     <= shift_register[MGMT_EN];
@@ -177,18 +190,23 @@
     /* set the pullup or pulldown condition, the pad output bit must	*/
     /* be set to the opposite state of dm[0].				*/
     /* 		dm[0] = 0 is pull-down;  dm[0] = 1 is pull-up.		*/
-    /* Otherwise, the output 
+    /*									*/
+    /* This is done for management control only, since the management	*/
+    /* control has only 1 inout signal for both input and output, and	*/
+    /* cannot set the output and read the input simultaneously.  The 	*/
+    /* user has control over both lines and only needs to be told what	*/
+    /* to set the output line to, to enable a pullup or pulldown.	*/
 
-    assign pad_gpio_out = (mgmt_ena) ? mgmt_gpio_io :
-		(((gpio_dm[2:1] == 2'b01) && (gpio_inenb == 1'b0)) ?
-			~gpio_dm[0] : user_gpio_out);
+    assign pad_gpio_out = (mgmt_ena) ?  
+			(((gpio_dm[2:1] == 2'b01) && (gpio_inenb == 1'b0)) ?
+			~gpio_dm[0] : mgmt_gpio_io) : user_gpio_out;
 
     /* When under user control, gpio_outenb = 1 means that the pad is	*/
     /* configured as input, and the user outenb is unused.  Otherwise,	*/
     /* the pad outenb signal is controlled by the user.			*/
 
     assign pad_gpio_outenb = (mgmt_ena) ? gpio_outenb : 
-		((gpio_outenb == 1) ? 1'b1 : user_gpio_outenb);
+		((gpio_outenb == 1) ? 1'b1 : user_gpio_oeb);
 
     /* User gpio_in is grounded when the management controls the pad	*/
     assign user_gpio_in = (mgmt_ena) ? 1'b0 : pad_gpio_in;
diff --git a/verilog/rtl/gpio_control_block2.v b/verilog/rtl/gpio_control_block2.v
new file mode 100644
index 0000000..b28a02e
--- /dev/null
+++ b/verilog/rtl/gpio_control_block2.v
@@ -0,0 +1,193 @@
+/* 
+ *---------------------------------------------------------------------
+ * See gpio_control_block for description.  This module is like
+ * gpio_contro_block except that it has an additional two management-
+ * Soc-facing pins, which are the out_enb line and the output line.
+ * If the chip is configured for output with the oeb control
+ * register = 1, then the oeb line is controlled by the additional
+ * signal from the management SoC.  If the oeb control register = 0,
+ * then the output is disabled completely.  The "io" line is input
+ * only in this module.
+ *
+ *---------------------------------------------------------------------
+ */
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * This module instantiates a shift register chain that passes through
+ * each gpio cell.  These are connected end-to-end around the padframe
+ * periphery.  The purpose is to avoid a massive number of control
+ * wires between the digital core and I/O, passing through the user area.
+ *
+ * See mprj_ctrl.v for the module that registers the data for each
+ * I/O and drives the input to the shift register.
+ *
+ *---------------------------------------------------------------------
+ */
+
+module gpio_control_block2 #(
+    parameter PAD_CTRL_BITS = 13,
+    // Parameterized initial startup state of the pad.
+    // The default parameters if unspecified is for the pad to be
+    // an input with no pull-up or pull-down, so that it is disconnected
+    // from the outside world.
+    parameter HOLD_INIT = 1'b0,
+    parameter SLOW_INIT = 1'b0,
+    parameter TRIP_INIT = 1'b0,
+    parameter IB_INIT = 1'b0,
+    parameter IENB_INIT = 1'b0,
+    parameter OENB_INIT = 1'b1,
+    parameter DM_INIT = 3'b001,
+    parameter AENA_INIT = 1'b0,
+    parameter ASEL_INIT = 1'b0,
+    parameter APOL_INIT = 1'b0
+) (
+    // Management Soc-facing signals
+    input  	 resetn,		// Global reset
+    input  	 serial_clock,
+
+    output       mgmt_gpio_in,		// Management from pad (input only)
+    input        mgmt_gpio_out,		// Management to pad (output only)
+    input        mgmt_gpio_oeb,		// Management to pad (output only)
+
+    // Serial data chain for pad configuration
+    input  	 serial_data_in,
+    output 	 serial_data_out,
+
+    // User-facing signals
+    input        user_gpio_out,		// User space to pad
+    input        user_gpio_oeb,		// Output enable (user)
+    output	 user_gpio_in,		// Pad to user space
+
+    // Pad-facing signals (Pad GPIOv2)
+    output	 pad_gpio_holdover,
+    output	 pad_gpio_slow_sel,
+    output	 pad_gpio_vtrip_sel,
+    output       pad_gpio_inenb,
+    output       pad_gpio_ib_mode_sel,
+    output	 pad_gpio_ana_en,
+    output	 pad_gpio_ana_sel,
+    output	 pad_gpio_ana_pol,
+    output [2:0] pad_gpio_dm,
+    output       pad_gpio_outenb,
+    output	 pad_gpio_out,
+    input	 pad_gpio_in
+);
+
+    /* Parameters defining the bit offset of each function in the chain */
+    localparam MGMT_EN = 0;
+    localparam OEB = 1;
+    localparam HLDH = 2;
+    localparam ENH  = 3;
+    localparam INP_DIS = 4;
+    localparam MOD_SEL = 5;
+    localparam AN_EN = 6;
+    localparam AN_SEL = 7;
+    localparam AN_POL = 8;
+    localparam SLOW = 9;
+    localparam TRIP = 10;
+    localparam DM = 11;
+
+    /* Internally registered signals */
+    reg	 	mgmt_ena;		// Enable management SoC to access pad
+    reg	 	gpio_holdover;
+    reg	 	gpio_slow_sel;
+    reg	  	gpio_vtrip_sel;
+    reg  	gpio_inenb;
+    reg	 	gpio_ib_mode_sel;
+    reg  	gpio_outenb;
+    reg [2:0] 	gpio_dm;
+    reg	 	gpio_ana_en;
+    reg	 	gpio_ana_sel;
+    reg	 	gpio_ana_pol;
+
+    /* Derived output values */
+    wire	pad_gpio_holdover;
+    wire	pad_gpio_slow_sel;
+    wire	pad_gpio_vtrip_sel;
+    wire      	pad_gpio_inenb;
+    wire       	pad_gpio_ib_mode_sel;
+    wire	pad_gpio_ana_en;
+    wire	pad_gpio_ana_sel;
+    wire	pad_gpio_ana_pol;
+    wire [2:0]  pad_gpio_dm;
+    wire        pad_gpio_outenb;
+    wire	pad_gpio_out;
+    wire	pad_gpio_in;
+
+    /* Serial shift for the above (latched) values */
+    reg [PAD_CTRL_BITS-1:0] shift_register;
+
+    /* Utilize reset and clock to encode a load operation */
+    wire load_data;
+    wire int_reset;
+
+    /* Create internal reset and load signals from input reset and clock */
+    assign serial_data_out = shift_register[PAD_CTRL_BITS-1]; 
+    assign int_reset = (~resetn) & (~serial_clock);
+    assign load_data = (~resetn) & serial_clock;
+
+    always @(posedge serial_clock or posedge int_reset) begin
+	if (int_reset == 1'b1) begin
+	    /* Clear shift register */
+	    shift_register <= 'd0;
+	end else begin
+	    /* Shift data in */
+	    shift_register <= {shift_register[PAD_CTRL_BITS-2:0], serial_data_in};
+	end
+    end
+
+    always @(posedge load_data or posedge int_reset) begin
+	if (int_reset == 1'b1) begin
+	    /* Initial state on reset:  Pad set to management input */
+	    mgmt_ena <= 1'b1;		// Management SoC has control over all I/O
+	    gpio_holdover <= HOLD_INIT;	 // All signals latched in hold mode
+	    gpio_slow_sel <= SLOW_INIT;	 // Fast slew rate
+	    gpio_vtrip_sel <= TRIP_INIT; // CMOS mode
+            gpio_ib_mode_sel <= IB_INIT; // CMOS mode
+	    gpio_inenb <= IENB_INIT;	 // Input enabled
+	    gpio_outenb <= OENB_INIT;	 // (unused placeholder)
+	    gpio_dm <= DM_INIT;		 // Configured as input only
+	    gpio_ana_en <= AENA_INIT;	 // Digital enabled
+	    gpio_ana_sel <= ASEL_INIT;	 // Don't-care when gpio_ana_en = 0
+	    gpio_ana_pol <= APOL_INIT;	 // Don't-care when gpio_ana_en = 0
+	end else begin
+	    /* Load data */
+	    mgmt_ena 	     <= shift_register[MGMT_EN];
+	    gpio_outenb      <= shift_register[OEB];
+	    gpio_holdover    <= shift_register[HLDH]; 
+	    gpio_inenb 	     <= shift_register[INP_DIS];
+	    gpio_ib_mode_sel <= shift_register[MOD_SEL];
+	    gpio_ana_en      <= shift_register[AN_EN];
+	    gpio_ana_sel     <= shift_register[AN_SEL];
+	    gpio_ana_pol     <= shift_register[AN_POL];
+	    gpio_slow_sel    <= shift_register[SLOW];
+	    gpio_vtrip_sel   <= shift_register[TRIP];
+	    gpio_dm 	     <= shift_register[DM+2:DM];
+
+	end
+    end
+
+    /* These pad configuration signals are static and do not change	*/
+    /* after setup.							*/
+
+    assign pad_gpio_holdover 	= gpio_holdover;
+    assign pad_gpio_slow_sel 	= gpio_slow_sel;
+    assign pad_gpio_vtrip_sel	= gpio_vtrip_sel;
+    assign pad_gpio_ib_mode_sel	= gpio_ib_mode_sel;
+    assign pad_gpio_ana_en	= gpio_ana_en;
+    assign pad_gpio_ana_sel	= gpio_ana_sel;
+    assign pad_gpio_ana_pol	= gpio_ana_pol;
+    assign pad_gpio_dm		= gpio_dm;
+    assign pad_gpio_inenb 	= gpio_inenb;
+
+    /* Implement pad control behavior depending on state of mgmt_ena */
+
+    assign pad_gpio_out    =  (mgmt_ena) ? mgmt_gpio_out : user_gpio_out; 
+    assign pad_gpio_outenb =  (mgmt_ena) ? mgmt_gpio_oeb : user_gpio_oeb;
+
+    assign user_gpio_in =    (mgmt_ena) ? 1'b0 : pad_gpio_in;
+    assign mgmt_gpio_in =    (mgmt_ena) ? pad_gpio_in : 1'b0;
+
+endmodule
diff --git a/verilog/rtl/housekeeping_spi.v b/verilog/rtl/housekeeping_spi.v
new file mode 100644
index 0000000..97bd7a1
--- /dev/null
+++ b/verilog/rtl/housekeeping_spi.v
@@ -0,0 +1,481 @@
+//-------------------------------------
+// SPI controller for Caravel (PicoSoC)
+//-------------------------------------
+// Written by Tim Edwards
+// efabless, inc. September 27, 2020
+//-------------------------------------
+
+//-----------------------------------------------------------
+// This is a standalone slave SPI for the caravel chip that is
+// intended to be independent of the picosoc and independent
+// of all IP blocks except the power-on-reset.  This SPI has
+// register outputs controlling the functions that critically
+// affect operation of the picosoc and so cannot be accessed
+// from the picosoc itself.  This includes the PLL enables
+// and trim, and the crystal oscillator enable.  It also has
+// a general reset for the picosoc, an IRQ input, a bypass for
+// the entire crystal oscillator and PLL chain, the
+// manufacturer and product IDs and product revision number.
+// To be independent of the 1.8V regulator, the slave SPI is
+// synthesized with the 3V digital library and runs off of
+// the 3V supply.
+//
+// This module is designed to be decoupled from the chip
+// padframe and redirected to the wishbone bus under
+// register control from the management SoC, such that the
+// contents can be accessed from the management core via the
+// SPI master.
+//
+//-----------------------------------------------------------
+
+//------------------------------------------------------------
+// Caravel defined registers:
+// Register 0:  SPI status and control (unused & reserved)
+// Register 1 and 2:  Manufacturer ID (0x0456) (readonly)
+// Register 3:  Product ID (= 2) (readonly)
+// Register 4-7: Mask revision (readonly) --- Externally programmed
+//	with via programming.  Via programmed with a script to match
+//	each customer ID.
+//
+// Register 8:   PLL enable (1 bit)
+// Register 9:   PLL bypass (1 bit)
+// Register 10:  IRQ (1 bit)
+// Register 11:  reset (1 bit)
+// Register 12:  trap (1 bit) (readonly)
+// Register 13-16:  PLL trim (26 bits)
+// Register 17:	 PLL output select (3 bits)
+// Register 18:	 PLL divider (5 bits)
+//------------------------------------------------------------
+
+module housekeeping_spi(
+`ifdef LVS
+    vdd, vss, 
+`endif
+    RSTB, SCK, SDI, CSB, SDO, sdo_enb,
+    mgmt_sck, mgmt_sdi, mgmt_csb, mgmt_sdo,
+    pll_dco_ena, pll_div, pll_sel,
+    pll_trim, pll_bypass, irq, reset, trap,
+    mask_rev_in, pass_thru_reset,
+    pass_thru_mgmt_sck, pass_thru_mgmt_csb,
+    pass_thru_mgmt_sdi, pass_thru_mgmt_sdo,
+    pass_thru_user_sck, pass_thru_user_csb,
+    pass_thru_user_sdi, pass_thru_user_sdo
+);
+
+`ifdef LVS
+    inout vdd;	    // 3.3V supply
+    inout vss;	    // common ground
+`endif
+    
+    input RSTB;	    // from padframe
+
+    input SCK;	    // from padframe
+    input SDI;	    // from padframe
+    input CSB;	    // from padframe
+    output SDO;	    // to padframe
+    output sdo_enb; // to padframe
+
+    input mgmt_sck;    // from management SoC
+    input mgmt_sdi;    // from management SoC
+    input mgmt_csb;    // from management SoC
+    output mgmt_sdo;   // to management SoC
+
+    output pll_dco_ena;
+    output [4:0] pll_div;
+    output [2:0] pll_sel;
+    output [25:0] pll_trim;
+    output pll_bypass;
+    output irq;
+    output reset;
+    input  trap;
+    input [31:0] mask_rev_in;	// metal programmed;  3.3V domain
+
+    // Pass-through programming mode for management area SPI flash
+    output pass_thru_reset;
+    output pass_thru_mgmt_sck;
+    output pass_thru_mgmt_csb;
+    output pass_thru_mgmt_sdi;
+    input  pass_thru_mgmt_sdo;
+
+    // Pass-through programming mode for user area SPI flash
+    output pass_thru_user_sck;
+    output pass_thru_user_csb;
+    output pass_thru_user_sdi;
+    input  pass_thru_user_sdo;
+
+    reg [25:0] pll_trim;
+    reg [4:0] pll_div;
+    reg [2:0] pll_sel;
+    reg pll_dco_ena;
+    reg pll_bypass;
+    reg reset_reg;
+    reg irq;
+
+    wire [7:0] odata;
+    wire [7:0] idata;
+    wire [7:0] iaddr;
+
+    wire trap;
+    wire rdstb;
+    wire wrstb;
+    wire pass_thru_mgmt;		// Mode detected by spi_slave
+    wire pass_thru_mgmt_delay;
+    wire pass_thru_user;		// Mode detected by spi_slave
+    wire pass_thru_user_delay;
+
+    // Connect to management SoC SPI master when mgmt_csb is low
+
+    wire loc_sck;
+    wire loc_csb;
+    wire loc_sdi;
+    wire loc_sdo;
+    wire loc_sdoenb;
+
+    assign loc_csb = (mgmt_csb == 1'b0) ? 1'b0 : CSB;
+    assign loc_sck = (mgmt_csb == 1'b0) ? mgmt_sck : SCK;
+    assign loc_sdi = (mgmt_csb == 1'b0) ? mgmt_sdi : SDI;
+
+    assign mgmt_sdo = (mgmt_csb == 1'b0) ? loc_sdo : 1'b0;
+    assign sdo_enb = (mgmt_csb == 1'b0) ? 1'b1 : loc_sdoenb;
+
+    // Pass-through mode handling
+
+    assign pass_thru_mgmt_csb = ~pass_thru_mgmt_delay;
+    assign pass_thru_mgmt_sck = pass_thru_mgmt ? SCK : 1'b0;
+    assign pass_thru_mgmt_sdi = pass_thru_mgmt ? SDI : 1'b0;
+
+    assign pass_thru_user_csb = ~pass_thru_user_delay;
+    assign pass_thru_user_sck = pass_thru_user ? SCK : 1'b0;
+    assign pass_thru_user_sdi = pass_thru_user ? SDI : 1'b0;
+
+    assign SDO = pass_thru_mgmt ? pass_thru_mgmt_sdo :
+		 pass_thru_user ? pass_thru_user_sdo : loc_sdo;
+    assign reset = pass_thru_reset ? 1'b1 : reset_reg;
+
+    // Instantiate the SPI slave module
+
+    housekeeping_spi_slave U1 (
+	.reset(~RSTB),
+    	.SCK(loc_sck),
+    	.SDI(loc_sdi),
+    	.CSB(loc_csb),
+    	.SDO(loc_sdo),
+    	.sdoenb(loc_sdoenb),
+    	.idata(odata),
+    	.odata(idata),
+    	.oaddr(iaddr),
+    	.rdstb(rdstb),
+    	.wrstb(wrstb),
+    	.pass_thru_mgmt(pass_thru_mgmt),
+    	.pass_thru_mgmt_delay(pass_thru_mgmt_delay),
+    	.pass_thru_user(pass_thru_user),
+    	.pass_thru_user_delay(pass_thru_user_delay),
+    	.pass_thru_reset(pass_thru_reset)
+    );
+
+    wire [11:0] mfgr_id;
+    wire [7:0]  prod_id;
+    wire [31:0] mask_rev;
+
+    assign mfgr_id = 12'h456;		// Hard-coded
+    assign prod_id = 8'h10;		// Hard-coded
+    assign mask_rev = mask_rev_in;	// Copy in to out.
+
+    // Send register contents to odata on SPI read command
+    // All values are 1-4 bits and no shadow registers are required.
+
+    assign odata = 
+    (iaddr == 8'h00) ? 8'h00 :	// SPI status (fixed)
+    (iaddr == 8'h01) ? {4'h0, mfgr_id[11:8]} :	// Manufacturer ID (fixed)
+    (iaddr == 8'h02) ? mfgr_id[7:0] :	// Manufacturer ID (fixed)
+    (iaddr == 8'h03) ? prod_id :	// Product ID (fixed)
+    (iaddr == 8'h04) ? mask_rev[31:24] :	// Mask rev (metal programmed)
+    (iaddr == 8'h05) ? mask_rev[23:16] :	// Mask rev (metal programmed)
+    (iaddr == 8'h06) ? mask_rev[15:8] :		// Mask rev (metal programmed)
+    (iaddr == 8'h07) ? mask_rev[7:0] :		// Mask rev (metal programmed)
+
+    (iaddr == 8'h08) ? {7'b0000000, pll_dco_ena} :
+    (iaddr == 8'h09) ? {7'b0000000, pll_bypass} :
+    (iaddr == 8'h0a) ? {7'b0000000, irq} :
+    (iaddr == 8'h0b) ? {7'b0000000, reset} :
+    (iaddr == 8'h0c) ? {7'b0000000, trap} :
+    (iaddr == 8'h0d) ? pll_trim[7:0] :
+    (iaddr == 8'h0e) ? pll_trim[15:8] :
+    (iaddr == 8'h0f) ? pll_trim[23:16] :
+    (iaddr == 8'h10) ? {6'b000000, pll_trim[25:24]} :
+    (iaddr == 8'h11) ? {5'b00000, pll_sel} :
+    (iaddr == 8'h12) ? {3'b000, pll_div} :
+               8'h00;	// Default
+
+    // Register mapping and I/O to slave module
+
+    always @(posedge SCK or negedge RSTB) begin
+    if (RSTB == 1'b0) begin
+        // Set trim for PLL at (almost) slowest rate (~90MHz).  However,
+        // pll_trim[12] must be set to zero for proper startup.
+        pll_trim <= 26'b11111111111110111111111111;
+        pll_sel <= 3'b000;
+        pll_div <= 5'b00100;	// Default divide-by-8
+        pll_dco_ena <= 1'b1;	// Default free-running PLL
+        pll_bypass <= 1'b1;		// NOTE: Default bypass mode (don't use PLL)
+        irq <= 1'b0;
+        reset_reg <= 1'b0;
+    end else if (wrstb == 1'b1) begin
+        case (iaddr)
+        8'h08: begin
+             pll_dco_ena <= idata[0];
+               end
+        8'h09: begin
+             pll_bypass <= idata[0];
+               end
+        8'h0a: begin
+             irq <= idata[0];
+               end
+        8'h0b: begin
+             reset_reg <= idata[0];
+               end
+        // Register 0xc is read-only
+        8'h0d: begin
+              pll_trim[7:0] <= idata;
+               end
+        8'h0e: begin
+              pll_trim[15:8] <= idata;
+               end
+        8'h0f: begin
+              pll_trim[23:16] <= idata;
+               end
+        8'h10: begin
+              pll_trim[25:24] <= idata[1:0];
+               end
+        8'h11: begin
+             pll_sel <= idata[2:0];
+               end
+        8'h12: begin
+             pll_div <= idata[4:0];
+               end
+        endcase	// (iaddr)
+    end
+    end
+endmodule	// housekeeping_spi
+
+//------------------------------------------------------
+// housekeeping_spi_slave.v
+//------------------------------------------------------
+// General purpose SPI slave module for the Caravel chip
+//------------------------------------------------------
+// Written by Tim Edwards
+// efabless, inc., September 28, 2020
+//------------------------------------------------
+// This file is distributed free and open source
+//------------------------------------------------
+
+// SCK ---   Clock input
+// SDI ---   Data  input
+// SDO ---   Data  output
+// CSB ---   Chip  select (sense negative)
+// idata --- Data from chip to transmit out, in 8 bits
+// odata --- Input data to chip, in 8 bits
+// addr  --- Decoded address to upstream circuits
+// rdstb --- Read strobe, tells upstream circuit to supply next byte to idata
+// wrstb --- Write strobe, tells upstream circuit to latch odata.
+
+// Data format (general purpose):
+// 8 bit format
+// 1st byte:   Command word (see below)
+// 2nd byte:   Address word (register 0 to 255)
+// 3rd byte:   Data word    (value 0 to 255)
+
+// Command format:
+// 00000000  No operation
+// 10000000  Write until CSB raised
+// 01000000  Read  until CSB raised
+// 11000000  Simultaneous read/write until CSB raised
+// 11000100  Pass-through read/write to management area flash SPI until CSB raised
+// 11000101  Pass-through read/write to user area flash SPI until CSB raised
+// wrnnn000  Read/write as above, for nnn = 1 to 7 bytes, then terminate
+
+// Lower three bits are reserved for future use.
+// All serial bytes are read and written msb first.
+
+// Fixed control and status registers
+
+// Address 0 is reserved and contains flags for SPI mode.  This is
+// currently undefined and is always value 0.
+// Address 1 is reserved and contains manufacturer ID low 8 bits.
+// Address 2 is reserved and contains manufacturer ID high 4 bits.
+// Address 3 is reserved and contains product ID (8 bits).
+// Addresses 4 to 7 are reserved and contain the mask ID (32 bits).
+// Addresses 8 to 255 are available for general purpose use.
+
+`define COMMAND  3'b000
+`define ADDRESS  3'b001
+`define DATA     3'b010
+`define USERPASS 3'b100
+`define MGMTPASS 3'b101
+
+module housekeeping_spi_slave(reset, SCK, SDI, CSB, SDO,
+	sdoenb, idata, odata, oaddr, rdstb, wrstb,
+	pass_thru_mgmt, pass_thru_mgmt_delay,
+	pass_thru_user, pass_thru_user_delay, pass_thru_reset);
+
+    input reset;
+    input SCK;
+    input SDI;
+    input CSB;
+    output SDO;
+    output sdoenb;
+    input [7:0] idata;
+    output [7:0] odata;
+    output [7:0] oaddr;
+    output rdstb;
+    output wrstb; 
+    output pass_thru_mgmt;
+    output pass_thru_mgmt_delay;
+    output pass_thru_user;
+    output pass_thru_user_delay;
+    output pass_thru_reset;
+
+    reg  [7:0]  addr;
+    reg		wrstb;
+    reg		rdstb;
+    reg		sdoenb;
+    reg  [2:0]  state;
+    reg  [2:0]  count;
+    reg		writemode;
+    reg		readmode;
+    reg  [2:0]	fixed;
+    wire [7:0]  odata;
+    reg  [6:0]  predata;
+    wire [7:0]  oaddr;
+    reg  [7:0]  ldata;
+    reg		pass_thru_mgmt;
+    reg		pass_thru_mgmt_delay;
+    reg		pre_pass_thru_mgmt;
+    reg		pass_thru_user;
+    reg		pass_thru_user_delay;
+    reg		pre_pass_thru_user;
+    wire	csb_reset;
+
+    assign odata = {predata, SDI};
+    assign oaddr = (state == `ADDRESS) ? {addr[6:0], SDI} : addr;
+    assign SDO = ldata[7];
+    assign csb_reset = CSB | reset;
+    assign pass_thru_reset = pass_thru_mgmt_delay | pre_pass_thru_mgmt;
+
+    // Readback data is captured on the falling edge of SCK so that
+    // it is guaranteed valid at the next rising edge.
+    always @(negedge SCK or posedge csb_reset) begin
+        if (csb_reset == 1'b1) begin
+            wrstb <= 1'b0;
+            ldata  <= 8'b00000000;
+            sdoenb <= 1'b1;
+        end else begin
+
+            // After CSB low, 1st SCK starts command
+
+            if (state == `DATA) begin
+            	if (readmode == 1'b1) begin
+                    sdoenb <= 1'b0;
+                    if (count == 3'b000) begin
+                	ldata <= idata;
+                    end else begin
+                	ldata <= {ldata[6:0], 1'b0};	// Shift out
+                    end
+                end else begin
+                    sdoenb <= 1'b1;
+                end
+
+                // Apply write strobe on SCK negative edge on the next-to-last
+                // data bit so that it updates data on the rising edge of SCK
+                // on the last data bit.
+ 
+                if (count == 3'b111) begin
+                    if (writemode == 1'b1) begin
+                        wrstb <= 1'b1;
+                    end
+                end else begin
+                    wrstb <= 1'b0;
+                end
+	    end else if (state == `MGMTPASS || state == `USERPASS) begin
+		wrstb <= 1'b0;
+		sdoenb <= 1'b0;
+            end else begin
+                wrstb <= 1'b0;
+                sdoenb <= 1'b1;
+            end		// ! state `DATA
+        end		// ! csb_reset
+    end			// always @ ~SCK
+
+    always @(posedge SCK or posedge csb_reset) begin
+        if (csb_reset == 1'b1) begin
+            // Default state on reset
+            addr <= 8'h00;
+            rdstb <= 1'b0;
+            predata <= 7'b0000000;
+            state  <= `COMMAND;
+            count  <= 3'b000;
+            readmode <= 1'b0;
+            writemode <= 1'b0;
+            fixed <= 3'b000;
+	    pass_thru_mgmt <= 1'b0;
+	    pass_thru_mgmt_delay <= 1'b0;
+	    pre_pass_thru_mgmt <= 1'b0;
+	    pass_thru_user = 1'b0;
+	    pass_thru_user_delay <= 1'b0;
+	    pre_pass_thru_user <= 1'b0;
+        end else begin
+            // After csb_reset low, 1st SCK starts command
+            if (state == `COMMAND) begin
+                rdstb <= 1'b0;
+                count <= count + 1;
+        	if (count == 3'b000) begin
+	            writemode <= SDI;
+	        end else if (count == 3'b001) begin
+	            readmode <= SDI;
+	        end else if (count < 3'b101) begin
+	            fixed <= {fixed[1:0], SDI}; 
+	        end else if (count < 3'b110) begin
+		    pass_thru_mgmt_delay <= pre_pass_thru_mgmt;
+		    pass_thru_user_delay <= pre_pass_thru_user;
+	        end else if (count == 3'b111) begin
+		    if (pre_pass_thru_mgmt == 1'b1) begin
+			state <= `MGMTPASS;
+			pre_pass_thru_mgmt <= 1'b0;
+		    end else if (pre_pass_thru_user == 1'b1) begin
+			state <= `USERPASS;
+			pre_pass_thru_user <= 1'b0;
+		    end else begin
+	                state <= `ADDRESS;
+		    end
+	        end
+            end else if (state == `ADDRESS) begin
+	        count <= count + 1;
+	        addr <= {addr[6:0], SDI};
+	        if (count == 3'b111) begin
+	            if (readmode == 1'b1) begin
+	            	rdstb <= 1'b1;
+	            end
+	            state <= `DATA;
+	        end else begin
+	            rdstb <= 1'b0;
+	        end
+            end else if (state == `DATA) begin
+	        predata <= {predata[6:0], SDI};
+	        count <= count + 1;
+	        if (count == 3'b111) begin
+	            if (fixed == 3'b001) begin
+	                state <= `COMMAND;
+	            end else if (fixed != 3'b000) begin
+	                fixed <= fixed - 1;
+	                addr <= addr + 1;	// Auto increment address (fixed)
+	            end else begin	
+	                addr <= addr + 1;	// Auto increment address (streaming)
+	            end
+	        end else begin
+	            rdstb <= 1'b0;
+	        end
+            end		// ! state `DATA
+        end		// ! csb_reset 
+    end			// always @ SCK
+
+endmodule // housekeeping_spi_slave
diff --git a/verilog/rtl/mgmt_core.v b/verilog/rtl/mgmt_core.v
index 26e7e55..bd52027 100644
--- a/verilog/rtl/mgmt_core.v
+++ b/verilog/rtl/mgmt_core.v
@@ -19,8 +19,7 @@
 	output flash_io1_oeb,
 	output flash_csb_ieb,
 	output flash_clk_ieb,
-	output flash_io0_ieb,
-	output flash_io1_ieb,
+	output flash_io0_ieb, output flash_io1_ieb,
 	output flash_io0_do,
 	output flash_io1_do,
 	input flash_io0_di,
@@ -29,14 +28,17 @@
 	input porb,
 	// Clocking
 	input clock,
-	input ext_clk,
 	output pll_clk16,
 	// LA signals
     	input  [127:0] la_input,           	// From Mega-Project to cpu
     	output [127:0] la_output,          	// From CPU to Mega-Project
     	output [127:0] la_oen,              // LA output enable  
 	// Mega-Project Control Signals
-	inout [`MPRJ_IO_PADS-1:0] mgmt_io_data,
+	// inout [`MPRJ_IO_PADS-1:0] mgmt_io_data,
+	input [`MPRJ_IO_PADS-1:0] mgmt_in_data,
+	output [`MPRJ_IO_PADS-1:0] mgmt_out_data,
+	output [`MPRJ_IO_PADS-1:0] mgmt_outz_data,
+	output [`MPRJ_IO_PADS-1:0] mgmt_oeb_data,
 	output mprj_io_loader_resetn,
 	output mprj_io_loader_clock,
 	output mprj_io_loader_data,
@@ -66,22 +68,16 @@
 	input [31:0] mask_rev
 );
     	wire ext_clk_sel;
-    	wire ext_clk;
     	wire pll_clk;
     	wire ext_reset;
 
-	wire spi_sck;
-	wire spi_csb;
-	wire spi_sdi;
-	wire spi_sdo;
-
 	caravel_clkrst clkrst(
 	`ifdef LVS
 		.vdd1v8(vdd1v8),
 		.vss(vss),
 	`endif		
 		.ext_clk_sel(ext_clk_sel),
-		.ext_clk(ext_clk),
+		.ext_clk(clock),		// Should be better handled. . .
 		.pll_clk(pll_clk),
 		.resetb(porb), 
 		.ext_reset(ext_reset),
@@ -93,18 +89,22 @@
 	// area pins, when under control of the management area (during
 	// startup, and when not otherwise programmed for the user project).
 
-	// JTAG      = mgmt_io_data[0]       (inout)
-	// SDO       = mgmt_io_data[1]       (output)	(shared with SPI master)
-	// SDI       = mgmt_io_data[2]       (input)	(shared with SPI master)
-	// CSB       = mgmt_io_data[3]       (input)	(shared with SPI master)
-	// SCK       = mgmt_io_data[4]       (input)	(shared with SPI master)
-	// ser_rx    = mgmt_io_data[5]       (input)
-	// ser_tx    = mgmt_io_data[6]       (output)
-	// irq       = mgmt_io_data[7]       (input)
-	// flash_csb = mgmt_io_data[8]	     (output)	(user area flash)
-	// flash_sck = mgmt_io_data[9]	     (output)	(user area flash)
-	// flash_io0 = mgmt_io_data[10]	     (output)	(user area flash)
-	// flash_io1 = mgmt_io_data[11]	     (input)	(user area flash)
+	// JTAG      = mgmt_in/out_data[0]   (inout)
+	// SDO       = mgmt_out_data[1]      (output)	(shared with SPI master)
+	// SDI       = mgmt_in_data[2]       (input)	(shared with SPI master)
+	// CSB       = mgmt_in_data[3]       (input)	(shared with SPI master)
+	// SCK       = mgmt_in_data[4]       (input)	(shared with SPI master)
+	// ser_rx    = mgmt_in_data[5]       (input)
+	// ser_tx    = mgmt_out_data[6]      (output)
+	// irq       = mgmt_in_data[7]       (input)
+	// flash_csb = mgmt_out_data[8]	     (output)	(user area flash)
+	// flash_sck = mgmt_out_data[9]	     (output)	(user area flash)
+	// flash_io0 = mgmt_in/out_data[10]  (input)	(user area flash)
+	// flash_io1 = mgmt_in/out_data[11]  (output)	(user area flash)
+
+	// OEB lines for [0] and [1] are the only ones connected directly to
+	// the pad.  All others have OEB controlled by the configuration bit
+	// in the control block.
 
 	mgmt_soc soc (
     	    `ifdef LVS
@@ -112,7 +112,7 @@
         	.vss(vss),
     	    `endif
         	.pll_clk(pll_clk),
-		.ext_clk(ext_clk),
+		.ext_clk(clock),
 		.ext_clk_sel(ext_clk_sel),
 		.clk(core_clk),
 		.resetn(core_rstn),
@@ -125,15 +125,16 @@
 		.gpio_outenb_pad(gpio_outenb_pad),
 		.gpio_inenb_pad(gpio_inenb_pad),
 		// UART
-		.ser_tx(mgmt_io_data[6]),
-		.ser_rx(mgmt_io_data[5]),
-		.irq_pin(mgmt_io_data[7]),
+		.ser_tx(mgmt_out_data[6]),
+		.ser_rx(mgmt_in_data[5]),
+		.irq_pin(mgmt_in_data[7]),
 		.irq_spi(irq_spi),
 		// SPI master
-		.spi_csb(spi_csb),
-		.spi_sck(spi_sck),
-		.spi_sdi(spi_sdi),
-		.spi_sdo(spi_sdo),
+		.spi_csb(mgmt_out_data[3]),
+		.spi_sck(mgmt_out_data[4]),
+		.spi_sdi(mgmt_in_data[1]),
+		.spi_sdo(mgmt_out_data[2]),
+		.spi_sdoenb(mgmt_oeb_data[2]),
 		// Flash
 		.flash_csb(flash_csb),
 		.flash_clk(flash_clk),
@@ -172,7 +173,11 @@
 		.mprj_io_loader_clock(mprj_io_loader_clock),
 		.mprj_io_loader_data(mprj_io_loader_data),
 		// I/O data
-		.mgmt_io_data(mgmt_io_data),
+		// .mgmt_io_data(mgmt_io_data),
+		.mgmt_in_data(mgmt_in_data),
+		.mgmt_out_data(mgmt_out_data),
+		.mgmt_outz_data(mgmt_outz_data),
+		.mgmt_oeb_data(mgmt_oeb_data),
 		// Mega Project Slave ports (WB MI A)
 		.mprj_cyc_o(mprj_cyc_o),
 		.mprj_stb_o(mprj_stb_o),
@@ -217,28 +222,25 @@
 	wire [25:0] spi_pll_trim;
 
 	// Housekeeping SPI (SPI slave module)
-	caravel_spi housekeeping (
+	housekeeping_spi housekeeping (
 	    `ifdef LVS
 		.vdd(vdd1v8),
 		.vss(vss),
 	    `endif
 	    .RSTB(porb),
-	    .SCK(mgmt_io_data[4]),
-	    .SDI(mgmt_io_data[2]),
-	    .CSB(mgmt_io_data[3]),
-	    .SDO(mgmt_io_data[1]),
+	    .SCK(mgmt_in_data[4]),
+	    .SDI(mgmt_in_data[2]),
+	    .CSB(mgmt_in_data[3]),
+	    .SDO(mgmt_out_data[1]),
+	    .sdo_enb(mgmt_oeb_data[1]),
 	     // Note that the Soc SPI master shares pins with the housekeeping
 	     // SPI but with SDI and SDO reversed, such that the CPU can
 	     // access the housekeeping SPI registers directly if the
 	     // SPI master is enabled.
-	    .mgmt_sck(mgmt_io_data[4]),
-	    .mgmt_sdi(mgmt_io_data[1]),
-	    .mgmt_csb(mgmt_io_data[3]),
-	    .mgmt_sdo(mgmt_io_data[2]),
-	     // NOTE:  SDO enable is not accessible in the current configuration.
-	     // May want to have a different type of GPIO control for the several
-	     // pins like SPI SDO that could benefit from it.
-	    .sdo_enb(),
+	    .mgmt_sck(mgmt_in_data[4]),
+	    .mgmt_sdi(mgmt_in_data[1]),
+	    .mgmt_csb(mgmt_in_data[3]),
+	    .mgmt_sdo(mgmt_out_data[2]),
 	    .pll_dco_ena(spi_pll_dco_ena),
 	    .pll_sel(spi_pll_sel),
 	    .pll_div(spi_pll_div),
@@ -253,10 +255,10 @@
     	    .pass_thru_mgmt_csb(pass_thru_mgmt_csb),
     	    .pass_thru_mgmt_sdi(pass_thru_mgmt_sdi),
     	    .pass_thru_mgmt_sdo(pass_thru_mgmt_sdo),
-    	    .pass_thru_user_sck(mgmt_io_data[9]),
-    	    .pass_thru_user_csb(mgmt_io_data[8]),
-    	    .pass_thru_user_sdi(mgmt_io_data[10]),
-    	    .pass_thru_user_sdo(mgmt_io_data[11])
+    	    .pass_thru_user_sck(mgmt_out_data[9]),
+    	    .pass_thru_user_csb(mgmt_out_data[8]),
+    	    .pass_thru_user_sdi(mgmt_out_data[10]),
+    	    .pass_thru_user_sdo(mgmt_in_data[11])
 	);
 
 endmodule
diff --git a/verilog/rtl/mgmt_soc.v b/verilog/rtl/mgmt_soc.v
index 5162a9b..ce43250 100644
--- a/verilog/rtl/mgmt_soc.v
+++ b/verilog/rtl/mgmt_soc.v
@@ -76,12 +76,17 @@
     output mprj_io_loader_data,
 
     // Mega-Project pad data (when management SoC controls the pad)
-    inout [MPRJ_IO_PADS-1:0] mgmt_io_data,
+    // inout [MPRJ_IO_PADS-1:0] mgmt_io_data,
+    input [MPRJ_IO_PADS-1:0] mgmt_in_data,
+    output [MPRJ_IO_PADS-1:0] mgmt_out_data,
+    output [MPRJ_IO_PADS-1:0] mgmt_outz_data,
+    output [MPRJ_IO_PADS-1:0] mgmt_oeb_data,
 
     // SPI master
     output spi_csb,
     output spi_sck,
     output spi_sdo,
+    output spi_sdoenb,
     input  spi_sdi,
 
     // UART
@@ -209,9 +214,9 @@
     parameter MPRJ_PWR_PADS = 32;
    
     // System Control Registers
-    parameter PLL_OUT       = 8'h0c;
-    parameter TRAP_OUT      = 8'h10;
-    parameter IRQ7_SRC      = 8'h14;
+    parameter PLL_OUT       = 8'h00;
+    parameter TRAP_OUT      = 8'h04;
+    parameter IRQ7_SRC      = 8'h08;
 
     // Wishbone Interconnect 
     localparam ADR_WIDTH = 32;
@@ -477,6 +482,7 @@
         .sck(spi_sck),
         .sdi(spi_sdi),
         .sdo(spi_sdo),
+        .sdoenb(spi_sdoenb),
 	.irq(irq_spi_master)
     );
 
@@ -650,7 +656,11 @@
 	.serial_clock(mprj_io_loader_clock),
 	.serial_resetn(mprj_io_loader_resetn),
 	.serial_data_out(mprj_io_loader_data),
-	.mgmt_gpio_io(mgmt_io_data)
+	// .mgmt_gpio_io(mgmt_io_data)
+	.mgmt_gpio_in(mgmt_in_data),
+	.mgmt_gpio_out(mgmt_out_data),
+	.mgmt_gpio_outz(mgmt_outz_data),
+	.mgmt_gpio_oeb(mgmt_oeb_data)
     );
 
     // Wishbone Slave RAM
diff --git a/verilog/rtl/mprj_ctrl.v b/verilog/rtl/mprj_ctrl.v
index 8970c41..cb67ac4 100644
--- a/verilog/rtl/mprj_ctrl.v
+++ b/verilog/rtl/mprj_ctrl.v
@@ -25,7 +25,10 @@
     output serial_data_out,
 
     // Read/write data to each GPIO pad from management SoC
-    inout [IO_PADS-1:0] mgmt_gpio_io
+    input [IO_PADS-1:0] mgmt_gpio_in,
+    output [IO_PADS-1:0] mgmt_gpio_out,
+    output [IO_PADS-1:0] mgmt_gpio_outz,
+    output [IO_PADS-1:0] mgmt_gpio_oeb		// Only JTAG and SDO connected
 );
     wire resetn;
     wire valid;
@@ -58,7 +61,11 @@
 	.serial_clock(serial_clock),
 	.serial_resetn(serial_resetn),
 	.serial_data_out(serial_data_out),
-	.mgmt_gpio_io(mgmt_gpio_io)
+	// .mgmt_gpio_io(mgmt_gpio_io)
+	.mgmt_gpio_in(mgmt_gpio_in),
+	.mgmt_gpio_out(mgmt_gpio_out),
+	.mgmt_gpio_outz(mgmt_gpio_outz),
+	.mgmt_gpio_oeb(mgmt_gpio_oeb)
     );
 
 endmodule
@@ -70,7 +77,7 @@
     parameter CONFIG = 8'h 08,
     parameter IO_PADS = 32,
     parameter PWR_PADS = 32,
-    parameter IO_CTRL_BITS = 14,
+    parameter IO_CTRL_BITS = 13,
     parameter PWR_CTRL_BITS = 1
 )(
     input clk,
@@ -86,26 +93,35 @@
     output serial_clock,
     output serial_resetn,
     output serial_data_out,
-    inout [IO_PADS-1:0] mgmt_gpio_io
+    // inout [IO_PADS-1:0] mgmt_gpio_io
+    input  [IO_PADS-1:0] mgmt_gpio_in,
+    output [IO_PADS-1:0] mgmt_gpio_out,
+    output [IO_PADS-1:0] mgmt_gpio_outz,
+    output [IO_PADS-1:0] mgmt_gpio_oeb
 );
 
-`define START	2'b00
-`define XBYTE	2'b01
-`define LOAD	2'b10
+`define IDLE	2'b00
+`define START	2'b01
+`define XBYTE	2'b10
+`define LOAD	2'b11
 
     localparam IO_BASE_ADR = (BASE_ADR | CONFIG);
     localparam PWR_BASE_ADR = (BASE_ADR | CONFIG) + IO_PADS*4;
-    localparam OEB = 1;			// Offset of OEB in shift register block.
+    localparam OEB = 1;			// Offset of output enable in shift register.
+    localparam INP_DIS = 3;		// Offset of input disable in shift register. 
 
     reg [IO_CTRL_BITS-1:0] io_ctrl [IO_PADS-1:0];  // I/O control, 1 word per gpio pad
     reg [PWR_CTRL_BITS-1:0] pwr_ctrl [PWR_PADS-1:0];// Power control, 1 word per power pad
-    reg [IO_PADS-1:0] mgmt_gpio_out;	// I/O read/write data, 1 bit per gpio pad
+    reg [IO_PADS-1:0] mgmt_gpio_out; // I/O write data, 1 bit per gpio pad
+    wire [IO_PADS-1:0] mgmt_gpio_outz;	 // I/O write data output when input disabled
+    wire [IO_PADS-1:0] mgmt_gpio_oeb;
     reg xfer_ctrl;			// Transfer control (1 bit)
 
     wire [IO_PADS-1:0] io_ctrl_sel;	// wishbone selects
     wire [PWR_PADS-1:0] pwr_ctrl_sel;
     wire io_data_sel;
     wire xfer_sel;
+    wire [IO_PADS-1:0] mgmt_gpio_in;
 
     assign xfer_sel = (iomem_addr[7:0] == XFER);
     assign io_data_sel = (iomem_addr[7:0] == DATA); 
@@ -114,14 +130,18 @@
     // if OEB = 0 then mgmt_gpio_out --> mgmt_gpio_io;  if OEB = 1 then
     // mgmt_gpio_io --> mgmt_gpio_in.  mgmt_gpio_in is always a copy of mgmt_gpio_io.
 
-    assign mgmt_gpio_in = mgmt_gpio_io;
+    // assign mgmt_gpio_in = mgmt_gpio_io;
 
     genvar i;
     generate
         for (i=0; i<IO_PADS; i=i+1) begin
             assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4)); 
-            assign mgmt_gpio_io[i] = (io_ctrl[0][i] + OEB == 1'b0) ?
-				mgmt_gpio_out[i] : 1'bz;
+	    // OEB is both tranferred by serial chain and output;  that way
+	    // each pad can selectively choose whether to have a dedicated
+	    // signal for OEB, or to use it as a static configuration bit.
+    	    assign mgmt_gpio_oeb[i] = io_ctrl[OEB][i];
+    	    assign mgmt_gpio_outz[i] = (io_ctrl[INP_DIS][i] == 1'b1) ?
+			mgmt_gpio_out[i] : 1'bz;
         end
     endgenerate
 
@@ -145,8 +165,9 @@
 
 		if (io_data_sel) begin
 		    iomem_rdata <= mgmt_gpio_in;
-		    mgmt_gpio_out <= 'd0;
-		    if (iomem_wstrb[0]) mgmt_gpio_out[IO_PADS-1:0] <= iomem_wdata[IO_PADS-1:0];
+		    if (iomem_wstrb[0]) begin
+			mgmt_gpio_out[IO_PADS-1:0] <= iomem_wdata[IO_PADS-1:0];
+		    end
 
 		end else if (xfer_sel) begin
 		    iomem_rdata <= {31'd0, xfer_ctrl};
@@ -162,7 +183,9 @@
                 if (!resetn) begin
 		    // NOTE:  This needs to be set to the specific bit sequence
 		    // that initializes every I/O pad to the appropriate state on
-		    // startup.
+		    // startup, to match the startup state at each pad.  Otherwise
+		    // surprises happen if not all pad configurations are applied
+		    // from the program code, and a transfer is initiated.
                     io_ctrl[i] <= 'd0;
                 end else begin
                     if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
@@ -213,7 +236,7 @@
     always @(posedge clk or negedge resetn) begin
 	if (resetn == 1'b0) begin
 
-	    xfer_state <= `START;
+	    xfer_state <= `IDLE;
 	    xfer_count <= 4'd0;
 	    pad_count  <= 6'd0;
 	    serial_resetn <= 1'b0;
@@ -222,7 +245,13 @@
 
 	end else begin
 
-	    if (xfer_state == `START) begin
+	    if (xfer_state == `IDLE) begin
+	    	serial_resetn <= 1'b0;
+		serial_clock <= 1'b0;
+		if (xfer_ctrl == 1'b1) begin
+		    xfer_state <= `START;
+		end
+	    end else if (xfer_state == `START) begin
 	    	serial_resetn <= 1'b1;
 		serial_clock <= 1'b0;
 	    	xfer_count <= 6'd0;
@@ -266,7 +295,7 @@
 		end else if (xfer_count == 4'd3) begin
 		    serial_resetn <= 1'b1;
 		    serial_clock <= 1'b0;
-		    xfer_state <= `START;
+		    xfer_state <= `IDLE;
 		end
 	    end	
 	end
diff --git a/verilog/rtl/mprj_ctrl.v.orig b/verilog/rtl/mprj_ctrl.v.orig
new file mode 100644
index 0000000..35fc346
--- /dev/null
+++ b/verilog/rtl/mprj_ctrl.v.orig
@@ -0,0 +1,283 @@
+module mprj_ctrl_wb #(
+    parameter BASE_ADR = 32'h 2300_0000,
+    parameter DATA   = 8'h 00,
+    parameter XFER   = 8'h 04,
+    parameter CONFIG = 8'h 08,
+    parameter IO_PADS = 32,   // Number of IO control registers
+    parameter PWR_PADS = 32   // Number of power control registers
+)(
+    input wb_clk_i,
+    input wb_rst_i,
+
+    input [31:0] wb_dat_i,
+    input [31:0] wb_adr_i,
+    input [3:0] wb_sel_i,
+    input wb_cyc_i,
+    input wb_stb_i,
+    input wb_we_i,
+
+    output [31:0] wb_dat_o,
+    output wb_ack_o,
+
+    // Output is to serial loader
+    output serial_clock,
+    output serial_resetn,
+    output serial_data_out,
+
+    // Read/write data to each GPIO pad from management SoC
+    inout [IO_PADS-1:0] mgmt_gpio_io
+);
+    wire resetn;
+    wire valid;
+    wire ready;
+    wire [3:0] iomem_we;
+
+    assign resetn = ~wb_rst_i;
+    assign valid  = wb_stb_i && wb_cyc_i; 
+
+    assign iomem_we = wb_sel_i & {4{wb_we_i}};
+    assign wb_ack_o = ready;
+
+    mprj_ctrl #(
+        .BASE_ADR(BASE_ADR),
+	.DATA(DATA),
+        .CONFIG(CONFIG),
+        .XFER(XFER),
+	.IO_PADS(IO_PADS),
+        .PWR_PADS(PWR_PADS)
+    ) mprj_ctrl (
+        .clk(wb_clk_i),
+        .resetn(resetn),
+        .iomem_addr(wb_adr_i),
+        .iomem_valid(valid),
+        .iomem_wstrb(iomem_we[1:0]),
+        .iomem_wdata(wb_dat_i),
+        .iomem_rdata(wb_dat_o),
+        .iomem_ready(ready),
+
+	.serial_clock(serial_clock),
+	.serial_resetn(serial_resetn),
+	.serial_data_out(serial_data_out),
+	.mgmt_gpio_io(mgmt_gpio_io)
+    );
+
+endmodule
+
+module mprj_ctrl #(
+    parameter BASE_ADR = 32'h 2300_0000,
+    parameter DATA   = 8'h 00,
+    parameter XFER   = 8'h 04,
+    parameter CONFIG = 8'h 08,
+    parameter IO_PADS = 32,
+    parameter PWR_PADS = 32,
+    parameter IO_CTRL_BITS = 14,
+    parameter PWR_CTRL_BITS = 1
+)(
+    input clk,
+    input resetn,
+
+    input [31:0] iomem_addr,
+    input iomem_valid,
+    input [1:0] iomem_wstrb,
+    input [31:0] iomem_wdata,
+    output reg [31:0] iomem_rdata,
+    output reg iomem_ready,
+
+    output serial_clock,
+    output serial_resetn,
+    output serial_data_out,
+    inout [IO_PADS-1:0] mgmt_gpio_io
+);
+
+`define IDLE	2'b00
+`define START	2'b01
+`define XBYTE	2'b10
+`define LOAD	2'b11
+
+    localparam IO_BASE_ADR = (BASE_ADR | CONFIG);
+    localparam PWR_BASE_ADR = (BASE_ADR | CONFIG) + IO_PADS*4;
+    localparam OEB = 1;			// Offset of OEB in shift register block.
+
+    reg [IO_CTRL_BITS-1:0] io_ctrl [IO_PADS-1:0];  // I/O control, 1 word per gpio pad
+    reg [PWR_CTRL_BITS-1:0] pwr_ctrl [PWR_PADS-1:0];// Power control, 1 word per power pad
+    reg [IO_PADS-1:0] mgmt_gpio_out;	// I/O read/write data, 1 bit per gpio pad
+    reg xfer_ctrl;			// Transfer control (1 bit)
+
+    wire [IO_PADS-1:0] io_ctrl_sel;	// wishbone selects
+    wire [PWR_PADS-1:0] pwr_ctrl_sel;
+    wire io_data_sel;
+    wire xfer_sel;
+    wire [IO_PADS-1:0] mgmt_gpio_in;
+
+    assign xfer_sel = (iomem_addr[7:0] == XFER);
+    assign io_data_sel = (iomem_addr[7:0] == DATA); 
+
+    // Direction of mgmt_gpio_io depends on the value of io_ctrl pad bit 1 (OEB)
+    // if OEB = 0 then mgmt_gpio_out --> mgmt_gpio_io;  if OEB = 1 then
+    // mgmt_gpio_io --> mgmt_gpio_in.  mgmt_gpio_in is always a copy of mgmt_gpio_io.
+
+    assign mgmt_gpio_in = mgmt_gpio_io;
+
+    genvar i;
+    generate
+        for (i=0; i<IO_PADS; i=i+1) begin
+            assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4)); 
+            assign mgmt_gpio_io[i] = (io_ctrl[0][i] + OEB == 1'b0) ?
+				mgmt_gpio_out[i] : 1'bz;
+        end
+    endgenerate
+
+    generate
+        for (i=0; i<PWR_PADS; i=i+1) begin
+            assign pwr_ctrl_sel[i] = (iomem_addr[7:0] == (PWR_BASE_ADR[7:0] + i*4)); 
+        end
+    endgenerate
+
+    // I/O transfer of xfer bit and gpio data to/from user project region under
+    // management SoC control
+
+    always @(posedge clk) begin
+	if (!resetn) begin
+	    xfer_ctrl <= 0;
+	    mgmt_gpio_out <= 'd0;
+	end else begin
+	    iomem_ready <= 0;
+	    if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
+		iomem_ready <= 1'b 1;
+
+		if (io_data_sel) begin
+		    iomem_rdata <= mgmt_gpio_in;
+		    mgmt_gpio_out <= 'd0;
+		    if (iomem_wstrb[0]) mgmt_gpio_out[IO_PADS-1:0] <= iomem_wdata[IO_PADS-1:0];
+
+		end else if (xfer_sel) begin
+		    iomem_rdata <= {31'd0, xfer_ctrl};
+		    if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[1:0];
+		end
+	    end
+	end
+    end
+
+    generate 
+        for (i=0; i<IO_PADS; i=i+1) begin
+             always @(posedge clk) begin
+                if (!resetn) begin
+		    // NOTE:  This needs to be set to the specific bit sequence
+		    // that initializes every I/O pad to the appropriate state on
+		    // startup.
+                    io_ctrl[i] <= 'd0;
+                end else begin
+                    if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
+                        if (io_ctrl_sel[i]) begin
+                            iomem_rdata <= io_ctrl[i];
+			    // NOTE:  Byte-wide write to io_ctrl is prohibited
+                            if (iomem_wstrb[0])
+				io_ctrl[i] <= iomem_wdata[IO_CTRL_BITS-1:0];
+                        end 
+                    end
+                end
+            end
+        end
+    endgenerate
+
+    generate 
+        for (i=0; i<PWR_PADS; i=i+1) begin
+             always @(posedge clk) begin
+                if (!resetn) begin
+                    pwr_ctrl[i] <= 'd0;
+                end else begin
+                    if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
+                        if (pwr_ctrl_sel[i]) begin
+                            iomem_rdata <= pwr_ctrl[i];
+                            if (iomem_wstrb[0])
+				pwr_ctrl[i] <= iomem_wdata[PWR_CTRL_BITS-1:0];
+                        end 
+                    end
+                end
+            end
+        end
+    endgenerate
+
+    reg [3:0]  xfer_count;
+    reg [5:0]  pad_count;
+    reg [1:0]  xfer_state;
+    reg	       serial_clock;
+    reg	       serial_resetn;
+    reg	       serial_data_out;
+
+    // NOTE:  Ignoring power control bits for now. . .  need to revisit.
+    // Depends on how the power pads are arranged among the GPIO, and
+    // whether or not switching will be internal and under the control
+    // of the SoC.
+
+    reg [IO_CTRL_BITS-1:0] serial_data_staging;
+
+    always @(posedge clk or negedge resetn) begin
+	if (resetn == 1'b0) begin
+
+	    xfer_state <= `IDLE;
+	    xfer_count <= 4'd0;
+	    pad_count  <= 6'd0;
+	    serial_resetn <= 1'b0;
+	    serial_clock <= 1'b0;
+	    serial_data_out <= 1'b0;
+
+	end else begin
+
+	    if (xfer_state == `IDLE) begin
+	    	serial_resetn <= 1'b0;
+		serial_clock <= 1'b0;
+		if (xfer_ctrl == 1'b1) begin
+		    xfer_state <= `START;
+		end
+	    end else if (xfer_state == `START) begin
+	    	serial_resetn <= 1'b1;
+		serial_clock <= 1'b0;
+	    	xfer_count <= 6'd0;
+		if (pad_count == IO_PADS) begin
+		    xfer_state <= `LOAD;
+		end else begin
+		    pad_count <= pad_count + 1;
+		    xfer_state <= `XBYTE;
+		    serial_data_staging <= io_ctrl[pad_count];
+		end
+	    end else if (xfer_state == `XBYTE) begin
+	    	serial_resetn <= 1'b1;
+		serial_clock <= ~serial_clock;
+		if (serial_clock == 1'b0) begin
+		    if (xfer_count == IO_CTRL_BITS) begin
+		    	xfer_state <= `START;
+		    end else begin
+		    	xfer_count <= xfer_count + 1;
+		    end
+		end else begin
+		    serial_data_staging <= {serial_data_staging[IO_CTRL_BITS-2:0], 1'b0};
+		    serial_data_out <= serial_data_staging[IO_CTRL_BITS-1];
+		end
+	    end else if (xfer_state == `LOAD) begin
+		xfer_count <= xfer_count + 1;
+
+		/* Load sequence:  Raise clock for final data shift in;
+		 * Pulse reset low while clock is high
+		 * Set clock back to zero.
+		 * Return to idle mode.
+		 */
+		if (xfer_count == 4'd0) begin
+		    serial_clock <= 1'b1;
+		    serial_resetn <= 1'b1;
+		end else if (xfer_count == 4'd1) begin
+		    serial_clock <= 1'b1;
+		    serial_resetn <= 1'b0;
+		end else if (xfer_count == 4'd2) begin
+		    serial_clock <= 1'b1;
+		    serial_resetn <= 1'b1;
+		end else if (xfer_count == 4'd3) begin
+		    serial_resetn <= 1'b1;
+		    serial_clock <= 1'b0;
+		    xfer_state <= `IDLE;
+		end
+	    end	
+	end
+    end
+
+endmodule
diff --git a/verilog/rtl/mprj_io.v b/verilog/rtl/mprj_io.v
index 0238649..32ae628 100644
--- a/verilog/rtl/mprj_io.v
+++ b/verilog/rtl/mprj_io.v
@@ -1,14 +1,16 @@
 module mprj_io(
-    inout vdd,
+    inout vdd3v3,
     inout vdd1v8,
     inout vss,
     input vddio_q,
     input vssio_q,
     input analog_a,
     input analog_b,
-    input [`MPRJ_IO_PADS-1:0] io,
+    input porb_h,
+    input por,
+    inout [`MPRJ_IO_PADS-1:0] io,
     input [`MPRJ_IO_PADS-1:0] io_out,
-    input [`MPRJ_IO_PADS-1:0] oeb_n,
+    input [`MPRJ_IO_PADS-1:0] oeb,
     input [`MPRJ_IO_PADS-1:0] hldh_n,
     input [`MPRJ_IO_PADS-1:0] enh,
     input [`MPRJ_IO_PADS-1:0] inp_dis,
@@ -22,10 +24,9 @@
     input [`MPRJ_IO_PADS*3-1:0] dm,
     output [`MPRJ_IO_PADS-1:0] io_in
 );
-
-	`MPRJ_IO_PAD_V(io, io_in, io_out, `MPRJ_IO_PADS, 
-		oeb_n, hldh_n, enh, inp_dis, ib_mode_sel,
-		vtrip_sel, slow_sel, holdolver,
-		analog_en, analog_sel, analog_pol, dm);
+    `MPRJ_IO_PAD_V(io, io_in, io_out, `MPRJ_IO_PADS, 
+    		oeb, hldh_n, enh, inp_dis, ib_mode_sel,
+    		vtrip_sel, slow_sel, holdover,
+    		analog_en, analog_sel, analog_pol, dm);
 
 endmodule
diff --git a/verilog/rtl/simple_spi_master.v b/verilog/rtl/simple_spi_master.v
index de6ac2a..dad5471 100755
--- a/verilog/rtl/simple_spi_master.v
+++ b/verilog/rtl/simple_spi_master.v
@@ -82,6 +82,7 @@
     output 	 csb,	 // SPI chip select
     output 	 sck,	 // SPI clock
     output 	 sdo,	 // SPI output
+    output 	 sdoenb, // SPI output enable
     output	 irq	 // interrupt output
 );
 
@@ -175,13 +176,16 @@
     wire	  irq_out;
     wire	  sck;
     wire	  sdo;
+    wire	  sdoenb;
 
     // Define behavior for inverted SCK and inverted CSB
-    assign    	  csb = (invcsb) ? ~icsb : icsb;
-    assign	  sck = (invsck) ? ~isck : isck;
+    assign    	  csb = (enable == 1'b0) ? 1'bz : (invcsb) ? ~icsb : icsb;
+    assign	  sck = (enable == 1'b0) ? 1'bz : (invsck) ? ~isck : isck;
 
     // No bidirectional 3-pin mode defined, so SDO is enabled whenever CSB is low.
-    assign	  sdo = icsb ? 1'bz : isdo;
+    assign	  sdoenb = icsb;
+    // assign	  sdo = (enable == 1'b0) ? 1'bz : icsb ? 1'bz : isdo;
+    assign	  sdo = isdo;
 
     assign	  irq_out = irqena & done;
 
diff --git a/verilog/rtl/spimemio.v b/verilog/rtl/spimemio.v
index 456c2d0..2d0b6fe 100644
--- a/verilog/rtl/spimemio.v
+++ b/verilog/rtl/spimemio.v
@@ -132,7 +132,13 @@
 
         .cfgreg_we(cfgreg_we),
         .cfgreg_di(wb_dat_i),
-        .cfgreg_do(spimemio_cfgreg_do)
+        .cfgreg_do(spimemio_cfgreg_do),
+
+	.pass_thru(pass_thru),
+	.pass_thru_csb(pass_thru_csb),
+	.pass_thru_sck(pass_thru_sck),
+	.pass_thru_sdi(pass_thru_sdi),
+	.pass_thru_sdo(pass_thru_sdo)
     );
 
 endmodule
@@ -176,7 +182,13 @@
 
     input   [3:0] cfgreg_we,
     input  [31:0] cfgreg_di,
-    output [31:0] cfgreg_do
+    output [31:0] cfgreg_do,
+
+    input  pass_thru,
+    input  pass_thru_csb,
+    input  pass_thru_sck,
+    input  pass_thru_sdi,
+    output pass_thru_sdo
 );
     reg        xfer_resetn;
     reg        din_valid;
diff --git a/verilog/rtl/sysctrl.v b/verilog/rtl/sysctrl.v
index 62ed4fc..86ec1e5 100644
--- a/verilog/rtl/sysctrl.v
+++ b/verilog/rtl/sysctrl.v
@@ -1,8 +1,8 @@
 module sysctrl_wb #(
     parameter BASE_ADR      = 32'h2F00_0000,
-    parameter PLL_OUT       = 8'h0c,
-    parameter TRAP_OUT      = 8'h10,
-    parameter IRQ7_SRC      = 8'h14
+    parameter PLL_OUT       = 8'h00,
+    parameter TRAP_OUT      = 8'h04,
+    parameter IRQ7_SRC      = 8'h08
 ) (
     input wb_clk_i,
     input wb_rst_i,
@@ -60,9 +60,9 @@
 
 module sysctrl #(
     parameter BASE_ADR = 32'h2300_0000,
-    parameter PLL_OUT       = 8'h0c,
-    parameter TRAP_OUT      = 8'h10,
-    parameter IRQ7_SRC      = 8'h14
+    parameter PLL_OUT       = 8'h00,
+    parameter TRAP_OUT      = 8'h04,
+    parameter IRQ7_SRC      = 8'h08
 ) (
     input clk,
     input resetn,