7nm项目——顶层规划(一)

planning步骤:

1.create block ndm(block stub netlist)

2.import top stub netlist

3.initialize top floorplan

4.commit block will be skipped

5.define block floorplan

6.adjust floorplan and block location

7.pin assignment

8.pipeline register insertion and placement

9.feedthrough

10.powerplan

11.write data

一、create block ndm(block stub netlist)

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
}

二、import top stub netlist

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

三、初始化top floorplan

### initialize top floorplan (manual or use def)
read_def data/CORTEXA53.floorplan.def.gz

可以读入def 也可以手动

四、微调floorplan size and block location and origin

为了更省面积,使得每个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有小箭头,

五.pin assignment

 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]]

结果展示:

 

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值