#!/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()