Padframe Configuration File

In the getting started guide you got a first grasp on how to use Padrick and already saw a brief example of a configuration file that tells padrick what to generate. In this chapter, we will deep dive into the configuration file syntax. After you familiarized yourself with the basic Padrick config structure, have a look at the `exhaustive syntax reference <Syntax Reference_>`_.

Concepts and Terminology

The basic idea behind padricks configuration file structure is to separate the specification into three different parts:

  • A technology dependent section that defines the IO cells and its configuration signals

  • An IO peripheral dependent section that defines the peripheral signals present in this SoC

  • A chip specific mapping that glues the above two domains together

This separation of concerns allows to easily port an existing SoC to a new technology by only adapting the technology dependent configuration file section. Similarly, reusing same peripherals in a new SoC with different numbers of pads and multiplexing scheme but same target technology just requires a change of the mapping sections while the technology specific section and parts of the IO peripheral section can be reused.

To better understand the remaining parts of this chapter, lets first start with some terminology:

Pad:

RTL instance of an IO pad. Each Pad instance will typically have several pad signals to control the funcionality of the TX Buffer, driving strength and the actual pad -> SoC and SoC -> pad signals.

Port:

Throughout this document and in the scope of padrick, a Port denotes a set of signals from an SoC peripheral that can be routed to one of the available pads within the same Pad Domain. E.g. an I2C peripheral would expose the I2C_SCL and I2C_SDA port. The Port I2C_SDA for example could consist of the Port signals sda_tx, sda_rx and out_enable which all correspond (through some logic mapping) to the pad signals of a single IO pad.

Configuration File Syntax

The configuration file is written in YAML syntax. If you are unfamiliar with YAML or only sporadically used it so far, please take 2-3 minutes to read up on its most important featues since this will allow you to write cleaner configuration files. Especially the “anchor” and “reference” feature is quite usefull for this particular tool since it avoids copy-paste hell.

Note

The YAML engine in padrick supports inclusions of external files to

modularize your config file. You can e.g. have a common config file to define the peripherals in your system that you combine with your technology specific YAML file. The examples folder contains an example config file that showcases the feature.

At the root, the configuration file contains three key-value pairs:

  • name: The name of the pad_frame to generate (usefull if there is more than one and you want to avoid naming collision of the generated RTL)

  • manifest_version: The current configuration file syntax version used for this particular file (at the moment, this is always the value 1)

  • pad_domains: A yaml list of Pad Domains (see next subsection)

Pad Domains

A Pad Domain incorporates a collection of IO Pads, corresponding configuration registers and multiplexing logic. Pad Domains do not interact with each other and are generated in individual RTL modules for simplified Power Intent description (i.e. Power Gating of High-performance IO pads).

Pad Domains also define the scope of IO signal to IO pad routing. Every pad_domain contains its own crossbar that by default allows mapping of every Port to every Pad within the same pad domain. In combination with the possibility to define staticly controlled pads (pads that are controlled by one set of external signals only) this approach allows to map any existing PULP SoC padframe multiplexing scheme and much more advanced ones to the configuration file. While for many SoCs a single pad domain might be enough, multiple pad domains are most usefull for chips where IO pads are partially power gated. The clear separtion between pad domains makes it very easy to specify the power intent for such power gating schemes.

Each pad_domain in the configuration file contains 3 entries: - A list of pad_types (technology specific) - A list of pad_instances (technology agnostic but chip specific) - A list of Port Groups (technology and chip agnostic)

Declaration of IO Cells (Pad Types)

A Pad Type defines an available pad cell from your IO cell library that your are going to use in your design. One design might use several differ IO pad cells e.g. low-power ones and high-speed pads, pads with integrated pull-down or pads dedicated for differential signalling. Each pad_type is characterized by it’s name and optional description key and most importantly the template key:

pad_types: # This section contains a list of pads
- name: pull_down_pad # user defined name of the pad. Used to reference it
                      # in the pad_list
  description: TSCM65 pad with controllable integrated 1kOhm pull down resistor
  # The template value is a Mako template (https://www.makotemplates.org/)
  # that specifies how to instantiate this partuclar pad. The '|' in the
  # beginning is YAML syntax to allow multiline strings without the need
  # for manual character escaping
  template: |
    PDDW04808 ${instance_name} (
    .PAD(${conn["pad"]}),
    .IE(${conn["enable_rx"]}),
    .DS(${conn["driving_strength"]}),
    .I(${conn["chip2pad"]}),
    .O(${conn["pad2chip"]})
    );
  pad_signals:
    .... # See below for example
The Instantiation Template

The template is a multiline string that describes how this particular pad shall be instantiated within the autogenerated RTL in the form of a Mako template. While most of the string will probably be just a single SystemVerilog Module instantiation it also contains special markers that the Mako template library will replace with the appropriate content. The syntax of these template markers is quite simple if you are already familiar with Python. Check the quickstart guide on their webpage for more information https://www.makotemplates.org. For the sake of understanding the above examples it suffices to know that ${...} is special Mako syntax to mark a python expression. When rendering a Mako template, the template render function is supplied with some user variables which are then available in the scope of such expression markers. The template render function will evaluate the python expression and replace the marker with the expressions value during template.

During instantiation of the pads, padrick renders each template by supplying it with two python variables that can be referenced within the Mako markers:

instance_name:

A string containing the instance name that should be used for this particular instantiation of the Pad Type.

conn:

A dictionary containing the wiring signals corresponding to the declared Pad Signals for this Pad Type that should be connected to this IO Pad during instantiation. E.g. when rendering the instantiation of IO pad “pad_gpio3”, ${conn[enable_rx]} will be replaced with something like s_pad_gpio3_rx_en which is an autogenerated internal SystemVerilog wiring signal.

The conn variable is used to connect the wiring signals to your IO pad during instantiation. You can define arbitraring IO cell wiring signals in the pad_signals section of your pad_type configuration (see next section).

Pad Signals

Padrick must not only know how to instantiate your pads, it must also be aware of all pad config signals like tx buffer enable, driving strenths, i/o signal, landing pads etc. Padrick does not contain a list of hardcoded IO config signals but leaves full control to the user.

Each pad_type has a set of associated pad signals that are required to control the pad. For a typical IO pad, there are at least three signals:

  • The signal connecting to the pads TX-buffer (SoC -> pad signal)

  • The signal connecting to the pads RX-buffer (pad -> SoC signal)

  • The pad signal itself which connectes to the toplevel of the RTL and is wired to the bonding pads/bumps of the chip. In addition to these signals there are most often numerous additional signals that control additional features of the pad like driving strength, optional schmidt-triggers etc.

Here is a (well documented) example of a pad_signals section for a very rudimentary IO pad:

pad_signals: &default_pad_signals #This is a YAML anchor to reuse a subblock somewhere else. Use it to avoid copy paste hell!
# The pad signals section specifies a list of all pad signald used in
# this particular pad_domain. This include the rx signal, tx signal, the
# actual pad signal as well as all pad configuration signals. These are
# the signals that can be referenced by name in the pad instantiation
# templates within the pad_types sections, the connections of each pad
# within the pad_list as well as the connections section in the
# port_list.
  - name: output_en
    description: "Enables the output driver of the pad" #optional description
                                                 #of the signal
    size: 1 # The number of bits
    kind: input # The signal is an input signal to the pad i.e. a signal
                # driven by the chip that controls the pad.
    conn_type: dynamic # This means, the signal value is dynamic. It can
                       # either be controlled by an autogenerated
                       # configuration register or (at runtime
                       # configurable) an IO signal (if any IO signal
                       # within the pad_domain is referencing it).
    and_override_signal: s_enable_all_outputs # Optional override signal
                                              # that is and-gated with
                                              # the control signal
    default_reset_value: 0 # The default reset value of the pad signal
                           # if not overriden in the "connections"
                           # section of a particular pad instance
  - name: driving_strength
    description: "Driving strength of the output driver"
    size: 3
    kind: input
    conn_type: static # This means, the signal has a static value that
                      # is either driven by a single signal or a
                      # constant value. The difference between the
                      # dynamic type is, that this pad_signal is not
                      # arbitrary connectable with IO signals in a
                      # crossbar fashion but tied to one dedicated
                      # signal only. The actual signal or value assigned
                      # is defined individually for each pad in the
                      # padlist or described globally with the
                      # default_static_value.
    default_static_value: 0 # The default static value of the signal if
                            # not overriden in the "connections" section
                            # of a particular pad instance
  - name: enable_rx
    description: "Input buffer enable"
    size: 1
    kind: input
    conn_type: dynamic
    default_reset_value: 1
  - name: pad2chip
    description: "The signal that connects to the pads RX buffer"
    size: 1
    kind: output
    conn_type: dynamic # In case of static output pad_signals, literal
                       # value assignments are illegal since the signal
                       # is not drivable from the outside. Only the name
                       # for a dedicated padframe output signal can be
                       # specified.
  - name: chip2pad
    description: "The signal that connects to the pads TX driver"
    size: 1
    kind: input
    conn_type: dynamic
    default_reset_value: 1
  - name: pad # The name of the signal can be chosen arbitrarily but for
              # the actual pad signal (the signal that connects to the
              # bonding pads) the name "pad" is a good choice. It is
              # legal to specify more than one signal of type pad (e.g.
              # if you want to instantiate a special differential
              # signaling pads ). However, at least one siganl of kind
              # pad is required
    size: 1
    kind: pad # Pad signals are handled specially. They are always exposed
              # directly to the toplevel of the generated padframe module and no
              # connection type, override signals or default values are allowed.
Pad Signal kind

Padrick does not make any assumption about the particular features controlled by a pad signal and does not do a distinction between the actual I and O signal or configuration signals. Padrick knows only three kinds of padsignals:

input:

Signals that are inputs to the pad_instance cell e.g. chip->pad signal or driving_strength signal

output:

Signals that are outputs to the pad_instance cell. E.g. pad->chip signal or power_up_ack signal.

pad:

Signals that correspond to a bonding pad and should be routed to the toplevel of the RTL. While typically an IO pad contains only one Pad signal of this kind, padrick can perfectly handle pads with more than one landing pad signal (e.g. for differential signaling pads).

Connection Types

The connection type of a pad_signal determines, whether this particular signal is later-on to be controlled statically or dynamically.

Pad signals of type static do not have an input-multiplexer and thus cannot be controlled by the routable Port signals. Instead, they are either tied to a constant logic level (e.g. 1’b0 to tie it to zero) or a logic expression of external signals consisting of unary or binary operators and signal identifiers. This connection type is usefull for pad_signals you don’t need to control at runtime but should be hardwired to instance specific values or connected to external signals. E.g. a static pad signal could be controlled by a single external signal e.g. “~``global_power_down``” connected to RX_en and TX_en.

For each dynamic pad signal, a configuration register is auto-generated for every pad instance. This provides the user with control over the signal in the default case, where no Port is routed to this particular pad instance’s pad_signal. Thus, pad_signals of type dynamic can be controlled by all connectable (more on how to control connectivity in chapter Port Multiplexing) ports within the same pad_domain that referencec them. In other words; if you connect some port (e.g. I2C_SDA) to your pad instance, that port might take over control over the output_en and enable_rx pad signals. Other dynamic pad_signals like a schmitt_trigger_en are not controlled by the I2C peripheral. In such a case (and also if no port is connected to the pad instance at all) the pad signal is driven (for signals of kind: input) or accessible (for signals of kind: output) via the auto-generated config register file.

Dynamic pad_signals of kind input require you to specify a default_reset_value for the auto generated register. If not overriden during pad instantiation, the value you specify here will become the reset value of the corresponding configuration register. On the other hand, static pad_signals of kind input require you to specify a default_static_value; a static expression connected to the pad_signal if not overriden during pad instantiation.

Pad Instance List

The pad list contains a list of concrete pad instantiations. This is the place where you actually define, how many pads there are within your design. Each pad instance specifies a name for the pad, references the particular Pad Type to use (you might have multiple IO cell flavors to choose from) and a static signal connection list.

Here is an example:

pad_list:
  - name: pad_ref_clk # The instance name of the pad.
    description: "32kHz reference clock" #Optional description of the pads function
    pad_type: pull_down_pad
    is_static: true # Declaring a whole pad as static overrides every single
                    # pad signal's conn_type for that particular pad
                    # instance to "static".
    connections: # A list of static pad signal connections (for static
                 # signals) or default config register values (for dynamic
                 # pad signals)
      pad2chip: ref_clk
      chip2pad: ~ #Leave unconnected, only legal for pad signals of kind
                  #"input"
      enable_rx: 1 #pad signals of kind "input" any SystemVerilog literal is
               #valid.
      driving_strength: 0
  - name: pad_gpio
    description: "General Purpose Input and Outpud pads. These pads can be configured to connect to any peripheral pad port."
    multiple: 32 #Generate 32 instances of this pad. Each instance will have
                 #its instance name postfixed with the index
                 #number.
    pad_type: pull_down_pad
    is_static: false #False is the default value, thus explicitly specifying
                     #static as false is optional. With this option, each
                     #pad_signal assumes the declared conn_type.
  - name: pad_high_speed
    description: "High-speed IO pads for fast IO signals. "
    multiple: 10
    pad_type: high_speed_pad_gf22
    mux_group: hs_pads # An optional string that specifies a custom multiplexing
                       # group. All pads and ports within the same pad_domain
                       # and multiplexing group can be connected to each other.
                       # Default value: "all" By default all pads and ports
                       # end-up in the "all" multiplexing group and thus by
                       # default, every port can be connected to every pad
                       # within the same domain.

Hint

You will learn more about generating multiple pad/port instances in Generating Multiple Ports/Pads with Regular Structure.

Static Signal Connections and Config Register Reset Values

For each pad instance, the user can supply a connections list entry that overrides how static pad signals of this particular pad instance are to be connected or what the reset value of the corresponding configuration register shall be. The connections field contains a mapping of Pad Signal names to expressions. The pad signal name is just a reference to a static or dynamic pad_signal declared for the chosen pad type. The expression on the other hand must be a simplified subset of a SystemVerilog expression.

Expression may consist of simple SystemVerilog literals (e.g. 45, 8'h0a, '0 etc.), unary and binary operators and signal identifiers without subscripting (e.g. out_en_i is legal, out_en[45] is not legal).

For pad_signals of kind ~output~ only single signal identifiers or the empty expression are allowed. After all, an output signal cannot be connected to an expression.

For dynamic pad_signals only constant expressions are allowed since this value is used as the reset value when asynchronously resetting the auto-generated register file.

The pad instance will be wired with the supplied expression and the generated pad_frame SystemVerilog module will expose each static signal used within any of the expressions within the pad_domain in its port_list for the user to connect these signal with the appropriate SoC logic. E.g.:

...
  connections:
    pad2chip: scan_en_i
    chip2pad: ~ # '~' is YAML syntax for 'None'. In this context it means leave
                # the signal unconnected, only legal for pad signals of kind
                # "input"
    enable_rx: 1 #pad signals of kind "input" any SystemVerilog literal is
                 #valid.
    enable_tx: ~test_en_i & gpio1_en_rx
...

This will cause the pad_frame to expose the signals scan_en_i, test_en_i and gpio1_en_rx.

The direction and size of each of those static signals is inferred from the size and directionality defined for the particular pad_signal they are connecting to. If a static signal (signal identifiers on the right-hand-side of the connections list) is used in expressions for multiple pad_signals with different sizes an error is issued since size inference would be ambiguous.

Static signal identifiers with identical name within the same pad_domain denote the same signals. Thus if you have several pad instances whith connections entries like:

connections:
  enable_rx: input_buffers_en_i

They will all be connected to the same input signal input_buffers_en_i.

Ports and Port Groups

Port groups provide logical grouping of ports and peripheral signals which are muxed on you pad instances. Peripheral signals are the signals your IO facing peripheral exposes (e.g. i2c_sda_tx_en or uart_rx). Ports on the other hand are roles assigned to an IO pad when muxed to it. A port might make have to make use of multiple peripheral signals when it is connected to a pad. E.g. when connecting an I2C sda port to some particular pad, you need not only to connect the i2c_sda signal to the pad but also some i2c_sda_tx_en to control the pads directionality. The ports within a port group thus need to specify a logical mapping between peripheral signals and the pad signals defined in the pad_types section.

Hint

Static pads define their connected signals directly, see static signal connections and config register reset values

A concrete example should make things clearer. Here we define a port group for an I2C peripheral which consists of two ports (SDA and SCL):

port_groups:
  - name: i2c_0
    mux_groups: [all] # You will learn about mux_groups in the next section.
    output_defaults: 1'b0
    ports:
      - name: i2c_scl
        description: "Bidirectional I2C clock signal"
        connections:
          chip2pad: scl_out
          scl_in: pad2chip
          enable_tx: ~oen & i2c_en #You can use verilog expression combining multiple peripheral signals in your connections
          enable_rx: oen & i2c_en

      - name: i2c_sda
        description: "Bidirection I2C data signal"
        connections:
          chip2pad: sda_out
          sda_in: pad2chip
          pull_up_en: 1'b1 # You can also use literals if e.g. I2C pad requires pull-ups to beautomatically enabled if I2C_SDA is connected to a pad.
          enable_tx: ~oen & i2c_en #You can use verilog expression combining multiple peripheral signals in your connections
          enable_rx: oen & i2c_en

Each port_group must be defined with a name, some optional description and a list of ports (we will elaborate more on the mux_groups key in chapter Port Multiplexing). Each port again is defined with a name and optional description and a connections block. The connections block tells padrick how to connect the peripheral signals to the target pad when the user configures the port to be connected to a particular pad (muxing configuration registers). The individual connections can be read like assignments i.e. the signal on the left-hand-side is assigned the value of the expression on the right-hand-side. The identifiers used are either pad_signal names or implicitly defined peripheral signals.

Considering the example I2C port group above. Let’s assume connected (by writing to the auto-generated config register) the i2c_scl port to some pad mypad_08 whose pad instance uses the same pad_signals as defined in our earlier example. In that case the connection block instructs padrick to connect mypad_08’s chip2pad signal to the scl_out peripheral signal. The IO pads pad2chip drives the peripheral signal scl_in. The enable_tx pad_signal is driven with a logic expression that consists of the two peripheral signals oen (an active low output-enable) and i2c_en (some global peripheral enable signal). The right hand side of a port connection can also be a literal e.g. if certain pad configuration signals should be tied to constant values when the peripheral is connected to the pad (e.g. enable_tx: 1'b0 if a port is always an output as would be the case for uart_rx).

Important

Note that we didn’t explicitly define our peripheral signals anywhere. Merely specifying a signal name in the connections block of a port implicitly defines the peripheral signal and causes padrick to generate the necessary module ports and muxing logic in the generated pad multiplexer. The scope of the implicitly defined peripheral signals is the whole port group. Thus in our above example, the enable_rx signals used in the ports i2c_scl and i2c_sda reference the exact same signal. Therefore, peripheral signals may be shared amongst ports within the same port group.

From the example before it should have become clear, that your peripheral can control any pad signal you defined for your pad_type. If you’re peripheral needs to control driving strenghts, schmidt-triggers or whatever control signal your IO library exposes this is all possible. The more interesting question is however, what happens with the pad signals that you’re port does not use? E.g. we didn’t specify a connection for the driving_strenght signal. What driving strenght is used when our mypad_08 is used as i2c_scl port? The answer is pretty simple:

Important

Every (dynamic) pad_signal that is not mentioned in your port’s connection block will be controlled by an auto-generated pad configuration register whose reset value is specifed in the pad instance’s connection block (see static signal connections and config register reset values). E.g. since we did not specify any connection for the driving_strength signal, the driving strenght of mypad_08 will remain controlled by mypad_08’s pad configuration registers.

Generating Multiple Ports/Pads with Regular Structure

Generating pad instances or ports of a regular structure can become quite verbose if every instance is explicitly described in the YAML config file. Therefore, Padrick contains a feature for templated vectorization of pad instances, port_groups and ports. Each of these entities accepts the optional multiple key to instruct Padrick to generate multiple copies of the entity. During vector expansion, padrick looks for special text markers containing a mini expression language to generate the names, descriptions etc. of the vectorized entity. An example should make the explanation much easier:

pad_list:
  - name: gpio{i:2d}
    description: "GPIO No {i}"
    is_static: false
    pad_type: high_speed_pad_gf22
    multiple: 32

While parsing the config file, padrick will expand this vectorized pad_instance to 32 copies. Padrick will replace the name of each pad with gpio00, gpio01 until gpio31. The description is handled similarly.

Mini Expression language

During expansion of the vectorized entity, padrick scans name, description, mux_groups, connections etc. for occurence of mini expressions (e.g. {i:2d}).

Each mini expression has the following format:

{<expression>:<format>} or {<expression>} (if you want to use the default format d)

expression can be any expression consisting of:

  • the binary operators ‘+’, ‘-’, ‘*’ (multiply), ‘/’ (integer divide), ‘%’ (modulo)

  • the unary operators ‘+’, ‘-’

  • braces ‘()’ to indicate associativity

  • integer literals

  • the loop variable i (a variable that starts counting from 0 during vector expansion and increments by one for every instance copy).

E.g.

name: gpio{i/2}_{i%2+1}
multiple: 4

Will be expaned to gpio0_1, gpio0_2, gpio1_1 and gpio1_2.

The format specifier consists of [<lenght>]<format_class>.

Format Class d:

Format result of the expression in decimal representation. The optional length specifies the amount of zero padding.

Format Class o:

Same as d but format expression in octal representation.

Format Class b:

Same as d but format expression in binary representation.

Format Class x:

Same as d but format expression in hexa decimal representation.

Format Class c:

Format expression in Base26 and map the individual ‘digits’ to the lowercase letters of the latin alphabet. Supplying the optional length forces padding with the letter a. E.g. pad_{i:c} will be mapped to pad_a, pad_b, pad_c, …, pad_aa, pad_ab, pad_ac and so forth. E.g. pad_{i:2c} will be mapped to pad_aa, pad_ab, pad_ac etc.

Format Class C:

Same as c but use upper-case letters.

Here is another example:

name: pad_{i/4:C}{i%4:2d}

Expands to pad_a00, pad_a01, pad_a02, pad_a03, pad_b00, pad_b01 etc.

Hint

You can use the padrick command padrick config <your_padrame.yml> to parse the config file and print it in expanded form. This will resolve all cross links in your config file (e.g. references to pad_types) and will expand all vectorized port, pad_instance etc. This is quite helpfull to debug how padrick is treating your vectorized config files.

Port Multiplexing

By default, Padrick allows routing any Port to any (non-static) Pad Instance. However, the degree of routability can be adjusted very finely. Padrick uses so called mux groups to configure the connectivity between ports and pad instances. Every pad instance and every port is a member of one or several mux groups. Ports can be dynamically connected to all pad instances which are contained in any of the port’s mux groups. I.e. port_xy can be connected to pad_123 if pad_123 is part of one (or multiple) of port_xy’s mux groups. In more mathematical terms; Each pad_instance and each port specify a set of labels (mux_groups), whenever there is set-intersection between a pad_instance and a port, they can be connected with each other.

A mux group is denoted by a simple string identifier and declared with the mux_groups key in the config file. E.g. the following config snippet declares a pad called my_pad that is member of the mux_groups mux1, my_pads, and all:

pad_list:
  - name: my_pad
    mux_groups: # some examples use the more compact notation [mux1 my_pads self]. Both styles are valid YAML lists.
      - mux1
      - my_pads
      - all
    connections:
      ...

Similar to peripheral signals or static connection signals you don’t have to explicitly declare mux groups. The first usage of an identifier creates the new mux group. You can use any C-identifier-like string as the mux group name.

You probably noticed, that our previous config example snippets most of the time did not specify the mux_groups key. The key is optional and has the default value [all]. I.e. by default, all ports and all pads are member of a mux group called all. If you followed our explanation so far you should realize now, why by default, all ports can be connected to all pads with this default value.

Apart from ports and pad instances, mux_groups can also be applied to a complete port group. In that case the declared mux_group acts as a default for any port within the port group that doesn’t explicitly specify its own port group.

Lets have a look at small example with a couple of pads and a couple of ports:

pad_list:
  - name: pad1
    mux_groups: [mx1]
    ...
  - name: pad2
    mux_groups: [mx1, mx2]
    ...
  - name: pad3
    mux_groups: [mx2]

port_groups:
  - name: spi
    mux_groups: [mx1]
    ports:
      - name: sck
        mux_groups: [mx2]
        ...
      - name: mosi
        mux_groups: [mx1, mx2]
        ...
      - name: miso
        ... # No mux_groups specified for mosi thus the port_group's default (mx1) applies

In this small example, we used 2 different mux groups called mx1 and mx2. We have the following connectivity for the 3 ports:

  • Port sck can be connected to pad2 and pad3 since both are member of the mx2 group.

  • Port mosi can be connected to all three pads since all pads are member of either mx1 or mx2.

  • Port miso does not specify a mux group, thus the default value of the mux group applies (if the mux group doesn’t specify one, [all] is used). Therefore, miso can be routed to either pad1 or pad2.

Mux Group Templating

Combining this chapter with the knowledge from mini expression language we now have all the ingredients to define more complex IO multiplexing schemes. The key realization is, that mux_groups can be templated using the mini expression language like we templated the port/pad instance names and descriptions in the examples on generating multiple ports/pads with regular structure.

Lets consider the following example:

...
pad_list:
  - name: hs_pad{i}
    multiple: 4
    pad_type: highspeed_pad
    mux_groups: [hs_pads, hs_pad{i}]
    ...
  - name: ls_pad{i}
    multiple: 4
    pad_type: lowspeed_pad
    mux_groups: [ls_pads, ls_pad{i}]
    ...

port_groups:
  - name: hs_gpio
    ports:
      - name: gpio{i}
        multiple: 4
        mux_groups: [hs_pad{i}]
  - name: ls_gpio
    ports:
      - name: gpio{i}
        multiple: 4
        mux_groups: [ls_pad{i}]
  - name: i2c
    mux_groups: [ls_pads]
    ports:
      ...
  - name: hyerflash
    mux_groups: [hs_pads]
    ports:
      ...

In this example, we have instantiate 4 highspeed (hs) and 4 low speed (ls) pads. After vector expansion the pad hs_pad0, will be member of the mux_group hs_pads and hs_pad0, the pad hs_pad1 will be member of mux groups hs_pads and hs_pad1 and so forth.

On the port side, we declare a low-speed gpio port group, a high speed gpio port group, an i2c port group and a hyperflash port group.

Since the individual ports of a GPIO peripheral are usually all identical, it doesn’t make much sense to waste the routing resources to allow routing e.g. GPIO0 to pad4, you just use GPIO4 instead. To allow for such a routing scenario, each port in the hs_gpios port group is member of the corresponding pad’s mux group. E.g. port gpio0 of the hs_gpio port group is member of the hs_pad0 mux group, port gpio1 is member of hs_pad1 and so forth. This results in the intended scenario. Since the i2c port group specifies the default mux group ls_pads, every port within i2c can be routed to any of the 4 low-speed pads, while any port of the hyperflash peripheral can be routed to any of the high_speed pads.

Default Pad Roles

By default, after reset each pad_instance’s set of dynamic pad signals is fully controlled by the auto-generated configuration register file. I.e. in order to have your dynamic pads configured as inputs after power-on reset, you have to choose the right reset values in your pad_instance’s connections block. However, sometimes you want a pad multiplexing scheme with a default port to pad_instance assignment right after reset. For these cases, you can use the optional default_port key when declaring a pad_instance to assign it a default port. The port name is specified using dot-notation, i.e. <expanded_port_group_name>.<expanded_port_name>.

Here is an example:

- name: pad_05
  pad_type: pull_down_pad
  default_port: hs_gpio.gpio05

For multi pads, i.e. pads with a multiple field larger than 1, the situation is a bit more complex. Since Padrick v0.3.4, you can also supply a dictionary of evaluated mappings to specifiy individual default_ports for multi-pads. An example makes this much easier to understand:

- name: pad_io{i}
  pad_type: pull_down_pad
  multiple: 32
  default_port:
    '*': gpio.gpio{i}
    pad_io5: uart.tx
    pad_io6: uart.rx
    pad_io16: spi.sck
    pad_io17: spi.mosi
    pad_io18: spi.miso

This example snippet in the pad_list section defines 32 io pads with the expanded names pad_io0, pad_pio1, …, pad_io31. The second entry in the default_port matches with instance pad_io5 and assigns it the default port uart.tx. Like for most fields in padrick, the port specifier string can contain miniexpressions and will be expanded accordingly. The entries are applied in the order they are listed and can override each other. This behavior is leveraged by the first entry; it uses the wildcard padname '*' which matches with every expanded pad. Thus every pad_io<xy> instance will be assigned the default role gpio.gpio<xy>. However, since the other entries are listed afterwards, they override this default assignment.

Important

The order of the default_port mapping matters since the mappings can override each other. If you use the wildcard match entry '*', make sure it is the first entry in the list.

Config File Schema

The following table contains an auto-generated schema reference of the configuration file format.

Padframe Config

Padframe class that represents the padframe configuration parsed from the configuration file.

Attributes:

manifest_version (int): The manifest version used by the parsed configuration file. name (str): Name of the pad_frame module. description (str): An optional short description of the padframes. pad_domains (List[PadDomain): A list of PadDomains within this padframe.

type

object

properties

  • manifest_version

Manifest Version

type

integer

  • name

Name

type

string

pattern

^[_a-zA-Z](?:[_a-zA-Z0-9])*

  • description

Description

type

string

  • pad_domains

Pad Domains

type

array

items

#/definitions/PadDomain

minItems

1

  • user_attr

#/definitions/UserAttrs

definitions

  • PadSignalKind

PadSignalKind

An enumeration.

type

string

enum

input, output, pad

  • ConnectionType

ConnectionType

An enumeration.

type

string

enum

static, dynamic

  • UserAttrs

UserAttrs

type

object

additionalProperties

anyOf

#/definitions/UserAttrs

type

integer

type

boolean

type

string

  • PadSignal

PadSignal

type

object

properties

  • name

Name

type

string

  • size

Size

type

integer

maximum

32

minimum

1

default

1

  • description

Description

type

string

  • kind

#/definitions/PadSignalKind

  • conn_type

#/definitions/ConnectionType

  • and_override_signal

And Override Signal

type

string

default

  • or_override_signal

Or Override Signal

type

string

default

  • default_reset_value

Default Reset Value

type

integer

  • default_static_value

Default Static Value

type

string

  • user_attr

#/definitions/UserAttrs

additionalProperties

False

  • PadType

PadType

type

object

properties

  • name

Name

type

string

pattern

^[_a-zA-Z](?:[_a-zA-Z0-9])*

  • description

Description

type

string

  • template

Template

type

string

  • pad_signals

Pad Signals

type

array

default

[]

items

#/definitions/PadSignal

  • user_attr

#/definitions/UserAttrs

additionalProperties

False

  • Port

Port

type

object

properties

  • name

Name

type

string

  • description

Description

type

string

  • connections

Connections

type

object

additionalProperties

type

string

  • mux_groups

Mux Groups

type

array

default

[‘all’, ‘self’]

items

type

string

minItems

1

uniqueItems

True

  • multiple

Multiple

type

integer

minimum

1

default

1

  • user_attr

#/definitions/UserAttrs

additionalProperties

False

  • PortGroup

PortGroup

type

object

properties

  • name

Name

type

string

  • description

Description

type

string

  • mux_groups

Mux Groups

type

array

items

type

string

minItems

1

uniqueItems

True

  • ports

Ports

type

array

items

#/definitions/Port

  • output_defaults

Output Defaults

default

OrderedDict()

anyOf

type

string

type

object

additionalProperties

type

string

  • multiple

Multiple

type

integer

minimum

1

default

1

  • user_attr

#/definitions/UserAttrs

additionalProperties

False

  • PadInstance

PadInstance

type

object

properties

  • name

Name

type

string

  • description

Description

type

string

  • multiple

Multiple

type

integer

minimum

1

default

1

  • pad_type

Pad Type

anyOf

type

string

pattern

^[_a-zA-Z](?:[_a-zA-Z0-9])*

#/definitions/PadType

  • is_static

Is Static

type

boolean

default

False

  • mux_groups

Mux Groups

type

array

default

[‘all’, ‘self’]

items

type

string

minItems

1

uniqueItems

True

  • connections

Connections

type

object

additionalProperties

type

string

  • default_port

Default Port

anyOf

type

object

additionalProperties

type

string

type

string

type

array

items

#/definitions/PortGroup

#/definitions/Port

maxItems

2

minItems

2

  • user_attr

#/definitions/UserAttrs

additionalProperties

False

  • PadDomain

PadDomain

A pad_domain contains the configuration about one collection of pads and ports that can connected with each other.

type

object

properties

  • name

Name

type

string

pattern

^[_a-zA-Z](?:[_a-zA-Z0-9])*

  • description

Description

type

string

  • pad_types

Pad Types

type

array

items

#/definitions/PadType

minItems

1

  • pad_list

Pad List

type

array

items

#/definitions/PadInstance

minItems

1

  • port_groups

Port Groups

type

array

default

[]

items

#/definitions/PortGroup

  • user_attr

User Attr

type

object

additionalProperties

anyOf

type

string

type

integer

type

boolean