#!/usr/bin/env python3 import os import re from edalize.edatool import get_edatool packages = { "Artix": { "xc7a12t" : ["cpg238", "csg325"], "xc7a15t" : ["cpg236", "csg324", "csg325", "ftg256", "fgg484"], "xc7a25t" : ["cpg238", "csg325"], "xc7a35t" : ["cpg236", "csg324", "csg325", "ftg256", "fgg484"], "xc7a50t" : ["cpg236", "csg324", "csg325", "ftg256", "fgg484"], "xc7a75t" : ["csg324", "ftg256", "fgg484", "fgg676"], "xc7a100t" : ["csg324", "ftg256", "fgg484", "fgg676"], "xc7a200t" : ["sbg484", "fbg484", "fbg676", "ffg1156"], }, # Added but seems not possible to use same bitstream # for all Kintex with the same size but different package. "Kintex 7": { "xc7k70t" : ["fbg484", "fbg676"], "xc7k160t" : ["fbg484", "fbg676", "ffg676"], "xc7k325t" : ["fbg676", "ffg676", "fbg900", "ffg900"], "xc7k355t" : ["ffg901"], "xc7k410t" : ["fbg676", "ffg676", "fbg900", "ffg900"], "xc7k420t" : ["ffg901", "ffg1156"], "xc7k480t" : ["ffg901", "ffg1156"], }, "Spartan 7": { "xc7s6" : ["ftgb196", "cpga196", "csga225"], "xc7s15" : ["ftgb196", "cpga196", "csga225"], "xc7s25" : ["ftgb196", "csga225", "csga324"], "xc7s50" : ["ftgb196", "csga324", "fgga484"], "xc7s75" : ["fgga484", "fgga676"], "xc7s100" : ["fgga484", "fgga676"], }, } if len(os.sys.argv) != 3: print("missing board flash type params") os.sys.exit() part = os.sys.argv[1] flash_type = os.sys.argv[2] # Check file type keyword assert flash_type in ["spi", "bpi"] build_dir = "tmp_" + part if not os.path.isdir(build_dir): try: os.mkdir(build_dir) except OSError: print("Creation of the directory %s failed" % build_dir) else: print("Successfully created the directory %s " % build_dir) currDir = os.path.abspath(os.path.curdir) + "/" files = [] parameters = {} pkg_name = None pkg = None model = "" subpart = part[0:4].lower() if subpart == "10cl": family = "Cyclone 10 LP" tool = "quartus" elif subpart == "ep4c": family = "Cyclone IV E" tool = "quartus" elif subpart[0:2] == "5c": family = "Cyclone V" tool = "quartus" files.append({"name": currDir + "constr_cycloneV.tcl", "file_type": "tclSource"}) elif subpart[0:2] == "5s": family = "Stratix V" tool = "quartus" files.append({"name": currDir + "constr_cycloneV.tcl", "file_type": "tclSource"}) elif subpart == "xc7a": family = "Artix" tool = "vivado" model = subpart elif subpart == "xc7v": family = "Virtex 7" tool = "vivado" elif subpart == "xc7k": device_size = int(part.split("k")[1].split("t")[0]) if flash_type == "bpi" or device_size <= 160: family = "Kintex 7" tool = "vivado" else: family = "Kintex7" tool = "ise" speed = -2 model = subpart elif subpart == "xc7s": family = "Spartan 7" tool = "vivado" model = subpart elif subpart == "xc6s": family = "Spartan6" tool = "ise" speed = -3 elif subpart == "xc3s": family = "Spartan3E" tool = "ise" speed = -4 elif subpart == "xc6v": family = "Virtex6" tool = "ise" speed = -1 elif subpart in ["xcvu", "xcku", "xcau"]: family = "Xilinx UltraScale" tool = "vivado" else: print("Error: unknown device") os.sys.exit() if model in ["xc7a", "xc7s"]: # Accept either a bare device (e.g. "xc7a100t" -> first package) or a # device suffixed with a package (e.g. "xc7a100tfgg676" -> "fgg676"). if part in packages[family]: pkg = packages[family][part][0] device = part else: m = re.match(r"(xc7[as]\d+t?)([a-z]+\d+)", part) if not m or m.group(1) not in packages[family]: print(f"Error: cannot parse part/package from '{part}'") os.sys.exit() device = m.group(1) pkg = m.group(2) if pkg not in packages[family][device]: print(f"Error: package '{pkg}' not listed for device '{device}'") os.sys.exit() pkg_name = f"{model}_{pkg}" if model in ["xc7k"]: m = re.match(r"(xc7k\d+t)(\w+)", part) pkg = m.group(2) pkg_name = f"{model}_{pkg}" if tool == "ise": model = m.group(1) if tool in ["ise", "vivado"]: pkg_name = { "xc3s500evq100" : "xc3s_vq100", "xc6slx9tqg144" : "xc6s_tqg144", "xc6slx9csg324" : "xc6s_csg324", "xc6slx16ftg256" : "xc6s_ftg256", "xc6slx16csg324" : "xc6s_csg324", "xc6slx25csg324" : "xc6s_csg324", "xc6slx25tcsg324" : "xc6s_t_csg324", "xc6slx45csg324" : "xc6s_csg324", "xc6slx45tfgg484" : "xc6s_t_fgg484", "xc6slx100fgg484" : "xc6s_fgg484", "xc6slx150tcsg484" : "xc6s_csg484", "xc6slx150tfgg484" : "xc6s_t_fgg484", "xc6vlx130tff784" : "xc6v_ff784", "xc7vx330tffg1157" : "xc7v_ffg1157", "xcku040-ffva1156" : "xcku040_ffva1156", "xcku060-ffva1156" : "xcku060_ffva1156", "xcvu9p-flga2104" : "xcvu9p_flga2104", "xcvu37p-fsvh2892" : "xcvu37p_fsvh2892", "xcvu7p-flvb2104" : "xcvu7p_flvb2104", "xcku3p-ffva676" : "xcku3p_ffva676", "xcku3p-ffvb676" : "xcku3p_ffvb676", "xcku5p-ffvb676" : "xcku5p_ffvb676", "xcau7p-sbvc484" : "xcau7p_sbvc484", "xcau10p-ffvb676" : "xcau10p_ffvb676", "xcau15p-ffvb676" : "xcau15p_ffvb676", }.get(part, pkg_name) if tool == "ise": cst_type = "UCF" tool_options = { "family": family, "device": { "xc3s500evq100" : "xc3s500e", "xc6slx9tqg144" : "xc6slx9", "xc6slx9csg324" : "xc6slx9", "xc6slx16ftg256" : "xc6slx16", "xc6slx16csg324" : "xc6slx16", "xc6slx25csg324" : "xc6slx25", "xc6slx25tcsg324" : "xc6slx25t", "xc6slx45csg324" : "xc6slx45", "xc6slx45tfgg484" : "xc6slx45t", "xc6slx100fgg484" : "xc6slx100", "xc6slx150tcsg484" : "xc6slx150t", "xc6slx150tfgg484" : "xc6slx150t", "xc6vlx130tff784" : "xc6vlx130t", }.get(part, model), "package": { "xc3s500evq100" : "vq100", "xc6slx9tqg144" : "tqg144", "xc6slx9csg324" : "csg324", "xc6slx16ftg256" : "ftg256", "xc6slx16csg324" : "csg324", "xc6slx25csg324" : "csg324", "xc6slx25tcsg324" : "csg324", "xc6slx45csg324" : "csg324", "xc6slx45tfgg484" : "fgg484", "xc6slx100fgg484" : "fgg484", "xc6slx150tcsg484" : "csg484", "xc6slx150tfgg484" : "fgg484", "xc6vlx130tff784" : "ff784", }.get(part, pkg), "speed" : speed, } else: cst_type = "xdc" # Artix/Spartan 7 Specific use case: if family in ["Artix", "Spartan 7"]: tool_options = {"part": f"{device}{pkg}-1"} elif family == "Xilinx UltraScale": if part in ["xcvu9p-flga2104", "xcku5p-ffvb676"]: tool_options = {"part": part + "-1-e"} parameters["secondaryflash"] = { "datatype": "int", "paramtype": "vlogdefine", "description": "secondary flash", "default": 1, } elif part == "xcku3p-ffva676": tool_options = {"part": part + "-2-e"} elif part == "xcku3p-ffvb676": tool_options = {"part": part + "-2-e"} elif part == "xcvu7p-flvb2104": tool_options = {"part": part + "-1-e"} elif part == "xcvu37p-fsvh2892": tool_options = {"part": part + "-2L-e"} elif part in ["xcku040-ffva1156", "xcku060-ffva1156"]: tool_options = {"part": part + "-2-e"} parameters["secondaryflash"] = { "datatype" : "int", "paramtype" : "vlogdefine", "description" : "secondary flash", "default" : 1, } elif part in ["xcau10p-ffvb676", "xcau7p-sbvc484"]: tool_options = {"part": part + "-1-e"} elif part == "xcau15p-ffvb676": tool_options = {"part": part + "-2-e"} else: tool_options = {"part": part + "-1"} cst_file = currDir + "constr_" + pkg_name + "." + cst_type.lower() files.append({"name": os.path.join(currDir, f"xilinx_{flash_type}OverJtag.v"), "file_type": "verilogSource"}) files.append({"name": cst_file, "file_type": cst_type}) else: # Altera only support SPI mode. assert flash_type in ["spi"] full_part = { "10cl016484" : "10CL016YU484C8G", "10cl025256" : "10CL025YU256C8G", "10cl055484" : "10CL055YU484C8G", "10cl006144" : "10CL006YE144C8G", "ep4cgx15027" : "EP4CGX150DF27I7", "ep4ce11523" : "EP4CE115F23C7", "ep4ce2217" : "EP4CE22F17C6", "ep4ce1523" : "EP4CE15F23C8", "ep4ce1017" : "EP4CE10F17C8", "ep4ce622" : "EP4CE6E22C8", "5ce215" : "5CEBA2U15C8", "5ce223" : "5CEFA2F23I7", "5ce523" : "5CEFA5F23I7", "5ce423" : "5CEBA4F23C8", "5ce927" : "5CEBA9F27C7", "5cse423" : "5CSEMA4U23C6", "5cse623" : "5CSEBA6U23I7", "5sgsd5" : "5SGSMD5K2F40I3", }[part] files.append({"name": currDir + "altera_spiOverJtag.v", "file_type": "verilogSource"}) files.append({"name": currDir + "altclkctrl_inst.v", "file_type": "verilogSource"}) files.append({"name": currDir + "altera_spiOverJtag.sdc", "file_type": "SDC"}) tool_options = {"device": full_part, "family": family} files.append({ "name" : os.path.join(currDir, f"{flash_type}OverJtag_core.v"), "file_type" : "verilogSource", }) parameters[family.lower().replace(" ", "")] = { "datatype": "int", "paramtype": "vlogdefine", "description": "fpga family", "default": 1 } edam = { "name" : f"{flash_type}OverJtag", "files" : files, "tool_options" : {tool: tool_options}, "parameters" : parameters, "toplevel" : f"{flash_type}OverJtag", } backend = get_edatool(tool)(edam=edam, work_root=build_dir) backend.configure() backend.build() if tool in ["vivado", "ise"]: import gzip import shutil import subprocess # Compress bitstream. with open(f"tmp_{part}/{flash_type}OverJtag.bit", "rb") as bit: with gzip.open(f"{flash_type}OverJtag_{part}.bit.gz", "wb", compresslevel=9) as bit_gz: shutil.copyfileobj(bit, bit_gz) # Create Symbolic links for all supported packages — only when building # the bare device target (e.g. "xc7a100t"). When the explicit # device+package form is used (e.g. "xc7a100tfgg676"), the bitstream is # package-specific and must not be aliased to other packages. if family in ["Artix", "Spartan 7"] and part in packages[family]: in_file = f"{flash_type}OverJtag_{part}.bit.gz" for pkg in packages[family][part]: out_file = f"{flash_type}OverJtag_{part}{pkg}.bit.gz" # Don't overwrite a package-specific bitstream with a symlink to # the first-package build (this was the original bug). if os.path.islink(out_file) or not os.path.exists(out_file): if os.path.islink(out_file): os.unlink(out_file) subprocess.run(["ln", "-s", in_file, out_file])