plc_client.PlacementCost
is a placement and routing simulator that provides an
approximate but fast estimate of key QoR metrics such as wirelength, congestion,
and density. It is used in RL optimization loops to train good placements.
plc_client.PlacementCost
can also be used standalone to measure these proxy
costs given a placement.
plc_client.PlacementCost
supports the following methods.
can_place_node(node_index: int, grid_cell_index: int) -> bool
: Checks if a node can be placed into a grid cell. This is assuming the node is not placed or fixed.create_blockage(minx: float, miny: float, maxx: float, maxy: float, blockage_rate: float)
: Creates a blockage area, which is used to initialize grid density. A blockage is defined as a rectangular area which a hard macro cannot overlap with. Using the updated grid density, placement of soft macros, and standard cells are limited. Blockage rate can be set lower than 1.0 if the area can be used by stdcells and soft macros. If a grid cell is partially blocked, a hard macro can occupy the unblocked part of that grid cell.fix_node_coord(node_index: int) -> Status
: Fixes the coordinates of a node by index.get_area() -> float
: Total area of the macros and stdcells. Height and widths are assumed to be in microns, so this will return micron^2.get_blockages() -> list<list<float>>
: Returns blockages.get_canvas_width_height() -> tuple<float, float>
: Returns (width, height) of the canvas.get_congestion_cost() -> float
: Returns the average routing congestion of the top 10% congested routing grid cells.get_congestion_smooth_range() -> int
: Gets congestion smooth range.get_cost() -> float
: Calculates the normalized wirelength cost associated with the current placement of the nodes (stdcells, macros and ports). It returns a number between 0 and 1. 0 meaning 0 wirelength, 1 meaning worst possible placement leading to all wires spanning the entire placement area (half perimeter of canvas).get_density_cost() -> float
: Returns the average density of the 10% most dense placement grid cells.get_fan_outs_of_node(node_index: int) -> list<int>
: Returns the vector of node indices that are driven by given node.get_grid_cell_of_node(node_index: int) -> int
: Returns the node's current location in terms of grid cell index.get_grid_num_columns_rows() -> tuple<int, int>
: Returns (num columns, num rows) of the placement grid.get_macro_and_clustered_port_adjacency() -> (adj_matrix: list<int>, grid_cell_of_clustered_ports: list<int>)
: Builds the adjacency matrix between macros and "clustered ports", where a "clustered ports" is an abstract element in the matrix that represents all ports in a given grid cell. This function does the clustering of ports by itself.get_macro_indices() -> list<int>
: Returns the indices of the macros in the netlist, including both hard macros and soft macros (clustered standard cells).get_macro_orientation(node_index: int) -> str
: Returns the orientation string ('N', 'FN', ...) of the macro. If it's not a hard macro, returns empty string.get_macro_routing_allocation() -> tuple<float, float>
: Returns horizontal and vertical routing tracks per micron used up by hard macros.get_node_location(node_index: int) -> tuple<float, float>
: Returns the (x, y) location of a node. (in microns).get_node_locations(node_indices: list<int>) -> list<tuple<float, float>>
: Returns the (x, y) location of a list of nodes. (in microns).get_node_mask_by_name(node_name: str) -> list<int>
: Returns available positions in the canvas grid for the given node. The size of the returned vector is num_columns * num_rows.get_node_mask(node_index: int) -> list<int>
: Uses a node index to get the placement mask for a node.get_node_name(node_index: int) -> str
: Gets the name of the node by index. If the index is out of range, returns empty string.get_node_type(node_index: int) -> str
: Returns the type of the node as string.get_node_width_height(node_index: int) -> tuple<float, float>
: Returns the (width, height) of a node (in microns).get_overlap_threshold() -> float
: Returns overlap threshold.get_routes_per_micron() -> tuple<float, float>
: Returns available horizontal and vertical tracks per micron.get_wirelength() -> float
: Returns total wire length estimate.is_node_fixed(node_index: int) -> bool
: Returns whether the node is fixed (not moveable) or not.is_node_placed(node_index: int) -> bool
: Returns whether a node is placed (has coordinates) or not.is_node_soft_macro(node_index: int) -> bool
: Returns whether the node is a soft macro or not.make_soft_macros_square()
: To be used in accordance with repel/attract forces.optimize_stdcells( use_current_loc: bool, move_stdcells: bool, move_macros: bool, log_scale_conns: bool, use_sizes: bool, io_factor: float, steps: list<int>, max_move_distance: list<float>, attract_factor: list<float>, repel_factor: list<float>) -> Status
: Optimizes locations of standard cells and standard cell clusters using force directed methods. If use_current_loc is false, all movable nodes are placed in the center initially. In every step a node can move at most max_move_distance microns. Attract factor is used as a multiplier for spring forces connecting nodes. Repelling forces push overlapping nodes from each other regardless they are connected or not.place_node_by_name(node_name: str, grid_cell_index: int) -> Status
: Places the node using canvas grid_cell_index = col + row * num_cols. Converts to the x, y positions corresponding to the center coordinates of the grid cell. Returns error if unsuccessful or if the node is not found.place_node(node_index: int, grid_cell_index: int) -> Status
: Uses a node index to place a node.restore_placement(filename: str) -> Status
: Save and restore placement information to/from file.save_placement(filename: str, comments: str) -> Status
: Save and restore placement information to/from file.set_canvas_size(width: float, height: float) -> Status
: Sets the size of the placement area (canvas).set_congestion_smooth_range(range: int)
: Set the number of neighboring rows and columns to distribute the calculated routing congestion for a cellset_placement_grid(columns: int, rows: int) -> Status
: Sets the number of columns and rows used by placement. By default, there are 100 rows and 100 columns.unplace_all_nodes()
: Clears coordinate information of all nodes that are not marked as fixed.unplace_node_by_name(node_name: str) -> Status
: Clears node coords (unplace node). Should not be called for macro_pins.unplace_node(node_index: int) -> Status
: Uses a node index to unplace a node.update_macro_orientation_by_name(node_name: str, orientation: str) -> Status
: Updates the macro orientation. If the node_name is not a macro name, or orientation is not one of expected enums in the protobuf description, it returns an error.update_macro_orientation(node_index: int, orientation: str) -> Status
: Uses a node index to update the macro orientation.update_node_coords_by_name(node_name: str, x: float, y: float) -> Status
: Updates the x, y coordinates of the given node. Should not be called for macro_pins. Use PlaceNode to place nodes into placement grid cells.update_node_coords(node_index: int, x: float, y: float) -> Status
: Uses a node index to update x, y coordinates of a node.save_placement_pnr( output_file: str, original_netlist: str, metis_groups_file: str, eda_tool: str, project: str) -> Status
: Generates placement tcl file. Supported EDA tools: dct, innovus, icc2. original_netlist and metis_groups_file are needed for writing standard cell locations. For macro placements only, set as empty.
Example code of interacting with PlacementCost
to query proxy costs:
$ python3 -m circuit_training.environment.plc_client_main \
--netlist_file ./circuit_training/environment/test_data/ariane/netlist.pb.txt
--plc_wrapper_main /usr/local/bin/plc_wrapper_main