Require¶
require
statements can be used in coordination with supports statements to automate pin assignment. When we use a require
statement it creates an abstract port
. We can use this abstract port like any other port and JITX will handle mapping that abstract port to a concrete port on a component.
The require
statement is valid in the following contexts:
Signature¶
; Implicit `self` form
require <NAME>:<TYPE>
require <NAME>:<TYPE>[<ARRAY>]
; Explicit form
require <NAME>:<TYPE> from <INST>
require <NAME>:<TYPE>[<ARRAY>] from <INST>
<NAME>
- Name of the created abstract port in this context. This must be a unique symbol name in the current context.<TYPE>
- TheBundle
type for the requested abstract port.<ARRAY>
- Optional Array Initializer for constructing an array of abstract port.<INST>
- TheInstance
from which we are requesting abstract port.- In the
Implicit
form, this value isself
by default. - In the
Explicit
form, we must provide a ref to a specific module or component instance in the current context.
Usage¶
Basic Pin Assignment¶
pcb-bundle i2c:
port sda
port scl
pcb-module top-level:
inst mcu : stm32f405G7
require bus:i2c from mcu
inst sensor : temp-sensor
net (bus, sensor.i2c-bus)
inst R : chip-resistor(4.7e3)[2]
net (bus.sda, R[0].p[1])
net (bus.scl, R[1].p[1])
This is a typical use case for pin assignment in a microcontroller circuit. Here we are requesting one of the 3 available I2C ports on the SM32F405 and constructing an abstract port that will map to one of them depending on what other require
statements exists as well as the board conditions.
The bus
abstract port can be used like any other port on a component or module. We can use the net
statement to connect it to other ports. We can use dot
notation to connect to individual pins of the abstract port.
Abstract Port Array¶
pcb-bundle gpio:
port p
pcb-module top-level:
inst mcu : stm32f405G7
val num-sw = 4
require sw-inputs:gpio[ num-sw ] from mcu
inst switches : momentary-switch[ num-sw ]
for i in 0 to num-sw do:
net (sw-inputs[i].p, switches[i].p[1])
Like other inst
or net
declarations, we can construct an array of abstract ports withe []
syntax. Here we construct 4 GPIO abstract ports requested from the mcu
instance.
We can then connect these individual gpio pins to other instance ports, like the momentary-switch
instances.
Use of require
inside supports
¶
We often want to cascade the construction of abstract ports by using require
statements inside supports
statements.
pcb-component stm32:
port PA : pin[32]
...
pcb-bundle I2C0_SDA:
port p
supports I2C0_SDA:
option:
I2C0_SDA.p => self.PA[1]
option:
I2C0_SDA.p => self.PA[7]
pcb-bundle I2C0_SCL:
port p
supports I2C0_SCL:
option:
I2C0_SCL.p => self.PA[2]
option:
I2C0_SCL.p => self.PA[6]
supports i2c:
require sda0:I2C0_SDA
require scl0:I2C0_SCL
i2c.sda => sda0
i2c.sda => scl0
pcb-module top-level:
inst mcu : stm32
require bus:i2c from mcu
In this example, we define ad-hoc pcb-bundle
definitions I2C0_SDA
and I2C0_SCL
that are only accessible within this component's context. The supports
statements for these two bundle types effectively make private pending ports
that can only be used within this context.
Finally - we make a supports i2c:
statement that constructs an externally accessible pending port for the i2c
bundle type. The bus
abstract port that we are ultimately able to connect to the rest of our system consists of:
bus.sda
=>mcu.PA[1]
ORmcu.PA[7]
bus.scl
=>mcu.PA[2]
ORmcu.PA[6]
Notice that in the supports i2c:
statement, the require
statement uses the Implicit
form (ie, the lack of a from <INST>
part of the statement). This means that this require
statement is targeting self. This statement is exactly the same as:
require sda0:I2C0_SDA from self
Check out restrict
¶
There is also the restrict statement which provide another method of defining the constraints for the pin assignment problem. The restrict
statement operates on the abstract port
instances defined by the require
statement.