;***************************************************************
;                                                              *
;  utils.s  -- General purpose utilities (Assembler)           *
;                                                              *
;  v0.9   01/06/2003    Formatted for jump table creation      *
;                                                              *
;**************************************************************/

;***************************************************************
;     _sp_gets  -- Gets string. If 1st char a space, it exits

_sp_gets:
      pshhx
      psha
      ldhx #_inbuf
      jsr _getch
      cmp #SPACE
      beq cancel_gets
      cmp #BS
      beq cancel_gets
      bra first_gets

;***************************************************************
;  _gets -- Receive a String, No Interrupt Routine
;           Returns carry set if ^C, or ESC

_gets:
      pshhx
      psha
      ldhx #_inbuf
inrlp:                          ; Fill receiver buffer with spaces
      clr ,x
      aix #1
      cphx #(_inbuf+RXBLEN)
      bne inrlp
      ldhx #_inbuf
wt_nxt_char:
      sta copctl                ; strobe Watch dog timer
      brclr SCRF,scs1,wt_nxt_char
      lda scdr                ; Read in byte
      jsr _putch
first_gets:
      cmp #CR
      bne notcr                 ; Is the entry over? (CR received)
                                ; If so, terminate entry with a null
      clr ,x                    ; Store null in buffer
      cphx #_inbuf
      bne rxdn_ok               ; If buffer not empty, exit with carry clear
      bra rxdn_err              ; If buffer empty, exit with carry set
notcr:
      cmp #$03                 ; ^C hit?
      bne not_cancel            ; If so store and buffer and terminate entry
cancel_gets:
      sta _inbuf
      clra
      sta _inbuf+1
rxdn_err:
      sec
      bra rxdn
not_cancel:
      cmp #$08
      bne notbs                 ; Is it a back space? (BS received)
      cphx #_inbuf
      beq rx_cancel             ; Don't baskspace past beginning
      aix #-1
      bra wt_nxt_char
notbs:
      sta ,x                  ; Store char in buffer
      aix #1
      cphx #_inbuf+RXBLEN-1      ; Is buffer full
      bne wt_nxt_char
rx_cancel:
      clr ,x
rxdn_ok:
      clc
rxdn:
      pula
      pulhx
      rts

;***************************************************************
;     _ahex2b --  Converts 2 ascii hex (h:x-reg) encodes byte
;                                to one byte hex (a-reg)
_ahex2b:
      txa
      bsr _a2nibhex     ; Convert low byte to ascii
      psha
      tha
      bsr _a2nibhex     ; Convert high byte to ascii
      nsa               ; put high byte in high nibble
      add 1,sp          ; Combine low and high nibbles
      pulx
      rts

;***************************************************************
;     _a2nibhex -- Convert ASCII Byte to hex nibble.

_a2nibhex:
      cmp #'9'       ; If Ascii A-F, you need to add 9 to
      bls ah1        ; convert to hex, ie, A(41) + 9 -> 4A -> 0A
      add #$09
ah1:
      and #$0F
      rts

;***************************************************************
;     _dblchar --  passed a byte in a register
;                returns ascii encoded chars in h-x registers

_dblchar:
      psha
      bsr _nib_to_asc
      tax
      pula
dblow:
      nsa
      bsr _nib_to_asc
      tah
      rts

;***************************************************************
;     _nib_to_asc -- Convert low nibble to ASCII encoded Hex

_nib_to_asc:
      and #$0F
      ora #$30
      cmp #$39
      ble dbend
      add #$07
dbend:
      rts

;***************************************************************
;     _comma_sp -- Output ,sp

_comma_sp:
      psha
      bsr _pr_comma
      lda #'s'
      bsr _putch
      lda #'p'
      bra out_byte

;***************************************************************
;     _pr_letter_x -- Output the letter X (X)

_pr_letter_x:
      psha
      lda #'x'
      bra out_byte

;--------------------------------
;     _pr_pound -- Output a pound sign (#)

_pr_pound:
      psha
      lda #'#'
      bra out_byte

;--------------------------------
;     _pr_comma -- Output a comma

_pr_comma:
      psha
      lda #','
      bra out_byte

;--------------------------------
;     _crlf -- Output a cr & lf

_crlf:
      psha
      lda #CR
      bsr _putch
      lda #LF
      bra out_byte

;--------------------------------
;     _sp_byte -- Prints a byte and then a space

_byte_sp:
      jsr _pbyte

;--------------------------------
;     _space -- Output a space

_space:
      psha
      lda #SPACE
out_byte:
      bsr _putch
      pula
      rts

;***************************************************************
;     _pr_nibble -- Output Ascii encoded low nibble

_pr_nibble:
      jsr _nib_to_asc

;--------------------------------
;      _putch -- Put a char, Nn ints

_putch:
wt_putch:
      sta copctl                   ; strobe Watch dog timer
      brclr SCTE,scs1,wt_putch     ;TDRE = 1 ?
      sta scdr                     ;OK, send
      rts

;***************************************************************
;     _pwordx -- Output 16 bit number pointed to by h:x-reg as 4 ascii chars
;
_pwordx:
      lda ,x
      bsr _pbyte
      lda 1,x
      bsr _pbyte
      rts

;***************************************************************
;     _pword -- Output 16 bit number in h:x-reg as 4 ascii chars
;
_pword:
      pshhx
      tha
      bsr _pbyte
      txa
      bsr _pbyte
      pulhx
      rts

;***************************************************************
;     _pbyte_sp -- Output Ascii encoded byte, No int.
;                                    and a space
;
_pbyte_sp:
      bsr _space
      bra _pbyte

;--------------------------------
;     pbytex  -- Put a byte pointed by x-reg

_pbytex:
      lda ,x

;--------------------------------
;     _pbyte -- Output Ascii encoded byte, No int.

_pbyte:
      pshhx
      jsr _dblchar
      tha
      bsr _putch
      txa
      bsr _putch
      pulhx
      rts

;***************************************************************
;     _ischar -- Checks for char, returns it in b-reg, =0 if none

_ischar:
      clra
      sta copctl
      brclr SCRF,scs1,no_char   ;SCRF = 1 ?
      lda scdr                  ;OK, get
no_char:
        rts

;***************************************************************
;     _getchne -- get a character, no echo, returns in a-reg
;             returns carry set if ESC or CTRL-C

_getchne:
      sta copctl
      brclr SCRF,scs1,_getchne   ;SCRF = 1 ?
      lda scdr                   ;OK, get
      bra no_geco

;--------------------------------
;     _getch -- get a character, echo, returns in a-reg
;             returns carry set if ESC or CTRL-C

_getch:
      sta copctl
      brclr SCRF,scs1,_getch     ;SCRF = 1 ?
      lda scdr                   ;OK, get
      bsr _putch
no_geco:
      clc
      cmp #ESC
      beq gc_can
      cmp #$0C
      bne egchar
gc_can:
      sec
egchar:
      rts

;***************************************************************
;     _do_again  -- Returns z set(zero) if again, clear if end

_do_again:
      bsr _getch
      cmp #SPACE
      beq yep_again
      cmp #CR
      bne _do_again
      tsta
yep_again:
      rts

;***************************************************************
;     _puts --  This subroutine will output the null teminated string
;               pointed to by H:X to the SCI.
;
;   Calling convention:
;       ldhx    #string
;       jsr     _puts
;
;   Returns:    nothing
;
;   Changes:    H:X

puts_lp:
        sta copctl                       ; strobe Watch dog timer
        brclr   SCTE,scs1,puts_lp        ; wait until SCI transmitter is empty
        mov     x+,scdr                  ; output character to the SCI and advance pointer
_puts:
        tst     ,x                       ; test string character
        bne     puts_lp                  ; loop back if not null
        rts                              ; else, return

;***************************************************************
;   GetHexByte
;       This subroutine retrieves two ASCII bytes via the SCI and converts
;       (packs) them into one hex byte, which is returned in ACC.
;
;   Calling convention:
;       jsr     GetHexByte
;
;   Returns:    CCRZ= 1 if valid hex byte retrieved.  Otherwise, CCRZ= 0.
;               ACC= data
;
;   Changes:    ACC

GetHexByte:
        bsr     _getchne          ; get msb character from the SCI
#if   HYPERTERM
#elseif
          jsr     _putch            ; echo it back
#endif
        bsr     _ishex             ; check if valid ASCII hex character
        beq     GetHexByte2       ; exit if not
        bsr     ToHex             ; convert ASCII hex character to hex value
        nsa                       ; swap lower nibble up
        psha                      ; save temporarily
        bsr     _getchne          ; get lsb character from the SCI
#if   HYPERTERM
#elseif
          jsr     _putch            ; echo it back
#endif
        bsr     _ishex            ; check if valid ASCII hex character
        beq     GetHexByte1       ; exit if not
        bsr     ToHex             ; convert ASCII hex character to hex value
        add     1,sp              ; combine msb and lsb nibbles
        bit     #0                ; CCRZ= 1
GetHexByte1:
        ais     #1                ; deallocate local variable
GetHexByte2:
        rts                       ; return

;***************************************************************
;     _get_atbl -- Look up address in table
;        Passed: byte to compare in a-reg
;                table address in h:x reg
;                   WARNING: last table entry must be null
;        Returns: Carry set if found, clear if not
;                 If found, returns value in address in h:x reg

_get_atbl:
      cmp ,x
      bne not_match
      lda 1,x
      psha
      lda 2,x
      tax
      pulh
      sec
      rts
not_match:
      aix #3
      tst ,x
      bne _get_atbl
      clc
      rts

;***************************************************************
;   ToHex
;       This subroutine converts the ASCII hex value passed in ACC to a
;       binary hex value.
;
;   Calling convention:
;       lda     data
;       jsr     ToHex
;
;   Returns:    ACC= data.
;
;   Changes:    ACC

ToHex:
        sub     #'0'              ; adjust first by subtracting '0'
        cmp     #9T                ; check if value was between '0' to '9'
        bls     ToHex1            ; exit if so
        sub     #7                ; else, adjust for value between 'A' to 'F'
ToHex1:
        rts                       ; return

;***************************************************************
;      _ishex -- Tests if it is an ascii hex
;                              Returns char if yes
;                              Returns 0 if no

_ishex:
      cmp #'0'
      blo nothex
      cmp #'9'
      bls yeshex
      and #$DF
      cmp #'F'
      bhi nothex
      cmp #'A'
      blo nothex
yeshex:
      tsta
      rts
nothex:
      clra
      rts

;***************************************************************
;     clr_spaces -- Increments x:h pointer past spaces

_clr_spaces:
      psha
cl_sp_lp:
      lda ,x
      cmp #SPACE
      bne not_sp
      aix #1
      bra cl_sp_lp
not_sp:
      pula
      rts

;***************************************************************
;   _first_hex --  Gets 1st parameter in buffer: 4 or a-reg hex chars
;   _next_hex --   Gets successive parameters in buffer: 4 or a-reg hex chars
;                  returns number in X-reg & carry clear if ok
;                     if error or cancel, set carry

_next_hex:
        lda _hbufpos
        tah
        ldx _hbufpos+1
        incx
        bra _again_hex
_first_hex:
        ldhx #_inbuf+1
_again_hex:
        bsr _clr_spaces
        bra _readhex

;--------------------------------
;   _gethex --  Gets up to 4  or a-reg length digit number,
;                  returns number in X-reg & carry clear if ok
;                     if error or cancel, set carry

_gethex:
      jsr _sp_gets
      bcs buf_can
      ldhx #_inbuf
_readhex:
      clra
      pshh
      pshx
numck_lp:
      psha
      lda ,x
      beq end_num_str
      cmp #SPACE
      beq end_num_str
      jsr _ishex
      pula
      beq err_can
      aix #1
      inca
      cmp #$05
      bne numck_lp
      bra err_can
end_num_str:
      tha
      sta _hbufpos
      stx _hbufpos+1
      pula
      tsta
      beq err_can
gnumok:
      pulx
      pulh
      cmp #$04
      beq gcv4
      cmp #$03
      beq gcv3
      cmp #$02
      beq gcv2
      bra gcv1
gcv4:
      pshx
      pshh
      lda  ,x
      ldx 1,x
      tah
gcv3_cut:
      jsr _ahex2b
      pulh
      pulx
      psha
      lda  2,x
      ldx 3,x
      tah
      jsr _ahex2b
      tax
      pulh
      bra gvc_end
gcv3:
      aix #-1
      pshx
      pshh
      lda #'0'
      ldx 1,x
      tah
      bra gcv3_cut
gcv2:
      lda  ,x
      ldx 1,x
      tah
      bra gcv1a
gcv1:
      ldhx #0
      ldx ,x
gcv1a:
      jsr _ahex2b
      ldhx #0
      tax
gvc_end:
      clc
      rts
err_can:
      pulx
      pulh
buf_can:
      sec
      rts
