mirror of https://github.com/openXC7/prjxray.git
Fuzzers: 007: add bel timing fuzzer
Signed-off-by: Karol Gugala <kgugala@antmicro.com>
This commit is contained in:
parent
3ccc2df586
commit
5d9da26f78
|
|
@ -0,0 +1,2 @@
|
|||
build
|
||||
debug*.json
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
all: build/sdf
|
||||
|
||||
clean:
|
||||
rm -rf build
|
||||
|
||||
build/bel_timings.txt:
|
||||
bash runme.sh
|
||||
|
||||
build/bel_timings.json: build/bel_timings.txt
|
||||
python3 tim2json.py --timings=build/bel_timings.txt --json=build/bel_timings.json --properties=build/bel_properties.txt --belpins=build/bel_pins.txt --sitepins=build/tile_pins.txt
|
||||
|
||||
build/sdf: build/bel_timings.json
|
||||
python3 ${XRAY_UTILS_DIR}/makesdf.py --json=${PWD}/build/bel_timings.json --sdf=${PWD}/build
|
||||
touch run.ok
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
# Create build dir
|
||||
export SRC_DIR=$PWD
|
||||
export BUILD_DIR=build
|
||||
|
||||
mkdir -p $BUILD_DIR
|
||||
cd $BUILD_DIR
|
||||
|
||||
${XRAY_VIVADO} -mode batch -source $SRC_DIR/runme.tcl
|
||||
test -z "$(fgrep CRITICAL vivado.log)" && touch run.ok
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
source "$::env(XRAY_DIR)/utils/utils.tcl"
|
||||
|
||||
proc create_design {} {
|
||||
|
||||
create_project -force -part $::env(XRAY_PART) design design
|
||||
read_verilog $::env(SRC_DIR)/top.v
|
||||
synth_design -top top -flatten_hierarchy none
|
||||
|
||||
set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports di]
|
||||
set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports do]
|
||||
|
||||
set_property CFGBVS VCCO [current_design]
|
||||
set_property CONFIG_VOLTAGE 3.3 [current_design]
|
||||
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
|
||||
}
|
||||
|
||||
proc place_and_route_design {} {
|
||||
|
||||
place_design
|
||||
route_design
|
||||
|
||||
write_checkpoint -force design.dcp
|
||||
}
|
||||
|
||||
proc dump_tile_timings {tile timing_fp config_fp pins_fp tile_pins_fp} {
|
||||
|
||||
set properties [list "DELAY" "FAST_MAX" "FAST_MIN" "SLOW_MAX" "SLOW_MIN"]
|
||||
set timing_line {}
|
||||
set config_line {}
|
||||
set pins_line {}
|
||||
set tile_pins_line {}
|
||||
|
||||
lappend timing_line [get_property TYPE $tile]
|
||||
lappend config_line [get_property TYPE $tile]
|
||||
lappend pins_line [get_property TYPE $tile]
|
||||
lappend tile_pins_line [get_property TYPE $tile]
|
||||
|
||||
set sites [get_sites -of_objects [get_tiles $tile]]
|
||||
|
||||
lappend tile_pins_line [llength $sites]
|
||||
lappend timing_line [llength $sites]
|
||||
lappend config_line [llength $sites]
|
||||
lappend pins_line [llength $sites]
|
||||
|
||||
foreach site $sites {
|
||||
set site_type [get_property SITE_TYPE $site]
|
||||
|
||||
lappend tile_pins_line $site_type
|
||||
lappend pins_line $site_type
|
||||
lappend timing_line $site_type
|
||||
lappend config_line $site_type
|
||||
|
||||
# dump site pins
|
||||
set site_pins [get_site_pins -of_objects [get_sites $site]]
|
||||
lappend tile_pins_line [llength $site_pins]
|
||||
|
||||
foreach pin $site_pins {
|
||||
set direction [get_property DIRECTION $pin]
|
||||
regexp {\/(.*)$} $pin -> pin
|
||||
lappend tile_pins_line $pin $direction
|
||||
}
|
||||
|
||||
# dump bel pins, speed_models and configs
|
||||
set bels [get_bels -of_objects $site]
|
||||
|
||||
lappend pins_line [llength $bels]
|
||||
lappend timing_line [llength $bels]
|
||||
lappend config_line [llength $bels]
|
||||
|
||||
foreach bel $bels {
|
||||
set speed_models [get_speed_models -of_objects $bel]
|
||||
set bel_type [get_property TYPE $bel]
|
||||
set bel_configs [list_property $bel CONFIG*]
|
||||
set bel_pins [get_bel_pins -of_objects [get_bels $bel]]
|
||||
|
||||
lappend pins_line $bel_type
|
||||
lappend pins_line [llength $bel_pins]
|
||||
foreach pin $bel_pins {
|
||||
set direction [get_property DIRECTION $pin]
|
||||
set is_clock [get_property IS_CLOCK $pin]
|
||||
regexp {\/.*\/(.*)$} $pin -> pin
|
||||
lappend pins_line $pin $direction $is_clock
|
||||
}
|
||||
|
||||
lappend config_line $bel_type
|
||||
lappend config_line [llength $bel_configs]
|
||||
foreach config $bel_configs {
|
||||
set config_vals [get_property $config $bel]
|
||||
lappend config_line $config
|
||||
lappend config_line [llength $config_vals]
|
||||
foreach val $config_vals {
|
||||
lappend config_line $val
|
||||
}
|
||||
}
|
||||
|
||||
lappend timing_line "$bel_type"
|
||||
lappend timing_line [llength $speed_models]
|
||||
foreach speed_model $speed_models {
|
||||
lappend timing_line $speed_model
|
||||
foreach property $properties {
|
||||
set value [get_property $property $speed_model]
|
||||
lappend timing_line "$property:$value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
puts $tile_pins_fp $tile_pins_line
|
||||
puts $pins_fp $pins_line
|
||||
puts $timing_fp $timing_line
|
||||
puts $config_fp $config_line
|
||||
}
|
||||
|
||||
proc dump {} {
|
||||
|
||||
set types [get_tile_types]
|
||||
set timing_fp [open "bel_timings.txt" w]
|
||||
set property_fp [open "bel_properties.txt" w]
|
||||
set pins_fp [open "bel_pins.txt" w]
|
||||
set tile_pins_fp [open "tile_pins.txt" w]
|
||||
foreach type $types {
|
||||
set tile [randsample_list 1 [get_tiles -filter "TYPE == $type"]]
|
||||
dump_tile_timings $tile $timing_fp $property_fp $pins_fp $tile_pins_fp
|
||||
}
|
||||
close $pins_fp
|
||||
close $timing_fp
|
||||
close $property_fp
|
||||
}
|
||||
|
||||
proc run {} {
|
||||
create_design
|
||||
place_and_route_design
|
||||
dump
|
||||
write_bitstream -force design.bit
|
||||
}
|
||||
|
||||
run
|
||||
|
|
@ -0,0 +1,381 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import json
|
||||
|
||||
|
||||
def check_sequential(speed_model):
|
||||
# combinational path models do not contain
|
||||
# the following keywords
|
||||
timing_keywords = {
|
||||
'setup': 'setup',
|
||||
'remov': 'removal',
|
||||
'hold': 'hold',
|
||||
'recov': 'recovery',
|
||||
'removal': 'removal',
|
||||
'recovery': 'recovery'
|
||||
}
|
||||
tmp = speed_model.split('_')
|
||||
for keyword in timing_keywords:
|
||||
if keyword in tmp:
|
||||
# return found keyword and it's map in SDF
|
||||
return [keyword, timing_keywords[keyword]]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# FF's can be configured to work as FF or latch
|
||||
def check_ff_latch(speed_model):
|
||||
|
||||
tmp = speed_model.split('_')
|
||||
if 'ff' in tmp:
|
||||
return 'ff'
|
||||
elif 'lat' in tmp:
|
||||
return 'lat'
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
# some bels have duplicate names e.g bufmrce_bufmrce
|
||||
# this function cleans them
|
||||
def clean_bname(bname):
|
||||
tmp = bname.split('_')
|
||||
if len(tmp) > 1 and tmp[0] == tmp[1]:
|
||||
return '_'.join(tmp[1:])
|
||||
return bname
|
||||
|
||||
|
||||
def pin_in_model(pin, model):
|
||||
|
||||
if len(pin.split('_')) == 1:
|
||||
# pin name is one word, search it in the model
|
||||
return pin in model.split('_')
|
||||
else:
|
||||
# pin name is multi word, search for a string
|
||||
return pin in model
|
||||
|
||||
|
||||
def remove_pin_from_model(pin, model):
|
||||
|
||||
if len(pin.split('_')) == 1:
|
||||
# pin name is one word, search it in the model
|
||||
tmp = model.split('_')
|
||||
tmp.remove(pin)
|
||||
return "_".join(tmp)
|
||||
else:
|
||||
# pin name is multi word, search for a string
|
||||
return "_".join(
|
||||
list(filter(None,
|
||||
speed_model.replace(pin, '').split('_'))))
|
||||
|
||||
|
||||
def read_raw_timings(fin, properties, pins, site_pins):
|
||||
|
||||
timings = dict()
|
||||
with open(fin, "r") as f:
|
||||
for line in f:
|
||||
|
||||
raw_data = line.split()
|
||||
slice = raw_data[0]
|
||||
|
||||
#XXX: debug
|
||||
if slice.startswith('DSP'):
|
||||
continue
|
||||
|
||||
sites_count = int(raw_data[1])
|
||||
loc = 2
|
||||
timings[slice] = dict()
|
||||
for site in range(0, sites_count):
|
||||
|
||||
site_name = raw_data[loc]
|
||||
bels_count = int(raw_data[loc + 1])
|
||||
print(slice, site_name)
|
||||
|
||||
# read all BELs data within
|
||||
loc += 2
|
||||
for bel in range(0, bels_count):
|
||||
tmp_data = raw_data[loc:]
|
||||
btype = (tmp_data[0]).lower()
|
||||
delay_count = int(tmp_data[1])
|
||||
|
||||
# get all the delays
|
||||
delay_loc = 2
|
||||
for delay in range(0, delay_count):
|
||||
speed_model = tmp_data[delay_loc]
|
||||
delay_btype = clean_bname(btype)
|
||||
delay_btype_orig = delay_btype
|
||||
# all the bel names seem to start with "bel_d_"
|
||||
# let's get rid of it
|
||||
if speed_model.startswith('bel_d_'):
|
||||
speed_model = speed_model[6:]
|
||||
|
||||
# keep original speed model string to use as unique dict entry
|
||||
speed_model_orig = speed_model
|
||||
|
||||
# if more than one BEL type exists in the slice
|
||||
# location is added at the end of the name
|
||||
tmp = speed_model.split(':')
|
||||
speed_model = tmp[0]
|
||||
|
||||
bel_location = site_name
|
||||
if len(tmp) > 2:
|
||||
bel_location += "/" + "/".join(tmp[2:])
|
||||
|
||||
bel_location = bel_location.upper()
|
||||
|
||||
sequential = check_sequential(speed_model)
|
||||
if sequential is not None:
|
||||
tmp = speed_model.split('_')
|
||||
tmp.remove(sequential[0])
|
||||
speed_model = '_'.join(tmp)
|
||||
|
||||
bel_input = None
|
||||
bel_output = None
|
||||
bel_clock = None
|
||||
|
||||
# strip btype from speed model so we can search for pins
|
||||
speed_model_clean = speed_model
|
||||
if speed_model.startswith(delay_btype):
|
||||
speed_model_clean = speed_model[len(delay_btype):]
|
||||
|
||||
# locate pins
|
||||
for pin in pins[slice][site_name][delay_btype_orig]:
|
||||
if pin_in_model(pin.lower(), speed_model_clean):
|
||||
if pins[slice][site_name][delay_btype_orig][
|
||||
pin]['direction'] == 'IN':
|
||||
bel_input = pin
|
||||
if pins[slice][site_name][delay_btype_orig][
|
||||
pin]['direction'] == 'OUT':
|
||||
bel_output = pin
|
||||
if pins[slice][site_name][delay_btype_orig][
|
||||
pin]['is_clock']:
|
||||
bel_clock = pin
|
||||
speed_model_clean = remove_pin_from_model(
|
||||
pin.lower(), speed_model_clean)
|
||||
|
||||
# Some speed models describe delays from/to site pins instead of BEL pins
|
||||
if bel_input is None:
|
||||
# search site inputs
|
||||
for pin in site_pins[slice][site_name.lower()]:
|
||||
if pin_in_model(pin.lower(),
|
||||
speed_model_clean):
|
||||
if site_pins[slice][site_name.lower(
|
||||
)][pin]['direction'] == 'IN':
|
||||
bel_input = pin
|
||||
speed_model_clean = remove_pin_from_model(
|
||||
pin.lower(), speed_model_clean)
|
||||
|
||||
if bel_output is None:
|
||||
for pin in site_pins[slice][site_name.lower()]:
|
||||
if pin_in_model(pin.lower(),
|
||||
speed_model_clean):
|
||||
if site_pins[slice][site_name.lower(
|
||||
)][pin]['direction'] == 'OUT':
|
||||
bel_output = pin
|
||||
speed_model_clean = remove_pin_from_model(
|
||||
pin.lower(), speed_model_clean)
|
||||
|
||||
if bel_clock is None:
|
||||
for pin in site_pins[slice][site_name.lower()]:
|
||||
if pin_in_model(pin.lower(),
|
||||
speed_model_clean):
|
||||
if site_pins[slice][site_name.lower(
|
||||
)][pin]['is_clock']:
|
||||
bel_clock = pin
|
||||
speed_model_clean = remove_pin_from_model(
|
||||
pin.lower(), speed_model_clean)
|
||||
|
||||
# restore speed model name
|
||||
speed_model = delay_btype + speed_model_clean
|
||||
|
||||
if sequential is not None:
|
||||
if bel_output is None and bel_clock is None:
|
||||
delay_loc += 6
|
||||
continue
|
||||
else:
|
||||
if bel_input is None or bel_output is None:
|
||||
delay_loc += 6
|
||||
continue
|
||||
|
||||
delay_btype = speed_model
|
||||
extra_ports = None
|
||||
|
||||
if bel_location not in timings[slice]:
|
||||
timings[slice][bel_location] = dict()
|
||||
|
||||
if delay_btype not in timings[slice][bel_location]:
|
||||
timings[slice][bel_location][delay_btype] = dict()
|
||||
|
||||
timings[slice][bel_location][delay_btype][
|
||||
speed_model_orig] = dict()
|
||||
timings[slice][bel_location][delay_btype][
|
||||
speed_model_orig]['type'] = btype.upper()
|
||||
timings[slice][bel_location][delay_btype][
|
||||
speed_model_orig]['input'] = bel_input.upper()
|
||||
if bel_output is not None:
|
||||
timings[slice][bel_location][delay_btype][
|
||||
speed_model_orig]['output'] = bel_output.upper(
|
||||
)
|
||||
if bel_clock is not None:
|
||||
timings[slice][bel_location][delay_btype][
|
||||
speed_model_orig]['clock'] = bel_clock.upper()
|
||||
timings[slice][bel_location][delay_btype][
|
||||
speed_model_orig]['location'] = bel_location.upper(
|
||||
)
|
||||
|
||||
#XXX: debug
|
||||
timings[slice][bel_location][delay_btype][
|
||||
speed_model_orig]['model'] = speed_model_orig
|
||||
if sequential is not None:
|
||||
timings[slice][bel_location][delay_btype][
|
||||
speed_model_orig]['sequential'] = sequential[1]
|
||||
if extra_ports is not None:
|
||||
timings[slice][bel_location][delay_btype][
|
||||
speed_model_orig]['extra_ports'] = extra_ports
|
||||
|
||||
# each timing entry reports 5 delays
|
||||
for d in range(0, 5):
|
||||
(t, v) = tmp_data[d + 1 + delay_loc].split(':')
|
||||
timings[slice][bel_location][delay_btype][
|
||||
speed_model_orig][t] = v
|
||||
|
||||
# 5 delay values + name
|
||||
delay_loc += 6
|
||||
loc += delay_loc
|
||||
return timings
|
||||
|
||||
|
||||
def read_bel_properties(properties_file):
|
||||
|
||||
properties = dict()
|
||||
with open(properties_file, 'r') as f:
|
||||
for line in f:
|
||||
raw_props = line.split()
|
||||
tile = raw_props[0]
|
||||
sites_count = int(raw_props[1])
|
||||
prop_loc = 2
|
||||
properties[tile] = dict()
|
||||
for site in range(0, sites_count):
|
||||
site_name = raw_props[prop_loc]
|
||||
bels_count = int(raw_props[prop_loc + 1])
|
||||
prop_loc += 2
|
||||
properties[tile][site_name] = dict()
|
||||
for bel in range(0, bels_count):
|
||||
bel_name = raw_props[prop_loc]
|
||||
bel_name = clean_bname(bel_name)
|
||||
bel_name = bel_name.lower()
|
||||
bel_properties_count = int(raw_props[prop_loc + 1])
|
||||
properties[tile][site_name][bel_name] = dict()
|
||||
prop_loc += 2
|
||||
for prop in range(0, bel_properties_count):
|
||||
prop_name = raw_props[prop_loc]
|
||||
# the name always starts with "CONFIG." and ends with ".VALUES"
|
||||
# let's get rid of that
|
||||
prop_name = prop_name[7:-7]
|
||||
prop_values_count = int(raw_props[prop_loc + 1])
|
||||
properties[tile][site_name][bel_name][
|
||||
prop_name] = raw_props[prop_loc + 2:prop_loc + 2 +
|
||||
prop_values_count]
|
||||
prop_loc += 2 + prop_values_count
|
||||
|
||||
return properties
|
||||
|
||||
|
||||
def read_bel_pins(pins_file):
|
||||
|
||||
pins = dict()
|
||||
with open(pins_file, 'r') as f:
|
||||
for line in f:
|
||||
raw_pins = line.split()
|
||||
tile = raw_pins[0]
|
||||
sites_count = int(raw_pins[1])
|
||||
pin_loc = 2
|
||||
pins[tile] = dict()
|
||||
for site in range(0, sites_count):
|
||||
site_name = raw_pins[pin_loc]
|
||||
bels_count = int(raw_pins[pin_loc + 1])
|
||||
pin_loc += 2
|
||||
pins[tile][site_name] = dict()
|
||||
for bel in range(0, bels_count):
|
||||
bel_name = raw_pins[pin_loc]
|
||||
bel_name = clean_bname(bel_name)
|
||||
bel_name = bel_name.lower()
|
||||
bel_pins_count = int(raw_pins[pin_loc + 1])
|
||||
pins[tile][site_name][bel_name] = dict()
|
||||
pin_loc += 2
|
||||
for pin in range(0, bel_pins_count):
|
||||
pin_name = raw_pins[pin_loc]
|
||||
pin_direction = raw_pins[pin_loc + 1]
|
||||
pin_is_clock = raw_pins[pin_loc + 2]
|
||||
pins[tile][site_name][bel_name][pin_name] = dict()
|
||||
pins[tile][site_name][bel_name][pin_name][
|
||||
'direction'] = pin_direction
|
||||
pins[tile][site_name][bel_name][pin_name][
|
||||
'is_clock'] = int(pin_is_clock) == 1
|
||||
pin_loc += 3
|
||||
return pins
|
||||
|
||||
|
||||
def read_site_pins(pins_file):
|
||||
|
||||
pins = dict()
|
||||
with open(pins_file, 'r') as f:
|
||||
for line in f:
|
||||
raw_pins = line.split()
|
||||
tile = raw_pins[0]
|
||||
site_count = int(raw_pins[1])
|
||||
pin_loc = 2
|
||||
pins[tile] = dict()
|
||||
for site in range(0, site_count):
|
||||
site_name = raw_pins[pin_loc]
|
||||
site_name = site_name.lower()
|
||||
site_pins_count = int(raw_pins[pin_loc + 1])
|
||||
pins[tile][site_name] = dict()
|
||||
pin_loc += 2
|
||||
for pin in range(0, site_pins_count):
|
||||
pin_name = raw_pins[pin_loc]
|
||||
pin_direction = raw_pins[pin_loc + 1]
|
||||
pins[tile][site_name][pin_name] = dict()
|
||||
pins[tile][site_name][pin_name][
|
||||
'direction'] = pin_direction
|
||||
# site clock pins are always named 'CLK'
|
||||
pins[tile][site_name][pin_name][
|
||||
'is_clock'] = pin_name.lower() == 'clk'
|
||||
pin_loc += 2
|
||||
return pins
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--timings', type=str, help='Raw timing input file')
|
||||
parser.add_argument('--json', type=str, help='json output file')
|
||||
parser.add_argument(
|
||||
'--properties', type=str, help='Bel properties input file')
|
||||
parser.add_argument('--belpins', type=str, help='Bel pins input file')
|
||||
parser.add_argument('--sitepins', type=str, help='Site pins input file')
|
||||
parser.add_argument(
|
||||
'--debug', type=bool, default=False, help='Enable debug json dumps')
|
||||
args = parser.parse_args()
|
||||
properties = read_bel_properties(args.properties)
|
||||
|
||||
if args.debug:
|
||||
with open('debug_prop.json', 'w') as fp:
|
||||
json.dump(properties, fp, indent=4, sort_keys=True)
|
||||
|
||||
pins = read_bel_pins(args.belpins)
|
||||
if args.debug:
|
||||
with open('debug_pins.json', 'w') as fp:
|
||||
json.dump(pins, fp, indent=4, sort_keys=True)
|
||||
|
||||
site_pins = read_site_pins(args.sitepins)
|
||||
if args.debug:
|
||||
with open('debug_site_pins.json', 'w') as fp:
|
||||
json.dump(site_pins, fp, indent=4, sort_keys=True)
|
||||
|
||||
timings = read_raw_timings(args.timings, properties, pins, site_pins)
|
||||
with open(args.json, 'w') as fp:
|
||||
json.dump(timings, fp, indent=4, sort_keys=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
module top(input di, output do);
|
||||
|
||||
assign do = di;
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue