版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
嵌入式系统原理与开发第二章嵌入式处理器(下)
第二章嵌入式处理器2.1引言
2.2 嵌入式处理器概述2.3 ARM处理器基础2.5 ARM程序设计基础2.4 ARM指令系统2.4 ARM指令系统2.4.1ARM编程模型2.4.2ARM寻址方式2.4.3ARM指令集2.4.4Thumb指令集2.4.1ARM编程模型2.4ARM指令系统
流水线数据类型处理器模式处理器工作状态寄存器组织异常存储器和存储器映射I/O1.流水线
2.4.1ARM编程模型
流水线技术是现代微处理器普遍采用的一种技术,它可以使得几条指令并行执行,因此可以大大提高处理器的运行效率。
1.流水线
2.4.1ARM编程模型从程序存储器中读取指令,放入流水线中操作码和操作数被译码,决定执行什么功能,为下一个时钟周期准备数据路径所需要的控制信号执行已译码的指令取指译码执行ARM7的3级流水线:1.流水线流水线能够正常工作的条件是在任意时刻,每一级所使用的硬件必须能够独立操作,不能多级同时占用同一硬件资源。在正常情况下,每条指令都被划分成这样3个时钟周期来完成,即指令执行时间(Latency)是3周期。流水线的执行使得程序计数器PC必须在当前指令取指前计数。对于ARM处理器的3级流水线,以当前PC取指后,PC值会增加为PC+4。2.4.1ARM编程模型1.流水线图2-5ARM单周期指令的多级流水线操作2.4.1ARM编程模型1.流水线图2-6ARM多周期指令的多级流水线操作2.4.1ARM编程模型1.流水线图2-7ARM分支指令的流水线操作2.4.1ARM编程模型2.数据类型
ARM处理器支持以下数据类型:2.4.1ARM编程模型
Byte
字节,8位;
Halfword
半字,16位(半字必须与 2字节边界对准);
Word
字,32位(字必须与4字 节边界对准)。2.数据类型
2.4.1ARM编程模型图2-8ARM数据类型存储图3.处理器模式
ARM体系结构支持7种处理器模式
:2.4.1ARM编程模型处理器模式说明用户usr程序正常执行模式FIQfiq支持高速数据传输或通道处理IRQirq通用中断处理管理svc操作系统保护模式中止abt虚拟存储器或存储器保护未定义und支持硬件协处理器的软件仿真系统sys运行特权操作系统任务4.处理器工作状态
ARM处理器具有特殊的两种工作状态:2.4.1ARM编程模型
ARM状态:32位,执行字对准的ARM指令;
Thumb状态:16位,执行半字对准的Thumb指令。
ARM处理器的操作状态可以通过BX指令(分支和交换指令)在ARM状态和Thumb状态之间切换。例:从ARM状态切换到Thumb状态:
LDRR0,=Label+1BXR0从Thumb状态切换到ARM状态:
LDRR0,=LabelBXR05.寄存器组织
ARM处理器共有37个寄存器:2.4.1ARM编程模型
31个通用寄存器:32位,含程序计数器PC;
6个状态寄存器:32位,只使用了其中的12位。当编写用户程序时,37个寄存器中仅有15个通用寄存器r0~r14、程序计数器PC(r15)和当前程序状态寄存器CPSR需要考虑。其余寄存器仅用于系统级编程和异常处理(如中断)。ARM状态下寄存器组织5.寄存器组织--不分组寄存器r0~r7
不分组意味着在所有处理器模式下,r0~r7都可被同样访问,没有体系结构所隐含的特殊用途。
2.4.1ARM编程模型5.寄存器组织--分组寄存器r8~r14
分组意味着r8~r14的访问与当前处理器的模式相关。如果要访问r8~r14,而不依赖于当前处理器的模式,就必须使用规定的寄存器名称。名称的形式为:2.4.1ARM编程模型r8_<mode>~r14_<mode>5.寄存器组织--分组寄存器r8~r14
r8~r12各有两组物理寄存器:一组为FIQ模式,另一组为FIQ以外的模式。寄存器r8~r12没有指定特殊用途,而使用r8_fiq~r12_fiq则允许快速中断。2.4.1ARM编程模型5.寄存器组织--分组寄存器r8~r14
寄存器r13和r14的用途比较特殊:
2.4.1ARM编程模型
r13通常用作堆栈指针SP,被初始化成指向异常模式分配的堆栈。
r14通常用作子程序链接寄存器LR。处理异常时,在程序入口处将异常处理程序用到的其它寄存器的值压入堆栈,返回时重新将这些值加载到寄存器中。当执行分支指令BL时,r15的内容拷贝到r14中,从而成为子程序调用后的返回地址5.寄存器组织--程序计数器r15
寄存器r15通常被用作程序计数器PC。在ARM状态下,PC的值保存在位[31:2],而位[1:0]为0;在Thumb状态下,PC的值保存在位[31:1],而位[0]为0。2.4.1ARM编程模型5.寄存器组织--当前程序状态寄存器CPSR
CPSR和SPSR具有相同的格式2.4.1ARM编程模型标志位含义N当用两个补码表示的带符号数进行运算时,N=1表示运算的结果为负数;N=0表示运算的结果为正数或零;ZZ=1表示运算的结果为零;Z=0表示运算的结果为非零;C可以有4种方法设置C的值:─加法运算(包括比较指令CMN):当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。─减法运算(包括比较指令CMP):当运算时产生了借位(无符号数溢出),C=0,否则C=1。─对于包含移位操作的非加/减运算指令,C为移出值的最后一位。─对于其他的非加/减运算指令,C的值通常不改变。V可以有2种方法设置V的值:─对于加/减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出。─对于其他的非加/减运算指令,V的值通常不改变。Q在ARMv5及以上版本的E系列处理器中,用Q标志位指示增强的DSP运算指令是否发生了溢出。在其他版本的处理器中,Q标志位无定义。5.寄存器组织--Thumb状态的寄存器集
2.4.1ARM编程模型Thumb状态下寄存器组织5.寄存器组织--Thumb状态的寄存器集
2.4.1ARM编程模型Thumb状态寄存器到ARM寄存器的映射6.异常
异常(exception)是指由内部或外部源产生从而使处理器需要处理的一个事件。2.4.1ARM编程模型例如,外部中断或试图实行未定义的指令都会引起异常的发生。处理异常之前,处理器必须保存当前的状态,以便在异常处理完成后,能够使原来的出现重新执行。6.异常
ARM支持7种类型的异常。对于每种异常,处理器将强制从异常对应的某个固定地址开始执行程序。这些固定地址称为异常向量。2.4.1ARM编程模型多个异常可能会同时发生,因此在ARM中就通过给各个异常赋予不同的优先级来确定处理异常的顺序。6.异常
优先级按照从高到低的顺序排列如下:2.4.1ARM编程模型复位数据异常中止FIQIRQ预取指异常中止SWI、未定义指令(这两种异常的指令编码互斥,不可能同时发生)异常类型具体含义复位当处理器的复位电平有效时产生复位异常,程序跳转到复位异常处理程序处执行。未定义指令当ARM处理器或协处理器遇到不能处理的指令时,产生未定义指令异常。可使用该异常机制进行软件仿真。软件中断该异常由执行SWI指令产生,可用于用户模式下的程序调用特权操作指令。可使用该异常机制实现系统功能调用。指令预取中止若处理器预取指令的地址不存在,或该地址不允许当前指令访问,存储器会向处理器发出中止信号,但当预取的指令被执行时,才会产生指令预取中止异常。数据中止若处理器数据访问指令的地址不存在,或该地址不允许当前指令访问时,产生数据中止异常。IRQ(外部中断请求)当处理器的外部中断请求引脚有效,且CPSR中的I位为0时,产生IRQ异常。系统的外设可通过该异常请求中断服务。FIQ(快速中断请求)当处理器的快速中断请求引脚有效且CPSR中的F位为0时,产生FIQ异常。6.异常
进入异常的操作:2.4.1ARM编程模型在相应的链接寄存器LR(r14)中保存下一条指令的地址将CPSR复制到相应的SPSR中强制使CPSR模式位置成对应异常类型的值强制使程序计数器指向相应异常向量,取下一条指令例子:用户模式到
FIQ模式*spsr_fiqcpsrr7r4r5r2r1r0r3r6r15(pc)r14_fiqr13_fiqr12_fiqr10_fiqr11_fiqr9_fiqr8_fiqr14(lr)r13(sp)r12r10r11r9r8用户模式CPSR复制到
FIQ模式
SPSRcpsrr15(pc)r14(lr)r13(sp)r12r10r11r9r8r7r4r5r2r1r0r3r6r14_fiqr13_fiqr12_fiqr10_fiqr11_fiqr9_fiqr8_fiq返回一个从用户模式计算的地址,PC值存储在FIQ模式RegistersinuseRegistersinuse异常用户模式FIQ模式spsr_fiq7.存储器和存储器映射I/O
与单片机等简单系统相比,现在一些复杂的嵌入式系统中,存储系统的功能更加强大,可能包含有多种现代计算机存储技术,如Cache和WriteBuffer、MMU、存储保护机制、快速上下文切换等。基于ARM内核的嵌入式系统可能包含Flash、ROM、SRAM、SDRAM等多种类型的存储器,不同类型的存储器存取速度和数据宽度等都不尽相同。2.4.1ARM编程模型7.存储器和存储器映射I/O
存储系统的设计可以是多种多样的,但是应当遵循一定的规则,否则可能会引起一些不必要的麻烦。2.4.1ARM编程模型例如:可能使存储系统的实现比较困难;可能导致向其它ARM处理器的移植出现麻烦;可能引起一些标准软件(如编译器)的不适应。基于系统设计和编程的考虑,关于ARM存储系统一般只需涉及地址空间、存储器格式、存储器访问对准以及存储器映射I/O等方面的问题。7.存储器和存储器映射I/O--地址空间
ARM体系结构使用232个8位字节的单一、线性地址空间,字节地址的范围为0~232-1;也可以将地址空间看作由230个32位的字组成,字地址可被4整除,且按字对准,例如以A为字对准地址的字地址由A、A+1、A+2、A+3共4个字节组成;在ARM体系结构v4以上版本中,也可以将地址空间看作由231个16位的半字组成,半字地址可被2整除,且按半字对准,例如以A为字对准地址的半字地址由A、A+1共2个字节组成。2.4.1ARM编程模型7.存储器和存储器映射I/O--存储器格式
存储器格式是指字、半字、字节在存储器中存放的方式,也反映了存储器中字、半字、字节之间的映射关系。存储器格式包括小端和大端两种格式。2.4.1ARM编程模型7.存储器和存储器映射I/O--存储器格式
2.4.1ARM编程模型大、小端存储格式对程序的影响7.存储器和存储器映射I/O--存储器访问对准对于非对准的取指,在ARM工作状态下,未对准的地址写入R15后,结果将不可预知或忽略地址位[1:0];在Thumb状态下,未对准的地址写入R15后,则通常忽略地址位[0]。对于非对准的数据访问,则体系结构可能定义成以下行为之一:2.4.1ARM编程模型不可预知;忽略使访问非对准的低地址位;忽略使访问非对准的低地址位,但使用这些位控制加载数据的循环移位(适用于LDR和SWP指令)。7.存储器和存储器映射I/O--存储器映射I/O
ARM系统实现I/O功能的标准方法是使用存储器映射I/O。这种方法使用特定的存储器地址,对这些地址加载和存储,即可完成I/O操作。通常,对存储器映射I/O地址加载对应输入,对对存储器映射I/O地址存储对应输出。另外,加载和存储也可执行控制功能,替代或附加到正常的I/O操作上。2.4.1ARM编程模型2.4 ARM指令系统
2.4.1ARM编程模型2.4.2ARM寻址方式2.4.3ARM指令集2.4.4Thumb指令集
寻址方式是指根据指令给出的地址码寻找真实操作数地址的方式。 寻址方式的多样化一方面出于编程的需要,另一方面可以增强程序设计的灵活性。2.4.2ARM寻址方式2.4ARM指令系统
2.4.2ARM寻址方式2.4ARM指令系统
寄存器寻址立即寻址寄存器移位寻址寄存器间接寻址基址寻址多寄存器寻址堆栈寻址块拷贝寻址相对寻址1.寄存器寻址
指令地址码给出寄存器的编号,寄存器中的内容为操作数。2.4.2ARM寻址方式例如:ADD R0,R1,R2 ;R0←R1+R2写操作数的顺序为:第一个寄存器R0为结果寄存器,第二个寄存器R1为第一操作数寄存器,第三个寄存器R2为第二操作数寄存器。注意2.立即寻址指令操作码后的地址码是立即数,即操作数本身。2.4.2ARM寻址方式例如:ADD R3,R3,#1 ;R3←R3+1AND R8,R7,#&FF ;R8←R7[7:0]立即数的表示以“#”为前缀,十六进制的立即数在“#”后面加“&”符号。
注意3.寄存器移位寻址
寄存器移位寻址是ARM指令集特有的寻址方式。第2个操作数与第1个操作数结合之前,选择进行移位操作。2.4.2ARM寻址方式例如:ADDR3,R2,R1,LSL#3 ;R3←R2+8×R13.寄存器移位寻址
可采取的移位操作包括:2.4.2ARM寻址方式
LSL:逻辑左移(LogicalShiftLeft)。寄存器中字的低端空出的位补0。
LSR:逻辑右移(LogicalShiftRight)。寄存器中字的高端空出的位补0。
ASR:算术右移(ArithmeticShiftRight)。算术移位的对象是带符号数。在移位过程中必须保持操作数的符号不变。若源操作数为正数,则字的高端空出的位补0;若源操作数为负数,则字的高端空出的位补1。
ROR:循环右移(ROtateRight)。从字的最低端移出的位填入字的高端空出的位。
RRX:扩展为1的循环右移(RotateRighteXtendedby1place)。操作数右移1位,空位(位[31])用原C标志填充。3.寄存器移位寻址
2.4.2ARM寻址方式移位操作过程4.寄存器间接寻址
指令地址码给出寄存器的编号,寄存器为地址指针,存放操作数的有效地址。2.4.2ARM寻址方式例如: LDR R0,[R1] ;R0←[R1] STR R0,[R1] ;R0→[R1]5.基址寻址
基址寻址是将基址寄存器的内容与指令中给出的位移量相加,形成操作数有效地址。基址寻址用于访问基址附近的存储单元。包括基址加偏移量寻址和基址加索引寻址,可以将寄存器间接寻址看作是位移量为0的基址加偏移量寻址。2.4.2ARM寻址方式5.基址寻址--基址加偏移量寻址
基址加偏移量寻址中的偏移量最大为4KB,可分为前索引寻址和后索引寻址。2.4.2ARM寻址方式前索引寻址举例: LDR R0,[R1,#4] ;R0←[R1+4]5.基址寻址--基址加偏移量寻址2.4.2ARM寻址方式例: LDR R0,[R1,#4]! ;R0←[R1] ;R1←R1+4后索引寻址举例: LDR R0,[R1],#4 ;R0←[R1] ;R1←R1+4这种改变基址寄存器指向下一个传送的地址对数据块传送很有用,还可以采用带自动索引的前索引寻址实现。注意5.基址寻址--基址加索引寻址基址加索引寻址是指令指定一个基址寄存器,再指定另一个寄存器(称为索引),其值作为位移加到基址上形成存储器地址。
2.4.2ARM寻址方式例: LDR R0,[R1,R2] ;R0←[R1+R2]6.多寄存器寻址
多寄存器寻址是指一次可以传动多个寄存器的值,允许一条指令可以传送16个寄存器的任何子集,包括16个寄存器。2.4.2ARM寻址方式例:LDMIA R1,{R0,R2,R5} ;R0←[R1] ;R2←[R1+4] ;R5←[R1+8]由于传送的数据总是32位的字,因此基址寄存器R1应当字对准。注意7.堆栈寻址
堆栈是一种按照特定顺序进行存取的存储区。这种特定的顺序是指“后进先出”(LIFO)或“先进后出”(FILO)。使用堆栈时需要使用一个专门的寄存器作为堆栈指针,栈指针所指定的存储单元就是堆栈的栈顶。如果堆栈指针指向最后压入堆栈的有效数据项,就称为满堆栈(fullstack);如果堆栈指针指向下一个数据项放入的空位置,就称为空堆栈(emptystack)。2.4.2ARM寻址方式7.堆栈寻址
另外,根据堆栈存储区地址增长的方向,可将堆栈分为递增堆栈(ascendingstack)和递减堆栈(descendingstack)。以上表示递增、递减、满、空的堆栈的各种组合就产生了4种堆栈类型。
ARM支持所有这4种类型的堆栈,即满递增、空递增、满递减、空递减。
ARM指令使用push向堆栈写数据,称为进栈;使用pop从堆栈读数据,称为出栈。2.4.2ARM寻址方式堆栈指针指向最后压入的数据且由低地址向高地址生成堆栈指针指向最后压入的数据且由高地址向低地址生成堆栈指针指向下一个将要放入数据的空位置且由低地址向高地址生成堆栈指针指向下一个将要放入数据的空位置且由高地址向低地址生成8.块拷贝寻址
从堆栈的角度来看,多寄存器传送指令是把一块数据从存储器的某一个位置拷贝到另一位置。从块拷贝的角度来看,指令还要基于数据存储在基址寄存器地址之上还是之下,地址在存储第一个值之前或之后增加或减少。这两种角度的映射均取决于执行加载操作还是存储操作。2.4.2ARM寻址方式8.块拷贝寻址
2.4.2ARM寻址方式向上生长向下生长满空满空增加之前STMIBSTMFALDMIBLDMED之后STMIASTMEALDMIALDMFD减少之前LDMDBLDMEASTMDBSTMFD之后LDMDALDMFASTMDASTMED表2-4多寄存器加载和存储指令映射8.块拷贝寻址
2.4.2ARM寻址方式例如:LDMIA R0!,{R2-R9} ;将数据加载到R2~R9STMIA R1,{R2-R9} ;将数据存入存储器执行指令后,由于引用自动索引“!”,R0的值共增加32,而R1不变。注意8.块拷贝寻址
2.4.2ARM寻址方式多寄存器指令的后缀含义如下:
I:Increment
D:DecrementorDescendingstack
A:AfterorAscendingstack
B:Before
F:Full
E:Empty 例如“FD”即表明是满递减堆栈寻址方式(fulldescendingstack)。9.相对寻址
可以将相对寻址看作是以程序计数器PC为基址的一种基址寻址方式。指令的地址码作为位移量,与PC相加得到操作数的有效地址。位移量指出了操作数与当前指令之间的相对位置。2.4.2ARM寻址方式例: BL SUBR ;转移到SUBR … ;返回到此SUBR … ;子程序入口地址 MOVPC,R14 ;返回2.4 ARM指令系统
2.4.1ARM编程模型
2.4.2ARM寻址方式2.4.3ARM指令集2.4.4Thumb指令集2.4ARM指令系统
ARM指令集编码条件执行ARM指令格式ARM存储器访问指令ARM数据处理指令ARM分支指令ARM协处理器指令ARM杂项指令ARM伪指令2.4.3ARM指令集1.ARM指令集编码
ARM指令集采用32位二进制编码方式,大部分指令编码中定义了第一操作数、第二操作数、目的操作数、条件标志影响位以及每条指令所对应的不同功能实现的二进制位。每条ARM指令都具有不同的编码方式,与不同的指令功能相对应。2.4.3ARM指令集1.ARM指令集编码
2.4.3ARM指令集ARM指令集编码2.条件执行
条件执行是指只有在当前程序状态寄存器CPSR中的条件码标志满足指定的条件时,带条件码的指令才能执行。条件转移是绝大多数指令集的标准特征,但ARM指令集将条件执行扩展到所有指令,包括监控调用和协处理器指令。
2.4.3ARM指令集2.条件执行2.4.3ARM指令集图2-17ARM的条件代码域操作码[31:28]助记符后缀标志含义0000EQZ置位相等0001NEZ清零不等0010CS/HSC置位大于或等于(无符号>=)0011CC/LOC清零小于(无符号<)0100MIN置位负0101PLN清零正或零0110VSV置位溢出0111VCV清零未溢出1000HIC置位且Z清零大于(无符号>)1001LSC清零或Z置位小于或等于(无符号<=)1010GEN和V相同带符号>=1011LTN和V不同带符号<1100GTZ清零且N和V相同带符号>1101LEZ置位或N和V不同带符号<=1110AL任何总是(缺省)1111NV无从不(不要使用)2.条件执行2.4.3ARM指令集对于条件执行,需要说明的有以下两点:注意几乎所有的ARM数据处理指令都可以根据执行结果来选择是否更新条件码标志。当指令中包含后缀“S”时,指令将更新条件码标志。可以根据另一条指令设置的标志,有条件地执行某条指令。3.ARM指令格式
ARM指令集是Load/Store型,只能通过Load/Store指令实现对存储器的访问,其它类型的指令都基于寄存器完成。2.4.3ARM指令集操作码;指令助记符,如ADD、LDR等可选的条件码;执行条件,如EQ、NE等可选后缀;若指定S,则根据指令执行结果更新CPSR中的条件码目标寄存器存放第一操作数的寄存器第二操作数例: LDR R0,[R1] BEQ DATAEVEN ADDS R2,R1,#1 SUBNES R2,R1,#0x20
ARM指令使用的基本格式如下所示:<opcode>{<cond>}{S} <Rd>,<Rn>,{<operand2>}3.ARM指令格式
2.4.3ARM指令集4.ARM存储器访问指令--LDR、STR
LDR和STR为单一数据传送指令,可传送字和无符号字节、半字和带符号字节、双字。
2.4.3ARM指令集(1)字和无符号字节
op{cond}{B}{T}Rd,[Rn] ;零偏移
op{cond}{B}Rd,[Rn,Flexoffset]{!} ;前索引偏移
op{cond}{B}Rd,label ;程序相对偏移
op{cond}{B}{T}Rd,[Rn],Flexoffset ;后索引偏移4.ARM存储器访问指令--LDR、STR
2.4.3ARM指令集句法:(1)字和无符号字节
指令用于加载或存储寄存器32位字或8位无符号字节。对于零偏移形式,Rn的值作为传送数据的地址。对于前索引偏移形式,在传送数据之前,将偏移量加到Rn中,结果作为传送数据的存储器地址。若使用“!”,则结果写回到Rn,且Rn不允许是R15。对于程序相对偏移形式,汇编器由PC计算偏移量,并将PC作为Rn生成前索引指令。不能使用后缀“!”。对于后索引形式,Rn的值作为传送数据的存储器地址。数据传送之后,将偏移量加到Rn中,结果写回到Rn。Rn不允许是R15。4.ARM存储器访问指令--LDR、STR
2.4.3ARM指令集指令说明:(1)字和无符号字节
LDR R8,[R10] LDRNE R2,[R5,#960]! STR R2,[R9,#CON] STRB R0,[R3,-R8,ASR#2] 4.ARM存储器访问指令--LDR、STR
2.4.3ARM指令集例:(2)半字和带符号字节
op{cond}typeRd,[Rn] ;零偏移
op{cond}typeRd,[Rn,offset]{!} ;前索引偏移
op{cond}typeRd,label ;程序相对偏移
op{cond}typeRd,[Rn],offset ;后索引偏移4.ARM存储器访问指令--LDR、STR
2.4.3ARM指令集句法:(2)半字和带符号字节指令用于加载寄存器16位半字或带符号8位字节,存储寄存器16位半字。
带符号加载是指带符号扩展到32位。
无符号半字加载是指零扩展到32位。半字传送的地址必须是偶数,即按照半字对准。不能将半字或字节加载到R15。。4.ARM存储器访问指令--LDR、STR
2.4.3ARM指令集指令说明:(2)字和无符号字节
LDREQSH R11,[R6] LDRH R1,[R0,#12] STRH R4,[R0,R1]! LDRSB R1,[R6],R3,LSL#4 4.ARM存储器访问指令--LDR、STR
2.4.3ARM指令集例:(3)双字
op{cond}DRd,[Rn] ;零偏移
op{cond}DRd,[Rn,offset]{!} ;前索引偏移
op{cond}DRd,label ;程序相对偏移
op{cond}DRd,[Rn],offset ;后索引偏移4.ARM存储器访问指令--LDR、STR
2.4.3ARM指令集句法:(3)双字
指令用于加载或存储两个相邻寄存器64位双字。对于双字传送,地址必须是8的倍数。4.ARM存储器访问指令--LDR、STR
2.4.3ARM指令集指令说明:(3)双字
LDRD R6,[R11] LDRD R1,[R6] STRD R4,[R9,#24] STRD R14,[R9,#24] STRD R2,[R3],R6 4.ARM存储器访问指令--LDR、STR
2.4.3ARM指令集例:op{cond}modeRn{!},reglist{^}4.ARM存储器访问指令--LDM、STM
2.4.3ARM指令集句法:指令用于加载或存储多个寄存器,可传送R0~R15的任何组合。指令忽略地址的位[1:0]。到R15的加载将引起处理器转移到加载地址处的指令如果Rn包含在寄存器列表中,且用“!”表明要写回,则若op是STM,且Rn是寄存器列表中数字最小的寄存器,则Rn的初值被保存。否则,Rn的加载和存储值不可预知。4.ARM存储器访问指令--LDM、STM
2.4.3ARM指令集指令说明:LDMIA R8, {R0,R2,R9}STMDB R1!, {R3-R6,R11,R12}STMFD R13!, {R0,R4-R7,LR} LDMFD R13!, {R0,R4-R7,PC}STMIA R5!, {R5,R4,R9} LDMDA R2, {}4.ARM存储器访问指令--LDM、STM
2.4.3ARM指令集例:PLD [Rn{Flexoffset}]4.ARM存储器访问指令--PLD
2.4.3ARM指令集句法:指令用于Cache预加载,提示存储系统从后面的几条指令所指定的存储器地址加载,用这种方法可以加速以后的存储器访问。指令没有地址的对准限制。指令说明:4.ARM存储器访问指令--PLD2.4.3ARM指令集PLD [R2]PLD [R0,#CON] ;CON范围为±4KB例:4.ARM存储器访问指令--SWP
2.4.3ARM指令集SWP{cond}{B}Rd,Rm,[Rn]句法:指令用于在寄存器和存储器之间进行数据交换,可以使用SWP来实现信号量。对于非字对准的处理与LDR、STR指令中的处理方法相同。指令说明:例:SWPB R1,R1,[R0] ;交换字节5.ARM数据处理指令
ARM数据处理指令可以完成的功能包括:2.4.3ARM指令集数据传送算术运算逻辑运算比较测试乘法5.ARM数据处理指令
ARM数据处理指令的特点
2.4.3ARM指令集操作数为32位,来自寄存器或定义的立即数。对于操作数可进行符号扩展和零扩展。处理结果除了长乘法指令为64位之外,均为32位,存放在寄存器中。大多数ARM通用数据处理指令都有一个灵活的第二操作数(flexiblesecondoperand)。第二操作数operand2可以是立即数形式或寄存器形式。#32位立即数Rm,{#shift}5.ARM数据处理指令--移位操作2.4.3ARM指令集ASR: 算术右移。即将寄存器内容除以2n。LSR: 逻辑右移。即将寄存器内容除以2n。LSL: 逻辑左移。即将寄存器内容乘以2n。ROR: 循环右移。RRX: 带扩展的循环右移。将寄存器内容循环 右移1位,进位标志拷贝到位[31]。5.ARM数据处理指令--移位操作2.4.3ARM指令集图2-18移位操作过程ADD、SUB、RSB、ADC、SBC、RSCop{cond}{S}Rd,Rn,Operand25.ARM数据处理指令--算术运算指令
2.4.3ARM指令集句法:指令用于加、减、反减等算术运算,包括带进位的算术运算。算术运算中如果使用R15作为Rn,则其值为指令的地址加8。如果使用R15作为Rd,则执行转移到结果相应的地址;或者在使用“S”的情况下,拷贝SPSR到CPSR,利用这点可从异常返回。在有寄存器控制移位的任何数据处理指令中,不能将R15作为Rd或任何操作数来使用。5.ARM数据处理指令--算术运算指令2.4.3ARM指令集指令说明:ADD、SUB、RSB、ADC、SBC、RSCADD R2,R1,R3SUBS R8,R6,#240 RSB R4,R4,#1280 ADCHI R11,R0,R3 RSCLES R0,R5,R0,LSLR4 RSCLES R0,R15,R0,LSLR4 5.ARM数据处理指令--算术运算指令2.4.3ARM指令集例:ADD、SUB、RSB、ADC、SBC、RSCAND、ORR、EOR、BICop{cond}{S}Rd,Rn,Operand25.ARM数据处理指令—逻辑运算指令
2.4.3ARM指令集句法:指令用于与、或、异或、位清零等逻辑运算。
BIC指令用于将Rn中的位与Operand2值中的相应位的反码进行“与”操作。若指定S,则指令将根据结果更新标志N和Z;计算Operand2时更新标志C;不影响标志V。关于R15的使用与算术运算指令相同。5.ARM数据处理指令--逻辑运算指令2.4.3ARM指令集指令说明:AND、ORR、EOR、BICAND R9,R2,#0xFF00ORREQ R2,R0,R5 EORS R0,R0,R3,RORR6 BICNES R8,R10,R0,RRX EORS R0,R15,R3,RORR6 5.ARM数据处理指令--逻辑运算指令2.4.3ARM指令集
例:AND、ORR、EOR、BICMOV、MVNop{cond}{S}Rd,Operand25.ARM数据处理指令—数据传送指令
2.4.3ARM指令集句法:指令用于数据传送。
MOV指令将Operand2的值拷贝到Rd;
MVN指令对Operand2的值按位取非后,将结果拷贝到Rd。关于条件码标志的影响与逻辑运算指令相同。关于R15的使用与算术运算指令相同。
5.ARM数据处理指令--数据传送指令2.4.3ARM指令集指令说明:MOV、MVNMOV R5,R2MVNNE R11,#0x0F000000 MOVS R0,R0,ASRR3
5.ARM数据处理指令--数据传送指令2.4.3ARM指令集
例:MOV、MVNCMP、CMNop{cond}{S}Rd,Operand25.ARM数据处理指令--比较指令
2.4.3ARM指令集句法:指令用于比较操作,根据结果更新条件码标志,结果并不放入寄存器。其中,CMP指令从Rn的值中减去Operand2的值,结果丢弃;CMN指令将Operand2的值加到Rn的值中,结果丢弃。如果将R15用作Rn,则使用的值是指令的地址加8。在控制寄存器移位的操作中,不能使用R15。5.ARM数据处理指令--比较指令2.4.3ARM指令集指令说明:CMP、CMNCMP R2,R9CMN R0,#6400CMPGT R13,R7,LSL#2 CMP R2,R15,ASRR0
5.ARM数据处理指令--比较指令2.4.3ARM指令集
例:CMP、CMNTST、TEQop{cond}{S}Rd,Operand25.ARM数据处理指令--测试指令
2.4.3ARM指令集句法:指令用于测试操作,根据结果更新条件码标志,结果不放入寄存器。其中,TST指令对Rn的值与Operand2的值进行按位“与”操作,结果丢弃;TEQ指令对Rn的值与Operand2的值进行按位“异或”操作,结果丢弃。关于条件码标志的影响与算术运算指令相同。关于R15的使用与比较指令相同。5.ARM数据处理指令--测试指令2.4.3ARM指令集指令说明:TST、TEQTST R0,#0x3F8TEQEQ R10,R9 TSTNE R1,R5,ASRR1 TEQ R15,R1,RORR0 5.ARM数据处理指令--测试指令2.4.3ARM指令集
例:TST、TEQMUL、MLAMUL{cond}{S}Rd,Rm,RsMLA{cond}{S}Rd,Rm,Rs,Rn5.ARM数据处理指令—乘法指令
2.4.3ARM指令集句法:指令用于进行乘法和乘加32位×32位运算,结果为低32位。如果指定S,则指令根据结果更新标志N和Z;不影响标志V;在ARMv4之前版本中标志C不可靠;在ARMv5以后版本中不影响标志C。
R15不能用作Rd、Rm、Rs或Rn。Rd不能与Rm相同。5.ARM数据处理指令--乘法指令2.4.3ARM指令集指令说明:MUL、MLAMUL R10,R2,R5MLA R10,R2,R1,R5MULS R0,R2,R2 MULLT R2,R3,R2 MLAVCS R8,R6,R3,R8 MUL R15,R0,R3 MLA R1,R1,R6 5.ARM数据处理指令--乘法指令2.4.3ARM指令集
例:MUL、MLACLZ {cond}Rd,Rm5.ARM数据处理指令--CLZ
2.4.3ARM指令集句法:指令用于对Rm中值的前导零的个数进行计数,结果放入Rd中。若Rm内容为0,则结果为32;若Rm位[31]为1,则结果为0。指令不影响条件码标志。
Rd不允许是R15。指令说明:B {cond} labelBL {cond} label6.ARM分支指令--B、BL
2.4.3ARM指令集句法:指令用于分支和带链接分支的操作。其中,B指令引起处理器转移到label;BL指令将下一条指令的地址拷贝到R14(LR,链接寄存器),并引起处理器转移到label。指令说明:6.ARM分支指令--B、BL2.4.3ARM指令集B loopABL sub例:BX {cond} Rm6.ARM分支指令--BX
2.4.3ARM指令集句法:指令用于实现分支,并可选地交换指令集。BX指令将引起处理器转移到Rm中的地址。若Rm的位[0]为1,则指令集变换到Thumb指令集。指令说明:6.ARM分支指令--BX2.4.3ARM指令集BX R6例:BLX {cond} Rm6.ARM分支指令--BLX
2.4.3ARM指令集句法:6.ARM分支指令--BLX
2.4.3ARM指令集指令用于实现带链接分支,并可选地交换指令集。
BLX指令具体用途有:将下一条指令的地址拷贝到R14(LR,链接寄存器)中;转移到label或Rm中的地址;切换到Thumb指令集,条件是Rm的位[0]为1或者使用“BLXlabel”的形式。机器级的“BLXlabel”指令的转移不能超过当前指令地址的±32Mb范围。指令说明:6.ARM分支指令--BX2.4.3ARM指令集BLX R0BLX thumbsub例:7.ARM协处理器指令
2.4.3ARM指令集
ARM支持16个协处理器,如用于控制片上功能(如cache、MMU)的系统协处理器、浮点协处理器以及其它一些专用的协处理器。每个协处理器均忽略ARM处理器和其它协处理器的指令。如果协处理器没有接受ARM的协处理器指令,则ARM将产生未定义指令中止的陷阱,以此可用来实现“协处理器丢失”的软件仿真。SWI {cond}immed_248.ARM杂项指令--SWI2.4.3ARM指令集句法:
SWI指令引起处理器SWI异常,即处理器变为管理模式,CPSR内容保存到管理模式的SPSR中,执行转移到SWI向量。这条指令不影响条件码标志。指令说明:软件中断指令——SWIBKPT immed_168.ARM杂项指令--BKPT2.4.3ARM指令集句法:
BKPT指令引起处理器进入调试模式,调试工具可利用这条指令到达特定的地址时查询系统状态。指令说明:断点指令——BKPTMRS {cond}Rd,psrMSR {cond}psr_fields,#immed_8rMSR {cond}psr_fields,Rm8.ARM杂项指令--MRS、MSR
2.4.3ARM指令集句法:
PSR操作指令MRS和MSR配合使用,可用来更新PSR的读-修改-写序列的一部分,如改变处理器模式或清除标志Q。指令说明:PSR操作指令——MRS、MSR9.ARM伪指令--ADR、ADRL、LDR
2.4.3ARM指令集ADR {cond}register,exprADRL{cond}register,exprLDR {cond}register,=[expr|label-expr]句法:
ADR、ADRL和LDR伪指令都是将一个地址加载到一个寄存器中。
指令说明:start MOV R0,#10 ADR R4,start ;=>SUBR4,PC,#0x0Cstart MOV R0,#10 ADRL R4,start+6000;=>ADDR4,PC,#0xE800 ;ADDR4,R4,#0x254LDR R3,=OxFF0 ;加载0xFF0到R3中 ;=>MOV R3,#0xFF0LDR R1,=OxFFF ;加载0xFFF到R1中 ;=>LDR R1,[PC,offset_to_litpool] ;… ;litpoolDCD0xFFFLDR R2,=place ;将place的地址加载到R2中 ;=>LDR R2,[PC,offset_to_litpool] ;… ;litpoolDCDplace9.ARM伪指令--NOP
2.4.3ARM指令集NOP句法:
NOP伪指令在汇编时被替换成ARM的空操作,如“MOVR0,R0”等。
NOP伪指令不能有条件执行。
NOP伪指令不影响CPSR中的条件标志位。指令说明:空操作——NOP2.4 ARM指令系统
2.4.1ARM编程模型
2.4.2ARM寻址方式2.4.3ARM指令集2.4.4Thumb指令集(*)第二章嵌入式处理器2.1引言
2.2 嵌入式处理器概述2.3 ARM处理器基础2.4 ARM指令系统2.5 ARM程序设计基础2.5 ARM程序设计基础在嵌入式系统程序设计中,大量使用了C语言进行编程。在有些程序中,使用汇编语言进行编程则更加方便、简单,甚至是不可替代的,例如初始化硬件的代码、启动代码等。2.5 ARM程序设计基础汇编语言都具有一些相同的基本特征,例如:一条指令一行。使用标号(label)给内存单元提供名称,从第一列开始书写。指令必须从第二列或能区分标号的地方开始书写。注释跟在指定的注释字符后面(ARM使用的是“;”),一直书写到行尾。2.5 ARM程序设计基础
2.5.1ARM汇编语句格式
2.5.2ARM汇编程序格式
2.5.3汇编语言编程实例
2.5.4汇编语言与C语言的混合编程2.5ARM程序设计基础
2.5.1ARM汇编语句格式ARM汇编语句的格式如下所示:{symbol}{instruction|directive|pseudo-instruction}{;comment}2.5ARM程序设计基础
2.5.1ARM汇编语句格式
symbol:符号。在ARM汇编语言中,符号在指令和伪指令中用作地址标号,在一些伪操作中用作变量或常量。符号的使用有以下一些规则:符号必须从一行的行头开始符号由大小写字母、数字以及下划线组成,但不能包含空格符号区分大小写局部标号以数字开头,其它符号都不能以数字开头符号在作用范围内是唯一的,即在其作用范围内不能有同名的符号程序中的符号不能与系统的内部变量或系统预定义的符号同名程序中的符号通常不要与指令助记符或伪操作同名2.5ARM程序设计基础
2.5.1ARM汇编语句格式
instruction:指令。在ARM汇编语言中,指令不能从一行的行头开始。在一行语句中,指令的前面必须有空格或符号。
directive:伪操作。
pseudo-instruction:伪指令。
comment:语句的注释。在ARM汇编语言中,注释以分号“;”开头。注释的结尾即为一行的结尾。注释也可单独占用一行。2.5ARM程序设计基础
2.5.1ARM汇编语句格式关于ARM汇编语句,需要说明的有以下几点:指令、伪指令以及伪操作的助记符可全部使用大写字母,也可全部使用小写字母,但不能在一个助记符中既有大写字母又有小写字母;在程序中,语句之间最好适当地插入空行,这样可提高源代码的可读性;如果一条语句很长,为提高可读性,可使用“\”将其分成若干行进行书写。在“\”后面不能再有其它字符,包括空格和制表符。
2.5 ARM程序设计基础
2.5.1ARM汇编语句格式
2.5.2ARM汇编程序格式
2.5.3汇编语言编程实例
2.5.4汇编语言与C语言的混合编程2.5ARM程序设计基础
2.5.2ARM汇编程序格式采用不同的编译器,ARM汇编语言程序的格式可能会略有不同。总体上,ARM汇编程序的基本格式是相同的。ARM汇编程序以段(section)为单位来组织源文件。2.5ARM程序设计基础
2.5.2ARM汇编程序格式ARM汇编程序经过汇编处理后生成一个可执行的映像文件,映像文件通常包括以下3个部分:一个或多个代码段。代码段的属性通常是只读的。
0或多个包含初始值的数据段。数据段的属性通常是可读/写的。
0或多个不包含初始值的数据段。这些数据段被初始化为0,属性是可读/写的。ARM汇编程序的基本结构AREAEXAMPLE,CODE,READONLY ENTRY start MOV R0,#10 MOV R1,#3 ADD R0,R0,R1 ENDAREA表示了一个段的开始,同时定义了这个段的名称和相关属性标识了程序执行的第一条指令,即程序的入口点标识源文件的结束。每一个汇编模块必须包含一个END伪操作,用来指示模块的结束2.5 ARM程序设计基础
2.5.1ARM汇编语句格式
2.5.2ARM汇编程序格式
2.5.3汇编语言编程实例
2.5.4汇编语言与C语言的混合编程
AREAHelloWorld,CODE,READONLY ;声明代码段SWI_WriteCEQU &0 ;输出R0中的字符SWI_Exit
EQU &11 ;程序结束
ENTRY
;代码的入口START ADR R1,TEXT ;R1→“HelloWorld”LOOP LDRB R0,[R1],#1 ;读取下一个字节
CMP R0,#0 ;检查文本终点
SWINE SWI_WriteC ;若非终点,则打印
BNE LOOP ;并返回LOOP
SWI SWI_Exit ;执行结束TEXT = “HelloWorld”,&0a,&0d,0
END
;程序源代码结束
AREABlkCpy,CODE,READONLY ;声明代码段SWI_WriteC EQU &0 ;输出R0中的字符SWI_Exit EQU &11 ;程序结束
ENTRY ;代码的入口 ADR R1,TABLE1 ;R1→TABLE1 ADR R2,TABLE2 ;R2→TABLE2 ADR R3,T1END ;R3→T1ENDLOOP1 LDR R0,[R1],#4 ;读取TABLE1的第一个字 STR R0,[R2],#4 ;拷贝到TABLE2 CMP R1,R3 ;结束? BLT LOOP1 ;若非,则再拷贝 ADR R1,TABLE2 ;R1→TABLE2LOOP2 LDRB R0,[R1],#1 ;读取下一个字 CMP R0,#0 ;检查文本终点 SWINE SWI_WriteC ;若非终点,则打印 BNE LOOP2 ;并返回LOOP2 SWI SWI_Exit ;执行结束TABLE1 = “Thisistherightstring!”,&0a,&0d,0T1END
ALIGN ;保证字对准TABLE2 = “Thisisthewrongstring!”,0
END ;程序源代码结束2.5 ARM程序设计基础
2.5.1ARM汇编语句格式
2.5.2ARM汇编程序格式
2.5.3汇编语言编程实例
2.5.4汇编语言与C语言的混合编程2.5ARM程序设计基础
2.5.4汇编语言与C语言的混合编程高级语言使程序能够以抽象的方式来表述。编译器是支持高级语言、可以达到抽象目的的依赖。灵活地运用汇编语言和C语言之间的关系进行混合编程,有利于系统和相关模块的开发。2.5ARM程序设计基础
2.5.4汇编语言与C语言的混合编程汇编语言和C语言的混合编程分为两种情况:如果汇编代码比较简单,则可以直接利用内嵌汇编的方式进行混合编程;如果汇编代码比较复杂,则可以将汇编程序和C程序分别以文件的形式加到一个工程里,通过ATPCS标准来完成汇编程序和C程序之间的调用。1.内嵌汇编
内嵌汇编器armcc和armcpp用来支持完整的ARM指令集,tcc和tcpp用来支持Thumb指令集。内嵌的汇编指令包括大部分ARM指令和Thumb指令,但不能直接引用C语言的变量定义,数据交换必须通过函数过程调用标准ATPCS(ARM-ThumbProcedureCallStandard)进行。嵌入式汇编在形式上表现为独立定义的函数体。2.5.4汇编语言与C语言的混合编程1.内嵌汇编--内嵌汇编指令
2.5.4汇编语言与C语言的混合编程__asm(“指令[;指令]”);语法格式
:其中“__asm”是ARMC编译器使用的关键字,“__”是两个下划线。指令之间用“;”分隔。如果一条指令占据多行,在行尾可使用连字符“\”。汇编命令段中可使用C语言的注释语句。如果有多条汇编指令嵌入,则可用“{}”将它们归为一条语句,注意1.内嵌汇编--内嵌汇编注意事项
对于寄存器R0~R3、LR和PC的使用要格外小心。编译器在计算表达式时可能会将寄存器R0~R3、R12和R14用于子程序调用,因此在内嵌的汇编指令中,不要将这些寄存器同时指定为物理寄存器。
2.5.4汇编语言与C语言的混合编程__asm{ MOV R0,x ADD y,R0,x/y /*(x/y)的结果覆盖了R0*/}例:__asm{ MOV var,x ADD y,var,x/y }1.内嵌汇编--内嵌汇编注意事项
不要使用寄存器寻址变量。2.5.4汇编语言与C语言的混合编程intbad_f(intx){ __asm{ADDR0,R0,#1} /*将发生寄存器冲突,R0 中保存的x的值将不变*/ returnx; }例:intbad_f(intx){ __asm{ADDx,x,#1} /*将发生寄存器冲突,R0 中保存的x的值将不变*/ returnx; }1.内嵌汇编--内嵌汇编注意事项
使用内嵌汇编时,编译器会自动保存和恢复可能用到的寄存器,用户无须在程序中再作这些工作。读物理寄存器(除PSR寄存器之外)之前必须先进行写入。2.5.4汇编语言与C语言的混合编程intf(intx){__asm { STMFD SP,{R0} ;由于SP出现了写前先读,因 此对R0的保存是非法的 ADD R0,x,#1 EOR x,R0,x LDMFD SP!,{R0} ;对R0的恢复没有必要 }returnx;}例:1.内嵌汇编--内嵌汇编注意事项
LDM和STM指令的寄存器列表中只允许使用物理寄存器。内嵌汇编可以修改处理器模式、协处理器状态和FP、SL、SB等ATPCS寄存器,但是编译器在编译时并不了解这些变化,所以必须保证在执行C语言代码前恢复被改变了的处理器模式。2.5.4汇编语言与C语言的混合编程由于汇编语言使用“,”作为操作数的分隔符,因此带“,”的C语言表达式作为操作数时,必须用“()”括起来归为一个汇编操作数。#include <stdio.h>void my_strcpy(char *src,constchar *dst){ intch; __asm { loop: #ifdef _arm /*ARM版本*/ LDRB ch,[src],#1 STRB ch,[dst],#1 #else /*Thumb版本*/ LDRB ch,[src] ADD src,#1 STRB ch,[dst] ADD dst,#1 #endif CMP ch,#0 BNE loop }}例1、字符串复制intmain(void){ constchar *a=“HelloWorld!”; charb[20]; __asm { MOVR0,a /*设置入口参数*/ MOVR1,b BLmy_strcpy,{R0,R1} /*调用my_strcpy()函数*/ } printf(“Originalstring:%s\n”,a); /*显示字符串复制结果*/ printf(“Copiedstring:%s\n”,b); return0;}__inlinevoid enable_IRQ(void){ inttmp; __asm { MRS tmp,CPSR BIC tmp,tmp,#0x80 MSR CPSR_c,tmp }}__inlinevoid disable_IRQ(void){ inttmp; __asm { MRS tmp,CPSR ORR tmp,tmp,#0x80 MSR CPSR_c,tmp }}例2、使能和禁止中断intmain(void){ disable_IRQ(); enable_IRQ();}2.C语言和ARM汇编语言之间相互调用为了使不同编译器产生的程序和汇编语言编写的程序能灵活地混合,ARM公司定义了一系列过程调用的规则,称为ATPCS(ARM-ThumbProcedureCallStandard)。这些基本规则包括子程序调用过程中寄存器的使用规则
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 海口商铺交易合同参考
- 水上乐园用电施工合同
- 酒店前台经理聘用合同模板
- 环保工程师聘用合同工协议书
- 新材料研发招投标居间合同
- 学校供暖换热站建设合同
- 培训机构讲师聘用合同范本
- 商业综合体用地租赁合同协议书
- 陵园工程塔吊信号工招聘合同
- 科技创新园区合同
- 2022-2023学年成都市高二上英语期末考试题(含答案)
- QC成果提高叠合板安装合格率
- 线路施工质量验收及评定范围划分表
- 北师大版二年级下册口算题大全(全册齐全)
- 亨利爱帮忙 绘本课件
- 2023版思想道德与法治专题4 继承优良传统 弘扬中国精神 第2讲 做新时代的忠诚爱国者
- 上海证券交易所董事会秘书资格考试题库和答案-完整版
- 大秦线更换道岔工程施工组织设计
- 建设工程造价咨询报告参考模板
- 2022年公务员多省联考《申论》题(河南县级卷)
- GB/T 9386-2008计算机软件测试文档编制规范
评论
0/150
提交评论