Vesta comes with the qflow package. Here we try to do a stand alone vesta installation, as it's very simple to do:

In dir where you have qflow downloaded, do this:

cd qflow-1.3.13/src

vesta.c, hash.c and hash.h are the 3 files used to generate binary vesta.

Copy these files + Makefile in some temporary dir, and generate vesta binary over there, so as to not mess the original qflow dir.

mkdir vesta_temp; cd vesta_temp; cp vesta.c, hash.c, hash.h, Makefile

Run Makefile in this dir to generate executable =>

make vesta

It runs this rule:

vesta$(EXEEXT): vesta.o $(HASHLIB)
$(CC) $(LDFLAGS) vesta.o $(HASHLIB) -o $@ $(LIBS)

These are the cmds seen on screen =>

cc -g -O2 -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DTCLSH_PATH=\"/usr/local/bin/tclsh\" -DQFLOW_MAGIC_PATH=\"/usr/local/bin/magic\" -DQFLOW_NETGEN_PATH=\"/usr/local/bin/netgen\" -DQFLOW_QROUTER_PATH=\"/usr/local/bin/qrouter\" -DQFLOW_GRAYWOLF_PATH=\"/usr/local/bin/graywolf\" -DQFLOW_YOSYS_PATH=\"/usr/local/bin/yosys\" -DQFLOW_OPENTIMER_PATH=\"\" -DQFLOW_OPENSTA_PATH=\"\" -DQFLOW_VERSION=\"1.3\" -DQFLOW_REVISION=\"13\" -c vesta.c -o vesta.o

cc -g -O2  -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DTCLSH_PATH=\"/usr/local/bin/tclsh\" -DQFLOW_MAGIC_PATH=\"/usr/local/bin/magic\" -DQFLOW_NETGEN_PATH=\"/usr/local/bin/netgen\" -DQFLOW_QROUTER_PATH=\"/usr/local/bin/qrouter\" -DQFLOW_GRAYWOLF_PATH=\"/usr/local/bin/graywolf\" -DQFLOW_YOSYS_PATH=\"/usr/local/bin/yosys\" -DQFLOW_OPENTIMER_PATH=\"\" -DQFLOW_OPENSTA_PATH=\"\" -DQFLOW_VERSION=\"1.3\" -DQFLOW_REVISION=\"13\" -c hash.c -o hash.o

cc vesta.o hash.o -o vesta

Or run this single cmd: cc -g -O2 hash.c vesta.c -o vesta => this will generate vesta executable

NOTE: for some reason, compilation shows error with this line when run as single cmd above (one of the defines -D is required):

vesta.c: In function ‘main’:
vesta.c:3795:31: error: expected ‘)’ before ‘QFLOW_VERSION’
  fprintf(stdout, "for qflow " QFLOW_VERSION "." QFLOW_REVISION "\n");
                               ^

Just comment out this line and compilation goes fine => //fprintf(stdout, "for qflow " QFLOW_VERSION "." QFLOW_REVISION "\n");

Now run vesta providing liberty file and netlist

./vesta map9v3.rtlnopwr.v /usr/local/share/qflow/tech/osu035/osu035_stdcells.lib => verilog netlist is the one generated by qflow after synthesis/PnR stage.

vesta.c:

main routine:

1. process cmd line arguments

2. Read liberty file => libertyRead(flib, &tables, &cells);

    liberty file table values get stored in linked list "tables" (struct lutable) and "cells" (struct cells)

3. Read verilog netlist => verilogRead(fsrc, cells, &netlist, &instlist, &inputlist, &outputlist, Nethash);

  • Parse thru verilog netlist. Look for module/endmodule keywords for start or end of module.
  • Then look for i/p, o/p pins and assign those i/o nets to inputlist (struct connect) and output list (struct connect).
  • Then parser parses lines like this "CLKBUF CLKBUF_1 ( .A(clock), .Y(clock_buf4) );" Here CLKBUF is instance definition, and CLKBUF_1 is instance name. Both are parsed and instlist (struct instance) is created for CLKBUF_1, whose reference inst is CLKBUF. Then pin names A,Y are parsed and "struct connect" is created for each pin, here for "clock" with direction as i/p pin, and for "clock_buf4" with direction as o/p pin. netlist (struct net) is created for the nets connecting to these pins.

4. create internal links => createLinks(netlist, instlist, inputlist, outputlist);

5. Report on max delay paths

6. Report on min delay paths

5. Report on max delay paths

6. Report on min delay paths

 

 

DFT: Design for Testatbility

Any chip that is fabricated is going to have some defects during fabrication, which will cause some of the transistors or wires on the chip to not function properly. This may cause the chip to fail. One way to check if the chip manufactured is good or not, is to run thru the same functional patterns on the chip pins that the chip is going to go thru when it's in operation.

For small chips this method may work, but for large chips, it's practically not feasible for 2 reasons. First, there may be billions of such possible patterns on chip pins that we may have to aplly, which is time prohibitive. Secondly, it may still not find out all bad devices or bad connections in chip, since those patterns may not target 100% of the chip devices.

Without having 100% check to test each and every transistor and each and every connection, we can never be sure if the chip being shipped is 100% functional or not. This is where DFT comes. DFT simply means adding extra logic on chip so as to allow us to test the whole chip. DFT is a broad field by itself, an you will usually see thousands of job postings just for DFT engineers.

In this section, we will go thru the basics of DFT,

IEEE 1500:

IEEE 1500 defines a standard for test access of cores within a big chip. For small designs, we just do connections at top level, and pass on signals from 1 module to other. But for big designs, it can get very complex. For such designs, we treat each block as a chip in itself, having it's own controller for dft purpose, which handles all internal details of dft. Then, at top level we justhave a top level 1500 controller, which connects and controls these block level 1500 controllers. All connections are controlled via JTAG pins. These pins go into top level TAP controller, which processes and passes all the appr signals to each block.

We define standard port interface for IEEE 1500, to connect different blocks. Most signals are prefixed with W which stands for wrapper. WIR = wrapper instruction reg, while DR = data reg (WDR or wrapper data reg name not used for whatever reason). These IO signals are:

WRCK/WRCLK = Clock. This is actually connected to chip JTAG pin TCK.

WRSTN = Reset (active low). This resets all reg in WIR to 0, indicating func mod. This is actually connected to chip JTAG pin TRSTN.

SHIFTWR/SHIFTDR = Shift WIR or DR. With this signal high, Shift reg gets connected b/w WSI and WSO and starts getting values shifted in/out

UPDATEWR/UPDATEDR = Update WIR or DR. With this signal high, Update reg gets updated with values in shift reg.  These signals coming out of Update reg thenget stored in bunch of internal reg, which control all test related stuff in Func logic (i.e bist control signals, bypass, etc)

SELECTWIR = Operate on WIR. (we can have multiple SELECTWIR1, SELECTWIR2, etc if we have multiple partions within WIR, which we want to activate separately)

WSI / WSO Scan In/Out Data. These are single bit line for scanning data in and out of IR/DR. These are connected to chip JTAG pin TDI/TDO via daisy chain. First block's WSI comes from top TAP controller, which in ultimately connected to TDI pin, WSO pin connects to next block WSI pin, and so on. Last block's WSO pin goes to top TAP controller, which finally connects to chip TDO pin. The i/p pin WSI is captured on +ve clk edge, while o/p pin WSO is fired on -ve clk edge. This follows the same convention as for all other pins of JTAG which are fired on -ve edge, but captured on +ve edge of clk.

WPI /WPO Parallel In/Out Data. These are multi bit bus, and used for scanning data in and out of functional flops (i.e scan chain stitching of functional flops). These are same as SDI (scan Data in) and SDO (scan data out) pins that are used in designs for scan data in/out. The reason, we have a bus is to have mutiple chains of scan in/out for big designs (since they may have millions of flops, and shifting data in/out via just one pin is going to take hours). WPI/WPO are captured/fired on same clk edge as WSI/WSO.

 

See diagram.

Top level TAP:

We specify special JTAG inst to control the above signals at block level. We can define as many JTAG inst as needed to have control over various 1500 controllers in the design. We can have JTAG instructions for selecting specific 1500 controllers at block level ,

J1500I = JTAG 1500 inst for Inst Reg. This gets SELECTWIR signal high, and SHIFTWR or UPDATEWR signal high

J1500D = JTAG 1500 inst for Data Reg. This gets SELECTWIR signal low, and SHIFTDR or UPDATEDR signal high

Once you have all the pieces ready, we will download, qflow:

Head over to this link: http://opencircuitdesign.com/qflow/index.html

Download latest stable version that is under stable download link. I downloaded "qflow-1.3.13.tgz" (which was the latest version with release date of Mar 19, 2019). Extract it in a dir named "qflow-1.3.13". In this dir, we see a README file, which has all instructions for installing it:

cd qflow-1.3.13 => Now run below 3 cmds in this dir

1. ./configure => This will look for all tools that qflow needs. It shows configuration results at end.

Using yosys verilog synthesis tool at: /usr/local/bin/yosys
Using graywolf placement tool at: /usr/local/bin/graywolf
Using qrouter detail route tool at: /usr/local/bin/qrouter
Using Magic layout tool at: /usr/local/bin/magic
Using Netgen LVS tool at: /usr/local/bin/netgen
Using Vesta STA tool (internal)
Using Vesta STA tool (internal)

If some thing not found in std path, it will show warning: WARNING: Netgen LVS tool not found.  Use --with-netgen=<DIR>. We will need to fix this by downloading/installing that tool and specifying an alternate path for that tool (if it exists in some other dir).


2. make => make is run. Last 2 lines indicating successful compilation are:

make[2]: Leaving directory `/home/proj/qflow-1.3.13/tech/gscl45nm'
make[1]: Leaving directory `/home/proj/qflow-1.3.13/tech'

3. sudo make install => This puts qflow executable in correct dir. It shows same last 2 lines as in "make" step above.

/usr/local/bin/qflow => qflow script put here

