清空电脑装系统前备份以前文档,汇编的精简学习

# 汇编语言超详细中文文档,
### 核心大纲。计算机基本组成 :CPU、内存、I/O设备的关系,汇编语言本质 :人类可读的机器指令助记符,寄存器概念 :CPU内部的超高速存储单元内存模型 :段地址+偏移地址的寻址方式

# 2023年6月 · 元歌 · 广州软件公司捉鱼学习笔记
## 📌 文档说明
- **创建时间**: 2023年6月
- **作者**: 元歌(广州软件公司)
- **用途**: 捉鱼学习笔记,专为零基础新手打造
学习以下需要的环境, 1. **编辑器**: - 推荐:VS Code(免费)+ 汇编插件 - 备选:Notepad++、Sublime Text 2. **汇编器**: - MASM 6.11(经典版本) - NASM(跨平台推荐) 3. **运行环境**: - DOSBox(模拟DOS环境,Windows 10/11必备) - 或:VMware + MS-DOS 6.22虚拟机 ### 安装步骤(Windows 10/11) ```bash # 1. 安装DOSBox 下载地址:https://www.dosbox.com/download.php 默认安装即可 # 2. 配置工作目录 在D盘创建文件夹:D:\asm_workspace 将汇编文件(.asm)放在这里 # 3. 挂载目录到DOSBox 打开DOSBox,输入: mount c d:\asm_workspace c:

 

以上当时我是随便做的笔记,最近硬盘空间不哆,可能要重做系统,所以备份一些以前的文档。

; 示例:计算1+2并存储结果
mov ax, 1        ; 将立即数1传送到AX寄存器(AX=1)
mov bx, 2        ; 将立即数2传送到BX寄存器(BX=2)
add ax, bx       ; 将AX和BX相加,结果存回AX(AX=AX+BX=3)
mov [0x100], ax  ; 将结果3存储到内存地址DS:0100处

  编写程序计算1到10的和并存储到内存:示例二

mov cx, 10       ; 循环计数器设为10
mov ax, 0        ; 累加器清零
mov bx, 1        ; 从1开始加

sum_loop:        ; 循环标签
    add ax, bx   ; 累加当前数字
    inc bx       ; BX自增1(bx=bx+1)
    loop sum_loop ; CX减1,不为0则继续循环
    
mov [0x200], ax  ; 存储结果55到内存

  示例三     ## 寄存器(CPU工作原理)

#          ## 2.1 通用寄存器(对应视频006-007) 核心大纲

- AX累加器 :算术运算主力寄存器
- BX基址寄存器 :常用于内存寻址
- CX计数器 :循环和字符串操作专用
- DX数据寄存器 :I/O操作和乘除法辅助

; 演示寄存器的基本操作
mov ax, 0x1234   ; AX=0x1234(16位立即数)
mov ah, 0x56     ; AX高8位=0x56,此时AX=0x5634
mov al, 0x78     ; AX低8位=0x78,此时AX=0x5678

xchg ax, bx      ; AX和BX交换内容(交换后AX=原BX,BX=原AX)
push ax          ; 将AX压入堆栈(SP=SP-2,[SP]=AX)
pop bx           ; 从堆栈弹出到BX(BX=[SP],SP=SP+2)

  

### 段寄存器与内存访问(对应视频008-010) 核心大纲
- CS代码段 :存储程序指令
- DS数据段 :存储程序数据
- SS堆栈段 :存储函数调用和临时数据
- ES附加段 :字符串操作的额外数据段

; 演示各种内存寻址方式
mov bx, 0x0100   ; BX作为基址寄存器
mov si, 0x0020   ; SI作为变址寄存器

mov ax, [0x1234] ; 直接寻址:从DS:1234读取数据
mov ax, [bx]     ; 间接寻址:从DS:0100读取数据
mov ax, [bx+10]  ; 相对寻址:从DS:0110读取数据(0100+0x0A)
mov ax, [bx+si]  ; 基址变址:从DS:0120读取数据(0100+0020)
mov ax, [bx+si+5]; 相对基址变址:从DS:0125读取数据

  

## 寄存器(内存访问)
### 3.1 内存寻址方式(对应视频013-015) 核心大纲
- 直接寻址 :[偏移地址]
- 寄存器间接寻址 :[BX]
- 寄存器相对寻址 :[BX+偏移量]
- 基址变址寻址 :[BX+SI]

; 演示各种内存寻址方式
mov bx, 0x0100   ; BX作为基址寄存器
mov si, 0x0020   ; SI作为变址寄存器

mov ax, [0x1234] ; 直接寻址:从DS:1234读取数据
mov ax, [bx]     ; 间接寻址:从DS:0100读取数据
mov ax, [bx+10]  ; 相对寻址:从DS:0110读取数据(0100+0x0A)
mov ax, [bx+si]  ; 基址变址:从DS:0120读取数据(0100+0020)
mov ax, [bx+si+5]; 相对基址变址:从DS:0125读取数据

  

### 堆栈操作(对应视频016-019) 核心大纲
- PUSH/POP :后进先出的数据存储
- CALL/RET :函数调用的核心机制
- BP寄存器 :栈帧基址指针

mov ax, 0x1000   ; 设置堆栈段地址
mov ss, ax
mov sp, 0xFFFE   ; 设置栈顶(堆栈向下增长)

push ax          ; 将AX压栈:SP=SP-2=0xFFFC,[0xFFFC]=AX
push bx          ; SP=0xFFFA,[0xFFFA]=BX
pop cx           ; CX=[0xFFFA],SP=0xFFFC
pop dx           ; DX=[0xFFFC],SP=0xFFFE

; 使用BP访问栈中数据
mov bp, sp       ; BP指向当前栈顶
mov ax, [bp+2]   ; 访问压入的第一个数据(原AX值)

  实战一    
- 段定义 :代码段、数据段、堆栈段
- 程序入口 :end start指定程序起点
- DOS中断 :程序退出的21h中断

; 完整的第一个汇编程序
assume cs:code, ds:data, ss:stack  ; 告诉汇编器各段与寄存器的对应关系

data segment                       ; 定义数据段
    msg db 'Hello, World!', '$'    ; 定义字符串,$是DOS字符串结束符
    num dw 1234h                  ; 定义16位数据
ends

stack segment stack               ; 定义堆栈段
    dw 128 dup(0)                ; 预留128个字的空间
ends

code segment                    ; 定义代码段
start:                          ; 程序入口标签
    mov ax, data                ; 加载数据段地址
    mov ds, ax                  ; 设置DS寄存器
    
    mov ah, 09h                 ; DOS功能号:显示字符串
    lea dx, msg                 ; DX指向字符串
    int 21h                     ; 调用DOS中断显示字符串
    
    mov ah, 4ch                 ; DOS功能号:程序结束
    int 21h                     ; 返回DOS
ends
end start                       ; 程序结束,指定入口点

  

## [BX]和loop指令
### 5.1 循环结构实现(对应视频023-028) 核心大纲
- LOOP指令 :CX寄存器自动递减的循环
- [BX]寻址 :灵活的内存访问方式
- 数组处理 :批量数据处理技巧

; 使用LOOP指令实现数组求和
data segment
    arr db 1,2,3,4,5,6,7,8,9,10  ; 定义10个字节的数组
    sum dw 0                     ; 存储累加结果
ends

code segment
assume cs:code, ds:data
start:
    mov ax, data
    mov ds, ax
    
    mov cx, 10                  ; 循环次数=数组长度
    mov bx, 0                   ; BX作为数组索引
    mov ax, 0                   ; AX存储累加结果
    
sum_loop:                    ; 循环开始
    add al, arr[bx]            ; 将数组元素加到AL
    adc ah, 0                  ; 处理进位
    inc bx                     ; 索引递增
    loop sum_loop              ; CX减1,不为0则继续
    
    mov sum, ax                ; 存储最终结果
    
    mov ah, 4ch
    int 21h
ends
end start

 多重循环实现

; 双重循环实现冒泡排序
sort_array proc near
    push cx                    ; 保存寄存器
    push si
    push di
    
    mov cx, 9                 ; 外层循环9次(10个元素)
outer_loop:
    mov si, cx                ; 保存外层循环计数器
    mov di, 0                 ; 内层循环索引
    mov cx, si                ; 内层循环次数=外层剩余次数
    
inner_loop:
    mov al, arr[di]          ; 加载当前元素
    mov bl, arr[di+1]        ; 加载下一个元素
    cmp al, bl               ; 比较两个元素
    jbe no_swap              ; 如果有序则跳过交换
    
    ; 交换两个元素
    mov arr[di], bl
    mov arr[di+1], al
    
no_swap:
    inc di                   ; 索引递增
    loop inner_loop          ; 内层循环
    
    mov cx, si               ; 恢复外层循环计数器
    loop outer_loop          ; 外层循环
    
    pop di                   ; 恢复寄存器
    pop si
    pop cx
    ret
sort_array endp

  

## 包含多个段的程序
### 6.1 复杂程序结构(对应视频029-031) 核心大纲
- 段间数据访问 :跨段数据处理
- 段的重叠 :灵活的内存布局
- 大型程序组织 :模块化设计思想

; 多段程序示例:学生成绩管理系统
datas segment                    ; 数据段1:学生信息
    names db 'Tom',0,'Ann',0,'Bob',0  ; 学生姓名
    scores db 85,92,78               ; 对应成绩
    count equ 3                      ; 学生数量
ends

datas2 segment                   ; 数据段2:统计结果
    total dw 0                     ; 总分
    average db 0                 ; 平均分
ends

stack segment stack              ; 堆栈段
    dw 256 dup(0)                ; 512字节堆栈空间
ends

code segment
assume cs:code, ds:datas, es:datas2, ss:stack

start:
    mov ax, datas               ; 加载数据段1
    mov ds, ax
    mov ax, datas2              ; 加载数据段2
    mov es, ax
    
    ; 计算总分
    mov cx, count               ; 学生数量
    mov si, 0                   ; 成绩索引
    mov ax, 0                   ; 累加器清零
    
calc_total:
    add al, scores[si]         ; 累加成绩
    adc ah, 0                  ; 处理进位
    inc si                     ; 下一个成绩
    loop calc_total
    
    mov es:total, ax           ; 存储到另一个段
    
    ; 计算平均分
    mov bl, count              ; 除数=学生数量
    div bl                     ; AX/BL,商在AL,余数在AH
    mov es:average, al         ; 存储平均分
    
    mov ah, 4ch
    int 21h
ends
end start

  

## 更灵活定位内存地址
### 7.1 寻址方式综合运用(对应视频032-037) 核心大纲
- and/or指令 :位操作基础
- ASCII码处理 :字符数据操作
- [bx+idata]寻址 :更灵活的地址计算

; 字符串大小写转换程序
data segment
    str db 'Hello ASM World!',0  ; 待转换字符串
    len equ $-str-1              ; 字符串长度(不含0)
ends

code segment
assume cs:code, ds:data
start:
    mov ax, data
    mov ds, ax
    
    mov cx, len                  ; 循环次数=字符串长度
    mov bx, 0                    ; 字符串索引
    
convert_loop:
    mov al, str[bx]             ; 加载字符
    cmp al, 'a'                 ; 判断是否小写字母
    jb not_lower                ; 小于'a'则跳过
    cmp al, 'z'                 ; 判断是否小写字母
    ja not_lower                ; 大于'z'则跳过
    
    ; 小写转大写:AND 0xDF(清第5位)
    and al, 0xDF                ; 小写转大写
    mov str[bx], al             ; 存回字符串
    
not_lower:
    inc bx                      ; 下一个字符
    loop convert_loop
    
    mov ah, 4ch
    int 21h
ends
end start

  附列二

; 3x4矩阵转置程序
data segment
    matrix db 1,2,3,4           ; 原始矩阵3行4列
           db 5,6,7,8
           db 9,10,11,12
    rows equ 3                  ; 行数
    cols equ 4                  ; 列数
    result db 12 dup(0)        ; 转置结果4行3列
ends

code segment
assume cs:code, ds:data
start:
    mov ax, data
    mov ds, ax
    
    mov si, 0                  ; 源矩阵索引
    mov di, 0                  ; 目标矩阵索引
    mov cx, rows               ; 外层循环=原矩阵行数
    
row_loop:
    push cx                    ; 保存外层计数器
    mov cx, cols               ; 内层循环=原矩阵列数
    mov di, 0                  ; 重置目标列索引
    
col_loop:
    mov al, matrix[si]        ; 加载源矩阵元素
    
    ; 计算转置位置:result[col*rows+row]
    mov bl, cl                ; 当前列号
    dec bl                    ; 调整为0基
    mov ah, rows              ; 每列元素数=原行数
    mul ah                    ; AX=col*rows
    add al, ch                ; 加上当前行号
    mov bx, ax                ; BX=目标索引
    
    mov result[bx], al        ; 存储到转置位置
    
    inc si                    ; 源矩阵下一个元素
    loop col_loop
    
    pop cx                    ; 恢复外层计数器
    loop row_loop
    
    mov ah, 4ch
    int 21h
ends
end start

  

## 数据处理的两个基本问题
### 8.1 数据位置与长度(对应视频038-041) 核心大纲
- 立即数寻址 :数据在指令中
- 寄存器寻址 :数据在寄存器中
- 内存寻址 :数据在内存中
- 数据长度指定 :byte ptr/word ptr

; 演示各种数据位置的处理
mov al, 100                 ; 立即数:100直接编码在指令中
mov ax, bx                  ; 寄存器:数据在BX寄存器中
mov al, [0x100]            ; 内存:数据在内存地址DS:0100处

; 明确指定数据长度
mov byte ptr [0x200], 0x55 ; 明确指定按字节操作
mov word ptr [0x200], 0x1234 ; 明确指定按字操作

; 不同长度的数据处理
mov al, byte ptr [0x100]   ; 从内存读取1字节
mov ax, word ptr [0x100]   ; 从内存读取2字节(0x100和0x101)

  

 其它例子

; 学生结构体数组处理
data segment
    student struct           ; 定义学生结构体
        id db 0              ; 学号1字节
        name db 'ABC',0      ; 姓名4字节(含结束符)
        score dw 0           ; 成绩2字节
    student ends
    
    ; 创建3个学生的结构体数组
    students student 3 dup(<>)
        ; 初始化数据
        db 1,'Tom',0,0,0,85
        db 2,'Ann',0,0,0,92
        db 3,'Bob',0,0,0,78
ends

code segment
assume cs:code, ds:data
start:
    mov ax, data
    mov ds, ax
    
    ; 计算学生总数
    mov cx, 3                  ; 学生数量
    mov bx, 0                  ; 结构体索引
    mov si, 0                  ; 结构体内偏移
    
calc_average:
    mov al, students[bx].score ; 加载学生成绩
    mov ah, 0                  ; 扩展为16位
    add total, ax              ; 累加到总分
    
    add bx, sizeof student     ; 下一个结构体
    loop calc_average
    
    ; 计算平均分
    mov ax, total
    mov bl, 3
    div bl                     ; AL=平均分
    
    mov ah, 4ch
    int 21h
ends
end start

  

## 转移指令的原理
### 9.1 条件转移指令(对应视频043-046) 核心大纲
- 标志位判断 :ZF、CF、SF、OF的含义
- 无符号比较 :JA/JB/JE等指令
- 有符号比较 :JG/JL/JE等指令

; 成绩等级判断程序
data segment
    score db 85                ; 测试成绩
    grade db 0                 ; 存储等级A/B/C/D/F
ends

code segment
assume cs:code, ds:data
start:
    mov ax, data
    mov ds, ax
    
    mov al, score              ; 加载成绩
    cmp al, 90                 ; 与90比较
    jae grade_a                ; >=90跳转到A级
    
    cmp al, 80                 ; 与80比较
    jae grade_b                ; >=80跳转到B级
    
    cmp al, 70                 ; 与70比较
    jae grade_c                ; >=70跳转到C级
    
    cmp al, 60                 ; 与60比较
    jae grade_d                ; >=60跳转到D级
    
    mov grade, 'F'             ; 否则为F级
    jmp done
    
grade_a:
    mov grade, 'A'
    jmp done
    
grade_b:
    mov grade, 'B'
    jmp done
    
grade_c:
    mov grade, 'C'
    jmp done
    
grade_d:
    mov grade, 'D'
    
done:
    mov ah, 4ch
    int 21h
ends
end start

  

## CALL和RET指令
### 10.1 子程序设计(对应视频048-053) 核心大纲
- CALL调用 :保存返回地址并跳转
- RET返回 :从堆栈恢复返回地址
- 参数传递 :寄存器/堆栈/内存传递方式

; 子程序示例:计算阶乘
stack segment stack
    dw 256 dup(0)
ends

data segment
    n db 5                     ; 计算5的阶乘
    result dw 0                ; 存储结果
ends

code segment
assume cs:code, ds:data, ss:stack

; 阶乘子程序:输入AL=n,输出AX=n!
factorial proc near
    push bp                   ; 保存旧的BP
    mov bp, sp                ; 建立栈帧
    push cx                   ; 保存使用的寄存器
    
    mov cx, ax                ; CX=循环计数器=n
    mov ax, 1                 ; AX=累乘结果=1
    
fact_loop:
    mul cx                    ; AX=AX*CX
    loop fact_loop            ; CX减1,不为0继续
    
    pop cx                    ; 恢复寄存器
    pop bp                    ; 恢复BP
    ret                       ; 返回调用点
factorial endp

start:
    mov ax, data
    mov ds, ax
    mov ax, stack
    mov ss, ax
    mov sp, 256
    
    mov al, n                 ; 加载参数n
    mov ah, 0                 ; 扩展为16位
    call factorial            ; 调用阶乘子程序
    
    mov result, ax            ; 保存结果(5! = 120)
    
    mov ah, 4ch
    int 21h
ends
end start

  

## 标志寄存器
### 11.1 标志位详解(对应视频054-059) 核心大纲
- 状态标志 :ZF、CF、SF、OF、PF、AF
- 控制标志 :DF、IF、TF
- 标志位操作 :LAHF/SAHF、PUSHF/POPF

; 标志位操作演示
data segment
    a dw 0x7FFF                ; 最大正数
    b dw 1                     ; 加1会溢出
    flags dw 0                 ; 存储标志位
ends

code segment
assume cs:code, ds:data
start:
    mov ax, data
    mov ds, ax
    
    ; 演示溢出标志OF
    mov ax, a                  ; AX=0x7FFF(32767)
    add ax, b                  ; 0x7FFF+1=0x8000(-32768)产生溢出
    pushf                      ; 将标志寄存器压栈
    pop bx                     ; BX=标志寄存器值
    mov flags, bx              ; 存储标志位
    
    ; 检查各标志位
    test bx, 0x8000            ; 检查SF(符号位)
    jnz negative               ; 结果为负
    
    test bx, 0x0040            ; 检查ZF(零标志)
    jz not_zero                ; 结果不为零
    
    test bx, 0x0001            ; 检查CF(进位标志)
    jnc no_carry               ; 无进位
    
negative:
    ; 处理负数结果
    jmp done
    
not_zero:
    ; 处理非零结果
    jmp done
    
no_carry:
    ; 处理无进位情况
    
done:
    mov ah, 4ch
    int 21h
ends
end start

  

## 内中断
### 12.1 中断处理机制(对应视频060-063) 核心大纲
- 中断向量表 :0000:0000开始的256个中断入口
- 中断过程 :CPU自动保存现场并跳转
- IRET指令 :中断返回

; 自定义除零中断处理程序
data segment
    msg db 'Division by zero!', '$'
ends

code segment
assume cs:code, ds:data

; 自定义中断处理程序
div_zero_handler proc far
    push ax
    push dx
    push ds
    
    mov ax, data
    mov ds, ax
    
    ; 显示错误信息
    mov ah, 09h
    lea dx, msg
    int 21h
    
    pop ds
    pop dx
    pop ax
    iret                        ; 中断返回
endp

start:
    ; 这里只是概念演示,实际设置中断向量需要修改中断向量表
    mov ah, 4ch
    int 21h
ends
end start

  

## INT指令
### 13.1 BIOS/DOS中断调用(对应视频064-066) 核心大纲
- INT 21h :DOS系统调用
- INT 10h :BIOS显示服务
- INT 16h :BIOS键盘服务

 

; 使用BIOS显示字符串
stack segment stack
    dw 256 dup(0)
ends

data segment
    str db 'Hello BIOS!', 0Dh, 0Ah, '$'  ; 字符串含回车换行
ends

code segment
assume cs:code, ds:data, ss:stack

start:
    mov ax, data
    mov ds, ax
    mov ax, stack
    mov ss, ax
    mov sp, 256
    
    ; 设置光标位置(第5行第10列)
    mov ah, 02h                ; BIOS功能:设置光标
    mov bh, 0                  ; 显示页号0
    mov dh, 5                  ; 行号5
    mov dl, 10                 ; 列号10
    int 10h                    ; 调用BIOS
    
    ; 显示字符串
    mov ah, 09h                ; DOS功能:显示字符串
    lea dx, str                ; DX指向字符串
    int 21h                    ; 调用DOS
    
    ; 等待按键
    mov ah, 00h                ; BIOS功能:读取键盘
    int 16h                    ; 等待按键
    
    mov ah, 4ch
    int 21h
