《汇编语言第三版》王爽学习历程——课程设计一

课程设计一

新人自己分析的,希望大神给予意见~!

任务:
将实验7中的Power idea公司的数据按照下图显示出来
《汇编语言第三版》王爽学习历程——课程设计一_第1张图片

需要重新编写一个子程序
编写一个新的数据到字符串转化的子程序,完成dword型数据到字符串的转化,说明如下:
名称:dtoc_dword(这里我自己取的名称)
功能:将dword型数转变为表示十进制的字符串,字符串以0为结尾符。
参数:(ax)=dword型数据的低16位,(dx)=dword型数据的高16位,ds:si指向字符串的首地址
返回:无
注:在这个子程序中要注意除法溢出的问题,可以用我们在试验10中设计的子程序divdw来解决。

分析
做一个简单的比喻:
我们是搬家公司的,要为4个人群搬家,从原来的数据段,搬到新家——显存段,而我们的工具是一辆搬家车——一个8各字节的空的字符串,这四类人群是:
1、年份:这类人群特点是,打包好了自己的行李,按时在家等我们去接他们去新的住所,而且上车就走。即,无需进行计算,也无需进行数值和ascii码之间的转换,从数据段复制到字符串然后写入显存相应位置就行。
2、年收入:这类人群的特点是,都是美女,虽然按时在家等我们去接,但是很懒,不打包行李而且行李又多,所以我们必须先打包行李再上车送她们去新的住所。即,需要进行数值和ascii码的转化,并且数值较大,必须写一个新的子程序,题干中有设计,不赘述。然后才可以从数据段复制到字符串后写入显存相应位置。
3、人数:这类人群和第二类人群很像,不过他们行李比较少,可以看做是比较懒的男孩子,行李不多。即,虽然需要转化ascii码,但是由于数值都比较小,所以子程序3完全可以胜任。
4、人均年收入:这类人群属于比较坑的,不仅行李不打包,而且人还不按时出现,需要我们去找到以后再帮他们打包行李,然后才能上车。即:需要计算后,然后进行数值和ascii码之间的转换,再存入字符串中后写入显存。

基本思路就是如此,现成的子程序有三个,由于刚学汇编,子程序写的不是很好,能不入栈的尽量不入,导致后寄存器冲突严重,调试了n次才可以正常运行,友情提示,尽量保存好主程序中的寄存器。
我是一列一列入显存的,还有我个格式是,列与列之间空出10个字符。
虽然我这样分析感觉不专业,但是没办法,刚学,希望用一个比较情景式的感觉来分析问题,可能比较好理解。

下面是我的代码,请大神指点:

assume cs:codesg

datasg segment
        db '1975', '1976', '1977', '1978', '1979', '1980'
        db '1981', '1982', '1983', '1984', '1985', '1986'
        db '1987', '1988', '1989', '1990', '1991', '1992'
        db '1993', '1994', '1995'
        ;上述是表示21年的21个字符串

        dd 16, 22, 382, 1356, 2390, 8000, 16000, 24486, 50065
        dd 97479, 140417, 197514, 345980, 590827, 803530
        dd 1183000, 1843000, 2759000, 3753000, 4649000
        dd 5937000
        ;以上表示21年公司总收入的21个dword型数据

        dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442
        dw 2258, 2793, 4037, 5635, 8226, 11542, 14430, 15257
        dw 17800
        ;以上是表示21年公司雇员人数的21个word型数据
datasg ends

temp segment
        db 8 dup(0)
        ;临时存储数值每一位的ascii码
temp ends

stacksg segment
        db 256 dup(0)
stacksg ends

codesg segment
 start:
        mov ax, datasg
        mov ds, ax
        mov si, 0

        mov ax, stacksg
        mov ss, ax
        mov sp, 100h

   ;第一列复制到显存中
        mov ax, temp
        mov es, ax          ;es永远指向临时字符串
        mov si, 0
        mov bh, 3
        mov bl, 13          ;行、列初始化
        mov cx, 21

   print_year:
        mov ax, ds:[si]
        mov es:[0], ax
        mov ax, ds:[si+2]
        mov es:[2], ax      ;相当于复制一个dword型数据

        mov dh, bh
        mov dl, bl
        call show_str

        add si, 4
        add bh, 1

        loop print_year

    ;第二列复制到显存中
        mov si, 0           ;数组偏移地址清0
        mov bh, 3       
        mov bl, 27          ;行、列初始化
        mov cx, 21

   print_income:
        mov ax, ds:84[si]   
        mov dx, ds:84[si+2] ;收入数组中的元素
        call dtoc_dword     ;dword型数据转换,结果在目标字符串

        mov dh, bh
        mov dl, bl          ;传参——行列
        call show_str       ;输出在屏幕

        inc bh              ;每写一行换一行
        add si, 4
        loop print_income

    ;第三列复制到显存中
        mov si, 0           ;数组偏移地址清0
        mov bh, 3       
        mov bl, 44          ;行、列初始化
        mov cx, 21

   print_people:
        mov ax, ds:168[si]
        call dtoc_word      ;数值转化字符

        mov dh, bh
        mov dl, bl
        call show_str

        add si, 2
        inc bh
        loop print_people   ;复制人数进显存

    ;第4列复制到显存中,需要进行除法计算
        mov si, 0           ;数组偏移地址清0
        mov di, 0
        mov bp, 0
        mov bh, 3       
        mov bl, 59          ;行、列初始化
        mov cx, 21

  print_ave:
        mov ax, ds:84[si]
        mov dx, ds:84[si+2]  ;被除数
        mov bp, ds:168[di]   ;除数
        div bp
        call dtoc_word       ;ax保存商

        mov dh, bh
        mov dl, bl
        call show_str

        inc bh
        add si, 4
        add di, 2

        loop print_ave

        mov ax, 4c00h
        int 21h


 ;以下为子程序
 -------------双字数据转换ASCII码---------------------------
 dtoc_dword:
        push ax
        push cx         ;用来判断是否除完
        push dx         
        push di         ;计算几位数
        push si         ;目标字符串偏移地址

        mov di, 0
        mov si, 0

        push_drem:      ;取余数入栈
        mov cx, 0ah
        call divdw      ;调用防止除法溢出子程序,返回值余数在cx中,商在dx和ax中
        push cx         ;第余数入栈
        inc di          ;位数+1

        mov cx, dx
        jcxz second     ;第一次判断商高位是否为0
    second:
        mov cx, ax
        jcxz ok_drem    ;第二次判断商低位是否为0,若高位低位都为0,说明商为0
        jmp short push_drem

   ok_drem:
        mov cx, di      ;一共几位数,要出栈几次

   pop_drem:
        pop ax
        add ax, 30H     ;将数值转换成ASCII码
        mov es:[si], al ;出栈到目标字符串中
        inc si
        loop pop_drem

        mov al, 0
        mov es:[si], al ;字符串末尾加0

        pop si
        pop di
        pop dx
        pop cx
        pop ax
        ret

--------------字型数据转换ASCII码---------------------
 dtoc_word:  
        push ax
        push bx         ;用来存放除数0AH
        push cx         ;用来判断是否除完
        push dx         ;用32位除法,用来保存余数
        push si         ;数据段偏移地址
        push di         ;计算数的位数

        mov si, 0
        mov cx, 0
        mov dx, 0
        mov di, 0
        mov bx, 0ah     ;寄存器的初始化

   push_wrem:           ;开始短除法取余数并入栈
        div bx
        mov cx, ax
        push dx         ;余数入栈
        mov dx, 0       ;重置被除数高位
        inc di
        jcxz ok_wrem    ;若商为0,则取余数已经完成

        jmp short push_wrem

   ok_wrem:              ;完成取余后,需要入数据段
        mov cx, di       ;出栈次数
   pop_wrem:
        pop ax
        add ax, 30h      ;对应ascii字符码
        mov es:[si], al  ;逆序入数据段
        inc si
        loop pop_wrem

        mov al, 0
        mov es:[si], al  ;字符串末尾加0

        pop di
        pop si
        pop dx
        pop cx
        pop bx
        pop ax
        ret
-------------解决除法溢出-----------------------
 divdw:
        push bx         ;临时保存中间运算结果
        push ax         ;首先计算数据的高位,低位入栈     

        mov ax, dx
        mov dx, 0
        div cx          ;ax保存商的高位,dx保存数据高位运算后产生的余数

        mov bx, ax      ;商的高位临时在bx中保存
        pop ax          ;此时,dx和ax保存了余*10000H+L
        div cx

        mov cx, dx      ;cx中保存最后的余数
        mov dx, bx      ;dx中保存商的高位

        pop bx
        ret
------------------屏幕输出-------------------------------
 show_str:
        push ds 
        push ax
        push bx
        push cx             ;保存字符属性
        push dx
        push di
        push si

        mov ax, 0b800h   
        mov ds, ax          ;初始化显示缓冲区

        mov al, 0a0h        ;进行行的计算,来确定行的偏移地址
        sub dh, 1
        mul dh
        mov bx, ax          ;行计算完毕

        mov al, 2           ;进行列的计算,来确定列的偏移地址
        sub dl, 1
        mul dl
        mov di, ax          ;列计算完毕

        mov al, 7 
        mov si, 0
        mov cx, 0           ;重置一下寄存器,以后需要用它判断是否结束       
 print:
        mov cl, es:[si]
        jcxz print_ok       ;判断如果字符读取完了就可以跳出循环了
        mov ds:[bx][di], cl     ;字符送入完毕
        mov ds:[bx][di+1], al   ;字符属性送入
        inc si
        add di, 2
        jmp short print         ;字符的循环复制

 print_ok:
        pop si
        pop di
        pop dx
        pop cx
        pop bx
        pop ax
        pop ds
        ret

codesg ends

end start   

程序效果:
《汇编语言第三版》王爽学习历程——课程设计一_第2张图片

其中还有很多不足之处,由于本身文字白色,也就不传递字符颜色属性等等,以后有时间再把这个做到最好。

你可能感兴趣的:(《汇编语言第三版》王爽学习历程——课程设计一)