[util/design] Use RuntimeError to signal errors in lc gen script

Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/util/design/gen-lc-state-enc.py b/util/design/gen-lc-state-enc.py
index aab01c2..401eba8 100755
--- a/util/design/gen-lc-state-enc.py
+++ b/util/design/gen-lc-state-enc.py
@@ -36,7 +36,6 @@
                         type=int,
                         metavar='<seed>',
                         help='Custom seed for RNG.')
-
     args = parser.parse_args()
 
     with open(LC_STATE_DEFINITION_FILE, 'r') as infile:
@@ -57,7 +56,11 @@
                     'No seed specified, setting to {}.'.format(new_seed))
 
         # validate config and generate encoding
-        lc_st_enc = LcStEnc(config)
+        try:
+            lc_st_enc = LcStEnc(config)
+        except RuntimeError as err:
+            log.error(err)
+            exit(1)
 
         # render all templates
         for template in TEMPLATES:
diff --git a/util/design/lib/LcStEnc.py b/util/design/lib/LcStEnc.py
index 32d4324..713d5eb 100644
--- a/util/design/lib/LcStEnc.py
+++ b/util/design/lib/LcStEnc.py
@@ -27,8 +27,7 @@
 def _is_incremental_codeword(word1, word2):
     '''Test whether word2 is incremental wrt word1.'''
     if len(word1) != len(word2):
-        log.error('Words are not of equal size')
-        exit(1)
+        raise RuntimeError('Words are not of equal size')
 
     _word1 = int(word1, 2)
     _word2 = int(word2, 2)
@@ -113,25 +112,23 @@
     for k, w in enumerate(words):
         # Check whether word is valid wrt to ECC polynomial.
         if not is_valid_codeword(config, w):
-            log.error('Codeword {} at index {} is not valid'.format(w, k))
-            exit(1)
+            raise RuntimeError('Codeword {} at index {} is not valid'.format(
+                w, k))
         # Check that word fulfills the Hamming weight constraints.
         pop_cnt = w.count('1')
         if pop_cnt < config['min_hw'] or pop_cnt > config['max_hw']:
-            log.error(
+            raise RuntimeError(
                 'Codeword {} at index {} has wrong Hamming weight'.format(
                     w, k))
-            exit(1)
         # Check Hamming distance wrt to all other existing words.
         # If the constraint is larger than 0 this implies uniqueness.
         if k < len(words) - 1:
             for k2, w2 in enumerate(words[k + 1:]):
                 if get_hd(w, w2) < config['min_hd']:
-                    log.error(
+                    raise RuntimeError(
                         'Hamming distance between codeword {} at index {} '
                         'and codeword {} at index {} is too low.'.format(
                             w, k, w2, k + 1 + k2))
-                    exit(1)
 
 
 def _validate_secded(config):
@@ -145,8 +142,7 @@
     total_width = config['secded']['data_width'] + config['secded']['ecc_width']
 
     if config['secded']['ecc_width'] != len(config['secded']['ecc_matrix']):
-        log.error('ECC matrix does not have correct number of rows')
-        exit(1)
+        raise RuntimeError('ECC matrix does not have correct number of rows')
 
     log.info('SECDED Matrix:')
     for i, l in enumerate(config['secded']['ecc_matrix']):
@@ -154,8 +150,7 @@
         for j, e in enumerate(l):
             e = check_int(e)
             if e < 0 or e >= total_width:
-                log.error('ECC bit position is out of bounds')
-                exit(1)
+                raise RuntimeError('ECC bit position is out of bounds')
             config['secded']['ecc_matrix'][i][j] = e
 
 
@@ -173,12 +168,10 @@
     if config['min_hw'] >= total_width or \
        config['max_hw'] > total_width or \
        config['min_hw'] >= config['max_hw']:
-        log.error('Hamming weight constraints are inconsistent.')
-        exit(1)
+        raise RuntimeError('Hamming weight constraints are inconsistent.')
 
     if config['max_hw'] - config['min_hw'] + 1 < config['min_hd']:
-        log.error('Hamming distance constraint is inconsistent.')
-        exit(1)
+        raise RuntimeError('Hamming distance constraint is inconsistent.')
 
 
 def _validate_tokens(config):
@@ -207,16 +200,16 @@
                 log.info('Inferred {} = {}'.format(
                     'num_' + typ + '_words', config['num_' + typ + '_words']))
             if config['num_' + typ + '_words'] != len(config[typ][state]):
-                log.error('{} entry {} has incorrect length {}'.format(
-                    typ, state, len(config[typ][state])))
-                exit(1)
+                raise RuntimeError(
+                    '{} entry {} has incorrect length {}'.format(
+                        typ, state, len(config[typ][state])))
             # Render the format templates above.
             for j, entry in enumerate(config[typ][state]):
                 legal_values = [fmt.format(j) for fmt in LC_STATE_TYPES[typ]]
                 if entry not in legal_values:
-                    log.error('Illegal entry "{}" found in {} of {}'.format(
-                        entry, state, typ))
-                    exit(1)
+                    raise RuntimeError(
+                        'Illegal entry "{}" found in {} of {}'.format(
+                            entry, state, typ))
 
 
 def _generate_words(config):
@@ -264,19 +257,15 @@
         log.info('')
 
         if 'seed' not in config:
-            log.error('Missing seed in configuration')
-            exit(1)
+            raise RuntimeError('Missing seed in configuration')
         if 'secded' not in config:
-            log.error('Missing secded configuration')
-            exit(1)
+            raise RuntimeError('Missing secded configuration')
         if 'tokens' not in config:
-            log.error('Missing token configuration')
-            exit(1)
+            raise RuntimeError('Missing token configuration')
 
         for typ in LC_STATE_TYPES.keys():
             if typ not in config:
-                log.error('Missing {} definition'.format(typ))
-                exit(1)
+                raise RuntimeError('Missing {} definition'.format(typ))
 
         config['seed'] = check_int(config['seed'])
         log.info('Seed: {0:x}'.format(config['seed']))
@@ -313,12 +302,11 @@
         ecc_width = self.config['secded']['ecc_width']
 
         if name not in LC_STATE_TYPES:
-            log.error('Unknown state type {}'.format(name))
-            exit(1)
+            raise RuntimeError('Unknown state type {}'.format(name))
 
         if state not in self.config[name]:
-            log.error('Unknown state {} of type {}'.format(state, name))
-            exit(1)
+            raise RuntimeError('Unknown state {} of type {}'.format(
+                state, name))
 
         # Assemble list of state words
         words = []