1、为了控制多个IIC总线操作,必须将值写入下面的寄存器:
多主控器IIC总线控制寄存器,IICCON;
多主控器IIC总线控制/状态寄存器,IICSTAT;
多主控器IIC总线发送/接收数据移位寄存器,IICDS;
读主控器IIC总线地址寄存器,IICADD。 2、当IIC总线空闲,SDA和SCL线必须是高电平。SDA从高到低转换能启动一个开始条件。当SCL处于高电
平,保持稳定时,SDA从低位到高位传输能启动一个停止条件 3、主设备能一直产生开始和停止条件。开始条件产生后,主控器通过在第一次输出的数据字节中写入7
位的地址来选择从属器设备。第8位用于确定传输方向(读或写)。 4、当主控器发起一个开始条件,它将发送一个从属地址来通知从属器设备。一个字节的地址域包含7位
地址和1位传输方向指示器(表示写或读)。如果位8是0,表示写操作(发送操作);如果位8是1,表示
请求读取数据(接收操作)。 5、在到SDA总线上的每一个数据字节总数上必须是8位。在总线传输操作期间,发送或接收字节没有限制。
数据一直是先从最高有效位(MSB)发送,并且每个字节后面必须立即跟随确认(ACK)位。 设置IIC主、从模式: IICSTAT:0x7F004004 IIC总线控制/状态寄存器 复位值0x0 IICSTART: void IIC_MasterWrp(u8 cSlaveAddr,u8 *pData) { //等待,直到IIC总线被释放(总线空闲状态)32 uTmp0; uTmp0=Inp32(rIICSTAT); while(uTmp0&(1<<5)) { uTmp0=Inp32(rIICSTAT); } //ACK使能,即IIC总线确认有效 u32 uTmp1; uTmp1=Inp32(rIICCON); uTmp1|=(1<<7); Outp32(rIICCON,uTmp1); //从模式地址写入 Outp32(rIICDS,cSlaveAddr); //主控器发送开始准备好 Outp32(rIICSTAT,0xf0);
s32 sDcnt=100; u32 uPT=0; while(!(sDcnt==-1)) { if(Inp8(rIICCON)&0x10)//确认是否IIC总线有效 { if((sDcnt--)==0)//确认已经有8位(一个字节)发送了 { Out32(rIICSTAT,0xd0);//停止主控器发送条件,ACK标志清除 uTmp0=Inp32(rIICCON); uTmp0&=~(1<<4);//清除等待位,重新开始 Out32(rIICCON,uTmp0); Delay(1);//等待,直到停止条件生效 break; } //如果还有位需要发送,则: Outp8(rIICDS,pData[uPT++]);//发送字节 for(cCnt=0;cCnt<10;cCnt++);//用于建立时间(HCSCL的上升沿) } } }
void IIC_MasterRdP(u8 cSlaveAddr,u8 *pData) { u32 uTmp0; u32 uTmp1; u8 cCnt; uTmp0=Inp32(rIICSTAT); while(uTmp0&(1<<5))//等待,直到IIC总线被释放 { uTmp0=Inp32(rIICSTAT); } uTmp1=Inp32(rIICCON); }
多主控器IIC总线控制寄存器 IICLC 0x7F004010 IIC总线主控器线/控制寄存器 复位值0x00
///////////////////////////////////////////////DDR_SDRAM/////////////////////////////////////////////////////////////// 基于ARM PrimeCell CP003 AXI DMC(PL340)的DRAM控制器,来自ARM PrimeCell CP003 AXI动态存储器控制(PL340)。最初的AMBA APB 3.0端口主要用于可编程配置寄存器,他是利用AxiToApb进行转换的。 DRAM控制器有AMBA AXI兼容总线用于设计其配置寄存器和访问SDRAM。在PL340配置寄存器中,DRAM控制器可以通过写芯片配置、ID配置和存储器定时参数来进行编程。在用户配置寄存器,两个较低位主要用于选择存储器的类型。 DRAM控制器可以直接接收一个SDRAM或DRAM控制器本身的指令。通过写指令到直接指令寄存器,DRAM控制器可发送像:Prechargeall Autorefresh NOP MRS EMRS指令到SDRAM. 通过SPCONSLP[4]来控制复位CKE的值。如果0,复位时Xm0CKE和Xm1CKE为0. SDRAM初始化顺序: 上电复位时,软件必须初始化DRAM控制器,SDRAM的每一项都连接到DRAM控制器。仅以SDRAM的数据表为启动程序。 ++++++++++++++++++++++++++++++++++++++++++ 本文系本站原创,欢迎转载! 转载请注明出处: ++++++++++++++++++++++++++++++++++++++++++
1. 概述 S3C6410内存控制器是采用的PL340内存控制芯片。AMBA APB3.0接口协议规定,可以通过编程将AXI从总线接口和APB主总线接口进行桥接,实现二者总线上的数据的传输。
DRAM控制器可以通过配置兼容SDRAM类型芯片。通过向DRAM控制器中PL340写入内存芯片配置参数,内存时序,来控制内存工作。
DRAM控制器可以直接从SDRAM或DRAM接收一个控制命令。通过将操作命令写入direct_cmd寄存器,操作SDRAM进行对应操作。通过向memc_cmd寄存器写入状态模式命令,使DRAM控制器进入对应的工作模式。例如:向direct_cmd寄存器写入:Prechargeall’,‘Autorefresh’,‘NOP’,and ‘MRS’ 等命令,可以让SDRAM芯片分别执行不同操作,向memc_cmd寄存器写入一些状态命令可以让SDRAM芯片进入’Config’, ‘Ready’, and ‘Low_power’等工作模式。
DRAM控制器支持两种节能模式。当SDRAM处于不活动状态并且持续一定的时钟周期时,DRAM控制器会自动将SDRAM进入预充电节能模式或正常节能模式下以降低系统功耗。当驱动操作DRAM控制器进入对应的STOP(停止),Deep Stop(深度睡眠),Sleep Mode(睡眠)等模式时,SDRAM芯片进入自刷新的节能模式。 l 支持SDR SDRAM,Mobile SDR SDRAM,DDR SDRAM和Mobile DDR SDRAM类型芯片 l 支持两个内存芯片 l 支持64位的AMBA AXI总线类型 l 支持16位、64位内存总线 n 存储器接口1:支持16位DDR SDRAM和Mobile DDR SDRAM类型芯片 支持32位DDR SDRAM,Mobile DDR SDRAM,Mobile SDR SDRAM和SDR SDRAM类型芯片 不支持16位Mobile SDR SDRAM和SDR SDRAM类型芯片 l 地址空间:存储器接口1支持最多2Gb地址空间 l 支持正常节能模式和预充电的节能模式 l 数据传输低延迟特性 l 外部存储器总线优化 l 通过设置SFR寄存器支持选择外部存储器选型 l 通过SFR寄存器配置存储器的时序 l 支持扩展MRS指令集 l 工作电压:存储器接口1: 1.8V,2.5V
2. SDRAM类型内存接口 DRAM控制器支持最多两个相同类型的内存芯片,每个芯片最大容量256M。所有芯片共享相同引脚(时钟使能引脚和片选引脚除外),如表1-1所示给出了DRAM控制器的外部存储器引脚配置信息。 3. SDRAM初始化 在系统上电后,必须通过软件配置SDRAM接入DRAM控制器并且初始化DRAM控制器,下面给出DDR、MOBILE DDR SDRAM的初始化流程。 a) 向mem_cmd寄存器写入0b10,使其进入NOP工作状态 b) 向mem_cmd寄存器写入0b00,使其进入Prechargeall(整片预充电)工作状态 c) 向mem_cmd寄存器写入0b11,使其进入Autorefresh(自刷新)工作状态 d) 再次向mem_cmd寄存器写入0b11,使其进入Autorefresh(自刷新)工作状态 e) 向mem_cmd寄存器写入0b10,使其进入MRS工作状态,并且地址空间内的EMRS必须置位 f) 再次向mem_cmd寄存器写入0b10,使其进入MRS工作状态,并且地址空间内的MRS必须置位
4. DRAM寄存器 1) DRAM控制器状态寄存器(P1MEMSTAT) P1MEMSTAT | 位 | 描述 | 初始值 | 保留 | [31:9] | - | - | 芯片数量 | [8:7] | 内存控制器支持的芯片最大数量: 01 = 2片 6410只支持2片芯片,初始化为只读的01 | 01 | 芯片类型 | [6:4] | 内存控制器支持的芯片类型: 100 = MSDR/SDR/MDDR/DDR中任一类型 | 100 | 芯片位宽 | [3:2] | 接入内存芯片的位宽: 00 = 16位 01 = 32位 10 = 保留 11 = 保留 | 01 | 控制器状态 | [1:0] | DRAM控制器状态: 00 = Config配置状态 01 = Ready就绪状态 10 = Pause暂停状态 11 = Low-Power节能状态 | 00 |
实际上,读到的有用信息就是Controller Status和Memory width。
2) DRAM控制器命令寄存器(P1MEMCCMD) P1MEMCCMD | 位 | 描述 | 初始值 | 保留 | [31:3] | 未定义,写入0 | - | Memc_cmd | [2:0] | 设置内存控制器的工作状态: 000 = Go 001 = sleep 010 = wakeup 011 = Pause 100 = Configure 101~111 = 保留 |
|
最开始应该配置为0x4,是处于Configure状态。在配置完所有的DRAM之后,将该寄存器设置为0x0,处于运行状态。
3) 直接命令寄存器(P1DIRECTCMD) P1DIRECTCMD | 位 | 描述 | 初始值 | 保留 | [31:23] | 未定义,写入0 |
| 扩展内存命令 | [22] | (见下表) |
| 芯片号 | [21:20] | 映射到外部存储芯片地址的位 |
| 命令 | [19:18] | 具体命令(见下表) |
| Bank地址 | [17:16] | 当以MRS或EMRS命令访问时,映射到外部存储器的Bank地址位 |
|
| [15:14] | 未定义,写入0 |
| 地址线0~13 | [13:0] | 当以MRS或EMRS命令访问时,映射到外部存储器的内存地址位 |
|
用于发送命令到DRAM和访问DRAM中的MRS和EMRS寄存器。通过该寄存器初始化DRAM,先设置为NOP模式,然后设置为PrechargeAll进行充电,然后设置EMRS和MRS寄存器,一般是这么一个流程。具体的要参见你所使用的DRAM的datasheet。
4) 内存配置寄存器(P1MEMCFG) P1MEMCFG | 位 | 描述 | 初始值 | 保留 | [31:23] | 未定义 |
| 启动芯片 | [22] | 使能下面数量的芯片开始执行刷新操作: 00 = 1芯片 01 = 2芯片 10/11 = 保留 | 00 |
QoS master位 | [20:18] | 设置QoS值: 000 = ARID[3:0] 001= ARID[4:1] 010 = ARID[5:2] 011 = ARID[6:3] 100 = ARID[7:4] 101~111 = 保留 | 000 | 内存突发访问 | [17:15] | 在内存读写时,设置突发访问数据的数量: 000 = 突发访问1个数据 001 = 突发访问2个数据 010 = 突发访问4个数据 011 = 突发访问8个数据 100 = 突发访问16个数据 101~111 = 保留 该值必须通过DIRECTORYCMD寄存器,写入到内存的模式寄存器中,并且数据必须匹配 | 010 | Bank地址 | [17:16] | 当以MRS或EMRS命令访问时,映射到外部存储器的Bank地址位 |
| Stop_mem_clock | [14] | 当停止芯片时钟,不允许访问内存数据时,置位 | 0 | 自动节能 | [13] | 当该位置位时,芯片自动进入节能状态 | 0 | 关闭芯片延迟时间 | [12:7] | 当关闭内存芯片时,延迟的时钟个数 | 000000 | 自动预充电位 | [6] | 内存地址中自动预充电位的位置: 0 = ADDR[10] 1 = ADDR[8] | 0 | 行地址位数 | [5:3] | AXI地址线上的行地址位数: 000 = 11位 001 = 12位 010 = 13位 011 = 14位 100 = 15位 101= 16位 | 100 | 列地址位数 | [2:0] | AXI地址线上的列地址位数: 000 = 8位 001 = 9位 010 = 10位 011 = 11位 100 = 12位 | 000 |
参考DRAM的datasheet。
5) 内存刷新时间寄存器(P1REFRESH) P1REFRESH | 位 | 描述 | 初始值 |
| [31:15] | - |
| 刷新时间 | [14:0] | 内存刷新时钟周期数 | 0xA60 |
6) CAS 延迟寄存器(P1CASLAT) P1CASLAT | 位 | 描述 | 初始值 |
| [31:4] | - | - | CAS延迟 | [3:1] | 列地址选通延迟内存时钟周期数 | 0xA60 | CAS HALF周期 | [0] | 设置CAS延迟数是否为半个内存时钟周期 0 = 以[3:1]设置数为CAS延迟时钟周期 1 = 以[3:1]设置数的一半为CAS延迟时钟周期 | 0 |
参考DRAM的datasheet。
下面13个寄存器用于DRAM操作中所需时间和延时寄存器,具体可以参考PL340文档。 7) T_DQSS寄存器(P1T_DQSS) P1T_DQSS | 位 | 描述 | 初始值 |
| [31:2] | - | - | t_DQSS | [1:0] | 写入DQS的时钟周期 | 1 |
8) T_MRD寄存器(P1T_MRD) P1T_MRD | 位 | 描述 | 初始值 |
| [31:7] | - | - | t_ MRD | [6:0] | 设置模式寄存器命令时间(内存时钟周期为单位) | 0x02 |
9) T_RAS寄存器(P1T_RAS) P1T_RAS | 位 | 描述 | 初始值 |
| [31:4] | - | - | t_RAS | [3:0] | 设置行地址选通到预充电操作延迟时间(内存时钟周期为单位) | 0x7 |
10) T_RC寄存器(P1T_RC) P1T_RC | 位 | 描述 | 初始值 |
| [31:4] | - | - | t_RC | [3:0] | 设置激活内存Bank x到激活另外一个Bank x操作的延迟时间(内存时钟周期为单位) | 0xB |
11) T_RCD寄存器(P1T_RCD) P1T_RCD | 位 | 描述 | 初始值 |
| [31:6] | - | - | Scheduled_RCD | [5:3] | 设置t_RCD-3 | 011 | t_RCD | [2:0] | 设置RAS到CAS操作的最小延迟时间(内存时钟周期为单位) | 101 |
12) T_RFC寄存器(P1T_RFC) P1T_RFC | 位 | 描述 | 初始值 |
| [31:10] | - | - | Scheduled_RFC | [9:5] | 设置t_RFC-3 | 0x10 | t_RFC | [4:0] | 设置自动刷新命令操作延迟时间(内存时钟周期为单位) | 0x12 |
13) T_RP寄存器(P1T_RP) P1T_RP | 位 | 描述 | 初始值 |
| [31:6] | - | - | Scheduled_RP | [5:3] | 设置t_RP-3 | 011 | t_RFC | [2:0] | 设置预充电到RAS操作的延迟时间(内存时钟周期为单位) | 101 |
14) T_RRD寄存器(P1T_RRD) P1T_ RRD | 位 | 描述 | 初始值 |
| [31:4] | - | - | t_RRD | [3:0] | 设置激活内存Bank x到激活内存Bank y操作的延迟时间(内存时钟周期为单位) | 0x2 |
15) T_WR寄存器(P1T_WR) P1T_ WR | 位 | 描述 | 初始值 |
| [31:3] | - | - | t_WR | [2:0] | 设置写入数据到预充电操作的延迟时间(内存时钟周期为单位) | 011 |
16) T_WTR寄存器(P1T_WTR) P1T_ WTR | 位 | 描述 | 初始值 |
| [31:3] | - | - | t_WTR | [2:0] | 设置写入数据到读取数据操作的延迟时间(内存时钟周期为单位) | 011 |
17) T_XP寄存器(P1T_XP) P1T_ XP | 位 | 描述 | 初始值 |
| [31:8] | - | - | t_XP | [7:0] | 设置退出关闭 电源命令的延迟时间(内存时钟周期为单位) | 0x1 |
18) T_XSR寄存器(P1T_XSR) P1T_ XSR | 位 | 描述 | 初始值 |
| [31:8] | - | - | t_XSR | [7:0] | 设置退出自刷新命令的延迟时间(内存时钟周期为单位) | 0xA |
19) T_ESR寄存器(P1T_ESR) P1T_ ESR | 位 | 描述 | 初始值 |
| [31:8] | - | - | t_ESR | [7:0] | 设置自刷新命令的延迟时间(内存时钟周期为单位) | 0x14 |
内存初始化代码: (开发环境为ADS1.2) [plain] view plaincopyprint?
- MEM_SYS_CFG EQU 0x7e00f120
- DMC1_BASE EQU 0x7e001000
- INDEX_DMC_MEMC_STATUS EQU 0x0
- INDEX_DMC_MEMC_CMD EQU 0x4
- INDEX_DMC_DIRECT_CMD EQU 0x08
- INDEX_DMC_MEMORY_CFG EQU 0x0c
- INDEX_DMC_REFRESH_PRD EQU 0x10
- INDEX_DMC_CAS_LATENCY EQU 0x14
- INDEX_DMC_T_DQSS EQU 0x18
- INDEX_DMC_T_MRD EQU 0x1c
- INDEX_DMC_T_RAS EQU 0x20
- INDEX_DMC_T_RC EQU 0x24
- INDEX_DMC_T_RCD EQU 0x28
- INDEX_DMC_T_RFC EQU 0x2c
- INDEX_DMC_T_RP EQU 0x30
- INDEX_DMC_T_RRD EQU 0x34
- INDEX_DMC_T_WR EQU 0x38
- INDEX_DMC_T_WTR EQU 0x3c
- INDEX_DMC_T_XP EQU 0x40
- INDEX_DMC_T_XSR EQU 0x44
- INDEX_DMC_T_ESR EQU 0x48
- INDEX_DMC_MEMORY_CFG2 EQU 0x4C
- INDEX_DMC_CHIP_0_CFG EQU 0x200
- INDEX_DMC_CHIP_1_CFG EQU 0x204
- INDEX_DMC_CHIP_2_CFG EQU 0x208
- INDEX_DMC_CHIP_3_CFG EQU 0x20C
- INDEX_DMC_USER_STATUS EQU 0x300
- INDEX_DMC_USER_CONFIG EQU 0x304
- AREA LOW_INIT, CODE, READONLY
- ENTRY
- EXPORT mem_init
- //第一步:设置内存子系统配置寄存器
- mem_init
- //使用ldr伪指令装载MEM_SYS_CFG的地址到r0
- ldr r0, =MEM_SYS_CFG ;Memory sussystem address 0x7e00f120
- //将立即数0xd放到r1中
- mov r1, #0xd ;Xm0CSn2 = NFCON CS0 设置NAND Flash为存储器
- //str是把寄存器上的数据传输到指定地址的寄存器上:str(条件)源寄存器,<存储器地址>
- str r1, [r0] ;在r0地址上写数据r1
- //第二步:设置DRAM控制器状态寄存器基地址
- //DRAM控制器状态寄存器
- //使用ldr伪指令装载DMC1_BASE的地址r0
- ldr r0, =DMC1_BASE ;DMC1 base address 0x7e001000
- //第三步:配置SDRAM 控制器命令寄存器
- ; memc_cmd : 010 wake up
- ; 唤醒内存
- //最开始应该配置为0x4,处于configure状态,在配置完所有的DRAM之后,将该寄存器设置为0x0,处于运行状态
- //使用ldr伪指令0x04
- ldr r1, =0x04
- //将r1的数据存储到r0+INDEX_DMC_MEMC_CMD存储单元,r0值不变
- str r1, [r0, #INDEX_DMC_MEMC_CMD]
- //第四步:设置SDRAM的行刷新周期
- //配置DDR SDRAM的行刷新时间
- ; Refresh period = ((Startup_HCLK / 1000 * DDR_tREFRESH) - 1) / 1000000 -> DDR_tREFRESH 7800 ns
- ; HCLK = 133MHz
- ; DDR内存规格规定,电容的电荷存储上限时间为64ms,而刷新操作每次是针对
- ; 一行进行的,即每一行的刷新时间为64ms,而内存芯片中一定数量的行
- ; 以L-Bank表示(见内存工作原理与物理特性),每个L-Bank有8192行(见内存硬件手册)
- ; 因此对L-Bank的刷新操作应该在64ms /8192 = 7813us时间内进行一次
- ; 而MDDR工作在133MHz时,其一个时钟周期为1/133M,那么一次L-Bank刷新
- ; 时间需要7.8us/1/133M个时钟周期,即有下面的公式:
- ; Refresh_Count = tREFRESH * HCLK(MHz)/1000
- ; tREFRESH = 7813 HCLK = 133 Refresh_Count = 1039
- //把立即数1039放到r1中
- ldr r1, = 1039 ; DMC_DDR_REFRESH_PRD
- //将r1的值放到地址为r0+INDEX_DMC_REFRESH_PRD
- str r1, [r0, #INDEX_DMC_REFRESH_PRD]
- ; CAS_Latency = DDR_CASL<<1 -> DDR_CASL 3
- //第五步:配置CAS延迟寄存器,默认初始值为6
- //把立即数6放入r1中
- ldr r1, = 6 ; DMC_DDR_CAS_LATENCY
- //str指令是把r1的数据传到r0+INDEX_DMC_CAS_LATENCY
- str r1, [r0, #INDEX_DMC_CAS_LATENCY]
- ; t_DQSS (clock cycles)
- //第六步:写入DQS的时钟周期,默认为0x1
- //数据选通脉冲DQS DQS是DDR中的重要功能,主要用来在一个时钟周期内准确的区分出每个传输周期,并便于//
- 接收数据
- //装载数据1到r1
- ldr r1, = 1 ; DMC_DDR_t_DQSS
- //str指令是把r1的数据传到r0+INDEX_DMC_T_DQSS
- str r1, [r0, #INDEX_DMC_T_DQSS]
- ; T_MRD (clock cycles)
- //第七步:MRD: 接收数据缓冲区首址,默认为2
- ldr r1, = 2 ; DMC_DDR_t_MRD
- str r1, [r0, #INDEX_DMC_T_MRD]
- ; T_RAS (clock cycles)
- //第八步:设置行地址选通到预充电操作延迟时间,默认为0x7
- ldr r1, = 7 ; DMC_DDR_t_RAS
- str r1, [r0, #INDEX_DMC_T_RAS]
- ; T_RC Active Bank x to Active Bank x delay(clock cycles)
- //第九 设置激活内存bank x到激活另一个BANK X操作的延迟时间
- ldr r1, = 10 ; DMC_DDR_t_RC
- str r1, [r0, #INDEX_DMC_T_RC]
- ; T_RCD RAS to CAD delay(clock cycles)
- ldr r1, = 4 ; DMC_DDR_t_RCD
- ldr r2, = 8 ; DMC_DDR_schedule_RCD
- //第十步:设置RAS到CAS操作的最小延迟时间(内存时钟周期为单位)
- //将寄存器r1的值与r2的值按位做逻辑 或 操作,结果保存在r1中
- 默认为0x1D
- orr r1, r1, r2
- str r1, [r0, #INDEX_DMC_T_RCD]
- ; T_RFC AutoRefresh(clock cycles)
- //第十一:
- ldr r1, = 11 ; DMC_DDR_t_RFC
- ldr r2, = 256 ; DMC_DDR_schedule_RFC
- //r1 | r2的结果保存在r1中
- orr r1, r1, r2
- //
- str r1, [r0, #INDEX_DMC_T_RFC]
- ; T_RP Precharge to RAS delay(clock cycles)
- ldr r1, = 4 ; DMC_DDR_t_RP
- ldr r2, = 8 ; DMC_DDR_schedule_RP
- //r1 = r1 | r2
- orr r1, r1, r2
- str r1, [r0, #INDEX_DMC_T_RP]
- ; T_RRD Active Bank x to Active Bank y delay(clock cycles)
- ldr r1, = 3 ; DMC_DDR_t_RRD
- str r1, [r0, #INDEX_DMC_T_RRD]
- ; T_WR Write to precharge delay(clock cycles)
- ldr r1, =3 ; DMC_DDR_t_WR
- str r1, [r0, #INDEX_DMC_T_WR]
- ; T_WTR Write to Read delay(clock cycles)
- ldr r1, = 2 ;DMC_DDR_t_WTR
- str r1, [r0, #INDEX_DMC_T_WTR]
- ; T_XP Exit Power down(clock cycles)
- ldr r1, = 2 ; DMC_DDR_t_XP
- str r1, [r0, #INDEX_DMC_T_XP]
- ; T_XSR Exit self refresh(clock cycles)
- ldr r1, = 17 ; DMC_DDR_t_XSR
- str r1, [r0, #INDEX_DMC_T_XSR]
- ; T_ESR SelfRefresh(clock cycles)
- ldr r1, = 17 ; DMC_DDR_t_ESR
- str r1, [r0, #INDEX_DMC_T_ESR]
- ; Memory Configuration Register
- ldr r1, = 0x40010012 ; DMC1_MEM_CFG
- str r1, [r0, #INDEX_DMC_MEMORY_CFG]
- ldr r1, = 0xb41 ; DMC1_MEM_CFG2
- str r1, [r0, #INDEX_DMC_MEMORY_CFG2]
- ldr r1, = 0x150f8 ; DMC1_CHIP0_CFG
- str r1, [r0, #INDEX_DMC_CHIP_0_CFG]
- ldr r1, = 0 ; DMC_DDR_32_CFG
- str r1, [r0, #INDEX_DMC_USER_CONFIG]
- ; The follows is according to the Datasheet initialization sequence
- ;DMC0 DDR Chip 0 configuration direct command reg
- ldr r1, = 0x0c0000 ; DMC_NOP0
- str r1, [r0, #INDEX_DMC_DIRECT_CMD]
- ;Precharge All
- ldr r1, = 0 ; DMC_PA0
- str r1, [r0, #INDEX_DMC_DIRECT_CMD]
- ;Auto Refresh 2 time
- ldr r1, = 0x40000 ; DMC_AR0
- str r1, [r0, #INDEX_DMC_DIRECT_CMD]
- str r1, [r0, #INDEX_DMC_DIRECT_CMD]
- ;MRS
- ldr r1, = 0xa0000 ; DMC_mDDR_EMR0
- str r1, [r0, #INDEX_DMC_DIRECT_CMD]
- ;Mode Reg
- ldr r1, = 0x80032 ; DMC_mDDR_MR0
- str r1, [r0, #INDEX_DMC_DIRECT_CMD]
- ;Enable DMC1
- //将值0x0放到r1中
- mov r1, #0x0
- str r1, [r0, #INDEX_DMC_MEMC_CMD]
- check_dmc1_ready
- ldr r1, [r0, #INDEX_DMC_MEMC_STATUS]
- mov r2, #0x3
- //r1 = r1 & r2
- and r1, r1, r2
- //比较r1是否为0x1
- cmp r1, #0x1
- //跳转指令,如果不等,则跳转到check_dmc1_ready
- bne check_dmc1_ready
- nop
- //lr的值移到pc
- mov pc, lr
- ARM指令集详解
;来源: MCU嵌入式领域 ARM可以用两套指令集:ARM指令集和Thumb指令集。本文介绍ARM指令集。在介绍ARM指令集之前,先介绍指令的格式。
1 指令格式
(1)基本格式
{}{S} ,{,}
其中,<>内的项是必须的,{}内的项是可选的,如是指令助记符,是必须的,而{}为指令执行条件,是可选的,如果不写则使用默认条件AL(无条件执行)。
opcode 指令助记符,如LDR,STR 等
cond 执行条件,如EQ,NE 等
S 是否影响CPSR 寄存器的值,书写时影响CPSR,否则不影响
Rd 目标寄存器
Rn 第一个操作数的寄存器
operand2 第二个操作数
指令格式举例如下:
LDR R0,[R1] ;读取R1 地址上的存储器单元内容,执行条件AL
BEQ DATAEVEN ;跳转指令,执行条件EQ,即相等跳转到DATAEVEN
ADDS R1,R1,#1 ;加法指令,R1+1=R1 影响CPSR 寄存器,带有S
SUBNES R1,R1,#0xD;条件执行减法运算(NE),R1-0xD=>R1,影响CPSR 寄存器,带有S
(2)第2个操作数
在ARM 指令中,灵活的使用第2个操作数能提高代码效率,第2个操作数的形式如下:
#immed_8r
常数表达式,该常数必须对应8 位位图,即常数是由一个8 位的常数循环移位偶数位得到。
合法常量
0x3FC、0、0xF0000000、200、0xF0000001等都是合法常量。
非法常量
0x1FE、511、0xFFFF、0x1010、0xF0000010等都是非法常量。
常数表达式应用举例如下:
MOV R0,#1 ;R0=1
AND R1,R2,#0x0F ;R2 与0x0F,结果保存在R1
LDR R0,[R1],#-4 ;读取R1 地址上的存储器单元内容,且R1=R1-4
Rm
寄存器方式,在寄存器方式下操作数即为寄存器的数值。
寄存器方式应用举例:
SUB R1,R1,R2 ;R1-R2=>R1
MOV PC,R0 ;PC=R0,程序跳转到指定地址
LDR R0,[R1],-R2 ;读取R1 地址上的存储器单元内容并存入R0,且R1=R1-R2
Rm, shift
寄存器移位方式。将寄存器的移位结果作为操作数,但RM 值保存不变,移位方法如下:
ASR #n 算术右移n 位(1≤n≤32)
LSL #n 逻辑左移n 位(1≤n≤31)
LSR #n 逻辑左移n 位(1≤n≤32)
ROR #n 循环右移n 位(1≤n≤31)
RRX 带扩展的循环右移1位
type Rs 其中,type 为ASR,LSL,和ROR 中的一种;Rs 偏移量寄存器,低8位有效,若其值大于或等于32,则第2 个操作数的结果为0(ASR、ROR例外)。
寄存器偏移方式应用举例:
ADD R1,R1,R1,LSL #3 ;R1=R1*9
SUB R1,R1,R2,LSR#2 ;R1=R1-R2*4
R15 为处理器的程序计数器PC,一般不要对其进行操作,而且有些指令是不允许使用R15,如UMULL 指令。
(3)条件码
使用指令条件码,可实现高效的逻辑操作,提高代码效率。表A-1给出条件码表。
表A-1 条件码表
对于Thumb指令集,只有B 指令具有条件码执行功能,此指令条件码同表A-?,但如果为无条件执行时,条件码助记符“AL”不能在指令中书写。
条件码应用举例如下:
比较两个值大小,并进行相应加1 处理,C 代码为:
if(a>b)a++ ;
else b++ ;
对应的ARM 指令如下。其中R0为a,R1为b。
CMP R0,R1 ; R0 与R1 比较
ADDHI R0,R0,#1 ; 若R0>R1,则R0=R0+1
ADDLS R1,R1,#1 ;若R0<=R1,则R1=R1+1
若两个条件均成立,则将这两个数值相加,C代码为:
If((a!=10)&&(b!=20)) a=a+b;
对应的ARM 指令如下,其中R0 为a,R1 为b。
CMP R0,#10 ; 比较R0 是否为10
CMPNE R1,#20 ; 若R0 不为10,则比较R1 是否20
ADDNE R0,R0,R1 ; 若R0 不为10 且R1 不为20,指令执行,R0=R0+R1
2 ARM 存储器访问指令
ARM 处理是加载/存储体系结构的典型的RISC 处理器,对存储器的访问只能使用加载和存储指令实现。ARM 的加载/存储指令是可以实现字、半字、无符/有符字节操作;批量加载/存储指令可实现一条指令加载/存储多个寄存器的内容,大大提高效率;SWP指令是一 条寄存器和存储器内容交换的指令,可用于信号量操作等。ARM 处理器是冯?诺依曼存储结构,程序空间、RAM 空间及IO 映射空间统一编址,除对对RAM 操作以外,对外围IO、程序数据的访问均要通过加载/存储指令进行。表A-2给出ARM 存储访问指令表。
表A-2 ARM 存储访问指令表
[url=http://www.mculy.com/batch.download.php?aid=8710]
LDR 和STR
加载/存储字和无符号字节指令。使用单一数据传送指令(STR 和LDR)来装载和存储单一字节或字的数据从/到内存。LDR 指令用于从内存中读取数据放入寄存器中;STR 指令用于将寄存器中的数据保存到内存。指令格式如下:
LDR{cond}{T} Rd,<地址>;加载指定地址上的数据(字),放入Rd 中
STR{cond}{T} Rd,<地址>;存储数据(字)到指定地址的存储单元,要存储的数据在Rd中
LDR{cond}B{T} Rd,<地址>;加载字节数据,放入Rd中,即Rd最低字节有效,高24位清零
STR{cond}B{T} Rd,<地址>;存储字节数据,要存储的数据在Rd,最低字节有效
其中,T 为可选后缀,若指令有T,那么即使处理器是在特权模式下,存储系统也将访问看成是处理器是在用户模式下。T 在用户模式下无效,不能与前索引偏移一起使用T。
LDR/STR 指令寻址是非常灵活的,由两部分组成,一部分为一个基址寄存器,可以为任一个通用寄存器,另一部分为一个地址偏移量。地址偏移量有以下3 种格式:
(1) 立即数。立即数可以是一个无符号数值,这个数据可以加到基址寄存器,也可以从基址寄存器中减去这个数值。指令举例如下:
LDR R1,[R0,#0x12] ;将R0+0x12 地址处的数据读出,保存到R1 中(R0 的值不变)
LDR R1,[R0,#-0x12];将R0-0x12 地址处的数据读出,保存到R1 中(R0 的值不变)
LDR R1,[R0] ;将R0 地址处的数据读出,保存到R1 中(零偏移)
(2)寄存器。寄存器中的数值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。指令举例值。指令举例如下:
LDR R1,[R0,R2] ;将R0+R2 地址的数据计读出,保存到R1 中(R0 的值不变)
LDR R1,[R0,-R2] ;将R0-R2 地址处的数据计读出,保存到R1 中(R0 的值不变)
(3)寄存器及移位常数。寄存器移位后的值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。指令举例如下:
LDR R1,[R0,R2,LSL #2] ;将R0+R2*4地址处的数据读出,保存到R1中(R0,R2的值不变)
LDR R1,[R0,-R2,LSL #2];将R0-R2*4地址处的数据计读出,保存到R1中(R0,R2的值不变)
从寻址方式的地址计算方法分,加载/存储指令有以下4 种形式:
(1)零偏移。Rn 的值作为传送数据的地址,即地址偏移量为0。指令举例如下:
LDR Rd,[Rn]
(2)前索引偏移。在数据传送之前,将偏移量加到Rn 中,其结果作为传送数据的存储地址。若使用后缀“!”,则结果写回到Rn 中,且Rn 值不允许为R15。指令举例如下:
LDR Rd,[Rn,#0x04]!
LDR Rd,[Rn,#-0x04]
(3)程序相对偏移。程序相对偏移是索引形式的另一个版本。汇编器由PC 寄存器计算偏移量,并将PC 寄存器作为Rn 生成前索引指令。不能使用后缀“!”。指令举例如下:
LDR Rd,label ;label 为程序标号,label 必须是在当前指令的±4KB 范围内
(4) 后索引偏移。Rn 的值用做传送数据的存储地址。在数据传送后,将偏移量与Rn相加,结果写回到Rn 中。Rn 不允许是R15。指令举例如下:
LDR Rd,[Rn],#0x04
地址对准--大多数情况下,必须保证用于32 位传送的地址是32 位对准的。
加载/存储字和无符号字节指令举例如下:
LDR R2,[R5] ;加载R5 指定地址上的数据(字),放入R2 中
STR R1,[R0,#0x04] ;将R1 的数据存储到R0+0x04 存储单元,R0 值不变
LDRB R3,[R2],#1 ;读取R2 地址上的一字节数据,并保存到R3 中,R2=R3+1
STRB R6,[R7] ;读R6 的数据保存到R7 指定的地址中,只存储一字节数据
加载/存储半字和带符号字节。这类LDR/STR 指令可能加载带符字节加载带符号半字、加载/存储无符号半字。偏移量格式、寻址方式与加载/存储字和无符号字节指令相同。指令格式如下:
LDR{cond}SB Rd,<地址> ;加载指定地址上的数据(带符号字节),放入Rd 中
LDR{cond}SH Rd,<地址> ;加载指定地址上的数据(带符号字节),放入Rd 中
LDR{cond}H Rd,<地址> ;加载半字数据,放入Rd中,即Rd最低16 位有效,高16位清零
STR{cond}H Rd,<地址> ;存储半字数据,要存储的数据在Rd,最低16 位有效
说明:带符号位半字/字节加载是指带符号位加载扩展到32 位;无符号位半字加载是指零扩展到32 位。
地址对准--对半字传送的地址必须为偶数。非半字对准的半字加载将使Rd 内容不可靠,非半字对准的半字存储将使指定地址的2 字节存储内容不可靠。
加载/存储半字和带符号字节指令举例如下:
LDRSB R1[R0,R3] ;将R0+R3 地址上的字节数据读出到R1,高24 位用符号位扩展
LDRSH R1,[R9] ;将R9 地址上的半字数据读出到R1,高16 位用符号位扩展
LDRH R6,[R2],#2 ;将R2 地址上的半字数据读出到R6,高16 位用零扩展,R2=R2+1
SHRH R1,[R0,#2]!;将R1 的数据保存到R2+2 地址中,只存储低2 字节数据,R0=R0+2
LDR/STR 指令用于对内存变量的访问,内存缓冲区数据的访问、查表、外设的控制操作等等,若使用LDR 指令加载数据到PC 寄存器,则实现程序跳转功能,这样也就实现了程序散转。
变量的访问
NumCount EQU 0x40003000 ;定义变量NumCount
…
LDR R0,=NumCount ;使用LDR 伪指令装载NumCount 的地址到R0
LDR R1,[R0] ;取出变量值
ADD R1,R1,#1 ;NumCount=NumCount+1
STR R1,[R0] ;保存变量值
…
GPIO 设置
GPIO-BASE EQU 0Xe0028000 ;定义GPIO 寄存器的基地址
…
LDR R0,=GPIO-BASE
LDR R1,=0x00FFFF00 ;装载32 位立即数,即设置值
STR R1,[R0,#0x0C] ;IODIR=0x00FFFF00, IODIR 的地址为0xE002800C
MOV R1,#0x00F00000
STR R1,[R0,#0x04] ;IOSET=0x00F00000,IOSET 的地址为0xE0028004
…
程序散转
…
MOV R2,R2,LSL #2 ;功能号乘上4,以便查表
LDR PC,[PC,R2] ;查表取得对应功能子程序地址,并跳转
NOP
FUN-TAB DCD FUN-SUB0
DCD FUN-SUB1
DCD FUN-SUB2
…
LDM 和STM
批量加载/存储指令可以实现在一组寄存器和一块连续的内存单元之间传输数据。LDM 为加载多个寄存器,STM 为存储多个寄存器。允许一条指令传送16 个寄存器的任何子集或所有寄存器。指令格式如下:
LDM{cond}<模式> Rn{!},reglist{^}
STM{cond}<模式> Rn{!},reglist{^}
LDM /STM 的主要用途是现场保护、数据复制、参数传送等。其模式有8 种,如下所列:(前面4 种用于数据块的传输,后面4 种是堆栈操作)。
(1) IA:每次传送后地址加4
(2) IB:每次传送前地址加4
(3) DA:每次传送后地址减4
(4) DB:每次传送前地址减4
(5) FD:满递减堆栈
(6) ED:空递增堆栈
(7) FA:满递增堆栈
(8) EA:空递增堆栈
其中,寄存器Rn 为基址寄存器,装有传送数据的初始地址,Rn 不允许为R15;后缀“!”表示最后的地址写回到Rn 中;寄存器列表reglist 可包含多于一个寄存器或寄存器范围,使用“,”分开,如{R1,R2,R6-R9},寄存器排列由小到大排列;“^”后缀不允许在用户模式呈系统模式下使 用,若在LDM 指令用寄存器列表中包含有PC 时使用,那么除了正常的多寄存器传送外,将SPSR 拷贝到CPSR 中,这可用于异常处理返回;使用“^”后缀进行数据传送且寄存器列表不包含PC 时,加载/存储的是用户模式的寄存器,而不是当前模式的寄存器。
地址对准――这些指令忽略地址的位[1:0]。
批量加载/存储指令举例如下:
LDMIA R0!,{R3-R9} ;加载R0 指向的地址上的多字数据,保存到R3~R9 中,R0 值更新
STMIA R1!,{R3-R9} ;将R3~R9 的数据存储到R1 指向的地址上,R1 值更新
STMFD SP!,{R0-R7,LR} ;现场保存,将R0~R7、LR 入栈
LDMFD SP!,{R0-R7,PC}^;恢复现场,异常处理返回
在进行数据复制时,先设置好源数据指针,然后使用块拷贝寻址指令LDMIA/STMIA、LDMIB/STMIB、LDMDA/STMDA、LDMDB /STMDB 进行读取和存储。而进行堆栈操作时,则要先设置堆栈指针,一般使用SP 然后使用堆栈寻址指令STMFD/LDMFD、STMED。LDMED、STMFA/LDMFA、STMEA/LDMEA 实现堆栈操作。
多寄存器传送指令示意图如图A-1所示,其中R1为指令执行前的基址寄存器,R1’则为指令执行完后的基址寄存器。
数据是存储在基址寄存器的地址之上还是之下,地址是在存储第一个值之前还是之后增加还是减少。表A-3给出多寄存器传送指令映射示意表。
使用LDM/STM 进行数据复制例程如下:
…
LDR R0,=SrcData ;设置源数据地址
LDR R1,=DstData ;设置目标地址
LDMIA R0,{R2-R9} ;加载8 字数据到寄存器R2~R9
STMIA R1,{R2-R9} ;存储寄存器R2~R9 到目标地址
使用LDM/STM 进行现场寄存器保护,常在子程序中或异常处理使用:
SENDBYTE
STMFD SP!,{R0-R7,LR} ;寄存器入堆
…
BL DELAY ;调用DELAY 子程序
…
LDMFD SP!,{R0-R7,PC} ;恢复寄存器,并返回
SWP
寄存器和存储器交换指令。SWP指令用于将一个内存单元(该单元地址放在寄存器Rn中)的内容读取到一个寄存器Rd 中,同时将另一个寄存器Rm 的内容写入到该内存单元中。使用SWP 可实现信号量操作。
指令格式如下:
SWP{cond}{B} Rd,Rm,[Rn]
其中,B 为可选后缀,若有B,则交换字节,否则交换32 位字:Rd 为数据从存储器加载到的寄存器;Rm 的数据用于存储到存储器中,若Rm 与Rn 相同,则为寄存器与存储器内容进行交换;Rn 为要进行数据交换的存储器地址,Rn 不能与Rd 和Rm 相同。
SWP 指令举例如下:
SWP R1,R1,[R0] ; 将R1 的内容与R0 指向的存储单元的内容进行交换
SWP R1,R2,,[R0] ; 将R0 指向的存储单元内容读取一字节数据到R1 中(高24 位清零)
; 并将R2 的内容写入到该内存单元中(最低字节有效)
使用SWP 指令可以方便地进行信号量的操作:
12C_SEM EQU 0x40003000
…
12C_SEM_WAIT
MOV R0,#0
LDR R0,=12C_SEM
SWP R1,R1,[R0] ;取出信号量,并设置其为0
CMP R1,#0 ;判断是否有信号
BEQ 12C_SEM_WAIT ;若没有信号,则等待
3 ARM 数据处理指令
数据处理指令大致可分为3 类;数据传送指令(如MOV、MVN),算术逻辑运算指令(如ADD,SUM,AND),比较指令(如CMP、TST)。数据处理指令只能对寄存器的内容进行操作。
所有ARM 数据处理指令均可选择使用S 后缀,以影响状态标志。比较指令CMP、CMN、TST和TEQ不需要后缀S,它们会直接影响状态标志。ARM 数据处理指令列于表A-4中。
表A-4 ARM 数据处理指令
[url=http://www.mculy.com/batch.download.php?aid=8714]
(1)数据传送指令
MOV
数据传送指令。将8 位图立即数或寄存器(operant2)传送到目标寄存器Rd,可用于移位运算等操作。指令格式如下:
MOV{cond}{S} Rd,operand2
MOV 指令举例如下:
MOV R1#0x10 ;R1=0x10
MOV R0,R1 ;R0=R1
MOVS R3,R1,LSL #2 ;R3=R1<<2,并影响标志位
MOV PC,LR ;PC=LR ,子程序返回
MVN
数据非传送指令。将8 位图立即数或寄存器(operand2)按位取反后传送到目标寄存器(Rd),因为其具有取反功能,所以可以装载范围更广的立即数。指令格式如下:
MVN{cond}{S} Rd,operand2
MVN 指令举例如下:
MVN R1,#0xFF ;R1=0xFFFFFF00
MVN R1,R2 ;将R2 取反,结果存到R1
(2)算术逻辑运算指令
ADD
加法运算指令。将operand2 数据与Rn 的值相加,结果保存到Rd 寄存器。指令格式如下:
ADD{cond}{S} Rd,Rn,operand2
ADD 指令举例如下:
ADDS R1,R1,#1 ;R1=R1+1
ADD R1,R1,R2 ;R1=R1+R2
ADDS R3,R1,R2,LSL #2 ;R3=R1+R2<<2
SUB
减法运算指令。用寄存器Rn 减去operand2。结果保存到Rd 中。指令格式如下:
SUB{cond}{S} Rd,Rn,operand2
SUB 指令举例如下:
SUBS R0,R0,#1 ;R0=R0-1
SUBS R2,R1,R2 ;R2=R1-R2
SUB R6,R7,#0x10 ;R6=R7-0x10
RSB
逆向减法指令。用寄存器operand2 减法Rn,结果保存到Rd 中。指令格式如下:
RSB{cond}{S} Rd,Rn,operand2
SUB 指令举例如下:
RSB R3,R1,#0xFF00 ;R3=0xFF00-R1
RSBS R1,R2,R2,LSL #2 ;R1=R2<<2-R2=R2×3
RSB R0,R1,#0 ;R0=-R1
ADC
带进位加法指令。将operand2 的数据与Rn 的值相加,再加上CPSR 中的C 条件标志位。结果保存到Rd 寄存器。指令格式如下:
ADC{cond}{S} Rd,Rn,operand2
ADC 指令举例如下:
ADDS R0,R0,R2
ADC R1,R1,R3 ;使用ADC 实现64 位加法,(R1、R0)=(R1、R0)+(R3、R2)
SBC
带进位减法指令。用寄存器Rn 减去operand2,再减去CPSR 中的C 条件标志位的非(即若C 标志清零,则结果减去1),结果保存到Rd 中。指令格式如下:
SCB{cond}{S}Rd,Rn,operand2
SBC 指令举例如下:
SUBS R0,R0,R2
SBC R1,R1,R3 ;使用SBC 实现64 位减法,(R1,R0)-(R3,R2)
RSC
带进位逆向减法指令。用寄存器operand2 减去Rn,再减去CPSR 中的C 条件标志位,结果保存到Rd 中。指令格式如下:
RSC{cond}{S} Rd,Rn,operand2
RSC 指令举例如下:
RSBS R2,R0,#0
RSC R3,R1,#0 ;使用RSC 指令实现求64 位数值的负数
AND
逻辑与操作指令。将operand2 值与寄存器Rn 的值按位作逻辑与操作,结果保存到Rd 中。指令格式如下:
AND{cond}{S} Rd,Rn,operand2
AND 指令举例如下:
ANDS R0,R0,#x01 ;R0=R0&0x01,取出最低位数据
AND R2,R1,R3 ;R2=R1&R3
ORR
逻辑或操作指令。将operand2 的值与寄存器Rn 的值按位作逻辑或操作,结果保存到Rd 中。指令格式如下:
ORR{cond}{S} Rd,Rn,operand2
ORR 指令举例如下:
ORR R0,R0,#x0F ;将R0 的低4 位置1
MOV R1,R2,LSR #4
ORR R3,R1,R3,LSL #8 ;使用ORR 指令将近R2 的高8 位数据移入到R3 低8 位中
EOR
逻辑异或操作指令。将operand2 的值与寄存器Rn 的值按位作逻辑异或操作,结果保存到Rd 中。指令格式如下:
EOR{cond}{S}Rd,Rn,operand2
EOR 指令举例如下:
EOR R1,R1,#0x0F ;将R1 的低4 位取反
EOR R2,R1,R0 ;R2=R1^R0
EORS R0,R5,#0x01 ;将R5 和0x01 进行逻辑异或,结果保存到R0,并影响标志位
BIC
位清除指令。将寄存器Rn 的值与operand2 的值的反码按位作逻辑与操作,结果保存到Rd 中。指令格式如下:
BIC{cond}{S}Rd,Rn,operand2
BIC 指令举例如下:
BIC R1,R1,#0x0F ;将R1 的低4 位清零,其它位不变
BIC R1,R2,R3 ;将拭的反码和R2 相逻辑与,结果保存到R1
(3)比较指令
CMP
比较指令。指令使用寄存器Rn 的值减去operand2 的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。指令格式如下:
CMP{cond} Rn,operand2
CMP 指令举例如下:
CMP R1,#10 ;R1 与10 比较,设置相关标志位
CMP R1,R2 ;R1 与R2 比较,设置相关标志位
CMP 指令与SUBS 指令的区别在于CMP 指令不保存运算结果。在进行两个数据大小判断时,常用CMP 指令及相应的条件码来操作。
CMN
负数比较指令。指令使用寄存器Rn 与值加上operand2 的值,根据操作的结果更新CPSR 中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行,指令格式如下:
CMN{cond} Rn,operand2
CMN R0,#1 ;R0+1,判断R0 是否为1 的补码,若是Z 置位
CMN 指令与ADDS 指令的区别在于CMN 指令不保存运算结果。CMN 指令可用于负数比较,比如CMNR0,#1 指令则表示R0 与-1 比较,若R0 为-(即1 的补码),则Z 置位,否则Z复位。
TST
位测试指令。指令将寄存器Rn 的值与operand2 的值按位作逻辑与操作,根据操作的结果更新CPSR 中相应的条件标志位,以便后面指令根据相应的条件标志来判断是否执行。指令格式如下:
TST{cond} Rn,operand2
TST 指令举例如下:
TST R0,#0x01 ;判断R0 的最低位是否为0
TST R1,#0x0F ;判断R1 的低4 位是否为0
TST 指令与ANDS 指令的区别在于TST4 指令不保存运算结果。TST 指令通常于EQ、NE条件码配合使用,当所有测试位均为0 时,EQ 有效,而只要有一个测试为不为0,则NE 有效。
TEQ
相等测试指令。指令寄存器Rn 的值与operand2 的值按位作逻辑异或操作,根据操作的结果更新CPSR 中相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。指令格式如下:
TEQ{cond} Rn,operand2
TEQ 指令举例如下:
TEQ R0,R1 ;比较R0 与R1 是否相等(不影响V 位和C 位)
TST 指令与EORS 指令的区别在于TST 指令不保存运算结果。使用TEQ 进行相等测试,常与EQNE 条件码配合使用,当两个数据相等时,EQ 有效,否则NE 有效。
(4)乘法指令
ARM7TDMI(-S)具有32×32 乘法指令、32×32 乘加指令、32×32 结果为64 位的乘法指令。表A-5给出全部的ARM 乘法指令。
表A-5 全部的ARM 乘法指令
[url=http://www.mculy.com/batch.download.php?aid=8715][/url]
MUL
32 位乘法指令。指令将Rm 和Rs 中的值相乘,结果的低32 位保存到Rd 中。指令格式如下:
MUL{cond}{S} Rd,Rm,Rs
MUL 指令举例如下:
MUL R1,R2,R3 ;R1=R2×R3
MULS R0,R3,R7 ;R0=R3×R7,同时设置CPSR 中的N 位和Z 位
MLA
32 位乘加指令。指令将Rm 和Rs 中的值相乘,再将乘积加上第3 个操作数,结果的低32 位保存到Rd 中。指令格式如下:
MLA{cond}{S} Rd,Rm,Rs,Rn
MLA 指令举例如下:
MLA R1,R2,R3,R0 ;R1=R2×R3+10
UMULL
64 位无符号乘法指令。指令将Rm 和Rs 中的值作无符号数相乘,结果的低32 位保存到RsLo 中,而高32 位保存到RdHi 中。指令格式如下:
UMULL{cond}{S} RdLo,RdHi,Rm,Rs
UMULL 指令举例如下:
UMULL R0,R1,R5,R8 ;(R1、R0)=R5×R8
UMLAL
64 位无符号乘加指令。指令将Rm 和Rs 中的值作无符号数相乘,64 位乘积与RdHi、RdLo 相加,结果的低32 位保存到RdLo 中,而高32 位保存到RdHi 中。指令格式如下:
UMLAL{cond}{S} RdLo,RdHi,Rm,Rs
UMLAL 指令举例如下:
UMLAL R0,R1,R5,R8 ;(R1,R0)=R5×R8+(R1,R0)
SMULL
64 位有符号乘法指令。指令将Rm 和Rs 中的值作有符号数相乘,结果的低32 位保存到RdLo 中,而高32 位保存到RdHi 中。指令格式如下:
SMULL{cond}{S} RdLo,RdHi,Rm,Rs
SMULL 指令举例如下:
SMULL R2,R3,R7,R6 ;(R3,R2)=R7×R6
SMLAL
64 位有符号乘加指令。指令将Rm 和Rs 中的值作有符号数相乘,64 位乘积与RdHi、RdLo,相加,结果的低32 位保存到RdLo 中,而高32 位保存到RdHi 中。指令格式如下:
SMLAL{cond}{S} RdLo,RdHi,Rm,Rs
SMLAL 指令举例如下:
SMLAL R2,R3,R7,R6 ;(R3,R2)=R7×R6+(R3,R2)
0
|
|
|
|