汇编语言实验十,超详细基础解析(原创)

1.显示字符串

思想:字有点难看但是这是我编写这个程序时的基础思想在这里插入图片描述

;time:2022/3/16	name:feng
;刚开始编写的时候头脑有点不清晰,导致没有思路也是因为跳转指令太难理解搞得我很烦躁,经过一天后重新思考这个问题很其实很简单,
;我感觉最难的是确定显存的起始地址,因为刚开始我是想直接将行设为b8000+460h的后来才发现这个是不能实现的只能将其放在偏移地址中存放
;我感觉我编写的这个程序最好的地方是我没有定义cx的值,直接用跳转指令实现控制。其实刚开始我受到loop指令的思想想为cx设置循环值,但是后面
;想到如果这样写还没我写的9_2.asm写的好,后面看到书本上的指令结合方式想到不需要去理会cx的值,因为只有当将字符串0存入cl时才会导致循环结束
assume cs:code
data segment
        db 'Welcome to masm!',0
data ends

code segment
start:  mov dh,08h		;行号
        mov dl,03h		;列号
        mov cl,2		;颜色
        mov ax,data
        mov ds,ax
        mov si,0
        call show_str		;相当于push ip,jmp near ptr 标号

        mov ax,4c00h
        int 21h
show_str:
        sub dh,1h		;显存为25*80,所以要算显存起始地址b800+8-1*160+4
        mov al,dh		;将行号存入al等待乘法使用
        mov bl,0a0h		;注意字母前面一定要加0,一直忘记,0a0h=160d
        mul bl
        mov di,ax		;之所以将后面的部分存入di是因为不能存入es中会发生错误:b800+460h,而我想要的是b8000+460h
        add di,4h
        mov ax,0b800h
        mov es,ax
       
        mov ah,cl		;将颜色存入ah

    s:  mov cl,[si]		;将字符存入cl
        mov ch,0
        jcxz ok		;判断字符是否为0,因为字符串以0为结束
        mov al,cl
        mov es:[di],ax
        inc si
        add di,2
        jmp short s		;跳转到s继续执行,直到字符是0时结束

    ok: ret

code ends
end start


     
        


        


2.解决除法溢出的问题

在这里插入图片描述

;time:2022/3/18	name:feng
;这个程序真的不是很难,但是它困扰了我两三天。原因是书本上提供的公式有点简略,导致我需要将数值带进公式去检查一下
;并且去理解一下这个公式的原理,比如按我理解的是dx存放的是溢出为的值,ax和cx存放的是公式后半部分的除法的值(32/16)
;但是书本上却没有讲的很清楚。然而当我理解并写出这个程序时却真的很开心,虽然这个程序简单,但是却让我意识到所有的编程
;其实难的不是如何去编程,而是思想,一旦有了想法,写出程序的方法有千万种。
assume cs:code,ss:stack

stack segment		;创建栈来存储会受影响的值
        dw 8 dup (0)
stack ends

code segment
start:  mov ax,stack
        mov ss,ax
        mov sp,10h
        mov ax,4240h		;被除数的低16位
        mov dx,000fh		;被除数的高16位(H)
        mov cx,0ah		;除数(N)
        call divdw
        mov ax,4c00h
        int 21h

divdw:  push ax		;将被除数的低16位(L)压栈,因为公式的后半部分需要使用,而在计算前半部分时ax的值会变。
        mov ax,dx		;将被除数的高16位赋给ax计算公式的前半部分。
        div cl		;al存放商,也就是溢出位的值;ah存放余数后面需要使用(rem(H/N))
        mov dl,ah		;将余数赋给dl后面需要使用,当作被除数的高16位
        mov bl,al		;将商赋给bl后面将其压栈,因为后面需要将栈中存放的ax取出,会影响所以用bl暂时存储
        pop ax		;ax=4240H
        push bx
        div cx
        mov cx,dx		;cx存放余数
        pop dx
        ret

code ends
end start


3.数值显示

在这里插入图片描述


;time:2022/3/17	name:feng	
;在做这个实验前我刚开始是想使用栈将data段中的数据逆序重新放置的,因为在这个程序中我使用了前面所写的show_str,
;但是后面想到栈存取是以字为单位,而我存储在data中的是以字节为单位的
;最终放弃逆序的想法,使用从后往前将数据存入显存中的方法,然后将show_str微调使其能够将数字在屏幕上显示,
;在编写这个程序中这个问题是困扰我许久的问题,编写dtoc其实很简单,但是想办法
;使其如何在屏幕上按正常的顺序显示是真的有一点困难。但是解决这个问题之后是真的很舒服。
;注:最后在写注释的时候show_str中的第一个jcxz我忘记了将其删除,应该是我编写的时候没注意到它会影响程序的运行结果
;后面发现如果我要将以0为尾数的数值显示出来那么这个jcxz将会提前导致程序的结束,果然编写注释是真的好,既能加强理解也能检查错误
assume cs:code

data segment
        db 10 dup (0)		
data ends


code segment
start:  mov ax,317ah		;存放12666这个数
        mov bx,data
        mov ds,bx
        mov si,0		;注意这个si在这个程序中至关重要
        call dtoc

        mov dh,8h		;行号
        mov dl,3h		;列号
        mov cl,2h		;颜色
        call show_str

        mov ax,4c00h
        int 21h

  dtoc: mov bx,0ah		;将除数放在bx中  (之所以使用32/16位的除法是因为第一次做除法得到的商为1266>255,不能使用八位的位置存储)
        mov dx,0		;被除数的最高位
        div bx
        mov cx,ax		;将商赋给cx来判断算法是否结束
        add dx,30h		;数字+30H正好对应数字的ASCII值
        mov [si],dl		;将所得余数存放在data段中
        inc si
        jcxz okk		;判断时候结束
        jmp short dtoc		;如果没结束就继续

    okk: ret

show_str:
        sub dh,1h		;这个show_str与10_1.asm所编写的相差不打,所以只注释微调的指令
        mov al,dh
        mov bl,0a0h
        mul bl
        mov di,ax
        add di,4h
        mov ax,0b800h
        mov es,ax

        mov ah,cl
     s: mov cl,-1[si]		;-1[si]=[-1+si],注意汇编语言中不能[si-1],之所以这样是因为所要显示的字符是逆序放置的如‘66621’而我要显示的是‘12666’
        mov ch,0
        ;jcxz ok   之所以将这行放到下面的原因是我已经不是从前往后存入了,而且如果数字末尾是0的话如果这行不删除将无法运行
        mov al,cl
        mov es:[di],ax
        sub	si,1
        mov cx,si
        jcxz ok		;以si是否为0来判断是否结束(注意jcxz只能判断cx的值我这里写si是更好理解结束的位置)
        add di,2
        jmp short s

    ok: ret

code ends
end start

总结

我是自学的,如果写的不好请指出。我个人感觉这三个实验真的不是很难,最难的是思想而不是编程,我在编写第二个程序的时候真的没有搞懂那个公式,导致最简单的程序反而是最后写出来的。这个是我的个人理解,可能你们比我更聪明觉得那个公式很简单,感觉写的还行的点个赞吧。(我的字很难看我知道,勿喷)

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值