;;; -*- Mode:MIDAS -*- ;;; Copyright (c) 1999 Massachusetts Institute of Technology ;;; ;;; This program is free software; you can redistribute it and/or ;;; modify it under the terms of the GNU General Public License as ;;; published by the Free Software Foundation; either version 3 of the ;;; License, or (at your option) any later version. ;;; ;;; This program is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program; if not, write to the Free Software ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. IMPVRS==.IFNM2 ; Version of IMP code IFN NCPP,.FATAL IMP Code doesn't support NCP any more! IFNDEF IMPDBG,IMPDBG==:0 ;Random bits of debugging code IFN IMPDBG,PRINTX /IMP Debugging code included / IFN KAIMP,[ $INSRT KAIMP ];KAIMP IFN KSIMP,[ $INSRT LHDH IMPLW==400000 ;Bit unused by hardware ];IFN KSIMP ; IMP 1822 PROTOCOL INFORMATION (EXTENDED-LEADER VERSION) ; The IMP leader is 96 bits long, usually organized as 3 words of 32 bits. ; For further details, these documents are available from the Network ; Information Center: ; IMP-HOST protocol: BBN Report No. 1822 ; NCP protocol: NIC 8246, Host-to-Host Protocol for the ARPANET ; IP, TCP: Internet Protocol Transition Workbook, and ; Internet Protocol Implementor's Guide ; ; Here is the leader format used by the IMP code. This format uses ; no IMP padding, assumes IP only, and expects all IMP<->HOST data ; transfers in 32-bit mode. ; ; Previous versions of this code which supported NCP used a much more ; complicated leader formatting scheme based on 36 bit transfers and ; IMP padding. That scheme is dead, see SYSTEM;IMPOLD WTHNCP for details. ; ; All data from the IMP interface ends up in the -10 as left-justified ; 32-bit words. Objects of less than 32 bits length, such as IP octets, ; are stored in PDP10 ILDB byte order. ; ;------------------------------------------------------------------------ ;1: 4.9-4.6 not used (0) ; 4.5-4.2 all 1's for new format, else old msg type (4=old nop) ; 4.1-3.3 network number (0) ; 3.2-2.8 not used (0) ; 2.7 trace (ignored) ; 2.6-2.4 leader flags (2.6 is to be ignored, 2.5-2.4 are not used!) ; 2.3-1.5 message type ; ;2: 4.9-4.2 Handling type (7 for big buffers, 4 for small buffers, ; 0 for the control link) ; 4.1-3.3 Host number on IMP ; 3.2-1.5 IMP number ; ;3: 4.9-4.2 Link Number (High 8 bits of Message ID) ; 4.1-3.7 Low 4 bits of Message ID (0) ; 3.6-3.3 Sub-type ; 3.2-1.5 Message length ;------------------------------------------------------------------------ ;4: 4.9-1.5 First word of IP datagram ; .... ;------------------------------------------------------------------------ ; ;In message types 2 and 6, the going-down status 16-bit word is ;in word 3 bits 4.9-3.3. ;3.6-3.3 of word 3 are the padding count for type 4 (nop) from host. ;This is currently 0 (none). Padding is only put on type-0 messages. IMOTBP: 340400,,IMPILB+0 ;BYTE POINTER FOR MESSAGE FORMAT TYPE IMTBP: 041000,,IMPILB+0 ;BYTE POINTER FOR MESSAGE TYPE FIELD IMSABP: 043000,,IMPILB+1 ;BYTE POINTER FOR SOURCE ADDR FIELD (HOST+IMP) IMSHBP: 241000,,IMPILB+1 ;BYTE POINTER FOR SOURCE HOST FIELD IMSIBP: 042000,,IMPILB+1 ;BYTE POINTER FOR SOURCE IMP FIELD IMLNBP: 341000,,IMPILB+2 ;BYTE POINTER FOR LINK NUMBER FIELD IMSTBP: 240400,,IMPILB+2 ;BYTE POINTER FOR SUBTYPE FIELD IMMLBP: 042000,,IMPILB+2 ;BYTE POINTER FOR MESSAGE LENGTH FIELD SUBTTL ARPANET VARIABLES AND TABLES EBLK IMPN:: ;IMP DATA AREA CLEARED WHEN IMPUP %IMXLN==:<<8159.-96.>+31.>/32. ; Max # of 32-bit words in IMP regular msg, ; exclusive of leader and leader padding. = 252. IMPIBS: 0 ; Saved initial BLKI pointer for IP datagram read IMPIDP: 0 ; Pointer to IP datagram being input at PI level IMPODP: 0 ; Pointer to IP datagram being output at PI level IFN KAIMP,[ IMPI: 0 ;-1 => IMPCHN INPUT INTERRUPT OCCURRED IMPO: 0 ;-1 => IMPCHN OUTPUT INTERRUPT OCCURRED IMPB: 0 ;-1 => IMPCHN FLAG INTERRUPT OCCURRED IMPIH: 0 ;-1 => INPUT WANTS PIA = IMPCHN IMPOH: 0 ;-1 => OUTPUT WANTS PIA = IMPCHN ] IFN KSIMP,[ IMPIEC: 0 ;Count of input errors while down. ] IMPIS: 0 ;INPUT STATE %ISIDN==:-1 ; Network shut off %ISIDL==:0 ; Normal - idle, not expecting input (i.e. between msgs) %ISIGN==:1 ; Ignore input until end of current message (32 bit mode) %ISIML==:2 ; Reading IMP initial leader (32 bit mode) %ISIID==:3 ; Reading IP datagram (32 bit mode) IMPOS: 0 ;OUTPUT STATE %ISODL==:0 ; Not expecting output done (i.e. between messages) %ISONP==:1 ; Sending NOP %ISOID==:2 ; Sending IP Datagram %ISOIL==:3 ; Sending IMP leader ; ACTIVE HOST TABLE. Entries herein are allocated as needed, using garbage ; collection. Most "host number" fields are really indices into this table. ; LIMPHT== ; TCP conns plus a few extra IMPHTN: BLOCK LIMPHT ; Host number. 1.1-1.8 HOST, 2.1-3.7 IMP IMPHTB: BLOCK LIMPHT ;Bits: ;4.9 UNUSED ;4.8 GC MARK BIT ;4.7-4.3 UNUSED ;4.2-4.1 STATUS OF HOST 0 DOWN, 1 RST SENT, 2 UP ;3.9-3.1 UNUSED .SEE IMPHDS ;RH Last message from IMP about "host dead status" IMPHTC: BLOCK LIMPHT ; # active messages outstanding for host (8 max) IMPHTT: BLOCK LIMPHT ; Time of last RFNM received LIMPN==.-1 ;Last location BLT'ed to zero when initialized IMNBLK: 0 ;Number of times blockage avoided (output held up by ITS) IMPHTF: -1 ;Host table free list, threaded through IMPHTB, end with -1 IMPUP: -1 ;0 => IMP up ;-1 => down ;-2 => coming up, PI lvl still off ;1 => down for good, until next time IMP ready line changes IMPTCU: 0 ;0 IMP up/down status not changing ;>0 Trying to reinitialize, SYSJOB hasn't done so yet ;-1 Has been reinitialized, haven't exchanged NOPs yet IMPUCT: 0 ;IMP coming up timeout, if 4 NOPs don't go through promptly. IMPDWN: BLOCK 3 ;Last message from IMP that it is going down ;WD0: "Reason" claimed by IMP (see ch 3 of BBN report 1822) ;WD1: Time when expected down ;WD2: Time when expected up (SYS time=1/30 sec since up) IFN KAIMP,[ IMPPIA: 0 ;Current IMP PIA IMPCNI: 0 ;CONI into here at slow clock level IMPA: 0 ;Save A at IMPCHN PI level ] IMERCN: -1 ;CONI into here when net goes down BBLK EBLK IMPCSH: -1 ;Current source host (IMPHTB index). -1 when idle. IMPCLN: 0 ;Current link number IMNWSI: 0 ;Second BLKI pointer, zero if none IMBLKI: 0 ;Place to store BLKI pointer IFN KSIMP,[ IMIFLS: 0 ;Flushing output at interrupt handler IMPIBP: 0 ;Pointer to input buffer data ] IMPILB: BLOCK 6 ;Input leader buffer IMNOPC: 0 ;< 0 => Send NOPs IMPOAC: 0 ;> 0 => Output active, don't restart IMBLKO: 0 ;Place to store BLKO pointer IMPBZY: 0 ;Software interrupt start flag ; IMP output list. ; ; NEGATIVE = BLKO POINTER ; 0=STOP, 1=SET LAST WORD ; 2=32-BIT MODE ; 3=NOP ; IMOPNT: 0 ;Index of next "instruction" in IMP output list: IMOLST: 0 ;BLKO for second and third leader words (first is DATAOed) IMOBK1: 0 ;First BLKO pointer IMOBK2: 0 ;Usually 1, set LAST IMP BIT IMOBK3: 0 ;Second BLKO pointer 0 ;Stop IMOLDR: BLOCK 6 ;Build preamble here for data messages ;METERS ;IP meters IMNIPI: 0 ; # of IP datagrams input (rcvd) IMNIPF: 0 ; # of IP datagrams flushed (input threw away) IMNIPO: 0 ; # of IP datagrams output (sent) IMNIPR: 0 ; # of IP RFNMs received IMNIP7: 0 ; # of IP Type 7 (Dest Host Dead) messages received IMNIP8: 0 ; # of IP Type 8 (Error) msgs rcvd IMNIP9: 0 ; # of IP Type 9 (Incomplete Transmission) msgs rcvd IMNWIG: 0 ; # words ignored by "Ignore" state (%ISIGN) IMNWIF: 0 ; # words flushed by IMPRM5 ;IMP meters IMNSRF: 0 ;Number of spurious RFNMs on non-IP links IMPMSR: BLOCK 20;Count of IMP messages rcvd IMPM1S: BLOCK 4 ; # Type 1 (Error in Leader) subtype msgs IMPM9S: BLOCK 2 ; # Type 9 (Incomplete Transmission) subtype msgs IMPMSS: BLOCK 1 ;Count of IMP msg sent (we only send regular msgs) IMCT1: 0 ;# Times at IMPBKZ IMCT2: 0 ;# Times at IMPIBZ IMCT3: 0 ;# Times at IMPOBZ BBLK SUBTTL ARPANET MAIN-PROGRAM LEVEL ;(Re)Start IMP ; IMPINI: IFN KAIMP,[ CONO IMP,IMI32S ;32-bit data mode DATAI IMP,A ;Clear any cruft CONO IMP,IMPODC ;Clear OUTPUT DONE and PIA CONSZ IMP,IMPOD+7 ;Check OUTPUT DONE, PIA, cause HOST READY BUG HALT,[IMP: Hardware dead] ;CONO didn't clear some bits? CONO IMP,IMPIR+IMPHEC ;Clear HOST ERR, enable int on IMP READY ] IFN KSIMP,[ IF2,IFN IMPIBF&777,.FATAL IMPIBF not on DEC page boundary MOVEI A,IMPIBF_-9. ;DEC page # of IMP buffer page TRO A,%UQ16B\%UQVAL ;Valid mapping, 16 bit device IOWRI A,UBAPAG+IUIMPG_1 ;Set up 1 DEC page of UBA mapping. Note that ; the second half of IUIMPG isn't mapped at all MOVEI A,%LHRST IOWRI A,%LHOCS ;Reset output side IOWRI A,%LHICS ;Reset Input side ] MOVE T,TIME ADDI T,30. CAMLE T,TIME PUSHJ P,UFLS ;Wait one sec for IMP to notice rdy line drop IFN KAIMP,[ CONO IMP,0 ;Clear "ENA IMP RDY" int (turns off IMP error) MOVEI A,NETCHN ;Set idle PIA MOVEM A,IMPPIA MOVE A,[JSR IMPIBK] ;Set up default interrupt handlers MOVEM A,IMPILC MOVE A,[JSR IMPOBK] MOVEM A,IMPOLC ] ;IMP now shut down. Reset variables IFN KAIMP,[ SETZM IMPILC+1 ;Clear BLKI, BLKO runout locations (KA\DM) SETZM IMPOLC+1 ] IFN KSIMP,[ SETZM IMPIBP ;Reset DMA input buffer pointer SETZM IMIFLS ;Not flushing output at PI handler ] SETOM IMPOAC ;Output not active SETOM IMPBZY ;Don't start interrupts by accident SETOM IMPUP ;Not up yet SETOM IMPTCU ;Note trying to come up MOVNI A,30. ;Allow 15 seconds to come up MOVEM A,IMPUCT SETOM IMPHTF ;Will GC IMPHTB on first reference MOVE A,[IMPN,,IMPN+1] ;This resets IMPIBS,IMPIDP,IMPODP,IMPI,IMPO, SETZM IMPN ; IMPB,IMPIH,IMPOH,IMPI,IMPOS, and host BLT A,LIMPN ; tables. SETOM IMPIS ;Init input state FSM correctly MOVE T,TIME ;Note when we last started IMP MOVEM T,LNETIM IFN KAIMP,[ CONO IMP,NETCHN ;Enable interrupts on NETCHN, start input ] IFN KSIMP,[ CALL IMPHRS ;Set host ready CALL IMPIST ;Start input ] SETOM IMPDWN+1 ;Time for IMP to go down, not known MOVE T,TIME ADDI T,15. ;Wait 1/2 sec before we try to output CAMLE T,TIME PUSHJ P,UFLS MOVNI A,4 MOVEM A,IMNOPC ;Send 4 NOPs to start ;Falls through to start output ;Start IMP output, from process level ; IMPOST: CONO PI,NETOFF ;Kill interrupts IFN KAIMP,[ MOVE TT,IMPPIA ;Get desired level for output done int AOSN IMPOAC ;Skip if output already active CONO IMP,IMPODS(TT) ;Generate output done int to start things JRST NETONJ ;Reenable interrupt system ];IFN KAIMP IFN KSIMP,[ SKIPL IMPOAC ;Skip if output already active JRST NETONJ ;Yes, nothing to do SETZM IMPBZY ;Tell interrupt handler to run CONO PI,NETRQ ;Request interrupt on net channel JRST NETONJ ;Reenable interrupt system ] ;Start output, called from PI (NETCHN) level ; IMPIOS: IFN KAIMP,[ AOSE IMPOAC ;Note output active. If already active, POPJ P, ; nothing more to do PUSH P,TT CONO PI,400 ;Turn PI off, IMP may have PIA = 1 MOVE TT,IMPPIA ;Get current PI level CONO IMP,IMPODS(TT) ;Set OUTPUT DONE to cause interrupt CONO PI,200 ;Reenable interrupts POP P,TT POPJ P, ] IFN KSIMP,[ SKIPL IMPOAC ;Output already active? POPJ P, ;Yes, do nothing SKIPE IMPOS ;Output state is idle? BUG HALT,[IMP: Bad IMPOS state, ],DEC,IMPOS SETZM IMPBZY ;Tell interrupt handler to run CONO PI,NETRQ ;Request net interrupt POPJ P, ;all done. ] ;Check if IMP ready line is set ; Called from SYSJOB. ; Return +1 if IMP not ready, +2 if so ; IMPCKR: IFN KSIMP,[ IORDI A,%LHICS ;Get input CSR TRNN A,%LHINR ;Skip if IMP not ready AOS (P) ;Return +2 if ready POPJ P, ;That's all ] IFN KAIMP,[ CONSZ IMP,IMPR ;Skip if IMP not ready AOS (P) ;Return +2 if ready POPJ P, ] SUBTTL HOST-TABLE MANAGEMENT ; FNDHST - Look up host-table index for a given IMP host address. ; Call with NETOFF or NETCHN PI in progress. ; T/ IMP host address (maybe someday other nets?) ; Returns .+1 if failed (no room in table) ; Returns .+2 ; H/ host-table index ; Smashes W. FNDHST: MOVEI H,LIMPHT-1 ;Search for an entry for this host CAME T,IMPHTN(H) SOJGE H,.-1 JUMPGE H,POPJ1 ;Found SKIPGE H,IMPHTF ;Not found, cons one off free list JRST FNDHS1 ;Oops, must garbage collect MOVE W,IMPHTB(H) CAIGE H,LIMPHT ;Make sure H is valid idx CAIL W,LIMPHT ;ditto W BUG HALT,[NET: FNDHST idx clobbered!!!] MOVEM W,IMPHTF MOVEM T,IMPHTN(H) SETZM IMPHTB(H) ;Nothing is known about this host SETZM IMPHTC(H) ;Assume no RFNMs outstanding SETZM IMPHTT(H) ;Clear out time of last RFNM. JRST POPJ1 ; Host-Table full, attempt to GC it and flush unused entries, by ; scanning all possible pointers into table. ; IMP pointers are IMPCSH and IMPHTC(H) ; TCP pointers are XBNADR(I) ; GC mark phase - mark entries in use FNDHS1: PUSH P,I MOVSI W,200000 ;Mark bit MOVEI H,LIMPHT-1 ;Clear all mark bits ANDCAM W,IMPHTB(H) SOJGE H,.-1 SKIPL H,IMPCSH ;Mark from IMPCSH IORM W,IMPHTB(H) IFN TCPP,[ MOVEI I,XBL-1 SKIPL H,XBNADR(I) ; See if TCP conn has a net addr specified IORM W,IMPHTB(H) ; Yes, set the mark bit. SOJGE I,.-2 ] ;IFN TCPP ; GC sweep phase - free all unmarked entries SETO I, ;Free pointer MOVEI H,LIMPHT-1 MOVSI W,601000 ;Protect if RFNM-WAIT, RST-WAIT, or marked FNDHS4: SKIPG IMPHTC(H) ;Also protect if any outstanding RFNMs TDNE W,IMPHTB(H) SOJGE H,FNDHS4 JUMPL H,FNDHS5 SETZM IMPHTN(H) ;Don't belong to any host MOVEM I,IMPHTB(H) ;Cons onto free list MOVE I,H SOJGE H,FNDHS4 FNDHS5: MOVEM I,IMPHTF ;Free list POP P,I SKIPGE IMPHTF POPJ P, ;GC-overflow JRST FNDHST ;Try again, should win SUBTTL ARPANET INPUT INTERRUPT LEVEL COMMENT | The KA/KL IMP interrupt level structure is fairly complicated and deserves some explanation. Because the IMP interface is not a DMA device, all I/O is done "by hand", a word at a time; for this reason all I/O is done at PI level IMPCHN=1 (the highest) whenever possible. However, to prevent general IMP processing from taking complete precedence over everything else, all non-I/O handling is done at PI level NETCHN=2, which is the same level as disk devices. Because the KA/KL interface only has one PI assignment available, the software to switch levels is much more complicated. For either case, the code will not make sense unless you understand the channel 1 multiplexing feature (see interface CONI bit descriptions). The KS interface avoids all this cruft by being a DMA device and only interrupting on NETCHN when it has finished a transfer. The first-level KS interrupt handler dispatches to IMPBER on errors, IMPBKZ for "control" interrupts (Last Imp Word seen) and IMPIBZ for other Input Done interrupts; this is very similar to the DM interface. | ; Here when IMP interface is interrupting at PI level 2 (NETCHN) ; TT has CONI bits. Can clobber most ACs ; IMPINT: IFN KAIMP,[ AOSN IMPB ;Requested by PI 1 control interrupt? JRST IMPBKZ ; Yes AOSN IMPI ;Requested by PI 1 Input Done interrupt? JRST IMPIBZ ; Yes AOSN IMPO ;Requested by PI 1 Output Done interrupt? JRST IMPOBZ ; Yes already TRNE TT,IMPLW+IMPHER+IMPERR ;No PI 1 ints, check status bits JRST IMPBKZ ;PI 2 Control interrupt (error, Last Imp Word) TRNE TT,IMPID JRST IMPIBZ ;PI 2 Input Done TRNE TT,IMPOD JRST IMPOBZ ;PI 2 Output Done BUG HALT,[IMP: Bogus interrupt] ] IFN KSIMP,[ SETOM IMPBZY ;Tell MP we are handling request SKIPL IMPOAC ;Output already active? JRST IMPEX ;Yes, do nothing AOS IMPOAC ;Output is now active JRST IMPOBZ ;No, go try to start output ] IFN KAIMP,[ ; IMPIBK - Default PI 1 Input Done routine, called from IMPILC. ; We're idling, switch to PI 2 to handle the input ; (normally 1st word of new IMP message) EBLK IMPIBK: 0 BBLK SETOM IMPI ;Set flag saying PI 1 Input Int seen CONO IMP,NETCHN ;Switch PIA to 2 JRST 12,@IMPIBK ;Go re-interrupt, will get to IMPINT->IMPIBK ; IMPBRK - PI 1 Control interrupt, called from PI0LOC+2 (= 42 on KA's) ; which is the standard PI 1 vector location. ; Again, switch to PI 2 to handle the condition ; (typically Last Imp Word seen on input) EBLK IMPBRK: 0 ;This interrupt is to 42, may not be the IMP BBLK CONSO IMP,IMPLW+IMPHER+IMPERR ;This really from the IMP? IFE NEWDTP,JRST RC1INT IFN NEWDTP,JRST IMPBR1 SETOM IMPB ;Yes, re-interrupt and handle at NETCHN level CONO IMP,NETCHN ;Switch PIA to 2 (NETCHN) JRST 12,@IMPBRK ;Go re-interrupt, will get to IMPINT->IMPBKZ IFN NEWDTP,[ IMPBR1: CONSZ DTC,70 ;Allow for non-IMP interrupt on PI chan 1 JRST 12,@IMPBRK ] RC1INT: MOVEM 17,R1NTAC+17 MOVEI 17,R1NTAC BLT 17,R1NTAC+16 MOVEI J,1 JSP E,SPUR MOVSI 17,R1NTAC BLT 17,17 JRST 12,@IMPBRK ; IMPRM4 - PI 1 Input-Done handler during readin of IMP data (not leader) ; BLKI has run out but haven't yet gotten Last Imp Word! ; Either read more (if 2nd ptr specifed) or ignore following data. EBLK IMPRM4: 0 BBLK MOVEM A,IMPA ;Save A SKIPL A,IMNWSI ;Second BLKI pointer exists? JRST IMPRM6 ;Nope, none now MOVEM A,IMBLKI ;Yes, store it! SETZM IMNWSI ;Clear this flag so don't do it again MOVE A,IMPA ;Restore A JRST 12,@IMPRM4 ;Return, continuing BLKI. IMPRM6: MOVE A,[JSR IMPRM5] ;Ugh! Ignore additional input MOVEM A,IMPILC ;Set up new vector to "ignore" routine MOVE A,IMPA JRST 12,@IMPRM4 ; IMPRM5 - PI 1 Input-Done handler while ignoring IMP data, only ; set up by IMPRM6 above. ; Just reads a word and ignores it. This loop is broken ; by a control interrupt when Last-Imp-Word is seen. EBLK IMPRM5: 0 ;Hmm? Flush input at PI 1 BBLK DATAI IMP,IMPA AOS IMNWIF ;See how often we come here. JRST 12,@IMPRM5 ];IFN KAIMP IFN KSIMP,[ ;First level interrupt handling for input side. Here from UBA vector hardware. IMPIBK: IFN NETCHN-UTCCHN,.ERR You lost at IMPIBK EBLK IMPIBK: 0 BBLK JSR UTCSAV ;Save AC's, get a stack IORDI TT,%LHICS ;Get CS register TRNE TT,%LHERR\%LHNXM BUG HALT,[IMP: I NXM] TRNE TT,%LHMRE ;Ready line flapped JRST IMPIER ;Go directly to error routine TRNN TT,%LHRDY ;Device ready for new operation? BUG HALT,[IMP: Input device not ready] TRNN TT,%LHEOM ;Saw EOM from IMP? JRST IMPIB1 ;No, word count ran out before message SKIPGE IMIFLS ;Flushing output? JRST [ SETZM IMIFLS ;Not any more! JRST IMPIRT ] ;But flush last piece by queueing new request IORDI A,%LHIWC ;End of message. Get remaining UB word count SKIPE A ;This would be a surprise, really TDO A,[-1,,600000] ;36bit number of UBA words remaining in bfr IDIVI A,2 ;Number of PDP10 words (cleverly rounded) ADDI A,IMPBFS ;Number of PDP10 words of message MOVNS A ;Negative word count HRLZS A ;NWG,,0 HRRI A,IMPIBF ;NWG,,Start of buffer MOVEM A,IMPIBP ;Init input buffer pointer for new data MOVE A,[-3,,IMPILB-1] ;Read leader - 3 words to IMPILB CALL IMPGRI ;Do it MOVEI A,%ISIML SKIPN IMPIS ;Already in non-idle state? (shouldn't happen) MOVEM A,IMPIS ;Was idling, set state to "Saw IMP LEADER" TRNE TT,IMPLW ;Saw last word of message? JRST IMPBKZ ;EOM, so this is a control interrupt JRST IMPIBZ ;Not EOM, handle differently ;Message didn't fit in input buffer. Shouldn't ever get here, but ;might if messages concatenated due to ready line randomness ; IMPIB1: BUG INFO,[IMP: Huge message] SETOM IMIFLS ;Say we are flushing output JRST IMPIRT ;And go queue up another read ;Fake output interrupt - come here when we have read more data from the ;input buffer and want to re-dispatch. ; IMPIBL: TRNE TT,IMPLW ;Saw last word of message? JRST IMPBKZ ;EOM, so this is a control interrupt JRST IMPIBZ ;Not EOM, handle differently ];IFN KSIMP ; IMPIBZ - PI 2 (NETCHN) "Input Done", via IMPINT (KA) or IMPIBK (KS) ;KA\KL: Note there is one input word waiting in the IMP interface, ; but it is NOT the last IMP word (if it was, we would get a ; control interrupt and go to IMPBKZ instead). This situation ; should only happen while reading the IMP leader and there is ; more input than just the leader, i.e. it is a NCP or IP message. ; This is also where we come after being in idle state. ; ;KS: A bunch of stuff has been DMA'd into the input buffer and the ; DMA word count ran out before the IMP sent EOM. ; ; TT/ IMP CONI word or status register IMPIBZ: AOS IMCT2 IFN KAIMP&IMPDBG,[ TRNN TT,IMPI32 ;Debugging, make sure we reading in 32 bit mode BUG HALT,[IMP: 36bit mode at IMPIBZ] ];IFN KAIMP&IMPDBG MOVE B,IMPIS ;Skip hold-up check unless start of msg (idle) CAILE B,%ISIID BUG HALT,[IMP: Bad IMPIBZ state] ;Unknown input state JRST @.+2(B) ;Dispatch, note data not read yet IMPIGN ;-1 Supposed to be shut off, go ignore message. OFFSET -. %ISIDL:: IMSTR1 ; 0 Was idle, this is start of a message! %ISIGN:: IMPIGN ; 1 Ignoring this message. %ISIML:: IMPLD2 ; 2 Reading IMP leader, see what we got. %ISIID:: [JRST 4,.] ; 3 Was reading IP datagram! Runout is error. OFFSET 0 IMPIGN: AOS IMNWIG ;See how often we come here. IFN KAIMP,[ DATAI IMP,A ;Ignore input (only come here via table above) JRST IMPRET ] IFN KSIMP,JRST IMPIRT ; All routines dispatched to from IMPIBZ and IMPOBZ return via IMPRET. IMPRET: IFN KAIMP,[ IFN IMPDBG,[ CONSO IMP,IMPI32 ;Make sure input is in 32-bit mode BUG HALT,[IMP: 36bit mode at IMPRET] ] CONO IMP,@IMPPIA ;Switch to desired exit PIA JRST IMPEX ] IFN KSIMP,JRST IMPEX ; IMPBKZ - PI 2 (NETCHN) Control interrupt, via IMPINT (KA) or IMPIBK (KS) ; Error or Last Imp Word on input. ; TT/ IMP CONI word or status register IMPBKZ: AOS IMCT1 ;Bump count of control interrupts IFN KAIMP,[ TRNE TT,IMPERR+IMPHER ;See if error or last-imp-word. JRST IMPBER ;Jump if IMP Error or Host Error ] ; Not an error, interface has Last Imp Word ready for DATAI'ing! ; Go handle end of IMP message IFN KAIMP,[ MOVE A,[JSR IMPIBK] ;Get rid of input BLKI MOVEM A,IMPILC ;Replace with default switch-PIA vector SETZM IMPIH ;Say don't need PI 1 for input any more. MOVEI A,NETCHN ;And change exit PIA to 2 SKIPL IMPOH ;Unless output side still needs PI 1. MOVEM A,IMPPIA ;Set value of PI level desired on exit. DATAI IMP,A ;Get the last input word for processing ] SKIPGE B,IMPIS ; Unless network has been shut off JRST IMPIGN ; (in which case ignore input) JRST @IMSDT2(B) ; then go process end of IMP message. IMSDT2: OFFSET -. %ISIDL:: IMPBKN ; 0 Was idle - leader only 1 word long?? %ISIGN:: IMPIRT ; 1 Ignore input %ISIML:: IMPLD1 ; 2 End of IMP leader - can't be regular msg %ISIID:: IMPRMI ; 3 End of IP datagram OFFSET 0 IMPBKN: IFN KSIMP,BUG HALT,[IMP: Bad state IMPBKN] IFN KAIMP,[ ; Here from table above for old-type leader (1 word) ; IMPBN1 is used by IMPLD2 if long leader has wrong format. ; MOVEM A,IMPILB ;Store first (and only) word of leader ;Falls through ];IFN KAIMP ;Here from KA short leader or all long leader with wrong format ; IMPBN1: LDB A,IMOTBP ; Get message format type CAIN A,4 ; Old-type NOP? JRST IMPIRT ; Just ignore it. CAIN A,16 ; Is it 1822L format? BUG INFO,[IMP: 1822L leader],OCT,IMPILB CAIE A,17 ; Is it not the long-leader format? BUG INFO,[IMP: Old-type leader],OCT,IMPILB JRST IMPIRT ; Ignore rest of message, if any ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; IMP LEADER READING/DISPATCH ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Code on this page handles the initial processing of ;;; IMP messages and dispatches to the appropriate ;;; routines for each message type. Only Type 0 ("Regular") ;;; messages carry Host-Host traffic. IMSTR1: IFN KAIMP,[ ; Here from IMPIBZ only, to handle first word of an IMP message. ; (It's not the last word or IMPBKZ would complain about it) ; Set up a BLKI to get the rest of the leader. DATAI IMP,A ;Get 1st word from interface ; Entry point from IMPOB6 only to restart input from "held-up" state ; First word already in A IMSTRT: MOVEM A,IMPILB ;Store first word of leader MOVEI C,%ISIML ;Set new state = reading rest of IMP leader MOVE B,[-2,,IMPILB] ;There are two more words in the leader JRST IMPRM9 ;Go read the leader. ];IFN KAIMP IFN KSIMP,BUG HALT,[IMP: Bad state IMSTR1] ; Here from IMPBKZ only for a leader not followed by any data. ; KA/KL has last word in A ; IMPLW flag in TT. ; IMPLD1: IFN KAIMP,[ AOS B,IMBLKI ;Update pointer to buffer MOVEM A,(B) ;and store last word in right place. ] JRST IMPLDD ; Fall through to handle what should be an IMP-Host note. ; The IMPLW flag distinguishes this entry point from IMPLD2, ; so we know there isn't a data word in the interface. ; Here from IMPIBZ only, for an IMP leader with more data following; ; almost certainly a "Regular" host-host message. ; IMPLD2: IFN KAIMP,[ +++++ ;Missing DATAI of current word first?? AOS B,IMBLKI ;Update pointer to buffer MOVEM A,(B) ;and store last word in right place. ] JRST IMPLDD ; Fall through to handle what should be a real message ; The IMPLW flag distinguishes this entry point from IMPLD2, ; so we know there is a data word in the interface. (KA) SUBTTL IMP leader dispatch handling IMPLDD: HRRZ B,IMBLKI ;Get address of last word read CAIGE B,IMPILB+2 ;Must be at least 3 words to be valid JRST IMPLD3 LDB T,IMOTBP ;Examine new-format flag bits of leader CAIN T,16 ;Is it 1822L format? BUG INFO,[IMP: 1822L leader],OCT,IMPILB CAIE T,17 ;Verify that leader is "new" 96-bit fmt. JRST IMPBN1 ;Something else?? Go discard. LDB T,IMLNBP ;Extract link number (high 8 bits of msg-id) MOVEM T,IMPCLN ;Save link message arrived on LDB T,IMSABP ;Get arpanet address (source host+imp) IFN 0,[ LDB T,IMSHBP ;Source host LDB A,IMSIBP ;Source imp DPB A,[112000,,T] ;Form host address ];IFN 0 PUSHJ P,FNDHST ;H gets host table index JRST IMPLD9 ;Host table full MOVEM H,IMPCSH ;Save current host LDB A,IMTBP ;Get message type in A CAILE A,10. JRST IMPUN ;Unknown type? AOS IMPMSR(A) ;Count IMP msgs rcvd JRST @IMTDT(A) ;Dispatch IMTDT: IMPRM ; 0 Regular Message IMPBE1 ; 1 Error in Leader (no msg-id) IMPGD ; 2 IMP Going Down IMPUN ; 3 - IMPIN ; 4 NOP IMPRFN ; 5 RFNM - Ready For Next Message (transmit succeeded) IMPHDS ; 6 Host Dead Status (general info) IMPDHD ; 7 Destination Host Dead (transmit failed) IMPBE8 ; 8 Error in Data (has msg-id) IMPINC ; 9 Incomplete Transmission (transmit failed temporarily) IMPIRS ;10 Interface Reset - IMP dropped its ready line IMPLD9: BUG INFO,[IMP: Message discarded due to host table full],OCT,IMPILB,OCT,IMPILB+1,OCT,IMPILB+2 JRST IMPIRT ;Here from IMPLDD if leader is too short ; IMPLD3: SUBI B,IMPILB-1 ;Number of words read BUG INFO,[IMP: Short leader, ],DEC,B,[wds. WD1=],OCT,IMPILB,[WD2=],OCT,IMPILB+1 JRST IMPIRT ;Flush rest of message ;;; IMP->Host Type X (e.g. 3, 11-255) - bad type IMPUN: BUG INFO,[IMP: Unknown msg type ],OCT,A,[ leader ],OCT,IMPILB,OCT,IMPILB+1,OCT,IMPILB+2 JRST IMPIRT ;;; IMP->Host Type 1 - Error in leader (msg-id not given) ;;; IMP->Host Type 8 - Error in data (msg-id given) IMPBE1: LDB T,IMSTBP ;Get subtype (4 bits) ANDI T,3 ;Only 2 bits should be used AOS IMPM1S(T) ;Increment count of Type 1 subtype messages IMPBE8: MOVE T,TIME SUB T,LNETIM CAIL T,60. ;Ignore error during initial synchronization BUG INFO,[IMP: Type ],DEC,A,[err msg, leader],OCT,IMPILB,OCT,IMPILB+1,OCT,IMPILB+2 MOVE B,IMPCLN ;Get link msg came in on CAIN B,233 ;Internet link? AOS IMNIP8 ;Yes, count IP meter CAIN A,8. ;Error identified with a particular message? JSP T,IMPBLD ;Decrement count of active messages JRST IMPIRT ;;; IMP->Host Type 2 - IMP going down IMPGD: LDB B,[420200,,IMPILB+2] ;Reason (see 1822) MOVEM B,IMPDWN LDB B,[360400,,IMPILB+2] ;How soon going down * 5 mins MOVE H,B IMULI B,5*60.*30. ;Ticks in 5 mins ADD B,TIME MOVEM B,IMPDWN+1 LDB C,[241200,,IMPILB+2] ;How long to be down * 5 minutes MOVE Q,C IMULI C,5*60.*30. ;Downtime in ticks ADD C,B ;Add to time down MOVEM C,IMPDWN+2 ;Store time when will be up IMULI H,5 ;Minutes IMULI Q,5 BUG INFO,[IMP: Going down in ],DEC,H,[mins for ],DEC,Q,[mins, reason],DEC,IMPDWN JRST IMPIRT ;;; IMP->Host Type 4 - NOP IMPIN: JRST IMPIRT ;One more NOP from IMP ;;; IMP->Host Type 5 - RFNM (Ready For Next Message) IMPRFN: JSP T,IMPBLD ; Decrement count of active IMP messages for this host MOVE A,IMPCLN ;Get link # CAIE A,233 ;IP link number? JRST IMRFNX ;No, skip IP code IFN INETP,.ERR INETP needs handling for RFNM on link 233 AOS IMNIPR ;Bump count of IP RFNMs received JRST IMPIRT ; and do nothing else about it, ugh. IMRFNX: BUG INFO,[IMP: Spurious RFNM from ],OCT,IMPHTN(H),[link],OCT,IMPCLN AOS IMNSRF JRST IMPIRT ;;; IMP->Host Type 6 - Host Down Status ; H/ host index IMPHDS: LDB A,[301400,,IMPILB+2];Bits 65-76 of leader, 4.9-3.7 3rd word HRRM A,IMPHTB(H) ;Store, hope user read RFC 611 JRST IMPIRT ;;; IMP->Host Type 7 - Destination Host Dead IMPDHD: MOVEI E,%NCDED JRST IMPHNR ;;; IMP->Host Type 9 - Incomplete Transmission IMPINC: LDB T,IMSTBP ;Get subtype field (4 bit reason for failure) AOS IMPM9S(T) ;Bump count of subtypes MOVEI E,%NCINC ;This is an incomplete msg response IMPHNR: JSP T,IMPBLD ;Decrement active IMP msg count for this host MOVE A,IMPCLN ;Link for this message? CAIE A,233 ;IP Link? JRST IMPHN1 CAIN E,%NCINC ;Yes, count IP meters AOS IMNIP9 CAIN E,%NCDED AOS IMNIP7 JRST IMPIRT IMPHN1: BUG INFO,[IMP: DHD or IT msg rcvd on non-IP link] JRST IMPIRT ;;; IMP->Host Type 10 - Interface Reset IMPIRS: BUG INFO,[IMP: Interface-reset msg] JRST IMPIRT ;Probably nothing useful to do about it. ; Here from all over, to flush rest of this message. ; All non-regular messages (not type 0) return here, as well as some ; errors with regular msgs. ; TT says whether there is any more data to read from this message. IFN KAIMP,[ IMPIRT: SETZM IMPIS ;Assume end of message, reset to normal state TRNN TT,IMPLW ;But if we haven't yet read the last word, AOSA IMPIS ;then change state to "Ignore" and flush input. ;Note skip over following SETZM. ; Regular messages (type 0) return here, when we already know this message ; was completely read. TT isn't valid. IMPIR1: SETZM IMPIS ;Reset to normal idle state SETOM IMPCSH ;Say no current host CONO IMP,IMI32S ;Make sure in 32 bit data mode JRST IMPRET ] IFN KSIMP,[ ;We have already read the whole message from the IMP into the input buffer, ; so flushing excess input is no work at all. IMPIRT: ;Regular messages (type 0) return here, when we already know this message ;was completely read. TT isn't valid. IMPIR1: SETZM IMPIS ;Set idle state CALL IMPIST ;Start listening for new input SETOM IMPCSH ;Say no current host JRST IMPRET ];IFN KSIMP ;;; IMP->Host Type 0 - Regular Host-Host message ; Unless the source host screwed up and sent a dataless message, ; there is at least one word waiting to be read from the interface. ; For IP this is the 4th word and we are in 32-bit mode. ; TT/ IMP CONI bits or status register ; B/ addr of last wd input (counted-out BLKI pointer) IMPRM: TRNE TT,IMPLW JRST IMPRM3 ;Foo, message shouldn't end so soon. Go barf. MOVE A,IMPCLN ;Is link number the magic cookie for IP? CAIE A,233 JRST IMPIRT ;No, ignore it since we don't have NCP ;This is an Internet Protocol datagram. Make sure we are ;in right mode for reading. ; AOS IMNIPI ;Bump count of IP datagrams received IFN KAIMP&IMPDBG,[ TRNN TT,IMPI32 ;Should already be in 32-bit mode BUG PAUSE,[IMP: Reading IP dgm in 36-bit mode] ] MOVEI A,%IMXLN ;Specify max size of IMP message ; (we can't trust msg-len leader field) PUSHJ P,IPGIPT ;Call IP module - get input buffer pointer JRST [ AOS IMNIPF ;Punted, bump cnt of datagrams lost JRST IMPIRT] ;Flush this message (err msg already printed) MOVEM A,IMPIDP ;Save datagram pointer MOVEM B,IMPIBS ;Save input BLKI pointer for later check MOVEI C,%ISIID ;Set state = reading IP datagram ;JRST IMPRM9 ;Go do it. ; Set up and start multiword data input. This place is jumped to by ; several things that initiate IMP input, specifically IMSTRT, IMPRMT, ; and IMPRM. ; B/ BLKI pointer ; C/ New input FSM state ; IMPRM9: MOVEM C,IMPIS ;Save current input state MOVEM B,IMBLKI ;Save BLKI pointer IFN KSIMP,[ MOVE A,B ;Set up BLKI pointer CALL IMPGRI ;Get requested data from input buffer JRST IMPIBL ;Jump back to handle new input data! ] IFN KAIMP,[ MOVE B,[BLKI IMP,IMBLKI] MOVEM B,IMPILC MOVE B,IMPBRO(C) ;Get BLKI runout instruction and set vector; MOVEM B,IMPILC+1 ; will execute when ptr counts out. SETOM IMPIH ;Say that input wants high pri MOVEI B,IMPCHN ;And set our exit PIA to it (IMP) MOVEM B,IMPPIA JRST IMPRET ;Return from interrupt ];IFN KAIMP ;Message with no data. Just ignore it, could print a note IMPRM3: JRST IMPIRT IFN KAIMP,[ ; This table holds the instruction to execute after the input ; BLKI has counted out the ptr and stored the current input word. ; Note that if the IMP message ends during the BLKI, a control ; interrupt will happen instead and control goes to IMPBKZ ; where there is another state dispatch table. ; Normally only %ISIML and %ISINL actually use these instructions; ; the other states are impossible or expect to read the entire ; remaining message. IMPBRO: OFFSET -. %ISIDL:: JRST 4,IMPBRO ; 0 Idle - shouldn't be BLKI'ing. %ISIGN:: JRST 4,IMPBRO+1 ; 1 Ignore - shouldn't be BLKI'ing. %ISIML:: JSR IMPLD5 ; 2 Reading IMP leader (4 wds partial msg) %ISIID:: JSR IMPRM4 ; 3 Reading IP datagram (get all) OFFSET 0 EBLK ; PI 1 Input Done interrupt (from IMPILC+1, runout) IMPLD5: 0 ; JSR here on BLKI runout after reading 3rd wd of IMP leader. BBLK ; Input Done is not set, because BLKI just turned it off. MOVEM A,IMPILC ;Save A MOVE A,[JSR IMPLD6] ;Make very next input word interrupt to IMPLD6 EXCH A,IMPILC ;Do it, restore A JRST 12,@IMPLD5 EBLK ; PI 1 Input Done interrupt (from IMPILC) IMPLD6: 0 ; JSR here with 4th wd of leader in interface. BBLK ; Must decide whether to continue reading leader in ; 36-bit mode (NCP) or 32-bit mode (IP). MOVEM A,IMPILC ; Save A MOVE A,IMPILB+1 ; Get word with link number in it ANDI A,377 ; Mask off CAIN A,233 ; Internet Protocol "link"? JRST IMPLI3 ; Yes! Go handle it. ; NCP read will immediately store current 36-bit word (4th), ; store another 36-bit word (5th), and then run out to IMPLD4. MOVE A,[-2,,IMPILB+2] ; Reading NCP message. MOVEM A,IMBLKI MOVEI A,%ISINL ; Reading NCP leader, set state thereto. MOVEM A,IMPIS MOVE A,[JSR IMPLD4] ; And change dispatch vector. MOVEM A,IMPILC+1 MOVE A,[BLKI IMP,IMBLKI] EXCH A,IMPILC ; Set up BLKI and restore A JRST 12,@IMPLD6 ; Return. Note current input word is still waiting. ; IP read will immediately store current 36-bit word (4th), ; then set up so next input-done interrupt (on 5th, 32-bit word) ; goes directly to IMPIBZ->IMPLD2 with NETCHN PI. ; (For AI-KA/ML-KA/MC-KL, perhaps by way of IMPIBK if output is active) IMPLI3: MOVEI A,%ISIIL ; Say reading IP type leader. MOVEM A,IMPIS CONO IMP,IMI32S+IMPCHN ; Set further input to 32-bit mode DATAI IMP,IMPILB+3 ; Store the 4th 36-bit word immediately; this ; also starts interface reading the 5th word. MOVE A,IMPLD6 ; Now must set up for next interrupt. MOVEM A,IMPLD4 ; Fake out the common code below JRST IMPLI4 ; Set up for next Input-Done interrupt EBLK ; PI 1 Input Done interrupt (from IMPILC+1, runout) IMPLD4: 0 ; JSR here on BLKI runout after reading IMP leader BBLK ; There is still one word to go, to be gotten at NETCHN level MOVEM A,IMPILC ; Save A ; Drop through to common code IMPLI4: SETZM IMPIH ; Say input no longer needs PI 1 MOVEI A,NETCHN ; Make PI 2 (NETCHN) the exit PIA, SKIPL IMPOH ; unless output side needs PI 1. MOVEM A,IMPPIA ; Set desired PIA channel on exit CONO IMP,@IMPPIA ; Set PIA to whatever it was! MOVE A,[JSR IMPIBK] ; Reset PI 1 Input-Done vector back to std. EXCH A,IMPILC ; and restore A. JRST 12,@IMPLD4 IMPBCM: BUG INFO,[NCP: CTL MSG BS NOT 8 OR CT>120. HST ],OCT,IMPHTN(H),[BS ],DEC,IMPCBS,[BC ],DEC,IMPCBC JRST IMPIRT ];IFN KAIMP ; IMPRMI - End of IP datagram, PI in progress on NETCHN, here from IMPBKZ ; A/ Last IMP word (32-bit) (KA/KL only) ; TT/ CONI bits as of interrupt ; IMPRMI: AOS B,IMBLKI ;Get address to store last word in IFN KAIMP,MOVEM A,(B) ;Store it away SUB B,IMPIBS ;Get # words read into datagram buffer MOVEI B,(B) MOVE A,IMPIDP ;Get pointer to IP datagram buffer we're using SETZ C, ;Say zero offset to IP header. MOVE J,IMPCSH ;Set idx to host-table entry dgm received from. PUSHJ P,IPRDGM ;Hand off rcvd datagram to IP SETZM IMPIDP ;Clear PI level pointer JRST IMPIR1 ;Return from PI level, setting up for next msg IFN KSIMP,[ ;Set HOST READY. From SYS job only, please, loops waiting. ; IMPHRS: IORDI T,%LHICS TRNN T,%LHRDY ;Can we mung? BUG IORI T,%LHHRC\%LHSE ;Turn on HR. SE prevents dropping messages IOWRI T,%LHICS MOVEI A,777777 ;I don't know why this takes so long. IMPHR1: IORDI T,%LHICS ;Get the bits back TRNE T,%LHHR ;LHDH thinks host ready is ready RET ;HR line set SOJG A,IMPHR1 ;Timed out yet? BUG CHECK,[IMP: Timed out setting Host Ready] RET ;Start listening for new input from IMP ; IMPIST: HRREI T,-IMPBFS*2 IOWRI T,%LHIWC ;Read up to a buffer full of data MOVEI T,+<4*> IOWRI T,%LHICA ;Read data to here MOVEI T,%LHIE\%LHHRC\%LHSE\%LHGO ;Interrupt, store data, go IOWRI T,%LHICS ;Start read RET ;Move data from IMP DMA buffer to somewhere else, reformatting as we go. ; IMBLKI/ BLKI ptr -count,,dest-addr-1 ; Updates IMBLKI ; Bashes A,B,C,D,E ; Sets IMPLW in TT iff last word we read was last word available. IMPGRI: IFN IMPDBG,[ SKIPL IMPIBP ;Make sure we have something to give BUG HALT,[IMP: IMPGRI called with no more data] ] MOVE B,IMPIBP ;Get current count,,location in input bfr. IMPGR1: MOVE C,(B) ;Get data word from message LDB D,[.BP <377_26.>,C] ;Get Byte 2 LDB E,[.BP <377_8.>,C] ;Get Byte 4 LSH C,10. ;Shift so Byte 1 is correct DPB D,[.BP <377_20.>,C] ;Put Byte 2 LDB D,[.BP <377_10.>,C] ;Get Byte 3 DPB E,[.BP <377_4.>,C] ;Put Byte 4 DPB D,[.BP <377_12.>,C] ;Put Byte 3 MOVEM C,1(A) ;Store word. It's a BLKI ptr, remember? AOBJP B,IMPGR2 ;Incr source, exit if done AOBJN A,IMPGR1 ;Incr dest, maybe loop for more ;Here if ran out of desstination buffer space TRZ TT,IMPLW ;Didn't see last word MOVEM A,IMBLKI MOVEM B,IMPIBP RET ;Here if ran out of source data IMPGR2: IORI TT,IMPLW ;Say we read last word AOBJN A,.+1 ;Adjust BLKI ptr for last word read MOVEM A,IMBLKI ;Update IMBLKI for everyone else MOVEM B,IMPIBP RET ];IFN KSIMP ;Here if error during IMP message transfer ; IFN KAIMP,[ IMPBER: SKIPGE IMPUP ;Skip if up, or thought to be broken JRST IMPBE2 ;Already down, let it come up in peace MOVSI J,SCLNET ;Thinks it's up, reset it IORM J,SUPCOR ;By getting system job to run SYSNET CONI IMP,IMERCN ;Record if imp error flip/flop set SETOM IMPUP ;IMP is down SETZM IMPTCU ;And not trying to come up IFN INETP,.ERR IP/TCP code needs handling for IMP crashing. IMPBE2: SETZM IMPPIA ;No PI expected CONO IMP,0 ;Clear IMP BUG INFO,[IMP: Ready line flapped, resetting] JRST IMPEX ];IFN KAIMP IFN KSIMP,[ ;Input side saw ready line flap IMPIER: SKIPE IMPUP ;Is the IMP supposed to be up? JRST IMPIE1 ;No, handle differently IORDI T,%LHICS ;Was up; get status BUG INFO,[IMP: Input RDY error, Status ],OCT,T JRST IMPRST ;And go request a full cycling of IMP IMPIE1: AOS T,IMPIEC CAIG T,10. ;Huge number of errors whiile down? JRST IMPIRT ;No, just ignore this input and start another SETZM IMPIEC ;Reset BUG INFO,[IMP: Excessive input errors while down] JRST IMPIRT ;Output side flapped IMPOER: SKIPN IMPUP ;IMP up? JRST IMPOE1 ;Running, request a full reset MOVE T,IMPOS CAIE T,%ISONP ;Were we sending a NOP? BUG CHECK,[IMP: Confusing output error] SOS IMNOPC ;Add another NOP to make up for this one SETZM IMPOS JRST IMPOB0 ;Go send it IMPOE1: IORDI T,%LHOCS BUG INFO,[IMP: Output RDY error, Status ],OCT,T ;;; JRST IMPRST IMPRST: BUG INFO,[IMP: Ready line flapped, resetting] MOVSI J,SCLNET ;Thinks it's up, reset it IORM J,SUPCOR ;By getting system job to run SYSNET IORDI T,%LHICS HRLZM T,IMERCN IORDI T,%LHOCS HRRM T,IMERCN SETOM IMPUP ;IMP is down MOVEI T,1 MOVEM T,IMPTCU ;But trying to come up (sysjob poked) IFN INETP,.ERR IP/TCP code needs handling for IMP crashing. JRST IMPEX ];IFN KSIMP ;;; IMP Blockage avoidance ; The current IMP software will not accept more than 8 active ; messages to a single host; attempting to send a 9th message will block ; ALL output to the interface, until the first message has been ack'd ; by means of one of the following message types: ; Type 5, RFNM - Message delivered OK ; Type 7, Host dead - transmit failed ("permanent") ; Type 8, Error in data - interface spazzed ; Type 9, Incomplete Transmission - temporary failure ; If for some reason the first message simply becomes lost, the IMP timeout ; (and blockage) can last for up to 30-45 seconds. ; More details in BBN Report 1822. ; ITS attempts to fix this by keeping a count of active un-ACKed ; messages for each host it is communicating with. A timeout is also ; associated with each host; if output to a given host is blocked by ITS ; because there are 8 active messages, trying to send a 9th message ; will check the last-RFNM-received time and if this was more than ; 30 or so seconds then the IMP is probably not giving us what it should ; and we should reset things for that host. %IMPMA==:8. ; # of maximum active IMP messages allowed ; IMPBLI, IMPBLD - routines to hack active-message counts, called via JSP T, ; IMPBLD decrements count. ; IMPBLI increments count and skips if successful (else failed, ; and must NOT output another message to this host!) ; Also clobbers Q. ; IMPBLI: AOS Q,IMPHTC(H) CAIGE Q,%IMPMA ;Trying to send max or more messages? JRST 1(T) ;No, can return safely. CAIG Q,8. ;Is this the maximum # allowed? JRST [ MOVE Q,TIME ;Yes, set up blockage timeout ADDI Q,60.*30. ; for one minute. MOVEM Q,IMPHTT(H) JRST 1(T)] ;And allow this one to be sent ; Trying to send too many messages, block it (check for timeout though) SOS IMPHTC(H) ;Restore original count AOS IMNBLK ;Increment # of times softwarily blocked. MOVE Q,IMPHTT(H) CAML Q,TIME ;See if timeout still in the future JRST (T) ;Yes, just take failure-return to block. BUG INFO,[IMP: RFNM-wait timeout! Hst=],OCT,IMPHTN(H) SETZM IMPHTC(H) ;This may be dangerous... oh well. SETZM IMPHTT(H) JRST (T) ;Block one last time, next try will win. ;Decrement block count on reciept of any kind of ACK ; IMPBLD: SOSL Q,IMPHTC(H) JRST IMPBL2 BUG INFO,[IMP: neg RFNM-wait cnt, Hst=],OCT,IMPHTN(H) SETZB Q,IMPHTC(H) IMPBL2: CAIL Q,8.-1 ;If we were blocking on this host, CALL IMPIOS ;Ensure IMP output started up so blocked stuff JRST (T) ; gets sent promptly. SUBTTL ARPANET OUTPUT INTERRUPT LEVEL IFN KAIMP,[ ; See comments at IMPINT for a description of the overall IMP interrupt ; structure. Output is simpler than input, however. ; Each IMP message is output at PI level 1 except for the initial DATAO; ; the setup and takedown for each message is done at PI level 2. ; The code on this page is not referenced by anything outside the page ; except interrupt vector setup at IMPINI (to IMPOBK) and IMOB9 (to IMPCH1). ; IMPCH1 - PI 1 Output-Done interrupt, from IMPOLC. ; Comes here when last word DATAO'd has been sent to IMP. EBLK IMPCH1: 0 BBLK MOVEM A,IMPOLC ;Save A MOVE A,IMOPNT IMCH1A: SKIPGE A,IMOLST(A) ;Get next "instruction" JRST IMCH1B ;Jump if it's a BLKO pointer CAILE A,3 ;Ensure valid operation BUG HLT,[IMP: Bad command in output list.] XCT IMCH1I(A) ;Do it AOS A,IMOPNT ;Still here? Point to next operation JRST IMCH1A ;and loop to do it. IMCH1I: JRST IMCH1C ;0 Stop - end of output list CONO IMP,IMPLHW+IMPCHN ;1 Set Last Word CONO IMP,IMO32S+IMPCHN ;2 Set 32-bit mode JFCL ;3 NOP IMCH1B: MOVEM A,IMBLKO ;Set up BLKO - store the pointer MOVE A,[JSR IMCH1D] ;Set dispatch for BLKO runout MOVEM A,IMPOLC+1 MOVE A,[BLKO IMP,IMBLKO] EXCH A,IMPOLC ;Store the BLKO and restore A AOS IMOPNT ;Increment output list ptr past this op. JRST 12,@IMPCH1 ;Will interrupt immediately for first BLKO ;word, since Output-Done wasn't cleared. ; PI 1 Output-Done, from IMPOLC+1 (BLKO runout) ; Final word of the BLKO pointer is now in interface, being sent ; to IMP, and Output-Done flag is off. EBLK IMCH1D: 0 BBLK MOVEM A,IMPOLC MOVE A,[JSR IMPCH1] ;Interrupt back when output of final word done EXCH A,IMPOLC JRST 12,@IMCH1D ; Here from IMPCH1, PI 1 Output-Done interrupt ; Output list has hit "stop" operation (previous op had better be ; 1 to set Last-Host-Word!) ; This code reverts control back to PI level 2 (IMPOBK). ; IMCH1C: SETZM IMPOH ;Say output side doesn't need PI 1 anymore MOVEI A,NETCHN ;And set exit PIA to 2, SKIPL IMPIH ;unless input side still needs PI 1 MOVEM A,IMPPIA ;Set it. CONO IMP,@IMPPIA SETOM IMPO ;Tell IMPINT we have output-done interrupt. MOVE A,[JSR IMPOBK] ;Point PI 1 channel at switch-PIA routine, EXCH A,IMPOLC JRST 12,@IMPCH1 ; PI 1 Output Done interrupt, when we should really be interrupting ; at IMPINT on PI 2. EBLK IMPOBK: 0 BBLK SETOM IMPO ;Tell IMPINT what kind of interrupt CONO IMP,NETCHN ;Reset PIA to 2 JRST 12,@IMPOBK ];IFN KAIMP IFN KSIMP,[ ;First-level interrupt handling, from hardware dispatch. IFN NETCHN-UTCCHN,.ERR Interrupt channel mismatch at IMPOBK EBLK IMPOBK: 0 BBLK JSR UTCSAV ;Save AC's, get a stack IORDI TT,%LHOCS ;Get CS register TRNE TT,%LHERR\%LHNXM ;Interface lost? BUG HALT,[IMP: O NXM] TRNE TT,%LHMRE ;Somebody bounce a ready line? JRST IMPOER TRNN TT,%LHRDY ;Device ready for new operation? BUG HALT,[IMP: Output device not ready] TRZ TT,%LHIE\%LHGO ;Is this right? IOWRI TT,%LHOCS AOS IMPOAC ;Output active. Reset when no more output ;JRST IMPOBZ ;Falls through ];IFN KSIMP ; IMPOBZ - PI 2 (NETCHN) "Output Done" interrupt, via IMPINT (or IMPOBK on KS) ; KA/KL, come here when we have finished sending stuff out at PI 1, ; also when something wants output to start and tickled the "Done" ; flag. ; TT/ IMP CONI word. ; ; KS, come here from output done interrupt if no errors, or when ; someone wants to start output. ; IMPOBZ: AOS IMCT3 SKIPL B,IMPOS CAIL B,IMPODL BUG HALT,[IMP: Bad output state] JRST @IMPODT(B) IMPODT: OFFSET -. %ISODL:: IMPOB0 ; 0 Idle, look for something to send %ISONP:: IMPOB1 ; 1 Finished NOP %ISOID:: IMPOB2 ; 2 Finished IP datagram messge %ISOIL:: IMPOB3 ; 3 Finished IP leader (KS10 only) IMPODL::OFFSET 0 ;Return from all output finished interrupts ; KA interface, we don't turn off Output Done unless there is no more ; output to go. Thus if there is more output we will immediately ; re-interrupt to look for it. ; ; KS, we explicitly look here for more output to send ; IMORET: SKIPE IMPOS BUG HALT,[IMP: Bad state at output finish] IFN KAIMP,[ JRST IMPRET ] IFN KSIMP,[ SKIPGE IMPOAC ;Output still active? JRST IMPRET ;Yes or no, don't look for more output ;JRST IMPOB0 ;Fall through to try for more ];IFN KSIMP ; Idle - Look for output to send. First ensure we can send stuff, ; then try things in the order: ; (1) Send NOP if net coming up ; (2) Check IP datagram queue ; IMPOB0: HRRZ T,IMPUP CAIE T,-2 ;Don't say it's up when it's still going down CAIN T,1 ;or when it is broken JRST IMPOBN ; First check to see if NOP needs to be sent. AOSG IMNOPC ;Check to see if sending NOPs JRST IMONOP ;Output a NOP SETZM IMPUP ;Say IMP is up SETZM IMPTCU ;Say no longer trying to come up ; Now see if there is any real traffic to send PUSHJ P,IPGIOQ ;Check IP. Get IP IMP output queue entry if any JRST IMPOBN ;Nothing there, we're done. ; Returns A/ ptr to IP dgm struct ; B/ BLKO pointer to 32-bit words ; C/ Arpanet address ; ;KA/KL interfaces build an output list which is interpreted ;by code running at PI 1. The output list should be set up as: ;IMOLST: -2,,IMOLDR ; Send 2nd and 3rd word of IMP leader ;IMOBK1: Output BLKO ; Send datagram minus last word ;IMOBK2: 1 ; Set last IMP bit ;IMOBK3: -1,,lstwd-1 ; BLKO to last word of datagram ; 0 ; Stop ; ;KS interface uses locations in IMOLST to store data for various ;output routines, which are dispatched to at PI 2 by the state ;machine at IMPOBZ. These locations are: ;IMOLST: Unused ;IMOBK1: Datagram BLKO ;IMOBK2: Unused ;IMOBK3: Unused IMOB01: MOVEM A,IMPODP ;Save ptr to datagram being output AOS IMNIPO ;# of IP datagrams sent IFN KAIMP,[ MOVE D,[-2,,IMOLDR] ;IMP leader is always three words output MOVEM D,IMOLST ; from IMOLST (first with DATAO) ADD B,[1,,] ;Reduce BLKO count by one MOVEM B,IMOBK1 ;Store in output list HLRO D,B ;Get -<# wds-1> MOVN D,D ;Get <#wds-1> ADDI D,(B) ;Get addr for last-word BLKO HRROM D,IMOBK3 ;Store -1,,lastwd-1 ] IFN KSIMP,[ MOVEM B,IMOBK1 ;Save BLKO pointer for IP datagram ] ;Output list set up, now must put together the IMP leader in IMOLDR. MOVE B,[17_10.,,0] ;Regular message MOVEM B,IMOLDR LSH C,4. ;Move net address to correct field MOVEM C,IMOLDR+1 ;Set up second word MOVSI B,233_10. ;IP link # in left 8 bits MOVEM B,IMOLDR+2 ;Set up third word ;IMP leader set up, start output IFN KAIMP,[ CONO IMP,IMO32S ;Set 32 bit mode, clear PIA DATAO IMP,IMOLDR ;Start it going! MOVEI C,%ISOID ;State = outputting IP datagram. ] IFN KSIMP,[ MOVE A,[-3,,IMOLDR-1] ;IMP leader is three words output from IMOLDR PUSHJ P,IMOST ;Go set up and start output MOVEI C,%ISOIL ;Remember we are outputting IP leader ] ;Here after output of any kind started ; IMOB9: MOVEM C,IMPOS ;Save current output state IFN KAIMP,[ SETZM IMOPNT ;Initialize output list pointer SETOM IMPOH ;Output side wants IMP to run on channel 1 MOVEI A,IMPCHN MOVEM A,IMPPIA MOVE C,[JSR IMPCH1] ;Set up handler for CH1 interrupts MOVEM C,IMPOLC ] JRST IMPRET ;Couldn't find anything to output IMPOBN: SETOM IMPOAC ;No more output IFN KAIMP,[ CONO IMP,IMPODC ;Clear Output-Done interrupt bit, so we won't ] ;immediately re-interrupt to start next output JRST IMORET ;IMONOP - Send a NOP, here from IMPOBZ only. ; IMONOP: IFN KAIMP,[ MOVEI A,IMPNOP ;Get address of NOP leader MOVEI B,1 ;No text, but one extra wd (to make BLKO win) CONO IMP,IMO32S ;Put IMP in 32-bit mode, Clear PIA DATAO IMP,(A) ;Output first leader word MOVEI C,(A) ;Set up BLKO pointer for 2nd word of NOP HRLI C,-1 ;Including count MOVEM C,IMOLST AOS C ;Now a BLKO ptr for third word MOVEM C,IMOBK2 ;Save it in output list MOVEI C,1 ;Command to set last IMP bit MOVEM C,IMOBK1 ;Set that in list SETZM IMOBK3 ;End of output list MOVEI C,%ISONP ;State for control return to NETCHN JRST IMOB9 ;Falls through ];IFN KAIMP IFN KSIMP,[ MOVE A,[-3,,IMPNOP-1] ;Get address of a BLKO word for NOP leader PUSHJ P,IMOSTL ;Start output to IMP MOVEI C,%ISONP ;State for control return to NETCHN JRST IMOB9 ;Go finish up interrupt ] ;Prefabricated NOP Host-IMP leader IMPNOP: 17_10.,,4_4 ;New format, type 4 = NOP 0 0 ;No padding required on regular messages ;Finished sending NOP, from IMPOBZ ; IMPOB1: SETZM IMPOS ;Reset state JRST IMORET ;No, was a NOP. Done. ;Was sending IP datagram, from IMPOBZ ; IMPOB2: SETZM IMPOS ;Reset output state MOVE A,IMPODP PUSHJ P,IPIODN ;Tell IP level that datagram was output SETZM IMPODP JRST IMORET ;Go see if there is anything else to do. IFN KSIMP,[ ;Was sending IP leader, from IMPOBZ. Start actual datagram output ; IMPOB3: MOVE A,IMOBK1 ;Get BLKO word set up before PUSHJ P,IMOSTL ;Go start output MOVEI C,%ISOID ;Remember sending IP datagram JRST IMOB9 ;Go clean up and dismiss ];IFN KSIMP IFN KSIMP,[ ;Output startup routines for KS IMP. Call from NETCHN level or interrupts off. ; IMOST - start output ; IMOSTL - start output for last segment of message ; A/ BLKO word describing output. ; Bashes A,B,C,D,E,T,TT ; IMOSTL: TLOA T,-1 ;Remember which entry point IMOST: SETZ T, IFN 0,[ HLRE TT,A ;Get count MOVN C,TT ;Make positive CAILE C,IMPBFS ;Message fits in output buffer? JRST IMOSTE HRLZI B,1(A) ;Build BLT arg IO_buffer,,IMPOBF HRRI B,IMPOBF BLTBU B,IMPOBF-1(C) ;Move and reformat data ] IFN 1,[ AOS A ;Point to first data address HLRE TT,A ;Get count MOVN C,TT ;Make positive CAILE C,IMPBFS ;Message fits in output buffer? JRST IMOSTE MOVNI B,-IMPOBF(A) ;B = HRLI B,A ;B = (A) IMOST1: MOVE C,(A) ;Get data word from message LDB D,[341000,,C] ;Get Byte 1 LDB E,[141000,,C] ;Get Byte 3 LSH C,6. ;Shift so Byte 2 is correct DPB D,[221000,,C] ;Put byte 1 LDB D,[121000,,C] ;Get Byte 4 DPB D,[101000,,C] ;Put Byte 4 DPB E,[001000,,C] ;Put Byte 3 MOVEM C,@B ;Store reformatted word in temp buffer AOBJN A,IMOST1 ;Do more words if there are any ] ASH TT,1 ;Convert PDP10 word count to unibus word count IOWRI TT,%LHOWC ;Tell the IMP interface MOVEI TT,+<4*> IOWRI TT,%LHOCA ;Unibus address of output buffer MOVEI TT,%LHIE\%LHGO ;IMP Interface interrupt enable, GO SKIPE T ;This the last segment in the message? IORI TT,%LHELB ;Yep, turn on EOM bit in interface IOWRI TT,%LHOCS ;Start DMA transfer POPJ P, ;And forget it. IMOSTE: BUG CHECK,[IMP output msg too big],DEC,C POPJ P, ;Ignore overly large msg ];IFN KSIMP SUBTTL ARPANET CLOCK LEVEL OVHMTR IMP ;NETWORK INTERRUPT LEVEL (NOT STYNET STUFF) IMRSTO: RET ;Nothing to do any more? ;NETHST (HOST INFO) ; ARG 1 - HOST => VAL 1 - STATUS, VAL 2 - HOST NUMBER ; ARG 1 - -1 => VAL 1 - (STATUS), VAL 2 - OUR HOST NUMBER ;NOT CURRENTLY IMPLEMENTED- ARG 1 - -1, ARG 2 - OUR GOING-DOWN REASON ; ANETHST:HRRE T,A ;Let immediate -1 win (777777 not a valid host) AOJE T,ANETH2 ;Jump if want local status and host number MOVE T,A JSP J,STDHST ;Standardize and error-check host number MOVE B,T ;Return new format TLO B,(NW%ARP) MOVEI H,LIMPHT-1 CONO PI,NETOFF ;Do we have status for this host? CAME T,IMPHTN(H) ;Scan table SOJGE H,.-1 JUMPGE H,ANETH1 ;Yes, return it CONO PI,NETON ;No, have to go get it MOVEM T,SRN3(U) POPJ P, ;Oh, too bad ;Here to return status of foreign ARPAnet host ANETH1: MOVE A,IMPHTB(H) ;Get status CONO PI,NETON EXCH A,B CALL CVH2NA ;Convert to HOSTS2 for compat EXCH A,B JRST LSWCJ1 ;Return IMSOC, NETLST if not done already ;Here to return our status, host ANETH2: REPEAT 0,[ CAIL W,2 ;(This is a crock) MOVEM B,NTHDSW ;If 2 args, set our reason for going down. ] SKIPE IMPUP ;Fake up our status TDZA A,A ;We're down MOVSI A,2000 ;We are up MOVEI B,IMPUS ;And our host umber JRST POPJ1 ;NETIMP (REASON,TIMEDOWN,TIMEUP) READ/SET ; ANETIM: JUMPLE W,ANETM1 ;No args, return current data CAIGE W,3 ;Must have 3 args if any JRST OPNL30 MOVEM A,IMPDWN ;Set data MOVEM B,IMPDWN+1 MOVEM C,IMPDWN+2 JRST POPJ1 ANETM1: MOVE A,IMPDWN ;Get data to return MOVE B,IMPDWN+1 MOVE C,IMPDWN+2 SKIPE IMPUP ;Note current condition of IMP, too TLO A,400000 JRST POPJ1