
; 2002.11.22 Kevin Timmerman - dci2007 [@t] compendiumarcana [d0t] com


				;
	list p=12C509		; CPU type
	include <P12C509a.inc>	; Include file
				;
	__config _MCLRE_OFF & _CP_OFF & _WDT_ON & _IntRC_OSC
;	__config _MCLRE_OFF & _CP_ON & _WDT_ON & _IntRC_OSC
				;
				;
				;
				;
	errorlevel	-224	; Disable tris and option warning messages
				;
	radix dec		; Default radix of decimal
				;
				;
				; --- Registers
				; 0x0C to 0x1F
				;
				; -- Serial Tx/Rx
rSerBitCnt	equ	0x0C	; Serial Rx/Tx bit count
rSerBitTmr	equ	0x0D	; Serial Rx/Tx bit timer
rSerTxChar	equ	0x0E	; Char to send to host
rSerRxChar	equ	0x0E	; Char received from host
rByteCnt	equ	0x0F	; Tx ASCII byte counter, message byte index
				;
				; -- Gauge
rBitCnt		equ	0x0C	; also used by scale
rData		equ	0x10	; 6 bytes 0x10-0x15
rChkSum		equ	rData+6	; 0x16
				;
				; -- Scale & Zero
rMode		equ	0x19	; 0=Raw, 1=IN, 2=MM, 3=binary
rMult		equ	0x0E	;
rProduct	equ	0x14	; 3 bytes 0x14-0x16
				;
				; -- Binary to ASCII
rBcd		equ	0x10	; 4 bytes 0x10-0x13
rAscii		equ	rBcd	; 8 bytes 0x10-0x17
rBin		equ	rProduct; 3 bytes 0x14-0x16
rPti		equ	0x0C	;
rPto		equ	0x0D	;
rI		equ	0x0E	;
rCnt		equ	0x0F	;
rTemp		equ	0x18	;
				;
				;
rFlags		equ	0x1A	; used for flags
				;
				; -- Flags
#define _LeadZero	rFlags,0 ; Supress zeros
#define _Negative	rFlags,1 ; Sample is (was) negative
#define	_ModeLock	rFlags,2 ; Model is locked by host
#define _HelpMsg	rFlags,3 ; Use help message in page 1
#define _BufValid	rFlags,4 ; Binary or ASCII buffer is valid
#define _DecPoint	rFlags,5 ; Decimal point follows this digit
#define _ReadGauge	rFlags,6 ; In gauge reading routines, handle WDT timeout differently
				;
PAGE1	equ	0x200		;
				;
				;
				;
				; --- Ports and port bits
pSerRx		equ	GPIO	; Serial Rx from host
bSerRx		equ	1	;
pSerTx		equ	GPIO	; Serial Tx to host
bSerTx		equ	5	;
				;
pGauge		equ	GPIO	; 
bData		equ	2	; Gauge Data
bClk		equ	0	; Gauge Clock
				;
pMode		equ	GPIO	; Jumper block
bMode0		equ	3	;
bMode1		equ	4	;
				;
				;
				;
				;
				;
				;
	org	0		; --- Program memory starts here
				;
	movwf	OSCCAL		; Setup osc. calibration
				;
	goto	Start		;
				;
				;
				;
				; ************************* Messages *********************
				;
Messages			;
	addwf	PCL,F		;
				;
msgStart			;
				;
msgCopyright			;
	DT	"Public Domain - Kevin Timmerman calpintf@pcmx.net",13,10,0
				;
msgVersion			;
	DT	"2002.11.22",13,10,0
				;
GetDp				;
	movf	rMode,W		; Get mode
	andlw	3		; Mask off other bits
	addwf	PCL,F		; Jump...
	retlw	0		; Raw
	retlw	4		; Inches
	retlw	2		; mm
	retlw	0		; binary
				;
				;
TxMessage			;
	movwf	rByteCnt	; Save message index
	btfss	_HelpMsg	; Help message (in page 1)?
	goto	nothelp		;
	bsf	STATUS,PA0	; Set page bit (page 1)
	call	msgHelp^PAGE1	;
	bcf     STATUS,PA0      ; Clear page bit (page 0)
	goto	tstchar		;
				;
nothelp	call	Messages	; Get a char
				;
tstchar	xorlw	0		; End?
	btfsc	STATUS,Z	; No...
	goto	msgdn		; End of message, return...
	call	SerTx		; Send char to host
	incf	rByteCnt,W	; Next char
	goto	TxMessage	; Loop...
				;
