Check Statements¶
Checks allow us to automatically verify our designs. We can write arbitrary code to scan through our designs, inspect the data and make sure the circuit will work as intended. JITX will generate a well-formatted report on the results of all checks; prompting users to enter more data or pointing out errors in the design.
We can define checks specific to a circuit or component. With checks, circuit generators can check themselves for correct usage, thus ensuring safe reusability.
Signature¶
pcb-check check-name (arg1:Type, ...) :
; One assertion (or sub-check)
#CHECK(
; Required field: a boolean expression
condition = <Exp>
; Optional metadata
name = <Printable>
description = <Printable>
category = <Printable>
subcheck-description = <Printable>
pass-message = <Printable>
fail-message = <Printable>
info-message = <Printable>
locators = <Tuple<JITXDef|JITXObject>>
)
; More #CHECK assertions as needed
pcb-module main-module :
; Apply a named check to a module or component
check <String>(<Exp>, ...)
...
; Run all checks in the current design
; JITX writes a report on all check results to the given filename
run-checks(<Filename>)
There are three key components to writing and using a check.
First, we define the check in the pcb-check
code block.
The check itself can take arguments; usually we will parameterize the check
by a JITX object that we want to verify.
A pcb-check
can contain any number of assertions generated
by the #CHECK
syntax.
The only required field in an assertion is its condition
: this
can be an arbitrary expression, but must return a boolean.
The remaining fields are metadata for the check.
When JITX runs checks, it will produce a report on the result of
all of the checks, which will contain information from the checks'
metadata.
Most of the fields are Printable
expressions used to describe the checks' purpose and status.
The one exception is the locators
field: a set of JITX objects or definitions,
allowing the final report to link back the code that passed or failed a check.
Second, we use the check
statement to apply the validation logic defined above
to a pcb-module
or pcb-component
.
Third, we use the command run-checks
to actually run all of the checks on
our design and write out the resulting report to a specified file.
Watch Out! - We cannot define both
info-message
andfail-message
. Ifinfo-message
is defined, an assertion failure will register as "incomplete"; otherwise it will register as a check failure
Usage¶
Below is an example check for AEC ratings and its usage.
; We will check that a given component has an AEC Q200 rating
; by verifying that it has a property called "aec-rating".
; `component` is the argument to our check
pcb-check aec-q200 (component:JITXObject):
; One assertion
#CHECK(
; Check name
name = "Automotive rating"
; Check description
description = "Check that a passive component is AEC Q200 rated"
; The check itself: does the component have a property named `aec-rating`?
condition = has-property?(component.aec-rating),
; Check category
category = "Component Data"
; Description of this particular assertion
subcheck-description = "Check that %_ has a defined aec-rating" % [ref(component)],
; Message when the check passes
pass-message = "%_ has a property for aec-rating of %_" % [ref(component) property(component.aec-rating)],
; Message when the check does not pass
info-message = "%_ does not have an aec-rating property attached" % [ref(component)],
; Metadata for associating the component's definition with the check.
locators = [instance-definition(component)]
)
; Another assertion
; This one checks that a component's `aec-rating` property is the
; string "Q200".
#CHECK(
name = "Automotive rating"
description = "Check that a passive component is AEC Q200 rated"
condition = property(component.aec-rating) == "Q200",
category = "Component Checks"
subcheck-description = "Check that %_ is AEC Q200 rated." % [ref(component)],
pass-message = "%_ is AEC Q200 rated" % [ref(component)],
; This assertion uses a `fail-message` instead of `info-message`.
; If the predicate fails the check will fail.
fail-message = "%_ is not AEC Q200 rated. Instead has rating %_." % [ref(component) property(component.aec-rating)],
locators = [instance-definition(component)]
)
; Use a check
pcb-module checked-design :
inst r : create-resistor(1.0)
check aec-q200(r)
; Run checks and log output.
set-main-module(checked-design)
run-checks("check-output.txt")
We want to check that our components are AEC Q200 rated.
In the context of JITX code, there are two ways we might verify that.
The first sub-check (the #CHECK
statement) looks to see if the
component has a property named aec-rating
.
If it does not, the check will be "incomplete", since we provided
an info-message
parameter.
The second sub-check looks at the property's value.
If property(component.aec-rating)
is not "Q200", the
check fails.
Besides the actual predicate, the most important part of each
sub-check is its failure condition.
A check is usually a sequence of sub-checks, where all but the last
one will have an info-message field.
If any of those fail, the check will be "incomplete".
Finally, if the last predicate (with its associated
fail-message)
fails, the entire check will fail.
If a programmer does not set either
info-messageor
fail-messagethe assertion defaults to a
fail-message` of "Failure".
The rest of the metadata is simply for producing an informative report.
After defining the pcb-check
we can apply it to
a specific component with the check aec-q200(some-component)
syntax.
When we eventually run all checks in our design, this will ensure
that some-component
has the required AEC Q200 metadata.
Finally, we run all of the checks on our design
with the run-checks
command.
This will execute every check in the design and log the results
to a text file at the specified filename.