from riscemu.colors import FMT_ERROR, FMT_NONE, FMT_BOLD, FMT_GREEN from riscemu.instructions import InstructionSet from riscemu.types import Instruction, CPU from riscemu.decoder import RISCV_REGS FMT_SUCCESS = FMT_GREEN + FMT_BOLD def assert_equals(ins: Instruction, cpu: CPU): a, b = (get_arg_from_ins(ins, i, cpu) for i in (0, 2)) return a == b def assert_equals_mem(ins: Instruction, cpu: CPU): a, b = (get_arg_from_ins(ins, i, cpu) for i in (0, 2)) a = cpu.mmu.read_int(a) return a == b def assert_in(ins: Instruction, cpu: CPU): a = get_arg_from_ins(ins, 0, cpu) others = [get_arg_from_ins(ins, i, cpu) for i in range(2, len(ins.args))] return a in others def _not(func): def test(ins: Instruction, cpu: CPU): return not func(ins, cpu) return test def get_arg_from_ins(ins: Instruction, num: int, cpu: CPU): a = ins.args[num] if a in RISCV_REGS: return cpu.regs.get(a) return ins.get_imm(num) assert_ops = { '==': assert_equals, '!=': _not(assert_equals), 'in': assert_in, 'not_in': _not(assert_in), } class Z_test(InstructionSet): def __init__(self, cpu: 'CPU'): print('[Test] loading testing ISA, this is only meant for running testcases and is not part of the RISC-V ISA!') self.failed = False super().__init__(cpu) def instruction_assert(self, ins: Instruction): if len(ins.args) < 3: print(FMT_ERROR + '[Test] Unknown assert statement: {}'.format(ins) + FMT_NONE) return op = ins.args[1] if op not in assert_ops: print(FMT_ERROR + '[Test] Unknown operation statement: {} in {}'.format(op, ins) + FMT_NONE) return if assert_ops[op](ins, self.cpu): print(FMT_SUCCESS + '[TestCase] 🟢 passed assertion {}'.format(ins)) else: print(FMT_ERROR + '[TestCase] 🔴 failed assertion {}'.format(ins)) self.cpu.halted = True self.failed = True def instruction_fail(self, ins: Instruction): print(FMT_ERROR + '[TestCase] 🔴 reached fail instruction! {}'.format(ins)) self.cpu.halted = True self.failed = True