0.common setting
### common setting
source scripts/00_common_initial_settings.tcl
00_common_initial_settings.tcl脚本:
从ICC2开始, synopsys 为了提高PR工具的速度,引入了一种新格式的库,即NDM(new data model)。NDM 其实就是将logic info 和 physical info合成到一起
这里的ndm和lef分别是什么?
一般Foundary只会提供标准单元的lef文件,这个lef文件是对标准单元的抽象,即只抽出它的尺寸大小,出pin信息以及blockage。ICC和ICC2都无法直接读入lef,ICC和ICC2分别只能读入Milkyway和NDM两种格式。因此需要用脚本将lef分别转成Milkyway和NDM。NDM全称是New Data Model,是ICC2特有的数据格式,包括我们的database也会保存成ndm格式,比如cortexa7core.nlib。
1.创建 block nlib
set block_list "ca53_cpu ca53_l2"
foreach design $block_list {
#set design "ca53_cpu"
#set design "ca53_l2"
set block_stub_netlist "data/blocks/${design}.stub.vnet.gz"
set block_floorplan_def "data/out/${design}.floorplan.def.gz"
### create nlib
set nlib_dir "data/blocks"
file mkdir $nlib_dir
set block_nlib $nlib_dir/${design}_frame.nlib
file delete -force $block_nlib
create_lib -technology $synopsys_tech_tf -ref_libs $ndm_files $block_nlib
set_svf -off
创建nlib 工作平台
nlib文件是什么?什么作用?
这个nlib就是ICC2保存数据的一个library库,这个库包含了既有标准单元,macro的物理信息也包含了它们的timing信息。所以你看到ICC2中是将建立一个nlib的库,然后每个阶段会保存出一颗cell,这颗cell ICC2的叫法是叫block,即save_block。
2.读取 block stub netlist
### read block stub netlist
read_verilog -library ${design}_frame.nlib -design $design -top $design $block_stub_netlist
3.读取floorplan def
### read block floorplan def (could be generated manual)
read_def $block_floorplan_def -include {diearea ports rows_tracks} -add_def_only_objects {none}
4.save nlib
### save lib and close
save_lib -all
close_lib -force
脚本总结
### common setting
source scripts/00_common_initial_settings.tcl
set block_list "ca53_cpu ca53_l2"
foreach design $block_list {
#set design "ca53_cpu"
#set design "ca53_l2"
set block_stub_netlist "data/blocks/${design}.stub.vnet.gz"
set block_floorplan_def "data/out/${design}.floorplan.def.gz"
### create nlib
set nlib_dir "data/blocks"
file mkdir $nlib_dir
set block_nlib $nlib_dir/${design}_frame.nlib
file delete -force $block_nlib
create_lib -technology $synopsys_tech_tf -ref_libs $ndm_files $block_nlib
set_svf -off
### read block stub netlist
read_verilog -library ${design}_frame.nlib -design $design -top $design $block_stub_netlist
### read block floorplan def (could be generated manual)
read_def $block_floorplan_def -include {diearea ports rows_tracks} -add_def_only_objects {none}
### save lib and close
save_lib -all
close_lib -force
}
source scripts/00_common_initial_settings.tcl
lappend ndm_files "/disk/hd02/projects/hesper/05_pnr/top/CORTEXA53/r20220114_CORTEXA53_init/data/blocks/ca53_cpu_frame.nlib"
lappend ndm_files "/disk/hd02/projects/hesper/05_pnr/top/CORTEXA53/r20220114_CORTEXA53_init/data/blocks/ca53_l2_frame.nlib"
### create nlib
set nlib_dir "data"
file mkdir $nlib_dir
set top_nlib $nlib_dir/${design}_stub.nlib
file delete -force $top_nlib
create_lib -technology $synopsys_tech_tf -ref_libs $ndm_files $top_nlib
set_svf -off
### read top stub netlist
read_verilog -library ${design}_stub.nlib -design $design -top $design $import_netlists_stub
### initialize top floorplan (manual or use def)
read_def data/CORTEXA53.floorplan.def.gz
可以读入def 也可以手动
为了更省面积,使得每个block的长宽是row 的整数倍
1.format_block_size 脚本
set top_block [get_att [current_design] full_name]
set_working_design_stack $top_block
foreach _block [get_att [get_blocks -hier] full_name] {
echo "Formatting floorplan size of block ${_block}"
set_working_design_stack ${_block}
initialize_floorplan -core_offset {0 0.240} -use_site_row -keep_all -keep_boundary
set design_boundary [get_att [current_design ] boundary]
set x_step 0.057
set y_step 0.24
set new_boundary ""
foreach _point $design_boundary {
set point_x [lindex ${_point} 0]
set point_y [lindex ${_point} 1]
# die to core distance at horizontal side should 0.057um*2n
set xnstep [expr int($point_x / $x_step)]
if { [expr $xnstep % 2] == 0 } {
set point_newx [expr $xnstep * $x_step]
} else {
set point_newx [expr ($xnstep + 1) * $x_step]
}
# die to core distance at vertical side should 0.24um*2n
set ynstep [expr int($point_y / $y_step)]
if { [expr $ynstep % 2] == 0 } {
set point_newy [expr $ynstep * $y_step]
} else {
set point_newy [expr ($ynstep + 1) * $y_step]
}
lappend new_boundary [list $point_newx $point_newy]
}
initialize_floorplan -core_offset {0 0.240} -use_site_row -keep_all -boundary $new_boundary
set_working_design_stack $top_block
}
set_working_design_stack $top_block
2.move_block_origin 脚本
set top_block [get_att [current_design] full_name]
set_working_design_stack $top_block
foreach _block [get_att [get_blocks -hier] full_name] {
echo "Moving block origin to die center for block ${_block}"
set_working_design_stack ${_block}
cdf_move_design_origin
set_working_design_stack $top_block
}
set_working_design_stack $top_block
3.legalize_blocks 脚本
set block_insts [get_object_name [get_cells -filter "is_soft_macro==true" -quiet]]
set x_step 0.057
set y_step 0.24
foreach _inst $block_insts {
set inst_origin [get_att ${_inst} origin]
set inst_origin_x [lindex $inst_origin 0]
set inst_origin_y [lindex $inst_origin 1]
# x of origin should be 0.057um*2n
set xnstep [expr int($inst_origin_x / $x_step)]
if { [expr $xnstep % 2] == 0 } {
set point_newx [expr $xnstep * $x_step]
} else {
set point_newx [expr ($xnstep + 1) * $x_step]
}
# y of origin should be 0.24um*2n
set ynstep [expr int($inst_origin_y / $y_step)]
if { [expr $ynstep % 2] == 0 } {
set point_newy [expr $ynstep * $y_step]
} else {
set point_newy [expr ($ynstep + 1) * $y_step]
}
set new_origin [list $point_newx $point_newy]
echo "Legalizing block instance location for ${_inst} from $inst_origin to $new_origin"
set_attribute [get_cells ${_inst}] origin $new_origin
}
效果:
M0 的track不均匀,为了power rail
M1track有小箭头,
type 1 : nets with fanout is 1 connected to blocks (最多)
type 2 : nets with fanout is 1 connected to top ports and block pins
type 3 : floating or tie pins/ports
type 4 : align pins of ca53_l2 based on placed pins of ca53_cpu
type 5 : rest of unplaced pins for each block
1.type 1 : nets with fanout is 1 connected to blocks (最多)
(1)用busplan 把所有net过滤出来;再用bubdle net 把一对一的net过滤出来
# create busplan to filter nets between specified blocks
create_busplans -name ${block1}_to_${block2} -from [get_pins ${block1}/* -filter "direction==out"] -to [get_pins ${block2}/* -filter "direction==in"]
create_busplans -name ${block2}_to_${block1} -from [get_pins ${block2}/* -filter "direction==out"] -to [get_pins ${block1}/* -filter "direction==in"]
# get nets of busplan
set bundle_nets ""
append_to_col bundle_nets [filter_col [get_att [get_busplans ${block1}_to_${block2}] all_nets] number_of_pins==2]
append_to_col bundle_nets [filter_col [get_att [get_busplans ${block2}_to_${block1}] all_nets] number_of_pins==2]
# create bundle based on nets collection
set bundle_name "bundle_${block1}_${block2}"
create_bundle -name $bundle_name $bundle_nets
(2)计算每层metal摆放多少pin
# calculate pin number of each layer
set pin_layers {M4 M6 M8}
set layer_cnt [llength $pin_layers]
set nets_num [sizeof_col $bundle_nets]
if { [expr $nets_num / ${layer_cnt}.0] > [expr int($nets_num / ${layer_cnt}.0)] } {
set pins_each_layer [expr int($nets_num / ${layer_cnt}.0) + 1]
} else {
set pins_each_layer [expr int($nets_num / ${layer_cnt}.0)]
}
(3)计算每层的pitch
# get track pitch of each layer
array unset track_pitch
foreach _layer $pin_layers {
set track_pitch(${_layer}) [get_att [get_layer ${_layer}] pitch]
}
(4)计算pin range
# calculate the pin range of each layer
set offset_value 170.16
set layer_range_end [expr $offset_value - $track_pitch(${_layer}) * 2 * $pins_each_layer]
(5*)用set_bundle_pin_constraints 摆放pin
create bundle for nets of each layer
if { [get_bundles * -quiet] != "" } {
remove_bundles [get_bundles * -quiet]
}
for {set i 0} {$i < $layer_cnt} {incr i} {
remove_bundle_pin_constraints
set slice_bundle_name "${bundle_name}_slice_$i"
set index_from [expr $i * $pins_each_layer]
set index_to [expr ($i + 1) * $pins_each_layer - 1]
set bundle_nets_slice($slice_bundle_name) [index_col $bundle_nets $index_from $index_to]
create_bundle -name $slice_bundle_name $bundle_nets_slice($slice_bundle_name)
set real_pin_layer [lindex $pin_layers $i]
## create pin constraints for bundle nets
#set_bundle_pin_constraints -bundles $slice_bundle_name -cells $block1 -keep_pins_together true -bundle_order ordered -allow_feedthroughs false -allowed_layers $real_pin_layer -pin_spacing 1 -sides 3 -range [list $offset_value $layer_range_end]
#set_bundle_pin_constraints -bundles $slice_bundle_name -cells $block2 -keep_pins_together true -bundle_order ordered -allow_feedthroughs false -allowed_layers $real_pin_layer -pin_spacing 1 -sides 1
## place constrained pins
#place_pins -nets $bundle_nets_slice($slice_bundle_name) -cells [list $block1 $block2]
(5)用individual_pin_constraints的方式摆放 pin
remove_terminals [get_terminals -of [get_pins ]]
remove_individual_pin_constraints
set initial_loc_y "1248.4815"
set net_cnt 0
set constrained_pins ""
foreach_in_col _net $bundle_nets_slice($slice_bundle_name) {
set connected_pins [get_pins -of ${_net}]
foreach_in_col _pin $connected_pins {
set pin_name [get_att ${_pin} full_name]
if { [regexp {u_ca53_l2} $pin_name] } {
set pin_loc_x "830.9875"
} elseif { [regexp {g_ca53_cpu_1__u_ca53_cpu} $pin_name] } {
set pin_loc_x "854.0465"
} else {
echo "MY-Error: pin name $pin_name is neither u_ca53_l2 nor g_ca53_cpu_1__u_ca53_cpu"
continue
}
set pin_loc_y [expr $initial_loc_y - $net_cnt * $track_pitch($real_pin_layer) * 2]
set pin_cmd "set_individual_pin_constraints -pins $pin_name -allowed_layers $real_pin_layer -location \[list $pin_loc_x $pin_loc_y\]"
# echo $pin_cmd
eval $pin_cmd
lappend constrained_pins $pin_name
}
incr net_cnt
}
place_pins -pins $constrained_pins
}
2.type 2 : nets with fanout is 1 connected to top ports and block pins
脚本摆放pin:
### type 2 : nets with fanout is 1 connected to top ports and block pins
# con1248.4815dition 1: unplaced
# condition 2: connected to specifed instances
# condition 3: fanout should be 1
# condition 4: should connect to top level port
set target_inst "u_ca53_l2"
set block_unplaced_pins [get_pins -of [get_cells $target_inst] -filter "physical_status==unplaced"]
set multifanout_nets [get_nets -filter "number_of_pins>2" -quiet]
set top_connected_nets [remove_from_col [get_nets -of [get_ports -of [get_nets -of $block_unplaced_pins]]] $multifanout_nets]
set real_unplaced_pins [get_pins -of $top_connected_nets]
set real_unplaced_ports [get_ports -of $top_connected_nets]
# calculate pin number of each layer
set pin_layers {M4 M6 M8}
set layer_cnt [llength $pin_layers]
set pins_num [sizeof_col $real_unplaced_pins]
if { [expr $pins_num / ${layer_cnt}.0] > [expr int($pins_num / ${layer_cnt}.0)] } {
set pins_each_layer [expr int($pins_num / ${layer_cnt}.0) + 1]
} else {
set pins_each_layer [expr int($pins_num / ${layer_cnt}.0)]
}
# get track pitch of each layer
array unset track_pitch
foreach _layer $pin_layers {
set track_pitch(${_layer}) [get_att [get_layer ${_layer}] pitch]
}
for {set i 0} {$i < $layer_cnt} {incr i} {
set slice_bundle_name "${bundle_name}_slice_$i"
set index_from [expr $i * $pins_each_layer]
if { $i == [expr $layer_cnt - 1] } {
set index_to "end"
} else {
set index_to [expr ($i + 1) * $pins_each_layer - 1]
}
set pins_slice($slice_bundle_name) [index_col $real_unplaced_pins $index_from $index_to]
set real_pin_layer [lindex $pin_layers $i]
# remove_terminals [get_terminals -of [get_pins ]]
remove_individual_pin_constraints
set initial_loc_y "951.9740"
set pin_cnt 0
set constrained_pins ""
foreach_in_col _pin $pins_slice($slice_bundle_name) {
set pin_name [get_att ${_pin} full_name]
if { [regexp {u_ca53_l2} $pin_name] } {
set pin_loc_x "10.6020"
} elseif { [regexp {g_ca53_cpu_1__u_ca53_cpu} $pin_name] } {
set pin_loc_x "1391.7115"
} else {
echo "MY-Error: pin name $pin_name is neither u_ca53_l2 nor g_ca53_cpu_1__u_ca53_cpu"
continue
}
set pin_loc_y [expr $initial_loc_y - $pin_cnt * $track_pitch($real_pin_layer) * 2]
set pin_cmd "set_individual_pin_constraints -pins $pin_name -allowed_layers $real_pin_layer -location \[list $pin_loc_x $pin_loc_y\]"
# echo $pin_cmd
eval $pin_cmd
lappend constrained_pins $pin_name
}
incr pin_cnt
place_pins -pins $constrained_pins
}
摆放port:
remove_individual_pin_constraints
set port_loc_x [lindex [get_attribute [current_design ] boundary_bbox] 0 0]
set constrained_ports ""
foreach_in_col _port $real_unplaced_ports {
set connected_net [get_nets -of ${_port}]
set port_name [get_object_name ${_port}]
set connected_pin [get_pins -of $connected_net -quiet]
if { $connected_pin == "" } {
echo "MY-Error: Failed to connected pin for net [get_object_name $connected_net]"
continue
}
set pin_layer [get_att $connected_pin layer.name]
set pin_bbox [get_attr $connected_pin bbox]
set pin_x0 [lindex $pin_bbox 0 0]
set pin_y0 [lindex $pin_bbox 0 1]
set pin_x1 [lindex $pin_bbox 1 0]
set pin_y1 [lindex $pin_bbox 1 1]
set pin_center_x [format "%.5f" [expr ($pin_x1 + $pin_x0)/2.0]]
set pin_center_y [format "%.5f" [expr ($pin_y1 + $pin_y0)/2.0]]
set port_loc_y $pin_center_y
set port_cmd "set_individual_pin_constraints -ports $port_name -allowed_layers $pin_layer -location \[list $port_loc_x $port_loc_y\]"
# echo $port_cmd
eval $port_cmd
lappend constrained_ports $port_name
}
place_pins -ports $constrained_ports
type 3 : floating or tie pins/ports
## type 3 : floating or tie pins/ports
#set block_ref "ca53_l2"
#set block_ref "ca53_cpu"
set block_ref "ca53_cpu ca53_l2"
foreach _block $block_ref {
set target_inst [get_att [index_col [get_cells -filter "ref_name==${_block}"] 0] name]
set floating_pins ""
append_to_col -unique floating_pins [get_pins ${target_inst}/* -filter "net.name=~*Logic0*||net.name=~*Logic1*||undefined(net.name)||net.name=~*SYNOPSYS_UNCONNECTED*" -quiet]
append_to_col -unique floating_pins [get_pins -of [get_nets -of [get_pins ${target_inst}/*] -filter "number_of_pins==1&&full_name!~*SYNOPSYS_UNCONNECTED*"]]
remove_individual_pin_constraints
if { [regexp {u_ca53_l2} ${target_inst}] } {
set_individual_pin_constraints -pins $floating_pins -allowed_layers {M5 M7 M9} -pin_spacing 1 -side 2 -offset {550 650}
} else {
set_individual_pin_constraints -pins $floating_pins -allowed_layers {M5 M7 M9} -pin_spacing 1 -side 2 -offset {450 530}
}
place_pins -pins $floating_pins
}
type 4 : nets with fanout more than 1 connected to block
#type 4 net with fannout more than 1 connected to blocks
set target_inst "u_ca53_l2"
set multifanout_net [get_nets -of [get_pins -of $target_inst -filter "physical_status==unplaced"] -filter "number_of_pins>2" -quiet]
set unplaced_pins [get_pins -of $multifanout_net -filter "full_name=~${target_inst}/*" -quiet]
if {$unplaced_pins != ""} {
set_individual_pin_constraints -pins $unplaced_pins -allowed_layers {M4 M6 M8} -pin_spacing 1 -side 3 -offset {680 700}
place_pins -pin $unplaced_pins
}
set target_inst "g_ca53_cpu_1__u_ca53_cpu"
set multifanout_net [get_nets -of [get_pins -of $target_inst -filter "physical_status==unplaced"] -filter "number_of_pins>2" -quiet]
set unplaced_pins [get_pins -of $multifanout_net -filter "full_name=~${target_inst}/*" -quiet]
if {$unplaced_pins != ""} {
set_individual_pin_constraints -pins $unplaced_pins -allowed_layers {M4 M6 M8} -pin_spacing 1 -side 1 -offset {158 163}
place_pins -pin $unplaced_pins
}
type 5 : 剩余pin摆放
### type 5 : rest of unplaced pins for each block
remove_individual_pin_constraints
set_app_options -name plan.macro.align_pins_on_parallel_edges -value false
set_app_options -name plan.pins.strict_alignment -value false
set target_inst "u_ca53_l2 g_ca53_cpu_1__u_ca53_cpu"
foreach _inst $target_inst {
#set multifanout_nets [get_nets -of [get_pins -of ${_inst} -filter "physical_status==unplaced"] -filter "number_of_pins>2" -quiet]
set unplaced_pins [get_pins -of ${_inst} -filter "physical_status==unplaced"]
remove_individual_pin_constraints
if { $unplaced_pins != "" } {
if { [regexp {u_ca53_l2} ${_inst}] } {
set_individual_pin_constraints -pins $unplaced_pins -allowed_layers {M4 M6 M8} -pin_spacing 1 -side 3 -offset {710 715}
} else {
set_individual_pin_constraints -pins $unplaced_pins -allowed_layers {M4 M6 M8} -pin_spacing 1 -side 1 -offset {140 145}
}
place_pins -pins $unplaced_pins
}
}
小tips 如何重新摆放
remove_terminals [get_terminals -of [get_selection]]
结果展示: