[util] Load HJSON config once to speed up ECC encoding
This commit add a function to load the secded config HJSON file and
updates several functions to inject the config instead of loading it at
every call.
This commit also removes the memoization decorator from `ecc_encode`
since `config` is not a hashable type.
Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/hw/ip/rom_ctrl/util/mem.py b/hw/ip/rom_ctrl/util/mem.py
index be914d0..1f96eeb 100644
--- a/hw/ip/rom_ctrl/util/mem.py
+++ b/hw/ip/rom_ctrl/util/mem.py
@@ -6,10 +6,10 @@
import re
import subprocess
import tempfile
-from typing import BinaryIO, IO, List, Optional, TextIO, Tuple
+from typing import Any, BinaryIO, Dict, IO, List, Optional, TextIO, Tuple
from elftools.elf.elffile import ELFFile # type: ignore
-from util.design.secded_gen import ecc_encode_some # type: ignore
+from util.design.secded_gen import ecc_encode_some, load_secded_config # type: ignore
class MemChunk:
@@ -47,20 +47,21 @@
toks.append(f'{word:0{word_chars}X}')
outfile.write(' '.join(toks) + '\n')
- def add_ecc32(self) -> None:
+ def add_ecc32(self, config: Dict[str, Any]) -> None:
'''Add ECC32 integrity bits
This extends the input words (which are assumed to be 32-bit) by 7
bits, to make 39-bit words.
'''
- self.words = ecc_encode_some('inv_hsiao', 32, self.words)[0]
+ self.words = ecc_encode_some(config, 'inv_hsiao', 32, self.words)[0]
class MemFile:
def __init__(self, width: int, chunks: List[MemChunk]):
self.width = width
self.chunks = chunks
+ self.config = load_secded_config()
def __str__(self) -> str:
return ('MemFile(width={}, chunks_len={})'
@@ -319,7 +320,7 @@
'''
assert self.width <= 32
for chunk in self.chunks:
- chunk.add_ecc32()
+ chunk.add_ecc32(self.config)
self.width = 39
def collisions(self) -> List[Tuple[int, int]]:
diff --git a/hw/ip/rom_ctrl/util/scramble_image.py b/hw/ip/rom_ctrl/util/scramble_image.py
index fd5c8c6..e4f6bb4 100755
--- a/hw/ip/rom_ctrl/util/scramble_image.py
+++ b/hw/ip/rom_ctrl/util/scramble_image.py
@@ -13,7 +13,7 @@
from Crypto.Hash import cSHAKE256
from mem import MemChunk, MemFile
-from util.design.secded_gen import ecc_encode_some # type: ignore
+from util.design.secded_gen import ecc_encode_some, load_secded_config # type: ignore
ROM_BASE_WORD = 0x8000 // 4
ROM_SIZE_WORDS = 8192
@@ -285,6 +285,7 @@
self.nonce = nonce
self.key = key
self.rom_size_words = rom_size_words
+ self.config = load_secded_config()
self._addr_width = (rom_size_words - 1).bit_length()
@@ -504,7 +505,7 @@
w39 = w32 | (chk_bits << 32)
clr39 = self.unscramble_word(39, log_addr, w39)
clr32 = clr39 & mask32
- exp39 = ecc_encode_some('inv_hsiao', 32, [clr32])[0][0]
+ exp39 = ecc_encode_some(self.config, 'inv_hsiao', 32, [clr32])[0][0]
if clr39 != exp39:
# The checksum doesn't match. Excellent!
found_mismatch = True
diff --git a/util/design/gen-flash-img.py b/util/design/gen-flash-img.py
index 36d1c66..64bc765 100755
--- a/util/design/gen-flash-img.py
+++ b/util/design/gen-flash-img.py
@@ -11,12 +11,13 @@
import math
import re
from pathlib import Path
+from typing import Dict, Any
import secded_gen
-def _add_intg_ecc(in_val: int) -> str:
- result, m = secded_gen.ecc_encode("hamming", 64, in_val)
+def _add_intg_ecc(config: Dict[str, Any], in_val: int) -> str:
+ result, m = secded_gen.ecc_encode(config, "hamming", 64, in_val)
m_nibbles = math.ceil(m / 4)
result = format(result, '0' + str(16 + m_nibbles) + 'x')
@@ -25,8 +26,8 @@
return result[1:]
-def _add_reliability_ecc(in_val: int) -> str:
- result, m = secded_gen.ecc_encode("hamming", 68, in_val)
+def _add_reliability_ecc(config: Dict[str, Any], in_val: int) -> str:
+ result, m = secded_gen.ecc_encode(config, "hamming", 68, in_val)
m_nibbles = math.ceil((68 + m) / 4)
result = format(result, '0' + str(m_nibbles) + 'x')
@@ -50,6 +51,8 @@
# search only for lines that contain data, skip all other comments
result = re.findall(r"^@.*$", vmem_orig, flags=re.MULTILINE)
+ config = secded_gen.load_secded_config()
+
output = []
for line in result:
items = line.split()
@@ -58,8 +61,8 @@
if re.match(r"^@", item):
result += item
else:
- data_w_intg_ecc = _add_intg_ecc(int(item, 16))
- full_ecc = _add_reliability_ecc(int(data_w_intg_ecc, 16))
+ data_w_intg_ecc = _add_intg_ecc(config, int(item, 16))
+ full_ecc = _add_reliability_ecc(config, int(data_w_intg_ecc, 16))
result += f' {full_ecc}'
# add processed element to output
diff --git a/util/design/secded_gen.py b/util/design/secded_gen.py
index 5b08aa4..9276ee2 100755
--- a/util/design/secded_gen.py
+++ b/util/design/secded_gen.py
@@ -19,7 +19,7 @@
import random
import hjson
import subprocess
-from typing import List, Tuple
+from typing import Any, Dict, List, Tuple
from pathlib import Path
COPYRIGHT = """// Copyright lowRISC contributors.
@@ -137,7 +137,7 @@
if dec:
for j in range(m):
fanin_masks[j] += 1 << (k + j)
- return fanin_masks
+ return tuple(fanin_masks)
def print_secded_enum_and_util_fns(cfgs):
@@ -356,9 +356,8 @@
return error
-def _ecc_pick_code(codetype: str, k: int) -> Tuple[int, List[int], int]:
+def _ecc_pick_code(config: Dict[str, Any], codetype: str, k: int) -> Tuple[int, List[int], int]:
# first check to see if bit width is supported among configuration
- config = hjson.load(SECDED_CFG_PATH.open())
codes = None
bitmasks = None
@@ -403,11 +402,10 @@
return codeword
-@functools.lru_cache(maxsize = 1024)
-def ecc_encode(codetype: str, k: int, dataword: int) -> Tuple[int, int]:
+def ecc_encode(config: Dict[str, Any], codetype: str, k: int, dataword: int) -> Tuple[int, int]:
log.info(f"Encoding ECC for {hex(dataword)}")
- m, bitmasks, invert = _ecc_pick_code(codetype, k)
+ m, bitmasks, invert = _ecc_pick_code(config, codetype, k)
codeword = _ecc_encode(k, m, bitmasks, invert, dataword)
# Debug printouts
@@ -416,10 +414,11 @@
return int(codeword, 2), m
-def ecc_encode_some(codetype: str,
+def ecc_encode_some(config: Dict[str, Any],
+ codetype: str,
k: int,
datawords: int) -> Tuple[List[int], int]:
- m, bitmasks, invert = _ecc_pick_code(codetype, k)
+ m, bitmasks, invert = _ecc_pick_code(config, codetype, k)
codewords = [int(_ecc_encode(k, m, bitmasks, invert, w), 2)
for w in datawords]
return codewords, m
@@ -901,6 +900,10 @@
f.write(outstr)
+def load_secded_config() -> Dict[str, Any]:
+ return hjson.load(SECDED_CFG_PATH.open())
+
+
def main():
parser = argparse.ArgumentParser(
prog="secded_gen",