王爽汇编语言课程设计1

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

;课程设计1

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

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

ASSUME CS:CODE,DS:DATA

 

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

DATA SEGMENT

    ;年份

    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 DD 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514

    DD 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000

    ;雇员人数

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

    DW 11542,14430,15257,17800

    AVERAGE DW 21 DUP (0)

    TABLE DB 21 DUP ('YEAR                                ',0)

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

DATA ENDS

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

 

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

CODE SEGMENT

START:

    MOV AX,DATA         ;初始化DS

    MOV DS,AX

   

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

    MOV CX,21           ;循环次数=21,21组数据

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

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

    STORE_ALL_YEAR:     ;保存所有的年份

    PUSH CX             ;压入外层循环次数

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

    STORE_ONE_YEAR:     ;保存一年的年份

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

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

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

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

    LOOP STORE_ONE_YEAR ;写入下一个字符

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

    POP CX              ;恢复外层循环次数

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

   

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

    MOV CX,21           ;循环次数=21,21组数据

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

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

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

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

    MOV AX,[BX]         ;16

    ADD BX,2            ;16

    MOV DX,[BX]

    CALL DTOC           ;转化为字符串

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

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

    MOV BYTE PTR [SI],' '   ;替换为空格

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

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

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

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

   

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

    MOV CX,21           ;循环次数=21,21组数据

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

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

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

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

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

    MOV DX,0            ;16位置零

    CALL DTOC           ;转化为字符串

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

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

    MOV BYTE PTR [SI],' '   ;替换为空格

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

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

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

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

   

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

    MOV CX,21           ;循环次数=21,21组数据

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

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

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

    GET_AVERAGE:

    PUSH CX         ;保存外层循环次数

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

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

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

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

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

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

    DIV CX              ;(AX)==人均收入AVERAGE

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

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

    POP CX              ;恢复外层循环次数

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

   

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

    MOV CX,21           ;循环次数=21,21组数据

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

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

    ADD SI,29               ;定位到AVERAGE

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

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

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

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

    CALL DTOC           ;转化为字符串

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

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

    MOV BYTE PTR [SI],' '   ;替换为空格

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

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

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

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

   

    ;输出各年的字符串

    MOV CX,21           ;循环次数=21,21组数据

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

    MOV DH,4            ;起始行数=4

    MOV DL,1            ;起始列数=1

    PRINT:              ;向屏幕输出

    PUSH CX         ;保存外层循环次数

    MOV CL,7            ;颜色=白色

    CALL SHOW_STR       ;显示一年的字符串

    POP CX              ;恢复外层循环次数

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

    INC DH              ;行号+1

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

   

    MOV AX,4C00H        ;程序返回

    INT 21H

 

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

;名称:DTOC(DIGITAL TOCHARACTER)

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

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

;返回:

DTOC PROC NEAR

    PUSH BX             ;保护现场

    PUSH DX

    PUSH CX

    PUSH AX

    PUSH SI

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

    DECIMAL_PLACE:

    MOV CX,10           ;除数=10

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

    ADD CX,30H          ;数字转化为ASCII

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

    INC BX              ;转化的位数+1

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

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

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

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

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

    POP CX              ;弹出一位数字的ASCII

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

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

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

    CMP BX,0            ;循环终止条件

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

    MOV AL,0

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

    POP SI              ;恢复现场

    POP AX

    POP CX

    POP DX

    POP BX

    RET                 ;返回

DTOC ENDP

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

 

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

;名称: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():取余

DIVDW PROC NEAR

    PUSH BX

    PUSH CX

    PUSH AX

    MOV AX,DX   ;(DX)储存到AX

    MOV DX,0    ;(DX)置零

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

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

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

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

    POP AX      ;(AX)=X的低16

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

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

    POP CX      ;恢复除数N

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

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

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

    POP BX

    RET

DIVDW ENDP

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

 

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

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

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

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

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

NEXT_STRING PROC NEAR

    PUSH AX         ;保护现场

    ZERO_OR_NOT:

    MOV AX,[SI]

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

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

    CMP AX,0        ;是不是结尾符0?

    JE END_OF_NUM_STRING        ;,则跳转到END_OF_NUM_STRING

    INC SI                      ;,SI+1

    JMP ZERO_OR_NOT             ;检测下一个byte

    END_OF_NUM_STRING:          ;是结尾符0

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

    POP AX          ;恢复现场

    RET             ;返回

NEXT_STRING ENDP

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

   

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

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

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

;返回:

SHOW_STR PROC NEAR

    PUSH AX             ;保护现场

    PUSH ES

    PUSH DX

    PUSH DI

    PUSH SI

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

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

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

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

    MOV DI,AX           ;转移到DI

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

    MUL DL              ;2×列号

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

    S:

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

    MOV ES:[DI],AX

    INC DI              ;准备写入颜色信息

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

    INC SI              ;准备输出下一个字符

    PUSH CX             ;保存颜色=(CL)

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

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

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

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

    POP CX              ;恢复颜色=(CL)

    INC DI              ;准备写入下一个字符

    JMP S               ;输出下一个字符

    END_SHOW:

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

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

    POP SI              ;恢复现场

    POP DI

    POP DX

    POP ES

    POP AX

    RET

SHOW_STR ENDP

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

 

CODE ENDS

END START

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

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值