diff --git a/fuzzers/036-iob-ologic/Makefile b/fuzzers/036-iob-ologic/Makefile new file mode 100644 index 00000000..63e4b3ad --- /dev/null +++ b/fuzzers/036-iob-ologic/Makefile @@ -0,0 +1,20 @@ +N := 40 +include ../fuzzer.mk + +database: build/segbits_xiob33.db + +build/segbits_xiob33.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} -c 6 -o build/segbits_xiob33.rdb $$(find -name segdata_liob33.txt) $$(find -name segdata_riob33.txt) + +build/segbits_xiob33.db: build/segbits_xiob33.rdb + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --seg-fn-in $^ --seg-fn-out $@ + ${XRAY_MASKMERGE} build/mask_xiob33.db $$(find -name segdata_liob33.txt) $$(find -name segdata_riob33.txt) + +pushdb: + ${XRAY_MERGEDB} liob33 build/segbits_xiob33.db + ${XRAY_MERGEDB} riob33 build/segbits_xiob33.db + ${XRAY_MERGEDB} mask_liob33 build/mask_xiob33.db + ${XRAY_MERGEDB} mask_riob33 build/mask_xiob33.db + +.PHONY: database pushdb + diff --git a/fuzzers/036-iob-ologic/bits.dbf b/fuzzers/036-iob-ologic/bits.dbf new file mode 100644 index 00000000..70361308 --- /dev/null +++ b/fuzzers/036-iob-ologic/bits.dbf @@ -0,0 +1,3 @@ +31_92,IOB33.IOB_Y0.ODDR.DDR_CLK_EDGE.OPPOSITE_EDGE +30_35,IOB33.IOB_Y1.ODDR.DDR_CLK_EDGE.OPPOSITE_EDGE + diff --git a/fuzzers/036-iob-ologic/generate.py b/fuzzers/036-iob-ologic/generate.py new file mode 100644 index 00000000..b2bf192f --- /dev/null +++ b/fuzzers/036-iob-ologic/generate.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 + +from prjxray.segmaker import Segmaker +from prjxray import verilog +import json + + +def handle_data_width(segmk, d): + if 'DATA_WIDTH' not in d: + return + + if d['DATA_RATE_OQ'] == 'DDR': + return + + for opt in [2, 3, 4, 5, 6, 7, 8, 10, 14]: + segmk.add_site_tag( + d['site'], 'OSERDESE.DATA_WIDTH.{}'.format(opt), + d['DATA_WIDTH'] == opt) + + +def handle_data_rate(segmk, d): + if 'DATA_WIDTH' not in d: + return + + for opt in ['SDR', 'DDR']: + segmk.add_site_tag( + d['site'], 'OSERDESE.DATA_RATE.{}'.format(opt), + verilog.unquote(d['DATA_RATE_OQ']) == opt) + + +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['site'] + + handle_data_width(segmk, d) + handle_data_rate(segmk, d) + + if d['use_oserdese2']: + if 'SRTYPE' in d: + for opt in ['ASYNC', 'SYNC']: + segmk.add_site_tag( + site, 'OSERDESE.SRTYPE.{}'.format(opt), + verilog.unquote(d['SRTYPE']) == opt) + + for opt in ['SDR', 'DDR']: + segmk.add_site_tag( + site, 'OSERDESE.DATA_RATE_OQ.{}'.format(opt), + verilog.unquote(d['DATA_RATE_OQ']) == opt) + + for opt in ['BUF', 'SDR', 'DDR']: + segmk.add_site_tag( + site, 'OSERDESE.DATA_RATE_TQ.{}'.format(opt), + verilog.unquote(d['DATA_RATE_TQ']) == opt) + + if d['oddr_mux_config'] != 'none': + segmk.add_site_tag(site, 'OFF.ZINIT_Q', not d['QINIT']) + 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) + + if d['tddr_mux_config'] != 'none': + segmk.add_site_tag(site, 'TFF.ZINIT_Q', not d['TINIT']) + # Note: edge settings seem to be ignored for TFF + for opt in ['OPPOSITE_EDGE', 'SAME_EDGE']: + segmk.add_site_tag( + site, 'TDDR.DDR_CLK_EDGE.{}'.format(opt), + verilog.unquote(d['TDDR_CLK_EDGE']) != opt) + + # all the bellow mux configs give 0 candidates + # this is wierd, as they are set when DDR output is used + # something's fishy here + if d['oddr_mux_config'] == 'direct': + segmk.add_site_tag(site, 'OMUXE2', 0) + + elif d['oddr_mux_config'] == 'none': + segmk.add_site_tag(site, 'OMUXE2', 1) + else: + assert False, d['oddr_mux_config'] + + if d['tddr_mux_config'] == 'direct': + segmk.add_site_tag(site, 'TMUXE2', 0) + + elif d['tddr_mux_config'] == 'none': + segmk.add_site_tag(site, 'TMUXE2', 1) + else: + assert False, d['tddr_mux_config'] + + segmk.compile() + segmk.write(allow_empty=True) + + +if __name__ == "__main__": + main() diff --git a/fuzzers/036-iob-ologic/generate.tcl b/fuzzers/036-iob-ologic/generate.tcl new file mode 100644 index 00000000..85caab36 --- /dev/null +++ b/fuzzers/036-iob-ologic/generate.tcl @@ -0,0 +1,99 @@ +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 IOB33* [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 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 {REQP-79}] + + write_checkpoint -force design_pre_place.dcp + + place_design + route_design + + write_checkpoint -force design.dcp + write_bitstream -force design.bit +} + +run diff --git a/fuzzers/036-iob-ologic/top.py b/fuzzers/036-iob-ologic/top.py new file mode 100644 index 00000000..9e4d07ca --- /dev/null +++ b/fuzzers/036-iob-ologic/top.py @@ -0,0 +1,323 @@ +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(): + ''' + IOB33S: main IOB of a diff pair + IOB33M: secondary IOB of a diff pair + IOB33: not a diff pair. Relatively rare (at least in ROI...2 of them?) + Focus on IOB33S to start + ''' + db = Database(util.get_db_root()) + 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 ['IOB33S', 'IOB33M']: + 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'))) + + 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}) + ) oserdese2_{site} ( + .OQ({owire}), + .TFB(tfb_{site}), + .TQ({twire}), + .CLK({clknet}), + .CLKDIV({clkdivnet}), + .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( + clknet=luts.get_next_output_net(), + clkdivnet=luts.get_next_output_net(), + 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(), + t1net=luts.get_next_output_net(), + t2net=luts.get_next_output_net(), + t3net=luts.get_next_output_net(), + t4net=luts.get_next_output_net(), + tcenet=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', + 'none', + )) + + p['tddr_mux_config'] = random.choice(( + 'direct', + 'none', + )) + + # toddr and oddr share the same clk + clknet = luts.get_next_output_net() + + if p['tddr_mux_config'] != 'none': + 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'))) + print( + ''' + (* KEEP, DONT_TOUCH, LOC = "{ologic_loc}" *) + ODDR #( + .INIT({TINIT}), + .SRTYPE({TSRTYPE}), + .DDR_CLK_EDGE({TDDR_CLK_EDGE}) + ) toddr_{site} ( + .C({cnet}), + .D1({d1net}), + .D2({d2net}), + .CE({cenet}), + .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'] == 'none': + pass + else: + assert False, p['tddr_mux_config'] + + if p['oddr_mux_config'] != 'none': + 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', + ))) + + print( + ''' + (* KEEP, DONT_TOUCH, LOC = "{ologic_loc}" *) + ODDR #( + .INIT({QINIT}), + .SRTYPE({SRTYPE}), + .DDR_CLK_EDGE({ODDR_CLK_EDGE}) + ) oddr_{site} ( + .C({cnet}), + .D1({d1net}), + .D2({d2net}), + .CE({cenet}), + .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'] == 'none': + pass + else: + assert False, p['oddr_mux_config'] + + +def run(): + iostandards = [ + 'LVCMOS12', 'LVCMOS15', 'LVCMOS18', 'LVCMOS25', 'LVCMOS33', 'LVTTL' + ] + iostandard = random.choice(iostandards) + + if iostandard in ['LVTTL', 'LVCMOS18']: + drives = [4, 8, 12, 16, 24] + elif iostandard == 'LVCMOS12': + drives = [4, 8, 12] + else: + drives = [4, 8, 12, 16] + + slews = ['FAST', 'SLOW'] + pulls = ["NONE", "KEEPER", "PULLDOWN", "PULLUP"] + + luts = lut_maker.LutMaker() + + connects = io.StringIO() + + tile_params = [] + params = [] + 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['pad_wire'] = 'dio[{}]'.format(idx - 1) + p['owire'] = 'do_buf[{}]'.format(idx - 1) + p['iwire'] = 'di_buf[{}]'.format(idx - 1) + p['twire'] = 't[{}]'.format(idx - 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_DI {n_di} + +module top(input clk, inout wire [`N_DI-1:0] dio); + wire [`N_DI-1:0] di_buf; + wire [`N_DI-1:0] do_buf; + wire [`N_DI-1:0] t; + '''.format(n_di=idx)) + + # Always output a LUT6 to make placer happy. + print( + ''' + (* KEEP, DONT_TOUCH *) + LUT6 dummy_lut(); + ''') + + for p in params: + 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) + + 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() diff --git a/fuzzers/Makefile b/fuzzers/Makefile index 9bf0aee3..db9f8e5c 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -75,6 +75,7 @@ $(eval $(call fuzzer,028-fifo-config,005-tilegrid)) $(eval $(call fuzzer,029-bram-fifo-config,005-tilegrid)) $(eval $(call fuzzer,030-iob,005-tilegrid)) $(eval $(call fuzzer,035-iob-ilogic,005-tilegrid)) +$(eval $(call fuzzer,036-iob-ologic,005-tilegrid)) $(eval $(call fuzzer,040-clk-hrow-config,005-tilegrid)) $(eval $(call fuzzer,041-clk-hrow-pips,005-tilegrid)) # 042 fuzzer is unstable, issue #657