...
which removes the need for labels.
Damn, BitWise, you rather neatly cleaned that up that code with assembler directives. Sorry for the delay in my reply. I don't always get email notifications when someone post a response.
Code: Select all
dex ; Decrement X register
Code: Select all
dex ; Decrement loop counter
Code: Select all
dex ; Decrement X register
Code: Select all
; Convert ASCII character to binary number in bases up to 41.
; This translates A-Z[\]^_ and a-z{|}~DEL as 10, 11...40.
; The caller must check the returned value if the intended base was
; less than 41.
;
; A: (written) ASCII character to convert; binary number on return
; N flag: (written) clear on success, set on error.
; X, Y: (preserved)
;
convascdigit
cmp #'9'+1
bcs .letter ; >'9', convert letter
sbc #'0'-1 ; convert digit; if <'0', N flag set for error
rts ; N clear, no error
.letter
and #%11011111 ; clear bit 5 to convert to upper-case
bmi .exit ; high bit set, error
sbc #'A'-$0A
cmp #$0A ; if <$0A, set N flag to indicate error
.exit rts
Code: Select all
; Convert ASCII character to binary number in bases up to 41.
; This translates A-Z[\]^_ and a-z{|}~DEL as 10, 11...40.
; The caller must check the returned value if the intended base was
; less than 41.
;
; A: (w) ASCII character to convert; binary number on return
; N flag: (w) clear on success, set on error.
; X, Y: (p)
;
convascdigit
; This routine has extra explanation for 6502 beginners.
cmp #'9'+1
bcs .letter ; >'9', convert letter
; At this point we know that the carry is clear, better thought
; of as the borrow being set. Rather than use an extra instr
; to set the carry, we instead subtract 1 from the subtrahend
; because the set borrow will also be subtracted from the result.
sbc #'0'-1 ; convert digit; if <'0', N flag set for error
; Normally for an unsigned comparison we'd check to see if the
; carry is clear, i.e., the borrow was used, to determine
; whether our result was negative. We can't do this here to see
; if our char was < '0' because of the optimization above. But
; it's safe to check the N flag because we know from the check at
; the start that the char was ≤ $39 ('9') and so this will
; always produce a result between $39-$30=$09 and $00-$30=-$30
; ($D0 in two's complement), all values of which are negative.
; Since the N flag is our error code, we need not even BMI;
; just let the N flag pass through.
rts ; N clear, no error
.letter
and #%11011111 ; clear bit 5 to convert to upper-case
; Now the char is in one of two ranges:
; $3A-$40 chars between '9' and 'A'
; $40-$5F A-Z and punctuation after ([\]^_)
; $80-$FF chars above DEL
; We check the N flag here to see if the high bit is set, which
; means the character is invalid. We have to do the AND first
; because the N bit from the CMP test is based on the result
; of the CMP subtraction.
bmi .exit ; high bit set, error
; We subtract 'A'-$0A to bring it down to the $00-$28 range,
; No SEC is needed before this SBC; we branched here because the
; carry was already set and AND does not affect the carry.
sbc #'A'-$0A
; Values less than $0A are invalid, so error out on those.
cmp #$0A ; if <$0A, set N flag to indicate error
; The result of SBC is signed, so it may be, e.g., -$01 = $FF.
; However, CMP does only unsigned comparisons so the carry flag
; would be set (indicating ≥) rather than clear (indicating <)
; for those "negative" results. But since we know our value in A
; is in range $00-$28, the most negative possible result produced
; by the SBC is -$28 = $D8, so we can check the N flag instead.
; Since the N flag is our error code, we need not even BMI.
.exit rts