home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / forth / compiler / fpc / source / tdebug.seq < prev    next >
Text File  |  1990-04-24  |  19KB  |  516 lines

  1. \\ CODEBUG.SEQ          A CODE debugger for F-PC        by Tom Zimmer
  2.  
  3.   This file contains a simple debugger for F-PC to allow debugging
  4. CODE routines. Don't expect TOO MUCH from this debugger, it is still
  5. in quite primitive form. It is useful though.
  6.  
  7.   The debugger can be invoked directly by:
  8.  
  9.         TRACE <forth_name> <enter>
  10.  
  11.   Each subsequent enter key press causes the debugger to step one
  12. instruction through <forth_name>. Limited operations are supported while
  13. in the debugger, read the screen while debugging and press F1 for some help.
  14.  
  15.   To set a break point that will invoke the debugger when a particular
  16. word is executed, use:
  17.  
  18.         BREAKAT <forth_name> <enter>
  19.  
  20.   The first time this word is executed, the code debugger will be started.
  21. If your break point is not ever executed, you should execute UNBREAK
  22. before leaving F-PC to remove the break point from memory.
  23.  
  24.  ***************************************************************************
  25.  
  26.   To make a debugger for CODE, we needed to make an interrupt handler for
  27. INT 1, and then enable the single step status flag bit TF.
  28.  
  29. {
  30.  
  31. \ **************************************************************************
  32. \ variables to hold all needed registers
  33. \ **************************************************************************
  34.  
  35. variable debugip
  36. variable debugcs
  37. variable debugflags
  38. variable debugax
  39. variable debugbx        variable forthbx
  40. variable debugcx
  41. variable debugdx
  42. variable debugbp        variable forthbp
  43. variable debugsi        variable forthsi
  44. variable debugdi        variable forthdi
  45. variable debuges        variable forthes
  46. variable debugss        variable forthss
  47. variable debugsp        variable forthsp
  48. variable debugds        variable forthds
  49.  
  50. \ **************************************************************************
  51. \ words to allow setting the debugging registers
  52. \ **************************************************************************
  53.  
  54. :: reg!         ( a1 | <name> -- )      \ defining word to make register
  55.                                         \ assignment words
  56.                 create , does> @ ! ;
  57.  
  58. debugcs    reg! =cs
  59. debugip    reg! =ip
  60. debugss    reg! =ss
  61. debugsp    reg! =sp
  62. debugds    reg! =ds
  63. debuges    reg! =es
  64. debugax    reg! =ax
  65. debugbx    reg! =bx
  66. debugcx    reg! =cx
  67. debugdx    reg! =dx
  68. debugsi    reg! =si
  69. debugdi    reg! =di
  70. debugbp    reg! =bp
  71. debugflags reg! =fl
  72.  
  73. :: reg@         ( a1 | <name> -- )      \ defining word to make register
  74.                                         \ fetch words
  75.                 create , does> @ @ ;
  76.  
  77. debugcs reg@ cs-@
  78. debugip reg@ ip-@
  79. debugss reg@ ss-@
  80. debugsp reg@ sp-@
  81. debugds reg@ ds-@
  82. debuges reg@ es-@
  83. debugax reg@ ax-@
  84. debugbx reg@ bx-@
  85. debugcx reg@ cx-@
  86. debugdx reg@ dx-@
  87. debugsi reg@ si-@
  88. debugdi reg@ di-@
  89. debugbp reg@ bp-@
  90.  
  91. \ **************************************************************************
  92. \ Some handy debugging utilities
  93. \ **************************************************************************
  94.  
  95. 2               constant dbtop
  96. rows 6 -        constant dbbot
  97. 0               value    dboff
  98. 0               value    dbto
  99. 0               value    dobreak
  100. 0               value    dbsave
  101. 0               value    keysave
  102. 0               value    spsave
  103.  
  104. : h.4           ( n1 -- )       \ display n1 in four digit hex
  105.                 $10 save!> base
  106.                 0 <# # # # # #> space type space
  107.                 restore> base ;
  108.  
  109. : sp>col        ( n1 -- )
  110.                 #out @ - 0max spaces ;
  111.  
  112. : dbeeol        ( -- )
  113.                 58 sp>col ;
  114.  
  115. : ?.cfa         ( a1 -- )
  116.                 ?symbol if type then ;
  117.  
  118. : debug_depth   ( -- n1 )
  119.                 si-@ sp0 @ swap - 2/ 1- ;
  120.  
  121. : %debug.s      ( .. n1 -- )
  122.                 dup ."  [" 1 .r ." ]" 0 swap 8 min 1-
  123.                 do      sp@ si-@ swap - 2/ i + pick
  124.                         7 u.r space
  125.             -1 +loop    ;
  126.  
  127. : debug.s       ( -- )
  128.                 savecursor cursor-off
  129.                 0 dbtop cols 1- dbtop 2+ box
  130.                 debug_depth 0<
  131.                 if      ."   Data Stack INVALID !! "
  132.                         cols 2- sp>col >norm
  133.                 else    debug_depth ?dup
  134.                         if      %debug.s
  135.                         else    ."  Stack Empty. "
  136.                         then    cols 1- sp>col
  137.                 then    restcursor ;
  138.  
  139. : .dbheader     ( -- )
  140.                 0 dbtop 2- at
  141.                 ."  Enter or Space  = single step instruction
  142.                 ."  ESC  = Quit debugging  F1  = Help "
  143.                 cr
  144.                 ."  Use  to select line to (G)o to. "
  145.                 ."  Press (R) to change registers. " ;
  146.  
  147. : .dbfooter     ( -- )
  148.                 0 dbbot 1+ at
  149.                 ."  Debugger terminated, type `STEPS` to restart. "
  150.                 cols sp>col >norm cr ;
  151.  
  152. \ **************************************************************************
  153. \ Display current instruction followed by data stack
  154. \ **************************************************************************
  155.  
  156. 0 value ipprev
  157. 0 value ipprev2
  158.  
  159. : .instruction  ( -- )          \ display one instruction
  160.                 save> base hex
  161.                 ip-@ ?.cfa 8 sp>col ."  >> "
  162.                 cs-@ =seg
  163.                 ip-@ dup cp ! =: ipprev
  164.                 inst dbeeol
  165.                 restore> base ;
  166.  
  167. : .ninst        ( n1 -- )
  168.                 save> base hex
  169.                 cp @ ?.cfa 8 sp>col
  170.                 1+ dboff =
  171.                 if      cp @ =: dbto
  172.                         ."  ** "
  173.                 else    ."     "
  174.                 then
  175.                 inst dbeeol
  176.                 restore> base ;
  177.  
  178. : .pinst        ( -- )
  179.                 ipprev 0=
  180.                 if      dbeeol exit
  181.                 then
  182.                 save> base hex
  183.                 cs-@ =seg
  184.                 ipprev dup cp ! =: ipprev2
  185.                 cp @ ?.cfa 12 sp>col
  186.                 inst dbeeol
  187.                 restore> base ;
  188.  
  189. \ **************************************************************************
  190. \ Display the processor registers
  191. \ **************************************************************************
  192.  
  193. : .regs         ( -- )
  194.                 key? ?exit
  195.                 savecursor cursor-off
  196.                 60 dbtop 3 + 79 dbtop 17 + box
  197.                 ."   Tom's Debugger " bcr 17 spaces bcr
  198.                 ."  CS" cs-@ h.4 ."  IP" ip-@ h.4   bcr
  199.                 ."  DS" ds-@ h.4 ."  SI" si-@ h.4   bcr
  200.                 ."  ES" es-@ h.4 ."  DI" di-@ h.4   bcr
  201.                 ."  SS" ss-@ h.4 ."  SP" sp-@ h.4   bcr
  202.                         ."           BP" bp-@ h.4   bcr
  203.                 ."  AX" ax-@ h.4 09 SPACES          bcr
  204.                 ."  BX" bx-@ h.4 ."  FL" debugflags @ h.4
  205.                                                     bcr
  206.                 ."  CX" cx-@ h.4 09 SPACES          bcr
  207.                 ."  DX" dx-@ h.4 09 SPACES          bcr
  208.                 ."  ----ODITsz-a-p-c"               bcr
  209.                 2 save!> base
  210.                 space
  211.                 debugflags @ 0 <# 16 0 do # loop #> type
  212.                 restore> base
  213.                 restcursor ;
  214.  
  215. \ **************************************************************************
  216. \ This is the single step "receiver". It saves the debugging registers
  217. \ and restores F-PC's registers then goes back to Forth.
  218. \ **************************************************************************
  219.  
  220. label int1      ( -- )          \ preserve all registers
  221.                 push ds
  222.                 push ax
  223.                 mov ax, cs: $00FE       \ we hide DS value here at startup
  224.                 mov ds, ax
  225.                 pop debugax
  226.                 pop debugds
  227.                 pop debugip
  228.                 pop debugcs
  229.                 pop ax
  230.                 and ax, # $FEFF         \ clear TF flag bit
  231.                 mov debugflags ax
  232.                 mov debugbx bx  mov bx, forthbx
  233.                 mov debugcx cx
  234.                 mov debugdx dx
  235.                 mov debugbp bp  mov bp, forthbp
  236.                 mov debugsi si  mov si, forthsi
  237.                 mov debugdi di  mov di, forthdi
  238.                 mov debuges es  mov es, forthes
  239.                 mov debugss ss  mov ss, forthss
  240.                 mov debugsp sp  mov sp, forthsp
  241.                 ret     end-code
  242.  
  243. \ **************************************************************************
  244. \ Routines to save, set & restore the number one & three interrupt vectors.
  245. \ **************************************************************************
  246.  
  247. 2variable int1save               \ a place to save the interrupt one vector
  248.  
  249. code save_int#  ( n1 --- )      \ save the current contents of interrupt one
  250.                 push es
  251.                 mov ax, # $3500
  252.                 or al, bl
  253.                 int $21
  254.                 mov int1save bx
  255.                 mov int1save 2+ es       \ save old vector
  256.                 pop es
  257.                 ret     end-code
  258.  
  259. code set_int#   ( n1 --- )      \ set interrupt one to our interrupt handler
  260.                 push es
  261.                 push ds
  262.                 mov ax, cs
  263.                 mov ds, ax
  264.                 mov dx, # int1
  265.                 mov ax, # $2500
  266.                 or al, bl
  267.                 int $21
  268.                 pop ds
  269.                 pop es
  270.                 ret     end-code
  271.  
  272. code rest_int#  ( n1 --- )      \ restore the contents of interrupt one
  273.                 push ds
  274.                 mov dx, int1save
  275.                 mov ds, int1save 2+
  276.                 mov ax, # $2500
  277.                 or al, bl
  278.                 int $21
  279.                 pop ds
  280.                 ret     end-code
  281.  
  282. \ **************************************************************************
  283. \ initiate one single instruction step. Swaps registers, sets up the
  284. \ hardware stack with processor status, code segment, and instruction
  285. \ pointer then does an IRET to return to do a single step. The TF flag
  286. \ is set in the status register to make the processor immediately perform
  287. \ an INT1 after a single instruction has been executed. Execution then
  288. \ returns to INT1 above, and consequently back to Forth.
  289. \ **************************************************************************
  290.  
  291. code one_step   ( -- )          \ single step through one instruction as
  292.                                 \ already setup in the debugging recisters
  293.                 mov forthsp sp
  294.                 mov forthss ss
  295.                 mov forthbp bp
  296.                 mov forthbx bx
  297.                 mov forthsi si
  298.                 mov forthdi di
  299.                 mov forthds ds
  300.                 mov forthes es
  301.                 cmp debugsp # 0         \ give a default if needed.
  302.              0= if      mov debugsp sp
  303.                         mov debugss ss
  304.                         mov debugds ds
  305.                         mov debugcs cs
  306.                         pushf
  307.                         pop ax
  308.                         and ax, # $FEFF         \ clear TF flag bit
  309.                         mov debugflags ax
  310.                 then
  311.                 mov bx, debugbx
  312.                 mov cx, debugcx
  313.                 mov dx, debugdx
  314.                 mov bp, debugbp
  315.                 mov si, debugsi
  316.                 mov di, debugdi
  317.                 mov ss, debugss
  318.                 mov es, debuges
  319.                 mov sp, debugsp
  320.                 mov ax, debugflags
  321.                 or ax, # $100           \ set TF bit in flags
  322.                 push ax
  323.                 push debugcs
  324.                 push debugip
  325.                 mov ax, debugax
  326.                 mov ds, debugds
  327.                 iret            end-code
  328.  
  329. code one_break  ( -- )          \ go till the breakpoint we just installed
  330.                 mov forthsp sp
  331.                 mov forthss ss
  332.                 mov forthbp bp
  333.                 mov forthbx bx
  334.                 mov forthsi si
  335.                 mov forthdi di
  336.                 mov forthds ds
  337.                 mov forthes es
  338.                 mov bx, debugbx
  339.                 mov cx, debugcx
  340.                 mov dx, debugdx
  341.                 mov bp, debugbp
  342.                 mov si, debugsi
  343.                 mov di, debugdi
  344.                 mov ss, debugss
  345.                 mov es, debuges
  346.                 mov sp, debugsp
  347.                 mov ax, debugflags
  348.                 and ax, # $FEFF         \ CLEAR TF bit in flags
  349.                 push ax
  350.                 push debugcs
  351.                 push debugip
  352.                 mov ax, debugax
  353.                 mov ds, debugds
  354.                 iret            end-code
  355.  
  356. \ **************************************************************************
  357. \ Set the single step interrupt, perform a single instruction step, and
  358. \ then restore the single step interrupt.
  359. \ **************************************************************************
  360.  
  361. : single_step   ( -- )                  \ perform one instruction step, and
  362.                                         \ display registers with next
  363.                                         \ instruction to be traced.
  364.                 1 save_int#             \ save existing interrupt vector
  365.                 1 set_int#              \ set to out interrupt routine
  366.                 one_step                \ do a single step trace of one inst
  367.                 1 rest_int#             \ restore the interrupt vector
  368.                 ;
  369.  
  370. : unbreak       ( -- )                  \ remove the break point
  371.                 dbto
  372.                 if      3 rest_int#
  373.                         dbsave ?cs: dbto c!L    \ restore program byte
  374.                 then    ;
  375.  
  376. : break_point   ( -- )                  \ break point to offset specified
  377.                 dbto 0=
  378.                 if      one_break exit  \ just continue execution
  379.                 then
  380.                 ?cs: dbto c@L =: dbsave
  381.                 dboff
  382.                 if      $CC ?cs: dbto c!L \ only break if not zero
  383.                 then
  384.                 3 save_int#
  385.                 3 set_int#
  386.                 one_break
  387.                 3 rest_int#
  388.                 dbsave ?cs: dbto c!L    \ restore program byte
  389.                 ip-@ 1- =ip             \ backup IP one byte
  390.                 off> dbto
  391.                 off> dboff ;            \ reset break point offset
  392.  
  393. \ **************************************************************************
  394. \ show the current registers, and a series of instructions as they will
  395. \ be executed.
  396. \ **************************************************************************
  397.  
  398. 0 value tbline
  399.  
  400. : show_debug_init ( -- )
  401.                 savecursor cursor-off
  402.                 .dbheader
  403.                 0 dbtop 3 + 59 dbbot box
  404.                 ."  Name      Addr   Instruction                  Data      "
  405.                 bline =: tbline
  406.                 restcursor
  407.                 0 20 at ;
  408.  
  409. : show_debug    ( -- )
  410.                 savecursor cursor-off
  411.                 .regs
  412.                 debug.s
  413.                 tbline =: bline
  414.                 bcr .pinst bcr .instruction bcr
  415.                 dbbot dbtop 4 + - 3 - 0
  416.                 do      i .ninst bcr
  417.                         key? ?leave
  418.                 loop    restcursor ;
  419.  
  420. : up_dbline     ( -- )
  421.                 ipprev2 =: ipprev
  422. ( up arrow )    dboff 1- 0max =: dboff ;
  423.  
  424. : down_dbline   ( -- )
  425.                 ipprev2 =: ipprev
  426. ( down arrow )  incr> dboff ;
  427.  
  428. \ **************************************************************************
  429. \ Additional MINI help for the debugger.
  430. \ **************************************************************************
  431.  
  432. : show_help     ( -- )
  433.                 ipprev2 =: ipprev
  434.                 savecursor cursor-off savescr
  435.                 0 5 59 19 box&fill
  436.         bcr ."   Debugger commands:"
  437.         bcr
  438.         bcr ."      SPACE  = Do a single instruction step."
  439.         bcr ."      ESC    = Done, terminate the debugger."
  440.         bcr ."      G      = Go-till '**' line, or just continue program"
  441.         bcr ."               execution if no Go-till line marked."
  442.         bcr
  443.         bcr ."        Press ANY key to continue debugging "
  444.                 key drop
  445.                 restscr restcursor show_debug_init ;
  446.  
  447. \ **************************************************************************
  448. \ the main trace loop, walks through instructions until the ESC key is
  449. \ pressed.
  450. \ **************************************************************************
  451.  
  452. : do_dbkey      ( c1 -- f1 )
  453.                 case
  454. ( terminate )   $1B of                          true    endof
  455. ( enter )       $0D of  single_step             false   endof
  456. ( space )       $20 of  single_step             false   endof
  457. ( up arrow )    $C8 of  up_dbline               false   endof
  458. ( down arrow )  $D0 of  down_dbline             false   endof
  459. ( help )        $BB of  show_help               false   endof
  460.                 upc                 \ remaining tests are case insensitive
  461. ( Go )          'G' of  break_point             false   endof
  462.                         ipprev2 =: ipprev
  463. ( all others )          drop beep               false
  464.                 endcase ;
  465.  
  466. : steps         ( -- )
  467.                 rp@      =sp
  468.                 rp@ 80 - rp!            \ move return stack out of the way
  469.                 =bx                     \ top of stack to debug BX
  470.                 sp@      =si            \ set debugger to Forth stack
  471.                 sp@ 20 - sp!
  472.                 dobreak 0=
  473.                 if      show_debug_init
  474.                 then
  475.                 begin   dobreak 0=
  476.                         if      show_debug
  477.                                 key do_dbkey
  478.                         else    dobreak =: dbto
  479.                                 off> dobreak
  480.                                 break_point
  481.                                 show_debug_init
  482.                                 false
  483.                         then
  484.                 until   .dbfooter abort ;
  485.  
  486.  
  487. \ **************************************************************************
  488. \ setup for tracing a series of instructions, and call STEPS.
  489. \ **************************************************************************
  490.  
  491. : %trace        ( a1 -- )
  492.                 ?dup 0= ?exit
  493.                 ?ds: ?cs: $00FE !L      \ a place to get the DS value later
  494.                 dup =ip =ax
  495.                 ?cs: dup =cs =es
  496.                 ?ds: dup =ds =ss
  497.                 off> ipprev
  498.                 steps ;
  499.  
  500. : $trace        ( a1 -- )               \ use as in: TRACE <word> <enter>
  501.                                         \ sets up and displays first
  502.                                         \ instruction with registers.
  503.                 off> dboff
  504.                 %trace ;
  505.  
  506. 0 value interp
  507.  
  508. : $breakat      ( a1 -- )
  509.                 =: dobreak
  510.                 1 =: dboff
  511.                 interp %trace ;         \ set the breakpoint and interpret
  512.                                         \ the rest of the line.
  513.  
  514. }
  515.  
  516.