王爽汇编语言课程设计1

来源:互联网 发布:淘宝卖家微淘怎么开通 编辑:程序博客网 时间:2024/05/19 17:51

;===============================================================================

;课程设计1

;将实验7中的power idea公司的数据按照格式在屏幕上显示.

;===============================================================================

ASSUMECS:CODE,DS:DATA

 

;-------------------------------------------------------------------------------

DATASEGMENT

   ;年份

   YEAR DB'1975','1976','1977','1978','1979','1980','1981','1982','1983'

   DB'1984','1985','1986','1987','1988','1989','1990','1991','1992'

   DB'1993','1994','1995'

   ;年收入

   INCOME DD16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514

   DD345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000

   ;雇员人数

   EMPLOYEE_NUM DW3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226

   DW11542,14430,15257,17800

   AVERAGE DW21DUP(0)

   TABLE DB21DUP('YEAR                               ',0)

   ;字符串的长度为25H(包括结尾符)

DATAENDS

;--------------------------------------------------------------------------------

 

;--------------------------------------------------------------------------------

CODESEGMENT

START:

   MOVAX,DATA        ;初始化DS

   MOVDS,AX

   

   ;输出年份的字符串到数据表各年字符串的年份段

   MOVCX,21          ;循环次数=21,21组数据

   MOVBX,0           ;年份的起始偏移地址

   MOVSI,OFFSET TABLE ;输出数据的表的起始偏移地址

   STORE_ALL_YEAR:    ;保存所有的年份

   PUSHCX            ;压入外层循环次数

   MOVCX,4           ;年份有4个字符,循环次数为4

   STORE_ONE_YEAR:    ;保存一年的年份

   MOVAL,[BX]        ;字符转移到AL

   MOV[SI],AL        ;AL中的字符转移到表

   INCBX             ;BX+1,准备读取下一个字符

   INCSI             ;SI+1,准备写入下一个字符

   LOOP STORE_ONE_YEAR ;写入下一个字符

   ADDSI,21H         ;定位到下一年份的起始偏移地址

   POPCX             ;恢复外层循环次数

   LOOP STORE_ALL_YEAR ;准备写入下一年份的数据

   

   ;转换收入为字符串并输出到数据表各年字符串的收入段

   MOVCX,21          ;循环次数=21,21组数据

   MOVSI,OFFSET TABLE ;输出数据的表的起始偏移地址

   ADDSI,10          ;指向第一组数据的收入那一项的偏移地址

   STORE_ALL_INCOME:  ;储存所有年份的收入

   PUSHSI            ;保存当前字符串收入项内存单元的偏移地址

   MOVAX,[BX]        ;16

   ADDBX,2           ;16

   MOVDX,[BX]

   CALL DTOC           ;转化为字符串

   CALL NEXT_STRING    ;SI指向下一个字符串收入项内存单元的偏移地址

   DECSI             ;SI指向收入项字符串的结尾符0

   MOVBYTEPTR[SI],' '  ;替换为空格

   POPSI             ;恢复为当前字符串收入项内存单元的偏移地址

   ADDBX,2           ;准备读取下一年份的收入

   ADDSI,25H         ;SI指向数据表中下一年份收入那一项的偏移地址

   LOOP STORE_ALL_INCOME   ;储存下一年份的收入数据

   

   ;转换雇员数为字符串并输出到数据表各年字符串的雇员数段

   MOVCX,21          ;循环次数=21,21组数据

   MOVSI,OFFSET TABLE ;输出数据的表的起始偏移地址

   ADDSI,20          ;指向第一组数据的雇员数那一项的偏移地址

   STORE_ALL_EMPLOYEE_NUM:;储存所有年份的雇员数

   PUSHSI        ;保存当前字符串雇员数项内存单元的偏移地址

   MOVAX,[BX]        ;16,(AX)=雇员数

   MOVDX,0           ;16位置零

   CALL DTOC           ;转化为字符串

   CALL NEXT_STRING    ;SI指向下一个字符串雇员数项内存单元的偏移地址

   DECSI             ;SI指向雇员数项字符串的结尾符0

   MOVBYTEPTR[SI],' '  ;替换为空格

   POPSI             ;恢复当前字符串雇员数项内存单元的偏移地址

   ADDBX,2           ;准备读取下一年份的雇员数

   ADDSI,25H         ;SI指向数据表中下一年份雇员数那一项的偏移地址

   LOOP STORE_ALL_EMPLOYEE_NUM ;存储下一年份的雇员数

   

   ;计算各年的人均收入并储存到AVERAGE

   MOVCX,21          ;循环次数=21,21组数据

   MOVSI,OFFSET AVERAGE       ;(SI)=AVERAGE项的起始偏移地址

   MOVBX,OFFSET INCOME        ;(BX)=INCOME项的起始偏移地址

   MOVDI,OFFSET EMPLOYEE_NUM ;(DI)=EMPLOYEE_NUM项的起始偏移地址

   GET_AVERAGE:

   PUSHCX        ;保存外层循环次数

   MOVAX,[BX]    ;(AX)=收入的低16

   ADDBX,2           ;BX+2,准备读取收入的高16

   MOVDX,[BX]    ;(DX)=收入的高16

   ADDBX,2           ;BX+2,准备读取下一年份的收入

   MOVCX,[DI]    ;(CX)=雇员数

   ADDDI,2           ;DI+2,准备读取下一年份的雇员数

   DIVCX             ;(AX)==人均收入AVERAGE

   MOV[SI],AX    ;转移到AVERAGE的内存单元中

   ADDSI,2           ;SI+2,准备写入下一年份的人均收入

   POPCX             ;恢复外层循环次数

   LOOP GET_AVERAGE    ;存储下一年份的平均收入AVERAGE

   

   ;转换人均收入为字符串并输出到数据表各年字符串的人均收入段

   MOVCX,21          ;循环次数=21,21组数据

   MOVBX,OFFSET AVERAGE   ;(BX)=AVERAGE项的起始偏移地址

   MOVSI,OFFSET TABLE     ;输出数据的表的起始偏移地址

   ADDSI,29              ;定位到AVERAGE

   STORE_ALL_EVERAGE:     ;储存所有年份的平均收入

   PUSHSI        ;保存当前字符串人均收入项内存单元的偏移地址

   MOVAX,[BX]        ;(AX)=人均收入的低16

   MOVDX,0           ;(DX)=人均收入的高16(0)

   CALL DTOC           ;转化为字符串

   CALL NEXT_STRING    ;SI指向下一个字符串人均收入项内存单元的偏移地址

   DECSI             ;SI指向人均收入项字符串的结尾符0

   MOVBYTEPTR[SI],' '  ;替换为空格

   POPSI             ;恢复当前字符串人均收入项内存单元的偏移地址

   ADDBX,2           ;准备读取下一年份的人均收入

   ADDSI,25H         ;SI指向数据表中下一年份人均收入那一项的偏移地址

   LOOP STORE_ALL_EVERAGE  ;存储下一年份的人均收入

   

   ;输出各年的字符串

   MOVCX,21          ;循环次数=21,21组数据

   MOVSI,OFFSET TABLE ;输出数据的表的起始偏移地址

   MOVDH,4           ;起始行数=4

   MOVDL,1           ;起始列数=1

   PRINT:             ;向屏幕输出

   PUSHCX        ;保存外层循环次数

   MOVCL,7           ;颜色=白色

   CALL SHOW_STR       ;显示一年的字符串

   POPCX             ;恢复外层循环次数

   ADDSI,25H         ;SI指向下一个字符串开始的内存单元的偏移地址

   INCDH             ;行号+1

   LOOP PRINT          ;输出下一年份的字符串

   

   MOVAX,4C00H       ;程序返回

   INT21H

 

;----------------------------------------------------------------------------  

;名称:DTOC(DIGITAL TOCHARACTER)

;功能:DWORD型数据转变为表示十进制数的字符串,字符串以0为结尾符。

;参数:(AX)=DWORD型数据的低16,(DX)=DWORD型数据的高16,(SI),DS:SI指向字符串的首地址

;返回:

DTOCPROCNEAR

   PUSHBX            ;保护现场

   PUSHDX

   PUSHCX

   PUSHAX

   PUSHSI

   MOVBX,0           ;BX用来计数,转化了多少位数字

   DECIMAL_PLACE:

   MOVCX,10          ;除数=10

   CALL DIVDW          ;(AX)=商的低16,(DX)=商的高16,(CX)=余数

   ADDCX,30H         ;数字转化为ASCII

   PUSHCX            ;压入(CL)=每一位数字的ASCII

   INCBX             ;转化的位数+1

   CMPDX,0           ;商的高16位是不是0?不是则未取得10进制数的每一位数字

   JNE DECIMAL_PLACE   ;如果不是0,则还没有转化完,继续取得下一位数字

   CMPAX,0           ;商的低16位是不是0?不是则未取得10进制数的每一位数字

   JNE DECIMAL_PLACE   ;如果不是0,则还没有转化完,继续取得下一位数字

   TRANSFER:          ;依次把十进制数每一位数的ASCII码送到DS:SI开始的内存单元

   POPCX             ;弹出一位数字的ASCII

   MOV[SI],CL        ;传送到DS:[SI]

   INCSI             ;SI+1,准备传送下一个字符的ASCII

   DECBX             ;每传送一个字符循环次数-1

   CMPBX,0           ;循环终止条件

   JNE TRANSFER        ;如果不为零继续传送

   MOVAL,0

   MOV[SI],AL        ;改写数字字符串的最后一个byte的数据为0作为结尾符

   POPSI             ;恢复现场

   POPAX

   POPCX

   POPDX

   POPBX

   RET                ;返回

DTOCENDP

;-----------------------------------------------------------------------------

 

;-----------------------------------------------------------------

;名称:DIVDW

;功能:进行不会产生溢出的除法运算,被除数位dword型,除数为word型,

;   结果为dword型。

;参数:(AX)=dword型数据的低16 ,(DX)=dword型数据的高16 ,(CX)=除数

;返回:(AX)=结果的低16 ,(DX)=结果的高16 ,(CX)=余数

;应用的公式:X/N = INT(H/N)*FFFF + [REM(H/N)*FFFF+L]/N

;X=被除数(0~FFFFFFFF),N=除数(0~FFFF),H=X的高16(0~FFFF),

;L=X的低16(0~FFFF),INT():取商,REM():取余

DIVDWPROCNEAR

   PUSHBX

   PUSHCX

   PUSHAX

   MOVAX,DX  ;(DX)储存到AX

   MOVDX,0   ;(DX)置零

   DIVCX     ;16位除法,H/N,(AX)=,(DX)=余数

   MOVBX,AX  ;AX中高16位的结果转移到BX

   MOVAX,0   ;(DX)=REM(H/N)*FFFF16,(AX)=REM(H/N)*FFFF16=0

   MOVCX,AX  ;(CX)=REM(H/N)*FFFF16

   POPAX     ;(AX)=X的低16

   ADDCX,AX  ;(CX)=REM(H/N)*FFFF+L的低16

   MOVAX,CX  ;(AX)=REM(H/N)*FFFF+L的低16

   POPCX     ;恢复除数N

   DIVCX     ;(AX)=结果的低16,(DX)=结果的余数

   MOVCX,DX  ;(CX)=结果的余数

   MOVDX,BX  ;(DX)=结果的高16

   POPBX

   RET

DIVDWENDP

;-------------------------------------------------------------------

 

;-----------------------------------------------------------------------------

;功能:SI从本字符串开始的内存单元的偏移地址指向下一个字符串开始的内存单元的

;    偏移地址,字符串以0为结尾符。

;参数:(SI)=本字符串开始的内存单元的偏移地址

;返回:(SI)=下一个字符串开始的内存单元的偏移地址

NEXT_STRINGPROCNEAR

   PUSHAX        ;保护现场

   ZERO_OR_NOT:

   MOVAX,[SI]

   MOVAH,0       ;!!!如果AX的低8(要比较的字符)0而高8位不为0

                   ;!!!则程序不能如期望的那样跳转到END_OF_NUM_STRING

   CMPAX,0       ;是不是结尾符0?

   JE END_OF_NUM_STRING        ;,则跳转到END_OF_NUM_STRING

   INCSI                     ;,SI+1

   JMP ZERO_OR_NOT             ;检测下一个byte

   END_OF_NUM_STRING:         ;是结尾符0

   INCSI                     ;SI+1,指向下一个字符串开始的内存单元的偏移地址

   POPAX         ;恢复现场

   RET            ;返回

NEXT_STRINGENDP

;------------------------------------------------------------------------------

   

;--------------------------------------------------------------------------------

;功能:在指定的位置,用指定的颜色,显示一个用0结尾的字符串。

;参数:(DH)=行号(0~24),(DL)=列号(0~79),(CL)=颜色,DS:SI指向字符串的首地址。

;返回:

SHOW_STRPROCNEAR

   PUSHAX            ;保护现场

   PUSHES

   PUSHDX

   PUSHDI

   PUSHSI

   MOVAX,0B800H      ;显示缓冲区段地址

   MOVES,AX          ;(ES)=显示缓冲区段地址

   MOVAL,0A0H        ;以下计算初始字符的偏移地址

   MULDH             ;行数×0A0H(160个字节)

   MOVDI,AX          ;转移到DI

   MOVAL,2           ;显示缓冲区中一个字符占两个字节空间

   MULDL             ;2×列号

   ADDDI,AX          ;获得初始字符的偏移地址

   S:

   MOVAX,DS:[SI]     ;输出字符到显示缓冲区

   MOVES:[DI],AX

   INCDI             ;准备写入颜色信息

   MOVES:[DI],CL     ;写入颜色信息

   INCSI             ;准备输出下一个字符

   PUSHCX            ;保存颜色=(CL)

   MOVCX,DS:[SI]     ;(CX)=下一个字符

   MOVCH,0           ;!!!DS:[SI]的低位字节为零,但其高位字节不为零,

                       ;!!!则程序不能如期望的那样跳转到END_SHOW

   JCXZ END_SHOW       ;不为零则继续输出,为零则结束子程序

   POPCX             ;恢复颜色=(CL)

   INCDI             ;准备写入下一个字符

   JMP S               ;输出下一个字符

   END_SHOW:

   POPCX             ;!!!如果(CX)≠0,就会跳转到这里,此时(CX)在栈中还没有弹出

                       ;!!!如果不弹出就会引发错误

   POPSI             ;恢复现场

   POPDI

   POPDX

   POPES

   POPAX

   RET

SHOW_STRENDP

;--------------------------------------------------------------------------------

 

CODEENDS

END START

;--------------------------------------------------------------------------------

0 0
原创粉丝点击