From 6d24fdbaffb701a128a3c4b9916e268af09f5028 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 23 Oct 2018 17:26:26 -0700 Subject: [PATCH] bram-config: baseline workflow Signed-off-by: John McMaster --- fuzzers/101-bram-config/.gitignore | 2 + fuzzers/101-bram-config/Makefile | 20 ++ fuzzers/101-bram-config/README.md | 2 + fuzzers/101-bram-config/generate.py | 34 ++++ fuzzers/101-bram-config/generate.sh | 16 ++ fuzzers/101-bram-config/generate.tcl | 26 +++ fuzzers/101-bram-config/top.py | 266 +++++++++++++++++++++++++++ prjxray/segmaker.py | 13 +- prjxray/verilog.py | 20 +- utils/genheader.sh | 1 + 10 files changed, 398 insertions(+), 2 deletions(-) create mode 100644 fuzzers/101-bram-config/.gitignore create mode 100644 fuzzers/101-bram-config/Makefile create mode 100644 fuzzers/101-bram-config/README.md create mode 100644 fuzzers/101-bram-config/generate.py create mode 100644 fuzzers/101-bram-config/generate.sh create mode 100644 fuzzers/101-bram-config/generate.tcl create mode 100644 fuzzers/101-bram-config/top.py diff --git a/fuzzers/101-bram-config/.gitignore b/fuzzers/101-bram-config/.gitignore new file mode 100644 index 00000000..932efba0 --- /dev/null +++ b/fuzzers/101-bram-config/.gitignore @@ -0,0 +1,2 @@ +/specimen_[0-9][0-9][0-9]/ +/seg_clbl[lm].segbits diff --git a/fuzzers/101-bram-config/Makefile b/fuzzers/101-bram-config/Makefile new file mode 100644 index 00000000..8f20b8bb --- /dev/null +++ b/fuzzers/101-bram-config/Makefile @@ -0,0 +1,20 @@ +N := 1 +SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N))) +SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) + +database: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} -o seg_bramx.block_ram.segbits $(addsuffix /segdata_bram_[lr].txt,$(SPECIMENS)) + +pushdb: + ${XRAY_MERGEDB} bram_l.block_ram seg_bramx.block_ram.segbits + ${XRAY_MERGEDB} bram_r.block_ram seg_bramx.block_ram.segbits + +$(SPECIMENS_OK): + bash generate.sh $(subst /OK,,$@) + touch $@ + +clean: + rm -rf specimen_[0-9][0-9][0-9]/ seg_*.segbits vivado*.log vivado_*.str vivado*.jou design *.bits *.dcp *.bit top.v + +.PHONY: database pushdb clean + diff --git a/fuzzers/101-bram-config/README.md b/fuzzers/101-bram-config/README.md new file mode 100644 index 00000000..da689dd5 --- /dev/null +++ b/fuzzers/101-bram-config/README.md @@ -0,0 +1,2 @@ +Solves for BRAM configuration bits (18K vs 36K, etc) + diff --git a/fuzzers/101-bram-config/generate.py b/fuzzers/101-bram-config/generate.py new file mode 100644 index 00000000..33e748bd --- /dev/null +++ b/fuzzers/101-bram-config/generate.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 + +import json + +from prjxray.segmaker import Segmaker +from prjxray import verilog + +segmk = Segmaker("design.bits", verbose=True) + +print("Loading tags") +f = open('params.jl', 'r') +f.readline() +for l in f: + j = json.loads(l) + ps = j['params'] + assert j['module'] == 'my_RAMB36E1' + site = verilog.unquote(ps['LOC']) + + ks = [ + 'IS_CLKARDCLK_INVERTED', + 'IS_CLKBWRCLK_INVERTED', + 'IS_ENARDEN_INVERTED', + 'IS_ENBWREN_INVERTED', + 'IS_RSTRAMARSTRAM_INVERTED', + 'IS_RSTRAMB_INVERTED', + 'IS_RSTREGARSTREG_INVERTED', + 'IS_RSTREGB_INVERTED', + ] + + for k in ks: + segmk.add_site_tag(site, k, verilog.parsei(ps[k])) + +segmk.compile() +segmk.write() diff --git a/fuzzers/101-bram-config/generate.sh b/fuzzers/101-bram-config/generate.sh new file mode 100644 index 00000000..955c41b6 --- /dev/null +++ b/fuzzers/101-bram-config/generate.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -ex + +source ${XRAY_GENHEADER} + +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/101-bram-config/generate.tcl b/fuzzers/101-bram-config/generate.tcl new file mode 100644 index 00000000..86162f92 --- /dev/null +++ b/fuzzers/101-bram-config/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/101-bram-config/top.py b/fuzzers/101-bram-config/top.py new file mode 100644 index 00000000..c781cf06 --- /dev/null +++ b/fuzzers/101-bram-config/top.py @@ -0,0 +1,266 @@ +import os +import random +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray import verilog +import sys +import json + + +def gen_bram18(): + # yield "RAMB18_X%dY%d" % (x, y) + for _tile_name, site_name, _site_type in util.get_roi().gen_sites( + ['RAMB18E1']): + yield site_name + + +def gen_bram36(): + #yield "RAMB36_X%dY%d" % (x, y) + for _tile_name, site_name, _site_type in util.get_roi().gen_sites( + ['RAMBFIFO36E1']): + yield site_name + + +def gen_brams(): + ''' + Correctly assign a site to either bram36 or 2x bram18 + ''' + #for _tile_name, site_name, _site_type in util.get_roi().gen_tiles(): + for site in gen_bram36(): + yield ('RAMBFIFO36E1', site) + + +brams = list(gen_brams()) +DUTN = len(brams) +DIN_N = DUTN * 8 +DOUT_N = DUTN * 8 + +verilog.top_harness(DIN_N, DOUT_N) + +f = open('params.jl', 'w') +f.write('module,loc,params\n') +print( + 'module roi(input clk, input [%d:0] din, output [%d:0] dout);' % + (DIN_N - 1, DOUT_N - 1)) + + +def vrandbit(): + if random.randint(0, 1): + return "1'b1" + else: + return "1'b0" + + +for loci, (site_type, site) in enumerate(brams): + + def place_bram18(): + assert 0, 'FIXME' + + def place_bram36(): + ports = { + 'clk': 'clk', + 'din': 'din[ %d +: 8]' % (8 * loci, ), + 'dout': 'dout[ %d +: 8]' % (8 * loci, ), + } + params = { + 'LOC': verilog.quote(site), + 'IS_CLKARDCLK_INVERTED': vrandbit(), + 'IS_CLKBWRCLK_INVERTED': vrandbit(), + 'IS_ENARDEN_INVERTED': vrandbit(), + 'IS_ENBWREN_INVERTED': vrandbit(), + 'IS_RSTRAMARSTRAM_INVERTED': vrandbit(), + 'IS_RSTRAMB_INVERTED': vrandbit(), + 'IS_RSTREGARSTREG_INVERTED': vrandbit(), + 'IS_RSTREGB_INVERTED': vrandbit(), + 'RAM_MODE': '"TDP"', + 'WRITE_MODE_A': '"WRITE_FIRST"', + 'WRITE_MODE_B': '"WRITE_FIRST"', + } + return ('my_RAMB36E1', ports, params) + + modname, ports, params = { + 'RAMB18E1': place_bram18, + 'RAMBFIFO36E1': place_bram36, + }[site_type]() + + verilog.instance(modname, 'inst_%u' % loci, ports, params=params) + + j = {'module': modname, 'i': loci, 'params': params} + f.write('%s\n' % (json.dumps(j))) + print('') +''' + + + +def randbits(n): + return ''.join([random.choice(('0', '1')) for _x in range(n)]) + + +loci = 0 + + +def make(module, gen_locs, pdatan, datan): + global loci + + for loci, loc in enumerate(gen_locs()): + if loci >= DUTN: + break + + pdata = randbits(pdatan * 0x100) + data = randbits(datan * 0x100) + + print(' %s #(' % module) + for i in range(pdatan): + print( + " .INITP_%02X(256'b%s)," % + (i, pdata[i * 256:(i + 1) * 256])) + for i in range(datan): + print( + " .INIT_%02X(256'b%s)," % + (i, data[i * 256:(i + 1) * 256])) + print(' .LOC("%s"))' % (loc, )) + print( + ' inst_%d (.clk(clk), .din(din[ %d +: 8]), .dout(dout[ %d +: 8]));' + % (loci, 8 * loci, 8 * loci)) + + f.write('%s,%s,%s,%s\n' % (module, loc, pdata, data)) + print('') + loci += 1 + assert loci == DUTN + + +#make('my_RAMB18E1', gen_bram18, 0x08, 0x40) +make('my_RAMB36E1', gen_bram36, 0x10, 0x80) +''' + +f.close() +print( + '''endmodule + +// --------------------------------------------------------------------- + +''') + +# RAMB18E1 +print( + ''' +module my_RAMB18E1 (input clk, input [7:0] din, output [7:0] dout); + parameter LOC = ""; + ''') +print('''\ + (* LOC=LOC *) + RAMB18E1 #(''') +for i in range(8): + print(" .INITP_%02X(256'b0)," % (i, )) +print('') +for i in range(0x40): + print(" .INIT_%02X(256'b0)," % (i, )) +print('') +print( + ''' + .IS_CLKARDCLK_INVERTED(1'b0), + .IS_CLKBWRCLK_INVERTED(1'b0), + .IS_ENARDEN_INVERTED(1'b0), + .IS_ENBWREN_INVERTED(1'b0), + .IS_RSTRAMARSTRAM_INVERTED(1'b0), + .IS_RSTRAMB_INVERTED(1'b0), + .IS_RSTREGARSTREG_INVERTED(1'b0), + .IS_RSTREGB_INVERTED(1'b0), + .RAM_MODE("TDP"), + .WRITE_MODE_A("WRITE_FIRST"), + .WRITE_MODE_B("WRITE_FIRST"), + .SIM_DEVICE("VIRTEX6") + ) 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(dout[1]), + .DOPADOP(dout[2]), + .DOPBDOP(dout[3])); +endmodule +''') + +print( + ''' + +module my_RAMB36E1 (input clk, input [7:0] din, output [7:0] dout); + parameter LOC = ""; + + parameter IS_CLKARDCLK_INVERTED = 1'b0; + parameter IS_CLKBWRCLK_INVERTED = 1'b0; + parameter IS_ENARDEN_INVERTED = 1'b0; + parameter IS_ENBWREN_INVERTED = 1'b0; + parameter IS_RSTRAMARSTRAM_INVERTED = 1'b0; + parameter IS_RSTRAMB_INVERTED = 1'b0; + parameter IS_RSTREGARSTREG_INVERTED = 1'b0; + parameter IS_RSTREGB_INVERTED = 1'b0; + parameter RAM_MODE = "TDP"; + parameter WRITE_MODE_A = "WRITE_FIRST"; + parameter WRITE_MODE_B = "WRITE_FIRST"; + + ''') +print('') +print('''\ + (* LOC=LOC *) + RAMB36E1 #(''') +for i in range(16): + print(" .INITP_%02X(256'b0)," % (i, )) +print('') +for i in range(0x80): + print(" .INIT_%02X(256'b0)," % (i, )) +print('') +print( + ''' + .IS_CLKARDCLK_INVERTED(1'b0), + .IS_CLKBWRCLK_INVERTED(1'b0), + .IS_ENARDEN_INVERTED(1'b0), + .IS_ENBWREN_INVERTED(1'b0), + .IS_RSTRAMARSTRAM_INVERTED(1'b0), + .IS_RSTRAMB_INVERTED(1'b0), + .IS_RSTREGARSTREG_INVERTED(1'b0), + .IS_RSTREGB_INVERTED(1'b0), + .RAM_MODE("TDP"), + .WRITE_MODE_A("WRITE_FIRST"), + .WRITE_MODE_B("WRITE_FIRST"), + .SIM_DEVICE("VIRTEX6") + ) 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(dout[1]), + .DOPADOP(dout[2]), + .DOPBDOP(dout[3])); +endmodule +''') diff --git a/prjxray/segmaker.py b/prjxray/segmaker.py index 2bb30873..2aaa82b5 100644 --- a/prjxray/segmaker.py +++ b/prjxray/segmaker.py @@ -122,6 +122,8 @@ class Segmaker: self.addtag('SLICE_X13Y101', 'CLB.SLICE_X0.AFF.DMUX.CY', 1) Indicates that the SLICE_X13Y101 site has an element called 'CLB.SLICE_X0.AFF.DMUX.CY' ''' + if '"' in site: + raise ValueError("Invalid site: %s" % site) self.site_tags.setdefault(site, dict())[name] = value def add_tile_tag(self, tile, name, value): @@ -130,6 +132,7 @@ class Segmaker: def compile(self, bitfilter=None): print("Compiling segment data.") tags_used = set() + sites_used = set() tile_types_found = set() self.segments_by_type = dict() @@ -241,6 +244,7 @@ class Segmaker: tag = tag.replace(".SLICEM.", ".") tag = tag.replace(".SLICEL.", ".") segments[segname]["tags"][tag] = value + sites_used.add(site) tile_type = tiledata["type"] tile_types_found.add(tile_type) @@ -279,8 +283,15 @@ class Segmaker: add_site_tags() if self.verbose: - ntags = recurse_sum(self.site_tags) + recurse_sum(self.tile_tags) + n_site_tags = recurse_sum(self.site_tags) + n_tile_tags = recurse_sum(self.tile_tags) + ntags = n_site_tags + n_tile_tags print("Used %u / %u tags" % (len(tags_used), ntags)) + print("Tag sites: %u" % (n_site_tags,)) + if n_site_tags: + print(' Ex: %s' % list(self.site_tags.keys())[0]) + print("Tag tiles: %u" % (n_tile_tags,)) + print("Used %u sites" % len(sites_used)) print("Grid DB had %u tile types" % len(tile_types_found)) assert ntags and ntags == len(tags_used) diff --git a/prjxray/verilog.py b/prjxray/verilog.py index a6175647..99a6dde7 100644 --- a/prjxray/verilog.py +++ b/prjxray/verilog.py @@ -48,4 +48,22 @@ def instance(mod, name, ports, params={}, sort=True): for i, (portk, portv) in enumerate(tosort(ports.items())): comma = '' if i == len(ports) - 1 else ',' print(' .%s(%s)%s' % (portk, portv, comma)) - print(' ));') + print(' );') + + +def quote(s): + return '"' + s + '"' + + +def unquote(s): + assert s[0] == '"' and s[-1] == '"' + return s[1:-1] + + +def parsei(s): + if s == "1'b0": + return 0 + elif s == "1'b1": + return 1 + else: + assert 0, 'FIXME' diff --git a/utils/genheader.sh b/utils/genheader.sh index b7850957..edf0cbb5 100644 --- a/utils/genheader.sh +++ b/utils/genheader.sh @@ -12,6 +12,7 @@ test $# = 1 || exit 1 test ! -e "$SPECN" SPECN=$1 +rm -rf "$SPECN" mkdir "$SPECN" cd "$SPECN"