mirror of
https://github.com/PDP-10/stacken.git
synced 2026-03-04 18:33:52 +00:00
307 lines
11 KiB
Plaintext
307 lines
11 KiB
Plaintext
TITLE NULFEK - LOCAL NETWORK "FRONT END" SERVICE ROUTINE - V013
|
||
SUBTTL WEM/ 26 NOV 85
|
||
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.
|
||
;ALL RIGHTS RESERVED.
|
||
|
||
.CPYRT<1978,1988>
|
||
|
||
|
||
XP VNLFEK,013 ;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.STC ; AND IF IT'S OUT OF RANGE STOP
|
||
; (WE DON'T WAKE OR SLEEP.)
|
||
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)
|
||
|
||
|
||
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
|