calculator.asm
来自「基于Multisim9的电子系统设计、仿真与综合应用(实例源文件)」· 汇编 代码 · 共 974 行 · 第 1/2 页
ASM
974 行
; --------------------------------------------------------------
; Calculator Example
;
; This program performs calculations of the form:
; operand1 operator operand2
; where the operator can be +,-,* or /.
; The operands 1 and 2 are positive integers between 0 and 9999.
; If the result of the calculations exceeds the range between
; 0 and 9999, it is considered an error.
;
; If an error occurs, "EEEE" will be applied to the output pins
; on ports P0 and P2. The operands and operator are obtained by
; reading the input signals received on port P1.
; --------------------------------------------------------------
$MOD51
$TITLE(TEST DEMO)
;
; Variables
;
NUM1L DATA 020H ; low byte of first operand
NUM1H DATA 021H ; high byte of first operand
OPERATOR DATA 022H ; operator
NUM2L DATA 023H ; low byte of second operand
NUM2H DATA 024H ; high byte of second operand
EWB DATA 0F8H ;EWB TRACE SFR
; Program Start
reset:
; move stack pointer past register banks and variables
MOV SP, #28H
MOV P0, #00H
MOV P2, #00H
JMP readystate
; Initialize values in memory
initVar:
MOV NUM1L, #00H
MOV NUM1H, #00H
MOV OPERATOR, #0FH
MOV NUM2L, #00H
MOV NUM2H, #00H
MOV R5, #00H
MOV R6, #00H
RET
; Getting first operand
getnum1:
MOV A, R1
MOV A, R5
MOV NUM1L, A
MOV A, R6
MOV NUM1H, A
CALL keyscan
call displaynum
MOV A, R1
XRL A, #03H ; C pressed
JZ readystate
MOV A, R1
XRL A, #02H ; = pressed
JZ getoperator
MOV A, R1
JZ getnum1op ; operator pressed
JMP getnum1 ; continue getting first num
; Got first operand and operator
getnum1op:
MOV R5, #00H
MOV R6, #00H
MOV A, R7
MOV OPERATOR, A
JMP getnum2
; Get operator
getoperator:
MOV R5, #00H
MOV R6, #00H
CALL keyscan
call displaynum
MOV A, R1
XRL A, #03H ; C pressed
JZ readystate
MOV A, R1
XRL A, #02H ; = pressed
JZ getoperator
MOV A, R1
JZ gotop ; operator pressed
JMP getnum1
; Got the operator
gotop:
MOV A, R7
MOV OPERATOR, A
JMP getnum2
; First state that program goes to when started.
; Waiting for the first key press.
readystate:
CALL initVar
CALL keyscan
CALL displaynum
MOV A, R1
XRL A, #03H
JZ readystate ; C pressed
MOV A, R1
JZ readystate ; operator pressed
MOV A, R1
XRL A, #02H ; = pressed
JZ readystate
JMP getnum1
; Get first digit of second operand.
getnum2:
MOV A, R5
MOV NUM2L, A
MOV A, R6
MOV NUM2H, A
CALL keyscan
call displaynum
MOV A, R1
XRL A, #03H ; C pressed
JZ readystate
MOV A, R1
XRL A, #02H ; = pressed
JZ getoperator
MOV A, R1
JZ gotop ; operator pressed
JMP gettingnum2 ; continue getting second num
; Got first digit of second operand. Continue
; getting subsequent digits of the operand or the next
; operator, = or C key press.
gettingnum2:
MOV A, R5
MOV NUM2L, A
MOV A, R6
MOV NUM2H, A
CALL keyscan
call displaynum
MOV A, R1
XRL A, #03H ; C pressed
JZ readystate
MOV A, R1
XRL A, #02H ; = pressed
JZ calcgetop ; Go do calculation
MOV A, R1
JZ calcgetnum2 ; operator pressed; go do calculation
JMP gettingnum2
; calculate result then get next operator
calcgetop:
CALL calculate
MOV A, R0
XRL A, #0EEH
JNZ calcgetopend
MOV A, R1
XRL A, #0EEH
JZ readystate
calcgetopend:
MOV A, R0
MOV NUM1L, A
MOV A, R1
MOV NUM1H, A
JMP getoperator
; calculate result then get next number
calcgetnum2:
CALL calculate
MOV A, R0
XRL A, #0EEH
JNZ calcgetnum2end
MOV A, R1
XRL A, #0EEH
JZ readystate
calcgetnum2end:
MOV A, R0
MOV NUM1L, A
MOV A, R1
MOV NUM1H, A
MOV A, R7
MOV OPERATOR, A
MOV R5, #00H
MOV R6, #00H
JMP getnum2
; Perform +, -, * or / operations
; Input:
; Values stored in variables NUM1L, NUM1H, OPERATOR, NUM2L, NUM2H
; Output:
; R0 - low byte of result
; R1 - high byte of result
; Valid values of R1, R0 range from 0 to 270FH (9999 in base 10)
; In case of overflow or error, R0 and R1 will each contain #0EEh
calculate:
PUSH ACC
MOV A, R2
PUSH ACC
MOV A, R3
PUSH ACC
MOV A, R5
PUSH ACC
MOV A, R6
PUSH ACC
MOV R0, NUM1L
MOV R1, NUM1H
MOV R2, NUM2L
MOV R3, NUM2H
calcAdd:
MOV A, OPERATOR
CJNE A, #0CH, calcSub
CALL ADD16
; check for overflow
MOV A, #027H
SUBB A, R1
JC calcoverflow
JNZ calcAddEnd
MOV A, #0FH
SUBB A, R0
JC calcoverflow
calcAddEnd:
JMP calcDisplay
calcSub:
MOV A, OPERATOR
CJNE A, #08H, calcMul
CALL SUB16
MOV A, #027H
SUBB A, R1
JC calcoverflow
JNZ calcSubEnd
MOV A, #0FH
SUBB A, R0
JNC calcSubEnd
JMP calcoverflow
calcSubNeg: ; calculate the negative value in BCD
MOV A, R0 ; (not used right now - negative values are
MOV R2, A ; considered an overflow)
MOV A, R1
MOV R3, A
MOV R0, #00H
MOV R1, #00H
CALL SUB16
SETB C
calcSubEnd:
JMP calcDisplay
calcMul:
MOV A, OPERATOR
CJNE A, #04H, calcDiv
CALL UMUL16
; make sure that result is not greater than 270FH (9999 in base 10)
MOV A, R3
JNZ calcoverflow
MOV A, R2
JNZ calcoverflow
MOV A, #027H
SUBB A, R1
JC calcoverflow
JNZ calcMulEnd
MOV A, #0FH
SUBB A, R0
JC calcoverflow
calcMulEnd:
JMP calcDisplay
calcDiv:
MOV A, OPERATOR
CJNE A, #00H, calcError
; check divide by zero
MOV A, R2
JNZ calcDoDiv
MOV A, R3
JZ calcDivByZero
calcDoDiv:
CALL UDIV16
JMP calcDisplay
; error occurred
calcError:
; divide by zero error
calcDivByZero:
; overflow occurred
calcoverflow:
MOV R0, #0EEH
MOV R1, #0EEH
MOV A, #0EEH
MOV P2, A
MOV P0, A
CALL delay
JMP calcEnd
; Display results of calculation.
; R0 and R1 contains low and high byte of result
calcDisplay:
MOV A, R0
MOV R5, A
MOV A, R1
MOV R6, A
CALL HEXtoDEC
MOV A, R5
MOV P2, A
MOV A, R6
MOV P0, A
CALL delay
calcEnd:
POP ACC
MOV A, R6
POP ACC
MOV A, R5
POP ACC
MOV A, R3
POP ACC
MOV A, R2
POP ACC
RET
; Returns key pressed in (row,col) format in R7
; For example: R7 = #028H if 1 was pressed on the keypad
; Keypad
; Row # -----------------
; 8 | 7 8 9 + |
; 4 | 4 5 6 - |
; 2 | 1 2 3 * |
; 1 | C 0 = / |
; -----------------
; Col # 8 4 2 1
keyscan:
PUSH ACC
MOV A, R0
PUSH ACC
MOV A, R1
PUSH ACC
MOV A, R3
PUSH ACC
MOV P1, #00FH
waitkeyuploop:
MOV A, P1
ANL A, #00FH
XRL A, #00FH
JNZ waitkeyuploop
MOV P1, #00FH
anykeyloop:
MOV A, P1
ANL A, #00FH
XRL A, #00FH
JZ anykeyloop
MOV R0, A
XRL A, #00FH
MOV R3, A
call lineclear
MOV P1, #0EFH
MOV R1, #010H
NOP
MOV A, P1
ANL A, #00FH
XRL A, R3
MOV R2,#000H
JZ scanmatch
call lineclear
MOV P1, #0DFH
MOV R1, #020H
NOP
MOV A, P1
ANL A, #00FH
XRL A, R3
MOV R2, #001H
JZ scanmatch
call lineclear
MOV P1, #0BFH
MOV R1, #040H
NOP
MOV A, P1
ANL A, #00FH
XRL A, R3
MOV R2, #002H
JZ scanmatch
call lineclear
MOV P1, #07FH
MOV R1, #080H
NOP
MOV A, P1
ANL A, #00FH
XRL A, R3
MOV R2, #003H
JZ scanmatch
MOV P1, #00FH
JMP keyscan
scanmatch:
MOV A, R1
ORL A, R0 ; combine into scancode
MOV R7, A ; R7 contains value in (row,col) format
keyscanend:
POP ACC
MOV R3, A
POP ACC
MOV R1, A
POP ACC
MOV R0, A
POP ACC
RET
; Input:
; R7 contains last key pressed
; R2 contains last key pressed in converted number
; R5 and R6 contains current number in hex
; Output:
; R5 and R6 contains new number in hex
displaynum:
MOV A, R7
MOV R4, A
MOV A, R2
MOV B, #04H
MUL AB
MOV R2, A
MOV A, R4
ANL A, #00FH
MOV R4, #000H
getnumloop:
INC R4
RR A
ANL A, #00FH
JNZ getnumloop
DEC R4
MOV A, R2
ADD A, R4
MOV R1, A
checknum2:
CJNE A, #02H,checknum5
MOV A, #00H
JMP numfound
checknum5:
CJNE A, #05H,checknum6
MOV A, #03H
JMP numfound
checknum6:
CJNE A, #06H,checknum7
MOV A, #02H
JMP numfound
checknum7:
CJNE A, #07H,checknum9
MOV A, #01H
JMP numfound
checknum9:
CJNE A, #09H,checknum10
MOV A, #06H
JMP numfound
checknum10:
CJNE A, #0AH,checknum11
MOV A, #05H
JMP numfound
checknum11:
CJNE A, #0BH,checknum13
MOV A, #04H
JMP numfound
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?