hugo-site/content/posts/2021/spice-monkey.md

6.5 KiB

title date draft toc images tags
Spice Monkey 💻🐒 2021-10-29T18:54:32+02:00 true false
spice
code
verification

Netlisting issues can be some of the more frustrating aspects of circuit design tool chains primarily because its it all text based and very old fashioned. The Cadence tools for example have various command-line utilities but documentation is underwhelming to say the least. Quite often though they are inevitable when combining different tools, design flows, or handling someone else's IP. In order to cope with the usual inconsistencies I rely on the scripts below to pre and post process SPICE netlists.

Port Order Reshuffling

The default netlister and spice simulators usually connects sub component terminals in terms of the order in which they are defined in the spice .SUBCKT definition. Conflict arises however since IP vendors on the other hand tend to sort the port order in someway in the spice netlist but the Cadence symbol/schematic definition will usually disregard this order causing connectivity issues later.

function getSortedOrder() {
  local SOURCE=""
  local SORTED=""
  read -a SOURCE <<< "$1"
  SORTED="${SOURCE[@]}"
  if [ -z "${SORTED//*\[*}" ] ; then
    SORTED=($(echo "${SOURCE[@]:2}" | tr " " "\n" | sed -r "s/\[([0-9]+)\]/ \1 /g" \
            | sort -k 1,1 -k2,2nr | sed -r "s/ ([0-9]+) /\[\1\]/g" ))
  else
    SORTED=($(echo "${SOURCE[@]:2}" | tr " " "\n" | sed -r "s/<([0-9]+)>/ \1 /g" \
            | sort -k 1,1 -k2,2nr | sed -r "s/ ([0-9]+) /<\1>/g" ))
  fi
  echo "${SOURCE[@]:0:2} ${SORTED[@]}"
}

Cadence tools will prefer alphabetical ordering. The bash script above will replicate this sorting behaviour if you pass it a .SUBCKT definition string. The purpose here is that when you are given a netlist from a vendor you can prepare an internal version that already sorts the ports alphabetically.

In order to do this in terms of editing a file however you can use the script below which is called as: updatePortOrder $CKT_NAME $FILE_NAME. This will look for the definition given a CKT_NAME in the spice file and create a new file CKT_NAME.cdl in the current directory.

