标签:
开学第一周完成的汇编计算器:前后一共写了很多版本,下面是俩个版本:
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