上机5

商品数组products中按照商品ID(0-9之间)保存的每样商品对应的价格(假设价格为整数),从键盘输入需要购买的一组商品的ID(假设一次性购买商品不超过10件),计算需要购买商品的总价,并显示出来。假设商品的价格为55,10,25,13,90,5,15,24,68,20(id为0~9)

代码1

.model small
.386

.data
array dw 55, 10, 25, 13, 90, 5, 15, 24, 68, 20
N equ ($-array)/2
order db N dup(10)
cost dw ?

.stack
dw 10 dup(?)

.code
main proc far
    mov ax, @data
    mov ds, ax      ;

    call input
    call calc
    call crlf       ; 输出回车
    call output

    mov ax, 4c00h
    int 21h
main endp
;------------------------------------------
;------------------------------------------ 显示回车换行
crlf proc near
    push dx         ; 保护现场
    mov dl, 0dh
    mov ah, 2
    int 21h
    mov dl, 0ah
    mov ah, 2
    int 21h
    pop dx
    ret
crlf endp
;------------------------------------------ 输入
input proc near
    push ax         ; 保护现场
    push cx
    push si

    mov ax, 0
    mov si, 0
    mov cx, N

readloop:
    ; 读取
    mov ah, 1
    int 21h
    ; 如果是回车,跳出
    cmp al, 0dh
    je endread
    ; 保存
    sub al, 30h     ; ascii 转 数字
    mov order[si], al
    inc si
    loop readloop

endread:
    pop si
    pop cx
    pop ax
    ret
input endp
;------------------------------------------ 输出(16进制转10进制,并输出)(除10取余法)
output proc near
    push ax
    push bx
    push cx
    push dx

    mov cx, 1
    mov bx, 10
    mov ax, cost
realin:
    div bx          ; 存余数
    push dx         ; 余数进栈
    cmp ax, 0       ; 是否已除净
    jle realout
    mov dx, 0
    inc cx
    jmp realin

realout:
    pop dx
    add dx, 30h
    mov ah, 2       ; 输出
    int 21h
    loop realout

    pop dx
    pop cx
    pop bx
    pop ax
    ret
output endp
;------------------------------------------ 计算
calc proc near
    push ax         ; 保存结果
    push bx         ; 临时存储 array 数组需要的元素
    push cx         ; 循环计数器
    push dx         ; 临时存储 order 数组需要的元素
    push si         ; order 下标

    mov ax, 0
    mov bx, 0
    mov cx, N
    mov dx, 0
    mov si, 0

calcloop:
    mov dl, order[si]
    ; 如果是 10(表示超出商品最大下标),跳出
    cmp dl, 10
    je endcalc

    push si         ; 保护 order 的下标
    mov si, dx
    add si, si      ; 操作16位数,两倍si

    ; 计算
    mov bx, array[si]
    add ax, bx

    pop si          ; 取出 order 的下标

    inc si
    loop calcloop

endcalc:
    ; 结束计算
    mov cost, ax
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    ret
calc endp
end main

代码2

ASSUME cs:code,ds:data
data SEGMENT
    commodity db 55,10,25,13,90,5,15,24,68,20
    id db 10 dup(0)
ENDS

code SEGMENT
start:
    mov ax,data
    mov ds,ax
;=========子函数执行==========
    call input;输入
    call calculate;计算
    call output;输出

    mov ah,4CH	
	int 21H	

input proc
        mov cx,10
        mov si,0

    s:
        MOV ah,01H     ;调用1号功能输入字符(只能输入一个字符)
        INT 21H

        cmp al,0dh
        je end_input;输入回车则结束输出

        sub al,48;al为 id

        mov ah,0 
        mov di,ax
        inc id[di];给对应的id 加1 
        ;例如 10件 id 为1的商品,id数组则为 10,0,0,0,0,0,0,0,0,0
    loop s
        ;输入10个则输出换行
        mov ah,02H
        mov dl,0AH
        int 21H
end_input:
    ret
input endp

;计算结果存放在bx中,
calculate proc
        mov cx,10
        mov si,0
        mov ax,0
        mov bx,0
    s1:
        ;al 商品价值
        ;dl 商品数量
        mov al,commodity[si]
        mov dl,id[si]

        mul dl
        ;dx中存放高位
        add bx,ax
        inc si
    loop s1
        ret
calculate endp

;入口为bx
output proc
        mov ax,bx;the number that needed to be output is saved in bx , now move it to ax
        mov bx,10
        mov cx,0;cx记录需要输出多少个个数
    division:  
        mov dx,0;dx每次除完必须置为0,否则回引起溢出问题
        div bx
        push dx; save the remainder in stack 
        inc cx
        cmp ax,0
        jne division ;if the ax is not zero,means still need ax still need to be divided

    ;!!! 必须先把栈清空在ret,使得ss:sp回到正常位置。否则ret无法正常工作
    ;提问网址 https://stackoverflow.com/questions/67950097/in-my-assembly-code-the-subroutine-returned-but-the-code-started-again-from-b
    print:
        pop dx
        add dl,48
        mov ah,02H
        int 21H
        loop print 

        ret 
output endp

ENDS
END start

上机6

从键盘输入n,计算其对应的斐波那契函数的fib(n),并输出结果。

代码1

.model small
.386

.data
buf db 20h
    db  0
    db 20h dup(?) 		; 缓冲区存储字符串
result dd ?             ; 32767 为dw最大表示数
n dd ?                  ; 字符串转换成数字后的临时存储单元

