circuitRF Reference Guide

Protected Models

For a device maker deciding whether to publish a model here - why circuitRF does not encrypt models, what to compile and what can stay outside, how to publish a cell as one compiled module or as one S-parameter block with its devices, what a protected model still reveals, how to restrict use from inside it, and how to sign the library.

Why circuitRF does not encrypt models

A simulator that accepts encrypted models has to decrypt them on the user's machine, so it needs the key. In a closed program the key is hidden inside the program's binary. circuitRF's source is public, so any key it held would be public too, and anyone could rebuild circuitRF to write the decrypted model to disk. An encryption feature here would protect nothing, so circuitRF has none.

What does protect a model, in any simulator, is compiled code. You compile your own model, and circuitRF only asks it for currents, charges and their derivatives at the terminal voltages it supplies. circuitRF runs a compiled .osdi in a separate process (see Verilog-A). The protection is entirely in your binary, so circuitRF being open source costs you nothing. circuitRF never holds a secret of yours, so there is nothing in circuitRF to extract.

What to compile, and what can stay outside

A protected model is an ordinary model folder in which the device you want to protect is a compiled .osdi with no source beside it.

Compile netlist: publish a cell as one compiled module

You do not have to write the Verilog-A yourself. If the model is already a circuitRF cell — a ComposedFET with its package network, or a matched stage built from lumped parts and a device — tick Protect the model in Export to Library and choose Compile netlist (one compiled module) (on the command line, --protect compile, or --compile-netlist). It is off unless you tick it. Export writes the whole cell as one Verilog-A module, compiles it with your own compiler, and publishes the compiled build in place of the cell. The cell's schematic, its sub-cells and any .cmodel are not copied into the library.

Export to Library Target Library /libraries/devices Browse… Libraries this workspace references Category Library Name Publisher Version 1.0.0 License Part Part number TSTPA200 Description Kind Active Value 10 pF Frequency 0 Hz 20 GHz Conditions Vds = 3 V, 25 °C Footprint 1005M(0402) Parameters Name Nominal Tolerance Lp 1 nH None ± 5 % at 3 σ Corners Add corner Frequency No component uses the technology. Sweep + Segment Step Points Single Lin Log Start 0 GHz = 0 Stop 20 GHz = 2E+10 Points 1001 DC is always included. Compiled models Compile Verilog-A models (ship the build, not the source) The cell places no Verilog-A source to compile. Builds for other platforms… Add build Compile netlist builds every platform the compiler can reach; another platform's build is added by exporting there. Protected model Compile netlist (protected model) The generated source goes to /designs/PowerAmp/protected-source/TSTPA200/ TSTPA200.va, outside the library. Proof bias g=-0.5 d=5 Proved at: all pins at 0 V; in=1 out=-1; in=-1 out=1. Type one point per line to choose your own. Documents Add… Remove Symbol Box Compiled into the model Compiled into one module: R1 (R), Q1 (ComposedFET), C1 (C), X1.L1 (L). Outside, in the wrapper: SNP1 (SnP). The module has 3 terminals: 1 of the cell's 2 pins, 1 added where outside elements meet it (n3) and ground. Add this library to the workspace Cancel Export Export to Library Target Library /libraries/devices Browse… Libraries this workspace references Category Library Name Publisher Version 1.0.0 License Part Part number TSTPA200 Description Kind Active Value 10 pF Frequency 0 Hz 20 GHz Conditions Vds = 3 V, 25 °C Footprint 1005M(0402) Parameters Name Nominal Tolerance Lp 1 nH None ± 5 % at 3 σ Corners Add corner Frequency No component uses the technology. Sweep + Segment Step Points Single Lin Log Start 0 GHz = 0 Stop 20 GHz = 2E+10 Points 1001 DC is always included. Compiled models Compile Verilog-A models (ship the build, not the source) The cell places no Verilog-A source to compile. Builds for other platforms… Add build Compile netlist builds every platform the compiler can reach; another platform's build is added by exporting there. Protected model Compile netlist (protected model) The generated source goes to /designs/PowerAmp/protected-source/TSTPA200/ TSTPA200.va, outside the library. Proof bias g=-0.5 d=5 Proved at: all pins at 0 V; in=1 out=-1; in=-1 out=1. Type one point per line to choose your own. Documents Add… Remove Symbol Box Compiled into the model Compiled into one module: R1 (R), Q1 (ComposedFET), C1 (C), X1.L1 (L). Outside, in the wrapper: SNP1 (SnP). The module has 3 terminals: 1 of the cell's 2 pins, 1 added where outside elements meet it (n3) and ground. Add this library to the workspace Cancel Export
Export to Library with Compile netlist ticked: the cell's R, C, sub-cell inductor and ComposedFET are compiled into one module, its S-parameter file stays outside in the wrapper, and the proof's default bias points are listed under the bias field.

