add support for the kintex high performance banks

Signed-off-by: Hans Baier <hansfbaier@gmail.com>
This commit is contained in:
Hans Baier 2022-11-08 17:31:50 +07:00
parent 480218e9c0
commit e929e5519b
64 changed files with 5186 additions and 1441 deletions

View File

@ -50,6 +50,7 @@ DB_SIMPLE=\
segbits_cmt_top_r_lower_b \
segbits_rioi3 \
segbits_riob33 \
segbits_riob18 \
segbits_hclk_cmt \
segbits_hclk_ioi3 \

View File

@ -11,7 +11,7 @@ proc extract_iobanks {filename} {
set sample_site [lindex [get_sites -of $iobank] 0]
if {[llength $sample_site] == 0} continue
set clock_region [get_property CLOCK_REGION $sample_site]
foreach tile [get_tiles -filter {TYPE=~HCLK_IOI3}] {
foreach tile [concat [get_tiles -filter {TYPE=~HCLK_IOI3}] [get_tiles -filter {TYPE=~HCLK_IOI}]] {
set tile_sites [get_sites -of_object $tile]
if {[llength $tile_sites] == 0} continue
set hclk_tile_clock_region [get_property CLOCK_REGION [lindex [get_sites -of_object $tile] 0]]

View File

@ -49,6 +49,13 @@ endif
# Kintex7 only fuzzers
ifeq (${XRAY_DATABASE}, kintex7)
# xc7k420t/xc7k480t have no high performance banks
ifneq (${XRAY_FABRIC}, $(filter ${XRAY_FABRIC}, xc7k480t))
TILEGRID_TDB_DEPENDENCIES += iob18/$(BUILD_FOLDER)/segbits_tilegrid.tdb
TILEGRID_TDB_DEPENDENCIES += iob18_int/$(BUILD_FOLDER)/segbits_tilegrid.tdb
TILEGRID_TDB_DEPENDENCIES += ioi18/$(BUILD_FOLDER)/segbits_tilegrid.tdb
endif
# These kintex parts give an empty design
ifneq (${XRAY_FABRIC}, $(filter ${XRAY_FABRIC}, xc7k160t xc7k325t xc7k480t))
TILEGRID_TDB_DEPENDENCIES += orphan_int_column/$(BUILD_FOLDER)/segbits_tilegrid.tdb
@ -85,12 +92,21 @@ cfg/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
iob/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
cd iob && $(MAKE)
iob18/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
cd iob18 && $(MAKE)
iob_int/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
cd iob_int && $(MAKE)
iob18_int/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
cd iob18_int && $(MAKE)
ioi/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
cd ioi && $(MAKE)
ioi18/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
cd ioi18 && $(MAKE)
mmcm/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
cd mmcm && $(MAKE)
@ -177,8 +193,11 @@ clean:
cd clb_int && $(MAKE) clean
cd cfg && $(MAKE) clean
cd iob && $(MAKE) clean
cd iob18 && $(MAKE) clean
cd iob_int && $(MAKE) clean
cd iob18_int && $(MAKE) clean
cd ioi && $(MAKE) clean
cd ioi18 && $(MAKE) clean
cd mmcm && $(MAKE) clean
cd pll && $(MAKE) clean
cd ps7_int && $(MAKE) clean
@ -208,8 +227,11 @@ clean_part:
cd clb_int && $(MAKE) clean_part
cd cfg && $(MAKE) clean_part
cd iob && $(MAKE) clean_part
cd iob18 && $(MAKE) clean_part
cd iob_int && $(MAKE) clean_part
cd iob18_int && $(MAKE) clean_part
cd ioi && $(MAKE) clean_part
cd ioi18 && $(MAKE) clean_part
cd mmcm && $(MAKE) clean_part
cd pll && $(MAKE) clean_part
cd ps7_int && $(MAKE) clean_part

View File

@ -94,7 +94,9 @@ def run(fn_in, fn_out, verbose=False):
int_frames, int_words = localutil.get_int_params()
tdb_fns = [
("iob", 42, 4),
("iob18", 42, 4),
("ioi", 42, 4),
("ioi18", 42, 4),
("mmcm", 30, 49),
("pll", 30, 27),
("monitor", 30, 101),
@ -112,6 +114,7 @@ def run(fn_in, fn_out, verbose=False):
("gtp_channel", 32, 22),
("clb_int", int_frames, int_words),
("iob_int", int_frames, int_words),
("iob18_int", int_frames, int_words),
("bram_int", int_frames, int_words),
("dsp_int", int_frames, int_words),
("fifo_int", int_frames, int_words),

View File

@ -369,7 +369,7 @@ def propagate_IOB_SING(database, tiles_by_grid):
if tile in seen_iobs:
continue
if database[tile]["type"] not in ["LIOB33", "RIOB33"]:
if database[tile]["type"] not in ["LIOB33", "RIOB33", "RIOB18"]:
continue
while True:
@ -439,7 +439,7 @@ def propagate_IOI_SING(database, tiles_by_grid):
if tile in seen_iois:
continue
if database[tile]["type"] not in ["LIOI3", "RIOI3"]:
if database[tile]["type"] not in ["LIOI3", "RIOI3", "RIOI"]:
continue
while True:

View File

@ -0,0 +1,10 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
N ?= 30
GENERATE_ARGS?="--oneval 1 --design params.csv --dframe 26 --dword 0"
include ../fuzzaddr/common.mk

View File

@ -0,0 +1,86 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
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 IOB18* [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]
gets $fp line
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]
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 2]
set pin_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 [dict get $io_pin_sites $site]
set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS18" $port
}
}
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
loc_pins
set_property CFGBVS GND [current_design]
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_property IS_ENABLED 0 [get_drc_checks {REQP-79}]
set_property IS_ENABLED 0 [get_drc_checks {NSTD-1}]
set_property IS_ENABLED 0 [get_drc_checks {UCIO-1}]
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
}
run

View File

@ -0,0 +1,84 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
import os
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray.db import Database
def gen_sites():
'''
IOB18S: main IOB of a diff pair
IOB18M: secondary IOB of a diff pair
IOB18: not a diff pair. Relatively rare (at least in ROI...2 of them?)
Focus on IOB18S to start
'''
db = Database(util.get_db_root(), util.get_part())
grid = db.grid()
for tile_name in sorted(grid.tiles()):
loc = grid.loc_of_tilename(tile_name)
gridinfo = grid.gridinfo_at_loc(loc)
for site_name, site_type in gridinfo.sites.items():
if site_type == 'IOB18S':
yield tile_name, site_name
def write_params(params):
pinstr = 'tile,val,site,pin\n'
for tile, (site, val, pin) in sorted(params.items()):
pinstr += '%s,%s,%s,%s\n' % (tile, val, site, pin)
open('params.csv', 'w').write(pinstr)
def run():
sites = list(gen_sites())
print(
'''
`define N_DI {}
module top(input wire [`N_DI-1:0] di);
wire [`N_DI-1:0] di_buf;
'''.format(len(sites)))
params = {}
print('''
(* KEEP, DONT_TOUCH *)
LUT6 dummy_lut();''')
for idx, ((tile_name, site_name), isone) in enumerate(zip(
sites, util.gen_fuzz_states(len(sites)))):
params[tile_name] = (site_name, isone, "di[%u]" % idx)
print(
'''
(* KEEP, DONT_TOUCH *)
IBUF #(
) ibuf_{site_name} (
.I(di[{idx}]),
.O(di_buf[{idx}])
);'''.format(site_name=site_name, idx=idx))
if isone:
print(
'''
(* KEEP, DONT_TOUCH *)
PULLUP #(
) pullup_{site_name} (
.O(di[{idx}])
);'''.format(site_name=site_name, idx=idx))
print("endmodule")
write_params(params)
if __name__ == '__main__':
run()

View File

@ -0,0 +1,10 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
N ?= 16
GENERATE_ARGS?="--oneval 0 --design params.csv --dframe 14 --dword 1"
include ../fuzzaddr/common.mk

View File

@ -0,0 +1,82 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
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 IOB18* [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]
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 3]
set pin_str [lindex $line 4]
# 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 [dict get $io_pin_sites $site]
set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS18" $port
}
}
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
loc_pins
set_property CFGBVS GND [current_design]
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_property IS_ENABLED 0 [get_drc_checks {REQP-79}]
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
}
run

View File