.stack
dw 100 dup(?)

.code
main proc far
    mov ax, @data
    mov ds, ax      ;

    call input
    call crlf       ; 输出回车
    call trans

    mov eax, n      ; eax 传参
    call fibo
    mov result, eax

    call output

    mov ax, 4c00h
    int 21h
main endp
;------------------------------------------
;------------------------------------------ 显示回车换行子程序
crlf proc near
    push dx         ; 保护现场
    mov dl, 0dh
    mov ah, 2
    int 21h
    mov dl, 0ah
    mov ah, 2
    int 21h
    pop dx
    ret
crlf endp
;------------------------------------------ 输入
input proc near
    push ax
    push dx         ; 保护现场

readloop:
    mov ah, 0ah
    lea dx, buf
    int 21h

endread:
    pop dx
    pop ax
    ret
input endp
;------------------------------------------ 输出(16进制转10进制,并输出)(除10取余法)
output proc near
    push eax
    push ebx
    push ecx
    push edx

    mov ecx, 1
    mov ebx, 10
    mov eax, result
realin:
    div ebx         ; 存余数
    push edx        ; 余数进栈
    cmp eax, 0      ; 是否已除净
    jle realout
    mov edx, 0
    inc ecx
    jmp realin

realout:
    pop edx
    add edx, 30h
    mov ah, 2       ; 输出
    int 21h
    loop realout

    pop edx
    pop ecx
    pop ebx
    pop eax
    ret
output endp
;------------------------------------------ 计算
fibo proc near
    push ebx
    push ecx
    push edx

    cmp eax, 1
    je endfibo
    cmp eax, 2
    je endfibo      ; n == 1 或 n == 2 返回 1

    mov edx, eax
    sub eax, 1
    call fibo
    mov ebx, eax

    mov eax, edx
    sub eax, 2
    call fibo
    mov ecx, eax

    mov eax, ebx
    add eax, ecx

    pop edx
    pop ecx
    pop ebx
    ret

endfibo:
    mov eax, 1
    pop edx
    pop ecx
    pop ebx
    ret
fibo endp
;------------------------------------------ 字符串转数字预处理
trans proc near
    push ax
    push bx
    push cx
    push dx
    push si

    mov dx, 0
    mov bx, 10
    mov si, 2
    mov ax, 0

maintrans:
    mov al, buf[si]
    cmp al, 0dh
    je endtrans
    sub al, 30h
    cmp n, 0
    je realtrans 
    push eax
    mov eax, n
    mul ebx
    mov n, eax  
    pop eax

realtrans:
    add n, eax
    mov eax, 0
    inc si
    jmp maintrans

endtrans:
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    ret
trans endp
end main

代码2

ASSUME cs:code,ds:data
data SEGMENT
    str db 10 dup(0)
    save_al db 0
    ten db 10
    temp dw 0
ENDS

code SEGMENT
start:
    mov ax,data
    mov ds,ax
;=========子函数执行==========
    call input
    call fib
    call output


    mov ah,4CH	
	int 21H	

;输入
input proc
        mov si,0
    s:
        MOV ah,01H     ;调用1号功能输入字符(只能输入一个字符)
        INT 21H

        cmp al,0dh
        je end_input ;输入回车则结束输出

        sub al,48;al为输入的字符
        mov str[si],al
        inc si

        jmp s ;不是回车则继续输入
end_input:

;结果存在bx中
call string_to_integer

    ret
input endp
; 把输入的string 转int 
string_to_integer proc
    mov cx,si
    mov al,1;从最后一位往前计算
    sub si,1
    mov bx,0
    s2:
        mov save_al,al
        mul str[si];执行完成后ax中存着这意味对应的十位数
        sub si,1

        add bx,ax
        mov al,save_al
        mul ten;al = al*10

    loop s2

    ret
string_to_integer endp

;计算斐波那契
fib proc
    ; 伪代码
    ; #bx中为结果
    ; ax=0
    ; bx=1
    ; if cx==0:
    ;     bx=0
    ; else if cx==1:
    ;     bx=1
    ; else
    ;     for i in range(cx):
    ;         ax= ax + bx
    ;         temp=ax
    ;         ax=bx
    ;         bx=tem
    mov cx,bx
    mov ax,0
    mov bx,1
    cmp cx,0
    je cx_equal_0
    cmp cx,1
    je cx_equal_1
    ;当 cx>1 时执行以下程序
    sub cx,1;cx 先减一
    s5:
    add ax,bx
    mov temp,ax
    mov ax,bx
    mov bx,temp
    loop s5
    ret 
    cx_equal_0:
        mov bx,0
        ret
    cx_equal_1:
        mov bx,1
        ret
fib endp
;入口为bx
output proc
        mov ax,bx;the number that needed to be output is saved in bx , now move it to ax
        mov bx,10
        mov cx,0;cx记录需要输出多少个个数
    division:  
        mov dx,0;dx每次除完必须置为0,否则回引起溢出问题
        div bx
        push dx; save the remainder in stack 
        inc cx
        cmp ax,0
        jne division ;if the ax is not zero,means still need ax still need to be divided

    ;!!! 必须先把栈清空在ret,使得ss:sp回到正常位置。否则ret无法正常工作
    ;提问网址 https://stackoverflow.com/questions/67950097/in-my-assembly-code-the-subroutine-returned-but-the-code-started-again-from-b
    print:
        pop dx
        add dl,48
        mov ah,02H
        int 21H
        loop print 

        ret 
output endp

ENDS
END start