Google
 

Trailing-Edge - PDP-10 Archives - decuslib20-03 - decus/20-0084/procol.mac
There is 1 other file named procol.mac in the archive. Click here to see a list.

	TITLE PROCOL -- INTERPROCESSOR COMMUNICATIONS OVER AN ASYNCHRONOUS LINE
	SUBTTL	COMMUNICATIONS PROTOCOL ROUTINES

;	P. HURLEY/R. SCHMIDT	MAYNARD, MASS.  OCT-72
;	R. PALM			SYRACUSE, N.Y. JUNE-74

;*** COPYRIGHT 1972,73,74 DIGITAL EQUIPMENT CORP. MAYNARD, MASS. ***


;	THIS MODULE CONTAINS THE ROUTINES WHICH IMPLEMENT THE
;	PROTOCOL FOR COMMUNICATIONS WITH ANOTHER PROCESSOR.
;	IT CONTAINS THE ROUTINES TO SEND AND RECEIVE A
;	MESSAGE.


;	ASSEMBLY INSTRUCTIONS:
;	MUST BE ASSEMBLED WITH PARAMETER FILE COMPRM.MAC
;	.COMPILE COMPRM.MAC+PROCOL.MAC


IFN FTVERSION,<
	CUSTVER==	0	;CUSTOMER VERSION NUMBER
	DECVER==	1	;DEC VERSION NUMBER
	DECMVR==	0	;DEC MINOR VERSION
	DECEVR==	102	;DEC EDIT VERSION

	LOC	137		;SET UP VERSION NUMBER
	BYTE	(3)CUSTVER(9)DECVER(6)DECMVR(18)DECEVR
	RELOC
>
;	DEFINE CONSTANTS


	SOH=	001		;START OF HEADER
	STX=	002		;START OF TEXT (DATA)
	ETX=	203		;END OF TEXT
	ACK=	240		;ACKNOWLEDGE
	NAK=	120		;NOT ACKNOWLEDGE

	SLPTIM=	^D3000		;MSEC TO HIBERNATE BEFORE NEXT TRY
	HNGACK=	^D5000		;M-SEC BEFORE SENDING RETRANSMISSION
	HNGMES=	^D30000		;MSEC TO TRY BEFORE GIVING UP
	TRYMAX=	10		;MAXIMUM NO. OF RETRIES (EITHER TO
				;SEND A MESS. OR TO ACK AN OLD ONE)
	HB.RTC=1B14		;WAKE ON CHARACTER READY
SUBTTL  GENERAL ROUTINES TO HANDLE CHARACTERS AND MESSAGES

;G E T C H R
;CALLED BY	PUSHJ	P,GETCHR
;		ERROR RETURN		;NO CHAR FOUND
;		NORMAL RETURN		;RETURNS CHAR IN CHR

EXTERNAL GETCHR			;ROUTINE TO GET A CHARACTER IN C


;N O C H R
;CALLED BY	PUSHJ	P,NOCHR
;PUTS JOB INTO SLEEP UNTIL CHAR AVAILABLE. TRIES UNTIL TIMEOUT
;OCCURS.

NOCHR:	DEBUG(1)		;NO CHARACTER READY, WAIT FOR ONE
	MSTIME	T1,			;GET CURRENT TIME
	MOVEM	T1,CURTIM#		;STORE FOR LATER USE
	MOVSI	T1,(HB.RTC)		;SETUP WAKE CONDITIONS
	HRRI	T1,SLPTIM		;AND SLEEP TIME
	HIBER	T1,			;WAIT
	JRST	NOHIB			;UUO NOT IMPLEMENTED
CHKTIM:	MSTIME	T1,			;GET DAYTIME
	SUB	T1,CURTIM		;DID WE TRY
	CAIL	T1,SLPTIM		;LONG ENOUGH?
	POPJ	P,			;YES, GIVE ERROR RETURN
	JUMPG	T1,GET1		;CHECK AGAIN IF SLEPT AT ALL
	MOVEI	T1,SLPTIM/5	;NO CHAR IN COMM LINE BUFFER SO
				; MUST BE CHAR IN ANOTHER TTY BUFFER.
	HIBER	T1,		;UNCONDITIONAL WAIT
	  JRST	NOHIB		;UUO NOT IMPLEMENTED
	SOS	T1,LPCNT	;DECREMENT TOTAL WAIT COUNTER
	JUMPE	T1,CPOPJ	;WAITED LONG ENOUGH, ERROR RETURN
GET1:	PUSHJ	P,GETCHR	;TRY TO GET CHAR FROM COMM LINE
	JRST	NOCHR			;STILL NO CHAR THERE.
	JRST	CPOPJ1##		;RETURN WITH CHAR


GET:	MOVEI	T1,5		;INIT LOOP COUNT FOR TIMEOUT
	MOVEM	T1,LPCNT#	; ...
	JRST	GET1		;TRY TO FIND CHAR AND WAIT IF
				; NECESSARY

NOHIB:	MOVEI	T1,SLPTIM/^D1000	;SLEEP TIME IN SECONDS
	SLEEP	T1,		;SLEEP
	JRST	CHKTIM			;CHECK ELAPSED TIME



;P U T C H R
;CALLED BY	MOVE	CHR,CHAR	;CHARACTER IN CHR
;		PUSHJ	P,PUTCHR	;SEND IT

EXTERNAL PUTCHR			;ROUTINE TO SEND ONE CHARACTER OUT
;R C V B C C
;CALLED BY	PUSHJ	P,RCVBCC
;RETURNS NEXT BYTE IN CHR WITHOUT AFFECTING CHECKSUM.
;EXITS IN CASE OF TIMEOUT.

RCVBCC:	DEBUG(2)
	PUSHJ	P,GET		;GET CRC BYTE
	POPJ	P,		;NONE THERE
	MSTIME	TIME,		;RESET TIMER
	JRST	CPOPJ1		;SKIP RETURN


;R C V C H R
;CALLED BY	PUSHJ	P,RCVCHR
;UPDATES ACCUMULATED CHECKSUM.
;RETURNS NEXT CHAR IN CHR OR EXITS IN CASE OF TIMEOUT.

RCVCHR:	DEBUG(3)
	PUSHJ	P,GET		;GET A BYTE
	POPJ	P,		;NONE THERE
	MSTIME	TIME,		;RESET TIMER
	MOVE	T1,CHR		;COMPUTE CRC:
	XOR	T1,CRC		;MAKE 8 BIT INDEX
	ANDI	T1,377		;CLEAR UNWANTED BITS
	LSH	CRC,-10		;SHIFT CRC 8 BITS
	XOR	CRC,CRCTAB(T1)	;UPDATE IT
	JRST	CPOPJ1		;RETURN WITH CHAR
;S A C K
;CALLED BY	MOVE	T1,MSN		;MESSAGE NUMBER IN T1
;		PUSHJ	P,SACK		;SEND ACKNOWLEDGE

SACK:	MOVEM	T1,LMNACK	;SAVE LAST MESSAGE NUMBER ACKED
	IORI	T1,ACK			;BUILD MESS. IDENT.
SACK1:	MOVEM	T1,MSI			;STORE IT
	DEBUG(4)
	SETZ	CRC,			;CLEAR CRC
	MOVEI	CHR,SOH		;GET START OF HEADER CHARACTER
	PUSHJ	P,SNDCHR		;1ST BYTE OUT
	MOVE	CHR,MSI
	PUSHJ	P,SNDCHR		;2ND BYTE OUT
	ROT	CRC,-10			;GET BCC0
	MOVE	CHR,CRC
	PUSHJ	P,PUTCHR		;SEND IT. DO NO CRC
	ROT	CRC,10			;RESTORE CRC
	MOVE	CHR,CRC
	PUSHJ	P,PUTCHR		;SEND BCC1
	PUSHJ	P,CLRINP##		;CLEAR ANY CHARACTERS IN INPUT BUFFER
	PUSHJ	P,PUTOUT##	;OUTPUT THE MESSAGE
	JRST	CPOPJ		;RETURN

;S N A K
;ENTERED BY	JRST	SNAK
;NOT ACKNOWLEDGES CURRENT MESSAGE, RETURNS TO RCVNXT.
;THE MESSAGE NUMBER IN THE NAK IS THE MESSAGE NUMBER EXPECTED
;AND NOT THE MESSAGE NUMBER ACTUALLY RECEIVED.  THE MESSAGE NUMBER IN
;THE NAK SHOULD BE IGNORED.


SNAK:	DEBUG(5)
	SKIPGE	T1,MSN		;GET MESSAGE NUMBER. IS IT FLOATING ?
	SETZ	T1,		;YES. SEND ZERO AS MESSAGE NUMBER
	IORI	T1,NAK		;MESS. IDENTIFICATION
	PUSHJ	P,SACK1		;SEND NAK MESSAGE
	MOVEI	CNT,MSLMAX	;RESET COUNTER
	JRST	RCVNXT		;GET NEXT MESSAGE


;SANLDDCBH	ROVE	CHR,CHAR		;CHARACTER IN CHR
;		PUSHJ	P,SNDCHR
;SENDS A BYTE AND UPDATES CYCLIC REDUNDANCY CHECK.

SNDCHR:	DEBUG(6)
	MOVE	T1,CHR		;SAVE CHR FOR CRC
	PUSHJ	P,PUTCHR	;SEND BYTE
	XOR	T1,CRC		;COMPUTE CRC
	ANDI	T1,377
	LSH	CRC,-10
	XOR	CRC,CRCTAB(T1)
	JRST	CPOPJ		;RETURN
	SUBTTL	ROUTINE TO GENERATE INITIAL CRC TABLE

;T A B G E N
;CALLED BY	PUSHJ	P,TABGEN
;GENERATES CRCTAB (256 WORDS) WITH 16 BIT BYTE DEPENDENT
;CRC RIGHT JUSTIFIED. BIT 35 IS 1 IFF BYTE HAS ODD PARITY.
;MUST BE CALLED AT INITIALIZATION.

	ENTRY	TABGEN

TABGEN:	MOVEI	CHR,377		;START WITH LAST BYTE
CRCNXT:	MOVEI	T2,7		;HERE ONCE FOR EACH BYTE
	MOVE	CRC,CHR		;GET CURRENT CHAR
CRCSHF:	LSHC	CRC,-1		;SHIFT IT AND
	SKIPGE	CRC+1		;CHECK RIGHT END BIT
	XORI	CRC,120001	;HERE IF BIT WAS ON
	SOJGE	T2,CRCSHF	;NEXT BIT
	MOVEM	CRC,CRCTAB(CHR)	;STORE CRC
	SOJGE	CHR,CRCNXT	;NEXT BYTE
CPOPJ:	POPJ	P,		;NON-SKIP RETURN
	SUBTTL	PROTOCOL INITIALIZATION ROUTINE

;I N I T P R
;INITIALIZE THE PROTOCOL ROUTINES.
;PERFORM ANY OTHER INITIALIZATION REQUIRED FOR LOCAL ROUTINES.
;MUST BE CALLED AT INITIALIZATION.
;CALLING SEQUENCE:
;	PUSHJ	P,INITPR
;	ALWAYS RETURN HERE

	ENTRY	INITPR

INITPR:

;SET THE MESSAGE NUMBER TO -1.
;THE RECEIVE ROUTINE INTERPRETS THIS TO MEAN THAT IT SHOULD SET THE
;MESSAGE NUMBER TO THE ONE RECEIVED IF THE MESSAGE RECEIVED WAS
;CORRECT.  THE SEND ROUTINE WILL INCREMENT THE MESSAGE NUMBER BY
;ONE BEFORE SENDING A MESSAGE.  THEREFORE, IF THESE ROUTINES SEND
;THE FIRST MESSAGE AFTER INITIALIZATION, ITS MESSAGE
;NUMBER WILL BE ZERO (0).

	SETOM	MSN		;FLOAT THE MESSAGE NUMBER
	SETZM	PRSTAT		;CLEAR PROTOCOL STATUS WORD
	PUSHJ	P,TABGEN	;GENERATE THE INITIAL CRC TABLE
	MOVSI	T1,STATBL	;SETUP TO CLEAR THE PERFORMANCE
	HRRI	T1,STATBL+1	; STATISTICS TABLE ENTRIES TO ZERO
	MOVEI	T2,STATLN-1	;GET LENGTH OF TABLE -1
	SETZM	STATBL		;CLEAR THE FIRST ENTRY
	JUMPLE	T2,.+2		;ALL DONE IF ONLY ONE
	BLT	T1,STATBL(T2)	;CLEAR THE REMAINDER OF THE TABLE
IFN FTSNOI,<
	MOVEI	T1,NAK		;SETUP NAK WITH ZERO MSG. NUMBER
	PUSHJ	P,SACK1		;SEND IT OUT.
>
	POPJ	P,		;RETURN TO CALLER
	SUBTTL	CSTAT - ROUTINE TO RETURN THE COMMUNICATIONS PERFORMANCE STATISTICS

	ENTR	(CSTAT)		;ENTRY POINT TO GET PERFORMANCE STATISTICS
	SAVE	(HIAC)		;SAVE TEMP REGISTERS
	SKIPA	T1,[XWD -STATLN,STATBL] ;AOBJN POINTER FOR ENTRIES

GETST:	AOJ	L,		;POINT TO NEXT ARGUMENT
	MOVE	0,(T1)		;GET THE STATISTIC VALUE
	MOVEM	0,@(L)		;RETURN IT TO THE CALLER
	AOBJN	T1,GETST	;FOR ALL TABLE ENTRIES

	JRST	EXIT1		;RETURN TO CALLER
SUBTTL  RECV - TO RECEIVE MESSAGES FROM ANOTHER PROCESSOR

;R E C V 

COMMENT                                                        %
CALL FROM COBOL:

	77 NUMBER
	77 FLAG
	77 TYPE

	01 DUMMY
	   02 ARRAY OCCURS 211 TIMES
	...
	ENTER MACRO RECV USING ARRAY, NUMBER, FLAG, TYPE.
	...

COBOL SHOULD GENERATE THE FOLLOWING MACRO CODE:
REQUIRES COBOL COMPILER VERSION 5 OR LATER

	MOVEI	16,ARGLST
	PUSHJ	17,RECV


	XWD	-4,0
ARGLST:	ARG	[ARRAY]
	ARG	0,NUMBER
	ARG	0,FLAG
	ARG	0,TYPE

RECV		RECEIVES MESSAGES FROM ANOTHER PROCESSOR.

		EXTRACTS THE DATA AND STORES THEM AS 8 BIT BYTES
		RIGHT JUSTIFIED IN ARRAY. CONTINUES UNTIL EITHER
		THE  NUMBER'TH  BYTE HAS BEEN STORED,  OR A TIME-
		OUT OCCURS.

		RETURNS IN FLAG -1, IF THE REQUEST HAS COMPLETELY
				   BEEN SATISFIED.
			       N, IF  THERE  OCCURED  A TIMEOUT
				   AFTER THE N'TH BYTE WAS PROPER-
				   LY RECEIVED.

A TIMEOUT OCCURS, WHEN WITHIN 30 SECONDS
		NO SOH COULD BE RECOGNIZED BY RCVMES, OR
		NO CHARACTER AT ALL COULD BE RECEIVED.         %
	ENTR	(RECV)		;ENTRY POINT TO RECEIVE A MESSAGE
	SAVE	(HIAC)		;SAVE TEMP ACS
	MOVEI	T1,@(L)		;GET ARRAY ADDRESS (1ST ARGUMENT)
	ARYREF	(T1)		;GET REAL ARRAY ADDRESS
	HRLI	T1,TXTBUF
	MOVEM	T1,BLTPTR	;INITIALIZE BLT POINTER
	AOJ	L,		;INCREMENT ARG POINTER
	MOVE	T1,@(L)		;GET 2ND ARG
	MOVEM	T1,NUMBER	;SAVE IT
	AOJ	L,		;INCREMENT ARG POINTER
	MOVEI	T1,STDMR	;DATA MESSAGE RECEIVED BY SEND
	TDNN	T1,PRSTAT	;IS IT WAITING ?
	SKIPGE	T1,MSN		;OR MESSAGE NUMBER FLOATING ?
	JRST	RECV0		;YES. DON'T UPDATE MSG NO.
	AOJ	T1,		;UPDATE MESS NO.
	ANDI	T1,17		;TRUNCATE TO 4 BITS
	MOVEM	T1,MSN		;SAVE 4 BIT MESSAGE NUMBER
RECV0:	SETZM	FLAG		;ZERO NO. OF PROPERLY RECEIVED CHARS
	SETZM	RESEND		;AND RESEND COUNTER
RCVNXT:	DEBUG(7)
	MSTIME	TIME,		;INITIALIZE TIMER
RCVNX1:	MOVEI	CNT,MSLMAX	;INITIALIZE COUNTER
	MOVEI	T1,STDMR	;DATA MESSAGE ALREADY RECEIVED
	TDNN	T1,PRSTAT	;DOES CONDITION REALLY EXIST ?
	JRST	RCVNX2		;NO. GET THE DATA MESSAGE
	ANDCAM	T1,PRSTAT	;YES. CLEAR INDICATION
	JRST	RCVNX3		;USE DATA ALREADY COLLECTED
RCVNX2:	PUSHJ	P,RCVMES	;GO RECEIVE A MESSAGE
	JRST	NOMESS		;THERE WASN'T A COMPLETE ONE
	SKIPE	T1,ACKCHR	;DID WE GET AN ACKNOWLEDGEMENT INSTEAD?
	JRST	CHKACK		;YES, GO HANDLE IT
RCVNX3:	MOVE	T1,MSNRCV	;NOW CHECK MESSAGE NUM
	CAME	T1,MSN		;IS THIS THE CORRECT MESSAGE
	JRST	BADMSN		;NO. CHECK OTHER POSSIBLE CONDITIONS
	DEBUG(21)
	PUSHJ	P,SACK		;ACKNOWLEDGE
RCVOK:	DEBUG(22)
	SETZM	RESEND
	MOVE	CNT,CCRCV#	;GET TEXT COUNT
	CAMLE	CNT,NUMBER	;GET ALL DATA BYTES WANTED?
	MOVE	CNT,NUMBER	;YES. RETURN ONLY THOSE ASKED FOR
	ADDM	CNT,FLAG	;NO. OF PROPERLY RECEIVED BYTES
	MOVE	T1,BLTPTR	;GET BLT POINTER
	HRRZ	T2,T1		;SET UP LAST BLT ADDRESS
	ADD	T2,CNT
	BLT	T1,-1(T2)	;TRANSFER TO USER'S ARRAY

IFE FTMRCV,<			;RECEIVE ONE MESSAGE PER REQUEST
	JRST	RCVXIT		;TAKE SUCCESSFUL RETURN
>
IFN FTMRCV,<			;RECEIVE MULTIPLE MESSAGES IN 1 REQUEST
	MOVN	T1,CNT		;DECREMENT CHAR REQUEST COUNT BY
	ADDM	T1,NUMBER	; NUMBER RECEIVED
	SKIPG	NUMBER		;MORE BYTES WANTED?
	JRST	RCVXIT		;NO.
	ADDM	CNT,BLTPTR	;YES. UPDATE BLT POINTER
	AOS	T1,MSN		;NO. OF NEXT MESS.
	ANDI	T1,17		;CLEAR CARRY
	MOVEM	T1,MSN
	JRST	RCVNXT		;GET IT
>

RCVXT1:	SKIPGE	MSN		;MESSAGE NUMBER FLOATING ?
	JRST	RCVXT2		;YES. DON'T TOUCH IT
	SOS	T2,MSN		;NO. MESSAGE NUMBER INCREMENTED AND NOT USED
	ANDI	T2,17		;DECREMENT TO PRESERVE MESSAGE NUMBER
	MOVEM	T2,MSN		;SYNCHRONIZATION
RCVXT2:	TDZA	T2,T2		;ERROR EXIT, SET IERR TO 0
RCVXIT:	SETO	T2,		;SUCCESSFUL EXIT, SET IERR TO -1
	MOVEM	T2,@(L)		;STORE ERROR FLAG
	AOJ	L,		;INCREMENT ARG POINTER
	MOVE	T2,FLAG		;GET ERROR TYPE 
	MOVEM	T2,@(L)		;SET UP FLAGWORD (ITYPE)
EXIT1:	AOJ	L,		;SET UP RETURN ADR
	RESTOR	(HIAC)		;RESTORE ACS
	JRST	EXIT%%		;RETURN TO CALLER THRU EXIT ROUTINE
;	HERE IF GOT WHAT LOOKED LIKE AN ACKNOWLEDGEMENT MESSAGE.
;	THAT IS, THE HIGH ORDER 4 BITS OF THE SECOND MESSAGE CHARACTER
;	(MESSAGE IDENTIFIER) ARE NONZERO AND THE NEXT TWO CHARACTERS ARE
;	A CORRECT CRC.
;	REGISTER T1 CONTAINS THE ACKNOWLEDGEMENT CHARACTER (ACKCHR)
;	RETURNED BY RCVMES.

CHKACK:	CAIN	T1,ACK_<-4>	;IS THIS A VALID ACK ?
	JRST	BADAKN		;YES. IGNORE
	CAIE	T1,NAK_<-4>	;IS THIS A VALID NAK ?
	JRST	NOMESS		;NO. BAD MESSAGE (NAK IT)
BADAKN:	MOVEI	T1,UEXPAK	;UNEXPECTED ACKNOWLEDGEMENT
	AOS	STATBL(T1)	;RECORD THAT IT OCCURRED
	JRST	RCVNXT		;IGNORE TO AVOID ACK/NAK LOOPS


;	HERE IF GOT ERROR RETURN FROM RCVMES.

NOMESS:	DEBUG(24)
	CAIGE	CNT,MSLMAX	;HAVE WE RECEIVED ANY LEGAL CHARACTERS
	JRST	SNAK		;YES, SEND A NAK OUT
	DEBUG(25)
	MSTIME	T1,		;GET CURRENT TIME
	SUB	T1,TIME		;CALCULATE TIME SINCE START
	CAIGE	T1,HNGMES	;HAVE WE WAITED LONG ENOUGH
	JRST	RCVNX1		;NO.  TRY AGAIN
	DEBUG(26)
	JRST	RCVXT1		;YES. GIVE TIMED OUT ERROR RETURN


;	HERE IF RECEIVED MESSAGE NUMBER DOES NOT AGREE WITH WHAT
;	WAS EXPECTED.

BADMSN:	DEBUG(27)
	CAMN	T1,LMNACK	;MESSAGE NO. SAME AS LAST ONE ACKED ?
	JRST	RLMNAR		;YES. COUNT IT, REACKNOWLEDGE, AND TRY AGAIN
	AOS	STATBL+NRESET	;NO. ASSUME A RESTART IN OTHER SYSTEM
	MOVEM	T1,MSN		;AND INITIALIZE MESSAGE NUMBER TO THE ONE RECEIVED
	PUSHJ	P,SACK		;SEND AN ACK OF THIS MESSAGE NUMBER
	JRST	RCVOK		;GO BACK TO MAIN STREAM

RLMNAR:	AOS	STATBL+NACKR	;RECEIVED LAST MESSAGE ACKED. COUNT IT
	PUSHJ	P,SACK		;SEND OUT AN ACK FOR IT
	JRST	RCVNXT		;THEN GO WAIT FOR THE RIGHT MESSAGE
;ROUTINE TO RECEIVE MESSAGES OR ACK/NAK'S
;CALLED BY:	PUSHJ P,RCVMES
;		ERROR RETURN		;NO CORRECT MESSAGE RECIEVED
;		NORMAL RETURN
;ON RETURN:
;  IF DATA MESSAGE		MSNRCV	CONTAINS RECEIVED MESSAGE NUMBER
;				ACKCHR	CONTAINS ZERO (0)
;  IF ACKNOWLEDGEMENT MESSAGE	ACKCHR	CONTAINS ACKNOWLEDGE CHARACTER
;				ACKMSN	CONTAINS ACKNOWLEDGE MESSAGE NO.

RCVMES:

;CHECK FOR START OF HEADER.

RCVSOH:	DEBUG(10)
	SETZ	CRC,			;INITIALIZE CRC
	PUSHJ	P,RCVCHR		;GET A BYTE
	POPJ	P,			;TIMED OUT
	CAIN	CHR,SOH			;IS IT SOH?
	SOJG	CNT,RCVMSN		;YES. CHECK MESS. NO.
BADCHR:	DEBUG(11)
	JRST	RCVSOH		;GO WAIT FOR A SOH

;CHECK MESSAGE IDENTIFICATION. EXPECTED NUMBER IS MSN.

RCVMSN:	DEBUG(12)
	PUSHJ	P,RCVCHR		;GET A BYTE
	POPJ	P,			;TIMED OUT
	SETZM	ACKCHR#			;INITIALIZE FLAG
	TRNE	CHR,360			;IS THIS AN ACK OR A NAK?
	JRST	CHKMSI			;POSSIBLY
	MOVEM	CHR,MSNRCV#		;STORE MESSAGE NUMBER
	SOJG	CNT,RCVCC		;YES. CHECK CC
	JRST	BADCHR		;RECEIVED TOO MANY CHARACTERS

;FROM HERE ON, A DATA MESSAGE IS EXPECTED.
;CHECK CHARACTER COUNT (ODD PARITY, COUNT.LE.TXLMAX).

RCVCC:	DEBUG(13)
	PUSHJ	P,RCVCHR		;GET A BYTE
	POPJ	P,			;TIMED OUT
IFN	FTODCC,
<	MOVE	T1,CRCTAB(CHR)		;LOOK INTO TABLE
	TRNN	T1,1			;WHETHER BYTE HAS
					;ODD PARITY.
	JRST	BADCHR			;IT HASN'T.
	ANDI	CHR,177			;GET CHAR COUNT
>
	CAILE	CHR,TXLMAX		;TOO MANY?
	JRST	BADCHR			;YES.
	MOVEM	CHR,CCRCV		;SAVE COUNT
	MOVN	T2,CHR			;FOR DATA POINTER
	HRLI	T2,TXTBUF	;SET UP TO SEND OUT TEXT
	SOJG	CNT,RCVSTX	;STILL GOT ROOM
	JRST	BADCHR		;NO, TOO MANY CHARACTERS RECEIVED

;CHECK START OF TEXT.

RCVSTX:	DEBUG(14)
	PUSHJ	P,RCVCHR		;GET A BYTE
	POPJ	P,			;TIMED OUT
	SOSLE	CNT			;RECEIVED TOO MANY CHARS YET?
	CAIE	CHR,STX			;IS IT STX?
	JRST	BADCHR			;NO.

;READ IN TEXT AND STORE IN TXTBUF.

	MOVSS	T2			;DATA POINTER IN CNT
RCVTXT:	DEBUG(15)
	PUSHJ	P,RCVCHR		;GET A DATA ITEM
	POPJ	P,			;TIMED OUT
	MOVEM	CHR,(T2)		;STORE IT
	SOSG	CNT
	POPJ	P,			;RECEIVED TOO MANY CHARACTERS!
	AOBJN	T2,RCVTXT		;NEXT DATA ITEM

;CHECK FOR ETX

RCVETX:	DEBUG(16)
	PUSHJ	P,RCVCHR		;GET A BYTE
	POPJ	P,			;TIMED OUT
	SOSLE	CNT			;MESSAGE TOO LONG?
	CAIE	CHR,ETX			;IS IT ETX?
	POPJ	P,			;NO.

;CHECK CRC. USE RCVBCC INSTEAD RCVCHR TO NOT INCLUDE
;BCC0 AND BCC1 IN CHECKSUM.

RCVBC0:	DEBUG(17)
	PUSHJ	P,RCVBCC		;GET A BYTE
	POPJ	P,			;TIMED OUT
	LSHC	CRC,-10			;GET HIGH ORDER PART OF CRC
	SOSLE	CNT
	CAME	CRC,CHR			;OK?
	POPJ	P,			;NO.
	LSHC	CRC,10			;RESTORE CRC
	ANDI	CRC,377			;GET LOW ORDER PART
	DEBUG(20)
	PUSHJ	P,RCVBCC		;GET A BYTE
	POPJ	P,			;TIMED OUT
	CAME	CRC,CHR			;CRC OK?
	POPJ	P,			;NO
	MOVE	T1,MSNRCV	;GET MESSAGE NUMBER RECEIVED
	SKIPGE	MSN		;IS THE MESSAGE NUMBER FLOATING ?
	MOVEM	T1,MSN		;YES. INITIALIZE TO THE VALUE RECEIVED
	JRST	CPOPJ1		;MESSAGE OK. GIVE SKIP RETURN
;	COME HERE IF RECEIVED MESSAGE IDENTIFICATION CHARACTER
;	(SECOND MESSAGE CHAR.) LOOKED LIKE IT MAY INDICATE AN
;	ACKNOWLEDGEMENT MESSAGE.

CHKMSI:	LDB	T1,ANPTR	;GET ACK FIELD
	MOVEM	T1,ACKCHR	;STORE FOR LATER
	DEBUG(35)
	ANDI	CHR,17		;CLEAR ACK FIELD
	MOVEM	CHR,ACKMSN#	;STORE MSN NUMBER
	SOJG	CNT,CHKBCC	;GO GET CRC
	JRST	BADCHR		;TOO MANY CHARACTERS RECEIVED

CHKBCC:	DEBUG(36)
	PUSHJ	P,RCVBCC	;GET CRC 1
	POPJ	P,		;NONE THERE GIVE ERROR RETURN
	LSHC	CRC,-10		;SHIFT IT
	SOSLE	CNT		;CHECK COUNT
	CAME	CRC,CHR		;IS THIS CHARACTER CORRECT
	JRST	BADCHR		;NO

	LSHC	CRC,10		;RESTORE ORIGINAL CRC
	ANDI	CRC,377		;CLEAR LEFTMOST BITS
	PUSHJ	P,RCVBCC	;GET LOW ORDER CRC BITS
	POPJ	P,		;NONE THERE
	CAME	CRC,CHR		;IS THIS CHARACTER OK
	JRST	BADCHR		;NO
	JRST	CPOPJ1		;YES, GIVE SKIP RETURN
SUBTTL  SEND - TO SEND MESSAGES TO ANOTHER PROCESSOR

	ENTR	(SEND)		;ENTRY POINT TO SEND A MESSAGE
	SAVE	(HIAC)		;SAVE TEMP ACS
	MOVEI	T2,@(L)		;GET ARRAY ADDRESS (1ST ARGUMENT)
	ARYREF	(T2)		;GET CORRECT ARRAY ADDR. IF NECESSARY
	MOVEM	T2,ARYPTR	;STORE AS ARRAY POINTER
	AOJ	L,		;ADVANCE  ARG POINTER
	MOVE	T1,@(L)		;GET NUMBER OF CHARACTERS TO SEND
	MOVEM	T1,NUMBER	;STORE IT
	AOJ	L,		;ADVANCE ARG POINTER
	MOVEI	T1,STDMR	;DATA MESSAGE BEEN RECEIVED BUT NO
	TDNN	T1,PRSTAT	; ACKNOWLEDGEMENT SENT ?
	JRST	SEND0		;NO. JUST SEND THE MESSAGE
	ANDCAM	T1,PRSTAT	;YES. CLEAR THE FLAG
	MOVE	T1,MSNRCV	;GET MESSAGE NUMBER RECEIVED
	IORI	T1,NAK		;MAKE A NAK MESSAGE IDENTIFIER
	PUSHJ	P,SACK1		;NAK THE DATA MESSAGE. MAYBE THE CALLER
				; WILL GET THE IDEA EVENTUALLY AND CALL
				; RECV TO GET THE MESSAGE BEFORE IT GETS LOST.
	JRST	SEND1		;USE THE SAME MESSAGE NUMBER AGAIN
SEND0:	AOS	T1,MSN		;UPDATE MESS NO.
	ANDI	T1,17		;TRUNCATE MSN TO 4 BITS
	MOVEM	T1,MSN		;SAVE TRUNCATED MSN
SEND1:	SETZM	FLAG		;ZERO NUMBER OF CHARS XMITTED
	SETZM	RESEND		;ZERO RESEND COUNT

;	UPON ARRIVING HERE, T2 MUST CONTAIN THE ADDRESS OF THE FIRST
;	CHARACTER IN THE ARRAY TO BE SENT (SEE SNDTXT-1).

SNDNXT:	DEBUG(30)
	MOVEI	T1,TXLMAX		;TO SET UP CC
	CAMLE	T1,NUMBER		;MORE THAN TXLMAX CHAR'S LEFT?
	MOVE	T1,NUMBER		;NO. THIS IS LAST MESS.
	MOVEM	T1,CCSEND#		;SAVE CHAR COUNT

;SEND THE MESSAGE.
;SEND SOH:

	SETZ	CRC,			;INITIALIZE CRC
	MOVEI	CHR,SOH		;GET START OF HEADER CHARACTER
	PUSHJ	P,SNDCHR	;SEND IT OUT

;SEND MSN:

	MOVE	CHR,MSN		;GET MSN
	PUSHJ	P,SNDCHR	;SEND IT OUT

;SEND CC, ODD PARITY:

	MOVE	CHR,CCSEND	;GET CHARACTER COUNT
IFN	FTODCC,
<	MOVE	T1,CRCTAB(CHR)
	TRNN	T1,1			;HAS BYTE ODD PAR?
	TRO	CHR,200			;NO. MAKE IT ODD
>
	PUSHJ	P,SNDCHR	;SEND OUT CHARACTER COUNT

;SEND STX:

	MOVEI	CHR,STX		;GET START OF TEXT
	PUSHJ	P,SNDCHR	;SEND STX OUT

;SEND THE TEXT (CC BYTES):

	MOVN	T1,CCSEND		;POINTER
	HRL	T2,T1			;ARRAY ADDR IN T2
SNDTXT:	MOVE	CHR,(T2)	;GET NEXT CHARACTER TO SEND
	PUSHJ	P,SNDCHR	;SEND IT
	AOBJN	T2,SNDTXT	;LOOP BACK FOR MORE

;SEND ETX:

	MOVEI	CHR,ETX		;GET END OF TEXT CHARACTER
	PUSHJ	P,SNDCHR	;SEND OUT ETX

;SEND BCC0:

	ROT	CRC,-10		;GET HIGH ORDER CRC BITS
	MOVE	CHR,CRC		;...
	PUSHJ	P,PUTCHR	;SEND OUT BCC1

;SEND BCC1:

	ROT	CRC,10		;GET LOW ORDER CRC BITS
	MOVE	CHR,CRC		;...
	PUSHJ	P,PUTCHR	;SEND OUT BCC2
IFN FTCIBS,<			;CLEAR INPUT BEFORE SENDING MESSAGE
	PUSHJ	P,CLRINP##	;CLEAR THE TTY INPUT BUFFER
>
	PUSHJ	P,PUTOUT	;SEND OUT THE MESSAGE

;RECEIVE AN ACK OR NAK MESSAGE:

	DEBUG(31)
	MSTIME	TIME,		;READ CURRENT TIME FOR TIMEOUT PURPOSES
RCVACK:	MOVEI	CNT,MSLMAX	;INITIALIZE COUNT TO MAX MESSAGE SIZE
	SETZM	NAKFLG		;INITIALIZE NAK FLAG
	PUSHJ	P,RCVMES		;GET ACK OR NAK
	JRST	NOACK			;NONE THERE
	SKIPN	T1,ACKCHR		;WAS THIS AN ACK/NAK
	JRST	GOTMES			;NO, IT WAS ANOTHER LEGAL MESSAGE
	CAIN	T1,ACK_-4		;IS THIS AN ACK?
	JRST	CHKMSN			;YES
	CAIE	T1,NAK_-4		;IS THIS A NAK?
	JRST	NOACK			;NO, THIS IS A BAD MESSAGE
	SETOM	NAKFLG			;MARK THAT A NAK WAS SEEN
CHKMSN:	MOVE	T1,ACKMSN	;GET MSN RECEIVED
	CAMN	T1,MSN		;IS THIS THE ONE WE EXPECT
	SKIPE	NAKFLG		;AND WAS THIS AN ACK
	JRST	BADACK		;NO, GO RESEND

;ACKNOWLEDGE RECEIVED. CHECK FOR MORE CHAR'S TO BE SENT.

SNDMOR:	DEBUG(37)
	MOVN	T1,CCSEND	;GET CHARACTERS SENT COUNT
	SUBM	T1,FLAG		;COUNT CHARS SUCCESSFULLY RECEIVED
	ADDM	T1,NUMBER	;SUBTRACT FROM NUMBER LEFT
	SKIPG	NUMBER		;ANY MORE TO GO OUT
	JRST	SNDXIT		;NO, WE ARE THROUGH
	SETZM	RESEND		;YES, GO SEND OUT NEXT GROUP
	MOVE	T2,CCSEND	;GET CHARACTERS SENT COUNT
	ADDB	T2,ARYPTR	;UPDATE ARRAY POINTER
	AOS	T1,MSN		;UPDATE MSN
	ANDI	T1,17		;TRUNCATE TO 4 BITS
	MOVEM	T1,MSN		;STORE TRUNCATED MSN
	JRST	SNDNXT		;GO SEND OUT NEXT MESSAGE

NOACK:	DEBUG(40)
	CAIGE	CNT,MSLMAX	;ANY LEGAL CHARACTERS SEEN
	JRST	BADACK		;YES, GO RESEND
NOACK1:	DEBUG(41)
	MSTIME	T1,		;GET TIME
	SUB	T1,TIME		;CALCULATE TIME WAITED
	CAIG	T1,HNGACK	;HAVE WE TIMED OUT
	JRST	RCVACK		;NO, GO WAIT SOME MORE
BADACK:	DEBUG(42)
	AOS	T1,RESEND		;UPDATE COUNTER
	CAIL	T1,TRYMAX		;DID WE TRY ENOUGH?
	JRST	SNDXT1			;YES. QUIT.

;NOT ACKNOWLEDGE RECEIVED. RETRANSMIT MESSAGE.

SNDAGN:	DEBUG(43)
	MOVE	T2,ARYPTR		;NO
	JRST	SNDNXT		;GO RETRANSMIT THE MESSAGE


;HERE IF WAITING FOR ACK OR NAK BUT GOT A DATA MESSAGE

GOTMES:	MOVE	T1,MSNRCV	;GET MSN RECEIVED
	CAMN	T1,MSN		;IS IT WHAT WE ARE TRYING TO SEND ?
	JRST	SNDXT0		;YES, GIVE ERROR RETURN. CALL RECV FOR A MSG
	MOVEI	T2,NIGNS	;ASSUME MESSAGE IS TO BE IGNORED
	CAME	T1,LMNACK	;IS MESSAGE NO. SAME AS THE LAST ONE ACKED?
	JRST	GOTMS2		;NO. THEN COUNT AND IGNORE THIS MESSAGE
				;YES, THEN SEND OUT AN ACK FOR THIS MSN
	PUSHJ	P,SACK		;THE OTHER PROGRAM PROBABLY LOST OUR ACK
	MOVEI	T2,NACKS	;POINT TO MESSAGE REACKNOWLEDGED BY SEND ENTRY
GOTMS2:	AOS	STATBL(T2)	;INCREMENT THE STATISTICS ENTRY
	JRST	NOACK1		;NOW GO WAIT SOME MORE

;	EXIT POINT FOR SEND ROUTINE

SNDXT0:	MOVEI	T2,STDMR	;DATA MESSAGE ALREADY RECEIVED (NO ACK SENT)
	IORM	T2,PRSTAT	;SAVE STATUS FOR RECV
	MOVEI	T2,1		;SET ERROR FLAG TO 1 (FALSE)
	JRST	SNDXT2		;HAVE RECEIVED A VAILD MESSAGE

SNDXT1:	SKIPGE	MSN		;MESSAGE NUMBER FLOATING ?
	JRST	SNDXT3		;YES. DON'T TOUCH IT
	SOS	T2,MSN		;NO. MESSAGE NUMBER INCREMENTED AND NOT USED
	ANDI	T2,17		;DECREMENT TO PRESERVE MESSAGE NUMBER
	MOVEM	T2,MSN		;SYNCHRONIZATION
SNDXT3:	TDZA	T2,T2		;IERR = 0
SNDXIT:	SETO	T2,		;IERR = -1  OK RETURN
SNDXT2:	MOVEM	T2,@(L)		;STORE ERROR FLAG
	AOJ	L,		;INCREMENT ARG POINTER
	MOVE	T2,FLAG		;GET CHARACTER COUNT
	MOVEM	T2,@(L)		;STORE IT IN 4TH ARG (ITYPE)
	JRST	EXIT1		;RETURN TO CALLER
	SUBTTL	STORAGE AREAS

ANPTR:	POINT	4,CHR,31		;TO DECODE MSI
ARYPTR:	Z				;POINTS TO 1ST BYTE IN
					;USER ARRAY TO BE SENT
BLTPTR:	XWD	TXTBUF,0		;TO FILL USER'S ARRAY
FLAG:	Z				;TO COUNT NO. OF ACTUALLY
					;XMITTED BYTES AND TO INDICATE
					;TIMEOUT

PRSTAT:	Z			;PROTOCOL STAUS WORD
; BITS IN RIGHT HALF
  STDMR=	1B35		;DATA MESSAGE RECEIVED (BY SEND ROUTINE)

MSI:	Z				;MESS. IDENTIFICATION
MSN:	Z				;NO. OF CURRENT MESSAGE
NAKFLG:	Z				;IF -1: LAST MESSAGE
					;RECEIVED WAS NAK
NUMBER:	Z				;FOR 2ND ARGUMENT
RESEND:	Z				;NO. OF TRIES OF RETRANSMITS
LMNACK:	Z				;LAST MSG NUMBER POSITIVELY ACKNOWLEDGED
STATBL:	BLOCK	STATLN			;TABLE FOR PERFORMANCE STATISTICS
					;ENTRIES ARE DEFINED IN COMPRM.MAC
CRCTAB:	BLOCK	^D256			;TABLE FOR CRC
TXTBUF:	BLOCK	TXLMAX			;TO STORE TEXT

	END			;END OF PROCOL