Merge pull request #581 from litghost/bram_cascade-fuzzer

BRAM Cascade pip fuzzer.
This commit is contained in:
litghost 2019-01-31 13:55:35 -08:00 committed by GitHub
commit c614a52d2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 708 additions and 90 deletions

View File

@ -0,0 +1,39 @@
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
# These PIPs all appear to be either a 0 or 2 bit solution.
SEGMATCH_FLAGS=-m 20 -M 45 -c 2
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_x.rdb \
$(shell find build -name segdata_bram_l.txt) \
$(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_x.rdb build/$(ITER)/segbits_bram_x.rdb
${XRAY_DBFIXUP} --db-root build \
--verbose \
--zero-db bits.dbf \
--seg-fn-in build/segbits_bram_x.rdb \
--seg-fn-out build/segbits_bram_x.db
python3 unmanagle_pips.py \
--bram_x build/segbits_bram_x.db \
--bram_l build/segbits_bram_l.db \
--bram_r 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

View File

@ -0,0 +1,63 @@
26_32 26_33 26_35 ,BRAM.BRAM_ADDRARDADDRL0.BRAM_IMUX_ADDRARDADDRL0
26_48 26_49 26_51 ,BRAM.BRAM_ADDRARDADDRL1.BRAM_IMUX_ADDRARDADDRL1
26_64 26_65 26_67 ,BRAM.BRAM_ADDRARDADDRL2.BRAM_IMUX_ADDRARDADDRL2
26_192 26_193 26_195,BRAM.BRAM_ADDRARDADDRL3.BRAM_IMUX_ADDRARDADDRL3
26_96 26_97 26_99 ,BRAM.BRAM_ADDRARDADDRL4.BRAM_IMUX_ADDRARDADDRL4
26_224 26_225 26_227,BRAM.BRAM_ADDRARDADDRL5.BRAM_IMUX_ADDRARDADDRL5
26_160 26_161 26_163,BRAM.BRAM_ADDRARDADDRL6.BRAM_IMUX_ADDRARDADDRL6
26_176 26_177 26_179,BRAM.BRAM_ADDRARDADDRL7.BRAM_IMUX_ADDRARDADDRL7
26_80 26_81 26_83 ,BRAM.BRAM_ADDRARDADDRL8.BRAM_IMUX_ADDRARDADDRL8
26_208 26_209 26_211,BRAM.BRAM_ADDRARDADDRL9.BRAM_IMUX_ADDRARDADDRL9
26_144 26_145 26_147,BRAM.BRAM_ADDRARDADDRL10.BRAM_IMUX_ADDRARDADDRL10
26_112 26_113 26_115,BRAM.BRAM_ADDRARDADDRL11.BRAM_IMUX_ADDRARDADDRL11
26_240 26_241 26_243,BRAM.BRAM_ADDRARDADDRL12.BRAM_IMUX_ADDRARDADDRL12
26_128 26_129 26_131,BRAM.BRAM_ADDRARDADDRL13.BRAM_IMUX_ADDRARDADDRL13
26_256 26_257 26_259,BRAM.BRAM_ADDRARDADDRL14.BRAM_IMUX_ADDRARDADDRL14
26_40 26_41 26_43 ,BRAM.BRAM_ADDRBWRADDRL0.BRAM_IMUX_ADDRBWRADDRL0
26_56 26_57 26_59 ,BRAM.BRAM_ADDRBWRADDRL1.BRAM_IMUX_ADDRBWRADDRL1
26_72 26_73 26_75 ,BRAM.BRAM_ADDRBWRADDRL2.BRAM_IMUX_ADDRBWRADDRL2
26_200 26_201 26_203,BRAM.BRAM_ADDRBWRADDRL3.BRAM_IMUX_ADDRBWRADDRL3
26_104 26_105 26_107,BRAM.BRAM_ADDRBWRADDRL4.BRAM_IMUX_ADDRBWRADDRL4
26_232 26_233 26_235,BRAM.BRAM_ADDRBWRADDRL5.BRAM_IMUX_ADDRBWRADDRL5
26_168 26_169 26_171,BRAM.BRAM_ADDRBWRADDRL6.BRAM_IMUX_ADDRBWRADDRL6
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_216 26_217 26_219,BRAM.BRAM_ADDRBWRADDRL9.BRAM_IMUX_ADDRBWRADDRL9
26_152 26_153 26_155,BRAM.BRAM_ADDRBWRADDRL10.BRAM_IMUX_ADDRBWRADDRL10
26_120 26_121 26_123,BRAM.BRAM_ADDRBWRADDRL11.BRAM_IMUX_ADDRBWRADDRL11
26_248 26_249 26_251,BRAM.BRAM_ADDRBWRADDRL12.BRAM_IMUX_ADDRBWRADDRL12
26_136 26_137 26_139,BRAM.BRAM_ADDRBWRADDRL13.BRAM_IMUX_ADDRBWRADDRL13
26_264 26_265 26_267,BRAM.BRAM_ADDRBWRADDRL14.BRAM_IMUX_ADDRBWRADDRL14
26_37 26_38 26_39 ,BRAM.BRAM_ADDRARDADDRU0.BRAM_IMUX_ADDRARDADDRU0
26_53 26_54 26_55 ,BRAM.BRAM_ADDRARDADDRU1.BRAM_IMUX_ADDRARDADDRU1
26_69 26_70 26_71 ,BRAM.BRAM_ADDRARDADDRU2.BRAM_IMUX_ADDRARDADDRU2
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_149 26_150 26_151,BRAM.BRAM_ADDRARDADDRU10.BRAM_IMUX_ADDRARDADDRU10
26_117 26_118 26_119,BRAM.BRAM_ADDRARDADDRU11.BRAM_IMUX_ADDRARDADDRU11
26_245 26_246 26_247,BRAM.BRAM_ADDRARDADDRU12.BRAM_IMUX_ADDRARDADDRU12
26_133 26_134 26_135,BRAM.BRAM_ADDRARDADDRU13.BRAM_IMUX_ADDRARDADDRU13
26_261 26_262 26_263,BRAM.BRAM_ADDRARDADDRU14.BRAM_IMUX_ADDRARDADDRU14
26_45 26_46 26_47 ,BRAM.BRAM_ADDRBWRADDRU0.BRAM_IMUX_ADDRBWRADDRU0
26_61 26_62 26_63 ,BRAM.BRAM_ADDRBWRADDRU1.BRAM_IMUX_ADDRBWRADDRU1
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_109 26_110 26_111,BRAM.BRAM_ADDRBWRADDRU4.BRAM_IMUX_ADDRBWRADDRU4
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_157 26_158 26_159,BRAM.BRAM_ADDRBWRADDRU10.BRAM_IMUX_ADDRBWRADDRU10
26_125 26_126 26_127,BRAM.BRAM_ADDRBWRADDRU11.BRAM_IMUX_ADDRBWRADDRU11
26_253 26_254 26_255,BRAM.BRAM_ADDRBWRADDRU12.BRAM_IMUX_ADDRBWRADDRU12
26_141 26_142 26_143,BRAM.BRAM_ADDRBWRADDRU13.BRAM_IMUX_ADDRBWRADDRU13
26_269 26_270 26_271,BRAM.BRAM_ADDRBWRADDRU14.BRAM_IMUX_ADDRBWRADDRU14

View File

@ -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

View File

@ -0,0 +1,84 @@
#!/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
# BRAM_R has some _R_ added to some pips. Because BRAM_L and BRAM_R
# appears to shares all bits, overlap the names during fuzzing to avoid
# extra work.
#
# BRAM.BRAM_ADDRARDADDRL0.BRAM_IMUX_R_ADDRARDADDRL0
#
# becomes
#
# BRAM.BRAM_ADDRARDADDRL0.BRAM_IMUX_ADDRARDADDRL0
src_no_r = src.replace('BRAM_R_IMUX_ADDR', 'BRAM_IMUX_ADDR')
if pip in ignpip:
pass
elif pip in pips:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src_no_r), 1)
elif src_dst[1] not in dsts:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src_no_r), 0)
segmk.compile()
segmk.write()

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,221 @@
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 [{address_bits}-1:0] {name}_wraddr;
wire [{address_bits}-1:0] {name}_rdaddr;
'''.format(
name=name,
address_bits=address_bits,
))
for bit in range(address_bits):
lines.append(
"""
assign {name}_wraddr[{bit}] = {net};""".format(
name=name, bit=bit, net=luts.get_next_output_net()))
for bit in range(address_bits):
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, 2, 4, 8, 16, 18, 32, 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 * 16, (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()

View File

@ -0,0 +1,33 @@
import argparse
def main():
parser = argparse.ArgumentParser(
description="Converts generic BRAM pips to BRAM_L and BRAM_R pips.")
parser.add_argument('--bram_x', required=True)
parser.add_argument('--bram_l', required=True)
parser.add_argument('--bram_r', required=True)
args = parser.parse_args()
with open(args.bram_x, 'r') as f_in, open(
args.bram_l, 'w') as f_l_out, open(args.bram_r, 'w') as f_r_out:
for l in f_in:
# BRAM_L has the same pip names as BRAM_X
print(l.strip(), file=f_l_out)
# BRAM_R has some _R_ added to some pips.
#
# BRAM.BRAM_ADDRARDADDRL0.BRAM_IMUX_ADDRARDADDRL0
#
# becomes
#
# BRAM.BRAM_ADDRARDADDRL0.BRAM_IMUX_R_ADDRARDADDRL0
print(
l.strip().replace('BRAM_IMUX_ADDR', 'BRAM_R_IMUX_ADDR'),
file=f_r_out)
if __name__ == '__main__':
main()

View File

@ -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
}
}

View File

@ -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

View File

@ -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)

75
fuzzers/pip_loop.mk Normal file
View File

@ -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

View File

@ -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
@ -104,8 +104,7 @@ def zero_groups(tag, bits, zero_db, strict=True, verbose=False):
len(a), len(bits), bits_str(bits))
def add_zero_bits(
fn_in, fn_out, zero_db, clb_int=False, strict=True, verbose=False):
def add_zero_bits(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 +153,14 @@ def add_zero_bits(
zero_range(tag, bits, 22, 25)
zero_groups(tag, bits, zero_db, strict=strict, verbose=verbose)
if strict:
assert len(bits) > 0, 'Line {} found no bits.'.format(line)
elif 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):
@ -225,6 +228,55 @@ def load_zero_db(fn):
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):
seg_files = 0
@ -234,13 +286,22 @@ 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, zero_db, clb_int=clb_int, strict=strict, verbose=verbose)
new_changes, final_lines = remove_ambiguous_solutions(
fn_in,
fn_out,
zero_db,
clb_int=clb_int,
new_lines,
strict=strict,
verbose=verbose)
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
@ -348,7 +409,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(

View File

@ -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"

View File

@ -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