pcb-routing-structure

The pcb-routing-structure is a statement for defining the geometric constraints of a single-ended topology. This may include:

  1. Singled-ended transmission lines, like microstrip and striplines.
  2. Uncoupled regions for differential pair transmission lines.
  3. Fanout regions for BGAs or other dense components.

Outline

pcb-routing-structure struct-name (arg1:Type1, ...) :
  name = <String>
  description = <String>

  layer-constraints(<LayerIndex|Side>):
    trace-width = <Double>    ; mm
    clearance = <Double>      ; mm
    velocity =  <Double>      ; mm/s
    insertion-loss = <Double> ; dB/mm
    ; Option #1 - NeckDown Instance
    neck-down = <NeckDown>

    ; Option #2 - NeckDown Macro
    ;  Notice the `:` instead of `=`
    neck-down :
      trace-width = <Double>
      clearance = <Double>      ; mm
      velocity =  <Double>      ; mm/s
      insertion-loss = <Double> ; dB/mm

  layer-constraints(<LayerIndex|Side>):
    ...

The routing structure requires an expression name struct-name that uniquely identifies this statement within the current context.

The arguments list (arg1:Type1, ...) is optional and provides a means to parameterize routing structures for common statements.

The name and description properties are optional and are primarily for documentation and labeling purposes. The name property in particular is typically for UI applications. If a name property is not provided, then the expression name struct-name will be used.

The elements of the pcb-routing-structure statement are identified using a layer-constraints statement. Each of these layer statements must match with a conductor layer in the pcb-stackup defined for the current board design. Conceptually, the idea is to apply different properties depending on the layer.

The layer-constraits() statement takes an argument of either a Side like Top or Bottom, or a LayerIndex. See LayerIndex for more information.

At each layer specification, the user can list any of these properties:

  1. Required Properties:
    1. trace-width - Width in mm of the traces on this layer.
    2. velocity - Signal Propagation Velocity (also known as Group Velocity) of the signals on this layer. This is primarily used for timing constraints. This property is in units mm/s.
    3. insertion-loss - Insertion Loss per unit distance of the signals on this layer.
      1. This property is in units of dB/mm
      2. This property is assumed to be at the frequency of interest for this design.
  2. Optional Properties
    1. clearance - Minimum "Net to Net" clearance in mm of the traces on this layer. If not provided, then the default minimum clearances from the design rules will be used.
    2. neck-down - This property allows the user to specify a special set of routing properties for the neckdown region. It comes in two forms:
      1. Instance Form - the user must assign a NeckDown instance.
      2. Macro Form - the user can provide, directly, statements for trace-width, clearance, etc like above.

If these properties are not explicitly provided in the routing structure, then either:

  1. The default design rules for the board will be consulted for trace-width and clearance
  2. If there are timing or loss constraints on this route, but no defined structure information for layers that have traces, then default values will be used for velocity and insertion-loss. The current default values are:
    1. velocity = 0.15e12 ; mm/s
    2. insertion-loss = 0.002 ; dB/mm

Usage

Here are a list of common examples:

Microstrip Example


val eps-r = 4.6
val vel = phase-velocity(eps-r)
val target-imped = 50.0 
val thickness = 0.035 ; mm
val height = 0.1; mm

; Compute an estimate of the trace width
;  for a 50 ohm impedance.
val w = ipc2141-microstrip-width(
  target-imped, eps-r, thickness, height 
)

public pcb-routing-structure se-50 :
  name = "50 Ohm Microstrip"

  layer-constraints(Top) :
    trace-width = w
    clearance = w * 3.0
    velocity = vel
    insertion-loss = 0.008

  layer-constraints(Bottom) :
    trace-width = w
    clearance = w * 3.0
    velocity = vel
    insertion-loss = 0.008

In this example, we construct a microstrip transmission line for the Top and Bottom layers.

Caution!

This routing structures does not provide parameters for any of the internal layers. If any of the routes that have this routing structure assigned to them transition to an internal layer, then the runtime will consult the default design rules for the trace width constraint.

Using NeckDown


; Define a single-ending routing structure for the
;  uncoupled regions
public pcb-routing-structure se-100 ( -- clearance-mult:Double = 3.0 ) :
  name = "100 Ohm Microstrip"
  val w-100 = 0.1048
  layer-constraints(Top) :
    trace-width = w-100
    clearance = w-100 * clearance-mult
    velocity = 0.19e12
    insertion-loss = 0.008
    neck-down = NeckDown(
      clearance = 0.5 * clearance-mult * w-100
    )
  ...

; Application
structure(A => B) = se-100( clearance-mult = 2.5 )

Here the neck-down property is used to change the clearance properties of neckdown traces on the Top layer.

Reusing Layer-Constraints Definitions

Sometimes, we would like to construct repeated layer-constraints definitions in the internal layers of a board, without resorting to copy/pasting code. We have two methods for doing this.

Using RoutingStructureLayerConstraints

val my-layer-constraints = RoutingStructureLayerConstraints(
  trace-width = 0.27
  clearance = 0.37
  velocity = 0.17e12
  insertion-loss = 0.0087
  neck-down = NeckDown(
    trace-width = 0.1567
    clearance = 0.17
    velocity = 0.17e12
    insertion-loss = 0.0087
  )
)

pcb-routing-structure my-routing-structure :
  name = "50 Ohm Single Ended"
  layer-constraints(Top) = my-layer-constraints
  layer-constraints(Bottom) = my-layer-constraints

Notice the syntax: after layer-constraints(Top) we use an equals sign rather than colon. This indicates the use of a pre-defined RoutingStructureLayerConstraints object. In place of my-layer-constraints after the equals sign, we could alternately use a function call or any Stanza expression that returns an object of this type.

Note that the definition of my-layer-constraints here is pure Stanza code, with no special macros. So when specifying neck-down we have to use the ordinary constructor for NeckDown (Option #1 above), not the NeckDown macro.

Using Generator Functions

We use the inside pcb-routing-structure macro to define a generator that can be called inside the pcb-routing-structure definition.

; Generator for constructing a stripline at 75 ohm
;  on a target internal layer.
defn gen-internal-stripline (l:LayerIndex) :
  val w = 0.12
  inside pcb-routing-structure:
    layer-constraints(l):
      trace-width = w
      clearance = 3.0 * w
      velocity = 0.19e12 ; mm / s
      insertion-loss = 0.008 ; dB / mm


pcb-routing-structure se-75:
  name = "75 ohm Single-Ended"

  val ms-w = 0.095
  layer-constraints(Top):
    trace-width = ms-w
    clearance = 3.0 * ms-w
    velocity = 0.19e12
    insertion-loss = 0.008

  for sig-layer in [2, 5, 7] do:
    gen-internal-stripline(LayerIndex(sig-layer))

  layer-constraints(Bottom):
    trace-width = ms-w
    clearance = 3.0 * ms-w
    velocity = 0.19e12
    insertion-loss = 0.008

In this example, we use a generator function to construct the layer-constraints() statement for the internal layers. We then use a for-loop to construct that same structure multiple times.

The resulting pcb-routing-structure object has the following layer statements:

  1. layer-constraints(Top) with trace-width = 0.095
  2. layer-constraints(LayerIndex(2)) with trace-width = 0.12
  3. layer-constraints(LayerIndex(5)) with trace-width = 0.12
  4. layer-constraints(LayerIndex(7)) with trace-width = 0.12
  5. layer-constraints(Bottom) with trace-width = 0.095