From d5dc09948aa536c0c715c135fee838abb745f5ed Mon Sep 17 00:00:00 2001 From: Karol Gugala Date: Wed, 19 Jun 2019 10:53:19 +0200 Subject: [PATCH] fuzzers: 007: remove unused code Signed-off-by: Karol Gugala --- fuzzers/007-timing/Makefile | 24 +- fuzzers/007-timing/README.md | 275 -- fuzzers/007-timing/benchmark.py | 73 - fuzzers/007-timing/checksub.py | 134 - fuzzers/007-timing/corner_csv.py | 60 - fuzzers/007-timing/csv_flat2group.py | 71 - fuzzers/007-timing/csv_group2flat.py | 112 - .../007-timing/minitest/test_cell_opins.tcl | 29 - fuzzers/007-timing/minitest/test_linprog.py | 139 - .../007-timing/minitest/test_unique/Makefile | 22 - .../007-timing/minitest/test_unique/README.md | 11 - .../minitest/test_unique/generate.sh | 9 - .../minitest/test_unique/generate.tcl | 95 - .../minitest/test_unique/node_unique.py | 107 - .../minitest/test_unique/perf_test.py | 143 - .../minitest/test_unique/pip_unique.py | 91 - fuzzers/007-timing/minitest/test_unique/top.v | 109 - .../minitest/test_unique/wire_unique.py | 96 - .../007-timing/minitest/test_zero/README.md | 1 - .../007-timing/minitest/test_zero/process.py | 76 - fuzzers/007-timing/projects/.gitignore | 3 - fuzzers/007-timing/projects/Makefile | 4 - fuzzers/007-timing/projects/corner.mk | 57 - fuzzers/007-timing/projects/generate.sh | 16 - fuzzers/007-timing/projects/is.mk | 74 - .../007-timing/projects/oneblinkw/Makefile | 4 - .../007-timing/projects/oneblinkw/README.md | 2 - .../007-timing/projects/oneblinkw/generate.sh | 8 - .../projects/oneblinkw/generate.tcl | 45 - fuzzers/007-timing/projects/oneblinkw/top.v | 37 - fuzzers/007-timing/projects/picorv32/Makefile | 2 - .../007-timing/projects/picorv32/README.md | 3 - .../007-timing/projects/picorv32/generate.sh | 8 - .../007-timing/projects/picorv32/generate.tcl | 46 - fuzzers/007-timing/projects/picorv32/top.v | 109 - fuzzers/007-timing/projects/placelut/Makefile | 2 - .../007-timing/projects/placelut/README.md | 2 - .../007-timing/projects/placelut/generate.py | 92 - .../007-timing/projects/placelut/generate.sh | 11 - .../007-timing/projects/placelut/generate.tcl | 45 - .../007-timing/projects/placelut_fb/Makefile | 2 - .../007-timing/projects/placelut_fb/README.md | 2 - .../projects/placelut_fb/generate.py | 103 - .../projects/placelut_fb/generate.sh | 9 - .../projects/placelut_fb/generate.tcl | 45 - .../projects/placelut_ff_fb/Makefile | 2 - .../projects/placelut_ff_fb/README.md | 3 - .../projects/placelut_ff_fb/generate.py | 127 - .../projects/placelut_ff_fb/generate.sh | 9 - .../projects/placelut_ff_fb/generate.tcl | 45 - fuzzers/007-timing/projects/project.mk | 55 - fuzzers/007-timing/projects/project.tcl | 221 -- fuzzers/007-timing/rref.py | 247 -- fuzzers/007-timing/solve_leastsq.py | 158 - fuzzers/007-timing/solve_linprog.py | 193 -- fuzzers/007-timing/solve_qor.py | 60 - fuzzers/007-timing/speed/.gitignore | 2 - fuzzers/007-timing/speed/Makefile | 12 - fuzzers/007-timing/speed/README.md | 4 - fuzzers/007-timing/speed/generate.tcl | 172 - fuzzers/007-timing/speed/speed_json.py | 94 - fuzzers/007-timing/speed/top.v | 8 - fuzzers/007-timing/src/picorv32.v | 2977 ----------------- fuzzers/007-timing/sub2csv.py | 89 - fuzzers/007-timing/tile_annotate.py | 156 - fuzzers/007-timing/timfuz.py | 844 ----- fuzzers/007-timing/timfuz_massage.py | 322 -- fuzzers/007-timing/timfuz_solve.py | 237 -- fuzzers/007-timing/timgrid/Makefile | 12 - fuzzers/007-timing/timgrid/generate.sh | 16 - fuzzers/007-timing/timgrid/generate.tcl | 118 - fuzzers/007-timing/timgrid/tile_txt2json.py | 80 - fuzzers/007-timing/timgrid/top.v | 49 - fuzzers/007-timing/timgrid/top_bram.v | 62 - fuzzers/007-timing/timgrid_vc2v.py | 165 - fuzzers/007-timing/timing_txt2icsv.py | 130 - fuzzers/007-timing/timing_txt2json.py | 201 -- fuzzers/007-timing/timing_txt2scsv.py | 167 - 78 files changed, 1 insertion(+), 9444 deletions(-) delete mode 100644 fuzzers/007-timing/README.md delete mode 100644 fuzzers/007-timing/benchmark.py delete mode 100644 fuzzers/007-timing/checksub.py delete mode 100644 fuzzers/007-timing/corner_csv.py delete mode 100644 fuzzers/007-timing/csv_flat2group.py delete mode 100644 fuzzers/007-timing/csv_group2flat.py delete mode 100644 fuzzers/007-timing/minitest/test_cell_opins.tcl delete mode 100644 fuzzers/007-timing/minitest/test_linprog.py delete mode 100644 fuzzers/007-timing/minitest/test_unique/Makefile delete mode 100644 fuzzers/007-timing/minitest/test_unique/README.md delete mode 100755 fuzzers/007-timing/minitest/test_unique/generate.sh delete mode 100644 fuzzers/007-timing/minitest/test_unique/generate.tcl delete mode 100644 fuzzers/007-timing/minitest/test_unique/node_unique.py delete mode 100644 fuzzers/007-timing/minitest/test_unique/perf_test.py delete mode 100644 fuzzers/007-timing/minitest/test_unique/pip_unique.py delete mode 100644 fuzzers/007-timing/minitest/test_unique/top.v delete mode 100644 fuzzers/007-timing/minitest/test_unique/wire_unique.py delete mode 100644 fuzzers/007-timing/minitest/test_zero/README.md delete mode 100644 fuzzers/007-timing/minitest/test_zero/process.py delete mode 100644 fuzzers/007-timing/projects/.gitignore delete mode 100644 fuzzers/007-timing/projects/Makefile delete mode 100644 fuzzers/007-timing/projects/corner.mk delete mode 100644 fuzzers/007-timing/projects/generate.sh delete mode 100644 fuzzers/007-timing/projects/is.mk delete mode 100644 fuzzers/007-timing/projects/oneblinkw/Makefile delete mode 100644 fuzzers/007-timing/projects/oneblinkw/README.md delete mode 100755 fuzzers/007-timing/projects/oneblinkw/generate.sh delete mode 100644 fuzzers/007-timing/projects/oneblinkw/generate.tcl delete mode 100644 fuzzers/007-timing/projects/oneblinkw/top.v delete mode 100644 fuzzers/007-timing/projects/picorv32/Makefile delete mode 100644 fuzzers/007-timing/projects/picorv32/README.md delete mode 100755 fuzzers/007-timing/projects/picorv32/generate.sh delete mode 100644 fuzzers/007-timing/projects/picorv32/generate.tcl delete mode 100644 fuzzers/007-timing/projects/picorv32/top.v delete mode 100644 fuzzers/007-timing/projects/placelut/Makefile delete mode 100644 fuzzers/007-timing/projects/placelut/README.md delete mode 100644 fuzzers/007-timing/projects/placelut/generate.py delete mode 100755 fuzzers/007-timing/projects/placelut/generate.sh delete mode 100644 fuzzers/007-timing/projects/placelut/generate.tcl delete mode 100644 fuzzers/007-timing/projects/placelut_fb/Makefile delete mode 100644 fuzzers/007-timing/projects/placelut_fb/README.md delete mode 100644 fuzzers/007-timing/projects/placelut_fb/generate.py delete mode 100755 fuzzers/007-timing/projects/placelut_fb/generate.sh delete mode 100644 fuzzers/007-timing/projects/placelut_fb/generate.tcl delete mode 100644 fuzzers/007-timing/projects/placelut_ff_fb/Makefile delete mode 100644 fuzzers/007-timing/projects/placelut_ff_fb/README.md delete mode 100644 fuzzers/007-timing/projects/placelut_ff_fb/generate.py delete mode 100755 fuzzers/007-timing/projects/placelut_ff_fb/generate.sh delete mode 100644 fuzzers/007-timing/projects/placelut_ff_fb/generate.tcl delete mode 100644 fuzzers/007-timing/projects/project.mk delete mode 100644 fuzzers/007-timing/projects/project.tcl delete mode 100644 fuzzers/007-timing/rref.py delete mode 100644 fuzzers/007-timing/solve_leastsq.py delete mode 100644 fuzzers/007-timing/solve_linprog.py delete mode 100644 fuzzers/007-timing/solve_qor.py delete mode 100644 fuzzers/007-timing/speed/.gitignore delete mode 100644 fuzzers/007-timing/speed/Makefile delete mode 100644 fuzzers/007-timing/speed/README.md delete mode 100644 fuzzers/007-timing/speed/generate.tcl delete mode 100644 fuzzers/007-timing/speed/speed_json.py delete mode 100644 fuzzers/007-timing/speed/top.v delete mode 100644 fuzzers/007-timing/src/picorv32.v delete mode 100644 fuzzers/007-timing/sub2csv.py delete mode 100644 fuzzers/007-timing/tile_annotate.py delete mode 100644 fuzzers/007-timing/timfuz.py delete mode 100644 fuzzers/007-timing/timfuz_massage.py delete mode 100644 fuzzers/007-timing/timfuz_solve.py delete mode 100644 fuzzers/007-timing/timgrid/Makefile delete mode 100644 fuzzers/007-timing/timgrid/generate.sh delete mode 100644 fuzzers/007-timing/timgrid/generate.tcl delete mode 100644 fuzzers/007-timing/timgrid/tile_txt2json.py delete mode 100644 fuzzers/007-timing/timgrid/top.v delete mode 100644 fuzzers/007-timing/timgrid/top_bram.v delete mode 100644 fuzzers/007-timing/timgrid_vc2v.py delete mode 100644 fuzzers/007-timing/timing_txt2icsv.py delete mode 100644 fuzzers/007-timing/timing_txt2json.py delete mode 100644 fuzzers/007-timing/timing_txt2scsv.py diff --git a/fuzzers/007-timing/Makefile b/fuzzers/007-timing/Makefile index 1b4f37bf..52202107 100644 --- a/fuzzers/007-timing/Makefile +++ b/fuzzers/007-timing/Makefile @@ -1,32 +1,10 @@ -# for now hammering on just picorv32 -# consider instead aggregating multiple projects -PRJ?=oneblinkw -PRJN?=1 - run: all -all: build/timgrid-v.json bel/build/sdf +all: bel/build/sdf touch run.ok clean: - rm -rf build - cd speed && $(MAKE) clean - cd timgrid && $(MAKE) clean cd bel && $(MAKE) clean - cd projects/$(PRJ) && $(MAKE) clean bel/build/sdf: cd bel && $(MAKE) -speed/build/speed.json: - cd speed && $(MAKE) - -timgrid/build/timgrid.json: - cd timgrid && $(MAKE) - -build/timgrid-v.json: projects/$(PRJ)/build/timgrid-v.json - mkdir -p build - cp projects/$(PRJ)/build/timgrid-v.json build/timgrid-v.json - -projects/$(PRJ)/build/timgrid-v.json: speed/build/speed.json timgrid/build/timgrid.json - cd projects/$(PRJ) && $(MAKE) N=$(PRJN) - diff --git a/fuzzers/007-timing/README.md b/fuzzers/007-timing/README.md deleted file mode 100644 index 308c0585..00000000 --- a/fuzzers/007-timing/README.md +++ /dev/null @@ -1,275 +0,0 @@ -# Timing analysis fuzzer (timfuz) - -WIP: 2018-09-10: this process is just starting together and is going to get significant cleanup. But heres the general idea - -This runs various designs through Vivado and processes the -resulting timing informationin order to create very simple timing models. -While Vivado might have more involved models (say RC delays, fanout, etc), -timfuz creates simple models that bound realistic min and max element delays. - -Currently this document focuses exclusively on fabric timing delays. - - -## Quick start - -``` -make -j$(nproc) -``` - -This will take a relatively long time (say 45 min) and generate build/timgrid-v.json. -You can do a quicker test run (say 3 min) using: - -``` -make PRJ=oneblinkw PRJN=1 -j$(nproc) -``` - - -## Vivado background - -Examples are for a XC750T on Vivado 2017.2. - -TODO maybe move to: https://github.com/SymbiFlow/prjxray/wiki/Timing - - -### Speed index - -Vivado seems to associate each delay model with a "speed index". -The fabric has these in two elements: wires (ie one delay element per tile) and pips. -For example, LUT output node A (ex: CLBLL_L_X12Y100/CLBLL_LL_A) has a single wire, also called CLBLL_L_X12Y100/CLBLL_LL_A. -This has speed index 733. Speed models can be queried and we find this corresponds to model C_CLBLL_LL_A. - -There are various speed model types: -* bel_delay -* buffer -* buffer_switch -* content_version -* functional -* inpin -* outpin -* parameters -* pass_transistor -* switch -* table_lookup -* tl_buffer -* vt_limits -* wire - -IIRC the interconnect is only composed of switch and wire types. - -Indices with value 65535 (0xFFFF) never appear. Presumably these are unused models. -They are used for some special models such as those of type "content_version". -For example, the "xilinx" model is of type "content_version". - -There are also "cost codes", but these seem to be very course (only around 30 of these) -and are suspected to be related more to PnR than timing model. - - -### Timing paths - -The Vivado timing analyzer can easily output the following: -* Full: delay from BEL pin to BEL pin -* Interconnect only (ICO): delay from BEL pin to BEL pin, but only report interconnect delays (ie exclude site delays) - -There is also theoretically an option to report delays up to a specific pip, -but this option is poorly documented and I was unable to get it to work. - -Each timing path reports a fast process and a slow process min and max value. So four process values are reported in total: -* fast_max -* fast_min -* slow_max -* slow_min - -For example, if the device is end of life, was poorly made, and at an extreme temperature, the delay may be up to the slow_max value. -Since ICO can be reported for each of these, fully analyzing a timing path results in 8 values. - -Finally, part of this was analyzing tile regularity to discover what a reasonably compact timing model was. -We verified that all tiles of the same type have exactly the same delay elements. - - - -## Methodology - -Make sure you've read the Vivado background section first - - -### Background - -This section briefly describes some of the mathmatics used by this technique that readers may not be familiar with. -These definitions are intended to be good enough to provide a high level understanding and may not be precise. - -Numerical analysis: the study of algorithms that use numerical approximation (as opposed to general symbolic manipulations) - -numpy: a popular numerical analysis python library. Often written np (import numpy as np). - -scipy: provides higher level functionality on top of numpy - -sympy ("symbolic python"): like numpy, but is designed to work with rational numbers. -For example, python actually stores 0.1 as 0.1000000000000000055511151231257827021181583404541015625. -However, sympy can represent this as the fraction 1/10, eliminating numerical approximation issues. - -Least squares (ex: scipy.optimize.least_squares): approximation method to do a best fit of several variables to a set of equations. -For example, given the equations "x = 1" and "x = 2" there isn't an exact solution. -However, "x = 1.5" is a good compromise since its reasonably solves both equations. - -Linear programming (ex: scipy.optimize.linprog aka linprog): approximation method that finds a set of variables that satisfy a set of inequalities. -For example, - -Reduced row echelon form (RREF, ex: sympy.Matrix.rref): the simplest form that a system of linear equations can be solved to. -For example, given "x = 1" and "x + y = 9", one can solve for "x = 1" and "y = 8". -However, given "x + y = 1" and "x + y + z = 9", there aren't enough variables to solve this fully. -In this case RREF provides a best effort by giving the ratios between correlated variables. -One variable is normalized to 1 in each of these ratios and is called the "pivot". -Note that if numpy.linalg.solve encounters an unsolvable matrix it may either complain -or generate a false solution due to numerical approximation issues. - - -### What didn't work - -First some quick background on things that didn't work to illustrate why the current approach was chosen. -I first tried to directly through things into linprog, but it unfairly weighted towards arbitrary shared variables. For example, feeding in: -* t0 >= 10 -* t0 + t1 >= 100 - -It would declare "t0 = 100", "t1 = 0" instead of the more intuitive "t0 = 10", "t1 = 90". -I tried to work around this in several ways, notably subtracting equations from each other to produce additional constraints. -This worked okay, but was relatively slow and wasn't approaching nearly solved solutions, even when throwing a lot of data at it. - -Next we tried randomly combining a bunch of the equations together and solving them like a regular linear algebra matrix (numpy.linalg.solve). -However, this illustrated that the system was under-constrained. -Further analysis revealed that there are some delay element combinations that simply can't be linearly separated. -This was checked primarily using numpy.linalg.matrix_rank, with some use of numpy.linalg.slogdet. -matrix_rank was preferred over slogdet since its more flexible against non-square matrices. - - -### Process - -Above ultimately led to the idea that we should come up with a set of substitutions that would make the system solvable. This has several advantages: -* Easy to evaluate which variables aren't covered well enough by source data -* Easy to evaluate which variables weren't solved properly (if its fully constrained it should have had a non-zero delay) - -At a high level, the above learnings gave this process: -* Find correlated variables by using RREF (sympy.Matrix.rref) to create variable groups - - Note pivots - - You must input a fractional type (ex: fractions.Fraction, but surprisingly not int) to get exact results, otherwise it seems to fall back to numerical approximation - - This is by far the most computationally expensive step - - Mixing RREF substitutions from one data set to another may not be recommended -* Use RREF result to substitute groups on input data, creating new meta variables, but ultimately reducing the number of columns -* Pick a corner - - Examples assume fast_max, but other corners are applicable with appropriate column and sign changes -* De-duplicate by removing equations that are less constrained - - Ex: if solving for a max corner and given: - - t0 + t1 >= 10 - - t0 + t1 >= 12 - - The first equation is redundant since the second provides a stricter constraint - - This significantly reduces computational time -* Use least squares (scipy.optimize.least_squares) to fit variables near input constraints - - Helps fairly weight delays vs the original input constraints - - Does not guarantee all constraints are met. For example, if this was put in (ignoring these would have been de-duplicated): - - t0 = 10 - - t0 = 12 - - It may decide something like t0 = 11, which means that the second constraint was not satisfied given we actually want t0 >= 12 -* Use linear programming (scipy.optimize.linprog aka linprog) to formally meet all remaining constraints - - Start by filtering out all constraints that are already met. This should eliminate nearly all equations -* Map resulting constraints onto different tile types - - Group delays map onto the group pivot variable, typically setting other elements to 0 (if the processed set is not the one used to create the pivots they may be non-zero) - - -## TODO, suggestions - -Includes -* Consider removing rref - - Intended to understand what can't be solved, maybe not useful in production -* Need more coverage - - Consider instrumenting all fuzzers to output data to feed into timing anlayzer - - Justification: we need a lot of weird cases, we have code that does that in the other fuzzers -* Tune performance parameters - - Can we improve quality of results? - - Do we have a good enough quality checker? (solve_qor.py) - - Compare our vs Xilinx output on random designs - - Does the solve take too long? What could speed it up? -* Investigate min corner - - Tends to solve towards 0, making this not useful - - Low priority: most designs just close timing with setup time -* Investigate characterizing full RC timing model -* Can we split pivot delays among elements instead of entirely into pivot? -* Consider breaking out timing analyzer into its own project / library so it can be re-used on other projects -* Review "--massage". Does this help? -* Review computed site delays vs published Xilinx numbers (DC and AC Switching Characteristics) -* Fabric delay models are RC, but are the site delay models RC as well or maybe just linear? -* Can we create antenna nets to get simpler solves? -* Can we get tcl timing analyzer to analyze a partial route? - - Option says you should be able to do this - - I could not actually get it to work - - -### Improve test cases - -Test cases are somewhat random right now. We could make much more targetted cases using custom routing to improve various fanout estimates and such. -Also there are a lot more elements that are not covered. -At a minimum these should be moved to their own directory. - - -### ZERO models - -Background: there are a number of speed models with the name ZERO in them. -These generally seem to be zero delay, although needs more investigation. - -Example: see pseudo pip item below - -The timing models will probably significantly improve if these are removed. -In the past I was removing them, but decided to keep them in for now in the spirit of being more conservative. - -They include: - * _BSW_CLK_ZERO - * BSW_CLK_ZERO - * _BSW_ZERO - * BSW_ZERO - * _B_ZERO - * B_ZERO - * C_CLK_ZERO - * C_DSP_ZERO - * C_ZERO - * I_ZERO - * _O_ZERO - * O_ZERO - * RC_ZERO - * _R_ZERO - * R_ZERO - - -### Virtual switchboxes - -Background: several low level configuration details are abstracted with virtual configurable elements. -For example, LUT inputs can be rearranged to reduce routing congestion. -However, the LUT configuratioon must be changed to match the switched inputs. -This is handled by the CLBLL_L_INTER switchbox, which doesn't encode any physical configuration bits. -However, this contains PIPs with delay models. - -For example, LUT A, input A1 has node CLBLM_M_A1 coming from pip junction CLBLM_M_A1 has PIP CLBLM_IMUX7->CLBLM_M_A1 -with speed index 659 (R_ZERO). - -This might be further evidence on related issue that ZERO models should probably be removed. - - -### Incporporate fanout - -We could probably significantly improve model granularity by studying delay impact on fanout - - -### Investigate RC delays - -Suspect accuracy could be significantly improved by moving to SPICE based models. But this will take significantly more characterization - - -### Characterize real hardware - -A few people have expressed interest on running tests on real hardware. Will take some thought given we don't have direct access - - -### Review approximation errors - -Ex: one known issue is that the objective function linearly weights small and large delays. -This is only recommended when variables are approximately the same order of magnitude. -For example, carry chain delays are on the order of 7 ps while other delays are 100 ps. -Its very easy to put a large delay on the carry chain while it could have been more appropriately put somewhere else. - diff --git a/fuzzers/007-timing/benchmark.py b/fuzzers/007-timing/benchmark.py deleted file mode 100644 index 39a6e797..00000000 --- a/fuzzers/007-timing/benchmark.py +++ /dev/null @@ -1,73 +0,0 @@ -''' -pr0ntools -Benchmarking utility -Copyright 2010 John McMaster -''' - -import time - - -def time_str(delta): - fraction = delta % 1 - delta -= fraction - delta = int(delta) - seconds = delta % 60 - delta /= 60 - minutes = delta % 60 - delta /= 60 - hours = delta - return '%02d:%02d:%02d.%04d' % (hours, minutes, seconds, fraction * 10000) - - -class Benchmark: - start_time = None - end_time = None - - def __init__(self, max_items=None): - # For the lazy - self.start_time = time.time() - self.end_time = None - self.max_items = max_items - self.cur_items = 0 - - def start(self): - self.start_time = time.time() - self.end_time = None - self.cur_items = 0 - - def stop(self): - self.end_time = time.time() - - def advance(self, n=1): - self.cur_items += n - - def set_cur_items(self, n): - self.cur_items = n - - def delta_s(self): - if self.end_time: - return self.end_time - self.start_time - else: - return time.time() - self.start_time - - def __str__(self): - if self.end_time: - return time_str(self.end_time - self.start_time) - elif self.max_items: - cur_time = time.time() - delta_t = cur_time - self.start_time - rate_s = 'N/A' - if delta_t > 0.000001: - rate = self.cur_items / (delta_t) - rate_s = '%f items / sec' % rate - if rate == 0: - eta_str = 'inf' - else: - remaining = (self.max_items - self.cur_items) / rate - eta_str = time_str(remaining) - else: - eta_str = "indeterminate" - return '%d / %d, ETA: %s @ %s' % ( - self.cur_items, self.max_items, eta_str, rate_s) - else: - return time_str(time.time() - self.start_time) diff --git a/fuzzers/007-timing/checksub.py b/fuzzers/007-timing/checksub.py deleted file mode 100644 index 34ab981a..00000000 --- a/fuzzers/007-timing/checksub.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import Benchmark, Ar_di2np, Ar_ds2t, A_di2ds, A_ds2di, loadc_Ads_b, index_names, A_ds2np, load_sub, run_sub_json -import numpy as np -import glob -import json -import math -from collections import OrderedDict -from fractions import Fraction - - -def Adi2matrix_random(A_ubd, b_ub, names): - # random assignment - # was making some empty rows - - A_ret = [np.zeros(len(names)) for _i in range(len(names))] - b_ret = np.zeros(len(names)) - - for row, b in zip(A_ubd, b_ub): - # Randomly assign to a row - dst_rowi = random.randint(0, len(names) - 1) - rownp = Ar_di2np(row, cols=len(names), sf=1) - - A_ret[dst_rowi] = np.add(A_ret[dst_rowi], rownp) - b_ret[dst_rowi] += b - return A_ret, b_ret - - -def Ads2matrix_linear(Ads, b): - names, Adi = A_ds2di(Ads) - cols = len(names) - rows_out = len(b) - - A_ret = [np.zeros(cols) for _i in range(rows_out)] - b_ret = np.zeros(rows_out) - - dst_rowi = 0 - for row_di, row_b in zip(Adi, b): - row_np = Ar_di2np(row_di, cols) - - A_ret[dst_rowi] = np.add(A_ret[dst_rowi], row_np) - b_ret[dst_rowi] += row_b - dst_rowi = (dst_rowi + 1) % rows_out - return A_ret, b_ret - - -def pmatrix(Anp, s): - import sympy - msym = sympy.Matrix(Anp) - print(s) - sympy.pprint(msym) - - -def pds(Ads, s): - names, Anp = A_ds2np(Ads) - pmatrix(Anp, s) - print('Names: %s' % (names, )) - - -def run(fns_in, sub_json=None, verbose=False): - assert len(fns_in) > 0 - # arbitrary corner...data is thrown away - Ads, b = loadc_Ads_b(fns_in, "slow_max") - - if sub_json: - print('Subbing JSON %u rows' % len(Ads)) - #pds(Ads, 'Orig') - names_old = index_names(Ads) - run_sub_json(Ads, sub_json, verbose=verbose) - names_new = index_names(Ads) - print("Sub: %u => %u names" % (len(names_old), len(names_new))) - print(names_new) - print('Subbed JSON %u rows' % len(Ads)) - names = names_new - #pds(Ads, 'Sub') - else: - names = index_names(Ads) - - # Squash into a matrix - # A_ub2, b_ub2 = Adi2matrix_random(A_ubd, b, names) - Amat, _bmat = Ads2matrix_linear(Ads, b) - #pmatrix(Amat, 'Matrix') - ''' - The matrix must be fully ranked to even be considered reasonable - Even then, floating point error *possibly* could make it fully ranked, although probably not since we have whole numbers - Hence the slogdet check - ''' - print - # https://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.linalg.matrix_rank.html - rank = np.linalg.matrix_rank(Amat) - print('rank: %s / %d col' % (rank, len(names))) - # doesn't work on non-square matrices - if 0: - # https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.linalg.slogdet.html - sign, logdet = np.linalg.slogdet(Amat) - # If the determinant is zero, then sign will be 0 and logdet will be -Inf - if sign == 0 and logdet == float('-inf'): - print('slogdet :( : 0') - else: - print('slogdet :) : %s, %s' % (sign, logdet)) - if rank != len(names): - raise Exception( - "Matrix not fully ranked w/ %u / %u" % (rank, len(names))) - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description='Check if sub.json would make a linear equation solvable') - - parser.add_argument('--verbose', action='store_true', help='') - parser.add_argument('--sub-json', help='') - parser.add_argument('fns_in', nargs='*', help='timing4i.csv input files') - args = parser.parse_args() - # Store options in dict to ease passing through functions - bench = Benchmark() - - fns_in = args.fns_in - if not fns_in: - fns_in = glob.glob('specimen_*/timing4i.csv') - - sub_json = None - if args.sub_json: - sub_json = load_sub(args.sub_json) - - try: - run(sub_json=sub_json, fns_in=fns_in, verbose=args.verbose) - finally: - print('Exiting after %s' % bench) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/corner_csv.py b/fuzzers/007-timing/corner_csv.py deleted file mode 100644 index 8b7290a3..00000000 --- a/fuzzers/007-timing/corner_csv.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import Benchmark, simplify_rows, loadc_Ads_b -import glob - - -def run(fout, fns_in, corner, verbose=0): - Ads, b = loadc_Ads_b(fns_in, corner, ico=True) - Ads, b = simplify_rows(Ads, b, corner=corner) - - fout.write('ico,fast_max fast_min slow_max slow_min,rows...\n') - for row_b, row_ds in zip(b, Ads): - # write in same format, but just stick to this corner - out_b = [str(row_b) for _i in range(4)] - ico = '1' - items = [ico, ' '.join(out_b)] - - for k, v in sorted(row_ds.items()): - items.append('%u %s' % (v, k)) - fout.write(','.join(items) + '\n') - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description='Create a .csv with a single process corner') - - parser.add_argument('--verbose', type=int, help='') - parser.add_argument( - '--auto-name', - action='store_true', - help='timing4i.csv => timing4c.csv') - parser.add_argument('--out', default=None, help='Output csv') - parser.add_argument('--corner', help='Output csv') - parser.add_argument('fns_in', nargs='+', help='timing4i.csv input files') - args = parser.parse_args() - bench = Benchmark() - - fnout = args.out - if fnout is None: - if args.auto_name: - assert len(args.fns_in) == 1 - fnin = args.fns_in[0] - fnout = fnin.replace('timing4i.csv', 'timing4c.csv') - assert fnout != fnin, 'Expect timing4i.csv in' - else: - fnout = '/dev/stdout' - print("Writing to %s" % fnout) - fout = open(fnout, 'w') - - fns_in = args.fns_in - if not fns_in: - fns_in = glob.glob('specimen_*/timing4i.csv') - - run(fout=fout, fns_in=fns_in, corner=args.corner, verbose=args.verbose) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/csv_flat2group.py b/fuzzers/007-timing/csv_flat2group.py deleted file mode 100644 index d382e6f1..00000000 --- a/fuzzers/007-timing/csv_flat2group.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import Benchmark, loadc_Ads_bs, index_names, load_sub, run_sub_json, instances - - -def gen_group(fnin, sub_json, strict=False, verbose=False): - print('Loading data') - Ads, bs = loadc_Ads_bs([fnin]) - - print('Sub: %u rows' % len(Ads)) - iold = instances(Ads) - names_old = index_names(Ads) - run_sub_json(Ads, sub_json, strict=strict, verbose=verbose) - names = index_names(Ads) - print("Sub: %u => %u names" % (len(names_old), len(names))) - print('Sub: %u => %u instances' % (iold, instances(Ads))) - - for row_ds, row_bs in zip(Ads, bs): - yield row_ds, row_bs - - -def run(fns_in, fnout, sub_json, strict=False, verbose=False): - with open(fnout, 'w') as fout: - fout.write('ico,fast_max fast_min slow_max slow_min,rows...\n') - for fn_in in fns_in: - for row_ds, row_bs in gen_group(fn_in, sub_json, strict=strict): - row_ico = 1 - items = [str(row_ico), ' '.join([str(x) for x in row_bs])] - for k, v in sorted(row_ds.items()): - items.append('%u %s' % (v, k)) - fout.write(','.join(items) + '\n') - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description='Substitute .csv to group correlated variables') - - parser.add_argument('--verbose', action='store_true', help='') - parser.add_argument('--strict', action='store_true', help='') - parser.add_argument('--sub-csv', help='') - parser.add_argument( - '--sub-json', - required=True, - help='Group substitutions to make fully ranked') - parser.add_argument('--out', help='Output sub.json substitution result') - parser.add_argument('fns_in', nargs='+', help='timing4i.csv input files') - args = parser.parse_args() - # Store options in dict to ease passing through functions - bench = Benchmark() - - fns_in = args.fns_in - if not fns_in: - fns_in = glob.glob('specimen_*/timing4i.csv') - - sub_json = load_sub(args.sub_json) - - try: - run( - fns_in, - args.out, - sub_json=sub_json, - strict=args.strict, - verbose=args.verbose) - finally: - print('Exiting after %s' % bench) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/csv_group2flat.py b/fuzzers/007-timing/csv_group2flat.py deleted file mode 100644 index 6f1e31b1..00000000 --- a/fuzzers/007-timing/csv_group2flat.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import Benchmark, loadc_Ads_bs, load_sub, Ads2bounds, corners2csv, corner_s2i - - -def gen_flat(fns_in, sub_json, corner=None): - Ads, bs = loadc_Ads_bs(fns_in) - bounds = Ads2bounds(Ads, bs) - # Elements with zero delay assigned due to sub group - group_zeros = set() - # Elements with a concrete delay - nonzeros = set() - - if corner: - zero_row = [None, None, None, None] - zero_row[corner_s2i[corner]] = 0 - else: - zero_row = None - - for bound_name, bound_bs in bounds.items(): - sub = sub_json['subs'].get(bound_name, None) - if bound_name in sub_json['zero_names']: - if zero_row: - yield bound_name, 0 - elif sub: - #print('sub', sub) - # put entire delay into pivot - pivot = sub_json['pivots'][bound_name] - assert pivot not in group_zeros - nonzeros.add(pivot) - non_pivot = set(sub.keys() - set([pivot])) - #for name in non_pivot: - # assert name not in nonzeros, (pivot, name, nonzeros) - group_zeros.update(non_pivot) - #print('yield PIVOT', pivot) - yield pivot, bound_bs - else: - nonzeros.add(bound_name) - yield bound_name, bound_bs - # non-pivots can appear multiple times, but they should always be zero - # however, due to substitution limitations, just warn - violations = group_zeros.intersection(nonzeros) - if len(violations): - print('WARNING: %s non-0 non-pivot' % (len(violations))) - - # XXX: how to best handle these? - # should they be fixed 0? - if zero_row: - # ZERO names should always be zero - #print('ZEROs: %u' % len(sub_json['zero_names'])) - for zero in sub_json['zero_names']: - #print('yield ZERO', zero) - yield zero, zero_row - - real_zeros = group_zeros - violations - print( - 'Zero candidates: %u w/ %u non-pivot conflicts => %u zeros as solved' - % (len(group_zeros), len(violations), len(real_zeros))) - # Only yield elements not already yielded - for zero in real_zeros: - #print('yield solve-0', zero) - yield zero, zero_row - - -def run(fns_in, fnout, sub_json, corner=None, verbose=False): - with open(fnout, 'w') as fout: - fout.write('ico,fast_max fast_min slow_max slow_min,rows...\n') - for name, corners in sorted(list(gen_flat(fns_in, sub_json, - corner=corner))): - row_ico = 1 - items = [str(row_ico), corners2csv(corners)] - items.append('%u %s' % (1, name)) - fout.write(','.join(items) + '\n') - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description='Substitute .csv to ungroup correlated variables') - - parser.add_argument('--verbose', action='store_true', help='') - parser.add_argument('--sub-csv', help='') - parser.add_argument( - '--sub-json', - required=True, - help='Group substitutions to make fully ranked') - parser.add_argument('--corner', default=None, help='') - parser.add_argument('--out', default=None, help='output timing delay .csv') - parser.add_argument( - 'fns_in', - nargs='+', - help='input timing delay .csv (NOTE: must be single column)') - args = parser.parse_args() - # Store options in dict to ease passing through functions - bench = Benchmark() - - sub_json = load_sub(args.sub_json) - - try: - run( - args.fns_in, - args.out, - sub_json=sub_json, - verbose=args.verbose, - corner=args.corner) - finally: - print('Exiting after %s' % bench) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/minitest/test_cell_opins.tcl b/fuzzers/007-timing/minitest/test_cell_opins.tcl deleted file mode 100644 index f3ed8130..00000000 --- a/fuzzers/007-timing/minitest/test_cell_opins.tcl +++ /dev/null @@ -1,29 +0,0 @@ -# Demonstrates that cells can have 0 to 2 BEL output pins -# roi/dout_shr_reg[0]: roi/dout_shr[0]_i_1/O roi/dout_shr_reg[0] - -set TIME_start [clock clicks -milliseconds] -set site_src_nets 0 -set neti 0 -set nets [get_nets -hierarchical] -set nnets [llength $nets] -set opins_zero 0 -set opins_multi 0 -foreach net $nets { - incr neti - puts "Net $neti / $nnets: $net" - - set out_pins [get_pins -filter {DIRECTION == OUT} -of_objects $net] - set npins [llength $out_pins] - if {$npins == 0} { - puts " $net zero source pins: $src_pin" - incr opins_zero - } - if {$npins > 1} { - puts " $net multi source pins: $src_pin" - incr opins_multi - } -} -set TIME_taken [expr [clock clicks -milliseconds] - $TIME_start] -puts "Took ms: $TIME_taken" -puts "Result: $opins_zero / $nnets zero" -puts "Result: $opins_multi / $nnets multi" diff --git a/fuzzers/007-timing/minitest/test_linprog.py b/fuzzers/007-timing/minitest/test_linprog.py deleted file mode 100644 index 78c8c24a..00000000 --- a/fuzzers/007-timing/minitest/test_linprog.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python3 - -import scipy.optimize as optimize -import numpy as np -import glob -import json -import math -import sys -import os -import time - - -def run_max(Anp, b, verbose=False): - cols = len(Anp[0]) - - b_ub = -1.0 * b - A_ub = [-1.0 * x for x in Anp] - - res = optimize.linprog( - c=[1 for _i in range(cols)], - A_ub=A_ub, - b_ub=b_ub, - bounds=(0, None), - options={ - "disp": True, - 'maxiter': 1000000, - 'bland': True, - 'tol': 1e-6, - }) - nonzeros = 0 - print('Ran') - if res.success: - print('Result sample (%d elements)' % (len(res.x))) - plim = 3 - for xi, x in enumerate(res.x): - nonzero = x >= 0.001 - if nonzero: - nonzeros += 1 - if nonzero and (verbose or ( - (nonzeros < 100 or nonzeros % 20 == 0) and nonzeros <= plim)): - print(' % 4u % 10.1f' % (xi, x)) - print('Delay on %d / %d' % (nonzeros, len(res.x))) - - -def run_min(Anp, b, verbose=False): - cols = len(Anp[0]) - - b_ub = b - A_ub = Anp - - res = optimize.linprog( - c=[-1 for _i in range(cols)], - A_ub=A_ub, - b_ub=b_ub, - bounds=(0, None), - options={ - "disp": True, - 'maxiter': 1000000, - 'bland': True, - 'tol': 1e-6, - }) - nonzeros = 0 - print('Ran') - if res.success: - print('Result sample (%d elements)' % (len(res.x))) - plim = 3 - for xi, x in enumerate(res.x): - nonzero = x >= 0.001 - if nonzero: - nonzeros += 1 - if nonzero and (verbose or ( - (nonzeros < 100 or nonzeros % 20 == 0) and nonzeros <= plim)): - print(' % 4u % 10.1f' % (xi, x)) - print('Delay on %d / %d' % (nonzeros, len(res.x))) - - -def run(verbose=False): - ''' - 1 * x0 = 10 - 1 * x0 + 1 * x1 = 100 - 1 * x0 = 40 - 2 * x1 = 140 - ''' - Anp = np.array([ - [1, 0], - [1, 1], - [1, 0], - [0, 2], - ]) - b = np.array([ - 10, - 100, - 40, - 140, - ]) - ''' - Max - Optimization terminated successfully. - Current function value: 110.000000 - Iterations: 4 - Ran - Result sample (2 elements) - 0 40.0 - 1 70.0 - Delay on 2 / 2 - ''' - print('Max') - run_max(Anp, b) - print('') - print('') - print('') - ''' - Min - Optimization terminated successfully. - Current function value: -80.000000 - Iterations: 2 - Ran - Result sample (2 elements) - 0 10.0 - 1 70.0 - Delay on 2 / 2 - ''' - print('Min') - run_min(Anp, b) - - -def main(): - import argparse - - parser = argparse.ArgumentParser(description='Test') - - parser.add_argument('--verbose', action='store_true', help='') - args = parser.parse_args() - - run(verbose=args.verbose) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/minitest/test_unique/Makefile b/fuzzers/007-timing/minitest/test_unique/Makefile deleted file mode 100644 index 0a3491ca..00000000 --- a/fuzzers/007-timing/minitest/test_unique/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -N := 1 -SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N))) -SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) - -all: $(SPECIMENS_OK) - -$(SPECIMENS_OK): - bash generate.sh $(subst /OK,,$@) || (if [ "$(BADPRJ_OK)" != 'Y' ] ; then exit 1; fi; exit 0) - touch $@ - -run: - $(MAKE) clean - $(MAKE) all - touch run.ok - -clean: - rm -rf specimen_[0-9][0-9][0-9]/ seg_clblx.db __pycache__ run.ok - rm -rf vivado*.log vivado_*.str vivado*.jou design *.bits *.dcp *.bit - rm -rf build - -.PHONY: all run clean - diff --git a/fuzzers/007-timing/minitest/test_unique/README.md b/fuzzers/007-timing/minitest/test_unique/README.md deleted file mode 100644 index 84c19977..00000000 --- a/fuzzers/007-timing/minitest/test_unique/README.md +++ /dev/null @@ -1,11 +0,0 @@ -Characterizes how attributes vary across pips, wires, and nodes. Usage: - -``` -$ make -$ python3 pip_unique.py -$ python3 wire_unique.py -$ python3 node_unique.py -``` - -NOTE: "make" will take a long time (about 2.5 hours on my machine) - diff --git a/fuzzers/007-timing/minitest/test_unique/generate.sh b/fuzzers/007-timing/minitest/test_unique/generate.sh deleted file mode 100755 index 73bd35e1..00000000 --- a/fuzzers/007-timing/minitest/test_unique/generate.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -set -ex - -source ${XRAY_GENHEADER} -TIMFUZ_DIR=$XRAY_DIR/fuzzers/007-timing - -${XRAY_VIVADO} -mode batch -source ../generate.tcl - diff --git a/fuzzers/007-timing/minitest/test_unique/generate.tcl b/fuzzers/007-timing/minitest/test_unique/generate.tcl deleted file mode 100644 index 2b9225c6..00000000 --- a/fuzzers/007-timing/minitest/test_unique/generate.tcl +++ /dev/null @@ -1,95 +0,0 @@ -source ../../../../utils/utils.tcl - -proc build_design {} { - create_project -force -part $::env(XRAY_PART) design design - read_verilog ../../src/picorv32.v - read_verilog ../top.v - synth_design -top top - - puts "Locking pins" - set_property LOCK_PINS {I0:A1 I1:A2 I2:A3 I3:A4 I4:A5 I5:A6} \ - [get_cells -quiet -filter {REF_NAME == LUT6} -hierarchical] - - puts "Package stuff" - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports stb] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports di] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports do] - - puts "pblocking" - create_pblock roi - set roipb [get_pblocks roi] - add_cells_to_pblock $roipb [get_cells roi] - resize_pblock $roipb -add "$::env(XRAY_ROI)" - - puts "randplace" - randplace_pblock 50 roi - - set_property CFGBVS VCCO [current_design] - set_property CONFIG_VOLTAGE 3.3 [current_design] - set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] - - puts "dedicated route" - set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] - - place_design - route_design - - write_checkpoint -force design.dcp - # disable combinitorial loop - # set_property IS_ENABLED 0 [get_drc_checks {LUTLP-1}] - #write_bitstream -force design.bit -} - -proc pips_all {} { - set outdir "." - set fp [open "$outdir/pip_all.txt" w] - set items [get_pips] - puts "Items: [llength $items]" - - set needspace 0 - set properties [list_property [lindex $items 0]] - foreach item $items { - set needspace 0 - foreach property $properties { - set val [get_property $property $item] - if {"$val" ne ""} { - if $needspace { - puts -nonewline $fp " " - } - puts -nonewline $fp "$property:$val" - set needspace 1 - } - } - puts $fp "" - } - close $fp -} -proc wires_all {} { - set outdir "." - set fp [open "$outdir/wire_all.txt" w] - set items [get_wires] - puts "Items: [llength $items]" - - set needspace 0 - set properties [list_property [lindex $items 0]] - foreach item $items { - set needspace 0 - foreach property $properties { - set val [get_property $property $item] - if {"$val" ne ""} { - if $needspace { - puts -nonewline $fp " " - } - puts -nonewline $fp "$property:$val" - set needspace 1 - } - } - puts $fp "" - } - close $fp -} - -build_design -pips_all -wires_all diff --git a/fuzzers/007-timing/minitest/test_unique/node_unique.py b/fuzzers/007-timing/minitest/test_unique/node_unique.py deleted file mode 100644 index df6cd0db..00000000 --- a/fuzzers/007-timing/minitest/test_unique/node_unique.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python3 - -import re - - -def gen_nodes(fin): - for l in fin: - lj = {} - l = l.strip() - for kvs in l.split(): - name, value = kvs.split(':') - ''' - NAME:LIOB33_SING_X0Y199/IOB_IBUF0 - - IS_BAD:0 - IS_COMPLETE:1 - IS_GND:0 IS_INPUT_PIN:1 IS_OUTPUT_PIN:0 IS_PIN:1 IS_VCC:0 - NUM_WIRES:2 - PIN_WIRE:1 - ''' - if name in ('COST_CODE', 'SPEED_CLASS'): - value = int(value) - lj[name] = value - - tile_type, xy, wname = re.match( - r'(.*)_(X[0-9]*Y[0-9]*)/(.*)', lj['NAME']).groups() - lj['tile_type'] = tile_type - lj['xy'] = xy - lj['wname'] = wname - - lj['l'] = l - - yield lj - - -def run(node_fin, verbose=0): - refnodes = {} - nodei = 0 - for nodei, anode in enumerate(gen_nodes(node_fin)): - - def getk(anode): - return anode['wname'] - #return (anode['tile_type'], anode['wname']) - - if nodei % 100000 == 0: - print('Check node %d, %u node types' % (nodei, len(refnodes))) - # Existing node? - try: - refnode = refnodes[getk(anode)] - except KeyError: - # Set as reference - refnodes[getk(anode)] = anode - continue - # Verify equivilence - for k in ( - 'SPEED_CLASS', - 'COST_CODE', - 'COST_CODE_NAME', - 'IS_BAD', - 'IS_COMPLETE', - 'IS_GND', - 'IS_VCC', - ): - if k in refnode and k in anode: - - def fail(): - print('Mismatch on %s' % k) - print(refnode[k], anode[k]) - print(refnode['l']) - print(anode['l']) - #assert 0 - - if k == 'SPEED_CLASS': - # Parameters known to effect SPEED_CLASS - # Verify at least one parameter is different - if refnode[k] != anode[k]: - for k2 in ('IS_PIN', 'IS_INPUT_PIN', 'IS_OUTPUT_PIN', - 'PIN_WIRE', 'NUM_WIRES'): - if refnode[k2] != anode[k2]: - break - else: - if 0: - print - fail() - elif refnode[k] != anode[k]: - print - fail() - # A key in one but not the other? - elif k in refnode or k in anode: - assert 0 - - -if __name__ == '__main__': - import argparse - - parser = argparse.ArgumentParser( - description= - 'Determines which info is consistent across nodes with the same name') - - parser.add_argument('--verbose', type=int, help='') - parser.add_argument( - 'node_fn_in', - default='specimen_001/wire_all.txt', - nargs='?', - help='Input file') - args = parser.parse_args() - run(open(args.node_fn_in, 'r'), verbose=args.verbose) diff --git a/fuzzers/007-timing/minitest/test_unique/perf_test.py b/fuzzers/007-timing/minitest/test_unique/perf_test.py deleted file mode 100644 index a857db13..00000000 --- a/fuzzers/007-timing/minitest/test_unique/perf_test.py +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env python3 -''' -Triaging tool to help understand where we need more timing coverage -Finds correlated variables to help make better test cases -''' - -from timfuz import Benchmark, Ar_di2np, loadc_Ads_b, index_names, A_ds2np, simplify_rows -import numpy as np -import glob -import math -import json -import sympy -from collections import OrderedDict -from fractions import Fraction -import random -from sympy import Rational - - -def intr(r): - DELTA = 0.0001 - - for i, x in enumerate(r): - if type(x) is float: - xi = int(x) - assert abs(xi - x) < DELTA - r[i] = xi - - -def fracr(r): - intr(r) - return [Fraction(x) for x in r] - - -def fracm(m): - return [fracr(r) for r in m] - - -def symratr(r): - intr(r) - return [Rational(x) for x in r] - - -def symratm(m): - return [symratr(r) for r in m] - - -def intm(m): - [intr(r) for r in m] - return m - - -def create_matrix(rows, cols): - ret = np.zeros((rows, cols)) - for rowi in range(rows): - for coli in range(cols): - ret[rowi][coli] = random.randint(1, 10) - return ret - - -def create_matrix_sparse(rows, cols): - ret = np.zeros((rows, cols)) - for rowi in range(rows): - for coli in range(cols): - if random.randint(0, 5) < 1: - ret[rowi][coli] = random.randint(1, 10) - return ret - - -def run( - rows=35, - cols=200, - verbose=False, - encoding='np', - sparse=False, - normalize_last=True): - random.seed(0) - if sparse: - mnp = create_matrix_sparse(rows, cols) - else: - mnp = create_matrix(rows, cols) - #print(mnp[0]) - - if encoding == 'fraction': - msym = sympy.Matrix(fracm(mnp)) - elif encoding == 'np': - msym = sympy.Matrix(mnp) - elif encoding == 'sympy': - msym = sympy.Matrix(symratm(mnp)) - # this actually produces float results - elif encoding == 'int': - msym = sympy.Matrix(intm(mnp)) - else: - assert 0, 'bad encoding: %s' % encoding - print(type(msym[0]), str(msym[0])) - - if verbose: - print('names') - print(names) - print('Matrix') - sympy.pprint(msym) - - print( - '%s matrix, %u rows x %u cols, sparse: %s, normlast: %s' % - (encoding, len(mnp), len(mnp[0]), sparse, normalize_last)) - bench = Benchmark() - try: - rref, pivots = msym.rref(normalize_last=normalize_last) - finally: - print('rref exiting after %s' % bench) - print(type(rref[0]), str(rref[0])) - - if verbose: - print('Pivots') - sympy.pprint(pivots) - print('rref') - sympy.pprint(rref) - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description='Matrix solving performance tests') - - parser.add_argument('--verbose', action='store_true', help='') - parser.add_argument('--sparse', action='store_true', help='') - parser.add_argument('--rows', type=int, help='') - parser.add_argument('--cols', type=int, help='') - parser.add_argument('--normalize-last', type=int, help='') - parser.add_argument('--encoding', default='np', help='') - args = parser.parse_args() - - run( - encoding=args.encoding, - rows=args.rows, - cols=args.cols, - sparse=args.sparse, - normalize_last=bool(args.normalize_last), - verbose=args.verbose) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/minitest/test_unique/pip_unique.py b/fuzzers/007-timing/minitest/test_unique/pip_unique.py deleted file mode 100644 index c64c1744..00000000 --- a/fuzzers/007-timing/minitest/test_unique/pip_unique.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python3 - -import re - - -def gen_wires(fin): - for l in fin: - lj = {} - l = l.strip() - for kvs in l.split(): - name, value = kvs.split(':') - lj[name] = value - - tile_type, xy, wname = re.match( - r'(.*)_(X[0-9]*Y[0-9]*)/(.*)', lj['NAME']).groups() - lj['tile_type'] = tile_type - lj['xy'] = xy - lj['wname'] = wname - - lj['l'] = l - - yield lj - - -def run(node_fin, verbose=0): - refnodes = {} - nodei = 0 - for nodei, anode in enumerate(gen_wires(node_fin)): - - def getk(anode): - return anode['wname'] - return (anode['tile_type'], anode['wname']) - - if nodei % 100000 == 0: - print('Check node %d, %u node types' % (nodei, len(refnodes))) - # Existing node? - try: - refnode = refnodes[getk(anode)] - except KeyError: - # Set as reference - refnodes[getk(anode)] = anode - continue - k_invariant = ( - 'CAN_INVERT', - 'IS_BUFFERED_2_0', - 'IS_BUFFERED_2_1', - 'IS_DIRECTIONAL', - 'IS_EXCLUDED_PIP', - 'IS_FIXED_INVERSION', - 'IS_INVERTED', - 'IS_PSEUDO', - 'IS_SITE_PIP', - 'IS_TEST_PIP', - ) - k_varies = ('TILE', ) - # Verify equivilence - for k in k_invariant: - if k in refnode and k in anode: - - def fail(): - print('Mismatch on %s' % k) - print(refnode[k], anode[k]) - print(refnode['l']) - print(anode['l']) - #assert 0 - - if refnode[k] != anode[k]: - print('') - fail() - # A key in one but not the other? - elif k in refnode or k in anode: - assert 0 - elif k not in k_varies: - assert 0 - - -if __name__ == '__main__': - import argparse - - parser = argparse.ArgumentParser( - description= - 'Determines which info is consistent across PIPs with the same name') - - parser.add_argument('--verbose', type=int, help='') - parser.add_argument( - 'node_fn_in', - default='specimen_001/pip_all.txt', - nargs='?', - help='Input file') - args = parser.parse_args() - run(open(args.node_fn_in, 'r'), verbose=args.verbose) diff --git a/fuzzers/007-timing/minitest/test_unique/top.v b/fuzzers/007-timing/minitest/test_unique/top.v deleted file mode 100644 index 0cb9b8a3..00000000 --- a/fuzzers/007-timing/minitest/test_unique/top.v +++ /dev/null @@ -1,109 +0,0 @@ -//move some stuff to minitests/ncy0 - -`define SEED 32'h12345678 - -module top(input clk, stb, di, output do); - localparam integer DIN_N = 42; - localparam integer DOUT_N = 79; - - reg [DIN_N-1:0] din; - wire [DOUT_N-1:0] dout; - - reg [DIN_N-1:0] din_shr; - reg [DOUT_N-1:0] dout_shr; - - always @(posedge clk) begin - din_shr <= {din_shr, di}; - dout_shr <= {dout_shr, din_shr[DIN_N-1]}; - if (stb) begin - din <= din_shr; - dout_shr <= dout; - end - end - - assign do = dout_shr[DOUT_N-1]; - - roi #(.DIN_N(DIN_N), .DOUT_N(DOUT_N)) - roi ( - .clk(clk), - .din(din), - .dout(dout) - ); -endmodule - -module roi(input clk, input [DIN_N-1:0] din, output [DOUT_N-1:0] dout); - parameter integer DIN_N = -1; - parameter integer DOUT_N = -1; - - /* - //Take out for now to make sure LUTs are more predictable - picorv32 picorv32 ( - .clk(clk), - .resetn(din[0]), - .mem_valid(dout[0]), - .mem_instr(dout[1]), - .mem_ready(din[1]), - .mem_addr(dout[33:2]), - .mem_wdata(dout[66:34]), - .mem_wstrb(dout[70:67]), - .mem_rdata(din[33:2]) - ); - */ - - /* - randluts randluts ( - .din(din[41:34]), - .dout(dout[78:71]) - ); - */ - randluts #(.N(150)) randluts ( - .din(din[41:34]), - .dout(dout[78:71]) - ); -endmodule - -module randluts(input [7:0] din, output [7:0] dout); - parameter integer N = 250; - - function [31:0] xorshift32(input [31:0] xorin); - begin - xorshift32 = xorin; - xorshift32 = xorshift32 ^ (xorshift32 << 13); - xorshift32 = xorshift32 ^ (xorshift32 >> 17); - xorshift32 = xorshift32 ^ (xorshift32 << 5); - end - endfunction - - function [63:0] lutinit(input [7:0] a, b); - begin - lutinit[63:32] = xorshift32(xorshift32(xorshift32(xorshift32({a, b} ^ `SEED)))); - lutinit[31: 0] = xorshift32(xorshift32(xorshift32(xorshift32({b, a} ^ `SEED)))); - end - endfunction - - wire [(N+1)*8-1:0] nets; - - assign nets[7:0] = din; - assign dout = nets[(N+1)*8-1:N*8]; - - genvar i, j; - generate - for (i = 0; i < N; i = i+1) begin:is - for (j = 0; j < 8; j = j+1) begin:js - localparam integer k = xorshift32(xorshift32(xorshift32(xorshift32((i << 20) ^ (j << 10) ^ `SEED)))) & 255; - (* KEEP, DONT_TOUCH *) - LUT6 #( - .INIT(lutinit(i, j)) - ) lut ( - .I0(nets[8*i+(k+0)%8]), - .I1(nets[8*i+(k+1)%8]), - .I2(nets[8*i+(k+2)%8]), - .I3(nets[8*i+(k+3)%8]), - .I4(nets[8*i+(k+4)%8]), - .I5(nets[8*i+(k+5)%8]), - .O(nets[8*i+8+j]) - ); - end - end - endgenerate -endmodule diff --git a/fuzzers/007-timing/minitest/test_unique/wire_unique.py b/fuzzers/007-timing/minitest/test_unique/wire_unique.py deleted file mode 100644 index 2f4cc339..00000000 --- a/fuzzers/007-timing/minitest/test_unique/wire_unique.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env python3 - -import re - - -def gen_wires(fin): - for l in fin: - lj = {} - l = l.strip() - for kvs in l.split(): - name, value = kvs.split(':') - lj[name] = value - - tile_type, xy, wname = re.match( - r'(.*)_(X[0-9]*Y[0-9]*)/(.*)', lj['NAME']).groups() - lj['tile_type'] = tile_type - lj['xy'] = xy - lj['wname'] = wname - - lj['l'] = l - - yield lj - - -def run(node_fin, verbose=0): - refnodes = {} - nodei = 0 - for nodei, anode in enumerate(gen_wires(node_fin)): - - def getk(anode): - return anode['wname'] - #return (anode['tile_type'], anode['wname']) - - if nodei % 100000 == 0: - print('Check node %d, %u node types' % (nodei, len(refnodes))) - # Existing node? - try: - refnode = refnodes[getk(anode)] - except KeyError: - # Set as reference - refnodes[getk(anode)] = anode - continue - k_invariant = ( - 'COST_CODE', - 'IS_INPUT_PIN', - 'IS_OUTPUT_PIN', - 'IS_PART_OF_BUS', - 'NUM_INTERSECTS', - 'NUM_TILE_PORTS', - 'SPEED_INDEX', - 'TILE_PATTERN_OFFSET', - ) - k_varies = ( - 'ID_IN_TILE_TYPE', - 'IS_CONNECTED', - 'NUM_DOWNHILL_PIPS', - 'NUM_PIPS', - 'NUM_UPHILL_PIPS', - 'TILE_NAME', - ) - # Verify equivilence - for k in k_invariant: - if k in refnode and k in anode: - - def fail(): - print('Mismatch on %s' % k) - print(refnode[k], anode[k]) - print(refnode['l']) - print(anode['l']) - #assert 0 - - if refnode[k] != anode[k]: - print - fail() - # A key in one but not the other? - elif k in refnode or k in anode: - assert 0 - elif k not in k_varies: - assert 0 - - -if __name__ == '__main__': - import argparse - - parser = argparse.ArgumentParser( - description= - 'Determines which info is consistent across wires with the same name') - - parser.add_argument('--verbose', type=int, help='') - parser.add_argument( - 'node_fn_in', - default='specimen_001/wire_all.txt', - nargs='?', - help='Input file') - args = parser.parse_args() - run(open(args.node_fn_in, 'r'), verbose=args.verbose) diff --git a/fuzzers/007-timing/minitest/test_zero/README.md b/fuzzers/007-timing/minitest/test_zero/README.md deleted file mode 100644 index ef5ea1e4..00000000 --- a/fuzzers/007-timing/minitest/test_zero/README.md +++ /dev/null @@ -1 +0,0 @@ -Collect info on ZERO speed classes diff --git a/fuzzers/007-timing/minitest/test_zero/process.py b/fuzzers/007-timing/minitest/test_zero/process.py deleted file mode 100644 index 3b2ce10c..00000000 --- a/fuzzers/007-timing/minitest/test_zero/process.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import os -import time -import json - - -def run_types(tilej, verbose=False): - def process(etype): - # dict[model] = set((tile, wire/pip)) - zeros = {} - print('Processing %s' % etype) - # Index delay models by type, recording where they occured - for tilek, tilev in tilej['tiles'].items(): - for ename, emodel in tilev[etype].items(): - if emodel.find('ZERO') >= 0: - zeros.setdefault(emodel, set()).add((tilek, ename)) - # Print out delay model instances - print('%s ZERO types: %u, %s' % (etype, len(zeros), zeros.keys())) - print( - '%s ZERO instances: %u' % - (etype, sum([len(x) for x in zeros.values()]))) - for model in sorted(zeros.keys()): - modelv = zeros[model] - print('Model: %s' % model) - for tile_name, element_name in sorted(list(modelv)): - print(' %s: %s' % (tile_name, element_name)) - - process('wires') - print('') - process('pips') - - -def run_prefix(tilej, verbose=False): - def process(etype): - prefixes = set() - print('Processing %s' % etype) - # Index delay models by type, recording where they occured - for tilek, tilev in tilej['tiles'].items(): - for ename, emodel in tilev[etype].items(): - prefix = emodel.split('_')[0] - prefixes.add(prefix) - print('%s prefixes: %u' % (etype, len(prefixes))) - for prefix in sorted(prefixes): - print(' %s' % prefix) - - process('wires') - print('') - process('pips') - - -def run(fnin, verbose=False): - tilej = json.load((open(fnin, 'r'))) - run_types(tilej) - print('') - print('') - run_prefix(tilej) - - -def main(): - import argparse - - parser = argparse.ArgumentParser(description='Solve timing solution') - parser.add_argument( - 'fnin', - default="../timgrid/build/timgrid-s.json", - nargs='?', - help='input timgrid JSON') - args = parser.parse_args() - - run(args.fnin, verbose=False) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/projects/.gitignore b/fuzzers/007-timing/projects/.gitignore deleted file mode 100644 index 374eddc2..00000000 --- a/fuzzers/007-timing/projects/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -specimen_* -build - diff --git a/fuzzers/007-timing/projects/Makefile b/fuzzers/007-timing/projects/Makefile deleted file mode 100644 index eb1f30a9..00000000 --- a/fuzzers/007-timing/projects/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -all: - echo "FIXME: tie projects together" - false - diff --git a/fuzzers/007-timing/projects/corner.mk b/fuzzers/007-timing/projects/corner.mk deleted file mode 100644 index d7b27a83..00000000 --- a/fuzzers/007-timing/projects/corner.mk +++ /dev/null @@ -1,57 +0,0 @@ -# Run corner specific calculations - -TIMFUZ_DIR=$(XRAY_DIR)/fuzzers/007-timing -CORNER=slow_max -ALLOW_ZERO_EQN?=N -BADPRJ_OK?=N -BUILD_DIR?=build/MUST_SET -CSV_BASENAME=timing4i.csv - -all: $(BUILD_DIR)/$(CORNER)/timgrid-vc.json $(BUILD_DIR)/$(CORNER)/qor.txt - -run: - $(MAKE) clean - $(MAKE) all - touch run.ok - -clean: - rm -rf $(BUILD_DIR)/$(CORNER) - -.PHONY: all run clean - -$(BUILD_DIR)/$(CORNER): - mkdir -p $(BUILD_DIR)/$(CORNER) - -# parent should have built this -$(BUILD_DIR)/checksub: - false - -$(BUILD_DIR)/$(CORNER)/leastsq.csv: $(BUILD_DIR)/sub.json $(BUILD_DIR)/grouped.csv $(BUILD_DIR)/checksub $(BUILD_DIR)/$(CORNER) - # Create a rough timing model that approximately fits the given paths - python3 $(TIMFUZ_DIR)/solve_leastsq.py $(BUILD_DIR)/grouped.csv --corner $(CORNER) --out $(BUILD_DIR)/$(CORNER)/leastsq.csv.tmp - mv $(BUILD_DIR)/$(CORNER)/leastsq.csv.tmp $(BUILD_DIR)/$(CORNER)/leastsq.csv - -$(BUILD_DIR)/$(CORNER)/linprog.csv: $(BUILD_DIR)/$(CORNER)/leastsq.csv $(BUILD_DIR)/grouped.csv - # Tweak rough timing model, making sure all constraints are satisfied - ALLOW_ZERO_EQN=$(ALLOW_ZERO_EQN) python3 $(TIMFUZ_DIR)/solve_linprog.py --bounds-csv $(BUILD_DIR)/$(CORNER)/leastsq.csv --massage $(BUILD_DIR)/grouped.csv --corner $(CORNER) --out $(BUILD_DIR)/$(CORNER)/linprog.csv.tmp - mv $(BUILD_DIR)/$(CORNER)/linprog.csv.tmp $(BUILD_DIR)/$(CORNER)/linprog.csv - -$(BUILD_DIR)/$(CORNER)/flat.csv: $(BUILD_DIR)/$(CORNER)/linprog.csv - # Take separated variables and back-annotate them to the original timing variables - python3 $(TIMFUZ_DIR)/csv_group2flat.py --sub-json $(BUILD_DIR)/sub.json --corner $(CORNER) --out $(BUILD_DIR)/$(CORNER)/flat.csv.tmp $(BUILD_DIR)/$(CORNER)/linprog.csv - mv $(BUILD_DIR)/$(CORNER)/flat.csv.tmp $(BUILD_DIR)/$(CORNER)/flat.csv - -$(BUILD_DIR)/$(CORNER)/timgrid-vc.json: $(BUILD_DIR)/$(CORNER)/flat.csv - # Final processing - # Insert timing delays into actual tile layouts - python3 $(TIMFUZ_DIR)/tile_annotate.py --timgrid-s $(TIMFUZ_DIR)/timgrid/build/timgrid-s.json --out $(BUILD_DIR)/$(CORNER)/timgrid-vc.json $(BUILD_DIR)/$(CORNER)/flat.csv - -$(BUILD_DIR)/$(CORNER)/qor.txt: $(BUILD_DIR)/$(CORNER)/flat.csv -ifeq ($(SOLVING),i) - python3 $(TIMFUZ_DIR)/solve_qor.py --corner $(CORNER) --bounds-csv $(BUILD_DIR)/$(CORNER)/flat.csv specimen_*/timing4i.csv >$(BUILD_DIR)/$(CORNER)/qor.txt.tmp - mv $(BUILD_DIR)/$(CORNER)/qor.txt.tmp $(BUILD_DIR)/$(CORNER)/qor.txt -else - # FIXME - touch $(BUILD_DIR)/$(CORNER)/qor.txt -endif - diff --git a/fuzzers/007-timing/projects/generate.sh b/fuzzers/007-timing/projects/generate.sh deleted file mode 100644 index a43fadcf..00000000 --- a/fuzzers/007-timing/projects/generate.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -source ${XRAY_GENHEADER} -TIMFUZ_DIR=$XRAY_DIR/fuzzers/007-timing - -timing_txt2csv () { - python3 $TIMFUZ_DIR/timing_txt2icsv.py --speed-json $TIMFUZ_DIR/speed/build/speed.json --out timing4i.csv.tmp timing4.txt - mv timing4i.csv.tmp timing4i.csv - - python3 $TIMFUZ_DIR/timing_txt2scsv.py --speed-json $TIMFUZ_DIR/speed/build/speed.json --out timing4s.csv.tmp timing4.txt - mv timing4s.csv.tmp timing4s.csv - - # delete really large file, see https://github.com/SymbiFlow/prjxray/issues/137 - rm timing4.txt -} - diff --git a/fuzzers/007-timing/projects/is.mk b/fuzzers/007-timing/projects/is.mk deleted file mode 100644 index 5c419487..00000000 --- a/fuzzers/007-timing/projects/is.mk +++ /dev/null @@ -1,74 +0,0 @@ -# Interconnect and site (IS) high level aggregation -# Creates corner data and aggregates them together - -TIMFUZ_DIR=$(XRAY_DIR)/fuzzers/007-timing -SOLVING=i -CSV_BASENAME=timing4$(SOLVING).csv -BUILD_DIR?=build/MUST_SET -SPECIMENS := -CSVS := $(addsuffix /$(CSV_BASENAME),$(SPECIMENS)) -RREF_CORNER=slow_max - -# Set ZERO elements to zero delay (as is expected they should be) -RMZERO?=N - -RREF_ARGS= -ifeq ($(RMZERO),Y) -RREF_ARGS+=--rm-zero -endif - - -# FIXME: clean this up by generating targets from CORNERS - -# fast_max => build/i/fast_max/timgrid-vc.json -TIMGRID_VCS=$(BUILD_DIR)/fast_max/timgrid-vc.json $(BUILD_DIR)/fast_min/timgrid-vc.json $(BUILD_DIR)/slow_max/timgrid-vc.json $(BUILD_DIR)/slow_min/timgrid-vc.json -#TIMGRID_VCS=$(addsuffix /timgrid-vc.json,$(addprefix $(BUILD_DIR_I)/,$(CORNERS))) -# make $(BUILD_DIR)/checksub first -$(BUILD_DIR)/fast_max/timgrid-vc.json: $(BUILD_DIR)/checksub - $(MAKE) -f $(TIMFUZ_DIR)/projects/corner.mk CORNER=fast_max -$(BUILD_DIR)/fast_min/timgrid-vc.json: $(BUILD_DIR)/checksub - $(MAKE) -f $(TIMFUZ_DIR)/projects/corner.mk CORNER=fast_min -$(BUILD_DIR)/slow_max/timgrid-vc.json: $(BUILD_DIR)/checksub - $(MAKE) -f $(TIMFUZ_DIR)/projects/corner.mk CORNER=slow_max -$(BUILD_DIR)/slow_min/timgrid-vc.json: $(BUILD_DIR)/checksub - $(MAKE) -f $(TIMFUZ_DIR)/projects/corner.mk CORNER=slow_min - - -# Normally require all projects to complete -# If BADPRJ_OK is allowed, only take projects that were successful -# FIXME: couldn't get call to work -exist_csvs = \ - for f in $(CSVS); do \ - if [ "$(BADPRJ_OK)" != 'Y' -o -f $$f ] ; then \ - echo $$f; \ - fi; \ - done - -all: $(BUILD_DIR)/timgrid-v.json - -# rref should be the same regardless of corner -$(BUILD_DIR)/sub.json: $(SPECIMENS_OK) - mkdir -p $(BUILD_DIR) - # Discover which variables can be separated - # This is typically the longest running operation - \ - csvs=$$(for f in $(CSVS); do if [ "$(BADPRJ_OK)" != 'Y' -o -f $$f ] ; then echo $$f; fi; done) ; \ - echo $$csvs ; \ - python3 $(TIMFUZ_DIR)/rref.py --corner $(RREF_CORNER) --simplify $(RREF_ARGS) --out $(BUILD_DIR)/sub.json.tmp $$csvs - mv $(BUILD_DIR)/sub.json.tmp $(BUILD_DIR)/sub.json - -$(BUILD_DIR)/grouped.csv: $(SPECIMENS_OK) $(BUILD_DIR)/sub.json - # Separate variables - \ - csvs=$$(for f in $(CSVS); do if [ "$(BADPRJ_OK)" != 'Y' -o -f $$f ] ; then echo $$f; fi; done) ; \ - python3 $(TIMFUZ_DIR)/csv_flat2group.py --sub-json $(BUILD_DIR)/sub.json --strict --out $(BUILD_DIR)/grouped.csv.tmp $$csvs - mv $(BUILD_DIR)/grouped.csv.tmp $(BUILD_DIR)/grouped.csv - -$(BUILD_DIR)/checksub: $(BUILD_DIR)/grouped.csv $(BUILD_DIR)/sub.json - # Verify sub.json makes a cleanly solvable solution with no non-pivot leftover - python3 $(TIMFUZ_DIR)/checksub.py --sub-json $(BUILD_DIR)/sub.json $(BUILD_DIR)/grouped.csv - touch $(BUILD_DIR)/checksub - -$(BUILD_DIR)/timgrid-v.json: $(TIMGRID_VCS) - python3 $(TIMFUZ_DIR)/timgrid_vc2v.py --out $(BUILD_DIR)/timgrid-v.json $(TIMGRID_VCS) - diff --git a/fuzzers/007-timing/projects/oneblinkw/Makefile b/fuzzers/007-timing/projects/oneblinkw/Makefile deleted file mode 100644 index 5e5721b7..00000000 --- a/fuzzers/007-timing/projects/oneblinkw/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# so simple that likely no linprog adjustments will be needed -ALLOW_ZERO_EQN?=Y -include ../project.mk - diff --git a/fuzzers/007-timing/projects/oneblinkw/README.md b/fuzzers/007-timing/projects/oneblinkw/README.md deleted file mode 100644 index ae7cac37..00000000 --- a/fuzzers/007-timing/projects/oneblinkw/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Minimal, simple test - diff --git a/fuzzers/007-timing/projects/oneblinkw/generate.sh b/fuzzers/007-timing/projects/oneblinkw/generate.sh deleted file mode 100755 index ee551b74..00000000 --- a/fuzzers/007-timing/projects/oneblinkw/generate.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -ex -source ../generate.sh - -${XRAY_VIVADO} -mode batch -source ../generate.tcl -timing_txt2csv - diff --git a/fuzzers/007-timing/projects/oneblinkw/generate.tcl b/fuzzers/007-timing/projects/oneblinkw/generate.tcl deleted file mode 100644 index 14b86cb1..00000000 --- a/fuzzers/007-timing/projects/oneblinkw/generate.tcl +++ /dev/null @@ -1,45 +0,0 @@ -source ../../../../../utils/utils.tcl -source ../../project.tcl - -proc build_design {} { - create_project -force -part $::env(XRAY_PART) design design - read_verilog ../top.v - synth_design -top top - - puts "Locking pins" - set_property LOCK_PINS {I0:A1 I1:A2 I2:A3 I3:A4 I4:A5 I5:A6} \ - [get_cells -quiet -filter {REF_NAME == LUT6} -hierarchical] - - puts "Package stuff" - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports stb] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports di] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports do] - - puts "pblocking" - create_pblock roi - set roipb [get_pblocks roi] - add_cells_to_pblock $roipb [get_cells roi] - resize_pblock $roipb -add "$::env(XRAY_ROI)" - - puts "randplace" - #randplace_pblock 50 roi - - set_property CFGBVS VCCO [current_design] - set_property CONFIG_VOLTAGE 3.3 [current_design] - set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] - - puts "dedicated route" - set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] - - place_design - route_design - - write_checkpoint -force design.dcp - # disable combinitorial loop - # set_property IS_ENABLED 0 [get_drc_checks {LUTLP-1}] - #write_bitstream -force design.bit -} - -build_design -write_info4 diff --git a/fuzzers/007-timing/projects/oneblinkw/top.v b/fuzzers/007-timing/projects/oneblinkw/top.v deleted file mode 100644 index 5e133bac..00000000 --- a/fuzzers/007-timing/projects/oneblinkw/top.v +++ /dev/null @@ -1,37 +0,0 @@ -module roi ( - input wire clk, - output wire out); - reg [23:0] counter; - assign out = counter[23] ^ counter[22] ^ counter[2] && counter[1] || counter[0]; - - always @(posedge clk) begin - counter <= counter + 1; - end -endmodule - -module top(input wire clk, input wire stb, input wire di, output wire do); - localparam integer DIN_N = 0; - localparam integer DOUT_N = 1; - - reg [DIN_N-1:0] din; - wire [DOUT_N-1:0] dout; - - reg [DIN_N-1:0] din_shr; - reg [DOUT_N-1:0] dout_shr; - - always @(posedge clk) begin - din_shr <= {din_shr, di}; - dout_shr <= {dout_shr, din_shr[DIN_N-1]}; - if (stb) begin - din <= din_shr; - dout_shr <= dout; - end - end - - assign do = dout_shr[DOUT_N-1]; - roi roi( - .clk(clk), - .out(dout[0]) - ); -endmodule - diff --git a/fuzzers/007-timing/projects/picorv32/Makefile b/fuzzers/007-timing/projects/picorv32/Makefile deleted file mode 100644 index 9c8b1947..00000000 --- a/fuzzers/007-timing/projects/picorv32/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -include ../project.mk - diff --git a/fuzzers/007-timing/projects/picorv32/README.md b/fuzzers/007-timing/projects/picorv32/README.md deleted file mode 100644 index 0be27709..00000000 --- a/fuzzers/007-timing/projects/picorv32/README.md +++ /dev/null @@ -1,3 +0,0 @@ -picorv32 uses more advanced structures than simple LUT/FF tests (such as carry chain) -It attempts to provide some realistic timing data wrt fanout and used fabric - diff --git a/fuzzers/007-timing/projects/picorv32/generate.sh b/fuzzers/007-timing/projects/picorv32/generate.sh deleted file mode 100755 index ee551b74..00000000 --- a/fuzzers/007-timing/projects/picorv32/generate.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -ex -source ../generate.sh - -${XRAY_VIVADO} -mode batch -source ../generate.tcl -timing_txt2csv - diff --git a/fuzzers/007-timing/projects/picorv32/generate.tcl b/fuzzers/007-timing/projects/picorv32/generate.tcl deleted file mode 100644 index 8e710ce3..00000000 --- a/fuzzers/007-timing/projects/picorv32/generate.tcl +++ /dev/null @@ -1,46 +0,0 @@ -source ../../../../../utils/utils.tcl -source ../../project.tcl - -proc build_design {} { - create_project -force -part $::env(XRAY_PART) design design - read_verilog ../../../src/picorv32.v - read_verilog ../top.v - synth_design -top top - - puts "Locking pins" - set_property LOCK_PINS {I0:A1 I1:A2 I2:A3 I3:A4 I4:A5 I5:A6} \ - [get_cells -quiet -filter {REF_NAME == LUT6} -hierarchical] - - puts "Package stuff" - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports stb] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports di] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports do] - - puts "pblocking" - create_pblock roi - set roipb [get_pblocks roi] - add_cells_to_pblock $roipb [get_cells roi] - resize_pblock $roipb -add "$::env(XRAY_ROI)" - - puts "randplace" - randplace_pblock 50 roi - - set_property CFGBVS VCCO [current_design] - set_property CONFIG_VOLTAGE 3.3 [current_design] - set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] - - puts "dedicated route" - set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] - - place_design - route_design - - write_checkpoint -force design.dcp - # disable combinitorial loop - # set_property IS_ENABLED 0 [get_drc_checks {LUTLP-1}] - #write_bitstream -force design.bit -} - -build_design -write_info4 diff --git a/fuzzers/007-timing/projects/picorv32/top.v b/fuzzers/007-timing/projects/picorv32/top.v deleted file mode 100644 index 0cb9b8a3..00000000 --- a/fuzzers/007-timing/projects/picorv32/top.v +++ /dev/null @@ -1,109 +0,0 @@ -//move some stuff to minitests/ncy0 - -`define SEED 32'h12345678 - -module top(input clk, stb, di, output do); - localparam integer DIN_N = 42; - localparam integer DOUT_N = 79; - - reg [DIN_N-1:0] din; - wire [DOUT_N-1:0] dout; - - reg [DIN_N-1:0] din_shr; - reg [DOUT_N-1:0] dout_shr; - - always @(posedge clk) begin - din_shr <= {din_shr, di}; - dout_shr <= {dout_shr, din_shr[DIN_N-1]}; - if (stb) begin - din <= din_shr; - dout_shr <= dout; - end - end - - assign do = dout_shr[DOUT_N-1]; - - roi #(.DIN_N(DIN_N), .DOUT_N(DOUT_N)) - roi ( - .clk(clk), - .din(din), - .dout(dout) - ); -endmodule - -module roi(input clk, input [DIN_N-1:0] din, output [DOUT_N-1:0] dout); - parameter integer DIN_N = -1; - parameter integer DOUT_N = -1; - - /* - //Take out for now to make sure LUTs are more predictable - picorv32 picorv32 ( - .clk(clk), - .resetn(din[0]), - .mem_valid(dout[0]), - .mem_instr(dout[1]), - .mem_ready(din[1]), - .mem_addr(dout[33:2]), - .mem_wdata(dout[66:34]), - .mem_wstrb(dout[70:67]), - .mem_rdata(din[33:2]) - ); - */ - - /* - randluts randluts ( - .din(din[41:34]), - .dout(dout[78:71]) - ); - */ - randluts #(.N(150)) randluts ( - .din(din[41:34]), - .dout(dout[78:71]) - ); -endmodule - -module randluts(input [7:0] din, output [7:0] dout); - parameter integer N = 250; - - function [31:0] xorshift32(input [31:0] xorin); - begin - xorshift32 = xorin; - xorshift32 = xorshift32 ^ (xorshift32 << 13); - xorshift32 = xorshift32 ^ (xorshift32 >> 17); - xorshift32 = xorshift32 ^ (xorshift32 << 5); - end - endfunction - - function [63:0] lutinit(input [7:0] a, b); - begin - lutinit[63:32] = xorshift32(xorshift32(xorshift32(xorshift32({a, b} ^ `SEED)))); - lutinit[31: 0] = xorshift32(xorshift32(xorshift32(xorshift32({b, a} ^ `SEED)))); - end - endfunction - - wire [(N+1)*8-1:0] nets; - - assign nets[7:0] = din; - assign dout = nets[(N+1)*8-1:N*8]; - - genvar i, j; - generate - for (i = 0; i < N; i = i+1) begin:is - for (j = 0; j < 8; j = j+1) begin:js - localparam integer k = xorshift32(xorshift32(xorshift32(xorshift32((i << 20) ^ (j << 10) ^ `SEED)))) & 255; - (* KEEP, DONT_TOUCH *) - LUT6 #( - .INIT(lutinit(i, j)) - ) lut ( - .I0(nets[8*i+(k+0)%8]), - .I1(nets[8*i+(k+1)%8]), - .I2(nets[8*i+(k+2)%8]), - .I3(nets[8*i+(k+3)%8]), - .I4(nets[8*i+(k+4)%8]), - .I5(nets[8*i+(k+5)%8]), - .O(nets[8*i+8+j]) - ); - end - end - endgenerate -endmodule diff --git a/fuzzers/007-timing/projects/placelut/Makefile b/fuzzers/007-timing/projects/placelut/Makefile deleted file mode 100644 index 9c8b1947..00000000 --- a/fuzzers/007-timing/projects/placelut/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -include ../project.mk - diff --git a/fuzzers/007-timing/projects/placelut/README.md b/fuzzers/007-timing/projects/placelut/README.md deleted file mode 100644 index 0df7e3f8..00000000 --- a/fuzzers/007-timing/projects/placelut/README.md +++ /dev/null @@ -1,2 +0,0 @@ -LUTs are physically laid out in an array and directly connected to a test pattern generator - diff --git a/fuzzers/007-timing/projects/placelut/generate.py b/fuzzers/007-timing/projects/placelut/generate.py deleted file mode 100644 index 68687f91..00000000 --- a/fuzzers/007-timing/projects/placelut/generate.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python - -import argparse - -parser = argparse.ArgumentParser(description='') -parser.add_argument('--sdx', default='8', help='') -parser.add_argument('--sdy', default='4', help='') -args = parser.parse_args() -''' -Generate in pairs -Fill up switchbox quad for now -Create random connections between the LUTs -See how much routing pressure we can generate - -Start with non-random connections to the LFSR for solver comparison - -Start at SLICE_X16Y102 -''' -SBASE = (16, 102) -SDX = int(args.sdx, 0) -SDY = int(args.sdy, 0) -nlut = 4 * SDX * SDY - -nin = 6 * nlut -nout = nlut - -print('//placelut simple') -print('//SBASE: %s' % (SBASE, )) -print('//SDX: %s' % (SDX, )) -print('//SDY: %s' % (SDX, )) -print('//nlut: %s' % (nlut, )) -print( - '''\ -module roi ( - input wire clk, - input wire [%u:0] ins, - output wire [%u:0] outs);''') % (nin - 1, nout - 1) - -ini = 0 -outi = 0 -for lutx in xrange(SBASE[0], SBASE[0] + SDX): - for luty in xrange(SBASE[1], SBASE[1] + SDY): - loc = "SLICE_X%uY%u" % (lutx, luty) - for belc in 'ABCD': - bel = '%c6LUT' % belc - print( - '''\ - - (* KEEP, DONT_TOUCH, LOC="%s", BEL="%s" *) - LUT6 #( - .INIT(64'hBAD1DEA_1DEADCE0) - ) %s (''') % (loc, bel, 'lut_x%uy%u_%c' % (lutx, luty, belc)) - for i in xrange(6): - print('''\ - .I%u(ins[%u]),''' % (i, ini)) - ini += 1 - print('''\ - .O(outs[%u]));''') % (outi, ) - outi += 1 -assert nin == ini -assert nout == outi - -print( - ''' -endmodule - -module top(input wire clk, input wire stb, input wire di, output wire do); - localparam integer DIN_N = %u; - localparam integer DOUT_N = %u; - - reg [DIN_N-1:0] din; - wire [DOUT_N-1:0] dout; - - reg [DIN_N-1:0] din_shr; - reg [DOUT_N-1:0] dout_shr; - - always @(posedge clk) begin - din_shr <= {din_shr, di}; - dout_shr <= {dout_shr, din_shr[DIN_N-1]}; - if (stb) begin - din <= din_shr; - dout_shr <= dout; - end - end - - assign do = dout_shr[DOUT_N-1]; - roi roi( - .clk(clk), - .ins(din), - .outs(dout) - ); -endmodule''') % (nin, nout) diff --git a/fuzzers/007-timing/projects/placelut/generate.sh b/fuzzers/007-timing/projects/placelut/generate.sh deleted file mode 100755 index 8afe86e4..00000000 --- a/fuzzers/007-timing/projects/placelut/generate.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -ex - -source ${XRAY_GENHEADER} -TIMFUZ_DIR=$XRAY_DIR/fuzzers/007-timing - -python3 ../generate.py --sdx 4 --sdy 4 >top.v -${XRAY_VIVADO} -mode batch -source ../generate.tcl -python3 $TIMFUZ_DIR/timing_txt2csv.py --speed-json $TIMFUZ_DIR/speed/build/speed.json --out timing4.csv timing4.txt - diff --git a/fuzzers/007-timing/projects/placelut/generate.tcl b/fuzzers/007-timing/projects/placelut/generate.tcl deleted file mode 100644 index 9997bfed..00000000 --- a/fuzzers/007-timing/projects/placelut/generate.tcl +++ /dev/null @@ -1,45 +0,0 @@ -source ../../../../../utils/utils.tcl -source ../../project.tcl - -proc build_design {} { - create_project -force -part $::env(XRAY_PART) design design - read_verilog top.v - synth_design -top top - - puts "Locking pins" - set_property LOCK_PINS {I0:A1 I1:A2 I2:A3 I3:A4 I4:A5 I5:A6} \ - [get_cells -quiet -filter {REF_NAME == LUT6} -hierarchical] - - puts "Package stuff" - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports stb] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports di] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports do] - - puts "pblocking" - create_pblock roi - set roipb [get_pblocks roi] - add_cells_to_pblock $roipb [get_cells roi] - resize_pblock $roipb -add "$::env(XRAY_ROI)" - - puts "randplace" - randplace_pblock 50 roi - - set_property CFGBVS VCCO [current_design] - set_property CONFIG_VOLTAGE 3.3 [current_design] - set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] - - puts "dedicated route" - set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] - - place_design - route_design - - write_checkpoint -force design.dcp - # disable combinitorial loop - # set_property IS_ENABLED 0 [get_drc_checks {LUTLP-1}] - #write_bitstream -force design.bit -} - -build_design -write_info4 diff --git a/fuzzers/007-timing/projects/placelut_fb/Makefile b/fuzzers/007-timing/projects/placelut_fb/Makefile deleted file mode 100644 index 9c8b1947..00000000 --- a/fuzzers/007-timing/projects/placelut_fb/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -include ../project.mk - diff --git a/fuzzers/007-timing/projects/placelut_fb/README.md b/fuzzers/007-timing/projects/placelut_fb/README.md deleted file mode 100644 index 1e597818..00000000 --- a/fuzzers/007-timing/projects/placelut_fb/README.md +++ /dev/null @@ -1,2 +0,0 @@ -LUTs are physically laid out in an array and connected to test pattern generator and fed back to other LUTs - diff --git a/fuzzers/007-timing/projects/placelut_fb/generate.py b/fuzzers/007-timing/projects/placelut_fb/generate.py deleted file mode 100644 index 8f22dd37..00000000 --- a/fuzzers/007-timing/projects/placelut_fb/generate.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python -''' -Note: vivado will (by default) fail bitgen DRC on LUT feedback loops -Looks like can probably be disabled, but we actually don't need a bitstream for timing analysis -''' - -import argparse -import random - -random.seed() - -parser = argparse.ArgumentParser(description='') -parser.add_argument('--sdx', default='8', help='') -parser.add_argument('--sdy', default='4', help='') -args = parser.parse_args() -''' -Generate in pairs -Fill up switchbox quad for now -Create random connections between the LUTs -See how much routing pressure we can generate - -Start with non-random connections to the LFSR for solver comparison - -Start at SLICE_X16Y102 -''' -SBASE = (16, 102) -SDX = int(args.sdx, 0) -SDY = int(args.sdy, 0) -nlut = 4 * SDX * SDY - -nin = 6 * nlut -nout = nlut - -print('//placelut w/ feedback') -print('//SBASE: %s' % (SBASE, )) -print('//SDX: %s' % (SDX, )) -print('//SDY: %s' % (SDX, )) -print('//nlut: %s' % (nlut, )) -print( - '''\ -module roi ( - input wire clk, - input wire [%u:0] ins, - output wire [%u:0] outs);''') % (nin - 1, nout - 1) - -ini = 0 -outi = 0 -for lutx in xrange(SBASE[0], SBASE[0] + SDX): - for luty in xrange(SBASE[1], SBASE[1] + SDY): - loc = "SLICE_X%uY%u" % (lutx, luty) - for belc in 'ABCD': - bel = '%c6LUT' % belc - print( - '''\ - - (* KEEP, DONT_TOUCH, LOC="%s", BEL="%s" *) - LUT6 #( - .INIT(64'hBAD1DEA_1DEADCE0) - ) %s (''') % (loc, bel, 'lut_x%uy%u_%c' % (lutx, luty, belc)) - for i in xrange(6): - if random.randint(0, 9) < 1: - wfrom = 'ins[%u]' % ini - ini += 1 - else: - wfrom = 'outs[%u]' % random.randint(0, nout - 1) - print('''\ - .I%u(%s),''' % (i, wfrom)) - print('''\ - .O(outs[%u]));''') % (outi, ) - outi += 1 -#assert nin == ini -assert nout == outi - -print( - ''' -endmodule - -module top(input wire clk, input wire stb, input wire di, output wire do); - localparam integer DIN_N = %u; - localparam integer DOUT_N = %u; - - reg [DIN_N-1:0] din; - wire [DOUT_N-1:0] dout; - - reg [DIN_N-1:0] din_shr; - reg [DOUT_N-1:0] dout_shr; - - always @(posedge clk) begin - din_shr <= {din_shr, di}; - dout_shr <= {dout_shr, din_shr[DIN_N-1]}; - if (stb) begin - din <= din_shr; - dout_shr <= dout; - end - end - - assign do = dout_shr[DOUT_N-1]; - roi roi( - .clk(clk), - .ins(din), - .outs(dout) - ); -endmodule''') % (nin, nout) diff --git a/fuzzers/007-timing/projects/placelut_fb/generate.sh b/fuzzers/007-timing/projects/placelut_fb/generate.sh deleted file mode 100755 index 560ff646..00000000 --- a/fuzzers/007-timing/projects/placelut_fb/generate.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -set -ex -source ../generate.sh - -python3 ../generate.py --sdx 4 --sdy 4 >top.v -${XRAY_VIVADO} -mode batch -source ../generate.tcl -timing_txt2csv - diff --git a/fuzzers/007-timing/projects/placelut_fb/generate.tcl b/fuzzers/007-timing/projects/placelut_fb/generate.tcl deleted file mode 100644 index 9997bfed..00000000 --- a/fuzzers/007-timing/projects/placelut_fb/generate.tcl +++ /dev/null @@ -1,45 +0,0 @@ -source ../../../../../utils/utils.tcl -source ../../project.tcl - -proc build_design {} { - create_project -force -part $::env(XRAY_PART) design design - read_verilog top.v - synth_design -top top - - puts "Locking pins" - set_property LOCK_PINS {I0:A1 I1:A2 I2:A3 I3:A4 I4:A5 I5:A6} \ - [get_cells -quiet -filter {REF_NAME == LUT6} -hierarchical] - - puts "Package stuff" - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports stb] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports di] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports do] - - puts "pblocking" - create_pblock roi - set roipb [get_pblocks roi] - add_cells_to_pblock $roipb [get_cells roi] - resize_pblock $roipb -add "$::env(XRAY_ROI)" - - puts "randplace" - randplace_pblock 50 roi - - set_property CFGBVS VCCO [current_design] - set_property CONFIG_VOLTAGE 3.3 [current_design] - set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] - - puts "dedicated route" - set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] - - place_design - route_design - - write_checkpoint -force design.dcp - # disable combinitorial loop - # set_property IS_ENABLED 0 [get_drc_checks {LUTLP-1}] - #write_bitstream -force design.bit -} - -build_design -write_info4 diff --git a/fuzzers/007-timing/projects/placelut_ff_fb/Makefile b/fuzzers/007-timing/projects/placelut_ff_fb/Makefile deleted file mode 100644 index 9c8b1947..00000000 --- a/fuzzers/007-timing/projects/placelut_ff_fb/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -include ../project.mk - diff --git a/fuzzers/007-timing/projects/placelut_ff_fb/README.md b/fuzzers/007-timing/projects/placelut_ff_fb/README.md deleted file mode 100644 index 983849b3..00000000 --- a/fuzzers/007-timing/projects/placelut_ff_fb/README.md +++ /dev/null @@ -1,3 +0,0 @@ -LUTs are physically laid out in an array and connected to test pattern generator and fed back to other LUTs. -FFs are randomly inserted between connections. - diff --git a/fuzzers/007-timing/projects/placelut_ff_fb/generate.py b/fuzzers/007-timing/projects/placelut_ff_fb/generate.py deleted file mode 100644 index 410e995f..00000000 --- a/fuzzers/007-timing/projects/placelut_ff_fb/generate.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python -''' -Note: vivado will (by default) fail bitgen DRC on LUT feedback loops -Looks like can probably be disabled, but we actually don't need a bitstream for timing analysis - -ERROR: [Vivado 12-2285] Cannot set LOC property of instance 'roi/lut_x22y102_D', Instance roi/lut_x22y102_D can not be placed in D6LUT of site SLICE_X18Y103 because the bel is occupied by roi/lut_x18y103_D(port:). This could be caused by bel constraint conflict -Resolution: When using BEL constraints, ensure the BEL constraints are defined before the LOC constraints to avoid conflicts at a given site. - -''' - -import argparse -import random - -random.seed() - -parser = argparse.ArgumentParser(description='') -parser.add_argument('--sdx', default='8', help='') -parser.add_argument('--sdy', default='4', help='') -args = parser.parse_args() -''' -Generate in pairs -Fill up switchbox quad for now -Create random connections between the LUTs -See how much routing pressure we can generate - -Start with non-random connections to the LFSR for solver comparison - -Start at SLICE_X16Y102 -''' -SBASE = (16, 102) -SDX = int(args.sdx, 0) -SDY = int(args.sdy, 0) -nlut = 4 * SDX * SDY - -nin = 6 * nlut -nout = nlut - -print('//placelut w/ FF + feedback') -print('//SBASE: %s' % (SBASE, )) -print('//SDX: %s' % (SDX, )) -print('//SDY: %s' % (SDX, )) -print('//nlut: %s' % (nlut, )) -print( - '''\ -module roi ( - input wire clk, - input wire [%u:0] ins, - output wire [%u:0] outs);''') % (nin - 1, nout - 1) - -ini = 0 -outi = 0 -for lutx in xrange(SBASE[0], SBASE[0] + SDX): - for luty in xrange(SBASE[1], SBASE[1] + SDY): - loc = "SLICE_X%uY%u" % (lutx, luty) - for belc in 'ABCD': - bel = '%c6LUT' % belc - name = 'lut_x%uy%u_%c' % (lutx, luty, belc) - print( - '''\ - - (* KEEP, DONT_TOUCH, LOC="%s", BEL="%s" *) - LUT6 #( - .INIT(64'hBAD1DEA_1DEADCE0) - ) %s (''') % (loc, bel, name) - for i in xrange(6): - rval = random.randint(0, 9) - if rval < 3: - wfrom = 'ins[%u]' % ini - ini += 1 - #elif rval < 6: - # wfrom = 'outsr[%u]' % random.randint(0, nout - 1) - else: - wfrom = 'outs[%u]' % random.randint(0, nout - 1) - print('''\ - .I%u(%s),''' % (i, wfrom)) - out_w = name + '_o' - print('''\ - .O(%s));''') % (out_w, ) - - outs_w = "outs[%u]" % outi - if random.randint(0, 9) < 5: - print(' assign %s = %s;' % (outs_w, out_w)) - else: - out_r = name + '_or' - print( - '''\ - reg %s; - assign %s = %s; - always @(posedge clk) begin - %s = %s; - end - ''' % (out_r, outs_w, out_r, out_r, out_w)) - outi += 1 - -#assert nin == ini -assert nout == outi - -print( - ''' -endmodule - -module top(input wire clk, input wire stb, input wire di, output wire do); - localparam integer DIN_N = %u; - localparam integer DOUT_N = %u; - - reg [DIN_N-1:0] din; - wire [DOUT_N-1:0] dout; - - reg [DIN_N-1:0] din_shr; - reg [DOUT_N-1:0] dout_shr; - - always @(posedge clk) begin - din_shr <= {din_shr, di}; - dout_shr <= {dout_shr, din_shr[DIN_N-1]}; - if (stb) begin - din <= din_shr; - dout_shr <= dout; - end - end - - assign do = dout_shr[DOUT_N-1]; - roi roi( - .clk(clk), - .ins(din), - .outs(dout) - ); -endmodule''') % (nin, nout) diff --git a/fuzzers/007-timing/projects/placelut_ff_fb/generate.sh b/fuzzers/007-timing/projects/placelut_ff_fb/generate.sh deleted file mode 100755 index 560ff646..00000000 --- a/fuzzers/007-timing/projects/placelut_ff_fb/generate.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -set -ex -source ../generate.sh - -python3 ../generate.py --sdx 4 --sdy 4 >top.v -${XRAY_VIVADO} -mode batch -source ../generate.tcl -timing_txt2csv - diff --git a/fuzzers/007-timing/projects/placelut_ff_fb/generate.tcl b/fuzzers/007-timing/projects/placelut_ff_fb/generate.tcl deleted file mode 100644 index 9997bfed..00000000 --- a/fuzzers/007-timing/projects/placelut_ff_fb/generate.tcl +++ /dev/null @@ -1,45 +0,0 @@ -source ../../../../../utils/utils.tcl -source ../../project.tcl - -proc build_design {} { - create_project -force -part $::env(XRAY_PART) design design - read_verilog top.v - synth_design -top top - - puts "Locking pins" - set_property LOCK_PINS {I0:A1 I1:A2 I2:A3 I3:A4 I4:A5 I5:A6} \ - [get_cells -quiet -filter {REF_NAME == LUT6} -hierarchical] - - puts "Package stuff" - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports stb] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports di] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports do] - - puts "pblocking" - create_pblock roi - set roipb [get_pblocks roi] - add_cells_to_pblock $roipb [get_cells roi] - resize_pblock $roipb -add "$::env(XRAY_ROI)" - - puts "randplace" - randplace_pblock 50 roi - - set_property CFGBVS VCCO [current_design] - set_property CONFIG_VOLTAGE 3.3 [current_design] - set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] - - puts "dedicated route" - set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] - - place_design - route_design - - write_checkpoint -force design.dcp - # disable combinitorial loop - # set_property IS_ENABLED 0 [get_drc_checks {LUTLP-1}] - #write_bitstream -force design.bit -} - -build_design -write_info4 diff --git a/fuzzers/007-timing/projects/project.mk b/fuzzers/007-timing/projects/project.mk deleted file mode 100644 index f21f803e..00000000 --- a/fuzzers/007-timing/projects/project.mk +++ /dev/null @@ -1,55 +0,0 @@ -# project.mk: build specimens (run vivado), compute rref -# corner.mk: run corner specific calculations - -N := 1 -SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N))) -SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) -TIMFUZ_DIR=$(XRAY_DIR)/fuzzers/007-timing -# Allow an empty system of equations? -# for testing only on small projects -ALLOW_ZERO_EQN?=N -# Constrained projects may fail to build -# Set to Y to make a best effort to suck in the ones that did build -BADPRJ_OK?=N -BUILD_DIR?=build -# interconnect -BUILD_DIR_I?=$(BUILD_DIR)/i -# site -BUILD_DIR_S?=$(BUILD_DIR)/s - -CORNERS=fast_max fast_min slow_max slow_min - -TIMGRID_V_I=$(BUILD_DIR_I)/timgrid-v.json -TIMGRID_V_S=$(BUILD_DIR_S)/timgrid-v.json - -all: $(BUILD_DIR)/timgrid-v.json - -$(SPECIMENS_OK): - bash generate.sh $(subst /OK,,$@) || (if [ "$(BADPRJ_OK)" != 'Y' ] ; then exit 1; fi; exit 0) - touch $@ - -run: - $(MAKE) clean - $(MAKE) all - touch run.ok - -clean: - rm -rf specimen_[0-9][0-9][0-9]/ seg_clblx.segbits __pycache__ run.ok - rm -rf vivado*.log vivado_*.str vivado*.jou design *.bits *.dcp *.bit - rm -rf $(BUILD_DIR) - -.PHONY: all run clean - -$(TIMGRID_V_I): $(SPECIMENS_OK) - $(MAKE) -f $(TIMFUZ_DIR)/projects/is.mk BUILD_DIR=$(BUILD_DIR_I) SOLVING=i SPECIMENS=$(SPECIMENS) all -i: $(TIMGRID_V_I) - -$(TIMGRID_V_S): $(SPECIMENS_OK) - $(MAKE) -f $(TIMFUZ_DIR)/projects/is.mk BUILD_DIR=$(BUILD_DIR_S) SOLVING=s SPECIMENS=$(SPECIMENS) all -s: $(TIMGRID_V_S) - -.PHONY: i s - -$(BUILD_DIR)/timgrid-v.json: $(TIMGRID_V_I) $(TIMGRID_V_S) - python3 $(TIMFUZ_DIR)/timgrid_vc2v.py --out $(BUILD_DIR)/timgrid-v.json $(TIMGRID_V_I) $(TIMGRID_V_S) - diff --git a/fuzzers/007-timing/projects/project.tcl b/fuzzers/007-timing/projects/project.tcl deleted file mode 100644 index 26be8067..00000000 --- a/fuzzers/007-timing/projects/project.tcl +++ /dev/null @@ -1,221 +0,0 @@ -# General notes: -# Observed nets with 1 to 2 source cell pins -# 2 example -# [get_pins -filter {DIRECTION == OUT} -of_objects $net] -# roi/dout_shr[0]_i_1/O: BEL, visible -# roi/dout_shr_reg[0]: no BEL, not visible, named after the net -# I don't understand what the relationship between these two is -# Maybe register retiming? -# Observed nets with 0 to 1 source bel pins -# 0 example: -# Recommendation: assume there is at most one source BEL -# Take that as the source BEL if it exists, otherwise don't do any source analysis - -# get_timing_paths vs get_net_delays -# get_timing_paths is built on top of get_net_delays? -# has some different info, but is fixed on the slow max corner -# *possibly* reports slightly better info within a site, but would need to verify that - -# Things safe to assume: -# -Each net has at least one delay? -# -Cell exists for every delay path -# -Each net has at least one destination BEL pin -# Things not safe to assume -# -Each net has at least one source BEL pin (ex: ) - - -proc list_format {l delim} { - set ret "" - set needspace 0 - foreach x $l { - if $needspace { - set ret "$ret$delim$x" - } else { - set ret "$x" - } - set needspace 1 - } - return $ret -} - -proc line_net_external {fp net src_site src_site_type src_site_pin src_bel src_bel_pin dst_site dst_site_type dst_site_pin dst_bel dst_bel_pin ico fast_max fast_min slow_max slow_min pips_out wires_out} { - puts $fp "NET,$net,$src_site,$src_site_type,$src_site_pin,$src_bel,$src_bel_pin,$dst_site,$dst_site_type,$dst_site_pin,$dst_bel,$dst_bel_pin,$ico,$fast_max,$fast_min,$slow_max,$slow_min,$pips_out,$wires_out" -} - -proc line_net_internal {fp net site site_type src_bel src_bel_pin dst_bel dst_bel_pin ico fast_max fast_min slow_max slow_min} { - set src_site $site - set src_site_type $site_type - set src_site_pin "" - - set dst_site $site - set dst_site_type $site_type - set dst_site_pin "" - - set pips_out "" - set wires_out "" - - puts $fp "NET,$net,$src_site,$src_site_type,$src_site_pin,$src_bel,$src_bel_pin,$dst_site,$dst_site_type,$dst_site_pin,$dst_bel,$dst_bel_pin,$ico,$fast_max,$fast_min,$slow_max,$slow_min,$pips_out,$wires_out" -} - -proc write_info4 {} { - set outdir "." - set fp [open "$outdir/timing4.txt" w] - # bel as site/bel, so don't bother with site - puts $fp "linetype,net,src_site,src_site_type,src_site_pin,src_bel,src_bel_pin,dst_site,dst_site_type,dst_site_pin,dst_bel,dst_bel_pin,ico,fast_max,fast_min,slow_max,slow_min,pips,wires" - - set TIME_start [clock clicks -milliseconds] - set delays_net 0 - set nets_no_src_cell 0 - set nets_no_src_bel 0 - set lines_no_int 0 - set lines_some_int 0 - set neti 0 - set nets [get_nets -hierarchical] - #set nets [get_nets clk] - #set nets [get_nets roi/counter[0]_i_2_n_0] - set nnets [llength $nets] - foreach net $nets { - incr neti - - puts "Net $neti / $nnets: $net" - - # there are some special places like on IOB where you may not have a cell source pin - # this is due to special treatment where BEL vs SITE are blurred - # The semantics of get_pins -leaf is kind of odd - # When no passthrough LUTs exist, it has no effect - # When passthrough LUT present: - # -w/o -leaf: some pins + passthrough LUT pins - # -w/ -leaf: different pins + passthrough LUT pins - # With OUT filter this seems to be sufficient - set src_cell_pins [get_pins -leaf -filter {DIRECTION == OUT} -of_objects $net] - if {$src_cell_pins eq ""} { - incr nets_no_src_cell - # ex: IOB internal bel net - puts " SKIP: no source cell" - continue - } - # 0 to 2 of these - # Seems when 2 of them they basically have the same bel + cell - # Make a best effort and move forward - set src_cell_pin [lindex $src_cell_pins 0] - set src_cell [get_cells -of_objects $src_cell_pin] - - # Only applicable if in a site - set src_bel [get_bels -of_objects $src_cell] - if {$src_bel eq ""} { - # just throw out cases where source site doesn't exist - # these are very special, don't really have timing info anyway - # rework these later if they become problematic - incr nets_no_src_bel - puts " SKIP: no source bel" - continue - } - - set src_bel_pin [get_bel_pins -of_objects $src_cell_pin] - set src_site [get_sites -of_objects $src_bel] - set src_site_type [get_property SITE_TYPE $src_site] - # optional - set src_site_pin [get_site_pins -of_objects $src_cell_pin] - - # Report delays with and without interconnect only - foreach ico "0 1" { - if $ico { - set delays [get_net_delays -interconnect_only -of_objects $net] - } else { - set delays [get_net_delays -of_objects $net] - } - set delays_net [expr "$delays_net + [llength $delays]"] - puts $fp "GROUP,$ico,[llength $delays]" - foreach delay $delays { - #set delaystr [get_property NAME $delay] - - set fast_max [get_property "FAST_MAX" $delay] - set fast_min [get_property "FAST_MIN" $delay] - set slow_max [get_property "SLOW_MAX" $delay] - set slow_min [get_property "SLOW_MIN" $delay] - - # Does this always exist? - set dst_cell_pin_str [get_property TO_PIN $delay] - set dst_cell_pin [get_pins $dst_cell_pin_str] - set dst_cell [get_cells -of_objects $dst_cell_pin] - set dst_bel [get_bels -of_objects $dst_cell] - # WARNING: when there is a passthrough LUT, this can be multiple values - # (one for the real dest pin, and one for the passthrough lut input) - set dst_bel_pin [get_bel_pins -of_objects $dst_cell_pin] - set dst_site [get_sites -of_objects $dst_bel] - set dst_site_type [get_property SITE_TYPE $dst_site] - # optional - set dst_site_pin [get_site_pins -of_objects $dst_cell_pin] - - # No fabric on this net? - # don't try querying sites and such - if {[get_nodes -of_objects $net] eq ""} { - if {$src_site ne $dst_site} { - puts "ERROR: site mismatch" - return - } - if {$src_site_type ne $dst_site_type} { - puts "ERROR: site mismatch" - return - } - - # Already have everything we could query - # Just output - incr lines_no_int - line_net_internal $fp $net $src_site $src_site_type $src_bel $src_bel_pin $dst_bel $dst_bel_pin $ico $fast_max $fast_min $slow_max $slow_min - # At least some fabric exists - # Does dest BEL exist but not source BEL? - } elseif {$src_bel eq ""} { - puts "ERROR: should have been filtered" - return - # Ideally query from and to cell pins - } else { - # Nested list delimination precedence: ",|:" - - # Pips in between - # Walk net, looking for interesting elements in between - # -from - (Optional) Defines the starting points of the pips to get - # from wire or site_pin - set pips [get_pips -of_objects $net -from $src_site_pin -to $dst_site_pin] - # Write pips w/ speed index - foreach pip $pips { - set speed_index [get_property SPEED_INDEX $pip] - lappend pips_out "$pip:$speed_index" - } - set pips_out [list_format "$pips_out" "|"] - - set nodes [get_nodes -of_objects $net -from $src_site_pin -to $dst_site_pin] - if {$nodes eq ""} { - puts "ERROR: no nodes" - return - } - - set wires [get_wires -of_objects $nodes] - # Write wires - foreach wire $wires { - set speed_index [get_property SPEED_INDEX $wire] - lappend wires_out "$wire:$speed_index" - } - set wires_out [list_format "$wires_out" "|"] - - incr lines_some_int - line_net_external $fp $net $src_site $src_site_type $src_site_pin $src_bel $src_bel_pin $dst_site $dst_site_type $dst_site_pin $dst_bel $dst_bel_pin $ico $fast_max $fast_min $slow_max $slow_min $pips_out $wires_out - } - } - } - } - close $fp - set TIME_taken [expr [clock clicks -milliseconds] - $TIME_start] - puts "Took ms: $TIME_taken" - puts "Checked $delays_net delays" - puts "Nets: $nnets" - puts " Skipped (no source cell): $nets_no_src_cell" - puts " Skipped (no source bel): $nets_no_src_bel" - puts "Lines" - puts " No interconnect: $lines_no_int" - puts " Has interconnect: $lines_some_int" -} - -# for debugging -# source ../project.tcl -# write_info4 diff --git a/fuzzers/007-timing/rref.py b/fuzzers/007-timing/rref.py deleted file mode 100644 index 7d6a449b..00000000 --- a/fuzzers/007-timing/rref.py +++ /dev/null @@ -1,247 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import Benchmark, Ar_di2np, loadc_Ads_b, index_names, A_ds2np, simplify_rows, OrderedSet -import numpy as np -import glob -import math -import json -import sympy -from collections import OrderedDict -from fractions import Fraction - - -def rm_zero_cols(Ads, verbose=True): - removed = OrderedSet() - - print('Removing ZERO elements') - for row_ds in Ads: - for k in set(row_ds.keys()): - if k in removed: - del row_ds[k] - elif k.find('ZERO') >= 0: - del row_ds[k] - removed.add(k) - if verbose: - print(' Removing %s' % k) - return removed - - -def fracr_quick(r): - return [Fraction(numerator=int(x), denominator=1) for x in r] - - -def fracm_quick(m): - '''Convert integer matrix to Fraction matrix''' - t = type(m[0][0]) - print('fracm_quick type: %s' % t) - return [fracr_quick(r) for r in m] - - -class State(object): - def __init__(self, Ads, zero_names=[]): - self.Ads = Ads - self.names = index_names(self.Ads) - - # known zero delay elements - self.zero_names = OrderedSet(zero_names) - # active names in rows - # includes sub variables, excludes variables that have been substituted out - self.base_names = OrderedSet(self.names) - #self.names = OrderedSet(self.base_names) - self.names = set(self.base_names) - # List of variable substitutions - # k => dict of v:n entries that it came from - self.subs = OrderedDict() - self.verbose = True - - def print_stats(self): - print("Stats") - print(" Substitutions: %u" % len(self.subs)) - if self.subs: - print( - " Largest: %u" % max([len(x) for x in self.subs.values()])) - print(" Rows: %u" % len(self.Ads)) - print( - " Cols (in): %u" % (len(self.base_names) + len(self.zero_names))) - print(" Cols (preprocessed): %u" % len(self.base_names)) - print(" ZERO names: %u" % len(self.zero_names)) - print(" Cols (out): %u" % len(self.names)) - print(" Solvable vars: %u" % len(self.names & self.base_names)) - assert len(self.names) >= len(self.subs) - - @staticmethod - def load(fn_ins, simplify=False, corner=None, rm_zero=False): - zero_names = OrderedSet() - - Ads, b = loadc_Ads_b(fn_ins, corner=corner) - if rm_zero: - zero_names = rm_zero_cols(Ads) - if simplify: - print('Simplifying corner %s' % (corner, )) - Ads, b = simplify_rows(Ads, b, remove_zd=False, corner=corner) - return State(Ads, zero_names=zero_names) - - -def write_state(state, fout): - j = { - 'names': - OrderedDict([(x, None) for x in state.names]), - 'zero_names': - sorted(list(state.zero_names)), - 'base_names': - sorted(list(state.base_names)), - 'subs': - OrderedDict([(name, values) for name, values in state.subs.items()]), - 'pivots': - state.pivots, - } - json.dump(j, fout, sort_keys=True, indent=4, separators=(',', ': ')) - - -def row_np2ds(rownp, names): - ret = OrderedDict() - assert len(rownp) == len(names), (len(rownp), len(names)) - for namei, name in enumerate(names): - v = rownp[namei] - if v: - ret[name] = v - return ret - - -def row_sym2dsf(rowsym, names): - '''Convert a sympy row into a dictionary of keys to (numerator, denominator) tuples''' - from sympy import fraction - - ret = OrderedDict() - assert len(rowsym) == len(names), (len(rowsym), len(names)) - for namei, name in enumerate(names): - v = rowsym[namei] - if v: - (num, den) = fraction(v) - ret[name] = (int(num), int(den)) - return ret - - -def state_rref(state, verbose=False): - print('Converting rows to integer keys') - names, Anp = A_ds2np(state.Ads) - - print('np: %u rows x %u cols' % (len(Anp), len(Anp[0]))) - mnp = Anp - print('Matrix: %u rows x %u cols' % (len(mnp), len(mnp[0]))) - print('Converting np to sympy matrix') - mfrac = fracm_quick(mnp) - # doesn't seem to change anything - #msym = sympy.MutableSparseMatrix(mfrac) - msym = sympy.Matrix(mfrac) - # internal encoding has significnat performance implications - #assert type(msym[0]) is sympy.Integer - - if verbose: - print('names') - print(names) - print('Matrix') - sympy.pprint(msym) - print('Making rref') - rref, pivots = msym.rref(normalize_last=False) - - if verbose: - print('Pivots') - sympy.pprint(pivots) - print('rref') - sympy.pprint(rref) - - state.pivots = OrderedDict() - - def row_solved(rowsym, row_pivot): - for ci, c in enumerate(rowsym): - if ci == row_pivot: - continue - if c != 0: - return False - return True - - #rrefnp = np.array(rref).astype(np.float64) - #print('Computing groups w/ rref %u row x %u col' % (len(rrefnp), len(rrefnp[0]))) - #print(rrefnp) - # rows that have a single 1 are okay - # anything else requires substitution (unless all 0) - # pivots may be fewer than the rows - # remaining rows should be 0s - for row_i, row_pivot in enumerate(pivots): - rowsym = rref.row(row_i) - # yipee! nothign to report - if row_solved(rowsym, row_pivot): - continue - - # a grouping - group_name = "GRP_%u" % row_i - rowdsf = row_sym2dsf(rowsym, names) - - state.subs[group_name] = rowdsf - # Add the new variables - state.names.add(group_name) - # Remove substituted variables - # Note: variables may appear multiple times - state.names.difference_update(OrderedSet(rowdsf.keys())) - pivot_name = names[row_pivot] - state.pivots[group_name] = pivot_name - if verbose: - print("%s (%s): %s" % (group_name, pivot_name, rowdsf)) - - return state - - -def run(fnout, fn_ins, simplify=False, corner=None, rm_zero=False, verbose=0): - print('Loading data') - - assert len(fn_ins) > 0 - state = State.load( - fn_ins, simplify=simplify, corner=corner, rm_zero=rm_zero) - state_rref(state, verbose=verbose) - state.print_stats() - if fnout: - with open(fnout, 'w') as fout: - write_state(state, fout) - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description= - 'Compute reduced row echelon (RREF) to form sub.json (variable groups)' - ) - - parser.add_argument('--verbose', action='store_true', help='') - parser.add_argument('--simplify', action='store_true', help='') - parser.add_argument('--corner', default="slow_max", help='') - parser.add_argument( - '--rm-zero', action='store_true', help='Remove ZERO elements') - parser.add_argument( - '--speed-json', - default='build_speed/speed.json', - help='Provides speed index to name translation') - parser.add_argument('--out', help='Output sub.json substitution result') - parser.add_argument('fns_in', nargs='*', help='timing4i.csv input files') - args = parser.parse_args() - bench = Benchmark() - - fns_in = args.fns_in - if not fns_in: - fns_in = glob.glob('specimen_*/timing4i.csv') - - try: - run( - fnout=args.out, - fn_ins=fns_in, - simplify=args.simplify, - corner=args.corner, - rm_zero=args.rm_zero, - verbose=args.verbose) - finally: - print('Exiting after %s' % bench) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/solve_leastsq.py b/fuzzers/007-timing/solve_leastsq.py deleted file mode 100644 index 3e6f5742..00000000 --- a/fuzzers/007-timing/solve_leastsq.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import Benchmark, load_sub -import timfuz -import numpy as np -import math -import sys -import os -import time -import timfuz_solve -import scipy.optimize as optimize - - -def mkestimate(Anp, b): - ''' - Ballpark upper bound estimate assuming variables contribute all of the delay in their respective row - Return the min of all of the occurances - - XXX: should this be corner adjusted? - ''' - cols = len(Anp[0]) - x0 = np.array([1e3 for _x in range(cols)]) - for row_np, row_b in zip(Anp, b): - for coli, val in enumerate(row_np): - # favor non-trivial values - if val <= 0: - continue - # Scale by number occurances - ub = row_b / val - if ub <= 0: - continue - if x0[coli] == 0: - x0[coli] = ub - else: - x0[coli] = min(x0[coli], ub) - # reject solutions that don't provide a seed value - # these lead to bad optimizations - assert sum(x0) != 0 - return x0 - - -def run_corner( - Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=None): - # Given timing scores for above delays (-ps) - assert type(Anp[0]) is np.ndarray, type(Anp[0]) - assert type(b) is np.ndarray, type(b) - - #check_feasible(Anp, b) - ''' - Be mindful of signs - Have something like - timing1/timing 2 are constants - delay1 + delay2 + delay4 >= timing1 - delay2 + delay3 >= timing2 - - But need it in compliant form: - -delay1 + -delay2 + -delay4 <= -timing1 - -delay2 + -delay3 <= -timing2 - ''' - rows = len(Anp) - cols = len(Anp[0]) - - print('Unique delay elements: %d' % len(names)) - print('Input paths') - print(' # timing scores: %d' % len(b)) - print(' Rows: %d' % rows) - ''' - You must have at least as many things to optimize as variables - That is, the system must be plausibly constrained for it to attempt a solve - If not, you'll get a message like - TypeError: Improper input: N=3 must not exceed M=2 - ''' - if rows < cols: - raise Exception("rows must be >= cols") - - tlast = [None] - iters = [0] - printn = [0] - - def progress_print(): - iters[0] += 1 - if tlast[0] is None: - tlast[0] = time.time() - if time.time() - tlast[0] > 1.0: - sys.stdout.write('I:%d ' % iters[0]) - tlast[0] = time.time() - printn[0] += 1 - if printn[0] % 10 == 0: - sys.stdout.write('\n') - sys.stdout.flush() - - def func(params): - progress_print() - return (b - np.dot(Anp, params)) - - print('') - # Now find smallest values for delay constants - # Due to input bounds (ex: column limit), some delay elements may get eliminated entirely - print('Running leastsq w/ %d r, %d c (%d name)' % (rows, cols, len(names))) - # starting at 0 completes quicky, but gives a solution near 0 with terrible results - # maybe give a starting estimate to the smallest net delay with the indicated variable - #x0 = np.array([1000.0 for _x in range(cols)]) - print('Creating x0 estimate') - x0 = mkestimate(Anp, b) - - print('Solving') - res = optimize.least_squares(func, x0, bounds=(0, float('inf'))) - print('Done') - - if outfn: - timfuz_solve.solve_save(outfn, res.x, names, corner, verbose=verbose) - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description= - 'Solve timing solution using least squares objective function') - - parser.add_argument('--verbose', action='store_true', help='') - parser.add_argument( - '--massage', - action='store_true', - help='Derive additional constraints to improve solution') - parser.add_argument( - '--sub-json', help='Group substitutions to make fully ranked') - parser.add_argument('--corner', required=True, default="slow_max", help='') - parser.add_argument( - '--out', default=None, help='output timing delay .json') - parser.add_argument('fns_in', nargs='+', help='timing4i.csv input files') - args = parser.parse_args() - # Store options in dict to ease passing through functions - bench = Benchmark() - - fns_in = args.fns_in - if not fns_in: - fns_in = glob.glob('specimen_*/timing4i.csv') - - sub_json = None - if args.sub_json: - sub_json = load_sub(args.sub_json) - - try: - timfuz_solve.run( - run_corner=run_corner, - sub_json=sub_json, - fns_in=fns_in, - corner=args.corner, - massage=args.massage, - outfn=args.out, - verbose=args.verbose) - finally: - print('Exiting after %s' % bench) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/solve_linprog.py b/fuzzers/007-timing/solve_linprog.py deleted file mode 100644 index 8216258f..00000000 --- a/fuzzers/007-timing/solve_linprog.py +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env python3 - -import scipy.optimize as optimize -from timfuz import Benchmark, load_sub, A_ub_np2d, acorner2csv, corner_s2i -import numpy as np -import glob -import json -import math -import sys -import os -import time -import timfuz_solve - - -def run_corner( - Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=None): - if len(Anp) == 0: - print('WARNING: zero equations') - if outfn: - timfuz_solve.solve_save(outfn, [], [], corner) - return - maxcorner = { - 'slow_max': True, - 'slow_min': False, - 'fast_max': True, - 'fast_min': False, - }[corner] - - # Given timing scores for above delays (-ps) - assert type(Anp[0]) is np.ndarray, type(Anp[0]) - assert type(b) is np.ndarray, type(b) - - #check_feasible(Anp, b) - ''' - Be mindful of signs - t1, t2: total delay contants - d1, d2..: variables to solve for - - Max corner intuitive form: - d1 + d2 + d4 >= t1 - d2 + d3 >= t2 - - But need it in compliant form: - -d1 + -d2 + -d4 <= -t1 - -d2 + -d3 <= -t2 - Minimize delay elements - - - Min corner intuitive form: - d1 + d2 + d4 <= t1 - d2 + d3 <= t2 - Maximize delay elements - ''' - - rows = len(Anp) - cols = len(Anp[0]) - if maxcorner: - print('maxcorner => scaling to solution form...') - b_ub = -1.0 * b - #A_ub = -1.0 * Anp - A_ub = [-1.0 * x for x in Anp] - else: - print('mincorner => no scaling required') - b_ub = b - A_ub = Anp - - print('Creating misc constants...') - # Minimization function scalars - # Treat all logic elements as equally important - if maxcorner: - # Best result are min delays - c = [1 for _i in range(len(names))] - else: - # Best result are max delays - c = [-1 for _i in range(len(names))] - # Delays cannot be negative - # (this is also the default constraint) - #bounds = [(0, None) for _i in range(len(names))] - # Also you can provide one to apply to all - bounds = (0, None) - - # Seems to take about rows + 3 iterations - # Give some margin - #maxiter = int(1.1 * rows + 100) - #maxiter = max(1000, int(1000 * rows + 1000)) - # Most of the time I want it to just keep going unless I ^C it - maxiter = 1000000 - - if verbose >= 2: - print('b_ub', b) - print('Unique delay elements: %d' % len(names)) - print(' # delay minimization weights: %d' % len(c)) - print(' # delay constraints: %d' % len(bounds)) - print('Input paths') - print(' # timing scores: %d' % len(b)) - print(' Rows: %d' % rows) - - tlast = [time.time()] - iters = [0] - printn = [0] - - def callback(xk, **kwargs): - iters[0] = xk['nit'] - if time.time() - tlast[0] > 1.0: - sys.stdout.write('I:%d ' % xk['nit']) - tlast[0] = time.time() - printn[0] += 1 - if printn[0] % 10 == 0: - sys.stdout.write('\n') - sys.stdout.flush() - - print('') - # Now find smallest values for delay constants - # Due to input bounds (ex: column limit), some delay elements may get eliminated entirely - # https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.optimize.linprog.html - print('Running linprog w/ %d r, %d c (%d name)' % (rows, cols, len(names))) - res = optimize.linprog( - c, - A_ub=A_ub, - b_ub=b_ub, - bounds=bounds, - callback=callback, - options={ - "disp": True, - 'maxiter': maxiter, - 'bland': True, - 'tol': 1e-6, - }) - nonzeros = 0 - print('Ran %d iters' % iters[0]) - if res.success: - print('Result sample (%d elements)' % (len(res.x))) - plim = 3 - for xi, (name, x) in enumerate(zip(names, res.x)): - nonzero = x >= 0.001 - if nonzero: - nonzeros += 1 - #if nonzero and (verbose >= 1 or xi > 30): - if nonzero and (verbose or ( - (nonzeros < 100 or nonzeros % 20 == 0) and nonzeros <= plim)): - print(' % 4u % -80s % 10.1f' % (xi, name, x)) - print('Delay on %d / %d' % (nonzeros, len(res.x))) - - if outfn: - timfuz_solve.solve_save( - outfn, res.x, names, corner, verbose=verbose) - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description= - 'Solve timing solution using linear programming inequalities') - - parser.add_argument('--verbose', action='store_true', help='') - parser.add_argument('--massage', action='store_true', help='') - parser.add_argument( - '--bounds-csv', help='Previous solve result starting point') - parser.add_argument( - '--sub-json', help='Group substitutions to make fully ranked') - parser.add_argument('--corner', required=True, default="slow_max", help='') - parser.add_argument( - '--out', default=None, help='output timing delay .json') - parser.add_argument('fns_in', nargs='+', help='timing4i.csv input files') - args = parser.parse_args() - # Store options in dict to ease passing through functions - bench = Benchmark() - - fns_in = args.fns_in - if not fns_in: - fns_in = glob.glob('specimen_*/timing4i.csv') - - sub_json = None - if args.sub_json: - sub_json = load_sub(args.sub_json) - - try: - timfuz_solve.run( - run_corner=run_corner, - sub_json=sub_json, - bounds_csv=args.bounds_csv, - fns_in=fns_in, - corner=args.corner, - massage=args.massage, - outfn=args.out, - verbose=args.verbose) - finally: - print('Exiting after %s' % bench) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/solve_qor.py b/fuzzers/007-timing/solve_qor.py deleted file mode 100644 index 5a0bcf17..00000000 --- a/fuzzers/007-timing/solve_qor.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import Benchmark, load_sub, load_bounds, loadc_Ads_b -import numpy as np - - -def run(fns_in, corner, bounds_csv, verbose=False): - print('Loading data') - Ads, borig = loadc_Ads_b(fns_in, corner) - - bounds = load_bounds(bounds_csv, corner) - # verify is flattened - for k in bounds.keys(): - assert 'GROUP_' not in k, 'Must operate on flattened bounds' - - # compute our timing model delay at the given corner - bgots = [] - for row_ds in Ads: - delays = [n * bounds[x] for x, n in row_ds.items()] - bgots.append(sum(delays)) - - ses = (np.asarray(bgots) - np.asarray(borig))**2 - mse = (ses).mean(axis=None) - print('MSE aggregate: %0.1f' % mse) - print('Min SE: %0.1f' % min(ses)) - print('Max SE: %0.1f' % max(ses)) - - -def main(): - import argparse - - parser = argparse.ArgumentParser(description='Report a timing fit score') - - parser.add_argument('--verbose', action='store_true', help='') - parser.add_argument('--corner', required=True, default="slow_max", help='') - parser.add_argument( - '--bounds-csv', - required=True, - help='Previous solve result starting point') - parser.add_argument('fns_in', nargs='+', help='timing4i.csv input files') - args = parser.parse_args() - # Store options in dict to ease passing through functions - bench = Benchmark() - - fns_in = args.fns_in - if not fns_in: - fns_in = glob.glob('specimen_*/timing4i.csv') - - try: - run( - fns_in=fns_in, - corner=args.corner, - bounds_csv=args.bounds_csv, - verbose=args.verbose) - finally: - print('Exiting after %s' % bench) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/speed/.gitignore b/fuzzers/007-timing/speed/.gitignore deleted file mode 100644 index 9ef96044..00000000 --- a/fuzzers/007-timing/speed/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build - diff --git a/fuzzers/007-timing/speed/Makefile b/fuzzers/007-timing/speed/Makefile deleted file mode 100644 index 436944c7..00000000 --- a/fuzzers/007-timing/speed/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -all: build/speed.json - -build/node.txt: speed_json.py generate.tcl - mkdir -p build - cd build && ${XRAY_VIVADO} -mode batch -source ../generate.tcl - -build/speed.json: build/node.txt - cd build && python3 ../speed_json.py speed_model.txt node.txt speed.json - -clean: - rm -rf build - diff --git a/fuzzers/007-timing/speed/README.md b/fuzzers/007-timing/speed/README.md deleted file mode 100644 index a10f335d..00000000 --- a/fuzzers/007-timing/speed/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Generates speed.json, describing speed index to string translation. -These indices appear to be fixed between runtimes. -It is unknown how stable they are across versions. - diff --git a/fuzzers/007-timing/speed/generate.tcl b/fuzzers/007-timing/speed/generate.tcl deleted file mode 100644 index 4af484fe..00000000 --- a/fuzzers/007-timing/speed/generate.tcl +++ /dev/null @@ -1,172 +0,0 @@ -proc pin_info {pin} { - set cell [get_cells -of_objects $pin] - set bel [get_bels -of_objects $cell] - set site [get_sites -of_objects $bel] - return "$site $bel" -} - -proc pin_bel {pin} { - set cell [get_cells -of_objects $pin] - set bel [get_bels -of_objects $cell] - return $bel -} - -proc build_design_full {} { - create_project -force -part $::env(XRAY_PART) design design - read_verilog ../top.v - read_verilog ../../src/picorv32.v - synth_design -top top - - #set_property LOCK_PINS {I0:A1 I1:A2 I2:A3 I3:A4 I4:A5 I5:A6} \ - # [get_cells -quiet -filter {REF_NAME == LUT6} -hierarchical] - - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports stb] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports di] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports do] - - set_property CFGBVS VCCO [current_design] - set_property CONFIG_VOLTAGE 3.3 [current_design] - set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] - - set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] - - place_design - route_design - - write_checkpoint -force design.dcp - write_bitstream -force design.bit -} - - -proc build_design_synth {} { - create_project -force -part $::env(XRAY_PART) design design - - read_verilog ../top.v - read_verilog ../picorv32.v - synth_design -top top -} - -# WARNING: [Common 17-673] Cannot get value of property 'FORWARD' because this property is not valid in conjunction with other property setting on this object. -# WARNING: [Common 17-673] Cannot get value of property 'REVERSE' because this property is not valid in conjunction with other property setting on this object. -proc speed_models1 {} { - set outdir "." - set fp [open "$outdir/speed_model.txt" w] - # list_property [lindex [get_speed_models] 0] - set speed_models [get_speed_models] - set properties [list_property [lindex $speed_models 0]] - # "CLASS DELAY FAST_MAX FAST_MIN IS_INSTANCE_SPECIFIC NAME NAME_LOGICAL SLOW_MAX SLOW_MIN SPEED_INDEX TYPE" - puts $fp $properties - - set needspace 0 - foreach speed_model $speed_models { - foreach property $properties { - if $needspace { - puts -nonewline $fp " " - } - puts -nonewline $fp [get_property $property $speed_model] - set needspace 1 - } - puts $fp "" - } - close $fp -} - -proc speed_models2 {} { - set outdir "." - set fp [open "$outdir/speed_model.txt" w] - # list_property [lindex [get_speed_models] 0] - set speed_models [get_speed_models] - puts "Items: [llength $speed_models]" - - set needspace 0 - # Not all objects have the same properties - # But they do seem to have the same list - set properties [list_property [lindex $speed_models 0]] - foreach speed_model $speed_models { - set needspace 0 - foreach property $properties { - set val [get_property $property $speed_model] - if {"$val" ne ""} { - if $needspace { - puts -nonewline $fp " " - } - puts -nonewline $fp "$property:$val" - set needspace 1 - } - } - puts $fp "" - } - close $fp -} - - -# For cost codes -# Items: 2663055s -# Hmm too much -# Lets filter out items we really want -proc nodes_all {} { - set outdir "." - set fp [open "$outdir/node_all.txt" w] - set items [get_nodes] - puts "Items: [llength $items]" - - set needspace 0 - set properties [list_property [lindex $items 0]] - foreach item $items { - set needspace 0 - foreach property $properties { - set val [get_property $property $item] - if {"$val" ne ""} { - if $needspace { - puts -nonewline $fp " " - } - puts -nonewline $fp "$property:$val" - set needspace 1 - } - } - puts $fp "" - } - close $fp -} - -# Only writes out items with unique cost codes -# (much faster) -proc nodes_unique_cc {} { - set outdir "." - set fp [open "$outdir/node.txt" w] - set items [get_nodes] - puts "Computing cost codes with [llength $items] items" - - set needspace 0 - set properties [list_property [lindex $items 0]] - set cost_codes_known [dict create] - set itemi 0 - foreach item $items { - incr itemi - set cost_code [get_property COST_CODE $item] - if {[ dict exists $cost_codes_known $cost_code ]} { - continue - } - puts " Adding cost code $cost_code @ item $itemi" - dict set cost_codes_known $cost_code 1 - - set needspace 0 - foreach property $properties { - set val [get_property $property $item] - if {"$val" ne ""} { - if $needspace { - puts -nonewline $fp " " - } - puts -nonewline $fp "$property:$val" - set needspace 1 - } - } - puts $fp "" - } - close $fp -} - -build_design_full -speed_models2 -nodes_unique_cc diff --git a/fuzzers/007-timing/speed/speed_json.py b/fuzzers/007-timing/speed/speed_json.py deleted file mode 100644 index 1f0a3910..00000000 --- a/fuzzers/007-timing/speed/speed_json.py +++ /dev/null @@ -1,94 +0,0 @@ -import json - - -def load_speed(fin): - speed_models = {} - speed_types = {} - for l in fin: - delay = {} - l = l.strip() - for kvs in l.split(): - name, value = kvs.split(':') - name = name.lower() - if name in ('class', ): - continue - if name in ('speed_index', ): - value = int(value) - if name == 'type': - speed_types.setdefault(value, {}) - delay[name] = value - delayk = delay['name'] - if delayk in delay: - raise Exception("Duplicate name") - - if "name" in delay and "name_logical" in delay: - # Always true - if delay['name'] != delay['name_logical']: - raise Exception("nope!") - # Found a counter example - if 0 and delay['name'] != delay['forward']: - # ('BSW_NONTLFW_TLRV', '_BSW_LONG_NONTLFORWARD') - print(delay['name'], delay['forward']) - raise Exception("nope!") - # Found a counter example - if 0 and delay['forward'] != delay['reverse']: - # _BSW_LONG_NONTLFORWARD _BSW_LONG_TLREVERSE - print(delay['forward'], delay['reverse']) - raise Exception("nope!") - - speed_models[delayk] = delay - return speed_models, speed_types - - -def load_cost_code(fin): - # COST_CODE:4 COST_CODE_NAME:SLOWSINGLE - cost_codes = {} - for l in fin: - lj = {} - l = l.strip() - for kvs in l.split(): - name, value = kvs.split(':') - name = name.lower() - lj[name] = value - cost_code = { - 'name': lj['cost_code_name'], - 'code': int(lj['cost_code']), - # Hmm is this unique per type? - #'speed_class': int(lj['speed_class']), - } - - cost_codes[cost_code['name']] = cost_code - return cost_codes - - -def run(speed_fin, node_fin, fout, verbose=0): - print('Loading data') - speed_models, speed_types = load_speed(speed_fin) - cost_codes = load_cost_code(node_fin) - - j = { - 'speed_model': speed_models, - 'speed_type': speed_types, - 'cost_code': cost_codes, - } - json.dump(j, fout, sort_keys=True, indent=4, separators=(',', ': ')) - - -if __name__ == '__main__': - import argparse - - parser = argparse.ArgumentParser(description='Timing fuzzer') - - parser.add_argument('--verbose', type=int, help='') - parser.add_argument( - 'speed_fn_in', default='/dev/stdin', nargs='?', help='Input file') - parser.add_argument( - 'node_fn_in', default='/dev/stdin', nargs='?', help='Input file') - parser.add_argument( - 'fn_out', default='/dev/stdout', nargs='?', help='Output file') - args = parser.parse_args() - run( - open(args.speed_fn_in, 'r'), - open(args.node_fn_in, 'r'), - open(args.fn_out, 'w'), - verbose=args.verbose) diff --git a/fuzzers/007-timing/speed/top.v b/fuzzers/007-timing/speed/top.v deleted file mode 100644 index cf662548..00000000 --- a/fuzzers/007-timing/speed/top.v +++ /dev/null @@ -1,8 +0,0 @@ -module top(input clk, stb, di, output do); - reg dor; - always @(posedge clk) begin - dor <= stb & di; - end - assign do = dor; -endmodule - diff --git a/fuzzers/007-timing/src/picorv32.v b/fuzzers/007-timing/src/picorv32.v deleted file mode 100644 index af634b47..00000000 --- a/fuzzers/007-timing/src/picorv32.v +++ /dev/null @@ -1,2977 +0,0 @@ -/* - * PicoRV32 -- A Small RISC-V (RV32I) Processor Core - * - * Copyright (C) 2015 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -`timescale 1 ns / 1 ps -// `default_nettype none -// `define DEBUGNETS -// `define DEBUGREGS -// `define DEBUGASM -// `define DEBUG - -`ifdef DEBUG - `define debug(debug_command) debug_command -`else - `define debug(debug_command) -`endif - -`ifdef FORMAL - `define FORMAL_KEEP (* keep *) - `define assert(assert_expr) assert(assert_expr) -`else - `ifdef DEBUGNETS - `define FORMAL_KEEP (* keep *) - `else - `define FORMAL_KEEP - `endif - `define assert(assert_expr) empty_statement -`endif - -// uncomment this for register file in extra module -// `define PICORV32_REGS picorv32_regs - -// this macro can be used to check if the verilog files in your -// design are read in the correct order. -`define PICORV32_V - - -/*************************************************************** - * picorv32 - ***************************************************************/ - -module picorv32 #( - parameter [ 0:0] ENABLE_COUNTERS = 1, - parameter [ 0:0] ENABLE_COUNTERS64 = 1, - parameter [ 0:0] ENABLE_REGS_16_31 = 1, - parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, - parameter [ 0:0] LATCHED_MEM_RDATA = 0, - parameter [ 0:0] TWO_STAGE_SHIFT = 1, - parameter [ 0:0] BARREL_SHIFTER = 0, - parameter [ 0:0] TWO_CYCLE_COMPARE = 0, - parameter [ 0:0] TWO_CYCLE_ALU = 0, - parameter [ 0:0] COMPRESSED_ISA = 0, - parameter [ 0:0] CATCH_MISALIGN = 1, - parameter [ 0:0] CATCH_ILLINSN = 1, - parameter [ 0:0] ENABLE_PCPI = 0, - parameter [ 0:0] ENABLE_MUL = 0, - parameter [ 0:0] ENABLE_FAST_MUL = 0, - parameter [ 0:0] ENABLE_DIV = 0, - parameter [ 0:0] ENABLE_IRQ = 0, - parameter [ 0:0] ENABLE_IRQ_QREGS = 1, - parameter [ 0:0] ENABLE_IRQ_TIMER = 1, - parameter [ 0:0] ENABLE_TRACE = 0, - parameter [ 0:0] REGS_INIT_ZERO = 0, - parameter [31:0] MASKED_IRQ = 32'h 0000_0000, - parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, - parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, - parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, - parameter [31:0] STACKADDR = 32'h ffff_ffff -) ( - input clk, resetn, - output reg trap, - - output reg mem_valid, - output reg mem_instr, - input mem_ready, - - output reg [31:0] mem_addr, - output reg [31:0] mem_wdata, - output reg [ 3:0] mem_wstrb, - input [31:0] mem_rdata, - - // Look-Ahead Interface - output mem_la_read, - output mem_la_write, - output [31:0] mem_la_addr, - output reg [31:0] mem_la_wdata, - output reg [ 3:0] mem_la_wstrb, - - // Pico Co-Processor Interface (PCPI) - output reg pcpi_valid, - output reg [31:0] pcpi_insn, - output [31:0] pcpi_rs1, - output [31:0] pcpi_rs2, - input pcpi_wr, - input [31:0] pcpi_rd, - input pcpi_wait, - input pcpi_ready, - - // IRQ Interface - input [31:0] irq, - output reg [31:0] eoi, - -`ifdef RISCV_FORMAL - output reg rvfi_valid, - output reg [63:0] rvfi_order, - output reg [31:0] rvfi_insn, - output reg rvfi_trap, - output reg rvfi_halt, - output reg rvfi_intr, - output reg [ 4:0] rvfi_rs1_addr, - output reg [ 4:0] rvfi_rs2_addr, - output reg [31:0] rvfi_rs1_rdata, - output reg [31:0] rvfi_rs2_rdata, - output reg [ 4:0] rvfi_rd_addr, - output reg [31:0] rvfi_rd_wdata, - output reg [31:0] rvfi_pc_rdata, - output reg [31:0] rvfi_pc_wdata, - output reg [31:0] rvfi_mem_addr, - output reg [ 3:0] rvfi_mem_rmask, - output reg [ 3:0] rvfi_mem_wmask, - output reg [31:0] rvfi_mem_rdata, - output reg [31:0] rvfi_mem_wdata, -`endif - - // Trace Interface - output reg trace_valid, - output reg [35:0] trace_data -); - localparam integer irq_timer = 0; - localparam integer irq_ebreak = 1; - localparam integer irq_buserror = 2; - - localparam integer irqregs_offset = ENABLE_REGS_16_31 ? 32 : 16; - localparam integer regfile_size = (ENABLE_REGS_16_31 ? 32 : 16) + 4*ENABLE_IRQ*ENABLE_IRQ_QREGS; - localparam integer regindex_bits = (ENABLE_REGS_16_31 ? 5 : 4) + ENABLE_IRQ*ENABLE_IRQ_QREGS; - - localparam WITH_PCPI = ENABLE_PCPI || ENABLE_MUL || ENABLE_FAST_MUL || ENABLE_DIV; - - localparam [35:0] TRACE_BRANCH = {4'b 0001, 32'b 0}; - localparam [35:0] TRACE_ADDR = {4'b 0010, 32'b 0}; - localparam [35:0] TRACE_IRQ = {4'b 1000, 32'b 0}; - - reg [63:0] count_cycle, count_instr; - reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out; - reg [4:0] reg_sh; - - reg [31:0] next_insn_opcode; - reg [31:0] dbg_insn_opcode; - reg [31:0] dbg_insn_addr; - - wire dbg_mem_valid = mem_valid; - wire dbg_mem_instr = mem_instr; - wire dbg_mem_ready = mem_ready; - wire [31:0] dbg_mem_addr = mem_addr; - wire [31:0] dbg_mem_wdata = mem_wdata; - wire [ 3:0] dbg_mem_wstrb = mem_wstrb; - wire [31:0] dbg_mem_rdata = mem_rdata; - - assign pcpi_rs1 = reg_op1; - assign pcpi_rs2 = reg_op2; - - wire [31:0] next_pc; - - reg irq_delay; - reg irq_active; - reg [31:0] irq_mask; - reg [31:0] irq_pending; - reg [31:0] timer; - -`ifndef PICORV32_REGS - reg [31:0] cpuregs [0:regfile_size-1]; - - integer i; - initial begin - if (REGS_INIT_ZERO) begin - for (i = 0; i < regfile_size; i = i+1) - cpuregs[i] = 0; - end - end -`endif - - task empty_statement; - // This task is used by the `assert directive in non-formal mode to - // avoid empty statement (which are unsupported by plain Verilog syntax). - begin end - endtask - -`ifdef DEBUGREGS - wire [31:0] dbg_reg_x0 = 0; - wire [31:0] dbg_reg_x1 = cpuregs[1]; - wire [31:0] dbg_reg_x2 = cpuregs[2]; - wire [31:0] dbg_reg_x3 = cpuregs[3]; - wire [31:0] dbg_reg_x4 = cpuregs[4]; - wire [31:0] dbg_reg_x5 = cpuregs[5]; - wire [31:0] dbg_reg_x6 = cpuregs[6]; - wire [31:0] dbg_reg_x7 = cpuregs[7]; - wire [31:0] dbg_reg_x8 = cpuregs[8]; - wire [31:0] dbg_reg_x9 = cpuregs[9]; - wire [31:0] dbg_reg_x10 = cpuregs[10]; - wire [31:0] dbg_reg_x11 = cpuregs[11]; - wire [31:0] dbg_reg_x12 = cpuregs[12]; - wire [31:0] dbg_reg_x13 = cpuregs[13]; - wire [31:0] dbg_reg_x14 = cpuregs[14]; - wire [31:0] dbg_reg_x15 = cpuregs[15]; - wire [31:0] dbg_reg_x16 = cpuregs[16]; - wire [31:0] dbg_reg_x17 = cpuregs[17]; - wire [31:0] dbg_reg_x18 = cpuregs[18]; - wire [31:0] dbg_reg_x19 = cpuregs[19]; - wire [31:0] dbg_reg_x20 = cpuregs[20]; - wire [31:0] dbg_reg_x21 = cpuregs[21]; - wire [31:0] dbg_reg_x22 = cpuregs[22]; - wire [31:0] dbg_reg_x23 = cpuregs[23]; - wire [31:0] dbg_reg_x24 = cpuregs[24]; - wire [31:0] dbg_reg_x25 = cpuregs[25]; - wire [31:0] dbg_reg_x26 = cpuregs[26]; - wire [31:0] dbg_reg_x27 = cpuregs[27]; - wire [31:0] dbg_reg_x28 = cpuregs[28]; - wire [31:0] dbg_reg_x29 = cpuregs[29]; - wire [31:0] dbg_reg_x30 = cpuregs[30]; - wire [31:0] dbg_reg_x31 = cpuregs[31]; -`endif - - // Internal PCPI Cores - - wire pcpi_mul_wr; - wire [31:0] pcpi_mul_rd; - wire pcpi_mul_wait; - wire pcpi_mul_ready; - - wire pcpi_div_wr; - wire [31:0] pcpi_div_rd; - wire pcpi_div_wait; - wire pcpi_div_ready; - - reg pcpi_int_wr; - reg [31:0] pcpi_int_rd; - reg pcpi_int_wait; - reg pcpi_int_ready; - - generate if (ENABLE_FAST_MUL) begin - picorv32_pcpi_fast_mul pcpi_mul ( - .clk (clk ), - .resetn (resetn ), - .pcpi_valid(pcpi_valid ), - .pcpi_insn (pcpi_insn ), - .pcpi_rs1 (pcpi_rs1 ), - .pcpi_rs2 (pcpi_rs2 ), - .pcpi_wr (pcpi_mul_wr ), - .pcpi_rd (pcpi_mul_rd ), - .pcpi_wait (pcpi_mul_wait ), - .pcpi_ready(pcpi_mul_ready ) - ); - end else if (ENABLE_MUL) begin - picorv32_pcpi_mul pcpi_mul ( - .clk (clk ), - .resetn (resetn ), - .pcpi_valid(pcpi_valid ), - .pcpi_insn (pcpi_insn ), - .pcpi_rs1 (pcpi_rs1 ), - .pcpi_rs2 (pcpi_rs2 ), - .pcpi_wr (pcpi_mul_wr ), - .pcpi_rd (pcpi_mul_rd ), - .pcpi_wait (pcpi_mul_wait ), - .pcpi_ready(pcpi_mul_ready ) - ); - end else begin - assign pcpi_mul_wr = 0; - assign pcpi_mul_rd = 32'bx; - assign pcpi_mul_wait = 0; - assign pcpi_mul_ready = 0; - end endgenerate - - generate if (ENABLE_DIV) begin - picorv32_pcpi_div pcpi_div ( - .clk (clk ), - .resetn (resetn ), - .pcpi_valid(pcpi_valid ), - .pcpi_insn (pcpi_insn ), - .pcpi_rs1 (pcpi_rs1 ), - .pcpi_rs2 (pcpi_rs2 ), - .pcpi_wr (pcpi_div_wr ), - .pcpi_rd (pcpi_div_rd ), - .pcpi_wait (pcpi_div_wait ), - .pcpi_ready(pcpi_div_ready ) - ); - end else begin - assign pcpi_div_wr = 0; - assign pcpi_div_rd = 32'bx; - assign pcpi_div_wait = 0; - assign pcpi_div_ready = 0; - end endgenerate - - always @* begin - pcpi_int_wr = 0; - pcpi_int_rd = 32'bx; - pcpi_int_wait = |{ENABLE_PCPI && pcpi_wait, (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_wait, ENABLE_DIV && pcpi_div_wait}; - pcpi_int_ready = |{ENABLE_PCPI && pcpi_ready, (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready, ENABLE_DIV && pcpi_div_ready}; - - (* parallel_case *) - case (1'b1) - ENABLE_PCPI && pcpi_ready: begin - pcpi_int_wr = ENABLE_PCPI ? pcpi_wr : 0; - pcpi_int_rd = ENABLE_PCPI ? pcpi_rd : 0; - end - (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready: begin - pcpi_int_wr = pcpi_mul_wr; - pcpi_int_rd = pcpi_mul_rd; - end - ENABLE_DIV && pcpi_div_ready: begin - pcpi_int_wr = pcpi_div_wr; - pcpi_int_rd = pcpi_div_rd; - end - endcase - end - - - // Memory Interface - - reg [1:0] mem_state; - reg [1:0] mem_wordsize; - reg [31:0] mem_rdata_word; - reg [31:0] mem_rdata_q; - reg mem_do_prefetch; - reg mem_do_rinst; - reg mem_do_rdata; - reg mem_do_wdata; - - wire mem_xfer; - reg mem_la_secondword, mem_la_firstword_reg, last_mem_valid; - wire mem_la_firstword = COMPRESSED_ISA && (mem_do_prefetch || mem_do_rinst) && next_pc[1] && !mem_la_secondword; - wire mem_la_firstword_xfer = COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg); - - reg prefetched_high_word; - reg clear_prefetched_high_word; - reg [15:0] mem_16bit_buffer; - - wire [31:0] mem_rdata_latched_noshuffle; - wire [31:0] mem_rdata_latched; - - wire mem_la_use_prefetched_high_word = COMPRESSED_ISA && mem_la_firstword && prefetched_high_word && !clear_prefetched_high_word; - assign mem_xfer = (mem_valid && mem_ready) || (mem_la_use_prefetched_high_word && mem_do_rinst); - - wire mem_busy = |{mem_do_prefetch, mem_do_rinst, mem_do_rdata, mem_do_wdata}; - wire mem_done = resetn && ((mem_xfer && |mem_state && (mem_do_rinst || mem_do_rdata || mem_do_wdata)) || (&mem_state && mem_do_rinst)) && - (!mem_la_firstword || (~&mem_rdata_latched[1:0] && mem_xfer)); - - assign mem_la_write = resetn && !mem_state && mem_do_wdata; - assign mem_la_read = resetn && ((!mem_la_use_prefetched_high_word && !mem_state && (mem_do_rinst || mem_do_prefetch || mem_do_rdata)) || - (COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg) && !mem_la_secondword && &mem_rdata_latched[1:0])); - assign mem_la_addr = (mem_do_prefetch || mem_do_rinst) ? {next_pc[31:2] + mem_la_firstword_xfer, 2'b00} : {reg_op1[31:2], 2'b00}; - - assign mem_rdata_latched_noshuffle = (mem_xfer || LATCHED_MEM_RDATA) ? mem_rdata : mem_rdata_q; - - assign mem_rdata_latched = COMPRESSED_ISA && mem_la_use_prefetched_high_word ? {16'bx, mem_16bit_buffer} : - COMPRESSED_ISA && mem_la_secondword ? {mem_rdata_latched_noshuffle[15:0], mem_16bit_buffer} : - COMPRESSED_ISA && mem_la_firstword ? {16'bx, mem_rdata_latched_noshuffle[31:16]} : mem_rdata_latched_noshuffle; - - always @(posedge clk) begin - if (!resetn) begin - mem_la_firstword_reg <= 0; - last_mem_valid <= 0; - end else begin - if (!last_mem_valid) - mem_la_firstword_reg <= mem_la_firstword; - last_mem_valid <= mem_valid && !mem_ready; - end - end - - always @* begin - (* full_case *) - case (mem_wordsize) - 0: begin - mem_la_wdata = reg_op2; - mem_la_wstrb = 4'b1111; - mem_rdata_word = mem_rdata; - end - 1: begin - mem_la_wdata = {2{reg_op2[15:0]}}; - mem_la_wstrb = reg_op1[1] ? 4'b1100 : 4'b0011; - case (reg_op1[1]) - 1'b0: mem_rdata_word = {16'b0, mem_rdata[15: 0]}; - 1'b1: mem_rdata_word = {16'b0, mem_rdata[31:16]}; - endcase - end - 2: begin - mem_la_wdata = {4{reg_op2[7:0]}}; - mem_la_wstrb = 4'b0001 << reg_op1[1:0]; - case (reg_op1[1:0]) - 2'b00: mem_rdata_word = {24'b0, mem_rdata[ 7: 0]}; - 2'b01: mem_rdata_word = {24'b0, mem_rdata[15: 8]}; - 2'b10: mem_rdata_word = {24'b0, mem_rdata[23:16]}; - 2'b11: mem_rdata_word = {24'b0, mem_rdata[31:24]}; - endcase - end - endcase - end - - always @(posedge clk) begin - if (mem_xfer) begin - mem_rdata_q <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata; - next_insn_opcode <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata; - end - - if (COMPRESSED_ISA && mem_done && (mem_do_prefetch || mem_do_rinst)) begin - case (mem_rdata_latched[1:0]) - 2'b00: begin // Quadrant 0 - case (mem_rdata_latched[15:13]) - 3'b000: begin // C.ADDI4SPN - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= {2'b0, mem_rdata_latched[10:7], mem_rdata_latched[12:11], mem_rdata_latched[5], mem_rdata_latched[6], 2'b00}; - end - 3'b010: begin // C.LW - mem_rdata_q[31:20] <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00}; - mem_rdata_q[14:12] <= 3'b 010; - end - 3'b 110: begin // C.SW - {mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00}; - mem_rdata_q[14:12] <= 3'b 010; - end - endcase - end - 2'b01: begin // Quadrant 1 - case (mem_rdata_latched[15:13]) - 3'b 000: begin // C.ADDI - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); - end - 3'b 010: begin // C.LI - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); - end - 3'b 011: begin - if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[4:3], - mem_rdata_latched[5], mem_rdata_latched[2], mem_rdata_latched[6], 4'b 0000}); - end else begin // C.LUI - mem_rdata_q[31:12] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); - end - end - 3'b100: begin - if (mem_rdata_latched[11:10] == 2'b00) begin // C.SRLI - mem_rdata_q[31:25] <= 7'b0000000; - mem_rdata_q[14:12] <= 3'b 101; - end - if (mem_rdata_latched[11:10] == 2'b01) begin // C.SRAI - mem_rdata_q[31:25] <= 7'b0100000; - mem_rdata_q[14:12] <= 3'b 101; - end - if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI - mem_rdata_q[14:12] <= 3'b111; - mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); - end - if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND - if (mem_rdata_latched[6:5] == 2'b00) mem_rdata_q[14:12] <= 3'b000; - if (mem_rdata_latched[6:5] == 2'b01) mem_rdata_q[14:12] <= 3'b100; - if (mem_rdata_latched[6:5] == 2'b10) mem_rdata_q[14:12] <= 3'b110; - if (mem_rdata_latched[6:5] == 2'b11) mem_rdata_q[14:12] <= 3'b111; - mem_rdata_q[31:25] <= mem_rdata_latched[6:5] == 2'b00 ? 7'b0100000 : 7'b0000000; - end - end - 3'b 110: begin // C.BEQZ - mem_rdata_q[14:12] <= 3'b000; - { mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <= - $signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2], - mem_rdata_latched[11:10], mem_rdata_latched[4:3]}); - end - 3'b 111: begin // C.BNEZ - mem_rdata_q[14:12] <= 3'b001; - { mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <= - $signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2], - mem_rdata_latched[11:10], mem_rdata_latched[4:3]}); - end - endcase - end - 2'b10: begin // Quadrant 2 - case (mem_rdata_latched[15:13]) - 3'b000: begin // C.SLLI - mem_rdata_q[31:25] <= 7'b0000000; - mem_rdata_q[14:12] <= 3'b 001; - end - 3'b010: begin // C.LWSP - mem_rdata_q[31:20] <= {4'b0, mem_rdata_latched[3:2], mem_rdata_latched[12], mem_rdata_latched[6:4], 2'b00}; - mem_rdata_q[14:12] <= 3'b 010; - end - 3'b100: begin - if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] == 0) begin // C.JR - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= 12'b0; - end - if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:25] <= 7'b0000000; - end - if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= 12'b0; - end - if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:25] <= 7'b0000000; - end - end - 3'b110: begin // C.SWSP - {mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {4'b0, mem_rdata_latched[8:7], mem_rdata_latched[12:9], 2'b00}; - mem_rdata_q[14:12] <= 3'b 010; - end - endcase - end - endcase - end - end - - always @(posedge clk) begin - if (resetn && !trap) begin - if (mem_do_prefetch || mem_do_rinst || mem_do_rdata) - `assert(!mem_do_wdata); - - if (mem_do_prefetch || mem_do_rinst) - `assert(!mem_do_rdata); - - if (mem_do_rdata) - `assert(!mem_do_prefetch && !mem_do_rinst); - - if (mem_do_wdata) - `assert(!(mem_do_prefetch || mem_do_rinst || mem_do_rdata)); - - if (mem_state == 2 || mem_state == 3) - `assert(mem_valid || mem_do_prefetch); - end - end - - always @(posedge clk) begin - if (!resetn || trap) begin - if (!resetn) - mem_state <= 0; - if (!resetn || mem_ready) - mem_valid <= 0; - mem_la_secondword <= 0; - prefetched_high_word <= 0; - end else begin - if (mem_la_read || mem_la_write) begin - mem_addr <= mem_la_addr; - mem_wstrb <= mem_la_wstrb & {4{mem_la_write}}; - end - if (mem_la_write) begin - mem_wdata <= mem_la_wdata; - end - case (mem_state) - 0: begin - if (mem_do_prefetch || mem_do_rinst || mem_do_rdata) begin - mem_valid <= !mem_la_use_prefetched_high_word; - mem_instr <= mem_do_prefetch || mem_do_rinst; - mem_wstrb <= 0; - mem_state <= 1; - end - if (mem_do_wdata) begin - mem_valid <= 1; - mem_instr <= 0; - mem_state <= 2; - end - end - 1: begin - `assert(mem_wstrb == 0); - `assert(mem_do_prefetch || mem_do_rinst || mem_do_rdata); - `assert(mem_valid == !mem_la_use_prefetched_high_word); - `assert(mem_instr == (mem_do_prefetch || mem_do_rinst)); - if (mem_xfer) begin - if (COMPRESSED_ISA && mem_la_read) begin - mem_valid <= 1; - mem_la_secondword <= 1; - if (!mem_la_use_prefetched_high_word) - mem_16bit_buffer <= mem_rdata[31:16]; - end else begin - mem_valid <= 0; - mem_la_secondword <= 0; - if (COMPRESSED_ISA && !mem_do_rdata) begin - if (~&mem_rdata[1:0] || mem_la_secondword) begin - mem_16bit_buffer <= mem_rdata[31:16]; - prefetched_high_word <= 1; - end else begin - prefetched_high_word <= 0; - end - end - mem_state <= mem_do_rinst || mem_do_rdata ? 0 : 3; - end - end - end - 2: begin - `assert(mem_wstrb != 0); - `assert(mem_do_wdata); - if (mem_xfer) begin - mem_valid <= 0; - mem_state <= 0; - end - end - 3: begin - `assert(mem_wstrb == 0); - `assert(mem_do_prefetch); - if (mem_do_rinst) begin - mem_state <= 0; - end - end - endcase - end - - if (clear_prefetched_high_word) - prefetched_high_word <= 0; - end - - - // Instruction Decoder - - reg instr_lui, instr_auipc, instr_jal, instr_jalr; - reg instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu; - reg instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw; - reg instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai; - reg instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and; - reg instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh, instr_ecall_ebreak; - reg instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer; - wire instr_trap; - - reg [regindex_bits-1:0] decoded_rd, decoded_rs1, decoded_rs2; - reg [31:0] decoded_imm, decoded_imm_uj; - reg decoder_trigger; - reg decoder_trigger_q; - reg decoder_pseudo_trigger; - reg decoder_pseudo_trigger_q; - reg compressed_instr; - - reg is_lui_auipc_jal; - reg is_lb_lh_lw_lbu_lhu; - reg is_slli_srli_srai; - reg is_jalr_addi_slti_sltiu_xori_ori_andi; - reg is_sb_sh_sw; - reg is_sll_srl_sra; - reg is_lui_auipc_jal_jalr_addi_add_sub; - reg is_slti_blt_slt; - reg is_sltiu_bltu_sltu; - reg is_beq_bne_blt_bge_bltu_bgeu; - reg is_lbu_lhu_lw; - reg is_alu_reg_imm; - reg is_alu_reg_reg; - reg is_compare; - - assign instr_trap = (CATCH_ILLINSN || WITH_PCPI) && !{instr_lui, instr_auipc, instr_jal, instr_jalr, - instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu, - instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw, - instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai, - instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and, - instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh, - instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer}; - - wire is_rdcycle_rdcycleh_rdinstr_rdinstrh; - assign is_rdcycle_rdcycleh_rdinstr_rdinstrh = |{instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh}; - - reg [63:0] new_ascii_instr; - `FORMAL_KEEP reg [63:0] dbg_ascii_instr; - `FORMAL_KEEP reg [31:0] dbg_insn_imm; - `FORMAL_KEEP reg [4:0] dbg_insn_rs1; - `FORMAL_KEEP reg [4:0] dbg_insn_rs2; - `FORMAL_KEEP reg [4:0] dbg_insn_rd; - `FORMAL_KEEP reg [31:0] dbg_rs1val; - `FORMAL_KEEP reg [31:0] dbg_rs2val; - `FORMAL_KEEP reg dbg_rs1val_valid; - `FORMAL_KEEP reg dbg_rs2val_valid; - - always @* begin - new_ascii_instr = ""; - - if (instr_lui) new_ascii_instr = "lui"; - if (instr_auipc) new_ascii_instr = "auipc"; - if (instr_jal) new_ascii_instr = "jal"; - if (instr_jalr) new_ascii_instr = "jalr"; - - if (instr_beq) new_ascii_instr = "beq"; - if (instr_bne) new_ascii_instr = "bne"; - if (instr_blt) new_ascii_instr = "blt"; - if (instr_bge) new_ascii_instr = "bge"; - if (instr_bltu) new_ascii_instr = "bltu"; - if (instr_bgeu) new_ascii_instr = "bgeu"; - - if (instr_lb) new_ascii_instr = "lb"; - if (instr_lh) new_ascii_instr = "lh"; - if (instr_lw) new_ascii_instr = "lw"; - if (instr_lbu) new_ascii_instr = "lbu"; - if (instr_lhu) new_ascii_instr = "lhu"; - if (instr_sb) new_ascii_instr = "sb"; - if (instr_sh) new_ascii_instr = "sh"; - if (instr_sw) new_ascii_instr = "sw"; - - if (instr_addi) new_ascii_instr = "addi"; - if (instr_slti) new_ascii_instr = "slti"; - if (instr_sltiu) new_ascii_instr = "sltiu"; - if (instr_xori) new_ascii_instr = "xori"; - if (instr_ori) new_ascii_instr = "ori"; - if (instr_andi) new_ascii_instr = "andi"; - if (instr_slli) new_ascii_instr = "slli"; - if (instr_srli) new_ascii_instr = "srli"; - if (instr_srai) new_ascii_instr = "srai"; - - if (instr_add) new_ascii_instr = "add"; - if (instr_sub) new_ascii_instr = "sub"; - if (instr_sll) new_ascii_instr = "sll"; - if (instr_slt) new_ascii_instr = "slt"; - if (instr_sltu) new_ascii_instr = "sltu"; - if (instr_xor) new_ascii_instr = "xor"; - if (instr_srl) new_ascii_instr = "srl"; - if (instr_sra) new_ascii_instr = "sra"; - if (instr_or) new_ascii_instr = "or"; - if (instr_and) new_ascii_instr = "and"; - - if (instr_rdcycle) new_ascii_instr = "rdcycle"; - if (instr_rdcycleh) new_ascii_instr = "rdcycleh"; - if (instr_rdinstr) new_ascii_instr = "rdinstr"; - if (instr_rdinstrh) new_ascii_instr = "rdinstrh"; - - if (instr_getq) new_ascii_instr = "getq"; - if (instr_setq) new_ascii_instr = "setq"; - if (instr_retirq) new_ascii_instr = "retirq"; - if (instr_maskirq) new_ascii_instr = "maskirq"; - if (instr_waitirq) new_ascii_instr = "waitirq"; - if (instr_timer) new_ascii_instr = "timer"; - end - - reg [63:0] q_ascii_instr; - reg [31:0] q_insn_imm; - reg [31:0] q_insn_opcode; - reg [4:0] q_insn_rs1; - reg [4:0] q_insn_rs2; - reg [4:0] q_insn_rd; - reg dbg_next; - - wire launch_next_insn; - reg dbg_valid_insn; - - reg [63:0] cached_ascii_instr; - reg [31:0] cached_insn_imm; - reg [31:0] cached_insn_opcode; - reg [4:0] cached_insn_rs1; - reg [4:0] cached_insn_rs2; - reg [4:0] cached_insn_rd; - - always @(posedge clk) begin - q_ascii_instr <= dbg_ascii_instr; - q_insn_imm <= dbg_insn_imm; - q_insn_opcode <= dbg_insn_opcode; - q_insn_rs1 <= dbg_insn_rs1; - q_insn_rs2 <= dbg_insn_rs2; - q_insn_rd <= dbg_insn_rd; - dbg_next <= launch_next_insn; - - if (!resetn || trap) - dbg_valid_insn <= 0; - else if (launch_next_insn) - dbg_valid_insn <= 1; - - if (decoder_trigger_q) begin - cached_ascii_instr <= new_ascii_instr; - cached_insn_imm <= decoded_imm; - if (&next_insn_opcode[1:0]) - cached_insn_opcode <= next_insn_opcode; - else - cached_insn_opcode <= {16'b0, next_insn_opcode[15:0]}; - cached_insn_rs1 <= decoded_rs1; - cached_insn_rs2 <= decoded_rs2; - cached_insn_rd <= decoded_rd; - end - - if (launch_next_insn) begin - dbg_insn_addr <= next_pc; - end - end - - always @* begin - dbg_ascii_instr = q_ascii_instr; - dbg_insn_imm = q_insn_imm; - dbg_insn_opcode = q_insn_opcode; - dbg_insn_rs1 = q_insn_rs1; - dbg_insn_rs2 = q_insn_rs2; - dbg_insn_rd = q_insn_rd; - - if (dbg_next) begin - if (decoder_pseudo_trigger_q) begin - dbg_ascii_instr = cached_ascii_instr; - dbg_insn_imm = cached_insn_imm; - dbg_insn_opcode = cached_insn_opcode; - dbg_insn_rs1 = cached_insn_rs1; - dbg_insn_rs2 = cached_insn_rs2; - dbg_insn_rd = cached_insn_rd; - end else begin - dbg_ascii_instr = new_ascii_instr; - if (&next_insn_opcode[1:0]) - dbg_insn_opcode = next_insn_opcode; - else - dbg_insn_opcode = {16'b0, next_insn_opcode[15:0]}; - dbg_insn_imm = decoded_imm; - dbg_insn_rs1 = decoded_rs1; - dbg_insn_rs2 = decoded_rs2; - dbg_insn_rd = decoded_rd; - end - end - end - -`ifdef DEBUGASM - always @(posedge clk) begin - if (dbg_next) begin - $display("debugasm %x %x %s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "*"); - end - end -`endif - -`ifdef DEBUG - always @(posedge clk) begin - if (dbg_next) begin - if (&dbg_insn_opcode[1:0]) - $display("DECODE: 0x%08x 0x%08x %-0s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN"); - else - $display("DECODE: 0x%08x 0x%04x %-0s", dbg_insn_addr, dbg_insn_opcode[15:0], dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN"); - end - end -`endif - - always @(posedge clk) begin - is_lui_auipc_jal <= |{instr_lui, instr_auipc, instr_jal}; - is_lui_auipc_jal_jalr_addi_add_sub <= |{instr_lui, instr_auipc, instr_jal, instr_jalr, instr_addi, instr_add, instr_sub}; - is_slti_blt_slt <= |{instr_slti, instr_blt, instr_slt}; - is_sltiu_bltu_sltu <= |{instr_sltiu, instr_bltu, instr_sltu}; - is_lbu_lhu_lw <= |{instr_lbu, instr_lhu, instr_lw}; - is_compare <= |{is_beq_bne_blt_bge_bltu_bgeu, instr_slti, instr_slt, instr_sltiu, instr_sltu}; - - if (mem_do_rinst && mem_done) begin - instr_lui <= mem_rdata_latched[6:0] == 7'b0110111; - instr_auipc <= mem_rdata_latched[6:0] == 7'b0010111; - instr_jal <= mem_rdata_latched[6:0] == 7'b1101111; - instr_jalr <= mem_rdata_latched[6:0] == 7'b1100111 && mem_rdata_latched[14:12] == 3'b000; - instr_retirq <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ; - instr_waitirq <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000100 && ENABLE_IRQ; - - is_beq_bne_blt_bge_bltu_bgeu <= mem_rdata_latched[6:0] == 7'b1100011; - is_lb_lh_lw_lbu_lhu <= mem_rdata_latched[6:0] == 7'b0000011; - is_sb_sh_sw <= mem_rdata_latched[6:0] == 7'b0100011; - is_alu_reg_imm <= mem_rdata_latched[6:0] == 7'b0010011; - is_alu_reg_reg <= mem_rdata_latched[6:0] == 7'b0110011; - - { decoded_imm_uj[31:20], decoded_imm_uj[10:1], decoded_imm_uj[11], decoded_imm_uj[19:12], decoded_imm_uj[0] } <= $signed({mem_rdata_latched[31:12], 1'b0}); - - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= mem_rdata_latched[19:15]; - decoded_rs2 <= mem_rdata_latched[24:20]; - - if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS) - decoded_rs1[regindex_bits-1] <= 1; // instr_getq - - if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ) - decoded_rs1 <= ENABLE_IRQ_QREGS ? irqregs_offset : 3; // instr_retirq - - compressed_instr <= 0; - if (COMPRESSED_ISA && mem_rdata_latched[1:0] != 2'b11) begin - compressed_instr <= 1; - decoded_rd <= 0; - decoded_rs1 <= 0; - decoded_rs2 <= 0; - - { decoded_imm_uj[31:11], decoded_imm_uj[4], decoded_imm_uj[9:8], decoded_imm_uj[10], decoded_imm_uj[6], - decoded_imm_uj[7], decoded_imm_uj[3:1], decoded_imm_uj[5], decoded_imm_uj[0] } <= $signed({mem_rdata_latched[12:2], 1'b0}); - - case (mem_rdata_latched[1:0]) - 2'b00: begin // Quadrant 0 - case (mem_rdata_latched[15:13]) - 3'b000: begin // C.ADDI4SPN - is_alu_reg_imm <= |mem_rdata_latched[12:5]; - decoded_rs1 <= 2; - decoded_rd <= 8 + mem_rdata_latched[4:2]; - end - 3'b010: begin // C.LW - is_lb_lh_lw_lbu_lhu <= 1; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rd <= 8 + mem_rdata_latched[4:2]; - end - 3'b110: begin // C.SW - is_sb_sh_sw <= 1; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rs2 <= 8 + mem_rdata_latched[4:2]; - end - endcase - end - 2'b01: begin // Quadrant 1 - case (mem_rdata_latched[15:13]) - 3'b000: begin // C.NOP / C.ADDI - is_alu_reg_imm <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= mem_rdata_latched[11:7]; - end - 3'b001: begin // C.JAL - instr_jal <= 1; - decoded_rd <= 1; - end - 3'b 010: begin // C.LI - is_alu_reg_imm <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= 0; - end - 3'b 011: begin - if (mem_rdata_latched[12] || mem_rdata_latched[6:2]) begin - if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP - is_alu_reg_imm <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= mem_rdata_latched[11:7]; - end else begin // C.LUI - instr_lui <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= 0; - end - end - end - 3'b100: begin - if (!mem_rdata_latched[11] && !mem_rdata_latched[12]) begin // C.SRLI, C.SRAI - is_alu_reg_imm <= 1; - decoded_rd <= 8 + mem_rdata_latched[9:7]; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]}; - end - if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI - is_alu_reg_imm <= 1; - decoded_rd <= 8 + mem_rdata_latched[9:7]; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - end - if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND - is_alu_reg_reg <= 1; - decoded_rd <= 8 + mem_rdata_latched[9:7]; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rs2 <= 8 + mem_rdata_latched[4:2]; - end - end - 3'b101: begin // C.J - instr_jal <= 1; - end - 3'b110: begin // C.BEQZ - is_beq_bne_blt_bge_bltu_bgeu <= 1; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rs2 <= 0; - end - 3'b111: begin // C.BNEZ - is_beq_bne_blt_bge_bltu_bgeu <= 1; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rs2 <= 0; - end - endcase - end - 2'b10: begin // Quadrant 2 - case (mem_rdata_latched[15:13]) - 3'b000: begin // C.SLLI - if (!mem_rdata_latched[12]) begin - is_alu_reg_imm <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= mem_rdata_latched[11:7]; - decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]}; - end - end - 3'b010: begin // C.LWSP - if (mem_rdata_latched[11:7]) begin - is_lb_lh_lw_lbu_lhu <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= 2; - end - end - 3'b100: begin - if (mem_rdata_latched[12] == 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JR - instr_jalr <= 1; - decoded_rd <= 0; - decoded_rs1 <= mem_rdata_latched[11:7]; - end - if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV - is_alu_reg_reg <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= 0; - decoded_rs2 <= mem_rdata_latched[6:2]; - end - if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR - instr_jalr <= 1; - decoded_rd <= 1; - decoded_rs1 <= mem_rdata_latched[11:7]; - end - if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD - is_alu_reg_reg <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= mem_rdata_latched[11:7]; - decoded_rs2 <= mem_rdata_latched[6:2]; - end - end - 3'b110: begin // C.SWSP - is_sb_sh_sw <= 1; - decoded_rs1 <= 2; - decoded_rs2 <= mem_rdata_latched[6:2]; - end - endcase - end - endcase - end - end - - if (decoder_trigger && !decoder_pseudo_trigger) begin - pcpi_insn <= WITH_PCPI ? mem_rdata_q : 'bx; - - instr_beq <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b000; - instr_bne <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b001; - instr_blt <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b100; - instr_bge <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b101; - instr_bltu <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b110; - instr_bgeu <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b111; - - instr_lb <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b000; - instr_lh <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b001; - instr_lw <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b010; - instr_lbu <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b100; - instr_lhu <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b101; - - instr_sb <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b000; - instr_sh <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b001; - instr_sw <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b010; - - instr_addi <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b000; - instr_slti <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b010; - instr_sltiu <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b011; - instr_xori <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b100; - instr_ori <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b110; - instr_andi <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b111; - - instr_slli <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000; - instr_srli <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000; - instr_srai <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000; - - instr_add <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0000000; - instr_sub <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0100000; - instr_sll <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000; - instr_slt <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b010 && mem_rdata_q[31:25] == 7'b0000000; - instr_sltu <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b011 && mem_rdata_q[31:25] == 7'b0000000; - instr_xor <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b100 && mem_rdata_q[31:25] == 7'b0000000; - instr_srl <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000; - instr_sra <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000; - instr_or <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b110 && mem_rdata_q[31:25] == 7'b0000000; - instr_and <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b111 && mem_rdata_q[31:25] == 7'b0000000; - - instr_rdcycle <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000000000010) || - (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000100000010)) && ENABLE_COUNTERS; - instr_rdcycleh <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000000000010) || - (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000100000010)) && ENABLE_COUNTERS && ENABLE_COUNTERS64; - instr_rdinstr <= (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000001000000010) && ENABLE_COUNTERS; - instr_rdinstrh <= (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000001000000010) && ENABLE_COUNTERS && ENABLE_COUNTERS64; - - instr_ecall_ebreak <= ((mem_rdata_q[6:0] == 7'b1110011 && !mem_rdata_q[31:21] && !mem_rdata_q[19:7]) || - (COMPRESSED_ISA && mem_rdata_q[15:0] == 16'h9002)); - - instr_getq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS; - instr_setq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000001 && ENABLE_IRQ && ENABLE_IRQ_QREGS; - instr_maskirq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000011 && ENABLE_IRQ; - instr_timer <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000101 && ENABLE_IRQ && ENABLE_IRQ_TIMER; - - is_slli_srli_srai <= is_alu_reg_imm && |{ - mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000, - mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000, - mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000 - }; - - is_jalr_addi_slti_sltiu_xori_ori_andi <= instr_jalr || is_alu_reg_imm && |{ - mem_rdata_q[14:12] == 3'b000, - mem_rdata_q[14:12] == 3'b010, - mem_rdata_q[14:12] == 3'b011, - mem_rdata_q[14:12] == 3'b100, - mem_rdata_q[14:12] == 3'b110, - mem_rdata_q[14:12] == 3'b111 - }; - - is_sll_srl_sra <= is_alu_reg_reg && |{ - mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000, - mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000, - mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000 - }; - - is_lui_auipc_jal_jalr_addi_add_sub <= 0; - is_compare <= 0; - - (* parallel_case *) - case (1'b1) - instr_jal: - decoded_imm <= decoded_imm_uj; - |{instr_lui, instr_auipc}: - decoded_imm <= mem_rdata_q[31:12] << 12; - |{instr_jalr, is_lb_lh_lw_lbu_lhu, is_alu_reg_imm}: - decoded_imm <= $signed(mem_rdata_q[31:20]); - is_beq_bne_blt_bge_bltu_bgeu: - decoded_imm <= $signed({mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8], 1'b0}); - is_sb_sh_sw: - decoded_imm <= $signed({mem_rdata_q[31:25], mem_rdata_q[11:7]}); - default: - decoded_imm <= 1'bx; - endcase - end - - if (!resetn) begin - is_beq_bne_blt_bge_bltu_bgeu <= 0; - is_compare <= 0; - - instr_beq <= 0; - instr_bne <= 0; - instr_blt <= 0; - instr_bge <= 0; - instr_bltu <= 0; - instr_bgeu <= 0; - - instr_addi <= 0; - instr_slti <= 0; - instr_sltiu <= 0; - instr_xori <= 0; - instr_ori <= 0; - instr_andi <= 0; - - instr_add <= 0; - instr_sub <= 0; - instr_sll <= 0; - instr_slt <= 0; - instr_sltu <= 0; - instr_xor <= 0; - instr_srl <= 0; - instr_sra <= 0; - instr_or <= 0; - instr_and <= 0; - end - end - - - // Main State Machine - - localparam cpu_state_trap = 8'b10000000; - localparam cpu_state_fetch = 8'b01000000; - localparam cpu_state_ld_rs1 = 8'b00100000; - localparam cpu_state_ld_rs2 = 8'b00010000; - localparam cpu_state_exec = 8'b00001000; - localparam cpu_state_shift = 8'b00000100; - localparam cpu_state_stmem = 8'b00000010; - localparam cpu_state_ldmem = 8'b00000001; - - reg [7:0] cpu_state; - reg [1:0] irq_state; - - `FORMAL_KEEP reg [127:0] dbg_ascii_state; - - always @* begin - dbg_ascii_state = ""; - if (cpu_state == cpu_state_trap) dbg_ascii_state = "trap"; - if (cpu_state == cpu_state_fetch) dbg_ascii_state = "fetch"; - if (cpu_state == cpu_state_ld_rs1) dbg_ascii_state = "ld_rs1"; - if (cpu_state == cpu_state_ld_rs2) dbg_ascii_state = "ld_rs2"; - if (cpu_state == cpu_state_exec) dbg_ascii_state = "exec"; - if (cpu_state == cpu_state_shift) dbg_ascii_state = "shift"; - if (cpu_state == cpu_state_stmem) dbg_ascii_state = "stmem"; - if (cpu_state == cpu_state_ldmem) dbg_ascii_state = "ldmem"; - end - - reg set_mem_do_rinst; - reg set_mem_do_rdata; - reg set_mem_do_wdata; - - reg latched_store; - reg latched_stalu; - reg latched_branch; - reg latched_compr; - reg latched_trace; - reg latched_is_lu; - reg latched_is_lh; - reg latched_is_lb; - reg [regindex_bits-1:0] latched_rd; - - reg [31:0] current_pc; - assign next_pc = latched_store && latched_branch ? reg_out & ~1 : reg_next_pc; - - reg [3:0] pcpi_timeout_counter; - reg pcpi_timeout; - - reg [31:0] next_irq_pending; - reg do_waitirq; - - reg [31:0] alu_out, alu_out_q; - reg alu_out_0, alu_out_0_q; - reg alu_wait, alu_wait_2; - - reg [31:0] alu_add_sub; - reg [31:0] alu_shl, alu_shr; - reg alu_eq, alu_ltu, alu_lts; - - generate if (TWO_CYCLE_ALU) begin - always @(posedge clk) begin - alu_add_sub <= instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2; - alu_eq <= reg_op1 == reg_op2; - alu_lts <= $signed(reg_op1) < $signed(reg_op2); - alu_ltu <= reg_op1 < reg_op2; - alu_shl <= reg_op1 << reg_op2[4:0]; - alu_shr <= $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0]; - end - end else begin - always @* begin - alu_add_sub = instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2; - alu_eq = reg_op1 == reg_op2; - alu_lts = $signed(reg_op1) < $signed(reg_op2); - alu_ltu = reg_op1 < reg_op2; - alu_shl = reg_op1 << reg_op2[4:0]; - alu_shr = $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0]; - end - end endgenerate - - always @* begin - alu_out_0 = 'bx; - (* parallel_case, full_case *) - case (1'b1) - instr_beq: - alu_out_0 = alu_eq; - instr_bne: - alu_out_0 = !alu_eq; - instr_bge: - alu_out_0 = !alu_lts; - instr_bgeu: - alu_out_0 = !alu_ltu; - is_slti_blt_slt && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}): - alu_out_0 = alu_lts; - is_sltiu_bltu_sltu && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}): - alu_out_0 = alu_ltu; - endcase - - alu_out = 'bx; - (* parallel_case, full_case *) - case (1'b1) - is_lui_auipc_jal_jalr_addi_add_sub: - alu_out = alu_add_sub; - is_compare: - alu_out = alu_out_0; - instr_xori || instr_xor: - alu_out = reg_op1 ^ reg_op2; - instr_ori || instr_or: - alu_out = reg_op1 | reg_op2; - instr_andi || instr_and: - alu_out = reg_op1 & reg_op2; - BARREL_SHIFTER && (instr_sll || instr_slli): - alu_out = alu_shl; - BARREL_SHIFTER && (instr_srl || instr_srli || instr_sra || instr_srai): - alu_out = alu_shr; - endcase - -`ifdef RISCV_FORMAL_BLACKBOX_ALU - alu_out_0 = $anyseq; - alu_out = $anyseq; -`endif - end - - reg clear_prefetched_high_word_q; - always @(posedge clk) clear_prefetched_high_word_q <= clear_prefetched_high_word; - - always @* begin - clear_prefetched_high_word = clear_prefetched_high_word_q; - if (!prefetched_high_word) - clear_prefetched_high_word = 0; - if (latched_branch || irq_state || !resetn) - clear_prefetched_high_word = COMPRESSED_ISA; - end - - reg cpuregs_write; - reg [31:0] cpuregs_wrdata; - reg [31:0] cpuregs_rs1; - reg [31:0] cpuregs_rs2; - reg [regindex_bits-1:0] decoded_rs; - - always @* begin - cpuregs_write = 0; - cpuregs_wrdata = 'bx; - - if (cpu_state == cpu_state_fetch) begin - (* parallel_case *) - case (1'b1) - latched_branch: begin - cpuregs_wrdata = reg_pc + (latched_compr ? 2 : 4); - cpuregs_write = 1; - end - latched_store && !latched_branch: begin - cpuregs_wrdata = latched_stalu ? alu_out_q : reg_out; - cpuregs_write = 1; - end - ENABLE_IRQ && irq_state[0]: begin - cpuregs_wrdata = reg_next_pc | latched_compr; - cpuregs_write = 1; - end - ENABLE_IRQ && irq_state[1]: begin - cpuregs_wrdata = irq_pending & ~irq_mask; - cpuregs_write = 1; - end - endcase - end - end - -`ifndef PICORV32_REGS - always @(posedge clk) begin - if (resetn && cpuregs_write && latched_rd) - cpuregs[latched_rd] <= cpuregs_wrdata; - end - - always @* begin - decoded_rs = 'bx; - if (ENABLE_REGS_DUALPORT) begin -`ifndef RISCV_FORMAL_BLACKBOX_REGS - cpuregs_rs1 = decoded_rs1 ? cpuregs[decoded_rs1] : 0; - cpuregs_rs2 = decoded_rs2 ? cpuregs[decoded_rs2] : 0; -`else - cpuregs_rs1 = decoded_rs1 ? $anyseq : 0; - cpuregs_rs2 = decoded_rs2 ? $anyseq : 0; -`endif - end else begin - decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1; -`ifndef RISCV_FORMAL_BLACKBOX_REGS - cpuregs_rs1 = decoded_rs ? cpuregs[decoded_rs] : 0; -`else - cpuregs_rs1 = decoded_rs ? $anyseq : 0; -`endif - cpuregs_rs2 = cpuregs_rs1; - end - end -`else - wire[31:0] cpuregs_rdata1; - wire[31:0] cpuregs_rdata2; - - wire [5:0] cpuregs_waddr = latched_rd; - wire [5:0] cpuregs_raddr1 = ENABLE_REGS_DUALPORT ? decoded_rs1 : decoded_rs; - wire [5:0] cpuregs_raddr2 = ENABLE_REGS_DUALPORT ? decoded_rs2 : 0; - - `PICORV32_REGS cpuregs ( - .clk(clk), - .wen(resetn && cpuregs_write && latched_rd), - .waddr(cpuregs_waddr), - .raddr1(cpuregs_raddr1), - .raddr2(cpuregs_raddr2), - .wdata(cpuregs_wrdata), - .rdata1(cpuregs_rdata1), - .rdata2(cpuregs_rdata2) - ); - - always @* begin - decoded_rs = 'bx; - if (ENABLE_REGS_DUALPORT) begin - cpuregs_rs1 = decoded_rs1 ? cpuregs_rdata1 : 0; - cpuregs_rs2 = decoded_rs2 ? cpuregs_rdata2 : 0; - end else begin - decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1; - cpuregs_rs1 = decoded_rs ? cpuregs_rdata1 : 0; - cpuregs_rs2 = cpuregs_rs1; - end - end -`endif - - assign launch_next_insn = cpu_state == cpu_state_fetch && decoder_trigger && (!ENABLE_IRQ || irq_delay || irq_active || !(irq_pending & ~irq_mask)); - - always @(posedge clk) begin - trap <= 0; - reg_sh <= 'bx; - reg_out <= 'bx; - set_mem_do_rinst = 0; - set_mem_do_rdata = 0; - set_mem_do_wdata = 0; - - alu_out_0_q <= alu_out_0; - alu_out_q <= alu_out; - - alu_wait <= 0; - alu_wait_2 <= 0; - - if (launch_next_insn) begin - dbg_rs1val <= 'bx; - dbg_rs2val <= 'bx; - dbg_rs1val_valid <= 0; - dbg_rs2val_valid <= 0; - end - - if (WITH_PCPI && CATCH_ILLINSN) begin - if (resetn && pcpi_valid && !pcpi_int_wait) begin - if (pcpi_timeout_counter) - pcpi_timeout_counter <= pcpi_timeout_counter - 1; - end else - pcpi_timeout_counter <= ~0; - pcpi_timeout <= !pcpi_timeout_counter; - end - - if (ENABLE_COUNTERS) begin - count_cycle <= resetn ? count_cycle + 1 : 0; - if (!ENABLE_COUNTERS64) count_cycle[63:32] <= 0; - end else begin - count_cycle <= 'bx; - count_instr <= 'bx; - end - - next_irq_pending = ENABLE_IRQ ? irq_pending & LATCHED_IRQ : 'bx; - - if (ENABLE_IRQ && ENABLE_IRQ_TIMER && timer) begin - if (timer - 1 == 0) - next_irq_pending[irq_timer] = 1; - timer <= timer - 1; - end - - if (ENABLE_IRQ) begin - next_irq_pending = next_irq_pending | irq; - end - - decoder_trigger <= mem_do_rinst && mem_done; - decoder_trigger_q <= decoder_trigger; - decoder_pseudo_trigger <= 0; - decoder_pseudo_trigger_q <= decoder_pseudo_trigger; - do_waitirq <= 0; - - trace_valid <= 0; - - if (!ENABLE_TRACE) - trace_data <= 'bx; - - if (!resetn) begin - reg_pc <= PROGADDR_RESET; - reg_next_pc <= PROGADDR_RESET; - if (ENABLE_COUNTERS) - count_instr <= 0; - latched_store <= 0; - latched_stalu <= 0; - latched_branch <= 0; - latched_trace <= 0; - latched_is_lu <= 0; - latched_is_lh <= 0; - latched_is_lb <= 0; - pcpi_valid <= 0; - pcpi_timeout <= 0; - irq_active <= 0; - irq_delay <= 0; - irq_mask <= ~0; - next_irq_pending = 0; - irq_state <= 0; - eoi <= 0; - timer <= 0; - if (~STACKADDR) begin - latched_store <= 1; - latched_rd <= 2; - reg_out <= STACKADDR; - end - cpu_state <= cpu_state_fetch; - end else - (* parallel_case, full_case *) - case (cpu_state) - cpu_state_trap: begin - trap <= 1; - end - - cpu_state_fetch: begin - mem_do_rinst <= !decoder_trigger && !do_waitirq; - mem_wordsize <= 0; - - current_pc = reg_next_pc; - - (* parallel_case *) - case (1'b1) - latched_branch: begin - current_pc = latched_store ? (latched_stalu ? alu_out_q : reg_out) & ~1 : reg_next_pc; - `debug($display("ST_RD: %2d 0x%08x, BRANCH 0x%08x", latched_rd, reg_pc + (latched_compr ? 2 : 4), current_pc);) - end - latched_store && !latched_branch: begin - `debug($display("ST_RD: %2d 0x%08x", latched_rd, latched_stalu ? alu_out_q : reg_out);) - end - ENABLE_IRQ && irq_state[0]: begin - current_pc = PROGADDR_IRQ; - irq_active <= 1; - mem_do_rinst <= 1; - end - ENABLE_IRQ && irq_state[1]: begin - eoi <= irq_pending & ~irq_mask; - next_irq_pending = next_irq_pending & irq_mask; - end - endcase - - if (ENABLE_TRACE && latched_trace) begin - latched_trace <= 0; - trace_valid <= 1; - if (latched_branch) - trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_BRANCH | (current_pc & 32'hfffffffe); - else - trace_data <= (irq_active ? TRACE_IRQ : 0) | (latched_stalu ? alu_out_q : reg_out); - end - - reg_pc <= current_pc; - reg_next_pc <= current_pc; - - latched_store <= 0; - latched_stalu <= 0; - latched_branch <= 0; - latched_is_lu <= 0; - latched_is_lh <= 0; - latched_is_lb <= 0; - latched_rd <= decoded_rd; - latched_compr <= compressed_instr; - - if (ENABLE_IRQ && ((decoder_trigger && !irq_active && !irq_delay && |(irq_pending & ~irq_mask)) || irq_state)) begin - irq_state <= - irq_state == 2'b00 ? 2'b01 : - irq_state == 2'b01 ? 2'b10 : 2'b00; - latched_compr <= latched_compr; - if (ENABLE_IRQ_QREGS) - latched_rd <= irqregs_offset | irq_state[0]; - else - latched_rd <= irq_state[0] ? 4 : 3; - end else - if (ENABLE_IRQ && (decoder_trigger || do_waitirq) && instr_waitirq) begin - if (irq_pending) begin - latched_store <= 1; - reg_out <= irq_pending; - reg_next_pc <= current_pc + (compressed_instr ? 2 : 4); - mem_do_rinst <= 1; - end else - do_waitirq <= 1; - end else - if (decoder_trigger) begin - `debug($display("-- %-0t", $time);) - irq_delay <= irq_active; - reg_next_pc <= current_pc + (compressed_instr ? 2 : 4); - if (ENABLE_TRACE) - latched_trace <= 1; - if (ENABLE_COUNTERS) begin - count_instr <= count_instr + 1; - if (!ENABLE_COUNTERS64) count_instr[63:32] <= 0; - end - if (instr_jal) begin - mem_do_rinst <= 1; - reg_next_pc <= current_pc + decoded_imm_uj; - latched_branch <= 1; - end else begin - mem_do_rinst <= 0; - mem_do_prefetch <= !instr_jalr && !instr_retirq; - cpu_state <= cpu_state_ld_rs1; - end - end - end - - cpu_state_ld_rs1: begin - reg_op1 <= 'bx; - reg_op2 <= 'bx; - - (* parallel_case *) - case (1'b1) - (CATCH_ILLINSN || WITH_PCPI) && instr_trap: begin - if (WITH_PCPI) begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_op1 <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - if (ENABLE_REGS_DUALPORT) begin - pcpi_valid <= 1; - `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) - reg_sh <= cpuregs_rs2; - reg_op2 <= cpuregs_rs2; - dbg_rs2val <= cpuregs_rs2; - dbg_rs2val_valid <= 1; - if (pcpi_int_ready) begin - mem_do_rinst <= 1; - pcpi_valid <= 0; - reg_out <= pcpi_int_rd; - latched_store <= pcpi_int_wr; - cpu_state <= cpu_state_fetch; - end else - if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin - pcpi_valid <= 0; - `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) - if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin - next_irq_pending[irq_ebreak] = 1; - cpu_state <= cpu_state_fetch; - end else - cpu_state <= cpu_state_trap; - end - end else begin - cpu_state <= cpu_state_ld_rs2; - end - end else begin - `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) - if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin - next_irq_pending[irq_ebreak] = 1; - cpu_state <= cpu_state_fetch; - end else - cpu_state <= cpu_state_trap; - end - end - ENABLE_COUNTERS && is_rdcycle_rdcycleh_rdinstr_rdinstrh: begin - (* parallel_case, full_case *) - case (1'b1) - instr_rdcycle: - reg_out <= count_cycle[31:0]; - instr_rdcycleh && ENABLE_COUNTERS64: - reg_out <= count_cycle[63:32]; - instr_rdinstr: - reg_out <= count_instr[31:0]; - instr_rdinstrh && ENABLE_COUNTERS64: - reg_out <= count_instr[63:32]; - endcase - latched_store <= 1; - cpu_state <= cpu_state_fetch; - end - is_lui_auipc_jal: begin - reg_op1 <= instr_lui ? 0 : reg_pc; - reg_op2 <= decoded_imm; - if (TWO_CYCLE_ALU) - alu_wait <= 1; - else - mem_do_rinst <= mem_do_prefetch; - cpu_state <= cpu_state_exec; - end - ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_getq: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_out <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - latched_store <= 1; - cpu_state <= cpu_state_fetch; - end - ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_setq: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_out <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - latched_rd <= latched_rd | irqregs_offset; - latched_store <= 1; - cpu_state <= cpu_state_fetch; - end - ENABLE_IRQ && instr_retirq: begin - eoi <= 0; - irq_active <= 0; - latched_branch <= 1; - latched_store <= 1; - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_out <= CATCH_MISALIGN ? (cpuregs_rs1 & 32'h fffffffe) : cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - cpu_state <= cpu_state_fetch; - end - ENABLE_IRQ && instr_maskirq: begin - latched_store <= 1; - reg_out <= irq_mask; - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - irq_mask <= cpuregs_rs1 | MASKED_IRQ; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - cpu_state <= cpu_state_fetch; - end - ENABLE_IRQ && ENABLE_IRQ_TIMER && instr_timer: begin - latched_store <= 1; - reg_out <= timer; - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - timer <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - cpu_state <= cpu_state_fetch; - end - is_lb_lh_lw_lbu_lhu && !instr_trap: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_op1 <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - cpu_state <= cpu_state_ldmem; - mem_do_rinst <= 1; - end - is_slli_srli_srai && !BARREL_SHIFTER: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_op1 <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - reg_sh <= decoded_rs2; - cpu_state <= cpu_state_shift; - end - is_jalr_addi_slti_sltiu_xori_ori_andi, is_slli_srli_srai && BARREL_SHIFTER: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_op1 <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - reg_op2 <= is_slli_srli_srai && BARREL_SHIFTER ? decoded_rs2 : decoded_imm; - if (TWO_CYCLE_ALU) - alu_wait <= 1; - else - mem_do_rinst <= mem_do_prefetch; - cpu_state <= cpu_state_exec; - end - default: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_op1 <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - if (ENABLE_REGS_DUALPORT) begin - `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) - reg_sh <= cpuregs_rs2; - reg_op2 <= cpuregs_rs2; - dbg_rs2val <= cpuregs_rs2; - dbg_rs2val_valid <= 1; - (* parallel_case *) - case (1'b1) - is_sb_sh_sw: begin - cpu_state <= cpu_state_stmem; - mem_do_rinst <= 1; - end - is_sll_srl_sra && !BARREL_SHIFTER: begin - cpu_state <= cpu_state_shift; - end - default: begin - if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin - alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu); - alu_wait <= 1; - end else - mem_do_rinst <= mem_do_prefetch; - cpu_state <= cpu_state_exec; - end - endcase - end else - cpu_state <= cpu_state_ld_rs2; - end - endcase - end - - cpu_state_ld_rs2: begin - `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) - reg_sh <= cpuregs_rs2; - reg_op2 <= cpuregs_rs2; - dbg_rs2val <= cpuregs_rs2; - dbg_rs2val_valid <= 1; - - (* parallel_case *) - case (1'b1) - WITH_PCPI && instr_trap: begin - pcpi_valid <= 1; - if (pcpi_int_ready) begin - mem_do_rinst <= 1; - pcpi_valid <= 0; - reg_out <= pcpi_int_rd; - latched_store <= pcpi_int_wr; - cpu_state <= cpu_state_fetch; - end else - if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin - pcpi_valid <= 0; - `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) - if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin - next_irq_pending[irq_ebreak] = 1; - cpu_state <= cpu_state_fetch; - end else - cpu_state <= cpu_state_trap; - end - end - is_sb_sh_sw: begin - cpu_state <= cpu_state_stmem; - mem_do_rinst <= 1; - end - is_sll_srl_sra && !BARREL_SHIFTER: begin - cpu_state <= cpu_state_shift; - end - default: begin - if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin - alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu); - alu_wait <= 1; - end else - mem_do_rinst <= mem_do_prefetch; - cpu_state <= cpu_state_exec; - end - endcase - end - - cpu_state_exec: begin - reg_out <= reg_pc + decoded_imm; - if ((TWO_CYCLE_ALU || TWO_CYCLE_COMPARE) && (alu_wait || alu_wait_2)) begin - mem_do_rinst <= mem_do_prefetch && !alu_wait_2; - alu_wait <= alu_wait_2; - end else - if (is_beq_bne_blt_bge_bltu_bgeu) begin - latched_rd <= 0; - latched_store <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0; - latched_branch <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0; - if (mem_done) - cpu_state <= cpu_state_fetch; - if (TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0) begin - decoder_trigger <= 0; - set_mem_do_rinst = 1; - end - end else begin - latched_branch <= instr_jalr; - latched_store <= 1; - latched_stalu <= 1; - cpu_state <= cpu_state_fetch; - end - end - - cpu_state_shift: begin - latched_store <= 1; - if (reg_sh == 0) begin - reg_out <= reg_op1; - mem_do_rinst <= mem_do_prefetch; - cpu_state <= cpu_state_fetch; - end else if (TWO_STAGE_SHIFT && reg_sh >= 4) begin - (* parallel_case, full_case *) - case (1'b1) - instr_slli || instr_sll: reg_op1 <= reg_op1 << 4; - instr_srli || instr_srl: reg_op1 <= reg_op1 >> 4; - instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 4; - endcase - reg_sh <= reg_sh - 4; - end else begin - (* parallel_case, full_case *) - case (1'b1) - instr_slli || instr_sll: reg_op1 <= reg_op1 << 1; - instr_srli || instr_srl: reg_op1 <= reg_op1 >> 1; - instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 1; - endcase - reg_sh <= reg_sh - 1; - end - end - - cpu_state_stmem: begin - if (ENABLE_TRACE) - reg_out <= reg_op2; - if (!mem_do_prefetch || mem_done) begin - if (!mem_do_wdata) begin - (* parallel_case, full_case *) - case (1'b1) - instr_sb: mem_wordsize <= 2; - instr_sh: mem_wordsize <= 1; - instr_sw: mem_wordsize <= 0; - endcase - if (ENABLE_TRACE) begin - trace_valid <= 1; - trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff); - end - reg_op1 <= reg_op1 + decoded_imm; - set_mem_do_wdata = 1; - end - if (!mem_do_prefetch && mem_done) begin - cpu_state <= cpu_state_fetch; - decoder_trigger <= 1; - decoder_pseudo_trigger <= 1; - end - end - end - - cpu_state_ldmem: begin - latched_store <= 1; - if (!mem_do_prefetch || mem_done) begin - if (!mem_do_rdata) begin - (* parallel_case, full_case *) - case (1'b1) - instr_lb || instr_lbu: mem_wordsize <= 2; - instr_lh || instr_lhu: mem_wordsize <= 1; - instr_lw: mem_wordsize <= 0; - endcase - latched_is_lu <= is_lbu_lhu_lw; - latched_is_lh <= instr_lh; - latched_is_lb <= instr_lb; - if (ENABLE_TRACE) begin - trace_valid <= 1; - trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff); - end - reg_op1 <= reg_op1 + decoded_imm; - set_mem_do_rdata = 1; - end - if (!mem_do_prefetch && mem_done) begin - (* parallel_case, full_case *) - case (1'b1) - latched_is_lu: reg_out <= mem_rdata_word; - latched_is_lh: reg_out <= $signed(mem_rdata_word[15:0]); - latched_is_lb: reg_out <= $signed(mem_rdata_word[7:0]); - endcase - decoder_trigger <= 1; - decoder_pseudo_trigger <= 1; - cpu_state <= cpu_state_fetch; - end - end - end - endcase - - if (CATCH_MISALIGN && resetn && (mem_do_rdata || mem_do_wdata)) begin - if (mem_wordsize == 0 && reg_op1[1:0] != 0) begin - `debug($display("MISALIGNED WORD: 0x%08x", reg_op1);) - if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin - next_irq_pending[irq_buserror] = 1; - end else - cpu_state <= cpu_state_trap; - end - if (mem_wordsize == 1 && reg_op1[0] != 0) begin - `debug($display("MISALIGNED HALFWORD: 0x%08x", reg_op1);) - if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin - next_irq_pending[irq_buserror] = 1; - end else - cpu_state <= cpu_state_trap; - end - end - if (CATCH_MISALIGN && resetn && mem_do_rinst && (COMPRESSED_ISA ? reg_pc[0] : |reg_pc[1:0])) begin - `debug($display("MISALIGNED INSTRUCTION: 0x%08x", reg_pc);) - if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin - next_irq_pending[irq_buserror] = 1; - end else - cpu_state <= cpu_state_trap; - end - if (!CATCH_ILLINSN && decoder_trigger_q && !decoder_pseudo_trigger_q && instr_ecall_ebreak) begin - cpu_state <= cpu_state_trap; - end - - if (!resetn || mem_done) begin - mem_do_prefetch <= 0; - mem_do_rinst <= 0; - mem_do_rdata <= 0; - mem_do_wdata <= 0; - end - - if (set_mem_do_rinst) - mem_do_rinst <= 1; - if (set_mem_do_rdata) - mem_do_rdata <= 1; - if (set_mem_do_wdata) - mem_do_wdata <= 1; - - irq_pending <= next_irq_pending & ~MASKED_IRQ; - - if (!CATCH_MISALIGN) begin - if (COMPRESSED_ISA) begin - reg_pc[0] <= 0; - reg_next_pc[0] <= 0; - end else begin - reg_pc[1:0] <= 0; - reg_next_pc[1:0] <= 0; - end - end - current_pc = 'bx; - end - -`ifdef RISCV_FORMAL - reg dbg_irq_call; - reg dbg_irq_enter; - reg [31:0] dbg_irq_ret; - always @(posedge clk) begin - rvfi_valid <= resetn && (launch_next_insn || trap) && dbg_valid_insn; - rvfi_order <= resetn ? rvfi_order + rvfi_valid : 0; - - rvfi_insn <= dbg_insn_opcode; - rvfi_rs1_addr <= dbg_rs1val_valid ? dbg_insn_rs1 : 0; - rvfi_rs2_addr <= dbg_rs2val_valid ? dbg_insn_rs2 : 0; - rvfi_pc_rdata <= dbg_insn_addr; - rvfi_rs1_rdata <= dbg_rs1val_valid ? dbg_rs1val : 0; - rvfi_rs2_rdata <= dbg_rs2val_valid ? dbg_rs2val : 0; - rvfi_trap <= trap; - rvfi_halt <= trap; - rvfi_intr <= dbg_irq_enter; - - if (!resetn) begin - dbg_irq_call <= 0; - dbg_irq_enter <= 0; - end else - if (rvfi_valid) begin - dbg_irq_call <= 0; - dbg_irq_enter <= dbg_irq_call; - end else - if (irq_state == 1) begin - dbg_irq_call <= 1; - dbg_irq_ret <= next_pc; - end - - if (!resetn) begin - rvfi_rd_addr <= 0; - rvfi_rd_wdata <= 0; - end else - if (cpuregs_write && !irq_state) begin - rvfi_rd_addr <= latched_rd; - rvfi_rd_wdata <= latched_rd ? cpuregs_wrdata : 0; - end else - if (rvfi_valid) begin - rvfi_rd_addr <= 0; - rvfi_rd_wdata <= 0; - end - - casez (dbg_insn_opcode) - 32'b 0000000_?????_000??_???_?????_0001011: begin // getq - rvfi_rs1_addr <= 0; - rvfi_rs1_rdata <= 0; - end - 32'b 0000001_?????_?????_???_000??_0001011: begin // setq - rvfi_rd_addr <= 0; - rvfi_rd_wdata <= 0; - end - 32'b 0000010_?????_00000_???_00000_0001011: begin // retirq - rvfi_rs1_addr <= 0; - rvfi_rs1_rdata <= 0; - end - endcase - - if (!dbg_irq_call) begin - if (dbg_mem_instr) begin - rvfi_mem_addr <= 0; - rvfi_mem_rmask <= 0; - rvfi_mem_wmask <= 0; - rvfi_mem_rdata <= 0; - rvfi_mem_wdata <= 0; - end else - if (dbg_mem_valid && dbg_mem_ready) begin - rvfi_mem_addr <= dbg_mem_addr; - rvfi_mem_rmask <= dbg_mem_wstrb ? 0 : ~0; - rvfi_mem_wmask <= dbg_mem_wstrb; - rvfi_mem_rdata <= dbg_mem_rdata; - rvfi_mem_wdata <= dbg_mem_wdata; - end - end - end - - always @* begin - rvfi_pc_wdata = dbg_irq_call ? dbg_irq_ret : dbg_insn_addr; - end -`endif - - // Formal Verification -`ifdef FORMAL - reg [3:0] last_mem_nowait; - always @(posedge clk) - last_mem_nowait <= {last_mem_nowait, mem_ready || !mem_valid}; - - // stall the memory interface for max 4 cycles - restrict property (|last_mem_nowait || mem_ready || !mem_valid); - - // resetn low in first cycle, after that resetn high - restrict property (resetn != $initstate); - - // this just makes it much easier to read traces. uncomment as needed. - // assume property (mem_valid || !mem_ready); - - reg ok; - always @* begin - if (resetn) begin - // instruction fetches are read-only - if (mem_valid && mem_instr) - assert (mem_wstrb == 0); - - // cpu_state must be valid - ok = 0; - if (cpu_state == cpu_state_trap) ok = 1; - if (cpu_state == cpu_state_fetch) ok = 1; - if (cpu_state == cpu_state_ld_rs1) ok = 1; - if (cpu_state == cpu_state_ld_rs2) ok = !ENABLE_REGS_DUALPORT; - if (cpu_state == cpu_state_exec) ok = 1; - if (cpu_state == cpu_state_shift) ok = 1; - if (cpu_state == cpu_state_stmem) ok = 1; - if (cpu_state == cpu_state_ldmem) ok = 1; - assert (ok); - end - end - - reg last_mem_la_read = 0; - reg last_mem_la_write = 0; - reg [31:0] last_mem_la_addr; - reg [31:0] last_mem_la_wdata; - reg [3:0] last_mem_la_wstrb = 0; - - always @(posedge clk) begin - last_mem_la_read <= mem_la_read; - last_mem_la_write <= mem_la_write; - last_mem_la_addr <= mem_la_addr; - last_mem_la_wdata <= mem_la_wdata; - last_mem_la_wstrb <= mem_la_wstrb; - - if (last_mem_la_read) begin - assert(mem_valid); - assert(mem_addr == last_mem_la_addr); - assert(mem_wstrb == 0); - end - if (last_mem_la_write) begin - assert(mem_valid); - assert(mem_addr == last_mem_la_addr); - assert(mem_wdata == last_mem_la_wdata); - assert(mem_wstrb == last_mem_la_wstrb); - end - if (mem_la_read || mem_la_write) begin - assert(!mem_valid || mem_ready); - end - end -`endif -endmodule - -// This is a simple example implementation of PICORV32_REGS. -// Use the PICORV32_REGS mechanism if you want to use custom -// memory resources to implement the processor register file. -// Note that your implementation must match the requirements of -// the PicoRV32 configuration. (e.g. QREGS, etc) -module picorv32_regs ( - input clk, wen, - input [5:0] waddr, - input [5:0] raddr1, - input [5:0] raddr2, - input [31:0] wdata, - output [31:0] rdata1, - output [31:0] rdata2 -); - reg [31:0] regs [0:30]; - - always @(posedge clk) - if (wen) regs[~waddr[4:0]] <= wdata; - - assign rdata1 = regs[~raddr1[4:0]]; - assign rdata2 = regs[~raddr2[4:0]]; -endmodule - - -/*************************************************************** - * picorv32_pcpi_mul - ***************************************************************/ - -module picorv32_pcpi_mul #( - parameter STEPS_AT_ONCE = 1, - parameter CARRY_CHAIN = 4 -) ( - input clk, resetn, - - input pcpi_valid, - input [31:0] pcpi_insn, - input [31:0] pcpi_rs1, - input [31:0] pcpi_rs2, - output reg pcpi_wr, - output reg [31:0] pcpi_rd, - output reg pcpi_wait, - output reg pcpi_ready -); - reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu; - wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu}; - wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu}; - wire instr_rs1_signed = |{instr_mulh, instr_mulhsu}; - wire instr_rs2_signed = |{instr_mulh}; - - reg pcpi_wait_q; - wire mul_start = pcpi_wait && !pcpi_wait_q; - - always @(posedge clk) begin - instr_mul <= 0; - instr_mulh <= 0; - instr_mulhsu <= 0; - instr_mulhu <= 0; - - if (resetn && pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin - case (pcpi_insn[14:12]) - 3'b000: instr_mul <= 1; - 3'b001: instr_mulh <= 1; - 3'b010: instr_mulhsu <= 1; - 3'b011: instr_mulhu <= 1; - endcase - end - - pcpi_wait <= instr_any_mul; - pcpi_wait_q <= pcpi_wait; - end - - reg [63:0] rs1, rs2, rd, rdx; - reg [63:0] next_rs1, next_rs2, this_rs2; - reg [63:0] next_rd, next_rdx, next_rdt; - reg [6:0] mul_counter; - reg mul_waiting; - reg mul_finish; - integer i, j; - - // carry save accumulator - always @* begin - next_rd = rd; - next_rdx = rdx; - next_rs1 = rs1; - next_rs2 = rs2; - - for (i = 0; i < STEPS_AT_ONCE; i=i+1) begin - this_rs2 = next_rs1[0] ? next_rs2 : 0; - if (CARRY_CHAIN == 0) begin - next_rdt = next_rd ^ next_rdx ^ this_rs2; - next_rdx = ((next_rd & next_rdx) | (next_rd & this_rs2) | (next_rdx & this_rs2)) << 1; - next_rd = next_rdt; - end else begin - next_rdt = 0; - for (j = 0; j < 64; j = j + CARRY_CHAIN) - {next_rdt[j+CARRY_CHAIN-1], next_rd[j +: CARRY_CHAIN]} = - next_rd[j +: CARRY_CHAIN] + next_rdx[j +: CARRY_CHAIN] + this_rs2[j +: CARRY_CHAIN]; - next_rdx = next_rdt << 1; - end - next_rs1 = next_rs1 >> 1; - next_rs2 = next_rs2 << 1; - end - end - - always @(posedge clk) begin - mul_finish <= 0; - if (!resetn) begin - mul_waiting <= 1; - end else - if (mul_waiting) begin - if (instr_rs1_signed) - rs1 <= $signed(pcpi_rs1); - else - rs1 <= $unsigned(pcpi_rs1); - - if (instr_rs2_signed) - rs2 <= $signed(pcpi_rs2); - else - rs2 <= $unsigned(pcpi_rs2); - - rd <= 0; - rdx <= 0; - mul_counter <= (instr_any_mulh ? 63 - STEPS_AT_ONCE : 31 - STEPS_AT_ONCE); - mul_waiting <= !mul_start; - end else begin - rd <= next_rd; - rdx <= next_rdx; - rs1 <= next_rs1; - rs2 <= next_rs2; - - mul_counter <= mul_counter - STEPS_AT_ONCE; - if (mul_counter[6]) begin - mul_finish <= 1; - mul_waiting <= 1; - end - end - end - - always @(posedge clk) begin - pcpi_wr <= 0; - pcpi_ready <= 0; - if (mul_finish && resetn) begin - pcpi_wr <= 1; - pcpi_ready <= 1; - pcpi_rd <= instr_any_mulh ? rd >> 32 : rd; - end - end -endmodule - -module picorv32_pcpi_fast_mul #( - parameter EXTRA_MUL_FFS = 0, - parameter EXTRA_INSN_FFS = 0, - parameter MUL_CLKGATE = 0 -) ( - input clk, resetn, - - input pcpi_valid, - input [31:0] pcpi_insn, - input [31:0] pcpi_rs1, - input [31:0] pcpi_rs2, - output pcpi_wr, - output [31:0] pcpi_rd, - output pcpi_wait, - output pcpi_ready -); - reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu; - wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu}; - wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu}; - wire instr_rs1_signed = |{instr_mulh, instr_mulhsu}; - wire instr_rs2_signed = |{instr_mulh}; - - reg shift_out; - reg [3:0] active; - reg [32:0] rs1, rs2, rs1_q, rs2_q; - reg [63:0] rd, rd_q; - - wire pcpi_insn_valid = pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001; - reg pcpi_insn_valid_q; - - always @* begin - instr_mul = 0; - instr_mulh = 0; - instr_mulhsu = 0; - instr_mulhu = 0; - - if (resetn && (EXTRA_INSN_FFS ? pcpi_insn_valid_q : pcpi_insn_valid)) begin - case (pcpi_insn[14:12]) - 3'b000: instr_mul = 1; - 3'b001: instr_mulh = 1; - 3'b010: instr_mulhsu = 1; - 3'b011: instr_mulhu = 1; - endcase - end - end - - always @(posedge clk) begin - pcpi_insn_valid_q <= pcpi_insn_valid; - if (!MUL_CLKGATE || active[0]) begin - rs1_q <= rs1; - rs2_q <= rs2; - end - if (!MUL_CLKGATE || active[1]) begin - rd <= $signed(EXTRA_MUL_FFS ? rs1_q : rs1) * $signed(EXTRA_MUL_FFS ? rs2_q : rs2); - end - if (!MUL_CLKGATE || active[2]) begin - rd_q <= rd; - end - end - - always @(posedge clk) begin - if (instr_any_mul && !(EXTRA_MUL_FFS ? active[3:0] : active[1:0])) begin - if (instr_rs1_signed) - rs1 <= $signed(pcpi_rs1); - else - rs1 <= $unsigned(pcpi_rs1); - - if (instr_rs2_signed) - rs2 <= $signed(pcpi_rs2); - else - rs2 <= $unsigned(pcpi_rs2); - active[0] <= 1; - end else begin - active[0] <= 0; - end - - active[3:1] <= active; - shift_out <= instr_any_mulh; - - if (!resetn) - active <= 0; - end - - assign pcpi_wr = active[EXTRA_MUL_FFS ? 3 : 1]; - assign pcpi_wait = 0; - assign pcpi_ready = active[EXTRA_MUL_FFS ? 3 : 1]; -`ifdef RISCV_FORMAL_ALTOPS - assign pcpi_rd = - instr_mul ? (pcpi_rs1 + pcpi_rs2) ^ 32'h5876063e : - instr_mulh ? (pcpi_rs1 + pcpi_rs2) ^ 32'hf6583fb7 : - instr_mulhsu ? (pcpi_rs1 - pcpi_rs2) ^ 32'hecfbe137 : - instr_mulhu ? (pcpi_rs1 + pcpi_rs2) ^ 32'h949ce5e8 : 1'bx; -`else - assign pcpi_rd = shift_out ? (EXTRA_MUL_FFS ? rd_q : rd) >> 32 : (EXTRA_MUL_FFS ? rd_q : rd); -`endif -endmodule - - -/*************************************************************** - * picorv32_pcpi_div - ***************************************************************/ - -module picorv32_pcpi_div ( - input clk, resetn, - - input pcpi_valid, - input [31:0] pcpi_insn, - input [31:0] pcpi_rs1, - input [31:0] pcpi_rs2, - output reg pcpi_wr, - output reg [31:0] pcpi_rd, - output reg pcpi_wait, - output reg pcpi_ready -); - reg instr_div, instr_divu, instr_rem, instr_remu; - wire instr_any_div_rem = |{instr_div, instr_divu, instr_rem, instr_remu}; - - reg pcpi_wait_q; - wire start = pcpi_wait && !pcpi_wait_q; - - always @(posedge clk) begin - instr_div <= 0; - instr_divu <= 0; - instr_rem <= 0; - instr_remu <= 0; - - if (resetn && pcpi_valid && !pcpi_ready && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin - case (pcpi_insn[14:12]) - 3'b100: instr_div <= 1; - 3'b101: instr_divu <= 1; - 3'b110: instr_rem <= 1; - 3'b111: instr_remu <= 1; - endcase - end - - pcpi_wait <= instr_any_div_rem && resetn; - pcpi_wait_q <= pcpi_wait && resetn; - end - - reg [31:0] dividend; - reg [62:0] divisor; - reg [31:0] quotient; - reg [31:0] quotient_msk; - reg running; - reg outsign; - - always @(posedge clk) begin - pcpi_ready <= 0; - pcpi_wr <= 0; - pcpi_rd <= 'bx; - - if (!resetn) begin - running <= 0; - end else - if (start) begin - running <= 1; - dividend <= (instr_div || instr_rem) && pcpi_rs1[31] ? -pcpi_rs1 : pcpi_rs1; - divisor <= ((instr_div || instr_rem) && pcpi_rs2[31] ? -pcpi_rs2 : pcpi_rs2) << 31; - outsign <= (instr_div && (pcpi_rs1[31] != pcpi_rs2[31]) && |pcpi_rs2) || (instr_rem && pcpi_rs1[31]); - quotient <= 0; - quotient_msk <= 1 << 31; - end else - if (!quotient_msk && running) begin - running <= 0; - pcpi_ready <= 1; - pcpi_wr <= 1; -`ifdef RISCV_FORMAL_ALTOPS - case (1) - instr_div: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h7f8529ec; - instr_divu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h10e8fd70; - instr_rem: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h8da68fa5; - instr_remu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h3138d0e1; - endcase -`else - if (instr_div || instr_divu) - pcpi_rd <= outsign ? -quotient : quotient; - else - pcpi_rd <= outsign ? -dividend : dividend; -`endif - end else begin - if (divisor <= dividend) begin - dividend <= dividend - divisor; - quotient <= quotient | quotient_msk; - end - divisor <= divisor >> 1; -`ifdef RISCV_FORMAL_ALTOPS - quotient_msk <= quotient_msk >> 5; -`else - quotient_msk <= quotient_msk >> 1; -`endif - end - end -endmodule - - -/*************************************************************** - * picorv32_axi - ***************************************************************/ - -module picorv32_axi #( - parameter [ 0:0] ENABLE_COUNTERS = 1, - parameter [ 0:0] ENABLE_COUNTERS64 = 1, - parameter [ 0:0] ENABLE_REGS_16_31 = 1, - parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, - parameter [ 0:0] TWO_STAGE_SHIFT = 1, - parameter [ 0:0] BARREL_SHIFTER = 0, - parameter [ 0:0] TWO_CYCLE_COMPARE = 0, - parameter [ 0:0] TWO_CYCLE_ALU = 0, - parameter [ 0:0] COMPRESSED_ISA = 0, - parameter [ 0:0] CATCH_MISALIGN = 1, - parameter [ 0:0] CATCH_ILLINSN = 1, - parameter [ 0:0] ENABLE_PCPI = 0, - parameter [ 0:0] ENABLE_MUL = 0, - parameter [ 0:0] ENABLE_FAST_MUL = 0, - parameter [ 0:0] ENABLE_DIV = 0, - parameter [ 0:0] ENABLE_IRQ = 0, - parameter [ 0:0] ENABLE_IRQ_QREGS = 1, - parameter [ 0:0] ENABLE_IRQ_TIMER = 1, - parameter [ 0:0] ENABLE_TRACE = 0, - parameter [ 0:0] REGS_INIT_ZERO = 0, - parameter [31:0] MASKED_IRQ = 32'h 0000_0000, - parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, - parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, - parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, - parameter [31:0] STACKADDR = 32'h ffff_ffff -) ( - input clk, resetn, - output trap, - - // AXI4-lite master memory interface - - output mem_axi_awvalid, - input mem_axi_awready, - output [31:0] mem_axi_awaddr, - output [ 2:0] mem_axi_awprot, - - output mem_axi_wvalid, - input mem_axi_wready, - output [31:0] mem_axi_wdata, - output [ 3:0] mem_axi_wstrb, - - input mem_axi_bvalid, - output mem_axi_bready, - - output mem_axi_arvalid, - input mem_axi_arready, - output [31:0] mem_axi_araddr, - output [ 2:0] mem_axi_arprot, - - input mem_axi_rvalid, - output mem_axi_rready, - input [31:0] mem_axi_rdata, - - // Pico Co-Processor Interface (PCPI) - output pcpi_valid, - output [31:0] pcpi_insn, - output [31:0] pcpi_rs1, - output [31:0] pcpi_rs2, - input pcpi_wr, - input [31:0] pcpi_rd, - input pcpi_wait, - input pcpi_ready, - - // IRQ interface - input [31:0] irq, - output [31:0] eoi, - -`ifdef RISCV_FORMAL - output rvfi_valid, - output [63:0] rvfi_order, - output [31:0] rvfi_insn, - output rvfi_trap, - output rvfi_halt, - output rvfi_intr, - output [ 4:0] rvfi_rs1_addr, - output [ 4:0] rvfi_rs2_addr, - output [31:0] rvfi_rs1_rdata, - output [31:0] rvfi_rs2_rdata, - output [ 4:0] rvfi_rd_addr, - output [31:0] rvfi_rd_wdata, - output [31:0] rvfi_pc_rdata, - output [31:0] rvfi_pc_wdata, - output [31:0] rvfi_mem_addr, - output [ 3:0] rvfi_mem_rmask, - output [ 3:0] rvfi_mem_wmask, - output [31:0] rvfi_mem_rdata, - output [31:0] rvfi_mem_wdata, -`endif - - // Trace Interface - output trace_valid, - output [35:0] trace_data -); - wire mem_valid; - wire [31:0] mem_addr; - wire [31:0] mem_wdata; - wire [ 3:0] mem_wstrb; - wire mem_instr; - wire mem_ready; - wire [31:0] mem_rdata; - - picorv32_axi_adapter axi_adapter ( - .clk (clk ), - .resetn (resetn ), - .mem_axi_awvalid(mem_axi_awvalid), - .mem_axi_awready(mem_axi_awready), - .mem_axi_awaddr (mem_axi_awaddr ), - .mem_axi_awprot (mem_axi_awprot ), - .mem_axi_wvalid (mem_axi_wvalid ), - .mem_axi_wready (mem_axi_wready ), - .mem_axi_wdata (mem_axi_wdata ), - .mem_axi_wstrb (mem_axi_wstrb ), - .mem_axi_bvalid (mem_axi_bvalid ), - .mem_axi_bready (mem_axi_bready ), - .mem_axi_arvalid(mem_axi_arvalid), - .mem_axi_arready(mem_axi_arready), - .mem_axi_araddr (mem_axi_araddr ), - .mem_axi_arprot (mem_axi_arprot ), - .mem_axi_rvalid (mem_axi_rvalid ), - .mem_axi_rready (mem_axi_rready ), - .mem_axi_rdata (mem_axi_rdata ), - .mem_valid (mem_valid ), - .mem_instr (mem_instr ), - .mem_ready (mem_ready ), - .mem_addr (mem_addr ), - .mem_wdata (mem_wdata ), - .mem_wstrb (mem_wstrb ), - .mem_rdata (mem_rdata ) - ); - - picorv32 #( - .ENABLE_COUNTERS (ENABLE_COUNTERS ), - .ENABLE_COUNTERS64 (ENABLE_COUNTERS64 ), - .ENABLE_REGS_16_31 (ENABLE_REGS_16_31 ), - .ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT), - .TWO_STAGE_SHIFT (TWO_STAGE_SHIFT ), - .BARREL_SHIFTER (BARREL_SHIFTER ), - .TWO_CYCLE_COMPARE (TWO_CYCLE_COMPARE ), - .TWO_CYCLE_ALU (TWO_CYCLE_ALU ), - .COMPRESSED_ISA (COMPRESSED_ISA ), - .CATCH_MISALIGN (CATCH_MISALIGN ), - .CATCH_ILLINSN (CATCH_ILLINSN ), - .ENABLE_PCPI (ENABLE_PCPI ), - .ENABLE_MUL (ENABLE_MUL ), - .ENABLE_FAST_MUL (ENABLE_FAST_MUL ), - .ENABLE_DIV (ENABLE_DIV ), - .ENABLE_IRQ (ENABLE_IRQ ), - .ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ), - .ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ), - .ENABLE_TRACE (ENABLE_TRACE ), - .REGS_INIT_ZERO (REGS_INIT_ZERO ), - .MASKED_IRQ (MASKED_IRQ ), - .LATCHED_IRQ (LATCHED_IRQ ), - .PROGADDR_RESET (PROGADDR_RESET ), - .PROGADDR_IRQ (PROGADDR_IRQ ), - .STACKADDR (STACKADDR ) - ) picorv32_core ( - .clk (clk ), - .resetn (resetn), - .trap (trap ), - - .mem_valid(mem_valid), - .mem_addr (mem_addr ), - .mem_wdata(mem_wdata), - .mem_wstrb(mem_wstrb), - .mem_instr(mem_instr), - .mem_ready(mem_ready), - .mem_rdata(mem_rdata), - - .pcpi_valid(pcpi_valid), - .pcpi_insn (pcpi_insn ), - .pcpi_rs1 (pcpi_rs1 ), - .pcpi_rs2 (pcpi_rs2 ), - .pcpi_wr (pcpi_wr ), - .pcpi_rd (pcpi_rd ), - .pcpi_wait (pcpi_wait ), - .pcpi_ready(pcpi_ready), - - .irq(irq), - .eoi(eoi), - -`ifdef RISCV_FORMAL - .rvfi_valid (rvfi_valid ), - .rvfi_order (rvfi_order ), - .rvfi_insn (rvfi_insn ), - .rvfi_trap (rvfi_trap ), - .rvfi_halt (rvfi_halt ), - .rvfi_intr (rvfi_intr ), - .rvfi_rs1_addr (rvfi_rs1_addr ), - .rvfi_rs2_addr (rvfi_rs2_addr ), - .rvfi_rs1_rdata(rvfi_rs1_rdata), - .rvfi_rs2_rdata(rvfi_rs2_rdata), - .rvfi_rd_addr (rvfi_rd_addr ), - .rvfi_rd_wdata (rvfi_rd_wdata ), - .rvfi_pc_rdata (rvfi_pc_rdata ), - .rvfi_pc_wdata (rvfi_pc_wdata ), - .rvfi_mem_addr (rvfi_mem_addr ), - .rvfi_mem_rmask(rvfi_mem_rmask), - .rvfi_mem_wmask(rvfi_mem_wmask), - .rvfi_mem_rdata(rvfi_mem_rdata), - .rvfi_mem_wdata(rvfi_mem_wdata), -`endif - - .trace_valid(trace_valid), - .trace_data (trace_data) - ); -endmodule - - -/*************************************************************** - * picorv32_axi_adapter - ***************************************************************/ - -module picorv32_axi_adapter ( - input clk, resetn, - - // AXI4-lite master memory interface - - output mem_axi_awvalid, - input mem_axi_awready, - output [31:0] mem_axi_awaddr, - output [ 2:0] mem_axi_awprot, - - output mem_axi_wvalid, - input mem_axi_wready, - output [31:0] mem_axi_wdata, - output [ 3:0] mem_axi_wstrb, - - input mem_axi_bvalid, - output mem_axi_bready, - - output mem_axi_arvalid, - input mem_axi_arready, - output [31:0] mem_axi_araddr, - output [ 2:0] mem_axi_arprot, - - input mem_axi_rvalid, - output mem_axi_rready, - input [31:0] mem_axi_rdata, - - // Native PicoRV32 memory interface - - input mem_valid, - input mem_instr, - output mem_ready, - input [31:0] mem_addr, - input [31:0] mem_wdata, - input [ 3:0] mem_wstrb, - output [31:0] mem_rdata -); - reg ack_awvalid; - reg ack_arvalid; - reg ack_wvalid; - reg xfer_done; - - assign mem_axi_awvalid = mem_valid && |mem_wstrb && !ack_awvalid; - assign mem_axi_awaddr = mem_addr; - assign mem_axi_awprot = 0; - - assign mem_axi_arvalid = mem_valid && !mem_wstrb && !ack_arvalid; - assign mem_axi_araddr = mem_addr; - assign mem_axi_arprot = mem_instr ? 3'b100 : 3'b000; - - assign mem_axi_wvalid = mem_valid && |mem_wstrb && !ack_wvalid; - assign mem_axi_wdata = mem_wdata; - assign mem_axi_wstrb = mem_wstrb; - - assign mem_ready = mem_axi_bvalid || mem_axi_rvalid; - assign mem_axi_bready = mem_valid && |mem_wstrb; - assign mem_axi_rready = mem_valid && !mem_wstrb; - assign mem_rdata = mem_axi_rdata; - - always @(posedge clk) begin - if (!resetn) begin - ack_awvalid <= 0; - end else begin - xfer_done <= mem_valid && mem_ready; - if (mem_axi_awready && mem_axi_awvalid) - ack_awvalid <= 1; - if (mem_axi_arready && mem_axi_arvalid) - ack_arvalid <= 1; - if (mem_axi_wready && mem_axi_wvalid) - ack_wvalid <= 1; - if (xfer_done || !mem_valid) begin - ack_awvalid <= 0; - ack_arvalid <= 0; - ack_wvalid <= 0; - end - end - end -endmodule - - -/*************************************************************** - * picorv32_wb - ***************************************************************/ - -module picorv32_wb #( - parameter [ 0:0] ENABLE_COUNTERS = 1, - parameter [ 0:0] ENABLE_COUNTERS64 = 1, - parameter [ 0:0] ENABLE_REGS_16_31 = 1, - parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, - parameter [ 0:0] TWO_STAGE_SHIFT = 1, - parameter [ 0:0] BARREL_SHIFTER = 0, - parameter [ 0:0] TWO_CYCLE_COMPARE = 0, - parameter [ 0:0] TWO_CYCLE_ALU = 0, - parameter [ 0:0] COMPRESSED_ISA = 0, - parameter [ 0:0] CATCH_MISALIGN = 1, - parameter [ 0:0] CATCH_ILLINSN = 1, - parameter [ 0:0] ENABLE_PCPI = 0, - parameter [ 0:0] ENABLE_MUL = 0, - parameter [ 0:0] ENABLE_FAST_MUL = 0, - parameter [ 0:0] ENABLE_DIV = 0, - parameter [ 0:0] ENABLE_IRQ = 0, - parameter [ 0:0] ENABLE_IRQ_QREGS = 1, - parameter [ 0:0] ENABLE_IRQ_TIMER = 1, - parameter [ 0:0] ENABLE_TRACE = 0, - parameter [ 0:0] REGS_INIT_ZERO = 0, - parameter [31:0] MASKED_IRQ = 32'h 0000_0000, - parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, - parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, - parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, - parameter [31:0] STACKADDR = 32'h ffff_ffff -) ( - output trap, - - // Wishbone interfaces - input wb_rst_i, - input wb_clk_i, - - output reg [31:0] wbm_adr_o, - output reg [31:0] wbm_dat_o, - input [31:0] wbm_dat_i, - output reg wbm_we_o, - output reg [3:0] wbm_sel_o, - output reg wbm_stb_o, - input wbm_ack_i, - output reg wbm_cyc_o, - - // Pico Co-Processor Interface (PCPI) - output pcpi_valid, - output [31:0] pcpi_insn, - output [31:0] pcpi_rs1, - output [31:0] pcpi_rs2, - input pcpi_wr, - input [31:0] pcpi_rd, - input pcpi_wait, - input pcpi_ready, - - // IRQ interface - input [31:0] irq, - output [31:0] eoi, - -`ifdef RISCV_FORMAL - output rvfi_valid, - output [63:0] rvfi_order, - output [31:0] rvfi_insn, - output rvfi_trap, - output rvfi_halt, - output rvfi_intr, - output [ 4:0] rvfi_rs1_addr, - output [ 4:0] rvfi_rs2_addr, - output [31:0] rvfi_rs1_rdata, - output [31:0] rvfi_rs2_rdata, - output [ 4:0] rvfi_rd_addr, - output [31:0] rvfi_rd_wdata, - output [31:0] rvfi_pc_rdata, - output [31:0] rvfi_pc_wdata, - output [31:0] rvfi_mem_addr, - output [ 3:0] rvfi_mem_rmask, - output [ 3:0] rvfi_mem_wmask, - output [31:0] rvfi_mem_rdata, - output [31:0] rvfi_mem_wdata, -`endif - - // Trace Interface - output trace_valid, - output [35:0] trace_data, - - output mem_instr -); - wire mem_valid; - wire [31:0] mem_addr; - wire [31:0] mem_wdata; - wire [ 3:0] mem_wstrb; - reg mem_ready; - reg [31:0] mem_rdata; - - wire clk; - wire resetn; - - assign clk = wb_clk_i; - assign resetn = ~wb_rst_i; - - picorv32 #( - .ENABLE_COUNTERS (ENABLE_COUNTERS ), - .ENABLE_COUNTERS64 (ENABLE_COUNTERS64 ), - .ENABLE_REGS_16_31 (ENABLE_REGS_16_31 ), - .ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT), - .TWO_STAGE_SHIFT (TWO_STAGE_SHIFT ), - .BARREL_SHIFTER (BARREL_SHIFTER ), - .TWO_CYCLE_COMPARE (TWO_CYCLE_COMPARE ), - .TWO_CYCLE_ALU (TWO_CYCLE_ALU ), - .COMPRESSED_ISA (COMPRESSED_ISA ), - .CATCH_MISALIGN (CATCH_MISALIGN ), - .CATCH_ILLINSN (CATCH_ILLINSN ), - .ENABLE_PCPI (ENABLE_PCPI ), - .ENABLE_MUL (ENABLE_MUL ), - .ENABLE_FAST_MUL (ENABLE_FAST_MUL ), - .ENABLE_DIV (ENABLE_DIV ), - .ENABLE_IRQ (ENABLE_IRQ ), - .ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ), - .ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ), - .ENABLE_TRACE (ENABLE_TRACE ), - .REGS_INIT_ZERO (REGS_INIT_ZERO ), - .MASKED_IRQ (MASKED_IRQ ), - .LATCHED_IRQ (LATCHED_IRQ ), - .PROGADDR_RESET (PROGADDR_RESET ), - .PROGADDR_IRQ (PROGADDR_IRQ ), - .STACKADDR (STACKADDR ) - ) picorv32_core ( - .clk (clk ), - .resetn (resetn), - .trap (trap ), - - .mem_valid(mem_valid), - .mem_addr (mem_addr ), - .mem_wdata(mem_wdata), - .mem_wstrb(mem_wstrb), - .mem_instr(mem_instr), - .mem_ready(mem_ready), - .mem_rdata(mem_rdata), - - .pcpi_valid(pcpi_valid), - .pcpi_insn (pcpi_insn ), - .pcpi_rs1 (pcpi_rs1 ), - .pcpi_rs2 (pcpi_rs2 ), - .pcpi_wr (pcpi_wr ), - .pcpi_rd (pcpi_rd ), - .pcpi_wait (pcpi_wait ), - .pcpi_ready(pcpi_ready), - - .irq(irq), - .eoi(eoi), - -`ifdef RISCV_FORMAL - .rvfi_valid (rvfi_valid ), - .rvfi_order (rvfi_order ), - .rvfi_insn (rvfi_insn ), - .rvfi_trap (rvfi_trap ), - .rvfi_halt (rvfi_halt ), - .rvfi_intr (rvfi_intr ), - .rvfi_rs1_addr (rvfi_rs1_addr ), - .rvfi_rs2_addr (rvfi_rs2_addr ), - .rvfi_rs1_rdata(rvfi_rs1_rdata), - .rvfi_rs2_rdata(rvfi_rs2_rdata), - .rvfi_rd_addr (rvfi_rd_addr ), - .rvfi_rd_wdata (rvfi_rd_wdata ), - .rvfi_pc_rdata (rvfi_pc_rdata ), - .rvfi_pc_wdata (rvfi_pc_wdata ), - .rvfi_mem_addr (rvfi_mem_addr ), - .rvfi_mem_rmask(rvfi_mem_rmask), - .rvfi_mem_wmask(rvfi_mem_wmask), - .rvfi_mem_rdata(rvfi_mem_rdata), - .rvfi_mem_wdata(rvfi_mem_wdata), -`endif - - .trace_valid(trace_valid), - .trace_data (trace_data) - ); - - localparam IDLE = 2'b00; - localparam WBSTART = 2'b01; - localparam WBEND = 2'b10; - - reg [1:0] state; - - wire we; - assign we = (mem_wstrb[0] | mem_wstrb[1] | mem_wstrb[2] | mem_wstrb[3]); - - always @(posedge wb_clk_i) begin - if (wb_rst_i) begin - wbm_adr_o <= 0; - wbm_dat_o <= 0; - wbm_we_o <= 0; - wbm_sel_o <= 0; - wbm_stb_o <= 0; - wbm_cyc_o <= 0; - state <= IDLE; - end else begin - case (state) - IDLE: begin - if (mem_valid) begin - wbm_adr_o <= mem_addr; - wbm_dat_o <= mem_wdata; - wbm_we_o <= we; - wbm_sel_o <= mem_wstrb; - - wbm_stb_o <= 1'b1; - wbm_cyc_o <= 1'b1; - state <= WBSTART; - end else begin - mem_ready <= 1'b0; - - wbm_stb_o <= 1'b0; - wbm_cyc_o <= 1'b0; - wbm_we_o <= 1'b0; - end - end - WBSTART:begin - if (wbm_ack_i) begin - mem_rdata <= wbm_dat_i; - mem_ready <= 1'b1; - - state <= WBEND; - - wbm_stb_o <= 1'b0; - wbm_cyc_o <= 1'b0; - wbm_we_o <= 1'b0; - end - end - WBEND: begin - mem_ready <= 1'b0; - - state <= IDLE; - end - default: - state <= IDLE; - endcase - end - end -endmodule diff --git a/fuzzers/007-timing/sub2csv.py b/fuzzers/007-timing/sub2csv.py deleted file mode 100644 index 48322dff..00000000 --- a/fuzzers/007-timing/sub2csv.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import Benchmark -import json - - -def write_state(state, fout): - j = { - 'names': dict([(x, None) for x in state.names]), - 'drop_names': list(state.drop_names), - 'base_names': list(state.base_names), - 'subs': dict([(name, values) for name, values in state.subs.items()]), - 'pivots': state.pivots, - } - json.dump(j, fout, sort_keys=True, indent=4, separators=(',', ': ')) - - -def gen_rows(fn_ins): - for fn_in in fn_ins: - try: - print('Loading %s' % fn_in) - j = json.load(open(fn_in, 'r')) - - group0 = list(j['subs'].values())[0] - value0 = list(group0.values())[0] - if type(value0) is float: - print("WARNING: skipping old format JSON") - continue - else: - print("Value OK") - - for sub in j['subs'].values(): - row_ds = {} - # TODO: convert to gcd - # den may not always be 0 - # lazy solution...just multiply out all the fractions - n = 1 - for _var, (_num, den) in sub.items(): - n *= den - - for var, (num, den) in sub.items(): - num2 = n * num - assert num2 % den == 0 - row_ds[var] = num2 / den - yield row_ds - except: - print("Error processing %s" % fn_in) - raise - - -def run(fnout, fn_ins, verbose=0): - print('Loading data') - - with open(fnout, 'w') as fout: - fout.write('ico,fast_max fast_min slow_max slow_min,rows...\n') - for row_ds in gen_rows(fn_ins): - ico = '1' - out_b = [1e9, 1e9, 1e9, 1e9] - items = [ico, ' '.join(['%u' % x for x in out_b])] - - for k, v in sorted(row_ds.items()): - items.append('%i %s' % (v, k)) - fout.write(','.join(items) + '\n') - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description= - 'Convert substitution groups into .csv to allow incremental rref results' - ) - - parser.add_argument('--verbose', action='store_true', help='') - parser.add_argument('--out', help='Output csv') - parser.add_argument('fns_in', nargs='+', help='sub.json input files') - args = parser.parse_args() - bench = Benchmark() - - fns_in = args.fns_in - - try: - run(fnout=args.out, fn_ins=args.fns_in, verbose=args.verbose) - finally: - print('Exiting after %s' % bench) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/tile_annotate.py b/fuzzers/007-timing/tile_annotate.py deleted file mode 100644 index e989d9a2..00000000 --- a/fuzzers/007-timing/tile_annotate.py +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env python3 - -import timfuz -from timfuz import loadc_Ads_bs, Ads2bounds, PREFIX_W, PREFIX_P, PREFIX_SW_EI, PREFIX_SW_EO, PREFIX_SW_I, sw_ei_s2vals, sw_eo_s2vals, sw_i_s2vals - -import sys -import os -import time -import json - - -def add_pip_wire(tilej, bounds, verbose=False): - ''' - We know all possible pips and wires from tilej - Iterate over them and see if a result was generated - ''' - used_bounds = set() - - for tile in tilej['tiles'].values(): - - def addk(pws, prefix, k, v): - variable = prefix + ':' + v - val = bounds.get(variable, None) - # print(variable, val) - if val: - used_bounds.add(variable) - else: - val = [None, None, None, None] - pws[k] = val - - pips = tile['pips'] - for k, v in pips.items(): - #pips[k] = bounds.get('PIP_' + v, [None, None, None, None]) - addk(pips, PREFIX_P, k, v) - - wires = tile['wires'] - for k, v in wires.items(): - #wires[k] = bounds.get('WIRE_' + v, [None, None, None, None]) - addk(wires, PREFIX_W, k, v) - - # verify all the variables that should be used were applied - # ...except tilecon may be an ROI and we solved everything - print( - "Interconnect: %u / %u variables used" % - (len(used_bounds), len(bounds))) - if verbose: - print('Remainder: %s' % (set(bounds.keys()) - used_bounds)) - - -def add_sites(tilej, bounds): - # XXX: no source of truth currently - # is there a way we could get this? - # Naming discussion https://github.com/SymbiFlow/prjxray/pull/126 - - sitej = tilej.setdefault('sites', {}) - - def add_ei(): - for variable, bound in bounds[PREFIX_SW_EI].items(): - site_type, src_site_pin, dst_bel_type, dst_bel_pin = sw_ei_s2vals( - variable) - # ex: SLICEL:AX->AFF.D - k = ( - '%s:%s->%s.%s' % - (site_type, src_site_pin, dst_bel_type, dst_bel_pin)) - sitej.setdefault(site_type, {})[k] = bound - - def add_eo(): - for variable, bound in bounds[PREFIX_SW_EO].items(): - site_type, src_bel_type, src_bel_pin, dst_site_pin = sw_eo_s2vals( - variable) - # ex: SLICEL:AFF.Q->AQ - k = ( - '%s:%s.%s->%s' % - (site_type, src_bel_type, src_bel_pin, dst_site_pin)) - sitej.setdefault(site_type, {})[k] = bound - - def add_i(): - for variable, bound in bounds[PREFIX_SW_I].items(): - site_type, src_bel, src_bel_pin, dst_bel, dst_bel_pin = sw_i_s2vals( - variable) - # ex: SLICEL:LUT6.O2->AFF.D - k = ( - '%s:%s.%s->%s.%s' % - (site_type, src_bel, src_bel_pin, dst_bel, dst_bel_pin)) - sitej.setdefault(site_type, {})[k] = bound - - add_ei() - add_eo() - add_i() - print('Sites: added %u sites' % len(sitej)) - print('Added site wires') - print(' Site external in: %u' % len(bounds[PREFIX_SW_EI])) - print(' Site external out: %u' % len(bounds[PREFIX_SW_EO])) - print(' Site internal: %u' % len(bounds[PREFIX_SW_I])) - - -def sep_bounds(bounds): - pw = {} - sites = {PREFIX_SW_EI: {}, PREFIX_SW_EO: {}, PREFIX_SW_I: {}} - for k, v in bounds.items(): - prefix = k.split(':')[0] - if prefix in (PREFIX_W, PREFIX_P): - pw[k] = v - elif prefix in (PREFIX_SW_EI, PREFIX_SW_EO, PREFIX_SW_I): - sites[prefix][k] = v - else: - assert 0, 'Unknown delay: %s %s' % (k, prefix) - return pw, sites - - -def run(fns_in, fnout, tile_json_fn, verbose=False): - # modified in place - tilej = json.load(open(tile_json_fn, 'r')) - - for fnin in fns_in: - Ads, bs = loadc_Ads_bs([fnin]) - bounds = Ads2bounds(Ads, bs) - bounds_pw, bounds_sites = sep_bounds(bounds) - print(len(bounds), len(bounds_pw), len(bounds_sites)) - - add_pip_wire(tilej, bounds_pw) - add_sites(tilej, bounds_sites) - - timfuz.tilej_stats(tilej) - - json.dump( - tilej, - open(fnout, 'w'), - sort_keys=True, - indent=4, - separators=(',', ': ')) - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description= - 'Substitute timgrid timing model names for real timing values') - parser.add_argument( - '--timgrid-s', - default='../../timgrid/build/timgrid-s.json', - help='tilegrid timing delay symbolic input (timgrid-s.json)') - parser.add_argument( - '--out', - default='build/timgrid-vc.json', - help='tilegrid timing delay values at corner (timgrid-vc.json)') - parser.add_argument( - 'fn_ins', nargs='+', help='Input flattened timing csv (flat.csv)') - args = parser.parse_args() - - run(args.fn_ins, args.out, args.timgrid_s, verbose=False) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/timfuz.py b/fuzzers/007-timing/timfuz.py deleted file mode 100644 index d380e525..00000000 --- a/fuzzers/007-timing/timfuz.py +++ /dev/null @@ -1,844 +0,0 @@ -#!/usr/bin/env python - -import math -import numpy as np -from collections import OrderedDict -import time -import re -import os -import datetime -import json -import copy -import sys -import random -import glob -from fractions import Fraction -import collections - -from benchmark import Benchmark - -# prefix to make easier to track -# models do not overlap between PIPs and WIREs -PREFIX_W = 'WIRE' -PREFIX_P = 'PIP' -# extneral site wire (ie site a to b) -PREFIX_SW_EI = 'SITEW-EI' -PREFIX_SW_EO = 'SITEW-EO' -# internal site wire (ie bel a to b within a site) -PREFIX_SW_I = 'SITEW-I' - - -def sw_ei_vals2s(site_type, src_site_pin, dst_bel, dst_bel_pin): - '''Pack site wire components into a variable string''' - return '%s:%s:%s:%s:%s' % ( - PREFIX_SW_EI, site_type, src_site_pin, dst_bel, dst_bel_pin) - - -def sw_ei_s2vals(s): - prefix, site_type, src_site_pin, dst_bel, dst_bel_pin = s.split(':') - assert prefix == PREFIX_SW_EI - return site_type, src_site_pin, dst_bel, dst_bel_pin - - -def sw_eo_vals2s(site_type, src_bel, src_bel_pin, dst_site_pin): - return '%s:%s:%s:%s:%s' % ( - PREFIX_SW_EO, site_type, src_bel, src_bel_pin, dst_site_pin) - - -def sw_eo_s2vals(s): - prefix, site_type, src_bel, src_bel_pin, dst_site_pin = s.split(':') - assert prefix == PREFIX_SW_EO - return site_type, src_bel, src_bel_pin, dst_site_pin - - -def sw_i_vals2s(site_type, src_bel, src_bel_pin, dst_bel, dst_bel_pin): - return '%s:%s:%s:%s:%s:%s' % ( - PREFIX_SW_I, site_type, src_bel, src_bel_pin, dst_bel, dst_bel_pin) - - -def sw_i_s2vals(s): - prefix, site_type, src_bel, src_bel_pin, dst_bel, dst_bel_pin = s.split( - ':') - assert prefix == PREFIX_SW_I - return site_type, src_bel, src_bel_pin, dst_bel, dst_bel_pin - - -# Equations are filtered out until nothing is left -class SimplifiedToZero(Exception): - pass - - -# http://code.activestate.com/recipes/576694/ -class OrderedSet(collections.MutableSet): - def __init__(self, iterable=None): - self.end = end = [] - end += [None, end, end] # sentinel node for doubly linked list - self.map = {} # key --> [key, prev, next] - if iterable is not None: - self |= iterable - - def __len__(self): - return len(self.map) - - def __contains__(self, key): - return key in self.map - - def add(self, key): - if key not in self.map: - end = self.end - curr = end[1] - curr[2] = end[1] = self.map[key] = [key, curr, end] - - def discard(self, key): - if key in self.map: - key, prev, next = self.map.pop(key) - prev[2] = next - next[1] = prev - - def __iter__(self): - end = self.end - curr = end[2] - while curr is not end: - yield curr[0] - curr = curr[2] - - def __reversed__(self): - end = self.end - curr = end[1] - while curr is not end: - yield curr[0] - curr = curr[1] - - def pop(self, last=True): - if not self: - raise KeyError('set is empty') - key = self.end[1][0] if last else self.end[2][0] - self.discard(key) - return key - - def __repr__(self): - if not self: - return '%s()' % (self.__class__.__name__, ) - return '%s(%r)' % (self.__class__.__name__, list(self)) - - def __eq__(self, other): - if isinstance(other, OrderedSet): - return len(self) == len(other) and list(self) == list(other) - return set(self) == set(other) - - -NAME_ZERO = OrderedSet( - [ - "BSW_CLK_ZERO", - "BSW_ZERO", - "B_ZERO", - "C_CLK_ZERO", - "C_DSP_ZERO", - "C_ZERO", - "I_ZERO", - "O_ZERO", - "RC_ZERO", - "R_ZERO", - ]) - -# csv index -corner_s2i = OrderedDict( - [ - ('fast_max', 0), - ('fast_min', 1), - ('slow_max', 2), - ('slow_min', 3), - ]) - - -def allow_zero_eqns(): - '''If true, allow a system of equations with no equations''' - return os.getenv('ALLOW_ZERO_EQN', 'N') == 'Y' - - -def print_eqns(A_ubd, b_ub, verbose=0, lim=3, label=''): - rows = len(b_ub) - - print('Sample equations (%s) from %d r' % (label, rows)) - prints = 0 - #verbose = 1 - for rowi, row in enumerate(A_ubd): - if verbose or ((rowi < 10 or rowi % max(1, (rows / 20)) == 0) and - (not lim or prints < lim)): - line = ' EQN: p%u: ' % rowi - for k, v in sorted(row.items()): - line += '%u*t%d ' % (v, k) - line += '= %d' % b_ub[rowi] - print(line) - prints += 1 - - -def print_name_eqns(A_ubd, b_ub, names, verbose=0, lim=3, label=''): - rows = len(b_ub) - - print('Sample equations (%s) from %d r' % (label, rows)) - prints = 0 - #verbose = 1 - for rowi, row in enumerate(A_ubd): - if verbose or ((rowi < 10 or rowi % max(1, (rows / 20)) == 0) and - (not lim or prints < lim)): - line = ' EQN: p%u: ' % rowi - for k, v in sorted(row.items()): - line += '%u*%s ' % (v, names[k]) - line += '= %d' % b_ub[rowi] - print(line) - prints += 1 - - -def print_names(names, verbose=1): - print('Names: %d' % len(names)) - for xi, name in enumerate(names): - print(' % 4u % -80s' % (xi, name)) - - -def invb(b_ub): - #return [-b for b in b_ub] - return -np.array(b_ub) - - -def check_feasible_d(A_ubd, b_ub, names): - A_ub, b_ub_inv = Ab_d2np(A_ubd, b_ub, names) - check_feasible(A_ub, b_ub_inv) - - -def check_feasible(A_ub, b_ub): - sys.stdout.write('Check feasible ') - sys.stdout.flush() - - rows = len(b_ub) - cols = len(A_ub[0]) - - progress = max(1, rows / 100) - - # Chose a high arbitrary value for x - # Delays should be in order of ns, so a 10 ns delay should be way above what anything should be - xs = [10e3 for _i in range(cols)] - - # FIXME: use the correct np function to do this for me - # Verify bounds - #b_res = np.matmul(A_ub, xs) - #print(type(A_ub), type(xs) - #A_ub = np.array(A_ub) - #xs = np.array(xs) - #b_res = np.matmul(A_ub, xs) - def my_mul(A_ub, xs): - #print('cols', cols - #print('rows', rows - ret = [None] * rows - for row in range(rows): - this = 0 - for col in range(cols): - this += A_ub[row][col] * xs[col] - ret[row] = this - return ret - - b_res = my_mul(A_ub, xs) - - # Verify bound was respected - for rowi, (this_b, this_b_ub) in enumerate(zip(b_res, b_ub)): - if rowi % progress == 0: - sys.stdout.write('.') - sys.stdout.flush() - if this_b >= this_b_ub or this_b > 0: - print( - '% 4d Want res % 10.1f <= % 10.1f <= 0' % - (rowi, this_b, this_b_ub)) - raise Exception("Bad ") - print(' done') - - -def Ab_ub_dt2d(eqns): - '''Convert dict using the rows as keys into a list of dicts + b_ub list (ie return A_ub, b_ub)''' - #return [dict(rowt) for rowt in eqns] - rows = [(OrderedDict(rowt), b) for rowt, b in eqns.items()] - A_ubd, b_ub = zip(*rows) - return list(A_ubd), list(b_ub) - - -# This significantly reduces runtime -def simplify_rows(Ads, b_ub, remove_zd=False, corner=None): - '''Remove duplicate equations, taking highest delay''' - # dict of constants to highest delay - eqns = OrderedDict() - assert len(Ads) == len(b_ub), (len(Ads), len(b_ub)) - - assert corner is not None - minmax = { - 'fast_max': max, - 'fast_min': min, - 'slow_max': max, - 'slow_min': min, - }[corner] - # An outlier to make unknown values be ignored - T_UNK = { - 'fast_max': 0, - 'fast_min': 10e9, - 'slow_max': 0, - 'slow_min': 10e9, - }[corner] - - sys.stdout.write('SimpR ') - sys.stdout.flush() - progress = int(max(1, len(b_ub) / 100)) - # Equations with a total delay of zero - zero_ds = 0 - # Equations with zero elements - # These should have zero delay - zero_es = 0 - for loopi, (b, rowd) in enumerate(zip(b_ub, Ads)): - if loopi % progress == 0: - sys.stdout.write('.') - sys.stdout.flush() - - if remove_zd and not b: - zero_ds += 1 - continue - - # think ran into these before when taking out ZERO elements - if len(rowd) == 0: - if b != 0: - assert zero_es == 0, 'Unexpected zero element row with non-zero delay' - zero_es += 1 - continue - ''' - Reduce any constants to canonical form - this simplifies later steps that optimize based on assuming there aren't duplicate constants - - Ex: - a = 10 - 2 a = 30 - max corner will get simplified to - a = 15 - - Otherwise these are not identical equations and would not get simplied - Don't try handling the general case of non-trivial equations - ''' - if len(rowd) == 1: - k, v = list(rowd.items())[0] - if v != 1: - rowd = {k: 1} - b = 1.0 * b / v - - rowt = Ar_ds2t(rowd) - eqns[rowt] = minmax(eqns.get(rowt, T_UNK), b) - - print(' done') - - print( - 'Simplify rows: %d => %d rows w/ rm zd %d, rm ze %d' % - (len(b_ub), len(eqns), zero_ds, zero_es)) - if len(eqns) == 0: - raise SimplifiedToZero() - A_ubd_ret, b_ub_ret = Ab_ub_dt2d(eqns) - #print_eqns(A_ubd_ret, b_ub_ret, verbose=True, label='Debug') - return A_ubd_ret, b_ub_ret - - -def A_ubr_np2d(row): - '''Convert a single row''' - #d = {} - d = OrderedDict() - for coli, val in enumerate(row): - if val: - d[coli] = val - return d - - -def A_ub_np2d(A_ub): - '''Convert A_ub entries in numpy matrix to dictionary / sparse form''' - Adi = [None] * len(A_ub) - for i, row in enumerate(A_ub): - Adi[i] = A_ubr_np2d(row) - return Adi - - -def Ar_di2np(row_di, cols): - rownp = np.zeros(cols) - for coli, val in row_di.items(): - # Sign inversion due to way solver works - rownp[coli] = val - return rownp - - -# NOTE: sign inversion -def A_di2np(Adi, cols): - '''Convert A_ub entries in dictionary / sparse to numpy matrix form''' - return [Ar_di2np(row_di, cols) for row_di in Adi] - - -def Ar_ds2t(rowd): - '''Convert a dictionary row into a tuple with (column number, value) tuples''' - return tuple(sorted(rowd.items())) - - -def A_ubr_t2d(rowt): - '''Convert a dictionary row into a tuple with (column number, value) tuples''' - return OrderedDict(rowt) - - -def A_ub_d2t(A_ubd): - '''Convert rows as dicts to rows as tuples''' - return [Ar_ds2t(rowd) for rowd in A_ubd] - - -def A_ub_t2d(A_ubd): - '''Convert rows as tuples to rows as dicts''' - return [OrderedDict(rowt) for rowt in A_ubd] - - -def Ab_d2np(A_ubd, b_ub, names): - A_ub = A_di2np(A_ubd, len(names)) - b_ub_inv = invb(b_ub) - return A_ub, b_ub_inv - - -def Ab_np2d(A_ub, b_ub_inv): - A_ubd = A_ub_np2d(A_ub) - b_ub = invb(b_ub_inv) - return A_ubd, b_ub - - -def sort_equations(Ads, b): - # Track rows with value column - # Hmm can't sort against np arrays - tosort = [(sorted(row.items()), rowb) for row, rowb in zip(Ads, b)] - #res = sorted(tosort, key=lambda e: e[0]) - res = sorted(tosort) - A_ubtr, b_ubr = zip(*res) - return [OrderedDict(rowt) for rowt in A_ubtr], b_ubr - - -def col_dist(Ads, desc='of', names=[], lim=0): - '''print(frequency distribution of number of elements in a given row''' - rows = len(Ads) - cols = len(names) - - fs = {} - for row in Ads: - this_cols = len(row) - fs[this_cols] = fs.get(this_cols, 0) + 1 - - print( - 'Col count distribution (%s) for %dr x %dc w/ %d freqs' % - (desc, rows, cols, len(fs))) - prints = 0 - for i, (k, v) in enumerate(sorted(fs.items())): - if lim == 0 or (lim and prints < lim or i == len(fs) - 1): - print(' %d: %d' % (k, v)) - prints += 1 - if lim and prints == lim: - print(' ...') - - -def name_dist(A_ubd, desc='of', names=[], lim=0): - '''print(frequency distribution of number of times an element appears''' - rows = len(A_ubd) - cols = len(names) - - fs = {i: 0 for i in range(len(names))} - for row in A_ubd: - for k in row.keys(): - fs[k] += 1 - - print('Name count distribution (%s) for %dr x %dc' % (desc, rows, cols)) - prints = 0 - for namei, name in enumerate(names): - if lim == 0 or (lim and prints < lim or namei == len(fs) - 1): - print(' %s: %d' % (name, fs[namei])) - prints += 1 - if lim and prints == lim: - print(' ...') - - fs2 = {} - for v in fs.values(): - fs2[v] = fs2.get(v, 0) + 1 - prints = 0 - print('Distribution distribution (%d items)' % len(fs2)) - for i, (k, v) in enumerate(sorted(fs2.items())): - if lim == 0 or (lim and prints < lim or i == len(fs2) - 1): - print(' %s: %s' % (k, v)) - prints += 1 - if lim and prints == lim: - print(' ...') - - zeros = fs2.get(0, 0) - if zeros: - raise Exception("%d names without equation" % zeros) - - -def filter_ncols(A_ubd, b_ub, cols_min=0, cols_max=0): - '''Only keep equations with a few delay elements''' - A_ubd_ret = [] - b_ub_ret = [] - - #print('Removing large rows') - for rowd, b in zip(A_ubd, b_ub): - if (not cols_min or len(rowd) >= cols_min) and (not cols_max or - len(rowd) <= cols_max): - A_ubd_ret.append(rowd) - b_ub_ret.append(b) - - print( - 'Filter ncols w/ %d <= cols <= %d: %d ==> %d rows' % - (cols_min, cols_max, len(b_ub), len(b_ub_ret))) - assert len(b_ub_ret) - return A_ubd_ret, b_ub_ret - - -def Ar_di2ds(rowA, names): - row = OrderedDict() - for k, v in rowA.items(): - row[names[k]] = v - return row - - -def A_di2ds(Adi, names): - rows = [] - for row_di in Adi: - rows.append(Ar_di2ds(row_di, names)) - return rows - - -def Ar_ds2di(row_ds, names): - def keyi(name): - if name not in names: - names[name] = len(names) - return names[name] - - row_di = OrderedDict() - for k, v in row_ds.items(): - row_di[keyi(k)] = v - return row_di - - -def A_ds2di(rows): - names = OrderedDict() - - A_ubd = [] - for row_ds in rows: - A_ubd.append(Ar_ds2di(row_ds, names)) - - return list(names.keys()), A_ubd - - -def A_ds2np(Ads): - names, Adi = A_ds2di(Ads) - return names, A_di2np(Adi, len(names)) - - -def loadc_Ads_mkb(fns, mkb, filt): - bs = [] - Ads = [] - for fn in fns: - with open(fn, 'r') as f: - # skip header - f.readline() - for l in f: - cols = l.split(',') - ico = bool(int(cols[0])) - corners = cols[1] - vars = cols[2:] - - def mkcorner(bstr): - if bstr == 'None': - return None - else: - return int(bstr) - - corners = [mkcorner(corner) for corner in corners.split()] - - def mkvar(x): - i, var = x.split() - return (var, int(i)) - - vars = OrderedDict([mkvar(var) for var in vars]) - if not filt(ico, corners, vars): - continue - - bs.append(mkb(corners)) - Ads.append(vars) - - return Ads, bs - - -def loadc_Ads_b(fns, corner, ico=None): - corner = corner or "slow_max" - corneri = corner_s2i[corner] - ''' - if ico is not None: - filt = lambda ico_, corners, vars: ico_ == ico - else: - filt = lambda ico_, corners, vars: True - ''' - assert ico is None, 'ICO filtering moved to higher levels' - filt = lambda ico_, corners, vars: True - - def mkb(val): - return val[corneri] - - return loadc_Ads_mkb(fns, mkb, filt) - - -def loadc_Ads_bs(fns, ico=None): - ''' - if ico is not None: - filt = lambda ico_, corners, vars: ico_ == ico - else: - filt = lambda ico_, corners, vars: True - ''' - assert ico is None, 'ICO filtering moved to higher levels' - filt = lambda ico_, corners, vars: True - - def mkb(val): - return val - - return loadc_Ads_mkb(fns, mkb, filt) - - -def loadc_Ads_raw(fns): - filt = lambda ico, corners, vars: True - - def mkb(val): - return val - - return loadc_Ads_mkb(fns, mkb, filt) - - -def index_names(Ads): - names = OrderedSet() - for row_ds in Ads: - for k1 in row_ds.keys(): - names.add(k1) - return names - - -def load_sub(fn): - j = json.load(open(fn, 'r')) - - for name, vals in sorted(j['subs'].items()): - for k, v in vals.items(): - vals[k] = Fraction(v[0], v[1]) - - return j - - -def row_sub_vars(row, sub_json, strict=False, verbose=False): - if 0 and verbose: - print("") - print(row.items()) - - delvars = 0 - for k in sub_json['zero_names']: - try: - del row[k] - delvars += 1 - except KeyError: - pass - if verbose: - print("Deleted %u variables" % delvars) - - if verbose: - print('Checking pivots') - print(sorted(row.items())) - for group, pivot in sorted(sub_json['pivots'].items()): - if pivot not in row: - continue - n = row[pivot] - print(' pivot %u %s' % (n, pivot)) - - #pivots = set(sub_json['pivots'].values()).intersection(row.keys()) - for group, pivot in sorted(sub_json['pivots'].items()): - if pivot not in row: - continue - # take the sub out n times - # note constants may be negative - n = row[pivot] - if verbose: - print('pivot %i %s' % (n, pivot)) - for subk, subv in sorted(sub_json['subs'][group].items()): - oldn = row.get(subk, type(subv)(0)) - rown = -n * subv - rown += oldn - if verbose: - print(" %s: %d => %d" % (subk, oldn, rown)) - if rown == 0: - # only becomes zero if didn't previously exist - del row[subk] - if verbose: - print(" del") - else: - row[subk] = rown - row[group] = n - assert pivot not in row - - # after all constants are applied, the row should end up positive? - # numeric precision issues previously limited this - # Ex: AssertionError: ('PIP_BSW_2ELSING0', -2.220446049250313e-16) - if strict: - # verify no subs are left - for subs in sub_json['subs'].values(): - for sub in subs: - assert sub not in row, 'non-pivot element after group sub %s' % sub - - # Verify all constants are positive - for k, v in sorted(row.items()): - assert v > 0, (k, v) - - -def run_sub_json(Ads, sub_json, strict=False, verbose=False): - ''' - strict: complain if a sub doesn't go in evenly - ''' - - nrows = 0 - nsubs = 0 - - ncols_old = 0 - ncols_new = 0 - - print('Subbing %u rows' % len(Ads)) - prints = OrderedSet() - - for rowi, row in enumerate(Ads): - if 0 and verbose: - print(row) - if verbose: - print('') - print('Row %u w/ %u elements' % (rowi, len(row))) - - row_orig = dict(row) - row_sub_vars(row, sub_json, strict=strict, verbose=verbose) - nrows += 1 - if row_orig != row: - nsubs += 1 - if verbose: - rowt = Ar_ds2t(row) - if rowt not in prints: - print('row', row) - prints.add(rowt) - ncols_old += len(row_orig) - ncols_new += len(row) - - if verbose: - print('') - - print("Sub: %u / %u rows changed" % (nsubs, nrows)) - print("Sub: %u => %u non-zero row cols" % (ncols_old, ncols_new)) - - -def print_eqns(Ads, b, verbose=0, lim=3, label=''): - rows = len(b) - - print('Sample equations (%s) from %d r' % (label, rows)) - prints = 0 - for rowi, row in enumerate(Ads): - if verbose or ((rowi < 10 or rowi % max(1, (rows / 20)) == 0) and - (not lim or prints < lim)): - line = ' EQN: p%u: ' % rowi - for k, v in sorted(row.items()): - line += '%u*t%s ' % (v, k) - line += '= %d' % b[rowi] - print(line) - prints += 1 - - -def print_eqns_np(A_ub, b_ub, verbose=0): - Adi = A_ub_np2d(A_ub) - print_eqns(Adi, b_ub, verbose=verbose) - - -def Ads2bounds(Ads, bs): - ret = {} - for row_ds, row_bs in zip(Ads, bs): - assert len(row_ds) == 1 - k, v = list(row_ds.items())[0] - assert v == 1 - ret[k] = row_bs - return ret - - -def instances(Ads): - ret = 0 - for row_ds in Ads: - ret += sum(row_ds.values()) - return ret - - -def acorner2csv(b, corneri): - corners = ["None" for _ in range(4)] - corners[corneri] = str(b) - return ' '.join(corners) - - -def corners2csv(bs): - assert len(bs) == 4 - corners = ["None" if b is None else str(b) for b in bs] - return ' '.join(corners) - - -def tilej_stats(tilej): - def tile_stats(): - stats = {} - for etype in ('pips', 'wires'): - tm = stats.setdefault(etype, {}) - tm['net'] = 0 - tm['solved'] = [0, 0, 0, 0] - tm['covered'] = [0, 0, 0, 0] - - for tile in tilej['tiles'].values(): - for etype in ('pips', 'wires'): - pips = tile[etype] - for k, v in pips.items(): - stats[etype]['net'] += 1 - for i in range(4): - if pips[k][i]: - stats[etype]['solved'][i] += 1 - if pips[k][i] is not None: - stats[etype]['covered'][i] += 1 - return stats - - def site_stats(): - sitesj = tilej['sites'] - ret = { - 'sites': len(sitesj), - 'wires': sum([len(wiresj) for wiresj in sitesj.values()]), - 'wires_solved': {}, - } - for corneri in corner_s2i.values(): - ret['wires_solved'][corneri] = sum( - [ - sum( - [ - 1 if site_wire[corneri] else 0 - for site_wire in sitej.values() - ]) - for sitej in sitesj.values() - ]) - return ret - - tstats = tile_stats() - sstats = site_stats() - - for corner, corneri in corner_s2i.items(): - print('Corner %s' % corner) - for etype in ('pips', 'wires'): - net = tstats[etype]['net'] - solved = tstats[etype]['solved'][corneri] - covered = tstats[etype]['covered'][corneri] - print( - ' %s: %u / %u solved, %u / %u covered' % - (etype, solved, net, covered, net)) - print( - ' sites: %u sites w/ %u solved / %u covered site wires' % ( - sstats['sites'], sstats['wires_solved'][corneri], - sstats['wires'])) - - -def load_bounds(bounds_csv, corner): - Ads, b = loadc_Ads_b([bounds_csv], corner) - return Ads2bounds(Ads, b) diff --git a/fuzzers/007-timing/timfuz_massage.py b/fuzzers/007-timing/timfuz_massage.py deleted file mode 100644 index d64853c2..00000000 --- a/fuzzers/007-timing/timfuz_massage.py +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import simplify_rows, print_eqns, print_eqns_np, sort_equations, col_dist, index_names -import numpy as np -import math -import sys -import datetime -import os -import time -import copy -from collections import OrderedDict - - -def lte_const(row_ref, row_cmp): - '''Return true if all constants are smaller magnitude in row_cmp than row_ref''' - #return False - for k, vc in row_cmp.items(): - vr = row_ref.get(k, None) - # Not in reference? - if vr is None: - return False - if vr < vc: - return False - return True - - -def sub_rows(row_ref, row_cmp): - '''Do row_ref - row_cmp''' - #ret = {} - ret = OrderedDict() - ks = set(row_ref.keys()) - ks.update(set(row_cmp.keys())) - for k in ks: - vr = row_ref.get(k, 0) - vc = row_cmp.get(k, 0) - res = vr - vc - if res: - ret[k] = res - return ret - - -def derive_eq_by_row(Ads, b, verbose=0, col_lim=0, cmp_heuristic=True): - ''' - Derive equations by subtracting whole rows - - cmp_heuristic: drop large generated rows since these are unlikely to constrain the solution - - - Given equations like: - t0 >= 10 - t0 + t1 >= 15 - t0 + t1 + t2 >= 17 - - When I look at these, I think of a solution something like: - t0 = 10f - t1 = 5 - t2 = 2 - - However, linprog tends to choose solutions like: - t0 = 17 - t1 = 0 - t2 = 0 - - To this end, add additional constraints by finding equations that are subsets of other equations - How to do this in a reasonable time span? - Also equations are sparse, which makes this harder to compute - ''' - assert len(Ads) == len(b), 'Ads, b length mismatch' - rows = len(Ads) - - # Index equations into hash maps so can lookup sparse elements quicker - assert len(Ads) == len(b) - Ads_ret = copy.copy(Ads) - assert len(Ads) == len(Ads_ret) - - #print('Finding subsets') - ltes = 0 - b_ret = list(b) - sys.stdout.write('Deriving rows (%u) ' % rows) - sys.stdout.flush() - progress = int(max(1, rows / 100)) - b_warns = 0 - for row_refi, row_ref in enumerate(Ads): - if row_refi % progress == 0: - sys.stdout.write('.') - sys.stdout.flush() - if col_lim and len(row_ref) > col_lim: - continue - - for row_cmpi, row_cmp in enumerate(Ads): - if row_refi == row_cmpi or col_lim and len(row_cmp) > col_lim: - continue - if not lte_const(row_ref, row_cmp): - continue - ltes += 1 - if verbose: - print('') - print('match') - print(' ', row_ref, b[row_refi]) - print(' ', row_cmp, b[row_cmpi]) - - # Reduce - row_new = sub_rows(row_ref, row_cmp) - - # Did this actually significantly reduce the search space? - # should be a relatively small number of rows and be significantly smaller than at least one of them - def is_smaller_row(): - # Keep any generally small rows - if len(row_new) <= 8: - return True - # And anything that reduced at least one row by half - # Ex: going from 120 and 100 element rows to a 20 element row - return len(row_new) <= len(row_cmp) / 2 or len( - row_new) <= len(row_ref) / 2 - - if cmp_heuristic and not is_smaller_row(): - continue - b_new = b[row_refi] - b[row_cmpi] - # Definitely possible - # Maybe filter these out if they occur? - if verbose: - print(b_new) - # Also inverted sign - if b_new < 0: - if verbose: - print("Unexpected b") - b_warns += 1 - continue - if verbose: - print('OK') - Ads_ret.append(row_new) - b_ret.append(b_new) - print(' done') - - #A_ub_ret = A_di2np(Ads2, cols=cols) - print( - 'Derive row: %d => %d rows using %d lte' % (len(b), len(b_ret), ltes)) - print('Dropped %u invalid equations' % b_warns) - assert len(Ads_ret) == len(b_ret) - return Ads_ret, b_ret - - -def derive_eq_by_col(Ads, b_ub, verbose=0, keep_orig=True): - ''' - Derive equations by subtracting out all bounded constants (ie "known" columns) - XXX: is this now redundant with derive_row? - Seems like a degenerate case, although maybe quicker - ''' - rows = len(Ads) - - # Index equations with a single constraint - knowns = {} - sys.stdout.write('Derive col indexing ') - sys.stdout.flush() - progress = max(1, rows / 100) - for row_refi, row_refd in enumerate(Ads): - if row_refi % progress == 0: - sys.stdout.write('.') - sys.stdout.flush() - if len(row_refd) == 1: - k, v = list(row_refd.items())[0] - # assume simplify_equations handles de-duplicating - new_b = 1.0 * b_ub[row_refi] / v - assert k not in knowns, "Got new %s w/ val %u, old val %u" % ( - k, new_b, knowns[k]) - knowns[k] = new_b - print(' done') - #knowns_set = set(knowns.keys()) - print('%d constrained' % len(knowns)) - ''' - Now see what we can do - Rows that are already constrained: eliminate - TODO: maybe keep these if this would violate their constraint - Otherwise eliminate the original row and generate a simplified result now - ''' - b_ret = [] - Ads_ret = [] - sys.stdout.write('Derive col main ') - sys.stdout.flush() - progress = max(1, rows / 100) - for row_refi, row_refd in enumerate(Ads): - if row_refi % progress == 0: - sys.stdout.write('.') - sys.stdout.flush() - b_ref = b_ub[row_refi] - if keep_orig: - Ads_ret.append(row_refd) - b_ret.append(b_ref) - - # Reduce as much as possible - #row_new = {} - row_new = OrderedDict() - b_new = b_ref - # Copy over single entries - if len(row_refd) == 1: - row_new = row_refd - else: - for k, v in row_refd.items(): - if k in knowns: - # Remove column and take out corresponding delay - b_new -= v * knowns[k] - # Copy over - else: - row_new[k] = v - - # Possibly reduced all usable contants out - if len(row_new) == 0: - continue - # invalid? - if b_new < 0: - continue - - if not keep_orig or row_new != row_refd: - Ads_ret.append(row_new) - b_ret.append(b_new) - print(' done') - - print('Derive col: %d => %d rows' % (len(b_ub), len(b_ret))) - return Ads_ret, b_ret - - -# iteratively increasing column limit until all columns are added -def massage_equations( - Ads, b, verbose=False, corner=None, iter_lim=1, col_lim=100000): - #col_lim = 15 - ''' - Subtract equations from each other to generate additional constraints - Helps provide additional guidance to solver for realistic delays - - Ex: given: - a >= 10 - a + b >= 100 - A valid solution is: - a = 100 - However, a better solution is something like - a = 10 - b = 90 - This creates derived constraints to provide more realistic results - - Equation pipeline - Some operations may generate new equations - Simplify after these to avoid unnecessary overhead on redundant constraints - Similarly some operations may eliminate equations, potentially eliminating a column (ie variable) - Remove these columns as necessary to speed up solving - ''' - - assert len(Ads) == len(b), 'Ads, b length mismatch' - - def check_cols(): - assert len(index_names(Ads)) == cols - - def debug(what): - check_cols() - if 1 or verbose: - print('') - print_eqns(Ads, b, verbose=verbose, label=what, lim=20) - col_dist(Ads, what) - #check_feasible_d(Ads, b) - - # Try to (intelligently) subtract equations to generate additional constraints - # This helps avoid putting all delay in a single shared variable - dstart = len(b) - cols = len(index_names(Ads)) - - # Each iteration one more column is allowed until all columns are included - # (and the system is stable) - di = 0 - while True: - print - n_orig = len(b) - - print('Loop %d, lim %d' % (di + 1, col_lim)) - # Meat of the operation - Ads, b = derive_eq_by_row(Ads, b, col_lim=col_lim, cmp_heuristic=True) - debug("der_rows") - # Run another simplify pass since new equations may have overlap with original - Ads, b = simplify_rows(Ads, b, corner=corner) - print('Derive row: %d => %d equations' % (n_orig, len(b))) - debug("der_rows simp") - - # derive_cols is mostly degenerate case of derive_rows - # however, it will sub out single variables a lot faster if there are a lot of them - # linear vs above quadratic, might as well keep it in - if 1: - n_orig2 = len(b) - # Meat of the operation - Ads, b = derive_eq_by_col(Ads, b) - debug("der_cols") - # Run another simplify pass since new equations may have overlap with original - Ads, b = simplify_rows(Ads, b, corner=corner) - print( - 'Derive col %d: %d => %d equations' % - (di + 1, n_orig2, len(b))) - debug("der_cols simp") - - # Doesn't help computation, but helps debugging - Ads, b = sort_equations(Ads, b) - debug("loop done") - col_dist(Ads, 'derive done iter %d, lim %d' % (di, col_lim), lim=12) - - rows = len(Ads) - di += 1 - dend = len(b) - # possible that a new equation was generated and taken away, but close enough - if n_orig == len(b) and col_lim >= cols or di >= iter_lim: - break - col_lim += col_lim / 5 - - print('') - print('Derive net: %d => %d' % (dstart, dend)) - print('') - # Was experimentting to see how much the higher order columns really help - - # Helps debug readability - Ads, b = sort_equations(Ads, b) - debug("final (sorted)") - print('') - print('Massage final: %d => %d rows' % (dstart, dend)) - cols_end = len(index_names(Ads)) - print('Massage final: %d => %d cols' % (cols, cols_end)) - assert cols_end == cols - return Ads, b diff --git a/fuzzers/007-timing/timfuz_solve.py b/fuzzers/007-timing/timfuz_solve.py deleted file mode 100644 index 3e09cf07..00000000 --- a/fuzzers/007-timing/timfuz_solve.py +++ /dev/null @@ -1,237 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import simplify_rows, loadc_Ads_b, index_names, A_ds2np, run_sub_json, print_eqns, Ads2bounds, instances, SimplifiedToZero, allow_zero_eqns, corner_s2i, acorner2csv -from timfuz_massage import massage_equations -import numpy as np -import sys -import math - - -def check_feasible(A_ub, b_ub): - ''' - Put large timing constants into the equations - See if that would solve it - - Its having trouble giving me solutions as this gets bigger - Make a terrible baseline guess to confirm we aren't doing something bad - ''' - - sys.stdout.write('Check feasible ') - sys.stdout.flush() - - rows = len(b_ub) - cols = len(A_ub[0]) - - progress = max(1, rows / 100) - ''' - Delays should be in order of ns, so a 10 ns delay should be way above what anything should be - Series can have several hundred delay elements - Max delay in ballpark - ''' - xs = [1e9 for _i in range(cols)] - - # FIXME: use the correct np function to do this for me - # Verify bounds - #b_res = np.matmul(A_ub, xs) - #print(type(A_ub), type(xs) - #A_ub = np.array(A_ub) - #xs = np.array(xs) - #b_res = np.matmul(A_ub, xs) - def my_mul(A_ub, xs): - #print('cols', cols - #print('rows', rows - ret = [None] * rows - for row in range(rows): - this = 0 - for col in range(cols): - this += A_ub[row][col] * xs[col] - ret[row] = this - return ret - - b_res = my_mul(A_ub, xs) - - # Verify bound was respected - for rowi, (this_b, this_b_ub) in enumerate(zip(b_res, b_ub)): - if rowi % progress == 0: - sys.stdout.write('.') - sys.stdout.flush() - if this_b >= this_b_ub or this_b > 0: - print( - '% 4d Want res % 10.1f <= % 10.1f <= 0' % - (rowi, this_b, this_b_ub)) - raise Exception("Bad ") - print(' done') - - -def filter_bounds(Ads, b, bounds, corner): - ''' - Given min variable delays, remove rows that won't constrain solution - Ex for max corner: - Given bounds: - a >= 10 - b >= 1 - c >= 0 - Given equations: - a + b >= 10 - a + c >= 100 - The first equation is already satisfied - However, the second needs either an increase in a or an increase in c ''' - - if 'max' in corner: - # Keep delays possibly larger than current bound - def keep(row_b, est): - return row_b > est - - T_UNK = 0 - elif 'min' in corner: - # Keep delays possibly smaller than current bound - def keep(row_b, est): - return row_b < est - - T_UNK = 1e9 - else: - assert 0 - - ret_Ads = [] - ret_b = [] - unknowns = set() - for row_ds, row_b in zip(Ads, b): - # some variables get estimated at 0 - def getvar(k): - #return bounds.get(k, T_UNK) - ret = bounds.get(k, None) - if ret is not None: - return ret - unknowns.add(k) - return T_UNK - - est = sum([getvar(k) * v for k, v in row_ds.items()]) - # will this row potentially constrain us more? - if keep(row_b, est): - ret_Ads.append(row_ds) - ret_b.append(row_b) - if len(unknowns): - print('WARNING: %u encountered undefined bounds' % len(unknowns)) - return ret_Ads, ret_b - - -def solve_save(outfn, xvals, names, corner, save_zero=True, verbose=False): - # ballpark minimum actual observed delay is around 7 (carry chain) - # anything less than one is probably a solver artifact - delta = 0.5 - corneri = corner_s2i[corner] - - roundf = { - 'fast_max': math.ceil, - 'fast_min': math.floor, - 'slow_max': math.ceil, - 'slow_min': math.floor, - }[corner] - - print('Writing results') - zeros = 0 - with open(outfn, 'w') as fout: - # write as one variable per line - # this natively forms a bound if fed into linprog solver - fout.write('ico,fast_max fast_min slow_max slow_min,rows...\n') - for xval, name in zip(xvals, names): - row_ico = 1 - - if xval < delta: - if verbose: - print('WARNING: near 0 delay on %s: %0.6f' % (name, xval)) - zeros += 1 - if not save_zero: - continue - items = [str(row_ico), acorner2csv(roundf(xval), corneri)] - items.append('%u %s' % (1, name)) - fout.write(','.join(items) + '\n') - nonzeros = len(names) - zeros - print( - 'Wrote: %u / %u constrained delays, %u zeros' % - (nonzeros, len(names), zeros)) - # max only...min corner seems to like 0 - # see https://github.com/SymbiFlow/prjxray/issues/136 - if 'max' in corner: - assert nonzeros, 'Failed to estimate delay' - - -def run( - fns_in, - corner, - run_corner, - sub_json=None, - bounds_csv=None, - dedup=True, - massage=False, - outfn=None, - verbose=False, - **kwargs): - print('Loading data') - Ads, b = loadc_Ads_b(fns_in, corner) - - # Remove duplicate rows - # is this necessary? - # maybe better to just add them into the matrix directly - if dedup: - oldn = len(Ads) - iold = instances(Ads) - Ads, b = simplify_rows(Ads, b, corner=corner) - print('Simplify %u => %u rows' % (oldn, len(Ads))) - print('Simplify %u => %u instances' % (iold, instances(Ads))) - - if sub_json: - print('Sub: %u rows' % len(Ads)) - iold = instances(Ads) - names_old = index_names(Ads) - run_sub_json(Ads, sub_json, verbose=verbose) - names = index_names(Ads) - print("Sub: %u => %u names" % (len(names_old), len(names))) - print('Sub: %u => %u instances' % (iold, instances(Ads))) - else: - names = index_names(Ads) - ''' - Substitution .csv - Special .csv containing one variable per line - Used primarily for multiple optimization passes, such as different algorithms or additional constraints - ''' - if bounds_csv: - Ads2, b2 = loadc_Ads_b([bounds_csv], corner) - bounds = Ads2bounds(Ads2, b2) - assert len(bounds), 'Failed to load bounds' - rows_old = len(Ads) - Ads, b = filter_bounds(Ads, b, bounds, corner) - print( - 'Filter bounds: %s => %s + %s rows' % - (rows_old, len(Ads), len(Ads2))) - Ads = Ads + Ads2 - b = b + b2 - assert len(Ads) or allow_zero_eqns() - assert len(Ads) == len(b), 'Ads, b length mismatch' - - if verbose: - print - print_eqns(Ads, b, verbose=verbose) - - #print - #col_dist(A_ubd, 'final', names) - if massage: - try: - Ads, b = massage_equations(Ads, b, corner=corner) - except SimplifiedToZero: - if not allow_zero_eqns(): - raise - print('WARNING: simplified to zero equations') - Ads = [] - b = [] - - print('Converting to numpy...') - names, Anp = A_ds2np(Ads) - run_corner( - Anp, - np.asarray(b), - names, - corner, - outfn=outfn, - verbose=verbose, - **kwargs) diff --git a/fuzzers/007-timing/timgrid/Makefile b/fuzzers/007-timing/timgrid/Makefile deleted file mode 100644 index 830a741d..00000000 --- a/fuzzers/007-timing/timgrid/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -all: build/timgrid.json - -build/timgrid.txt: generate.tcl - mkdir -p build - cd build && ${XRAY_VIVADO} -mode batch -source ../generate.tcl - -build/timgrid.json: build/timgrid.txt - cd build && python3 ../tile_txt2json.py --speed-json ../../speed/build/speed.json timgrid.txt timgrid-s.json - -clean: - rm -rf build - diff --git a/fuzzers/007-timing/timgrid/generate.sh b/fuzzers/007-timing/timgrid/generate.sh deleted file mode 100644 index 418a0866..00000000 --- a/fuzzers/007-timing/timgrid/generate.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -x - -source ${XRAY_GENHEADER} - -${XRAY_VIVADO} -mode batch -source ../generate.tcl - -for x in design*.bit; do - ${XRAY_BITREAD} -F $XRAY_ROI_FRAMES -o ${x}s -z -y $x -done - -for x in design_*.bits; do - diff -u design.bits $x | grep '^[-+]bit' > ${x%.bits}.delta -done - -python3 ../generate.py design_*.delta > tilegrid.json - diff --git a/fuzzers/007-timing/timgrid/generate.tcl b/fuzzers/007-timing/timgrid/generate.tcl deleted file mode 100644 index 267f2605..00000000 --- a/fuzzers/007-timing/timgrid/generate.tcl +++ /dev/null @@ -1,118 +0,0 @@ -proc build_project {} { - if 0 { - set grid_min_x -1 - set grid_max_x -1 - set grid_min_y -1 - set grid_max_y -1 - } { - set grid_min_x $::env(XRAY_ROI_GRID_X1) - set grid_max_x $::env(XRAY_ROI_GRID_X2) - set grid_min_y $::env(XRAY_ROI_GRID_Y1) - set grid_max_y $::env(XRAY_ROI_GRID_Y2) - } - - create_project -force -part $::env(XRAY_PART) design design - - read_verilog ../top.v - synth_design -top top - - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports di] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports do] - set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports stb] - - create_pblock roi - add_cells_to_pblock [get_pblocks roi] [get_cells roi] - resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)" - - set_property CFGBVS VCCO [current_design] - set_property CONFIG_VOLTAGE 3.3 [current_design] - set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] - set_param tcl.collectionResultDisplayLimit 0 - - set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] - - set luts [get_bels -of_objects [get_sites -of_objects [get_pblocks roi]] -filter {TYPE =~ LUT*} */A6LUT] - set selected_luts {} - set lut_index 0 - - # LOC one LUT (a "selected_lut") into each CLB segment configuration column (ie 50 per column) - # Also, if GRID_MIN/MAX is not defined, automatically create it based on used CLBs - # See caveat in README on automatic creation - foreach lut $luts { - set tile [get_tile -of_objects $lut] - set grid_x [get_property GRID_POINT_X $tile] - set grid_y [get_property GRID_POINT_Y $tile] - - if [expr $grid_min_x < 0 || $grid_x < $grid_min_x] {set grid_min_x $grid_x} - if [expr $grid_max_x < 0 || $grid_x > $grid_max_x] {set grid_max_x $grid_x} - - if [expr $grid_min_y < 0 || $grid_y < $grid_min_y] {set grid_min_y $grid_y} - if [expr $grid_max_y < 0 || $grid_y > $grid_max_y] {set grid_max_y $grid_y} - - # 50 per column => 50, 100, 150, etc - if [regexp "Y(0|[0-9]*[05]0)/" $lut] { - set cell [get_cells roi/is[$lut_index].lut] - set_property LOC [get_sites -of_objects $lut] $cell - set lut_index [expr $lut_index + 1] - lappend selected_luts $lut - } - } - - place_design - route_design - - write_checkpoint -force design.dcp - write_bitstream -force design.bit -} - -proc write_data {} { - if 0 { - set grid_min_x -1 - set grid_max_x -1 - set grid_min_y -1 - set grid_max_y -1 - } { - set grid_min_x $::env(XRAY_ROI_GRID_X1) - set grid_max_x $::env(XRAY_ROI_GRID_X2) - set grid_min_y $::env(XRAY_ROI_GRID_Y1) - set grid_max_y $::env(XRAY_ROI_GRID_Y2) - } - - # Get all tiles in ROI, ie not just the selected LUTs - set tiles [get_tiles -filter "GRID_POINT_X >= $grid_min_x && GRID_POINT_X <= $grid_max_x && GRID_POINT_Y >= $grid_min_y && GRID_POINT_Y <= $grid_max_y"] - - # Write tiles.txt with site metadata - set fp [open "timgrid.txt" w] - foreach tile $tiles { - set type [get_property TYPE $tile] - set grid_x [get_property GRID_POINT_X $tile] - set grid_y [get_property GRID_POINT_Y $tile] - - set items {} - - set wires [get_wires -of_objects $tile] - if [llength $wires] { - foreach wire $wires { - set name [get_property NAME $wire] - set speed_index [get_property SPEED_INDEX $wire] - lappend items wire $name $speed_index - } - } - - set pips [get_pips -of_objects $tile] - if [llength $pips] { - foreach pip $pips { - set name [get_property NAME $pip] - set speed_index [get_property SPEED_INDEX $pip] - lappend items pip $name $speed_index - } - } - - puts $fp "$type $tile $grid_x $grid_y $items" - } - close $fp -} - -build_project -write_data diff --git a/fuzzers/007-timing/timgrid/tile_txt2json.py b/fuzzers/007-timing/timgrid/tile_txt2json.py deleted file mode 100644 index 4342805d..00000000 --- a/fuzzers/007-timing/timgrid/tile_txt2json.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import os -import time -import json - -SI_NONE = 0xFFFF - - -def load_speed_json(f): - j = json.load(f) - # Index speed indexes to names - speed_i2s = {} - for k, v in j['speed_model'].items(): - i = v['speed_index'] - if i != SI_NONE: - speed_i2s[i] = k - return j, speed_i2s - - -def gen_tiles(fnin, speed_i2s): - for l in open(fnin): - # lappend items pip $name $speed_index - # puts $fp "$type $tile $grid_x $grid_y $items" - parts = l.strip().split() - tile_type, tile_name, grid_x, grid_y = parts[0:4] - grid_x, grid_y = int(grid_x), int(grid_y) - tuples = parts[4:] - assert len(tuples) % 3 == 0 - pips = {} - wires = {} - for i in range(0, len(tuples), 3): - ttype, name, speed_index = tuples[i:i + 3] - name_local = name.split('/')[1] - { - 'pip': pips, - 'wire': wires, - }[ttype][name_local] = speed_i2s[int(speed_index)] - yield (tile_type, tile_name, grid_x, grid_y, pips, wires) - - -def run(fnin, fnout, speed_json_fn, verbose=False): - speedj, speed_i2s = load_speed_json(open(speed_json_fn, 'r')) - - tiles = {} - for tile in gen_tiles(fnin, speed_i2s): - (tile_type, tile_name, grid_x, grid_y, pips, wires) = tile - this_dat = {'pips': pips, 'wires': wires} - if tile_type not in tiles: - tiles[tile_type] = this_dat - else: - if tiles[tile_type] != this_dat: - print(tile_name, tile_type) - print(this_dat) - print(tiles[tile_type]) - assert 0 - - j = {'tiles': tiles} - json.dump( - j, open(fnout, 'w'), sort_keys=True, indent=4, separators=(',', ': ')) - - -def main(): - import argparse - - parser = argparse.ArgumentParser(description='Solve timing solution') - parser.add_argument( - '--speed-json', - default='../../speed/build/speed.json', - help='Provides speed index to name translation') - parser.add_argument('fnin', default=None, help='input tcl output .txt') - parser.add_argument('fnout', default=None, help='output .json') - args = parser.parse_args() - - run(args.fnin, args.fnout, speed_json_fn=args.speed_json, verbose=False) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/timgrid/top.v b/fuzzers/007-timing/timgrid/top.v deleted file mode 100644 index 5fd239b5..00000000 --- a/fuzzers/007-timing/timgrid/top.v +++ /dev/null @@ -1,49 +0,0 @@ -//Need at least one LUT per frame base address we want -`define N 100 - -module top(input clk, stb, di, output do); - localparam integer DIN_N = 6; - localparam integer DOUT_N = `N; - - reg [DIN_N-1:0] din; - wire [DOUT_N-1:0] dout; - - reg [DIN_N-1:0] din_shr; - reg [DOUT_N-1:0] dout_shr; - - always @(posedge clk) begin - din_shr <= {din_shr, di}; - dout_shr <= {dout_shr, din_shr[DIN_N-1]}; - if (stb) begin - din <= din_shr; - dout_shr <= dout; - end - end - - assign do = dout_shr[DOUT_N-1]; - - roi roi ( - .clk(clk), - .din(din), - .dout(dout) - ); -endmodule - -module roi(input clk, input [5:0] din, output [`N-1:0] dout); - genvar i; - generate - for (i = 0; i < `N; i = i+1) begin:is - LUT6 #( - .INIT(64'h8000_0000_0000_0001 + (i << 16)) - ) lut ( - .I0(din[0]), - .I1(din[1]), - .I2(din[2]), - .I3(din[3]), - .I4(din[4]), - .I5(din[5]), - .O(dout[i]) - ); - end - endgenerate -endmodule diff --git a/fuzzers/007-timing/timgrid/top_bram.v b/fuzzers/007-timing/timgrid/top_bram.v deleted file mode 100644 index 880fd375..00000000 --- a/fuzzers/007-timing/timgrid/top_bram.v +++ /dev/null @@ -1,62 +0,0 @@ -`define N 100 - -module top(input clk, stb, di, output do); - localparam integer DIN_N = 8; - localparam integer DOUT_N = `N; - - reg [DIN_N-1:0] din; - wire [DOUT_N-1:0] dout; - - reg [DIN_N-1:0] din_shr; - reg [DOUT_N-1:0] dout_shr; - - always @(posedge clk) begin - din_shr <= {din_shr, di}; - dout_shr <= {dout_shr, din_shr[DIN_N-1]}; - if (stb) begin - din <= din_shr; - dout_shr <= dout; - end - end - - assign do = dout_shr[DOUT_N-1]; - - roi roi ( - .clk(clk), - .din(din), - .dout(dout) - ); -endmodule - -module roi(input clk, input [7:0] din, output [`N-1:0] dout); - genvar i; - generate - for (i = 0; i < `N; i = i+1) begin:is - (* KEEP, DONT_TOUCH *) - RAMB36E1 #(.INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000)) ram ( - .CLKARDCLK(din[0]), - .CLKBWRCLK(din[1]), - .ENARDEN(din[2]), - .ENBWREN(din[3]), - .REGCEAREGCE(din[4]), - .REGCEB(din[5]), - .RSTRAMARSTRAM(din[6]), - .RSTRAMB(din[7]), - .RSTREGARSTREG(din[0]), - .RSTREGB(din[1]), - .ADDRARDADDR(din[2]), - .ADDRBWRADDR(din[3]), - .DIADI(din[4]), - .DIBDI(din[5]), - .DIPADIP(din[6]), - .DIPBDIP(din[7]), - .WEA(din[0]), - .WEBWE(din[1]), - .DOADO(dout[0]), - .DOBDO(), - .DOPADOP(), - .DOPBDOP()); - end - endgenerate -endmodule - diff --git a/fuzzers/007-timing/timgrid_vc2v.py b/fuzzers/007-timing/timgrid_vc2v.py deleted file mode 100644 index 8cb19162..00000000 --- a/fuzzers/007-timing/timgrid_vc2v.py +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import os -import time -import json -from collections import OrderedDict -import timfuz - -corner_s2i = OrderedDict( - [ - ('fast_max', 0), - ('fast_min', 1), - ('slow_max', 2), - ('slow_min', 3), - ]) - -corner2minmax = { - 'fast_max': max, - 'fast_min': min, - 'slow_max': max, - 'slow_min': min, -} - - -def merge_bdict(vi, vo): - ''' - vi: input dictionary - vo: output dictionary - values are corner delay 4 tuples - ''' - - for name, bis in vi.items(): - bos = vo.get(name, [None, None, None, None]) - for cornerk, corneri in corner_s2i.items(): - bo = bos[corneri] - bi = bis[corneri] - # no new data - if bi is None: - pass - # no previous data - elif bo is None: - bos[corneri] = bi - # combine - else: - minmax = corner2minmax[cornerk] - bos[corneri] = minmax(bi, bo) - - -def merge_tiles(tileji, tilejo): - ''' - { - "tiles": { - "BRKH_B_TERM_INT": { - "pips": {}, - "wires": { - "B_TERM_UTURN_INT_ER1BEG0": [ - null, - null, - 93, - null - ], - ''' - - for tilek, tilevi in tileji.items(): - # No previous data? Copy - tilevo = tilejo.get(tilek, None) - if tilevo is None: - tilejo[tilek] = tilevi - # Otherwise combine - else: - merge_bdict(tilevi['pips'], tilevo['pips']) - merge_bdict(tilevi['wires'], tilevo['wires']) - - -def merge_sites(siteji, sitejo): - for k, vi in siteji.items(): - vo = sitejo.get(k, None) - # No previous data? Copy - if vo is None: - sitejo[k] = vi - # Otherwise combine - else: - merge_bdict(vi, vo) - - -def build_tilejo(fnins): - # merge all inputs into blank output - tilejo = {"tiles": {}, "sites": {}} - for fnin in fnins: - tileji = json.load(open(fnin, 'r')) - - merge_tiles(tileji['tiles'], tilejo['tiles']) - merge_sites(tileji['sites'], tilejo['sites']) - - return tilejo - - -def check_corner_minmax(tilej, verbose=False): - # Post processing pass looking for min/max inconsistencies - # Especially an issue due to complexities around under-constrained elements - # (ex: pivots set to 0 delay) - print('Checking for min/max consistency') - checks = 0 - bad = 0 - - for tilev in tilej['tiles'].values(): - - def process_type(etype): - nonlocal checks - nonlocal bad - - for pipk, pipv in tilev[etype].items(): - for corner in ('slow', 'fast'): - mini = corner_s2i[corner + '_min'] - minv = pipv[mini] - maxi = corner_s2i[corner + '_max'] - maxv = pipv[maxi] - if minv is not None and maxv is not None: - checks += 1 - if minv > maxv: - if verbose: - print( - 'WARNING: element %s %s min/max adjusted on corner %s' - % (etype, pipk, corner)) - bad += 1 - pipv[mini] = maxv - pipv[maxi] = minv - - process_type('pips') - process_type('wires') - - print('') - print('minmax: %u / %u pairs bad pairs adjusted' % (bad, checks)) - timfuz.tilej_stats(tilej) - - -def run(fnins, fnout, verbose=False): - tilejo = build_tilejo(fnins) - check_corner_minmax(tilejo) - # XXX: check fast vs slow? - # check_corners_minmax(tilejo) - json.dump( - tilejo, - open(fnout, 'w'), - sort_keys=True, - indent=4, - separators=(',', ': ')) - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description='Combine multiple tile corners into one .json file') - parser.add_argument( - '--out', required=True, help='Combined timgrid-v.json files') - parser.add_argument('fnins', nargs='+', help='Input timgrid-vc.json files') - args = parser.parse_args() - - run(args.fnins, args.out, verbose=False) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/timing_txt2icsv.py b/fuzzers/007-timing/timing_txt2icsv.py deleted file mode 100644 index 469df204..00000000 --- a/fuzzers/007-timing/timing_txt2icsv.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import Benchmark, A_di2ds, PREFIX_W, PREFIX_P -from timing_txt2json import gen_timing4n, load_speed_json - -import glob -import math -import json -import sys -from collections import OrderedDict - - -# Verify the nodes and wires really do line up -def vals2Adi_check(vals, names): - print('Checking') - for val in vals: - node_wires = 0 - for _node, wiresn in val['nodes']: - node_wires += wiresn - assert node_wires == len(val['wires']) - print('Done') - assert 0 - - -def row_json2Ads(val, verbose=False): - '''Convert timing4 JSON into Ads interconnect equations''' - - def pip2speed(pip): - _site, _name, pip_name = pip - return PREFIX_P + ':' + pip_name - - def wire2speed(wire): - _site, _name, wire_name = wire - return PREFIX_W + ':' + wire_name - - def add_name(name): - row_ds[name] = row_ds.get(name, 0) + 1 - - row_ds = {} - - for pip in val['pips']: - add_name(pip2speed(pip)) - for wire in val['wires']: - add_name(wire2speed(wire)) - return row_ds - - -def load_Ads_gen(speed_json_f, fn_ins): - - print('Loading data') - - _speedj, speed_i2s = load_speed_json(speed_json_f) - - for fn_in in fn_ins: - - def mkb(val): - t = val['t'] - return (t['fast_max'], t['fast_min'], t['slow_max'], t['slow_min']) - - for val in gen_timing4n(fn_in, speed_i2s): - row_ds = row_json2Ads(val) - row_bs = mkb(val) - row_ico = val['ico'] - - yield row_bs, row_ds, row_ico - - -def run(speed_json_f, fout, fns_in, verbose=0, corner=None): - fout.write('ico,fast_max fast_min slow_max slow_min,rows...\n') - for row_bs, row_ds, row_ico in load_Ads_gen(speed_json_f, fns_in): - # XXX: consider removing ico column - # its obsolete at this point - if not row_ico: - continue - # like: 123 456 120 450, 1 a, 2 b - # first column has delay corners, followed by delay element count - items = [str(row_ico), ' '.join([str(x) for x in row_bs])] - for k, v in sorted(row_ds.items()): - items.append('%u %s' % (v, k)) - fout.write(','.join(items) + '\n') - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description= - 'Convert obscure timing4.txt into timing4i.csv (interconnect delay variable occurances)' - ) - - parser.add_argument('--verbose', type=int, help='') - # made a bulk conversion easier...keep? - parser.add_argument( - '--auto-name', action='store_true', help='timing4.txt => timing4i.csv') - parser.add_argument( - '--speed-json', - default='build_speed/speed.json', - help='Provides speed index to name translation') - parser.add_argument('--out', default=None, help='Output timing4i.csv file') - parser.add_argument('fns_in', nargs='+', help='Input timing4.txt files') - args = parser.parse_args() - bench = Benchmark() - - fnout = args.out - if fnout is None: - if args.auto_name: - assert len(args.fns_in) == 1 - fnin = args.fns_in[0] - fnout = fnin.replace('.txt', 'i.csv') - assert fnout != fnin, 'Expect .txt in' - else: - # practically there are too many stray prints to make this work as expected - assert 0, 'File name required' - fnout = '/dev/stdout' - print("Writing to %s" % fnout) - fout = open(fnout, 'w') - - fns_in = args.fns_in - if not fns_in: - fns_in = glob.glob('specimen_*/timing4.txt') - - run( - speed_json_f=open(args.speed_json, 'r'), - fout=fout, - fns_in=fns_in, - verbose=args.verbose) - - -if __name__ == '__main__': - main() diff --git a/fuzzers/007-timing/timing_txt2json.py b/fuzzers/007-timing/timing_txt2json.py deleted file mode 100644 index 4d26a5f6..00000000 --- a/fuzzers/007-timing/timing_txt2json.py +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import Benchmark, A_di2ds -import glob -import math -import json -import sys -from collections import OrderedDict - -# Speed index: some sort of special value -SI_NONE = 0xFFFF - - -def parse_pip(s, speed_i2s): - # Entries like - # CLK_BUFG_REBUF_X60Y117/CLK_BUFG_REBUF.CLK_BUFG_REBUF_R_CK_GCLK0_BOT<<->>CLK_BUFG_REBUF_R_CK_GCLK0_TOP - # Convert to (site, type, pip_junction, pip) - pipstr, speed_index = s.split(':') - speed_index = int(speed_index) - site, instance = pipstr.split('/') - #type, pip_junction, pip = others.split('.') - #return (site, type, pip_junction, pip) - return site, instance, speed_i2s[int(speed_index)] - - -def parse_pips(pips, speed_i2s): - if not pips: - return [] - return [parse_pip(pip, speed_i2s) for pip in pips.split('|')] - - -def parse_wire(s, speed_i2s): - # CLBLM_R_X3Y80/CLBLM_M_D6:952 - wirestr, speed_index = s.split(':') - site, instance = wirestr.split('/') - return site, instance, speed_i2s[int(speed_index)] - - -def parse_wires(wires, speed_i2s): - if not wires: - return [] - return [parse_wire(wire, speed_i2s) for wire in wires.split('|')] - - -def gen_timing4(fn, speed_i2s): - f = open(fn, 'r') - header_want = "linetype,net,src_site,src_site_type,src_site_pin,src_bel,src_bel_pin,dst_site,dst_site_type,dst_site_pin,dst_bel,dst_bel_pin,ico,fast_max,fast_min,slow_max,slow_min,pips,wires" - ncols = len(header_want.split(',')) - - # src_bel dst_bel ico fast_max fast_min slow_max slow_min pips - header_got = f.readline().strip() - if header_got != header_want: - raise Exception("Unexpected columns") - - rets = 0 - # XXX: there were malformed lines, but think they are fixed now? - bads = 0 - net_lines = 0 - for l in f: - - def group_line(): - ncols = len('lintype,ico,delays'.split(',')) - assert len(parts) == ncols - _lintype, ico, delays = parts - return int(ico), int(delays) - - def net_line(): - assert len(parts) == ncols, "Expected %u parts, got %u" % ( - ncols, len(parts)) - _lintype, net, src_site, src_site_type, src_site_pin, src_bel, src_bel_pin, dst_site, dst_site_type, dst_site_pin, dst_bel, dst_bel_pin, ico, fast_max, fast_min, slow_max, slow_min, pips, wires = parts - - def filt_passthru_lut(bel_pins): - ''' - Ex: SLICE_X11Y110/A6LUT/A6 SLICE_X11Y110/AFF/D - ''' - parts = bel_pins.split() - if len(parts) == 1: - return parts[0] - else: - assert len(parts) == 2 - # the LUT shoudl always go first? - bel_pin_lut, bel_pin_dst = parts - assert '6LUT' in bel_pin_lut - return bel_pin_dst - - return { - 'net': net, - 'src': { - 'site': src_site, - 'site_type': src_site_type, - 'site_pin': src_site_pin, - 'bel': src_bel, - 'bel_pin': src_bel_pin, - }, - 'dst': { - 'site': dst_site, - 'site_type': dst_site_type, - 'site_pin': dst_site_pin, - 'bel': dst_bel, - 'bel_pin': filt_passthru_lut(dst_bel_pin), - }, - 't': { - # ps - 'fast_max': int(fast_max), - 'fast_min': int(fast_min), - 'slow_max': int(slow_max), - 'slow_min': int(slow_min), - }, - 'ico': int(ico), - 'pips': parse_pips(pips, speed_i2s), - 'wires': parse_wires(wires, speed_i2s), - 'line': l, - } - - l = l.strip() - if not l: - continue - parts = l.split(',') - lintype = parts[0] - - val = { - 'NET': net_line, - 'GROUP': group_line, - }[lintype]() - yield lintype, val - - rets += 1 - print(' load %s: %d bad, %d good lines' % (fn, bads, rets)) - - -def gen_timing4n(fn, speed_i2s): - '''Only generate nets''' - for lintype, val in gen_timing4(fn, speed_i2s): - if lintype == 'NET': - yield val - - -def gen_timing4a(fn, speed_i2s): - ''' - Like above, but aggregate ico + non-ico into single entries - Key these based on uniqueness of (src_bel, dst_bel) - - ico 0 is followed by 1 - They should probably even be in the same order - Maybe just assert that? - ''' - entries = {} - timgen = gen_timing4(fn, speed_i2s) - rets = 0 - while True: - - def get_ico(exp_ico): - ret = [] - try: - lintype, val = next(timgen) - except StopIteration: - return None - assert lintype == 'GROUP' - ico, delays = val - assert ico == exp_ico - for _ in range(delays): - lintype, val = next(timgen) - assert lintype == 'NET' - ret.append(val) - return ret - - ico0s = get_ico(0) - if ico0s is None: - break - ico1s = get_ico(1) - # TODO: verify this is actually true - assert len(ico0s) == len(ico1s) - - def same_path(l, r): - # if source and dest are the same, should be the same thing - return l['src']['bel_pin'] == r['src']['bel_pin'] and l['dst'][ - 'bel_pin'] == r['dst']['bel_pin'] - - for ico0, ico1 in zip(ico0s, ico1s): - # TODO: verify this is actually true - # otherwise move to more complex algorithm - assert same_path(ico0, ico1) - # aggregate timing info as (ic0, ic1) into ico0 - ico0['t'] = ( - ico0['t'], - ico1['t'], - ) - yield ico0 - rets += 1 - print(' load %s: %u aggregated lines' % (fn, rets)) - - -def load_speed_json(f): - j = json.load(f) - # Index speed indexes to names - speed_i2s = {} - for k, v in j['speed_model'].items(): - i = v['speed_index'] - if i != SI_NONE: - speed_i2s[i] = k - return j, speed_i2s diff --git a/fuzzers/007-timing/timing_txt2scsv.py b/fuzzers/007-timing/timing_txt2scsv.py deleted file mode 100644 index 1dedb470..00000000 --- a/fuzzers/007-timing/timing_txt2scsv.py +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env python3 - -from timfuz import Benchmark, A_di2ds, sw_ei_vals2s, sw_eo_vals2s, sw_i_vals2s -from timing_txt2json import gen_timing4a, load_speed_json - -import glob -import math -import json -import sys -from collections import OrderedDict - - -def gen_diffs(speed_json_f, fns_in): - print('Loading data') - _speedj, speed_i2s = load_speed_json(speed_json_f) - - for fn_in in fns_in: - for val in gen_timing4a(fn_in, speed_i2s): - # diff to get site only delay - tsites = {} - for k in val['t'][0].keys(): - v = val['t'][0][k] - val['t'][1][k] - assert v >= 0 - tsites[k] = v - yield val, tsites - - -# XXX: move to json converter? -def sd_parts(sd): - '''Return site_type, site_pin, bel_type, bel_pin as non-prefixed strings''' - # IOB_X0Y106 IOB_X0Y106/INBUF_EN IOB_X0Y106/INBUF_EN/OUT - # print(sd['site'], sd['bel'], sd['bel_pin']) - site_type = sd['site_type'] - site, bel_type, bel_pin = sd['bel_pin'].split('/') - assert sd['site'] == site - assert sd['bel'] == site + '/' + bel_type - - site_pin_str = sd['site_pin'] - if site_pin_str: - site, site_pin = sd['site_pin'].split('/') - assert sd['site_pin'] == sd['site'] + '/' + site_pin - else: - site_pin = None - return site_type, site_pin, bel_type, bel_pin - - -def run(speed_json_f, fout, fns_in, verbose=0, corner=None): - ''' - instead of writing to a simplified csv, lets just go directly to a delay format identical to what fabric uses - Path types: - -inter site: think these are removed for now? - 1 model - NOTE: be careful of a net that goes external and comes back in, which isn't inter site - definition is that it doesn't have any site pins - -intra site - 2 models - ''' - - fout.write( - 'ico,fast_max fast_min slow_max slow_min,src_site_type,src_site,src_bel,src_bel_pin,dst_site_type,dst_site,dst_bel,dst_bel_pin\n' - ) - for val, tsites in gen_diffs(speed_json_f, fns_in): - - def mkb(t): - return (t['fast_max'], t['fast_min'], t['slow_max'], t['slow_min']) - - bstr = ' '.join([str(x) for x in mkb(tsites)]) - - # Identify inter site transaction (SITEI) - if not val['src']['site_pin'] and not val['dst']['site_pin']: - # add one delay model for the path - # XXX: can these be solved exactly? - # might still have fanout and such - - src_site_type, _src_site_pin, src_bel_type, src_bel_pin = sd_parts( - val['src']) - dst_site_type, _dst_site_pin, dst_bel_type, dst_bel_pin = sd_parts( - val['dst']) - assert src_site_type == dst_site_type - assert (src_bel_type, src_bel_pin) != (dst_bel_type, dst_bel_pin) - - k = sw_i_vals2s( - src_site_type, src_bel_type, src_bel_pin, dst_bel_type, - dst_bel_pin) - row_ds = {k: 1} - elif val['src']['site_pin'] and val['dst']['site_pin']: - # if it exits a site it should enter another (possibly the same site) - # site in (SITEI) or site out (SITEO)? - # nah, keep things simple and just call them SITEW - row_ds = {} - - def add_dst_delay(): - sd = val['dst'] - site_type, src_site_pin, dst_bel, dst_bel_pin = sd_parts(sd) - k = sw_ei_vals2s(site_type, src_site_pin, dst_bel, dst_bel_pin) - assert k not in row_ds - row_ds[k] = 1 - - def add_src_delay(): - sd = val['src'] - site_type, dst_site_pin, src_bel, src_bel_pin = sd_parts(sd) - k = sw_eo_vals2s(site_type, src_bel, src_bel_pin, dst_site_pin) - assert k not in row_ds - row_ds[k] = 1 - - add_dst_delay() - add_src_delay() - else: - # dropped by the tcl script - raise Exception("FIXME: handle destination but no source") - - row_ico = 0 - items = [str(row_ico), bstr] - for k, v in sorted(row_ds.items()): - items.append('%u %s' % (v, k)) - fout.write(','.join(items) + '\n') - print('done') - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description= - 'Convert obscure timing4.txt into timing4s.csv (site delay variable occurances)' - ) - - parser.add_argument('--verbose', type=int, help='') - # made a bulk conversion easier...keep? - parser.add_argument( - '--auto-name', action='store_true', help='timing4.txt => timing4i.csv') - parser.add_argument( - '--speed-json', - default='build_speed/speed.json', - help='Provides speed index to name translation') - parser.add_argument('--out', default=None, help='Output timing4i.csv file') - parser.add_argument('fns_in', nargs='+', help='Input timing4.txt files') - args = parser.parse_args() - bench = Benchmark() - - fnout = args.out - if fnout is None: - if args.auto_name: - assert len(args.fns_in) == 1 - fnin = args.fns_in[0] - fnout = fnin.replace('.txt', 's.csv') - assert fnout != fnin, 'Expect .txt in' - else: - # practically there are too many stray prints to make this work as expected - assert 0, 'File name required' - fnout = '/dev/stdout' - print("Writing to %s" % fnout) - fout = open(fnout, 'w') - - fns_in = args.fns_in - if not fns_in: - fns_in = glob.glob('specimen_*/timing4.txt') - - run( - speed_json_f=open(args.speed_json, 'r'), - fout=fout, - fns_in=fns_in, - verbose=args.verbose) - - -if __name__ == '__main__': - main()