练习汇编代码在命令行显示字符时写的一个显示内容显得花里胡哨的程序,感觉挺好玩!
先贴代码:
assume cs:code,ds:data,ss:stack
data segment
db 26,0,1;
data ends
stack segment
dw 0,0,0,0,0,0,0,0;
stack ends
code segment
start: mov ax,0b800h
mov ds,ax
mov ax,data
mov es,ax
mov ax,stack
mov ss,ax
mov sp,10h
mov bx,0
mov cx,0
mov dx,0
mov si,0
mov bp,0
mov cx,2000
s0: push cx
mov bp,sp
mov cx,2
s1: mov ax,2000
sub ax,ss:[bp]
mov dx,0
mov si,cx
and si,0001h
div word ptr es:[si]
push dx
loop s1
pop dx
mov ah,dl
pop dx
add dl,41h
mov al,dl
mov ds:[bx],ax
add bx,2
pop cx
loop s0
mov ax,4c00h
int 21h
code ends
end start
显示结果如下:显示内容为大写字母A-Z循环重复显示,但其显示格式不同,其显示字符时每个字符的背景色、是否下划线、前景字符颜色不同、是否闪烁,从0000 0000b到1111 1111b共256种显示格式,由于存在闪烁故截取如下两张闪烁时不同状态的图,运行结果是,这两张图中不同的部分一直在闪烁。
颜色格式遵循如下格式:
7 6 5 4 3 2 1 0
BL R G B I R G B
闪烁 背景颜色 下划线 前景颜色
显示本应是从大写字母A开始显示,但由于程序结束后返回dos会弹出一行回显,将第一行该显示的内容挤上去看不见了。字符的显示格式为从0000 0000B到1111 1111B循环重复显示。
数据段的26作用为大写字母的个数为26个。
8086汇编在显示存储空间共可以存放4000个字符,dos命令行为25*80的规格,所以可以一次性显示2000个字符。所以外层s0循环计数器cx的值为2000(D)。
内层循环s1计数器为2,即循环两次,第一次操作为(2000-当前显示第几个字符)%(0000 001A),此处0000 001A(H)等于26(D),即求出(2000-当前显示第几个字符)对26取余的值。 第二次操作为(2000-当前显示第几个符)%(0001 0000),此处0001 0000(H)等于256,即求出(2000-当前显示第几个字符)对256取余的值。
需要说明的是,除法指令div在除以16位字形数据时,将商放在ax中,将余数放在dx中。所以在loop s1之前有一个 push dx的操作。将求得的值放在堆栈。
外层循环操作为,将对26取余的值加41H,41H为大写字母A的ASCII码的16进制形式,即为要显示A时需要在存储空间存放的字符数据,将对256取余的值作为颜色属性存放在下一字节单元。
程序比较简单,只是因为好玩写的,没什么其他用途,博君一笑,啊哈!