decoder 发表于 2014-5-24 19:20:54

第十章课程设计1____源码————————

本帖最后由 decoder 于 2014-5-24 19:55 编辑

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'
      dd 16,22,382,1356,2390,8000,16000,24486,50065,97478,140417,197514
      dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
      dw 3,7,9,13,28,38,130,220,476,778,1001,1422,2258,2793,4037,5635,8226
      dw 11542,14430,15257,17800
data ends

buff_mem segment   
   db 1280 dup(0)   ;48个字节储存一行数据,共使用1008个字节为了内存对齐申请1280字节内存空间
buff_mem ends
;es:21年循环变量 3f0h3f0h
;es:年数据最低位 3f2h3f2h
;es:年数据次低位 3f3h3f3h
;es:年数据次高位 3f4h3f4h
;es:年数据最高位 3f5h3f5h
;es:除数         3f6h 3f6h
;es:四位十六进制数除法的低位商       3f8h 3f8h
;es:四位十六进制除法的   余数 3fah 3fah
;es:   ds:中bx的值         3fch 3fch
;es:保存bp的值    3f8h3feh
;es:保存di的值          0400h
;ds:保存字符处理循环中的临时cx变量
;ds:保存显示函数中的di
code segment
   start:            call get_data
                           call process_data   ;0014
                           call display_data
                           mov ax,4c00h
                           int 21h
      
    get_data:       mov ax,data
                        mov ds,ax
      ret
   process_data:                                    ;ip=0014
                           ;初始化
                         mov ax,buff_mem ;es指向buff_memes=0b5e
                         mov es,ax
                         mov bx,0
                         mov si,84         ;数据偏移到收入地址
                         mov bp,0
                         mov di,48            ;行递增数据,初始化为距左边4字节
                         mov cx,21
                                                
   _loop_21_:   push cx      ;保存21年的循环
                        mov es:,di      ;保存21年循环中di的当前值
                        mov es:,bp
                        call covent_year      ;年份       ip=0086
                        call covent_summ      ;资产       ip=00a3
                        call covent_ne          ;人数       ip=00e0
                        call covent_pcdi      ;人均收入
                        pop cx
                        dec cx
                        jcxz _l_21_out
                        add bp,4
                        add di,2ch
                        add word ptr es:,4      ;bx镜像递增
                        mov bx,es:
                           jmp _loop_21_
      _l_21_out:ret      
                                                
      display_data:      
                        mov ax,0b80ah
                        mov es,ax
                        mov ax,buff_mem
                        mov ds,ax
                        mov bx,0
                        mov si,0
                        mov bp,0
                        mov di,20h
                        mov cx,21
                                                
                     b:push cx
                        push di            ;用来定位要显示字符的位置
                        push bx            ;用来定位要载入字符的位置
                        mov ds:,di   ;定位年列的位置
                        mov cx,4
          get_year: push cx            ;年份字符串的循环处理
                        mov cx,ds:    ;取得年份字符的
                        mov es:,cx
                        pop cx
                        add bx,2
                        add di,2
                        loop get_year
                        add di,16
                        mov cx,8
                        mov ax,0
                        add word ptr ds:,16   ;定位资产列的位置
                        mov di,ds:
_get_summ:   push cx            ;资产字符串的循环处理
                        mov cx,ds:
                        jcxz _summ_eq0   ;判断字符是否为空,在48字节的段中去掉空格存入显存
                        mov es:,cx
                        add di,2
_summ_eq0:    add ax,2
                         add bx,2
                         pop cx
                         loop _get_summ
                         add di,16
                         mov cx,8
                         sub di,ax
                         add di,16
                         add word ptr ds:,20;定位人员列的位置
                         mov di,ds:
get_ne:            push cx
                         mov cx,ds:             ;取得人员的字符
                         jcxz _cx_ne_eq_0;判断字符是否为空,在48字节的段中去掉空格存入显存
                         mov es:,cx
                         add di,2
_cx_ne_eq_0: add ax,2
                         add bx,2
                         pop cx
                         loop get_ne
                         add di,16
                         mov cx,4
                         sub di,ax
                         add di,32
                         add word ptr ds:,16;定位人均收入列的位置
                         mov di,ds:
get_sr:            push cx
                         mov cx,ds:             ;取得人均收入位置的字符
                         jcxz _cx_sr_eq_0    ;判断字符是否为空,在48字节的段中去掉空格存入显存
                         mov es:,cx
                         add di,2
_cx_sr_eq_0:add ax,2
                         add bx,2
                         pop cx
                         loop get_sr
                         add di,16
                         pop bx
                         pop di
                         add di,0a0h
                         add bx,48
                         pop cx
                         dec cx
                         jcxz dp_out
                         jmp b            ;此处原本用loop循环,但循环溢出,只能使用jmp段内转移
dp_out:             ret


covent_year:    push bx                      ;ip=0086   年份字符串处理
                         push si
                         push bp
                         push di
                         mov cx,4
                                                
_loop_str:      mov al,byte ptr ds:;年的单位字节数据
                        mov byte ptr es:,al
                        mov byte ptr es:,07h
                        inc bx
                        add bp,2
                        loop    _loop_str
                     pop di
                     pop bp
                     pop si
                     pop bx
    ret
      
covent_summ: push bx                     ;ip=00a3资产字符串处理
                     push si
                     push bp
                     push di
                     mov ax,word ptr ds:
                     mov dx,word ptr ds:
                     mov word ptr es:,10
