aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2024-05-01 01:28:58 -0700
committerAndrew Waterman <andrew@sifive.com>2024-05-01 01:46:31 -0700
commit89d129614a6b7e0cf6a8ccffb825fb0b6a2af9f7 (patch)
treeb1548dd31793a00edf37b8e29d11dda8c1db03f5
parent09879e6b56714aa705aa67705b1ccb215be427e5 (diff)
downloadriscv-opcodes-89d129614a6b7e0cf6a8ccffb825fb0b6a2af9f7.zip
riscv-opcodes-89d129614a6b7e0cf6a8ccffb825fb0b6a2af9f7.tar.gz
riscv-opcodes-89d129614a6b7e0cf6a8ccffb825fb0b6a2af9f7.tar.bz2
Correctly detect overlapping encodings
A regression introduced a few years ago prevented detecting partially overlapping encodings; instead, we only detected exact matches. Now, we detect the partial cases. We now need to maintain two allowlists (overlapping_extensions and overlapping_instructions) for the cases that extensions and/or instructions overlap by design.
-rw-r--r--constants.py14
-rwxr-xr-xparse.py45
2 files changed, 48 insertions, 11 deletions
diff --git a/constants.py b/constants.py
index dc76ba3..cb3e689 100644
--- a/constants.py
+++ b/constants.py
@@ -2,6 +2,20 @@ import re
import csv
+overlapping_extensions = {
+ 'rv_zcmt': {'rv_c_d'},
+ 'rv_zcmp': {'rv_c_d'},
+ 'rv_c': {'rv_zcmop'},
+}
+
+overlapping_instructions = {
+ 'c_addi': {'c_nop'},
+ 'c_lui': {'c_addi16sp'},
+ 'c_mv': {'c_jr'},
+ 'c_jalr': {'c_ebreak'},
+ 'c_add': {'c_ebreak', 'c_jalr'},
+}
+
isa_regex = \
re.compile("^RV(32|64|128)[IE]+[ABCDEFGHJKLMNPQSTUVX]*(Zicsr|Zifencei|Zihintpause|Zam|Ztso|Zkne|Zknd|Zknh|Zkse|Zksh|Zkg|Zkb|Zkr|Zks|Zkn|Zba|Zbc|Zbb|Zbp|Zbr|Zbm|Zbs|Zbe|Zbf|Zbt|Zmmul|Zbpbo|Zca|Zcf|Zcd|Zcb|Zcmp|Zcmt){,1}(_Zicsr){,1}(_Zifencei){,1}(_Zihintpause){,1}(_Zmmul){,1}(_Zam){,1}(_Zba){,1}(_Zbb){,1}(_Zbc){,1}(_Zbe){,1}(_Zbf){,1}(_Zbm){,1}(_Zbp){,1}(_Zbpbo){,1}(_Zbr){,1}(_Zbs){,1}(_Zbt){,1}(_Zkb){,1}(_Zkg){,1}(_Zkr){,1}(_Zks){,1}(_Zkn){,1}(_Zknd){,1}(_Zkne){,1}(_Zknh){,1}(_Zkse){,1}(_Zksh){,1}(_Ztso){,1}(_Zca){,1}(_Zcf){,1}(_Zcd){,1}(_Zcb){,1}(_Zcmp){,1}(_Zcmt){,1}$")
diff --git a/parse.py b/parse.py
index 98e06a6..48507d9 100755
--- a/parse.py
+++ b/parse.py
@@ -133,7 +133,7 @@ def process_enc_line(line, ext):
return (name, single_dict)
-def same_base_ext (ext_name, ext_name_list):
+def same_base_isa(ext_name, ext_name_list):
type1 = ext_name.split("_")[0]
for ext_name1 in ext_name_list:
type2 = ext_name1.split("_")[0]
@@ -144,6 +144,26 @@ def same_base_ext (ext_name, ext_name_list):
return True
return False
+def overlaps(x, y):
+ x = x.rjust(len(y), '-')
+ y = y.rjust(len(x), '-')
+
+ for i in range(0, len(x)):
+ if not (x[i] == '-' or y[i] == '-' or x[i] == y[i]):
+ return False
+
+ return True
+
+def overlap_allowed(a, x, y):
+ return x in a and y in a[x] or \
+ y in a and x in a[y]
+
+def extension_overlap_allowed(x, y):
+ return overlap_allowed(overlapping_extensions, x, y)
+
+def instruction_overlap_allowed(x, y):
+ return overlap_allowed(overlapping_instructions, x, y)
+
def create_inst_dict(file_filter, include_pseudo=False, include_pseudo_ops=[]):
'''
This function return a dictionary containing all instructions associated
@@ -222,29 +242,32 @@ def create_inst_dict(file_filter, include_pseudo=False, include_pseudo_ops=[]):
# instruction is already imported and raise SystemExit
if name in instr_dict:
var = instr_dict[name]["extension"]
- if same_base_ext(ext_name, var):
- # disable same names on the same base extensions
+ if same_base_isa(ext_name, var):
+ # disable same names on the same base ISA
err_msg = f'instruction : {name} from '
err_msg += f'{ext_name} is already '
- err_msg += f'added from {var} in same base extensions'
+ err_msg += f'added from {var} in same base ISA'
logging.error(err_msg)
raise SystemExit(1)
elif instr_dict[name]['encoding'] != single_dict['encoding']:
- # disable same names with different encodings on different base extensions
+ # disable same names with different encodings on different base ISAs
err_msg = f'instruction : {name} from '
err_msg += f'{ext_name} is already '
- err_msg += f'added from {var} but each have different encodings in different base extensions'
+ err_msg += f'added from {var} but each have different encodings in different base ISAs'
logging.error(err_msg)
raise SystemExit(1)
instr_dict[name]['extension'].extend(single_dict['extension'])
else:
for key in instr_dict:
item = instr_dict[key]
- if item["encoding"] == single_dict['encoding'] and same_base_ext(ext_name, item["extension"]):
- # disable different names with same encodings on the same base extensions
- err_msg = f'instruction : {name} from '
- err_msg += f'{ext_name} has the same encoding with instruction {key} '
- err_msg += f'added from {item["extension"]} in same base extensions'
+ if overlaps(item['encoding'], single_dict['encoding']) and \
+ not extension_overlap_allowed(ext_name, item['extension'][0]) and \
+ not instruction_overlap_allowed(name, key) and \
+ same_base_isa(ext_name, item['extension']):
+ # disable different names with overlapping encodings on the same base ISA
+ err_msg = f'instruction : {name} in extension '
+ err_msg += f'{ext_name} overlaps instruction {key} '
+ err_msg += f'in extension {item["extension"]}'
logging.error(err_msg)
raise SystemExit(1)