_reg_log.tcl 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. namespace eval reg_log {
  2. set_help_text reg_log \
  3. {Logs the contents (e.g. registers) of a given debuggable or replays such a log.
  4. The state of the debuggable is saved to a log file every VDP frame. Note that
  5. it does not take into account different VDP interrupt rates.
  6. Usage:
  7. reg_log record <debuggable> [<filename>] record <debuggable> to <filename>
  8. (default: <debuggable>.log)
  9. reg_log stop <debuggable> stop recording <debuggable>
  10. reg_log play <debuggable> <filename> replay log in <filename>
  11. Examples:
  12. reg_log record "PSG regs" start logging PSG registers to
  13. "PSG regs.log"
  14. reg_log record memory mem.log start logging memory to file mem.log
  15. reg_log stop "PSG regs" stop logging "PSG regs"
  16. reg_log play "PSG regs" my.log replay the log of "PSG regs" in my.log
  17. }
  18. set_tabcompletion_proc reg_log [namespace code tab_reg_log]
  19. proc tab_reg_log {args} {
  20. switch [llength $args] {
  21. 2 {return "record play stop"}
  22. 3 {return [debug list]}
  23. }
  24. }
  25. variable log_file
  26. variable data
  27. proc reg_log {subcommand debuggable {filename ""}} {
  28. if {$filename eq ""} {set filename ${debuggable}.log}
  29. switch $subcommand {
  30. "record" {return [record $debuggable $filename]}
  31. "play" {return [play $debuggable $filename]}
  32. "stop" {return [stop $debuggable]}
  33. default {error "bad option \"$subcommand\": must be record, play or stop"}
  34. }
  35. }
  36. proc check {debuggable} {
  37. if {$debuggable ni [debug list]} {
  38. error "No such debuggable: $debuggable"
  39. }
  40. }
  41. proc record {debuggable filename} {
  42. variable log_file
  43. check $debuggable
  44. stop $debuggable
  45. set log_file($debuggable) [open $filename {WRONLY TRUNC CREAT}]
  46. do_reg_record $debuggable
  47. return ""
  48. }
  49. proc play {debuggable filename} {
  50. variable data
  51. check $debuggable
  52. stop $debuggable
  53. set log_file [open $filename RDONLY]
  54. set data($debuggable) [split [read $log_file] \n]
  55. close $log_file
  56. do_reg_play $debuggable
  57. return ""
  58. }
  59. proc stop {debuggable} {
  60. variable log_file
  61. global file data
  62. if {[info exists log_file($debuggable)]} {
  63. close $log_file($debuggable)
  64. unset log_file($debuggable)
  65. }
  66. if {[info exists data($debuggable)]} {
  67. unset data($debuggable)
  68. }
  69. return ""
  70. }
  71. proc do_reg_record {debuggable} {
  72. variable log_file
  73. if {![info exists log_file($debuggable)]} return
  74. set size [debug size $debuggable]
  75. for {set i 0} {$i < $size} {incr i} {
  76. puts -nonewline $log_file($debuggable) "[debug read $debuggable $i] "
  77. }
  78. puts $log_file($debuggable) "" ;#newline
  79. after frame [list reg_log::do_reg_record $debuggable]
  80. }
  81. proc do_reg_play {debuggable} {
  82. variable data
  83. if {![info exists data($debuggable)]} return
  84. set reg 0
  85. foreach val [lindex $data($debuggable) 0] {
  86. debug write $debuggable $reg $val
  87. incr reg
  88. }
  89. set data($debuggable) [lrange $data($debuggable) 1 end]
  90. if {[llength $data($debuggable)] > 0} {
  91. after frame [list reg_log::do_reg_play $debuggable]
  92. }
  93. }
  94. namespace export reg_log
  95. } ;# namespace reg_log
  96. namespace import reg_log::*