重复从键盘输入不超过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寄存器最长是216=655362^{16}=65536216=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:BXadd AX,BXadc DX,DIret
op_add endp
本次程序中,最多使用到两个16位数的乘法,MUL可以胜任工作
MUL BX
的被乘数隐含在AX中,两个16位数相乘,乘积最多是32位的,存放于DX:AX中
op_mul proc near;a*b, factors use AX and BXmul BXret ;result in DX:AX
op_mul endp
以上两个就足够了
下面考虑将一个最多五位整数的字符串转化为一个DX:AX这样存放的数值
修改一下input函数,CX返回实际输入字符数,AX返回字符串首地址,也就是说AX之前指向buffer,现在指向buffer+2
这样
AX=字符串基地址,存放的是十进制数的最高位
CX=字符串长度
atoi proc nearpush siloop0:mov si,ax;ax要进行计算,si承担其责任mov ax,0mov dx,0 ;sum=0->DX:AXmov bx,10call op_mulmov bh,0mov bl,ds:[si]mov di,0call op_adddec cxinc sicmp cx,0jz finijmp loop0fini:pop siret
atoi endp
输入一个5位以内的整数,输出其二进制表示,
DSEG SEGMENTdbg DB 'debugger, actived!' ,0DH,0AH,24Hnext_row DB 0DH,0AH,24Hbuffer 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 ENDSSSEG SEGMENT PARA STACKDW 256 DUP(?)
SSEG ENDSCSEG SEGMENTASSUME CS:CSEG,DS:DSEG;调用约定:需要打印的字符->al
putchar procpush dxpush axmov ah,02hmov dl,alint 21hpop axpop dxret
putchar endp;调用约定:输入字符用al返回
getchar proc nearmov ah,01hmov al,0int 21Hretngetchar endp;16进制打印一个字节,调用约定:
hex PROC nearpush axpush dxmov dx,axmov ch, 4L1: mov cl, 4rol dx, clmov al,dland al,0FHadd al,30hcmp al,3ahjl printitadd al,7hprintit: call putchardec chjnz L1pop dxpop axret
hex ENDP;二进制形式的输出,入口参数为ax
binary procpush bx ;数据入栈,保留数值push dxmov dh,0 ;用于计数,总共16次binaryagain: cmp dh,16je binaryover ;输出结束,到达函数末端rol ax,1 ;移动一位mov bx,ax ;数值保留and ax,0001h ;剥离出最后一位mov dl,al ;用于输出add dl,48mov ah,2int 21hinc dh ;计数加一mov ax,bx ;数值恢复jmp binaryagain ;再来一次binaryover: pop dx ;数据出栈,数值还原pop bxret
binary endp;调用约定:ax指定一个buffer的基地址,用于获取一个字符串
print proc nearpush bxpush cxpush dxmov dx,axmov ah,09Hmov al,00Hint 21Hpop dxpop cxpop bxret
print endp;调用约定:ax指定一个buffer的基地址,用于获取一个字符串
println proc nearcall printmov al,0Dhcall putcharmov al,0DHcall putcharret
println endpnewline proc nearpush axlea ax,next_rowcall printpop axret
newline endp;AX存放目的地址,结束时CX返回输入字符个数
input proc nearpush BX; push cx; push di; push ax; MOV CX, 0ffh; mov DI, ax; mov al,'$'; REPZ STOSB; pop axMOV DX,AXMOV BX,DXMOV byte ptr DS:[BX], 0ffh; mov [DX],BLmov ah,0ah ;将0ah放入ahmov al,0int 21h ;输入字符串功能调用mov CX,0mov CL,DS:[BX+1]lea AX,DS:[BX+2]pop BXret
input endpcircle proc nearrolling: lea ax,cmdpromptcall printlncall getcharcmp al,'q'jz finimov ah,0call newlinecall hexcall newlinejmp rollingfini: retncircle endp;调用约定:ax存放基地址,cx存放长度,bl存放目标字符
memset proc nearpush dimov di,axmemset_circle:cmp cx,0jz memset_finimov ds:[di],blinc didec cxjmp memset_circlememset_fini: pop diret
memset endpop_mul proc near;a*b, factors use AX and BXmul BXret ;result in DX:AX
op_mul endpop_add proc near;first in DX:AX;second in DI:BXadd AX,BXadc DX,DIret
op_add endpdebugger proc nearpush axlea ax,dbgcall printcall newlinepop axret
debugger endp;检查一个字符是否是数字,BL传递ascii值,如果是则bp为1,否则为0
isdigit proc nearcmp bl,'9'jz flagoncmp bl,'8'jz flagoncmp bl,'7'jz flagoncmp bl,'6'jz flagoncmp bl,'5'jz flagoncmp bl,'4'jz flagoncmp bl,'3'jz flagoncmp bl,'2'jz flagoncmp bl,'1'jz flagoncmp bl,'0'jz flagoncmp bl,'q'jz flagfailmov bp,0retflagon: mov bp,1retflagfail: mov bp,-1ret
isdigit endp;buffer+2 in AX,length in CX
atoi proc nearmov si,axmov di,0mov ax,0mov bx,0mov dx,0shift: cmp cx,0jz atoi_fini; call debuggermov bx,10call op_mulmov bl,[si]call isdigitcmp bp,0jz atoi_failcmp bp,-1jz atoi_exitsub bl,'0'call op_addinc sidec cxjmp shiftatoi_fini: mov bp,1retatoi_exit: call exitatoi_fail: mov bp,0ret
atoi endpexit proc nearmov ah,4Chmov al,0int 21h
exit endpBEGIN: MOV AX,DSEGMOV DS,AXloopinput: call newlinelea AX,hintcall printcall newlinelea AX,buffermov cx,0ffhmov bl,'$'call memsetlea AX,buffercall input;首先判断输入长度是否合法,要大于0小于6cmp cx,6jnc loopinputcmp cx,0jz loopinput; call debuggercall atoicmp bp,0jz loopinputxchg ax,dx;先打印高位的dx,然后才是低位的axcall binarymov ax,dxcall binarycall newlinejmp loopinputmain_fini: call debuggercall exit
CSEG ENDSEND BEGIN
输入一个字符串,统计其中的数字的个数
assume cs:code,ds:data,ss:mystackdata segmenthint 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 stackdb 32 dup(?)
mystack endscode segment
newline proc nearpush axlea ax,next_rowcall printpop axret
newline endp;调用约定:需要打印的字符->al
putchar procpush dxpush axmov ah,02hmov dl,alint 21hpop axpop dxret
putchar endp;AX存放目的地址,结束时CX返回输入字符个数
input proc nearpush BX; push cx; push di; push ax; MOV CX, 0ffh; mov DI, ax; mov al,'$'; REPZ STOSB; pop axMOV DX,AXMOV BX,DXMOV byte ptr DS:[BX], 0ffh; mov [DX],BLmov ah,0ah ;将0ah放入ahmov al,0int 21h ;输入字符串功能调用pop BXret
input endp;调用约定:ax指定一个buffer的基地址,用于获取一个字符串
print proc nearpush bxpush cxpush dxmov dx,axmov ah,09Hmov al,00Hint 21Hpop dxpop cxpop bxret
print endphello proc nearpush axlea ax,buffercall printcall newlinepop axret
hello endp
isdigit proc nearcmp bl,'9'jz flagoncmp bl,'8'jz flagoncmp bl,'7'jz flagoncmp bl,'6'jz flagoncmp bl,'5'jz flagoncmp bl,'4'jz flagoncmp bl,'3'jz flagoncmp bl,'2'jz flagoncmp bl,'1'jz flagoncmp bl,'0'jz flagonjmp flagoffflagon: mov bp,1retflagoff: mov bp,0ret
isdigit endpexit proc nearmov ah,4chmov al,0int 21h
exit endp;buffer+2 in AX,length in CX,result in AX
count proc nearpush dimov di,axmov ax,0loop_count:mov bl,[di]call isdigitcmp bp,1jnz bottomadd_count: inc axbottom: dec cxinc dicmp cx,0jnz loop_countpop diret
count endp;16进制打印一个字节,调用约定:
hex PROC nearpush axpush dxmov dx,axmov ch, 4L1: mov cl, 4rol dx, clmov al,dland al,0FHadd al,30hcmp al,3ahjl printitadd al,7hprintit: call putchardec chjnz L1pop dxpop axret
hex ENDPstart: mov ax,datamov ds,axlea ax,hintcall printlea ax,buffercall inputlea ax,[buffer+2]call countcall newlinecall hexcall exitcode ends
end start