| # 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 = 40 |
| |
| 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"): ["DIFF_SSTL18_I", "DIFF_SSTL18_I_DCI", "SLVS_400_18", "LVDS"], |
| ("HPIOB", "1.5"): ["DIFF_SSTL15", "DIFF_SSTL15_DCI"], |
| ("HPIOB", "1.35"): ["DIFF_SSTL135", "DIFF_SSTL135_DCI"], |
| ("HPIOB", "1.2"): ["DIFF_SSTL12", "DIFF_SSTL12_DCI", |
| "DIFF_HSUL_12", "DIFF_HSUL_12_DCI", |
| "DIFF_POD12", "DIFF_POD12_DCI"], |
| ("HPIOB", "1.0"): ["DIFF_POD10", "DIFF_POD10_DCI"], |
| } |
| |
| prims = { |
| "HPIOB": ["IBUFDS", "OBUFDS", "OBUFTDS", "IOBUFDS", "IOBUFDSE3"], |
| #"HDIOB": ["IBUF","OBUF", "OBUFT", "IOBUF"] |
| } |
| 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 "HPIOB_M" not in st: |
| continue |
| if np.random.choice([True, True, False]): |
| 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 ("DIFF_HSTL_I_12", "DIFF_HSTL_I_DCI_12", "DIFF_SSTL12", "DIFF_SSTL12_DCI", "DIFF_HSUL_12", "DIFF_HSUL_12_DCI"): |
| continue |
| if bank in bank_pod_not_used and ios in ("DIFF_POD12", "DIFF_POD12_DCI"): |
| continue |
| params["IOSTANDARD"] = ios |
| prim = np.random.choice(prims[iot]) |
| |
| if ios == "SLVS_400_18": |
| prim = "IBUFDS" |
| |
| params["prim"] = prim |
| if prim in ("OBUFDS", "OBUFTDS", "IOBUFDS", "IOBUFDSE3"): |
| 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 ("IBUFDS", "IOBUFDS", "IOBUFDSE3", "IBUFDS_IBUFDISABLE", "IBUFDS_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"]) |
| if "LVDS" in ios or "SLVS" in ios: |
| params["DIFF_TERM_ADV"] = np.random.choice(["TERM_NONE", "TERM_100"]) |
| used_pins.append(pin) |
| io_config.append(params) |
| |
| if ios in ("DIFF_POD12", "DIFF_POD12_DCI"): |
| bank_pod_used.add(bank) |
| if ios in ("DIFF_HSTL_I_12", "DIFF_HSTL_I_DCI_12", "DIFF_SSTL12", "DIFF_SSTL12_DCI", "DIFF_HSUL_12", "DIFF_HSUL_12_DCI"): |
| bank_pod_not_used.add(bank) |
| with open(root + "/diffio/diffio%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["int_vref"] = bank_iref[bank] |
| print ("(* %s *)" % ", ".join('X_%s="%s"' % (k, v) for k, v in sorted(params.items())), file=f) |
| if prim in ("IBUFDS", "IBUFDS_IBUFDISABLE"): |
| print("input p%d, pn%d%s" % (i, i, "," if i < len(io_config)-1 else ""), file=f) |
| elif prim in ("OBUFDS", "OBUFTDS"): |
| print("output p%d, pn%d%s" % (i, i, "," if i < len(io_config)-1 else ""), file=f) |
| elif prim in ("IOBUFDS", "IOBUFDSE3"): |
| print("inout p%d, pn%d%s" % (i, 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 == "IBUFDS": |
| print(""" |
| IBUFDS buf_{i} ( |
| .I(p{i}), .IB(pn{i}), |
| .O({sig_o}) |
| ); |
| """.format(i=i, sig_o=maybe_inp()), file=f) |
| elif prim == "OBUFDS": |
| print(""" |
| OBUFDS buf_{i} ( |
| .O(p{i}), .OB(pn{i}), |
| .I({sig_i}) |
| ); |
| """.format(i=i, sig_i=maybe_outp()), file=f) |
| elif prim == "OBUFTDS": |
| print(""" |
| OBUFTDS buf_{i} ( |
| .O(p{i}), .OB(pn{i}), |
| .T({sig_t}), |
| .I({sig_i}) |
| ); |
| """.format(i=i, sig_t=outp(), sig_i=maybe_outp()), file=f) |
| elif prim == "IOBUFDS": |
| print(""" |
| IOBUFDS buf_{i} ( |
| .IO(p{i}), .IOB(pn{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 == "IOBUFDSE3": |
| if np.random.choice([True, False]): |
| print("(* KEEP, DONT_TOUCH *)", file=f) |
| print(""" |
| IOBUFDSE3 buf_{i} ( |
| .IO(p{i}), .IOB(pn{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 + "/diffio/diffio%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 + "/diffio/diffio%d.tcl" % x, "w") as f: |
| print("add_files %s" % (root + ("/diffio/diffio%d.v" % x)), file=f) |
| print("add_files %s" % (root + ("/diffio/diffio%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/diffio%d.dcp" % (root, x), file=f) |
| print("write_edif -force %s/specimen_io/diffio%d.edf" % (root, x), file=f) |
| print("write_bitstream -force %s/specimen_io/diffio%d.bit" % (root, x), file=f) |
| with open(root + "/diffio/run.sh", "w") as f: |
| print("#/usr/bin/env bash", file=f) |
| print("set -ex", file=f) |
| print("vivado -mode batch -nolog -nojournal -source diffio$1.tcl", file=f) |
| print("if [ $? -eq 0 ]; then", file=f) |
| print(" ../../ultra/tools/dump_bitstream %s/specimen_io/diffio$1.bit %s/frames.txt > %s/specimen_io/diffio$1.dump" % (root, root, root), file=f) |
| print(" python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_io/diffio$1.dump > %s/specimen_io/diffio$1.tbits" % (root, root, root), file=f) |
| #print(" rm %s/specimen_io/diffio$1.bit" % (root, ), file=f) |
| #print(" rm %s/specimen_io/diffio$1.dump" % (root, ), file=f) |
| print("else", file=f) |
| print(" rm %s/specimen_io/diffio$1.dump" % (root, ), file=f) |
| print(" rm %s/specimen_io/diffio$1.tbits" % (root, ), file=f) |
| print(" rm %s/specimen_io/diffio$1.dcp" % (root, ), file=f) |
| print(" rm %s/specimen_io/diffio$1.bit" % (root, ), file=f) |
| print(" rm %s/specimen_io/diffio$1.features" % (root, ), file=f) |
| print("fi", file=f) |
| with open(root + "/diffio/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) |