码迷,mamicode.com
首页 > 其他好文 > 详细

汇编计算器

时间:2015-03-10 21:32:36      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:

开学第一周完成的汇编计算器:前后一共写了很多版本,下面是俩个版本:

by  hfut  叶泽坤 冯弘承 许金龙 宋彬彬。

基础功能完善版:

stack segment stack
       db 1024 dup(?)
stack ends

data segment
    LedMap       db    0c0h,0f9h,0a4h,0b0h,099h,092h,082h,0f8h                  ;0 1 2 3 4.....
                 db    080h,090h,088h,083h,0c6h,0a1h,086h,08eh
    KeyTable     db    07h,04h,08h,05h,09h,06h,0ah,0bh                          ;键码定义
                 db    01h,00h,02h,0fh,03h,0eh,0ch,0dh
    bit          dw    0h
    stack_sign   db    0ffh,   100 dup(?)                                       ;符号栈
    stack_numb   dw    0ffffh, 100 dup(?) 				       ;操作数栈
    OUTSEG  equ  0ffdch                          			       ;段控制口
    OUTBIT  equ  0ffddh             				                 ;位控制口/键扫口
    IN_KEY  equ  0ffdeh                                                          ;键盘读入口
    TEN     db   10
    LedBuf  db   00h,  00h, 00h, 00h, 00h, 00h          	          	;显示缓冲
data ends

code    segment'code'
        assume cs:code,ds:data,ss:stack
        org  1000h

Start:
        mov  LedMap+0,0c0h 						    ;初始化工作
        mov  LedMap+1,0f9h
        mov  LedMap+2,0a4h
        mov  LedMap+3,0b0h
        mov  LedMap+4,099h
        mov  LedMap+5,092h
        mov  LedMap+6,082h
        mov  LedMap+7,0f8h
        mov  LedMap+8,080h
        mov  LedMap+9,090h
        mov  LedMap+10,088h
        mov  LedMap+11,083h
        mov  LedMap+12,0c6h
        mov  LedMap+13,0a1h
        mov  LedMap+14,086h
        mov  LedMap+15,08eh

        mov  KeyTable+0, 07h
        mov  KeyTable+1, 04h
        mov  KeyTable+2, 08h
        mov  KeyTable+3, 05h
        mov  KeyTable+4, 09h
        mov  KeyTable+5, 06h
        mov  KeyTable+6, 0ah
        mov  KeyTable+7, 0bh
        mov  KeyTable+8, 01h
        mov  KeyTable+9, 00h
        mov  KeyTable+10, 02h
        mov  KeyTable+11, 0fh
        mov  KeyTable+12, 03h
        mov  KeyTable+13, 0eh
        mov  KeyTable+14, 0ch
        mov  KeyTable+15, 0dh
        mov stack_sign,0ffh;
        mov stack_numb,0ffffh;
        mov  TEN,10
        mov ch,0ffh;
        call get0

 ss1:
      mov bl,ch;                            					前一个符号
      call show;                            					  显示灯
      mov al,20h;
      call getkey;                         					  获得键
      cmp al,20h;                         					  是否有键按下
      je  ss1;                              						 若无键按下,重新显示


       and  al,0fh                         					 ;高位清零!
       call myDelay                        					   ;这段时间应该等于手离开键盘的时间


      mov ch,al;                         						  保存前一个符号
      cmp al,10
      jnb next0                           					  ;若是数字:

      cmp bl,10
        jb go1
        call clearbuf;

      cmp dx,0                          						    ;若是0,则buff改为0先
      jne  go1
      call clearbuf;
go1:
      call renew_led;                        					 更新显示
      inc bit                              						 ;位数+1

      mov bh,al ;                         						   乘以10加个位法
      mov ax,dx ;
      mul TEN   ;
      add al,bh ;
      adc ah,0  ;
      mov dx,ax ;                          					 中间结果暂存与dx


      jmp ss1;

next0:                                     						 ;若是符号
      cmp bl,10
      jnb go0                                                  ;之前的是符号就跳
      call mypush_numb                   					  ;先将之前的数字入栈
go0:

      mov dx,0;
      cmp al,0fh                       						  ;是否=
      jne go3
