1)显示字符串
assume cs:codeseg, ds:data data segment db 'Welcome to masm!', 0 data ends codeseg segment start: mov dh, 8 ; 行 mov dl, 3 ; 列 mov cl, 2 ; 颜色 ; 数据开始 mov ax, data mov ds, ax mov si, 0 call show_str mov ax, 4c00h int 21h ; 显示字符串 ; @desc 参数:dh => 行,dl => 列,cl => 颜色,ds:si => 字符串地址,以要 0 结尾 show_str: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 保存寄存器 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; show_str_start: push ax push bx push dx push cx push es push si ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 开始实现功能 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 显存 B8000 - BFFFF,我们使用 B800 作为段地址 ; 段空间位 64K,而显存只有 32K,所以不会超过段 ; 第一步、设置段地址 mov ax, 0B800H mov es, ax ; es => 写入字符的段地址 ; 第二步、计算偏移量 ; 每行的长度:0 - 9F | 每列的宽度:两字节,高位颜色,低位字符 ; 写入字符的开始地址 = (行号 - 1) x 0A0H + 列号 x 2 sub dh, 1 mov al, dh mov bl, 0A0H mul bl ; ax add dl, dl mov dh, 0 ; dx add dx, ax ; ax => 写入字符的开始地址 mov bx, dx ; 第三步、开始写入 mov ah, cl ; 颜色 copy_char: mov cl, ds:[si] ; 判断字符是否为零 mov ch, 0 jcxz show_str_end mov al, cl mov es:[bx], ax ; 将字符写入显存 inc si add bx, 2 jmp short copy_char ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 恢复寄存器 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; show_str_end: pop si pop es pop cx pop dx pop bx pop ax ret codeseg ends end start
2)解决除法溢出问题
assume cs:codeseg codeseg segment start: mov ax, 4240H ; LOW mov dx, 000FH ; HIGH mov cx, 0AH call divdw mov ax, 4c00H int 21h ; 解决除法溢出问题 ; @desc 参数:dx => 被除数高位,ax => 被除数低位,cx => 除数 ; @desc 结果:dx => 结果高位,ax => 结果低位,cx => 余数 divdw: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 保存寄存器 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 根据题目,并结合我们的实现方式,只有 bx 寄存器是“借用”的, ; 其他寄存器(ax, dx, cx)会被使用,并且内容会被改变 ; 因此无需保存 push bx ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 开始计算除法 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 第一部分、计算【int(H/N) * 65536】Start push ax ; 由于需要使用 ax 寄存器,所以先保存 ax 寄存器(即初始的低位值) mov ax, dx ; 开始计算 int(H/N) mov dx, 0 div cx ; 此时:ax => 商,这就是“结果的高 16 位”;dx => 余数,即 rem(H/N) 值 mov bx, ax ; 后面需要使用 ax 寄存器,因此将 ax 保存到 bx 中 ; 第二部分、计算【[rem(H/N) * 65536 + L]/N】 ; [rem(H/N) * 65536 + L]/N 是 16 位除法,因为 N 为 16 位(既初始的 cx 寄存器) ; [rem(H/N) * 65536 + L]/N 等价于: ; (1)将“高位(000FH)除法的余数”放在 dx 寄存器中 ; (2)将低位(4240H)放在 ax 寄存器中 ; (3)然后除以 cx 寄存器 ; (1)而前一步的除法已经将余数放在 dx 寄存器中, ; (2)因此设置 ax 寄存器即可,即将低位放入 ax 中 ; (3)然后除以 cx 寄存器 pop ax ; 由于 ax 的值之前写入到栈中,此时弹出 div cx ; => ax...dx ; 按照实验要求,存储计算结果 mov cx, dx mov dx, bx ; mov ax, ax ; 由于 ax 已经存储低位,因此无需处理 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 恢复寄存器 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pop bx ret codeseg ends end start
3)数值显示
assume cs:codeseg dateseg segment db 10 dup (0) dateseg ends codeseg segment start: mov ax, 12666 mov bx, dateseg mov ds, bx mov si, 0 call dtoc mov dh, 8 ; 行 mov dl, 3 ; 列 mov cl, 2 ; 颜色 call show_str mov ax, 4c00H int 21H ; 将数值转化为字符换 ; @desc 参数:dx => 数据高位,ax => 数据低位,ds:si => 数据写入地址 ; @desc 结果:保存到 ds:si 中,并以 0 结尾 dtoc: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 保存寄存器 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; push ax push bx push cx push dx ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 实现逻辑 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 计算数值字符串 mov bx, 0 push bx ; 无需理解此步骤,往下看就知道了 _do_some_stuff_start: mov dx, 0 mov ax, ax mov bx, 10 div bx ; dx,ax / bx = ax...dx add dx, 30H push dx ; 余数,计算结果与显示结果是相反的。先入栈再弹出 mov cx, ax jcxz _do_some_stuff_end ; 如果商为零,则结束 jmp short _do_some_stuff_start ; 继续运行,进行下一轮除法 _do_some_stuff_end: ; 将数值写到数据段 mov bx, 0 save_to_dateseg: pop cx ; 最开始我们在栈底写入零,用于标识数据弹出结束(再弹就不是我们的数据了) jcxz _append_zero_to_sting ; 跳转到结束 mov ds:[bx], cl ; 这里保留低位即可,高位没有意义,而且字符只占一个字节 inc bx jmp short save_to_dateseg ; 字符串末尾追加零,因为 show_str 要求字符串以 0 结尾 _append_zero_to_sting: mov byte ptr ds:[bx], 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 恢复寄存器 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; dtoc_end: pop dx pop cx pop bx pop ax ret show_str: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 保存寄存器 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _show_str_start: push ax push bx push dx push cx push es ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 开始实现功能 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 显存 B8000 - BFFFF,我们使用 B800 作为段地址 ; 段空间位 64K,而显存只有 32K,所以不会超过段 ; 第一步、设置段地址 mov ax, 0B800H mov es, ax ; es => 写入字符的段地址 ; 第二步、计算偏移量 ; 每行的长度:0 - 9F | 每列的宽度:两字节,高位颜色,低位字符 ; 写入字符的开始地址 = (行号 - 1) x 0A0H + (列号-1) x 2 sub dh, 1 mov al, dh mov bl, 0A0H mul bl ; ax sub dl, 1 add dl, dl mov dh, 0 ; dx add dx, ax ; ax => 写入字符的开始地址 mov bx, dx ; 第三步、开始写入 mov ah, cl ; 颜色 _copy_char: mov cl, ds:[si] ; 判断字符是否为零 mov ch, 0 jcxz _show_str_end mov al, cl mov es:[bx], ax ; 将字符写入显存 inc si add bx, 2 jmp short _copy_char ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 恢复寄存器 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _show_str_end: pop es pop cx pop dx pop bx pop ax ret codeseg ends end start
相关文章
「汇编语言 第 3 版 王爽」- 参考答案:检测点 13.1
「汇编语言 第 3 版 王爽」- 参考答案:检测点 11.2
「汇编语言 第 3 版 王爽」- 参考答案:检测点 16.2
「汇编语言 第 3 版 王爽」- 参考答案:实验 15 安装新的 int 9 中断例程
「汇编语言 第 3 版 王爽」- 参考答案:实验 7 寻址方式在结构化数据访问中的应用
「汇编语言 第 3 版 王爽」- 参考答案:实验 14 访问 CMOS RAM
参考文献
CSDN/汇编语言王爽第三版答案
百度文库/汇编语言实验答案 (王爽)