; ******************************************************************************
;									       *
;       PJT2.ASM - PIC#2 (19200 BAUD 8 MHz)				       *
;									       *
;  Monitor serial input on the pin defined by "_RX".  Display frequency and    *
;  channel number, or produce freq counter gate pulse, based on commands       *
;  received from PIC#1.							       *
;									       *
; ******************************************************************************

	LIST            F=INHX8M
	PROCESSOR       16F84
	RADIX           DEC

;
;  __CONFIG bits:
;
; 					B4:   CODE PROTECTION, 1=OFF
; 					B3:   POWER UP, 1=TIMED
; 					B2:   WDOG, 0=off, 1=ON
; 					B1-0: OSC SELECT, 01=XT, 11=RC
        __CONFIG        B'11001' 

	__IDLOCS	H'0002'

; ------------------------------------------------------

	include p16f84.inc
;
;     STATUS bit definitions
;
		#define	_C		STATUS,0
		#define	_Z		STATUS,2
;
;  Other bit definitions
;
MSB		equ	7	; most significant bit
LSB		equ	0	; least significant bit
;
;  Math includes, from MATH16.INC
;
LOOPCOUNT       equ     0x20    ; divide loop counter
TEMPB1          equ     0x21
TEMPB0          equ     0x22
TEMP            equ     0x22    ; temporary storage
;
REMB3           equ     0x1B
REMB2           equ     0x1C
REMB1           equ     0x1D
REMB0           equ     0x1E    ; most significant byte of remainder
;
;       general register variables
;
ACCB5		equ	0x0E
ACCB4		equ	0x0F
ACCB3           equ     0x10
ACCB2           equ     0x11
ACCB1           equ     0x12
ACCB0           equ     0x13
ACC             equ     0x13    ; most significant byte of contiguous 8 byte accumulator
;
SIGN            equ     0x15    ; save location for sign in MSB
;
;
;       binary operation arguments
;
AARGB3          equ     0x10
AARGB2          equ     0x11
AARGB1          equ     0x12
AARGB0          equ     0x13
AARG            equ     0x13    ; most significant byte of argument A
;
BARGB3          equ     0x17
BARGB2          equ     0x18
BARGB1          equ     0x19
BARGB0          equ     0x1A
BARG            equ     0x1A    ; most significant byte of argument B
;
;       Note that AARG and ACC reference the same storage locations
;
;  Data memory for timers
;
TEMP1	EQU	0x23			; timer count 1 us
TEMP2	EQU	0x24			;             20 ms
TEMP3	EQU	0x25			;	      5 s
TEMP4	EQU	0x26			; character temp
;  Data memory for serial receive
COUNT	EQU	0x27			; # bits/serial character
RCREG	EQU	0x28			; received data (3 bytes)
DELAY   EQU	0x29			; delay between serial bits
;
;  Gate multiplier.  PIC#1 counts frequency for 16 ms.  Prescaler is set to
;  divide by 16.  Conversion from counts to kilocycles is counts*GMUL/10000.
;  Copied into these locations from EEPROM addresses GMULE<0,1>.
;
GMUL0	EQU	0x2A			; Gate multiplier RAM most significant byte
GMUL1	EQU	0x2B			;		      least
GMULE0  EQU	0			; Gate mult. EEPROM most significant byte
GMULE1	EQU	1			;		    least
;
;  Intermediate frequency.  PIC#1 sends local oscillator "counts" for
;  conversion to frequency.  In order to display tuned frequency, the IF
;  must be added.
;
IF0	EQU	0x2C			; IF RAM most significant byte
IF1	EQU	0x2D			;	 least
IFE0	EQU	2			; IF EEPROM most significant byte
IFE1	EQU	3			;	    least
;
;  Symbolic constants other than memory locations
;
CLOCKRATE	equ	.8000000	; clock rate MHz
BAUDRATE	equ	.19200		; baud rate (must match PJT1.ASM)
FCLK		equ	CLOCKRATE/4	; instruction rate
BAUDCONST	equ	((FCLK/BAUDRATE)/3-2)	; delay for 1 serial bit
EXTRASTRT	equ	BAUDCONST/2	; delay to get to middle of bit
DLY100US	equ	((.32*FCLK)/.1000000)	; tight loops for 100us wait

#define	_RX	PORTB,3			; Serial receive data port RB3
#define _OPT_E	PORTB,4			; Optrex enable bit RB4
#define _GATE	PORTB,5			; Freq counter gate pulse port RB5

	ORG	0x2100			; EEPROM initialization:
	DE	0x27,0x51		; Gate pulse multiplier (~10000 decimal)
	DE	0x2A,0xA4		; Intermediate frequency (~10916 kHz)

	ORG     0			; Begin execution here on reset
	GOTO	START

	ORG	4			; Vector here on interrupt
	RETFIE

; ---------------------------------------------------------

	;       SETUP

START   MOVLW   B'11111111'     ; PORT REGS TO DEFAULTS
	MOVWF   PORTB

	BSF     STATUS,RP0      ; OPTION & TRIS ARE HI REGS

	MOVLW   B'00000000'
	; B7:   RBPU   - ENABLE PORT B PULL-UP RES, 0=OFF
	; B6:   INTEDG - RB0 INT EDGE SEL 0=-VE
	; B5:   T0CS   - TMR0 SOURCE, 0=FOSC/4, 1=RA4 PIN
	; B4:   T0SE   - RA4CLK PIN EDGE SELECT, 0=+VE
	; B3:   PSA    - PRESCALE ASSIGN 0=TIMER, 1=WDG
	; B2-0: PS2-0  - PRESCALE RATE 111=256 FOR TIMER (=127 FOR WDT)

	MOVWF   OPTION_REG

	MOVLW   B'00000000'
	MOVWF	INTCON		; DISABLE ALL INTERRUPTS

	MOVLW   B'00001000'     ; 0=OUTPUT; 1=INPUT; _RX is only input
	MOVWF   TRISB
	MOVLW   B'00000000'     ; 0=OUTPUT; 1=INPUT
	MOVWF	TRISA

	BCF     STATUS,RP0      ; BACK TO LO REGS
;
;  Initialize OPTREX display.  Connections are:
;  PIC		OPTREX
;  RB0		RS
;  RB1		R/W
;  RB4		E
;  RA0		DB4
;  RA1		DB5
;  RA2		DB6
;  RA3		DB7
;
INIT	BCF	_GATE		; clear freq counter gate 

	CALL 	WT20M		; Per p. 30 of Optrex instructions:
	MOVLW	B'0011'		; 4-bit initialization
	MOVWF	PORTA
	CLRF	PORTB
	CALL	SENDOP		; Function Set Cmd: 8-bit interface

	MOVLW	B'0011'
	MOVWF	PORTA	
	CLRF	PORTB
	CALL 	SENDOP		; Function Set Cmd: 8-bit interface

	MOVLW	B'0011'
	MOVWF	PORTA
	CLRF	PORTB		; Function Set Cmd: 8=bit interface
	CALL	SENDOP		; After this cmd, BF can be checked

	MOVLW	B'0010'
	MOVWF	PORTA
	CLRF	PORTB
	CALL	SENDOP		; Function Set:  Sets interface to 4-bit

	MOVLW	B'0010'		; Set number of lines and
	MOVWF	PORTA		; character font
	CLRF	PORTB
	CALL	SENDOP
	MOVLW	B'1000'
	MOVWF	PORTA
	CLRF	PORTB
	CALL 	SENDOP

	CALL	DISPOFF
	CALL	CLEAR
	CALL	DISPON

	CALL	INCNSH		; Send RDY message and wait 5 seconds
	MOVLW	B'1100'	
	MOVWF	PORTA	
	CLRF	PORTB	
	CALL	SENDOP	
	MOVLW	B'0000'
	MOVWF	PORTA
	CLRF	PORTB
	CALL	SENDOP

	CALL	WT20M
	CALL	DISPOFF
	CALL	CLEAR
	CALL	DISPON
	CALL	DECNSH

	MOVLW	GMULE0		; Load gate pulse multiplier RAM from
	CALL	READEE		; EEPROM.
	MOVWF	GMUL0
	MOVLW	GMULE1
	CALL	READEE
	MOVWF	GMUL1

	MOVLW	IFE0		; Load intermediate frequency RAM
	CALL	READEE		; from EEPROM.
	MOVWF	IF0
	MOVLW	IFE1
	CALL	READEE
	MOVWF	IF1

NXTCMD	CALL	GETCMD		; Receive and execute serial port
	CALL	DECNSH		; commands.
	GOTO	NXTCMD
;
;  Optrex display routines
;
DISPON	CLRF	PORTA		; Turn display ON
	CLRF	PORTB
	CALL	SENDOP
	MOVLW	B'1100'
	MOVWF	PORTA
	CALL	SENDOP
	RETURN

DISPOFF	CLRF	PORTA		; Turn display OFF
	CLRF	PORTB
	CALL	SENDOP
	MOVLW	B'1000'
	MOVWF	PORTA
	CALL	SENDOP
	RETURN

CLEAR	CLRF	PORTA
	CLRF	PORTB
	CALL	SENDOP		; Clear display
	MOVLW	B'0001'
	MOVWF	PORTA
	CALL	SENDOP
	CALL	WT20M
	CLRF	PORTA
	CLRF	PORTB
	CALL	SENDOP
	MOVLW	B'0010'		; Return Home
	MOVWF	PORTA
	CALL	SENDOP
	CALL	WT20M
	RETURN

INCNSH	CLRF	PORTA		; Entry mode set to
	CLRF	PORTB		; increment DD RAM address, no shift
	CALL	SENDOP
	MOVLW	B'0110'		
	MOVWF	PORTA
	CALL	SENDOP
	RETURN

DECNSH	CLRF	PORTA		; Entry mode set to
	CLRF	PORTB		; decrement DD RAM address, no shift
	CALL	SENDOP
	MOVLW	B'0100'		
	MOVWF	PORTA
	CALL	SENDOP
	RETURN
;
;  Output character in W to Optrex
;
PUTCH	MOVWF	TEMP4
	SWAPF	TEMP4,0
	MOVWF	PORTA
	MOVLW	B'0001'
	MOVWF	PORTB
	CALL	SENDOP		; output high nibble
	
	MOVF	TEMP4,0
	MOVWF	PORTA
	MOVLW	B'0001'
	MOVWF	PORTB
	CALL	SENDOP		; output low nibble
	RETURN

SENDOP	BCF	_OPT_E		; Toggle Optrex ENABLE bit to read/write
	CALL	WT100U
	BSF	_OPT_E
	CALL	WT100U
	BCF	_OPT_E
	CALL	WT100U
	RETURN
;
;  Time delay routines
;
WT100U	MOVLW	DLY100US	; 100 usec wait w/4MHz clock s/b .32
	MOVWF	TEMP1	
WT1A	DECFSZ	TEMP1,1		; 1(2)us
	GOTO	WT1A		; 2us
	RETURN		

WT20M   MOVLW	.200		; 20 ms wait s/b .200
	MOVWF	TEMP2
WT20A	CALL	WT100U
	DECFSZ	TEMP2,1
	GOTO	WT20A
	RETURN

WT5S	MOVLW	.250		; 5s wait s/b .250
	MOVWF	TEMP3
WT5SA	CALL	WT20M
	DECFSZ	TEMP3,1
	GOTO	WT5SA
	RETURN

WT100M  MOVLW	.5		; 100 ms wait s/b .5
	MOVWF	TEMP4
WT100A  CALL	WT20M
	DECFSZ	TEMP4,1
	GOTO	WT100A
	RETURN

WT16M   MOVLW	.160		; 16 ms wait s/b .160
	MOVWF	TEMP2
WT16A	CALL	WT100U
	DECFSZ	TEMP2,1
	GOTO	WT16A
	RETURN
;
;  Serial receive
;
RECEIVE	BTFSS	_RX		; USE BTFSC TO FLIP POLARITY
	GOTO	RECEIVE
	MOVLW	EXTRASTRT	; WAIT 1.5 BAUDCONST'S ON START
	MOVWF	DELAY		; BIT SO WE'RE IN THE MIDDLE
RCVW1	DECFSZ	DELAY,F		; OF THE 1ST DATA BIT.
	GOTO	RCVW1
	MOVLW	.9
	MOVWF	COUNT
	MOVLW	BAUDCONST
	MOVWF	DELAY
RBAUDWT	DECFSZ	DELAY,F		; OTHER BITS, WAIT 1 BAUDCONST
	GOTO	RBAUDWT		; BETWEEN BITS.  IGNORE THE	
	MOVLW	BAUDCONST	; STOP BIT.
	MOVWF	DELAY
	DECFSZ	COUNT,F
	GOTO	RNXTBIT
	RETURN
RNXTBIT	BCF	_C
	BTFSS	_RX		; USE BTFSC TO FLIP POLARITY
	BSF	_C
	RRF	RCREG,F
	GOTO	RBAUDWT
;
;  Get command from the other PIC.  Commands are:
;
;  Ndd	display decimal number dd (no conversion) in left-hand 5 
;	character positions.
;  Fdd	display decimal tuned frequency dd (freq=counts*factor/10000+if) in
;	right-hand 5 character positions.
;  Ldd  display local oscillator decimal frequency dd (freq=counts*factor/10000)
;  Cd	display decimal channel d
;  P	Send freq counter duration gate pulse on RB1
;  Tx.. Display text x... terminated by a non-printing null byte.
;  B	Blank display
;  S    display gate pulse multiplier value
;  G    increment gate pulse multiplier
;  g    decrement gate pulse multiplier
;  W    Write gate pulse multiplier back to EEPROM
;
;  where each character is one byte.  Numbers d... and x... are
;  binary.
;
GETCMD	CALL	RECEIVE
GETCMD1	MOVF	RCREG,0		; 1st received character
	SUBLW	'F'		; =F?
	BTFSC	_Z		; no, try next command
	GOTO	DO_F		; Display tuned frequency
	MOVF	RCREG,0
	SUBLW	'N'		; =N?
	BTFSC	_Z
	GOTO	DO_N		; Display number with no conversion
	MOVF	RCREG,0
	SUBLW	'C'		; =C?
	BTFSC	_Z
	GOTO	DO_C		; Set channel display
	MOVF	RCREG,0
	SUBLW	'P'		; =P?
	BTFSC	_Z
	GOTO	DO_P		; Send gate pulse
	MOVF	RCREG,0
	SUBLW	'L'		; =L?
	BTFSC	_Z
	GOTO	DO_L		; Display local oscillator frequency
	MOVF	RCREG,0
	SUBLW	'T'		; =T?
	BTFSC	_Z
	GOTO	DO_T		; Text string
	MOVF	RCREG,0
	SUBLW	'S'		; =S?
	BTFSC	_Z
	GOTO	DO_S		; Display gate pulse multiplier
	MOVF	RCREG,0
	SUBLW	'G'		; =G?
	BTFSC	_Z
	GOTO	DO_IG		; Increment gate pulse multiplier
	MOVF	RCREG,0
	SUBLW	'g'		; =g?
	BTFSC	_Z
	GOTO	DO_DG		; Decrement gate pulse multiplier
	MOVF	RCREG,0
	SUBLW	'W'		; =W?
	BTFSC	_Z
	GOTO	DO_WG		; Write gate pulse multiplier EEPROM
	MOVF	RCREG,0
	SUBLW	'B'		; =B?
	BTFSC	_Z
	CALL	CLEAR		; Blank display
	RETURN
;
;  DO_S - Display gate pulse multiplier value
;
DO_S	MOVF	GMUL0,0
	MOVWF	AARGB0
	MOVF	GMUL1,0
	MOVWF	AARGB1
	GOTO	DO_N1
;
;  DO_IG - Increment gate pulse multiplier value
;
DO_IG	INCF	GMUL1,1
	BTFSC	_Z		; Least significant byte overflow?
	INCF	GMUL0,1
	GOTO	DO_S
;
;  DO_DG - Decrement gate pulse multiplier value
;
DO_DG	MOVLW	1
	SUBWF	GMUL1,1
	BTFSS	_C
	DECF	GMUL0,1
	GOTO	DO_S
;
;  DO_WG - Write gate pulse multiplier back to EEPROM
;
DO_WG	MOVF	GMUL0,0		; MS byte value
	MOVWF	AARG
	MOVLW	GMULE0		; EEPROM address
	CALL	WRITEE
	MOVF	GMUL1,0		; LS byte value
	MOVWF	AARG
	MOVLW	GMULE1		; EEPROM address
	CALL	WRITEE
	RETURN
;
;  DO_N - Display 5-character number with no conversion
;
DO_N	CALL	RECEIVE
	MOVF	RCREG,0
	MOVWF	AARGB1		; LS byte in AARGB1
	CALL	RECEIVE
	MOVF	RCREG,0
	MOVWF	AARGB0		; MS byte in AARGB0.

DO_N1	MOVLW	B'1000'		; Set Optrex DD RAM address=04
	MOVWF	PORTA		; to set character position to the 5th
	CLRF	PORTB		; from the left.  Digits are set in
	CALL	SENDOP		; reverse order.
	MOVLW	B'0100'
	MOVWF	PORTA
	CLRF	PORTB
	CALL	SENDOP

	GOTO	DO_DSP1
;
;  Display the 16-bit number in AARGB0,1
;
DO_DISP	MOVLW	B'1100'		; Set Optrex DD RAM address=47
	MOVWF	PORTA		; to set character position to end of line,
	CLRF	PORTB		; the last character in the frequency
	CALL	SENDOP		; section of the display.  Digits are sent
	MOVLW	B'0111'		; in reverse order.
	MOVWF	PORTA
	CLRF	PORTB
	CALL	SENDOP
	
DO_DSP1	MOVLW	.5		; # digits
	MOVWF	COUNT
	MOVLW	.10
	MOVWF	BARGB0

DIVF2	CALL	DIV1608
	MOVF	REMB0,0		; remainder is the current digit
	ADDLW	0x30
;	MOVWF	RCREG
	CALL	PUTCH
	DECFSZ  COUNT,1		; decrement # digits counter
	GOTO	DIVF2

	RETURN
;
;  DO_F - Display 5-character tuned frequency.  The value received
;	  from PIC#1 is the number of counts over the period set by
;	  the gate pulse, approximately 16 ms.  The prescaler is
;	  set to divide by 16.  If the gate pulse were exactlly 16ms,
;	  the conversion would be freq(kHz)=counts.  In order to adjust
;         the counter more precisely, set set freq(kHz)=counts*GMUL/10000.
;	  The numerator of conversion factor GMUL/10000 is the gate 
;	  pulse multiplier, which may be adjusted by commands G and g
;	  from PIC#1, and (re)stored to EEPROM by command W.  
;	  Adjustment to the gate pulse multiplier accommodate deviation 
;	  of the gate pulse period from 16ms, and errors in the PIC#1 
;	  measurement routine which are proportional to frequency.
;
DO_F	CALL	RECEIVE
	MOVF	RCREG,0
	MOVWF	AARGB1		; frequency LS byte
	CALL	RECEIVE
	MOVF	RCREG,0
	MOVWF	AARGB0		; frequency MS byte

	MOVF	GMUL0,0		; gate multiplier (~10000) MS byte
	MOVWF	BARGB0
	MOVF	GMUL1,0		; gate multiplier LS byte
	MOVWF	BARGB1	
	CALL	MUL1616		; Product in AARGB(0..3)
	
	MOVLW	0x27	
	MOVWF	BARGB0		; Load BARGB(0,1) with 10000 decimal
	MOVLW	0x10
	MOVWF	BARGB1		; Lower 16 bits of 32-bit quotient in
	CALL	DIV3115		; AARGB(2..3)

	MOVF	AARGB2,0
	MOVWF	AARGB0
	MOVF	AARGB3,0
	MOVWF	AARGB1

	GOTO	DO_DISP		; Display it
;
;  DO_L - Display local oscillator frequency - similar to DO_F, but
;	  intermediate frequency is not added.
;
DO_L	CALL	RECEIVE
	MOVF	RCREG,0
	MOVWF	AARGB1		; frequency LS byte
	CALL	RECEIVE
	MOVF	RCREG,0
	MOVWF	AARGB0		; frequency MS byte

	MOVF	GMUL0,0		; gate multiplier (~10000) MS byte
	MOVWF	BARGB0
	MOVF	GMUL1,0		; gate multiplier LS byte
	MOVWF	BARGB1	
	CALL	MUL1616		; Product in AARGB(0..3)
	
	MOVLW	0x27	
	MOVWF	BARGB0		; Load BARGB(0,1) with 10000 decimal
	MOVLW	0x10
	MOVWF	BARGB1		; Lower 16 bits of 32-bit quotient in
	CALL	DIV3115		; AARGB(2..3)

	MOVF	AARGB2,0
	MOVWF	AARGB0
	MOVF	AARGB3,0
	MOVWF	AARGB1

	GOTO	DO_DISP		; Display it
;
;  DO_C - Display 2-character channel number
;
DO_C	
	CALL	RECEIVE
	MOVF	RCREG,0
	MOVWF	AARGB1		; frequency LS byte
	CLRF	AARGB0		; frequency MS byte

	MOVLW	B'1000'		; Set Optrex DD RAM address=07
	MOVWF	PORTA		; to set character position to the last
	CLRF	PORTB		; character in the channel section of the 
	CALL	SENDOP		; display.  Digits are sent in reverse order.
	MOVLW	B'0111'
	MOVWF	PORTA
	CLRF	PORTB
	CALL	SENDOP
	
	MOVLW	.2		; # digits
	MOVWF	COUNT
	MOVLW	.10
	MOVWF	BARGB0

DIVC2	CALL	DIV1608
	MOVF	REMB0,0		; remainder is the current digit
	ADDLW	0x30
;	MOVWF	RCREG
	CALL	PUTCH
	DECFSZ  COUNT,1		; decrement # digits counter
	GOTO	DIVC2
	RETURN
;
;  DO_P - Send freq counter gate pulse (16 ms) to PIC#1
;
DO_P	BSF	_GATE
	CALL	WT16M	
	BCF	_GATE
	RETURN
;
;  DO_T - Display null-terminated text up to 8 bytes long
;
DO_T	CALL	INCNSH		; Text sent in ascending order
	MOVLW	B'1100'		; set Optrex DD RAM address to 40
	MOVWF	PORTA	
	CLRF	PORTB	
	CALL	SENDOP	
	MOVLW	B'0000'
	MOVWF	PORTA
	CLRF	PORTB
	CALL	SENDOP

	MOVLW	.8
	MOVWF	LOOPCOUNT

DO_TNXT	CALL	RECEIVE
	MOVF	RCREG,0
	BTFSC	_Z	
	RETURN
	CALL	PUTCH
	DECFSZ	LOOPCOUNT,1
	GOTO 	DO_TNXT
	RETURN
;
;  READEE - Read EEPROM address in W, return value in W
;
READEE	MOVWF	EEADR
	BSF	STATUS,RP0
	BSF	EECON1,RD
	BCF	STATUS,RP0
	MOVF	EEDATA,0
	RETURN
;
;  WRITEE - Write AARG into EEPROM address W
;
WRITEE	MOVWF	EEADR
	MOVF	AARG,0
	MOVWF	EEDATA
	BSF	STATUS,RP0	; Bank 1
	BCF	EECON1,EEIF
	BSF	EECON1,WREN	; Write enable EEPROM
	MOVLW	0x55		; Magic sequence
	MOVWF	EECON2
	MOVLW	0xAA
	MOVWF	EECON2
	BSF	EECON1,WR	; Begin write

WRITE1	BTFSS	EECON1,EEIF
	GOTO	WRITE1

	BCF	EECON1,EEIF	; Clear write interrupt flag
	BCF	EECON1,WREN
	BCF	STATUS,RP0	; Back to bank 0
	RETURN
;
;  Unsigned fixed point divide from MicroChip applications note AN617:
;  16 bits (ACCB0,ACCB1) = 16 bits (AARGB0,AARGB1)/8 bits (BARGB0)
;
UDIV1608L  macro

;       Max Timing: 2+7*12+11+3+7*24+23 = 291 clks

;       Min Timing: 2+7*11+10+3+7*17+16 = 227 clks

;       PM: 39                                  DM: 7

                MOVLW           8
                MOVWF           LOOPCOUNT

LOOPU1608A      RLF             ACCB0,W
                RLF             REMB0, F
                MOVF            BARGB0,W
                SUBWF           REMB0, F

                BTFSC           _C
                GOTO            UOK68A          
                ADDWF           REMB0, F
                BCF             _C
UOK68A          RLF             ACCB0, F

                DECFSZ          LOOPCOUNT, F
                GOTO            LOOPU1608A

                CLRF            TEMP

                MOVLW           8
                MOVWF           LOOPCOUNT

LOOPU1608B      RLF             ACCB1,W
                RLF             REMB0, F
                RLF             TEMP, F
                MOVF            BARGB0,W
                SUBWF           REMB0, F
                CLRF            ACCB5
                CLRW
                BTFSS           _C
                INCFSZ          ACCB5,W
                SUBWF           TEMP, F

                BTFSC           _C
                GOTO            UOK68B          
                MOVF            BARGB0,W
                ADDWF           REMB0, F
                CLRF            ACCB5
                CLRW
                BTFSC           _C
                INCFSZ          ACCB5,W
                ADDWF           TEMP, F

                BCF             _C
UOK68B          RLF             ACCB1, F

                DECFSZ          LOOPCOUNT, F
                GOTO            LOOPU1608B

                endm

;
;  Unsigned fixed point divide from MicroChip applications note AN617:
;  31 bits (ACCB0..3) = 31 bits (AARGB0..3)/15 bits (BARGB0)
;
UDIV3115L       macro

;       Max Timing:     9+6*17+16+16+6*17+16+16+6*17+16+16+6*17+16+8 = 537 clks

;       Min Timing:     9+6*16+15+15+6*16+15+15+6*16+15+15+6*16+15+3 = 501 clks

;       PM: 157                                 DM: 9

                MOVF            BARGB1,W
                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                RLF             ACCB0, F

                MOVLW           7
                MOVWF           LOOPCOUNT

LOOPU3115A      RLF             ACCB0,W
                RLF             REMB1, F
                RLF             REMB0, F
                MOVF            BARGB1,W
                BTFSS           ACCB0,LSB
                GOTO            UADD15LA

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                GOTO            UOK15LA

UADD15LA        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
        
UOK15LA 	RLF             ACCB0, F

                DECFSZ          LOOPCOUNT, F
                GOTO            LOOPU3115A

                RLF             ACCB1,W
                RLF             REMB1, F
                RLF             REMB0, F
                MOVF            BARGB1,W
                BTFSS           ACCB0,LSB
                GOTO            UADD15L8

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                GOTO            UOK15L8

UADD15L8        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
        
UOK15L8 	RLF             ACCB1, F

                MOVLW           7
                MOVWF           LOOPCOUNT

LOOPU3115B      RLF             ACCB1,W
                RLF             REMB1, F
                RLF             REMB0, F
                MOVF            BARGB1,W
                BTFSS           ACCB1,LSB
                GOTO            UADD15LB

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                GOTO            UOK15LB

UADD15LB        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
        
UOK15LB 	RLF             ACCB1, F

                DECFSZ          LOOPCOUNT, F
                GOTO            LOOPU3115B

                RLF             ACCB2,W
                RLF             REMB1, F
                RLF             REMB0, F
                MOVF            BARGB1,W
                BTFSS           ACCB1,LSB
                GOTO            UADD15L16

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                GOTO            UOK15L16

UADD15L16       ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
        
UOK15L16        RLF             ACCB2, F

                MOVLW           7
                MOVWF           LOOPCOUNT

LOOPU3115C      RLF             ACCB2,W
                RLF             REMB1, F
                RLF             REMB0, F
                MOVF            BARGB1,W
                BTFSS           ACCB2,LSB
                GOTO            UADD15LC

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                GOTO            UOK15LC

UADD15LC        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
        
UOK15LC 	RLF             ACCB2, F

                DECFSZ          LOOPCOUNT, F
                GOTO            LOOPU3115C

                RLF             ACCB3,W
                RLF             REMB1, F
                RLF             REMB0, F
                MOVF            BARGB1,W
                BTFSS           ACCB2,LSB
                GOTO            UADD15L24

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                GOTO            UOK15L24

UADD15L24       ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
        
UOK15L24        RLF             ACCB3, F

                MOVLW           7
                MOVWF           LOOPCOUNT

LOOPU3115D 	RLF		ACCB3,W
                RLF             REMB1, F
                RLF             REMB0, F
                MOVF            BARGB1,W
                BTFSS           ACCB3,LSB
                GOTO            UADD15LD

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                GOTO            UOK15LD

UADD15LD        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
        
UOK15LD 	RLF             ACCB3, F

                DECFSZ          LOOPCOUNT, F
                GOTO            LOOPU3115D

                BTFSC           ACCB3,LSB
                GOTO            UOK15L
                MOVF            BARGB1,W
	        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
UOK15L

                endm
;
;  Unsigned fixed point multiply from MicroChip applications note AN617:
;  32 bits (ACCB0...3) = 16 bits (AARGB0,AARGB1) * 16 bits (BARGB0,BARGB1)
;

UMUL1616L        macro

;       Max Timing:     2+13+6*15+14+2+7*16+15 = 248 clks

;       Min Timing:     2+7*6+5+1+7*6+5+4 = 101 clks

;       PM: 51            DM: 9

                MOVLW   	0x08
                MOVWF   	LOOPCOUNT

LOOPUM1616A
                RRF     	BARGB1, F
                BTFSC   	_C
                GOTO    	ALUM1616NAP
                DECFSZ  	LOOPCOUNT, F
                GOTO    	LOOPUM1616A

                MOVWF   	LOOPCOUNT

LOOPUM1616B
                RRF     	BARGB0, F
                BTFSC   	_C
                GOTO    	BLUM1616NAP
                DECFSZ  	LOOPCOUNT, F
                GOTO    	LOOPUM1616B

                CLRF    	AARGB0
                CLRF    	AARGB1
                RETLW   	0x00

BLUM1616NAP
                BCF     	_C
                GOTO    	BLUM1616NA

ALUM1616NAP
                BCF     	_C
                GOTO    	ALUM1616NA

ALOOPUM1616
                RRF     	BARGB1, F
                BTFSS   	_C
                GOTO    	ALUM1616NA
                MOVF   		TEMPB1,W
                ADDWF   	ACCB1, F
                MOVF            TEMPB0,W
                BTFSC           _C
                INCFSZ          TEMPB0,W
                ADDWF           ACCB0, F

ALUM1616NA
                RRF    		ACCB0, F
                RRF    		ACCB1, F
                RRF    		ACCB2, F
                DECFSZ  	LOOPCOUNT, F
                GOTO    	ALOOPUM1616

                MOVLW   	0x08
                MOVWF   	LOOPCOUNT

BLOOPUM1616
                RRF             BARGB0, F
                BTFSS   	_C
                GOTO    	BLUM1616NA
                MOVF   		TEMPB1,W
                ADDWF   	ACCB1, F
                MOVF            TEMPB0,W
                BTFSC           _C
                INCFSZ          TEMPB0,W
                ADDWF           ACCB0, F

BLUM1616NA
                RRF    		ACCB0, F
                RRF    		ACCB1, F
                RRF    		ACCB2, F
                RRF             ACCB3, F
                DECFSZ  	LOOPCOUNT, F
                GOTO    	BLOOPUM1616

                endm


;
;  Divide 16 bits (AARGB<0,1>)/8 bits (BARGB0) giving 16 bit quotient and 
;  8 bit remainder (REMB0).
;
DIV1608	CLRF	REMB0
	UDIV1608L
	RETURN

DIV3115	CLRF	REMB0
	CLRF	REMB1
	UDIV3115L
	RETURN

MUL1616	CLRF    ACCB2          ; clear partial product
        CLRF    ACCB3
        MOVF	AARGB0,W
        MOVWF   TEMPB0
        MOVF	AARGB1,W
        MOVWF   TEMPB1
        UMUL1616L
        RETURN

	END
