diff --git a/fuzzers/060-bram-cascades/Makefile b/fuzzers/060-bram-cascades/Makefile new file mode 100644 index 00000000..ce1713ac --- /dev/null +++ b/fuzzers/060-bram-cascades/Makefile @@ -0,0 +1,38 @@ +MAKETODO_FLAGS=--re "BRAM_.\.BRAM_(?!LOGIC_OUTS).*" +export FUZDIR=$(shell pwd) +PIPLIST_TCL=$(FUZDIR)/bram_pip_list.tcl +PIP_TYPE?=bram_pips_int +SEG_TYPE?=bram +N = 50 +SEGMATCH_FLAGS=-m 20 -M 45 +include ../pip_loop.mk +# +# Specimens from current run must complete, but previous iterations may exist +database: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} $(SEGMATCH_FLAGS) -o build/segbits_bram_l.rdb $(shell find build -name segdata_bram_l.txt) + ${XRAY_SEGMATCH} $(SEGMATCH_FLAGS) -o build/segbits_bram_r.rdb $(shell find build -name segdata_bram_r.txt) + + # Keep a copy to track iter progress + # Also is pre-fixup, which drops and converts + cp build/segbits_bram_l.rdb build/$(ITER)/segbits_bram_l.rdb + cp build/segbits_bram_r.rdb build/$(ITER)/segbits_bram_r.rdb + ${XRAY_DBFIXUP} --db-root build \ + --verbose \ + --zero-db bits.dbf \ + --seg-fn-in build/segbits_bram_l.rdb \ + --seg-fn-out build/segbits_bram_l.db + ${XRAY_DBFIXUP} --db-root build \ + --verbose \ + --zero-db bits.dbf \ + --seg-fn-in build/segbits_bram_r.rdb \ + --seg-fn-out build/segbits_bram_r.db + + # Clobber existing .db to eliminate potential conflicts + cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db build/database/${XRAY_DATABASE} + XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} bram_l build/segbits_bram_l.db + XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} bram_r build/segbits_bram_r.db + +# Final pushdb to real repo +pushdb: database + ${XRAY_MERGEDB} bram_l build/segbits_bram_l.db + ${XRAY_MERGEDB} bram_r build/segbits_bram_r.db diff --git a/fuzzers/060-bram-cascades/bits.dbf b/fuzzers/060-bram-cascades/bits.dbf new file mode 100644 index 00000000..3b37454a --- /dev/null +++ b/fuzzers/060-bram-cascades/bits.dbf @@ -0,0 +1,30 @@ +26_184 26_185 26_187,BRAM.BRAM_ADDRBWRADDRL7.BRAM_IMUX_ADDRBWRADDRL7 +26_88 26_89 26_91 ,BRAM.BRAM_ADDRBWRADDRL8.BRAM_IMUX_ADDRBWRADDRL8 + +26_197 26_198 26_199,BRAM.BRAM_ADDRARDADDRU3.BRAM_IMUX_ADDRARDADDRU3 +26_101 26_102 26_103,BRAM.BRAM_ADDRARDADDRU4.BRAM_IMUX_ADDRARDADDRU4 +26_229 26_230 26_231,BRAM.BRAM_ADDRARDADDRU5.BRAM_IMUX_ADDRARDADDRU5 +26_165 26_166 26_167,BRAM.BRAM_ADDRARDADDRU6.BRAM_IMUX_ADDRARDADDRU6 +26_181 26_182 26_183,BRAM.BRAM_ADDRARDADDRU7.BRAM_IMUX_ADDRARDADDRU7 +26_85 26_86 26_87 ,BRAM.BRAM_ADDRARDADDRU8.BRAM_IMUX_ADDRARDADDRU8 +26_213 26_214 26_215,BRAM.BRAM_ADDRARDADDRU9.BRAM_IMUX_ADDRARDADDRU9 + +26_77 26_78 26_79 ,BRAM.BRAM_ADDRBWRADDRU2.BRAM_IMUX_ADDRBWRADDRU2 +26_205 26_206 26_207,BRAM.BRAM_ADDRBWRADDRU3.BRAM_IMUX_ADDRBWRADDRU3 +26_237 26_238 26_239,BRAM.BRAM_ADDRBWRADDRU5.BRAM_IMUX_ADDRBWRADDRU5 +26_173 26_174 26_175,BRAM.BRAM_ADDRBWRADDRU6.BRAM_IMUX_ADDRBWRADDRU6 +26_189 26_190 26_191,BRAM.BRAM_ADDRBWRADDRU7.BRAM_IMUX_ADDRBWRADDRU7 +26_93 26_94 26_95 ,BRAM.BRAM_ADDRBWRADDRU8.BRAM_IMUX_ADDRBWRADDRU8 +26_221 26_222 26_223,BRAM.BRAM_ADDRBWRADDRU9.BRAM_IMUX_ADDRBWRADDRU9 + +26_176 26_177 26_179,BRAM.BRAM_ADDRARDADDRL7.BRAM_R_IMUX_ADDRARDADDRL7 +26_80 26_81 26_83 ,BRAM.BRAM_ADDRARDADDRL8.BRAM_R_IMUX_ADDRARDADDRL8 + +26_165 26_166 26_167,BRAM.BRAM_ADDRARDADDRU6.BRAM_R_IMUX_ADDRARDADDRU6 +26_181 26_182 26_183,BRAM.BRAM_ADDRARDADDRU7.BRAM_R_IMUX_ADDRARDADDRU7 +26_85 26_86 26_87 ,BRAM.BRAM_ADDRARDADDRU8.BRAM_R_IMUX_ADDRARDADDRU8 + +26_88 26_89 26_91 ,BRAM.BRAM_ADDRBWRADDRL8.BRAM_R_IMUX_ADDRBWRADDRL8 + +26_189 26_190 26_191,BRAM.BRAM_ADDRBWRADDRU7.BRAM_R_IMUX_ADDRBWRADDRU7 +26_93 26_94 26_95 ,BRAM.BRAM_ADDRBWRADDRU8.BRAM_R_IMUX_ADDRBWRADDRU8 diff --git a/fuzzers/060-bram-cascades/bram_pip_list.tcl b/fuzzers/060-bram-cascades/bram_pip_list.tcl new file mode 100644 index 00000000..af175f38 --- /dev/null +++ b/fuzzers/060-bram-cascades/bram_pip_list.tcl @@ -0,0 +1,20 @@ +create_project -force -part $::env(XRAY_PART) design design +set_property design_mode PinPlanning [current_fileset] +open_io_design -name io_1 + +proc print_tile_pips {tile_type filename} { + set tile [lindex [get_tiles -filter "TYPE == $tile_type"] 0] + puts "Dumping BRAM PIPs for tile $tile ($tile_type) to $filename." + set fp [open $filename w] + foreach pip [lsort [get_pips -filter {IS_DIRECTIONAL} -of_objects [get_tiles $tile]]] { + set src [get_wires -uphill -of_objects $pip] + set dst [get_wires -downhill -of_objects $pip] + if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 1} { + puts $fp "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]" + } + } + close $fp +} + +print_tile_pips BRAM_L bram_pips_int_l.txt +print_tile_pips BRAM_R bram_pips_int_r.txt diff --git a/fuzzers/060-bram-cascades/generate.py b/fuzzers/060-bram-cascades/generate.py new file mode 100644 index 00000000..ebf373a3 --- /dev/null +++ b/fuzzers/060-bram-cascades/generate.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +from prjxray.segmaker import Segmaker + +segmk = Segmaker("design.bits") + +tiledata = {} +pipdata = {} +ignpip = set() + +print("Loading tags from design.txt.") +with open("design.txt", "r") as f: + for line in f: + tile, pip, src, dst, pnum, pdir = line.split() + + if not tile.startswith('BRAM_'): + continue + + # BRAM_R_X37Y0/BRAM_R.BRAM_IMUX35_1->BRAM_R_IMUX_ADDRBWRADDRL2 + pip_prefix, pip = pip.split(".") + tile_from_pip, tile_type = pip_prefix.split('/') + assert tile == tile_from_pip + _, src = src.split("/") + _, dst = dst.split("/") + pnum = int(pnum) + pdir = int(pdir) + + if tile not in tiledata: + tiledata[tile] = {"type": tile_type, "pips": set(), "srcs": set(), "dsts": set()} + + if tile_type not in pipdata: + pipdata[tile_type] = {} + + if pip in pipdata[tile_type]: + assert pipdata[tile_type][pip] == (src, dst) + else: + pipdata[tile_type][pip] = (src, dst) + + tiledata[tile]["pips"].add(pip) + tiledata[tile]["srcs"].add(src) + tiledata[tile]["dsts"].add(dst) + + if pdir == 0: + tiledata[tile]["srcs"].add(dst) + tiledata[tile]["dsts"].add(src) + + if pnum == 1 or pdir == 0: + ignpip.add(pip) + +for tile, pips_srcs_dsts in tiledata.items(): + tile_type = pips_srcs_dsts["type"] + pips = pips_srcs_dsts["pips"] + srcs = pips_srcs_dsts["srcs"] + dsts = pips_srcs_dsts["dsts"] + + for pip, src_dst in pipdata[tile_type].items(): + src, dst = src_dst + if pip in ignpip: + pass + + elif pip in pips: + segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 1) + elif src_dst[1] not in dsts: + segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 0) + +segmk.compile() +segmk.write() diff --git a/fuzzers/060-bram-cascades/generate.sh b/fuzzers/060-bram-cascades/generate.sh new file mode 100644 index 00000000..c83a1b3c --- /dev/null +++ b/fuzzers/060-bram-cascades/generate.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -ex + +FUZDIR=$PWD +source ${XRAY_GENHEADER} + +echo '`define SEED 32'"'h$(echo $1 | md5sum | cut -c1-8)" > setseed.vh + +${XRAY_VIVADO} -mode batch -source $FUZDIR/generate.tcl | tee vivado_stdout.log | grep "FUZ[^:]\+:" + +${XRAY_BITREAD} -F $XRAY_ROI_FRAMES -o design.bits -z -y design.bit +python3 $FUZDIR/generate.py + diff --git a/fuzzers/060-bram-cascades/generate.tcl b/fuzzers/060-bram-cascades/generate.tcl new file mode 100644 index 00000000..e65d9b96 --- /dev/null +++ b/fuzzers/060-bram-cascades/generate.tcl @@ -0,0 +1,45 @@ +puts "FUZ([pwd]): Creating project" +create_project -force -part $::env(XRAY_PART) design design + +puts "FUZ([pwd]): Reading verilog" +read_verilog top.v + +puts "FUZ([pwd]): Synth design" +synth_design -top top + +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 + +source "$::env(XRAY_DIR)/utils/utils.tcl" + +puts "FUZ([pwd]): Placing design" +place_design +puts "FUZ([pwd]): Routing design" +route_design + +write_checkpoint -force design.dcp + +proc write_txtdata {filename} { + puts "FUZ([pwd]): Writing $filename." + set fp [open $filename w] + foreach net [get_nets -hierarchical] { + if [string match "*addr*" $net] { + puts "Tick $net." + foreach pip [get_pips -of_objects $net] { + set tile [get_tiles -of_objects $pip] + set src_wire [get_wires -uphill -of_objects $pip] + set dst_wire [get_wires -downhill -of_objects $pip] + set num_pips [llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst_wire]]] + set dir_prop [get_property IS_DIRECTIONAL $pip] + puts $fp "$tile $pip $src_wire $dst_wire $num_pips $dir_prop" + } + } + } + close $fp +} + +write_bitstream -force design.bit +write_txtdata design.txt diff --git a/fuzzers/060-bram-cascades/top.py b/fuzzers/060-bram-cascades/top.py new file mode 100644 index 00000000..c77b4ee6 --- /dev/null +++ b/fuzzers/060-bram-cascades/top.py @@ -0,0 +1,211 @@ +import os +import sys +import random +import math +from prjxray import util +from prjxray.db import Database +random.seed(int(os.getenv("SEED"), 16)) + +def bram_count(): + db = Database(util.get_db_root()) + grid = db.grid() + + count = 0 + for tile_name in grid.tiles(): + loc = grid.loc_of_tilename(tile_name) + gridinfo = grid.gridinfo_at_loc(loc) + + for site_name, site_type in gridinfo.sites.items(): + if site_type in ['RAMBFIFO36E1']: + count += 1 + + return count + +class LutMaker(object): + def __init__(self): + self.input_lut_idx = 0 + self.output_lut_idx = 0 + self.lut_input_idx = 0 + + def get_next_input_net(self): + net = 'lut_{}_i[{}]'.format(self.input_lut_idx, self.lut_input_idx) + + self.lut_input_idx += 1 + if self.lut_input_idx > 5: + self.lut_input_idx = 0 + self.input_lut_idx += 1 + + return net + + def get_next_output_net(self): + net = 'lut_{}_o'.format(self.output_lut_idx) + self.output_lut_idx += 1 + return net + + def create_wires_and_luts(self): + if self.output_lut_idx > self.input_lut_idx: + nluts = self.output_lut_idx + else: + nluts = self.input_lut_idx + if self.lut_input_idx > 0: + nluts += 1 + + for lut in range(nluts): + yield """ + wire [5:0] lut_{lut}_i; + wire lut_{lut}_o; + + (* KEEP, DONT_TOUCH *) + LUT6 lut_{lut} ( + .I0(lut_{lut}_i[0]), + .I1(lut_{lut}_i[1]), + .I2(lut_{lut}_i[2]), + .I3(lut_{lut}_i[3]), + .I4(lut_{lut}_i[4]), + .I5(lut_{lut}_i[5]), + .O(lut_{lut}_o) + ); + """.format(lut=lut) + +def sdp_bram(name, width, address_bits): + depth = 2**address_bits + + return ''' +module {name}( + // Write port + input wrclk, + input [{width}-1:0] di, + input wren, + input [{address_bits}-1:0] wraddr, + // Read port + input rdclk, + input rden, + input [{address_bits}-1:0] rdaddr, + output reg [{width}-1:0] do); + + (* ram_style = "block" *) reg [{width}-1:0] ram[0:{depth}]; + + always @ (posedge wrclk) begin + if(wren == 1) begin + ram[wraddr] <= di; + end + end + + always @ (posedge rdclk) begin + if(rden == 1) begin + do <= ram[rdaddr]; + end + end + +endmodule + '''.format( + name=name, + width=width, + address_bits=address_bits, + depth=depth, + ) + +MAX_BRAM = 8 + +def emit_sdp_bram(luts, name, modules, lines, width, address_bits): + modules.append(sdp_bram(name=name, width=width, address_bits=address_bits)) + + lines.append(''' + wire [9:0] {name}_wraddr; + wire [9:0] {name}_rdaddr; + '''.format(name=name)) + + for bit in range(10): + lines.append(""" + assign {name}_wraddr[{bit}] = {net};""".format( + name=name, + bit=bit, + net=luts.get_next_output_net())) + + for bit in range(10): + lines.append(""" + assign {name}_rdaddr[{bit}] = {net};""".format( + name=name, + bit=bit, + net=luts.get_next_output_net())) + + lines.append(''' + (* KEEP, DONT_TOUCH *) + {name} {name}_inst( + .wraddr({name}_wraddr), + .rdaddr({name}_rdaddr) + ); + '''.format(name=name)) + + return width, address_bits, math.ceil(float(width)/72)*72*(2**address_bits) + +def max_address_bits(width): + return math.floor(math.log(float(MAX_BRAM*36*1024)/width, 2)) + +def random_sdp_bram(luts, name, modules, lines): + sdp_choices = set() + + for width in (1, 18, 36): + sdp_choices.add((width, (1, max_address_bits(width)))) + + for nbram in range(2, MAX_BRAM+1): + #sdp_choices.add((nbram*32, (1, max_address_bits(nbram*32)))) + #sdp_choices.add((nbram*36, (1, max_address_bits(nbram*36)))) + #sdp_choices.add((nbram*16, (1, max_address_bits(nbram*16)))) + #sdp_choices.add((nbram*32, (1, max_address_bits(nbram*32)))) + + # Bias some wide but shallow BRAMs to toggle the lower address bits + # more. + for address_bits in range(1, 4): + sdp_choices.add((nbram*32, (address_bits, address_bits))) + + sdp_choices = sorted(sdp_choices) + + width, address_bits_range = random.choice(sdp_choices) + address_bits = random.randint(*address_bits_range) + return emit_sdp_bram(luts, name, modules, lines, width, address_bits) + + +def run(): + luts = LutMaker() + count = bram_count() + + max_bram_count = random.randint(1, 200) + + modules = [] + lines = [] + + idx = 0 + while count > MAX_BRAM: + width, address_bits, bits = random_sdp_bram(luts, "ram{}".format(idx), modules, lines) + + brams = math.ceil(bits/float(36*1024)) + + count -= brams + + print(width, address_bits, bits, brams, count, file=sys.stderr) + idx += 1 + + if idx >= max_bram_count: + break + + for module in modules: + print(module) + + print( + ''' +module top(); +''') + + for lut in luts.create_wires_and_luts(): + print(lut) + + for l in lines: + print(l) + + print("endmodule") + + +if __name__ == '__main__': + run() + diff --git a/fuzzers/071-ppips/generate.tcl b/fuzzers/071-ppips/generate.tcl index 8f1a5c47..d5a749af 100644 --- a/fuzzers/071-ppips/generate.tcl +++ b/fuzzers/071-ppips/generate.tcl @@ -60,6 +60,29 @@ proc write_int_ppips_db {filename tile} { close $fp } +proc write_bram_ppips_db {filename tile} { + set fp [open $filename "w"] + set tile [get_tiles $tile] + set tile_type [get_property TILE_TYPE $tile] + + foreach pip [get_pips -of_objects $tile] { + set dst_wire [get_wires -downhill -of_objects $pip] + if {[get_pips -uphill -of_objects [get_nodes -of_objects $dst_wire]] == $pip} { + set src_wire [get_wires -uphill -of_objects $pip] + puts $fp "${tile_type}.[regsub {.*/} $dst_wire ""].[regsub {.*/} $src_wire ""] always" + } + + # LOGIC_OUTS pips appear to be always, even thought multiple inputs to + # the pip junction. Best guess is that the underlying hardware is + # actually just one wire, and there is no actually junction. + if [string match "*LOGIC_OUTS*" dst_wire] { + puts $fp "${tile_type}.[regsub {.*/} $dst_wire ""].[regsub {.*/} $src_wire ""] always" + } + } + + close $fp +} + foreach tile_type {CLBLM_L CLBLM_R CLBLL_L CLBLL_R} { set tiles [get_tiles -filter "TILE_TYPE == $tile_type"] if {[llength $tiles] != 0} { @@ -68,10 +91,17 @@ foreach tile_type {CLBLM_L CLBLM_R CLBLL_L CLBLL_R} { } } -foreach tile_type {INT_L INT_R BRAM_L BRAM_R BRAM_INT_INTERFACE_L BRAM_INT_INTERFACE_R} { +foreach tile_type {INT_L INT_R BRAM_INT_INTERFACE_L BRAM_INT_INTERFACE_R} { set tiles [get_tiles -filter "TILE_TYPE == $tile_type"] if {[llength $tiles] != 0} { set tile [lindex $tiles 0] write_int_ppips_db "ppips_[string tolower $tile_type].db" $tile } } +foreach tile_type {BRAM_L BRAM_R} { + set tiles [get_tiles -filter "TILE_TYPE == $tile_type"] + if {[llength $tiles] != 0} { + set tile [lindex $tiles 0] + write_bram_ppips_db "ppips_[string tolower $tile_type].db" $tile + } +} diff --git a/fuzzers/int_loop.mk b/fuzzers/int_loop.mk index a213355e..c2015768 100644 --- a/fuzzers/int_loop.mk +++ b/fuzzers/int_loop.mk @@ -1,28 +1,4 @@ -TODO_N ?= 50 -# Number of spcimens -ifeq ($(QUICK),Y) -N = 1 -TODO_N = 3 -SEGMATCH_FLAGS= -else -# Should be at least the -m value -N ?= 20 -SEGMATCH_FLAGS=-m 15 -M 45 -endif -# Iteration number (each containing N specimens) -# Driven by int_loop.sh -ITER ?= 1 -MAKETODO_FLAGS ?= -PIP_TYPE?=pips_int -PIPLIST_TCL?=$(XRAY_FUZZERS_DIR)/piplist/piplist.tcl - -# See int_loop_check.py -# rempips took 35 iters once, so set 50 as a good start point -CHECK_ARGS := --zero-entries --timeout-iters 50 -SPECIMENS := $(addprefix build/$(ITER)/specimen_,$(shell seq -f '%03.0f' $(N))) -SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) -# Individual fuzzer directory, such as ~/prjxray/fuzzers/010-lutinit -export FUZDIR=$(shell pwd) +include pip_loop.mk # Specimens from current run must complete, but previous iterations may exist database: $(SPECIMENS_OK) @@ -55,50 +31,3 @@ pushdb: ${XRAY_MERGEDB} mask_clbll_r build/mask_clbll_r.db ${XRAY_MERGEDB} mask_clblm_l build/mask_clblm_l.db ${XRAY_MERGEDB} mask_clblm_r build/mask_clblm_r.db - -$(SPECIMENS_OK): build/todo.txt - mkdir -p build/$(ITER) - bash ${XRAY_DIR}/utils/top_generate.sh $(subst /OK,,$@) - touch $@ - -$(XRAY_FUZZERS_DIR)/piplist/build/$(PIP_TYPE)_l.txt: $(PIPLIST_TCL) - mkdir -p $(XRAY_FUZZERS_DIR)/piplist/build - cd $(XRAY_FUZZERS_DIR)/piplist/build && ${XRAY_VIVADO} -mode batch -source $(PIPLIST_TCL) - -# Used 1) to see if we are done 2) pips to try in generate.tcl -build/todo.txt: $(XRAY_FUZZERS_DIR)/piplist/build/$(PIP_TYPE)_l.txt $(XRAY_DIR)/fuzzers/int_maketodo.py build/database/seeded - XRAY_DATABASE_DIR=${FUZDIR}/build/database python3 $(XRAY_DIR)/fuzzers/int_maketodo.py --pip-type $(PIP_TYPE) $(MAKETODO_FLAGS) |sort >build/todo_all.txt - cat build/todo_all.txt | sort -R | head -n$(TODO_N) > build/todo.txt.tmp - mv build/todo.txt.tmp build/todo.txt - # Per iter files - mkdir -p build/$(ITER) - cp build/todo_all.txt build/todo.txt build/$(ITER)/ - # All in one dir for easier trending - mkdir -p build/todo - cp build/todo_all.txt build/todo/$(ITER)_all.txt - -# Initial copy for first todo.txt -# Subsequent are based on updated db -build/database/seeded: - mkdir -p build/database/${XRAY_DATABASE} - cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db build/database/${XRAY_DATABASE} - touch build/database/seeded - -# XXX: conider moving to script -run: - $(MAKE) clean - XRAY_DIR=${XRAY_DIR} MAKE="$(MAKE)" QUICK=$(QUICK) $(XRAY_DIR)/fuzzers/int_loop.sh --check-args "$(CHECK_ARGS)" - touch run.ok - -clean: - rm -rf build run.ok todo - -# Remove iteration specific files, but keep piplist.tcl output -cleaniter: - rm -rf build/$(ITER) build/todo.txt - -cleanpiplist: - rm -rf $(XRAY_FUZZERS_DIR)/piplist/build - -.PHONY: database pushdb run clean cleaniter cleanpiplist - diff --git a/fuzzers/int_maketodo.py b/fuzzers/int_maketodo.py index 7e1e31b1..69b1d9e3 100644 --- a/fuzzers/int_maketodo.py +++ b/fuzzers/int_maketodo.py @@ -91,6 +91,7 @@ def run( pip_dir, intre, pip_type, + seg_type, not_endswith=None, verbose=False): if db_dir is None: @@ -103,13 +104,13 @@ def run( assert intre, "RE is required" maketodo( "%s/%s_l.txt" % (pip_dir, pip_type), - "%s/segbits_int_l.db" % db_dir, + "%s/segbits_%s_l.db" % (db_dir, seg_type), intre, not_endswith, verbose=verbose) maketodo( "%s/%s_r.txt" % (pip_dir, pip_type), - "%s/segbits_int_r.db" % db_dir, + "%s/segbits_%s_r.db" % (db_dir, seg_type), intre, not_endswith, verbose=verbose) @@ -127,6 +128,7 @@ def main(): parser.add_argument('--pip-dir', default=None, help='') parser.add_argument('--re', required=True, help='') parser.add_argument('--pip-type', default="pips_int", help='') + parser.add_argument('--seg-type', default="int", help='') parser.add_argument( '--not-endswith', help='Drop lines if they end with this') args = parser.parse_args() @@ -137,6 +139,7 @@ def main(): pip_dir=args.pip_dir, intre=args.re, pip_type=args.pip_type, + seg_type=args.seg_type, not_endswith=args.not_endswith, verbose=args.verbose) diff --git a/fuzzers/pip_loop.mk b/fuzzers/pip_loop.mk new file mode 100644 index 00000000..768f62ec --- /dev/null +++ b/fuzzers/pip_loop.mk @@ -0,0 +1,75 @@ +TODO_N ?= 50 +# Number of spcimens +ifeq ($(QUICK),Y) +N = 1 +TODO_N = 3 +SEGMATCH_FLAGS= +else +# Should be at least the -m value +N ?= 20 +SEGMATCH_FLAGS=-m 15 -M 45 +endif +# Iteration number (each containing N specimens) +# Driven by int_loop.sh +ITER ?= 1 +MAKETODO_FLAGS ?= +PIP_TYPE?=pips_int +SEG_TYPE?=int +PIPLIST_TCL?=$(XRAY_FUZZERS_DIR)/piplist/piplist.tcl + +# See int_loop_check.py +# rempips took 35 iters once, so set 50 as a good start point +CHECK_ARGS := --zero-entries --timeout-iters 50 +SPECIMENS := $(addprefix build/$(ITER)/specimen_,$(shell seq -f '%03.0f' $(N))) +SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) +# Individual fuzzer directory, such as ~/prjxray/fuzzers/010-lutinit +export FUZDIR=$(shell pwd) + +all: database + +$(SPECIMENS_OK): build/todo.txt + mkdir -p build/$(ITER) + bash ${XRAY_DIR}/utils/top_generate.sh $(subst /OK,,$@) + touch $@ + +$(XRAY_FUZZERS_DIR)/piplist/build/$(PIP_TYPE)_l.txt: $(PIPLIST_TCL) + mkdir -p $(XRAY_FUZZERS_DIR)/piplist/build + cd $(XRAY_FUZZERS_DIR)/piplist/build && ${XRAY_VIVADO} -mode batch -source $(PIPLIST_TCL) + +# Used 1) to see if we are done 2) pips to try in generate.tcl +build/todo.txt: $(XRAY_FUZZERS_DIR)/piplist/build/$(PIP_TYPE)_l.txt $(XRAY_DIR)/fuzzers/int_maketodo.py build/database/seeded + XRAY_DATABASE_DIR=${FUZDIR}/build/database python3 $(XRAY_DIR)/fuzzers/int_maketodo.py --pip-type $(PIP_TYPE) --seg-type $(SEG_TYPE) $(MAKETODO_FLAGS) |sort >build/todo_all.txt + cat build/todo_all.txt | sort -R | head -n$(TODO_N) > build/todo.txt.tmp + mv build/todo.txt.tmp build/todo.txt + # Per iter files + mkdir -p build/$(ITER) + cp build/todo_all.txt build/todo.txt build/$(ITER)/ + # All in one dir for easier trending + mkdir -p build/todo + cp build/todo_all.txt build/todo/$(ITER)_all.txt + +# Initial copy for first todo.txt +# Subsequent are based on updated db +build/database/seeded: + mkdir -p build/database/${XRAY_DATABASE} + cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db build/database/${XRAY_DATABASE} + touch build/database/seeded + +# XXX: conider moving to script +run: + $(MAKE) clean + XRAY_DIR=${XRAY_DIR} MAKE="$(MAKE)" QUICK=$(QUICK) $(XRAY_DIR)/fuzzers/int_loop.sh --check-args "$(CHECK_ARGS)" + touch run.ok + +clean: + rm -rf build run.ok todo + +# Remove iteration specific files, but keep piplist.tcl output +cleaniter: + rm -rf build/$(ITER) build/todo.txt + +cleanpiplist: + rm -rf $(XRAY_FUZZERS_DIR)/piplist/build + +.PHONY: all database pushdb run clean cleaniter cleanpiplist + diff --git a/utils/dbfixup.py b/utils/dbfixup.py index 37509fa0..34cf1769 100755 --- a/utils/dbfixup.py +++ b/utils/dbfixup.py @@ -20,7 +20,7 @@ clb_int_zero_db = [ def zero_range(tag, bits, wordmin, wordmax): """ If any bits occur wordmin <= word <= wordmax, - default bits in wordmin <= word <= wordmax to 0 + default bits in wordmin <= word <= wordmax to 0 """ # The bit index, if any, that needs to be one hotted @@ -105,7 +105,7 @@ def zero_groups(tag, bits, zero_db, strict=True, verbose=False): def add_zero_bits( - fn_in, fn_out, zero_db, clb_int=False, strict=True, verbose=False): + fn_in, zero_db, clb_int=False, strict=True, verbose=False): ''' Add multibit entries This requires adding some zero bits (ex: !31_09) @@ -154,6 +154,13 @@ def add_zero_bits( zero_range(tag, bits, 22, 25) zero_groups(tag, bits, zero_db, strict=strict, verbose=verbose) + if len(bits) == 0: + verbose and print( + "WARNING: dropping unresolved line: %s" % line) + drops += 1 + continue + + new_line = " ".join([tag] + sorted(bits)) if re.match(r'.*<.*>.*', new_line): @@ -168,11 +175,7 @@ def add_zero_bits( if drops: print("WARNING: %s dropped %s unresolved lines" % (fn_in, drops)) - with open(fn_out, "w") as f: - for line in sorted(new_lines): - print(line, file=f) - - return changes + return changes, new_lines def update_mask(db_root, mask_db, src_dbs, offset=0): @@ -224,6 +227,57 @@ def load_zero_db(fn): ret.append(l) return ret +def remove_ambiguous_solutions(fn_in, db_lines, strict=True, verbose=True): + """ Removes features with identical solutions. + + During solving, some tags may be tightly coupled and solve to the same + solution. In these cases, those solutions must be dropped until + disambiguating information can be found. + """ + solutions = {} + dropped_solutions = set() + + for l in db_lines: + parts = l.split() + feature = parts[0] + bits = frozenset(parts[1:]) + + if bits in solutions: + if strict: + assert False, "Found solution {} at least twice, in {} and {}".format( + bits, feature, solutions[bits]) + else: + dropped_solutions.add(bits) + else: + solutions[bits] = feature + + + if strict: + return 0, db_lines + + drops = 0 + output_lines = [] + + for l in db_lines: + parts = l.split() + feature = parts[0] + bits = frozenset(parts[1:]) + + if bits not in dropped_solutions: + output_lines.append(l) + drops += 1 + else: + if verbose: + print( + "WARNING: dropping line due to duplicate solution: %s" % l) + + if drops > 0: + print("WARNING: %s dropped %s duplicate solutions" % (fn_in, drops)) + + return drops, output_lines + + + def update_seg_fns( fn_inouts, zero_db, clb_int, lazy=False, strict=True, verbose=False): @@ -234,13 +288,27 @@ def update_seg_fns( if lazy and not os.path.exists(fn_in): continue - changes = add_zero_bits( + changes, new_lines = add_zero_bits( fn_in, - fn_out, zero_db, clb_int=clb_int, strict=strict, verbose=verbose) + + new_changes, final_lines = remove_ambiguous_solutions( + fn_in, + new_lines, + strict=strict, + verbose=verbose, + ) + + changes += new_changes + + + with open(fn_out, "w") as f: + for line in sorted(final_lines): + print(line, file=f) + if changes is not None: seg_files += 1 seg_lines += changes @@ -249,6 +317,7 @@ def update_seg_fns( (seg_files, seg_lines)) + def update_masks(db_root): for mask_db, src_dbs in [ ("clbll_l", ("clbll_l", "int_l")), @@ -348,7 +417,7 @@ def main(): parser.add_argument('--zero-db', help='Apply custom patches') parser.add_argument('--seg-fn-in', help='') parser.add_argument('--seg-fn-out', help='') - util.add_bool_arg(parser, "--strict", default=None) + util.add_bool_arg(parser, "--strict", default=False) args = parser.parse_args() run( diff --git a/utils/environment.sh b/utils/environment.sh index 8ccfb715..e5e76da8 100644 --- a/utils/environment.sh +++ b/utils/environment.sh @@ -27,7 +27,7 @@ export XRAY_DBFIXUP="python3 ${XRAY_UTILS_DIR}/dbfixup.py" export XRAY_MASKMERGE="bash ${XRAY_UTILS_DIR}/maskmerge.sh" export XRAY_SEGMATCH="${XRAY_TOOLS_DIR}/segmatch" export XRAY_SEGPRINT="python3 ${XRAY_UTILS_DIR}/segprint.py" -export XRAY_BITS2FASM="python3 ${XRAY_UTILS_DIR}/bits2fasm.py" +export XRAY_BIT2FASM="python3 ${XRAY_UTILS_DIR}/bit2fasm.py" export XRAY_FASM2FRAMES="python3 ${XRAY_UTILS_DIR}/fasm2frames.py" export XRAY_BITTOOL="${XRAY_TOOLS_DIR}/bittool" export XRAY_BLOCKWIDTH="python3 ${XRAY_UTILS_DIR}/blockwidth.py" diff --git a/utils/top_generate.mk b/utils/top_generate.mk index 207a0fd1..690b7c63 100644 --- a/utils/top_generate.mk +++ b/utils/top_generate.mk @@ -17,6 +17,7 @@ design_bits.ok: vivado.ok \ for x in design*.bit; do \ ${XRAY_BITREAD} -F ${XRAY_ROI_FRAMES} -o $${x}s -z -y $$x ; \ + ${XRAY_BIT2FASM} --verbose $$x > $${x%.*}.fasm; \ done touch design_bits.ok