commo.asm
;
; FILE NAME COMMO.ASM
;
;------- HPC COMMUNICATION ROUTINES TO & FROM MASTER COMPUTER ---------------
;
; SynPet Personal Electronic Technologies
; 7225 Franklin Road, Boise, Idaho 83709
;
; Created: 8/9/89 LRE
;
;
;
;
;
;----------------------------------------------------------------------------
.chip 16003
.incld GLOBDEFS
;---------------------- MODULE PRIVATE DEFINES ----------------------------
COMMO_STATUS_PORT = 01400H ; Address of commo id & busy bit port.
COMMO_DATA_IN_PORT = 01000H ; Data from PC.
INT_ID_BIT = 01 ; Bit position of id bit.
STX = 02 ; ASCII start of text. Flags msg begin.
COMMO_DATA_OUT_PORT = 01000H ; Adress to send data.
PC_BUSY_BIT = 0 ; PC busy bit.
IN_BUFFER_ROLLOVER = 07FH ; 128 byte buffer.
CGIE_BIT = 06H ; Bit position of global int en copy.
OUT_INT_ID_BIT = 00 ; ID bit position sent to PC.
CLR_BUSY_ADD = 0A000H ; Read or Write this port to clr busy.
LENGTH_BYTE_OFFSET = 01 ; Position of length byte in Q.
RET_STATUS_OFFSET = 03 ; Position of status byte in Q.
FAIL_MSG_LENGTH = 03 ; Length of last mst failed msg.
FAIL_MSG_STATUS = 0FEH ; Status to show last wasn't echoed right.
CMD_OFFSET = 01 ; Position of job code & option in process
; buffer.
;---------------- END OF MODULE PRIVATE DEFINES --------------------------
.sect DATA,ram8
;--------------------- MODULE PRIVATE VARIABLES -----------------------------
.public commo_out_buffer
.public commo_out_ptr
.public bytes_to_send
.public bytes_sent
.public send_next_tx_flag
.public tx_busy
.public two_in_progress
.public commo_in_buffer
.public commo_in_process_ptr
.public commo_in_ptr
.public rx_buff_full
.public strt_new_msg
.public msg_process_buff_ptr
.public msg_process_buffer
.public process_byte_cnt
.public first_process_two_flag
.public job_transfer_cnt
.public cur_transfer_top_ptr
.public cur_transfer_btm_ptr
.public next_q_to_send
.public tx_transfer_ptr
.public commo_out_trnsfr_ptr
.public commo_out_transfer_bytes
commo_out_buffer: .DSB 32 ; Buffer for current msg being sent.
commo_out_ptr: .DSB 1 ; Offset into buffer of next byte to send.
bytes_to_send: .DSB 1 ; Number of bytes in msg.
bytes_sent: .DSB 1 ; Number of bytes of current msg sent already.
last_msg_nok: .DSB 1 ; Flag to indicate last msg had error.
send_next_tx_flag: .DSB 1 ; Tell higher to send next char.
tx_busy: .DSB 1 ; Flag to keep others from messing up current.
two_in_progress: .DSB 1 ; Flag for handling STX vs. data 02.
commo_in_buffer: .DSB 128 ; Receive buffer of 128 bytes.
commo_in_ptr: .DSB 1 ; Pointer to next mt slot in buffer.
commo_in_process_ptr: .DSB 1 ; Pointer to next slot to be processed.
rx_buff_full: .DSB 1 ; Flag set if buffer is full.
ack_byte: .DSB 1 ; Byte to be echoed by higher level if PC busy.
send_ack_flag: .DSB 1 ; Flag to tell higher level to send ack if
; PC busy
old_msg_length: .DSB 1 ; For last byte sent error recovery.
old_msg_status: .DSB 1 ; For last byte sent error recovery.
strt_new_msg: .DSB 1 ; Flag to say send first msg byte.
last_resend: .DSB 1 ; Flag to say resend last after error msg
; is finished.
waiting_for_stx: .DSB 1 ; Flag to tell if need stx to start rx msg
; assembly. INITIALIZE TO 0FFH
msg_process_buff_ptr: .DSB 1 ; Ptr to next slot in rx msg assembly buffer.
msg_process_buffer: .DSB 32 ; Temporary holder for assembly rx msg.
process_byte_cnt: .DSB 1 ; rx bytes still expected for assembly.
first_process_two_flag: .DSB 1 ; rx STX vs data byte flag.
job_transfer_cnt: .DSB 1 ; Number of bytes tranfered to job q.
cur_transfer_top_ptr: .DSB 1 ; Local copy of job q pointer.
cur_transfer_btm_ptr: .DSB 1 ; Likewise.
next_q_to_send: .DSB 1 ; Number of next job q to chk for tx msg.
tx_transfer_ptr: .DSB 1 ; Next byte in to trnsfr to in commo out buffer.
commo_out_trnsfr_ptr: .DSB 1 ; Next byte in q to go to commo out buffer.
commo_out_transfer_bytes: .DSB 1 ; Number of bytes to transfer to tx.
;------------------ END OF MODULE PRIVATE VARIABLES ------------------------
;--------------------- EXTERNAL GLOBAL VARIABLES ---------------------------
.extrn start_of_job_msg_in_queues:BYTE
.extrn job_in_q_top_ptrs:BYTE
.extrn job_in_q_btm_ptrs:BYTE
.extrn buffer_full_errors:BYTE
.extrn jobs_in_q:BYTE
.extrn cancel_in_q:BYTE
.extrn continue_in_q:BYTE
.extrn total_jobs_in_qs:BYTE
.extrn start_of_job_msg_out_queues:BYTE
.extrn msgs_to_send:BYTE
.extrn total_msgs_to_send:BYTE
.extrn job_out_q_btm_ptrs:BYTE
;----------------- END OF EXTERNAL GLOBAL VARIABLES -----------------------
.endsect
;------------------------- START OF MODULE CODE ----------------------------
.sect CODE,rom8
.ipt 1,COMMO_NMI
.public PROCESS_COMMO
.public INIT_COMMO
.public NEW_MESSAGE
.public PROCESS_MSG
;------------------ NON MASKABLE INTERRUPT -------------------------------
; RECEIVES & TRANSMITS TO/FROM XT BUS
COMMO_NMI: ; TX & RX to & from XT bus.
PUSH A ; Going to use A.
PUSH B ; & B.
IFBIT INT_ID_BIT,COMMO_STATUS_PORT.B ; Chk for rx or tx.
JMP RX_HNDLR ; Go receive if bit set.
;-------------- START OF TRANSMIT PART OF NMI ----------------------------
TX_HNDLR: ; Bit cleared means tx ack interrrupt.
IFEQ two_in_progress,#0 ;
JMP CHK_REGULAR ;
IFEQ COMMO_DATA_IN_PORT.B,#2 ; Stx back?
JMP ACK_OK ; Yes - all sympatico.
JMP TX_ERROR ; No - start again.
CHK_REGULAR:
LD A,commo_out_ptr ; Get pointer to next byte.
DEC A ; Point to last byte sent.
LD B,A ; Offset in B.
LD A,COMMO_DATA_IN_PORT.B ; Get the ack byte.
IFEQ A,commo_out_buffer[B].B ; Compare with last sent.
JMP ACK_OK ; Sent back correct byte.
TX_ERROR: ; Fall thru means didn't get back the last byte sent.
IFEQ bytes_sent,bytes_to_send ; See if was last byte.
JMP END_OF_MSG_ERROR ; We'll have to let higher level cancel msg.
; Otherwise we'll restart msg.
LD commo_out_ptr,#0 ; Reset to beginning of buffer.
LD bytes_sent,#0 ; Starting all over.
LD two_in_progress,#0 ; In case it was set.
; Fall thru to send byte.
ACK_OK: ; Check for byte to send & send if is one to send.
; Else tell higher level done with tx.
IFEQ bytes_to_send,bytes_sent ; See if last was sent.
JMP DONE_WITH_TX ; If so, we're done.
CHK_TX_BUSY:
IFBIT PC_BUSY_BIT,COMMO_STATUS_PORT.B ; See if PC ready for int.
JMP DO_TX_BUSY ; Let higher level take care of next send if busy.
; Else send next byte.
SBIT OUT_INT_ID_BIT,PORT_B_LO.B ; ID as tx int.
LD B,commo_out_ptr ; Pointer to next byte to send.
LD A,commo_out_buffer[B].B ; Get the byte.
IFEQ A,#STX ; See if is stx.
JMP TWO_HNDLR ; Takes special handling if it is stx.
; Otherwise go ahead and send it.
SND_BYTE: ; Comes here for send with ptr and bytes sent increment.
LD COMMO_DATA_OUT_PORT.B,A ; Send the byte.
INC commo_out_ptr ; Increment ptr for next.
INC bytes_sent ; Just sent another byte.
JMP RETURN_FROM_NMI ; Done for this time.
TWO_HNDLR:
IFEQ bytes_sent,#0 ; STX will be sent normally.
JMP SND_BYTE ;
IFEQ two_in_progress,#0 ; First of double two.
JMP NEW_TWO ; Yes - go set flag & send.
LD two_in_progress,#0 ; No this is second of pair.
JMP SND_BYTE ; So well send with advanced count & pointer.
NEW_TWO:
LD two_in_progress,#0FFH ;
LD COMMO_DATA_OUT_PORT.B,A ; We send this one --
JMP RETURN_FROM_NMI ; Without advancing count or pointer.
END_OF_MSG_ERROR:
LD last_msg_nok,#0FFH ; Tell higher level to cancel last msg & resend.
LD tx_busy,#0 ; All done with tx.
JMP RETURN_FROM_NMI ; All done with interrupt.
DO_TX_BUSY:
LD send_next_tx_flag,#0FFH ; Let higher level crank up commo when ready.
JMP RETURN_FROM_NMI ; In the meanwhile we'll get out of here.
DONE_WITH_TX:
LD tx_busy,#0 ; Higher level can startup new msg.
JMP RETURN_FROM_NMI ;
;------------------ END OF TRANSMIT PART OF NMI ---------------------------
;------------------ START OF RECEIVE PART OF NMI ---------------------------
RX_HNDLR:
LD A,COMMO_DATA_IN_PORT.B ; Get the byte.
IFEQ rx_buff_full,#0FFH ; Chk for buffer overflow.
JMP RX_BUFF_FULL_ERROR ; Go handle if buffer full.
; Else put in buffer.
BUFFER_NOT_FULL:
LD B,commo_in_ptr ; Get pointer to next in slot.
LD commo_in_buffer[B].B,A ; & store it.
INC commo_in_ptr ; For next.
AND commo_in_ptr,#IN_BUFFER_ROLLOVER ; Circular Q.
INC B ; Going to chk for full buffer.
INC B ;
AND B,#IN_BUFFER_ROLLOVER ;
IFEQ B,commo_in_process_ptr ; Chk for buffer full - 1.
LD rx_buff_full,#0FF ; Can't have equal or we'll mess up ptrs.
SND_ACK: ; Send back char for ack, echo chk, & ready for more.
IFBIT PC_BUSY_BIT,COMMO_STATUS_PORT.B ; See if PC ready for int.
JMP DO_RX_BUSY ; Let higher level take care of next ack if busy.
; Else send next ack.
RBIT OUT_INT_ID_BIT,PORT_B_LO.B ; ID as ack int.
IFEQ rx_buff_full,#0FFH ; See if buffer full.
COMP A ; Send ones complement back if buffer full.
LD COMMO_DATA_OUT_PORT.B,A ; Echo byte.
JMP RETURN_FROM_NMI ; All done.
DO_RX_BUSY: ; Set up for higher level to send ack.
LD send_ack_flag,#0FFH ; Flag for higher.
LD ack_byte,A ; Char for higher to ack with.
JMP RETURN_FROM_NMI ; Let main scan do when PC not busy.
RX_BUFF_FULL_ERROR:
LD B,commo_in_ptr ; Get pointer to next in slot.
INC B ; Going to chk for full buffer.
INC B ;
AND B,#IN_BUFFER_ROLLOVER ;
IFEQ B,commo_in_process_ptr ; Chk for buffer full - 1.
JMP SND_ACK ; Still full - don't clear full.
LD rx_buff_full,#0 ; Clear full flag.
JMP BUFFER_NOT_FULL ; Go ahead & keep char.
;--------------- END OF NMI RECEIVE ROUTINE ----------------------------
RETURN_FROM_NMI:
POP B ; Restore registers.
POP A ;
IFBIT CGIE_BIT,PSW.B ; See if ints enabled when entered.
JMP INT_EN_NMI_RET ; Enable ints on return if were to start.
LD CLR_BUSY_ADD.B,A ; Let PC interrupt again.
RET ; & Return with ints disabled.
INT_EN_NMI_RET:
LD CLR_BUSY_ADD.B,A ; Strobe latch.
RETI ; & Return with ints enabled.
;------------------ END OF NMI ROUTINE ---------------------------------
;------------------- MAIN COMMO SCAN ROUTINE -----------------------------
;COMMENTED FOR TESTING - REMOVE COMMENTS FOR REAL!!!!!!!!!!!!!!!!
PROCESS_COMMO: ; See if communications need any attention.
SND_ACK_CHK: ; See if rx is waiting for scan to send ack.
IFEQ send_ack_flag,#0FFH ;
JMP HI_LVL_SEND_ACK ; Go try to do it if flag set by NMI.
; NOTE! HI_LVL_SEND_ACK JUMPS BACK TO END OF CHECKS TO
; SKIP REST OF CHECKS IF THIS ONE TRUE.
SND_NXT_CHK: ; See if tx is waiting for scan to send next char.
IFEQ send_next_tx_flag,#0FFH ;
JMP HI_LVL_SND_NXT ; Go do it if NMI wants scan to.
; JUMPS TO RETURN AS ABOVE.
SND_LAST_CHK: ; See if nok error sent & ready to send old msg again.
; IFEQ tx_busy,#0FFH ; Don't chk if tx busy.
; JMP LAST_NOK_CHK ;
; IFEQ strt_new_msg,#0FFH ; Don't chk if waiting to send msg.
; JMP LAST_NOK_CHK ;
; IFEQ last_resend,#0FFH ; See if resend just occured.
; JMP RESEND_OLD ;
LAST_NOK_CHK:
; IFEQ last_msg_nok,#0FFH ; See if last char of last msg garbled.
; Can't have strt new & have last nok.
; JSR LAST_NOK ; Will return to same place as others.
CHK_COMMO_IN:
IFEQ commo_in_process_ptr,commo_in_ptr ; See if anything to be
; processed.
JMP CHK_COMMO_OUT ; No - Go check for new msg to send.
JSR PROCESS_RECEIVE ; Yes - go work on.
JMP CHK_COMMO_IN ; Will stay here as long as chars are available.
; Except that once a message is complete the return
; from process receive will be a return & skip.
; Only one message max will be completely processed
; per scan.
CHK_COMMO_OUT:
IFEQ tx_busy, #0FFH ; Check for last msg complete.
RET ; All done if msg in progress.
IFEQ strt_new_msg,#0FFH ; No new msg if waiting for one to get sent.
JMP SEND_NEW ; Try to send if one waiting.
; IFEQ last_msg_nok,#0FFH ; May have happened between chk & now.
; RET ; If so catch next time.
IFEQ total_msgs_to_send.B,#0 ; See if anything in out Q's.
RET ; No - all done.
IFEQ tx_busy,#0FFH ;
RET ;
JSR NEW_MESSAGE ; ; Yes - assemble & start send.
SEND_NEW:
IFEQ tx_busy,#0FFH ;
RET ;
JSR TRY_NEW ; See if can send. Do if PC not busy.
RET ; All done checking commo.
;----------------- END OF MAIN COMMO SCAN ROUTINE -----------------------
;---------- HI LEVEL ROUTINES TO RECOVER FROM NMI PC BUSY -----------------
HI_LVL_SEND_ACK: ; NMI ran into a PC busy so we'll do it.
_DIS_NMI_ ; Can't let NMI in while doing activity based on PC
; busy bit.
IFBIT PC_BUSY_BIT,COMMO_STATUS_PORT.B ; See if PC ready.
JMP HI_LVL_SEND_ACK_RET ; Is busy - we'll try again next time.
; Fall thru means we'll send ack.
RBIT OUT_INT_ID_BIT,PORT_B_LO.B ; ID as ack int.
LD A,ack_byte ; Get the ack byte.
IFEQ rx_buff_full,#0FFH ; See if buffer full.
COMP A ; Send ones complement back if buffer full.
LD COMMO_DATA_OUT_PORT.B,A ; Echo byte.
HI_LVL_SEND_ACK_RET:
_EN_NMI_ ; Turn NMI back on.
JMP CHK_COMMO_IN ; All done - Go check for received chars.
HI_LVL_SND_NXT: ; Send next char if NMI ran into PC busy.
_DIS_NMI_ ; Can't let NMI confuse us.
IFBIT PC_BUSY_BIT,COMMO_STATUS_PORT.B ; See if PC busy.
JMP HI_LVL_SND_NXT_RET ; Try next time if it is.
SBIT OUT_INT_ID_BIT,PORT_B_LO.B ; ID as tx int.
IFEQ two_in_progress,#0FFH ; See if second two is to be sent.
JMP HI_LVL_SEND_TWO ;
LD B,commo_out_ptr ; Get pointer to next to tx.
LD A,commo_out_buffer[B].B ; Get the char.
IFEQ A,#STX ; Chk for a two.
JMP HI_LVL_TWO_HNDLR ; Two's take special handling.
HI_LVL_SND_BYTE:
LD COMMO_DATA_OUT_PORT.B,A ; Send the byte.
LD send_next_tx_flag,#0 ; Skip next.
INC commo_out_ptr ; Set up for next.
INC bytes_sent ; One more gone.
IFEQ bytes_sent,bytes_to_send ; See if we're done.
JMP DONE_WITH_HI_LVL_SND ;
HI_LVL_SND_NXT_RET:
_EN_NMI_ ; Let NMI back in.
JMP CHK_COMMO_IN ; Go back to main scan.
HI_LVL_TWO_HNDLR:
IFEQ bytes_sent,#0 ; First byte is Single STX.
JMP HI_LVL_SND_BYTE ; Go send like regular char.
LD two_in_progress,#0FFH ; Next ack needs advanced ptrs.
LD COMMO_DATA_OUT_PORT.B,A ; Send the byte.
LD send_next_tx_flag,#0 ; Skip next.
INC commo_out_ptr ; Set up for next.
INC bytes_sent ; One more gone.
JMP HI_LVL_SND_NXT_RET ;
HI_LVL_SEND_TWO:
LD two_in_progress,#0 ; Second two is on its way.
LD A,#2 ; Going to send two.
LD COMMO_DATA_OUT_PORT.B,A ; Send byte without advancing pointers.
LD send_next_tx_flag,#0 ; Skip next.
IFEQ bytes_sent,bytes_to_send ; See if we're done.
JMP DONE_WITH_HI_LVL_SND ;
JMP HI_LVL_SND_NXT_RET ;
DONE_WITH_HI_LVL_SND:
LD tx_busy,#0 ; Ready for next msg.
LD send_next_tx_flag,#0 ; Skip next.
JMP HI_LVL_SND_NXT_RET ;
;------------------- END OF PC BUSY RECOVERY ROUTINES ---------------------
;------------ RECOVERY FROM LAST BYTE OF MSG NOT ECHOED RIGHT --------------
LAST_NOK: ; Last msg byte not echoed right - tell PC.
; Save old msg length.
LD old_msg_length,commo_out_buffer+LENGTH_BYTE_OFFSET ;
; Save old msg byte where we're going to put failed status.
LD old_msg_status,commo_out_buffer+RET_STATUS_OFFSET ;
; Set fail msg length.
LD commo_out_buffer+LENGTH_BYTE_OFFSET.B,#FAIL_MSG_LENGTH ;
; Set fail msg status.
LD commo_out_buffer+RET_STATUS_OFFSET.B,#FAIL_MSG_STATUS ;
; Will go back with same job code, but fail status.
; Set up to send.
LD bytes_sent,#0 ;
LD bytes_to_send,#FAIL_MSG_LENGTH+1 ;
; Tell startup procedure to go when PC ready.
LD strt_new_msg,#0FFH ;
; Tell scan to send last when this one is finished.
LD last_resend,#0FFH ;
; Done with nok flag.
LD last_msg_nok,#0 ;
RET ;
RESEND_OLD: ; Last nok error msg has been sent - now resend
; the nok msg.
; Restore old msg length.
LD commo_out_buffer+LENGTH_BYTE_OFFSET.B,old_msg_length ;
; Restore old msg byte to where we had put failed status.
LD commo_out_buffer+RET_STATUS_OFFSET.B,old_msg_status ;
; Set up to send.
LD bytes_sent,#0 ;
LD bytes_to_send,old_msg_length ;
INC bytes_to_send ;
; Tell startup procedure to go when PC ready.
LD strt_new_msg,#0FFH ;
; Tell scan to we're done.
LD last_resend,#0 ;
JMP CHK_COMMO_IN ;
;-------- END OF RECOVERY FROM LAST BYTE NOT ECHOED RIGHT -------------------
;---- START OF TRY NEW - START NEW MSG TRANSMISSION IF PC NOT BUSY ----------
TRY_NEW: ; Start mesg send if PC not busy.
_DIS_NMI_ ; Can't let NMI in while doing activity based on PC
; busy bit.
IFBIT PC_BUSY_BIT,COMMO_STATUS_PORT.B ; See if PC ready.
JMP TRY_NEW_RET ; Is busy - we'll try again next time.
; Fall thru means we'll send char.
SBIT OUT_INT_ID_BIT,PORT_B_LO.B ; ID as tx int.
LD A,#STX ; Start of msg.
LD COMMO_DATA_OUT_PORT.B,A ; Send the byte.
INC bytes_sent ;
INC commo_out_ptr ;
LD tx_busy,#0FFH ; Show we're cranked up.
LD strt_new_msg,#0 ; Have it started now.
TRY_NEW_RET:
_EN_NMI_ ; Turn NMI back on.
RET ; All done - Go back to main scan.
;-------- END OF TRY NEW - START NEW MSG XMT IF PC NOT BUSY ---------------
;----- START OF PROCESS RECEIVE - GET INPUT CHARS & ASSEMBLE INTO MSG ------
PROCESS_RECEIVE: ; Get characters out of rx buffer & assemble into msg.
LD B,commo_in_process_ptr ; Get buffer ptr.
LD A,commo_in_buffer[B].B ; Get char
INC commo_in_process_ptr ; Set for next.
AND commo_in_process_ptr,#IN_BUFFER_ROLLOVER ; Maybe need to dis nmi?
IFEQ waiting_for_stx,#0FFH ; Need first?
JMP PROCESS_STX ; Yes - go do stx stuff.
NOT_WAITING:
IFEQ A,#STX ; See if char is to be checked for data two.
JMP PROCESS_TWO ; Is a two - go chk.
IFEQ first_process_two_flag,#0FFH ; Fall thru means restart msg.
; Cause single STX has been received.
JMP CHK_FOR_NOT_2ND_STX ;
PUT_IN_PROCESS_BUFFER:
LD B,msg_process_buff_ptr ;
LD msg_process_buffer[B].B,A ; Put char in buffer.
IFEQ B,#0 ; See if cnt byte.
LD process_byte_cnt,A ; Set byte count if is.
INC msg_process_buff_ptr ; Set up for next.
SC ; We'll set up for next & see if done.
SUBC process_byte_cnt,#1 ;
IFEQ process_byte_cnt,#0 ; Will be zero if done.
JMP PROCESS_MSG ; Got a whole message - go take care of it.
RET ; Otherwise we're done with this byte.
PROCESS_STX: ; Looking for stx.
IFEQ first_process_two_flag,#0FFH ;
JMP CHK_FOR_NOT_2ND_STX ;
IFEQ A,#STX ; See if char is STX.
LD first_process_two_flag,#0FF ; Set flag if is.
RET ; Return with flag set or not set according to char.
CHK_FOR_NOT_2ND_STX: ; Have received one stx - make sure this is not another.
LD first_process_two_flag,#0 ; Whether STX or not going to clr.
IFEQ A,#STX ; See if char is STX
RET ; Is a second STX - dump in bit bucket & return.
; Fall thru means not stx - must be count byte.
LD waiting_for_stx,#0 ; We have our stx.
LD msg_process_buff_ptr,#0 ; Set ptr to beginning of buffer.
JMP PUT_IN_PROCESS_BUFFER ; Put count byte into buffer.
PROCESS_TWO: ; Handle data two's.
IFEQ first_process_two_flag,#0FFH ; See if second two.
JMP SECOND_TWO ; Yes go do flags & put in buffer.
LD first_process_two_flag,#0FFH ; Is 1st - set flag & return.
RET ; Don't do anything but set flag on first 2;
SECOND_TWO: ; Clear flag & put data 2 in buffer.
LD first_process_two_flag,#0 ;
JMP PUT_IN_PROCESS_BUFFER ;
;------- END OF PROCESS RECEIVE - TAKE INPUT CHARS & MAKE A MSG -----------
;--------- START OF PROCESS MESSAGE - PUT IN JOB QUEUE -------------------
PROCESS_MSG: ; Have a complete message - put it in job q.
LD A,msg_process_buffer+CMD_OFFSET.B ; Get job & option.
AND A,#0F0H ; Mask off option bits. CAREFUL! HARD NUMBER HERE!
PUSH A ; Save a copy.
SHL A ; WATCH OUT ! DEPENDENT ON BUFFER SIZE!!
; Job number * 64 in A.
SHL A ; Have offset into job buffers in A.
LD BP_temp_reg.W,A ; Offset into X.
POP A ; Get job number back.
SWAP A ; Get job number into lower byte.
AND A,#0FH ; Mask off swap garbage.
LD B,A ; Offset into B.
LD A,job_in_q_btm_ptrs[B].B ; Pointer to next byte to be processed
; by job.
DEC A ; Only A can be decremted.
AND A,#JOB_IN_Q_ROLLOVER ; Mod q size.
LD cur_transfer_btm_ptr,A ; For buffer full error chk.
; Get pointer to byte in.
LD A,job_in_q_top_ptrs[B].B ;
LD cur_transfer_top_ptr.B,A ;
PUSH B ; Save index to set new pointer.
LD job_transfer_cnt,#0 ; For loop.
TRANSFER_LOOP:
IFEQ cur_transfer_top_ptr,cur_transfer_btm_ptr ; Chk buffer full.
JMP TRANSFER_BUFFER_FULL_ERROR ; Go error if equal.
; Otherwise transfer byte.
LD B,job_transfer_cnt ; Get byte to transfer.
LD A,msg_process_buffer[B].B ;
LD B,BP_temp_reg.W ; Get base offset.
ADD B,cur_transfer_top_ptr ; Full address of slot.
LD start_of_job_msg_in_queues[B].B,A ; Byte into q.
INC cur_transfer_top_ptr ; Set up for next.
AND cur_transfer_top_ptr,#JOB_IN_Q_ROLLOVER ;
INC job_transfer_cnt ;
IFEQ job_transfer_cnt,msg_process_buffer ; First byte is count.
JMP DONE_WITH_TRANSFER ;
JMP TRANSFER_LOOP ;
DONE_WITH_TRANSFER: ; All of message transfered - clean up for next.
POP B ; Index into pointers back.
IFBIT CANCEL_BIT,A ; A still has last byte & last byte has cancel.
INC cancel_in_q[B].B ; Tell job it has a cancel in the queue.
IFBIT CONTINUE_BIT,A ;
INC continue_in_q[B].B ; Tell job it has a continue.
LD A,cur_transfer_top_ptr.B ; set new q ptr.
LD job_in_q_top_ptrs[B].B,A ;
INC jobs_in_q[B].B ; Show another job to be done.
INC total_jobs_in_qs ; & more total to be done.
RETSK ; All done. Won't process more rx until next time thru
; commo scan.
TRANSFER_BUFFER_FULL_ERROR: ; Tell job it missed a msg.
POP B ; Index into pointers back.
LD A,msg_process_buffer+CMD_OFFSET.B ; Get job code.
LD buffer_full_errors[B].B,A ; & put in errors for error msg.
INC jobs_in_q[B].B ; So will get processed.
INC total_jobs_in_qs ; Likewise.
RETSK ;
;---- END OF PROCESSING INCOMING MSG - HAS BEEN PUT IN JOB QUEUE -----------
;------ NEW MESSAGE - TRANSFER FROM JOB MSG OUT Q TO TX Q -----------------
NEW_MESSAGE:
; First find the first job with a message waiting for tx.
LD B,next_q_to_send ; Next q to chk. Round robin equal priority.
NEXT_TX_TRNSFR_LOOP:
LD A,msgs_to_send[B].B ; Get msgs to send in this q.
IFEQ A,#0 ; See if any msgs this q.
JMP CHK_FOR_NEXT ; No go set up to chk next q.
JMP TRANSFER ; Yes - go get it.
CHK_FOR_NEXT: ; Set up to chk next q.
INC B ; For next q.
IFGT B,#NUMBER_OF_JOBS_ROLLOVER ; Mod rollover.
LD B,#0 ;
JMP NEXT_TX_TRNSFR_LOOP ; Go try next q.
TRANSFER: ; Found the q with a msg. Now put it into the tx buffer.
; Still have job number in B.
LD A,msgs_to_send[B].B ; Get number of msgs in q.
DEC A ; Will be one less in q.
LD msgs_to_send[B].B,A ; For next.
LD A,total_msgs_to_send ; Likewise for total.
DEC A ;
LD total_msgs_to_send.B,A ;
PUSH B ; Save for q base address calc & ptr fetch.
PUSH B ; Save another copy of job number for end.
INC B ; For next time thru chk.
IFGT B,#NUMBER_OF_JOBS_ROLLOVER ; Mod rollover.
LD B,#0 ;
LD next_q_to_send.B,B ;
POP A ; Get job number into A.
LD B,A ; Save another copy in B.
SWAP A ; Job number * 16 in A.
SHL A ; Job number * 32 = base q address in A.
LD BP_temp_reg.W,A ; Save q base address.
; Get pointer to bytes to be transfered.
LD A,job_out_q_btm_ptrs[B].B ;
LD tx_transfer_ptr.B,A ;
LD commo_out_buffer.B,#STX ; Msg starts with STX.
LD commo_out_trnsfr_ptr,#1 ; First byte transferred will go
; after STX.
LD B,BP_temp_reg.W ; Q base address into B.
ADD B,tx_transfer_ptr ; Offset address of count byte in q.
LD A,start_of_job_msg_out_queues[B].B ;
LD commo_out_transfer_bytes.B,A ;
; Number of bytes in msg into transfer bytes.
INC A ; Send will also have STX.
LD bytes_to_send.B,A ; For TX.
TRANSFER_OUT_LOOP:
LD A,start_of_job_msg_out_queues[B].B ; Get byte to transfer.
LD B,commo_out_trnsfr_ptr.B ; Slot in output buffer.
LD commo_out_buffer[B].B,A ; Transfer byte.
INC tx_transfer_ptr ;
AND tx_transfer_ptr,#JOB_OUT_Q_ROLLOVER ; Do rollover.
IFEQ commo_out_trnsfr_ptr.B,commo_out_transfer_bytes ; Done with msg?
JMP DONE_WITH_TX_TRANSFER ; Yes - cleanup & leave.
INC commo_out_trnsfr_ptr ; For next & done check.
LD B,BP_temp_reg.W ; No - Set up for next.
ADD B,tx_transfer_ptr ; New offset address.
JMP TRANSFER_OUT_LOOP ; Do next byte.
DONE_WITH_TX_TRANSFER: ; Set up for next & let main loop start tx.
POP B ; Get job number back into B.
LD A.B,tx_transfer_ptr ; Ptr for next msg this job.
LD job_out_q_btm_ptrs[B].B,A ; Advanced ptr.
LD bytes_sent.B,#0 ; Haven't sent any yet.
LD commo_out_ptr.B,#0 ;
LD strt_new_msg,#0FF ; Tell main loop to send the msg.
RET ; All done.
;------ END OF TRANSFERRING MSG FROM JOB OUT Q TO TX BUFFER --------------
;----------------- INITIALIZE COMMUNICATIONS -----------------------------
INIT_COMMO:
LD waiting_for_stx,#0FF ; Haven't got a msg yet.
SBIT 1,DIRB_LO.B ; B1 pin is output that controls NMI disable.
SBIT OUT_INT_ID_BIT,DIRB_LO.B ; B2 pin is output for int id.
LD CLR_BUSY_ADD.B,A ; Not busy yet.
_DIS_NMI_
RET ;
;----------------- DONE WITH INITIALIZATION -----------------------------
;---------------- END OF COMMUNICATIONS MODULE --------------------------
.endsect
.end