mirror of
https://github.com/PDP-10/stacken.git
synced 2026-03-02 01:30:40 +00:00
3733 lines
144 KiB
Plaintext
3733 lines
144 KiB
Plaintext
TITLE D8KINT - SERVICE FOR KMC-11/DUP-11 V105
|
||
SUBTTL W. E. MATSON/TARL/TL 15-DEC-87
|
||
SEARCH F, S, NETPRM, D36PAR
|
||
$RELOC
|
||
$HIGH
|
||
|
||
.DIRECT FLBLST
|
||
|
||
;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 VD8KINT,105
|
||
Comment @ Loose ends.
|
||
|
||
o Worry about 2 lines to same node. Also worry about
|
||
"connected to self". (ie. lines connected together.)
|
||
|
||
End Comment @
|
||
|
||
D8KINT::ENTRY D8KINT
|
||
SUBTTL FEK -- FEK INTERFACE FOR D8KINT
|
||
|
||
;D8KINT FEK INTERFACE. ENTRIES ARE:
|
||
;
|
||
; D8KONC ;INITIALIZATION FOR FEK (ZERO KDL PAGE).
|
||
; D8KSEC ;ONCE A SECOND CODE.
|
||
; D8KRDD ;SET UP A READ REQUEST (NO-OP).
|
||
; D8KWRT ;QUEUE A BUFFER FOR OUTPUT.
|
||
; D8KCRS ;SHUT DOWN A LINE
|
||
; D8KDWN ;NOT USED
|
||
; D8KUP ;NOT USED
|
||
; D8KSTC ;CALLED WITH "U" := STC MESSAGE TO SEND
|
||
;
|
||
;FEKINT IN NETSER IS CALLED WHENEVER
|
||
;
|
||
; A KDL GOES OFFLINE (FF.DWN INTERRUPT)
|
||
; A MESSAGE IS RECEIVED (FF.IN INTERRUPT)
|
||
; AN XMIT MESSAGE IS ACKED (FF.OUT INTERRUPT)
|
||
|
||
D8KDSP::CAIL T1,FF.ONC ;RANGE CHECK FUNCTION
|
||
CAILE T1,FF.CPW ; CODE AND STOP IF BAD
|
||
PUSHJ P,NTDSTP## ;++ ERROR: BAD FUNCTION CODE TO FEK
|
||
JRST @.+1(T1) ;DISPATCH TO APPROPRIATE ROUTINE
|
||
JRST NTFONC## ;ONCE ONLY CODE (USE NETSER'S DEFAULT)
|
||
JRST NTFSEC## ;USE NETSER DEFAULT (FOR NODE ID. ETC)
|
||
JRST D8KRDD ;SET UP A READ REQUEST
|
||
JRST D8KWRT ;SET UP A WRITE REQUEST
|
||
JRST D8KCRS ;CRASH THE FEK (CPU WENT (WILL BE) DOWN?)
|
||
JRST CPOPJ## ;FEK DOWN (NOT USED)
|
||
JRST CPOPJ## ;FEK UP (NOT USED)
|
||
JRST D8KSTC ;CALLED WITH "U := STC MESSAGE TO SEND"
|
||
JRST D8KCRS ;SYSTEM SLEEPING AND
|
||
JRST D8KCRS ; WAKING IS TOO COMPLEX TO THINK ABOUT NOW
|
||
|
||
|
||
D8KCRS: PUSHJ P,NTDSTP## ;THIS SHOULD NEVER EVER HAPPEN. WE
|
||
POPJ P, ; DO BETTER TIMING THAN NETSER. IF
|
||
; IT DOES HAPPEN, SOMETHING IS HORRIBLY
|
||
; WRONG.
|
||
|
||
D8KRDD: AOS FEKBSI(J) ;SET FLAG SAYING WE HAVE AN INPUT BUFFER
|
||
POPJ P, ;KDPINT CALLS US WHEN DATA ARRIVES
|
||
D8KWRT: NETOFF ;FIRST DISABLE INTERRUPTS
|
||
SKIPG FEKOCT(J) ;IF THERE ARE NO MORE MESSAGES,
|
||
JRST NTONPJ## ;THEN WE ARE DONE
|
||
HRRZ T3,FEKOAD(J) ;GET THE ADDRESS OF THE NEXT MSG
|
||
HRRZ T1,PCBBLK(T3) ;GET THE ADDRESS OF THE ONE AFTER IT
|
||
HRRZM T1,FEKOAD(J) ;MAKE THE SECOND THE NEW FIRST
|
||
SKIPN T3 ;IF WE DIDN'T GET A MESSAGE,
|
||
PUSHJ P,NTDSTP## ;THE OUTPUT QUEUE IS MESSED UP
|
||
SOS FEKOCT(J) ;COUNT DOWN ONE LESS MESSAGE
|
||
NETON ;RE-ENABLE THE INTERRUPTS
|
||
SETZM MB.FMS(T3) ;MAKE SURE THIS LOOKS LIKE AN ANF MSG
|
||
MOVEI T1,DC.FQB ;GET THE QUEUE DATA FUNCTION
|
||
MOVE T2,FEKUNI(J) ;GET THE KDL PAGE ADDRESS
|
||
PUSH P,T3 ;SAVE THE MSG POINTER
|
||
PUSHJ P,KDADSP## ;QUEUE THE MESSAGE
|
||
JRST [MOVEI T1,DC.IOF ;GIVE THE NOTIFICATION OF
|
||
MOVE T2,J ; THE OUTPUT NOT DONE
|
||
POP P,T3 ;RESTORE MSG POINTER
|
||
PUSHJ P,D8KK2D ;DO WHATEVER NEEDED
|
||
JRST D8KWRT] ;CHECK FOR MORE
|
||
POP P,T3 ;RESTORE MSG POINTER
|
||
JRST D8KWRT ;AND GO CHECK FOR MORE
|
||
|
||
D8KSTC: SKIPGE T1,FEKBLK(J) ;GET THE FEK'S FLAGS
|
||
POPJ P, ;IF RUNNING, THEN DON'T TAKE THE LINE DOWN
|
||
TLNE T1,FK.MAI ;IF WE'RE IN MAINT MODE
|
||
JRST D8KST1 ; THEN WE CAN JUST QUEUE THE MESSAGE
|
||
MOVEI T1,DC.FSM ;IF NOT IN MAINT MODE, GET FUNCTION
|
||
MOVE T2,FEKUNI(J) ; TO PUT IN MAINT MODE, AND
|
||
PUSHJ P,KDADSP## ; CALL THE DRIVER.
|
||
POPJ P, ;COULDN'T DO ANYTHING, WE DON'T OWN LINE
|
||
MOVSI T1,FK.MAI ;GET THE MAINT BIT
|
||
IORM T1,FEKBLK(J) ; AND SAY WE'RE IN MAINT MODE
|
||
D8KST1: MOVEI T1,DC.FQB ;IF IN MAINT MODE, GET "QUEUE OUTPUT"
|
||
MOVE T2,FEKUNI(J) ; FUNCTION, AND PASS THE
|
||
MOVE T3,U ; BUFFER OFF TO THE DRIVER
|
||
SETZM MB.FMS(T1) ; MAKE SURE IT LOOKS LIKE AN ANF-10 MSG
|
||
PUSHJ P,KDADSP## ;CALL KDPINT TO SEND THE MESSAGE
|
||
JRST [MOVEI T1,DC.IOF ;GIVE THE NOTIFICATION OF
|
||
MOVE T2,J ; THE OUTPUT NOT DONE
|
||
MOVE T3,U ;SET UP MSG POINTER
|
||
PUSHJ P,D8KK2D ;DO WHATEVER NEEDED
|
||
JRST CPOPJ1] ;GIVE GOOD RETURN
|
||
RETSKP ; AND GIVE A GOOD RETURN
|
||
SUBTTL KDPINT - INTERFACE FROM KMC/DUP DRIVER
|
||
|
||
;D8KK2D HERE ON DISPATCH ENTRYS FROM THE KMC-11/DUP-11 KONTROLLER
|
||
;CALL T1 := FUNCTION CODE (BELOW)
|
||
; T2 := FEK/LINE-BLOCK ADDRESS
|
||
; T3 := BUFFER ADDRESS OR BYTE COUNT
|
||
|
||
D8KK2D::CAIL T1,DC.IPU ;FIRST RANGE CHECK THE
|
||
CAILE T1,DC.ICC ; FUNCTION CODE
|
||
PUSHJ P,NTDSTP## ;IF FUNCTION OUT OF RANGE, DUMP IT.
|
||
PUSH P,U ;SAVE AN AC
|
||
PUSH P,J ;AND ANOTHER AC
|
||
MOVE J,T2 ;USE J AS THE FEK ADDRESS
|
||
PUSHJ P,@D8KKKD(T1) ;DISPATCH BASED ON FUNCTION
|
||
POP P,J ;RESTORE ANOTHER AC
|
||
POP P,U ;RESTORE AN AC
|
||
POPJ P, ;BACK TO WHOMEVER
|
||
|
||
D8KKKD: IFIW D8PUP ;(00) PROTOCOL UP (START/STACK COMPLETE)
|
||
IFIW D8PDN ;(01) PROTOCOL DOWN (ALL BUFFERS RETURNED)
|
||
IFIW D8MAI ;(02) MAINT MSG RECEIVED (IMPLIES PDN)
|
||
IFIW D8STR ;(03) START RECEIVED (LEAVE MAINT PROTOCOL)
|
||
IFIW D8ODN ;(04) OUTPUT DONE (MESSAGE SUCCESSFULY SENT)
|
||
IFIW D8OND ;(05) OUTPUT NOT DONE (LINE IS GOING DOWN)
|
||
IFIW D8IDN ;(06) INPUT DONE (T3 := BUFFER ADDRESS)
|
||
IFIW D8RQI ;(07) REQUEST INPUT BUFFER (T3 := BYTE COUNT)
|
||
IFIW NTDSTP## ;(10) NEW LINE CREATION
|
||
IFIW NTDSTP## ;(11) OLD LINE DISSOLUTION
|
||
;D8PUP HERE WHEN PROTOCOL IS ESTABLISHED (START/STACK/ACK COMPLETE)
|
||
; MAKE SURE KONTROLLER IS HONEST AND THEN SET THE FEK ONLINE
|
||
|
||
D8PUP: SKIPGE FEKBLK(J) ;MAKE SURE THE FEK IS OFF-LINE
|
||
PUSHJ P,NTDSTP## ;IF IT'S ONLINE, KONTROLLER IS BUGGY
|
||
MOVSI T1,FK.MAI ;GET BIT AND CLEAR
|
||
ANDCAM T1,FEKBLK(J) ; MAINTENANCE MODE
|
||
MOVSI T1,FK.ONL ;GET BIT AND SET
|
||
IORM T1,FEKBLK(J) ; FEK-IS-ONLINE (WILL SOON QUEUE NODE-ID)
|
||
POPJ P, ;ALL DONE
|
||
|
||
;D8PDN HERE WHEN PROTOCOL IS TERMINATED (TIME-OUT OR WHATEVER)
|
||
; MAKE SURE WE ARE IN PROTOCOL, THEN CLEAR FEK-ONLINE
|
||
|
||
D8PDN: SKIPL FEKBLK(J) ;IF WE THINK THE FEK IS DOWN NOW,
|
||
POPJ P, ;THEN NO NEED TO CALL NETSER
|
||
MOVEI T1,FI.DWN ;GET THE "FEK CRASHED" FUNCTION CODE
|
||
PJRST CALNET ;AND TELL NETSER THE BAD NEWS
|
||
;D8MAI HERE WHEN WE RECEIVE A MAINTENANCE MESSAGE IN NORMAL PROTOCOL
|
||
; AT THIS POINT ALL OUTPUT BUFFERS HAVE BEEN RETURNED
|
||
|
||
D8MAI: SKIPGE FEKBLK(J) ;MAKE SURE WE DON'T THINK THAT
|
||
PUSHJ P,NTDSTP## ; WE ARE UP AND RUNNING.
|
||
MOVSI T1,FK.MAI ;GET AND SET THE
|
||
IORM T1,FEKBLK(J) ; MAINT-MODE BIT (SO WE ALLOC STC BLKS)
|
||
POPJ P, ;DONE. RESTORE AC'S AND LEAVE
|
||
|
||
;D8STR HERE WHEN WE RECEIVE A START MESSAGE WHILE IN MAINTENANCE PROTOCOL
|
||
; AT THIS POINT ALL OUTPUT BUFFERS HAVE BEEN RETURNED.
|
||
|
||
D8STR: MOVEI T1,DC.FIL ;NOW TELL THE KONTROLLER
|
||
MOVE T2,FEKUNI(J) ; TO INITIALIZE ITSELF IN "NORMAL" MODE
|
||
PUSHJ P,KDADSP## ;DO IT
|
||
POPJ P, ;WE NO LONGER OWN THE LINE, NOTHING MATTERS
|
||
MOVSI T1,FK.MAI ;GET AND CLEAR THE MAINT
|
||
ANDCAM T1,FEKBLK(J) ; MODE BIT
|
||
POPJ P, ;RESTORE AC'S AND LEAVE
|
||
|
||
|
||
;D8ODN HERE WHEN A BUFFER HAS BEEN SUCCESSFULLY OUTPUT
|
||
;D8OND HERE WHEN A BUFFER COULD NOT BE SENT (LINE DOWN ETC.)
|
||
; FIGURE OUT IF WE ARE IN MAINT/NORMAL MODE AND EITHER
|
||
; DESTROY OR RETURN THE BUFFER TO NETSER
|
||
|
||
D8ODN:
|
||
D8OND: MOVE T1,FEKBLK(J) ;GET THE FEK STATUS BITS
|
||
TLNE T1,FK.MAI ; AND IF WE ARE IN MAINT MODE
|
||
JRST D8MOD ; THEN GO FREE THE USLESS BUFFER
|
||
MOVEI T1,FI.ODN ;GET THE FEK CODE FOR OUTPUT DONE
|
||
HRRZM T3,FEKODN(J) ;PUT ADDRESS WHERE NETSER LIKES IT
|
||
PJRST CALNET ; AND RETURN THE BUFFER TO NETSER
|
||
|
||
D8MOD: MOVE J,T3 ;PUT ADDRESS OF STD IN "J"
|
||
PJRST GIVSTC## ; AND TELL NETSER TO FREE THE STORAGE
|
||
;D8IDN HERE WHEN A MESSAGE HAS BEEN RECEIVED (T3 := MESSAGE)
|
||
; DETERMINE WHICH MODE WE ARE IN (NORMAL/MAINT) AND FORWARD
|
||
; THE MESSAGE TO NETSER APPROPRIATLY
|
||
|
||
D8IDN: MOVE T1,FEKBLK(J) ;GET THE FEK'S STATUS BITS
|
||
TLNE T1,FK.MAI ;IF WE'RE IN MAINT MODE,
|
||
JRST D8IDNM ;THEN HANDLE MAINT MSGS
|
||
SOS FEKBSI(J) ;IN NORMAL MODE, SAY WE ARE NO LONGER BUSY
|
||
CAME T3,FEKIAD(J) ;MAKE SURE WE GOT THE RIGHT MESSAGE BACK
|
||
PUSHJ P,NTDSTP## ;WRONG MESSAGE RETURNED!
|
||
MOVEI T1,FI.RDD ;FUNCTION CODE IS READ-DONE
|
||
PJRST CALNET ;TELL NETSER
|
||
|
||
D8IDNM: MOVEI T1,FI.STC ;IF IN MAINT MODE, SAY IT'S MAINT DATA
|
||
MOVE U,T3 ;COPY THE POINTER INTO NETSER'S FAVORITE
|
||
PJRST CALNET ; REGISTER, AND CALL NETSER
|
||
|
||
|
||
;D8RQI HERE WHEN THE KONTROLLER WANTS US TO ALLOCATE SPACE FOR
|
||
; AN INCOMING MESSAGE. (SIZE OF MESSAGE IN T3)
|
||
|
||
D8RQI: MOVE T1,FEKBLK(J) ;GET THE FEK STATUS BITS, AND
|
||
TLNE T1,FK.MAI ; IF WE ARE IN MAINT MODE, THEN
|
||
JRST D8RQM ; GIVE THE KONTROLLER MAINT BUFFERS
|
||
MOVE T1,FEKIAD(J) ;GET THE BUFFER (BUT IT MAY NOT BE THERE)
|
||
SKIPGE FEKBSI(J) ;MAKE SURE THERE WAS A BUFFER THERE
|
||
TDCA T1,T1 ;IF THERE WASN'T, SAY WE DIDN'T HAVE ONE
|
||
SETZM MB.FMS(T1) ;MAKE SURE IT LOOKS LIKE AN ANF-10 MSG
|
||
POPJ P, ;CLEAN UP AND RETURN
|
||
|
||
D8RQM: MOVE T1,T3 ;COPY THE REQUESTED LENGTH
|
||
PUSHJ P,GETSTC## ;IF MAINT MODE, GET AN STC BLOCK
|
||
SETZ J, ; IF NONE AVAILABLE, RETURN ZERO
|
||
SKIPE T1,J ;PUT POINTER IN T1 (OR A ZERO IF NO BUFFER)
|
||
SETZM MB.FMS(T1) ;MAKE SURE IT LOOKS LIKE AN ANF-10 MSG
|
||
POPJ P, ; AND RETURN
|
||
SUBTTL UTILITY ROUTINES.
|
||
|
||
;CALNET ROUTINE TO CALL NETSER. PRESERVES REGISTERS THAT NETSER
|
||
; LIKES TO CLOBBER
|
||
;CALL PUSHJ P,CALNET
|
||
;RETURN POPJ P,
|
||
|
||
CALNET: PUSH P,W ;W (NDB)
|
||
PUSH P,F ; F (DDB)
|
||
PUSH P,T4 ; AND T4 (???)
|
||
PUSHJ P,FEKINT## ;CALL NETSER
|
||
POP P,T4 ;AND THEN
|
||
POP P,F ; RESTORE
|
||
POP P,W ; EVERYTHING
|
||
POPJ P, ;AND RETURN
|
||
|
||
|
||
PRGEND ;OF D8KINT.MAC
|
||
TITLE KDPSER - USER INTERFACE FOR KDP CONTROL V001
|
||
SUBTTL W. E. MATSON 12 FEB 80
|
||
SEARCH F, S, NETPRM, D36PAR
|
||
$RELOC
|
||
$HIGH
|
||
|
||
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
|
||
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
|
||
;
|
||
;COPYRIGHT (C) 1981 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
|
||
XP VKDPSER,001
|
||
|
||
Comment @ Loose ends.
|
||
|
||
End Comment @
|
||
|
||
KDPSER::ENTRY KDPSER
|
||
|
||
KDPMXQ==^D10 ;MAXIMUM NUMBER OF INPUT OR OUTPUT MSGS
|
||
; ALLOWED FOR A USER OF THE KDP: DEVICE
|
||
IOSMAI==400 ;IF SET, LINE SHOULD BE USED IN MAINT MODE
|
||
IOSSRM==200 ;IF SET, START WAS RECEIVED IN MAINT MODE
|
||
IOSMRN==100 ;IF SET, NORMAL MSG WAS RECEIVED IN MAINT MODE
|
||
DALBUG==1 ;IF TRUE, THEN WASTE LOTS OF TIME WORKING
|
||
; AROUND LEWINE'S MICRO-CODE BUG
|
||
|
||
|
||
;ERROR BITS RETURNED IN DEVIOS
|
||
; IOIMPM LINE NOW "OWNED" BY THE KDP DEVICE (ANF/DECNET CONTROLS IT)
|
||
; IODTER LINE NOT "STARTED" YET (ONLY HAPPENS IN "NORMAL" MODE)
|
||
; IODERR LINE WENT DOWN (USUALLY IOSSRM OR IOSMRN ARE SET AS WELL)
|
||
; IOBKTL BLOCK TO LARGE -- ONE WAY OR THE OTHER
|
||
SUBTTL KDPDDB - PROTOTYPE DDB FOR THE KDP DEVICE
|
||
|
||
DEFINE X(NAME<%%%OFF>,SIZE<1>),<NAME==:<%%%OFF==%%%OFF+SIZE>-SIZE>
|
||
|
||
%%%OFF==DEVLLD ;INITIALIZE THE OFFSET
|
||
|
||
X DEVKDL ;XWD KDL-ADDRESS, INPUT MSG QUEUE
|
||
X DEVOBC ;COUNT OF OUTPUT BUFFERS OUTSTANDING
|
||
X KDPDBL,0 ;LENGTH OF A KDP DDB
|
||
|
||
PURGE X ;FLUSH THE MACRO
|
||
|
||
|
||
;NOW LAY OUT THE PROTOTYPE DDB
|
||
|
||
DEFINE X(OFFSET,EXPR)< ;MACRO TO SET SELECTED LOCATIONS IN THE BLOCK
|
||
RELOC KDPDDB+OFFSET ;GO TO THE RIGHT WORD
|
||
EXPR ;ASSEMBLE IN THE EXPRESSION
|
||
>
|
||
$LOW ;WE NEED TO LINK THIS IN
|
||
KDPDDB::X DEVCHR,<XWD <6*HUNGST>+DVC2IO,KDLMMS+1> ;BUFFER SIZE
|
||
X DEVSER,<XWD 0,KDPUDS> ;DEFINE NETWORK DISPATCH VECTOR
|
||
X DEVMOD,<XWD DVIN!DVOUT,1_BYTMOD>
|
||
X DEVSTA,<XWD DEPLEN!<.TYKDP*.TYEST>,DEPEVM> ;VARIABLE BUFFERS, NO EVM
|
||
; X DEVCPU,<EXP 707B8> ;SET DEYPCL SO WILL RUN ON ANY CPU.
|
||
X NETLEN,0 ;RESERVE ENOUGH SPACE FOR ENTIRE DDB
|
||
|
||
$HIGH ;BACK TO PURE CODE
|
||
PURGE X ;FLUSH THE MACRO
|
||
SUBTTL KDPUUO -- UUO ENTRY TO KDPSRV
|
||
|
||
;DISPATCH TABLE (FROM UUOCON)
|
||
|
||
JRST CPOPJ## ;(-5) DEVICE OFF LINE
|
||
JRST CPOPJ## ;(-4) SPECIAL ERROR STATUS
|
||
JRST REGSIZ## ;(-3) LENGTH CAN BE GOTTEN FROM DDB
|
||
JRST CPOPJ## ;(-2) INITIALIZE (WE DO IT IN TSTKDP)
|
||
JRST CPOPJ## ;(-1) HUNG DEVICE
|
||
KDPUDS: JRST KDPREL ;(0) RELEASE (MAKE SURE KDL DOESN'T POINT)
|
||
JRST KDPCLO ;(1) CLOSE OUTPUT
|
||
JRST KDPOUT ;(2) OUTPUT
|
||
JRST KDPIN ;(3) INPUT
|
||
;TSTKDP ROUTINE CALLED FROM UUOCON DURING A PHYSICAL DEVICE SEARCH
|
||
;CALL T1 := DEVICE NAME
|
||
;RETURN CPOPJ NOT KDP, NOT IN OPEN UUO, ALREADY ASSIGNED OR NO PRIVS
|
||
; CPOPJ1 F := DDB ADDRESS
|
||
|
||
TSTKDP::HLRZ T2,T1 ;GET THE RH OF THE NAME,
|
||
CAIE T2,'KDP' ; AND IF IT ISN'T "KDP"
|
||
POPJ P, ; THEN GIVE THE ERROR RETURN RIGHT AWAY
|
||
LDB T2,[POINT 9,M,8] ;GET THE OP-CODE OF THE UUO THAT GOT HERE
|
||
CAIE T2,<OPEN>_<-33> ;DON'T ALLOW RANDOM COMMANDS TO BUILD DDB'S
|
||
POPJ P, ;IF NOT AN OPEN UUO, THEN DEVICE NOT THERE
|
||
PUSHJ P,SAVT## ;SAVE THE TEAS
|
||
PUSHJ P,SAVE1## ; AND A PEA
|
||
MOVE P1,T1 ;STORE THE DEVICE NAME IN P1 FOR THE DURATION
|
||
MOVSI T1,JP.POK ;ONE LAST QUICK CHECK, DON'T ALLOW
|
||
PUSHJ P,PRVBIT## ; JUST ANYONE TO USE THE DEVICE.
|
||
CAIA ; ONLY OPR AND POKE ALLOWED.
|
||
POPJ P, ;STUPID BASS AKWARDS UUO
|
||
|
||
;NOW CHECK THE NAME
|
||
LDB T1,KDNMPA ;GET THE MULTI-POINT ADDRESS
|
||
JUMPN T1,CPOPJ## ;THERE BETTER NOT BE ANY. WE DON'T SUPPORT IT
|
||
LDB T1,KDNKDP ;GET THE CONTROLLER NUMBER
|
||
CAIG T1,KDPMAX## ; AND MAKE SURE IT'S BOTH LEAGAL
|
||
SKIPN W,KDPTBL##(T1) ; AND THAT IT EXISTS
|
||
POPJ P, ;IF IT DOESN'T EXIST, USER CAN'T OPEN IT
|
||
LDB T1,KDNKDL ;GET THE LINE NUMBER ON THE KONTROLLER
|
||
CAML T1,KDPDPN(W) ; MAKE SURE THAT THE DUP NUMBER IS
|
||
POPJ P, ; IN RANGE. IF NOT, FAIL
|
||
MOVEI F,KDPKDL(W) ;NOW CALCULATE THE ADDRESS OF THE
|
||
ADD F,T1 ; POINTER TO THE KDL PAGE
|
||
SKIPN F,(F) ;GET THE POINTER,
|
||
POPJ P, ;IF NO POINTER, THEN DUP DOESN'T EXIST
|
||
SKIPE KDLDDB(F) ;SEE IF SOMEONE ELSE OWN'S THE DDB
|
||
JRST CLRFPJ ; IF SO, ZERO F AND RETURN
|
||
|
||
;NOW BUILD A DDB
|
||
MOVEI T2,KDPDBL ;GET THE LENGTH OF A KDP DDB
|
||
PUSHJ P,GETWDS## ; AND ALLOCATE THE SPACE
|
||
JRST CLRFPJ ; IF NOT ENOUGH, GIVE THE FAIL RETURN
|
||
MOVSI T2,KDPDDB ;GET THE ADDRESS OF THE PROTOTYPE
|
||
HRR T2,T1 ; AND A COPY OF THE ADDRESS OF THE NEW ONE
|
||
DDBSRL ;LOCK THE DDB CHAIN
|
||
BLT T2,KDPDBL-1(T1) ;INITIALIZE THE NEW ONE
|
||
HRLM T1,DEVSER+KDPDDB ; AND SET UP THE LINKS
|
||
DDBSRU ;DDB IS IN PLACE, UNLOCK THE DDB CHAIN
|
||
HRLM F,DEVKDL(T1) ;MAKE THE DDB POINT TO THE KDL BLOCK
|
||
EXCH T1,KDLDDB(F) ;MAKE THE KDL BLOCK POINT TO THE DDB
|
||
SKIPE T1 ;JUST A PARANOID CHECK.
|
||
PUSHJ P,NTDSTP## ; I DON'T THINK THIS IS POSSIBLE
|
||
MOVE F,KDLDDB(F) ;GET THE ADDRESS OF THE DDB
|
||
MOVEM P1,DEVNAM(F) ;SET THE DEVICE'S NAME
|
||
RETSKP ; AND GIVE A GOOD RETURN TO DDBSRC
|
||
CLRFPJ: SETZ F, ;CLEAR "F" IF AN ERROR
|
||
POPJ P, ; AND RETURN
|
||
;KDPREL ROUTINE TO PROCESS THE "RELEASE" FUNCTION OF A KDP
|
||
;CALL F := ADDRESS OF THE DDB
|
||
;RETURN CPOPJ ;ALWAYS
|
||
|
||
KDPREL: PUSHJ P,KDPCKO ;SEE IF WE ARE THE LINE'S "OWNER"
|
||
JRST KDPRL1 ;IF NOT, DON'T MESS WITH THE KONTROLLER
|
||
MOVEI T1,DC.FHL ;GET THE "HALT" FUNCTION CODE
|
||
HLRZ T2,DEVKDL(F) ;GET THE ADDRESS OF THE KDL PAGE
|
||
PUSHJ P,KDODSP## ;CALL THE KONTROLLER. TELL HIM TO HALE
|
||
JFCL ;IF WE DON'T OWN THE LINE WE DON'T CARE
|
||
KDPRL1: SKIPE DEVOBC(F) ;ALL BUFFERS SHOULD BE RETURNED BY NOW
|
||
PUSHJ P,NTDSTP## ;SINCE THEY ARE RETURNED BY THE "HALT" CALL
|
||
HLRZ T1,DEVKDL(F) ;CLEAR THE KDL'S POINTER TO THE DDB
|
||
SETZM KDLDDB(T1) ; SO WE DON'T GET ANY MORE INTERRUPTS
|
||
|
||
;NOW FREE ANY MSGS ON THE INPUT QUEUE
|
||
KDPRL2: KDPOFF ;PROBABLY DON'T NEED TO, BUT...
|
||
HRRZ T1,DEVKDL(F) ;GET THE NEXT INPUT MESSAGE
|
||
JUMPE T1,KDPRL3 ;IF NONE, THEN WE ARE DONE
|
||
HRRZ T2,MB.NXT(T1) ;GET THE MESSAGE AFTER THAT ONE
|
||
HRRM T2,DEVKDL(F) ; AND MAKE SURE WE GET IT NEXT
|
||
KDPON ;QUEUE IS CONSISTANT AGAIN
|
||
PUSHJ P,GIVKDB ;RETURN THE BUFFER
|
||
JRST KDPRL2 ; AND GO GET THE NEXT ONE
|
||
|
||
KDPRL3: KDPON ;ALL MESSAGES HAVE BEEN FREED
|
||
POPJ P, ; AND WE'RE DONE
|
||
;ZAPKDP ROUTINE TO DESTROY A KDP DDB
|
||
;CALL F := DDB ADDRESS
|
||
;RETURN CPOPJ
|
||
ZAPKDP::PUSHJ P,KDPREL ;FIRST "RELEASE" IT (IN CASE OF SWAP READ ERR)
|
||
MOVEI T2,KDPDDB ;GET THE STARTING DDB
|
||
ZAPKD1: MOVE T1,T2 ;FOLLOW THE DDB CHAIN
|
||
HLRZ T2,DEVSER(T1) ;NEXT DDB
|
||
SKIPN T2 ;MAKE SURE THAT THE
|
||
PUSHJ P,NTDSTP## ;++ DDB WENT AWAY?
|
||
CAIE T2,(F) ;IS THIS THE ONE
|
||
JRST ZAPKD1 ;NO CONTINUE
|
||
DDBSRL ;LOCK THE DDB CHAIN
|
||
HLRZ T2,DEVSER(F) ;GET THE NEXT DDB
|
||
HRLM T2,DEVSER(T1) ;REMOVE THE DDB LINKS
|
||
DDBSRU ;UNLOCK THE CHAIN
|
||
HRRZ T2,F ;GET THE ADDRESS OF THE DDB
|
||
MOVEI T1,KDPDBL ; AND IT'S LENGTH
|
||
PUSHJ P,GIVWDS## ;FREE THE STORAGE
|
||
POPJ P, ;AND WE'RE DONE.
|
||
;KDPIN ROUTINE TO PROCESS THE IN UUO FOR THE KDP DEVICE
|
||
;CALL F := DDB ADDRESS
|
||
;RETURN CPOPJ ;ALWAYS
|
||
T5==T4+1 ;T5 FOR THE EXTEND INSTRUCTION
|
||
T6==T5+1 ;T6 FOR INDEXED MSD PTRS (DECNET)
|
||
IFN M-T6,<PRINTX ?KDPSER assumes that ACs M and T6 are the same
|
||
PRINTX ?Because it knows that M is OK to trash>
|
||
|
||
KDPIN: PUSHJ P,SAVE2## ;P1 = DEVIAD, P2 = INPUT MESSAGE
|
||
MOVSI S,IOBEG!IO ;CLEAR IOBEG SET "INPUT"
|
||
ANDCAB S,DEVIOS(F) ; FOR NO PARTICULARLY GOOD REASON
|
||
PUSHJ P,KDPCKM ;MAKE SURE WE'RE IN THE CORRECT MODE
|
||
|
||
KILOOP: PUSHJ P,KDPONL ;MAKE SURE THE KMC IS UP
|
||
POPJ P, ; IF NOT, RETURN WITH ERROR BITS SET
|
||
HRRZ P1,DEVIAD(F) ;GET THE ADDRESS OF THE INPUT BUFFER
|
||
SKIPE T1,P1 ;MAKE SURE THAT THERE IS ONE,
|
||
EXCTUX <SKIPGE (T1)> ; AND THAT IT IS EMPTY
|
||
POPJ P, ;IF NO EMPTY BUFFER, THEN RETURN
|
||
PUSHJ P,BRNGE## ;MAKE SURE THE BUFFER IS ADDRESSABLE
|
||
HRRZ P2,DEVKDL(F) ;GET THE ADDRESS OF THE INPUT MESSAGE
|
||
JUMPE P2,KIWAIT ;IF NO INPUT, GO WAIT FOR SOME
|
||
|
||
;NOW SET UP TO COPY THE DATA
|
||
EXCTUX <HLRZ T4,(P1)> ;GET THE LENGTH OF THE INPUT BUFFER (+1)
|
||
SUBI T4,1 ;GET ACTUAL LENGTH IN WORDS
|
||
LSH T4,2 ; AND CONVERT THAT TO BYTES
|
||
MOVSI T5,(POINT 8) ;MAKE A BYTE POINTER TO THE
|
||
HRRI T5,2(P1) ; USER'S INPUT BUFFER
|
||
MOVE T3,MB.FMS(P2) ;GET THE ADDRESS OF THE SEGMENT DESCRIPTOR
|
||
MOVE T1,MD.BYT(T3) ;FROM THE MSC, GET THE BYTE COUNT
|
||
MOVE T6,MD.ALA(T3) ;BYTE POINTER IS INDEXED BY T6
|
||
MOVE T2,MD.PTR(T3) ; AND THE BYTE POINTER
|
||
CAMGE T4,T1 ;MAKE SURE THAT THE DATA WILL FIT,
|
||
JRST K.BKTL ; IF NOT, THEN GIVE "BLOCK TOO LARGE"
|
||
MOVEI T4,3(T1) ;MAKE THE "DST" LENGTH BE THE SOURCE
|
||
TRZ T4,3 ; LENGTH ROUNDED UP SO AS TO ZERO FILL LAST WD
|
||
EXCTUU <HRRM T1,1(P1)> ;STORE THE BYTE COUNT FOR THE USER
|
||
IFE DALBUG,< ;D.A.LEWINE
|
||
PXCT 1,[EXTEND T1,[EXP MOVSLJ,0]] ;AND COPY THE DATA
|
||
PUSHJ P,NTDSTP## ;WE CHECKED... THIS SHOULDN'T HAPPEN
|
||
>
|
||
IFN DALBUG,< ;UNTIL THEY GET THE MICRO-CODE RIGHT...
|
||
JRST .+3 ;SKIP INTO THE MIDDLE OF THE LOOP
|
||
ILDB T4,T2 ;GET THE NEXT BYTE
|
||
EXCTUU <IDPB T4,T5> ;STORE THE NEXT BYTE
|
||
SOJGE T1,.-2 ;LOOP TILL ALL STORED
|
||
SETZ T3, ;CLEAR THE "TO COUNT"
|
||
>
|
||
;NOW DEQUEUE THE INPUT MESSAGE AND ADVANCE THE USER'S BUFFER
|
||
KDPOFF ;KEEP INTERRUPT LEVEL OUT
|
||
HRRZ T1,MB.NXT(P2) ;GET THE ADDRESS OF THE NEXT MESSAGE
|
||
HRRM T1,DEVKDL(F) ; AND MAKE THAT ONE BE THE FIRST
|
||
KDPON ;RE-ENABLE INTERRUPTS
|
||
MOVE T1,P2 ;GET THE KDB ADDR BACK
|
||
PUSHJ P,GIVKDB ;FREE THE MESSAGE BLOCK
|
||
PUSHJ P,ADVBFF## ;ADVANCE THE USER'S INPUT BUFFER
|
||
POPJ P, ;IF WE'RE SUPPOSED TO STOP, RETURN TO UUOCON
|
||
JRST KILOOP ;OTHERWISE TRY TO DO MORE INPUT
|
||
;KDPOUT ROUTINE TO PROCESS THE OUTPUT UUO FOR THE KDP DEVICE
|
||
;CALL F := DDB ADDRESS
|
||
;RETURN CPOPJ ;ALWAYS
|
||
KDPCLO:
|
||
KDPOUT: PUSHJ P,SAVE2## ;P1 := DEVOAD, P2 := DATA BUFFER ADDRESS
|
||
MOVSI S,IOBEG ;CLEAR IOBEG
|
||
ANDCAB S,DEVIOS(F) ; FOR NO PARTICULAR GOOD REASON
|
||
MOVSI S,IO ;GET AND SET
|
||
IORB S,DEVIOS(F) ; "OUTPUT" SO IOSETC WORKS RIGHT
|
||
PUSHJ P,KDPCKM ;CHECK THE MODE
|
||
|
||
KOLOOP: PUSHJ P,KDPONL ;MAKE SURE THAT THE DEVICE IS ONLINE
|
||
POPJ P, ;IF NOT, RETURN (WITH ERROR BITS SET)
|
||
HRRZ P1,DEVOAD(F) ;GET THE ADDRESS OF THE OUTPUT BUFFER
|
||
SKIPE T1,P1 ;MAKE SURE THAT THERE IS ONE, AND
|
||
EXCTUX <SKIPL (T1)> ; THAT IT HAS DATA IN IT
|
||
POPJ P, ;IF NO FULL BUFFER, THEN EXIT
|
||
PUSHJ P,BRNGE## ;MAKE SURE THE BUFFER IS ADDRESSABLE
|
||
|
||
AOS T1,DEVOBC(F) ;COUNT UP THE NUMBER OF BUFFERS OUTSTANDING
|
||
CAILE T1,KDPMXQ ;IF TOO MANY, THEN
|
||
JRST [SOS DEVOBC(F) ; TAKE BACK WHAT WE JUST SAID
|
||
JRST KOWAIT] ; AND WAIT FOR SOME TO GET SENT
|
||
|
||
;NOW ALLOCATE A KDP DATA BLOCK TO HOLD THE DATA
|
||
KOLOO1: EXCTUX <HRRZ T1,1(P1)> ;GET THE NUMBER OF USER BYTES
|
||
CAILE T1,KDLMMS*4 ;MAKE SURE THAT THE NUMBER IS REALISTIC
|
||
JRST [SOS DEVOBC(F) ;IF TOO MANY, TAKE BACK THE COUNT
|
||
JRST K.BKTL] ; AND TELL THE USER "BLOCK TOO LARGE"
|
||
PUSHJ P,GETKDB ;GET A BUFFER FOR THE MESSAGE
|
||
JRST [SOS DEVOBC(F) ;SINCE ^C CAN HAPPEN HERE...
|
||
MOVEI T1,2 ;IF NO CORE AVAILABLE,
|
||
PUSHJ P,SLEEPF## ;SLEEP FOR 2 SECONDS AND
|
||
JRST KOLOOP] ; TRY AGAIN
|
||
MOVE P2,T1 ;REMEMBER THE ADDRESS OF THE MESSAGE BLOCK
|
||
;NOW COPY THE DATA INTO THE DATA BLOCK
|
||
EXCTUX <HRRZ T1,1(P1)> ;GET THE USER'S BYTE COUNT BACK AGAIN
|
||
MOVSI T2,(POINT 8) ;BUILD A BYTE POINTER TO THE
|
||
HRRI T2,2(P1) ; USER'S DATA
|
||
MOVE T3,MB.FMS(P2) ;GET THE ADDRESS OF THE SEGMENT DESCRIPTOR
|
||
MOVE T4,T1 ;GET THE LENGTH
|
||
MOVEM T1,MD.BYT(T3) ;STORE THE NUMBER OF BYTES WE'RE GOING TO COPY
|
||
MOVE T5,MD.AUX(T3) ;GET THE ADDRESS OF THE FIRST BYTE
|
||
MOVE T6,MD.ALA(T3) ;MD.AUX IS INDEXED BY T6
|
||
IFE DALBUG,< ;D.A.LEWINE
|
||
PXCT 2,[EXTEND T1,[EXP MOVSLJ,0]] ;COPY THE DATA
|
||
PUSHJ P,NTDSTP## ;CAN'T HAPPEN
|
||
>
|
||
IFN DALBUG,< ;UNTIL THEY GET THE MICRO-CODE RIGHT...
|
||
JRST .+3 ;SKIP INTO THE MIDDLE OF THE LOOP
|
||
EXCTUX <ILDB T4,T2> ;LOAD THE NEXT BYTE
|
||
IDPB T4,T5 ; AND STORE IT IN THE MONITOR BUFFER
|
||
SOJGE T1,.-2 ;LOOP TILL ALL STORED
|
||
SETZ T3, ;CLEAR THE "TO COUNT"
|
||
>
|
||
MOVEI T1,DC.FQB ;FUNCTION = QUEUE OUTPUT DATA
|
||
HLRZ T2,DEVKDL(F) ; TO THIS KDL
|
||
MOVE T3,P2 ; AND THIS IS THE MESSAGE BLOCK
|
||
PUSHJ P,KDODSP## ;CALL THE KONTROLLER
|
||
JRST [MOVEI T1,DC.IOF ;SIGNAL OUPUT NOT DONE
|
||
MOVE T2,F ;POINT TO DDB
|
||
MOVE T3,P2 ;POINT TO MSG BLOCK
|
||
PUSHJ P,KDPIDS ;GIVE THE INTERRUPT
|
||
JRST .+1] ; AND CONTINUE
|
||
PUSHJ P,ADVBFE## ;ADVANCE THE USER'S OUTPUT BUFFER
|
||
POPJ P, ;IF NO MORE OUTPUT, RETURN TO UUOCON
|
||
JRST KOLOOP ;OTHERWISE TRY TO SEND MORE
|
||
|
||
PURGE T5 ;DONE WITH EXTEND INSTRUCTIONS
|
||
;KIWAIT ROUTINE TO WAIT FOR INPUT
|
||
KIWAIT: MOVE T2,DEVAIO(F) ;GET THE ASYNCH IO BITS
|
||
HRRZ T1,DEVBUF(F) ;GET THE ADDRESS OF THE BUFFER CONTROL BLOCK
|
||
JUMPE T1,CPOPJ## ;IF NO BUFFERS SETUP ??
|
||
EXCTUX <HRRZ T1,(T1)> ;GET THE ADDRESS OF THE NEXT USER'S BUFFER
|
||
EXCTUX <SKIPL (T1)> ;IF HE HAS INPUT TO READ,
|
||
TRNE T2,DEPAIO ; OF IF THIS IS ASYNCH IO, THEN
|
||
POPJ P, ; RETURN TO THE USER
|
||
MOVEI T1,EV.KDP ;OTHERWISE, GO INTO
|
||
PUSHJ P,ESLEEP## ; EVENT WAIT AND THEN
|
||
JRST KILOOP ; CHECK FOR MORE INPUT
|
||
|
||
|
||
;KOWAIT WAIT FOR OUTPUT TO COMPLETE
|
||
KOWAIT: MOVE T1,DEVAIO(F) ;GET THE WORD WITH THE ASYNCH IO BITS
|
||
TRNE T1,DEPAIO ;SEE IF WE ARE DOING ASYNCH IO
|
||
POPJ P, ;IF ASYNCH IO, THEN RETURN TO THE USER
|
||
MOVEI T1,EV.KDP ;OTHERWISE, GO INTO
|
||
PUSHJ P,ESLEEP## ; EVENT WAIT, AND
|
||
JRST KOLOOP ; THEN SEE IF WE CAN DO OUTPUT
|
||
|
||
|
||
;KDPIAV ROUTINE TO SIGNAL THAT KDP INPUT IS AVAILABLE
|
||
KDPIAV: MOVE T1,DEVAIO(F) ;GET THE WORD WITH THE ASYNCH IO BITS
|
||
TRNN T1,DEPAIO ; AND IF THIS IS NOT ASYNCH IO,
|
||
JRST [LDB T1,PJOBN## ; ASSUME THAT THE GUY IS IN EVENT WAIT
|
||
PJRST EWAKE##] ; AND GO WAKE HIM
|
||
PUSH P,DEVIOS(F) ;IF ASYNCH IO, THEN MAKE
|
||
MOVSI S,IO ; SURE THAT THE "IO" BIT IS
|
||
ANDCAB S,DEVIOS(F) ; CLEAR. THIS INSURES THAT SETIOD
|
||
PUSHJ P,SETIOD## ; WILL GENERATE AN INPUT DONE INTERRUPT
|
||
POP P,DEVIOS(F) ;RESTORE THE STATE OF DEVIOS
|
||
POPJ P, ; AND RETURN.
|
||
|
||
|
||
;KDPOAV ROUTINE TO SIGNAL THAT OUTPUT HAS BEEN COMPLETED
|
||
KDPOAV: MOVE T1,DEVAIO(F) ;GET THE ASYNCH IO BITS
|
||
TRNN T1,DEPAIO ;IF WE ARE NOT DOING ASYNCH IO
|
||
PJRST [LDB T1,PJOBN## ; THEN ASSUME THAT THE GUY IS IN
|
||
JRST EWAKE##] ; EVENT WAIT AND WAKE HIM
|
||
PUSH P,DEVIOS(F) ;IF ASYNCH IO, THEN MAKE SURE THAT
|
||
MOVSI S,IO ; THE "IO" BIT SAYS OUTPUT. THIS
|
||
IORB S,DEVIOS(F) ; WILL CAUSE SETIOD TO GENERATE
|
||
PUSHJ P,SETIOD## ; AN "OUTPUT DONE" INTERRUPT.
|
||
POP P,DEVIOS(F) ;RESTORE DEVIOS AND
|
||
POPJ P, ; RETURN
|
||
;KDPCKO ROUTINE TO CHECK OWNERSHIP OF THE KDL BLOCK.
|
||
;CALL F := DDB ADDRESS
|
||
;RETURN CPOPJ ;KDL IS NOT IN "PROGRAM" MODE
|
||
; CPOPJ1 ;KDL IS IN "PROGRAM" MODE
|
||
|
||
KDPCKO: HLRZ T1,DEVKDL(F) ;GET THE KDL PAGE ADDRESS
|
||
HRRZ T1,KDLUSR(T1) ;GET THE USER CODE
|
||
CAIN T1,DD.PRO ;IF IT IS "PROGRAM"
|
||
AOS (P) ; THEN GIVE A GOOD
|
||
POPJ P, ; RETURN
|
||
|
||
|
||
;KDPONL ROUTINE TO CHECK TO SEE IF THE KDP IN "ON LINE"
|
||
;CALL F := DDB ADDRESS
|
||
;RETURN CPOPJ ;NOT OWNED OR NOT ONLINE (ERROR BITS SET)
|
||
; CPOPJ1 ;KDP APPEARS TO BE READY FOR I/O
|
||
|
||
KDPONL: PUSHJ P,KDPCKO ;FIRST SEE IF WE OWN THE LINE
|
||
JRST K.IMPM ; IF NOT, THEN IT'S IMPROPER MODE
|
||
HLRZ T1,DEVKDL(F) ;GET THE KDL PAGE ADDRESS
|
||
HRRZ T1,KDLKDP(T1) ; AND FROM THAT GET THE KDP ADDRESS
|
||
JUMPE T1,K.DERR ;IF NO KDP YET (NOT INITED) THEN NOT UP
|
||
MOVE T1,KDPSTS(T1) ; AND FROM THAT GET THE KDP STATUS
|
||
TLNN T1,(KDPSRU) ;SEE IF WE'RE RUNNING
|
||
JRST K.DERR ;IF NOT, SAY DEVICE ERROR
|
||
MOVE S,DEVIOS(F) ;FIRST GET THE DEVICE STATUS
|
||
TRNE S,IOSSRM!IOSMRN ; AND IF EITHER ERROR IS STILL LIT
|
||
JRST K.DERR ; RETURN "DEVICE ERROR"
|
||
TRNE S,IODERR!IODTER!IOIMPM!IOBKTL ;IF ANY "STANDARD" ERROR
|
||
POPJ P, ; FORCE THE USER TO CLEARR IT
|
||
PUSH P,F ;PRESERVE THE DDB ADDRESS
|
||
HLRZ F,DEVKDL(F) ;GET THE KDL PAGE ADDRESS
|
||
LDB T1,KDLSTA ; AND GET THE STATE
|
||
POP P,F ;RESTORE THE DDB ADDRESS
|
||
TRNE S,IOSMAI ;IF WE ARE TRYING MAINT MODE,
|
||
JRST KDPON1 ; GO CHECK ONLINE DIFFERENTLY
|
||
CAIGE T1,KD%STR ;IF SUPPOSED TO BE NORMAL, BUT NOT
|
||
JRST K.DERR ; THEN WE MUST HAVE SCREWED UP
|
||
CAIE T1,KD%RUN ;IF WE'RE NOT RUNNING, THEN
|
||
JRST K.DTER ; IT'S A "SOFT" AREA. (WAIT FOR ONLINE)
|
||
RETSKP ;IF IN RUN, THEN ALL'S OK
|
||
|
||
KDPON1: CAIE T1,KD%MAI ;IF WE'RE NOT IN MAINT MODE, THEN
|
||
JRST K.DERR ; IT'S AN ERROR
|
||
RETSKP ;OTHERWISE WE'RE "ONLINE"
|
||
;KDPCKM ROUTINE TO CHECK/SET THE MAINT/NORMAL MODE OF THE LINE
|
||
;CALL F := DDB
|
||
;RETURN CPOPJ ;ALWAYS (STARTS THE LINE IN MAINT/NORMAL)
|
||
|
||
KDPCKM: PUSHJ P,KDPCKO ;SEE IF WE ARE THE LINE'S OWNER
|
||
POPJ P, ; IF NOT, DON'T DO ANYTHING
|
||
PUSH P,F ;FIRST PRESERVE THE DDB POINTER
|
||
HLRZ F,DEVKDL(F) ;FROM THAT GET THE KDL PAGE ADDRESS
|
||
LDB T1,KDLSTA ;FROM THAT, GET THE STATE
|
||
POP P,F ;NOW RESTORE THE DDB ADDRESS
|
||
MOVE S,DEVIOS(F) ;RELOAD THE IO STATUS
|
||
TRNE S,IOSMAI ;IF WE'RE SUPPOSED TO BE IN MAINT
|
||
JRST KDPCK1 ; THEN DGO CHECK DIFFERENTLY
|
||
CAIL T1,KD%STR ;IF WE'RE TRYING TO START OR BETTER
|
||
POPJ P, ; THEN ALL'S OK
|
||
MOVEI T1,DC.FIL ;WE WANT TO "INITIALIZE" THE LINE
|
||
JRST KDPCK2 ; SO GO TO COMMON CODE TO DO SO
|
||
|
||
KDPCK1: CAIN T1,KD%MAI ;IF WE'RE IN MAINT MODE
|
||
POPJ P, ; THEN IT'S OK
|
||
MOVEI T1,DC.FSM ;WE WANT TO PUT IN MAINT STATE
|
||
KDPCK2: PUSH P,T1 ;SAVE THE "DESTINATION STATE"
|
||
MOVEI T1,DC.FHL ;FIRST WE MUST "HALT" THE LINE
|
||
HLRZ T2,DEVKDL(F) ; GET THE LINE ID
|
||
PUSHJ P,KDODSP## ; AND CALL THE KONTROLLER
|
||
JFCL ;CAN'T BE, WE ALREADY CHECK THAT WE ARE OWNER
|
||
POP P,T1 ;NOW GET THE "MODE" BACK
|
||
HLRZ T2,DEVKDL(F) ; AND THE LINE ID
|
||
PUSHJ P,KDODSP## ;CHANGE THE STATE
|
||
JFCL ;CAN'T BE, WE ALREADY CHECK THAT WE ARE OWNER
|
||
POPJ P, ; AND RETURN
|
||
|
||
|
||
;ROUTINES TO SET VARIOUS ERROR BITS
|
||
K.IMPM: MOVEI S,IOIMPM ;GET THE IMPROPER MODE BIT
|
||
JRST K.SET ; AND GO SET IT
|
||
K.DTER: MOVEI S,IODTER ;GET "SOFT ERROR"
|
||
JRST K.SET ; AND SET IT
|
||
K.DERR: MOVEI S,IODERR ;GET THE DEVICE ERROR BIT
|
||
JRST K.SET ;AND SET IT
|
||
K.BKTL: MOVEI S,IOBKTL ;GET THE BLOCK TOO LARGE BIT
|
||
K.SET: IORB S,DEVIOS(F) ;SET THE APPROPRIATE BIT
|
||
POPJ P, ; AND RETURN
|
||
;KDPIDS INTERRUPT LEVEL DISPATCH FROM KMC-11/DUP-11 KONTROLLER
|
||
|
||
KDPIDS::CAIL T1,DC.IPU ;RANGE CHECK THE FUNCTION CODE
|
||
CAILE T1,DC.ICC ; BEFORE BLINDLY DISPATCHING ON IT
|
||
PUSHJ P,NTDSTP## ;++ KONTROLLER GAVE BAD FUNCTION?
|
||
PUSH P,F ;SAVE THE KDL PAGE ADDRESS (OR WHAT EVER)
|
||
MOVE F,T2 ;SET F TO POINT TO THE DDB
|
||
PUSHJ P,@KDPID1(T1) ;CALL THE APPROPRIATE INTERRUPT ROUTINE
|
||
POP P,F ;RESTORE "F"
|
||
POPJ P, ; AND RETURN TO THE KONTROLLER
|
||
|
||
KDPID1: IFIW KD.PUP ;(00) PRIMARY PROTOCOL UP
|
||
IFIW KD.PDN ;(01) PRIMARY PROTOCOL DOWN
|
||
IFIW KD.MAI ;(02) MAINT MSG RECEIVED IN NORMAL PROTOCOL
|
||
IFIW KD.STR ;(03) START MSG RECEIVED IN MAINT PROTOCOL
|
||
IFIW KD.ODN ;(04) OUTPUT DONE
|
||
IFIW KD.OND ;(05) OUTPUT NOT DONE
|
||
IFIW KD.IDN ;(06) INPUT DONE
|
||
IFIW KD.RQI ;(07) REQUEST INPUT BUFFER
|
||
IFIW NTDSTP## ;(10) LINE CREATION
|
||
IFIW NTDSTP## ;(11) LINE DISSOLUTION
|
||
|
||
|
||
;PROTOCOL UP
|
||
KD.PUP: MOVEI S,IODERR ;GET THE IO DEVICE ERROR BIT
|
||
ANDCAB S,DEVIOS(F) ; AND CLEAR IT
|
||
PUSHJ P,PSIONL## ;SIGNAL THE DEVICE IS ONLINE
|
||
JRST KD.WAK ; AND WAKE UP ANY SERVICE ROUTINES
|
||
|
||
;PROTOCOL DOWN
|
||
KD.PDN: PUSHJ P,K.DERR ;SIGNAL AN IO DEVICE ERROR
|
||
PUSHJ P,PSIDWN## ; AND GIVE AN OFFLINE INTERRUPT
|
||
KD.WAK: PUSHJ P,KDPIAV ;NOW MAKE SURE THAT THE SERVICE ROUTINE
|
||
PUSHJ P,KDPOAV ; WAKE UP SO THAT THE SEE THE
|
||
LDB T1,PJOBN## ;GET THE JOB NUMBER
|
||
PUSHJ P,WAKPST## ; AND WAKE HIM FROM A POSSIBLE HIBER
|
||
POPJ P, ; PROBLEM
|
||
|
||
;MAINT OR START RECEIVED IN THE WRONG MODE
|
||
KD.MAI: ;IF EITHER ONE OF THE "WRONG TYPE" OF
|
||
KD.STR: PUSHJ P,K.IMPM ; MESSAGES ARRIVES, SAY "IMPROPER MODE"
|
||
PJRST KD.PDN ; AND TREAT IT AS "PROTOCOL DOWN"
|
||
;KD.IDN ROUTINE TO PROCESS INPUT MESSAGES FROM THE KDP
|
||
KD.IDN: KDPOFF ;NO INTERRUPTS WHILE HACKING QUEUE
|
||
HRRZ T2,DEVKDL(F) ;GET THE ADDRESS OF INPUT MESSAGE QUEUE
|
||
JUMPE T2,[HRRM T3,DEVKDL(F) ; IF NO QUEUE, START ONE AND
|
||
JRST KD.ID1] ; RETURN
|
||
JRST .+2 ;SKIP INTO THE MIDDLE OF THE LOOP
|
||
MOVE T2,T1 ;ADVANCE TO THE NEXT ENTRY IN THE LIST
|
||
HRRZ T1,MB.NXT(T2) ;GET THE ADDRESS OF THE ENTRY AFTER THAT
|
||
JUMPN T1,.-2 ;LOOP IF THE END IS STILL NOT IN SIGHT
|
||
HRRM T3,MB.NXT(T2) ;MAKE OUR INPUT MSG BE THE LAST ONE
|
||
KD.ID1: KDPON ;RE-ENABLE INTERRUPTS
|
||
PUSHJ P,KDPIAV ;SIGNAL THAT INPUT IS AVAILABLE
|
||
POPJ P, ; AND RETURN
|
||
|
||
|
||
;KD.ODN KD.OND ROUTINES TO PROCESS RETURNED OUTPUT MESSAGES
|
||
KD.ODN:
|
||
KD.OND: MOVE T1,T3 ;GET THE ADDRESS OF THE SPENT MSG
|
||
PUSHJ P,GIVKDB ; AND FREE IT
|
||
SOS DEVOBC(F) ; DECREMENT THE COUNT OF OUTSTANDING MSGS
|
||
PJRST KDPOAV ; AND WAKE UP THE DRIVER
|
||
|
||
|
||
;KD.RQI ROUTINE TO PROCESS A KONTROLLER'S REQUEST FOR AN INPUT BUFFER
|
||
;CALL T3 := NUMBER OF BYTES REQUESTED
|
||
;RETURN T1 := 0 IF NO BUFFER AVAILABLE, T1 := ADDRESS OF BUFFER OTHERWISE
|
||
KD.RQI: MOVE T2,DEVIOS(F) ;GET DEVICE STATUS
|
||
TRNE T2,IOIMPM ;IN WRONG PROTOCOL?
|
||
JRST KD.RQ1 ;YES, DON'T ACCEPT MESSAGE
|
||
KDPOFF ;LOCK THE INPUT CHAIN WHILE WE COUNT BUFFERS
|
||
HRRZ T2,DEVKDL(F) ;GET THE ADDRESS OF THE FIRST MESSAGE
|
||
MOVEI T1,KDPMXQ ; AND GET THE QUOTA OF INPUT BUFFERS
|
||
JUMPN T2,[HRRZ T2,MB.NXT(T2) ;KEEP LOOKING FOR THE END
|
||
SOJN T1,. ; AND COUNTING DOWN THE QUOTA
|
||
KDPON ; IF THE QUOTA IS EXHAUSTED
|
||
POPJ P,] ; THEN RETURN (T1 := 0)
|
||
KDPON ;THE CHAIN IS CONSISTANT AGAIN
|
||
MOVE T1,T3 ;GET THE BYTE COUNT
|
||
PUSHJ P,GETKDB ; AND ALLOCATE A MESSAGE BUFFER
|
||
KD.RQ1: SETZ T1, ;IF NONE, TELL THE KONTROLLER
|
||
POPJ P, ;RETURN
|
||
;ROUTINES TO GET AND FREE KDP BUFFERS.
|
||
;FORMAT OF THE BUFFERS IS:
|
||
; 0 MB.NXT (POINTER TO NEXT MESSAGE BLOCK)
|
||
; 1 MB.FMS (POINTS TO SEGMENT DESCRIPTOR)
|
||
; 2 MB.MSN (DDCMP MSG NUMBER)
|
||
; 3 CONTAINS SIXBIT /KMCDUP/
|
||
; 4 \
|
||
; 5 \ MESSAGE SEGMENT
|
||
; 6 / DESCRIPTOR GOES HERE
|
||
; 7 /
|
||
; 8 \
|
||
; . \ DATA
|
||
; . / DATA
|
||
; N-1 /
|
||
; N CONTAINS SIXBIT /DUPKMC/ (CHECK WORD)
|
||
|
||
KDPHDL==4+MD.LEN ;LENGTH OF KDP HEADER IN WORDS
|
||
KDPMSD==4 ;OFFSET TO MSD FROM BEG OF BLK
|
||
|
||
GETKDB::PUSH P,T1 ;SAVE BYTE COUNT
|
||
MOVEI T2,<KDPHDL*4>+3+4(T1) ;ALLOW FOR OVERHEAD AND ROUND UP
|
||
LSH T2,-2 ;CONVERT TO WORD COUNT
|
||
PUSHJ P,GETWDS## ; AND TRY TO ALLOCATE SPACE
|
||
JRST TPOPJ## ;IF NO CORE, GIVE ERROR RETURN
|
||
POP P,T2 ;GET BYTE COUNT BACK
|
||
SETZM MB.NXT(T1) ;NO POINTERS PLEASE
|
||
SETZM KDPMSD+MD.NXT(T1) ;MAKE SURE THERE IS ONLY 1 MSD
|
||
MOVEM T2,KDPMSD+MD.BYT(T1) ; AND STORE THAT FOR USER
|
||
MOVEM T2,KDPMSD+MD.ALA(T1) ; & PUT IT IN "ALLOC INFO" AREA
|
||
MOVEM T2,KDPMSD+MD.ALL(T1) ; ...
|
||
MOVSI T3,(POINT 8) ;MAKE A BYTE POINTER TO DATA
|
||
HRRI T3,KDPMSD+MD.LEN(T1) ; AREA AFTER HEADER
|
||
MOVEM T3,KDPMSD+MD.PTR(T1) ; AND STORE THAT
|
||
MOVEM T3,KDPMSD+MD.AUX(T1) ;STORE OUTPUT BYTE POINTER ALSO
|
||
MOVEI T3,KDPMSD(T1) ;GET ADDRESS OF MSD
|
||
MOVEM T3,MB.FMS(T1) ; AND STORE IT IN MESSAGE BLOCK
|
||
MOVEI T2,<KDPHDL*4>+3+4(T2) ;GET BYTE COUNT AGAIN
|
||
LSH T2,-2 ; AND CONVERT TO LENGTH OF BLOCK
|
||
ADD T2,T1 ;RELOCATE BY ADDRESS OF BLOCK
|
||
MOVE T3,[SIXBIT /KMCDUP/] ;GET CHECK DATA
|
||
MOVEM T3,3(T1) ;STORE THAT IN FIRST PART
|
||
MOVSM T3,-1(T2) ; AND SWAP OF IT IN LAST CHECK WD
|
||
RETSKP ;RETURN
|
||
;ROUTINE TO RETURN MEMORY
|
||
;CALL T1 := ADDRESS OF THE KDP BUFFER
|
||
;RETURN CPOPJ ;ALWAYS
|
||
GIVKDB::MOVE T2,KDPMSD+MD.ALL(T1) ;RECOVER ORIGINAL BYTE COUNT
|
||
MOVEI T2,<KDPHDL*4>+3+4(T2) ;GET LENGTH (IN BYTES)
|
||
LSH T2,-2 ; AND CONVERT THAT TO WORDS
|
||
MOVE T3,T2 ;COPY LENGTH
|
||
ADD T3,T1 ; AND RELOCATE BY BLOCK ADDRESS
|
||
MOVE T4,[SIXBIT /KMCDUP/] ;GET CHECK WORD
|
||
CAME T4,3(T1) ;CHECK FIRST ONE
|
||
PUSHJ P,NTDSTP## ;CHECK WORD CLOBBERED
|
||
MOVS T4,T4 ;GET VALUE FOR LAST CHECK WORD
|
||
CAME T4,-1(T3) ; AND COMPARE THAT
|
||
PUSHJ P,NTDSTP## ;CHECK WORD CLOBBERED
|
||
EXCH T1,T2 ;IDIOTIC AC CONVENTIONS
|
||
PUSHJ P,GIVWDS## ;RETURN STORAGE
|
||
POPJ P, ; AND WE'RE DONE
|
||
;THESE ARE THE BYTE POINTERS INTO THE VARIOUS FIELDS OF THE
|
||
;DEVICE NAME (USED BY TSTKDP)
|
||
|
||
KDNMPA: POINT 10,P1,35 ;LOW 10 BITS ARE MULTI POINT ADDR
|
||
KDNKDL: POINT 4,P1,25 ;NEXT 4 BITS ARE LINE NUMBER
|
||
KDNKDP: POINT 4,P1,21 ;NEXT 4 BITS ARE KONTROLLER NUMBER
|
||
|
||
|
||
KDLSTA::EXP KD%STA ;THE KDL LINE STATE VARIABLE
|
||
KDLTIM::EXP KD%TIM ;THE KDL DDCMP TIMER
|
||
KDLXNK::EXP KD%XNK ;POINTER TO THE NAK CODE TO BE TRANSMITTED
|
||
KDLRMN::EXP KD%RMN ;POINTER TO THE RECEIVE MESSAGE COUNTER
|
||
KDLLMX::EXP KD%LMX ;POINTER TO LAST MESSAGE NUMBER ASSIGNED
|
||
KDLLMA::EXP KD%LMA ;POINTER TO LAST MESSAGE ACKED
|
||
KDLRPC::EXP KD%RPC ;POINTER TO THE REP COUNTER
|
||
|
||
XLIST
|
||
$LIT ;DON'T LIST LITERALS
|
||
LIST
|
||
KDSEND::PRGEND
|
||
TITLE KDPINT - SERVICE FOR KMC-11/DUP-11 V002
|
||
SUBTTL W. E. MATSON/TL 21-Oct-84
|
||
SEARCH F, S, NETPRM, D36PAR
|
||
$RELOC
|
||
$HIGH
|
||
|
||
.DIRECT FLBLST
|
||
|
||
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
|
||
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
|
||
;
|
||
;COPYRIGHT (C) 1978,1979,1980 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
|
||
XP VKDPINT,001
|
||
|
||
Comment @ Loose ends.
|
||
|
||
End Comment @
|
||
|
||
KDPINT::ENTRY KDPINT
|
||
|
||
|
||
COMMENT @
|
||
|
||
EHPL MI RTPADE NIISED A DP1P1
|
||
|
||
END OF COMMENT @
|
||
|
||
|
||
|
||
OPDEF BLTBU [716B8] ;FAST BYTE TO UNIBUS
|
||
OPDEF BLTUB [717B8] ;FAST UNIBUS TO BYTE
|
||
SUBTTL KDPPRM -- PARAMETERS FOR THE KMC/DUP
|
||
|
||
REPMAX==^D20 ;NUMBER OF UNANSWERED REPS IMPLIES DEAD LINE
|
||
STRSEC==^D5 ;NUMBER OF SECONDS BETWEEN STARTS
|
||
STKSEC==^D2 ;NUMBER OF SECONDS BETWEEN STACKS
|
||
REPSEC==^D3 ;NUMBER OF SECONDS BETWEEN REPS
|
||
MAXOUT==^D10 ;MAXIMUM NUMBER OF OUTSTANDING UN-ACKED MSGS
|
||
|
||
T6==T4+2 ;T6 FOR INDEXED MSD PTRS (DECNET)
|
||
|
||
PURGE NETOFF, NETON ;GET RID OF THE OLD ONES
|
||
|
||
|
||
;COMPUTE CODE FOR "TIMER STOPPED" BASED ON FIELD SIZE
|
||
KD%MXT==-1_-^D<36-<<KD%TIM&^O<007700,,0>>_-24>>
|
||
SUBTTL DEFINITIONS -- DDCMP
|
||
|
||
SYN==226
|
||
ENQ==005 ;1ST CHAR IN UNNUMBERED MESSAGES
|
||
DLE==220 ;1ST CHAR IN BOOTSTRAP MESSAGES
|
||
SOH==201 ;1ST CHAR IN NUMBERED MESSAGES
|
||
|
||
;NUMBERED MESSAGES
|
||
; SOH CC1 (CC2 QSYNC SELECT) R N A0 BCC1 DATA BCC2
|
||
; CC1&CC2 ARE TOTAL LENGTH OF DATA(BCC1 THRU BCC2 EXCLUSIVE)
|
||
; CC1 IS LOWORDER 8BITS OF LENGTH
|
||
; CC2 IS HIGH ORDER 6 BITS OF LENGTH
|
||
QSYNC==100 ;QSYNC BIT
|
||
SELECT==200 ;SELECT BIT
|
||
; R IS # OF LAST GOOD MESSAGE RECEIVED
|
||
; N IS THIS MESSAGE NUMBER
|
||
; A0 ;A0 IS THE DESTINATION STATION ADR(ALWAYS 1)
|
||
; BCC1 IS THE 16 BIT CRC ON SOH THROUGH A0 INCLUSIVE
|
||
; DATA IS PASSED TO NCL
|
||
; BCC2 IS THE 16BIT CRC OF DATA
|
||
;UNNUMBERED MESSAGES
|
||
|
||
;ACK: ENQ ACK (QSYNC SELECT FILL) MSG# FILL A0 BCC1 BCC2
|
||
; MSG# IS LAST GOOD MSG RECEIVED
|
||
%ACK==1
|
||
|
||
;NAK: ENQ NAK (QSYNC SELECT RNAK) MSG# FILL A0 BCC1 BCC2
|
||
; RNAK IS NAK REASON
|
||
; MSG# IS LAST GOOD MSG RECEIVED
|
||
%NAK==2
|
||
|
||
;REP: ENQ REP (QSYNC SELECT FILL) FILL N A0 BCC1 BCC2
|
||
; N IS THE LAST MESSAGE# SENT
|
||
%REP==3
|
||
|
||
;START: ENQ STRT (QSYNC SELECT FILL) FILL N A0 BCC1 BCC2
|
||
; N IS NEXT NUMBERED MESSAGE TO BE SENT
|
||
%START==6
|
||
|
||
;STACK: ENQ STACK (QSYNC SELECT FILL) R N A0 BCC1 BCC2
|
||
; R IS NEXT EXPECTED MESSAGE # FOR RECPTION
|
||
; N IS NEXT MESSAGE # FOR TRANSMISSION
|
||
%STACK==7
|
||
|
||
;NAK REASONS
|
||
RSNHCK==^D1 ;HEADER BCC ERROR
|
||
RSNDCK==^D2 ;DATA BCC ERROR
|
||
RSNREP==^D3 ;REP RESPONSE
|
||
RSNBTU==^D8 ;BUFFER TEMPORARILY UNAVAILABLE
|
||
RSNOVR==^D9 ;RECEIVER OVERRUN
|
||
RSNM2L==^D16 ;MESSAGE TOO LONG (FATAL)
|
||
RSNHFA==^D17 ;MESSAGE HEADER FORMAT ERROR.
|
||
SUBTTL DEFINITIONS -- DUP11
|
||
|
||
DUPADR==3760300 ;ADDRESS OF 1ST DUP11
|
||
DUPUBN==3 ;UNIBUS ADAPTER NUMBER FOR DUP11
|
||
|
||
DPRCSR==0 ;RECEIVER CSR
|
||
DPDTR==000002 ;DATA TERMINAL READY
|
||
DPRDBF==2 ;(RO)RECEIVER DATA BUFFER
|
||
DPPCSR==2 ;(WO)PARAMETER CONTROL AND STATUS REGISTER
|
||
DPTCSR==4 ;TRANSMIT CONTROL AND STATUS REGISTER
|
||
DPCBLP==010000 ;EXTERNAL MAINTENCE MODE (CABLE LOOPBACK)
|
||
DPCNLP==004000 ;SYSTEMS TEST MODE (CONTROLLER LOOPBACK)
|
||
DPMAIN==014000 ;MAINTAINENCE MODE BITS
|
||
DPTDBF==6 ;TRANSMIT DATA BUFFER
|
||
SUBTTL DEFINITIONS -- KMC11
|
||
|
||
SEL0==0
|
||
BSEL1==1
|
||
KMCRUN==100000 ;RUN FLOP
|
||
KMCMCL==040000 ;MASTER CLEAR
|
||
KMCCWR==020000 ;CRAM WRITE
|
||
KMCSLU==010000 ;STEP LINE UNIT
|
||
KMCLUL==004000 ;LINE UNIT LOOP
|
||
KMCRMO==002000 ;ROM OUTPUT
|
||
KMCRMI==001000 ;ROM INPUT
|
||
KMCSUP==000400 ;STEP u-PROCESSOR
|
||
KMCRQI==000200 ;REQUEST INPUT
|
||
KMCIEO==000020 ;INTERRUPT ENABLE OUTPUT
|
||
KMCIEI==000001 ;INTERRUPT ENABLE INPUT
|
||
SEL2==2
|
||
BSEL3==3 ;CONTAINS LINE NUMBER
|
||
KMCOVR==100000 ;KMC BUFFER OVER-RUN
|
||
KMCRDO==000200 ;READY FOR OUTPUT
|
||
KMCRDI==000020 ;READY FOR INPUT
|
||
KMCIOT==000004 ;SET FOR RECEIVE CLEARED FOR TRANSMIT
|
||
KMCTYP==000003 ;COMMAND TYPE
|
||
BASEIN==000003 ;BASE IN
|
||
CNTLIN==000001 ;CONTROL IN
|
||
BFADIN==000000 ;BUFFER ADDRESS IN
|
||
CNTLOU==000001 ;CONTROL OUT
|
||
BFADOU==000000 ;BUFFER ADDRESS OUT
|
||
SEL4==4
|
||
BSEL5==5
|
||
;BUFFER DESCRIPTOR LIST ADDRESS
|
||
; (BUFFER ADR IN & OUT & CONTROL OUT)
|
||
SEL6==6
|
||
BSEL7==7
|
||
;140000 ;ADR BITS 17 & 16
|
||
; (BUFFER ADR IN & OUT & CONTROL OUT)
|
||
BFREOM==010000 ;END OF MESSAGE (BUFFER ADR OUT)
|
||
BFRENB==020000 ;BUFFER ENABLE (BUFFER ADR IN)
|
||
BFRKIL==010000 ;BUFFER KILL (BUFFER ADR IN)
|
||
CSRMSK==017770 ;MASK FOR DUP11 CSR ADR (BASE IN)
|
||
CDDCMP==100000 ;FLAG THIS A DDCMP LINE (CONTROL IN)
|
||
CHALFD==020000 ;FLAG THIS IS HALF DUPLEX (CONTROL IN)
|
||
;010000 ;ENABLE SECONDARY STATION (CONTROL IN)
|
||
;001000 ;CRC INHIBIT (CONTROL IN)
|
||
CENABL==000400 ;FLAG TO ENABLE LINE (CONTROL IN)
|
||
COUERR==000377 ;ERROR CODE (CONTROL OUT)
|
||
|
||
CRAMSZ==2000 ;SIZE OF KMC11 CRAM
|
||
DRAMSZ==2000 ;SIZE OF KMC11 DRAM
|
||
;BUFFER DESCRIPTOR LISTS ARE STRINGS OF 3 16 BIT WORDS
|
||
; 1ST WORD 16 BITS OF BUFFER ADDRESS
|
||
; 2ND WORD 16 BIT BYTE COUNT
|
||
; 3RD WORD
|
||
BDLLDS==100000 ;LAST DESCRIPTOR
|
||
BDLRSY==010000 ;RESYNC TRANSMITTER
|
||
BDLXAD==006000 ;BUFFER ADDRESS BITS 17 & 16
|
||
BDLEOM==001000 ;END OF MESSAGE
|
||
BDLSOM==000400 ;START OF MESSAGE
|
||
|
||
|
||
;MESSAGES TO THE KMC11
|
||
; BASEIN: BSEL2/ <LINE #>*400+3
|
||
; BSEL6/ <DUP11 ADR>&017770
|
||
; CONTROL IN: BSEL2/ <LINE #>*400+1
|
||
; BSEL6/ FLAGS
|
||
; BF AD IN: BSEL2/ <LINE NU>*400+0+<4 IF INPUT>
|
||
; BSEL4/ BUFFER DESCRIPTOR LIST ADR
|
||
; BSEL6/ FLAGS
|
||
; BF AD OUT: BSEL2/ <LINE NU>*400+0+<4 IF RECEIVE>
|
||
; BSEL4/ BUFFER DESCRIPTOR LIST ADR
|
||
; BSEL6/ FLAGS
|
||
; CONTROL OUT: BSEL2/ <LINE NU>*400+1+<4 IF RECEIVE>
|
||
; BSEL4/ BUFFER DESCRIPTOR LIST ADR
|
||
; BSEL6/ ERROR CODE
|
||
|
||
|
||
;CONTROL OUT BIT MASK DEFINITIONS. THE ROUTINE "CTOTLY" TAKES A
|
||
; CONTROL OUT CODE, TALLYS THE CONTROL OUT IN THE KDL BLOCK, AND
|
||
; PRODUCES A BIT VECTOR OF ONE BIT REPRESENTING THE CODE. THIS
|
||
; BIT VECTOR REPRESENTATION IS USED TO FACILITATE PARALLEL TESTING
|
||
; FOR VARIOUS CONDITIONS. BIT DEFINITIONS ARE:
|
||
|
||
CTLO06==040000 ;ABORT. SHOULD NEVER HAPPEN
|
||
CTLO10==020000 ;HEADER CRC ERROR.
|
||
CTLO12==010000 ;DATA CRC ERROR.
|
||
CTLO14==004000 ;NO RECEIVE BUFFER ASSIGNED
|
||
CTLO16==002000 ;DATA SET READY TRANSITION
|
||
CTLO20==001000 ;KMC-11 GOT A NXM ON A UNIBUS ADDRESS
|
||
CTLO22==000400 ;TRANSMIT UNDERRUN.
|
||
CTLO24==000200 ;RECEIVE OVERRUN
|
||
CTLO26==000100 ;BUFFER KILL COMPLETE
|
||
SUBTTL KDPONC -- ONCE ONLY ROUTINE FOR KMC/DUP
|
||
|
||
;THIS ROUTINE IS CALLED BY SYSINI. IT VERIFYS THAT ALL KMC-11 AND
|
||
; DUP-11 UNITS SPECIFIED BY MONGEN ACTUALLY EXIST.
|
||
|
||
|
||
KDPONC::PUSHJ P,SAVE2## ;HERE FROM ONCE. WE USE 2 P'S
|
||
MOVSI P1,(DF.RQK) ;JUST TO GET THINGS STARTED,
|
||
IORM P1,DEBUGF## ; REQUEST KDPLDR TO RUN NEXT (FIRST) TICK
|
||
|
||
SETZ P1, ;P1 IS CURRENT KDP INDEX, START WITH KDP ZERO
|
||
|
||
KDPOCP: CAILE P1,KDPMAX## ;LOOP OVER ALL KDP'S
|
||
POPJ P, ;IF WE'VE DONE THEM ALL, RETURN
|
||
|
||
SKIPN W,KDPTBL##(P1) ;GET THE ADDRESS OF THE NEXT KDP BLOCK
|
||
AOJA P1,KDPOCP ; IF IT'S NOT THERE, TRY THE NEXT ONE
|
||
HLRZ T1,KDPCSR(W) ;GET UNIBUS ADAPTER NUMBER
|
||
MOVEI T2,KDLPPL ;NUMBER OF MAPPING REGISTERS REQUIRED
|
||
PUSHJ P,AUTAMR## ;ALLOCATE MAPPING REGISTERS
|
||
JRST KDPNXP ;DUH?
|
||
MOVEM T1,KDPIMR(W) ;SAVE FIRST MAPPING REGISTER NUMBER
|
||
MOVEM T3,KDPIEA(W) ;SAVE INITIAL ELEVEN ADDRESS
|
||
MOVE T1,KDPCSR(W) ;GET THE ADDRESS OF THE KMC-11/KDP
|
||
PUSHJ P,UBGOOD## ;SEE IF IT EXISTS (UNIBUS TRAP/DOESN'T TRAP)
|
||
JRST KDPNXP ;NON-EXISTANT KMC/KDP
|
||
|
||
;NOW MAKE SURE IT'S NOT RUNNING (OTHERWISE IT WILL INTERRUPT BEFORE
|
||
; THE VECTORS ARE SET UP)
|
||
|
||
MOVEI T1,KMCMCL ;GET THE MASTER CLEAR BIT.
|
||
WRIO T1,@KDPCSR(W) ;STOP IT GOOD.
|
||
;NOW CHECK ALL LINES ON THE KDP
|
||
|
||
SETZ P2, ;START WITH LINE ZERO
|
||
|
||
KDPOCL: CAML P2,KDPDPN(W) ;LOOP OVER ALL LINES
|
||
AOJA P1,KDPOCP ;WHEN DONE ALL LINES, DO NEXT KDP
|
||
|
||
MOVEI F,KDPKDL(W) ;GET THE ADDRESS OF THE KDL TABLE
|
||
ADDI F,(P2) ;RELOCATE TO THIS LINE
|
||
SKIPN F,(F) ;GET ADDRESS OF KDL PAGE (SKIP IF VALID)
|
||
AOJA P2,KDPOCL ;DUP-11 PATCHED OUT. DO NEXT ONE.
|
||
|
||
PUSH P,KDLUSR(F) ;PRESERVE THE MONGEN LINE USER
|
||
HRLI T1,(F) ;GET FROM ADDRESS
|
||
HRRI T1,1(F) ;GET TO ADDRESS
|
||
SETZM (F) ;ZERO FIRST WORD AND
|
||
BLT T1,KDLLEN-1(F) ; BLT THE ENTIRE PAGE TO ZERO
|
||
POP P,KDLUSR(F) ;RESTORE LINE USER SO WE AUTO START
|
||
|
||
MOVEI T1,(P2) ;GET A COPY OF THE LINE NUMBER
|
||
LSH T1,3 ; * 8 TO GET DUP-11 CSR OFFSET
|
||
ADD T1,KDP1DP(W) ;RELOCATE TO THE ADDRESS OF KDP'S 1ST DUP
|
||
PUSHJ P,UBGOOD## ;SEE IF THE DUP-11 EXISTS.
|
||
JRST KDPNXL ;NON-EXISTANT DUP-11
|
||
AOJA P2,KDPOCL ;GO CHECK NEXT LINE.
|
||
;KDPNXP - ROUTINE TO DECLARE A KMC-11 NON-EXISTANT. UNIT IS MARKED
|
||
; NON-EXISTANT BY PUTTING A ZERO IN IT'S "KDPTBL" ENTRY.
|
||
|
||
KDPNXP: SETZM KDPTBL##(P1) ;CLEAR THE KDP TABLE ENTRY SO IT'S IGNORED
|
||
MOVE U,OPRLDB## ;GET THE ADDRESS OF THE OPR'S TTY
|
||
PUSHJ P,INLMES## ;TELL HIM FIRST PART OF BAD NEWS.
|
||
ASCIZ /? No KMC-11 for /
|
||
PUSHJ P,PRKDP ;TELL HIM WHICH KDP (FROM "W")
|
||
PUSHJ P,INLMES## ;FINISH THE MESSAGE
|
||
ASCIZ /.
|
||
/
|
||
AOJA P1,KDPOCP ;GO DO NEXT KDP
|
||
|
||
|
||
;KDPNXL - ROUTINE TO DECLARE A DUP-11 NON-EXISTANT. LINE IS MARKED
|
||
; NON-EXISTANT BY PUTTING A ZERO IN IT'S "KDPKDL" ENTRY.
|
||
|
||
KDPNXL: MOVEI T1,KDPKDL(W) ;GET THE ADDRESS OF THE KDL TABLE
|
||
ADDI T1,(P2) ;GET ADDRESS OF ENTRY FOR THIS LINE
|
||
SETZM (T1) ;CLEAR IT SO DUP-11 WON'T BE USED
|
||
MOVEM P2,KDLINE(F) ;SET LINE NUMBER IN PAGE FOR "PRKDL"
|
||
MOVE U,OPRLDB## ;GET THE ADDRESS OF THE OPRS TERMINAL
|
||
PUSHJ P,INLMES## ;TELL HIM THE FIRST PART OF THE BAD NEWS
|
||
ASCIZ /? No DUP-11 for /
|
||
PUSHJ P,PRKDL ;TELL HIM WHICH LINE
|
||
PUSHJ P,INLMES## ;FINISH THE LINE
|
||
ASCIZ /.
|
||
/
|
||
AOJA P2,KDPOCL ;STEP TO THE NEXT LINE
|
||
;KDPLDR ROUTINE TO START KDPLDR ON "FRCLIN"
|
||
;CALL PUSHJ P,KDPLDR## ;CALLED FROM CLOCK1
|
||
;RETURN POPJ ;ALWAYS
|
||
|
||
KDPLDR::SKIPGE DEBUGF## ;DON'T RUN IF DEBUGGING
|
||
POPJ P, ;THINGS ARE CONFUSING ENOUGH AS IT IS
|
||
PUSHJ P,FRCSET## ;SETUP TO TYPE ON FRCLIN
|
||
PUSHJ P,INLMES## ;TYPE THE COMMAND
|
||
ASCIZ /KDPLDR/
|
||
PJRST CRLF## ;TYPE THE CLOSING CRLF AND WE'RE DONE
|
||
SUBTTL KDPSEC - ONCE/SECOND PROCESSING
|
||
|
||
;KDPSEC THIS ROUTINE PERFORMS THE TIMING FUNCTIONS REQUIRED BY DDCMP
|
||
; IN PARTICULAR, IT SENDS
|
||
; STARTS WITH PERIOD "STRSEC"
|
||
; STACKS WITH PERIOD "STKSEC"
|
||
; REPS WITH PERIOD "REPSEC"
|
||
; IT ALSO COUNTS THE NUMBER OF "UN-ANSWERED" REPS, AND DECLARES THE
|
||
; LINE DOWN IF THIS COUNT EXCEEDS "REPMAX".
|
||
; IN THE EVENT THAT A LINE-DOWN EVENT DOES OCCUR, THE
|
||
; OPERATOR IS INFORMED THAT THE LINE "TIMED OUT"
|
||
|
||
KDPSEC::PUSHJ P,SAVEFW ;PRESERVE W & F
|
||
PUSHJ P,SAVE2## ;P1 := KDP COUNT, P1 := KDL
|
||
SETZ P1, ;START AT THE FIRST (0 TH) KDP
|
||
KDPSEP: CAILE P1,KDPMAX## ;IF WE HAVE DONE ALL KMC-11'S
|
||
POPJ P, ; THEN RETURN
|
||
SETZ P2, ;START AT LINE ZERO ON EACH KDP
|
||
SKIPE W,KDPTBL##(P1) ;IF THE KDP EXISTS, THEN
|
||
PUSHJ P,KDPSEL ; GO PROCESS IT'S LINES
|
||
AOJA P1,KDPSEP ;COUNT THE KDP AND TRY THE NEXT
|
||
|
||
KDPSEL: CAML P2,KDPDPN(W) ;IF WE HAVE PROCESSED ALL LINES ON THIS
|
||
POPJ P, ; KDP, THEN RETURN
|
||
MOVEI F,KDPKDL(W) ;GET ADDRESS OF THIS KDP'S KDL TABLE
|
||
ADD F,P2 ; AND CALCULATE ADDRESS OF CURRENT LINE
|
||
SKIPE F,(F) ;IF THE LINE EXISTS, THEN
|
||
PUSHJ P,KDPSE0 ; GO DO 1/SECOND PROCESSING ON IT
|
||
AOJA P2,KDPSEL ;LOOP OVER ALL LINES ON THE KDL
|
||
KDPSE0: AOS KDLZTM(F) ;INDICATE THAT WE'VE BEEN UP A SECOND LONGER
|
||
PUSHJ P,FREMAI ;FREE ANY STALE MAINTENANCE MESSAGES
|
||
|
||
KDPOFF ;WE BETTER BE CAREFULL WHEN IT'S RUNNING
|
||
|
||
LDB T1,KDLSTA## ;GET OUR STATE
|
||
SUBI T1,KD%STR ;ADJUST SO THAT "SENDING STARTS" IS STATE 0
|
||
JUMPL T1,KDPSE2 ; ANY STATE BEFORE DOESN'T GET TIMED
|
||
|
||
CAILE T1,KD%RUN-KD%STR ;[DBUG] JUST MAKE SURE IT'S A
|
||
PUSHJ P,NTDSTP## ;[DBUG] REASONABLE STATE
|
||
|
||
LDB T2,KDLTIM## ;GET THE TIMER
|
||
CAIN T2,KD%MXT ;STOPPED?
|
||
JRST KDPSE2 ;YES, IGNORE IT
|
||
AOS T2 ;COUNT UP ONE MORE SECOND
|
||
DPB T2,KDLTIM## ;PUT THE UPDATED TIME BACK
|
||
CAMGE T2,[EXP STRSEC,STKSEC,REPSEC](T1) ;HAS IT OVERFLOWED
|
||
JRST KDPSE2 ; IF NOT, JUST CALL NETSER
|
||
SETO T2, ;IF IT'S OVERFLOWED, STOP IT
|
||
DPB T2,KDLTIM## ; (NEXT EVENT WILL RESTART IT IF NECESSARY)
|
||
MOVE T2,[EXP KDSSTR,KDSSTK,KDSREP](T1) ;GET "REQUEST BIT" TO SET.
|
||
IORM T2,KDLSTS(F) ;REQUEST THE APROPRIATE CONTROL MESSAGE
|
||
TLNN T2,(KDSREP) ;WAS THIS A "REP"
|
||
JRST KDPSE1 ; IF NOT, SEND MESSAGE AND EXIT.
|
||
|
||
LDB T1,KDLRPC## ;IF IT'S A REP, GET THE REPCOUNT
|
||
AOS T1 ; AND ACCOUNT FOR THE COMING REP.
|
||
DPB T1,KDLRPC## ;STORE THE UPDATED COUNT BACK
|
||
CAIG T1,REPMAX ;HAVE WE "REP TIMED-OUT"?
|
||
JRST KDPSE1 ; IF NOT, JUST SEND THE REP AND EXIT
|
||
|
||
;FALL THROUGH TO DECLARE THE LINE DOWN
|
||
;(FROM ABOVE) LINE HAS TIMED OUT. RESTART IT AND TELL THE OPERATOR.
|
||
|
||
MOVEI T1,KD%STR ;GET THE "SENDING START'S STATE"
|
||
DPB T1,KDLSTA## ; AND PUT THIS LINE IN THAT STATE
|
||
MOVSI T1,(XMTBTS) ;GET MASK OF "MESSAGE QUEUED" BITS
|
||
ANDCAM T1,KDLSTS(F) ; AND CLEAR ALL PENDING REQUESTS
|
||
MOVSI T1,(KDSSTR) ;GET THE "SEND A START" REQUEST BIT
|
||
IORM T1,KDLSTS(F) ; AND REQUEST A START
|
||
|
||
PUSHJ P,KDLPDN ;TELL OWNER THAT THIS LINE IS RESTARTING.
|
||
|
||
KDPON ;ALLOW INTERRUPTS WHILE CALLING SCNSER
|
||
|
||
MOVE U,OPRLDB## ;WE WANT TO TELL THE OPR, GET HIS LDB ADDR
|
||
PUSHJ P,INLMES## ;SEND FIRST PART OF MESSAGE
|
||
ASCIZ /%% Synch line /
|
||
PUSHJ P,PRKDL ;PRINT THE FULL KDP#, KDL# MESSAGE
|
||
PUSHJ P,INLMES## ;NOW FINISH THE MESSAGE WITH .CRLF
|
||
ASCIZ / timed out.
|
||
/
|
||
|
||
KDPOFF ;NO INTERRUPTS FOR XMT/RCV BUF
|
||
KDPSE1: PUSHJ P,RCVBUF ;MAKE SURE WE'VE POSTED RECEIVE BUFFERS
|
||
PUSHJ P,XMTBUF ;TRY TO SEND THE MESSAGE
|
||
KDPSE2: KDPON ;INT'S OK NOW
|
||
POPJ P, ; AND WE'RE DONE
|
||
SUBTTL KDP. -- UUO INTERFACE TO THE KMC/DUP LINE UNIT.
|
||
;KDP.
|
||
;
|
||
;FUNCTIONS THAT AFFECT THE KMC AND/OR ALL DUP-11'S CONNECTED:
|
||
;
|
||
; KDP.KN ;RETURN THE NUMBER OF KMC-11'S ON SYS
|
||
; KDP.DN ;RETURN THE NUMBER OF DUP-11'S ON A KMC
|
||
; KDP.HA ;HALT THE KMC. ARG1 = KMC #
|
||
; KDP.MC ;MASTER CLEAR. ARG1 = KMC #
|
||
; KDP.ST ;START THE KMC. ARG1 = KMC #
|
||
; KDP.RE ;READ CRAM. ARG1 = KMC #,
|
||
; ; ARG2 = CRAM ADDRESS,
|
||
; ; ARG3 GETS CONTENTS OF CRAM
|
||
; KDP.WR ;WRITE CRAM. ARGS AS IN KDP.RE.
|
||
; KDP.KS ;GET THE STATUS OF THE KMC.
|
||
;
|
||
;FUNCTIONS THAT AFFECT JUST A SINGLE DUP-11:
|
||
;
|
||
; KDL.RS ;READ DUP-11'S STATUS REGISTERS
|
||
; KDL.HA ;HALT DDCMP ON THE LINE
|
||
; KDL.ST ;START DDCMP ON THE LINE
|
||
; KDL.SU ;SET THE LINE'S USER
|
||
;
|
||
;ERRORS
|
||
|
||
KE%ILF==ECOD1## ;ILLEGAL FUNCTION CODE
|
||
KE%ILK==ECOD2## ;ILLEGAL KDP NUMBER
|
||
KE%ALS==ECOD3## ;ARG LIST TOO SHORT
|
||
KE%IWR==ECOD4## ;ILLEGAL WHEN KMC-11 RUNNING
|
||
KE%ICA==ECOD5## ;ILLEGAL CRAM ADDRESS (READ OR WRITE)
|
||
KE%ILL==ECOD6## ;ILLEGAL LINE NUMBER
|
||
KE%KNR==ECOD7## ;KMC-11 NOT RUNNING (KDL TYPE OP'S)
|
||
KE%LNS==ECOD10## ;KDL LINE NOT STARTED
|
||
KE%LAS==ECOD11## ;KDL LINE ALREADY STARTED
|
||
KE%UNP==ECOD12## ;USER NOT PRIVILEGED
|
||
KE%IUN==ECOD13## ;ILLEGAL LINE USER NAME (SET LINE USER FCN)
|
||
KE%NDL==ECOD14## ;NO DDB FOR LINE WHILE TRYING TO START PROTOCOL
|
||
UKDP:: PUSHJ P,SAVE2## ;SAVE A COUPLE OF P'S
|
||
HLRZ P2,T1 ;SAVE THE LENGTH OF THE ARG LIST
|
||
CAIGE P2,2 ;MAKE SURE THAT THERE ARE AT LEAST 2 ARGS
|
||
PJRST KE%ALS ;ILLEGAL ARGUMENT LIST
|
||
HRR M,T1 ;SET RH(M) := ADDRESS OF ARG LIST
|
||
PUSHJ P,GETWDU## ;GET THE FUNCTION CODE
|
||
JUMPLE T1,KE%ILF ;ILLEGAL FUNCTION
|
||
CAILE T1,KDOPMX ;RANGE CHECK FOR KDP FUNCTIONS
|
||
JRST [CAILE T1,KLOPST;IF NOT KDP, SEE IF KDL FUNCTION
|
||
CAILE T1,KLOPMX; WHICH IS BETWEEN THESE TWO VALUES
|
||
PJRST KE%ILF ;ILLEGAL FUNCTION
|
||
JRST .+1] ;LEGAL FUNCTION. CONTINUE WITH MAIN FLOW
|
||
MOVEI P1,(T1) ;REMEMBER THE FUNCTION CODE FOR LATER
|
||
CAIG P1,1 ;IF IT'S A KDPOP THAT DOESN'T SPECIFY A KDP
|
||
JRST KDPOP. ; GO TO THE DISPATCH NOW
|
||
PUSHJ P,GETWD1## ;GET THE KMC-11 NUMBER
|
||
SKIPL T1 ;MAKE SURE THAT IT'S A
|
||
CAILE T1,KDPMAX## ; LEGAL KMC-11 NUMBER
|
||
PJRST KE%ILK ;EXIT IF ILLEGAL KMC-11 NUMBER
|
||
SKIPN W,KDPTBL##(T1) ;LOAD KDP POINTER
|
||
PJRST KE%ILK ;KMC MUST NOT EXIST (ONCE DIDN'T FIND IT)
|
||
|
||
;HERE IF THIS IS A KMC-11 (KDP) ORIENTED FUNCTION
|
||
; AT THIS POINT:
|
||
;
|
||
; P1 := KDP. FUNCTION CODE.
|
||
; P2 := LENGTH OF ARG-LIST.
|
||
|
||
KDPOP.: CAILE P1,KDOPMX ;IS THIS A KDP OR A KDL STYLE OP?
|
||
JRST KDLOP. ;THIS IS A KDL OP. USE DIFFERENT DISPATCH
|
||
JRST @.(P1) ;DISPATCH ON THE FUNCTION CODE
|
||
JRST KDPKN ; 1 = RETURN NUMBER OF KMC-11'S
|
||
JRST KDPDN ; 2 = RETURN NUMBER OF DUP=11'S
|
||
JRST KDPSS ; 3 = READ STATUS
|
||
JRST KDPHA ; 4 = HALT KMC-11
|
||
JRST KDPMC ; 5 = MASTER CLEAR THE KMC (DECLARE LINES DOWN)
|
||
JRST KDPST ; 6 = START THE KMC-11
|
||
JRST KDPRE ; 7 = READ A KMC-11 CRAM LOCATION
|
||
JRST KDPWR ; 8 = WRITE A KMC-11 CRAM LOCATION
|
||
KDOPMX==8 ;MAXIMUM KDP FUNCTION CODE
|
||
;HERE IF THIS IS A DUP-11 (KDL) ORIENTED FUNCTION
|
||
; AT THIS POINT:
|
||
;
|
||
; P1 := KDP. FUNCTION CODE.
|
||
; P2 := LENGTH OF ARG-LIST.
|
||
|
||
|
||
KDLOP.: CAIGE P2,3 ;MAKE SURE THERE IS A THIRD ARG (LINE #)
|
||
PJRST KE%ALS ; IF NOT, GIVE ARG LIST TOO SHORT ERROR
|
||
PUSHJ P,GETWD1## ;GET THE DUP-11 NUMBER
|
||
CAML T1,KDPDPN(W) ;MAKE SURE IT'S IN RANGE
|
||
PJRST KE%ILL ; IF NOT, GIVE "ILLEGAL LINE NUMBER" ERROR
|
||
|
||
MOVEI F,KDPKDL(W) ;GET ADDRESS OF POINTERS TO KDL BLOCKS
|
||
ADDI F,(T1) ;ADD OFFSET TO PROPER LINE
|
||
SKIPN F,(F) ;LOAD ADDRESS OF KDL BLOCK
|
||
PJRST KE%ILL ;DUP-11 DOES NOT EXIST. (ONCE DIDN'T FIND IT)
|
||
|
||
KLOPTB: JRST @.-KLOPST(P1) ;DISPATCH ON THE FUNCTION CODE
|
||
KLOPST==100 ;LINE OP'S START AT "100"
|
||
JRST KDLRS ; 1 = READ LINE'S STATUS
|
||
JRST KDLHA ; 2 = HALT THE LINE (STOP DDCMP)
|
||
JRST KDLST ; 3 = START THE LINE (CONTROL OUT) START DDCMP
|
||
JRST KDLSU ; 4 = SET LINE'S USER (ANF, DECnet, PROGRAM)
|
||
JRST KDLRU ; 5 = READ LINE'S USER IN SIXBIT
|
||
KLOPMX==KLOPST+.-KLOPTB ;MAX OP CODE ALLOWED
|
||
SUBTTL KDP. SUB-FUNCTIONS (KDPOP.)
|
||
|
||
;HERE ARE THE VARIOUS KMC-11 (KDP) ORIENTED FUNCTION
|
||
; AT THIS POINT:
|
||
;
|
||
; P1 := KDP. FUNCTION CODE.
|
||
; P2 := LENGTH OF ARG-LIST.
|
||
|
||
; #1 -- RETURN THE NUMBER OF KDP'S ON THE SYSTEM
|
||
KDPKN: MOVEI T1,KDPMAX## ;GET NUMBER OF THE LAST ONE
|
||
ADDI T1,1 ;INCREMENT IT TO GET A COUNT
|
||
PUSHJ P,PUTWD1## ;RETURN THE NUMBER IN ARG #2
|
||
RETSKP ;GIVE GOOD RETURN
|
||
|
||
|
||
; #2 -- RETURN THE NUMBER OF DUP-11'S ON A PARTICULAR KDP
|
||
KDPDN: MOVE T1,KDPDPN(W) ;GET THE NUMBER OF DUP-11'S ON THIS KDP
|
||
PUSHJ P,PUTWD1## ;RETURN THE NUMBER IN ARG #3
|
||
RETSKP ;GIVE GOOD RETURN
|
||
|
||
|
||
; #3 -- RETURN THE STATUS WORD OF KDP BLOCK
|
||
KDPSS: MOVE T1,KDPSTS(W) ;GET THE STATUS WORD
|
||
PUSHJ P,PUTWD1## ;RETURN STATUS WORD
|
||
RETSKP ;GIVE GOOD RETURN
|
||
|
||
|
||
; #4 -- HALT THE KMC-11. THIS DOES NOT DECLARE DUP-11 LINES DOWN SINCE
|
||
; SETTING THE RUN BIT WOULD, IN THEORY, ALLOW THE KMC-11 TO CONTINUE.
|
||
KDPHA: PUSHJ P,NTDPRV## ;THIS IS A PRIVILEGED FUNCTION
|
||
PJRST KE%UNP ;IF NO PRIVILEGES, GIVE ERROR RETURN
|
||
MOVEI T1,0 ;GET THE KMC-11 RUN BIT
|
||
WRIO T1,@KDPCSR(W) ;CLEAR THE RUN/MAINT BITS
|
||
MOVSI T1,(KDPSRU) ;GET THE "MICROCODE RUNNING" BIT
|
||
ANDCAM T1,KDPSTS(W) ; AND CLEAR THAT
|
||
RETSKP ;GIVE GOOD RETURN
|
||
|
||
|
||
; #5 -- MASTER CLEAR THE KMC-11. THIS DECLARES THE DUP-11 LINES DOWN SINCE
|
||
; THERE IS NOW NO WAY TO CONTINUE DDCMP ON THEM.
|
||
KDPMC: PUSHJ P,NTDPRV## ;THIS IS A PRIVILEGED FUNCTION
|
||
PJRST KE%UNP ;IF NO PRIVILEGES, GIVE ERROR RETURN
|
||
PUSHJ P,KDPHLT ;LET "HALT" DO THE WORK
|
||
RETSKP ;GIVE GOOD RETURN
|
||
; #6 -- START THE KMC-11. THIS FIRST STARTS THE KMC-11, AND THEN
|
||
; SETS UP THE INTERRUPT VECTORS. ONCE THE VECTORS ARE SET UP,
|
||
; IT SETS THE TWO KMC-11 INTERRUPT ENABLES, AND DECLARES THE KDP RUNNING.
|
||
KDPST: PUSHJ P,NTDPRV## ;THIS IS A PRIVILEGED FUNCTION
|
||
PJRST KE%UNP ;IF NO PRIVILEGES, GIVE ERROR RETURN
|
||
MOVEI T1,KMCRUN ;GET THE RUN BIT
|
||
TIOE T1,@KDPCSR(W) ;MAKE SURE THE KMC-11 ISN'T RUNNING ALREADY
|
||
PJRST KE%IWR ;IF IT IS, GIVE "ILLEGAL WHEN RUNNING" ERROR
|
||
WRIO T1,@KDPCSR(W) ;SET RUN NOW, WILL SET IEI & IEO SOON
|
||
; (MUST GIVE KMC TIME TO INIT)
|
||
|
||
HLRZ T1,KDPCSR(W) ;GET UNIBUS ADAPTER NUMBER
|
||
MOVE T2,KDPVEC(W) ;GET THE ADDRESS OF THE VECTOR
|
||
PUSHJ P,AUTVIA## ;COMPUTE ADDRESS OF VECTOR INSTRUCTION
|
||
MOVSI T2,(XPCW) ;GET BODY OF A "XPCW" INSTRUCTION
|
||
HRRI T2,KDPIVA(W) ;GET ADDRESS OF VECTOR "A" INTERRUPT SERVICE
|
||
MOVEM T2,0(T1) ;STORE ADDRESS OF ROUTINE TO FORCE JSR TO
|
||
HRRI T2,KDPIVB(W) ;GET ADDRESS OF "B" SERVICE ROUTINE
|
||
MOVEM T2,1(T1) ;SET UP VECTOR "B" INTERRUPT SERVICE
|
||
|
||
MOVEI T1,KMCRUN!KMCIEI!KMCIEO ;START THE KMC-11 AND ENABLE INTS
|
||
WRIO T1,@KDPCSR(W) ;START THE KMC-11
|
||
|
||
MOVSI T1,(KDPSRU) ;GET AND SET THE "RUNNING"
|
||
IORB T1,KDPSTS(W) ; BIT SO IT AT LEAST LOOKS LIKE WE'RE UP.
|
||
|
||
RETSKP ;ALL DONE. GIVE THE USER A GOOD RETURN
|
||
; #7 -- READ A KMC-11 CRAM LOCATION. KMC-11 MUST BE HALTED
|
||
KDPRE: CAIGE P2,4 ;MAKE SURE THE ARG LIST IS LONG ENOUGH
|
||
PJRST KE%ALS ;IF ARG LIST IS TO SHORT, GIVE AN ERROR
|
||
MOVE P1,KDPCSR(W) ;GET THE ADDRESS OF THE CSR FOR THE KMC-11
|
||
MOVEI T1,KMCRUN ;GET THE RUN BIT
|
||
TIOE T1,SEL0(P1) ;SEE IF THE KMC-11 IS RUNNING
|
||
PJRST KE%IWR ;IF IT IS RUNNING, GIVE AN ERROR
|
||
MOVEI T1,KMCRMO ;GET THE "READ CRAM" BIT
|
||
WRIO T1,SEL0(P1) ;ENABLE THE KMC-11 FOR MAINT CRAM READ
|
||
PUSHJ P,GETWD1## ;GET THE ARG WHICH IS THE CRAM ADDRESS
|
||
CAIL T1,0 ;RANGE CHECK THE CRAM ADDRESS
|
||
CAIL T1,CRAMSZ ; TO BE SURE IT FITS IN THE CRAM
|
||
PJRST KE%ICA ;GIVE AN ILLEGAL CRAM ADDR IF IT'S OUT
|
||
WRIO T1,SEL4(P1) ;STORE THE ADDRESS IN MAINT CRAM ADDR REG
|
||
RDIO T1,SEL6(P1) ;READ THE CRAM LOCATION
|
||
PUSHJ P,PUTWD1## ;STORE THE RESULT IN ARG #4
|
||
PJRST KDPHA ;CLEAR KDPSRU AND EXIT
|
||
|
||
|
||
; #8 -- WRITE A KMC-11 CRAM LOCATION. JUST LIKE READ (ALMOST)
|
||
KDPWR: CAIGE P2,4 ;MAKE SURE THE ARG LIST IS LONG ENOUGH
|
||
PJRST KE%ALS ;IF ARG LIST IS TO SHORT, GIVE AN ERROR
|
||
MOVE P1,KDPCSR(W) ;GET THE ADDRESS OF THE CSR FOR THE KMC-11
|
||
MOVEI T1,KMCRUN ;GET THE RUN BIT
|
||
TIOE T1,SEL0(P1) ;SEE IF THE KMC-11 IS RUNNING
|
||
PJRST KE%IWR ;IF IT IS RUNNING, GIVE AN ERROR
|
||
MOVEI T1,KMCRMO ;GET THE "READ CRAM" BIT
|
||
WRIO T1,SEL0(P1) ;ENABLE THE KMC-11 FOR MAINT CRAM READ
|
||
PUSHJ P,GETWD1## ;GET THE ARG WHICH IS THE CRAM ADDRESS
|
||
CAIL T1,0 ;RANGE CHECK THE CRAM ADDRESS
|
||
CAIL T1,CRAMSZ ; TO BE SURE IT FITS IN THE CRAM
|
||
PJRST KE%ICA ;GIVE AN ILLEGAL CRAM ADDR IF IT'S OUT
|
||
WRIO T1,SEL4(P1) ;STORE THE ADDRESS IN MAINT CRAM ADDR REG
|
||
PUSHJ P,GETWD1## ;GET THE VALUE TO WRITE
|
||
WRIO T1,SEL6(P1) ;PUT IT IN THE CRAM MEMORY BUFFER REGISTER
|
||
MOVEI T1,KMCCWR ;GET THE CRAM WRITE BIT
|
||
BSIO T1,SEL0(P1) ;CLOCK THE DATA INTO THE CRAM
|
||
PJRST KDPHA ;CLEAR KDPSRU AND EXIT
|
||
SUBTTL KDLOP. SUB-FUNCTIONS.
|
||
|
||
;THESE ARE THE DUP-11 (KDL) ORIENTED KDP. SUB-FUNCTIONS.
|
||
; AT THIS POINT:
|
||
;
|
||
; T1 := THE DUP-11'S LINE NUMBER (NEEDED FOR "START")
|
||
; P1 := KDP. FUNCTION CODE.
|
||
; P2 := LENGTH OF THE ARGLIST
|
||
|
||
; #101 RETURN THE LINE STATUS BLOCK. RETURNS ALL COUNTERS ETC...
|
||
|
||
KDLRS: CAIGE P2,4 ;SKIP IF ARG LIST CONTAINS "XWD LEN,ADDR"
|
||
PJRST KE%ALS ;ARG LIST TOO SHORT IF NOT THERE
|
||
PUSHJ P,GETWD1## ;GET "XWD LENGTH,ADDRESS" OF RETURN VAL AREA
|
||
MOVE P2,T1 ;COPY IT TO A SAFER PLACE
|
||
HLRZ T2,P2 ;GET THE LENGTH OF THE RETURN VALUE AREA
|
||
CAIGE T2,<KDLEST-KDLSTS>+1 ;SEE IF IT WILL HOLD THE DATA
|
||
PJRST KE%ALS ;GIVE ARGLIST TOO SHORT ERROR IF WON'T FIT
|
||
MOVEI T1,(P2) ;GET USER ADDRESS OF RETURN AREA
|
||
ADDI T2,-1(T1) ;GET ADDRESS OF LAST WORD IN AREA
|
||
PUSHJ P,TRNGE## ;MAKE SURE IT'S ALL IN CORE.
|
||
MOVEI T1,(P2) ;GET ADDRESS OF RETURN AREA BACK
|
||
MOVEI T2,<KDLEST-KDLSTS>+1 ;GET LENGTH OF STATUS BLOCK
|
||
ADDI T2,-1(T1) ;GET ADDRESS OF LAST WORD TO WRITE
|
||
HRLI T1,KDLSTS(F) ;GET ADDRESS OF FIRST STATUS WORD TO SEND
|
||
EXCTXU <BLT T1,(T2)> ;COPY THE BLOCK INTO USER MEMORY
|
||
RETSKP ;GIVE GOOD RETURN
|
||
; #102 HALT A SINGLE DUP-11 LINE. TERMINATES DDCMP AND DECLARES THE
|
||
; LINE DOWN.
|
||
KDLHA: MOVE T1,KDPSTS(W) ;GET THE KMC-11 STATUS
|
||
TLNN T1,(KDPSRU) ;IF IT'S NOT RUNNING
|
||
PJRST KE%KNR ; GIVE A "KDP NOT RUNNING" ERROR
|
||
|
||
PUSHJ P,NTDPRV## ;THIS IS A PRIVILEGED FUNCTION
|
||
PJRST KE%UNP ;IF NO PRIVILEGES, GIVE ERROR RETURN
|
||
LDB T1,KDLSTA## ;GET THE LINES STATE
|
||
CAIG T1,KD%FLS ;MAKE SURE WE THINK THAT THE LINE'S UP
|
||
PJRST KE%LNS ; IF NOT, GIVE "LINE NOT STARTED" ERROR
|
||
PJRST KF.HA ;HALT THE LINE
|
||
; #103 ROUTINE TO START DDCMP ON A SPECIFIED DUP-11 LINE.
|
||
;NOTE: T1 STILL HAS THE LINE'S NUMBER IN IT!!!
|
||
KDLST: MOVE T1,KDPSTS(W) ;GET THE KMC-11 STATUS
|
||
TLNN T1,(KDPSRU) ;IF IT'S NOT RUNNING
|
||
PJRST KE%KNR ; GIVE A "KDP NOT RUNNING" ERROR
|
||
|
||
PUSHJ P,NTDPRV## ;THIS IS A PRIVILEGED FUNCTION
|
||
PJRST KE%UNP ;IF NO PRIVILEGES, GIVE ERROR RETURN
|
||
LDB T2,KDLSTA## ;GET OUR CURRENT STATE
|
||
CAIL T2,KD%FLS ;SEE IF WE ARE IN A STATE TO RESTART
|
||
PJRST KE%LAS ; IF RUNNING, SAY "LINE ALREADY STARTED"
|
||
|
||
HRRZ T2,KDLUSR(F) ;GET THE LINE'S USER'S ID
|
||
CAIN T2,DD.PRO ; AND IF IT'S NOT "PROGRAM"
|
||
SKIPE KDLDDB(F) ; OR IF HE HAS A DDB,
|
||
CAIA ; THEN HE'S OK
|
||
PJRST KE%NDL ;NO DDB FOR LINE IN PROGRAM MODE
|
||
|
||
LDB T1,KDLSTA## ;GET THE STATE,
|
||
CAIL T1,KD%INI ; AND IF WE'VE BEEN INITIALIZED
|
||
JRST KDLST1 ;DON'T DO IT AGAIN
|
||
PUSHJ P,KDLINI ;INITIALIZE THE LINE
|
||
PUSHJ P,ZRCTRS ;ZERO THE STATISTIC COUNTERS
|
||
|
||
;NOW SEE WHAT MODE THE USER WANT'S TO START THE LINE IN
|
||
KDLST1: SETZ T1, ;ASSUME NORMAL MODE
|
||
CAIL P2,4 ;IF THE USER SPECIFIED A FORTH ARG,
|
||
PUSHJ P,GETWD1## ; THEN GO FETCH THE TYPE
|
||
MOVEI T2,KD%MAI ;ASSUME HE MENT TO START MAINT MODE
|
||
JUMPN T1,KDLST2 ; AND IF SO, GO DO IT
|
||
MOVSI T1,(XMTBTS) ;MAKE SURE WE LEAVE NO CONTROL MESSAGES
|
||
ANDCAM T1,KDLSTS(F) ;PENDING FROM LAST TIME
|
||
MOVSI T1,(KDSSTR) ;GET THE "NEED TO SEND START" BIT
|
||
IORM T1,KDLSTS(F) ; AND SET IT SO WE SEND ONE SOON
|
||
PUSHJ P,CLCTRS ;MAKE SURE WE START CORRECTLY
|
||
MOVEI T2,KD%STR ;GET THE "SENDING STARTS" STATE
|
||
KDLST2: DPB T2,KDLSTA## ;SET THIS LINE'S STATE
|
||
KDPOFF ;NO INT'S IN RCV/XMT-BUF
|
||
PUSHJ P,RCVBUF ;SET UP A RECEIVE REQUEST
|
||
PUSHJ P,XMTBUF ;TRY TO SEND THE START
|
||
KDPON ;INT'S OK NOW
|
||
RETSKP ;GIVE GOOD RETURN
|
||
; #104 ROUTINE TO SET THE LINE'S USER
|
||
KDLSU: PUSHJ P,NTDPRV## ;MUST BE PRIVILEGED TO TO THIS
|
||
PJRST KE%UNP ;IF HE'S NOT, THEN GIVE AN ERROR
|
||
CAIGE P2,3 ;MAKE SURE THAT THE ARG LIST IS LONG ENOUGH
|
||
PJRST KE%ALS ;IF NOT, SAY "ARG LIST TOO SHORT"
|
||
LDB T1,KDLSTA## ;GET THE LINE'S CURRENT STATE
|
||
CAIL T1,KD%FLS ;THE LINE MUST BE HALTED TO SWITCH USERS
|
||
PJRST KE%LAS ;SAY "LINE STARTED" IF IT IS RUNNING
|
||
PUSHJ P,GETWD1## ;GET THE "NAME" OF THE USER TO SWITCH TO
|
||
KDLSU1: PUSHJ P,KONUSN## ;IDENTIFY USER NAME
|
||
JRST KE%IUN ; THEN SAY ILLEGAL USER NAME
|
||
HRRZM T2,KDLUSR(F) ;IF IT MATCHES, SET THE LINE TYPE
|
||
CAIN T2,DD.DEC ;IS THE USER DECNET?
|
||
JRST KDLSUD ;YES, START UP ROUTER
|
||
CAIN T2,DD.PRO ;NO, IS IT PROGRAM?
|
||
HRLM J,KDLUSR(F) ;YES, SAVE THE JOB NUMBER
|
||
RETSKP ;NO, RETURN SUCCESS
|
||
|
||
;Now that we know we are setting the user to DECNET, we'll set the
|
||
;line's state to on, so that when the protocol comes up RTR will be
|
||
;ready. Note that if the definitions of the LINE ID change,
|
||
;this crock will have to change.
|
||
|
||
KDLSUD: SETZ T4, ;START OFF WITH A CLEAN LINE ID
|
||
MOVE T2,KDPNUM(W) ;GET THE KMC NUMBER (USUALLY ZERO)
|
||
DPB T2,[POINT 9,T4,17] ;SAVE IT AS KONTROLLER NUMBER (LI.KON)
|
||
MOVE T2,KDPDPN(W) ;GET THE NUMBER OF KDPS ON THIS KMC
|
||
MOVEI T3,KDPKDL(W) ;POINT TO KDL TABLE
|
||
SOJGE T2,[CAMN F,(T3) ;DO WE HAVE A MATCH
|
||
JRST KDLSD1 ;YES, THAT MEANS WE FOUND KDP NUMBER
|
||
AOJA T3,.] ;NO, ADVANCE TO NEXT AND CHECK IT OUT
|
||
PUSHJ P,NTDSTP ;OOPS, SEVERE PROBLEM
|
||
|
||
KDLSD1: SUBI T3,KDPKDL(W) ;FIND THE KDP NUMBER
|
||
DPB T3,[POINT 9,T4,26] ;SAVE IT AS UNIT NUMBER (LI.UNI)
|
||
MOVEI T2,LD.KDP ;THIS MEANS THE KDP DEVICE TO RTR
|
||
DPB T2,[POINT 9,T4,8] ;SAVE AS DEVICE TYPE (LI.DEV)
|
||
MOVEI T1,DC.IOC ;INTERRUPT TO OPEN A CIRCUIT
|
||
TLO T4,(LILXC) ;SET THE BIT TO MAKE IT A LINE ID
|
||
MOVE T3,T4 ;GET LINE ID IN PROPER AC
|
||
PUSHJ P,CALDVR ;CALL THE DRIVER
|
||
RETSKP ;GIVE A GOOD RETURN
|
||
|
||
; #105 ROUTINE TO READ THE LINE'S USER
|
||
KDLRU: CAIGE P2,3 ;MAKE SURE ARG LIST IS LONG ENOUGH
|
||
PJRST KE%ALS ;IF NOT, SAY "ARG LIST TOO SHORT"
|
||
HRRZ T1,KDLUSR(F) ;GET THE USER OF THE LINE
|
||
MOVE T1,DTNAME##(T1) ;GET THE SIXBIT NAME
|
||
PUSHJ P,PUTWD1## ;PLACE THE VALUE IN USER BLOCK
|
||
HLRZ T1,KDLUSR(F) ;GET THE JOB NUMBER OF THE OWNER
|
||
; (ZERO IF NOT DD.PRO)
|
||
PUSHJ P,PUTWD1## ;PLACE IT IN NEXT WORD OF USER BLOCK
|
||
RETSKP ; AND GIVE A GOOD RETURN
|
||
SUBTTL KDPDSP - ENTRY TO KDPINT
|
||
|
||
;KDPDSP - THIS ROUTINE IS THE OUTSIDE WORLD'S ENTRY INTO KDPINT.
|
||
;CALL MOVX T1,FUNCTION-CODE (DC.F??)
|
||
; MOVX T2,KDL-BLOCK ADDRESS
|
||
; T3, T4 ARE ARGUMENTS FOR FUNCTION
|
||
;PUSHJ P,KDPDSP
|
||
;RETURN CPOPJ ;IF CALLED WHEN OWNED BY SOMEONE ELSE
|
||
; CPOPJ1 ;ON SUCCESS
|
||
|
||
;FOR DECNET
|
||
KDPDSP::SKIPL T1 ;RANGE CHECK
|
||
CAILE T1,DC.FAL ; THE FUNCTION CODE [DC.FMX]
|
||
PUSHJ P,NTDSTP## ;IF OUT OF RANGE, STOP
|
||
PUSHJ P,SAVEFW ;WE USE F := KDL, W := KDP
|
||
CAIN T1,DC.FAL ;ASSIGN LINE?
|
||
JRST KF.AL ;YES
|
||
MOVE F,T2 ;SET UP OUR KDL BLOCK POINTER
|
||
HRRZ T2,KDLUSR(F) ;GET THE USER OF THE LINE
|
||
SKIPE KDLLBK(F) ;BETTER HAVE A DECNET BLOCK
|
||
CAIE T2,DD.DEC ;DECNET?
|
||
POPJ P, ;NOPE, GIVE ERROR RETURN.
|
||
HRRZ W,KDLKDP(F) ;SET UP THE KDP ADDRESS AS WELL
|
||
PUSHJ P,@KDPDST(T1) ;DISPATCH ON THE FUNCTION CODE
|
||
POPJ P, ;FAILURE
|
||
PJRST CPOPJ1## ;GIVE GOOD RETURN
|
||
|
||
;FOR ANF
|
||
KDADSP::SKIPL T1 ;RANGE CHECK
|
||
CAILE T1,DC.FQB ; THE FUNCTION CODE [DC.FMX]
|
||
PUSHJ P,NTDSTP## ;IF OUT OF RANGE, STOP
|
||
PUSHJ P,SAVEFW ;WE USE F := KDL, W := KDP
|
||
CAIN T1,DC.FAL ;ASSIGN LINE?
|
||
JRST KF.AL ;YES
|
||
MOVE F,T2 ;SET UP OUR KDL BLOCK POINTER
|
||
HRRZ T2,KDLUSR(F) ;GET THE USER OF THE LINE
|
||
CAIE T2,DD.ANF ;ANF?
|
||
POPJ P, ;NOPE, GIVE ERROR RETURN.
|
||
HRRZ W,KDLKDP(F) ;SET UP THE KDP ADDRESS AS WELL
|
||
PUSHJ P,@KDPDST(T1) ;DISPATCH ON THE FUNCTION CODE
|
||
POPJ P, ;FAILURE
|
||
PJRST CPOPJ1## ;GIVE GOOD RETURN
|
||
|
||
;FOR PROGRAM
|
||
KDODSP::SKIPL T1 ;RANGE CHECK
|
||
CAILE T1,DC.FQB ; THE FUNCTION CODE [DC.FMX]
|
||
PUSHJ P,NTDSTP## ;IF OUT OF RANGE, STOP
|
||
PUSHJ P,SAVEFW ;WE USE F := KDL, W := KDP
|
||
CAIN T1,DC.FAL ;ASSIGN LINE?
|
||
JRST KF.AL ;YES
|
||
MOVE F,T2 ;SET UP OUR KDL BLOCK POINTER
|
||
HRRZ T2,KDLUSR(F) ;GET THE USER OF THE LINE
|
||
CAIE T2,DD.PRO ;DECNET?
|
||
POPJ P, ;NOPE, GIVE ERROR RETURN.
|
||
HRRZ W,KDLKDP(F) ;SET UP THE KDP ADDRESS AS WELL
|
||
PUSHJ P,@KDPDST(T1) ;DISPATCH ON THE FUNCTION CODE
|
||
POPJ P, ;FAILURE
|
||
PJRST CPOPJ1## ;GIVE GOOD RETURN
|
||
KDPDST: IFIW KF.HA ;0 = HALT ALL PROTOCOLS
|
||
IFIW KF.IN ;1 = INITIALIZE NORMAL PROTOCOL (DDCMP)
|
||
IFIW KF.MA ;2 = INITIALIZE MAINT PROTOCOL (BOOTING)
|
||
IFIW KF.QO ;3 = QUEUE OUTPUT BUFFERS (MAINT OR NORMAL)
|
||
IFIW NTDSTP## ;4 = ASSIGN -- SEE SPECIAL DECODE ABOVE
|
||
;KF.AL - ROUTINE TO ASSIGN A LINE
|
||
;CALL MOVX T2,DECNET LINE ID
|
||
|
||
KF.AL: LDB W,[POINT 9,T2,17] ;YES, CONVERT LINE ID (LIKON)
|
||
CAILE W,KDPMAX## ;BETTER BE IN RANGE
|
||
POPJ P, ;SIGH
|
||
SKIPN W,KDPTBL##(W) ;POINT TO THE KDP BLOCK
|
||
POPJ P, ;PATCHED OUT
|
||
MOVE T1,KDPCSR(W) ;GET UNIBUS ADDRESS
|
||
PUSHJ P,UBGOOD## ;BE SURE WE'RE THERE
|
||
POPJ P, ;WE'RE NOT
|
||
LDB F,[POINT 9,T2,26] ;GET UNIT (DUP) NUMBER (LIUNI)
|
||
CAML F,KDPDPN(W) ;LEGAL NUMBER
|
||
POPJ P, ;NO
|
||
ADDI F,KDPKDL(W) ;POINT TO KDL POINTER
|
||
SKIPN F,0(F) ;SEE IF PRESENT
|
||
POPJ P, ;PATCHED OUT
|
||
LDB T1,[POINT 9,T2,26] ;GET UNIT (DUP) NUMBER (LIUNI) AGAIN
|
||
LSH T1,3 ; * 8 TO GET DUP-11 CSR OFFSET
|
||
ADD T1,KDP1DP(W) ;RELOCATE TO THE ADDRESS OF KDP'S 1ST DUP
|
||
PUSHJ P,UBGOOD## ;SEE IF THE DUP-11 EXISTS.
|
||
POPJ P, ;IT DOESN'T, DON'T INIT
|
||
HRRZ T2,KDLUSR(F) ;GET LINE OWNER
|
||
CAIE T2,DD.DEC ;HACKING?
|
||
POPJ P, ;NOT ME, YOU DON'T
|
||
MOVEM T3,KDLLBK(F) ;SAVE ADDRESS OF DECNET'S BLOCK
|
||
MOVE T1,F ;RETURN ADDRESS OF OURS
|
||
JRST CPOPJ1## ;SUCCESS
|
||
;KF.HA - ROUTINE TO SHUT-DOWN PROTOCOL ON A KDL-LINE.
|
||
;CALL MOVX F,KDL-BLOCK ADDRESS
|
||
; PUSHJ P,KF.HA ;FROM EITHER CLOCK OR UUO LEVEL WITH THE
|
||
; ; INTERRUPTS ON.
|
||
;RETURN POPJ P, ;ALWAYS - HALTS KMC IF ERROR
|
||
|
||
KF.HA: LDB T1,KDLSTA## ;FIRST GET OUR STATE,
|
||
CAIGE T1,KD%FLS ;IF WE ARE ALREADY "HALTED"
|
||
RETSKP ;RETURN WITH OUT TOUCHING ANYTHING
|
||
; PUSHJ P,KDLFLS ;MUST DO A BUFFER FLUSH TO QUIESCE THE KMC
|
||
MOVEI T1,KD%INI ;FLUSH COMPLETE, NOW GO
|
||
DPB T1,KDLSTA## ;TO "INITIALIZED" STATE
|
||
PUSHJ P,KDLPDN ;TELL OUR DRIVER THAT WE ARE DOWN
|
||
RETSKP ;AND THE "HALT" COMMAND IS DONE
|
||
;KF.IN - ROUTINE TO INITIALIZE THE KDL AND PUT IT IN NORMAL PROTOCOL
|
||
;CALL MOVX F,KDL-BLOCK ADDRESS
|
||
; PUSHJ P,KF.IN
|
||
;RETURN CPOPJ ;ALWAYS
|
||
|
||
KF.IN: PUSHJ P,FREMAI ;FREE BUFFERS IF IN MAINT STATE
|
||
LDB T1,KDLSTA## ;GET THE LINE'S STATE
|
||
CAIGE T1,KD%INI ;IF THE LINE NEEDS { BASE ! CONTROL } IN
|
||
PUSHJ P,KDLINI ;THEN INITIALIZE THE LINE
|
||
|
||
PUSHJ P,KDLPD0 ;CLEAN OUT QUEUES.
|
||
MOVEI T1,KD%STR ;GET THE "SENDING STARTS" STATE
|
||
DPB T1,KDLSTA## ; AND SET THIS LINE'S STATE TO IT
|
||
MOVSI T1,(XMTBTS) ;MAKE SURE WE LEAVE NO CONTROL MESSAGES
|
||
ANDCAM T1,KDLSTS(F) ;PENDING FROM LAST TIME
|
||
MOVSI T1,(KDSSTR) ;GET THE "NEED TO SEND START" BIT
|
||
IORM T1,KDLSTS(F) ; AND SET IT SO WE SEND ONE SOON
|
||
PUSHJ P,CLCTRS ;CLEAR THE MESSAGE NUMBERS
|
||
KDPOFF ;NO INT'S IN RCV/XMT-BUF
|
||
PUSHJ P,RCVBUF ;SET UP A RECEIVE REQUEST
|
||
PUSHJ P,XMTBUF ;TRY TO SEND THE START
|
||
KDPON ;INT'S OK NOW
|
||
RETSKP ;AND WE'RE DONE
|
||
;KF.MA - ROUTINE TO INITIALIZE MAINT PROTOCOL ON THE KDL-LINE
|
||
;CALL MOVX F,KDL-BLOCK
|
||
; PUSHJ P,KF.MA
|
||
;RETURN POPJ P, ;ALWAYS
|
||
|
||
KF.MA: LDB T1,KDLSTA## ;FIRST MAKE GET OUR STATE, AND
|
||
CAIN T1,KD%MAI ; IF WE ARE ALREADY IN MAINT STATE,
|
||
RETSKP ; THEN DON'T DO ANYTHING MORE
|
||
CAILE T1,KD%MAI ;IF WE ARE RUNNING (OR TRYING TO START)
|
||
PUSHJ P,KF.HA ; THEN FLUSH ALL BUFFERS
|
||
JFCL ;IGNORE ERROR RETURN
|
||
LDB T1,KDLSTA## ;GET OUR STATE AGAIN
|
||
CAIGE T1,KD%INI ;IF THE LINE NEEDS INITIALIZATION,
|
||
PUSHJ P,KDLINI ;THEN RE-SETUP THE KDL-BLOCK
|
||
MOVEI T1,KD%MAI ;GET AND SET THIS LINE TO
|
||
DPB T1,KDLSTA## ; MAINT STATE
|
||
KDPOFF ;DISABLE INTERRUPTS WHILE WE
|
||
PUSHJ P,RCVBUF ;SET UP RECEIVE AND
|
||
PUSHJ P,XMTBUF ; TRANSMIT REQUESTS
|
||
KDPON ;INTERUPTS ON AGAIN
|
||
RETSKP ;AND WE'RE DONE
|
||
;KF.QO - ROUTINE TO QUEUE OUTPUT MESSAGES
|
||
;CALL MOVX F,KDL-BLOCK ADDRESS
|
||
; MOVX T3,MESSAGE BUFFER ADDRESS
|
||
; PUSHJ P,KF.QO
|
||
;RETURN CPOPJ ;ALWAYS
|
||
|
||
KF.QO: HLLZS MB.NXT(T3) ;ZERO THE FORWARD POINTER
|
||
SETOM MB.MSN(T3) ;-1 IN NUMBER FIELD MEANS NO NUMBER ASSIGNED
|
||
KDPOFF ;PREPARE TO MESS WITH THE QUEUES
|
||
LDB T1,KDLSTA## ;GET STATE
|
||
CAIE T1,KD%RUN ;ARE WE IN STILL RUN STATE?
|
||
CAIN T1,KD%MAI ;IT'S OK TO SEND DATA IN MAINT MODE TOO
|
||
CAIA ;GOODNESS, IT'S OK
|
||
JRST [KDPON ;NO, PASS PTR TO MSG IN T3
|
||
MOVEI T1,DC.IOF ; GET THE "OUTPUT NOT DONE" FUNCTION
|
||
PUSHJ P,CALDVR ; AND TELL OUR DRIVER THE NEWS
|
||
RETSKP] ;AND RETURN NO ERROR
|
||
HRRZ T1,KDLWTO(F) ;GET THE FIRST MESSAGE ON THE "WAIT OUTPUT" Q
|
||
JUMPE T1,[HRRZM T3,KDLWTO(F) ;IF NONE, THEN WE'RE FIRST
|
||
JRST KF.QO2] ;GO TRY TO SEND IT
|
||
|
||
KF.QO1: HRRZ T2,MB.NXT(T1) ;GET THE ADDRESS OF THE NEXT MESSAGE
|
||
JUMPE T2,[HRRM T3,MB.NXT(T1) ;IF NONE, APPEND TO THE END
|
||
JRST KF.QO2] ;AND FIRE UP THE XMITTER
|
||
MOVE T1,T2 ;STEP TO NEXT MSG IN QUEUE
|
||
JRST KF.QO1 ;AND SEE IF IT'S THE LAST
|
||
|
||
KF.QO2: PUSHJ P,RCVBUF ;MAKE SURE A RCV BUFFER IS QUEUED
|
||
PUSHJ P,XMTBUF ;TRY TO SEND THE MESSAGE
|
||
KDPON ;DONE MESSING
|
||
PUSHJ P,FREMAI ;TRY TO FREE STALE MAINT MSG
|
||
RETSKP ;DONE
|
||
SUBTTL INTERRUPTS -- INTERRUPT LEVEL INTERFACE TO THE KMC-11
|
||
|
||
Comment @
|
||
|
||
Each KMC-11 has two interrupt vector addresses.
|
||
|
||
"A" This interrupt is taken when RDYI (KMCRDI) comes up. In this
|
||
state the KMC-11 is ready for an input transaction. All
|
||
input transactions for the KMC-11 are queued in the KDP block.
|
||
This is necessary because the following situation would otherwise
|
||
cause a deadlock.
|
||
1) The KMC-11 sets RDYO and gives a BUFFER-OUT transaction.
|
||
2) At interrupt level, we want to do a BUFFER-IN.
|
||
3) If, in the meantime, the KMC-11 has set RDYO again,
|
||
we will not be able to get RDYI until we process another
|
||
output transaction.
|
||
The solution to this is to queue all input transactions. This does
|
||
mean that we have to take an interrupt on each transaction, but it
|
||
does circumvent the above problem.
|
||
|
||
"B" This interrupt is taken when RDYO (KMCRDO) comes up. In this
|
||
state the KMC-11 is wants to perform an output transaction.
|
||
It is these output transactions that drive almost all of the
|
||
interrupt level KMC/DUP processing.
|
||
|
||
The vector instructions are set up to be JSR's to the locations "KDPAIV",
|
||
and "KDPBIV" in the KDP block for the KMC-11. These locations contain the
|
||
5 or 6 instructions necessary to save the AC's, load "W" with the address
|
||
of the particular KDP block, and dispatch to either of the two interrupt
|
||
routines "KDPAIV" or "KDPBIV".
|
||
|
||
End comment @
|
||
SUBTTL KDPAIV -- KMC-11 INTERRUPT VECTOR "A" PROCESSING.
|
||
|
||
;KDPAIV -- ROUTINE TO HANDLE KMC-11 INTERRUPT VECTOR "A" (INPUT)
|
||
;CALL MOVE W,[EXP KDP-BLOCK-ADDRESS]
|
||
; PUSHJ P,KDPAIV ;CALLED FROM KDPIVA IN THE KDP BLOCK
|
||
;RETURN POPJ P, ;TO DISMISS THE INTERRUPT.
|
||
;
|
||
;CLOBBERS MOST AC'S (WE SHOULD HAVE OUR OWN AC BLOCK ANYWAY)
|
||
;
|
||
;ON MULTI-PROCESSOR SYSTEMS, THIS CODE WILL NEED TO AOSE THE KDP INTERLOCK
|
||
;
|
||
KDPAIV::AOS KDPACT(W) ;COUNT THE INTERRUPT
|
||
MOVE T1,KDPSTS(W) ;GET THE STATUS
|
||
TLNN T1,(KDPSRU) ; AND MAKE SURE WE THINK WE'RE ON LINE
|
||
PJSP T1,KDPERR ; IF WE DON'T, CLEAR "RUN" SO INTS WILL STOP
|
||
|
||
MOVE U,KDPCSR(W) ;GET THE UNIBUS ADDRESS OF THE KMC-11
|
||
MOVEI T1,KMCRDI ;GET THE "RDYI" FLAG
|
||
TION T1,SEL2(U) ;MAKE SURE "RDYI" IS UP
|
||
PJSP T1,KDPERR ; IF IT'S NOT, THEN ITS AN ILLEGAL INTERRUPT
|
||
MOVE T3,KDPIQT(W) ;GET NUMBER OF NEXT QUEUED TRANSACTION
|
||
CAMN T3,KDPIQP(W) ;MAKE SURE THAT IT'S DIFFERENT NOT THE "PUTTER"
|
||
PJSP T1,KDPERR ; IF IT IS, THEN WE'RE GETTINT UNSOLICITED
|
||
; INTERRUPTS. DECLARE KDP ILL.
|
||
LSH T3,1 ;MAKE IT AN OFFSET INTO THE QUEUE
|
||
ADDI T3,KDPINQ(W) ;RELOCATE BY THE ADDRESS OF THE QUEUE
|
||
MOVE T1,0(T3) ;GET SEL2 DATA
|
||
MOVE T2,1(T3) ;GET SEL4, SEL6 DATA
|
||
AOS T3,KDPIQT(W) ;ADVANCE QUEUE TAKER
|
||
CAIL T3,KDPQLN ;IF ITS TIME TO WRAP AROUND, THEN
|
||
SETZB T3,KDPIQT(W) ; WRAP AROUND TO THE FIRST ENTRY
|
||
MOVEI T4,KMCRQI ;GET THE REQUEST INPUT INTERRUPT BIT
|
||
CAMN T3,KDPIQP(W) ;IF QUEUE EMPTY (PUTTER = TAKER) THEN
|
||
BCIO T4,SEL0(U) ; CLEAR RQI TO STOP THE INTERRUPTS
|
||
|
||
WRIO T2,SEL6(U) ;STORE TOP WORD
|
||
MOVSS T2,T2 ;GET SEL4 DATA
|
||
WRIO T2,SEL4(U) ; AND STORE THAT
|
||
TRZ T1,KMCRDI ;MAKE SURE RDYI CLEAR (SO KMC CAN RUN)
|
||
WRIO T1,SEL2(U) ;GIVE REST OF DATA TO KMC
|
||
POPJ P, ;ALL DONE
|
||
;KDPBIV -- ROUTINE TO HANDLE KMC-11 INTERRUPT VECTOR "B" (OUTPUT)
|
||
;CALL MOVE W,[EXP KDP-BLOCK-ADDRESS]
|
||
; PUSHJ P,KDPBIV ;CALLED FROM KDPIVB IN THE KDP BLOCK
|
||
;RETURN POPJ P, ;TO DISMISS THE INTERRUPT
|
||
;
|
||
;CLOBBERS MOST AC'S (WE SHOULD HAVE OUR OWN AC BLOCK ANYWAYS)
|
||
;
|
||
;ON MULTI-PROCESSOR SYSTEMS THIS CODE WILL NEED TO AOSE THE KDP INTERLOCK.
|
||
;
|
||
KDPBIV::AOS KDPBCT(W) ;COUNT THE INTERRUPT
|
||
MOVE T1,KDPSTS(W) ;GET OUR PERCEIVED STATUS
|
||
TLNN T1,(KDPSRU) ; AND MAKE SURE WE THINK WE'RE RUNNING
|
||
PJSP T1,KDPERR ; IF WE'RE NOT, CLEAR RUN AND RETURN
|
||
|
||
MOVE U,KDPCSR(W) ;GET THE UNIBUS ADDRESS OF THE KMC
|
||
RDIO P1,SEL2(U) ;READ STATUS BITS
|
||
TRNN P1,KMCRDO ;BETTER WANT AN OUTPUT TRANSACTION
|
||
PJSP T1,KDPERR ;ILLEGAL INTERRUPT. CRASH KMC
|
||
RDIO P2,SEL4(U) ;READ BDL ADDRESS
|
||
RDIO P3,SEL6(U) ;READ ERROR, STATUS OR WHAT EVER
|
||
|
||
MOVEI T1,KMCRDO ;GET THE RDYO BIT
|
||
BCIO T1,SEL2(U) ;CLEAR IT TO LET THE KMC CONTINUE
|
||
TRNE P1,2!KMCOVR ;MAKE SURE TYPE IS RIGHT, AND NO OVERRUN
|
||
PJSP T1,KDPERR ; WE'RE CONFUSED. GIVE UP.
|
||
|
||
LDB F,[POINT 7,P1,27] ;GET 7 BIT LINE #.
|
||
CAML F,KDPDPN(W) ;IS THIS A LEGAL LINE FOR THIS KDP
|
||
PJSP T1,KDPERR ; IF NOT, BETTER STOP NOW...
|
||
ADDI F,KDPKDL(W) ;MAKE IT AN OFFSET INTO THE KDP BLOCK
|
||
HRRZ F,(F) ;LOAD APPRIOATE KDL BLOCK ADDRESS
|
||
|
||
SETZ T1, ;GET A ZERO REGISTER
|
||
TRNE P1,KMCIOT ;IF INPUT, THEN
|
||
TRO T1,1 ; SET LOW ORDER BIT
|
||
TRNE P1,1 ;IF CONTROL, THEN
|
||
TRO T1,2 ; SET NEXT TO LOW ORDER BIT
|
||
JRST @[JRST KDPBOO ;BUFFER OUT (OUTPUT)
|
||
JRST KDPBOI ;BUFFER OUT (INPUT)
|
||
JRST KDPCOO ;CONTROL OUT (OUTPUT)
|
||
JRST KDPCOI](T1);CONTROL OUT (INPUT)
|
||
;ROUTINE DISPATCHED TO WILL RETURN.
|
||
SUBTTL KDPBOO -- KMC-11 BUFFER-OUT(OUTPUT) TRANSACTION PROCESSING.
|
||
|
||
; This routine frees output buffers when a BUFFER-OUT(OUTPUT) transaction
|
||
;declares that the KMC/DUP has output all data in the buffer. It:
|
||
; 1) Makes sure that this is the last buffer in the current
|
||
; Buffer Description List. (Data messages consist of two
|
||
; buffers. The DDCMP header buffer, and the data buffer.
|
||
; These two buffers are combined in a single BDL) If
|
||
; the current buffer is not the last in the list, nothing
|
||
; more is done, and the interrupt is exited. (We will
|
||
; get another interrupt when the next buffer in the BDL
|
||
; finishes.)
|
||
; 2) The count of buffers outstanding is decremented, and a
|
||
; check is made to ensure that this buffer is really the
|
||
; next one we expected to finish.
|
||
; 3) XMTBUF is called in an attempt to fill the just freed output
|
||
; buffer.
|
||
;
|
||
;called with:
|
||
; F, W := KDL and KDP pointers
|
||
; P1, P2, P3 := SEL2, SEL4 and SEL6 of the KMC-11
|
||
;
|
||
KDPBOO: PUSHJ P,GETBDL ;GET T4 SET UP TO POINT TO BDL
|
||
TLNE T4,1 ;MAKE SURE THAT BUFFER-OUT STARTS ON EVEN BYTE
|
||
PJSP T1,KDPERR ; IF ODD BYTE, THEN KMC-11 SCREWED US
|
||
MOVE T1,1(T4) ;GET WORD WITH LAST BD HALFWORD
|
||
TLNN T4,2 ;IF WE WANT FIRST HALFWORD,
|
||
MOVS T1,T1 ; THEN SWAP IT TO THE LOW HALF
|
||
TRNN T1,BDLLDS ;IS THIS THE LAST BUFFER IN THE BDL
|
||
POPJ P, ;IF NOT, IGNORE THIS INTERRUPT.
|
||
|
||
;WE ARE AT END OF MESSAGE. MAKE SURE WE GOT THE RIGHT ONE BACK
|
||
|
||
MOVEI S,KDSNXB ;STATUS BIT THAT SAYS WHICH BUFFER IS NEXT OUT
|
||
MOVEI T1,KDLXD1(F) ;ASSUME THAT BUFFER #1 IS FIRST BACK
|
||
TDNE S,KDLSTS(F) ; BUT IF IT SHOULD BE BUFFER #2, THEN
|
||
MOVEI T1,KDLXD2(F) ; THEN CHANGE OUR MIND.
|
||
|
||
MOVSI T2,(1B0) ;GET THE BDL IN-USE MARK BIT
|
||
TDNN T2,0(T1) ; AND MAKE SURE THAT IT'S SET
|
||
;[DBUG] PJSP T1,KDLERR ;IF NOT, TRY TO CRASH THE LINE
|
||
PUSHJ P,NTDSTP## ;WE'VE SCREWED UP THE BUFFERS [DBUG]
|
||
ANDCAM T2,0(T1) ;CLEAR THE USE BIT
|
||
|
||
HLRZ T3,1(T1) ;GET THE HALFWORD CONTAINING THE 3RD WORD
|
||
; OF THE FIRST BD IN THE BDL
|
||
TRNN T3,BDLLDS ;IF IT'S NOT THE LAST BD, THEN
|
||
ADD T1,[XWD 2,1] ; ADVANCE THE CBP IN T1 3 WORDS (6 BYTES)
|
||
CAMN T1,T4 ;MAKE SURE IT'S THE BDL ADDRESS THE KMC GAVE US
|
||
SOSGE KDLXBC(F) ;DECREMENT THE NUMBER OF ACTIVE OUTPUT BUFFERS
|
||
PJSP T1,KDPERR ;++ EITHER BAD BUFFER, OF COUNT WENT NEGATIVE.
|
||
XORB S,KDLSTS(F) ;SIGNAL THAT OTHER BUFFER IS NEXT BUFFER OUT
|
||
PJRST XMTBUF ;NOW GO TRY TO FILL THE JUST FREED BUFFER
|
||
SUBTTL KDPBOI -- ROUTINE TO HANDLE BUFFER-OUT(INPUT) TRANSACTIONS.
|
||
|
||
; This routine handles BUFFER-OUT(INPUT) transactions. These
|
||
;transactions consist of input messages coming in over the synchronous
|
||
;line. This routine:
|
||
; 1) Frees the receive buffer. (No worry about races, this
|
||
; code runs under the KMC interlock on multiprocessor
|
||
; systems. On a single processor system, it runs at
|
||
; interrupt level. Hence no one will try to allocate
|
||
; the buffer between when it is freed and when it is
|
||
; processed
|
||
; 2) Calls RCVMSG to process the incoming message
|
||
;
|
||
;called with:
|
||
; F, W := KDL and KDP pointers
|
||
; P1, P2, P3 := SEL2, SEL4 and SEL6 of the KMC-11
|
||
;
|
||
KDPBOI: PUSHJ P,FREBOI ;FREE THE INPUT BUFFER, (SET UP T4)
|
||
PJSP T1,KDPERR ;?? KMC-11 GAVE BAD BDL ADDRESS ??
|
||
PJRST RCVMSG ;GO PROCESS MESSAGE (T4 POINTS TO BDL)
|
||
SUBTTL KDPCOO -- PROCESS A CONTROL-OUT(OUTPUT) TRANSACTION
|
||
|
||
; This routine processes CONTROL-OUT(OUTPUT) transactions. These
|
||
;consist primarily of various errors detected by the KMC-11. This routine:
|
||
; 1) Counts the control out transaction code (CTOTLY)
|
||
; 2) Verifys that the error is legal/recoverable. If not,
|
||
; it crashes the KMC-11.
|
||
; 3) If the control out frees an output BDL, it assumes that
|
||
; an output message has been clobbered, queues a REP message
|
||
; to speed a recovery NAK, and calls "KDPBOO" to free the BDL.
|
||
;
|
||
;called with:
|
||
; F, W := KDL and KDP pointers
|
||
; P1, P2, P3 := SEL2, SEL4 and SEL6 of the KMC-11
|
||
;
|
||
KDPCOO: PUSHJ P,SAVE1## ;WE USE P1 FOR A "BIT MASK"
|
||
PUSHJ P,CTOTLY ;TALLY THE CONTROL OUT CODE AND
|
||
; PUT "BIT MASK" IN P1
|
||
PJSP T1,KDPERR ;IF ILLEGAL CODE, KMC-11 IS SICK...
|
||
|
||
TLNE P1,^-<CTLO14!CTLO16!CTLO22!CTLO26> ;THESE ARE LEGAL OUTPUT
|
||
PJSP T1,KDPERR ; IF IT'S NOT ONE OF THEM, CRASH KMC-11
|
||
|
||
TLNE P1,CTLO14 ;IS THIS A BUFFER TEMP UNAVAILABLE?
|
||
JRST [MOVEI T1,RSNBTU ;IF SO, GET THAT NAK CODE
|
||
PJRST RCVXNK] ;SEND THE NAK AND RETURN
|
||
|
||
TLNE P1,CTLO26 ;IF THIS A "FLUSH DONE" TRANSACTION
|
||
JRST KDPFLO ; IF FLUSH DONE, GO UPDATE KDLSTS
|
||
TLNN P1,CTLO22 ;DOES THIS TRANSACTION FREE A BDL?
|
||
POPJ P, ; IF NOT, RETURN (DON'T CALL XMTBUF...)
|
||
|
||
MOVSI T1,(KDSREP) ;ASSUME MESSAGE WAS CLOBBERED, SO
|
||
IORM T1,KDLSTS(F) ; SO REQUEST A REP TO SPEED RECOVERY
|
||
|
||
PJRST KDPBOO ;PROCESS REST JUST LIKE ANY OTHER BUFFER-OUT
|
||
SUBTTL KDPCOI -- PROCESS CONTROL-OUT(INPUT) TRANSACTIONS
|
||
|
||
; This routine processes the CONTROL-OUT(INPUT) transactions. These
|
||
;transactions are primarily errors noticed by the KMC-11. In particular,
|
||
;BCC (checksum) errors are processed here. This routine:
|
||
; 1) Tallys the CONTROL-OUT transaction
|
||
; 2) Sees if it is a legal/recoverable error. If not, it
|
||
; crashes the KMC-11
|
||
; 3) If the transaction frees an input buffer, that is done.
|
||
; 4) If the transaction implies that a message was lost,
|
||
; an approiate NAK is queued.
|
||
;
|
||
;called with:
|
||
; F, W := KDL and KDP pointers
|
||
; P1, P2, P3 := SEL2, SEL4 and SEL6 of the KMC-11
|
||
;
|
||
KDPCOI: PUSHJ P,SAVE1## ;P1 WILL HAVE THE "BIT MASK" IN IT.
|
||
PUSHJ P,CTOTLY ;TALLY THE CONTROL OUT TYPE
|
||
; RETURNS "BIT MASK" IN P1
|
||
PJSP T1,KDPERR ;UNKNOWN CODE. KMC-11 IS SICK...
|
||
TLNE P1,^-<CTLO10!CTLO12!CTLO24!CTLO26> ;IS THIS LEGAL FOR INPUT
|
||
PJSP T1,KDLERR ;UN-RECOVERABLE ERROR. BETTER START OVER
|
||
|
||
TLNE P1,CTLO26 ;IS THIS AN "INPUT FLUSH" DONE TRANSACTION
|
||
JRST KDPFLI ; IF INPUT FLUSH, GO UPDATE KDLSTS
|
||
TLNE P1,<CTLO10!CTLO12!CTLO24> ;DOES THIS FREE A BDL?
|
||
PUSHJ P,[PUSHJ P,FREBOI ;FREE THE INPUT BDL
|
||
PJSP T1,KDLERR ;BAD ADDRESS RETURNED BY KMC-11. DIE
|
||
POPJ P,] ;RETURN TO MAIN FLOW
|
||
|
||
TLNN P1,<CTLO10!CTLO12!CTLO24> ;DOES THIS REQUIRE A NAK?
|
||
PJRST RCVBUF ;IF NO NAK REQUIRED, WE ARE DONE
|
||
; ATTEMPT TO REQUEUE A BUFFER AND RETURN
|
||
MOVEI T1,RSNHCK ;ASSUME THAT ERROR WAS HEADER CHECKSUM
|
||
TLNE P1,CTLO12 ; BUT IF IT WAS A DATA CHECKSUM
|
||
MOVEI T1,RSNDCK ; THEN CHANGE OUR MINDS AND USE THAT
|
||
TLNE P1,CTLO24 ; UNLESS IT WAS AN OVER-RUN, IN WHICH
|
||
MOVEI T1,RSNOVR ; CASE WE SHOULD USE THIS.
|
||
PJRST RCVXNK ;QUEUE NAK AND REQUEUE BUFFERS IF POSSIBLE
|
||
;KDPFLO ROUTINE TO CLEAN UP WHEN OUTPUT BUFFER FLUSH IS COMPLETED.
|
||
; CLEAR "XMIT FLUSH IN PROGRESS" AND SAY NO OUTPUT BUFFERS QUEUED.
|
||
|
||
KDPFLO: LDB T1,KDLSTA## ;GET THE LINE'S STATE (JUST TO MAKE SURE)
|
||
MOVEI T2,KDSXFL ;GET THE "XMIT FLUSH" IN PROGRESS BIT
|
||
CAIN T1,KD%FLS ;IF WE'RE NOT IN "BUFFER FLUSH STATE", OR
|
||
TDNN T2,KDLSTS(F) ; WE'RE NOT FLUSHING XMIT BUFFERS
|
||
PJSP T1,KDPERR ; THEN ASSUME THE KMC-11 SCREWED UP
|
||
|
||
SETZM KDLXBC(F) ;SAY "NO OUTPUT BUFFERS ACTIVE"
|
||
MOVEI T1,KDSNXB!KDSXFL; ALSO SAY THAT NEXT BUFFER IS #0, AND
|
||
ANDCAB T1,KDLSTS(F) ; WE'RE NOT FLUSHING ANY MORE
|
||
JRST KDPFLX ;SEE IF WE CAN LEAVE "FLUSH" STATE
|
||
|
||
|
||
;KDPFLI ROUTINE TO CLEAN UP WHEN INPUT BUFFER FLUSH IS COMPLETE
|
||
|
||
KDPFLI: LDB T1,KDLSTA## ;GET LINE'S STATE
|
||
MOVEI T2,KDSRFL ;"RECEIVE FLUSH IN PROGRESS" BIT
|
||
CAIN T1,KD%FLS ;MAKE SURE WE'RE FLUSHING
|
||
TDNN T2,KDLSTS(F) ;MAKE SURE IT'S INPUT
|
||
PJSP T1,KDPERR ;IF NOT INPUT FLUSH, THEN KMC GAVE BAD CODE
|
||
|
||
SETZM KDLRBC(F) ;ZERO COUNT OF RECEIVE BUFFERS POSTED
|
||
MOVEI T1,KDSNRB!KDSRFL;SAY BUFFER #0 NEXT, AND
|
||
ANDCAB T1,KDLSTS(F) ; INPUT FLUSH COMPLETE
|
||
|
||
KDPFLX: MOVEI T2,KD%INI ;ASSUME THAT WE HAVE CLEARED BOTH FLUSH BITS
|
||
TRNN T1,KDSRFL!KDSXFL; AND IF WE HAVE,
|
||
DPB T2,KDLSTA## ; THEN WE'RE IN "INITED" STATE
|
||
POPJ P, ;DONE WITH THE INTERRUPT
|
||
SUBTTL RCVMSG -- ROUTINE TO DISPATCH ON THE DDCMP MESSAGE TYPE.
|
||
|
||
;Called from KDPBOI with:
|
||
; F, W := KDL and KDP pointers
|
||
; P1, P2, P3 := SEL2, SEL4 and SEL6 of the KMC-11
|
||
; T4 := a CBP to the first byte of the BDL (set up by FREBOI)
|
||
;
|
||
RCVMSG: ADDI T4,3 ;POINT TO BUFFER 3 PDP-10 WORDS AFTER BDL
|
||
HRLI T4,2 ;DDCMP HEADER STARTS IN RH SO DATA IS ON A WORD
|
||
LDB T1,BYTABL+2 ;GET FIRST CHAR FROM MESSAGE
|
||
CAIN T1,SOH ;SOH ==: DATA MESSAGE
|
||
JRST RCVDAT ; IF DATA, GO PROCESS IT
|
||
CAIN T1,ENQ ;ENQ ==: CONTROL MESSAGE
|
||
JRST RCVCTL ; IF CONTROL GO PROCESS IT
|
||
CAIN T1,DLE ;DLE ==: MAINTENANCE MESSAGE.
|
||
JRST RCVMAI ; IF MAINT, GO PROCESS THAT
|
||
|
||
PJSP T1,KDPERR ;IF WE DON'T RECOGNIZE IT, ASSUME KMC IS ILL.
|
||
SUBTTL RCVMAI -- ROUTINE TO PROCESS INCOMING MAINTENANCE MESSAGES.
|
||
;Called from RCVMSG with:
|
||
; F, W := KDL and KDP pointers
|
||
; P1, P2, P3 := SEL2, SEL4 and SEL6 of the KMC-11
|
||
; T4 := a CBP to the first byte of the BDL (set up by FREBOI)
|
||
;
|
||
|
||
RCVMAI: AOS KDLMAR(F) ;COUNT THE MAINTENANCE MESSAGES RECEIVED
|
||
LDB T1,KDLSTA## ;GET THE LINE'S STATE
|
||
CAIG T1,KD%MAI ; AND SEE IF WERE IN MAINT STATE ALREADY
|
||
JRST RCVMA1 ;IF NOT UP-AND-RUNNING, DON'T TELL OPERATOR
|
||
CAIL T1,KD%RUN ;IF THIS LINE IS UP, THEN
|
||
PUSHJ P,KDLPDN ; TELL OUR USER THAT IT'S NOT!
|
||
|
||
MOVE U,OPRLDB## ;LINE JUST CRASHED. TELL OPERATOR
|
||
PUSHJ P,INLMES## ; ABOUT THIS
|
||
ASCIZ /%% Maintenance message received on /
|
||
PUSHJ P,PRKDL ;PRINT THE LINE NUMBER
|
||
PUSHJ P,INLMES## ;WE ALSO WANT TO TIME-STAMP THIS
|
||
ASCIZ / at /
|
||
PUSHJ P,PRDTIM## ;SO PRINT THE TIME OF DAY.
|
||
RCVMA1: LDB T1,KDLSTA## ;GET OUR STATE, AND
|
||
MOVEI T2,KD%MAI ;GET THE MAINTENANCE STATE
|
||
DPB T2,KDLSTA## ; AND SET THIS LINE TO IT.
|
||
CAILE T1,KD%MAI ;IF WE ARE TRYING TO START OR RUNNING PROTOCOL
|
||
PUSHJ P,[PUSH P,T4 ;SAVE CURRENT BDL POINTER
|
||
PUSHJ P,KDLPDN ;FREE OUR BUFFERS, TELL USER
|
||
MOVEI T1,DC.IMR ;THEN TELL OUR DRIVER THAT
|
||
PUSHJ P,CALDVR
|
||
POP P,T4 ;RESTORE THE BDL POINTER
|
||
POPJ P,] ;AND RETURN
|
||
LDB T1,KDLSTA## ;GET OUR (POSSIBLY CHANGED!!) STATE
|
||
CAIE T1,KD%MAI ;AND IF OUR DRIVER HASN'T LEFT US IN MAINT
|
||
PJRST RCVBUF ; STATE - DON'T READ THE MESSAGE
|
||
|
||
TRNN P3,BFREOM ;DOES THIS BUFFER HOLD THE ENTIRE MESSAGE
|
||
PJSP T1,KDLERR ; IF NOT, WE CAN'T HANDLE IT. DECLARE ERROR.
|
||
|
||
LDB T3,BYTABL+3 ;GET THE LOW 8 BITS OF THE LENGTH
|
||
LDB T2,BYTABL+4 ;GET THE HIGH 6 BITS
|
||
DPB T2,[POINT 6,T3,27] ;MAKE A 12 BIT NUMBER FROM THEM
|
||
JUMPE T3,RCVBUF ;IF EMPTY MESSAGE, IGNORE IT
|
||
PUSH P,T3 ;SAVE THE COUNT
|
||
PUSH P,T4 ; AND THE CBP TO THE MESSAGE
|
||
MOVEI T1,DC.IGB ;REQUEST AN INPUT BUFFER
|
||
PUSHJ P,CALDVR ;CALL THE DRIVER FOR A BUFFER
|
||
POP P,T4 ;RESTORE THE CBP
|
||
POP P,T3 ; AND THE LENGTH OF THE MESSAGE
|
||
JUMPE T1,RCVBUF ;IF NO FREE BUFFERS, IGNORE THE MESSAGE
|
||
ADD T4,[XWD 1,1] ;ADVANCE THE INPUT BYTE POINTER TO START OF MSG
|
||
;(HEADER IS 6 BYTES, WE WANT PRE-DEC CBP)
|
||
MOVE T2,MB.FMS(T1) ;GET THE POINTER TO THE MSD (IF DECNET)
|
||
JUMPE T2,[MOVSI T2,(POINT 8) ;IF ANF STYLE, BUILD A BYTE
|
||
HRRI T2,STCDAT(T1) ; POINTER TO THE DATA AREA
|
||
JRST RCVMA2] ; AND GO COPY THE DATA
|
||
CAMLE T3,MD.BYT(T2) ;FIRST MAKE SURE THE WE GOT A BIG ENOUGH BUFFER
|
||
PUSHJ P,NTDSTP## ;++ DRIVER GAVE US A BAD BUFFER
|
||
MOVEM T3,MD.BYT(T2) ;STORE THE BYTE COUNT
|
||
MOVE T6,MD.ALA(T2) ;BYTE POINTER IS INDEXED BY T6
|
||
MOVE T2,MD.PTR(T2) ;FETCH THE BYTE POINTER TO THE FIRST BYTE
|
||
RCVMA2: IBP T2 ;POINT TO WORD CONTAINING FIRST BYTE
|
||
MOVEI T2,@T2 ;RESOLVE ANY INDEXING, ETC
|
||
HRLI T2,1(T4) ;POINT TO FIRST DATA WORD OF MESSAGE
|
||
SOS T3 ;ROUND BYTE COUNT AND CONVERT TO WDS (+3 -4)
|
||
LSH T3,-2 ;BYTES - WORDS
|
||
ADDI T3,(T2) ;END ADDRESS
|
||
BLTUB T2,(T3) ;MOVE MESSAGE TRANSLATED. (MABYE FEW EXTRA)
|
||
|
||
MOVE T3,T1 ;COPY THE ADDRESS OF THE BUFFER
|
||
MOVEI T1,DC.IIC ;GET THE "INPUT DONE" FUNCTION
|
||
PUSHJ P,CALDVR ;TELL THE DRIVER THAT THE BUFFER'S FULL
|
||
PJRST RCVBUF ; AND WE'RE DONE
|
||
SUBTTL RCVCTL -- ROUTINE TO PROCESS INCOMING CONTROL MESSAGES.
|
||
|
||
; This routine dispatches on the type field of incoming DDCMP
|
||
;control messages.
|
||
;
|
||
;Called from RCVMSG with:
|
||
; F, W := KDL and KDP pointers
|
||
; P1, P2, P3 := SEL2, SEL4 and SEL6 of the KMC-11
|
||
; T4 := a CBP to the first byte of the BDL (set up by FREBOI)
|
||
;
|
||
RCVCTL: TRNN P3,BFREOM ;WAS THIS MESSAGE LONGER THAN A SINGLE BUFFER
|
||
PJSP T1,KDPERR ; IF IT WAS, THEN THE KMC-11 SCREWED UP...
|
||
LDB T3,KDLSTA## ;GET THE LINES STATE
|
||
CAIG T3,KD%FLS ;IF LINE IS NOT CURRENTLY ACTIVE,
|
||
POPJ P, ; THEN RETURN WITH OUT RE-QUEUEING A RCV RQST
|
||
|
||
LDB T1,BYTABL+3 ;GET THE SECOND BYTE (CONTROL TYPE)
|
||
; CAIL T1,%ACK ;RANGE CHECK IT
|
||
CAILE T1,%STACK ; TO BE SURE THAT IT'S A LEGAL MESSAGE
|
||
PJSP T1,KDPERR ;THE KMC FED US GARBAGE...
|
||
MOVEI T2,KDLCTR-1(F) ;GET A POINTER TO THE CONTROL MESSAGE COUNTS
|
||
ADDI T2,(T1) ; OFFSET BY THE MESSAGE TYPE
|
||
AOS (T2) ; AND COUNT THIS RECEIVED CONTROL MESSAGE
|
||
JRST .(T1) ;DISPATCH TO APPROIATE MESSAGE PROCESSOR
|
||
JRST RCVACK ; 1 = ACK
|
||
JRST RCVNAK ; 2 = NAK
|
||
JRST RCVREP ; 3 = REP
|
||
JSP T1,KDPERR ; 4 = RESET (VESTIGIAL MESSAGE, NOW ILLEGAL)
|
||
JSP T1,KDPERR ; 5 = RESET (VESTIGIAL MESSAGE, NOW ILLEGAL)
|
||
JRST RCVSTR ; 6 = START
|
||
JRST RCVSTK ; 7 = STACK
|
||
RCVACK: PUSHJ P,CHKACK ;PROCESS ACK FIELD (MAY CALL DRIVER)
|
||
PJRST RCVBUF ;TRY TO SET UP ANOTHER RECEIVE REQUEST
|
||
; AND EXIT THE INTERRUPT.
|
||
|
||
|
||
RCVNAK: LDB T1,BYTABL+4 ;GET THE NAK REASON
|
||
ANDI T1,77 ; AND JUST THE REASON
|
||
PUSHJ P,NAKTRN ;CONVERT THE NAK CODE INTO A TABLE INDEX
|
||
ADDI T1,KDLNKR(F) ;RELOCATE TO RECEIVED NAK TABLE
|
||
AOS (T1) ;COUNT THE RECEIVED NAK
|
||
|
||
LDB T1,KDLSTA## ;GET OUR STATE, AND
|
||
CAIE T1,KD%RUN ; IF WE AREN'T RUNNING
|
||
PJRST RCVBUF ;DON'T PROCESS ANY NAK'S
|
||
PUSHJ P,CHKACK ;PROCESS THE ACK FIELD
|
||
PUSHJ P,STPTMR ;STOP THE TIMER
|
||
HRRZ T2,KDLWTA(F) ;GET THE HEAD OF THE LIST OF PCB'S AWAITING
|
||
; AN ACK
|
||
JUMPE T2,RCVNK2 ;IF NONE, SKIP OVER CODE THAT RESENDS THEM
|
||
|
||
RCVNK1: MOVEI T1,(T2) ;COPY THE ADDRESS OF THE "NEXT" PCB
|
||
HRRZ T2,MB.NXT(T2) ;GET THE POINTER TO THE REST OF THE LIST
|
||
JUMPN T2,RCVNK1 ;KEEP LOOPING IF NOT AT END OF LIST.
|
||
; AT EXIT, T1 := POINTER TO LAST PCB TO
|
||
; RE-TRANSMIT
|
||
HRRZ T2,KDLWTO(F) ;GET THE HEAD OF THE OUTPUT WAIT QUEUE
|
||
HRRM T2,PCBBLK(T1) ;AND MAKE IT THE "REST" OF THE WAIT ACK LIST
|
||
SETZ T1, ;GET A "ZERO" AND USE IT TO
|
||
EXCH T1,KDLWTA(F) ; CLEAR THE "WAIT FOR ACK" QUEUE.
|
||
MOVEM T1,KDLWTO(F) ;NOW MAKE THE OLD ACK QUEUE THE WAIT FOR OUTPUT
|
||
; QUEUE
|
||
SETZM KDLCTA(F) ;SAY THAT THERE ARE NO MESSAGES AWAITING ACK.
|
||
|
||
RCVNK2: PUSHJ P,XMTBUF ;SEE IF THE TRANSMITTER NEEDS POKING
|
||
; (IT WILL IF OUTPUT QUEUE WAS EMPTY)
|
||
PJRST RCVBUF ;GO SET UP A RECEIVE REQUEST AND EXIT.
|
||
|
||
|
||
RCVREP: LDB T1,KDLSTA## ;GET LINE STATE
|
||
CAIE T1,KD%RUN ;MUST IGNORE UNLESS RUNNING
|
||
PJRST RCVBUF ;IGNORE, REQUEUE RECEIVE BUFFER
|
||
LDB T1,KDLRMN## ;GET THE LAST RECIEVED MESSAGE NUMBER
|
||
LDB T2,BYTABL+6 ;GET THE "N" FIELD OF THE REP MESSAGE
|
||
CAIE T1,(T2) ;COMPARE MESSAGE NUMBERS. SKIP IF ALL OK
|
||
JRST [MOVEI T1,RSNREP ;IF WE MISSED SOME, GET CODE "REP RESPONSE"
|
||
PJRST RCVXNK] ;AND GO SEND A NAK
|
||
MOVSI S,(KDSACK) ;ASSUME RANDOM REP (RESPOND WITH ACK)
|
||
IORM S,KDLSTS(F) ;SET THE NEED TO SEND "?" MESSAGE FLAG
|
||
MOVSI S,(KDSNAK) ;CLEAR ANY PENDING NAK
|
||
ANDCAM S,KDLSTS(F) ;BECAUSE IT WOULD BE POINTLESS NOW
|
||
PJRST RCVNK2
|
||
RCVSTR: CAIE T3,KD%MAI ;IF NOT IN MAINT MODE
|
||
JRST RCVST1 ;SEE IF WE'RE IN "RUN"
|
||
MOVEI T1,DC.ISR ;IF IN MAINT MODE, SAY WE'VE RECEIVED
|
||
PUSHJ P,CALDVR ; A START MESSAGE
|
||
JRST RCVST2 ;AND GO SEE IF WE CAN PROCESS IT
|
||
|
||
RCVST1: CAIGE T3,KD%RUN ;ARE WE RUNNING NOW?
|
||
JRST RCVST2 ; IF NOT, DON'T WORRY ABOUT TELLING NETSER
|
||
|
||
PUSHJ P,KDLPDN ;TELL NETSER THAT THIS LINE IS RESTARTING.
|
||
|
||
MOVE U,OPRLDB## ;WE WANT TO TELL THE OPR, GET HIS LDB ADDR
|
||
PUSHJ P,INLMES## ;SEND FIRST PART OF MESSAGE
|
||
ASCIZ /%% Unexpected restart on /
|
||
PUSHJ P,PRKDL ;PRINT THE FULL KDP#, KDL# MESSAGE
|
||
PUSHJ P,INLMES## ;FINISH MESSAGE OFF WITH TIME OF DAY
|
||
ASCIZ / at /
|
||
PUSHJ P,PRDTIM## ;PRINT TIME AND CRLF
|
||
|
||
;DDCMP SAYS WE SHOULD JUST HALT. BUT WE WANT TO TRY AND KEEP THE
|
||
;LINE UP. SO WE ENTER SENDING STARTS STATE. WE CAN NOT SKIP TO
|
||
;SENDING STACKS, AS ANF PDP-11S GET VERY CONFUSED.
|
||
|
||
MOVEI T1,KD%STR ;SEND STARTS
|
||
DPB T1,KDLSTA## ;STARTING NOW
|
||
MOVSI T1,(XMTBTS) ;MAKE SURE PAST QUEUED REQUESTS ARE CANCELED
|
||
ANDCAM T1,KDLSTS(F) ;AS WE'D ONLY GET CONFUSED LATER
|
||
MOVSI T1,(KDSSTR) ;SEND A START
|
||
IORM T1,KDLSTS(F) ;WHEN WE GET A CHANGE
|
||
PJRST RCVNK2 ;CRANK UP THE KMC
|
||
|
||
RCVST2: LDB T1,KDLSTA## ;GET OUR STATE, AND
|
||
CAIE T1,KD%STR ; IF WE'RE NOT SENDING STARTS,
|
||
CAIN T1,KD%STK ; OR SENDING STACKS
|
||
CAIA ;OK
|
||
PJRST RCVBUF ;THEN DON'T PROCESS THE START
|
||
MOVEI T1,KD%STK ;GET THE "SENDING STACK'S STATE"
|
||
DPB T1,KDLSTA## ; AND PUT THIS LINE IN THAT STATE
|
||
MOVSI T1,(XMTBTS) ;GET MASK OF "MESSAGE QUEUED" BITS
|
||
ANDCAM T1,KDLSTS(F) ; AND CLEAR ALL PENDING REQUESTS
|
||
MOVSI T1,(KDSSTK) ;GET THE "SEND A STACK" REQUEST BIT
|
||
IORM T1,KDLSTS(F) ; AND REQUEST A STACK
|
||
PJRST RCVNK2 ;CRANK US UP
|
||
RCVSTK: CAIE T3,KD%RUN ;IF NOT RUNNING
|
||
JRST RCVSK1 ;PROCEED
|
||
MOVSI T1,(KDSACK) ;RUNNING, SEND AN ACK
|
||
IORM T1,KDLSTS(F) ;TO KEEP OTHER END HAPPY
|
||
MOVSI T1,(KDSNAK) ;DON'T ALLOW NAK
|
||
ANDCAM T1,KDLSTS(F) ;WHICH WOULD KEEP THE ACK FROM GOING OUT
|
||
JRST RCVNK2 ;CRANK THINGS UP
|
||
|
||
RCVSK1: CAIE T3,KD%STR ;IF WE AREN'T SENDING STARTS, THEN
|
||
CAIN T3,KD%STK ; OK IF SENDING STACKS TOO
|
||
CAIA
|
||
PJRST RCVBUF ; IGNORE ALL STACKS
|
||
PUSHJ P,STPTMR ;STOP THE TIMER
|
||
MOVEI T1,KD%RUN ;GET THE "RUN" STATE
|
||
DPB T1,KDLSTA## ; AND PUT THIS LINE IN "RUN"
|
||
MOVSI T1,(XMTBTS) ;GET THE BIT MASK OF MSG REQUESTS
|
||
ANDCAM T1,KDLSTS(F) ; AND CLEAR ALL QUEUED REQUESTS
|
||
MOVSI T1,(KDSACK) ;GET THE "REQUEST ACK" BIT,
|
||
IORM T1,KDLSTS(F) ; AND QUEUE AN ACK TO GET THINGS STARTED
|
||
|
||
PUSHJ P,KDLPUP ;TELL NETSER THAT THIS KDL IS ONLINE
|
||
JRST RCVNK2 ;CRANK THINGS UP
|
||
SUBTTL RCVDAT -- ROUTINE TO PROCESS INCOMING DATA MESSAGES.
|
||
|
||
;Called from RCVMSG with:
|
||
; F, W := KDL and KDP pointers
|
||
; P1, P2, P3 := SEL2, SEL4 and SEL6 of the KMC-11
|
||
; T4 := a CBP to the first byte of the BDL (set up by FREBOI)
|
||
;
|
||
RCVDAT: AOS KDLDTR(F) ;COUNT THIS RECEIVED DATA MESSAGE
|
||
TRNN P3,BFREOM ;DOES THIS BUFFER CONTAIN THE ENTIRE MESSAGE
|
||
PJSP T1,KDLERR ;IF NOT, WE'RE NOT GOING TO RECOVER
|
||
;SHOULD GIVE A "MESSAGE TO BIG" NAK BUT
|
||
; THE SECOND HALF OF THE MESSAGE WOULD
|
||
; BE INTERPRETED AS A COMPLETE NEW MESSAGE.
|
||
PUSH P,T4 ;PRESERVE OUR BDL POINTER
|
||
PUSHJ P,CHKACK ;PROCESS THE IMPLICIT ACK IN THE MESSAGE
|
||
POP P,T4 ;GET OUR BUFFER POINTER BACK
|
||
LDB T1,KDLSTA## ;FETCH OUR STATE
|
||
CAIE T1,KD%RUN ;IF WE ARE NOT RUNNINT,
|
||
PJRST RCVBUF ;THEN DON'T RECEIVE ANY DATA
|
||
|
||
LDB T1,BYTABL+6 ;GET THIS MESSAGES NUMBER
|
||
LDB T2,KDLRMN## ;GET THE NUMBER OF THE LAST MESSAGE RECEIVED
|
||
AOS T2 ; PLUS ONE
|
||
ANDI T2,377 ;MASK TO 8 BITS
|
||
CAIE T1,(T2) ;IS THIS THE ONE WE'RE EXPECTING?
|
||
PJRST RCVBUF ;IF NOT, JUST POST ANOTHER RECEIVE BUFFER
|
||
|
||
LDB T3,BYTABL+3 ;FIRST GET THE LOW 8 BITS
|
||
LDB T1,BYTABL+4 ; AND THEN THE UPPER 6
|
||
DPB T1,[POINT 6,T3,27] ;ASSEMBLE THEM INTO THE MESSAGE LENGTH
|
||
JUMPE T3,RCVBUF ;IF ZERO LENGTH MESSAGE, IGNORE
|
||
|
||
PUSH P,T2 ;REMEMBER MESSAGE NUMBER
|
||
PUSH P,T3 ;SAVE THE MESSAGE LENGTH
|
||
PUSH P,T4 ; AND OUR POINTER INTO THE INPUT BUFFER
|
||
MOVEI T1,DC.IGB ;GET THE "REQUEST INPUT BUFFER" FUNCTION
|
||
PUSHJ P,CALDVR ; AND CALL OUR DRIVER
|
||
POP P,T4 ;RESTORE BHT CBP
|
||
POP P,T3 ; AND THE MESSAGE LENGTH
|
||
POP P,T2 ;RESTORE OUR MESSAGE NUMBER
|
||
JUMPE T1,[MOVEI T1,RSNBTU ;IF WE DIDN'T GET A BUFFER
|
||
PJRST RCVXNK] ; SEND A "NO ROOM" NAK
|
||
DPB T2,KDLRMN## ;FINALLY. NOW WE CAN INCREMENT THE "RMN"
|
||
;NOW FIGURE OUT WHAT SORT OF INPUT BUFFER WE ARE COPYING INTO
|
||
|
||
PUSH P,T1 ;SAVE OUR POINTER TO THE BUFFER
|
||
MOVE T2,MB.FMS(T1) ;GET THE POINTER TO THE MSD (IF DECNET)
|
||
JUMPE T2,RCVDA1 ;IF ANY, GO GET POINTERS FROM PCB
|
||
; CAMLE T3,MD.ALL(T2) ;MAKE SURE THAT THE DATA WILL FIT
|
||
; PUSHJ P,NTDSTP## ;++ DRIVER GAVE US TOO SMALL A BUFFER
|
||
MOVEM T3,MD.BYT(T2) ;STORE THE BYTE COUNT
|
||
MOVE T6,MD.ALA(T2) ;BYTE POINTER IS INDEXED BY T6
|
||
MOVE T2,MD.PTR(T2) ; AND FETCH THE BYTE POINTER
|
||
JRST RCVDA2 ;NOW GO COPY THE DATA
|
||
|
||
;HERE FOR ANF-10 STYLE BUFFERS
|
||
RCVDA1: MOVE T2,PCBCTR(T1) ;GET THE SIZE OF THE PCB
|
||
CAMLE T3,T2 ; AND MAKE A QUICK SIZE CHECK
|
||
PUSHJ P,NTDSTP## ;STOP IF DRIVER GAVE TOO SMALL A BUFFER
|
||
MOVEM T3,PCBCTR(T1) ;STORE THE ACTUAL LENGTH FOR NETSER
|
||
MOVE T2,PCBPTR(T1) ;GET THE INPUT BYTE POINTER
|
||
; JRST RCVDA2 ;FALL THROUGH TO THE COPY ROUTINES
|
||
;AT THIS POINT
|
||
; T2 := A BYTE POINTER INTO THE PCB
|
||
; T3 := THE NUMBER OF BYTES TO MOVE
|
||
; T4 := A CBP INTO THE MESSAGE TO COPY.
|
||
;FOR EFFICIENCY, COPY AS MANY SETS OF FOUR BYTES AS POSSIBLE.
|
||
|
||
RCVDA2: ADD T4,[XWD 1,1] ;ADVANCE THE CBP TO THE FIRST DATA BYTE
|
||
;(DDCMP HEADER IS 6 BYTES, WANT PRE DEC CBP)
|
||
IBP T2 ;POINT TO WORD CONTAINING FIRST BYTE
|
||
MOVEI T2,@T2 ;RESOLVE ANY INDEXING, ETC
|
||
HRLI T2,1(T4) ;POINT TO FIRST DATA WORD OF MESSAGE
|
||
SOS T3 ;ROUND BYTE COUNT AND CONVERT TO WDS (+3 -4)
|
||
LSH T3,-2 ;BYTES - WORDS
|
||
ADDI T3,(T2) ;END ADDRESS
|
||
BLTUB T2,(T3) ;MOVE MESSAGE TRANSLATED. (MAYBE FEW EXTRA)
|
||
|
||
RCVDA6: POP P,T3 ;GET OUR BUFFER ADDRESS BACK
|
||
MOVEI T1,DC.IIC ;GET THE "INPUT DONE" FUNCTION CODE
|
||
PUSHJ P,CALDVR ;CALL THE DRIVER TO RETURN THE FILLED BUFFER
|
||
PUSHJ P,RCVBUF ;TRY TO QUEUE ANOTHER RECEIVE BUFFER
|
||
MOVSI T1,(KDSNAK) ;NO POINT ANY MORE
|
||
ANDCAM T1,KDLSTS(F) ;...
|
||
MOVSI T1,(KDSACK) ;SEND AN ACK WHEN XMITTER IS IDLE
|
||
IORM T1,KDLSTS(F) ;TO ALLOW REMOTE TO FREEE BUFFERS & FILL PIPE
|
||
PJRST XMTBUF ;ANY DATA MESSAGE 'IMPLIED ACK' WILL CANCEL
|
||
SUBTTL RCVBUF -- POST AN INPUT BUFFER RECEIVE REQUEST
|
||
|
||
; This routine:
|
||
; 1) Checks for a free input buffer. If none, it returns.
|
||
; 2) Allocates the input buffer and marks it as "in use".
|
||
; 3) Constructs a BDL for the buffer.
|
||
; 4) Queue's a BUFFER-INPUT(INPUT) transaction for the KMC-11
|
||
;
|
||
;Called from "many places" with:
|
||
; F, W := KDL and KDP pointers
|
||
;
|
||
RCVBUF: LDB T1,KDLSTA## ;GET OUR STATE
|
||
CAIG T1,KD%FLS ;SKIP IF WE CAN QUEUE ANOTHER RECEIVE BUFFER
|
||
POPJ P, ; IF WE CAN'T, JUST EXIT NOW
|
||
AOSG T1,KDLRBC(F) ;INCREMENT COUNT OF RCV BUFFERS QUEUED
|
||
PUSHJ P,NTDSTP## ;++ SHOULD NEVER BE NEGATIVE
|
||
CAILE T1,2 ;IF LESS THAN 2 BUFFERS QUEUED, WE CAN Q MORE
|
||
JRST [SOS KDLRBC(F) ;CORRECT THE COUNT
|
||
POPJ P,] ; AND RETURN
|
||
|
||
PUSHJ P,SAVP4## ;BEFORE WE DO REAL WORK, PRESERVE PERM AC
|
||
SOS T1 ;T1 NOW IS EITHER 0 ! 1
|
||
MOVE T2,KDLSTS(F) ;GET THE STATUS (CONTAINS NEXT BUFFER OUT BIT)
|
||
TRNE T2,KDSNRB ;IF NEXT BUFFER OUT ISN'T 0
|
||
XORI T1,1 ;THEN NEXT BUFFER IN IS DIFFERENT
|
||
MOVEI P4,@[CAI KDLRD1(F) ;LOAD PROPER BDL ADDRESS
|
||
CAI KDLRD2(F)](T1) ;FROM T1
|
||
|
||
MOVSI T1,(1B0) ;GET A SIGN BIT AND USE IT TO MAKE SURE
|
||
TDNE T1,(P4) ; THAT THIS BDL IS REALLY FREE
|
||
PUSHJ P,NTDSTP ;++ SOMETHING SCREWED UP...
|
||
; IORM T1,(P4) ;SET BDL IN USE CHECK BIT (WE SET IT LATER)
|
||
|
||
;DROP TRHOUGH TO CONSTRUCT THE BDL
|
||
;FROM ABOVE. HERE TO CONSTRUCT THE BDL AND QUEUE THE BUFFER-IN TRANSACTION
|
||
|
||
MOVEI T1,3(P4) ;GET START OF DATA MESSAGE AREA
|
||
SUBI T1,(F) ;CONVERT TO OFFSET ON PAGE
|
||
LSH T1,2 ;CONVERT FROM WORDS TO BYTES
|
||
ADDI T1,2 ;STARTS AT 3+1/2 WDS SO USER DATA IS WORD
|
||
;ALIGNED & CAN UBABLT
|
||
ADD T1,KDLADR(F) ;CONVERT PAGE OFFSET TO UNIBUS ADDR
|
||
MOVEI T2,-16(T1) ;SAVE ADDR OF BDL FOR LATER
|
||
;BDL1.1
|
||
HRLZM T1,0(P4) ;STORE LOW 16 BITS OF ADDR IN THE BDL
|
||
;BDL1.3
|
||
LSH T1,-6 ;SHIFT BITS 16 & 17 DOWN TO SCREWY POSITION
|
||
ANDI T1,BDLXAD ;MASK TO GET JUST THE EXTENDED ADDR BITS
|
||
TRO T1,BDLLDS ;SAY THAT THIS IS THE LAST BD
|
||
HRLZM T1,1(P4) ;STORE THIRD BDL WORD
|
||
;BDL1.2
|
||
MOVEI T1,KDLMMS*4 ;GET MAX MESSAGE SIZE
|
||
HRRM T1,0(P4) ;AND STORE THAT IN THE LENGTH FIELD
|
||
|
||
MOVSI T1,(1B0) ;GET THE BDL IN USE BIT
|
||
IORM T1,0(P4) ; AND MARK BDL AS IN USE
|
||
|
||
;NOW QUEUE THE BUFFER IN TRANSACTION
|
||
|
||
MOVE W,KDLKDP(F) ;JUST MAKE SURE "W" IS SET UP
|
||
MOVE T1,KDLINE(F) ;GET OUR LINE NUMBER
|
||
LSH T1,10 ;SHIFT INTO THE HIGH BYTE
|
||
TRO T1,KMCIOT ;SAY THAT WE ARE QUEUEING AN INPUT BUFFER
|
||
HRLZ T3,T2 ;COPY THE BDL ADDRESS
|
||
LSH T2,-2 ;SHIFT TWO HIGH ORDER BITS DOWN
|
||
IOR T2,T3 ;COMBINE SEL4 AND SEL6
|
||
AND T2,[XWD 177777,140000] ;MASK OUT TRASH
|
||
PUSHJ P,KMCINP ;QUEUE TRANSACTION
|
||
POPJ P, ;AND RETURN
|
||
POPJ P, ;(IGNORE SKIP RETURN)
|
||
SUBTTL XMTBUF -- ROUTINE TO TRANSMIT DDCMP CONTROL AND DATA MESSAGES.
|
||
|
||
;Called from "most anywhere" with interrupts off and:
|
||
; F, W := KDL and KDP pointers
|
||
;
|
||
XMTBUF: PUSHJ P,SAVE4## ;THIS CODE CLOBBERS THEM ALL
|
||
MOVE T1,KDLSTS(F) ;GET THE WORD WITH THE MESSAGE FLAGS
|
||
AND T1,[XMTBTS] ; AND GET JUST THE FLAGS
|
||
LDB T2,KDLSTA## ;GET THE STATE
|
||
CAIG T2,KD%FLS ; AND IF WE'RE FLUSHING,
|
||
POPJ P, ; THEN DON'T DO ANYTHING
|
||
CAIN T2,KD%MAI ;IF WE ARE IN MAINT STATE, THEN
|
||
SETZ T1, ; WE CAN ONLY SEND DATA (MAINT) MSGS
|
||
SKIPE KDLWTO(F) ;IF THERE IS DATA TO GO,
|
||
TLO T1,(KDSDAT) ; THEN SET THE BIT SAYING SO.
|
||
JFFO T1,XMTBF1 ;JUMP IF THERE ARE ANY MSGS TO SEND
|
||
POPJ P, ; IF NO MSGS TO SEND, EXIT
|
||
|
||
XMTBF1: AOSG T1,KDLXBC(F) ;INCREMENT COUNT OF XMIT BUFFERS QUEUED
|
||
PUSHJ P,NTDSTP## ;++ SHOULD NEVER BE NEGATIVE
|
||
CAILE T1,2 ;IF LESS THAN 2 BUFFERS QUEUED, WE CAN Q MORE
|
||
JRST [SOS KDLXBC(F) ;CORRECT THE COUNT
|
||
POPJ P,] ; AND RETURN
|
||
|
||
SOS T1 ;T1 NOW IS EITHER 0 ! 1
|
||
MOVE T3,KDLSTS(F) ;GET THE STATUS (CONTAINS NEXT BUFFER OUT BIT)
|
||
TRNE T3,KDSNXB ;IF NEXT BUFFER OUT ISN'T 0
|
||
XORI T1,1 ;THEN NEXT BUFFER IN IS DIFFERENT
|
||
MOVEI P4,@[CAI KDLXD1(F) ;LOAD PROPER BDL ADDRESS
|
||
CAI KDLXD2(F)](T1) ;FROM T1
|
||
|
||
MOVSI T1,(1B0) ;GET A SIGN BIT AND USE IT TO MAKE SURE
|
||
TDNE T1,(P4) ; THAT THIS BDL IS REALLY FREE
|
||
PUSHJ P,NTDSTP ;++ SOMETHING SCREWED UP...
|
||
IORM T1,(P4) ;SET BDL IN USE CHECK BIT (WE SET IT LATER)
|
||
|
||
;NOW P4 := BDL ADDRESS, TIME TO DISPATCH TO PROPER ROUTINE.
|
||
|
||
PUSHJ P,@[ ;DISPATCH ON JFFO CODE
|
||
JRST XMTSTR ;SEND START
|
||
JRST XMTSTK ;SEND STACK
|
||
JRST XMTNAK ;SEND NAK
|
||
JRST XMTREP ;SEND REP
|
||
JRST XMTDAT ;SEND DATA
|
||
JRST XMTACK ;SEND ACK
|
||
](T2) ;MUST REMEMBER NOT TO CLOBBER "T2" ABOVE...
|
||
JFCL ;IGNORE IT IF KMC-11 CRASHES
|
||
POPJ P, ;BACK TO CALLER
|
||
XMTSTR: MOVEI T1,%START ;GET THE START MESSAGE TYPE
|
||
MOVSI T2,(KDSSTR) ;GET THE "BIT TO CLEAR"
|
||
DPB T2,KDLTIM## ;START THE TIMER
|
||
PUSHJ P,XMTSET ;SET UP BDL, T1, T2, T4 ETC...
|
||
PJRST KMCINP ; QUEUE TRANSACTION, CLEAR THE BIT AND RETURN
|
||
|
||
XMTSTK: MOVEI T1,%STACK ;GET THE STACK MESSAGE TYPE
|
||
MOVSI T2,(KDSSTK) ;GET THE "BIT TO CLEAR"
|
||
DPB T2,KDLTIM## ;START THE TIMER
|
||
PUSHJ P,XMTSET ;SET UP BDL, T1, T2, T4 ETC...
|
||
PJRST KMCINP ; QUEUE TRANSACTION, CLEAR THE BIT AND RETURN
|
||
|
||
XMTREP: MOVEI T1,%REP ;GET THE REP MESSAGE TYPE
|
||
MOVSI T2,(KDSREP) ;GET THE "BIT TO CLEAR"
|
||
DPB T2,KDLTIM## ;START THE TIMER
|
||
PUSHJ P,XMTSET ;SET UP BDL, T1, T2, T4 ETC...
|
||
LDB T3,KDLLMX## ;GET LAST TRANSMIT MSG. NUMBER ASSIGNED
|
||
DPB T3,BYTABL+4 ; AND SEND THAT AS THE MSG NUMBER
|
||
PJRST KMCINP ; QUEUE TRANSACTION, CLEAR THE BIT AND RETURN
|
||
|
||
XMTNAK: MOVSI T1,(KDSACK) ;IF ACK QUEUE'D TOO
|
||
TDNE T1,KDLSTS(F) ;I'M VERY CONFUSED
|
||
PUSHJ P,NTDSTP## ;SO I'D BETTER QUIT
|
||
MOVEI T1,%NAK ;GET THE NAK MESSAGE TYPE
|
||
MOVSI T2,(KDSNAK) ;GET THE "BIT TO CLEAR"
|
||
PUSHJ P,XMTSET ;SET UP BDL, T1, T2, T4 ETC...
|
||
PUSH P,T1 ;SAVE T1
|
||
PUSH P,T2 ; AND T2 (NAKTRN GET'S EM)
|
||
LDB T1,KDLXNK## ;GET THE NAK CODE.
|
||
IORI T1,QSYNC!SELECT ;PUT ON THE TWO "REQUIRED" BITS
|
||
DPB T1,BYTABL+2 ; AND STORE THAT IN THE MESSAGE
|
||
ANDI T1,77 ;GET JUST THE NAK CODE BACK AGAIN,
|
||
PUSHJ P,NAKTRN ; CONVERT IT INTO A TABLE INDEX
|
||
ADDI T1,KDLNKX(F) ; RELOCATE TO OUR XMIT NAK COUNTER TABLE
|
||
AOS (T1) ; AND INCREMENT THE ENTRY.
|
||
POP P,T2 ;GET T2 AND
|
||
POP P,T1 ; BACK
|
||
LDB T3,KDLRMN## ;GET LAST MSG. RECEIVED
|
||
DPB T3,BYTABL+3 ; SEND THAT AS IMPLICIT ACK
|
||
PJRST KMCINP ;QUEUE TRANSACTION, CLEAR THE BIT AND RETURN
|
||
|
||
XMTACK: MOVEI T1,%ACK ;GET THE ACK MESSAGE TYPE
|
||
MOVSI T2,(KDSACK) ;GET THE "BIT TO CLEAR"
|
||
PUSHJ P,XMTSET ;SET UP BDL, T1, T2, T4 ETC...
|
||
LDB T3,KDLRMN## ;GET LAST MSG. RECEIVED
|
||
DPB T3,BYTABL+3 ; SEND THAT AS IMPLICIT ACK
|
||
PJRST KMCINP ;QUEUE TRANSACTION, CLEAR THE BIT AND RETURN
|
||
; XMTSET is a utility subroutine used in constructing the various
|
||
;DDCMP control messages. It performs the functions of:
|
||
; 1) Clearing the message request bit in KDLSTS.
|
||
; 2) Constructing a BDL for the control message
|
||
; 3) Filling in selected portions of the control message.
|
||
; Specifically, the header (ENQ), type, control bits and
|
||
; station address (= 1).
|
||
; 4) Sets things up to make it convenient to call KMCINP
|
||
;
|
||
;Called from XMT??? with:
|
||
; F, W := KDL and KDP pointers
|
||
; T1 := Control message type
|
||
; T2 := Message request bit in KDLSTS to clear.
|
||
; P4 := Address of the BDL to use for the message
|
||
;
|
||
;Returns "CPOPJ" with:
|
||
; T1, T2 := Set up with SEL2, SEL4 and SEL6 for KMCINP.
|
||
; T4 := A CBP to the first byte of the message (The ENQ)
|
||
;
|
||
XMTSET: PUSH P,T1 ;SAVE MESSAGE TYPE FOR A BIT
|
||
ADDI T1,KDLCTX-1(F) ;MAKE MESSAGE TYPE A POINTER INTO THE XMITTED
|
||
AOS (T1) ; COUNTS TABLE, AND COUNT THIS CONTROL MSG
|
||
|
||
ANDCAM T2,KDLSTS(F) ;CLEAR THE REQUEST BIT.
|
||
|
||
MOVEI T4,4(P4) ;GET ADDRESS OF THE DATA AREA
|
||
|
||
MOVEI T2,(T4) ;GET ADDRESS OF DATA
|
||
SUBI T2,(F) ;CONVERT TO OFFSET WITHIN PAGE
|
||
LSH T2,2 ;GET PAGE OFFSET IN BYTES
|
||
ADD T2,KDLADR(F) ;MAKE IT A UNIBUS ADDRESS
|
||
;BDL1.1
|
||
MOVEI T1,400000(T2) ;MAKE SURE WE SET THE IN-USE MARK BIT
|
||
HRLZM T1,0(P4) ;STORE -11 ADDRESS OF DDCMP HEADER
|
||
;BDL1.2
|
||
MOVEI T1,6 ;GET THE LENGTH OF THE DDCMP HEADER
|
||
HRRM T1,0(P4) ;WRITE THE LENGTH
|
||
;BDL1.3
|
||
MOVEI T1,(T2) ;GET ADDRESS OF THE HEADER AGAIN
|
||
LSH T1,-6 ;SHIFT TO GET TWO HIGH BITS OF ADDRESS
|
||
ANDI T1,BDLXAD ;MASK TO JUST 2 BITS (6000)
|
||
TRO T1,BDLLDS!BDLRSY!BDLSOM!BDLEOM ;RESYNC, START, END OF MESSAGE
|
||
HRLZM T1,1(P4) ;WRITE THIRD WORD OF HEADER
|
||
|
||
;FALL THROUGH TO WRITE THE CONTROL MESSAGE
|
||
;FROM ABOVE. HERE TO WRITE THE CONTROL MESSAGE
|
||
|
||
MOVE W,KDLKDP(F) ;MAKE SURE "W" IS SET UP
|
||
MOVE T1,KDLINE(F) ;GET THE LINE #
|
||
LSH T1,10 ;PUT LINE NUMBER IN THE HIGH BYTE
|
||
|
||
ADDI T2,-20 ;CORRECT TO GET ADDRESS OF THE BDL
|
||
HRLZ T3,T2 ;COPY THE BDL'S -11 ADDRESS
|
||
LSH T2,-2 ;SHIFT HIGH TWO BITS DOWN
|
||
IOR T2,T3 ;COMBINE
|
||
AND T2,[XWD 177777,140000] ;MASK OUT TRASH
|
||
|
||
MOVEI T3,ENQ ;GET THE CONTROL MESSAGE HEADER
|
||
DPB T3,BYTABL+0 ; AND SET THAT
|
||
POP P,T3 ;GET THE CONTROL MESSAGE TYPE
|
||
DPB T3,BYTABL+1 ; AND SET THAT
|
||
MOVEI T3,QSYNC!SELECT ;THESE TWO BITS ARE REQUIRED BY DDCMP
|
||
DPB T3,BYTABL+2 ; SO PUT THEM IN THE MESSAGE
|
||
|
||
SETZ T3, ;ZERO THE MESSAGE NUMBER FIELDS
|
||
DPB T3,BYTABL+3 ; ACK FIELD
|
||
DPB T3,BYTABL+4 ; NUMBER FIELD
|
||
MOVEI T3,1 ;GET THE POINT-TO-POINT STATION ADDR = 1
|
||
DPB T3,BYTABL+5 ;SET STATION ADDRESS
|
||
POPJ P, ;AND THAT'S ALL
|
||
SUBTTL XMTDAT -- ROUTINE TO SEND A DATA MESSAGE.
|
||
|
||
; XMTDAT constructs DDCMP data messages. It:
|
||
; 1) Requeues the BFR of the message it is outputing
|
||
; to the "awaiting ACK" (KDLWTA) queue. (We are
|
||
; interlocked, so there is no fear of races.)
|
||
; 2) Copies the "header" portion of the message to the
|
||
; appropriate output buffer in the KDL page.
|
||
; 3) Copies, with the appropriate compression, the "data"
|
||
; portion of the BFR. (Ie. The PCBPT2 data.)
|
||
; 4) It the fills in the DDCMP header, constructs a BDL
|
||
; consisting of two buffer descriptors. (One for the
|
||
; DDCMP header, and one for the data portion)
|
||
; 5) It queues BUFFER-OUT(OUTPUT) transaction for the KMC-11
|
||
;
|
||
;Called from XMTBUF with:
|
||
; F, W := KDL and KDP pointers
|
||
; P4 := The address of the BDL to use for the message.
|
||
;Returns
|
||
; CPOPJ If KMC died.
|
||
; CPOPJ1 With message queued if all went OK.
|
||
;
|
||
;Register usage.
|
||
; S = The character we are currently hacking
|
||
; T1 = Count of chars left in BFR
|
||
; T2 = Byte pointer into the BFR
|
||
; T3 = Total number of chars put in the output message buffer
|
||
; T4 = A "canonical" byte pointer to the output message buffer
|
||
;
|
||
; P1-P3 = "Scratch" registers for the conversion routines.
|
||
; P4 = Pointer to KDLXD?. Ie. the approiate buffer descriptor.
|
||
;
|
||
; U = Pointer to the BFR
|
||
; F = Pointer to kdl line block table
|
||
; W = Pointer to kdp table
|
||
;
|
||
;FIRST MAKE SURE THAT WE DON'T HAVE TOO MANY MSGS IN THE "PIPE"
|
||
|
||
XMTDAT: AOS T1,KDLCTA(F) ;COUNT UP THE MESSAGES AWAITING ACK
|
||
CAIL T1,MAXOUT ; BUT IF THERE ARE TOO MANY,
|
||
JRST [SOS KDLCTA(F) ; CORRECT THE ACK AND
|
||
SOS KDLXBC(F) ; NUMBER OF BUFFERS QUEUED COUNTS
|
||
SETZM (P4) ; MARK THE BDL AS "FREE"
|
||
POPJ P,] ; AND DON'T DO ANYTHING.
|
||
|
||
;NOW REQUEUE THE BFR FROM THE WTO QUEUE TO THE WTA.
|
||
PUSH P,U ;SAVE "U" FOR THE DURATION
|
||
HRRZ U,KDLWTO(F) ;GET THE FIRST ENTRY ON THE WTO QUEUE
|
||
HRRZ T1,MB.NXT(U) ;GET THE SECOND ENTRY ...
|
||
HRRZM T1,KDLWTO(F) ;NOW MAKE THE SECOND THE NEW FIRST
|
||
|
||
HLLZS MB.NXT(U) ;MAKE SURE THERE ARE NO STRAY POINTERS
|
||
HRRZ T1,KDLWTA(F) ;GET ADDR OF FIRST ON WTA QUEUE
|
||
JUMPE T1,[HRRZM U,KDLWTA(F) ;IF NONE, MAKE THIS THE FIRST
|
||
JRST XMTDA2] ; AND GO PROCESS IT
|
||
|
||
XMTDA1: HRRZ T2,MB.NXT(T1) ;SEE IF WE'VE REACHED THE END OF THE WTQ Q
|
||
JUMPE T2,[HRRM U,MB.NXT(T1) ;IF SO, APPEND THIS ONE TO THE END
|
||
JRST XMTDA2] ; AND TO PROCESS IT
|
||
MOVE T1,T2 ;IF NOT AT END OF QUEUE, GO TO NEXT BFR
|
||
JRST XMTDA1 ; AND SEE IF IT IS THE END OF THE QUEUE
|
||
|
||
|
||
;NOW SEE IF THE MESSAGE HAS BEEN ASSIGNED A NUMBER. IF NOT, THEN
|
||
; ASSIGN A NEW ONE
|
||
XMTDA2: LDB T1,KDLSTA## ;GET OUR STATE, AND
|
||
CAIN T1,KD%MAI ; IF WE ARE IN MAINT STATE
|
||
JRST XMTDA3 ; THEN DON'T ASSIGN A MESSAGE NUMBER
|
||
MOVE T1,MB.MSN(U) ;(MB.MSNN) = -1 MEANS NO NUMBER ASSIGNED
|
||
JUMPGE T1,XMTDA3 ;IF RESENDING MSG, DON'T ASSIGN A NUMBER
|
||
LDB T1,KDLLMX## ;GET LAST NUMBER ASSIGNED
|
||
ADDI T1,1 ;INCREMENT IT TO THE NEXT
|
||
ANDI T1,^O377 ;MASK TO 8 BITS
|
||
DPB T1,KDLLMX## ;REMEMBER LAST MESSAGE ASSIGNED
|
||
MOVEM T1,MB.MSN(U) ; AND ASSIGN IT TO THIS MESSAGE
|
||
; FROM HERE ON, THE FOLLOWING CONVENTIONS GENERALLY HOLDS
|
||
; T3 := COUNT OF THE NUMBER OF BYTES SO FAR
|
||
; T4 := A BYTE POINTER (PDP-10 STYLE) TO THE OUTPUT BUFFER.
|
||
; WHEN WE ARE ALL DONE COPYING THE DATA, WE WILL SWAP THE BYTES
|
||
; ALL AT ONCE.
|
||
|
||
XMTDA3: MOVE T2,MB.FMS(U) ;NOW SEE IF THIS IS ANF-10 OR DECNET FORMAT
|
||
JUMPE T2,XMTANF ; IF IT'S ANF, GO HANDLE FUNNY BUFFERS
|
||
MOVSI T4,(POINT 8) ;START OFF WITH T4 BEING A BYTE POINTER
|
||
HRRI T4,6(P4) ; TO THE OUTPUT BUFFER
|
||
PUSH P,[EXP 0] ;INITIALIZE THE "TOTAL" COUNT
|
||
XMTDEC: ;ADD CHECK FOR BEING OVERLOADED
|
||
MOVE T6,MD.ALA(T2) ;BYTE POINTER IS INDEXED BY T6
|
||
MOVE T1,MD.AUX(T2) ; AND IT'S BYTE ADDRESS
|
||
MOVE T3,MD.BYT(T2) ;COPY THE LENGTH FOR THE DESTINATION
|
||
ADDM T3,(P) ; AND ACCUMULATE THE TOTAL COPIED
|
||
XMTDE0: SOJL T3,XMTDE1 ;COUNT DOWN NUMBER OF BYTES
|
||
ILDB T5,T1 ;GET A BYTE
|
||
IDPB T5,T4 ;PUT A BYTE
|
||
JRST XMTDE0 ;AND LOOP
|
||
|
||
XMTDE1: HRRZ T2,MD.NXT(T2) ;STEP TO THE NEXT SEGMENT
|
||
JUMPN T2,XMTDEC ; AND IF THERE IS ONE, COPY THAT TOO
|
||
POP P,T3 ;T3 := THE TOTAL LENGTH
|
||
CAILE T3,KDLMMS*4 ;MAKE SURE THE LENGTH WAS REASONABLE
|
||
PUSHJ P,NTDSTP## ;++ MESSAGE WAS TOO BIG
|
||
JRST XMTXIT ;GO SWAP THE BYTES AND SEND THE MESSAGE
|
||
;HERE FOR ANF-10 STYLE BUFFERS
|
||
XMTANF: LDB T1,KDLSTA## ;FIRST GET THE STATE, AND
|
||
CAIN T1,KD%MAI ;IF THIS IS A MAINT MESSAGE
|
||
JRST XMTANM ; GO PROCESS THE STC-BLOCK FORMAT
|
||
|
||
;NOW COPY THE "NCL HEADER" PORTION OF THE MESSAGE.
|
||
; (SNEAKILY MAKING USE OF THE FACT THAT PCB'S START ON WORDS)
|
||
|
||
MOVE T1,PCBCTR(U) ;GET THE LENGTH OF THE HEADER
|
||
MOVE T3,T1 ;GET A "FINAL" COPY OF THE LENGTH
|
||
MOVE T4,T1 ; AND A COPY TO USE FOR ADJBP.
|
||
|
||
HLRZ T2,PCBPTR(U) ;GET THE PCB'S BYTE POINTER
|
||
CAIN T2,(POINT 8,0) ; AND IF IT'S NOT A NEW 8 BIT POINTER
|
||
SKIPG T1 ; OR THE COUNT IS .LE. 0
|
||
PUSHJ P,NTDSTP## ;LET SOMEONE KNOW ABOUT IT.
|
||
|
||
SOS T1 ;ROUND DOWN, AND SHIFT TO GET THE
|
||
LSH T1,-2 ; NUMBER OF WORDS TO BLT (LESS 1)
|
||
|
||
HRLZ T2,PCBPTR(U) ;GET THE ADDRESS TO START BLT'ING FROM
|
||
HRRI T2,6(P4) ;GET THE ADDRESS TO BLT TO
|
||
ADDI T1,(T2) ;ADDRESS OF LAST WORD TO BLT TO
|
||
BLT T2,(T1) ;TRANSFER THE ENTIRE HEADER (AND
|
||
; POSSIBLY A FEW EXTRA BYTES...)
|
||
MOVSI T1,(POINT 8) ;GET A SKELETON BYTE POINTER AND
|
||
HRRI T1,6(P4) ; MAKE IT POINT TO THE OUTPUT BUFFER
|
||
ADJBP T4,T1 ;ADVANCE IT TO ACCOUNT FOR THE DATA
|
||
; WE JUST PUT IN THE BUFFER.
|
||
|
||
;NOW THE "NCL HEADER" HAS BEEN COPIED, READ CONVERSION CODE AND COPY "DATA"
|
||
|
||
LDB T1,PCBPCV## ;GET THE CONVERSION CODE
|
||
CAIL T1,PCV.NC ;RANGE CHECK
|
||
CAILE T1,PCV.BN ; THE CONVERSION CODE
|
||
PUSHJ P,NTDSTP## ;++ NETSER GAVE GARBAGE
|
||
SKIPE PCBCT2(U) ;IF NO SECOND BUFFER, DON'T TRY TO SEND IT
|
||
PUSHJ P,@[EXP C.NC,C.LP,C.BN](T1) ;CALL CONVERSION ROUTINE
|
||
JRST XMTXIT ;GO SWAP THE BYTES AND SEND IT
|
||
;XMTANM ROUTINE TO SEND AN ANF-10 MAINT MESSAGE (STC BLOCK)
|
||
XMTANM: HLRZ T3,STCBLK(U) ;GET THE BYTE COUNT WHERE XMTXIT WANTS IT
|
||
CAIL T3,KDLMMS*4 ;MAKE SURE THAT THE LENGTH IS REASONABLE
|
||
PUSHJ P,NTDSTP## ;IF NOT, TELL SOMEONE
|
||
MOVEI T1,6(P4) ;GET THE ADDRESS OF THE KDL BUFFER
|
||
HRLI T1,STCDAT(U) ;GET THE ADDRESS OF THE MAINT DATA
|
||
MOVE T2,T3 ;GET THE LENGTH (IN BYTES)
|
||
SOS T2 ;ROUND UP(+3), LESS 1 WD (-4)
|
||
LSH T2,-2 ;CONVERT TO WORDS
|
||
ADDI T2,(T1) ;CALCULATE THE END OF THE "BLT"
|
||
BLTBU T1,(T2) ;COPY AND SWAP IN ONE SWELL FOOP
|
||
JRST XMTDON ;DONE
|
||
|
||
;NOW WE HAVE THE BUFFER FILLED, BUT WE MUST SWAP THE BYTES FOR THE
|
||
; STUPID UBA...
|
||
; T3 := THE NUMBER OF BYTES IN THE BUFFER
|
||
;
|
||
;DECNET MESSAGES CAN COME AS CHAINED MSDS OF ODD BYTE LENGTHS, AND
|
||
;ANF MESSAGES CAN HAVE CONVERSION. SO UBABLT HAS TO WAIT TILL NOW,
|
||
;WHEN THE DATA IS IN A FINAL FORM, AND THE START IS WORD-ALIGNED.
|
||
|
||
XMTXIT: MOVEI T1,3(T3) ;GET THE NUMBER OF BYTES, ROUND UP
|
||
ASH T1,-2 ;CONVERT TO A -10 WORD COUNT
|
||
ADDI T1,6(P4) ;SKIP THE BUFFER DESCRIPTIOR, PT TO USER DATA
|
||
MOVEI T4,6(P4) ;T1 HAS THE END ADDR +1, T4 THE START
|
||
HRLI T4,0(T4) ;THIS BLT GOES IN PLACE (SET SOURCE)
|
||
BLTBU T4,-1(T1) ;DO THE SWAP
|
||
;HERE TO WRITE THE BUFFER DESCRIPTOR HEADER
|
||
|
||
XMTDON: LDB T1,KDLSTA## ;GET STATE (MAINT OR NOT) WE USE IT A LOT
|
||
CAIN T1,KD%MAI ;IF THIS IS A MAINT MSG, THEN
|
||
AOSA KDLMAX(F) ; THEN COUNT IT.
|
||
AOS KDLDTX(F) ;OTHERWISE IT'S DATA
|
||
MOVEI T4,3(P4) ;BUILD A PRE-DECREMENTED CBP TO THE
|
||
HRLI T4,3 ; HEADER AREA
|
||
|
||
;HEADER
|
||
MOVEI S,SOH ;ASSUME THAT THIS IS A DATA MESSAGE
|
||
CAIN T1,KD%MAI ; BUT IF IT TURNS OUT TO BE MAINT
|
||
MOVEI S,DLE ; THEN CHANGE THE HEADER CHAR
|
||
PUSHJ P,IDPCB ;WRITE THE HEADER CHARACTER
|
||
;CC1
|
||
MOVE S,T3 ;GET THE LOW 8 BITS OF THE COUNT
|
||
ANDI S,377 ; AND JUST THE LOW 8 BITS
|
||
PUSHJ P,IDPCB ;WRITE THE FIRST PART OF THE COUNT
|
||
;CC2
|
||
MOVE S,T3 ;GET THE COUNT AGAIN
|
||
LSH S,-10 ; AND THIS TIME JUST THE TOP 6 BITS
|
||
TRZE S,777700 ;MAKE SURE THE COUNT WAS REASONABLE
|
||
PUSHJ P,NTDSTP## ; AND STOP IF BUFFER WAS TO BIG
|
||
M9312:: TRO S,SELECT ;SET THE SELECT (POINT 2 POINT)
|
||
CAIN T1,KD%MAI ;AND IF WE ARE IN MAINT MODE,
|
||
TRO S,QSYNC ;SET THE QSYNC ALSO (MAKE THE DMR HAPPY)
|
||
PUSHJ P,IDPCB ;STORE THE UPPER-COUNT AND FLAGS
|
||
;RESP
|
||
SETZ S, ;ASSUME THIS IS MAINT, HENCE ZERO REPS
|
||
CAIE T1,KD%MAI ; BUT IF WE ARE SENDING REAL DATA,
|
||
LDB S,KDLRMN## ;LOAD THE "IMPLIED ACK" NUMBER
|
||
PUSHJ P,IDPCB ;WRITE THE ACK FIELD
|
||
MOVSI S,(KDSACK) ;NO NEED TO ACK
|
||
CAIE T1,KD%MAI ;AT LEAST IF A DATA MESSAGE
|
||
ANDCAM S,KDLSTS(F) ;BECAUSE THE RESP IS JUST AS GOOD
|
||
;NOTE: RH OF S IS STILL ZERO
|
||
;NUM
|
||
CAIE T1,KD%MAI ;IF WE ARE SENDING DATA MESSAGES
|
||
MOVE S,MB.MSN(U) ;GET THE MESSAGE'S NUMBER
|
||
PUSHJ P,IDPCB ;WRITE THE MESSAGE NUMBER FIELD
|
||
;ADDR
|
||
MOVEI S,1 ;GET OUR STATION ADDRESS (1 = P 2 P)
|
||
PUSHJ P,IDPCB ; AND SEND IT
|
||
;TIMER
|
||
SETZ S, ;PREPARE TO START TIMER
|
||
LDB T1,KDLTIM## ;IF IT'S RUNNING
|
||
CAIN T1,KD%MXT ;WE DON'T CHANGE IT
|
||
DPB S,KDLTIM## ;IT'S NOT, START IT
|
||
;IT'S OK NOT TO CHECK MAINT - TIMER IS IGNORED
|
||
;BCC1
|
||
;BCC2
|
||
;FROM ABOVE. AT THIS POINT, THE ENTIRE MESSAGE IS COMPLETE.
|
||
; ALL THAT IS LEFT IS TO BUILD THE BUFFER DESCRIPTOR LIST AND
|
||
; GIVE IT TO THE KMC. P4 := ADDRESS OF THE BDL
|
||
|
||
MOVEI T4,(P4) ;GET ADDRESS OF THE BDL AREA
|
||
TLO T4,(POINT 18,0) ;MAKE A HALF WORD BYTE POINTER
|
||
|
||
MOVEI T2,(P4) ;GET ADDRESS OF THE DATA
|
||
SUBI T2,(F) ;GET JUST THE OFFSET WITHIN THE PAGE
|
||
LSH T2,2 ;GET PAGE OFFSET IN BYTES
|
||
ADD T2,KDLADR(F) ;MAKE IT A UNIBUS ADDRESS
|
||
MOVEI S,20(T2) ;ADDR OF DDCMP HEADER IS 20 BYTES PAST BDL
|
||
;BDL1.1
|
||
IORI S,(1B0) ;MAKE SURE WE SET THE IN-USE MARK BIT
|
||
IDPB S,T4 ;STORE -11 ADDRESS OF DDCMP HEADER
|
||
;BDL1.2
|
||
MOVEI S,6 ;GET THE LENGTH OF THE DDCMP HEADER
|
||
IDPB S,T4 ;WRITE THE LENGTH
|
||
;BDL1.3
|
||
MOVEI S,20(T2) ;GET ADDRESS OF THE HEADER AGAIN
|
||
LSH S,-6 ;SHIFT TO GET TWO HIGH BITS OF ADDRESS
|
||
ANDI S,BDLXAD ;MASK TO JUST 2 BITS (6000)
|
||
TRO S,BDLRSY!BDLSOM!BDLEOM ;RESYNC, START AND END OF MESSAGE
|
||
IDPB S,T4 ;WRITE THIRD WORD
|
||
;BDL2.1
|
||
MOVEI S,30(T2) ;GET ADDRESS AGAIN (OFFSET PAST DDCMP HEADER)
|
||
IDPB S,T4 ;STORE LOW 16 BITS OF ADDR
|
||
;BDL2.2
|
||
IDPB T3,T4 ;T3 STILL HAS THE LENGTH (REMEMBER...)
|
||
;BDL2.3
|
||
MOVEI S,30(T2) ;GET ADDR FOR NEARLY THE LAST TIME
|
||
LSH S,-6 ;SHIFT TO GET HIGH ORDER 2 BITS
|
||
ANDI S,BDLXAD ;MASK TO 2 BITS (6000)
|
||
TRO S,BDLLDS!BDLSOM!BDLEOM ;LAST BDL, START AND END OF MESSAGE
|
||
IDPB S,T4 ;STORE LAST DESCRIPTOR WORD
|
||
|
||
;BDL IS NOW COMPLETE. TIME TO QUEUE IT TO KMCINP
|
||
|
||
MOVE W,KDLKDP(F) ;GET THE ADDRESS OF THE KDP BLOCK
|
||
MOVE T1,KDLINE(F) ;GET THE LINE #
|
||
LSH T1,10 ;PUT LINE NUMBER IN THE HIGH BYTE
|
||
|
||
HRLZ T3,T2 ;COPY THE BDL'S -11 ADDRESS
|
||
LSH T2,-2 ;SHIFT HIGH TWO BITS DOWN
|
||
IOR T2,T3 ;COMBINE
|
||
AND T2,[XWD 177777,140000] ;MASK OUT TRASH
|
||
POP P,U ;RESTORE THE REG USED TO HOLD BFR ADDR
|
||
PJRST KMCINP ;WILL SKIP IF KMC STILL RUNNING
|
||
SUBTTL XMTJNK - ANF-10 SPECIFIC CONVERSION/COMPRESSION ROUTINES
|
||
|
||
;C.NC COPY. NO CONVERSION
|
||
|
||
|
||
C.NC:
|
||
MOVE T1,PCBPT2(U) ;GET THE BYTE POINTER FOR IT
|
||
MOVE T2,PCBCT2(U) ;GET THE LENGTH OF THE STRING TO MOVE
|
||
ADD T3,T2 ;UPDATE T3 TO REFLECT IMPENDING COPY
|
||
C.NC0: SOJL T2,CPOPJ## ;COUNT DOWN BYTES TO COPY
|
||
ILDB T5,T1 ;GET A BYTE
|
||
IDPB T5,T4 ;PUT A BYTE
|
||
JRST C.NC0 ;AND LOOP
|
||
;C.BN COPY. BINARY CONVERSION
|
||
|
||
C.BN: MOVE T1,PCBCT2(U) ;GET COUNT OF SECONDARY BUFFER
|
||
MOVE T2,PCBPT2(U) ;GET ADDRESS OF SECONDARY BUFFER
|
||
C.BN1: SOJL T1,C.BN2 ;LOOP OVER ALL OUTPUT BYTES
|
||
ILDB P1,T2 ;GET FIRST 12 BIT BYTE
|
||
LDB S,[POINT 8,P1,31] ;GET FIRST 8 BITS (4 BITS LEFT)
|
||
IDPB S,T4 ; AND STORE THEM
|
||
SOJL T1,C.BNX ;IF WE COUNT OUT NOW, SEND LAST 4 BITS
|
||
ILDB P2,T2 ;GET NEXT 12 BIT CHAR
|
||
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 FROM OLD 12 BIT BYTE
|
||
IDPB S,T4 ; AND STORE THEM
|
||
LDB S,[POINT 8,P2,35] ;GET LAST 8 BITS FROM NEW BYTE
|
||
IDPB S,T4 ; AND GET RID OF THE LAST
|
||
JRST C.BN1 ;LOOP OVER ALL 12 BIT BYTES
|
||
|
||
C.BNX: DPB P1,[POINT 4,S,31] ;HERE IF ODD NUMBER, GET LAST 4 BITS
|
||
ANDI S,360 ;MASK TO ONLY 4 BITS
|
||
IDPB S,T4 ; AND WEVE MOVED ALL THE DATA
|
||
|
||
;NOW TO ADJUST "T3" TO ACCOUNT FOR THE BYTES JUST STORED
|
||
|
||
C.BN2: MOVE T1,PCBCT2(U) ;GET THE COUNT BACK
|
||
IMULI T1,^D12 ; (12 * PCBCTR) + 7
|
||
ADDI T1,7 ; ----------------- = NUMBER OF 8 BIT BYTES
|
||
LSH T1,-3 ; 8
|
||
ADDI T3,(T1) ;UPDATE THE COUNT
|
||
POPJ P, ;DONE, T4 CONTAINS UPDATED BYTE POINTER
|
||
;C.LP COPY. LINE PRINTER CONVERSION (WITH COMPRESSION)
|
||
;
|
||
;DATA FOR LINE PRINTER IS COMPRESSED AS FOLLOWS
|
||
; 1CCCCCCC ;CCCCCCC IS A SINGLE CHARACTER
|
||
; 01XXXXXX ;XXXXXX IS A COUNT OF BLANKS
|
||
; 001XXXXX ;XXXXX IS A REPETITION COUNT FOR NEXT CHAR
|
||
;
|
||
;REGISTER USAGE
|
||
; P1 := REPEAT COUNT
|
||
; P2 := CHAR BEING REPEATED
|
||
; P3 := NEXT CHAR (PUT HERE & COMPARED WITH P2)
|
||
|
||
C.LP: MOVE T1,PCBCT2(U) ;GET COUNT OF SECONDARY DATA
|
||
MOVE T2,PCBPT2(U) ;GET POINTER TO SECONDARY DATA
|
||
|
||
PUSH P,T4 ;SAVE BYTE POSITION AND COUNT. WE WILL
|
||
PUSH P,T3 ; HAVE TO "FIXUP" THE NCL HEADER TO ACCOUNT
|
||
; FOR THE LENGTH DIFFERENCE AFTER COMPRESSION.
|
||
;FROM ABOVE. NOW START COMPRESSING THE LINE-PRINTER DATA.
|
||
|
||
SETZ P1, ;INITIALIZE REPEAT COUNT
|
||
SOJL T1,C.LPX ;IF NO DATA, FIX UP MSG LENGTH ANYWAY
|
||
ILDB P2,T2 ;PRIME THE LOOP WITH AN INITIAL CHAR
|
||
|
||
LPLOOP: SOJL T1,NMATCH ;HO CHARS DON'T MATCH ANY CHARS
|
||
ILDB P3,T2 ;GET NEXT CHAR
|
||
CAIN P3,(P2) ;SAME AS LAST?
|
||
AOJA P1,LPLOOP ;IF SO, COUNT IT AND KEEP SCANNING
|
||
|
||
NMATCH: JUMPE P1,SINGLE ;JUMP IF THIS WAS AN UN-REPEATED CHAR
|
||
AOJ P1, ;FIXUP THE COUNT (WAS OFF BY 1)
|
||
CAIN P2," " ;WERE WE COMPRESSING SPACES?
|
||
JRST SPACES ;IF IT WAS SPACES, HANDLE DIFFERENTLY
|
||
|
||
CHARS: CAIG P1,37 ;MORE CHARS THAN 1 BYTE CAN REPEAT?
|
||
JRST CHARX ;IF IT WILL FIT IN 1 BYTE, SEND NOW
|
||
MOVEI S,77 ;MAXIMUM REPEAT COUNT & CHAR FLAG
|
||
IDPB S,T4 ;WRITE THE REPEAT COUNT
|
||
IDPB P2,T4 ; AND NOW WRITE THE CHARACTER
|
||
ADDI T3,2 ;ACCOUNT FOR THE TWO BYTES WRITTEN
|
||
SUBI P1,37 ;ACCOUNT FOR 37 LESS CHARS IN REPEAT COUNT
|
||
JRST CHARS ;LOOP TILL REPEAT COUNT GETS SMALL ENOUGH
|
||
|
||
CHARX: MOVEI S,40(P1) ;GET REPEAT CHAR BYTE
|
||
IDPB S,T4 ;STORE THE REPEAT COUNT
|
||
TRO P2,200 ;TURN ON THE EXTEND BIT TO KEEP 8'S HAPPY
|
||
IDPB P2,T4 ; AND NOW THE CHARACTER
|
||
ADDI T3,2 ;ACCOUNT FOR BOTH
|
||
JRST ADVNC1 ; AND GO BACK TO COMPARE LOOP
|
||
|
||
SPACES: CAIG P1,77 ;SEE IF WE CAN FIT THIS ALL IN 1 REPEAT COUNT
|
||
JRST SPACEX ;JUMP IF 1 REPEAT COUNT BYTE IS SUFFICIENT
|
||
MOVEI S,177 ;GET A "77" SPACES REPEAT BYTE
|
||
IDPB S,T4 ;STORE THE SPACE REPEAT COUNT
|
||
AOS T3 ; AND ACCOUNT FOR IT
|
||
SUBI P1,77 ;COUNT OFF THE 77 SPACES
|
||
JRST SPACES ;LOOP TILL COUNT GETS SMALL ENOUGH
|
||
|
||
SPACEX: MOVEI S,100(P1) ;GET "SPACE REPEAT" BIT AND COUNT
|
||
JRST ADVNCE ;WRITE THE BYTE AND GO BACK TO COMPARE LOOP
|
||
|
||
SINGLE: MOVEI S,200(P2) ;GET THE SINGLE CHAR BIT (AND THE CHAR)
|
||
ADVNCE: IDPB S,T4 ;STORE THE BYTE
|
||
AOS T3 ; AND ACCOUNT FOR IT
|
||
ADVNC1: MOVEI P2,(P3) ;ADVANCE THE CHAR TO ATTEMPT A MATCH ON
|
||
SETZ P1, ;CLEAR THE COUNT
|
||
JUMPGE T1,LPLOOP ;GO BACK IF THERE ARE MORE CHARS TO DO
|
||
; JRST C.LPX ;IF DONE, GO FIXUP NCL HEADER (SIGH)
|
||
;C.LPX At this point the line printer data has been compressed.
|
||
; T3 contains the actual number of data bytes. (P) contains
|
||
; the number of bytes in the "NCL HEADER" portion of the
|
||
; message. (This includes the "type" field)
|
||
;
|
||
C.LPX: POP P,T2 ;GET LENGTH OF HEADER
|
||
SUBM T3,T2 ;SUBTRACT TO GET LENGTH OF DATA
|
||
ADDI T2,1 ;COUNT THE TYPE FIELD TWICE. (WE JUST
|
||
; SUBTRACTED IT OUT ONCE.)
|
||
EXCH T4,(P) ;GET A BYTE POINTER TO LAST "CNT" BYTE
|
||
PUSHJ P,C.DLB ;SKIP BACKWARDS OVER THE "TYPE" FIELD
|
||
MOVEI T1,0 ;INITIALIZE LENGTH OF THE "CNT" FIELD
|
||
|
||
C.LPX1: PUSHJ P,C.DLB ;DECREMENT AND LOAD THE BYTE
|
||
TRNE S,200 ;IS THE EXTENSIBLE BIT ON?
|
||
AOJA T1,C.LPX1 ;IF STILL EXTENSIBLE, THEN STILL IN "CNT"
|
||
|
||
C.LPX2: MOVEI S,(T2) ;GET A COPY OF T2 (DATA BYTE COUNT)
|
||
LSH T2,-7 ;SHIFT COUNT DOWN FOR NEXT TIME
|
||
ANDI S,177 ;GET JUST 7 BITS WORTH
|
||
SKIPE T1 ;BUT IF THIS ISN'T THE LAST BYTE
|
||
TRO S,200 ; THEN SET THE EXTENSIBLE BIT
|
||
IDPB S,T4 ;STORE THE BYTE
|
||
SOJGE T1,C.LPX2 ;LOOP OVER ALL OF THE "CNT" FIELD
|
||
|
||
SKIPE T2 ;WE BETTER HAVE STORED IT ALL
|
||
PUSHJ P,NTDSTP## ;++ HORRIBLE BUG.
|
||
|
||
POP P,T4 ;GET POINTER TO MESSAGE BACK AGAIN
|
||
POPJ P, ;DONE WITH LPT COMPRESSION
|
||
; T3 := LENGTH OF ENTIRE MESSAGE BUFFER
|
||
|
||
;ROUTINE TO DO A "DECREMENT AND LOAD BYTE"
|
||
|
||
C.DLB: MOVE S,T4 ;COPY THE BYTE POINTER
|
||
SETO T4, ;GET A -1
|
||
ADJBP T4,S ;BACK IT UP
|
||
LDB S,T4 ;GET THE BYTE
|
||
POPJ P, ; AND RETURN
|
||
SUBTTL CHKACK -- PROCESS THE "ACK" FIELD OF CONTROL AND DATA MSGS.
|
||
|
||
; CHKACK is a routine that scans the "awaiting ack" message queue for
|
||
;messages whose numbers are less than, or equal to the "ack" field of the
|
||
;message header pointed to by "T4". Such messages are de-queued and returned
|
||
;to the driver via DC.IOD
|
||
;
|
||
;Called from RCV??? with:
|
||
; F, W := KDL and KDP pointers
|
||
; T4 := a CBP to the first byte of the message.
|
||
; (Set up by XMTSET)
|
||
;Returns
|
||
; CPOPJ ALWAYS
|
||
;
|
||
CHKACK: LDB T1,KDLSTA## ;GET THE DDCMP "STATE" VARIABLE
|
||
CAIN T1,KD%STK ;SEE IF WE ARE SENDING STACKS
|
||
JRST [MOVSI S,(KDSSTR!KDSSTK) ;IF WE ARE, CLEAR SEND STACK!START
|
||
ANDCAB S,KDLSTS(F) ; SO WE WON'T CLOBBER NEWLY STARTED LINE
|
||
MOVEI T1,KD%RUN ;GET THE "RUN" STATE VALUE
|
||
DPB T1,KDLSTA##;AND SET THE STATE TO "RUNNING"
|
||
PUSHJ P,KDLPUP ;TELL NETSER THE LINE'S UP
|
||
JRST CHKAC1] ;RETURN TO MAIN LINE CODE
|
||
CAIE T1,KD%RUN ;ARE WE "RUNNING"
|
||
POPJ P, ;IF NOT RUNNING, GIVE ERROR RETURN
|
||
|
||
;THE LINE IS UP. FALL THROUGH TO PROCESS THE ACK
|
||
;FROM ABOVE
|
||
|
||
;NOW LOOP INCREMENTING "LAST MESSAGE ACKED" UNTIL IT EITHER
|
||
; EQUALS "LAST MESSAGE SENT" OR THIS ACK'S VALUE.
|
||
; MESSAGES THAT GET ACK'ED ARE GIVEN BACK TO NETSER
|
||
|
||
CHKAC1: LDB T1,BYTABL+5 ;GET THE ACK FIELD OF THE MESSAGE
|
||
LDB T2,KDLLMA## ;GET THE LAST MESSAGE ACKED
|
||
CAIN T1,(T2) ;SEE IF THIS IS A "NEW" ACK
|
||
JRST CHKAC4 ;IF WE'VE SEEN THIS ACK, CLEAR REP CNT AND EXIT
|
||
SUBI T1,(T2) ;GET THE DIFFERENCE BETWEEN MESSAGES
|
||
SKIPG T1 ;CHECK FOR MESSAGE NUMBER WRAP-AROUND
|
||
ADDI T1,400 ;IF WRAP-AROUND, CORRECT TO POSITIVE VALUE
|
||
CAIL T1,MAXOUT ;SEE IF THIS ACK IS IN RANGE
|
||
POPJ P, ;IF ACK IS OUT OF RANGE, RETURN WITH-OUT
|
||
; PROCESSING. (MIGHT WANT TO GIVE ERROR...)
|
||
LDB T1,KDLLMA## ;GET THE "LAST MESSAGE ACKED"
|
||
ADDI T1,1 ;INCREMENT IT TO NEXT MESSAGE
|
||
ANDI T1,377 ;MASK TO 8 BITS
|
||
DPB T1,KDLLMA## ;STORE THE NEW "LAST MESSAGE ACKED"
|
||
HRRZ T3,KDLWTA(F) ;GET ADDRESS OF NEXT MESSAGE AWAITING AN ACK
|
||
JUMPE T3,CHKAC2 ;NOTHING ON THE WAIT ACK QUEUE, TRY OUTPUT
|
||
HRRZ T2,MB.NXT(T3) ;GET THE ADDRESS OF THE MESSAGE AFTER THAT
|
||
HRRZM T2,KDLWTA(F) ;MAKE THAT MESSAGE THE "NEXT" MESSAGE WAITING
|
||
SOSGE KDLCTA(F) ;SAY THAT THERE IS ONE LESS AWAITING ACK
|
||
PUSHJ P,NTDSTP## ;WE'VE SCREWED UP THE ACK COUNT?
|
||
PJRST CHKAC3 ;GO RETURN THE MESSAGE TO NETSER
|
||
|
||
|
||
;HERE IF BFR IS NOT ON THE WAIT ACK QUEUE. CHECK FOR IT ON OUTPUT WAIT
|
||
|
||
CHKAC2: HRRZ T3,KDLWTO(F) ;GET THE FIRST ENTRY FROM THE OUTPUT WAIT QUEUE
|
||
SKIPN T3 ;IF THERE ISN'T ONE, THEN WE GOT AN ACK FOR
|
||
PJSP T1,KDLERR ; A MSG WE NEVER SENT. THIS IS A FATAL ERROR
|
||
HRRZ T2,MB.NXT(T3) ;GET THE NEXT MSG OFF THE QUEUE
|
||
HRRZM T2,KDLWTO(F) ; AND MAKE IT THE FIRST AWAITING OUTPUT
|
||
|
||
;DROP THROUGH TO RETURN THE BFR
|
||
;HERE WE HAVE T3 := THE BFR THAT HAS BEEN ACKED. FIRST MAKE SURE
|
||
; THAT IT'S REASONABLE, THEN RETURN IT TO THE DRIVER.
|
||
|
||
CHKAC3: MOVE T2,MB.MSN(T3) ;GET THE DDCMP MESSAGE NUMBER
|
||
SKIPLE T3 ;MAKE SURE WE GOT A BFR
|
||
CAIE T1,(T2) ; AND IT BETTER BE THE "NEXT" ONE
|
||
PUSHJ P,NTDSTP## ;++ MESSAGES OUT OF ORDER. KDPINT SCREWED UP.
|
||
HLLZS MB.NXT(T3) ;NO STRAY POINTERS PLEASE
|
||
PUSH P,T4 ;PRESERVE THE POINTER TO THE MSG
|
||
MOVEI T1,DC.IOD ;GET THE "OUTPUT DONE" FUNCTION CODE
|
||
PUSHJ P,CALDVR ; AND TELL THE DRIVER THE GOOD NEWS
|
||
POP P,T4 ;RECOVER THE POINTER TO THE MESSAGE
|
||
SETZ T1, ;GET A ZERO AND USE IT TO CLEAR THE REP
|
||
DPB T1,KDLRPC## ; COUNTER SINCE THINGS SEEM TO BE WORKING.
|
||
DPB T1,KDLTIM## ;RESTART REP TIMER
|
||
JRST CHKAC1 ;LOOP INCREMENTING "LAST MESSAGE ACK'ED" UNTIL
|
||
; IT EQUALS THE "ACK" FIELD OF THE MESSAGE.
|
||
|
||
|
||
CHKAC4: LDB T1,KDLLMX## ;GET THE LAST MESSAGE SENT
|
||
; LDB T2,KDLLMA## ;(FROM ABOVE)
|
||
CAIE T1,(T2) ;SEE IF ANY MESSAGES ARE OUTSTANDING
|
||
POPJ P, ;IF SO, LEAVE REP COUNTER RUNNING
|
||
SETZ T1, ;GET A ZERO AND USE IT TO CLEAR THE REP
|
||
DPB T1,KDLRPC## ; COUNTER SINCE NO MESSAGES OUTSTANDING
|
||
PUSHJ P,STPTMR ;STOP THE TIMER, THERE'S NOTHING OUTSTANDING
|
||
POPJ P,
|
||
SUBTTL GETBDL -- ROUTINE TO FIND A BDL GIVEN IT'S UNIBUS ADDRESS.
|
||
|
||
;Called from KDP?O? with:
|
||
; F, W := KDL and KDP pointers
|
||
; P1, P2, P3 := SEL2, SEL4 and SEL6 of the KMC-11 (Which contain
|
||
; the unibus address of a BDL)
|
||
;Returns
|
||
; CPOPJ With T4 := CBP pointing to the BDL described in P2 & P3.
|
||
;
|
||
GETBDL: MOVE T1,P2 ;GET BUFFER DESCRIPTOR LIST ADDRESS (11 ADDR)
|
||
MOVE T4,P3 ;GET 2 HIGH ORDER BITS
|
||
LSH T4,2 ;POSITION THEM AS HIGH BITS IN 18 BIT ADDR
|
||
ANDI T1,177777 ;GET LOW ORDER 16 BITS
|
||
ANDI T4,600000 ;GET HIGH ORDER 2 BITS
|
||
IORI T4,(T1) ;"OR" THEM TO GET ENTIRE 18 BIT 11 ADDRESS
|
||
|
||
SUB T4,KDLADR(F) ;T1 NOW HAS BYTE OFFSET FROM START OF PAGE
|
||
|
||
DPB T4,[POINT 2,T4,15] ;MOVE THE TWO LOW ORDER BITS TO HIGH HALF
|
||
LSH T4,-2 ;SHIFT WHOLE MESS INTO A CANONICAL BP
|
||
|
||
TDNE T4,[XWD 777774,^-<KDLLEN-1>] ;MAKE SURE IT MAPS TO A PAGE
|
||
PUSHJ P,NTDSTP## ;++ OUR MAP'S ARE SCREWED UP...
|
||
|
||
ADDI T4,(F) ;RELOCATE TO A PAGE ADDRESS
|
||
POPJ P, ;ALL DONE. T4 := A CBP TO THE BDL
|
||
SUBTTL KMCINP -- ROUTINE TO QUEUE TRANSACTIONS FOR THE KMC-11
|
||
|
||
;Called with:
|
||
; W := KDP pointer
|
||
; T1 := XWD 0,SEL2
|
||
; T2 := XWD SEL4,SEL6
|
||
;Returns
|
||
; CPOPJ KMC-11 not running
|
||
; CPOPJ1 Transaction described by T1 & T2 has been queued.
|
||
; RQI has been set to request an interrupt on vector "A".
|
||
; KDPAIV will then process the top transaction on the queue.
|
||
;
|
||
KMCINU: KDPOFF ;ENTRY TO TURN INTERRUPTS OFF FIRST
|
||
PUSHJ P,KMCINP ;QUEUE THE TRANSACTION
|
||
SKIPA ;HANDLE SKIP RETURNS PROPERLY
|
||
AOS (P) ;GIVE SKIP
|
||
KDPONJ: KDPON ;RE-ENABLE INTERRUPTS
|
||
POPJ P, ;ALL DONE
|
||
|
||
|
||
|
||
KMCINP: MOVE T3,KDPIQP(W) ;GET INDEX OF NEXT ENTRY IN THE QUEUE
|
||
LSH T3,1 ;MAKE IT AN OFFSET (ENTRYS ARE 2 WDS)
|
||
ADDI T3,KDPINQ(W) ;RELOCATE TO THE ADDRESS OF THE QUEUE
|
||
MOVEM T1,0(T3) ;STORE SEL2
|
||
MOVEM T2,1(T3) ;STORE XWD SEL4,SEL6
|
||
AOS T3,KDPIQP(W) ;ADVANCE THE "PUTTER"'S INDEX
|
||
CAIL T3,KDPQLN ;IF WE NEED TO WRAP AROUND, THEN
|
||
SETZB T3,KDPIQP(W) ; THEN WRAP TO THE FIRST ENTRY
|
||
CAMN T3,KDPIQT(W) ;IS THE QUEUE FULL (PUTTER = TAKER)
|
||
PJSP T1,KDPERR ; IF SO, KMC MUST BE DEAD. CRASH IT.
|
||
|
||
MOVEI T3,KMCRQI ;GET RQI AND SET IT IN BSEL0
|
||
BSIO T3,@KDPCSR(W) ; THIS WILL CAUSE A VECTOR "A" INTERRUPT
|
||
RETSKP ;GOOD RETURN
|
||
;NAKTRN - ROUTINE TO "TRANSLATE" NAKS. SINCE NAK CODES ARE SPARSE, AND
|
||
; WE WISH TO USE DENSE NAK COUNT TABLES, THIS ROUTINE MAPS FROM
|
||
; NAK CODE TO TABLE INDEX
|
||
;
|
||
;CALL MOVEI T1,NAK-CODE
|
||
; PUSHJ P,NAKTRN
|
||
;RETURN CPOPJ ;ALWAYS, T1 := TRANSLATED NAK,
|
||
; ; OR 0 IF UN-RECOGNIZED NAK (RANDOM NAK)
|
||
;
|
||
NAKTRN: PUSHJ P,SAVE1## ;WE NEED A TEMP. SO WE USE P1
|
||
MOVEI T2,(T1) ;COPY THE NAK CODE
|
||
MOVEI T1,1 ;GET FIRST GUESS AT TABLE INDEX
|
||
MOVE P1,[POINT 6,NAKTBL] ;GET A POINTER TO THE NAK XLATION TBL
|
||
NAKTR1: ILDB T3,P1 ;GET THE NEXT NAK CODE
|
||
CAIN T3,(T2) ;DOES IT MATCH OUR NAK
|
||
POPJ P, ;IF IT MATCHES, RETURN. T1 HAS TABLE INDEX
|
||
SKIPE T3 ;WAS THIS A ZERO BYTE?
|
||
AOJA T1,NAKTR1 ;IF NOT AT END OF TABLE, KEEP LOOPING
|
||
SETZ T1, ;TABLE EXHAUSTED, RETURN NAK TYPE OF ZERO
|
||
POPJ P, ;ALL DONE
|
||
|
||
NAKTBL: BYTE (6)1,2,3,^D8,^D9,^D16,^D17,0 ;TABLE OF NAKS
|
||
;CTOTLY - ROUTINE TO "TALLY" CONTROL OUT TRANSACTIONS
|
||
;CALL MOVE P3,SEL6(U) ;CONTAINS THE ERROR CODE
|
||
; PUSHJ P,CTOTLY ;TALLY THE CONTROL OUT TRANSACTION
|
||
; ERROR ;UNKNOWN CONTROL OUT CODE
|
||
; OK ;TRANSACTION TALLYED.
|
||
; ; P1 := "BIT MAP" WHICH HAS A SINGLE
|
||
; ; BIT SET ACCORDING TO THE CODE. THIS IS
|
||
; ; USEFULL FOR KDPCOO AND KDPCOI.
|
||
;RETURN "BIT MASK" IN P1
|
||
|
||
CTOTLY: MOVEI P1,(P3) ;COPY THE ERROR CODE FOR A WHILE
|
||
ANDI P1,377 ;MAKE SURE WE HAVE JUST THE ERROR CODE
|
||
CAIL P1,6 ;LOWEST ERROR CODE WE KNOW OF...
|
||
CAILE P1,26 ;IS THIS ERROR CODE "IN RANGE"
|
||
POPJ P, ; IF NOT IN RANGE, GIVE ERROR RETURN
|
||
|
||
LSH P1,-1 ;MAKE CODES DENSE (NOT EVERY OTHER)
|
||
MOVN T1,P1 ;COPY THE NEGATIVE OF THE CODE FOR LATER LSH
|
||
ADDI P1,KDLCTO-3(F) ;RELOCATE CODE TO COUNTER TABLE
|
||
AOS (P1) ;TALLY THE CONTROL OUT TRANSACTION
|
||
|
||
MOVSI P1,(1B0) ;GET A BIT SHIFTED 0 BITS
|
||
LSH P1,(T1) ;SHIFT IT BY "ERROR CODE" BITS
|
||
RETSKP ;GOOD RETURN
|
||
;FREBOI FREE AN INPUT BUFFER DESCRIPTOR LIST
|
||
; RETURN CANONICAL BYTE POINTER TO MESSAGE IN T4
|
||
FREBOI: PUSHJ P,GETBDL ;GET T4 SET UP FROM P2, P3
|
||
TLNE T4,3 ;BUFFER DESCRIPTOR BETTER START ON EVEN -10 WD
|
||
POPJ P, ; IF NOT EVEN -10 ADDRESS, THEN KMC SCREWED UP
|
||
MOVEI S,KDSNRB ;BIT DESIGNATING NEXT RECEIVE BUFFER
|
||
MOVEI T1,KDLRD1(F) ;ASSUME THAT THIS SHOULD BE BUFFER #1
|
||
TDNE S,KDLSTS(F) ; BUT IF IT SHOULD BE #2, THEN
|
||
MOVEI T1,KDLRD2(F) ; CHANGE OUR MIND.
|
||
CAMN T1,T4 ;MAKE SURE WE GOT THE CORRECT BUFFER BACK
|
||
SOSGE KDLRBC(F) ;DECREMENT THE NUMBER OF ACTIVE RECEIVE BUFFERS
|
||
POPJ P, ;++ EITHER WRONG BUFFER, OR TOO MANY. KILL LINE
|
||
XORB S,KDLSTS(F) ;TOGGLE THE NEXT BUFFER OUT BIT
|
||
|
||
MOVSI T1,(1B0) ;GET THE BDL IN-USE MARK BIT
|
||
TDNN T1,0(T4) ; AND MAKE SURE THAT IT'S SET.
|
||
;[DBUG] POPJ P, ;WE'VE SCREWED UP THE BDL POINTERS?
|
||
PUSHJ P,NTDSTP## ;WE'VE SCREWED UP THE BDL POINTERS [DBUG]
|
||
ANDCAM T1,0(T4) ;CLEAR THE IN-USE BIT
|
||
RETSKP
|
||
|
||
|
||
;RCVXNK - UTILITY ROUTINE TO SEND A NAK. CODE IN T1
|
||
RCVXNK: DPB T1,KDLXNK## ;SAVE THE NAK CODE
|
||
LDB T1,KDLSTA## ;GET THE STATE, AND
|
||
CAIE T1,KD%RUN ; IF WE ARE NOT RUNNING,
|
||
JRST RCVXN1 ; DON'T SEND A NAK
|
||
MOVSI T1,(KDSNAK) ;GET THE NEED TO NAK FLAG
|
||
IORM T1,KDLSTS(F) ;SET FLAG FOR XMTBUF TO SEE
|
||
MOVSI T1,(KDSACK) ;NO POINT IN ACKING...
|
||
ANDCAM T1,KDLSTS(F) ; WHEN WE'RE NAKING
|
||
RCVXN1: PUSHJ P,XMTBUF ;CALL XMTBUF TO TRY TO SEND THE NAK
|
||
PJRST RCVBUF ;TRY TO QUEUE ANOTHER RECEIVE REQUEST
|
||
;FREMAI ROUTINE TO FREE MAINT MESSAGES
|
||
; MAINT MESSAGES MUST BE FREED OUTSIDE THE KDPOFF/KDPON INTERLOCK WHICH
|
||
; IS NOT POSSIBLE IN XMTMAI.
|
||
;CALL F := KDL POINTER
|
||
;RETURN CPOPJ
|
||
|
||
FREMAI: LDB T1,KDLSTA## ;GET OUR STATE, AND
|
||
CAIE T1,KD%MAI ;IF WE AREN'T IN MAINT STATE
|
||
POPJ P, ;DON'T SCREW AROUND WITH THE QUEUE!!
|
||
FREMA1: KDPOFF ;INTERLOCK WRT XMTMAI
|
||
HRRZ T3,KDLWTA(F) ;GET THE NEXT MSG AWATING AN ACK
|
||
JUMPE T3,FREMA2 ; IF NONE, WE ARE DONE
|
||
HRRZ T2,MB.NXT(T3) ;GET THE "NEXT" MESSAGE
|
||
HRRZM T2,KDLWTA(F) ; AND MAKE IT THE NEW FIRST
|
||
SOSGE KDLCTA(F) ;COUNT DOWN ONE LESS MESSAGE
|
||
PUSHJ P,NTDSTP## ;SCREWED UP THE COUNTS...
|
||
KDPON ;GIVE BACK THE INTERLOCK
|
||
MOVEI T1,DC.IOD ;SAY OUTPUT DONE
|
||
PUSHJ P,CALDVR ; TO OUR FRIEND THE DRIVER
|
||
JRST FREMA1 ;SEE IF THEY ARE ANY MORE LEFT
|
||
|
||
;HERE IF NO MORE MAINT MSGS TO FREE
|
||
FREMA2: SKIPE KDLCTA(F) ;MAKE SURE THE COUNT IS ZERO
|
||
PUSHJ P,NTDSTP## ;STOP IF COUNT IS WRONG W.R.T. QUEUES
|
||
KDPON ;RE-ENABLE INTERRUPTS
|
||
POPJ P, ; AND WE ARE DONE
|
||
SUBTTL ERROR ROUTINES
|
||
|
||
;KDPERR - CALLED WHEN A KDP IS HOPELESSLY ILL.
|
||
;CALL JSP T1,KDPERR ;T1 CONTAINS CALLERS PC FOR DEBUGGING
|
||
;RETURN CPOPJ ; USUALLY TO CALLER'S CALLER
|
||
|
||
KDPERR: MOVEM T1,KDPCPC(W) ;SAVE THE CALLER'S PC
|
||
MOVE U,OPRLDB## ;WE HAD BETTER TELL SOMEONE ABOUT THIS...
|
||
PUSHJ P,INLMES## ;SEND THE OPERATOR A MESSAGE
|
||
ASCIZ /%% Fatal KMC-11 error on /
|
||
PUSHJ P,PRKDP ;TELL HIM WHICH KDP IT WAS.
|
||
PUSHJ P,INLMES## ;TELL HIM WHO NOTICED
|
||
ASCIZ /, called/
|
||
MOVE T2,KDPCPC(W) ;GET THE CALLER'S PC BACK
|
||
SOS T2 ; BACK IT UP 1 LOCATION
|
||
PUSHJ P,PCP## ; AND PRINT IT AS A "PC"
|
||
PUSHJ P,INLMES## ;FINISH OFF THE MESSAGE
|
||
ASCIZ / KMC-11 Halted.
|
||
/
|
||
|
||
PUSHJ P,KDPHLT ;STOP IT (CLEAR RUN)
|
||
MOVSI T1,(DF.RQK) ;NOW REQUEST THAT KDPLDR
|
||
IORM T1,DEBUGF## ; ON THE NEXT CLOCK TICK
|
||
POPJ P, ;RETURN (LET SOME ONE ELSE CLEAN UP...)
|
||
;KDLERR - ROUTINE CALLED WHEN AN EVENT FATAL TO ONLY ONE LINE OCCURS
|
||
;CALL PJSP T1,KDLERR ;T1 HAS CALLER'S PC
|
||
;RETURN POPJ P, ;USUALLY TO CALLER'S CALLER
|
||
|
||
KDLERR: MOVEM T1,KDLCPC(F) ;REMEMBER THE CALLERS PC
|
||
MOVE U,OPRLDB## ;GET THE OPER'S TTY POINTER
|
||
PUSHJ P,INLMES## ;TELL HIM THE BAD NEWS
|
||
ASCIZ /%% Fatal error on /
|
||
PUSHJ P,PRKDL ;TELL HIM WHICH LINE.
|
||
PUSHJ P,INLMES##
|
||
ASCIZ /, called/
|
||
MOVE T2,KDLCPC(F) ;GET THE CALLER'S PC BACK
|
||
SOS T2 ;BACK IT UP TO THE POINT OF CALL
|
||
PUSHJ P,PCP## ;PRINT THE PC
|
||
PUSHJ P,INLMES## ;FINISH OFF
|
||
ASCIZ / Line shut down.
|
||
/
|
||
|
||
;NOW SHUT DOWN THE LINE
|
||
|
||
PUSHJ P,KDLFLS ;START THE BUFFERS FLUSHING
|
||
|
||
MOVE T1,KDLMAP(F) ;GET THE FIRST MAP LOCATION
|
||
MOVEI T2,KDLPPL ;PAGES PER LINE
|
||
SETZ T3, ;A ZERO TO ZAP THE MAP WITH
|
||
SOJGE T2,[WRIO T3,(T1);ZAP THE PAGE
|
||
AOJA T1,.] ;AND LOOP OVER THEM ALL
|
||
|
||
PUSHJ P,KDLPDN ;TELL THE DRIVER HIS LINE IS DOWN
|
||
PJRST CLBFRS ;CLEAR THE BUFFER USE BITS AND RETURN
|
||
;KDLFLS ROUTINE TO SET THE "FLUSH IN PROGRESS" BITS, GO TO "FLUSH" STATE
|
||
; AND QUEUE FLUSH TRANSACTIONS TO THE KMC-11
|
||
KDLFLS: MOVEI T1,KD%FLS ;GET THE "FLUSHING BUFFERS" STATE
|
||
DPB T1,KDLSTA## ; AND USE SET OUR STATE TO THAT
|
||
MOVEI T1,KDSXFL!KDSRFL;GET THE "FLUSH IN PROGRESS BITS"
|
||
IORM T1,KDLSTS(F) ; AND SET THEM IN THE STATUS WORD
|
||
HRRZ T1,KDLINE(F) ;GET OUR LINE NUMBER
|
||
LSH T1,10 ; AND PUT IT IN BSEL3
|
||
MOVEI T2,BFRKIL ;GET THE KILL BIT (LEAVE BDL ADDR = 0)
|
||
MOVE W,KDLKDP(F) ;JUST MAKE SURE "W" IS SET UP
|
||
PUSHJ P,KMCINU ;MASSACRE THE OUTPUT BUFFERS
|
||
PJSP T1,KDPERR ;?? KMC-11 CRASHED WHILE WE WEREN'T LOOKING ??
|
||
IORI T1,KMCIOT ;SET "INPUT" BUFFER BIT
|
||
PUSHJ P,KMCINU ;MURDER ALL THE INPUT BUFFERS AS WELL.
|
||
PJSP T1,KDPERR ;?? "" ??
|
||
POPJ P, ;ALL DONE
|
||
;KDPHLT - ROUTINE TO CRASH A KMC-11 (KDP) WHEN SOMETHING IS DRASTICALLY
|
||
; WRONG.
|
||
|
||
KDPHLT: PUSHJ P,SAVE1## ;WE USE 1 P
|
||
MOVEI T1,KMCMCL ;GET THE MASTER CLEAR BIT
|
||
WRIO T1,@KDPCSR(W) ;CLEAR RUN, SET MASTER CLEAR. (DIE DIE DIE...)
|
||
|
||
MOVSI T1,(KDPSRU) ;GET MICROCODE RUNNING BIT
|
||
ANDCAM T1,KDPSTS(W) ;AND CLEAR IT SO WE WON'T TRY TO RESTART
|
||
|
||
MOVE T2,KDPCSR(W) ;GET ADDRESS OF THE KMC-11 CSR'S
|
||
MOVE T3,[POINT 18,KDPRGS(W)] ;GET A BYTE POINTER TO "CRASH REGS"
|
||
MOVEI T1,4 ;GET COUNT OF REGISTERS TO READ
|
||
|
||
KDPHL1: RDIO S,(T2) ;GET KMC-11 REGISTER
|
||
IDPB S,T3 ; AND STORE IT IN THE KDP BLOCK FOR DEBUGGING
|
||
ADDI T2,2 ;GO TO THE NEXT -11 WORD
|
||
SOJG T1,KDPHL1 ;LOOP OVER ALL REGISTERS
|
||
|
||
;NOW CLEAR THE "VOLITILE" PART OF THE KDP BLOCK
|
||
|
||
HRLI T1,KDPZER(W) ;GET ADDR OF FIRST WORD TO ZERO
|
||
HRRI T1,KDPZER+1(W) ;GET ADDRESS OFF THE SECOND
|
||
SETZM KDPZER(W) ;CLEAR THE FIRST WORD
|
||
BLT T1,KDPLEN-1(W) ;CLEAR THE REST
|
||
|
||
;NOW DECLARE ALL LINES ASSOCIATED WITH THIS KDP AS CRASHED.
|
||
|
||
MOVE P1,KDPDPN(W) ;GET A COUNT OF THE NUMBER OF DUP-11 ATTACHED
|
||
KDPHL2: SOJL P1,CPOPJ## ;COUNT DOWN EACH DUP-11 PROCESSED
|
||
|
||
MOVE T1,P1 ;GET OUR LINE NUMBER
|
||
IMULI T1,KDLPPL ; TIMES NUMBER OF PAGES PER LINE
|
||
ADD T1,KDPIMR(W) ; RELOCATE TO THE FIRST PAGE
|
||
MOVEI T2,KDLPPL ;GET THE NUMBER OF PAGES TO CLEAR
|
||
SETZ T3, ;GET A ZERO
|
||
SOJGE T2,[WRIO T3,(T1);ZERO THE NEXT WORD
|
||
AOJA T1,.] ;AND LOOP OVER ALL PAGES FOR THIS LINE
|
||
|
||
MOVEI F,(P1) ;COPY OFFSET INTO LINE TABLE
|
||
ADDI F,KDPKDL(W) ;RELOCATE OFFSET TO LINE TABLE
|
||
SKIPN F,(F) ;LOAD ADDRESS OF KDL BLOCK
|
||
JRST KDPHL2 ;ONCE SAID THERE WASN'T ONE, LOOP OVER REST
|
||
|
||
LDB T1,KDLSTA## ;GET THE STATE OF THIS LINE
|
||
MOVEI T2,KD%DWN ;GET THE "DOWN" STATE
|
||
DPB T2,KDLSTA## ; AND MARK THIS LINE AS HOPELESS
|
||
CAILE T1,KD%FLS ;WAS LINE "ALIVE"
|
||
PUSHJ P,KDLPDN ; IF IT WAS UP, REQUEUE PCB'S AND CALL NETSER
|
||
|
||
JRST KDPHL2 ;LOOP OVER ALL LINES
|
||
SUBTTL PROTOCOL CONTROL SUBROUTINES
|
||
|
||
;KDLPUP - ROUTINE TO TELL OUR DRIVER THAT PROTOCOL IS UP
|
||
|
||
KDLPUP: PUSH P,T4 ;CALLER EXPECTS US TO SAVE T4
|
||
MOVEI T1,DC.IPU ;GET THE PROTOCOL "UP" FUNCTION
|
||
PUSHJ P,CALDVR ; AND TELL THE DRIVER THE GOOD NEWS
|
||
POP P,T4 ;RESTORE CALLER'S T4
|
||
POPJ P, ;AND WE'RE DONE
|
||
|
||
|
||
;KDLPDN - ROUTINE TO RETURN ALL UNSENT BFR'S AND THEN DECLARE THE
|
||
; LINE DOWN
|
||
; HERE EITHER FROM CLOCK LEVEL (TIMED OUT), OR FROM RECEIVE
|
||
; INTERRUPT LEVEL (MAINT/START MSG), OR CONTROLLER REQUEST
|
||
; FROM A DRIVER (ROUTER KF.IN OR KF.HA)
|
||
|
||
KDLPDN: PUSHJ P,KDLPD0 ;EMPTY THE QUEUES FIRST
|
||
;HERE WHEN WE'VE RETURNED ALL THE MESSAGES. DECLARE PROTOCOL DOWN
|
||
MOVEI T1,DC.IPD ;GET THE "PROTOCOL DOWN" FUNCTION
|
||
PUSHJ P,CALDVR ;TELL THE DRIVER THE BAD NEWS
|
||
PUSHJ P,CLCTRS ;CLEAR THE DDCMP MESSAGE NUMBER COUNTERS
|
||
POPJ P, ;AND WE'RE DONE
|
||
|
||
|
||
KDLPD0: KDPOFF ;NO INTERRUPTS WHILE HACKING QUEUES
|
||
HRRZ T3,KDLWTA(F) ;GET THE FIRST BFR ON THE WTA QUEUE
|
||
JUMPE T3,KDLPD1 ;IF QUEUE IS EMPTY, TRY WTO
|
||
HRRZ T2,MB.NXT(T3) ;GET THE "NEXT" BFR ON THE QUEUE
|
||
HRRZM T2,KDLWTA(F) ; AND MAKE IT THE FIRST
|
||
SOSGE KDLCTA(F) ;COUNT DOWN ONE LESS WTA BFR
|
||
PUSHJ P,NTDSTP## ;IF IT WENT NEGATIVE, DUMP IT.
|
||
JRST KDLPD2 ;GO RETURN THE BUFFER
|
||
|
||
;HERE IF THE WTA QUEUE IS EMPTY, TRY WTO
|
||
KDLPD1: SKIPE KDLCTA(F) ;MAKE SURE THE WTA QUEUE COUNTED OUT RIGHT
|
||
PUSHJ P,NTDSTP## ;STOP IF COUNT AND QUEUE DON'T AGREE
|
||
HRRZ T3,KDLWTO(F) ;GET THE FIRST BFR ON THE WTO QUEUE
|
||
JUMPE T3,KDLPD3 ;IF NONE, WE'VE RETURNED ALL THE BFRS
|
||
HRRZ T2,MB.NXT(T3) ;GET THE "SECOND" BUFFER ON THE WTO QUEUE
|
||
HRRZM T2,KDLWTO(F) ;AND MAKE IT THE FIRST BUFFER
|
||
|
||
;HERE TO RETURN A MESSAGE AS "OUTPUT NOT DONE"
|
||
KDLPD2: KDPON ;WE'VE GOT OUR BFR, RE-ENABLE INTERRUPTS
|
||
MOVEI T1,DC.IOF ;GET THE "OUTPUT NOT DONE" FUNCTION
|
||
PUSHJ P,CALDVR ;AND TELL OUR DRIVER THE NEWS
|
||
JRST KDLPD0 ;LOOP TILL WE HAVE RETURNED ALL BFRS
|
||
|
||
KDLPD3: KDPON ;RE-ENABLE INTERRUPTS
|
||
POPJ P, ;AND RETURN
|
||
;KDLINI - ROUTINE TO INITIALIZE A KDL-PAGE
|
||
;CALL MOVX F,KDL-BLOCK ADDRESS
|
||
; PUSHJ P,KDLINI ;FROM CLOCK OR UUO LEVEL
|
||
;RETURN POPJ P, ;ALWAYS
|
||
; THIS ROUTINE RE-BUILDS A KDL BLOCK. IN PARTICULAR IT:
|
||
; A) SETS UP ALL IMPORTANT "STATIC" LOCATIONS IN THE KDL PAGE
|
||
; B) MAPS THE KDL PAGE SO AS TO MAKE IT ACCESSIBLE TO THE KMC-11
|
||
; C) QUEUES THE BASE IN AND CONTROL IN TRANSACTIONS NECESSARY
|
||
; TO LET THE LINE SEND AND RECEIVE MSGS
|
||
|
||
KDLINI: MOVEI T1,KDPMAX## ;FIRST FIND THE KDP THAT OWNS THIS KDL
|
||
KDLIN1: SKIPGE T1 ;IF WE COULDN'T FIND ONE
|
||
PUSHJ P,NTDSTP## ; THEN A DRIVER GAVE US A BAD KDL ADDRESS
|
||
HRRZ W,KDPTBL##(T1) ;ASSUME THAT THIS IS THE RIGHT KDP
|
||
HRRZ T2,KDPDPN(W) ;GET THE NUMBER OF DUPS ON THIS ONE
|
||
MOVEI T3,KDPKDL(W) ;GET THE ADDRESS OF THE DUP TABLE
|
||
KDLIN2: SOJL T2,[SOJA T1,KDLIN1] ;IF NO MORE DUPS, DO NEXT KDP
|
||
HRRZ T4,(T3) ;GET THE RH OF THE NEXT ENTRY
|
||
CAIE T4,(F) ;SEE IF THIS IS THE ONE
|
||
AOJA T3,KDLIN2 ;IF NOT, KEEP LOOKING
|
||
|
||
SETZM KDLFZR(F) ;START CLEARING AFTER THE BLOCK POINTERS
|
||
HRLI T3,KDLFZR(F) ;FIRST HALF OF "BLT" POINTER
|
||
HRRI T3,KDLFZR+1(F) ;SECOND HALF OF "BLT" POINTER
|
||
BLT T3,KDLLEN-1(F) ;CLEAR THE BLOCK
|
||
|
||
HRRZM W,KDLKDP(F) ;STORE THE KDP ADDRESS
|
||
|
||
MOVE T1,KDPDPN(W) ;GET THE NUMBER OF DUPS ON THIS KMC
|
||
SUBI T1,1(T2) ;GET THE NUMBER OF THIS ONE
|
||
MOVEM T1,KDLINE(F) ;GET OUR LINE NUMBER
|
||
IMULI T1,KDLPPL ;OFFSET BY THE NUMBER OF PAGES PER LINE
|
||
ADD T1,KDPIMR(W) ;CALCULATE OUR MAP REGISTER'S ADDRESS
|
||
MOVEM T1,KDLMAP(F) ;STORE THE MAP REGISTER'S ADDRESS
|
||
|
||
MOVEI T1,KDPKDL(W) ;GET ADDR OF FEK TO KDL CORRISPONDENCE TBL
|
||
ADD T1,KDLINE(F) ; THAT LIVES IN THE KDP BLOCK
|
||
HLRZ T1,(T1) ;GET OUR FEK ADDRESS (IF RUNNING ANF)
|
||
MOVEM T1,KDLFEK(F) ; AND STORE THAT
|
||
|
||
MOVEI T1,M.DN60## ;SEE IF DN60 WAS LOADED
|
||
JUMPE T1,KDLIN3 ; IF NOT, THEN THERE IS NO DLX FOR THIS LINE
|
||
MOVE T1,KDLINE(F) ;IF THERE IS A DLX, GET THE LINE NUMBER
|
||
MOVE T1,KDPBAS##(T1) ; AND FROM THAT, THE DLX TABLE ADDRESS
|
||
KDLIN3: MOVEM T1,KDLDLX(F) ;AND STORE A POINTER TO THE DLX BLOCK
|
||
MOVE T1,KDLINE(F) ;GET OUR LINE NUMBER BACK
|
||
IMULI T1,KDLPPL ;MULTIPLY BY THE NUMBER OF PAGES PER LINK
|
||
LSH T1,^D11 ;CONVERT PAGE OFFSET TO BYTE OFFSET
|
||
ADD T1,KDPIEA(W) ;CALCULATE OUR PAGE ADDRESS
|
||
MOVEM T1,KDLADR(F) ;STORE OUR PAGE'S -11 ADDRESS
|
||
|
||
MOVE T1,KDLINE(F) ;GET OUR DUP-11'S NUMBER AGAIN
|
||
LSH T1,3 ;MULTIPLY BY THE SIZE OF A DUP-11 (IE. 8)
|
||
ADD T1,KDP1DP(W) ;RELOCATE BY ADDRESS OF THE FIRST DUP-11
|
||
MOVEM T1,KDLCSR(F) ;STORE OUR CSR ADDRESS (FOR BASE IN)
|
||
|
||
;KDL PAGE NOW INITIALIZED. TIME TO SET UP THE MAP.
|
||
|
||
MAP T1,(F) ;GET THE PHYSICAL ADDRESS OF THE KDL PAGE.
|
||
AND T1,[XWD 17,-1] ;GET JUST THE ADDRESS
|
||
LSH T1,W2PLSH## ;CHANGE ADDRESS TO PAGE NUMBER
|
||
IORI T1,UNBVBT!UNBD18;VALID & 18 BIT DISABLE
|
||
MOVEI T2,KDLPPL ;GET A COUNT OF THE NUMBER OF PAGES PER LINE
|
||
MOVE T3,KDLMAP(F) ;GET THE ADDRESS OF THE MAP
|
||
SOJGE T2,[WRIO T1,(T3);WRITE THE PAGE REGISTER
|
||
AOS T1 ;GET READY TO WRITE THE NEXT ONE
|
||
AOJA T3,.] ;LOOP OVER ALL REGISTERS
|
||
|
||
HRRZ T1,KDLINE(F) ;GET LINE NUMBER FOR "BASE IN"
|
||
LSH T1,10 ;SHIFT INTO UPPER BYTE
|
||
IORI T1,BASEIN ;SET THE FUNCTION CODE
|
||
HRRZ T2,KDLCSR(F) ;GET THE DUP-11'S CSR ADDRESS (-11 MEMORY)
|
||
ANDI T2,17777 ; BUT ONLY USE LOW 13 BITS OF IT.
|
||
PUSHJ P,KMCINU ;QUEUE BASE-IN TRANSACTION
|
||
JSP T1,KDPERR ;?? KMC-11 CRASHED ?? GIVE KMC NOT RUNNING ??
|
||
|
||
TRZ T1,2 ;CHANGE BASE-IN FUNCTION TO CONTROL-IN (UGLY)
|
||
MOVEI T2,CDDCMP!CENABL;SET POLLING = 0, DDCMP MODE, AND ENABLE
|
||
PUSHJ P,KMCINU ;QUEUE THE CONTROL-IN TRANSACTION
|
||
JSP T1,KDPERR ;?? KMC-11 CRASHED ?? GIVE KMC NOT RUNNING ??
|
||
POPJ P, ;KDL HAS BEEN INITIALIZED
|
||
;CALDVR ROUTINE TO CALL THIS LINE'S DRIVER
|
||
;CALL F := POINTER TO A KDL
|
||
; SETS UP T2 := DRIVER'S BLOCK ADDRESS
|
||
; AND DISPATCHES TO THE DRIVER ROUTINE
|
||
;DON'T PRESERVE F/W SINCE OUR DRIVER SHOULDN'T CLOBBER THEM!
|
||
|
||
DEFINE X(TYP,CON,DAT,ADR),<
|
||
IFN .-CALDV0-<2*DD.'TYP>,<
|
||
PRINTX ? CALDVR vector dispatch phase error for TYP user>
|
||
IFE CON,<
|
||
PUSHJ P,NTDSTP## ;;DIE IF NO DRIVER SUPPORTED
|
||
HALT .> ;;FILLER FOR TWO-WORD VECTOR
|
||
IFN CON,<
|
||
MOVE T2,DAT(F) ;;GET "DRIVER" DATA BLOCK ADDRESS
|
||
PJRST ADR> ;;AND GO TO APPROPRIATE DRIVER
|
||
> ;END DEFINE X
|
||
|
||
CALDVR: PUSHJ P,SAVR## ;DECnet USES R AS A TRASH AC.
|
||
HRRZ T2,KDLUSR(F) ;GET THE USER CODE
|
||
CAILE T2,DD.MAX ; AND RANGE CHECK IT
|
||
PUSHJ P,NTDSTP## ;++ ILLEGAL USER CODE
|
||
LSH T2,1 ;TRANSLATE INTO TWO-WORD BLOCK OFFSET
|
||
PJRST .+1(T2) ;DISPATCH BASED ON "USER" TYPE
|
||
|
||
CALDV0: X (NOBODY,1,0,NOBDSP##)
|
||
CALDV1: X (ANF10,FTNET,KDLFEK,D8KK2D##)
|
||
CALDV2: X (DECNET,FTDECN,KDLLBK,CALPPI)
|
||
CALDV3: X (PROGRAM,1,KDLDDB,KDPIDS##)
|
||
CALDV4: X (IBMCOMM,1,KDLDLX,D6KK2D##)
|
||
|
||
IFN .-CALDV0-<2*<DD.MAX+1>>,<
|
||
PRINTX ? CALDVR vector dispatch entry missing>
|
||
|
||
IFN FTDECN,<
|
||
CALPPI: DNCALL KDIPPI## ;CALL DECNET IN DECNET CONTEXT
|
||
POPJ P, ;AND RETURN
|
||
PJRST CPOPJ1## ;...
|
||
>; END IFN FTDECN
|
||
;CLCTRS CLEAR THE VARIOUS COUNTERS ASSOCIATED WITH A LINE
|
||
CLCTRS: SETZ T1, ;GET A ZERO
|
||
DPB T1,KDLTIM## ;CLEAR THE TIMER
|
||
DPB T1,KDLRMN## ;CLEAR THE RECEIVE MESSAGE NUMBER
|
||
DPB T1,KDLLMX## ;CLEAR LAST MESSAGE SENT
|
||
DPB T1,KDLLMA## ;CLEAR LAST MESSAGE ACKED
|
||
DPB T1,KDLRPC## ;CLEAR THE REP COUNTER
|
||
POPJ P,
|
||
|
||
|
||
;CLBFRS ROUTINE TO SET ALL BUFFERS TO "EMPTY". USED WHEN GOING INTO
|
||
; MAINT MODE.
|
||
CLBFRS: MOVEI T1,KDSNRB!KDSNXB!KDSRFL!KDSXFL ;STATUS BITS TO CLEAR
|
||
ANDCAM T1,KDLSTS(F) ;MAKE SURE NEXT BUFFER IS FIRST BUFFER.
|
||
HRLI T1,KDLXBC(F) ;START ZEROING HERE
|
||
HRRI T1,KDLXBC+1(F) ; ...
|
||
SETZM KDLXBC(F) ;WRITE THE "SEED" ZERO
|
||
BLT T1,KDLLEN-1(F) ; AND ZAP THE REST OF THE BLOCK
|
||
POPJ P, ;RETURN WITH ALL BUFFERS AND USE BITS CLEAR
|
||
;STPTMR ROUTINE TO STOP THE DDCMP TIMER
|
||
|
||
STPTMR: SETO T1, ;STOP TIMER
|
||
HRRZ T2,KDLUSR(F) ;CHECK FOR ANF CROCK
|
||
CAIN T2,DD.ANF ;BECAUSE IT WANTS TO
|
||
SETZ T1, ;IDLE REPS, SO WE JUST RESTART TIMER
|
||
DPB T1,KDLTIM## ;WHATEVER
|
||
POPJ P,
|
||
|
||
|
||
;ZRCTRS - ROUTINE TO ZERO THE COUNTER SECTION OF THE KDL BLOCK
|
||
;CALL MOVX F,KDL-BLOCK ADDRESS
|
||
; PUSHJ P,ZRCTRS
|
||
;RETURN CPOPJ ;ALWAYS
|
||
|
||
ZRCTRS: HRLI T1,KDLZER(F) ;NOW ZERO COUNTER SECTION OF THE KDL (RESTART)
|
||
HRRI T1,KDLZER+1(F) ;GET ADDRESS OF SECOND WORD ...
|
||
SETZM KDLZER(F) ;CLEAR THE FIRST ONE
|
||
BLT T1,KDLLEN-1(F) ;CLEAR THE REST
|
||
POPJ P, ;AND WE'RE DONE
|
||
SUBTTL PRINT ROUTINES
|
||
|
||
;PRKDP - ROUTINE TO PRINT OUT "KDP #?"
|
||
|
||
PRKDP: PUSHJ P,INLMES## ;PRINT OUT THE ASCII PART
|
||
ASCIZ /KDP #/
|
||
MOVE T1,KDPNUM(W) ;GET THE KDP'S NUMBER
|
||
PJRST PRTDIG## ; AND PRINT THAT
|
||
|
||
;PRKDL - ROUTINE TO PRINT "KDP #?, KDL #?"
|
||
|
||
PRKDL: PUSHJ P,PRKDP ;PRINT OUT THE FIRST PART
|
||
PUSHJ P,INLMES## ;PRINT OUT THE ", KDL #"
|
||
ASCIZ /, KDL #/
|
||
MOVE T1,KDLINE(F) ;GET OUR DUP-11 LINE NUMBER
|
||
PJRST PRTDIG## ; AND PRINT THAT.
|
||
|
||
|
||
|
||
|
||
|
||
;ROUTINE TO SAVE F & W FOR THE KDP??? ROUTINES
|
||
|
||
SAVEFW: EXCH F,(P) ;SAVE F, GET PC
|
||
PUSH P,W ;SAVE W
|
||
PUSH P,S ;SAVE S TOO...
|
||
MOVEM F,1(P) ;PUT PC IN A "SAFE" PLACE
|
||
MOVE F,-2(P) ;GET F BACK
|
||
PUSHJ P,@1(P) ;CALL CALLER BACK.
|
||
SKIPA ;NON SKIP RETURN
|
||
AOS -3(P) ;PROPAGATE THE SKIP RETURN
|
||
POP P,S ;GET S BACK
|
||
POP P,W ;RESTORE W
|
||
POP P,F ;RESTORE F
|
||
POPJ P, ;RETURN
|
||
;ROUTINES TO DO "CANONICAL" BYTE POINTER MANIPULATION
|
||
;BECAUSE THE BYTES TO/FROM THE UBA ARE SWAPPED NORMAL PDP-10 BYTE
|
||
; INSTRUCTIONS DON'T WORK. HENCE THE "CANONICAL" -11 BYTE POINTER
|
||
; AND THESE ROUTINES.
|
||
;THE FORMAT OF THE BYTE POINTER IS:
|
||
;
|
||
; XWD BYTE-POS,ADDR
|
||
;
|
||
;WHERE
|
||
;
|
||
; BYTE-POS = {0, 1, 2, 3} ;THE POSITION OF THE BYTE IN THE -10 WORD
|
||
; ADDR = THE 10 ADDRESS OF THE WHOLE WORD
|
||
;
|
||
|
||
;HERE IS A TABLE OF BYTE POINTERS TO THE FOUR -11 BYTES IN A -10 WORD
|
||
|
||
BYTABL: POINT 8,(T4),17 ;FIRST BYTE
|
||
POINT 8,(T4),9 ;SECOND BYTE
|
||
POINT 8,(T4),35 ;THIRD BYTE
|
||
POINT 8,(T4),27 ;FOURTH BYTE
|
||
POINT 8,1(T4),17 ;FIFTH BYTE
|
||
POINT 8,1(T4),9 ;SIXTH BYTE
|
||
POINT 8,1(T4),35 ;SEVENTH BYTE
|
||
POINT 8,1(T4),27 ;EIGHTH BYTE
|
||
;IDPCB - ROUTINE TO INCREMENT AND DEPOSITE CANONICAL BYTE
|
||
;CALL MOVEI S,BYTE ;THE BYTE TO STORE
|
||
; MOVE T4,BP ;A CANONICAL BYTE POINTER AS ABOVE
|
||
; PUSHJ P,IDPCB ;DO THE DEPOSIT BYTE FUNCTION
|
||
;
|
||
;CLOBBERS NO REGISTERS
|
||
|
||
IDPCB: PUSH P,T1 ;GET A TEMP
|
||
HLRZ T1,T4 ;GET THE POSITION FIELD
|
||
AOS T1 ;INCREMENT THE POSITION
|
||
CAIL T1,4 ;SEE IF WE HAVE GONE TO NEXT WORD YET
|
||
JRST [AOS T4 ;IF NEXT WORD, INCREMENT ADDRESS
|
||
SETZ T1, ; AND SET BYTE POSITION TO ZERO
|
||
JRST .+1] ;BACK TO MAIN FLOW
|
||
HRLM T1,T4 ;PUT THE UPDATED POSITION BACK
|
||
DPB S,BYTABL(T1) ;STORE THE BYTE
|
||
POP P,T1 ;RESTORE T1
|
||
POPJ P, ;RETURN (NOT "JRST TPOPJ" TO SAVE TIME)
|
||
|
||
|
||
;ILDCB - ROUTINE TO INCREMENT AND LOAD CANONICAL BYTE
|
||
;CALL MOVE T4,BP ;A CANONICAL BYTE POINTER AS ABOVE
|
||
; PUSHJ P,IDPCB ;DO THE DEPOSIT BYTE FUNCTION
|
||
;RETURN CPOPJ ; S := REQUESTED BYTE
|
||
;CLOBBERS NO REGISTERS (EXCEPT S)
|
||
|
||
ILDCB: PUSH P,T1 ;GET A TEMP
|
||
HLRZ T1,T4 ;GET THE POSITION FIELD
|
||
AOS T1 ;INCREMENT THE POSITION
|
||
CAIL T1,4 ;SEE IF WE HAVE GONE TO NEXT WORD YET
|
||
JRST [AOS T4 ;IF NEXT WORD, INCREMENT ADDRESS
|
||
SETZ T1, ; AND SET BYTE POSITION TO ZERO
|
||
JRST .+1] ;BACK TO MAIN FLOW
|
||
HRLM T1,T4 ;PUT THE UPDATED POSITION BACK
|
||
LDB S,BYTABL(T1) ;FETCH THE BYTE
|
||
POP P,T1 ;RESTORE T1
|
||
POPJ P, ;RETURN (NOT "JRST TPOPJ" TO SAVE TIME)
|
||
|
||
;DLDCB - ROUTINE TO DECREMENT AND LOAD CANONICAL BYTE
|
||
;CALL MOVE T4,BP ;A CANONICAL BYTE POINTER
|
||
; PUSHJ P,DLDCB ;DECREMENT AND LOAD BYTE
|
||
;RETURN CPOPJ ;WITH S := THE BYTE
|
||
;
|
||
;CLOBBERS NO REGISTERS (EXCEPT "S" OF COURSE)
|
||
|
||
DLDCB: HLRZ S,T4 ;GET THE BYTE "POSITION"
|
||
SOJL S,[SOS T4 ;DECREMENT POSITION AND ADDR IF NECESSARY
|
||
MOVEI S,3 ;IF BACKING UP, SET BP TO 4TH BYTE
|
||
JRST .+1] ;BACK TO MAIN STREAM
|
||
HRLM S,T4 ;PUT THE "POSITION" BACK IN THE BP
|
||
ADDI S,BYTABL ;INDEXING DOESN'T WORK FOR "S"
|
||
LDB S,@S ;GET THE REQUESTED BYTE
|
||
POPJ P, ;RETURN
|
||
; XLIST
|
||
; $LIT ;DON'T LIST LITERALS
|
||
LIST
|
||
KDPEND::END
|