head	1.1;
access;
symbols;
locks
	david:1.1; strict;
comment	@;; @;


1.1
date	97.06.04.02.59.13;	author david;	state Exp;
branches;
next	;


desc
@Initial Version.
@


1.1
log
@Initial revision
@
text
@
        ORG   $18
FPSCR   DS    8     ; Floating point scratch area.

        org $20     ; Start of on chip stuff.
 
RAWCNT  ds   5      ; (5) Store raw counts from BCD A/D convertor here.
DISPLY  equ  RAWCNT ; (5) Display data is kept here before moving external.
ZERO    ds   2      ; (2) Binary zero count for scale base one.
ZERO2   ds   2      ; (2) Zero count for scale base two.
BIN     ds   4      ; (4) Binary weight (lo byte- hi byte). BINDIV uses 4.
MOD10   equ  BIN+2  ; (2) Temporary storage for bindec.
TARE    ds   2      ; (2) Binary tare value.
BASE    ds   1      ; (1) Flag to show wich base we are using.

         ORG   $30

FPR0     DS    4           ; Floating point register 0.
FPR1     DS    8           ; Floating point register 1.
FPR2     DS    4           ; Floating point register 2.


;******* DEFINE OFF CHIP ADDRESSES  *******

LEDADR  EQU $05     ; ADDRESS OF LED DATA IN EXTERNAL MEMORY

;******* DEFINE SOME CONSTANTS THAT ARE USED IN PROG *******
ZON	EQU $80	    ; ORL P2,# to turn AZT light on.
ZOFF	EQU $7F     ; ANL P2,# to turn AZT light off.
SETAOF	EQU $10     ; ORL P1,# to turn relay A off.
SETAON  EQU $EF     ; ANL P1,# to turn relay A on.
SETBOF  EQU $20     ; ORL P1,# to turn relay B off.
SETBON  EQU $DF     ; ANL P1,# to turn relay B on. 
BLNK    EQU $0F     ; CODE TO TURN DISPLAY DIGIT OFF
UNDERC	EQU $0E     ; Underline code.
OVERC	EQU $0C     ; Overload code.
TOPBOX  EQU $0B	    ; This is the top box code.
BOTBOX  EQU $0A	    ; Bottom box code.
MINUSC  EQU $0D     ; This is the minus code.
KYDBNC  EQU $02     ; Keyboard debounce amount.
DYAMT   EQU $20     ; DELAY AMOUNT FOR DEBOUNCE DELAY ROUTINE

ZEROBT  EQU $00     ; The zero button is the zero key.
SCA0BT  EQU $01     ; Scale 0 select button.
SCA1BT  EQU $02     ; Scale 1 select button.
TAREBT  EQU $03     ; This defines the 3 key as the TARE   button.
SAMPBT  EQU $0A     ; This defines the * key as the SAMPLE button.
ENTRBT  EQU $0B     ; This defines the # key as the ENTER  button.
PRNTBT  equ $04     ; Printout button is key 4.

AVERGS  EQU $01     ; Number of averages per displayed reading (power of two)
SCALE0  EQU $BF     ; Force circuitry to read scale 1 by turning P26 lo.
SCALE1  EQU $40     ; Force reading of scale 2 by making P26 hi.

;******* Explanation of divide, mulply, decplc. ********
; Find number of displayed divisions (5000 or less on 3250).
; Find a number less than 18000 that the number of divisions will
; divide evenly into. The DIVIDE constant is found by dividing the second
; number by the first. The MULPLY constant is the number you wish
; the scale to count by. The DECPLC constant is the number of displayed 
; decimal places.
;    Examples:
; 
; scale type       divisions         divisor  DIVIDE         MULPLY  DECPLC
; ---------------------------------------------------------------------------
; 2  lb X .001      2000 (2/.001)    16000    8 (16000/2000)  1       3
; 2     X .0005     4000             16000    4               5       4
; 5  lb X .002      2500 (5/.002)    17500    7 (17500/2500)  2       3
; 10 lb X .005      2000 (10/.005)   16000    8 (16000/2000)  5       3
; 15 lb X .005      3000 (15/.005)   15000    5 (15000/3000)  5       3
; 25    X .01       2500 (25/.01)    17500    7 (17500/2500)  1       2
;*30    X .01       3000 (30/.01)    15000    5 (15000/3000)  1       2
; 30    X .005      6000             18000    3               5       3
; 50 lb X .02       2500 (50/.02)    17500    7 (17500/2500)  2       2
; 100   X .05       2000 (100/.05)   16000    8 (16000/2000)  5       2      
; 200   X .1        2000 (200/.1)    16000    8 (16000/2000)  1       1 
; 500   X .1        5000             15000    3               1       1
; 500   X .2        2500 (500/.2)    17500    7 (17500/2500)  2       1
; 1000  X .2        5000 (1000/.2)   15000    3 (15000/5000)  2       1
; 1000  X .5        2000 (1000/.5)   16000    8 (18000/2000)  5       1
; 2000  X .5        4000 (2000/.5)   16000    4 (16000/4000)  5       1
; 2000  X  1        2000 (2000/1)    16000    8 (16000/2000)  1       0
; 5000  X  1        5000 (5000/1)    15000    3 (15000/5000)  1       0
; 5000  X  2        2500 (5000/2)    17500    7 (17500/2500)  2       0
; 20000 X  10       2000             16000    8               10      0
;
DIVIDE  EQU  05     ; DISPLAY = RAW COUNTS/DIVIDE
MULPLY  EQU  01     ; DISPLAY = DISPLAY * MULPLY
DECPLC  EQU  02     ; Number of displayed decimal places.
;*********Which led to light up*****************************************
;Note: left = lbs, middle = oz, right = grams.   
;
LED     EQU $0C     ; LED left=$0C, middle=$0E, right=$0D
;******* RESET CODE HERE ***********************************************
 ORG $000      	 ; ORIGIN =000
RESET  		 ; RESET VECTOR
 MOVD P4,A     	 ; PROG RUNNING
 JMP  START  	 ; START PROG
 MOVD P4,A     	 ; PROG RUNNING
 JMP  START  	 ; START PROG
 NOP
 MOVD P4,A     	 ; PROG RUNNING
 JMP  START  	 ; START PROG
 ;********************************
START		 ; Any reset code here.

 mov  R0,#BASE   ; Start off with base 0, for internal scale.
 mov  @@R0,#$01
 ANL  P2,#SCALE0 ; Select scale zero by making P26 lo.

 MOV  R0,#TARE
 CALL LOCZER	 ;Zero TARE location.

 MOV  A,#BOTBOX	 ; Puts lower boxes on display.
 CALL CLRDSP	 ; Clear the display.

WAITKY
 MOVD P4,A       ; Allow the test switch to get out of this mode.
 CALL READ   	 ; Read A/D COUNTS into RAWCNT.
 CALL TRANS  	 ; Move RAWCNT to DISPLY.
 call DECBIN
 call BINDEC
 ANL  P1,#$F0 	
 ORL  P1,#$07 	 ; Select address 7 on 74150 (read dip switch on t0).
 JT0  BEGIN   	 ; If gross switch is on, display raw counts.

 CALL GETKEY	 ; Read keyboard.
 JZ   WAITKY	 ; No keys pressed, wait some more.

 CALL SWZERO     ; Zero the scale.
 ;********************************
BEGIN            ; MAIN LOOP HERE
;
 CALL READ   	 ; Read A/D COUNTS into RAWCNT.
 CALL TRANS  	 ; Move RAWCNT to DISPLY.

 ANL  P1,#$F0 	
 ORL  P1,#$07 	 ; Select address 7 on 74150 (read dip switch on t0).
 JT0  DISPRW   	 ; If gross switch is on, display raw counts.
 JF0  UNDER	 ; If we have negative raw counts, STOP display of weight.

 CALL DECBIN 	 ; Change BCD data at DISPLY to binary data at BIN.
 MOV  R1,#ZERO
 CALL BINSUB     ; SUBTRACT ZERO VAL   BIN=BIN-ZERO    (set f0=1 for minus).
 CALL BINDIV 	 ; DIVIDE COUNTS       BIN=BIN/DIVIDE
 CALL MUL16  	 ; MULTIPLY BY MULPLY  BIN=BIN*MULPLY
 CALL AZTRK	 ; See if we need to auto zero track the weight.

 MOV  R1,#TARE
 CALL BINSUB	 ; Subtract the tare value. BIN=BIN-TARE

 MOV  R0,#BIN    ; ****** Don't forget that BINDEC is destructive!!!*****
 CALL BINDEC 	 ; Convert binary data at BIN to BCD data at DISPLY.

 CALL DECMAL 	 ; Put a decimal point in the proper location.
 CALL ZTOSP  	 ; Supress leading zeros.
 CALL DISP	 ; Display number, including minus sign if f0=1.

 CALL CHKEY	 ; Are any keys pressed? If so, process them.

 JMP  BEGIN   	 ; Start it all over again.

UNDER
 MOV  A,#UNDERC  ; This is the code for underload.
 CALL CLRDSP
 JMP  BEGIN
;
DISPRW
 CALL DISP	 ; Display raw counts only.
 JMP  BEGIN
;
 ORG $70         ; Give me some breathing room for additions to prog.
 ;********************************
READ      	 ; USES A,R0,R1,R2
 ;          	   SAVES DATA TO RAWCNT
 ;            	   D1=RAWCNT D5=RAW+4
 ;		   R1=Mask for digit 1.

 mov  r1,#BASE	 ; Check and see if we need to read base 0 or 1.
 mov  a,@@r0      ; If it is zero, read internal scale.
 jnz  read2      ; Otherwise read external scale.

 ANL  P2,#SCALE0 ; Select scale zero by making P26 lo.

 MOV  R1,#$10     
 MOV  R0,#RAWCNT+4
READL
 MOVD P4,A
 MOVX A,@@R0    	 ; GET A-D DATA
 MOV  R2,A     	 ; SAVE
 CPL A        	 ; COMPLEMENT
 ANL A,R1     	 ; DIGIT ACTIVE?
 JZ  READL  	 ; NO,CHECK AGAIN
 MOV A,R2     	 ; GET DATA BACK
 ANL A,#$0F   	 ; MASK DATA
 MOV @@R0,A    	 ; SAVE DATA
 DEC R0       	 ; INC ADDRESS
 CLR C        	 ; CLEAR CARRY
 MOV A,R1     	 ; GET MASK
 RLC A        	 ; NEXT MASK
 MOV R1,A     	 ; GET MASK
 JNZ READL 	 ; NOT DONE 4 YET
TRANS1
 MOVD P4,A
DIGIT5
 JT1 DIGIT5 	 ; DIGIT 5 ACTIVE?
 NOP
 MOVX A,@@R0   	 ; GET A-D DATA
 JT1  TRANS1
 ANL  A,#$0F   	 ; MASK DATA
 MOV  @@R0,A   	 ; SAVE DIGIT 5
 RET          	 ; BACK TO CALLER

;*****Read scale base two here.*********

read2
 ORL  P2,#SCALE1 	; Select scale one by making P26 hi.
 
 MOV  R0,#RAWCNT 	; Save digit 5 at RAWCNT.
 mov  r3,#5		; Number of shifts before done.

trans2
 movd p4,a
 in   a,p2
 anl  a,#$20	 	; Is digit 5 not active?
 jnz  trans2 	 	; Wait for not active state.

 nop 

trans3
 movd p4,a
 in   a,p2
 anl  a,#$20	 ; Is digit 5 active?
 jz   trans3 	 ; Wait for active state.

 MOVX A,@@R0   	 ; GET A-D DATA

 ANL  A,#$0F   	 ; MASK DATA
 MOV  @@R0,A   	 ; SAVE DIGIT 5

 dec  r3	 ; Done 1 digit.
 inc  r0	 ; Save digit 4 at RAWCNT+1.

 MOV  R1,#$80	 ; Start mask at $80 for digit 4.   
  
READL2
 MOVD P4,A
 MOVX A,@@R0    	 ; GET A-D DATA
 MOV  R2,A     	 ; SAVE
 ANL  A,R1     	 ; DIGIT ACTIVE?
 JZ   READL2  	 ; NO,CHECK AGAIN
 MOV A,R2     	 ; GET DATA BACK
 ANL A,#$0F   	 ; MASK DATA
 MOV @@R0,A    	 ; SAVE DATA
 dec r3 	 ; Keep track of how many digits have been done.
 inc R0       	 ; INC ADDRESS
 CLR C        	 ; CLEAR CARRY
 MOV A,R1     	 ; GET MASK
 RRC A        	 ; NEXT MASK
 MOV R1,A     	 ; GET MASK
 mov a,r3	 ; Have we done 5 digits yet?
 JNZ READL2	 ; NOT DONE 5 YET

 RET          	 ; BACK TO CALLER

 ;*******************************
TRANS     ; USES R0,R1,R2,A
 ;          Moves RAWCNT to DISPLY
 MOV R0,#RAWCNT+4
 MOV R1,#DISPLY+4
 MOV R3,#$05     ; # TO MOVE
MOVE
 MOV A,@@R0     ; GET DATA
 MOV @@R1,A     ; PUT TO DISPLY
 MOV R2,A      ; SAVE
 DEC R1        ; NEXT MEMORY
 DEC R0        ; LOCATION
 DJNZ R3,MOVE

 mov  R0,#BASE	; See which base we are reading.
 mov  A,@@R0    
 jnz  tran2     ; Do special translation for base 1.

 MOVD P4,A
 CLR  F0 	; ASSUME A POSITIVE NUMBER
 MOV  A,R2	; GET DIGIT 5
 ANL  A,#$01 	; GET THE SIGN BIT
 JZ   NONEG	; IF BIT IS SET, WE HAVE NEGATIVE RAW COUNTS
 CPL  F0	; SHOW THAT WE HAVE NEGATIVE COUNTS
NONEG
 MOV A,R2       ; RETRIEV DIGIT 5
 ANL A,#$0E     ; +-1 CODE
 XRL A,#$0E     ; ONE?
 JNZ BLANK      ; NO
 MOV A,#$01     ; CODE FOR 1
 MOV R1,#DISPLY
 MOV @@R1,A      ; STORE DIGIT 5
 RET
BLANK
 MOV A,#00     ; ZERO CODE
 MOV R1,#DISPLY
 MOV @@R1,A     ; STORE IN DIGIT 5
 RET           ; YES,RETURN

tran2
 MOVD P4,A
 CLR  F0 	; ASSUME A POSITIVE NUMBER
 MOV  A,R2	; GET DIGIT 5
 ANL  A,#$08 	; GET THE SIGN BIT
 JNZ  NOTNEG	; IF BIT IS zero, WE HAVE NEGATIVE RAW COUNTS
 CPL  F0	; SHOW THAT WE HAVE NEGATIVE COUNTS
NOTNEG
 MOV A,R2       ; RETRIEVE DIGIT 5
 ANL A,#$01     ; Mask off all bits but zero.
 MOV R1,#DISPLY
 MOV @@R1,A      ; STORE DIGIT 5
 RET

 ;*******************************
 
; org $100

DISP   ; USES R0,R1,R2,R3,A
 MOVD P4,A
 MOV  R3,#$05    ; NUMBER TO SEND
 MOV  R0,#DISPLY ; GET DATA
 MOV  R1,#$05    ; DISPLAY ADDRESS
 MOV  A,#LED	 ; Get the LED code to light up.
 MOVX @@R1,A	 ; Move LED code out to display.
 DEC  R1
 JF0  DISP1 	 ;F0=1 for minus.
 JMP  LOOPER
DISP1
 MOV  A,@@R0	 ;Get first digit.
 ANL  A,#$10	 ;Mask of decimal point.
 JNZ  GODCP
 MOV  A,#MINUSC  ;Make this digit show minus sign.
 MOV  @@R0,A
 JMP  LOOPER
GODCP
 MOV  A,#MINUSC	 ;Minus sign if number is negative.
 ORL  A,#$10	 ;Turn decimal point on if decpt=4.
 MOV  @@R0,A
LOOPER
 MOV  A,@@R0      ; Get data from ram.
 MOVX @@R1,A      ; PUT TO DISPLAY
 INC  R0         ; INC GET ADDR
 DEC  R1         ; INC PUT ADDR
 DJNZ R3,LOOPER
 ORL  P1,#$40    ; UNDER LIGHT OFF
 RET
 ;*******************************
 ;
; ORG $100
SEND             ; R0,R1,R2,R3,A
 ;                 THIS SENDS DATA OUT
 ;                 DATA AT DISPLY
 ;
 JF0  NOSEND     ; If we have a negative number, do not send it!
 CALL ASEND      ; Print out the weight on scale which is at DISPLY.
 CALL LFCR       ; Send linefeed and carriage return.
