王爽《汇编语言》第 3 版 实验 课程设计 1

warning: 这篇文章距离上次修改已过710天,其中的内容可能已经有所变动。
assume cs:codesg

stacksg segment stack
    dw 0,0,0,0,0,0,0,0
    dw 0,0,0,0,0,0,0,0
    dw 0,0,0,0,0,0,0,0
    dw 0,0,0,0,0,0,0,0
stacksg ends

datasg 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,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
datasg ends

dataview segment
    db 16 dup (0)
    db 16 dup (0)
dataview ends


table segment
    db 21 dup ('????????????????'),0
table ends

codesg segment
start:

    mov ax,datasg
    mov ds,ax
    mov ax,table
    mov es,ax
    mov ax,stacksg
    mov ss,ax
    mov sp,64

    mov cx,21 ;设置循环次数为 21 次
    mov bx,0 ;每个循环加 4
    mov si,0 ;每个循环加 2
    mov di,0 ;每个循环加 16

    s1:
        ;1  处理年份
        mov ax,ds:[bx]
        mov dx,ds:[bx+2]
        mov es:[di],ax
        mov es:[di+2],dx

        ;2 处理收入
        mov ax,ds:[bx+84]
        mov dx,ds:[bx+86]
        mov es:[di+5],ax
        mov es:[di+7],dx

        ;3 处理雇员数量
        mov ax,ds:[si+168]
        mov es:[di+10],ax

        ;4 处理人均收入
        mov ax,es:[di+5]
        mov dx,es:[di+7]
        div word ptr es:[di+10]
        mov es:[di+13],ax


        ;处理 4 个 空格
        mov al,' '
        mov es:[di+4],al
        mov es:[di+9],al
        mov es:[di+12],al
        mov es:[di+15],al

        ;循环计数器累加
        add si,2
        add bx,4
        add di,16
    loop s1


    mov cx,21 ;设置循环次数为 21 次
    mov bx,0 ;每个循环加 16
    mov ax,table
    mov es,ax

    mov ax,dataview
    mov ds,ax

    mov dh,4
    mov dl,1

    s2:
        mov bp,cx ;备份 cx
        mov dl,1

        ;打印年份
        mov ax,es:[bx+0]
        mov ds:[0],ax
        mov ax,es:[bx+2]
        mov ds:[2],ax
        mov byte ptr ds:[4],0h

        mov cl,2
        mov si,0
        call show_str

        ;打印 收入
        mov cx,dx
        mov ax,es:[bx+5]
        mov dx,es:[bx+7]
        call fn_dtoc

        mov dx,cx
        add dl,16
        mov si,0
        mov cl,2
        call show_str

        ;打印 雇员数量
        mov cx,dx
        mov ax,es:[bx+10]
        mov dx,0h
        call fn_dtoc
        mov dx,cx
        add dl,16
        mov si,0
        mov cl,2
        call show_str

        ;打印 人均收入
        mov cx,dx
        mov ax,es:[bx+13]
        mov dx,0h
        call fn_dtoc
        mov dx,cx
        add dl,16
        mov si,0
        mov cl,2
        call show_str


        ;循环计数器累加
        add bx,16

        inc dh
        mov cx,bp ;还原 cx
    loop s2


    ;call show_str
    mov ax,4c00H
    int 21H



    ;把给定的字符串交换位置 比如: 1234 变成 4321
    ;段地址放 ds 起始地址放 si 长度放 cx
    fn_chang_str:

        ;如果字符串长度为 1 就返回
        sub cx,1
        jcxz label_fn_chang_str_return_now
        inc cx

        push ax
        push dx
        push bx
        push bp

        mov ax,cx ;这里做除法用
        mov dx,cx ;这里把长度放的 bx 中后面要用
        mov ch,0
        mov cl,2
        div cl ;这时 al=商 ah = 余数

        sub dx,1
        mov cl,al
        mov bp,0
        label_fn_chang_str_3:
            mov ah,ds:[bp+si]
            mov bx,dx
            sub bx,bp
            mov al,ds:[si+bx]
            mov ds:[bp+si],al
            mov ds:[si+bx],ah
            inc bp
            loop label_fn_chang_str_3

        label_fn_chang_str_return:
            pop bp
            pop bx
            pop dx
            pop ax

        label_fn_chang_str_return_now:
            ret

    ;把一个数值变成可以显示的 ascii 码
    ;高位放 dx
    ;低位放 ax
    ;无返回, 结果直接写到 dataview:[0]
    fn_dtoc:

        push cx
        push bx
        push ds
        push si

        mov bx,dataview
        mov ds,bx
        mov si,0


        label_fn_dtoc_j:
            mov cx,10
            call fn_divdw
            mov bx,cx
            add bx,30h
            mov ds:[si],bx
            add si,1
            mov cx,ax
            jcxz label_fn_dtoc_return
            jmp short label_fn_dtoc_j


        label_fn_dtoc_return:
            ;翻转
            mov cx,si
            mov byte ptr ds:[si],0
            mov si,0
            call fn_chang_str


            pop si
            pop bx
            mov ds,bx
            pop bx
            pop cx

            ret

    ;不会溢出的除法
    ; 被除数低位放 ax, 被除数高位放 dx,除数放 cx
    ; 结果: 高16 位放 dx,低 16 位放 ax, 余数放 cx
    fn_divdw:
        ;备份 reg
        push bp
        push bx

        ;1 算 H/N
        ;备份 被除数低 16 位放到 bp 中
        mov bp,ax
        mov ax,dx
        div cl
        mov bx,ax  ;这时候 bl 是 H/N 的商,bh 是 H/N 的余数

        ;算 [rem(h/n)*65536+L]/N
        mov dh,0
        mov dl,bh
        mov ax,bp
        div cx  ; ax=商,dx=余

        ;把结果放到相关寄存器中
        mov cx,dx

        mov dh,0
        mov dl,bl

        pop bx
        pop bp
        ret

    ; 在指定的位置打印指定的字符串
    ;  dh = 行号  dl= 列号 cl = 颜色 si = 要打印的字符串地址
    show_str:
        ;1 暂存子程序用到的寄存器
        push ax ;备份 ax
        push bx ;备份 bx
        push cx ;备份 cx
        push dx ;备份 dx
        push es    ;备份 es

        ;2 设置显存地址,段地址放入 es 中
        mov ax,0b800h
        mov es,ax ;设置显存段地址

        ;3 设置指定的行和列的显示偏移地址放入 bx 中
        push cx ;因为后面 loop 要用到 cx ,所以再备份一次
        mov ch,0
        mov cl,dh ;把参数行号放入 cx 中准备 loop
        mov bx,0 ;要把实际的行偏移地址放在 bx 中,所以清理 bx 准备放数据
        sub cx,1 ;cx-1 是因为要在第 8 行显示的话,地址加到第 7 行就行了
        setrows:
            add bx,160 ;这里加 160 是一行显示 80 个字符,每个字符占用 1 个字
            loop setrows
        mov ch,0
        mov cl,dl
        sub cx,1
        setcols:
            add bx,2
            loop setcols
        pop cx
        mov dh,cl
        mov ch,0

        mov ax,16 ; 如果不够 20 个字符就用空格补齐

        ;3 读取 data 中的字符, 直到读取到 0 为止
        readdata:
            mov cl,ds:[si]
            jcxz next_01
            mov dl,cl
            mov es:[bx],dx
            inc si
            add bx,2
            sub ax,1
            jmp short readdata

        next_01:
            mov cx,ax
            mov dl,20h
        addspace:
            jcxz return_show_str
            add bx,2
            mov es:[bx], dx
            sub cx,1
            jmp short addspace

        ;返回
        return_show_str:

            pop es
            pop dx
            pop cx
            pop bx
            pop ax
            ret
codesg ends
end start

1719309261605.png1719309261605.png

寄存器太少, 很多还指定寄存器, 要不停的备份,还原

none
最后修改于:2024年06月25日 17:57

添加新评论