mirror of https://github.com/openXC7/prjxray.git
add support for the kintex high performance banks
Signed-off-by: Hans Baier <hansfbaier@gmail.com>
This commit is contained in:
parent
480218e9c0
commit
e929e5519b
|
|
@ -50,6 +50,7 @@ DB_SIMPLE=\
|
|||
segbits_cmt_top_r_lower_b \
|
||||
segbits_rioi3 \
|
||||
segbits_riob33 \
|
||||
segbits_riob18 \
|
||||
segbits_hclk_cmt \
|
||||
segbits_hclk_ioi3 \
|
||||
|
||||
|
|
|
|||
|
|
@ -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]]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ 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]
|
||||
puts $fp "$site,$tile,[get_property CLOCK_REGION $site]"
|
||||
# exclude IDELAYCTRL from high speed banks
|
||||
if {![string match "*_IOI_*" $tile]} {
|
||||
puts $fp "$site,$tile,[get_property CLOCK_REGION $site]"
|
||||
}
|
||||
}
|
||||
}
|
||||
close $fp
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# IOB18 Fuzzer
|
||||
|
||||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# HCLK_IOI interconnect fuzzer
|
||||
|
||||
Solves pips located within the HCLK_IOI switch box.
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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" ;;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue