blob: 3f1e1a4bee7faf5dbd3f813b4b86778dcb97e31c [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
import logging as log
from reggen.validate import val_types, check_keys
# For the reference
# val_types = {
# 'd': ["int", "integer (binary 0b, octal 0o, decimal, hex 0x)"],
# 'x': ["xint", "x for undefined otherwise int"],
# 'b': [
# "bitrange", "bit number as decimal integer, \
# or bit-range as decimal integers msb:lsb"
# ],
# 'l': ["list", "comma separated list enclosed in `[]`"],
# 'ln': ["name list", 'comma separated list enclosed in `[]` of '\
# 'one or more groups that have just name and dscr keys.'\
# ' e.g. `{ name: "name", desc: "description"}`'],
# 'lnw': ["name list+", 'name list that optionally contains a width'],
# 'lp': ["parameter list", 'parameter list having default value optionally'],
# 'g': ["group", "comma separated group of key:value enclosed in `{}`"],
# 's': ["string", "string, typically short"],
# 't': ["text", "string, may be multi-line enclosed in `'''` "\
# "may use `**bold**`, `*italic*` or `!!Reg` markup"],
# 'T': ["tuple", "tuple enclosed in ()"],
# 'pi': ["python int", "Native python type int (generated)"],
# 'pb': ["python Bool", "Native python type Bool (generated)"],
# 'pl': ["python list", "Native python type list (generated)"],
# 'pe': ["python enum", "Native python type enum (generated)"]
# }
# Required/optional field in top hjson
top_required = {
'name': ['s', 'Top name'],
'type': ['s', 'type of hjson. Shall be "top" always'],
'clocks': ['l', 'list of clocks'],
'module': ['l', 'list of modules to instantiate'],
'memory': [
'l', 'list of memories. At least one memory is needed to run \
the software'
],
'debug_mem_base_addr':
['d', 'Base address of RV_DM. Planned to move to \
module'],
'xbar': ['l', 'List of the xbar used in the top'],
}
top_optional = {
'interrupt_modules': ['l', 'list of the modules that connects to rv_plic'],
'interrupt': ['lnw', 'interrupts (generated)'],
'pinmux': ['g', 'pinmux definition if doesn\'t exist, tool uses defaults'],
'padctrl':
['g', 'PADS instantiation, if doesn\'t exist, tool creates direct output'],
}
top_added = {}
pinmux_required = {}
pinmux_optional = {
'dio_modules': ['l', 'List of Dedicated IO.'],
'mio_modules': ['l', 'List of Multiplexing IO'],
'nc_modules': ['l', 'List of NotConnected IO'],
}
pinmux_added = {
'inputs': ['l', 'Full list of SoC inputs, `module_name.sig_name`'],
'outputs': ['l', 'Full list of SoC outputs, `module_name.sig_name`'],
}
padctrl_required = {}
padctrl_optional = {
'pads': ['l', 'List of pads'],
'attr_default': ['l', 'List of the attribute']
}
padctrl_added = {}
def check_padctrl(top, prefix):
error = check_keys(top["padctrl"], padctrl_required, padctrl_optional,
padctrl_added, prefix + " PadControl")
return error
def check_pinmux(top, prefix):
return 0
def check_resets(top, ipobjs, xbarobjs):
# all defined reset nets
reset_nets = [reset['name'] for reset in top['resets']]
error = 0
# Check reset port connection for all IPs
for ipcfg in top['module']:
log.info("Checking resets for %s" % ipcfg['name'].lower())
ipdef = [ip for ip in ipobjs if ipcfg['type'] == ip['name'].lower()]
error += check_rst_def(ipdef, ipcfg['type'])
error += validate_reset(ipcfg, ipdef[0], reset_nets)
if error:
log.error("module reset checking failed")
break
# Check reset port connection for all xbars
for xbarcfg in top['xbar']:
log.info("Checking resets for %s" % xbarcfg['name'].lower())
xbardef = [
xbar for xbar in xbarobjs
if xbarcfg['name'] == xbar['name'].lower()
]
error += check_rst_def(xbardef, xbarcfg['name'])
error += validate_reset(xbarcfg, xbardef[0], reset_nets, "xbar")
if error:
log.error("xbar reset checking failed")
break
return error
def check_rst_def(inst_def, name):
error = 0
if not inst_def:
log.error("Could not find %s.hjson for" % name)
error += 1
if len(inst_def) > 1:
log.error("Duplicate %s.hjson" % name)
error += 1
return error
# Checks the following
# For each defined reset connection in top*.hjson, there exists a defined port at the destination
# and defined reset net
# There are the same number of defined connections as there are ports
def validate_reset(top, inst, reset_nets, prefix=""):
# Gather inst port list
error = 0
inst_port_list = []
if 'reset_primary' not in inst.keys():
log.info("%s %s does not have a reset_primary defined, default used" %
(prefix, inst['name']))
inst_port_list.append("rst_ni")
else:
inst_port_list.append(inst['reset_primary'])
if 'other_reset_list' in inst.keys():
inst_port_list.extend(inst['other_reset_list'])
log.info("%s %s resets are %s" %
(prefix, inst['name'].lower(), inst_port_list))
if len(top['reset_connections'].keys()) != len(inst_port_list):
error += 1
log.error("%s %s mismatched number of ports and nets" %
(prefix, inst['name']))
missing_port = [
port for port in top['reset_connections'].keys()
if port not in inst_port_list
]
if missing_port:
error += 1
log.error("%s %s Following reset ports do not exist:" %
(prefix, inst['name']))
[log.error("%s" % port) for port in missing_port]
missing_net = [
net for port, net in top['reset_connections'].items()
if net not in reset_nets
]
if missing_net:
error += 1
log.error("%s %s Following reset nets do not exist:" %
(prefix, inst['name']))
[log.error("%s" % net) for net in missing_net]
return error
def validate_top(top, ipobjs, xbarobjs):
# return as it is for now
error = check_keys(top, top_required, top_optional, top_added, "top")
if error != 0:
log.error("Top HJSON has top level errors. Aborting")
return top, error
component = top['name']
## Reset check
error += check_resets(top, ipobjs, xbarobjs)
## MODULE check
## MEMORY check
## RV_PLIC check
## PINMUX & PADS check
if not "padctrl" in top:
log.warning("padsctrl field doesn't exist in top. Skipping pads \
generation. Top input/output are directly connected from \
peripherals.")
# Pads configuration check
else:
error = check_padctrl(top, component)
if not "pinmux" in top:
log.warning("Top {} has no 'pinmux' field. Please consider specifying \
pinmux and pads configuration")
top["pinmux"] = {}
# checking pinmux after pads as dio connects to PAD
error += check_pinmux(top, component)
## XBAR check
return top, error