mirror of https://github.com/openXC7/prjxray.git
Merge pull request #1229 from litghost/serdes_timing
I/OSERDES BEL timing
This commit is contained in:
commit
541d88c999
|
|
@ -19,6 +19,7 @@ build/fixup_timings: build/run.ok
|
||||||
python3 fixup_timings_txt.py --txtin build/bel_pins.txt --txtout build/bel_pins.txt --site RAMBFIFO36E1 --slice BRAM_R --type pins
|
python3 fixup_timings_txt.py --txtin build/bel_pins.txt --txtout build/bel_pins.txt --site RAMBFIFO36E1 --slice BRAM_R --type pins
|
||||||
python3 fixup_timings_txt.py --txtin build/bel_properties.txt --txtout build/bel_properties.txt --site RAMBFIFO36E1 --slice BRAM_L --type properties
|
python3 fixup_timings_txt.py --txtin build/bel_properties.txt --txtout build/bel_properties.txt --site RAMBFIFO36E1 --slice BRAM_L --type properties
|
||||||
python3 fixup_timings_txt.py --txtin build/bel_properties.txt --txtout build/bel_properties.txt --site RAMBFIFO36E1 --slice BRAM_R --type properties
|
python3 fixup_timings_txt.py --txtin build/bel_properties.txt --txtout build/bel_properties.txt --site RAMBFIFO36E1 --slice BRAM_R --type properties
|
||||||
|
touch build/fixup_timings
|
||||||
|
|
||||||
build/bel_timings.json: build/fixup_timings
|
build/bel_timings.json: build/fixup_timings
|
||||||
python3 tim2json.py --timings=build/bel_timings.txt --json=build/bel_timings.json --properties=build/bel_properties.txt --propertiesmap=properties_map.json --pinaliasmap=pin_alias_map.json --belpins=build/bel_pins.txt --sitepins=build/tile_pins.txt --debug true
|
python3 tim2json.py --timings=build/bel_timings.txt --json=build/bel_timings.json --properties=build/bel_properties.txt --propertiesmap=properties_map.json --pinaliasmap=pin_alias_map.json --belpins=build/bel_pins.txt --sitepins=build/tile_pins.txt --debug true
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ def fix_line(line, site, filetype):
|
||||||
entries.append(line[loc])
|
entries.append(line[loc])
|
||||||
loc += 1
|
loc += 1
|
||||||
elif filetype == 'pins':
|
elif filetype == 'pins':
|
||||||
for pin_word in range(0, 3):
|
for pin_word in range(0, 4):
|
||||||
entries.append(line[loc])
|
entries.append(line[loc])
|
||||||
loc += 1
|
loc += 1
|
||||||
elif filetype == 'properties':
|
elif filetype == 'properties':
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,9 @@ proc dump_tile_timings {tile timing_fp config_fp pins_fp tile_pins_fp} {
|
||||||
|
|
||||||
foreach pin $site_pins {
|
foreach pin $site_pins {
|
||||||
set direction [get_property DIRECTION $pin]
|
set direction [get_property DIRECTION $pin]
|
||||||
|
set is_part_of_bus [get_property IS_PART_OF_BUS $pin]
|
||||||
regexp {\/(.*)$} $pin -> pin
|
regexp {\/(.*)$} $pin -> pin
|
||||||
lappend tile_pins_line $pin $direction
|
lappend tile_pins_line $pin $direction $is_part_of_bus
|
||||||
}
|
}
|
||||||
|
|
||||||
# dump bel pins, speed_models and configs
|
# dump bel pins, speed_models and configs
|
||||||
|
|
@ -78,8 +79,9 @@ proc dump_tile_timings {tile timing_fp config_fp pins_fp tile_pins_fp} {
|
||||||
foreach pin $bel_pins {
|
foreach pin $bel_pins {
|
||||||
set direction [get_property DIRECTION $pin]
|
set direction [get_property DIRECTION $pin]
|
||||||
set is_clock [get_property IS_CLOCK $pin]
|
set is_clock [get_property IS_CLOCK $pin]
|
||||||
|
set is_part_of_bus [get_property IS_PART_OF_BUS $pin]
|
||||||
regexp {\/.*\/(.*)$} $pin -> pin
|
regexp {\/.*\/(.*)$} $pin -> pin
|
||||||
lappend pins_line $pin $direction $is_clock
|
lappend pins_line $pin $direction $is_clock $is_part_of_bus
|
||||||
}
|
}
|
||||||
|
|
||||||
lappend config_line $bel_type
|
lappend config_line $bel_type
|
||||||
|
|
@ -123,6 +125,17 @@ proc dump {} {
|
||||||
set tile [randsample_list 1 [get_tiles -filter "TYPE == $type"]]
|
set tile [randsample_list 1 [get_tiles -filter "TYPE == $type"]]
|
||||||
dump_tile_timings $tile $timing_fp $property_fp $pins_fp $tile_pins_fp
|
dump_tile_timings $tile $timing_fp $property_fp $pins_fp $tile_pins_fp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set other_site_types [list ISERDESE2 OSERDESE2]
|
||||||
|
foreach site_type $other_site_types {
|
||||||
|
set cell [create_cell -reference $site_type test]
|
||||||
|
place_design
|
||||||
|
set tile [get_tiles -of [get_sites -of $cell]]
|
||||||
|
dump_tile_timings $tile $timing_fp $property_fp $pins_fp $tile_pins_fp
|
||||||
|
unplace_cell $cell
|
||||||
|
remove_cell $cell
|
||||||
|
}
|
||||||
|
|
||||||
close $pins_fp
|
close $pins_fp
|
||||||
close $timing_fp
|
close $timing_fp
|
||||||
close $property_fp
|
close $property_fp
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import re
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
|
import functools
|
||||||
|
|
||||||
|
NUMBER_RE = re.compile(r'\d+$')
|
||||||
|
|
||||||
|
|
||||||
def check_sequential(speed_model):
|
def check_sequential(speed_model):
|
||||||
|
|
@ -120,7 +124,7 @@ def instance_in_model(instance, model):
|
||||||
return instance in model
|
return instance in model
|
||||||
|
|
||||||
|
|
||||||
def pin_in_model(pin, pin_aliases, model, direction=None):
|
def create_pin_in_model(pin_aliases):
|
||||||
"""
|
"""
|
||||||
Checks if a given pin belongs to the model.
|
Checks if a given pin belongs to the model.
|
||||||
|
|
||||||
|
|
@ -145,45 +149,50 @@ def pin_in_model(pin, pin_aliases, model, direction=None):
|
||||||
The second returned value contains found pin name. If the
|
The second returned value contains found pin name. If the
|
||||||
pin is not found, None is returned.
|
pin is not found, None is returned.
|
||||||
|
|
||||||
>>> pin_in_model("d", None, "ff_init_din_q", "in")
|
>>> create_pin_in_model(None)("d", "ff_init_din_q", "in")
|
||||||
(True, 'din')
|
(True, 'din')
|
||||||
|
|
||||||
>>> pin_in_model("q", None, "ff_init_clk_q", None)
|
>>> create_pin_in_model(None)("q", "ff_init_clk_q", None)
|
||||||
(True, 'q')
|
(True, 'q')
|
||||||
|
|
||||||
>>> pin_in_model("q", {"Q": {"names" : ["QL", "QH"], "is_property_related" : True}}, "ff_init_clk_ql", None)
|
>>> create_pin_in_model({"Q": {"names" : ["QL", "QH"], "is_property_related" : True}})("q", "ff_init_clk_ql", None)
|
||||||
(True, 'q')
|
(True, 'q')
|
||||||
|
|
||||||
>>> pin_in_model("logic_out", None, "my_cell_i_logic_out", None)
|
>>> create_pin_in_model(None)("logic_out", "my_cell_i_logic_out", None)
|
||||||
(True, 'logic_out')
|
(True, 'logic_out')
|
||||||
|
|
||||||
>>> pin_in_model("logic_out", {"LOGIC_OUT": {"names" : ["LOGIC_O", "O"], "is_property_related" : False}}, "my_cell_i_logic_o", None)
|
>>> create_pin_in_model({"LOGIC_OUT": {"names" : ["LOGIC_O", "O"], "is_property_related" : False}})("logic_out", "my_cell_i_logic_o", None)
|
||||||
(True, 'logic_o')
|
(True, 'logic_o')
|
||||||
|
|
||||||
>>> pin_in_model("logic_out", {"LOGIC_OUT": {"names" : ["LOGIC_O", "O"], "is_property_related" : False}}, "my_cell_i_o", None)
|
>>> create_pin_in_model({"LOGIC_OUT": {"names" : ["LOGIC_O", "O"], "is_property_related" : False}})("logic_out", "my_cell_i_o", None)
|
||||||
(True, 'o')
|
(True, 'o')
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# strip site location
|
@functools.lru_cache(maxsize=10000)
|
||||||
model = model.split(':')[0]
|
def pin_in_model(pin, model, direction=None):
|
||||||
extended_pin_name = pin
|
# strip site location
|
||||||
aliased_pin, aliased_pin_name = find_aliased_pin(
|
model = model.split(':')[0]
|
||||||
pin.upper(), model, pin_aliases)
|
|
||||||
|
|
||||||
# some timings reports pins with their directions
|
extended_pin_name = pin
|
||||||
# this happens for e.g. CLB reg_init D pin, which
|
aliased_pin, aliased_pin_name = find_aliased_pin(
|
||||||
# timing is reported as DIN
|
pin.upper(), model, pin_aliases)
|
||||||
if direction is not None:
|
|
||||||
extended_pin_name = pin + direction
|
|
||||||
|
|
||||||
if instance_in_model(pin, model):
|
# some timings reports pins with their directions
|
||||||
return True, pin
|
# this happens for e.g. CLB reg_init D pin, which
|
||||||
elif instance_in_model(extended_pin_name, model):
|
# timing is reported as DIN
|
||||||
return True, extended_pin_name
|
if direction is not None:
|
||||||
elif aliased_pin:
|
extended_pin_name = pin + direction
|
||||||
return True, aliased_pin_name
|
|
||||||
else:
|
if instance_in_model(pin, model):
|
||||||
return False, None
|
return True, pin
|
||||||
|
elif instance_in_model(extended_pin_name, model):
|
||||||
|
return True, extended_pin_name
|
||||||
|
elif aliased_pin:
|
||||||
|
return True, aliased_pin_name
|
||||||
|
else:
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
return pin_in_model
|
||||||
|
|
||||||
|
|
||||||
def remove_pin_from_model(pin, model):
|
def remove_pin_from_model(pin, model):
|
||||||
|
|
@ -227,6 +236,43 @@ def remove_pin_from_model(pin, model):
|
||||||
return "_".join(list(filter(None, model.replace(pin, '').split('_'))))
|
return "_".join(list(filter(None, model.replace(pin, '').split('_'))))
|
||||||
|
|
||||||
|
|
||||||
|
def merged_dict(itr):
|
||||||
|
""" Create a merged dict of dict (of dict) based on input.
|
||||||
|
|
||||||
|
Input is an iteratable of (keys, value).
|
||||||
|
|
||||||
|
Return value is root dictionary
|
||||||
|
|
||||||
|
Keys are successive dictionaries indicies. For example:
|
||||||
|
(('a', 'b', 'c'), 1)
|
||||||
|
|
||||||
|
would set:
|
||||||
|
|
||||||
|
output['a']['b']['c'] = 1
|
||||||
|
|
||||||
|
This function returns an error if two values conflict.
|
||||||
|
|
||||||
|
>>> merged_dict(((('a', 'b', 'c'), 1), (('a', 'b', 'd'), 2)))
|
||||||
|
{'a': {'b': {'c': 1, 'd': 2}}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
output = {}
|
||||||
|
for keys, value in itr:
|
||||||
|
target = output
|
||||||
|
for key in keys[:-1]:
|
||||||
|
if key not in target:
|
||||||
|
target[key] = {}
|
||||||
|
target = target[key]
|
||||||
|
|
||||||
|
if keys[-1] in target:
|
||||||
|
assert target[keys[-1]] == value, (keys, value, target[keys[-1]])
|
||||||
|
else:
|
||||||
|
target[keys[-1]] = value
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
def extract_properties(tile, site, bel, properties, model):
|
def extract_properties(tile, site, bel, properties, model):
|
||||||
|
|
||||||
if tile not in properties:
|
if tile not in properties:
|
||||||
|
|
@ -254,379 +300,417 @@ def extract_properties(tile, site, bel, properties, model):
|
||||||
return model_properties
|
return model_properties
|
||||||
|
|
||||||
|
|
||||||
def read_raw_timings(fin, properties, pins, site_pins, pin_alias_map):
|
def parse_raw_timing(fin):
|
||||||
|
|
||||||
timings = dict()
|
|
||||||
with open(fin, "r") as f:
|
with open(fin, "r") as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
|
|
||||||
raw_data = line.split()
|
raw_data = line.split()
|
||||||
slice = raw_data[0]
|
slice = raw_data[0]
|
||||||
|
|
||||||
#XXX: debug
|
|
||||||
if slice.startswith('DSP'):
|
|
||||||
continue
|
|
||||||
|
|
||||||
sites_count = int(raw_data[1])
|
sites_count = int(raw_data[1])
|
||||||
loc = 2
|
loc = 2
|
||||||
for site in range(0, sites_count):
|
for site in range(0, sites_count):
|
||||||
|
|
||||||
site_name = raw_data[loc]
|
site_name = raw_data[loc]
|
||||||
bels_count = int(raw_data[loc + 1])
|
bels_count = int(raw_data[loc + 1])
|
||||||
print(slice, site_name)
|
|
||||||
|
|
||||||
# read all BELs data within
|
# read all BELs data within
|
||||||
loc += 2
|
loc += 2
|
||||||
for bel in range(0, bels_count):
|
for bel in range(0, bels_count):
|
||||||
btype = (raw_data[loc]).lower()
|
bel = raw_data[loc]
|
||||||
delay_count = int(raw_data[loc + 1])
|
delay_count = int(raw_data[loc + 1])
|
||||||
|
|
||||||
# get all the delays
|
# get all the delays
|
||||||
loc += 2
|
loc += 2
|
||||||
for delay in range(0, delay_count):
|
for delay in range(0, delay_count):
|
||||||
speed_model = raw_data[loc]
|
speed_model = raw_data[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):]
|
|
||||||
|
|
||||||
# remove properties from the model
|
|
||||||
speed_model_properties = extract_properties(
|
|
||||||
slice, site_name, delay_btype_orig, properties,
|
|
||||||
speed_model_clean)
|
|
||||||
if speed_model_properties is not None:
|
|
||||||
for prop in speed_model_properties:
|
|
||||||
# properties values in the model always follow properties name
|
|
||||||
prop_string = "_".join(
|
|
||||||
[prop, speed_model_properties[prop]])
|
|
||||||
speed_model_clean = remove_pin_from_model(
|
|
||||||
prop_string.lower(), speed_model_clean)
|
|
||||||
|
|
||||||
# Get pin alias map
|
|
||||||
pin_aliases = pin_alias_map.get(delay_btype, None)
|
|
||||||
|
|
||||||
# locate pins
|
|
||||||
for pin in pins[slice][site_name][delay_btype_orig]:
|
|
||||||
orig_pin = pin
|
|
||||||
pim, pin = pin_in_model(
|
|
||||||
pin.lower(), pin_aliases, speed_model_clean,
|
|
||||||
'in')
|
|
||||||
|
|
||||||
if pim:
|
|
||||||
if pins[slice][site_name][delay_btype_orig][
|
|
||||||
orig_pin]['is_clock']:
|
|
||||||
bel_clock = pin
|
|
||||||
bel_clock_orig_pin = orig_pin
|
|
||||||
elif pins[slice][site_name][delay_btype_orig][
|
|
||||||
orig_pin]['direction'] == 'IN':
|
|
||||||
bel_input = pin
|
|
||||||
elif pins[slice][site_name][delay_btype_orig][
|
|
||||||
orig_pin]['direction'] == 'OUT':
|
|
||||||
bel_output = 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_clock is None:
|
|
||||||
for pin in site_pins[slice][site_name.lower()]:
|
|
||||||
orig_pin = pin
|
|
||||||
pim, pin = pin_in_model(
|
|
||||||
pin.lower(), pin_aliases,
|
|
||||||
speed_model_clean)
|
|
||||||
if pim:
|
|
||||||
if site_pins[slice][site_name.lower(
|
|
||||||
)][orig_pin]['is_clock']:
|
|
||||||
bel_clock = pin
|
|
||||||
bel_clock_orig_pin = orig_pin
|
|
||||||
speed_model_clean = remove_pin_from_model(
|
|
||||||
pin.lower(), speed_model_clean)
|
|
||||||
|
|
||||||
if bel_input is None:
|
|
||||||
# search site inputs
|
|
||||||
for pin in site_pins[slice][site_name.lower()]:
|
|
||||||
orig_pin = pin
|
|
||||||
pim, pin = pin_in_model(
|
|
||||||
pin.lower(), pin_aliases,
|
|
||||||
speed_model_clean, 'in')
|
|
||||||
if pim:
|
|
||||||
if site_pins[slice][site_name.lower(
|
|
||||||
)][orig_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()]:
|
|
||||||
orig_pin = pin
|
|
||||||
pim, pin = pin_in_model(
|
|
||||||
pin.lower(), pin_aliases,
|
|
||||||
speed_model_clean)
|
|
||||||
if pim:
|
|
||||||
if site_pins[slice][site_name.lower(
|
|
||||||
)][orig_pin]['direction'] == 'OUT':
|
|
||||||
bel_output = pin
|
|
||||||
speed_model_clean = remove_pin_from_model(
|
|
||||||
pin.lower(), speed_model_clean)
|
|
||||||
|
|
||||||
# if we couldn't find input, check if the clock is the
|
|
||||||
# only input. This applies only to combinational paths
|
|
||||||
if (sequential is None) and (bel_input is None) and (
|
|
||||||
bel_clock is not None):
|
|
||||||
if bel_clock_orig_pin in site_pins[slice][site_name.lower()] and \
|
|
||||||
site_pins[slice][site_name.lower(
|
|
||||||
)][bel_clock_orig_pin]['direction'] == 'IN':
|
|
||||||
bel_input = bel_clock
|
|
||||||
|
|
||||||
# if we still don't have the input check if the input
|
|
||||||
# is wider than 1 bit and timing defined for the whole
|
|
||||||
# port
|
|
||||||
import re
|
|
||||||
if (bel_input is None) or (bel_output is None):
|
|
||||||
for pin in pins[slice][site_name][
|
|
||||||
delay_btype_orig]:
|
|
||||||
number = re.search(r'\d+$', pin)
|
|
||||||
if number is not None:
|
|
||||||
orig_pin = pin[:-(
|
|
||||||
len(str(number.group())))]
|
|
||||||
orig_pin_full = pin
|
|
||||||
pim, pin = pin_in_model(
|
|
||||||
orig_pin.lower(), pin_aliases,
|
|
||||||
speed_model_clean)
|
|
||||||
if not pim:
|
|
||||||
# some inputs pins are named with unsignificant zeros
|
|
||||||
# remove ti and try again
|
|
||||||
orig_pin = orig_pin + str(
|
|
||||||
int(number.group()))
|
|
||||||
pim, pin = pin_in_model(
|
|
||||||
orig_pin.lower(), pin_aliases,
|
|
||||||
speed_model_clean)
|
|
||||||
|
|
||||||
if pim:
|
|
||||||
if pins[slice][site_name][delay_btype_orig][orig_pin_full]['direction'] == 'IN' \
|
|
||||||
and bel_input is None:
|
|
||||||
bel_input = pin
|
|
||||||
if pins[slice][site_name][delay_btype_orig][orig_pin_full]['direction'] == 'OUT' \
|
|
||||||
and bel_output is None:
|
|
||||||
bel_output = pin
|
|
||||||
speed_model_clean = remove_pin_from_model(
|
|
||||||
orig_pin.lower(),
|
|
||||||
speed_model_clean)
|
|
||||||
|
|
||||||
# check if the input is not a BEL property
|
|
||||||
if bel_input is None:
|
|
||||||
# if there is anything not yet decoded
|
|
||||||
if len(speed_model_clean.split("_")) > 1:
|
|
||||||
if len(speed_model_properties.keys()) == 1:
|
|
||||||
bel_input = list(
|
|
||||||
speed_model_properties.keys())[0]
|
|
||||||
|
|
||||||
# if we still don't have input, give up
|
|
||||||
if bel_input is None:
|
|
||||||
loc += 6
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 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 or \
|
|
||||||
bel_output is None and bel_clock == bel_input:
|
|
||||||
loc += 6
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
if bel_input is None or bel_output is None:
|
|
||||||
loc += 6
|
|
||||||
continue
|
|
||||||
|
|
||||||
delay_btype = speed_model
|
|
||||||
# add properties to the delay_btype
|
|
||||||
for prop in sorted(speed_model_properties):
|
|
||||||
prop_string = "_".join(
|
|
||||||
[prop, speed_model_properties[prop]])
|
|
||||||
delay_btype += "_" + prop_string
|
|
||||||
extra_ports = None
|
|
||||||
|
|
||||||
if slice not in timings:
|
|
||||||
timings[slice] = dict()
|
|
||||||
|
|
||||||
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
|
# each timing entry reports 5 delays
|
||||||
for d in range(0, 5):
|
timing = [
|
||||||
(t, v) = raw_data[d + 1 + loc].split(':')
|
raw_data[d + 1 + loc].split(':')
|
||||||
timings[slice][bel_location][delay_btype][
|
for d in range(0, 5)
|
||||||
speed_model_orig][t] = v
|
]
|
||||||
|
|
||||||
|
yield slice, site_name, bel, speed_model, timing
|
||||||
|
|
||||||
# 5 delay values + name
|
# 5 delay values + name
|
||||||
loc += 6
|
loc += 6
|
||||||
return timings
|
|
||||||
|
|
||||||
|
def read_raw_timings(fin, properties, pins, site_pins, pin_alias_map):
|
||||||
|
def inner():
|
||||||
|
raw = list(parse_raw_timing(fin))
|
||||||
|
|
||||||
|
pin_in_models = {}
|
||||||
|
|
||||||
|
for slice, site_name, bel, speed_model, timing in raw:
|
||||||
|
btype = bel.lower()
|
||||||
|
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):]
|
||||||
|
|
||||||
|
# remove properties from the model
|
||||||
|
speed_model_properties = extract_properties(
|
||||||
|
slice, site_name, delay_btype_orig, properties,
|
||||||
|
speed_model_clean)
|
||||||
|
if speed_model_properties is not None:
|
||||||
|
for prop in speed_model_properties:
|
||||||
|
# properties values in the model always follow properties name
|
||||||
|
prop_string = "_".join(
|
||||||
|
[prop, speed_model_properties[prop]])
|
||||||
|
speed_model_clean = remove_pin_from_model(
|
||||||
|
prop_string.lower(), speed_model_clean)
|
||||||
|
|
||||||
|
# Get pin alias map
|
||||||
|
if delay_btype not in pin_in_models:
|
||||||
|
pin_aliases = pin_alias_map.get(delay_btype, None)
|
||||||
|
pin_in_models[delay_btype] = create_pin_in_model(pin_aliases)
|
||||||
|
|
||||||
|
pin_in_model = pin_in_models[delay_btype]
|
||||||
|
|
||||||
|
# locate pins
|
||||||
|
for pin in pins[slice][site_name][delay_btype_orig]:
|
||||||
|
orig_pin = pin
|
||||||
|
pim, pin = pin_in_model(pin.lower(), speed_model_clean, 'in')
|
||||||
|
|
||||||
|
if pim:
|
||||||
|
if pins[slice][site_name][delay_btype_orig][orig_pin][
|
||||||
|
'is_clock'] and not pins[slice][site_name][
|
||||||
|
delay_btype_orig][orig_pin]['is_part_of_bus']:
|
||||||
|
bel_clock = pin
|
||||||
|
bel_clock_orig_pin = orig_pin
|
||||||
|
elif pins[slice][site_name][delay_btype_orig][orig_pin][
|
||||||
|
'direction'] == 'IN':
|
||||||
|
bel_input = pin
|
||||||
|
elif pins[slice][site_name][delay_btype_orig][orig_pin][
|
||||||
|
'direction'] == 'OUT':
|
||||||
|
bel_output = 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_clock is None:
|
||||||
|
for pin in site_pins[slice][site_name.lower()]:
|
||||||
|
orig_pin = pin
|
||||||
|
pim, pin = pin_in_model(pin.lower(), speed_model_clean)
|
||||||
|
if pim:
|
||||||
|
if site_pins[slice][site_name.lower(
|
||||||
|
)][orig_pin]['is_clock'] and not site_pins[slice][
|
||||||
|
site_name.lower()][orig_pin]['is_part_of_bus']:
|
||||||
|
bel_clock = pin
|
||||||
|
bel_clock_orig_pin = orig_pin
|
||||||
|
speed_model_clean = remove_pin_from_model(
|
||||||
|
pin.lower(), speed_model_clean)
|
||||||
|
|
||||||
|
if bel_input is None:
|
||||||
|
# search site inputs
|
||||||
|
for pin in site_pins[slice][site_name.lower()]:
|
||||||
|
orig_pin = pin
|
||||||
|
pim, pin = pin_in_model(
|
||||||
|
pin.lower(), speed_model_clean, 'in')
|
||||||
|
if pim:
|
||||||
|
if site_pins[slice][site_name.lower(
|
||||||
|
)][orig_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()]:
|
||||||
|
orig_pin = pin
|
||||||
|
pim, pin = pin_in_model(pin.lower(), speed_model_clean)
|
||||||
|
if pim:
|
||||||
|
if site_pins[slice][site_name.lower(
|
||||||
|
)][orig_pin]['direction'] == 'OUT':
|
||||||
|
bel_output = pin
|
||||||
|
speed_model_clean = remove_pin_from_model(
|
||||||
|
pin.lower(), speed_model_clean)
|
||||||
|
|
||||||
|
# if we couldn't find input, check if the clock is the
|
||||||
|
# only input. This applies only to combinational paths
|
||||||
|
if (sequential is None) and (bel_input is None) and (bel_clock is
|
||||||
|
not None):
|
||||||
|
if bel_clock_orig_pin in site_pins[slice][site_name.lower()] and \
|
||||||
|
site_pins[slice][site_name.lower(
|
||||||
|
)][bel_clock_orig_pin]['direction'] == 'IN':
|
||||||
|
bel_input = bel_clock
|
||||||
|
|
||||||
|
# if we still don't have the input check if the input
|
||||||
|
# is wider than 1 bit and timing defined for the whole
|
||||||
|
# port
|
||||||
|
if (bel_input is None) or (bel_output is None):
|
||||||
|
for pin in pins[slice][site_name][delay_btype_orig]:
|
||||||
|
number = NUMBER_RE.search(pin)
|
||||||
|
if number is not None:
|
||||||
|
orig_pin = pin[:-(len(str(number.group())))]
|
||||||
|
orig_pin_full = pin
|
||||||
|
pim, pin = pin_in_model(
|
||||||
|
orig_pin.lower(), speed_model_clean)
|
||||||
|
if not pim:
|
||||||
|
# some inputs pins are named with unsignificant zeros
|
||||||
|
# remove ti and try again
|
||||||
|
orig_pin = orig_pin + str(int(number.group()))
|
||||||
|
pim, pin = pin_in_model(
|
||||||
|
orig_pin.lower(), speed_model_clean)
|
||||||
|
|
||||||
|
if pim:
|
||||||
|
if pins[slice][site_name][delay_btype_orig][orig_pin_full]['direction'] == 'IN' \
|
||||||
|
and bel_input is None:
|
||||||
|
bel_input = pin
|
||||||
|
if pins[slice][site_name][delay_btype_orig][orig_pin_full]['direction'] == 'OUT' \
|
||||||
|
and bel_output is None:
|
||||||
|
bel_output = pin
|
||||||
|
speed_model_clean = remove_pin_from_model(
|
||||||
|
orig_pin.lower(), speed_model_clean)
|
||||||
|
|
||||||
|
# check if the input is not a BEL property
|
||||||
|
if bel_input is None:
|
||||||
|
# if there is anything not yet decoded
|
||||||
|
if len(speed_model_clean.split("_")) > 1:
|
||||||
|
if len(speed_model_properties.keys()) == 1:
|
||||||
|
bel_input = list(speed_model_properties.keys())[0]
|
||||||
|
|
||||||
|
# if we still don't have input, give up
|
||||||
|
if bel_input is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# restore speed model name
|
||||||
|
speed_model = delay_btype + speed_model_clean
|
||||||
|
|
||||||
|
if sequential is not None:
|
||||||
|
if bel_clock is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if bel_output is None and bel_clock is None or \
|
||||||
|
bel_output is None and bel_clock == bel_input:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
if bel_input is None or bel_output is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
delay_btype = speed_model
|
||||||
|
# add properties to the delay_btype
|
||||||
|
if speed_model_properties is not None:
|
||||||
|
for prop in sorted(speed_model_properties):
|
||||||
|
prop_string = "_".join(
|
||||||
|
[prop, speed_model_properties[prop]])
|
||||||
|
delay_btype += "_" + prop_string
|
||||||
|
|
||||||
|
yield (slice, bel_location, delay_btype, speed_model_orig,
|
||||||
|
'type'), btype.upper()
|
||||||
|
yield (
|
||||||
|
slice, bel_location, delay_btype, speed_model_orig,
|
||||||
|
'input'), bel_input.upper()
|
||||||
|
|
||||||
|
if bel_output is not None:
|
||||||
|
yield (
|
||||||
|
slice, bel_location, delay_btype, speed_model_orig,
|
||||||
|
'output'), bel_output.upper()
|
||||||
|
|
||||||
|
if bel_clock is not None:
|
||||||
|
yield (
|
||||||
|
slice, bel_location, delay_btype, speed_model_orig,
|
||||||
|
'clock'), bel_clock.upper()
|
||||||
|
|
||||||
|
yield (
|
||||||
|
slice, bel_location, delay_btype, speed_model_orig,
|
||||||
|
'location'), bel_location.upper()
|
||||||
|
|
||||||
|
#XXX: debug
|
||||||
|
yield (
|
||||||
|
slice, bel_location, delay_btype, speed_model_orig,
|
||||||
|
'model'), speed_model_orig
|
||||||
|
|
||||||
|
if sequential is not None:
|
||||||
|
assert bel_clock is not None, (
|
||||||
|
slice, bel_location, delay_btype, speed_model_orig)
|
||||||
|
yield (
|
||||||
|
slice, bel_location, delay_btype, speed_model_orig,
|
||||||
|
'sequential'), sequential[1]
|
||||||
|
|
||||||
|
for t, v in timing:
|
||||||
|
yield (
|
||||||
|
slice, bel_location, delay_btype, speed_model_orig, t), v
|
||||||
|
|
||||||
|
return merged_dict(inner())
|
||||||
|
|
||||||
|
|
||||||
def read_bel_properties(properties_file, properties_map):
|
def read_bel_properties(properties_file, properties_map):
|
||||||
|
def inner():
|
||||||
|
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 = dict()
|
if sites_count == 0:
|
||||||
with open(properties_file, 'r') as f:
|
yield (tile, ), {}
|
||||||
for line in f:
|
|
||||||
raw_props = line.split()
|
for site in range(0, sites_count):
|
||||||
tile = raw_props[0]
|
site_name = raw_props[prop_loc]
|
||||||
sites_count = int(raw_props[1])
|
bels_count = int(raw_props[prop_loc + 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
|
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]
|
|
||||||
# append name prop name mappings
|
|
||||||
if bel_name in properties_map:
|
|
||||||
if prop_name in properties_map[bel_name]:
|
|
||||||
prop_name = properties_map[bel_name][prop_name]
|
|
||||||
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
|
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])
|
||||||
|
|
||||||
|
props = 0
|
||||||
|
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
|
||||||
|
if prop_name.startswith(
|
||||||
|
'CONFIG.') and prop_name.endswith(
|
||||||
|
'.VALUES'):
|
||||||
|
prop_name = prop_name[7:-7]
|
||||||
|
|
||||||
|
prop_values_count = int(raw_props[prop_loc + 1])
|
||||||
|
|
||||||
|
if prop_name not in [
|
||||||
|
'RAM_MODE',
|
||||||
|
'WRITE_WIDTH_A',
|
||||||
|
'WRITE_WIDTH_B',
|
||||||
|
'READ_WIDTH_A',
|
||||||
|
'READ_WIDTH_B',
|
||||||
|
]:
|
||||||
|
if bel_name in properties_map:
|
||||||
|
if prop_name in properties_map[bel_name]:
|
||||||
|
prop_name = properties_map[bel_name][
|
||||||
|
prop_name]
|
||||||
|
|
||||||
|
yield (tile, site_name, bel_name, prop_name), \
|
||||||
|
raw_props[prop_loc + 2:prop_loc + 2 +
|
||||||
|
prop_values_count]
|
||||||
|
props += 1
|
||||||
|
|
||||||
|
prop_loc += 2 + prop_values_count
|
||||||
|
|
||||||
|
if props == 0:
|
||||||
|
yield (tile, site_name, bel_name), {}
|
||||||
|
|
||||||
|
return merged_dict(inner())
|
||||||
|
|
||||||
|
|
||||||
def read_bel_pins(pins_file):
|
def read_bel_pins(pins_file):
|
||||||
|
def inner():
|
||||||
|
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 = dict()
|
if sites_count == 0:
|
||||||
with open(pins_file, 'r') as f:
|
yield (tile, ), {}
|
||||||
for line in f:
|
|
||||||
raw_pins = line.split()
|
for site in range(0, sites_count):
|
||||||
tile = raw_pins[0]
|
site_name = raw_pins[pin_loc]
|
||||||
sites_count = int(raw_pins[1])
|
bels_count = int(raw_pins[pin_loc + 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
|
pin_loc += 2
|
||||||
for pin in range(0, bel_pins_count):
|
|
||||||
pin_name = raw_pins[pin_loc]
|
for bel in range(0, bels_count):
|
||||||
pin_direction = raw_pins[pin_loc + 1]
|
bel_name = raw_pins[pin_loc]
|
||||||
pin_is_clock = raw_pins[pin_loc + 2]
|
bel_name = clean_bname(bel_name)
|
||||||
pins[tile][site_name][bel_name][pin_name] = dict()
|
bel_name = bel_name.lower()
|
||||||
pins[tile][site_name][bel_name][pin_name][
|
bel_pins_count = int(raw_pins[pin_loc + 1])
|
||||||
'direction'] = pin_direction
|
|
||||||
pins[tile][site_name][bel_name][pin_name][
|
pin_loc += 2
|
||||||
'is_clock'] = int(pin_is_clock) == 1
|
for pin in range(0, bel_pins_count):
|
||||||
pin_loc += 3
|
pin_name = raw_pins[pin_loc]
|
||||||
return pins
|
pin_direction = raw_pins[pin_loc + 1]
|
||||||
|
pin_is_clock = raw_pins[pin_loc + 2]
|
||||||
|
pin_is_part_of_bus = raw_pins[pin_loc + 3]
|
||||||
|
|
||||||
|
yield (
|
||||||
|
tile, site_name, bel_name, pin_name,
|
||||||
|
'direction'), pin_direction
|
||||||
|
yield (
|
||||||
|
tile, site_name, bel_name, pin_name,
|
||||||
|
'is_clock'), int(pin_is_clock) == 1
|
||||||
|
yield (
|
||||||
|
tile, site_name, bel_name, pin_name,
|
||||||
|
'is_part_of_bus'
|
||||||
|
), int(pin_is_part_of_bus) == 1
|
||||||
|
pin_loc += 4
|
||||||
|
|
||||||
|
return merged_dict(inner())
|
||||||
|
|
||||||
|
|
||||||
def read_site_pins(pins_file):
|
def read_site_pins(pins_file):
|
||||||
|
def inner():
|
||||||
|
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
|
||||||
|
|
||||||
|
if site_count == 0:
|
||||||
|
yield (tile, ), {}
|
||||||
|
|
||||||
|
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 = 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
|
pin_loc += 2
|
||||||
return pins
|
for pin in range(0, site_pins_count):
|
||||||
|
pin_name = raw_pins[pin_loc]
|
||||||
|
pin_direction = raw_pins[pin_loc + 1]
|
||||||
|
pin_is_part_of_bus = raw_pins[pin_loc + 2]
|
||||||
|
|
||||||
|
yield (
|
||||||
|
(tile, site_name, pin_name, 'direction'),
|
||||||
|
pin_direction)
|
||||||
|
yield (
|
||||||
|
(tile, site_name, pin_name, 'is_clock'),
|
||||||
|
pin_name.lower() == 'clk')
|
||||||
|
yield (
|
||||||
|
(tile, site_name, pin_name, 'is_part_of_bus'),
|
||||||
|
int(pin_is_part_of_bus))
|
||||||
|
|
||||||
|
# site clock pins are always named 'CLK'
|
||||||
|
pin_loc += 3
|
||||||
|
|
||||||
|
return merged_dict(inner())
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
-e third_party/fasm
|
-e third_party/fasm
|
||||||
|
-e third_party/python-sdf-timing
|
||||||
intervaltree
|
intervaltree
|
||||||
junit-xml
|
junit-xml
|
||||||
numpy
|
numpy
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue