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
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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']:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue