零 安装交叉编译器
1. 创建共享目录
2. 拷贝压缩包 arm-cortex_a9-eabi-4.7-eglibc-2.18.tar.gz
3. 解压 tar xvf arm-cortex_a9-eabi-4.7-eglibc-2.18.tar.gz
4. 修改环境变量 PATH
5. vi ~/.bashrc
添加 export PATH=$PATH:/opt/arm-cortex_a9-eabi-4.7-eglibc-2.18/bin
6. 验证
source ~/.bashrc
arm- + TAB 键
如果可以补全,则说明交叉编译工具安装成功
一 回忆昨天的内容
三大系统软件的烧录
EMMC分区
【 】 【ubootpak.bin】 【uImage】 【rootfs_ext4.img】 【大片】
0 ~ 512byte 513byte ~ 1M 1M ~ 65M 65M ~ 819M .....
bootcmd 加载引导linux内核到内存中
bootargs 给linux内核传参
setenv bootcmd mmc read 0x48000000 0x800 0x3000 \;
bootm 0x48000000
setenv bootargs root=/dev/mmcblk0p2 init=/linuxrc
console=ttySAC0,115200 maxcpus=1 lcd=wy070ml tp=gslx680-linux
saveenv
二 ARM体系结构与汇编
2.1 什么是ARM:
Advanced RISC Machines
RISC : 精简指令集 ---》 ARM MIPS LA IBM
CISC : 复杂指令集 ---> intel AMD
www.arm.com
指令集 架构 soc
ARMV4T ARM7 s3c44b0
ARMV5TE arm9 S3C2410
armv6 arm11 s3c6410
armv7 cortex-a sp5v210
armv8 cortex-a53 s5p6818
cortex-r 实时性较强的领域
cortex-m 以单片机的价格实现32bit的性能
流水线:
三级流水线 取指令 解码指令 执行指令
for (i = 0; i < 10; i++) //执行效率更高
{
for (j = 0; j < 10000; j++)
{
.....
}
}
for (j = 0; j < 10000; j++)
{
for (i = 0; i < 10; i++)
{
......
}
}
CPI 怎么算?
指令周期/周期内执行指令的个数
2.2 ARM编程模型
2.2.1 ARM的工作模式 7种
svc: 管理模式,系统上电,执行软中断指令
fiq: 快速中断,发生了高优先级的中断
irq:发生了低优先级的中断
abort:当产生了非法访问存储器时
undef:遇到不认识的指令
system:与用户共用寄存器,需要特权
user:应用程序和系统任务运行在用户模式
前5种是异常模式,后两种是正常模式
前6种是特权模式,后一种是非特权模式
2.2.2 ARM的工作状态:
ARM 状态:执行ARM (32bit)指令时
Thumb 状态:执行Thumb (16bit)指令时
0x90000002
以上两种状态可以切换,
异常处理过程中必须处于ARM状态
2.2.3 寄存器的组织结构
寄存器和特殊功能寄存器的区别:
1.存放的位置不同:
寄存器位于 ARM core 内部
特殊功能寄存器 位于ARM core外部
2.访问的方式不一样:
特殊功能寄存器都有特定的物理地址
寄存器只有名字没有地址
C很难访到
* (volatile int *) (0xc001c000) ---> GPIOCOUT
ARM核中一共有37个32bit的寄存器
其中一共有32个通用寄存器
命名为r0~r15
r11 (fp, frame pointer 忽略)
r13 (sp, stack pointer)
r14 (lr, 保存函数的指针)
r15 (pc, 保存取指令的位置)
6个状态寄存器:
1个cpsr程序状态寄存器
5个spsr是cpsr的备份
[4:0] mode 模式位,标识当前arm核处于什么模式,
在特权模式下,可以写该寄存器
[5] T位,1,当前处于Thumb状态, 0 arm状态
[7] I位,1,禁止RIQ
0, 使能RIQ
[6] F位,1,禁止FIQ
0, 使能FIQ
[28] v位 有符号数据在做运算的时候有进位
[29] C位 运算结果最高位有进位
0xfffffffc + 10 => C = 1
[30] Z位 运算结果为0, z位为1
[31] N,运算结果为负, =1
每一种模式下,都只能访问其中的一个子集
2.2.4 异常向量与异常向量表
裸板程序:
main (){
xxx_init ();
...
while (1)
{
周期性事件
}
}
+ 异常处理
ARM Core 支持 7种工作模式
reset (复位异常) 按下复位键
undef (未定义的异常) 执行到不认识的指令
swi (软中断异常) 执行汇编指令“swi”
prefetch abort (预取值终止异常)
取指令时进行了非法的存储器访问
data abort 取数据时进行了非法的存储器访问
irq (中断异常) 按键中断
fiq (快速中断) 高优先级中断发生时
7种异常会导致arm进入5种异常模式
当异常产生时,ARM核硬件上自动做4件事:
1. 备份cpsr
spsr_
2. 修改 cpsr
a) 切换为arm工作模式 CPSR[T]
b) 切换为异常工作模式 CPSR[4:0]
c) 禁止中断 CPSR[I] = 1 CPSR[F] = 1
3. 保存返回地址到LR_
4. 给pc赋值
reset 异常 ==》pc = 0x00
..
fiq 异常 ===》 pc = 0x1C
从异常返回的时候,软件上需要处理:
1)恢复cpsr
2)返回被打断的位置
fun(){
...
return
}
main (){
func (); //i++指令的地址 ---》 LR
i++;
}
2.2.5 ARM 支持的数据类型
byte
half word
word
double word
对齐方式:
4字节对齐,存储的地址可以被4整除
struct stu{
int a;
char c;
short d;
int b;
};
sizeof (struct stu) = 12;
大小端的判断:
int a = 0x12345678;
字节序:
大端模式 小端模式
地址 值 值
0x00 12 78
0x01 34 56
0x02 56 34
0x03 78 12
权重最大的在低地址叫大端
编程实现arm处理器大小端的判断?
参见代码: Endian.c
三 arm汇编
3.1 基本概念
arm 汇编语言,又叫助记符语言
大多数系统设计的主要工作都集中在编译代码(C),
一般不需要了解指令集,但是以下情况会用到汇编:
嵌入式系统中需要初始化和中断服务程序
所有的系统都需要调试,可能会用汇编调试
可以通过汇编语言来提升系统的性能
有些指令编译器无法产生,只能通过汇编完成
3.2 ARM汇编指令
ARM汇编指令的特点
1)大多数汇编指令都是单周期
2)大多数arm汇编指令可以条件执行
3.2.1 分支跳转指令
b {cond} <目标地址> //类似于goto
b main
b 指令应用实例:
start:
cmp r0,r1
beq not_copy
move r0,r1
not_copy:
b .
bl {cond} <目标地址> //函数调用 l是 link
bl main //在向main跳转之前,记录下下一条指令的地址到LR
注意:目标地址的范围:土32M
将指令中的24位带符号的补码立即数扩展为32位,将32bit左移两位,
将得到的数值加到pc寄存器中,得到目的地址。
指令的编码格式
31 28 25 24 23 0
cond B L target
bl指令的应用实例:
start:
mov r0, #1
mov r1, #2
bl DoAdd
b . // 跳转到当前地址
DoAdd:
add r0, r0, r1
mov pc, lr
bx
blx
b {l} {cond}
b {l} {cond}
x,带状态切换
Rn,一定是通用寄存器 r0~r15
注意:跳转的范围不受限制 (0~4G)
bx指令的应用实例:
.code 32 arm指令 32bit
ARM_code:
ADR R0, THUMB_code + 1 @R0中存放的是要跳转的地址
BX R0
.code 16 thumb 指令 16bit
THUMB_code:
ADR R0, ARM_code
BX R0
3.2.2 数据处理指令
1)移位指令
LSL: logical shift left 逻辑左移
LSR:
logical shift right 逻辑右移,空出的位0
ASR:
Arithmetic shift right 算数右移
最高位补符号位
ROR:
ROR 循环右移
RRX:
带扩展位的循环右移 新的最高位由CPSR的C位,而且更新C位
2) 数据传输指令
mov {cond} {s}
cond, 可以条件
s, 操作结果影响cpsr的NZCV位
mov R0, #10 @ r0 = 10
movs R0, #10 @ r0 = 10, N = 0 Z = 0
Rd 一定是通用寄存器
operand : 有三种表现形式
mov r0, #10
注意立即数的合法性问题
存在一个8bit的立即数,
循环右移偶数位得到,那么这个立即数就是合法的
mov r0, r2 @ r0 = r2
mov r0, r2, lsl #2 @r0 = r2 << 2
moveqs r0, r1 @ if (CPSR.Z ==1)
movs r0, r1
@ r0 = r1 if (r0 == 0) Z = 1 else Z = 0
@ N = r0[31]
mvn {cond} {s}
将operand表示的数据的反码传送到目标寄存器r0中
并根据操作的结果影响CPSR的NZCV位
3.2.3 算数运算指令
add {cond} {s}
cond, 可以条件执行
s,操作结果影响NZCV位
N = r[31]
if (Rn == 0) Z = 1 else Z = 0
最高位有进位 C = 1 else C = 0
Rd, Rn 一定是通用寄存器
operand 有三种表现形式
add r0, #10
add r0, r1, r2
add r0, r1, r2, lsl #3 @r0 = r1+r2*8
adc {cond} {s}
adc r0, r1, r2 @r0 = r1 + r2 + C
64bit的加法运算:
高 低
被加数 r0 r1
加数 r2 r3
和 r0 r1
adds r1, r1, r3
adc r0, r0, r2
sub {cond} {s}
s, 注意对C位影响
Rn > Operand C = 1
C = 0
sbc {cond} {s}
sbc r0, r1, r2 @r0 = r1-r2-NOT(C) @出现负负得正的效果
64bit的减法:
高 低
被减数 r4 r5
减数 r6 r7
差 r8 r9
subs r9, r5, r7 @if (r5 > r7) C = 1
sbc r8, r4, r6 @r8 = r4 - r6 -NOT(C)
rsb {cond} {s}
rsb r0, r1, r2 @r0 = r2 - r1
rsb r0, r1, #8 @r0 = 8 - r1
rsb r0, #8, r1 @不对,语法错误
rsb r0, r0, #0 @取相反数
练习:求1到10的累加和,结果保存到r0中
参见代码 add.s
作业:对照 数据手册 和电路原理图 读懂01工程文件
建立ctags文件:
ctags -R *
如何跳转:光标移到要跳转的位置 --》ctrl + }
跳回来 ctrl + t