#!/usr/bin/env python3
import argparse
import json
from urllib import request
from urllib import parse
import requests
import yaml
import sys
import re
#opcodes_yaml = "https://five-embeddev.github.io/riscv-docs-html/opcodes.yaml"
opcodes_yaml = "https://five-embeddev.github.io/riscv-docs-html/opcodes.yaml"
htmlhost = "https://five-embeddev.github.io/riscv-docs-html/"
parser = argparse.ArgumentParser(description='Scrape the five-embeddev quick reference page and generate the riscv documentation')
parser.add_argument('-i', '--opcode-data', type=str, help='Input opcode data in YAML format.',
default=opcodes_yaml)
parser.add_argument('-o', '--outputpath', type=str, help='Final path of the .ts file. Default is ./asm-docs-riscv64.ts',
default='./asm-docs-riscv64.ts')
def bold_keyword(text, keyword):
for keywordr in (keyword.upper(), keyword.lower()):
rer = re.compile(f"\\b{keywordr}\\b")
text,_ = re.subn(rer,f"{keywordr}",text)
return text
class operation:
def __init__(self, yaml_record, yaml_data):
opcode = yaml_record['opcode'][0].upper()
# Remove "@" and "c." from opcode
# These are
self.opcode = opcode
self.opcode_alias = None
if 'opcode_alias' in yaml_record:
self.opcode_alias = yaml_record['opcode_alias'].upper()
tool_opcode_args = opcode + " " + ', '.join(yaml_record['opcode_args']) + "\n"
html_opcode_args = f"{opcode} {', '.join(yaml_record['opcode_args'])}"
# What ISA does this opcode belong to?
# Is it a psuedo opcode?
group=""
if 'main_desc' in yaml_record:
group += yaml_record['main_desc']
if 'psuedo' == yaml_record['opcode_group']:
group += "(pseudo)"
html_code = ""
text_code = ""
html_group = f"
ISA: {group}
"
if 'psuedo_to_base' in yaml_record:
html_code += "
Equivalent ASM:"
html_code += "\n".join(yaml_record['psuedo_to_base'])
html_code += "
"
text_code += "Equivalent ASM:\n\n" + "\n".join(yaml_record['psuedo_to_base'])
if 'main_url_base' in yaml_record:
main_url_base = yaml_record['main_url_base']
main_desc = yaml_record['main_desc']
main_id = yaml_record['main_id']
opcode_descs = yaml_record['desc'][main_desc][main_id]['text']
tool_desc = "\n".join(opcode_descs) + "\n\n" + text_code + "\n\n(ISA: " + group + ")"
html_desc = "
" + "
".join([bold_keyword(x,opcode) for x in opcode_descs]) + "
"
self.url = htmlhost + main_url_base + main_id
self.tooltip = tool_desc
# extract all elements under the second column and the third column which are td
# and put them into a new div tag
self.html = "" + html_opcode_args + html_desc + html_code + html_group + "
"
elif 'psuedo_to_base' in yaml_record:
self.url = htmlhost
self.tooltip = "Psuedo Instruction.\n\n" + text_code + "\n\n"
self.html = "" + html_opcode_args + html_code + html_group + "
"
else:
self.url = htmlhost
self.tooltip = "\n\n(ISA: " + group + ")"
self.html = "" + html_opcode_args + html_group + "
"
def __str__(self):
dic = {
# no opcode here
"tooltip": self.tooltip,
"url": self.url,
"html": self.html
}
return json.dumps(dic, indent=16, separators=(',', ': '), sort_keys=True)
if __name__ == '__main__':
args = parser.parse_args()
yaml_text=None
try:
if args.opcode_data[:4] == "http":
r = requests.get(args.opcode_data)
r.encoding = 'utf-8'
yaml_text = r.text
else:
with open(args.opcode_data, 'r') as fin :
yaml_text=fin.read()
except:
print("ERROR: Loading YAML file or URL: " + args.opcode_data + ":")
print(exc)
sys.exit(-1)
yaml_data=None
try:
yaml_data = yaml.safe_load(yaml_text)
except yaml.YAMLError as exc:
print("ERROR: Parsing YAML file: " + args.opcode_data + ":")
print(exc)
sys.exit(-1)
with open(args.outputpath, "w") as output:
output.write("""
import {AssemblyInstructionInfo} from '../base.js';
export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInfo | undefined {
if (!opcode) return;
switch (opcode.toUpperCase()) {
""".lstrip())
for record in [operation(o, yaml_data) for o in yaml_data['opcodes'].values()]:
# for each opcode
output.write(f' case "{record.opcode}":\n')
if record.opcode_alias:
output.write(f' case "{record.opcode_alias}":\n')
output.write(f' return {str(record)[:-1]} }};\n\n')
output.write("""
}
}
""")