112 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			112 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Tests for the implementation of SYS_MultiplyBytes_126"""
 | 
						|
import os.path
 | 
						|
import pathlib
 | 
						|
from importlib import reload
 | 
						|
from types import SimpleNamespace
 | 
						|
 | 
						|
from hypothesis import given
 | 
						|
from hypothesis import strategies as st
 | 
						|
 | 
						|
import asm
 | 
						|
from gtemu import RAM, Emulator
 | 
						|
 | 
						|
MAX_CYCLES = 120
 | 
						|
 | 
						|
 | 
						|
SYS_DIR = (pathlib.Path(__file__).parent / ".." / "sys").resolve()
 | 
						|
SCRIPT = SYS_DIR / "ROM.asm.py"
 | 
						|
 | 
						|
 | 
						|
def setup_module():
 | 
						|
    global vars
 | 
						|
    """Load the Emulator from the ROM script"""
 | 
						|
    reload(asm)
 | 
						|
    name, _ = os.path.splitext(os.path.basename(SCRIPT))
 | 
						|
    script_globals = {"__file__": str(SCRIPT.absolute()), "__name__": name}
 | 
						|
    with SCRIPT.open("rb") as file:
 | 
						|
        exec(compile(file.read(), SCRIPT, "exec"), script_globals)
 | 
						|
    Emulator.load_rom_from_asm_module()
 | 
						|
    vars = SimpleNamespace(**script_globals)
 | 
						|
 | 
						|
 | 
						|
def setup_function():
 | 
						|
    RAM[vars.sysFn : vars.sysFn + 2] = asm.symbol("SYS_MultiplyBytes_120").to_bytes(
 | 
						|
        2, "little"
 | 
						|
    )
 | 
						|
    RAM[vars.vTicks] = 75
 | 
						|
    Emulator.next_instruction = "SYS"
 | 
						|
    Emulator.AC = 270 - max(14, MAX_CYCLES // 2)
 | 
						|
 | 
						|
 | 
						|
def test_timing_both_lt_128():
 | 
						|
    """Follow the routine through, checking the timing comments
 | 
						|
 | 
						|
    This follows the case where both values are less than 128
 | 
						|
    I'm just trying to check that the comments are correct!
 | 
						|
    """
 | 
						|
    RAM[vars.sysArgs : vars.sysArgs + 2] = 3, 5
 | 
						|
    # fmt: off
 | 
						|
    cycles = 9  # On entry to SYS, 9 cycles have already elapsed
 | 
						|
    cycles += Emulator.run_to("SYS_MultiplyBytes_120");                              assert 14 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes.tableEntry");                       assert 29 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes.high-byte-action.store-inverted");  assert 35 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes.tableExit");                        assert 40 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes#44");                               assert 43 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes.tableEntry");                       assert 51 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes.high-byte-action.restore-and-add"); assert 57 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes.tableExit");                        assert 64 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes#68");                               assert 67 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("NEXTY");                                              assert 90 == cycles        # noqa: E702, E241, E272
 | 
						|
    # fmt: on
 | 
						|
 | 
						|
 | 
						|
def test_timing_neither_lt_128():
 | 
						|
    """Follow the routine through, checking the timing comments
 | 
						|
 | 
						|
    This follows the case where neither value is less than 128
 | 
						|
    """
 | 
						|
    RAM[vars.sysArgs : vars.sysArgs + 2] = 172, 160
 | 
						|
    # fmt: off
 | 
						|
    cycles = 9  # On entry to SYS, 9 cycles have already elapsed
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes#68");  assert 67  == cycles        # noqa: E702, E241, E272, E221
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes#92");  assert 91  == cycles        # noqa: E702, E241, E272, E221
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes#114"); assert 113 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("NEXTY");                 assert 118 == cycles        # noqa: E702, E241, E272
 | 
						|
    # fmt: on
 | 
						|
 | 
						|
 | 
						|
def test_timing_one_lt_128():
 | 
						|
    """Follow the routine through, checking the timing comments
 | 
						|
 | 
						|
    This follows the case where one value is less than 128
 | 
						|
    """
 | 
						|
    RAM[vars.sysArgs : vars.sysArgs + 2] = 3, 160
 | 
						|
    # fmt: off
 | 
						|
    cycles = 9  # On entry to SYS, 9 cycles have already elapsed
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes#68");            assert 67 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes.oneMsbSetCase"); assert 85 == cycles        # noqa: E702, E241, E272
 | 
						|
    cycles += Emulator.run_to("sys_MultiplyBytes#92");            assert 91 == cycles        # noqa: E702, E241, E272
 | 
						|
    # fmt: on
 | 
						|
 | 
						|
 | 
						|
def _sign_extend(byte_):
 | 
						|
    if byte_ & 0x80:
 | 
						|
        return ~0xFF | byte_
 | 
						|
    return byte_
 | 
						|
 | 
						|
 | 
						|
_bytes = st.integers(min_value=0, max_value=255)
 | 
						|
 | 
						|
 | 
						|
@given(a=_bytes, b=_bytes)
 | 
						|
def test_multiply_bytes(a, b):
 | 
						|
    setup_function()
 | 
						|
    RAM[vars.sysArgs : vars.sysArgs + 2] = a, b
 | 
						|
 | 
						|
    cycles = 10  # Because Next is marked as zero
 | 
						|
    cycles += Emulator.run_to("NEXT")
 | 
						|
 | 
						|
    assert cycles <= MAX_CYCLES
 | 
						|
    assert cycles == _sign_extend(Emulator.AC) * -2
 | 
						|
    assert a * b == Emulator.vAC
 |