aboutsummaryrefslogtreecommitdiffstats
path: root/test/e2e
diff options
context:
space:
mode:
authorJan Tuomi <jan@jantuomi.fi>2024-04-11 18:23:08 +0100
committerJan Tuomi <jan@jantuomi.fi>2024-04-11 18:23:08 +0100
commit92de76627baf7c239a517316d85150149403f0c9 (patch)
treeea8d80e88584f5d383a4e11237d8e56c37c414e8 /test/e2e
parent3963742d5cc195bbbcc8081ec261b0d3e0c1d83d (diff)
Add perf test
Diffstat (limited to 'test/e2e')
-rw-r--r--test/e2e/emulation_speed/bootstrap.atk1678
-rw-r--r--test/e2e/emulation_speed/long_loop.atk1616
-rw-r--r--test/e2e/emulation_speed/test_emulation_speed.py43
-rw-r--r--test/e2e/fibo/test_fibo.py7
4 files changed, 137 insertions, 7 deletions
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