西电计组II 实验二
迪丽瓦拉
2024-02-02 00:34:21
0

西电计组II 实验二

8086汇编实验二: 数制转换

重复从键盘输入不超过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的加减乘除运算

首先考虑加法运算

32位加法

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

32位乘法

本次程序中,最多使用到两个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

相关内容