实验九
1. 补全程序t1.asm,完成在屏幕上输出内存单元中的十进制两位数 2. 补全程序t2.asm,完成在屏幕上输出data段定义的5个十进制两位数,数
1 ; 在屏幕上输出内存单元中的十进制两位数 2 assume cs:code, ds:data 3 data segment 4 db 12 5 db ?,? ; 前一个字节用于保存商,后一个字节用于保存余数 6 data ends 7 code segment 8 start: 9 mov ax,data 10 mov ds,ax ; 补全指令,使得ds <-- data段地址 11 12 mov ah,0 13 mov al,ds:[0] ; ax <-- data段字节单元的被除数12 14 mov bl,10 15 div bl 16 mov ds:[2],al ; 补全代码,让商保存到data段注释中指定的单元 17 mov ds:[3],ah ; 补全代码,让余数保存到data段注释中指定的单元 18 19 mov ah,2 20 mov dl,ds:[2] ; 补全代码,使得dl <-- data段中保存的商的字节单元数值 21 add dl,30h ; 补全代码,使得dl中的数值转换为数字字符 22 int 21h 23 24 mov ah,2 25 mov dl,ds:[3] ; 补全代码,使得dl <-- data段中保存余数的字节单元数值 26 add dl,30h ; 补全代码,使得dl中的数值转换为数字字符 27 int 21h 28 29 mov ax,4c00h 30 int 21h 31 code ends 32 end start
2. 补全程序t2.asm,完成在屏幕上输出data段定义的5个十进制两位数,数据和数据 之间以空格间隔。
1 assume cs:code, ds:data 2 data segment 3 db 12,35,96,55,67 4 data ends 5 code segment 6 start: 7 mov ax,data 8 mov ds,ax 9 10 mov cx,5 11 mov bx,0 12 13 14 s: mov ah,0 15 mov al,ds:[bx] 16 mov dl,10 17 div dl 18 19 mov ds:[5],al 20 mov ds:[6],ah 21 inc bx 22 23 mov ah,2 24 mov dl,ds:[5] 25 add dl,30h 26 int 21h 27 28 mov ah,2 29 mov dl,ds:[6] 30 add dl,30h 31 int 21h 32 33 mov ah,2 34 mov dl,0 35 int 21h 36 loop s 37 ; 补全程序,参考t1.asm,综合应用以下知识完成: 38 ; (1) loop指令、内存单元地址的灵活表示 39 ; (2) div指令, 数字→数字字符的转换 40 ; (3) int 21h的2号子功能,完成单个字符输出的方法,即: 41 ; mov ah,2 42 ; mov dl,待输出字符或其ASCⅡ码 43 ; int 21h 44 ; (4) 数据和数据之间以空格间隔的实现: 使用(3)输出空格字符 45 46 mov ax,4c00h 47 int 21h 48 code ends 49 end start
3. 教材实验9(P187)
1 ; p187 实验9 2 3 assume ds:data, cs:code 4 data segment 5 db 'welcome to masm!' 6 db 2H,24H,71H ;字符串属性值 7 data ends 8 9 code segment 10 start: mov ax,data 11 mov ds,ax ;字符串及属性值所在段的段地址送入ds 12 13 mov ax,0b800H 14 15 mov es,ax ;80×25彩色字符模式显示缓冲区段地址送入es 16 17 mov si,0 ;用来记录属性 18 mov cx,3 19 20 21 mov di,0 22 mov di,0678h;相对于es:0的偏移量,要显示到屏幕中心,需要给一个初始的偏移量,di:目的变址寄存器 23 s: push cx;外循环 24 mov byte ptr al,ds:[10h+si];存放属性 25 mov bx,0 26 mov cx,10h 27 28 s1: mov dl,ds:[bx] 29 mov byte ptr es:[di],dl 30 mov byte ptr es:[di+1],al 31 inc bx 32 add di,2 33 loop s1 34 35 pop cx 36 37 mov ax,es 38 add ax,8;到下一行去,一行80个字符,一个字符256种属性 39 mov es,ax 40 inc si 41 loop s 42 ; 添加代码,通过循环逐个将每个字符及其属性送入相应的显示缓冲区对应行 43 ; 即:将data段的字符及属性通过循环逐个mov到显示缓冲区(es)段相应的单元内 44 45 ; 可以先尝试分别写三段代码,每次完成一行的显示 46 ; 程序运行起来后,再尝试通过灵活的寻址方式和循环,对三段代码修改和简化 47 ; 学习第10章子程序后,还可以进一步完善优化,设计子程序,将行号、列号、颜色属性设置成入口参数 48 49 50 mov ax,4c00h 51 int 21h 52 code ends 53 end start
结果截图:
总结与体会
最后一个实验感触较深,通过栈来储存CX的值,来实现二次循环。
由于不能像C语言中自由地申请内存空间,故只能调用栈机制。将需要使用的寄存器内的变量入栈,然后使用寄存器当一个新的变量,很显然,这样当你需要管理很多个变量的时候会带来极大的不方便。因为不能直接通过一次出栈来访问,而需要通过访问内存单元的方法,这是不安全的。(实模式下就不管安全了吧。。。)
在最后一个实验中,我没有设置SS,SP的初始值,所以会有一个随机的初始值,会操作一块未知的内存单元,(这也是不安全的)不知道会不会出问题
对于显存空间:B8000H-BFFFFH 25行*80个字符,每个字符256种属性。
最后转载一下寄存器的英文名,方便读者记忆(明明是自己实验时记错好几次。。)(如何充分安排寄存器的使用还真是个问题,目前程序短还好,长的话就。。。)
1:数据寄存器,一般称之为通用寄存器组
8086 有8个8位数据寄存器,
这些8位寄存器可分别组成16位寄存器:
AH&AL=AX:累加寄存器,常用于运算;
BH&BL=BX:基址寄存器,常用于地址索引;
CH&CL=CX:计数寄存器,常用于计数;
DH&DL=DX:数据寄存器,常用于数据传递。
2:地址寄存器/段地址寄存器
为了运用所有的内存空间,8086设定了四个段寄存器,专门用来保存段地址:
CS(Code Segment):代码段寄存器;
DS(Data Segment):数据段寄存器;
SS(Stack Segment):堆栈段寄存器;
ES(Extra Segment):附加段寄存器。
3:特殊功能的寄存器
IP(Instruction Pointer):指令指针寄存器,与CS配合使用,可跟踪程序的执行过程;
SP(Stack Pointer):堆栈指针,与SS配合使用,可指向目前的堆栈位置。
BP(Base Pointer):基址指针寄存器,可用作SS的一个相对基址位置;
SI(Source Index):源变址寄存器可用来存放相对于DS段之源变址指针;
DI(Destination Index):目的变址寄存器,可用来存放相对于 ES 段之目的变址指针。来源:http://nannan408.iteye.com/blog/982942
关于中断,可以参考:https://blog.csdn.net/heavengl/article/details/6035716