Skip to content

Instantly share code, notes, and snippets.

@linsinan1995
Last active March 15, 2021 23:36
Show Gist options
  • Save linsinan1995/a5d670af631e6701163096f49925ea19 to your computer and use it in GitHub Desktop.
Save linsinan1995/a5d670af631e6701163096f49925ea19 to your computer and use it in GitHub Desktop.
A tool used for easing the pain of adding opcode and mask to risc-v binutils. See gen_opcode.py

Intro

A tool used for easing the pain of adding opcode and mask to risc-v binutils. Other example, see gen_opcode.py and gen_kadd.py.

Usage

from gen_opcode import *

# init instruction
kadd8 = Inst("kadd8")
kaddh = Inst("kaddh")

# set output path
file_path = "kadd.txt"

# fill the fields of instruction
kadd8.adds([
    # add field by field
    [6, '1110111'], # 0~6
    # 0 => reg field, '0' => non-reg field. distinguish them for generating mask
    [11, 0],        # 7~11
    [14, '0'],      # 12~14
    [24, 0],        # 15~24
    [31, '1100']    # 25~31, or [31, '0001100'] 
])

kaddh.adds([
    [6, '1110111'], # 0~6
    [11, 0],        # 7~11
    [14, '001'],    # 12~14
    [24, 0],        # 15~24
    [31, '10']      # 25~31
])

# put them in a list to create a generation pipeline
insts = [kadd8, kaddh]

output = [[inst.match_macro, inst.mask_macro, ] for inst in insts if inst.gen()]

with open(file_path, "w") as f:
    for ret in output:
        f.writelines(ret)

Terminal output

KADD8
#define MATCH_KADD8 0x18000077
#define MASK_KADD8 0xfe00707f
length :  32
opcoede:  00011000000000000000000001110111
mask   :  11111110000000000111000001111111
KADDH
#define MATCH_KADDH 0x4001077
#define MASK_KADDH 0xfe00707f
length :  32
opcoede:  00000100000000000001000001110111
mask   :  11111110000000000111000001111111

File output (kadd.txt)

#define MATCH_KADD8 0x18000077
#define MASK_KADD8 0xfe00707f
#define MATCH_KADDH 0x4001077
#define MASK_KADDH 0xfe00707f
from gen_opcode import *
file_path = "kadd.txt"
op_p = [6, '1110111']
inst_list = ["kadd" + str(i) for i in [8, 16, 64, 'h', 'w']]
inst_list += ["kabs" + str(i) for i in [8, 16, 32, 'w']]
insts = {inst_name : Inst(inst_name) for inst_name in inst_list}
insts["kadd8"].adds([
# add field by field
op_p, # 0~6
[11, 0], # 7~11, 0 => reg field, '0' => non-reg field
[14, '0'], # 12~14
[24, 0], # 15~24
[31, '1100'] # 25~31
])
insts["kadd16"].adds([
# add field by field
op_p, # 0~6
[11, 0], # 7~11
[14, '0'], # 12~14
[24, 0], # 15~24
[31, '1000'] # 25~31
])
insts["kadd64"].adds([
# add field by field
op_p, # 0~6
[11, 0], # 7~11, 0 => reg field, '0' => non-reg field
[14, '1'], # 12~14
[24, 0], # 15~24
[31, '1001000'] # 25~31
])
insts["kaddh"].adds([
# add field by field
op_p, # 0~6
[11, 0], # 7~11, 0 => reg field, '0' => non-reg field
[14, '001'], # 12~14
[24, 0], # 15~24
[31, '0000010'] # 25~31
])
insts["kaddw"].adds([
# add field by field
op_p, # 0~6
[11, 0], # 7~11, 0 => reg field, '0' => non-reg field
[14, '1'], # 12~14
[24, 0], # 15~24
[31, '0'] # 25~31
])
insts["kabs8"].adds([
# add field by field
op_p, # 0~6
[11, 0], # 7~11, 0 => reg field, '0' => non-reg field
[14, '0'], # 12~14
[19, 0],
[24, '10000'], # 15~24
[31, '1010110'] # 25~31
])
insts["kabs16"].adds([
# add field by field
op_p, # 0~6
[11, 0], # 7~11, 0 => reg field, '0' => non-reg field
[14, '0'], # 12~14
[19, 0],
[24, '10001'], # 15~24
[31, '1010110'] # 25~31
])
insts["kabs32"].adds([
# add field by field
op_p, # 0~6
[11, 0], # 7~11, 0 => reg field, '0' => non-reg field
[14, '0'], # 12~14
[19, 0],
[24, '10010'], # 15~24
[31, '1010110'] # 25~31
])
insts["kabsw"].adds([
# add field by field
op_p, # 0~6
[11, 0], # 7~11, 0 => reg field, '0' => non-reg field
[14, '0'], # 12~14
[19, 0],
[24, '10100'], # 15~24
[31, '1010110'] # 25~31
])
output = [[inst.match_macro, inst.mask_macro, ] for inst in insts.values() if inst.gen()]
with open(file_path, "w") as f:
for ret in output:
f.writelines(ret)
def err(string):
print("\033[93m{}\033[0m".format(string))
def ok(string, end="\n"):
print("\033[92m{}\033[0m".format(string), end=end)
def warning(string):
print("\033[92m{}\033[0m".format(string))
class Inst:
def __init__(self, name, FIX_LENGTH = 32):
self.name = name
self.field_map = {}
self.idx = 0
self.match_macro = None
self.mask_macro = None
self.cFIX_LENGTH = 32
def add(self, end, code):
expected_len = end - self.idx + 1
if isinstance(code, int):
if code == 0:
self.field_map[end] = 0
self.idx += expected_len
return True
else:
return self.error("[ERROR] invalid code {} in {}".format(code, self.name))
# 0 padding
if len(code) < expected_len:
self.field_map[end] = '0' * (expected_len - len(code)) + code
elif (len(code) == expected_len):
self.field_map[end] = code
else:
return self.error("""[ERROR] it is supposed to get code {} ending at pos {} in {}, but it ends at pos {}""".format(
code, self.idx + expected_len, self.name, len(code) + self.idx))
self.idx += expected_len
return True
def error(self, string):
err(string)
self.field_map = {}
return False
@staticmethod
def str_to_bin(bin_str, base = 2):
return bin(int(bin_str, base))
@staticmethod
def str_to_hex(bin_str, base = 2):
return hex(int(bin_str, base))
def adds(self, end_code_pairs = False, show = True):
if isinstance(end_code_pairs, list):
for end, code in end_code_pairs:
if not self.add(end, code):
warning("[Warning] Stop add fields for {}".format(self.name))
break
def gen(self, show = True):
if self.mask_macro is not None:
return [self.match_macro, self.mask_macro]
if len(self.field_map) == 0:
err("[Skip] Haven't set fields in {}".format(self.name))
return
# maybe sometimes I do not follow the order
list_field_map = sorted(self.field_map.items(), key=lambda t: t[0])
opcode = ''
mask = ''
for k, v in list_field_map:
if v == 0:
opcode = (k-len(opcode)+1) * '0' + opcode
mask = (k-len(mask)+1) * '0' + mask
else:
opcode = v + opcode
mask = (k-len(mask)+1) * '1' + mask
if len(opcode) != self.cFIX_LENGTH:
err("[ERROR] invalid length of opcode, we expect {}, but we expect {} but got {}!".format(opcode, self.cFIX_LENGTH, len(opcode)))
return
if len(mask) != self.cFIX_LENGTH:
err("[ERROR] invalid length of mask, we expect {}, but we expect {} but got {}!".format(mask, self.cFIX_LENGTH, len(mask)))
return
inst_name = self.name.upper()
self.match_macro = "#define MATCH_{} {}\n".format(inst_name, Inst.str_to_hex(opcode, 2))
self.mask_macro = "#define MASK_{} {}\n".format(inst_name, Inst.str_to_hex(mask, 2))
if show:
ok("{}".format(inst_name))
ok(self.match_macro, "")
ok(self.mask_macro, "")
print("length : ", len(opcode))
print("opcoede: ", opcode)
print("mask : ", mask)
return True
if __name__ == "__main__":
file_path = "opcode.txt"
op_p = [6, '1110111']
insts = {
"kadd8": Inst("kadd8"),
"kadd16": Inst("kadd16"),
"kadd64": Inst("kadd64"),
"kaddh": Inst("kaddh"),
"kaddw": Inst("kaddw"),
}
insts["kadd8"].adds([
# add field by field
op_p, # 0~6
[11, 0], # 7~11, 0 => reg field, '0' => non-reg field
[14, '0'], # 12~14
[24, 0], # 15~24
[31, '1100'] # 25~31
])
insts["kaddh"].adds([
op_p, # 0~6
[11, 0], # 7~11
[14, '001'], # 12~14
[24, 0], # 15~24
[31, '10'] # 25~31
])
output = [[inst.match_macro, inst.mask_macro, ] for inst in insts.values() if inst.gen()]
with open(file_path, "w") as f:
for ret in output:
f.writelines(ret)
#define MATCH_KADD8 0x18000077
#define MASK_KADD8 0xfe00707f
#define MATCH_KADD16 0x10000077
#define MASK_KADD16 0xfe00707f
#define MATCH_KADD64 0x90001077
#define MASK_KADD64 0xfe00707f
#define MATCH_KADDH 0x4001077
#define MASK_KADDH 0xfe00707f
#define MATCH_KADDW 0x1077
#define MASK_KADDW 0xfe00707f
#define MATCH_KABS8 0xad000077
#define MASK_KABS8 0xfff0707f
#define MATCH_KABS16 0xad100077
#define MASK_KABS16 0xfff0707f
#define MATCH_KABS32 0xad200077
#define MASK_KABS32 0xfff0707f
#define MATCH_KABSW 0xad400077
#define MASK_KABSW 0xfff0707f
#define MATCH_KADD8 0x18000077
#define MASK_KADD8 0xfe00707f
#define MATCH_KADDH 0x4001077
#define MASK_KADDH 0xfe00707f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment