[reggen] Add Parameter list to the hjson format
- add `param_list` in IP configuration
- The parameter name can be used in `multireg["count"]` field
- `param_list` is added to the register package
This is related to #30 #47
diff --git a/hw/ip/rv_timer/doc/rv_timer.hjson b/hw/ip/rv_timer/doc/rv_timer.hjson
index 1fcbb87..ff6f703 100644
--- a/hw/ip/rv_timer/doc/rv_timer.hjson
+++ b/hw/ip/rv_timer/doc/rv_timer.hjson
@@ -15,13 +15,25 @@
desc: "raised if the timer 0_0 expired (mtimecmp >= mtime)"
},
],
+ param_list: [
+ { name: "N_HARTS",
+ desc: "Number of harts",
+ type: "int",
+ default: "1"
+ },
+ { name: "N_TIMERS",
+ desc: "Number of timers per Hart",
+ type: "int",
+ default: "1"
+ }
+ ],
no_auto_intr_regs: "true",
regwidth: "32",
registers: [
{ multireg: {
name: "CTRL",
desc: "Control register",
- count: 1,
+ count: "N_HARTS",
cname: "TIMER",
swaccess: "rw",
hwaccess: "hro",
@@ -75,7 +87,7 @@
{ multireg: {
name: "INTR_ENABLE0",
desc: "Interrupt Enable",
- count: 1,
+ count: "N_TIMERS",
cname: "TIMER",
swaccess: "rw",
hwaccess: "hro",
@@ -87,7 +99,7 @@
{ multireg: {
name: "INTR_STATE0",
desc: "Interrupt Status",
- count: 1,
+ count: "N_TIMERS",
cname: "TIMER",
swaccess: "rw1c",
hwaccess: "hrw",
@@ -99,7 +111,7 @@
{ multireg: {
name: "INTR_TEST0",
desc: "Interrupt test register",
- count: 1,
+ count: "N_TIMERS",
cname: "TIMER",
swaccess: "wo",
hwaccess: "hro",
diff --git a/hw/ip/rv_timer/doc/rv_timer.tpl.hjson b/hw/ip/rv_timer/doc/rv_timer.tpl.hjson
index 8b652cf..fa07de8 100644
--- a/hw/ip/rv_timer/doc/rv_timer.tpl.hjson
+++ b/hw/ip/rv_timer/doc/rv_timer.tpl.hjson
@@ -22,13 +22,25 @@
% endfor
% endfor
],
+ param_list: [
+ { name: "N_HARTS",
+ desc: "Number of harts",
+ type: "int",
+ default: "${harts}"
+ },
+ { name: "N_TIMERS",
+ desc: "Number of timers per Hart",
+ type: "int",
+ default: "${timers}"
+ }
+ ],
no_auto_intr_regs: "true",
regwidth: "32",
registers: [
{ multireg: {
name: "CTRL",
desc: "Control register",
- count: ${harts},
+ count: "N_HARTS",
cname: "TIMER",
swaccess: "rw",
hwaccess: "hro",
@@ -85,7 +97,7 @@
{ multireg: {
name: "INTR_ENABLE${i}",
desc: "Interrupt Enable",
- count: ${timers},
+ count: "N_TIMERS",
cname: "TIMER",
swaccess: "rw",
hwaccess: "hro",
@@ -97,7 +109,7 @@
{ multireg: {
name: "INTR_STATE${i}",
desc: "Interrupt Status",
- count: ${timers},
+ count: "N_TIMERS",
cname: "TIMER",
swaccess: "rw1c",
hwaccess: "hrw",
@@ -109,7 +121,7 @@
{ multireg: {
name: "INTR_TEST${i}",
desc: "Interrupt test register",
- count: ${timers},
+ count: "N_TIMERS",
cname: "TIMER",
swaccess: "wo",
hwaccess: "hro",
diff --git a/hw/ip/rv_timer/rtl/rv_timer_reg_pkg.sv b/hw/ip/rv_timer/rtl/rv_timer_reg_pkg.sv
index 9fba0ba..30c80d7 100644
--- a/hw/ip/rv_timer/rtl/rv_timer_reg_pkg.sv
+++ b/hw/ip/rv_timer/rtl/rv_timer_reg_pkg.sv
@@ -6,6 +6,10 @@
package rv_timer_reg_pkg;
+ // Param list
+ localparam int N_HARTS = 1;
+ localparam int N_TIMERS = 1;
+
// Register to internal design logic
typedef struct packed {
diff --git a/util/reggen/gen_rtl.py b/util/reggen/gen_rtl.py
index 9e2ce58..8d1933c 100644
--- a/util/reggen/gen_rtl.py
+++ b/util/reggen/gen_rtl.py
@@ -89,6 +89,7 @@
regs = []
wins = []
blocks = []
+ params = []
def __init__(self):
self.width = 32
@@ -98,6 +99,7 @@
self.regs = []
self.wins = []
self.blocks = []
+ self.params = []
def escape_name(name):
@@ -208,6 +210,8 @@
log.info("Data Width is set to %d bits", block.width)
+ block.params = obj["param_list"] if "param_list" in obj else []
+
for r in obj["registers"]:
# Check if any exception condition hit
if 'reserved' in r:
diff --git a/util/reggen/reg_pkg.tpl.sv b/util/reggen/reg_pkg.tpl.sv
index 3a0cb6a..cb9df67 100644
--- a/util/reggen/reg_pkg.tpl.sv
+++ b/util/reggen/reg_pkg.tpl.sv
@@ -9,6 +9,13 @@
max_regs_char = len("{}".format(num_regs-1))
%>\
package ${block.name}_reg_pkg;
+% if len(block.params) != 0:
+
+ // Param list
+% endif
+% for param in block.params:
+ localparam ${param["type"]} ${param["name"]} = ${param["default"]};
+% endfor
// Register to internal design logic
typedef struct packed {
diff --git a/util/reggen/validate.py b/util/reggen/validate.py
index da45c21..2793f39 100644
--- a/util/reggen/validate.py
+++ b/util/reggen/validate.py
@@ -27,6 +27,18 @@
return d
+def check_count(params, x, err_prefix):
+ '''Checking mreg count if it is in param list
+ '''
+ name_list = [z["name"] for z in params]
+ try:
+ index = name_list.index(x)
+ return check_int(params[index]["default"], err_prefix + " default")
+ except ValueError:
+ # cannot find entry in the param list
+ return check_int(x, err_prefix)
+
+
# validating version of int(x, 0)
# returns int value, error flag
# if error flag is True value will be zero
@@ -92,6 +104,31 @@
return error
+def check_lp(obj, x, err_prefix):
+ error = 0
+ if not isinstance(obj[x], list):
+ log.error(err_prefix + ' element ' + x + ' not a list')
+ return 1
+
+ for y in obj[x]:
+ error += check_keys(y, lp_required, lp_optional, {},
+ err_prefix + ' element ' + x)
+ # TODO: Check if PascalCase or ALL_CAPS
+ if not "type" in y:
+ y["type"] = "int"
+ if not "default" in y:
+ if y["type"][:3] == "int":
+ y["default"] = "1"
+ elif y["type"] == "string":
+ y["default"] = ""
+ else:
+ log.err(err_prefix + ' element ' + x + '["' + y["name"] +
+ '"]' + ' type is not supported')
+ return error + 1
+
+ return error
+
+
def check_keys(obj, required_keys, optional_keys, added_keys, err_prefix):
error = 0
for x in required_keys:
@@ -108,6 +145,9 @@
log.warning(err_prefix + " contains extra key " + x)
if type[:2] == 'ln':
error += check_ln(obj, x, type == 'lnw', err_prefix)
+ if type == 'lp':
+ error += check_lp(obj, x, err_prefix)
+
return error
@@ -179,6 +219,7 @@
'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 `'''` "\
@@ -212,6 +253,7 @@
"Defaults to false if not present."],
'alert_list': ['ln', "list of peripheral alerts"],
'regwidth': ['d', "width of registers in bits (default 32)"],
+ 'param_list': ['lp', "list of parameters of the IP"],
'SPDX-License-Identifier': ['s', "License ientifier (if using pure json) "\
"Only use this if unable to put this "\
"information in a comment at the top of the "\
@@ -235,6 +277,16 @@
'width': ['d', "bit width of the item (if not 1)"],
}
+# lp type
+lp_required = {
+ 'name': ['s', "name of the item"],
+}
+lp_optional = {
+ 'desc': ['s', "description of the item"],
+ 'type': ['s', "item type. int by default"],
+ 'default': ['s', "item default value"],
+}
+
# Registers list may have embedded keys
list_optone = {'reserved': ['d', "number of registers to reserve space for"],
'skipto': ['d', "set next register offset to value"],
@@ -329,7 +381,9 @@
# Multireg keys
multireg_required = {'name': ['s', "base name of the registers"],
'desc': ['t', "description of the registers"],
- 'count': ['d', "number of instances to generate"],
+ 'count': ['s', "number of instances to generate."\
+ " This field can be integer or string matching"\
+ " from param_list"],
'cname': ['s', "base name for each instance, mostly "\
"useful for refering to instance in messages"],
'fields': ['l', "list of register field description"\
@@ -773,8 +827,7 @@
reg['genoffset'] = offset
reg['gendvrights'] = parse_dvrights(default_sw)
- if ((reg['regwen'] != '') and
- (not reg['regwen'] in top['genwennames'])):
+ if ((reg['regwen'] != '') and (not reg['regwen'] in top['genwennames'])):
top['genwennames'].append(reg['regwen'])
log.info(rname + "@" + hex(offset) + " " + str(error) + " errors. Mask " +
@@ -809,7 +862,10 @@
error += gen[0]
- mcount, ierr = check_int(mreg['count'], mrname + " multireg count")
+ # Check `count` field if it is in paramter list
+ mcount, ierr = check_count(
+ top['param_list'] if "param_list" in top else [], mreg['count'],
+ mrname + " multireg count")
if ierr:
error += 1
@@ -1119,8 +1175,8 @@
# auto header generation would go here and update autoregs
if 'no_auto_intr_regs' in regs:
- no_autoi, err = check_bool(
- regs['no_auto_intr_regs'], 'no_auto_intr_regs')
+ no_autoi, err = check_bool(regs['no_auto_intr_regs'],
+ 'no_auto_intr_regs')
if err:
error += 1
else: