diff options
Diffstat (limited to 'ice40/tmfuzz.py')
-rw-r--r-- | ice40/tmfuzz.py | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/ice40/tmfuzz.py b/ice40/tmfuzz.py new file mode 100644 index 00000000..4ec2a546 --- /dev/null +++ b/ice40/tmfuzz.py @@ -0,0 +1,357 @@ +#!/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--") |