1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
#!/usr/bin/python3
#
# Copyright 2018 Ettus Research, a National Instruments Company
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
import argparse
import math
import sys
import datetime
import random
# Parse command line options
# ------------------------------------------------
def get_options():
parser = argparse.ArgumentParser(description='Generate a node to coordinate mapping file.')
parser.add_argument('--pattern', type=str, default='xy', choices=['xy', 'yx', 'spiral', 'random'], help='Node distribution pattern')
parser.add_argument('--dimsize', type=int, default=4, help='Maximum dimension size')
parser.add_argument('--seed', type=int, default=None, help='Seed for random permutation generator')
return parser.parse_args()
# Pattern Generators
# ------------------------------------------------
def gen_xy(N):
nodes = dict()
for y in range(N):
for x in range(N):
nodes[(y*N + x)] = (x, y)
return nodes
def gen_yx(N):
nodes = dict()
for y in range(N):
for x in range(N):
nodes[(x*N + y)] = (x, y)
return nodes
def gen_spiral(N):
nodes = dict()
x = y = 0
dx = 0
dy = -1
for i in range(N**2):
if (-N/2 < x <= N/2) and (-N/2 < y <= N/2):
nodes[i] = (x + int(math.ceil(N/2)) - 1, y + int(math.ceil(N/2)) - 1)
if x == y or (x < 0 and x == -y) or (x > 0 and x == 1-y):
dx, dy = -dy, dx
x, y = x+dx, y+dy
return nodes
def gen_random(N):
nodes = dict()
rnodes = random.sample(range(N*N), N*N)
for y in range(N):
for x in range(N):
nodes[rnodes[x*N + y]] = (x, y)
return nodes
# Source Generators
# ------------------------------------------------
def layout_nodes(nodes):
N = int(math.sqrt(len(nodes)))
#inv_nodes = {v: k for k, v in nodes.iteritems()}
coords = {v: k for k, v in nodes.items()}
lines = []
for y in range(N):
line = ''
for x in range(N):
line += '%5d'%(coords[(x,y)])
lines.append(line)
return lines
def gen_vparams(nodes, N, pattern):
src_lines = [ '\n// DIM_SIZE = %d, PATTERN = %s'%(N,pattern.upper()), '//------------------------------------' ]
for l in layout_nodes(nodes):
src_lines.append('// ' + l)
bitw = math.ceil(math.log2(N))
xvals = ','.join(['%d\'d%d'%(bitw,v[0]) for k, v in sorted(nodes.items(), reverse=True)])
yvals = ','.join(['%d\'d%d'%(bitw,v[1]) for k, v in sorted(nodes.items(), reverse=True)])
xpar = 'localparam [%d:0] XCOORD_DIM_%03d = {%s};'%(bitw*N*N-1, N, xvals)
ypar = 'localparam [%d:0] YCOORD_DIM_%03d = {%s};'%(bitw*N*N-1, N, yvals)
src_lines.append(xpar)
src_lines.append(ypar)
src_lines.append('')
return src_lines
def gen_lookup_func(dim, N):
src_lines = [ 'function [CLOG2_DIM_SIZE-1:0] node_to_%sdst;'%(dim), ' input [WIDTH-1:0] header;', 'begin']
dim_sizes = range(2, N+1)
for i in dim_sizes:
node_bitw = math.ceil(math.log2(i*i))
dim_bitw = math.ceil(math.log2(i))
prefix = ' ' if (i == dim_sizes[0]) else ' else '
src_lines.append(prefix + 'if (DIM_SIZE == %d)'%(i))
src_lines.append(' node_to_%sdst = %sCOORD_DIM_%03d[%d*header[%d:0] +: %d];'%(dim,dim.upper(),i,dim_bitw,node_bitw-1,dim_bitw))
src_lines.append(' else')
src_lines.append(' node_to_%sdst = {CLOG2_DIM_SIZE{1\'d0}};'%(dim))
src_lines.append('end endfunction\n\n')
return src_lines
def gen_vheader(dimsize, mapgen, pattern, filename):
with open(filename, 'w') as vhfile:
vhfile.write('// Copyright %s Ettus Research, A National Instruments Company\n'%(datetime.datetime.now().year))
vhfile.write('// SPDX-License-Identifier: LGPL-3.0-or-later\n')
vhfile.write('//\n')
vhfile.write('// Autogenerated file. Do not modify.\n')
vhfile.write('// $ %s\n'%(' '.join(sys.argv[:])))
vhfile.write('\nparameter CLOG2_DIM_SIZE = $clog2(DIM_SIZE); //Vivado workaround\n\n')
for i in range(2, dimsize+1):
nodes = mapgen(i)
N = math.sqrt(len(nodes))
vhfile.write('\n'.join(gen_vparams(nodes, N, pattern)))
vhfile.write('\n\n')
vhfile.write('\n'.join(gen_lookup_func('x', dimsize)))
vhfile.write('\n'.join(gen_lookup_func('y', dimsize)))
def main():
args = get_options();
random.seed(args.seed)
generators = {'xy': gen_xy, 'yx': gen_yx, 'spiral':gen_spiral, 'random': gen_random}
gen_vheader(args.dimsize, generators[args.pattern], args.pattern, 'mesh_node_mapping.vh')
if __name__ == '__main__':
main()
|