post on 21 May 2025 about 6722words require 23min
CC BY 4.0 (除特别声明或转载文章外)
如果这篇博客帮助到你,可以请我喝一杯咖啡~
参考博客
把数据段中 1 维数组 AA_1 变量地址中连续 7 个数(1,3,5,7,2,4,6)读出,把每个数加 2 后再存入到数据段中 BB_1 数组开始的标号地址中去,并显示出 BB_1 数组中每个数来(之间用空格分开)
DATA SEGMENT
ORG 0100H
AA_1 DB 1,3,5,7,2,4,6
ORG 0150H
BB_1 DB 7 dup(?)
COUNT DW 7 _;给7设置别名_
DATA ENDS
CSEG SEGMENT
ASSUME CS: CSEG,DS:DATA
START:MOV AX, DATA
MOV DS, AX
MOV CX, COUNT
LEA SI, AA_1 _;取偏移地址(或者使用offset) _
LEA DI, BB_1
LP1: MOV AL, [SI] _;寄存器间接寻址方式可以改成相对寻址方式 _
ADD AL,2
MOV [DI], AL
INC SI _;SI+1 _
INC DI _;DI+1 _
LOOP LP1 _;不是0就转到标号LP1_
LEA SI, BB_1
MOV CX, COUNT
DISP: MOV DL, [SI]
ADD DL, 30H
MOV AH,02 _;显示输出(要背下来)_
INT 21H
MOV DL,' ' _;每显示输出一个数后,输出一个空格 _
MOV AH,2
INT 21H
INC SI
LOOP DISP
MOV AH,4CH
INT 21H
CSEG ENDS
END START
从键盘接收一个小写字母,然后找出它的前导字符和后续字符,再按顺序显示这三个字符。
CSEG SEGMENT
ASSUME CS:CSEG
ORG 100H
START:
; 从键盘接收一个小写字母
MOV AH,1
INT 21H
MOV DL,AL
DEC DL
; 设置循环次数
MOV CX,3 ; 设置循环次数
LOOP1:
; 检查输入是否为小写字母
CMP DL,'a'
JB EXIT ; 小于'a'就退出
CMP DL,'z'
JA EXIT ; 大于'z'就退出
MOV AH,2
INT 21H
ADD DL,1
LOOP LOOP1 ; CX减1,若不为0则跳转到LOOP1继续循环
EXIT:
MOV AH,4CH
INT 21H
CSEG ENDS
END START
在 x86 汇编中,MOV AH, 02H
指令将立即数 02H 存入 AH 寄存器。在 DOS 中断服务程序中,这个值有特殊含义:将 AH 设置为 02H 是为了调用 DOS 的 2 号功能 - 显示字符输出功能。
当执行 INT 21H
中断调用时,系统会根据 AH 中的值来确定要执行的 DOS 功能。02H 功能会将 DL 寄存器中的 ASCII 字符显示到标准输出设备(通常是屏幕)上。
指令 ADD DL, 30H
的作用是将 DL 寄存器中的数值转换为对应的 ASCII 码字符。
具体来说:
在这个程序中,由于 BB_1 数组中存储的是加 2 后的数值(3,5,7,9,4,6,8),需要将这些数值转换为 ASCII 码才能正确显示,否则会显示为不可见的控制字符。
注意:这种转换方法只适用于单个十进制数字(0-9)。对于大于 9 的数字,这种简单的加 30H 方法会产生错误的字符。
参考程序中使用的是基于寄存器间接寻址方式(使用 SI 作为指针)来访问 AA_1 数组元素。除此之外,还可以使用以下方式:
MOV AL, AA_1[0] ; 访问第一个元素
MOV AL, AA_1[1] ; 访问第二个元素
MOV BX, OFFSET AA_1
MOV AL, [BX] ; 访问第一个元素
MOV AL, [BX+1] ; 访问第二个元素
MOV SI, 0
MOV AL, AA_1[SI] ; 访问第一个元素
INC SI
MOV AL, AA_1[SI] ; 访问第二个元素
MOV BX, OFFSET AA_1
MOV SI, 0
MOV AL, [BX+SI] ; 访问第一个元素
INC SI
MOV AL, [BX+SI] ; 访问第二个元素
MOV BX, OFFSET AA_1
MOV SI, 1
MOV AL, [BX+SI-1] ; 访问第一个元素
MOV AL, [BX+SI] ; 访问第二个元素
已知 DATAX 和 DATAY 单元各存放一个带符号字节数据,从键盘上接收加(+)、减(-)、乘(*)或除(/)符号,然后完成相应运算,把结果显示在屏幕上。
DATA SEGMENT
num DB -6 _; 8位有符号数_
buf DB 4 DUP(?) _; 最多3位+1_
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX
MOV AL, num _; 取数_
CBW _; 符号扩展到AX_
CMP AL, 0
JGE PRINT_DEC _; 如果是正数,直接打印_
NEG AL _; 取绝对值_
CBW
PRINT_DEC:
_; AX中为正数,转十进制_
MOV SI, 0
MOV BX, 10
CONV_LOOP:
XOR DX, DX
DIV BX _; AX / 10, 商->AX, 余数->DX_
ADD DL, '0'
MOV buf[SI], DL
INC SI
CMP AX, 0
JNZ CONV_LOOP
PRINT_LOOP:
DEC SI
MOV DL, buf[SI]
MOV AH, 2
INT 21H
CMP SI, 0
JNZ PRINT_LOOP
MOV AH, 4CH
INT 21H
CODE ENDS
END START
DATA SEGMENT
DATAX DB 6 _; 带符号字节数据,负数_
DATAY DB -2 _; 带符号字节数据,正数_
RESULT DB 0
BUF DB 4 DUP(?)
DATA ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
_;从键盘接收+,-,*,/_
MOV AH,1
INT 21H
CMP AL,'+'
JE ADD_OP
CMP AL,'-'
JE SUB_OP
CMP AL,'*'
JE MUL_OP
CMP AL,'/'
JE DIV_OP
ADD_OP:
MOV AL,DATAX
MOV BL,DATAY
ADD AL,BL
MOV RESULT,AL
JMP SHOW_RESULT
SUB_OP:
MOV AL,DATAX
MOV BL,DATAY
SUB AL,BL
MOV RESULT,AL
JMP SHOW_RESULT
MUL_OP:
_; 字节乘法: _
_; (AL)*(OPS8)→AX_
MOV AL,DATAX
MOV BL,DATAY
IMUL BL
MOV RESULT,AL
JMP SHOW_RESULT
DIV_OP:
MOV AL,DATAX
MOV BL,DATAY
CBW _;将AL符号扩展到AX_
IDIV BL
MOV RESULT,AL
JMP SHOW_RESULT
_;难点在打印,将每次除以10,把余数入栈,然后出栈,打印_
SHOW_RESULT:
MOV AL, RESULT
CBW
CMP AL, 0
JGE SHOW
PUSH AX _; 保存原始AL_
MOV DL, '-'
MOV AH, 2
INT 21H
POP AX _; 恢复AL_
NEG AL
CBW
SHOW:
MOV SI,0 _; SI为BUF索引_
MOV BX,10
CONV_LOOP:
MOV DX,0
DIV BX
ADD DL,'0'
MOV BUF[SI],DL
INC SI
CMP AX,0
JNZ CONV_LOOP
PRINT_LOOP:
DEC SI
MOV DL,BUF[SI]
MOV AH,2
INT 21H
CMP SI,0
JNZ PRINT_LOOP
JMP EXIT
EXIT:
MOV AH,4CH
INT 21H
CSEG ENDS
END START
注意事项
_; 简单计算器程序 - 对DATAX和DATAY中的有符号字节数据进行四则运算_
_; 支持加(+)、减(-)、乘(*)、除(/)四种运算符_
.MODEL SMALL
.STACK 100H
.DATA
DATAX DB ? _; 第一个操作数_
DATAY DB ? _; 第二个操作数_
MSG1 DB 'Input first number: $'
MSG2 DB 0DH, 0AH, 'Input second number: $'
MSG3 DB 0DH, 0AH, 'Input operator (+, -, *, /): $'
MSG4 DB 0DH, 0AH, 'Result: $'
MSG5 DB 0DH, 0AH, 'Division by zero! $'
TEMP DW ? _; 临时存储乘法或除法结果_
NEG_FLAG DB 0 _; 负数标志 (1表示结果为负)_
BUF DB 6 DUP(?) _; 用于存储结果字符串_
NEG_INPUT DB 0 _; 输入负号标志_
VALUE DB 0 _; 输入值_
.CODE
MAIN PROC
MOV AX, @DATA _; 初始化数据段_
MOV DS, AX
_; 显示第一条提示消息_
LEA DX, MSG1
MOV AH, 09H
INT 21H
_; 输入第一个数字_
CALL INPUT_SIGNED_BYTE
MOV DATAX, AL
_; 显示第二条提示消息_
LEA DX, MSG2
MOV AH, 09H
INT 21H
_; 输入第二个数字_
CALL INPUT_SIGNED_BYTE
MOV DATAY, AL
_; 显示操作符提示消息_
LEA DX, MSG3
MOV AH, 09H
INT 21H
_; 输入操作符_
MOV AH, 01H
INT 21H
MOV BL, AL _; 保存操作符在BL中_
_; 显示结果提示消息_
LEA DX, MSG4
MOV AH, 09H
INT 21H
_; 根据操作符执行相应运算_
CMP BL, '+' _; 检查是否为加法_
JE DO_ADD
CMP BL, '-' _; 检查是否为减法_
JE DO_SUB
CMP BL, '*' _; 检查是否为乘法_
JE DO_MUL
CMP BL, '/' _; 检查是否为除法_
JE DO_DIV
JMP EXIT _; 如果不是有效操作符,直接退出_
DO_ADD:
MOV AL, DATAX _; 加法运算_
ADD AL, DATAY
JMP DISPLAY_RESULT
DO_SUB:
MOV AL, DATAX _; 减法运算_
SUB AL, DATAY
JMP DISPLAY_RESULT
DO_MUL:
MOV AL, DATAX _; 乘法运算_
MOV BL, DATAY
CALL SIGNED_MUL
JMP DISPLAY_AX
DO_DIV:
MOV AL, DATAX _; 除法运算_
MOV BL, DATAY
CALL SIGNED_DIV
JMP DISPLAY_AX
DISPLAY_RESULT:
_; 结果在AL中,转换为字符串并显示_
MOV AH, 0 _; 清零AH,结果扩展到AX_
CMP AL, 0
JGE POSITIVE
NEG AL _; 如果为负,取绝对值_
MOV NEG_FLAG, 1 _; 设置负数标志_
JMP CONTINUE
POSITIVE:
MOV NEG_FLAG, 0 _; 清除负数标志_
CONTINUE:
MOV AX, AX _; AX中现在是结果的绝对值_
DISPLAY_AX:
_; 显示AX中的有符号结果_
CALL DISPLAY_SIGNED_NUM
EXIT:
_; 程序结束_
MOV AH, 4CH
INT 21H
MAIN ENDP
_; 输入有符号字节的过程_
INPUT_SIGNED_BYTE PROC
_; 检查第一个字符是否为负号_
MOV AH, 01H
INT 21H
CMP AL, '-'
JNE CHECK_DIGIT1
MOV NEG_INPUT, 1 _; 设置负号标志_
MOV AH, 01H _; 再次读取一个字符_
INT 21H
CHECK_DIGIT1:
_; 检查输入字符是否为数字_
CMP AL, '0'
JL EXIT_INPUT _; 如果小于'0',不是数字_
CMP AL, '9'
JG EXIT_INPUT _; 如果大于'9',不是数字_
_; 转换为数值并保存_
SUB AL, '0'
MOV VALUE, AL
_; 读取可能存在的第二个数字_
MOV AH, 01H
INT 21H
_; 检查第二个字符是否为数字_
CMP AL, '0'
JL EXIT_INPUT2 _; 如果小于'0',不是数字_
CMP AL, '9'
JG EXIT_INPUT2 _; 如果大于'9',不是数字_
_; 处理第二个数字_
SUB AL, '0'
MOV BL, VALUE _; 将第一个数字移到BL_
MOV BH, 0 _; 清零BH_
MOV CX, 10
MUL CX _; 将BX乘以10_
ADD BL, AL _; 加上第二个数字_
MOV VALUE, BL
JMP EXIT_INPUT
EXIT_INPUT2:
_; 如果第二个字符不是数字,将它放回缓冲区(模拟未读取)_
MOV DL, AL
MOV AH, 02H
INT 21H
EXIT_INPUT:
_; 返回结果_
MOV AL, VALUE
CMP NEG_INPUT, 1
JNE RETURN_INPUT
NEG AL _; 如果有负号标志,取负值_
RETURN_INPUT:
RET
INPUT_SIGNED_BYTE ENDP
_; 有符号乘法过程 - 结果在AX中_
SIGNED_MUL PROC
_; 保存符号_
MOV CL, AL _; 保存第一个操作数_
MOV CH, BL _; 保存第二个操作数_
_; 取绝对值_
CMP AL, 0
JGE ABS1_DONE
NEG AL
ABS1_DONE:
CMP BL, 0
JGE ABS2_DONE
NEG BL
ABS2_DONE:
_; 执行无符号乘法_
MUL BL _; AX = AL * BL_
_; 确定结果符号_
MOV BH, 0 _; 清零BH_
MOV BL, 0 _; 假设结果为正_
CMP CL, 0 _; 检查第一个操作数符号_
JGE CHECK_OP2_MUL
XOR BL, 1 _; 翻转符号位_
CHECK_OP2_MUL:
CMP CH, 0 _; 检查第二个操作数符号_
JGE APPLY_SIGN_MUL
XOR BL, 1 _; 翻转符号位_
APPLY_SIGN_MUL:
CMP BL, 1 _; 检查是否需要取负_
JNE RETURN_MUL
NEG AX _; 对结果取负_
RETURN_MUL:
RET
SIGNED_MUL ENDP
_; 有符号除法过程 - 结果在AX中_
SIGNED_DIV PROC
_; 检查除数是否为零_
CMP BL, 0
JNE NOT_ZERO_DIV
_; 除数为零处理_
LEA DX, MSG5 _; 显示除零错误消息_
MOV AH, 09H
INT 21H
MOV AX, 0 _; 返回0_
RET
NOT_ZERO_DIV:
_; 保存符号_
MOV CL, AL _; 保存第一个操作数_
MOV CH, BL _; 保存第二个操作数_
_; 取绝对值_
CMP AL, 0
JGE ABS1_DIV_DONE
NEG AL
ABS1_DIV_DONE:
CMP BL, 0
JGE ABS2_DIV_DONE
NEG BL
ABS2_DIV_DONE:
_; 执行无符号除法_
MOV AH, 0 _; 扩展AL到AX_
DIV BL _; AL = AX / BL, AH = AX % BL_
MOV AH, 0 _; 清零AH(我们只关心商)_
_; 确定结果符号_
MOV BH, 0 _; 清零BH_
MOV BL, 0 _; 假设结果为正_
CMP CL, 0 _; 检查第一个操作数符号_
JGE CHECK_OP2_DIV
XOR BL, 1 _; 翻转符号位_
CHECK_OP2_DIV:
CMP CH, 0 _; 检查第二个操作数符号_
JGE APPLY_SIGN_DIV
XOR BL, 1 _; 翻转符号位_
APPLY_SIGN_DIV:
CMP BL, 1 _; 检查是否需要取负_
JNE RETURN_DIV
NEG AX _; 对结果取负_
RETURN_DIV:
RET
SIGNED_DIV ENDP
_; 显示有符号数字_
DISPLAY_SIGNED_NUM PROC
_; 检查符号_
CMP AX, 0
JGE POS_NUM
_; 显示负号_
MOV DL, '-'
MOV AH, 02H
INT 21H
NEG AX _; 取绝对值_
POS_NUM:
_; 将数字转换为字符串并显示_
MOV CX, 0 _; 初始化计数器_
MOV BX, 10 _; 基数(十进制)_
_; 将数字转换为字符串(逆序)_
CONVERT_LOOP:
MOV DX, 0 _; 清零DX_
DIV BX _; AX / 10, 商在AX,余数在DX_
PUSH DX _; 保存余数_
INC CX _; 增加计数器_
CMP AX, 0 _; 检查商是否为0_
JNE CONVERT_LOOP _; 如果不是0,继续转换_
_; 显示字符串(正序)_
DISPLAY_LOOP:
POP DX _; 取出一个数字_
ADD DL, '0' _; 转换为ASCII_
MOV AH, 02H _; 显示字符功能_
INT 21H
LOOP DISPLAY_LOOP _; 循环直到所有数字显示完毕_
RET
DISPLAY_SIGNED_NUM ENDP
END MAIN
Related posts