module Origen::Pins

****** These notes refer to the pin model for the upcoming Origen V3 ******

Pin muxing and grouping on modern SoCs can be incredibly complex, Origen provides the following pin model architecture which should hopefully be sufficient to accurately model even the most complex of cases…

At the lowest layer are the pin objects, one per physical pin on a DUT. Each pin can store 1-bit of data with directional/state information for pattern generation, and additional metadata about the function of that pin in different modes of operation.

pin1                        pin2                        pin3                        pin4

Package

Packages are the first layer of filtering that can be applied to pins, each pin has a package hash which contains information about which packages it is available in and any additional metadata associated with the pin when in that package - for example what package pin location it is.

pin1                        pin2                        pin3                        pin4
  packages:                   packages:                   packages:                   packages:
    p1:                         p1:                         p1:
      location: "A5"              location: "B2"              location: "B3"
    p2:                                                     p2:
      location: "A5"                                          location: "B2"

Based on the above metadata these pins will work as follows within an SoC model:

$dut.package                     # => :none
$dut.pins.size                   # => 4

$dut.with_package :p1 do
  $dut.pins.size                 # => 3     (No pin4)
  $dut.pin(:pin1).location       # => "A5"
  $dut.has_pin?(:pin2)           # => true
  $dut.pin(:pin2).location       # => "B2"
  $dut.pin(:pin3).location       # => "B3"
end

$dut.with_package :p2 do
  $dut.pins.size                 # => 2     (No pin2 or pin4)
  $dut.pin(:pin1).location       # => "A5"
  $dut.has_pin?(:pin2)           # => false
  $dut.pin(:pin2).location       # => ERROR! The soc does not have pin 2 in the current configuration!
  $dut.pin(:pin3).location       # => "B2"
end

Aside from a physical package the packages attribute can also be used to model pseudo-packages like the subset of pins that are available in a probe or burn-in setup for example.

Pins availability can also be scoped by SoC mode and configuration…

Mode

The SoC mode attribute is inteded to be used to model top-level operating modes, such as functional test, RAMBIST, NVMBIST, etc. As such it is a top-level attribute similar to package attribute e.g. the SoC can be in RAMBIST mode within package P1, or it could be in User mode within package P2.

Configuration

The configuration scope should be used to model pin muxing that can occur independently of the SoC mode, for example in a functional test mode many different pin configurations may exist based on the IP modules that are enabled or disabled at runtime. Unlike the mode the configuration attribute can also be set at pin level as well. Any configuration attribute set on a pin will override the configuration attribute that is currently live on the SoC. This allows individual pins, or perhaps more commonly individual pin groups, to be set to a particular configuration independently of the other pins or the SoC.

The mode and configuration attributes at pin level are similar to those for the package, each pin also has a current_configuration attribute which will override the current_configuration attribute of the SoC when present. Each mode and configuration entry will be hash for storing meta data as required.

pin1                        pin2                        pin3                        pin4
  modes:                      modes:                      modes:                      modes:
    user:                       user:                       user:
    nvmbist:                    nvmbist:
  configurations:             configurations:             configurations:             configurations:
    default:                    default:                    default:                    default:
    alt0:                       alt1:                       alt0:
                                                            alt1:

Pin availability will be scoped accordingly when the mode and configuration of the SoC model is changed.

Although not shown in this example all of these filters are AND’d together, so a pin is only available if it is available in the current package, mode and configuration.

$dut.mode                        # => :none
$dut.configuration               # => :none

$dut.pins.size                   # => 4
$dut.mode = :user
$dut.pins.size                   # => 3   (No pin4)

$dut.configuration = :alt0
$dut.pins.size                   # => 2   (No pin2 or pin4)
# Set the configuration of pin2 directly, the all_pins method will bypass the current scope
# when looking up a pin
$dut.all_pins(:pin2).configuration = :alt1
$dut.pins.size                   # => 3   (pin2 is now available to)

While not shown here an additional value of :all can be set when specifying the mode/configuration attributes of a given pin and which means that it will be available in all modes and/or configurations.

Functions

Each pin can have multiple functions associated with it which is intended to reflect the current signal that is mux’d onto it. Functions are scoped by mode and configuration (not package) and only one function can exist per mode/configuration combo.

Again the reserved mode/configuration name :all can be used here to reflect a function that will be common to all modes/configurations unless a more specific function has been declared. The top-level key of the functions hash is the mode, then the configuration and then the meta data associated with that selection:

pin1                        pin2                        pin3                        pin4
  functions:                  functions:                  functions:                  functions:
    user:                       user:                       user:
      all:                        default:                    default:
        name: "TDI"                  name: "PORTA0"              name: "PORTA1"
        direction: :input            direction: :io              direction: :io
                                  alt1:                       alt0:
                                     name: "SPI0"                name: "IIC0"
                                     direction: :io              direction: :output
                                                              alt1:
                                                                 name: "SPI1"
                                                                 direction: :io
    nvmbist:                    nvmbist:
      all:                        all:
        name: "NVM_FAIL"            name: "NVM_DONE"
        direction: :output          direction: :output

The function attributes returned will automatically scope to the current SoC state:

$dut.mode = :user
$dut.pin(:pin1).name             # => "TDI"
$dut.pin(:pin1).direction        # => :input

$dut.mode = :nvmbist
$dut.pin(:pin1).name             # => "NVM_FAIL"
$dut.pin(:pin1).direction        # => :output

Aliases

Aliases are alternative names/handles to give to pins when using them to create patterns and other IP in Origen. Aliases can be made universal in which case they will work regardless of scope, or they can be scoped to the current package, mode and configuration.

The Origen pin API will automatically create scoped aliases for functions and package locations as they are declared, so for example:

$dut.mode = :user
$dut.pin(:pin1).name             # => "TDI"
$dut.pin(:tdi).name              # => "TDI"
$dut.has_pin?(:nvm_fail)         # => false
$dut.pin(:nvm_fail).name         # => ERROR! No pin called NVM_FAIL in the current scope!

$dut.mode = :nvmbist
$dut.pin(:pin1).name             # => "NVM_FAIL"
$dut.has_pin?(:nvm_fail)         # => true
$dut.pin(:nvm_fail).name         # => "NVM_FAIL"

*Pin Groups*

Pin groups will be similar to aliases in that they can be made universal or scoped to a specific package/mode/ configuration.

While aliases are simply pointers to pin objects pin groups will themselves be an Origen object which will be like a Ruby array with additional metadata attached (such as a name) and a dedicated API for working with the pins. Generally a pin and pingroup will respond to the same API so that calling code does not need to worry very much about dealing with a single pin vs. a collection.