预备知识
软件
系统软件
中间件
应用软件
硬件
电源
输入设备
输出设备
存储器
CPU寄存器(CPU Register)存临时数据、控制设备
高速缓冲(Cache)主要存热点数据
内存(RAM)掉电数据丢失(直接寻址)
硬盘(Hard Disk)掉电数据不会丢失(无法直接寻址)
总线
CPU
物理结构
CPU组成
运算器(累加器,乘除使用位移)
控制器(控制程序的运行)
存储器
总线(bus)信息交流通道
工作原理
取指令(Fetch)
翻译指令(Decode)
执行指令(Execute)
CPU性能提升
提升工艺
Cache
多ALU(逻辑运算单元)和FPU(浮点运算单元)
流水线
架构演进(哈弗)
系统设计
SOC(System on Chip)系统级芯片,是模仿计算机系统,微缩成了一个微系统
AMBA(Advanced Microcontroller Bus Architecture)高级微控制器总线架构
AHB(高速总线)
ASB(系统总线)
APB(外部总线)
AXI
编程模型
数据和指令类型
工作模式
User:非特权模式
System:特权模式
FIQ:高优先级中断产生
IRQ:低优先级中断产生
Supervisor(SVC):复位或软中断产生
Abort:存取异常产生
Undef:执行未定义指令
Monitor:执行安全监控代码(也是一种特权模式)
异常
大小端
大端是高字节存放到内存的低地址
小端是高字节存放到内存的高地址
寄存器组织
通用寄存器
r1-r12 寄存器:存放任意数据
r13(sp)stack pointer 寄存器:存放栈顶的地址(栈区)
r14(lr)link register/return 寄存器:存放返回的地址
r15(pc)point counter 寄存器:存放下一条指令的地址(跳转指令)(功能类似goto)
cpsr (当前程序状态寄存器)寄存器
spsr (备份程序状态寄存器)寄存器:还原状态
ARM操作指令(最后一个可以为数值)
数据传输指令:mov
mov r0,#1
算术运算指令:add,sub,mul,adds(加法,若溢出,会将cpsr的溢出位,置1),adc(加法,若溢出,会将cpsr的溢出位加到结果中)
add r1,r0,r2
sub r2,r1,r0
mul r1,r2,r0
位操作指令:and(&),orr(|),eor(^),bic(按位清零)
and r0,r1,r2
orr r1,r0,r2
eor
bic r0,r0,r1
跳转指令:b,bl(保存返回地址到lr寄存器)
b 标签
比较指令:cmp(比较后存储在cpsr中 NZ)
cmp r0,r1
movgt r0,#4
注释:@,/**/
模拟调试流程
编写代码
.global _start
_start:
mov r0,#1
mov r1,#3
nop
nop
编译代码
arm-linux-gcc test.s -o test.o -c -g
arm-linux-ld test.o -o test.elf -Ttext=0x0
启动虚拟arm版
qemu-system-arm -machine xilinx-zynq-a9 -m 256M -serial stdio -kernel test.elf -S -s
调试(可能由于bash编码出现错误,修改bashrc,只保留LA_ALL=C)
arm-none-linux-gnueabi-gdb test.elf
gdb命令
target remote 127.0.0.1:1234
立即数
可以直接从指令中得到的数值(转换为二进制,去掉循环的偶数个0,相邻两位去掉,且剩下的数据<=8bits)
伪指令
由编译器拟定的规则,在编译的过程中生成相应的指令(gnu提供)
ldr r3,=0xffff @r3 = 0xffff(伪指令)
ldr r0,[r1] @r0 = *((int*)r1)(指令)
ldr r0,[r1,#4] @r0 = *((int*)r1+4)(指令)
str r0,[r1] @*((int*)r1) = r0(指令)
.global @声明为全局变量,可在外部调用
.text @代码段
.data @数据
.bss @全局未初始化变量
buf: .word 1,2,3,4,5 @int buf[] = {1,2,3,4};
buf: .space 0x100 @int* buf = malloc(0x100);
ARM的寻址方式
立即数寻址:数据存放在指令中
mov r0,#1
寄存器寻址:寄存器中存放数据
mov r0,r1
寄存器偏移寻址:
mov r0,r1,lsl #3@逻辑左偏移3位(lsl逻辑左移,lsr逻辑右移,asl算术左移,asr算术右移)
寄存器间接寻址:寄存器中存放数据的地址
ldr r0,[r1] @取r1地址的值
寄存器基址变址寻址:
ldr r0,[r1,#4] @取r1地址+4的值
多寄存器寻址:同时操作多个寄存器
stmfd sp!,{r0,r1,r2} @入栈 ldmfd sp!,{r0,r1,r2} @出栈 @!:其执行的操作会修改原来的值
相对寻址
堆栈寻址
块拷贝寻址
异常
异常(CPU逻辑运行的一种机制)(类似信号)
异常和模式的关系:
模式:异常
SVC:reset swi
Abort:data prefetch
FIQ:fiq
IRQ:irq
Undefined:undefined
中断处理流程
中断会触发异常信号,
CPU捕获异常信号,备份当前状态(在用户态user模式,使用spsr),保存下一条指令的地址(在内核态irq模式,使用lr)(通过使用栈,irq中lr寄存器保存的地址不会改变),并切换到相应的模式(修改cpsr)
查找异常向量表(存放跳转到相应异常处理函数的指令)(不同异常对应的地址偏移量是固定的)
跳转到异常处理函数(由CPU内部提供),分配中断处理函数(用户提供),跳转中断处理函数,恢复先前状态,并返回下一条指令的地址(恢复状态和返回指令同时运行)
异常优先级
Reset
Data Abort
FIQ
IRQ
Prefetch Abort
SWI
Undefined
汇编程序编译流程
arm-linux-gcc sys.s -o sys.o -c -g
arm-linux-ld sys.o main.o -o sys.elf -Ttext=0x41000000
arm-linux-objcopy sys.elf sys.bin -O binary
C汇编混合程序编译流程
arm-linux-gcc sys.s -o sys.o -c -g
arm-linux-gcc main.c -o main.o -c -g
arm-linux-ld sys.o main.o -o sys.elf -T test.lds
arm-linux-objcopy sys.elf sys.bin -O binary
连接文件test.lds(决定sys.o与main.c的连接顺序)
ENTRY(_start)
SECTIONS{
. = 0x41000000;
.text : {
sys.o(.text)
*(.text)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}
中断处理示例(汇编)
.globl _start
_start:
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word _undefined_instruction
_software_interrupt: .word swi_handler
_prefetch_abort: .word _prefetch_abort
_data_abort: .word _data_abort
_not_used: .word _not_used
_irq: .word _irq
_fiq: .word _fiq
stack: .space 16*8
stacktop: .word stack+16*8
stack1: .space 16*8
stacktop1: .word stack1+16*8
buf: .space 16
reset:
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
ldr r0, =0x0
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
ldr r0,=stacktop
ldr sp, [r0]
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd0 @110 10000
msr cpsr,r0
ldr r0,=stacktop1
ldr sp, [r0]
bl _main
_main:
mov r7, #3
mov r8, #6
ldr r0,=buf
str r7,[r0]
str r8,[r0,#4]
bl usr_add
bl usr_sub
nop
nop
usr_add:
stmfd sp!, {lr}
mov r1,#1
ldr r0,=buf
str r1,[r0,#8]
swi 1
ldmfd sp!, {pc}
usr_sub:
stmfd sp!,{lr}
mov r1,#0
ldr r0,=buf
str r1,[r0,#8]
swi 0
ldmfd sp!,{pc}
swi_handler:
stmfd sp!, {lr}
ldr r0,=buf
ldr r1,[r0,#8]
cmp r1,#1
bleq sys_add
cmp r1,#0
bleq sys_sub
ldmfd sp!, {pc}^
sys_add:
stmfd sp!, {lr}
ldr r0,=buf
ldr r7,[r0]
ldr r8,[r0,#4]
add r7, r7, r8
ldmfd sp!, {pc}
sys_sub:
stmfd sp!, {lr}
ldr r0,=buf
ldr r7,[r0]
ldr r8,[r0,#4]
sub r7, r7, r8
ldmfd sp!, {pc}
点灯
.globl _start
_start:
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word _undefined_instruction
_software_interrupt: .word _software_interrupt
_prefetch_abort: .word _prefetch_abort
_data_abort: .word _data_abort
_not_used: .word _not_used
_irq: .word _irq
_fiq: .word _fiq
stack: .space 16*8 @ stack = malloc(16*8)
stacktop: .word stack+16*8
stack1: .space 16*8 @ stack1 = malloc(16*8)
stacktop1: .word stack1+16*8
reset:
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
ldr r0, =0x41000000
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
ldr r0,=stacktop
ldr sp, [r0]
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd0 @110 10000
msr cpsr,r0
ldr r0,=stacktop1
ldr sp, [r0]
bl _main
_main:
ldr r0,=0x114001E0
ldr r1,[r0]
bic r1,r1,#0xf00000
orr r1,r1,#0x100000
str r1,[r0]
ldr r0,=0x114001E4
ldr r1,[r0]
bic r1,r1,#0x20
orr r1,r1,#0x20
str r1,[r0]