[Hb-X] 课程设计I(寻址 数字转字符串 除法溢出 显示字符串)

来源:互联网 发布:如寡人者安与知耻的知 编辑:程序博客网 时间:2024/05/17 02:35

《汇编语言·第三版》--王爽


1 任务

将实验7中的Power idea公司的数据按照图10.2所示的格式在屏幕上显示出来。


在这个程序中,要用到前面学到的几乎所有的知识,主要选择适当的寻址方式和相关子程序的设计和应用。


另外,要注意,因为程序显示的数据有些已经大于65535,应该编写一个新的数据到字符串转化的子程序,完成dword型数据到字符串的转化,说明如下。

名称:dtoc

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

参数:(ax) = dword型数据的低16位,(dx) = dword型数据的高16位,ds:si指向字符串的首地址

返回:无

在这个子程序中要注意除法溢出的问题,可以用我们在实验IV中设计的子程序divdw来解决。


2 程序设计

(1) 程序流程图


Figure1. 程序设计图

divdw():解决“收入/员工”除法溢出问题,并得出员工平均工资。

dtoc():数字转字符串。

show_str():将Buf内以0结束的字符串以指定属性显示在指定的行列。


(2) 程序流程图对应的程序框架

1.        assume    cs:main,ss:stack

2.         

3.        ;数据段:存储欲显示在显存之上的数据

4.        data segment

5.                 db     '1975','1976','1977','1978','1979','1980','1981','1982','1983'

6.                 db     '1984','1985','1986','1987','1988','1989','1990','1991','1992'

7.                 db     '1993','1994','1995'

8.                 ;以上是表示21年的21个字符串

9.                

10.             dd     16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514

11.             dd     345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000

12.             ;以上是表示21年公司总收入的21个dword型数据

13.            

14.             dw    3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226

15.             dw    11542,14430,15275,17800

16.             ;以上是表示21年雇员人数的21个word型数据

17.    data ends

18.     

19.    ;缓存区

20.    buf   segment

21.             db     32 dup(0),0

22.    buf   ends

23.     

24.    ;堆栈段:(7 + 14 * 2)bytes足矣

25.    stack         segment

26.             dw    20     dup(0)

27.    stack         ends

28.     

29.     

30.    main         segment

31.    start:       

32.        main0:

33.            call   far ptr       read_year         ;调用read_year函数,将data段(si) + 1年份读到buf中,以0结束

34.            call   far ptr       show_str ;调用show_str显示在buf中的字符串

35.            

36.     

37.            call   far ptr read_money ;调用read_money读si年的收入,将收入的低16位保存到ax中,收入的高16位保存到dx中

38.            call   far ptr       dtoc          ;调用dtoc将ax和dx共同保存的数据转换为对应的字符串到buf中

39.            call   far ptr       show_str ;调用show_str显示在buf中的字符串

40.            

41.     

42.            call   far ptr       read_staff        ;调用read_staff读取data中的员工数目,(bx) =员工数目

43.            call   far ptr       dtoc          ;调用dtoc将ax和dx共同保存的数据转换为对应的字符串到buf中

44.            call   far ptr       show_str ;调用show_str显示在buf中的字符串

45.            

46.     

47.            call   far ptr read_money ;调用read_money读si年的收入,将收入的低16位保存到ax中,收入的高16位保存到dx中

48.            call   far ptr read_staff     ;调用read_staff读取data中si年的员工数目,(bx) =员工数目

49.            call   far ptr       dtoc          ;调用dtoc将ax和dx共同保存的数据转换为对应的字符串到buf中

50.            call   far ptr       show_str ;调用show_str显示在buf中的字符串

51.    loop main0

52.     

53.    mov    ax, 4c00h

54.    int 21h

3 子函数

编写子函数时,各子函数要主要压栈保存在子函数内会修改的寄存器变量值。


(1) 数字转字符串

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

2.        ;参数:(ax) = dword型数据的低16位,(dx) = dword型数据的高16位,ds:si指向字符串的首地址

3.        ;返回:无

4.                 dtoc:

5.                           push          ax

6.                           push          cx

7.                           push          dx

8.                           push          si

9.                          

10.                       mov cx, 0

11.                       push          cx     ;先将0入栈,作为标记

12.                     

13.                       dtc_s0:

14.                                mov cx,ax

15.                                add  cx,dx

16.                                jcxz  dtc_s1

17.                                mov cx,10

18.                                call   far ptr       divdw

19.                                add  cx,30h

20.                                push          cx

21.                                loop dtc_s0

22.                      

23.                       dtc_s1:    

24.                                pop cx

25.                                mov ds:[si],cl

26.                                jcxz  dtc_s2

27.                                inc    si

28.                                loop dtc_s1      ;将栈中数据取出  

29.                      

30.                       dtc_s2:

31.                                pop  si

32.                                pop  dx

33.                                pop  cx

34.                                pop  ax

35.         retf

(2) 解决除法溢出问题

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

2.        ;参数:(ax) = dword型数据的低16位,(dx) = dword型数据的高16位,(cx) = 除数

3.        ;返回:(dx) = 结果的高16位,(ax) = 结果的低16位,(cx) = 余数

4.                 divdw:

5.                           push          bx

6.                           push          si

7.                          

8.                           mov bx,ax

9.                           mov ax, dx

10.                       mov dx, 0

11.                      

12.                       div    cx     ;ax = int(H/N), dx = rem(H/N)

13.                       mov si, ax         ;si     =int(H/N), (dx) = rem(H/N) * 65536

14.                      

15.                       mov ax, bx

16.                       div    cx     ;(rem(H/N) * 65536 + L) / N, ax保存的低16位商,(dx) = 余数

17.                      

18.                       mov cx, dx

19.                       mov dx, si

20.                      

21.                       pop  si

22.                       pop  bx

23.         retf

(3) 显示字符串

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

2.        ;参数:(dh) = 行号(取值范围 0 ~ 24),(dl) = 列号(取值范围0 ~ 79),(cl) = 颜色,ds:si指向字符串的首地址

3.         ;返回:无

4.                 show_str:

5.                           push          ax

6.                           push          cx

7.                           push          dx

8.                           push          es

9.                           push          bp

10.                       push          di

11.                       push          si

12.                      

13.                       mov ax, 0b800h

14.                       mov es, ax        ;es段保存显存段地址

15.                      

16.                       mov al, cl ;字符前景色保存到al

17.                      

18.                       mov bp, 0

19.                       mov ch, 0

20.                       mov cl, dh

21.                       inc    cl

22.                       str_s0:

23.                                jcxz  str_s1

24.                                add  bp,160              ;行号对应的显存地址

25.                                loop str_s0

26.                       str_s1:

27.                                mov di,0

28.                                mov ch,0

29.                                mov cl,dl

30.                       str_s2:    

31.                                jcxz  str_s3

32.                                add  di,2           ;列号对应的显存地址

33.                                loop str_s2                ;es:[di + bp]为dh行dl列对应的显存地址

34.                               

35.                       str_s3:    

36.                                mov cl,ds:[si]

37.                                jcxz  str_s4                ;检测当前字符是否为0,如果为0则转移到s4处执行

38.                                mov         es:[bp+ di],cl

39.                                inc    di

40.                                mov         es:[bp+di], al           ;字符前景色

41.                                inc    di

42.                                inc    si

43.                                loop str_s3

44.                                        

45.                       str_s4:    

46.                                pop  si

47.                                pop  di

48.                                pop  bp

49.                                pop  es

50.                                pop  dx

51.                                pop  cx

52.                                pop  ax

53.         retf


(4) 用来读(寻址)data段数据的子函数

1.        ;功能:读取data段的(si)年份到buf中,以0结束

2.        ;参数:无

3.         ;返回:无

4.                 read_year:

5.                           push          ax

6.                           push          cx

7.                           push          dx

8.                           push          ds

9.                           push          si

10.                       push          bp

11.                      

12.                       mov ax, data

13.                       mov ds, ax

14.                       mov ax, 4

15.                       mul  si

16.                       mov si, ax         ;ds:[si]指向pop si,(si)年的年份

17.                      

18.                       mov ax, buf

19.                       mov es,ax

20.                       mov bp, 0         ;es:[bp]指向buf段的首个内存单元

21.                      

22.                       mov cx, 2

23.                       read_s0:

24.                                mov ax,ds:[si]

25.                                mov es:[bp],ax        ;年份低字节

26.                                add  si,2

27.                                add  bp,2

28.                                loop read_s0

29.                      

30.                       mov al, 0

31.                       mov es:[bp],al         ;字符串以0为结尾符

32.                      

33.                       pop  bp

34.                       pop  si

35.                       pop  ds

36.                      pop  dx

37.                       pop  cx

38.                       pop  ax

39.             Retf

40.     

41.     

42.    ;功能:读取data段的(si)年收入到(ax)和(dx)中

43.    参数:(si) = 第几年

44.     ;返回:(ax) = dword低16位,(dx)=dword高16位

45.             read_money:

46.                       push          si

47.                       push          ds

48.                      

49.                       mov ax, data

50.                       mov ds, ax

51.                       mov ax, 4

52.                       mul  si

53.                       mov si, ax

54.                       add  si, 84                  ;ds:[si]指向pop si年的收入

55.                      

56.                       mov ax,ds:[si]

57.                       mov dx,ds:[si + 2]

58.                      

59.                       pop  ds

60.                       pop  si

61.             Retf

62.     

63.     

64.     

65.    ;功能:读取data段的(si)年员工数到(ax)中

66.     ;参数:(si) = 第几年

67.     ;返回:(ax) = 员工数

68.             read_staff:

69.                       push          ax

70.                       push          dx     ;乘法会改变dx的值

71.                       push          si

72.                       push          ds

73.                      

74.                       mov ax, data

75.                       mov ds, ax

76.                       mov ax, 2

77.                       mul  si

78.                       mov si, ax

79.                       add  si, 168                ;ds:[si]指向pop si年的员工

80.                      

81.                       mov bx,ds:[si]

82.                      

83.                       pop  ds

84.                       pop  si

85.                       pop  dx

86.                       pop  ax

87.         retf

4 主程序

1.        main         segment

2.        start:        mov ax, stack

3.                 mov ss, ax

4.                 mov sp, 40                 ;ss:sp指向栈底

5.                

6.                 mov cx, 21                 ;每次读一年数据,一共21年的数据,需要读21次

7.                 mov si, 0           ;用来表示将要读取第(si) + 1年的数据

8.                 mov dx, 02h              ;第一年数据第一个数据在屏幕上显示的位置

9.                

10.             main_s1_3:

11.                       ;---------------显示年份--------------------------------------------

12.                       call   far ptr       read_year         ;调用read_year函数,将data段(si) + 1年份读到buf中,以0结束

13.                      

14.                       push          cx

15.                       push          si                         ;需要压栈保存寄存器的值

16.                       mov ax, buf

17.                       mov ds, ax

18.                       mov si, 0

19.                       mov cl, 02

20.                       call   far ptr       show_str ;调用show_str显示在buf中的字符串

21.                       ;---------------显示年份--------------------------------------------

22.                      

23.                       ;---------------显示收入--------------------------------------------

24.                       pop  si                         ;需要出栈使用寄存器的值

25.                       push          si

26.                       push          dx

27.                       call   far ptr read_money ;调用read_money读si年的收入,将收入的低16位保存到ax中,收入的高16位保存到dx中

28.                       mov bx, buf

29.                       mov ds, bx

30.                       mov si, 0

31.                       call   far ptr       dtoc          ;调用dtoc将ax和dx共同保存的数据转换为对应的字符串到buf中

32.                      

33.                       pop  dx

34.                       push          dx

35.                       mov ax, buf

36.                       mov ds, ax

37.                       mov si, 0

38.                       add  dl, 12

39.                       mov cl, 2

40.                       call   far ptr       show_str ;调用show_str显示在buf中的字符串

41.                       pop  dx

42.                       ;---------------显示收入--------------------------------------------

43.                      

44.                       ;---------------显示员工--------------------------------------------

45.                       pop  si

46.                       push          si

47.                       push          dx

48.                       call   far ptr       read_staff        ;调用read_staff读取data中的员工数目,(bx) =员工数目

49.                       mov ax, bx

50.                       mov dx, 0

51.                       mov bx, buf

52.                       mov ds, bx

53.                       mov si, 0

54.                       call   far ptr       dtoc          ;调用dtoc将ax和dx共同保存的数据转换为对应的字符串到buf中

55.                      

56.                       pop  dx

57.                      

58.                       push          dx

59.                       mov ax, buf

60.                       mov ds, ax

61.                       mov si, 0

62.                       add  dl, 24

63.                       call   far ptr       show_str ;调用show_str显示在buf中的字符串

64.                       pop  dx

65.                       pop  si

66.                      

67.                      

68.                       inc    si                         ;下一年数据

69.                       inc    dh                       ;显示在下一行

70.                      

71.                       pop  cx

72.                       loop main_s1_3

73.                       ;---------------显示员工--------------------------------------------

74.                      

75.                       ;---------------显示员工平均工资--------------------------------------------

76.                      

77.                       mov cx, 21                 ;每次读一年数据,一共21年的数据,需要读21次

78.                       mov si, 0           ;用来表示将要读取第(si) + 1年的数据

79.                       mov dx, 02h              ;第一年数据第一个数据在屏幕上显示的位置

80.             main_s4:

81.                       push          cx

82.                       push          dx

83.                       call   far ptr read_money ;调用read_money读si年的收入,将收入的低16位保存到ax中,收入的高16位保存到dx中

84.                       call   far ptr read_staff     ;调用read_staff读取data中si年的员工数目,(bx) =员工数目

85.                       mov cx, bx

86.                       call   far ptr divdw

87.                      

88.                       push          si

89.                       mov bx, buf

90.                       mov ds, bx

91.                       mov si, 0

92.                       call   far ptr       dtoc          ;调用dtoc将ax和dx共同保存的数据转换为对应的字符串到buf中

93.                       pop  si

94.                      

95.                       pop  dx

96.                       push          si

97.                       push          dx

98.                       mov ax, buf

99.                       mov ds, ax

100.                     mov si, 0

101.                     add  dl, 34

102.                     mov cl, 2

103.                     call   far ptr       show_str ;调用show_str显示在buf中的字符串

104.                     ;---------------显示员工平均工资--------------------------------------------

105.                     pop  dx

106.                     pop  si

107.                    

108.                     inc    si                         ;下一年数据

109.                     inc    dh                       ;显示在下一行

110.                    

111.                     pop  cx

112.           loop main_s4

113.                    

114.                     mov ax, 4c00h

115.                     int    21h

116.   

117.   ;子函数定义区

118.   

119.   main       ends

120.   end  start


5 运行结果

Figure2. 程序运行结果(未在下一页中显示)
[2014.12.16 - 18:42]
R《Hb》Note Over.

0 0
原创粉丝点击