msgdn	bcf	_HelpMsg	; Clear help msg flag
	goto	breakack	;
				;
				;
				;
tblMode				;
	movf	rMode,W		;
	andlw	3		;
	addwf	PCL,F		;
	DT	"rimb"		;
				;
				;
				; **************** Async Serial I/O **************
				;
				; 104 us/bit = 9615.4 bps
				; Stop bit should be at least 106 us to prevent framing errors
				;
				; --- Send char to host
				; Warning: Requies one word of the stack
SerTx				;
	bsf	pSerTx,bSerTx	; Start bit
	clrwdt			; Clear watchdog
	movwf	rSerTxChar	; Move W to Tx char
	movlw	9		; 8 data bits + stop bit
	movwf	rSerBitCnt	;
	movlw	29		; Wait 1 bit time
	call	Delay		;
stxbit	call	SendBit		; Tx a bit
	movlw	28		; Wait 1 bit time
	call	Delay2		;
	decfsz	rSerBitCnt,F	; Dec bit count
	goto	stxbit		; Not 0, do next bit...
	goto	Delay2		; Finish stop bit and return
				;
SendBit				; -- Send bit to host
	bsf	STATUS,C	; 3     Shift in a 1 (stop bit)
	rrf	rSerTxChar,F	; 4     Shift out a bit
	btfss	STATUS,C	; 5     Is it a zero?
	goto	$+4		; 6(,7) Yes..
	nop			; 7     Precise timing
	bcf	pSerTx,bSerTx	; 8     Send a one (data is inverted, non-inverting buffer or direct connection used)
	retlw	0		; 9,10  Return
	bsf	pSerTx,bSerTx	; 8     Send a zero (data is inverted, non-inverting buffer or direct connection used)
	retlw	0		; 9,10  Return
				;
				;
				;
				; --- Get char from host
				; Note: Delay subs are not used so that stack usage is minimal
SerRx	movlw  8		; 8 bits
	movwf  rSerBitCnt	;
	clrf   rSerRxChar	; Clear Rx char
srxwsb	clrwdt			; Reset watchdog
	btfss  pSerRx,bSerRx	; Wait for start bit
	goto   srxwsb		;
	movlw  46		; Setup bit timer
	movwf  rSerBitTmr	;
srxwbt	decfsz rSerBitTmr,F	; Wait for 1 1/2 bits time
	goto   srxwbt		;
srxbit	nop			;
	bcf    STATUS,C		; Assume 0
	btfss  pSerRx,bSerRx	; Check Rx state
	bsf    STATUS,C		; Got a 1
	rrf    rSerRxChar,F	; Shift in the bit
	movlw  31		; Setup bit timer
	movwf  rSerBitTmr	;
srxbt	decfsz rSerBitTmr,F	; Wait for 1 bit time
	goto   srxbt		;
	decfsz rSerBitCnt,F	; Dec bit count
	goto   srxbit		; Not 0, do next bit...
	retlw  0		; Return
				;
				;
				;
				; **************** Delay subroutines *******************
Delay2	goto	$+1		; --- 6 + ( N * 3 ) Cycle delay
Delay				; --- 4 + ( N * 3 ) Cycle delay
	movwf	rSerBitTmr	; 3      Setup timer
	decfsz	rSerBitTmr,F	; 4      Decrement timer
	goto	$-1		; 5(,6)  Loop if not zero...
	retlw	0		; 6,7    Return
				;
				;
TxAscii				; *************** Send ASCII results to host ************
				;
				;
	movf	rAscii,W	; Get sign
	btfss	STATUS,Z	; Skip positive
	call	SerTx		; To host...
				;
	bsf	_LeadZero	; Suppress zeros
				;
	movlw	6		; 6 bytes to tx
	movwf	rByteCnt	;
	movlw	rAscii+1	; Setup pointer
	movwf	FSR		;
				;
nextbyte			;
	bcf	_DecPoint	; Assume not DP
	call	GetDp		; Get decimal place
	subwf	rByteCnt,W	; This one?
	btfss	STATUS,Z	;
	goto	notdec		; No...
	bsf	_DecPoint	;
	goto	txdigit		; Yes...
				;
notdec				;
	btfss	_LeadZero	; Suppress zeros?
	goto	txdigit		; No..
	movf	INDF,W		; Get a byte
	xorlw	'0'		; Zero?
	btfsc	STATUS,Z	;
	goto	skiptx		; Yes...
	bcf	_LeadZero	; Non-zero, stop checking for zeros
				;
txdigit				;
	movf	INDF,W		; Get the byte again
	call	SerTx		; Send to host
				;
	btfss	_DecPoint	; Skip if decimal should be sent
	goto	skiptx		; No decimal...
	bcf	_LeadZero	; No more zero supression
	movlw	'.'		; Prepare to send DP
	call	SerTx		; Send it
				;
skiptx				;
	incf	FSR,F		; Point to next byte
	decfsz	rByteCnt,F	; Dec byte count
	goto	nextbyte	; Next byte...
				;
	movf	INDF,W		; Always send last byte
	call	SerTx		;
				;
	movlw	0x0D		; CR
	call	SerTx		;
	movlw	0x0A		; LF
	call	SerTx		;
				;
				;
	goto	txdone		;
				;
				;
				; ********************** Main routine ********************
Start				;
	movlw	(1 << NOT_GPWU) | (1 << NOT_GPPU)
	option			; Set options
				;
	movlw	(1 << bSerRx) | (1<<bClk) | (1<<bData) | (1<<bMode0) | (1<<bMode1)
	tris	GPIO		;
				; 
	btfsc	STATUS,NOT_TO	; Watchdog timeout ?
	goto	notwdt		; No...
	btfsc	_ReadGauge	; Reading gauge during WDT timeout?
	goto	DoGauge		; Yes...
				;
notwdt				;
	clrf	GPIO		; Turn off all outputs
				;
				;
	clrf	rFlags		; Clear flags
				;
DoGauge				; ******************** 90 kHz sync reciever ******************
				; Read 6 bytes, See timing.sch/timing.pdf
				;
				;
	bsf	_ReadGauge	; There are many chances to get stuck within the following code
				; If the WDT does timeout, don't do a full reset, just return to here
				;
				; --- Idle clock line
	movlw	16		;
	movwf	rBitCnt		;
	btfss	pGauge,bClk	; Test clock
	goto	$-3		; Low, start over
	decfsz	rBitCnt,F	;
	goto	$-3		;
				;
				; --- Clock sync
chkbrk	clrwdt			; Reset watchdog
	btfsc	pSerRx,bSerRx	; Check for host break
	goto	breakwait	; Handle break...
	movlw	8		;
	movwf	rBitCnt		;
	btfsc	pGauge,bClk	; Test clock
	goto	chkbrk		; High, start over
	decfsz	rBitCnt,F	;
	goto	$-3		;
				;
				; --- Read sixth byte
	bsf	rBitCnt,3	; Do 8 bits
nb6	bcf	STATUS,C	; Assume low
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b6		;
	btfss	pGauge,bClk	; Wait for clock to go high
	goto	$-1		;
b6	btfsc	pGauge,bData	; Check data
	bsf	STATUS,C	; Is High
	rrf	rData+5,F	; Save bit
	decfsz	rBitCnt,F	; Dec bit count
	goto	nb6		; Next bit...
				;
				; --- Read fifth byte
	bsf	rBitCnt,3	; Do 8 bits
nb5	bcf	STATUS,C	; Assume low
	btfss	pGauge,bClk	; Wait for clock to go high
	goto	$-1		;
	btfsc	pGauge,bData	; Check data
	bsf	STATUS,C	; Is High
	rrf	rData+4,F	; Save bit
	decfsz	rBitCnt,F	; Dec bit count
	goto	nb5		; Next bit...
				;
				; --- Read fourth byte
	bsf	rBitCnt,3	; Do 8 bits
nb4	bcf	STATUS,C	; Assume low
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfsc	pGauge,bClk	; Wait for clock to go high
	goto	b4		;
	btfss	pGauge,bClk	; Wait for clock to go high
	goto	nextsec		;
b4	btfsc	pGauge,bData	; Check data
	bsf	STATUS,C	; Is High
	rrf	rData+3,F	; Save bit
	decfsz	rBitCnt,F	; Dec bit count
	goto	nb4		; Next bit...
				;
				; --- Clock sync
nextsec	movlw	16		;
	movwf	rBitCnt		;
	btfsc	pGauge,bClk	; Test clock
	goto	$-3		; High, start over
	decfsz	rBitCnt,F	;
	goto	$-3		;
				;
				; --- Read third byte
	bsf	rBitCnt,3	; Do 8 bits
nb3	bcf	STATUS,C	; Assume low 
	btfss	pGauge,bClk	; Wait for clock to go high
	goto	$-1		;
	btfsc	pGauge,bData	; Check data
	bsf	STATUS,C	; Is High
	rrf	rData+2,F	; Save bit
	decfsz	rBitCnt,F	; Dec bit count
	goto	nb3		; Next bit...
				;
				; --- Read second byte
	bsf	rBitCnt,3	; Do 8 bits
nb2	bcf	STATUS,C	; Assume low
	btfss	pGauge,bClk	; Wait for clock to go high
	goto	$-1		;
	btfsc	pGauge,bData	; Check data
	bsf	STATUS,C	; Is High
	rrf	rData+1,F	; Save bit
	decfsz	rBitCnt,F	; Dec bit count
	goto	nb2		; Next bit...
				;
				; --- Read first byte
	bsf	rBitCnt,3	; Do 8 bits
nb1	bcf	STATUS,C	; Assume low
	btfss	pGauge,bClk	; Wait for clock to go high
	goto	$-1		;
	btfsc	pGauge,bData	; Check data
	bsf	STATUS,C	; Is High
	rrf	rData,F		; Save bit
	decfsz	rBitCnt,F	; Dec bit count
	goto	nb1		; Next bit...
				;
				;
	clrwdt			; Out of the woods
	bcf	_ReadGauge	;
				;
				;
chkmode				;
	btfsc	_ModeLock	; Mode locked?
	goto	mdlk		; Yes...
	movlw	0		; Clear all bits
	btfss	pMode,bMode0	; Test bit 0
	iorlw	1		; Set it
	btfss	pMode,bMode1	; Test bit 1
	iorlw	2		; Set it
	movwf	rMode		;
				;
mdlk				;
	bsf	_BufValid	; Got a valid binary buffer, will be converted to
				;  valid ASCII buffer if needed
				;
	movf	rMode,W		; Get mode
	xorlw	3		; Binary mode?
	btfsc	STATUS,Z	;
	goto	txbin		; Yes...
	bsf	STATUS,PA0	;
	goto	AsciiMode^PAGE1 ; No...
				;
				;
				; ************ Send binary results to host *************
txbin				;
	movlw	0x55		;
	call	SerTx		;
				;
	clrf	rChkSum		; Clear checksum
	movf	rData,W		; Get first byte
	addwf	rChkSum,F	; Update checksum
	call	SerTx		; Send to host
	movf	rData+1,W	; Get second byte
	addwf	rChkSum,F	; Update checksum
	call	SerTx		; Send to host
	movf	rData+2,W	; Get third byte
	addwf	rChkSum,F	; Update checksum
	call	SerTx		; Send to host
	movf	rData+3,W	; Get fourth byte
	addwf	rChkSum,F	; Update checksum
	call	SerTx		; Send to host
	movf	rData+4,W	; Get fifth byte
	addwf	rChkSum,F	; Update checksum
	call	SerTx		; Send to host
	movf	rData+5,W	; Get sixth byte
	addwf	rChkSum,F	; Update checksum
	call	SerTx		; Send to host
				;
	movf	rChkSum,W	; Get checksum
	call	SerTx		; Send to host
				;
txdone				;
	goto	DoGauge		; Loop...
				;
				;
				;
				;
				; ********************* Host commands *************************
				;
breakwait			;
	clrwdt			; Could be here a while, reset watchdog
	bcf	_ReadGauge	;
	btfsc	pSerRx,bSerRx	; Wait for break to end
	goto	breakwait	;
				;
breakack			; Ack host break
	movlw	'?'		; "ACK"
	call	SerTx		; To host...
				;
	call	SerRx		; Get command from host
				;
	bcf	rSerRxChar,5	; Lower case to upper case
	movf	rSerRxChar,W	; Get command to W
				;
	xorlw	0		; Possible break
	btfsc	STATUS,Z	;
	goto	breakwait	;
	xorlw	0^'I'		; 'I'nches
	btfsc	STATUS,Z	;
	goto	Inches		;
	xorlw	'I'^'M'		; 'M'M
	btfsc	STATUS,Z	;
	goto	MM		;
	xorlw	'M'^'R'		; 'R'aw
	btfsc	STATUS,Z	;
	goto	Raw		;
	xorlw	'R'^'B'		; 'B'inary
	btfsc	STATUS,Z	;
	goto	Binary		;
	xorlw	'B'^'D'		; 'D'efault (jumpered) mode
	btfsc	STATUS,Z	;
	goto	Default		;
	xorlw	'D'^'G'		; 'G'et mode
	btfsc	STATUS,Z	;
	goto	Mode		;
	xorlw	'G'^'E'		; 'E'xit command mode
	btfsc	STATUS,Z	;
	goto	DoGauge		;
	xorlw	'E'^'V'		; 'V'ersion
	btfsc	STATUS,Z	;
	goto	Version		;
	xorlw	'V'^'C'		; 'C'opyright
	btfsc	STATUS,Z	;
	goto	Copyright	;
	xorlw	'C'^'N'		; I'n'itialize (reset)
	btfsc	STATUS,Z	;
	goto	$		; Watchdog timeout will reset
	xorlw	'N'^'H'		; 'H'elp
	btfsc	STATUS,Z	;
	goto	Help		;
				;
	movlw	'x'		; "NAK"
acknak				;
	call	SerTx		; To host...
	goto	breakack	;
				;
				;
Inches				;
	movlw	1		; Mode - 1=IN
	goto	setmode		;
				;
MM				;
	movlw	2		; Mode - 2=MM
	goto	setmode		;
				;
Raw				;
	movlw	0		; Mode - 0=Raw
	goto	setmode		;
				;
Binary				;
	movlw	3		; Mode - 3=binary
	;goto	setmode		;
				;
setmode				;
	movwf	rMode		;
	bsf	_ModeLock	; Stay in this mode
	bcf	_BufValid	; Buffer may be wrong mode
				;
Mode				;
	call	tblMode		;
txnack	call	SerTx		;
	goto	breakack	;
				;
Default				;
	bcf	_BufValid	; Buffer may be wrong mode
	bcf	_ModeLock	; Used jumpered mode
	;goto	Jumpers		;
				;
Jumpers				;
	movlw	0		; Clear all bits
	btfss	pMode,bMode0	; Test bit 0
	iorlw	1		; Set it
	btfss	pMode,bMode1	; Test bit 1
	iorlw	2		; Set it
	call	tblMode+1	;
	goto	txnack		;
				;
				;
Version				;
	movlw	msgVersion-msgStart
	goto	txm		;
				;
Copyright			;
	movlw	msgCopyright-msgStart
	goto	txm		;
				;
Help				;
	bsf	_HelpMsg	; Flag help message (in page 1)
	movlw	0		; Start with first char
txm	goto	TxMessage	; Send to host...
				;
				;
	org	0x200		; Second page
				;
msgHelp				; ************************** Help **********************
	addwf	PCL,F		;
	dt	13,10		;
	dt	"'H'elp",13,10
	dt	"'I'nches",13,10
	dt	"'M'illimeters",13,10
	dt	"'R'aw",13,10
	dt	"'B'inary",13,10
	dt	"use 'D'efault (jumper) setting",13,10
	dt	"'G'et mode",13,10
	dt	"'C'opyright",13,10
	dt	"'V'ersion",13,10
	dt	0		;
				;
				;
				;
AsciiMode			;
				;
				;
Scale				; ****** Scale native units to Inches or MM ******
				;
	bcf	_Negative	; Assume positive
	btfss	rData,7		; Test if negative
	goto	not_neg		; No...
				;
				; Sample is negative so make one's complement 
	comf	rData+2,F	;
	comf	rData+1,F	;
	comf	rData,F		;
	bsf	_Negative	; Flag negative
				;
not_neg				;
	movf	rMode,W		; Get mode
	xorlw	0		; Raw?
	btfsc	STATUS,Z	;
	goto	noscale		; Yes...
				;
				;
	movf	rMode,W		; Get mode
	xorlw	1		; Inches?
	btfss	STATUS,Z	;
	goto	scmm		; No...
				;
	movlw	125		; 125/256 - Inches
	movwf	rMult		;
	movlw	8		;
	goto	inmm		;
				;
scmm				;
	movlw	127		; 127/1024 - MM
	movwf	rMult		;
	movlw	10		;
inmm				;
	movwf	rBitCnt		; Setup bit count (N)
				;
				;
				; --- 24 * N (frac) multiply, fractional not calculated
				;
	clrf	rProduct	; Clear product
	clrf	rProduct+1	;
	clrf	rProduct+2	;
				;
mul				;
	bcf	STATUS,C	; Shift in a 0
	rrf	rMult,F		; Get the lsb of multiplier
				;
	btfss	STATUS,C	; Check the lsb
	goto	no_add		; Clear...
				;
				; -- 24 bit add
	movfw	rData+2		; LSB
	addwf	rProduct+2,F	;
				;
	movfw	rData+1		; Middle byte
	btfsc	STATUS,C	;
	incfsz	rData+1,W	;
	addwf	rProduct+1,F	;
				;
	movfw	rData		; MSB
	btfsc	STATUS,C	;
	incfsz	rData,W		;
	addwf	rProduct,F	;
				;