NOSEND
 RET
;
ASEND		 ; Send Whatever is at DISPLY to printer.
 MOV  R0,#DISPLY
 MOV  A,@@R0      ; GET DIGIT
 ANL  A,#$0F     ; KILL DEC PT
 XRL  A,#$0D     ; IS IT MINUS?
 JNZ  NOZZZ
 MOV  A,#$2D     ; MINUS SIGN
 CALL OUTD
 MOV  A,#$20     ; SPACE
 CALL OUTD
 JMP  SEND4
NOZZZ
 MOV  A,#$20     ; SEND SPACE
 CALL OUTD
 MOV  A,#$20     ; SEND SPACE
 CALL OUTD
 MOV  A,@@R0      ; GET DIGIT 5
 XRL  A,#BLNK    ; IS IT BLANK?
 JZ  SKIP9       ; YES,SEND ZERO
 MOV  A,@@R0      ; NO,SEND DIGIT
 ANL  A,#$0F
 ORL  A,#$30     ; MAKE IT ASCII
 CALL OUTD
 JMP  SEND4
MINSS
 MOV  A,#$2D     ; MINUS CODE
 CALL OUTD
 MOV  A,#$20     ; SEND  SPACE
 CALL OUTD
 JMP  SEND4
SKIP9
 MOV  A,#$30     ; SEND ZERO
 CALL OUTD
SEND4
 MOV  R1,#$04    ; NUMBER OF DIG
SKIPT
 INC  R0         ; POINT TO NEXT
 MOV  A,@@R0      ; GET DIGIT
 ANL  A,#$0F     ; KILL DEC PLACE
 XRL  A,#BLNK    ; IS IT BLANK?
 JNZ  DODIG      ; NO, SEND DIGIT
 MOV  A,#$30     ; YES, SEND ZERO
 CALL OUTD       ; SEND IT
 JMP  COUNDG 
DODIG
 MOV  A,@@R0      ; GET DIGIT
 ANL  A,#$10     ; IS IT DECIMAL PT
 JZ   NODEC      ; NO DEC PT
 MOV  A,@@R0      ; GET DIGIT
 ANL  A,#$0F     ; KILL DEC PT
 ORL  A,#$30     ; MAKE IT ASCII
 CALL OUTD       ; SEND DIGIT
 MOV  A,#$2E     ; DEC PT CODE
 CALL OUTD       ; SEND IT
 JMP  COUNDG     ; DO NEXT DIGIT
NODEC
 MOV  A,@@R0      ; GET DIGIT
 ANL  A,#$0F     ; KILL DEC  PT
 ORL  A,#$30     ; MAKE IT ASCII
 CALL OUTD       ; SEND  IT
COUNDG
 DEC  R1         ; DONE 4 YET?
 MOV  A,R1       ; TEST R1
 JNZ  SKIPT      ; NO, DO MORE
 MOV  A,#$20     ; SEND SPACE
 CALL OUTD
 MOV  A,#$4C     ; SEND L
 CALL OUTD
 MOV  A,#$42     ; SEND B
 CALL OUTD
 MOV  A,#$20     ; Send a space.
 RET 
LFCR 
 MOV  A,#$0D     ; SEND (RET)
 CALL OUTD
 MOV  A,#$0A     ; SEND (LF)
 CALL OUTD
 MOV  A,#$0D     ; SEND (RET)	; They want two spaces between each print.
 CALL OUTD
 MOV  A,#$0A     ; SEND (LF)
 CALL OUTD
 RET
 ;*******************************
 ORG $205
OUTD      ; USES R2,R3,A
 ;           DIGIT TO SEND IN A
 CLR  C
 CPL  C
 MOV  R2,#$07
BACK
 JB0  ROTAT
 CPL  C
ROTAT
 RR   A
 DJNZ R2,BACK
 RRC  A
 MOVD P4,A     ; PROG RUNNING
 DIS  TCNTI    ; STOP TIMER IRQ
 ANL  P1,#$7F   ; P17 OFF
 CALL DELAY  ; OFF DELAY TIME
 NOP
 NOP
 MOV  R3,#$08
RIGHT
 RRC  A
 JC   P17HI
 ANL  P1,#$7F    ; P17 OFF
 JMP  NOTHI
P17HI
 ORL  P1,#$80    ; P17 ON
 NOP
 NOP
NOTHI
 CALL DELAY     ; ON DELAY TIME
 DJNZ R3,OUTD1
 JMP  OUTD2
OUTD1
 JMP  RIGHT
OUTD2
 ORL  P1,#$80    ; P17 ON
 CALL DELAY
 CALL DELAY      ; STOP BIT?
                 ;  EN   TCNTI
 RET
DELAY            ; DELAY ROUTINE
 MOV  R2,#$5C    ; DELAY AMOUNT
DEL
 DJNZ R2,DEL     ; LOOP 5C TIMES
 RET
 ;*******************************
SUBTR          ; R0,A,ANSW IN A
 ;               R0-A
 ;               ACTS LIKE SUBC INSTR
 CPL  A        ; ONES COMPLMNT
 ADDC A,R0     ; ADD
 CPL  A
 RET
 ;*******************************
DECBIN        ;  R0,R1,R3,R6,R7,A
 ;               CONVERTS 5 DIGIT
 ;               DECIMAL AT DISPLY
 ;               TO 2 BYTE BINARY
 ;               NUMBER AT BIN
 ;              (UNSIGNED)
 MOVD P4,A
 MOV  R0,#DISPLY  ; ADDR BCD
 MOV  R3,#$5     ; LEN BCD
 MOV  R1,#BIN   ; BIN ADDR
 MOV  A,#0 
 MOV  @@R1,A     ; BIN=00
 INC  R1
 MOV  @@R1,A     ; BIN+1=00
HELP
 ;**ASL BIN******
 CLR  C
 MOV  R1,#BIN
 MOV  A,@@R1     ; GET BIN
 RLC  A         ; *2
 MOV  @@R1,A
 MOV  R6,A      ; SAVE BIN
 ;**ASL BIN+1****
 MOV  R1,#BIN+1
 MOV  A,@@R1
 RLC  A         ; BIN+1=(BIN+1)*2
 MOV  @@R1,A
 MOV  R7,A      ; SAVE BIN+1
 ;**ASL BIN******
 CLR  C
 MOV  R1,#BIN
 MOV  A,@@R1     ; GET BIN
 RLC  A         ; *4
 MOV  @@R1,A
 ;**ASL BIN+1****
 MOV  R1,#BIN+1
 MOV  A,@@R1
 RLC  A         ; BIN+1=(BIN+1)*4
 MOV  @@R1,A
 ;**ASL BIN******
 CLR  C
 MOV  R1,#BIN
 MOV  A,@@R1     ; GET BIN
 RLC  A         ; *8
 MOV  @@R1,A
 ;**ASL BIN+1****
 MOV  R1,#BIN+1
 MOV  A,@@R1
 RLC  A         ; BIN+1=(BIN+1)*8
 MOV  @@R1,A
 ;***************
 MOVD P4,A      ; PROG RUNNING
 CLR  C         ; BINARY *10 HERE
 MOV  R1,#BIN
 MOV  A,@@R1     ; GET BIN
 ADDC A,R6      ; BIN*8 +BIN*2
 MOV  @@R1,A     ; SAVE BIN*10
 MOV  R6,A      ; SAVE BIN*10
 MOV  R1,#BIN+1
 MOV  A,@@R1     ; GET BIN+1
 ADDC A,R7      ; BIN+1*2+BIN+1*8
 MOV  @@R1,A     ; SAVE (BIN+1)*10
 MOV  R7,A      ; SAVE (BIN+1)*10
 ;***************
 CLR  C         ; BIN=BIN+DIG
 MOV  A,@@R0     ; GET FIRST DIGIT
 ANL  A,#$0F    ; Kill any decimal points.
 ADDC A,R6      ; BIN+DIGIT
 MOV  R1,#BIN
 MOV  @@R1,A     ; SAVE BIN
 JNC  NOCARY    ; CARRY SET?
 MOV  R1,#BIN+1
 MOV  A,@@R1     ; GET BIN+1
 INC  A         ; BIN+1=(BIN+1)+1
 MOV  @@R1,A
 ;***************
NOCARY
 INC  R0        ; NEXT DIGIT
 DEC  R3
 MOV  A,R3      ; SET ZERO FLAG
 XRL  A,#$0
 JZ  RETRN
 JMP HELP       ; THIS TO JUMP TO
RETRN           ; ANOTHER PAGE
 CLR  C
 RET
 ;*******************************
BINDEC      ;R0,R1,R3,R4,R7,A
;	     Call with source address in R0.
 ;           CONVERTS 2 BYTE
 ;           BINARY AT @@R0
 ;           TO 5 DIGIT NUMBER     ****Warning: Bindec is destructive*****
 ;           AT DISPLY             ****It will destroy whatever is at*****
 ;           (UNSIGNED)		   ****the address @@R0!!!!!!!!!!!!!!!*****
 MOVD P4,A
 MOV  A,R0
 MOV  R4,A	  ; Save source address.
 MOV  R1,#DISPLY  ; ADDR BCD
 MOV  R3,#$5      ; LEN BCD
 MOV  A,#$0       ; ZERO BCD DATA
CLEER
 MOV  @@R1,A
 INC  R1          ; NEXT ADDRESS
 DJNZ R3,CLEER    ; DONE FIVE YET?
 MOV  R0,#DISPLY+4
 ;***************
CNVERT
 MOV  R1,#MOD10
 MOV  A,#$0
 MOV  @@R1,A      ; MOD10=0
 INC  R1
 MOV  @@R1,A      ; MOD10+1=0
 ;***************
 MOV  R3,#$10
 CLR  C
DVLOOP
 MOV  A,R4
 MOV  R1,A	; Get source address.
; MOV  R1,#BIN  ; SHIFT CARRY TO
 CALL ROL       ; DIV BIT 0 =QUOT
 INC  R1        ; SHIFT DIV ALSO
 CALL ROL       ; BIN+1
 MOV  R1,#MOD10
 CALL ROL
 INC  R1
 CALL ROL       ; MOD10+1
 MOVD P4,A      ; PROG RUNNING
 ;            A,R7=DVDEND=DIVIS
 CLR  C
 DEC  R1        ; MOD10
 MOV  A,@@R1
 CPL  A         ; SUBC A,#0A
 ADDC A,#$0A
 CPL  A
 MOV  R7,A      ; SAVE LO BYTE
 INC  R1        ; MOD10+1
 MOV  A,@@R1
 CPL  A         ; SUBTRACT CARRY
 ADDC A,#0      ; SUBC A,#0
 CPL  A         ; DIVDEN<DIVIS?
 JC   DECCNT    ; YES ,BRANCH
 MOV  @@R1,A     ; A TO MOD10+1
 DEC  R1        ; MOD10
 MOV  A,R7
 MOV  @@R1,A     ; R7 TO MOD10
 ;            NEXT BIT OF QUOT=1
 ;            DIVDEN=DIDEN-DIVIS
DECCNT
 CPL  C
 DJNZ R3,DVLOOP
 MOV  A,R4
 MOV  R1,A
; MOV  R1,#BIN  ; SHIFT IN LAST
 CALL ROL       ; LAST CARRY FOR
 INC  R1        ; QUOTIENT
 CALL ROL
CONCH
 MOV  R1,#MOD10
 MOV  A,@@R1
 MOV  @@R0,A     ; SAVE DIGIT
 DEC  R0        ; POINT TO NEXT
 MOV  A,R4
 MOV  R1,A
; MOV  R1,#BIN
 MOV  A,@@R1
 INC  R1
 ORL  A,@@R1     ; BIN=0?
 JNZ  CNVERT    ; NO DO MORE
 RET
 ;*****ROL @@R1*******************
ROL             ; USES A,R1
 MOV  A,@@R1
 RLC  A
 MOV  @@R1,A
 RET
 ;*******************************
;
;The 4 X 3 matrix for the keyboard is stored here.
;
 ORG $300
TABLE
 DB $01, $02, $03
 DB $04, $05, $06
 DB $07, $08, $09
 DB $0A, $00, $0B
ENDTAB
;
 ;*******************************
BINSUB  ; USES R0,R1,A,F0
 ; ON  ENTRY R1=SUBTRAHEND
 ;           SUBTRACTS BINARY
 ;           BIN=BIN-(@@R1)
 MOVD P4,A
 JF0  BINADD ; -A-B=-(A+B)
 CLR  C
 MOV  R0,#BIN
 MOV  A,@@R0    ; A=BIN
 CPL  A
 ADDC A,@@R1    ; A=A-ZERO
 CPL  A
 MOV  @@R0,A    ; BIN=A
 INC  R0       ; R0=BIN+1
 INC  R1       ; R1=ZERO+1
 MOV  A,@@R0    ; A=BIN+1
 CPL  A
 ADDC A,@@R1    ; A=A-ZERO+1
 CPL  A
 MOV  @@R0,A    ; BIN+1=A
 CLR  F0
 MOV  R1,#BIN+1
 MOV  A,@@R1
 JC   SKIPME
 JMP  CNVRT1
SKIPME
 ;*****CONVERT MINUS TO PLUS*****
BINSB1    ; FIX MINUS VALUE?
 CPL  F0       ; BIN=0-BIN
 MOV  A,#0     ; F0=1 IF MINUS
 CLR  C
 MOV  R1,#BIN
 CPL  A
 ADDC A,@@R1
 CPL  A
 MOV  @@R1,A
 MOV  A,#0
 MOV  R1,#BIN+1
 CPL  A
 ADDC A,@@R1
 CPL  A
 MOV  @@R1,A
CNVRT1
 RET
 ;*******************************
 ;*****BINARY ADDITION***********
 ;*******************************
BINADD  ; USES R0,R1,A,F0
 ; ON  ENTRY R1=ADDER
 ;           ADDS BINARY
 ;           BIN=BIN+(@@R1)
 CLR  C
 MOV  R0,#BIN
 MOV  A,@@R0    ; A=BIN
 ADDC A,@@R1    ; A=A-@@R1
 MOV  @@R0,A    ; BIN=A
 INC  R0       ; R0=BIN+1
 INC  R1       ; R1=R1+1
 MOV  A,@@R0    ; A=BIN+1
 ADDC A,@@R1    ; A=A-@@R1+1
 MOV  @@R0,A    ; BIN+1=A
 RET
 ;*******************************
BINDIV  ;    R0,R1,R3,R7,A
 ;           BIN=BIN/DIV
 MOVD P4,A
 MOV  R1,#BIN+3
 MOV  R3,#$02    ; # OF LOC'S
 MOV  A,#0     	 ; ZERO LOCATIONS
CLEAR
 MOV  @@R1,A
 DEC  R1       	 ; NEXT ADDRESS
 DJNZ R3,CLEAR 	 ; DONE 3 YET?
 MOV  R3,#$10    ; LOOP 16 BITS
 CLR  C        	 ; THIS NO NEED
DIVLP
 MOV  R1,#BIN	 ; SHIFT CARRY TO
 CALL ROL    	 ; DIV BIT 0 =QUOT
 INC  R1       	 ; SHIFT DIV ALSO
 CALL ROL    	 ; BIN+1
 INC  R1
 CALL ROL        ; BIN+2
 INC  R1
 CALL ROL        ; BIN+3
 MOVD P4,A       ; PROG RUNNING
 CLR  C 
 DEC  R1         ; BIN+2
 MOV  A,@@R1
 CPL  A
 ADDC A,#DIVIDE     ; SUBC A,DIV
 CPL  A
 MOV  R7,A      ; SAVE LO BYTE
 INC  R1        ; BIN+3
 MOV  A,@@R1     ; GET BIN+3
 CPL  A         ; SUBTRACT CARRY
 ADDC A,#0      ; SUBC A,DIV+1  (HI BYTE OF DIVIDE IS ZERO)
 CPL  A         ; DIVDEN<DIVIS?
 JNC  CONTY     ; YES ,BRANCH
 JMP  DCCNT     ; YES ,BRANCH
CONTY           ;
 MOV  @@R1,A     ; A TO BIN+3
 DEC  R1        ; MOD10
 MOV  A,R7
 MOV  @@R1,A     ; R7 TO BIN+2
 ;                NEXT BIT OF QUOT=1
 ;                DIVDEN=DIDEN-DIVIS
DCCNT
 CPL  C
 DEC  R3
 MOV  A,R3
 ANL  A,#$FF
 JZ   SKIPP
 JMP  DIVLP
SKIPP
 MOV  R1,#BIN    ; SHIFT IN LAST
 CALL ROL        ; LAST CARRY FOR
 INC  R1         ; QUOTIENT
 CALL ROL
 CLR  C
 RET
 ;*******************************
REZERO ; SAVE ZERO VALUE
 ;          USES R0,R1,A
 MOVD P4,A
 MOV  R1,#ZERO
 MOV  R0,#BIN
 MOV  A,@@R0   ; GET LO BYTE
 MOV  @@R1,A   ; SAVE AT ZERO
 INC  R1      ; ZERO+1
 INC  R0      ; BIN+1
 MOV  A,@@R0   ; GET HI BYTE
 MOV  @@R1,A   ; SAVE AT ZERO+1
 RET
 ;*******************************
SWZERO ; 
 ;          IF CALLED THIS ZEROES
 ;          THE SCALE.
 MOVD P4,A
 CALL READ    ; READ A TO D
 CALL TRANS   ; GET ZERO VALUE
 CALL DECBIN  ; CHANGE TO BIN
 CALL REZERO  ; SAVE ZERO VALUE
 RET
 ;*******************************
MUL16    ; MULTIPLY TWO
 ;          16 BIT NUMBERS.
 ;    BIN := BIN * 2
 ;    USES R0,R1,R2,R3,R4,R5,R6,A
 MOV  R0,#BIN ; GET ADDRESS
 MOV  A,@@R0     ; PUT MULTIPLICND
 MOV  R3,A      ; IN R2,R3
 INC  R0
 MOV  A,@@R0
 MOV  R2,A
 MOV  A,#MULPLY ; GET MULTIPLI CONSTANT
 MOV  R5,A
 MOV  A,#0      ; HI BYTE OF MULPLY IS ZERO!!!!
 MOV  R4,A
 MOV  A,#0      ; FIRST 16 BITS
 MOV  R0,A      ; RESULT := 0
 MOV  R1,A
 MOV  R6,#$11  ; : # BITS IN MUL+1
 CLR  C
MUL01    ; MUL   LOOP STARTS
 MOV  A,R0    ; SHFT RESULT RIGHT
 RRC  A       ; THROUGH CARRY
 MOV  R0,A
 MOV  A,R1
 RRC  A
 MOV  R1,A
 MOV  A,R2    ; SHIFT MULTIPLIER
 RRC  A       ; RIGHT THROUGH
 MOV  R2,A    ; CARRY
 MOV  A,R3
 RRC  A
 MOV  R3,A
 JC   MUL02 ; JUMP ON CARRY SET
 JMP  MUL03 ; ELSE CHECK FR END
MUL02 ; ADD MULTIPLICAND TO
 CLR  C    ; RESULT
 MOV  A,R1
 ADDC A,R5
 MOV  R1,A
 MOV  A,R0
 ADDC A,R4
 MOV  R0,A
MUL03
 DJNZ R6,MUL01
 MOV  R0,#BIN ; PUT RESULT BACK
 MOV  A,R3      ; INTO BIN
 MOV  @@R0,A
 INC  R0
 MOV  A,R2
 MOV  @@R0,A
 RET            ; MUL16 ENDS
 ;*******************************
ZTOSP ; ZERO TO SPACE
 ;  SUPPRESS LEADING ZEROES
 ;  USES A,R0,R1
 MOV  R1,#$04   ; # OF LED DSPLAYS
 MOV  R0,#DISPLY ; DISPLAY BUFF
ZTOSP1
 MOV  A,@@R0
 JNZ  ZTOSP2
 MOV  A,#$0F
 MOV  @@R0,A
 INC  R0
 DJNZ R1,ZTOSP1
ZTOSP2
 RET
 ;*******************************
DECMAL ; PUT # OF DEC PLACES
 MOV  A,#DECPLC
 CPL  A
 ADD  A,#$05
 ADD  A,#DISPLY ; GET DEC LOC
 MOV  R0,A
 MOV  A,@@R0 ; GET THE BYTE
 ORL  A,#$10 ; PUT POINT
 MOV  @@R0,A
 RET
 ;*******************************

 ;*******************************
SWPRIN         ; READ PRINT SWTCH
 ;               IF PUSHED IT PRINTS
 ANL  P1,#$F0  ; CLEAR LO NIBBLE
 ORL  P1,#$0E  ; READ PRNT SWITCH
 JT0  PRON     ; SWITCH OFF
 RET
PRON           ; SWITCH IS ON
 CALL SEND     ; PRINT WIEGHT
PROFF
 MOVD P4,A
 ANL  P1,#$F0  ; CLEAR LO NIBBLE
 ORL  P1,#$0E  ; READ PRNT SWITCH
 MOV  R3,#00   ; FLAG=0 NO PRNT
 JT0  PROFF    ; WAIT SWITCH OFF
 RET
 ;************************************
DELY               ;USES R0 TO TELL HOW LONG TO DELAY
 MOV  A,#DYAMT     ; USES R0,A   ---GENERAL DELAY ROUTINE
DAIRY
 MOVD P4,A
 DEC  A 
 JNZ  DAIRY
 DJNZ  R0,DAIRY
 RET   
 ;*************************************
;
; Routine to read 12 key keypad on 74150.
; The pad is a 2 of 7 type pad, with the following codes:
;
;                3250            3250     
;  key	code 1	 MOLEX  code 2   MOLEX    
;   1	  B       7       D        5  
;   2	  A       8       D        5
;   3	  9       9       D        5
;   4 	  B	  7       E        3
;   5 	  A	  8       E        3
;   6	  9  	  9       E        3
;   7	  B 	  7       6        4
;   8     A	  8       6        4
;   9     9	  9       6        4
;   *     B	  7       C        6
;   0     A       8       C        6
;   # 	  9	  9       C        6
;
; The following is the wiring diagram to use:
;
;  3250     GRAYHILL   GRAYHILL    3250
;  MOLEX    PIN #      LETTER	   DESIGNATION 
;   10       8           D          GROUND
;   9        7           E          E9
;   8        6           F          E10
;   7        5           G          E11
;   6        4           H          E12
;   5        3           J          E13
;   4        2           K          E6
;   3        1           L          E14
;
;Note: something about the following code does not agree with all
;      of the written documentation, but I just modified the code
;      until it started working.
;                USES: A,R0,R1,R2
;
; ORG $500	;Start keypad at $500 to avoid of page jumps.
KEYPAD
 MOV  R1,#$00   ;Row 0 in memory matrix.
 MOV  R0,#$0E	
 CALL SETADR    ;Check on address 14.
 JT0  FNDROW  
 MOV  R1,#$03   ;Row 1 in memory matrix.   	
 MOV  R0,#$06	
 CALL SETADR    ;Check on address 6.
 JT0  FNDROW  
 MOV  R1,#$06   ;Row 2 in memory matrix.
 MOV  R0,#$0D	
 CALL SETADR    ;Check on address 13.
 JT0  FNDROW 
 MOV  R1,#$09   ;Row 3 in memory matrix.       
 MOV  R0,#$0C	
 CALL SETADR    ;Check on address 12.
 JT0  FNDROW 
 MOV  A,#$00    ;Set zero flag if no active rows.
 RET            
SETADR		;Set address in a onto 74150 address lines.
 IN   A,P1      ;Get current data on port 1.
 ANL  A,#$F0    ;Force low nibble to 0.
 ORL  A,R0      ;Set up low nibble as address.
 OUTL P1,A      ;Write old high nibble + new lo nibble to port 1.
 RET
FNDROW 
 MOV  R2,#$00    ;Column 0.    
 MOV  R0,#$0B    ;Is E11 active?
 CALL SETADR
 JT0  FNDCOL
 MOV  R2,#$01    ;Column 1. 
 MOV  R0,#$0A    ;Is E10 active?
 CALL SETADR
 JT0  FNDCOL   
 MOV  R2,#$02    ;Column 2.
 MOV  R0,#$09    ;Is E9 active?
 CALL SETADR
 JT0  FNDCOL    
 MOV  A,#$00     ;No active columns.
 RET
FNDCOL              
 MOV   A,R1       ;Start with the row number.
 ADD   A,R2       ;Add the column number.
 MOVP3 A,@@A       ;Get the keyboard data.
 MOV   R0,A       
 MOV   A,#$FF     ;Show that we do have a key.
 RET
;*****************************************
;
; Routine to read keyboard and debounce it.
;                USES: A,R0,R1,R2,R3
GETKEY
 CALL KEYPAD	 ;Read keypad.
 JNZ  CONPAD     ;We have a key.
 MOV  A,#$00
 RET
CONPAD 
 MOV  A,R0       ;Save keypad value.
 MOV  R3,A
KEYOFF
 MOVD P4,A
 MOV  R0,#KYDBNC ;Delay for keyboard debounce.
 CALL DELY
 CALL KEYPAD     ;Read Keypad and wait until no keys are pressed.
 JNZ  KEYOFF
 MOV  R0,#KYDBNC ;Delay for keyboard debounce.
 CALL DELY
 CALL KEYPAD     ;Check one more time.
 JNZ  KEYOFF
 MOV  A,R3
 MOV  R0,A       ;Key is returned in R0.
 MOV  A,#$FF	 ;Signal that a key was pressed.
 RET
;************************************************
;
; Routine to get a numeric entry for tare and setpoints.
;            USES: A,R0,R1,R2,R3,R4
GETNUM
; MOV  A,#$00	;Fill display with zeroes.
; CALL CLRDSP	;Clear the display
SFTNUM 
 MOVD P4,A
 CALL GETKEY	;Wait for a keypress. (key is in r0).
 JZ   SFTNUM
 MOV  A,#$0B    ;Was it the # key?
 CALL CMP
 JF1  EVALEX    ;Evaluate expression.
 MOV  A,#$0A    ;Was it the * button?
 CALL CMP	;Ignore it if it was.
 JF1  SFTNUM    
 CALL PUTDSP    ;Put number to display.
 JMP  SFTNUM
EVALEX
 RET
;*******************************
;
;Put an entry to the display, and maintain decimal point.
;    Also this keeps a copy of what is in the display at disply.
;             Number to enter is in R0.
;             USES: A,R0,R1
PUTDSP
 MOV  A,R0	;Save Key value.
 MOV  R3,A
 MOV  R0,#DISPLY+1	;Left hand side of display here.
 MOV  R1,#DISPLY	;Move everything left one digit.
 MOV  R2,#$04		;Move only four digits (end will drop off).
SFTLFT
 MOV  A,@@R0	;Get digit.
 ANL  A,#$0F    ;Kill decimal point so it will not shift left.
 MOV  @@R1,A	;Shift it left.
 INC  R1
 INC  R0        ;Point to next digit.
 DJNZ R2,SFTLFT
;                        Store key code into right side of display.
 MOV  R1,#DISPLY+4	;Right side of display here.
 MOV  A,R3	        ;Recover key value.
 MOV  @@R1,A
 CLR  F0 	;F0=0 for positive number.
 CALL DECMAL	;Put a decimal point in it.
 CALL DISP
 RET
;*******************************
;
; CLEAR THE DISPLAY
;           Call with the code to blank with in A.
;           USES: R0,R1,A
CLRDSP
 MOV  R1,#$05
 MOV  R0,#DISPLY	
CLOOP 
 MOV  @@R0,A	;Move the code out to the display.
 INC  R0
 DJNZ R1,CLOOP	;Done 5 digits yet?
 CALL DECMAL	;Put decimal point.
 CLR  F0	;No minus sign.
 CALL DISP 	;Display all blanks.
 RET
;*******************************
;COMPARE SUBROUTINE
; NONDESTRUCTIVE COMPARE A-R0 (Saves a)
; USES A,R0,R3,R4,F1
CMP
 CLR   F1       ; INIT FLAG
 MOV   R3,A     ; SAVE A
 MOV   A,R0     ; Save R0.
 MOV   R4,A
 MOV   A,R3     ; Get a back.
 XRL   A,R0     ; A=R0?
 JZ    EQUAL
 MOV   A,R4
 MOV   R0,A     ; Get R0 back.
 MOV   A,R3     ; GET A BACK
 RET            ; F1=0 A<>R0
EQUAL
 MOV   A,R4
 MOV   R0,A     ; Get R0 back.
 MOV   A,R3     ; GET A
 CPL   F1       ; F1=1 for  A=R0
 RET
;****************
;
; Any keys pressed?
;		USES: A,R0,R1
CHKEY
 CALL GETKEY	;Read keyboard.
 JZ   BLOWOF	;None pressed.
 MOV  A,#TAREBT
 CALL CMP	;Tare button pressed? (# key)
 JF1  TARIT    
 MOV  A,#PRNTBT
 CALL CMP	;Print key pressed? (1 key)
 JF1  DOPRT    
 MOV  A,#ZEROBT
 CALL CMP	;Zero button pressed? (0 key)
 JF1  DOZERO 
BLOWOF 
 MOV  A,#$00    ;No keys are pressed.
 RET
;*****************
DOZERO
 CALL SWZERO	;Zero the scale.
 MOV  A,#$FF
 RET
;*****************
TARIT
 MOV  R0,#TARE	;Get tare.
 MOV  A,#$FF
 JMP  PUTNUM
;*****************
DOPRT
 CALL SEND      ; Send data to printer.
 RET
;*****************
PUTNUM
;		 USES A,R1,R2,R3,R4,R5,R6,R7
;		 Call with number to fill in R0.
 CLR  F0	;Make sure that we display a positive tare weight.
 MOV  A,R0
 MOV  R5,A	;Save target for later.
 CALL BINDEC	;Convert current tare at TARE to BCD at DISPLY.
 CALL DECMAL    ;Insert decimal point.
 CALL DISP	;Display it.
 CALL GETNUM
 CALL DECBIN	;Convert BCD number to binary at bin.
 MOV  R0,#BIN	
 MOV  A,R5	;Retrieve target.
 MOV  R1,A
 MOV  A,@@R0	;Move tare weight at bin to tare.
 MOV  @@R1,A
 INC  R0
 INC  R1
 MOV  A,@@R0
 MOV  @@R1,A
 RET
;****************
LOCZER
;		 USES: A,R0
;		;Zero out a binary lo byte- hi byte location.
 MOV  A,#$00	  
 MOV  @@R0,A	;Zero first location.
 INC  R0
 MOV  @@R0,A	;Zero 2nd location.
 RET
;***************
MOVE2
;	Routine to move 2 bytes from @@R1 to @@R0.
 MOV  A,@@R1	 
 MOV  @@R0,A     ;Byte 1.
 INC  R0
 INC  R1
 MOV  A,@@R1     ;Byte 2.
 MOV  @@R0,A
 RET
;***************
MOVE3
;	Routine to move 3 bytes from @@R1 to @@R0.
 MOV  A,@@R1	  
 MOV  @@R0,A     ;Byte 1.
 INC  R0
 INC  R1
 MOV  A,@@R1
 MOV  @@R0,A     ;Byte 2.
 INC  R0
 INC  R1
 MOV  A,@@R1
 MOV  @@R0,A     ;Byte 3.
 RET
;**************
; Automatic zero tracking:
;
;	   Here we check to see if we are on zero, or one displayed 
;	        division off zero. If one off, rezero the scale and
;	        turn the AZT light on. If on zero, turn AZT light on.
;	        If off zero, turn AZT light off.
;
; USES A,R0,R1
; COMPARES  BIN TO +-1
; IF BIN=1 THEN REZERO SCALE
;
AZTRK
 MOV  R0,#BIN+1
 MOV  A,@@R0   	 ; GET BINHI
 XRL  A,#0     	 ; BINHI=0?
 JNZ  OFZERO 	 ; If hi byte of bin is nonzero, then we are off zero.
 MOV  R0,#BIN
 MOV  A,@@R0    	 ; GET BINLO
 XRL  A,#1     	 ; IS IT 1?
 JNZ  NOTRK  	 ; No,it is not a 1, so it must be zero or more than one.
; CALL SWZERO 	 ; We can only be here if scale needs to AZT.
; MOV  A,#0
; MOV  @@R0,A    	 ; BINLO=0
; INC  R0
; MOV  @@R0,A    	 ; BINHI=0
 ;*****AZT LIGH ON**************
 MOV A,#$1     	 ; AZT ON NOW
LGHTON
 CLR  F0         ; IF WE ARE TRACKING, TURN MINUS SIGN OFF (FOR 3250 PY)
 ORL  P2,#ZON	 ; ZERO LIGHT ON
 RET
 ;*****HERE IF NOT TRACKING*****
NOTRK
 MOV  A,@@R0    	 ; GET BINLO
 XRL  A,#0     	 ; IS IT 0?
 JZ   LGHTON 	 ; AZT LIGHT ON
OFZERO 		 ; SCALE OFF ZERO
 ANL  P2,#ZOFF	 ; ZERO LGHT OFF
 MOV  A,#0    	 ; NO AZT NOW
 RET
;****************
RDZERO ; READ ZERO SWITCH
 ;          IF PUSHED IT ZEROES
 ;          THE SCALE
 MOVD P4,A
 ANL  P1,#$F0  ; CLEAR LO NIBBLE
 ORL  P1,#$08  ; READ ZERO SWITCH
 MOV  R3,#00   ; FLAG=0 NO ZERO
 JT0  SWON     ; SWITCH OFF
 MOV  A,#$FF
 RET
SWON          ; SWITCH IS ON
 CALL READ    ; READ A TO D
 CALL TRANS   ; GET ZERO VALUE
 CALL DECBIN  ; CHANGE TO BIN
 CALL REZERO  ; SAVE ZERO VALUE
 MOV  A,#$00
 RET

;********************************
; 
;Floating point routines follow.
;Written by: Adrian Griffis
;
;********************************


;Subtraction macro.

SUBC	 MACRO p0
         CPL   A
         ADDC  A,p0
         CPL   A
         ENDM
;
;         ORG   $500
;***************************************
;*****  Clear Floating Point Register 0.
;*****     Uses: R0, R1
;
FP0CLR   MOV   R0,#FPR0    ; Point R0 to FPR 0.
         MOV   R1,#4       ; Set byte count to 4.
FP0CLL   MOV   @@R0,#0      ; Zero a byte.
         INC   R0          ; Increment pointer.
         DJNZ  R1,FP0CLL   ; IF not done THEN loop back.
         RET
;
;****************************************
;*****  Clear Floating Point Register 1.
;*****     Uses: R0, R1
;
FP1CLR   MOV   R0,#FPR1    ; Point R0 to FPR 1.
         MOV   R1,#8       ; Set byte count to 8.
FP1CLL   MOV   @@R0,#0      ; Zero a byte.
         INC   R0          ; Increment pointer.
         DJNZ  R1,FP1CLL   ; IF not done THEN loop back.
         RET
;
;****************************************
;*****  Clear Floating Point Register 2.
;*****     Uses: R0, R1
;
FP2CLR   MOV   R0,#FPR2    ; Point R0 to FPR 2.
         MOV   R1,#4       ; Set byte count to 4.
FP2CLL   MOV   @@R0,#0      ; Zero a byte.
         INC   R0          ; Increment pointer.
         DJNZ  R1,FP2CLL   ; IF not done THEN loop back.
         RET
;
;******************************************
;*****  Normalize Floating Point Register 1.
;*****     Uses: R0, R1, R2, A
;
;-------- See if it's already normalized.
FP1NRM   MOV   R0,#FPR1+1  ; Load address of high order byte of mantissa.
         MOV   A,@@R0       ; Load high order byte of mantissa.
         ANL   A,#$F0      ; Mask off low order nibble.
         JZ    $+3         ; If not zero THEN skip over RETURN.
         RET               ; ELSE return.
;-------- See if exponent can be reduced.
         DEC   R0          ; Point R0 to exponent.
         MOV   A,@@R0       ; Load sign/exponent byte.
         ANL   A,#$7F      ; Mask off sign bit.
         JZ    FP1CLR      ; IF exponent zero THEN clear FPR1.
;-------- IF so THEN adjust exponent and shift mantissa left.
         MOV   A,@@R0       ; Load exponent.
         DEC   A           ; Decrement exponent.
         MOV   @@R0,A       ; Store back into memory.
         MOV   R2,#4       ; Load shift count.
FP1NL0   MOV   R1,#7       ; Load bytecount.
         CLR   C           ; Clear Carry.
         MOV   R0,#FPR1+7  ; Point to low order mantissa byte.
FP1NL1   MOV   A,@@R0       ; Load a mantissa byte.
         RLC   A           ; Shift left a bit.
         MOV   @@R0,A       ; Store back into memory.
         DEC   R0          ; Decrement pointer.
         DJNZ  R1,FP1NL1   ; IF more bytes THEN loop back.
         DJNZ  R2,FP1NL0   ; IF more shifts THEN loop back.
         JMP   FP1NRM      ; See if another shift is needed.
;
;***********************************
;*****  Clear low order 4 bytes of
;*****     extended FPR1 mantissa.
;*****     Uses: R0, R1
FP1EC    MOV   R0,#FPR1+4  ; Point R0 to mantissa extention.
         MOV   R1,#4       ; Load byte count.
         MOV   @@R0,#0      ; Zero a byte.
         INC   R0          ; Increment pointer.
         DJNZ  R1,$-3      ; IF not done THEN loop back.
         RET               ; ELSE return.
;
;***********************************
;*****  Convert from (low/high) binary
;*****     in BIN to float in FPR1.
;
BIN2FP   CALL  FP1CLR      ; Clear FPR1.
         MOV   R0,#FPR1+2  ; Point to byte 2 of FPR1 mantissa.
         MOV   R1,#BIN     ; Point to low byte of BIN.
         MOV   A,@@R1       ; Load low byte of BIN.
         MOV   @@R0,A       ; Store into FPR1.
         DEC   R0          ; Decrement FPR1 pointer.
         INC   R1          ; Increment BIN pointer.
         MOV   A,@@R1       ; Load hi BIN byte.
         MOV   @@R0,A       ; Store into FPR1.
         DEC   R0          ; Point to FPR1 sign/exponent.
         MOV   A,#$C4      ; Load conversion exponent (assume neg).
         JF0   $+4         ; IF negative THEN skip next instruction.
         ANL   A,#$7F      ; ELSE clear sign flag.
         MOV   @@R0,A       ; Store sign/exponent into FPR1.
         CALL  FP1NRM      ; Normallize it.
         RET               ; And return.
;
;***********************************
;*****  Convert from float to BIN.
;*****     Uses: R0, R1, R2, A.
;
;-------- Check for overflow.
FP2BIN   MOV   R0,#FPR1    ; Point to FPR1 exponent.
         MOV   A,@@R0       ; Load FPR1 exponent.
         CLR   C           ; Clear carry.
         ANL   A,#$7F      ; Mask off sign.
         SUBC  #$45        ; Make sure exponent is not too big.
         JC    FP2BL0      ; IF not THEN continue.
         CPL   C           ; ELSE set carry
         RET               ;   and return.
;-------- See if unnormalization is necessary.
FP2BL0   MOV   R0,#FPR1    ; Point to FPR1 exponent.
         MOV   A,@@R0       ; Load FPR1 exponent.
         CLR   C           ; Clear carry.
         ANL   A,#$7F      ; Mask off sign.
         SUBC  #$44        ; Is exponent too small?
         JC    FP2BS0      ; IF so THEN prepare for next loop.
;-------- IF not THEN prepare answer.
         MOV   R0,#FPR1+3  ; Point to first fraction byte.
         MOV   A,@@R0       ; Pick up fraction byte.
         ADD   A,#$80      ; Make carry indication rounding direction.
         DEC   R0          ; Point to low order integer byte.
         MOV   R1,#BIN     ; Point to low BIN byte.
         MOV   A,@@R0       ; Load low result.
         ADDC  A,#0        ; Round low byte.
         MOV   @@R1,A       ; Store into BIN low.
         DEC   R0          ; Point to high result.
         INC   R1          ; Point to BIN high.
         MOV   A,@@R0       ; Load high result.
         ADDC  A,#0        ; Round high byte.
         MOV   @@R1,A       ; Store into BIN high.
         DEC   R0          ; Point to sign/exponent.
         MOV   A,@@R0       ; Load sign/exponent.
         ANL   A,#$80      ; Mask off exponent.
         CLR   F0          ; Assume positive.
         JZ    $+3         ; IF not neg THEN skip next instruction.
         CPL   F0          ; ELSE indicate negative.
         CLR   C           ; Indicate successfull conversion,
         RET               ;   and return.
;-------- OTHERWISE unnormallize and check again.
FP2BS0   CALL  FP1UN1      ; Unnormallize by one.
         JMP   FP2BL0      ; Loop back for another check.
;
;***********************************
;*****  Unnormalize FPR1 by one shift
;*****     to the right.
;*****     Uses: R0, R1, R2, A
;
FP1UN1   MOV   R2,#4        ; Load shift count.
FP1UL0   MOV   R1,#7        ; Load byte count.
         MOV   R0,#FPR1+1   ; Point to FPR1 Mantissa.
         CLR   C            ; Clear carry.
FP1UL1   MOV   A,@@R0        ; Load a mantissa byte.
         RRC   A            ; Shift Right.
         MOV   @@R0,A        ; Store back into memory.
         INC   R0           ; Increment pointer.
         DJNZ  R1,FP1UL1    ; IF more bytes THEN loop back.
         DJNZ  R2,FP1UL0    ; ELSE IF more shifts THEN loop back.
         MOV   R0,#FPR1     ; Point to exponent.
         INC   @@R0          ; Increment exponent.
         RET                ; Return.
;
;***********************************
;*****  Transfer FPR1 to FPR0.
;*****     Uses: R0, R1, R2, A.
FP1TO0   MOV   R0,#FPR0     ; Load destination pointer.
         MOV   R1,#FPR1     ; Load source pointer.
         MOV   R2,#4        ; Load byte count.
FP1T0L   MOV   A,@@R1        ; Load source byte.
         MOV   @@R0,A        ; Store into destination.
         INC   R0           ; Increment source pointer.
         INC   R1           ; Increment destination pointer.
         DJNZ  R2,FP1T0L    ; IF more bytes THEN loop back.
         RET                ; Return.
;
;***********************************
;*****  Divide FPR1 by FPR0 (preserving FPR0).
;*****     Uses: R0, R1, R2, R6, A
;
FPDIV    CALL  FP1EC       ; Clear low order part of mantissa.
;-------- Move FPR0 mantissa to scratch area.
         MOV   R0,#FPSCR+1 ; Point to scratch area.
         MOV   R1,#FPR0+1  ; Point to FPR0 mantissa.
         MOV   A,@@R1       ; Load first byte.
         ANL   A,#$F0      ; Test high order nibble.
         JNZ   $+5         ; IF non-zero THEN all is well.
         CLR   C           ; Clear carry
         CPL   C           ;   and then complement to set it.
         RET               ;   and return.
         MOV   R2,#3       ; Load byte count.
FPDL0    MOV   A,@@R1       ; Load a mantissa byte.
         MOV   @@R0,A       ; Store into scratch area.
         INC   R0          ; Increment scratch pointer.
         INC   R1          ; Increment source pointer.
         DJNZ  R2,FPDL0    ; IF more THEN loop back.
         MOV   R2,#4       ; ELSE load byte count for next loop.
         MOV   @@R0,#0      ; Zero a byte.
         INC   R0          ; Increment pointer.
         DJNZ  R2,$-3      ; IF more THEN loop back.
;-------- Subtract and Count Stage.
         CALL  FP2CLR      ; Clear FPR2.
         MOV   R6,#6       ; Load digit count.
FPDL1    CALL  FPDCHK      ; See if a subtract is in order.
         JC    FPSCS0      ; IF not THEN work on next digit.
         CALL  FPDSUB      ; ELSE subtract.
         MOV   R0,#FPR2+3  ; Point to low order byte of FPR2.
         INC   @@R0         ; Increment low order byte of FPR2.
         JMP   FPDL1       ; Loop back.
FPSCS0   DJNZ  R6,$+4      ; IF more digits THEN skip next.
         JMP   FPDTXF      ; ELSE mantissa is ready.
FPDNXD   MOV   R2,#4       ; Load shift count.
FPDNL0   MOV   R1,#3       ; Load FPR2 mantissa byte count.
         MOV   R0,#FPR2+3  ; Point to lower order byte of FPR2 mantissa.
         CLR   C           ; Clear carry before rotates.
FPDNL1   MOV   A,@@R0       ; Load a mantissa byte.
         RLC   A           ; Shift left a bit.
         MOV   @@R0,A       ; Store back into memory.
         DEC   R0          ; Decrement pointer.
         DJNZ  R1,FPDNL1   ; IF more bytes THEN loop back.
         DJNZ  R2,FPDNL0   ; ELSE IF more shifts THEN loop back.
         MOVD  P4,A        ; Reset watchdog timer.
         CALL  FPSSFT      ; Shift for next pass.
         JMP   FPDL1       ; Do next pass.
;-------- Transfer FPR2 mantissa to FPR1.
FPDTXF   MOV   R2,#3       ; Load byte count.
         MOV   R1,#FPR2+1  ; Point to FPR2 mantissa.
         MOV   R0,#FPR1+1  ; Point to FPR1 mantissa.
FPDTL    MOV   A,@@R1       ; Load FPR2 byte.
         MOV   @@R0,A       ; Point to FPR2.
         INC   R0          ; Increment FPR1 pointer.
         INC   R1          ; Increment FPR2 pointer.
         DJNZ  R2,FPDTL    ; IF more THEN loop back.
         CALL  FP1EC       ; Clear low 4 bytes of FPR1 mant.
;-------- Determine the resultant exponent.
         MOV   R0,#FPR0    ; Point to FPR0 sign/exponent.
         MOV   A,@@R0       ; Load it.
         ANL   A,#$7F      ; Mask off sign.
         MOV   R0,#FPR2    ; Point to FPR2 sign/exponent.
         MOV   @@R0,A       ; Store pure exponent.
         MOV   R1,#FPR1    ; Point to FPR1 sign/exponent.
         MOV   A,@@R1       ; Load FPR1 sign/exponent.
         CLR   C           ; Clear carry/borrow.
         SUBC  @@R0         ; Subtract divisor exponent.
         ADD   A,#65       ; Make excess 64.
         MOV   @@R0,A       ; Store into FPR2.
;-------- Determine sign.
         MOV   R0,#FPR0    ; Point to divisor sign/exponent.
         MOV   A,@@R0       ; Load it.
         XRL   A,@@R1       ; X-OR with other sign/exponent.
         ANL   A,#$80      ; Mask off exponent part.
         MOV   R0,#FPR2    ; Point to FPR2 sign/exponent.
         ORL   A,@@R0       ; Combine sign with exponent.
         MOV   @@R1,A       ; Store combination in FPR1.
;
         CALL  FP1NRM      ; Normallize result.
         CLR   C           ; Indicate success.
         RET               ; And return.
;
;*************************************
;*****  Shift Scratch Area Right One Nibble.
;*****     Uses: R0, R1, R2, A
;
FPSSFT   MOV   R2,#4       ; Load shift count.
FPSSL0   MOV   R1,#7       ; Load byte count.
         CLR   C           ; Clear carry.
         MOV   R0,#FPSCR+1 ; Point to FP Scratch low byte.
FPSSL1   MOV   A,@@R0       ; Load a byte.
         RRC   A           ; Shift left a bit.
         MOV   @@R0,A       ; Store back into memory.
         INC   R0          ; Decrement pointer.
         DJNZ  R1,FPSSL1   ; IF more bytes THEN loop back.
         DJNZ  R2,FPSSL0   ; ELSE IF not done THEN loop back.
         RET               ; ELSE return.
;
;***************************************
;*****  Compare Scratch Mantissa to FPR1
;*****     Extended Mantissa.
;*****     Uses: R0, R1, R2, A
;
FPDCHK   MOV   R0,#FPSCR+1 ; Point to scratch mantissa.
         MOV   R1,#FPR1+1  ; Point to FPR1 mantissa.
         MOV   R2,#7       ; Load byte count.
FPDCKL   MOV   A,@@R1       ; Load FPR1 byte.
         SUBC  @@R0         ; Subtract scratch byte.
         JZ    $+3         ; IF zero THEN continue.
         RET               ; ELSE return.
         INC   R0          ; Increment scratch byte.
         INC   R1          ; Increment FPR1 byte.
         DJNZ  R2,FPDCKL   ; IF more bytes THEN loop back.
         RET               ; ELSE return.
;
;****************************************
;*****  Subtract Scratch Mantissa from
;*****     FPR1 Extended Mantissa.
;*****     Uses: R0, R1, R2, A
;
FPDSUB   MOV   R0,#FPSCR+7 ; Point to scratch mantissa.
         MOV   R1,#FPR1+7  ; Point to FPR1 mantissa.
         MOV   R2,#7       ; Load byte count.
         CLR   C           ; Clear carry/borrow.
FPDSL0   MOV   A,@@R1       ; Load FPR1 byte.
         SUBC  @@R0         ; Subtract scratch byte.
         MOV   @@R1,A       ; Store result into FPR1.
         DEC   R0          ; Decrement scratch pointer.
         DEC   R1          ; Decrement FPR1 pointer.
         DJNZ  R2,FPDSL0   ; IF more bytes THEN loop back.
         RET               ; ELSE return.
;
         END
@
