练习一:补全程序 t1.asm,完成在屏幕上输出内存单元中的十进制两位数:
第一步:补全代码(如下):
; 在屏幕上输出内存单元中的十进制两位数
assume cs:code, ds:data
data segment
db 12
db ?,? ; 前一个字节用于保存商,后一个字节用于保存余数
data ends
code segment
start:
mov ax,data
mov ds,ax ; 补全指令,使得ds <-- data段地址
mov ah,0
mov al,ds:[0] ; ax <-- data段字节单元的被除数12
mov bl,10
div bl
mov ds:[10H],al ; 补全代码,让商保存到data段注释中指定的单元
mov ds:[11H],ah ; 补全代码,让余数保存到data段注释中指定的单元
mov ah,2
mov dl,ds:[10H] ; 补全代码,使得dl <-- data段中保存的商的字节单元数值
add dl,30H ; 补全代码,使得dl中的数值转换为数字字符
int 21h
mov ah,2
mov dl,ds:[11H] ; 补全代码,使得dl <-- data段中保存余数的字节单元数值
or dl,30H ; 补全代码,使得dl中的数值转换为数字字符
int 21h
mov ax,4c00h
int 21h
code ends
end start
第二步:运行代码(如下图):
练习二: 补全程序 t2.asm,完成在屏幕上输出 data 段定义的 5 个十进制两位数,数据和数据之间以空格间隔。
第一步:补全代码(如下):
assume cs:code, ds:data
data segment
db 12,35,96,55,67
data ends
code segment
start:
; 补全程序,参考t1.asm,综合应用以下知识完成
mov ax,data
mov ds,ax
mov si,0
mov cx,5
s:
push cx
mov ah,0
mov al,byte ptr ds:[si]
mov bl,10
div bl
mov bh,ah
mov ah,2
mov dl,al
add dl,30H
int 21H
mov ah,2
mov dl,bh
add dl,30H
int 21H
mov ah,2
mov dl,' '
int 21H
inc si
pop cx
loop s
mov ax,4c00h
int 21h
code ends
end start
第二步:运行代码(如下图):
练习三:
设计代码(如下,用到了利用偏移地址换行输出的原理):
代码一:
assume ds:data, cs:code
data segment
db 'welcome to masm!'
db 2H,24H,71H ;字符串属性值
data ends
code segment
start: mov ax,data
mov ds,ax ;字符串及属性值所在段的段地址送入ds
mov ax,0b800H
mov es,ax ;80×25彩色字符模式显示缓冲区段地址送入es
mov cx,16
mov si,16
mov bx,0
mov di,0
s:
mov al,ds:[bx]
mov es:[di],al
mov al,ds:[si]
mov es:[di+1],al
inc bx
add di,2
loop s
mov ax,0b80aH
mov es,ax
mov cx,16
mov si,16
mov bx,0
mov di,0
mov si,17
s1:
mov al,ds:[bx]
mov es:[di],al
mov al,ds:[si]
mov es:[di+1],al
inc bx
add di,2
loop s1
mov ax,0b814H
mov es,ax
mov cx,16
mov si,16
mov bx,0
mov di,0
mov si,18
s2:
mov al,ds:[bx]
mov es:[di],al
mov al,ds:[si]
mov es:[di+1],al
inc bx
add di,2
loop s2
mov ax,4c00h
int 21h
code ends
end start
运行代码一(如下图):
代码二:为了实现每个字符的颜色不一样(达到颜色以周期为三循环),而使用了循环嵌套:
assume ds:data, cs:code
data segment
db 'welcome to masm!'
db 2H,24H,71H ;字符串属性值
data ends
code segment
start: mov ax,data
mov ds,ax ;字符串及属性值所在段的段地址送入ds
mov ax,0b800H
mov es,ax ;80×25彩色字符模式显示缓冲区段地址送入es
mov cx,5
mov si,16
mov di,0
mov bx,0
;大循环
s:
push cx
mov cx,3
s1:
mov dl,ds:[di]
mov byte ptr es:[bx],dl
mov dl,ds:[si]
mov es:[bx+1],dl
inc si
add bx,2
inc di
loop s1
mov si,16
pop cx
loop s
mov dl,ds:[di]
mov es:[bx],dl
mov dl,ds:[si]
mov es:[bx+1],dl
mov ax,4c00h
int 21h
code ends
end start
运行代码(如下图):
保证了每个字符颜色均不同。
实验感悟:
练习1:输出内存单元中的一个十进制数(数码)
1. 件中写入的数据,不加特殊说明,均默认为十进制,所以在代码段中定义的那个12数据是一个十进制数,在人眼看来,这个是一个十进制的12,但是在计算机中这个12是以16进制的数据来存储的。
2. 另外,使用dl寄存器来实现数据的输出:dl输出的是字符,所以若要输出6这个字符,就要先将6这个数据转化为‘6’字符的ascll码(使用or命令或者add命令,数值和对应的数字字符的ascll码在数值上差十进制48,就是十六进制30)。又因为dl是8位寄存器,所以or dl,30H和add dl,30H是一样的。所以使用这两种方法都可以将数值型的数据转化成对应字符的ascll码,从而完成输出一个十进制数码。
练习2:输出连续内存单元中的五个十进制数,并以空格分隔
1. 基本操作是输出一个十进制数码。
2. 所以思想就是使用循环来实现基本操作的重复进行。
3. 注意:除法指令div的使用,除法分为16位除以8位,和32位除以16位,在16位除以8位中,被除数存放在ax中,而除数被存放在某个8位寄存器或者内存单元中,在做完div之后,结果的余数存放于ah(高)中,商存放在al(低)中。而在32除以16位中,被除数被存放在dx和ax中,其中dx存放被除数的高16位,ax存放低16位,在做完了除法之后,dx中为余数,ax中为商。所以在练习二中,每一个被除数据均是8位数据,所以为了能使除法成功,就要始终保持除法指令进行之前ah=0,这样才能每次成功地将字节型数据作为除数放入al中,再做除法。如果没有每次将ah置零,那么就会出现将上一次做下来的余数也包含在这一轮的除法的被除数里面,出现错误。
练习3:在屏幕上打印出不同颜色的字符串/字符
一. 打印字符串(让每一个字符的性质都一样):首先一个字符的特性是如何被控制的:
利用控制字节,先输入字符到b800段地址中,然后再将性质输入到紧接着的后面的字节单元中,这个占了一个字节的性质控制如下
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
0~3这部分的位中的二进制代码控制前景色(数值大小取值为0~15)
4~6这部分控制背景色(取值大小范围是0~7)
第七位控制是否闪烁:1为闪烁,0为不闪烁
其中在0~3这几位中最高位控制是否高亮
由于这个字符串每一个字符均为同性质,所以我考虑整体,将性质作为高位字节放入ah中,然后通过循环每次将不同的数据放入al中,在利用小端法的存储方法达到效果。
二.打印字符串(性质周期为三):利用二重循环,和push cx指令,pop cx指令,达到内外兼顾的作用,由于总字符数并非三的倍数,所以在循环次数为15的时候跳出循环,然后将最后一个‘!’字符以第一个性质放入附加段所代表的显存中,从而达到连续两个字符性质不同的效果。