# ############################################################################## # Tool: OpenFPGA-Physical # Script: fpga_grid_gen.py ################################################################################ ''' fpga_render_svg --------------- TODO: Requires Restructuring This scripts read the layout section of the VPR architecture file and render the layout in SVG format. The outputs are stored in the release directory (location passed as an argument) to this script. python3.8 RenderArchitectureSVG.py \ --design_name FPGA66_flex \ --arch_file example_files/vpr_arch_render_demo.xml \ --layout dp \ --skip_channels \ --output_root _release ''' import argparse import csv import logging import math import os import pickle import sys import xml.etree.ElementTree as ET from importlib import util # Prinitng and logging related packages from pprint import pprint import matplotlib.pyplot as plt import numpy as np import pandas as pd import svgwrite import yaml from svgwrite.container import Group from openfpga_physical import fpga_grid_gen if util.find_spec("coloredlogs"): import coloredlogs # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = # Configure logging system # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = LOG_FORMAT = "%(levelname)5s (%(threadName)15s) - %(message)s" if util.find_spec("coloredlogs"): coloredlogs.install(level='INFO', stream=sys.stdout, fmt=LOG_FORMAT) else: logging.basicConfig(level=logging.INFO, stream=sys.stdout, format=LOG_FORMAT) logger = logging.getLogger('RenderArchitecureSVG_logs') # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = def formatter(prog): return argparse.HelpFormatter(prog, max_help_position=60) parser = argparse.ArgumentParser(formatter_class=formatter) # Mandatory arguments parser.add_argument('--design_name', type=str, default="FPGA22_QLAP3_SOFA_HD") parser.add_argument('--arch_file', type=str, default="vpr_arch.xml") parser.add_argument('--layout', type=str, default="dp") # Configuration files parser.add_argument('--shaping_conf_file', type=str, default="") parser.add_argument('--area_file', type=str, default="") parser.add_argument('--output_root', type=str, default="release") # Rendering Related Parameters parser.add_argument('--physical', action='store_true') parser.add_argument('--clear_color', action='store_true') parser.add_argument('--skip_channels', action='store_true') parser.add_argument('--add_pads', action='store_true') parser.add_argument('--cmap', action='store_true') parser.add_argument('--debug', action='store_true') args = parser.parse_args() # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = area, width, height = 0, 1, 2 CPP = 4 SC_HEIGHT = 4 LOGICAL = not args.physical def main(): grid = fpga_grid_gen( design_name=args.design_name, arch_file=args.arch_file, layout=args.layout, release_root="") FPGA_SIZE = tuple([grid.get_width(), grid.get_height()]) DESIGN_NAME = args.design_name SaveLocation = [args.output_root, ] for eachLoc in ["data", "pickle", "TCL", "SVG", "ConnectNets", "PNG"]: os.makedirs(os.path.join(*SaveLocation, eachLoc), exist_ok=True) # = = = = = = Create dummy area file = = = = = = = = = = = = = = = = = = = # incase of logical model create intermidiate file if LOGICAL: args.area_file = "_areafile.txt" with open(args.area_file, "w") as fp: CLBA, CBA = (32*32, 40) fp.write(f"grid_clb_1__1_ {CLBA} 0 0 0\n") fp.write(f"cbx_1__1_ {CBA} 0 0 0\n") # = = = = = = Shaping Configuration file = = = = = = = = = = = = = = = = = args.shaping_conf_file = "_shapingConf.yml" with open(args.shaping_conf_file, "w") as file: yaml.dump({"CLB_CHAN_X": 10, "SC_RATIO": SC_HEIGHT/CPP, "CPP": CPP, "SC_HEIGHT": SC_HEIGHT, "GRID_CLB_RATIO": 1, "CBX_WIDTH_RATIO": 0.6, "CBY_HEIGHT_RATIO": 0.6, "GRID_RATIO_X": 1.4, "GRID_RATIO_Y": 1.4, "CBx_CHAN_X": 0, "gridIO_HT": 10, "gridIO_HB": 10, "gridIO_WL": 12, "gridIO_WR": 12, "CBx_CHAN_Y": 0}, file) # = = = = = = Read Pinmap = = = = = = = = = = = = = = = = = = = = = = = = FPGAShape = FPGAShaping(FPGA_SIZE[0], FPGA_SIZE[1], debug=args.debug, areaFile=args.area_file, shapingConf=args.shaping_conf_file, gridIO=LOGICAL, arch_file=args.arch_file, layout_name=args.layout, padFile=None) FPGAShape.ComputeGrid(skipChannels=args.skip_channels) FPGAShape.CreateDatabase() # = = = = = = = = Setting up SVG Canvas = = = = = = = = = = = = = = = = = = CoreBBox = (0, 0, int(FPGAShape.CLB_GRID_X*(FPGA_SIZE[0]+1))*CPP, int(FPGAShape.CLB_GRID_Y*(FPGA_SIZE[1]+1))*SC_HEIGHT) svgFilepath = os.path.join( *SaveLocation, "SVG", DESIGN_NAME + '_Render.svg') dwg = svgwrite.Drawing(svgFilepath, CoreBBox[2:]) dwg.viewbox(0, -1*CoreBBox[3], CoreBBox[2], CoreBBox[3]) dwgMain = dwg.add(Group(id="main", transform="scale(1,-1)")) dwgMain.add(dwg.rect(size=CoreBBox[2:], id="core_boundary", class_="boundary", stroke="grey", fill="none", stroke_width=2)) dwg.defs.add(dwg.style(""" text{font-family: Verdana; } .cbx_1__0__def{fill:#d9d9f3} .cbx_1__1__def{fill:#d9d9f3} .cbx_1__2__def{fill:#d9d9f3} .cby_0__1__def{fill:#a8d0db} .cby_1__1__def{fill:#a8d0db} .cby_2__1__def{fill:#a8d0db} .sb_0__0__def{fill:#ceefe4} .sb_0__1__def{fill:#ceefe4} .sb_0__2__def{fill:#ceefe4} .sb_1__0__def{fill:#ceefe4} .sb_1__1__def{fill:#ceefe4} .sb_1__2__def{fill:#ceefe4} .sb_2__0__def{fill:#ceefe4} .sb_2__1__def{fill:#ceefe4} .sb_2__2__def{fill:#ceefe4} .grid_def{fill:#f4f0e6;} """)) dwgShapes = dwgMain.add(Group(id="mainShapes")) dwgText = dwgMain.add(Group(id="mainText")) dwgGridShapes = dwgMain.add(Group(id="gridShapes")) dwgGridText = dwgMain.add(Group(id="gridText")) dwgMarker = dwgMain.add(Group(id="mainMarker")) # addGrid markers for i in range(1, FPGAShape.sizeX+1): dwgMarker.add(dwg.line(start=(i*FPGAShape.CLB_GRID_X*CPP, CoreBBox[1]), end=(i*FPGAShape.CLB_GRID_X*CPP, CoreBBox[3]), class_="marker")) for i in range(1, FPGAShape.sizeY+1): dwgMarker.add(dwg.line(start=(CoreBBox[0], i*FPGAShape.CLB_GRID_Y*SC_HEIGHT), end=(CoreBBox[2], i * FPGAShape.CLB_GRID_Y*SC_HEIGHT), class_="marker")) defList = {} UniqueModules = [i["module"] for _, i in FPGAShape.PlacementDBKey.items()] UniqueModules = set(UniqueModules) UniqueModules = list( filter(lambda x: not "grid_io" in x, set(UniqueModules))) for eachModule in sorted(FPGAShape.PlacementDB, key=lambda x: "y" if "grid_clb" in x else 'z' if "grid" in x else x): if (not args.add_pads) and ("grid_io" in eachModule): continue # Shape Definitions mouleinfo = FPGAShape.PlacementDBKey[eachModule] Module = mouleinfo["module"] if not Module in defList.keys(): defList[Module] = dwg.symbol(id=Module) xx = min([i[0] for i in mouleinfo["shape"]]) yy = min([i[1] for i in mouleinfo["shape"]]) if len(mouleinfo["shape"]) == 1: llx, lly, w, h = mouleinfo["shape"][0] defList[Module].add(dwg.rect(size=(float(w)*CPP, float(h)*SC_HEIGHT), insert=((llx-xx)*CPP, (lly-yy)*SC_HEIGHT), # fill=mouleinfo["color"], fill_opacity="1" if "grid" in Module else "0.7", stroke="black")) elif len(mouleinfo["shape"]) == 2: Points = f"M " Points += f"{mouleinfo['points'][0]*CPP} " Points += f"{mouleinfo['points'][1]*SC_HEIGHT} " Points += f"L " for X, Y in np.reshape(np.array(mouleinfo['points'][2:]), (int(len(mouleinfo['points'])*0.5)-1, 2)): Points += f"{X*CPP} " Points += f"{Y*SC_HEIGHT} " defList[Module].add(dwg.path(d=Points + " z", fill=mouleinfo["color"], fill_opacity="0.7", stroke="black")) dwg.defs.add(defList[Module]) # Instantiation x1, y1, w, h = mouleinfo["bbox"] shapedwg = dwgGridShapes if "grid" in Module else dwgShapes shapedwg.add(dwg.use(defList[Module], class_=f"{Module}_def {eachModule}" + (" grid_def" if "grid" in Module else ""), insert=((x1*CPP), (y1*SC_HEIGHT)))) # # Uncomment following lines to print center of module # dwgShapes.add(dwg.circle( # center=(mouleinfo['center'][0]*CPP, # mouleinfo['center'][1]*SC_HEIGHT), # r=2,fill="red")) x1, y1 = mouleinfo["center"] textdwg = dwgGridText if "grid" in Module else dwgText textdwg.add(dwg.text(f" {mouleinfo['short_name']} ", insert=((x1*CPP), (-1*y1*SC_HEIGHT)), transform="scale(1,-1)", class_="moduleLabel", fill="black", alignment_baseline="middle", text_anchor="middle")) if LOGICAL: logger.info("Printing Logical Model") logger.info(f"Rendered image stored in {svgFilepath}") dwg.save(pretty=True, indent=4) pickle.dump(FPGAShape.get_variables(), open(os.path.join(*SaveLocation, "pickle", f"{DESIGN_NAME}_FPGAShapeVars.pickle"), 'wb')) pickle.dump(FPGAShape.PlacementDBKey, open(os.path.join(*SaveLocation, "pickle", f"{DESIGN_NAME}_PlacementDBKey.pickle"), 'wb')) pickle.dump(FPGAShape.PlacementDB, open(os.path.join(*SaveLocation, "pickle", f"{DESIGN_NAME}_PlacementDB.pickle"), 'wb')) pickle.dump(dwg, open(os.path.join(*SaveLocation, "pickle", f"{DESIGN_NAME}_dwg.pickle"), 'wb')) pickle.dump(FPGAShape.grid, open(os.path.join(*SaveLocation, "pickle", f"{DESIGN_NAME}_grid.pickle"), 'wb')) return class FPGAShaping(): """ Accepts the architecture file and layout name to generate a tile database to render as an SVG args: """ def __init__(self, sizeX, sizeY, debug=False, areaFile=None, padFile=None, gridIO=False, arch_file=None, layout_name="", shapingConf=None): self.sizeX = sizeX self.sizeY = sizeY self.PlacementDB = [] self.PlacementDBKey = {} self.GPIOPlacmentKey = [] self.debug = debug self.get_default_configuration() self.areaFile = areaFile self.padFile = padFile self.gridIO = gridIO self.PadNames = {} self.skipChannels = False # Color Setting self.CLB_COLOR = "#f4f0e6" self.CBX_COLOR = "#d9d9f3" self.CBY_COLOR = "#a8d0db" self.SB_COLOR = "#ceefe4" self.PAD_COLOR = "#204969" self.GRID_IO_COLOR = "#ff8000" # Pads Related self.pad_w = 80 self.pad_h = 10 self.arch_file = arch_file self.layout_name = layout_name if shapingConf: self.update_default_configuration(shapingConf) self.grid = fpga_grid_gen("", arch_file, layout_name, "") self.fpga_grid = self.grid.enumerate_grid() self.grid.print_grid() def update_default_configuration(self, shapingConf): with open(shapingConf, "r") as file: for eachKey, eachValue in yaml.load(file, Loader=yaml.FullLoader).items(): setattr(self, eachKey, eachValue) def get_default_configuration(self): # Grid clb shape self.SC_RATIO = 8 # This is SC_HEIGHT/CPP of stadard cell self.GRID_CLB_RATIO = 1 # This is actual dimension of the CLB unit width/height # Connection box size self.GRID_RATIO_X, self.GRID_RATIO_Y = 1.34, 1.48 self.CBX_WIDTH_RATIO, self.CBY_HEIGHT_RATIO = 0.6, 0.6 # Channel spacing between blocks self.CLB_CHAN_T, self.CLB_CHAN_B = 1, 1 self.CLB_CHAN_L, self.CLB_CHAN_R = 4, 4 self.CBX_CHAN_T, self.CBX_CHAN_B = 0, 0 self.CBX_CHAN_L, self.CBX_CHAN_R = 4, 4 self.CBY_CHAN_T, self.CBY_CHAN_B = 1, 1 self.CBY_CHAN_L, self.CBY_CHAN_R = 0, 0 self.gridIO_MT, self.gridIO_MB = 1, 1 self.gridIO_ML, self.gridIO_MR = 2, 2 self.gridIO_HT, self.gridIO_HB = 10, 10 self.gridIO_WL, self.gridIO_WR = 48, 48 self.GRID_IOV_H_RATIO = 1 self.GRID_IOH_W_RATIO = 1 # TODO: Deprecate this self.GPIO_CHAN_X, self.GPIO_CHAN_Y = 12, 4 self.GPIO_WIDTH, self.GPIO_HEIGHT = 40, 8 def get_variables(self): return { "CPP": self.CPP, "SC_HEIGHT": self.SC_HEIGHT, "CLB_COLOR": self.CLB_COLOR, "CBX_COLOR": self.CBX_COLOR, "CBY_COLOR": self.CBY_COLOR, "SB_COLOR": self.SB_COLOR, "PAD_COLOR": self.PAD_COLOR, "GRID_IO_COLOR": self.GRID_IO_COLOR, "CORE_BBOX": (0, 0, int(self.CLB_GRID_X*(self.sizeX+1)), int(self.CLB_GRID_Y*(self.sizeY+1))) } def figSize(self): size = (4+(1*self.sizeX), 4+(1*self.sizeY)) if self.sizeX < 16: dpi = 300 elif self.sizeX < 64: dpi = 100 else: dpi = 50 return {"size": size, "dpi": dpi} def snapDims(self, num, dim=2): return math.ceil(num/dim)*dim def setChannelSpacing(self, module, X, Y): raise NotImplementedError def ComputeGrid(self, skipChannels=False): self.skipChannels = skipChannels if self.areaFile: BlockArea = {} for eachLine in open(self.areaFile, "r"): module, dims = eachLine.split(" ", 1) BlockArea[module] = list(map(float, list(dims.split()))) self.CLB_DIM = BlockArea["grid_clb_1__1_"] self.CB_DIM = BlockArea["cbx_1__1_"] # self.CLB_DIM = math.floor(BlockArea["grid_clb_1__1_"][1]*0.5)*2 # self.CB_DIM = [self.CLB_DIM*0.6, 0, 0] else: self.CLB_DIM = [2500, 24*8, 24] self.CB_DIM = [2500*0.6, 0, 0] # Snap CLB Height and Width to next Multiple of 2 self.CLB_UNIT = math.sqrt( self.CLB_DIM[area]/(self.GRID_CLB_RATIO*self.SC_RATIO)) self.CLB_H = self.snapDims(self.CLB_UNIT, 2) self.CLB_W = self.snapDims(self.CLB_DIM[area]/self.CLB_H, 2) self.CLB_GRID_X = self.snapDims(self.CLB_W*self.GRID_RATIO_X, 2) self.CLB_GRID_Y = self.snapDims(self.CLB_H*self.GRID_RATIO_Y, 2) self.CBX_W = self.snapDims(self.CLB_W*self.CBX_WIDTH_RATIO, 2) self.CBX_H = self.CLB_GRID_Y-self.CLB_H self.CBY_W = self.CLB_GRID_X-self.CLB_W self.CBY_H = self.snapDims(self.CLB_H*self.CBY_HEIGHT_RATIO, 2) self.SB_W = self.CLB_GRID_X - self.CBX_W self.SB_H = self.CLB_GRID_Y - self.CBY_H self.SIDE_X = self.CLB_GRID_X - self.CLB_W self.SIDE_Y = self.CLB_GRID_Y - self.CLB_H self.GRID_IOV_H = self.CLB_H*self.GRID_IOV_H_RATIO self.GRID_IOH_W = self.CLB_W*self.GRID_IOH_W_RATIO if self.debug: print(f"self.CLB_W {self.CLB_W}") print(f"self.CLB_H {self.CLB_H}") print(f"self.CLB_GRID_X {self.CLB_GRID_X}") print(f"self.CLB_GRID_Y {self.CLB_GRID_Y}") print(f"self.CBX_W {self.CBX_W}") print(f"self.CBX_H {self.CBX_H}") print(f"self.CBY_W {self.CBY_W}") print(f"self.CBY_H {self.CBY_H}") print(f"self.SB_W {self.SB_W}") print(f"self.SB_H {self.SB_H}") if self.padFile: if os.path.exists(self.padFile): print(f"Found PinMapFile {self.padFile}") df_pinMap = pd.read_csv(self.padFile) df_pinMap.rename(columns=lambda x: x.strip(), inplace=True) self.PadNames["L"] = df_pinMap["Remark"] self.PadNames["T"] = df_pinMap["Remark.1"] self.PadNames["R"] = df_pinMap["Remark.2"] self.PadNames["B"] = df_pinMap["Remark.3"] self.NumOfPads = len(df_pinMap.index) def CreateDatabase(self): # Create Blocks grid_ele_size = {} for x in range(self.sizeX+1): for y in range(self.sizeY+1): self.add_sb(x, y) if x < self.sizeX: self.add_cbx(x, y) if y < self.sizeY: self.add_cby(x, y) if (x < self.sizeX) and (y < self.sizeY): label = self.fpga_grid[y+1][x+1] if not (label in [self.grid.RIGHT_ARROW, self.grid.UP_ARROW, "EMPTY"]): if not label in grid_ele_size.keys(): ele_w, ele_h = self.grid.fpga_arch.tiles[label] grid_ele_size[label] = (ele_w, ele_h) else: ele_w, ele_h = grid_ele_size[label] self.add_clb(x, y, width=ele_w, height=ele_h, lbl=label) # Create gridIOs if self.gridIO: if (y == self.sizeY) and (x < self.sizeX): self.add_gridIOH(x, y, side="top") if (y == 0) and (x < self.sizeX): self.add_gridIOH(x, y, side="bottom") if (x == 0) and (y < self.sizeY): self.add_gridIOV(x, y, side="left") if (x == self.sizeX) and (y < self.sizeY): self.add_gridIOV(x, y, side="right") # Create Pins if self.PadNames: for side in ["L", "T", "R", "B"]: for i in range(self.NumOfPads): self.add_pad(side, i, self.PadNames[side][i]) return self.PlacementDB def add_clb(self, xi, yi, width=1, height=1, lbl="grid_clb"): x, y = (xi+1)*self.CLB_GRID_X, (yi+1)*self.CLB_GRID_Y llx = x-self.snapDims(self.CLB_W*0.5) lly = y-self.snapDims(self.CLB_H*0.5) W1 = self.CLB_W + ((width-1) * self.CLB_GRID_X) H1 = self.CLB_H + ((height-1) * self.CLB_GRID_Y) initShape = [(llx, lly, W1, H1)] x += ((width-1) * self.CLB_GRID_X)*0.5 y += ((height-1) * self.CLB_GRID_Y)*0.5 if not self.skipChannels: llx += self.CLB_CHAN_L lly += self.CLB_CHAN_B W1 = self.CLB_W-self.CLB_CHAN_L-self.CLB_CHAN_R H1 = self.CLB_H-self.CLB_CHAN_T-self.CLB_CHAN_B block_name = f"grid_{lbl}_{xi+1}__{yi+1}_" short_block_name = f"{lbl}_{xi+1}_{yi+1}" COLOR = self.CLB_COLOR points = [0, 0, 0, self.CLB_H, self.CLB_W, self.CLB_H, self.CLB_W, 0] self.PlacementDB.append(block_name) self.PlacementDBKey[block_name] = {"name": block_name, "short_name": short_block_name, "bbox": [llx, lly, llx+W1, lly+H1], "points": points, "module": f"grid_{lbl}_1__1_", "center": [x, y], "color": COLOR, "shape": [(llx, lly, W1, H1)], "initShape": initShape, "xi": xi, "yi": yi} def add_cbx(self, xi, yi, lbl=None): x, y = (xi+1)*self.CLB_GRID_X, (yi+1)*self.CLB_GRID_Y llx = x-self.snapDims((self.CBX_W)*0.5) lly = y-self.snapDims((self.CLB_H*0.5)+self.CBX_H) W1 = self.CBX_W H1 = self.CBX_H initShape = [(llx, lly, W1, H1)] if not self.skipChannels: llx += self.CBX_CHAN_L lly += self.CBX_CHAN_B W1 = self.CBX_W-self.CBX_CHAN_L-self.CBX_CHAN_R H1 = self.CBX_H-self.CBX_CHAN_T-self.CBX_CHAN_B block_name = f"cbx_{xi+1}__{yi}_" short_block_name = f"CX_{xi+1}_{yi}" points = [0, 0, 0, W1, H1, W1, H1, 0] self.PlacementDB.append(block_name) moduleName = "cbx_1__0_" if yi == 0 else "cbx_1__2_" if yi == self.sizeY else "cbx_1__1_" self.PlacementDBKey[block_name] = {"name": block_name, "short_name": short_block_name, "bbox": [llx, lly, llx+W1, lly+H1], "points": points, "center": [llx+W1*0.5, lly+H1*0.5], "module": moduleName, "color": self.CBX_COLOR, "shape": [(llx, lly, W1, H1)], "initShape": initShape, "xi": xi, "yi": yi} def add_cby(self, xi, yi, lbl=None): x, y = (xi+1)*self.CLB_GRID_X, (yi+1)*self.CLB_GRID_Y llx = x-self.snapDims((self.CLB_W*0.5)+self.CBY_W) lly = y-self.snapDims(self.CBY_H)*0.5 W1 = self.CBY_W H1 = self.CBY_H initShape = [(llx, lly, W1, H1)] if not self.skipChannels: llx += self.CBY_CHAN_L lly += self.CBY_CHAN_B W1 = self.CBY_W-self.CBY_CHAN_L-self.CBY_CHAN_R H1 = self.CBY_H-self.CBY_CHAN_T-self.CBY_CHAN_B block_name = f"cby_{xi}__{yi+1}_" short_block_name = f"CY_{xi}_{yi+1}" points = [0, 0, 0, W1, H1, W1, H1, 0] self.PlacementDB.append(block_name) moduleName = "cby_0__1_" if xi == 0 else "cby_2__1_" if xi == self.sizeY else "cby_1__1_" self.PlacementDBKey[block_name] = {"name": block_name, "short_name": short_block_name, "bbox": [llx, lly, llx+W1, lly+H1], "points": points, "center": [llx+W1*0.5, lly+H1*0.5], "module": moduleName, "color": self.CBY_COLOR, "shape": [(llx, lly, W1, H1)], "initShape": initShape, "xi": xi, "yi": yi} def get_stype(self, x, y): if x == 0: if y == 0: return 1 elif y == self.sizeY: return 3 else: return 2 elif x == self.sizeX: if y == 0: return 7 elif y == self.sizeY: return 5 else: return 6 else: if y == 0: return 8 elif y == self.sizeY: return 4 else: if self.grid.get_block(x, y+1) == self.grid.get_block(x+1, y+1): return 4 if self.grid.get_block(x+1, y+1) == self.grid.get_block(x+1, y): return 6 if self.grid.get_block(x, y) == self.grid.get_block(x+1, y): return 8 if self.grid.get_block(x, y) == self.grid.get_block(x, y+1): return 2 else: return 0 def unique(self, sequence): seen = set() u = [x for x in sequence if not (x in seen or seen.add(x))] return [val for sublist in u for val in sublist] def add_sb(self, xi, yi): ''' d +----+ c | | b | | e +----+ +----+ a | | Cross Shape | | -lengths {a b c d e f} +----+ +----+ | | | | f +----+ ''' x = xi*self.CLB_GRID_X y = yi*self.CLB_GRID_Y llxB1 = x+(0.5*self.CLB_W) llyB1 = y+(self.CBY_H*0.5) WidthB1 = self.SIDE_X HeightB1 = self.SB_H llxB2 = x + (self.CBX_W*0.5) llyB2 = y + (self.CLB_H*0.5) WidthB2 = self.SB_W HeightB2 = self.SIDE_Y a = self.SIDE_Y b = e = (WidthB2-self.SIDE_X) * 0.5 c = f = (HeightB1-self.SIDE_Y)*0.5 d = self.SIDE_X Stype = self.get_stype(xi, yi) if Stype == 1: # SB_0__0_ llyB1 += c HeightB1 += -c llxB2 += b WidthB2 += -b b = f = 0 elif Stype == 2: # SB_0__1_ llxB2 += b WidthB2 -= b b = 0 elif Stype == 3: # SB_0__2_ llxB2 += b WidthB2 -= b HeightB1 -= f c = b = 0 elif Stype == 4: # SB_1__2_ HeightB1 -= c c = 0 elif Stype == 5: # SB_2__2_ HeightB1 -= c WidthB2 -= e c = e = 0 elif Stype == 6: # SB_2__1_ WidthB2 -= e e = 0 elif Stype == 7: # SB_2__0_ llyB1 += f HeightB1 -= f WidthB2 -= e e = f = 0 elif Stype == 8: # SB_1__0_ llyB1 += f HeightB1 -= f f = 0 block_name = f"sb_{xi}__{yi}_" short_block_name = f"SB_{xi}_{yi}" initShape = [(llxB1, llyB1, WidthB1, HeightB1), (llxB2, llyB2, WidthB2, HeightB2)] # initShape = [(llxB1, llyB1, WidthB1, HeightB1), ] # initShape = [(llxB2, llyB2, WidthB2, HeightB2), ] points = self.unique([(b, 0), (b, f), (0, f), (0, (f+a)), (b, (f+a)), (b, (a+c+f)), ((b+d), (a+c+f)), ((b+d), (a+f)), ((b+d+e), (a+f)), ((b+d+e), f), ((b+d), f), ((b+d), 0)]) self.PlacementDB.append(block_name) moduleNames = [ "sb_1__1_", "sb_0__0_", "sb_0__1_", "sb_0__2_", "sb_1__2_", "sb_2__2_", "sb_2__1_", "sb_2__0_", "sb_1__0_", ] # ┿ ┗ ┝ ┏ ┯ ┓ ┫ ┛ ┷ ┃ ━ llx = min([i[0] for i in initShape]) lly = min([i[1] for i in initShape]) self.PlacementDBKey[block_name] = {"name": block_name, "short_name": short_block_name, "bbox": [llx, lly, llx+f+a+c, lly+b+d+e], "points": points, "center": [llx+(WidthB1*0.5)+b, lly+(HeightB2*0.5)+f], "module": moduleNames[Stype], "color": self.SB_COLOR, "shape": initShape, "xi": xi, "yi": yi, "dims": [a, b, c, d, e, f], "initShape": initShape} def add_gridIOH(self, xi, yi, side, lbl=None): x, y = (xi+1)*self.CLB_GRID_X, (yi+1)*self.CLB_GRID_Y llx = x-self.snapDims((self.GRID_IOH_W)*0.5) lly = y-self.snapDims((self.CLB_H*0.5)+self.CBX_H) lly += (-1*self.gridIO_HB) if side == "bottom" else self.CBX_H W1 = self.GRID_IOH_W H1 = self.gridIO_HB initShape = [(llx, lly, W1, H1)] if not self.skipChannels: llx += self.CBX_CHAN_L lly += 0 if side == "bottom" else self.gridIO_MT W1 = self.GRID_IOH_W-self.CBX_CHAN_L-self.CBX_CHAN_R H1 = self.gridIO_HB-self.gridIO_MB if side == "bottom": moduleName = "grid_io_bottom_bottom" block_name = f"grid_io_{side}_{side}_{xi+1}__{yi}_" short_block_name = f"io{side}_{xi+1}_{yi}" else: moduleName = "grid_io_top_top" block_name = f"grid_io_{side}_{side}_{xi+1}__{yi+1}_" short_block_name = f"io{side}_{xi+1}_{yi+1}" points = [0, 0, 0, W1, H1, W1, H1, 0] self.PlacementDB.append(block_name) self.PlacementDBKey[block_name] = {"name": block_name, "short_name": short_block_name, "bbox": [llx, lly, llx+W1, lly+H1], "points": points, "center": [llx+W1*0.5, lly+H1*0.5], "module": moduleName, "color": self.GRID_IO_COLOR, "shape": [(llx, lly, W1, H1)], "initShape": initShape} def add_gridIOV(self, xi, yi, side, lbl=None): x, y = (xi+1)*self.CLB_GRID_X, (yi+1)*self.CLB_GRID_Y llx = x-self.snapDims((self.CLB_W*0.5)+self.CBY_W) lly = y-self.snapDims(self.GRID_IOV_H)*0.5 llx += (-1*(self.gridIO_WL)) if side == "left" else self.CBY_W W1 = self.gridIO_WL H1 = self.GRID_IOV_H initShape = [(llx, lly, W1, H1)] if not self.skipChannels: llx += self.CBY_CHAN_L llx += (-1*self.gridIO_ML) if side == "left" else self.gridIO_MR lly += self.CBY_CHAN_B W1 = self.gridIO_WL-self.gridIO_ML H1 = self.GRID_IOV_H-self.CBY_CHAN_T-self.CBY_CHAN_B if side == "left": block_name = f"grid_io_{side}_{side}_{xi}__{yi+1}_" short_block_name = f"io{side}_{xi}_{yi+1}" moduleName = "grid_io_left_left" else: block_name = f"grid_io_{side}_{side}_{xi+1}__{yi+1}_" short_block_name = f"io{side}_{xi+1}_{yi+1}" moduleName = "grid_io_right_right" points = [0, 0, 0, W1, H1, W1, H1, 0] self.PlacementDB.append(block_name) self.PlacementDBKey[block_name] = {"name": block_name, "short_name": short_block_name, "bbox": [llx, lly, llx+W1, lly+H1], "points": points, "center": [llx+W1*0.5, lly+H1*0.5], "module": moduleName, "color": self.GRID_IO_COLOR, "shape": [(llx, lly, W1, H1)], "initShape": initShape} def add_pad(self, side="L", number=0, padname="xx"): CoreMinX, CoreMinY = (0.5*self.CLB_W), (0.5*self.CLB_H) CoreMaxX, CoreMaxY = (((self.sizeX+0.5) * self.CLB_GRID_X)+0.5*self.CBY_W, ((self.sizeY+0.5) * self.CLB_GRID_Y)+0.5*self.CBX_H) if side in ["L", "R"]: pad_w = self.pad_w pad_h = (((self.CLB_H+self.CBX_H)*self.sizeY+1) + self.CBX_H)/self.NumOfPads shift = (number*pad_h) initialshitX = (self.CLB_GRID_Y - self.CBX_H-(self.CLB_H*0.5)) initialshitY = (self.CLB_GRID_X - self.CBY_W-(self.CLB_W*0.5)) pad_spacing = 24 if side == "L": pad_x = CoreMinX - (pad_w*0.5) - pad_spacing pad_y = initialshitX + shift + pad_h*0.5 pad_llx = pad_x - (pad_w*0.5) pad_lly = pad_y - (pad_h*0.5) pad_w, pad_h = pad_w, pad_h rot = 0 t = 0.5 elif side == "R": pad_x = CoreMaxX + (pad_w*0.5) + pad_spacing pad_y = initialshitX + shift + pad_h*0.5 pad_llx = pad_x - (pad_w*0.5) pad_lly = pad_y - (pad_h*0.5) pad_w, pad_h = pad_w, pad_h rot = 0 t = 0.5 else: pad_w = (((self.CLB_W+self.CBY_W)*self.sizeX+1) + self.CBY_W)/self.NumOfPads pad_h = self.pad_h shift = (number*pad_w) initialshitY = (self.CLB_GRID_X - self.CBY_W-(self.CLB_W*0.5)) pad_spacing = 3 if side == "T": pad_x = initialshitY + shift + pad_w*0.5 pad_y = CoreMaxY + pad_spacing + pad_h*0.5 pad_llx = pad_x - (0.5*pad_w) pad_lly = pad_y - pad_h*0.5 pad_w, pad_h = pad_w, pad_h rot = 90 t = 0.5 elif side == "B": pad_x = initialshitY + shift + pad_w*0.5 pad_y = CoreMinY - pad_spacing - pad_h*0.5 pad_llx = pad_x - (0.5*pad_w) pad_lly = pad_y - pad_h*0.5 pad_w, pad_h = pad_w, pad_h rot = -90 t = 0.5 self.GPIOPlacmentKey.append( { "side": side, "rot": rot, "text": padname.strip(), "shape": [(pad_llx, pad_lly, pad_w, pad_h)], "color": self.PAD_COLOR, "center": [pad_x, pad_y], } ) def moduleFmt(self, mod, X, Y): return f"{mod}_{X}__{Y}_" if __name__ == "__main__": main()