go4:                                						;  是的话
      cmp byte ptr stack_sign[si],0ffh         				  ;  是的话,一直爆栈,是否栈底
      jne go11
      call get_ans                    						   ;       是栈底,显示结果结束。
      jmp ss1
go11:
     call calcu
     jmp go4;


go3:
      cmp al,0ch                         					  ;是否复位
      jne go5
      call get0;
      jmp ss1;

go5:
      cmp al,0eh;                         					 ;是否括号
      jne go2
      
      cmp bl,0feh;
      je  go6
      
      cmp bl,10                         						 ;是否左括号 (符号后面必是左括号)
      jnb left

go6:
      mov ch,0feh;
      cmp byte ptr stack_sign[si],0eh;        				      ;若是右括号,是否遇到左括号
      jne go12


      call mypop_sign                      					;遇到左括号,出栈之
      jmp ss1
go12:
       call calcu
       jmp go6

left:
      call mypush_sign                   					  ;左括号入站
      jmp ss1


go2:
      cmp byte ptr stack_sign[si],0eh                				 ;否则必是运算符号,比较优先级
      jne  go7
      call mypush_sign                       					;若是栈顶是左括号,必入栈
      jmp ss1

go7:

      cmp al,0dh;                               					 若是乘号
      jne go9
      cmp byte ptr stack_sign[si],0dh;           				;栈顶是否也是乘号
      jne go8
      call calcu                                					 ;计算,并*入栈
go8:
      call mypush_sign
      jmp ss1
go9:                                         					 ;若是加减号,必爆栈计算
      cmp  si,0                              					  ;栈是否空,空必入栈
      jne  go10
      call mypush_sign
      jmp ss1;
go10:
      call calcu
      call mypush_sign
      jmp  ss1



calcu:                        						   ;爆栈计算子程序
      push ax
      push bx
      push cx
      push dx
      call mypop_sign
      mov bl,al
      call mypop_numb
      push dx
      call mypop_numb
      mov ax,dx
      pop dx
      cmp bl,0ah;
      je myadd
      cmp bl,0bh;
      je mysub
      cmp bl,0dh;
      je mymul

myadd:add ax,dx
      mov dx,ax
      call mypush_numb
      pop dx
      pop cx
      pop bx
      pop ax
      ret
mysub:sub ax,dx
      mov dx,ax
      call mypush_numb
      pop dx
      pop cx
      pop bx
      pop ax
      ret
mymul:mul dx
      mov dx,ax
      call mypush_numb
      pop dx
      pop cx
      pop bx
      pop ax
      ret





get_ans:                                     						;将答案(在栈底)显示器buf修改子程序
     push bx;
     push dx;
     push ax;
     push si
     push di

     call mypop_numb;      						  初始值弹出到DX
     mov di,5;              						从左边低位开始
     mov  bx,10;
     mov  ax,dx         						    ;将结果放在ax便于除法
do:
     xor  dx,dx
     div  bx                 						 ;ax/10 ,余数在dx,结果在ax
     mov si,dx
     mov dl,LedMap[si];
     mov  LedBuf[di],dl        						 ;改余数对应位的buff
     dec di;
     cmp ax,0;
     jne  do


     pop di
     pop si
     pop ax
     pop dx
     pop bx
     ret

clearbuf:
        mov  LedBuf+0,0ffh                				      ;显示"0"子程序
        mov  LedBuf+1,0ffh
        mov  LedBuf+2,0ffh
        mov  LedBuf+3,0ffh
        mov  LedBuf+4,0ffh
        mov  LedBuf+5,0c0h
        mov dx,0
        mov bit,0
       ret;

get0:
        mov  LedBuf+0,0ffh                				      ;显示"0"子程序
        mov  LedBuf+1,0ffh
        mov  LedBuf+2,0ffh
        mov  LedBuf+3,0ffh
        mov  LedBuf+4,0ffh
        mov  LedBuf+5,0c0h
        mov dx,0
        mov si,0
        mov di,0
        mov bit,0
      ret;


mypush_sign :              						   ;al->符号入栈 子程序
             inc si
             mov byte ptr  stack_sign[si],al
             ret


mypush_numb  :            						     ;dx->操作数入栈子程序
             add di,2
             mov word ptr   stack_numb[di],dx
             ret


mypop_sign   :						            	      ; 出栈->al
             mov al,stack_sign[si]
             cmp al,0ffh
             je  next3
             dec si
next3:
             ret

mypop_numb   :     							              ;出栈->dx
             mov dx,stack_numb[di]
             cmp dx,0ffffh
             je  next11
             dec di
             dec di
next11:
             ret


renew_led:                              						  ;更新buff子程序子程序
      push si
      push bx
      push dx



      mov si,bit;
      mov bx,offset LedBuf;
      cmp si,0
      je  go
again:
      neg si
      mov dx,[bx+si+6];
      mov [bx+si+5],dx;
      neg si
      dec si
      jnz   again
go:
     mov ah,0
     mov si,ax
     mov dl, [LedMap+si]
     mov [bx+5],dl

      pop dx
      pop bx
      pop si

   ret;


Delay:                                 							    ;延时子程序
        push  cx
        mov   cx,256
        loop  $
        pop   cx
        ret

myDelay:                               							     ;键盘读入延时子程序
        push  cx
        mov   cx,25
xx:
        call show
        loop  xx
        pop   cx
        ret


show:                                            						    ;显示当前buff的子程序
        push ax;
        push bx
        push cx;
        push dx;
        mov  bx,offset LEDBuf
        mov  cl,6                       							     ;共6个八段管
        mov  ah,00100000b             						      ;从左边开始显示
DLoop:
       ; mov  dx,OUTBIT
       ; mov  al,0
       ; out  dx,al                           						  ;关所有八段管

        mov  al,[bx]
        mov  dx,OUTSEG
        out  dx,al

        mov  dx,OUTBIT
        mov  al,ah
        out  dx,al                           						   ;显示一位八段管

        push ax
        mov  ah,1
        call Delay
        pop  ax

        shr  ah,1
        inc  bx
        dec  cl
        jnz  DLoop

       ; mov  dx,OUTBIT
       ; mov  al,0h;
      ;  out  dx,al            							  ;关所有八段管
         pop dx
         pop cx
         pop bx
         pop ax;
        ret

getkey:                     							     ;结果存在al中

        push bx
        push dx
        push cx
        mov  al,0ffh        							      ;关显示口
        mov  dx,OUTSEG
        out  dx,al
        mov  bl,0
        mov  ah,0feh
        mov  cx,8
key1:   mov  al,ah
        mov  dx,OUTBIT
        out  dx,al
        shl  al,1
        mov  ah,al
        nop
        nop
        nop
        nop
        nop
        nop
        mov  dx,IN_KEY
        in   al,dx
        not  al
        nop
        nop
        and  al,0fh
        jnz  key2
        inc  bl
        loop key1
nkey:   mov  al,20h
        pop cx
        pop dx
        pop bx
        ret
key2:   test al,1
        je   key3
        mov  al,0
        jmp  key6
key3:   test al,2
        je   key4
        mov  al,8
        jmp  key6
key4:   test al,4
        je   key5
        mov  al,10h
        jmp  key6
key5:   test al,8
        je   nkey
        mov  al,18h
key6:   add  al,bl
        cmp  al,10h
        jnc  fkey
        mov  bx,offset KeyTable
        xlat
        pop cx
        pop dx
        pop bx
fkey:   ret




code ends
       end Start

 

 

 

 


 

功能加强版:(所有括号自动匹配(如25*((15+5)+125)-10*(21*6)=   ),还有溢出警报(警示灯),并显示,error)

 

;******************************************
; 硬件综合实训 模拟计算器实验
; By 叶泽坤 冯弘承 许金龙 宋彬彬
;  2015.3
;******************************************

stack segment stack
       db 1024 dup(?)
stack ends

data segment
    LedMap       db    0c0h,0f9h,0a4h,0b0h,099h,092h,082h,0f8h                  ;0 1 2 3 4.....
                 db    080h,090h,088h,083h,0c6h,0a1h,086h,08eh
    KeyTable     db    07h,04h,08h,05h,09h,06h,0ah,0bh                          ;键码定义
                 db    01h,00h,02h,0fh,03h,0eh,0ch,0dh
    bit          dw    0h
    stack_sign   db    0ffh,   100 dup(?)                                       ;符号栈
    stack_numb   dw    0ffffh, 100 dup(?) 					                    ;操作数栈
    OUTSEG  equ  0ffdch                          				                ;段控制口
    OUTBIT  equ  0ffddh             				                            ;位控制口/键扫口
    IN_KEY  equ  0ffdeh                                                         ;键盘读入口
    PA      EQU 0FFD8H
    PB      EQU 0FFD9H
    PC      EQU 0FFDAH
    PCTL    EQU 0FFDBH
    TEN     db   10
    LedBuf  db   00h,  00h, 00h, 00h, 00h, 00h          	          		    ;显示缓冲
data ends

code    segment'code'
        assume cs:code,ds:data,ss:stack
        org  1000h
Start:
        mov  LedMap+0,0c0h 						                                ;初始化工作
        mov  LedMap+1,0f9h
        mov  LedMap+2,0a4h
        mov  LedMap+3,0b0h
        mov  LedMap+4,099h
        mov  LedMap+5,092h
        mov  LedMap+6,082h
        mov  LedMap+7,0f8h
        mov  LedMap+8,080h
        mov  LedMap+9,090h
        mov  LedMap+10,088h
        mov  LedMap+11,083h
        mov  LedMap+12,0c6h
        mov  LedMap+13,0a1h
        mov  LedMap+14,086h
        mov  LedMap+15,08eh

        mov  KeyTable+0, 07h
        mov  KeyTable+1, 04h
        mov  KeyTable+2, 08h
        mov  KeyTable+3, 05h
        mov  KeyTable+4, 09h
        mov  KeyTable+5, 06h
        mov  KeyTable+6, 0ah
        mov  KeyTable+7, 0bh
        mov  KeyTable+8, 01h
        mov  KeyTable+9, 00h
        mov  KeyTable+10, 02h
        mov  KeyTable+11, 0fh
        mov  KeyTable+12, 03h
        mov  KeyTable+13, 0eh
        mov  KeyTable+14, 0ch
        mov  KeyTable+15, 0dh
        mov stack_sign,0ffh;
        mov stack_numb,0ffffh;
        mov  TEN,10
        mov ch,0ffh;
        call get0
        
ss1:      
      mov bl,ch                            					        ;前一个符号
      call show                            					        ;显示灯
      mov al,20h;
      call getkey                                                   ;获得键
      cmp al,20h;                         					        ;是否有键按下
      je  ss1;                              						;若无键按下,重新显示

      and  al,0fh                         					        ;高位清零!
      call myDelay                        					        ;这段时间应该等于手离开键盘的时间

      mov ch,al;                         						    ;保存前一个符号
      cmp al,10
      jnb next0                           					        ;若是数字:

      cmp bl,10
      jb go1
      call clearbuf;

      cmp dx,0                          						    ;若是0,则buff改为0先
      jne  go1
      call clearbuf;
	  
go1:
      call renew_led;                        					    ;更新显示
      inc bit                              						    ;位数+1

      cmp bit,5
      jne gonext1
      call error;
      jmp ss1
	  
gonext1:
      mov bh,al ;                         						    ;乘以10加个位法
      mov ax,dx ;
      mul TEN   ;
      add al,bh ;
      adc ah,0  ;
      mov dx,ax ;                          					        ;中间结果暂存与dx

      jmp ss1;

next0:                                     						    ;若是符号
      cmp bl,10
      jnb go0                                                       ;之前的是符号就跳
      call mypush_numb                   					        ;先将之前的数字入栈
	  
go0:
      mov dx,0;
      cmp al,0fh                       						        ;判断是否=
      jne go3
	  
go4:                                						        ;是的话
      cmp byte ptr stack_sign[si],0ffh         				        ;是的话,一直爆栈,是否栈底
      jne go11
      call get_ans                    						        ;是栈底,显示结果结束。
      jmp ss1
	  
go11:
      call calcu
      jmp go4;
	 
go3:
      cmp al,0ch                         					        ;是否复位
      jne go5
      call get0;
      jmp ss1;

