blob: 7e3db78e955e5c9c383d56484bd19cc822351c83 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2023 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
import os, random
random.seed(int(os.getenv("SEED"), 16))
import sys
import json
from prjxray import util
from prjxray.db import Database
# =============================================================================
def gen_sites():
db = Database(util.get_db_root(), util.get_part())
grid = db.grid()
tile_list = []
for tile_name in sorted(grid.tiles()):
if "IOB18" not in tile_name or "SING" in tile_name:
continue
tile_list.append(tile_name)
get_xy = util.create_xy_fun('RIOB18_')
tile_list.sort(key=get_xy)
for iob_tile_name in tile_list:
iob_gridinfo = grid.gridinfo_at_loc(
grid.loc_of_tilename(iob_tile_name))
# Find IOI tile adjacent to IOB
for suffix in ["IOI", "IOI_TBYTESRC", "IOI_TBYTETERM"]:
try:
ioi_tile_name = iob_tile_name.replace("IOB18", suffix)
ioi_gridinfo = grid.gridinfo_at_loc(
grid.loc_of_tilename(ioi_tile_name))
break
except KeyError:
pass
iob18s = [k for k, v in iob_gridinfo.sites.items() if v == "IOB18S"][0]
iob18m = [k for k, v in iob_gridinfo.sites.items() if v == "IOB18M"][0]
odelay_s = iob18s.replace("IOB", "ODELAY")
odelay_m = iob18m.replace("IOB", "ODELAY")
yield iob18m, odelay_m, iob18s, odelay_s
def run():
# Get all [LR]IOI3 tiles
tiles = list(gen_sites())
# Header
print("// Tile count: %d" % len(tiles))
print("// Seed: '%s'" % os.getenv("SEED"))
ninputs = 0
do_idx = []
for i, sites in enumerate(tiles):
if random.randint(0, 1):
do_idx.append(ninputs)
ninputs += 1
else:
do_idx.append(None)
print(
'''
module top (
(* CLOCK_BUFFER_TYPE = "NONE" *)
input wire clk,
output wire [{N}:0] do
);
wire clk_buf = clk;
wire [{N}:0] do_buf;
'''.format(N=ninputs - 1))
# LOCes IOBs
data = []
for i, (sites, obuf_idx) in enumerate(zip(tiles, do_idx)):
if random.randint(0, 1):
iob_inuse = sites[0]
iob_other = sites[2]
odelay_inuse = sites[1]
odelay_other = sites[3]
else:
iob_inuse = sites[2]
iob_other = sites[0]
odelay_inuse = sites[3]
odelay_other = sites[1]
use_obuf = obuf_idx is not None
if not use_obuf:
continue
params = {
"LOC":
"\"" + odelay_inuse + "\"",
"ODELAY_TYPE":
"\"" + random.choice(
["FIXED", "VARIABLE", "VAR_LOAD"]) + "\"",
"ODELAY_VALUE":
random.randint(0, 31),
"HIGH_PERFORMANCE_MODE":
"\"" + random.choice(["TRUE", "FALSE"]) + "\"",
"CINVCTRL_SEL":
"\"" + random.choice(["TRUE", "FALSE"]) + "\"",
"PIPE_SEL":
"\"" + random.choice(["TRUE", "FALSE"]) + "\"",
"IS_C_INVERTED":
random.randint(0, 1),
"IS_ODATAIN_INVERTED":
random.randint(0, 1),
}
if params["ODELAY_TYPE"] != "\"VAR_LOAD_PIPE\"":
params["PIPE_SEL"] = "\"FALSE\""
# The datasheet says that for these two modes the delay is set to 0
if params["ODELAY_TYPE"] == "\"VAR_LOAD\"":
params["ODELAY_VALUE"] = 0
if params["ODELAY_TYPE"] == "\"VAR_LOAD_PIPE\"":
params["ODELAY_VALUE"] = 0
if params["ODELAY_TYPE"] == "\"FIXED\"":
params["IS_C_INVERTED"] = 0
param_str = ",".join(".%s(%s)" % (k, v) for k, v in params.items())
if random.randint(0, 5) == 0:
print('')
print('(* LOC="%s", KEEP, DONT_TOUCH *)' % iob_inuse)
print(
'OBUF obuf_%03d (.I(%d), .O(do[%3d]));' %
(obuf_idx, random.randint(0, 1), obuf_idx))
params['ODELAY_BYPASS'] = True
params["ODELAY_NOT_IN_USE"] = odelay_inuse + " " + odelay_other
else:
print('')
print('(* LOC="%s", KEEP, DONT_TOUCH *)' % iob_inuse)
print(
'OBUF obuf_%03d (.I(do_buf[%3d]), .O(do[%3d]));' %
(obuf_idx, obuf_idx, obuf_idx))
print(
'mod #(%s) mod_%03d (.clk(clk_buf), .O(do_buf[%3d]));' %
(param_str, i, obuf_idx))
params['ODELAY_BYPASS'] = False
params["ODELAY_IN_USE"] = odelay_inuse
params["ODELAY_NOT_IN_USE"] = odelay_other
data.append(params)
# Store params
with open("params.json", "w") as fp:
json.dump(data, fp, sort_keys=True, indent=1)
print(
'''
// IDELAYCTRL
(* KEEP, DONT_TOUCH *)
IDELAYCTRL idelayctrl();
endmodule
(* KEEP, DONT_TOUCH *)
module mod(
input wire clk,
output wire O
);
parameter LOC = "";
parameter ODELAY_TYPE = "FIXED";
parameter ODELAY_VALUE = 0;
parameter DELAY_SRC = "ODATAIN";
parameter HIGH_PERFORMANCE_MODE = "TRUE";
parameter SIGNAL_PATTERN = "DATA";
parameter CINVCTRL_SEL = "FALSE";
parameter PIPE_SEL = "FALSE";
parameter IS_C_INVERTED = 0;
parameter IS_ODATAIN_INVERTED = 0;
wire x;
wire lut;
(* KEEP, DONT_TOUCH *)
LUT2 l( .O(lut) );
// ODELAY
(* LOC=LOC, KEEP, DONT_TOUCH *)
ODELAYE2 #(
.ODELAY_TYPE(ODELAY_TYPE),
.ODELAY_VALUE(ODELAY_VALUE),
.DELAY_SRC(DELAY_SRC),
.HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE),
.SIGNAL_PATTERN(SIGNAL_PATTERN),
.CINVCTRL_SEL(CINVCTRL_SEL),
.PIPE_SEL(PIPE_SEL),
.IS_C_INVERTED(IS_C_INVERTED),
.IS_ODATAIN_INVERTED(IS_ODATAIN_INVERTED)
)
odelay
(
.C(clk),
.REGRST(),
.LD(),
.CE(),
.INC(),
.CINVCTRL(),
.CNTVALUEIN(),
.ODATAIN(lut),
.LDPIPEEN(),
.DATAOUT(O),
.CNTVALUEOUT()
);
endmodule
''')
run()