Google
 

Trailing-Edge - PDP-10 Archives - BB-JR93N-BB_1990 - 10,7/mon/nulfek.mac
There are 8 other files named nulfek.mac in the archive. Click here to see a list.
TITLE NULFEK - LOCAL NETWORK "FRONT END" SERVICE ROUTINE - V014
SUBTTL	WEM/  17 APR 90
	SEARCH	F,S,NETPRM
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
; 1978,1979,1980,1982,1984,1986,1988,1990.
;ALL RIGHTS RESERVED.

.CPYRT<1978,1990>


XP VNLFEK,014			;PUT VERSION NUMBER IN GLOB AND LOADER MAP

NULFEK::ENTRY	NULFEK

				COMMENT @

     The "null" FEK is intended to behave the same as any normal FEK except
for the fact that any "output" messages it is given are returned as "input"
messages.  This allows the -10 to talk to itself on lonely nights when the
operators have gone home.  Currently it's only use is in the implementation
of local task's.  Whether of not this method is smaller than the local tasks
of yesteryear may be debated.  It's certianly slower.  It has however, the
following redeeming features.

    a)	Task to task may be completly debugged on a singly -10 cpu.  (Even
	the fancy connect processing)

    b)	Common code is used as much as possible.  This means that local
	tasks won't get broken every week.

    c)	I don't have to worry about the case of two 100k user jobs trying
	to talk to each other via local tasks on a 256k machine.  (As far
	as I can tell trying to lock both jobs in core would simply hang
	the system...)

A few things should be mentioned about the code.  First, the code attempts
to perform the proper byte conversion and data compression operations normally
delegated to the front-end -11.  These functions will also be required by the
KS-10 project.  Steal this code.  Second,  one can run the "null" FEK as fast
as one wants simply by putting the call go "NLFCPY" in the approiate place.  I
expect that the optimal place is in the "NLFRDD" and "NLFWRT" routines for
maximum through put, though for controlled debugging, I suggest some less
synchronous place such as a clock interrupt.

				    @
SUBTTL 1.0      NULL FEK ENTRY POINTS.  (VECTORED HERE BY THE FEK BLOCK)

NLFDSP::CAIL	T1,FF.ONC	;RANGE CHECK THE FUNCTION CODE
	CAILE	T1,FF.CPW	;  CODE AND STOP IF BAD
	STOPCD	.,STOP,NULFNC,	;++ FUNCTION CODE OUT OF RANGE
	JRST	@.+1(T1)	;DISPATCH ON FUNCTION CODE
	IFIW	NLFONC		;ONCE ONLY CODE
	IFIW	NTFSEC##	;ONCE/SECOND CODE  (USE NETSER'S DEFAULT)
	IFIW	NLFRDD		;READ REQUEST
	IFIW	NLFWRT		;WRITE REQUEST
	IFIW	NTDSTP##	;CRASH.  SHOULD NEVER HAPPEN
	IFIW	NTDSTP##	;DOWN.  SHOULD NEVER HAPPEN
	IFIW	NTDSTP##	;UP. SHOULD NEVER HAPPEN
	IFIW	CPOPJ##		;STATION CONTROL (WE'RE NOT INTERESTED)
	IFIW	CPOPJ##		;OUR CPU IS GOING TO SLEEP
	IFIW	CPOPJ##		;OUR CPU IS WAKING UP


NLFONC:	MOVSI	T1,FK.ONL!FK.NID!FK.NUL	;GET THE BITS THAT SYSINI CLEARS
	IORB	T1,FEKBLK(J)	;AND SET THEM SO THIS FEK IS "ALIVE"
	POPJ	P,		;THAT'S ALL



NLFRDD:	AOS	FEKBSI(J)	;MARK "INPUT ACTIVE"
	MOVSI	T1,FK.STO	;GET THE "KICK OUTPUT BIT"
	IORM	T1,FEKBLK(J)	;  AND TELL CLOCK LEVEL TO TRY OUTPUT
	POPJ	P,		;WE DON'T CALL NLFCPY HERE BECAUSE
				;  WE WOULD BUILD THE STACK UP TOO HIGH

NLFWRT:;PJRST	NLFCPY		;CALL THE COPY ROUTINE
;NLFCPY	ROUTINE CALLED TO PROCESS ONE OUTPUT PCB AND COPY IT IN TO ONE
; INPUT PCB, FINALLY CALLING FEKINT TWICE SO THAT NETSER NOTICES.
;CALL	MOVEI	J,FEK
;	PUSHJ	P,NLFCPY
;RETURN	CPOPJ			;AFTER CALLING "FEKINT"
;
;REGISTER USAGE FOR THIS IS
;	S :=	USUALLY USED TO PASS THE NEXT CHAR TO BE COPIED
;	T1 :=	THE COUNT OF CHARS TO TAKE FROM THE "OUTPUT" PCB
;	T2 :=	THE BYTE POINTER USED IN REMOVING CHARS FROM THE "OUTPUT" PCB
;	T3 :=	THE COUNT OF CHARS PUT IN THE "INPUT" PCB
;	T4 :=	THE BYTE POINTER USED TO PUT CHARS IN THE "INPUT" PCB
;	P1-P3 :=LOCAL STORAGE FOR THE ROUTINES THAT MUST TO BYTE PACKING.
;	U :=	POINTER TO THE "OUTPUT" PCB (THE ONE WE READ DATA FROM)
;	W :=	POINTER TO THE "INPUT" PCB (THE ONE WE WRITE DATA TO)
;	J :=	POINTER TO THE FEK (AT ENTRY), OR RETURN ADDR FOR "QUICKIES"
;

NLFCPY::JSP	T1,SETUP	;PUSH W, U, S AND SET UP S
NLFCP1:	AOSE	FEKBSO(J)	;TRY TO GET THE OUTPUT INTERLOCK
	JRST	[MOVSI T1,FK.STO;IF THE OTHER CPU IS COPYING,
		 IORM T1,FEKBLK(J);  THEN MAKE SURE HE LOOKS AT US LATER
		 JRST EXIT]	;  AND LEAVE. (1 CPU'S ENOUGH)
	SKIPLE	FEKOCT(J)	;MAKE SURE THERE IS OUTPUT TO GO
	SKIPGE	FEKBSI(J)	;  AND MAKE SURE WE'VE GOT AN INPUT BUFFER
	JRST	[SETOM FEKBSO(J);IF WE CAN'T COPY NOW, CLEAR OUTPUT ACTIVE
		 JRST EXIT]	;  AND EXIT

	HRRZ	U,FEKOAD(J)	;GET THE OUTPUT (WE READ FROM IT) PCB
	HRRZ	W,FEKIAD(J)	;GET THE INPUT (WE WRITE TO IT) PCB
	SETZ	T3,		;WE HAVE COPIED NO BYTES TO THE INPUT PCB
	MOVE	T4,PCBPTR(W)	;BUT THIS IS WHERE WE'LL PUT 'EM WHEN WE DO.
	MOVE	T1,PCBCTR(U)	;THE COUNT OF THE NUMBER OF CHARS IN THE HEADER
	MOVE	T2,PCBPTR(U)	;BYTE POINTER TO THE HEADER SECTION
CPY1:	SOJL	T1,CPY2		;COUNT DOWN THE HEADER CHARS
	ILDB	S,T2		;GET THE NEXT BYTE
	IDPB	S,T4		;STORE IT IN THE "INPUT" PCB
	AOJA	T3,CPY1		;LOOP OVER ALL HEADER CHARS

CPY2:	LDB	T1,PCBPCV##	;GET THE CONVERSION CODE
	CAIL	T1,PCV.NC	;RANGE CHECK
	CAILE	T1,PCV.BN	; IT BEFORE DISPATCHING OFF OF IT
	STOPCD	.,STOP,NULCCR,	;++ CONVERSION CODE OUT OF RANGE
	PUSHJ	P,@[		;DISPATCH TO PROPER COPY ROUTINE
		IFIW	C.NC		;NO CONVERSION/COMPRESSION
		IFIW	C.LP		;LINE PRINTER COMPRESSION
		IFIW	C.BN](T1)	;BINARY CONVERSION
	MOVEM	T3,PCBCTR(W)	;STORE THE COUNT OF CHARS COPIED

	NETOFF			;NO INTERRUPTS WHILE HACKING QUEUES
	HRRZM	U,FEKODN(J)	;STORE THE EMPTIED PCB
	HRRZ	U,PCBBLK(U)	;GET POINTER TO "NEXT" PCB TO BE OUTPUT
	HRRZM	U,FEKOAD(J)	;  AND MAKE IT "FIRST"
	SOS	FEKOCT(J)	;DECREMENT THE NUMBER OF PCB'S TO BE OUTPUT
	NETON			;INTERRUPTS OK NOW

	SETOM	FEKBSI(J)	;CLEAR INPUT ACTIVE
	MOVEI	T1,FI.RDD	;GET THE "INPUT DONE" BIT
	PUSHJ	P,FEKINT##	;LET NETSER GROVEL ON RECYCLED DATA
	MOVEI	T1,FI.ODN	;GET THE "OUTPUT DONE" BIT
	PUSHJ	P,FEKINT##	;LET NETSER CALL US BACK WITH A NEW OUTPUT PCB
	SETOM	FEKBSO(J)	;CLEAR OUTPUT ACTIVE
	JRST	NLFCP1		;GO SEE IF THERE ARE ANY MORE TO DO
;C.NC	ROUTINE TO DO A QUICK "NO COMPRESSION" COPY

C.NC:	MOVE	T1,PCBCT2(U)	;GET THE SECONDARY BYTE COUNT
	MOVE	T2,PCBPT2(U)	;GET THE SECONDARY BYTE POINTER
C.NC1:	SOJL	T1,CPOPJ##	;LOOP OVER ALL CHARACTERS
	ILDB	S,T2		;GET THE NEXT 8 BIT CHAR
	IDPB	S,T4		;AND STORE IT IN THE "INPUT" MESSAGE
	AOJA	T3,C.NC1	;KEEP IT UP UNTIL ALL CHARS COPIED
;C.LP	ROUTINE TO SEND THE SECONDARY DATA OF A PCB WITH LINE PRINTER
; COMPRESSION
;
;DATA FOR LINE PRINTER IS COMPRESSED AS FOLLOWS:
;	1CCCCCCC	CCCCCCC IS CHARACTER
;	01XXXXXX	XXXXXX IS NUMBER OF BLANKS
;	001XXXXX	XXXXX IS REPETITION FOR FOLLOWING CHAR
;
;REGISTER USAGE IS
;	P1 :=	REPEAT COUNT
;	P2 :=	CHAR BEING REPEATED
;	P3 :=	NEXT CHAR (READ HERE AND COMPARED WITH P2)
;
C.LP:	JSP	T1,SAVE4	;PUSH J, P1, P2, P3
	MOVE	T1,PCBCT2(U)	;GET THE SECONDARY BYTE COUNT
	MOVE	T2,PCBPT2(U)	;GET THE BYTE POINTER

	SETZ	P1,		;INITIALIZE THE REPEAT COUNT
	SOJL	T1,RTN4X	;COUNT OFF THE FIRST BYTE
	ILDB	P2,T2		;READ THE FIRST BYTE FOR COMPARISON
LPLOOP:	SOJL	T1,NMATCH	;COUNTING DOWN IS THE SAME AS NO-MATCH
	ILDB	P3,T2		;GET THE NEXT BYTE
	CAIN	P2,(P3)		;IS IT THE SAME AS THE LAST?
	AOJA	P1,LPLOOP	;IF SO, COUNT IT AND CONTINUE
NMATCH:	JUMPE	P1,SINGLE	;IF P1 = 0, THEN ONLY ONE CHAR TO SEND
	AOS	P1		;ACCOUNT FOR THE FIRST CHAR
	CAIN	P2," "		;ARE WE COMPRESSING SPACES?
	JRST	SPACES		;IF SO. TREAT THEM ESPECIAL

CHAR:	CAIG	P1,37		;WAS THIS REPEATED TOO MANY TIMES FOR ONE BYTE
	JRST	CHARX		;NO. WE CAN SEND IT AT ONCE
	MOVEI	S,77		;MAXIMUM REPEAT COUNT
	JSP	J,WRITE8	;SEND THE COUNT
	MOVEI	S,(P2)		;GET THE CHARACTER WE REPEATED
	JSP	J,WRITE8	;AND SEND THAT
	SUBI	P1,37		;INDICATE THAT WE HAVE SEND SOME
	JRST	CHAR		;GO BACK AND SEE IF IT WAS ENOUGH

CHARX:	MOVEI	S,40(P1)	;GET THE REPEAT COUNT
	JSP	J,WRITE8	;SEND THAT
	MOVEI	S,(P2)		;GET THE CHARACTER
	JSP	J,WRITE8	;AND SEND THAT
	JRST	ADVNCE		;COPY P2 := P3, CLEAR P1 AND LOOK FOR MORE.

SPACES:	CAIG	P1,77		;MORE SPACES THAN WE CAN COMPRESS IN 1 BYTE
	JRST	SPACEX		;IF NOT. SEND THE COUNT AND GO BACK TO LOOP
	MOVEI	S,177		;WE CAN SEND 77 IN ONE BYTE.
	JSP	J,WRITE8	;SEND THEM
	SUBI	P1,77		;ACCOUNT FOR THE SPACES SENT
	JRST	SPACES		;AND TRY TO SEND MORE

SPACEX:	MOVEI	S,100(P1)	;GET THE "SPACE" BIT AND THE COUNT
	JSP	J,WRITE8	;SEND THE SPACES
	JRST	ADVNCE		;ADVANCE THE CHARACTERS AND READ SOME MORE

SINGLE:	MOVEI	S,200(P2)	;GET THE "SINGLE CHAR" BIT
	JSP	J,WRITE8	;SEND THE CHARACTER

ADVNCE:	SETZ	P1,		;CLEAR THE REPEAT COUNT
	MOVEI	P2,(P3)		;ADVANCE THE CHARACTER TO MATCH
	JUMPG	T1,LPLOOP	;GO BACK TO LOOP IF THERE ARE MORE CHARS TO DO
	JRST	RTN4X		;OTHERWISE RESTORE THE STACK AND POPJ



;*** FOOTNOTE ***

COMMENT \

     Currently the line-printer compression code does not work.  The code
must be made smart enough to fixup the "CNT" field for the message whose
data it is compressing.  This involves re-parsing the NCL header and poking
in the new "CNT" (Which is NEVER longer.  Either shorter or the same length)

\

;C.BN	ROUTINE TO DO A "BINARY" (IE 12 BIT) COPY.
;	THE BASIC IDEA IS TO USE FANCY BYTE MOTION TO PLACE THE 4 BIT SUB-BYTES

C.BN:	JSP	T1,SAVE4	;PUSH J, P1, P2, AND P3
	MOVE	T1,PCBCT2(U)	;GET THE SECONDARY BYTE COUNT (12 BIT BYTES)
	MOVE	T2,PCBPT2(U)	;GET THE SECONDARY BYTE POINTER.

C.BN1:	SOJL	T1,RTN4X	;IF ALL DONE. RETURN 4 AND POPJ
	ILDB	P1,T2		;GET THE FIRST 12 BITS
	LDB	S,[POINT 8,P1,31]	;SEND THE FIRST 8 BITS (LEAVE 4)
	JSP	J,WRITE8
	SOJL	T1,C.BNX	;IF WE COUNT OUT NOW WE HAVE 4 LEFT.
	ILDB	P2,T2		;GET SECOND 12 BITS
	LDB	S,[POINT 4,P2,27] ;GET 4 LOW BITS FROM NEW 12 BIT BYTE
	DPB	P1,[POINT 4,S,31] ;PUT 4 HIGH BITS IN FROM OLD 12 BIT BYTE
	JSP	J,WRITE8	;SEND THE 8 BITS
	LDB	S,[POINT 8,P2,35] ;GET THE LAST 8 BITS FROM NEW 12
	JSP	J,WRITE8	;SEND THOSE
	JRST	C.BN1		;LOOP UNTIL "OUTPUT" IS EXHAUSTED

C.BNX:	LDB	S,[POINT 4,P1,35] ;HERE WE HAVE 4 BITS LEFT OVER. GET THEM IN S
	LSH	S,4		;MAKE THEM HIGH ORDER BITS. FILL WITH ZEROS
	JSP	J,WRITE8	;SEND THE BYTE
	JRST	RTN4X		;POP STACK AND POPJ
;UTILITY ROUTINES USED BY THE NULL FEK

;WRITE8	ROUTINE TO OUTPUT 8 BITS TO THE "INPUT" PCB
;CALL	MOVE	S,CHAR
;	JSP	J,WRITE8
;RETURN	JRST	(J)
;
WRITE8:	IDPB	S,T4		;STORE THE CHARACTER
	AOJA	T3,(J)		;COUNT IT AND RETURN


;SETUP	SAVE 3 REGISTERS. SETUP S AND RETURN
;CALL	JSP	T1,SETUP
;RETURN	JRST	(T1)
;
SETUP:	PUSH	P,W		;SAVE THE NDB POINTER (OR WHATEVER)
	PUSH	P,U		;SAVE THE PCB POINTER
	PUSH	P,S		;SAVE THE STATUS REGISTER
	HLLZ	S,FEKBLK(J)	;GET THE FLAGS
	JRST	(T1)

;EXIT	RESTORE THE STACK AND POPJ
;
EXIT:	POP	P,S		;RESTORE THE STATUS
	POP	P,U
	POP	P,W
	POPJ	P,

;SAVE4	ROUTINE TO SAVE 4 COMMONLY USED REGISTERS
;CALL	JSP	T1,SAVE4
;
SAVE4:	PUSH	P,J
	PUSH	P,P1
	PUSH	P,P2
	PUSH	P,P3
	JRST	(T1)


;RTN4X	RESTORE THE 4 REGIXTERS AND EXIT (POPJ)
;
RTN4X:	POP	P,P3
	POP	P,P2
	POP	P,P1
	POP	P,J
	POPJ	P,



	XLIST		;DON'T LIST LITERALS
	$LIT
	LIST
	END