Closed kcaisley closed 1 year ago
I think there are a few potential cases there.
Module
or ExternalModule
. E.g. SomeExternalModule = h.ExternalModule(
paramtype=MosParams, # the `MosParams` class from above
# ... all the other fields
)
@h.paramclass
class ParamsYouActuallySpecify:
w = ...
l = ...
# Note "dependent" things like `ad` are not parameters
def something(params: ParamsYouActuallySpecify) -> h.ExternalModule:
ad = params.w * params.l * whatever_else
# ...
return SomeExternalModule(ad=ad, ..., **asdict(params))
If you don't know their values - e.g. if they are provided in some external netlist or other file - them h.Literal
is the way to tell SPICE to make combinations such as w * l
.
You... don't actually need the dependent parameters at all? If you dig into those models, you'll often find this default-value expression is embedded somewhere further down, so long as it's provided with a good value for required parameters such as w
and l
. It is very unlikely that you'll ever want to set them to anything but that default expression. (In code that you actually write. An extraction program is another matter).
And separately, while it's different for each simulator, it's pretty common for netlist-language-support to include fairly elaborate mathematical-expressions, such as that %
modulo operator, ternary a ? b : c
expressions, and in some cases conditionals (if
/ else
) and function definitions. I.e. everything in here:
https://github.com/dan-fritchman/Netlist/blob/56790e83efd50725f8648f1afa3e3634d49e022d/netlist/data.py#L609
Thank you so much for the feedback. I think my use case squarely falls under the Case 1 you outlined. I will try writing a function which computes these other parameters, and reply back with my solution for posterity.
When I use my PDK's devices to draw a schematic in a commercial tool, I just specify w
, l
, multi
and nf
. For example:
Then, when I convert this schematic to a netlist, I get the following .scs
file with additional BSIM6 instance parameters already pre-computed:
subckt inv vdd vin vout vss
M0 (vout vin vdd vdd) pch_mac l=50n w=400n multi=1 nf=2 sd=100n \
ad=4e-14 as=5.5e-14 pd=3.2u ps=4.5u nrd=2.391274 nrs=1.391274 \
sa=339.369n sb=339.369n sa1=235.441n sa2=327.889n sa3=322.265n \
sa4=128.196n sb1=435.441n sb2=427.889n sb3=422.265n spa=100n \
spa1=100n spa2=100n spa3=100n sap=232.843n sapb=250.777n \
spba=215.715n spba1=417.043n dfm_flag=0 spmt=1.21111e+14 spomt=0 \
spomt1=1.121111e+30 spmb=2.21111e+15 spomb=0 spomb1=2.11111e+30
M1 (vout vin vss vss) nch_mac l=50n w=400n multi=1 nf=2 sd=100n \
ad=4e-14 as=5.5e-14 pd=3.2u ps=4.5u nrd=2.391274 nrs=1.391274 \
sa=339.369n sb=339.369n sa1=235.441n sa2=327.889n sa3=322.265n \
sa4=128.196n sb1=435.441n sb2=427.889n sb3=422.265n spa=100n \
spa1=100n spa2=100n spa3=100n sap=232.843n sapb=250.777n \
spba=215.715n spba1=417.043n dfm_flag=0 spmt=1.21111e+14 spomt=0 \
spomt1=1.121111e+30 spmb=2.21111e+15 spomb=0 spomb1=2.11111e+30
ends inv
// not real PDK values; don't sue me please!
I hoped (as you mentioned in your Case 3) that I could instead rely on the values of these parameters being determined by the lower-level .scs
device macro models imported with include
from my PDK. In fact, I did find sections in the macro models which appeared to do that. But when I factored out the additional parameters in my test netlist, like so..
subckt inv vdd vin vout vss
M0 (vout vin vdd vdd) pch_mac l=50n w=400n multi=1 nf=2
M1 (vout vin vss vss) nch_mac l=50n w=400n multi=1 nf=2
ends inv
... and re-simulated the circuit, I got different results. This led me to believe that something else (OA cellviews?) was probably auto-magically pre-filling these additional values before writing the netlist.
∴ This led to me figuring out the function between w
, l
, nf
and these other "dependent" values, and then trying to get my Hdl21 PDK package to replicate the same.
Right, so - there's another layer to dig in then.
I expect I know just which piece of commercial software (which shall not be named) produced this netlist. And it, and similar programs, can in general have custom netlisting routines, transforming a relatively terse set of parameters into that very verbose one.
So the next layer is - what do all those verbose parameters mean?
Generally, they are for what (your) foundry calls "LDE" - layout-dependent effects.
There is not great public info about what the advanced technology LDE's are. Here's an OK-looking summary from AMD:
https://ewh.ieee.org/r5/denver/sscs/Presentations/2009_04_Faricelli.pdf.
(Your foundry-provided docs will have more detailed & better versions.)
So, these parameters include things like:
Those questions all effect the device characteristics, and ultimately matter.
But what you should be wondering is: how could you possibly get those values from a schematic?
And the short answer is, you can't.
If you have a layout, or know a priori how you're going to lay the whole circuit out, then yes, you implicitly (or explicitly) know good values for these parameters. (Extraction programs will set them, often plus a bunch more.) I imagine that netlist above is, like, "the values that the default layout p-cells would generate, maybe if placed in an otherwise infinite empty universe, or maybe if placed in whatever we think is like 'the average layout'". I don't know how much better of a guess one could make? Nor have I ever really followed why they insist on putting them there.
So anyway - whatever these values are, don't get too attached to them at the schematic level. If you really believe your design is sufficiently sensitive to them, do some layout and extract it. That time will be better-spent than reverse-engineering any schematic-based estimations!
Perfect, the deeper explanation really helped. Your comment that "Extraction programs will set them, often plus a bunch more" was precisely on point.
I've tested the foundry-provided decks from my PDK. When fed through a DRC->LVS->PEX flow, the aforementioned and many additional layout-dependent effect (LDE) parameters are "back-annotated" to the device instances. The delta between having and not having these effects at the schematic-level certainly isn't worth the trouble.
I'll simply follow the mantra "extract early and often".
Context
I'm a bit stuck working on a
paramclass
meant to pass BSIM6 instance parameters to a correspondingExternalModule
for transistors in a PDK.What I'd like to do
I'm curious if there is a (recommended) way to express the default value of a
h.Param
, as a function of other parameters, without having to rely onh.Literal
strings? To be concrete, let's say we have thisparamclass
for example:And let's say I know the correct default expression for
ad
, in terms of widthw
and finger countnf
, is:Many of the other BSIM6 instance parameters have a similarly complicated expression, so if I use
h.Literal()
, I think the resulting raw output netlist will become quite convoluted. Instead, I'd like to be able to match the behavior of commercial EDA tools I'm using, which calculate the exact BSIM instance parameters before netlisting. (I'm also not sure ifngspice
/spectre
simulators even support operators like%
?)What I've tried so far
MosParams
class. The decorator function behind@paramclass
inparams.py
givesRuntimeError: Invalid class-attribute 'x' in paramclass <class 'pdk.MosParams'>. All attributes should be 'hdl21.Params'.
h.Param
. That yieldsTypeError: unsupported operand type(s) for %: 'Param' and 'Prefixed'
def paramclass(cls: Type[T]) -> Type[T]
, I see:*All* non-Python-internal fields must be of type Param
. This, and the errors before, make sense to me as aparamclass
is immutable after creation.w
,l
, andnf
:def calc_inst_params(w: float, l: float, nf: int) -> h.Prefixed
. I suppose I can use it's return values to create instances ofMosParams
, but this feels inelegant as it sort of overlaps with thedefault
s functionality already built into Hdl21.I suspect this could be a justified instance of "You're holding it wrong." If anyone has any guidance, I would really appreciate it. Thanks!