Coverage Options

  • Explicit (user defined)
    • Fully and clearly expressed within sources
      • Sequence and temporal coverage using assertions
      • Data-oriented coverage using covergroup
    • Planned and defined by the verification team
  • Implicit
    • Derived or computed from source
      • Code coverage measured by the simulator
    • May be defined outside the verification team
    • May be implied by the verification interface
      • e.g., an industry standard protocol

Explicit Coverage in Systemverilog

Assertions for control-oriented coverage

  • Defined as procedural statements
  • CANNOT be defined in a class
1
2
3
4
5
6
7
8
property req_gnt (cyc);
@(posedge clk)
$rose(req) ##0 (req && !gnt)[cyc] ##1 gnt;
endproperty

cover property (req_gnt(3));
cover property (req_gnt(4));
cover property (req_gnt(5));

Control-oriented coverage uses SystemVerilog Assertion (SVA) syntax and the cover directive. It is used to cover sequences of signal values over time. Assertions cannot be declared or "covered" in a class declaration, so their use in an UVM verification environment is restricted to interface only

Covergroup for data-oriented coverage

  • CAN be declared as a class member and created in class constructor
  • Used in interface and module UVCs
1
2
3
4
5
6
7
8
9
10
covergroup cg @(posedge clk);
len: coverpoint pkt.lenght {
illegal_bins zero = {0};
bins sml = {[1:10]}
...
}
addrxlen : cross pkt.addr, len;
endgroup

cg cg1 = new();

Data-oriented coverage uses the covergroup construct. Covergroups can be declared and created in classes, therefore they are essential for explicit coverage in a UVM verification environment.

Interface Monitor Coverage

covergroup new constructor is called directly off the declaration of the covergroup, it does not have a separate instance name

1
collected_pkts_cq = new();

The covergroup instance must be created in the class constructor, not a UVM build_phase or other phase method

image-20220403210225837

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class yapp_tx_monitor extends uvm_monitor;
// constructor

covergroup collected_pkts_cg;
...
endgroup

yapp_packet packet_collected;

task run_phase(uvm_phase phase);
collect_packet();
...
endtask

task collect_packet();
// read RTL signals via interface
// reconstruct packet
collected_pkts_cg.sample();
...
endtask

...
endclass

Module UVC Coverage

Typical module UVC coverage:

  • Routing - packets flow from input ports to all legal outputs
  • latency - all packets received within speicied delay

The module UVC monitor receives data from the interface monitors via analysis ports, so the implementation of the analysis write function is a convenient place to put coverage code

image-20220403212529981

image-20220403094350570

image-20220403094404891

  • Blocking methods are defined with get() or put() tasks to allow them to consume time
  • Non-blocking methods are defined with try_get() or try_put() functions as they execute in zero time

Uni-Directional TLM Methods Reference

Method Description Syntax
put() Blocking put virtual task put(iput TR t);
try_put() Nonblocking put
-return 1 if successful
-return 0 if not
virtual function bit try_put(input TR t);
can_put() Nonblocking test put
-return 1 if put would be successful
-return 0 if not
virtual function bit can_put();
get() Blocking get virtual task get(output TR t);
try_get() Nonblocking get
-return 1 if successful
-return 0 if not
virtual function bit try_get(output TR t);
can_get() Nonblocking test get
-return 1 if get would be successful
-return 0 if not
virtual function bit can_get();
peek() Blocking peek virtual task peek(output TR t);
try_peek() Nonblocking peek
-return 1 if successful
-return 0 if not
virtual function bit try_peek(output TR t);
can_peek Nonblocking test peek
-return 1 if peek would be successful
-return 0 if not
virtual function bit can_peek();

The peek() methods are similarly to the get() methods, but copy the transaction instead of removing it. The transaction is not consumed, and a subsequent get or peek operation will return the same transaction

Selected Connector and Method Options

put try_put can_put get try_get can_get peek try_peed can_peek
uvm_put_*
uvm_blocking_put_*
uvm_nonblocking_put_*
uvm_get_*
uvm_blocking_get_*
uvm_nonblocking_get_*
uvm_get_peek_*
uvm_blocking_get_peek_*
uvm_nonblocking_get_peek_*

in the connectors above, * can be replaced by port, imp, or export

All the methods for a specific connector type MUST be implemented. If you define an uvm_put connection between two compoents, then the component with the uvm_put_imp object must provide implementations of ALL three put methods, put, try_put and can_put, even if these methods are not explicitly called

TLM FIFO

The TLM FIFO is a FIFO component wrapped in get and put imp connectors. This has the benefit of data storage as well as providing implementations of the communication methods. Components connected to the TLM FIFO are in control of data transfer and can simply defined port connectors to initiate read and write operations on the FIFO

uvm_tlm_fifo

image-20220403141222126

The TLM FIFO object is effectively a FIFO component instantiated between and connected to two components. The FIFO contains imp connectors for the standard TLM put and get/peek interfaces, therefore the user does not have to defineimp ports or communication methods and the FIRO takes care of data storage

The advantages are:

  • The user does not need to define communication methods or imp connectors
  • The FIFO provides data storage between the write (put) and read (get/peek) components
  • There are a number of built-in methods for checking FIFO status

The disadvantages are:

  • The user must now initiate both sides of the transfer (both get/peek and put) to complete the transaction
  • Two connections must be made (both sides of the FIFO) rather than one

The put_export and get_peek_export connection objects have alternatives which provide subsets of the full connector. For example, blocking_put_export and nonblocking_put_export can replace put_export. blocking_get_export, nonblocking_get_export and get_export (as well as others) can replace get_peek_export.

built-in methods

Method Description Syntax
new Standard component constructor with an additional third argument, size, which sets the maximum FIFO size. Default size is 1. A size of 0 is an unbounded FIFO function new(string name, uvm_component parent=null, int size=1);
size Return size of FIFO. 0 indicates unbounded FIFO virtual function int size()
used Return number of entries written to the FIFO virtual function int used();
is_empty Return 1 if used() is 0, otherwise 0 virtual function bit is empty();
is_full Return 1 if used() is equal to size, otherwise 0 virtual function bit is_full()
flush Delete all entries from the FIFO, upon which used() is 0 and is_empty() is 1 virtual funciton void flush();
1
2
3
class uvm_tlm_fifo #(type T=int) extends uvm_tlm_fifo_base #(T);
...
endclass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
virtual class uvm_tlm_fifo_base #(type T=int) extends uvm_component;
uvm_put_imp #(T, this_type) put_export;

uvm_get_peek_imp #(T, this_type) get_peek_export;

uvm_analysis_port #(T) put_ap;

uvm_analysis_port #(T) get_ap;

// The following are aliases to the above put_export
uvm_put_imp #(T, this_type) blocking_put_export;
uvm_put_imp #(T, this_type) nonblocking_put_export;

// The following are all aliased to the above get_peek_export, which provides
// the superset of these interfaces.
uvm_get_peek_imp #(T, this_type) blocking_get_export;
uvm_get_peek_imp #(T, this_type) nonblocking_get_export;
uvm_get_peek_imp #(T, this_type) get_export;

uvm_get_peek_imp #(T, this_type) blocking_peek_export;
uvm_get_peek_imp #(T, this_type) nonblocking_peek_export;
uvm_get_peek_imp #(T, this_type) peek_export;

uvm_get_peek_imp #(T, this_type) blocking_get_peek_export;
uvm_get_peek_imp #(T, this_type) nonblocking_get_peek_export;

function new(string name, uvm_component parent = null);
super.new(name, parent);

put_export = new("put_export", this);
blocking_put_export = put_export;
nonblocking_put_export = put_export;

get_peek_export = new("get_peek_export", this);
blocking_get_peek_export = get_peek_export;
nonblocking_get_peek_export = get_peek_export;
blocking_get_export = get_peek_export;
nonblocking_get_export = get_peek_export;
get_export = get_peek_export;
blocking_peek_export = get_peek_export;
nonblocking_peek_export = get_peek_export;
peek_export = get_peek_export;

put_ap = new("put_ap", this);
get_ap = new("get_ap", this);

endfunction

Analysis FIFO

uvm_tlm_analysis_fifo

image-20220403144951278

uvm_tlm_analysis_fifo is a specialization of uvm_tlm_fifo

  • Intended to buffer write transactions between the UVC monitor analysis port and scoreboard

It has the following characteristics:

  • Unbounded (size=0)
  • analysis_export connector replaces put_export
    • Support the analysis write method

image-20220403150326750

By declaring the FIFO in the scoreboard, we can get directly from the FIFO output.

However the write side connection of the FIFO to the interface UVC monitor analysis port must be made (usually) in the testbench which has visibility of both UVC and scoreboard components. The connection is made using a connect method call inside the connect phase method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class uvm_tlm_analysis_fifo #(type T = int) extends uvm_tlm_fifo #(T);

// Port: analysis_export #(T)
//
// The analysis_export provides the write method to all connected analysis
// ports and parent exports:
//
//| function void write (T t)
//
// Access via ports bound to this export is the normal mechanism for writing
// to an analysis FIFO.
// See write method of <uvm_tlm_if_base #(T1,T2)> for more information.

uvm_analysis_imp #(T, uvm_tlm_analysis_fifo #(T)) analysis_export;


// Function: new
//
// This is the standard uvm_component constructor. ~name~ is the local name
// of this component. The ~parent~ should be left unspecified when this
// component is instantiated in statically elaborated constructs and must be
// specified when this component is a child of another UVM component.

function new(string name , uvm_component parent = null);
super.new(name, parent, 0); // analysis fifo must be unbounded
analysis_export = new("analysis_export", this);
endfunction

const static string type_name = "uvm_tlm_analysis_fifo #(T)";

virtual function string get_type_name();
return type_name;
endfunction

function void write(input T t);
void'(this.try_put(t)); // unbounded => must succeed
endfunction

endclass

Analysis Port Broadcast

image-20220403152922101

Analysis ports can (uniquely) be connected to any number of imp connectors, including zero

image-20220403153148158

The analysis port in component yapp_monitor will be connected to both monitor_one and monitor_two components. Each of the receiving components has an analysis imp object and a write communication method declared. The write method must have the same signature - i.e., they must be void functions called write with a single input argument of type yapp_packet, but their implementations can be completely different.

When the send_yapp port is connected to both mone_in and mtwo_in imps, then a single write call from yapp_monitor executes both write implementations in monitor_one and monitor_two

image-20220403153742706

For non-analysis connections

  • the TLM object must be connected to a single destination only, i.e., each non-analysis object has exactly one connect call. An object may be used multiple times as the argument to a connect, but exactly once as the caller. This is called many-to-one connection. For example, many ports can be connected to a one imp connector

For analysis connections

  • a TLM object can be connected to any number of destinations i.e., one analysis object can call connect many times. This is called one-to-many connection. For example, one port can be connected to many imp connectors. one-to-many is only allowed for analysis connections. An analysis connection can also NOT call connect. An unconnected TLM object is also only allowed for analysis connections

Bi-Directional TLM Transport Connection

image-20220403160248099

Connector syntax

1
2
3
uvm_blocking_transport_XXX #(type REA, type RSP)
uvm_nonblocking_transport_XXX #(type REQ, type RSP)
uvm_transport_XXX #(type REQ, type RSP)

Communication methods

1
2
task transport(REQ request, output RSP response)
function bit nb_transport(REQ request, output RSP response)

Gotchas

FIFO/analysis FIFOs do not perform any cloning on input transactions. Therefore, you will need to check that the UVC monitors collect every transaction into a different instance to avoid overwriting data in the FIFOs

imp and port connectors are sufficient for modeling most connections, but there is third connector, export, which is used exclusively in hierarchical connections.

Normally hierarchical routing is not required. A port on an UVC monitor can be connected directly to an imp in a scoreboard by specifying full hierarchical pathname (e.g., env.agent.monitor.analysis_port). The structure of an UVC is fixed and so the user knows to look in the monitor component for the analysis ports.

However the internal hierarchy of a module UVC is more arbitrary, and it may be convenient to route all the module UVC connectors to the top level to allow use without knowledge of the internal structure.

On the initiator side

  • ports are routed up the hierarchy via other port instances

On the target side

  • only the component which defines the communication method is allowed to have an imp instance. So we need a third object to route connections up the target side hierarchy - export

The hierarchical route must be connected at each level in the direction of control flow:

1
initiator.connect(target)

Connection rules are as follows:

  • port initiators can be connected to port, export or imp targets
  • export initiators can be connected to export or imp targets
  • imp cannot be connection initiator. imp is target only and is always the last connection object on a route

uvm_analysis_port

1
2
3
class uvm_analysis_port # (
type T = int
) extends uvm_port_base # (uvm_tlm_if_base #(T,T))

uvm_analysis_port

1
2
3
class uvm_analysis_port # (
type T = int
) extends uvm_port_base # (uvm_tlm_if_base #(T,T))

uvm_analysis_imp

1
2
3
4
class uvm_analysis_imp #(
type T = int,
type IMP = int
) extends uvm_port_base #(uvm_tlm_if_base #(T,T))

QA

  1. What are the three distinct functions of a scoreboard?

    Reference model, expected data storage and comparison

  2. To how many consumer components can an analysis port be connected?

    Any number, including zero

  3. What are the names of the two declarations made available by the following macro:

    1
    `uvm_analysis_imp_decl(_possible)

    Subclass uvm_analysis_imp_possible

    Method write_possible

  4. Why should a scoreboard clone the data received by a write method?

    The write method only sends a reference, therefore if the sending component uses the same reference for every data item, overwriting of data in the storage function of the scoreboard is possible without cloning.

Problem

There is no network connection and device is not managed

1
2
3
4
$ nmcli device status
DEVICE TYPE STATE CONNECTION
eth0 ethernet unmanaged --
lo loopback unmanaged --

image-20220401011509900

solution

1
sudo nmcli networking on

Then, eth0 is connected

1
2
3
4
$ nmcli device status
DEVICE TYPE STATE CONNECTION
eth0 ethernet connected Ethernet connection 1
lo loopback unmanaged --

image-20220401011543866

topo.drawio

compile

  • -incdir for all UVC's `include
  • all pkg.sv
  • all if.sv
  • all RTL DUT
  • uvm top module

uvm top.sv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
module tb_top;

// import the UVM library
import uvm_pkg::*;

// include the UVM macros
`include "uvm_macros.svh"

// import the yapp UVC
import yapp_pkg::*;
import hbus_pkg::*;
import channel_pkg::*;
import clock_and_reset_pkg::*;

// include the test library file
`include "router_tb.sv"
`include "router_test_lib.sv"

initial begin
yapp_vif_config::set(null, "uvm_test_top.tb.yapp.tx_agent.*", "vif", hw_top.in0);
hbus_vif_config::set(null, "uvm_test_top.tb.hbus.*", "vif", hw_top.hif );
channel_vif_config::set(null, "uvm_test_top.tb.chan0.*", "vif", hw_top.ch0);
channel_vif_config::set(null, "uvm_test_top.tb.chan1.*", "vif", hw_top.ch1);
channel_vif_config::set(null, "uvm_test_top.tb.chan2.*", "vif", hw_top.ch2);
clock_and_reset_vif_config::set(null, "uvm_test_top.tb.clock_and_reset.*", "vif", hw_top.clk_rst_if);
run_test();
end


endmodule : tb_top

RTL top

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
module hw_top;

// Clock and reset signals
logic [31:0] clock_period;
logic run_clock;
logic clock;
logic reset;

// YAPP Interface to the DUT
yapp_if in0(clock, reset);
// reset will now be generated by the Clock and Reset UVC
// input: clock; output: reset, run_clock, clock_period
clock_and_reset_if clk_rst_if(.clock(clock), .reset(reset), .run_clock(run_clock), .clock_period(clock_period));
hbus_if hif(.clock(clock), .reset(reset));

channel_if ch0(.clock(clock), .reset(reset));
channel_if ch1(.clock(clock), .reset(reset));
channel_if ch2(.clock(clock), .reset(reset));

// CLKGEN module generates clock
clkgen clkgen (
.clock(clock),
.run_clock(run_clock),
.clock_period(clock_period)
);

yapp_router dut(
...


endmodule

pkg.sv

`include all related uvm class in pgk.sv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package yapp_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"

typedef uvm_config_db#(virtual yapp_if) yapp_vif_config;

`include "yapp_packet.sv"
`include "yapp_tx_monitor.sv"
`include "yapp_tx_sequencer.sv"
`include "yapp_tx_seqs.sv"
`include "yapp_tx_driver.sv"
`include "yapp_tx_agent.sv"
`include "yapp_env.sv"

endpackage

if.sv

1
2
3
4
5
6
7
8
9
10
11
interface yapp_if (input clock, input reset );
timeunit 1ns;
timeprecision 100ps;

import uvm_pkg::*;
`include "uvm_macros.svh"

import yapp_pkg::*;
...

endinterface : yapp_if

import and compile order

project

yapp_pkg.sv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package yapp_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"

typedef uvm_config_db#(virtual yapp_if) yapp_vif_config;

`include "yapp_packet.sv"
`include "yapp_tx_monitor.sv"
`include "yapp_tx_sequencer.sv"
`include "yapp_tx_seqs.sv"
`include "yapp_tx_driver.sv"
`include "yapp_tx_agent.sv"
`include "yapp_env.sv"

endpackage

yapp_tx_monitor.sv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class yapp_tx_monitor extends uvm_monitor;

// Collected Data handle
yapp_packet pkt;

// Count packets collected
int num_pkt_col;

// component macro
`uvm_component_utils_begin(yapp_tx_monitor)
`uvm_field_int(num_pkt_col, UVM_ALL_ON + UVM_NOCOMPARE)
`uvm_component_utils_end
/////////////////// virtual interface ////////////////////
virtual interface yapp_if vif;
/////////////////////////////////////////////////////////

function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
...

endclass : yapp_tx_monitor

yapp_tx_driver.sv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class yapp_tx_driver extends uvm_driver #(yapp_packet);

////////////////// virtual interface ////////////////////
virtual interface yapp_if vif;
/////////////////////////////////////////////////////

int num_sent;

// component macro
`uvm_component_utils_begin(yapp_tx_driver)
`uvm_field_int(num_sent, UVM_ALL_ON + UVM_NOCOMPARE)
`uvm_component_utils_end

// Constructor - required syntax for UVM automation and utilities
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new

function void start_of_simulation_phase(uvm_phase phase);
`uvm_info(get_type_name(), {"start of simulation for ", get_full_name()}, UVM_HIGH)
endfunction : start_of_simulation_phase
...

endclass : yapp_tx_driver

yapp_if.sv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface yapp_if (input clock, input reset );
timeunit 1ns;
timeprecision 100ps;

import uvm_pkg::*;
`include "uvm_macros.svh"

////////////////// import package //////////////////////
import yapp_pkg::*;
//////////////////////////////////////////////////////

// Actual Signals
logic in_data_vld;
logic in_suspend;
logic [7:0] in_data;

// signal for transaction recording
bit monstart, drvstart;

// local storage for payload
logic [7:0] payload_mem [0:63];
...

endinterface : yapp_if

virtual interface is in package;

yapp_pkg is imported into interface

!!! typedef uvm_config_db#(virtual yapp_if) yapp_vif_config; is forward declaration

A forward typedef declares an identifier as a type in advance of the full definition of that type

VCS compile

1
vcs -full64 -R -sverilog  -ntb_opts uvm-1.2 +UVM_TESTNAME=short_yapp_012_test  -f vcs.f  

vcs.f

1
2
3
4
5
6
7
8
9
-timescale=1ns/1ns

+incdir+../sv

../sv/yapp_if.sv
../sv/yapp_pkg.sv
./clkgen.sv
./hw_top.sv
./tb_top.sv

output ERROR

1
2
3
4
5
6
Error-[SV-LCM-PND] Package not defined
../sv/yapp_if.sv, 18
yapp_if, "yapp_pkg::"
Package scope resolution failed. Token 'yapp_pkg' is not a package.
Originating module 'yapp_if'.
Move package definition before the use of the package.

xrun compile

1
xrun -f xrun.f

xrun.f

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-64

-uvmhome CDNS-1.2

// incdir for include files
-incdir ../sv

+UVM_TESTNAME=short_yapp_012_test

-timescale 1ns/1ns

// compile files
../sv/yapp_if.sv
../sv/yapp_pkg.sv
./clkgen.sv
./hw_top.sv
./tb_top.sv

output Error

1
2
3
4
5
6
file: ../sv/yapp_if.sv
import yapp_pkg::*;
|
xmvlog: *E,NOPBIND (../sv/yapp_if.sv,18|14): Package yapp_pkg could not be bound.
interface worklib.yapp_if:sv
errors: 1, warnings: 0

solution

place ../sv/yapp_pkg.sv before ../sv/yapp_if.sv.

In this particular example, yapp_pkg is NOT needed in interface. just delete import yapp_pkg::* is enough in ../sv/yapp_if.sv

plain example

The order of compilation unit DON'T matter

project

hw_top.sv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
module hw_top;

// Clock and reset signals
logic [31:0] clock_period;
logic run_clock;
logic clock;
logic reset;

// YAPP Interface to the DUT
yapp_if in0(clock, reset);

// CLKGEN module generates clock
clkgen clkgen (
.clock(clock),
.run_clock(1'b1),
.clock_period(32'd10)
);

yapp_router dut(
.reset(reset),
.clock(clock),
.error(),
// YAPP interface signals connection
.in_data(in0.in_data),
.in_data_vld(in0.in_data_vld),
.in_suspend(in0.in_suspend),
// Output Channels
//Channel 0
.data_0(),
.data_vld_0(),
.suspend_0(1'b0),
//Channel 1
.data_1(),
.data_vld_1(),
.suspend_1(1'b0),
//Channel 2
.data_2(),
.data_vld_2(),
.suspend_2(1'b0),
// Host Interface Signals
.haddr(),
.hdata(),
.hen(),
.hwr_rd());

...

endmodule

yapp_router.sv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module yapp_router (input clock,                              
input reset,
output error,

// Input channel
input [7:0] in_data,
input in_data_vld,
output in_suspend,
// Output Channels
output [7:0] data_0, //Channel 0
output reg data_vld_0,
input suspend_0,
output [7:0] data_1, //Channel 1
output reg data_vld_1,
input suspend_1,
output [7:0] data_2, //Channel 2
output reg data_vld_2,
input suspend_2,

// Host Interface Signals
input [15:0] haddr,
inout [7:0] hdata,
input hen,
input hwr_rd);
...
endmodule

compile

place hw_top.sv before or after yapp_router.sv doesn't matter, the compiler (xrun, vcs) can compile them successfully.

Conclusion

Always place package before DUT is preferred choice during compiling.

refernce

class forward declaration

https://vlsiverify.com/uvm/uvm_config_db-in-uvm#Precedence_Rule

Two Precedence rules

There are two precedence rules applicable to uvm_config_db. In the build_phase,

  1. A set() call in a context higher up the component hierarchy takes precedence over a set() call that occurs lower in the hierarchical path.
  2. On having same context field, the last set() call takes precedence over the earlier set() call.

Example for rule - 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
`include "uvm_macros.svh"
import uvm_pkg::*;

