#!/usr/bin/env python # # Generate core_selector.v for a set of cores import argparse import re import sys if sys.version > '3': import configparser else: import ConfigParser as configparser # defaults config = 'config.cfg' outfile = 'core_selector.v' section = '' cores = [] # added cores for TRNG, muxed through trng.v trng_cores = ['avalanche_entropy', 'rosc_entropy', 'trng_mixer', 'trng_csprng'] # parse the command line def cmdParse(): global config, outfile, section, cores parser = argparse.ArgumentParser() parser.add_argument('--cores', help='comma-delimited list of cores') parser.add_argument('-c', '--config', default=config, help='config file (default "%s")' % config) parser.add_argument('-s', '--section', help='config file section') parser.add_argument('-o', '--outfile', help='output file (default "%s")' % outfile) args = parser.parse_args() if args.cores: cores = re.split(',\s*', args.cores) if args.config: config = args.config if args.outfile: outfile = args.outfile if args.section: section = args.section # parse the config file def configParse(section): cfg = configparser.ConfigParser() try: with open(config, 'r') as f: cfg.readfp(f) except (IOError, configparser.MissingSectionHeaderError) as e: print e exit(1); try: if not section: section = cfg.get('default', 'default') cores = cfg.get(section, 'cores') except (configparser.NoSectionError, configparser.NoOptionError) as e: print e exit(1); return re.split(r',\s*', cores) # create an entry in the Core Address Table def createAddr(core, corenum): return " localparam CORE_ADDR_{:21s} = 9'h{:02x};\n".format(core.upper(), corenum) # create an instantiation of the core # This is complicated because TRNG is a mux for 5 cores. def createInstance(core): core_stripped = re.sub('_\d+$', '', core) if core_stripped == 'trng': s3 = "(addr_core_num >= CORE_ADDR_TRNG) && (addr_core_num <= CORE_ADDR_TRNG_CSPRNG)" s4 = " wire [3:0] trng_prefix = addr_core_num[3:0] - CORE_ADDR_TRNG;\n" s5 = "{trng_prefix, addr_core_reg}" s6 = ",\n\n .avalanche_noise(noise),\n .debug(debug)" else: s3 = "(addr_core_num == CORE_ADDR_{0})".format(core.upper()) s4 = "" s5 = "addr_core_reg" s6 = "" return "\ //----------------------------------------------------------------\n\ // {1}\n\ //----------------------------------------------------------------\n\ wire enable_{0} = {3};\n\ wire [31: 0] read_data_{0};\n\ wire error_{0};\n\ {4}\n\ {2} {0}_inst\n\ (\n\ .clk(sys_clk),\n\ .reset_n(~sys_rst),\n\ \n\ .cs(enable_{0} & (sys_eim_rd | sys_eim_wr)),\n\ .we(sys_eim_wr),\n\ \n\ .address({5}),\n\ .write_data(sys_write_data),\n\ .read_data(read_data_{0}){6}\n\ );\n\n\n".format(core, core.upper(), core_stripped, s3, s4, s5, s6) # create an entry in the Output (Read Data) Multiplexer def createMux(core, core0): return "\ CORE_ADDR_{0}:\n\ begin\n\ sys_read_data_mux = read_data_{1};\n\ sys_error_mux = error_{1};\n\ end\n".format(core.upper(), core0) # create the core_selector module def createModule(cores): cores = ['board_regs', 'comm_regs'] + cores # if multiple instances of a core, number them for a in set([x for x in cores if cores.count(x) > 1]): i = 0 j = 0 while (1): try: j = cores.index(a, j) except ValueError: break cores[j] += '_' + str(i) i += 1 j += 1 addrs = "" insts = "" muxs = "" corenum = 0 for core in cores: addrs += createAddr(core, corenum) insts += createInstance(core) muxs += createMux(core, core) corenum += 1 if core == 'trng': for tcore in trng_cores: addrs += createAddr(tcore, corenum) muxs += createMux(tcore, core) corenum += 1 # write the boilerplate and all per-core bits with open(outfile, 'w') as f: f.write("\ // NOTE: This file is generated; do not edit by hand.\n\ \n\ module core_selector\n\ (\n\ input wire sys_clk,\n\ input wire sys_rst,\n\ \n\ input wire [16: 0] sys_eim_addr,\n\ input wire sys_eim_wr,\n\ input wire sys_eim_rd,\n\ output wire [31: 0] sys_read_data,\n\ input wire [31: 0] sys_write_data,\n\ output wire sys_error,\n\ \n\ input wire noise,\n\ output wire [7 : 0] debug\n\ );\n\ \n\ \n\ //----------------------------------------------------------------\n\ // Address Decoder\n\ //----------------------------------------------------------------\n\ // upper 9 bits specify core being addressed\n\ wire [ 8: 0] addr_core_num = sys_eim_addr[16: 8];\n\ // lower 8 bits specify register offset in core\n\ wire [ 7: 0] addr_core_reg = sys_eim_addr[ 7: 0];\n\ \n\n\ //----------------------------------------------------------------\n\ // Core Address Table\n\ //----------------------------------------------------------------\n\ {0}\n\ \n\ {1}\n\ //----------------------------------------------------------------\n\ // Output (Read Data) Multiplexer\n\ //----------------------------------------------------------------\n\ reg [31: 0] sys_read_data_mux;\n\ assign sys_read_data = sys_read_data_mux;\n\ reg sys_error_mux;\n\ assign sys_error = sys_error_mux;\n\ \n\ always @*\n\ \n\ case (addr_core_num)\n\ {2}\n\ default:\n\ begin\n\ sys_read_data_mux = {{32{{1'b0}}}};\n\ sys_error_mux = 1;\n\ end\n\ endcase\n\ \n\ \n\ endmodule\n\ \n\ \n\ //======================================================================\n\ // EOF core_selector.v\n\ //======================================================================\n".format(addrs, insts, muxs)) # main cmdParse() if not cores: cores = configParse(section) createModule(cores)