@ -0,0 +1,139 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
'''
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.db import Database
import re
def gen_sites():
'''
IOB18S: main IOB of a diff pair
IOB18M: secondary IOB of a diff pair
IOB18: not a diff pair. Relatively rare (at least in ROI...2 of them?)
Focus on IOB18S to start
'''
db = Database(util.get_db_root(), util.get_part())
grid = db.grid()
for tile_name in sorted(grid.tiles()):
loc = grid.loc_of_tilename(tile_name)
gridinfo = grid.gridinfo_at_loc(loc)
sites = []
for site_name, site_type in gridinfo.sites.items():
if site_type == 'IDELAYE2_FINEDELAY':
sites.append(site_name)
if len(sites) == 0:
continue
sites_y = [
int(re.match('IDELAY_X[0-9]+Y([0-9]+)', site).group(1))
for site in sites
]
sites, _ = zip(*sorted(zip(sites, sites_y), key=lambda x: x[1]))
if gridinfo.tile_type[0] == 'L':
int_grid_x = loc.grid_x + 3
pad_grid_x = loc.grid_x - 1
int_tile_type = 'INT_L'
else:
int_grid_x = loc.grid_x - 3
pad_grid_x = loc.grid_x + 1
int_tile_type = 'INT_R'
int_tile_locs = [
(int_grid_x, loc.grid_y),
]
pad_gridinfo = grid.gridinfo_at_loc((pad_grid_x, loc.grid_y))
pad_sites = pad_gridinfo.sites.keys()
pad_sites_y = [
int(re.match('IOB_X[0-9]+Y([0-9]+)', site).group(1))
for site in pad_sites
]
pad_sites, _ = zip(
*sorted(zip(pad_sites, pad_sites_y), key=lambda x: x[1]))
if not gridinfo.tile_type.endswith("_SING"):
int_tile_locs.append((int_grid_x, loc.grid_y - 1))
assert len(sites) == len(int_tile_locs), (
tile_name, sites, int_tile_locs)
assert len(sites) == len(pad_sites), (sites, pad_sites)
for site_name, pad_site, int_tile_loc in zip(sites, pad_sites,
int_tile_locs):
int_tile_name = grid.tilename_at_loc(int_tile_loc)
assert int_tile_name.startswith(int_tile_type), (
int_tile_name, site_name, int_tile_loc)
yield int_tile_name, site_name, pad_site
def write_params(params):
pinstr = ''
for tile, (site, val, pad_site_name, pin) in sorted(params.items()):
pinstr += '%s,%s,%s,%s,%s\n' % (tile, val, site, pad_site_name, pin)
open('params.csv', 'w').write(pinstr)
def run():
sites = list(gen_sites())
print(
'''
`define N_DI {}
module top(input wire [`N_DI-1:0] di);
wire [`N_DI-1:0] di_buf;
(* KEEP, DONT_TOUCH, IODELAY_GROUP = "iodelays" *)
IDELAYCTRL idelayctrl (
.REFCLK()
);
'''.format(len(sites)))
params = {}
for idx, ((tile_name, site_name, pad_site_name), isone) in enumerate(zip(
sites, util.gen_fuzz_states(len(sites)))):
params[tile_name] = (site_name, isone, pad_site_name, "di[%u]" % idx)
# Force HARD0 -> GFAN1 with CNTVALUEIN4 = 0
# Toggle 1 pip with CNTVALUEIN3 = ?
print(
'''
// Solving for {3}
(* KEEP, DONT_TOUCH *)
IBUF ibuf_{0}(.I(di[{2}]), .O(di_buf[{2}]));
(* KEEP, DONT_TOUCH, LOC = "{0}", IODELAY_GROUP = "iodelays" *)
IDELAYE2 idelay_{0} (
.CNTVALUEIN(5'b0{1}111),
.IDATAIN(di_buf[{2}])
);
'''.format(site_name, isone, idx, tile_name))
print("endmodule")
write_params(params)
if __name__ == '__main__':
run()

View File

@ -0,0 +1,10 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
N ?= 24
GENERATE_ARGS?="--oneval 1 --design params.csv --dframe 20 --dword 3"
include ../fuzzaddr/common.mk

View File

@ -0,0 +1,88 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
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 IOB18* [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]
gets $fp line
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 package_pin_keys [dict keys $io_pin_sites]
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 2]
set pin_str [lindex $line 3]
set pad_str [lindex $line 4]
# Have: site
# Want: pin for site
set site [get_sites $site_str]
set port [get_ports $pin_str]
set tile [get_tiles -of_objects $site]
set pin [dict get $io_pin_sites $pad_str]
set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS18" $port
}
}
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
#loc_pins
set_property CFGBVS GND [current_design]
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_property IS_ENABLED 0 [get_drc_checks {REQP-79}]
set_property SEVERITY {Warning} [get_drc_checks NSTD-1]
set_property SEVERITY {Warning} [get_drc_checks UCIO-1]
#set_property IS_ENABLED 0 [get_drc_checks {REQP-83}]
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
}
run

View File

@ -0,0 +1,119 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
import json
import io
import os
import random
import re
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray import lut_maker
from prjxray import verilog
from prjxray.db import Database
def gen_sites():
db = Database(util.get_db_root(), util.get_part())
grid = db.grid()
for tile_name in sorted(grid.tiles()):
loc = grid.loc_of_tilename(tile_name)
gridinfo = grid.gridinfo_at_loc(loc)
if gridinfo.tile_type.endswith("_SING"):
continue
# Y9 tiles have frame address 1 frame higher than the rest
# Need to investigate what is so special about them
if tile_name.endswith("Y9"):
continue
sites = []
for site_name, site_type in gridinfo.sites.items():
if site_type == 'IDELAYE2_FINEDELAY':
yield tile_name, site_name
def write_params(params):
pinstr = 'tile,isone,site\n'
for vals in params:
pinstr += ','.join(map(str, vals)) + '\n'
open('params.csv', 'w').write(pinstr)
def use_idelay(p, luts, connects):
print(
'''
wire idelay_{site};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
IDELAYE2_FINEDELAY #(
.HIGH_PERFORMANCE_MODE("{param}"),
.DELAY_SRC("DATAIN")
) idelay_site_{site} (
.DATAIN({onet}),
.DATAOUT(idelay_{site})
);
assign {net} = idelay_{site};
'''.format(
onet=luts.get_next_output_net(),
net=luts.get_next_input_net(),
param="TRUE" if p['isone'] else "FALSE",
**p),
file=connects)
def run():
luts = lut_maker.LutMaker()
connects = io.StringIO()
tile_params = []
params = []
sites = sorted(list(gen_sites()))
for idx, ((tile, site), isone) in enumerate(zip(
sites, util.gen_fuzz_states(len(sites)))):
p = {}
p['tile'] = tile
p['site'] = site
p['isone'] = isone
params.append(p)
tile_params.append((tile, p['isone'], site))
write_params(tile_params)
print('''
module top();
''')
# Always output a LUT6 to make placer happy.
print('''
(* KEEP, DONT_TOUCH *)
LUT6 dummy_lut();
''')
# Need IDELAYCTRL for IDEALAYs
print('''
(* KEEP, DONT_TOUCH *)
IDELAYCTRL();
''')
for p in params:
use_idelay(p, luts, connects)
for l in luts.create_wires_and_luts():
print(l)
print(connects.getvalue())
print("endmodule")
if __name__ == '__main__':
run()

View File

@ -96,8 +96,8 @@ def add_tile_bits(
max_frames = tile_frames.get_tile_frames(baseaddr)
if frames > max_frames:
print(
"Warning: The number of frames specified for the tile {} ({}) exceeds the maximum allowed value ({}). Falling back to the maximum value."
.format(tile_name, frames, max_frames))
"Warning: The number of frames for base address {} specified for the tile {} ({}) exceeds the maximum allowed value ({}). Falling back to the maximum value."
.format(hex(baseaddr), tile_name, frames, max_frames))
frames = max_frames
# If frames count is None then use the maximum
if frames is None:

View File

@ -20,9 +20,12 @@ set fp [open "cmt_regions.csv" "w"]
foreach site_type { IOB33M IOB33S IDELAYCTRL} {
foreach site [get_sites -filter "SITE_TYPE == $site_type"] {
set tile [get_tiles -of $site]
# exclude IDELAYCTRL from high speed banks
if {![string match "*_IOI_*" $tile]} {
puts $fp "$site,$tile,[get_property CLOCK_REGION $site]"
}
}
}
close $fp
set fp [open "pudc_sites.csv" "w"]

View File

@ -0,0 +1,41 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
N := 80
SPECIMENS_DEPS := build/iobanks.txt
include ../fuzzer.mk
database: build/segbits_riob18.db build/segbits_hclk_ioi.db
build/iobanks.txt: write_io_banks.tcl
mkdir -p build
cd build/ && ${XRAY_VIVADO} -mode batch -source ../write_io_banks.tcl
build/segbits_riob18.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -c 23 -o build/segbits_riob18.rdb $$(find -name segdata_riob18.txt)
build/segbits_riob18.db: build/segbits_riob18.rdb process_rdb.py bits.dbf
# delete the Y1 LVDS tags because they are empty anyway and are missing the DRIVE tag which upsets process_rdb.py
sed '/IOB18.IOB_Y1.LVDS/d' -i build/segbits_riob18.rdb
python3 process_rdb.py build/segbits_riob18.rdb > build/segbits_riob18_processed.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --groups tag_groups.txt --seg-fn-in build/segbits_riob18_processed.rdb --seg-fn-out $@
${XRAY_MASKMERGE} build/mask_riob18.db $$(find -name segdata_riob18.txt)
build/segbits_hclk_ioi.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -c 10 -o build/segbits_hclk_ioi.rdb $$(find -name segdata_hclk_ioi.txt)
build/segbits_hclk_ioi.db: build/segbits_hclk_ioi.rdb
${XRAY_DBFIXUP} --db-root build --zero-db hclk_bits.dbf --seg-fn-in build/segbits_hclk_ioi.rdb --seg-fn-out $@
pushdb:
${XRAY_MERGEDB} riob18 build/segbits_riob18.db
${XRAY_MERGEDB} mask_riob18 build/mask_riob18.db
${XRAY_MERGEDB} hclk_ioi build/segbits_hclk_ioi.db
.PHONY: database pushdb

View File

@ -0,0 +1,2 @@
# IOB18 Fuzzer

View File

View File

@ -0,0 +1,235 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
""" Sanity checks FASM output from IOB fuzzer.
The IOB fuzzer is fairly complicated, and it's output is hard to verify by
inspection. For this reason, check_results.py was written to compare the
specimen's generated and their FASM output. The FASM output does pose a
chicken and egg issue. The test procedure is a follows:
1. Build the database (e.g. make -j<N> run)
2. Build the database again (e.g. make -j<N> run)
3. Run check_results.py
The second time that the database is run, the FASM files in the specimen's
will have the bits documented by fuzzer.
"""
import argparse
import os
import os.path
from prjxray import verilog
import json
import generate
def process_parts(parts):
if len(parts) == 0:
return
if parts[-1] == 'IN_ONLY':
yield 'type', ['IBUF', 'IBUFDS']
if len(parts) > 2 and parts[-2] == 'SLEW':
yield 'SLEW', verilog.quote(parts[-1])
if parts[0] == 'PULLTYPE':
yield 'PULLTYPE', verilog.quote(parts[1])
if len(parts) > 1 and parts[1] == 'IN':
yield 'IOSTANDARDS', parts[0].split('_')
yield 'IN', True
if len(parts) > 1 and parts[1] == 'IN_DIFF':
yield 'IOSTANDARDS', parts[0].split('_')
yield 'IN_DIFF', True
if len(parts) > 1 and parts[1] == 'DRIVE':
yield 'IOSTANDARDS', parts[0].split('_')
if parts[2] == 'I_FIXED':
yield 'DRIVES', [None]
else:
yield 'DRIVES', parts[2].split('_')
def create_sites_from_fasm(fasm_file):
sites = {}
diff_tiles = set()
with open(fasm_file) as f:
for l in f:
if 'IOB18' not in l:
continue
parts = l.strip().split('.')
tile = parts[0]
site = parts[1]
if 'OUT_DIFF' == site:
diff_tiles.add(tile)
continue
if (tile, site) not in sites:
sites[(tile, site)] = {
'tile': tile,
'site_key': site,
}
if len(parts) > 3 and 'IN_DIFF' == parts[3]:
diff_tiles.add(tile)
for key, value in process_parts(parts[2:]):
sites[(tile, site)][key] = value
for key in sites:
if 'type' not in sites[key]:
if 'IOSTANDARDS' not in sites[key]:
sites[key]['type'] = [None]
else:
assert 'IOSTANDARDS' in sites[key], sites[key]
assert 'DRIVES' in sites[key], sites[key]
if 'IN' in sites[key]:
sites[key]['type'] = ['IOBUF', 'IOBUF_DCIEN']
else:
sites[key]['type'] = [
"OBUF",
"OBUFDS",
"OBUFTDS",
"OBUFDS_DUAL_BUF",
"OBUFTDS_DUAL_BUF",
]
return sites, diff_tiles
def process_specimen(fasm_file, params_json):
sites, diff_tiles = create_sites_from_fasm(fasm_file)
with open(params_json) as f:
params = json.load(f)
count = 0
for p in params['tiles']:
tile = p['tile']
for site in p['site'].split(' '):
site_y = int(site[site.find('Y') + 1:]) % 2
if generate.skip_broken_tiles(p):
continue
site_key = 'IOB_Y{}'.format(site_y)
if (tile, site_key) not in sites:
assert p['type'] is None, p
continue
site_from_fasm = sites[(tile, site_key)]
if site_y == 0 or tile not in diff_tiles:
assert p['type'] in site_from_fasm['type'], (
tile, site_key, p['type'], site_from_fasm['type'])
else:
# Y1 on DIFF tiles is always none.
assert p['type'] is None, p
if p['type'] is None:
continue
assert 'PULLTYPE' in p, p
assert 'PULLTYPE' in site_from_fasm, site_from_fasm
if verilog.unquote(p['PULLTYPE']) == '':
# Default is None.
pulltype = verilog.quote('NONE')
else:
pulltype = p['PULLTYPE']
assert pulltype == site_from_fasm['PULLTYPE'], (
tile, site_key, p, site_from_fasm)
assert 'IOSTANDARDS' in site_from_fasm, (tile, site)
iostandard = verilog.unquote(p['IOSTANDARD'])
if iostandard.startswith('DIFF_'):
iostandard = iostandard[5:]
assert iostandard in site_from_fasm['IOSTANDARDS'], (
p['IOSTANDARD'],
site_from_fasm['IOSTANDARDS'],
)
if p['type'] not in ['IBUF', 'IBUFDS']:
if verilog.unquote(p['SLEW']) == '':
# Default is None.
slew = verilog.quote('SLOW')
else:
slew = p['SLEW']
assert slew == site_from_fasm['SLEW'], (
tile, site_key, p, site_from_fasm)
assert 'DRIVES' not in p, p
assert 'DRIVES' in site_from_fasm, (
tile, site, p['type'], site_from_fasm)
if p['DRIVE'] is None:
assert None in site_from_fasm['DRIVES'], (
tile, site_key, p['DRIVE'], site_from_fasm['DRIVES'])
elif p['DRIVE'] == '':
if None in site_from_fasm['DRIVES']:
# IOSTANDARD has not DRIVE setting, ignore
pass
else:
# Check that drive is at default
assert 'I12' in site_from_fasm['DRIVES'], (
tile, site_key, p['DRIVE'],
site_from_fasm['DRIVES'])
else:
assert 'I{}'.format(
p['DRIVE']) in site_from_fasm['DRIVES'], (
tile, site_key, p['DRIVE'],
site_from_fasm['DRIVES'])
count += 1
return count
def scan_specimens():
for root, dirs, files in os.walk('build'):
if os.path.basename(root).startswith('specimen_'):
print('Processing', os.path.basename(root))
process_specimen(
fasm_file=os.path.join(root, 'design.fasm'),
params_json=os.path.join(root, 'params.json'))
print('No errors found!')
def main():
parser = argparse.ArgumentParser(description="Verify IOB FASM vs BELs.")
parser.add_argument('--fasm')
parser.add_argument('--params')
args = parser.parse_args()
if not args.fasm and not args.params:
scan_specimens()
else:
count = process_specimen(fasm_file=args.fasm, params_json=args.params)
print('No errors found in {} IO sites'.format(count))
if __name__ == "__main__":
main()

View File

@ -0,0 +1,302 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
from prjxray.segmaker import Segmaker
from prjxray import segmaker
from prjxray import verilog
import os
import json
import csv
from iostandards import *
def bitfilter(frame, word):
# the fuzzers seem to find bits in frame 24 which seems
# to be used by other tile types
if frame < 30:
return False
return True
def mk_drive_opt(iostandard, drive):
if drive is None:
drive = '_FIXED'
return '{}.DRIVE.I{}'.format(iostandard, drive)
def drives_for_iostandard(iostandard):
if iostandard in ['LVCMOS18', 'LVCMOS15']:
drives = [2, 4, 6, 8, 12, 16]
elif iostandard == 'LVCMOS12':
drives = [2, 4, 6, 8]
elif iostandard in SSTL + DIFF_SSTL:
return ['_FIXED']
else:
assert False, "this line should be unreachable"
return drives
STEPDOWN_IOSTANDARDS = LVCMOS + SSTL
IBUF_LOW_PWR_SUPPORTED = LVDS + DIFF_SSTL
ONLY_DIFF_IOSTANDARDS = LVDS
def main():
# Create map of iobank -> sites
iobanks = {}
site_to_iobank = {}
iobank_iostandards = {}
with open(os.path.join(os.getenv('FUZDIR'), 'build', 'iobanks.txt')) as f:
for l in f:
iob_site, iobank = l.strip().split(',')
iobank = int(iobank)
if iobank not in iobanks:
iobanks[iobank] = set()
iobanks[iobank].add(iob_site)
assert iob_site not in site_to_iobank
site_to_iobank[iob_site] = iobank
for iobank in iobanks:
iobank_iostandards[iobank] = set()
# Load a list of PUDC_B pin function tiles. They are configured differently
# by the vendor tools so need to be skipped
pudc_tiles = set()
with open(os.path.join(os.getenv('FUZDIR'), 'build',
'pudc_sites.csv')) as f:
for l in csv.DictReader(f):
pudc_tiles.add(l["tile"])
print("Loading tags")
segmk = Segmaker("design.bits")
'''
port,site,tile,pin,slew,drive,pulltype
di[0],IOB_X1Y107,RIOB18_X1Y107,AF4,PULLDOWN
di[10],IOB_X1Y147,RIOB18_X1Y147,U5,PULLUP
'''
with open('params.json', 'r') as f:
design = json.load(f)
diff_pairs = set()
for d in design['tiles']:
iostandard = verilog.unquote(d['IOSTANDARD'])
if iostandard.startswith('DIFF_'):
diff_pairs.add(d['pair_site'])
for d in design['tiles']:
site = d['site']
tile = d['tile']
if tile in pudc_tiles:
continue
if site in diff_pairs:
continue
iostandard = verilog.unquote(d['IOSTANDARD'])
if iostandard.startswith('DIFF_'):
iostandard = iostandard[5:]
iobank_iostandards[site_to_iobank[site]].add(iostandard)
only_diff_io = iostandard in ONLY_DIFF_IOSTANDARDS
if d['type'] is None:
segmk.add_site_tag(site, 'INOUT', 0)
segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 0)
segmk.add_site_tag(site, '{}.IN'.format(iostandard), 0)
segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 0)
segmk.add_site_tag(site, '{}.IN_ONLY'.format(iostandard), 0)
elif d['type'] == 'IBUF':
segmk.add_site_tag(site, 'INOUT', 0)
segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1)
segmk.add_site_tag(site, '{}.IN'.format(iostandard), 1)
segmk.add_site_tag(site, '{}.IN_DIFF'.format(iostandard), 0)
segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 0)
segmk.add_site_tag(site, '{}.IN_ONLY'.format(iostandard), 1)
segmk.add_tile_tag(tile, 'IN_DIFF', 0)
if iostandard in IBUF_LOW_PWR_SUPPORTED:
segmk.add_site_tag(site, 'IBUF_LOW_PWR', d['IBUF_LOW_PWR'])
segmk.add_site_tag(site, 'ZIBUF_LOW_PWR', 1 ^ d['IBUF_LOW_PWR'])
elif d['type'] == 'IBUFDS':
psite = d['pair_site']
segmk.add_site_tag(site, 'INOUT', 0)
segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1)
segmk.add_site_tag(site, '{}.IN'.format(iostandard), 1)
segmk.add_site_tag(site, '{}.IN_DIFF'.format(iostandard), 1)
segmk.add_site_tag(psite, '{}.IN_DIFF'.format(iostandard), 1)
segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 0)
segmk.add_site_tag(site, '{}.IN_ONLY'.format(iostandard), 1)
segmk.add_tile_tag(tile, 'IN_DIFF', 1)
if iostandard in IBUF_LOW_PWR_SUPPORTED:
segmk.add_tile_tag(tile, 'DIFF.IBUF_LOW_PWR', d['IBUF_LOW_PWR'])
segmk.add_tile_tag(tile, 'DIFF.ZIBUF_LOW_PWR', 1 ^ d['IBUF_LOW_PWR'])
elif d['type'] == 'OBUF':
segmk.add_site_tag(site, 'INOUT', 0)
segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1)
segmk.add_site_tag(site, '{}.IN'.format(iostandard), 0)
segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 1)
segmk.add_tile_tag(tile, 'OUT_DIFF', 0)
elif d['type'] == 'OBUFDS':
segmk.add_site_tag(site, 'INOUT', 0)
segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1)
segmk.add_site_tag(site, '{}.IN'.format(iostandard), 0)
segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 1)
segmk.add_tile_tag(tile, 'OUT_DIFF', 1 and not only_diff_io)
segmk.add_tile_tag(tile, 'OUT_TDIFF', 0)
elif d['type'] == 'OBUFTDS':
segmk.add_site_tag(site, 'INOUT', 0)
segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1)
segmk.add_site_tag(site, '{}.IN'.format(iostandard), 0)
segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 1)
segmk.add_tile_tag(tile, 'OUT_DIFF', 1 and not only_diff_io)
segmk.add_tile_tag(tile, 'OUT_TDIFF', 1 and not only_diff_io)
elif d['type'] == 'IOBUF_DCIEN':
segmk.add_site_tag(site, 'INOUT', 1)
segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1)
segmk.add_site_tag(site, '{}.IN'.format(iostandard), 1)
segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 1)
if d['type'] is not None:
segmaker.add_site_group_zero(
segmk, site, "PULLTYPE.",
("NONE", "KEEPER", "PULLDOWN", "PULLUP"), "PULLDOWN",
verilog.unquote(d['PULLTYPE']))
if d['type'] in [None, 'IBUF', 'IBUFDS']:
continue
drive_opts = set()
for opt in LVCMOS:
for drive_opt in ("2", "4", "6", "8", "12", "16"):
if drive_opt in ["12", "16"] and opt == "LVCMOS12":
continue
drive_opts.add(mk_drive_opt(opt, drive_opt))
for sstl in SSTL:
drive_opts.add(mk_drive_opt(sstl, None))
drive_opts.add(mk_drive_opt("LVDS", None))
segmaker.add_site_group_zero(
segmk, site, '', drive_opts, mk_drive_opt('LVCMOS25', '12'),
mk_drive_opt(iostandard, d['DRIVE']))
if d['SLEW']:
for opt in ["SLOW", "FAST"]:
segmk.add_site_tag(
site, iostandard + ".SLEW." + opt,
opt == verilog.unquote(d['SLEW']))
if 'ibufdisable_wire' in d:
segmk.add_site_tag(
site, 'IBUFDISABLE.I', d['ibufdisable_wire'] != '0')
if 'dcitermdisable_wire' in d:
segmk.add_site_tag(
site, 'DCITERMDISABLE.I', d['dcitermdisable_wire'] != '0')
site_to_cmt = {}
site_to_tile = {}
tile_to_cmt = {}
cmt_to_idelay = {}
with open(os.path.join(os.getenv('FUZDIR'), 'build', 'cmt_regions.csv')) as f:
for l in f:
site, tile, cmt = l.strip().split(',')
site_to_tile[site] = tile
site_to_cmt[site] = cmt
tile_to_cmt[tile] = cmt
# Given IDELAYCTRL's are only located in HCLK_IOI tiles, and
# there is only on HCLK_IOI tile per CMT, update
# CMT -> IDELAYCTRL / tile map.
if 'IDELAYCTRL' in site:
assert cmt not in cmt_to_idelay
cmt_to_idelay[cmt] = site, tile
# For each IOBANK with an active VREF set the feature
cmt_vref_active = set()
with open('iobank_vref.csv') as f:
for l in f:
iobank, vref = l.strip().split(',')
iobank = int(iobank)
cmt = None
for cmt_site in iobanks[iobank]:
if cmt_site in site_to_cmt:
cmt = site_to_cmt[cmt_site]
break
if cmt is None:
continue
cmt_vref_active.add(cmt)
_, hclk_cmt_tile = cmt_to_idelay[cmt]
opt = 'VREF.V_{:d}_MV'.format(int(float(vref) * 1000))
segmk.add_tile_tag(hclk_cmt_tile, opt, 1)
for iobank in iobank_iostandards:
if len(iobank_iostandards[iobank]) == 0:
continue
for cmt_site in iobanks[iobank]:
if cmt_site in site_to_cmt:
cmt = site_to_cmt[cmt_site]
break
if cmt is None:
continue
_, hclk_cmt_tile = cmt_to_idelay[cmt]
assert len(iobank_iostandards[iobank]) == 1, iobank_iostandards[iobank]
iostandard = list(iobank_iostandards[iobank])[0]
for only_diff_io in ONLY_DIFF_IOSTANDARDS:
segmk.add_tile_tag(
hclk_cmt_tile, '{}_IN_USE'.format(only_diff_io),
iostandard == only_diff_io)
segmk.add_tile_tag(
hclk_cmt_tile, 'ONLY_DIFF_IN_USE',
iostandard in ONLY_DIFF_IOSTANDARDS)
# For IOBANK's with no active VREF, clear all VREF options.
for cmt, (_, hclk_cmt_tile) in cmt_to_idelay.items():
if cmt in cmt_vref_active:
continue
for vref in (
.600,
.675,
.75,
.90,
):
opt = 'VREF.V_{:d}_MV'.format(int(vref * 1000))
segmk.add_tile_tag(hclk_cmt_tile, opt, 0)
segmk.compile(bitfilter=bitfilter)
segmk.write(allow_empty=True)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,122 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
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 IOB18* [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]
gets $fp line
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]
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 1]
set pin_str [lindex $line 2]
set iostandard [lindex $line 3]
set drive [lindex $line 4]
set slew [lindex $line 5]
set pulltype [lindex $line 6]
# 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 [dict get $io_pin_sites $site]
set props {}
lappend props PACKAGE_PIN $pin
lappend props IOSTANDARD $iostandard
lappend props PULLTYPE $pulltype
if {$drive != "None"} {
lappend props DRIVE $drive
}
if {$slew != "None"} {
lappend props SLEW $slew
}
puts $props
set_property -dict "$props" $port
}
}
proc set_vref {} {
set fp [open "iobank_vref.csv" r]
for {gets $fp line} {$line != ""} {gets $fp line} {
set parts [split $line ","]
set iobank [lindex $parts 0]
set vref [lindex $parts 1]
puts "setting $iobank ([get_iobanks $iobank]) to INTERNAL_VREF $vref"
set_property INTERNAL_VREF $vref [get_iobanks $iobank]
}
}
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
loc_pins
set_vref
set_property CFGBVS GND [current_design]
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_property IS_ENABLED 0 [get_drc_checks {NSTD-1}]
set_property IS_ENABLED 0 [get_drc_checks {UCIO-1}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-79}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-144}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-74}]
write_checkpoint -force design_pre_place.dcp
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
}
run

View File

View File

@ -0,0 +1,17 @@
LVCMOS = ['LVCMOS12', 'LVCMOS15', 'LVCMOS18']
# TODO: add support for digitally controlled impedance (_DCI) and termination (_T)
SSTL = ['SSTL15', #'SSTL15_DCI', 'SSTL15_T_DCI'
'SSTL135', #'SSTL135_DCI', 'SSTL135_T_DCI'
'SSTL12', #'SSTL12_DCI', 'SSTL12_T_DCI'
]
# TODO: add support for digitally controlled impedance (_DCI) and termination (_T)
DIFF_SSTL15 = ['DIFF_SSTL15', ] # 'DIFF_SSTL15_DCI', 'DIFF_SSTL15_T_DCI']
DIFF_SSTL135 = ['DIFF_SSTL135', ] # 'DIFF_SSTL135_DCI', 'DIFF_SSTL135_T_DCI']
DIFF_SSTL12 = ['DIFF_SSTL12', ] # 'DIFF_SSTL12_DCI', 'DIFF_SSTL12_T_DCI']
DIFF_SSTL = DIFF_SSTL15 + DIFF_SSTL135 + DIFF_SSTL12
LVDS = ['LVDS']
DIFF = DIFF_SSTL + LVDS

View File

@ -0,0 +1,251 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
""" IOB bits are more complicated than can be easily expressed to segmaker.
There are couple cases that need to be handled here:
- There are some bits that are always set for IN-only ports, but are cleared
selectively for OUT and INOUT ports.
- There are bits per each IOSTANDARD, in addition to drive patterns. These
can be merged to provide unique "(IOSTANDARD, DRIVE)" bit sets.
"""
import argparse
def get_name(l):
parts = l.strip().split(' ')
return parts[0]
def get_site(l):
return get_name(l).split('.')[1]
def parse_bits(l):
parts = l.strip().split(' ')
if parts[1] in ['<0', '<const0>', '<const1>']:
return frozenset()
else:
return frozenset(parts[1:])
def filter_negbits(site, feature, bits):
lvds_bits = frozenset(['!38_24', "!38_48", "!39_33", '!39_47', '!39_49'])
if "IOB_Y0" in feature and not "LVDS" in feature:
bits = bits.difference(lvds_bits)
if feature.endswith("IOB_Y0.LVCMOS12_LVCMOS15_LVCMOS18.IN"):
bits = bits.difference(frozenset(['!39_01']))
if feature.endswith("IOB_Y1.LVCMOS12_LVCMOS15_LVCMOS18.IN"):
bits = bits.difference(frozenset(['!38_126']))
return bits
def process_features_sets(iostandard_lines):
sites = {}
for iostd_type, iostd_list in iostandard_lines.items():
for iostd_line in iostd_list:
feature = get_name(iostd_line)
feature_parts = feature.split('.')
site = get_site(iostd_line)
iostandard = feature_parts[2]
bits = parse_bits(iostd_line)
key = (site, iostd_type)
if key not in sites:
sites[key] = {}
group = feature_parts[3]
if group not in sites[key]:
sites[key][group] = {}
if group in ['DRIVE', 'SLEW']:
enum = feature_parts[4]
sites[key][group][(iostandard, enum)] = bits
elif group in ['IN', 'IN_DIFF', 'IN_ONLY', 'IN_USE', 'OUT',
'STEPDOWN', 'ZIBUF_LOW_PWR']:
sites[key][group][(iostandard, None)] = bits
else:
assert False, group
for site in sites:
for iostandard, enum in sites[site]['DRIVE']:
sites[site]['DRIVE'][(iostandard, enum)] |= sites[site]['OUT'][(
iostandard, None)]
for iostandard, enum in sites[site]['IN']:
sites[site]['IN_ONLY'][(iostandard, enum)] -= sites[site]['IN'][(
iostandard, enum)]
common_bits = {}
for site, iostd_type in sites:
for group in sites[(site, iostd_type)]:
if (site, group) not in common_bits:
common_bits[(site, group)] = set()
for bits in sites[(site, iostd_type)][group].values():
common_bits[(site, group)] |= bits
slew_in_drives = {}
for site, iostd_type in sites:
common_bits[(site, 'IN')] |= common_bits[(site, 'IN_DIFF')]
common_bits[(site, 'IN_DIFF')] |= common_bits[(site, 'IN')]
# Only DIFF IOSTANDARDS such as LVDS or TMDS do not have DRIVE or SLEW features
if iostd_type == "NORMAL":
key = (site, iostd_type)
common_bits[(site, 'DRIVE')] -= common_bits[(site, 'SLEW')]
common_bits[(site, 'IN_ONLY')] |= common_bits[(site, 'DRIVE')]
for iostandard, enum in sites[key]['DRIVE']:
slew_in_drive = common_bits[
(site, 'SLEW')] & sites[key]['DRIVE'][(iostandard, enum)]
if slew_in_drive:
if (key, iostandard) not in slew_in_drives:
slew_in_drives[(key, iostandard)] = set()
slew_in_drives[(key, iostandard)] |= slew_in_drive
sites[key]['DRIVE'][(iostandard, enum)] -= slew_in_drive
for site, iostandard in slew_in_drives:
for _, enum in sites[site]['SLEW']:
sites[site]['SLEW'][(iostandard,
enum)] |= slew_in_drives[(site, iostandard)]
for site in sites:
for iostandard, enum in sites[site]['DRIVE']:
sites[site]['DRIVE'][(iostandard, enum)] |= sites[site]['IN_USE'][(
iostandard, None)]
for iostandard, enum in sites[site]['IN']:
_, iostd_type = site
if iostd_type == "ONLY_DIFF":
sites[site]['IN_DIFF'][(iostandard, enum)] = \
sites[site]['IN'][(iostandard, enum)]
elif sites[site]['IN_DIFF'][(iostandard, enum)]:
sites[site]['IN_DIFF'][(iostandard, enum)] |= \
sites[site]['IN'][(iostandard, enum)]
for site, iostd_type in sites:
if iostd_type == "NORMAL":
del sites[(site, iostd_type)]['OUT']
allow_zero = ['SLEW']
common_groups = dict()
for site, iostd_type in sites:
if site not in common_groups:
common_groups[site] = dict()
key = (site, iostd_type)
for group in sites[key]:
if iostd_type == "ONLY_DIFF" and group == "IN":
continue
# Merge features that are identical.
#
# For example:
#
# IOB18.IOB_Y1.LVCMOS15.IN 38_42 39_41
# IOB18.IOB_Y1.LVCMOS18.IN 38_42 39_41
#
# Must be grouped.
for (iostandard, enum), bits in sites[key][group].items():
if (bits, group) not in common_groups[site]:
common_groups[site][(bits, group)] = {
'IOSTANDARDS': set(),
'enums': set(),
}
common_groups[site][(bits,
group)]['IOSTANDARDS'].add(iostandard)
if enum is not None:
common_groups[site][(bits, group)]['enums'].add(enum)
visited_iostandards = list()
for site, groups in common_groups.items():
for (bits, group), v in groups.items():
iostandards = v['IOSTANDARDS']
enums = v['enums']
# It happens that some features appear only in one of the IOB sites and not
# in the other. This makes it hard to assign the correct features to the correct
# site in the P&R toolchain.
#
# The following code makes sure that the same set of iostandards
# (even if not really present at a site location) appears for each site
for visited_iostandard, visited_group, visited_enums in visited_iostandards:
same_enum = enums == visited_enums
same_group = group == visited_group
compatible_iostd = any(
x in iostandards for x in visited_iostandard)
take_visited_iostd = len(visited_iostandard) > len(iostandards)
if same_enum and same_group and compatible_iostd and take_visited_iostd:
iostandards = visited_iostandard
break
visited_iostandards.append((iostandards, group, enums))
iostandards_string = '_'.join(sorted(iostandards))
if enums:
feature = 'IOB18.{site}.{iostandards}.{group}.{enums}'.format(
site=site,
iostandards=iostandards_string,
group=group,
enums='_'.join(sorted(enums)),
)
else:
feature = 'IOB18.{site}.{iostandards}.{group}'.format(
site=site,
iostandards=iostandards_string,
group=group,
)
if not bits and group not in allow_zero:
continue
neg_bits = frozenset(
'!{}'.format(b) for b in (common_bits[(site, group)] - bits))
neg_bits = filter_negbits(site, feature, neg_bits)
print('{} {}'.format(feature, ' '.join(sorted(bits | neg_bits))))
def main():
parser = argparse.ArgumentParser(
description="Convert IOB rdb into good rdb."
"")
parser.add_argument('input_rdb')
args = parser.parse_args()
iostandard_lines = {
"NORMAL": list(),
"ONLY_DIFF": list(),
}
with open(args.input_rdb) as f:
for l in f:
if ('.SSTL' in l or '.LVCMOS' in l
or '.LVTTL' in l) and 'IOB_' in l:
iostandard_lines["NORMAL"].append(l)
elif ('.TMDS' in l or 'LVDS' in l):
iostandard_lines["ONLY_DIFF"].append(l)
else:
print(l.strip())
process_features_sets(iostandard_lines)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,2 @@
IOB18.IOB_Y0.PULLTYPE.KEEPER IOB18.IOB_Y0.PULLTYPE.NONE IOB18.IOB_Y0.PULLTYPE.PULLDOWN IOB18.IOB_Y0.PULLTYPE.PULLUP
IOB18.IOB_Y1.PULLTYPE.KEEPER IOB18.IOB_Y1.PULLTYPE.NONE IOB18.IOB_Y1.PULLTYPE.PULLDOWN IOB18.IOB_Y1.PULLTYPE.PULLUP

425
fuzzers/030-iob18/top.py Normal file
View File

@ -0,0 +1,425 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
import json
import io
import os
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray import lut_maker
from prjxray import verilog
from prjxray.db import Database
from iostandards import *
def gen_sites():
'''
IOB18S: main IOB of a diff pair
IOB18M: secondary IOB of a diff pair
IOB18: not a diff pair. Relatively rare (at least in ROI...2 of them?)
Focus on IOB18S to start
'''
db = Database(util.get_db_root(), util.get_part())
grid = db.grid()
for tile_name in sorted(grid.tiles()):
loc = grid.loc_of_tilename(tile_name)
gridinfo = grid.gridinfo_at_loc(loc)
sites = {}
for site_name, site_type in gridinfo.sites.items():
if site_type in ['IOB18S', 'IOB18M']:
sites[site_type] = site_name
if sites:
yield tile_name, sites
def write_params(params):
pinstr = 'tile,site,pin,iostandard,drive,slew,pulltype\n'
for vals in params:
pinstr += ','.join(map(str, vals)) + '\n'
open('params.csv', 'w').write(pinstr)
def run():
tile_types = ['IBUF', 'OBUF', 'IOBUF_DCIEN', None, None]
i_idx = 0
o_idx = 0
io_idx = 0
iostandards = LVCMOS + SSTL + LVDS
diff_map = {
"SSTL15": DIFF_SSTL15,
"SSTL135": DIFF_SSTL135,
"SSTL12": DIFF_SSTL12,
}
only_diff_map = {
"LVDS": ["LVDS"],
}
slews = ['FAST', 'SLOW']
pulls = ["NONE", "KEEPER", "PULLDOWN", "PULLUP"]
luts = lut_maker.LutMaker()
connects = io.StringIO()
tile_params = []
params = {
"tiles": [],
'INTERNAL_VREF': {},
}
with open(os.path.join(os.getenv('FUZDIR'), 'build', 'iobanks.txt')) as f:
iobanks = set()
iob_sites = dict()
for l in f:
fields = l.split(',')
iob_site = fields[0]
iobank = fields[1].rstrip()
iobanks.add(iobank)
iob_sites[iob_site] = iobank
params['iobanks'] = iobanks
iostandard_map = dict()
for iobank in iobanks:
iostandard = random.choice(iostandards)
if iostandard in SSTL:
params['INTERNAL_VREF'][iobank] = random.choice(
(
.600,
.675,
.75,
.90,
))
iostandard_map[iobank] = iostandard
params['iobanks'] = list(iobanks)
any_idelay = False
for tile, sites in gen_sites():
iostandard = None
site_bels = {}
for site_type, site_name in sites.items():
iobank = iob_sites[site_name]
iostandard = iostandard_map[iobank]
if iostandard in ['LVCMOS12']:
drives = [2, 4, 6, 8]
elif iostandard in ['LVCMOS15', 'LVCMOS18']:
drives = [2, 4, 6, 8, 12, 16]
elif iostandard in LVDS + SSTL:
drives = None
else:
assert False, f"Unhandled iostandard: {iostandard}"
if site_type.endswith('M'):
if iostandard in diff_map:
site_bels[site_type] = random.choice(
tile_types + ['IBUFDS', 'OBUFDS', 'OBUFTDS'])
elif iostandard in only_diff_map:
site_bels[site_type] = random.choice(
['IBUFDS', 'OBUFDS', 'OBUFTDS', None, None])
else:
site_bels[site_type] = random.choice(tile_types)
is_m_diff = site_bels[site_type] is not None and site_bels[
site_type].endswith('DS')
else:
site_bels[site_type] = random.choice(tile_types)
if is_m_diff or iostandard in only_diff_map:
site_bels['IOB18S'] = None
for site_type, site in sites.items():
p = {}
p['tile'] = tile
p['site'] = site
p['type'] = site_bels[site_type]
if p['type'] is not None and p['type'].endswith('DS'):
if iostandard in diff_map:
iostandard_site = random.choice(diff_map[iostandard])
elif iostandard in only_diff_map:
iostandard_site = random.choice(only_diff_map[iostandard])
p['pair_site'] = sites['IOB18S']
else:
iostandard_site = iostandard
p['IOSTANDARD'] = verilog.quote(iostandard_site)
p['PULLTYPE'] = verilog.quote(random.choice(pulls))
if p['type'] is None:
p['pad_wire'] = None
elif p['type'] == 'IBUF':
p['pad_wire'] = 'di[{}]'.format(i_idx)
p['IDELAY_ONLY'] = random.randint(0, 1)
if not p['IDELAY_ONLY']:
p['owire'] = luts.get_next_input_net()
else:
any_idelay = True
p['owire'] = 'idelay_{site}'.format(**p)
p['DRIVE'] = None
p['SLEW'] = None
p['IBUF_LOW_PWR'] = random.randint(0, 1)
i_idx += 1
elif p['type'] == 'IBUFDS':
p['pad_wire'] = 'di[{}]'.format(i_idx)
i_idx += 1
p['bpad_wire'] = 'di[{}]'.format(i_idx)
i_idx += 1
p['IDELAY_ONLY'] = random.randint(0, 1)
p['DIFF_TERM'] = random.randint(0, 1) if iostandard in LVDS else 0
if not p['IDELAY_ONLY']:
p['owire'] = luts.get_next_input_net()
else:
any_idelay = True
p['owire'] = 'idelay_{site}'.format(**p)
p['DRIVE'] = None
p['SLEW'] = None
p['IBUF_LOW_PWR'] = random.randint(0, 1)
elif p['type'] == 'OBUF':
p['pad_wire'] = 'do[{}]'.format(o_idx)
p['iwire'] = luts.get_next_output_net()
if drives is not None:
p['DRIVE'] = random.choice(drives)
else:
p['DRIVE'] = None
p['SLEW'] = verilog.quote(random.choice(slews))
o_idx += 1
elif p['type'] == 'OBUFDS':
p['pad_wire'] = 'do[{}]'.format(o_idx)
o_idx += 1
p['bpad_wire'] = 'do[{}]'.format(o_idx)
o_idx += 1
p['iwire'] = luts.get_next_output_net()
if drives is not None:
p['DRIVE'] = random.choice(drives)
else:
p['DRIVE'] = None
p['SLEW'] = verilog.quote(random.choice(slews))
elif p['type'] == 'OBUFTDS':
p['pad_wire'] = 'do[{}]'.format(o_idx)
o_idx += 1
p['bpad_wire'] = 'do[{}]'.format(o_idx)
o_idx += 1
p['tristate_wire'] = random.choice(
('0', luts.get_next_output_net()))
p['iwire'] = luts.get_next_output_net()
if drives is not None:
p['DRIVE'] = random.choice(drives)
else:
p['DRIVE'] = None
p['SLEW'] = verilog.quote(random.choice(slews))
elif p['type'] == 'IOBUF_DCIEN':
p['pad_wire'] = 'dio[{}]'.format(io_idx)
p['iwire'] = luts.get_next_output_net()
p['owire'] = luts.get_next_input_net()
if drives is not None:
p['DRIVE'] = random.choice(drives)
else:
p['DRIVE'] = None
p['SLEW'] = verilog.quote(random.choice(slews))
p['tristate_wire'] = random.choice(
('0', luts.get_next_output_net()))
p['ibufdisable_wire'] = random.choice(
('0', luts.get_next_output_net()))
p['dcitermdisable_wire'] = random.choice(
('0', luts.get_next_output_net()))
io_idx += 1
if 'DRIVE' in p:
if p['DRIVE'] is not None:
p['DRIVE_STR'] = '.DRIVE({}),'.format(p['DRIVE'])
else:
p['DRIVE_STR'] = ''
if 'SLEW' in p:
p['SLEW_STR'] = ''
if iostandard in only_diff_map:
p['SLEW'] = None
elif p['DRIVE'] is not None:
p['SLEW_STR'] = '.SLEW({}),'.format(p['SLEW'])
if p['type'] is not None:
tile_params.append(
(
tile,
site,
p['pad_wire'],
iostandard_site,
p['DRIVE'],
verilog.unquote(p['SLEW']) if p['SLEW'] else None,
verilog.unquote(p['PULLTYPE']),
))
params['tiles'].append(p)
write_params(tile_params)
with open('iobank_vref.csv', 'w') as f:
for iobank, vref in params['INTERNAL_VREF'].items():
f.write('{},{}\n'.format(iobank, vref))
print(
'''
`define N_DI {n_di}
`define N_DO {n_do}
`define N_DIO {n_dio}
module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N_DIO-1:0] dio, input refclk);
'''.format(n_di=i_idx, n_do=o_idx, n_dio=io_idx))
if any_idelay:
print('''
(* KEEP, DONT_TOUCH *)
IDELAYCTRL(.REFCLK(refclk));''')
# Always output a LUT6 to make placer happy.
print('''
(* KEEP, DONT_TOUCH *)
LUT6 dummy_lut();''')
for p in params['tiles']:
if p['type'] is None:
continue
elif p['type'] == 'IBUF':
print(
'''
wire idelay_{site};
(* KEEP, DONT_TOUCH *)
IBUF #(
.IBUF_LOW_PWR({IBUF_LOW_PWR}),
.IOSTANDARD({IOSTANDARD})
) ibuf_{site} (
.I({pad_wire}),
.O({owire})
);'''.format(**p),
file=connects)
if p['IDELAY_ONLY']:
print(
"""
(* KEEP, DONT_TOUCH *)
IDELAYE2 idelay_site_{site} (
.IDATAIN(idelay_{site})
);""".format(**p),
file=connects)
elif p['type'] == 'IBUFDS':
print(
'''
wire idelay_{site};
(* KEEP, DONT_TOUCH *)
IBUFDS #(
.IBUF_LOW_PWR({IBUF_LOW_PWR}),
.DIFF_TERM({DIFF_TERM}),
.IOSTANDARD({IOSTANDARD})
) ibuf_{site} (
.I({pad_wire}),
.IB({bpad_wire}),
.O({owire})
);'''.format(**p),
file=connects)
if p['IDELAY_ONLY']:
print(
"""
(* KEEP, DONT_TOUCH *)
IDELAYE2 idelay_site_{site} (
.IDATAIN(idelay_{site})
);""".format(**p),
file=connects)
elif p['type'] == 'OBUF':
print(
'''
(* KEEP, DONT_TOUCH *)
OBUF #(
{DRIVE_STR}
{SLEW_STR}
.IOSTANDARD({IOSTANDARD})
) obuf_{site} (
.O({pad_wire}),
.I({iwire})
);'''.format(**p),
file=connects)
elif p['type'] == 'OBUFDS':
print(
'''
(* KEEP, DONT_TOUCH *)
OBUFDS #(
{DRIVE_STR}
{SLEW_STR}
.IOSTANDARD({IOSTANDARD})
) obufds_{site} (
.O({pad_wire}),
.OB({bpad_wire}),
.I({iwire})
);'''.format(**p),
file=connects)
elif p['type'] == 'OBUFTDS':
print(
'''
(* KEEP, DONT_TOUCH *)
OBUFTDS #(
{DRIVE_STR}
{SLEW_STR}
.IOSTANDARD({IOSTANDARD})
) obufds_{site} (
.O({pad_wire}),
.OB({bpad_wire}),
.T({tristate_wire}),
.I({iwire})
);'''.format(**p),
file=connects)
elif p['type'] == 'IOBUF_DCIEN':
print(
'''
(* KEEP, DONT_TOUCH *)
IOBUF_DCIEN #(
{DRIVE_STR}
{SLEW_STR}
.IOSTANDARD({IOSTANDARD})
) ibuf_{site} (
.IO({pad_wire}),
.I({iwire}),
.O({owire}),
.T({tristate_wire}),
.IBUFDISABLE({ibufdisable_wire}),
.DCITERMDISABLE({dcitermdisable_wire})
);'''.format(**p),
file=connects)
for l in luts.create_wires_and_luts():
print(l)
print(connects.getvalue())
print("endmodule")
with open('params.json', 'w') as f:
json.dump(params, f, indent=2)
if __name__ == '__main__':
run()

View File

@ -0,0 +1,44 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
create_project -force -part $::env(XRAY_PART) design design
set_property design_mode PinPlanning [current_fileset]
open_io_design -name io_1
set fp [open "iobanks.txt" "w"]
foreach iobank [get_iobanks] {
foreach site [get_sites -of $iobank] {
puts $fp "$site,$iobank"
}
}
close $fp
set fp [open "cmt_regions.csv" "w"]
foreach site_type { IOB18M IOB18S IDELAYCTRL} {
foreach site [get_sites -filter "SITE_TYPE == $site_type"] {
set tile [get_tiles -of $site]
if {![string match "*IOI3*" $tile]} {
puts $fp "$site,$tile,[get_property CLOCK_REGION $site]"
}
}
}
close $fp
set fp [open "pudc_sites.csv" "w"]
puts $fp "tile,site"
foreach tile [get_tiles *IOB18*] {
foreach site [get_sites -of_objects $tile] {
set site_type [get_property SITE_TYPE $site]
set pin [get_package_pins -of_objects $site]
set pin_func [get_property PIN_FUNC $pin]
if {[string first "PUDC_B" $pin_func] != -1} {
puts $fp "$tile,$site,$site_type"
}
}
}
close $fp

View File

@ -22,19 +22,29 @@ build/segbits_xioi3.db: build/segbits_xioi3.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --groups tag_groups.txt --seg-fn-in $^ --seg-fn-out $@
${XRAY_MASKMERGE} build/mask_xioi3.db $$(find -name segdata_*)
pushdb:
# fuzzers of the RIOI tiles give near identical results, so reuse these
build/segbits_rioi.db: build/segbits_xioi3.db
sed 's/IOI3/IOI/g' < $< > $@
pushdb: build/segbits_rioi.db
${XRAY_MERGEDB} lioi3 build/segbits_xioi3.db
${XRAY_MERGEDB} lioi3_tbytesrc build/segbits_xioi3.db
${XRAY_MERGEDB} lioi3_tbyteterm build/segbits_xioi3.db
${XRAY_MERGEDB} rioi3 build/segbits_xioi3.db
${XRAY_MERGEDB} rioi3_tbytesrc build/segbits_xioi3.db
${XRAY_MERGEDB} rioi3_tbyteterm build/segbits_xioi3.db
${XRAY_MERGEDB} rioi build/segbits_rioi.db
${XRAY_MERGEDB} rioi_tbytesrc build/segbits_rioi.db
${XRAY_MERGEDB} rioi_tbyteterm build/segbits_rioi.db
${XRAY_MERGEDB} mask_lioi3 build/mask_xioi3.db
${XRAY_MERGEDB} mask_lioi3_tbytesrc build/mask_xioi3.db
${XRAY_MERGEDB} mask_lioi3_tbyteterm build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi3 build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi3_tbytesrc build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi3_tbyteterm build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi_tbytesrc build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi_tbyteterm build/mask_xioi3.db
.PHONY: database pushdb

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
N := 5
include ../fuzzer.mk
database: build/segbits_riob18.db
build/segbits_riob18.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -m 1 -M 1 -o build/segbits_riob18.rdb $$(find -name segdata_*.txt)
build/segbits_riob18.db: build/segbits_riob18.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --seg-fn-in $^ --seg-fn-out $@
${XRAY_MASKMERGE} build/mask_riob18.db $$(find -name segdata_*.txt)
pushdb:
${XRAY_MERGEDB} rioi build/segbits_riob18.db
${XRAY_MERGEDB} rioi_tbytesrc build/segbits_riob18.db
${XRAY_MERGEDB} rioi_tbyteterm build/segbits_riob18.db
${XRAY_MERGEDB} mask_rioi build/mask_riob18.db
${XRAY_MERGEDB} mask_rioi_tbytesrc build/mask_riob18.db
${XRAY_MERGEDB} mask_rioi_tbyteterm build/mask_riob18.db
.PHONY: database pushdb

View File

@ -0,0 +1,14 @@
34_08 34_14 ,IOI3.IDELAY_Y1.IDELAY_TYPE_FIXED
35_113 35_119 ,IOI3.IDELAY_Y0.IDELAY_TYPE_FIXED
34_120 34_122
34_114 34_116
34_108 34_110
34_100 34_102
34_94 34_96
35_05 35_07
35_11 35_13
35_17 35_19
35_25 35_27
35_31 35_33
34_72 35_69
34_58 35_55

View File

@ -0,0 +1,87 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
import json
from prjxray.segmaker import Segmaker, add_site_group_zero
from prjxray import verilog
def bitfilter(frame, word):
if frame < 26:
return False
return True
def main():
segmk = Segmaker("design.bits", verbose=True)
# Load tags
with open("params.json", "r") as fp:
data = json.load(fp)
idelay_types = ["FIXED", "VARIABLE", "VAR_LOAD"]
delay_srcs = ["IDATAIN", "DATAIN"]
# Output tags
for params in data:
segmk.add_site_tag(params['IDELAY_IN_USE'], 'IN_USE', True)
segmk.add_site_tag(params['IDELAY_NOT_IN_USE'], 'IN_USE', False)
loc = verilog.unquote(params["LOC"])
# Delay type
value = verilog.unquote(params["IDELAY_TYPE"])
value = value.replace(
"_PIPE", "") # VAR_LOAD and VAR_LOAD_PIPE are the same
add_site_group_zero(
segmk, loc, "IDELAY_TYPE_", idelay_types, "FIXED", value)
# Delay value
value = int(params["IDELAY_VALUE"])
for i in range(5):
segmk.add_site_tag(
loc, "IDELAY_VALUE[%01d]" % i, ((value >> i) & 1) != 0)
segmk.add_site_tag(
loc, "ZIDELAY_VALUE[%01d]" % i, ((value >> i) & 1) == 0)
# Delay source
value = verilog.unquote(params["DELAY_SRC"])
for x in delay_srcs:
segmk.add_site_tag(loc, "DELAY_SRC_%s" % x, int(value == x))
value = verilog.unquote(params["CINVCTRL_SEL"])
segmk.add_site_tag(loc, "CINVCTRL_SEL", int(value == "TRUE"))
value = verilog.unquote(params["PIPE_SEL"])
segmk.add_site_tag(loc, "PIPE_SEL", int(value == "TRUE"))
if "IS_C_INVERTED" in params:
segmk.add_site_tag(
loc, "IS_C_INVERTED", int(params["IS_C_INVERTED"]))
segmk.add_site_tag(loc, "ZINV_C", 1 ^ int(params["IS_C_INVERTED"]))
segmk.add_site_tag(
loc, "IS_DATAIN_INVERTED", int(params["IS_DATAIN_INVERTED"]))
if params['IBUF_IN_USE']:
value = verilog.unquote(params["HIGH_PERFORMANCE_MODE"])
segmk.add_site_tag(
loc, "HIGH_PERFORMANCE_MODE", int(value == "TRUE"))
segmk.add_site_tag(
loc, "IS_IDATAIN_INVERTED", int(params["IS_IDATAIN_INVERTED"]))
segmk.compile(bitfilter=bitfilter)
segmk.write()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,31 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
set_property CFGBVS GND [current_design]
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_param tcl.collectionResultDisplayLimit 0
set_property IS_ENABLED 0 [get_drc_checks {NSTD-1}]
set_property IS_ENABLED 0 [get_drc_checks {UCIO-1}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-79}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-81}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-84}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-85}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-87}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-85}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-28}]
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit

View File

@ -0,0 +1,237 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
import os, random
random.seed(int(os.getenv("SEED"), 16))
import re
import json
from prjxray import util
from prjxray.db import Database
# =============================================================================
def gen_sites():
db = Database(util.get_db_root(), util.get_part())
grid = db.grid()
tile_list = []
for tile_name in sorted(grid.tiles()):
if "IOB18" not in tile_name or "SING" in tile_name:
continue
tile_list.append(tile_name)
get_xy = util.create_xy_fun('RIOB18_')
tile_list.sort(key=get_xy)
for iob_tile_name in tile_list:
iob_gridinfo = grid.gridinfo_at_loc(
grid.loc_of_tilename(iob_tile_name))
# Find IOI tile adjacent to IOB
for suffix in ["IOI", "IOI_TBYTESRC", "IOI_TBYTETERM"]:
try:
ioi_tile_name = iob_tile_name.replace("IOB18", suffix)
ioi_gridinfo = grid.gridinfo_at_loc(
grid.loc_of_tilename(ioi_tile_name))
break
except KeyError:
pass
iob18s = [k for k, v in iob_gridinfo.sites.items() if v == "IOB18S"][0]
iob18m = [k for k, v in iob_gridinfo.sites.items() if v == "IOB18M"][0]
idelay_s = iob18s.replace("IOB", "IDELAY")
idelay_m = iob18m.replace("IOB", "IDELAY")
yield iob18m, idelay_m, iob18s, idelay_s
def run():
# Get all [LR]IOI3 tiles
tiles = list(gen_sites())
# Header
print("// Tile count: %d" % len(tiles))
print("// Seed: '%s'" % os.getenv("SEED"))
ninputs = 0
di_idx = []
for i, sites in enumerate(tiles):
if random.randint(0, 1):
di_idx.append(ninputs)
ninputs += 1
else:
di_idx.append(None)
print(
'''
module top (
(* CLOCK_BUFFER_TYPE = "NONE" *)
input wire clk,
input wire [{N}:0] di
);
wire clk_buf = clk;
wire [{N}:0] di_buf;
'''.format(N=ninputs - 1))
# LOCes IOBs
data = []
for i, (sites, ibuf_idx) in enumerate(zip(tiles, di_idx)):
if random.randint(0, 1):
iob_i = sites[0]
iob_o = sites[2]
idelay = sites[1]
other_idelay = sites[3]
else:
iob_i = sites[2]
iob_o = sites[0]
idelay = sites[3]
other_idelay = sites[1]
use_ibuf = ibuf_idx is not None
DELAY_SRC = random.choice(["IDATAIN", "DATAIN"])
if not use_ibuf:
DELAY_SRC = 'DATAIN'
params = {
"LOC":
"\"" + idelay + "\"",
"IDELAY_TYPE":
"\"" + random.choice(
["FIXED", "VARIABLE", "VAR_LOAD", "VAR_LOAD_PIPE"]) + "\"",
"IDELAY_VALUE":
random.randint(0, 31),
"DELAY_SRC":
"\"" + DELAY_SRC + "\"",
"HIGH_PERFORMANCE_MODE":
"\"" + random.choice(["TRUE", "FALSE"]) + "\"",
"CINVCTRL_SEL":
"\"" + random.choice(["TRUE", "FALSE"]) + "\"",
"PIPE_SEL":
"\"" + random.choice(["TRUE", "FALSE"]) + "\"",
"IS_C_INVERTED":
random.randint(0, 1),
"IS_DATAIN_INVERTED":
random.randint(0, 1),
"IS_IDATAIN_INVERTED":
random.randint(0, 1),
}
if params["IDELAY_TYPE"] != "\"VAR_LOAD_PIPE\"":
params["PIPE_SEL"] = "\"FALSE\""
# The datasheet says that for these two modes the delay is set to 0
if params["IDELAY_TYPE"] == "\"VAR_LOAD\"":
params["IDELAY_VALUE"] = 0
if params["IDELAY_TYPE"] == "\"VAR_LOAD_PIPE\"":
params["IDELAY_VALUE"] = 0
if params["IDELAY_TYPE"] == "\"FIXED\"":
params["IS_C_INVERTED"] = 0
param_str = ",".join(".%s(%s)" % (k, v) for k, v in params.items())
if use_ibuf:
print('')
print('(* LOC="%s", KEEP, DONT_TOUCH *)' % iob_i)
print(
'IBUF ibuf_%03d (.I(di[%3d]), .O(di_buf[%3d]));' %
(ibuf_idx, ibuf_idx, ibuf_idx))
print(
'mod #(%s) mod_%03d (.clk(clk_buf), .I(di_buf[%3d]));' %
(param_str, i, ibuf_idx))
else:
print('mod #(%s) mod_%03d (.clk(clk_buf), .I());' % (param_str, i))
params['IBUF_IN_USE'] = use_ibuf
params["IDELAY_IN_USE"] = idelay
params["IDELAY_NOT_IN_USE"] = other_idelay
data.append(params)
# Store params
with open("params.json", "w") as fp:
json.dump(data, fp, sort_keys=True, indent=1)
print(
'''
// IDELAYCTRL
(* KEEP, DONT_TOUCH *)
IDELAYCTRL idelayctrl();
endmodule
(* KEEP, DONT_TOUCH *)
module mod(
input wire clk,
input wire I
);
parameter LOC = "";
parameter IDELAY_TYPE = "FIXED";
parameter IDELAY_VALUE = 0;
parameter DELAY_SRC = "IDATAIN";
parameter HIGH_PERFORMANCE_MODE = "TRUE";
parameter SIGNAL_PATTERN = "DATA";
parameter CINVCTRL_SEL = "FALSE";
parameter PIPE_SEL = "FALSE";
parameter IS_C_INVERTED = 0;
parameter IS_DATAIN_INVERTED = 0;
parameter IS_IDATAIN_INVERTED = 0;
wire x;
wire lut;
(* KEEP, DONT_TOUCH *)
LUT2 l( .O(lut) );
// IDELAY
(* LOC=LOC, KEEP, DONT_TOUCH *)
IDELAYE2 #(
.IDELAY_TYPE(IDELAY_TYPE),
.IDELAY_VALUE(IDELAY_VALUE),
.DELAY_SRC(DELAY_SRC),
.HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE),
.SIGNAL_PATTERN(SIGNAL_PATTERN),
.CINVCTRL_SEL(CINVCTRL_SEL),
.PIPE_SEL(PIPE_SEL),
.IS_C_INVERTED(IS_C_INVERTED),
.IS_DATAIN_INVERTED(IS_DATAIN_INVERTED),
.IS_IDATAIN_INVERTED(IS_IDATAIN_INVERTED)
)
idelay
(
.C(clk),
.REGRST(),
.LD(),
.CE(),
.INC(),
.CINVCTRL(),
.CNTVALUEIN(),
.IDATAIN(I),
.DATAIN(lut),
.LDPIPEEN(),
.DATAOUT(x),
.CNTVALUEOUT()
);
endmodule
''')
run()

View File

@ -22,19 +22,30 @@ build/segbits_xioi3.db: build/segbits_xioi3.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --groups tag_groups.txt --seg-fn-in $^ --seg-fn-out $@
${XRAY_MASKMERGE} build/mask_xioi3.db $$(find -name segdata_*.txt)
pushdb:
# running the fuzzers for RIOI tiles yields mostly identical
# results, so reuse the results of IOI3 tiles
build/segbits_rioi.db: build/segbits_xioi3.db
sed 's/IOI3/IOI/g' < $< > $@
pushdb: build/segbits_rioi.db
${XRAY_MERGEDB} lioi3 build/segbits_xioi3.db
${XRAY_MERGEDB} lioi3_tbytesrc build/segbits_xioi3.db
${XRAY_MERGEDB} lioi3_tbyteterm build/segbits_xioi3.db
${XRAY_MERGEDB} rioi3 build/segbits_xioi3.db
${XRAY_MERGEDB} rioi3_tbytesrc build/segbits_xioi3.db
${XRAY_MERGEDB} rioi3_tbyteterm build/segbits_xioi3.db
${XRAY_MERGEDB} rioi build/segbits_rioi.db
${XRAY_MERGEDB} rioi_tbytesrc build/segbits_rioi.db
${XRAY_MERGEDB} rioi_tbyteterm build/segbits_rioi.db
${XRAY_MERGEDB} mask_lioi3 build/mask_xioi3.db
${XRAY_MERGEDB} mask_lioi3_tbytesrc build/mask_xioi3.db
${XRAY_MERGEDB} mask_lioi3_tbyteterm build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi3 build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi3_tbytesrc build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi3_tbyteterm build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi_tbytesrc build/mask_xioi3.db
${XRAY_MERGEDB} mask_rioi_tbyteterm build/mask_xioi3.db
.PHONY: database pushdb

View File

@ -0,0 +1,29 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
N := 40
include ../fuzzer.mk
database: build/segbits_rioi.db
build/segbits_rioi.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -c 7 -o build/segbits_rioi.rdb $$(find -name segdata_*)
build/segbits_rioi.db: build/segbits_rioi.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --seg-fn-in $^ --seg-fn-out $@
${XRAY_MASKMERGE} build/mask_rioi.db $$(find -name segdata_*)
pushdb:
${XRAY_MERGEDB} rioi build/segbits_rioi.db
${XRAY_MERGEDB} rioi_tbytesrc build/segbits_rioi.db
${XRAY_MERGEDB} rioi_tbyteterm build/segbits_rioi.db
${XRAY_MERGEDB} mask_rioi build/mask_rioi.db
${XRAY_MERGEDB} mask_rioi_tbytesrc build/mask_rioi.db
${XRAY_MERGEDB} mask_rioi_tbyteterm build/mask_rioi.db
.PHONY: database pushdb

View File

@ -0,0 +1,8 @@
31_92,IOB33.IOB_Y0.ODDR.DDR_CLK_EDGE.OPPOSITE_EDGE
30_35,IOB33.IOB_Y1.ODDR.DDR_CLK_EDGE.OPPOSITE_EDGE
33_91 33_93
32_36 32_34
33_61 32_58 33_57
32_70 32_66 33_69
30_95 30_99 30_127 31_126 31_124 30_121 31_120 30_123 31_116 31_100
31_00 30_01 30_03 31_06 30_07 31_04 30_11 31_28 31_32 30_29 30_27

View File

@ -0,0 +1,196 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
from prjxray.segmaker import Segmaker
from prjxray import verilog
import json
# Set to true to enable additional tags useful for tracing bit toggles.
DEBUG_FUZZER = False
def bitfilter(frame, word):
# TODO: do we need this here?
# this frame number limit does not seem
# to apply to 1.8V high speed banks
#if frame < 30 or frame > 37:
# return False
return True
def handle_data_width(segmk, d):
if 'DATA_WIDTH' not in d:
return
site = d['ologic_loc']
data_rate = verilog.unquote(d['DATA_RATE_OQ'])
segmk.add_site_tag(
site, 'OSERDES.DATA_WIDTH.{}.W{}'.format(data_rate, d['DATA_WIDTH']),
1)
def no_oserdes(segmk, site):
for mode in ['SDR', 'DDR']:
if mode == 'SDR':
widths = [2, 3, 4, 5, 6, 7, 8]
else:
assert mode == 'DDR'
widths = [4, 6, 8]
for opt in widths:
segmk.add_site_tag(
site, 'OSERDES.DATA_WIDTH.{}.W{}'.format(mode, opt), 0)
def main():
print("Loading tags")
segmk = Segmaker("design.bits")
with open('params.jl', 'r') as f:
design = json.load(f)
for d in design:
site = d['ologic_loc']
handle_data_width(segmk, d)
segmk.add_site_tag(site, 'OSERDES.IN_USE', d['use_oserdese2'])
if d['use_oserdese2']:
segmk.add_site_tag(site, 'OQUSED', 1)
for opt in ['SDR', 'DDR']:
segmk.add_site_tag(
site, 'OSERDES.DATA_RATE_OQ.{}'.format(opt),
verilog.unquote(d['DATA_RATE_OQ']) == opt)
data_rate_tq = verilog.unquote(d['DATA_RATE_TQ'])
segmk.add_site_tag(
site, 'OSERDES.DATA_RATE_TQ.{}'.format(data_rate_tq), 1)
for opt in ['BUF', 'SDR', 'DDR']:
segmk.add_site_tag(
site, 'OSERDES.DATA_RATE_TQ.{}'.format(opt),
opt == data_rate_tq)
for opt in ['SRVAL_OQ', 'SRVAL_TQ', 'INIT_OQ', 'INIT_TQ']:
segmk.add_site_tag(site, opt, d[opt])
segmk.add_site_tag(site, 'Z' + opt, 1 ^ d[opt])
for opt in ['CLK', 'CLKDIV']:
if d['{}_USED'.format(opt)]:
k = 'IS_{}_INVERTED'.format(opt)
segmk.add_site_tag(site, k, d[k])
segmk.add_site_tag(
site, 'ZINV_{}'.format(opt), 1 ^ d[k])
if d['io']:
for idx in range(4):
k = 'IS_T{}_INVERTED'.format(idx + 1)
segmk.add_site_tag(site, k, d[k])
segmk.add_site_tag(
site, 'ZINV_T{}'.format(idx + 1), 1 ^ d[k])
for idx in range(8):
k = 'IS_D{}_INVERTED'.format(idx + 1)
segmk.add_site_tag(site, k, d[k])
segmk.add_site_tag(
site, 'ZINV_D{}'.format(idx + 1), 1 ^ d[k])
for tristate_width in [1, 4]:
segmk.add_site_tag(
site,
'OSERDES.TRISTATE_WIDTH.W{}'.format(tristate_width),
d['TRISTATE_WIDTH'] == tristate_width)
for opt in ['MASTER', 'SLAVE']:
segmk.add_site_tag(
site, 'OSERDES.SERDES_MODE.{}'.format(opt),
opt == verilog.unquote(d['OSERDES_MODE']))
if 'o_sr_used' in d:
if d['o_sr_used'] in ['S', 'R']:
segmk.add_site_tag(site, 'ODDR.SRUSED', 1)
segmk.add_site_tag(site, 'ODDR.ZSRUSED', 0)
else:
assert d['o_sr_used'] == 'None'
segmk.add_site_tag(site, 'ODDR.SRUSED', 0)
segmk.add_site_tag(site, 'ODDR.ZSRUSED', 1)
if 't_sr_used' in d:
if d['t_sr_used'] in ['S', 'R']:
segmk.add_site_tag(site, 'TDDR.SRUSED', 1)
segmk.add_site_tag(site, 'TDDR.ZSRUSED', 0)
else:
assert d['t_sr_used'] == 'None'
segmk.add_site_tag(site, 'TDDR.SRUSED', 0)
segmk.add_site_tag(site, 'TDDR.ZSRUSED', 1)
if d['oddr_mux_config'] == 'direct':
segmk.add_site_tag(site, 'ODDR_TDDR.IN_USE', 1)
if d['tddr_mux_config'] == 'direct':
segmk.add_site_tag(site, 'ODDR_TDDR.IN_USE', 1)
if d['oddr_mux_config'] == 'direct' and d[
'tddr_mux_config'] == 'direct':
segmk.add_site_tag(site, 'ZINV_CLK', 1 ^ d['IS_CLK_INVERTED'])
if d['IS_CLK_INVERTED'] == 0:
for opt in ['OPPOSITE_EDGE', 'SAME_EDGE']:
segmk.add_site_tag(
site, 'ODDR.DDR_CLK_EDGE.{}'.format(opt),
verilog.unquote(d['ODDR_CLK_EDGE']) == opt)
segmk.add_site_tag(
site, 'TDDR.DDR_CLK_EDGE.INV',
d['ODDR_CLK_EDGE'] != d['TDDR_CLK_EDGE'])
segmk.add_site_tag(
site, 'TDDR.DDR_CLK_EDGE.ZINV',
d['ODDR_CLK_EDGE'] == d['TDDR_CLK_EDGE'])
if 'SRTYPE' in d:
for opt in ['ASYNC', 'SYNC']:
segmk.add_site_tag(
site, 'OSERDES.SRTYPE.{}'.format(opt),
verilog.unquote(d['SRTYPE']) == opt)
for opt in ['ASYNC', 'SYNC']:
segmk.add_site_tag(
site, 'OSERDES.TSRTYPE.{}'.format(opt),
verilog.unquote(d['TSRTYPE']) == opt)
if not d['use_oserdese2']:
no_oserdes(segmk, site)
if d['oddr_mux_config'] == 'lut':
segmk.add_site_tag(site, 'ODDR_TDDR.IN_USE', 0)
segmk.add_site_tag(site, 'OMUX.D1', 1)
segmk.add_site_tag(site, 'OQUSED', 1)
elif d['oddr_mux_config'] == 'direct':
segmk.add_site_tag(site, 'OMUX.D1', 0)
elif d['oddr_mux_config'] == 'none' and not d['io']:
segmk.add_site_tag(site, 'OQUSED', 0)
segmk.add_site_tag(site, 'TQUSED', d['io'])
if DEBUG_FUZZER:
for k in d:
segmk.add_site_tag(
site, 'param_' + k + '_' + str(d[k]).replace(
' ', '').replace('\n', ''), 1)
segmk.compile(bitfilter=bitfilter)
segmk.write(allow_empty=True)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,107 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
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 IOB18* [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]
gets $fp line
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]
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 1]
set pin_str [lindex $line 2]
set iostandard [lindex $line 3]
set drive [lindex $line 4]
set slew [lindex $line 5]
set pulltype [lindex $line 6]
# 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 [dict get $io_pin_sites $site]
set props {}
#lappend props PACKAGE_PIN $pin
lappend props IOSTANDARD $iostandard
lappend props PULLTYPE $pulltype
if {$drive != "None"} {
lappend props DRIVE $drive
}
if {$slew != "None"} {
lappend props SLEW $slew
}
puts $props
set_property -dict "$props" $port
}
}
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
loc_pins
set_property CFGBVS GND [current_design]
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_property IS_ENABLED 0 [get_drc_checks {REQP-79}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-144}]
write_checkpoint -force design_pre_place.dcp
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
}
run

View File

@ -0,0 +1,474 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
import json
import io
import os
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray import lut_maker
from prjxray import verilog
from prjxray.db import Database
def gen_sites():
'''
IOB18S: main IOB of a diff pair
IOB18M: secondary IOB of a diff pair
IOB18: not a diff pair. Relatively rare (at least in ROI...2 of them?)
Focus on IOB18S to start
'''
db = Database(util.get_db_root(), util.get_part())
grid = db.grid()
for tile_name in sorted(grid.tiles()):
loc = grid.loc_of_tilename(tile_name)
gridinfo = grid.gridinfo_at_loc(loc)
for site_name, site_type in gridinfo.sites.items():
if site_type in ['IOB18S', 'IOB18M']:
yield tile_name, site_name
def write_params(params):
pinstr = 'tile,site,pin,iostandard,drive,slew\n'
for vals in params:
pinstr += ','.join(map(str, vals)) + '\n'
open('params.csv', 'w').write(pinstr)
def use_oserdese2(p, luts, connects):
p['oddr_mux_config'] = 'none'
p['tddr_mux_config'] = 'none'
p['DATA_RATE_OQ'] = verilog.quote(random.choice((
'SDR',
'DDR',
)))
p['DATA_RATE_TQ'] = verilog.quote(random.choice((
'BUF',
'SDR',
'DDR',
)))
if verilog.unquote(p['DATA_RATE_OQ']) == 'SDR':
data_widths = [2, 3, 4, 5, 6, 7, 8]
else:
data_widths = [4, 6, 8]
p['DATA_WIDTH'] = random.choice(data_widths)
if p['DATA_WIDTH'] == 4 and verilog.unquote(
p['DATA_RATE_OQ']) == 'DDR' and verilog.unquote(
p['DATA_RATE_TQ']) == 'DDR':
tristate_width = 4
else:
tristate_width = 1
p['SERDES_MODE'] = verilog.quote(random.choice(('MASTER', 'SLAVE')))
p['TRISTATE_WIDTH'] = tristate_width
p['OSERDES_MODE'] = verilog.quote(random.choice(('MASTER', 'SLAVE')))
if p['io']:
p['TFB'] = '.TFB(tfb_{site}),'.format(**p)
p['TQ'] = '.TQ({twire}),'.format(**p)
p['t1net'] = luts.get_next_output_net()
p['t2net'] = luts.get_next_output_net()
p['t3net'] = luts.get_next_output_net()
p['t4net'] = luts.get_next_output_net()
p['tcenet'] = luts.get_next_output_net()
for idx in range(4):
p['IS_T{}_INVERTED'.format(idx + 1)] = random.randint(0, 1)
else:
p['TFB'] = '.TFB(),'
p['TQ'] = '.TQ(),'
p['t1net'] = ''
p['t2net'] = ''
p['t3net'] = ''
p['t4net'] = ''
p['tcenet'] = ''
for idx in range(4):
p['IS_T{}_INVERTED'.format(idx + 1)] = 0
p['SRVAL_OQ'] = random.randint(0, 1)
p['SRVAL_TQ'] = random.randint(0, 1)
p['INIT_OQ'] = random.randint(0, 1)
p['INIT_TQ'] = random.randint(0, 1)
for idx in range(8):
p['IS_D{}_INVERTED'.format(idx + 1)] = random.randint(0, 1)
p['IS_CLK_INVERTED'] = random.randint(0, 1)
p['IS_CLKDIV_INVERTED'] = random.randint(0, 1)
clk_connections = ''
p['CLK_USED'] = random.randint(0, 1)
p['CLKDIV_USED'] = random.randint(0, 1)
if p['CLK_USED']:
clk_connections += '''
.CLK({}),'''.format(luts.get_next_output_net())
if p['CLKDIV_USED']:
clk_connections += '''
.CLKDIV({}),'''.format(luts.get_next_output_net())
print(
'''
(* KEEP, DONT_TOUCH, LOC = "{ologic_loc}" *)
OSERDESE2 #(
.SERDES_MODE({OSERDES_MODE}),
.DATA_RATE_TQ({DATA_RATE_TQ}),
.DATA_RATE_OQ({DATA_RATE_OQ}),
.DATA_WIDTH({DATA_WIDTH}),
.TRISTATE_WIDTH({TRISTATE_WIDTH}),
.SRVAL_OQ({SRVAL_OQ}),
.SRVAL_TQ({SRVAL_TQ}),
.INIT_OQ({INIT_OQ}),
.INIT_TQ({INIT_TQ}),
.IS_T1_INVERTED({IS_T1_INVERTED}),
.IS_T2_INVERTED({IS_T2_INVERTED}),
.IS_T3_INVERTED({IS_T3_INVERTED}),
.IS_T4_INVERTED({IS_T4_INVERTED}),
.IS_D1_INVERTED({IS_D1_INVERTED}),
.IS_D2_INVERTED({IS_D2_INVERTED}),
.IS_D3_INVERTED({IS_D3_INVERTED}),
.IS_D4_INVERTED({IS_D4_INVERTED}),
.IS_D5_INVERTED({IS_D5_INVERTED}),
.IS_D6_INVERTED({IS_D6_INVERTED}),
.IS_D7_INVERTED({IS_D7_INVERTED}),
.IS_D8_INVERTED({IS_D8_INVERTED}),
.IS_CLK_INVERTED({IS_CLK_INVERTED}),
.IS_CLKDIV_INVERTED({IS_CLKDIV_INVERTED})
) oserdese2_{site} (
.OQ({owire}),
{TFB}
{TQ}
{clk_connections}
.D1({d1net}),
.D2({d2net}),
.D3({d3net}),
.D4({d4net}),
.D5({d5net}),
.D6({d6net}),
.D7({d7net}),
.D8({d8net}),
.OCE({ocenet}),
.RST({rstnet}),
.T1({t1net}),
.T2({t2net}),
.T3({t3net}),
.T4({t4net}),
.TCE({tcenet})
);'''.format(
clk_connections=clk_connections,
rstnet=luts.get_next_output_net(),
d1net=luts.get_next_output_net(),
d2net=luts.get_next_output_net(),
d3net=luts.get_next_output_net(),
d4net=luts.get_next_output_net(),
d5net=luts.get_next_output_net(),
d6net=luts.get_next_output_net(),
d7net=luts.get_next_output_net(),
d8net=luts.get_next_output_net(),
ocenet=luts.get_next_output_net(),
ofb_wire=luts.get_next_input_net(),
**p),
file=connects)
def use_direct_and_oddr(p, luts, connects):
p['oddr_mux_config'] = random.choice((
'direct',
'lut',
'none',
))
if p['io']:
if p['oddr_mux_config'] != 'lut':
p['tddr_mux_config'] = random.choice((
'direct',
'lut',
'none',
))
else:
p['tddr_mux_config'] = random.choice((
'lut',
'none',
))
else:
p['tddr_mux_config'] = 'none'
# toddr and oddr share the same clk
if random.randint(0, 1):
clknet = luts.get_next_output_net()
p['IS_CLK_INVERTED'] = 0
else:
clknet = 'bufg_o'
p['IS_CLK_INVERTED'] = random.randint(0, 1)
if p['tddr_mux_config'] == 'direct':
p['TINIT'] = random.randint(0, 1)
p['TSRTYPE'] = verilog.quote(random.choice(('SYNC', 'ASYNC')))
p['TDDR_CLK_EDGE'] = verilog.quote('OPPOSITE_EDGE')
# Note: it seems that CLK_EDGE setting is ignored for TDDR
p['TDDR_CLK_EDGE'] = verilog.quote(
random.choice(('OPPOSITE_EDGE', 'SAME_EDGE')))
p['t_sr_used'] = random.choice(('None', 'S', 'R'))
if p['t_sr_used'] == 'None':
p['t_srnet'] = ''
elif p['t_sr_used'] == 'S':
p['srnet'] = luts.get_next_output_net()
p['t_srnet'] = '.S({}),\n'.format(p['srnet'])
elif p['t_sr_used'] == 'R':
p['srnet'] = luts.get_next_output_net()
p['t_srnet'] = '.R({}),\n'.format(p['srnet'])
print(
'''
(* KEEP, DONT_TOUCH, LOC = "{ologic_loc}" *)
ODDR #(
.INIT({TINIT}),
.SRTYPE({TSRTYPE}),
.DDR_CLK_EDGE({TDDR_CLK_EDGE}),
.IS_C_INVERTED({IS_CLK_INVERTED})
) toddr_{site} (
.C({cnet}),
.D1({d1net}),
.D2({d2net}),
.CE({cenet}),
{t_srnet}
.Q(tddr_d_{site})
);
'''.format(
cnet=clknet,
d1net=luts.get_next_output_net(),
d2net=luts.get_next_output_net(),
cenet=luts.get_next_output_net(),
**p),
file=connects)
if p['tddr_mux_config'] == 'direct':
print(
'''
assign {twire} = tddr_d_{site};'''.format(**p, ),
file=connects)
elif p['tddr_mux_config'] == 'lut':
print(
'''
assign {twire} = {lut};'''.format(lut=luts.get_next_output_net(), **p),
file=connects)
pass
elif p['tddr_mux_config'] == 'none':
pass
else:
assert False, p['tddr_mux_config']
if p['oddr_mux_config'] == 'direct':
p['QINIT'] = random.randint(0, 1)
p['SRTYPE'] = verilog.quote(random.choice(('SYNC', 'ASYNC')))
p['ODDR_CLK_EDGE'] = verilog.quote(
random.choice((
'OPPOSITE_EDGE',
'SAME_EDGE',
)))
p['o_sr_used'] = random.choice(('None', 'S', 'R'))
if p['o_sr_used'] == 'None':
p['o_srnet'] = ''
elif p['o_sr_used'] == 'S':
if 'srnet' not in p:
p['srnet'] = luts.get_next_output_net()
p['o_srnet'] = '.S({}),\n'.format(p['srnet'])
elif p['o_sr_used'] == 'R':
if 'srnet' not in p:
p['srnet'] = luts.get_next_output_net()
p['o_srnet'] = '.R({}),\n'.format(p['srnet'])
print(
'''
(* KEEP, DONT_TOUCH, LOC = "{ologic_loc}" *)
ODDR #(
.INIT({QINIT}),
.SRTYPE({SRTYPE}),
.DDR_CLK_EDGE({ODDR_CLK_EDGE}),
.IS_C_INVERTED({IS_CLK_INVERTED})
) oddr_{site} (
.C({cnet}),
.D1({d1net}),
.D2({d2net}),
.CE({cenet}),
{o_srnet}
.Q(oddr_d_{site})
);
'''.format(
cnet=clknet,
d1net=luts.get_next_output_net(),
d2net=luts.get_next_output_net(),
cenet=luts.get_next_output_net(),
**p),
file=connects)
if p['oddr_mux_config'] == 'direct':
print(
'''
assign {owire} = oddr_d_{site};'''.format(**p, ),
file=connects)
elif p['oddr_mux_config'] == 'lut':
print(
'''
assign {owire} = {lut};'''.format(lut=luts.get_next_output_net(), **p),
file=connects)
pass
elif p['oddr_mux_config'] == 'none':
pass
else:
assert False, p['oddr_mux_config']
def run():
iostandards = [
'LVCMOS12', 'LVCMOS15', 'LVCMOS18'
]
iostandard = random.choice(iostandards)
if iostandard in ['LVCMOS12']:
drives = [2, 4, 6, 8]
elif iostandard in ['LVCMOS15', 'LVCMOS18']:
drives = [2, 4, 6, 8, 12, 16]
else:
assert False, "This should be unreachable"
slews = ['FAST', 'SLOW']
pulls = ["NONE", "KEEPER", "PULLDOWN", "PULLUP"]
luts = lut_maker.LutMaker()
connects = io.StringIO()
tile_params = []
params = []
ndio = 0
ndo = 0
for idx, (tile, site) in enumerate(gen_sites()):
if idx == 0:
continue
p = {}
p['tile'] = tile
p['site'] = site
p['ilogic_loc'] = site.replace('IOB', 'ILOGIC')
p['ologic_loc'] = site.replace('IOB', 'OLOGIC')
p['IOSTANDARD'] = verilog.quote(iostandard)
p['PULLTYPE'] = verilog.quote(random.choice(pulls))
p['DRIVE'] = random.choice(drives)
p['SLEW'] = verilog.quote(random.choice(slews))
p['io'] = random.randint(0, 1)
p['owire'] = 'do_buf[{}]'.format(idx - 1)
if p['io']:
p['pad_wire'] = 'dio[{}]'.format(ndio)
ndio += 1
p['iwire'] = 'di_buf[{}]'.format(idx - 1)
p['twire'] = 't[{}]'.format(idx - 1)
else:
p['pad_wire'] = 'do[{}]'.format(ndo)
ndo += 1
params.append(p)
tile_params.append(
(
tile, site, p['pad_wire'], iostandard, p['DRIVE'],
verilog.unquote(p['SLEW']) if p['SLEW'] else None,
verilog.unquote(p['PULLTYPE'])))
write_params(tile_params)
print(
'''
`define N_DO {n_do}
`define N_DIO {n_dio}
module top(input clk, output wire [`N_DO-1:0] do, inout wire [`N_DIO-1:0] dio);
wire [(`N_DIO+`N_DO)-1:0] di_buf;
wire [(`N_DIO+`N_DO)-1:0] do_buf;
wire [(`N_DIO+`N_DO)-1:0] t;
'''.format(n_dio=ndio, n_do=ndo))
# Always output a LUT6 to make placer happy.
print(
'''
(* KEEP, DONT_TOUCH *)
LUT6 dummy_lut();
wire bufg_o;
(* KEEP, DONT_TOUCH *)
BUFG (.O(bufg_o));
''')
for p in params:
if p['io']:
print(
'''
wire oddr_d_{site};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
IOBUF #(
.IOSTANDARD({IOSTANDARD})
) obuf_{site} (
.IO({pad_wire}),
.I({owire}),
.O({iwire}),
.T({twire})
);
'''.format(**p),
file=connects)
else:
print(
'''
wire oddr_d_{site};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
OBUF #(
.IOSTANDARD({IOSTANDARD})
) obuf_{site} (
.O({pad_wire}),
.I({owire})
);
'''.format(**p),
file=connects)
p['use_oserdese2'] = random.randint(0, 1)
if p['use_oserdese2']:
use_oserdese2(p, luts, connects)
else:
use_direct_and_oddr(p, luts, connects)
for l in luts.create_wires_and_luts():
print(l)
print(connects.getvalue())
print("endmodule")
with open('params.jl', 'w') as f:
json.dump(params, f, indent=2)
if __name__ == '__main__':
run()

View File

@ -0,0 +1,58 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
export FUZDIR=$(shell pwd)
PIP_TYPE?=ioi
PIPLIST_TCL=$(FUZDIR)/ioi_pip_list.tcl
TODO_RE=".*"
EXCLUDE_RE=".*((PHASER)|(CLKDIVF)|(CLKDIVP)|(CLKDIVB)|(IOI_ILOGIC[01]_O)|(IOI_OLOGIC[01]_CLKB?\.)|(IOI_IMUX_RC)|(IOI_OLOGIC[01]_[OT]FB)|(OCLKM.*IMUX31)).*"
MAKETODO_FLAGS=--pip-type ${PIP_TYPE} --seg-type $(PIP_TYPE) --re $(TODO_RE) --sides "xr" --exclude-re $(EXCLUDE_RE)
N = 120
SPECIMENS_DEPS=build/cmt_regions.csv
include ../pip_loop.mk
SIX_BIT_PIPS="OLOGIC[01]_CLKDIV"
build/segbits_ioi_x.rdb: $(SPECIMENS_OK)
# Most pips are 3 bits, force a 3 bit solution
${XRAY_SEGMATCH} -c 3 -m 20 -M 50 -o build/segbits_ioi_x_match_3.rdb \
$(shell find build -name segdata_rioi*.txt)
# Some are 6 bit solutions, solve for 6 bits and merge respectively
${XRAY_SEGMATCH} -c 6 -m 20 -M 50 -o build/segbits_ioi_x_match_6.rdb \
$(shell find build -name segdata_rioi*.txt)
grep -v ${SIX_BIT_PIPS} build/segbits_ioi_x_match_3.rdb > build/segbits_ioi_x.rdb
grep ${SIX_BIT_PIPS} build/segbits_ioi_x_match_6.rdb >> build/segbits_ioi_x.rdb
RDBS = build/segbits_ioi_x.rdb
database: ${RDBS}
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_ioi_x.rdb \
--seg-fn-out build/segbits_ioi_x.db
# Keep a copy to track iter progress
cp build/segbits_ioi_x.rdb build/$(ITER)/segbits_ioi_x.rdb
cp build/segbits_ioi_x.db build/$(ITER)/segbits_ioi_x.db
# Clobber existing .db to eliminate potential conflicts
cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db build/database/${XRAY_DATABASE}
XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} rioi build/segbits_ioi_x.db
build/cmt_regions.csv: output_cmt.tcl
mkdir -p build
cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl
pushdb: database
${XRAY_MERGEDB} rioi build/segbits_ioi_x.db
${XRAY_MERGEDB} rioi_tbytesrc build/segbits_ioi_x.db
${XRAY_MERGEDB} rioi_tbyteterm build/segbits_ioi_x.db
.PHONY: database pushdb

View File

View File

@ -0,0 +1,105 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
from prjxray.segmaker import Segmaker
import os, re
import os.path
def bitfilter(frame, word):
if frame < 28:
return False
return True
def main():
segmk = Segmaker("design.bits")
tiledata = {}
pipdata = {}
ignpip = set()
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
'ioi', 'rioi.txt')) as f:
for l in f:
tile_type, dst, src = l.strip().split('.')
if tile_type not in pipdata:
pipdata[tile_type] = []
pipdata[tile_type].append((src, dst))
print("Loading tags from design.txt.")
with open("design.txt", "r") as f:
for line in f:
tile, pip, src, dst, pnum, pdir = line.split()
if not tile.startswith('RIOI') or "X43Y9" in tile:
continue
log = open("log.txt", "a")
print(line, file=log)
pip_prefix, _ = pip.split(".")
tile_from_pip, tile_type = pip_prefix.split('/')
_, src = src.split("/")
_, dst = dst.split("/")
pnum = int(pnum)
pdir = int(pdir)
if tile not in tiledata:
tiledata[tile] = {
"type": tile_type,
"pips": set(),
"srcs": set(),
"dsts": set(),
}
tiledata[tile]["pips"].add((src, dst))
tiledata[tile]["srcs"].add(src)
tiledata[tile]["dsts"].add(dst)
if pdir == 0:
tiledata[tile]["srcs"].add(dst)
tiledata[tile]["dsts"].add(src)
for tile, pips_srcs_dsts in tiledata.items():
tile_type = pips_srcs_dsts["type"]
if tile_type.startswith('RIOI'):
tile_type = 'RIOI'
for src, dst in pipdata[tile_type]:
if (src, dst) in ignpip:
pass
if re.match(r'.*PHASER.*', src) or re.match(r'.*CLKDIV[PFB].*',
dst):
pass
elif (src, dst) in tiledata[tile]["pips"]:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 1)
elif dst not in tiledata[tile]["dsts"]:
disable_pip = True
if dst == 'IOI_OCLKM_0' and 'IOI_OCLK_0' in tiledata[tile][
"dsts"]:
disable_pip = False
if dst == 'IOI_OCLKM_1' and 'IOI_OCLK_1' in tiledata[tile][
"dsts"]:
disable_pip = False
if disable_pip:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 0)
segmk.compile(bitfilter=bitfilter)
segmk.write()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,109 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
source "$::env(XRAY_DIR)/utils/utils.tcl"
proc write_pip_txtdata {filename} {
puts "FUZ([pwd]): Writing $filename."
set fp [open $filename w]
set nets [get_nets -hierarchical]
set nnets [llength $nets]
set neti 0
foreach net $nets {
incr neti
if {($neti % 100) == 0 } {
puts "FUZ([pwd]): Dumping pips from net $net ($neti / $nnets)"
}
foreach pip [get_pips -of_objects $net] {
set tile [get_tiles -of_objects $pip]
set src_wire [get_wires -uphill -of_objects $pip]
set dst_wire [get_wires -downhill -of_objects $pip]
set num_pips [llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst_wire]]]
set dir_prop [get_property IS_DIRECTIONAL $pip]
puts $fp "$tile $pip $src_wire $dst_wire $num_pips $dir_prop"
}
}
close $fp
}
proc make_manual_routes {filename} {
puts "MANROUTE: Loading routes from $filename"
set fp [open $filename r]
foreach line [split [read $fp] "\n"] {
if {$line eq ""} {
continue
}
puts "MANROUTE: Line: $line"
# Parse the line
set fields [split $line " "]
set net_name [lindex $fields 0]
set wire_name [lindex $fields 1]
# Check if that net exists
if {[get_nets $net_name] eq ""} {
puts "MANROUTE: net $net_name does not exist"
continue
}
set net [get_nets $net_name]
# Rip it up
set_property -quiet FIXED_ROUTE "" $net
set_property IS_ROUTE_FIXED 0 $net
route_design -unroute -nets $net
# Make the route
set nodes [get_nodes -of_objects [get_wires $wire_name]]
set status [route_via $net_name [list $nodes] 0]
# Failure, skip manual routing of this net
if { $status != 1 } {
puts "MANROUTE: Manual routing failed!"
set_property -quiet FIXED_ROUTE "" $net
set_property IS_ROUTE_FIXED 0 $net
continue
}
puts "MANROUTE: Success!"
}
}
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
set_property CFGBVS GND [current_design]
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-74}]
set_property IS_ENABLED 0 [get_drc_checks {PDRC-26}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-4}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-5}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-13}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-98}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-99}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-105}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-115}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-144}]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets]
place_design -directive Quick
write_checkpoint -force design_before_route.dcp
make_manual_routes routes.txt
route_design -directive Quick -preserve
write_checkpoint -force design.dcp
write_bitstream -force design.bit
write_pip_txtdata design.txt
}
run

View File

@ -0,0 +1,47 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
proc print_tile_pips {tile_type filename} {
set fp [open $filename w]
set pips [dict create]
foreach tile [get_tiles -filter "TYPE == $tile_type"] {
foreach pip [lsort [get_pips -of_objects $tile]] {
set src [get_wires -uphill -of_objects $pip]
set dst [get_wires -downhill -of_objects $pip]
# Skip pips with disconnected nodes
set src_node [get_nodes -of_objects $src]
if { $src_node == {} } {
continue
}
set dst_node [get_nodes -of_objects $src]
if { $dst_node == {} } {
continue
}
set src_wire [regsub {.*/} $src ""]
set src_match [regexp {IOI_OCLKM?_[01]} $src_wire]
if { [llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 1 || $src_match } {
set pip_string "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]"
if ![dict exists $pips $pip_string] {
puts $fp $pip_string
dict set pips $pip_string 1
}
}
}
}
close $fp
}
create_project -force -part $::env(XRAY_PART) design design
set_property design_mode PinPlanning [current_fileset]
open_io_design -name io_1
print_tile_pips RIOI rioi.txt

View File

@ -0,0 +1,18 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
create_project -force -part $::env(XRAY_PART) design design
set_property design_mode PinPlanning [current_fileset]
open_io_design -name io_1
set fp [open "cmt_regions.csv" "w"]
foreach site_type {MMCME2_ADV BUFHCE BUFR BUFMRCE BUFIO ILOGICE2 OLOGICE2 IDELAYE2 IDELAYCTRL PLLE2_ADV} {
foreach site [get_sites -filter "SITE_TYPE == $site_type"] {
puts $fp "$site,[get_property CLOCK_REGION $site]"
}
}
close $fp

View File

@ -0,0 +1,391 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
import os
import random
import math
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray import verilog
from prjxray import lut_maker
from prjxray.db import Database
NOT_INCLUDED_TILES = ['RIOI_SING']
SITE_TYPES = ['OLOGICE2', 'ILOGICE2']
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:
site, cmt = l.strip().split(',')
yield (site, cmt)
def gen_sites():
''' Return dict of ISERDES/OSERDES locations. '''
db = Database(util.get_db_root(), util.get_part())
grid = db.grid()
xy_fun = util.create_xy_fun('\S+')
tiles = grid.tiles()
for tile_name in sorted(tiles):
loc = grid.loc_of_tilename(tile_name)
gridinfo = grid.gridinfo_at_loc(loc)
tile_type = gridinfo.tile_type
tile = {'tile': tile_name, 'tile_type': tile_type, 'ioi_sites': {}}
for site_name, site_type in gridinfo.sites.items():
if site_type in SITE_TYPES:
xy = xy_fun(site_name)
if xy not in tile['ioi_sites']:
tile['ioi_sites'][xy] = {}
tile['ioi_sites'][xy][site_type] = site_name
yield tile
class ClockSources(object):
def __init__(self):
self.site_to_cmt = dict(read_site_to_cmt())
self.leaf_gclks = {}
self.ioclks = {}
self.rclks = {}
self.selected_leaf_gclks = {}
self.lut_maker = lut_maker.LutMaker()
for cmt in set(self.site_to_cmt.values()):
self.leaf_gclks[cmt] = []
self.ioclks[cmt] = []
self.rclks[cmt] = []
def init_clocks(self):
""" Initialize all IOI clock sources. """
for site, cmt in self.site_to_cmt.items():
clk = 'clk_' + site
if 'BUFHCE' in site:
print(
"""
wire {clk};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFH bufh_{site}(
.O({clk})
);
""".format(
clk=clk,
site=site,
))
self.leaf_gclks[cmt].append(clk)
if 'BUFIO' in site:
print(
"""
wire {clk};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFIO bufio_{site}(
.O({clk})
);
""".format(
clk=clk,
site=site,
))
self.ioclks[cmt].append(clk)
if 'BUFR' in site:
print(
"""
wire {clk};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFR bufr_{site}(
.O({clk})
);
""".format(
clk=clk,
site=site,
))
self.rclks[cmt].append(clk)
# Choose 6 leaf_gclks to be used in each CMT.
for cmt in self.leaf_gclks:
self.selected_leaf_gclks[cmt] = random.sample(
self.leaf_gclks[cmt], 6)
def get_clock(
self,
site,
allow_ioclks,
allow_rclks,
allow_fabric=True,
allow_empty=True):
cmt = self.site_to_cmt[site]
choices = []
if allow_fabric:
choices.append('lut')
if allow_empty:
choices.append('')
choices.extend(self.selected_leaf_gclks[cmt])
if allow_ioclks:
choices.extend(self.ioclks[cmt])
if allow_rclks:
choices.extend(self.rclks[cmt])
clock = random.choice(choices)
is_lut = False
if clock == "lut":
clock = self.lut_maker.get_next_output_net()
is_lut = True
return clock, is_lut
def add_port(ports, port, signal):
ports.append('.{}({})'.format(port, signal))
def run():
print("module top();")
clocks = ClockSources()
clocks.init_clocks()
"""
ISERDESE2 clock sources:
CLK/CLKB:
- Allows LEAF_GCLK, IOCLKS, RCLKS and fabric
- Dedicated pips
CLKDIV:
- No dedicated pips, uses fabric clock in.
CLKDIVP:
- Has pips, MIG only, PHASER or fabric.
OCLK/OCLKB:
- Allows LEAF_GCLK, IOCLKS, RCLKS and fabric
- Must match OSERDESE2:CLK/CLKB
OSERDESE2 clock sources:
CLKDIV/CLKDIVB:
- Allows LEAF_GCLK and RCLKS and fabric
- Dedicated pips
CLKDIVF/CLKDIVFB:
- Allows LEAF_GCLK and RCLKS and fabric
- No explicit port, follows CLKDIV/CLKDIVB?
"""
output = []
route_file = open("routes.txt", "w")
for tile in gen_sites():
if tile['tile_type'] in NOT_INCLUDED_TILES:
continue
for xy in tile['ioi_sites']:
ilogic_site_type = random.choice([None, 'ISERDESE2', 'IDDR'])
use_oserdes = random.randint(0, 1)
ilogic_site = tile['ioi_sites'][xy]['ILOGICE2']
ologic_site = tile['ioi_sites'][xy]['OLOGICE2']
if use_oserdes:
oclk, _ = clocks.get_clock(
ologic_site, allow_ioclks=True, allow_rclks=True)
oclkb = oclk
else:
oclk, is_lut = clocks.get_clock(
ilogic_site, allow_ioclks=True, allow_rclks=True)
if random.randint(0, 1):
oclkb = oclk
else:
if random.randint(0, 1):
oclkb, _ = clocks.get_clock(
ilogic_site,
allow_ioclks=True,
allow_rclks=True,
allow_fabric=not is_lut)
else:
# Explicitly provide IMUX stimulus to resolve IMUX pips
oclk = random.randint(0, 1)
oclkb = random.randint(0, 1)
DATA_RATE = random.choice(['DDR', 'SDR'])
clk, clk_is_lut = clocks.get_clock(
ilogic_site,
allow_ioclks=True,
allow_rclks=True,
allow_empty=DATA_RATE == 'SDR')
clkb = clk
while clkb == clk:
clkb, clkb_is_lut = clocks.get_clock(
ilogic_site,
allow_ioclks=True,
allow_rclks=True,
allow_empty=False)
imux_available = {
0: set(("IOI_IMUX20_0", "IOI_IMUX22_0")),
1: set(("IOI_IMUX20_1", "IOI_IMUX22_1")),
}
# Force CLK route through IMUX when connected to a LUT
if clk_is_lut:
y = (xy[1] + 1) % 2
route = random.choice(list(imux_available[y]))
imux_available[y].remove(route)
route = "{}/{}".format(tile["tile"], route)
route_file.write("{} {}\n".format(clk, route))
# Force CLKB route through IMUX when connected to a LUT
if clkb_is_lut:
y = (xy[1] + 1) % 2
route = random.choice(list(imux_available[y]))
imux_available[y].remove(route)
route = "{}/{}".format(tile["tile"], route)
route_file.write("{} {}\n".format(clkb, route))
if ilogic_site_type is None:
pass
elif ilogic_site_type == 'ISERDESE2':
INTERFACE_TYPE = random.choice(
[
'MEMORY',
'MEMORY_DDR3',
'MEMORY_QDR',
'NETWORKING',
'OVERSAMPLE',
])
ports = []
add_port(ports, 'CLK', clk)
add_port(ports, 'CLKB', clkb)
add_port(ports, 'OCLK', oclk)
add_port(ports, 'OCLKB', oclkb)
output.append(
"""
(* KEEP, DONT_TOUCH, LOC="{site}" *)
ISERDESE2 #(
.DATA_RATE({DATA_RATE}),
.INTERFACE_TYPE({INTERFACE_TYPE}),
.IS_CLK_INVERTED({IS_CLK_INVERTED}),
.IS_CLKB_INVERTED({IS_CLKB_INVERTED}),
.IS_OCLK_INVERTED({IS_OCLK_INVERTED}),
.IS_OCLKB_INVERTED({IS_OCLKB_INVERTED}),
.INIT_Q1({INIT_Q1}),
.INIT_Q2({INIT_Q2}),
.INIT_Q3({INIT_Q3}),
.INIT_Q4({INIT_Q4}),
.SRVAL_Q1({SRVAL_Q1}),
.SRVAL_Q2({SRVAL_Q2}),
.SRVAL_Q3({SRVAL_Q3}),
.SRVAL_Q4({SRVAL_Q4})
) iserdes_{site}(
{ports});""".format(
site=ilogic_site,
ports=',\n'.join(ports),
DATA_RATE=verilog.quote(DATA_RATE),
INTERFACE_TYPE=verilog.quote(INTERFACE_TYPE),
IS_CLK_INVERTED=random.randint(0, 1),
IS_CLKB_INVERTED=random.randint(0, 1),
IS_OCLK_INVERTED=random.randint(0, 1),
IS_OCLKB_INVERTED=random.randint(0, 1),
INIT_Q1=random.randint(0, 1),
INIT_Q2=random.randint(0, 1),
INIT_Q3=random.randint(0, 1),
INIT_Q4=random.randint(0, 1),
SRVAL_Q1=random.randint(0, 1),
SRVAL_Q2=random.randint(0, 1),
SRVAL_Q3=random.randint(0, 1),
SRVAL_Q4=random.randint(0, 1),
))
elif ilogic_site_type == 'IDDR':
ports = []
add_port(ports, 'C', clk)
add_port(ports, 'CB', clkb)
output.append(
"""
(* KEEP, DONT_TOUCH, LOC="{site}" *)
IDDR_2CLK #(
.INIT_Q1({INIT_Q1}),
.INIT_Q2({INIT_Q2}),
.SRTYPE({SRTYPE})
) iserdes_{site}(
{ports});""".format(
site=ilogic_site,
ports=',\n'.join(ports),
INIT_Q1=random.randint(0, 1),
INIT_Q2=random.randint(0, 1),
SRTYPE=verilog.quote(random.choice(['ASYNC', 'SYNC'])),
))
else:
assert False, ilogic_site_type
if use_oserdes:
ports = []
add_port(
ports, 'CLKDIV',
clocks.get_clock(
ologic_site,
allow_ioclks=False,
allow_rclks=True,
)[0])
add_port(ports, 'CLK', oclk)
output.append(
"""
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
OSERDESE2 #(
.IS_CLK_INVERTED({IS_CLK_INVERTED}),
.DATA_RATE_OQ("SDR"),
.DATA_RATE_TQ("SDR")
) oserdes_{site} (
{ports});""".format(
IS_CLK_INVERTED=random.randint(0, 1),
site=ologic_site,
ports=',\n'.join(ports),
))
for s in clocks.lut_maker.create_wires_and_luts():
print(s)
for s in output:
print(s)
print("endmodule")
if __name__ == '__main__':
run()

View File

@ -9,7 +9,7 @@ N ?= 50
include ../fuzzer.mk
database: build/segbits_hclk_ioi3.db
database: build/segbits_hclk_ioi.db
build/segbits_hclk_ioi3.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -c 5 -o build/segbits_hclk_ioi3.rdb \
@ -22,8 +22,16 @@ build/segbits_hclk_ioi3.db: build/segbits_hclk_ioi3.rdb
${XRAY_MASKMERGE} build/mask_hclk_ioi3.db \
$(addsuffix /segdata_hclk_ioi3.txt,$(SPECIMENS))
# The fuzzer results for the high performance banks
# are identical, so just copy those
build/segbits_hclk_ioi.db: build/segbits_hclk_ioi3.db build/mask_hclk_ioi3.db
sed -e 's/HCLK_IOI3/HCLK_IOI/g' $< > $@
cp build/mask_hclk_ioi3.db build/mask_hclk_ioi.db
pushdb: database
${XRAY_MERGEDB} hclk_ioi3 build/segbits_hclk_ioi3.db
${XRAY_MERGEDB} mask_hclk_ioi3 build/mask_hclk_ioi3.db
${XRAY_MERGEDB} hclk_ioi build/segbits_hclk_ioi.db
${XRAY_MERGEDB} mask_hclk_ioi build/mask_hclk_ioi.db
.PHONY: database pushdb

View File

@ -0,0 +1,53 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
export FUZDIR=$(shell pwd)
PIP_TYPE?=hclk_ioi
PIPLIST_TCL=$(FUZDIR)/hclk_ioi_pip_list.tcl
TODO_RE=".*"
# FIXME Modify fuzzer to solve PIPs that drive the BUFIO and BUFR from ILOGIC clock or through the IOI tile.
EXCLUDE_RE=".*\.HCLK_IOI_((I2IOCLK)|(IDELAYCTRL))"
MAKETODO_FLAGS= --sides "" --pip-type ${PIP_TYPE} --seg-type ${PIP_TYPE} --re $(TODO_RE) --exclude-re $(EXCLUDE_RE)
N = 499
SEGMATCH_FLAGS=-c 4 -m 4 -M 4
SPECIMENS_DEPS=build/cmt_regions.csv
A_PIPLIST=hclk_ioi.txt
include ../pip_loop.mk
build/segbits_hclk_ioi.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_hclk_ioi.rdb \
$(shell find build -name segdata_hclk_ioi.txt)
build/segbits_hclk_ioi.db: build/segbits_hclk_ioi.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_hclk_ioi.rdb \
--seg-fn-out build/segbits_hclk_ioi.db
# Keep a copy to track iter progress
cp build/segbits_hclk_ioi.rdb build/$(ITER)/segbits_hclk_ioi.rdb
${XRAY_MASKMERGE} build/mask_hclk_ioi.db \
$(shell find build -name segdata_hclk_ioi.txt)
database: build/segbits_hclk_ioi.db
# Clobber existing .db to eliminate potential conflicts
cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db build/database/${XRAY_DATABASE}
XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} hclk_ioi build/segbits_hclk_ioi.db
build/cmt_regions.csv: output_cmt.tcl
mkdir -p build
cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl
pushdb: database
${XRAY_MERGEDB} hclk_ioi build/segbits_hclk_ioi.db
${XRAY_MERGEDB} mask_hclk_ioi build/mask_hclk_ioi.db
.PHONY: database pushdb

View File

@ -0,0 +1,3 @@
# HCLK_IOI interconnect fuzzer
Solves pips located within the HCLK_IOI switch box.

View File

View File

@ -0,0 +1,92 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
from prjxray.segmaker import Segmaker
import os
import os.path
def bitfilter(frame, word):
if frame < 26:
return False
return True
def main():
segmk = Segmaker("design.bits")
tiledata = {}
pipdata = {}
ignpip = set()
tile_ports = {}
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
'hclk_ioi', 'hclk_ioi.txt')) as f:
for l in f:
tile_type, dst, src = l.strip().split('.')
if tile_type not in pipdata:
pipdata[tile_type] = []
tile_ports[tile_type] = set()
pipdata[tile_type].append((src, dst))
tile_ports[tile_type].add(src)
tile_ports[tile_type].add(dst)
print("Loading tags from design.txt.")
with open("design.txt", "r") as f:
for line in f:
tile, pip, src, dst, pnum, pdir = line.split()
if not tile.startswith('HCLK_IOI_'):
continue
pip_prefix, _ = pip.split(".")
tile_from_pip, tile_type = pip_prefix.split('/')
assert tile == tile_from_pip
_, src = src.split("/")
_, dst = dst.split("/")
pnum = int(pnum)
pdir = int(pdir)
if tile not in tiledata:
tiledata[tile] = {
"type": tile_type,
"pips": set(),
"srcs": set(),
"dsts": set()
}
tiledata[tile]["pips"].add((src, dst))
tiledata[tile]["srcs"].add(src)
tiledata[tile]["dsts"].add(dst)
if pdir == 0:
tiledata[tile]["srcs"].add(dst)
tiledata[tile]["dsts"].add(src)
for tile, pips_srcs_dsts in tiledata.items():
tile_type = pips_srcs_dsts["type"]
pips = pips_srcs_dsts["pips"]
for src, dst in pipdata[tile_type]:
if (src, dst) in ignpip:
pass
elif (src, dst) in pips:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 1)
elif dst not in tiledata[tile]["dsts"]:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 0)
segmk.compile(bitfilter=bitfilter)
segmk.write()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,358 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
source "$::env(XRAY_DIR)/utils/utils.tcl"
proc load_todo {{dir "dst"}} {
set fp [open "../../todo_all.txt" r]
# Create map of pip source to remaining destinations for that pip
set todo_map [dict create]
for {gets $fp line} {$line != ""} {gets $fp line} {
set parts [split $line .]
if {$dir == "dsts"} {
dict lappend todo_map [lindex $parts 2] [list [lindex $parts 0] [lindex $parts 1]]
} elseif {$dir == "srcs"} {
dict lappend todo_map [lindex $parts 1] [list [lindex $parts 0] [lindex $parts 2]]
} else {
error "Incorrect argument. Available options: src, dst"
}
}
close $fp
return $todo_map
}
proc shuffle_list {list} {
set l [llength $list]
for {set i 0} {$i<=$l} {incr i} {
set x [lindex $list [set p [expr {int(rand()*$l)}]]]
set list [lreplace $list $p $p]
set list [linsert $list [expr {int(rand()*$l)}] $x]
}
return $list
}
# Get the dictionary of nets with one corresponding source wire
# of a PIP from the todo list
proc get_nets_with_todo_pip_wires {direction net_regexp wire_regexp used_destinations {verbose false}} {
set todo_map [load_todo $direction]
puts $todo_map
set nets [get_nets]
set todo_nets [dict create]
foreach net $nets {
if {![regexp $net_regexp $net]} {
continue
}
# Check to see if this net is one we are interested in*
set wires [get_wires -of_objects $net -filter {TILE_NAME =~ "*HCLK_IOI*" } -quiet]
set wire_found 0
foreach wire $wires {
if [regexp $wire_regexp $wire] {
set wire_found 1
break
}
}
if {$wire_found == 0} {
if {$verbose} {
puts "$net not going to a HCLK port, skipping."
}
continue
}
set tile [lindex [split $wire /] 0]
set wire [lindex [split $wire /] 1]
set tile_type [get_property TILE_TYPE [get_tiles $tile]]
if { ![dict exists $todo_map $wire] } {
continue
}
set candidates [dict get $todo_map $wire]
# This net is interesting, see if it is already going somewhere we
# want.
set found_target 0
foreach other_wire $wires {
if { $found_target == 1 } {
break
}
set other_wire [lindex [split $other_wire /] 1]
if { $wire == $other_wire } {
continue
}
foreach candidate $candidates {
set candidate_tile_type [lindex $candidate 0]
if {$candidate_tile_type != $tile_type} {
continue
}
set candidate_wire [lindex $candidate 1]
if { $other_wire == $candidate } {
set found_target 1
if {$verbose} {
puts "Interesting net $net already going from $wire to $other_wire."
}
set_property IS_ROUTE_FIXED 1 $net
dict set used_destinations "$tile/$candidate_wire" 1
break
}
}
}
if { $found_target == 1 } {
# Net already has an interesting feature - don't reroute.
continue
}
dict set todo_nets $net [list $tile $wire]
if {$verbose} {
puts "Interesting net $net (including $wire) is being rerouted."
}
}
return $todo_nets
}
proc route_todo {} {
set used_destinations [dict create]
set todo_map [load_todo "dsts"]
set serdes_nets [get_nets_with_todo_pip_wires "dsts" "serdes_clk_ILOGIC" "HCLK_IOI_CK_IGCLK" $used_destinations]
puts "Serdes nets: $serdes_nets"
dict for {net tile_wire} $serdes_nets {
set tile [lindex $tile_wire 0]
set wire [lindex $tile_wire 1]
set dsts [dict get $todo_map $wire]
set tile_type [get_property TILE_TYPE [get_tiles $tile]]
set todos {}
set old_target_wire [get_wires -of_objects $net -filter {TILE_NAME =~ "*HCLK_IOI*" && NAME =~ "*HCLK_IOI_LEAF_GCLK_*"}]
if {$old_target_wire == {}} {
continue
}
if {[dict exists $used_destinations $old_target_wire]} {
puts "Not routing to $old_target_wire, in use."
continue
}
puts "Rerouting net $net at $tile / $wire (type $tile_type)"
puts "Previous target wire: $old_target_wire"
set old_target_node [get_nodes -of_objects $old_target_wire]
if [regexp "HCLK_IOI_LEAF_GCLK_\(\(TOP\)|\(BOT\)\).*" $old_target_wire match group] {
set old_target_side $group
}
foreach dst $dsts {
set dst_tile_type [lindex $dst 0]
if {$dst_tile_type != $tile_type} {
continue
}
set dst_wire [lindex $dst 1]
set is_gclk_net 0
if [regexp "HCLK_IOI_LEAF_GCLK_\(\(TOP\)|\(BOT\)\).*" $dst_wire match group] {
set is_gclk_net 1
set dst_side $group
}
if {$is_gclk_net == 0 || $dst_side != $old_target_side} {
continue
}
lappend todos $dst_wire
}
set todos_length [llength $todos]
if {$todos_length == 0} {
continue
}
puts "All todos for $tile_type / $wire"
foreach dst_wire $todos {
puts " - $dst_wire"
}
set todos [shuffle_list $todos]
set origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]]
puts "Origin node: $origin_node"
route_design -unroute -nets $net
# Find an input in the todo list that this can can drive.
foreach dst_wire $todos {
if { [dict exists $used_destinations "$tile/$dst_wire"] } {
puts "Not routing to $tile / $dst_wire, in use."
continue
}
set target_wire [get_wires "$tile/$dst_wire"]
set target_node [get_nodes -of_objects $target_wire]
if {[llength $target_node] == 0} {
error "Failed to find node for $tile/$dst_wire."
}
set old_net [get_nets -of_objects $target_node -quiet]
if {$old_net == {}} {
continue
}
puts "Unrouting the old net: $old_net"
route_design -unroute -nets $old_net
set old_origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $old_net]]
# Route the net through the desired node
puts "Attempting to route to $target_node for net $net."
route_via $net [list $target_node]
puts "Attempting to route to $old_target_node for net $old_net."
# Route the old net through the old target node
route_via $old_net [list $old_target_node ]
puts "Origin node: $origin_node, Old origin node: $old_origin_node"
puts "Target wire: $target_wire, Old target wire: $old_target_wire"
puts "Target node: $target_node, Old target node: $old_target_node"
dict set used_destinations "$target_wire" 1
dict set used_destinations "$old_target_wire" 1
break
}
}
set todo_map [load_todo "srcs"]
set before_div_nets [get_nets_with_todo_pip_wires "srcs" "I_BUFR" "HCLK_IOI_RCLK_BEFORE_DIV" $used_destinations]
puts "Before div nets: $before_div_nets"
dict for {net tile_wire} $before_div_nets {
set tile [lindex $tile_wire 0]
set wire [lindex $tile_wire 1]
set srcs [dict get $todo_map $wire]
set tile_type [get_property TILE_TYPE [get_tiles $tile]]
set todos {}
set old_origin_wire [get_wires -of_objects $net -filter {TILE_NAME =~ "*HCLK_IOI*" && NAME =~ "*HCLK_IOI_RCLK_IMUX*"}]
if {$old_origin_wire == {}} {
continue
}
puts "Rerouting net $net at $tile / $wire (type $tile_type)"
puts "Previous target wire: $old_origin_wire"
set old_origin_node [get_nodes -of_objects $old_origin_wire]
if [regexp "HCLK_IOI_RCLK_IMUX.*" $old_origin_wire match group] {
set old_target_side $group
}
foreach src $srcs {
set src_tile_type [lindex $src 0]
if {$src_tile_type != $tile_type} {
continue
}
set src_wire [lindex $src 1]
set is_gclk_net 0
if [regexp "HCLK_IOI_RCLK_IMUX.*" $src_wire match group] {
set is_gclk_net 1
}
if {$is_gclk_net == 0} {
continue
}
lappend todos $src_wire
}
set todos_length [llength $todos]
if {$todos_length == 0} {
continue
}
puts "All todos for $tile_type / $wire"
foreach src_wire $todos {
puts " - $src_wire"
}
set todos [shuffle_list $todos]
set target_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net]]
puts "Target node: $target_node"
route_design -unroute -nets $net
# Find an output in the todo list that can drive.
foreach src_wire $todos {
if { [dict exists $used_destinations "$tile/$src_wire"] } {
puts "Not routing to $tile / $src_wire, in use."
continue
}
set origin_wire [get_wires "$tile/$src_wire"]
set origin_node [get_nodes -of_objects $origin_wire]
if {[llength $origin_node] == 0} {
error "Failed to find node for $tile/$src_wire."
}
set old_net [get_nets -of_objects $origin_node -quiet]
if {$old_net != {}} {
puts "Unrouting the old net: $old_net"
route_design -unroute -nets $old_net
}
# Route the net through the desired node
puts "Attempting to route to $src_wire for net $net."
route_via $net [list $origin_node]
puts "Target node: $target_node"
puts "Origin wire: $origin_wire, Old origin wire: $old_origin_wire"
puts "Origin node: $origin_node, Old origin node: $old_origin_node"
dict set used_destinations "$origin_wire" 1
break
}
}
}
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_property IS_ENABLED 0 [get_drc_checks {PDRC-29}]
set_property IS_ENABLED 0 [get_drc_checks {PDRC-38}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-13}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-123}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-161}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-1575}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-1684}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-1712}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-50}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-78}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-81}]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets]
place_design
route_design
route_todo
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
write_pip_txtdata design.txt
}
run

View File

@ -0,0 +1,49 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
proc print_tile_pips {tile_type filename} {
set fp [open $filename w]
set pips [dict create]
foreach tile [get_tiles -filter "TYPE == $tile_type"] {
puts "Dumping PIPs for tile $tile ($tile_type) to $filename."
foreach pip [lsort [get_pips -of_objects $tile]] {
set src [get_wires -uphill -of_objects $pip]
set dst [get_wires -downhill -of_objects $pip]
# Skip pips with disconnected nodes
set src_node [get_nodes -of_objects $src]
if { $src_node == {} } {
continue
}
set dst_node [get_nodes -of_objects $dst]
if { $dst_node == {} } {
continue
}
set dst_wire [regsub {.*/} $dst ""]
set dst_match [regexp {HCLK_IOI_CK_IGCLK[0-9]+} $dst_wire]
if {[llength [get_nodes -uphill -of_objects $dst_node]] > 1 || $dst_match} {
set pip_string "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]"
if ![dict exists $pips $pip_string] {
puts $fp $pip_string
dict set pips $pip_string 1
}
} else {
puts "Ignoring PIP: $pip"
}
}
}
close $fp
}
create_project -force -part $::env(XRAY_PART) design design
set_property design_mode PinPlanning [current_fileset]
open_io_design -name io_1
print_tile_pips HCLK_IOI hclk_ioi.txt

View File

@ -0,0 +1,18 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
create_project -force -part $::env(XRAY_PART) design design
set_property design_mode PinPlanning [current_fileset]
open_io_design -name io_1
set fp [open "cmt_regions.csv" "w"]
foreach site_type {MMCME2_ADV PLLE2_ADV BUFHCE IOB18M BUFR BUFMRCE BUFIO ILOGICE2 IDELAYCTRL} {
foreach site [get_sites -filter "SITE_TYPE == $site_type"] {
puts $fp "$site,[get_property CLOCK_REGION $site]"
}
}
close $fp

View File

@ -0,0 +1,479 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
""" Emits top.v's for various BUFHCE routing inputs. """
import os
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray.lut_maker import LutMaker
from prjxray.db import Database
from io import StringIO
CMT_XY_FUN = util.create_xy_fun(prefix='')
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:
site, cmt = l.strip().split(',')
yield (site, cmt)
class ClockSources(object):
""" Class for tracking clock sources.
"""
def __init__(self, limit=14):
self.sources = {}
self.source_to_cmt = {}
self.used_sources_from_cmt = {}
self.limit = limit
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] = []
self.sources[cmt].append(source)
self.source_to_cmt[source] = cmt
def get_random_source(self, cmt, no_repeats=False):
""" 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.
"""
choices = []
if cmt in self.sources:
choices.extend(self.sources[cmt])
random.shuffle(choices)
for source in choices:
source_cmt = self.source_to_cmt[source]
if source_cmt not in self.used_sources_from_cmt:
self.used_sources_from_cmt[source_cmt] = set()
if no_repeats and source in self.used_sources_from_cmt[source_cmt]:
continue
if len(self.used_sources_from_cmt[source_cmt]) >= self.limit:
continue
self.used_sources_from_cmt[source_cmt].add(source)
return source
return None
def main():
"""
HCLK_IOI has the following inputs:
12 (east) BUFH from the right side of the HROW
12 (west) Bounce PIPs from one BUFH to any of 6 GCLK_BOT and 6 GCLK_TOP
4 (east) PHSR_PERFCLK (IOCLK_PLL) from HCLK_CLB to input of BUFIO
8 (4 north and 4 south) BUFR CLR and CE
2 (south) I2IOCLK to input of BUFR
2 (north) I2IOCLK to input of BUFR
2 RCLK IMUX (IMUX0 and IMUX1) choosing input of BUFR
outputs:
4 (east) BUFRCLK - from BUFR to HROW
4 (north) BUFR2IO - from BUFR
4 (north) IOCLK from BUFIO
"""
global_clock_sources = ClockSources()
cmt_clock_sources = ClockSources()
cmt_fast_clock_sources = ClockSources(4)
bufr_clock_sources = ClockSources()
bufio_clock_sources = ClockSources()
site_to_cmt = dict(read_site_to_cmt())
clock_region_limit = dict()
clock_region_serdes_location = dict()
db = Database(util.get_db_root(), util.get_part())
grid = db.grid()
def gen_sites(desired_site_type):
for tile_name in sorted(grid.tiles()):
loc = grid.loc_of_tilename(tile_name)
gridinfo = grid.gridinfo_at_loc(loc)
for site, site_type in gridinfo.sites.items():
if site_type == desired_site_type:
yield tile_name, site
def serdes_relative_location(tile, site):
(serdes_loc_x, serdes_loc_y) = grid.loc_of_tilename(tile)
serdes_clk_reg = site_to_cmt[site]
for tile_name in sorted(grid.tiles()):
if 'HCLK_IOI' in tile_name:
(hclk_tile_loc_x,
hclk_tile_loc_y) = grid.loc_of_tilename(tile_name)
if hclk_tile_loc_x == serdes_loc_x:
gridinfo = grid.gridinfo_at_loc(
(hclk_tile_loc_x, hclk_tile_loc_y))
random_site = next(iter(gridinfo.sites.keys()))
hclk_clk_reg = site_to_cmt[random_site]
if hclk_clk_reg == serdes_clk_reg:
if serdes_loc_y < hclk_tile_loc_y:
return "TOP"
elif serdes_loc_y > hclk_tile_loc_y:
return "BOTTOM"
else:
assert False
clock_region_sites = set()
def get_clock_region_site(site_type, clk_reg):
for site_name, reg in site_to_cmt.items():
if site_name.startswith(site_type) and reg in clk_reg:
if site_name not in clock_region_sites:
clock_region_sites.add(site_name)
return site_name
print(
'''
module top();
(* KEEP, DONT_TOUCH *)
LUT6 dummy();
''')
luts = LutMaker()
bufs = StringIO()
for _, site in gen_sites('MMCME2_ADV'):
mmcm_clocks = [
'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx)
for idx in range(13)
]
for idx, clk in enumerate(mmcm_clocks):
if idx < 4:
cmt_fast_clock_sources.add_clock_source(clk, site_to_cmt[site])
else:
cmt_clock_sources.add_clock_source(clk, site_to_cmt[site])
print(
"""
wire cin1_{site}, cin2_{site}, clkfbin_{site}, {c0}, {c1}, {c2}, {c3}, {c4}, {c5};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
MMCME2_ADV pll_{site} (
.CLKIN1(cin1_{site}),
.CLKIN2(cin2_{site}),
.CLKFBIN(clkfbin_{site}),
.CLKOUT0({c0}),
.CLKOUT0B({c4}),
.CLKOUT1({c1}),
.CLKOUT1B({c5}),
.CLKOUT2({c2}),
.CLKOUT2B({c6}),
.CLKOUT3({c3}),
.CLKOUT3B({c7}),
.CLKOUT4({c8}),
.CLKOUT5({c9}),
.CLKOUT6({c10}),
.CLKFBOUT({c11}),
.CLKFBOUTB({c12})
);
""".format(
site=site,
c0=mmcm_clocks[0],
c1=mmcm_clocks[1],
c2=mmcm_clocks[2],
c3=mmcm_clocks[3],
c4=mmcm_clocks[4],
c5=mmcm_clocks[5],
c6=mmcm_clocks[6],
c7=mmcm_clocks[7],
c8=mmcm_clocks[8],
c9=mmcm_clocks[9],
c10=mmcm_clocks[10],
c11=mmcm_clocks[11],
c12=mmcm_clocks[12],
))
for _, site in gen_sites('PLLE2_ADV'):
pll_clocks = [
'pll_clock_{site}_{idx}'.format(site=site, idx=idx)
for idx in range(7)
]
for clk in pll_clocks:
cmt_clock_sources.add_clock_source(clk, site_to_cmt[site])
print(
"""
wire cin1_{site}, cin2_{site}, clkfbin_{site}, {c0}, {c1}, {c2}, {c3}, {c4}, {c5}, {c6};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
PLLE2_ADV pll_{site} (
.CLKIN1(cin1_{site}),
.CLKIN2(cin2_{site}),
.CLKFBIN(clkfbin_{site}),
.CLKOUT0({c0}),
.CLKOUT1({c1}),
.CLKOUT2({c2}),
.CLKOUT3({c3}),
.CLKOUT4({c4}),
.CLKOUT5({c5}),
.CLKFBOUT({c6})
);
""".format(
site=site,
c0=pll_clocks[0],
c1=pll_clocks[1],
c2=pll_clocks[2],
c3=pll_clocks[3],
c4=pll_clocks[4],
c5=pll_clocks[5],
c6=pll_clocks[6],
))
for tile_name, site in gen_sites('BUFHCE'):
print(
"""
wire I_{site};
wire O_{site};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFHCE buf_{site} (
.I(I_{site}),
.O(O_{site})
);""".format(site=site),
file=bufs)
global_clock_sources.add_clock_source(
'O_{site}'.format(site=site), site_to_cmt[site])
hclks_used_by_clock_region = {}
for cmt in site_to_cmt.values():
hclks_used_by_clock_region[cmt] = set()
def check_hclk_src(src, src_cmt):
if len(hclks_used_by_clock_region[src_cmt]
) >= 12 and src not in hclks_used_by_clock_region[src_cmt]:
return None
else:
hclks_used_by_clock_region[src_cmt].add(src)
return src
cmt_clks_used_by_clock_region = {}
for cmt in site_to_cmt.values():
cmt_clks_used_by_clock_region[cmt] = list()
def check_cmt_clk_src(src, src_clock_region):
print(
"//src: {}, clk_reg: {}, len {}".format(
src, src_clock_region,
len(cmt_clks_used_by_clock_region[src_clock_region])))
if len(cmt_clks_used_by_clock_region[src_clock_region]) >= 4:
return None
else:
cmt_clks_used_by_clock_region[src_clock_region].append(src)
return src
#Add IDELAYCTRL
idelayctrl_in_clock_region = {}
for cmt in site_to_cmt.values():
idelayctrl_in_clock_region[cmt] = False
for _, site in gen_sites('IDELAYCTRL'):
if random.random() < 0.5:
wire_name = global_clock_sources.get_random_source(
site_to_cmt[site], no_repeats=False)
if wire_name is None:
continue
src_cmt = global_clock_sources.source_to_cmt[wire_name]
wire_name = check_hclk_src(wire_name, src_cmt)
if wire_name is None:
continue
idelayctrl_in_clock_region[src_cmt] = True
print(
"""
assign I_{site} = {clock_source};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
IDELAYCTRL idelay_ctrl_{site} (
.RDY(),
.REFCLK(I_{site}),
.RST()
);""".format(site=site, clock_source=wire_name))
# Add SERDES driven by BUFH or MMCM
for tile, site in gen_sites('ILOGICE2'):
wire_name = None
clock_region = site_to_cmt[site]
if clock_region not in clock_region_limit:
# Select serdes limit and relative location per clock region
serdes_location = random.choice(["TOP", "BOTTOM", "ANY"])
if serdes_location in "ANY":
#We want TOP and BOTTOM IGCLK PIPs occupied but leave one slot for IDELAYCTRL
if idelayctrl_in_clock_region[clock_region]:
clock_region_limit[clock_region] = 0 if random.random(
) < 0.2 else 11
else:
clock_region_limit[clock_region] = 0 if random.random(
) < 0.2 else 12
else:
if idelayctrl_in_clock_region[clock_region]:
clock_region_limit[clock_region] = 0 if random.random(
) < 0.2 else 5
else:
clock_region_limit[clock_region] = 0 if random.random(
) < 0.2 else 6
clock_region_serdes_location[clock_region] = serdes_location
# We reached the limit of hclks in this clock region
if clock_region_limit[clock_region] == 0:
continue
# Add a serdes if it's located at the correct side from the HCLK_IOI tile
if clock_region_serdes_location[clock_region] not in "ANY" and \
serdes_relative_location(tile, site) != clock_region_serdes_location[clock_region]:
continue
if random.random() > 0.3:
wire_name = global_clock_sources.get_random_source(
site_to_cmt[site], no_repeats=True)
if wire_name is None:
continue
src_cmt = global_clock_sources.source_to_cmt[wire_name]
wire_name = check_hclk_src(wire_name, src_cmt)
if wire_name is None:
print("//wire is None")
continue
clock_region_limit[clock_region] -= 1
print(
"""
assign serdes_clk_{site} = {clock_source};""".format(
site=site, clock_source=wire_name))
else:
wire_name = cmt_fast_clock_sources.get_random_source(
site_to_cmt[site], no_repeats=False)
if wire_name is None:
continue
src_cmt = cmt_fast_clock_sources.source_to_cmt[wire_name]
wire_name = check_cmt_clk_src(wire_name, src_cmt)
if wire_name is None:
continue
bufio_site = get_clock_region_site("BUFIO", clock_region)
if bufio_site is None:
continue
print(
"""
assign serdes_clk_{serdes_loc} = O_{site};
assign I_{site} = {clock_source};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFIO bufio_{site} (
.O(O_{site}),
.I(I_{site})
);""".format(site=bufio_site, clock_source=wire_name, serdes_loc=site))
print(
"// clock_region: {} {}".format(
clock_region, clock_region_serdes_location[clock_region]))
print(
"""
(* KEEP, DONT_TOUCH, LOC = "{loc}" *)
ISERDESE2 #(
.DATA_RATE("SDR"),
.DATA_WIDTH(4),
.DYN_CLKDIV_INV_EN("FALSE"),
.DYN_CLK_INV_EN("FALSE"),
.INIT_Q1(1'b0),
.INIT_Q2(1'b0),
.INIT_Q3(1'b0),
.INIT_Q4(1'b0),
.INTERFACE_TYPE("OVERSAMPLE"),
.IOBDELAY("NONE"),
.NUM_CE(2),
.OFB_USED("FALSE"),
.SERDES_MODE("MASTER"),
.SRVAL_Q1(1'b0),
.SRVAL_Q2(1'b0),
.SRVAL_Q3(1'b0),
.SRVAL_Q4(1'b0)
)
ISERDESE2_inst_{loc} (
.CLK(serdes_clk_{loc}),
.CLKB(),
.CLKDIV(),
.D(1'b0),
.DDLY(),
.OFB(),
.OCLKB(),
.RST(),
.SHIFTIN1(),
.SHIFTIN2()
);
""".format(loc=site, clock_source=wire_name))
# BUFRs
for _, site in gen_sites('BUFR'):
if random.random() < 0.5:
if random.random() < 0.5:
wire_name = luts.get_next_output_net()
else:
wire_name = cmt_fast_clock_sources.get_random_source(
site_to_cmt[site], no_repeats=False)
if wire_name is None:
continue
src_cmt = cmt_fast_clock_sources.source_to_cmt[wire_name]
wire_name = check_cmt_clk_src(wire_name, src_cmt)
if wire_name is None:
continue
bufr_clock_sources.add_clock_source(
'O_{site}'.format(site=site), site_to_cmt[site])
# Add DIVIDE
divide = "BYPASS"
if random.random() < 0.8:
divide = "{}".format(random.randint(2, 8))
print(
"""
assign I_{site} = {clock_source};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFR #(.BUFR_DIVIDE("{divide}")) bufr_{site} (
.O(O_{site}),
.I(I_{site})
);""".format(site=site, clock_source=wire_name, divide=divide),
file=bufs)
for _, site in gen_sites('MMCME2_ADV'):
wire_name = bufr_clock_sources.get_random_source(
site_to_cmt[site], no_repeats=True)
if wire_name is None:
continue
print(
"""
assign cin1_{site} = {wire_name};""".format(
site=site, wire_name=wire_name))
print(bufs.getvalue())
for l in luts.create_wires_and_luts():
print(l)
print("endmodule")
if __name__ == '__main__':
main()

View File

@ -322,7 +322,7 @@ foreach tile_type {HCLK_IOI3} {
}
foreach tile_type {RIOI3 LIOI3 LIOI3_TBYTETERM RIOI3_TBYTETERM \
LIOI3_TBYTESRC RIOI3_TBYTESRC LIOI3_SING RIOI3_SING} {
LIOI3_TBYTESRC RIOI3_TBYTESRC LIOI3_SING RIOI3_SING RIOI RIOI_SING RIOI_TBYTESRC RIOI_TBYTETERM} {
set tiles [get_tiles -filter "TILE_TYPE == $tile_type"]
if {[llength $tiles] != 0} {
set tile [lindex $tiles 0]
@ -392,7 +392,7 @@ foreach tile_type {PCIE_INT_INTERFACE_L PCIE_INT_INTERFACE_R} {
}
}
foreach tile_type {RIOB33 LIOB33 RIOB33_SING LIOB33_SING} {
foreach tile_type {RIOB33 LIOB33 RIOB33_SING LIOB33_SING RIOB18 RIOB18_SING} {
set tiles [get_tiles -filter "TILE_TYPE == $tile_type"]
if {[llength $tiles] != 0} {
set tile [lindex $tiles 0]

View File

@ -113,6 +113,9 @@ $(eval $(call fuzzer,027-bram36-config,005-tilegrid,all))
$(eval $(call fuzzer,028-fifo-config,005-tilegrid,all))
$(eval $(call fuzzer,029-bram-fifo-config,005-tilegrid,all))
$(eval $(call fuzzer,030-iob,005-tilegrid,all))
ifeq ($(XRAY_DATABASE),kintex7)
$(eval $(call fuzzer,030-iob18,005-tilegrid,all))
endif
$(eval $(call fuzzer,031-cmt-mmcm,005-tilegrid,all))
$(eval $(call fuzzer,032-cmt-pll,005-tilegrid,all))
$(eval $(call fuzzer,034-cmt-pll-pips,005-tilegrid 071-ppips,all))
@ -123,9 +126,18 @@ $(eval $(call fuzzer,034b-cmt-mmcm-pips,005-tilegrid 071-ppips,all))
endif
$(eval $(call fuzzer,035-iob-ilogic,005-tilegrid,all))
$(eval $(call fuzzer,035a-iob-idelay,005-tilegrid,all))
ifeq ($(XRAY_DATABASE),kintex7)
$(eval $(call fuzzer,035a-iob18-idelay,005-tilegrid,all))
endif
$(eval $(call fuzzer,035b-iob-iserdes,005-tilegrid,all))
$(eval $(call fuzzer,036-iob-ologic,005-tilegrid,all))
ifeq ($(XRAY_DATABASE),kintex7)
$(eval $(call fuzzer,036-iob18-ologic,005-tilegrid,all))
endif
$(eval $(call fuzzer,037-iob-pips,005-tilegrid 035b-iob-iserdes,all))
ifeq ($(XRAY_DATABASE),kintex7)
$(eval $(call fuzzer,037-iob18-pips,005-tilegrid 035b-iob-iserdes,all))
endif
$(eval $(call fuzzer,038-cfg,005-tilegrid,all))
$(eval $(call fuzzer,039-hclk-config,005-tilegrid,all))
$(eval $(call fuzzer,040-clk-hrow-config,005-tilegrid,all))
@ -136,6 +148,9 @@ $(eval $(call fuzzer,044-clk-bufg-pips,046-clk-bufg-muxed-pips,all))
$(eval $(call fuzzer,045-hclk-cmt-pips,005-tilegrid,all))
$(eval $(call fuzzer,046-clk-bufg-muxed-pips,005-tilegrid,all))
$(eval $(call fuzzer,047-hclk-ioi-pips,005-tilegrid,all))
ifeq ($(XRAY_DATABASE),kintex7)
$(eval $(call fuzzer,047-hclk-ioi18-pips,005-tilegrid,all))
endif
$(eval $(call fuzzer,047a-hclk-idelayctrl-pips,047-hclk-ioi-pips,all))
$(eval $(call fuzzer,048-int-piplist,005-tilegrid,all))
$(eval $(call fuzzer,049-int-imux-gfan,048-int-piplist,all))

View File

@ -359,6 +359,8 @@ class Segmaker:
-CLK_HROW_TOP_R => CLK_HROW
-LIOB33 => IOB33
-LIOI3 => IOI3
-RIOB18 => IOB18
-RIOI => IOI
'''
tile_type_norm = re.sub("(_TOP|_BOT|LL|LM)?_[LR]$", "", tile_type)
tile_type_norm = re.sub(
@ -366,13 +368,20 @@ class Segmaker:
if tile_type_norm in ['LIOB33', 'RIOB33']:
tile_type_norm = 'IOB33'
if tile_type_norm in ['LIOB18', 'RIOB18']:
tile_type_norm = 'IOB18'
if tile_type_norm in ['LIOI3', 'RIOI3']:
tile_type_norm = 'IOI3'
if tile_type_norm in ['LIOI', 'RIOI']:
tile_type_norm = 'IOI'
if tile_type_norm in ['LIOI3_TBYTESRC', 'RIOI3_TBYTESRC']:
tile_type_norm = 'IOI3'
if tile_type_norm in ['LIOI3_TBYTETERM', 'RIOI3_TBYTETERM']:
tile_type_norm = 'IOI3'
if tile_type_norm in ['LIOI_TBYTESRC', 'RIOI_TBYTESRC']:
tile_type_norm = 'IOI'
if tile_type_norm in ['LIOI_TBYTETERM', 'RIOI_TBYTETERM']:
tile_type_norm = 'IOI'
if tile_type_norm in ['CMT_TOP_L_LOWER_B', 'CMT_TOP_R_LOWER_B']:
tile_type_norm = 'CMT_LOWER_B'
if 'GTP_CHANNEL' in tile_type_norm:

View File

@ -86,8 +86,8 @@ def get_fabric():
def get_part_information(db_root, part):
filename = os.path.join(db_root, "mapping", "parts.yaml")
assert os.path.isfile(filename), \
"Mapping file {} does not exists".format(filename)
with OpenSafeFile(filename, 'r') as stream:
"Mapping file {} does not exist".format(filename)
with open(filename, 'r') as stream:
part_mapping = yaml.load(stream, Loader=yaml.FullLoader)
part = part_mapping.get(part, None)
assert part, "Part {} not found in {}".format(part, part_mapping)
@ -99,14 +99,14 @@ def set_part_information(db_root, information):
with OpenSafeFile(filename, 'w+') as stream:
yaml.dump(information, stream)
assert os.path.isfile(filename), \
"Mapping file {} does not exists".format(filename)
"Mapping file {} does not exist".format(filename)
def get_part_resources(file_path, part):
filename = os.path.join(file_path, "resources.yaml")
assert os.path.isfile(filename), \
"Mapping file {} does not exists".format(filename)
with OpenSafeFile(filename, 'r') as stream:
"Mapping file {} does not exist".format(filename)
with open(filename, 'r') as stream:
res_mapping = yaml.load(stream, Loader=yaml.FullLoader)
res = res_mapping.get(part, None)
assert res, "Part {} not found in {}".format(part, part_mapping)
@ -118,13 +118,13 @@ def set_part_resources(file_path, information):
with OpenSafeFile(filename, 'w+') as stream:
yaml.dump(information, stream)
assert os.path.isfile(filename), \
"Mapping file {} does not exists".format(filename)
"Mapping file {} does not exist".format(filename)
def get_fabric_for_part(db_root, part):
filename = os.path.join(db_root, "mapping", "devices.yaml")
assert os.path.isfile(filename), \
"Mapping file {} does not exists".format(filename)
"Mapping file {} does not exist".format(filename)
part = get_part_information(db_root, part)
with OpenSafeFile(filename, 'r') as stream:
device_mapping = yaml.load(stream, Loader=yaml.FullLoader)
@ -137,8 +137,8 @@ def get_fabric_for_part(db_root, part):
def get_devices(db_root):
filename = os.path.join(db_root, "mapping", "devices.yaml")
assert os.path.isfile(filename), \
"Mapping file {} does not exists".format(filename)
with OpenSafeFile(filename, 'r') as stream:
"Mapping file {} does not exist".format(filename)
with open(filename, 'r') as stream:
device_mapping = yaml.load(stream, Loader=yaml.FullLoader)
return device_mapping
@ -146,8 +146,8 @@ def get_devices(db_root):
def get_parts(db_root):
filename = os.path.join(db_root, "mapping", "parts.yaml")
assert os.path.isfile(filename), \
"Mapping file {} does not exists".format(filename)
with OpenSafeFile(filename, 'r') as stream:
"Mapping file {} does not exist".format(filename)
with open(filename, 'r') as stream:
part_mapping = yaml.load(stream, Loader=yaml.FullLoader)
return part_mapping

View File

@ -10,17 +10,17 @@ export XRAY_PART="xc7k70tfbg676-2"
export XRAY_ROI_FRAMES="0x00000000:0xffffffff"
# FIXME: make entire part
export XRAY_ROI_TILEGRID="SLICE_X0Y50:SLICE_X19Y99 DSP48_X0Y20:DSP48_X0Y39 RAMB18_X0Y20:RAMB18_X0Y39 RAMB36_X0Y10:RAMB36_X0Y19"
export XRAY_ROI_TILEGRID="SLICE_X0Y50:SLICE_X19Y99 DSP48_X0Y20:DSP48_X0Y39 RAMB18_X0Y0:RAMB18_X3Y39 RAMB36_X0Y0:RAMB36_X3Y19"
export XRAY_EXCLUDE_ROI_TILEGRID=""
export XRAY_IOI3_TILES="LIOI3_X0Y9"
export XRAY_IOI3_TILES="LIOI3_X0Y9 RIOI_X43Y9"
# These settings must remain in sync
export XRAY_ROI="SLICE_X0Y50:SLICE_X19Y99 DSP48_X0Y20:DSP48_X0Y39 RAMB18_X0Y20:RAMB18_X0Y39 RAMB36_X0Y10:RAMB36_X0Y19 IOB_X0Y50:IOB_X0Y99"
export XRAY_ROI="SLICE_X0Y50:SLICE_X19Y99 DSP48_X0Y20:DSP48_X0Y39 RAMB18_X0Y0:RAMB18_X3Y39 RAMB36_X0Y0:RAMB36_X3Y19 IOB_X0Y50:IOB_X0Y99 IOB_X1Y50:IOB_X1Y99"
# Part of CMT X0Y1
export XRAY_ROI_GRID_X1="0"
export XRAY_ROI_GRID_X2="38"
export XRAY_ROI_GRID_X2="116"
# Include VBRK / VTERM
export XRAY_ROI_GRID_Y1="104"
export XRAY_ROI_GRID_Y2="156"

View File

@ -255,7 +255,7 @@ int main(int argc, char** argv) {
read_input(f, argv[optind]);
}
} else {
printf("Reading from stding.\n");
printf("Reading from stdin...\n");
read_input(std::cin, "stdin");
}

