cpu:运算器、控制器、寄存器、总线
8086cpu:14个寄存器
通用:ax\bx\cx\dx
每个都只能存放两个两位十六进制的数据(al,ah分别储存两位十六进制)也就是4位,2的4次方=16,每个字节8bit,所以占两个字节
Byte(字节) 是计算机存储和寻址的基本单位


超出能保存的位数则无法在指定寄存器中保存

进行数据传送或运算时需要保证两个操作对象位数一致
比如 mov ax,bl 是错的
8086内存寻址

原理

本质:基础地质(段地址*16)和一个相对基础地址的偏移地址相加
cs和ip寄存器中分别为代码段寄存器和指令指针寄存器。
8086cpu将从内存:(cs*16+ip)单元开始读取指令并进行。
即任意时刻,cpu吧cs:ip指向的内容当作指令执行。

流程:读取cs、ip到地址加法器->再到输入输出控制电路通过地址总线向内存中寻初始地址->读取对应地址所在的汇编指令并解码判断对应内存的机器指令(获取到内存中储存的机器指令再通过数据总线传回输入输出控制电路,同时IP偏移,cs:ip指向下一段汇编指令的起始地址)->机器指令送入cpu(->指令缓冲器->执行控制器)

段的概念
段起始地址一定为16位,偏移地址的寻址能力:

GNU汇编语法
大部分芯片在上电以后 C 语言环境还没准备好,所以第一行程序肯定是汇编的,至于要写多少汇编程序,那就看你能在哪一步把 C 语言环境准备好。所谓的 C语言环境就是保证 C 语言能够正常运行。 C 语言中的函数调用涉及到出栈入栈,出栈入栈就要对堆栈进行操作,所谓的堆栈其实就是一段内存,这段内存比较特殊,由 SP 指针访问, SP 指针指向栈顶。芯片一上电 SP 指针还没有初始化,所以 C 语言没法运行,对于有些芯片还需要初始化 DDR,因为芯片本身没有 RAM,或者内部 RAM 不开放给用户使用,用户代码需要在DDR 中运行,因此一开始要用汇编来初始化 DDR 控制器。
编写的是 ARM汇编,编译使用的 GCC 交叉编译器,所以我们的汇编代码要符合 GNU 语法。
GNU 汇编语法适用于所有的架构
每行一条语句:
label: instruction @ comment

可用.section伪操作来预定义一个段
系统预定义的:
.text 表示代码段。
.data 初始化的数据段。
.bss 未初始化的数据段。
.rodata 只读数据段。


GNU 汇编同样也支持函数,函数格式如下:
函数名:
函数体
返回语句
GNU 汇编函数返回语句不是必须的,
cortex-a7常用汇编指令

存储器访问指令
ARM 不能直接访问存储器,比如 RAM 中的数据, I.MX6UL 中的寄存器就是 RAM 类型的,我们用汇编来配置 I.MX6UL 寄存器的时候需要借助存储器访问指令,一般先将要配置的值写入到 Rx(x=0~12)寄存器中,然后借助存储器访问指令将 Rx 中的数据写入到 I.MX6UL 寄存器。读取 I.MX6UL 寄存器也是一样的,只是过程相反。常用的存储器访问指令有两种: LDR 和STR

压栈与出栈指令
我们通常会在 A 函数中调用 B 函数,当 B 函数执行完以后再回到 A 函数继续执行。要想在跳回 A 函数以后代码能够接着正常运行,那就必须在跳到 B 函数之前将当前处理器状态保存起来(就是保存 R0~R15 这些寄存器值),当 B 函数执行完成以后再用前面保存的寄存器值恢复R0~R15 即可。保存 R0~R15 寄存器的操作就叫做现场保护,恢复 R0~R15 寄存器的操作就叫做恢复现场。在进行现场保护的时候需要进行压栈(入栈)操作,恢复现场就要进行出栈操作。压栈的指令为 PUSH,出栈的指令为 POP, PUSH 和 POP 是一种多存储和多加载指令,即可以一次操作多个寄存器数据,他们利用当前的栈指针 SP 来生成地址
例:
压栈:

出栈:

跳转指令
1.B指令
跳转后无法返回

2.bl指令:
BL 指令相比 B 指令,在跳转之前会在寄存器 LR(R14)中保存当前 PC 寄存器值,所以可以通过将 LR 寄存器中的值重新加载到 PC 中来继续从跳转之前的代码处运行,这是子程序调用一个基本但常用的手段。比如 Cortex-A 处理器的 irq 中断服务函数都是汇编写的,主要用汇编来实现现场的保护和恢复、获取中断号等。但是具体的中断处理过程都是 C 函数,所以就会存在汇编中调用 C 函数的问题。而且当 C 语言版本的中断处理函数执行完成以后是需要返回到irq 汇编中断服务函数,因为还要处理其他的工作,一般是恢复现场。

算术运算

逻辑运算

浙公网安备 33010602011771号