mirror of https://github.com/openXC7/prjxray.git
Address review comments.
Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
parent
d2c9c96b96
commit
ca232e4e81
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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']:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue