我要开始啦!bulabulabulabulabula.
例题
物理地址=DS*16+有效地址
1.直接寻址
2.直接寻址(允许符号代替数值,变量存的地址)
3.基址寻址(16位:用寄存器SI、DI、BX、BP存的有效地址)
下面是寄存器间接寻址👇
(1)16位
(2)32位
除ESP和EBP默认段寄存器为SS外,其余6个通用寄存器均默认段寄存器为DS
下面是基址寻址👇
4.基址加变址寻址
变址寻址就是带了变址寄存器(如SI、DI),默认DS为段基址寄存器。
基址加变址寻址就是带了基址寄存器+变址寄存器
5.基址变址相对寻址
为什么是基址?因为有效地址放在寄存器里了,BP
为什么是变址?因为有变址寄存器,SI
为什么是相对??
段基址用SS,因为基址寄存器用的BP
已懵圈。
1.段寄存器不能直接赋立即数
2.内存之间不能直接传输数据
3.LEA的目标必须是寄存器
4.PUSH必须16/31,可以扩展AL到AX
5.MUL只有一个操作数
首先,咱们要知道一个指令大概长这样:助记符 目标操作数,源操作数
然后我们检查操作数数量、操作数类型、操作数大小
MUL是单操作数;MOV是俩
操作数类型是否允许组合?寄存器、内存、立即数
PUSH不能是8位
1.
MOV AX,SEG VAR0
MOV DS,AX
2.
MOV CL,4
SAL BX,CL
是把BX左移四位
逻辑左移SHL
算数左移SAL
移位次数置于CL中
3.
CMP DX, 0 ; 比较DX和0
JGE POSITIVE ; 如果DX ≥ 0,跳到POSITIVE
NEG DX ; 否则对DX取负
POSITIVE:
CMP DX,0
JGE SKIP
NEG DX
SKIP:
4.
TEST AX, 3 ; 检查最后2位是否为0
JZ LAB0 ; 如果结果为0(能被4整除),跳转到LAB0
AND AX, 3
CMP AX, 0
JE LAB0
如果能被四整除,后两位一定是00。
3的二进制是11,如果AX与11AND的结果是00,那么AX一定能被4整除
AND结果写到AX里,进行比较JE(JE和JZ一样,结果为0跳转)
5.
MOV DI, 2025 ; 设置目标地址(DI=2025)
MOV CX, 100 ; 设置计数器(CX=100)
MOV AL, 0 ; 要存储的值(AL=0)
CLD ; 清除方向标志(DF=0,地址递增)
REP STOSB ; 重复执行: [ES:DI]←AL, DI←DI+1
"DI当快递员,CX记件数,AL带零蛋,CLD向前冲,REP自动干"
MOV DI, 2025 ; 快递员站在2025号仓库(起始地址)
MOV CX, 100 ; 今天要送100个包裹(计数器)
MOV AL, 0 ; 每个包裹里是数字0(要存储的值)
CLD ; 设定方向:向前走(DF=0,地址递增)
REP STOSB ; 开始自动送货!; 动作分解:; 1. 把AL的0放进[DI]仓库; 2. DI向前走1步(+1); 3. CX减1(剩余包裹数); 重复直到CX=0
MOV SI, 2025 ; 起始地址
MOV CX, 100 ; 计数器
MOV AL, 0 ; 清零值
CLEAR_LOOP:MOV [SI], AL ; 清零当前字节INC SI ; 地址+1LOOP CLEAR_LOOP ; CX减1,若CX≠0则循环
MOV SI, 2025 ; 把SI寄存器当作"指针",指向内存地址2025(就像C语言的 int *p=2025)
MOV CX, 100 ; CX是计数器,表示要清零100个字节(像 for(int i=100; i>0; i--))
MOV AL, 0 ; AL是8位寄存器,存要写入的值0(像 char zero=0)CLEAR_LOOP: ; 循环开始标签(像 while(true){ )MOV [SI], AL ; 把0写入SI指向的内存位置(像 *p = zero)INC SI ; 指针SI向后移动1字节(像 p++)LOOP CLEAR_LOOP ; CX减1,如果CX≠0就跳回循环开始(像 if(--i>0) goto loop)
; 假设在数据段已定义100字节的零缓冲区ZERO_BUFFER
MOV SI, OFFSET ZERO_BUFFER ; 源地址(全零)
MOV DI, 2025 ; 目标地址
MOV CX, 100 ; 字节数
CLD
REP MOVSB ; 复制零到目标区域
ORG(origin)设置起始地址为150H
DUP是复读机
X4那行,连续存了三个,第一个是1234H,第二个是当前地址(0160H)-20?最后一个是(0162H)+25?
$地址
-106=96H | 85=55H |
DW低字节=E9 | DW高字节=07 |
D的ascii=44 | o的ascii=6F |
u=75 | b=62 |
l=6C | e=65 |
34=22H | -69=BBH |
34=22H | -69=BBH |
1234H低字节=34H | 1234H高字节=12H |
-20低字节=4CH | -20高字节=01H |
+25低字节=8BH?好像不太对 | +25高字节=01H |
"DB放字节,DW存字;
负数转补码,字符串ASCII;
DUP是复制,$是当前位置;
小端记心间,地址逐个加!"
DATA SEGMENTARRAY DB 23, 5, 17, 3, 8, 12 ; 定义无符号字节数组(示例数据)LEN EQU $-ARRAY ; 计算数组长度RESULT DW ? ; 存放结果的字变量
DATA ENDSCODE SEGMENTASSUME CS:CODE, DS:DATA
START:MOV AX, DATAMOV DS, AX ; 设置DS指向数据段; 初始化:假设前两个元素是最小的MOV AL, ARRAY[0] ; AL = 第一个数MOV BL, ARRAY[1] ; BL = 第二个数; 确保AL <= BL(交换使AL存最小值,BL存次小值)CMP AL, BLJBE NO_SWAP ; 如果AL <= BL,不交换XCHG AL, BL ; 否则交换AL和BL
NO_SWAP:; 遍历数组剩余元素(从第3个开始)MOV CX, LEN - 2 ; 循环次数 = 数组长度 - 2MOV SI, 2 ; 数组索引从2开始
FIND_MIN:MOV DL, ARRAY[SI] ; 取出当前元素; 比较当前元素与最小值ALCMP DL, ALJAE CHECK_SECOND ; 如果DL >= AL,检查是否比BL小; 更新最小值和次小值MOV BL, AL ; 原最小值变成次小值MOV AL, DL ; DL成为新的最小值JMP NEXT_ITERCHECK_SECOND:CMP DL, BLJAE NEXT_ITER ; 如果DL >= BL,跳过MOV BL, DL ; 否则更新次小值NEXT_ITER:INC SI ; 移动到下一个元素LOOP FIND_MIN ; 循环处理; 计算和并存入RESULTXOR AH, AH ; 清空AH(AL是无符号字节)ADD AL, BL ; AL = AL + BLADC AH, 0 ; 处理可能的进位(和>255时)MOV RESULT, AX ; 保存结果到RESULTMOV AH, 4CHINT 21H ; 程序结束
CODE ENDS
END START
DATA SEGMENTBUFFER DB 201 DUP(?) ; 输入缓冲区(200字符+1回车)X1 DB 0 ; 大写字母计数器X2 DB 0 ; 小写字母计数器X3 DB 0 ; 数字计数器X4 DB 0 ; 其他字符计数器MSG DB 'Input a string: $'
DATA ENDSCODE SEGMENTASSUME CS:CODE, DS:DATA
START:MOV AX, DATAMOV DS, AX ; 设置DS指向数据段; 显示提示信息MOV AH, 09HLEA DX, MSGINT 21H; 从键盘读取字符串MOV AH, 0AHLEA DX, BUFFERMOV BUFFER, 200 ; 设置最大长度INT 21H; 统计字符LEA SI, BUFFER + 2 ; SI指向实际输入的字符串首地址MOV CL, BUFFER + 1 ; CL=实际输入字符数MOV CH, 0 ; CX=字符数JCXZ DONE ; 如果输入为空则跳过COUNT_LOOP:MOV AL, [SI] ; 取当前字符; 检查大写字母(A-Z)CMP AL, 'A'JB NOT_UPPERCMP AL, 'Z'JA NOT_UPPERINC X1JMP NEXT_CHARNOT_UPPER:; 检查小写字母(a-z)CMP AL, 'a'JB NOT_LOWERCMP AL, 'z'JA NOT_LOWERINC X2JMP NEXT_CHARNOT_LOWER:; 检查数字(0-9)CMP AL, '0'JB OTHERCMP AL, '9'JA OTHERINC X3JMP NEXT_CHAROTHER:INC X4 ; 其他字符计数NEXT_CHAR:INC SI ; 指向下一个字符LOOP COUNT_LOOP ; CX减1,循环直到CX=0DONE:MOV AH, 4CHINT 21H ; 程序结束
CODE ENDS
END START
一、数组求和中断程序
; 数据段定义
DATA SEGMENTARRAY DW -100, 200, -50, 300, 150 ; 定义带符号字数组LEN EQU ($-ARRAY)/2 ; 计算数组长度RESULT DD ? ; 保存结果的变量
DATA ENDS; 代码段
CODE SEGMENTASSUME CS:CODE, DS:DATA; 主程序MAIN PROC FARMOV AX, DATAMOV DS, AX; 设置中断向量(假设INT 63H中断向量已指向SUM服务程序)MOV BX, OFFSET ARRAY ; 数组起始地址MOV CX, LEN ; 数组长度INT 63H ; 调用中断服务程序; 保存结果MOV WORD PTR RESULT, AX ; 低16位MOV WORD PTR RESULT+2, DX ; 高16位MOV AH, 4CHINT 21HMAIN ENDP; 中断服务程序SUMSUM PROC FARPUSH SIPUSH DIPUSH CXXOR AX, AX ; 清空AX(低16位)XOR DX, DX ; 清空DX(高16位)MOV SI, BX ; 数组起始地址SUM_LOOP:MOV DI, [SI] ; 取数组元素ADD SI, 2 ; 指向下一个元素; 带符号数累加CMP DI, 0JGE POSITIVE; 负数处理NEG DISUB AX, DISBB DX, 0JMP NEXTPOSITIVE:ADD AX, DIADC DX, 0NEXT:LOOP SUM_LOOPPOP CXPOP DIPOP SIIRETSUM ENDP
CODE ENDS
END MAIN
二、8259A初始化程序
; 主片8259A初始化 (端口320H,321H)
MOV AL, 00010001b ; ICW1: 边沿触发,级联,需要ICW4
OUT 320H, ALMOV AL, 00011000b ; ICW2: 中断类型号18H-1FH
OUT 321H, ALMOV AL, 00000100b ; ICW3: 从片连接在IR5
OUT 321H, ALMOV AL, 00011101b ; ICW4: 特殊完全嵌套,缓冲,非自动EOI
OUT 321H, AL; 第一个从片8259A初始化 (端口322H,323H)
MOV AL, 00010001b ; ICW1: 边沿触发,级联,需要ICW4
OUT 322H, ALMOV AL, 10000000b ; ICW2: 中断类型号80H-87H
OUT 323H, ALMOV AL, 00000101b ; ICW3: 从片ID=5(连接主片IR5)
OUT 323H, ALMOV AL, 00001001b ; ICW4: 非特殊完全嵌套,缓冲,非自动EOI
OUT 323H, AL; 第二个从片8259A初始化 (端口324H,325H)
MOV AL, 00010001b ; ICW1: 边沿触发,级联,需要ICW4
OUT 324H, ALMOV AL, 10001000b ; ICW2: 中断类型号88H-8FH
OUT 325H, ALMOV AL, 00000101b ; ICW3: 从片ID=5(连接主片IR5)
OUT 325H, ALMOV AL, 00001001b ; ICW4: 非特殊完全嵌套,缓冲,非自动EOI
OUT 325H, AL
三、
四、8254计数器初始化
; 计数器0初始化(方式2,二进制计数,初值216)
MOV AL, 00110100b ; 控制字: 00计数器,先低后高字节,方式2,二进制
OUT 7F3H, AL
MOV AL, 216 ; 计数初值低字节
OUT 7F0H, AL
MOV AL, 0 ; 计数初值高字节
OUT 7F0H, AL; 计数器1初始化(方式0,BCD计数,初值7500)
MOV AL, 01110001b ; 控制字: 01计数器,先低后高字节,方式0,BCD
OUT 7F3H, AL
MOV AL, 00H ; 计数初值低字节(7500的BCD码: 7500H)
OUT 7F1H, AL
MOV AL, 75H ; 计数初值高字节
OUT 7F1H, AL; 计数器2初始化(方式3,二进制计数,初值35FFH)
MOV AL, 10110110b ; 控制字: 10计数器,先低后高字节,方式3,二进制
OUT 7F3H, AL
MOV AL, 0FFH ; 计数初值低字节
OUT 7F2H, AL
MOV AL, 35H ; 计数初值高字节
OUT 7F2H, AL; 读取计数器2当前值
MOV AL, 10000000b ; 控制字: 锁存计数器2当前值
OUT 7F3H, AL
IN AL, 7F2H ; 读低字节
MOV AH, AL
IN AL, 7F2H ; 读高字节
XCHG AH, AL ; 调整字节顺序
MOV COUNT, AX ; 保存到COUNT变量
五、8237A初始化程序
; 8237A初始化
; 先发送主清除命令
MOV AL, 0
OUT 0A00DH, AL ; 主清除命令; 设置命令寄存器
MOV AL, 00000000b ; 正常时序,固定优先级,正常写,DREQ高有效,DACK高有效
OUT 0A008H, AL; 设置模式寄存器(通道1,单字节传输,读传输,自动预置禁止)
MOV AL, 01001001b ; 通道1,模式49H
OUT 0A00BH, AL; 设置地址寄存器(低16位)
MOV AX, OFFSET BUFF
OUT 0A002H, AL ; 低字节
MOV AL, AH
OUT 0A002H, AL ; 高字节; 设置地址寄存器(高4位,页面寄存器)
MOV AL, SEG BUFF ; 取段地址
AND AL, 0FH ; 取高4位
OUT 0A083H, AL ; 通道1页面寄存器(A000H+83H); 设置字节计数器
MOV AX, 1500 ; 传输字节数
DEC AX ; 8237A计数为n-1
OUT 0A003H, AL ; 低字节
MOV AL, AH
OUT 0A003H, AL ; 高字节; 清除屏蔽位,启动DMA
MOV AL, 00000001b ; 屏蔽寄存器: 仅通道1非屏蔽
OUT 0A00FH, AL
复习
首先就是补码、ASCII码,有一个计算题用到。比如负数要补码,也就是二进制取反加1;比如字母直接ASCII。
CPU引脚这里应该是CPU引脚功能(地址线、数据线)??
物理地址、逻辑地址、有效地址。
物理地址就是CPU最终访问内存单元的实际地址(20位,00000H~FFFFFH)
计算公式:物理地址=段地址(segment)*16+偏移地址(offset)
逻辑地址就是程序员在汇编语言中使用的地址形式,由段地址:偏移地址组成(如DS:SI)
物理地址的计算公式好像也是这样
有效地址(EA)是偏移地址的计算结果,用于确定操作数在段内的位置,由基址寄存器(BX/BP)+变址寄存器(SI/DI)+位移量(dispplacement)
计算方式:EA=[BX/BP]+[SI/DI]+8/16位位移量,还是有了DS段地址然后公式计算物理地址
段寄存器(CS, DS, ES, SS)与偏移量寄存器(IP, SI, DI, SP, BP)的对应关系
段寄存器 | 主要用途 | 默认偏移量寄存器 | 典型应用场景 |
CS | 代码段(Code Segment) | IP(指令指针) | 取指令(CS:IP指向下一条指令) |
DS | 数据段(Data Segment) | BX/SI/DI | 访问数据(如MOV AX,[BX]) |
ES | 附加段(Extra Segment) | DI(串操作目标) | 串操作(如MOVSB使用DS:SI->ES:DI) |
SS | 堆栈段(Stack Segment) | SP/BP | 堆栈操作(如PUSH AX使用SS:SP) |
寻址方式会看,弄明白源操作数和目标操作数的寻址方式
指令集👇
判断指令的对错
mov d,s两个操作数什么情况下可以赋值👇
两个操作数位数相等、目标操作数必须能重写,x86不能直接从内存到内存(需通过寄存器中转)
各种指令的错误使用👇
1.操作数类型不匹,mov ax,bl(bl是8位,ax是16位)
2.立即数不能直接赋值给段寄存器,要通过中间寄存器中转
3.不能内存到内存
4.特权指令不能乱用
5.错误的栈操作
太多了这也。。。
debug里的调试指令?
各类伪指令?
dos中断(中断向量表)?
断点?
现场?
中断的整个过程?
外部中断:可屏蔽,不可屏蔽
内部中断:异常,陷阱
8259A?
8255A? 8254/8253? 8237A?