go5:
      cmp al,0eh;                         					        ;是否括号
      jne go2

      cmp bl,0feh;
      je  go6

      cmp bl,10                         						    ;是否左括号 (符号后面必是左括号)
      jnb left

go6:
      mov ch,0feh;
      cmp byte ptr stack_sign[si],0eh;        				        ;若是右括号,是否遇到左括号
      jne go12
      call mypop_sign                      					        ;遇到左括号,出栈之
      jmp ss1
	  
go12:
      call calcu
      jmp go6

left:
      call mypush_sign                   					        ;左括号入站
      jmp ss1

go2:
      cmp byte ptr stack_sign[si],0eh                				;否则必是运算符号,比较优先级
      jne  go7
      call mypush_sign                       					    ;若是栈顶是左括号,必入栈
      jmp ss1

go7:
      cmp al,0dh;                               					;若是乘号
      jne go9
      cmp byte ptr stack_sign[si],0dh;           				    ;栈顶是否也是乘号
      jne go8
      call calcu                                					;计算,并*入栈
	  
go8:
      call mypush_sign
      jmp ss1
	  
go9:                                         					    ;若是加减号,必爆栈计算
      cmp  si,0                              					    ;栈是否空,空必入栈
      jne  go10
      call mypush_sign
      jmp ss1
	  
go10:
      call calcu
      call mypush_sign
      jmp  ss1

;**********************爆栈计算子程序************************
calcu:                        						   
      push ax
      push bx
      push cx
      push dx
      call mypop_sign
      mov bl,al
      call mypop_numb
      push dx
      call mypop_numb
      mov ax,dx
      pop dx
      cmp bl,0ah;
      je myadd
      cmp bl,0bh;
      je mysub
      cmp bl,0dh;
      je mymul

myadd:
      add ax,dx
      mov dx,ax
      call mypush_numb
      pop dx
      pop cx
      pop bx
      pop ax
      ret
	  
mysub:
      sub ax,dx
      mov dx,ax
      call mypush_numb
      pop dx
      pop cx
      pop bx
      pop ax
      ret
	  
mymul:
      mul dx
      cmp dx,0
      je go13
      call get0
      call error
      jmp ss1;
      ret
	  
go13:
      mov dx,ax
      call mypush_numb
      pop dx
      pop cx
      pop bx
      pop ax
      ret
	  
;**********************将答案(在栈底)显示器buf修改子程序************************

get_ans:                                     						
      push bx;
      push dx;
      push ax;
      push si
      push di
      call mypop_numb;      						      ;初始值弹出到DX
      mov di,5;              						      ;从左边低位开始
      mov  bx,10;
      mov  ax,dx         						          ;将结果放在ax便于除法
	  
do:
      xor  dx,dx
      div  bx                 						      ;ax/10 ,余数在dx,结果在ax
      mov si,dx
      mov dl,LedMap[si];
      mov  LedBuf[di],dl        						  ;改余数对应位的buff
      dec di;
      cmp ax,0;
      jne  do
      pop di
      pop si
      pop ax
      pop dx
      pop bx
      ret

;**********************抛出异常子程序************************

error:
      push ax
      mov dx,PCTL
      mov al,080h;
      out dx,al
      mov dx,PB
      mov al,00h
      out dx,al;
	  
      mov  LedBuf+0,86h                				      
      mov  LedBuf+1,0afh
      mov  LedBuf+2,0afh
      mov  LedBuf+3,0a3h
      mov  LedBuf+4,0afh
      mov  LedBuf+5,0ffh
      mov dx,0
        
      pop ax
      ret;

;*********************清buff,显示"0"子程序***********************

clearbuf:
      mov  LedBuf+0,0ffh                				      
      mov  LedBuf+1,0ffh
      mov  LedBuf+2,0ffh
      mov  LedBuf+3,0ffh
      mov  LedBuf+4,0ffh
      mov  LedBuf+5,0c0h
      mov dx,0
      mov bit,0
      ret;

;************************显示"0"子程序******************************

