| # 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 |
| |
| bufgces_by_tile = {} |
| tiles_by_xy = {} |
| rclk_int_l = [] |
| slices_by_tile = {} |
| with open(sys.argv[1], "r") as tf: |
| for line in tf: |
| sl = line.strip().split(",") |
| if len(sl) < 4: |
| continue |
| tiles_by_xy[int(sl[0]), int(sl[1])] = sl[2] |
| if sl[2].startswith("RCLK_INT_L"): |
| rclk_int_l.append((int(sl[0]), int(sl[1]), sl[2])) |
| for site in sl[4:]: |
| if ("BUFGCE" in site or "BUFGCTRL" in site) and "HDIO" not in site: |
| if sl[2] not in bufgces_by_tile: |
| bufgces_by_tile[sl[2]] = [] |
| bufgces_by_tile[sl[2]].append(site.split(":")) |
| elif "SLICE_" in site: |
| slices_by_tile[int(sl[0]), int(sl[1])] = site.split(":")[0] |
| |
| halfcolumn_slices_by_row = {} |
| for x, y, rclk in rclk_int_l: |
| hc_up = [] |
| hc_down = [] |
| if y not in halfcolumn_slices_by_row: |
| halfcolumn_slices_by_row[y] = [] |
| for yplus in range(y + 1, y + 31): |
| if (x, yplus) not in tiles_by_xy: |
| continue |
| if not tiles_by_xy[x, yplus].startswith("INT_"): |
| break |
| slice_x = x + np.random.choice([+1, -1]) |
| if (slice_x, yplus) not in slices_by_tile: |
| continue |
| hc_up.append(slices_by_tile[slice_x, yplus]) |
| for yminus in range(y - 1, y - 31, -1): |
| if (x, yminus) not in tiles_by_xy: |
| continue |
| if not tiles_by_xy[x, yminus].startswith("INT_"): |
| break |
| slice_x = x + np.random.choice([+1, -1]) |
| if (slice_x, yminus) not in slices_by_tile: |
| continue |
| hc_down.append(slices_by_tile[slice_x, yminus]) |
| halfcolumn_slices_by_row[y].append(hc_up) |
| halfcolumn_slices_by_row[y].append(hc_down) |
| |
| X = 32 |
| |
| root = sys.argv[2] |
| |
| for x in range(X): |
| buffers = [] |
| |
| tiles = list(sorted(bufgces_by_tile.keys())) |
| np.random.shuffle(tiles) |
| |
| for tile in tiles: |
| shuffled_bufs = list(bufgces_by_tile[tile]) |
| np.random.shuffle(shuffled_bufs) |
| target_type = np.random.choice( |
| ["BUFGCE", "BUFGCE_DIV", "BUFGCTRL"] |
| if len(buffers) > 0 else ["BUFGCE", "BUFGCE_DIV"]) |
| tile_buffers = np.random.randint(6) |
| found_buffers = 0 |
| for buf, buftype in shuffled_bufs: |
| if found_buffers >= tile_buffers: |
| break |
| if buftype != target_type: |
| continue |
| buffers.append((buf, buftype)) |
| print("%s %s" % (tile, buf)) |
| found_buffers += 1 |
| |
| def random_inversion(pins): |
| return ", ".join( |
| [".IS_%s_INVERTED(%d)" % (p, np.random.randint(2)) for p in pins]) |
| |
| def random_control(pins): |
| return ", ".join( |
| [".%s(aux[%d])" % (p, np.random.randint(10)) for p in pins]) |
| |
| with open(root + "/clkroute5/gclkc_%d.v" % x, "w") as f: |
| print( |
| "module top(input [23:0] i, input [9:0] aux, input d, output o, q);", |
| file=f) |
| N = 24 |
| print(" wire [71:0] r;", file=f) |
| # print(" assign r[0] = i;", file=f) |
| # print(" assign o = r[%d];" % N, file=f) |
| # for i in range(N): |
| # bg, buftype = buffers[i] |
| # #print("(* LOC=\"%s\" *)" % bg, file=f) |
| # if "BUFGCTRL" in buftype: |
| # print(" BUFGCTRL #(", file=f) |
| # print(" %s," % random_inversion(["I0", "I1", "S0", "S1", "CE0", "CE1", "IGNORE0", "IGNORE1"]), file=f) |
| # print(" .INIT_OUT(%d), .PRESELECT_I0(\"%s\"), .PRESELECT_I1(\"%s\")" % |
| # (np.random.randint(2), np.random.choice(["TRUE", "FALSE"]), np.random.choice(["TRUE", "FALSE"])), file=f) |
| # print(" ) bufgctrl_%d (" % i, file=f) |
| # print(" .I0(r[%d]), .I1(r[%d]), " % (i, np.random.randint(i+1)), file=f) |
| # print(" %s," % random_control(["S0", "S1", "CE0", "CE1", "IGNORE0", "IGNORE1"]), file=f) |
| # print(" .O(r[%d])" % (i+1), file=f) |
| # print(" );", file=f) |
| print(" assign r[23:0] = i;", file=f) |
| for i in range(12): |
| print(" BUFGCE_DIV #(", file=f) |
| print( |
| " .BUFGCE_DIVIDE(%d)," % np.random.randint(1, 9), |
| file=f) |
| print(" %s" % random_inversion(["I", "CE", "CLR"]), file=f) |
| print(" ) bufgce_div_%d (" % i, file=f) |
| print(" .I(i[%d])," % i, file=f) |
| print(" %s," % random_control(["CE", "CLR"]), file=f) |
| print(" .O(r[%d])" % (24 + i), file=f) |
| print(" );", file=f) |
| for i in range(12): |
| print(" BUFGCE #(", file=f) |
| print( |
| " .CE_TYPE(\"%s\")," % np.random.choice( |
| ["SYNC", "ASYNC"]), |
| file=f) |
| print(" %s" % random_inversion(["I", "CE"]), file=f) |
| print(" ) bufgce_%d (" % i, file=f) |
| print(" .I(i[%d])," % np.random.randint(24), file=f) |
| print(" %s," % random_control(["CE"]), file=f) |
| print(" .O(r[%d])" % (i + 36), file=f) |
| print(" );", file=f) |
| |
| R2 = 0 |
| NS = 64 |
| ffs = "" |
| for row, hcs in sorted(halfcolumn_slices_by_row.items()): |
| row_clks = np.random.randint(20, 25) |
| clks = [np.random.randint(48) for k in range(row_clks)] |
| hi = [] |
| while len(hi) < NS: |
| next_i = np.random.randint(len(hcs)) |
| while next_i in hi: |
| next_i = np.random.randint(len(hcs)) |
| hi.append(next_i) |
| |
| halfs = [hcs[hi[k]] for k in range(NS)] |
| for h in halfs: |
| half_clks = np.random.randint(13, 17) |
| rclks = [np.random.choice(clks) for k in range(half_clks)] |
| for sl in h: |
| ffs += "(* LOC=\"%s\" *) FDCE ff_%d (.C(r[%d]), .CE(aux[%d]), .CLR(~aux[%d]), .D(r2[%d]), .Q(r2[%d]));\n" % ( |
| sl, R2, rclks[R2 % len(rclks)], np.random.randint(10), |
| np.random.randint(10), R2, R2 + 1) |
| R2 += 1 |
| print(" wire [%d:0] r2;" % R2, file=f) |
| print(" assign r2[0] = d;", file=f) |
| print(" assign q = r2[%d];" % R2, file=f) |
| print(ffs, file=f) |
| print("endmodule", file=f) |
| with open(root + "/clkroute5/gclkc_%d.tcl" % x, "w") as f: |
| print("add_files %s" % (root + ("/clkroute5/gclkc_%d.v" % x)), file=f) |
| #print("read_xdc %s" % (root + ("/clkroute5/gclkc_%d.xdc" % x)), file=f) |
| print("synth_design -top top -part xczu7ev-ffvc1156-2-e", file=f) |
| print("# set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets]", file=f) |
| print("opt_design", file=f) |
| print("place_design", file=f) |
| print("route_design", 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 BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", |
| file=f) |
| print( |
| "write_checkpoint -force %s/specimen_clk/gclkc_%d.dcp" % (root, x), |
| file=f) |
| print( |
| "write_edif -force %s/specimen_clk/gclkc_%d.edf" % (root, x), |
| file=f) |
| print( |
| "write_bitstream -force %s/specimen_clk/gclkc_%d.bit" % (root, x), |
| file=f) |
| with open(root + "/clkroute5/run.sh", "w") as f: |
| print("#/usr/bin/env bash", file=f) |
| #print("set -ex", file=f) |
| for x in range(X): |
| print( |
| "vivado -mode batch -nolog -nojournal -source gclkc_%d.tcl" % x, |
| file=f) |
| print("if [ $? -eq 0 ]; then", file=f) |
| print( |
| " ../../ultra/tools/dump_bitstream %s/specimen_clk/gclkc_%d.bit %s/frames.txt > %s/specimen_clk/gclkc_%d.dump" |
| % (root, x, root, root, x), |
| file=f) |
| print( |
| " python3 ../../ultra/tools/bits_to_tiles.py %s/tile.json %s/specimen_clk/gclkc_%d.dump > %s/specimen_clk/gclkc_%d.tbits" |
| % (root, root, x, root, x), |
| file=f) |
| print("else", file=f) |
| print(" rm %s/specimen_clk/gclkc_%d.dump" % (root, x), file=f) |
| print(" rm %s/specimen_clk/gclkc_%d.tbits" % (root, x), file=f) |
| print(" rm %s/specimen_clk/gclkc_%d.dcp" % (root, x), file=f) |
| print(" rm %s/specimen_clk/gclkc_%d.bit" % (root, x), file=f) |
| print(" rm %s/specimen_clk/gclkc_%d.features" % (root, x), file=f) |
| print("fi", file=f) |