/usr/local/share/qflow/* => all qflow related scripts, etc put here

Run "which qflow" to make sure it shows "/usr/local/bin/qflow" as the path. Type "qflow" on cmdline, and it should show you a help menu.

Project:

Now, we will setup a "experiment" dir where we will get a small project going.

mkdir test_ex1
cd test_ex1
emacs map9v3.v => this creates a new blank file called map93v3.v. This small file is on tutorials link on qflow page. Copy contents from there to this file.
qflow map9v3 => run qflow on this module named "map9v3". Note we do not provide the name of verilog file, but just the name of top level module. Then it will look for module named "map9v3", which it will find in file named map9v3.v. Screen shows this o/p:

--------------------------------
Qflow project setup
--------------------------------

No technology specified or found;  using default technology osu035

No actions specified on command line;
creating qflow script file /home/kailash/Project/test_ex1/qflow_exec.sh only.
Uncomment lines in this file and source the file to run the flow.

The flow created a csh file called qflow_exec.sh file, which is very simple wrapper for calling individual steps in the flow. All of these asteps re commented. We can uncomment lines 1 at a time, and run the script, or copy cmds from this cript, and run that cmd directly on the shell. All output files are generated in same dir. These are the steps, running them 1 by 1:

1. Synthesis => runs synthesis using Yosys and generates verilog gate netlist map9v3.rtlnopwr.v, map9v3.rtl.v, and bunch of other files.

/usr/local/share/qflow/scripts/synthesize.sh /home/Project/test_ex1 map9v3 /home/Project/test_ex1/map9v3.v || exit 1

2. Placement => runs placement using graywolf

/usr/local/share/qflow/scripts/placement.sh -d /home/Project/test_ex1 map9v3 || exit 1

3. Timing => runs timing using vesta. This is initial timing run on placed design (with no routing info)

/usr/local/share/qflow/scripts/vesta.sh  /home/Project/test_ex1 map9v3 || exit 1

4. Routing => runs detailed routing using qrouter

/usr/local/share/qflow/scripts/router.sh /home/Project/test_ex1 map9v3 || exit 1

5. Timing => runs timing using vesta. This is final timing run on routed design (with all wire delays included)

/usr/local/share/qflow/scripts/vesta.sh  -d /home/Project/test_ex1 map9v3 || exit 1

6. Migrate => runs magic to generate final layout

/usr/local/share/qflow/scripts/migrate.sh /home/Project/test_ex1 map9v3 || exit 1

7. DRC => runs drc using magic on final
/usr/local/share/qflow/scripts/drc.sh /home/Project/test_ex1 map9v3 || exit 1

8. LVS => run lvs using netgen
/usr/local/share/qflow/scripts/lvs.sh /home/Project/test_ex1 map9v3 || exit 1

9. GDS => run magic to generate gds
# /usr/local/share/qflow/scripts/gdsii.sh /home/Project/test_ex1 map9v3 || exit 1

10. cleanup => cleanup script to remove un-needed files
/usr/local/share/qflow/scripts/cleanup.sh /home/Project/test_ex1 map9v3 || exit 1

11. display => display final layout in gds using magic
 /usr/local/share/qflow/scripts/display.sh /home/Project/test_ex1 map9v3 || exit 1

 


Cadence IMC tool info:
---------------------------
IMC = Incisive Metrics Center. It is metrics anlysis tool for coverage (code, FSM and functional) analysis. It can analyze data generated from ICC (Incisive Comprehensive coverage) which is generated when irun is run with -coverage. Coverage file is generated in test_name/coverage/tests/*.ucd and *.ucm file

3 kinds of coverage:
1. Code coverage: consists of block, expresssion and toggle coverage
2. FSM coverage: coverage of all possible states and transitions in state machine.
3. Functional coverage: generated by inserting PSL, SystemVerilog assertions, or SystemVerilog covergroup statements into the code and simulating the design.

IMC reads metrics data from run dir which has all coverage database from single run. By default, metrics data is stored in:
cov_work/scope/*.ucm => model file. 8 digit hex is the checksum of design hier and code coverage metrics
cov_work/scope/test/*.ucd => data file. 8 digit hex is the checksum of design hier and func coverage metrics

By using option "irun -covworkdir coverage -covdesign tests -covtest <TEST1>", we set cov_work=coverage, scope=tests, test=TEST1. So, final coverage results stored in this dir:
coverage/tests/*.ucm
coverage/tests/TEST1/*.ucd

If we have multiple tests, we need to merge coverage results of all tests. To do this we run imc
imc -15.10-incisiv -batch -init imc_merge => -batch starts imc in cmd line interactive mode (otherwise it starts in gui mode)
imc_merge has these 2 lines:
merge test_*/coverage/tests/* -overwrite -out result
exit

This takes coverage results for all tests from "test_*/coverage/tests/*.ucm and <test_name>/*.ucd" and puts results in "cov_work/scope/result/*.ucm, *.ucd" (as specified in -out dir specified above).

Then run imc with the same version to look at coverage results:
imc -15.10-incisiv

imc window:
----------
on imc window, look in module interested in, and see "overall covered" results. This needs to be 100%. It's divided under 3 coverage: Code coverage (Block, Expression, Toggle), FSM coverage and Functional coverage.

Code coverage:
-------------
Block coverage:
Expresssion coverage:
Toggle coverage:

Expression coverage:
------
It shows terms T1, T2, etc. It looks for all possible 0/1 values of T1,T2,etc to see if everything is covered. tool should have entered that line in sim, by exercising whatever cond is needed to get there.
ex: state <= sel ? STATE1 : STATE0; It shows T1=sel, T2=STATE1, T3=STATE0. It looks for 8 possible combo of T1,T2,T3 from 000 to 111. If it says, it's looking for term T2=1, it means it's looking for STATE1 values of 0 and 1. STATE1 might be encoded as 001 => STATE1 is always 1. If STATE0 is encoded as 000 => STATE0 is always 0. Tool is smart to figure out that STATE1 can never be 0 and STATE0 can never be 1. So, it will automatically exclude these cond (shows as red with white line in b/w, reads "exclusion rule type = simulation time)

Exclusions:
-----------
We can apply exclude to whole block by clicking "Exclude" button on top after selecting amodule (shows up as red dot on LHS of that block).
We can save exclusions in *.vRefine file by clicking on Analysis->Save Refine. Then we can load it back when opening new session of imc. That way we won't have to type exclusions again.

Exclusions rule types can be 2 types:
1. Analysis time:
2. simulation time:

--------------
Vmanager:
-------------

vmanager is verification tool suite. It used to be emanager, but now it's all combined as vmanager.

It lets automate the process of verification planning, regression, collecting results and displaying them in tabular format. Vmanager provides capability to launch IMC from vPlan window for detailed coverage reports

emanager:
--------
regresssion:
--------
To run regression, do this:
emanager & => once emanager is up, click setup, then start and then open one of *.vsif file that has regression script in it. On clciking ok, it starts regression. It will show the session window that shows tests run (and how many pass, fail, run, wait, timeout(or dropped from lsf queue)

top vsif file to run is veridian_regress.vsif. It has parameters and calls another vsif file which has list of tests.

veridian_regress.vsif:
----------------
session veridian_regression {
   top_dir: $ENV(MY_REGRESSION_AREA)/top_dir; => dir to run sims
   master_submission_policy : execute_locally;
   drm    : lsf;
   default_dispatch_parameters: <text>-q regress -We 00:30 -R "select[ws60 && CCASE && mem>2000]" -o /dev/null -e /dev/null -u /dev/null</text>; => lsf parameters
   max_runs_in_parallel     : 1000;
   queuing_policy : round_robin;
};

group smoke { //there can be multiple groups with each group having separate tests to run
   runs_dispatch_parameters:<text>-q regress -We 04:00 -R "select[ws60 && CCASE && mem>2000]"  -o /dev/null -e /dev/null -u /dev/null </text>;
   sve_name : "$ENV(DVWORK)/software/rtl_sim/regress.sve";
   run_script: "$ENV(DVWORK)/software/rtl_sim/run_regress.csh"; => calls this run script which has irun cmd
   scan_script: "vm_scan.pl `vm_root -home`/bin/ius.flt `vm_root -home`/bin/uvm.flt"; //this is scan script that scans for errors  (*E) in log files, and reports them. provided by cadence. To have your own filtering for errors, provide your own filter file, i.e custom.flt which has these lines:
                add_filter ("error", 5, "ERROR:",failure(1,"ICS", "FAILED", "FAILED", "$ENV{BRUN_TEST_NAME} FAILED due to 'ERROR' in logs")); //This si to filter out ERROR from log file
   sv_seed: gen_random; //use random seed for svseed parameter on irun
   timeout : 200000; //timeout a test after 200K sec
   count : 1;
   #include "veridian_tests.vsif" => has a lit of tests (doesn't need to be vsif file). #include is needed (C pgm syntax for including files)
};
-----------------
Above file calls "run_regress.csh" which is the run script which has irun cmd. This script has "$BRUN_TEST_NAME" in place of testcase name in irun cmd line, so that test names get picked up from *_tests.vsif file
It also has include file for other vsif file which has list of tests with args:
veridian_tests.vsif:
------
test efuse_t1 { count: 5 }; => test to be run 5 times with 5 random seed (and no additional args)
test efuse_jtag {
     sim_args : ahb_bfm;
     test_dir : efuse;
     test_def : DISABLE_DAP_SW_BFM;
};
test pwr_smoke {
     sim_args : ahb_bfm;
     test_dir : pwr_if;
};
#include "veridian_other_tests.vsif" => can include other vsif files too
---------------

top vsif file is called by emanager and starts running regression. It saves results in *.vsof file, which can be loaded later to see the results of regression. This is helpful when we want to reopen the window later.

#to run regression from cmd line, do this:
emanager -c "start_session -vsif /vobs/../veridian_regress.vsif

--------
vPlan:
-------
To create/update vplan, click on vPlan icon (right before Config icon). That will bring new vPlan window.
To create new vplan, click on "New", while to read existing vPlan click on "Read".
vplan file looks like xml file. It is easy to read it in emanager, but difficult to read text.

For new vPlan, on the new window, edit Plan name on vplan editor on left to something meaningful like "refsys dv". Then goto specs on right, and "add a spec". As as many spec files (im pdf) that you want. Highlight the section, that you want to be added, right click and choose "New section (sibling or child=> child will create sub section within that test, i.e 1.1->1.1.1)". Put a name, and then it shows that item on vplan editor on left.  Now if you click on "Plan" (by side of spec), then it shows attributes for each testcase that you added (if you click on that testcase). You can add "implementation notes" here to show what the testcase does. Once done, save file by going to File->Save as "refsys.vPlan".

---------------
 

verilog-A & verilog-AMS:
-------------------------
both these languages don't support synthesis. They are used for simulation only to verify complex blocks.

Verilog-A:  
--------
In face of competition from VHDL (an IEEE standard), which was absorbing analog capability from other languages (e.g. MAST) and evolving into VHDL-AMS, OVI agreed to support standardization of spectre behavioral language to add analog capability to verilog. However, OVI wanted to create Verilog-AMS \ a single language covering both analog and digital design. Verilog-A was an all-analog subset of Verilog-AMS that was the first phase of the project.

Verilog-A standard does not exist stand-alone - it is part of the complete Verilog-AMS standard. It is the continuous-time subset of Verilog-AMS. Spectre/TI-spice runs verilog-A, while ncsim runs verilog. Then results are combined. At top level, ncsim (or irun) is run on combined netlist. spectre is called as needed.

Verilog AMS:
-----------
Verilog analog and mixed signal (V-AMS) is a derivative of Verilog which extends event based simulator loops of digital simulation(V/SV/VHDL) by continuous time simulator. So, can simulate analog, digital and mixed ckt. It's a superset of digital Verilog HDL. It combines both Verilog and verilog-A, and then adds additional capability to allow description of mixed signal components.

The original intention of the Verilog-AMS committee was a single language for both analog and digital design, however due to delays in the merger process it remains at Accellera while Verilog evolved into SystemVerilog and went to the IEEE. Final plan is to pass accellera VAMS std to IEEE.

Verilog/AMS is a superset of the Verilog digital HDL, so all statements in digital domain work as in Verilog (see there for examples). We add electrical, analog, contribution (<+) as extra keywords in Verilog-A. Rest all syntax remains same as digital verilog.

NOTE:
1. Any module can have as many digital process, but only ONE analog process.
2. VerilogA can't have any digital signals (we can still have real/integer var). Every signal has to be analog. That's why we switch to Verilog-AMS since it allows us to use digital or analog for any i/p, o/p or internal signals.
3. cross, transition and bound_step are most needed functions to model in verilogA.
4. In irun, digital verilog only supports verilog 2001 or before. It can't support "always @*", nor any SV constructs as "#2ms". This is a limitation of irun. So, any vams file shouldn't have any newer verilog code.

Extra keywords added in Verilog-A:
--------------------------------

disciplines:
------------
Verilog AMS supports multiple disciplines. A discipline is a collection of related physical signal types, which in Verilog-A/MS are referred to as natures. For example, the electrical discipline consists of voltages and currents, where both voltage and current are natures. Verilog-A/MS by itself defines only one discipline, the empty discipline, and it defines no natures. Thus, in order for the language to be able to describe models that operate on physical signals, the disciplines and natures associated with those signals must be defined. A collection of common disciplines and natures are defined in a file disciplines.vams that is provided with all implementations of Verilog-A/MS.

natures: specifies attributes of signal type
------
nature Voltage
  abstol = 1u; //absolute tolerance in real number
  units = "V";
  access = V; //access function name that we use in verilogA to get voltage of a node. Note capital V used, so using small v to get voltage of a node won't work
endnature

nature Current
  abstol = 1p; //absolute tolerance in real number
  units = "A";
  access = I; //access function name that we use in verilogA to get current b/w 2 nodes
endnature

disciplines: combines 2 natures to define potential/flow pair. One gives type for potential(voltage) while other for flow(current)
--------
discipline electrical
 potential Voltage;
 flow Current;
enddiscipline

discipline voltage //we use separate voltage discipline where currents are not needed. saves computation time
 potential Voltage;
enddiscipline

ex:
electrical in; //in can take both voltage and current value
voltage out;  //out can take only voltage value but not current. electrical and voltage ports can be connected directly.

mixed signal behaviour can be modeled from models which are built from purely digital and analog blocks, and these models can be freely interconnected with VAMS automatically performing the signal conversion.
discipline are not part of verilog, but were introduced in verilog-A for cont time signals. VAMS extended this concept to digital signals also, but disciplines were made optional for these discrete time signals by having default discrete time discipline as "logic", which is defined in discipline.vams.

discipline logic
  domain discrete;
enddiscipline

NOTE: logic in VAMS is diff than one in SV. It just says that these signals are not electrical, but digital 0/1.

VrilogA vs VerilogAMS: Since i/p, o/p signals in VerilogA can only be electrical, modeling digital signals in Verilog-A is difficult (see ex of nand gate on pg 71 of Designer's guide notes). Use Verilog-AMS instead. In verilogAMS, we can write digital code within analog block, so it's much easier to model digital signals.

probe: to probe voltage or current. If branch is empty, current probe shorts the branch, while voltage probe causes open ckt.  
---
These below stmt don't need to be in "analog block". They can be anywhere (i.e in digital always too) in vams file.
real x; x=V(a,b); //x gets voltage b/w a and b
real x; x=I(a);   //x gets current b/w a and ground. Everything is referenced in any schematic wrt ground. So, we need to have a ground node or else everything is floating. We provide gnd! on one node, then all nodes are solved wrt this node. If we do not provide gnd node, then tool can't solve as there will be infinite soln for node voltages. (i.e tool can choose gnd node at 1V, 2V, etc and all other node voltages will change based on that). ground node is provided as follows:

electrical gnd;
ground gnd;
 
$cds_iprobe => to probe volt/cur at any node. Can be used only inside "analog block"
real x; x=$cds_iprobe("TB.I0.net1); => this puts a current probe and continuously assigns value on net1 to var x.

NOTE: all signals in regular schematics of transistors are electrical (since transistors are verilogA models with electrical input/output). So, we can probe any of these signals same way as we can probe any signal in Verilog-A.

Simvision:
--------
1. A/D signals: On simvision gui, the way to know if a signal is digital or analog is to look at signal icon whenever we see at signal list to choose. If it shows a pulse type, it's digital, while if it shows sine wave, it' analog. If we see *_$flow as signal name, it represents a current for that signal as opposed to voltage.
NOTE: If a signal comes from srcVerilogAMS model, it's digital (0/1), while if it comes from schematic, it's analog (V/I). If a digital goes into analog or vice versa, D2A or A2D connect modules are placed. Depending on whether they are placed on o/p pin of 1st gate or i/p pin of next gate, the signal may show up as an analog or digital signal in waveform viewer. Only when both 1st and 2nd logic are both analog or both digital, only then the signal will show up as only analog or only digital. At interfaces of analog and digital, tool tries to keep digital signals as much as possible to save on sim time.

2. timestep: To know the timestep for analog signals, we can display any anlog signal on waveform. Then right click on signal value (where it shows the voltage/current number). then click on symbol->Points & Lines. Then click on triangle or plus, and it will show the all the points where analog values were calculated. This is a good way to see how tool is working with analog signals.


AMS simulator: see "running AMS" section in cadence_virtuoso.txt
-------------
See also in simulation.txt for probe of ams signals.

type:
----
We have signals as electrical/voltage type, and variables as integer/real type.
ex: real [3:0] vout;
reg [5:0] gain; real vgain; vgain = pow(10.0,(gain-32.0)/20); //here if we use integer 32 instead of real 32.0, then we get convergence error during sim complaining it's NaN. This happens because result of operations on unsigned registers/nets is unsigned. Here gain is unsigned, so when gain=0, then gain-32=-32 which is 0+(-32)=32'b0+32'b111...11100000=32'b111...11100000. However, since the result is supposed to be unsigned, this result is treated as unsigned number. Then this unsignned number represents 2^32-32=4294967296-32=4294967264. This is a huge +ve number which causes vgain to be infinite, and hence convergence issues. Use real as one of the inputs, which makes the result real, which is signed. Another soln is to assign reg "gain" to integer which is signed by defn, and then perform "-" which gives signed result.

wreal: wire with real value on it. This is useful as it can be used in digital block instead of using analog block
ex:
wreal out; real result;
assign out=result; => usually real number can be assigned to out in analog module (analog V(out) <+ result;)

wire porz; wreal VDD;
assign #10 porz = (VDD > 1.2) ? 1'b1 : 1'b0; => This converts from real to signal. very useful

expressions:
----------
1. If else: A ? cond1 : cond2; if (V(in) > 0) V(sw) <+ 0; else I(sw) <+0;
2. case: case (a) 0:.. 1:... endcase
3. for: for(i=0;i<=10;i=i+1) begin ... end
4. while: while(i<bits) begin ... end

Events: they force simulator to place time points at events, else simulator may miss that time point, and results may vary from run to un.
-----
@blocks : blocks of code executed upon an event. These are non-blocking so other smt can proceed.
analog begin
 @(initial_step or final_step) begin //simulator places time point at initial step and final step, and assigns hold to V(in) at that time
   hold=V(in); //since hold is variable, it retains it's value over time. So, initial value of hold is retained until the end.
   V(a,b) <+ 5; //since V(a,b) is electrical and assigned using <+, it is evaluated only at initial or final step. At other times, it's not evaluated, so, it's X or floating.So, <+ operator should not be used within event (@).
 end
 @(timer(Tstart,T)) //creates events every t=Tstart+kT, where k=0,1,2,..
 
 @cross(V(in),+1) //places event when V(in) is rising (-1 for falling, 0 for either) just after the crossing within tolerances. NOTE: V(in) needs to go from -ve to +ve for it to detect event. If V(in) goes from 0 to 1V, then cross never happens.
  ;               //It's placed simply to assure edges are not missed. Very imp to place it at start of every "analog" block.
end

always @above(V(in)-Vmax, 1n, 1m) $display("MAX exceeded"); //this looks for arg to be above 0 (V(in) >= Vmax) within 1mV tolerance, and a time delay of 1ns. NOTE: this is not within an "analog begin end" block, but is an always block as if in digital. This works !!

transition filter: converts piecewise constant signal to PWL signal. Can only be applied to piecewise constant and NOT to continuous signals.
-----------------
Out = transition(In, td, tt); //adds td delay to "In" signal with rise/fall time of tt. If different rise/fall desired, then ad 4th arg, i.e:
Out = transition(In, td, tr, tf); //NOTE: out is a "real" variable, and not a signal. IN shouldn't vary continuously, i.e it should be any voltage/current in analog domain
V(mid) <+ transition(en, 1n, 10n)*V(vdd); //causes "en" to rise/fall with 10ns time, delay of 1ns and goes from rail to rail. This stmt converted a digital signal (en) to analog signal (mid). NOTE: <+ is needed, since this needs to be evaluated continuously. So, needs to be in "analog begin .. end" block.

NOTE: transition stmt is used to ramp up power supplies:
ex:
real vsys_r =0;
electrical out;
initial begin
  #0   vsys_r = 0;
  #100 vsys_r = 1.8;
  #100 vsys_r = 1.2;
end

analog begin
   V(out) <+ transition(vsys_r, 10u, 1u);
end

contribution:
-------------
In analog domain, some new operators are defined, for example the "<+" branch contribution operator. It's called contribution operator, because it keeps on adding contributions.
For ex: A <+ 1; A <+ 2; will assign final value of 1+2=3 to A. A simple assign would have assigned value of 2 to A.
A contribution statement takes the form of a branch signal on the left side of a contribution operator, e<+f, followed by an expression on the right side. The branch signal on the left side is forced to be equal to the value of the expression at all times. So, it's different than other languages in the sense that it solcves differential eqn to arrive at a soln that satisifies this. So can be time intensive.

1. Ex of Resistor: V=I*R: model below models a liner resistor
-----------
`include gdisciplines.vamsh // It defines names V and I which are used in the model below.
module resistor (p, n);
  parameter real r=0; // resistance (Ohms)
  inout p, n; //port dirn is bidir (ports are optional as they aren't used in verilog-a/spice simulation)
  electrical p, n; //type of port is electrical (electrical is a discipline), meaning signals associated with the ports are expected to be voltage and current.
  //branch (p,n) res; //optional to specify branch. This gives more concise code, as we can use V(res) instead of V(p,n) below.
    analog // analog says that it's an analog process, which describes continuous time behaviour (similar to always).
       V(p,n) <+ r * I(p,n); //contribution stmt that defines relationship b/w voltage across branch b/w "p and n ports" and current flowing thru the branch b/w "p and n ports".
       //I(p,n) <+ c*ddt(V(p,n)); => for cap (ddt=time derivative, idt=time integral of its arg)
       //V(p,n) <+ l*ddt(I(p,n)); => for ind (idt used for integral, not needed here)
    //for more than one stmt in anlog section, use "analog begin .... end" stmt.
endmodule

resistor #(.r(50)) Rload (out, gnd); //instantiates a 50 ohm resistor

-----------------------


2. Ex of inverter:
-----------------
include gdisciplines.vamsh
module inverter (q, a);
 output q;
 input a;
 wire a, q; // digital net type (declaration optional)
 logic a, q; //discipline for a,q default to "logic" when not defined. So, this stmt optional

 assign q = ~a; //cont assignment
endmodule

3. Ex of sinusoid wave:
-------------
module sinwave(out);
 output out; electrical out;
 parameter real freq,phase; //these can be set wherever this module is instantiated
 analog begin
   V(out) <+ sin(2*`M_PI*(freq*$abstime + phase/360)); //$abstime returns time in seconds.
   $bound_step(0.1/freq); //specifies max time step that can be taken. else simulator may choose very large timestep exactly at same point every cycle that will still satisfy above eqn. $bound_step is usually needed for indep src which produce repetitive o/p with no i/p. This specs 10 timesteps every sinusoid, enough to generate smooth curve. For 1MHz sinewave, we'll see 100ns timestep on ams simulation.log window. But tran time on log window will show results every couple of steps, so that every 5% of simtime we see tran time and other info. That has nothing to do with timestep. step size shows in last 2 columns.
 end
endmodule

NOTE: In verilog (digital), we can model a sinewave with real numbers, by inc time step in a for loop. see system_verilog.txt for ex.

4.  module instantiations: we do it in same way as in verilog. By default, nets are electrical.
--------------
module das_top(ind, in0, in1, out0, out1);
 logic ind; //specifies tha this is digital signal
 electrical in0, in1, out0, out1; //specifies tha these are analog signals.
  diffamp Idiff0 (in0, out0);
  diffamp Idiff1 (in0, out1);
endmodule

5. mux in verilog-AMS: note: digital signals are freely used inside analog block (unlike in verilog-A). so easier to model digital. Make sure events are synchronized b/w digital and analog, else edges might be missed, since analog and digital have different time steps.
-----------
module (in0,in1,out,sel);
 input in0,in1; electrical in0,in1; //analog signal, so electrical. nature "electrical" of signal is figured out automatically by tool, depending on who's driving it
 input sel; logic sel; ///digital signal, voltage levels for digital signals are still unknown here, but we don't need them
 output out; logic out; //digital signal, nature "logic" of signal is figured out automatically by tool, depending on who's driving it
 real gain; //this variable cab shared b/w analog and digital modules
 
 always begin //digital block
  gain = V(in0)*20; //since var gain is assigned value in digital, digital owns it and analog block may only read it, but not modify it. Note: electrical signals can be read into digital and assigned to int/real to be used
  @(vgain); //we need @ stmt or else this always block gets into infinite loop
 end

 always @(cross(V(in0,in1),+1) count = count+1; //digital block. analog cross function can be used in digital

 analog begin //analog block
  @(posedge sel or negedge sel) //we need separate posedge and negedge, else tool complains. In pure verilog, we could do @(sel), but not here. This is limitation of AMS-Designer tool
   ; //forces time step at edge of sel signal. Any digital signal from digital block can be read into analog block. We synchronize analog kernel to avoid missing edges. However if sel signal is not wire/reg, but integer/real, then we need to do it as in pg 121 of Designer's guide book
  V(out) <+ V(in0)*(transition(sel==0 ? 1 : 0),0,1n); //sel=0
  V(out) <+ V(in1)*(transition(sel==1 ? 1 : 0),0,1n); //sel=1
 end
endmodule

6. DAC in verilog-AMS:
--------------
`timescale 1s/1ps => we should give 1s as timescale in digital modules also, as analog blocks always use 1s as timescale, so both digital and analog will remain in sync. Very important to do this and use #delay carefully as they have 1sec as timescale
module dac(in, out,clk);
 input [5:0] in; //in can take digital codes from 0 to 63
 input clk;
 output out; //no need to define electrical or logic as tool figures it out
 real result;
 analog begin
  @(posedge clk)
   result = in/63; //result varies from 0 to 1
  V(out) <+ transition(result,0,10n); out varies from 0V to 1V
 end
endmodule

7. AND gate in verilog-AMS in TI library (AN210 srcVerilogAMS file)
-------------
`include "disciplines.vams"
module AN210 (  A , B , Y  , VDD, VSS); //NOTE 2 extra pins VDD and VSS added. There's also srcVerilog file which doesn't have these vdd/vss pins
  electrical VDD; electrical VSS;
  input(* integer supplySensitivity = "VDD" ; integer groundSensitivity = "VSS" ; *) A; //pins voltages are VDD/VSS for 1/0
  input(* integer supplySensitivity = "VDD" ; integer groundSensitivity = "VSS" ; *) B;
  output(* integer supplySensitivity = "VDD" ;integer groundSensitivity = "VSS" ; *) Y;
     
  and #0 TI_AND_PRIM0 ( Y , A , B ) ;
endmodule

8. analog switch in  verilog-AMS:
-----------
module sw_ana (vin, control, vout); //control connects vin to vout
 inout      vin, vout;
 electrical vin, vout; //analog
 input      control;
 logic      control; //digital (this should be digital (piecewise constant) else can't be used in transition filter below)

 parameter real Ron=1, Roff=10M; //parameters that can be changed from outside
 real rout; //local variable

 initial begin .. end //digital process
 always @(...) begin .. end //digital process

 analog begin
  Rout = Ron/Roff * pow(Ron/Roff, transition(control, td, tr, tf)); //log func implemented for contonuously varying resistance from on->off or off->on. Note: here it's = sign (not <+ sign). If control signal can be "high z" or "x", we can add internal signal that forces "control_int" to 0, whenever control is anything other than 1 by writing this code as separate digital process => always @(control) if (control == 1'b1) control_int=1'b1 else control_int=1'b0;
  //Rout = Roff + ((Ron - Roff) * transition(control, td, tr, tf)); //linear func instead of log func above. simplistic but not accurate in how switches work.
  I(vin, vout) <+ V(vin, vout) / Rout; //solves for V,I with resistor in between nodes vin and vout
 end
endmodule

9. Fuse model: fuse is a resistor with 2 pins: P, M (used in silverfox, since fuse needed vams model)
----------
module FUSE_WRAPPER(M, P);
inout M;
electrical M;
inout P;
electrical P;
localparam  real rblown = 700000 ;
localparam  real rfuse_initial = 50;
integer numCross;
real t1, t2;
localparam real iBlow = 35e-3 ;
real rfuse ;
integer status;

analog begin
  @(initial_step("tran"))  begin
                  numCross = 0;
                  t1 = 0 ;
                  t2 = 0 ;
                  $display("INSTANCE PATH :- %m");
                  rfuse = rfuse_initial;
                  $display("VALUE OF RFUSE IS %f",rfuse);
                  status = 0;
  end
  @(cross(I(P,M)-iBlow,1)) begin //rising edge of current
                  if (numCross == 0 && status == 0)  begin
                    numCross=numCross+1;
                    t1 = $abstime ;
                end
  end
  @(cross(I(P,M)-iBlow,-1)) begin //falling edge of current
                  if (numCross == 1 && status == 0)  begin
                    numCross=numCross+1;
                    t2 = $abstime ;
                end
  end              
  if (numCross == 2 && status == 0)  begin //check how long current remained high. If met time spec, then blow it.
                  if((t2 - t1) > 300e-9) begin // make 300ns per design team
                    rfuse = rblown ;
                    status = 1;
                    $display("IN INSTANCE PATH :- %m");
                    $display("PROGRAMMED :- %m");
                  end
  end
                
  V(P,M) <+ rfuse*I(P,M) ;   //rfuse_unprog=50ohms, rfuse_prog=700Kohms                          
                
end //analog end
endmodule


10. Write top level TB for design:
-------------------------------
A. Create top level schematic. Instantiate sdtimulus block, and DUT block and connect pins as needed.
B. Create verilogams view of stimulus block. Write code to Drive stimulus to DUT (DUT is schematic for SilverFox or some other top level chip block)
--
creating a verilogams view of stimulus providing block:

`include "constants.vams"
`include "disciplines.vams"

module TOP_stim (A, VDD_TX, VDD_RX, VIO_OUT, VSS, Y, Z); //VDD_* are supply to blocks inside DUT, while VIO_OUT is supply to IO pad of DUT.
 input VSS;
 input  (* integer supplySensitivity = "VIO_OUT" ; integer groundSensitivity = "VSS" ; *) A; //indicates pin voltages for i/p pin A
 output (* integer supplySensitivity = "VIO_OUT" ; integer groundSensitivity = "VSS" ; *) Y; //indicates pin voltages for 0/p pin Y
 output  Z; //output pins can also be w/o any SS.
 output VDD_TX, VDD_RX, VIO_OUT;

 electrical Z;
 electrical VDD_TX, VDD_RX, VIO_OUT, VSS; //all supplies defined as electrical

 parameter real Vtx=0.0, Vrx=3.3, Vio=1.8, I_PD1; //specified as parameters so that they can be modified from other testcase module.
 reg A, Y, Z;
 reg [7:0] data, etc;
 reg [255*8:0] sim_description; //to display test name on waveform viewer

 //instantiate other modules
 switch_ana (* integer library_binding="SILVERFOX_TOPSIMS"; *) reset_sw (dut.RST, RST_SW, dut.VIO); //this adds an additional connection b/w VIO and RST pin of DUT. This helps us drive VIO on RST pin by controlling RST_SW signal.

 //include testcase file which has digital initial process
 `include "/db/.../fuse_tc.vams"; //explained in separate section below

 //digital initial process
 initial begin
  $sdf_annotate(...); //for max/min

     Y=0; Vtx=0; //NOTE: reg Y is written as 0 instead of 1'b0. That's valid as verilog treats this as 32 bit decimal and uses lsb of "32'd0".
  #5 Y=1; Vtx=5.0;

 end

 //analog process (runs at every timestep)
 analog begin
  I_PD1 = $cds_irprobe("ams_TOP.DUT.PD[1]"); //This is convenient way so that current can be displayed anytime desired in testcase, by displaying this variable. Else we'll need to include it in irun cmd line to dump current at that level of hierarchy.

  //to ramp up power supply
  V(VDD_TX) <+ transition(Vtx, td, tr, tf); //since Vtx is real and piecewise constant, transition func works on it.

  //to display thermal shutdown event
  @cross(V(ams_top.TSD)-0.7,0) begin
   TSD_temp = $temperature-273; //records tsd temp
   //vrx = V(VDD_RX); //record supply voltage
   $display("TSD temp = %g", TSD_temp); //%g is is used to display real var (can also use %f, %r, %e")
  end

 end

endmodule

fuse_tc.vams:
---
real diff; //any new var defined here
initial begin
  SCK =0;
  #5 LED=0;
  #1_000_000;
  Vtx=2.2; //Vtx is changed so analog block in stim file above causes V(VDD_TX) to ramp down to 2.2V.

  force ams_TOP.nPUC = 1'b0;
  spi_read(...);
  diff = V(ams_TOP.SILVER.I1.SH_OUT1) - V(ams_TOP.SILVER.I1.SH_OUT2); //analog sigs can be accessed directly in this digital block
  $finish;
end

--------------------------