- https://blog.csdn.net/wxc971231/article/details/103767271
- 记录汇编语言课笔记,可能有不正确的地方,欢迎指出
- 教材《80X86微机原理及接口技术实验指导书》
- 这篇文章是书中部分软件实验代码的总结,可以用Tdpit 环境编译并运行在配套实验箱中(本文中给出的软件实验代码实际上不需要实验箱的硬件资源),这个环境支持比较标准的intel风格汇编,我估计在masm编译器中也能便宜运行。
- 下一篇文章将给出一些硬件实验的示例
- 后面我会发一些基于nasm编译器的全汇编代码,nasm也支持intel风格全汇编,但是在语法上稍微有点区别,将来发出来后可以和这里的代码对比看
- nasm和masm的区别
文章目录
一、软件实验
- 实验中所使用DOS 功能调用( INT 21H )说明如下
- 2号功能:显示单个字符输出
入口:AH=02H
调用参数:DL= 输出字符 - 9号功能:显示字符串
入口:AH=09H
调用参数:DS:DX= 串地址,’$’为结束字符 - 10号功能:键盘输入
入口:AH=0 A H
调用参数:DS:DX= 输入缓冲区地址, 首字节为缓冲区字节长度,第二字节为实际输入的字符计数 - 4ch号功能:返回 DOS 系统
入口:AH=4CH
调用参数:AL= 返回码
- 2号功能:显示单个字符输出
1. 四则运算
(1)实验要求
完成 32 位无符号数的加法、减法,16 位乘以 16 位,32 位除以 16 位除法的四则运算练习。
(2)原理提要
- 字节序
字节序分为大端模式(Big-Endian)和小端模式(Little-Endian),定义如下:- Little-Endian 就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
- Big-Endian 就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
例如:32bit 宽的数 0x12345678 在小端模式以及大端模式 CPU 内存中的存放方式(假
设从地址 0x4000 开始存放)为:
- x86架构是小端存储的,注意下面代码
A DW 1234H, 5678H ;被加数
,可以看到这一句定义了连续的两个字数据,数据地址按先后顺序由低到高排列,又因为每一个字在存储时按找小段存储规则,所以它在内存中的存储情况时34 12 78 56
,解释称十六进制数就是0x56781234
(3)代码示例
DATA SEGMENT
A DW 1234H, 5678H ;被加数 32位数分两个16位存 56781234H
B DW 0FEDCH, 123AH 加数 32位数分两个16位存 FEDC123AH
C DW 2 DUP (?) ;预留和 留两个双字(16位)空间存加法结果
AD DW 0FEDCH, 0BA98H;被减数 BA98FEDCH
BD DW 1234H, 789AH ;减数 789A1234H
CD DW 2 DUP (?) ;预留差
A1 DW 0D678H ;被乘数
B1 DW 0012H ;乘数
C1 DW 2 DUP (?) ;预留积
A2 DW 5678H, 0234H ;被除数 02345678
B2 DW 0F234H ;除数 F234
C2 DW 2 DUP (?) ;预留商,余数
DATA ENDS
STACK1 SEGMENT STACK
;DB 100 DUP(?)
buffer db 100 dup(0)
STACK1 ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK1
START PROC FAR
;标准序
PUSH DS
MOV AX, 0
PUSH AX
MOV AX, DATA
MOV DS, AX
;32位+32位 结果68B31110H
MOV AX, A
ADD AX, B
MOV C, AX ;低16位加完存在C,进位在CF
MOV AX, A+2
ADC AX, B+2 ;ADC带进位加,处理高16位,存在C+2
MOV C+2, AX
;32位-32位 结果41FEECA8H
MOV AX, AD
SUB AX, BD
MOV CD, AX
MOV AX, AD+2
SBB AX, BD+2
MOV CD+2, AX
;16位乘16位 结果000F1470H
MOV AX, A1
MOV BX, B1
MUL BX
MOV C1, AX
MOV C1+2, DX
;32位除16位 结果254H..7568H
MOV DX, A2+2
MOV AX, A2
MOV BX, B2
DIV BX
MOV C2, AX ;商在AX
MOV C2+2, DX ;余数在DX
RET
START ENDP
CODE ENDS
END START
- 在emu8086中运行并查看内存,可以观察到计算结果
2. 数据统计
(1)实验任务
- 本实验要求通过求某数据区内负数的个数来表现循环程序的结构形式。要求实验程序在数据段
中存放一组数据,分类统计数据中正数、负数和零的个数,并分别存入内存变量 Positive、Negative
和 Zero 中。将所有数据累加求和,存入 SUM 中。
(2)参考代码
- 主要逻辑代码
;宏函数,输出回车
CRLF MACRO
MOV DL, 0DH
MOV AH, 02H ;INT21的2号功能(单个字符输出)
INT 21H
MOV DL, 0AH
MOV AH, 02H
INT 21H ;连续输出0DH和0AH,显示回车
ENDM
DATA SEGMENT
NUM DB 12H,88H,82H,89H,33H,90H,0H,10H,0BDH,01H ;10个8位数据
Positive DB DUP (0) ;正数个数 4
Negative DB DUP (0) ;负数个数 5
Zero DB DUP (0) ;0个数 1
SUM DW 2 DUP (0) ;总和
MESP DB 'Positive number:$'
MESN DB 'Negative number:$'
MESZ DB 'Zero number:$'
MESS DB 'Sum = $'
result DB 0,0,'$'
DATA ENDS
STACK1 SEGMENT STACK
;DB 100 DUP(?)
buffer db 100 dup(0)
STACK1 ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK1 ;设置段寄存器
START PROC FAR
PUSH DS
MOV AX, 0
PUSH AX
MOV AX, DATA
MOV DS, AX
MOV CX,10 ;循环10次
LEA SI,NUM
MOV BX,0
LAB1:
MOV DL,[SI]
CMP DL,0 ;判断num是否为0
JG LAB2 ;num>0,跳转到LAB2
JL LAB3 ;num<0,跳转到LAB3
INC ZERO ;num=0,ZERO加1
JMP LAB4
LAB2:
INC Positive ;负数+1
JMP LAB4
LAB3:
INC Negative ;正数+1
LAB4:
MOV AL,[SI]
CBW ;符号拓展,8位拓展为16位
ADD SUM,AX ;+sum
ADC [SUM+2],0
INC SI
LOOP LAB1 ;循环
RET
START ENDP
CODE ENDS
END START
- 观察内存:
- 显示部分代码 (利用int 21h的9号功能)
MOV DX,OFFSET MESP ;显示“Positive number:”提示
MOV AH,9
INT 21H
MOV BL,Positive ;取字节变量positive
MOV AL,BL
SHR AL,4
CALL ToASCII ;把高四位转换为对应的ASCII码
MOV [result],AL
MOV AL,BL
CALL ToASCII ;把低四位转换为对应的ASCII码
MOV [result+1],AL
MOV DX,OFFSET result
MOV AH,9
INT 21H
ToASCII PROC
AND AL,0FH
ADD AL,'0'
CMP AL,'9'
JBE LAB5
ADD AL,7
LAB5:
RET
ToASCII ENDP
3. 代码转换
(1)实验任务
- 从键盘输入小写字母(最多 20 个),以 “.”号作为结束标志, 将其变换成相应的大写字母输岀
在屏幕上。
(2)原理提要
- 输入小写字母用 INT 21 的 0AH 号功能,将读入的数据存放在缓冲区 SMALL 中,其中 SMALL
的笫一个字节指岀缓冲区能容纳的字节数,不能为 0(程序暂定为 50),第二个字节保留,以用作存放
实际键入的输入字符的个数;从笫三个字节开始存放从键盘上输入字符的 ASCII 码,所以转换时要
从 SMALL 的笫三个字节,即 SMALL+2 开始。 - SMALL 中存放的是小写字母的 ASSII 码,将此值减去 20H,即为大写字母的 ASSII 码,将其依次
存放在名为 CAPITAL 的数据段中,然后用 INT 21 中的 09H 功能输出。
(3)参考代码
CRLF MACRO
MOV DL, 0DH
MOV AH, 02H ;INT21的2号功能(单个字符输出)
INT 21H
MOV DL, 0AH
MOV AH, 02H
INT 21H ;连续输出0DH和0AH,显示回车
ENDM
DATA SEGMENT
MES1 DB 'PLEASE INPUT THE SMALL LETTER,ENDED WITH ".":$'
MES2 DB 'THE CAPTAL LETTER IS:$'
SMALL DB 50 ; 预留键盘输入缓冲区长度为50个
DB 0 ; 预留实际键盘输入字符数的个数
DB 50 DUP(0) ; 存放输入符号串的位置
CAPITAL DB 50 DUP(0) ; 预留大写字母缓冲区长度为50个
DATA ENDS
STACK1 SEGMENT STACK
DB 100 DUP (0)
STACK1 ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK1
START PROC FAR
PUSH DS
MOV AX, 0
PUSH AX
MOV AX, DATA
MOV DS, AX ;数据段DS指向DATA
MOV AH, 9 ;INT21的9号功能(输出)
LEA DX, MES1 ;输出信息位置
INT 21H ;输岀提示信息MES1
CRLF ;宏调用,输出回车
MOV AH, 0AH ;INT21的10号功能(输入)
LEA DX, SMALL ;输入信息缓存位置
;INC DX
INT 21H ;接收小写字符串
CRLF ;宏调用,输出回车
;转换部分利用INT21的10号功能得到的字符串长度实现,没有考虑超长问题
;LEA SI,SMALL
;LEA DI,CAPITAL
;XOR CH,CH ;CL中存储循环次数,注意最后输入的.不算
;MOV CL,[SI+1]
;ADD SI,2 ;指向真正输入数据
;DEC CL
;LOOPSIGN: ;循环cx次,把小写字符转大写存入CAPITAL
;MOV AL,[SI]
;SUB AL,20H
;MOV [DI],AL
;INC DI
;INC SI
;LOOP LOOPSIGN
;转换时利用句号判断终止时机,进行了长度限制,比上面那个好
LEA BX, SMALL+2
LEA DI, CAPITAL
MOV CX, 20 ;最多20个字符
LAB:
MOV AL, [BX]
CMP AL, 2EH ;是否遇到句号.
JE KE
SUB AL, 20H ;转为大写,ASCLL-20H
MOV [DI], AL
INC BX
INC DI
LOOP LAB
KE:
MOV AL, '$' ;大写字符串后加“$”
MOV [DI], AL
MOV DX, OFFSET MES2 ;输岀提示信息MES2
MOV AH, 9
INT 21H
CRLF ;宏调用,输出回车
MOV DX, OFFSET CAPITAL
MOV AH, 9 ;输岀大写字符串
INT 21H
RET
START ENDP
CODE ENDS
END START
- 软件部分代码到此结束,下一篇文章给出一些硬件实验相关的代码