The dialog, top to bottom. Everything above Protected model is Export to Library as it is without Compile netlist; what changes with it ticked is noted.

Control What it does
Library, Libraries this workspace references The library folder the part goes into. An empty or new folder starts a new library.
Category The folder inside the library, /-separated (Amplifiers/LNA); empty puts the part at the library's root.
Name, Publisher, Version, License Written to a new library's library.clib; greyed when the library already has one.
Part number, Description The part's name in the palette (the model folder's name) and its one-line description.
Kind, Value Active or Passive (a nonlinear part makes it Active), and a passive's value, which value search reads.
Frequency, Conditions, Footprint The range the model is valid over, the conditions it was made at, and the footprint, as the palette shows them. The proof's three frequencies are spread across this range.
Parameters The cell's parameters, each with a Tolerance: a spread here still draws per placed part in a yield run, because the wrapper evaluates it.
Corners Named sets of parameter values a placed part can select.
Frequency (sweep) The plan technology parts are sampled over when they become S-parameter files, and the plan an encapsulated block is sampled over. Greyed when the cell has no technology part and Encapsulated netlist is not chosen.
Compile Verilog-A models Ships each Verilog-A device and ComposedFET the cell places as its compiled build instead of its source (a ComposedFET is written as Verilog-A first). The cell's topology still ships. With Compile netlist, this applies to the Verilog-A devices left outside.
Builds for other platforms… Adds builds of a compiled device made elsewhere. Greyed with Compile netlist, which builds every platform the compiler can reach itself.
Protect the model Publishes the model without its schematic. Off until you tick it; the two ways under it are greyed until then.
Encapsulated netlist (one S-parameter block) Chosen when you tick the box: the cell's linear network as one S-parameter block, its devices placed against it. Needs no compiler. See Encapsulated netlist.
Compile netlist (one compiled module) Publishes the cell as one compiled module, without its schematic. Greyed with the reason when no Verilog-A compiler is found. The line under it says where the generated source will be written.
Proof bias The bias points the proof runs at, one per line (g=-0.5 d=5; pins not named are at 0 V). Left empty, the line under it lists the default set.
Builds Appears once a compiled export has run: one row per platform, led by the platforms the part will be unavailable on. After an encapsulated export it is Exported: the model folder and the proof's summary. The dialog stays open to show it; Close finishes.
Documents Files copied into the part's docs/ folder, such as a data sheet.
Symbol The symbol the part is placed with: the cell's own, the FET glyph, R, C, L or a box.
Compiled into the model With Compile netlist: what is compiled, what stays outside, and the module's terminals. With Encapsulated netlist it is The S-parameter block. Unprotected, this list is Copied into the model: every sub-cell and file the export copies.
Red lines under it Every reason the export cannot go ahead. Export stays greyed while any stands.
Add this library to the workspace References the library from the workspace, so the part is in the palette as soon as the export finishes.
Export Builds, compiles and proves the part; nothing reaches the library unless the proof passes.