ends
end start

  

## 端口  核心大纲
- IN/OUT指令 :CPU与硬件设备通信
- 端口地址 :00h-FFh的256个端口
- 设备控制 :通过端口控制外设

; 演示端口操作(概念性,实际硬件相关)
; 控制PC扬声器发声

code segment
assume cs:code

start:
    ; 设置扬声器频率(概念演示)
    mov al, 0xB6              ; 控制字:选择计数器2,方波模式
    out 0x43, al              ; 发送到控制端口43h
    
    mov ax, 1193              ; 1000Hz频率(1193180/1000)
    out 0x42, al              ; 发送低8位到端口42h
    mov al, ah
    out 0x42, al              ; 发送高8位到端口42h
    
    ; 打开扬声器
    in al, 0x61               ; 读取端口61h当前值
    or al, 0x03               ; 设置位0和位1(开启扬声器)
    out 0x61, al              ; 写回端口61h
    
    ; 延时(简单循环)
    mov cx, 0xFFFF
delay:
    loop delay
    
    ; 关闭扬声器
    in al, 0x61
    and al, 0xFC              ; 清除位0和位1
    out 0x61, al
    
    mov ah, 4ch
    int 21h
ends
end start

  

## 外中断  核心大纲
- 可屏蔽中断 :由IF标志控制
- 非屏蔽中断 :NMI,优先级最高
- 中断控制器 :8259A可编程中断控制器

; 键盘中断处理示例(概念性)
code segment
assume cs:code

; 键盘中断处理程序(IRQ1,中断号09h)
keyboard_handler proc far
    push ax
    push bx
    
    in al, 0x60               ; 从键盘端口读取扫描码
    
    ; 处理扫描码(这里只是存储)
    mov bl, al                ; 保存扫描码
    
    ; 发送EOI(中断结束)给8259A
    mov al, 0x20
    out 0x20, al
    
    pop bx
    pop ax
    iret
endp

start:
    ; 中断处理程序的安装需要修改中断向量表
    ; 这里只是概念演示
    
    mov ah, 4ch
    int 21h
ends
end start

  

## 直接定址表
查表法应用 - 查表法 :用空间换时间的算法    - 地址表 :函数指针数组
- 跳转表 :实现多分支选择

; 星期显示程序:使用查表法
stack segment stack
    dw 256 dup(0)
ends

data segment
    weekday db 3               ; 星期三(0=周日,6=周六)
    
    ; 星期字符串表
    week_table dw offset sun, offset mon, offset tue
                dw offset wed, offset thu, offset fri, offset sat
    
    sun db 'Sunday$',0
    mon db 'Monday$',0
    tue db 'Tuesday$',0
    wed db 'Wednesday$',0
    thu db 'Thursday$',0
    fri db 'Friday$',0
    sat db 'Saturday$',0
ends

code segment
assume cs:code, ds:data, ss:stack

start:
    mov ax, data
    mov ds, ax
    mov ax, stack
    mov ss, ax
    mov sp, 256
    
    mov al, weekday            ; 加载星期索引
    mov ah, 0                  ; 清零高8位
    shl ax, 1                  ; 乘以2(字偏移)
    mov bx, ax                 ; BX=偏移量
    
    mov ax, week_table[bx]     ; 从地址表获取字符串偏移
    mov dx, ax                 ; DX=字符串地址
    
    mov ah, 09h                ; 显示字符串
    int 21h
    
    mov ah, 4ch
    int 21h
ends
end start

  

## 使用BIOS进行键盘输入和磁盘读写
### 17.1 键盘输入处理(对应视频075-077) 核心大纲
- INT 16h :键盘BIOS中断
- 扫描码与ASCII码 :键盘输入的双重编码
- 磁盘读写 :INT 13h磁盘服务

 

; 完整键盘输入和文件操作示例
stack segment stack
    dw 256 dup(0)
ends

data segment
    filename db 'test.txt',0   ; 文件名
    buffer db 512 dup(0)      ; 读写缓冲区
    key_msg db 'Press any key...$',0
ends

code segment
assume cs:code, ds:data, ss:stack

