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