[dv/common] add ECC support to mem_bkdr_if
This PR adds full ECC support to the memory backdoor interface.
To do this, secded_gen.py was modified to also output an enum of the
different ECC variants, which are used to parameterize the mem_bkdr_if
so that we can pick up the correct data widths internally, etc...
Some ECC-specific wrapper functions for `read()` have also been added to
mem_bkdr_if that return the syndrome and error information as well as
the read data - these can be useful for ECC error tests
(sram/flash/otp).
A followup PR will enable this functionality in the OTP and Flash
testbenches.
Signed-off-by: Udi Jonnalagadda <udij@google.com>
diff --git a/util/design/secded_gen.py b/util/design/secded_gen.py
index 98ec4b6..d94ffa1 100755
--- a/util/design/secded_gen.py
+++ b/util/design/secded_gen.py
@@ -84,6 +84,54 @@
return fanin_masks
+def print_secded_enum_and_util_fns(cfgs):
+ enum_vals = [" SecdedNone"]
+ parity_width_vals = []
+ data_width_vals = []
+ for cfg in cfgs:
+ k = cfg['k']
+ m = cfg['m']
+ n = k + m
+ suffix = CODE_OPTIONS[cfg['code_type']]
+ formatted_suffix = suffix.replace('_', '').capitalize()
+
+ enum_name = " Secded%s_%s_%s" % (formatted_suffix, n, k)
+ enum_vals.append(enum_name)
+
+ parity_width = " %s: return %s;" % (enum_name, m)
+ parity_width_vals.append(parity_width)
+
+ data_width = " %s: return %s;" % (enum_name, k)
+ data_width_vals.append(data_width)
+
+ enum_str = ",\n".join(enum_vals)
+ parity_width_fn_str = "\n".join(parity_width_vals)
+ data_width_fn_str = "\n".join(data_width_vals)
+
+ enum_str = '''
+ typedef enum int {{
+{}
+ }} prim_secded_e;
+
+ function automatic int get_ecc_data_width(prim_secded_e ecc_type);
+ case (ecc_type)
+{}
+ // Return a non-zero width to avoid VCS compile issues
+ default: return 32;
+ endcase
+ endfunction
+
+ function automatic int get_ecc_parity_width(prim_secded_e ecc_type);
+ case (ecc_type)
+{}
+ default: return 0;
+ endcase
+ endfunction
+'''.format(enum_str, data_width_fn_str, parity_width_fn_str)
+
+ return enum_str
+
+
def print_pkg_types(n, k, m, codes, suffix, codetype):
typename = "secded%s_%d_%d_t" % (suffix, n, k)
@@ -102,7 +150,7 @@
enc_out = print_enc(n, k, m, codes)
dec_out = print_dec(n, k, m, codes, codetype, "function")
- typename = "secded%s_%d_%d_t" % (suffix, n, k)
+ typename = "secded_%d_%d_t" % (n, k)
module_name = "prim_secded%s_%d_%d" % (suffix, n, k)
outstr = '''
@@ -168,7 +216,8 @@
outstr += " {}// Corrected output calculation\n".format(
preamble if print_type == "function" else "")
for i in range(k):
- outstr += " {}".format(preamble) + "data_o[%d] = (syndrome_o == %d'h%x) ^ data_i[%d];\n" % (
+ outstr += " {}".format(preamble)
+ outstr += "data_o[%d] = (syndrome_o == %d'h%x) ^ data_i[%d];\n" % (
i, m, calc_syndrome(codes[i]), i)
outstr += "\n"
outstr += " {}// err_o calc. bit0: single error, bit1: double error\n".format(
@@ -256,8 +305,10 @@
if not args.no_fpv:
write_fpv_files(n, k, m, codes, codetype, args.fpv_outdir)
+ # create enum of various ECC types - useful for DV purposes in mem_bkdr_if
+ enum_str = print_secded_enum_and_util_fns(cfgs['cfgs'])
# write out package file
- full_pkg_str = pkg_type_str + pkg_out_str
+ full_pkg_str = enum_str + pkg_type_str + pkg_out_str
write_pkg_file(args.outdir, full_pkg_str)