一、课程设计(综合实验)的目的与要求
    通过本门课程的学习与实践,学生可以加深对汇编语言程序设计课程的理解与掌握,有助于提高学生的汇编语言程序设计能力,同时可以加深对计算机工作原理的理解,有助于促进后续课程的学习。
    本课程要求学生针对课本所学知识从调试程序、循环程序设计、分支程序设计、子程序设计(选做:键盘输入程序设计、中断练习程序)等部分学习实践,使学生对汇编语言有更深入细致和全面的了解,并能用所学知识解决实际问题,每个实验的具体要求如下:
    各个实验要求有设计说明,对有实现要求的程序画出程序流程图,然后根据流程图编写程序,并上机调试写出运行结果。
    二、设计(实验)正文
    实验二 用表格形式显示ASCII字符SMASCII
    (1)
    设计思路(包括程序的原理,算法及数据结构等)
    用栈保存数据外层循环次数,dl作为数据存储 ASCII 码,内外双层循环,用内层循环实现行的输出,外层循环进行换行。
    显示每个字符:可使用功能号为02的显示输出功能调用,使用方法如下:
    mov ah, 02h;
    mov dl,输出字符的ASCII码
    int 21h
    在显示空白或回车、换行符前用指令push dx把dl的内容保存到堆栈中去。在显示空白或回车、换行符后用指令pop dx恢复dl寄存器的原始内容。
    本实验中可把dl初始化为10H,然后不断加1(用INC指令)以取得下一个字符的ASCII码。

    (2)程序框图(画出程序主要部分流程图)
    image.png
    (2)
    程序实现(注意:不用写出整体程序,写出部分关键代码即可,代码后要求用文字描述代码完成的功能)
    (3)
    部分代码:
    (4)
    mov dx, 0000H
    (5)
    mov dl, 10H ;从ASCII码为10H的字符开始显示
    (6)
    mov cx, 000FH ;设置外循环的次数15,即要显示的行数
    (7)
    mov ax, 0000H
    (8)
    r:
    (9)
    mov ah, 02H ;设置显示方式
    (10)
    push cx ;保存外循环次数的计数
    (11)
    mov cx, 0010H ;设置内循环次数16,即一行16个字符
    (12)
    c:
    (13)
    int 21H
    (14)
    push dx ;保存dx的值
    (15)
    mov dl, 00H ;输出空格
    (16)
    int 21H
    (17)

    (18)
    pop dx ;恢复dx的值,并加1,产生下一个ASCII字符
    (19)
    inc dx
    (20)
    loop c
    (21)
    ;已经进行完了一次内循环
    (22)
    pop cx ;恢复外循环次数的计数
    (23)
    push dx ;保存dx的值
    (24)

    (25)
    mov dl, 0dH ;输出回车换行
    (26)
    int 21H
    (27)
    mov dl, 0aH
    (28)
    int 21H
    (29)

    (30)
    pop dx ;恢复dx的值
    (31)

    (32)
    loop r
    代码是循环输出部分,每一次进入内循环的时候压栈保存外循环即行数的数据。等待进行输出 ASCII 码的字符完成之后再恢复并递减
    在内循环中,需要保护的是 dx 的值,即 ASCII 码输出到哪一个部分。在输入空格和字符之间,压栈dx数据保存,同时推栈之后加1作为下一个字符。
    (4)实验结果(实验的运行结果)
    image.png
    实验三:分类统计字符的个数
    (1)设计思路
    首先程序可采用01H功能调用把键入字符后先分类计数再存入缓冲区中,0AH功能调用把键入字符直接送到缓冲区中,然后再逐个取出分类计数。
    设置三个标志分别为letter,digit和other,并初始化为0,当接收到字符时,按照ASCII表比较,30h-39h为数字,61-7A,41-5A为字母,其余放在other。每收到一个字母, 经判断后的相应类型标志+1。最后输出三个标志位表示相应类型的数量。
    输出结束要转为两位数字的十进制数,AX/BL,AL=商,AH=余数,保存AX中的信息,分别输出十位数字和个位数字。
    (2)程序框图
    image.png
    (3)程序实现
    首先是判断的主程序
    main proc far
    start:
    push ds
    mov ax,0h
    push ax
    mov ax,datas ;初始化ds
    mov ds,ax

    ;输入一行的提示 ‘input a line:’
    lea dx,input
    mov ah,9 ; 09h 输出到屏幕一串
    int 21h

    ;输入一行字符
    lea dx,line_max_length
    mov ah,10 ; 16进制为 0ah ,接受一串键盘输入
    int 21h ; DOS 调用,根据 ah 中的数据 选择不同的功能

    ;对输入的一行字符进行统计 cx 存储 字符串长度
    mov cl,line
    xor ch,ch
    mov si,1
    cmp cx,0 ;判断字符串的长度是否为0
    jz break ;若为0,跳转 意味着 count 全为0

    s: ;循环计数
    mov al,line[si] ;si 是数组下标
    cmp al,’0’ ;判断字符是否小于’0’
    jb other ;若小于’0’,则字符为其他字符

    cmp al,’9’ ;判断字符是否大于’9’
    ja letter_or_other ;若大于’9’,则字符为字母或其他字符

    inc digit_count ;否则,字符为数字字符,数字记录器 加1
    jmp next ;跳转

    letter_or_other:
    and al,11011111b ;将字符转为大写字符
    cmp al,’A’ ;判断字符是否大于’A’
    jb other ;若小于,则字符是其他字符,跳转

    cmp al,’Z’ ;判断字符是否大于’Z’
    ja other ;若大于,则字符为其他字符,跳转

    inc letter_count ;否则,字符为字母字符,字母记录器 加1
    jmp next
    other:
    inc other_count ;字符为其他字符, 其他记录器 加1

    next:
    inc si ;数组下标 +1
    loop s ; cx -1,继续 s 代码块循环
    结果需要十进制输出:
    显示输出两位数字为十进制代码段:
    DISPLAY PROC NEAR;输出两位数字的子程序(输出两位数字为十进制)
    MOV BL,10
    DIV BL ;AX/BL,AL=商,AH=余数
    PUSH AX ;保存AX中的信息
    MOV DL,AL
    ADD DL,30H
    MOV AH,02H
    INT 21H ;输出十位数
    POP AX ;出栈送AX
    MOV DL,AH
    ADD DL,30H
    MOV AH,02H
    INT 21H ;输出个位数
    RET
    DISPLAY ENDP
    (4)实验结果(实验的运行结果)

    image.png
    实验四 查找匹配字符串
    (1)设计思路(包括程序的原理,算法及数据结构等)
    首先输入关键字和一个句子,分别存入相应的缓冲区中。并比较句子长度和关键字长度,当句子长度小于关键字长度时直接到no match结束;当句子长度大于等于关键字长度时进入查找关键字程序。
    关键字和句子中相应字段的比较可用串比较指令。定义附加段,可与数据段定义为同一段,以便于串指令的使用。相应的寄存器也有了确定的含义:
    SI:寄存器为关键字的指令;
    DI:寄存器为句子中正相比较的字段的指针;
    CX:寄存器存放关键字的字母个数(长度)。
    循环中用BX寄存器,保存句子中当前正在比较字段的首地址。
    输用功能调用09H分“找到”或“未找到”两种情况分别显示不同的信息。当找到时用(句子长度—关键字长度—句子首地址)即可得到关键字在句子中的位置,并调用转为十六进制子程序将其转换为十六进制输出;当未找到时直接输出no match。

    (2)程序框图(画出程序主要部分流程图)
    image.png
    (3)程序实现(注意:不用写出整体程序,写出部分关键代码即可,代码后要求用文字描述代码完成的功能)
    使用宏定义帮助输出、换行、输入简化
    ;—————————————————————
    CRLF MACRO
    MOV AH,2 MOV DL,0DH INT 21H
    MOV AH,2 MOV DL,0AH INT 21H
    ENDM ;—————————————————————
    S_SHOW MACRO STRING
    MOV AH,9 ;打印字符串(宏定义)
    MOV DX,OFFSET STRING
    INT 21H
    ENDM
    ;————————————————————-
    S_IN MACRO BUFF
    MOV AH,0AH
    MOV DX,OFFSET BUFF ;接收一个输入(宏定义)
    INT 21H
    ENDM
    比较代码:
    MATCH :
    S_SHOW
    MESS1 ;显示匹
    ;—————————————————————
    S_SHOW
    MESS11
    ;输出关键字在句子中匹配的第一个字符的位置
    MOV DX,OFFSET sentence
    push bx
    sub Bx,dx
    sub bx,2
    mov dx,bx
    push dx

    shr dx,1
    shr dx,1
    shr dx,1
    shr dx,1
    cmp dx,9
    ja anine2
    a3:

    cmp dx,9
    jb bnine2
    a4:
    mov ah,02h
    mov al,40h
    int 21h
    pop dx
    and dx,0fh
    cmp dx,9
    ja anine1
    a1:
    cmp dx,9
    jb bnine1
    a2:
    mov ah,02h
    mov al,40
    int 21h

    ;输出后半句 h of the sentence
    S_SHOW
    MESS22
    CRLF

    pop bx
    JMP
    GO ;跳转到开始

    anine1:
    add dx,37h
    jmp a1
    bnine1:
    add dx,30h
    jmp a2
    anine2:
    add dx,37h
    jmp a3
    bnine2:
    add dx,30h
    jmp a4

    EXIT:
    S_SHOW
    MESS2 ;显示不匹配
    CRLF
    JMP
    GO ;跳转到 GO 代码块
    ;———————————-
    CODE
    ENDS
    END START
    (4)实验结果(实验的运行结果)
    image.png
    三、课程设计(综合实验)总结或结论
    Masm for windows 集成实验环境是针对汇编语言初学者的特点开发的一个简单易用的汇编语言学习与实验软件,刚开始实验的时候,我对功能调用语句的使用还不太熟练,通过参考课本及实验书明白了使用堆栈来保存数据.我学到了许多基础知识,对循环设计程序有了进一步的了解,进一步明确了对loop的使用,对DOS系统功能调用有了初步的了解,明白了数据进栈和出栈是用来保护数据并恢复原始数据。分类统计字符的个数通过多个分支比较即可实现,这使我对分支结构和比较、跳转语句有了进一步了解。
    学习计算机组成原理的时候就对汇编有所了解,但通过汇编语言的学习,使我更加深入了解了其知识体系和计算机组成及内部程序执行的原理。对于各命令的熟练掌握后,自己亲自动手实验更是体会到了各命令的用途及执行的方法。通过各个基本命令可以轻松更改计算机内部寄存器的值和读写内存,磁盘,端口的值,通过更改观察其对计算机的影响变化。
    对于汇编语言的寻址方式,更是多种多样,通过对各寻址方式的比较,可以感受到各寻址方式的足与好处,还有是对各寻址方式的注意事项,有的寻址方式需专用的寄存器,有的寄存器是禁止使用的,然而有的就开放的多,对寄存器没有特殊要求,然而在编程过程中使用较为合适的寻址方式是提高程序运行效率的保障,在对寄存器中的值做运算时要正确书写各值,在X86中只支持十六进制数,在运算结束后值得保存也是很重要的,不能随意保存。
    希望以后能在这方面加强自己,争取学到更多的专业知识。

    四、参考文献
    [1] 沈美明, 温冬婵. IBM-PC汇编语言程序设计. 清华大学出版社, 第2版. 2001
    [2] 沈美明, 温冬婵. IBM-PC汇编语言程序设计实验教程. 清华大学出版社. 1992
    ASCII表
    DOS调用指令。