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