_vdp_access_test.tcl 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. namespace eval vdp_access_test {
  2. # you can tweak these to test for other stuff
  3. # TODO: make this flexible so the timing can be specified for each combination
  4. # of ports and read/write
  5. variable ioports {0x98 0x99}
  6. variable cycle_max 29
  7. # if you set this to true, you can also see OK I/O, but there are many of those!
  8. variable debug false
  9. # if you set this to true, openMSX will break when too fast access happens, so
  10. # you can investigate what's going on with the debug commands (or debugger)
  11. variable enable_break false
  12. variable last_access_time 0
  13. variable last_access_type
  14. variable last_access_port
  15. variable is_enabled false
  16. variable watchpoint_write_id
  17. variable watchpoint_read_id
  18. variable address_list
  19. set_help_text toggle_vdp_access_test \
  20. "Report in the console when VDP I/O is done which could possibly cause data
  21. corruption on the slowest VDP (TMS99xx), i.e. when time between successive I/O
  22. was less than $cycle_max cycles and display was active. Note: this script is
  23. not 100% accurate! Keep testing on a real MSX as well. The script has some
  24. tuning options; edit the script to do so, it's explained at the top what can be
  25. tuned."
  26. proc check_time {access_type} {
  27. variable last_access_time
  28. variable last_access_type
  29. variable last_access_port
  30. variable cycle_max
  31. variable debug
  32. variable enable_break
  33. variable address_list
  34. set port [expr {$::wp_last_address & 255}]
  35. set current_time [machine_info time]
  36. set cycles [expr {round(3579545 * ($current_time - $last_access_time))}]
  37. set screen_enabled [expr {[debug read "VDP regs" 1] & 64}]
  38. set vblank [expr {[debug read "VDP status regs" 2] & 64}]
  39. set pc [format "%04x" [reg PC]]
  40. if {($cycles < $cycle_max) && $screen_enabled && !$vblank} {
  41. if {$pc ni $address_list} {
  42. set valuetext ""
  43. if {$access_type eq "write"} {
  44. set valuetext [format " (value 0x%02X)" $::wp_last_value]
  45. }
  46. puts [format "VDP $last_access_type on port 0x%02X followed by a $access_type${valuetext} on port 0x%02X on address $pc and time $current_time with too few cycles in between: $cycles (< $cycle_max)" $last_access_port $port]
  47. lappend address_list $pc
  48. set address_list [lsort $address_list]
  49. puts "Sorted list of addresses where too fast I/O is done: $address_list"
  50. if {$enable_break} {
  51. debug break
  52. }
  53. }
  54. } else {
  55. if {$debug} {
  56. if {!$screen_enabled} {
  57. set reason "screen is disabled"
  58. } elseif {$vblank} {
  59. set reason "in vblank"
  60. } else {
  61. set reason "last access was $cycles cycles ago, >= $cycle_max"
  62. }
  63. puts [format "VDP I/O $access_type to port 0x%02X OK on address: 0x$pc, $reason" $port]
  64. }
  65. }
  66. set last_access_time $current_time
  67. set last_access_port $port
  68. set last_access_type $access_type
  69. }
  70. proc toggle_vdp_access_test {} {
  71. variable is_enabled
  72. variable watchpoint_write_id
  73. variable watchpoint_read_id
  74. variable address_list
  75. variable ioports
  76. if {!$is_enabled} {
  77. set watchpoint_write_id [debug set_watchpoint write_io $ioports {} {vdp_access_test::check_time "write"}]
  78. set watchpoint_read_id [debug set_watchpoint read_io $ioports {} {vdp_access_test::check_time "read"}]
  79. set is_enabled true
  80. set address_list [list]
  81. } else {
  82. debug remove_watchpoint $watchpoint_write_id
  83. debug remove_watchpoint $watchpoint_read_id
  84. set is_enabled false
  85. }
  86. }
  87. namespace export toggle_vdp_access_test
  88. } ;# namespace vdp_access_test
  89. namespace import vdp_access_test::*