get0:
      mov  LedBuf+0,0ffh                				      
      mov  LedBuf+1,0ffh
      mov  LedBuf+2,0ffh
      mov  LedBuf+3,0ffh
      mov  LedBuf+4,0ffh
      mov  LedBuf+5,0c0h
      mov dx,PCTL
      mov al,080h;
      out dx,al
      mov dx,PB
      mov al,0ffh
      out dx,al;       
      mov dx,0
      mov si,0
      mov di,0
      mov bit,0
      ret;

;**********************符号、数字的入栈、出栈************************

mypush_sign:              						          ;al->符号入栈 子程序
             inc si
             mov byte ptr  stack_sign[si],al
             ret

mypush_numb:            						          ;dx->操作数入栈子程序
             add di,2
             mov word ptr   stack_numb[di],dx
             ret

mypop_sign:						            	          ;出栈->al
             mov al,stack_sign[si]
             cmp al,0ffh
             je  next3
             dec si
next3:
             ret

mypop_numb:     							              ;出栈->dx
             mov dx,stack_numb[di]
             cmp dx,0ffffh
             je  next11
             dec di
             dec di
next11:
             ret

;**********************更新buff子程序子程序************************

renew_led:                              						  
      push si
      push bx
      push dx
      mov si,bit;
      mov bx,offset LedBuf;
      cmp si,0
      je  go
	  
again:
      neg si
      mov dx,[bx+si+6];
      mov [bx+si+5],dx;
      neg si
      dec si
      jnz   again
	  
go:
      mov ah,0
      mov si,ax
      mov dl, [LedMap+si]
      mov [bx+5],dl
      pop dx
      pop bx
      pop si
      ret

;************************延时子程序************************

Delay:                                 							    
        push  cx
        mov   cx,256
        loop  $
        pop   cx
        ret

;********************键盘读入延时子程序********************

myDelay:                               							     
        push  cx
        mov   cx,25
xx:
        call show
        loop  xx
        pop   cx
        ret

;********************显示当前buff的子程序********************

show:                                            						    
        push ax;
        push bx
        push cx;
        push dx;
        mov  bx,offset LEDBuf
        mov  cl,6                       		          ;共6个八段管
        mov  ah,00100000b             				      ;从左边开始显示
DLoop:
       ; mov  dx,OUTBIT
       ; mov  al,0
       ; out  dx,al                           		      ;关所有八段管

        mov  al,[bx]
        mov  dx,OUTSEG
        out  dx,al

        mov  dx,OUTBIT
        mov  al,ah
        out  dx,al                           			  ;显示一位八段管

        push ax
        mov  ah,1
        call Delay
        pop  ax

        shr  ah,1
        inc  bx
        dec  cl
        jnz  DLoop

       ; mov  dx,OUTBIT
       ; mov  al,0h;
       ; out  dx,al            							  ;关所有八段管
        pop dx
        pop cx
        pop bx
        pop ax;
        ret

;*************************获取按键的数值********************

getkey:                     							  ;结果存在al中
        push bx
        push dx
        push cx
        mov  al,0ffh        							  ;关显示口
        mov  dx,OUTSEG
        out  dx,al
        mov  bl,0
        mov  ah,0feh
        mov  cx,8
		
key1:   mov  al,ah
        mov  dx,OUTBIT
        out  dx,al
        shl  al,1
        mov  ah,al
        nop
        nop
        nop
        nop
        nop
        nop
        mov  dx,IN_KEY
        in   al,dx
        not  al
        nop
        nop
        and  al,0fh
        jnz  key2
        inc  bl
        loop key1
		
nkey:   mov  al,20h
        pop cx
        pop dx
        pop bx
        ret
		
key2:   test al,1
        je   key3
        mov  al,0
        jmp  key6
		
key3:   test al,2
        je   key4
        mov  al,8
        jmp  key6
key4:   test al,4
        je   key5
        mov  al,10h
        jmp  key6
		
key5:   test al,8
        je   nkey
        mov  al,18h
		
key6:   add  al,bl
        cmp  al,10h
        jnc  fkey
        mov  bx,offset KeyTable
        xlat
        pop cx
        pop dx
        pop bx
		
fkey:   ret

code  ends
       end  Start


 

 

 

汇编计算器

标签:

原文地址:http://blog.csdn.net/u011498819/article/details/44180347

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!