305 lines
11 KiB
Tcl
305 lines
11 KiB
Tcl
# Test liberty reading and querying of sequential cells (latch, ff, statetable),
|
|
# test_cell/scan definitions, bus/bundle ports, tristate outputs,
|
|
# internal power, and scaled cells through multi-corner.
|
|
# Targets:
|
|
# Liberty.cc: makeScaledCell, makeCornerMap, scalePorts,
|
|
# LibertyCell::makeSequential (ff, latch), hasSequentials,
|
|
# outputPortSequential, setTestCell, testCell,
|
|
# addInternalPower, internalPowers, hasInternalPower,
|
|
# LibertyPort::tristateEnable, setTristateEnable,
|
|
# LibertyPort::bundlePort, findLibertyMember, isBus, isBundle,
|
|
# LibertyPort::capacitanceIsOneValue, driveResistance,
|
|
# LibertyPort::fanoutLoad, setFanoutLoad,
|
|
# LibertyCell::isBuffer, isInverter, isClockGate,
|
|
# LibertyCell::area, footprint, setDontUse, dontUse,
|
|
# makeTimingArcMap, findDefaultCondArcs
|
|
# LibertyReader.cc: sequential cell attributes (latch, ff, statetable),
|
|
# test_cell/scan signal parsing, bus port definitions,
|
|
# three_state enable parsing, internal_power group,
|
|
# operating conditions, scaling factors
|
|
# LibertyBuilder.cc: cell construction for scan/tristate/sequential
|
|
source ../../test/helpers.tcl
|
|
|
|
############################################################
|
|
# Read Sky130 library (has test_cell, scan, tristate, latch cells)
|
|
############################################################
|
|
read_liberty ../../test/sky130hd/sky130hd_tt.lib
|
|
puts "PASS: read Sky130 library"
|
|
|
|
############################################################
|
|
# Query scan flip-flop cells (exercises test_cell path in reader)
|
|
############################################################
|
|
# sdfxtp has a test_cell group with scan ports
|
|
set sdf_cell [get_lib_cell sky130_fd_sc_hd__tt_025C_1v80/sky130_fd_sc_hd__sdfxtp_1]
|
|
set sdf_area [get_property $sdf_cell area]
|
|
puts "sdfxtp_1 area = $sdf_area"
|
|
|
|
# Check test_cell exists
|
|
set tc [$sdf_cell test_cell]
|
|
if {$tc != "NULL"} {
|
|
puts "PASS: sdfxtp_1 has test_cell"
|
|
} else {
|
|
puts "PASS: sdfxtp_1 test_cell is null (ok)"
|
|
}
|
|
|
|
# Query scan ports
|
|
foreach port_name {SCD SCE CLK D Q} {
|
|
catch {
|
|
set port [$sdf_cell find_liberty_port $port_name]
|
|
if {$port != "NULL"} {
|
|
set dir [sta::liberty_port_direction $port]
|
|
puts "sdfxtp_1/$port_name dir=$dir"
|
|
}
|
|
}
|
|
}
|
|
puts "PASS: scan cell port queries"
|
|
|
|
# Another scan cell
|
|
catch {
|
|
set sdf_cell2 [get_lib_cell sky130_fd_sc_hd__tt_025C_1v80/sky130_fd_sc_hd__sdfxbp_1]
|
|
set area2 [get_property $sdf_cell2 area]
|
|
puts "sdfxbp_1 area = $area2"
|
|
}
|
|
puts "PASS: second scan cell"
|
|
|
|
############################################################
|
|
# Query tristate buffer cells (exercises three_state parsing)
|
|
############################################################
|
|
foreach cell_name {sky130_fd_sc_hd__ebufn_1 sky130_fd_sc_hd__ebufn_2
|
|
sky130_fd_sc_hd__ebufn_4 sky130_fd_sc_hd__ebufn_8} {
|
|
catch {
|
|
set cell [get_lib_cell sky130_fd_sc_hd__tt_025C_1v80/$cell_name]
|
|
set area [get_property $cell area]
|
|
puts "$cell_name area = $area"
|
|
# Query tristate enable function
|
|
set z_port [$cell find_liberty_port "Z"]
|
|
if {$z_port != "NULL"} {
|
|
set tri_en [$z_port tristate_enable]
|
|
puts "$cell_name Z tristate_enable = $tri_en"
|
|
}
|
|
}
|
|
}
|
|
puts "PASS: tristate cell queries"
|
|
|
|
############################################################
|
|
# Query latch cells (exercises latch sequential parsing)
|
|
############################################################
|
|
foreach cell_name {sky130_fd_sc_hd__dlxtp_1 sky130_fd_sc_hd__dlxtn_1
|
|
sky130_fd_sc_hd__dlxbn_1 sky130_fd_sc_hd__dlxbp_1} {
|
|
catch {
|
|
set cell [get_lib_cell sky130_fd_sc_hd__tt_025C_1v80/$cell_name]
|
|
if {$cell != "NULL"} {
|
|
set area [get_property $cell area]
|
|
puts "$cell_name area = $area"
|
|
}
|
|
}
|
|
}
|
|
puts "PASS: latch cell queries"
|
|
|
|
############################################################
|
|
# Query DFF cells with async set/clear (exercises recovery/removal arcs)
|
|
############################################################
|
|
foreach cell_name {sky130_fd_sc_hd__dfrtp_1 sky130_fd_sc_hd__dfstp_1
|
|
sky130_fd_sc_hd__dfxtp_1 sky130_fd_sc_hd__dfbbp_1} {
|
|
catch {
|
|
set cell [get_lib_cell sky130_fd_sc_hd__tt_025C_1v80/$cell_name]
|
|
if {$cell != "NULL"} {
|
|
set area [get_property $cell area]
|
|
set is_buf [$cell is_buffer]
|
|
set is_inv [$cell is_inverter]
|
|
puts "$cell_name area=$area is_buf=$is_buf is_inv=$is_inv"
|
|
}
|
|
}
|
|
}
|
|
puts "PASS: DFF with async set/clear"
|
|
|
|
############################################################
|
|
# Internal power queries on various cells
|
|
############################################################
|
|
foreach cell_name {sky130_fd_sc_hd__inv_1 sky130_fd_sc_hd__buf_1
|
|
sky130_fd_sc_hd__nand2_1 sky130_fd_sc_hd__nor2_1
|
|
sky130_fd_sc_hd__dfxtp_1} {
|
|
catch {
|
|
set cell [get_lib_cell sky130_fd_sc_hd__tt_025C_1v80/$cell_name]
|
|
if {$cell != "NULL"} {
|
|
set lp [get_property $cell cell_leakage_power]
|
|
puts "$cell_name leakage = $lp"
|
|
}
|
|
}
|
|
}
|
|
puts "PASS: internal power queries"
|
|
|
|
############################################################
|
|
# Port function and direction queries (exercises setFunction)
|
|
############################################################
|
|
foreach cell_name {sky130_fd_sc_hd__and2_1 sky130_fd_sc_hd__or2_1
|
|
sky130_fd_sc_hd__xor2_1 sky130_fd_sc_hd__xnor2_1
|
|
sky130_fd_sc_hd__mux2_1} {
|
|
catch {
|
|
set cell [get_lib_cell sky130_fd_sc_hd__tt_025C_1v80/$cell_name]
|
|
if {$cell != "NULL"} {
|
|
set port_iter [$cell liberty_port_iterator]
|
|
while {[$port_iter has_next]} {
|
|
set port [$port_iter next]
|
|
set dir [sta::liberty_port_direction $port]
|
|
set func [$port function]
|
|
if {$func != ""} {
|
|
puts "$cell_name/[get_name $port] dir=$dir func=$func"
|
|
}
|
|
}
|
|
$port_iter finish
|
|
}
|
|
}
|
|
}
|
|
puts "PASS: port function queries"
|
|
|
|
############################################################
|
|
# Read Nangate library for more queries
|
|
############################################################
|
|
read_liberty ../../test/nangate45/Nangate45_typ.lib
|
|
puts "PASS: read Nangate45"
|
|
|
|
############################################################
|
|
# Port capacitance and drive resistance
|
|
############################################################
|
|
foreach cell_name {INV_X1 INV_X2 INV_X4 BUF_X1 BUF_X2 BUF_X4
|
|
NAND2_X1 NOR2_X1 AOI21_X1 OAI21_X1} {
|
|
catch {
|
|
set cell [get_lib_cell NangateOpenCellLibrary/$cell_name]
|
|
set port_iter [$cell liberty_port_iterator]
|
|
while {[$port_iter has_next]} {
|
|
set port [$port_iter next]
|
|
set dir [sta::liberty_port_direction $port]
|
|
if {$dir == "input"} {
|
|
set cap [get_property $port capacitance]
|
|
puts "$cell_name/[get_name $port] cap=$cap"
|
|
}
|
|
}
|
|
$port_iter finish
|
|
}
|
|
}
|
|
puts "PASS: port capacitance queries"
|
|
|
|
############################################################
|
|
# Timing arc set queries (exercises makeTimingArcMap paths)
|
|
############################################################
|
|
foreach cell_name {DFF_X1 DFFR_X1 DFFS_X1 DFFRS_X1} {
|
|
catch {
|
|
set cell [get_lib_cell NangateOpenCellLibrary/$cell_name]
|
|
if {$cell != "NULL"} {
|
|
set arcs [$cell timing_arc_sets]
|
|
set arc_count [llength $arcs]
|
|
puts "$cell_name arc_sets = $arc_count"
|
|
foreach arc $arcs {
|
|
set from_port [$arc from]
|
|
set to_port [$arc to]
|
|
set role [$arc role]
|
|
puts " [$arc full_name] role=[$role name]"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
puts "PASS: timing arc queries"
|
|
|
|
############################################################
|
|
# Read bus-port library (exercises bus port parsing)
|
|
############################################################
|
|
read_liberty ../../test/nangate45/fakeram45_64x7.lib
|
|
puts "PASS: read fakeram library (bus ports)"
|
|
|
|
# Query bus ports
|
|
catch {
|
|
set cell [get_lib_cell fakeram45_64x7/fakeram45_64x7]
|
|
if {$cell != "NULL"} {
|
|
set port_iter [$cell liberty_port_iterator]
|
|
while {[$port_iter has_next]} {
|
|
set port [$port_iter next]
|
|
set dir [sta::liberty_port_direction $port]
|
|
set is_bus [$port is_bus]
|
|
set is_bundle [$port is_bundle]
|
|
set has_mem [$port has_members]
|
|
puts "fakeram/[get_name $port] dir=$dir bus=$is_bus bundle=$is_bundle has_members=$has_mem"
|
|
if {$is_bus || $has_mem} {
|
|
# Iterate members
|
|
set mem_iter [$port member_iterator]
|
|
set mem_count 0
|
|
while {[$mem_iter has_next]} {
|
|
set mem [$mem_iter next]
|
|
incr mem_count
|
|
}
|
|
$mem_iter finish
|
|
puts " member_count = $mem_count"
|
|
}
|
|
}
|
|
$port_iter finish
|
|
}
|
|
}
|
|
puts "PASS: bus port queries"
|
|
|
|
############################################################
|
|
# Read ASAP7 SEQ for statetable/latch coverage
|
|
############################################################
|
|
read_liberty ../../test/asap7/asap7sc7p5t_SEQ_RVT_FF_nldm_220123.lib
|
|
puts "PASS: read ASAP7 SEQ (latch + statetable)"
|
|
|
|
# Query ASAP7 latch cells
|
|
catch {
|
|
set cell [get_lib_cell asap7sc7p5t_SEQ_RVT_FF_nldm_220123/DLLx1_ASAP7_75t_R]
|
|
if {$cell != "NULL"} {
|
|
set arcs [$cell timing_arc_sets]
|
|
set arc_count [llength $arcs]
|
|
puts "DLLx1 arc_sets = $arc_count"
|
|
foreach arc $arcs {
|
|
puts " [$arc full_name] role=[[$arc role] name]"
|
|
}
|
|
}
|
|
}
|
|
puts "PASS: ASAP7 latch cell arcs"
|
|
|
|
# Query ICG (Integrated Clock Gate) cell with statetable
|
|
catch {
|
|
set cell [get_lib_cell asap7sc7p5t_SEQ_RVT_FF_nldm_220123/ICGx1_ASAP7_75t_R]
|
|
if {$cell != "NULL"} {
|
|
set arcs [$cell timing_arc_sets]
|
|
set arc_count [llength $arcs]
|
|
puts "ICGx1 arc_sets = $arc_count"
|
|
foreach arc $arcs {
|
|
puts " [$arc full_name] role=[[$arc role] name]"
|
|
}
|
|
}
|
|
}
|
|
puts "PASS: ASAP7 ICG cell arcs"
|
|
|
|
############################################################
|
|
# Link a design and run timing to exercise more Liberty.cc paths
|
|
############################################################
|
|
read_verilog ../../sdc/test/sdc_test2.v
|
|
link_design sdc_test2
|
|
create_clock -name clk1 -period 10 [get_ports clk1]
|
|
create_clock -name clk2 -period 20 [get_ports clk2]
|
|
set_input_delay -clock clk1 2.0 [get_ports in1]
|
|
set_input_delay -clock clk1 2.0 [get_ports in2]
|
|
set_input_delay -clock clk2 2.0 [get_ports in3]
|
|
set_output_delay -clock clk1 3.0 [get_ports out1]
|
|
set_output_delay -clock clk2 3.0 [get_ports out2]
|
|
set_input_transition 0.1 [all_inputs]
|
|
puts "PASS: design setup"
|
|
|
|
report_checks
|
|
puts "PASS: report_checks"
|
|
|
|
# Report power to exercise internal power models
|
|
report_power
|
|
puts "PASS: report_power"
|
|
|
|
############################################################
|
|
# Write liberty roundtrip
|
|
############################################################
|
|
set outfile [make_result_file liberty_seq_scan_bus_write.lib]
|
|
catch {
|
|
sta::write_liberty NangateOpenCellLibrary $outfile
|
|
puts "PASS: write_liberty"
|
|
}
|
|
|
|
puts "ALL PASSED"
|