检查数字是否在 8051 的范围内

Check if number is in range on 8051

我通过 UART 接收到一个字符,需要验证它是否是数字字符。

通常我会这样做

if (char >= '0' && char <= '9') { /* VALID */ }

但是,我必须在汇编中完成

我没有找到任何比较指令(所以我假设有none)。

我该怎么做?

    mov A, SBUF    ; load the number

    ; -- pseudocode --
    cmp A, #'0'    ; In AVR, I'd do it this way
    brlt fail      ; but I'm new to 8051
    cmp A, #'9'
    brge fail
    ; -- pseudocode --

    ; number is good

fail:

编辑:好的,这就是我现在拥有的,但它不起作用

;======================================================
; check if r1 is number char -> r0 = 1 or 0
;------------------------------------------------------
fn_isnum:
    PUSH acc
    PUSH 1

    MOV r1,A

    SUBB A,#'0'
    JC isnum_bad

    MOV A,r1

    SUBB A,#'9'+1
    JC isnum_bad

    POP 1
    POP acc

    MOV r0,#1
    RET 

isnum_bad:

    POP 1
    POP acc

    MOV r0,#0
    RET
;======================================================

利用this techniqueif (a >= '0' && a <= '9')可以转化为

if ((unsigned char)(a - '0') <= ('9'-'0'))

这样就省去了比较和跳转。现在只需比较一次就够了

结果可能是这样

    SUBB A, #'0'  ;  A = a - '0'
    CLR  C
    MOV  R1, A    ; R1 = a - '0'
    MOV  A, #9    ;  A = '9' - '0'
    SUBB A, R1    ;  C = 1 if ('9' - '0') < (a - '0')
    JC   bad:     ; jump when C != 0, i.e. !((a - '0') <= ('9' - '0'))
valid:
    ; do something
bad:

大多数现代编译器都知道如何优化此范围检查。我找不到 8051 在线编译器,也没有适用于它的离线编译器,但 AVR 足以提供演示。 AVR gcc 为 both the original condition and the transformed one

提供相同的输出
    mov r25,r24          ; input in r24
    subi r25,lo8(-(-48)) ; r25 = input - '0'
    ldi r24,lo8(1)       ; r24 = 1
    cpi r25,lo8(10)      ; if r25 < 10
    brlo .L2             ; jump to .L2
    ldi r24,lo8(0)       ; r24 = 0
.L2:
    ret                  ; return value in r24

更新:

Sample output for 8051 来自 SDCC

        mov     r7,dpl
        cjne    r7,#0x30,00110$
00110$:
        jc      00103$
        mov     a,r7
        add     a,#0xff - 0x39
        jnc     00104$
00103$:
        mov     r7,#0x00
        sjmp    00105$
00104$:
        mov     r7,#0x01
00105$:
        mov     dpl,r7
        ret

最简单的做法是用C 编译它并检查列表文件。这是我的编译器生成的结果。

MOV     A, SBUF
CLR     C
SUBB    A, #030H
JC      ?C0026
MOV     A, SBUF
SETB    C
SUBB    A, #039H
JNC     ?C0026

; Put instructions here to execute when the code is valid

?C0026: