[reggen] Minor updates to reggen tool
- Slight refactoring of multireg handling
- This is not the full blown restructuring discussed in #270
- Add 'compact' feature to multireg
- Revive 'regwen_incr', now renamed to 'regwen_multi'
Signed-off-by: Timothy Chen <timothytim@google.com>
[reggen] Change to OrderedDict
Signed-off-by: Timothy Chen <timothytim@google.com>
[reggen] Address review comments
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/Makefile b/hw/Makefile
index e0d4fdd..95d9208 100644
--- a/hw/Makefile
+++ b/hw/Makefile
@@ -73,7 +73,7 @@
$(ips_reg): pre_reg
if [ -f ${PRJ_DIR}/hw/ip/$(subst _reg,,$@)/$(dir_hjson)/$(subst _reg,,$@).hjson ]; then \
- ${PRJ_DIR}/util/regtool.py -r ${PRJ_DIR}/hw/ip/$(subst _reg,,$@)/$(dir_hjson)/$(subst _reg,,$@).hjson; \
+ ${PRJ_DIR}/util/regtool.py ${toolflags} -r ${PRJ_DIR}/hw/ip/$(subst _reg,,$@)/$(dir_hjson)/$(subst _reg,,$@).hjson; \
${PRJ_DIR}/util/regtool.py -s -t ${REG_OUTPUT_DV_DIR} \
${PRJ_DIR}/hw/ip/$(subst _reg,,$@)/$(dir_hjson)/$(subst _reg,,$@).hjson; \
fi
diff --git a/util/reggen/validate.py b/util/reggen/validate.py
index 63e528c..39925e9 100644
--- a/util/reggen/validate.py
+++ b/util/reggen/validate.py
@@ -9,6 +9,7 @@
import re
import operator
from collections import OrderedDict
+from copy import deepcopy
from reggen.field_enums import SwWrAccess, SwRdAccess, SwAccess, HwAccess
@@ -509,10 +510,14 @@
}
multireg_optional = reg_optional
multireg_optional.update({
- 'regwen_incr': [
- 's', "If true, regwen term increments"
+ 'regwen_multi': [
+ 'pb', "If true, regwen term increments"
" along with current multireg count."
],
+ 'compact': [
+ 'pb', "If true, allow multireg compacting."
+ "If false, do not compact."
+ ],
})
multireg_added = {
@@ -1108,27 +1113,27 @@
mreg["name"] = "MREG_" + hex(offset)
else:
mrname = mreg['name']
+
+ # multireg defaults
+ # Should probably create this structure somewhere else as part checking,
+ # then directly create the default value
+ defaults = {'regwen_multi': False, 'compact': True}
+ for entry in defaults:
+ mreg.setdefault(entry, defaults[entry])
+
error = check_keys(mreg, multireg_required, multireg_optional,
multireg_added, mrname)
derr, default_sw, default_hw, full_resval = validate_reg_defaults(
mreg, mrname)
error += derr
- # multireg specific default validation
- regwen_incr = False
- if 'regwen_incr' not in mreg or 'regwen' not in mreg:
- mreg['regwen_incr'] = 'false'
- else:
- regwen_incr, derr = check_bool(mreg['regwen_incr'],
- mrname + " multireg increment")
- error += derr
-
# if there was an error before this then can't trust anything!
if error > 0:
log.info(mrname + "@" + hex(offset) + " " + str(error) +
" top level errors. Not processing fields")
return error
+ # should add an option to include a register directly instead of a field
gen = validate_fields(mreg['fields'], mrname, default_sw, default_hw,
full_resval, mreg['hwqe'] == "true",
mreg['hwre'] == "true", width, top)
@@ -1151,115 +1156,105 @@
if error > 0:
return (error, 0)
- bused = gen[3]
- max_rval = (1 << width) - 1
+ # multireg attributes
cname = mreg['cname']
- bpos = 0
- inum = 0
+ template_reg = OrderedDict ([
+ ('name', mrname + "{}"),
+ ('desc', mreg['desc']),
+ ('hwext', mreg['hwext']),
+ ('hwqe', mreg['hwqe']),
+ ('hwre', mreg['hwre']),
+ ('swaccess', mreg['swaccess']),
+ ('hwaccess', mreg['hwaccess']),
+ ('shadowed', mreg['shadowed']),
+ ('regwen_multi', mreg['regwen_multi']),
+ ('compact', mreg['compact']),
+ ('fields', []),
+ ])
+
+ template_reg['tags'] = mreg['tags'] if 'tags' in mreg else []
+ template_reg['regwen'] = mreg['regwen'] if 'regwen' in mreg else []
+
+ # msb of the field bitmask
+ # Should probably consider making the validate_field return a class so that we do not
+ # hardcode a selection like this
+ field_bitmask = gen[3]
+ field_msb = 0
+ for pos in range(width - 1, 0, -1):
+ if (field_bitmask & (1 << pos)):
+ field_msb = pos
+ break
+
+ # number of bits needed
+ bits_used = field_msb + 1
+
+ # Number of fields
+ num_fields = len(mreg['fields'])
+
+ # Maximum number of fields per reg
+ max_fields_per_reg = 1 if num_fields > 1 else min(mcount, int(width / bits_used))
+
+ # list of created registers
rlist = []
+
+ # rnum represents which register we are currently working on.
+ # idx represents which index in the mcount we are working on.
+ # These two are not the same due to the compacting feature.
+ # Compacting happens under the following conditions:
+ # - There is only 1 field type for a multi-reg and compact is not set to
+ # false.
rnum = 0
- while inum < mcount:
- closereg = False
- if bpos == 0:
- genreg = {}
- if shadowed is True:
- genreg['name'] = mrname[:idx] + "_" + str(rnum) + mrname[idx:]
- else:
- genreg['name'] = mrname + "_" + str(rnum)
- genreg['desc'] = mreg['desc']
- genreg['hwext'] = mreg['hwext']
- genreg['hwqe'] = mreg['hwqe']
- genreg['hwre'] = mreg['hwre']
- genreg['swaccess'] = default_sw
- genreg['hwaccess'] = default_hw
- if 'tags' in mreg:
- genreg['tags'] = mreg['tags']
- else:
- genreg['tags'] = []
+ idx = 0
- if regwen_incr:
- genreg['regwen'] = mreg['regwen'] + str(rnum)
- else:
- genreg['regwen'] = mreg['regwen']
- genreg['shadowed'] = mreg['shadowed']
+ # will fields be compacted?
+ is_compact = num_fields == 1 and template_reg['compact']
- resval = 0
- resmask = 0
- bits_used = 0
- genfields = []
+ # will there be multiple registers?
+ is_mult = (mcount > max_fields_per_reg) or (not is_compact and mcount > 1)
- while bpos < width:
- # bused is a bit mask of how many bits the fields need
- # bpos is the current LSB of the bits allocated for the fields
- trypos = bused << bpos
+ log.info("Multireg attributes 0x{:x} {} {} {}".format(field_bitmask, bits_used,
+ num_fields, max_fields_per_reg))
+ while idx < mcount:
- # if register can no longer contain another homogenous field
- # if the field is not homogenous and has been allocated
- # Currently we only compact if field is homogenous
- if (trypos > max_rval) or (bpos != 0 and len(mreg['fields']) > 1):
- bpos = width
- break
- # if bits have not been used, break and allocate
- if (trypos & bits_used) == 0:
- break
- bpos += 1
+ genreg = deepcopy(template_reg)
- if bpos < width:
- # found a spot
- for fn in mreg['fields']:
- newf = fn.copy()
- newf['name'] += "_" + str(inum)
- if bpos != 0:
- newf['bits'] = bitfield_add(newf['bits'], bpos)
- newf['desc'] = 'for ' + cname + str(inum)
- newf['bitinfo'] = (newf['bitinfo'][0] << bpos,
- newf['bitinfo'][1],
- newf['bitinfo'][2] + bpos)
- if 'tags' not in fn:
- newf['tags'] = []
- if 'enum' in newf:
- del newf['enum']
- else:
- newf['desc'] += ' for ' + cname + str(inum)
- genfields.append(newf)
- bits_used = bits_used | bused << bpos
- resval = resval | gen[1] << bpos
- resmask = resmask | gen[2] << bpos
- bpos += 1
- inum += 1
- if inum == mcount:
- closereg = True
+ # name the register
+ # if everything fits into 1 reg, do not add numbered suffix.
+ # if shadowed, add shadowed suffix.
+ name = "_" + str(rnum) if is_mult else ""
+ name += "_shadowed" if shadowed else ""
+ genreg['name'] = genreg['name'].format(name)
+
+ if (is_compact):
+ # Compact the minimum of remaining fields, or the max number of fields
+ # we are able to compact into a register.
+ for fnum in range(0, min(mcount - idx, max_fields_per_reg)):
+ new_field = deepcopy(mreg['fields'][0])
+ new_field['name'] += "_" + str(idx)
+ new_field['bits'] = bitfield_add(new_field['bits'], fnum * bits_used)
+ new_field['desc'] = "For {}{}".format(cname, idx)
+ genreg['fields'].append(new_field)
+ idx += 1
else:
- # need new register
- closereg = True
+ genreg['fields'] = deepcopy(mreg['fields'])
+ # This is here to ensure no deltas with previous code.
+ # This is not needed if on separate registers we do not enforce suffix
+ for f in genreg['fields']:
+ f['name'] += "_" + str(idx)
+ idx += 1
- if closereg:
- genreg['fields'] = genfields
- genreg['genbasebits'] = bused
- genreg['genresval'] = resval
- genreg['genresmask'] = resmask
- error += validate_register(genreg, offset + (rnum * addrsep),
- width, top)
- if error:
- return (error, 0)
- rnum += 1
- bpos = 0
- rlist.append(genreg)
- # there is only one entry, so the index is unnecessary. Pop and re-assign names
- # associated with the index
- if len(rlist) == 1:
- if regwen_incr:
- error += 1
- log.error(
- "%s multireg has only 1 register entry with regwen_incr set to true"
- % mrname)
- # TODO really should make the following a function that reverses the last node inserted
- # may have more properties than just genrnames in the future
- rlist[0]['name'] = mrname
- rlist[0]['regwen'] = mreg['regwen']
- top['genrnames'].pop()
+ # if regwen_multi is used, each register uses a different regen
+ if (genreg['regwen'] and genreg['regwen_multi']):
+ genreg['regwen'] += "_{}".format(rnum)
+
+ # validate register
+ validate_register(genreg, offset + (rnum * addrsep), width, top)
+ rnum += 1
+
+ # append to register list
+ rlist.append(genreg)
+
mreg['genregs'] = rlist
- top['genrnames'].append(mrname.lower())
return error, rnum
@@ -1457,8 +1452,7 @@
""" Check that terms specified for regwen exist
-Regwen can be individual registers or fields within a register. The function
-below checks for both and additional regwen properties.
+Regwen are all assumed to be individual registers.
"""
@@ -1478,17 +1472,33 @@
reg_list = [(reg['name'].lower(), reg['genresval'], reg['swaccess'],
reg['hwaccess']) for reg in regs['registers']
- if 'name' in reg and 'genresval' in reg]
+ if 'name' in reg and 'genresval' in reg and 'swaccess' in reg]
+
mreg_list = [
reg['multireg'] for reg in regs['registers'] if 'multireg' in reg
]
- field_list = [((reg['name'] + "_" + field['name']).lower(),
- field['genresval'], field['swaccess'], field['hwaccess'])
- for mreg in mreg_list for reg in mreg['genregs']
- for field in reg['fields']]
+
+ # all generated registers
+ mreg_reg_list = [reg for mreg in mreg_list for reg in mreg['genregs']]
+
+ # genreg attr
+ genreg_list = []
+ for reg in mreg_reg_list:
+ # There is only one field
+ if len(reg['fields']) == 1:
+ genreg_list.append((reg['name'].lower(),
+ reg['fields'][0]['genresval'],
+ reg['fields'][0]['swaccess'],
+ reg['fields'][0]['hwaccess']))
+ else:
+ for f in reg['fields']:
+ genreg_list.append(((reg['name'] + "_" + f['name']).lower(),
+ f['genresval'],
+ f['swaccess'],
+ f['hwaccess']))
# Need to check in register names and field list in case of multireg
- reg_list.extend(field_list)
+ reg_list.extend(genreg_list)
# check for reset value
# both w1c and w0c are acceptable, ro is also acceptable when hwaccess is wo (hw managed regwen)