;;; busdemo.asm
;;;
;;; demonstrates use of Handy Cricket bus
;;; toggles a pin when addressed by Cricket, 
;;; then gives one of two replies based on resulting state of the pin.
;;; 
;;; pin assignments:
;;; Port B 0 is bus I/O, Port B 7 is toggle pin
;;; 
;;; bus values:
;;; 17 (decimal) is bus address
;;; 100 or 101 are return values based on toggle pin's state.
;;; 
;;; NOTE!
;;; this bus code requires 4 MHz crystal with 1 usec per instruction clock

;	device pic16f84
;	config  OSC=xt
	radix dec
	
;;; register destination constants
W       equ     0
F       equ     1
	
;;; register constants
INDF	equ 0	
STATUS	equ 3			; status register
C	equ 0			; status C bit
Z	equ 2			; status Z bit
RP0	equ 5			; status register page 0
FSR	equ 4	
PORTB	equ 6			; port B register

;;; bus port and pin
BUSPORT	equ PORTB
BUSTRIS	equ PORTB + 0x80	; for setting bus as output
BUSPIN	equ 0			; bit 0

;;; memory variables
buscntr equ 0x20		; bit counter 
busdata	equ 0x21		; bus data register
counter equ 0x22		; temp register

	org 0
	
start:
	bsf STATUS,RP0
	bcf PORTB,7		; make port B7 output
	bcf STATUS,RP0

;;; the main loop
;;; block until receives word on bus
;;; check if it's cmd or data, if data, ignore.
;;; if cmd, check if it's our magic number, if not, ignore
;;; if it's for us, toggle output pin then generate reply.
loop:	
	call bus_tyi		; get word from bus
	btfss STATUS,C		; if C set, it's a cmd word
	goto loop

	movf busdata,W
	xorlw 17		; 17 is our magic number
	btfss STATUS,Z
	goto loop		; if Z clear, wasn't our number
	
	;; toggle PORTB 7 so we'll know cmd word was received!
	call toggle

	;; now, return 100 if PORTB 7 is low, 101 if high!
	;; from logo, "IF (BSR 256 + 17) = 101 [BEEP]"
	;;   will beep on alternate tries as the pin is toggled.
	movlw 100
	movwf busdata
	btfsc PORTB,7		; if PB7 set,
	incf busdata,F		;   incr busdata to 101
	call bus_tyo		; now return it.
	
	goto loop
	
;;; inverts state of PORTB 7
toggle:
	btfsc PORTB,7
	goto togclr
	bsf PORTB,7
	return
togclr:	bcf PORTB,7
	return

	
;;; returns byte in busdata
;;; the inverse of the stop bit in the carry
;;; commands have a 0 stop bit -> carry set
;;; data has a 1 stop bit -> carry clear
bus_tyi:	
	btfsc BUSPORT,BUSPIN
	goto bus_tyi		; loop until bus line goes low

;	bcf INTCON,GIE		; disable interrupts (if necessary)

btyi20	btfss BUSPORT,BUSPIN
	goto btyi20		; wait for end of prestart

	movlw 8
	movwf buscntr
	call an_rts		; use 4 cycles, into middle of start bit

btyi30	nop
	nop
	nop
	rrf busdata,F		; pre-rotate destination byte
	bcf busdata,7		; clear high bit (it'll rotate down)
	btfsc BUSPORT,BUSPIN
	bsf busdata,7		; if BUSPIN was set, set busdata bit
	decfsz buscntr,F
	goto btyi30

	call an_rts
	nop
	bsf STATUS,C		; pre-set carry (cmd word)
	btfsc BUSPORT,BUSPIN
	bcf STATUS,C		; if no stop bit, clear carry

;	bsf INTCON,GIE		; re-enable interrupts (if necessary)
an_rts
	return

;;; send a byte down the bus.
;;; this is the slave device code, so send '1' as stop bit,
;;;   indicating a data word.
;;; put the byte to send in busdata before calling.
bus_tyo:
;	bcf INTCON,GIE		; disable interrupts (if necessary)

	movlw BUSTRIS
	movwf FSR		; will be controlling bus to output
	bcf BUSPORT,BUSPIN	; put 0 into pin register
	bcf INDF,BUSPIN		; write it out & begin pre-start pulse
	movlw 33
	movwf counter
btyo20:	decfsz counter,F
	goto btyo20		; wait 100 usec
	bsf BUSPORT,BUSPIN	; end pre-start, begin start bit

	bsf STATUS,C		; will be stop bit, indicating data word
	movlw 9			; 8 data bits plus C bit last
	movwf counter
	call an_rts		; use up 4 cycles
	nop			; plus 1 more making 10 for start bit
	
btyo50:	rrf busdata,F		; bit -> carry
	btfss STATUS,C		; if C is clear, 
	bcf BUSPORT,BUSPIN	;   clear bus pin
	btfsc STATUS,C		; if C was set,
	bsf BUSPORT,BUSPIN	;   set bus pin
	nop
	nop			; tune the loop to take 10 us
	decfsz counter,F
	goto btyo50
	nop
	nop
	bsf INDF,BUSPIN		; bus to input again, float high
;	bsf INTCON,GIE		; re-enable interrupts (if necessary)
	return

	end

