Address review comments.

Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
Keith Rothman 2019-02-12 14:06:45 -08:00
parent d2c9c96b96
commit ca232e4e81
8 changed files with 124 additions and 79 deletions

View File

@ -5,13 +5,17 @@ include ../fuzzer.mk
database: build/segbits_clk_hrow.db
build/segbits_clk_hrow.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -o build/segbits_clk_hrow.rdb $(addsuffix /segdata_clk_hrow_top_r.txt,$(SPECIMENS)) $(addsuffix /segdata_clk_hrow_bot_r.txt,$(SPECIMENS))
${XRAY_SEGMATCH} -o build/segbits_clk_hrow.rdb \
$(addsuffix /segdata_clk_hrow_top_r.txt,$(SPECIMENS)) \
$(addsuffix /segdata_clk_hrow_bot_r.txt,$(SPECIMENS))
build/segbits_clk_hrow.db: build/segbits_clk_hrow.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_clk_hrow.rdb \
--seg-fn-out build/segbits_clk_hrow.db
${XRAY_MASKMERGE} build/mask_clk_hrow.db $(addsuffix /segdata_clk_hrow_top_r.txt,$(SPECIMENS)) $(addsuffix /segdata_clk_hrow_bot_r.txt,$(SPECIMENS))
${XRAY_MASKMERGE} build/mask_clk_hrow.db \
$(addsuffix /segdata_clk_hrow_top_r.txt,$(SPECIMENS)) \
$(addsuffix /segdata_clk_hrow_bot_r.txt,$(SPECIMENS))
pushdb: database
${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow.db

View File

@ -25,7 +25,8 @@ def main():
row['site'], '{}.INIT_OUT'.format(base_name), row['INIT_OUT'])
segmk.add_site_tag(
row['site'], '{}.ZINV_CE'.format(base_name), 1 ^ row['IS_CE_INVERTED'])
row['site'], '{}.ZINV_CE'.format(base_name),
1 ^ row['IS_CE_INVERTED'])
# SYNC is a zero pattern
for opt in ['ASYNC']:

View File

@ -1,18 +1,14 @@
import json
import os
import re
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray import verilog
from prjxray.db import Database
XY_RE = re.compile('^BUFHCE_X([0-9]+)Y([0-9]+)$')
def gen_sites():
db = Database(util.get_db_root())
grid = db.grid()
get_xy = util.create_xy_fun('BUFHCE_')
db = Database(util.get_db_root())
grid = db.grid()
for tile_name in sorted(grid.tiles()):
@ -24,10 +20,7 @@ def gen_sites():
ys = []
for site, site_type in gridinfo.sites.items():
if site_type == 'BUFHCE':
m = re.match(XY_RE, site)
assert m, site
x = int(m.group(1))
y = int(m.group(2))
x, y = get_xy(site)
xs.append(x)
ys.append(y)

View File

@ -1,30 +1,34 @@
HCLKS = 24
GCLKS = 32
SIDE_CLK_INPUTS = 14
CLK_TABLE = {}
CLK_TABLE_NUM_ROWS = 8
CLK_TABLE_NUM_COLS = 8
for gclk in range(GCLKS):
gclk_name = 'CLK_HROW_R_CK_GCLK{}'.format(gclk)
row = gclk % CLK_TABLE_NUM_ROWS
column = int(gclk / CLK_TABLE_NUM_ROWS)
CLK_TABLE[gclk_name] = (row, column)
for row in range(8):
CLK_TABLE['CLK_HROW_CK_IN_L{}'.format(row)] = (row, 4)
for row in range(6):
CLK_TABLE['CLK_HROW_CK_IN_L{}'.format(row + 8)] = (row, 5)
def get_clk_table():
clk_table = {}
for gclk in range(GCLKS):
gclk_name = 'CLK_HROW_R_CK_GCLK{}'.format(gclk)
row = gclk % CLK_TABLE_NUM_ROWS
column = int(gclk / CLK_TABLE_NUM_ROWS)
clk_table[gclk_name] = (row, column)
for row in range(8):
CLK_TABLE['CLK_HROW_CK_IN_R{}'.format(row)] = (row, 6)
for row in range(6):
CLK_TABLE['CLK_HROW_CK_IN_R{}'.format(row + 8)] = (row, 7)
for row in range(8):
clk_table['CLK_HROW_CK_IN_L{}'.format(row)] = (row, 4)
for row in range(6):
clk_table['CLK_HROW_CK_IN_L{}'.format(row + 8)] = (row, 5)
# HROW_CK_INT_<X>_<Y>, Y == Y share the same bits, and only X = 0 or X = 1 are
# present on a particular HROW.
for y in range(2):
for x in range(2):
int_clk_name = 'CLK_HROW_CK_INT_{}_{}'.format(x, y)
CLK_TABLE[int_clk_name] = (y + 6, 7)
for row in range(8):
clk_table['CLK_HROW_CK_IN_R{}'.format(row)] = (row, 6)
for row in range(6):
clk_table['CLK_HROW_CK_IN_R{}'.format(row + 8)] = (row, 7)
# HROW_CK_INT_<X>_<Y>, Y == Y share the same bits, and only X = 0 or X = 1
# are present on a particular HROW.
for y in range(2):
for x in range(2):
int_clk_name = 'CLK_HROW_CK_INT_{}_{}'.format(x, y)
clk_table[int_clk_name] = (y + 6, 7)
return clk_table

View File

@ -6,6 +6,7 @@ import clk_table
def main():
segmk = Segmaker("design.bits")
table = clk_table.get_clk_table()
print("Loading tags from design.txt.")
with open("design.txt", "r") as f:
@ -24,8 +25,8 @@ def main():
rows = set(range(clk_table.CLK_TABLE_NUM_ROWS))
columns = set(range(clk_table.CLK_TABLE_NUM_COLS))
if src in clk_table.CLK_TABLE:
row, column = clk_table.CLK_TABLE[src]
if src in table:
row, column = table[src]
segmk.add_tile_tag(
tile, '{}.HCLK_ENABLE_ROW{}'.format(dst, row), 1)

View File

@ -50,13 +50,15 @@ def main():
piplists[dst].append(src)
table = clk_table.get_clk_table()
with open(args.out_segbit, 'w') as f:
for dst in sorted(hrow_outs):
for src in sorted(piplists[dst]):
if src not in clk_table.CLK_TABLE:
if src not in table:
continue
row, column = clk_table.CLK_TABLE[src]
row, column = table[src]
if row not in hrow_outs[dst]['rows']:
continue

View File

@ -1,27 +1,11 @@
""" Emits top.v's for various BUFHCE routing inputs. """
import os
import re
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray.db import Database
XY_RE = re.compile('^BUFHCE_X([0-9]+)Y([0-9]+)$')
BUFGCTRL_XY_RE = re.compile('^BUFGCTRL_X([0-9]+)Y([0-9]+)$')
"""
BUFHCE's can be driven from:
MMCME2_ADV
BUFHCE
PLLE2_ADV
BUFGCTRL
"""
def get_xy(s):
m = BUFGCTRL_XY_RE.match(s)
x = int(m.group(1))
y = int(m.group(2))
return x, y
CMT_XY_FUN = util.create_xy_fun(prefix='')
def gen_sites(desired_site_type):
@ -53,6 +37,7 @@ def gen_bufhce_sites():
def read_site_to_cmt():
""" Yields clock sources and which CMT they route within. """
with open(os.path.join(os.getenv('FUZDIR'), 'build',
'cmt_regions.csv')) as f:
for l in f:
@ -60,10 +45,15 @@ def read_site_to_cmt():
yield (site, cmt)
CMT_RE = re.compile('X([0-9]+)Y([0-9]+)')
class ClockSources(object):
""" Class for tracking clock sources.
Some clock sources can be routed to any CMT, for these, cmt='ANY'.
For clock sources that belong to a CMT, cmt should be set to the CMT of
the source.
"""
def __init__(self):
self.sources = {}
self.merged_sources = {}
@ -71,6 +61,10 @@ class ClockSources(object):
self.used_sources_from_cmt = {}
def add_clock_source(self, source, cmt):
""" Adds a source from a specific CMT.
cmt='ANY' indicates that this source can be routed to any CMT.
"""
if cmt not in self.sources:
self.sources[cmt] = []
@ -80,6 +74,12 @@ class ClockSources(object):
self.source_to_cmt[source] = cmt
def get_random_source(self, cmt):
""" Get a random source that is routable to the specific CMT.
get_random_source will return a source that is either cmt='ANY',
cmt equal to the input CMT, or the adjecent CMT.
"""
if cmt not in self.merged_sources:
choices = []
if 'ANY' in self.sources:
@ -88,9 +88,7 @@ class ClockSources(object):
if cmt in self.sources:
choices.extend(self.sources[cmt])
m = CMT_RE.match(cmt)
x = int(m.group(1))
y = int(m.group(2))
x, y = CMT_XY_FUN(cmt)
if x % 2 == 0:
x += 1
@ -123,17 +121,35 @@ class ClockSources(object):
def check_allowed(mmcm_pll_dir, cmt):
""" Check whether the CMT specified is in the allowed direction.
This function is designed to bias sources to either the left or right
input lines.
"""
if mmcm_pll_dir == 'BOTH':
return True
elif mmcm_pll_dir == 'ODD':
return (int(CMT_RE.match(cmt).group(1)) & 1) == 1
x, y = CMT_XY_FUN(cmt)
return (x & 1) == 1
elif mmcm_pll_dir == 'EVEN':
return (int(CMT_RE.match(cmt).group(1)) & 1) == 0
x, y = CMT_XY_FUN(cmt)
return (x & 1) == 0
else:
assert False, mmcm_pll_dir
def main():
"""
BUFHCE's can be driven from:
MMCME2_ADV
PLLE2_ADV
BUFGCTRL
Local INT connect
"""
print('''
module top();
''')
@ -142,6 +158,9 @@ module top();
clock_sources = ClockSources()
# To ensure that all left or right sources are used, sometimes only MMCM/PLL
# sources are allowed. The force of ODD/EVEN/BOTH further biases the
# clock sources to the left or right column inputs.
mmcm_pll_only = random.randint(0, 1)
mmcm_pll_dir = random.choice(('ODD', 'EVEN', 'BOTH'))
@ -154,20 +173,6 @@ module top();
wire zero = 0;
wire one = 1;""")
for idx in range(1):
wire_name = "lut_wire_{}".format(idx)
#clock_sources.add_clock_source(wire_name, 'ANY')
print(
"""
(* KEEP, DONT_TOUCH *)
wire {wire_name};
LUT6 lut{idx} (
.O({wire_name})
);""".format(
idx=idx,
wire_name=wire_name,
))
for site in gen_sites('MMCME2_ADV'):
mmcm_clocks = [
'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx)
@ -250,7 +255,8 @@ module top();
c5=pll_clocks[5],
))
for site in sorted(gen_sites("BUFGCTRL"), key=get_xy):
for site in sorted(gen_sites("BUFGCTRL"),
key=util.create_xy_fun('BUFGCTRL_')):
wire_name = 'clk_{}'.format(site)
if not mmcm_pll_only:
@ -268,8 +274,7 @@ module top();
wire_name=wire_name,
))
bufhce_sites = list(gen_bufhce_sites())
for tile_name, sites in bufhce_sites:
for tile_name, sites in gen_bufhce_sites():
for site in sites:
wire_name = clock_sources.get_random_source(site_to_cmt[site])
if wire_name is None:

View File

@ -22,6 +22,41 @@ def roi_xy():
return (x1, x2), (y1, y2)
def create_xy_fun(prefix):
""" Create function that extracts X and Y coordinate from a prefixed string
>>> fun = create_xy_fun(prefix='')
>>> fun('X5Y23')
(5, 23)
>>> fun('X0Y0')
(0, 0)
>>> fun('X50Y100')
(50, 100)
>>> fun = create_xy_fun(prefix='SITE_')
>>> fun('SITE_X5Y23')
(5, 23)
>>> fun('SITE_X0Y0')
(0, 0)
>>> fun('SITE_X50Y100')
(50, 100)
"""
compiled_re = re.compile(
'^{prefix}X([0-9]+)Y([0-9]+)$'.format(prefix=prefix))
def get_xy(s):
m = compiled_re.match(s)
assert m, (prefix, s)
x = int(m.group(1))
y = int(m.group(2))
return x, y
return get_xy
def slice_xy():
'''Return (X1, X2), (Y1, Y2) from XRAY_ROI, exclusive end (for xrange)'''
# SLICE_X12Y100:SLICE_X27Y149