| from scipy import optimize | |
| from scipy.sparse import linalg | |
| import numpy | |
| import parse_sdf | |
| import design_pip_classes | |
| import pip_classes | |
| import sys | |
| import math | |
| import json | |
| def solve_pip_delays(ncl, sdf, debug=False): | |
| path_pip_classes, wire_fanout = design_pip_classes.get_equations(ncl) | |
| sdf_data = parse_sdf.parse_sdf_file(sdf) | |
| top_ic = None | |
| for cell in sdf_data.cells: | |
| if len(sdf_data.cells[cell].interconnect) != 0: | |
| top_ic = sdf_data.cells[cell].interconnect | |
| break | |
| assert top_ic is not None | |
| variables = {} | |
| for path in sorted(path_pip_classes.values()): | |
| for wire, pipclass in path: | |
| if (pipclass, "delay") not in variables and not pip_classes.force_zero_delay_pip(pipclass): | |
| vid = len(variables) | |
| variables[pipclass, "delay"] = vid | |
| if not pip_classes.force_zero_fanout_pip(pipclass): | |
| if (pipclass, "fanout") not in variables: | |
| vid = len(variables) | |
| variables[pipclass, "fanout"] = vid | |
| kfid = len(variables) | |
| data = {} | |
| corners = "min", "typ", "max" | |
| i = 0 | |
| A = numpy.zeros((len(path_pip_classes), len(variables))) | |
| for arc, path in sorted(path_pip_classes.items()): | |
| for wire, pipclass in path: | |
| if not pip_classes.force_zero_delay_pip(pipclass): | |
| A[i, variables[pipclass, "delay"]] += 1 | |
| if not pip_classes.force_zero_fanout_pip(pipclass): | |
| A[i, variables[pipclass, "fanout"]] += wire_fanout[wire, pipclass] | |
| if pipclass not in data: | |
| data[pipclass] = { | |
| "delay": [0, 0, 0], | |
| "fanout": [0, 0, 0], | |
| } | |
| i += 1 | |
| for corner in corners: | |
| b = numpy.zeros((len(path_pip_classes), )) | |
| i = 0 | |
| for arc, path in sorted(path_pip_classes.items()): | |
| src, dest = arc | |
| srcname = "{}/{}".format(src[0].replace('/', '\\/').replace('.', '\\.'), src[1]) | |
| destname = "{}/{}".format(dest[0].replace('/', '\\/').replace('.', '\\.'), dest[1]) | |
| b[i] = getattr(top_ic[srcname, destname].rising, corner + "v") | |
| i += 1 | |
| print("Starting least squares solver!") | |
| x, rnorm = optimize.nnls(A, b) | |
| for var, j in sorted(variables.items()): | |
| pipclass, vartype = var | |
| data[pipclass][vartype][corners.index(corner)] = x[j] | |
| if debug: | |
| error = numpy.matmul(A, x) - b | |
| i = 0 | |
| worst = 0 | |
| sqsum = 0 | |
| for arc, path in sorted(path_pip_classes.items()): | |
| src, dest = arc | |
| rel_error = error[i] / b[i] | |
| print("error {}.{} -> {}.{} = {:.01f} ps ({:.01f} %)".format(src[0], src[1], dest[0], dest[1], error[i], rel_error * 100)) | |
| worst = max(worst, abs(error[i])) | |
| sqsum += error[i]**2 | |
| i = i + 1 | |
| with open("error.csv", "w") as f: | |
| print("actual, percent", file=f) | |
| for i in range(len(path_pip_classes)): | |
| rel_error = error[i] / b[i] | |
| print("{}, {}".format(b[i], rel_error * 100), file=f) | |
| for var, j in sorted(variables.items()): | |
| print("{}_{} = {:.01f} ps".format(var[0], var[1], x[j])) | |
| print("Error: {:.01f} ps max, {:.01f} ps RMS".format(worst, math.sqrt(sqsum / len(path_pip_classes)))) | |
| return data | |
| def main(): | |
| data = solve_pip_delays(sys.argv[1], sys.argv[2], debug=True) | |
| with open("out.json", "w") as f: | |
| json.dump(data, f, indent=4, sort_keys=True) | |
| if __name__ == "__main__": | |
| main() |