What goes inside, and what stays outside. Sub-cells are flattened into the one module. Each element then lands on one side:

Compiled into the module Left in the wrapper, visibly
R, C, L, Mutual, Short SnP files, and every technology part Export turns into one
ComposedFET ideal and physical transmission lines
SPICE-file devices, Verilog-A devices and external devices

Anything else is refused by name; nothing is approximated to make it fit. Each net that joins an outside element to the module becomes an extra terminal of the module, and ground is its last terminal. The dialog lists what is compiled, what stays outside and the terminal count before anything is written. A Verilog-A device left outside ships as source unless you also tick Compile Verilog-A models, which ships its build instead.

Parameters stay parameters. The cell's parameters become the module's, so a placed part takes overrides, sweeps, corners and tuning as the cell did. A tolerance on a cell parameter still draws in a yield run, because the wrapper evaluates it and passes the result in. A distribution written inside an element's value is refused — compiled, it could never draw — with "Make … a cell parameter to keep its spread."

A ComposedFET with a table constituent is refused, with Model Composer's own sentence: a table cannot be written as Verilog-A. Refit that constituent as an ANN or an equation, or keep the FET outside as a separate protected device.

Where the source goes, and why to keep it. The generated .va is written to protected-source/<Part>/<Part>.va in your workspace folder (--source-out chooses another place; a place inside the library is refused). It is never in the library, so the target library must be a folder outside your workspace: a library that is the workspace folder, or a folder above it, is refused with "Change the target library to a folder outside the workspace." Keep it: every platform's build is made from it. The same cell always generates the same bytes, and part.cpart records their hash as CompiledFrom.

The proof. Before anything reaches the library, Export runs the original cell and the wrapper with its freshly compiled module through the same engine and compares the DC current into every pin, and the Y-parameters at three frequencies across the part's range, at a set of bias points: every pin at 0 V, then each pair of pins at +1 V and −1 V across them. For a FET, the bias that matters is yours to know: type your own points in Proof bias, one per line (g=-0.5 d=5; on the command line, --check-bias "g=-0.5 d=5"). A cell whose thermal pin is a pin is checked at two ambient temperatures as well. The limit is 1e-6 relative, with floors of 1e-12 A and 1e-12 S. Over it, nothing is written to the library, the worst point is named with both values, and the source stays in protected-source/ for you to inspect.

Encapsulated netlist: publish a cell's linear network as one S-parameter block

Compile netlist needs a Verilog-A compiler on your machine, refuses a ComposedFET with a table constituent, and leaves every SnP, transmission line and technology part in the wrapper, where anyone can read them. Encapsulated netlist needs nothing installed. Tick Protect the model and keep Encapsulated netlist (one S-parameter block), which is chosen first (on the command line, --protect encapsulate). Every linear element of the cell becomes one N-port S-parameter block, and the devices are placed against its ports. What ships is the network's behaviour at its ports over the frequency plan. Its topology, its element values and its parts list do not.

What goes into the block, and what stays outside. Sub-cells are flattened first. Every linear element then goes into one block: R, L, C, mutual inductances, transmission lines, every technology part, and every SnP the cell already places. The engine decides, not a list: an element whose model is linear goes in, so a linear model added to circuitRF later goes in too. These stay outside, placed as written:

A SPICE subcircuit is flattened too, and its parts are sorted one by one. One that holds both linear parts and devices is refused, because the block cannot take part of one placed subcircuit. A model holds exactly one block, never two. A cell with nothing linear in it exports with no block: the dialog says "Nothing in the cell is linear: the model is its devices."

The ports. The block has one port for each cell pin it touches, in pin order, then one for each net where it meets a device. Ground is the reference. A pin that only devices touch needs no port. A thermal net is a node like any other, so linear elements on it go into the block and the thermal network is hidden too. In the wrapper the joining nets are called n1, n2, …, because a flattened name such as X1.mid would describe the hierarchy the block hides. The dialog lists each port and what it joins before anything is written. There is no limit on the port count. The dialog shows the count and the file size first, for example "14 ports × 1,001 points, about 8.3 MB". A block with many ports is a large dense matrix at every frequency.

The frequency plan must reach the highest harmonic a run will use. The block is sampled over the Frequency plan, which is live whenever Encapsulated netlist is chosen. It always includes 0 Hz, and the 0 Hz row is the network's DC solution. Above the plan's top frequency the block holds its last point and warns. That is harmless for an S-parameter run inside the plan. In harmonic balance, though, every harmonic above the top frequency sees the network at the top frequency. The line under the plan states the highest fundamental that keeps the default harmonic count inside it, for example "up to a 2.857 GHz fundamental" for a 20 GHz plan and 7 harmonics. If your users will run higher, extend the plan.

Parameters. A cell parameter that reaches only devices, such as a FET's N or Temp, stays a parameter of the part and passes through to them. A parameter that reaches anything inside the block is frozen at its default, because the block is sampled at one set of values. The dialog lists every frozen parameter by name. The published part does not have it, and a device it also reached gets the frozen value. A spread or a corner on a frozen parameter is refused: "Lp has a spread and reaches the S-parameter block, which is sampled at one value. Make it reach only a device, or use Compile netlist." The block is sampled at the design's ambient temperature (25 °C unless the design says otherwise), so a temperature-dependent linear element is fixed there.

Devices ship as they are. Encapsulation hides the linear network only. A ComposedFET's .cmodel and a Verilog-A source ship readable unless you also tick Compile Verilog-A models, which works with Encapsulated netlist as it does alone. The dialog names every device that stays readable while that box is unticked.

Nothing in the library describes the network. The cell's schematic, its sub-cell folders, the element values and every SnP the block absorbed are not copied. The model folder holds models/<Part>.s<N>p, the outside devices' own files, and the wrapper .cnl and .csch. The block's Touchstone header carries the part number, the plan and the circuitRF version, and no element name, net name or time, so the same cell and plan always give the same bytes. part.cpart records "Protection": "encapsulated" and the plan.

The proof. Before anything reaches the library, Export runs the original cell and the wrapper with its block through the same engine at the Proof bias points (--check-bias on the command line). It compares the DC current into every pin, and the Y-parameters at three frequencies taken on sampled points, where the block is exact. The limit is Compile netlist's: 1e-6 relative, with floors of 1e-12 A and 1e-12 S. Over it, nothing is written and the worst point is named with both values. Between samples the block is its interpolation: the worst |S| difference halfway between samples is reported in dB, as information. The proof runs at the one ambient the block was sampled at.

Which method to use

Encapsulated netlist Compile netlist
Needs nothing a Verilog-A compiler, and zig for other platforms' builds
Hides every linear element, SnPs, transmission lines and technology parts included R, C, L, mutuals, shorts and ComposedFETs
Stays visible the devices, unless Compile Verilog-A models is ticked SnPs, transmission lines, technology parts and outside devices
Parameters only those that reach devices; the rest are frozen all of them
Valid over the frequency plan every frequency (an SnP left outside keeps its own range)

What a compiled model still reveals

Know this before publishing, rather than finding it out afterwards. Anyone who has your compiled model can read:

Give internal nodes opaque names (n1, n2) rather than names that describe the circuit. The sparsity pattern cannot be hidden, because the simulator has to know it to solve the circuit.

Restricting use from inside the model

If you want to limit who can run the model — a machine, a date, a licence file, a licence server — build that check into your own model. circuitRF does not know or care which you choose. What it guarantees is this: a model that refuses to start stops the run, and the user reads your sentence. The run ends as one refusal that leads with your words, in the Messages panel and on the command line's standard error with exit code 1. It does not continue on zeros, retry, or wait.

A sketch, where licensed() stands for whatever check you write:

