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-whenstatements work in tandem with the run-evals command. Therun-evalsfunction traverses the passed module and orchestrates the running of variouseval-whenblocks. This means foreval-whenstatements in your modules/components to run - you must callrun-evalsat some point after you have completed your design declarations. Theeval-whenstatements work in tandem with the run-evals command. Therun-evalsfunction traverses the passed module and orchestrates the running of variouseval-whenblocks. This means foreval-whenstatements in your modules/components to run - you must callrun-evalsat 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-whento run. - The
<STATEMENT-1>is a list of statements that are valid for the current context. This list of statements is typically called thebodyof theeval-whenstatement. This can be general stanza code or any validpcb-componentorpcb-modulestatements, 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
instandnetstatements - Adding concrete ports with the
portstatement. - Adding new abstract ports with the
requirestatement.
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.