| # Copyright 2020 Project U-Ray Authors |
| # |
| # 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. |
| |
| import numpy as np |
| import sys |
| |
| X = 110 |
| |
| root = sys.argv[1] |
| |
| pins = [] |
| bank_to_pins = {} |
| bank_to_iotype = {} |
| site_to_pin = {} |
| pin_to_bank = {} |
| with open (root + "/iopins.txt", "r") as iof: |
| for line in iof: |
| sl = line.strip().split(",") |
| if len(sl) < 5: |
| continue |
| pin = sl[0] |
| bank = int(sl[1]) |
| func = sl[2] |
| site_name = sl[3] |
| site_type = sl[4] |
| pins.append((pin, bank, func, site_name, site_type)) |
| if bank not in bank_to_pins: |
| bank_to_pins[bank] = [] |
| bank_to_pins[bank].append(pin) |
| pin_to_bank[pin] = bank |
| if bank not in bank_to_iotype: |
| bank_to_iotype[bank] = site_type.split("_")[0] |
| site_to_pin[site_name] = pin |
| |
| for x in range(X): |
| used_pins = [] |
| io_config = [] |
| |
| bank_to_vcc = {} |
| bank_pod_used = set() |
| bank_pod_not_used = set() |
| lut_inputs = [] |
| lut_outputs = [] |
| bank_iref = {} |
| bound_pins = set() |
| def inp(): |
| sig = "li[%d]" % len(lut_inputs) |
| lut_inputs.append(sig) |
| return sig |
| def outp(): |
| sig = "lo[%d]" % len(lut_outputs) |
| lut_outputs.append(sig) |
| return sig |
| def maybe_inp(): |
| return inp() if np.random.choice([True, False]) else "" |
| def maybe_outp(): |
| return outp() if np.random.choice([True, False]) else "" |
| |
| for b, t in sorted(bank_to_iotype.items()): |
| if t == "HPIOB": |
| bank_to_vcc[b] = np.random.choice( |
| ["1.0", "1.2", "1.35", "1.5", "1.8"] |
| ) |
| elif t == "HDIOB": |
| bank_to_vcc[b] = np.random.choice( |
| ["1.2", "1.5", "1.8", "2.5", "3.3"] |
| ) |
| else: |
| assert False, t |
| standards = { |
| ("HPIOB", "1.8"): ["LVCMOS18", "LVDCI_18", "HSLVDCI_18", |
| "HSTL_I_18", "HSTL_I_DCI_18", |
| "SSTL18_I", "SSTL18_I_DCI"], |
| ("HPIOB", "1.5"): ["LVCMOS15", "LVDCI_15", "HSLVDCI_15", |
| "HSTL_I", "HSTL_I_DCI", |
| "SSTL15", "SSTL15_DCI"], |
| ("HPIOB", "1.35"): ["SSTL135", "SSTL135_DCI"], |
| ("HPIOB", "1.2"): ["LVCMOS12", "HSTL_I_12", "HSTL_I_DCI_12", |
| "SSTL12", "SSTL12_DCI", |
| "HSUL_12", "HSUL_12_DCI", |
| "POD12", "POD12_DCI"], |
| ("HPIOB", "1.0"): ["POD10", "POD10_DCI"], |
| |
| ("HDIOB", "3.3"): ["LVCMOS33", "LVTTL"], |
| ("HDIOB", "2.5"): ["LVCMOS25"], |
| ("HDIOB", "1.8"): ["LVCMOS18"], |
| ("HDIOB", "1.5"): ["LVCMOS15"], |
| ("HDIOB", "1.2"): ["LVCMOS12"] |
| } |
| |
| prims = { |
| "HPIOB": ["IBUF", "OBUF", "OBUFT", "IOBUF", "IOBUFE3", "IBUF_IBUFDISABLE"], |
| "HDIOB": ["IBUF","OBUF", "OBUFT", "IOBUF"] |
| } |
| |
| drives = { |
| ("HPIOB", "LVCMOS18"): ["2", "4", "6", "8", "12"], |
| ("HPIOB", "LVCMOS15"): ["2", "4", "6", "8", "12"], |
| ("HPIOB", "LVCMOS12"): ["2", "4", "6", "8"], |
| ("HDIOB", "LVCMOS33"): ["4", "8", "12", "16"], |
| ("HDIOB", "LVCMOS25"): ["4", "8", "12", "16"], |
| ("HDIOB", "LVCMOS18"): ["4", "8", "12", "16"], |
| ("HDIOB", "LVCMOS15"): ["4", "8", "12", "16"], |
| ("HDIOB", "LVCMOS12"): ["4", "8", "12"], |
| } |
| |
| for (pin, bank, func, sn, st) in pins: |
| if "VREF" in func: |
| continue # conflict |
| if "VRP" in func or "VRN" in func: |
| continue # conflict |
| if np.random.randint(1, 3) == 1: |
| continue # improved fuzzing |
| params = {} |
| iot = st.split("_")[0] |
| assert (iot, bank_to_vcc[bank]) in standards, (pin, bank, iot, bank_to_vcc[bank]) |
| ios = np.random.choice(standards[iot, bank_to_vcc[bank]]) |
| if bank in bank_pod_used and ios in ("HSTL_I_12", "HSTL_I_DCI_12", "SSTL12", "SSTL12_DCI", "HSUL_12", "HSUL_12_DCI"): |
| ios = "LVCMOS12" |
| if bank in bank_pod_not_used and ios in ("POD12", "POD12_DCI"): |
| ios = "LVCMOS12" |
| params["IOSTANDARD"] = ios |
| prim = np.random.choice(prims[iot]) |
| params["prim"] = prim |
| if prim in ("IBUF", "IOBUF", "IOBUFE3", "IBUF_IBUFDISABLE", "IBUF_INTERMDISABLE"): |
| params["PULLTYPE"] = np.random.choice(["NONE", "PULLUP", "PULLDOWN", "KEEPER"]) |
| if prim in ("OBUF", "OBUFT", "IOBUF", "IOBUFE3"): |
| if (iot, ios) in drives: |
| params["DRIVE"] = np.random.choice(drives[iot, ios]) |
| if iot == "HPIOB": |
| params["SLEW"] = np.random.choice(["SLOW", "MEDIUM", "FAST"]) |
| else: |
| params["SLEW"] = np.random.choice(["SLOW", "FAST"]) |
| if iot == "HPIOB" and ("POD" in ios or "SSTL" in ios): |
| params["OUTPUT_IMPEDANCE"] = np.random.choice(["RDRV_40_40", "RDRV_48_48", "RDRV_60_60"]) |
| if prim in ("IBUF", "IOBUF", "IOBUFE3", "IBUF_IBUFDISABLE", "IBUF_INTERMDISABLE"): |
| if "POD" in ios: |
| odt_choices = [] |
| if "DCI" not in ios: |
| odt_choices.append("RTT_NONE") |
| if "OUTPUT_IMPEDANCE" not in params or params["OUTPUT_IMPEDANCE"] != "RDRV_48_48": |
| odt_choices += ["RTT_40", "RTT_60"] |
| else: |
| odt_choices += ["RTT_48"] |
| params["ODT"] = np.random.choice(odt_choices) |
| if "POD12" in ios: |
| params["EQUALIZATION"] = np.random.choice(["EQ_LEVEL0", "EQ_LEVEL1", "EQ_LEVEL2", "EQ_LEVEL3", "EQ_LEVEL4", "EQ_NONE"]) |
| used_pins.append(pin) |
| io_config.append(params) |
| if iot == "HDIOB": |
| if ios in ( "HSTL_I_18", "SSTL18_I", "SSTL18_II"): |
| bank_iref[bank] = "0.90" |
| elif ios in ( "HSTL_I", "SSTL15", "SSTL15_II"): |
| bank_iref[bank] = "0.75" |
| elif ios in ("SSTL135", "SSTL135_II"): |
| bank_iref[bank] = "0.675" |
| elif ios == "SSTL12": |
| bank_iref[bank] = "0.60" |
| if ios in ("POD12", "POD12_DCI"): |
| bank_pod_used.add(bank) |
| bank_iref[bank] = np.random.choice([None, "0.84"]) |
| if ios in ("HSTL_I_12", "HSTL_I_DCI_12", "SSTL12", "SSTL12_DCI", "HSUL_12", "HSUL_12_DCI"): |
| bank_pod_not_used.add(bank) |
| bank_iref[bank] = np.random.choice([None, "0.60"]) |
| with open(root + "/io/io%d.v" % x, "w") as f: |
| print("module top(", file=f); |
| for i, params in enumerate(io_config): |
| prim = params["prim"] |
| bank = pin_to_bank[used_pins[i]] |
| if bank in bank_iref and bank_iref[bank] is not None: |
| params["internal_vref"] = bank_iref[bank] |
| print ("(* %s *)" % ", ".join('X_%s="%s"' % (k, v) for k, v in sorted(params.items())), file=f) |
| if prim in ("IBUF", "IBUF_IBUFDISABLE"): |
| print("input p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f) |
| elif prim in ("OBUF", "OBUFT"): |
| print("output p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f) |
| elif prim in ("IOBUF", "IOBUFE3"): |
| print("inout p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f) |
| print(");", file=f) |
| for i, params in enumerate(io_config): |
| print("(* KEEP, DONT_TOUCH *)", file=f) |
| prim = params["prim"] |
| if prim == "IBUF": |
| print(""" |
| IBUF buf_{i} ( |
| .I(p{i}), |
| .O({sig_o}) |
| ); |
| """.format(i=i, sig_o=maybe_inp()), file=f) |
| elif prim == "OBUF": |
| print(""" |
| OBUF buf_{i} ( |
| .O(p{i}), |
| .I({sig_i}) |
| ); |
| """.format(i=i, sig_i=maybe_outp()), file=f) |
| elif prim == "OBUFT": |
| print(""" |
| OBUFT buf_{i} ( |
| .O(p{i}), |
| .T({sig_t}), |
| .I({sig_i}) |
| ); |
| """.format(i=i, sig_t=outp(), sig_i=maybe_outp()), file=f) |
| elif prim == "IOBUF": |
| print(""" |
| IOBUF buf_{i} ( |
| .IO(p{i}), |
| .T({sig_t}), |
| .I({sig_i}), |
| .O({sig_o}) |
| ); |
| """.format(i=i, sig_t=maybe_outp(), sig_i=maybe_outp(), sig_o=maybe_inp()), file=f) |
| elif prim == "IBUF_IBUFDISABLE": |
| print(""" |
| IBUF_IBUFDISABLE buf_{i} ( |
| .I(p{i}), |
| .O({sig_o}), |
| .IBUFDISABLE({ibuf_dis}) |
| ); |
| """.format(i=i, sig_o=maybe_inp(), ibuf_dis=maybe_outp()), file=f) |
| elif prim == "IOBUFE3": |
| if np.random.choice([True, False]): |
| print("(* KEEP, DONT_TOUCH *)", file=f) |
| print(""" |
| IOBUFE3 buf_{i} ( |
| .IO(p{i}), |
| .T({sig_t}), |
| .I({sig_i}), |
| .O({sig_o}), |
| .DCITERMDISABLE({dci_dis}), |
| .IBUFDISABLE({ibuf_dis}) |
| ); |
| """.format(i=i, sig_t=maybe_outp(), sig_i=maybe_outp(), sig_o=maybe_inp(), |
| dci_dis=maybe_outp(), ibuf_dis=maybe_outp()), file=f) |
| print("", file=f) |
| print("wire [%d:0] li;" % (len(lut_inputs)-1), file=f) |
| print("wire [%d:0] lo;" % (len(lut_outputs)-1), file=f) |
| |
| for i in range(max(len(lut_inputs)//6 + 1, len(lut_outputs))): |
| ip = ["1'b0" if (i * 6 + j) >= len(lut_inputs) else "li[%d]" % (i * 6 + j) for j in range(6)] |
| op = "lo[%d]" % i if i < len(lut_outputs) else "" |
| print(""" |
| (* KEEP, DONT_TOUCH *) |
| LUT6 lut{i} (.I0({i0}), .I1({i1}), .I2({i2}), .I3({i3}), .I4({i4}), .I5({i5}), .O({o})); |
| """.format( |
| i=i, i0=ip[0], i1=ip[1], i2=ip[2], i3=ip[3], i4=ip[4], i5=ip[5], o=op, |
| ), file=f) |
| print("endmodule", file=f) |
| with open(root + "/io/io%d.xdc" % x, "w") as f: |
| for i, params in enumerate(io_config): |
| pin = used_pins[i] |
| print("set_property PACKAGE_PIN %s [get_ports {p%d}]" % (pin, i), file=f) |
| for k, v in sorted(params.items()): |
| if k.isupper(): |
| print("set_property %s %s [get_ports {p%d}]" % (k, v, i), file=f) |
| for bank, iref in sorted(bank_iref.items()): |
| if iref is None: |
| continue |
| print("set_property INTERNAL_VREF {%s} [get_iobanks %d]" % (iref, bank), file=f) |
| with open(root + "/io/io%d.tcl" % x, "w") as f: |
| print("add_files %s" % (root + ("/io/io%d.v" % x)), file=f) |
| print("add_files %s" % (root + ("/io/io%d.xdc" % x)), file=f) |
| print("synth_design -top top -part xczu7ev-ffvf1517-2-e", file=f) |
| print("set_property SEVERITY {Warning} [get_drc_checks NSTD-1]", file=f) |
| print("set_property SEVERITY {Warning} [get_drc_checks UCIO-1]", file=f) |
| print("set_property SEVERITY {Warning} [get_drc_checks AVAL-*]", file=f) |
| print("set_property SEVERITY {Warning} [get_drc_checks REQP-*]", file=f) |
| print("set_property SEVERITY {Warning} [get_drc_checks BIVR-*]", file=f) |
| print("set_property SEVERITY {Warning} [get_drc_checks PLHDIO-1]", file=f) |
| print("opt_design", file=f) |
| print("place_design", file=f) |
| print("route_design", file=f) |
| print("set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", file=f) |
| print("write_checkpoint -force %s/specimen_io/io%d.dcp" % (root, x), file=f) |
| print("write_edif -force %s/specimen_io/io%d.edf" % (root, x), file=f) |
| print("write_bitstream -force %s/specimen_io/io%d.bit" % (root, x), file=f) |
| with open(root + "/io/run.sh", "w") as f: |
| print("#/usr/bin/env bash", file=f) |
| print("set -ex", file=f) |
| print("vivado -mode batch -nolog -nojournal -source io$1.tcl", file=f) |
| print("if [ $? -eq 0 ]; then", file=f) |
| print(" ../../ultra/tools/dump_bitstream %s/specimen_io/io$1.bit %s/frames.txt > %s/specimen_io/io$1.dump" % (root, root, root), file=f) |
| print(" python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_io/io$1.dump > %s/specimen_io/io$1.tbits" % (root, root, root), file=f) |
| #print(" rm %s/specimen_io/io$1.bit" % (root, ), file=f) |
| #print(" rm %s/specimen_io/io$1.dump" % (root, ), file=f) |
| print("else", file=f) |
| print(" rm %s/specimen_io/io$1.dump" % (root, ), file=f) |
| print(" rm %s/specimen_io/io$1.tbits" % (root, ), file=f) |
| print(" rm %s/specimen_io/io$1.dcp" % (root, ), file=f) |
| print(" rm %s/specimen_io/io$1.bit" % (root, ), file=f) |
| print(" rm %s/specimen_io/io$1.features" % (root, ), file=f) |
| print("fi", file=f) |
| with open(root + "/io/Makefile", "w") as f: |
| print("all: %s" % " ".join(["%d.done" % i for i in range(X)]), file=f) |
| print("", file=f) |
| print("%.done: ", file=f) |
| print("\tbash run.sh $*", file=f) |
| print("\ttouch $@", file=f) |
| print("", file=f) |
| print("clean: ", file=f) |
| print("\trm -f *.done", file=f) |