mirror of https://github.com/openXC7/prjxray.git
tilegrid iob: generate addresses automatically
Signed-off-by: John McMaster <johndmcmaster@gmail.com>
This commit is contained in:
parent
1eeb359120
commit
b501c10fa2
|
|
@ -20,13 +20,21 @@ build/clb/deltas:
|
||||||
build/bram/deltas:
|
build/bram/deltas:
|
||||||
bash generate.sh build/bram bram
|
bash generate.sh build/bram bram
|
||||||
|
|
||||||
|
# FIXME: review IOB
|
||||||
build/iob/deltas:
|
build/iob/deltas:
|
||||||
bash generate.sh build/iob iob
|
bash generate.sh build/iob iob
|
||||||
|
|
||||||
build/tilegrid.json: generate_full.py build/tilegrid_basic.json build/clb/deltas build/bram/deltas build/iob/deltas
|
build/tilegrid_tdb.json: iob/build/segbits_tilegrid.tdb
|
||||||
|
python3 add_tdb.py --fn-in build/tilegrid_basic.json --fn-out build/tilegrid_tdb.json
|
||||||
|
|
||||||
|
iob/build/segbits_tilegrid.tdb: build/tilegrid_basic.json
|
||||||
|
cd iob && $(MAKE)
|
||||||
|
|
||||||
|
# FIXME: review IOB
|
||||||
|
build/tilegrid.json: generate_full.py build/tilegrid_tdb.json build/clb/deltas build/bram/deltas
|
||||||
cd build && python3 ${FUZDIR}/generate_full.py \
|
cd build && python3 ${FUZDIR}/generate_full.py \
|
||||||
--json-in tilegrid_basic.json --json-out ${BUILD_DIR}/tilegrid.json \
|
--json-in tilegrid_tdb.json --json-out ${BUILD_DIR}/tilegrid.json \
|
||||||
--tiles $(FUZDIR)/build/tiles/tiles.txt */design_*.delta
|
--tiles $(FUZDIR)/build/tiles/tiles.txt {clb,bram}/design_*.delta
|
||||||
|
|
||||||
run:
|
run:
|
||||||
$(MAKE) clean
|
$(MAKE) clean
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from prjxray import util
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
# Copied from generate_full.py
|
||||||
|
def add_tile_bits(tile_db, baseaddr, offset, frames, words, height=None):
|
||||||
|
'''
|
||||||
|
Record data structure geometry for the given tile baseaddr
|
||||||
|
For most tiles there is only one baseaddr, but some like BRAM have multiple
|
||||||
|
Notes on multiple block types:
|
||||||
|
https://github.com/SymbiFlow/prjxray/issues/145
|
||||||
|
'''
|
||||||
|
|
||||||
|
bits = tile_db['bits']
|
||||||
|
block_type = util.addr2btype(baseaddr)
|
||||||
|
|
||||||
|
assert 0 <= offset <= 100, offset
|
||||||
|
assert 1 <= words <= 101
|
||||||
|
assert offset + words <= 101, (
|
||||||
|
tile_db, offset + words, offset, words, block_type)
|
||||||
|
|
||||||
|
assert block_type not in bits
|
||||||
|
block = bits.setdefault(block_type, {})
|
||||||
|
|
||||||
|
# FDRI address
|
||||||
|
block["baseaddr"] = '0x%08X' % baseaddr
|
||||||
|
# Number of frames this entry is sretched across
|
||||||
|
# that is the following FDRI addresses are used: range(baseaddr, baseaddr + frames)
|
||||||
|
block["frames"] = frames
|
||||||
|
|
||||||
|
# Index of first word used within each frame
|
||||||
|
block["offset"] = offset
|
||||||
|
|
||||||
|
# related to words...
|
||||||
|
# deprecated field? Don't worry about for now
|
||||||
|
# DSP has some differences between height and words
|
||||||
|
block["words"] = words
|
||||||
|
if height is None:
|
||||||
|
height = words
|
||||||
|
block["height"] = height
|
||||||
|
|
||||||
|
|
||||||
|
def parse_addr(line):
|
||||||
|
# 00020027_003_03
|
||||||
|
line = line.split("_")
|
||||||
|
frame = int(line[0], 16)
|
||||||
|
wordidx = int(line[1], 10)
|
||||||
|
bitidx = int(line[2], 10)
|
||||||
|
return frame, wordidx, bitidx
|
||||||
|
|
||||||
|
|
||||||
|
def load_db(fn):
|
||||||
|
for l in open(fn, "r"):
|
||||||
|
l = l.strip()
|
||||||
|
# FIXME: add offset to name
|
||||||
|
# IOB_X0Y101.DFRAME:27.DWORD:3.DBIT:3 00020027_003_03
|
||||||
|
tagstr, addrstr = l.split(' ')
|
||||||
|
|
||||||
|
frame, wordidx, bitidx = parse_addr(addrstr)
|
||||||
|
bitidx_up = False
|
||||||
|
|
||||||
|
tparts = tagstr.split('.')
|
||||||
|
tile = tparts[0]
|
||||||
|
for part in tparts[1:]:
|
||||||
|
k, v = part.split(':')
|
||||||
|
if k == "DFRAME":
|
||||||
|
frame -= int(v, 16)
|
||||||
|
elif k == "DWORD":
|
||||||
|
wordidx -= int(v, 10)
|
||||||
|
elif k == "DBIT":
|
||||||
|
bitidx -= int(v, 10)
|
||||||
|
bitidx_up = True
|
||||||
|
else:
|
||||||
|
assert 0, (l, part)
|
||||||
|
|
||||||
|
# XXX: maybe just ignore bitidx and always set to 0 instead of allowing explicit
|
||||||
|
# or detect the first delta auto and assert they are all the same
|
||||||
|
if not bitidx_up:
|
||||||
|
bitidx = 0
|
||||||
|
assert bitidx == 0
|
||||||
|
assert frame % 0x100 == 0, "Unaligned frame"
|
||||||
|
yield (tile, frame, wordidx)
|
||||||
|
|
||||||
|
|
||||||
|
def run(fn_in, fn_out, verbose=False):
|
||||||
|
database = json.load(open(fn_in, "r"))
|
||||||
|
|
||||||
|
# Load a map of sites to base addresses
|
||||||
|
# Need to figure out the
|
||||||
|
# FIXME: generate frames from part file (or equivilent)
|
||||||
|
# See https://github.com/SymbiFlow/prjxray/issues/327
|
||||||
|
# FIXME: generate words from pitch
|
||||||
|
tdb_fns = [("iob/build/segbits_tilegrid.tdb", 42, 4)]
|
||||||
|
for (tdb_fn, frames, words) in tdb_fns:
|
||||||
|
for (tile, frame, wordidx) in load_db(tdb_fn):
|
||||||
|
tilej = database[tile]
|
||||||
|
bitsj = tilej['bits']
|
||||||
|
bt = util.addr2btype(frame)
|
||||||
|
verbose and print("Add %s %08X_%03u" % (tile, frame, wordidx))
|
||||||
|
add_tile_bits(tilej, frame, wordidx, frames, words)
|
||||||
|
|
||||||
|
# Save
|
||||||
|
json.dump(
|
||||||
|
database,
|
||||||
|
open(fn_out, "w"),
|
||||||
|
sort_keys=True,
|
||||||
|
indent=4,
|
||||||
|
separators=(",", ": "))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Annotate tilegrid addresses using solved base addresses")
|
||||||
|
parser.add_argument("--verbose", action="store_true", help="")
|
||||||
|
parser.add_argument("--fn-in", required=True, help="")
|
||||||
|
parser.add_argument("--fn-out", required=True, help="")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
run(args.fn_in, args.fn_out, verbose=args.verbose)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -11,28 +11,7 @@ A post processing step verifies that two tiles don't reference the same bitstrea
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from generate import load_tiles
|
from generate import load_tiles
|
||||||
|
from prjxray import util
|
||||||
# matches lib/include/prjxray/xilinx/xc7series/block_type.h
|
|
||||||
block_type_i2s = {
|
|
||||||
0: 'CLB_IO_CLK',
|
|
||||||
1: 'BLOCK_RAM',
|
|
||||||
2: 'CFG_CLB',
|
|
||||||
# special...maybe should error until we know what it is?
|
|
||||||
# 3: 'RESERVED',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def addr2btype(base_addr):
|
|
||||||
'''
|
|
||||||
Convert integer address to block type
|
|
||||||
|
|
||||||
Table 5-24: Frame Address Register Description
|
|
||||||
Bit Index: [25:23]
|
|
||||||
https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
|
|
||||||
"Valid block types are CLB, I/O, CLK ( 000 ), block RAM content ( 001 ), and CFG_CLB ( 010 ). A normal bitstream does not include type 011 ."
|
|
||||||
'''
|
|
||||||
block_type_i = (base_addr >> 23) & 0x7
|
|
||||||
return block_type_i2s[block_type_i]
|
|
||||||
|
|
||||||
|
|
||||||
def nolr(tile_type):
|
def nolr(tile_type):
|
||||||
|
|
@ -77,7 +56,7 @@ def make_tile_baseaddrs(tiles, site_baseaddr, verbose=False):
|
||||||
if site_name not in site_baseaddr:
|
if site_name not in site_baseaddr:
|
||||||
continue
|
continue
|
||||||
framebaseaddr = site_baseaddr[site_name]
|
framebaseaddr = site_baseaddr[site_name]
|
||||||
bt = addr2btype(framebaseaddr)
|
bt = util.addr2btype(framebaseaddr)
|
||||||
tile_baseaddr = tile_baseaddrs.setdefault(tile["name"], {})
|
tile_baseaddr = tile_baseaddrs.setdefault(tile["name"], {})
|
||||||
if bt in tile_baseaddr:
|
if bt in tile_baseaddr:
|
||||||
# actually lets just fail these, better to remove at tcl level to speed up processing
|
# actually lets just fail these, better to remove at tcl level to speed up processing
|
||||||
|
|
@ -251,16 +230,19 @@ def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False):
|
||||||
'make_segment: drop %s' % (tile_type, ))
|
'make_segment: drop %s' % (tile_type, ))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
"""
|
||||||
|
FIXME: review IOB
|
||||||
|
"RIOB33": process_iob,
|
||||||
|
"LIOB33": process_iob,
|
||||||
|
"RIOB33_SING": process_iob_sing,
|
||||||
|
"LIOB33_SING": process_iob_sing,
|
||||||
|
"""
|
||||||
{
|
{
|
||||||
"CLBLL": process_clb,
|
"CLBLL": process_clb,
|
||||||
"CLBLM": process_clb,
|
"CLBLM": process_clb,
|
||||||
"HCLK": process_hclk,
|
"HCLK": process_hclk,
|
||||||
"BRAM": process_bram_dsp,
|
"BRAM": process_bram_dsp,
|
||||||
"DSP": process_bram_dsp,
|
"DSP": process_bram_dsp,
|
||||||
"RIOB33": process_iob,
|
|
||||||
"LIOB33": process_iob,
|
|
||||||
"RIOB33_SING": process_iob_sing,
|
|
||||||
"LIOB33_SING": process_iob_sing,
|
|
||||||
}.get(nolr(tile_type), process_default)()
|
}.get(nolr(tile_type), process_default)()
|
||||||
|
|
||||||
return segments
|
return segments
|
||||||
|
|
@ -516,7 +498,7 @@ def add_tile_bits(tile_db, baseaddr, offset, frames, words, height=None):
|
||||||
'''
|
'''
|
||||||
|
|
||||||
bits = tile_db['bits']
|
bits = tile_db['bits']
|
||||||
block_type = addr2btype(baseaddr)
|
block_type = util.addr2btype(baseaddr)
|
||||||
|
|
||||||
assert 0 <= offset <= 100, offset
|
assert 0 <= offset <= 100, offset
|
||||||
assert 1 <= words <= 101
|
assert 1 <= words <= 101
|
||||||
|
|
@ -554,6 +536,32 @@ def db_add_bits(database, segments):
|
||||||
offset) in segments[segment_name]["baseaddr"].items():
|
offset) in segments[segment_name]["baseaddr"].items():
|
||||||
for tile_name in segments[segment_name]["tiles"]:
|
for tile_name in segments[segment_name]["tiles"]:
|
||||||
tile_type = database[tile_name]["type"]
|
tile_type = database[tile_name]["type"]
|
||||||
|
"""
|
||||||
|
FIXME: review IOB
|
||||||
|
# IOB
|
||||||
|
# design_IOB_X0Y100.delta:+bit_00020027_000_29
|
||||||
|
# design_IOB_X0Y104.delta:+bit_00020027_008_29
|
||||||
|
# design_IOB_X0Y112.delta:+bit_00020027_024_29
|
||||||
|
# design_IOB_X0Y120.delta:+bit_00020027_040_29
|
||||||
|
# design_IOB_X0Y128.delta:+bit_00020027_057_29
|
||||||
|
# design_IOB_X0Y136.delta:+bit_00020027_073_29
|
||||||
|
# design_IOB_X0Y144.delta:+bit_00020027_089_29
|
||||||
|
# $XRAY_BLOCKWIDTH design_IOB_X0Y100.bit |grep 00020000
|
||||||
|
# 0x00020000: 0x2A (42)
|
||||||
|
("RIOI3", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("LIOI3", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("RIOI3_SING", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("LIOI3_SING", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("RIOI3_TBYTESRC", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("LIOI3_TBYTESRC", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("RIOI3_TBYTETERM", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("LIOI3_TBYTETERM", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("LIOB33", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("RIOB33", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("LIOB33", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("RIOB33_SING", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
("LIOB33_SING", "CLB_IO_CLK"): (42, 2, 4),
|
||||||
|
"""
|
||||||
entry = {
|
entry = {
|
||||||
# (tile_type, block_type): (frames, words, height)
|
# (tile_type, block_type): (frames, words, height)
|
||||||
("CLBLL", "CLB_IO_CLK"): (36, 2, 2),
|
("CLBLL", "CLB_IO_CLK"): (36, 2, 2),
|
||||||
|
|
@ -565,30 +573,6 @@ def db_add_bits(database, segments):
|
||||||
("DSP", "CLB_IO_CLK"): (28, 2, 10),
|
("DSP", "CLB_IO_CLK"): (28, 2, 10),
|
||||||
("INT_INTERFACE", "CLB_IO_CLK"): (28, 2, None),
|
("INT_INTERFACE", "CLB_IO_CLK"): (28, 2, None),
|
||||||
("BRAM_INT_INTERFACE", "CLB_IO_CLK"): (28, 2, None),
|
("BRAM_INT_INTERFACE", "CLB_IO_CLK"): (28, 2, None),
|
||||||
|
|
||||||
# IOB
|
|
||||||
# design_IOB_X0Y100.delta:+bit_00020027_000_29
|
|
||||||
# design_IOB_X0Y104.delta:+bit_00020027_008_29
|
|
||||||
# design_IOB_X0Y112.delta:+bit_00020027_024_29
|
|
||||||
# design_IOB_X0Y120.delta:+bit_00020027_040_29
|
|
||||||
# design_IOB_X0Y128.delta:+bit_00020027_057_29
|
|
||||||
# design_IOB_X0Y136.delta:+bit_00020027_073_29
|
|
||||||
# design_IOB_X0Y144.delta:+bit_00020027_089_29
|
|
||||||
# $XRAY_BLOCKWIDTH design_IOB_X0Y100.bit |grep 00020000
|
|
||||||
# 0x00020000: 0x2A (42)
|
|
||||||
("RIOI3", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("LIOI3", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("RIOI3_SING", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("LIOI3_SING", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("RIOI3_TBYTESRC", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("LIOI3_TBYTESRC", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("RIOI3_TBYTETERM", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("LIOI3_TBYTETERM", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("LIOB33", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("RIOB33", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("LIOB33", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("RIOB33_SING", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
("LIOB33_SING", "CLB_IO_CLK"): (42, 2, 2),
|
|
||||||
}.get((nolr(tile_type), block_type), None)
|
}.get((nolr(tile_type), block_type), None)
|
||||||
if entry is None:
|
if entry is None:
|
||||||
# Other types are rare, not expected to have these
|
# Other types are rare, not expected to have these
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
N := 15
|
||||||
|
SPECIMENS := $(addprefix build/specimen_,$(shell seq -f '%03.0f' $(N)))
|
||||||
|
SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS))
|
||||||
|
|
||||||
|
database: build/segbits_tilegrid.tdb
|
||||||
|
|
||||||
|
build/segbits_tilegrid.tdb: $(SPECIMENS_OK)
|
||||||
|
${XRAY_SEGMATCH} -o build/segbits_tilegrid.tdb $$(find build -name "segdata_tilegrid.txt")
|
||||||
|
|
||||||
|
$(SPECIMENS_OK):
|
||||||
|
bash generate.sh $(subst /OK,,$@)
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
run:
|
||||||
|
$(MAKE) clean
|
||||||
|
$(MAKE) database
|
||||||
|
$(MAKE) pushdb
|
||||||
|
touch run.ok
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf build
|
||||||
|
|
||||||
|
.PHONY: database pushdb run clean
|
||||||
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from prjxray import bitstream
|
||||||
|
|
||||||
|
|
||||||
|
def write(bits_fn, fnout, tags):
|
||||||
|
'''
|
||||||
|
seg 00020000_046
|
||||||
|
bit 18_20
|
||||||
|
bit 39_63
|
||||||
|
tag LIOB33.IOB_Y1.REFBIT 0
|
||||||
|
'''
|
||||||
|
fout = open(fnout, "w")
|
||||||
|
|
||||||
|
def line(s):
|
||||||
|
fout.write(s + "\n")
|
||||||
|
|
||||||
|
# Everything relative to start of bitstream
|
||||||
|
line("seg 00000000_000")
|
||||||
|
|
||||||
|
bitdata = bitstream.load_bitdata2(open(bits_fn, "r"))
|
||||||
|
|
||||||
|
for frame, words in bitdata.items():
|
||||||
|
for word, wbits in words.items():
|
||||||
|
for bitidx in sorted(list(wbits)):
|
||||||
|
# Are the names arbitrary? Lets just re-create
|
||||||
|
line("bit %08X_%03u_%02u" % (frame, word, bitidx))
|
||||||
|
|
||||||
|
for k, v in tags.items():
|
||||||
|
line("tag %s %u" % (k, v))
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import bitsmaker
|
||||||
|
|
||||||
|
|
||||||
|
def run(bits_fn, design_fn, fnout, verbose=False):
|
||||||
|
# Raw: IOB_X0Y101 00020027_003_03
|
||||||
|
metastr = "DFRAME:27.DWORD:3.DBIT:3"
|
||||||
|
|
||||||
|
tags = dict()
|
||||||
|
f = open(design_fn, 'r')
|
||||||
|
f.readline()
|
||||||
|
for l in f:
|
||||||
|
l = l.strip()
|
||||||
|
port, site, tile, pin, val = l.split(',')
|
||||||
|
'''
|
||||||
|
PULLTYPE 28 29 30
|
||||||
|
NONE X
|
||||||
|
KEEPER X X
|
||||||
|
PULLDOWN
|
||||||
|
PULLUP X X
|
||||||
|
'''
|
||||||
|
tags["%s.%s" % (tile, metastr)] = val == "KEEPER"
|
||||||
|
|
||||||
|
bitsmaker.write(bits_fn, fnout, tags)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=
|
||||||
|
"Solve bits (like segmaker) on raw .bits file without segments")
|
||||||
|
parser.add_argument("--bits-file", default="design.bits", help="")
|
||||||
|
parser.add_argument("--verbose", action="store_true", help="")
|
||||||
|
parser.add_argument("--design", default="design.csv", help="")
|
||||||
|
parser.add_argument("--fnout", default="/dev/stdout", help="")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
run(args.bits_file, args.design, args.fnout, args.verbose)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
export FUZDIR=$PWD
|
||||||
|
source ${XRAY_GENHEADER}
|
||||||
|
|
||||||
|
# Some projects have hard coded top.v, others are generated
|
||||||
|
if [ -f $FUZDIR/top.py ] ; then
|
||||||
|
python3 $FUZDIR/top.py >top.v
|
||||||
|
fi
|
||||||
|
|
||||||
|
vivado -mode batch -source $FUZDIR/generate.tcl
|
||||||
|
test -z "$(fgrep CRITICAL vivado.log)"
|
||||||
|
|
||||||
|
for x in design*.bit; do
|
||||||
|
${XRAY_BITREAD} -F $XRAY_ROI_FRAMES -o ${x}s -z -y $x
|
||||||
|
done
|
||||||
|
|
||||||
|
python3 $FUZDIR/generate.py >segdata_tilegrid.txt
|
||||||
|
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
source "$::env(XRAY_DIR)/utils/utils.tcl"
|
||||||
|
|
||||||
|
proc make_io_pin_sites {} {
|
||||||
|
# get all possible IOB pins
|
||||||
|
foreach pad [get_package_pins -filter "IS_GENERAL_PURPOSE == 1"] {
|
||||||
|
set site [get_sites -of_objects $pad]
|
||||||
|
if {[llength $site] == 0} {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if [string match IOB33* [get_property SITE_TYPE $site]] {
|
||||||
|
dict append io_pin_sites $site $pad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $io_pin_sites
|
||||||
|
}
|
||||||
|
|
||||||
|
proc load_pin_lines {} {
|
||||||
|
# IOB_X0Y103 clk input
|
||||||
|
# IOB_X0Y129 do[0] output
|
||||||
|
|
||||||
|
set fp [open "params.csv" r]
|
||||||
|
set pin_lines {}
|
||||||
|
for {gets $fp line} {$line != ""} {gets $fp line} {
|
||||||
|
lappend pin_lines [split $line ","]
|
||||||
|
}
|
||||||
|
close $fp
|
||||||
|
return $pin_lines
|
||||||
|
}
|
||||||
|
|
||||||
|
proc loc_pins {} {
|
||||||
|
set pin_lines [load_pin_lines]
|
||||||
|
set io_pin_sites [make_io_pin_sites]
|
||||||
|
|
||||||
|
set fp [open "design.csv" w]
|
||||||
|
puts $fp "port,site,tile,pin,val"
|
||||||
|
|
||||||
|
puts "Looping"
|
||||||
|
for {set idx 0} {$idx < [llength $pin_lines]} {incr idx} {
|
||||||
|
set line [lindex $pin_lines $idx]
|
||||||
|
puts "$line"
|
||||||
|
|
||||||
|
set site_str [lindex $line 0]
|
||||||
|
set pin_str [lindex $line 1]
|
||||||
|
set io [lindex $line 2]
|
||||||
|
set cell_str [lindex $line 3]
|
||||||
|
|
||||||
|
# Have: site
|
||||||
|
# Want: pin for site
|
||||||
|
|
||||||
|
set site [get_sites $site_str]
|
||||||
|
set pad_bel [get_bels -of_objects $site -filter {TYPE =~ PAD && NAME =~ IOB_*}]
|
||||||
|
# set port [get_ports -of_objects $site]
|
||||||
|
set port [get_ports $pin_str]
|
||||||
|
set tile [get_tiles -of_objects $site]
|
||||||
|
|
||||||
|
set pin "FIXME"
|
||||||
|
set pin [dict get $io_pin_sites $site]
|
||||||
|
#set pin [get_property PACKAGE_PIN $port]
|
||||||
|
|
||||||
|
#set cell [get_cells $cell_str]
|
||||||
|
# puts "LOCing cell $cell to site $site (from bel $pad_bel)"
|
||||||
|
# set_property LOC $site $cell
|
||||||
|
|
||||||
|
set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS33" $port
|
||||||
|
|
||||||
|
|
||||||
|
# list_property isn't working
|
||||||
|
# set keys [list_property_value PULLTYPE $port]
|
||||||
|
set keys "NONE KEEPER"
|
||||||
|
set val [randsample_list 1 $keys]
|
||||||
|
if { $val == "NONE" } {
|
||||||
|
set val ""
|
||||||
|
}
|
||||||
|
set_property PULLTYPE $val $port
|
||||||
|
# puts "IOB $port $site $tile $pin $val"
|
||||||
|
puts $fp "$port,$site,$tile,$pin,$val"
|
||||||
|
}
|
||||||
|
close $fp
|
||||||
|
}
|
||||||
|
|
||||||
|
proc run {} {
|
||||||
|
create_project -force -part $::env(XRAY_PART) design design
|
||||||
|
read_verilog top.v
|
||||||
|
synth_design -top top
|
||||||
|
|
||||||
|
# Mostly doesn't matter since IOB are special, but add anyway
|
||||||
|
create_pblock roi
|
||||||
|
add_cells_to_pblock [get_pblocks roi] [get_cells roi]
|
||||||
|
resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)"
|
||||||
|
|
||||||
|
loc_pins
|
||||||
|
|
||||||
|
set_property CFGBVS VCCO [current_design]
|
||||||
|
set_property CONFIG_VOLTAGE 3.3 [current_design]
|
||||||
|
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
|
||||||
|
set_param tcl.collectionResultDisplayLimit 0
|
||||||
|
|
||||||
|
place_design
|
||||||
|
route_design
|
||||||
|
|
||||||
|
write_checkpoint -force design.dcp
|
||||||
|
write_bitstream -force design.bit
|
||||||
|
}
|
||||||
|
|
||||||
|
run
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
'''
|
||||||
|
Generate a primitive to place at every I/O
|
||||||
|
Unlike CLB tests, the LFSR for this is inside the ROI, not driving it
|
||||||
|
'''
|
||||||
|
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
random.seed(int(os.getenv("SEED"), 16))
|
||||||
|
from prjxray import util
|
||||||
|
from prjxray import verilog
|
||||||
|
|
||||||
|
|
||||||
|
def gen_iobs():
|
||||||
|
'''
|
||||||
|
IOB33S: main IOB of a diff pair
|
||||||
|
IOB33M: secondary IOB of a diff pair
|
||||||
|
IOB33: not a diff pair. Relatively rare (at least in ROI...2 of them?)
|
||||||
|
Focus on IOB33S to start
|
||||||
|
'''
|
||||||
|
for _tile_name, site_name, site_type in util.get_roi().gen_sites(
|
||||||
|
# ['IOB33', 'IOB33S']):
|
||||||
|
# FIXME: special cases on IOB33
|
||||||
|
['IOB33S']):
|
||||||
|
yield site_name, site_type
|
||||||
|
|
||||||
|
|
||||||
|
def write_pins(ports):
|
||||||
|
pinstr = ''
|
||||||
|
for site, (name, dir_, cell) in sorted(ports.items(), key=lambda x: x[1]):
|
||||||
|
# pinstr += 'set_property -dict "PACKAGE_PIN %s IOSTANDARD LVCMOS33" [get_ports %s]' % (packpin, port)
|
||||||
|
pinstr += '%s,%s,%s,%s\n' % (site, name, dir_, cell)
|
||||||
|
open('params.csv', 'w').write(pinstr)
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
# All possible values
|
||||||
|
iosites = {}
|
||||||
|
for site_name, site_type in gen_iobs():
|
||||||
|
iosites[site_name] = site_type
|
||||||
|
|
||||||
|
# Assigned in this design
|
||||||
|
ports = {}
|
||||||
|
DIN_N = 0
|
||||||
|
DOUT_N = 0
|
||||||
|
|
||||||
|
def remain_sites():
|
||||||
|
return set(iosites.keys()) - set(ports.keys())
|
||||||
|
|
||||||
|
def rand_site():
|
||||||
|
'''Get a random, unused site'''
|
||||||
|
return random.choice(list(remain_sites()))
|
||||||
|
|
||||||
|
def assign_i(site, name):
|
||||||
|
nonlocal DIN_N
|
||||||
|
|
||||||
|
assert site not in ports
|
||||||
|
cell = "di_bufs[%u].ibuf" % DIN_N
|
||||||
|
DIN_N += 1
|
||||||
|
ports[site] = (name, 'input', cell)
|
||||||
|
|
||||||
|
def assign_o(site, name):
|
||||||
|
nonlocal DOUT_N
|
||||||
|
|
||||||
|
assert site not in ports
|
||||||
|
cell = "do_bufs[%u].obuf" % DOUT_N
|
||||||
|
DOUT_N += 1
|
||||||
|
ports[site] = (name, 'output', cell)
|
||||||
|
|
||||||
|
# Assign at least one di and one do
|
||||||
|
assign_i(rand_site(), 'di[0]')
|
||||||
|
assign_o(rand_site(), 'do[0]')
|
||||||
|
# Now assign the rest randomly
|
||||||
|
while len(remain_sites()):
|
||||||
|
if random.randint(0, 1):
|
||||||
|
assign_i(rand_site(), 'di[%u]' % DIN_N)
|
||||||
|
else:
|
||||||
|
assign_o(rand_site(), 'do[%u]' % DOUT_N)
|
||||||
|
|
||||||
|
write_pins(ports)
|
||||||
|
|
||||||
|
print(
|
||||||
|
'''
|
||||||
|
`define N_DI %u
|
||||||
|
`define N_DO %u
|
||||||
|
|
||||||
|
module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do);
|
||||||
|
genvar i;
|
||||||
|
|
||||||
|
//Instantiate BUFs so we can LOC them
|
||||||
|
|
||||||
|
wire [`N_DI-1:0] di_buf;
|
||||||
|
generate
|
||||||
|
for (i = 0; i < `N_DI; i = i+1) begin:di_bufs
|
||||||
|
IBUF ibuf(.I(di[i]), .O(di_buf[i]));
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
wire [`N_DO-1:0] do_unbuf;
|
||||||
|
generate
|
||||||
|
for (i = 0; i < `N_DO; i = i+1) begin:do_bufs
|
||||||
|
OBUF obuf(.I(do_unbuf[i]), .O(do[i]));
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
roi roi(.di(di_buf), .do(do_unbuf));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
//Arbitrary terminate into LUTs
|
||||||
|
module roi(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do);
|
||||||
|
genvar i;
|
||||||
|
|
||||||
|
generate
|
||||||
|
for (i = 0; i < `N_DI; i = i+1) begin:dis
|
||||||
|
(* KEEP, DONT_TOUCH *)
|
||||||
|
LUT6 #(
|
||||||
|
.INIT(64'h8000_0000_0000_0001)
|
||||||
|
) lut (
|
||||||
|
.I0(di[i]),
|
||||||
|
.I1(di[i]),
|
||||||
|
.I2(di[i]),
|
||||||
|
.I3(di[i]),
|
||||||
|
.I4(di[i]),
|
||||||
|
.I5(di[i]),
|
||||||
|
.O());
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
generate
|
||||||
|
for (i = 0; i < `N_DO; i = i+1) begin:dos
|
||||||
|
(* KEEP, DONT_TOUCH *)
|
||||||
|
LUT6 #(
|
||||||
|
.INIT(64'h8000_0000_0000_0001)
|
||||||
|
) lut (
|
||||||
|
.I0(),
|
||||||
|
.I1(),
|
||||||
|
.I2(),
|
||||||
|
.I3(),
|
||||||
|
.I4(),
|
||||||
|
.I5(),
|
||||||
|
.O(do[i]));
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
''' % (DIN_N, DOUT_N))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run()
|
||||||
|
|
@ -3,10 +3,20 @@ WORD_SIZE_BITS = 32
|
||||||
|
|
||||||
# How many 32-bit words for frame in a 7-series bitstream?
|
# How many 32-bit words for frame in a 7-series bitstream?
|
||||||
FRAME_WORD_COUNT = 101
|
FRAME_WORD_COUNT = 101
|
||||||
|
'''
|
||||||
|
Sample:
|
||||||
|
bit_0002000f_079_06
|
||||||
|
|
||||||
|
Where:
|
||||||
|
-0002000f: FDRI address
|
||||||
|
-079: FDIR word number (0-100)
|
||||||
|
-06: bit index (0-31)
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
def load_bitdata(f):
|
def load_bitdata(f):
|
||||||
""" Read bit file and return bitdata map.
|
""" Read bit file and return bitdata map.
|
||||||
|
Similar to segbits file
|
||||||
|
|
||||||
bitdata is a map of of two sets.
|
bitdata is a map of of two sets.
|
||||||
The map key is the frame address.
|
The map key is the frame address.
|
||||||
|
|
@ -34,16 +44,24 @@ def load_bitdata(f):
|
||||||
# used by segprint
|
# used by segprint
|
||||||
# TODO: merge these
|
# TODO: merge these
|
||||||
def load_bitdata2(f):
|
def load_bitdata2(f):
|
||||||
# these are not compatible
|
'''
|
||||||
# return bitstream.load_bitdata(open(bits_file, "r"))
|
return as bitdata[frame][wordidx].add(bitidx)
|
||||||
|
ie indexed by frame, word index, and then a set with bit indexes
|
||||||
|
Similar to .bits file: bit_00020012_014_20
|
||||||
|
'''
|
||||||
|
|
||||||
bitdata = dict()
|
bitdata = dict()
|
||||||
|
|
||||||
for line in f:
|
for lineraw in f:
|
||||||
line = line.split("_")
|
lineraw = lineraw.strip()
|
||||||
frame = int(line[1], 16)
|
line = lineraw.split("_")
|
||||||
wordidx = int(line[2], 10)
|
try:
|
||||||
bitidx = int(line[3], 10)
|
frame = int(line[1], 16)
|
||||||
|
wordidx = int(line[2], 10)
|
||||||
|
bitidx = int(line[3], 10)
|
||||||
|
except:
|
||||||
|
print("Invalid line %s" % lineraw)
|
||||||
|
raise
|
||||||
|
|
||||||
if frame not in bitdata:
|
if frame not in bitdata:
|
||||||
bitdata[frame] = dict()
|
bitdata[frame] = dict()
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,29 @@ def addr2str(addr, word, bit):
|
||||||
return "%08x_%03u_%02u" % (addr, word, bit)
|
return "%08x_%03u_%02u" % (addr, word, bit)
|
||||||
|
|
||||||
|
|
||||||
|
# matches lib/include/prjxray/xilinx/xc7series/block_type.h
|
||||||
|
block_type_i2s = {
|
||||||
|
0: 'CLB_IO_CLK',
|
||||||
|
1: 'BLOCK_RAM',
|
||||||
|
2: 'CFG_CLB',
|
||||||
|
# special...maybe should error until we know what it is?
|
||||||
|
# 3: 'RESERVED',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def addr2btype(base_addr):
|
||||||
|
'''
|
||||||
|
Convert integer address to block type
|
||||||
|
|
||||||
|
Table 5-24: Frame Address Register Description
|
||||||
|
Bit Index: [25:23]
|
||||||
|
https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
|
||||||
|
"Valid block types are CLB, I/O, CLK ( 000 ), block RAM content ( 001 ), and CFG_CLB ( 010 ). A normal bitstream does not include type 011 ."
|
||||||
|
'''
|
||||||
|
block_type_i = (base_addr >> 23) & 0x7
|
||||||
|
return block_type_i2s[block_type_i]
|
||||||
|
|
||||||
|
|
||||||
def gen_tile_bits(db_root, tilej, strict=False, verbose=False):
|
def gen_tile_bits(db_root, tilej, strict=False, verbose=False):
|
||||||
'''
|
'''
|
||||||
For given tile yield
|
For given tile yield
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue