| #!/usr/bin/env python3 |
| """Runs test within Qemu and Renode simulators.""" |
| import argparse |
| import os |
| import re |
| import sys |
| import tempfile |
| |
| import io |
| import pexpect |
| |
| |
| parser = argparse.ArgumentParser( |
| description="Run a springbok test on an simulator.") |
| |
| parser.add_argument('simulator', |
| help='Select a simulator', |
| choices=['renode', 'qemu']) |
| parser.add_argument('elf', |
| help='Elf to execute on a simulator') |
| parser.add_argument('--renode-path', |
| help="Path to renode simulator") |
| parser.add_argument('--qemu-path', |
| help="Path to qemu simulator") |
| parser.add_argument('--timeout', type=int, |
| help="Timeout for test", default=1000) |
| |
| class Simulation: # pylint: disable=too-few-public-methods |
| """ Base class for simulation """ |
| def __init__(self, simulator_cmd): |
| self.simulator_cmd = simulator_cmd |
| self.buffer = io.StringIO() |
| self.child = None |
| self.termination_strings = ["main returned", "Exception occurred"] |
| |
| def run(self, timeout=1000): |
| """ Run the simulation command and quit the simulation.""" |
| self.child = pexpect.spawn(self.simulator_cmd, encoding='utf-8') |
| self.child.logfile = self.buffer |
| self.child.expect(self.termination_strings, timeout=timeout) |
| self.child.send("\nq\n") |
| self.child.expect(pexpect.EOF, timeout=timeout) |
| self.child.close() |
| self.buffer.seek(0) |
| return self.buffer.read() |
| |
| class QemuSimulation(Simulation): # pylint: disable=too-few-public-methods |
| """ Qemu simulation """ |
| def __init__(self, path, elf): |
| self.qemu_simulator_cmd = ( |
| "%(sim)s -M springbok -nographic -d springbok -device loader,file=%(elf)s") |
| self.sim_params = {"sim": path, "elf": elf} |
| super().__init__(self.qemu_simulator_cmd % self.sim_params) |
| |
| |
| class RenodeSimulation(Simulation): # pylint: disable=too-few-public-methods |
| """ Renode Simulation """ |
| def __init__(self, path, elf): |
| # Get the ROOTDIR path if it exists |
| self.rootdir = os.environ.get('ROOTDIR', default=None) |
| if self.rootdir is None: |
| parser.error("ROOTDIR environment variable not set.") |
| renode_script = """ |
| path set @%(rootdir)s |
| $bin=@%(elf)s |
| include @sim/config/springbok.resc |
| sysbus.cpu2 PerformanceInMips 2000 |
| emulation SetGlobalQuantum "1" |
| start |
| sysbus.vec_controlblock WriteDoubleWord 0xc 0""" |
| self.script_params = { |
| "rootdir": self.rootdir, |
| "elf":elf |
| } |
| self.renode_script = renode_script % self.script_params |
| |
| self.renode_args = [ |
| "mono", |
| "%s" % path, |
| '--disable-xwt', |
| ' --console', |
| '--plain', |
| ] |
| self.renode_simulator_cmd = " ".join(self.renode_args) |
| super().__init__(self.renode_simulator_cmd) |
| |
| def run(self, timeout=120): |
| file_desc, script_path = tempfile.mkstemp(suffix=".resc") |
| try: |
| with os.fdopen(file_desc, 'w') as tmp: |
| tmp.write(self.renode_script) |
| tmp.flush() |
| self.simulator_cmd += " %s" % script_path |
| test_output = super().run() |
| finally: |
| os.remove(script_path) |
| return test_output |
| |
| |
| Simulators = { |
| "qemu": QemuSimulation, |
| "renode": RenodeSimulation |
| } |
| |
| args = parser.parse_args() |
| |
| simulators_paths = { |
| "renode": args.renode_path, |
| "qemu": args.qemu_path |
| } |
| |
| |
| def main(): |
| """ Run a test and check for Pass or Fail """ |
| simulator_path = simulators_paths[args.simulator] |
| if simulator_path is None: |
| parser.error( |
| "Must provide path to simulator %s, use argument --%s-path" % (args.simulator, |
| args.simulator)) |
| |
| simulator_class = Simulators[args.simulator] |
| simulator = simulator_class(simulator_path, args.elf) |
| output = simulator.run(timeout=args.timeout) |
| # mono API generates escape characters at the termination. Need to clean up. |
| # TODO(hcindyl): Remove this when Renode fix the mono call. |
| ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") |
| output = ansi_escape.sub("", output) |
| print(output) |
| failure_strings = ["FAILED", "Exception occurred"] |
| if any(x in output for x in failure_strings): |
| sys.exit(1) |
| |
| |
| if __name__ == "__main__": |
| main() |