005-tilegrid: add iob18_sing sub-fuzzer for SING-row IOB18 sites

The existing iob18 sub-fuzzer filters to IOB18S (main IOB of a diff
pair) and ioi18 explicitly skips _SING tile types, so the SING-row
IOB18 singletons (one IOB18 site per LIOB18_SING / RIOB18_SING tile)
never had their tilegrid frame addresses resolved.  On xc7vx485t this
left 28 tile rows un-addressed in tilegrid.json.

Add a parallel iob18_sing sub-fuzzer: places an IBUF on every SING-row
IOB18 site (14 specimens), bit-diffs to a segbits_tilegrid.tdb, and
hooks into TILEGRID_TDB_DEPENDENCIES alongside iob18 / iob18_int so
add_tdb.py merges the resulting frame addresses into tilegrid.json.

Pairs with task #17 (HP-bank glue end-to-end).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Dr Jonathan Richard Robert Kimmitt 2026-05-30 15:53:15 +01:00
parent f8b9075808
commit 1574e9ca85
4 changed files with 193 additions and 0 deletions

View File

@ -72,6 +72,7 @@ endif
ifeq (${HAS_HIGH_PERFORMANCE_BANKS}, 1)
TILEGRID_TDB_DEPENDENCIES += iob18/$(BUILD_FOLDER)/segbits_tilegrid.tdb
TILEGRID_TDB_DEPENDENCIES += iob18_int/$(BUILD_FOLDER)/segbits_tilegrid.tdb
TILEGRID_TDB_DEPENDENCIES += iob18_sing/$(BUILD_FOLDER)/segbits_tilegrid.tdb
TILEGRID_TDB_DEPENDENCIES += ioi18/$(BUILD_FOLDER)/segbits_tilegrid.tdb
# GTX transceiver fuzzers. Kintex-7 only: the xc7vx485t-ffg1761 package used for
# virtex7 bonds only ~7 of its 14 GTX quads, so the unbonded GTX_COMMON tiles
@ -129,6 +130,9 @@ iob_int/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
iob18_int/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
cd iob18_int && $(MAKE)
iob18_sing/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
cd iob18_sing && $(MAKE)
ioi/$(BUILD_FOLDER)/segbits_tilegrid.tdb: ${BASICDB_TILEGRID}
cd ioi && $(MAKE)
@ -233,6 +237,7 @@ clean:
cd iob18 && $(MAKE) clean
cd iob_int && $(MAKE) clean
cd iob18_int && $(MAKE) clean
cd iob18_sing && $(MAKE) clean
cd ioi && $(MAKE) clean
cd ioi18 && $(MAKE) clean
cd mmcm && $(MAKE) clean
@ -270,6 +275,7 @@ clean_part:
cd iob18 && $(MAKE) clean_part
cd iob_int && $(MAKE) clean_part
cd iob18_int && $(MAKE) clean_part
cd iob18_sing && $(MAKE) clean_part
cd ioi && $(MAKE) clean_part
cd ioi18 && $(MAKE) clean_part
cd mmcm && $(MAKE) clean_part

View File

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

View File

@ -0,0 +1,86 @@
# Copyright (C) 2017-2020 The Project X-Ray Authors
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
source "$::env(XRAY_DIR)/utils/utils.tcl"
proc make_io_pin_sites {} {
# get all possible IOB pins
foreach pad [get_package_pins -filter "IS_GENERAL_PURPOSE == 1"] {
set site [get_sites -of_objects $pad]
if {[llength $site] == 0} {
continue
}
if [string match IOB18* [get_property SITE_TYPE $site]] {
dict append io_pin_sites $site $pad
}
}
return $io_pin_sites
}
proc load_pin_lines {} {
# IOB_X0Y103 clk input
# IOB_X0Y129 do[0] output
set fp [open "params.csv" r]
gets $fp line
set pin_lines {}
for {gets $fp line} {$line != ""} {gets $fp line} {
lappend pin_lines [split $line ","]
}
close $fp
return $pin_lines
}
proc loc_pins {} {
set pin_lines [load_pin_lines]
set io_pin_sites [make_io_pin_sites]
puts "Looping"
for {set idx 0} {$idx < [llength $pin_lines]} {incr idx} {
set line [lindex $pin_lines $idx]
puts "$line"
set site_str [lindex $line 2]
set pin_str [lindex $line 3]
# Have: site
# Want: pin for site
set site [get_sites $site_str]
set pad_bel [get_bels -of_objects $site -filter {TYPE =~ PAD && NAME =~ IOB_*}]
# set port [get_ports -of_objects $site]
set port [get_ports $pin_str]
set tile [get_tiles -of_objects $site]
set pin [dict get $io_pin_sites $site]
set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS18" $port
}
}
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
loc_pins
set_property CFGBVS GND [current_design]
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_property IS_ENABLED 0 [get_drc_checks {REQP-79}]
set_property IS_ENABLED 0 [get_drc_checks {NSTD-1}]
set_property IS_ENABLED 0 [get_drc_checks {UCIO-1}]
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
}
run

View File

@ -0,0 +1,91 @@
#!/usr/bin/env python3
# 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
#
# 005-tilegrid sub-fuzzer for SING-row IOB18 tiles. The existing
# iob18 sub-fuzzer filters to `IOB18S` (the main IOB of a diff pair)
# and ioi18 explicitly skips `_SING` tile types, so the SING-row
# IOB18 sites (one per LIOB18_SING / RIOB18_SING tile) never get
# their tilegrid frame addresses resolved by the existing fuzzers.
# This sub-fuzzer addresses that gap (task #17): place an IBUF on
# every SING-row IOB18 site, then bit-diff produces a tdb that
# add_tdb.py merges into tilegrid.json.
import os
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray.db import Database
def gen_sites():
'''SING-row IOB18 singleton sites: tile_type ends in _SING, site
type is plain IOB18 (no S/M suffix, no diff-pair partner).'''
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 not gridinfo.tile_type.endswith("_SING"):
continue
# Skip non-IOB SING tiles (LIOI_SING etc.); only LIOB18_SING
# / RIOB18_SING expose an IOB18 site.
for site_name, site_type in gridinfo.sites.items():
if site_type == 'IOB18':
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()