start:
    mov ax, data
    mov ds, ax
    mov ax, stack
    mov ss, ax
    mov sp, 256
    
    ; 显示提示信息
    mov ah, 09h
    lea dx, key_msg
    int 21h
    
    ; 等待按键
    mov ah, 00h               ; BIOS功能:读取键盘
    int 16h                   ; AL=ASCII码,AH=扫描码
    
    ; 显示按下的键
    mov dl, al                ; DL=ASCII字符
    mov ah, 02h               ; DOS功能:显示字符
    int 21h
    
    ; 磁盘操作示例(概念性)
    ; 实际文件操作需使用DOS INT 21h的文件功能
    
    mov ah, 4ch
    int 21h
ends
end start

  

### 简易计算器 项目要求
实现一个支持加减乘除的命令行计算器

; 简易计算器:支持+ - * /
stack segment stack
    dw 256 dup(0)
ends

data segment
    prompt db 'Enter expression (e.g., 5+3): $'
    result_msg db 13,10,'Result: $'
    num1 dw 0                ; 第一个操作数
    num2 dw 0                ; 第二个操作数
    op db 0                  ; 运算符
    buffer db 10 dup(0)      ; 输入缓冲区
ends

code segment
assume cs:code, ds:data, ss:stack

; 数字输入子程序:将ASCII数字转为二进制
decimal_input proc near
    push bx
    push cx
    push dx
    
    xor ax, ax              ; AX=结果
    xor cx, cx              ; CX=数字计数
    
input_loop:
    mov ah, 01h             ; DOS功能:读取字符并回显
    int 21h
    cmp al, 13              ; 回车结束
    je input_done
    
    cmp al, '0'             ; 检查是否为数字
    jb input_done
    cmp al, '9'
    ja input_done
    
    sub al, '0'             ; ASCII转数字
    mov bl, al
    mov ax, cx              ; 当前结果*10
    mov dx, 10
    mul dx
    add ax, bx              ; 加上新数字
    mov cx, ax
    jmp input_loop
    
input_done:
    mov ax, cx              ; 返回结果
    pop dx
    pop cx
    pop bx
    ret
decimal_input endp

; 显示结果子程序:二进制转ASCII显示
display_result proc near
    push bx
    push cx
    push dx
    
    mov cx, 0               ; 数字位数计数
    mov bx, 10              ; 除数
    
convert_loop:
    xor dx, dx              ; DX清零
    div bx                  ; AX/10,余数在DX
    push dx                 ; 保存余数
    inc cx                  ; 位数+1
    cmp ax, 0
    jne convert_loop
    
    ; 显示数字
show_loop:
    pop dx                  ; 取出数字
    add dl, '0'             ; 转为ASCII
    mov ah, 02h             ; 显示字符
    int 21h
    loop show_loop
    
    pop dx
    pop cx
    pop bx
    ret
display_result endp

start:
    mov ax, data
    mov ds, ax
    mov ax, stack
    mov ss, ax
    mov sp, 256
    
    ; 显示提示
    mov ah, 09h
    lea dx, prompt
    int 21h
    
    ; 输入第一个数字
    call decimal_input
    mov num1, ax
    
    ; 输入运算符
    mov ah, 01h
    int 21h
    mov op, al
    
    ; 输入第二个数字
    call decimal_input
    mov num2, ax
    
    ; 执行运算
    mov ax, num1
    mov bx, num2
    
    cmp op, '+'
    je do_add
    cmp op, '-'
    je do_sub
    cmp op, '*'
    je do_mul
    cmp op, '/'
    je do_div
    jmp done
    
do_add:
    add ax, bx
    jmp show_result
    
do_sub:
    sub ax, bx
    jmp show_result
    
do_mul:
    mul bx                    ; AX*BX,结果在DX:AX
    jmp show_result
    
do_div:
    xor dx, dx                ; DX清零
    div bx                    ; DX:AX/BX,商在AX
    
show_result:
    push ax                   ; 保存结果
    
    ; 显示结果标签
    mov ah, 09h
    lea dx, result_msg
    int 21h
    
    pop ax                    ; 恢复结果
    call display_result
    
done:
    mov ah, 4ch
    int 21h
ends
end start

  当是钞的笔记,如果有空的话我们应写一个对应的c   来参考学习,,

 

posted @ 2025-08-02 18:02  谢双元小号  阅读(14)  评论(0)    收藏  举报