; ***************************************************************************
;                                                                           *
;                       HC908 Debug Monitor  V1.0                           *
;                          George Heron, N2APB                              *
;                               12/2002                                     *
;                                                                           *
; This program is a simple, low-level debug monitor developed to support    *
; the projects based on the "HC908 Daughtercard" project described          *
; in QRP Homebrewer magazine (published by the NJQRP Club), in QRP          *
; Quarterly magazine (published by QRP ARCI), and on the website of the     *
; New Jersey QRP Club (www.njqrp.org)                                       *
;                                                                           *
; The operator interfaces to the HC908 Debug Monitor by means of a dumb     *
; terminal connected to the RS-232 serial port of the MPU daughtercard.     *
; Through the Monitor's command/response structure, the operator may edit   *
; memory amd MPU registers, set and reset breakpoints, "go" or single step  *
; from any executable location in the loaded program, load S record files   *
; sent by the terminal, program Flash memory from the downloaded S records, *
; and read input ports and set output ports.                                *
;                                                                           *
; The HC908 Debug Monitor is programmed into all HC908 Daughtercards after  *
; manufacture. In some instances, another software program may also be      *
; programmed in the HC908 Daughtercard at time of manufacture, providing    *
; the customer with one of a growing number of software applications for    *
; this product (e.g., the Digital Breadboard, the Antenna Analyzer, HC908   *
; Commander, the HC908 Digital VFO and others).                             *
;                                                                           *
; As mentioned, the HC908 Daughtercard and its debug monitor provides the   *
; user with an ability to program the permament and nonvolatile "flash"     *
; memory directly from downloaded "S records". An S record file is a common *
; format for the assembled or compiled 68HC908 MPU binary code, as          *
; used in most Motorola-based processors and tools. Thus, when a user       *
; wishes to load a program other than what arrived on his HC908             *
; Daughtercard, he may download any of the available S record files from the*
; project's Internet website and "burn" the program into the MPU's flash    *
; memory, thus making the program permanent and available for his use. In   *
; this way, the user is able to change the HC908 Daughtercard's             *
; "personality" without any other tools than a terminal program connected   *
; to the Daughtercard on its serial port.                                   *
;                                                                           *
; Most "dumb terminals" may be used to communicate with the HC908 Debug     *
; Monitor. Examples of such programs include HyperTerminal, Red Ryder,      *
; ProComm and PCPlus. However, a  useful, public domain (freeware) terminal *
; program called "Tera Term" is also available to run on Microsoft Windows  *
; platforms. Tera Term has a convenient scripting ability that can be       *
; invoked to send an S record file (like a new software program) to your    *
; HC908 Daughtercard for flash programming by the Monitor.  The Tera Term   *
; terminal program and its S record transfer script are provided on the     *
; HC908 project website for users to download and use on their systems.     *
;                                                                           *
; There are many more features and details concerning the use of the HC908  *
; Debug Monitor on the HC908 Daughtercard-based projects.  Please refer to  *
; written documentation provided with the Monitor and Daughtercard for the  *
; latest and authoritative information concerning capabilities and use.     *
;                                                                           *
; Questions may be addressed to me by email and I'll do my best to help out.*
;
;  v1   Dec 2002      Initial release
;  v2a  May 5, 2003   Removed $803C hook into User Space to reduce
;                     complexity and chance for user to mess up by
;                     inadvertently overwriting the hook code
;  v2b  June 8, 2003  Corrected comment for PIT interrupt vector code (FFF6+FFF7)
;                                                                           *
;  George Heron, N2APB                                                      *
;  email: n2apb@amsat.org                                                   *
;                                                                           *
; ***************************************************************************
;   GNU Public License                                                      *
;                                                                           *
;   This program is free software; you can redistribute it and/or modify    *
;   it under the terms of the GNU General Public License as published by    *
;   the Free Software Foundation; either version 2 of the License, or       *
;   (at your option) any later version.                                     *
;                                                                           *
;   This program is distributed in the hope that it will be useful,         *
;   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
;   GNU General Public License for more details.                            *
;                                                                           *
;   You should have received a copy of the GNU General Public License       *
;   along with this program; if not, write to the Free Software             *
;   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
;                                                                           *
;   See license.txt file for details                                        *
;                                                                           *
;****************************************************************************
;   Credits:                                                                *
;                                                                           *
;   Major portions of this program were adapted from the Pony 68HC908 Debug *
;   Monitor V1.4 by Larry Bateman.  Copyright (c) 2000, L3 Systems.         *
;                                                                           *
;   Portions borrowed from Motorola's "MC68HC908GP32 User Bootloader",      *
;   Copyright (c) Motorola 2000. Written by DGJ Klotz  Rev ES 1.0 26-Feb-00 *
;                                                                           *
; ***************************************************************************

$BASE 10T

        include "../ab_regs.asm"            ; MC68HC908GP32 register defimitions
        include "../macros.asm"             ; Macro instruction definition
        include "../local.asm"              ; Local variables

;            User Base RAM

                org $50
_count          rmb 1                   ; Byte Counter for s record download
_temp_sp        rmb 2                   ; Temporary stack pointer

;            User stack - Hex 3ff

                org $3FF
_user_stack     rmb 1                   ; Position to Initialize user stack

;            Monitor RAM - Hex 400-44F

                org $400
_hbufpos        rmb 2                   ; buffer position temp storage
_tempx          rmb 2                   ; Temporary h:x register storage
_stack_save     rmb 2                   ; Stack save
_last_break     rmb 2                   ; Save last break, to reset break
                                        ; when resuming
_h_save         rmb 1                   ; h-reg save
_state          rmb 1                   ; State after break point
_inbuf          rmb RXBLEN              ; Input Buffer

;            Monitor stack, initialize at end of RAM Hex 23F

                org $44F
_mon_stack      rmb 1                   ; Position of monitor stack

                org $EF00
_user_reset     fdb $8040               ; pointer to start User Application

;************************************************************
;   Power-on Reset
;************************************************************
__start:
_bootreset:
                ; Launch the bootloader from power-on reset.

        sei                             ; disable all interupts
        ldhx     #_mon_stack+1          ; initialize
        txs                             ;  the stack pointer

        jsr     PLLset                  ; change bus speed

                ; Initialize the SCI.

        mov      #init_scbr,scbr        ; initialize baud rate
        mov      #init_scc1,scc1        ; initialize SCI Control Register 1
        mov      #init_scc2,scc2        ; initialize SCI Control Register 2
        mov      #init_config1,config1  ; init Configuration Register 1

                ; Test Port F7 for "Monitor Jumper"
                ;   Entry to Monitor  = jumper OFF ==> F7 = 1
                ;   Entry to User Pgm = jumper ON  ==> F7 = 0

        mov     #$40,ddrf               ;set portf bits 7,5,4,3,2,1,0 as inputs, bit 6 (LED) as output
        mov     #$B8,prtfpu             ;assign pullups to Port F bits 7,5,4,3
        bclr    6,portf                 ;turn LED on continuously while in monitor
        brclr   7,portf,MonStart        ;go start Monitor if "Monitor Jumper" is in place
        ldhx    #_user_stack            ;else init user SP
        jsr     _save_sp                ;  in _user_stack area
        jsr     $8040                   ;  and go start User application at $8040

MonStart:
        ldhx #ram_start
clrRAM: clr     ,x                      ;Clear RAM
        aix #1
        cphx #ram_last+1
        bne clrRAM

        jsr _init_ustack                ;Initialize user stack

        nop
        nop
        nop

                ; Boot start
_boot:
        sta copctl                      ;clear the COP counter
        lda #$FF
        jsr _delay                      ;delay just a bit
        ldhx #_PWR_MSG                  ;point to monitor sign-on message
        jsr _puts                       ;and display it
_main:
        ldhx #_PROMPT                   ; Print prompt
        jsr _puts
        jsr _gets                       ;get user input command string
        bcs _main                       ;keep looking if ESC or ctl-C
        lda _inbuf                      ;check input buffer
        beq _main                       ;keep looking if empty (just CR entered)
        and #$DF                        ;turn to capital letter
        ldhx #_cmdtab                   ;point to command table
        jsr _get_atbl                   ;get menu selection
        bcc  notfound                   ;valid menu item not selected
        jsr ,x                          ;found menu item, call corresponding routine
        bra _main                       ;get another command when processing done
notfound:
        ldhx #_ERR_MSG                  ;pointer to error string
        jsr _puts                       ;print the string
        bra _main                       ;go get another command

;************************************************************
;       _init_ustack  After power up or download, checks for
;                     valid user reset jump statement.  If one exists,
;                     then initialize user stack to go there on an rti
;************************************************************
_init_ustack:
        brclr 7,PortF,no_rst_vec ; "Mon Jumper" in place, we're in Monitor
        ldhx #_user_stack-4      ; Read user stack address + rti frame
        jsr _save_sp             ; Store address in stack_save
        lda _user_reset          ; Get address of user program reset
        sta _user_stack-1        ;   and store in address field of stack frame
        lda _user_reset+1        ;
        sta _user_stack
no_rst_vec:
        rts

;************************************************************
; _medit() Edit memory locations
;************************************************************
_medit:
        jsr _first_hex
        bcs end_medit
mexlp:
        jsr _crlf
        jsr _pword
        lda ,x
        jsr _pbyte_sp
        jsr _space
        lda #2
        pshhx
        jsr _gethex
        lda _inbuf
        bcs not_byte
        txa
        pulh
        pulx
        sta ,x
        aix #1
        bra mexlp
not_byte:
        pulhx
        aix #1
        cmp #SPACE
        beq mexlp     ; If nul entry (ENTER), go to next byte
        aix #-2
        cmp #BS
        beq mexlp     ; If Backspace, go to previous byte
end_medit:
        rts           ;  Else return

;************************************************************
;       _dump() Dump Memory locations
;************************************************************
_dump:
        jsr _first_hex
        bcs end_dump
        txa              ; Init even boundary
        and #$F0
        tax
prmem:
        pshhx
        ldhx #_HEADING
        jsr _puts
        pulhx
prmlp:
        txa
        and #$0F
        bne nxmem
        jsr _crlf
        tha
        jsr _pbyte
        txa
        jsr _byte_sp
nxmem:
        lda ,x
        jsr _byte_sp
        aix #1
        txa
        tsta
        bne prmlp
wt_end_dump:
        jsr _do_again
        beq prmem
end_dump:
        rts

;************************************************************
;************************************************************
;
;  D E B U G   C O M M A N D S
;
;************************************************************
;************************************************************

;************************************************************
;           _fill() --  Fill Memory locations
;************************************************************
_fill:
        jsr _first_hex
        bcs end_fill
        pshhx
        jsr _next_hex
        bcc get_val
        pulhx
        bra end_fill
get_val:
        tha
        sta _tempx
        stx _tempx+1
        jsr _next_hex
        txa
        pulhx
        bcs end_fill
fill_lp:
        sta ,x
        psha
        tha
        cmp _tempx
        pula
        bne nxt_fill
        cpx _tempx+1
        beq end_fill
nxt_fill:
        aix #1
        bra fill_lp
end_fill:
        rts

;************************************************************
;       _pr_reg, _out_reg -- Outputs registers from user stack
;************************************************************
_prreg:
        jsr _crlf
_out_reg:
        ldhx #SP_MSG
        jsr _puts
        jsr _get_sp
        aix #-1
        jsr _pword
        pshhx
        ldhx #CC_MSG
reg_lp:
        jsr _puts
        aix #1
        pshhx
        lda ,x
        cmp #':'
        bne not_h_reg
        lda _h_save
        jsr _pbyte
        bra nxt_reg
not_h_reg:
        lda 3,sp
        tah
        ldx 4,sp
        aix #1
        lda ,x
        jsr _pbyte
        tha
        sta 3,sp
        stx 4,sp
nxt_reg:
        pulhx
        lda ,x
        cmp #'E'
        bne reg_lp
        pulhx
        rts

;************************************************************
;       _set_break -- Sets breakpoint
;************************************************************
_set_break:
        jsr _first_hex      ; Gets breakpoint address
        bcs pr_brkpt
        tha                    ; store breakpoint so that it can be restored
        sta _last_break        ; at next breakpoint when resuming
        stx _last_break+1
        bsr _wt_break
pr_brkpt:
        ldhx #_MSG_BREAK
        jsr _puts
        lda brkscr
        bpl end_set_bp
        lda brkh
        tah
        ldx brkl
        jsr _pword
end_set_bp:
        rts

;************************************************************
;       _restore_bk -- Restores break address to last set value
;************************************************************
_restore_break:
        lda _last_break
        tah
        ldx _last_break+1

                ;  _wt_break  writes a break point at h:x

_wt_break:
        stx brkl           ; stores breakpoint
        tha
        sta brkh
        lda #$80
        sta brkscr         ; enables breakpoint
        sta sbfcr          ; Allows access to break status registers
        rts

;************************************************************
;       _clr_break -- Clears breakpoint
;************************************************************
_clr_break:
        clra               ; disables breakpoint
        sta brkscr
        rts

;************************************************************
;       _break_pt  -- Routine to process breakpoint
;************************************************************
_break_pt:
        sei
        lda #$80
        sta sbfcr          ; Allows access to break status registers
        sta brkscr
        tha
        sta _h_save        ; Save h register
        tsx
        jsr _save_sp       ; Save user stack pointer
        ldhx #_mon_stack+1 ; Transfer stack to monitor RAM
        txs
        bsr _restore_break ; restore breakpoint
        lda _state         ; Check if this was a go from a breakpoint
        cmp #1             ; If so, we need to resume
        bne not_resume
        clra               ; Clear resume state
        sta _state
        jmp _do_rti        ; Resume from current breakpoint
not_resume:
        ldhx #_MSG_BREAK   ; Output breakpoint message
        jsr  _puts
        jsr _out_reg       ; Output registers
        jsr _get_pc        ; Get current user program counter
        jsr _disasm_1x     ; Disassemble where you are
        lda _state
        cmp #2             ; Is it in single step mode?
        bne not_sstep      ; If not, go back to prompt
        jsr _do_again      ; If so, look for space to step next
        beq _step_again    ;   If space, do next instruction
        clra               ;   If not, clear resume state
        sta _state         ;   and go back to prompt
not_sstep:
        jmp _main

;************************************************************
;       _next -- Step one instruction
;************************************************************
_next:
        bsr _is_stack_ok   ; Only step if Stack is initialized
        bcs no_step        ;   WARNING: this is not a bullet-proof test!
_step_again:
        bsr _break_next    ; Set breakpoint to stop at next instruction
        lda #2             ; Sets single step state
        sta _state
        jmp _go_stack      ;

;************************************************************
;       _break_next --  Set to break on next instruction Based on following:
;                         - If current instruction is 2 or more bytes
;                           setting the break in the 2nd byte will cause
;                           the break to occur on the next instruction
;                         - If one byte instruction, only jsr ,x and
;                           jmp ,x will start at next byte
;************************************************************
_break_next:
        jsr _get_pc      ; Get current user program counter
        lda ,x
        aix #1           ; Check if instruction is a jmp ,x or jsr ,x
        and #$FE
        cmp #$FC
        bne not_jx
        bsr _get_hx
        lda ,x          ; If it is a jmp ,x or jsr ,x
        ldx 1,x          ; Then set break at address pointed to by x-reg
        tah
not_jx:
        jmp _wt_break

;************************************************************
;       _is_stack_ok  returns carry clear if ok,  set if not,
;
;************************************************************
_is_stack_ok:
        lda _stack_save ; Check that user SP is valid
        beq ck_ss_low
        cmp #1
        bne stk_not_ok
        bra stk_ok
ck_ss_low:
        lda _stack_save+1
        beq stk_not_ok
stk_ok:
        clc
        rts
stk_not_ok:
        sec
no_step:
end_go:
        rts

;************************************************************
;       _get_pc    Gets user PC off of user stack, returned in h:x reg
;************************************************************
_get_pc:
        bsr _get_sp
        lda 3,x
        ldx 4,x
        bra done_get

;************************************************************
;       _get_hx    Gets user h:x reg, gets x-reg off of stack and
;                       h reg from _h_save. Returns in h:x reg
;************************************************************
_get_hx:
        bsr _get_sp
        ldx 2,x
        lda _h_save
        bra done_get

;************************************************************
;       _get_sp    Gets user stack pointer from +stack_save
;                       Returns in h:x reg
;************************************************************
_get_sp:
        lda _stack_save
        ldx _stack_save+1
done_get:
        tah
        rts

;************************************************************
;       _save_sp    Saves user stack pointer in stack_save
;                       Passed in h:x reg
;************************************************************
_save_sp:
        tha
        sta _stack_save      ; Store address in stack_save
        stx _stack_save+1
        rts

;************************************************************
;           go(*x-reg) Execute program at X-reg
;************************************************************
_go:
        jsr _first_hex
        bcs  chk_stack_add
        tha
        stx _tempx
        ldhx #_user_stack+1
        txs
        tah
        ldx _tempx
        cli
        jmp  ,x        ; Call user prog,x
chk_stack_add:
        bsr _is_stack_ok
        bcs end_go
_go_stack:
        lda brkscr
        bpl _do_rti
        jsr _get_pc            ; Get current user program counter
        cpx brkl               ; compares breakpoint address to current
        bne _do_rti
        tha
        cmp brkh
        bne _do_rti
        lda #1                 ; If currently at breakpoint, set _state to 1
        sta _state             ; to indicate to continue from next break
        tha                    ; and store breakpoint to be restored
        sta _last_break        ; at next breakpoint when resuming
        stx _last_break+1
        jsr _break_next        ; and set break at next instruction
_do_rti:
        bsr _get_sp   ; If user SP is valid, set SP to user SP and do RTI
        txs
        lda _h_save
        tah
        rti

;************************************************************
;           Prints Help message
;************************************************************
_help:
        ldhx #_PWR_MSG
        jsr _puts
        ldhx #_HELPLIST
        jsr _puts
        rts

;************************************************************
;   Copy Flash Mass Erase algorithm into RAM and execute.
;************************************************************

; ram_exec        equ $200-STACK_ALLOC-ProgramRamSize+1 ; executable RAM

ram_exec        equ $19A

_do_mass_erase:
        ldhx #EraseRamSize    ; initialize pointer
BootErase1:
        lda MassErase-1,x     ; get program from Flash
        sta ram_exec-1,x      ; copy into RAM
        dbnzx BootErase1      ; decrement pointer and loop back until done
        jsr ram_exec          ; execute Flash Mass Erase algorithm from RAM
BootDone:
        jsr _init_ustack      ; initialize user stack
        rts

;-------------------------------------------------------------------
;   Check for Program Flash command.

_do_dnload:
                ; Copy Program Flash algorithm into RAM and execute.

        ldhx #ProgramRamSize  ; initialize pointer
BootProg:
        lda _delay-1,x        ; get program from Flash
        sta ram_exec-1,x      ; copy into RAM
        dbnzx BootProg        ; decrement pointer and loop back until done
        ldhx #_MSG_WAITING    ; point to waiting message
        jsr _puts             ; output it

                ; Get S-Record from host.
BootProg1:
        sta copctl            ; clear the COP counter
        tsx                   ; get the Stack Pointer
        sthx _temp_sp         ; save it temporarily
        ais #-36T              ; allocate stack space for data
        jsr GetSRec           ; get an S-Record
        bne BootProg3         ; indicate error if S-Record is invalid
        pula                  ; get S-Record type
        cmp #'9'              ; check for end record type
        beq BootProg2         ; indicate operation complete
        cmp #'1'              ; check for data record type
        bne BootProg3         ; indicate error if S-Record is invalid

                ; Program Flash.

        jsr {ram_exec+ProgramRam}  ; execute Program Flash alg from RAM
        ais #35T                    ; deallocate stack space
        bra BootProg1              ; loop bacl for next S-Record

BootProg2:
        ais #35T                    ; deallocate stack space
        brclr SCRF,scs1,BootDone   ; skip if SCI receiver is empty
        jsr _getchne               ; else, clear last ASCII carriage
                                   ;   return from the SCI
        brclr SCRF,scs1,BootDone   ; skip if SCI receiver is empty
        jsr _getchne               ; else, clear last LF from the SCI
        bra BootDone               ; indicate operation complete

BootProg3:
        ais #36T                   ; deallocate stack space

                ; Respond to error situations.

        ldhx #_MSG_ERROR           ; point to error message
Boot4:
        jsr _puts                  ; output it
        jmp _boot                  ; jump back to the top

;********************************************************************
;   CGM PLL Bus Frequency Change Subroutine
;
;       This subroutine will program the CGM PLL to change the bus frequency
;       from that of the 4.915 MHz xtal to about 8 MHz
;********************************************************************
PLLset:
         bclr  BCS,pctl            ; select external reference as base clock
         bclr  PLLON,pctl          ; turn off PLL
         mov   #$77,PPG            ; set up PLL Programming Register
         bset  AUTO,pbwc           ; enable automatic bandwidth control
         bset  PLLON,pctl          ; turn on PLL
PLLwait:
         brclr LOCK,pbwc,PLLwait   ; wait for PLL to lock
         bset  BCS,pctl            ; select VCO as base clock
         rts                       ; return


;********************************************************************
;   GetSRec Subroutine
;
;       This subroutine will retrieve data in S19 record format via the SCI.
;
;   Calling convention:
;
;       ais     #-buffer_length
;       jsr     GetSRec
;
;   Returns:    CCRZ= 1 if valid S-Record retrieved.  Otherwise, CCRZ= 0.
;               S-Record Type at SP+1     (1 byte)
;               S-Record Size at SP+2     (1 byte)
;               S-Record Address at SP+3  (2 bytes)
;               S-Record Data at SP+5     (up to 32 bytes, typically)
;
;               |                |    <-sp (after local space allocation)
;       H:X->   | SRecCount      |
;               | SRecChkSum     |    <-sp (when called)
;               | ReturnAddr msb |
;               | ReturnAddr lsb |    <-sp (upon return)
;               | SRecType       |
;               | SRecSize       |
;       H:X->   | SRecAddr msb   |
;               | SRecAddr lsb   |
;               | SRecData 00    |
;               | SRecData 01    |  etc..
;
;   Changes:    ACC, H:X
;********************************************************************
SRecCount       equ   1  ; stack pointer offset for S-Record Counter (local)
SRecChkSum      equ   2  ; stack pointer offset for S-Record Check Sum (local)
SRecType        equ   5  ; stack pointer offset for S-Record Type
SRecSize        equ   6  ; stack pointer offset for S-Record Size
SRecAddr        equ   7  ; stack pointer offset for S-Record Address
SRedData        equ   8  ; stack pointer offset for S-Record Data

GetSRec:
        ais #-2               ; allocate local variable space
        clr SRecSize,sp       ; initialize S-Record size
GetSRec1:
        jsr _getchne          ; get a character from the SCI
#if HYPERTERM
#elseif
          jsr _putch            ; echo it back
#endif
        cmp #CR               ; check for ASCII carriage return
        bne GetSRec1a         ; just loop back if so
        lda #LF               ; get ASCII line feed
#if HYPERTERM
#elseif
          jsr _putch            ; echo it back
#endif
GetSRec1a:
        cmp #'S'              ; check for start of record character
        bne GetSRec1          ; loop back if not
        jsr _getchne          ; else, get next character from the SCI
#if HYPERTERM
#elseif
          jsr _putch          ; echo it back
#endif
        cmp #'0'              ; check for header record type
        beq GetSRec1          ; loop back if so
        cmp #'9'              ; else, check for end record type
        beq GetSRec2          ; continue if so
        cmp #'1'              ; else, check for data record type
        bne GetSRec1          ; loop back if not
GetSRec2:
        sta SRecType,sp       ; save S-Record type
        jsr GetHexByte        ; get the S-Record length
        bne GetSRec4          ; exit if not a valid hex byte
        sta SRecCount,sp      ; initialize S-Record counter
        sta SRecChkSum,sp     ; initialize S-Record check sum
        sub #3                ; adjust for address and checksum
        sta SRecSize,sp       ; save S-Record size
        tsx                   ; use H:X as data stack frame pointer
        aix #(SRecAddr-1)     ; adjust so pointer starts at S-Record Address
GetSRec3:
        jsr GetHexByte        ; get next S-Record hex byte
        bne GetSRec4          ; exit if not a valid hex byte
        sta ,x                ; save data in stack frame
        add SRecChkSum,sp     ; add data to check sum
        sta SRecChkSum,sp     ; save new check sum
        aix #1                ; move data stack frame pointer
        dbnz SRecCount,sp,GetSRec3 ; loop back until all data received
        inc SRecChkSum,sp     ; final calc zeros check sum if it's okay
GetSRec4:
        ais #2                ; deallocate local variables
        rts                       ; return

;**************************************************************************
;   Flash Mass Erase Subroutine
;       This subroutine performs multiple Page Erase operations in order
;       to completely erase the application space Flash memory.
;       This subroutine is copied into and executed from RAM.
;********************************************************************
MassErase:
        ldhx #rom_start     ; initialize pointer to start of Flash memory

MassErase1:
              ; Set ERASE, read the Flash Block Protect Register and write any
              ; data into Flash page.
        lda #ERASE            ; set ERASE control bit
        sta flcr              ;  in Flash Control Register
        lda flbpr             ; read from Flash Block Protect Register
        sta ,x                ; write any data to address within page

              ; Wait for >10us, then set HVEN.
        lda #1                ; wait
        bsr _delay            ;  for 11.7us
        lda #(ERASE|HVEN)     ; set HVEN control bit
        sta flcr              ;  in Flash Control Register

              ; Wait for >1ms, then clear ERASE.
        lda #100T              ; wait
        bsr _delay            ;  for 1.005ms
        lda #HVEN             ; clear ERASE control bit
        sta flcr              ;  in Flash Control Register

TestLabel:
              ; Wait for >5us, then clear HVEN.
        lda #1                ; wait
        bsr _delay            ;  for 11.7us
        clra                  ; clear HVEN control bit
        sta flcr              ;  in Flash Control Register

              ; Advance pointer and repeat until finished.
        aix #{flash_page/2}   ; add half of Flash Erase Page size twice,
        aix #{flash_page/2}   ;  since it's 128 bytes for GP32
        cphx    #boot_start   ; check if finished
        bne MassErase1        ; loop back if not

        rts                   ; return

;********************************************************************
;   delay Subroutine
;
;       This subroutine performs a simple software delay loop based upon
;       the value passed in ACC.
;       The following timing calculation applies:
;
;               delay = ((ACC * 74) + 12) (tcyc)
;       If A=1
;          then delay = 11.7us at 114.545ns/cycle
;
;********************************************************************
_delay:
        psha                  ; [2] save delay parameter temporarily
delay1:
        lda #102T              ; [2] initialize 5us loop counter
                              ;     (repeat for timing)
delay2:
        dbnza delay2          ; [3] decrement inner delay loop counter
        dbnz 1,sp,delay1      ; [6] decrement outer delay loop counter
        pula                  ; [2] deallocate local variable
        rts                   ; [4] return

EraseRamSize    equ     (*-MassErase)
ProgramRam      equ     (*-_delay)

;********************************************************************
;   Flash Program Subroutine
;
;       This subroutine controls the Flash programming sequence.  A stack
;       frame data block is passed to it in the format shown below.
;       This subroutine is copied into and executed from RAM.
;
;               |                |    <-sp (when called)
;               | ReturnAddr msb |
;               | ReturnAddr lsb |    <-sp (upon return)
;               | SRecSize       |
;               | SRecAddr msb   |
;               | SRecAddr lsb   |
;               | SRecData 00    |
;               | SRecData 01    |  etc..
;********************************************************************
FlashProgram:
        tsx                   ; get the Stack Pointer
        sthx _temp_sp         ; save it temporarily

              ; Get S-Record size and use the Stack Pointer as the data source pointer.
        ais #2                ; SP points to SRecSize
        pula                  ; get SRecSize
        sta _count            ; save it temporarily

              ; Establish H:X as the destination pointer.
        pulh                  ; get destination address msb
        pulx                  ; get destination address lsb

              ; Set PGM, read the Flash Block Protect Register and write anywhere
              ; in desired Flash row.
        lda #PGM              ; set PGM control bit
        sta flcr              ;  in Flash Control Register
        lda flbpr             ; read from Flash Block Protect Register
        sta ,x                ; write any data to first Flash address

              ; Wait for >10us, then set HVEN.
        LDA     #tnvs
        DBNZA   *
        lda #(PGM|HVEN)       ; set HVEN control bit
        sta flcr              ;  in Flash Control Register

              ; Wait for >5us.
        LDA     #tpgs
        DBNZA   *

              ; Write data to Flash and wait for 30 - 40us.
FlashProgram1:
        pula                  ; get S-Record data
        sta ,x                ; write data to Flash
        LDA     #tprog
        DBNZA   *

              ; Advance destination pointer and data counter.
        aix #1                    ; advance destination pointer
        dbnz _count,FlashProgram1 ; decrement counter and loop back
                                  ;  if not done.

              ; Clear PGM.
        lda #HVEN             ; clear PGM
        sta flcr              ;  in Flash Control Register

              ; Wait for >5us, then clear HVEN.
        LDA     #tnvh
        DBNZA   *
        clra                  ; clear HVEN control bit
        sta flcr              ;  in Flash Control Register

        ldhx _temp_sp         ; restore
        txs                   ;  Stack Pointer
        rts                   ; return

ProgramRamSize: equ     (*-_delay)

;********************************************************************
;  Command lookup table
;********************************************************************
_cmdtab:
        fcb 'B'
        fdb  _set_break
        fcb 'U'
        fdb  _clr_break
        fcb 'E'
        fdb  _medit
        fcb 'D'
        fdb  _dump
        fcb 'G'
        fdb  _go
        fcb 'N'
        fdb  _next
        fcb 'F'
        fdb _fill
        fcb 'R'
        fdb _prreg
        fcb 'L'
        fdb _do_dnload
        fcb 'H'
        fdb _help
        fcb 'C'
        fdb _do_mass_erase
        fcb 'A'
        fdb _disasm
        fcb 'X'
        fdb $8040
        fcb NUL

;*************************************************************
;     Prompts and Messages
;*************************************************************

