<@U01819B63HP>: I'd like your opinion on somethin...
# xschem
t
@Stefan Schippers: I'd like your opinion on something I'm working on. I once wrote a system called "CACE" for doing automatic characterization of circuits across corners; basically a way to create a spec for a circuit and then automatically test whether the circuit meets or fails the spec. It was running on the Efabless Open Galaxy servers for a while. But now that we have open PDKs, we're moving away from the Open Galaxy system, and I'm trying to port everything to work on a local machine with the open PDKs. I got that much working a while back. But the original system depended on hand-written testbench netlists and I'd like to upgrade those to xschem schematics. The main issue is that to make the system work automatically across corners, I've coded a bunch of things in the netlist as variable names so I can have a script go through it and replace variables with numbers (or strings) and then run it though ngspice. What I'm looking for is to start with the attached schematic
dccurrent_vdd.sch
and generate the same contents as the attached hand-written netlist
dccurrent_vdd.spice.orig
. I'm not quite there yet. I'm not sure about how to handle the symbol for the DUT. The original system used a generic placeholder for the DUT and would actually figure out what order the pins were supposed to be in. The thinking behind that is that you can write a spec with a pinout and prepare all the testbenches without worrying about the actual schematic or how it's drawn or whether it even has a symbol. But xschem isn't too happy about the pins being named things like
${PIN:vdd:vdd}
. Probably I just need to replace the
@pins
in the instance and not try to actually give the pins themselves variable names. But there are a few other places that xschem is not very happy with my CACE-friendly syntax. The use of
$
to denote variables to be replaced is more tradition than necessity. If changing to some other character helps get a resulting netlist that's easy to do search-and-replace on, that's all I really need. But the
$
is working fine in some cases like the
code_shown
blocks, so I'm not sure if that's the actual problem.
s
Hi, @Tim Edwards Voltage source symbols had a tcl evaluation stage on the
format
string that was used to add a
.save i(vxxx)
line in the netlist if a
savecurrent=true
attribute was present. I never did like this solution, since calling tcl for such a simple task is overkill. SInce voltage sources (
vsource.sym
) and ammeters (
ammeter.sym
) where the only two symbols doing this I have now removed any tcl evaluation on their netlist rule. As a result any
$
character is no more interpreted by tcl and we don't need to enter the quoting hell to prevent such characters from being interpreted. The
savecurrent
attribute is still honored as before (a .save line is added in the netlist if set to
true
) but it is done in the C code parser. Faster and cleaner. As a result I have netlisted your dccurrent_vdd.sch circuit and this is the result , that seems correct.
Copy code
** sch_path: /home/schippes/.xschem/xschem_library/cace/dccurrent_vdd.sch
**.subckt dccurrent_vdd
VVDAC7 b7 VSUB DC ${DIGITAL:b1} ${VOLTAGE:dvdd} ${*}
VVDAC1 b1 VSUB DC ${DIGITAL:b1} ${VOLTAGE:dvdd} ${*}
VVDAC2 b2 VSUB DC ${DIGITAL:b2} ${VOLTAGE:dvdd} ${*}
VVDAC3 b3 VSUB DC ${DIGITAL:b3} ${VOLTAGE:dvdd} ${*}
VVDAC4 b4 VSUB DC ${DIGITAL:b4} ${VOLTAGE:dvdd} ${*}
VVDAC5 b5 VSUB DC ${DIGITAL:b5} ${VOLTAGE:dvdd} ${*}
VVDAC6 b6 VSUB DC ${DIGITAL:b6} ${VOLTAGE:dvdd} ${*}
VVDAC0 b0 VSUB DC ${DIGITAL:b0} ${VOLTAGE:dvdd} ${*}
VVlow Vlow VSUB DC ${VOLTAGE:Vlow}
VVhigh Vhigh VSUB DC ${VOLTAGE:Vhigh}
Vena ena VSUB DC ${DIGITAL:ena} ${VOLTAGE:dvdd} ${*}
Vvss vss VSUB DC ${VOLTAGE:vss}
Rout out VSUB ${RESISTANCE:out} m=1
Cout out VSUB ${CAPACITANCE:out} m=1
Vdvss dvss VSUB DC ${VOLTAGE:dvss}
Vvdd vdd VSUB DC ${VOLTAGE:vdd}
Vdvdd dvdd VSUB DC ${VOLTAGE:dvdd}
RSUB VSUB GND 0.01 m=1
*  XDUT -  dut  IS MISSING !!!!
**** begin user architecture code

.control
op
let vtest = -I(Vvdd)
echo ${FILENAME} $&vtest
quit
.endc



* CACE gensim simulation file ${FILENAME}_${N}
* Generated by CACE gensim, Efabless Corporation (c) 2023
* Find the current through the DAC.  Include both current through vdd and VREFH

.include ${DUT_PATH}
.include ${PDK_ROOT}/sky130A/libs.ref/sky130_fd_sc_hvl/spice/sky130_fd_sc_hvl.spice

.lib ${PDK_ROOT}/sky130A/libs.tech/ngspice/sky130.lib.spice ${CORNER}

.option TEMP=${TEMPERATURE}
* Flag unsafe operating conditions (exceeds models' specified limits)
.option warn=1


**** end user architecture code
**.ends
.GLOBAL GND
.end
The next step is to handle the
dut.sym
symbol. It is currently shown as a "missing symbol", if you have one
dut.sym
example just to see what needs to be done next...
1.png
t
@Stefan Schippers: I posted the
dut.sym
above. But I modified it several times to see what might or might not work, so let me post what I wanted originally.
s
Oh sorry, I missed it. Thanks
@Tim Edwards does the
dut.sym
have a corresponding schematic? or is the dut netlist available/generated in some separate file? In this latter case you can change the
type=subcircuit
attribute of the dut symbol to
type=primitive
. Xschem will only generate the instance call (
XDUT dvdd vss dvss vdd b0 Vhigh b1 b2 b3 out b4 b5 ena b6 b7 Vlow ${DUT_NAME}
) for it and will not complain about non existing
dut.sch
t
Yes, that's the intent. It may or may not have a corresponding schematic. The "primitive" flag is probably what I want. But the pins are supposed to have the form
${PIN:name:name}
which is not represented in the version of
dut.sym
that I posted above.
s
ok, please post the modified desiderata
dut.sym
, will see what does xschem do with it and then decide what to do next :-)
Usually when I need parametric circuits I use TCL substitution. If I set for example
value="tcleval(DC ${dcval} AC ${acval} ${tranval})"
on -say- a voltage source the result will be the string with the value of tcl variables substituted in. In the same way you can use tcl command substitution
[command]
instead of
$variable
substitution. the tcleval() wrapper informs xschem a TCL
subst
needs to be done on the attribute string (at global scope). if no tcleval() is present no such substitution / evaluation occurs. This works almost for any attribute string, so for a symbol pin:
name="tcleval($pinvar)" dir=inout
You can then define these variables / procedures in a tcl file and call xschem this way:
xschem --script defs.tcl circuit.sch
or define everything on the command line:
xschem --command 'set dcval 3; set acval {1 0}; set tranval {pulse 0 0 1u 0 1.1u 3}; set pinvar PLUS' circuit.sch
A more pervert (but sometimes powerful) approach for parametric schematics is to use generators (kind of pcells). If a symbol reference has the form
gen_script(param1,param2,param3,...)
instead of -say-
inv.sym
the symbol will be loaded by executing the
gen_script
with parameters
param1, param2, param3, ...
and reading the standard output from it.
gen_script
can be anything, like a tcl program, a python program, a bash script. Usually I write generators by drawing a symbol template in xschem, saving to a file, renaming the file to
gen_script
and transforming the symbol template into a parametric generator. https://xschem.sourceforge.io/stefan/xschem_man/tutorial_symbol_generators.html
t
There are definitely multiple solutions and I am currently just trying to figure out which of them is best. Attached is the
dut.sym
symbol as I had originally envisioned it. The format of the pin output is
${PIN:name1:name2}
where
name1
is the net in the testbench and
name2
is the pin name in the schematic (it could be the other way around---I always use the same name for both, so I can't remember which way it is without looking back at the parsing code I wrote). That way it's more like a verilog instance where the pins can be in any order, since the instance calls out both the connection and the pin name, and the CACE system can then generate a netlist where the pin order is always correct as long as the schematic and symbol have the same pins. But the way I have it now, the net connection name is hard-coded into the instance, which is not the way I want it, but I haven't spent the time to figure out how I can get xschem to write out the pin with both the pin name and the connection name.
s
Thank you. I see there are some warnings because xschem does not understand the symbol pin format. Since xschem allows vector instances and vector net names it must figure out if a symbol pin is a single bit or a multi-bit bundle, example:
CLK
is a single bit, while
ADD[15:0]
is a 16 bit bundle. Spice netlist must have all bundles unrolled to single bits. if a symbol pin is given as: ${PINb0b0} xschem does not recognize the format, so issues a warning and assumes it is a single bit. Of course I can waive this particular case, for example do not issue warnings if the pin name begins with a given character or has some other pattern. Referring to the picture below the
adder_64bit
must be netlisted as a subckt that takes 196 bits. if xschem assumes 1 bit width for all pins it would netlist as a 7 port subcircuit.
t
It's probably much easier for me just to change the delimiter from
:
to something else; it is only meaningful to the CACE parser. I will have to figure out how to incorporate xschem's handling of vectors into CACE. The example I posted lists the DAC input as
b[7:0]
in the verilog but expands that out to
b7
...
b0
in the netlist. If the testbench symbol can be made to work as a vector, that's generally better.
@Stefan Schippers: I think I'm getting closer to what I want. So I changed
:
to
|
everywhere to get rid of issues related to the use of colons in arrays. But I decided that if I want both the pin name and pin connectivity inside the pin list, then I need to do something like this:
Copy code
format="@name $\{PIN|@@dvdd\|dvdd\} $\{PIN|@@vdd\|vdd\} $\{PIN|@@dvss\|dvss\} $\{PIN|@@vss\|vss\} $\{PIN|@@Vhigh\|Vhigh\} $\{PIN|@@Vlow\|Vlow\} $\{PIN|@@out\|out\} $\{PIN|@@ena\|ena\} $\{PIN|@@b0\|b0\} $\{PIN|@@b1\|b1\} $\{PIN|@@b2\|b2\} $\{PIN|@@b3\|b3\} $\{PIN|@@b4\|b4\} $\{PIN|@@b5\|b5\} $\{PIN|@@b6\|b6\} $\{PIN|@@b7\|b7\} $\{DUT_NAME\}"
My understanding is that
@@pin
should be replaced by the connectivity, and if the character following it is not a space, then it needs to be escaped. But instead of
Copy code
XDUT ${PIN|dvdd|dvdd} ${PIN|vdd|vdd} ...
in the output netlist, I'm getting
Copy code
XDUT ${PIN| ${PIN| ${PIN| ${PIN| ...
That is, it does not recognize the
@@pin
with
\|
after it.
s
@Tim Edwards In general xschem supports vectors (expecially important where natively allowed, like verilog or vhdl netlists). For spice these buses are expanded to single bits: For example in verilog the MSB instance x0[3] of the above adder_64bit netlists in verilog as:
Copy code
adder_64bit
x0_3 ( 
 .A( A[255:192] ),
 .S( S[255:192] ),
 .B( B[255:192] ),
 .COUT( net1 ),
 .SG( G[3] ),
 .CIN( C3 ),
 .SP( P[3] )
);
And the module definition looks like:
Copy code
module adder_64bit
(
  input wire [63:0] A,
  output wire [63:0] S,
  input wire [63:0] B,
  output wire COUT,
  output wire SG,
  input wire CIN,
  output wire SP
);
...
...
endmodule
While the spice netlist is a single bit orgy:
Copy code
x0[3] A[255] A[254] A[253] A[252] A[251] A[250] A[249] A[248] A[247] A[246] A[245] A[244] A[243]
+ A[242] A[241] A[240] A[239] A[238] A[237] A[236] A[235] A[234] A[233] A[232] A[231] A[230] A[229] A[228]
+ A[227] A[226] A[225] A[224] A[223] A[222] A[221] A[220] A[219] A[218] A[217] A[216] A[215] A[214] A[213]
+ A[212] A[211] A[210] A[209] A[208] A[207] A[206] A[205] A[204] A[203] A[202] A[201] A[200] A[199] A[198]
+ A[197] A[196] A[195] A[194] A[193] A[192] S[255] S[254] S[253] S[252] S[251] S[250] S[249] S[248] S[247]
+ S[246] S[245] S[244] S[243] S[242] S[241] S[240] S[239] S[238] S[237] S[236] S[235] S[234] S[233] S[232]
+ S[231] S[230] S[229] S[228] S[227] S[226] S[225] S[224] S[223] S[222] S[221] S[220] S[219] S[218] S[217]
+ S[216] S[215] S[214] S[213] S[212] S[211] S[210] S[209] S[208] S[207] S[206] S[205] S[204] S[203] S[202]
+ S[201] S[200] S[199] S[198] S[197] S[196] S[195] S[194] S[193] S[192] B[255] B[254] B[253] B[252] B[251]
+ B[250] B[249] B[248] B[247] B[246] B[245] B[244] B[243] B[242] B[241] B[240] B[239] B[238] B[237] B[236]
+ B[235] B[234] B[233] B[232] B[231] B[230] B[229] B[228] B[227] B[226] B[225] B[224] B[223] B[222] B[221]
+ B[220] B[219] B[218] B[217] B[216] B[215] B[214] B[213] B[212] B[211] B[210] B[209] B[208] B[207] B[206]
+ B[205] B[204] B[203] B[202] B[201] B[200] B[199] B[198] B[197] B[196] B[195] B[194] B[193] B[192] net1
+ G[3] C3 P[3] adder_64bit
...
...
.subckt adder_64bit A[63] A[62] A[61] A[60] A[59] A[58] A[57] A[56] A[55] A[54] A[53] A[52] A[51]
+ A[50] A[49] A[48] A[47] A[46] A[45] A[44] A[43] A[42] A[41] A[40] A[39] A[38] A[37] A[36] A[35] A[34]
+ A[33] A[32] A[31] A[30] A[29] A[28] A[27] A[26] A[25] A[24] A[23] A[22] A[21] A[20] A[19] A[18] A[17]
+ A[16] A[15] A[14] A[13] A[12] A[11] A[10] A[9] A[8] A[7] A[6] A[5] A[4] A[3] A[2] A[1] A[0] S[63] S[62]
+ S[61] S[60] S[59] S[58] S[57] S[56] S[55] S[54] S[53] S[52] S[51] S[50] S[49] S[48] S[47] S[46] S[45]
+ S[44] S[43] S[42] S[41] S[40] S[39] S[38] S[37] S[36] S[35] S[34] S[33] S[32] S[31] S[30] S[29] S[28]
+ S[27] S[26] S[25] S[24] S[23] S[22] S[21] S[20] S[19] S[18] S[17] S[16] S[15] S[14] S[13] S[12] S[11]
+ S[10] S[9] S[8] S[7] S[6] S[5] S[4] S[3] S[2] S[1] S[0] B[63] B[62] B[61] B[60] B[59] B[58] B[57] B[56]
+ B[55] B[54] B[53] B[52] B[51] B[50] B[49] B[48] B[47] B[46] B[45] B[44] B[43] B[42] B[41] B[40] B[39]
+ B[38] B[37] B[36] B[35] B[34] B[33] B[32] B[31] B[30] B[29] B[28] B[27] B[26] B[25] B[24] B[23] B[22]
+ B[21] B[20] B[19] B[18] B[17] B[16] B[15] B[14] B[13] B[12] B[11] B[10] B[9] B[8] B[7] B[6] B[5] B[4]
+ B[3] B[2] B[1] B[0] COUT SG CIN SP
...
...
.ends
@Tim Edwards the
@@pin
syntax works without side effects if it appears surrounded by white space. This because some metadata is added to handle vector net connections to vector symbol ports of vectored instances, metadata that is removed after the netlisting is complete. if
@@pin
is inserted without white spaces around it the parsers downstream don't understand the syntax and you get garbage. There is another syntax to just '_give me the net name attached to this port, no other side effects please_',
@#port_name:net_name
this should work for your specific case:
Copy code
format="@name ${PIN|@#dvdd:net_name\\|dvdd} ${PIN|@#vdd:net_name\\|vdd} .... "
This is how you enter the format attribute if you do a 'q' on a symbol and enter the format attribute. If you are writing directly the symbol file this is how it is stored:
Copy code
format="@name $\{PIN|@#in:net_name\\\\|in\} $\{PIN|@#out:net_name\\\\|out\} @model"
You see the quoting hell (the 4 backslashes): Xschem file format uses braces {...} to group items so the \ is used as escape character (for example if you need to enter a literal brace) and it must escape itself. After reading the file the 4 backslashes are therefore reduced to 2 The symbol attribute list is a text string with various
token=value
or
token="value with spaces"
items. Again since double quotes are used to allow space in token values a backslash is used to allow entering literal " characters. Again backslash must escape itself. So after format=... value is extracted from the double quotes the 2 backslashes are reduced to 1 and you get:
Copy code
@name ${PIN|@#dvdd:net_name\|dvdd} ${PIN|@#vdd:net_name\|vdd} ....
this is the correct representation. The backslash at the end of
net_name
tells xschem the
|
is not part of the
@#dvdd:net_name
. and this will be substituted with the net attached to the symbol port.
t
@Stefan Schippers: Many thanks! The
@#port_name:net_name
syntax was just what I needed. I'm still not sure that's the best way I want to go about the whole thing ultimately, but at least that gets me what I want for the output with the existing framework. I like the way you just assume I'm going to hack the .sym file directly with a text editor. : )
s
@Tim Edwards I have made a small xschem change. If symbol ports begin with '$' assume these will be processed by some scripts downstream so don't try to look at the node syntax. Assume 1 bit width and leave the node as is in the netlist, without issuing warnings. If there are some other syntaxes you plan to use I can add other exceptions as well.
@Tim Edwards just for info, the reason xschem tries to analyze node labels for producing netlists is because it allows complex bundle representations, like: •
AAA,BBB,CCC: described a bundle of 3 signals, AAA, BBB, CCC.
AAA[3:0]: describes the set AAA[3],AAA[2],AAA[1],AAA[0]. The form AAA[3:0] and AAA[3],AAA[2],AAA[1],AAA[0] are exactly equivalent.
AAA[1:0],BBB[5:4]: describes the bundle: AAA[1],AAA[0],BBB[5],BBB[4].
AAA[6:0:2]: describes the bundle AAA[6],AAA[4],AAA[2],AAA[0].
AAA[0:1:4:3]: describes the bundle AAA[0],AAA[1],AAA[4],AAA[5],AAA[8],AAA[9].  The meaning of the 4 parameters are: start:end:offset:repetitions.
2*AAA[1:0]: describes the bundle AAA[1],AAA[0],AAA[1],AAA[0].
AAA[1:0]*2: describes the bundle AAA[1],AAA[1],AAA[0],AAA[0].
2*(AAA[1:0],BBB): describes the bundle AAA[1],AAA[0],BBB,AAA[1],AAA[0],BBB.
All above syntaxes can also be given with KiCad style
..
instead of
:
, in this case the square brackets will be removed, like in: •
AAA[1..0]*2: describes the bundle AAA1,AAA1,AAA0,AAA0.
So no matter how complex a bundle is given to a net or a symbol port (or even a component vector placement) these will be processed by xschem and returned as a list:
A[3:0]
-->
A[3],A[2],A[1],A[0]
that is easier to manage when writing the final netlist.
t
@Stefan Schippers: One more question: To generate the netlist from within the program, I'm running xschem with python "subprocess". To get it to write the netlist of the DUT with the subcircuit wrapper around it, I'm using:
Copy code
xschem -n -r -q --tcl "xschem set format lvs_format" -o <path> -N <file> <schematic>
I am unable to get the subcircuit wrapper in the output to be uncommented. I used to have
--tcl "set top_subckt 1"
but I'm not sure where that came from or if it was ever tested. The
xschem set format lvs_format
comes from the callback function used by the menu item selection, which always works. What am I doing wrong?
s
Copy code
xschem -n -s -r -x -q --tcl "set lvs_netlist 1" -o <path> -N <file> <schematic>
I have added -x (do not connect to the Xserver, no windows avoiding a potential flash on the screen, (open/close window ) and also -s to force spice netlist (just in case the default was changed in xschemrc) The
xschem set format lvs_format
is executed if
lvs_netlist
is set to
1
. This will force xschem to use
lvs_format
attribute (if existing) as netlisting rule for the device instead of the default
format
. This allows to differentiate netlist for simulation and for LVS check. By the way if setting
lvs_netlist 1
on cmdline the xschem initialization code did not execute the
xschem set format lvs_format
, so you discovered a bug (but the command line above works for you). So thank you!.
t
@Stefan Schippers: Perfect, works great! I had some issue previously with using
-x
which probably had to do with the rest of the options I was using. But the command line above does everything that I want it to.
Sometimes I am able to take a few minutes out of my busy schedule of tracking down bugs in my own tools, to find a bug in somebody else's tool. . .
s
If you find cases where the -x on command line causes problems (there were cases in the past and they are fixed) for uses where GUI is not needed (like extracting a netlist) let me know.