View File

@ -121,6 +121,9 @@ case "$1" in
riob33)
sed < "$2" > "$tmp1" -e 's/^IOB33\./RIOB33./' ;;
riob18)
sed < "$2" > "$tmp1" -e 's/^IOB18\./RIOB18./' ;;
lioi3)
sed < "$2" > "$tmp1" -e 's/^IOI3\./LIOI3./' ;;
@ -133,12 +136,21 @@ case "$1" in
rioi3)
sed < "$2" > "$tmp1" -e 's/^IOI3\./RIOI3./' ;;
rioi)
sed < "$2" > "$tmp1" -e 's/^IOI\./RIOI./' ;;
rioi3_tbytesrc)
sed < "$2" > "$tmp1" -e 's/^IOI3\./RIOI3_TBYTESRC./' ;;
rioi_tbytesrc)
sed < "$2" > "$tmp1" -e 's/^IOI\./RIOI_TBYTESRC./' ;;
rioi3_tbyteterm)
sed < "$2" > "$tmp1" -e 's/^IOI3\./RIOI3_TBYTETERM./' ;;
rioi_tbyteterm)
sed < "$2" > "$tmp1" -e 's/^IOI\./RIOI_TBYTETERM./' ;;
cmt_top_r_upper_t)
sed < "$2" > "$tmp1" -e 's/^CMT_UPPER_T\./CMT_TOP_R_UPPER_T./' ;;
@ -157,6 +169,9 @@ case "$1" in
hclk_ioi3)
cp "$2" "$tmp1" ;;
hclk_ioi)
cp "$2" "$tmp1" ;;
pcie_bot)
cp "$2" "$tmp1" ;;