function updatePortOrder() {
  local TARGET="$1"
  local CDL_FILE="$2"
  local PORTORDER="$(awk -v target="subckt ${TARGET} " -f "catch.awk" "$CDL_FILE")"
  local PORTREF=$(getSortedOrder "$PORTORDER")
  local SWPDELIMITER=""
  echo $TARGET
  if [ -z "${PORTREF//*\[*}" ] ; then SWPDELIMITER="TRUE" ; fi
  awk -v target="subckt ${TARGET} " -v release="$PORTREF" -v swpdelim="$SWPDELIMITER" \
      -f "release.awk" "$CDL_FILE" > "${TARGET}.cdl"
  [ ! -z "$(grep -m 1 "\[" "${TARGET}.cdl")" ] && [ ! -z "$(grep -m 1 "<" "${TARGET}.cdl")" ] \
      && echo "Error $CDL_FILE uses mixed delimiters"
}

The second script however relies on some awk-based spice parsing calls to properly find and replace the relevant sections in the netlist. catch.awk simple finds the SUBCKT statement relevant and prints it to stdout.

BEGIN{ hold = ""; IGNORECASE = 1 }
NF {
    if( $1 == "+" && hold != "")
      { for(i=2;i<=NF;i++) hold=hold " " $i }
    else if( hold != "") { print hold; hold=""; exit }
  };
$0 ~ target { hold = $0 };

Then release.awk helps to insert the definition back into the netlist with the option to swap out any delimiters in the port names.

BEGIN{output="";hold="";IGNORECASE=1};
NF{if($1!="+")hold=""}
$0~target{
  hold=$0
  n=split(release,ports," ")
  for(i=n;i>0;i--){
    if(swpdelim!=""){
      gsub("<","[",ports[i])
      gsub(">","]",ports[i])}
    output=ports[i]" "output}
  print output}
NF{if(hold=="")print $0}

Netlisting Environment:

;; spice.env
simStopList = '("auCdl")
simViewList = '("auCdl" "schematic")
auCdlDefNetlistProc = "ansCdlSubcktCall"
globalGndSig = ""
globalPowerSig = ""
shrinkFACTOR = 0
checkScale = "meter"
preserveDIO = 'nil
checkDIOAREA = 'nil
checkDIOPERI = 'nil
preserveCAP = 'nil
checkCAPVAL = 'nil
checkCAPAREA = 'nil
checkCAPPERI = 'nil
preserveRES = 'nil
checkRESVAL = 'nil
checkRESSIZE ='nil
resistorModel = ""
shortRES = 2000
simNetlistHier = 't
pinMAP = 'nil
displayPININFO = 't
checkLDD = 'nil
connects = ""
setEQUIV = ""
cdlSimViewList = '("auCdl" "schematic")
cdlSimStopList = '("auCdl")
simSimulator = "auCdl"
simRunDir = "$RUN_DIR"
hnlNetlistFileName = "$CELL.src.net"
simViewName = "$SCH_VIEW"
simCellName = "$CELL"
simLibName = "$LIBRARY"
incFILE = "$RUN_DIR/source.added"
auCdlNoForwardSlash = t
;; simrc
hnlSetBusDirectionDescending = 't
simVerilogGenerateSingleNetlistFile = 't
hnlVerilogPrintSpecparam = nil
simVerilogNetlistExplicit = 't
simPrintInhConnAttributes = t
hnlInhConnUseDefSigName = t
;; verilog.env
simLibName = "$LIBRARY"
simCellName = "$CELL"
simViewName = "$SCH_VIEW"
simSimulator = "verilog"
simNotIncremental = nil
simReNetlistAll = 't
simNetlistHier = t
simVerilogLaiLmsiNetlisting = 'nil
verilogSimViewList = '("behavioral" "functional" "system" "verilog" "schematic" "symbol")
simVerilogAutoNetlisting = 't
simVerilogTestFixtureFlag = 't
simVerilogTestFixtureTemplate = "All"
simVerilogNetlistExplicit = 't
hnlVerilogTermSyncUp = "mergeAll"
simVerilogFlattenBuses = 'nil
vtoolsUseUpperCaseFlag = 'nil
hnlVerilogCreatePM = 'nil
simVerilogTopLevelModuleName = "verilog_$CELL.top"
simHierarchyPrefix = "verilog_$CELL.top"
simNCVerilogHierPrefix = "verilog_$CELL:top"
verilogSimStopList = '("verilog" "symbol")
simVerilogPwrNetList = '("$PWRLIST")
simVerilogGndNetList = '("$GNDLIST")
vtoolsifForceReNetlisting = 'nil
simVerilogLibNames = '("$LIBLIST")
vlogifInternalTestFixtureFlag = 'nil
simVerilogBusJustificationStr = "U"
simVerilogTestFixtureTemplate = "All"
simVerilogDropPortRange = 't
simVerilogHandleUseLib = 'nil
simVerilogHandleAliasPort = 't
simVerilogPrintStimulusNameMappingTable = 'nil
simVerilogProcessNullPorts = 'nil
simVerilogIncrementalNetlistConfigList = 'nil
hnlVerilogNetlistStopCellImplicit = 'nil
simVerilogOverWriteSchTimeScale = 'nil
vlogifCompatibilityMode = "4.2"
simVerilogHandleSwitchRCData = 'nil
vlogifUseAssignsForAlias = 't
vlogifDeclareGlobalNetLocal = 'nil
vlogifSkipTimingInfo = 'nil
simVerilogEnableEscapeNameMapping = 'nil
simVerilogStopAfterCompilation = 't
simVerilogVhdlImport = 'nil
simVerilogTopCellCounter = 0
hnlSupportIterInst = 't
hnlNetlistFileName = "$CELL.v"
hnlSetBusDirectionDescending = 't
simVerilogGenerateSingleNetlistFile = 't
hnlVerilogPrintSpecparam = 'nil
simPrintInhConnAttributes = 't
hnlInhConnUseDefSigName = 't

Property Based Removal

hnlHonorLxRemoveDevice = 't
hnlUserShortCVList = list( list("analogLib" "res") list("tsmcN40" "rnpolywo")  )