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 database: build/segbits_clk_hrow.db
build/segbits_clk_hrow.rdb: $(SPECIMENS_OK) 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 build/segbits_clk_hrow.db: build/segbits_clk_hrow.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_clk_hrow.rdb \ --seg-fn-in build/segbits_clk_hrow.rdb \
--seg-fn-out build/segbits_clk_hrow.db --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 pushdb: database
${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow.db ${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']) row['site'], '{}.INIT_OUT'.format(base_name), row['INIT_OUT'])
segmk.add_site_tag( 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 # SYNC is a zero pattern
for opt in ['ASYNC']: for opt in ['ASYNC']:

View File

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

View File

@ -1,30 +1,34 @@
HCLKS = 24 HCLKS = 24
GCLKS = 32 GCLKS = 32
SIDE_CLK_INPUTS = 14 SIDE_CLK_INPUTS = 14
CLK_TABLE = {}
CLK_TABLE_NUM_ROWS = 8 CLK_TABLE_NUM_ROWS = 8
CLK_TABLE_NUM_COLS = 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): def get_clk_table():
CLK_TABLE['CLK_HROW_CK_IN_L{}'.format(row)] = (row, 4) clk_table = {}
for row in range(6): for gclk in range(GCLKS):
CLK_TABLE['CLK_HROW_CK_IN_L{}'.format(row + 8)] = (row, 5) 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): for row in range(8):
CLK_TABLE['CLK_HROW_CK_IN_R{}'.format(row)] = (row, 6) clk_table['CLK_HROW_CK_IN_L{}'.format(row)] = (row, 4)
for row in range(6): for row in range(6):
CLK_TABLE['CLK_HROW_CK_IN_R{}'.format(row + 8)] = (row, 7) 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 for row in range(8):
# present on a particular HROW. clk_table['CLK_HROW_CK_IN_R{}'.format(row)] = (row, 6)
for y in range(2): for row in range(6):
for x in range(2): clk_table['CLK_HROW_CK_IN_R{}'.format(row + 8)] = (row, 7)
int_clk_name = 'CLK_HROW_CK_INT_{}_{}'.format(x, y)
CLK_TABLE[int_clk_name] = (y + 6, 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(): def main():
segmk = Segmaker("design.bits") segmk = Segmaker("design.bits")
table = clk_table.get_clk_table()
print("Loading tags from design.txt.") print("Loading tags from design.txt.")
with open("design.txt", "r") as f: with open("design.txt", "r") as f:
@ -24,8 +25,8 @@ def main():
rows = set(range(clk_table.CLK_TABLE_NUM_ROWS)) rows = set(range(clk_table.CLK_TABLE_NUM_ROWS))
columns = set(range(clk_table.CLK_TABLE_NUM_COLS)) columns = set(range(clk_table.CLK_TABLE_NUM_COLS))
if src in clk_table.CLK_TABLE: if src in table:
row, column = clk_table.CLK_TABLE[src] row, column = table[src]
segmk.add_tile_tag( segmk.add_tile_tag(
tile, '{}.HCLK_ENABLE_ROW{}'.format(dst, row), 1) tile, '{}.HCLK_ENABLE_ROW{}'.format(dst, row), 1)

View File

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

View File

@ -1,27 +1,11 @@
""" Emits top.v's for various BUFHCE routing inputs. """
import os import os
import re
import random import random
random.seed(int(os.getenv("SEED"), 16)) random.seed(int(os.getenv("SEED"), 16))
from prjxray import util from prjxray import util
from prjxray.db import Database from prjxray.db import Database
XY_RE = re.compile('^BUFHCE_X([0-9]+)Y([0-9]+)$') CMT_XY_FUN = util.create_xy_fun(prefix='')
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
def gen_sites(desired_site_type): def gen_sites(desired_site_type):
@ -53,6 +37,7 @@ def gen_bufhce_sites():
def read_site_to_cmt(): def read_site_to_cmt():
""" Yields clock sources and which CMT they route within. """
with open(os.path.join(os.getenv('FUZDIR'), 'build', with open(os.path.join(os.getenv('FUZDIR'), 'build',
'cmt_regions.csv')) as f: 'cmt_regions.csv')) as f:
for l in f: for l in f:
@ -60,10 +45,15 @@ def read_site_to_cmt():
yield (site, cmt) yield (site, cmt)
CMT_RE = re.compile('X([0-9]+)Y([0-9]+)')
class ClockSources(object): 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): def __init__(self):
self.sources = {} self.sources = {}
self.merged_sources = {} self.merged_sources = {}
@ -71,6 +61,10 @@ class ClockSources(object):
self.used_sources_from_cmt = {} self.used_sources_from_cmt = {}
def add_clock_source(self, source, 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: if cmt not in self.sources:
self.sources[cmt] = [] self.sources[cmt] = []
@ -80,6 +74,12 @@ class ClockSources(object):
self.source_to_cmt[source] = cmt self.source_to_cmt[source] = cmt
def get_random_source(self, 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: if cmt not in self.merged_sources:
choices = [] choices = []
if 'ANY' in self.sources: if 'ANY' in self.sources:
@ -88,9 +88,7 @@ class ClockSources(object):
if cmt in self.sources: if cmt in self.sources:
choices.extend(self.sources[cmt]) choices.extend(self.sources[cmt])
m = CMT_RE.match(cmt) x, y = CMT_XY_FUN(cmt)
x = int(m.group(1))
y = int(m.group(2))
if x % 2 == 0: if x % 2 == 0:
x += 1 x += 1
@ -123,17 +121,35 @@ class ClockSources(object):
def check_allowed(mmcm_pll_dir, cmt): 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': if mmcm_pll_dir == 'BOTH':
return True return True
elif mmcm_pll_dir == 'ODD': 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': 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: else:
assert False, mmcm_pll_dir assert False, mmcm_pll_dir
def main(): def main():
"""
BUFHCE's can be driven from:
MMCME2_ADV
PLLE2_ADV
BUFGCTRL
Local INT connect
"""
print(''' print('''
module top(); module top();
''') ''')
@ -142,6 +158,9 @@ module top();
clock_sources = ClockSources() 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_only = random.randint(0, 1)
mmcm_pll_dir = random.choice(('ODD', 'EVEN', 'BOTH')) mmcm_pll_dir = random.choice(('ODD', 'EVEN', 'BOTH'))
@ -154,20 +173,6 @@ module top();
wire zero = 0; wire zero = 0;
wire one = 1;""") 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'): for site in gen_sites('MMCME2_ADV'):
mmcm_clocks = [ mmcm_clocks = [
'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx) 'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx)
@ -250,7 +255,8 @@ module top();
c5=pll_clocks[5], 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) wire_name = 'clk_{}'.format(site)
if not mmcm_pll_only: if not mmcm_pll_only:
@ -268,8 +274,7 @@ module top();
wire_name=wire_name, wire_name=wire_name,
)) ))
bufhce_sites = list(gen_bufhce_sites()) for tile_name, sites in gen_bufhce_sites():
for tile_name, sites in bufhce_sites:
for site in sites: for site in sites:
wire_name = clock_sources.get_random_source(site_to_cmt[site]) wire_name = clock_sources.get_random_source(site_to_cmt[site])
if wire_name is None: if wire_name is None:

View File

@ -22,6 +22,41 @@ def roi_xy():
return (x1, x2), (y1, y2) 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(): def slice_xy():
'''Return (X1, X2), (Y1, Y2) from XRAY_ROI, exclusive end (for xrange)''' '''Return (X1, X2), (Y1, Y2) from XRAY_ROI, exclusive end (for xrange)'''
# SLICE_X12Y100:SLICE_X27Y149 # SLICE_X12Y100:SLICE_X27Y149