( ************************** Debugger  ********************************* 
  See main file for description of monitor.

  Debugger commands:
     A hex_address                              Alter Memory
     C hex_address_a hex_address_b hex_count    Copy Memory a to Memory b
     D hex_address hex_count                    Dump Memory
     G hex_address                              Go to Address
     S                                          Print stack pointer register
     X                                          Enter Download mode

     Download mode accepts a ".ols" file generated by the fc complier when fc
     is invoked with the -o option.  Download mode accepts the ascii/hex file 
     and loads it into memory. Once download mode is entered, the monitor 
     remains in download mode until an escape character is received.  When 
     an escape is received, the monitor will print out a check sum that 
     should be zero after error free download.  
      
)

#macro ESC 0x1b
#macro 'A' 0x41
#macro 'C' 0x43
#macro 'D' 0x44
#macro 'G' 0x47
#macro 'S' 0x53
#macro 'X' 0x58
#macro '>' 0x3E
#macro CR 0xD
#macro LF 0xA


cvariable cmd_index            ( Index of next char in buffer )
cvariable altmode              ( =TRUE for alter memory mode, FALSE otherwise )
variable alt_address          ( Address for alter memory mode )
variable mon_checksum         ( Checksum for download )
cvariable abort_load          ( =TRUE for load abort, FALSE otherwise )
32 carray cmdbuffer           ( Command buffer )


: do_prompt ( -- )
( Print out debugger prompt )
  0 cmd_index c!         ( point to start of command buffer )
  PROMPT emit_string
;

: do_aprompt ( a -- )
( Prompt for memory alter )
   0 cmd_index c!       ( point to start of command buffer )
   newline              ( carriage return line feed )
   alt_address @ 
   dup .x                 ( Print address )
   @ .x                   ( Print word value )
   '>' emit               ( Print a prompt character )
; 

xlink
: debug_init ( -- )
( Initialize debugger )
   FALSE altmode c!           ( Normal command mode )
   do_prompt
;

xlink
: debugger ( -- )
( Waits for, then processes character from test port )
   key
   dup emit                    ( echo char )
   toupper                     ( Force to upper case )
   dup 0x8 = if               ( Check for backspace )
     cmd_index c@ dup if      ( Make sure were not already at start of buffer )
       1 -                    ( do backspace by decrementing index )
     then
   else
     cmd_index c@ over over cmdbuffer + c!   ( save char in buffer )
     1 + 31 and                             ( increment index and mask )
   then
   cmd_index c!                           ( save new cmd_index )
   CR = if
      cmdbuffer skip_space       ( Point to first non space char )
      altmode c@ if
           ram_alter           ( alter memory )
       else
           parse_cmd           ( execute command )
       then
   then
;

: parse_cmd  ( a -- )
( Parse input command at address a )
     c@+ swap                  ( Get first char, char on top, address next )
     dup 'X' = if
       newline
       downloader             ( download software )
       mon_checksum @ .x
     then
     dup 'A' = if
       swap getnum drop alt_address !    ( Alt function address )
       drop
       TRUE altmode c!                ( Set to alter mode )
       do_aprompt
       exit
     then
     dup 'C' = if
        swap getnum getnum     ( get source and destination addresses )
        >r swap r>             ( source second, destination third )
        getnum drop            ( get count )
        cpy_ram_ram            ( Copy RAM to RAM )
       0 swap                  ( leave two parameters on stack, char on top )
     then
     dup 'D' = if
       swap getnum getnum drop  ( get address and count )
       dumper                   ( do dump )
       0 swap                   ( leave two parameters on stack, char on top )
     then
     dup 'S' = if
        newline
        spr@ .x                     ( print stack pointer register )
     then
     dup 'G' = if
       newline
       >r         ( put char on return stack )
       getnum drop execute    ( Go to )
       0
       r>
     then
     drop                                      ( Drop character )
     drop                                      ( Drop address )
     do_prompt               ( write debugger prompt )
;

: directnum  ( -- n )
( Get a hex number directly from test port stream, ignore command buffer
  Return 0 if abort_load = TRUE )
   0
   4 for                    ( Always 4 hex digits per number for download )
      begin 
         abort_load c@ if
           TRUE               ( No processing for abort, return 0 )
         else
           key                ( Get a char  )
           dup emit            ( Echo it )
           dup CR = if
             LF emit          ( send line feed for CR )
           then
           dup ESC = if
             TRUE abort_load c!   ( abort load )
           then
           do_digit not
         then
      until                 ( Repeat until valid nibble or abort )
   next
   dup mon_checksum @ +       ( add to checksum )
   rotate_right
   mon_checksum !             ( save checksum )
;

: downloader ( -- )
( download from PC )
   FALSE abort_load c!    ( load mode )
   0 mon_checksum !       ( clear checksum )
   begin
     directnum drop       ( Configuration )
     directnum            ( Start address )
     directnum            ( Length )
     directnum drop       ( header checksum )
     abort_load c@ if
       drop
     else
       for
         directnum
         swap !+         ( store data into memory if load not aborted )
       next
     then
     drop               ( drop address )
     mon_checksum @
     directnum - mon_checksum !    ( Full checksum )
     abort_load c@
   until
;

: dumper  ( s l -- )
( Dump starting at s, length l words  )
   0                ( dump count for newlines )
   swap
   for 
      dup 7 and 0= if       ( Print out address every 8 words )
         newline
         over .x               ( print address )
         ": " emit_string      ( print colon )
      then
      swap
        @+             ( Get data using dpr )
      swap .x               ( Print data )
      swap 1 +
   next
   drop
   drop
;

: ram_alter ( a -- )
( Alter RAM memory, a address of text string )
   dup c@ CR = if
       FALSE altmode c!      ( turn off alter mode )
       drop
       do_prompt
   else
       getnum drop
       alt_address @ !+ alt_address !
       do_aprompt
    then
;




     
    
