|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 wangkaichao2 于 2011-9-24 20:35 编辑
- ;;------------------------------------------------------------------------------------------
- ;; 王爽汇编课程设计1(第211页)
- ;; 感谢王爽老师的这本《汇编语言》,让我受益匪浅,尤其是代码段,数据段,栈段的讲解,
- ;; 太经典了,看了之后已经对这本书爱不释手,以前看过单片机的的汇编,8086的汇编刚学了两
- ;; 周,下面是我对课程设计1的实现。
- ;; 求助:
- ;; 1)我觉得我写的代码很不规范,希望高手在编写规范的和高质量的汇编代码方面给我多提出意见。
- ;; 2)我不知道如何将汇编的多个子模块分别放在多个*.asm文件里,然后像C语言一样编译连接相互
- ;; 调用的各个模块文件,希望高手能给出帮助,谢谢
- ;; 作者:wangkaichao2
- ;;-----------------------------------------------------------------------------------------
- assume cs:code
- data segment
- db '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983'
- db '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992'
- db '1993', '1994', '1995'
- ;0 + 21 * 4 = 84
- dd 16, 22, 382, 1356, 2390, 8000, 16000, 24486, 50065, 97479, 140417, 197514
- dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000
- ;84 + 21 * 4 = 168
- dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5735, 8226
- dw 11542, 14430, 15257, 17800
- ;168 + 2 * 21 = 210
- data ends
- table segment
- db 80 dup (0)
- table ends
- code segment
- ;;------------------------------------------------------------------------------------
- ;; 王爽汇编课程设计1(第211页)
- ;; MAIN
- ;;------------------------------------------------------------------------------------
- start:
- mov ax, data
- mov es, ax
- mov di, 0
- mov bx, 0
- mov ax, table
- mov ds, ax ;指定table的段地址
- mov si, 0
-
- mov dh, 3 ;行号
- mov dl, 0 ;列号
- mov cx, 21
- next_line:
- push cx ;循环体中用到cl
- call fill_table
- inc dh ;行号加1,显示下一行
- mov cl, 2 ;绿色字
- call show_str ;入参(dh),(dl),(cl),ds:si
- add di, 4 ;如果把data段看作结构体数组,(di)就是结构体数组中“年份”和“总收入”下标
- add bx, 2 ;(bx)是结构体数组中“公司雇员”的下标
- pop cx
- loop next_line
-
- mov ax, 4c00H
- int 21H
- ;;------------------------------------------------------------------------
- ;;名称:show_str
- ;;功能:在指定位置,用指定的颜色,显示一个用0结束的字符串
- ;;入参:(dh)=行号(0~24),(dl)=列号(0~79),(cl)=颜色,
- ;; ds:si指向字符串的首地址
- ;;返回值:无
- ;;------------------------------------------------------------------------
- show_str: ;dh * A0H + dl定位显存偏移起始地址
- push dx
- push ds
- push si
- push ax
- push bx ;显存偏移地址
- push es ;显存段地址
- push cx ;保存ch中的未知数据
- mov ax, 0b800H
- mov es, ax
- mov ax, 0a0H ;一行a0H个字节
- mul dh ;计算第(dh)行的起始偏移地址
- mov dh, 0 ;清零,只保留dl中的列数
- add ax, dx ;加上列地址,不行的话改为mov dh, 0;add ax, dx
- add ax, dx ;一列占两个字节
- mov bx, ax ;es:bx = 字符串在显存中的起始地址
- mov ah, cl ;ah存储颜色
- mov ch, 0
- showChar: ;将字符串循环填充到显存
- mov cl, [si]
- jcxz toNull
- mov al, cl ;al存储ASCII码
- mov es:[bx], ax ;将ASCII码和属性送入显存
- add bx, 2
- inc si
- jmp short showChar
-
- toNull:
- pop cx
- pop es
- pop bx
- pop ax
- pop si
- pop ds
- pop dx
- ret ;;show_str end
- ;;-------------------------------------------------------------------------------
- ;; 名称:dtoc
- ;; 功能:将dword型数据转变为表示十进制数的字符串,字符串以0为结尾符。
- ;; 参数:(dx)=dword型高16位
- ;; (ax)=dword型低16位
- ;; ds:si指向字符串首地址
- ;; 返回:无
- ;; 应用举例:将12666以十进制形式在屏幕的8行3列,用绿色显示
- ;; 该子模块调用了show_str, divdw子程序段
- ;;-------------------------------------------------------------------------------
- dtoc:
- push dx
- push ax
- push ds
- push cx
- push si
- next_div:
- mov cx, 10
- call divdw ;商(dx)(ax),余数(cx)
- add cx, 30H
- mov [si], cl ;ASCII占一个字节
- inc si
- ;;判断(ax)是否等于0
- mov cx, ax
- add cx, 1 ;cx先增1,改成 inc cx ?
- loop next_div ;cx先减1,if(cx != 0),商不为0
- ;;在(ax)等于0的前提下,判断(dx)是否等于0
- mov cx, dx
- jcxz div_end ;if(dx==0),商为0,循环结束
- loop next_div
- div_end:
- mov byte ptr [si], 0 ;字符串0结束符
- pop si ;ds:si=字符串起始地址
- call str_reserve ;颠倒字符串
- pop cx
- pop ds
- pop ax
- pop dx
- ret ;;dtoc子程序结束
- ;;--------------------------------------------------------------------------------------
- ;; 名称:divdw
- ;; 功能:进行不会产生溢出的除法运算,被除数dword型,除数word型
- ;; 入参:(dx) = 被除数高16位,(ax)= 被除数第16位,(cx) = 除数
- ;; 返回值:(dx) = 商高16位,(ax) = 商第16位,(cx) = 余数
- ;; 余数为word型,结果为dword型
- ;; int():描述性运算符,取商,比如,int(38/10)=3
- ;; rem():描述性运算符,取余,比如,rem(38/10)=8
- ;; X:被除数,N:除数
- ;; 公式:X/N = int(H/N)*10000H + [rem(H/N)*10000H + L]/N
- ;;--------------------------------------------------------------------------------------
- divdw:
- push bx
- push ax ;被除数低16位入栈
- mov ax, dx ;处理高16被除数
- mov dx, 0
- div cx ;int(H/N)*10000H
- mov bx, ax ;bx暂存高16位除后的商
- pop ax ;获取被除数低16位
- div cx ;[rem(H/N)*10000H + L]/N
- mov cx, dx ;cx存放余数
- mov dx, bx
- pop bx
- ret ;;end divdw
- ;;-------------------------------------------------------------------------------------
- ;; 名称:str_reserve
- ;; 功能:将数据段中的以0结尾字符串逆序排列
- ;; 参数:ds:si = 字符串首地址
- ;; 返回值:(cx) = 字符串长度
- ;; 该子模块调用了get_str_length
- ;;-------------------------------------------------------------------------------------
- str_reserve:
- push ds
- push si ;字符串前后交换时,(si)从第一个字符开始向中间移动
- push di ;字符串前后交换时,(di)从最后一个字符开始向中间移动
- push ax ;除法操作
- call get_str_length ;字符串长度在(cx)中
- push cx ;将字符长度入栈
- mov di, si
- add di, cx
- dec di ;(di)=最后一个字符的下标
- mov ax, cx
- mov cl, 2
- div cl ;该8位除法只针对长度小于512的字符串,>=512产生除法溢出
- mov ah, 0
- add ax, si ;;(ax)=字符中间下标,
- next_char_reserve:
- mov cx, ax ;(ax)是字符串中间下标
- sub cx, si ;if(cx == 0),字符串逆序完成
- jcxz str_reserve_end
- ;;交换前后字符
- mov cl, [si]
- mov ch, [di]
- mov [di], cl
- mov [si], ch
- dec di
- inc si
- jmp next_char_reserve
- str_reserve_end:
- pop cx ;字符创长度出栈
- pop ax
- pop di
- pop si
- pop ds
- ret ;end str_reserve
- ;;-------------------------------------------------------------------------------------
- ;; 名称:get_str_length
- ;; 功能:获取一个以0结束的字符串的长度
- ;; 入参:ds:si = 字符串首地址
- ;; 返回值:(cx) = 字符串长度
- ;;-------------------------------------------------------------------------------------
- get_str_length: ;返回值(cx)
- push ds
- push si
- mov cx, 0
- next_char:
- mov cl, [si]
- jcxz str_end
- inc si
- jmp short next_char
- str_end:
- mov cx, si
- pop si
- pop ds
- sub cx, si ;(cx)-(si)的值就是字符串长度
- ret ;end get_str_length
- ;;----------------------------------------------------------------------------------
- ;; 名称:fill_table
- ;; 功能:将data段(结构体数组)中的所有字段,转换成以零结束的字符串,存储到table段中,
- ;; 格式如下:
- ;; 0123456789012345678901234567890123456789|
- ;; 1975 16 3 5 |结束符
- ;; 入参:ds:si = table段首地址,es:di = ,es:bx
- ;; 补充说明: es:[di].0 = data中某一年份(4个byte)首地址
- ;; es:[di].84 = data中某一年份总收入(dword)首地址
- ;; es:[bx].168 = data中某一年份公司雇员(dw)字段首地址
- ;; 返回值:无
- ;; 该子模块调用了fill_blank,get_str_length,dtoc
- ;;----------------------------------------------------------------------------------
- fill_table:
- push es
- push di ;;(es):(di) = data中的数据
- push bx ;;(es):(bx) = data中的数据
- push ds
- push si ;;(ds):(si) = table中的数据
- push cx ;;控制各种循环及jcxp指令等
- push ax
- push dx ;;除法操作入参
- ;;填充年份
- mov cx, 4
- push di
- s0:
- mov al, es:[di]
- mov [si], al
- inc di
- inc si
- loop s0
- pop di
- ;;填充空格
- mov cx, 10 ;;cx绝对下标
- call fill_blank ;入参(cx), ds:si
- mov si, cx ;ds:si = 空格后(收入)字符串起始地址
- ;;填充公司收入 (si)=10H
- mov ax, es:[di+0].84
- mov dx, es:[di+2].84
- call dtoc
- call get_str_length ;(cx)=收入字符串长度
- add si, cx ;ds:si=收入字符串0结束符地址
- ;;填充空格
- mov cx, 20
- call fill_blank
- mov si, cx
- s4: ;;填充雇员数 2字节
- mov ax, es:168[bx] ;入参
- mov dx, 0 ;入参
- call dtoc
- call get_str_length
- add si, cx
- ;;填充空格,上面入栈的(di)没有出栈是因为计算人均收入时还要用到现在减半的(di)
- mov cx, 30
- call fill_blank
- mov si, cx
- ;;填充人均收入
- mov cx, es:168[bx] ;入参,这里的(di)是减半后的(di)
- mov ax, es:84[di] ;入参
- mov dx, es:84[di+2] ;入参
- call divdw
- call dtoc
- call get_str_length
- add si, cx
- ;;填充空格
- mov cx, 40
- call fill_blank
- mov si, cx
- ;;填充字符串结束符
- mov byte ptr [si], 0
- ;;end
- pop dx
- pop ax
- pop cx
- pop si
- pop ds
- pop bx
- pop di
- pop es
- ret ;;end fill table
- ;;--------------------------------------------------------------------------------------
- ;;名称:fill_blank
- ;;功能:将指定的一段偏移内存填充为空格字符
- ;;入参:ds:si = 填充空格起始下标,(cx) = 填充空格截止下标,该字节不会被空格填充
- ;;返回值:无
- ;;--------------------------------------------------------------------------------------
- fill_blank: ;;入参(cx)=填充空格截止下标,ds:si = 填充空格起始下标
- push ds
- push si
- push bx
- fill_next_blank:
- push cx ;填充空格截止下标入栈
- sub cx, si
- jcxz fill_blank_end ;(cx)==0时,栈顶为(cx)
- mov bl, 20H
- mov [si], bl
- inc si
- pop cx ;填充空格截止下标出栈
- jmp fill_next_blank
- fill_blank_end:
- pop cx
- pop bx
- pop si
- pop ds
- ret ;;end fill_blank
- ;;-------------------------------------------------------------------------------------
- code ends
- end start
复制代码
|
|