`include "disciplines.vams"

module tstfet100(g, d, s);
  inout g, d, s;
  electrical g, d, s;
  parameter real vto = -0.8;

  analog begin
    @(initial_step)
      if (!licensed())
        $fatal(1, "TSTFET100: this build is not licensed on this machine. Contact the publisher for one.");
    // the model itself
  end
endmodule

Write the sentence for the person who reads it: what stopped, and what they can do about it.

Signing, and the platforms to build for

Sign the library so users can tell that it is yours and unmodified. A compiled model is native code that runs on their machine, so this matters more for a protected model than for any other. circuitrf sign --new-key makes a key and circuitrf sign <library> --key <key> signs the library. Keep the key outside the library. The details, and what users see, are in Signed libraries.

Build for each platform your users have, and put each build in its own folder under models/, named for the platform:

Folder Platform
win-x64 Windows, 64-bit Intel and AMD
win-arm64 Windows on Arm
win-x86 Windows, 32-bit
osx-arm64 macOS on Apple silicon
osx-x64 macOS on Intel
linux-x64 Linux, 64-bit Intel and AMD
linux-arm64 Linux on Arm

List them in part.cpart's Builds. On a platform you did not build for, the part is listed greyed with the platforms you do ship for, so a user knows what to ask you for. Export to Library copies the build it ran with and takes the others under Builds for other platforms… (on the command line, --build <rid>=<path>). circuitrf check proves that every listed build is there and is for the platform its folder names.

Building for every platform

With Compile netlist, Export tries every platform in the table above and reports each one in a Builds table: built and checked (the proof ran here), built, not run on this machine, or not built, with the compiler's own first error line and what would fix it. A platform that fails never fails the export. Every build put in a library is compiled for a generic processor, so it runs on older processors than the one it was built on.

The platform you export on is built exactly as it always is, with the compiler's own linker. Every other platform is linked with zig, which circuitRF does not ship: install it and put it on PATH, or name it in Settings ▸ Security & Permissions ▸ Linker (zig). A Mac build made on a Mac uses the Mac's own linker and needs no zig. With zig installed, and with a Verilog-A compiler that targets every processor, one export from any of the three operating systems builds:

Platform Built from any machine
win-x64 Yes. Not run before it ships.
win-arm64 Yes. Not run before it ships.
win-x86 No: the compiler has no 32-bit Windows target.
osx-arm64 Yes.
osx-x64 Yes. Not run before it ships.
linux-x64 Yes.
linux-arm64 Yes.

A platform that is not built says why in its row:

Why The row says
zig is not installed "Install zig to build for other platforms, or name it in Settings ▸ Security & Permissions."
The compiler builds only for its own processor "The Verilog-A compiler builds only for the processor it runs on (arm64 here). A compiler build that targets every processor builds this platform too." A compiler built this way on a Mac on Apple silicon builds linux-arm64 and win-arm64, and none of the x86-64 platforms.
win-x86 "The compiler has no 32-bit Windows target, so no machine can build this platform with it."
zig refused the link zig's own first line, as zig wrote it.

Every build made on another machine goes into Builds and not Proved: it was compiled for that platform and never run by you. A Windows or Intel Mac build made elsewhere ships without having been run on its platform. To have every build proved, export on each platform: run the same Export with Compile netlist on a Windows, Linux or Intel Mac machine into the same library. When the source's hash matches CompiledFrom, that platform's build is added and proved there, and part.cpart's Proved lists it. When it differs, nothing is written: "The cell changed since the osx-arm64 build. Rebuild every platform from one source." A continuous-integration job on each platform does this without the GUI; its --json output carries the same table as builds[] (rid, state, reason, fix), and the exit code stays 0 when a platform is missing.

What your users see when a platform is missing

On a platform you did not build for, the part is listed greyed in the palette with the platforms you do ship for. A build that is in Builds but not in Proved was compiled on another machine and never run by you; it runs normally.

The MCP server's reference tool serves this page as the topic protected-models.