Merge branch 'master' into ps7

This commit is contained in:
Alessandro Comodi 2019-01-09 18:52:28 +01:00
commit 3ec9dd58af
19 changed files with 642 additions and 74 deletions

View File

@ -4,8 +4,8 @@ FROM ${DEV_ENV_IMAGE} AS db_builder
ARG NUM_PARALLEL_JOBS=1 ARG NUM_PARALLEL_JOBS=1
COPY . /source COPY . /source
RUN cd /source && make -j${NUM_PARALLEL_JOBS} --output-sync=target --warn-undefined-variables build RUN cd /source && make -j${NUM_PARALLEL_JOBS} --output-sync=target --warn-undefined-variables build && make env
RUN bash -c ". /source/database/artix7/settings.sh; cd /source/fuzzers && make -j${NUM_PARALLEL_JOBS} --output-sync=target --warn-undefined-variables" RUN bash -c ". /source/database/artix7/settings.sh; cd /source/fuzzers && make --output-sync=target --warn-undefined-variables"
#RUN find /source/database -mindepth 1 -maxdepth 1 -type d -exec /source/htmlgen/htmlgen.py --settings={}/settings.sh --output=/output/html \; #RUN find /source/database -mindepth 1 -maxdepth 1 -type d -exec /source/htmlgen/htmlgen.py --settings={}/settings.sh --output=/output/html \;
RUN mkdir -p /output/raw && find /source/database -mindepth 1 -maxdepth 1 -type d -exec cp -R {} /output/raw \; RUN mkdir -p /output/raw && find /source/database -mindepth 1 -maxdepth 1 -type d -exec cp -R {} /output/raw \;

View File

@ -0,0 +1,20 @@
N := 1
include ../fuzzer.mk
SEGDATAS=$(addsuffix /segdata_liob33.txt,$(SPECIMENS))
database: build/segbits_liob33.db
build/segbits_liob33.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -c -1 -o build/segbits_liob33.rdb $(SEGDATAS)
build/segbits_liob33.db: build/segbits_liob33.rdb
python3 ${XRAY_DIR}/utils/groupmask.py $^ $@
${XRAY_MASKMERGE} build/mask_liob33.db $(SEGDATAS)
pushdb:
${XRAY_MERGEDB} liob33 build/segbits_liob33.db
${XRAY_MERGEDB} mask_liob33 build/mask_liob33.db
.PHONY: database pushdb

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
from prjxray.segmaker import Segmaker
from prjxray import segmaker
segmk = Segmaker("design.bits")
print("Loading params")
f = open('params.csv', 'r')
f.readline()
for l in f:
l = l.strip()
site, name, dir_, cell = l.split(',')
segmaker.add_site_group_zero(
segmk, site, "MACRO.", ("INPUT", "OUTPUT"), "", dir_.upper())
segmk.compile()
segmk.write()

View File

@ -0,0 +1,5 @@
#!/bin/bash
set -ex
source ${XRAY_DIR}/utils/top_generate.sh

View File

@ -0,0 +1,90 @@
source "$::env(XRAY_DIR)/utils/utils.tcl"
proc make_io_pin_sites {} {
# get all possible IOB pins
foreach pad [get_package_pins -filter "IS_GENERAL_PURPOSE == 1"] {
set site [get_sites -of_objects $pad]
if {[llength $site] == 0} {
continue
}
if [string match IOB33* [get_property SITE_TYPE $site]] {
dict append io_pin_sites $site $pad
}
}
return $io_pin_sites
}
proc load_pin_lines {} {
# IOB_X0Y103 clk input
# IOB_X0Y129 do[0] output
set fp [open "params.csv" r]
set pin_lines {}
for {gets $fp line} {$line != ""} {gets $fp line} {
lappend pin_lines [split $line ","]
}
close $fp
return $pin_lines
}
proc loc_pins {} {
set pin_lines [load_pin_lines]
set io_pin_sites [make_io_pin_sites]
set fp [open "design.csv" w]
puts $fp "port,site,tile,pin,val"
puts "Looping"
for {set idx 1} {$idx < [llength $pin_lines]} {incr idx} {
set line [lindex $pin_lines $idx]
puts "$line"
set site_str [lindex $line 0]
set pin_str [lindex $line 1]
set io [lindex $line 2]
set cell_str [lindex $line 3]
# Skip unused site
if {"$pin_str" == ""} {
continue
}
# Have: site
# Want: pin for site
set site [get_sites $site_str]
set pad_bel [get_bels -of_objects $site -filter {TYPE =~ PAD && NAME =~ IOB_*}]
set port [get_ports $pin_str]
set tile [get_tiles -of_objects $site]
set pin [dict get $io_pin_sites $site]
set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS33" $port
puts $fp "$port,$site,$tile,$pin"
}
close $fp
}
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
# Mostly doesn't matter since IOB are special, but add anyway
create_pblock roi
add_cells_to_pblock [get_pblocks roi] [get_cells roi]
resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)"
loc_pins
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
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
}
run

View File

@ -0,0 +1 @@
LIOB33.IOB_Y1.MACRO

152
fuzzers/034-iob-stag/top.py Normal file
View File

@ -0,0 +1,152 @@
'''
Generate a primitive to place at every I/O
Unlike CLB tests, the LFSR for this is inside the ROI, not driving it
'''
import os
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray import verilog
def gen_iobs():
'''
IOB33S: main IOB of a diff pair
IOB33M: secondary IOB of a diff pair
IOB33: not a diff pair. Relatively rare (at least in ROI...2 of them?)
Focus on IOB33S to start
'''
for _tile_name, site_name, site_type in util.get_roi().gen_sites(
#['IOB33', 'IOB33S', 'IOB33M']):
['IOB33S']):
yield site_name, site_type
def write_pins(ports):
pinstr = 'site,name,dir,cell\n'
for site, (name, dir_, cell) in sorted(ports.items(), key=lambda x: x[1]):
# pinstr += 'set_property -dict "PACKAGE_PIN %s IOSTANDARD LVCMOS33" [get_ports %s]' % (packpin, port)
pinstr += '%s,%s,%s,%s\n' % (site, name, dir_, cell)
open('params.csv', 'w').write(pinstr)
def run():
# All possible values
iosites = {}
for site_name, site_type in gen_iobs():
iosites[site_name] = site_type
# Assigned in this design
ports = {}
DIN_N = 0
DOUT_N = 0
def remain_sites():
return set(iosites.keys()) - set(ports.keys())
def rand_site():
'''Get a random, unused site'''
return random.choice(list(remain_sites()))
def assign_i(site, name):
nonlocal DIN_N
assert site not in ports
cell = "di_bufs[%u].ibuf" % DIN_N
DIN_N += 1
ports[site] = (name, 'input', cell)
def assign_o(site, name):
nonlocal DOUT_N
assert site not in ports
cell = "do_bufs[%u].obuf" % DOUT_N
DOUT_N += 1
ports[site] = (name, 'output', cell)
# Assign at least one di and one do
assign_i(rand_site(), 'di[0]')
assign_o(rand_site(), 'do[0]')
# Now assign the rest randomly
while len(remain_sites()):
site = rand_site()
choice = random.randint(0, 2)
if choice == 0:
assign_i(site, 'di[%u]' % DIN_N)
elif choice == 1:
assign_o(site, 'do[%u]' % DOUT_N)
# Empty to provide a reference for no instance
else:
ports[site] = ("", "", "")
write_pins(ports)
print(
'''
`define N_DI %u
`define N_DO %u
module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do);
genvar i;
//Instantiate BUFs so we can LOC them
wire [`N_DI-1:0] di_buf;
generate
for (i = 0; i < `N_DI; i = i+1) begin:di_bufs
IBUF ibuf(.I(di[i]), .O(di_buf[i]));
end
endgenerate
wire [`N_DO-1:0] do_unbuf;
generate
for (i = 0; i < `N_DO; i = i+1) begin:do_bufs
OBUF obuf(.I(do_unbuf[i]), .O(do[i]));
end
endgenerate
roi roi(.di(di_buf), .do(do_unbuf));
endmodule
//Arbitrary terminate into LUTs
module roi(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do);
genvar i;
generate
for (i = 0; i < `N_DI; i = i+1) begin:dis
(* KEEP, DONT_TOUCH *)
LUT6 #(
.INIT(64'h8000_0000_0000_0001)
) lut (
.I0(di[i]),
.I1(di[i]),
.I2(di[i]),
.I3(di[i]),
.I4(di[i]),
.I5(di[i]),
.O());
end
endgenerate
generate
for (i = 0; i < `N_DO; i = i+1) begin:dos
(* KEEP, DONT_TOUCH *)
LUT6 #(
.INIT(64'h8000_0000_0000_0001)
) lut (
.I0(),
.I1(),
.I2(),
.I3(),
.I4(),
.I5(),
.O(do[i]));
end
endgenerate
endmodule
''' % (DIN_N, DOUT_N))
if __name__ == '__main__':
run()

View File

@ -1,23 +1,23 @@
N := 1 N := 1
SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N))) SPECIMENS := $(addprefix build/specimen_,$(shell seq -f '%03.0f' $(N)))
SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS))
database: $(SPECIMENS_OK) database: $(SPECIMENS_OK)
cp specimen_001/ppips_clblm_l.txt . cp build/specimen_001/ppips_clblm_l.txt build/
cp specimen_001/ppips_clblm_r.txt . cp build/specimen_001/ppips_clblm_r.txt build/
cp specimen_001/ppips_clbll_l.txt . cp build/specimen_001/ppips_clbll_l.txt build/
cp specimen_001/ppips_clbll_r.txt . cp build/specimen_001/ppips_clbll_r.txt build/
cp specimen_001/ppips_int_l.txt . cp build/specimen_001/ppips_int_l.txt build/
cp specimen_001/ppips_int_r.txt . cp build/specimen_001/ppips_int_r.txt build/
pushdb: pushdb:
cp ppips_clblm_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clblm_l.db cp build/ppips_clblm_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clblm_l.db
cp ppips_clblm_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clblm_r.db cp build/ppips_clblm_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clblm_r.db
cp ppips_clbll_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clbll_l.db cp build/ppips_clbll_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clbll_l.db
cp ppips_clbll_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clbll_r.db cp build/ppips_clbll_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clbll_r.db
cp ppips_int_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_int_l.db cp build/ppips_int_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_int_l.db
cp ppips_int_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_int_r.db cp build/ppips_int_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_int_r.db
$(SPECIMENS_OK): $(SPECIMENS_OK):
bash generate.sh $(subst /OK,,$@) bash generate.sh $(subst /OK,,$@)
@ -30,7 +30,7 @@ run:
touch run.ok touch run.ok
clean: clean:
rm -rf specimen_[0-9][0-9][0-9]/ ppips_clbl[ml]_[lr].txt ppips_int_[lr].txt run.ok rm -rf build run.ok
.PHONY: database pushdb run clean .PHONY: database pushdb run clean

View File

@ -2,5 +2,5 @@
source ${XRAY_GENHEADER} source ${XRAY_GENHEADER}
${XRAY_VIVADO} -mode batch -source ../generate.tcl ${XRAY_VIVADO} -mode batch -source $FUZDIR/generate.tcl

View File

@ -1,6 +1,6 @@
create_project -force -part $::env(XRAY_PART) design design create_project -force -part $::env(XRAY_PART) design design
read_verilog ../top.v read_verilog $::env(FUZDIR)/top.v
synth_design -top top synth_design -top top
set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports a] set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports a]

View File

@ -425,10 +425,6 @@ def get_bit_info(dbstate, frameidx, bitidx, tiletype):
bit_pos = "%02d_%02d" % (frameidx, bitidx) bit_pos = "%02d_%02d" % (frameidx, bitidx)
bit_name = get_bit_name(dbstate, frameidx, bitidx, bit_pos, tiletype) bit_name = get_bit_name(dbstate, frameidx, bitidx, bit_pos, tiletype)
if tiletype in ["clbll_l", "clbll_r", "clblm_l", "clblm_r", "dsp_l",
"dsp_r", "bram_l", "bram_r"]:
if bit_name is not None:
return bit_pos, "INT", [bit_pos], "#88aaff"
label = None label = None
title = [bit_pos] title = [bit_pos]
@ -490,7 +486,7 @@ def get_bit_info(dbstate, frameidx, bitidx, tiletype):
else: else:
bgcolor = "#ff0000" bgcolor = "#ff0000"
m = re.search(r"\.([ABCD])DI1MUX\.", bit_name) m = re.search(r"\.([ABCD])LUT.DI1MUX\.", bit_name)
if m: if m:
bgcolor = "#ffffaa" bgcolor = "#ffffaa"
label = m.group(1) + "DI1" label = m.group(1) + "DI1"
@ -581,11 +577,11 @@ def get_bit_info(dbstate, frameidx, bitidx, tiletype):
bgcolor = "#4466bb" bgcolor = "#4466bb"
label = "LH" label = "LH"
if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]FF.DMUX", bit_name): if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]5?FFMUX", bit_name):
bgcolor = "#88aaff" bgcolor = "#88aaff"
label = "DMX" label = "DMX"
if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]MUX", bit_name): if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]OUTMUX", bit_name):
bgcolor = "#aa88ff" bgcolor = "#aa88ff"
label = "OMX" label = "OMX"

View File

@ -1,3 +1,7 @@
import json
import os
from prjxray import util
# Break frames into WORD_SIZE bit words. # Break frames into WORD_SIZE bit words.
WORD_SIZE_BITS = 32 WORD_SIZE_BITS = 32
@ -71,3 +75,40 @@ def load_bitdata2(f):
bitdata[frame][wordidx].add(bitidx) bitdata[frame][wordidx].add(bitidx)
return bitdata return bitdata
def gen_part_base_addrs():
"""
Return (block_type, top_bottom, cfg_row, cfg_col, frame_count)
Where:
-block_type ("bus"): typically CLB_IO_CLK, sometimes BLOCK_RAM
-top_bottom: either "top" or "bottom"
-cfg_row: a relative row
-cfg_col: a relative column
-frame_count: number of frames to fully configure this minor address
Example:
('CLB_IO_CLK', 'bottom', 0, 3, 36)
('BLOCK_RAM', 'top', 0, 1, 128)
('CLB_IO_CLK', 'top', 1, 34, 28)
"""
fn = os.getenv("XRAY_PART_YAML").replace(".yaml", ".json")
j = json.load(open(fn, "r"))
for tbk, tbv in j["global_clock_regions"].items():
for rowk, rowv in tbv["rows"].items():
for busk, busv in rowv["configuration_buses"].items():
for colk, colv in busv["configuration_columns"].items():
yield (
busk, tbk, int(rowk), int(colk), colv["frame_count"])
def addr_bits2word(block_type, top_bottom, cfg_row, cfg_col, minor_addr):
"""Convert a deconstructed address to a 32 bit word"""
# https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
ret = 0
ret |= util.block_type_s2i[block_type] << 23
ret |= {"top": 0, "bottom": 1}[top_bottom] << 22
ret |= cfg_row << 17
ret |= cfg_col << 7
ret |= minor_addr
return ret

View File

@ -53,8 +53,8 @@ def add_site_group_zero(segmk, site, prefix, vals, zero_val, val):
vals: all possible tag enum vals vals: all possible tag enum vals
zero_val: tag value known to have no bits set zero_val: tag value known to have no bits set
''' '''
assert zero_val in vals, "Got %s, need %s" % (zero_val, vals) # assert zero_val in vals, "Got %s, need %s" % (zero_val, vals)
assert val in vals, "Got %s, need %s" % (val, vals) assert val in vals or val == zero_val, "Got %s, need %s" % (val, vals)
if val == zero_val: if val == zero_val:
# Zero symbol occured, none of the others did # Zero symbol occured, none of the others did
@ -64,10 +64,11 @@ def add_site_group_zero(segmk, site, prefix, vals, zero_val, val):
else: else:
# Only add the occured symbol # Only add the occured symbol
tag = prefix + val tag = prefix + val
segmk.add_site_tag(site, tag, 1) segmk.add_site_tag(site, tag, True)
# And zero so that it has something to solve against if zero_val in vals:
tag = prefix + zero_val # And zero so that it has something to solve against
segmk.add_site_tag(site, tag, 0) tag = prefix + zero_val
segmk.add_site_tag(site, tag, False)
class Segmaker: class Segmaker:

View File

@ -103,6 +103,23 @@ def parse_db_line(line):
return tag, bits, None return tag, bits, None
def parse_db_lines(fn):
with open(fn, "r") as f:
for line in f:
yield line, parse_db_line(line)
def write_db_lines(fn, entries):
new_lines = []
for tag, bits in entries.items():
new_line = " ".join([tag] + sorted(bits))
new_lines.append(new_line)
with open(fn, "w") as f:
for line in sorted(new_lines):
print(line, file=f)
def parse_tagbit(x): def parse_tagbit(x):
# !30_07 # !30_07
if x[0] == '!': if x[0] == '!':
@ -137,6 +154,9 @@ block_type_i2s = {
# special...maybe should error until we know what it is? # special...maybe should error until we know what it is?
# 3: 'RESERVED', # 3: 'RESERVED',
} }
block_type_s2i = {}
for k, v in block_type_i2s.items():
block_type_s2i[v] = k
def addr2btype(base_addr): def addr2btype(base_addr):
@ -183,14 +203,12 @@ def gen_tile_bits(db_root, tilej, strict=False, verbose=False):
elif not os.path.exists(fn): elif not os.path.exists(fn):
continue continue
with open(fn, "r") as f: for line, (tag, bits, mode) in parse_db_lines(fn):
for line in f: assert mode is None
tag, bits, mode = parse_db_line(line) for bitstr in bits:
assert mode is None # 31_06
for bitstr in bits: _bit_inv, (bit_addroff, bit_bitoff) = parse_tagbit(bitstr)
# 31_06 yield (baseaddr + bit_addroff, bitbase + bit_bitoff, tag)
_bit_inv, (bit_addroff, bit_bitoff) = parse_tagbit(bitstr)
yield (baseaddr + bit_addroff, bitbase + bit_bitoff, tag)
def specn(): def specn():

30
utils/addrwidth.py Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
import json
from prjxray import bitstream
def gen_addrs():
for block_type, top_bottom, cfg_row, cfg_col, frame_count in bitstream.gen_part_base_addrs(
):
yield bitstream.addr_bits2word(
block_type, top_bottom, cfg_row, cfg_col, 0), frame_count
def run(verbose=False):
for addr, frame_count in sorted(gen_addrs()):
print("0x%08X: %u" % (addr, frame_count))
def main():
import argparse
parser = argparse.ArgumentParser(
description='Print number of frames at a base address')
args = parser.parse_args()
run(verbose=False)
if __name__ == '__main__':
main()

81
utils/groupmask.py Normal file
View File

@ -0,0 +1,81 @@
#/usr/bin/env python3
import sys, os, re
from prjxray import util
def index_masks(fn_in, groups_in):
"""Return a dictionary with the bits active in each group for the specified list of groups"""
# Only analyze the given groups
groups = {}
for group in groups_in:
groups[group] = set()
# Index bits
for line, (tag, bits, mode) in util.parse_db_lines(fn_in):
assert not mode, "Unresolved tag: %s" % (line, )
prefix = tag[0:tag.rfind(".")]
group = groups.get(prefix, None)
# Drop groups we aren't interested in
if group is None:
continue
for bit in bits:
bit = bit.replace("!", "")
group.add(bit)
# Verify we were able to find all groups
for groupk, groupv in groups.items():
assert len(groupv), "Bad group %s" % groupk
return groups
def apply_masks(fn_in, groups):
"""Add 0 entries ("!") to .db entries based on groups definition"""
new_db = {}
for line, (tag, bits, mode) in util.parse_db_lines(fn_in):
assert not mode, "Unresolved tag: %s" % (line, )
prefix = tag[0:tag.rfind(".")]
group = groups.get(prefix, None)
if group:
bits = set(bits)
for bit in group:
if bit not in bits:
bits.add("!" + bit)
bits = frozenset(bits)
new_db[tag] = bits
return new_db
def load_groups(fn):
ret = []
for l in open(fn, "r"):
ret.append(l.strip())
return ret
def run(fn_in, fn_out, groups_fn, verbose=False):
groups_in = load_groups(groups_fn)
groups = index_masks(fn_in, groups_in)
new_db = apply_masks(fn_in, groups)
util.write_db_lines(fn_out, new_db)
def main():
import argparse
parser = argparse.ArgumentParser(description='Create multi-bit entries')
parser.add_argument('--verbose', action='store_true', help='')
parser.add_argument(
'--groups-fn',
default="groups.grp",
help='File containing one group per line to parse')
parser.add_argument('fn_in', help='')
parser.add_argument('fn_out', help='')
args = parser.parse_args()
run(args.fn_in, args.fn_out, args.groups_fn, verbose=args.verbose)
if __name__ == '__main__':
main()

64
utils/mergedb.py Executable file
View File

@ -0,0 +1,64 @@
#!/usr/bin/env python3
import sys, re
import os
from prjxray import util
def run(fn_ins, fn_out, strict=False, verbose=False):
# tag to bits
entries = {}
# tag to (bits, line)
tags = dict()
# bits to (tag, line)
bitss = dict()
for fn_in in fn_ins:
for line, (tag, bits, mode) in util.parse_db_lines(fn_in):
line = line.strip()
assert mode is not None or mode != "always", "strict: got ill defined line: %s" % (
line, )
if tag in tags:
orig_bits, orig_line = tags[tag]
if orig_bits != bits:
print("WARNING: got duplicate tag %s" % (tag, ))
print(" Orig line: %s" % orig_line)
print(" New line : %s" % line)
assert not strict, "strict: got duplicate tag"
if bits in bitss:
orig_tag, orig_line = bitss[bits]
if orig_tag != tag:
print("WARNING: got duplicate bits %s" % (bits, ))
print(" Orig line: %s" % orig_line)
print(" New line : %s" % line)
assert not strict, "strict: got duplicate bits"
entries[tag] = bits
tags[tag] = (bits, line)
if bits != None:
bitss[bits] = (tag, line)
util.write_db_lines(fn_out, entries)
def main():
import argparse
parser = argparse.ArgumentParser(description="Combine multiple .db files")
util.db_root_arg(parser)
parser.add_argument('--verbose', action='store_true', help='')
parser.add_argument('--out', help='')
parser.add_argument('ins', nargs='+', help='Last takes precedence')
args = parser.parse_args()
run(
args.ins,
args.out,
strict=int(os.getenv("MERGEDB_STRICT", "1")),
verbose=args.verbose)
if __name__ == '__main__':
main()

View File

@ -29,6 +29,7 @@ ${XRAY_PARSEDB} --strict "$2"
# However, expand back to L/R to make downstream tools not depend on this # However, expand back to L/R to make downstream tools not depend on this
# in case we later find exceptions # in case we later find exceptions
ismask=false
case "$1" in case "$1" in
clbll_l) clbll_l)
sed < "$2" > "$tmp1" \ sed < "$2" > "$tmp1" \
@ -77,6 +78,7 @@ case "$1" in
mask_*) mask_*)
db=$XRAY_DATABASE_DIR/$XRAY_DATABASE/$1.db db=$XRAY_DATABASE_DIR/$XRAY_DATABASE/$1.db
ismask=true
cp "$2" "$tmp1" ;; cp "$2" "$tmp1" ;;
*) *)
@ -86,7 +88,12 @@ case "$1" in
esac esac
touch "$db" touch "$db"
sort -u "$tmp1" "$db" | grep -v '<.*>' > "$tmp2" || true if $ismask ; then
sort -u "$tmp1" "$db" | grep -v '<.*>' > "$tmp2" || true
else
# tmp1 must be placed second to take precedence over old bad entries
python3 ${XRAY_DIR}/utils/mergedb.py --out "$tmp2" "$db" "$tmp1"
fi
# Check aggregate db for consistency and make canonical # Check aggregate db for consistency and make canonical
${XRAY_PARSEDB} --strict "$tmp2" "$db" ${XRAY_PARSEDB} --strict "$tmp2" "$db"

View File

@ -7,6 +7,7 @@ Ex: BRAM_L_X6Y100:CLB_IO_CLK
''' '''
import sys, os, json, re import sys, os, json, re
import copy
from prjxray import bitstream from prjxray import bitstream
from prjxray import db as prjxraydb from prjxray import db as prjxraydb
from prjxray import util from prjxray import util
@ -34,7 +35,7 @@ def process_db(db, tile_type, process, verbose):
process(line) process(line)
def get_database(db, tile_type, verbose=False): def get_database(db, tile_type, bit_only=False, verbose=False):
tags = list() tags = list()
if tile_type in segbitsdb: if tile_type in segbitsdb:
@ -47,6 +48,8 @@ def get_database(db, tile_type, verbose=False):
name = parts[0] name = parts[0]
if parts[1] == 'always' or parts[1] == 'hint': if parts[1] == 'always' or parts[1] == 'hint':
if bit_only:
return
tagbits = [] tagbits = []
else: else:
tagbits = [util.parse_tagbit(x) for x in parts[1:]] tagbits = [util.parse_tagbit(x) for x in parts[1:]]
@ -93,31 +96,42 @@ def mk_segbits(seginfo, bitdata):
return segbits return segbits
def print_unknown_bits(segments, bitdata): def gen_tilegrid_masks(tiles):
"""yield (addr_min, addr_max + 1, word_min, word_max + 1)"""
for tilek, tilev in tiles.items():
for block_type, blockj in tilev["bits"].items():
baseaddr = int(blockj["baseaddr"], 0)
frames = blockj["frames"]
offset = blockj["offset"]
words = blockj["words"]
yield (baseaddr, baseaddr + frames, offset, offset + words)
def print_unknown_bits(tiles, bitdata):
''' '''
Print bits not covered by known tiles Print bits not covered by known tiles
'''
# Index all known locations tiles: tilegrid json
# seggrames[address] = set() bitdata[addr][word] = set of bit indices (0 to 31)
# where set contains word numbers '''
segframes = dict() # Start with an open set and remove elements as we find them
for segname, segment in segments.items(): tocheck = copy.deepcopy(bitdata)
block = segment["block"]
framebase = int(block["baseaddr"][0], 16) for addr_min, addr_max_p1, word_min, word_max_p1 in gen_tilegrid_masks(
for i in range(block["frames"]): tiles):
words = segframes.setdefault(framebase + i, set()) for addr in range(addr_min, addr_max_p1):
for j in range(int(block["baseaddr"], 16), if addr not in tocheck:
int(block["baseaddr"], 16) + block["words"]): continue
words.add(j) for word in range(word_min, word_max_p1):
if word not in tocheck[addr]:
continue
del tocheck[addr][word]
# print uncovered locations # print uncovered locations
print('Non-database bits:') print('Non-database bits:')
for frame in sorted(bitdata.keys()): for frame in sorted(tocheck.keys()):
for wordidx in sorted(bitdata[frame].keys()): for wordidx in sorted(tocheck[frame].keys()):
if frame in segframes and wordidx in segframes[frame]: for bitidx in sorted(tocheck[frame][wordidx]):
continue
for bitidx in sorted(bitdata[frame][wordidx]):
print("bit_%08x_%03d_%02d" % (frame, wordidx, bitidx)) print("bit_%08x_%03d_%02d" % (frame, wordidx, bitidx))
@ -145,7 +159,7 @@ def tag_matched(entry, segbits):
decode_warnings = set() decode_warnings = set()
def seg_decode(db, seginfo, segbits, segments, verbose=False): def seg_decode(db, seginfo, segbits, segments, bit_only=False, verbose=False):
''' '''
Remove matched tags from segbits Remove matched tags from segbits
Returns a list of all matched tags Returns a list of all matched tags
@ -169,7 +183,8 @@ def seg_decode(db, seginfo, segbits, segments, verbose=False):
return return
try: try:
entries = get_database(db, tile_type, verbose=verbose) entries = get_database(
db, tile_type, bit_only=bit_only, verbose=verbose)
except NoDB: except NoDB:
verbose and print("WARNING: failed to load DB for %s" % tile_type) verbose and print("WARNING: failed to load DB for %s" % tile_type)
assert tile_type != 'BRAM_L' assert tile_type != 'BRAM_L'
@ -247,10 +262,19 @@ def seg_decode(db, seginfo, segbits, segments, verbose=False):
return segtags return segtags
def print_seg(segname, segbits, segtags, decode_emit): def print_seg(
segname, seginfo, nbits, segbits, segtags, decode_emit, verbose=False):
'''Print segment like used by segmaker/segmatch''' '''Print segment like used by segmaker/segmatch'''
print("seg %s" % (segname, )) print("seg %s" % (segname, ))
if verbose:
print("Bits: %s" % nbits)
print(
"Address: %s, +%s" %
(seginfo["block"]["baseaddr"], seginfo["block"]["frames"]))
print(
"Words: %s, +%s" %
(seginfo["block"]["offset"], seginfo["block"]["words"]))
# Bits that weren't decoded # Bits that weren't decoded
for bit in sorted(segbits): for bit in sorted(segbits):
@ -269,27 +293,34 @@ def handle_segment(
decode_omit, decode_omit,
omit_empty_segs, omit_empty_segs,
segments, segments,
bit_only=False,
verbose=False): verbose=False):
seginfo = segments[segname] seginfo = segments[segname]
# only print bitstream tiles
#if segname not in segments:
# return
segbits = mk_segbits(seginfo, bitdata) segbits = mk_segbits(seginfo, bitdata)
nbits = len(segbits)
if decode_emit or decode_omit: if decode_emit or decode_omit:
segtags = seg_decode(db, seginfo, segbits, segments, verbose=verbose) segtags = seg_decode(
db, seginfo, segbits, segments, bit_only=bit_only, verbose=verbose)
else: else:
segtags = set() segtags = set()
# Found something to print? # Found something to print?
if not (not omit_empty_segs or len(segbits) > 0 or len(segtags) > 0): keep = not omit_empty_segs or len(segbits) > 0 or len(segtags) > 0
if not keep:
return return
print() print()
print_seg(segname, segbits, segtags, decode_emit) print_seg(
segname,
seginfo,
nbits,
segbits,
segtags,
decode_emit,
verbose=verbose)
def overlap(a, b): def overlap(a, b):
@ -402,6 +433,7 @@ def run(
flag_unknown_bits=False, flag_unknown_bits=False,
flag_decode_emit=False, flag_decode_emit=False,
flag_decode_omit=False, flag_decode_omit=False,
bit_only=False,
verbose=False): verbose=False):
db = prjxraydb.Database(db_root) db = prjxraydb.Database(db_root)
tiles = load_tiles(db_root) tiles = load_tiles(db_root)
@ -409,7 +441,8 @@ def run(
bitdata = bitstream.load_bitdata2(open(bits_file, "r")) bitdata = bitstream.load_bitdata2(open(bits_file, "r"))
if flag_unknown_bits: if flag_unknown_bits:
print_unknown_bits(segments, bitdata) print_unknown_bits(tiles, bitdata)
print("")
# Default: print all # Default: print all
if segnames: if segnames:
@ -432,6 +465,7 @@ def run(
flag_decode_omit, flag_decode_omit,
omit_empty_segs, omit_empty_segs,
segments, segments,
bit_only=bit_only,
verbose=verbose) verbose=verbose)
@ -453,19 +487,29 @@ def main():
'-d', '-d',
action='store_true', action='store_true',
help='decode known segment bits and write them as tags') help='decode known segment bits and write them as tags')
# XXX: possibly broken, or we have missing DB data
parser.add_argument( parser.add_argument(
'-D', '-D',
action='store_true', action='store_true',
help='decode known segment bits and omit them in the output') help='decode known segment bits and omit them in the output')
parser.add_argument(
'--bit-only',
action='store_true',
help='only decode real bitstream directives')
parser.add_argument('bits_file', help='') parser.add_argument('bits_file', help='')
parser.add_argument( parser.add_argument(
'segnames', nargs='*', help='List of tile or tile:block to print') 'segnames', nargs='*', help='List of tile or tile:block to print')
args = parser.parse_args() args = parser.parse_args()
run( run(
args.db_root, args.bits_file, args.segnames, args.z, args.b, args.d, args.db_root,
args.D, args.verbose) args.bits_file,
args.segnames,
args.z,
args.b,
args.d,
args.D,
bit_only=args.bit_only,
verbose=args.verbose)
if __name__ == '__main__': if __name__ == '__main__':