第三章 8086寻址方式和指令系统

1. 8086 的 8 种寻址方式

  1. 立即寻址
1
MOV CX,2A50H
  1. 寄存器寻址
1
2
DX=18C7H,AX=3A68H
MOV DX,AX ;DX=3A68H
  1. 直接寻址

​ 为了和立即数区分,指令中有效地址两侧需要加一个方括号。

1
2
DS= 3000H, (32000H)=34H, (32001H)=12H
MOV CX,[2000H] ;CX=1234H
  1. 寄存器间接寻址

    指令中给出的寄存器中的值不再是操作数本身,而是操作数的有效地址。

ps:出现在中括号[]里的只能是BX,BP,SI,DI。其中BP比较特殊,默认是和SS寄存器搭配,其他三个默认与DS搭配。

物理地址 = $16\times$DS + BX (或SI,DI)

物理地址 = $16\times$SS + BP

1
2
DS=1000H, SI=2000H, (12000H)=318BH
MOV BX,[SI] ;BX=318BH
  1. 寄存器相对寻址

    有效地址是基址(BX,BP)或变址(SI,DI)寄存器的内容与指令中指定的偏移量之和。

1
2
3
4
5
6
DS=3000H,SI=2000H,ADDR1=4000H,(36000H)=5678H
MOV BX,4000H[SI]
MOV BX,[4000H][SI]
MOV BX,[4000H+SI]
MOV BX,ADDR1[SI]
;以上四条等价
  1. 基址变址

    有效地址是一个基址寄存器和一个变址寄存器的内容之和。

1
2
3
DS=3000H,BX=1200H,SI=0500H,[31700H]=ABCDH
MOV AX,[BX][SI] ;AX=ABCDH
MOV AX,[BX+SI]
  1. 相对基址变址

    有效地址=基址+变址+偏移量

1
2
DS=2000H,BX=1500H,SI=0300H,MASK=0200H,(21A00H)=26BFH
MOV AX,MASK[BX][SI] ;AX=26BFH
  1. 其它

    不重要,略

image-20241125170049583

2. 8086指令系统

1. 通用数据传输指令

  1. MOV
image-20241125171039705
2. PUSH
image-20241231225142507
3. POP
image-20241125171303262
4. XCHG
image-20241125171452005
5. XLAT
image-20241125171559779
6. IN/OUT
image-20241125171653277

补充:16位端口由两个地址连续的八位端口组成,从16位端口输入时,先将给定端口中的字节送进AL,再把端口地址加一,然后将该端口中的字节读入AH

  1. LEA
image-20241125172351036

2. 算术运算指令

  1. 加法指令

    • ADD:

      ADD DX,AX ;DX+AX -> DX

    • ADC(带进位加法):

      ADC CX,BX ;CX+BX+CF -> CX

    • INC(++指令):

      INC DEST ; DEST+1 -> DEST

    • DAA(加法的十进制调整指令):

      格式:DAA

      指令功能:将两个压缩BCD数相加后的结果调整为正确的压缩BCD数,相加后的结果必须在AL中才能使用DAA指令。

      image-20250104161746095
  2. 减法指令

    • SUB:

      SUB DX,AX ;DX-AX -> DX

    • SBB:

      SBB CX,BX ;CX-BX-CF -> CX

    • DEC(–):

      DEC DEST ;DEST-1 -> DEST

      image-20241126101728282

    ps:上述注意事项同样适用于INC,如:

    1
    2
    >INC BYTE PTR [SI]
    >DEC WORD PTR [SI]

    出现[]说明操作数在存储器中,需要用PTR标明是字还是字节

  3. CMP

    CMP DEST, SRC ;计算DEST-SRC->PSW(标志寄存器),结果不送回DEST,仅仅影响标志位

    ps:对于双操作数指令ADD、SUB、CMP等:

    • 目的操作数不能是立即数
    • 两个操作数不能都是存储单元
    • 源操作数和目的操作数的类型必须一致,即都是字节或者字
    • 影响所有标志位:CF/OF/PF/SF/ZF/AF
  4. NEG

    NEG DEST ;0-DEST -> DEST,对目的操作数取负,再送回到目的操作数

    image-20241126101421856
  5. MUL

​ MUL 源

​ 如果源操作数是字节,那么与AL相乘,乘积为16位,存入AX中:

1
2
3
4
Eg:
MOV AL,12H
MOV BL,34H
MUL BL ;AL*BL -> AX

​ 如果源操作数是字,则与AX相乘,乘积为32位,高16位存放在DX中,低16位存放在AX中:

1
2
3
4
Eg:
MOV AX,1200H
MOV BX,0034H
MUL BX ;AX*BX->(DX,AX)
  1. DIV

    DIV 源

    如果源操作数是字节,则16位的被除数必须存放在AX中;相除之后,8位的商在AL中,余数在AH中。

1
2
3
4
Eg:
MOV AX,1200H
MOV BL,34H
DIV BL ;AX/BL -> AL,AH

​ 如果源操作数是字,则32位被除数的高16位放在DX中,低16位放在AX中;相除之后,16位的商放在AX中,余数在DX中。

3. 逻辑运算指令

  1. NOT (全取反,相当于~)
1
2
MOV AL,10010011B 	;AL=10010011B
NOT AL ;AL=01101100B
  1. OR (相当于 |)
1
2
MOV AL,00001001B
OR AL,00110000B ;AL = 001111001B
  1. XOR(相当于^)

  2. AND(相当于&)

  3. TEST

    对两个操作数进行&操作,并修改标志位,但不回送结果

1
2
3
MOV  AL,1011 1001B
TEST AL,1000 0000B
JZ NEXT ;此处会跳到NEXT处,因为AL第8位是1

​ 该指令用于测试某位是否为1或0,通常与JZ、JNZ配合使用

4. 移位指令

  1. SAL 算术左移

    1
    2
    3
    MOV AL, 1110 0101B
    MOV CL, 2
    SAL AL, CL ;AL=1001 0100B
  2. SHL 逻辑左移

    1
    2
    MOV AL, 0011 1011B
    SHL AL,1 ;AL=0111 0110B
  3. SHR 逻辑右移(最高位补0)

  4. SAR 算术右移(最高位补符号位)

  5. 循环移位

image-20241224121044826

注意:如果移位的次数多于1,则应先把计数值放入CL中,如:

1
2
3
4
>MOV AL, 0000 0001B
>错误做法:SHL AL,3 ;error!
>正确做法:MOV CL,3
SHL AL,CL

5. 循环指令

  1. JMP 无条件转移指令

    格式:JMP DEST

    功能:使程序无条件地转移到指令中指定的目的地址去执行

    JA、JB 针对无符号数

    JG、JL 针对有符号数

  2. CALL

    • 调用时返回地址(CALL指令之后的那条指令的地址,也是当前IP寄存器的值)入堆栈

      1
      SP-2 -> SP	;IP入栈
  3. RET

    • 从堆栈弹出一个字给IP,并且SP+2->SP
  4. LOOP

    格式:LOOP 短标号

    • 循环的次数事先放在 CX 中
    • 每执行一次 LOOP 指令,CX 自动减1,直到 CX=0,循环结

3. 常错指令大汇总

  1. MOV DL, AX

    错误原因:AX 大小为 16 位,DL大小为 8 位

  2. MOV DS, 0200H

    错误原因:段寄存器不能直接加载立即数(牢记下图)

    image-20241224164313324
  3. MOV IP, 0FFH

    MOV [BX+SI+3],IP

    错误原因:IP寄存器不能出现在指令中,不能作为源操作数或目标操作数直接参与任何指令

  4. MOV [BX], [1200]

    错误原因:存储器内部不能相互传输数据

  5. MOV 8660H, AX

    错误原因:目的操作数不能是立即数

  6. MOV AX, [BX+BP]

    错误原因:BX和BP都是基址寄存器,不能同时组合使用

    同理有以下错误指令:

    MOV DL, [SI+DI]

    在8086中,有效地址计算的格式是:[基址寄存器 + 变址寄存器 + 偏移量]

    基址寄存器:BX,BP(BP比较特殊,默认与SS搭配)

    变址寄存器:SI,DI

  7. MOV AL, ES:[BP]

    该指令是正确的!BP默认与SS搭配,但是可以强制修改

    ps:ES:[BP] 在这里是一个8位的数据

    MOV AL,ES:[BP] ;从存储器中读8位

    MOV AX,ES:[BP] ;从存储器中读16位

    上面两条指令都是对的,这是因为在 8086 微处理器中,内存的数据宽度由指令中的目标寄存器或操作数指定,而不是由内存地址本身决定。内存地址(如 ES:[BP])只是一个位置,它并不包含关于数据大小的信息。指令的目标寄存器或操作数会明确告诉处理器需要从该内存位置读取多少位的数据

  8. MOV AX, OFFSET 0A20H

    错误原因:OFFSET 操作符只能用于标号或变量的地址,而不能直接对一个立即数(如 0A20H)使用

  9. MOV AL, OFFSET TABLE

​ 这条指令是对的,虽然偏移地址是16位的,但这条指令会将 TABLE 的偏移地址的 低 8 位 传输到 AL 中,而高 8 位将被丢弃。

  1. XCHG AL, 50H

​ 错误原因: XCHG 指令 不允许立即数参与操作

  1. IN BL, 05H

    错误原因:IN指令的目的操作数只能是AL/AX

    同理:OUT 05H,CX也不对,第二个操作数必须是累加器寄存器 AL 或 AX,表示将数据从累加器输出到指定端口

  2. OUT AL, 0FFEH

    错误原因1: 应该是OUT 0FFEH, AL

    错误原因2: 0FFEH太大,必须先存入DX中

  3. ADD [DI], [SI]

    错误原因:8086不允许两个内存操作数直接相加或相减

    修改方式:

    MOV AX, [SI]

    ADD [DI], AX

  4. PUSH 1000H

    错误原因:PUSH的源操作数不能是立即数