diff --git a/fuzzers/037-iob-pips/Makefile b/fuzzers/037-iob-pips/Makefile new file mode 100644 index 00000000..f31f236a --- /dev/null +++ b/fuzzers/037-iob-pips/Makefile @@ -0,0 +1,48 @@ +export FUZDIR=$(shell pwd) +PIP_TYPE?=ioi3 +PIPLIST_TCL=$(FUZDIR)/ioi3_pip_list.tcl + +TODO_RE="[LR]IOI3\.(IOI_([IO]LOGIC[01]_CLK(DIV|B)?)|(IOI_OCLK_[01]))\.IOI_LEAF_GCLK[0-9]" + +MAKETODO_FLAGS=--pip-type ${PIP_TYPE} --seg-type $(PIP_TYPE) --re $(TODO_RE) +N = 40 + +SEGMATCH_FLAGS=-c 2 -m 15 -M 30 +SPECIMENS_DEPS=build/cmt_regions.csv + +include ../pip_loop.mk + +build/segbits_ioi3_x.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_ioi3_x.rdb \ + $(shell find build -name segdata_lioi3*.txt) $(shell find build -name segdata_rioi3*.txt) + +RDBS = build/segbits_ioi3_x.rdb + +database: ${RDBS} + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ + --seg-fn-in build/segbits_ioi3_x.rdb \ + --seg-fn-out build/segbits_ioi3_x.db + + # Keep a copy to track iter progress + cp build/segbits_ioi3_x.rdb build/$(ITER)/segbits_ioi3_x.rdb + cp build/segbits_ioi3_x.db build/$(ITER)/segbits_ioi3_x.db + + + ${XRAY_MASKMERGE} build/mask_xioi3.db \ + $(shell find build -name segdata_ioi3_l.txt) \ + $(shell find build -name segdata_ioi3_r.txt) + + # 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} ioi3_l build/segbits_ioi3_x.db + XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} ioi3_r build/segbits_ioi3_x.db + +build/cmt_regions.csv: output_cmt.tcl + mkdir -p build + cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl + +pushdb: + ${XRAY_MERGEDB} lioi3 build/segbits_ioi3_x.db + ${XRAY_MERGEDB} rioi3 build/segbits_ioi3_x.db + +.PHONY: database pushdb diff --git a/fuzzers/037-iob-pips/bits.dbf b/fuzzers/037-iob-pips/bits.dbf new file mode 100644 index 00000000..e69de29b diff --git a/fuzzers/037-iob-pips/generate.py b/fuzzers/037-iob-pips/generate.py new file mode 100644 index 00000000..5ea9eb91 --- /dev/null +++ b/fuzzers/037-iob-pips/generate.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 + +from prjxray.segmaker import Segmaker +import os, re +import os.path + + +def bitfilter(frame, word): + if frame < 26: + return False + return True + + +def main(): + segmk = Segmaker("design.bits") + + tiledata = {} + pipdata = {} + ignpip = set() + + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', + 'ioi3', 'ioi3_l.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)) + + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', + 'ioi3', 'ioi3_r.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('LIOI3') and not tile.startswith('RIOI3'): + 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) + + if pnum == 1 or pdir == 0: + print("Ignoring pip: {}".format(pip), file=log) + ignpip.add((src, dst)) + + for tile, pips_srcs_dsts in tiledata.items(): + tile_type = pips_srcs_dsts["type"] + + if tile_type.startswith('LIOI3'): + tile_type = 'LIOI3' + elif tile_type.startswith('RIOI3'): + tile_type = 'RIOI3' + + pips = pips_srcs_dsts["pips"] + + 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 (src, dst) not in tiledata[tile]["pips"]: + segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 0) + + internal_feedback = False + + segmk.compile(bitfilter=bitfilter) + segmk.write() + + +if __name__ == "__main__": + main() diff --git a/fuzzers/037-iob-pips/generate.tcl b/fuzzers/037-iob-pips/generate.tcl new file mode 100644 index 00000000..8b81bcbe --- /dev/null +++ b/fuzzers/037-iob-pips/generate.tcl @@ -0,0 +1,250 @@ +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 load_todo {} { + set fp [open "../todo.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 .] + dict lappend todo_map [lindex $parts 1] [list [lindex $parts 0] [lindex $parts 2]] + } + close $fp + return $todo_map +} + +proc route_todo {} { + puts "Checking TODO's" + set todo_map [load_todo] + + puts $todo_map + + set nets [get_nets] + + set todo_nets [dict create] + set used_sources [dict create] + + foreach net $nets { + # Check to see if this net is one we are interested in + set wires [get_wires -of_objects $net -filter {TILE_NAME =~ *IOI3*}] + set is_gclk_net 0 + foreach wire $wires { + if [regexp "IOI_\[IO\]LOGIC\[01\]_CLKB?" $wire] { + set is_gclk_net 1 + break + } + if [regexp "IOI_OCLK_\[01\]" $wire] { + set is_gclk_net 1 + break + } + if [regexp "IOI_\[IO\]LOGIC\[01\]_CLKDIV" $wire] { + set is_gclk_net 1 + break + } + } + + if {$is_gclk_net == 0} { + puts "$net not going to a IOI3 port, skipping." + continue + } + + foreach wire $wires { + 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 srcs [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 src $srcs { + set src_tile_type [lindex $src 0] + + if {$src_tile_type != $tile_type} { + continue + } + + set src_wire [lindex $src 1] + + if { $other_wire == $src } { + set found_target 1 + puts "Interesting net $net already going from $wire to $other_wire." + break + } + } + } + + if { $found_target == 1 } { + # Net has an interesting + continue + } + + dict set todo_nets $net [list $tile $wire] + puts "Interesting net $net (including $wire) is being rerouted." + } + } + + dict for {net tile_wire} $todo_nets { + set tile [lindex $tile_wire 0] + set wire [lindex $tile_wire 1] + set srcs [dict get $todo_map $wire] + set site [lindex [get_sites -of_objects [get_tiles $tile]] 0] + set region [get_clock_regions -of_objects [get_sites $site]] + + puts "Rerouting net $net at $tile / $wire (type $tile_type)" + + set tile_type [get_property TILE_TYPE [get_tiles $tile]] + + set todos {} + 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 "IOI_LEAF_GCLK\[0-9\]+" $src_wire] { + set is_gclk_net 1 + } + + if {$is_gclk_net == 0} { + continue + } + + lappend todos $src_wire + } + + puts "All todos for $tile_type / $wire" + foreach src_wire $todos { + puts " - $src_wire" + } + + route_design -unroute -nets $net + + # Find an input in the todo list that this can can drive. + foreach src_wire $todos { + puts "Attempting to route to $src_wire for net $net." + set target_wire [get_wires "$tile/$src_wire"] + set target_node [get_nodes -of_objects $target_wire] + + if {[llength $target_node] == 0} { + error "Failed to find node for $tile/$src_wire." + } + + if { [regexp ".*TOP.*" $target_node match group] } { + set loc TOP + } elseif { [regexp ".*BOT.*" $target_node match group] } { + set loc BOT + } + + if { [dict exists $used_sources "$region/$loc/$src_wire"] } { + puts "Not routing to $tile / $src_wire, in use." + continue + } + + + set old_nets [get_nets -of_objects $target_node] + + if { $old_nets != {} } { + set old_nets_property [get_property IS_ROUTE_FIXED [get_nets -of_objects $target_node]] + if { $old_nets_property == 0 } { + route_design -unroute -nets $old_nets + } + } + + set origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] + set new_route [find_routing_path -to $target_node -from $origin_node] + puts "Origin node: $origin_node" + puts "Target wire: $target_wire" + puts "Target node: $target_node" + + # Only need to set route to one of the destinations. + # Router will handle the rest. + set_property FIXED_ROUTE $new_route $net + + dict set used_sources "$region/$loc/$src_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-25}] + set_property IS_ENABLED 0 [get_drc_checks {PDRC-39}] + 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-98}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-99}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-123}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-144}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-1576}] + set_property IS_ENABLED 0 [get_drc_checks {AVAL-74}] + set_property IS_ENABLED 0 [get_drc_checks {AVAL-81}] + set_property IS_ENABLED 0 [get_drc_checks {DRC INBB-1}] + + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets] + + place_design + route_design + write_checkpoint -force design_before.dcp + + route_todo + route_design + write_checkpoint -force design_after.dcp + + set_property SEVERITY {Warning} [get_drc_checks UCIO-1] + set_property SEVERITY {Warning} [get_drc_checks NSTD-1] + + write_bitstream -force design.bit + write_pip_txtdata design.txt +} + +run diff --git a/fuzzers/037-iob-pips/ioi3_pip_list.tcl b/fuzzers/037-iob-pips/ioi3_pip_list.tcl new file mode 100644 index 00000000..6eb726ca --- /dev/null +++ b/fuzzers/037-iob-pips/ioi3_pip_list.tcl @@ -0,0 +1,43 @@ +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 $src] + if { $dst_node == {} } { + continue + } + + if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 1} { + 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 + +# Cleaning ioi3.txt pip file +set fp [open ioi3.txt w] +close $fp + +print_tile_pips LIOI3 ioi3_l.txt +print_tile_pips RIOI3 ioi3_r.txt diff --git a/fuzzers/037-iob-pips/output_cmt.tcl b/fuzzers/037-iob-pips/output_cmt.tcl new file mode 100644 index 00000000..663789a5 --- /dev/null +++ b/fuzzers/037-iob-pips/output_cmt.tcl @@ -0,0 +1,11 @@ +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 ILOGICE3 OLOGICE3 IDELAYE2 IDELAYCTRL PLLE2_ADV} { + foreach site [get_sites -filter "SITE_TYPE == $site_type"] { + puts $fp "$site,[get_property CLOCK_REGION $site]" + } +} +close $fp diff --git a/fuzzers/037-iob-pips/top.py b/fuzzers/037-iob-pips/top.py new file mode 100644 index 00000000..e5fc72ef --- /dev/null +++ b/fuzzers/037-iob-pips/top.py @@ -0,0 +1,336 @@ +import json +import io +import os +import random +import math +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 + +NOT_INCLUDED_TILES = ['LIOI3_SING', 'RIOI3_SING'] + +SITE_TYPES = ['OLOGICE3', 'ILOGICE3'] + +REGIONAL_CLOCK_BUFFERS = ['BUFHCE', 'BUFIO'] +GLOBAL_CLOCK_BUFFERS = ['BUFGCTRL'] +CLOCK_BUFFERS = REGIONAL_CLOCK_BUFFERS + GLOBAL_CLOCK_BUFFERS + +MAX_REG_CLK_BUF = 2 +MAX_GLB_CLK_BUF = 24 +CUR_CLK = 0 +MAX_ATTEMPTS = 50 + + +def get_location(tile_name, divisor): + y_location = int(tile_name.split("Y")[-1]) + + if math.floor(y_location / divisor) % 2 == 0: + # Location is on the bottom of the row/tile + return "BOT" + else: + return "TOP" + + +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(site_types): + ''' + Generates all sites belonging to `site_types` of + a desired `tile` + ''' + db = Database(util.get_db_root()) + grid = db.grid() + + tiles = grid.tiles() + + #Randomize tiles + tiles_list = list(tiles) + random.shuffle(tiles_list) + + for tile_name in tiles: + loc = grid.loc_of_tilename(tile_name) + gridinfo = grid.gridinfo_at_loc(loc) + tile_type = gridinfo.tile_type + + for site_name, site_type in gridinfo.sites.items(): + if site_type in site_types: + yield tile_type, tile_name, site_type, site_name + + +def generate_mmcm(site_to_cmt, clock_region): + mmcm_clocks = None + + for _, _, _, site in gen_sites('MMCME2_ADV'): + mmcm_region = site_to_cmt[site] + + if mmcm_region == clock_region: + mmcm_clocks = [ + 'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx) + for idx in range(3) + ] + + print( + """ + wire {c0}, {c1}, {c2}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + MMCME2_ADV mmcm_{site} ( + .CLKOUT0({c0}), + .CLKOUT1({c1}), + .CLKOUT2({c2}) + );""".format( + site=site, + c0=mmcm_clocks[0], + c1=mmcm_clocks[1], + c2=mmcm_clocks[2])) + + if not mmcm_clocks: + return None + + return mmcm_clocks + + +def generate_glb_clk_buf(clock_regions, mmcm_clocks_dict): + clk_buf_count = 0 + + clock_signals = [] + + for tile_type, _, site_type, site_name in gen_sites(GLOBAL_CLOCK_BUFFERS): + + if clk_buf_count >= MAX_GLB_CLK_BUF: + break + + clock_signal = "buf_clk_{site}".format(site=site_name) + + if site_type == 'BUFGCTRL': + mmcm_clocks = [] + + for clock_region in clock_regions: + # BUFGCTRL must have the clock coming from the same fabric row + if ('Y0' in clock_region and tile_type == 'CLK_BUFG_BOT_R' + ) or ('Y0' not in clock_region + and tile_type == 'CLK_BUFG_TOP_R'): + mmcm_clocks = mmcm_clocks_dict[clock_region] + break + + assert mmcm_clocks, "No clock can be produced. Buffer not instantiated" + + print( + ''' + wire {clk_out}; + + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFG buf_{site} (.I({clk_in}), .O({clk_out}));'''.format( + clk_in=random.choice(mmcm_clocks), + clk_out=clock_signal, + site=site_name)) + + else: + assert False, "The site is somehow corrupted" + + clk_buf_count += 1 + + clock_signals.append(clock_signal) + + return clock_signals + + +def generate_reg_clk_buf(site_to_cmt, clock_region, mmcm_clocks, buf_type): + clk_buf_count = 0 + clock_signals = [] + + for tile_type, _, site_type, site_name in gen_sites( + REGIONAL_CLOCK_BUFFERS): + buf_region = site_to_cmt[site_name] + + if clk_buf_count >= MAX_REG_CLK_BUF: + break + + if buf_type != site_type: + continue + + if buf_region != clock_region: + continue + + clock_signal = "buf_clk_{site}".format(site=site_name) + + if site_type == 'BUFR': + print( + ''' + wire {clk_out}; + + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFR buf_{site} (.I({clk_in}), .O({clk_out}));'''.format( + clk_in=random.choice(mmcm_clocks), + clk_out=clock_signal, + site=site_name)) + + elif site_type == 'BUFIO': + print( + ''' + wire {clk_out}; + + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFIO buf_{site} (.I({clk_in}), .O({clk_out}));'''.format( + clk_in=random.choice(mmcm_clocks), + clk_out=clock_signal, + site=site_name)) + + elif site_type == 'BUFHCE': + print( + ''' + wire {clk_out}; + + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFH buf_{site} (.I({clk_in}), .O({clk_out}));'''.format( + clk_in=random.choice(mmcm_clocks), + clk_out=clock_signal, + site=site_name)) + + else: + assert False, "The site is somehow corrupted" + + clk_buf_count += 1 + + clock_signals.append(clock_signal) + + return clock_signals + + +def get_clock_signal(clock_signals, clock_types): + ''' + Get a unique clock signals for a specific tile. + ''' + global CUR_CLK + + clock_signal_string = '' + is_first_clock = True + + for clock_type in clock_types: + if random.choice([True, True, False]): + continue + + clock_signal = clock_signals[CUR_CLK] + if is_first_clock: + clock_signal_string += ''' + .{}({})'''.format(clock_type, clock_signal) + else: + clock_signal_string += ''', + .{}({})'''.format(clock_type, clock_signal) + + is_first_clock = False + + CUR_CLK = (CUR_CLK + 1) % MAX_GLB_CLK_BUF + + return clock_signal_string + + +def run(): + + global CUR_CLK + # One buffer type for each specimen + buf_type = random.choice(GLOBAL_CLOCK_BUFFERS) + + site_location = random.choice(['TOP', 'BOT']) + + site_to_cmt = dict(read_site_to_cmt()) + clock_regions = list(dict.fromkeys(site_to_cmt.values())) + + print("module top();") + + clock_mmcm_dict = {} + clock_signals_dict = {} + site_types_dict = {} + + # Generate MMCM Clock generator + for clock_region in clock_regions: + mmcm_clocks = generate_mmcm(site_to_cmt, clock_region) + + if mmcm_clocks: + clock_mmcm_dict[clock_region] = mmcm_clocks + clock_signals_dict[clock_region] = [] + + if buf_type in REGIONAL_CLOCK_BUFFERS: + clock_signals_dict[clock_region] = generate_reg_clk_buf( + site_to_cmt, clock_region, mmcm_clocks, buf_type) + else: + clock_regions.remove(clock_region) + + if buf_type in GLOBAL_CLOCK_BUFFERS: + clock_signals = generate_glb_clk_buf(clock_regions, clock_mmcm_dict) + + for clock_region in clock_regions: + clock_signals_dict[clock_region] = clock_signals + site_types_dict[clock_region] = random.choice(SITE_TYPES) + + half_column_used_clocks = {} + + for tile_type, tile_name, site_type, site_name in gen_sites(SITE_TYPES): + if tile_type in NOT_INCLUDED_TILES: + continue + + if random.choice([True, True, False]): + continue + + site_region = site_to_cmt[site_name] + + if site_type != site_types_dict[site_region]: + continue + + clock_signals = clock_signals_dict[site_region] + + bot_or_top = get_location(site_name, 1) + + half_column = '{}_{}'.format(site_region, get_location(tile_name, 25)) + + if half_column not in half_column_used_clocks: + half_column_used_clocks[half_column] = { + 'TOP': { + 'ILOGIC': + get_clock_signal(clock_signals, ['CLK', 'CLKB', 'CLKDIV']), + 'OLOGIC': + get_clock_signal(clock_signals, ['CLK', 'CLKDIV']) + }, + 'BOT': { + 'ILOGIC': + get_clock_signal(clock_signals, ['CLK', 'CLKB', 'CLKDIV']), + 'OLOGIC': + get_clock_signal(clock_signals, ['CLK', 'CLKDIV']) + } + } + + if site_type == 'ILOGICE3': + print( + ''' + (* KEEP, DONT_TOUCH, LOC = "{site_name}" *) + ISERDESE2 #( + .DATA_RATE("SDR") + ) iserdes_{site_name} ({clk});'''.format( + site_name=site_name, + clk=half_column_used_clocks[half_column][bot_or_top] + ['ILOGIC'])) + elif site_type == 'OLOGICE3': + print( + ''' + (* KEEP, DONT_TOUCH, LOC = "{site_name}" *) + OSERDESE2 #( + .DATA_RATE_OQ("SDR"), + .DATA_RATE_TQ("SDR") + ) oserdes_{site_name} ({clk});'''.format( + site_name=site_name, + clk=half_column_used_clocks[half_column][bot_or_top] + ['OLOGIC'])) + + print("endmodule") + + +if __name__ == '__main__': + run() diff --git a/fuzzers/Makefile b/fuzzers/Makefile index c515cde3..532fa5d1 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -88,6 +88,7 @@ $(eval $(call fuzzer,034-cmt-pll-pips,005-tilegrid)) $(eval $(call fuzzer,035-iob-ilogic,005-tilegrid)) $(eval $(call fuzzer,035a-iob-idelay,005-tilegrid)) $(eval $(call fuzzer,036-iob-ologic,005-tilegrid)) +$(eval $(call fuzzer,037-iob-pips,005-tilegrid)) $(eval $(call fuzzer,038-cfg,005-tilegrid)) $(eval $(call fuzzer,040-clk-hrow-config,005-tilegrid)) $(eval $(call fuzzer,041-clk-hrow-pips,005-tilegrid)) diff --git a/utils/mergedb.sh b/utils/mergedb.sh index 6e85a2c3..d39cd95b 100755 --- a/utils/mergedb.sh +++ b/utils/mergedb.sh @@ -144,6 +144,12 @@ case "$1" in hclk_ioi3) cp "$2" "$tmp1" ;; + ioi3_l) + sed < "$2" > "$tmp1" -e 's/^IOI3\./LIOI3./' ;; + + ioi3_r) + sed < "$2" > "$tmp1" -e 's/^IOI3\./RIOI3./' ;; + mask_*) db=$XRAY_DATABASE_DIR/$XRAY_DATABASE/$1.db ismask=true