class component_A extends uvm_component;
int id;
`uvm_component_utils(component_A)

function new(string name = "component_A", uvm_component parent = null);
super.new(name, parent);
id = 1;
endfunction

function display();
`uvm_info(get_type_name(), $sformatf("inside component_A: id = %0d", id), UVM_LOW);
endfunction
endclass

class component_B extends component_A;
int receive_value;
int id;

`uvm_component_utils(component_B)

function new(string name = "component_B", uvm_component parent = null);
super.new(name, parent);
id = 2;
endfunction

function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db #(int)::get(this, "*", "value", receive_value))
`uvm_fatal(get_type_name(), "get failed for resource in this scope");
endfunction

function display();
`uvm_info(get_type_name(), $sformatf("inside component_B: id = %0d, receive_value = %0d", id, receive_value), UVM_LOW);
endfunction
endclass

class env extends uvm_env;
`uvm_component_utils(env)
component_A comp_A;
component_B comp_B;

function new(string name = "env", uvm_component parent = null);
super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
super.build_phase(phase);
comp_A = component_A ::type_id::create("comp_A", this);
comp_B = component_B ::type_id::create("comp_B", this);

uvm_config_db #(int)::set(this, "*", "value", 200);
endfunction

task run_phase(uvm_phase phase);
super.run_phase(phase);
void'(comp_A.display());
void'(comp_B.display());
endtask
endclass

class my_test extends uvm_test;
bit control;
`uvm_component_utils(my_test)
env env_o;

function new(string name = "my_test", uvm_component parent = null);
super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
super.build_phase(phase);
////////////////////////////////////////////////////
env_o = env::type_id::create("env_o", this); // line 99

uvm_config_db #(int)::set(null, "*", "value", 100); // line 101
////////////////////////////////////////////////////
endfunction

function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
uvm_top.print_topology();
endfunction
endclass

module tb_top;
initial begin
run_test("my_test");
end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
UVM_INFO /xcelium20.09/tools//methodology/UVM/CDNS-1.2/sv/src/base/uvm_root.svh(605) @ 0: reporter [UVMTOP] UVM testbench topology:
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top my_test - @1810
env_o env - @1877
comp_A component_A - @1922
comp_B component_B - @1953
--------------------------------------

UVM_INFO testbench.sv(14) @ 0: uvm_test_top.env_o.comp_A [component_A] inside component_A: id = 1
UVM_INFO testbench.sv(36) @ 0: uvm_test_top.env_o.comp_B [component_B] inside component_B: id = 2, receive_value = 100

As you can see , the uvm_config_db::set is after the factory type_id::create, but receive_value is still 100, I believe that build_phase of upper hierarchy finish first before create lower components.

But the recommendation in literature and many web is place uvm_config_db::set before create

Simple Example for rule - 2

1
2
uvm_config_db #(int)::set(null, "*", "value", 100);
uvm_config_db #(int)::set(null, "*", "value", 200);

[complete code]

1
2
3
4
5
6
7
8
9
10
11
12
UVM_INFO /xcelium20.09/tools//methodology/UVM/CDNS-1.2/sv/src/base/uvm_root.svh(605) @ 0: reporter [UVMTOP] UVM testbench topology:
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top my_test - @1810
env_o env - @1877
comp_A component_A - @1924
comp_B component_B - @1955
--------------------------------------

UVM_INFO testbench.sv(14) @ 0: uvm_test_top.env_o.comp_A [component_A] inside component_A: id = 1
UVM_INFO testbench.sv(36) @ 0: uvm_test_top.env_o.comp_B [component_B] inside component_B: id = 2, receive_value = 200

Another Example for rule - 2

The set in super.build_phase and set in current build_phase are at the same hierarchy, so rule-2 apply

base_test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class base_test extends uvm_test;

// component macro
`uvm_component_utils(base_test)

router_tb tb;

// component constructor
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction : new

// UVM build_phase()
function void build_phase(uvm_phase phase);
super.build_phase(phase);
uvm_config_int::set(this, "*", "recording_detail", 1);
uvm_config_wrapper::set(this, "tb.yapp.tx_agent.sequencer.run_phase",
"default_sequence",
yapp_5_packets::get_type());
tb = router_tb::type_id::create("tb", this);
endfunction : build_phase

endclass : base_test

test2 - One

yapp_incr_payload_seq override the yapp_5_packets in super.build_phase(phase), yapp_incr_payload_seq is used.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class test2 extends base_test;

// component macro
`uvm_component_utils(test2)

// component constructor
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction : new

function void build_phase(uvm_phase phase);
yapp_packet::type_id::set_type_override(short_yapp_packet::get_type());
super.build_phase(phase);
uvm_config_wrapper::set(this, "tb.yapp.tx_agent.sequencer.run_phase",
"default_sequence",
yapp_incr_payload_seq::get_type());
endfunction : build_phase

endclass : test2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---------------------------------------------------------------------------------------------------------------------                   
Name Type Size Value
---------------------------------------------------------------------------------------------------------------------
req short_yapp_packet - @3045
length integral 6 'h5
addr integral 2 'h1
payload da(integral) 5 -
[0] integral 8 'h0
[1] integral 8 'h1
[2] integral 8 'h2
[3] integral 8 'h3
[4] integral 8 'h4
parity integral 8 'h11
parity_type parity_t 1 GOOD_PARITY
packet_delay integral 32 'd19
begin_time time 64 0
depth int 32 'd2
parent sequence (name) string 21 yapp_incr_payload_seq
parent sequence (full name) string 61 uvm_test_top.tb.yapp.tx_agent.sequencer.yapp_incr_payload_seq
sequencer string 39 uvm_test_top.tb.yapp.tx_agent.sequencer
---------------------------------------------------------------------------------------------------------------------

test2 - Two

the yapp_5_packets in super.build_phase(phase) overide yapp_incr_payload_seq in test2's build_phase, yapp_5_packets is used

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class test2 extends base_test;

// component macro
`uvm_component_utils(test2)

// component constructor
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction : new

function void build_phase(uvm_phase phase);
yapp_packet::type_id::set_type_override(short_yapp_packet::get_type());
uvm_config_wrapper::set(this, "tb.yapp.tx_agent.sequencer.run_phase",
"default_sequence",
yapp_incr_payload_seq::get_type());
super.build_phase(phase);
endfunction : build_phase

endclass : test2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
--------------------------------------------------------------------------------------------------------------                          
Name Type Size Value
--------------------------------------------------------------------------------------------------------------
req short_yapp_packet - @3176
length integral 6 'h6
addr integral 2 'h1
payload da(integral) 6 -
[0] integral 8 'h4f
[1] integral 8 'hbe
[2] integral 8 'hb
[3] integral 8 'h1d
[4] integral 8 'h72
[5] integral 8 'hc5
parity integral 8 'h49
parity_type parity_t 1 GOOD_PARITY
packet_delay integral 32 'd0
begin_time time 64 40
depth int 32 'd2
parent sequence (name) string 14 yapp_5_packets
parent sequence (full name) string 54 uvm_test_top.tb.yapp.tx_agent.sequencer.yapp_5_packets
sequencer string 39 uvm_test_top.tb.yapp.tx_agent.sequencer
--------------------------------------------------------------------------------------------------------------

The Laplace transform converts integro-differential equations into algebraic equations - continuous-time systems

The z-transforms changes difference equations into algebraic equations - discrete-time systems

FIR Equalization

Frequency Response

image-20220322093428287 \[ z = e^{j\omega T_s} \]

Unit impulse

filter coefficients are [-0.131, 0.595, -0.274] and sampling period is 100ps

image-20220428125454912

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
%% Frequency response
w = [-0.131, 0.595, -0.274];
Ts = 100e-12;
[mag, w] = freqz(w, 1, [], 1/Ts);
subplot(2, 1, 1)
plot(w/1e9, 20*log10(abs(mag)));
xlabel('Freq(GHz)');
ylabel('dB');
grid on;
title('frequency response');

%% unit impulse response from transfer function
subplot(2, 1, 2)
z = tf('z', Ts);
h = -0.131 + 0.595*z^(-1) -0.274*z^(-2);
[y, t] = impulse(h);
stem(t*1e10, y*Ts); % !!! y*Ts is essential
grid on;
title("unit impulse response");
xlabel('Time(\times 100ps)');
ylabel('mag');

impulse:

For discrete-time systems, the impulse response is the response to a unit area pulse of length Ts and height 1/Ts, where Ts is the sample time of the system. (This pulse approaches \(\delta(t)\) as Ts approaches zero.)

Scale output:

Multiply impulse output with sample period Ts in order to correct 1/Ts height of impulse function.

PSD transformation

If we have power spectrum or power spectrum density of both edge's absolute jitter (\(x(n)\)) , \(P_{\text{xx}}\)

Then 1UI jitter is \(x_{\text{1UI}}(n)=x(n)-x(n-1)\), and Period jitter is \(x_{\text{Period}}(n)=x(n)-x(n-2)\), which can be modeled as FIR filter, \(H(\omega) = 1-z^{-k}\), i.e. \(k=1\) for 1UI jitter and \(k=2\) Period jitter \[\begin{align} P_{\text{xx}}'(\omega) &= P_{\text{xx}}(\omega) \cdot \left| 1-z^{-k} \right|^2 \\ &= P_{\text{xx}}(\omega) \cdot \left| 1-(e^{j\omega T_s})^{-k} \right|^2 \\ &= P_{\text{xx}}(\omega) \cdot \left| 1-e^{-j\omega T_s k} \right|^2 \end{align}\]

image-20220519172239916

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
clear all
close all
clc

xf_fs = 0:0.01:0.5;
k = 1;
H_1UI = 1 - exp(-1i*2*pi*xf_fs);
HH_1UI = abs(H_1UI).^2;
subplot(2, 1, 1);
plot(xf_fs, HH_1UI);
grid on;
xlabel('Freq');
ylabel('|H|^2')
title('Weight for 1UI jitter');

k = 2;
H_period = 1 - exp(-1i*2*pi*xf_fs);
HH_period = abs(H_period).^2;
subplot(2, 1, 2)
plot(xf_fs, HH_period);
grid on;
xlabel('Freq');
ylabel('|H|^2')
title('Weight for Period jitter');

image-20220709104127384 \[ x(t-\Delta T)\overset{FT}{\longrightarrow} X(s)e^{-\Delta T \cdot s} \]

reference

Sam Palermo, ECEN720, Lecture 7: Equalization Introduction & TX FIR Eq

Sam Palermo, ECEN720, Lab5 –Equalization Circuits

B. Razavi, "The z-Transform for Analog Designers [The Analog Mind]," IEEE Solid-State Circuits Magazine, Volume. 12, Issue. 3, pp. 8-14, Summer 2020.

Jhwan Kim, CICC 2022, ES4-4: Transmitter Design for High-speed Serial Data Communications

Mathuranathan. Digital filter design – Introduction https://www.gaussianwaves.com/2020/02/introduction-to-digital-filter-design/

Most user-defined UVM classes are placed in separate files

Classes can only be compiled from a module or package scope

Recommendation:

  • Include related class files into a package
  • Import the package into modules where required

The UVM library is supplied in the package uvm_pkg

  • Import package to access library
  • The macro file uvm_macros.svh must be included separately

yapp_packet.sv

1
2
3
class yapp_packet extends uvm_sequence_item;
...
endclass : yapp_packet

yapp_pkg.sv

1
2
3
4
5
6
package  yapp_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"

`include "yapp_packet.sv"
endpackage : yapp_pkg

run.f for xrun

1
2
3
4
5
6
7
8
9
10
11
// 64 bit option for AWS labs
-64

-uvmhome CDNS-1.2

// include directories
-incdir ../sv

// compile files
../sv/yapp_pkg.sv
./top.sv

  • Broaden the bandwidth
  • Create a constant, resistive input impedance in the presence of a heavy load capacitance (ESD protection circuit)

L1 = L2 for impedance matching

The use of T-coils can dramatically increase the bandwidth and improve the return loss in both TXs and RXs.

image-20240712234028634

equivalent circuit

image-20240713001415948

image-20240713011127116

image-20240713011152541

Note the negative sign of \(L_M\), which is a consequence of magnetic coupling; owing to this, the driving impedance at the center tap as seen by \(C\) is lower than without the coupling.

\[\begin{align} Z_{c} &= sL_a/2 -sL_M = sL/2 - sL_M/2 \\ Z_{noc} &= sL/2 \end{align}\]

Bridged T-Coil

The vertical stacking of the inductor halves causes a significant bridging capacitance \(C_B\)​ between them.

The most important aspect is that \(C_B\) does not prohibit perfect impedance matching but can be used to tune certain transfer functions.

Tcoil in RX

image-20220502201254057

ppwl: Independent Piece-Wise Linear Resistive Source

image-20220502201321341

simple model

L1, L2, Km, Cb

image-20220502215310947

image-20220622224842237

image-20220622225709712

lumped model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
simulator lang=spectre
include "/path/to/INDL0.scs"
subckt for_import(p0 p1 p2 gnd)
xmod (p0 p1 p2 gnd) INDL0
ends for_import

x_1 (p_1_1 p_1_2 p_1_3 0) for_import
v_1_1 (p_1_1 0) vsource mag=-1
v_1_2 (p_1_2 0) vsource mag=0
v_1_3 (p_1_3 0) vsource mag=0
save v_1_1:p v_1_2:p v_1_3:p

x_2 (p_2_1 p_2_2 p_2_3 0) for_import
v_2_1 (p_2_1 0) vsource mag=0
v_2_2 (p_2_2 0) vsource mag=-1
v_2_3 (p_2_3 0) vsource mag=0
save v_2_1:p v_2_2:p v_2_3:p

x_3 (p_3_1 p_3_2 p_3_3 0) for_import
v_3_1 (p_3_1 0) vsource mag=0
v_3_2 (p_3_2 0) vsource mag=0
v_3_3 (p_3_3 0) vsource mag=-1
save v_3_1:p v_3_2:p v_3_3:p
Y ac start=1.000000e+08 stop=2.000000e+10 step=1.000000e+08

xsp (p_1 p_2 p_3 0) for_import
port1 (p_1 0) port
port2 (p_2 0) port
port3 (p_3 0) port
S sp start=1.000000e+08 stop=2.000000e+10 step=1.000000e+08 ports=[ port1 port2 port3]

image-20220503005728763

image-20220503005903105

EMX_plot_tcoil in emxform.ils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
(define (EMX_plot_tcoil bgui wid what)
(needNCells 'adtComplex 100000)
(letseq ((to_z (lambda (ys)
(letseq ((y11 (EMX_matrix_ref ys 0 0))
(y12 (EMX_matrix_ref ys 0 1))
(y21 (EMX_matrix_ref ys 1 0))
(y22 (EMX_matrix_ref ys 1 1))
(det y11*y22-y12*y21)
(z11 y22/det)
(z12 -y12/det)
(z22 y11/det))
(list z11 z12 z22))))
(ground
(lambda (y p)
(letseq ((n (EMX_matrix_rows y))
(yg (make_EMX_matrix n-1)))
(do ((i 0 i+1))
((i >= n-1))
(do ((j 0 j+1))
((j >= n-1))
(EMX_matrix_set yg i j (EMX_matrix_ref y i+(if (i >= p) 1 0) j+(if (j >= p) 1 0)))))
yg)))
(reduce
(lambda (yys)
(letseq ((xvec (drGetWaveformXVec (car yys)))
(n (drVectorLength xvec))
(yyvecs (mapcar drGetWaveformYVec yys))
(zz1 (drCreateVec 'doublecomplex n))
(zz2 (drCreateVec 'doublecomplex n))
(zz3 (drCreateVec 'doublecomplex n)))
(do ((i 0 i+1))
((i >= n))
(let ((ys (mapcar (lambda (w) (drGetElem w i)) yyvecs)))
(setq ys (ground (as_EMX_matrix 3 3 ys) 2))
(let ((zz (to_z ys)))
(drSetElem zz1 i (nth 0 zz))
(drSetElem zz2 i (nth 1 zz))
(drSetElem zz3 i (nth 2 zz)))))
(list (drCreateWaveform xvec zz1)
(drCreateWaveform xvec zz2)
(drCreateWaveform xvec zz3)))))
(get_k
(lambda (l12 l1122)
(letseq ((xvec (drGetWaveformXVec l12))
(n (drVectorLength xvec))
(l12v (drGetWaveformYVec l12))
(l1122v (drGetWaveformYVec l1122))
(resultv (drCreateVec 'double n)))
(do ((i 0 i+1))
((i >= n))
(letseq ((l12i (drGetElem l12v i))
(l1122i (drGetElem l1122v i))
(kk (if (l1122i > 0.0)
l12i/(sqrt l1122i)
0.0))
(k (if ((abs kk) < 2.0) kk 0.0)))
(drSetElem resultv i k)))
(drCreateWaveform xvec resultv)))))
(EMX_plot_aux bgui wid what 3
'("Inductance" "Q" "k")
'("Henry" "" "")
(lambda (ys)
(letseq ((zs (reduce ys))
(z11 (nth 0 zs))
(z12 (nth 1 zs))
(z22 (nth 2 zs))
(pi 3.14159265358979)
(f (xval z11))
(l11 (imag z11)/(2*pi*f))
(q11 (imag z11)/(real z11))
(l12 (imag z12)/(2*pi*f))
(l22 (imag z22)/(2*pi*f))
(q22 (imag z22)/(real z22))
(k (get_k l12 l11*l22)))
`((,l11 ,l22) (,q11 ,q22) (,k))))
'(("L1" "L2") ("Q1" "Q2") ("k")))))

Tcoil vs tapped inductor

tcoil and tapped inductor share same EM simulation result, and use modelgen with different model formula.

The relationship is \[ L_{\text{sim}} = L1_{\text{sim}}+L2_{\text{sim}}+2\times k_{\text{sim}} \times \sqrt{L1_{\text{sim}}\cdot L2_{\text{sim}}} \] where \(L1_{\text{sim}}\), \(L2_{\text{sim}}\) and \(k_{\text{sim}}\) come from tcoil model result, \(L_{\text{sim}}\) comes from tapped inductor model result

\(k_{\text{sim}}\) in EMX have assumption, induce current from P1 and P2 Given Dot Convention:

Same direction : k > 0

Opposite direction : k < 0

So, the \(k_{\text{sim}}\) is negative if routing coil in same direction

image-20220623013225554

image-20220623013923263

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
% EMX - shield tcoil model
L1 = csvread('./L1sim.csv', 1, 0);
L2 = csvread('./L2sim.csv', 1, 0);
k = csvread('./ksim.csv', 1, 0);

% EMX - Tapped shield inductor
L = csvread('./Lsim.csv', 1, 0);

freq = L1(:, 1)/1e9; % GHz
L1 = L1(:, 2);
L2 = L2(:, 2);
k = -k(:, 2); % Caution: minus of EMX ksim due to same current direction

L = L(:, 2);

Lcalc = L1 + L2 + 2*k.*(L1.*L2).^0.5;

plot(freq, L*1e9, 'r', 'LineWidth', 3);
hold on;
plot(freq, Lcalc*1e9, '--b', 'LineWidth', 3);
grid on;
xlabel('Freq (GHz)');
ylabel('Inductance (nH)');
legend('Tapped inductor model', 'tcoil model calc');

电磁感应定律 (electromagnetic induction)

任何封闭电路中感应电动势大小,等于穿过这一电路磁通量的变化率。 \[ \epsilon = -\frac{d\Phi_B}{dt} \] 其中 \(\epsilon\)是电动势,单位为伏特

\(\Phi_B\)是通过电路的磁通量,单位为韦伯

电动势的方向(公式中的负号)由楞次定律决定

楞次定律: 由于磁通量的改变而产生的感应电流,其方向为抗拒磁通量改变的方向。

在回路中产生感应电动势的原因是由于通过回路平面的磁通量的变化,而不是磁通量本身,即使通过回路的磁通量很大,但只要它不随时间变化,回路中依然不会产生感应电动势。

自感电动势

当电流\(I\)随时间变化时,在线圈中产生的自感电动势为 \[ \epsilon = -L\frac{dI}{dt} \]

image-20240713131201618

image-20240713145315890

image-20240713145343423

image-20240713145005306

image-20240713145212327


image-20240713140911612

image-20240713135148710

image-20240713135236291

同名端:当两个电流分别从两个线圈的对应端子流入 ,其所 产生的磁场相互加强时,则这两个对应端子称为同名端。

image-20240713142238398

image-20240713142249362

image-20240713142506673

reference

S. Shekhar, J. S. Walling and D. J. Allstot, "Bandwidth Extension Techniques for CMOS Amplifiers," in IEEE Journal of Solid-State Circuits, vol. 41, no. 11, pp. 2424-2439, Nov. 2006

David J. Allstot Bandwidth Extension Techniques for CMOS Amplifiers

B. Razavi, "The Bridged T-Coil [A Circuit for All Seasons]," IEEE Solid-State Circuits Magazine, Volume. 7, Issue. 40, pp. 10-13, Fall 2015.

B. Razavi, "The Design of Broadband I/O Circuits [The Analog Mind]," IEEE Solid-State Circuits Magazine, Volume. 13, Issue. 2, pp. 6-15, Spring 2021.

S. Galal and B. Razavi, "Broadband ESD protection circuits in CMOS technology," in IEEE Journal of Solid-State Circuits, vol. 38, no. 12, pp. 2334-2340, Dec. 2003, doi: 10.1109/JSSC.2003.818568.

M. Ker and Y. Hsiao, "On-Chip ESD Protection Strategies for RF Circuits in CMOS Technology," 2006 8th International Conference on Solid-State and Integrated Circuit Technology Proceedings, 2006, pp. 1680-1683, doi: 10.1109/ICSICT.2006.306371.

M. Ker, C. Lin and Y. Hsiao, "Overview on ESD Protection Designs of Low-Parasitic Capacitance for RF ICs in CMOS Technologies," in IEEE Transactions on Device and Materials Reliability, vol. 11, no. 2, pp. 207-218, June 2011, doi: 10.1109/TDMR.2011.2106129.

Bob Ross, "T-Coil Topics" DesignCon IBIS Summit 2011

Ross, Bob and Cong Ling. “Wang Algebra: From Theory to Practice.” IEEE Open Journal of Circuits and Systems 3 (2022): 274-285.

S. Lin, D. Huang and S. Wong, "Pi Coil: A New Element for Bandwidth Extension," in IEEE Transactions on Circuits and Systems II: Express Briefs, vol. 56, no. 6, pp. 454-458, June 2009

Starič, Peter and Erik Margan. “Wideband amplifiers.” (2006).

Kosnac, Stefan (2021) Analysis of On-Chip Inductors and Arithmetic Circuits in the Context of High Performance Computing [https://archiv.ub.uni-heidelberg.de/volltextserver/30559/1/Dissertation_Stefan_Kosnac.pdf]

0%