text: 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_iserdese2(p, luts, connects):
      iobdelay = random.choice((
          'NONE',
          'BOTH',
          'IBUF',
          'IFD',
      ))
  
      p['IOBDELAY'] = verilog.quote(iobdelay)
      p['INIT_Q1'] = random.randint(0, 1)
      p['INIT_Q2'] = random.randint(0, 1)
      p['INIT_Q3'] = random.randint(0, 1)
      p['INIT_Q4'] = random.randint(0, 1)
  
      p['SRVAL_Q1'] = random.randint(0, 1)
      p['SRVAL_Q2'] = random.randint(0, 1)
      p['SRVAL_Q3'] = random.randint(0, 1)
      p['SRVAL_Q4'] = random.randint(0, 1)
      p['NUM_CE'] = random.randint(1, 2)
  
      p['IS_CLK_INVERTED'] = random.randint(0, 1)
      p['IS_CLKB_INVERTED'] = random.randint(0, 1)
      p['IS_OCLK_INVERTED'] = random.randint(0, 1)
      p['IS_OCLKB_INVERTED'] = random.randint(0, 1)
      p['IS_CLKDIV_INVERTED'] = random.randint(0, 1)
      p['IS_D_INVERTED'] = random.randint(0, 1)
      p['INTERFACE_TYPE'] = verilog.quote(
          random.choice(
              (
                  'MEMORY',
                  'MEMORY_DDR3',
                  'MEMORY_QDR',
                  'NETWORKING',
                  'OVERSAMPLE',
              )))
      p['DATA_RATE'] = verilog.quote(random.choice((
          'SDR',
          'DDR',
      )))
      if verilog.unquote(p['DATA_RATE']) == 'SDR':
          data_widths = [2, 3, 4, 5, 6, 7, 8]
      else:
          data_widths = [4, 6, 8]
  
      p['DATA_WIDTH'] = random.choice(data_widths)
      p['SERDES_MODE'] = verilog.quote(random.choice(('MASTER', 'SLAVE')))
  
      use_delay = iobdelay != 'NONE'
  
      if iobdelay == 'NONE':
          p['mux_config'] = 'direct'
          p['iddr_mux_config'] = 'direct'
      elif iobdelay == 'BOTH':
          p['mux_config'] = 'idelay'
          p['iddr_mux_config'] = 'idelay'
      elif iobdelay == 'IBUF':
          p['mux_config'] = 'idelay'
          p['iddr_mux_config'] = 'direct'
      elif iobdelay == 'IFD':
          p['mux_config'] = 'direct'
          p['iddr_mux_config'] = 'idelay'
  
      p['OFB_USED'] = verilog.quote(random.choice(('TRUE', 'FALSE')))
      p['DYN_CLKDIV_INV_EN'] = verilog.quote(random.choice(('TRUE', 'FALSE')))
      p['DYN_CLK_INV_EN'] = verilog.quote(random.choice(('TRUE', 'FALSE')))
  
      if use_delay:
          print(
              """
      wire idelay_{site};
  
      (* KEEP, DONT_TOUCH, LOC = "{idelay_loc}" *)
      IDELAYE2 #(
      ) idelay_site_{site} (
          .IDATAIN({iwire}),
          .DATAOUT(idelay_{site})
          );""".format(**p),
              file=connects)
  
          p['ddly_connection'] = '.DDLY(idelay_{site}),'.format(**p)
      else:
          p['ddly_connection'] = ''
  
      if verilog.unquote(p['OFB_USED']) == 'TRUE':
          p['ODATA_RATE'] = verilog.quote(random.choice((
              'SDR',
              'DDR',
          )))
          if verilog.unquote(p['ODATA_RATE']) == 'SDR':
              data_widths = [2, 3, 4, 5, 6, 7, 8]
          else:
              data_widths = [4, 6, 8]
  
          p['ODATA_WIDTH'] = random.choice(data_widths)
          p['OSERDES_MODE'] = verilog.quote(random.choice(('MASTER', 'SLAVE')))
  
          if p['ODATA_WIDTH'] == 4 and verilog.unquote(p['ODATA_RATE']) == 'DDR':
              p['TRISTATE_WIDTH'] = 4
          else:
              p['TRISTATE_WIDTH'] = 1
  
          print(
              """
      wire tfb_{site};
      wire ofb_{site};
  
      (* KEEP, DONT_TOUCH, LOC = "{ologic_loc}" *)
      OSERDESE2 #(
          .SERDES_MODE({OSERDES_MODE}),
          .DATA_RATE_TQ({ODATA_RATE}),
          .DATA_RATE_OQ({ODATA_RATE}),
          .DATA_WIDTH({ODATA_WIDTH}),
          .TRISTATE_WIDTH({TRISTATE_WIDTH})
      ) oserdese2_{site} (
          .CLK(0),
          .CLKDIV(0),
          .D1(0),
          .TFB(tfb_{site}),
          .OQ({owire}),
          .TQ({twire}),
          .OFB(ofb_{site})
          );""".format(**p),
              file=connects)
  
          p['ofb_connections'] = """
          .OFB(ofb_{site}),
          """.format(**p)
      else:
          p['ofb_connections'] = ''
  
      if random.randint(0, 1):
          clknet = luts.get_next_output_net()
      else:
          clknet = random.choice((
              'clk_BUFG1',
              'clk_BUFG2',
          ))
  
      if random.randint(0, 1):
          clkbnet = luts.get_next_output_net()
      else:
          clkbnet = random.choice((
              'clk_BUFG1',
              'clk_BUFG2',
          ))
  
      if random.randint(0, 1):
          oclknet = luts.get_next_output_net()
      else:
          oclknet = random.choice((
              'clk_BUFG1',
              'clk_BUFG2',
          ))
  
      clkdiv = random.choice(('clk_BUFG3', 'clk_BUFG4'))
  
      p['DISABLE_CLOCKS'] = random.randint(0, 1)
      if p['DISABLE_CLOCKS']:
          clknet = '0'
          clkbnet = '0'
          oclknet = '0'
          clkdiv = '0'
  
      print(
          '''
      (* KEEP, DONT_TOUCH, LOC = "{ilogic_loc}" *)
      ISERDESE2 #(
          .SERDES_MODE({SERDES_MODE}),
          .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}),
          .DYN_CLKDIV_INV_EN({DYN_CLKDIV_INV_EN}),
          .DYN_CLK_INV_EN({DYN_CLK_INV_EN}),
          .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}),
          .IS_CLKDIV_INVERTED({IS_CLKDIV_INVERTED}),
          .IS_D_INVERTED({IS_D_INVERTED}),
          .OFB_USED({OFB_USED}),
          .NUM_CE({NUM_CE}),
          .DATA_RATE({DATA_RATE}),
          .DATA_WIDTH({DATA_WIDTH}),
          .IOBDELAY({IOBDELAY})
      ) iserdese2_{site} (
          {ddly_connection}
          {ofb_connections}
          .D({iwire}),
          .CLK({clknet}),
          .CLKB({clkbnet}),
          .OCLK({oclknet}),
          .O({onet}),
          .Q1({q1net}),
          .CLKDIV({clkdiv})
      );'''.format(
              clkdiv=clkdiv,
              clknet=clknet,
              clkbnet=clkbnet,
              oclknet=oclknet,
              onet=luts.get_next_input_net(),
              q1net=luts.get_next_input_net(),
              shiftout1net=luts.get_next_input_net(),
              shiftout2net=luts.get_next_input_net(),
              **p),
          file=connects)
  
  
  def use_direct_and_iddr(p, luts, connects):
      p['mux_config'] = random.choice((
          'direct',
          'idelay',
          'none',
      ))
  
      p['iddr_mux_config'] = random.choice((
          'direct',
          'idelay',
          'none',
      ))
  
      if p['iddr_mux_config'] != 'none':
          p['INIT_Q1'] = random.randint(0, 1)
          p['INIT_Q2'] = random.randint(0, 1)
          p['IS_C_INVERTED'] = random.randint(0, 1)
          p['IS_D_INVERTED'] = random.randint(0, 1)
          p['SRTYPE'] = verilog.quote(random.choice(('SYNC', 'ASYNC')))
          p['DDR_CLK_EDGE'] = verilog.quote(
              random.choice(
                  (
                      'OPPOSITE_EDGE',
                      'SAME_EDGE',
                      'SAME_EDGE_PIPELINED',
                  )))
  
          print(
              '''
      (* KEEP, DONT_TOUCH, LOC = "{ilogic_loc}" *)
      IDDR #(
          .IS_D_INVERTED({IS_D_INVERTED}),
          .IS_C_INVERTED({IS_C_INVERTED}),
          .INIT_Q1({INIT_Q1}),
          .INIT_Q2({INIT_Q2}),
          .SRTYPE({SRTYPE}),
          .DDR_CLK_EDGE({DDR_CLK_EDGE})
      ) iddr_{site} (
          .C({cnet}),
          .D(iddr_d_{site}),
          .Q1({q1}),
          .Q2({q2})
          );
          '''.format(
                  cnet=luts.get_next_output_net(),
                  q1=luts.get_next_input_net(),
                  q2=luts.get_next_input_net(),
                  **p),
              file=connects)
  
      if p['iddr_mux_config'] == 'idelay' or p['mux_config'] == 'idelay' or p[
              'iddr_mux_config'] == 'tristate_feedback':
          print(
              """
      wire idelay_{site};
  
      (* KEEP, DONT_TOUCH, LOC = "{idelay_loc}" *)
      IDELAYE2 #(
      ) idelay_site_{site} (
          .IDATAIN({iwire}),
          .DATAOUT(idelay_{site})
          );""".format(**p),
              file=connects)
  
      print(
          """
      assign {owire} = {onet};
      assign {twire} = {tnet};
          """.format(
              onet=luts.get_next_output_net(),
              tnet=luts.get_next_output_net(),
              **p),
          file=connects)
  
      if p['iddr_mux_config'] == 'direct':
          print(
              '''
      assign iddr_d_{site} = {iwire};'''.format(**p, ),
              file=connects)
      elif p['iddr_mux_config'] == 'idelay':
          print(
              '''
      assign iddr_d_{site} = idelay_{site};'''.format(**p, ),
              file=connects)
      elif p['iddr_mux_config'] == 'tristate_feedback':
          print(
              '''
      assign iddr_d_{site} = tfb_{site} ? ofb_{site} : idelay_{site};'''.format(
                  **p, ),
              file=connects)
      elif p['iddr_mux_config'] == 'none':
          pass
      else:
          assert False, p['mux_config']
  
      if p['mux_config'] == 'direct':
          print(
              '''
      assign {net} = {iwire};'''.format(
                  net=luts.get_next_input_net(),
                  **p,
              ),
              file=connects)
      elif p['mux_config'] == 'idelay':
          print(
              '''
      assign {net} = idelay_{site};'''.format(
                  net=luts.get_next_input_net(),
                  **p,
              ),
              file=connects)
      elif p['mux_config'] == 'none':
          pass
      else:
          assert False, p['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['idelay_loc'] = site.replace('IOB', 'IDELAY')
          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;
  
      wire clk_BUFG1;
      wire clk_BUFG2;
      wire clk_BUFG3;
      wire clk_BUFG4;
  
      (* KEEP, DONT_TOUCH  *)
      BUFG bufg1(
          .O(clk_BUFG1)
          );
      (* KEEP, DONT_TOUCH  *)
      BUFG bufg2(
          .O(clk_BUFG2)
          );
      (* KEEP, DONT_TOUCH  *)
      BUFG bufg3(
          .O(clk_BUFG3)
          );
      (* KEEP, DONT_TOUCH  *)
      BUFG bufg4(
          .O(clk_BUFG4)
          );
      '''.format(n_di=idx))
  
      # Always output a LUT6 to make placer happy.
      print(
          '''
          (* KEEP, DONT_TOUCH *)
          LUT6 dummy_lut();
          ''')
  
      any_idelay = False
  
      for p in params:
          print(
              '''
          wire iddr_d_{site};
  
          (* KEEP, DONT_TOUCH, LOC = "{site}" *)
          IOBUF #(
              .IOSTANDARD({IOSTANDARD})
          ) ibuf_{site} (
              .IO({pad_wire}),
              .I({owire}),
              .O({iwire}),
              .T({twire})
              );
              '''.format(**p),
              file=connects)
  
          p['use_iserdese2'] = random.randint(0, 1)
          if p['use_iserdese2']:
              use_iserdese2(p, luts, connects)
          else:
              use_direct_and_iddr(p, luts, connects)
  
          if p['iddr_mux_config'] == 'idelay' or p['mux_config'] == 'idelay':
              any_idelay = True
  
      if any_idelay:
          print("""
      (* KEEP, DONT_TOUCH *)
      IDELAYCTRL();""")
  
      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()
  