1、BCD码的意义和表示
压缩BCD数 → 用8位二进制数表示2个十进制数位
非压缩BCD数 → 用8位二进制数表示1个十进制数位
如:19
- 压缩BCD → 0001 1001 = 19H
- 非压缩BCD → 00000001 00001001 = 0109H
① 十进制数与BCD数的转换
直接转换
② BCD数转换为二进制数
写出BCD数的十进制数 → 十进制数转换为二进制数
③ 二进制数转换为BCD数
二进制数转换为十进制数 → 根据十进制数写出BCD数
十进制数4256的压缩BCD码表示为:
0100 0010 0101 0110 B (即4256H)
十进制数4256的非压缩BCD码表示为:
xxxx0100 xxxx0010 xxxx0101 xxxx0110 B
有时,要求非压缩BCD码的高4位为0,这时,4256(10)的非压缩BCD码为04020506H。
BCD数低位与高位之间逢“10”进1,4位二进制数之间逢“16”进1。而计算机按二进制规律运算,故BCD数进行运算后须进行调整
简而言之,压缩BCD码就是一个十进制数占4位,非压缩BCD码就是一个十进制数占8位。
1. BCD数加法运算
调整规则:
- 和在0~9之间, 保持不变;
- 和大于9, 加6调整
如:48+59=107
1. BCD数减法运算
调整规则:
- 差在0~9之间, 不变;
- 差大于9, 减6调整
2、执行单元和总线接口单元的作用
8086 CPU从功能上可分为两部分,即总线接口部件(bus interface unit,缩写为BIU)和执行部件EU(execution unit)。8086的内部结构如图所示。
EU不与外部总线,即外部世界相连,只负责执行指令。BIU则负责从存储器或外部设备中读取指令和读写数据,即完成所有的总线操作。这两个单元处于并行工作状态,可以同时进行执行指令和读写操作。
1.执行单元EU
对于负责执行指令的执行单元EU
- 算数逻辑单元ALU
- 标志寄存器FLAGS:反映CPU状态和控制标志状态的
- 一组通用寄存器和运算寄存器系统:内部的数据传输都是16位
EU从BIU中取得指令和数据,执行指令要求的操作,该操作有2种:
- 进行算数逻辑运算
- 计算存储器操作数的偏移地址
当指令要求执行存储器或IO设备的数据存取操作时,EU向BIU发出请求,BIU根据EU的请求,完成8088/8086与存储器或外设之间的数据传送
2总线接口BIU
对于负责与存储器或外设进行读取指令和数据的总线接口BIU
- 一组段寄存器CS,DS,SS,ES(S-segment)
- 一个指令寄存器IP,6个字节的指令队列
- 地址加法器
- 总线控制逻辑。
段寄存器提供的段地址和偏移地址在地址加法器中相加,并将其结果存放在物理地址锁存器中。
指令队列寄存器为一个能存放6个字节的存储器,在EU执行指令的过程中,BIU根据指令提示器的偏移地址,从存放指令的存储器中预先取出一些指令放在指令队列中。指令在队列中是顺序排序的。(流水线结构)
多数情况下,指令队列中至少应有一个字节的指令,这样EU不比等待BIU去取指令。
BIU在下面两种情况要执行取值操作:
- 指令队列中出现2个以上字节空的时候
- 当程序发生转移时,BIU执行取值操作,BIU将所取得的第一条指令直接送到EU中去执行,将随后取来的指令重新填入指令队列中,冲掉转移前放入指令队列中的指令。
3、什么是物理地址,什么是逻辑地址,如何转换?
采用分段结构的存储器中,任何一个逻辑地址都是由段基址和偏移地址两部分构成,它们都是无符号的16位二进制数。存储器的任何单元都有唯一的物理地址。也就是说每个存储单元都可以用物理地址和逻辑地址来表示。物理地址是用唯一的20位二进制数表示的,CPU与存储器交换信息使用的是物理地址。程序中不能使用物理地址(位数不够),而要使用逻辑地址,即段基址:偏移地址
物理地址的形成:段寄存器的值 × 10H + 偏移地址
将段寄存器的值即段基址乘以10H(将16位二进制数逻辑左移4位)得到20位的段首址,然后与16位的偏移地址相加得到20位的物理地址。例如:
- 逻辑地址0001H:1010H对应的物理地址为00010H+1010H=01020H
- 逻辑地址0101H:0010H对应的物理地址为01010H+0010H=01020H
4、什么是段基址,什么是偏移地址?什么段?理解段的概念、意义、性质和使用。
8086/8088有20条地址线,存储器的物理地址必须用20位二进制数表示。ALU只能处理16位的地址运算,与地址有关的寄存器都只有16位。因此8086/8088把20位的存储器地址分成若干个段来表示。段寄存器就是用来存放段基址(段的起始地址的高16位地址)的寄存器。段内再由16位二进制数来寻址,段内寻址的16位二进制数是段起始地址到存储单元的字节距离,称为段内偏移地址。
存储单元的地址由段基址或段寄存器和偏移地址两部分组成,用冒号连接段基址或段寄存器和偏移地址,像这样表示的地址称为逻辑地址。
1 | 段基址:偏移地址 或 段寄存器:偏移地址 |
CS——存放代码段的段基址
SS——存放堆栈段的段基址
DS——存放数据段的段基址
ES——存放附加数据段的段基址
代码段的逻辑地址 ——CS:IP
堆栈段的逻辑地址—— SS:SP
通过4个段寄存器的使用,使得在任意时刻,程序都可以仅通过偏移地址立即访问4个段中的存储器,CPU自动根据偏移地址安排到代码段中去存取指令代码,到数据段中去存储数据,到堆栈段中执行进栈和出栈操作。
每次需要生成物理地址的时候,一个段寄存器就会自动被选择,且都可以自动左移4位,再与一个16位的偏移地址相加,产生所需要的20位物理地址。
8086/88有4个段寄存器CS,DS,SS,ES来存放段基址,还有6个16位寄存器SP,SI,DI,BX,BP,SP来存放偏移地址,在寻址时要使用哪个寄存器是BIU根据操作要求来确定的。
如果是取指令,则由代码段寄存器CS给段基址,指令提示器IP给取指令的偏移地址。
如果是存取数据,段基址一般由DS给出,偏移地址可以由指令直接给出,也可由BX,SI,DI给出,或者根据指令的要求计算出来,计算出来的偏移地址称为有效地址。
如果是堆栈操作,被寻址的操作数的段基址和偏移地址由堆栈寄存器和堆栈指示器给出。
为什么一个段最大为64K?
8086/88是16位微处理器,所有操作可以按字节为单位也可以按字为单位处理。该系统中存储器是以8位(1个字节)为一个存储单元进行编址的,每个存储单元用唯一的一个地址码来表示,一个字即16位占2个单元,这两个单元都有各自的地址,规定处于低地址的字节的地址称为这个字的地址。存储器中任何连续存放2个字节都可以称为一个字。偶数地址的字称规则字,奇数地址的字称为非规则字。高地址字节为高位字节,低地址字节为低位字节。如00000H地址中存放一个字2301H,则00000H单元中存放01H,00001H单元中存放23H。字4523H的存放地址为00001H。字2301H为规则字,4523H为非规则字。
大端:高对低,低对高
小端:高对高,低对低
5、出栈和入栈操作的过程
概念:是按后进先出原则组织的一片存储区域,用来暂存一批需要回避的数据或地址。用途:暂存数据、断点信息或传送信息
8086中的堆栈是向下生长的。即栈顶向地址码小的方向生长。
空栈:在进行堆栈操作前,为空栈。此时SP应预置一个初值。该值为堆栈空间的大小。
SP初值=堆栈空间的最大容量
例:SP=0008H。则最大容量为8个字节。
SP指向当前的栈顶。
6、如何定义变量?
变量是存储器中数据的符号表示,变量名为数据首地址
1 | [变量名] DB 表达式[, ……] ;定义字节变量 |
数据定义指明了变量的类型
表达式确定变量的初值。表达式有如下6种:
(1)表达式为常量或数值表达式 → 存入数值
1 | W1 DW 1 |
(2)表达式为ASCII字符串 → 存入ASCII值
1 | W2 DW ’AB’ ;用DW定义时,串长不可大于2 |
(3)表达式为重复子句
1 | N DUP(表达式) |
(4)地址表达式(只适用DW、DD和DF3个伪指令)
1 | [变量名] DW 地址表达式 ;取其偏移地址来初始化变量 |
(5)由以上表达式组成的序列,之间用‘,’分隔
1 | B5 DB 1,2,3 |
(6)地址表达式类型的变更
变量、标号以及由其组成的地址表达式均有类型属性。地址表达式的类型属性由其中的变量或标号(一个地址表达式不可能同时含有变量和标号)决定。不含变量或标号,仅含寄存器的地址表达式没有类型属性。可以使用PTR算符临时变更原地址表达式的类型属性,或者明确没有类型属性的地址表达式的类型,而仍保持它们原来的段基址和偏移地址属性不变。
1 | 类型 PTR 地址表达式 |
7、8255写方式控制字时,地址线应如何连接?
见笔记
8、定义变量在存储器中的存放,表7-2
在汇编语言中,我们通常使用变量和地址表达式来访问存储器,而不是直接使用物理地址。
- 变量: 变量是存储器位置的符号名称。例如,
BUFF
就是一个变量,它代表存储器中的一个地址。 - 地址表达式: 地址表达式是使用变量和运算符(如
+
、-
)计算出的地址。例如,BUFF+1
表示BUFF
地址后的一个字节的地址。
字(Word)和双字(Double Word)
- 字(Word): 一个字通常由 2 个字节(16 位)组成。
- 双字(Double Word): 一个双字通常由 4 个字节(32 位)组成。
存储方式、地址和字节序(小端)
假设变量 BUFF
指向的内存区域如下(以十六进制表示,并假设 BUFF
的起始地址为 0x1000
,仅作示例):
地址 | 内容 |
---|---|
0x1000 (BUFF) |
01H |
0x1001 (BUFF+1) |
23H |
0x1002 (BUFF+2) |
45H |
0x1003 (BUFF+3) |
67H |
0x1004 (BUFF+4) |
89H |
0x1005 (BUFF+5) |
ABH |
- 字
2301H
: 存储在BUFF
和BUFF+1
两个字节中。由于是小端字节序,低位字节01H
存储在低地址BUFF (0x1000)
,高位字节23H
存储在高地址BUFF+1 (0x1001)
。因此,字2301H
的地址是BUFF (0x1000)
。 - 字
4523H
: 存储在BUFF+1
和BUFF+2
两个字节中。低位字节23H
存储在BUFF+1 (0x1001)
,高位字节45H
存储在BUFF+2 (0x1002)
。因此,字4523H
的地址是BUFF+1 (0x1001)
。 - 双字
AB896745H
: 存储在BUFF+2
、BUFF+3
、BUFF+4
和BUFF+5
四个字节中。按照小端存储,字节的排列顺序为45H
、67H
、89H
、ABH
。因此,双字AB896745H
的地址是BUFF+2 (0x1002)
。
规则字和非规则字
- 规则字: 如果一个字的起始地址是偶数,则称为规则字(或对齐的字)。
- 非规则字: 如果一个字的起始地址是奇数,则称为非规则字(或未对齐的字)。
在上面的例子中,如果 BUFF
的地址是偶数(例如 0x1000
),那么字 2301H
就是规则字,而字 4523H
就是非规则字。访问非规则字在某些处理器上可能会导致性能下降或需要特殊的处理。
字节序(小端)
小端字节序(Little Endian) 指的是:
- 低位字节存储在低地址,高位字节存储在高地址。
这是与人类书写数字的习惯相反的。
9、总线中的数据流通是通过什么控制的?
10、dos2号功能调用是做什么?
2号功能调用——显示器显示一个字符
1 | MOV DL,;待显示字符的ASCII |
入口:输出字符的ASCII 送 DL
出口:无出口参数
例:显示字符 ’B’
1 | MOV AH,2 |
11、什么是中断方式,什么是查询方式?
传送控制方式有查询、中断和DMA 3种。
(1)查询方式
查询方式是中央处理器在数据传送之前通过接口的状态设置存储电路询问外设,待外设允许传送数据后才传送数据的操作方式。
在查询方式下,CPU需要完成以下操作:
- CPU向接口发出传送命令,输入数据或输出数据;
- 中央处理器查询外设是否允许传送?
在查询方式下,中央处理器会询问外设是否允许传送,若不允许传送,则继续查询外设,直到外设允许CPU传送数据后,CPU才会向外设发送数据,因此CPU需要花费较多的时间去不断地“询问”外设,外设的接口电路处于被动状态。
(2)中断方式
中断方式是在外设要与中央处理器传送数据时,外设向中央处理器发出请求,中央处理器响应后再传送数据的操作方式。
在中断方式下,中央处理器不必查询外设,提高了系统的工作效率,但中央处理器管理中断的接口比管理查询复杂。
12、8253的初始化、频率如何计算?
13、8255A的编程
14、左移指令,右移指令,求补指令,取反指令
1. 左移指令 (Shift Left)
左移指令将操作数中的所有位向左移动指定的位数。空出的位用 0 填充。
逻辑左移 (SHL/SAL): 移出的最高位进入进位标志位 CF (Carry Flag),最低位补 0。SHL 和 SAL 指令在功能上是相同的。
1
2SHL 操作数, 移位次数
SAL 操作数, 移位次数操作数
:可以是寄存器或内存单元。移位次数
:可以是立即数 (1 或 CL 寄存器中的值)。
例子:
1
2
3MOV AL, 00011011B ; AL = 27
SHL AL, 1 ; AL 左移 1 位,AL = 00110110B = 54,CF = 0
SHL AL, 2 ; AL 左移 2 位,AL = 11011000B = 216,CF = 0解释: 每次左移一位,相当于将原数乘以 2。
循环左移 (ROL): 移出的最高位不仅进入 CF,还填补到最低位。
1
ROL 操作数, 移位次数
例子:
1
2MOV AL, 10000001B
ROL AL, 1 ; AL 循环左移 1 位,AL = 00000011B, CF=1
2. 右移指令 (Shift Right)
右移指令将操作数中的所有位向右移动指定的位数。
逻辑右移 (SHR): 移出的最低位进入 CF,最高位补 0。
1
SHR 操作数, 移位次数
例子:
1
2MOV AL, 11001000B
SHR AL, 1 ; AL 逻辑右移 1 位,AL = 01100100B, CF = 0解释: 每次逻辑右移一位,相当于将无符号数除以 2。
算术右移 (SAR): 移出的最低位进入 CF,最高位保持不变 (即用原最高位的值填充)。这对于有符号数的除法很有用,可以保持符号位不变。
1
SAR 操作数, 移位次数
例子:
1
2MOV AL, 11001000B (-56) ; 假设是有符号数
SAR AL, 1 ; AL 算术右移 1 位,AL = 11100100B (-28), CF = 0解释: 每次算术右移一位,相当于将有符号数除以 2。
循环右移 (ROR): 移出的最低位不仅进入 CF,还填补到最高位。
1
ROR 操作数, 移位次数
例子:
1
2MOV AL, 00000011B
ROR AL, 1 ; AL 循环右移 1 位,AL = 10000001B, CF=1
3. 求补指令 (NEG - Negate)
求补指令将操作数取反 (所有位取反),然后加 1。这实际上就是计算操作数的二进制补码,相当于乘以 -1。
1 | NEG 操作数 |
例子:
1 | MOV AX, 0000000000001010B (10) |
解释:
- 先取反:
0000000000001010B
取反后得到1111111111110101B
。 - 然后加 1:
1111111111110101B + 1 = 1111111111110110B
。
4. 取反指令 (NOT - Not)
取反指令将操作数中的每一位进行翻转,0 变为 1,1 变为 0。
1 | NOT 操作数 |
例子:
1 | MOV AL, 00111100B |
总结
指令 | 功能 | 影响标志位 |
---|---|---|
SHL/SAL | 逻辑/算术左移 | CF, OF, PF, SF, ZF |
SHR | 逻辑右移 | CF, OF, PF, SF, ZF |
SAR | 算术右移 | CF, OF, PF, SF, ZF |
ROL | 循环左移 | CF, OF |
ROR | 循环右移 | CF, OF |
NEG | 求补 (取反加 1) | AF, CF, OF, PF, SF, ZF |
NOT | 取反 | 无 |
编程例题
Eg2两个BCD数相加
编程实现如下功能:已知字变量W1和W2分别存放着两个压缩BCD数,分别为W1=8931H,W2=5678H,求两数之和,并将其和送到SUM字节变量中
1 | DATA SEGMENT |
DAA
(Decimal Adjust Accumulator after Addition) 指令用于在加法运算后对AL寄存器中的结果进行十进制调整,使其符合压缩BCD码的表示。
DAA
指令只对AL寄存器有效。由于我们进行的是字(16位)加法,结果在AX中,DAA
只会调整AL部分。因此,如果需要处理多字节BCD加法,需要分别处理每个字节,并考虑进位。DAA
DATA SEGMENT BUF DB 3H,7H,9H DATA ENDS1
2
3
4
5
6
7
8
9
10
11
12
指令根据以下规则进行调整:
- 如果AL的低四位大于9或辅助进位标志AF=1,则AL=AL+6。
- 如果AL的高四位大于9或进位标志CF=1,则AL=AL+60H。
### Eg3冒泡法从大到小排序
编程实现如下功能:设有3个单字节无符号数存放在BUF开始的缓冲区中,编写一个能将它们从大到小排列的程序。如何将以上三个数字代表的字符在屏幕上进行显示?
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV AL,BUF[0]
CMP AL,BUF[1]
JG CON
XCHG AL,BUF[1]
;如果0<1,交换。此时AL中是BUF1的值为最大
MOV BUF[0],AL
;最大值在AL中要给BUF0
CON:
MOV AL,BUF[2]
JG CON2
XCHG AL,BUF[2]
MOV BUF[0],AL
CON2:
MOV AL,BUF[1]
CMP AL,BUF[2]
JG FINISH
XCHG AL,BUF[2]
MOV BUF[1],AL
FINISH:
MOV AH,4CH
INT 21H
CODE END
START END
1 |
|
DATA SEGMENT
X DD 723156A8H
Y DD 91A4C2EFH
Z DD ?
DATA ENDS
CODE SEGMENT
CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV CX,4
MOV SI,0
AND AX,AX
AGAIN:
MOV AL,BYTE PTR X[SI]
ADC AL,BYTE PTR Y[SI]
MOV BYTE PTR Z[SI],AL
INC SI
LOOP AGAIN
MOV AL,4CH
INT 21H
CODE ENDS
START END
1 |
|
DATA SEGMENT
BUF1 DB 1H,0H,5H,0H,9H
CNT DB 0
DATA ENDS
CODE SEGMENT
CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV CX,5
MOV SI,0
AND AX,AX
AGAIN:
MOV AL,BYTE BUF1[SI]
CMP AL,0
JNE CON
INC BL
MOV CNT,BL
CON:
INC SI
LOOP AGAIN
FINISH:
MOV AL,4CH
INT 21H
CODE ENDS
START END
1 |
|
INC BL
MOV CNT,BL
1 |
|
DATA SEGMENT
BLOCK DB 1H,-3H,5H,-7H,9H
COUNT EQU $-BLOCK
DPLUS DB COUNT DUP(0)
DMINUS DB COUNT DUP(0)
DATA ENDS
CODE SEGMENT
CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV CX,5
MOV SI,0
MOV DI,0
XOR AX,AX
AGAIN:
MOV AL,BYTE BLOCK[SI]
CMP AL,0
JG PLUS
MOV BYTE DMINUS[DI],AL
INC DI
JMP NEXT
PLUS:
MOV BYTE DPLUE[DI],AL
INC DI
NEXT:
INC SI
LOOP AGAIN
MOV AL,4CH
INT 21H
CODE ENDS
START END
1 |
|
DATA SEGMENT
DATT DB 10H,-20H,23H,45H,-66H,77H,88H,99H,-32H,-12H
NUM DB 0
DATA ENDS
CODE SEGMENT
CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV CX,10
MOV SI,0
MOV DI,0
XOR AX,AX
AGAIN:
MOV AL,BYTE DATT[SI]
JS NEXT
INC DI
NEXT:
INC SI
LOOP AGAIN
MOV NUM,DL
MOV AL,
INT 21H
CODE ENDS
START END
1 |
|
DATA SEGMENT
STRING DB ‘AOPYSYSNN$’ ;(元素个数<10)
DATA ENDS
DATA SEGMENT
STRING DB ‘AOPYSYSNN$’
LENGTH DB 0
DATA ENDS
CODE SEGMENT
CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
XOR DI,DI
MOV SI, OFFSET STRING
AGAIN:
CMP STRING[SI],’$’
JE FINISH
INC SI
INC DI
JMP AGAIN
FINISH:
MOV LENGTH,DL
ADD DL,’0’ ; 将数字转换为 ASCII 字符
MOV DL,DL ; 将字符存入 DL 寄存器(输出字符)
MOV AH,2 ; 系统调用:显示字符
INT 21H ; 输出字符
CODE ENDS
START END
1 |
|
DATA SEGMENT
ARRAY DB 10H,-20H,23H,45H,-66H,77H,88H,99H,-32H,-12H
POSI DB ?
NEGA DB ?
MAX DB ?
MIN DB ?
NUMPOSI DB ?
DATA ENDS