重复从键盘输入不超过5位的十进制数,按回车键结束输入;
将该十进制数转换成二进制数;结果以2进制数的形式显示在屏幕上;
如果输入非数字字符,则报告出错信息,重新输入;
直到输入“Q”或‘q’时程序运行结束。
键盘输入一字符串,以空格结束,统计其中数字字符的个数,在屏幕显示
sum维护在BX寄存器中
首先使用int 21H软中断AH=0AH入口,输入一串字符串,放到buffer中
buffer[0]也需要在中断之前指定一下buffer缓冲区的大小
buffer[1]在中断获取输入返回之后,存放的是实际上输入的字符个数
我们希望输入5位十进制整数,因此首先检查buffer[1],如果等于0或者大于5都要报错,然后程序回到最初状态,重新接受输入
buffer[2]开始就是实际获取到的输入了,比如输入12345,那么就有
buffer[0] | sizeof(buffer) |
---|---|
buffer[1] | strlen(buffer) |
buffer[2] | ‘1’ |
buffer[3] | ‘2’ |
buffer[4] | ‘3’ |
显然buffer[2]的权位最高,越往后越低,伪代码表示为
for(i=2;i<=len;++i){
if(buffer[i]>='0'&&buffer[i]<='9'){
sum=sum*10+(buffer[i]-'0');
}
else{
//输入非法,报错,重来
}
}
binary(sum)
考虑如何用8086汇编实现之
首先这个十进制数最大5位,而一个AX寄存器最长是 2 16 = 65536 2^{16}=65536 216=65536,
也就是说5位的十进制数有可能用一个寄存器放不下
如果只用AX,则达到65535之后就发生整数上溢,mod 65536截断
考虑用DX:AX一起作为sum
假设故意找茬输入了65536
前四个只是用AX可以正常计算到6553,如果继续之前的套路计算,会有6553*10+6=65536
然后mod 65536=0,算了个寂寞吧
应该怎么算?就是用8086实现32位整数,即int的加减乘除运算
首先考虑加法运算
8086提供了两种加法指令,ADD和ADC
前者不考虑进位标志CF,后者要考虑
也就是ADD A,B相当于A+B->A
ADC A,B相当于A+B+CF->A
这样的话一个32位数可以分两次运算
mov ax,first_low
mov bx,second_low
add ax,bx ;ax+bx->ax,此时考虑进位
mov dx,first_high
mov di,second_high
adc dx,di ;dx+bx+cf->dx
因此可以包装一个函数op_add(first in DX:AX,second in DI:BX)
op_add proc near
;first in DX:AX
;second in DI:BX
add AX,BX
adc DX,DI
ret
op_add endp
本次程序中,最多使用到两个16位数的乘法,MUL可以胜任工作
MUL BX
的被乘数隐含在AX中,两个16位数相乘,乘积最多是32位的,存放于DX:AX中
op_mul proc near
;a*b, factors use AX and BX
mul BX
ret ;result in DX:AX
op_mul endp
以上两个就足够了
下面考虑将一个最多五位整数的字符串转化为一个DX:AX这样存放的数值
修改一下input函数,CX返回实际输入字符数,AX返回字符串首地址,也就是说AX之前指向buffer,现在指向buffer+2
这样
AX=字符串基地址,存放的是十进制数的最高位
CX=字符串长度
atoi proc near
push si
loop0:
mov si,ax;ax要进行计算,si承担其责任
mov ax,0
mov dx,0 ;sum=0->DX:AX
mov bx,10
call op_mul
mov bh,0
mov bl,ds:[si]
mov di,0
call op_add
dec cx
inc si
cmp cx,0
jz fini
jmp loop0
fini:
pop si
ret
atoi endp
输入一个5位以内的整数,输出其二进制表示,
DSEG SEGMENT
dbg DB 'debugger, actived!' ,0DH,0AH,24H
next_row DB 0DH,0AH,24H
buffer DB 0100H dup('$')
hint db 'please input an decimal within 5 digit number > $'
STUID DB 'please input your id >','$'
STUNAME DB 'please input your name >','$'
cmdprompt DB 'please input an alpha to get its ascii code, q to quit >','$'
badinput DB 'input length should in [1,5] ,please re input $'
DSEG ENDS
SSEG SEGMENT PARA STACK
DW 256 DUP(?)
SSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DSEG
;调用约定:需要打印的字符->al
putchar proc
push dx
push ax
mov ah,02h
mov dl,al
int 21h
pop ax
pop dx
ret
putchar endp
;调用约定:输入字符用al返回
getchar proc near
mov ah,01h
mov al,0
int 21H
retn
getchar endp
;16进制打印一个字节,调用约定:
hex PROC near
push ax
push dx
mov dx,ax
mov ch, 4
L1:
mov cl, 4
rol dx, cl
mov al,dl
and al,0FH
add al,30h
cmp al,3ah
jl printit
add al,7h
printit:
call putchar
dec ch
jnz L1
pop dx
pop ax
ret
hex ENDP
;二进制形式的输出,入口参数为ax
binary proc
push bx ;数据入栈,保留数值
push dx
mov dh,0 ;用于计数,总共16次
binaryagain:
cmp dh,16
je binaryover ;输出结束,到达函数末端
rol ax,1 ;移动一位
mov bx,ax ;数值保留
and ax,0001h ;剥离出最后一位
mov dl,al ;用于输出
add dl,48
mov ah,2
int 21h
inc dh ;计数加一
mov ax,bx ;数值恢复
jmp binaryagain ;再来一次
binaryover:
pop dx ;数据出栈,数值还原
pop bx
ret
binary endp
;调用约定:ax指定一个buffer的基地址,用于获取一个字符串
print proc near
push bx
push cx
push dx
mov dx,ax
mov ah,09H
mov al,00H
int 21H
pop dx
pop cx
pop bx
ret
print endp
;调用约定:ax指定一个buffer的基地址,用于获取一个字符串
println proc near
call print
mov al,0Dh
call putchar
mov al,0DH
call putchar
ret
println endp
newline proc near
push ax
lea ax,next_row
call print
pop ax
ret
newline endp
;AX存放目的地址,结束时CX返回输入字符个数
input proc near
push BX
; push cx
; push di
; push ax
; MOV CX, 0ffh
; mov DI, ax
; mov al,'$'
; REPZ STOSB
; pop ax
MOV DX,AX
MOV BX,DX
MOV byte ptr DS:[BX], 0ffh
; mov [DX],BL
mov ah,0ah ;将0ah放入ah
mov al,0
int 21h ;输入字符串功能调用
mov CX,0
mov CL,DS:[BX+1]
lea AX,DS:[BX+2]
pop BX
ret
input endp
circle proc near
rolling:
lea ax,cmdprompt
call println
call getchar
cmp al,'q'
jz fini
mov ah,0
call newline
call hex
call newline
jmp rolling
fini:
retn
circle endp
;调用约定:ax存放基地址,cx存放长度,bl存放目标字符
memset proc near
push di
mov di,ax
memset_circle:
cmp cx,0
jz memset_fini
mov ds:[di],bl
inc di
dec cx
jmp memset_circle
memset_fini:
pop di
ret
memset endp
op_mul proc near
;a*b, factors use AX and BX
mul BX
ret ;result in DX:AX
op_mul endp
op_add proc near
;first in DX:AX
;second in DI:BX
add AX,BX
adc DX,DI
ret
op_add endp
debugger proc near
push ax
lea ax,dbg
call print
call newline
pop ax
ret
debugger endp
;检查一个字符是否是数字,BL传递ascii值,如果是则bp为1,否则为0
isdigit proc near
cmp bl,'9'
jz flagon
cmp bl,'8'
jz flagon
cmp bl,'7'
jz flagon
cmp bl,'6'
jz flagon
cmp bl,'5'
jz flagon
cmp bl,'4'
jz flagon
cmp bl,'3'
jz flagon
cmp bl,'2'
jz flagon
cmp bl,'1'
jz flagon
cmp bl,'0'
jz flagon
cmp bl,'q'
jz flagfail
mov bp,0
ret
flagon:
mov bp,1
ret
flagfail:
mov bp,-1
ret
isdigit endp
;buffer+2 in AX,length in CX
atoi proc near
mov si,ax
mov di,0
mov ax,0
mov bx,0
mov dx,0
shift:
cmp cx,0
jz atoi_fini
; call debugger
mov bx,10
call op_mul
mov bl,[si]
call isdigit
cmp bp,0
jz atoi_fail
cmp bp,-1
jz atoi_exit
sub bl,'0'
call op_add
inc si
dec cx
jmp shift
atoi_fini:
mov bp,1
ret
atoi_exit:
call exit
atoi_fail:
mov bp,0
ret
atoi endp
exit proc near
mov ah,4Ch
mov al,0
int 21h
exit endp
BEGIN:
MOV AX,DSEG
MOV DS,AX
loopinput:
call newline
lea AX,hint
call print
call newline
lea AX,buffer
mov cx,0ffh
mov bl,'$'
call memset
lea AX,buffer
call input
;首先判断输入长度是否合法,要大于0小于6
cmp cx,6
jnc loopinput
cmp cx,0
jz loopinput
; call debugger
call atoi
cmp bp,0
jz loopinput
xchg ax,dx;先打印高位的dx,然后才是低位的ax
call binary
mov ax,dx
call binary
call newline
jmp loopinput
main_fini:
call debugger
call exit
CSEG ENDS
END BEGIN
输入一个字符串,统计其中的数字的个数
assume cs:code,ds:data,ss:mystack
data segment
hint db 'input a string then the program will tell the number of digits>$'
buffer DB 0100H dup('$')
debugger db 'debugging',10,13,'$'
next_row DB 0DH,0AH,24H
data ends
mystack segment stack
db 32 dup(?)
mystack ends
code segment
newline proc near
push ax
lea ax,next_row
call print
pop ax
ret
newline endp
;调用约定:需要打印的字符->al
putchar proc
push dx
push ax
mov ah,02h
mov dl,al
int 21h
pop ax
pop dx
ret
putchar endp
;AX存放目的地址,结束时CX返回输入字符个数
input proc near
push BX
; push cx
; push di
; push ax
; MOV CX, 0ffh
; mov DI, ax
; mov al,'$'
; REPZ STOSB
; pop ax
MOV DX,AX
MOV BX,DX
MOV byte ptr DS:[BX], 0ffh
; mov [DX],BL
mov ah,0ah ;将0ah放入ah
mov al,0
int 21h ;输入字符串功能调用
pop BX
ret
input endp
;调用约定:ax指定一个buffer的基地址,用于获取一个字符串
print proc near
push bx
push cx
push dx
mov dx,ax
mov ah,09H
mov al,00H
int 21H
pop dx
pop cx
pop bx
ret
print endp
hello proc near
push ax
lea ax,buffer
call print
call newline
pop ax
ret
hello endp
isdigit proc near
cmp bl,'9'
jz flagon
cmp bl,'8'
jz flagon
cmp bl,'7'
jz flagon
cmp bl,'6'
jz flagon
cmp bl,'5'
jz flagon
cmp bl,'4'
jz flagon
cmp bl,'3'
jz flagon
cmp bl,'2'
jz flagon
cmp bl,'1'
jz flagon
cmp bl,'0'
jz flagon
jmp flagoff
flagon:
mov bp,1
ret
flagoff:
mov bp,0
ret
isdigit endp
exit proc near
mov ah,4ch
mov al,0
int 21h
exit endp
;buffer+2 in AX,length in CX,result in AX
count proc near
push di
mov di,ax
mov ax,0
loop_count:
mov bl,[di]
call isdigit
cmp bp,1
jnz bottom
add_count:
inc ax
bottom:
dec cx
inc di
cmp cx,0
jnz loop_count
pop di
ret
count endp
;16进制打印一个字节,调用约定:
hex PROC near
push ax
push dx
mov dx,ax
mov ch, 4
L1:
mov cl, 4
rol dx, cl
mov al,dl
and al,0FH
add al,30h
cmp al,3ah
jl printit
add al,7h
printit:
call putchar
dec ch
jnz L1
pop dx
pop ax
ret
hex ENDP
start:
mov ax,data
mov ds,ax
lea ax,hint
call print
lea ax,buffer
call input
lea ax,[buffer+2]
call count
call newline
call hex
call exit
code ends
end start