005-tilegrid: top-SING alias start_offset 0 -> 2 (OLOGIC/IOB)

propagate_IOB_SING and propagate_IOI_SING set the top SING-row tile's alias
start_offset to 0, mapping the full tile's lower words (0-1) into the tile's
only frame words (99-100).  But nextpnr-xilinx targets the full tile's UPPER
OLOGIC/IOB words (2-3) on the top SING tile; under start_offset 0 those map to
absolute frame words 101-102, which don't exist, so fasm2frames raises
"invalid word address" and silently drops the features (e.g. a VC707 LED or
UART output on LIOI_SING_X82Y51.OLOGIC_Y0).

start_offset 2 (effective offset 97) lands words 2-3 at abs 99-100 -- matching
the bottom SING tiles and the HW-verified tilegrid data fix.  Confirmed by
re-running fuzzer 036-iob18-ologic-sing (OLOGIC_Y0.OMUX.D1 at abs word 100) and
by the open-flow UART DSP calculator computing correctly on hardware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dr Jonathan Richard Robert Kimmitt 2026-06-10 06:33:48 +01:00
parent 6fd1d26311
commit 0e3f20b577
1 changed files with 15 additions and 2 deletions

View File

@ -406,9 +406,16 @@ def propagate_IOB_SING(database, tiles_by_grid):
database[top_tile]['bits']['CLB_IO_CLK'] = copy.deepcopy(bits)
database[top_tile]['bits']['CLB_IO_CLK']['words'] = 2
database[top_tile]['bits']['CLB_IO_CLK']['offset'] = 99
# start_offset 2 (not 0): the top SING tile only has frame words 99-100,
# and nextpnr-xilinx places the IOB features that live in the full
# tile's *upper* words (2-3) here. With start_offset 0 those map to
# absolute words 101-102, which don't exist -> fasm2frames "invalid
# word address" and the features are silently dropped. start_offset 2
# gives effective offset 97 so words 2-3 land at abs 99-100. HW-verified
# (VC707 open-flow UART DSP calculator computes correctly).
database[top_tile]['bits']['CLB_IO_CLK']['alias'] = {
'type': database[prev_tile]['type'],
'start_offset': 0,
'start_offset': 2,
'sites': {
'IOB33_Y0': 'IOB33_Y1',
}
@ -481,9 +488,15 @@ def propagate_IOI_SING(database, tiles_by_grid):
database[top_tile]['bits']['CLB_IO_CLK'] = copy.deepcopy(bits)
database[top_tile]['bits']['CLB_IO_CLK']['words'] = 2
database[top_tile]['bits']['CLB_IO_CLK']['offset'] = 99
# start_offset 2 (not 0): see propagate_IOB_SING. The top SING IOI tile
# has only frame words 99-100; nextpnr-xilinx targets the full tile's
# upper OLOGIC/ILOGIC words (2-3) here, which under start_offset 0 map to
# absolute words 101-102 (don't exist) and get dropped by fasm2frames.
# start_offset 2 -> effective offset 97 -> words 2-3 at abs 99-100.
# HW-verified via the open-flow calculator (OLOGIC_Y0.OMUX.D1 @ abs 100).
database[top_tile]['bits']['CLB_IO_CLK']['alias'] = {
'type': database[prev_tile]['type'],
'start_offset': 0,
'start_offset': 2,
'sites': {}
}