用汇编程序求R6R7中的双字节有符号数的补码,并将结果存入R1R0

本文详细介绍如何使用汇编语言程序来求双字节有符号数的补码,并通过具体实例进行说明。针对正数和负数的不同情况,提供了具体的实现步骤及代码示例。

想必很多初学汇编的朋友都会碰到这种类型的题,下面我就详细的解答一下这道题,希望对大家有所帮助。

题目要求:用汇编程序求R6R7中的双字节有符号数的补码,并将结果存入R1R0。

(1)双字节有符号数求补码,首先要判断这个数的符号,如果是正数,那么它的补码就是它本身,如果是负数,那么就得求反、再加一。

这是基本思路,

举个例子

十进制:     R6=8FH,R7=3FH;

二进制:   1000 1111,0011 1111

很明显这是个负数,所以得先求反,再加1


(2)下面贴上代码:  

ORG 0000H

MOV A,#8FH

MOV R6,A

MOV A,#3FH

MOV R7,A ;上面这几段代码是给寄存器R6R7赋初值,大小可以自己定。



MOV A,R6

JNB ACC.7,NEXT ;判断R6的最高字节是否为0,如果为0,则跳转到NEXT后;否则,则顺序执行程序。

XRL A,#7FH ;异或运算,将寄存器A的值取反

MOV R1,A

MOV A,R7

CPL A

ADD A,#1 ;如果有进位,则进位标志C变为1

MOV R0,A

MOV A,#0 ;这里也可以用CLR A,将累加器A清零,

ADDC A,R1 ;寄存器R1+C(进位标志)

MOV R1,A

SJMP $

NEXT:  ;如果R6的最高位是0,则直接将R6赋给R1,R7赋给R0

MOV A,R7

MOV R0,A

MOV A,R6

MOV R1,A

SJMP $

END

(3)

下面是Keil中的运行结果:




; 1. 数据段,按照"分散加载文件-RW_RAM1 0x31000000"定义变量/常量 AREA Data, DATA, READWRITE ALIGN 4 op1 DCD 11 ; 操作数1:32位有符号整数(可修改) op2 DCD 4 ; 操作数2:32位有符号整数(可修改) op_type DCD 11 ; 操作类型:0=ADD,1=SUB,2=MUL,3=DIV,4=AND,5=ORR,6=EOR,7=LSL,8=LSR,9=FACT,10=FIB,11=SIN,12=MULTI result DCD 0 ; 结果存储(RW_RAM1中,便于观察目标) remainder DCD 0 ; 余数存储(RW_RAM1中) overflow_flag DCD 0 ; 溢出标志(0=无溢出,1=溢出)RW_RAM1中 n_fact DCD 4 ; 阶乘参数n(12以内) n_fib DCD 10 ; 斐波那契参数n(20以内) x_rad DCD 7854 ; sin(x)的x弧度值(5236代表0.5236弧度,精度0.0001) a_multi DCD 2 ; 多步运算(a+b)*c-d的参数a b_multi DCD 3 ; 多步运算参数b c_multi DCD 6 ; 多步运算参数c d_multi DCD 5 ; 多步运算参数d loop_cnt DCD 0 ; 循环计数器(默认值0)RW_RAM1中 ; 泰勒级数计算所需常量(适配ARMv4T,避免溢出) SCALE EQU 1000 ; 结果放大1000倍(保留3位小数) INPUT_SCALE EQU 1000 ; 输入x缩放为整数(x=实际值*1000,如0.5236→524) MAX_TERMS EQU 4 ; 减少项数(到x^7/7!,避免溢出,误差≤0.001) ; 预定义阶乘常量(适配INPUT_SCALE,避免乘法溢出) FACT_1 DCD 1 ; 1! = 1 FACT_3 DCD 6 ; 3! = 6 FACT_5 DCD 120 ; 5! = 120 FACT_7 DCD 5040 ; 7! = 5040(x^7/7! 已足够精确) ; 预计算 INPUT_SCALE^R9(32位可表示,避免溢出) SCALE_1 DCD 1000 ; INPUT_SCALE^1 = 1000 SCALE_3 DCD 1000000000 ; INPUT_SCALE^3 = 1e9(32位无符号可表示) SCALE_5 DCD 1000000 ; INPUT_SCALE^5 = 1e6(简化,不影响精度) SCALE_7 DCD 1000000000 ; INPUT_SCALE^7 = 1e9(简化,平衡精度和溢出) ; 2. 代码段,按照"分散加载文件-LR_ROM1 0x30000000"定义执行逻辑 AREA RESET, CODE, READONLY ENTRY ; 程序入口 PRESERVE8 ; 保持8字节栈对齐 ARM ; 使用ARMv4T指令集(无UDIV/SDIV) ; 异常向量表,自动定位在内存起始地址 0x30000000 Vectors B Reset_Handler ; 0x30000000:复位异常入口 B . ; 0x30000004:未定义指令异常 B . ; 0x30000008:软件中断异常 B . ; 0x3000000C:预取指令中止异常 B . ; 0x30000010:数据访问中止异常 B . ; 0x30000014:保留异常 B . ; 0x30000018:IRQ中断异常 B . ; 0x3000001C:FIQ快速中断异常 ; -------------------------- 工具函数:无符号除法(修正版) -------------------------- ; 功能:计算R0 / R1(无符号),返回商R0,余数R1 ; 输入:R0=被除数,R1=除数(非0) ; 输出:R0=商,R1=余数 udiv_armv4t CMP R1, #0 ; 检查除数是否为0 BEQ udiv_by_zero ; 除数为0,返回0 MOV R2, #0 ; 商初始化为0 MOV R3, R0 ; 保存原始被除数到R3 udiv_loop CMP R3, R1 ; 比较当前被除数和除数 BLT udiv_done ; 如果被除数 < 除数,结束 SUB R3, R3, R1 ; 被除数 = 被除数 - 除数 ADD R2, R2, #1 ; 商 = 商 + 1 B udiv_loop ; 继续循环 udiv_done MOV R0, R2 ; 商存入R0 MOV R1, R3 ; 余数存入R1 MOV PC, LR ; 返回 udiv_by_zero MOV R0, #0 ; 除数为0时,商=0 MOV R1, #0 ; 余数=0 MOV PC, LR ; 返回 ; -------------------------- 工具函数:有符号加法(避免无符号累加错误) -------------------------- ; 功能:R0 = R0 + R1(有符号),无溢出检查(因sin结果范围可控) sadd ADDS R0, R0, R1 MOV PC, LR ; -------------------------- 复位处理程序:初始化SDRAM + 跳转到main -------------------------- Reset_Handler LDR SP, =0x31001000 ; 设置栈指针(SDRAM高地址,避免覆盖数据段) B main ; -------------------------- 主程序 -------------------------- main ; 初始化溢出标志 LDR R0, =overflow_flag MOV R1, #0 STR R1, [R0] ; 读取操作类型 LDR R2, =op_type LDR R2, [R2] ; 分支跳转(适配ARMv4T,避免过多嵌套) CMP R2, #0 BEQ call_add CMP R2, #1 BEQ call_sub CMP R2, #2 BEQ call_mul CMP R2, #3 BEQ call_div CMP R2, #4 BEQ call_and CMP R2, #5 BEQ call_orr CMP R2, #6 BEQ call_eor CMP R2, #7 BEQ call_lsl CMP R2, #8 BEQ call_lsr CMP R2, #9 BEQ call_fact CMP R2, #10 BEQ call_fib CMP R2, #11 BEQ call_sin CMP R2, #12 BEQ call_multi B main ; 无效操作类型,重新循环 ; -------------------------- 基础运算 -------------------------- call_add LDR R0, =op1 LDR R0, [R0] LDR R1, =op2 LDR R1, [R1] ADDS R0, R0, R1 BVS set_overflow B store_result call_sub LDR R0, =op1 LDR R0, [R0] LDR R1, =op2 LDR R1, [R1] SUBS R0, R0, R1 BVS set_overflow B store_result call_mul LDR R0, =op1 LDR R0, [R0] LDR R1, =op2 LDR R1, [R1] SMULL R2, R3, R0, R1 ; 有符号乘法,R2=低32位,R3=高32位 MOV R4, R2, ASR #31 ; 符号扩展(低32位的符号位) CMP R3, R4 ; 高32位是否与符号位一致(无溢出) BEQ mul_ok LDR R2, =overflow_flag MOV R1, #1 STR R1, [R2] mul_ok MOV R0, R2 B store_result call_div LDR R0, =op1 ; R0=被除数(有符号) LDR R0, [R0] LDR R1, =op2 ; R1=除数(有符号) LDR R1, [R1] CMP R1, #0 BEQ div_overflow ; 除数为0,溢出 ; 步骤1:记录符号(商的符号=被除数符号 XOR 除数符号) MOV R4, #0 ; sign_flag=0(默认正) EOR R5, R0, R1 ; R5的最高位=符号异或结果 TST R5, #0x80000000 ; 检查最高位是否为1(符号不同) BNE set_sign_neg ; 符号不同,商为负 B sign_done set_sign_neg MOV R4, #1 ; sign_flag=1(商为负) sign_done ; 步骤2:将被除数和除数转为绝对值(补码取反+1) TST R0, #0x80000000 ; 被除数是否为负 BPL abs_dividend_ok MVN R0, R0 ; 取反 ADD R0, R0, #1 ; +1(绝对值) abs_dividend_ok TST R1, #0x80000000 ; 除数是否为负 BPL abs_divisor_ok MVN R1, R1 ADD R1, R1, #1 abs_divisor_ok ; 步骤3:调用无符号除法函数 STMFD SP!, {R4, R5, LR} ; 保存寄存器 BL udiv_armv4t ; R0=商,R1=余数 LDMFD SP!, {R4, R5, LR} ; 恢复寄存器 MOV R2, R0 ; R2 = 商(绝对值) MOV R3, R1 ; R3 = 余数(绝对值) ; 步骤4:修正商的符号 CMP R4, #1 ; 商是否为负 BNE quotient_ok MVN R2, R2 ADD R2, R2, #1 ; 商取补码(负数) quotient_ok ; 步骤5:修正余数的符号(与原被除数一致) LDR R5, =op1 ; 读取原被除数 LDR R5, [R5] TST R5, #0x80000000 ; 原被除数是否为负 BPL remainder_ok MVN R3, R3 ADD R3, R3, #1 ; 余数取补码(负数) remainder_ok ; 存储结果 LDR R6, =result STR R2, [R6] LDR R6, =remainder STR R3, [R6] B main div_overflow LDR R2, =overflow_flag MOV R1, #1 STR R1, [R2] B store_result call_and LDR R0, =op1 LDR R0, [R0] LDR R1, =op2 LDR R1, [R1] AND R0, R0, R1 B store_result call_orr LDR R0, =op1 LDR R0, [R0] LDR R1, =op2 LDR R1, [R1] ORR R0, R0, R1 B store_result call_eor LDR R0, =op1 LDR R0, [R0] LDR R1, =op2 LDR R1, [R1] EOR R0, R0, R1 B store_result call_lsl LDR R0, =op1 LDR R0, [R0] LDR R1, =op2 LDR R1, [R1] LSL R0, R0, R1 B store_result call_lsr LDR R0, =op1 LDR R0, [R0] LDR R1, =op2 LDR R1, [R1] LSR R0, R0, R1 B store_result ; -------------------------- 扩展功能 -------------------------- call_fact LDR R0, =n_fact LDR R0, [R0] MOV R1, #1 ; 结果初始化为1 MOV R2, #1 ; 计数器从1开始 fact_loop CMP R2, R0 BGT fact_done UMULL R3, R4, R1, R2 ; 无符号乘法,R3=低32位结果 MOV R1, R3 ; 更新结果 ADD R2, R2, #1 B fact_loop fact_done MOV R0, R1 B store_result call_fib LDR R0, =n_fib LDR R0, [R0] CMP R0, #0 BEQ fib_zero CMP R0, #1 BEQ fib_one MOV R1, #0 ; fib(n-2) MOV R2, #1 ; fib(n-1) MOV R3, #2 ; 当前n fib_loop ADD R4, R1, R2 ; fib(n) = fib(n-2) + fib(n-1) MOV R1, R2 MOV R2, R4 ADD R3, R3, #1 CMP R3, R0 BLE fib_loop MOV R0, R2 B store_result fib_zero MOV R0, #0 B store_result fib_one MOV R0, #1 B store_result ; -------------------------- 泰勒级数实现sin(x) -------------------------- call_sin STMFD SP!, {R4-R12, LR} ; 保存寄存器 ; 步骤1:读取输入x正确缩放(x_rad=5236 → 实际x=0.5236 → 缩放为524) LDR R0, =x_rad LDR R0, [R0] ; R0=5236(x_rad=实际x*10000) MOV R1, #10 ; 缩放转换:5236/10 = 523.6 → 四舍五入为524 BL udiv_armv4t ; R0=523(商),R1=6(余数) CMP R1, #5 BGE round_up ; 余数≥5,进1 B round_done round_up ADD R0, R0, #1 ; 523+1=524 round_done MOV R4, R0 ; R4=524(x=0.524,缩放1000倍) ; 步骤2:初始化泰勒级数参数 MOV R5, #0 ; R5=累加和(初始0,有符号) MOV R6, #1 ; R6=符号位(1=正,-1=负) MOV R7, #1 ; R7=当前项指数(1,3,5,7) MOV R8, #0 ; R8=项数计数器(0~3,共4项) sin_loop ; 子步骤1:加载当前项的阶乘和INPUT_SCALE^R7 CMP R8, #0 BEQ term_1 ; 第0项:x^1/1! CMP R8, #1 BEQ term_3 ; 第1项:-x^3/3! CMP R8, #2 BEQ term_5 ; 第2项:+x^5/5! CMP R8, #3 BEQ term_7 ; 第3项:-x^7/7! term_1 LDR R9, =FACT_1 ; R9=1!(地址) LDR R10, =SCALE_1 ; R10=INPUT_SCALE^1(地址) B term_calc term_3 LDR R9, =FACT_3 ; R9=3!(地址) LDR R10, =SCALE_3 ; R10=INPUT_SCALE^3(地址) B term_calc term_5 LDR R9, =FACT_5 ; R9=5!(地址) LDR R10, =SCALE_5 ; R10=INPUT_SCALE^5(地址) B term_calc term_7 LDR R9, =FACT_7 ; R9=7!(地址) LDR R10, =SCALE_7 ; R10=INPUT_SCALE^7(地址) term_calc LDR R9, [R9] ; 加载阶乘值 LDR R10, [R10] ; 加载缩放因子值 ; 子步骤2:计算当前项的分子 = x^R7(修正所有UMULL寄存器冲突) MOV R0, R4 ; R0=524 CMP R7, #1 BEQ pow_1 CMP R7, #3 BEQ pow_3 CMP R7, #5 BEQ pow_5 CMP R7, #7 BEQ pow_7 pow_1 MOV R11, R0 ; x^1 = 524 → R11=524 B pow_done pow_3 ; x^3 = 524 * 524 * 524 → 使用不同的目标寄存器 UMULL R0, R1, R4, R4 ; 524*524 = 274576 → 源R4-R4,目标R0-R1 UMULL R2, R3, R0, R4 ; 274576*524 = 143877824 → 源R0-R4,目标R2-R3 MOV R11, R2 ; R11=143877824 B pow_done pow_5 ; x^5 = x^3 * x^2 → 使用不同的目标寄存器 UMULL R0, R1, R11, R4 ; x^4 = x^3 * x → 源R11-R4,目标R0-R1 UMULL R2, R3, R0, R4 ; x^5 = x^4 * x → 源R0-R4,目标R2-R3 MOV R11, R2 ; R11=x^5 B pow_done pow_7 ; x^7 = x^5 * x^2 → 使用不同的目标寄存器 UMULL R0, R1, R11, R4 ; x^6 = x^5 * x → 源R11-R4,目标R0-R1 UMULL R2, R3, R0, R4 ; x^7 = x^6 * x → 源R0-R4,目标R2-R3 MOV R11, R2 ; R11=x^7 pow_done ; 子步骤3:计算当前项的分母 = INPUT_SCALE^R7 * 阶乘 UMULL R0, R1, R10, R9 ; 分母 = 缩放因子 * 阶乘 → 源R10-R9,目标R0-R1 MOV R12, R0 ; R12=除数 ; 子步骤4:计算当前项 = (x^R7 * SCALE) / 分母 MOV R0, R11 ; 分子 = x^R7 MOV R1, #SCALE ; 缩放因子 UMULL R2, R3, R0, R1 ; 分子 * SCALE → 源R0-R1,目标R2-R3 MOV R0, R2 ; 被除数 MOV R1, R12 ; 除数 BL udiv_armv4t ; R0=项的绝对值,R1=余数 ; 子步骤5:应用符号位 CMP R6, #1 BEQ term_pos ; 正号 → 直接保留 ; 负号 → 取补码 MVN R0, R0 ADD R0, R0, #1 term_pos ; 子步骤6:有符号累加当前项 MOV R1, R0 ; R1=当前项 MOV R0, R5 ; R0=累加和 BL sadd ; 有符号加法 MOV R5, R0 ; 更新累加和 ; 子步骤7:更新参数 CMP R6, #1 BEQ set_neg MOV R6, #1 ; 当前为-1 → 转为1 B sign_updated set_neg MVN R6, #0 ; 1 → -1 sign_updated ADD R7, R7, #2 ; 指数+2 ADD R8, R8, #1 ; 项数+1 CMP R8, #MAX_TERMS ; 是否达到4项 BLT sin_loop ; 继续循环 ; 步骤3:结果范围检查 MOV R0, R5 CMP R0, #-1000 BLT sin_overflow CMP R0, #1000 BGT sin_overflow B sin_store sin_overflow ; 溢出处理 LDR R2, =overflow_flag MOV R1, #1 STR R1, [R2] MOV R0, #0 sin_store LDMFD SP!, {R4-R12, LR} ; 恢复寄存器 B store_result ; -------------------------- 多步运算 -------------------------- call_multi LDR R0, =a_multi LDR R0, [R0] LDR R1, =b_multi LDR R1, [R1] ADD R2, R0, R1 ; a + b LDR R0, =c_multi LDR R0, [R0] UMULL R3, R4, R2, R0 ; (a + b) * c MOV R2, R3 ; 更新结果 LDR R0, =d_multi LDR R0, [R0] SUB R0, R2, R0 ; (a + b) * c - d B store_result ; -------------------------- 溢出处理 -------------------------- set_overflow LDR R2, =overflow_flag MOV R1, #1 STR R1, [R2] B store_result ; -------------------------- 存储结果 -------------------------- store_result LDR R2, =result STR R0, [R2] B main END 这个代码在keil软件上调试的时候应该怎么调试
最新发布
11-14
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值