home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / forth / compiler / fpc / source / codebug.seq < prev    next >
Text File  |  1990-03-07  |  26KB  |  697 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. \ Load the disassembler, we need it in the debugger
  33. \ **************************************************************************
  34.  
  35. fload dis8086
  36.  
  37. ( dis8086 ) symbolic off
  38.  
  39. \ **************************************************************************
  40. \ variables to hold all needed registers
  41. \ **************************************************************************
  42.  
  43. variable debugip
  44. variable debugcs
  45. variable debugflags
  46. variable debugax
  47. variable debugbx
  48. variable debugcx
  49. variable debugdx
  50. variable debugbp        variable forthbp
  51. variable debugsi        variable forthsi
  52. variable debugdi        variable forthdi
  53. variable debuges        variable forthes
  54. variable debugss        variable forthss
  55. variable debugsp        variable forthsp
  56. variable debugds        variable forthds
  57.  
  58. \ **************************************************************************
  59. \ words to allow setting the debugging registers
  60. \ **************************************************************************
  61.  
  62. : reg!          ( a1 | <name> -- )      \ defining word to make register
  63.                                         \ assignment words
  64.                 create , does> @ ! ;
  65.  
  66. debugcs    reg! =cs
  67. debugip    reg! =ip
  68. debugss    reg! =ss
  69. debugsp    reg! =sp
  70. debugds    reg! =ds
  71. debuges    reg! =es
  72. debugax    reg! =ax
  73. debugbx    reg! =bx
  74. debugcx    reg! =cx
  75. debugdx    reg! =dx
  76. debugsi    reg! =si
  77. debugdi    reg! =di
  78. debugbp    reg! =bp
  79. debugflags reg! =fl
  80.  
  81. : reg@          ( a1 | <name> -- )      \ defining word to make register
  82.                                         \ fetch words
  83.                 create , does> @ @ ;
  84.  
  85. debugcs reg@ cs-@
  86. debugip reg@ ip-@
  87. debugss reg@ ss-@
  88. debugsp reg@ sp-@
  89. debugds reg@ ds-@
  90. debuges reg@ es-@
  91. debugax reg@ ax-@
  92. debugbx reg@ bx-@
  93. debugcx reg@ cx-@
  94. debugdx reg@ dx-@
  95. debugsi reg@ si-@
  96. debugdi reg@ di-@
  97. debugbp reg@ bp-@
  98.  
  99. 2variable break_save
  100.           break_save off
  101.  
  102. \ **************************************************************************
  103. \ Some handy debugging utilities
  104. \ **************************************************************************
  105.  
  106. 2               constant dbtop
  107. rows 6 -        constant dbbot
  108. 0               value    dboff
  109. 0               value    dbto
  110. 0               value    dbsave
  111. 0               value    keysave
  112. 0               value    spsave
  113.  
  114. : h.4           ( n1 -- )       \ display n1 in four digit hex
  115.                 $10 save!> base
  116.                 0 <# # # # # #> space type space
  117.                 restore> base ;
  118.  
  119. ' no-name >name constant [no-name]
  120.  
  121. : sp>col        ( n1 -- )
  122.                 #out @ - 0max spaces ;
  123.  
  124. : dbeeol        ( -- )
  125.                 58 sp>col ;
  126.  
  127. : ?.cfa         ( a1 -- )
  128.                 >name dup [no-name] <>
  129.                 if      dup .id
  130.                 then    drop ;
  131.  
  132. : debug_depth   ( -- n1 )
  133.                 sp-@ sp0 @ swap - 2/  ;
  134.  
  135. : debug.s       ( -- )
  136.                 savecursor cursor-off
  137.                 0 dbtop cols 1- dbtop 2+ box
  138.                 debug_depth 0<
  139.                 if      ."  \2 Data Stack INVALID !! "
  140.                         >attrib2 cols 2- sp>col >norm
  141.                 else    debug_depth ?dup
  142.                         if      dup ."  [" 1 .r ." ]" 0 swap 8 min 1-
  143.                                 do      sp@ sp-@ swap - 2/ i + pick
  144.                                         7 u.r space
  145.                             -1 +loop
  146.                         else    ."  Stack Empty. "
  147.                         then    cols 1- sp>col
  148.                 then    restcursor ;
  149.  
  150. : .dbheader     ( -- )
  151.                 cls
  152.                 0 dbtop 2- at
  153.                 ." \3 Enter or Space \1 = single step instruction
  154.                 ." \2 ESC \1 = Quit debugging \2 F1 \1 = Help "
  155.                 cr
  156.                 ." \1 Use  to select line to (G)o to. "
  157.                 ." \1 Press (R) to change registers. " ;
  158.  
  159. : .dbfooter     ( -- )
  160.                 0 dbbot 1+ at
  161.                 ." \1 Type \`\3STEPS\1\` to restart debugger.  "
  162.                 >attrib1 cols sp>col >norm cr ;
  163.  
  164. : .bytes        ( a1 n1 -- )
  165.                 0max bounds
  166.                 ?do     i c@ 0 <# # # #> type space
  167.                 loop    ;
  168.  
  169. \ **************************************************************************
  170. \ Display current instruction followed by data stack
  171. \ **************************************************************************
  172.  
  173. dis8086 also
  174.  
  175. 0 value ipprev
  176. 0 value ipprev2
  177.  
  178. : .inst         ( -- )          \ display one instruction
  179.                 save> base hex
  180.                 ip-@ ?.cfa 11 sp>col
  181.                 cs-@ =seg
  182.                 ip-@ dup cp ! =: ipprev
  183.                 >rev
  184.                 ip-@ h.4 inst 44 sp>col
  185.                 ip-@ cp @ over - 5 min .bytes dbeeol >norm
  186.                 restore> base ;
  187.  
  188. : .ninst        ( n1 -- )
  189.                 save> base hex
  190.                 cp @ ?.cfa 11 sp>col
  191.                 1+ dboff =
  192.                 if      cp @ =: dbto >attrib3
  193.                 then
  194.                 cp @ dup>r h.4 inst 44 sp>col
  195.                 r> cp @ over - 5 min .bytes dbeeol >norm
  196.                 restore> base ;
  197.  
  198. : .pinst        ( -- )
  199.                 ipprev 0=
  200.                 if      dbeeol
  201.                 else    save> base hex
  202.                         cs-@ =seg
  203.                         ipprev dup cp ! =: ipprev2
  204.                         cp @ ?.cfa 11 sp>col
  205.                         cp @ dup>r h.4 inst 44 sp>col
  206.                         r> cp @ over - 5 min .bytes dbeeol >norm
  207.                         restore> base
  208.                 then    ;
  209.  
  210. previous
  211.  
  212. \ **************************************************************************
  213. \ Display the processor registers
  214. \ **************************************************************************
  215.  
  216. : .regs         ( -- )
  217.                 savecursor cursor-off
  218.                 60 dbtop 3 + 79 dbtop 17 + box
  219.                 ."  \3 Tom's Debugger " bcr bcr
  220.                 ."  \1CS" cs-@ h.4 ."  \1IP" ip-@ h.4 bcr
  221.                 ."  \1DS" ds-@ h.4 ."  \1SI" si-@ h.4 bcr
  222.                 ."  \1ES" es-@ h.4 ."  \1DI" di-@ h.4 bcr
  223.                 ."  \1SS" ss-@ h.4 ."  \1SP" sp-@ h.4 bcr
  224.                           ."           \1BP" bp-@ h.4 bcr
  225.                 ."  \1AX" ax-@ h.4 09 SPACES          bcr
  226.                 ."  \1BX" bx-@ h.4 ."  \1FL" debugflags @ h.4
  227.                                                       bcr
  228.                 ."  \1CX" cx-@ h.4 09 SPACES          bcr
  229.                 ."  \1DX" dx-@ h.4 09 SPACES          bcr
  230.                 ."  ----ODITsz-a-p-c"                 bcr
  231.                 2 save!> base
  232.                 space
  233.                 debugflags @ 0 <# 16 0 do # loop #> type
  234.                 restore> base
  235.                 restcursor ;
  236.  
  237. \ **************************************************************************
  238. \ This is the single step "receiver". It saves the debugging registers
  239. \ and restores F-PC's registers then goes back to Forth.
  240. \ **************************************************************************
  241.  
  242. label int1      ( -- )          \ preserve all registers
  243.                 push ds
  244.                 push ax
  245.                 mov ax, cs: forthds
  246.                 mov ds, ax
  247.                 pop debugax
  248.                 pop debugds
  249.                 pop debugip
  250.                 pop debugcs
  251.                 pop ax
  252.                 and ax, # $FEFF         \ clear TF flag bit
  253.                 mov debugflags ax
  254.                 mov debugbx bx
  255.                 mov debugcx cx
  256.                 mov debugdx dx
  257.                 mov debugbp bp  mov bp, forthbp
  258.                 mov debugsi si  mov si, forthsi
  259.                 mov debugdi di  mov di, forthdi
  260.                 mov debuges es  mov es, forthes
  261.                 mov debugss ss  mov ss, forthss
  262.                 mov debugsp sp  mov sp, forthsp
  263.                 next            end-code
  264.  
  265. \ **************************************************************************
  266. \ This is the break point "receiver". It saves the debugging registers
  267. \ and restores F-PC's registers then goes to "STEPS".
  268. \ **************************************************************************
  269.  
  270. defer do_steps
  271. 2variable int3save
  272.  
  273. label int3      ( -- )          \ preserve all registers
  274.                 push ds
  275.                 push ax
  276.                 mov ax, cs: forthds
  277.                 mov ds, ax
  278.                 pop debugax
  279.                 pop debugds
  280.                 pop ax
  281.                 dec ax                  \ backup one byte to break point
  282.                 mov debugip ax
  283.                 pop debugcs
  284.                 pop ax
  285.                 and ax, # $FEFF         \ clear TF flag bit
  286.                 mov debugflags ax
  287.                 mov debugbx bx
  288.                 mov debugcx cx
  289.                 mov debugdx dx
  290.                 mov bx, break_save
  291.                 mov ax, break_save 2+
  292.                 mov 0 [bx], al          \ restore break point
  293.                 mov break_save # 0 word \ clear break point variable
  294.                 mov debugbp bp  mov bp, forthbp
  295.                 mov debugsi si  mov si, forthsi
  296.                 mov debugdi di  mov di, forthdi
  297.                 mov debuges es  mov es, forthes
  298.                 mov debugss ss  mov ss, forthss
  299.                 mov debugsp sp  \ mov sp, forthsp
  300.                 mov cx, cs
  301.                 mov ds, cx
  302.                 mov dx, cs: int3save            \ restore interrupt three
  303.                 mov ds, cs: int3save 2+
  304.                 mov ax, # $2503
  305.                 int $21
  306.                 mov ax, cs
  307.                 mov ds, ax
  308.                 mov ax, # ' do_steps            \ goto "STEPS"
  309.                 jmp ax
  310.                 end-code
  311.  
  312. \ **************************************************************************
  313. \ Routines to save, set & restore the number one & three interrupt vectors.
  314. \ **************************************************************************
  315.  
  316. 2variable int1save               \ a place to save the interrupt one vector
  317.  
  318. code save_int#  ( n1 --- )      \ save the current contents of interrupt one
  319.                 pop bx
  320.                 push es
  321.                 mov ax, # $3500
  322.                 or al, bl
  323.                 int $21
  324.                 mov int1save bx
  325.                 mov int1save 2+ es       \ save old vector
  326.                 pop es
  327.                 next            end-code
  328.  
  329. code save_int3  ( --- )      \ save the current contents of interrupt three
  330.                 push es
  331.                 mov ax, # $3503
  332.                 int $21
  333.                 mov int3save bx
  334.                 mov int3save 2+ es       \ save old vector
  335.                 pop es
  336.                 next            end-code
  337.  
  338. code set_int#   ( n1 --- )      \ set interrupt one to our interrupt handler
  339.                 pop bx
  340.                 push es
  341.                 mov ax, cs
  342.                 mov ds, ax
  343.                 mov dx, # int1
  344.                 mov ax, # $2500
  345.                 or al, bl
  346.                 int $21
  347.                 pop es
  348.                 next            end-code
  349.  
  350. code set_int3   ( --- )      \ set interrupt three to our interrupt handler
  351.                 push es
  352.                 mov ax, cs
  353.                 mov ds, ax
  354.                 mov dx, # int3
  355.                 mov ax, # $2503
  356.                 int $21
  357.                 pop es
  358.                 next            end-code
  359.  
  360. code rest_int#  ( n1 --- )      \ restore the contents of interrupt one
  361.                 pop bx
  362.                 mov cx, cs
  363.                 mov ds, cx
  364.                 mov dx, cs: int1save
  365.                 mov ds, cs: int1save 2+
  366.                 mov ax, # $2500
  367.                 or al, bl
  368.                 int $21
  369.                 mov ax, cs
  370.                 mov ds, ax
  371.                 next            end-code
  372.  
  373. code rest_int3  ( --- )      \ restore the contents of interrupt three
  374.                 mov cx, cs
  375.                 mov ds, cx
  376.                 mov dx, cs: int3save
  377.                 mov ds, cs: int3save 2+
  378.                 mov ax, # $2503
  379.                 int $21
  380.                 mov ax, cs
  381.                 mov ds, ax
  382.                 next            end-code
  383.  
  384. \ **************************************************************************
  385. \ initiate one single instruction step. Swaps registers, sets up the
  386. \ hardware stack with processor status, code segment, and instruction
  387. \ pointer then does an IRET to return to do a single step. The TF flag
  388. \ is set in the status register to make the processor immediately perform
  389. \ an INT1 after a single instruction has been executed. Execution then
  390. \ returns to INT1 above, and consequently back to Forth.
  391. \ **************************************************************************
  392.  
  393. code one_step   ( -- )          \ single step through one instruction as
  394.                                 \ already setup in the debugging recisters
  395.                 mov forthsp sp
  396.                 mov forthss ss
  397.                 mov forthbp bp
  398.                 mov forthsi si
  399.                 mov forthdi di
  400.                 mov forthds ds
  401.                 mov forthes es
  402.                 cmp debugsp # 0         \ give a default if needed.
  403.              0= if      mov debugsp sp
  404.                         mov debugss ss
  405.                         mov debugds ds
  406.                         mov debugcs cs
  407.                         pushf
  408.                         pop ax
  409.                         and ax, # $FEFF         \ clear TF flag bit
  410.                         mov debugflags ax
  411.                 then
  412.                 mov bx, debugbx
  413.                 mov cx, debugcx
  414.                 mov dx, debugdx
  415.                 mov bp, debugbp
  416.                 mov si, debugsi
  417.                 mov di, debugdi
  418.                 mov ss, debugss
  419.                 mov es, debuges
  420.                 mov sp, debugsp
  421.                 mov ax, debugflags
  422.                 or ax, # $100           \ set TF bit in flags
  423.                 push ax
  424.                 push debugcs
  425.                 push debugip
  426.                 mov ax, debugax
  427.                 mov ds, debugds
  428.                 iret            end-code
  429.  
  430. code one_break  ( -- )          \ go till the breakpoint we just installed
  431.                 mov forthsp sp
  432.                 mov forthss ss
  433.                 mov forthbp bp
  434.                 mov forthsi si
  435.                 mov forthdi di
  436.                 mov forthds ds
  437.                 mov forthes es
  438.                 mov bx, debugbx
  439.                 mov cx, debugcx
  440.                 mov dx, debugdx
  441.                 mov bp, debugbp
  442.                 mov si, debugsi
  443.                 mov di, debugdi
  444.                 mov ss, debugss
  445.                 mov es, debuges
  446.                 mov sp, debugsp
  447.                 mov ax, debugflags
  448.                 and ax, # $FEFF         \ CLEAR TF bit in flags
  449.                 push ax
  450.                 push debugcs
  451.                 push debugip
  452.                 mov ax, debugax
  453.                 mov ds, debugds
  454.                 iret            end-code
  455.  
  456. code trace_done ( -- )
  457.                 mov bx, debugbx
  458.                 mov cx, debugcx
  459.                 mov dx, debugdx
  460.                 mov bp, debugbp
  461.                 mov si, debugsi
  462.                 mov di, debugdi
  463.                 mov ss, debugss
  464.                 mov es, debuges
  465.                 mov sp, debugsp
  466.                 mov ax, debugflags
  467.                 and ax, # $FEFF           \ CLEAR TF bit in flags
  468.                 push ax
  469.                 push debugcs
  470.                 push debugip
  471.                 mov ax, debugax
  472.                 mov ds, debugds
  473.                 iret            end-code
  474.  
  475. \ ***************************************************************************
  476. \ initialize the Forth registers, so they will be valid when the break point
  477. \ occurs.
  478. \ ***************************************************************************
  479.  
  480. : set_fregs  ( -- )                  \ give forth registers some defaults
  481.                 sp@     forthsp !
  482.                 ?cs:    forthss !
  483.                 ?cs:    forthds !
  484.                 rp@     forthbp !
  485.                 0       forthdi !
  486.                 0       forthsi !
  487.                 ['] quit >body @ xseg @ + forthes ! ;
  488.  
  489. \ **************************************************************************
  490. \ Set the single step interrupt, perform a single instruction step, and
  491. \ then restore the single step interrupt.
  492. \ **************************************************************************
  493.  
  494. : single_step   ( -- )                  \ perform one instruction step, and
  495.                                         \ display registers with next
  496.                                         \ instruction to be traced.
  497.                 1 save_int#             \ save existing interrupt vector
  498.                 1 set_int#              \ set to out interrupt routine
  499.                 one_step                \ do a single step trace of one inst
  500.                 1 rest_int#             \ restore the interrupt vector
  501.                 ;
  502.  
  503. : break_point   ( -- )                  \ break point to offset specified
  504.                 dbto c@ =: dbsave
  505.                 dboff
  506.                 if      $CC dbto c!     \ only break if not zero
  507.                 then
  508.                 3 save_int#
  509.                 3 set_int#
  510.                 one_break
  511.                 3 rest_int#
  512.                 dbsave dbto c!          \ restore program byte
  513.                 ip-@ 1- =ip             \ backup program counter one byte
  514.                 off> dboff ;            \ reset break point offset
  515.  
  516. \ ***************************************************************************
  517. \ Break point control words, allow setting, removing, and displaying
  518. \ the current break point.
  519. \ ***************************************************************************
  520.  
  521. : unbreak       ( -- )                  \ remove the break point
  522.                 break_save @ ?dup
  523.                 if      break_save 2+ @ swap c!         \ restore break point
  524.                         break_save off                  \ clear break_save
  525.                         rest_int3                       \ restore vector
  526.                 then    defers byefunc ;
  527.  
  528. ' unbreak is byefunc    \ make break point removal automatic
  529.  
  530. : breakat       ( | <name> -- )         \ install a break point
  531.                 unbreak                 \ restore previous if needed
  532.                 set_fregs               \ give Forth registers a default
  533.                 save_int3               \ save interrupt three
  534.                 set_int3                \ set interrupt three
  535.                 ' dup break_save !
  536.                 dup c@ break_save 2+ !  \ save break point
  537.                 $CC swap c!             \ set break point
  538.                 off> ipprev
  539.                 cr ." Break point set" ;
  540.  
  541. ' breakat alias xx              \ xx is an alias for breakat
  542.  
  543. : .break        ( -- )                  \ display the current break point
  544.                 break_save @ ?dup cr
  545.                 if      ." Break point set in " >name .id
  546.                 else    ." No break point set"
  547.                 then    ;
  548.  
  549. \ **************************************************************************
  550. \ show the current registers, and a series of instructions as they will
  551. \ be executed.
  552. \ **************************************************************************
  553.  
  554. : show_debug    ( -- )
  555.                 savecursor cursor-off
  556.                 .regs
  557.                 debug.s
  558.                 0 dbtop 3 + 59 dbbot box
  559.         ." \1 Name      Addr   Instruction              Data          "
  560.                 bcr .pinst bcr .inst bcr
  561.                 dbbot dbtop 4 + - 3 - 0
  562.                 do      i .ninst bcr
  563.                 loop    restcursor ;
  564.  
  565. : set_register  ( -- )
  566.                 ipprev2 =: ipprev
  567.                 savecursor
  568.                 0 dbbot 1+ 2dup at cols 1- sp>col at
  569.                 sp@ >r sp-@ sp!
  570.                 ." \1 {in the form $23 =AX } command: "
  571.                 query interpret
  572.                 sp@ =sp r> sp!
  573.                 0 dbbot 1+ 2dup at cols 1- sp>col at
  574.                 restcursor ;
  575.  
  576. : up_dbline     ( -- )
  577.                 ipprev2 =: ipprev
  578. ( up arrow )    dboff 1- 0max =: dboff ;
  579.  
  580. : down_dbline   ( -- )
  581.                 ipprev2 =: ipprev
  582. ( down arrow )  incr> dboff ;
  583.  
  584. \ **************************************************************************
  585. \ Additional MINI help for the debugger.
  586. \ **************************************************************************
  587.  
  588. : show_help     ( -- )
  589.                 ipprev2 =: ipprev
  590.                 savecursor cursor-off savescr
  591.                 0 5 59 19 box&fill
  592.         bcr ."   Debugger commands:" bcr
  593.         bcr ." \S04\1 SPACE \0 = Do a single instruction"
  594.         bcr ." \S04\1 ESC \0   = Done, terminate debugger"
  595.         bcr ." \S04\1 D \0     = Done, continue execution from break point"
  596.         bcr ." \S04\1 G \0     = Go till hilighted line"
  597.         bcr ." \S04\1 R \0     = Set a Register"
  598.         bcr
  599.         bcr ."   \1 Press ESC to continue, or SPACE for more help "
  600.                 key $1B <>
  601.                 if
  602.                 0 5 59 19 box&fill
  603.         bcr ."   Using R, \`<number> =AX\` will set AX to <number>."
  604.         bcr ."   Registers that can be set are:"
  605.         bcr ."     =CS =DS =ES =SS =IP =SI =DI =SP =BP =AX =BX =CX =DX"
  606.         bcr
  607.         bcr ."   TRACE gives registers CS, DS, SS, ES, IP, and AX"
  608.         bcr ."   default values. Use TRACE once, then use 'R' to set"
  609.         bcr ."   registers to your desired values."
  610.         bcr bcr ." \S10\1 Press ANY key to continue " key drop
  611.                 then
  612.                 restscr restcursor ;
  613.  
  614. \ **************************************************************************
  615. \ the main trace loop, walks through instructions until the ESC key is
  616. \ pressed.
  617. \ **************************************************************************
  618.  
  619. : do_dbkey      ( c1 -- f1 )
  620.                 case
  621. ( terminate )   $1B of                          true    endof
  622. ( enter )       $0D of  single_step             false   endof
  623. ( space )       $20 of  single_step             false   endof
  624. ( up arrow )    $C8 of  up_dbline               false   endof
  625. ( down arrow )  $D0 of  down_dbline             false   endof
  626. ( help )        $BB of  show_help               false   endof
  627.                 upc                 \ remaining tests are case insensitive
  628. ( Go )          'G' of  break_point             false   endof
  629. ( register set) 'R' of  set_register            false   endof
  630. ( debug done )  'D' of  0 20 at trace_done      false   endof
  631.                         ipprev2 =: ipprev
  632. ( all others )          drop beep               false
  633.                 endcase ;
  634.  
  635. : steps         ( -- )
  636.                 .dbheader
  637.                 0 20 at
  638.                 rp@      =bp
  639.                 rp@ 80 - rp!            \ move return stack out of the way
  640.                 sp@      =sp            \ set debugger to Forth stack
  641.                 sp@ 20 - sp!
  642.                 begin   show_debug
  643.                         key do_dbkey
  644.                 until   sp0 @ sp-@ - 2/ 0>      \ is stack empty?
  645.                 if      sp-@ sp!                \ if not, restore it
  646.                 else    sp0 @ sp!               \ else clear stack
  647.                 then
  648.                 debugbp @ rp! .dbfooter ;
  649.  
  650. ' steps   is do_steps     \ link into break point handler
  651.  
  652. \ **************************************************************************
  653. \ setup for tracing a series of instructions, and call STEPS.
  654. \ **************************************************************************
  655.  
  656. : trace         ( | <name> -- )         \ use as in: TRACE <word> <enter>
  657.                                         \ sets up and displays first
  658.                                         \ instruction with registers.
  659.                 ' dup =ip =ax
  660.                 ?cs: dup =cs dup =ds =ss
  661.                 ?es: =es
  662.                 off> dboff
  663.                 off> ipprev
  664.                 steps ;
  665.  
  666. \ ***************************************************************************
  667. \ some test words for the debugger
  668. \ ***************************************************************************
  669.  
  670. code tst        ( -- )
  671.                 mov ax, # 23
  672.                 push ax
  673.                 next            end-code
  674.  
  675. cr .( try:  TRACE TST <enter>  )
  676.  
  677. : ++ + ;
  678.  
  679. : test 2 3 ++ . ;
  680.  
  681. .( try:  BREAKAT ++ <enter>  )
  682. .( then:  TEST <enter> )
  683. cr
  684.  
  685. \ **************************************************************************
  686. \ A utility to allow dropping into the BXDEBUG program while testing this
  687. \ debugger
  688. \ **************************************************************************
  689.  
  690.  
  691. \ code int3       ( -- )          \ a debugging tool
  692. \                 int 3
  693. \                 next            end-code
  694.  
  695. }
  696.  
  697.