#!/usr/bin/env python3 # -*- coding: utf-8 -*- # ../nextpnr-ice40 --hx8k --tmfuzz > tmfuzz_hx8k.txt # ../nextpnr-ice40 --lp8k --tmfuzz > tmfuzz_lp8k.txt # ../nextpnr-ice40 --up5k --tmfuzz > tmfuzz_up5k.txt import numpy as np import matplotlib.pyplot as plt from collections import defaultdict device = "hx8k" # device = "lp8k" # device = "up5k" sel_src_type = "LUTFF_OUT" sel_dst_type = "LUTFF_IN_LUT" #%% Read fuzz data src_dst_pairs = defaultdict(lambda: 0) delay_data = list() all_delay_data = list() delay_map_sum = np.zeros((41, 41)) delay_map_sum2 = np.zeros((41, 41)) delay_map_count = np.zeros((41, 41)) same_tile_delays = list() neighbour_tile_delays = list() type_delta_data = dict() with open("tmfuzz_%s.txt" % device, "r") as f: for line in f: line = line.split() if line[0] == "dst": dst_xy = (int(line[1]), int(line[2])) dst_type = line[3] dst_wire = line[4] src_xy = (int(line[1]), int(line[2])) src_type = line[3] src_wire = line[4] delay = int(line[5]) estdelay = int(line[6]) all_delay_data.append((delay, estdelay)) src_dst_pairs[src_type, dst_type] += 1 dx = dst_xy[0] - src_xy[0] dy = dst_xy[1] - src_xy[1] if src_type == sel_src_type and dst_type == sel_dst_type: if dx == 0 and dy == 0: same_tile_delays.append(delay) elif abs(dx) <= 1 and abs(dy) <= 1: neighbour_tile_delays.append(delay) else: delay_data.append((delay, estdelay, dx, dy, 0, 0, 0)) relx = 20 + dst_xy[0] - src_xy[0] rely = 20 + dst_xy[1] - src_xy[1] if (0 <= relx <= 40) and (0 <= rely <= 40): delay_map_sum[relx, rely] += delay delay_map_sum2[relx, rely] += delay*delay delay_map_count[relx, rely] += 1 if dst_type == sel_dst_type: if src_type not in type_delta_data: type_delta_data[src_type] = list() type_delta_data[src_type].append((dx, dy, delay)) delay_data = np.array(delay_data) all_delay_data = np.array(all_delay_data) max_delay = np.max(delay_data[:, 0:2]) mean_same_tile_delays = np.mean(neighbour_tile_delays) mean_neighbour_tile_delays = np.mean(neighbour_tile_delays) print("Avg same tile delay: %.2f (%.2f std, N=%d)" % \ (mean_same_tile_delays, np.std(same_tile_delays), len(same_tile_delays))) print("Avg neighbour tile delay: %.2f (%.2f std, N=%d)" % \ (mean_neighbour_tile_delays, np.std(neighbour_tile_delays), len(neighbour_tile_delays))) #%% Apply simple low-weight bluring to fill gaps for i in range(0): neigh_sum = np.zeros((41, 41)) neigh_sum2 = np.zeros((41, 41)) neigh_count = np.zeros((41, 41)) for x in range(41): for y in range(41): for p in range(-1, 2): for q in range(-1, 2): if p == 0 and q == 0: continue if 0 <= (x+p) <= 40: if 0 <= (y+q) <= 40: neigh_sum[x, y] += delay_map_sum[x+p, y+q] neigh_sum2[x, y] += delay_map_sum2[x+p, y+q] neigh_count[x, y] += delay_map_count[x+p, y+q] delay_map_sum += 0.1 * neigh_sum delay_map_sum2 += 0.1 * neigh_sum2 delay_map_count += 0.1 * neigh_count delay_map = delay_map_sum / delay_map_count delay_map_std = np.sqrt(delay_map_count*delay_map_sum2 - delay_map_sum**2) / delay_map_count #%% Print src-dst-pair summary print("Src-Dst-Type pair summary:") for cnt, src, dst in sorted([(v, k[0], k[1]) for k, v in src_dst_pairs.items()]): print("%20s %20s %5d%s" % (src, dst, cnt, " *" if src == sel_src_type and dst == sel_dst_type else "")) print() #%% Plot estimate vs actual delay plt.figure(figsize=(8, 3)) plt.title("Estimate vs Actual Delay") plt.plot(all_delay_data[:, 0], all_delay_data[:, 1], ".") plt.plot(delay_data[:, 0], delay_data[:, 1], ".") plt.plot([0, max_delay], [0, max_delay], "k") plt.ylabel("Estimated Delay") plt.xlabel("Actual Delay") plt.grid() plt.show() #%% Plot delay heatmap and std dev heatmap plt.figure(figsize=(9, 3)) plt.subplot(121) plt.title("Actual Delay Map") plt.imshow(delay_map) plt.colorbar() plt.subplot(122) plt.title("Standard Deviation") plt.imshow(delay_map_std) plt.colorbar() plt.show() #%% Generate Model #0 def nonlinearPreprocessor0(dx, dy): dx, dy = abs(dx), abs(dy) values = [1.0] values.append(dx + dy) return np.array(values) A = np.zeros((41*41, len(nonlinearPreprocessor0(0, 0)))) b = np.zeros(41*41) index = 0 for x in range(41): for y in range(41): if delay_map_count[x, y] > 0: A[index, :] = nonlinearPreprocessor0(x-20, y-20) b[index] = delay_map[x, y] index += 1 model0_params, _, _, _ = np.linalg.lstsq(A, b) print("Model #0 parameters:", model0_params) model0_map = np.zeros((41, 41)) for x in range(41): for y in range(41): v = np.dot(model0_params, nonlinearPreprocessor0(x-20, y-20)) model0_map[x, y] = v plt.figure(figsize=(9, 3)) plt.subplot(121) plt.title("Model #0 Delay Map") plt.imshow(model0_map) plt.colorbar() plt.subplot(122) plt.title("Model #0 Error Map") plt.imshow(model0_map - delay_map) plt.colorbar() plt.show() for i in range(delay_data.shape[0]): dx = delay_data[i, 2] dy = delay_data[i, 3] delay_data[i, 4] = np.dot(model0_params, nonlinearPreprocessor0(dx, dy)) plt.figure(figsize=(8, 3)) plt.title("Model #0 vs Actual Delay") plt.plot(delay_data[:, 0], delay_data[:, 4], ".") plt.plot(delay_map.flat, model0_map.flat, ".") plt.plot([0, max_delay], [0, max_delay], "k") plt.ylabel("Model #0 Delay") plt.xlabel("Actual Delay") plt.grid() plt.show() print("In-sample RMS error: %f" % np.sqrt(np.nanmean((delay_map - model0_map)**2))) print("Out-of-sample RMS error: %f" % np.sqrt(np.nanmean((delay_data[:, 0] - delay_data[:, 4])**2))) print() #%% Generate Model #1 def nonlinearPreprocessor1(dx, dy): dx, dy = abs(dx), abs(dy) values = [1.0] values.append(dx + dy) # 1-norm values.append((dx**2 + dy**2)**(1/2)) # 2-norm values.append((dx**3 + dy**3)**(1/3)) # 3-norm return np.array(values) A = np.zeros((41*41, len(nonlinearPreprocessor1(0, 0)))) b = np.zeros(41*41) index = 0 for x in range(41): for y in range(41): if delay_map_count[x, y] > 0: A[index, :] = nonlinearPreprocessor1(x-20, y-20) b[index] = delay_map[x, y] index += 1 model1_params, _, _, _ = np.linalg.lstsq(A, b) print("Model #1 parameters:", model1_params) model1_map = np.zeros((41, 41)) for x in range(41): for y in range(41): v = np.dot(model1_params, nonlinearPreprocessor1(x-20, y-20)) model1_map[x, y] = v plt.figure(figsize=(9, 3)) plt.subplot(121) plt.title("Model #1 Delay Map") plt.imshow(model1_map) plt.colorbar() plt.subplot(122) plt.title("Model #1 Error Map") plt.imshow(model1_map - delay_map) plt.colorbar() plt.show() for i in range(delay_data.shape[0]): dx = delay_data[i, 2] dy = delay_data[i, 3] delay_data[i, 5] = np.dot(model1_params, nonlinearPreprocessor1(dx, dy)) plt.figure(figsize=(8, 3)) plt.title("Model #1 vs Actual Delay") plt.plot(delay_data[:, 0], delay_data[:, 5], ".") plt.plot(delay_map.flat, model1_map.flat, ".") plt.plot([0, max_delay], [0, max_delay], "k") plt.ylabel("Model #1 Delay") plt.xlabel("Actual Delay") plt.grid() plt.show() print("In-sample RMS error: %f" % np.sqrt(np.nanmean((delay_map - model1_map)**2))) print("Out-of-sample RMS error: %f" % np.sqrt(np.nanmean((delay_data[:, 0] - delay_data[:, 5])**2))) print() #%% Generate Model #2 def nonlinearPreprocessor2(v): return np.array([1, v, np.sqrt(v)]) A = np.zeros((41*41, len(nonlinearPreprocessor2(0)))) b = np.zeros(41*41) index = 0 for x in range(41): for y in range(41): if delay_map_count[x, y] > 0: A[index, :] = nonlinearPreprocessor2(model1_map[x, y]) b[index] = delay_map[x, y] index += 1 model2_params, _, _, _ = np.linalg.lstsq(A, b) print("Model #2 parameters:", model2_params) model2_map = np.zeros((41, 41)) for x in range(41): for y in range(41): v = np.dot(model1_params, nonlinearPreprocessor1(x-20, y-20)) v = np.dot(model2_params, nonlinearPreprocessor2(v)) model2_map[x, y] = v plt.figure(figsize=(9, 3)) plt.subplot(121) plt.title("Model #2 Delay Map") plt.imshow(model2_map) plt.colorbar() plt.subplot(122) plt.title("Model #2 Error Map") plt.imshow(model2_map - delay_map) plt.colorbar() plt.show() for i in range(delay_data.shape[0]): dx = delay_data[i, 2] dy = delay_data[i, 3] delay_data[i, 6] = np.dot(model2_params, nonlinearPreprocessor2(delay_data[i, 5])) plt.figure(figsize=(8, 3)) plt.title("Model #2 vs Actual Delay") plt.plot(delay_data[:, 0], delay_data[:, 6], ".") plt.plot(delay_map.flat, model2_map.flat, ".") plt.plot([0, max_delay], [0, max_delay], "k") plt.ylabel("Model #2 Delay") plt.xlabel("Actual Delay") plt.grid() plt.show() print("In-sample RMS error: %f" % np.sqrt(np.nanmean((delay_map - model2_map)**2))) print("Out-of-sample RMS error: %f" % np.sqrt(np.nanmean((delay_data[:, 0] - delay_data[:, 6])**2))) print() #%% Generate deltas for different source net types type_deltas = dict() print("Delay deltas for different src types:") for src_type in sorted(type_delta_data.keys()): deltas = list() for dx, dy, delay in type_delta_data[src_type]: dx = abs(dx) dy = abs(dy) if dx > 1 or dy > 1: est = model0_params[0] + model0_params[1] * (dx + dy) else: est = mean_neighbour_tile_delays deltas.append(delay - est) print("%15s: %8.2f (std %6.2f)" % (\ src_type, np.mean(deltas), np.std(deltas))) type_deltas[src_type] = np.mean(deltas) #%% Print C defs of model parameters print("--snip--") print("%d, %d, %d," % (mean_neighbour_tile_delays, 128 * model0_params[0], 128 * model0_params[1])) print("%d, %d, %d, %d," % (128 * model1_params[0], 128 * model1_params[1], 128 * model1_params[2], 128 * model1_params[3])) print("%d, %d, %d," % (128 * model2_params[0], 128 * model2_params[1], 128 * model2_params[2])) print("%d, %d, %d, %d" % (type_deltas["LOCAL"], type_deltas["LUTFF_IN"], \ (type_deltas["SP4_H"] + type_deltas["SP4_V"]) / 2, (type_deltas["SP12_H"] + type_deltas["SP12_V"]) / 2)) print("--snap--")