blob: a89cbb929ffc07631d46083de731b37880ae8dbb [file] [log] [blame]
#!/usr/bin/env python3
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
'''Wrapper script to run the OTBN random instruction generator'''
import argparse
import json
import os
import random
import sys
from typing import Optional, cast
from shared.insn_yaml import InsnsFile, load_insns_yaml
# Ensure that the OTBN utils directory is on sys.path. This means that RIG code
# can import modules like "shared.foo" and get the OTBN shared code.
sys.path.append(os.path.dirname(__file__))
from rig.rig import gen_program, snippets_to_program # noqa: E402
from rig.snippet import Snippet # noqa: E402
def get_insns_file() -> Optional[InsnsFile]:
'''Load up insns.yml'''
try:
return load_insns_yaml()
except RuntimeError as err:
print(err, file=sys.stderr)
return None
def gen_main(args: argparse.Namespace) -> int:
'''Entry point for the gen subcommand'''
random.seed(args.seed)
insns_file = get_insns_file()
if insns_file is None:
return 1
# Run the generator
snippets, program = gen_program(args.start_addr, args.size, insns_file)
# Write out the snippets to a JSON file
ser_snippets = [snippet.to_json() for snippet in snippets]
try:
if args.output == '-':
json.dump(ser_snippets, sys.stdout)
# Add a newline at end of output: json.dump doesn't, and it makes a
# bit of a mess of some consoles.
sys.stdout.write('\n')
else:
with open(args.output, 'w') as out_file:
json.dump(ser_snippets, out_file)
except OSError as err:
print('Failed to open json output file {!r}: {}.'
.format(args.output, err),
file=sys.stderr)
return 1
return 0
def asm_main(args: argparse.Namespace) -> int:
'''Entry point for the asm subcommand'''
insns_file = get_insns_file()
if insns_file is None:
return 1
# Load snippets JSON
try:
snippets_json = json.load(args.snippets)
except json.JSONDecodeError as err:
print('Snippets file at {!r} is not valid JSON: {}.'
.format(args.snippets.name, err),
file=sys.stderr)
return 1
# Parse these to proper snippet objects and then make a program by
# combining them
try:
if not isinstance(snippets_json, list):
raise ValueError('Top-level structure should be a list.')
snippets = [Snippet.from_json(insns_file, idx, x)
for idx, x in enumerate(snippets_json)]
except ValueError as err:
print('Failed to parse snippets from {!r}: {}'
.format(args.snippets, err),
file=sys.stderr)
return 1
program = snippets_to_program(snippets)
# Dump the assembly output.
if args.output is None or args.output == '-':
program.dump_asm(sys.stdout)
else:
try:
asm_path = args.output + '.S'
with open(asm_path, 'w') as out_file:
program.dump_asm(out_file)
except OSError as err:
print('Failed to open asm output file {!r}: {}.'
.format(args.output, err),
file=sys.stderr)
return 1
try:
ld_path = args.output + '.ld'
with open(ld_path, 'w') as out_file:
program.dump_linker_script(out_file)
except OSError as err:
print('Failed to open ld script output file {!r}: {}.'
.format(ld_path, err),
file=sys.stderr)
return 1
return 0
def main() -> int:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
gen = subparsers.add_parser('gen', help='Generate a random program')
asm = subparsers.add_parser('asm', help='Convert snippets to assembly')
gen.add_argument('--output', '-o',
default='-',
help=("Path for JSON output of generated snippets. The "
"special path '-' (which is the default) means to "
"write to stdout"))
gen.add_argument('--seed', type=int, default=0,
help='Random seed. Defaults to 0.')
gen.add_argument('--size', type=int, default=100,
help=('Max number of instructions in stream. '
'Defaults to 100.'))
gen.add_argument('--start-addr', type=int, default=0,
help='Reset address. Defaults to 0.')
gen.set_defaults(func=gen_main)
asm.add_argument('--output', '-o',
metavar='out',
help=('Base path for output filenames. Will generate '
'out.S with an assembly listing and out.ld with '
'a linker script. If this is not supplied, the '
'assembly (but no linker script) will be dumped '
'to stdout.'))
asm.add_argument('snippets', metavar='path.json',
type=argparse.FileType('r'), nargs='?', default=sys.stdin,
help=('A JSON file of snippets, as generated by '
'otbn-rig gen.'))
asm.set_defaults(func=asm_main)
args = parser.parse_args()
return cast(int, args.func(args))
if __name__ == '__main__':
sys.exit(main())