| // SPDX-FileCopyrightText: 2020 Efabless Corporation |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| `default_nettype none |
| /* |
| *--------------------------------------------------------------------- |
| * 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 |
| ) ( |
| `ifdef USE_POWER_PINS |
| inout vccd, |
| inout vssd, |
| inout vccd1, |
| inout vssd1, |
| `endif |
| |
| // Power-on defaults |
| input [PAD_CTRL_BITS-1:0] gpio_defaults, |
| |
| // Management Soc-facing signals |
| input resetn, // Global reset, locally propagated |
| output resetn_out, |
| input serial_clock, // Global clock, locally propatated |
| output serial_clock_out, |
| input serial_load, // Register load strobe |
| output serial_load_out, |
| |
| 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, |
| |
| // to provide a way to automatically disable/enable output |
| // from the outside with needing a conb cell |
| output one, |
| output zero |
| ); |
| |
| /* 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 one; |
| wire zero; |
| |
| wire user_gpio_in; |
| wire gpio_in_unbuf; |
| wire gpio_logic1; |
| wire serial_data_pre; |
| |
| /* Serial shift for the above (latched) values */ |
| reg [PAD_CTRL_BITS-1:0] shift_register; |
| |
| /* Create internal reset and load signals from input reset and clock */ |
| assign serial_data_pre = shift_register[PAD_CTRL_BITS-1]; |
| |
| /* Propagate the clock and reset signals so that they aren't wired */ |
| /* all over the chip, but are just wired between the blocks. */ |
| assign serial_clock_out = serial_clock; |
| assign resetn_out = resetn; |
| assign serial_load_out = serial_load; |
| |
| /* Serial data should be buffered again to avoid hold violations */ |
| assign serial_data_out = serial_data_pre & one; |
| |
| always @(posedge serial_clock or negedge resetn) begin |
| if (resetn == 1'b0) 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 serial_load or negedge resetn) begin |
| if (resetn == 1'b0) begin |
| /* Initial state on reset depends on applied defaults */ |
| mgmt_ena <= gpio_defaults[MGMT_EN]; |
| gpio_holdover <= gpio_defaults[HLDH]; |
| gpio_slow_sel <= gpio_defaults[SLOW]; |
| gpio_vtrip_sel <= gpio_defaults[TRIP]; |
| gpio_ib_mode_sel <= gpio_defaults[MOD_SEL]; |
| gpio_inenb <= gpio_defaults[INP_DIS]; |
| gpio_outenb <= gpio_defaults[OEB]; |
| gpio_dm <= gpio_defaults[DM+2:DM]; |
| gpio_ana_en <= gpio_defaults[AN_EN]; |
| gpio_ana_sel <= gpio_defaults[AN_SEL]; |
| gpio_ana_pol <= gpio_defaults[AN_POL]; |
| 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 = pad_gpio_in; |
| assign mgmt_gpio_in = (gpio_inenb == 1'b0 && gpio_outenb == 1'b1) ? |
| pad_gpio_in : 1'bz; |
| 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 */ |
| |
| gpio_logic_high gpio_logic_high ( |
| `ifdef USE_POWER_PINS |
| .vccd1(vccd1), |
| .vssd1(vssd1), |
| `endif |
| .gpio_logic1(gpio_logic1) |
| ); |
| |
| 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) |
| ); |
| |
| sky130_fd_sc_hd__conb_1 const_source ( |
| `ifdef USE_POWER_PINS |
| .VPWR(vccd), |
| .VGND(vssd), |
| .VPB(vccd), |
| .VNB(vssd), |
| `endif |
| .HI(one), |
| .LO(zero) |
| ); |
| |
| endmodule |
| `default_nettype wire |