primary clocks

  • Primary clocks should be created at input ports and output pins of black boxes.
  • Never create clocks on hierarchy pins. Creating clocks on hierarchy will cause problems when reading SDF. The net timing arc becomes segmented at the hierarchy and PrimeTime will be unable to annotate the net successfully.

generated clocks

  • Generated clocks are generally created for waveform modifications of a primary clock (not including simple inversions). PrimeTime does not simulate a design and thus will not derive internally generated clocks automatically - these clocks must be created by the user and applied as a constraint.
  • PrimeTime caculate source latency for generated clocks if primary clock is propagated, otherwise its source latency is zero.
1
2
3
4
5
# primary clock
create_clock -period 4 [get_ports Clk]
set_clock_latency -source 2 [get_clocks Clk]
set_propagated_clock [get_clocks Clk]
create_generated_clock -divide_by 2 -name div_clk -source [get_ports Clk] FF3/Q

virtual clocks

  • Are clock objects without a source
  • Do not clock sequential devices within the current_design
  • Serve as references of input or output delays
1
2
3
4
# create a virtual clock, vclk, for input and output delay constraints
create_clock -period 5 -name vclk
set_input_delay -max 2 -clock vclk [get_ports in1]
set_output_delay -max 1 -clock vclk [get_ports out2]

There is no network latency to calculate, even if a virtual clock is propagated.

Mechanism in UVM-1.1

1
2
3
4
5
function void test_base::start_of_simulation_phase(uvm_phase phase);
super.start_of_simulation_phase(phase);
uvm_top.print_topology(); // Will not compile in UVM-1.2
factory.print(); // Will not compile in UVM-1.2
endfunction

Global handles uvm_top and factory in uvm_pkg have been removed in UVM-1.2 and later

Mechanism in UVM-1.1 and UVM-1.2

Call the get() method of the class to retrieve the singleton handle.

1
2
3
4
5
function void test_base::start_of_simulation_phase(uvm_phase phase);
super.start_of_simulation_phase(phase);
uvm_root::get().print_topology(); // Works in UVM-1.1 & UVM-1.2
uvm_factory::get().print(); // Works in UVM-1.1 & UVM-1.2
endfunction

Mechanism Only in UVM-1.2

1
2
3
4
5
function void test_base::start_of_simulation_phase(uvm_phase phase);
uvm_coreservice_t cs = uvm_coreservice_t::get();
cs.get_root().print_topology();
cs.get_factory().print();
endfunction

uvm_coreservice_t is the uvm-1.2 mechanism for accessing all the central UVM services such as uvm_root,uvm_factory, uvm_report_server, etc.

1
2
3
4
5
6
7
// Using the uvm_coreservice_t:
uvm_coreservice_t cs;
uvm_factory f;
uvm_root top;
cs = uvm_coreservice_t::get();
f = cs.get_factory();
top = cs.get_root();

Topology of the test

1
2
3
function void test_base::start_of_simulation_phase(uvm_phase phase);
uvm_root::get().print_topology(); // defaults to table printer
endfunction

The default printer policy is uvm_default_table_printer

There are three default printer policies that the uvm_pkg provides:

uvm_default_table_printer uvm_default_tree_printer uvm_default_line_printer

Check all configuration settings

Check all configuration settings in a components configuration table to determine if the setting has been used, overridden or not used. When recurse is 1 (default), configuration for this and all child components are recursively checked. This function is automatically called in the check phase, but can be manually called at any time.

To get all configuration information prior to the run phase, do something like this in your top object:

1
2
3
function void start_of_simulation_phase(uvm_phase phase);
check_config_usage();
endfunction

UVM phase

image-20220221230440017

  • Functions are executed bottom-up (Except for build and final phases , which are executed top-down)
  • Tasks are forked into concurrent executing threads

Objections are handled in pre/post body decalared in a base sequence class

This is efficient for all sequence execution options:

  • Default sequences use body objections

  • Test sequences use test objections

  • Subsequences use objections of the root sequence which calls them

1
2
3
4
5
6
7
8
9
10
11
12
13
class yapp_base_seq extends uvm_sequence#(yapp_packet);

task pre_body();
if(starting_phase != null);
starting_phase.raise_objection(this, get_type_name());
endtask
task post_body();
if(starting_phase != null);
starting_phase.drop_objection(this, get_type_name());
endtask

class yapp012 extends yapp_base_seq;

Set as default sequence of sequencer:

A default sequence is a root sequence, so the pre/post body methods are executed and objection are raised/dropped there

Test sequence:

A test sequence is a root sequence, so the pre/post body methods are executed. However, for a test sequence, starting_phase is null and so the objection is not handled in the sequence. The test must raise and drop objections

Subsequence:

Not a root sequence, so pre/post body methods are not executed. The root sequence which ultimately called the subsequence handles the objections, using one of the two options above.

If a sequence is call via a `uvm_do variant, the it is defined as a subsequence and its pre/post_body() methods are not executed.

objection change in UVM1.2

Raising or dropping objections directly from starting_phase is deprecated

  • must use get_starting_phase() method

  • prevents modification of phase during sequence

1
2
3
4
5
task pre_body();
uvm_phase sp = get_starting_phase();
if (sp != null)
sp.raise_objection(this, get_type_name());
endtask

First place place hard macro and add placement halo, then execute the following code to add endcap and tapcell.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
deleteFill -prefix ENDCAP
deleteFill -prefix WELL

setEndCapMode \
-leftEdge BOUNDARY_RIGHTBWP16P90CPD \
-rightEdge BOUNDARY_LEFTBWP16P90CPD \
-leftBottomCorner BOUNDARY_NCORNERBWP16P90CPD \
-leftTopCorner BOUNDARY_PCORNERBWP16P90CPD \
-rightTopEdge FILL3BWP16P90CPD \
-rightBottomEdge FILL3BWP16P90CPD \
-topEdge "BOUNDARY_PROW2BWP16P90CPD BOUNDARY_PROW3BWP16P90CPD"
-bottomEdge "BOUNDARY_NROW2BWP16P90CPD BOUNDARY_NROW3BWP16P90CPD" \
-boundary_tap true

set_well_tap_mode \
-rule 33
-bottom_tap_cell BOUNDARY_NTAPBWP16P90CPD \
-top_tap_cell BOUNDARY_PTAPBWP16P90CPD \
-cell TAPCELLBWP16P90CPD

addEndCap
addWellTap -checkerBoard -cell TAPCELLBWP16P90CPD -cellInterval 160

endcap_tapcell_floorplan.drawio

REF: StanfordAHA/PowerDomainDesign

power/ground bump

1
2
3
4
5
6
7
create_bump –cell PAD90UBMBOP –loc_type cell_center –loc $x0 $y  
create_bump –cell PAD90UBMBOP –loc_type cell_center –loc $x1 $y
...
create_bump –cell PAD90UBMBOP –loc_type cell_center –loc $xn $y
deselectAll
select_bump –bum_cell PAD90UBMBOP
assignPGBumps –nets {vss vdd_dig} -selected –checkboard

pma_dig_bumps.drawio

signal or power/ground bump

1
2
3
4
5
set bump_name [create_bump –cell PAD150PITCH –loc $bump_x $bump_y –loc_type cell_center –return_bumps_name] 
# assign power/ground bump
assignPGBumps –bumps $bump_name –nets $pin_name
# or assign to signal bump
assignSigToBump –bumps $bump_name –net $pin_name

$readmemh("hex_memory_file.mem", memory_array, [start_address], [end_address]) $readmemb("bin_memory_file.mem", memory_array, [start_address], [end_address])

The system task has no versions to accept octal data or decimal data.

  • The 1st argument is the data file name.
  • The 2nd argument is the array to receive the data.
  • The 3rd argument is an optional start address, and if you provide it, you can also provide
  • The 4th argument optional end address.

Note, the 3rd and 4th argument address is for array not data file.

If the memory addresses are not specified anywhere, then the system tasks load file data sequentially from the lowest address toward the highest address.

The standard before 2005 specify that the system tasks load file data sequentially from the left memory address bound to the right memory address bound.

readtest.v

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 readfile;
reg [7:0] array4 [0:3];
reg [7:0] array7 [6:0];
reg [7:0] array12 [11:0];

integer i;

initial begin
$readmemb("data.txt", array4);
$readmemb("data.txt", array7, 2, 5);
$readmemb("data.txt", array12);

for (i = 0; i < 4; i = i+1)
$display("array4[%0d] = %b", i, array4[i]);

$display("=========================");

for (i = 0; i < 7; i = i+1)
$display("array7[%0d] = %b", i, array7[i]);

$display("=========================");

for (i = 0; i < 12; i = i+1)
$display("array12[%0d] = %b", i, array12[i]);
end
endmodule

data.txt

1
2
3
4
5
6
7
8
00000000 
00000001
00000010
00000011
00000100
00000101
00000110
00001000

result

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
array4[0] = 00000000
array4[1] = 00000001
array4[2] = 00000010
array4[3] = 00000011
=========================
array7[0] = xxxxxxxx
array7[1] = xxxxxxxx
array7[2] = 00000000
array7[3] = 00000001
array7[4] = 00000010
array7[5] = 00000011
array7[6] = xxxxxxxx
=========================
array12[0] = 00000000
array12[1] = 00000001
array12[2] = 00000010
array12[3] = 00000011
array12[4] = 00000100
array12[5] = 00000101
array12[6] = 00000110
array12[7] = 00001000
array12[8] = xxxxxxxx
array12[9] = xxxxxxxx
array12[10] = xxxxxxxx
array12[11] = xxxxxxxx

ref

Initialize Memory in Verilog

A range of contiguous bits can be selected and is known as part-select. There are two types of part-selects, one with a constant part-select and another with an indexed part-select

1
2
reg [31:0] addr;
addr [23:16] = 8'h23; //bits 23 to 16 will be replaced by the new value 'h23 -> constant part-select

Having a variable part-select allows it to be used effectively in loops to select parts of the vector. Although the starting bit can be varied, the width has to be constant.

[<start_bit +: ] // part-select increments from start-bit

[<start_bit -: ] // part-select decrements from start-bit

Example

1
2
3
4
5
6
7
8
9
10
11
12
logic [31: 0] a_vect;
logic [0 :31] b_vect;

logic [63: 0] dword;
integer sel;

a_vect[ 0 +: 8] // == a_vect[ 7 : 0]
a_vect[15 -: 8] // == a_vect[15 : 8]
b_vect[ 0 +: 8] // == b_vect[0 : 7]
b_vect[15 -: 8] // == b_vect[8 :15]

dword[8*sel +: 8] // variable part-select with fixed width

ref

Verilog scalar and vector

What is the "+:" operator called in Verilog?

0%