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
def test_read_initial_state(): # The following are not necessary, but it was very helpful in debugging Emulator.run_to(0x2FF, max_instructions=10_000_000) # Entry of vCPU Emulator.run_vcpu_to(0x200) # Pass through loading sequence buffer = bytearray() for _ in range(5): value = Emulator.read_serial(bits=8) buffer.append(value) assert buffer == b"READY"
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 test_MulShift8(a, b): _prepare_for_vcpu_execution_at(execution_address) Emulator.run_vcpu_to( 0x300) # Run the first page, so the variable is defined _write_word(vars.sysFn, asm.symbol("SYS_MultiplyBytes_120"), signed=False) _write_word(symbol_table["A"], a, signed=True) _write_word(symbol_table["B"], b, signed=True) _call_vcpu_function("MulShift8") assert int(a * b / 256) == _read_word(vars.vAC, signed=True)
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
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
def test_multiplication_8(a, b): """Multiplication of two eight-bit integers should work""" Emulator.reset() RAM[vars.a] = a RAM[vars.b] = b Emulator.next_instruction = "multiply 8x8" expected_saving = (vars.no_msb_cost_saving if a < 128 and b < 128 else vars.one_msb_cost_saving if a < 128 or b < 128 else 0) cycles = Emulator.run_to("done") result = int.from_bytes(RAM[vars.result:vars.result + 2], "little", signed=False) assert a * b == result assert vars.cost_of_8bit_multiply - expected_saving == cycles
def test_low_byte_lookup(value): """Lookup of the low-byte of a quarter square should work""" Emulator.Y = asm.symbol("Quarter-squares lookup table") >> 8 Emulator.AC = value Emulator.next_instruction = "low-byte table entry" cycles = Emulator.run_to("low-byte return point") assert int(math.floor((value**2) / 4)) & 0xFF == Emulator.AC assert vars.cost_of_low_byte_table_entry == cycles
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
def setup_module(): global vars, symbol_table, execution_address """Load the Emulator from the ROM script and Mandelbrot """ 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) # This sequence of calls is roughly taken from compilegcl.py old_rom_size = asm._romSize program = gcl.Program("Mandelbrot", forRom=False) user_code = asm.symbol("userCode") user_vars = asm.symbol("userVars") program.org(user_code) asm.align(1) asm.zpReset(user_vars) with GCL.open("r", encoding="utf-8") as fp: for line in fp.readlines(): program.line(line) program.end() asm.end() # Copy the resulting data straight into RAM, in the appropriate blocks data = asm.getRom1()[old_rom_size:] index, more_data = 0, bool(data) while more_data: start_address = int.from_bytes(data[index:index + 2], "big", signed=False) index += 2 size = data[index] or 256 index += 1 chunk = data[index:index + size] index += size RAM[start_address:start_address + len(chunk)] = chunk more_data = data[index] execution_address = program.execute symbol_table = program.vars
def test_high_byte_lookup(value): """Lookup of the high-byte of a quarter square should work""" RAM[vars.high_byte_action] = asm.symbol("high-byte action.store") Emulator.AC = value Emulator.Y = asm.symbol("Quarter-squares lookup table") >> 8 Emulator.next_instruction = "table entry" cycles = Emulator.run_to("high-byte action.store") assert int(math.floor((value**2) / 4)) >> 8 == Emulator.AC assert vars.cost_of_high_byte_table_entry == cycles
def test_multiplication_7(a, b): """Multiplication of two seven-bit integers should work""" RAM[vars.a] = a RAM[vars.b] = b Emulator.next_instruction = "multiply 7x7" cycles = Emulator.run_to("done") result = int.from_bytes(RAM[vars.result:vars.result + 2], "little", signed=False) assert a * b == result assert vars.cost_of_7bit_multiply == cycles
def test_subtract_quarter_square(a, b, previous_value): """to done should subtract the""" RAM[vars.a] = a RAM[vars.b] = b RAM[vars.result:vars.result + 2] = (previous_value + 1).to_bytes( 2, "little", signed=False) Emulator.Y = asm.symbol("Quarter-squares lookup table") >> 8 Emulator.next_instruction = asm.symbol(".after-first-lookup") + 2 expected = (previous_value - math.floor((a - b)**2 / 4)) & 0xFFFF cycles = Emulator.run_to(asm.symbol("done")) assert expected == int.from_bytes(RAM[vars.result:vars.result + 2], "little", signed=False) assert asm.symbol("Quarter-squares lookup table") >> 8 == Emulator.Y assert vars.cost_of_7bit_multiply - vars.cost_after_first_lookup - 2 == cycles
def test_both_byte_lookup(a, b): """Lookup of both bytes of a quarter square should work The multiplication routine actually adds 1 to the result, so storing it, so check for that. """ RAM[vars.a] = a RAM[vars.b] = b Emulator.next_instruction = "multiply 7x7" expected = int(math.floor(((a + b)**2) / 4)) + 1 cycles = Emulator.run_to(asm.symbol(".after-first-lookup") + 2) assert expected == int.from_bytes(RAM[vars.result:vars.result + 2], "little", signed=False) assert cycles == vars.cost_after_first_lookup + 2 assert asm.symbol("Quarter-squares lookup table") >> 8 == Emulator.Y
def emulator(): emulator = Emulator() emulator.zero_memory() yield emulator print(emulator.state)
def setup_module(): Emulator.load_rom_file(_ROM_FILE)
def test_write(): assert _read_bytes(5) == b"READY" for b in b"Hello": Emulator.send_byte(b) assert _read_bytes(5) == b"Hello"
def _read_bytes(n): buffer = bytearray() for _ in range(n): buffer.append(Emulator.read_serial(bits=8)) return bytes(buffer)
def setup_function(): Emulator.reset()
def _call_vcpu_function(variable): return_point = Emulator.vPC & 0xFF00 | (Emulator.vPC + 2) & 0xFF Emulator.AC = symbol_table[variable] Emulator.next_instruction = "CALL" Emulator.step_vcpu() # Execute CALL Emulator.run_vcpu_to(return_point)