hardcode docker version to riscduino/openlane:mpw5
diff --git a/openlane/Makefile b/openlane/Makefile index d5f37cb..ecdee61 100644 --- a/openlane/Makefile +++ b/openlane/Makefile
@@ -19,8 +19,8 @@ CONFIG = $(foreach block,$(BLOCKS), ./$(block)/config.tcl) CLEAN = $(foreach block,$(BLOCKS), clean-$(block)) -OPENLANE_TAG ?= mpw4 -OPENLANE_IMAGE_NAME ?= riscduino/openlane:$(OPENLANE_TAG) +OPENLANE_TAG = mpw5 +OPENLANE_IMAGE_NAME = riscduino/openlane:$(OPENLANE_TAG) OPENLANE_BASIC_COMMAND = "cd /project/openlane && flow.tcl -design ./$* -save_path .. -save -tag $* -overwrite" OPENLANE_INTERACTIVE_COMMAND = "cd /project/openlane && flow.tcl -it -file ./$*/interactive.tcl -design ./$* -save_path .. -save -tag $* -overwrite" @@ -44,20 +44,12 @@ @if [ -f ./$*/interactive.tcl ]; then\ docker run -it -v $(OPENLANE_ROOT):/openLANE_flow \ - -v $(PDK_ROOT):$(PDK_ROOT) \ -v $(PWD)/..:/project \ - -v $(CARAVEL_ROOT):$(CARAVEL_ROOT) \ - -e PDK_ROOT=$(PDK_ROOT) \ - -e CARAVEL_ROOT=$(CARAVEL_ROOT) \ -u $(shell id -u $(USER)):$(shell id -g $(USER)) \ $(OPENLANE_IMAGE_NAME) sh -c $(OPENLANE_INTERACTIVE_COMMAND);\ else\ docker run -it -v $(OPENLANE_ROOT):/openLANE_flow \ - -v $(PDK_ROOT):$(PDK_ROOT) \ -v $(PWD)/..:/project \ - -v $(CARAVEL_ROOT):$(CARAVEL_ROOT) \ - -e PDK_ROOT=$(PDK_ROOT) \ - -e CARAVEL_ROOT=$(CARAVEL_ROOT) \ -u $(shell id -u $(USER)):$(shell id -g $(USER)) \ $(OPENLANE_IMAGE_NAME) sh -c $(OPENLANE_BASIC_COMMAND);\ fi
diff --git a/openlane/io_place.py b/openlane/io_place.py deleted file mode 100755 index 86ac1f2..0000000 --- a/openlane/io_place.py +++ /dev/null
@@ -1,528 +0,0 @@ -# Copyright 2020 Efabless Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Places the IOs according to an input file. Supports regexes. -File format: -#N|#S|#E|#W -pin1_regex -pin2_regex -... - -#S|#N|#E|#W -... -... -""" -import odb - -import os -import re -import sys -import click -import random - - -@click.command() -@click.option("-l", "--input-lef", required=True, help="Input merged tlef/lef file.") -@click.option( - "-o", - "--output-def", - default="./output.def", - help="Output DEF file with newly placed pins", -) -@click.option("-c", "--config", required=False, help="Optional configuration file.") -@click.option( - "-r", - "--reverse", - default="", - type=str, - help="Reverse along comma,delimited,cardinals: e.g. N,E", -) -@click.option("-L", "--length", default=2, type=float, help="Pin length in microns.") -@click.option( - "-V", - "--ver-layer", - required=True, - help="Name of metal layer to place vertical pins on.", -) -@click.option( - "-H", - "--hor-layer", - required=True, - help="Name of metal layer to place horizontal pins on.", -) -@click.option( - "--hor-extension", - default=0, - type=float, - help="Extension for vertical pins in microns.", -) -@click.option( - "--ver-extension", - default=0, - type=float, - help="Extension for horizontal pins in microns.", -) -@click.option( - "--ver-width-mult", default=2, type=float, help="Multiplier for vertical pins." -) -@click.option( - "--hor-width-mult", default=2, type=float, help="Multiplier for horizontal pins." -) -@click.option( - "--bus-sort/--no-bus-sort", - default=False, - help="Misnomer: pins are grouped by index instead of bus, i.e. a[0] goes with b[0] instead of a[1].", -) -@click.argument("input_def") -def cli( - input_lef, - output_def, - config, - ver_layer, - hor_layer, - ver_width_mult, - hor_width_mult, - length, - hor_extension, - ver_extension, - reverse, - bus_sort, - input_def, -): - """ - Places the IOs in an input def with an optional config file that supports regexes. - - Config format: - #N|#S|#E|#W - pin1_regex (low co-ordinates to high co-ordinates; e.g., bottom to top and left to right) - pin2_regex - ... - - #S|#N|#E|#W - """ - - def_file_name = input_def - lef_file_name = input_lef - output_def_file_name = output_def - config_file_name = config - bus_sort_flag = bus_sort - - #1. Manual Pad Placement - Dinesh A - manual_place_flag = False - - h_layer_name = hor_layer - v_layer_name = ver_layer - - h_width_mult = float(hor_width_mult) - v_width_mult = float(ver_width_mult) - - # Initialize OpenDB - db_top = odb.dbDatabase.create() - odb.read_lef(db_top, lef_file_name) - odb.read_def(db_top, def_file_name) - block = db_top.getChip().getBlock() - - micron_in_units = block.getDefUnits() - - LENGTH = int(micron_in_units * length) - - H_EXTENSION = int(micron_in_units * hor_extension) - V_EXTENSION = int(micron_in_units * ver_extension) - - if H_EXTENSION < 0: - H_EXTENSION = 0 - - if V_EXTENSION < 0: - V_EXTENSION = 0 - - reverse_arr_raw = reverse.split(",") - reverse_arr = [] - for element in reverse_arr_raw: - if element.strip() != "": - reverse_arr.append(f"#{element}") - - def getGrid(origin, count, step): - tracks = [] - pos = origin - for i in range(count): - tracks.append(pos) - pos += step - assert len(tracks) > 0 - tracks.sort() - - return tracks - - def equallySpacedSeq(m, arr): - seq = [] - n = len(arr) - # Bresenham - indices = [i * n // m + n // (2 * m) for i in range(m)] - for i in indices: - seq.append(arr[i]) - return seq - - # HUMAN SORTING: https://stackoverflow.com/questions/5967500/how-to-correctly-sort-a-string-with-a-number-inside - def natural_keys(enum): - def atof(text): - try: - retval = float(text) - except ValueError: - retval = text - return retval - - text = enum[0] - text = re.sub(r"(\[|\]|\.|\$)", "", text) - """ - alist.sort(key=natural_keys) sorts in human order - http://nedbatchelder.com/blog/200712/human_sorting.html - (see toothy's implementation in the comments) - float regex comes from https://stackoverflow.com/a/12643073/190597 - """ - return [ - atof(c) for c in re.split(r"[+-]?([0-9]+(?:[.][0-9]*)?|[.][0-9]+)", text) - ] - - def bus_keys(enum): - text = enum[0] - m = re.match(r"^.*\[(\d+)\]$", text) - if not m: - return -1 - else: - return int(m.group(1)) - - #2. Find the Slot matching next nearest slot-DineshA - def findSlot(val, arr): - for i in arr: - if(i > val): - return i - print("ERROR: Next Valid Position not found :",val) - return -1 - - # read config - - pin_placement_cfg = {"#N": [], "#E": [], "#S": [], "#W": []} - cur_side = None - if config_file_name is not None and config_file_name != "": - with open(config_file_name, "r") as config_file: - for line in config_file: - line = line.split() - if len(line) == 0: - continue - - #3. Dinesh A - Start - if(manual_place_flag == False): - if len(line) > 1: - print("Only one entry allowed per line.") - sys.exit(1) - token = line[0] - else: - #During Manual Place we are allowing Four field - # <Pad Name> <Offset> <Position> <Multiplier> - # Causion: Make sure that you have given absolute name, else it will give issue - if len(line) > 4: - print("Only Four entry allowed per line.") - sys.exit(1) - if line[0] not in ["#N", "#E", "#S", "#W", "#NR", "#ER", "#SR", "#WR"]: - token = line - else: - token = line[0] - - if cur_side is not None and token[0] != "#": - pin_placement_cfg[cur_side].append(token) - elif token not in [ - "#N", - "#E", - "#S", - "#W", - "#NR", - "#ER", - "#SR", - "#WR", - "#BUS_SORT", - "#MANUAL_PLACE" - ]: - print( - "Valid directives are #N, #E, #S, or #W. Append R for reversing the default order.", - "Use #BUS_SORT to group 'bus bits' by index.", - "Please make sure you have set a valid side first before listing pins", - ) - sys.exit(1) - elif token == "#BUS_SORT": - bus_sort_flag = True - #4 - Dinesh A - elif token == "#MANUAL_PLACE": - print("Input token ",token) - manual_place_flag = True - else: - if len(token) == 3: - token = token[0:2] - reverse_arr.append(token) - cur_side = token - - # build a list of pins - - chip_top = db_top.getChip() - block_top = chip_top.getBlock() - top_design_name = block_top.getName() - tech = db_top.getTech() - - H_LAYER = tech.findLayer(h_layer_name) - V_LAYER = tech.findLayer(v_layer_name) - - H_WIDTH = int(h_width_mult * H_LAYER.getWidth()) - V_WIDTH = int(v_width_mult * V_LAYER.getWidth()) - - print("Top-level design name:", top_design_name) - - bterms = block_top.getBTerms() - bterms_enum = [] - for bterm in bterms: - pin_name = bterm.getName() - bterms_enum.append((pin_name, bterm)) - - # sort them "humanly" - bterms_enum.sort(key=natural_keys) - if bus_sort_flag: - bterms_enum.sort(key=bus_keys) - bterms = [bterm[1] for bterm in bterms_enum] - - pin_placement = {"#N": [], "#E": [], "#S": [], "#W": []} - bterm_regex_map = {} - #5. Dinesh A - if(manual_place_flag == False): - for side in pin_placement_cfg: - for regex in pin_placement_cfg[side]: # going through them in order - regex += "$" # anchor - for bterm in bterms: - # if a pin name matches multiple regexes, their order will be - # arbitrary. More refinement requires more strict regexes (or just - # the exact pin name). - pin_name = bterm.getName() - if re.match(regex, pin_name) is not None: - if bterm in bterm_regex_map: - print( - "Error: Multiple regexes matched", - pin_name, - ". Those are", - bterm_regex_map[bterm], - "and", - regex, - ) - sys.exit(os.EX_DATAERR) - bterm_regex_map[bterm] = regex - pin_placement[side].append(bterm) # to maintain the order - - unmatched_bterms = [bterm for bterm in bterms if bterm not in bterm_regex_map] - - if len(unmatched_bterms) > 0: - print("Warning: Some pins weren't matched by the config file") - print("Those are:", [bterm.getName() for bterm in unmatched_bterms]) - if True: - print("Assigning random sides to the above pins") - for bterm in unmatched_bterms: - random_side = random.choice(list(pin_placement.keys())) - pin_placement[random_side].append(bterm) - else: - sys.exit(1) - - #6 Dinesh A - else: - for side in pin_placement_cfg: - for regex in pin_placement_cfg[side]: # going through them in order - regex = regex[0] # take first value - regex += "$" # anchor - for bterm in bterms: - # if a pin name matches multiple regexes, their order will be - # arbitrary. More refinement requires more strict regexes (or just - # the exact pin name). - pin_name = bterm.getName() - if re.match(regex, pin_name) is not None: - print("Debug: Serching Pin match",regex) - if bterm in bterm_regex_map: - #print("Warning: Multiple regexes matched", pin_name) - # ". Those are", bterm_regex_map[bterm], "and", regex) - sys.exit(1) - bterm_regex_map[bterm] = regex - pin_placement[side].append(bterm) # to maintain the order - - unmatched_bterms = [bterm for bterm in bterms if bterm not in bterm_regex_map] - - if len(unmatched_bterms) > 0: - print("Warning: Some pins weren't matched by the config file") - print("Those are:", [bterm.getName() for bterm in unmatched_bterms]) - sys.exit(1) - - - assert len(block_top.getBTerms()) == len( - pin_placement["#N"] - + pin_placement["#E"] - + pin_placement["#S"] - + pin_placement["#W"] - ) - - # generate slots - - DIE_AREA = block_top.getDieArea() - BLOCK_LL_X = DIE_AREA.xMin() - BLOCK_LL_Y = DIE_AREA.yMin() - BLOCK_UR_X = DIE_AREA.xMax() - BLOCK_UR_Y = DIE_AREA.yMax() - - print("Block boundaries:", BLOCK_LL_X, BLOCK_LL_Y, BLOCK_UR_X, BLOCK_UR_Y) - - origin, count, step = block_top.findTrackGrid(H_LAYER).getGridPatternY(0) - - #7. Save the horizontal origin and step - DineshA - h_origin = origin - h_step = step - - h_tracks = getGrid(origin, count, step) - - origin, count, step = block_top.findTrackGrid(V_LAYER).getGridPatternX(0) - - #8. Save the horizontal origin and step - DineshA - v_origin = origin - v_step = step - - v_tracks = getGrid(origin, count, step) - - for rev in reverse_arr: - pin_placement[rev].reverse() - - # create the pins - #9. DineshA - if(manual_place_flag == False): - for side in pin_placement: - if side in ["#N", "#S"]: - slots = equallySpacedSeq(len(pin_placement[side]), v_tracks) - else: - slots = equallySpacedSeq(len(pin_placement[side]), h_tracks) - - assert len(slots) == len(pin_placement[side]) - - for i in range(len(pin_placement[side])): - bterm = pin_placement[side][i] - slot = slots[i] - - pin_name = bterm.getName() - pins = bterm.getBPins() - if len(pins) > 0: - print("Warning:", pin_name, "already has shapes. Modifying them") - assert len(pins) == 1 - pin_bpin = pins[0] - else: - pin_bpin = odb.dbBPin_create(bterm) - - pin_bpin.setPlacementStatus("PLACED") - - if side in ["#N", "#S"]: - rect = odb.Rect(0, 0, V_WIDTH, LENGTH + V_EXTENSION) - if side == "#N": - y = BLOCK_UR_Y - LENGTH - else: - y = BLOCK_LL_Y - V_EXTENSION - rect.moveTo(slot - V_WIDTH // 2, y) - odb.dbBox_create(pin_bpin, V_LAYER, *rect.ll(), *rect.ur()) - else: - rect = odb.Rect(0, 0, LENGTH + H_EXTENSION, H_WIDTH) - if side == "#E": - x = BLOCK_UR_X - LENGTH - else: - x = BLOCK_LL_X - H_EXTENSION - rect.moveTo(x, slot - H_WIDTH // 2) - odb.dbBox_create(pin_bpin, H_LAYER, *rect.ll(), *rect.ur()) - - else: - #10.New Logic, Manual Pin Placement - Dinesh A - #print("Allowed VTracks",v_tracks) - #print("Allowed hTracks",h_tracks) - - for side in pin_placement: - - if(len(pin_placement[side]) != len(pin_placement_cfg[side])): - print("ERROR : At Side:", side, " Total Pin Defined ",len(pin_placement_cfg[side]), "More than available:",len(pin_placement[side])) - - #check defined pad are more than avaibale one - assert len(pin_placement[side]) == len(pin_placement_cfg[side]) - start = 0 - - start_loc = 0 - pad_pos = 0 - slot_pre = 0 - #Dinesh: Give Step Multipler size *2 for better pad placement - multiplier= 2 - for i in range(len(pin_placement_cfg[side])): - #Dinesh: Multiply the offset by 1000 for micro conversion - if(len(pin_placement_cfg[side][i]) > 1): - start_loc = int(pin_placement_cfg[side][i][1]) - if(len(pin_placement_cfg[side][i]) > 2): - pad_pos = int(pin_placement_cfg[side][i][2]) - if(len(pin_placement_cfg[side][i]) > 3): - multiplier = int(pin_placement_cfg[side][i][3]) - - if side in ["#N", "#S"]: - slott = start_loc*1000+int(v_origin)+(int(v_step) * pad_pos * multiplier) - slot =findSlot(slott,v_tracks) - else: - slott = start_loc*1000+int(h_origin)+(int(h_step) * pad_pos * multiplier) - slot =findSlot(slott,h_tracks) - - pad_pos +=1 - bterm = pin_placement[side][i] - - pin_name = bterm.getName() - pins = bterm.getBPins() - if len(pins) > 0: - print("Warning:", pin_name, "already has shapes. Modifying them") - assert len(pins) == 1 - pin_bpin = pins[0] - else: - pin_bpin = odb.dbBPin_create(bterm) - - if(slot < slot_pre): - print("ERROR:", "Current Pad:", pin_name, " Slot:" , slot, " is less than Previous One:",slot_pre) - sys.exit(1) - - slot_pre = slot - - print("Dinesh: Placing Pad:" ,pin_name, " At Side: ", side, " Slot: ", slot) - pin_bpin.setPlacementStatus("PLACED") - - if side in ["#N", "#S"]: - rect = odb.Rect(0, 0, V_WIDTH, LENGTH+V_EXTENSION) - if side == "#N": - y = BLOCK_UR_Y-LENGTH - else: - y = BLOCK_LL_Y-V_EXTENSION - rect.moveTo(slot-V_WIDTH//2, y) - odb.dbBox_create(pin_bpin, V_LAYER, *rect.ll(), *rect.ur()) - else: - rect = odb.Rect(0, 0, LENGTH+H_EXTENSION, H_WIDTH) - if side == "#E": - x = BLOCK_UR_X-LENGTH - else: - x = BLOCK_LL_X-H_EXTENSION - rect.moveTo(x, slot-H_WIDTH//2) - odb.dbBox_create(pin_bpin, H_LAYER, *rect.ll(), *rect.ur()) - - - print( - f"Writing {output_def_file_name}...", - ) - odb.write_def(block_top, output_def_file_name) - - -if __name__ == "__main__": - cli()
diff --git a/openlane/user_project_wrapper/config.tcl b/openlane/user_project_wrapper/config.tcl index 1a720a6..8d8c8e0 100644 --- a/openlane/user_project_wrapper/config.tcl +++ b/openlane/user_project_wrapper/config.tcl
@@ -20,11 +20,11 @@ set ::env(STD_CELL_LIBRARY) "sky130_fd_sc_hd" # YOU ARE NOT ALLOWED TO CHANGE ANY VARIABLES DEFINED IN THE FIXED WRAPPER CFGS -source $::env(CARAVEL_ROOT)/openlane/user_project_wrapper_empty/fixed_wrapper_cfgs.tcl +source $::env(CARAVEL_ROOT)/openlane/user_project_wrapper/fixed_wrapper_cfgs.tcl # YOU CAN CHANGE ANY VARIABLES DEFINED IN THE DEFAULT WRAPPER CFGS BY OVERRIDING THEM IN THIS CONFIG.TCL -source $::env(CARAVEL_ROOT)/openlane/user_project_wrapper_empty/default_wrapper_cfgs.tcl +source $::env(CARAVEL_ROOT)/openlane/user_project_wrapper/default_wrapper_cfgs.tcl set script_dir [file dirname [file normalize [info script]]]