no_add	rrf	rProduct,F	; Shift product
	rrf	rProduct+1,F	;
	rrf	rProduct+2,F	;
				;
	decfsz	rBitCnt,F	; Dec bit count
	goto	mul		;
				;
	goto	ToAscii		; Convert to ASCII...
				;
noscale				;
				; No scaling - copy data to product
	movf	rData,W		;
	movwf	rProduct	;
	movf	rData+1,W	;
	movwf	rProduct+1	;
	movf	rData+2,W	;
	movwf	rProduct+2	;
				;
				;
				; ****************** Convert 24 bit binary to ASCII ************
				; Derived from 32 bit code by Ron Kreymborg and Mike Keitz 
				; See also Microchip app note 526
				;
ToAscii				; --- Do binary to packed BCD first
				;
b2bcd	movlw	24		; 24-bits
	movwf	rI		; Make cycle counter
	clrf	rBcd		; Clear result area
	clrf	rBcd+1		;
	clrf	rBcd+2		;
	clrf	rBcd+3		;
				;
b2bcd2	movlw	rBcd		; Make pointer
	movwf	FSR		;
	movlw	8/2		; Eight BCD nibbles, four packed bytes
	movwf	rCnt		;
				;
b2bcd3	movlw	0x33		; Add 3 to each nybble
	addwf	INDF,F		;
	btfsc	INDF,3		; Test if low result > 7
	andlw	0xf0		; Low result >7 so don't take the 3 out
	btfsc	INDF,7		; Test if high result > 7
	andlw	0x0f		; High result > 7 so don't take the 3 out
	subwf	INDF,F		; Any results <= 7, subtract back
	incf	FSR,F		; Point to next
	decfsz	rCnt,F		; Dec byte count
	goto	b2bcd3		; Do next byte...
				;
	rlf	rBin+2,f	; Get another bit
	rlf	rBin+1,f	;
	rlf	rBin+0,f	;
	rlf	rBcd+3,f	; Put it into bcd
	rlf	rBcd+2,f	;
	rlf	rBcd+1,f	;
	rlf	rBcd+0,f	;
	decfsz	rI,f		; All done?
	goto	b2bcd2		; No, loop
				;
				;
				;
				; --- Convert the 10 binary coded digits (5 bytes) starting at 
				; <bcd> into an ascii string also starting at <bcd>. Original
				; bcd digits are lost.
				;
bcd2a	movlw	rAscii+7	;
	movwf	rPto		; Destination pointer
	movlw	rBcd+3		;
	movwf	rPti		; Source pointer
	movlw	4		; 4 bytes to process
	movwf	rCnt		;
				;
bcd2a1	movf	rPti,W		; Get current input pointer
	movwf	FSR		;
	decf	rPti,F		; Prepare for next
	movf	INDF,W		; Get 2 bcds
	movwf	rTemp		; Save for later
	movf	rPto,W		; Get current output pointer
	movwf	FSR		;
	decf	rPto,F		; Prepare for next
	decf	rPto,F		;
	movf	rTemp,W		; Get digits back
	andlw	0x0f		; Process lsd
	movwf	INDF		;
	movlw	'0'		;
	addwf	INDF,F		; To output
	decf	FSR,F		;
	swapf	rTemp,W		; Process msd
	andlw	0x0f		;
	movwf	INDF		;
	movlw	'0'		;
	addwf	INDF,F		; To output
	decfsz	rCnt,F		; All digits?
	goto	bcd2a1		;
				;
				; --- Fixup last digit for Inches
	movf	rMode,W		; Get mode
	xorlw	1		; Inches?
	btfss	STATUS,Z	;
	goto	mmraw		; No...
				;
	movlw	'5'		; Compare to 5
	subwf	rAscii+7,W	; Get last digit
	movlw	'0'		; Assume <5
	btfsc	STATUS,C	; <5?
	movlw	'5'		; No
	movwf	rAscii+7	; Update
				;
mmraw				;
	movlw	0		; Assume no sign
	btfsc	_Negative	; Need it?
	movlw	'-'		; Put negative sign
	movwf	rAscii		; To first char
				;
				;
	bcf	STATUS,PA0	; Clear page bit (page 0)
	goto	TxAscii^PAGE1	; Send to host...
				;
				;
				;
	org	0x3FF		;
				;
	movlw	0x60		; 12C509A-JW OscCal
				;
	end





