diff --git a/fuzzers/010-lutinit/.gitignore b/fuzzers/010-lutinit/.gitignore new file mode 100644 index 00000000..47f246a6 --- /dev/null +++ b/fuzzers/010-lutinit/.gitignore @@ -0,0 +1,2 @@ +/specimen_[0-9][0-9][0-9]/ +/database.txt diff --git a/fuzzers/010-lutinit/Makefile b/fuzzers/010-lutinit/Makefile new file mode 100644 index 00000000..0273a2a7 --- /dev/null +++ b/fuzzers/010-lutinit/Makefile @@ -0,0 +1,20 @@ + +N := 1 +SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N))) +SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) + +database.txt: $(SPECIMENS_OK) + ../../tools/segmatch -o database.txt \ + $(addsuffix /segdata_0.txt,$(SPECIMENS)) \ + $(addsuffix /segdata_1.txt,$(SPECIMENS)) \ + $(addsuffix /segdata_2.txt,$(SPECIMENS)) + +$(SPECIMENS_OK): + bash generate.sh $(subst /OK,,$@) + touch $@ + +clean: + rm -rf $(SPECIMENS) + +.PHONY: clean + diff --git a/fuzzers/010-lutinit/generate.py b/fuzzers/010-lutinit/generate.py new file mode 100644 index 00000000..512a2d6e --- /dev/null +++ b/fuzzers/010-lutinit/generate.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 + +import os, sys, json, re + + +################################################# +# Loading Raw Source Data + +grid = None +bits = dict() +luts = dict() + +print("Loading grid.") +with open("../../../gridinfo/grid-%s-db.json" % os.getenv("XRAY_PART"), "r") as f: + grid = json.load(f) + +print("Loading bits.") +with open("design_%s.bits" % sys.argv[1], "r") as f: + for line in f: + line = line.split("_") + bit_frame = int(line[1], 16) + bit_wordidx = int(line[2], 16) + bit_bitidx = int(line[3], 16) + base_frame = bit_frame & ~0x7f + + if base_frame not in bits: + bits[base_frame] = dict() + + if bit_wordidx not in bits[base_frame]: + bits[base_frame][bit_wordidx] = set() + + bits[base_frame][bit_wordidx].add((bit_frame, bit_wordidx, bit_bitidx)) + +print("Loading lut data.") +with open("lutdata_%s.txt" % sys.argv[1], "r") as f: + for line in f: + line = line.split() + site = line[0] + bel = line[1] + init = int(line[2][4:], 16) + + if site not in luts: + luts[site] = dict() + + for i in range(64): + bitname = "%s.INIT[%02d]" % (bel, i) + luts[site][bitname] = ((init >> i) & 1) != 0 + + +################################################# +# Group per Segment + +print("Compile segment data.") + +segments = dict() + +for tilename, tiledata in grid["tiles"].items(): + found_data = False + for site in tiledata["sites"]: + if site in luts: + found_data = True + + if not found_data: + continue + + tile_type = tiledata["props"]["TYPE"] + segname = "%s_%02x" % (tiledata["cfgcol"]["BASE_FRAMEID"][2:], min(tiledata["cfgcol"]["WORDS"])) + + if not segname in segments: + segments[segname] = { "bits": list(), "tags": dict() } + + for site in tiledata["sites"]: + if site not in luts: + continue + + if re.match(r"SLICE_X[0-9]*[02468]Y", site): + sitekey = "SLICE_X0" + elif re.match(r"SLICE_X[0-9]*[13579]Y", site): + sitekey = "SLICE_X1" + else: + assert 0 + + for name, value in luts[site].items(): + segments[segname]["tags"]["%s.%s.%s" % (tile_type, sitekey, name)] = value + + base_frame = int(tiledata["cfgcol"]["BASE_FRAMEID"][2:], 16) + for wordidx in tiledata["cfgcol"]["WORDS"]: + if base_frame not in bits: + continue + if wordidx not in bits[base_frame]: + continue + for bit_frame, bit_wordidx, bit_bitidx in bits[base_frame][wordidx]: + segments[segname]["bits"].append("%02x_%02x_%02x" % (bit_frame - base_frame, bit_wordidx - min(tiledata["cfgcol"]["WORDS"]), bit_bitidx)) + + segments[segname]["bits"].sort() + + +################################################# +# Print + +print("Write segment data.") + +with open("segdata_%s.txt" % sys.argv[1], "w") as f: + for segname, segdata in sorted(segments.items()): + print("seg %s" % segname, file=f) + for bitname in sorted(segdata["bits"]): + print("bit %s" % bitname, file=f) + for tagname, tagval in sorted(segdata["tags"].items()): + print("tag %s %d" % (tagname, tagval), file=f) + diff --git a/fuzzers/010-lutinit/generate.sh b/fuzzers/010-lutinit/generate.sh new file mode 100644 index 00000000..e90af8ab --- /dev/null +++ b/fuzzers/010-lutinit/generate.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -ex +source ../../settings.sh + +test $# = 1 +test ! -e $1 +mkdir $1 +cd $1 + +echo '`define SEED 32'"'h$(echo $1 | md5sum | cut -c1-8)" > setseed.vh + +vivado -mode batch -source ../generate.tcl + +for i in 0 1 2; do + ../../../tools/bitread -F $XRAY_ROI_FRAMES -o design_$i.bits -zy < design_$i.bit + python3 ../generate.py $i +done + diff --git a/fuzzers/010-lutinit/generate.tcl b/fuzzers/010-lutinit/generate.tcl new file mode 100644 index 00000000..26dd7544 --- /dev/null +++ b/fuzzers/010-lutinit/generate.tcl @@ -0,0 +1,89 @@ +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] + +set_property LOCK_PINS {I0:A1 I1:A2 I2:A3 I3:A4 I4:A5 I5:A6} \ + [get_cells -quiet -filter {REF_NAME == LUT6} -hierarchical] + +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_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] + +place_design +route_design + +write_checkpoint -force design.dcp + + +######################################## +# Unmodified design with random LUTs + +proc write_lutdata {filename} { + puts "Writing $filename." + set fp [open $filename w] + foreach cell [get_cells -hierarchical -filter {REF_NAME == LUT6}] { + set bel [get_property BEL $cell] + set loc [get_property LOC $cell] + set init [get_property INIT $cell] + puts $fp "$loc $bel $init" + } + close $fp +} + +write_bitstream -force design_0.bit +write_lutdata lutdata_0.txt + + +######################################## +# XOR LUT INITs + +set pattern_list { + 0x1234567812345678 + 0xFFFFFFFF00000000 + 0xFFFF0000FFFF0000 + 0xFF00FF00FF00FF00 + 0xF0F0F0F0F0F0F0F0 + 0xCCCCCCCCCCCCCCCC + 0xAAAAAAAAAAAAAAAA +} + +set pattern_index 0 + +foreach cell [get_cells -hierarchical -filter {REF_NAME == LUT6}] { + set v [get_property init $cell] + set v [scan [string range $v 4 100] %x] + set v [expr $v ^ [lindex $pattern_list $pattern_index]] + set v [format %x $v] + set_property init 64'h$v $cell + set pattern_index [expr ($pattern_index + 1) % 7] +} + +write_bitstream -force design_1.bit +write_lutdata lutdata_1.txt + + +######################################## +# Set LUT INITs + +set pattern_index 1 + +foreach cell [get_cells -hierarchical -filter {REF_NAME == LUT6}] { + set_property init 64'h[lindex $pattern_list $pattern_index] $cell + set pattern_index [expr ($pattern_index + 1) % 7] +} + +write_bitstream -force design_2.bit +write_lutdata lutdata_2.txt + diff --git a/fuzzers/010-lutinit/top.v b/fuzzers/010-lutinit/top.v new file mode 100644 index 00000000..b0619b4a --- /dev/null +++ b/fuzzers/010-lutinit/top.v @@ -0,0 +1,92 @@ +`include "setseed.vh" + +module top(input clk, stb, di, output do); + localparam integer DIN_N = 10; + localparam integer DOUT_N = 10; + + 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 [9:0] din, output [9:0] dout); + localparam integer N = 200; + + function [31:0] xorshift32(input [31:0] v); + begin + xorshift32 = v; + xorshift32 = xorshift32 ^ (xorshift32 << 13); + xorshift32 = xorshift32 ^ (xorshift32 >> 17); + xorshift32 = xorshift32 ^ (xorshift32 << 5); + end + endfunction + + function [31:0] hash32(input [31:0] v); + begin + hash32 = v ^ `SEED; + hash32 = xorshift32(hash32); + hash32 = xorshift32(hash32); + hash32 = xorshift32(hash32); + hash32 = xorshift32(hash32); + end + endfunction + + function [63:0] hash64(input [31:0] v); + begin + hash64[63:32] = hash32(v); + hash64[31: 0] = hash32(~v); + end + endfunction + + wire [N*10+9:0] nets; + + assign nets[9:0] = din; + assign dout = nets[N*10+9:N*10]; + + genvar i, j; + generate + for (i = 0; i < N; i = i+1) begin:is + for (j = 0; j < 10; j = j+1) begin:js + localparam integer k = i*10 + j + 10; + wire lut_out; + + LUT6 #( + .INIT(hash64({i, j, 8'hff})) + ) lut ( + .I0(nets[hash32({i, j, 8'h00}) % k]), + .I1(nets[hash32({i, j, 8'h01}) % k]), + .I2(nets[k-10]), + .I3(nets[k-9]), + .I4(nets[k-8]), + .I5(nets[k-7]), + .O(lut_out) + ); + + reg lut_out_reg; + always @(posedge clk) + lut_out_reg <= lut_out; + + assign nets[k] = ((i+j) % 17) < 10 ? lut_out_reg : lut_out; + end + end + endgenerate +endmodule diff --git a/tools/segmatch.cc b/tools/segmatch.cc index 83973b13..b798bb8d 100644 --- a/tools/segmatch.cc +++ b/tools/segmatch.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -26,18 +27,18 @@ static inline vector &segdata_bits(segdata_t &sd) { return std::get<0>(sd) static inline vector &segdata_tags1(segdata_t &sd) { return std::get<1>(sd); } static inline vector &segdata_tags0(segdata_t &sd) { return std::get<2>(sd); } -void read_input() +void read_input(std::istream &f, std::string filename) { string token; segdata_t *segptr = nullptr; - while (std::cin >> token) + while (f >> token) { if (token == "seg") { - std::cin >> token; - while (segdata.count(token)) - token += "_"; + f >> token; + token = filename + ":" + token; + assert(segdata.count(token) == 0); segptr = &segdata[token]; continue; } @@ -46,7 +47,7 @@ void read_input() { assert(segptr != nullptr); - std::cin >> token; + f >> token; if (bit_ids.count(token) == 0) { bit_ids[token] = num_bits++; bit_ids_r.push_back(token); @@ -66,7 +67,7 @@ void read_input() { assert(segptr != nullptr); - std::cin >> token; + f >> token; if (tag_ids.count(token) == 0) { tag_ids[token] = num_tags++; tag_ids_r.push_back(token); @@ -74,7 +75,7 @@ void read_input() int tag_idx = tag_ids.at(token); - std::cin >> token; + f >> token; assert(token == "0" || token == "1"); auto &tags = token == "1" ? segdata_tags1(*segptr) : segdata_tags0(*segptr); @@ -116,53 +117,57 @@ void andc_masks(vector &dst_mask, const vector &src_mask) int main(int argc, char **argv) { + const char *outfile = nullptr; + int opt; - while ((opt = getopt(argc, argv, "")) != -1) + while ((opt = getopt(argc, argv, "o:")) != -1) switch (opt) { - // case 'c': - // mode_c = true; - // break; - // case 'r': - // mode_r = true; - // break; - // case 'm': - // mode_m = true; - // break; - // case 'x': - // mode_x = true; - // break; - // case 'y': - // mode_y = true; - // break; - // case 'z': - // mode_z = true; - // break; - // case 'C': - // chksum = true; - // break; - // case 'f': - // frames.insert(strtol(optarg, nullptr, 0)); - // break; - // case 'o': - // outfile = optarg; - // break; + case 'o': + outfile = optarg; + break; default: goto help; } - if (optind != argc) { + if (0) { help: fprintf(stderr, "\n"); - fprintf(stderr, "Usage: %s [options] < segdata.txt\n", argv[0]); + fprintf(stderr, "Usage: %s [options] file..\n", argv[0]); fprintf(stderr, "\n"); - // fprintf(stderr, " -c\n"); - // fprintf(stderr, " continuation mode. output '*' for repeating patterns\n"); + fprintf(stderr, " -o \n"); + fprintf(stderr, " set output file\n"); fprintf(stderr, "\n"); return 1; } - read_input(); + if (optind != argc) { + while (optind != argc) { + printf("Reading %s.\n", argv[optind]); + std::ifstream f; + f.open(argv[optind]); + assert(!f.fail()); + read_input(f, argv[optind++]); + } + } else { + printf("Reading from stding.\n"); + read_input(std::cin, "stdin"); + } + + printf("#of segments: %d\n", int(segdata.size())); + printf("#of bits: %d\n", num_bits); + printf("#of tags: %d\n", num_tags); + + FILE *f = stdout; + + if (outfile) { + f = fopen(outfile, "w"); + assert(f != nullptr); + } + + int min_candidates = num_bits; + int max_candidates = 0; + float avg_candidates = 0; for (int tag_idx = 0; tag_idx < num_tags; tag_idx++) { @@ -184,19 +189,26 @@ help: } int num_candidates = std::accumulate(mask.begin(), mask.end(), 0); + min_candidates = std::min(min_candidates, num_candidates); + max_candidates = std::max(max_candidates, num_candidates); + avg_candidates += float(num_candidates) / num_tags; - printf("%s", tag_ids_r.at(tag_idx).c_str()); + fprintf(f, "%s", tag_ids_r.at(tag_idx).c_str()); if (0 < num_candidates && num_candidates <= 4) { for (int bit_idx = 0; bit_idx < num_bits; bit_idx++) if (mask.at(bit_idx)) - printf(" %s", bit_ids_r.at(bit_idx).c_str()); - printf("\n"); + fprintf(f, " %s", bit_ids_r.at(bit_idx).c_str()); + fprintf(f, "\n"); } else { - printf(" <%d candidates>\n", num_candidates); + fprintf(f, " <%d candidates>\n", num_candidates); } } + printf("min #of candidates: %d\n", min_candidates); + printf("max #of candidates: %d\n", max_candidates); + printf("avg #of candidates: %f\n", avg_candidates); + return 0; }