实验10问题3数值显示
本帖最后由 奥普瓯江 于 2018-11-19 00:24 编辑这个破问题可是坑哭我了,弄了很久很久,如有什么不对的地方还望指点一二,如果有什么更简单高效的书写方法也请不吝指教谢谢谢谢{:7_117:}
assume cs:code, ds:data1, ds:data2, ds:data3
data1 segment
dw 123, 12666, 1, 8, 3, 38, 0
data1 ends
data2 segment
db 10 dup (0)
data2 ends
data3 segment
db 20 dup (0)
data3 ends
code segment
start:
mov di, 0
mov si, 0
one_str:
mov ax, data1
mov ds, ax
mov ax, word ptr ds:
mov cx, ax
jcxz one_end
push si
mov si, 0
mov bx, data2
mov ds, bx
mov bx, data3
mov es, bx
call div_str
pop si
add si, 2
jmp short one_str
one_end:
mov dh, 8
mov dl, 3
mov cl, 2
call show_str
mov ax, 4C00H
int 21H
div_str:
mov dx, 0
mov bx, 10
div bx
add dl, 30H
mov byte ptr ds:, dl
mov cx, ax
jcxz div_end
inc si
jmp short div_str
div_end:
mov al, byte ptr ds:
mov byte ptr es:, al
mov cx, si
inc di
jcxz chang_str
dec si
jmp short div_end
chang_str:
mov byte ptr es:, 20h
inc di
ret
show_str:
dec dh
mov ax, 0A0H
mul dh
mov bx, ax
mov ax, 2
mul dl
sub ax, 2
add bx, ax
mov ax, 0b800h
mov ds, ax
mov si, 0
mov di, 0
mov al, cl
ok:
mov cl, byte ptr es:
mov ch, 0
jcxz good
mov byte ptr ds:, cl
mov byte ptr ds:, al
inc si
add di, 2
jmp short ok
good:
ret
code ends
end start
以下为我按照我的理解所做的注释
assume cs:code, ds:data1, ds:data2, ds:data3
data1 segment
dw 123, 12666, 1, 8, 3, 38, 0
data1 ends
data2 segment
db 10 dup (0)
data2 ends
data3 segment
db 20 dup (0)
data3 ends
code segment
start:
mov di, 0 ;初始化di寄存器为零
mov si, 0 ;初始化si寄存器为零
one_str:
mov ax, data1 ;把data1数据段的段地址传给ax
mov ds, ax ;把ax数据传给ds寄存器,使得数据段可以被调用
mov ax, word ptr ds:;把data1中的两个字节的数据传给ax寄存器
mov cx, ax ;把ax中数据传给cx已被jcxz验证
jcxz one_end ;判断cx是否为零如果不为零不执行该条语句
push si ;使得si寄存器的数据进入栈中暂时保存,这里要注意栈的调用只能是两个字节也就是十六位数据不能是八位数据
mov si, 0 ;再次初始化si,这里可以再次调用si是因为si以进栈,在循环重复的时候si将被pop从新赋值所以不影响si的使用
mov bx, data2 ;把data2数据段的段地址传给bx因为8086中只有ax和bx能被直接赋值,所以他俩需要交替使用,在这里ax以被使用所以就调用bx使他间接赋值给ds
mov ds, bx ;把bx中的数据传给ds,因为这个循环是从one_str开始的所以从新付给ds数据并不冲突
mov bx, data3 ;把data3的值付给bx
mov es, bx ;把bx数据传给es使得可以向data3数据段中读取写入数据
call div_str ;跳转到div_str标记处
pop si ;把si的数值从栈中取回,并在此赋给si
add si, 2 ;data1中的si加2
jmp short one_str ;无条件跳转回one_str,该程序一共需要循环6次,因为data1中有六组word数据第七组是0
one_end: ;上面的循环执行完毕后跳转到该处向下执行上面数据转换和排序等执行完毕后,以下的数据就是显示数据
mov dh, 8 ;把他显示在第八行
mov dl, 3 ;第三列这个地方
mov cl, 2 ;显示是字体所呈现的属性,绿字
call show_str ;跳转到字符标记处show_str:,当遇到ret这条语句就跳转回来,并继续向下执行
mov ax, 4C00H ;结束语句
int 21H ;结束语句
div_str: ;16进制数转换成10进制的方法是用10除以16进制数每次的余数就是十进制数的一个元素,直到被除数为0结束
mov dx, 0 ;初始dx寄存器数据,这里初始dx主要是为了div运算如果不初始化div运算就会报错
mov bx, 10 ;初始bx中的数据为10
div bx ;执行除法运算,被除数高位存放在dx中低位存放在了ax中,除数存放在了bx中,商存放在ax中余数存放在dx中
add dl, 30H ;给余数加30h因为在ascii码中1的代码是31剩下的以此类推
mov byte ptr ds:, dl;把加30h后的余数传到data2中暂时储存
mov cx, ax ;把被除数的数据传给cx
jcxz div_end ;如果cx中的数据是0那么执行本条语句,跳转到div_end标记处,如果cx中的数据不是0那么什么也不做继续执行下一条语句
inc si ;使得si自动加1
jmp short div_str ;无条件跳转到div_str标记处,jmp与jcxz是搭配使用的jcxz是他的结束条件
div_end: ;下列语句主要是把顺序倒了的数据调转过来并传到data3数据段
mov al, byte ptr ds:;把data2中本次本次循环si这个字节传给al八位寄存器
mov byte ptr es:, al;al八位寄存器中的数据传给data3这个数据段偏移地址di这个位置
mov cx, si ;把si中的数据传给cx
inc di ;di自动加1
jcxz chang_str ;当cx中的数据为0的时候跳转到chang_str这个标记位置,如果cx中的数据不是0就什么也不做继续执行下一条语句
dec si ;si 自动减1
jmp short div_end ;无条件跳转回div_end
chang_str:
mov byte ptr es:, 20h ;给米格段后面加上一个空格
inc di ;di自动加一
ret ;返回call div_str向下执行
show_str:
dec dh ;先让行数自动减一因为计算机是从0开始计算的,8行计算机计算的时候是从0开始的到7
mov ax, 0A0H ;因为每一行是160个字节换算成16进制就是A0H,把被乘数赋给ax因为mul计算的时候是用ax乘一个寄存器或者内存单元
mul dh ;乘法运算,最后乘积保存在ax中
mov bx, ax ;把ax传给bx暂时保存,因为我们还有第二个乘法需要使用到ax寄存器
mov ax, 2 ;第二个乘法被乘数传给ax
mul dl ;乘法运算,乘积传给ax,3列每一列时2个字节一个字所以这里乘以2
sub ax, 2 ;乘积减2这里的减2是因为计算机是从0开始运算的所以上面那三个列是从0开始的也就是0到2,这所说的列是一字为单位的不是以字节所以上面乘以2
add bx, ax ;用行数字节数加上列数字节数最后定位到的就是我们要在屏幕那个地方输出,最后数据传输给bx
mov ax, 0b800h ;把0B800H这个段地址传给ax
mov ds, ax ;把ax中的数据传给ds使得他可以被读写
mov si, 0 ;初始化si寄存器为零
mov di, 0 ;初始化di寄存器为零
mov al, cl ;把cl中字体的属性参数传给al因为我们下面要调用cl
ok:
mov cl, byte ptr es:;把data3中si位置的数据传给cl中,这样可以及可以传输数据也可以有做下面的jcxz做判断是否跳转,因为汇编规定,内存段中不能相互传输数据,必须得借助寄存器
mov ch, 0 ;初始化ch防止ch中有数据
jcxz good ;如果cx中数据是0及执行该条语句跳转到good标记处,如果不是0就不执行该语句
mov byte ptr ds:, cl;把cl中的数据传给显示段地址0B800H偏移地址bx+di处
mov byte ptr ds:, al;把属性传给段地址0B800H偏移地址bx+di+1处
inc si ;si+1
add di, 2 ;di+2因为显示段一次性是输入两个字节的数据所以di+2
jmp short ok ;跳转回ok标记处继续执行输出
good: ;如果jcxz good处检测到cx寄存器的数据是0就跳转到该处,并向下执行
ret ;返回call show_str处并向下执行结束语句
code ends
end start 首先,这是你的代码运行的结果,有什么问题吗?
然后,我写了一个给你参考
assume cs:code, ds:data, ss:stack
data segment
data_arr dw 123, 12666, 1, 8, 3, 38, 0
buffer db 512 dup(0)
data ends
stack segment
db 512 dup(0)
stack ends
code segment
; void NumberToString(uint16_t number, char *buffer);
NumberToString:
push bp
mov bp, sp
push bx
push si
push di
mov di, ; buffer
mov ax, ; number
xor dx, dx
mov cx, 10
@@:
div cx
add dx, '0'
mov , dl
inc di
xor dx, dx
cmp ax, 0
jne @B
mov byte ptr , 0 ; '\0'
; 下面翻转字符串
dec di
mov si, ; buffer
@@:
cmp si, di
jge @F
mov ah,
mov al,
mov , al
mov , ah
inc si
dec di
jmp @B
@@:
pop di
pop si
pop bx
mov sp, bp
pop bp
ret
; void ShowString(uint8_t x, uint8_t y, char *str, uint8_t attr);
ShowString:
push bp
mov bp, sp
push bx
push si
push di
push es
mov ax, 0b800h
mov es, ax
mov dl, ; y
mov al, 160
mul dl
mov di, ax
mov dl, ; x
mov al, 2
mul dl
add di, ax
mov ah, ; attr
mov si, ; str
@@:
mov al,
cmp al, 0
je @F
mov es:, ax
inc si
add di, 2
jmp @B
@@:
pop es
pop di
pop si
pop bx
mov sp, bp
pop bp
ret
start:
mov ax, stack
mov ss, ax
mov sp, 512
mov ax, data
mov ds, ax
mov si, offset data_arr
xor bx, bx
@@:
cmp word ptr , 0
je @F
mov ax, offset buffer
push ax
push
call NumberToString
add sp, 4
mov ax, 07h
push ax
mov ax, offset buffer
push ax
push bx
mov ax, 0
push ax
call ShowString
add sp, 8
add si, 2
inc bx
jmp @B
@@:
mov ax, 4c00h
int 21h
code ends
end start
上面的对齐有问题,我这边是对齐的
人造人 发表于 2018-11-17 22:17
首先,这是你的代码运行的结果,有什么问题吗?
谢谢,我研究研究吧因为你给的那个程序有好的语句我还没有学到比如说cmp、jmp @B、xor、je等这些我都还不会,所以你这个程序我也是看的一知半解没全看懂,我先往下学也许以后会看懂的 奥普瓯江 发表于 2018-11-18 10:54
谢谢,我研究研究吧因为你给的那个程序有好的语句我还没有学到比如说cmp、jmp @B、xor、je等这些我都还不 ...
嗯
页:
[1]