Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • The NanoSoC Tour
  • Reading Path
  • SoC Glossary10
  • SoC Metrics Reference
  • SoC Cheatsheet
  • What SoC Integration Is12
  • Architecture and Budgets21
  • Memory Maps and Address Decode26
  • Interconnect and Bus Fabrics26
  • Clock and Reset Architecture24
  • Power Architecture21
  • Interrupts, DMA and Peripherals15
  • Memories, Boot and Security21
  • IP Integration and Handoff21
  • Top-Level Verification and Bring-up21
  • Package, Pads and I/O18
    • I/O Ring and Pad Types
      • Pad Types: Digital, Analog and Supply
      • The I/O Ring
      • Pad Function, Drive and Reset State
    • Pad Count and Simultaneous Switching
    • Package and Ballout
    • Power Delivery Through Package and Bumps
    • ESD and Latch-Up at the Top
    • Test and Debug Pins (extension)
  • Chip Signoff and Tapeout18
  • SoC Interview Prep16
  • Capstone: Integrate NanoSoC14
Loading lesson

←I/O Ring and Pad Types
  1. Topics
  2. SoC Design
  3. Package, Pads and I/O
  4. I/O Ring and Pad Types
  5. Pad Function, Drive and Reset State
On this page

    Part 11 of 14, lesson 3 of 18Part 11 of 14/Package, Pads and I/O/Lesson 3 of 18All levels

    Pad Function, Drive and Reset State

    Function, pull and drive per pin, the reset-state table, and a pad cell with its own power-on control.

    Why it matters

    At power-on, before the ROM executes its first fetch, every pin is already doing something: driving, floating or held by a pull. If the SPI chip-select floats low, the flash is selected from power-up and sees the first clock edges in the middle of a command; the boot ROM's image load then fails its checksum, in a chip that simulates perfectly because RTL simulation has no pad model. The reset state of every pin is therefore a deliverable, written before tapeout and checked by a script, and this lesson builds it for NanoSoC.

    The core idea

    Each digital pad has a function, a pull, a drive and a receiver. NanoSoC has no pad-control register: the function of a shared pad follows the peripheral's own enable bit. If the UART's EN is 1, P0 and P1 belong to the UART; otherwise they are GPIO, with direction from the GPIO direction register. The pulls are fixed in the pad cell, not programmable, so they must be right for the state before firmware has run. The rule that makes the table easy to review is this: for every shared pad, the reset pull equals the idle level of the function the pad takes when enabled. UART TX idles high, so P0 has a pull-up. SPI chip-select is active low and inactive at 1, so P5 has a pull-up. SPI clock idles low in mode 0, so P2 has a pull-down, as do MOSI and MISO. All ten plain GPIO pads, P6 to P15, are inputs at reset with a pull-down, so nothing drives and no interrupt fires.

    The drive is the default for every output: an illustrative 4 mA with medium slew. A stronger, fast drive is possible but halves the number of outputs a supply pair can tolerate switching together (the next topic), so the rule is default drive everywhere and a fast drive only with a measured timing reason. RESET_N is an input with a Schmitt trigger and a weak pull-up: an open pin means run, a slow board reset edge does not double-trigger, and the 16-cycle debounce in the reset controller then filters the rest.

    Pad

    Direction at reset

    Pull (illustrative 50 kohm)

    Open pin reads

    Why

    P0 (uart_tx)

    Input, driver off

    Pull-up

    1

    TX idles high; the far end must not see a break while the UART is disabled.

    P1 (uart_rx)

    Input

    Pull-up

    1

    RX idles high; a pull-down would read as a continuous break.

    P2 (spi_sck)

    Input, driver off

    Pull-down

    0

    Mode 0 clock idles low.

    P3 (spi_mosi)

    Input, driver off

    Pull-down

    0

    Quiet default.

    P4 (spi_miso)

    Input

    Pull-down

    0

    A missing flash reads 0, never a floating level.

    P5 (spi_cs_n)

    Input, driver off

    Pull-up

    1

    Active low: floating or low would select the flash.

    P6 to P15

    Input (direction register 0)

    Pull-down

    0

    Quiet default, no interrupt enabled.

    RESET_N

    Input, Schmitt trigger

    Pull-up

    1 (not in reset)

    An open pin means run; the power-on reset still resets at power-up.

    XTAL_IN, XTAL_OUT

    Analog

    None

    n/a

    The oscillator runs whenever its supply is on.

    The table holds from the moment the power-on reset releases. Before that, while rails are still ramping and perhaps only the I/O supply is up, the core-side output enable is undefined, so the pad cell itself must keep its driver off. Library pad cells provide a power-on-control input for exactly this (its name varies by library), tied to a signal that says the core supply is valid. It is the mechanism that makes "nothing drives at reset" true, and the audit needs one row for it: every digital pad's power-on-control is connected, or the library states a safe default.

    The pad slice

    The module below is the teaching version of what sits behind one bidirectional GPIO pad: a function select, a registered output enable, and the power-on-control gate. The output enable is registered so that a control write does not decode combinationally onto the pin. The function select is not registered, so firmware must change it with the output disabled: clear the enable, change the select, then set the enable again.

    nano_pad_slice.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    // NanoSoC teaching values: one bidirectional pad slice.
    // pad_oe is held off by the pad's power-on control until the core is valid.
    module nano_pad_slice (
      input  logic clk,
      input  logic rst_n,
      input  logic core_pgood, // power-on control: core supply valid
      input  logic func_sel,   // 0 = gpio path, 1 = peripheral path
      input  logic gpio_out,
      input  logic alt_out,
      input  logic oe_req,     // requested output enable
      input  logic pad_in_raw, // from the pad receiver
      output logic pad_out,    // to the pad driver
      output logic pad_oe,     // to the pad driver
      output logic gpio_in,
      output logic alt_in
    );
      logic oe_q;
    
      always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) oe_q <= 1'b0; // reset: input, never driving
        else        oe_q <= oe_req;
      end
    
      assign pad_out = func_sel ? alt_out : gpio_out;
      assign pad_oe  = oe_q & core_pgood;
      assign gpio_in = pad_in_raw;
      assign alt_in  = pad_in_raw;
    endmodule

    The reset-state checker

    The script below holds the table as data, one row per pad (31 pads), and applies three rules through one function: no pad drives at reset; every shared pad's pull equals its idle level; RESET_N is an input with a pull-up and a Schmitt trigger. A fourth rule, the power-on-control audit, requires every digital pad to be listed as connected. The function is then run on three broken tables, each reproducing a real failure, and must reject all of them: a pull-down on the SPI chip-select, a pad that drives at reset, and a RESET_N without its pull-up.

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    IDLE = {"P0": 1, "P1": 1, "P2": 0, "P3": 0, "P4": 0, "P5": 1}   # idle level of the shared function
    ROWS = {}
    for i in range(16):
        ROWS["P%d" % i] = ("input", "up" if IDLE.get("P%d" % i, 0) else "down", False)
    ROWS["RESET_N"] = ("input", "up", True)       # direction, pull, Schmitt trigger
    PON = set(ROWS)                                # pads whose power-on control is connected
    
    def check(rows, pon):
        assert len(rows) == 17, len(rows)
        for pad, (direction, pull, schmitt) in rows.items():
            assert direction != "output", pad + " drives at reset"
            assert pull in ("up", "down"), pad + " floats"
            if pad in IDLE:
                assert pull == ("up" if IDLE[pad] else "down"), pad + ": pull differs from idle level"
        assert rows["RESET_N"] == ("input", "up", True), "RESET_N needs a pull-up and a Schmitt trigger"
        assert pon == set(rows), "a pad has no power-on control: " + str(set(rows) - pon)
    
    check(ROWS, PON)
    bad_cs = dict(ROWS); bad_cs["P5"] = ("input", "down", False)
    bad_drive = dict(ROWS); bad_drive["P7"] = ("output", "down", False)
    bad_rst = dict(ROWS); bad_rst["RESET_N"] = ("input", "down", True)
    for rows, pon in ((bad_cs, PON), (bad_drive, PON), (bad_rst, PON), (ROWS, PON - {"P3"})):
        try:
            check(rows, pon)
            raise SystemExit("a bad reset-state table was accepted")
        except AssertionError:
            pass
    print("PASS: 17 digital pads checked; pull-down CS_N, driving pad, open RESET_N and missing power-on control all rejected")

    What the review looks for

    • The reset-state table, signed, with one row per pad and no pending entries.

    • Every pad shown as an input or driver-off at reset, with the RTL reset value of its output enable quoted.

    • Each reset pull compared with the idle level of the function the pad takes, row by row.

    • The power-on-control connection of every digital pad, or the library's stated safe default.

    • Drive choices justified per pin against a timing or noise budget, not copied from a previous chip.

    Verify and debug

    Check the table against the RTL reset values: the output-enable reset of every pad slice must be zero, as in the module above, and the check is a lint over reset assignments, not a visual skim. On the bench, a contention suspect is confirmed by measuring the pin voltage at power-on: a healthy undriven pin sits at its pull level, a fighting pin sits somewhere between the rails and runs warm. The SPI chip-select deserves its own scope trace during boot, because a wrong pull there looks like a flash or software problem.

    A reset pull copied from the neighbouring row. Giving the SPI chip-select the same pull-down as the other GPIO pads selects the flash from power-up; the boot ROM's image load then fails its checksum, though every simulation passes. It is caught by the rule that the reset pull equals the idle level of the function, and fixed by a pull-up on P5 (and on P0 and P1).

    If asked what a pin does at reset, answer from a table you would write, not from memory of one chip: direction, pull, drive, and which RTL reset value or pad power-on control guarantees it.

    Check yourself Why does the SPI chip-select pad get a pull-up while the SPI clock pad gets a pull-down?

    Because each pull must equal the idle level of the function the pad takes. Chip-select is active low and inactive at 1, so a pull-up keeps the flash deselected; the mode 0 clock idles low, so a pull-down keeps the clock quiet. The same fixed rule gives the UART TX pad a pull-up.

    Related topics

    • The I/O Ring

    • Test and Debug Pins (extension)

    • Physical Design: IO Ring Checks

    Previous

    213 / 289

    Next: Bring-Up Readiness

    Up next

    Up nextBring-Up Readiness

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Pad Types: Digital, Analog and Supply