?? calc.asm
字號:
;; 顯示程序符號定義
;;
COM EQU 45H
DAT EQU 46H
CW_ADD EQU 5FFCH
CR_ADD EQU 5FFDH
DW_ADD EQU 5FFEH
DR_ADD EQU 5FFFH
; 子程序說明:
; 寄存器工作組使用
; WAITKEY, 00
; KEYPRESSED, MAKENUM, RES2RAW 等子程序, 01
; FLOATING LIB, 10
; CALCULATE使用01, 當調用浮點程序庫時 10
; 顯示子程序,11
; ======================================================================
; 工作區(qū)使用注意:
; -=-= 1. 位尋址區(qū) =-=-=-
; 20H-21H 兩個字用作位狀態(tài)(位地址00H-0FH)
; 23H-27H ; NOT USE! ESP. 23H
; 28H-2FH為顯示區(qū)域與記錄輸入數字所用,RAWIN
PNTB BIT 10H ; 小數點位指示(位地址, POINT BIT)
POSB BIT 11H ; 位置位,POSB=1表示創(chuàng)建BCD低位,POSB=0表示創(chuàng)建BCD高位
DPB BIT 12H ; 大于1的浮點數MAKENUM時,指示小數點是否已經加入
; 04H-08H, ARBITRARY USE
BYTE2 BIT 14H ; SEE BYTE2USAGE (CTRL+F, FIND IT.)
; STAT保存整個計算器的運行狀態(tài)!
; BIT ASSIGNMENT:
; .7: ERROR
; .6: FLOAT
; .5 & .4: OPERATOR
; VALUE MEANING:
; 00: ADD
; 01: SUB
; 10: MUL
; 11: DIV
; .3: OPERATOR PRESSED
; .2: CONSTRUCTING NUM2
; .1: CONSTRUCTING NUM1
; .0: EQUAL SIGN PRESSED
STAT EQU 20H
DCOUNT EQU 21H ; 數字位數計數(DIGIT COUNT),只是RAWIN中有效字節(jié)
INPUT EQU 2AH ; 鍵盤輸入暫存
RAWPTR EQU 2BH ; 顯示緩沖區(qū)指針
NUMPTR EQU 2CH ; 當前組建數字的指針
TEMP1 EQU 2DH ; 臨時存儲,一般用于臨時保存R0, R1
TEMP2 EQU 2EH ; 以切換寄存器組, UNUNSED... 07.25.NIGHT
; -=-= 2. IRAM =-=-
; 30H-33H為第一個操作數
; 34H-37H為第二個操作數
; 38H-3FH為顯示區(qū)域
; 48H-4FH為臨時存儲區(qū)域
; 結果則存儲在第一個操作數位置
NUM1 EQU 30H
NUM2 EQU 34H
RAWIN EQU 38H
TEMP EQU 48H
; -=-=-= 3. REGISTERS =-=-=-
; 鍵盤掃描使用寄存器組 0,浮點程序使用寄存器組 2
; 其余數字組合部分用寄存器組 1
; 測試程序使用寄存器組 3
; ASCII TABLE
; '.' -> 2EH
; '+' -> 2BH
; '-' -> 2DH
; '*' -> 2AH
; '/' -> 2FH
; '=' -> 3DH
;/////////////////////////////////////////////////////////////////////
;///
;/// T H E [ M A I N ] P R O G R A M
;/// ZEROX@2005.7.14
;////////////////////////////////////////////////////////////////////
ORG 0000H
LJMP MAIN
ORG 0030H
MAIN:
; 全局初始化
MOV SP, #60H ; 堆棧
MOV IE, #00H ; 禁止所有中斷
; 寄存器組 00
CLR RS1
CLR RS0
; 工作區(qū)IRAM(20H-5FH)默認全為0
INIT20TO5F:
MOV R0, #20H ; START AT 20H
MOV R7, #40H ; 64 BYTES TO ZERO
LOOP20TO5F:
MOV @R0, #00H
INC R0
DJNZ R7, LOOP20TO5F
LJMP HCQ1
; ---------------------------------
SETB STAT.0 ; 初始狀態(tài)為等號狀態(tài)
MOV R7, #00H
MOV SCON, #00H ; 串行工作方式0
; -------------------------------------
;DISPLAY INIT
; -------------------------------------
; LCALL LCDINIT
MOV COM,#06H
;LCALL PR1
MOV COM,#0C0H
;LCALL PR1
MAIN_LOOP:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 鍵 盤 輸 入
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 獲取鍵盤輸入,使用寄存器組00
CLR RS1
CLR RS0
; 獲取輸入
MOV A, #0F0H
WAITKEY:
NOP
CJNE A, #0F0H, WAITKEY_OK
LCALL KEY
SJMP WAITKEY
WAITKEY_OK:
MOV A, R7
MOV INPUT, A ; 保存鍵盤輸入到INPUT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 按鍵響應(內部處理)
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 處理鍵盤輸入,使用寄存器組01
CLR RS1
SETB RS0
LCALL KEYPRESSED
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 顯 示
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LCALL DISPLAY
SJMP MAIN_LOOP
; ========================================================
; ==
; == S U B R O U T I N E S
; ==
; ========================================================
KEYPRESSED:
; 鍵盤輸入保存在 A 中,同時也保存在 INPUT 中
ANL A, #0F0H ; 屏閉低4位字節(jié)
JNZ NONDIGIT ; 高位非零,不是數字
; =========================================
; 按鍵為數字
; 否則按下的是數字,添加到顯示緩沖區(qū)
MOV A, INPUT ; 取回數字,高位已經是0
; 如果之前處于“等號”狀態(tài),則此為NUM1
JB STAT.0, NEWNUM1
; 如果之前處于運算符狀態(tài),則此為NUM2
JB STAT.3, NEWNUM2
; 如果處于第一個數字狀態(tài)
JB STAT.1, INNUM1
; 如果處于第二個數字狀態(tài)
JB STAT.2, INNUM2
; 否則出錯?。?
SETB STAT.7 ; ERROR BIT
RET ; KEYPRESSED 直接結束
; --------------------------
NEWNUM1:
ANL STAT, #0F0H ; 操作狀態(tài)清零(低4位)
SETB STAT.1 ; 計算器狀態(tài)改為 NUM1
; 同時清除浮點運算狀態(tài)
CLR STAT.6 ; STAT.6 -> FLOATING POINT
SJMP NEWNUM
NEWNUM2:
ANL STAT, #0F0H ; 操作狀態(tài)清零(低4位)
SETB STAT.2 ; 計算器狀態(tài)改為 NUM2
SJMP NEWNUM
NEWNUM:
; 準備開始一個新的操作數,首先清除顯示緩沖區(qū)
MOV RAWPTR, #RAWIN ; 指向開始
; 清除小數點標志位
CLR PNTB
MOV DCOUNT, #00H ; 數字個數清零
; 判斷數字是否為0,0則忽略
JZ IGNORE0
; 非零數字,保存
MOV RAWIN, A ; 此時RAWPTR單元的值,也就是地址
; 就是RAWIN
INC RAWPTR
; 數字位數增 1
INC DCOUNT
IGNORE0:
RET
; --------------------------
INNUM1:
INNUM2:
MOV R2, DCOUNT
CJNE R2, #08H, INNUM_OK
; 數字個數已經達到最大值,忽略本次輸入
RET
INNUM_OK:
MOV R0, RAWPTR ; 使用R0間接尋址
MOV @R0, A
INC RAWPTR
INC DCOUNT
RET
; =========================================
; 按鍵非數字
NONDIGIT:
MOV A, INPUT ; 恢復A
INC A ; '.' 用 0FFH 表示,加1后為0
JZ DECPNT ; DECIMAL POINT PRESSED
DEC A ; 否則不是小數點,減一恢復之
; 非數字的情況:
; 1. 加, 減, 乘, 除: 高4位應該分別為 0001, 0010, 0011, 0100
; 2. 小數點: 代碼為 0FFH, 前面已經考慮
; 3. 等號: 1000 0000 (80H)
; 首先檢查是否是等號 (最高位為1)
JB ACC.7, KEYEQU
; 否則作為運算符對待
LJMP KEYOP
; ---------------------------------
ERRORND:; ERROR OF NON-DIGIT
; 出錯…………
SETB STAT.7
LJMP EXIT
; =======================================================
DECPNT:
; 根據計算器狀態(tài)進行操作
JB STAT.1, DP1
JB STAT.2, DP2
JB STAT.3, DP3
JB STAT.0, DP0
; ERROR
SETB STAT.7
LCALL EXIT
DP1:
DP2:
; 在數字輸入狀態(tài)下下按下了小數點,如果之前已經按過小數點
; 則忽略此次輸入,計算器狀態(tài)字無需修改
JB PNTB, DP_DONE ; 小數點已經按下
; 否則,這是本次操作數輸入第一次按下小數點
; 首先設置小數點已經按下標志位
SETB PNTB
; 否則添加小數點到輸入區(qū),也就是顯示區(qū)
; 首先判斷第一個數字是不是0
MOV R0, RAWPTR ; 獲取指針用于比較
; 如果當前輸入位置不是開始(前面已有非零數字存儲),直接添加小數點
CJNE R0, #RAWIN, DP_ADD
; 否則,RAWPTR還是指向RAWIN位置,第一個數字設置為0,
; 后再添加小數點
MOV R0, RAWPTR ; 用R0間接尋址
MOV @R0, #00H
INC RAWPTR
INC DCOUNT
DP_ADD:
MOV R0, RAWPTR ; R0間接尋址
MOV @R0, #0FFH ; DECIMAL POINT
INC RAWPTR
INC DCOUNT
DP_DONE:
RET
; --------------------
DP0:
; 之前的狀態(tài)為等號,按下小數點后因該開始第一個操作數輸入
; 設置狀態(tài)
ANL STAT, #0F0H
SETB STAT.1
SJMP DP_NEW
; --------------------
DP3:
; 之前處于操作符狀態(tài),按下小數點則應該開始第二個操作數輸入
; 設置狀態(tài)
ANL STAT, #0F0H
SETB STAT.2
; 新的操作數開始
SJMP DP_NEW
; --------------------
DP_NEW:
; 小數點開始的新的操作數,添加'0' '.' 兩個輸入
; 初始化
MOV RAWPTR, #RAWIN
MOV DCOUNT, #00H
CLR PNTB
MOV RAWIN, #00H ; 第一個數字,0
INC RAWPTR
INC DCOUNT
MOV R0, RAWPTR ; 使用R0間接尋址來存儲小數點
MOV @R0, #0FFH ; 小數點使用0FFH表示
INC RAWPTR
INC DCOUNT
RET
; =======================================================
KEYEQU:
; 保存原來的狀態(tài)
MOV B, STAT
; 設置現(xiàn)在的狀態(tài)為EQU
ANL STAT, #0F0H ; 清楚低4位狀態(tài)
SETB STAT.0 ; EQU STAT BIT
; 根據原來的狀態(tài)采取相應的操作
JB B.1, EQU1 ; 原來處于第一個數的輸入狀態(tài)
JB B.2, EQU2 ; 原來處于第二個數的輸入狀態(tài) (NORMAL)
JB B.3, EQU3 ; 原來處于操作符狀態(tài)
JB B.0, EQU0 ; 原來處于等號狀態(tài)
; ERROR
SETB STAT.7
LJMP EXIT
EQU1:
; 在第一個數的狀態(tài)下按了等號,那么第一個數不需要進行計算
; 直接作為結果顯示,實際上RAWIN就是當前的操作數的顯示格式
; 因此只需要將第一個數轉換成浮點數存儲于NUM1
SETB RS0
CLR RS1
MOV R0, #RAWIN ; SOURCE
MOV R1, #NUM1 ; DESTINATION
LCALL MAKENUM ; NOTE: MAKENUM!!!
RET
EQU2:
; 在第二個數的狀態(tài)下按了等號,這是最普通的操作
; 首先轉換操作數二到NUM2位置,然后計算結果
; 并將結果轉化為RAWIN形式,供DISPLAY顯示
MOV R0, #RAWIN
MOV R1, #NUM2 ; DESTINATION
LCALL MAKENUM ; NOTE: MAKENUM..
; 計算結果,結果放在NUM1
LCALL CALCULATE ; NOTE: CALCULATE!!!
; 結果轉換為RAWIN,即從NUM1到RAWIN
LCALL RES2RAW ; NOTE: RES2RAW
NOP
RET
EQU3:
; 原來狀態(tài)為操作符,然后直接按了等號
; 本程序采取的措施為:等1號覆蓋前面的操作符
; 因此不需要采取任何措施,直接同按下了第一個
; 操作數后直接按等號相同,由于按下操作符的時候
; 已經處理了第一個操作數,因此這里直接返回
RET
EQU0: ; SYSTEM RESET
; 原來狀態(tài)為等號,然后又按了等號
; 第一次按等號的時候已經處理好,這里只需返回
; 07.24 修改,連續(xù)兩次等號相當于清0
; 首先清除錯誤狀態(tài)位
CLR STAT.7
MOV DCOUNT, #00H ; DCOUNT設置為0,顯示就為0
RET
; ========================================================
; 操作符處理,注意:前面已經判斷不是等號
KEYOP:
; 保存操作符號: 給定的是 10H, 20H, 30H, 40H
; 轉換為 00H, 10H, 20H, 30H. 即,減去 10H
;DEBUGHERE
CLR C
SUBB A, #10H
; INVARIANT: 除了4, 5位,其他位不可能為1
KEYOP_NE: ; KEY OPERATOR, NO ERROR
; 如果是第一個數之后按的運算符
JB STAT.1, KOP1
; 如果是第二個數之后按的運算符
JB STAT.2, KOP2
; 如果是一個運算符之后按的運算符
JB STAT.3, KOP3
; 如果是按了等號后按的運算符
JB STAT.0, KOP0
; ERROR
SETB STAT.7
LJMP EXIT
; ------------------
KO_NE_DONE: ; KEY OPERATOR, NOT EQUAL, DONE
; 完成相應的操作后,更新STAT到當前狀態(tài)
; 取回 INPUT ,并減去 10H ,成為STAT要求的操作符表示
MOV A, INPUT
CLR C
SUBB A, #10H
; 運算符信息保存在 STAT 的 4,5位
; 先將4,5位清0
ANL STAT, #0CFH ; #1100 1111B
ORL STAT, A ; 設置4,5位
; 設置新的計算器狀態(tài)
ANL STAT, #0F0H ; 清除狀態(tài)(低4位)
SETB STAT.3 ; 操作符號狀態(tài)
RET ; KEYPRESSED 返回
; --------
KOP1:
; 如果按了第一個數字之后按了操作符
; 則首先將當前顯示緩沖區(qū)里的數字
; 拼合為3字節(jié)浮點數
; 保存在NUM1位置
; RAWIN 保持不變,因此計算器顯示的仍然為
; 第一個操作數
MOV R0, #RAWIN ; 需要進行拼湊的數字
MOV R1, #NUM1 ; 目的
LCALL MAKENUM
SJMP KO_NE_DONE
KOP2:
; 如果按了第二個數字之后按了操作符,
; 首先計算前面的結果,然后結果作為
; 第一個數, 并設置狀態(tài)為操作符
; 顯示區(qū)域的數據為前面操作的結果
; 即:需要將3字節(jié)的浮點數結果轉化
; 為可以顯示的RAWIN格式。
; 創(chuàng)建第二個操作數
MOV R0, #RAWIN
MOV R1, #NUM2
LCALL MAKENUM
; 執(zhí)行計算
LCALL CALCULATE
; 結果默認已經存儲于到NUM1位置
; 但是需要將其轉換為RAWIN形式用于DISPLAY子程序的顯示
LCALL RES2RAW ; NOTE: RES2RAW
SJMP KO_NE_DONE
KOP3:
; 按了一個操作符后又按了另一個操作符,則直接忽略原來的
; 前面已經設置了操作符狀態(tài),此處無需進行任何操作
SJMP KO_NE_DONE
KOP0:
; 按了等號之后按的操作符,則運算結果直接作為第一個
; 操作數,因為按等號的時候已經進行了結果運算和顯示
; 所需要的準備工作(將浮點數轉換為RAWIN形式)
; 因此這里不需要再作其他工作
SJMP KO_NE_DONE
; =======================================================
EXIT:
SJMP $
; =======================================================
; =======================================================
MAKENUM: ; NOTEE!!!
; [R0] 為RAWIN
; [R1] 為目標,NUM1 OR NUM2
; 先決條件:見前面
; 后決條件:NUM1中為二進制浮點數(3字節(jié),補碼形式)
; 轉換結果,RAWIN形式的數字被轉換為3字節(jié)二進制浮點數
MOV A, R0
MOV R3, A ; 保存源位置
MOV A, R1
MOV R4, A ; 保存目的位置
MOV R2, #00H ; 小數點位置
; 保存 DCOUNT ,子程序結束后 DCOUNT
; 和 [R0] 內容應該不變
PUSH DCOUNT
; 如果 DCOUNT 為零,則就是0
MOV A, DCOUNT
JZ VALZERO
SJMP MN_DC_NZ ; DCOUNT NOT ZERO
; ------------------
; 結果為0
VALZERO:
; 三個字節(jié)均設置為0
MOV @R1, #00H
INC R1
MOV @R1, #00H
INC R1
MOV @R1, #00H
LJMP MAKENUM_DONE
; -----------------------
MN_DC_NZ: ; MAKENUM, DCOUNT, NOT ZERO
; 判斷是否以0開始,是則為純小數
MOV A, @R0
JZ PUREDEC
; 不是純小數,則從第一位開始計算數字個數,
; 直到遇到小數點或者輸入數據結束(即是個整數)
NONPUREDEC:
; 在計算指數的同時進行尾數的創(chuàng)建
INC R1 ; 暫時忽略第一個指數字節(jié)
; POSB 為 0 則進行高字節(jié)創(chuàng)建
CLR POSB
FINDPNT:
MOV A, @R0 ; 取數
; 更新 R0 ,指向下一個
INC R0
; 如果為小數點(用0FFH表示的一個字節(jié)),
; 則計數結束,否則繼續(xù)
CJNE A, #0FFH, NEXTFP
NDMAN_CONT: ; NON DECIMAL MANTISSA, CONTINUE
; 小數點找到,繼續(xù)創(chuàng)建尾數的BCD碼
; 指數已經保存于 R2
DEC DCOUNT
MOV A, DCOUNT
; 出口
JZ NPD_DONE ; NON PURE DECIMAL DONE
MOV A, @R0 ; 取數
JB POSB, LOWER4_2 ; 創(chuàng)建低4位
; -------------
; 高4位
SWAP A
MOV @R1, A
INC R0 ; 指向下一個,繼續(xù)判斷
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -