diff --git a/fuzzers/019_ndi1mux/.gitignore b/fuzzers/019_ndi1mux/.gitignore new file mode 100644 index 00000000..93b5bef8 --- /dev/null +++ b/fuzzers/019_ndi1mux/.gitignore @@ -0,0 +1,4 @@ +/specimen_*/ +/*.segbits +/vivado.log +/vivado.jou diff --git a/fuzzers/019_ndi1mux/Makefile b/fuzzers/019_ndi1mux/Makefile new file mode 100644 index 00000000..cdd3cf23 --- /dev/null +++ b/fuzzers/019_ndi1mux/Makefile @@ -0,0 +1,22 @@ +N := 1 +SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N))) +SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) + +database: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} -o seg_clblx.segbits $(addsuffix /segdata_clbl[lm]_[lr].txt,$(SPECIMENS)) + +pushdb: + ${XRAY_MERGEDB} clbll_l seg_clblx.segbits + ${XRAY_MERGEDB} clbll_r seg_clblx.segbits + ${XRAY_MERGEDB} clblm_l seg_clblx.segbits + ${XRAY_MERGEDB} clblm_r seg_clblx.segbits + +$(SPECIMENS_OK): + bash generate.sh $(subst /OK,,$@) + touch $@ + +clean: + rm -rf specimen_[0-9][0-9][0-9]/ seg_clblx.segbits vivado*.log vivado_*.str vivado*.jou design *.bits *.dcp *.bit top.v + +.PHONY: database pushdb clean + diff --git a/fuzzers/019_ndi1mux/README.txt b/fuzzers/019_ndi1mux/README.txt new file mode 100644 index 00000000..258c746b --- /dev/null +++ b/fuzzers/019_ndi1mux/README.txt @@ -0,0 +1,2 @@ +See minitest for DI notes + diff --git a/fuzzers/019_ndi1mux/generate.py b/fuzzers/019_ndi1mux/generate.py new file mode 100644 index 00000000..c0cf1a7f --- /dev/null +++ b/fuzzers/019_ndi1mux/generate.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +# FIXME: getting two bits +# 00_40 31_46 +# Can we find instance where they are not aliased? +WA7USED = 0 + +import sys, re, os + +sys.path.append("../../../utils/") +from segmaker import segmaker + +segmk = segmaker("design.bits") + +print("Loading tags") +''' +module,loc,c31,b31,a31 +my_NDI1MUX_NI_NMC31,SLICE_X12Y100,1,1,0 +my_NDI1MUX_NI_NMC31,SLICE_X12Y101,1,1,1 +my_NDI1MUX_NI_NMC31,SLICE_X12Y102,1,1,1 +''' +f = open('params.csv', 'r') +f.readline() +for l in f: + l = l.strip() + module,loc,c31,b31,a31 = l.split(',') + c31 = int(c31) + b31 = int(b31) + a31 = int(a31) + segmk.addtag(loc, "ADI1MUX.AI", 1 ^ a31) + segmk.addtag(loc, "BDI1MUX.BI", 1 ^ b31) + segmk.addtag(loc, "CDI1MUX.CI", 1 ^ c31) + +segmk.compile() +segmk.write() + diff --git a/fuzzers/019_ndi1mux/generate.sh b/fuzzers/019_ndi1mux/generate.sh new file mode 100644 index 00000000..54774bf8 --- /dev/null +++ b/fuzzers/019_ndi1mux/generate.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -ex + +source ${XRAY_GENHEADER} + +#echo '`define SEED 32'"'h$(echo $1 | md5sum | cut -c1-8)" > setseed.vh + +python3 ../top.py >top.v +vivado -mode batch -source ../generate.tcl +test -z "$(fgrep CRITICAL vivado.log)" + +for x in design*.bit; do + ${XRAY_BITREAD} -F $XRAY_ROI_FRAMES -o ${x}s -z -y $x +done + +python3 ../generate.py + diff --git a/fuzzers/019_ndi1mux/generate.tcl b/fuzzers/019_ndi1mux/generate.tcl new file mode 100644 index 00000000..86162f92 --- /dev/null +++ b/fuzzers/019_ndi1mux/generate.tcl @@ -0,0 +1,26 @@ +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 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] + +create_pblock roi +set_property EXCLUDE_PLACEMENT 1 [get_pblocks 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 +write_bitstream -force design.bit + diff --git a/fuzzers/019_ndi1mux/top.py b/fuzzers/019_ndi1mux/top.py new file mode 100644 index 00000000..ea137279 --- /dev/null +++ b/fuzzers/019_ndi1mux/top.py @@ -0,0 +1,162 @@ +import random +random.seed(0) +import os +import re + +def slice_xy(): + '''Return (X1, X2), (Y1, Y2) from XRAY_ROI, exclusive end (for xrange)''' + # SLICE_X12Y100:SLICE_X27Y149 + # Note XRAY_ROI_GRID_* is something else + m = re.match(r'SLICE_X(.*)Y(.*):SLICE_X(.*)Y(.*)', os.getenv('XRAY_ROI')) + ms = [int(m.group(i + 1)) for i in range(4)] + return ((ms[0], ms[2] + 1), (ms[1], ms[3] + 1)) + +CLBN = 50 +SLICEX, SLICEY = slice_xy() +# 800 +SLICEN = (SLICEY[1] - SLICEY[0]) * (SLICEX[1] - SLICEX[0]) +print('//SLICEX: %s' % str(SLICEX)) +print('//SLICEY: %s' % str(SLICEY)) +print('//SLICEN: %s' % str(SLICEN)) +print('//Requested CLBs: %s' % str(CLBN)) + +# Rearranged to sweep Y so that carry logic is easy to allocate +# XXX: careful...if odd number of Y in ROI will break carry +def gen_slicems(): + ''' + SLICEM at the following: + SLICE_XxY* + Where Y any value + x + Always even (ie 100, 102, 104, etc) + In our ROI + x = 6, 8, 10, 12, 14 + ''' + # TODO: generate this from DB + assert((12, 28) == SLICEX) + for slicex in (12, 14): + for slicey in range(*SLICEY): + # caller may reject position if needs more room + #yield ("SLICE_X%dY%d" % (slicex, slicey), (slicex, slicey)) + yield "SLICE_X%dY%d" % (slicex, slicey) + + +DIN_N = CLBN * 8 +DOUT_N = CLBN * 8 + +print(''' +module top(input clk, stb, di, output do); + localparam integer DIN_N = %d; + localparam integer DOUT_N = %d; + + 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 +''' % (DIN_N, DOUT_N)) + +f = open('params.csv', 'w') +f.write('module,loc,c31,b31,a31\n') +slices = gen_slicems() +print('module roi(input clk, input [%d:0] din, output [%d:0] dout);' % (DIN_N - 1, DOUT_N - 1)) +multis = 0 +for clbi in range(CLBN): + loc = next(slices) + module = 'my_NDI1MUX_NI_NMC31' + c31 = random.randint(0, 1) + b31 = random.randint(0, 1) + a31 = random.randint(0, 1) + + print(' %s' % module) + print(' #(.LOC("%s"), .C31(%d), .B31(%d), .A31(%d))' % (loc, c31, b31, a31)) + print(' clb_%d (.clk(clk), .din(din[ %d +: 8]), .dout(dout[ %d +: 8]));' % (clbi, 8 * clbi, 8 * clbi)) + + f.write('%s,%s,%d,%d,%d\n' % (module, loc, c31, b31, a31)) +f.close() +print('''endmodule + +// --------------------------------------------------------------------- + +''') + +print(''' +module my_NDI1MUX_NI_NMC31 (input clk, input [7:0] din, output [7:0] dout); + parameter LOC = "SLICE_X6Y100"; + parameter C31 = 0; + parameter B31 = 0; + parameter A31 = 0; + + wire [3:0] q31; + + wire [3:0] lutd; + assign lutd[3] = din[7]; + assign lutd[2] = C31 ? q31[3] : din[7]; + assign lutd[1] = B31 ? q31[2] : din[7]; + assign lutd[0] = A31 ? q31[1] : din[7]; + + (* LOC=LOC, BEL="D6LUT" *) + SRLC32E #( + .INIT(32'h00000000), + .IS_CLK_INVERTED(1'b0) + ) lutd ( + .Q(dout[0]), + .Q31(q31[3]), + .A(din[4:0]), + .CE(din[5]), + .CLK(din[6]), + .D(lutd[3])); + (* LOC=LOC, BEL="C6LUT" *) + SRLC32E #( + .INIT(32'h00000000), + .IS_CLK_INVERTED(1'b0) + ) lutc ( + .Q(dout[1]), + .Q31(q31[2]), + .A(din[4:0]), + .CE(din[5]), + .CLK(din[6]), + .D(lutd[2])); + (* LOC=LOC, BEL="B6LUT" *) + SRLC32E #( + .INIT(32'h00000000), + .IS_CLK_INVERTED(1'b0) + ) lutb ( + .Q(dout[2]), + .Q31(q31[1]), + .A(din[4:0]), + .CE(din[5]), + .CLK(din[6]), + .D(lutd[1])); + (* LOC=LOC, BEL="A6LUT" *) + SRLC32E #( + .INIT(32'h00000000), + .IS_CLK_INVERTED(1'b0) + ) luta ( + .Q(dout[3]), + .Q31(q31[0]), + .A(din[4:0]), + .CE(din[5]), + .CLK(din[6]), + .D(lutd[0])); +endmodule +''') +