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:
|
||||
bash generate.sh build/bram bram
|
||||
|
||||
# FIXME: review IOB
|
||||
build/iob/deltas:
|
||||
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 \
|
||||
--json-in tilegrid_basic.json --json-out ${BUILD_DIR}/tilegrid.json \
|
||||
--tiles $(FUZDIR)/build/tiles/tiles.txt */design_*.delta
|
||||
--json-in tilegrid_tdb.json --json-out ${BUILD_DIR}/tilegrid.json \
|
||||
--tiles $(FUZDIR)/build/tiles/tiles.txt {clb,bram}/design_*.delta
|
||||
|
||||
run:
|
||||
$(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
|
||||
|
||||
# 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]
|
||||
from prjxray import util
|
||||
|
||||
|
||||
def nolr(tile_type):
|
||||
|
|
@ -77,7 +56,7 @@ def make_tile_baseaddrs(tiles, site_baseaddr, verbose=False):
|
|||
if site_name not in site_baseaddr:
|
||||
continue
|
||||
framebaseaddr = site_baseaddr[site_name]
|
||||
bt = addr2btype(framebaseaddr)
|
||||
bt = util.addr2btype(framebaseaddr)
|
||||
tile_baseaddr = tile_baseaddrs.setdefault(tile["name"], {})
|
||||
if bt in tile_baseaddr:
|
||||
# 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, ))
|
||||
pass
|
||||
|
||||
"""
|
||||
FIXME: review IOB
|
||||
"RIOB33": process_iob,
|
||||
"LIOB33": process_iob,
|
||||
"RIOB33_SING": process_iob_sing,
|
||||
"LIOB33_SING": process_iob_sing,
|
||||
"""
|
||||
{
|
||||
"CLBLL": process_clb,
|
||||
"CLBLM": process_clb,
|
||||
"HCLK": process_hclk,
|
||||
"BRAM": 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)()
|
||||
|
||||
return segments
|
||||
|
|
@ -516,7 +498,7 @@ def add_tile_bits(tile_db, baseaddr, offset, frames, words, height=None):
|
|||
'''
|
||||
|
||||
bits = tile_db['bits']
|
||||
block_type = addr2btype(baseaddr)
|
||||
block_type = util.addr2btype(baseaddr)
|
||||
|
||||
assert 0 <= offset <= 100, offset
|
||||
assert 1 <= words <= 101
|
||||
|
|
@ -554,6 +536,32 @@ def db_add_bits(database, segments):
|
|||
offset) in segments[segment_name]["baseaddr"].items():
|
||||
for tile_name in segments[segment_name]["tiles"]:
|
||||
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 = {
|
||||
# (tile_type, block_type): (frames, words, height)
|
||||
("CLBLL", "CLB_IO_CLK"): (36, 2, 2),
|
||||
|
|
@ -565,30 +573,6 @@ def db_add_bits(database, segments):
|
|||
("DSP", "CLB_IO_CLK"): (28, 2, 10),
|
||||
("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)
|
||||
if entry is None:
|
||||
# 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?
|
||||
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):
|
||||
""" Read bit file and return bitdata map.
|
||||
Similar to segbits file
|
||||
|
||||
bitdata is a map of of two sets.
|
||||
The map key is the frame address.
|
||||
|
|
@ -34,16 +44,24 @@ def load_bitdata(f):
|
|||
# used by segprint
|
||||
# TODO: merge these
|
||||
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()
|
||||
|
||||
for line in f:
|
||||
line = line.split("_")
|
||||
frame = int(line[1], 16)
|
||||
wordidx = int(line[2], 10)
|
||||
bitidx = int(line[3], 10)
|
||||
for lineraw in f:
|
||||
lineraw = lineraw.strip()
|
||||
line = lineraw.split("_")
|
||||
try:
|
||||
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:
|
||||
bitdata[frame] = dict()
|
||||
|
|
|
|||
|
|
@ -124,6 +124,29 @@ def addr2str(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):
|
||||
'''
|
||||
For given tile yield
|
||||
|
|
|
|||
Loading…
Reference in New Issue