_PROMPT:
              fcb CR,LF
              fcb "HCmon> "
              fcb NUL
_HEADING:
      fcb CR,LF,LF
      fcb "ADDR  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F"
      fcb CR,LF
      fcb "---- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --"
      fcb NUL
#if HYPERTERM
_MSG_WAITING:
              fcb " -waiting..."
              fcb NUL
#elseif
_MSG_WAITING:
              fcb " -waiting..."
              fcb CR,LF,NUL
#endif
_MSG_ERROR:
              fcb "  - error"
              fcb NUL
_MSG_BREAK:
              fcb CR,LF
              fcb "Break: "
              fcb NUL
_PWR_MSG:
              fcb CR,LF
              fcb "HC908 Monitor, rev 2a   Dec 2002,  G.Heron N2APB"
              fcb CR,LF,NUL
_ERR_MSG:
              fcb "Huh?"
              fcb NUL
_HELPLIST:
              fcb CR,LF,LF
              fcb "Monitor Commands:"
              fcb CR,LF,LF
              fcb "H Help"
              fcb CR,LF
              fcb "A ADDR Disassemble"
              fcb CR,LF
              fcb "B ADDR Set Break"
              fcb CR,LF
              fcb "U Undo Break"
              fcb CR,LF,LF
              fcb "D ADDR Dump"
              fcb CR,LF
              fcb "E ADDR Edit"
              fcb CR,LF
              fcb "F BEGIN END VALUE Fill"
              fcb CR,LF
              fcb "R Print Regs"
              fcb CR,LF,LF
              fcb "G ADDR Go"
              fcb CR,LF
              fcb "N Next"
              fcb CR,LF
              fcb "L Load Srec"
              fcb CR,LF
              fcb "C Clear Flash"
              fcb CR,LF
              fcb "X Goto User Application"
              fcb CR,LF
              fcb NUL

;*************************************************************
;  Register prompts

SP_MSG:
              fcb "SP="
              fcb NUL
CC_MSG:
              fcb " CC="
              fcb NUL
A_MSG:
              fcb " A="
              fcb NUL
H_MSG:
              fcb " H:X="
              fcb NUL
X_MSG:
              fcb ":"
              fcb NUL
PC1_MSG:
              fcb " -- PC="
              fcb NUL
PC2_MSG:      fcb NUL
END_MSG:      fcb "EE"

;************************************************************
#include "../utils.asm"
#include "./disasm08.asm"

;************************************************************
;   Vectors
;************************************************************
         org $ffd0

adc_vec:      fdb   $8000         ; ADC Conversion Complete vector to user jump table
keyboard_vec: fdb   $8003         ; Keyboard Vector to user jump table
scitx_vec:    fdb   $8006         ; SCI Transmit Vector to user jump table
scirx_vec:    fdb   $8009         ; SCI Receive Vector to user jump table
scierr_vec:   fdb   $800C         ; SCI Error Vector to user jump table
              rmb   4             ; RESERVED
timbch3_vec:  fdb   $800F         ; TIMB Channel 3 Vector to user jump table
timbch2_vec:  fdb   $8012         ; TIMB Channel 2 Vector to user jump table
spitx_vec:    fdb   $8015         ; SPI Transmit Vector to user jump table
spirx_vec:    fdb   $8018         ; SPI Receive Vector to user jump table
timb_of_vec:  fdb   $801B         ; TIMB Overflow Vector to user jump table
timb_ch1_vec: fdb   $801E         ; TIMB Channel 1 Vector to user jump table
timb_ch0_vec: fdb   $8021         ; TIMB Channel 0 Vector to user jump table
tima_of_vec:  fdb   $8024         ; TIMA Overflow Vector to user jump table
tima_ch3_vec: fdb   $8027         ; TIMA Channel 3 Vector to user jump table
tima_ch2_vec: fdb   $802A         ; TIMA Channel 2 Vector to user jump table
tima_ch1_vec: fdb   $802D         ; TIMA Channel 1 Vector to user jump table
tima_ch0_vec: fdb   $8030         ; TIMA Channel 0 Vector to user jump table
pit_vec:      fdb   $8033         ; PIT Vector to user jump table
pll_vec:      fdb   $8036         ; PLL Vector to user jump table
irq_veq:      fdb   $8039         ; ~IRQ1 Vector to user jump table
break_vec:    fdb   _break_pt     ; SWI break point vector
reset_vec:    fdb   _bootreset    ; Reset vector to start of Monitor
