嵌入式系统基础学习知识原理及其应用题目要求程序代码.doc

收藏

编号:2606079    类型:共享资源    大小:93.52KB    格式:DOC    上传时间:2020-04-23
8
金币
关 键 词:
嵌入式 系统 基础 学习 知识 原理 及其 应用 利用 运用 题目 要求 请求 程序代码
资源描述:
.\ 《嵌入式系统原理及应用》 作业题目 作业1 一、调试下面的程序,并回答问题。 .global _start .text _start: LDR SP, =src LDMFD SP!,{R0-R6} STMFD SP!,{R0-R6} LDMFD SP!,{R3} LDMFD SP!,{R4} LDMFD SP!,{R5} LDMFD SP!,{R6} LDMFD SP!,{R0} LDMFD SP!,{R1} LDMFD SP!,{R2} stop: b stop .ltorg src: .long 1,2,3,4,5,6,7 .end 问:该程序完成了什么功能? 答: 该程序完成的功能:先把数据区堆栈中的1~7这七个数据送给R0~R0寄存器,然后又把寄存器列表中的R0~R7存入堆栈,然后又依次把堆栈中的1~7这七个数送给R3~R6,R0~R2,然后程序就结束了,在取数和存数的过程中。堆栈指针sp由0x0000变到0x8030再到0x804c,然后到0x8030,然后依次加4,最后到0x804c;程序计数器R15(PC)由0x8000地址依次加4 。 二、LDMFD,STMFD伪代码实现的原理。 答: 指令STMFD和LDMFD分析: 根据ATPCS规则,我们一般使用FD(Full Descending)类型的数据栈!所以经常使用的指令就有STMFD和LDMFD, 通过ARM对于栈操作和批量Load/Store指令寻址方式,可以知道指令STMFD和LDMFD的地址计算方法: STMFD指令的寻址方式为事后递减方式(DB) 而DB寻址方式实际内存地址为: start_address = Rn - (Number_Of_Set_Bits_In(register_list)*4) end_address = Rn - 4 STM指令操作的伪代码: if ConditionPassed(cond) then address = start_address for i = 0 to 15 if register_list[i] == 1 Memory[address] = Ri address = address + 4 有上面两个伪代码可以得出 STMFD SP!,{R0-R7,LR} 的伪代码如下: SP = SP - 94; address =SP; for i = 0 to 7 Memory[address] = Ri; address = address + 4; Memory[address] = LR; LDMFD指令的寻址方式为事后递增方式(IA) IA内存的实际地址的伪代码 start_address = Rn end_address = Rn + (Number_of_set_bits_in(register_list)*4) - 4 LDM指令操作的伪代码(未考虑PC寄存器): if ConditionPassed(cond) then address = start_address for i = 0 to 15 if register_list[i] == 1 Ri = Memory[address,4] address = address + 4 所以LDMFD SP!,{R0-R7,PC}^ (;恢复现场,异常处理返回)伪代码是: address = SP; for i = 0 to 7 Ri = Memory[address ,4] address = address + 4; SP = address; 作业2 一、用移位操作完成(R0)*10运算。 参考程序: .text .global _start _start: mov R0,#10 mov R1,R0,LSL #3 mov R2,R0,LSL #1 add R3,R1,R2 stop: B stop .end 二、已知数据缓冲池中有两组数据x和y,每组中有3个数据(例如x: 90,60,30,y: 60,40,20),将x中的数据减去y中的数据,最后将两组数相减得到的结果送回到x中去! 参考代码: .text .global _start _start: LDR SP,=x LDMFD SP!,{R0-R2} LDMFD SP!,{R3-R5} sub R2,R2,R5 Sub R1,R1,R4 Sub R0,R0,R3 STMFD SP!,{R0-R2} stop: b stop .ltorg x: .long 80,90,100 y: .long 10,20,30 .end 作业3 已知R0和R1的值,要求保留R0的低16位,保留R1的高16位状态,最后将这两个值组成一个新的数送给R3. 参考代码: .text .global _start _start: LDR R0,=0x12345678 LDR R1,=0x87654321 ldr R2,=0xffff LDR R4,=0xffff0000 AND R0,R0,R2 AND R1,R1,R4 ORR R3,R0,R1 stop: B stop .end 作业4 在ARM GNU环境下用ARM汇编语言编程序实现 参考代码: .text .global _start _start: LDR R0,=x LDR R1,=y LDR R2,[R0] CMP R2,#0 BEQ ZERO BGT ZHENG BLT FU ZERO: MOV R3,#0 STR R3,[R1] B stop ZHENG: mov R3,R2 STR R3,[R1] B stop FU: mvn R3,R2 mov R4,#0x1 add R3,R3,R4 STR R3,[R1] B stop stop: B stop .ltorg x: .long -10 y: .long 0 作业5 求20的阶乘:64位结果放在【R9:R8】中,R9放高32位,R放低32位 思路:每轮乘法操作中,低32位(R8)乘以X(R0)后,结果的低32位放在R8中,高32位放在R9中;高32位R1乘以X(R0)后再加上R9,得到64位结果的高32位,存入R9 参考程序: .global _start .text _start: MOV R8 , #20 @低32位初始化为20 MOV R9 , #0 @高位初始化为0 SUB R0,R8,#1 @初始化计数器 Loop: MOV R1 , R9 @暂存高位值 UMULL R8 , R9 , R0 , R8 @[R9:R8]=R0*R8 MLA R9 , R1 , R0 , R9 @R9=R1*R0+R9 SUBS R0 , R0 , #1 @计数器递减 BNE Loop @计数器不为0继续循环 Stop: B stop .end 二、已知a=R0,b=R1. while(a< >b) do if(a>b) then a=a-b else a=b-a end if end while result=a 根据以上代码写出对应的汇编代码: 参考代码: CMP R0,R1 CMPNE R0,R1 SubGT R0,R0,R1 SubLT R0,R1,R0 .end 作业6 1.将下面的ADS环境下的程序代码改写成GUN环境下的程序代码。 (调试时使用F11 step into,注意和F10 step over的区别) AREA Jump, CODE, READONLY num EQU 4 ; 函数地址表内容的个数 ENTRY CODE32 start LDR R0, =choice ; R0指向存储区的choice单元 LDR R0, [R0] ; 设置第一个参数:选择执行哪一个函数 MOV R1, #16 ; 设置第1个操作数 MOV R2, #2 ; 设置第2个操作数 BL arithfunc ; 调用子程序arithfunc stop MOV R0, #0x18 ; 程序结束返回编译器调试环境 LDR R1, =0x20026 SWI 0x123456 arithfunc CMP R0, #num ; 比较R0的值是否超过函数地址表的个数 MOVHS PC, LR ; 如果大于,那么就返回到标号stop处 ADR R3, JumpTable ; 将函数地址表的地址作为基地址 LDR PC, [R3, R0, LSL #2] ; 根据R0参数进入对应的子程序 JumpTable ; 函数地址表的入口基地址 DCD DoAdd ; 加法子程序 DCD DoSub ; 减法子程序 DCD DoMul ; 乘法子程序 DCD DoDiv ; 除法子程序 DoAdd ADD R0, R1, R2 ; R0 = R1 + R2 MOV PC, LR ; 返回 DoSub SUB R0, R1, R2 ; R0 = R1 - R2 MOV PC, LR ; 返回 DoMul MOV R0, R1, LSL R2 ; R0 = R1 << R2 MOV PC, LR ; 返回 DoDiv MOV R0, R1, LSR R2 ; R0 = R1 >> R2 MOV PC, LR ; 返回 AREA NUM, DATA, READWRITE choice DCD 3 ; 0:表示选择加法子程序 1:表示选择减法子程序 ; 2:表示选择乘法子程序 3:表示选择除法子程序 END 参考程序: .equ num,4 @ 函数地址表内容的个数 .text .global _start _start: LDR R0,=choice @R0指向存储区的choice单元 LDR R0,[R0] @设置第一个参数:选择执行哪一个函数 MOV R1,#16 @设置第1个操作数 MOV R2,#2 @设置第2个操作数 Bl arithfunc @调用子程序arithfunc stop: b stop arithfunc: CMP R0,#num @比较R0的值是否超过函数地址表的个数 MOVHS PC, LR @如果大于,那么就返回到标号stop处 ADR R3, JumpTable @将函数地址表的地址作为基地址 LDR PC, [R3, R0, LSL#2] @根据R0参数进入对应的子程序 JumpTable: @函数地址表的入口基地址 .long DoAdd @加法子程序 .long DoSub @减法子程序 .long DoMul @乘法子程序 .long DoDiv @除法子程序 DoAdd: ADD R0, R1, R2 @R0 = R1 + R2 MOV PC, LR @返回 DoSub: SUB R0, R1, R2 @R0 = R1 - R2 MOV PC, LR @返回 DoMul: MOV R0, R1, LSL R2 @R0 = R1 << R2 MOV PC, LR @返回 DoDiv: MOV R0, R1, LSR R2 @R0 = R1 >> R2 MOV PC, LR @返回 .ltorg choice: .long 3 @0:表示选择加法子程序 @1:表示选择减法子程序 @2:表示选择乘法子程序 @:表示选择除法子程序 .end 2. 改写以下程序,实现从ARM状态切换到thumb状态,最后再切换到ARM状态! #******************************************************************************************* # NAME: ThumbCode.s * # Author: Embest * # Desc: ThumbCode examples * # History: shw.He 2005.02.22 * #********************************************************************************************* /*-----------------------------------------------------------------------------------------------------------*/ /* constant define */ /*-----------------------------------------------------------------------------------------------------------*/ .global _start /*-----------------------------------------------------------------------------------------------------------*/ /* unable to locate source file. code */ /*-----------------------------------------------------------------------------------------------------------*/ .text _start: .arm /* Subsequent instructions are ARM */ header: adr r0, Tstart + 1 /* Processor starts in ARM state, */ bx r0 /* so small ARM code header used */ /* to call Thumb main program. */ nop .thumb Tstart: mov r0, #10 /* Set up parameters */ mov r1, #3 bl doadd /* Call subroutine */ stop: b stop /*------------------------------------------------------------------------------------------*/ /* Subroutine code:R0 = R0 + R1 and return */ /*------------------------------------------------------------------------------------------*/ doadd: add r0, r0, r1 /* Subroutine code */ mov pc, lr /* Return from subroutine. */ .end /* Mark end of file */ 参考程序: .global _start .text _start: mov r3,#0 .arm header: adr r0,Tstart + 1 add r3,r3,#1 //设置循环标志,便于从thumb切换到arm后能停止程序 cmp r3,#2 Beq stop bx r0 stop: b stop .thumb Tstart: LDR r2,=header mov r0, #10 mov r1, #3 bl doadd bx r2 doadd: add r0, r0, r1 mov pc, lr .end 作业7 已知,若任意给一个定值,假定为-25,存放在x单元,函数值存放在y单元;要求根据x中的值来确定y的值。 参考程序: .text .global _start _start: ldr r0,=src ldr r3,=dst ldr r1,[r0] ldr r2,=0x0 /*r2储存常数0*/ cmp r1,r2 addgt r2,r2,#1 sublt r2,r2,#1 str r2,[r3] stop: b stop .ltorg src: .long -25 dst: .long 0 .end 作业8 从x单元开始的5个连续字单元中存放5个无符号数,从中找出最大者送入y单元中。 参考程序: .text .global _start .equ num,4 _start: ldr r4,=num /*r4内的数值作为计数变量*/ ldr r0,=x ldr r5,=y ldr r1,[r0],#4 loop: ldr r1,[r0],#4 ldr r2,[r0],#4 cmp r2,r1 strge r2,[r5] strlt r1,[r5] sub r4,r4,#1 cmp r4,#0 bne loop stop: b stop .ltorg x: .long 1,2,6,3,9 y: .long 0 .end 作业9 (冒泡排序法):利用逐次求大数的方法对内存单元ARRAY开始的以字节为单位的无符号数进行从大到小排序。在以BUF为首址的字存储区中存放有10个无符号数 0x0FF,0x00, 0x40, 0x10, 0x90, 0x20, 0x80, 0x30, 0x50, 0x70, 0x60,现需将它们按从小到大的顺序排列在BUF存储区中,试编写其程序。 参考程序: 分析:采用逐一比较法: l 将第一个存储单元中的数与其后n-1个存储单元中的数逐一比较,每次比较之后,总是把小者放在第一个存储单元之中,经过n-1次比较之后,n个数中最小者存入第一存储单元中; l 接着从第二个存储单元开始,同理,经过n-2次比较之后,得到n-1个数中最小者存入第二存储单元中;如此类推,当最后两个存储单元的数比较完成之后,从小到大的排列顺序就实现了。 “冒泡排序”算法。 各寄存器分配功能如下: R0:用来指示缓冲区初始地址 R1:外循环计数器 R2:内循环计数器 R3:外循环地址指针 R4:内循环地指针 R5:内循环下一个数地址指针 R6:存放内循环一轮比较的最小值 R7:存放内循环取出的下一个比较值 程序代码: .equ num,10 .text .global _start _start: LDR R0,=Datas @指向数组的首地址 mov R1,#0 @外循环计数器 mov R2,#0 @内循环计数器 LOOPI: add R3,R0,R1,lsl #2 @外循环首地址存R3 mov R4,R3 @内循环首地址存R4 ADD R2,R1,#1 @内存换计数器初值 MOV R5,R4 @内循环下一地址初值 LDR R6,[R4] @取内循环下一地址值R4 LOOPJ: add r5,r5,#4 @内循环下一地址值 ldr r7,[r5] @取出下一地址值至R7 cmp r6,r7 @比较 blt next @小则取下一个 swp r7,r6,[r5] @大则交换,最小值R6 mov r6,r7 next: add r2,r2,#1 @内循环计数 cmp r2,#num @循环中止条件 blt LOOPJ @小于N则继续内循环 swp r7,r6,[r3] @否则,内循环一轮结束,将最小数存入外循环的首地址处 add r1,r1,#1 @外循环计数 cmp r1,#num-1 @外循环中止条件 blt LOOPI @小于N-1则继续执行外循环 BEQ stop b _start stop: b stop .ltorg Datas: .long 0x0FF, 0x00, 0x40 .long 0x10, 0x90, 0x20, .long 0x80, 0x30, 0x50, .long 0x70 .end 作业10 通过设置的入口参数查找函数地址表,实现选择不同的函数功能。已知两个操作数分别存放于寄存器R0与R1中,函数1实现两数相加R0+R1;函数2实现两数相减R0-R1;函数3实现两数相乘R0*R1; 函数4实现两数相除R0/R1。 参考代码: .text .equ num,3 .global _start _start: ldr r0,=0x01 ldr r1,=0x02 ldr r4,=0x02 /*r4用来作为选择函数入口Doadd,Dosub,Domul的选项(默认为1,可修改)*/ bl Func stop: b stop Func: cmp r4,#num movge pc,lr /*当r4内的值大于等于3时,调回_start函数*/ ldr r3,=JTable ldr pc,[r3,r4,lsl #2] /*因为函数入口是.long类型,所以需要左移(LSL)2位*/ JTable: .long Doadd,Dosub,Domul Doadd: add r2,r0,r1 mov pc,lr Dosub: sub r2,r0,r1 mov pc,lr Domul: mul r2,r0,r1 mov pc,lr .end 作业11 编程实现S=1+2*3+4*5+…….+N*(N+1),其中N=10。 参考答案: 分析过程 l 算法功能: l 相邻数相乘:MUL l 累加: ADD l 循环次数:10 CMP B指令 l 初始值 S=1 N l N+1 部分和N(N+1) 寄存器分配 l R0: S 1 R0+R3得S值 l R1:N的初始值 2 循环变量 l R2:N+1 由R1=1 求得 l R3:N(N+1) 参考程序: .text .equ N,10 .global _start _start: MOV R0, #1 @R0用作累加,置初值1,S MOV R1, #2 @R1用作第一个乘数, 初值为2, N loop: /*内层循环loop1,做乘法运算*/ ADD R2, R1, #1 @R2用作第二个乘数,N+1 MUL R3, R2, R1 @实现N *(N+1)部分积存于R3 ADD R0, R0, R3 @将部分乘积累加至R0 ADD R1, R1, #1 @改N的值得到下一轮乘数 CMP R1, #10 @循环次数比较 BLE loop @未完成则重复 stop: b stop .end 作业12 编程实现S=1!+2!+3!……+N!,要求N!用子程序实现。 程序代码: .global _start .text _start: mov R0,#0 mov R1,#1 loop: mov R2,#1 mov R3,#1 mov R4,#1 loop1: mul R4,R2,R3 mov R3,R4 add R2,R2,#1 cmp R1,R2 bge loop1 loop2: add R0,R0,R3 add R1,R1,#1 cmp R1,#10 bls loop stop: b stop .end 作业13 在C程序中内嵌汇编程序实现将源字符串src中的数据拷贝到目的字符串dest中 参考程序: 其中主程序如下:*/ #include void strcpyy(const char *src, char *dest); __gccmain(void) { char *s= "this is a example AsmInC !"; char temp[64]; strcpyy(s,temp); //printf("Original string: %s \n ", s); //printf("Copyed string: %s", temp); return 0; } void strcpyy(const char *src, char *dest) { __asm( /*GNU和ADS环境下的区别*/ " loop: ldrb r5,[r0],#1 strb r5,[r1],#1 cmp r5,#0; bne loop " ); } 作业14 /*在GNU ARM环境下设计程序,实现字符串的逆序拷贝。*/ .global _start .text _start: LDR R0, =SrcString @ 源字符串指针 LDR R1, =DstString @ 目标字符串指针 StrCopyDes: MOV R4, #0 @ 字符串长度记录寄存器 Strcpydes_L1: @ 计算字符串的长度 LDRB R2, [R0], #1 ADD R4, R4, #1 TST R2, #0xFF BNE Strcpydes_L1 SUB R4, R4, #1 SUB R0, R0, #2 @ R0 指向源字符串的末尾 MOV R3, R1 @ R3 作为目标串的游标指针 Strcpydes_L2: LDRB R2, [R0], #-1 @ 逐个拷贝字符串 STRB R2, [R3], #1 SUBS R4, R4, #1 BNE Strcpydes_L2 Strcpydes_L3: STRB R4, [R3] @向目标串末尾写\0,此处R4的值一定为0 Stop: B Stop .ltorg SrcString: .string "Hello World!" DstString: .string "" .end 作业15 1、在GNU ARM编译环境下设计程序,用ARM汇编语言调用C语言实现20的阶乘20的阶乘(20!)操作,并将64位结果保存到寄存器R0、R1中,其中R1中存放高32位结果。 程序代码: 汇编程序: /* Factorial.s */ .text .equ NI,20 .global _start .extern Factorial @申明Factorial是外部函数 _start: mov r0,#NI BL Factorial @调用Factorial stop: B stop .end /*main.c*/ long Factorial(char n) { long long ni=1; char i; for(i=1;i<=n;i++) { ni=ni*i; } return ni; } 2、在GNU ARM编译环境下设计程序,用C语言调用ARM汇编语言实现20的阶乘(20!)操作,并将64位结果保存到0xFFFFFFF0开始的内存地址单元,按照小端格式低位数据存放在低地址单元。 /* 首先建立汇编源文件start.s */ .global _start .global __gccmain .extern main @ 定义外部函数 .text _start: BL main @调用Main函数 Stop: B Stop __gccmain: mov pc, lr .end /* 第二 建立C语言源文件main.c */ extern void Factorial(char Nx); //声明Factorial是一个外部函数 main() { char N =20; Factorial(N); //调用汇编文件实现N!操作 /*注:在此处观察结果*/ while(1); } /* Factorial.s */ .global Factorial @声明Factorial为一个全局函数 Factorial: MOV R8 , R0 @取参数 MOV R9 , #0 @高位初始化 SUB R0,R8,#1 @初始化计数器 Loop: MOV R1 , R9 @暂存高位值 UMULL R8 , R9 , R0 , R8 @[R9:R8]=R0*R8 MLA R9 , R1 , R0 , R9 @R9=R1*R0+R9 SUBS R0 , R0 , #1 @计数器递减 BNE Loop @计数器不为0继续循环 LDR R0,=0xFFFFFFF0 STMIA R0, {R8,R9} @结果保存到0x10000开始的内存单元 MOV PC,LR @子程序返回 .end
展开阅读全文
提示  淘文阁 - 分享文档赚钱的网站所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
关于本文
本文标题:嵌入式系统基础学习知识原理及其应用题目要求程序代码.doc
链接地址:https://www.taowenge.com/p-2606079.html
关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

收起
展开