tashkm/daisy-device/daisy-device.asm

1611 lines
44 KiB
NASM

;;; 80 characters wide please ;;;;;;;;;;;;;;;;;;;;;;;;;; 8-space tabs please ;;;
;
;;;
;;;;; TashKM: Daisy-Chain-Controlled ADB Device
;;;
;
;;; License ;;;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Connections ;;;
;;; ;;;
; .--------. ;
; Supply -|01 \/ 08|- Ground ;
; ADB Data <--> RA5 -|02 07|- RA0/TX ---> To Next RX ;
; ADB Power <--- RA4 -|03 06|- RA1/RX <--- From Previous TX ;
; ---> RA3 -|04 05|- RA2 ---- ;
; '--------' ;
;;; ;;;
;;; Assembler Directives ;;;
list P=PIC12F1840, F=INHX32, ST=OFF, MM=OFF, R=DEC, X=ON
#include P12F1840.inc
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
;_FOSC_INTOSC Internal oscillator, I/O on RA5
;_WDTE_OFF Watchdog timer disabled
;_PWRTE_ON Keep in reset for 64 ms on start
;_MCLRE_OFF RA3/!MCLR is RA3
;_CP_OFF Code protection off
;_CPD_OFF Data memory protection off
;_BOREN_OFF Brownout reset off
;_CLKOUTEN_OFF CLKOUT disabled, I/O on RA4
;_IESO_OFF Internal/External switch not needed
;_FCMEN_OFF Fail-safe clock monitor not needed
__config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _LVP_OFF
;_WRT_OFF Write protection off
;_PLLEN_ON 4x PLL on
;_STVREN_ON Stack over/underflow causes reset
;_LVP_OFF High-voltage on Vpp to program
;;; Macros ;;;
DELAY macro value ;Delay 3*W cycles, set W to 0
movlw value
decfsz WREG,F
bra $-1
endm
DNOP macro
bra $+1
endm
;;; Constants ;;;
;Timer0 values to time out after:
PULSE_DNS equ -8 ;A short down pulse (first half of a '1')
PULSE_DNL equ -16 ;A long down pulse (first half of a '0')
PULSE_UPS equ -8 ;A short up pulse (second half of a '0')
PULSE_UPL equ -16 ;A long up pulse (second half of a '1')
;RX_FLAGS:
SRQ_ON equ 7 ;Set when holding the line low for a service request
RX_RST equ 6 ;Set when the receiver has detected a reset condition
RX_CMD equ 5 ;Set when ADB_CMD contains a command byte
RX_DATA equ 4 ;Set when ADB_BUF-ADB_BUF8 contain a data packet
RX_ABRT equ 3 ;Set when a data packet has been aborted
RX_SIZ2 equ 2 ;Number of bytes received minus one
RX_SIZ1 equ 1 ; "
RX_SIZ0 equ 0 ; "
;TX_FLAGS:
TX_RDY equ 7 ;Set when data is set up to transmit
TX_ON equ 6 ;Set when transmitter is running
TX_COL equ 5 ;Set when transmitter detected a collision
TX_SIZ2 equ 2 ;Number of bytes to be transmitted minus one
TX_SIZ1 equ 1 ; "
TX_SIZ0 equ 0 ; "
;DV_FLAGS:
DV_KBDC equ 7 ;Set when there was a collision on keyboard's address
DV_MSEC equ 6 ;Set when there was a collision on mouse's address
DV_MSES equ 4 ;Set when the mouse needs service
;U_FLAGS:
U_HEADR equ 7 ;Set when we've received and are working a header byte
U_FWD equ 6 ;Set when we're just forwarding (not queuing) bytes
U_ISMSE equ 5 ;Set to receive for the mouse, clear for keyboard
U_CNTR3 equ 3 ;Counter of bytes to forward or act on
U_CNTR2 equ 2 ; "
U_CNTR1 equ 1 ; "
U_CNTR0 equ 0 ; "
;KBD_2_H:
K2H_DEL equ 6 ;Delete
K2H_CAP equ 5 ;CapsLock
K2H_RST equ 4 ;Reset
K2H_CTL equ 3 ;Control
K2H_SHF equ 2 ;Shift
K2H_OPT equ 1 ;Option
K2H_CMD equ 0 ;Command
;KBD_2_L:
K2L_CLR equ 7 ;Clear
K2L_SLK equ 6 ;ScrollLock
;KBD_MODS:
KMD_LCT equ 7 ;Left Control
KMD_RCT equ 6 ;Right Control
KMD_LSH equ 5 ;Left Shift
KMD_RSH equ 4 ;Right Shift
KMD_LOP equ 3 ;Left Option
KMD_ROP equ 2 ;Right Option
;;; Variable Storage ;;;
cblock 0x70 ;Bank-common registers
RX_FLAGS ;Receiver flags
TX_FLAGS ;Transmitter flags
DV_FLAGS ;Device flags
U_FLAGS ;UART flags
RX_TDOWN ;Time spent down in the last down-up transition
RX_TUP ;Time spent up in the last down-up transition
ADB_PTR ;Receiver/transmitter state machine pointer
ADB_CMD ;Receiver command buffer
ADB_BUF ;Receiver/transmitter buffer
ADB_BUF2 ;2nd byte of receiver/transmitter buffer
ADB_BUF3 ;3rd byte of receiver/transmitter buffer
ADB_BUF4 ;4th byte of receiver/transmitter buffer
ADB_BUF5 ;5th byte of receiver/transmitter buffer
ADB_BUF6 ;6th byte of receiver/transmitter buffer
ADB_BUF7 ;7th byte of receiver/transmitter buffer
ADB_BUF8 ;8th byte of receiver/transmitter buffer
endc
cblock 0xD0 ;Upper half of bank 1 registers
KBD_2_H ;Keyboard register 2 high byte
KBD_2_L ;Keyboard register 2 low byte
KBD_MODS ;Keyboard modifier key state
KBD_3_H ;Keyboard register 3 high byte
KBD_3_L ;Keyboard register 3 low byte
MSE_DXH ;Mouse delta X high byte
MSE_DXL ;Mouse delta X low byte
MSE_DYH ;Mouse delta Y high byte
MSE_DYL ;Mouse delta Y low byte
MSE_BTN ;Mouse buttons
MSE_3_H ;Mouse register 3 high byte
MSE_3_L ;Mouse register 3 low byte
endc
;;; Vectors ;;;
org 0x0 ;Reset vector
bra Init
org 0x4 ;Interrupt vector
;;; Interrupt Handler ;;;
Interrupt
btfsc RX_FLAGS,SRQ_ON ;If the SRQ_ON flag is set, branch into the
bra IntSrqDone ; logic to end the service request condition
btfsc TX_FLAGS,TX_ON ;If the TX_ON flag is set, branch into the
bra IntXmit ; transmitter logic
;fall through
IntRecv
movlb 0 ;Quick as we can, capture the current value
movf TMR0,W ; from Timer0 and reset it
clrf TMR0 ; "
btfsc INTCON,TMR0IF ;If Timer0 overflowed, set the captured value
movlw 0xFF ; to 0xFF instead
movlb 7 ;If we aren't here because of an on-change
btfss IOCAF,5 ; interrupt, we're here because of a timer
bra IntRecvTimeout ; overflow while the bus is high - a timeout
btfss IOCAN,5 ;If the on-change interrupt is set to capture
bra IntRecvRising ; rising edges, branch into rising-edge logic
;fall through
IntRecvFalling
bcf IOCAN,5 ;Switch the on-change interrupt to capture
bsf IOCAP,5 ; rising edges
bcf IOCAF,5 ;Clear the on-change interrupt flag
bcf INTCON,TMR0IF ;Reset the Timer0 interrupt if it was set
bcf INTCON,TMR0IE ;Don't interrupt on bus timeout when low
addlw 33 ;Adjust the time the line spent floating high
movwf RX_TUP ; so it's zero-based and store it
addwf RX_TDOWN,W ;Check if the sum of the time spent up and the
btfsc STATUS,C ; time spent down is greater than 132 us; if it
bra IntRecvNotBit ; is, then it's out of range for a 1 or 0 bit
addlw -34 ; cell and must be something else
btfsc STATUS,C ; "
bra IntRecvNotBit ; "
;fall through
IntRecvBitCell
addlw 34 ;If it is 132 us or less, halve it to see what
lsrf WREG,W ; the threshold is to tell a 1 from a 0
subwf RX_TDOWN,W ;If the down time is less than the threshold,
movlp high RxFsa0 ; point PCLATH to the state machine for
btfss STATUS,C ; receiving a 1, else a zero
movlp high RxFsa1 ; "
movf ADB_PTR,W ;Jump into the appropriate state machine
callw ; "
movwf ADB_PTR ; "
retfie
IntRecvNotBit
movf RX_TDOWN,W ;Bucketize the time the line spent pulled down;
movlp high RxFsaR ; if none of these apply, treat as a reset
addlw -24 ;232 ;If <= 23 (70us +30%), treat as 0 (stop bit)
btfss STATUS,C ; "
movlp high RxFsa0 ; "
addlw -75 ;181 ;If <= 98 (300us +30%), treat as service req
btfss STATUS,C ; "
movlp high RxFsaS ; "
addlw -108 ;148 ;If <= 206 (800us +3%), treat as attention
btfss STATUS,C ; "
movlp high RxFsaA ; "
movf ADB_PTR,W ;Jump into the appropriate state machine
callw ; "
movwf ADB_PTR ; "
retfie
IntRecvRising
btfsc TX_FLAGS,TX_RDY ;If the mainline code is ready to transmit,
bra IntXmitReady ; a rising edge is where we switch modes
bcf IOCAP,5 ;Switch the on-change interrupt to capture
bsf IOCAN,5 ; falling edges
bcf IOCAF,5 ;Clear the on-change interrupt flag
movwf RX_TDOWN ;Store the time the line spent pulled low
bcf INTCON,TMR0IF ;Reset the Timer0 interrupt if it was set
movlb 0 ;Set Timer0 to time out after 132 us, just
movlw -33 ; a bit longer than the maximum bit cell time,
movwf TMR0 ; so we catch the end of a transaction quickly
bsf INTCON,TMR0IE ;Use Timer0 interrupt to detect bus timeout
retfie
IntRecvTimeout
bcf INTCON,TMR0IE ;Only interrupt on bus timeout once
movlp high RxFsaT ;Jump into the timeout state machine
movf ADB_PTR,W ; "
callw ; "
movwf ADB_PTR ; "
retfie
IntSrqDone
bcf RX_FLAGS,SRQ_ON ;Clear the SRQ_ON flag so we don't return here
bcf INTCON,TMR0IF ;Clear the timer interrupt that brought us here
bcf INTCON,TMR0IE ;Disable timer interrupt as the line is low
movlb 1 ;Release the ADB line to end the service
movlw B'00100000' ; request and cause an on-change interrupt
iorwf TRISA,F ; "
movlb 0 ;Set Timer0 to 75 (300 us), same nominal value
movlw 75 ; as if the service request had been made by
movwf TMR0 ; another device so receiver reads it as such
retfie
IntXmitReady
bcf IOCAP,5 ;Switch on-change interrupt to capture falling
bsf IOCAN,5 ; edges (trigger on other devices pulling low)
bcf IOCAF,5 ;Clear the interrupt that brought us here
bcf TX_FLAGS,TX_RDY ;Clear the TX_RDY flag and raise the TX_ON flag
bsf TX_FLAGS,TX_ON ; to indicate that we've switched modes
clrf ADB_PTR ;Clear state pointer now we've changed machines
movlb 0 ;Get a pseudorandom number between 0 and 15,
movf TMR1H,W ; turn it into a number between 199 and 214;
xorwf TMR1L,W ; that will make Timer0 overflow in between
andlw B'00001111' ; 168 us and 228 us, which is close enough to
addlw -57 ; the specced range of 160 us to 240 us to wait
movwf TMR0 ; before transmitting
bcf INTCON,TMR0IF ;Reset the Timer0 interrupt if it was set
bsf INTCON,TMR0IE ;Use Timer0 interrupt to cause transmit start
retfie
IntXmit
btfsc INTCON,IOCIF ;If we're in the transmit logic because of IOC,
bra IntXmitCol ; pin changed under us and we have a collision
movlb 1 ;If not, we're here because of a timer
movlw B'00100000' ; interrupt that signifies we should toggle
xorwf TRISA,F ; whether we're pulling the ADB pin low
btfss TRISA,5 ;If we're pulling the pin low, we can't detect
bra IntXmitNoCol ; a collision, so assume there isn't one
movlb 0 ;If we're letting the pin float but it's still
btfsc PORTA,5 ; low, something else is driving it at the same
bra IntXmitNoCol ; time as us and there's a collision
;fall through
IntXmitCol
bsf TX_FLAGS,TX_COL ;Raise the collision flag
bcf TX_FLAGS,TX_ON ;Reset everything into receiver mode as though
clrf ADB_PTR ; the line were idle; the receiver will ignore
movlb 7 ; the rest of the conflicting transmission and
movlw B'00100000' ; await the next attention or reset pulse
movwf IOCAN ; "
clrf IOCAP ; "
clrf IOCAF ; "
clrf RX_TDOWN ; "
movlw B'00001000' ; "
movwf INTCON ; "
retfie
IntXmitNoCol
movlb 0 ;Call into the transmitter state machine
movlp high TxFsa ; "
movf ADB_PTR,W ; "
callw ; "
movwf ADB_PTR ; "
bcf INTCON,TMR0IF ;Clear Timer0 interrupt that brought us here
movlb 7 ;Clear the on-change interrupt in case we
bcf IOCAF,5 ; pulled the line low and caused one
retfie
;;; Mainline ;;;
Init
banksel OSCCON ;32 MHz (w/PLL) high-freq internal oscillator
movlw B'11110000'
movwf OSCCON
banksel IOCAN ;RA5 sets IOCAF[5] on negative edge
movlw B'00100000'
movwf IOCAN
banksel RCSTA ;UART async mode, 115.2 kHz
movlw B'01001000'
movwf BAUDCON
clrf SPBRGH
movlw 68
movwf SPBRGL
movlw B'00100110'
movwf TXSTA
movlw B'10010000'
movwf RCSTA
banksel OPTION_REG ;Timer0 uses instruction clock, 1:32 prescaler,
movlw B'01010100' ; thus ticking every 4 us; weak pull-ups on
movwf OPTION_REG
banksel T1CON ;Timer1 ticks with instruction clock
movlw B'00000001'
movwf T1CON
banksel ANSELA ;All pins digital, not analog
clrf ANSELA
banksel LATA ;Ready to pull RA5-4 low when outputs
movlw B'00001111'
movwf LATA
banksel TRISA ;TX output, RX and unused pins inputs, RA5-4
movlw B'00111110' ; open-collector outputs, currently off
movwf TRISA
movlb 1
movlw 0x22 ;Keyboard register 3 puts it at address 0x2,
movwf KBD_3_H ; with SRQ enabled and handler ID 2
movlw 0x02
movwf KBD_3_L
movlw 0x23 ;Mouse register 3 puts it at address 0x3, with
movwf MSE_3_H ; SRQ enabled and handler ID 1
movlw 0x01
movwf MSE_3_L
movlw 0x20 ;Set up keyboard queue (0x2000-0x207F), for
movwf FSR0H ; which FSRs are push (FSR0) and pop (FSR1)
movwf FSR1H ; pointers
clrf FSR0L
clrf FSR1L
clrf TX_FLAGS ;Particularly important that these are zero
clrf RX_FLAGS
clrf DV_FLAGS
clrf U_FLAGS
clrf ADB_PTR
movlw B'10001000' ;On-change interrupt and interrupt subsystem on
movwf INTCON
bra Main
GotUartByte
btfss U_FLAGS,U_HEADR ;If we're awaiting a header byte, this is it
bra GUNewHeader ; "
btfsc U_FLAGS,U_FWD ;If we're forwarding bytes, forward this one,
bra GUForwardByte ; else queue it
btfsc U_FLAGS,U_ISMSE ;If this byte is for the mouse, interpret it
bra GUMouseByte ; as such, otherwise interpret for keyboard
;fall through
GUKeyboardByte
movlb 3 ;Push the byte that came in over the UART onto
movf RCREG,W ; the keyboard queue
movwi FSR0++ ; "
bcf FSR0L,7 ; "
clrf U_FLAGS ;Keyboard packet done, await new header
bra Main
GUMouseByte
bcf DV_FLAGS,DV_MSES;Don't signal for service, data may not be done
movf U_FLAGS,W ;Branch into one of the following depending on
andlw B'00000011' ; the remaining-bytes counter to determine how
brw ; to interpret this byte for the mouse:
nop ;(0) This shouldn't happen, fall through to...
bra GUMouseButtons ;(1) Finish with the mouse buttons
bra GUMouseDeltaX ;(2) Add to the mouse X delta
bra GUMouseDeltaY ;(3) Add to the mouse Y delta
GUMouseButtons
movlb 3 ;Grab the byte that came in over the UART
movf RCREG,W ; "
movlb 1 ;AND it with the current state of mouse buttons
andwf MSE_BTN,F ; so that clicks are always registered
bsf DV_FLAGS,DV_MSES;Signal that the mouse needs service
clrf U_FLAGS ;Mouse packet done, await new header
bra Main
GUMouseDeltaX
movlb 3 ;Grab the byte that came in over the UART
movf RCREG,W ; "
movlb 1 ;Add it to the low byte of the 16-bit delta X
addwf MSE_DXL,F ; counter
iorlw B'01111111' ;Sign-extend the byte and add this to the high
btfss WREG,7 ; byte of the 16-bit delta X counter
movlw 0 ; "
addwfc MSE_DXH,F ; "
decf U_FLAGS,F ;Decrement remaining-bytes counter
bra Main
GUMouseDeltaY
movlb 3 ;Grab the byte that came in over the UART
movf RCREG,W ; "
movlb 1 ;Add it to the low byte of the 16-bit delta Y
addwf MSE_DYL,F ; counter
iorlw B'01111111' ;Sign-extend the byte and add this to the high
btfss WREG,7 ; byte of the 16-bit delta Y counter
movlw 0 ; "
addwfc MSE_DYH,F ; "
decf U_FLAGS,F ;Decrement remaining-bytes counter
bra Main
GUForwardByte
movlb 3 ;Retransmit the byte that came in over the UART
movf RCREG,W ; "
movwf TXREG ; "
decf U_FLAGS,F ;Decrement the counter in the UART flags
movf U_FLAGS,W ;If the counter has reached zero, lower all
andlw B'00001111' ; flags and await a new header byte
btfsc STATUS,Z ; "
clrf U_FLAGS ; "
bra Main
GUNewHeader
movlb 3 ;Grab the byte that came in over the UART
movf RCREG,W ; "
btfss WREG,7 ;All header bytes have MSB set; if it's clear,
clrf TXREG ; relay a zero; this way the host can send a
btfss WREG,7 ; string of zero bytes to get all units to a
bra Main ; known state
bsf U_FLAGS,U_HEADR ;Raise the flag that we have a header byte
bsf U_FLAGS,U_CNTR0 ;We'll be receiving at least one byte
btfsc WREG,6 ;If bit 6 of the header byte is set, this is a
bsf U_FLAGS,U_ISMSE ; mouse packet, so raise that flag
btfsc WREG,6 ;If receiving a mouse packet, it has 3 bytes so
bsf U_FLAGS,U_CNTR1 ; add 2 to the counter in the flags register
btfsc WREG,5 ;If any of the incoming byte's address bits are
bsf U_FLAGS,U_FWD ; set, then we need to forward it
btfsc WREG,4 ; "
bsf U_FLAGS,U_FWD ; "
btfsc WREG,3 ; "
bsf U_FLAGS,U_FWD ; "
btfsc WREG,2 ; "
bsf U_FLAGS,U_FWD ; "
btfsc WREG,1 ; "
bsf U_FLAGS,U_FWD ; "
btfsc WREG,0 ; "
bsf U_FLAGS,U_FWD ; "
btfss U_FLAGS,U_FWD ;If we're not forwarding, we're done here
bra Main ; "
decf WREG,W ;Decrement the address and then pass the header
movwf TXREG ; byte forward to the next device
bra Main
GotReset
movlb 1
movlw 0x22 ;Keyboard register 3 puts it at address 0x2,
movwf KBD_3_H ; with SRQ enabled and handler ID 2
movlw 0x02
movwf KBD_3_L
movlw 0x23 ;Mouse register 3 puts it at address 0x3, with
movwf MSE_3_H ; SRQ enabled and handler ID 1
movlw 0x01
movwf MSE_3_L
bcf RX_FLAGS,RX_RST
bra Main
GotCmd
bcf RX_FLAGS,RX_CMD ;Clear the command flag
movf ADB_CMD,W ;If the low four bits of the command are zeroes
andlw B'00001111' ; then this is a SendReset command and should
btfsc STATUS,Z ; be treated the same as a long reset pulse
bra GotReset ; "
andlw B'00001100' ;If bits 3-2 of the command are 0b11, this is
xorlw B'00001100' ; a talk command; otherwise, it's a flush which
btfss STATUS,Z ; we ignore or a listen which we'll handle when
bra Main ; we get the data that comes along with it
movlb 1 ;Compare the address of the talk command with
swapf ADB_CMD,W ; the stored address for the keyboard; if they
xorwf KBD_3_H,W ; match, this is a talk command for the
andlw B'00001111' ; keyboard
btfsc STATUS,Z ; "
bra KeyboardTalk ; "
swapf ADB_CMD,W ;Compare the address of the talk command with
xorwf MSE_3_H,W ; the stored address for the mouse; if they
andlw B'00001111' ; match, this is a talk command for the mouse
btfsc STATUS,Z ; "
bra MouseTalk ; "
movf FSR0L,W ;If the keyboard queue is not empty or the
xorwf FSR1L,W ; mouse service flag is up, we need our devices
btfsc STATUS,Z ; to be polled, so send a service request
btfsc DV_FLAGS,DV_MSES; "
call ServiceRequest ; "
bra Main
KeyboardTalk
movf ADB_CMD,W ;If this is a talk register 0, handle that
andlw B'00000011' ; "
btfsc STATUS,Z ; "
bra KeyboardTalk0 ; "
addlw -1 ;If this is a talk register 1, we have no
btfsc STATUS,Z ; handler for that, so done
bra Main ; "
addlw -1 ;If this is a talk register 2, handle that
btfsc STATUS,Z ; "
bra KeyboardTalk2 ; "
bra KeyboardTalk3 ;Else it's a talk register 3, handle that
KeyboardTalk0
btfsc DV_FLAGS,DV_MSES;If the mouse needs service, effect a service
call ServiceRequest ; request condition so the computer polls it
movf FSR0L,W ;If the keyboard queue is empty, we have no
xorwf FSR1L,W ; data, so bail
btfsc STATUS,Z ; "
bra Main ; "
moviw FSR1++ ;Pop the next keyboard code off the queue
bcf FSR1L,7 ; "
movwf ADB_BUF ;Copy it into the ADB buffer
clrf ADB_BUF2 ;Put the customary 0xFF into the second byte of
decf ADB_BUF2,F ; the ADB buffer
xorlw 0x7F ;If the keyboard code was 0x7F, the reset key,
btfsc STATUS,Z ; we need to put it in both bytes of what we
bcf ADB_BUF2,7 ; send to the computer
xorlw 0x7F ;Update keyboard register 2 according to this
call UpdateKeyboard2 ; key press or release
bsf TX_FLAGS,TX_RDY ;Set up the transmitter flags so we signal that
bcf TX_FLAGS,TX_SIZ2; we're ready to transmit two bytes
bcf TX_FLAGS,TX_SIZ1; "
bsf TX_FLAGS,TX_SIZ0; "
bra Main
KeyboardTalk2
movlb 1 ;Move the contents of keyboard register 2 into
movf KBD_2_H,W ; the ADB buffer and signal the transmitter
movwf ADB_BUF ; that we're ready to transmit two bytes
bsf TX_FLAGS,TX_RDY ; "
bcf TX_FLAGS,TX_SIZ2; "
bcf TX_FLAGS,TX_SIZ1; "
bsf TX_FLAGS,TX_SIZ0; "
movf KBD_2_L,W ; "
movwf ADB_BUF2 ; "
bra Main
KeyboardTalk3
movlb 1 ;Move the high byte of keyboard register 3 into
movf KBD_3_H,W ; the ADB buffer with its low nibble masked off
andlw B'11110000' ; "
movwf ADB_BUF ; "
movlb 0 ;Get a pseudorandom four-bit number and put it
movf TMR1H,W ; into the low nibble of the ADB buffer; this
xorwf TMR1L,W ; way we replace address (which the host
andlw B'00001111' ; already knows) with a random number, which
iorwf ADB_BUF,F ; helps with collision detection
bsf TX_FLAGS,TX_RDY ;Signal the transmitter that we're ready to
bcf TX_FLAGS,TX_SIZ2; transmit two bytes
bcf TX_FLAGS,TX_SIZ1; "
bsf TX_FLAGS,TX_SIZ0; "
movlb 1 ;Move the low byte of keyboard register 3 into
movf KBD_3_L,W ; the ADB buffer
movwf ADB_BUF2 ; "
bra Main
MouseTalk
movf ADB_CMD,W ;If this is a talk register 0, handle that
andlw B'00000011' ; "
btfsc STATUS,Z ; "
bra MouseTalk0 ; "
addlw -1 ;If this is a talk register 1, we have no
btfsc STATUS,Z ; handler for that, so done
bra Main ; "
addlw -1 ;If this is a talk register 2, we have no
btfsc STATUS,Z ; handler for that, so done
bra Main ; "
bra MouseTalk3 ;Else it's a talk register 3, handle that
Main
movlb 0
btfsc PIR1,RCIF
bra GotUartByte
btfsc RX_FLAGS,RX_RST
bra GotReset
btfsc RX_FLAGS,RX_CMD
bra GotCmd
btfsc RX_FLAGS,RX_DATA
bra GotData
btfsc RX_FLAGS,RX_ABRT
bcf RX_FLAGS,RX_ABRT
btfsc TX_FLAGS,TX_COL
bra GotCollision
bra Main
MouseTalk0
movf FSR0L,W ;If the keyboard queue is not empty, we have
xorwf FSR1L,W ; data for the keyboard, so effect a service
btfss STATUS,Z ; request so the computer knows to poll the
call ServiceRequest ; keyboard
btfss DV_FLAGS,DV_MSES;If the mouse doesn't need service, we're done
bra Main ; "
bcf DV_FLAGS,DV_MSES;Clear the mouse-needs-service flag
MT0Y movlb 1 ;We handle the Y delta differently depending on
btfsc MSE_DYH,7 ; whether it's negative or positive
bra MT0YNeg ; "
MT0YPos movlw 0xC1 ;If it's positive, subtract 63 from it
addwf MSE_DYL,F ; "
movlw 0xFF ; "
addwfc MSE_DYH,F ; "
btfsc STATUS,C ;If it didn't borrow, leave the difference,
bra MT0YPMo ; it's more than we can convey in one delta
movlw B'00111111' ;If it borrowed, add 63 to the difference and
addwf MSE_DYL,W ; that's our final delta
movwf ADB_BUF ; "
clrf MSE_DYH ; "
clrf MSE_DYL ; "
bra MT0X ;Go to handle the X delta
MT0YPMo movlw B'00111111' ;If it didn't borrow, send the delta 63 and
movwf ADB_BUF ; signal that we need to be serviced again to
bsf DV_FLAGS,DV_MSES; convey the rest of it
bra MT0X ;Go to handle the X delta
MT0YNeg movlw 0x40 ;If it's negative, add 64 to it
addwf MSE_DYL,F ; "
movlw 0 ; "
addwfc MSE_DYH,F ; "
btfss STATUS,C ;If it didn't overflow, leave the sum, it's
bra MT0YNMo ; more than we can convey in one delta
movlw B'01000000' ;If it overflowed, add -64 to the sum and
addwf MSE_DYL,W ; that's our final delta
movwf ADB_BUF ; "
clrf MSE_DYL ; "
bra MT0X ;Go to handle the X delta
MT0YNMo movlw B'01000000' ;If it didn't overflow, send the delta -64 and
movwf ADB_BUF ; signal that we need to be serviced again to
bsf DV_FLAGS,DV_MSES; convey the rest of it
MT0X btfsc MSE_DXH,7 ;We handle the X delta differently depending on
bra MT0XNeg ; whether it's negative or positive
MT0XPos movlw 0xC1 ;If it's positive, subtract 63 from it
addwf MSE_DXL,F ; "
movlw 0xFF ; "
addwfc MSE_DXH,F ; "
btfsc STATUS,C ;If it didn't borrow, leave the difference,
bra MT0XPMo ; it's more than we can convey in one delta
movlw B'00111111' ;If it borrowed, add 63 to the difference and
addwf MSE_DXL,W ; that's our final delta
movwf ADB_BUF2 ; "
clrf MSE_DXH ; "
clrf MSE_DXL ; "
bra MT0Btns ;Go to handle the X delta
MT0XPMo movlw B'00111111' ;If it didn't borrow, send the delta 63 and
movwf ADB_BUF2 ; signal that we need to be serviced again to
bsf DV_FLAGS,DV_MSES; convey the rest of it
bra MT0Btns ;Go to handle the X delta
MT0XNeg movlw 0x40 ;If it's negative, add 64 to it
addwf MSE_DXL,F ; "
movlw 0 ; "
addwfc MSE_DXH,F ; "
btfss STATUS,C ;If it didn't overflow, leave the sum, it's
bra MT0XNMo ; more than we can convey in one delta
movlw B'01000000' ;If it overflowed, add -64 to the sum and
addwf MSE_DXL,W ; that's our final delta
movwf ADB_BUF2 ; "
clrf MSE_DXL ; "
bra MT0Btns ;Go to handle the X delta
MT0XNMo movlw B'01000000' ;If it didn't overflow, send the delta -64 and
movwf ADB_BUF2 ; signal that we need to be serviced again to
bsf DV_FLAGS,DV_MSES; convey the rest of it
MT0Btns btfsc MSE_BTN,0 ;Copy the mouse button bits
bsf ADB_BUF,7 ; "
btfsc MSE_BTN,1 ; "
bsf ADB_BUF2,7 ; "
bsf TX_FLAGS,TX_RDY ;Signal the transmitter that we're ready to
bcf TX_FLAGS,TX_SIZ2; transmit two bytes
bcf TX_FLAGS,TX_SIZ1; "
bsf TX_FLAGS,TX_SIZ0; "
movlw B'11111111' ;Overwrite the mouse button bits with ones so
movwf MSE_BTN ; the mouse buttons can be released
bra Main
MouseTalk3
movlb 1 ;Move the high byte of mouse register 3 into
movf MSE_3_H,W ; the ADB buffer with its low nibble masked off
andlw B'11110000' ; "
movwf ADB_BUF ; "
movlb 0 ;Get a pseudorandom four-bit number and put it
movf TMR1H,W ; into the low nibble of the ADB buffer; this
xorwf TMR1L,W ; way we replace address (which the host
andlw B'00001111' ; already knows) with a random number, which
iorwf ADB_BUF,F ; helps with collision detection
bsf TX_FLAGS,TX_RDY ;Signal the transmitter that we're ready to
bcf TX_FLAGS,TX_SIZ2; transmit two bytes
bcf TX_FLAGS,TX_SIZ1; "
bsf TX_FLAGS,TX_SIZ0; "
movlb 1 ;Move the low byte of mouse register 3 into the
movf MSE_3_L,W ; ADB buffer
movwf ADB_BUF2 ; "
bra Main
GotData
bcf RX_FLAGS,RX_DATA;Clear the data flag
movf ADB_CMD,W ;If bits 3-2 of the command are 0b10, this is
andlw B'00001100' ; a listen command and we've now got the data
xorlw B'00001000' ; for it; it should be if we're here, but check
btfss STATUS,Z ; just in case
bra Main ; "
movlb 1 ;Compare the address of the listen command with
swapf ADB_CMD,W ; the stored address for the keyboard; if they
xorwf KBD_3_H,W ; match, this is a talk command for the
andlw B'00001111' ; keyboard
btfsc STATUS,Z ; "
bra KeyboardListen ; "
swapf ADB_CMD,W ;Compare the address of the listen command with
xorwf MSE_3_H,W ; the stored address for the mouse; if they
andlw B'00001111' ; match, this is a talk command for the mouse
btfsc STATUS,Z ; "
bra MouseListen ; "
bra Main ;Else, this is not for one of our devices
KeyboardListen
movf ADB_CMD,W ;We only care about listen commands for
andlw B'00000011' ; register 3, so if this isn't one of those,
xorlw B'00000011' ; we're done
btfss STATUS,Z ; "
bra Main ; "
movf ADB_BUF2,W ;If the low byte of the listen register 3 data
btfsc STATUS,Z ; is 0x00, handle this
bra KeyboardL3_00 ; "
addlw 2 ;If the low byte of the listen register 3 data
btfsc STATUS,Z ; is 0xFE, handle this
bra KeyboardL3_FE ; "
addlw 251 ;If the low byte of the listen register 3 data
btfsc STATUS,Z ; is 0x02 or 0x03, these are handler IDs that
bra KeyboardL3ChgH ; we (as an extended keyboard) understand, so
addlw 1 ; change our handler ID accordingly
btfsc STATUS,Z ; "
bra KeyboardL3ChgH ; "
bra Main
KeyboardL3_00
movf ADB_BUF,W ;Change the address and flags in register 3
movlb 1 ; according to the first (high) data byte
movwf KBD_3_H ; "
bra Main
KeyboardL3_FE
btfsc DV_FLAGS,DV_KBDC;If there was a collision, do not change the
bra KL3FENo ; address
movlw B'00001111' ;Snuff the top nibble of the first data byte,
andwf ADB_BUF,F ; we don't care about those bits
movlb 1 ;Copy the address from the first (high) data
movf KBD_3_H,W ; byte into keyboard register 3
andlw B'11110000' ; "
iorwf ADB_BUF,W ; "
movwf KBD_3_H ; "
KL3FENo bcf DV_FLAGS,DV_KBDC;Clear the collision flag if it was set
bra Main
KeyboardL3ChgH
movf ADB_BUF2,W ;Change our handler ID (the low byte of
movlb 1 ; register 3) to the byte given in the listen
movwf KBD_3_L ; register 3 command
bra Main
MouseListen
movf ADB_CMD,W ;We only care about listen commands for
andlw B'00000011' ; register 3, so if this isn't one of those,
xorlw B'00000011' ; we're done
btfss STATUS,Z ; "
bra Main ; "
movf ADB_BUF2,W ;If the low byte of the listen register 3 data
btfsc STATUS,Z ; is 0x00, handle this
bra MouseL3_00 ; "
addlw 2 ;If the low byte of the listen register 3 data
btfsc STATUS,Z ; is 0xFE, handle this
bra MouseL3_FE ; "
bra Main
MouseL3_00
movf ADB_BUF,W ;Change the address and flags in register 3
movlb 1 ; according to the first (high) data byte
movwf MSE_3_H ; "
bra Main
MouseL3_FE
btfsc DV_FLAGS,DV_MSEC;If there was a collision, do not change the
bra ML3FENo ; address
movlw B'00001111' ;Snuff the top nibble of the first data byte,
andwf ADB_BUF,F ; we don't care about those bits
movlb 1 ;Copy the address from the first (high) data
movf MSE_3_H,W ; byte into keyboard register 3
andlw B'11110000' ; "
iorwf ADB_BUF,W ; "
movwf MSE_3_H ; "
ML3FENo bcf DV_FLAGS,DV_MSEC;Clear the collision flag if it was set
bra Main
GotCollision
bcf TX_FLAGS,TX_COL ;Clear the collision flag
movlb 1 ;Compare the address of the last command with
swapf ADB_CMD,W ; the stored address for the keyboard; if they
xorwf KBD_3_H,W ; match, this is a collision on the keyboard's
andlw B'00001111' ; address
btfsc STATUS,Z ; "
bsf DV_FLAGS,DV_KBDC; "
swapf ADB_CMD,W ;Compare the address of the last command with
xorwf MSE_3_H,W ; the stored address for the mouse; if they
andlw B'00001111' ; match, this is a collision on the mouse's
btfsc STATUS,Z ; address
bsf DV_FLAGS,DV_MSEC; "
goto Main
;;; Subprograms ;;;
ServiceRequest
movlb 0 ;Set Timer0 to overflow after 300 us, the
movlw -75 ; nominal service request time
movwf TMR0 ; "
bsf RX_FLAGS,SRQ_ON ;Signal that we're making a service request
bcf INTCON,TMR0IF ;Enable the Timer0 interrupt so we end the
bsf INTCON,TMR0IE ; service request after the timer overflows
movlb 1 ;Pull the ADB line low
movlw B'11011111' ; "
andwf TRISA,F ; "
return
UpdateKeyboard2
btfsc WREG,7 ;If MSB is set, a key has been released, else
bra Update2KeyUp ; one has been pressed
;fall through
Update2KeyDown
addlw -51 ;0x33 Delete/Backspace
btfsc STATUS,Z ; if keycode matches,
bcf KBD_2_H,K2H_DEL ; mark key as down
addlw -3 ;0x36 LeftControl
btfsc STATUS,Z ; if keycode matches,
bcf KBD_MODS,KMD_LCT; mark key as down
addlw -1 ;0x37 Command
btfsc STATUS,Z ; if keycode matches,
bcf KBD_2_H,K2H_CMD ; mark key as down
addlw -1 ;0x38 LeftShift
btfsc STATUS,Z ; if keycode matches,
bcf KBD_MODS,KMD_LSH; mark key as down
addlw -1 ;0x39 CapsLock
btfsc STATUS,Z ; if keycode matches,
bcf KBD_2_H,K2H_CAP ; mark key as down
addlw -1 ;0x3A LeftOption
btfsc STATUS,Z ; if keycode matches,
bcf KBD_MODS,KMD_LOP; mark key as down
addlw -13 ;0x47 Clear/NumLock
btfsc STATUS,Z ; if keycode matches,
bcf KBD_2_L,K2L_CLR ; mark key as down
addlw -36 ;0x6B F14/ScrollLock
btfsc STATUS,Z ; if keycode matches,
bcf KBD_2_L,K2L_SLK ; mark key as down
addlw -16 ;0x7B RightShift
btfsc STATUS,Z ; if keycode matches,
bcf KBD_MODS,KMD_RSH; mark key as down
addlw -1 ;0x7C RightOption
btfsc STATUS,Z ; if keycode matches,
bcf KBD_MODS,KMD_ROP; mark key as down
addlw -1 ;0x7D RightControl
btfsc STATUS,Z ; if keycode matches,
bcf KBD_MODS,KMD_RCT; mark key as down
addlw -2 ;0x7F Reset
btfsc STATUS,Z ; if keycode matches,
bcf KBD_2_H,K2H_RST ; mark key as down
bra Update2Mods
Update2KeyUp
andlw B'01111111' ;Clear MSB so we can check released key's code
addlw -51 ;0x33 Delete/Backspace
btfsc STATUS,Z ; if keycode matches,
bsf KBD_2_H,K2H_DEL ; mark key as up
addlw -3 ;0x36 LeftControl
btfsc STATUS,Z ; if keycode matches,
bsf KBD_MODS,KMD_LCT; mark key as up
addlw -1 ;0x37 Command
btfsc STATUS,Z ; if keycode matches,
bsf KBD_2_H,K2H_CMD ; mark key as up
addlw -1 ;0x38 LeftShift
btfsc STATUS,Z ; if keycode matches,
bsf KBD_MODS,KMD_LSH; mark key as up
addlw -1 ;0x39 CapsLock
btfsc STATUS,Z ; if keycode matches,
bsf KBD_2_H,K2H_CAP ; mark key as up
addlw -1 ;0x3A LeftOption
btfsc STATUS,Z ; if keycode matches,
bsf KBD_MODS,KMD_LOP; mark key as up
addlw -13 ;0x47 Clear/NumLock
btfsc STATUS,Z ; if keycode matches,
bsf KBD_2_L,K2L_CLR ; mark key as up
addlw -36 ;0x6B F14/ScrollLock
btfsc STATUS,Z ; if keycode matches,
bsf KBD_2_L,K2L_SLK ; mark key as up
addlw -16 ;0x7B RightShift
btfsc STATUS,Z ; if keycode matches,
bsf KBD_MODS,KMD_RSH; mark key as up
addlw -1 ;0x7C RightOption
btfsc STATUS,Z ; if keycode matches,
bsf KBD_MODS,KMD_ROP; mark key as up
addlw -1 ;0x7D RightControl
btfsc STATUS,Z ; if keycode matches,
bsf KBD_MODS,KMD_RCT; mark key as up
addlw -2 ;0x7F Reset
btfsc STATUS,Z ; if keycode matches,
bsf KBD_2_H,K2H_RST ; mark key as up
;fall through
Update2Mods
bsf KBD_2_H,K2H_CTL ;If either control key is down, reflect that in
btfsc KBD_MODS,KMD_LCT; the appropriate bits in keyboard register 2
btfss KBD_MODS,KMD_RCT; "
bcf KBD_2_H,K2H_CTL ; "
bsf KBD_2_H,K2H_SHF ;If either shift key is down, reflect that in
btfsc KBD_MODS,KMD_LSH; the appropriate bits in keyboard register 2
btfss KBD_MODS,KMD_RSH; "
bcf KBD_2_H,K2H_SHF ; "
bsf KBD_2_H,K2H_OPT ;If either option key is down, reflect that in
btfsc KBD_MODS,KMD_LOP; the appropriate bits in keyboard register 2
btfss KBD_MODS,KMD_ROP; "
bcf KBD_2_H,K2H_OPT ; "
return
;;; State Machines ;;;
TxFsa org 0x900
TStartU movlw PULSE_DNS
movwf TMR0
retlw low TStartD
TStartD movlw PULSE_UPL
movwf TMR0
retlw low TData7D
TData7D movlw PULSE_DNL
btfsc ADB_BUF,7
movlw PULSE_DNS
movwf TMR0
retlw low TData7U
TData7U movlw PULSE_UPS
btfsc ADB_BUF,7
movlw PULSE_UPL
movwf TMR0
retlw low TData6D
TData6D movlw PULSE_DNL
btfsc ADB_BUF,6
movlw PULSE_DNS
movwf TMR0
retlw low TData6U
TData6U movlw PULSE_UPS
btfsc ADB_BUF,6
movlw PULSE_UPL
movwf TMR0
retlw low TData5D
TData5D movlw PULSE_DNL
btfsc ADB_BUF,5
movlw PULSE_DNS
movwf TMR0
retlw low TData5U
TData5U movlw PULSE_UPS
btfsc ADB_BUF,5
movlw PULSE_UPL
movwf TMR0
retlw low TData4D
TData4D movlw PULSE_DNL
btfsc ADB_BUF,4
movlw PULSE_DNS
movwf TMR0
retlw low TData4U
TData4U movlw PULSE_UPS
btfsc ADB_BUF,4
movlw PULSE_UPL
movwf TMR0
retlw low TData3D
TData3D movlw PULSE_DNL
btfsc ADB_BUF,3
movlw PULSE_DNS
movwf TMR0
retlw low TData3U
TData3U movlw PULSE_UPS
btfsc ADB_BUF,3
movlw PULSE_UPL
movwf TMR0
retlw low TData2D
TData2D movlw PULSE_DNL
btfsc ADB_BUF,2
movlw PULSE_DNS
movwf TMR0
retlw low TData2U
TData2U movlw PULSE_UPS
btfsc ADB_BUF,2
movlw PULSE_UPL
movwf TMR0
retlw low TData1D
TData1D movlw PULSE_DNL
btfsc ADB_BUF,1
movlw PULSE_DNS
movwf TMR0
retlw low TData1U
TData1U movlw PULSE_UPS
btfsc ADB_BUF,1
movlw PULSE_UPL
movwf TMR0
retlw low TData0D
TData0D movlw PULSE_DNL
btfsc ADB_BUF,0
movlw PULSE_DNS
movwf TMR0
retlw low TData0U
TData0U movlw PULSE_UPS
btfsc ADB_BUF,0
movlw PULSE_UPL
movwf TMR0
movf ADB_BUF2,W ;Rotate the next byte into position, if there
movwf ADB_BUF ; is one
movf ADB_BUF3,W ; "
movwf ADB_BUF2 ; "
movf ADB_BUF4,W ; "
movwf ADB_BUF3 ; "
movf ADB_BUF5,W ; "
movwf ADB_BUF4 ; "
movf ADB_BUF6,W ; "
movwf ADB_BUF5 ; "
movf ADB_BUF7,W ; "
movwf ADB_BUF6 ; "
movf ADB_BUF8,W ; "
movwf ADB_BUF7 ; "
movf TX_FLAGS,W ;If the counter in the three least significant
andlw B'00000111' ; bits of TX_FLAGS has hit zero, next move is
btfsc STATUS,Z ; to send a stop bit
retlw low TStopD ; "
decf TX_FLAGS,F ;Otherwise, decrement the counter and send
retlw low TData7D ; another byte
TStopD movlw PULSE_DNL
movwf TMR0
retlw low TStopU
TStopU bcf TX_FLAGS,TX_ON ;Reset everything into receiver mode
movlb 7 ; "
movlw B'00100000' ; "
movwf IOCAN ; "
clrf IOCAP ; "
clrf IOCAF ; "
clrf RX_TDOWN ; "
movlw B'00001000' ; "
movwf INTCON ; "
retlw low TStartU
RxFsa0 org 0xA00
R0idle retlw low R0idle
nop
R0cmd7 bcf ADB_CMD,7
retlw low R0cmd6
R0cmd6 bcf ADB_CMD,6
retlw low R0cmd5
R0cmd5 bcf ADB_CMD,5
retlw low R0cmd4
R0cmd4 bcf ADB_CMD,4
retlw low R0cmd3
R0cmd3 bcf ADB_CMD,3
retlw low R0cmd2
R0cmd2 bcf ADB_CMD,2
retlw low R0cmd1
R0cmd1 bcf ADB_CMD,1
retlw low R0cmd0
R0cmd0 bcf ADB_CMD,0
bsf RX_FLAGS,RX_CMD
retlw low R0cmdP
R0cmdP retlw low R0dataS
nop
R0dataS retlw low R0idle
nop
nop
R0data7 bcf ADB_BUF8,7
retlw low R0data6
nop
R0data6 bcf ADB_BUF8,6
retlw low R0data5
nop
R0data5 bcf ADB_BUF8,5
retlw low R0data4
nop
R0data4 bcf ADB_BUF8,4
retlw low R0data3
nop
R0data3 bcf ADB_BUF8,3
retlw low R0data2
nop
R0data2 bcf ADB_BUF8,2
retlw low R0data1
nop
R0data1 bcf ADB_BUF8,1
retlw low R0data0
nop
R0data0 bcf ADB_BUF8,0
movf ADB_BUF8,W
R0stxxx btfsc RX_FLAGS,RX_SIZ2
bra R0st1xx
R0st0xx btfsc RX_FLAGS,RX_SIZ1
bra R0st01x
R0st00x btfsc RX_FLAGS,RX_SIZ0
bra R0st001
R0st000 movwf ADB_BUF
retlw low R0dataN
R0st001 movwf ADB_BUF2
retlw low R0dataN
R0st01x btfsc RX_FLAGS,RX_SIZ0
bra R0st011
R0st010 movwf ADB_BUF3
retlw low R0dataN
R0st011 movwf ADB_BUF4
retlw low R0dataN
R0st1xx btfsc RX_FLAGS,RX_SIZ1
bra R0st11x
R0st10x btfsc RX_FLAGS,RX_SIZ0
bra R0st101
R0st100 movwf ADB_BUF5
retlw low R0dataN
R0st101 movwf ADB_BUF6
retlw low R0dataN
R0st11x btfsc RX_FLAGS,RX_SIZ0
bra R0st111
R0st110 movwf ADB_BUF7
retlw low R0dataN
R0st111 bsf RX_FLAGS,RX_DATA
retlw low R0idle
R0dataN incf RX_FLAGS,F
bcf ADB_BUF8,7
retlw low R0data6
RxFsa1 org 0xB00
R1idle retlw low R1idle
nop
R1cmd7 bsf ADB_CMD,7
retlw low R1cmd6
R1cmd6 bsf ADB_CMD,6
retlw low R1cmd5
R1cmd5 bsf ADB_CMD,5
retlw low R1cmd4
R1cmd4 bsf ADB_CMD,4
retlw low R1cmd3
R1cmd3 bsf ADB_CMD,3
retlw low R1cmd2
R1cmd2 bsf ADB_CMD,2
retlw low R1cmd1
R1cmd1 bsf ADB_CMD,1
retlw low R1cmd0
R1cmd0 bsf ADB_CMD,0
bsf RX_FLAGS,RX_CMD
retlw low R1cmdP
R1cmdP retlw low R1idle
nop
R1dataS movlw B'11111000'
andwf RX_FLAGS,F
retlw low R1data7
R1data7 bsf ADB_BUF8,7
retlw low R1data6
nop
R1data6 bsf ADB_BUF8,6
retlw low R1data5
nop
R1data5 bsf ADB_BUF8,5
retlw low R1data4
nop
R1data4 bsf ADB_BUF8,4
retlw low R1data3
nop
R1data3 bsf ADB_BUF8,3
retlw low R1data2
nop
R1data2 bsf ADB_BUF8,2
retlw low R1data1
nop
R1data1 bsf ADB_BUF8,1
retlw low R1data0
nop
R1data0 bsf ADB_BUF8,0
movf ADB_BUF8,W
R1stxxx btfsc RX_FLAGS,RX_SIZ2
bra R1st1xx
R1st0xx btfsc RX_FLAGS,RX_SIZ1
bra R1st01x
R1st00x btfsc RX_FLAGS,RX_SIZ0
bra R1st001
R1st000 movwf ADB_BUF
retlw low R1dataN
R1st001 movwf ADB_BUF2
retlw low R1dataN
R1st01x btfsc RX_FLAGS,RX_SIZ0
bra R1st011
R1st010 movwf ADB_BUF3
retlw low R1dataN
R1st011 movwf ADB_BUF4
retlw low R1dataN
R1st1xx btfsc RX_FLAGS,RX_SIZ1
bra R1st11x
R1st10x btfsc RX_FLAGS,RX_SIZ0
bra R1st101
R1st100 movwf ADB_BUF5
retlw low R1dataN
R1st101 movwf ADB_BUF6
retlw low R1dataN
R1st11x btfsc RX_FLAGS,RX_SIZ0
bra R1st111
R1st110 movwf ADB_BUF7
retlw low R1dataN
R1st111 bsf RX_FLAGS,RX_DATA
retlw low R1idle
R1dataN incf RX_FLAGS,F
bsf ADB_BUF8,7
retlw low R1data6
RxFsaA org 0xC00
RAidle retlw low RAcmd7
nop
RAcmd7 retlw low RAcmd7
nop
RAcmd6 retlw low RAcmd7
nop
RAcmd5 retlw low RAcmd7
nop
RAcmd4 retlw low RAcmd7
nop
RAcmd3 retlw low RAcmd7
nop
RAcmd2 retlw low RAcmd7
nop
RAcmd1 retlw low RAcmd7
nop
RAcmd0 retlw low RAcmd7
nop
nop
RAcmdP retlw low RAcmd7
nop
RAdataS retlw low RAcmd7
nop
nop
RAdata7 bsf RX_FLAGS,RX_ABRT
retlw low RAcmd7
nop
RAdata6 bsf RX_FLAGS,RX_ABRT
retlw low RAcmd7
nop
RAdata5 bsf RX_FLAGS,RX_ABRT
retlw low RAcmd7
nop
RAdata4 bsf RX_FLAGS,RX_ABRT
retlw low RAcmd7
nop
RAdata3 bsf RX_FLAGS,RX_ABRT
retlw low RAcmd7
nop
RAdata2 bsf RX_FLAGS,RX_ABRT
retlw low RAcmd7
nop
RAdata1 bsf RX_FLAGS,RX_ABRT
retlw low RAcmd7
nop
RAdata0 bsf RX_FLAGS,RX_ABRT
retlw low RAcmd7
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
RAdataN bsf RX_FLAGS,RX_ABRT
retlw low RAcmd7
nop
RxFsaS org 0xD00
RSidle retlw low RSidle
nop
RScmd7 retlw low RSidle
nop
RScmd6 retlw low RSidle
nop
RScmd5 retlw low RSidle
nop
RScmd4 retlw low RSidle
nop
RScmd3 retlw low RSidle
nop
RScmd2 retlw low RSidle
nop
RScmd1 retlw low RSidle
nop
RScmd0 retlw low RSidle
nop
nop
RScmdP retlw low RSdataS
nop
RSdataS retlw low RSidle
nop
nop
RSdata7 bsf RX_FLAGS,RX_ABRT
retlw low RSidle
nop
RSdata6 bsf RX_FLAGS,RX_ABRT
retlw low RSidle
nop
RSdata5 bsf RX_FLAGS,RX_ABRT
retlw low RSidle
nop
RSdata4 bsf RX_FLAGS,RX_ABRT
retlw low RSidle
nop
RSdata3 bsf RX_FLAGS,RX_ABRT
retlw low RSidle
nop
RSdata2 bsf RX_FLAGS,RX_ABRT
retlw low RSidle
nop
RSdata1 bsf RX_FLAGS,RX_ABRT
retlw low RSidle
nop
RSdata0 bsf RX_FLAGS,RX_ABRT
retlw low RSidle
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
RSdataN bsf RX_FLAGS,RX_ABRT
retlw low RSidle
nop
RxFsaR org 0xE00
RRidle bsf RX_FLAGS,RX_RST
retlw low RRidle
RRcmd7 bsf RX_FLAGS,RX_RST
retlw low RRidle
RRcmd6 bsf RX_FLAGS,RX_RST
retlw low RRidle
RRcmd5 bsf RX_FLAGS,RX_RST
retlw low RRidle
RRcmd4 bsf RX_FLAGS,RX_RST
retlw low RRidle
RRcmd3 bsf RX_FLAGS,RX_RST
retlw low RRidle
RRcmd2 bsf RX_FLAGS,RX_RST
retlw low RRidle
RRcmd1 bsf RX_FLAGS,RX_RST
retlw low RRidle
RRcmd0 bsf RX_FLAGS,RX_RST
retlw low RRidle
nop
RRcmdP bsf RX_FLAGS,RX_RST
retlw low RRidle
RRdataS bsf RX_FLAGS,RX_RST
retlw low RRidle
nop
RRdata7 bsf RX_FLAGS,RX_ABRT
bsf RX_FLAGS,RX_RST
retlw low RRidle
RRdata6 bsf RX_FLAGS,RX_ABRT
bsf RX_FLAGS,RX_RST
retlw low RRidle
RRdata5 bsf RX_FLAGS,RX_ABRT
bsf RX_FLAGS,RX_RST
retlw low RRidle
RRdata4 bsf RX_FLAGS,RX_ABRT
bsf RX_FLAGS,RX_RST
retlw low RRidle
RRdata3 bsf RX_FLAGS,RX_ABRT
bsf RX_FLAGS,RX_RST
retlw low RRidle
RRdata2 bsf RX_FLAGS,RX_ABRT
bsf RX_FLAGS,RX_RST
retlw low RRidle
RRdata1 bsf RX_FLAGS,RX_ABRT
bsf RX_FLAGS,RX_RST
retlw low RRidle
RRdata0 bsf RX_FLAGS,RX_ABRT
bsf RX_FLAGS,RX_RST
retlw low RRidle
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
RRdataN bsf RX_FLAGS,RX_ABRT
bsf RX_FLAGS,RX_RST
retlw low RRidle
RxFsaT org 0xF00
RTidle retlw low RTidle
nop
RTcmd7 retlw low RTidle
nop
RTcmd6 retlw low RTidle
nop
RTcmd5 retlw low RTidle
nop
RTcmd4 retlw low RTidle
nop
RTcmd3 retlw low RTidle
nop
RTcmd2 retlw low RTidle
nop
RTcmd1 retlw low RTidle
nop
RTcmd0 retlw low RTidle
nop
nop
RTcmdP retlw low RTcmdP ;A timeout during 'Tlt' is not a timeout
nop
RTdataS retlw low RTidle
nop
nop
RTdata7 bsf RX_FLAGS,RX_ABRT
retlw low RTidle
nop
RTdata6 bsf RX_FLAGS,RX_ABRT
retlw low RTidle
nop
RTdata5 bsf RX_FLAGS,RX_ABRT
retlw low RTidle
nop
RTdata4 bsf RX_FLAGS,RX_ABRT
retlw low RTidle
nop
RTdata3 bsf RX_FLAGS,RX_ABRT
retlw low RTidle
nop
RTdata2 bsf RX_FLAGS,RX_ABRT
retlw low RTidle
nop
RTdata1 bsf RX_FLAGS,RX_ABRT
retlw low RTidle
nop
RTdata0 bsf RX_FLAGS,RX_ABRT
retlw low RTidle
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
RTdataN bsf RX_FLAGS,RX_DATA
retlw low RTidle
nop
;;; End of Program ;;;
end