躲不过,出来混,ARM汇编还是要学的。本文将结和bootloader中要用到的汇编语句来学习。
如果有疑问,联系Q328333568.
ARM指令在汇编程序中用助记符表示,一般ARM指令的助记符格式为:
<opcode>{<cond>} {S} <Rd>,<Rn>,<op2>
1 init armclk
mov r4, #0xE00
add r4, r4, #0x11
ldr r5, apld_base
str r4, [r5, #APLD_LOCK]
2 init gpio
ldr r5, gpacom
mov r6,#2200
add r6
str r6, [r5]
3 init uart0, 这边都比较好理解,只是为什么是配置这些值得对应DATA SHEET, 如果有问题,联系Q328333568
ldr r5, ucon_base
mov r6, #03
str r6, [r5, #ULCON0]
mov r6, #0xc00
add r6, r6, #0x05
str r6, [r5, #UCON0]
mov r6, #0xx67
str r6, [r5, #CFCON0]
@设置波特率, 我们看到,其实很简单,就是用到两个寄存器,一个存值,一个存地址,把值存入寄存器指向的地址。
ldr r5, =UBRDIV0
mov r6, #35
str r6, [r5]
ldr r5, =UDIVSLPTP
mov r6 #0
str r6, [r5]
ldr r0, =msg
bl my_printf
4 init nand flash
参考:http://www.360doc.com/content/10/1019/16/4026366_62240627.shtml
@init NFCONF 用来设置NAND FLASH 的时序, 数据位宽,是否支持其他大小的页
@下面三个数值如何确定的要参看我后面转的一篇文章。
@tacls = tcls -twp = 21 -21 = 0ns(1.8v) :表示地址锁存到 nWE 有效的时间;
@twrph0= twp = 21ns
@twrph1= tclh = 5ns : 表示nWE无效 到数据或地址无效的延时;
ldr r5, =NAND_BASE
mov r6, #0x200
add r6, r6, #0x4: 到这边又忘记立即数是不是有限制?那寄存器里存了多大就不管?
str r6, [r5, #NFCONF]: 到这里str往哪里放数据都不确定啦,没过几天就不确定,做孽。
@nfcont 用来使能flash 控制器
mov r6, #01
str r6, [r5, #NFCONT]
@read id
@发出命令字90h,发出4个地址序列(都设定为0),然后就可以连续读入5个数据,分别表示厂商代码(对一SAMSUNG公司为Ech)、设备代码(对于K9F1208U0M为76h)、保留的字节(对于K9F1208U0M为A5h)、多层操作代码(C0h表示支持多层操作)。
mov r6, 0x90
str r6, [r5, #NFCMMD] : 写id 命令
mov r6, 0x0:
str r6, [r5, #NFADDR]
@get 5 cycle
mov r6, #5
@test busy
ldr r7, [r5, #NFSTAT]: 只要读一次就可以,不是每读一个BYTE 都要判断
tst r7, #01 : 0表示BUSY,按位与之后结果为0, 那么ALU 的Z置位,beq 将跳回重新判断。其实这个真别扭,beq会让人觉得是要相等,那么tst结果要为1才有eq的感觉。
beq 1b
@show data
2:
ldrb r0, [r5, #NFDATA]
bl show_reg
sub r6, r6, #1
cmp r6, #0 : 这边应该可以不用这句的,因为sub本身会影响全部标志位
bne 2b :如果标志位ZF 不为1,就跳转回2处。
@这边插入sub用法
@init sdram, 比较复杂,比较专业,待查
@读取kernel
mov r3, #0x100
mov r6, #0x400
mov r0, #0x53000000
ldr r5, =NAND_BASE
mov r4, #0x00
str r4, [r5, #NFCMMD]
mov r4, #0x00
str r4, [r5, #NFADDR]
strb r3, [r5, #NFADDR]
lsr r4, r3, #8
strb r4, [r5, #NFADDR]
lsr r4, r3, #16
strb r4, [r5, #NFADDR]
这里对flash的操作进行一个插播:
K9F1208U0M容量为528Mbit,分为131072行(页)、528列,每一页大小为512字节,外加16字节的额外空间,这16字节额外空间的列地址为512 - 527。
所以从上面这句从别人处的引用可以看出,每页的大小跟列数是有关系的。我们用的是2048个字节。
一片NAND Flash为一个设备, 其数据存储分层为:1设备=4 096块;1块=32页;1页=528字节=数据块大小(512字节)+OOB块大小(16字节)。在每一页中,最后16字节(又称OOB,Out of Band)用于NAND Flash命令执行完后设置状态用,剩余512字节又分为前半部分和后半部分。可以通过NAND Flash命令00h/01h/50h分别对前半部、后半部、OOB进行定位,通过NAND Flash内置的指针指向各自的首地址。
1:
ldr r7, [r5, #NFSTAT]
tst r7, #0x1: 发现这样还是很吻合的,r7为0,表示busy, 相与结果为0, 置位ZF,然后beq 成功往回跳转。
beq 1b
2:
ldrb r1, [r5, #NFDATA]
strb r1, [r0]:r0, 就象个指针
add r0, r0, #1: SDRAM地址加1
sub r8, r8, #1
cmp r8, #0
bne 2b :从下面可以知道, 如果r8不为0, 那么不会置位ZF,那么ZF = 0, NE成立,跳到2b处。
插播:
问题:
EQ Z置位 相等
NE Z清零 不相等
CS/HS C置位 无符号数大于或等于
请问标志位的set或者clear是根据什么带条件码之前的语句结果得出的么?
比如说以下代码:
MOVS R0,R0
BNE Label ;书上的注释为:如果R0不为0,则跳转到Label标号处
解答:
MOVS 目的寄存器,源操作数
其中S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。
ARM 中很多指令在其后面加上 "S " 都会影响 CPSR中条件标志位, 如 MVNS, ANDS, ADDS...
这个得看具体是什么指令,根据执行的结果,来判断:
a,Z标志,是否为0;如比较指令产生相等的结果、计算结果为0;
b,N标志,是否为负;如果指令的结果被认为是有符号数,而它的第31位为1,那就会被设置为1;
c,C标志,是否有产生进位/借位,以及进行移位操作时作移出位使用;
d,V标志,有符号数进行运算,结果是否有溢出。
可以分成两种情况来考虑 movs 指令对标志位的影响:
a,假如目标寄存器非r15,也即非PC。那么看所移动的值是否为零或者是否为负来影响 cpsr 中的z标志和n标志;假如 movs 指令中还有移位操作,那么移出位还为被设置到 c标志中。
b,假如目标寄存器是 r15,那不管是 mov 还是 movs ,都会用 spsr 中的值来更新cpsr,其中的标志位自然会受到影响。
这两种情况下,都不会影响到 cpsr 中的 v标志。您可以直接参考 arm_arch_ref_manual 或者参与 JulianTec 的邮件列表像师兄师姐们请教。