From 92de76627baf7c239a517316d85150149403f0c9 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Thu, 11 Apr 2024 18:23:08 +0100 Subject: Add perf test --- test/e2e/emulation_speed/bootstrap.atk16 | 78 ++++++++++++++++++++++++ test/e2e/emulation_speed/long_loop.atk16 | 16 +++++ test/e2e/emulation_speed/test_emulation_speed.py | 43 +++++++++++++ test/e2e/fibo/test_fibo.py | 7 --- 4 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 test/e2e/emulation_speed/bootstrap.atk16 create mode 100644 test/e2e/emulation_speed/long_loop.atk16 create mode 100644 test/e2e/emulation_speed/test_emulation_speed.py (limited to 'test/e2e') diff --git a/test/e2e/emulation_speed/bootstrap.atk16 b/test/e2e/emulation_speed/bootstrap.atk16 new file mode 100644 index 0000000..9b024e6 --- /dev/null +++ b/test/e2e/emulation_speed/bootstrap.atk16 @@ -0,0 +1,78 @@ +@let SP RH + +; vector table fields +@let vector_table 0x10 +@let vt_ISR0 0x10 ; ISR0 +@let vt_ISR1 0x11 ; ISR1 +@let vt_ISR2 0x12 ; ISR2 +@let vt_ISR3 0x13 ; ISR3 +@let vt_stack_addr 0x14 ; Stack address +@let vt_term_pp_addr 0x15 ; Terminal peripheral address +@let vt_kb_pp_addr 0x16 ; Keyboard peripheral address +@let vt_gr_mode_addr 0x17 ; Graphics mode setting address +@let vt_sprite_mem 0x18 ; Sprite memory address +@let vt_text_mem 0x19 ; Text memory buffer address + +; memory segments +@let stack_segment 0x8000 +@let mmio_segment 0xE000 +@let terminal_addr 0xE000 +@let keyboard_addr 0xE001 +@let gr_mode_addr 0xE002 +@let sprite_mem 0xE800 +@let text_mem 0xF800 ; to 0xFFFF +; note: sprite memory & text memory can use the same space +; since they are never used at the same time + +; graphics mode settings +@let gr_disabled_mode 0b00 +@let gr_text_mode 0b01 +@let gr_sprite_mode 0b10 + +@address vector_table + keyboard_isr ; 0x10 + hlt_isr ; 0x11 + hlt_isr ; 0x12 + hlt_isr ; 0x13 + stack_segment ; 0x14 + terminal_addr ; 0x15 + keyboard_addr ; 0x16 + gr_mode_addr ; 0x17 + sprite_mem ; 0x18 + text_mem ; 0x19 + +@label hlt_isr + ldi 0x55 RE + hlt + +@label keyboard_isr + spu RA + spu RB + ldi vt_kb_pp_addr RA ; RA := Keyboard peripheral address pointer + ldr RA RA ; RA := Keyboard peripheral address deref + ldr RA RA ; RA := <16-bit keyboard character code> from MMIO register + ldi vt_term_pp_addr RB ; RB := Terminal peripheral address pointer + ldr RB RB ; RB := Terminal peripheral address deref + str RA RB ; terminal <- character code (ASCII?) + mov RA RE ; RE := character code (for debugging) + spo RB + spo RA + rti +@label program_segment + +; define short prelude that sets up vital instructions +; NOTE: must be shorter than the vector table offset +@address 0x0 +; set up stack pointer to point to beginning of stack segment + ldi vt_stack_addr RA + ldr RA SP + jpi program_segment + +@address program_segment +; set graphics mode to disabled + ldi vt_gr_mode_addr RA + ldr RA RA + ldi gr_disabled_mode RB + str RB RA +; jump to main (user defined) + jpi main diff --git a/test/e2e/emulation_speed/long_loop.atk16 b/test/e2e/emulation_speed/long_loop.atk16 new file mode 100644 index 0000000..2303311 --- /dev/null +++ b/test/e2e/emulation_speed/long_loop.atk16 @@ -0,0 +1,16 @@ +; bootstrap code (must be called to setup mandatory data) +; will jump to label main +@include bootstrap + +@label iters + 10000 + +@label main + ldi iters RA + ldr RA RA +@label loop + dec RA + bri zero done + jpi loop +@label done + hlt diff --git a/test/e2e/emulation_speed/test_emulation_speed.py b/test/e2e/emulation_speed/test_emulation_speed.py new file mode 100644 index 0000000..f2bcd22 --- /dev/null +++ b/test/e2e/emulation_speed/test_emulation_speed.py @@ -0,0 +1,43 @@ +import time +from atk16_asm import assemble +from atk16_emu import Machine +from test.utils import pad_bytearray + +def test_emulation_speed(): + filename = "test/e2e/emulation_speed/long_loop.atk16" + with open(filename, "r") as f: + source = f.read() + + obj = assemble(source, filename) + rom_image = pad_bytearray(obj.program) + + machine = Machine() + machine.load_rom_image(rom_image) + machine.reset() + start = time.perf_counter_ns() + machine.run_until_halted() + end = time.perf_counter_ns() + machine.print_state_summary() + + elapsed = end - start + print("Elapsed time:", elapsed, "ns") + steps_taken = machine.steps_taken + mean_ns_per_instr = elapsed / steps_taken + print("Instructions / second:", steps_taken / (elapsed / 1e9)) + print("ns / instruction:", mean_ns_per_instr) + + # VGA frequency is 25.175 MHz + # Divided by 16, that's 1.5734375 MHz (main clock) + # Instructions take 3–5 cycles, the average instruction takes around 4 cycles + # 1.5734375 MHz / 4 = 393359.375 Hz + # That is the goal instruction frequency + # TODO limit emulation speed to 393359.375 Hz ~= 2542 ns per instruction + # this is in order to have similar speed as the actual machine + + expected = 2542 + allowed_range = 0.05 # 0..1 + expected_min = expected * (1 - allowed_range) + expected_max = expected * (1 + allowed_range) + percentage = 100 * mean_ns_per_instr / expected + assert expected_min < mean_ns_per_instr, f"Emulator seems to run too fast ({percentage:.2f}% of expected ns per instruction)" + assert mean_ns_per_instr < expected_max, f"Emulator seems to run too slow ({percentage:.2f}% of expected ns per instruction)" diff --git a/test/e2e/fibo/test_fibo.py b/test/e2e/fibo/test_fibo.py index 65af07a..664e701 100644 --- a/test/e2e/fibo/test_fibo.py +++ b/test/e2e/fibo/test_fibo.py @@ -22,13 +22,6 @@ def test_fibo(): elapsed = end - start print("Elapsed time:", elapsed, "ns") steps_taken = machine.steps_taken - - # VGA frequency is 25.175 MHz - # Divided by 16, that's 1.5734375 MHz (main clock) - # Instructions take 3–5 cycles, the average instruction takes around 4 cycles - # 1.5734375 MHz / 4 = 393359.375 Hz - # That is the goal instruction frequency - # TODO limit emulation speed to 393359.375 Hz print("Instructions / second:", steps_taken / (elapsed / 1e9)) assert machine.ra.value == 41443 -- cgit v1.3