tcl/tools: Add function to measure the speed of ARM Cortex-M devices
[fw/openocd] / tcl / tools / test_cpu_speed.tcl
1 # SPDX-License-Identifier: GPL-2.0-or-later
2
3 # Description:
4 #  Measure the CPU clock frequency of an ARM Cortex-M based device.
5 #
6 # Return:
7 #  The CPU clock frequency in Hz. A negative value indicates that the loop
8 #  counter was saturated.
9 #
10 # Note:
11 #  You may need to adapt the number of cycles for your device.
12 #
13 add_help_text cortex_m_test_cpu_speed "Measure the CPU clock frequency of an ARM Cortex-M based device"
14 add_usage_text cortex_m_test_cpu_speed {address [timeout [cycles_per_loop]]}
15 proc cortex_m_test_cpu_speed { address { timeout 200 } { cycles_per_loop 4 } } {
16         set loop_counter_start 0xffffffff
17
18         halt
19
20         # Backup registers and memory.
21         set backup_regs [get_reg -force {pc r0 xPSR}]
22         set backup_mem [read_memory $address 16 3]
23
24         # We place the following code at the given address to measure the
25         # CPU clock frequency:
26         #
27         # 3801: subs r0, #1
28         # d1fd: bne #-2
29         # e7fe: b #-4
30         write_memory $address 16 {0x3801 0xd1fd 0xe7fe}
31
32         set_reg "pc $address r0 $loop_counter_start"
33         resume
34         sleep $timeout
35         halt
36
37         # Get the loop counter value from register r0.
38         set loop_counter_end [dict values [get_reg r0]]
39         set loop_counter_diff [expr {$loop_counter_start - $loop_counter_end}]
40
41         # Restore registers and memory.
42         set_reg $backup_regs
43         write_memory $address 16 $backup_mem
44
45         if { [expr {$loop_counter_end == 0}] } {
46                 return -1
47         }
48
49         return [expr {double($loop_counter_diff) * $cycles_per_loop / $timeout * 1000}]
50 }