; Utility subroutines for SuBAsm. print_hi: phb.q ; Preserve B. sbs #$10 ; Make room for the hex string buffer. and #0 ; Reset A. mov b, d ; Get the string buffer pointer. mov (b), #'$' ; Print the hex delimiter to the string buffer. inb ; Increment the string buffer pointer. lea d, (sp+1) ; Get the address of the hex string buffer. mov f, #$10 ; Set digit count to 16. jsr print_hex ; Print the address. mov.q (b), (d) ; Print the lower half of the hex string to the string buffer. mov.q (b+8), (d+8) ; Print the upper half of the hex string to the string buffer. add b, #$10 ; Add 16 to the index. mov.w (b), #': ' ; Print a colon, and space to the string buffer. add b, #2 ; Add two to the string buffer pointer. tba ; Return the string buffer pointer after the printed string. ads #$10 ; Cleanup the stack frame. plb.q ; Restore B. rts ; End of print_hi. print_lo: pha.q ; Preserve A. phb.q ; Preserve B. phx.q ; Preserve X. sbs #$33 ; Make room for the hex string buffer, and the normal string buffer. and #0 ; Reset A. tab ; Reset B. lea d, (sp+1) ; Get the address of the hex string buffer. lea x, (sp+3) ; Get the address of the string buffer. @loop: lea f, 2 ; Set the digit count to two. mov s, b ; Get the low nibble offset. jsr print_hex ; Print the low nibble offset. mov.w (x), (d) ; Place the hex digits in the string buffer. add x, #2 ; Add two to the string buffer pointer. inb ; Increment the nibble offset. cpb #$10 ; Are we at the last offset? bcs @end ; Yes, so we're done. @loop1: mov (x), #' ' ; No, so add a space to the string buffer. inx ; Increment the string buffer pointer. bra @loop ; Keep looping. @end: mov (x), #0 ; Null terminate the string buffer. lea d, (sp+3) ; Get the address of the string buffer. lea s, (buffer)+y ; Get the address of the screen buffer, at the current cursor position. ; jsr print_str ; Print the string buffer. jsr print_sfast ; Use the faster, but less robust print string routine. ads #$33 ; Cleanup the stack frame. plx.q ; Restore X. plb.q ; Restore B. pla.q ; Restore A. rts ; End of print_lo. print_chunk: pha.q ; Preserve A. phb.q ; Preserve B. phx.q ; Preserve X. phy.q ; Preserve Y. sbs #16 ; Make room for the hex string buffer. and #0 ; Reset A. tay ; Reset Y. ldy #2 ; Set the number of 8 byte chunks to read to 2. mov x, d ; Get the address of the string buffer. mov b, s ; Get the starting address. lea d, (sp+1) ; Get the address of the hex string buffer. ; xor s, s ; Reset S. @print_hex: lda #16 ; Set the hex string index to 16. mov f, a ; Set the digit count to 16. dey ; Decrement the chunk count. bng @end ; The chunk count is negative, so we're done. mov.q s, (b) ; Read 8 bytes from that address. jsr print_hex ; Print 8 bytes. add b, #8 ; Add 8 to the address. @loop: sub #2 ; Subtract two from the hex string index. mov.w (x), (d+a) ; Print the hex string to the string buffer. mov (x+2), #' ' ; Print a space to the string buffer. add x, #3 ; Add three to the string buffer pointer. cmp #0 ; Did we print 8 bytes? beq @print_hex ; Yes, so read 8 more bytes. bra @loop ; No, so keep looping. @end: mov (x-1), #0 ; Null terminate the string. ads #16 ; Cleanup the stack frame. ply.q ; Restore Y. plx.q ; Restore X. plb.q ; Restore B. pla.q ; Restore A. rts ; End of print_chunk. print_hex: pha.q ; Preserve A. phb.q ; Preserve B. phx.q ; Preserve X. phy.q ; Preserve Y. lea b, hex_char ; Get the address of the hex character table. mov a, f ; Get the digit count. set x, eq ; Set the auto digit count flag if so. lne #16 ; Also set the digit count to 16 if so. cmp #17 ; Is the digit count greater than 16? lcs #16 ; Set the digit count to 16 if so. add d, a ; Add the string pointer with the digit count. @loop: mov y, s ; No, so mask the low nibble of the value. and y, #$F ; dec d ; Decrement the string pointer. mov (d), (b+y) ; Place the hex digit character in the string. lsr s, #4 ; Get the next nibble. bne @loop1 ; No, so decrement the digit count. @isauto: cpx #1 ; Is the auto digit count flag set? beq @end ; Yes, so we're done. @loop1: dec ; Decrement the digit count. bne @loop ; The digit count is non zero, so keep looping. @end: ply.q ; Restore Y. plx.q ; Restore X. plb.q ; Restore B. pla.q ; Restore A. rts ; End of print_hex. strcmpg: lea strcmp ; Get the address of strcmp. mov.q d, ptr ; Get the first pointer. bra gargs ; Jump to the argument handler. strcaseg: lea strcasecmp ; Get the address of strcasecmp. mov.q d, ptr ; Get the first pointer. bra gargs ; Jump to the argument handler. gargs: mov s, a ; Use the value in A as the second arg. and #0 ; Reset a. tab ; Reset b. jsr (e) ; Call the pushed routine. rts ; End of gargs. strtoullg: ldb.q ptr3 ; Get the third pointer. phb.q ; Push the first arg. pha ; Push the second arg. and #0 ; Reset A. tab ; Reset B. jsr strtoull ; Call strtoull. tab ; Preserve the return value. pla ; Get the second arg back. pla.q ; Get the first arg back. tba ; Get the return value back. pha.q ; Preserve the return value. and #0 ; Reset A. tab ; Reset B. pla.q ; Get the return value back. rts ; End of strtoullg. isdelm2: ldx #0 ; Reset X. @loop: ldb dtab2, x ; Get the compare value. beq @other ; We hit the end of the table, so check for the others. cmp b ; Are they the same? beq @r1 ; Yes, so return 1. inx ; No, so increment the table index. bra @loop ; Keep looping. @other: ldx #0 ; Reset X. cmp #0 ; Is this a null terminator? beq @r1 ; Yes, so return 1. cmp #'\t' ; No, but is it a tab? beq @r2 ; Yes, so return 2. cmp #' ' ; No, but is it a space? beq @r2 ; Yes, so also return 2. @r0: lda #0 ; Return 0. rts ; End of isdelm2. @r1: ldx #0 ; Reset X. lda #1 ; Return 1. rts ; End of isdelm2. @r2: lda #2 ; Return 2. rts ; End of isdelm2. isdelm: ldx #0 ; Reset X. @loop: ldb dtab, x ; Get the compare value. beq @other ; We hit the end of the table, so check for the others. cmp b ; Are they the same? beq @rshft ; Yes, so return 1 << index. inx ; No, so increment the table index. bra @loop ; Keep looping. @other: ldx #0 ; Reset X. cmp #0 ; Is this a null terminator? beq @rshft ; Yes, so return 1. ldx #4 ; No, so set the shift amount to 4. cmp #'\t' ; Is this a tab? beq @rshft ; Yes, so return 16. ldx #0 ; No, so reset X. @r0: lda #0 ; Return 0. rts ; End of isdelm. @rshft: lda #1 ; Set up the bitshift. phx ; Push the shift value to stack. lsl sp+1 ; Return 1 << X. plx ; Pull the shift value off the stack. ldx #0 ; Reset X. rts ; End of isdelm. isesc: ldy.w idx0 ; Get the string index. lda (ptr), y ; Get the current character. cmp #'\\' ; Is it a backslash? bne @false ; No, so return false. @dec: dey ; Decrement the string index. lda (ptr), y ; Get the current character. iny ; Set the string index back. cmp #'\\' ; Is it a backslash? beq @false ; Yes, so return false. lda #1 ; No, so return true. rts ; End of isesc. @false: and #0 ; Return false. rts ; End of isesc. is_altok: sec ; Do a non borrowing subtract. sbc #12 ; Subtract 12 from the token. and #$FF ; Make sure the value is 8 bits. cmp #4 ; Is the token in between PTOK_B, and PTOK_P? bcc @r1 ; Yes, so return 1. beq @r1 ; @r0: lda #0 ; Return 0. rts ; End of is_altok. @r1: lda #1 ; Return 1. rts ; End of is_altok. get_ptok: ldx #0 ; Reset X. jsr tolower ; Conver the character to lowercase. @loop: ldb ptok_tab, x ; Get the compare value. beq @other ; We hit the end of the table, so check for the others. cmp b ; Are they the same? beq @rtab ; Yes, so return X. inx ; No, so increment the table index. bra @loop ; Keep looping. @rtab: txa ; Return X. rts ; End of get_ptok. @other: tab ; Preserve the character. jsr isdigit ; Is this character a digit? bne @rnum ; Yes, so return PTOK_NUM. tba ; No, so get the character back. jsr islower ; Is it an alphabetical character? bne @ralph ; Yes, so return PTOK_ALPH. lda #PTOK_OTHR ; No, so return PTOK_OTHR. rts ; End of get_ptok. @rnum: lda #PTOK_NUM ; Return PTOK_NUM. rts ; End of get_ptok. @ralph: lda #PTOK_ALPH ; Return PTOK_ALPH. rts ; End of get_ptok. get_ctrlidx: sub #8 ; Subtract 8 from the character, to get the index. tax ; Copy the index to X. and #0 ; Reset A. cpx #19 ; Are we within the range of the table? lea ct_rtb, x ; Get the address of the value to return. lcc (e) ; Read from the table if we're within the range of the table. leq (e) ; cmp #$7F ; Is this a delete character? leq #2 ; Return 2 if this is the delete character. rts ; End of get_ctrlidx. findramend: and #0 ; Reset A. @loop: mov a, (d) ; Preserve the value. mov (d), #MAGIC ; Write the magic number to the current end of RAM. cmp (d), #MAGIC ; Is the value in RAM, the same as the magic number we wrote? bne @moveback ; No, so move back until we find the last writable memory location. mov (d), a ; Yes, so restore the previous value. add.w d, #$4000 ; Increment the end of RAM pointer by 16K. bra @loop ; Keep looping. @moveback: dec d ; Decrement the end of RAM pointer. mov a, (d) ; Preserve the value. mov (d), #MAGIC ; Write the magic number to the current end of RAM. cmp (d), #MAGIC ; Is the value in RAM, the same as the magic number we wrote? bne @moveback ; No, so keep looping. mov (d), a ; Yes, so restore the previous value. @end: mov a, d ; Return the end of RAM pointer. rts ; End of findramend. ; get_index: Get the index of a given character from a string. ; Input: D = Pointer to string. S = Character to look for. F = Indexing mode. ; Output: A = Index of the character in the string, if found. ; Caller preserved registers: D, S, F. ; Callee preserved registers: B. ; ; Indexing modes: ; 0 = Increment mode. ; 1 = Boolean mode. ; 2 = Increment mode, plus one. get_index: phb.q ; Preserve B. and #0 ; Reset A. tab ; Reset B. cmp f, #2 ; Is the index starting at one? leq #1 ; Set the index to one if so. dec ; Decrement the index to account for incrementing at the start. @loop: inc ; Increment the index. mov b, (d+a) ; Are we at the end of the string? beq @is_bool ; Yes, so check if we're using boolean mode. @@loop: cmp s, b ; Is this character the same as the one we're looking for? bne @loop ; No, so keep looping. @is_bool: and f, f ; Are we using boolean mode? beq @end ; No, so we're done. @bool: cmp s, b ; Is this character the same as the one we're looking for? set a, eq ; Set the index to true if so. @end: plb.q ; Restore B. rts ; End of get_index. print_sfast: pha.q ; Preserve A. and #0 ; Reset A. @loop: cmp (d+a), #0 ; Did we hit the end of the string? beq @end ; Yes, so we're done. mov (s+a), (d+a) ; No, so print the character to the buffer. mov scr, (d+a) ; Print the character to the screen. inc ; Increment the index. bra @loop ; Keep looping. @end: pla.q ; Restore A. rts ; End of print_sfast.