The eval-when
Statement¶
When constructing a component or module, there are often times checks we want to write that are dependent on the application. We need to know more about the other circuits we are connected to before we can write the check. To delay the evaluation of these checks until we have the information we need - we use the eval-when
statement.
The eval-when
statement is valid in the following contexts:
The
eval-when
statements work in tandem with the run-evals command. Therun-evals
function traverses the passed module and orchestrates the running of variouseval-when
blocks. This means foreval-when
statements in your modules/components to run - you must callrun-evals
at some point after you have completed your design declarations. Theeval-when
statements work in tandem with the run-evals command. Therun-evals
function traverses the passed module and orchestrates the running of variouseval-when
blocks. This means foreval-when
statements in your modules/components to run - you must callrun-evals
at some point after you have completed your design declarations.
Signature¶
eval-when <CONDITION> :
<STATEMENT-1>
...
- The
<CONDITION>
is a predicate (ie, something that evaluates toTrue|False
). This condition indicates what data needs to be present in order for thiseval-when
to run. - The
<STATEMENT-1>
is a list of statements that are valid for the current context. This list of statements is typically called thebody
of theeval-when
statement. This can be general stanza code or any validpcb-component
orpcb-module
statements, depending on their respective contexts.
Usage¶
The eval-when
statement is a powerful method of customizing modules for the context in which those modules are instantiated. This method allows us to keep the logic that applies to a particular module or component co-located with the definition of that module or component.
pcb-component LDO :
pin-properties:
[pin:Ref | pads:Int ... ]
[VIN | 1 ]
[GND | 2 ]
[VOUT | 3 ]
...
property(self.VOUT.voltage) = 3.3
property(self.MAX_VIN) = 12.0
property(self.MAX_DROP_OUT) = 0.2
eval-when has-property?(self.VIN.voltage) :
val max-rating = property(self.MAX_VIN)
if self.VIN.voltage > max-rating:
fatal(
"Invalid Input Voltage - %_ exceeds max rating of %_" %
[self.VIN.voltage, max-rating]
)
val min-rating = property(self.VOUT.voltage) + property(self.MAX_DROP_OUT)
if self.VIN.voltage < min-rating :
fatal(
"Invalid Input Voltage - %_ is less than min rating of %_" %
[self.VIN.voltage, min-rating]
)
In this case, we're defining a simple, fixed-voltage LDO regulator. We want to check that the voltage applied to the VIN
port is within the expected and allowed range for this component.
For these checks to work - we need to know what voltage is being applied to the VIN
port and we don't necessarily know that when the component is instantiated. The eval-when
is waiting for the application of a voltage
property on the VIN
port. Some other entity is going to apply this at the application layer.
Once the voltage
property exists on VIN
, the statements in the body will execute. In this case we do some minimal checks on the accepted voltage range of VIN
.
With Great Power - Comes Great Responsibility¶
You might notice that this adds some conditional logic to what would otherwise be a purely declarative component or module. This is a concept that doesn't really exist in other legacy CAD tools - ie, you don't typically have to worry about the components mutating.
The safest operations to use inside an eval-when
clause are operations that don't modify the physical nature of the PCB:
- Checks - These are typically non-mutating and only read properties or structures.
- BOM Variations - Changing the BOM or any variants is usually OK.
- Adding
no-connect()
statements - Adding
property()
statements
Operations that are more difficult to use consistently in an eval-when
body include:
- Adding
inst
andnet
statements - Adding concrete ports with the
port
statement. - Adding new abstract ports with the
require
statement.
There are certainly cases where you might want to use these statements in an eval-when
body. These statements are supported and will execute as part of the design run. We suggest proceeding with care and purpose when using these statements.