_div_loop:       call divdw                  ;cx为余数,ax为商
                     mov word ptr es:,cx   ;余数用来做显示位
                     add word ptr es:,30h;转换成字符
                     mov ax,word ptr es:   ;字符放入ax
                     mov ah,07h                   ;把ah变成颜色位
                     mov word ptr es:,ax   ;保存入显示缓冲中
                     mov ax,word ptr es:    ;低位商
                     mov cx,ax
                     jcxz _div_out                ;只要低位商为零就跳出
                     sub bp,2                     ;从后往前放资产值
                     jmp _div_loop
_div_out:      pop di
                     pop bp
                     pop si
                     pop bx
            ret
      
covent_ne:    push bx                     ;ip=00e0   人员字符串处理
                      push si
                      push bp
                      push di
                      push word ptr es:
                                                
                      mov cx,es:             ;被保存的bx的值??????
                      mov ax,cx                     
                      jcxz _init_data               ;检测第一次循环bx是否为零,若为零则跳过-2步骤
                      mov dx,0
                      mov cx,2
                      div cx                        ;4/2,8/2,12/2,16/2....
                      mov bx,ax                     ;2,4,6,8....
                                                
_init_data:   mov ax,ds:      ;ax的值是ne部分
                      mov dx,0                     ;因为都是求余数,并且人数不会超过32位
_divw_loop:   call divdw
                      mov word ptr es:,cx   ;余数用来做显示位
                      add word ptr es:,30h;转换成字符
                      mov ax,word ptr es:   ;放入ax
                      mov ah,07h                   ;把ah变成颜色位
                      mov word ptr es:,ax   ;保存入显示缓冲中32-8-20
                      mov ax,word ptr es:   ;低位商
                      mov dx,0
                      mov cx,ax
                      jcxz _divw_out                ;只要低位商为零就跳出
                                                
                      sub bp,2                      ;从右到左(从小到大)写数据
                      jmp _divw_loop
_divw_out:    pop word ptr es:
                      pop di
                      pop bp
                      pop si
                      pop bx
                                                
      ret      
      
covent_pcdi:                                    ;ip=013b人均收入字符串处理
                     push bx                     ;ip=00e0   人员字符串处理
                     push si
                     push bp
                     push di
                     push word ptr es:
                     mov ax,word ptr ds:      ;把资产低位当作被除数
                     mov dx,word ptr ds:    ;把资产高位当作被除数
                     push ax                           ;此处注意保存ax和dx的值
                     push dx
                                                
                     mov cx,es:             ;被保存的bx的值??????
                     mov ax,cx                     
                     jcxz _init_ne_data               ;检测第一次循环bx是否为零,若为零则跳过-2步骤
                     mov dx,0
                     mov cx,2
                     div cx                        ;4/2,8/2,12/2,16/2....
                     mov bx,ax                     ;2,4,6,8....
                                                
_init_ne_data: pop dx                        ;还原dx和ax的值
                     pop ax
                     mov cx,ds:
                     mov word ptr es:,cx   ;把人数当作除数
                     call divdw
                     mov word ptr es:,ax   ;商用来做人均收入的被除数
                     mov word ptr es:,10   ;循环中的除数,意思是缩小十倍
                     mov dx,0
      pcdi_:    call divdw
                     mov word ptr es:,cx   ;余数用来做显示位
                     add word ptr es:,30h;转换成字符
                     mov ax,word ptr es:   ;字符放入ax
                     mov ah,07h                   ;把ah变成颜色位
                     mov word ptr es:,ax;保存入显示缓冲中
                     mov ax,word ptr es:    ;低位商
                     mov cx,ax
                     jcxz pcdi_out                ;只要低位商为零就跳出
                     sub bp,2                     ;从后往前放资产值
                     jmp pcdi_
                                                
pcdi_out:      pop word ptr es:
                     pop di
                     pop bp
                     pop si
                     pop bx
      ret      
      
      divdw:                  
                  push ax   ip= 0175h
                  mov ax,dx
                   mov dx,0
                  div word ptr es:    ;ax=ax/【x】 高位商dx=ax/cx高位余如果高位为零,则全为零
                  mov bx,ax ;bx=ax 如果高位被除为零则取ES:的值为商
                  pop ax   ;ax=低位被除数 dx=在进行高位除法时作为高位被除数,低位时为余数(隐含高位被除数)
                   div word ptr es:   ;dx:ax= 14240/ cx= 0f
                   mov es:,ax ;保存低位除法的商
                   mov cx,dx;将余数保存在cx
                   mov dx,bx;将商保存在dx(高位商)
      ret      
code ends
end start

传说。 发表于 2014-5-25 01:31:34

碉堡了。。。。。

传说。 发表于 2014-5-25 01:34:00

楼主可有divdw 的解释?那里我不理解。 高16位 低16位怎么算出原数的商和余数。有推导么?
而且还是16进制的。搞不懂。跪求啊!!!

15岁的小朋友 发表于 2014-5-25 09:41:07

传说。 发表于 2014-5-25 01:34
楼主可有divdw 的解释?那里我不理解。 高16位 低16位怎么算出原数的商和余数。有推导么?
而且还是16进制 ...

书里后面有公式证明 在附注5

decoder 发表于 2014-5-25 11:38:24

15岁的小朋友 发表于 2014-5-25 09:41 static/image/common/back.gif
书里后面有公式证明 在附注5

此楼正解   哎,没啥话可说非得要我补齐十个字啊?又不是灌水
页: [1]
查看完整版本: 第十章课程设计1____源码————————