INC R1 ; 指向尾数第一个字节
; 创建尾数
; R0 指向了尾数第一个数字
; 逐个读取只到读满4个数字或者输入数据用完(DCOUNT -> 0)
MANTISSA: ; BYTE2USAGE
CLR BYTE2 ; 指示是否已经设置尾数中的第二个字节 ; 因为可能在只有一位或者二位尾数的情况下, ; 尾数中的字节2没有设置,此时必须显示将其设为0 MAKEMAN: ; MAKE MANTISSA
; 2字节的RAWIN对应于1个字节的BCD形式 ; BCD高位:第一个数字 MOV A, @R0 ; 取出 SWAP A ; 放到高字节 MOV @R1, A ; 存放
; DCOUNT 等在子程序 UPDATEM 里更新 ACALL UPDATE_MS ; UPDATE MANTISSA STATE ; BCD低位:第二个数字
MOV B, @R1 ; 取回设置了高字节的BCD MOV A, @R0 ; 取输入数字
ORL A, B ; 将原来的数和现在的数结合为BCD码 MOV @R1, A
ACALL UPDATE_MS ; 更新状态,判断是否结束
; 如果没有结束,开始一个新的字节 ; 此时至少是第二个字节,设置 BYTE2 SETB BYTE2
; 将所有的的输入数据都转换为BCD码。
; 虽然只有前4个字节(对应2字节BCD码)有效 SJMP MAKEMAN
; -----------------------------------
UPDATE_MS: ; UPDATE MANTISSA STATE INC R0 DEC DCOUNT MOV A, DCOUNT JZ VALDONE ; 数字用完 RET VALDONE:
; 从UPDATEM子程序中跳出,首先跳过堆栈前面两个字节 POP ACC POP ACC
JB BYTE2, VALDONE_RET ; 第二个字节已经写入,可以返回 ; 尾数第二个字节没有写过,说明还需要将末尾字节填0 ; 例如,0.009,尾数为 90H XXH,第2个字节未设置 MOV A, R4 ; 取目的地址 MOV R1, A
INC R1 ; 指向第3个字节,第2个字节 INC R1 ; 不可能为零,否则整个数为0 MOV @R1, #00H VALDONE_RET: ; FINALIZE 操作 LJMP MAKENUM_DONE
; -----------------------
; 计算小数点后0的个数 PUREZERO:
INC R2 ; 0个数增加
; INC R1 ; 指向下一个数据 ; CMT. 07.25 ; DEC DCOUNT ; DEL: 07.25 MOV A, DCOUNT
JZ TOVALZERO ; 如果在计算零的过程中数据用完,则这是个零 SJMP COUNTZERO ; 继续计数 ; ----------------------------------- TOVALZERO: LJMP VALZERO
; ----------------------------------- MAKENUM_DONE:
POP DCOUNT ; 恢复 DCOUNT MOV A, R4
; 进行BCD到二进制浮点数的转换
; 使用寄存器工作组10 -> OBSOLETED. 07.25 SETB RS1 CLR RS0
MOV R0, A ; R0指向刚刚创建的BCD浮点数 LCALL BTOF ; BCD TO FLOAT ; 恢复寄存器工作组01 CLR RS1 SETB RS0
RET ; MAKENUM 完成
; =======================================================
CALCULATE: ; NOTEE!!!
; 操作数在NUM1, NUM2,格式为MAKENUM的结果,即二进制的浮点数 ; 可以直接对其进行浮点程序库的调用 ; REGISTER GROUP 10 SETB RS1 CLR RS0
; 操作数: MOV R0, #NUM1 MOV R1, #NUM2
; 根据计算器的状态进行加减乘除的调用 ; 操作符保存在 STAT 的第5第4位 ;54: OPERATOR ; 00: ADD (0) ; 01: SUB (1) ; 10: MUL (2) ; 11: DIV (3) MOV A, STAT
ANL A, #30H ; 仅保留5,4两位 SWAP A ; 切换到低位用于查表 JZ CALC_ADD ; 0表示加 DEC A
JZ CALC_SUB ; 减1后为零,说明原来是1,表示减 DEC A
JZ CALC_MUL ; 乘法 DEC A
JZ CALC_DIV ; 除法 ; ----------- CALC_DONE:
; 如果 OV 为1,则计算结果有误,设置错误位STAT.7 ; 显示的时候如果STAT.7为1,则显示错误字符 E JNB OV, CALC_OK ; OV为1,设置 STAT.7 SETB STAT.7 CALC_OK: RET ; -------- CALC_ADD: LCALL FADD SJMP CALC_DONE CALC_SUB: LCALL FSUB SJMP CALC_DONE
CALC_MUL: LCALL FMUL SJMP CALC_DONE CALC_DIV: LCALL FDIV SJMP CALC_DONE
; ======================================================= RES2RAW: ; NOTEE!!!
; 运算结束后,NUM1中存放的是3字节二进制浮点数格式的结果, ; 将其转换为RAWIN形式存放于RAWIN位置,供显示程序使用
; 首先将结果转换为 BCD 的浮点数,保存于一个临时位置TEMP
MOV R0, #NUM1 ; 初始化要转换的数字 MOV R1, #TEMP ; 暂存地址
MOV R2, #03H ; 移动3个字节, R2仅使用于R2R_COPY3 R2R_COPY3: ; 将NUM1复制到 TEMP MOV A, @R0 MOV @R1, A INC R0 INC R1
DJNZ R2, R2R_COPY3
MOV R0, #TEMP ; 将这个二进制浮点数转换为BCD格式浮点数 ; 注意:NUM1中数字不可转换,因为之后还要在计算中使用
; 寄存器工作组 10 SETB RS1 CLR RS0
LCALL FTOB ; FLOAT TO BCD
; 恢复使用寄存器组01 CLR RS1 SETB RS0 ; 初始化
MOV DCOUNT, #00H ; 数字个数计数(此计数包括减号和小数点) ; 判断是否为零(即2,3字节均为00H) MOV R0, #TEMP ; 间接取址寄存器
INC R0 ; 字节2 MOV A, @R0
JZ R2R_B2_ZERO ; 为零,继续检查第三字节是否为零
SJMP R2R_NORMAL ; 开始正常处理
R2R_B2_ZERO: ; RES2RAW, BYTE 2, ZERO INC R0 ; 第三个字节 MOV A, @R0 JZ R2R_VAL_ZERO
SJMP R2R_NORMAL ; 开始正常处理 R2R_VAL_ZERO: ; R2R, VALUE, ZERO
MOV DCOUNT, #00H ; DCOUNT 为零表示结果为零 RET
; ---------------
R2R_NORMAL: ; 非零情况 ; 寄存器使用: ; R0 源指针 ; R1 目的指针 ; R2 临时 ; R3 临时 ; R4 ; R5
; R6 指数迭代器 ; R7 循环计数器
MOV R0, #TEMP ; 源指针 MOV R1, #RAWIN ; 目的指针
MOV A, TEMP ; 取第一个字节,即指数 JNB ACC.7, R2R_POS ; 最高位为0,正数
; 否则为负数,应该先放置一个'-' ; '-' 用 #0BH 表示 MOV @R1, #0BH INC R1 ; 下一个位置
INC DCOUNT ; DCOUNT指示整个字符串长度
R2R_POS: ; RES2RAW, POSITIVE: 正数 MOV C, ACC.6 ; 指数的符号位是第7位
MOV ACC.7, C ; 设置A的最高位为A的第6位,即指数的符号位 JZ R2R_ZERO_E ; 指数为零,数字形式为 0.XXXX
; NOTE: JUMP OUT OF RANGE?? JNB ACC.7, R2R_POS_E ; 指数为正