arm-cortex_a9-eabi-4.7.....
)tar xf ......
export PATH=$PATH:/opt/arm-cortex_a9-eabi-4.7-eglibc-2.1........
source ~/.bashrc
and arm- + Tab键
三大系统软件的烧录 EMMC 分区 (测试题) [ ] [ubookpak.bin] [uImage] [rootfs_ext4.img] [应用程序 本地库 驱动程序]
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官网 : https://www.arm.com/
Advanced RISC Machines RISC : 精简指令集 ----> ARM MIPS LA IBM CISC : 复杂指令集 ----> Intal AMD
指令集 | 架构 | 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(i = 0; j < 10000; j++){
...
}
}
//第二种写法
for(j = 0; j < 10000; j++){
for(i = 0; i < 10; i++){
...
}
}
//第一种执行效率更高
(测试题) CPI 怎么算?
指令周期/周期内执行指令的个数 BL : 带分支的跳转
七种工作模式:
前5种是异常模式, 后两种是正常模式 前6种是特权模式, 后一种是非特权模式
ARM 状态 : 执行ARM (32bit) 指令时, PC值字对齐 (32位) Tumb 状态: 执行 Tumb (16bit) 指令时, PC值半字对齐 (16位) 访问0x900000002 合法
寄存器和特殊功能寄存器的区别:
存放的位置不同: 寄存器位于 ARM core 内部 特殊功能寄存器: 位于 ARM core 外部
访问的方式不一样 特殊功能寄存器都有特定的物理地址 寄存器只有名字没有地址, C很难访问
* (volatile int *) (0xc001c000) ----> GPIOCOUT
ARM核中一共有 37 个32bit的寄存器, 其中有31个通用寄存器, 命名为r0-r15 r11 (fp, frame pointer 忽略) r13 (sp, stack pointer 重要) r14 (lr, 保存函数的指针) r15 (pc, 保存取指令的位置)
6个状态寄存器: 1个 cpsr 程序状态寄存器, spsr是cpsr的备份
[4 : 0] mode 模式位, 标识当前 ARM核 处于什么模式, 在特权模式下, 可以写该寄存器 [5] T位, 1 --处于 Thumb 状态, 0 -- ARM 状态 [6] F位, 1 -- 禁止FIQ, 0 -- 使能FIQ [7] I位, 1 -- 禁止RIQ, 0 -- 使能RIQ [28] V位, 有符号数据在做运算的时候进位 [29] C位, 运算结果最高位有进位 0xfffffffc + 10 => C = 1 [30] Z位, 运算结果为0, z位为1 [31] N位, 运算结果为负 =1 , 为正 = 0
每一种模式下, 只能访问其中的一个子集.
裸板程序:
main(){
xxx_init();
...
while(1){
//其中为周期性事件
}
}
xxx //+ 异常处理
ARM Core 支持 7
种工作模式, 2
种异常
7
种异常会导致 ARM 进入 5
种异常模式:
reset
: (复位异常) 按下复位键undef
: (未定义的异常) 执行到不认识的指令swi
: (软中断异常) 执行汇编指令 swi
prefetch abort
: (预取值终止异常) 取指令时进行了非法的存取器访问data abort
: 取数据时进行了非法访问存储器irq
: (中断异常) 按键中断fiq
: (快速中断) 高优先级中断发生时触发(测试题)当异常产生时, ARM核 硬件上自动做 4
件事:
spsr_<mode> = cpsr
CPSR[T]
CPSR[4:0]
CPSR[I] = 1, CPSR[F] = 1
LR_\<mode>
reset 异常 ---> pc = 0x00
...
fiq 异常 ---> pc = 0x1C
从异常返回的时候, 软件上需要处理:
fun(){
...
return;
}
main(){//ARM 保存 i++ 的值
func(); // i++指令的地址 ----> LR
i++;
}
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
//法1:
#include<stdio.h>
int main(void){
int a = 0x12345678;
char * p = (char *)&a;
if(0x12 == *p)
printf("BIG-Endian");
else
printf("Little-Endian");
return 0;
}
使用交叉编译器 见:零.安装交叉编译器
//法2:
#include<stdio.h>
union{
int a;
char c[4];
} endian;
int main(void){
int i = 0;
endian.a = 1;
if(endian.c[0] == 1)
printf("Little Endian\n")
else
printf("BIG Endian\n");
return 0;
}
arm汇编语言(又叫助记符语言), 大多数系统设计的主要工作都集中在编译代码(C), 一般不需要了解指令集, 但是以下情况会用到汇编:
ARM 汇编指令的特点
语法规则: 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
<cond>
为指令的条件码, EQ, NE, CC, CS, LT...
<target>
为指令跳转的目标地址
为什么为32M: 将指令中的 24位 带符号的补码立即数拓展为 32位 , 将 32位 的数 左移两位, 所得到的数值加到PC寄存器中, 得到目的地址。
指令编码格式: 31 28 25 24 23 0 cond B L target
bl指令应用实例:
start:
mov ro, #1
mov r1, #2
bl DoAdd
b .
DoAdd:
add r0, r0, r1
mov pc, lr
bx指令编码格式:
bx
or blx
or b {1} {cond} <target>
or b {1} {cond} <Rn>
x 带状态切换
Rn, 一定是通用寄存器 r0~r15
注意:跳转的范围不受限制(0~4G)
bx指令应用实例:
.code 32
ARM_CODE:
ADR RO, THUMB_CODE + 1
BX R0
.code 16
THUMB_code:
ADR R0, ARM_code
BX R0
LSL : logical shift left 逻辑左移, 空出的位填0
<Rn>, LSL #<shift_imm>
or <Rn>, LSL, <Rs>
移位的位数由Rs寄存器的bit[7:0]
LSR : logical shift right 逻辑右移, 空出的位填0
<Rn>, LSR #<shift_imm>
ASR : Arithmetic shift right 算术右移, 最高位补符号位
ROR : 循环右移
RRX: 带扩展位的循环右移, 新的最高位由 CPSR 的C位填充, 而且更新C位
mov {cond} {s} <Rd>, <oprand>
cond : 可以条件执行
s : 操作结果影响 cpsr 的 NZCV 位
mov R0, #10 @ r0 = 10
or movs R0, #10 @ r0 = 10, N = 0 Z = 0
Rd 一定是通用寄存器
operand : 有三种表现形式
mov r0, #10
注意立即数的合法性问题, 存在一个 8bit 的立即数, 循环右移偶数位得到, 那么这个立即数就是合法的.
mov r0, r2
@ r0 = r2
mov r0, r2, ls1 #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} <Rd>, <oprand>
将 operand 表示的数据的反码传送到目标寄存器 r0 中, 并根据操作的结果影响 CPSR 的 NZCV 位.
add {cond} {s} <Rd>, <Rn>, <oprand>
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, ls1 #3
@ro = r1+r2*8
adc {cond} {s} <Rd>, <Rn>, <oprand>
eg : adc r0, r1, r2
@r0 = r1 + r2 + C
eg : 64bit 加法运算
高 | 低 | |
---|---|---|
被加数 | r0 | r1 |
加数 | r2 | r3 |
和 | r0 | r1 |
adds r1, r1, r3
addc r0, r0, r2
sub {cond} {s} <Rd>, <Rn>, <oprand>
s 注意对C位的影响
Rn > Operand C = 1 else C = 0
减法指令: sbc {cond} {s} <Rd>, <Rn>, <oprand>
sbc r0, r1, r2
@ r0 = r1 - r2 -NOT(C)
eg: 64位 减法运算
高 | 低 | |
---|---|---|
被减数 | r4 | r5 |
减数 | r6 | r7 |
和 | r8 | r9 |
subs r9, r5, r7
@if(r5 > r7) C = 1 else C = 0
sbc r8, r4, r6
@ r8 = r4 - r6 - NOT(C) @出现了负负得正的效果
逆向减法指令: rsb {cond} {s} <Rd>, <Rn>, <oprand>
eg : rsb r0, r1, r2
@ r0 = r2 - r1
eg : rsb r0, r1, #8
@ r0 = 8 - r1
eg : rsb r0, #8, r1
@ 不对, 语法错误
eg : rsb r0, r0, #0
@ 取相反数
练习: 求 1 到 10 的 累加和, 结果保存到 r0中
@add.s
.text
.code 32
.global _start
_start:
mov r1, #10
mov r0, #0
sum:
add r0, r0, #1
sub r1, r1, #1
cmp r1, #0
beq sum
b .
.end
作业: 对照 数据手册 和 电路原理图 读懂01工程文件
本文章使用limfx的vscode插件快速发布