微机原理
一、基础知识
进制数的转换
掌握2、10、16之间的转换,包括小数
整数部分使用除N取余法,小数部分使用乘N取整法
计算机保存数值数据的策略(原码、反码、补码)
补码的优点:1、唯一0表示.2、统一处理加减法运算(补码可以直接二进制相加得到正确的补码,减法可以将减数变成补码,然后二进制相加)
原码转补码: 1、确认符号位,2、如果是负数,原码取反+1,否则相同
补码转原码: 1、确认符号位 2、如果是负数,补码取反+1,否则相同
计算机保存非数值数据策略
保存字符,通过ASCII对照表来中的关系来保存对应的2进制数
需要记忆的有0的ASCII码为00110000即30H; A的为41H ; a的为61H; 换行 0AH ; 回车 0DH ;
计算机系统总线
数据总线、地址总线、控制总线
性能指标
字长
字长表示CPU一次能够处理的二进制代码的位数.32位系统一次能处理32位的二进制数.
二、8086CPU(经典CPU)
组成
由执行单元(执行指令)和总线接口单元(读取指令、读取或存储数据)组成
总线接口又包含地址线和数据线,才能和存储器交换数据
8086有20条地址线,可以寻址2^20也就是1M个地址
寻址策略: (16位)偏移地址+(16位变20位)段地址*16=20位真实物理地址 (有一个地址加法器专门处理)
CPU内部寄存器
段寄存器
- CS代码段寄存器,只和IP搭配:指令代码地址=16*CS+IP
- SS堆栈段寄存器,只和SP或BP搭配
- DS、ES数据段寄存器,放普通数据的段地址只和SI、DI、BX搭配.
一个段长度为16位,每个位置对应1B的数据,即64KB数据
标志寄存器(16位)
- CF(Carry Flag)进位或者借位置1
- PF(Parity Flag)运算结果有偶数个1时置1,用于校验防错.
- AG(Auxiliary carry Flag)专门给BCD进行修正用,要修正时置1
- ZF零标志位,结果为0时置1.条件语句会用到
- SF(Sign Flag) 负数置1
- OF(Overflow)溢出置1
- DF(Direction Flag)开机为0,0时数据地址递增处理
- IF(Interrupt)中断允许标志位,置1时表示允许中断.
通用寄存器
AX BX CX DX
字数据存放规则
字数据占连续的地址时,基地址作为字数据的地址
规则字: 字数据的基地址为偶地址
8086存储器分两片,一片单一片双数地址,可以并行传输数据,通过连接高位地址+片选位,可以达到即能传输16位也能传输8位,规则字保证16位和8位都统一只用传输1次.
8086寻址IO端口
8086使用16条地址总线对IO端口寻址,也就是可以寻址64K个端口
三、汇编指令
执行汇编指令,需要指令集(将指令翻译成机器码)和操作数
指令集
不同的公司的指令集往往不兼容
对操作数的寻址方法
根据操作数所在位置,分为三种寻址方式
- 在存储器代码段中,立即操作数,立即寻址
- 在存储器数据段中,存储器操作数,存储器寻址
- 在CPU的寄存器中,寄存器操作数,寄存器寻址
立即寻址
操作数直接就在指令本身中,不用去拿,比如指令是1,操作数就是1,速度最快
也就是说,CPU从代码段中拿到指令就已经包括操作数了
寄存器寻址
寄存器在CPU中,因此不需要地址,直接能找到相应的寄存器拿数据,速度较快
存储器寻址
最慢的,CPU从代码段中拿到指令,执行指令时需要再次通过总线到存储器中寻找相应的操作数.
直接寻址
指令中直接写出16位偏移地址.
执行时,段寄存器中的段地址(默认DS段)会和偏移地址组合成为物理地址
取多长?由目的操作数的长度决定.寄存器间接寻址
通过访问寄存器(例如BX)来间接得到偏移地址,合成物理地址再寻址
特别的: 当间接寻址制定的寄存器时BP、SP时,段寄存器将不同于其他,而是默认使用SS来作为偏移地址参与计算.寄存器相对寻址
在间接寻址的基础上,给寄存器多加一个相对偏移量,也是C中的数组下标的原型.数组下标其实就是相对偏移量.对应C中的 A[1];基址变址寻址
在寄存器相对寻址基础基础上,偏移量也是一个变量.对应C中的A[i];相对基址变址寻址
对应C语言的A[i+2];其实更多的是用于多维数组,比如A[i][2],当然A[1][0]应该是寄存器相对寻址.二维数组寻址时会根据数组类型(包含数组长度信息)来计算正确的物理地址,比如查到A的类型是*[2][3],那么在解析A[1][2]时,就要用A基地址+1 * 4 H + 2H 得到正确的地址(4是每行4个元素).当然以上的数据元素大小都是1H也就是16位,2字节.如果是4字节数据,偏移量要相应乘2.
常用指令
MOV ( 理解为C中的赋值)
- 目的操作数不能立即寻址(赋值号左值不能为常量)
- 两个操作数不能同时为存储器寻址,即在汇编中无法一条指令搞定C中的a=b
- 段寄存器只能与通用寄存器或存储单元传数据
- CS、IP、FLAGS不可以赋值
- 操作数字长需要相等
PUSH、POP
- 其实就是MOV 目的操作数 顶栈元素 然后将顶栈指针++或–,因此继承了MOV的所有
- 只能操作字数据(PUSH一个字,SP-2)
PUSHF、POPF
- 其实就是PUSH FLAGS
一般通过OR指令来改变某一位标志位
XCHG
- 其实就是自带中间变量的MOV指令,交换两个操作数.
IN、OUT
也是赋值,但是源操作数是端口的地址,没有中括号
- 放端口内容的只能使用A寄存器
- 端口地址如果为16位,必须写入DX才能用(IN AL ,1234H是错误的)
XLAT (翻译AL的内容)
将AL中的立即数作为偏移量,将BX的物理地址作为基地址取内容,放回AL,需要预先将BX指向数组.
LEA
给源操作数加取地址(OFFSET)的MOV指令
ADD SUB ( C中的+=和-=运算符)
也就是说,它的目的操作数也不能是立即数,即被加数和被减数都不能是立即数
ADC SBB( 多加一个进位、借位标志的+=和-=运算符)
当8086处理双字长的数据加法时,高位加法需要使用ADC
INC DEC(C中的++和- -运算符)
NGE ( 将负变正,将正变负)
将操作数的补码变为相反数的补码,保存下来,如何变?取反加一.
CMP ( C中的==逻辑运算符,比较两个操作数是否相等,相等时将ZF置1)
MUL IMUL (*=运算符)
先判断源操作数的位数,8位的与的AL(8位)寄存器相乘放AX(16位).16位的与AX相乘放DX和AX.
- 源操作数不可以立即寻址(判断不了位数)
- 使用前确保被乘数放在了A上,且符合位数要求,有符号数放入寄存器时可能需要扩展,因此需要配合CBD和CWD
- 当使用寄存器间接寻址时,需要制定位数: MUL BYTE PTR [BX]
1 | MOV AX, -6 ; AX = FFFA (-6 的 16 位表示) |
DIV IDIV (/=运算符)
先判断源操作数的位数,8位的会拿AX(16位)来除,商放在AL ,余数放在 AH.16位的会拿DX,AX(32位)来除, 商放在AX ,余数放在DX
- 使用事项同MUL.
- 可能溢出.OF将会记录
DAA DAS ( 压缩BCD码修正指令)
无操作数,将会加六或减六修正AL中的BCD码
AAA AAS(非压缩BCD码修正指令)
无操作数,将会加六修正AL中的非压缩BCD码 (会自动给高位置0)
AND OR XOR
与操作常常用于置0, 或操作常常用于置1,异或操作往往用来保持(0)和取反(1)或者清零(异或自己)
TEST JNZ
将两个操作数相与,结果为非0时执行JNZ后的标签.同CMP用于条件分支语句,但是这里可以单独判断某一位的情况,而CMP是比较两个完整的数.
SAL SAR SHL SHR 移位运算,前两个是算数移位,后两个是有符号数移位
- 源操作数只能是1或者CL,表示移位的次数
- 移位常常用来计算乘法,比MUL速度快很多.
比如要算10*AX,就可以分为2AX+8AX.即将AX左移1位和左移3位的数相加.
ROL ROR RCL RCR 循环移位 移位出来的值能从另一边赋进去.后两个大循环移位,会包括进位
可以用来快速交换AH和AL的数值
JMP 无条件跳转语句 (goto 语句)
JMP语句将会根据跳转需求,修改IP的指向
JMP 地址标号 或JMP FAR PTR 地址标号
JZ JNE JO JC JB JA 无符号 JL JG有符号 条件跳转语句 (根据标志位进行跳转)
CALL 调用子程序(函数)
会使用堆栈保存IP的地址,然后IP才会指向子程序,返回时IP地址出栈.
INT 调用中断子程序
14H为串口中断,
使用前初始化AX、DX寄存器:
AH : 0初始化、1 写 、2读、3取状态
AL : 3位波特率、2位奇偶、1位终止位、2位字长
DX : 0指向COM1 、1指向COM2…
INT 14H; 使用后返回AH(通信口状态)AL(调制解调器状态)
写:
AH : 1
AL : ‘A’
DX : 0
INT 14H;使用后返回AH(通信口状态,第七位0成功)
读:
AH: 2
DX: 0
INT 14H使用后返回AH(通信口状态,第七位0成功)
21H为键盘中断 有按下AL为1
初始化:
AH : 0BH ( 检查状态) 1 7 8 ( 输入字符)
INT 21H (AL作为状态位) 或 (等待输入字符到AL)
CMP AL , 0 或字符
JE 跳转
一下是一个接受键盘输入字符串,输出第1个字符的例子(使用DOS中断):
1 | DATAS SEGMENT |
伪指令
段名 SEGMENT … 段名 ENDS 和 ASSUME CS : 段名可以定义段和段类型
START: … END START (类似于C中的mian,让计算机的IP从这里开始指,开始执行.
EQU (类似于C中的宏定义) ; = ( 可以覆盖的宏定义) ;PURGE ( 解除宏定义,类似于C中的 #undef)
a EQU 7 ; #define a 7
变量名 DB/DW/DD 值 (类似于C中的定义变量,但是又有区别)
汇编中,在数据段中生成变量相应的内容.(因此它不是指令,放在数据段中,只有指令才放在代码段中)
C中,在数据段中生成变量内容,还要生成处理这些内容的指令到代码段,程序执行时,通过代码段指令拿到数据段内容,然后再放到内存的某个位置(比如全局变量会放到数据段)
如何取得数据段定义好的值,如果是字节,直接MOV取.如果是数组,需要先取首地址作偏移地址,然后通过相对寻址取数据
1 | MOV SI , OFFSET arrayName |
EVEN (保证从偶地址开始定义数据) ALIGN N (保证地址从N的倍数地址开始)
子程序名 PROC 远近属性 … RET ENDP
如果希望不要主程序数据,应该再子程序逻辑前后使用PUSH和POP保护数据.
四、总线
地址和数据不在同一时候传送,因此可以让CPU引脚分时复用,从而减少引脚数
| 引脚 | BHE/S7 | A19/S6 | A18/S5 | A17/S4 | A16/S3 | AD15~AD0 |
|---|---|---|---|---|---|---|
| 传地址时 | BHE | A19 | A18 | A17 | A16 | A15~A0 |
| 传数据时 | S7 | S6 | S5 | S4 | S3 | D15~D0 |
8086引脚
M/IO非
标识现在给出的地址是存储还是IO地址
DT/R非
标识数据总线的数据的方向,是发送还是接收
DEN非
低电平表示传输的是数据
ALE
高电平表示传输的是地址
HOLD HLDA
请求总线标志和已允许请求标志
WR非 RD非
标志CPU对存储器或IO写、读
INTR INTA非 NMI
INTR 是可屏蔽中断请求,一般接可以不管的中断比如鼠标键盘
INTA非 是根据IF位对INTR请求的相应,IF如果是0,即使INTR是1,也不相应,置1
NMI 是不可屏蔽中断请求,必须相应,一般接不可不管的中断,比如Reset,断电等.
READY
有效则CPU继续运行,有些设备会使CPU等待,就置0
TEST非
WAIT指令期间,TEST非有效才能脱离等待继续运行
RESET
所有寄存器清零,除了CS复位位0FFFFH,让程序从0FFFF0H开始执行.
8284时钟发生器
引脚
F/C非
选择是本地还是外部时钟,如果是1则选择本地X1X2连接的石英晶体振荡器
得到CLK(三分之一fOSC)和PCLK(六分之一fOSC)
RES非 RESET
RES非接受到下降沿(按下按键)时,RESET引脚置1
RDY1 RDY2 AEN1非 AEN2非 READY
可以统一管理多个READY信号,防止冲突



