| `default_nettype none | 
 | /*  | 
 |  *--------------------------------------------------------------------- | 
 |  * 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_block #( | 
 |     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 | 
 | ) ( | 
 |     `ifdef USE_POWER_PINS | 
 |          inout vccd, | 
 |          inout vssd, | 
 |          inout vccd1, | 
 |          inout vssd1, | 
 |     `endif | 
 |  | 
 |     // 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 INP_DIS = 3; | 
 |     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 | 
 |     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; | 
 |  | 
 |     wire user_gpio_in; | 
 |     wire gpio_in_unbuf; | 
 |     wire gpio_logic1; | 
 |  | 
 |     /* 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 gpio_in_unbuf =    (mgmt_ena) ? 1'b0 : pad_gpio_in; | 
 |     assign mgmt_gpio_in =    (mgmt_ena) ? ((gpio_inenb == 1'b0) ? | 
 | 					pad_gpio_in : 1'bz) : 1'b0; | 
 |  | 
 |     assign pad_gpio_outenb =  (mgmt_ena) ? ((mgmt_gpio_oeb == 1'b1) ? gpio_outenb : | 
 | 					1'b0) : user_gpio_oeb; | 
 |     assign pad_gpio_out    =  (mgmt_ena) ?  | 
 | 			((mgmt_gpio_oeb == 1'b1) ? | 
 | 			((gpio_dm[2:1] == 2'b01) ? ~gpio_dm[0] : mgmt_gpio_out) : | 
 | 			mgmt_gpio_out) : | 
 | 			user_gpio_out;  | 
 |  | 
 |     /* Buffer user_gpio_in with an enable that is set by the user domain vccd */ | 
 |  | 
 |     sky130_fd_sc_hd__conb_1 gpio_logic_high ( | 
 | `ifdef USE_POWER_PINS | 
 |             .VPWR(vccd1), | 
 |             .VGND(vssd1), | 
 |             .VPB(vccd1), | 
 |             .VNB(vssd1), | 
 | `endif | 
 |             .HI(gpio_logic1), | 
 |             .LO() | 
 |     ); | 
 |  | 
 |     sky130_fd_sc_hd__einvp_8 gpio_in_buf ( | 
 | `ifdef USE_POWER_PINS | 
 |             .VPWR(vccd), | 
 |             .VGND(vssd), | 
 |             .VPB(vccd), | 
 |             .VNB(vssd), | 
 | `endif | 
 |             .Z(user_gpio_in), | 
 |             .A(~gpio_in_unbuf), | 
 |             .TE(gpio_logic1) | 
 |     ); | 
 |  | 
 | endmodule | 
 | `default_nettype wire |