1.
;-------------------------------------------------------------------------------------- show_str: ;push指令保护子程序用到的寄存器 push bx push cx push dx push si push di ;指定显存区域 mov ax,0b800h mov es,ax ;初始化行 mov ax,0a0h dec dh mul dh mov bx,ax ;初始化列 mov ax,2 mul dl mov di,ax ;将字符属性存入AH中 mov ah,cl mov cx,16 ;开始逐字符显示 s: mov al,[si] ;源地址DS:SI指向数据段字符 cmp al,0 ;如果遇到0,则表示循环结束跳至ok处退出子程序 jz ok mov es:[bx+di],ax ;目标地址ES:[BX+DI],AH=属性,AL=字符 inc si ;指向数据段下一个字符 add di,2 ;指向下一列 loop s ;如果CX≠0,继续循环
ok: ;恢复保护的寄存器 pop di pop si pop dx pop cx pop bx ;返回调用 ret
2.
assume cs:code stack segment dw 8 dup(0) stack ends code segment start: mov ax,stack mov ss,ax mov sp,16 mov ax,4240h ;被除数为000f4240H mov dx,0fh mov cx,0ah ;除数为0aH call divdw ;int(H/N) mov ax,4c00h int 21h divdw: push ax mov ax,dx ;因为此时要做的是16位的除法,所以要设置AX,DX。根据公式这里做的是被除数的高位除以除数,被除数的高位为0FH,放到在16位除法中就应该是dx=0000h,ax=000fh mov dx,0 div cx mov bx,ax ;16位除法完后商会保存在ax中,我们先把高位除以除数的商保存在bx中 pop ax ;把被除数的低位从栈中取出 div cx ;这一步是关键,很多人不明白公式的后半段[rem(H/N)*65536+L]/N,在这我跟大家解释一 下,65536是10进制数,转换为16进制也就是10000. ;这里很多人要问,我们并没有用高位的余数*10000H+低位,而是直接用低位当被除数直接开始除法了!类似与L/N了,我想说你错了!因为在高位的除法中它的余数直接保留在DX中,而在低位除法中,DX正是这次除法的高位! ;也就是说,rem(H/N)*10000H这一步我们已经做了,这段公式不就说让我们把高位的余数放到高位吗?然后再加上低位组成一个新的被除数再除以除数[rem(H/N)*65536+L]这段公式的目的并不是要我们把数值相加,而是让我们完成一个32位的被除数,也就是用原始被除数的余数与原始被除数低位凑成一个完整的数如:设rem(H/N)值为0006H,L=4240H,这个数应该是00064240H mov cx,dx mov dx,bx ret code ends end start
3.
第10章实验10.3 数值显示 (带详细注释);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;名称: dtoc ;功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符. ;参数:(ax)=word型数据 ; ds:si指向字符串的首地址 ;返回: 无 ;应用举例:编程将数据12666以十进制的形式在屏幕的8行3列,用绿色显示 ;出来.在显示时我们调用本次实验中的第一个子程序show_str. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;author:chinaljg ;time:2011年1月22日 assume cs:code data segment db 10 dup (0) data ends code segment start: mov ax,12666 mov bx,data mov ds,bx mov si,0 call dtoc ;调用完后,ds:si应指向data段中的以0结尾的字符串 mov dh,8 ;提供入口参数8行 mov dl,3 ;提供入口参数3列 mov cl,2 ;提供入口参数绿色 mov si,0 ;ds:si指向字符串首地址 call show_str ;调用子程序显示ds:si指向的以0结尾的字符串 mov ax,4c00h ;程序正常返回 int 21h ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;名称: dtoc ;功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符. ;参数:(ax)=word型数据 ; ds:si指向字符串的首地址 ;返回: 无 ;应用举例:编程将数据12666以十进制的形式在屏幕的8行3列,用绿色显示 ;出来.在显示时我们调用本次实验中的第一个子程序show_str. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; dtoc: push ax ;子程序调用的寄存器入栈 push bx ;子程序调用的寄存器入栈 push cx ;子程序调用的寄存器入栈 push dx ;子程序调用的寄存器入栈 push ds ;子程序调用的寄存器入栈 mov dx,0 mov bx,0ah div bx ;用dxax/bx 16位除法,dx放余数,ax放商,ax是提供的入口参数 add dx,30h ;把数据码转变为ASCII码 push dx ;入栈 mov cx,ax jcxz savedata call dtoc ;通过递归就不用考虑出栈的数量.考虑:在那种情况下用递归?(除法取余) savedata: ;第一次:31 00 ;第二次:31 32 00 ;第三次:31 32 36 00 ;...... pop dx mov ds:[si],dx inc si mov byte ptr ds:[si],0 pop ds ;子程序调用的寄存器出栈 pop dx ;子程序调用的寄存器出栈 pop cx ;子程序调用的寄存器出栈 pop bx ;子程序调用的寄存器出栈 pop ax ;子程序调用的寄存器出栈 ret ;递归后,ret返回到了savedata标号处,最后一层ret才返回到mov dh,8处. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;名称:show_str ;功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串. ;参数:(dh)=行号(取值范围0-24),(dl)=列号(取值范围0-79). ; (cl)=颜色, ds:si指向字符串的首地址 ;返回:无 ;应用举例:在屏幕的8行3列,用绿色显示data段中的字符串. show_str: push ax ;子程序用到的寄存器入栈 push bx ;子程序用到的寄存器入栈 push cx ;子程序用到的寄存器入栈 push dx ;子程序用到的寄存器入栈 push ds ;子程序用到的寄存器入栈 push si ;子程序用到的寄存器入栈 push es ;子程序用到的寄存器入栈 push di ;子程序用到的寄存器入栈 mov ax,0b800h mov es,ax mov di,0 ;es:di指向显示缓存区,用来显示字符串 ;根据入口参数行号和列号计算显存中的地址 mov al,160 ;8位乘法,一个默认放在al中,另一个放在8位的reg或内存单元,结果默认放在ax中,思考:ah不用清0的原因。 mul dh add ax,160 ;加上第0行,因为行号是从0开始的。行号是8指的其实是第9行 add dl,dl ;一个字符占2列,一列放字符,另一列放这个字符的颜色属性,请思考:这儿为什么不加第0列? mov dh,0 ; ax与cl中的数相加就是显存地址,但是ax与cl长度不对等,不能直接相加 add ax,dx ;ax中存放的就是8行3列所对应的显存地址的开始位置 mov di,ax ;用di作为显存地址的偏移量 show_str_display: push cx ;下面要用cx来做判断,为了不破坏原数据,入栈 mov cl,ds:[si] ;将字符串中的字符传送到显示缓冲区 mov es:[di],cl mov ch,0 ;构造cx用来判断是否到字符串的结束符‘0’ jcxz show_str_ok ;字符已经显示完毕,返回 pop cx ;没有到字符串结尾,出栈用来设置字符颜色。思考:若到字符串结尾了,你的出栈指令写在哪? mov es:[di].1,cl ;给字符设置颜色属性 inc si ;下一个字符 add di,2 ;下一个用来显示字符的显存地址(一个字符要想显示要占2个显存地址,一个是字符,另一个是颜色) jmp short show_str_display show_str_ok: pop cx ;到字符串结尾,出栈。以免影响子程序返回的ip pop di ;子程序用到的寄存器出栈,注意顺序 pop es ;子程序用到的寄存器出栈,注意顺序 pop si ;子程序用到的寄存器出栈,注意顺序 pop ds ;子程序用到的寄存器出栈,注意顺序 pop dx ;子程序用到的寄存器出栈,注意顺序 pop cx ;子程序用到的寄存器出栈,注意顺序 pop bx ;子程序用到的寄存器出栈,注意顺序 pop ax ;子程序用到的寄存器出栈,注意顺序 ret ;返回 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; code ends end start