我必须完成下面的程序框架,才能仅计算可分割数据区域中这些值的总和 乘以8,并将结果存储在寄存器r5中。我的程序必须能够处理任意数量的数据值 (在内存和32位整数范围限制内),并且用户必须只能更改值 在数据区域中,程序将继续正常运行。
THUMB
AREA RESET, DATA, READONLY
EXPORT Vectors
EXPORT Reset_Handler
Vectors
DCD 0x20001000 ; top of the stack
DCD Reset_Handler ; reset vector - where the program starts
AREA Task2Code, CODE, READONLY
ENTRY
Reset_Handler
num EQU 51
MOV r1,#0
MOV r5,#0
LDR r8,=sum_up
loop
MOV r2, r1, ROR #3 ; divide by 8
LDR r2,[r8],#4
ADD r5,r5,r2
ADD r1,r1,#1
CMP r1,#num
B loop
terminate
B terminate
sum_up
DCD -16,100,-456,7,-123,-42,126789,2349,-34,-2344,45,-45,-3345 ; example values
END
这是我到目前为止编写的代码,但是我无法运行它,也不知道如何正确地除以8,有人对此有任何想法吗?
答案 0 :(得分:4)
@Peter Cordes的answer对于使用班次划分的方式是全面而准确的。但是,要完成您的任务(“仅计算数据区域中被8整除的那些值的总和”),您实际上不需要将除以8。您只需要测试是否或不是数字可以被8整除。
您可能已经知道,任何可被8整除的数字的最低有效三位在其二进制表示形式中将为零,就像任何可被1000整除的数字的后三位数字均为十进制的零一样。幸运的是,它包括二进制的负数-仅是2的补码算术的加法。因此,您的任务归结为测试每个数字的最低有效三位是否全部为零。如果是,则该数字可被8除;如果不是,那么不是。
您要实现此目的的指令是TST
。该指令有效地对其自变量执行按位与运算,并根据结果设置状态标志,然后丢弃结果本身。就像没有目的地寄存器的ANDS
一样。通过使用值为0x7(二进制111)的TST
作为一个参数,如果另一个操作数可被8整除,则结果将为零,否则为非零;因此,如果另一个操作数可被8整除,则将置零标志,否则将其清除。
例如:
loop
; (somehow obtain the next number in r4 here)
TST r4, #0x7
BNE loop ; If the value in r4 is not divisible by 8, continue
ADD r5, r5, r4 ; Add the value in r4 to the sum in r5
B loop
该示例显然是不完整的(没有将值加载到r4中,并且最终分支是无条件的),但希望它将为您提供一个起点。
答案 1 :(得分:2)
旋转显然是不正确的,它将使低位移动到符号位位置。
您想右移,例如MOV r2, r1, ASR #3
,又称asr r2, r1, #3
还是您需要带符号的整数除法与C的舍入为零的行为相同?? (算术右移向-Infinity舍入,但是C风格的整数除法向零截断。)
如果是这样,可以使用符号位作为更正,以与编译器相同的方式实现。 Divide a signed integer by a power of 2。另请参见此x86示例Why does the compiler generate a right-shift by 31 bits when dividing by 2?。
或者只是look at ARM compiler output on the Godbolt compiler explorer:
int div8(int a) { return a/8; }
gcc -O3 -mcpu=cortex-m4
(缩略图模式的asm):
div8(int):
cmp r0, #0
it lt
addlt r0, r0, #7 @@ increase past the next multiple of 8 if it wasn't one
asrs r0, r0, #3 @@ arithmetic right-shift by 3
bx lr
clang的代码生成更加紧凑,我认为所有16位指令都不需要it
来确定其中之一:
div8(int):
asrs r1, r0, #31 @ copy the sign bit to all bits of r1
add.w r0, r0, r1, lsr #29 @ add 0 or 7 (logical shift right of all-ones or zeros)
asrs r0, r0, #3 @ r0 >>= 3
bx lr