Water and Food:

Water and Food are consumed by us, and are needed to keep the body alive. Water provides hydration to cells, while food provides important nutrients needed by the body's cells, which eventually provide energy to body.

Water and food (all food have some water content) are taken in by mouth. We smash and grind it up in the mouth. From the mouth, there's a pipe called esophagus which takes it to the stomach. The stomach mixes it all up with chemicals that start to dissolve it. Bile is added a little later to dissolve fats. The bile also gives the food mass its color brown.

Small/Large Intestine:

This mass of mixed solids and liquids moves through the intestines. Everything that can be broken down is broken down into individual molecules. The whole mass is now considered a liquid with larger solids suspended in it. Even though we drink 2-3 litres of water a day, saliva, gastric juice, bile, etc secreted to the this whole mass makes up like 9 litres of liquid. The individual molecules (good and bad) then are absorbed from the intestines into your bloodstream by actually “soaking” through the intestine wall and through the blood vessel walls waiting on the other side. Some of these molecules are chemically pushed or pulled across into the blood vessels. What is left in the intestines gets drier and drier as more and more water is pulled out and absorbed into the bloodstream.

Food needs to be broken up into smaller molecules. Water, on the other hand, is a very simple molecule, so our body doesn’t have to break it down into smaller, simpler molecules. As a matter of fact, water molecules are so small that they have no problem diffusing through the phospholipid bilayer that forms the cell membrane of human tissues. This cell membrane (presumably) consists of small channels or pores through which water or water-soluble substances can enter, meaning that water is directly absorbed through the epithelial cells that cover humans’ intestinal tract. Small intestine tract has villi which are finger like projections, which are made of epithelial cells. These epithelial cells have brush like border called microvilli, which further increase the surface area for absorption. In short, this means that the small intestine is responsible for the absorption of most of the water that we consume. 90% of the fluid is absorbed in small intestine, and only 10% in large intestine. Blood capillaries are inside the villi, so anything absorbed via these epithelial cells  is passed on to the blood, which carries to all the places in human body.

The kidneys are constantly monitoring the amount of water and other by products and waste products in the bloodstream, such as uric acid, and pull or push them into the urinary tract, to keep the concentration in the blood just right. This all collects in the bladder. It is a mixture of mostly excess, unneeded water and other chemicals such as ammonia. When the bladder is full, we urinate (called urine because of the uric acid).

Meanwhile, the soon-to-be stool keeps moving along and at different parts of the intestine, different molecules are absorbed. It is held in the end of the large intestine. When it is full, we defecate.

Water's Journey thru body:

 

Attributes:

Attributes are NOT part of SDC.

Every object in design has multiple attributes assigned such as name, power, size, etc. Each object has attr type and it's value. What attributes a particular object will have depends on it's class (class may be design, port, cell, pin, net , lib, lib_cell, lib_pin, and clock), i.e a "cell" class may have it's attribute types as name, size, pins, etc, while a net may have it's attribute types as name, driver, receiver, etc. Many attributes are provided by default on different cell types (called as application attr). We can also define our own attributes on any object (known as user-defined attr). user defined attr are usually not needed for simple tasks (as appl attr are enough for most purposes). These attributes are helpful to sort objects based on similar or differing attributes.

Attributes are not standardized, and Synopsys/Cadence have different attributes for their objects. Attributes vary across tools too (i.e Synthesis and Timing tools may not have same attribute on an object even though both tools are from same company). So, none of the cmds involving setting or getting attributes are SDC cmds. You have to look thru Cadence/Synopsys tool manuals. Since there are so many attr, both Synopsys/Cadence have dedicated manual for all attributes for each tool.You should download and keep this manual handy at all times, as you need to work with attr all the times. Searching for them on Cadence/Synopsys website is very time consuming.

  • PT has a dedicated manual "PT variables and attributes" which list all such attr for all objects. Look in cell_attributes, pin_attributes, port_attributes, net_attributes, clock_attributes, etc in the manual for most important attr. "man" cmd with "_attributes" appended to the object class name shows details of that attr (ex: man design_attributes => shows info about design attr).
  • Genus has a dedicated manual "Genus Attribute reference for Legacy" as well as "Genus Attribute reference for CUI" manuals.
    • Genus Legacy:
      • help cmds for attr:
        • get_attribute -h => list all valid object types as net, pin, cell, pin, port, design, lib*, memory*, etc
        • get_attribute -h <attribute_name> <object_type>' will give you more information. Both 'attribute_name' and 'object_type' support the wildcard ('*') character for non-hidden attributes 
          • ex: get_attribute -h * net => reports all attr names for object type "net", such as basename, driver, load
      • get_attribute: To retrieve the value of an attribute on an object, use the get_attribute cmd above with no "-h" option
        • get_attribute attr_name object => ex:
      • set_attribute: To change the setting of an attribute on an object, use the following command:
        • set_attribute attr_name attr_value objects => ex:
      • Attr common to all objects:
        • obj_type <name_of_obj> => This returns the obj type of any object
        • name <name_of_obj> => returns obj name which is useful in get_db/set_db cmds
      • Attr for specific objects:
        • Pin: get_attribute capacitance [find /des*/design -port *] => find port cap for all the ports in design

Some common application attributes are:

  • full_name => Returns the complete name (string type) of the cell. For example, the full name cell U3 within cell U2 within cell U1 is U1/U2/U3.
  • base_name => Returns the leaf name (string type) of the cell. For example, the base_name of cell U1/U2/U3 is U3
  • ref_name => Returns the name of the design or library cell of which the cell is (or will be) an instantiation; also known as the reference name. for ex I_my_inv is an instance of an inverter from lib which is tsmc_INV_NOM_D2.
  • object_class =>Returns the class of the object, which may be "cell", "net", etc. You cannot set this attribute.
  • is_hierarchical => Returns true for hierarchical cells and false for leaf cells. This is helpful in finding leaf cells.
  • power attr as dynamic_power, leakage_power, glitch_power, internal_power, total_power, switching_power, etc

Some important attr for different classes are:

  • cell_attributes => apart from common appl attr, cell_attr as cell_type (is_memory_cell, is_pad_cell, is_sequential_cell (2 flavors: is_rise_edge_triggered, is_fall_edge_triggered), are also present. We also have lib_cell_attributes for lib_cells. Attr may differ b/w cells and lib_cells even though both refer to the same underlying cell. These may even differ from what's there in .lib file for that cell.
    • size_only => can be set to true or false. Returns true if the cell is protected from removal by the set_size_only command. When this attribute is set to true, the ECO fixing commands (fix_eco_drc, fix_eco_power, and fix_eco_timing) can resize the cell but not remove it. The cell can still be removed by the remove_cell command.
  • clock_attributes
  • design_attributes
  • lib_attributes =>
  • net_attributes =>
  • pin_attributes => also has lib_pin_attributes for lib pins of lib cells. Attr may differ b/w pins and lib_pins even though both refer to the same underlying pin. These may even differ from what's there in .lib file for that pin. An ex is capa
  • port_attributes
  • timng_path_attributes =>
  • timng_arc_attributes => also has lib_tiimng_arc_attributes
  • upf_attributes

Some attr are only specified for leaf cells (i.e flop, AND gate, etc instantiated in design), so we can't apply or retrieve pin attr on IO pins of a module. In such case, we'll get an error "no such attr found".

Attribute cmds from Synopsys PrimeTime: Below are some Important attribute cmds from Synopsys PT (other tools from Synopsys may not support these cmds):

1. list_attributes => shows alphabetically sorted list of all attr for all object class. It doesn't show the values for these attr for any instance, but attr name and their type (i.e attr max_capacitance, thier type as "float" and the properties as Application defined, user defined, etc). By default, it shows only user defined attr, but using -application shows application attr too. Since there are too many appl attr for all object classes combined (about 3K or so), we should limit to specific object class using -class option.

  • Cell Attributes: list_attributes -application -class cell -nosplit => shows all cell attr (both appl and user defined). -nosplit prevents line splitting, so that it's more readable when dumped into some other file. "cell" class has attr as full_name, area, ref_name, lib_cell, etc.
  • Lib Cell Attributes: list_attributes -application -class lib_cell -nosplit => Same as above, except that it shows attr for lib cells. These are the attr found in .lib for that cell. The names reported here may be different than what's reported in .lib file, i.e it may have attr is_physical in .lib, but PT may report attr as is_physsical_only in lib_cell attr (as PT uses it's std attr for lib_cell so that it's consistent)
  • Pin Attributes: list_attributes -application -class pin -nosplit => shows all pin attr as cell, case_value, user_case_value, constant_value, full_name, clocks, is_clock_pin, is_clock_network, etc. Some pin attr as case_value, clocks, etc are valid for pins of leaf cells only.
    • capacitance on pin: returns max/min cap of pin for rise/fall. Attr are:
      • pin_capacitance_max/min_rise/fall, pin_capacitance_max/min (it's max/min of rise and fall). This cap is only for the cap on the lib pin, and not for anything connected to lib pin (i.e it doesn't add up the cap on the net for o/p pin). For o/p pins, this is usually 0, as output pins have almost 0 cap (as it's gate/src and gate/drn miller cap), while for i/p pin, it's the gate cap which is substantial. If we want to get all of the cap on that pin (including net cap + load cap), use attr: effective_capacitance_max/min. This refers to effective cap max_capacitance and min_capacitance that is seen on the pin. However, this effective_cap* values may not be present for all pins, in that case, use the cap attr on net (explained below) to find total load cap. Max and min cap values will be very close here, as cap doesn't vary much with max/min conditions. NOTE: always use "pin_capacitance_max/min" for getting cap values on pins of gates. These are guaranteed to be defined for all pins of all gates.
      • min/max_capacitance attr refers to min/max cap allowed on that pin as per .lib file (mentioned as max/min_capacitance for that pin in .lib, NOT the cap values in index for cell delay). This is the drc value for max/min cap on that pin. One other set of attr also defined for drc: drc_constraining_max_capacitance = max cap allowed as per drc rules (specified in .lib), drc_actual_max_capacitance = actual max cap present on this pin that is going to be used for drc purpose, drc_max_capacitance_slack = drc slack for max cap which is (drc_constraining_max_capacitance  - drc_actual_max_capacitance). These attr values may also not be defined for all pins.
    • delay: There are bunch of max/min_rise/fall_arrival/slack and max/min_arrival/slack that may be used to get timing path values.
    • transition on pin: returns max/min transition times on pin for rise/fall. Attr are: actual_rise/fall_transition_max/min, actual_transition_max/min (it's max/min of rise and fall). For i/p pins, there's also an attr "max_transition" that specifies the max_transition that's allowed on that pin as per .lib file (mentioned as max_transition for that pin in .lib). This is the drc value that's used for max transition on the pin. Similar to the cap values, one other set of attr also defined for drc: drc_constraining_max_transition = max tran allowed as per drc rules (specified in .lib), drc_actual_max_transition = actual max tran present on this pin that is going to be used for drc purpose, drc_max_transition_slack = drc slack for max tran which is (drc_constraining_max_transition  - drc_actual_max_transition)
    • net: This attr returns a collection that contains the net connected to this pin; this attribute is defined only if the pin is connected to a net.
    • cell: This attr returns a collection that contains the cell that this pin belongs to.
    • pin_direction: This attr specifies whether pin is "output" or "input" pin.
    • case_value: This attr is one of the most attr during debug of paths. It returns the user-specified logic value of the pin or port propagated from a case analysis or logic constant. This attribute is computed only for leaf pins.
    • constant_value: This attr returns the logic value of a pin tied to logic constant zero or one in the netlist.
    • full_name, disable_timing, fanout_load, is_clock_pin, is_Data_pin, is_clear_pin, is_async_pin, is_port, object_class,
  • Lib Pin Attributes: list_attributes -application -class lib_pin -nosplit => Same as above, except that it shows attr for lib pins. Again lib_pin attr in .lib may be diff than what's reported by PT, i.e attr "direction" in .lib is replaced by "pin_direction" attr in PT.
  • Net Attributes: list_attributes -application -class net -nosplit => shows all net attr as dont_touch, base_name, full_name, is_ideal, is_clock_network, leaf_drivers, leaf_loads, etc
    • capacitance/resistance on net: returns cap/res of net. Cap can be reported separately for wire and gate, while res is for whole wire. Attr are:
      • wire_capacitance_max/min, net_resistance_max/min: This attr reports wire cap (w/o any pin cap) and wire res.
        • ex: To get cap of net on o/p pin of gate: all_connected top/I_INV/Z => gives net name as top/n_12. Now run: get_att [get_net top/n_12] wire_capacitance_max => returns 0.004 (4 ff)
      • pin_capacitance_max/min, total_capacitance_max/min: pin_cap attr is the same as the one used for pins above. However, here it's reported for net, so it reports total of all pin caps connected to that net. If we report total_cap attr, then it shows total cap on that net which is the sum of wire_cap & pin_cap
        • ex: To get all pins connected to that net: get_pins -leaf -quiet -of top/n_12 => {top/I_INV/Z top/ND2/A1 top/NR3/A2} => This shows one o/p pin and 2 i/p pins connected ro this net. If we report attr pin_cap* for all 3 gate pins, and report pin_cao for the net, then the sum of all 3 pin caps should be the same as wire_cap.
        • Total_cap = pin_cap (on wire) + wire_cap (of wire). i.e  get_att [get_net top/n_12] total_capacitance_max = 0.013 (sum of wire_cap (0.0040) + 3 gate cap (0.001+0.003+0.005))
  • Clock Attributes: list_attributes -application -class clock -nosplit => shows all clock attr as period, waveform, master clock, master pin, setup_uncertainty, hold_uncertainty, etc.

Other than list_attributes cmd, report_attribute and get_attribute are 2 other most common cmds:

2. report_attribute => reports all attr on list of objects, which can either be a collection or a pattern (pattern needs to define object class with -class option). Here we report actual values for any attr of an object. By default only user defined attr are displayed. To see application attr, add option -application.

NOTE: report_attribute in Design Compiler (DC) has very different syntax than one in PT. See DC section for that.

ex: report_attribute -application [get_pins chip/.../D] => This reports all user attr + appl attr on pin D of given flop

Design          Object             Type            Attribute Name          Value
----------------------------------------------------------------------------------------
chip            chip/../D          float    actual_fall_transition_max  0.028304 => and 100's of other attr such as temperature_max, is_ideal, is_clock_pin, etc.

ex: report_attribute -application -attribute case_value [get_pins -hier */SE] => reports only this attr "case_value" on SE pins of all objects in design. Since SE (shift En) pin only exists on scannable flops, it's reporting case value on SE pin of all scannable flops (mostly to debug when in scanshift mode). case_value reports attribute on pin as 0 or 1, not just due to set_case_analysis, but also due to tieoff, propagated constants, or other reasons. This attribute is computed only for leaf pins.

ex: report_attribute -application -attribute lib_pin [get_pins mod1/dfg/D] => returns "tsmc_NOM_125/SDF_FLOP/D". This returns name of std cell and name of liberty library where it's present. This can be applied to cells also to get attr "lib_cell".

3. get_attribute => gets value of a given attr type for speciifed object or collection of object.  get_att is used compared to report_att when we want to use it within a script to extract values. syntax is: get_attribute <options> object attr_name

return value is a list (if multiple objects specified) or a string (if single object specified). To force return value to be a list, use option: -value_list

ex: get_attribute [get_cells -hier *] ref_name => shows reference cells for all "cell" objects in design. This will show not only std cells, but also module defn names as those modules have "module defn" as their reference name

Tracing constant values on clock network or other nets: Below 2 cmds useful in figuring out why some nets/pins are showing off constant value. This info can be seen in "report_attr -application" cmd above, as all attr values for a given object are shown there too, but get_attribute can be used in scripts for processing. We can keep on getting i/p and o/p pins of drivers on the fanin and backtrace to see the original source of this constant value.

ex: get_attribute [get_pins abc/.../D1] case_value => Returns the user-specified logic value of the pin or port propagated from a set_case_analysis or logic constant in netlist itself. This attribute is computed only for leaf pins. If you try to use it on nets, you will get "no such attr defined".

ex: get_attribute [get_pins abc/.../D1] constant_value => shows case value on a pin due to constant in netlist. When used in conjunction with case_value, we can know whether constant value comes from tied off net in netlist or due to set_case_analysis.

This below cmd is also being used which shows "user_case_value" , though not sure how it's different from "case_value" attribute. FIXME ? I've very seldom seen this attribute defined for pins.

ex: get_attribute [get_pins abc/.../D1] user_case_value => Returns the user-specified logic value of a pin or port.

4. define_user_attribute => defines new user defined attr.

ex: define_user_attribute attr_ir1 -classes cell -type int => defines new attr "attr_ir1" on all cell type whose value is integer

5. set_user_attribute => once we define a user attr, we can set it's value.

ex: set_user_attribute [get_cells *] attr_ir1 30 => setts attr value to 30 for above defined attr

6. remove_user_attribute => we can remove user attr defined above on specific cells. We can't remove application attr which are inbuilt.

ex: remove_user_attribute [get_cells i1] attr_ir1 => This removes user defined attr only from cell i1.

 

 

Object acccess functions: SDC supports these object access cmds. These cmds are supported both in DC and PT with same syntax (although there are some variations). Look in both PT manual, and DC manual to make sure the syntax is the same. Most of these cmds, which have the same syntax as in PT are in STA PT cmd section: primetime-commands:

1. Design get_* cmds:  get_cells, get_nets, get_pins, get_ports, get_clocks. Look in STA PT cmd section.

2. LIB get_* cmds: get_libs, get_lib_cells, get_lib_pins. Look in STA PT cmd section.

3. Design report_* cmds:  Supported by synthesis tools, but not part of SDC. Lots of reporting cmds as report_*. Look in STA PT cmd section, as these report cmds are common across DC and PT. Few cmds which are important or different in DC are explained below.

I. report_attribute: This cmd in DC has very diff syntax than corresponding cmd in PT, although the o/p reported is in the same format as that of PT. Here, the cmd reports the attributes of specified objects. An object can be a cell, net, pin, port, instance, or design. report is always generated for whatever is set as current design.

syntax: report_attribute <options> <object_list> => If object list is specified, then all attr reported for that object. If object list is not specified, then all attr reported for all objects in current design, which match the options.

dc_shell> report_attribute => reports all attributes for all objects in curent design. i.e for all cells, pin, ports, nets and design. If we use option -net, -cell, -design, -port, -pin, -instance, -hierarchy, then it reports attr for only that object type. report_attribute is very large report, since it reports everything, but then it can be narrowed byy reporting attr for only cells for ex by running "report_attribute -cell" cmd.

dc_shell> report_attribute mod1/mod2/pin1 => This reports all attr for a given object. Most of the times, we want to know if a given object is pin, net, cell, etc. This cmd helps us find that out. In this cae, object is a pin, as reported below.

Design          Object             Type      Attribute Name            Value
---------------------------------------------------------------------------------------------
digtop     mod1/mod2/pin1    pin       psnmp_oname     M:mod1 M:mod2 L:pin1

II. report_design: This cmd common across DC/PT, but used very commonly in DC to see all libs, op cond etc used for current design.

III. report_reference: This cmd in DC has very diff syntax than corresponding cmd in PT, although the o/p reported is in the same format as that of PT. It supports option "hier" to include hier.

IV. report_area: This cmd only supported in DC. It lists area for cells. It supports option "hier" to include hier.

4. LIB report_* cmds: report_lib is the only cmd here. It displays information about the specified logic library, physical library, or symbol library. It has lots of options. Look in STA PT cmd section.

5. set_hierarchy_separator => starting from SDC 1.2, hierarchical names can be made non-ambiguous using the set_hierarchy_separator SDC command and/or the -hsc option available on the
get_cells, get_lib_cells, get_lib_pins, get_nets, and get_pins SDC object access commands.

 

sample sdc file generated by Syntheis/Timing Tools: DC/PT/Genus:

pt_shell> write_sdc design.sdc

design.sdc:

set sdc_version 2.1
set_units -time ns -capacitance pF -current mA -voltage V -resistance kOhm

set_operating_conditions -analysis_type on_chip_variation  -library [get_libs TSM_max.db:TSM_max}]

set_wire_load_model -min -library [get_libs {zero_wire_load}] -name zwlm

set_wire_load_model -max -library [get_libs {zero_wire_load}] -name zwlm
set_wire_load_mode top

#create all clks needed
create_clock -name debug_rosc_clk -period 1.207 -waveform { 0 0.6035 } [get_ports {PORT1}]\
set_propagated_clock [get_clocks {debug_rosc_clk}]

#clk uncertainty set
 set_clock_uncertainty -setup  0.10462 [get_clocks {debug_rosc_clk}]
 set_clock_uncertainty -hold  0.0155 [get_clocks {debug_rosc_clk}]

#clk gating checks specified for all clocks
set_clock_gating_check -rise -setup  0.1 [get_clocks {debug_rosc_clk}]
 set_clock_gating_check -fall -setup  0.1 [get_clocks {debug_rosc_clk}]
set_clock_gating_check -rise -hold  0.45 [get_clocks {debug_rosc_clk}]
set_clock_gating_check -fall -hold  0.45 [get_clocks {debug_rosc_clk}]

#generated clks => source pin and master clk specified

create_generated_clock .....

#set derate on all cells rise/fall, late/early. It's done for both clock and data for each cell in library.

set_timing_derate -increment -cell_delay -clock -rise -early -0.0026  [get_lib_cells  {TSM_MAX/AN2_HVT}]

set_timing_derate -increment -cell_delay -data  -rise -early -0.0214  [get_lib_cells  {TSM_MAX/AN2_HVT}]

#set clk groups

set_clock_groups -asynchronous -name clk_grp_clk1 -group [get_clocks {my_clk}] -group [get_clocks {debug_rosc_clk ...}] ...

group_path -name io_to_flop -from [get_ports {IN1 IN2 ...}]
group_path -name flop_to_io -to      [get_ports {OUT1 OUT2 ...}]

group_path -name io_to_io -from [get_ports {IN3 ..}] -to [get_ports {OUT3 ..}] 

set_sense -stop_propagation -clocks [get_clocks {nec_clk}] [get_pins {I_1/reg_56/Q4}]

set_min_delay  0 -to [get_pins {I_1/pin1_out}]
set_max_delay  10000 -to [get_pins {I_1/pin1_out}]

#set MCL, FP, set case analysis, set_disable_timing, etc

set_case_analysis 0 [get_pins {clkmux2_0/S}]

set_disable_timing  -from PI -to PO [get_cells {chip/u_CTRL0}]

#set IO delay

set_output_delay  -1.3 -clock [get_clocks {spi0_clk}] -clock_fall -min -add_delay -reference_pin [get_pins {TOP/I_SC/PAD}] [get_ports {SPI0_MOSI}]
set_input_delay  17.4 -clock [get_clocks {spi0_clk}] -max -reference_pin [get_pins {TOP/I_SC/PAD}] [get_ports {SEP_SPI0_MISO}]

set_data_check -fall_from [get_pins  {I_1/flop_0/D}] -fall_to [get_pins {I_2/flop_0/D}] -clock [get_clocks {my_clk}] -hold  5

set_load -pin_load  50 [get_ports {AOP_LSPMI_CS_TRIG_1}]

set_max_transition 0.46 [get_pins {design1/mod2/gate/A design1/mod2/gate/Y ... }

set_input_transition 0.2 [get_ports *]

 

Using SDC cmds in Cadence Synthesis tools:

Cadence Synthesis tool RC didn't support SDC cmds natively. However their older PnR tool called EDI did support the SDC cmds. Cadence newer Synthsis tool called Genus support almost all SDC cmds natively. Their PnR tool Innovus also supports most SDC cmds. The section below is written for Cadence Synthesis tool, RC, which isn't being used anymore since 2020. So, below section is obselete, but provided since I prepared the notes anyway.


All of these cmds are synopsys cmd, so they don't work directly in Cadence tools as RC (they do work in EDI). In RC, these cmds only work, if they are used in a file, and read via "read_sdc constraints.sdc" cmd. They also work if we precede them with dc::
ex in RC:
rc:/> dc::set_load -pin_load 4.1912 [dc::get_ports n_puc_sync]
rc:/> read_sdc -stop_on_errors constraint.sdc => reads sdc file and stops on errors
rc:/> echo $::dc::sdc_failed_commands > failed_sdc => reports all failed cmds when reading sdc

NOTE: Although set_operating_conditions, set_max_area, set_units, set_propagated_clock present in sdc gen by DC, are standard sdc cmds, but they are ignored by RC,VDI. cdns tools looks at timing library (in /db/.../synopsys/src/*.lib) for default units [time_unit : "1ns"; current_unit : "1mA"; voltage_unit : "1V"; capacitive_load_unit (1,pf); pulling_resistance_unit : "1kohm"; leakage_power_unit : "1pW";]. If the default unit is not specified, cdns sets default unit of time to ns and cap to pf. Upto this point it's same behaviour as snps tools. But then it muultiplies these values by appr factor to convert them to ps and ff, which are cdns tools units. ns and pf are snps tools units.

#get_attribute returns the value of an attribute on a list of design or library objects. It's supported in both cdns/snps tools, but they are native cmds for each vendor. DC get_attribute is not supported in RC (i.e dc::get_attribute in RC will give an error). RC get_attribute behaves differently than DC get_attribute.
DC: get_attribute <object_list> <attribute_name> => returns value in dc default units of ns,pf.
RC: get_attribute <attribute_name> <object_list> => order is reversed. returns value in rc default units of ps,ff.

ex: rc:/> get_attribute capacitance [find [find "MSL270_W_125_2.5_CORE.db" -libcell IV110] -libpin A] => get_attribute, which is an RC cmd, looks at pin cap which is "0.0049". since cap units are set to pf in the .lib file, it correctly infers the pin cap to be 0.0049pf. Now, it converts this to ff which is 4.9ff and returns the value as 4.9.

ex: rc:/> get_liberty_attribute capacitance [find [find "MSL270_W_125_2.5_CORE.db" -libcell IV110] -libpin A] => get_liberty_attribute, which is an RC cmd, but returns values in default units specified in .lib file. So, it returns the value as 0.0049 which is in pf, which is the default unit for cdns specified in .lib file.

ex: dc_shell> get_attribute [get_lib_pins {"MSL270_W_125_2.5_CORE.db/IV110/A"}] capacitance => returns cap value in default units as specified in .lib file, which is pf. So, it returns the value as 0.0049 which is in pf, same as get_liberty_attribute.

set_load in constraints.sdc file gets affected by this, as being an sdc cmd, it expects the i/p to be in snps default units of pf. So, when using set_load in cdns, it gets off by factor of 1000.
ex: rc:/> dc::set_load [get_attribute capacitance [find [find "MSL270_W_125_2.5_CORE.db" -libcell IV110] -libpin A]] [dc::all_outputs] => get_attribute being an rc cmd returns value in ff which is 4.9. set_load treats this as 4.9pf (pf is default for dc), and sets a load of 4.9pf on all outputs, which is incorrect (correct value should be 0.0049pf)

To fix this, do this in RC:
rc:/> set load_scaled [expr [get_attribute capacitance [find [find "MSL270_W_125_2.5_CORE.db" -libcell IV110] -libpin A]]/1000] => load_scaled gets a value of 4.9/1000 = 0.0049 which is in pf.
rc:/> dc::set_load load_scaled [dc::all_outputs] => correctly sets o/p cap to 0.0049pf.

#possible issue in some library: not sure if this is an issue, FIX it later.
In a hypothetical library, default Cap unit=0.00693pf in .lib file. "set_units" cmd of sdc generated by DC, multiplies it by appr units in set_units to get load in pf unit. However, when we run any CDNS tool using the same sdc file, it ignores set_units cmd, so it treats the SL load in set_load in units of pf. It seems that the default units specified in .lib files, are not used as default units for anything outside those .lib files, that's why the units in "set_load" aren't adjusted by appr factor. This is only a problem for lbc8, as default Cap unit=0.00693pf. This causes diff when we gen sdf file using PT or ETS as PT sees diff load on o/p pins than ETS, so o/p buf delays are diff. "create_delay_corner" in create_views.tcl file in vdio is the equiv of set_operating_conditions in synopsys sdc file.

#set_units: to set units for env. When generating this in sdc, DC sets these units of time to ns, cap to pf, res to kohm, voltage to V, current to mA, based on units in .lib file. When generating this in sdc, RC sets units of cap in ff and time in ps. set_units is used by snps tools, but not by cdns tools.
DC: set_units -time ns -resistance 1.641228e+02kOhm -capacitance 6.093000e-03pF -voltage V -current mA
RC: set_units -time 1000.0ps -capacitance 6093.0fF

#set_operating_conditions: ignored by cdns tools. See synthesis_DC.txt for details.
set_operating_conditions W_150_1.65 -library PML30_W_150_1.65_CORE.db

 

----------

Heart:

Heart is one of the central system keeping the human body alive. The instant it stops working, you go dead. Heart failure is the number one cause of death.

Here's a good link to Heart's working: https://www.youtube.com/watch?v=_qmNCJxpsr0

One more good one with hand drawn diagram by Dr John Campbell: https://www.youtube.com/watch?v=VWamhZ8vTL4

Heart explained with a physical 3D model: https://www.youtube.com/watch?v=WyKBFWYKRBY

There's artificial hearts being made, which are someday going to replace failed hearts all together. The longest such an artificial heart has worked continuously in a human body is about 4 years. So, there's hope that over the next few decades, we may have artificial hearts lasting 20-30 years. Here's a video on such artificial hearts: https://www.youtube.com/watch?v=3uV8XZcIBbk

 

Heart anatomy: Heart sits in the center of our body near chest region. However, we hear that Heart is to our left. This is because some bigger chamber of heart is little bit to the left, so looks like heat is to the left. Right half of Heart is the one that collects dirty deoxygenated blood and passes it to the lungs for oxygenation. Once it gets oxygenated by lung, it's pushed to the left side of heart which transfers it to the rest of the body.

Link => https://medicoapps.org/wp-content/uploads/2018/10/1522314495.jpg

4 chambers of heart:

  1. Right Atrium (RA): Deoxygenated blood from all over the body is passed via blood pipes called Vena Cava (Superior Vena Cava (SVC) for top part and Anterior Vena Cava (AVC) for bottom part). These pipes or Veins enters the RA chamber here. Blood is passed to Right Ventricle which is sitting below the right atrium. There is a valve called "Tricuspid valve (TV)" that opens or closes to allow blood to pass from right atrium to right ventricle.
  2. Right Ventricle (RV): Deoxygenated blood flows from Right atrium to right ventricle and is pumped out to Lungs for oxygenation. There is a valve called "Pulmonic valve (PV)" that opens or closes to allow blood to pass from right ventricle to the lungs. The pipes going out of the heart to the lungs are called Pulmonary Artery (PA).
  3. Left Atrium (LA): Oxygenated blood from lungs is passed via blood vessels called Pulmonary Veins (PV). These pipes or veins enter the LA chamber here. The blood is then pushed to Left Ventricle which is sitting below the left atrium. There is a valve called "Bicuspid valve (BV)" or "mitral valve (MV)" that opens or closes to allow blood to pass from left atrium to left ventricle. MV is the equiv of TV that's seen on right side of heart b/w RA and RV.
  4. Left Ventricle (LV): Oxygenated blood flows from left atrium to left ventricle and is pumped out to the whole body (from brain to legs). Blood gets to cells which take oxygen from the blood, which gets the blood deoxygenated. Then this deoxygenated blood is passed on to the right atrium, and the 4 step cycle repeats again. There is a valve called "Aorotic valve (AV)" that opens or closes to allow blood to pass from left ventricle to the Aorta (a thick blood pipe which are arteries) which eventually branches out to the whole body. AV is the equiv of PV that's seen on right side of heart b/w RV and PA.

Atrium are much smaller than Ventricle, so when you see a pic of heart, you mostly see 2 front ventricles. The atriums are on the back and on the top of the heart (Ventricles are on the bottom). Though the cycle repeats from step 1 to step 4, processes in right side of heart are going in parallel to left side of heart, implying right and left atrium beat at the same time, while right and left ventricle also beat exactly at same time. So, we can consider only right side of heart for understanding purposes.

 


 

Veins and Arteries:

It's important to understand the difference b/w the two. Both are referred to as the blood vessels in the body. Veins are blood vessels going to the heart, while arteries are blood vessels going out of the heart. Veins get into the heart from 2 places => one from SVC/AVC into RA, and other from the lungs to LA in heart. Arteries get out of the heart from 2 places => one from RV going to the lungs, and other from the LV in heart. Usually blood vessels going into the heart carry deoxygenated blood, so veins are shown blue in color (blue means deprived blood, i.e in Hindi, people say a person's body has turned blue or "neela"meaning blood supply is dying), while blood vessels going out of the heart carry oxygenated blood, so arteries are shown red in color (red means rich blood). The only exception to this is the blood vessels going to the lungs and coming out of the lungs. The PA goes out of the heart to lungs carrying deoxygenated blood, and is shown blue even though it's an artery. Similarly, the PV goes from lungs to the heart carrying oxygenated blood, and is shown red even though it's a vein.

Blood Flow:

  • Right Heart: SVC/AVC (Veins) --> Heart (RA) -> Valve (TV) --> Heart (RV) -> Valve (PV) --> PA (Artery)
  • Lungs:                                                               --> Lungs -->
  • Left Heart:                PV (Vein) ->  Heart (LA) -> Valve (MV)  --> Heart (LV) -> Valve (AV) --> Aorta (Artery)

Arteries: Arteries carry blood away from the heart to the rest of the body. It needs pressure to push blood to everywhere in body. So, they have thick walls with muscle tissue. That thick pipe carrying blood from the heart to body is called "Aorta" as it's a Artery. It's the widest tube you find anywhere in body. It goes until the neck (which is a very short distance), before it branches off into smaller arteries to go to the head. The Aorta then curves back down to your chest. It continues through your abdomen and ends at your groin. Along the way, it splits off into other arteries that deliver oxygen-rich blood to your arms, legs, and the rest of your body..

Veins: Veins push deoxygenated blood back to your heart. Veins have thinner walls and are not as wide as arteries. Unlike arteries, veins generally need to work against gravity to push blood back to your heart. Veins have valves to help with this. These are one-way pairs of flaps inside a vein. They open for blood that’s heading upwards toward the heart, and close to keep blood from flowing back downwards.‌ Your veins usually hold about 75% of all the blood flowing through your body.‌ Your largest veins are the superior and inferior vena cava. Your superior vena cava carries blood from your upper body to the heart. Your inferior vena cava carries blood from everywhere below your heart. Like arteries, these two veins branch off into many other veins throughout your body. The veins coming out of right hear to go to Lungs are called Left Pulmonary Vein and Right Pulmonary vein. Muscle surrounds most veins in your body. When you walk, run, or otherwise use your muscles, they make a squeezing motion. These squeezes push against the vein and force the blood upwards toward your heart.

Capillaries: Arteries and veins connect through structures called capillaries. Capillaries are small webs of thin tubes that connect to an artery on one side and a vein on the other.‌ Some parts of your body have more capillaries depending on how much energy they need. For example, your muscles use a lot more energy than your skin, which is why your muscles have more capillaries than your outer skin.

 


 

Heart Disease:

CVD (Cardiovascular disease) refers to all diseases of cardiovascular system – which consists of the heart and all the blood vessels in the body. CVD is leading cause of death globally, with 18M deaths every year.

  1. Atherosclerosis: It is the main underlying cause of CVD. It is a disease in which plaques consisting of fat, cholesterol, calcium and other substances build up in the walls of arteries. Over time, the plaques harden, narrowing the opening of the arteries and restricting blood flow. If atherosclerosis occurs in one of the arteries that supply blood to the heart, it can cause a Heart Attack. If blood clot (known as thrombosis) occurs in one of the arteries to the brain, it causes a Stroke. Heart Attack and Cardian Arrest are used interchangeably, though they are different. A cardiac arrest usually occurs when there is a malfunction in the heart’s electrical system that causes the heart to stop beating properly. It suddenly stops beating. This results in the stoppage of blood flow to the brain and other vital organs, and the sufferer loses consciousness and stops breathing normally, resulting in death.
    1. Stroke (Aka Brain Stroke or Brain attack): 16M ppl suffer from stroke every year. Just a few hours of poor blood flow to some parts of brain causes the body to become paralyzed forever. Few symptoms of stroke include face changes, unbalanced walking, difficulty speaking or slurred speech, etc. 2 kinds of stroke:
      1. Ischemic Stroke:  This is caused due to lack of blood flow (because of a clot in the blood artery to brain). It can be temporary called as Transient Ischemic Attack (TIA) or permanent called as Ischemic Stroke. There is no medication for this, although some medicines given within few hours of stroke have been said to help dissolve the clot. However, there are medicines that are actively being researched to give to survivors of a Brain stroke so that they they form any more blood clots in future. One such medicine => https://www.hri.org.au/news/groundbreaking-world-first-trial-offers-new-hope-to-stroke-sufferers
      2. Hemorrhagic stroke: This is caused when a blood vessel in your brain ruptures or breaks, spilling blood into the surrounding tissues. This is very deadly and untreatable. However this is less common.
  2. Arrythmia (Irregular heartbeat): t is a type of heart condition where the heart rhythm is not steady. Instead, the heart may feel as though it were skipping a beat, have extra heartbeats every now and then, flutter or race, or beat faster or slower than normal. There are many types of arrhythmias, varying in severity and danger. Atrial Fibrillation (AF) is the most common type. Problems with the heart’s rhythm can occur when there is any interruption to the electrical signals that stimulate the heart’s pumping activity.
  3. Congestive heart failure (CHF):  CHF is #1 heart disease. It is a broad term used to describe a clinical condition resulting from the inability of the heart to adequately pump blood and causing symptoms such as orthopnea, dyspnea on exertion and edema.Heart has blood filling in and blood pumped out every beat. Insufficient filling or insufficient pumping are both problems that lead to CHF.
    1. Diastolic dysfunction, which is a condition of impaired ventricular filling. Less common.
    2. Systolic dysfunction, which is a condition of impaired ventricular emptying.
      1. Ejection Fraction (EF) : of heart is defined as volume of blood pumped per beat out of heart's chamber to the volume of blood filled per beat into the heart's chamber. This is defined for both left ventricle (LVEF) and right ventricle (RVEF). The full capacity of heart is about 120ml-150ml for an adult, and after each beat, volume of blood remaining is ~50ml, meaning 70ml-100ml was pumped out per beat giving an EF=60%-65%. EF of 50%-70% is considered normal. Low LVEF of < 40% is the most common kind of CHF (known as HFrEF) as it results in insufficient supply of blood to body parts. Low RVEF means heart is not pumping enough blood in lungs resulting in various issues. Usually, HF refers to tlow LVEF.

 


 

Treatment plan for HFrEF (Heart Failure with reduced Ejection Fraction):

These are 4 pillars of this treatment, which cosnsists of 4 different medications introduced in parallel.

Link => https://blog.bswhealth.med/four-pillars-of-heart-failure-therapy-should-be-rapidly-and-simultaneously-introduced/

4 Pillars:

  • Beta Blocker: This is the first pillar. These medications have been around for 30+ years.These are first line of defense. 
    • There are several types of beta-blockers, but only three are approved by the FDA to treat heart failure:
      • Bisoprolol (Zebeta) => Bisoprolol (Zebeta) is a selective beta1 antagonist without significant intrinsic sympathetic activity or vasodilating properties 
      • Carvedilol (Coreg) => Carvedilol is a non-selective beta-blocker with additional alpha1-blocking and antioxidant activities. Nebivolol is a novel beta-blocker with both a greater degree of selectivity for beta-1 adrenergic receptors than other agents in this class and an ability to stimulate endothelial nitric oxide production, leading to vasodilation and other potential clinical effects. Carvedilol (Coreg) is a novel agent with antagonist activity against alpha1, beta1 and beta2 receptors, as well as some antioxidant activity. It is the only beta blocker labeled by the U.S. Food and Drug Administration (FDA) for the treatment of heart failure.
      • Metoprolol (Toprol) => Like bisoprolol, metoprolol tartrate (Lopressor) and metoprolol succinate (Toprol XL) are beta1-selective blockers without significant intrinsic sympathetic activity or vasodilating properties.
    • A study published in 2000, showed little benefits for all 3 drugs when measured in terms of mortality rates (only 40% fewer deaths, but => https://www.aafp.org/pubs/afp/issues/2000/1201/p2453.html
       
  • ARNI inhibitor: ARNI is a combination of sacubitril, a neprilysin inhibitor, and valsartan, an angiotensin II receptor blocker (ARB) and is now considered first choice for initiation. ex: Vyamada (sold in India).
  • SGLT2 inhibitor: This has an additive when added on top of ARNI inhibitor. Two drugs, dapagliflozin or empagliflozin are recommended to reduce the risk of heart failure hospitalization and cardiovascular death in HFrEF patients.
  • MRA: Aldosterone Receptor Antagonist are also known as MRA. Discovered in the 1990s, these drugs are aldosterone antagonists that reduce excess fluid in the body while preventing the loss of potassium. Yet the primary efficacy is from neurohormonal blockage. They are weak diuretics. The normal dose is usually 25 mg daily.

 


 

UVM like tb framework using SV: (from sample project)

Here, we build a testbench framework using all these SV constructs that we learned earlier, i.e class, program, env, interface, etc. This is how UVM framework is developed that we'll learn in other section.


usbpd_tb.sv:

`include testbench.sv //this has the program for all classes
module usbpd_tb();
 wire, reg, ...;
 function/task func1() .. endfunction //functions/tasks
 initial/always @(...) begin .... end //build osc, release porz, checkers for clk
 digtop I_digtop (.in1(tb_in1), out1(tb_out1)); //DUT inst
 i2c_bfm I_i2c_bfm ( ...);
 sram_monitor i_mon (.addr(s_addr), ...);
 cm0_tarmac u_tarmac(.en(1'b1),...); //tarmac inst for M0
 specify $width(...); ....; endspecify //we can define our own clk pulse width check, etc (similar to what's in gate models)
//property checkers included here
 property hready_checker;
  @(posedge clk) disable iff (hresetn) !hready |=> hready_i; //checker disabled if hresetn=0, else hready_i should match !hready on next clk posedge
 endproperty
 ass_prop_chk : assert property (hready_checker) //property asserted here
                      begin $display("OK"); end
               else begin $display("ERR"); end
 cov_prop_chk : cover property (hready_checker) //property covered here

 tb_intf I_tb_if(); //interface defined  below in testbench.sv
endmodule

testbench.sv:

typedef class register_base;
typedef class register_field_base;
typedef class register_block_base;
typedef class ahb_collector;

interface tb_intf(); //i/f defn
 logic data, addr, ...;
 task wrt_addr(...);
endinterface

//start of register_base class => has all reg attributes as name, value, etc.
class register_base;
   string         parent_module;
   string         name;
   enum {READ, WRITE} rw;
   bit [31:0] address;
   bit [31:0] value;             // same as mirrored_value in UVM registers
   bit [31:0] rand_value;        // same as value or desired value in UVM registers
   bit [31:0] rd_mask; //similarly wr_mask, rd_to_clr, wr0_to_clr, wr1_to_clr, wr1_to_set.

  register_block_base parent_reg_blk;
  //covergroups
   covergroup cg_bit_31 @(bit_31_wr_done_ev or bit_31_rd_done_ev); //sampled whenever these events happen
      cp_bit_31 : coverpoint {rw,value[31] } { //coverpoint cp_bit_31 defined for rw and value[31] bits
     wildcard bins tran_r0_w0_r = ({READ,1'b0} => {WRITE,1'b0} => {READ,1'bx}); // bin for transition from rd to wrt to rd
     wildcard bins trans_r1_r   = ({READ,1'b1} => {READ,1'bx});
      }
   endgroup //similar covergroup for other bits  

   register_field_base reg_fld_q[$]; // queue of register fields
   
   function new ( string module_name, string reg_name, bit [31:0] reg_address,
          bit [31:0] rd_mask, bit [31:0] wr_value, bit [31:0] rd_value, register_block_base register_block_base_inst);
      this.parent_module = module_name;
      this.nmame = reg_name;
      this.address = reg_address;
      this.value = rst_value;
      this.rd_mask = rd_mask;
      this.parent_reg_blk = register_block_base_inst;
      this.d_value   = this.value;
 
     register_block_base_inst.add_reg(module_name, this); //func defined in reg block base
   endfunction

   virtual function string get_name(); //string implies return value
      return (name); //returns name and so on for other func
   endfunction

   virtual function void reset(); //to reset fields, return value is nothing, so "void" used
      value      = rst_value;
      foreach (reg_fld_q[i]) void'(reg_fld_q[i].reset());
   endfunction
endclass //end of register_base class

//create a class for each reg
class SPARE_REG_type extends register_base;
   rand register_field #(6) RESERVED;
   rand register_field #(6) STICKY_STS_SET;
   rand register_field #(20) RESERVED1;

   function new ( string module_name, string reg_name, bit [31:0] reg_address, bit [31:0] rst_value,
                  bit [31:0] rd_mask, bit [31:0] wr_value, bit [31:0] rd_value, register_block_base reg_blk_inst);
     super.new(module_name, reg_name, reg_address, rst_value, rd_mask,  wr_value, rd_value, reg_blk_inst);
   endfunction
endclass

class AUX_REG ... endclass // and so on for all regs
//end of class for all regs in design

//start of register_field_base
class register_field_base;
   string          name;
   bit      [7:0]      start_bit;
   bit      [7:0]      length;
   register_base parent_reg;

   function new ();
   endfunction // note: nothing defined in new func, similarly other func defined with nothing in them, as they will be defined in register_field class
endclass

class register_field #(int FIELD_LENGTH = 32) extends register_field_base;
   rand bit [FIELD_LENGTH-1:0]      rand_value; // desired_value   // parameterized
   bit      [FIELD_LENGTH-1:0]      value;      // mirrrored_value // parameterized

   covergroup    reg_field_cg  @(parent_reg.wr_done_ev or parent_reg.rd_done_ev);
      option.name = name;
      cp_reg_field_value: coverpoint (value) { // coverpoint for all values of that reg field
     bins field_val[] = {[0: max_value]}; //array of bins created from field_val_0 to field_val[max_value]. So, if 0 sampled, then bin fiel_val_0 is covered and so on. advantage of array of bins is that we can see which values are missing from coverage
      }
   endgroup // reg_field_cg
 
   function new ( string fld_name, int start_bit, int fld_len, register_base parent_register);
      this.name       = fld_name; //name, start_bit, length properties come from reg field base
      this.start_bit  = start_bit;
      this.length     = fld_len;
      this.parent_reg = parent_register;
      parent_register.add_reg_field(this);
   endfunction // new

   virtual       function void reset();
      // get the reset value from the parent register and copy to the rest of values
      value      = ((parent_reg.rst_value >> start_bit) & max_value);
      prev_value = value;
   endfunction // reset
endclass

//class reg block base => largest class in terms of code => all checkers implemented here as tasks
class register_block_base;
 register_base reg_q[string][$]; //contains queue of reg base
 mailbox reg_tr_mbx;
 SPARE_REG_type SPARE_REG; //and so on for all other regs
 
   covergroup custom_SPI_cg; //specify covergroups for regs and bits which we want sampled when C pgm accesses those
    cp_mon: coverpoint SPARE_REG.MODE.value;
    ...
   endgroup

   task ... forever ... endtask
   task automatic cfg_assert(); //all IO pin checks are in this task, similarly frs_assert, gpio_assert etc
     config_assert: assert(SPARE_REG.SPARE_OUT.value === `TB.pin[12]) else $display("ASSERTION ERROR"); //similarly for all other IO pins
   endtask
 
   function void add_reg (string module_name, register_base reg_inst);    
      foreach (reg_q[module_name][i]) // check existing registers to make sure there is no duplicate address
    if (reg_q[module_name][i].get_address() == reg_inst.get_address()) //do not add reg
    begin
         $display("ERROR: module_name.substr %s", module_name.substr(0,2));
             $finish;
        end  
      reg_q[module_name].push_back(reg_inst); // push reg at end of queue,
   endfunction // add_reg
 
   function cg_sample ( ...) //called from detect_rand_request (whenever C pgm writes to loc indicating it wants sampling)
     if (testname.substr(0, 2) == "spi") custom_SPI_cg.sample();
     else if (...)                     custom_UART0_cg.sample();

   function void build();      
      create_reg_space(); // instantiate register model and covergroups etc (defined in function below)
      CONFIG_SPARE_WAKEUP_REG.rd_mask = 32'hFFF81FFF;      
   endfunction // build

   task start (); //impl as task since they have always, forever etc
      apply_hw_lock_mask(); //func defined in this class
      apply_trim_lock_mask(); //func defined in this class
      fork
     register_adapter(); forever task in reg_block_base. At every FCLK edge, it samples AHB tran, and calls gpio_sample, config_sample, etc, depending on addr.
     detect_rand_request(); //forever task (@ posedge FCLK, HWRITE=1 and HADDR=RAND_REQ_ADDR and then look at HWDATA[15:0]) to detect random req wrt to different regs (wrt rand val to reg model and copy that to sram)
     detect_incoming_rand_xfer(); //to detect tb_if.req to wrt incoming addr/data to sram + detect tb_if.done to wrt end signature once done
     test_end_detect(); //this is a forever task to detect "EXIT" inst being written
         output_checker(); //it's a fork forever task that calls bunch of other assert tasks as "cfg_assert", on event @config_debug_sampled, etc. these events are triggered in func "config_sample" (called in register_adapter task) when addr match for wrt happens on AHB bus.
      join_none //above forked process keep running for ever
  endtask // start
 
   function void create_reg_space();
      SPARE_REG = new("CONFIG", "SPARE_REG", 32'h01F0, 32'h00000000, 32'hffffffff, 32'hffffffff, 32'h00000000, 32'h00000000, 32'h00000000, 32'h00000000, 32'h00000000, 32'h00000000, 32'h00000000, this); // 0x01F0 - SPARE_WAKEUP_SET_REG
        SPARE_REG.RESERVED = new("RESERVED", 26, 6, SPARE_REG);
        SPARE_REG.STICKY_STS_SET = new("STICKY_STS_SET", 20, 6, SPARE_REG);
        SPARE_REG.RESERVED1 = new("RESERVED1", 0, 20, SPARE_REG);

     AUX_REG = new("...); //similarly for all other regs and corresponding bits
   endfunction

   task register_adapter(); //samples transaction on AHB, and depending on reg addr, puts deglitch values, etc on tb_pin_intf signals
    forever begin
      @(posedge `CPUTOP.FCLK);
        if (reg_tr_mbx.try_get(curr_tran) == 1'b0) $display ("NO AHB transaction"); //get AHB msg that was put in collector below
        else begin (if curr_tran.addr == 16'h0F30) reg_h = config_sample(curr_tran.addr[15:2], curr_tran.wr_data, curr_tran.rd_data, 0);
    else       (if curr_tran.addr == 16'h0A50) reg_h = gpio_sample(...) and so on
   endtask

endclass //end of reg block base

//AHB collector
class ahb_collector; //this collects 1 AHB transaction with addr, rddata, wrdata, etc
  string name;
  mailbox tr_mbx;
  ahb_transaction ahb_tran; //a class defined with addr, wrdata, etc
 
  function new (string name, mailbox tr_mbx);
    this.name = name;
    this.tr_mbx = tr_mbx;
  endfunction // new
      
  task body();    
     forever begin        
        @(negedge `CPUTOP.FCLK);
          ahb_tran = new(`CPUTOP.HWDATA, `CPUTOP.HRDATA, ... );
        if (tr_mbx.try_put(ahb_tran) == 1'b0) $display(ERROR"); //ahb_tran class object pushed into mailbox
         end
  endtask
endclass
               
       
//class env
class env;
   register_block_base reg_blk_inst;
   mailbox tr_mbx; //mailbox to store 1 AHB transaction from M0
   ahb_collector  ahb_collector_0;
 
   function new();
      tr_mbx       = new(1); // each module mailbox is one deep
      ahb_collector_0     = new("AHB Collector for M0p", tr_mbx);  
      reg_blk_inst = new(tr_mbx);
   endfunction // new
    
   virtual task build();
      reg_blk_inst.build(); //creates reg class for all regs and their fields by calling "create_reg_space" func
   endtask // build
   
   virtual task start();
      fork
     reg_blk_inst.start(); //task start, which itself is bunch of forked proc, called from reg block_base. all checkers, etc here
     ahb_collector_0.body(); //collects all AHB transactions
     misc_collector_0.body();
     dbg_fifo_sb_0.body();    
      join_none; //above forked proc run forever
   endtask // start
endclass // env

//testbench starts from here. this is another top level module besides usbpd_tb. It's not called from anywhere.
program testbench();
 env env_inst;

 initial begin
  env_inst = new();
  env_inst.build();
  env_inst.start();
  wait(`TB.tb_finish_test == 1); // wait for test bench to finish test (happens on receiving "EXIT" from main pgm
 end

 property .... endproperty
endprogram


 

SDC Synthesis Constraints:

SDC was developed mainly for Synthesis design constarints, but we saw above that a lot of other cmds got added over time. Below we see the design constraints that are standard in all synthesis tools now.
write_sdc is an sdc cmd that writes all constraints that the synthsis tool sees in the design (provided by the user in any format) in the sdc format. This file in sdc format can then be used as i/p to any other tool, that relies on sdc cmds. This is very useful when porting constraints. These are few SDC cmds that are provided to any design for synthesis:

  1. Environment Constraints: external to design: op cond (PVT), WLM, load (both i/p and o/p), drive (only on i/p) and fanout(only on o/p).
  2. Clocks (primary and generated clocks): clk pins, freq, uncertainty and drive.
  3. Constraints: design and opt constraints. Mainly input and output delays.
  4. False paths and multicycle paths: timing constraints
  5. Case analysis (for functional and scan): global constraints. sets appr pins and nets to 0/1 to enable func or scan. needed only when scan present.
  6. Misc: set_don_touch, set_dont_use: global constraints. not needed for PT.

1. Environment Constraints: op cond (PVT), WLM, load (both i/p and o/p), drive (only on i/p) and fanout(only on o/p).

  1. op cond: set operating condition of design
    1. set_operating_conditions =>
  2. wire load models (WLM): WLM are set based on how we want to model net delays.
    1. set_wire_load_model: used only when design is not in physical (DC-topo or RC Physical) mode. WLM estimates effect of wire length and Fanout on res, cap and area of net. No. of fanout determines net length based on fanout to length table. Which Fanout to length table to use is determined based on area of cell which drives the net. DC uses the cap/res to calc wire delay.
    2. NOTE: In .lib file, we specify wire load model and wire load selection for different area of cell. See in liberty.txt for details.
      1. set auto_wire_load_selection true
      2. set_wire_load_model "6K_3LM" => sets wire load model to something other than the default one set in .lib file
      3. set_wire_load_mode enlosed:  Setting enclosed wire load mode. We may set different wire load models for different hier cells. By setting this parameter, we help tool decide which wire load mode to pick for a net in a specific hier. allowed values are: top(default), enclosed, segmented. By setting to enclosed, Wire load model of the module that entirely encompasses the wire is used for each wire. This more realistic than the more conservation "top" mode (in top mode, WLM for top design is used for all nets). segmented mode is most accurate as it uses WLM for each segment of wire, depending on which design it lies in.
    3. set_wire_load_min_block_size
    4. set_wire_load_selection_group
  3. load (on both i/p and o/p): set_load cmd sets load on i/p or o/p ports and nets in design. -min/max can be used for hold/setup. we need to set load on i/p ports when the driving_cell on i/p port is far away or has extra fanout, so wire/pin cap added on i/p port using this cmd. Usually we only specify load for o/p ports, as i/p ports don't branch out anywhere else, so no extra load.
    1. NOTE: set_load also applies on internal nets, and so will override internally calculated net load value. When using DC-TOPO, for each net, cap and resistance are estimated based on estimated physical layout. so, in DC-TOPO, when we write sdc using write_sdc, we get set_load and set_resistance for each internal net in the sdc file. Be careful, not to use this sdc file in PnR tools as EDI or timing tools as PT. In EDI, use report_ports to view cap on ports. For EDI, Cap is in units from tech lib. For DC, cap is in units of set_units, if specified, else from tech lib.
    2. ex: set_load -pin_load 4.1912 [get_ports n_puc_sync] => -pin_load implies that load value for the port should be treated as extrnal pin cap and -wire_load implies external wire cap, or tot cap (pin+wire) when nothing specified.
    3. ex: set_load 4.1912 [all_outputs] => sets load of 4.2 units (total cap=pin+wire) on all o/p ports.
      1. Cadence Synthesis RC cmd: set_attribute external_pin_cap 0.05 [all_outputs] => RC cmd for setting cap on all o/p ports. set_load is preferred cmd as it's sdc cmd.
  4. drive on i/p: 2 cmds used here: set_driving_cell and set_drive/set_input_transition
    1. ex: set_driving_cell -lib_cell <cell_name> [ports] => Sets  attributes  on input or inout ports of the current design, specifying that a library cell or output pin of a  library  cell drives specified ports. last entry is the name of i/p or inout ports on which driving cells are to be placed. These driving cells are not actually put in the design, they are used to model what is driving the pins from external world.
    2. set_driving_cell -lib_cell IV110 [get_ports n_puc] => puts IV110 to drive port n_puc
      1. Cadence Synthesis RC equiv => set_attr external_driver [find /lib*/ -libcell IV110] [all_inputs]
    3. set_drive => to set drive resitance (res unit in .libfile, usually Kohm) directly on port. For clocks, set drive res to 0 (infinite drive), so that DC/RC doesn't put buffers on it.
      1. syntax: set_drive <port_list> <resistance> => sets resistance of external driver in units of .lib for that port
      2. ex: set_drive 0 clk1 => sets clk1 driver res to be 0 Kohms, i.e ideal driver (infinite drive)
        1. RC equiv => set_attr external_resistance 0 [clk1]
    4. set_input_transition => Alt to set_drive. Sets  the  max_transition_rise, max_transition_fall, min_transition_rise, or min_transition_fall attributes  to  the  specified input and inout ports. -min/max state whether it's to be applied for hold/setup. "0" implies infinite transition
  5. fanout on o/p: set_fanout_load cmd is used to model expected FO load on o/p port. When synthesizing, DC tries to keep FO on o/p port (by adding FO specified on o/p  port plus FO presented internally by cells connected to o/p port) less than max_FO specified for the design.
    1. ex: set_fanout_load 4 {out1} => puts FO of 4 (unitless number) on out1.
    2. set_port_fanout_number
  6. MISC: Many misc cmds which are not needed in regular synthsis flow.
    1. set_resistance => sets the back annotated resistance value, which enables the back-annotation of resistance value for nets in net_list. The  specified  value overrides the internally-estimated net resistance value, so use it carefully. To use diff value for min delay analysis (hold), and max delay analysis (setup), use -min/-max option
      1. ex: set_resistance -min 300 U1/U2/NET3 => sets a resistance of 300 units to be used for hold analysis on net U1/U2/NET3


2. design constraints:

  1. Design rule constraints: set_min_capacitance, set_max_transition, set_max_fanout, set_max_capacitance, set_cell_degradation (usually in .lib). precedence of design rule const in DC: min_cap (highest priority), max_tran, max_FO, max_cap, cell_degrad (lowest priority). precednece can be changed by using set_cost_priority in DC.
    1. set_min_capacitance => sets min cap attr on i/p ports. This ensures that load driven by i/p port is not below a certain value. not set in std cell .lib file. min cap is usually the lowest cap value with which a cell has been characterized to operate.
    2. set_max_transition 4.0 [find design *] => sets  the  maximum  transition  time, on specified clocks, ports, or designs. set by default for all i/p pin of all the cells in .lib (using max_transition : 4.10;). We can override the one in lib by specifying it explicitly for i/p, o/p ports or designs.
      1. Ex: set_max_transition 5 [get_clocks Clk] => sets value of 5 on all pins belonging to "Clk" clock group. Needed in cases where there are multiple clocks running at diff freq, so transition requirement for each group might be diff.
    3. set_max_fanout 20 => default_max_fanout defines as 20 in top of .lib file. Then for o/p pin of some cells (as tie-hi/tie-lo cell TO020), we specify max_fanout to 50 (max_fanout : 50;) in .lib file. Can be specified on i/p ports or designs.
    4. set_max_capacitance => Sets  the  max_capacitance attribute to a specified value on the specified clocks, ports and designs.
      1. ex: set_max_capacitance 2.0 [current_design] => sets max cap of 2 units on all design. Not needed as it's set by default for o/p pin of all the cells in .lib (using max_capacitance : 0.21;). allows to control cap directly, while set_max_transition & set_max_fanout control cap indirectly.
    5. set_cell_degradation => some .lib contain cell degradation table that list the maximum capacitance that can be driven by a cell as a function of the transition times at the inputs of the cell.
  2. Optimization constraints: defines goals for area, power and timing (clocks, clock skews, i/p delay, o/p delay). DC attempts to meet these goals, w/o violating design rule constraints.
    1. area const:
      1. ex: set_max_area 0 => tries to reduce area to min. Not supported by Cadence
    2. power const: max_dynamic_power and max_leakage_power (requires power compiler license). Not needed if no pwr const for design.
    3. timing const:
      1. set_input_delay: sets external i/p delay on i/p ports. The delay specified is the delay from the rising edge of specified clk. Default is rising edge of clk (may be changed via -clock_fall option). Assumption is that the specified clk is firing the i/p port and is taking the specified amount of time outside the block, before it gets to the i/p port.
        • set_input_delay 0.2 -clock clk1 [remove_from_collection [all_inputs] [get_ports {all_clocks}]] => sets 0.2 unit delay on all i/p pins (except clk ports) relative to clk1 (clk1 is imaginary clk that fires the imaginary flop that is firing the i/p pin. It's NOT the i/p clk port of DUT. Almost all the time, clk1 is chosen to be same as i/p clk port). By default, i/p delay is 0 if not specified. -max specifies that delay refers to longest path (i.e for setup calc), while -min is for shortest path (i.e for hold calc). If not specified, same delay is used for both setup/hold and rise/fall. Usually for spi/i2c etc signals, we specify diff min/max value as setup/hold numbers are different (we try to provide large setup delay and almost 0 hold delay). We can also specify rising/falling edge of clk.
          • ex: setup: set_input_delay -max 40 -clock spi_clk spi_cs_n => specifies a setup time of 10ns (assuming clk=50ns period, then 50-40=10ns of time available for internal ckt) for port "spi_cs_n". The port data is fired on rising edge of "spi_clk". Depending on how it's captured inside the chip, it may be full cycle orhaf cycle path.
          • ex: hold:  set_input_delay -min 0 -clock spi_clk spi_cs_n => specifies 0ns holdtime. "-min" is not needed in DC, as we don't run any hold timing optimization (as there are no clk tree buffers, clk is treated ideal). But it's needed to be used in PnR for the tool to work on this path to fix hold.
      2. set_output_delay: sets external o/p delay on o/p ports. The delay specified is the delay from the output port to the rising edge of specified clk. Default is rising edge of clk (may be changed via -clock_fall option). Assumption is that the specified clk is capturing the o/p port and is taking the specified amount of time outside the block, before it gets captured.
        • ex: set_output_delay -clock osc_clk -clock_fall 10  [get_ports {dout[65]}] => specifies o/p delay of 10ns wrt falling edge of osc_clk for port "dout[65]". By default, delay is wrt rising edge of clk.
        • ex: set the input and output delays for the bidirectional port INOUT1. The input signal arrives at INOUT1 2.5 units after the falling edge of CLK1. The output signal is required at INOUT1 at 1.4 units before the rising edge of CLK2.
          • set_input_delay 2.5 -clock CLK1 -clock_fall { INOUT1 }
          • set_output_delay 1.4 -clock CLK2 { INOUT1 }
      3. Optional ideal attr => not needed for clocks in synthesis tools (such as DC). clk nets are ideal nets by default.
        1. set_ideal_network {clk1 clk2} (added in sdc 1.7) => marks ports/pins (clk1, clk2) as src of ideal network. Ideal networks are an extension of ideal nets that incorporate automatic propagation  of  the  ideal  attribute. All nets, cells, and pins on the transitive fanout of these objects are treated as ideal. Propagation  traverses through combinational cells but stops at sequential cells. "-no_propagate" option prevents ideal propagation thru logic gates. In  addition  to disabling timing updates and timing optimizations, all cells and nets in the ideal network have the dont_touch attribute  set. The latency and transition times of an ideal network are 0 by  default, but   you   can  override  them  by  using  the  set_ideal_latency  and set_ideal_transition commands.
        2. set_ideal_latency 2 clk1 (added in sdc 1.7) => Specifies latency of 2 units for ideal network (clk1). By default, "0" ideal latency ias assumed for ideal networks.
        3. set_ideal_transition (added in sdc 1.7) =>
        4. set_dont_touch_network [get_clocks *] => dont_touch attributes is placed on all cells/nets in the transitive  fanout  of  dont_touch_network objects (clk, pins or ports). It's intended primarily  for clock circuitry. Placing a dont_touch_network on a clock object prevents the compile command from  modifying  the  clock  buffer network.

 
clock related:
-------------
create_clock

create_generated_clock

set_clock_gating_check

set_clock_latency

set_clock_transition

set_clock_uncertainty

set_propagated_clock

clock_group, path group cmds

timing exceptions:
-----------
set_false_path:

set_multicycle_path:

set_max_delay/set_min_delay

set_disable_timing
set_max_time_borrow

set_data_check

set_timing_derate
                           
3. global constraints:

These are extra constraints that we want the tool to adhere to.

  1. set_dont_use => It says not to use certain lib cells in design.
    1. syntax: set_dont_use <libcell> <true/false> => sets dont_use attr on that libcell to true/false. default=true. true/false can also come before libcell, i.e: set_dont_use  <true/false> <libcell>. NOTE: set_dont_use isn't supported in PT.
      1. set_dont_use [get_lib_cells CGP*] FALSE  => sets clk gating attr dont_use to false => use CGP cells. We can use "list" to get all cells in a particular library "set_dont_use [list PML30_W_150_1.65_CTS.db/CGP*] FALSE", but this won't work in RC, as list is not sdc cmd.
        1. RC equiv => set_attr avoid 0 [find /lib* -libcell CGP*]  => 0/false means use it.  1/true means dont use. NOTE: PML30*.db lib exist in /libraries/MSL* virtual dir structure in RC, so, we have to use find in /libraries/. We could use dc::get_lib_cells also in RC. ex:
          1. set_attr avoid 0 [dc::get_lib_cells PML30*/CGP*] => finds all CGP* cells in any subdir with PML30* name in top virtual dir.
          2. set_attr avoid 0 [dc::get_lib_cells CGP*] => finds all CGP* cells in all dir/subdir in virtual dir /libraries/MSL270_W_125_2.5_CTS.db/libcells/CGP40, etc.
  2. set_dont_touch => This specifies not to touch this object. This may be needed when we have an instance in RTL that is already speciifed as a std cell from lib, and we don't want synthesis tool to mess with it.
    1. syntax: set_dont_touch {<design> | <subdesign> | <instance> | <net> | <libcell>} => keeps that object.
      1. ex: set_dont_touch Imtr_a/hs_buf => keeps hs_buf in design as it is. However, nets connected to this buf can be optimized away. To keep the nets untouched too, use this:
      2. ex: set_dont_touch [get_nets -of_objects [get_cells {Imtr_a/hs_buf}]] => all nets connected to hs_buf set to dont_touch. this needed to prevent nets of that cell from getting removed. Otherwise the cell may be there, but it's i/p, o/p nets may be optimized away.
        1. RC equiv => set_attr preserve 1 Imtr_a/hs_buf => .  1/true means dont touch. 0/false means the tool is free to modify it (which is the default case)
  3. set_case_analysis:
  4. set_logic_dc,set_logic_one, set_logic_zero