Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/improved latex table #160

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 133 additions & 60 deletions parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,13 @@ def make_latex_table():
dataset_list.append((['64_zfh'],'RV64Zfh Standard Extension (in addition to RV32Zfh)', [], False))
make_ext_latex_table(type_list, dataset_list, latex_file, 32, caption)

# Zc* extensions
# caption = '\\caption{Zc* extensions for code size reduction on RISC-V}'
# dataset_list = [(['_zcb', '64_zcb'], 'Zcb (basic compressed ops) extension', [], True)]
# dataset_list.append((['_zcmp'], 'Zcmp (push/pop) extension', [], True))
# dataset_list.append((['_zcmt'], 'Zcmt (table jump) extension', [], True))
# make_ext_latex_table(type_list, dataset_list, latex_file, 16, caption)

## The following is demo to show that Compressed instructions can also be
# dumped in the same manner as above

Expand Down Expand Up @@ -536,6 +543,8 @@ def make_ext_latex_table(type_list, dataset, latex_file, ilen, caption):
multicolumn entry in the table.

'''
max_entries_per_page = 42 # Arbitrary limit chosen at random, promise!
entries_printed = 0 # Keep track of the instructions printed (headers count as 2) to not overflow a page
column_size = "".join(['p{0.002in}']*(ilen+1))

type_entries = '''
Expand Down Expand Up @@ -573,59 +582,23 @@ def make_ext_latex_table(type_list, dataset, latex_file, ilen, caption):
\\multicolumn{1}{c}{0} \\\\
\\cline{2-17}\n&\n\n
'''

# depending on the type_list input we create a subset dictionary of
# latex_inst_type dictionary present in constants.py
type_dict = {key: value for key, value in latex_inst_type.items() if key in type_list}

# iterate ovr each instruction type and create a table entry
for t in type_dict:
fields = []

# first capture all "arguments" of the type (funct3, funct7, rd, etc)
# and capture their positions using arg_lut.
for f in type_dict[t]['variable_fields']:
(msb, lsb) = arg_lut[f]
name = f if f not in latex_mapping else latex_mapping[f]
fields.append((msb, lsb, name))

# iterate through the 32 bits, starting from the msb, and assign
# argument names to the relevant portions of the instructions. This
# information is stored as a 3-element tuple containing the msb, lsb
# position of the arugment and the name of the argument.
msb = ilen - 1
y = ''
for r in range(0,ilen):
if y != '':
fields.append((msb,ilen-1-r+1,y))
y = ''
msb = ilen-1-r-1
if r == 31:
if y != '':
fields.append((msb, 0, y))
y = ''

# sort the arguments in decreasing order of msb position
fields.sort(key=lambda y: y[0], reverse=True)

# for each argument/string of 1s or 0s, create a multicolumn latex table
# entry
entry = ''
for r in range(len(fields)):
(msb, lsb, name) = fields[r]
if r == len(fields)-1:
entry += f'\\multicolumn{{{msb - lsb + 1}}}{{|c|}}{{{name}}} & {t} \\\\\n'
elif r == 0:
entry += f'\\multicolumn{{{msb - lsb + 1}}}{{|c|}}{{{name}}} &\n'
else:
entry += f'\\multicolumn{{{msb - lsb + 1}}}{{c|}}{{{name}}} &\n'
entry += f'\\cline{{2-{ilen+1}}}\n&\n\n'
type_entries += entry

if ilen == 16:
# For compressed instructions, print the bit positions above each table to make it easier to read
c_instr_header = type_entries
else:
c_instr_header = ''
# for each entry in the dataset create a table
content = ''
content_list = []
auto_types = {key: False for key, _ in latex_inst_type.items()}
# For simplicity's sake, assume R-type always present for 32-bit
auto_types['R-type'] = (ilen == 32)
for (ext_list, title, filter_list, include_pseudo) in dataset:
instr_dict = {}
# Support multi-page tables
entries_list = []
if title != '':
entries_printed += 2 # Each time a new table starts the heading eats 2 lines

# for all extensions list in ext_list, create a dictionary of
# instructions associated with those extensions.
Expand Down Expand Up @@ -654,6 +627,22 @@ def make_ext_latex_table(type_list, dataset, latex_file, ilen, caption):
(msb,lsb) = arg_lut[f]
name = f.replace('_','.') if f not in latex_mapping else latex_mapping[f]
fields.append((msb, lsb, name))
# if 'funct7' == f: # NOTE: this doesn't really get detected but in most cases we can assume R-type is present by default
# auto_types['R-type'] = True
if 'imm20' == f:
auto_types['U-type'] = True
elif 'imm12hi' == f:
auto_types['S-type'] = True
elif 'bimm12hi' == f:
auto_types['B-type'] = True
elif 'rs3' == f:
auto_types['R4-type'] = True
elif 'jimm20' == f:
auto_types['J-type'] = True
# elif 'shamt' in arguments[n] or 'shamtw' in arguments[n] or 'imm12' in arguments[n] or n == 'ecall' or n == 'ebreak' or n[:3] == 'csr':
elif 'imm12' == f:
auto_types['I-type'] = True


msb = ilen -1
y = ''
Expand Down Expand Up @@ -691,25 +680,109 @@ def make_ext_latex_table(type_list, dataset, latex_file, ilen, caption):
entry += f'\\multicolumn{{{msb - lsb + 1}}}{{c|}}{{{name}}} &\n'
entry += f'\\cline{{2-{ilen+1}}}\n&\n\n'
instr_entries += entry
entries_printed += 1

if entries_printed >= max_entries_per_page:
# Once we've filled a page, break and start a new one
entries_list.append(str(instr_entries)) # Make sure it's a deep copy and not just a link
instr_entries = ''
entries_printed = 0

# Flush out the rest, if any
if entries_printed > 0:
entries_list.append(str(instr_entries)) # Make sure it's a deep copy and not just a link
instr_entries = ''

# once an entry of the dataset is completed we create the whole table
# with the title of that dataset as sub-heading (sort-of)
if title != '':
content += f'''
content_list.append((title, entries_list))

\\multicolumn{{{ilen}}}{{c}}{{}} & \\\\
\\multicolumn{{{ilen}}}{{c}}{{\\bf {title} }} & \\\\
\\cline{{2-{ilen+1}}}
# depending on the autodetected encoding types we create a subset dictionary of
# latex_inst_type dictionary present in constants.py
type_dict = {key: value for key, value in latex_inst_type.items() if auto_types[key]}

# iterate over each instruction type and create a table entry
for t in type_dict:
fields = []

# first capture all "arguments" of the type (funct3, funct7, rd, etc)
# and capture their positions using arg_lut.
for f in type_dict[t]['variable_fields']:
(msb, lsb) = arg_lut[f]
name = f if f not in latex_mapping else latex_mapping[f]
fields.append((msb, lsb, name))

# iterate through the 32 bits, starting from the msb, and assign
# argument names to the relevant portions of the instructions. This
# information is stored as a 3-element tuple containing the msb, lsb
# position of the arugment and the name of the argument.
msb = ilen - 1
y = ''
for r in range(0,ilen):
if y != '':
fields.append((msb,ilen-1-r+1,y))
y = ''
msb = ilen-1-r-1
if r == 31:
if y != '':
fields.append((msb, 0, y))
y = ''

# sort the arguments in decreasing order of msb position
fields.sort(key=lambda y: y[0], reverse=True)

# for each argument/string of 1s or 0s, create a multicolumn latex table
# entry
entry = ''
for r in range(len(fields)):
(msb, lsb, name) = fields[r]
if r == len(fields)-1:
entry += f'\\multicolumn{{{msb - lsb + 1}}}{{|c|}}{{{name}}} & {t} \\\\\n'
elif r == 0:
entry += f'\\multicolumn{{{msb - lsb + 1}}}{{|c|}}{{{name}}} &\n'
else:
entry += f'\\multicolumn{{{msb - lsb + 1}}}{{c|}}{{{name}}} &\n'
entry += f'\\cline{{2-{ilen+1}}}\n&\n\n'
type_entries += entry
# If we for some reason don't have any type entries, skip printing the single empty row altogether
if len(type_dict) == 0:
type_entries = ''

# Now that we have everything, run through and generate the proper output!
for (title, entries_list) in content_list:
for i, instr_entries in enumerate(entries_list):
if i > 0: # Second time around, add footer and header because it's a new page
content += f'''

\\end{{tabular}}
\\end{{center}}
\\end{{small}}
\\end{{table}}
\\newpage

\\begin{{table}}[p]
\\begin{{small}}
\\begin{{center}}
\\begin{{tabular}} {{{column_size}l}}
{" ".join(['&']*ilen)} \\\\

&
{instr_entries}
'''
else:
content += f'''
{instr_entries}
{type_entries}
'''
if title != '':
content += f'''


\\multicolumn{{{ilen}}}{{c}}{{}} & \\\\
\\multicolumn{{{ilen}}}{{c}}{{\\bf {title + ", cont'd" if i > 0 else title} }} & \\\\
'''
if ilen == 32:
content += f' \\cline{{2-{ilen+1}}} &'
else:
content += '&\n' + c_instr_header
content += f'''
{instr_entries}
'''

header = f'''
\\newpage

Expand Down