寄存器低8位的ARM奇偶校验

问题描述 投票:1回答:2

我在使用汇编语言时遇到了一些困难,不幸的是,当我在Google上搜索信息时,找不到任何可以帮助我解决问题的信息。我已经编写了这段代码,我正在寻求帮助,以查看是否有一种方法可以使它更简单(如果可能)。另外,如果评论有误,请让我知道。

        NAME main
        PUBLIC main
        SECTION .text: CODE (2)
        THUMB

main    
        LDR R4, =0x0097         ; R4 = 97 in hex 
        BL SUBROUTINE           ; Go to Subroutine

STOP    B STOP

SUBROUTINE
        MOV R1, #1              ; Initialize R1 to 1        
        MOV R2, #0              ; Initialize R2 to 0        
        MOV R0, #0              ; Initialize R0 to 0        
        PUSH {R4}               

LOOP
        CMP R0, #8              ; Bits counter
        BEQ DONE                ; Go to DONE R0 = 8
        ADD R0, R0, #1          ; Calculates the bits
        AND R3, R4, R1          ; Checks if R3 = R4
        CMP R3, #1              ; Comparing result with 1
        BEQ ONE                 ; Jump to ONE
        LSR R4, R4, #1          ; Right shift by 1
        B LOOP

ONE
        ADD R6, R6, #1          ; Saving #1 in R6
        LSR R4, R4, #1          ; Right shift by 1
        B LOOP

RETURN0
        MOV R2, #0              
        POP {R4}
        B STOP

RETURN1
        MOV R2, #1
        POP {R4}
        B STOP

DONE
        CMP R6, #2
        BEQ RETURN0
        CMP R6, #4
        BEQ RETURN0
        CMP R6, #6
        BEQ RETURN0
        CMP R8, #8
        BEQ RETURN0
        B RETURN1

        END

任务如下:该子例程在寄存器R4中具有输入参数,并提供返回值寄存器R2中的值。该子例程将检查8个最小的奇偶校验输入参数的有效位。如果奇偶校验为偶数,则值为0为返回,如果奇偶校验为奇数,则返回值1。均等意味着一的数目是偶数,一的数目是奇数奇偶校验很奇怪。

提前感谢

assembly arm parity
2个回答
3
投票

您的编程风格已经非常不错,您可以对代码进行彻底注释。这非常有价值,您应该继续做。该算法本身看似正确,并且可以接受,但是可以更有效地实现。

编写高效的汇编代码时,最重要的事情是了解您要为其编程的体系结构的指令集。您的代码是为ARM编写的,具有许多有用的指令和功能以加快处理速度。让我们从一些基本改进入手。

首先,您使用此序列隔离R4的最低有效位,然后检查其是否为非零:

        ADD R0, R0, #1          ; Calculates the bits
        AND R3, R4, R1          ; Checks if R3 = R4
        CMP R3, #1              ; Comparing result with 1
        BEQ ONE                 ; Jump to ONE

这可以更有效地完成。首先,请注意,可以将立即数与AND指令一起使用,因此无需为此在寄存器中保留1:

        AND   R3, R4, #1

下一个,而不是将按位AND的结果与#1进行比较,您可以告诉处理器直接根据AND指令的结果设置标志。如果结果为零,则将其设置为零(可能还有其他标志,不要太在意),因此您可以立即跳转到结果。

        ANDS  R3, R4, #1        ; check if least significant bit set in R4
        BNE   ONE               ; jump to ONE if it is

现在,此ANDS执行作业,但是不必要地将其结果写入R3。我们真的不需要那里。快速浏览指令集引用会告诉我们TSTANDS的作用相同,但是只设置标志就丢弃了结果。这正是我们想要的。

        TST   R4, #1            ; check if least signficant bit set in R4
        BNE   ONE               ; jump to ONE if it is

现在,我们接下来要做的就是摆脱该条件分支。 ONE分支中代码之间的唯一区别是,它递增R6。代替条件分支,我们仅在设置了零标志时才可以使用ARM的条件执行功能执行ADD指令:

        TST   R4, #1             ; check if least significant bit set in R4
        ADDNE R6, R6, #1         ; increment R6 if it is

这使代码效率更高!通过将TST合并到LSR指令中,我们甚至可以进一步改进。看,如果我们告诉LSR设置标志,它将进位标志设置为移出的最后一位。这正是我们感兴趣的!这样我们就可以做到

        LSRS  R4, R4, #1         ; shift R4 to the right and set flags
        ADDCS R6, R6, #1         ; increment R6 if a 1 was shifted out

请注意,在其他没有条件执行的体系结构上,您可以使用带进位加法指令达到与ADDCS R6, R6, #1类似的效果:

        ADC   R6, R6, #0         ; add 1 to R6 if carry is set

除了设置进位标志之外,如果结果为零,LSRS还将设置零标志。因此,如果我们简单地迭代直到R4中的所有位都被移出,则可以省去循环计数器,从而为我们节省了寄存器和一堆指令。请注意,如果在R4中设置了任何额外的位(除了检查的最低8位之外),这可能不会产生正确的结果,因此您可能想先用AND R4, R4, #0xff屏蔽掉它们。这是代码:

LOOP:   LSRS  R4, R4, #1         ; shift R4 to the right and set flags
        ADDCS R6, R6, #1         ; increment R6 if a 1 was shifted out
        BNE   LOOP               ; loop until R4 is 0.

您可以类似地优化DONE部分中的代码:本质上,您只需检查R6是偶数还是奇数,然后返回1如果是奇数或0如果是偶数。您可以用一个测试来代替整个跳跃过程:

        TST   R6, #1             ; set the zero flag if R6 is even
        BEQ   RETURN0            ; return 0 if even
        B     RETURN1            ; otherwise return 1

但是,请注意,这基本上与返回R6的最低有效位相同,因此您可以通过以下方式替换整个代码:>

        AND   R0, R6, #1         ; set R0 to 1 if R6 is odd, 0 if R6 is even
        POP   {R4}
        B     STOP

这有点短,不是吗?

现在需要进行一些算法上的改进:您的代码可以解决问题,但确实很慢,因为每个循环执行一次迭代。一种更快的方法是使用XOR指令将位压缩在一起。这样一来,我们只需3个步骤即可计算奇偶校验,而不是像您的代码那样计算8个奇偶校验:

        LSR   R3, R6, #4        ; keep a copy of R6 shifted by 4 places
        EOR   R6, R6, R3        ; and xor it into R6
        LSR   R3, R6, #2
        EOR   R6, R6, R3        ; same but shifted by 2 places
        LSR   R3, R6, #1
        EOR   R6, R6, R3        ; same but shifted by 1 place
        AND   R0, R6, #1        ; isolate parity

这可以使用移位的操作数进一步改进,这是ARM的另一个特定功能:

        EOR   R6, R6, R6, LSR #4 ; xor R6 with R6 shifted right 4 places
        EOR   R6, R6, R6, LSR #2 ; xor R6 with R6 shifted right 2 places
        EOR   R6, R6, R6, LSR #1 ; xor R6 with R6 shifted right 1 place
        AND   R0, R6, #1         ; isolate parity

这是通常不使用任何指令集扩展的最快方法。如果您有足够先进的处理器,则可以使用CNT指令一步计算位数,但是,这在这里还是不值得的。


1
投票

下一次使用CODE(编辑器中的花括号)代替打印屏幕(例如,您无法从prtscn复制粘贴)。我从未使用过ARM汇编语言,但会使用这种方法:

© www.soinside.com 2019 - 2024. All rights reserved.