鱼C论坛

 找回密码
 立即注册
查看: 2648|回复: 5

[技术交流] 课程设计1,弄好好久,终于出来了,有注释。

[复制链接]
发表于 2011-12-2 11:20:47 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
assume cs:code,ds:data
data segment
   db 1000 dup (0)
   db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
   db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
   db '1993','1994','1995'
   
   dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
   dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
   
   dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
   dw 11542,14430,15257,17800
data ends

code segment
start:
      mov ax,data
      mov ds,ax                ;将data的偏移地址写入ds
   
     mov bx,0
     mov si,1000
     mov di,0                 ;初始化bx,si,di的值,data段首定义了1000个0,所以si的值等于1000
   
     call year                ;调用子程序:year(年)
   
     mov bx,0
     mov cx,0
     mov bp,0
     mov si,1084
     mov di,0                 ;初始化bx,cx,bp,si,di的值,21年年收入的第一个数据的偏移地址等于1084  

(1000+84,1000是data段首写义的1000个0,84是21年*4=84个字节)
   
     call income              ;调用字程序,income(年收入)
   
     mov bx,0
     mov cx,0
     mov bp,0
     mov si,1168
     mov di,0                 ;初始化bx,cx,bp,di和si的值,第三组数据——公司员工数的第一个数据地址为ds:[si],si=1168d
   
     call staff               ;调用子程序staff(员工),该子程序的作用是将员工数显示出来
   
     mov bp,0
     mov bx,0
     mov si,1084
     mov di,1168              ;初始化,si用来指向公司年收入数据,再写入ax和dx作为被除数;di用来指向公司职工数,再写入cx作为除数
   
     call renjun              ;调用子程序renjun(人均),该程序的作用是算出人均收入,并转换成ASCII码值,写入显存
   
     mov ax,4c00h
     int 21h                  ;程序返回,打完收功!
   
xianshi:                       ;子程序:xianshi(显示)开始,该子程序的作用是计算行与列的偏移地址
     mov ax,160               ;一行有160个字节,所以ax=160
     dec dh                  
     mul dh                   ;行数减1后和ax相乘,计算出行数的偏移地址
     mov bx,ax                ;再将行数的偏移地址写入bx
   
     mov ax,2                 ;一列有2个字节,所以ax=2
     dec dl                  
     mul dl                   ;列数减1后和ax相乘,计算出列数的偏移地址
     add bx,ax                ;再将列数的偏移地址和行数的偏移地址相加,存入bx
   
     mov al,cl                ;cl保存的是字符属性,将cl转存入al,因为后面的程序中要占用到cl
   
     ret                      ;返回
   
year:                          ;字程序year(年)开始
      push ax
     push bx
     push cx
     push dx
     push si
     push di                  ;将ax,bx,cx,dx,si,di压栈
   
     mov ax,0b800h
     mov es,ax                ;将偏移地址b800h写入es。b800h是显存的地址
      
     mov dh,3
     mov dl,24
     mov cl,02               ;定义行数、列数、字符属性
   
     call xianshi            ;调用字程序,xianshi(显示)
   
     mov cx,21               ;循环21次,有21年嘛。呵呵
   s:mov di,0               
     push cx                 ;将cx压栈,后面嵌套循环还要用到cx

     mov cx,4                ;嵌套循环开始,循环4次
s1:mov ah,[si]             ;将(ds:[1000])处的值写入ah
     mov es:[bx+di],ah       ;将ah写入(es:[bx+di])处(将字符写入显存)
     mov es:[bx+di+1],al     ;将al写入(es:[bx+di+1])处(将字符属性写入显存)
     inc si                  ;si自增1
     add di,2                ;di自增2,一列有两个字节嘛
     loop s1                 ;返回s1
   
     add bx,160              ;第一年四个字符都写入显存后,第二年的四个字符要换一行显示,所以bx要加160
     pop cx                  
   
     loop s                  ;返回到s处继续循环
      
     pop di
     pop si
     pop dx
     pop cx
     pop bx
     pop ax                  ;还原di,si,dx,cx,bx,ax的值
   
     ret                     ;返回

income:                       ;字程序income(年收入)开始
     push ax
     push bx
     push cx
     push dx
     push si
     push di
     push bp                 ;妈的,又要入栈啊,没办法。整吧!
   
     mov cx,21               ;又要循环21回
   
s2:mov bp,0                ;初始化bp为0,作用是在子程序divw中记录将dx压栈的次数,再将bp写入cx作为循环次数
     mov ax,[si]             ;把(ds:[1084])处的值写入ax(32位中的低16位)
     mov dx,[si+2]           ;把(ds:[si+2])处的值写入dx(32位中的高16位)
   
     call divw               ;调用子程序:divw,该程序的作用是进行不会溢出的除法,从而算出每一位数的ASCII码值
   
     add si,4                ;不用我说了吧!32位的!

     loop s2                 ;返回s2循环21回
   
     mov dh,3
     mov dl,33
     mov cl,02               ;知道什么意思吧,不会吧?真的不知道??我靠!定义行数、列数和字符属性!
   
     call xianshi            ;调用子程序xianshi(显示)
   
     mov si,0                ;初始化si和di的值,si=0,那么ds:[si]就直接指向data段首
     mov di,0                ;这个用说了,地球人都知道。
   
     mov cx,21               ;又来一个21回的循环,谁叫他妈的是21年呢。
   
s6:push cx
   
s5:mov cl,[si]             ;将(ds:[si])处的值写入cl
     mov ch,0
   
     jcxz ok2                ;判断cx是否为0,若为0则跳到ok2处执行,若不为0则向下执行
   
     mov es:[bx+di],cl      
     mov es:[bx+di+1],al     ;将cl和al写入显存
   
     inc si                  ;si自增1
     add di,2                ;di加2,因为一列有两个字节
   
     jmp short s5            ;跳到s5继续循环
   

ok2:add bx,160              ;上面的cx为0,则跳到此处,要换一行显行下一个数据,所以bx加160
      inc si            
     mov di,0                ;di初始化为0,因为只是加了一行,列数不变
      
     pop cx
     loop s6                 ;这个你懂的
   
     pop bp
     pop di
     pop si
     pop dx
     pop cx
     pop bx
     pop ax                 ;郁闷的POP

     ret                    ;嘿嘿
   
divw:                        ;子程序divw开始,进行不会溢出的除法,从而算出每一位数的ASCII码
     push bx
     push cx
     push dx
     push si                ;“我不想说,我很纯洁”
      
s3:mov cx,10              ;除数为10,除以10才能算出一组数据每一位上的数值,再加30h就得出ASCII码值,再......
     push ax
     mov ax,dx
     mov dx,0
     div cx
     mov bx,ax
     pop ax
     div cx
     mov cx,ax             ;进行不会溢出的除法,这个都不懂的话,去翻书,别问我
   
     jcxz ok1              
   
     add dx,30h
     push dx
     inc bp                ;核心部分,算出一组数据每一位数的ASCII码值,push保存,保存一次,bp自增1
   
     mov dx,bx            
     jmp short s3          ;bx的值写入高16位dx,再跳到s3继续进行不会溢出的除法
   
ok1:add dx,30h
      push dx
      inc bp                 ;核心部分,算出一组数据每一位数的ASCII码值,push保存,保存一次,bp自增1
   
     mov cx,bp              ;把bp的值写入cx,准备进行循环
   

  s4:pop ax
      mov [di],al
     inc di
     loop s4                ;循环四回,将前面push进去的dx的ASCII码值依次写入ds:[di]
   
     mov byte ptr [di],0    ;一组数据写入完成以后,写一个0进去,方便在以后在程序中jcxz命令能准确判断一组数据是否写完
     inc di
   
     pop si
     pop dx
     pop cx
     pop bx                 ;忠实的pop
   
    ret
   
staff:                       ;子程序staff(员工)开始
     push ax
     push bx
     push cx
     push dx
     push si
     push di
     push bp                ;没完没了的push
   
     mov cx,21               ;又要循环21回
   
s9:push cx                 ;将cx入栈,以后还会用到cx
      mov bp,0                ;初始化bp为0,作用是在子程序divw中记录将dx压栈的次数,再将bp写入cx作为循环次数
      mov ax,[si]             ;把(ds:[si])处的值写入ax,si的初始值是1168d,被除数最历害的一组是17800d,除以10d是不会溢出的,所以直接做除法运算就OK
      
s7:mov cx,10               ;定义除数为10
      mov dx,0                ;dx一定要设为0,因为它默认是32位除法的高16位
      div cx                  ;开始除了
      mov cx,ax               ;把商写入cx,方便jcxz命令判断其是否为0
  
      jcxz ok3                ;判断cx是否为0,为0则跳到ok3执行
   
      add dx,30h              ;dx加30h,将其变成ASCII码
      push dx
      inc bp                  ;一样的,push dx一次,bp就自增1,作为后面循环的依据
   
      jmp short s7            ;跳回s7继续
   
ok3:add dx,30h              ;上面cx为0,则跳到此处,把最后一次余数(dx)加30h变成ASCII码
      push dx
      inc bp                  ;原理同上
   
      mov cx,bp               ;将bp的值写入cx准备循环
s8:pop ax                  
      mov [di],al
      inc di                  ;将之前压入栈的dx逐个出栈,再写入ds:[di]保存
      loop s8
   
      mov byte ptr [di],0     ;一组数据结束后,写入一个0,方便以后的程序中jcxz命令的判断
      inc di
   
      add si,2                ;不用我说了吧,16位的
      
      pop cx                  ;还原cx的值,确保循环21次
      loop s9                 ;返回s8循环21回
      
      mov dh,3
      mov dl,43
      mov cl,02               ;知道什么意思吧,不会吧?真的不知道??我靠!定义行数、列数和字符属性!
   
      call xianshi            ;调用子程序xianshi(显示)
   
      mov si,0                ;初始化si和di的值,si=0,那么ds:[si]就直接指向data段首
      mov di,0                ;这个用说了,地球人都知道。
   
      mov cx,21               ;又来一个21回的循环,谁叫他妈的是21年呢。
   

s11:push cx
   
s10:mov cl,[si]             ;将(ds:[si])处的值写入cl
      mov ch,0
   
      jcxz ok4                ;判断cx是否为0,若为0则跳到ok2处执行,若不为0则向下执行
   
      mov es:[bx+di],cl      
      mov es:[bx+di+1],al     ;将cl和al写入显存
   
      inc si                  ;si自增1
      add di,2                ;di加2,因为一列有两个字节
   
      jmp short s10            ;跳到s10继续循环
   
ok4:add bx,160              ;上面的cx为0,则跳到此处,要换一行显行下一个数据,所以bx加160
      inc si            
      mov di,0                ;di初始化为0,因为只是加了一行,列数不变
      
      pop cx
      loop s11                ;这个你懂的
   
      pop bp
      pop di
      pop si
      pop dx
      pop cx
      pop bx
      pop ax                 ;郁闷的POP

      ret                    ;嘿
   
renjun:                      ;子程序renjun(人均)开始
      push ax
      push bx
      push cx
      push dx
      push si
      push di
      push bp               ;发现打这些push速度已经很快了
   
      mov cx,21             ;21年,不想再说了
s14:mov bp,0              ;bp记录入栈记数,一组数据结束,bp还原为0
      push cx               ;保存起来,后面还要用到cx
   
      mov ax,[si]
      mov dx,[si+2]         ;定义被除数
      mov cx,[di]           ;定义除数
   
      div cx                ;不会溢出的,直接除算了,这次除是为了先算出人均年收入
   
s12:mov cx,10d            ;定义除数,这一次是用来算出人均收入数据的ASCII码值的
      mov dx,0              ;dx一定要设为0,它表示的是32位的高16位
   
      div cx                ;直接整,没事儿
   
      mov cx,ax             ;将ax写入cx,方便后面jcxz好判断
      jcxz ok5              ;判断,如果cx为0,则跳到ok5
   
      add dx,30h            ;余数dx加上30h,就是人均收入数据每一位上的数的ASCII码值
      push dx               ;将dx入栈保存
      inc bp                ;每入一次栈,bp就自增1,作用是为了cx的循环提供依据
   
      jmp short s12         ;跳回s12继续
   
ok5:add dx,30h
      push dx
      inc bp                ;上面如果cx为0,则跳到此处,最后一位数加30h变成ASCII码......  
   
      mov cx,bp             ;将bp的值写入cx,为循环提供依据
s13:pop ax                ;将之前入栈的dx的ASCII码出栈到ax
      mov [bx],al           ;将al写入data段首
      inc bx
      loop s13
   
      mov byte ptr [bx],0   ;写一个0进去,方便后面的jcxz命令判断
      inc bx

      pop cx                ;还原cx的值
   
      add si,4
      add di,2              ;(ds:[si])指向的是32位的数据,故si+4;(ds:[di])指向的是16位的数据,故di+2
   
      loop s14              ;返回到s14继续
   
      mov dh,3
      mov dl,53
      mov cl,2              ;定义行、列、字数属性
   
      call xianshi          ;调用子程序xianshi(显示)
   
      mov si,0
      mov di,0              ;初始化si和di,使ds:[si]指向data段首,di指向显存的列
   
      mov cx,21             ;21年

s16:push cx               ;入栈保存
   
s15:mov cl,[si]
      mov ch,0
   
      jcxz ok6              ;将(ds[si])写入cl,ch为0,判断cx是否为0,为0则跳
   
      mov es:[bx+di],cl
      mov es:[bx+di+1],al   ;写入显存
   
      inc si
      add di,2              ;si自增1,di加2(一列两个字节)
   
      jmp short s15         ;跳到s15继续
   
ok6:add bx,160
      inc si
      mov di,0              ;一组数据写完,跳一行再写另一组数据,故bx加160;每一组数据,列数不变,故di=0
   
      pop cx                ;还原cx
      loop s16         ;跳到s16继续
   
      pop bp
      pop di
      pop si
      pop dx
      pop cx
      pop bx
      pop ax                 ;不想说了
   
      ret
   
code ends
end start


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-12-2 11:37:30 | 显示全部楼层
有很多语句多余的,适当的进行下优化吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-12-2 11:54:41 | 显示全部楼层
需要优化哇
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-12-2 19:54:24 | 显示全部楼层
恭喜楼主完成课程设计1,向楼主如此的认真态度学习!!!{:1_1:}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2013-10-10 20:52:21 | 显示全部楼层
丛败你。。。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2013-10-11 13:03:04 | 显示全部楼层
楼主很厉害哈
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-17 09:48

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表