📄 calc.asm
字号:
sd_test: jc sd_decimal
sd_decimal: mov R4,digitcode ; Test for decimal points - only allow one per number to be inputed.
cjne R4,#02Eh,sd_continue
inc decimalcnt ; We need to see whether this is the first decimal point to be inputed in this number.
mov R3,decimalcnt ; This will be reset in the inputnum subroutine when we are finished with the number.
cjne R3,#1,sd_done ; It is a decimal point and it is not the first so don't store it.
; Fall through to sd_continue if it is the first decimal point.
sd_continue: cjne R5,#0,sd_loop ; If it is zero goto write
jmp sd_write ;
sd_loop: inc DPTR
djnz R5,sd_loop ; increment DPTR to DPTR + bufferctr
sd_write: mov A,digitcode
movx @DPTR,A ; Write the digit into the Buffer
inc bufferctr ; we write digits from bufferctr pos 1 - 8.
; Buffer position 0 is reserved for the sign.
sd_done: pop DPL
pop DPH
ret
;---------------------------------------------------------------------------------
;STATUSCHECK - Subroutine to test if this is the first key pressed after an operation
; and if so to clear the screen.
;---------------------------------------------------------------------------------
statuscheck: mov R2,status
cjne R2,#1,sc_done
mov R2,equalsflag
cjne R2,#1,sc_clear
mov R4,digitcode ; This caters for num - op - num - equ - num. A number after an equals
mov local, R4 ; signifies a new calculation.
mov mode,#3
call getmode
call floating_point_output
call bufferclear
mov opcounter,#0
mov bufferctr,#00h
mov digitcode,#020h
call storedigit
mov R4,local
mov digitcode,R4
mov mode,#1
call getmode
mov decimalcnt,#00h
sc_clear: mov status,#00h
sc_setflags: mov memopflag,#00h
mov equalsflag,#00h
mov arithopflag,#00h
mov pctopflag,#00h
sc_done: ret ; clear status to indicate that a digit key has been pressed.
;---------------------------------------------------------------------------------
;BUFFEROUTPUT - Subroutine to write the keybuffer onto the screen.
;---------------------------------------------------------------------------------
bufferoutput: push DPH ; preserve the Datapointer
push DPL
call clearscreen ; clears the screen and sets the LCD address to the far right.
call getmode ; point at the keybuffer
mov R3,bufferctr ; We know the length of the number from the bufferctr
mov bufferctr,#0
mov R5,#0
bo_start: mov R7,bufferctr
clr A
bo_output: movx A,@DPTR ; read the digit into A
;cjne A,#02Eh,bo_write ; if a decimal point don't count that as one of the 8 output chars.
;dec R5
;jmp bo_write
bo_write: call wrdata ; write out the digit.
bo_test: clr c ; need to clear the carry before the subb instruction.
mov A,R3 ; test for the end of the string.
subb A,R7
mov R7,A
clr A
cjne R7,#01h,bo_test2
jmp bo_sign
bo_test2: cjne R5,#8,bo_test3
jmp bo_increment
bo_test3: jc bo_increment
jmp bo_sign
bo_increment: inc bufferctr
inc R5
inc DPTR
jmp bo_start
bo_sign: mov R4,memocc
cjne R4,#1,bo_done
mov A,R3 ; Draws the 'M' on the far left when there is a number
add A,#LCD_SETDDADDR + 1 ; in the memory buffer. We need to offset by the amount of the
call wrcmd ; buffercounter because of the *shift* mode we have the LCD display
mov A,#04Dh ; set up in.
call wrdata
bo_done: mov bufferctr,R3
pop DPL
pop DPH
ret
;---------------------------------------------------------------------------------
;BUFFERCLEAR - Subroutine to clear the keybuffer.
;---------------------------------------------------------------------------------
bufferclear: push DPH
push DPL
call getmode
mov R2,#9 ; Clear the buffer.
mov A,#0
bc_loop: movx @DPTR,A ; Write a zero into the buffer position addressed by DPTR
inc DPTR ; move the Datapointer along the databuffer.
djnz R2,bc_loop ; loop through the bufferlength
pop DPL
pop DPH
ret
;---------------------------------------------------------------------------------
;CLEARSCREEN - Subroutine to clear the screen and set the writing to the RHS.
;---------------------------------------------------------------------------------
clearscreen: mov A,#LCD_CLS
call wrcmd
mov R4,memocc ; We need to account for the extra digit outputed ( 'M' ) when
cjne R4,#1,cs_standard ; there is a number in memory. Due to the mode that we have set the
mov A,#LCD_SETDDADDR + 16 ; display in (i.e. shifts display left) we need ddaddress set one further
call wrcmd ; right in this case.
jmp cs_done
cs_standard: mov A,#LCD_SETDDADDR + 15 ; Standard case when nothing is in memory (output number only )
call wrcmd
cs_done: ret
;---------------------------------------------------------------------------------
;BUFFERCOPY - Subroutine to copy the keybuffer contents into oldnumbuffer.
;---------------------------------------------------------------------------------
buffercopy: push DPH ; Preserve the DataPointer
push DPL
mov R7,bufferctr ; Preserve the Bufferctr
mov bufferctr,#00h
mov R2,#8 ; Set the counter to the buffer size
bc_transfer:
mov R5,bufferctr
mov R6,copyfrom ; Get the copy info.
mov mode,R6 ; ( set to a mode depending on which buffer we wish to access )
call getmode
cjne R5,#0,bc_address1
jmp bc_readin
bc_address1: inc DPTR
djnz R5,bc_address1
bc_readin: movx A,@DPTR
;cjne A,#020h,bc_continue
;jmp bc_increment
bc_continue: mov R6,copyto
mov mode,R6
call getmode
mov R5,bufferctr
cjne R5,#0,bc_address2
jmp bc_writeout
bc_address2: inc DPTR
djnz R5,bc_address2
bc_writeout: movx @DPTR,A
bc_increment: inc bufferctr ; loop through the Buffersize .
djnz R2,bc_transfer
mov bufferctr,R7 ; Restore Bufferctr
mov mode,#1
bc_done: pop DPL
pop DPH
ret
;---------------------------------------------------------------------------------
;INPUTNUM - Subroutine to push the number onto the stack.
;---------------------------------------------------------------------------------
inputnum: call getmode ; move the DPTR back to the beginning of the appropriate buffer
call floating_point_input ; move the contents of the keybuffer onto the floating point stack
mov bufferctr,#00h ; move the buffercounter back to zero ready for the next operation
mov decimalcnt,#00h ; Reset the decimal point counter for the next number.
ret
;---------------------------------------------------------------------------------
;INITIALIZE - Subroutine to initialize the calc on startup.
;---------------------------------------------------------------------------------
initialize: mov mode,#1 ; set the mode to default ( DPTR, points at the KEYBUFFER )
call getmode ; Set the DPTR to address the appropriate buffer.
call bufferclear
mov bufferctr,#00h
mov digitcode,#020h ; initialise with a space in position 0 to indicate a positive number.
call storedigit
mov signflag,#0
mov status,#1 ; start with status = 1 so if an op is pressed first 0 becomes the first no
; on the stack - if a digit is pressed first the zero is trashed.
call clearscreen ; sets the ddaddress to be at the RHS
mov digitcode,#30h ; start with 0 on the screen
call storedigit
call bufferoutput
mov R4,bufferctr
dec R4
mov bufferctr,R4
ret
;---------------------------------------------------------------------------------
;RESETSIGN - Subroutine to ensure that every number starts as being positive.
;---------------------------------------------------------------------------------
resetsign: call getmode ; point at the buffer to clear.
call bufferclear
mov bufferctr,#00h ; Clear the signfrom the buffer and set the buffer position.
mov digitcode,#020h ; StoreDigit increments the buffer position *AFTER* storage.
call storedigit ; This leaves us with position 0 clear and bufferctr set to 1.
mov signflag,#00h
rs_done: ret
;----------------------------------------------------------------------------------------------
;GETMODE - Subroutine to point the Datapointer at the required buffer - dependant on the mode.
;----------------------------------------------------------------------------------------------
getmode: mov R4,mode
cjne R4,#1,gm_memory
mov DPTR,#KEYBUFFER
jmp gm_done
gm_memory: cjne R4,#2,gm_oldnum
mov DPTR,#MEMORYBUFFER
jmp gm_done
gm_oldnum: cjne R4,#3,gm_const
mov DPTR,#OLDNUMBUFFER
jmp gm_done
gm_const: cjne R4,#4,gm_bounds
mov DPTR,#HUNDREDBUFF
jmp gm_done
gm_bounds: cjne R4,#5,gm_temp
mov DPTR,#BOUNDBUFFER
jmp gm_done
gm_temp: cjne R4,#6,gm_done
mov DPTR,#TEMPBUFFER
gm_done: ret
;----------------------------------------------------------------------------------------------
;BOUNDSBUFFER- Generate a buffer with the maximum permissable value i.e 99999999
;----------------------------------------------------------------------------------------------
boundsbuffer: push DPH
push DPL
mov mode,#5
mov R3,bufferctr ; Preserve the bufferctr.
mov bufferctr,#0
mov digitcode,#020h
call storedigit
bb_loop: mov digitcode,#039h ; Enter digit 9.
call storedigit
mov R4,bufferctr
cjne R4,#9, bb_loop
mov digitcode,#0
call storedigit
mov bufferctr,R3
bb_done: pop DPL
pop DPH
ret
;----------------------------------------------------------------------------------------------
;ERRORCHECK - Checks the upper and lower bounds and divide by zero.
;----------------------------------------------------------------------------------------------
errorcheck: jb ACC.3,ec_divide ; Result is on the stack.
mov errorflag,#01h ; We set the error flag here and clear it if appropriate later.
mov mode,#6 ; output and then input result
call getmode
mov bufferctr,#0
call floating_point_output
call inputnum
mov mode,#5
mov bufferctr,#0
mov digitcode,#020h
call storedigit
call inputnum ; input the UBound on the stack
clr c
call floating_comp ; Call floating_compare ( pops twice and returns status ).
jc ec_lower ; Carry set so less than Ubound
jmp ec_upperr ; Otherwise error - result too large.
ec_lower: mov mode,#6
call inputnum ; input result
mov mode,#5 ; make the max number negative ( i.e. the lower bound )
mov bufferctr,#0
mov digitcode,#02Dh
call storedigit
mov mode,#5
call inputnum ; input the lower bound.
clr c
call floating_comp
jc ec_lowerr ; Error - result too low
jmp ec_ok ; Greater than lower bound so o.k.
ec_divide: call clearscreen
mov DPTR,#errorstr ; Error message.
call wrstr
mov DPTR,#500
call wtms
mov mode,#6
call inputnum ; input result.
mov mode,#1
call getmode
mov status,#1
jmp ec_done
ec_upperr: call clearscreen
mov DPTR,#errorstr ; Error message.
call wrstr
mov DPTR,#500
call wtms
mov mode,#6
call inputnum ; input result.
mov mode,#1
call getmode
mov status,#1
jmp ec_done
ec_lowerr: call clearscreen
mov DPTR,#errorstr ; Error Message
call wrstr
mov DPTR,#500
call wtms
mov mode,#6
call inputnum ; input result.
mov mode,#1
call getmode
mov status,#1
jmp ec_done
ec_ok: mov mode,#6
call inputnum ; input result.
mov errorflag,#00h
ec_done: mov mode,#6
call getmode
call bufferclear
mov mode,#1
call getmode
ret
;----------------------------------------------------------------------------------------------
;BANNER - Exports a wraparound banner to the LCD screen.
;----------------------------------------------------------------------------------------------
Banner:
call clearscreen
mov A,#LCD_SETDDADDR+16 ; Start at right hand side of the display
call wrcmd
Reloop: mov DPTR,#STRING1
Iterate: call wrstr
mov DPTR,#1000
call wtms
call clearscreen
ret
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -