G
N
I
D
A
O
L

嵌入式课程作业记录(1)

本学期的第一次嵌入式(小)作业,出现了许多问题和解决办法,特开一文用以记录,以防忘记。

关于ARM开发工具ADS的一些注意点

(1)code32表示后面全部用 ARM 指令集!

(2)点击 debug,若出现如下错误:error starting external process process error code 87(0x57) can't read symbolics for this tar,请以管理员身份重新运行 ADS。

(3)编译时,若AREA出现unknown opcode,解决办法:AREA前面要加空格,不要顶格写,否则编译不通过!另外程序文件最开始最好空一行出来。

(4)在写 C 语言内嵌 ARM 汇编的程序时,主函数的名字不是main而要写成xmain_main,否则编译不通过!

(5)编译时出现Warning: L6305W: Image does not have an entry point.(Not specified or not set due to multiple choices.)的警告,我不太了解这个是怎样解决的。

汇编作业

之前也自学过 x86 汇编,但从未写过一个完整的汇编程序。这次作业使用 ARM 汇编写程序,虽然与 x86 语法有较大的区别,但还是很容易理解的。

1、先赋值一段字符,然后统计出其中数字字符出现的频次

注意,如果使用LDR指令来读取数据段的字符串内容,会将整个字符串都读到寄存器中,不便于分离单个字符进行计数。因为LDR指令会加载整个字放入寄存器中。

而现在我们需要将一字节内容放入到寄存器中,通过查阅指令集,可以发现LDRBLDRSB可以达到这个目的,有所区别的是后者为带符号字节读入。

按理说应该两个指令都可以,但我试了一下,只有LDRSB可以,用LDRB还是会整个字读入,不知道是什么原因,希望有知情者可以解释一下。


 AREA 	COPY, CODE, READONLY
		ENTRY
		CODE32
		
START	
		LDR		R5, =RESULT
		LDR 	R0, =DATA
		MOV 	R1, #0		;统计数字次数
		MOV 	R2, #20		;循环次数
		MOV		R3, #0		;测试是否为数字,若是则为负数
		B		LOOP
		
NUMBER
		ADD 	R1, R1, #1	;数字字符,加一
		B		NEXT
		
LOOP	
		LDRSB	R4, [R0]	;从源地址获取数据
							;数字字符ASCII:48-57
		CMP		R4, #47
		BLE		NEXT
		CMP		R4, #58
		BLE		NUMBER

NEXT		
		ADD		R0, R0, #1	;地址	
		SUB		R2, R2, #1	;循环减一
		CMP		R2, #0
		BNE		LOOP
		STR		R1, [R5]
		B		EXIT
		
EXIT
		B 		EXIT
		
 AREA 	COPYDATA, DATA, READONLY
DATA 	DCB 	"012abc34def56dd78j90"
RESULT	DCD		0

		END 
		

调试过程中:

image

2. 约瑟夫问题(ARM汇编)

n 个人围成一圈,编号从 1 到 n ,从编号为 1 的人开始报数,报到 m 的人离队,下面的人接着从1开始报数,依次下去,写程序求最后剩下一个人编号是几?

有点惭愧,因为当时时间紧迫,这个题目我是直接拿网上的用 x86 汇编写的程序改的(前往:用80x86汇编 求约瑟夫环问题)。数据段分为两个部分,FLAG段是标记出列,RESULT记录出列标号。

这里给出的是 10 个人围成一圈,报到 4 时出列的约瑟夫问题求解程序。

 
 AREA COPY, CODE, READONLY
	ENTRY
	
START
	LDR 	R8, =RESULT
	LDR		R6, =FLAG
	MOV		R0, #10		;总共10个人	
	MOV 	R1, #4		;出列号码4
	MOV 	R2, #0		;起始号码
	MOV 	R3, #0		;报数
	MOV 	R4, #0		;出列人数
	MOV 	R5, #0		;用于保存出列号码
	
L1
	LDR		R7, [R6, R2, LSL #2] ;R7=地址(R6+R2*4)的值
	CMP 	R7, #0		;检测是否为出列
	BNE 	NEXT		;若不是,则转到下一个人处理
	ADD		R3, R3, #1	;若是,则报数,加一
	CMP		R3, R1		;检测是否已经报到出列号码
	BNE		NEXT		;若不是,则转到下一个人处理
	ADD		R7, R7, #1	;若是,则标记出列
	STR		R7, [R6, R2, LSL #2] ;记录回memory
	MOV		R3, #0		;报数重新置零
	MOV 	R5, R2		;保存出列号码
	STR		R5, [R8, R4, LSL #2]
	ADD		R4, R4, #1	;出列人数加一
	CMP		R4, R0		;检测出列人数是否等于总人数
	BEQ		EXIT		;若是,则结束程序
	
NEXT
	ADD 	R2, R2, #1	;转到下一个人
	CMP 	R2, R0		;检测是否数到了最后一个人
	BNE 	L1			;若不是,则继续数
	MOV 	R2, #0		;若是,起始号码从0开始数
	B 		L1
	
EXIT
	B		EXIT

 AREA COPYDATA, DATA, READWRITE
FLAG 	DCD  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
RESULT	DCD	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

	END
	

3. 约瑟夫问题(C和ARM混合)

将上面汇编程序改成 C 语言和 ARM 汇编混合。注意,LDR R8, [result]若写为LDR R8, =result编译时就会报错,不知道为什么。

我调试过,一直出现找不到函数入口,PC 指针一直指向初始位置,因此也无法得知该程序是否正确与否。在Edit->DebugRel Settings里设置Image entry point也没用,希望能有朝一日能解决这个问题。

image

#include <stdio.h>
#include <stdlib.h>

int _main()
{
	int num[100];
	int n=10, m=4, i;
	int count, locate, sum;
	int result[100];
	
	for(i = 0; i < n; i++)
		num[i] = 0;
	
	__asm
	{
			LDR		R8, [result]
			LDR 	R6, [num]
			
			LDR		R0, [n]
			LDR		R1, [m] 
			
			LDR		R2, [locate]
			LDR		R3, [count]
			LDR		R4, [sum]
				
	LOOP:
			LDR		R7, [R6, R2]
			
			CMP 	R7, #0		
			BNE 	NEXT		
			ADD		R3, R3, #1	
			
			CMP		R3, R1		
			BNE		NEXT		
			ADD		R7, R7, #1			
			
			MOV		R3, #0		
			ADD		R4, R4, #1	
			
			ADD		R8, R8, R4
			STR		R2, [R8]	
			CMP		R4, R0		
			
	NEXT:
			ADD 	R2, R2, #1	
			CMP 	R2, R0		
			BNE 	LOOP		
			MOV 	R2, #0		
			B 		LOOP	
	}
	
	for(i = 0; i < n; i++)
		printf("%d ", result[i]);
	
	return 0;
}
	
posted @ 2021-10-30 11:12  漫舞八月(Mount256)  阅读(162)  评论(0编辑  收藏  举报