Ken's computer

D:\PROJECTS\TIMEMON\SERMUX\SERMUX_M.ASM


;-----------------------------------------------------------------------------------------------------
; Serial port multiplexer
; Main processor
;
; This is the PIC16C74 which is connected to the SRAM as well as all the other (slave) processors.
; It is responsible for reading and writing from/to the other processors, buffering data in the
; SRAM, and packaging and unpackaging data to/from routing packets.
;
; Code developed 04/22/98 through 08/09/98
;
;
;****************************************************************************************************
;  Overview:
;****************************************************************************************************
;
; The serial port multipler board is used to allow one RS-232 port on a PC to be shared among 7
; devices requiring simple (no handshake) serial I/O.  Any of these 7 devices may themselves be
; another (cascaded) multiplexer board.
;
;****************************************************************************************************
;  Packets:
;****************************************************************************************************
;
; All data sent to or from the PC is wrapped in packets which facilitate routing and data integrity
; verification.  Packets contain the following components:
;
; 1). Prefix
;     The prefix provides a means by which the receive logic can be easily synchronized
;     with the packet transmission phase.  It also identifies the type of packet.
;
; 2). Header
;     The header contains routing and/or sequencing information.
;
; 3). Body
;     The body contains the data itself.
;
; 4). Suffix
;     The suffix contains checksums used to verify the integrity of the data in the header and body.
;
; Note that some types of packet may lack a header, body, or suffix.
;
;
;
;------------------------------------------------------------------------------------------------------
; Nomenclature for "Data packets": (next topic below this one)
;
; When elements of a packet are listed or when elements of a component of a packet are listed,
; the items occuring closer to the top of the page are sent/received first.
;
; <byte>
;    An 8-bit (single character) value
;
; <word>
;    A 16-bit (2 character) value with the following components:
;       <byte> least-significant byte (bits 0..7 of the word, sent/received first)
;       <byte> most-significant byte (bits 8..15 of the word, sent/received last)
;
;
;
;------------------------------------------------------------------------------------------------------
; Data Packets:
;
;     Data packets may be sent to or from the PC.  They contain data which came from or
;     will be sent to one of the slave ports or the control channel (this MCU's command
;     interpreter).
;
;     Data packets may be streamed out back-to-back and are not acknowledged.  If the
;     checksum fails, the data packet is simply ignored.  Lost data packets are detected by
;     checking the serial number of each packet.
;
;
;     a). Prefix = @P
;
;         The prefix consists of the 'at' character (0x40) followed by an uppercase 'P'.
;         All packet prefixes consist of the '@' followed by one or more letters.
;
;
;     b). Header:
;
;         <byte> address/length
;
;                Bits 0..4 specify the length:
;                   Values 0..31 specify 1..32 bytes
;
;                Bits 5..7 specify the address:
;                   Values 0..6 specify slave ports 0..6 (labeled Aux1..Aux7 on the board)
;                   The value 7 specifies the control channel (messages sent to/from this MCU)
;
;         <word> serial number
;
;                The serial number is used to identify each packet.  It starts at an arbitrary
;                number then increases in value by 1 for each subsequent packet sent over the
;                RS232 connection to/from the PC.
;
;
;     c). Body
;
;         The body contains the data (1 to 32 bytes, as specified in the header).
;
;         The data bytes themselves are modified via the following algorithm: (using C syntax)
;               output_byte = input_byte ^ (cyclic_checksum & 0xff);
;               apply_to_checksums( input_byte );
;
;         To restore the data to its original value:
;               input_byte = output_byte ^ (cyclic_checksum & 0xff);
;               apply_to_checksums( input_byte );
;
;         This modification of the data is done to prevent packets being sent to cascaded
;         multiplexers from being misinterpreted as packets destined for this multiplexer if the
;         receive logic gets out of phase.
;
;
;     d). Suffix
;
;         <byte> plain checksum of header and pre-modified body
;
;         <word> cyclic checksum of header and pre-modified body
;                The cyclic checksum algorithm is difficult to explain in words but the code
;                speaks for itself (see the code for details).
;
;
;     The length of a data packet ranges from 9 to 40 bytes
;
;
;
;****************************************************************************************************
;  Data flow:
;****************************************************************************************************
;
;    PC --> IRQ --> Rx_pipe --> Rx_input() # --> Receive_Buffer[address] --> Service_slave() * --> slave port
;    slave port --> Service_slave() ** --> Transmit_Buffer --> Tx_output() ## --> Tx_pipe --> IRQ --> PC
;
;       * = packet extracted
;       # = prefix and checksum examined and stripped
;      ** = packet encoded
;      ## = prefix and checksum generated
;
;
;------------------------------------------------------------------------------------------------------
; Data flow from PC to slave port:
;
;
; 1). PC transmits packet addressed to a slave port
;
; 2). IRQ handler buffers data in Rx_pipe
;
; 3). Rx_input() checks and discards the packet prefix ("@P") and header and moves the contents
;         of the packet from Rx_pipe to Receive_Buffer for the addressed slave
;     If the checksum fails or Receive_Buffer is full then the packet is discarded
;
; 4). Service_slave() spools the contents of the packet off to the slave port
;
;
;------------------------------------------------------------------------------------------------------
; Data flow from slave port to PC:
;
;
; 1). Service_slave() transfers data from the slave processor to a new packet and puts the packet in Transmit_Buffer
;     The packet is encoded (except for "@P" prefix and checksums which are generated later)
;     Bandwidth useage is optimized by not beginning a packet transfer from a slave processor
;        until a full packet worth of data is available or Transmit_Buffer is close to empty
;
; 2). Tx_output() moves data from Transmit_Buffer to Tx_pipe
;     The "@P" prefix and checksums are added by Tx_output()
;
; 3). IRQ handler writes data from Tx_pipe to the PC port
;
; 4). PC receives packet addressed from a slave port
;
;
;
;
;****************************************************************************************************
;  Data structures:
;****************************************************************************************************
;
; Rx_pipe and Tx_pipe are simple FIFO buffers in register space with one enqueue pointer and
; one dequeue pointer each.
;
; Transmit_Buffer is a 64k FIFO buffer implemented in external SRAM.
;
; There is one 8k Receive_Buffer for each slave port plus one for the control channel.
; The Receive buffers are FIFOs implemented in external SRAM.  Each receive buffer has an
; enqueue pointer and a dequeue pointer.  There is one global tentative enqueue pointer which is
; used to receive each packet.  It is initialized to the value of the enqueue pointer for the
; buffer to which the packet is addressed and then advanced for each character received.  Once an
; entire packet has been received and the checksum verified, the enqueue pointer for the addressed
; buffer is set to the value of the tentative enqueue pointer.
;
;
;
;
;****************************************************************************************************
;  Control channel messages:
;****************************************************************************************************
;
; The control channel is mapped to address 7.  It is written in the same manner as writing to any
; slave port.  Data sent from it arrives in the same manner as data arriving from a slave port.
; Rather than being connected to an external port, however, the control channel is "connected"
; to this MCU's command-interpreter.  The messages the command-interpreter understands and the
; responses it sends are detailed below:
;
;
; 1). Read registers
;
;     "@R" (prefix, 2 bytes)
;
;     <byte> Address/length
;                Bits 0..1 specify the length:
;                   Values 0..3 specify 1..4 bytes
;
;                Bits 2..4 are 0s ... the packet will be ignored if they are non-zero
;
;                Bits 5..7 specify the address:
;                   Values 0..6 specify slave MCUs 0..6 (corresponding to Aux1..Aux7 ports on the board)
;                   The value 7 specifies this MCU
;
;     <byte> Register start address
;                This specifies the first of <length> registers to read
;
;     <byte> plain checksum of Address/length and register start address
;
;     <word> cyclic checksum of Address/length and register start address
;
;
;     Response:
;
;     "@r" (prefix, 2 bytes)
;
;     <byte> plain checksum of Address/length and register start address (from command packet)
;
;     <word> cyclic checksum of Address/length and register start address (from command packet)
;
;     length * <byte> data
;
;     <byte> plain checksum of data
;
;     <word> cyclic checksum of data
;
;
;
; 2). Write registers
;
;     "@W" (prefix, 2 bytes)
;
;     <byte> Address/length
;                Bits 0..1 specify the length:
;                   Values 0..3 specify 1..4 bytes
;
;                Bits 2..4 are 0s ... the packet will be ignored if they are non-zero
;
;                Bits 5..7 specify the address:
;                   Values 0..6 specify slave MCUs 0..6 (corresponding to Aux1..Aux7 ports on the board)
;                   The value 7 specifies this MCU
;
;     <byte> Register start address
;                This specifies the first of <length> registers to write
;
;     length * <byte> data
;
;     <byte> plain checksum of data and header
;
;     <word> cyclic checksum of data and header
;
;
;     Response:
;
;     "@w" (prefix, 2 bytes)
;
;     <byte> plain checksum from command packet
;
;     <word> cyclic checksum from command packet
;
;
;
; Note that up to 4 registers are read and written via a holding buffer which is copied to/from
; register space all at once so that 32-bit words can be read or written with no danger of
; having the value modified by the operating program in between bytes read or written.
;
;
; 3). Change baud rate
;
;     "@B" (prefix, 2 bytes)
;
;     <byte> new TXSTA value XOR'd with 0X6C (causes checksums to fail if this packet is mistaken for "read" packet or vice versa)
;
;     <byte> new SPBRG value XOR'd with 0X35
;
;     <byte> plain checksum of TXSTA and SPBRG (original non-XOR'd values)
;
;     <word> cyclic checksum of TXSTA and SPBRG (original non-XOR'd values)
;
;
;     This command causes all buffers to be flushed prior to writing TXSTA and SPBRG.  It also
;     resets the serial port to clear any error flags.
;
;
;     Response:
;
;     None -- if the command was properly received then the baud rate will be reset and the
;     multiplexer will then respond to commands at the new baud rate.
;
;
;
;
;****************************************************************************************************
;  Slave processor bus operation:
;****************************************************************************************************
;
; The master controls the bus.  It has 8 bits of bidirectional data connected to RB0..7 of each
; slave processor.  It also has the following control lines:
;
;
;  Name       Brief description                                 Driven by       port bit
; -----------------------------------------------------------------------------------
;  CID1       Cycle ID bit 1                                    Master          RA3
;  CID0       Cycle ID bit 0                                    Master          RA2
;  R/W        High for read cycle, Low for write cycle          Master          RA1
;  E          Enable -- active high strobe                      Master          RA0
;  Ack        Acknowledge -- active low, common-drain           Slave           RA4
;
;
; Each slave may either be addressed to respond to normal bus read/write cycles or
; to ignore normal bus cycles.  A special bus cycle is used to address a specific
; slave processor to "listen" or "unlisten" to normal bus cycles.  Only one slave
; processor at a time should be addressed to "listen".
;
;
; All bus cycles (including the special "listen" / "unlisten" one) fall into one
; of two categories:  read cycles or write cycles.  Note that "read" and "write"
; are from the master's point-of-view.
;
; Write cycle timing:
;     1). Master sets up CID1, CID0, and R/W
;     2). Master waits if Ack is being driven low (prior cycle not yet ended by slave)
;     3). Master drives data onto RB0..7
;     4). Master asserts E
;     5). The addressed slave samples RB0..7
;     6). The addressed slave drives Ack low
;     7). The master de-asserts E (and is then free to change any other signal)
;     8). The addressed slave stops driving Ack low
;
; Read cycle timing:
;     1). Master sets up CID1, CID0, and R/W
;     2). Master waits if Ack is being driven low (prior cycle not yet ended by slave)
;     3). Master asserts E
;     4). The addressed slave drives data onto RB0..7
;     5). The addressed slave drives Ack low
;     6). The master samples RB0..7
;     7). The master de-asserts E (and is then free to change any other signal)
;     8). The addressed slave stops driving RB0..7 and Ack
;     
;
; Types of bus cycles:
;
; CID1  CID0    R/W     Cycle name      Description
; -------------------------------------------------------------------------------------------------
;    0     0      0     Write Tx        Data is written to the Transmit Pipe
;    0     0      1     Read Rx         Data is read from the Receive Pipe
;    0     1      0     Write IAddr     Data is written to the indirect addressing register (IAddr)
;    0     1      1     Poll Tx         Reads the number of free bytes in the Transmit Pipe
;    1     0      0     Chip Select     Special cycle which addresses a slave to "listen" or "unlisten"
;    1     0      1     Poll Rx         Reads the number of bytes waiting in the Receive Pipe
;    1     1      0     Write Indirect  Writes the register pointed to by the IAddr register
;    1     1      1     Read Indirect   Reads the register pointed to by the IAddr register
;
;
; The Chip Select cycle requires further description:
;    Data bits 0..3 contain the address of the slave which should respond to this cycle (and assert Ack)
;    Data bit 7 is:
;       1 if the addressed slave should "listen" (respond) to all other types of bus cycle
;       0 if the addressed slave should "unlisten" to (ignore) all other types of bus cycle
;    Data bits 4..6 are unused
;
; If a slave is addressed to "unlisten" when it is already in the "unlistened" state then it will
; reset all internal registers (thus disabling the serial port receiver and flushing all buffers).
; This special double unlisten condition is sent by the master as part of its BREAK reset ...
; thus a BREAK sent to the master will reset the entire board to its power-up state.
;
;
; The Write IAddr cycle has special meaning for the following values:
;    0X00 -- Transfers a block of up to 4 registers into the word buffer (read transfer)
;    0X80 -- Transfers a block of up to 4 registers from the word buffer (write transfer)
;
; Prior to executing either of the above commands, the word buffer address and length registers
; should be written in the normal manner.  The word buffer itself should be written prior to
; executing a write transfer.  It is read to fetch the results of a read transfer.
;
; The data in the word buffer is right-justified (WordBuf3 is always filled, WordBuf2 is
; filled if 2 or more bytes are transfered, etc.)
;
; These special commands facilitate "snapshot" transfers of 32-bit words in order to avoid
; having the value modified by the operating program partway through a read or write.








;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
;####################################################################################################
;****************************************************************************************************
; Definitions, macros, variables, constants
;****************************************************************************************************
;####################################################################################################
;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

                        LIST            P=PIC16C74A, R=DEC              ; PIC16C74A, radix = base 10
                        INCLUDE         <P16C74A.INC>




;-----------------------------------------------------------------------------
;Software registers (RAM) in bank0

wtemp                   EQU     0x20            ;EQU 0XA0 -- both banks -- storage for w register for interrupt context save

        CBLOCK  0X21
                stemp           ;for saving status register in IRQ handler
                PCLATHTEMP      ;for saving PCLATH in IRQ handler
                FSRTEMP         ;for saving FSR in IRQ handler


                Flags1          ;miscellaneous flags -- see individual bit definitions below
                Flags2
                
                SlaveFlags      ;bits 0..6 correspond to slaves at addresses 0..6 -- if a bit is on then the slave MCU is installed
                SlaveAddress    ;address of slave being serviced on each iteration of the "service slaves" algorithm
                SlaveMask       ;bitmask into SlaveFlags byte of slave being serviced on each iteration of the "service slaves" algorithm
                
                SoftTimer1      ;countdown timer which is decremented every 100ms by the timer interrupt until it reaches zero
                
                temp            ;temporary register
                temp2           ;  note that these registers are generally reserved for the highest-level code (main loop and rx, tx state machines)
                temp3           
                temp4
                temp5
                temp6

                mem_temp        ;temporary register for use by memory-interface subroutines
                mem_temp2

                TxBufPCount0    ;counter for number of packets in the transmit buffer
                TxBufPCount1    ;high byte of word

                TxSerial0       ;serial number to use for next transmit packet encoded
                TxSerial1       ;high byte of word

                RxSerial0       ;serial number of last packet received
                RxSerial1       ;high byte of word

                TxBufVCount0    ;counter for number of packets lost due to transmit buffer overflow
                TxBufVCount1    ;2nd byte of long word
                TxBufVCount2
                TxBufVCount3

                RxBufMissCount0 ;counter for number of packets detected missing on receive
                RxBufMissCount1
                RxBufMissCount2
                RxBufMissCount3
                
                
                rx_state        ;state of serial port receive logic -- index into jump table
                rx_substate     ;substate ... used by some state handlers
                rx_substate2
                rx_substate3
                rx_substate4
                r232            ;char received from serial port
                r232xs          ;simple checksum for receive
                r232cl          ;cyclic checksum low byte for receive
                r232ch          ;cyclic checksum high byte for receive


                tx_state        ;state of serial port transmit logic -- index into jump table
                tx_substate     ;substate ... used by some state handlers
                tx_substate2
                t232            ;char to transmit to serial port
                t232xs          ;simple checksum for transmit
                t232cl          ;cyclic checksum low byte for transmit
                t232ch          ;cyclic checksum high byte for transmit
                




                crx_state       ;state of command interpreter receive logic -- index into jump table
                rCmd            ;char to process from channel receive buffer
                rCmdxs          ;simple checksum for rCmd
                rCmdcl          ;cyclic checksum low byte for rCmd
                rCmdch          ;cyclic checksum high byte for rCmd

                ctx_state       ;state of command interpreter transmit logic -- index into jump table
                ctx_substate    ;substate ... used by some state handlers

                tCmd            ;char to transmit via command channel
                tCmdxs          ;simple checksum for tCmd
                tCmdcl          ;cyclic checksum low byte for tCmd
                tCmdch          ;cyclic checksum high byte for tCmd

                CTxPipeRptr     ;Read pointer for command-interpreter transmit pipe
                CTxPipeWptr     ;Write pointer for command-interpreter transmit pipe
                TentativeCTxWptr        ;tentative CTxPipe write pointer
                CTxPipeCount    ;number of bytes in CTx pipe





                                
                tmr_softper     ;software timer period register for matching 12.8ms interrupt with 100ms timer event
                led_code        ;LED error code -- 0 = off, 1 = 1PPS, 2 = blink code 2, 3 = blink code 3, etc.
                led_codephs     ;LED blink code phase
                led_bphs        ;LED blink phase

                ferr_count      ;Number of framing errors detected since reset (maxes out at 255)
                rc_break_counter        ;counter for detecting BREAK condition on Rx line
                


;Read and write pointers for Tx and Rx pipes (FIFO buffers between IRQ and foreground processes for serial port)
;Note: "transmit" and "receive" are relative to this processor's serial port which connects to the PC,
;thus, all "transmit" buffers hold data which will be sent to the PC and all "receive" buffers hold
;data which came from the PC.

                TxPipeRptr      ;Read pointer for Transmit pipe
                TxPipeWptr      ;Write pointer for Transmit pipe
                TentativeTxWptr ;tentative TxPipe write pointer
                
                RxPipeRptr      ;Read pointer for Receive pipe
                RxPipeWptr      ;Write pointer for Receive pipe
                                

;Read and write pointers for SRAM queues (FIFO buffers)
;
;The transmit buffer holds all the data received from all the slaves pending transmission
;to the PC.  It contains packets lacking the prefix and suffix (checksums).
;
;Each individual receive buffer holds data received from the PC which is waiting to be
;sent to the slave processor it was addressed to.
;
;Receive buffer size = 8k
;Transmit buffer size = 64k


;Transmit_Buffer pointers:
                Txwl            ;low byte of write pointer for Transmit_Buffer   (Enqueue pointer)
                Txwh            ;high byte of write pointer for Transmit_Buffer
                
                Txrl            ;low byte of read pointer for Transmit_Buffer    (Dequeue pointer)
                Txrh            ;high byte of read pointer for Transmit_Buffer






                RxBufEmptyFlags         ;bits 0..7 correspond to the Receive_Buffer for packet addresses 0..7 -- bit is set if buffer is empty
                RxBufIndex              ;packet address * 2 of receive buffer read by ReadRxBuf
                RxBufMask               ;mask for RxBufEmptyFlags bit corresponding to RxBufIndex

                RxTwl                   ;low byte of tentative write pointer for an Rxbuf
                RxTwh                   ;high byte of tentative write pointer for an Rxbuf



                CTxPipe                 ;command-interpreter transmit pipe (runs up through end of bank0 ... should be at least 33 bytes long for optimum efficiency)
        ENDC


CTxPipeEnd              EQU     0X80    ;first byte past the end of CTxPipe

        CBLOCK  0XA1
;Receive_Buffer pointers:
;Note that pointers are grouped so that each pointer belongs to an array of 8 pointers
;which can be indexed by the packet address (* 2)
                Rx0rl           ;low byte of read pointer for Rx0buf
                Rx0rh           ;high byte of read pointer for Rx0buf
                Rx1rl           ;low byte of read pointer for Rx1buf
                Rx1rh
                Rx2rl
                Rx2rh
                Rx3rl
                Rx3rh
                Rx4rl
                Rx4rh
                Rx5rl
                Rx5rh
                Rx6rl
                Rx6rh
                RxMrl           ;read pointer for buffer for control channel
                RxMrh

                Rx0wl           ;low byte of write pointer for Rx0buf
                Rx0wh           ;high byte of write pointer for Rx0buf
                Rx1wh
                Rx1wl
                Rx2wl
                Rx2wh
                Rx3wl
                Rx3wh
                Rx4wl
                Rx4wh
                Rx5wl
                Rx5wh
                Rx6wl
                Rx6wh
                RxMwl
                RxMwh

;Registers used to transfer data between master or slave MCU registers and the host computer
;via command packets and responses sent to/from the control channel
                RegXferMCUAddr          ;MCU address of register block to transfer (0..6 are slaves 0..6, 7 is this MCU)
                RegXferAddr             ;base address of register block to transfer
                RegXferLen              ;length of register block to transfer (1..4)
                RegXfer0                ;low byte of block to transfer
                RegXfer1
                RegXfer2
                RegXfer3                ;high byte of block to transfer
;Note that these registers are used by both the command recieve logic and the command transmit logic --
;receipt and transmission of command messages may not be overlapped... the host PC must wait for a reply
;to arrive for each command it sends or wait until a reasonable timeout elapses before sending another
;command.

        ENDC            





;------------------------------------------------------------------------------
; Flags contained in the Flags1 register:
POST                    EQU     0               ;set durring Power-On Self Test -- disables blink-code driver so error LED stays lit
RxPipeEmpty             EQU     1               ;receive pipe is empty
TxPipeFull              EQU     2               ;transmit pipe is full
Receiving               EQU     3               ;serial port is receiving data -- used by interrupt routine to update Rx LED
Transmitting            EQU     4               ;serial port is sending data -- used by interrupt routine to update Tx LED
TxBufOverflow           EQU     5               ;transmit buffer overflowed -- signal from WriteTxBuf subroutine to its caller
SlaveSelected           EQU     6               ;set if the slave at SlaveAddress is addressed to "listen"
CTxPipeFull             EQU     7               ;command-interpreter channel transmit pipe is full



;------------------------------------------------------------------------------
; Flags contained in the Flags2 register:
CTxPipeEmpty            EQU     0               ;Control channel Tx pipe is empty
RC_FERR                 EQU     1               ;Framing error detected on last char received
RC_BREAK                EQU     2               ;BREAK condition detected on Rx line -- reset baud rate
RC_OERR                 EQU     3               ;TESTING -- send diagnostic message if overrun detected


;------------------------------------------------------------------------------
;Pipes for buffering data between IRQ and foreground processes
;
;Note: "transmit" and "receive" are relative to this processor's serial port
;which connects to the PC, thus, all "transmit" buffers hold data which will
;be sent to the PC and all "receive" buffers hold data which came from the PC.
;
;The receive pipe ensures that no data is lost when characters come in while
;the foreground process is busy.
;
;The transmit pipe helps keep data streaming out at the maximum rate allowed
;by the serial port.
;
;Since a receive pipe overflow will result in a lost packet whereas a transmit
;pipe underflow only results in a small delay, the receive buffer is larger
;than the transmit buffer.
;
;Receive buffer size = 40 bytes
;Transmit buffer size = 16 bytes

TxPipe                  EQU     0XC8            ;first byte within the buffer
TxPipeEnd               EQU     0XD8            ;first byte past the end of the buffer
RxPipe                  EQU     0XD8            ;first byte within the buffer
RxPipeEnd               EQU     0X00            ;first byte past the end of the buffer (buffer goes up through 0XFF)




;------------------------------------------------------------------------------
;SRAM buffer addresses
;
;The transmit buffer holds all the data received from all the slaves pending transmission
;to the PC.  It contains packets lacking the prefix and suffix (checksums).
;
;Each individual receive buffer holds data received from the PC which is waiting to be
;sent to the slave processor it was addressed to.
;
;Receive buffer size = 8k
;Transmit buffer size = 64k
;
;Tx buffer is at 0x10000 + given address (A16 high)
;Rx buffer is at given address (A16 low)

Rx0buf                  EQU             0X0000                  ;holding buffer for data being streamed to slave 0
Rx1buf                  EQU             0X2000                  ;holding buffer for data being streamed to slave 1
Rx2buf                  EQU             0X4000                  ;etc.
Rx3buf                  EQU             0X6000
Rx4buf                  EQU             0X8000
Rx5buf                  EQU             0XA000
Rx6buf                  EQU             0XC000
RxMbuf                  EQU             0XE000                  ;data being streamed to master -- control messages

Txbuf                   EQU             0X0000                  ;holding buffer for data pending transmission to PC





;----------------------------------------------------------------------------------
; Special addresses within the slave processors' register space.
; These are register locations which the master must access in order to facilitate
; data transfer requests made by the host computer.
;
        CBLOCK  0X20

;Word buffer registers
;These registers are used to facilitate "snapshot" transfers of 16 or 32 bit words so
;that the values can be read or written without danger of the value being modified by
;the operating program partway through a read or write.
                WordBufAddr     ;address base for word transfer
                WordBufLen      ;length, 1..4
                WordBuf0        ;low databyte of word
                WordBuf1        ;note that data is right-justified, i.e. a 16-bit word
                WordBuf2        ;   occupies WordBuf2 and WordBuf3
                WordBuf3        ;high databyte of word
        ENDC




;------------------------------------------------------------------------------
;Macros

Move                    MACRO           destination,source
                        MOVFW           source
                        MOVWF           destination
                        ENDM

Movlf                   MACRO           destination,source
                        MOVLW           source
                        MOVWF           destination
                        ENDM


;Clear global interrupt enable -- note that an IRQ may be acknowledged
;before the BCF instruction and the IRQ may be executed after the BCF
;instruction and leave gie set upon return (thus the BTFSC instruction
;to make sure this hasn't happened)
ClrI                    MACRO
                        LOCAL           lpclri
lpclri                  BCF             INTCON,GIE
                        BTFSC           INTCON,GIE
                        GOTO            lpclri
                        ENDM

;Set global interrupt enable
SetI                    MACRO
                        BSF             INTCON,GIE
                        ENDM



Bank0                   MACRO
                        BCF             STATUS,RP0
                        ENDM

Bank1                   MACRO
                        BSF             STATUS,RP0
                        ENDM

LowPage                 MACRO
                        BCF             PCLATH,3
                        ENDM

HighPage                MACRO
                        BSF             PCLATH,3
                        ENDM                    


;-------------------------------------------------
; LEDs
LightStatus             MACRO
                        BSF             PORTE,0
                        ENDM

DouseStatus             MACRO
                        BCF             PORTE,0
                        ENDM

LightError              MACRO           
                        BSF             PORTA,5
                        ENDM

DouseError              MACRO   
                        BCF             PORTA,5
                        ENDM

LightRx                 MACRO
                        BSF             PORTC,1
                        ENDM

DouseRx                 MACRO
                        BCF             PORTC,1
                        ENDM

LightTx                 MACRO
                        BSF             PORTC,2
                        ENDM

DouseTx                 MACRO
                        BCF             PORTC,2
                        ENDM

;---------------------------------
; Blink codes:
;    The "error" LED is used as a simple output device for reporting errors.
;    When an error occurs, a blink-code is set which describes the error.
;    The "error" LED is then flashed by the timer interrupt routine.  It blinks
;       the number of times specified by the code, pauses, then repeats.
;

; Codes:
ERR_RX_PIPE_OVERRUN     EQU             2               ;Rx pipe overflowed
ERR_RXREG_OVERRUN       EQU             3               ;Hardware Rx overrun
ERR_NO_SLAVE_PORTS      EQU             4               ;No slave ports detected
ERR_MEMORY_TEST         EQU             5               ;Memory test failed
ERR_BUS_FAILURE         EQU             6               ;Bus timeout on attempt to scan for slaves (Ack is asserted)

Blink                   MACRO           code
                        MOVLW           code
                        CALL            set_blink_code
                        ENDM


;------------------------------------------------
; Slave processor interface
;
; Write macros are invoked with the databyte to write in the W register.
; Read macros end with the data byte read in the W register.
;
; These macros do not time out.  Slave processors should be scanned for with a different
; algorithm which does time out.  These macros should be used only to communicate
; with slaves which are present.
;
;
; The macros available are:
;
; BusWriteTx            writes W to the transmit pipe (of the addressed slave)
; BusReadRx             reads W from the receive pipe
; BusWriteIAddr         writes W to the IAddr register
; BusPollTx             returns number of bytes free in transmit pipe
; BusChipSelect         addresses a slave to listen or unlisten
; BusPollRx             returns number of bytes buffered in receive pipe
; BusWriteIndirect      writes W to the register pointed to by the IAddr register
; BusReadIndirect       reads W from the register pointed to by the IAddr register
;

BusWriteTx              MACRO                           ;Write W to addressed slave's transmit pipe
                        BusStartWrite                   ;wait for prior cycle to end then drive W onto data bus
                        MOVLW           0XE0            
                        ANDWF           PORTA,F         ;setup cycle ID and R/W bits for a "Write Tx" bus cycle
                        NOP
                        BSF             PORTA,0         ;assert E to start the cycle
                        BusWaitAck
                        BusEndWrite
                        ENDM

BusReadRx               MACRO
                        BusStartRead                    ;wait for prior cycle to end
                        MOVFW           PORTA
                        ANDLW           0XE0
                        IORLW           0X02
                        MOVWF           PORTA           ;setup cycle ID and R/W bits for a "Read Rx" bus cycle
                        IORLW           0X01
                        MOVWF           PORTA           ;assert E to start the cycle
                        BusWaitAck
                        BusEndRead
                        ENDM

BusWriteIAddr           MACRO
                        BusStartWrite
                        MOVFW           PORTA
                        ANDLW           0XE0
                        IORLW           0X04
                        MOVWF           PORTA           ;setup cycle ID and R/W bits for a "Write IAddr" bus cycle
                        IORLW           0X01
                        MOVWF           PORTA           ;assert E to start the cycle
                        BusWaitAck
                        BusEndWrite
                        ENDM

BusPollTx               MACRO
                        BusStartRead
                        MOVFW           PORTA
                        ANDLW           0XE0
                        IORLW           0X06
                        MOVWF           PORTA           ;setup cycle ID and R/W bits for a "Poll Tx" bus cycle
                        IORLW           0X01
                        MOVWF           PORTA           ;assert E to start the cycle
                        BusWaitAck
                        BusEndRead                      
                        ENDM


BusChipSelect           MACRO
                        BusStartWrite
                        MOVFW           PORTA
                        ANDLW           0XE0
                        IORLW           0X08
                        MOVWF           PORTA           ;setup cycle ID and R/W bits for a "Chip Select" bus cycle
                        IORLW           0X01
                        MOVWF           PORTA           ;assert E to start the cycle
                        BusWaitAck
                        BusEndWrite                     
                        ENDM


BusPollRx               MACRO
                        BusStartRead
                        MOVFW           PORTA
                        ANDLW           0XE0
                        IORLW           0X0A
                        MOVWF           PORTA           ;setup cycle ID and R/W bits for a "Poll Rx" bus cycle
                        IORLW           0X01
                        MOVWF           PORTA           ;assert E to start the cycle
                        BusWaitAck
                        BusEndRead                      
                        ENDM


BusWriteIndirect        MACRO
                        BusStartWrite
                        MOVFW           PORTA
                        ANDLW           0XE0
                        IORLW           0X0C
                        MOVWF           PORTA           ;setup cycle ID and R/W bits for a "Write Indirect" bus cycle
                        IORLW           0X01
                        MOVWF           PORTA           ;assert E to start the cycle
                        BusWaitAck
                        BusEndWrite                     
                        ENDM


BusReadIndirect         MACRO
                        BusStartRead
                        MOVFW           PORTA
                        ANDLW           0XE0
                        IORLW           0X0E
                        MOVWF           PORTA           ;setup cycle ID and R/W bits for a "Read Indirect" bus cycle
                        IORLW           0X01
                        MOVWF           PORTA           ;assert E to start the cycle
                        BusWaitAck
                        BusEndRead                      
                        ENDM


;Sub-macros used by above macros
;These sub-macros perform common subfunctions

BusStartWrite           MACRO                           ;disables interrupts, waits for prior cycle to end, then drives W onto bus
                        LOCAL           bus_wait_no_ack
                        ClrI
                        MOVWF           PORTB
bus_wait_no_ack         BTFSS           PORTA,4         ;wait for prior cycle to finish if necessary
                        GOTO            bus_wait_no_ack                 
                        MOVLW           TRISB
                        MOVWF           FSR             ;leaves FSR pointing to TRISB
                        CLRF            INDF            ;drive data onto bus
                        ENDM



BusStartRead            MACRO                           ;disables interrupts and waits for ack to be released
                        LOCAL           bus_wait_no_ack
                        ClrI
bus_wait_no_ack         BTFSS           PORTA,4         ;wait for prior cycle to finish if necessary
                        GOTO            bus_wait_no_ack                 
                        ENDM



BusWaitAck              MACRO                           ;waits for slave to assert Ack
                        LOCAL           bus_wait_ack
bus_wait_ack            BTFSC           PORTA,4
                        GOTO            bus_wait_ack
                        ENDM



BusEndWrite             MACRO                           ;Terminates a bus write cycle
                        BCF             PORTA,0
                        DECF            INDF,F          ;assumes FSR was set to TRISB at the start of the bus cycle
                        SetI                            
                        ENDM



BusEndRead              MACRO                           ;Terminates a bus read cycle
                        BCF             PORTA,0
                        MOVFW           PORTB           ;reads data bus ... although this happens after E is de-asserted it is ok since interrupts are disabled and the slave cannot respond within 200ns to stop driving the data bus
                        SetI
                        ENDM







;-------------------------------------------------
; SRAM interface
SetMemCE1               MACRO
                        BCF             PORTE,1
                        ENDM

ClrMemCE1               MACRO
                        BSF             PORTE,1
                        ENDM

SetMemCE2               MACRO
                        BSF             PORTC,5
                        ENDM

ClrMemCE2               MACRO
                        BCF             PORTC,5
                        ENDM

SetMemWr                MACRO
                        BCF             PORTC,3
                        ENDM
                        
ClrMemWr                MACRO
                        BSF             PORTC,3
                        ENDM                    

SetMemOE                MACRO
                        BCF             PORTC,0
                        ENDM

ClrMemOE                MACRO
                        BSF             PORTC,0
                        ENDM

SetMemA16               MACRO
                        BSF             PORTC,4
                        ENDM

ClrMemA16               MACRO
                        BCF             PORTC,4
                        ENDM

SetMemAClk              MACRO
                        BSF             PORTE,2
                        ENDM

ClrMemAClk              MACRO
                        BCF             PORTE,2
                        ENDM








;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
;####################################################################################################
;****************************************************************************************************
; Start of code
;****************************************************************************************************
;####################################################################################################
;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||



;******************************************************************************
;Reset vector
                        ORG             0                       
                        CLRF            PCLATH
                        GOTO            start



;******************************************************************************
;Interrupt vector
;
;Interrupt sources:
;   TMR2IF -- Timer2 expired
;   RCIF   -- Serial port received a character
;   TXIF   -- Serial port is ready to transmit a character


                        ORG             4

;Save context                        
                        MOVWF           wtemp                ;Save W and status registers
                        SWAPF           STATUS,W             ;gets status into W without affecting flags
                        Bank0
                        MOVWF           stemp
                        MOVF            PCLATH,W
                        MOVWF           PCLATHTEMP
                        MOVFW           FSR
                        MOVWF           FSRTEMP


;Branch to appropriate handler
;If more than one interrupt is pending then the other(s) will be serviced after the RETFIE instruction is executed
;Interrupt sources are prioritized as follows:
;    1). RCIF
;    2). TMR2IF
;    3). TXIF
                        LowPage

                        BTFSC           PIR1,RCIF
                        GOTO            receive_char

                        BTFSS           PIR1,TMR2IF
                        GOTO            transmit_char




;--------------------------------
; Begin timer 2 interrupt handler
;
;
;Timer2 interrupt occurs every 12.8ms (78.125 Hz) and causes a timer event to be
;executed every 100ms (on average).

;Update Rx and Tx LEDs
;The Receiving and Transmitting flags are set by the foreground process and cleared here every 12.8ms
                        BTFSC           Flags1,POST
                        GOTO            skip_led_update         ;don't do anything with the LEDs if the Power-On Self Test is in progress
                        DouseRx
                        BTFSC           Flags1,Receiving
                        LightRx
                        BCF             Flags1,Receiving
                        DouseTx
                        BTFSC           Flags1,Transmitting
                        LightTx
                        BCF             Flags1,Transmitting
skip_led_update         

;Test for "break" on Rx line
                        BTFSC           PORTC,7
                        GOTO            no_break
                        DECFSZ          rc_break_counter,F
                        GOTO            tmr2int_c1
                        BSF             Flags2,RC_BREAK         ;BREAK detected -- trigger foreground routine to reset baud rate
                        GOTO            tmr2int_c1

no_break                MOVLW           10
                        MOVWF           rc_break_counter

tmr2int_c1
;Update software timer period register and generate 100ms event
                        MOVLW           0X10                 ;interrupt period = 128/1000 of 100ms = 16/125 of 100ms
                        ADDWF           tmr_softper,F
                        BTFSS           STATUS,C
                        GOTO            ret_tmr_int
                        MOVLW           0X7D                 ;0x7d = 125
                        SUBWF           tmr_softper,F

;-----------
;100ms event

;check for hardware overrun error
                        BTFSS           RCSTA,OERR
                        GOTO            no_overrun_err
                        MOVLW           ERR_RXREG_OVERRUN       ;set blink code unless a higher code has previously been set
                        SUBWF           led_code,W
                        BTFSC           STATUS,C
                        GOTO            no_overrun_err
                        MOVLW           ERR_RXREG_OVERRUN
                        MOVWF           led_code
no_overrun_err


;update timeout timers
                        MOVF            SoftTimer1,F
                        BTFSS           STATUS,Z
                        DECF            SoftTimer1,F            ;decrement countdown timer if not already 0


;Display blink codes on the "error" LED
                        BTFSC           Flags1,POST             ;blink-code driver is disabled durring Power-On Self Test
                        GOTO            ret_tmr_int
                        
                        MOVF            led_code,F              ;code 0 = no error ... no blinking ... LED doused
                        BTFSC           STATUS,Z
                        GOTO            ret_tmr_dl

                        DECFSZ          led_bphs,F
                        GOTO            ret_tmr_dl
                        LightError
                        DECFSZ          led_codephs,F
                        GOTO            set_led_bp
                        MOVFW           led_code
                        MOVWF           led_codephs
                        DECFSZ          led_codephs,W
                        GOTO            set_led_bp2          ;code 1 (1PPS)?
                        MOVLW           10                   ;code 1 -- blink once per second
                        GOTO            set_led_bpc
set_led_bp2             MOVLW           20                   ;code other than 1 -- delay 2 seconds between code repetitions
                        GOTO            set_led_bpc
set_led_bp              MOVLW           5                    ;LED blinks every 500ms when flashing a code
set_led_bpc             MOVWF           led_bphs
                        GOTO            ret_tmr_int
ret_tmr_dl              DouseError
ret_tmr_int             BCF             PIR1,TMR2IF          ;clear timer2 interrupt flag
                        GOTO            ret_int

; End timer 2 interrupt handler
;------------------------------





;------------------------------------------------------
; Begin serial port receive character interrupt handler
;
receive_char            BTFSS           RCSTA,OERR              ;check for overrun
                        GOTO            rc_no_oerr
                        BSF             Flags2,RC_OERR
                        BCF             RCSTA,CREN
                        BSF             RCSTA,CREN              ;overrun occurred -- reset receive logic
                        GOTO            ret_int
                        
rc_no_oerr              BCF             Flags1,RxPipeEmpty

                        BCF             Flags2,RC_FERR
                        BTFSS           RCSTA,FERR              ;Check for framing errors -- keep track of how many occur
                        GOTO            no_ferr
                        BSF             Flags2,RC_FERR
                        INCF            ferr_count,F
                        BTFSC           STATUS,Z
                        DECF            ferr_count,F            ;count maxes out at 255
                        
no_ferr                 MOVF            RxPipeWptr,W            ;Move character from RCREG to RxPipe
                        MOVWF           FSR
                        MOVF            RCREG,W
                        MOVWF           INDF
                        
                        MOVLW           10                      ;must have 10 consecutive low Rx samples (on timer interrupt) with no characters received before resetting baud rate
                        MOVWF           rc_break_counter

                        INCF            RxPipeWptr,F            ;Increment RxPipe write pointer
                        MOVFW           RxPipeWptr
                        SUBLW           RxPipeEnd
                        MOVLW           RxPipe
                        BTFSC           STATUS,Z
                        MOVWF           RxPipeWptr

                        MOVFW           RxPipeWptr              ;Check for pipe overflow                        
                        SUBWF           RxPipeRptr,W
                        BTFSS           STATUS,Z
                        GOTO            ret_int

                        DouseStatus                             ;Overflow has occurred -- turn off "ok" status LED
                        MOVLW           ERR_RX_PIPE_OVERRUN     ;set blink code unless a higher code has previously been set
                        SUBWF           led_code,W
                        BTFSC           STATUS,C
                        GOTO            ret_int
                        MOVLW           ERR_RX_PIPE_OVERRUN
                        MOVWF           led_code
                        GOTO            ret_int

; End serial port receive character interrupt handler
;------------------------------------------------------                        







;-------------------------------------------------------
; Begin serial port transmit character interrupt handler
;
; Move character from TxPipe to TXREG
; If TxPipe is empty then disable this interrupt (clear TXIE)
; TXIE is set when data is written to TxPipe
transmit_char           BCF             Flags1,TxPipeFull
                        MOVFW           TxPipeRptr
                        MOVWF           FSR
                        SUBWF           TxPipeWptr,W
                        BTFSC           STATUS,Z
                        GOTO            clear_txie              ;TxPipe is empty
                        
                        MOVFW           INDF                    ;TxPipe contains data -- move one character to TXREG
                        MOVWF           TXREG
                        
                        INCF            TxPipeRptr,F            ;Increment TxPipe read pointer
                        MOVFW           TxPipeRptr
                        SUBLW           TxPipeEnd
                        MOVLW           TxPipe
                        BTFSC           STATUS,Z
                        MOVWF           TxPipeRptr
                        


;Restore context and return from interrupt
ret_int                 MOVFW           FSRTEMP
                        MOVWF           FSR
                        MOVF            PCLATHTEMP,W
                        MOVWF           PCLATH
                        SWAPF           stemp,W              ;gets original status to W without affecting flags
                        MOVWF           STATUS
                        SWAPF           wtemp,F              ;swaps halves of wtemp
                        SWAPF           wtemp,W              ;gets original W back without affecting flags
                        RETFIE



clear_txie              Bank1
                        BCF             PIE1,TXIE               ;TxPipe is empty -- disable the "transmit buffer empty" interrupt
                        Bank0
                        GOTO            ret_int

; End serial port transmit character interrupt handler
;------------------------------------------------------                        




                        

;****************************************************************************************************
; Entry point from reset vector ... initializations
;****************************************************************************************************
start

;-----------------------------------------------------------------------------
;Initialize all relevent special function registers to their reset states ...
;this is done incase a watchdog timer reset occurs and some SFRs have values
;which would otherwise impair normal operation
                        CLRF            STATUS          ;Clear RP0, RP1 and IRP bits
                        CLRF            PCLATH
                        CLRF            INTCON
                        CLRF            T1CON
                        CLRF            T2CON
                        CLRF            SSPCON
                        CLRF            CCP1CON
                        CLRF            RCSTA
                        CLRF            CCP2CON
                        CLRF            ADCON0
                Bank1
                        MOVLW           0XFF
                        MOVWF           0X81            ;OPTION register -- symbol not defined in stock header
                        MOVWF           TRISA
                        MOVWF           TRISB
                        MOVWF           TRISC
                        MOVWF           TRISD
                        MOVLW           0X07
                        MOVWF           TRISE
                        CLRF            PIE1
                        CLRF            PIE2
                        CLRF            SSPSTAT
                        CLRF            TXSTA
                        CLRF            SPBRG
                        CLRF            ADCON1


;-----------------------------------------------------------------------------
;Initialize some software registers (any that interrupt service routine uses)

                Bank0
                        MOVLW           (1 << POST) | (1 << RxPipeEmpty)
                        MOVWF           Flags1
                        MOVLW           (1 << CTxPipeEmpty)
                        MOVWF           Flags2
                        MOVLW           10
                        MOVWF           rc_break_counter
                        CLRF            CTxPipeCount
                        CLRF            ferr_count
                        CLRF            TxBufPCount0
                        CLRF            TxBufPCount1
                        CLRF            TxSerial0
                        CLRF            TxSerial1
                        CLRF            TxBufVCount0
                        CLRF            TxBufVCount1
                        CLRF            TxBufVCount2
                        CLRF            TxBufVCount3
                                                
                        MOVLW           1
                        MOVWF           led_code
                        MOVWF           led_codephs
                        MOVWF           led_bphs

                        Movlf           TxPipeRptr,TxPipe       ;Read pointer for Transmit pipe
                        Movlf           TxPipeWptr,TxPipe       ;Write pointer for Transmit pipe
                        Movlf           RxPipeRptr,RxPipe       ;Read pointer for Receive pipe
                        Movlf           RxPipeWptr,RxPipe       ;Write pointer for Receive pipe

                        Movlf           CTxPipeRptr,CTxPipe     ;Read pointer for command-interpreter Tx pipe
                        Movlf           CTxPipeWptr,CTxPipe     ;Write pointer for command-interpreter Tx pipe

                        

;--------------------------------------------------------------------------
; Initialize special function registers (I/O port states, most peripherals)

                        CLRF            PORTA
                        MOVLW           0X29            ;0010 1001 -- no memory rd or wr, mem CE2 set, A16 low, tx and rx LEDs doused
                        MOVWF           PORTC
                        MOVLW           0X06            ;0000 0110 -- no error LED, mem CE1 clear, latch clk high
                        MOVWF           PORTE

                        MOVLW           0X7F            ;enable tmr2, prescale 16, postscale 16
                        MOVWF           T2CON

                Bank1
                        MOVLW           0X10
                        MOVWF           TRISA           ;RA4 is the only input (/Ack)
                        MOVLW           0XFF
                        MOVWF           TRISB           ;port B is data bus
                        MOVLW           0X80
                        MOVWF           TRISC           ;port C is all output except RC7/Rx
                        CLRF            TRISD           ;port D is the memory address bus -- all output
                        CLRF            TRISE           ;port E is all output
                        Movlf           ADCON1,6        ;configure RA0..5 and RE0..2 as digital I/O rather than analog inputs



                        
                        MOVLW           249             ;tmr2 period 250 x 256 x 4 (prescale, postscale, fixed /4) = 256000 = 12.8ms with 20MHz oscillator
                        MOVWF           PR2
                        MOVLW           (1 << TMR2IE) | (1 << RCIE)   ;enable tmr2 interrupt and receive character interrupt (TXIE is set when TxPipe is written to ... cleared when TxPipe becomes empty)
                        MOVWF           PIE1


                Bank0
                        MOVLW           (1 << GIE) | (1 << PEIE)      ;enable peripheral interrupts (tmr2, serial port)
                        MOVWF           INTCON




;**********************************************************************************************************************
;Begin Power-On Self Test
;*********************************************************************************************************************

                        LightStatus                     ;turn on all LEDs durring the POST
                        NOP
                        LightError
                        NOP
                        LightRx
                        NOP
                        LightTx

;------------------------------------------------------------
;Test the SRAM

;First, fill the memory with pseudo-random numbers...
                        CLRF            r232xs          ;checksums and checksum algorithm is used to produce pseudo-random numbers for memory test
                        CLRF            r232cl
                        CLRF            r232ch
                        CLRF            t232xs
                        CLRF            t232cl
                        CLRF            t232ch

                        CLRF            Txwl
                        CLRF            Txwh
                        Movlf           FSR,Txwl

                        ClrMemA16
lprtw1                  CLRWDT

                        MOVFW           t232xs
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        CALL            update_rx_checksums
                        MOVFW           r232xs
                        XORWF           r232cl,W
                        XORWF           r232ch,W
                        CALL            update_tx_checksums
                        MOVFW           t232xs
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        CALL            WriteMem
                        INCF            Txwl,F
                        BTFSC           STATUS,Z
                        INCFSZ          Txwh,F
                        GOTO            lprtw1

                        SetMemA16
lprtw2                  CLRWDT
                        MOVFW           t232xs
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        CALL            update_rx_checksums
                        MOVFW           r232xs
                        XORWF           r232cl,W
                        XORWF           r232ch,W
                        CALL            update_tx_checksums
                        MOVFW           t232xs
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        CALL            WriteMem
                        INCF            Txwl,F
                        BTFSC           STATUS,Z
                        INCFSZ          Txwh,F
                        GOTO            lprtw2
                        


;Now read back and verify the pseudo-random numbers and, at the same time,
;write back the one's compliments of those numbers

                        DouseTx
                        NOP
                        DouseStatus
                        
                        CLRF            r232xs
                        CLRF            r232cl
                        CLRF            r232ch
                        CLRF            t232xs
                        CLRF            t232cl
                        CLRF            t232ch



                        ClrMemA16
lprtr1                  CLRWDT
                        MOVFW           t232xs
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        CALL            update_rx_checksums
                        MOVFW           r232xs
                        XORWF           r232cl,W
                        XORWF           r232ch,W
                        CALL            update_tx_checksums
                        CALL            ReadMem
                        MOVWF           temp
                        XORWF           t232xs,W
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        BTFSS           STATUS,Z
                        GOTO            mem_test_failed
                        MOVFW           temp
                        XORLW           0XFF
                        CALL            WriteMem
                        INCF            Txwl,F
                        BTFSC           STATUS,Z
                        INCFSZ          Txwh,F
                        GOTO            lprtr1

                        SetMemA16
lprtr2                  CLRWDT
                        MOVFW           t232xs
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        CALL            update_rx_checksums
                        MOVFW           r232xs
                        XORWF           r232cl,W
                        XORWF           r232ch,W
                        CALL            update_tx_checksums
                        CALL            ReadMem
                        MOVWF           temp
                        XORWF           t232xs,W
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        BTFSS           STATUS,Z
                        GOTO            mem_test_failed
                        MOVFW           temp
                        XORLW           0XFF
                        CALL            WriteMem                        
                        INCF            Txwl,F
                        BTFSC           STATUS,Z
                        INCFSZ          Txwh,F
                        GOTO            lprtr2
                        


;Now read back and verify the one's compliments of the pseudo-random numbers

                        DouseError

                        CLRF            r232xs
                        CLRF            r232cl
                        CLRF            r232ch
                        CLRF            t232xs
                        CLRF            t232cl
                        CLRF            t232ch


                        ClrMemA16
lprtr3                  CLRWDT
                        MOVFW           t232xs
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        CALL            update_rx_checksums
                        MOVFW           r232xs
                        XORWF           r232cl,W
                        XORWF           r232ch,W
                        CALL            update_tx_checksums
                        CALL            ReadMem
                        XORWF           t232xs,W
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        XORLW           0XFF
                        BTFSS           STATUS,Z
                        GOTO            mem_test_failed
                        INCF            Txwl,F
                        BTFSC           STATUS,Z
                        INCFSZ          Txwh,F
                        GOTO            lprtr3

                        SetMemA16
lprtr4                  CLRWDT
                        MOVFW           t232xs
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        CALL            update_rx_checksums
                        MOVFW           r232xs
                        XORWF           r232cl,W
                        XORWF           r232ch,W
                        CALL            update_tx_checksums
                        CALL            ReadMem
                        XORWF           t232xs,W
                        XORWF           t232cl,W
                        XORWF           t232ch,W
                        XORLW           0XFF
                        BTFSS           STATUS,Z
                        GOTO            mem_test_failed
                        INCF            Txwl,F
                        BTFSC           STATUS,Z
                        INCFSZ          Txwh,F
                        GOTO            lprtr4

                        GOTO            mem_test_passed
                        



mem_test_failed         Blink           ERR_MEMORY_TEST


mem_test_passed

;------------------------------------------------------------------------------------
; Scan for slave processors -- the board may have up to 7 slave processors installed

                        DouseRx

                        CLRF            temp                    ;slave address
                        CLRF            SlaveAddress
                        Movlf           temp2,1                 ;SlaveFlags bitmask for addressed slave
                        MOVWF           SlaveMask
                        CLRF            SlaveFlags                      

loop_scan_slaves        Movlf           SoftTimer1,2            ;give each processor 100-200ms to respond (should respond in a few microseconds but timer resolution is 100ms)

                        MOVFW           temp                    ;loop for each slave 0..6
                        MOVWF           PORTB                   ;address the slave to "unlisten"
                        
wait_no_ack             CLRWDT
                        BTFSC           PORTA,4                 ;wait for prior cycle to finish if necessary
                        GOTO            ack_is_off
                        MOVF            SoftTimer1,F            ;check for timeout ... this would indicate a serious bus malfunction
                        BTFSS           STATUS,Z
                        GOTO            wait_no_ack
                        Blink           ERR_BUS_FAILURE
                        GOTO            end_slave_scan
                        
ack_is_off              MOVLW           TRISB
                        MOVWF           FSR                     ;leaves FSR pointing to TRISB
                        CLRF            INDF                    ;drive data onto bus
                        MOVFW           PORTA
                        ANDLW           0XE0
                        IORLW           0X08
                        MOVWF           PORTA                   ;setup cycle ID and R/W bits for a "Chip Select" bus cycle
                        IORLW           0X01
                        MOVWF           PORTA                   ;assert E to start the cycle

wait_ack                CLRWDT
                        BTFSS           PORTA,4                 ;wait for acknowledge                   
                        GOTO            ack_is_on
                        MOVF            SoftTimer1,F            ;check for timeout ... this would indicate that the addressed slave is not present
                        BTFSS           STATUS,Z
                        GOTO            wait_ack
                        GOTO            ack_timed_out

ack_is_on               MOVFW           temp2                   ;slave is present -- set corresponding flag bit
                        IORWF           SlaveFlags,F
                        
ack_timed_out           BCF             PORTA,0                 ;de-assert E ... end the write cycle
                        DECF            INDF,F                  ;tri-state the databus


                        INCF            temp,F                  ;index/address the next slave
                        RLF             temp2,F
                        BTFSS           temp2,7
                        GOTO            loop_scan_slaves


end_slave_scan          MOVF            SlaveFlags,F            ;are any slave ports present?
                        MOVLW           ERR_NO_SLAVE_PORTS
                        BTFSC           STATUS,Z
                        CALL            set_blink_code


;*********************************************************************************************************************
;End Power-On Self Test
;*********************************************************************************************************************

                        DouseError
                        NOP
                        DouseTx
                        NOP
                        DouseRx
                        
                        LightStatus
                        MOVLW           2
                        SUBWF           led_code,W
                        BTFSC           STATUS,C
                        DouseStatus



;---------------------------------------------------------------------------------------------------------------------
; 2nd phase of initializations...  (Power-On Self Test has now finished)

;Initialize most software registers (variables)
;First set up default baud rate to 2400 ... this is the power-on value
;The baud rate can be changed later via software commands

;Entry point for BREAK command (break condition on serial port receive line)
;The break command is used to reset the baud rate to 2400
BREAK_RESET     Bank1
                        MOVLW           (1 << TXEN)     ;enable serial port transmit, not BRGH, asynchronous mode, 8 bit
                        MOVWF           RegXfer0        ;this register is later transfered to TXSTA
                        MOVLW           129             ;2400 baud
                        MOVWF           RegXfer1        ;this register is later transfered to SPBRG
                Bank0
                        

;Entry point for changing baud rate ... flushes all buffers and resets port at new baud rate
;Also resets all slave ports to their power-up (inactive) state
;TXSTA is copied from RegXfer0
;SPBRG is copied from RegXfer1
RESET_BAUD      ClrI
                        MOVLW           1 << SPEN
                        MOVWF           RCSTA                   ;Disable serial port receiver but leave I/O pins configured as Rx and Tx

;Reset slaves by "unlistening" them while they are already in an "unlistened" state
;This will trigger them to reset to their power-on state (clear all buffers, disable serial port receiver, etc.)
                        BTFSS           Flags1,SlaveSelected            ;is a slave addressed?
                        GOTO            no_unl_slave_rst

                        MOVFW           SlaveAddress
                        BusChipSelect                           ;tell last slave to "unlisten"
                        BCF             Flags1,SlaveSelected
                        
no_unl_slave_rst        MOVF            SlaveFlags,F            ;are any slaves connected?
                        BTFSC           STATUS,Z
                        GOTO            no_slaves_rst

                        MOVLW           2
                        MOVWF           temp                    ;loop counter for assurring that each slave is "unlistened" at least once

next_slave_rst          INCF            SlaveAddress,F          ;compute address of next connected slave
                        BCF             STATUS,C
                        RLF             SlaveMask,F
                        BTFSS           SlaveMask,7
                        GOTO            no_lsm_roll_rst
                        
                        CLRF            SlaveAddress
                        Movlf           SlaveMask,1
                        DECF            temp,F
                        BTFSC           STATUS,Z
                        GOTO            no_slaves_rst           ;done "unlistening" all the slaves
                        
no_lsm_roll_rst         MOVFW           SlaveMask
                        ANDWF           SlaveFlags,W
                        BTFSC           STATUS,Z
                        GOTO            next_slave_rst

                        MOVF            SlaveAddress,W          ;"unlisten" next slave
                        BusChipSelect
                        GOTO            next_slave_rst


no_slaves_rst           MOVLW           (1 << RxPipeEmpty)
                        MOVWF           Flags1
                        MOVLW           (1 << CTxPipeEmpty)
                        MOVWF           Flags2
                        MOVLW           10
                        MOVWF           rc_break_counter                        
                        CLRF            CTxPipeCount
                        CLRF            ferr_count
                        CLRF            TxBufPCount0
                        CLRF            TxBufPCount1
                        CLRF            TxSerial0
                        CLRF            TxSerial1
                        CLRF            TxBufVCount0
                        CLRF            TxBufVCount1
                        CLRF            TxBufVCount2
                        CLRF            TxBufVCount3

                        Movlf           TxPipeRptr,TxPipe       ;Read pointer for Transmit pipe
                        Movlf           TxPipeWptr,TxPipe       ;Write pointer for Transmit pipe
                        Movlf           RxPipeRptr,RxPipe       ;Read pointer for Receive pipe
                        Movlf           RxPipeWptr,RxPipe       ;Write pointer for Receive pipe

                        Movlf           CTxPipeRptr,CTxPipe     ;Read pointer for command-interpreter Tx pipe
                        Movlf           CTxPipeWptr,CTxPipe     ;Write pointer for command-interpreter Tx pipe
                SetI



                        CLRF            rx_state                ;Rx state starts at 0
                        CLRF            tx_state                ;Tx state starts at 0
                        CLRF            ctx_state               ;command Tx state
                        CLRF            crx_state               ;command Rx state

                        Movlf           Txwl,LOW(Txbuf)         ;low byte of write pointer for Transmit_Buffer   (Enqueue pointer)
                        Movlf           Txwh,HIGH(Txbuf)        ;high byte of write pointer for Transmit_Buffer
                
                        Movlf           Txrl,LOW(Txbuf)         ;low byte of read pointer for Transmit_Buffer    (Dequeue pointer)
                        Movlf           Txrh,HIGH(Txbuf)        ;high byte of read pointer for Transmit_Buffer

                        Movlf           RxBufEmptyFlags,0XFF            ;all buffers are empty


                Bank1
                        Movlf           Rx0rl,LOW(Rx0buf)               ;low byte of read pointer for Rx0buf
                        Movlf           Rx1rl,LOW(Rx1buf)               ;low byte of read pointer for Rx1buf
                        Movlf           Rx2rl,LOW(Rx2buf)
                        Movlf           Rx3rl,LOW(Rx3buf)
                        Movlf           Rx4rl,LOW(Rx4buf)
                        Movlf           Rx5rl,LOW(Rx5buf)               
                        Movlf           Rx6rl,LOW(Rx6buf)
                        Movlf           RxMrl,LOW(RxMbuf)               ;low byte of read pointer for buffer for control channel

                        Movlf           Rx0rh,HIGH(Rx0buf)              ;high byte of read pointer for Rx0buf
                        Movlf           Rx1rh,HIGH(Rx1buf)
                        Movlf           Rx2rh,HIGH(Rx2buf)
                        Movlf           Rx3rh,HIGH(Rx3buf)
                        Movlf           Rx4rh,HIGH(Rx4buf)
                        Movlf           Rx5rh,HIGH(Rx5buf)              
                        Movlf           Rx6rh,HIGH(Rx6buf)
                        Movlf           RxMrh,HIGH(RxMbuf)

                        Movlf           Rx0wl,LOW(Rx0buf)               ;low byte of write pointer for Rx0buf
                        Movlf           Rx1wl,LOW(Rx1buf)
                        Movlf           Rx2wl,LOW(Rx2buf)
                        Movlf           Rx3wl,LOW(Rx3buf)
                        Movlf           Rx4wl,LOW(Rx4buf)
                        Movlf           Rx5wl,LOW(Rx5buf)
                        Movlf           Rx6wl,LOW(Rx6buf)
                        Movlf           RxMwl,LOW(RxMbuf)

                        Movlf           Rx0wh,HIGH(Rx0buf)              ;high byte of write pointer for Rx0buf
                        Movlf           Rx1wh,HIGH(Rx1buf)              
                        Movlf           Rx2wh,HIGH(Rx2buf)
                        Movlf           Rx3wh,HIGH(Rx3buf)
                        Movlf           Rx4wh,HIGH(Rx4buf)
                        Movlf           Rx5wh,HIGH(Rx5buf)
                        Movlf           Rx6wh,HIGH(Rx6buf)
                        Movlf           RxMwh,HIGH(RxMbuf)

                        
;Enable and initialize the serial port hardware

                        MOVF            RegXfer0,W
                        MOVWF           TXSTA
                        MOVF            RegXfer1,W
                        MOVWF           SPBRG
                Bank0
                        MOVLW           (1 << SPEN) | (1 << CREN)       ;enable serial port, enable receiver
                        MOVWF           RCSTA









;#####################################################################################################################
;*********************************************************************************************************************
; Main foreground loop
;*********************************************************************************************************************


mainloop                CLRWDT
                        BTFSS           Flags1,RxPipeEmpty
                        GOTO            process_rx
                        
;------ poll_slaves ------
;This code only gets executed once the RxPipe has been emptied
;
;Select next slave and ask it if it has any data ... read the data if so
;Also write data from its corresponding receive buffer if it is ready to accept it
                        BTFSS           Flags1,SlaveSelected            ;is a slave addressed?
                        GOTO            no_unlisten_slave

                        MOVFW           SlaveAddress
                        BusChipSelect                           ;tell last slave to "unlisten"
                        BCF             Flags1,SlaveSelected
                        
no_unlisten_slave       MOVF            SlaveFlags,F            ;are any slaves connected?
                        BTFSC           STATUS,Z
                        GOTO            no_slaves

next_slave_address      INCF            SlaveAddress,F          ;compute address of next connected slave
                        BCF             STATUS,C
                        RLF             SlaveMask,F
                        BTFSS           SlaveMask,7
                        GOTO            no_lsm_roll
                        CLRF            SlaveAddress
                        Movlf           SlaveMask,1
no_lsm_roll             MOVFW           SlaveMask
                        ANDWF           SlaveFlags,W
                        BTFSC           STATUS,Z
                        GOTO            next_slave_address

                        MOVLW           0X80                    ;Select next slave
                        IORWF           SlaveAddress,W
                        BusChipSelect
                        BSF             Flags1,SlaveSelected

                        BusPollRx                                       ;see if slave has any data waiting
                        BTFSC           STATUS,Z
                        GOTO            no_slave_rxdata

                        MOVWF           temp
                        SUBLW           31                      ;is there at least 32 bytes bufferred?
                        BTFSC           STATUS,C
                        GOTO            check_txbuf_size        ;no, don't encode a packet unless the transmit buffer is close to empty

                        Movlf           temp,32                 ;encode a packet holding 32 bytes of data
                        GOTO            encode_packet

check_txbuf_size        MOVF            TxBufPCount1,F          ;If the Transmit buffer is close to empty then encode the packet regardless of its size
                        BTFSS           STATUS,Z
                        GOTO            no_slave_rxdata
                        MOVLW           8                       ;less than 8 packets buffered?
                        SUBWF           TxBufPCount0,W
                        BTFSC           STATUS,C
                        GOTO            no_slave_rxdata

encode_packet           MOVFW           Txwl                    ;save transmit buffer enqueue pointer incase it overflows
                        MOVWF           temp3                   ;(so the addition of this latest packet can be undone)
                        MOVFW           Txwh
                        MOVWF           temp4

                        SWAPF           SlaveAddress,W
                        MOVWF           temp2                   
                        RLF             temp2,F
                        MOVLW           0XE0
                        ANDWF           temp2,F                 ;slave address goes in bits 5..7

                        DECF            temp,W
                        IORWF           temp2,W                 ;size encoded in packet header is (byte_count - 1) and it goes in bits 0..4

                        CALL            WriteTxBuf
                        MOVFW           TxSerial0
                        CALL            WriteTxBuf
                        MOVFW           TxSerial1
                        CALL            WriteTxBuf
                        
move_packet_loop        BusReadRx
                        CALL            WriteTxBuf
                        DECFSZ          temp,F
                        GOTO            move_packet_loop

                        BTFSS           Flags1,TxBufOverflow    ;did the Transmit buffer overflow?
                        GOTO            no_txbuf_overflow
                        BCF             Flags1,TxBufOverflow    ;consume the flag

                        MOVFW           temp3                   ;reset write pointer to its value before this last packet was added
                        MOVWF           Txwl                    ;(discard the packet)
                        MOVFW           temp4
                        MOVWF           Txwh

                        INCF            TxBufVCount0,F          ;increment packet loss counter
                        BTFSC           STATUS,Z
                        INCF            TxBufVCount1,F
                        BTFSC           STATUS,Z
                        INCF            TxBufVCount2,F
                        BTFSC           STATUS,Z
                        INCF            TxBufVCount3,F
                        GOTO            no_slave_rxdata


no_txbuf_overflow       INCF            TxSerial0,F             ;increment transmit packet serial number
                        BTFSC           STATUS,Z
                        INCF            TxSerial1,F

                        INCF            TxBufPCount0,F          ;increment transmit buffer packet counter
                        BTFSC           STATUS,Z
                        INCF            TxBufPCount1,F


no_slave_rxdata         
;Check if there is data to send to the slave... if so check if slave can accept any ... if so send it
                        MOVFW           SlaveMask
                        ANDWF           RxBufEmptyFlags,W
                        BTFSS           STATUS,Z
                        GOTO            no_slave_txdata

                        BusPollTx                               ;see if slave can accept any more transmit data
                        BTFSC           STATUS,Z
                        GOTO            no_slave_txdata
                        MOVWF           temp

                        Move            RxBufIndex,SlaveAddress
                        ADDWF           RxBufIndex,F
                        Move            RxBufMask,SlaveMask

fill_txpipe_loop        CALL            ReadRxBuf
                        BusWriteTx
                        MOVFW           RxBufMask
                        ANDWF           RxBufEmptyFlags,W               ;loop while there is data to send 
                        BTFSS           STATUS,Z
                        GOTO            no_slave_txdata
                        DECFSZ          temp,F                          ;   ... and the slave's Tx Pipe is not full
                        GOTO            fill_txpipe_loop


no_slave_txdata
no_slaves




;Encode a packet from the control channel if enough bytes are buffered or the transmit buffer is empty
                        BTFSC           Flags2,CTxPipeEmpty     ;is there any data in the control channel's transmit pipe?
                        GOTO            no_control_packet       ;   no
                        BTFSC           Flags1,CTxPipeFull      ;is control channel's transmit pipe full?
                        GOTO            encode_control_packet   ;   yes, encode a packet
                        MOVF            ctx_state,F             ;is the control channel still generating output?
                        BTFSS           STATUS,Z
                        GOTO            no_control_packet       ;   yes, wait until it stops or its pipe fills

encode_control_packet   MOVFW           Txwl                    ;save transmit buffer enqueue pointer incase it overflows
                        MOVWF           temp3                   ;(so the addition of this latest packet can be undone)
                        MOVFW           Txwh
                        MOVWF           temp4
                        MOVFW           CTxPipeCount            ;also save CTx pipe position .. don't loose data from the control channel
                        MOVWF           temp5                   ;since it can simply wait to encode more output
                        MOVFW           CTxPipeRptr
                        MOVWF           temp6

                        Move            temp,CTxPipeCount
                        MOVLW           33
                        SUBWF           temp,W
                        MOVLW           32
                        BTFSC           STATUS,C
                        MOVWF           temp                    ;temp is packet size .. truncated to 32 bytes if necessary
                        DECF            temp,W                  ;size-1 goes in low 5 bits
                        IORLW           0XE0                    ;address (=7) goes in high 3 bits
                        CALL            WriteTxBuf
                        MOVFW           TxSerial0
                        CALL            WriteTxBuf
                        MOVFW           TxSerial1
                        CALL            WriteTxBuf


                        
ec_packet_loop          Move            FSR,CTxPipeRptr
                        MOVFW           INDF
                        CALL            WriteTxBuf
                        INCF            CTxPipeRptr,F
                        MOVFW           CTxPipeRptr
                        XORLW           CTxPipeEnd
                        MOVLW           CTxPipe
                        BTFSC           STATUS,Z
                        MOVWF           CTxPipeRptr
                        DECF            CTxPipeCount,F
                        DECFSZ          temp,F
                        GOTO            ec_packet_loop

                        BTFSS           Flags1,TxBufOverflow    ;did the Transmit buffer overflow?
                        GOTO            no_txbuf_overflow2
                        BCF             Flags1,TxBufOverflow    ;consume the flag

                        MOVFW           temp3                   ;reset write pointer to its value before this last packet was added
                        MOVWF           Txwl                    ;(discard the packet)
                        MOVFW           temp4
                        MOVWF           Txwh

                        MOVFW           temp5                   ;reset CTx pipe position to value before write attempt
                        MOVWF           CTxPipeCount
                        MOVFW           temp6
                        MOVWF           CTxPipeRptr

                        GOTO            no_control_packet       ;Note:  packet loss counter not incremented since data was left in CTxPipe


no_txbuf_overflow2      BCF             Flags1,CTxPipeFull      ;update CTx pipe status flags
                        MOVF            CTxPipeCount,F
                        BTFSC           STATUS,Z
                        BSF             Flags2,CTxPipeEmpty

                        INCF            TxSerial0,F             ;increment transmit packet serial number
                        BTFSC           STATUS,Z
                        INCF            TxSerial1,F

                        INCF            TxBufPCount0,F          ;increment transmit buffer packet counter
                        BTFSC           STATUS,Z
                        INCF            TxBufPCount1,F


no_control_packet               












;Drive the Tx state machine through another state if the Tx Pipe isn't full
                        BTFSC           Flags1,TxPipeFull       ;can this processor's transmit pipe accept another character?
                        GOTO            tx_return

                        MOVF            tx_state,F              ;is any transmit activity currently occurring? (state 0 = idle)
                        BTFSS           STATUS,Z
                        GOTO            process_tx

;Transmit state is currently idle...
;check if Transmit_Buffer contains any packets ... begin transmitting a packet if so
                        MOVFW           TxBufPCount1
                        IORWF           TxBufPCount0,W
                        BTFSS           STATUS,Z
                        INCF            tx_state,F      ;tx state 1 begins transmission of next packet in TxBuf


tx_return               CLRWDT
;If there is any data waiting in the Receive Buffer for the command-interpreter then process it
                        BTFSS           RxBufEmptyFlags,7
                        GOTO            process_command_rx

;If the command-interpreter is sending anything then drive its tx state machine through another state
;Note that tx states are started by the command_rx state machine ... commands and responses are ping-ponged (not streamed)

                        BTFSC           Flags1,CTxPipeFull
                        GOTO            mainloop

                        MOVF            ctx_state,F
                        BTFSS           STATUS,Z
                        GOTO            process_command_tx


                        BTFSS           Flags2,RC_BREAK         ;has a BREAK condition been detected?
                        GOTO            ml_nobreak
                        CLRF            RCSTA                   ;   yes, shut off serial port so its logic resets
                        BTFSS           Flags1,SlaveSelected    ;is a slave addressed?
                        GOTO            nus_brk
                        MOVFW           SlaveAddress
                        BusChipSelect                           ;   yes, tell last slave to "unlisten"
                        BCF             Flags1,SlaveSelected                    
nus_brk                 GOTO            BREAK_RESET             ;Reset baud rate
                        
                        

ml_nobreak              GOTO            mainloop



















;--------------------------------------------------------------------------------------
; Receive 1 character from RxPipe and process it via the Rx state machine
process_rx              MOVFW           RxPipeRptr
                        MOVWF           FSR
                        SUBWF           RxPipeWptr,W
                        BTFSC           STATUS,Z
                        GOTO            rx_pipe_is_empty
                        
                        BSF             Flags1,Receiving                        
                        MOVFW           INDF
                        MOVWF           r232
                        
                        INCF            RxPipeRptr,F            ;Increment RxPipe read pointer
                        MOVFW           RxPipeRptr
                        SUBLW           RxPipeEnd
                        MOVLW           RxPipe
                        BTFSC           STATUS,Z
                        MOVWF           RxPipeRptr

                        MOVLW           HIGH RxJmpTbl
                        MOVWF           PCLATH
                        MOVF            rx_state,W
                        ADDLW           LOW RxJmpTbl
                        BTFSC           STATUS,C
                        INCF            PCLATH,F
                        MOVWF           PCL                     ;jump to handler for current rx_state
                        
;State-machine state handler takes over from here ...
;
;The context for the state handlers is as follows:
;   1). The r232 register contains the next character from the input stream
;   2). Control should be returned to rx_done (jump to the label below when done)
;       or, alternately, to rx_done_noxs if the checksums need to be preserved
;       rather than updated




rx_done                 MOVFW           r232
                        CALL            update_rx_checksums
rx_done_noxs            GOTO            mainloop



rx_pipe_is_empty        BSF             Flags1,RxPipeEmpty
                        GOTO            mainloop




;------------------------------------------------------------------------------------------------
; TxPipe is not full (or has not yet been detected as being full) and tx_state is not idle --
; drive the Tx state machine through 1 state/iteration (each state/iteration typically produces
; one output character which is written to the transmit pipe)
process_tx              INCF            TxPipeWptr,W            ;tentatively increment TxPipe write pointer (to detect a full pipe)
                        MOVWF           TentativeTxWptr
                        SUBLW           TxPipeEnd
                        MOVLW           TxPipe
                        BTFSC           STATUS,Z
                        MOVWF           TentativeTxWptr
                        
                        MOVFW           TxPipeRptr              ;check to see if pipe is full
                        SUBWF           TentativeTxWptr,W
                        BTFSC           STATUS,Z
                        GOTO            tx_pipe_is_full

                        BSF             Flags1,Transmitting

                        MOVLW           HIGH TxJmpTbl
                        MOVWF           PCLATH
                        DECF            tx_state,W              ;tx_state = 1 is the first entry in the table
                        ADDLW           LOW TxJmpTbl
                        BTFSC           STATUS,C
                        INCF            PCLATH,F
                        MOVWF           PCL                     ;jump to handler for current tx_state
                        
;State-machine state handler takes over from here ...
;
;The context for the state handlers is as follows:
;   1). The character produced should be written to t232 ... it will be written to the TxPipe below
;   2). Control should be returned to tx_done (below) if a character was written, to tx_null
;       if a character was not written, or to tx_done_noxs if a character was written but
;       should not be applied to the checksums

tx_done                 MOVFW           t232
                        call            update_tx_checksums
tx_done_noxs            Move            FSR,TxPipeWptr
                        Move            INDF,t232
                        Move            TxPipeWptr,TentativeTxWptr
                Bank1
                        BSF             PIE1,TXIE
                Bank0
tx_null                 GOTO            tx_return



tx_pipe_is_full         BSF             Flags1,TxPipeFull
                        GOTO            tx_return
























;------------------------------------------------------------------------------------------
; Read 1 character from Receive_Buffer[7] and process it via the command Rx state machine
process_command_rx      Movlf           RxBufIndex,14
                        Movlf           RxBufMask,0X80
                        CALL            ReadRxBuf
                        MOVWF           rCmd

                        MOVLW           HIGH CRxJmpTbl
                        MOVWF           PCLATH
                        MOVF            crx_state,W
                        ADDLW           LOW CRxJmpTbl
                        BTFSC           STATUS,C
                        INCF            PCLATH,F
                        MOVWF           PCL                     ;jump to handler for current rx_state
                        
;State-machine state handler takes over from here ...
;
;The context for the state handlers is as follows:
;   1). The rCmd register contains the next character from the input stream
;   2). Control should be returned to crx_done (jump to the label below when done)
;       or, alternately, to crx_done_noxs if the checksums should not be updated



crx_done                MOVFW           rCmd
                        CALL            update_crx_checksums
crx_done_noxs

;------ Testing -- printf( "rxc %.2X   s %.2X   xs %.2X   cl %.2X  ch %.2X\n", rCmd, crx_state, rCmdxs, rCmdcl, rCmdch );
;                  to the auxiliary port at address 6
;
;                       MOVLW           'r'
;                       CALL            WriteRxBuf6
;                       MOVLW           'x'
;                       CALL            WriteRxBuf6
;                       MOVLW           'c'
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       SWAPF           rCmd,W
;                       CALL            WriteNybRB6
;                       MOVF            rCmd,W
;                       CALL            WriteNybRB6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;
;                       MOVLW           's'
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       SWAPF           crx_state,W
;                       CALL            WriteNybRB6
;                       MOVF            crx_state,W
;                       CALL            WriteNybRB6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;
;                       MOVLW           'x'
;                       CALL            WriteRxBuf6
;                       MOVLW           's'
;                       CALL            WriteRxBuf6                     
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       SWAPF           rCmdxs,W
;                       CALL            WriteNybRB6
;                       MOVF            rCmdxs,W
;                       CALL            WriteNybRB6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;
;                       MOVLW           'c'
;                       CALL            WriteRxBuf6
;                       MOVLW           'l'
;                       CALL            WriteRxBuf6                     
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       SWAPF           rCmdcl,W
;                       CALL            WriteNybRB6
;                       MOVF            rCmdcl,W
;                       CALL            WriteNybRB6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;
;                       MOVLW           'c'
;                       CALL            WriteRxBuf6
;                       MOVLW           'h'
;                       CALL            WriteRxBuf6                     
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       SWAPF           rCmdch,W
;                       CALL            WriteNybRB6
;                       MOVF            rCmdch,W
;                       CALL            WriteNybRB6
;                       MOVLW           13
;                       CALL            WriteRxBuf6
;                       MOVLW           10
;                       CALL            WriteRxBuf6





                        GOTO            mainloop






;------ Testing -- write hexadecimal representation of nybble to channel 6's receive buffer ------
;WriteNybRB6            andlw    0x0f
;                       addlw    0xf6
;                       btfsc    STATUS,C
;                       addlw    7
;                       addlw    58
;
;------ Testing -- write character to channel 6's receive buffer ------
;WriteRxBuf6            MOVWF           PORTB
;                       ClrMemA16
;               Bank1
;                       MOVF            Rx6wl,W
;               Bank0
;                       MOVWF           PORTD
;                       ClrMemAClk
;               Bank1
;                       MOVF            Rx6wh,W
;               Bank0
;                       SetMemAClk
;                       MOVWF           PORTD
;                       Movlf           FSR,TRISB
;                       CLRF            INDF
;                       SetMemCE1
;                       SetMemWr                        ;note -- CE1 and OE are on different ports so its ok to do read-modify-write back-to-back
;
;               Bank1
;                       INCF            Rx6wl,F         ;increment the enqueue pointer
;                       BTFSS           STATUS,Z        ;Carry out of low byte?
;                       GOTO            wrxbuf6_noihbp  ;   no, no need to increment high byte
;
;                       INCF            Rx6wh,F
;                       MOVLW           0X1F            ;check for a carry from bit 4 to bit 5 (high 3 bits are buffer address ... low 5 are offset)
;                       ANDWF           Rx6wh,W
;                       BTFSS           STATUS,Z        ;Carry from bit4 to bit5 ?
;                       GOTO            wrxbuf6_noihbp  ;   no, done
;
;                       DECF            Rx6wh,F         ;   yes, restore the high 3 bits and clear the low 5 bits
;                       MOVLW           0XE0            
;                       ANDWF           Rx6wh,F
;
;wrxbuf6_noihbp Bank0
;                       ClrMemWr
;                       ClrMemCE1
;                       DECF            INDF,F
;
;                       BCF             RxBufEmptyFlags,6
;                       RETURN
;

















;------------------------------------------------------------------------------------------------
; CTxPipe is not full (or has not yet been detected as being full) and ctx_state is not idle --
; drive the command interpreter Tx state machine through 1 state/iteration (each state/iteration
; typically produces one output character)
process_command_tx      INCF            CTxPipeWptr,W           ;tentatively increment CTxPipe write pointer (to detect a full pipe)
                        MOVWF           TentativeCTxWptr
                        SUBLW           CTxPipeEnd
                        MOVLW           CTxPipe
                        BTFSC           STATUS,Z
                        MOVWF           TentativeCTxWptr
                        
                        MOVFW           CTxPipeRptr
                        SUBWF           TentativeCTxWptr,W
                        BTFSC           STATUS,Z
                        GOTO            ctx_pipe_is_full

                        MOVLW           HIGH CTxJmpTbl
                        MOVWF           PCLATH
                        DECF            ctx_state,W             ;ctx_state = 1 is the first entry in the table
                        ADDLW           LOW CTxJmpTbl
                        BTFSC           STATUS,C
                        INCF            PCLATH,F
                        MOVWF           PCL                     ;jump to handler for current tx_state
                        
;State-machine state handler takes over from here ...
;
;The context for the state handlers is as follows:
;   1). The character produced should be written to tCmd ... tCmd will be written to the CTx Pipe below
;   2). Control should be returned to ctx_done (below) if a character was written, ctx_null if a
;       character was not written, or ctx_done_noxs if the checksums should not be updated

ctx_done                MOVFW           tCmd
                        call            update_ctx_checksums
ctx_done_noxs           BCF             Flags2,CTxPipeEmpty
                        Move            FSR,CTxPipeWptr
                        Move            INDF,tCmd
                        Move            CTxPipeWptr,TentativeCTxWptr
                        INCF            CTxPipeCount,F






;------ Testing -- printf( "txc %.2X   s %.2X   xs %.2X   cl %.2X  ch %.2X\n", tCmd, ctx_state, tCmdxs, tCmdcl, tCmdch );
;                  to the auxiliary port at address 6
;
;                       MOVLW           't'
;                       CALL            WriteRxBuf6
;                       MOVLW           'x'
;                       CALL            WriteRxBuf6
;                       MOVLW           'c'
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       SWAPF           tCmd,W
;                       CALL            WriteNybRB6
;                       MOVF            tCmd,W
;                       CALL            WriteNybRB6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;
;                       MOVLW           's'
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       SWAPF           ctx_state,W
;                       CALL            WriteNybRB6
;                       MOVF            ctx_state,W
;                       CALL            WriteNybRB6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;
;                       MOVLW           'x'
;                       CALL            WriteRxBuf6
;                       MOVLW           's'
;                       CALL            WriteRxBuf6                     
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       SWAPF           tCmdxs,W
;                       CALL            WriteNybRB6
;                       MOVF            tCmdxs,W
;                       CALL            WriteNybRB6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;
;                       MOVLW           'c'
;                       CALL            WriteRxBuf6
;                       MOVLW           'l'
;                       CALL            WriteRxBuf6                     
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       SWAPF           tCmdcl,W
;                       CALL            WriteNybRB6
;                       MOVF            tCmdcl,W
;                       CALL            WriteNybRB6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;
;                       MOVLW           'c'
;                       CALL            WriteRxBuf6
;                       MOVLW           'h'
;                       CALL            WriteRxBuf6                     
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       SWAPF           tCmdch,W
;                       CALL            WriteNybRB6
;                       MOVF            tCmdch,W
;                       CALL            WriteNybRB6
;                       MOVLW           13
;                       CALL            WriteRxBuf6
;                       MOVLW           10
;                       CALL            WriteRxBuf6
;




                        
ctx_null                GOTO            mainloop



ctx_pipe_is_full        BSF             Flags1,CTxPipeFull
                        GOTO            mainloop







        












;-----------------------------------------------------------------------------------
; Set blink code
; Higher blink codes are assumed to be more severe errors than lower
; blink codes so a higher code will not be replaced by a lower code.
set_blink_code          DouseStatus
                        MOVWF           temp
                        SUBWF           led_code,W
                        BTFSC           STATUS,C
                        RETURN
                        MOVFW           temp
                        MOVWF           led_code
                        RETURN







;------------------------------------------------------------------------------------
; Apply W to receive checksums
update_rx_checksums     xorwf           r232xs,F          ;update plain checksum
                        xorwf           r232cl,F          ;update cyclic checksum
                        addwf           r232ch,F
                        bcf             STATUS,C
                        rrf             r232ch,F
                        btfsc           r232cl,0
                        bsf             r232ch,7
                        rrf             r232cl,F
                        movlw           0x31
                        addwf           r232cl,F
                        btfsc           STATUS,C
                        incf            r232ch,F
                        movlw           0x03
                        addwf           r232ch,F
                        return

;------------------------------------------------------------------------------------
; Apply W to transmit checksums
update_tx_checksums     xorwf           t232xs,F          ;update plain checksum
                        xorwf           t232cl,F          ;update cyclic checksum xor w with low byte
                        addwf           t232ch,F	;add w to high byte
                        bcf             STATUS,C	;clear status carry
                        rrf             t232ch,F	;rotate high right through carry
                        btfsc           t232cl,0	;t232.0 set?
                        bsf             t232ch,7	; set t232.15
                        rrf             t232cl,F	;rotate low byte right through carry
                        movlw           0x31
                        addwf           t232cl,F	;add 31h to low byte
                        btfsc           STATUS,C	;Carry?
                        incf            t232ch,F	; inc high byte
                        movlw           0x03		
                        addwf           t232ch,F	;add 3h to high byte
                        return


;------------------------------------------------------------------------------------
; Apply W to command-interpreter receive checksums
update_crx_checksums    xorwf           rCmdxs,F          ;update plain checksum
                        xorwf           rCmdcl,F          ;update cyclic checksum
                        addwf           rCmdch,F
                        bcf             STATUS,C
                        rrf             rCmdch,F
                        btfsc           rCmdcl,0
                        bsf             rCmdch,7
                        rrf             rCmdcl,F
                        movlw           0x31
                        addwf           rCmdcl,F
                        btfsc           STATUS,C
                        incf            rCmdch,F
                        movlw           0x03
                        addwf           rCmdch,F
                        return

;------------------------------------------------------------------------------------
; Apply W to command-interpreter transmit checksums
update_ctx_checksums    xorwf           tCmdxs,F          ;update plain checksum
                        xorwf           tCmdcl,F          ;update cyclic checksum
                        addwf           tCmdch,F
                        bcf             STATUS,C
                        rrf             tCmdch,F
                        btfsc           tCmdcl,0
                        bsf             tCmdch,7
                        rrf             tCmdcl,F
                        movlw           0x31
                        addwf           tCmdcl,F
                        btfsc           STATUS,C
                        incf            tCmdch,F
                        movlw           0x03
                        addwf           tCmdch,F
                        return





;################################################################################################
; SRAM interface subroutines

;---------------------------------------------------------------------------
; Read one byte from SRAM.  Call with FSR pointing to the low byte of the
; address and FSR + 1 pointing to the high byte of the address.  A16 should
; be set by the caller (it is not changed).
;
; The address pin assignment is arbitrary.  All of the SRAM interface
; subroutines adhere to the convention that the latched address lines
; are A0..7 and the direct lines are A8..15.
; 
; The byte read is returned in W.
;
; Time = 17 instruction cycles (3.4us) including call and return
;
ReadMem                 Move            PORTD,INDF
                        ClrMemAClk
                        INCF            FSR,F
                        SetMemAClk
                        Move            PORTD,INDF
                        SetMemCE1
                        SetMemOE                        ;note -- CE1 and OE are on different ports so its ok to do read-modify-write back-to-back
                        DECF            FSR,F
                        MOVFW           PORTB
                        ClrMemOE
                        ClrMemCE1
                        RETURN


;---------------------------------------------------------------------------
; Write one byte to SRAM.  Call with FSR pointing to the low byte of the
; address and FSR + 1 pointing to the high byte of the address.  A16 should
; be set by the caller (it is not changed).  The byte to write should be
; in the W register.
;
; The W register is modified (contains high byte of address) upon return.
;
; Time = 23 instruction cycles (4.6us) including call and return
;
WriteMem                MOVWF           PORTB
                        Move            PORTD,INDF
                        ClrMemAClk
                        INCF            FSR,F
                        SetMemAClk
                        Move            PORTD,INDF
                        Bank1
                        CLRF            TRISB
                        Bank0
                        SetMemCE1
                        SetMemWr                        ;note -- CE1 and OE are on different ports so its ok to do read-modify-write back-to-back
                        DECF            FSR,F
                        ClrMemWr
                        ClrMemCE1
                        Bank1
                        DECF            TRISB,F
                        Bank0
                        RETURN




;---------------------------------------------------------------------------
; Write one byte to the transmit buffer.
;
; Updates enqueue pointer.
; Sets Flags1:TxBufOverflow and doesn't move enqueue pointer if the enqueue
; pointer would lap the dequeue pointer when moved.
;
; Modifies FSR
;
WriteTxBuf              MOVWF           PORTB
                        SetMemA16
                        Move            PORTD,Txwl
                        ClrMemAClk
                        MOVFW           Txwh
                        SetMemAClk
                        MOVWF           PORTD
                        Movlf           FSR,TRISB
                        CLRF            INDF
                        SetMemCE1
                        SetMemWr                        ;note -- CE1 and OE are on different ports so its ok to do read-modify-write back-to-back

                        INCF            Txwl,F          ;this pointer needs to be incremented sooner or later and here is a good place to do it
                        BTFSC           STATUS,Z        ;since something needs to be inserted between the SetMemWr and the ClrMemWr
                        INCF            Txwh,F
                        
                        ClrMemWr
                        ClrMemCE1
                        DECF            INDF,F

                        MOVFW           Txwl            ;Check for buffer overflow
                        XORWF           Txrl,W
                        BTFSS           STATUS,Z
                        RETURN
                        MOVFW           Txwh
                        XORWF           Txrh,W
                        BTFSS           STATUS,Z
                        RETURN

                        BSF             Flags1,TxBufOverflow    ;The buffer did overflow
                        MOVLW           1
                        SUBWF           Txwl,F
                        BTFSS           STATUS,C
                        SUBWF           Txwh,F
                        RETURN
                        

;---------------------------------------------------------------------------
; ReadTxBuf is located on high page



;---------------------------------------------------------------------------
; WriteRxBuf is located on high page





;---------------------------------------------------------------------------
; Read one byte from one of the receive buffers.
;
; Precondition:
;
;    RxBufIndex contains SlaveAddress * 2.
;    Note that SlaveAddress = 7 for the control channel.
;
;    RxBufMask contains POW(2, SlaveAddress).
;
;    The dequeue pointer for the buffer (pointer pair at Rx0rl + RxBufIndex)
;    points to the next location within the buffer to be read.
;
;
; Postcondition:
;
;    W contains the byte read from [Rx0rl + RxBufIndex].
;
;    The dequeue pointer for the indexed receive buffer has been incremented.
;
;    RxBufEmptyFlags has been OR'd with RxBufMask (bit corresponding to the
;    indexed slave has been set) if the dequeue ptr equals the enqueue ptr.
;
;
; Modifies:
;    FSR
;    mem_temp
;    mem_temp2

ReadRxBuf               ClrMemA16
                        MOVLW           Rx0rl
                        ADDWF           RxBufIndex,W
                        MOVWF           FSR
                        Move            PORTD,INDF
                        MOVWF           mem_temp        ;copy dequeue pointer to mem_temp2:mem_temp
                        ClrMemAClk
                        INCF            FSR,F
                        MOVFW           INDF
                        MOVWF           mem_temp2
                        SetMemAClk
                        MOVWF           PORTD
                        SetMemCE1
                        SetMemOE                        ;note -- CE1 and OE are on different ports so its ok to do read-modify-write back-to-back


                        INCF            mem_temp,F              ;increment mem_temp2:mem_temp and copy back to dequeue pointer
                        BTFSS           STATUS,Z
                        GOTO            rrxbnboc
                        
                        INCF            mem_temp2,F
                        MOVLW           0X1F
                        ANDWF           mem_temp2,W
                        BTFSS           STATUS,Z                ;was there a carry from bit 4 to bit 5 ? (high 3 bits are buffer address ... low 5 are offset)
                        GOTO            rrxbnboc

                        DECF            mem_temp2,F             ;   yes, clear low 5 bits but leave buffer address the same
                        MOVLW           0XE0
                        ANDWF           mem_temp2,F
                        
rrxbnboc                Move            INDF,mem_temp2          ;copy incremented pointer to dequeue pointer
                        DECF            FSR,F
                        Move            INDF,mem_temp

                        MOVLW           Rx0wl                   ;check for empty buffer
                        ADDWF           RxBufIndex,W
                        MOVWF           FSR
                        MOVFW           INDF
                        XORWF           mem_temp,W
                        BTFSS           STATUS,Z
                        GOTO            no_empty_readrxbuf
                        INCF            FSR,F
                        MOVFW           INDF
                        XORWF           mem_temp2,W
                        BTFSS           STATUS,Z
                        GOTO            no_empty_readrxbuf

                        MOVFW           RxBufMask
                        IORWF           RxBufEmptyFlags,F


no_empty_readrxbuf      MOVFW           PORTB                   ;end the memory read cycle
                        ClrMemOE
                        ClrMemCE1
                        RETURN





































;***********************************************************************************************
; ROM page break
;***********************************************************************************************
                        org             0x800           ;high page of ROM





;---------------------------------------------------------------------------------------------------------------------
; Rx state machine dispatch table and handlers
;
; This table is used to jump to the receive character state-machine state handler for a given rx_state.
; The first entry corresponds to rx_state = 0, the second entry to rx_state = 1, etc.
;
;
; The context for the state handlers is as follows:
;
;    1). The r232 register contains the next character from the input stream
;
;    2). Control should be returned to rx_done.  Since rx_done is on a different ROM page, each handler
;        should jump to return_from_rx ... this code fragment will set the page bits and jump to rx_done.
;
;    3). Additional labels are provided upstream from return_from_rx which perform commonly executed
;        tasks prior to returning as a convenience and to save space in ROM
;
;    4). The normal return methods update the checksums.  If the checksums need to be left alone then
;        use the _noxs versions of the returns.

clear_rx_state          CLRF            rx_state
                        GOTO            return_from_rx
next_rx_state           INCF            rx_state,W
set_rx_state            MOVWF           rx_state
return_from_rx          LowPage
                        goto            rx_done


clear_rx_state_noxs     CLRF            rx_state                ;no checksum update versions of returns
                        GOTO            return_from_rx_noxs
next_rx_state_noxs      INCF            rx_state,W
set_rx_state_noxs       MOVWF           rx_state
return_from_rx_noxs     LowPage
                        goto            rx_done_noxs


;
; This dispatch table must be located in same ROM page as the handlers
RxJmpTbl                GOTO            RX_0
                        GOTO            RX_1
                        GOTO            RX_2
                        GOTO            RX_3
                        GOTO            RX_4                        
                        GOTO            RX_5
                        GOTO            RX_6
                        GOTO            RX_7
                        GOTO            RX_8

rxs0                    CLRF            rx_state        ;jump here to reset Rx state and test r232 from state 0

RX_0                    MOVFW           r232            ;1st byte of packet header
                        XORLW           '@'
                        BTFSS           STATUS,Z
                        GOTO            return_from_rx
                        GOTO            next_rx_state

RX_1                    MOVFW           r232            ;2nd byte of packet header
                        XORLW           'P'
                        BTFSS           STATUS,Z
                        GOTO            rxs0
                        CLRF            r232xs
                        CLRF            r232cl
                        CLRF            r232ch
                        GOTO            next_rx_state_noxs

RX_2                    SWAPF           r232,W          ;address/length descriptor
                        MOVWF           rx_substate
                        RRF             rx_substate,F
                        MOVLW           0X07
                        ANDWF           rx_substate,F   ;rx_substate = address

                        MOVLW           0X1F
                        ANDWF           r232,W
                        ADDLW           1
                        MOVWF           rx_substate2    ;rx_substate2 = length

                        MOVLW           Rx0wl           ;RxTwh:RxTwl = buffer enqueue pointer
                        ADDWF           rx_substate,W   ;   used later by WriteRxBuf
                        ADDWF           rx_substate,W
                        MOVWF           FSR
                        MOVFW           INDF
                        MOVWF           RxTwl
                        INCF            FSR,F
                        MOVFW           INDF
                        MOVWF           RxTwh
                        
                        GOTO            next_rx_state

RX_3                    MOVFW           r232
                        MOVWF           rx_substate3    ;rx_substate3 = low byte of serial number
                        GOTO            next_rx_state



;serial number ... high byte
;Lost packet count = (packet serial number - expected serial number)
;expected serial number = RxSerial1:RxSerial0 + 1
;Stick lost packet count in rx_substate4:rx_substate_3 ...
;if checksum passes then add it to total lost packet count and add it (+1) to RxSerial1:RxSerial0
RX_4                    Move            rx_substate4,r232       ;high byte of serial number
                        COMF            RxSerial0,F     ;take 1's compliment and add... same result as adding 1 then subtracting
                        COMF            RxSerial1,F     ;   or adding 1 then taking 2's compliment and adding

                        MOVFW           RxSerial0
                        ADDWF           rx_substate3,F
                        BTFSC           STATUS,Z
                        INCF            rx_substate4,F
                        MOVFW           RxSerial1
                        ADDWF           rx_substate4,F
                        
                        GOTO            next_rx_state



;Receive one databyte ... note that data has been scrambled and must be unscrambled:
;
;   The body contains the data (1 to 32 bytes, as specified in the header).
;
;   The data bytes themselves are modified via the following algorithm: (using C syntax)
;         output_byte = input_byte ^ (cyclic_checksum & 0xff);
;         apply_to_checksums( input_byte );
;
;   To restore the data to its original value:
;         input_byte = output_byte ^ (cyclic_checksum & 0xff);
;         apply_to_checksums( input_byte );
;
;   This modification of the data is done to prevent packets being sent to cascaded
;   multiplexers from being misinterpreted as packets destined for this multiplexer if the
;   receive logic gets out of phase.

RX_5                    MOVFW           r232cl          ;restore original databyte from scrambled value 
                        XORWF           r232,W          
                        MOVWF           r232            ;r232 will be applied to the checksums upon return
                        CALL            WriteRxBuf
                        DECFSZ          rx_substate2,F
                        GOTO            return_from_rx
                        GOTO            next_rx_state

;Checksums
RX_6                    MOVFW           r232xs          ;plain checksum
                        XORWF           r232,W
                        BTFSC           STATUS,Z
                        GOTO            next_rx_state_noxs
                        GOTO            rxs0
                        
RX_7                    MOVFW           r232cl          ;low byte of cyclic checksum
                        XORWF           r232,W
                        BTFSC           STATUS,Z
                        GOTO            next_rx_state_noxs
                        GOTO            rxs0

RX_8                    MOVFW           r232ch          ;high byte of cyclic checksum
                        XORWF           r232,W
                        BTFSS           STATUS,Z
                        GOTO            rxs0

;All checksums passed ... the packet was good
;add current missing packet count to accumulator
                        MOVFW           rx_substate3
                        ADDWF           RxBufMissCount0,F
                        MOVLW           1
                        BTFSC           STATUS,C
                        ADDWF           RxBufMissCount1,F
                        BTFSC           STATUS,C
                        ADDWF           RxBufMissCount2,F
                        BTFSC           STATUS,C
                        ADDWF           RxBufMissCount3,F
                        MOVFW           rx_substate4
                        ADDWF           RxBufMissCount1,F
                        MOVLW           1
                        BTFSC           STATUS,C
                        ADDWF           RxBufMissCount2,F
                        BTFSC           STATUS,C
                        ADDWF           RxBufMissCount3,F

;add current missing packet count + 1 to the Rx serial number to bring RxSerial1:RxSerial0 up to date
;(missing packet count is the only information about the packet's serial number saved)
                        MOVFW           rx_substate3
                        ADDWF           RxSerial0,F
                        BTFSC           STATUS,C
                        INCF            RxSerial1,F
                        MOVFW           rx_substate4
                        ADDWF           RxSerial1,F

;Commit the packet to the buffer by copying the tentative write pointer to the actual enqueue pointer
                        MOVLW           Rx0wl           
                        ADDWF           rx_substate,W
                        ADDWF           rx_substate,W
                        MOVWF           FSR
                        Move            INDF,RxTwl
                        INCF            FSR,F
                        Move            INDF,RxTwh

;Clear the "buffer empty" flag for the receive buffer to which the packet was addressed
                        Movlf           rx_substate2,0XFE
                        MOVF            rx_substate,F
                        BTFSC           STATUS,Z
                        GOTO            xtlprrbefmrxp
lprrbefmrxp             BSF             STATUS,C
                        RLF             rx_substate2,F
                        DECFSZ          rx_substate,F
                        GOTO            lprrbefmrxp

xtlprrbefmrxp           MOVFW           rx_substate2
                        ANDWF           RxBufEmptyFlags,F
                        
                        GOTO            clear_rx_state








;---------------------------------------------------------------------------------------------------------------------
; Tx state machine dispatch table and handlers
;
; This table is used to jump to the transmit character state-machine state handler for a given tx_state.
; The first entry corresponds to tx_state = 1, the second entry to tx_state = 2, etc.
; Note that there is no entry for tx_state = 0 since that is the idle state.
;
;
;The context for the state handlers is as follows:
;
;   1). The character generated should be written to t232.
;
;   2). Control should be returned to tx_done if an output character was written.  Since tx_done is on a
;       different ROM page, each handler should jump to return_from_tx ... this code fragment will set the
;       page bits and jump to tx_done.
;
;   3). Control should be returned to tx_null if a character was not written.  Each handler should jump
;       to null_tx_return when done if no output was produced.
;
;   4). Additional labels are provided upstream from return_from_tx which perform commonly executed
;       tasks prior to returning as a convenience and to save space in ROM
;
;   5). The normal return methods update the checksums.  If the checksums need to be left alone then
;       use the _noxs versions of the returns.

end_tx                  CLRF            tx_state
                        GOTO            return_from_tx
next_tx_state           INCF            tx_state,W
set_tx_state            MOVWF           tx_state
return_from_tx          LowPage
                        goto            tx_done
                        
null_tx_return          LowPage
                        goto            tx_null


end_tx_noxs             CLRF            tx_state                ;no checksums update versions of returns
                        GOTO            return_from_tx_noxs
next_tx_state_noxs      INCF            tx_state,W
set_tx_state_noxs       MOVWF           tx_state
return_from_tx_noxs     LowPage
                        goto            tx_done_noxs

;
; This dispatch table must be located in same ROM page as the handlers
TxJmpTbl                GOTO            TX_1
                        GOTO            TX_2
                        GOTO            TX_3
                        GOTO            TX_4
                        GOTO            TX_5
                        GOTO            TX_6
                        GOTO            TX_7
                        GOTO            TX_8
                        GOTO            TX_9


TX_1                    Movlf           t232,'@'
                        GOTO            next_tx_state

TX_2                    Movlf           t232,'P'
                        GOTO            next_tx_state

TX_3                    CALL            ReadTxBuf       ;address/length descriptor
                        MOVWF           t232

                        SWAPF           t232,W          
                        MOVWF           tx_substate
                        RRF             tx_substate,F
                        MOVLW           0X07
                        ANDWF           tx_substate,F   ;tx_substate = address

                        MOVLW           0X1F
                        ANDWF           t232,W
                        ADDLW           1
                        MOVWF           tx_substate2    ;tx_substate2 = length

                        CLRF            t232xs
                        CLRF            t232cl
                        CLRF            t232ch
                        GOTO            next_tx_state

TX_4                    CALL            ReadTxBuf       ;low byte of serial number
                        MOVWF           t232
                        GOTO            next_tx_state

TX_5                    CALL            ReadTxBuf       ;high byte of serial number
                        MOVWF           t232
                        GOTO            next_tx_state


;Write one databyte ... note that data needs to be scrambled:
;
;   The body contains the data (1 to 32 bytes, as specified in the header).
;
;   The data bytes themselves are modified via the following algorithm: (using C syntax)
;         output_byte = input_byte ^ (cyclic_checksum & 0xff);
;         apply_to_checksums( input_byte );
;
;   To restore the data to its original value:
;         input_byte = output_byte ^ (cyclic_checksum & 0xff);
;         apply_to_checksums( input_byte );
;
;   This modification of the data is done to prevent packets being sent to cascaded
;   multiplexers from being misinterpreted as packets destined for this multiplexer if the
;   receive logic gets out of phase.

TX_6                    CALL            ReadTxBuf
                        MOVWF           temp            ;save unmodified databyte for checksum computation
                        XORWF           t232cl,W
                        MOVWF           t232
                        MOVFW           temp
                        LowPage
                        CALL            update_tx_checksums     ;compute checksum using unmodified databyte
                        HighPage
                        DECFSZ          tx_substate2,F
                        GOTO            return_from_tx_noxs
                        GOTO            next_tx_state_noxs

TX_7                    Move            t232,t232xs             ;plain checksum
                        GOTO            next_tx_state_noxs

TX_8                    Move            t232,t232cl             ;cyclic checksum low byte
                        GOTO            next_tx_state_noxs

TX_9                    Move            t232,t232ch             ;cyclic checksum high byte
                        MOVLW           1
                        SUBWF           TxBufPCount0,F
                        BTFSS           STATUS,C
                        SUBWF           TxBufPCount1,F
                        GOTO            end_tx_noxs























;---------------------------------------------------------------------------------------------------------------------
; Command-interpreter Rx state machine dispatch table and handlers
;
; This table is used to jump to the receive character state-machine state handler for a given crx_state.
; The first entry corresponds to crx_state = 0, the second entry to crx_state = 1, etc.
;
;
; The context for the state handlers is as follows:
;
;    1). The rCmd register contains the next character from the input stream
;
;    2). Control should be returned to crx_done.  Since crx_done is on a different ROM page, each handler
;        should jump to return_from_crx ... this code fragment will set the page bits and jump to crx_done.
;
;    3). Additional labels are provided upstream from return_from_crx which perform commonly executed
;        tasks prior to returning as a convenience and to save space in ROM
;
;    4). The normal return methods update the checksums.  If the checksums need to be left alone then
;        use the _noxs versions of the returns.


clear_crx_state         CLRF            crx_state
                        GOTO            return_from_crx
next_crx_state          INCF            crx_state,W
set_crx_state           MOVWF           crx_state
return_from_crx         LowPage
                        goto            crx_done


clear_crx_state_noxs    CLRF            crx_state               ;no checksum versions of returns
                        GOTO            return_from_crx_noxs
next_crx_state_noxs     INCF            crx_state,W
set_crx_state_noxs      MOVWF           crx_state
return_from_crx_noxs    LowPage
                        goto            crx_done_noxs


;
; This dispatch table must be located in same ROM page as the handlers
CRxJmpTbl               GOTO            CRX_0
                        GOTO            CRX_1
                        GOTO            CRX_2
                        GOTO            CRX_3
                        GOTO            CRX_4                        
                        GOTO            CRX_5
                        GOTO            CRX_6
                        GOTO            CRX_7
                        GOTO            CRX_8
                        GOTO            CRX_9
                        GOTO            CRX_10
                        GOTO            CRX_11
                        GOTO            CRX_12
                        GOTO            CRX_13
                        GOTO            CRX_14
                        GOTO            CRX_15
                        GOTO            CRX_16
                        GOTO            CRX_17
                        GOTO            CRX_18
                        GOTO            CRX_19
                        GOTO            CRX_20


crxs0                   CLRF            crx_state       ;jump here to reset CRX state and test rCmd from state 0

CRX_0                   MOVFW           rCmd
                        XORLW           '@'
                        BTFSC           STATUS,Z
                        GOTO            next_crx_state_noxs
                        GOTO            return_from_crx_noxs

CRX_1                   MOVFW           rCmd
                        XORLW           'R'
                        BTFSC           STATUS,Z
                        GOTO            next_crx_state_noxs     ;"read" command
                        XORLW           'W' ^ 'R'
                        BTFSC           STATUS,Z
                        GOTO            SET_CRX_7
                        XORLW           'B' ^ 'W'
                        BTFSS           STATUS,Z
                        GOTO            crxs0
                        MOVLW           16
                        GOTO            set_crx_state_noxs      ;"baud rate" command

SET_CRX_7               MOVLW           7                       ;"write" command
                        GOTO            set_crx_state_noxs

;------ Read command ------
CRX_2                   MOVLW           0X1C            ;Address/length byte -- verify that bits 2..4 are zeros
                        ANDWF           rCmd,W
                        BTFSS           STATUS,Z
                        GOTO            crxs0
                        
                        SWAPF           rCmd,W
                Bank1
                        MOVWF           RegXferMCUAddr          ;MCU address is in high 3 bits
                        RRF             RegXferMCUAddr,F
                        MOVLW           7
                        ANDWF           RegXferMCUAddr,F
                Bank0

                        MOVLW           3
                        ANDWF           rCmd,W
                        ADDLW           1
                Bank1
                        MOVWF           RegXferLen
                Bank0
                        
                        CLRF            rCmdxs          ;clear checksums ... checksum will be taken over addr/len byte
                        CLRF            rCmdcl          ;   (this byte) and register start address (next byte)
                        CLRF            rCmdch
                        GOTO            next_crx_state                  


CRX_3                   MOVFW           rCmd            ;register start address
                Bank1
                        MOVWF           RegXferAddr
                Bank0
                        GOTO            next_crx_state
                        
;Checksums of addr/len and register start address bytes
CRX_4                   MOVFW           rCmdxs          ;plain checksum
                        XORWF           rCmd,W
                        BTFSC           STATUS,Z
                        GOTO            next_crx_state_noxs
                        GOTO            crxs0
                        
CRX_5                   MOVFW           rCmdcl          ;low byte of cyclic checksum
                        XORWF           rCmd,W
                        BTFSC           STATUS,Z
                        GOTO            next_crx_state_noxs
                        GOTO            crxs0

CRX_6                   MOVFW           rCmdch          ;high byte of cyclic checksum
                        XORWF           rCmd,W
                        BTFSS           STATUS,Z
                        GOTO            crxs0

;All checksums passed ... the packet was good ... generate a response
;At this point
;   RegXferMCUAddr holds the MCU address,
;   RegXferAddr holds the register address,
;   RegXferLen holds the length
;   rCmdxs, rCmdcl, and rCmdch hold the checksums of the command packet (which must be echoed in the reply)
                        Move            tCmdxs,rCmdxs           ;copy checksums for reply
                        Move            tCmdcl,rCmdcl
                        Move            tCmdch,rCmdch
                        MOVLW           7
                Bank1
                        XORWF           RegXferMCUAddr,W
                Bank0
                        BTFSC           STATUS,Z
                        GOTO            REGREAD_MASTER          ;read from this MCU's register space


;Read from a slave MCU's register space
;Note that if a read command specifies an address for which no slave is installed then the
;firmware will crash.  It is the host computer's responsibility to check the installed slaves
;status byte and not request any transfers to/from non-existent slave MCUs.


                        BTFSS           Flags1,SlaveSelected            ;is a slave addressed?
                        GOTO            nus_rreg

                        MOVFW           SlaveAddress
                        BusChipSelect                           ;tell last slave to "unlisten"
                        BCF             Flags1,SlaveSelected
                        
nus_rreg        Bank1
                        MOVF            RegXferMCUAddr,W
                Bank0
                        IORLW           0X80
                        BusChipSelect                           ;address the slave specified
                        
                        MOVLW           WordBufAddr
                        BusWriteIAddr
                Bank1
                        MOVF            RegXferAddr,W
                Bank0
                        BusWriteIndirect
                Bank1
                        MOVF            RegXferLen,W
                Bank0
                        BusWriteIndirect

                        MOVLW           0
                        BusWriteIAddr                   ;command the slave MCU to perform a read transfer to the Word Buffer

                        MOVLW           WordBuf0
                        BusWriteIAddr
                        BusReadIndirect
                Bank1
                        MOVWF           RegXfer0        ;move data into RegXfer 0..3
                Bank0
                        BusReadIndirect
                Bank1
                        MOVWF           RegXfer1
                Bank0
                        BusReadIndirect
                Bank1
                        MOVWF           RegXfer2
                Bank0
                        BusReadIndirect
                Bank1
                        MOVWF           RegXfer3
                        MOVF            RegXferMCUAddr,W
                Bank0
                        BusChipSelect                   ;"unlisten" the slave

FINISH_CRX_READ         MOVLW           1               ;CTx state for response to read command
                        MOVWF           ctx_state
                        GOTO            clear_crx_state_noxs



;Read a block of registers from this MCU's register space
REGREAD_MASTER  Bank1
                        MOVF            RegXferAddr,W
                Bank0
                        MOVWF           FSR
                        MOVLW           HIGH WBRTT              ;use jump-table to read n bytes to buffer in right-justified fashion
                        MOVWF           PCLATH
                Bank1
                        MOVF            RegXferLen,W
                Bank0
                        ADDLW           LOW WBRTT
                        BTFSC           STATUS,C
                        INCF            PCLATH,F
                ClrI
                        MOVWF           PCL

WBRTT                   GOTO            WBR0
                        GOTO            WBR1
                        GOTO            WBR2
                        GOTO            WBR3
;WBR4                   
                        MOVF            INDF,W
                Bank1
                        MOVWF           RegXfer0
                Bank0
                        INCF            FSR,F
WBR3                    MOVF            INDF,W
                Bank1
                        MOVWF           RegXfer1
                Bank0
                        INCF            FSR,F
WBR2                    MOVF            INDF,W
                Bank1
                        MOVWF           RegXfer2
                Bank0
                        INCF            FSR,F
WBR1                    MOVF            INDF,W
                Bank1
                        MOVWF           RegXfer3
                Bank0
WBR0            SetI
                        GOTO            FINISH_CRX_READ



;------ Write Command ------
CRX_7                   MOVLW           0X1C            ;Address/length byte -- verify that bits 2..4 are zeros
                        ANDWF           rCmd,W
                        BTFSS           STATUS,Z
                        GOTO            crxs0
                        
                        SWAPF           rCmd,W
                Bank1
                        MOVWF           RegXferMCUAddr          ;MCU address is in high 3 bits
                        RRF             RegXferMCUAddr,F
                        MOVLW           7
                        ANDWF           RegXferMCUAddr,F
                Bank0

                        MOVLW           3
                        ANDWF           rCmd,W
                        ADDLW           1
                Bank1
                        MOVWF           RegXferLen
                Bank0
                        
                        CLRF            rCmdxs          ;clear checksums
                        CLRF            rCmdcl
                        CLRF            rCmdch
                        GOTO            next_crx_state                  


CRX_8                   MOVFW           rCmd            ;register start address
                Bank1
                        MOVWF           RegXferAddr
                        MOVF            RegXferLen,W    ;block length (1..4)
                Bank0
                        SUBLW           5
                        ADDWF           crx_state,F     ;State 9 for 4 bytes, state 10 for 3 bytes, etc.
                        GOTO            return_from_crx

CRX_9                   MOVF            rCmd,W
                Bank1
                        MOVWF           RegXfer0
                Bank0
                        GOTO            next_crx_state

CRX_10                  MOVF            rCmd,W
                Bank1
                        MOVWF           RegXfer1
                Bank0
                        GOTO            next_crx_state

CRX_11                  MOVF            rCmd,W
                Bank1
                        MOVWF           RegXfer2
                Bank0
                        GOTO            next_crx_state

CRX_12                  MOVF            rCmd,W
                Bank1
                        MOVWF           RegXfer3
                Bank0
                        GOTO            next_crx_state

CRX_13                  MOVFW           rCmdxs          ;plain checksum
                        XORWF           rCmd,W
                        BTFSC           STATUS,Z
                        GOTO            next_crx_state_noxs
                        GOTO            crxs0
                        
CRX_14                  MOVFW           rCmdcl          ;low byte of cyclic checksum
                        XORWF           rCmd,W
                        BTFSC           STATUS,Z
                        GOTO            next_crx_state_noxs
                        GOTO            crxs0

CRX_15                  MOVFW           rCmdch          ;high byte of cyclic checksum
                        XORWF           rCmd,W
                        BTFSS           STATUS,Z
                        GOTO            crxs0

;All checksums passed ... the packet was good ... write the data and then generate a response


;At this point
;   RegXferMCUAddr holds the MCU address,
;   RegXferAddr holds the register address,
;   RegXferLen holds the length
;   RegXfer0 .. RegXfer3 hold the right-justified block of registers
;   rCmdxs, rCmdcl, and rCmdch hold the checksums of the command packet (which must be echoed in the reply)
                        Move            tCmdxs,rCmdxs           ;copy checksums for reply
                        Move            tCmdcl,rCmdcl
                        Move            tCmdch,rCmdch
                        MOVLW           7
                Bank1
                        XORWF           RegXferMCUAddr,W
                Bank0
                        BTFSC           STATUS,Z
                        GOTO            REGWRITE_MASTER         ;write to this MCU's register space


;Write to a slave MCU's register space
;Note that if a read command specifies an address for which no slave is installed then the
;firmware will crash.  It is the host computer's responsibility to check the installed slaves
;status byte and not request any transfers to/from non-existent slave MCUs.


                        BTFSS           Flags1,SlaveSelected            ;is a slave addressed?
                        GOTO            nus_wreg

                        MOVFW           SlaveAddress
                        BusChipSelect                           ;tell last slave to "unlisten"
                        BCF             Flags1,SlaveSelected
                        
nus_wreg












;------ Testing -- printf( "Block Write %.2X   addr %.2X   len %.2X   %.2X%.2X%.2X%.2X\n", RegXferMCUAddr, RegXferAddr, RegXferLen, RegXfer3, RegXfer2, RegXfer1, RegXfer0 );
;                  to the auxiliary port at address 6
;
;               LowPage
;                       MOVLW           'B'
;                       CALL            WriteRxBuf6
;                       MOVLW           'l'
;                       CALL            WriteRxBuf6
;                       MOVLW           'o'
;                       CALL            WriteRxBuf6
;                       MOVLW           'c'
;                       CALL            WriteRxBuf6
;                       MOVLW           'k'
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           'W'
;                       CALL            WriteRxBuf6
;                       MOVLW           'r'
;                       CALL            WriteRxBuf6
;                       MOVLW           'i'
;                       CALL            WriteRxBuf6
;                       MOVLW           't'
;                       CALL            WriteRxBuf6
;                       MOVLW           'e'
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;               Bank1
;                       SWAPF           RegXferMCUAddr,W
;               Bank0
;                       CALL            WriteNybRB6
;               Bank1
;                       MOVF            RegXferMCUAddr,W
;               Bank0
;                       CALL            WriteNybRB6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;
;                       MOVLW           'a'
;                       CALL            WriteRxBuf6
;                       MOVLW           'd'
;                       CALL            WriteRxBuf6
;                       MOVLW           'd'
;                       CALL            WriteRxBuf6
;                       MOVLW           'r'
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;               Bank1
;                       SWAPF           RegXferAddr,W
;               Bank0
;                       CALL            WriteNybRB6
;               Bank1
;                       MOVF            RegXferAddr,W
;               Bank0
;                       CALL            WriteNybRB6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;
;                       MOVLW           'l'
;                       CALL            WriteRxBuf6
;                       MOVLW           'e'
;                       CALL            WriteRxBuf6
;                       MOVLW           'n'
;                       CALL            WriteRxBuf6                                             
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;               Bank1
;                       SWAPF           RegXferLen,W
;               Bank0
;                       CALL            WriteNybRB6
;               Bank1
;                       MOVF            RegXferLen,W
;               Bank0
;                       CALL            WriteNybRB6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;                       MOVLW           ' '
;                       CALL            WriteRxBuf6
;
;               Bank1
;                       SWAPF           RegXfer3,W
;               Bank0
;                       CALL            WriteNybRB6
;               Bank1
;                       MOVF            RegXfer3,W
;               Bank0
;                       CALL            WriteNybRB6
;               Bank1
;                       SWAPF           RegXfer2,W
;               Bank0
;                       CALL            WriteNybRB6
;               Bank1
;                       MOVF            RegXfer2,W
;               Bank0
;                       CALL            WriteNybRB6
;               Bank1
;                       SWAPF           RegXfer1,W
;               Bank0
;                       CALL            WriteNybRB6
;               Bank1
;                       MOVF            RegXfer1,W
;               Bank0
;                       CALL            WriteNybRB6
;               Bank1
;                       SWAPF           RegXfer0,W
;               Bank0
;                       CALL            WriteNybRB6
;               Bank1
;                       MOVF            RegXfer0,W
;               Bank0
;                       CALL            WriteNybRB6
;
;                       MOVLW           13
;                       CALL            WriteRxBuf6
;                       MOVLW           10
;                       CALL            WriteRxBuf6
;               HighPage
;









                Bank1
                        MOVF            RegXferMCUAddr,W
                Bank0
                        IORLW           0X80
                        BusChipSelect                           ;address the slave specified
                        
                        MOVLW           WordBufAddr
                        BusWriteIAddr
                Bank1
                        MOVF            RegXferAddr,W
                Bank0
                        BusWriteIndirect
                Bank1
                        MOVF            RegXferLen,W
                Bank0
                        BusWriteIndirect

                Bank1
                        MOVF            RegXfer0,W      ;move data from RegXfer 0..3
                Bank0
                        BusWriteIndirect
                Bank1
                        MOVF            RegXfer1,W
                Bank0
                        BusWriteIndirect
                Bank1
                        MOVF            RegXfer2,W
                Bank0
                        BusWriteIndirect
                Bank1
                        MOVF            RegXfer3,W
                Bank0
                        BusWriteIndirect                        

                        MOVLW           0X80
                        BusWriteIAddr                   ;command the slave MCU to perform a write transfer from the Word Buffer
                Bank1
                        MOVF            RegXferMCUAddr,W
                Bank0           
                        BusChipSelect                   ;"unlisten" the slave

FINISH_CRX_WRITE        MOVLW           13              ;CTx state for response to write command
                        MOVWF           ctx_state
                        GOTO            clear_crx_state_noxs



;Write a block of registers to this MCU's register space
REGWRITE_MASTER Bank1
                        MOVF            RegXferAddr,W
                Bank0
                        MOVWF           FSR
                        MOVLW           HIGH WBWTT              ;use jump-table to write n bytes from buffer in right-justified fashion
                        MOVWF           PCLATH
                Bank1
                        MOVF            RegXferLen,W
                Bank0
                        ADDLW           LOW WBWTT
                        BTFSC           STATUS,C
                        INCF            PCLATH,F
                ClrI
                        MOVWF           PCL

WBWTT                   GOTO            WBW0
                        GOTO            WBW1
                        GOTO            WBW2
                        GOTO            WBW3
;WBW4                   
                Bank1
                        MOVF            RegXfer0,W
                Bank0
                        MOVWF           INDF
                        INCF            FSR,F
WBW3            Bank1
                        MOVF            RegXfer1,W
                Bank0
                        MOVWF           INDF
                        INCF            FSR,F
WBW2            Bank1
                        MOVF            RegXfer2,W
                Bank0
                        MOVWF           INDF
                        INCF            FSR,F
WBW1            Bank1
                        MOVF            RegXfer3,W
                Bank0
                        MOVWF           INDF
                        INCF            FSR,F
WBW0            SetI
                        GOTO            FINISH_CRX_WRITE



;------ Baud rate change command ------
CRX_16                  MOVLW           0X6C            ;TXSTA value XOR'd with 0X6C
                        XORWF           rCmd,F
                        MOVF            rCmd,W
                Bank1
                        MOVWF           RegXfer0        ;stash TXSTA value here for now
                Bank0

                        CLRF            rCmdxs          ;clear checksums
                        CLRF            rCmdcl
                        CLRF            rCmdch
                        GOTO            next_crx_state

CRX_17                  MOVLW           0X35            ;SPBRG value XOR'd with 0X35
                        XORWF           rCmd,F
                        MOVF            rCmd,W
                Bank1
                        MOVWF           RegXfer1        ;stash SPBRG value here for now
                Bank0
                        GOTO            next_crx_state

;Checksums of TXSTA and SPBRG
CRX_18                  MOVFW           rCmdxs          ;plain checksum
                        XORWF           rCmd,W
                        BTFSC           STATUS,Z
                        GOTO            next_crx_state_noxs
                        GOTO            crxs0
                        
CRX_19                  MOVFW           rCmdcl          ;low byte of cyclic checksum
                        XORWF           rCmd,W
                        BTFSC           STATUS,Z
                        GOTO            next_crx_state_noxs
                        GOTO            crxs0

CRX_20                  MOVFW           rCmdch          ;high byte of cyclic checksum
                        XORWF           rCmd,W
                        BTFSS           STATUS,Z
                        GOTO            crxs0

;All checksums passed ... the packet was good ... reset baud rate
                        CLRF            RCSTA           ;shut off serial port so its logic resets
                        BTFSS           Flags1,SlaveSelected            ;is a slave addressed?
                        GOTO            nus_rbr
                        MOVFW           SlaveAddress
                        BusChipSelect                           ;tell last slave to "unlisten"
                        BCF             Flags1,SlaveSelected                    
nus_rbr                 LowPage
                        GOTO            RESET_BAUD











;---------------------------------------------------------------------------------------------------------------------
; Command interpreter Tx state machine dispatch table and handlers
;
; This table is used to jump to the transmit character state-machine state handler for a given ctx_state.
; The first entry corresponds to ctx_state = 1, the second entry to ctx_state = 2, etc.
; Note that there is no entry for ctx_state = 0 since that is the idle state.
;
;
;The context for the state handlers is as follows:
;
;   1). The output character should be written to tCmd
;
;   2). Control should be returned to ctx_done if an output character was written.  Since ctx_done is on a
;       different ROM page, each handler should jump to return_from_ctx ... this code fragment will set the
;       page bits and jump to ctx_done.
;
;   3). Control should be returned to ctx_null if a character was not written.  Each handler should jump
;       to null_ctx_return when done if no output was produced.
;
;   4). Additional labels are provided upstream from return_from_ctx which perform commonly executed
;       tasks prior to returning as a convenience and to save space in ROM
;
;   5). The normal return methods update the checksums.  If the checksums need to be left alone then
;       use the _noxs versions of the returns.

end_ctx                 CLRF            ctx_state
                        GOTO            return_from_ctx
next_ctx_state          INCF            ctx_state,W
set_ctx_state           MOVWF           ctx_state
return_from_ctx         LowPage
                        goto            ctx_done
                        
null_ctx_return         LowPage
                        goto            ctx_null


end_ctx_noxs            CLRF            ctx_state               ;no-checksums versions of returns
                        GOTO            return_from_ctx_noxs
next_ctx_state_noxs     INCF            ctx_state,W
set_ctx_state_noxs      MOVWF           ctx_state
return_from_ctx_noxs    LowPage
                        goto            ctx_done_noxs
                        

;
; This dispatch table must be located in same ROM page as the handlers
CTxJmpTbl               GOTO            CTX_1
                        GOTO            CTX_2
                        GOTO            CTX_3
                        GOTO            CTX_4
                        GOTO            CTX_5
                        GOTO            CTX_6
                        GOTO            CTX_7
                        GOTO            CTX_8
                        GOTO            CTX_9
                        GOTO            CTX_10
                        GOTO            CTX_11
                        GOTO            CTX_12
                        GOTO            CTX_13
                        GOTO            CTX_14


;-----------
;Send "read registers" response
CTX_1                   MOVLW           '@'
                        MOVWF           tCmd
                        GOTO            next_ctx_state_noxs

CTX_2                   MOVLW           'r'
                        MOVWF           tCmd
                        GOTO            next_ctx_state_noxs

CTX_3                   MOVF            tCmdxs,W                ;Checksum previously saved from the command packet now being replied to
                        MOVWF           tCmd
                        GOTO            next_ctx_state_noxs

CTX_4                   MOVF            tCmdcl,W
                        MOVWF           tCmd
                        GOTO            next_ctx_state_noxs

CTX_5                   MOVF            tCmdch,W
                        MOVWF           tCmd
                        CLRF            tCmdxs
                        CLRF            tCmdcl
                        CLRF            tCmdch
                Bank1
                        MOVF            RegXferLen,W
                Bank0
                        SUBLW           5
                        ADDWF           ctx_state,F             ;goto state 6 for 4-byte transfer, 5 for 3-byte transfer, etc.
                        GOTO            return_from_ctx_noxs

CTX_6           Bank1
                        MOVF            RegXfer0,W
                Bank0
                        MOVWF           tCmd
                        GOTO            next_ctx_state

CTX_7           Bank1
                        MOVF            RegXfer1,W
                Bank0
                        MOVWF           tCmd
                        GOTO            next_ctx_state

CTX_8           Bank1
                        MOVF            RegXfer2,W
                Bank0
                        MOVWF           tCmd
                        GOTO            next_ctx_state

CTX_9           Bank1
                        MOVF            RegXfer3,W
                Bank0
                        MOVWF           tCmd
                        GOTO            next_ctx_state

CTX_10                  MOVF            tCmdxs,W                ;Checksum of data
                        MOVWF           tCmd
                        GOTO            next_ctx_state_noxs

CTX_11                  MOVF            tCmdcl,W
                        MOVWF           tCmd
                        GOTO            next_ctx_state_noxs

CTX_12                  MOVF            tCmdch,W
                        MOVWF           tCmd
                        GOTO            end_ctx_noxs



;-----------
;Send "write registers" response
CTX_13                  MOVLW           '@'
                        MOVWF           tCmd
                        GOTO            next_ctx_state_noxs

CTX_14                  MOVLW           'w'
                        MOVWF           tCmd
                        MOVLW           10
                        GOTO            set_ctx_state_noxs      ;Send checksums previously saved from the command packet now being replied to










;---------------------------------------------------------------------------
; Read one byte from the transmit buffer.
;
; Updates dequeue pointer.
;
ReadTxBuf               SetMemA16
                        Move            PORTD,Txrl
                        ClrMemAClk
                        MOVFW           Txrh
                        SetMemAClk
                        MOVWF           PORTD
                        SetMemCE1
                        SetMemOE                        ;note -- CE1 and OE are on different ports so its ok to do read-modify-write back-to-back

                        INCF            Txrl,F          ;this pointer needs to be incremented sooner or later and here is a good place to do it
                        BTFSC           STATUS,Z        ;since a delay has to come between asserting OE and reading the data
                        INCF            Txrh,F

                        MOVFW           PORTB
                        ClrMemOE
                        ClrMemCE1
                        RETURN


;---------------------------------------------------------------------------
; Write one byte to one of the receive buffers.
;
; Precondition:
;
;    The tentative enqueue pointer (RxTwl, RxTwh) points to the next location
;    within the buffer to be written.
;
;    W contains the databyte to be written to the buffer.
;
;
; Postcondition:
;
;    W has been written to [RxTwh:RxTwl].
;
;    The tentative enqueue pointer has been incremented.
;
;
; Modifies:
;    FSR (= TRISB)

WriteRxBuf              MOVWF           PORTB
                        ClrMemA16
                        Move            PORTD,RxTwl
                        ClrMemAClk
                        MOVFW           RxTwh
                        SetMemAClk
                        MOVWF           PORTD
                        Movlf           FSR,TRISB
                        CLRF            INDF
                        SetMemCE1
                        SetMemWr                        ;note -- CE1 and OE are on different ports so its ok to do read-modify-write back-to-back

                        INCF            RxTwl,F         ;increment the tentative enqueue pointer
                        BTFSS           STATUS,Z        ;Carry out of low byte?
                        GOTO            wrxbuf_noihbp   ;   no, no need to increment high byte

                        INCF            RxTwh,F
                        MOVLW           0X1F            ;check for a carry from bit 4 to bit 5 (high 3 bits are buffer address ... low 5 are offset)
                        ANDWF           RxTwh,W
                        BTFSS           STATUS,Z        ;Carry from bit4 to bit5 ?
                        GOTO            wrxbuf_noihbp   ;   no, done

                        DECF            RxTwh,F         ;   yes, restore the high 3 bits and clear the low 5 bits
                        MOVLW           0XE0            
                        ANDWF           RxTwh,F

wrxbuf_noihbp           ClrMemWr
                        ClrMemCE1
                        DECF            INDF,F

                        RETURN




                        END


Source Code        Old Source Code        Older Source Code        Subtree        Local home        Home