;TITLE D36COM - Common Routines for DECnet-36 ;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 1976,1985,1986. ;ALL RIGHTS RESERVED. SUBTTL V. Brownell, W. Nichols & Tarl Neustaedter ;This is the common routine package for DECnet-36. SEARCH D36PAR,MACSYM IFN FTOPS20,< SEARCH SCAPAR > ;END IFN FTOPS20 SALL IFN FTOPS10,< .CPYRT<1976,1986> > ;END IFN FTOPS10 IFN FTOPS20,< SEARCH PROLOG TTITLE D36COM,,< - Common Routines for DECnet-36> > IFN FTOPS10,< SEARCH F,S TITLE D36COM - Common Routines for DECnet-36 > ENTRY D36INI ;DEFINE AN ENTRY POINT WHICH MUST BE CALLED, ; SO THAT WE ARE GUARANTEED THIS WILL LOAD D36SYM ;SET UP D36 SPECIFIC PARAMETERS IFNDEF FTD36MM,FTD36MM==1 ;Use DECnet-36 memory manager FTBYTBLT==FTOPS20 ;NON-ZERO TO USE MONITOR-MONITOR BYTE BLT DBGS2==FTOPS20 ;NON-ZERO TO DO SAVEAC's OF Q1/Q2 FOR ROUTINES ; USED BY LLMOP FTFIXCOR==0 ;NON-ZERO TO FORCE PHYSICALLY CONTIGUOUS ; BUFFERS. REQUIRED BY NISRV ONCE UPON A TIME. IFN FTOPS10,<$RELOC> XRESCD ;RELOC TO HIGHSEG (RSCOD PSECT ON TOPS-20) SUBTTL Table of Contents ; Table of Contents for D36COM ; ; ; Section Page ; 1. Table of Contents. . . . . . . . . . . . . . . . . . . 2 ; 2. Definitions ; 2.1. External References . . . . . . . . . . . . . 3 ; 2.2. Core manager data structures. . . . . . . . . 4 ; 2.3. Mongenable parameters . . . . . . . . . . . . 5 ; 3. Data Storage . . . . . . . . . . . . . . . . . . . . . 6 ; 4. Definitions ; 4.1. Memory Manager Tables . . . . . . . . . . . . 7 ; 5. MSDs ; 5.1. Initialize MS pointer for MB input. . . . . . 9 ; 5.2. Initialize MS for input . . . . . . . . . . . 10 ; 5.3. Set up MSD for input on received buffer . . . 11 ; 5.4. Initialize MSD for output . . . . . . . . . . 12 ; 6. DNSBP ; 6.1. Byte routines ; 6.1.1. Store a byte pointer . . . . . . . . 13 ; 7. DNF2WG ; 7.1. Byte routines ; 7.1.1. Fetch a two word global from an MSD. 14 ; 8. MSDs ; 8.1. Byte routines ; 8.1.1. Get a byte . . . . . . . . . . . . . 15 ; 8.1.2. Get two bytes. . . . . . . . . . . . 16 ; 8.1.3. Get HI-ORDER 4 bytes of Ethernet Addr 17 ; 8.1.4. Get six byte Ethernet Address. . . . 18 ; 8.1.5. Get two bytes from specified position 19 ; 8.1.6. Get an extensible field. . . . . . . 20 ; 8.1.7. Get a byte, skip if non-extensible . 21 ; 8.1.8. Put a byte into message. . . . . . . 22 ; 8.1.9. Put two bytes in message . . . . . . 23 ; 8.1.10. Put two bytes to specified position. 24 ; 8.1.11. Put four bytes in message. . . . . . 25 ; 8.1.12. Put HI-ORDER 4 bytes of Ethernet Addr 26 ; 8.1.13. Put six byte Ethernet Address. . . . 27 ; 8.1.14. Put an extensible field into message 28 ; 8.1.15. Put some zero bytes. . . . . . . . . 29 ; 8.1.16. Skip some bytes. . . . . . . . . . . 30 ; 8.1.17. Go Backwards some number of bytes. . 31 ; 8.2. Read and Goto Position. . . . . . . . . . . . 32 ; 8.3. Link a Message Segment into a Message Block . 34 ; 8.4. Copy message block. . . . . . . . . . . . . . 35 ; 8.5. Calculate length of a whole message . . . . . 36 ; 8.6. Calculate Length of Message Segment . . . . . 37 ; 8.7. DNMINI - Initialize an allocated message block 38 ; 8.8. DNCMSD - Copy MSD chain to contiguous block . 39 ; 9. Buffers ; 9.1. Copy buffer to a message segment. . . . . . . 40 ; 9.2. Copy message data to a buffer . . . . . . . . 41 ; 10. BYTBLT - Non fancy versions. . . . . . . . . . . . . . 42 ; 11. BYTBLT - Fancy version . . . . . . . . . . . . . . . . 43 ; 12. Buffers ; 12.1. Copy user buffer to a message segment . . . . 54 ; 12.2. Copy message data to a user buffer. . . . . . 55 ; 13. Core manager ; 13.1. Smear a block of memory with value. . . . . . 56 ; 13.2. Copy some words . . . . . . . . . . . . . . . 57 ; 13.3. Get Some Words. . . . . . . . . . . . . . . . 58 ; 13.4. Get Some Zeroed Words . . . . . . . . . . . . 59 ; 13.5. Free Some Words . . . . . . . . . . . . . . . 60 ; 13.6. Get a DECnet-36 message block . . . . . . . . 61 ; 13.7. Free a DECnet-36 message block. . . . . . . . 63 ; 13.8. Fixed size block allocation entry points. . . 64 ; 13.9. Memory manager initialization code. . . . . . 66 ; 13.10. Increment count of emergency buffers. . . . . 68 ; 13.11. Return number of blocks available (for router) 69 ; 13.12. Get a Block from a Free Pool. . . . . . . . . 70 ; 14. DNMCUB - Check for trashed UBL . . . . . . . . . . . . 72 ; 15. Core manager ; 15.1. Checking routines for debugging only. . . . . 73 ; 15.2. Check pointer for validity. . . . . . . . . . 74 ; 16. Time ; 16.1. Get current time in ms. . . . . . . . . . . . 76 ; 17. Network management ; 17.1. NTPARM - parameters . . . . . . . . . . . . . 77 ; 17.2. NTCTRS - counters . . . . . . . . . . . . . . 78 ; 18. Trace ; 18.1. Interface for exec-mode trace.. . . . . . . . 79 ; 18.2. SCAN's output routines. . . . . . . . . . . . 80 ; 18.3. Routine store character in shared buffer. . . 81 ; 19. TOPS10 ; 19.1. AC save routines. . . . . . . . . . . . . . . 82 ; 20. Kontroller data. . . . . . . . . . . . . . . . . . . . 83 ; 21. Initialization routines. . . . . . . . . . . . . . . . 84 ; 22. DCNJB0 - DECnet periodic checks. . . . . . . . . . . . 85 ; 23. NMX ; 23.1. Privilege checking routine. . . . . . . . . . 86 ; 23.2. Time stamp a queued even block. . . . . . . . 87 ; 24. TESTSB ; 24.1. Assert that Code is Running in section 1. . . 90 ; 25. TOPS20 ; 25.1. User mode checking routines.. . . . . . . . . 91 ; 26. End of D36COM. . . . . . . . . . . . . . . . . . . . . 92 SUBTTL Definitions -- External References ;External monitor symbols EXT %RTBSZ ;Default executor block size (STG) EXT %DLBSZ ;Default maximum buffer size ;External monitor routines EXT RTN EXT RSKP EXT XBLTA EXT XBLTAT ;References into layers. EXT SCJINI ;Initialize SCJSYS EXT SCTINI ;Initialize session control, NSP and ROUTER EXT SCTSEC ;SCLINK once-a-second routine EXT NSPJIF ;LLINKS once-a-jiffy routine EXT RTRON ;To turn ROUTER on EXT RTRJIF ;ROUTER once-a-jiffy routine EXT RTRSEC ;ROUTER once-a-second routine EXT DNDJIF ;DNADLL once-a-jiffy routine EXT NSPCG ;TO TELL NSP ABOUT CONGESTION EXT NSPCR ;.. EXT NSPJB0 ;NSP periodic checks EXT NRTINI ;Initialize NRT ;AC definition. XP FL,FREE1 ;NEEDED BY MEMORY MANAGER. SAVES POINTER HERE XP LH.ALF,<777777,,0> ;LEFT HALF QUANTITY ;Explanation of Byte Pointer Usage: ; ;In order to make the byte pointers in MDPTR and MDAUX work on ;both extended and non-extended machines, we build indexed byte ;pointers, with a Y field of zero initially. The byte pointers ;are always indexed by T6, which is loaded from MDALA at the ;beginning of every DNxxx routine. VGNPTR is used to point ;readers to this comment. VGNPTR==: SUBTTL Definitions -- Core manager data structures BEGSTR FB WORD NXT ;Forward pointer in a free block ENDSTR BEGSTR CH ;Core handler structure WORD BOT ;Pointer to free pool start WORD PTR ;pointer to first free block WORD AVL ;Number of available blocks HWORD LWM ;;; Low water mark HWORD REQ ;;; Size requested ;The following 3 fields are expected to be in the last word, see CHBLKS FIELD CON,1 ;Set if this block type subject to congestion FIELD NUM,17 ;Total blocks, alloc & unalloc. HWORD SIZ ;Size of blocks. ENDSTR ;On TOPS10, structure MI is referenced by COMMON.MAC with HRRZ and other ;non-BEGSTR instructions so don't change MI rashly! BEGSTR MI HWORD SIZ ;SIZE (IN WORDS) OF THE BLOCK HWORD CNT ;NUMBER OF BLOCKS ENDSTR SUBTTL Definitions -- Mongenable parameters ;These are some default router parameters: RADIX 10 ;NETWORK MANGLEMENT IS DECIMAL DEFINE MP(SYMBOL,VALUE),< ;SYMBOLS DEFINED WITH MP ARE MONGENABLE IFN FTOPS10, ;;DEFINED IN COMNET ON TOPS-10 IFN FTOPS20, ;;AND THUS NOT DEFINED HERE ON TOPS10 > IFN FTP4R,MP %RTMXN,1023 ;MAXIMUM NODE NUMBER MP %RTMX3,255 ;DEFAULT MAXIMUM NODE ADDRESS FOR ROUTER MP %RTTM3,<15*1000> ;DEFAULT HELLO FREQUENCY TIMER MP %RTTM4,<30*1000> ;DEFAULT NODE LISTENER TIMER MP %RTITM,<1*60*1000> ;INITIALIZATION TIMER MP %RTT3M,2 ;HELLO TIMER MULTIPLIER FOR NON-BROADCAST MP %RTB3M,3 ;HELLO TIMER MULTIPLIER - BROADCAST ADJACENCIES MP %RTADR,1 ;DEFAULT LOCAL ADDRESS MP %RTHOM,1 ;DEFAULT HOME AREA MP %RTRTY,RNT.L1 ;DEFAULT ROUTER TYPE (ROUTING) MP %RTCST,1 ;DEFAULT COST FOR CIRCUIT MP %RTMXR,16 ;Default maximum number of routers on an NI MP %RTBRA,32 ;MAXIMUM NUMBER OF BROADCAST ROUTER ADJACENCIES MP %RTBEA,64 ;MAXIMUM NUMBER OF END NODE ADJACENCIES MP %RTCTO,<60*1000> ;Endnode cache timeout MP %RTPRI,5 ;OUR PRIORITY TO BE THE DESIGNATED ROUTER MP %RTMXC,100 ;MAXIMUM LINE COST MP %RTMXH,16 ;MAXIMUM HOPS MP %RTMXV,20 ;DEFAULT MAXIMUM VISITS MP %RTTM1,<10*60*1000> ;DEFAULT MAXIMUM ROUTING MESSAGE INTERVAL (P-P) MP %RTBT1,<40*1000> ;DEFAULT MAXIMUM ROUTING MESSAGE INTERVAL (NI) XP %RTEHS,<2+7-6+21+4> ;Ethernet header size, composed of: ;+2 Ethernet padding bytes ;+7 Router Phase-IV pad bytes ;-6 corrects for assumed Phase III header ;+21 allows for full P-IV NI header ;+4 allows for 4 KLNIA CRC bytes (input) ; & for byte misalignment after BLT (output) XP %RTVER,2 ;VERSION OF ROUTER XP %RTECO,0 ;EDIT LEVEL OF ROUTER XP %RTCUS,0 ;CUSTOMER VERSION NUMBER ;These are LLINKS default parameter values: MP %NSDLY,<3*16> ;Delay factor MP %NSWGT,10 ;Delay weight MP %NSINA,120 ;Inactivity timer MP %NSRTH,10 ;Retransmission threshold MP %NSFLR,1000 ;Delay floor MP %NSRUF,10000 ;Delay roof MP %NSADL,2 ;ACK delay in seconds ;These are Session Control default parameter values: XP %SCHDR,<11+6> ;LENGTH OF HEADERS BELOW SESSION CONTROL ;11 IS MAX NSP HEADER LENGTH (PHASE IV) ;6 IS ARCHITECTURALLY DEFINED RTR HDR OVERHEAD XP %SCP2Q,1 ;PHASE II QUOTA MP %SCINT,<30*1000> ;INCOMING TIMER VALUE MP %SCOTT,<1*60*1000> ;OUTGOING TIMER VALUE RADIX 8 ;LCG IS OCTAL ;Keep these definitions here! They need to be defined in OCTAL radix. XP %RTHIO,<> ;HIORD AA-00-04-00(16) XP %RTRMA,<> ;Multicast ID "ALL ROUTERS" ; AB-00-00-03 XP %RTEMA,<> ;Multicast ID "ALL ENDNODES" ; AB-00-00-04 SUBTTL Data Storage RESDT ;Define static incarnation of DECnet-36 initialization block ASSUME IB.PH2,EQ,0 ASSUME IB.RTR,EQ,0 ASSUME IB.FCM,EQ,0 ASSUME IB.NAM,EQ,1 ASSUME IB.ADR,EQ,2 ASSUME IB.MXA,EQ,3 ASSUME IB.MXB,EQ,4 ASSUME IB.DGL,EQ,5 ASSUME IB.DBL,EQ,6 ASSUME IB.BIP,EQ,7 ASSUME IB.BSZ,EQ,10 IBBLK:: 0B!<%RTRTY>B!B ;IBFLG IFN FTOPS20,< SIXBIT /TOPS20/ ;IBNAM <%RTHOM>B!<%RTADR>B ;IBADR >; END IFN FTOPS20 IFN FTOPS10,< 0 ;IBNAM 0 ;IBADR >; END IFN FTOPS10 EXP %RTMXN ;IBMXA EXP ^D80 ;IBMXB EXP ^D0 ;IBDGL EXP ^D8 ;IBDBL EXP ^D50 ;IBBIP EXP %DLBSZ ;IBBSZ ; D36IFG::EXP 0 ;0 before DECnet initializes, ;+1 while -"- -"- ;-1 after -"- -"- DCNSTA::EXP DS.OFF ;INITIALLY OFF, STATES ARE IN D36PAR DNDEFS::EXP !! ;Flow control - Goal, Quota, Input percentage RTRADR::EXP %RTADR ;Our local address, setable with SETSPD RTRHOM::EXP %RTHOM ;Default area to which this ROUTER belongs RTRHIO::%RTHIO ;Hi-order DECnet Ethernet address RTRLOO::EXP 0 ;Low order part of Ethernet address (computed ; at startup by Router) RTRBSZ::%RTBSZ ;Default block size RTRMXN::%RTMXN ;MAXIMUM NODE NUMBER RTRMX3::%RTMX3 ;MAXIMUM PHASE III NODE ADDRESS EVSDRP::EXP 0 ;NON-ZERO TO HAVE ROUTER SNOOP ROUTING INFO RTRVER::%RTVER ;VERSION OF OUR ROUTER RTRECO::%RTECO ;EDIT LEVEL OF ROUTER RTRCUS::%RTCUS ;CUSTOMER ARGUMENT ;Freecore pointers ifn ftki10,< ;[JE] Put these back. DCNLOC::BLOCK 1 ;POINTER TO LOW LOCATION OF FREECORE DCNPTR::BLOCK 1 ;POINTER TO BIT MAP OF FREECORE >;ki10 IFN FTOPS10,< DCNTCR: BLOCK 1 ;TOTAL DECNET CORE REQUIREMENTS DCNCOR::BLOCK 1 ;POINTER TO DECNET CORE DCNVFF::BLOCK 1 ;DECNET FIRST FREE LOCATION >; END IFN FTOPS10 DCNEMR: BLOCK 1 ;EMERGENCY MESSAGE BLOCK THRESHOLD DCNTSB::BLOCK 1 ;TOTAL SYSTEM BUFFERS (SET UP IN D36INI) DCNCON::BLOCK 1 ;NON-ZERO IF SYSTEM IS CONGESTED DCNRSB::BLOCK 1 ;RESERVED BUFFERS, MODIFIED UNDER SYSPIF ; TO PROTECT AGAINST SCTRIB CALL FROM LLINKS DCNRHT::BLOCK 1 ;HIGH TIDE FOR DCNRSB DCNRIF::BLOCK 1 ;INPUT RESERVATION FAILURES DCNROF::BLOCK 1 ;OUTPUT RESERVATION FAILURES DCNCNG: DEC 5 ;CONGESTION MESSAGE BLOCK THRESHOLD DCNUCG: DEC 7 ;UNCONGESTION MESSAGE BLOCK THRESHOLD IFN FTOPS10,< EV96.0::0 ;DON'T LOG EVENT 96.0 DCNTIM: ^D10 ;DCNJB0 COUNTDOWN TIMER (SECONDS) >; END IFN FTOPS10 IFN FTTRACE!FTMINTrace,< ;;NOTE - ALL THESE VALUES MUST BE SET BY SNOOP. THERE IS NO CHECKING ;WHATSOEVER THAT THE MONITOR DOES ON THEM - IT MERELY USES THEM. ZERBPT::BLOCK 1 ;FIRST BYTE POINTER IN USER'S BUFFER CURBPT::BLOCK 1 ;CURRENT BYTE POINTER MAXBYT::BLOCK 1 ;MAXIMUM NUMBER OF BYTES TO USE IN BUFFER LASBYT::BLOCK 1 ;LAST BYTE TO USE IN BUFFER (.GT. MAXBYT) CURBYT::BLOCK 1 ;CURRENT BYTE POSITION IN BUFFER TRAJOB::BLOCK 1 ;NUMBER OF JOB DOING THE TRACE S.ETRA::BLOCK 1 ;ERROR TRACE BITS S.TRAC::BLOCK 1 ;THE ORDINARY TRACE MASK > ;END IFN FTTRACE!FTMINTrace XRESCD SUBTTL Definitions -- Memory Manager Tables ;Memory Management Definitions ;$NAM - Three-character name of block type ;$SIZ - Size of block in words, DNGRBL overhead added in DEFBLK macro ;$CNT - Number of blocks ;$CON - Flag saying this block type is subject to congestion control DEFINE BLKDFS,< ;; $NAM, $SIZ, $CNT, $CON IFN FTD36MM,< DEFBLK (SBL, ^D7, ^D145, ) ;;SMALL BLOCKS DEFBLK (ABL, ^D31, ^D250, ) ;;ARBITRARY BLOCKS DEFBLK (BBL, ^D78, ^D140, ) ;;SLIGHTLY LARGER ARB. BLOCKS ;Increase LBL's by 15. for multinode CI testing /mp DEFBLK (LBL, ^D510, ^D35, ) ;;LARGE BLOCKS ;; (These must fit on 1 page) IFE FTHMMEM,< DEFBLK (VBL, ^D2058, ^D3, ) ;;VERY LARGE BLOCKS > IFN FTHMMEM,< ;;One extra for MRQTAB DEFBLK (VBL, ^D2058, ^D4, ) ;;VERY LARGE BLOCKS > >;END IFN FTD36MM ; DEFBLK (EBL, ^D60, ^D4, ) ;;EVENT BLOCKS DEFBLK (MBL, MB.LEN, ^D100, CONGEST ) ;;MESSAGE BLOCKS DEFBLK (UBL, 0, ^D80, CONGEST ) ;;USER-DATA BLOCKS >;END DEFINE BLKDFS IFE FTD36MM, ;NEEDED IN DNSWDS ;The following page(s) expand this macro to define the tables and symbols ;used by the memory manager (DNINIM, DNGRBL and DNFRBL) IFE FTLSTCOR, IFN FTLSTCOR, ;Now define symbols for $SIZ and $CNT DEFINE DEFBLK($nam,$siz,$cnt),< $nam'SIZ==:$siz+OVHWDS ;;SIZE OF BLOCKS IN DECIMAL WORDS + OVERHEAD $nam'CNT==:$cnt ;;NUMBER OF BLOCKS ..CORS==..CORS+<$nam'SIZ*$cnt> >;END DEFINE DEFBLK ..CORS==0 ;INITIALIZE TOTAL MEMORY COUNTER BLKDFS ;DEFINE SYMBOLS IFN CH.LEN-CH.SIZ-1, IFN CH.NUM-CH.SIZ, IFN CH.CON-CH.SIZ, DEFINE DEFBLK($nam,$siz,$cnt,$con),< ..CON==0 ;;ASSUME NO CONGESTION CONTROL ON THIS BLK TYPE IFNB <$con>,<..CON==1> ;;IF CONTROLLED, SET 1-BIT FLAG $nam'CB: BLOCK CH.LEN-2 EXP ,CHLWM)> EXP ,CHCON)>!,CHSIZ)>!,CHNUM)> PURGE ..CON >;END DEFINE DEFBLK RESDT CHBLKQ: CHBLKN ;FOR GETTAB PURPOSES. DO NOT MOVE CHBLKS::!BLKDFS ;VECTOR OF CH BLOCKS CHBLKN==<.-CHBLKS>/CH.LEN ;NUMBER OF CH BLOCKS WE HAVE IFN FTHMMEM,< MRQTAB::BLOCK 1 ;Pointer to memory request table MRQMAX: BLOCK 1 ;Maximum table address > ;END FTHMMEM XRESCD SUBTTL MSDs -- Initialize MS pointer for MB input ;DNGINI - Initialize MS for input (DNGxxx routines) ; ; Call: ; T1/ Pointer to Input Message Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,T2,MS ; ;Note: We are assuming that someone has set up the dynamic byte ;pointer and the count when the message came in (usually the DLL will ;have done this). The DNGxxx routines use the dynamic byte pointer and ;count to go through the message. ; ;Callers assume that is it OK to call this routine more than ;once on a given message. ; ;This routine works for MB's only. INTERNAL DNGINI XRESCD DNGINI: XMOVEI MS,IN.MSD(T1) ;POINT TO THE INPUT MSD RET ; AND RETURN SUBTTL MSDs -- Initialize MS for input ;DNGMSI - Initialize an MSD for a raw (empty) buffer ; ; Call: ; T1/ MSD address ; T2/ Buffer Address ; T3/ Buffer Length in bytes ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,MS ; XRESCD DNGMSI:: MOVE MS,T1 ;MAKE MS POINT TO MSD SETZRO MDNXT,(MS) ;INPUT MSD's CAN'T BE CHAINED MOVX T1,VGNPTR ;BUILD A VIRGIN BYTE POINTER STOR T1,MDAUX,(MS) ;STORE THE BYTE POINTER FOR LATER PEOPLE STOR T1,MDPTR,(MS) ; AND STORE THE DYNAMIC BYTE POINTER STOR T2,MDALA,(MS) ;STORE BUFFER ADDRESS SETZRO MDBYT,(MS) ;NOTHING RECEIVED YET STOR T3,MDALL,(MS) ;SET BUFFER LENGTH RET ; AND RETURN SUBTTL MSDs -- Set up MSD for input on received buffer ;DNGMSS - Set up an initialized MSD to point to received data ; ; Call: ; T1/ MSD address ; T2-T3/ 2 word global pointer to data in receive buffer ; T4/ Receive data length in bytes ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,MS ; XRESCD DNGMSS:: MOVE MS,T1 ;MAKE MS POINT TO MSD STOR T4,MDBYT,(MS) ;SET RECEIVED BYTE COUNT LOAD T1,MDALA,(MS) ;GET RAW BUFFER ADDRESS SUB T3,T1 ;GET WORD OFFSET TO RECEIVE DATA IN BUFFER ADDI T2,(T3) ;ADD OFFSET IN E-field OF POINTER TXZ T2,1B12 ;CLEAR 2 word global bit TLO T2,T6 ;SET STANDARD INDEX FOR VGNPTR STOR T2,MDPTR,(MS) ;STORE POINTER RET ; AND RETURN SUBTTL MSDs -- Initialize MSD for output ;DNPINI - Initialize MSD ptr and count for output (DNPxxx routines) ; ; Call: ; T1/ Pointer to MSD to initialize ;It is assumed that the byte pointer wanted starts at the allocated ;address of the MSD (MDALA). ; ; Return: ; RET ;ALWAYS, LEAVING T1 ALONE ; ; Uses: T1,T2,MS ; ;The DNPxxx routines will use the byte pointers and byte count in the ;MSD. There are two byte pointers, one which is updated all the time ;and one which is left alone for future people to use. XRESCD DNPINI:: MOVE MS,T1 ;MAKE MS POINT TO MSD MOVX T2,VGNPTR ;BUILD A VIRGIN BYTE POINTER STOR T2,MDAUX,(MS) ;STORE THE BYTE POINTER FOR LATER PEOPLE STOR T2,MDPTR,(MS) ; AND STORE THE DYNAMIC BYTE POINTER SETZRO MDBYT,(MS) ;JUST IN CASE RET ;ONLY RETURN ;DNPINR is a variant of DNPINI for re-initializing an MSD which is to ;have data added to it. XRESCD DNPINR:: MOVE MS,T1 ;MAKE MS POINT TO MSD RET ;THAT'S ALL FOR A RE-INITIALIZATION SUBTTL DNSBP -- Byte routines -- Store a byte pointer ;DNSBP - Store a byte pointer into an MSD ; ; Call: ; T1 & T2/ Byte pointer of any type, except OWGBP, indexed or indirect ; T3/ Pointer to MSD to modify ; ;DNSBP makes the indicated MSD point to the same byte as the passed byte ;pointer. ife ftki10,< ;[je] This routine is only called from ;[je] DNADLL, and under FTNI conditional. INTERNAL DNSBP XRESCD DNSBP: LDB T4,[POINT 6,T1,5] ; Fetch P field of byte pointer CAILE T4,44 ; One word global? BUG.(HLT,COMBBP,D36COM,SOFT,,,< Cause: DNSBP was called with a one-word global byte pointer. DNSPB is only set up to handle local one-word and two-word byte pointers, without indexing or indirection. Action: Either change the caller to pass a two-word byte pointer or upgrade DNSBP to handle OWGBPs. >) TXZN T1,1B12 ; Two word byte pointer? HRRZ T2,T1 ; No, one word pointer. Fetch Y field. OPSTR ,MDALA,(T3) ; Compute Y field for MDPTR HRR T1,T2 ; Install it TXZ T1,37B17 ; Clear indexing and indirection TXO T1,<(T6)> ; Use index AC T6 STOR T1,MDPTR,(T3) ; Save the byte pointer RET >;ki10 SUBTTL DNF2WG -- Byte routines -- Fetch a two word global from an MSD ;DNF2WG - Fetch a two word global byte pointer from an MSD ; ; Call: ; T1/ Pointer to MSD ; Return: T1 & T2/ Two word global byte pointer ; ife ftki10,< ;[je] This routine is only called from ;[je] DNADLL, and under FTNI conditional. INTERNAL DNF2WG XRESCD DNF2WG: LOAD T2,MDALA,(T1) ; Fetch Y field for byte pointer LOAD T1,MDPTR,(T1) ; Fetch P & S fields TXC T1,<1B12+<(T6)>> ; Clear AC and @, set two word global RET >;ki10 SUBTTL MSDs -- Byte routines -- Get a byte ;DNG1BY - Get one byte from message ; ; Call: ; MS/ Pointer to current MSD in use ; ; Return: ; RET ;RAN OUT OF BYTES ; RETSKP ;SUCCESS: T1 CONTAINING BYTE ; ; Uses: T1,MS INTERNAL DNG1BY XRESCD DNG1BY: LOAD T6,MDALA,(MS) ;;SET UP INDEX FOR MDPTR OPSTRM ,MDBYT,(MS) ;;UPDATE THE COUNT JUMPL T1,RTN ;;RETURN IF WE RAN OUT OPSTRM ,MDPTR,(MS) ;;GET THE NEXT BYTE RETSKP ;TO SENDER SUBTTL MSDs -- Byte routines -- Get two bytes ;DNG2BY - Get two bytes from message ; ; Call: ; MS/ Pointer to current input MSD ; ; Return: ; RET ;WHEN WE'RE OUT OF BYTES ; RETSKP ;SUCCESS: WITH T1 CONTAINING THE 16 BIT BYTE ; ; Uses: T1,T2,MS INTERNAL DNG2BY XRESCD DNG2BY: LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR MOVX T1,-2 ;WE NEED TWO BYTES OPSTRM ,MDBYT,(MS) ;UPDATE STRING COUNT JUMPL T1,RTN ;IF THERE ISN'T ENOUGH ROOM, LEAVE OPSTRM ,MDPTR,(MS) ;GET THE LOW BYTE OPSTRM ,MDPTR,(MS) ;GET THE NEXT BYTE LSH T2,^D8 ;PLACE IT IN THE HIGH POSITION IOR T1,T2 ;MAKE UP 16-BIT VALUE RETSKP ; AND RETURN TO SENDER SUBTTL MSDs -- Byte routines -- Get HI-ORDER 4 bytes of Ethernet Addr ;DNGHIO - Get high order four bytes of Ethernet address from message ; ; Call: ; MS/ Pointer to current input MSD ; ; Return: ; RET ;WHEN WE'RE OUT OF BYTES ; RETSKP ;SUCCESS: WITH ; T1/ Ethernet Address, bytes 0,1,2,3 left justified ; ; Uses: T1,T2,T3,MS INTERNAL DNGHIO XRESCD DNGHIO: STKVAR SETZM STG MOVX T2, ;POINT TO 4 BYTE STRING LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR HRLZI T3,<-4> ;SET UP LOOP COUNT DNGHI1: OPSTRM ,MDBYT,(MS) ;;UPDATE THE COUNT JUMPL T1,RTN ;;RETURN IF WE RAN OUT OPSTRM ,MDPTR,(MS) ;GET CURRENT BYTE IDPB T1,T2 ;OUTPUT CURRENT BYTE AOBJN T3,DNGHI1 ;DO ALL 4 BYTES MOVE T1,STG ;MAKE 4 BYTE STRING ON STACK RETSKP ;AND GIVE HIM A GOOD RETURN ENDSV. SUBTTL MSDs -- Byte routines -- Get six byte Ethernet Address ;DNGENA - Get six byte Ethernet address from message ; ; Call: ; MS/ Pointer to current input MSD ; ; Return: ; RET ;WHEN WE'RE OUT OF BYTES ; RETSKP ;SUCCESS: WITH ; T1/ Ethernet Address, bytes 0,1,2,3 left justified ; T2/ Ethernet Address, bytes 4,5 left justified ; ; Uses: T1,T2,T3,MS INTERNAL DNGENA XRESCD DNGENA: STKVAR SETZM STG1 ;MAKE FOR CLEAN RESULT SETZM STG2 MOVX T2, ;POINT TO 6 BYTE STRING LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR HRLZI T3,<-6> ;SET UP LOOP COUNT DNGEN1: OPSTRM ,MDBYT,(MS) ;;UPDATE THE COUNT JUMPL T1,RTN ;;RETURN IF WE RAN OUT OPSTRM ,MDPTR,(MS) ;GET CURRENT BYTE IDPB T1,T2 ;OUTPUT CURRENT BYTE AOBJN T3,DNGEN1 ;DO ALL 6 BYTES DMOVE T1,STG2 ;MAKE 6 BYTE STRING ON STACK RETSKP ;AND GIVE HIM A GOOD RETURN ENDSV. SUBTTL MSDs -- Byte routines -- Get two bytes from specified position ;DNG2BS - Get two bytes from message at a specified position ; ; Call: T1/ Beginning byte position ; MS/ Pointer to current input MSD ; ; Return: ; RET ;WHEN WE'RE OUT OF BYTES ; RETSKP ;SUCCESS: WITH T1 CONTAINING THE 16 BIT BYTE ; ; Uses: T1,T2,T3,MS DNG2BS::LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR ;Need to check if went past end of message ;This code only checks for buffer exceeded ; MOVX T1,-2 ;WE NEED TWO BYTES ; OPSTRM ,MDBYT,(MS) ;UPDATE STRING COUNT ; JUMPL T1,RTN ;IF THERE ISN'T ENOUGH ROOM, LEAVE MOVEI T2,2(T1) OPSTRM ,MDALL,(MS) JUMPG T2,RTN ;IF THERE ISN'T ENOUGH ROOM, LEAVE OPSTRM ,MDAUX,(MS) ;ADJUST TO SPECIFIED BYTE POSITION MOVE T3,T1 ;SAVE ADJUSTED POINTER FOR USE ILDB T1,T3 ;GET THE LOW BYTE ILDB T2,T3 ;GET THE NEXT BYTE LSH T2,^D8 ;PLACE IT IN THE HIGH POSITION IOR T1,T2 ;MAKE UP 16-BIT VALUE RETSKP ; AND RETURN TO SENDER SUBTTL MSDs -- Byte routines -- Get an extensible field ;DNGEBY - Get an extensible field from message ; ; Call: ; MS/ Pointer to current input MSD ; ; Return: ; RET ;IF WE RAN OUT OF BYTES ; RETSKP ;SUCCESS: WITH T1 CONTAINING THE BYTE ; ; Uses: T1-T4,MS XRESCD DNGEBY:: LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR SETZ T1, ;BUILD BYTE IN T1 MOVE T3,[POINT 7,T1,35] ;MAKE BYTE POINTER FOR BUILDING BYTE DNGEB1: OPSTRM ,MDBYT,(MS) ;DECREMENT THE COUNT JUMPL T4,RTN ;GIVE ERROR RETURN IF WE'RE OUT OPSTRM ,MDPTR,(MS) ;GET THE NEXT BYTE DPB T2,T3 ;PUT IT IN WORD WE'RE BUILDING TRNN T2,200 ;IS IT EXTENSIBLE RETSKP ;NO, RETURN ADD T3,[7B5] ;CONTINUE BUILDING JRST DNGEB1 ; BY LOOPING SUBTTL MSDs -- Byte routines -- Get a byte, skip if non-extensible ;DNGSBY - Get a byte, giving non-skip return if extensible ; ; Call: ; MS/ Pointer to current input MSD ; ; Return: ; RET ;WE GOT AN EXTENSIBLE BYTE OR RAN OUT OF BYTES ; RETSKP ;T1 CONTAINING THE BYTE ; ; Uses: T1,MS INTERNAL DNGSBY XRESCD DNGSBY: LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR OPSTRM ,MDBYT,(MS) ;DECREMENT THE COUNT JUMPL T1,RTN ;IF WE'RE OUT, GIVE ERROR RETURN OPSTRM ,MDPTR,(MS) ;YUP, GET NEXT ONE TRNN T1,200 ;IS IT EXTENSIBLE? AOS (P) ;GIVE GOOD RETURN RET ;RETURN SUBTTL MSDs -- Byte routines -- Put a byte into message ;DNP1BY - Place one byte into message ; ; Call: ; T1/ The byte ; MS/ Pointer to current output MSD ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,MS INTERNAL DNP1BY XRESCD DNP1BY: LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR OPSTRM ,MDPTR,(MS) ;PUT BYTE IN MESSAGE INCR MDBYT,(MS) ;INCREMENT THE COUNT RET ;RETURN TO SENDER SUBTTL MSDs -- Byte routines -- Put two bytes in message ;DNP2BY - Place two bytes into message stream ; ; Call: ; T1/ 2 bytes (a PDP-11 word) ; MS/ Pointer to current output MSD ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,MS XRESCD DNP2BY:: IFN DBGS2,> ;*LLMOP* LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR OPSTRM ,MDPTR,(MS) ;OUTPUT FIRST PART OF WORD LSH T1,-^D8 ;SHIFT A BYTE OPSTRM ,MDPTR,(MS) ;OUTPUT NEXT PART MOVEI T1,2 ;WE DID TWO BYTES OPSTRM ,MDBYT,(MS) ;INCREMENT THE COUNT RET ;RETURN TO SENDER SUBTTL MSDs -- Byte routines -- Put two bytes to specified position ;DNP2BS - Put two bytes in message at a specified position ; ; Call: T1/ Beginning byte position ; T2/ 2 bytes (a PDP-11 word) ; MS/ Pointer to current input MSD ; ; Return: ; RET ;WHEN WE'RE OUT OF BYTES ; RETSKP ;SUCCESS: WITH T1 CONTAINING THE 16 BIT BYTE ; ; Uses: T1,T2,T3,MS XRESCD DNP2BS:: LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR ; MOVEI T3,2(T1) ; OPSTRM ,MDALL,(MS) ; JUMPG T3,RTN ;IF THERE ISN'T ENOUGH ROOM, LEAVE OPSTRM ,MDAUX,(MS) ;ADJUST TO SPECIFIED BYTE POSITION IDPB T2,T1 ;PUT THE LOW BYTE LSH T2,-^D8 ;SHIFT TO HI BYTE IDPB T2,T1 ;PUT THE NEXT BYTE RET ; AND RETURN TO SENDER SUBTTL MSDs -- Byte routines -- Put four bytes in message ;DNP4BY - Place four byte value into message stream ; ; Call: ; T1/ 4 bytes (a PDP-11 double word) ; MS/ Pointer to current output MSD ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,MS INTERNAL DNP4BY XRESCD DNP4BY: LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR HRLZI T2,<-4> ;SET UP LOOP COUNT DNP4B1: OPSTRM ,MDPTR,(MS) ;OUTPUT FIRST BYTE OF WORD LSH T1,-^D8 ;SHIFT TO NEXT BYTE OPSTRM ,MDBYT,(MS) ;INCREMENT THE COUNT AOBJN T2,DNP4B1 ;DO ALL BYTES IN WORD RET ;RETURN TO SENDER SUBTTL MSDs -- Byte routines -- Put HI-ORDER 4 bytes of Ethernet Addr ;DNPHIO - Put high order four bytes of Ethernet address in message ; ; Call: ; T1/ Ethernet Address, bytes 0,1,2,3 left justified ; MS/ Pointer to current output MSD ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,T2,MS INTERNAL DNPHIO XRESCD DNPHIO: STKVAR MOVEM T1,STG ;MAKE 4 BYTE STRING ON STACK MOVX T2, ;POINT TO 4 BYTE STRING LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR HRLZI T3,<-4> ;SET UP LOOP COUNT DNPHI1: ILDB T1,T2 ;GET CURRENT BYTE OPSTRM ,MDPTR,(MS) ;OUTPUT CURRENT BYTE OPSTRM ,MDBYT,(MS) ;INCREMENT THE COUNT AOBJN T3,DNPHI1 ;DO ALL 4 BYTES RET ;AND GIVE HIM A GOOD RETURN ENDSV. SUBTTL MSDs -- Byte routines -- Put six byte Ethernet Address ;DNPENA - Put six byte Ethernet address in message ; ; Call: ; T1/ Ethernet Address, bytes 0,1,2,3 left justified ; T2/ Ethernet Address, bytes 4,5 left justified ; MS/ Pointer to current output MSD ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,T2,MS INTERNAL DNPENA XRESCD DNPENA: STKVAR DMOVEM T1,STG2 ;MAKE 6 BYTE STRING ON STACK MOVX T2, ;POINT TO 6 BYTE STRING LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR HRLZI T3,<-6> ;SET UP LOOP COUNT DNPEN1: ILDB T1,T2 ;GET CURRENT BYTE OPSTRM ,MDPTR,(MS) ;OUTPUT CURRENT BYTE OPSTRM ,MDBYT,(MS) ;INCREMENT THE COUNT AOBJN T3,DNPEN1 ;DO ALL 6 BYTES RET ;AND GIVE HIM A GOOD RETURN ENDSV. SUBTTL MSDs -- Byte routines -- Put an extensible field into message ;DNPEBY - Put extensible byte into message stream ; ; Call: ; T1/ Byte ; MS/ Pointer to current input MSD ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,T2,MS INTERNAL DNPEBY XRESCD DNPEBY: DO. LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR CAIG T1,177 ;IS IT BIG ENUF FOR AN EXTENSIBLE BYTE? CALLRET DNP1BY ;NO, OUTPUT THE REST AS ONE BYTE LSHC T1,-7 ;PUSH BYTE OVER TO T2 ROT T2,7 ;LINE IT UP TRO T2,200 ;LIGHT UP "EXTENSIBLE" BIT OPSTRM ,MDPTR,(MS) ;PUT BYTE IN STREAM INCR MDBYT,(MS) ;INCREMENT COUNT LOOP. ENDDO. SUBTTL MSDs -- Byte routines -- Put some zero bytes ;DNPZB - Put (T1) bytes of zeros into a message ; ; Call: ; MS/ Pointer to current MSD ; T1/ Number of zeros to put ; ; Return: ; RET ; ; Uses: T1,MS INTERNAL DNPZB XRESCD DNPZB: JUMPE T1,RTN ;Nothing to do if zero OPSTRM ,MDBYT,(MS) ;Adjust the byte count LOAD T6,MDALA,(MS) ;Set up index for MDPTR SETZ T2, ;Datum is a zero DNPZB1: OPSTRM ,MDPTR,(MS) ;Put byte in message SOJG T1,DNPZB1 ;Put as many as requested RET SUBTTL MSDs -- Byte routines -- Skip some bytes ;DNSKBY - Skip (T1) bytes in input message ; ; Call: ; MS/ Pointer to current input MSD ; T1/ Number of Bytes to Skip ; ; Return: ; RET ;WHEN WE RAN OUT OF BYTES ; RETSKP ;ON SUCCESS ; ; Uses: T1,T2,MS INTERNAL DNSKBY XRESCD DNSKBY: JUMPE T1,RSKP ;Success return if no bytes to skip LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR MOVN T2,T1 ;GET THE NEGATIVE COUNT OPSTRM ,MDBYT,(MS) ;NEGATE COUNT OPSTRM ,MDBYT,(MS) ;SUBTRACT THE NUMBER OF BACKSPACES JUMPL T2,RTN ;IF WE'RE OUT, GIVE ERROR RETURN OPSTR ,MDPTR,(MS) ;ADJUST THE BYTE POINTER STOR T1,MDPTR,(MS) ;STORE THE POINTER BACK RETSKP ;WE'RE OK SUBTTL MSDs -- Byte routines -- Go Backwards some number of bytes ;DNBKBY - Go backwards (T1) bytes in input message ; ; Call: ; T1/ Number of bytes to go backwards over ; MS/ Pointer to input MSD ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,MS ; ;Note: It is your responsiblity to make sure that you do not go ;backwards over an MSD boundary. If you do the program will not work. INTERNAL DNBKBY XRESCD DNBKBY: LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR OPSTRM ,MDBYT,(MS) ;ADJUST THE BYTE COUNT MOVN T1,T1 ;GET NEGATIVE COUNT OPSTR ,MDPTR,(MS) ;ADJUST THE BYTE POINTER FIXADJ T1 ;COMPENSATE FOR BUG IN BP EA CALC STOR T1,MDPTR,(MS) ;STORE THE POINTER BACK RET ;TO SENDER SUBTTL MSDs -- Read and Goto Position ;DNRPOS - Read the current position in the input data ; ; Call: ; MS/ Pointer to input MSD ; ; Return: ; RET ;Always, T1 holds full-word of position ; ; which can be fed to DNGPOS ; ; Uses: T1 ; ;Note that DNRPOS is called far more frequently than DNGPOS, so ;DNRPOS is simple, where DNGPOS is complicated. INTERNAL DNRPOS XRESCD DNRPOS: LOAD T1,MDBYT,(MS) ;LOAD UP 'BYTES TO GO' RET ;THAT WAS EASY ;NSP's message trace facility (TRCMSG) makes illicit use of ;the MSD fields and of the nature of the position value returned ;by DNRPOS. ;DNGPOS - Go to a position in the input data spec'd by caller ; ; Call: ; T1/ POSition word returned from DNRPOS ; MS/ Pointer to input MSD ; ; Return: ; RET ; ; Uses: T1,T2 ; ;Caller passes a value returned from DNRPOS (above). No other ;routines are expected to understand the contents of the POSition word. ;This routine should be called for INPUT MESSAGES ONLY. INTERNAL DNGPOS XRESCD DNGPOS: LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR TLNN MS,770000 ;MAKE SURE LEFT HALF ISN'T GARBAGE OPSTR ,CHBOT,+MBLCB ;MAKE SURE WE HAVE AN MS BUG.(CHK,COMDNP,D36COM,SOFT,,,< Cause: The ac MS points to memory not used by message blocks. This was found during range checking. Action: Trace back to the caller and find out why there is a bad pointer. >,RTN) LOAD T2,MDBYT,(MS) ;GET CURRENT 'BYTES TO GO' STOR T1,MDBYT,(MS) ;STORE SAVED 'BYTES TO GO' SUB T2,T1 ;DERIVE BYTES TO BACK UP OPSTR ,MDPTR,(MS) ;BACK UP THE BYTE POINTER FIXADJ T2 ;COMPENSATE FOR BUG IN BP EA CALC STOR T2,MDPTR,(MS) ;STORE THE UPDATED BYTE POINTER RET ;DNGOPS - Go to a position in the input data spec'd by caller ; ; Call: ; T1/ POSition word returned from DNRPOS ; MS/ Pointer to input MSD ; ; Return: ; RET ; ; Uses: T1,T2 ; ;Caller passes a value returned from DNRPOS (above). No other ;routines are expected to understand the contents of the POSition word. ;This routine should be called for OUTPUT MESSAGES ONLY. INTERNAL DNGOPS XRESCD DNGOPS: LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR TLNN MS,770000 ;MAKE SURE LEFT HALF ISN'T GARBAGE OPSTR ,CHBOT,+MBLCB ;MAKE SURE WE HAVE AN MS BUG.(CHK,COMODP,D36COM,SOFT,,,< Cause: The ac MS points to memory not used by message blocks. This was found during range checking. Action: Trace back to the caller and find out why there is a bad pointer. >,RTN) LOAD T2,MDBYT,(MS) ;GET CURRENT 'BYTES TO GO' STOR T1,MDBYT,(MS) ;STORE SAVED 'BYTES TO GO' SUBM T1,T2 ;DERIVE BYTES TO BACK UP OPSTR ,MDPTR,(MS) ;BACK UP THE BYTE POINTER FIXADJ T2 ;COMPENSATE FOR BUG IN BP EA CALC STOR T2,MDPTR,(MS) ;STORE THE UPDATED BYTE POINTER RET SUBTTL MSDs -- Link a Message Segment into a Message Block ;DNLMSS - Link message segment into MB ; ; Call: ; T1/ Pointer to MSD that will point to segment ; T2/ Pointer to previous MSD ; T3/ Pointer to data (segment) ; T4/ Count of bytes in data ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T4 INTERNAL DNLMSS XRESCD DNLMSS: JUMPE T3,DNLMS1 ;IF NO POINTER IS SPECIFIED, JUST LINK PREVIOUS STOR T3,MDAUX,(T1) ;STORE THE BYTE POINTER STOR T3,MDPTR,(T1) ; AND THE DYNAMIC BYTE POINTER STOR T4,MDBYT,(T1) ;STORE THE BYTE COUNT STOR T4,MDALL,(T1) ; AND THE ALLOCATED LENGTH DNLMS1: STOR T1,MDNXT,(T2) ;LINK PREVIOUS MSD TO US RET ;RETURN SUBTTL MSDs -- Copy message block ;DNCPMS - Gather message blocks MSDs into a new message block ; ; Call: ; MB/ Pointer to message block to copy ; ; Return: ; RET ;ERROR IN COPYING ; RETSKP ;T1 POINTING TO NEW MESSAGE BLOCK ; ; MB STILL POINTING TO OLD BLOCK ; Uses: T1-T5 ; ;Note that the byte pointers in MDPTR and MDAUX are indexed by ;(T6), see comment at VGNPTR definition, above. Since we are ;using two msg blks here, one of the byte ptrs has to have its ;X field changed to T3. INTERNAL DNCPMS XRESCD DNCPMS: SAVEAC ;P1 WILL POINT TO NEW MESSAGE BLOCK ;First, allocate a new message block MOVE T1,MB ;POINTER TO SOURCE MSG BLK CALL DNLENG ;HOW MANY BYTES IN IT? CALL DNGMSG ;GET A NEW MSG BLK FOR THAT MANY RET ;CAN'T RETURN FAILURE TO CALLER MOVE P1,T1 ;SAVE POINTER TO NEW MSG BLK ;Now we can fill in the new message block with data as if ;it had come from the outside world: all in IN.MSD. SETZ T4, ;WE'LL COLLECT BYTE COUNT HERE OPSTR ,MBFMS,(MB) ;GET PTR TO FIRST MSD JRST DNCPM6 ;LEAVE NOW IF NO DATA TO COPY DNCPM1: OPSTR ,MDNXT,(T5) ;REMEMBER ADDR OF LAST MSD IN T5 JRST DNCPM2 ;DON'T COUNT LAST MSD IN CHAIN OPSTR ,MDBYT,(T5) ;COUNT THIS MSD'S DATA MOVE T5,T3 ;MOVE TO NEXT MSD JRST DNCPM1 ;THERE IS A NEXT, GO COUNT IT DNCPM2: LOAD T6,MDAUX,(T5) ;INDEXED 8-BIT BYTE PTR TO BEG OF SOURCE HRRZ T2,T6 ;ISOLATE OFFSET IN RH OF BYTE PTR TLNE T6,700000 ;IS IT 041000,,xxx? JRST DNCPM3 ;NO, NO PROBLEM TLO T6,400000 ;YES, MAKE IT 4410xx,nnn+1 HRRI T6,1(T6) ;NON-CARRYING ADD TO RH, TLO JUST MADE IFIW DNCPM3: OPSTR ,MDALA,(T5) ; WHICH WAS INDEXED BY T6=MDALA MOVEI T3,3(T4) ;GET BYTES BEFORE THIS MSD, ROUNDED UP ASH T3,-2 ;CALCULATE WORDS FOR ALL BUT LAST MSD HRR T6,T3 ;SAVE INDEXED BYTE PTR TO BEG OF DEST OPSTR ,MDALA,+IN.MSD(P1) ;ADD ALLOC ADDR IN DEST MSD LOAD T1,MDBYT,(T5) ;GET # OF BYTES IN LAST MSD ADDI T1,3+3 ;ADD 3 BEFORE + 3 AFTER FOR BLT MISALIGNMENT ASH T1,-2 ;CALC # OF WORDS TO BLT TESTS1 ;ASSERT THAT WE'RE IN SECTION 1 CALL XBLTAT ;(T1,T2,T3)COPY MONITOR TO MONITOR ;Calc dest start byte ptr into T5, byte pointer indexed by T3 for MOVSLJ MOVE T3,T4 ;GET # BYTES BEFORE BLT DATA OPSTR ,MDBYT,(T5) ;GET TOTAL LENGTH OF NEW MESSAGE STOR T3,MDBYT,+IN.MSD(P1) ;STORE IN NEW MSD JUMPE T4,[ ;DON'T CHANGE 441006,,0 TO 041006,,-1 STOR T6,MDPTR,+IN.MSD(P1) JRST DNCPM6] ;ALL DONE MOVN T5,T4 ;NEGATE # OF BYTES BEFORE BLT'D DATA ADJBP T5,T6 ;(T6) BYTE PTR TO START OF MSG FIXADJ T5 ;COMPENSATE FOR BUG IN BP EA CALC STOR T5,MDPTR,+IN.MSD(P1) ;NEW BEG PTR, STILL INDEXED BY T6 TLZ T5,17 ;GET RID OF T6 INDEX FOR USE BELOW TLO T5,T3 ;REPLACE IT WITH T3 INDEX LOAD T3,MDALA,+IN.MSD(P1) ;WE'LL INDEX DEST BPT WITH T3 ;MB will now point to source MSDs instead of source msg blk LOAD P2,MBFMS,(MB) ;PICK UP PTR TO FIRST MSD DNCPM5: TMNN MDNXT,(P2) ;IS THIS THE LAST MSD? JRST DNCPM6 ;YES, ALREADY BLT'D, DON'T MOVSLJ IT LOAD T1,MDBYT,(P2) ;LENGTH OF DATA IN THIS MSD LOAD T2,MDAUX,(P2) ;BYTE PTR TO BEG OF DATA LOAD T6,MDALA,(P2) ;BYTE PTR IN T2 IS INDEXED BY T6 MOVE T4,T1 ;COPY SOURCE LENGTH TO DEST LENGTH ife ftki10,< ;Remove processor-specific code. EXTEND T1,[MOVSLJ] ;PREPEND HEADER TO USER DATA BUG.(CHK,COMMTS,D36COM,SOFT,,,< Cause: A MOVSLJ instruction in D36COM has failed. >,RTN) >;julgransprocessor. ifn ftki10,< ildb cx,t2 ;Copy the data with a simple-minded loop. idpb cx,t5 sojg t1,.-2 >;ki10 LOAD P2,MDNXT,(P2) ;GET PTR TO NEXT MSD IN CHAIN JRST DNCPM5 ;GO COPY NEXT IF ITS NOT LAST DNCPM6: XMOVEI T1,IN.MSD(P1) ;GET POINTER TO INPUT MSD IN NEW MSG STOR T1,MBFMS,(P1) ;STORE AS FIRST MSD IN MSD CHAIN MOVE T1,P1 ;T1 PTS TO NEW MSG BLK FOR CALLER RETSKP ;RETURN SUCCESS SUBTTL MSDs -- Calculate length of a whole message ;DNLENG - Find length of message left ; ; Call: ; T1/ Pointer to Message Block ; ; Return: ; RET ;ALWAYS WITH T1 CONTAINING COUNT ; ; Uses: T1,T2 INTERNAL DNLENG XRESCD DNLENG: SETZ T2, ;KEEP COUNTER IN T2 LOAD T1,MBFMS,(T1) ;GET POINTER TO FIRST MSD IN MSG BLK DNLEN1: OPSTR ,MDBYT,(T1) ;ADD UP THE COUNT LOAD T1,MDNXT,(T1) ;GET THE NEXT MSD JUMPN T1,DNLEN1 ;LOOP IF WE GOT SOME MORE MOVE T1,T2 ;PUT IT WERE WE WANT IT RET ;OTHERWISE RETURN SUBTTL MSDs -- Calculate Length of Message Segment ;DNSLNG - Figure out length of MS segment ; ; Call: ; T1/ Pointer to input MSD ; ; Return: ; RET ;ALWAYS WITH LENGTH IN T1 ; ; Uses: T1,T2 ; ;Use this instead of looking at the count yourself, so that we can ;wedge the byte count somewhere with extended byte pointers. INTERNAL DNSLNG XRESCD DNSLNG: LOAD T1,MDBYT,(T1) ;GET OUR BYTE COUNT RET ; AND RETURN SUBTTL MSDs -- DNMINI - Initialize an allocated message block ;DNMINI - Initialize a message block ; ;Call ; T1/ Pointer to message block ; T2/ Number of user bytes desired ;Return ; RET ;ON ALLOCATION FAILURE FOR USER DATA BLOCK ; ; (WILL DE-ALLOCATE MESSAGE BLOCK) ; RETSKP ;SUCCESS, VIRGIN MESSAGE BLOCK WITH USER DATA INTERNAL DNMINI XRESCD DNMINI: TDZA T3, ;FLAG AN UNPRIVED CALL DNMINP: SETO T3, ;FLAG A PRIVED CALL SAVEAC MOVEI P2,3+3(T2) ;SAVE NUMBER OF USER DATA BYTES ; NEEDED, WITH LEEWAY BEFORE & AFTER FOR ; BYTE MISALIGNMENT FROM BLT'D DATA ; IN ROUTINES LIKE DNCU2M, DNCPMS MOVE P3,T3 ; Save privelege flag SKIPN P1,T1 ;SAVE PTR TO MSG BLK BUG.(CHK,COMMZP,D36COM,SOFT,,,< Cause: Some caller probably meant to ask for zero bytes of user data in T2 and mistakenly put the count in T1, which is supposed to be the pointer to the message block to refresh. Action: Find caller on the stack and fix it. >,RTN) XMOVEI T2,UD.DAT(P1) ;PTR TO LITTLE USER DATA BFR IN MSG BLK LOAD T1,MDALA,+UD.MSD(P1) ;GET MSD'S PTR TO USER DATA JUMPE T1,DNMIN1 ;JUMP IF NO USER DATA BLK PTR CAME T1,T2 ;ARE THESE THE SAME? JRST DNMIN2 ;NO, WE HAVE A SEPARATE USER DATA BLOCK DNMIN1: CAIG P2,UDH.LN ;NO SEPARATE BLOCK, DO WE WANT ONE? JRST DNMIN4 ;NO, LITTLE USER DATA BLOCK IS GOOD ENOUGH XMOVEI T1,UBLCB ;YES, PTR TO CH FOR USER DATA BLKS LOAD P2,CHSIZ,(T1) ;Get size of UBL SUBI P2,OVHWDS ; Allowance for overhead word(s) IMULI P2,4 ;Convert to bytes for caller MOVE T2,P3 ; Get privilege flag CALL DNGRBA ;(T1,T2)GO GET BIG UD BLK (T6 IS PRIV FLAG) RET ;WE LOSE IFN FTLSTCOR,< MOVE T2,-4(P) ;GET CALLER'S PC MOVEM T2,(T1) ;PUT INTO FIRST HEADER WORD MOVE T2,['D36INI'] ;PUT TEST THING MOVEM T2,1(T1) ; IN SECOND HEADER WORD ADDI T1,2 ;POINT PAST HEADER WORDS >;END IFN FTLSTCOR STOR T1,MDALA,+UD.MSD(P1) ;STORE ALLOCATED ADDRESS OF USER DATA JRST DNMIN5 ;WE ARE WARM AND FUZZY NOW DNMIN2: CAILE P2,UDH.LN ;WE HAVE A BLK, DO WE NEED IT? JRST DNMIN5 ;YES, WE ARE ALL WARM AND FUZZY IFN FTLSTCOR,< SUBI T1,2 ;ACCOUNT FOR THE HEADER WORDS >;END IFN FTLSTCOR XMOVEI T2,UBLCB ;POINTER TO CH FOR USER DATA BLOCKS CALL DNFRBL ;(T1,T2)RELEASE THE USER DATA BLOCK XMOVEI T2,UD.DAT(P1) ;PTR TO PLACE WE CAN FIT USER DATA IN DNMIN4: STOR T2,MDALA,+UD.MSD(P1) ;STORE ALLOCATED ADDRESS OF USER DATA DNMIN5: STOR P2,MDALL,+UD.MSD(P1) ;STASH AWAY ALLOCATED LENTGH OF STRING XMOVEI T1,NM.HDR(P1) ;GET POINTER TO NSP HEADER AREA STOR T1,MDALA,+NM.MSD(P1) ;STORE IT IN ALLOCATED ADDRESS FIELD MOVX T1,NMH.LN ;GET THE NSP HEADER AREA LENGTH (IN BYTES) STOR T1,MDALL,+NM.MSD(P1) ;STORE AWAY THE ALLOCATED LENGTH XMOVEI T1,RM.HDR(P1) ;GET POINTER TO RTR HEADER AREA STOR T1,MDALA,+RM.MSD(P1) ;STORE POINTER IN ALLOCATED ADDRESS FIELD MOVX T1,RMH.LN ;GET LENGTH OF HEADER AREA (IN BYTES) STOR T1,MDALL,+RM.MSD(P1) ;STORE ALLOCATED LENGTH FOR SOMEONE SETZRO MDBYT,+UD.MSD(P1) ;NO BYTES IN USER DATA MSD YET SETZRO MDBYT,+NM.MSD(P1) ;NO BYTES IN NSP MSD YET SETZRO MDBYT,+RM.MSD(P1) ;NO BYTES IN ROUTER MSD YET MOVX T1,VGNPTR ;BUILD A VIRGIN BYTE PTR STOR T1,MDAUX,+UD.MSD(P1) ;STASH AWAY BYTE POINTER TO USER DATA STOR T1,MDPTR,+UD.MSD(P1) ;STASH AWAY IN DYNAMIC POINTER STOR T1,MDAUX,+NM.MSD(P1) ;STORE IN NSP STRING POINTER FIELD STOR T1,MDPTR,+NM.MSD(P1) ;AND IN THE DYNAMIC BYTE POINTER AREA STOR T1,MDAUX,+RM.MSD(P1) ;STORE IT IN STRING POINTER STOR T1,MDPTR,+RM.MSD(P1) ;AND IN THE DYNAMIC BYTE POINTER ;Link all of the MSD's to their header areas SETZRO MDNXT,+UD.MSD(P1) ;NO FORWARD PTR FROM USER DATA MSD SKIPE T1,P2 ;ANY USER DATA? XMOVEI T1,UD.MSD(P1) ;YES, GET POINTER TO USER DATA MSD STOR T1,MDNXT,+NM.MSD(P1) ;STORE USER DATA OR ZERO AS NEXT TO NSP XMOVEI T1,NM.MSD(P1) ;POINT TO THE NSP MSD STOR T1,MDNXT,+RM.MSD(P1) ;POINT RTR'S NEXT POINT TO NSP MSD XMOVEI T1,RM.MSD(P1) ;POINT TO THE START OF THE RTR MSD STOR T1,MBFMS,(P1) ;STORE THAT AS THE FIRST MSD POINTER ;Here to fix up the msg blk SETZM MB.FLG(P1) ;CLEAR OUT COMMON FLAGS WORD SETZM MB.CHN(P1) ;ASSUME NO LOOPBACK CHANNEL SETZM NM.FLG(P1) ;CLEAR OUT LLINKS' FLAGS WORD IFN NM.FLG-NM.CNT, ;SEND COUNT IF IN DIFFERENT WORD SETZM RM.FLG(P1) ;CLEAR OUT ROUTER'S FLAGS WORD SETZM RM.ICP(P1) ;CLEAR INPUT CIRCUIT POINTER SETZM RM.OCP(P1) ;CLEAR OUTPT CIRCUIT POINTER SETZM RM.MK1(P1) ;CLEAR OUT THE EVENT MARK TO INDICATE NO ROUTER HEADER RETSKP ;RETURN SUCCESS SUBTTL MSDs -- DNCMSD - Copy MSD chain to contiguous block ;DNCMSD - copy a MSD chain to a contiguous block ; ;Call: T1/ 30-bit pointer of destination block ; T2/ # of bytes in destination block ; MB/ message block address ; CALL DNCMSD ; +1 return: not room to copy message ; +2 return: success with - ; T1/ BP to destination string without any address information ; T2/ # of pad bytes required to word-align ; T3/ total # of bytes (excluding pad) in message INTERNAL DNCMSD XRESCD DNCMSD: SAVEAC STKVAR ;PRECNT is the sum of bytes in all MSDs except the last one ;TOTCNT is the total number of bytes in the message ;DSTBLK is address of destination block ;DSTCNT is the number of bytes the destination block can accomodate ;NRPAD is the number of pad bytes needed to word-align the message ;DSTPTR is the destination byte pointer as returned to the user MOVEM T1,DSTBLK ;Save destination address MOVEM T2,DSTCNT ;Save # of bytes in destination block ;Find last MSD and count bytes along the way (into T1) LOAD MS,MBFMS,(MB) ;Get first MSD SETZ T1, ; and clear count DO. ;Loop OPSTR ,MDNXT,(MS) ;Is there another MSD? EXIT. ; -no, this is the last - exit OPSTR ,MDBYT,(MS) ;Count the # of bytes in this MSD MOVE MS,T2 ;Go to next MSD LOOP. ; and loop back ENDDO. MOVEM T1,PRECNT ;Save count of bytes before last MSD ;Should we do XBLT or MOVSLJs? LOAD T2,MDBYT,(MS) ;Get # of bytes in last MSD ADD T1,T2 ;Calculate total # of bytes in message MOVEM T1,TOTCNT ; and save that CAIG T2,20 ;More than 20 bytes in last MSD? JRST COPSLJ ; -no, copy with MOVSLJ ife ftki10,< ;[JE] Seems to be the easiest way... ;Do XBLT ;The bytepointer in a MSD is of the format x41006,,nnn LOAD T1,MDAUX,(MS) ;Get the last MSDs pointer HRRZ T2,T1 ;Isolate offset LDB T1,[POINT 3,T1,2] ;Get "x" from byte pointer ;The "x" is either 0 (make it into 4, and increase offset), 1,2,3 or 4 SKIPE T1 ;Is it 0? IFSKP. ; then MOVX T1,4 ; make it 4 AOJ T2, ; and increase offset ENDIF. IFN FTDEBUG < ;Verify bp only if debugging CAILE T1,4 ;Should never be greater than 4 BUG.(CHK,DNBBP,CIDLL,SOFT,,,< Cause: CIDLL while copying a DECnet message to a SCA buffer, saw a bytepointer in a MSD where the first three bits are 5,6 or 7. >,RTN) > ;T2 is the offset from the last MSD bytepointer - make it XBLT source address OPSTR ,MDALA,(MS) ;Thats it! ;Since the last MSD do not need to start on a word boundary, there may be ; room for a couple of bytes there: MOVE T1,[EXP 3,2,1,0]-1(T1) ;Get that # of bytes MOVE T3,PRECNT ;Get number of bytes before last MSD SUB T3,T1 ; and number of bytes that do not fit ;T3 is the number of bytes before the word where the last MSD starts MOVEI T4,3(T3) ;Add 3 and ASH T4,-2 ; divide by 4 to get number of words ;T4 now has number of words before last MSD in destination MOVE T5,T4 ;Get word count ASH T5,2 ; and make into bytes SUB T5,T3 ;Difference is number of pad bytes MOVEM T5,NRPAD ;Verify that destination block has room for all bytes ADD T5,TOTCNT ;Total length is message length + pad bytes CAMLE T5,DSTCNT ;Fit? RET ; -no, return error ;Calculate # of words in XBLT OPSTR ,MDBYT,(MS) ;Add # of "spare bytes" in first word ; with number of bytes in last MSD ADDI T1,3 ;Add 3 to ASH T1,-2 ; make word count ;T2 is already loaded MOVE T3,DSTBLK ;Load destination block address ADD T3,T4 ; and add in offset EXTEND T1,[XBLT] ;XBLT... ;Now copy all MSDs except the last one with MOVSLJs ;T1 and T4 is byte count ;T2 is source byte pointer, indexed by P1 (and not T6) ;T5 is destination byte pointer, indexed by P2 (and not T6) ;P1 is source word address (MDALA) ;P2 is destination block address (DSTBLK) LOAD MS,MBFMS,(MB) ;Point to first MSD MOVE T5,NRPAD ;Get number of pad bytes MOVE T1,[POINT 8,0] ;Make destination pointer without address ADJBP T5,T1 ;Make destination pointer point by pad in T5 FIXADJ T5 ;COMPENSATE FOR BUG IN BP EA CALC MOVEM T5,DSTPTR ; and save it for a while TLO T5,P2 ;Now insert index through P2 MOVE P2,DSTBLK ;Load destination block address DO. ;Until last MSD do.. OPSTR ,MDNXT,(MS) ;Is there another MSD? EXIT. ; -no, this is the last one - dont copy CALL CMSDSG ; Copy one MSD segment LOAD MS,MDNXT,(MS) ; and move to next MSD LOOP. ENDDO. ;All done for the XBLT case - just return MOVE T1,DSTPTR ;Get destination pointer MOVE T2,NRPAD ; and number of pad bytes MOVE T3,TOTCNT ; and length of entire message RETSKP >;ki10 from long ago... ;COPSLJ - copy all segments with MOVSLJs ;T1 and T4 is byte count ;T2 is source byte pointer, indexed by P1 (and not T6) ;T5 is destination byte pointer, indexed by P2 (and not T6) ;P1 is source word address (MDALA) ;P2 is destination block address (DSTBLK) ; COPSLJ: MOVE T1,TOTCNT ;Room for message? CAMLE T1,DSTCNT ; .. RET ; -no, error return LOAD MS,MBFMS,(MB) ;Point to first MSD MOVE T5,[POINT 8,(P2)] ;Make destination pointer MOVE P2,DSTBLK ;Load destination block address DO. ;Until last MSD do.. CALL CMSDSG ; Copy one MSD segment OPSTR ,MDNXT,(MS) ;Move to next MSD if there is one EXIT. ; -no, at end, exit LOOP. ENDDO. ;All done for the MOVSLJ case - just return MOVSI T1,(POINT 8,0) ;Get LH of destination pointer SETZ T2, ;Number of pad bytes MOVE T3,TOTCNT ; and length of entire message RETSKP ENDSV. ;CMSDSG - copy a MSD segment ; ;Call: T5/ destination byte pointer indexed by P2 ; P2/ destination address ; MS/ points to current MSD ;May use T1-T6, P1 CMSDSG: LOAD T1,MDBYT,(MS) ;# of bytes to copy JUMPE T1,RTN ; -nothing to copy LOAD T2,MDAUX,(MS) ;Get byte pointer to source TLZ T2,17 ;Clear out index AC TLO T2,P1 ; and make it index through P1 LOAD P1,MDALA,(MS) ;Get source word address to P1 ife ftki10,< MOVE T4,T1 ; and move count EXTEND T1,[MOVSLJ] ;Copy the bytes BUG.(CHK,DNSLJ,CIDLL,SOFT,,,< Cause: A MOVSLJ instruction did not skip. >) >;julgransprocessor. ifn ftki10,< ildb cx,t2 idpb cx,t5 sojg t1,.-2 >;ki10 RET SUBTTL Buffers -- Copy buffer to a message segment ;DNCB2M - Copy buffer to a message segment ; ; Call: ; T1/ Byte Count ; T2/ 1- or 2-word Byte Pointer to String Block ; T3/ Optional second word of byte pointer ; MS/ Pointer to current message segment ; ; Return: ; RET ;ALWAYS WITH T2 CONTAINING UPDATED BYTE POINTER ; ; AND T1, T2 & T3 UPDATED ; ; Uses: T1-T6 ; ;Note that this is used only to copy from a DECnet (monitor) buffer to ;a DECnet message block. INTERNAL DNCB2M XRESCD DNCB2M: STKVAR MOVEM T1,BYTCNT ;Save count of bytes asked to copy TXNE T2,1B12 ;IS IT A 2-WORD GLOBAL PTR? HRR T2,T3 ;YES, MAKE LOCAL PTR FOR OLD MACHINES MOVE T4,T1 ;SET UP THE DESTINATION BYTE COUNT LOAD T5,MDPTR,(MS) ; AND THE DESTINATION BYTE POINTER LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR CALL BBM2M ;(T1-T6/T1-T6) MOVE BYTES TRN ;WON'T HAPPEN MOVE T4,BYTCNT ;Number of bytes requested to copy SUBI T4,(T1) ;Minus those we didn't send OPSTRM ,MDBYT,(MS) ;INCREMENT THE BYTE COUNT STOR T5,MDPTR,(MS) ;STORE THE UPDATED BYTE POINTER RET ;RETURN ENDSV. SUBTTL Buffers -- Copy message data to a buffer ;DNCM2B - Copy message data to a buffer ; ; Call: ; T1/ Count of bytes ; T2/ 1- or 2-word Byte Pointer to buffer ; T3/ Optional second word of byte pointer ; MS/ Pointer to current message segment ; ; Return: ; RET ;IF LENGTH IS NOT CORRECT ; RETSKP ;ON SUCCESSFUL COPY WITH T1 AND T2 CONTAINING ; ; BYTE COUNT AND POINTER ; ; Uses: T1-T6 INTERNAL DNCM2B XRESCD DNCM2B: OPSTR ,MDBYT,(MS) ;MESSAGE BIG ENOUGH? RET ;NO, LET CALLER DEAL WITH ERROR SAVEAC ;Will contain index AC MOVE T4,T1 ;SET UP DESTINATION BYTE COUNT DMOVE T5,T2 ; AND DESTINATION BYTE PTR TXNE T5,1B12 ;2-WORD BYTE PTR TO MONITOR BUFFER? HRR T5,T6 ;YES, MAKE LOCAL FOR OLD MACHINES MOVN T2,T1 ;GET NEGATIVE COUNT OPSTRM ,MDBYT,(MS) ;UPDATE THE BYTE COUNT LOAD T2,MDPTR,(MS) ;SET UP THE SOURCE BYTE POINTER MOVE P1,T2 ; and save it for restore TLZE T2,17 ;IS MDPTR INDEXED? TLO T2,T3 ;YES, USE T3, NOT T6 LOAD T3,MDALA,(MS) ;SET UP INDEX FOR MDPTR CALL BBM2M ;(T1-T6/T1-T6) MOVE BYTES TRN ;WON'T HAPPEN TLZN T2,17 ;MDPTR indexed? IFSKP. ; -yes, restore old index AC AND P1,[17,,0] ; Clear out everything but old index AC TDO T2,P1 ; and put it into byte pointer ENDIF. STOR T2,MDPTR,(MS) ;STORE BACK THE UPDATED SOURCE BYTE PTR MOVE T1,T4 ;UPDATE COUNT FOR CALLER DMOVE T2,T5 ;ALSO POSSIBLY 2-WORD BYTE PTR RETSKP ;RETURN SUCCESS SUBTTL BYTBLT - Non fancy versions IFE FTBYTBLT,< BBM2M: JUMPLE T1,RSKP ;RETURN WHEN DONE ILDB CX,T2 ;GET A BYTE IDPB CX,T5 ;DEPOSIT A BYTE SOJA T1,BBM2M ;COUNT DOWN >;END IFE FTBYTBLT SUBTTL BYTBLT - Fancy version IFN FTBYTBLT,< COMMENT # Indirection not permitted If a byte pointer passed to this routine is indexed, the index register must be T3 for the source, T6 for the destination. Does three special cases: 1) 8 bit bytes, in "normal" position 2) packs 8 bit bytes into words 3) unpacks words into 8 bit bytes In all other cases, do an ILDB, IDPB loop CALL BBM2M T1/ source count T2/ source b.p. T3/ optional source b.p. word 2 or index for source b.p. T4/ destination count T5/ destination b.p. T6/ optional destination b.p. word 2 or index for destination b.p. returns +1 on failure (bad arguments) returns +2 on success with T1-T6 updated. Assumes that the 8 bit byte pointers are "normal", i.e., as below, or one word global. When the word position is used, it means the number of bytes not yet used in the word addressed by the E field of the bp. 441000,,X - position is 4 341000,,X - position is 3 241000,,X - position is 2 141000,,X - position is 1 041000,,X - position is 0 For 36 bit byte pointers, the count means the number of 8 bit bytes # IFN FTOPS10,< P4==FREE1 ;EXTRA ACS FOR BYTE BLT P5==FREE2 >; END IFN FTOPS10 SMLBLT==30 ;MINIMUM FOR COMPLICATED WAY. BP2==1B12 ;2 WORD BP BIT BBM2M:: SAVEAC ;SAVE ACS USED BY THIS ROUTINE TRVAR > LDB P1,[POINT 6,T2,5] ;GET P OF SOURCE LDB P3,[POINT 6,T5,5] ;GET P OF DESTINATION CAIG P1,44 ;OWGBP SOURCE ? IFSKP. CAIG P1,60 ;8 BIT CAIL P1,54 ; BYTES ? IFSKP. MOVEI P2,10 ;YES. SUBI P1,54 ;GET MOVNS P1 ; POSI- ADDI P1,4 ; TION SETOM OWGS ;MARK ONE WORD GLOBAL SOURCE ELSE. MOVEI P2,7 ;NO. ENDIF. ELSE. LDB P2,[POINT 6,T2,11] ;NO. GET S OF SOURCE TRNE P1,3 ;IN NORMAL POSITION ? JRST BY8LP ;NO. DO SLOWLY. LSH P1,-3 ;GET POSITION. SETZM OWGS ;MARK NOT ONE WORD GLOBAL SOURCE ENDIF. CAIG P3,44 ;OWGBP SOURCE ? IFSKP. CAIG P3,60 ;YES. 8 BIT CAIL P3,54 ; BYTES ? IFSKP. MOVEI P4,10 ;YES. SUBI P3,54 ;GET MOVNS P3 ; POSI- ADDI P3,4 ; TION SETOM OWGD ;MARK ONE WORD GLOBAL DEST. ELSE. MOVEI P4,7 ;NO. ENDIF. ELSE. LDB P4,[POINT 6,T5,11] ;NO. GET S OF SOURCE TRNE P3,3 ;IN NORMAL POSITION ? JRST BY8LP ;NO. DO SLOWLY. LSH P3,-3 ;GET POSITION SETZM OWGD ;MARK NOT ONE WORD GLOBAL DEST. ENDIF. ;... ;... ;Dispose of the various cases CAIN P2,10 ;8 BIT SOURCE CAIE P4,44 ; AND 36 BIT DESTINATION ? TRNA ;NO. JRST IN36 ;YES. GO DO IT. CAIN P2,44 ;36 BIT SOURCE AND CAIE P4,10 ; 8 BIT DESTINATION ? TRNA ;NO. JRST OUT36 ;YES. CAMGE T4,T1 ;IS THERE ROOM ? RET ;NO. BOMB OUT. SUB T4,T1 ;YES. OBTAIN RETURNED COUNT. CAIG T1,SMLBLT ;JUST A FEW BYTES ? JRST BY8LP ;YES. DO IT EASILY CAMN P2,P4 ;BYTE SIZES EQUAL AND CAIE P2,10 ; 8 BIT BYTES ? JRST BY8LP ;NO. DO IT THE SLOW WAY. ;Here when 8 bit bytes and using a fast method. ;Convert source position and byte pointer if necessary. IFE. P1 ;IS IT 0 ? MOVEI P1,4 ;YES. CONVERT IT TO 4 SKIPN OWGS ;ONE WORD GLOBAL ? IFSKP. TLZ T2,600000 ;YES. CONVERT POINTER TLO T2,540000 ELSE. TLO T2,440000 ;NO. CONVERT POINTER ENDIF. TXNN T2,BP2 ;2 WORD BYTE POINTER ? IFSKP. AOS T3 ;YES. ELSE. HRRZ CX,T2 ;NO. AOS CX HRR T2,CX ENDIF. ENDIF. ;Convert dest. position and byte pointer if necessary. IFE. P3 ;IS IT 0 ? MOVEI P3,4 ;YES. CONVERT SKIPN OWGD ;ONE WORD GLOBAL ? IFSKP. TLZ T5,600000 ;YES. CONVERT POINTER TLO T5,540000 ELSE. TLO T5,440000 ;NO. CONVERT POINTER ENDIF. TXNN T5,BP2 ;2 WORD BYTE POINTER ? IFSKP. AOS T6 ;YES. ELSE. HRRZ CX,T5 ;NO. AOS CX HRR T5,CX ENDIF. ENDIF. ;BLT or BYTE BLT ? CAME P1,P3 ;POSITIONS MATCH ? JRST BY8SLW ;(T1-T6,P1-P4) NO. BYTE BLT. ;... ;... ;BLT - Here when positions match. transfer 0-3 bytes slowly, blt, then ;transfer the last 0-3 bytes slowly. BBBLT: CAIN P1,4 ;POSITION = 4 ? (WORD ALIGNED) IFSKP. SUB T1,P1 ;NO. MOVE SOME BYTES. UPDATE COUNT. BBBLT1: ILDB P5,T2 ;DO IDPB P5,T5 ; THOSE SOJG P1,BBBLT1 ; BYTES MOVEI P5,1 ;REMEMBER WE WERE HERE. ELSE. SETZ P5, ;WE DIDN'T MOVE BYTES. ENDIF. ;Get source address MOVE P2,T2 SKIPN OWGS ;ONE WORD GLOBAL ? IFSKP. TLZ P2,770000 ;YES. 30 BITS, NO INDIRECTION OR INDEXING ELSE. TXNN P2,BP2 ;NO. 2 WORD B.P. ? IFSKP. XMOVEI P2,(T3) ;YES. GET ADDRESS ELSE. TLZ P2,777740 ;NO. ONE WORD LOCAL TXO P2, ;OBTAIN XCT P2 ; ADDRESS ENDIF. ENDIF. ADD P2,P5 ;ADD IN IF THE B.P. WAS AT THE END OF A WORD. ;get destination address MOVE P3,T5 SKIPN OWGD ;ONE WORD GLOBAL ? IFSKP. TLZ P3,770000 ;YES. 30 BITS, NO INDIRECTION OR INDEXING ELSE. TXNN P3,BP2 ;NO. 2 WORD B.P. ? IFSKP. XMOVEI P3,(T6) ;YES. GET ADDRESS ELSE. TLZ P3,777740 ;NO. ONE WORD LOCAL TXO P3, ;OBTAIN XCT P3 ; ADDRESS ENDIF. ENDIF. ADD P3,P5 ;ADD IN IF THE B.P.S WERE AT THE END OF A WORD. MOVE P1,T1 ;SAVE REMAINING BYTE COUNT LSH T1,-2 ;CONVERT TO WORD COUNT EXCH P2,T2 ;SAVE SOURCE BYTE POINTER (WORDS 1 & 2) EXCH P3,T3 ; SET UP FOR XBLT CALL XBLTA ;(T1,T2,T3) MOVE IT. MOVE T1,P1 ;UPDATE LSH T1,-2 ; THE MOVE T2,P2 ; BYTE MOVE T3,P3 ; POINTERS BY THAT MANY WORDS CALL UPDBPW ;(T1,T2,T3,T5,T6/T2,T3,T5,T6) MOVE T1,P1 ;REMAINING BYTE ANDI T1,3 ; COUNT ; CALLRET BY8LP ;FINISH OFF THOSE FEW BYTES. ;Transfer bytes the easy & slow way ;CALL BY8LP ;T1/ Byte count ;T2,T3/ Source bp ;T5,T6/ Destination bp ;RETURNS +2 ALWAYS ;Uses T1-T6,CX BY8LP: JUMPE T1,RSKP BY8LP1: ILDB CX,T2 IDPB CX,T5 SOJG T1,BY8LP1 RETSKP ;Update byte pointers by words ;Call UPDBPW ;T1/ Word count ;T2,T3/ Source byte pointer ;T5,T6/ Destination byte pointer ;Returns +1 always with T2,T3,T5,T6 updated ;Uses CX ;Preserves all other ACs UPDBPW: TXNN T2,BP2 ;TWO WORD BP ? IFSKP. ADD T3,T1 ;YES. ELSE. HRRZ CX,T2 ;NO. DO IT THIS WAY SO ADD CX,T1 ; NEGATIVE OFFSET IN B.P. HRR T2,CX ; WORKS ENDIF. TXNN T5,BP2 ;TWO WORD BP ? IFSKP. ADD T6,T1 ;YES. ELSE. HRRZ CX,T5 ;NO. DO IT THIS WAY SO ADD CX,T1 ; NEGATIVE OFFSET IN B.P. HRR T5,CX ; WORKS ENDIF. RET ;Here when byte positions do not match ;Call BY8SLW ;T1/ Byte count ;T2,T3/ Source byte pointer ;T4/ Remaining byte count already updated ;T5,T6/ Destination byte pointer ;P1/ Source position ;P3/ Dest. position ;Returns +1 always with ;T2,T3,T5,T6 updated. ;uses P1-P5 ;uses the TRVAR OWGS, OWGD BY8SLW: SUB T1,P3 ;UPDATE COUNT ;COMPUTE (SOURCE-DESTINATION MOD 4) SUB P1,P3 ; WHAT SOURCE POSITION CAIG P1,0 ; WILL BE AFTER ADDI P1,4 ; FILLING FIRST WORD OF DEST. BY8BL1: ILDB P5,T2 ;FILL IN FIRST WORD OF DESTINATION IDPB P5,T5 SOJG P3,BY8BL1 ;at this point the destination position is 4, and the ;source position is 1, 2, or 3. MOVE P4,T1 ;SAVE COUNT MOVE P2,T2 ;AND BYTE MOVE P3,T3 ; POINTER MOVEI T1,LPRG ;GET COPY OF XMOVEI T2,PROTO ;PROTOTYPE BYTE BLT XMOVEI T3,PRG ;ON THE STACK CALL XBLTA MOVE T1,P4 ;RESTORE COUNT AND BYTE POINTER MOVE T2,P2 MOVE T3,P3 ;Alter the program on the stack (TRVAR PRG) CAIN P1,3 ;POSITION NOT 3 ? IFSKP. XMOVEI P2,PRG ;YES. MUST ALTER. ADDRESS OF BYTBLT ROUTINE MOVE P3,3(P2) ;GET FIRST INSTRUCTION TO BE ALTERED XCT PROT1-1(P1) ;ALTER IT. MOVEM P3,3(P2) ;STICK IT IN THE PROGRAM. MOVE P3,4(P2) ;GET SECOND INSTRUCTION TO BE ALTERED TXZ P3,17B12 ;CLEAR AC FIELD TXO P3,11B12 ;SET IT TO P2 MOVEM P3,4(P2) ;STICK IT IN THE PROGRAM. ENDIF. ;... ;... ;Get source address MOVE P3,T2 SKIPN OWGS ;ONE WORD GLOBAL ? IFSKP. TLZ P3,770000 ;YES. 30 BITS, NO INDIRECTION OR INDEXING ELSE. TXNN P3,BP2 ;NO. 2 WORD B.P. ? IFSKP. XMOVEI P3,(T3) ;YES. GET ADDRESS ELSE. TLZ P3,777740 ;NO. ONE WORD LOCAL TXO P3, ;OBTAIN XCT P3 ; ADDRESS ENDIF. ENDIF. ;Get destination address MOVE P4,T5 SKIPN OWGD ;ONE WORD GLOBAL ? IFSKP. TLZ P4,770000 ;YES. 30 BITS, NO INDIRECTION OR INDEXING ELSE. TXNN P4,BP2 ;NO. 2 WORD B.P. ? IFSKP. XMOVEI P4,(T6) ;YES. GET ADDRESS ELSE. TLZ P4,777740 ;NO. ONE WORD LOCAL TXO P4, ;OBTAIN XCT P4 ; ADDRESS ENDIF. ENDIF. AOS P4 ;SINCE B.P. WAS AT END OF WORD ;Set up word count for shifting program. MOVE P5,T1 ;GET BYTE COUNT LSH P5,-2 ;CONVERT TO WORD COUNT CALL PRG ;(P3,P4,P5)GO SHIFT AWAY ;Finish up. MOVE P1,T1 ;UPDATE LSH T1,-2 ; BYTE CALL UPDBPW ; POINTERS (T1,T2,T3,T5,T6/T2,T3,T5,T6) MOVE T1,P1 ;GET REMAINING ANDI T1,3 ; BYTE COUNT JRST BY8LP ;FINISH IT OFF ;Alteration table for the LSHC instruction in PRG. PROT1: HRRI P3,-^D8 HRRI P3,-^D16 ;Prototype 8 bit byte blt, where bytes are aligned, and source and destination ;are not in phase, and the destination position is 4. ;The E field of PROTO+3 will be be ^D12, -^D8 or -^D16 ;The AC field of PROTO+4 will be be T1 or T2 ;This routine, as written, will do the transfer for source position = 3. ;The low order 4 bits of the destination words will be randomized. ;P3/ address of source ;P4/ address of destination ;P5/ word count ;Uses P1-P5 ;Assumes that the count is positive. PROTO: DMOVE P1,(P3) ;GET SOME SOURCE AOS P3 ;UPDATE SOURCE ADDRESS LSH P1,-4 ;RIGHT JUSTIFY FIRST SOURCE WORD LSHC P1,^D12 ;E FIELD FILLED IN AT RUN TIME - ALIGN SOURCE MOVEM P1,(P4) ;AC FIELD FILLED IN AT RUN TIME - FILL DEST. AOS P4 ;UPDATE DESTINATION ADDRESS SOJG P5,PRG ;LOOP, THE TOP OF THIS ROUTINE IS REALLY PRG. RET LPRG==.-PROTO ENDTV. ;pack 8 bit bytes into 36 bit words ;JRST IN36 ;T1/ # of 8 bit bytes ;T2,T3/ 8 bit byte pointer ;T4/ # of 8 bit bytes ;T5,T6/ 36 bit byte pointer ;Indirection not permitted ;If a byte pointer passed to this routine is indexed, the index ;register must be T3 for the source, T6 for the destination. ;Uses P1-P5 ;Returns +2 on success, with T1-T6 updated ;Returns +1 on failure (no room) IN36: MOVE P4,T1 ;COMPUTE # OF WORDS LSH P4,1 ; WORDS = BYTES * 2 / 9 IDIVI P4,11 ANDI P5,3 ;ANY REMAINDER ? IFN. P5 AOS P4 ;YES. NEED ONE MORE WORD. ENDIF. CAMGE T4,T1 ;ENOUGH ROOM ? RET ;NO. SUB T4,T1 ;YES. UPDATE # OF 8 BIT BYTES LEFT IN BUFFER. ;Get destination address TXNN T5,BP2 ;2 WORD B.P. ? IFSKP. XMOVEI P3,(T6) ;YES. GET ADDRESS ELSE. MOVE P3,T5 ;NO. ONE WORD TLZ P3,777740 ; LOCAL, MASK OFF P & S TXO P3, ;OBTAIN XCT P3 ; ADDRESS ENDIF. ;update destination pointer TXNN T5,BP2 ;2 WORD BYTE POINTER ? IFSKP. ADD T6,P4 ;YES. UPDATE IT. ELSE. HRRZ CX,T5 ;NO. UPDATE ONE WORD BYTE POINTER ADD CX,P4 HRR T5,CX ENDIF. ;loop IN36A: SETZB P1,P2 ;INIT WORDS MOVEI P5,11 ;ASSUME ENOUGH ROOM CAIGE T1,11 ;ENOUGH ROOM FOR 2 WORDS OF BYTES ? MOVE P5,T1 ;NO. GET SMALLER COUNT ;subloop IN36B: LSHC P1,10 ;SHIFT BYTES ILDB CX,T2 ;GET NEXT BYTE FROM NET BUFFER DPB CX,[POINT 8,P2,35] ;STASH IT SOJG P5,IN36B ;DO THEM ALL SUBI T1,11 ;UPDATE REMAINING BYTE COUNT IFL. T1 ;SOME ODD BYTES AT THE END ? LSHC P1,-4 ;YES. ALIGN ODD WORD MOVEM P2,(P3) ;STORE ODD WORD AND DONE. ELSE. DMOVEM P1,(P3) ;STORE BOTH WORDS ADDI P3,2 ;INCREMENT DESTINATION POINTER JUMPG T1,IN36A ;DO MORE IF NEEDED ENDIF. ;end loop. update destination byte pointer SETZ T1, ;WE TRANSFERRED ALL THOSE BYTES. RETSKP ;ALL DONE ;unpack 36 bit bytes into 8 bit bytes ;JRST OUT36 ;T1/ # of 8 bit bytes in the 36 bit byte buffer ;T2,T3/ 36 bit byte pointer ;T4/ size in words of 8 bit byte buffer ;T5,T6/ 8 bit byte pointer ;Returns +2 on success, with T1-T6 updated ;Returns +1 on failure (no room) ;Uses P1-P5 ;Indirection not permitted ;If a byte pointer passed to this routine is indexed, the index ;register must be T3 for the source, T6 for the destination. OUT36: STKVAR MOVE P1,T1 ;Get request count CAILE T1,^D9 ;If nine or less just transfer them IFSKP. SETZM WCNT ;All bytes transferred ELSE. IDIVI P1,^D9 ;Number of 8 bit bytes in two words IMULI P1,^D9 ;Compute the number that fit on word boundary EXCH P1,T1 SUB P1,T1 ;P1 will contain number we can't copy MOVEM P1,WCNT ;Remember that ENDIF. ;Get source address TXNN T2,BP2 ;2 WORD B.P. ? IFSKP. XMOVEI P1,(T3) ;YES. GET ADDRESS ELSE. MOVE P1,T2 ;NO. ONE WORD TLZ P1,777740 ; LOCAL, MASK OFF P & S TXO P1, ;OBTAIN XCT P1 ; ADDRESS ENDIF. MOVE P2,T1 ;COMPUTE # OF WORDS LSH P2,1 ; WORDS = BYTES * 2 / 9 IDIVI P2,11 ANDI P3,3 ;ANY REMAINDER ? IFN. P3 AOS P2 ;YES. NEED ONE MORE WORD. ENDIF. CAMGE T4,T1 ;ENOUGH ROOM ? RET ;NO. SUB T4,T1 ;YES. UPDATE # OF 8 BIT BYTES LEFT IN BUFFER. TXNN T2,BP2 ;2 WORD BYTE POINTER ? IFSKP. ADD T3,P2 ;YES. UPDATE IT. ELSE. HRRZ CX,T2 ;NO. UPDATE ONE WORD BYTE POINTER ADD CX,P2 HRR T2,CX ENDIF. ;outer loop OUT36A: CAIL P2,2 ;HAVE AT LEAST 2 MORE WORDS? IFSKP. MOVE P3,(P1) ;NO. GET LAST WORD SETZ P4, ;AND THE OTHER IS NULL. MOVEI P5,5 ;5 MORE BYTES TO MOVE ELSE. DMOVE P3,(P1) ;GET TWO MORE WORDS ADDI P1,2 ;INCREMENT MOVEI P5,11 ;MOVE 9 BYTES ENDIF. SUBI P2,2 ;TAKE TWO WORDS WORTH OF BYTES. ;inner loop OUT36B: ROTC P3,10 ;GET NEXT BYTE RIGHT JUSTIFIED IDPB P4,T5 ;STORE IT SOJG P5,OUT36B ;DO ALL BYTES JUMPG P2,OUT36A ;GO DO MORE DATA ;finish up. MOVE T1,WCNT ;Number of bytes we didn't transfer RETSKP ENDSV. IFN FTOPS10, > ;END IFN FTBYTBLT SUBTTL Buffers -- Copy user buffer to a message segment ;DNCU2M - Copy user buffer to a message segment ; ; Call: ; T1/ User Byte Count ; T2/ User Byte Pointer ; T3/ Optional second word of byte pointer, not implemented yet ; for user mode ; MS/ Pointer to current message segment ; ; Return: ; RET ;ALWAYS, WITH T2 CONTAINING UPDATED BYTE PTR ; ; AND T1 CONTAINING UPDATED BYTE COUNT ; ; Uses: T1-T6 XRESCD DNCU2M::TSTS6 TORESCD ;Run in section 1 because of PXCT IFN FTOPS10,< TXZ T2,1B12 ;DON'T ALLOW USER 2-WORD BPTs LOAD T4,MDBYT,(MS) ;GET COUNT OF BYTES ALREADY IN MSG BLK OPSTRM ,MDBYT,(MS) ;INCREMENT THE BYTE COUNT JUMPG T4,DNCUM0 ;CAN'T BLT IF SOME ALREADY THERE HLRZ T4,T2 ;GET P & S FIELDS OF USER BPT CAIE T4,441000 ;IS IT A STANDARD 8-BIT PTR? CAIN T4,341000 ;IN ANY OF THE 4 POSITIONS? JRST DNCUMB ;YES, WE CAN BLT CAIE T4,241000 ;TWO MORE CAIN T4,141000 ; NORMAL ONES TO CHECK JRST DNCUMB ;YES, WE CAN BLT CAIN T4,041000 ;NO, STANDARD 'NEXT-WORD' BPT? JRST [ TLO T2,400000 ;YES, MAKE IT 441000,,N+1 HRRI T2,1(T2) ; . . . JRST DNCUMB] ;AND BLT THE DATA DNCUM0: >;END OF IFN FTOPS10 ;Here if we must do a byte-wise copy IFN FTOPS20,,MDBYT,(MS)> ;INCREMENT THE BYTE COUNT LOAD T6,MDALA,(MS) ;SET UP INDEX FOR MDPTR LOAD T5,MDPTR,(MS) ; AND THE DESTINATION BYTE POINTER SKIPG T4,T1 ;SET UP THE DESTINATION BYTE COUNT RET ;IF NON-POSITIVE, WE'RE DONE DNCUM1: ife ftki10, ;GET THE BYTE FROM USER BUFFER ifn ftki10, ;GET THE BYTE FROM USER BUFFER IDPB CX,T5 ;PUT IT IN THE MESSAGE BLOCK SOJG T1,DNCUM1 ;LOOP UNTIL DONE STOR T5,MDPTR,(MS) ;STORE THE UPDATED BYTE POINTER RET ;RETURN IFN FTOPS10,< ;Here if we can BLT the user data DNCUMB: HLLZ T4,T2 ;PICK UP ADJUSTED USER BPT'S P&S FIELDS TLO T4,T6 ;MDAUX IS INDEXED BY T6 STOR T4,MDAUX,(MS) ;STORE NEW BEG-OF-MSG BYTE POINTER MOVE T5,T1 ;GET BYTE LENGTH AGAIN ADJBP T5,T4 ;FIGURE BYTE PTR AT END OF NEW DATA STOR T5,MDPTR,(MS) ;STORE NEW END-OF-MSG BYTE POINTER LDB T4,[POINT 3,T2,2] ;PICK UP WORD ALIGNMENT FROM BYTE POINTER MOVNS T4 ;NEGATE ADDI T4,7(T1) ;CALCULATE MESSAGE WORD COUNT ASH T4,-2 ;... IFN FTXMON,< HRRZ T5,T2 ;SOURCE ADDR, USER ALWAYS IN SECTION 0 LOAD T6,MDALA,(MS) ;ALLOCATED ADDRESS OF MONITOR DATA BLK XCT 2,[EXTEND T4,[XBLT]] ;COPY FROM USER TO MONITOR >;END IFN FTXMON IFE FTXMON,< LOAD T5,MDALA,(MS) ;DESTINATION ADDR IN MONITOR SPACE HRL T5,T2 ;SOURCE ADDR IN USER SPACE ADDI T4,-1(T5) ;MAKE DEST END ADDRESS IN SECTION 0 XCT 1,[BLT T5,(T4)] ;COPY USER TO MONITOR >;END IFE FTXMON MOVE T4,T1 ;GET LENGTH (BYTES) AGAIN ADJBP T4,T2 ;MAKE NEW USER BPT MOVEM T4,T2 ;PUT BACK FOR CALLER SETZM T1 ;UPDATED BYTE COUNT FOR CALLER RET ;ONLY RETURN >;END OF IFN FTOPS10 SUBTTL Buffers -- Copy message data to a user buffer ;DNCM2U - Copy message data to a user buffer ; ; Call: ; T1/ Count of bytes ; T2/ Pointer to data ; T3/ Optional second word of byte pointer ; MS/ Pointer to current message segment ; ; Return: ; RET ;IF LENGTH IS NOT CORRECT ; RETSKP ;ON SUCCESSFUL COPY WITH T1 AND T2 CONTAINING ; ; BYTE COUNT AND POINTER ; ; Uses: T1-T6 XRESCD ;Previous context executes run in section 1 DNCM2U::TSTS6 TORESCD IFN DBGS2,> ;*LLMOP* TXNE T2,1B12 ;2-WORD BYTE PTR? HRR T2,T3 ;YES, MAKE LOCAL FOR OLD MACHINES MOVE T4,T1 ;SET UP DESTINATION BYTE COUNT DMOVE T5,T2 ;AND DESTINATION BYTE POINTER OPSTR ,MDBYT,(MS) ;MESSAGE BIG ENOUGH? RET ;NO, LET CALLER DEAL WITH ERROR MOVN T2,T1 ;SET UP NEGATIVE COUNT OPSTRM ,MDBYT,(MS) ;UPDATE THE BYTE COUNT LOAD T2,MDPTR,(MS) ;SET UP THE SOURCE BYTE POINTER TLZE T2,17 ;IS MDPTR INDEXED? TLO T2,T3 ;YES, USE T3, NOT T6 LOAD T3,MDALA,(MS) ;SET UP INDEX FOR MDPTR JRST DNCMU2 ;START IN MIDDLE OF LOOP DNCMU1: ILDB CX,T2 ;GET THE BYTE FROM MESSAGE BLOCK XCTBU [IDPB CX,T5] ;PLACE BYTE IN USER BUFFER DNCMU2: SOJGE T4,DNCMU1 ;DO UNTIL DONE STOR T2,MDPTR,(MS) ;STOR THE UPDATED BP TO MESSAGE MOVE T1,T4 ;UPDATE COUNT FOR CALLER DMOVE T2,T5 ; ALSO POSSIBLY 2-WORD BYTE PTR RETSKP ;RETURN SUCCESS SUBTTL Core manager -- Smear a block of memory with value ;DNSWDS - Smear a value into a block of words ; ;Call: T1/ Address of start of block ; T2/ Address of end of block ; T3/ Value to put in block (typically zero) ; CALL DNSWDS ; Normal Return ; ;Changes T1,T2,T3,T4 INTERNAL DNSWDS XRESCD DNSWDS: MOVEM T3,(T1) ;STORE THE VALUE TO BE SMEARED TESTS1 ;ASSERT THAT WE'RE IN SECTION 1 MOVE T3,T2 ;ADDR OF EO BLOCK INTO T3 MOVE T2,T1 ;ADDR OF BEG OF BLK INTO T2 SUBM T3,T1 ;NUMBER OF WORDS TO COPY INTO T1 XMOVEI T3,1(T2) ;CALC SMEARING DESTINATION ADDR CAILE T1,VBLSIZ ;IS THIS A LEGITIMATE SMEAR? BUG.(CHK,COMSTB,D36COM,SOFT,,,< Cause: The caller has requested that a very large block be smeared. Action: Find out what the caller really wanted to smear and fix the call. >,DNSWD1) CALLRET XBLTAT ;(T1,T2,T3)COPY MONITOR TO MONITOR DNSWD1: MOVEI T1,VBLSIZ ;TRY TO RECOVER FROM OVERSIZE SMEAR CALLRET XBLTAT ;(T1,T2,T3)COPY MONITOR TO MONITOR SUBTTL Core manager -- Copy some words ;DNCPYW - Copy words using a BLT or a XBLT ; ; Call: ; T1/ From ; T2/ To ; T3/ Count ; ; Return: ; RET ;ALWAYS ; Uses: INTERNAL DNCPYW XRESCD DNCPYW: TESTS1 ;ASSERT THAT WE'RE IN SECTION 1 EXCH T1,T3 ;CHANGE TO T1/COUNT, T2/TO, T3/FROM EXCH T2,T3 ;CHANGE TO T1/COUNT, T2/FROM, T3/TO CALLRET XBLTAT ;(T1,T2,T3)COPY MONITOR TO MONITOR SUBTTL Core manager -- Get Some Words ;DNGWDP - Get memory-Lowest priority - process context ;DNGWDN - Get memory-normal priority ;DNGWDH - Get memory-Highest priority ;DNGWDS - Get some words, not zeroed ; ; Call: ; T1/ Count of words we want ; ; Return: ; RET ;ON ALLOCATION FAILURE ; RETSKP ;WITH T1 POINTING TO WORDS ; ; ;Note: The count of words allocated is stored in the word before the ;returned pointer. XRESCD DNGWDS:: IFE FTD36MM,< IFN FTOPS20,< DNGWDH::MOVEI T2,.RESP1 ;Get memory-High priority JRST GTWRDS DNGWDN::SKIPA T2,[.RESP2] ;Get memory-normal priority DNGWDP::MOVEI T2,.RESP3 ;Get memory-Process context (process can be ; descheduled) > IFN FTOPS10,< DNGWDH:: DNGWDN:: DNGWDP:: >> IFN FTD36MM,< DNGWDH:: DNGWDN:: DNGWDP:: > GTWRDS: SAVEAC ;NOTE - THIS ROUTINE "KNOWS" HOW MANY ACS ARE ; SAVED, AND USES THIS KNOWLEDGE TO LOOK AT ; THE STACK. SEE FTLSTCORE. IFE FTD36MM,< STKVAR ; Priority to get memory from ASGRES MOVEM T2,MEMPRI ; Save it > HRRZ P1,T1 ;SAVE THE COUNT MOVEI T2,1(T1) ;T2 GETS NUMBER OF WORDS. IFN FTLSTCOR, ADDI T2,3 ;Overhead for check words IFN FTD36MM,< OPSTR ,CHSIZ,+VBLCB ;WILL A LARGE A-BLOCK SATISFY REQUEST? BUG.(CHK,COMATB,D36COM,SOFT,,,< Cause: For the time being, until we get a real memory-manager for non message-block requests, we only support requests for memory up to the size of a VBL block, see DEFBLK macro. Action: Wait for the real memory manager or make the size of VBLs bigger than they are now. >,RTN) > ;End FTD36MM IFN FTHMMEM,< SKIPN T6,MRQTAB ; Get address of our memory request table IFSKP. ADD T6,P1 ; Index by request amount CAML T6,MRQMAX ; Have we goone too far? IFSKP. AOS (T6) ; Increment the count of requests this size HRRZ T3,(T6) ; Get current outstanding requests HLRZ T4,(T6) ; Get the previous high water mark CAMLE T3,T4 ; Is this higher? HRLM T3,(T6) ; Yes, it becomes new high water mark ENDIF. ENDIF. > ;END FTHMMEM IFN FTD36MM,< XMOVEI T1,VBLCB OPSTR ,CHSIZ,+LBLCB ;SEE IF IT MIGHT BE A LARGE BLOCK XMOVEI T1,LBLCB ;YES, POINTER TO CH FOR LARGE A-BLOCKS OPSTR ,CHSIZ,+BBLCB ;HOW ABOUT A LARGE-MEDIUM BLOCK? XMOVEI T1,BBLCB ;YES, POINTER TO CH FOR LARGE-MEDIUM A-BLOCKS OPSTR ,CHSIZ,+ABLCB ;HOW ABOUT A MEDIUM BLOCK? XMOVEI T1,ABLCB ;YES, POINTER TO CH FOR MEDIUM A-BLOCKS OPSTR ,CHSIZ,+SBLCB ;HOW ABOUT A SMALL BLOCK? XMOVEI T1,SBLCB ;YES, POINTER TO CH FOR SMALL A-BLOCKS STOR P1,CHREQ,(T1) ;;; Remember amount requested CALL DNGRBL ;ALLOCATE AN A-BLOCK (DON'T ZERO IT) RET ;TELL CALLER WE LOST >;END IFN FTD36MM IFE FTD36MM,< IFN FTOPS20,< MOVE T1,T2 ; Number of words needed HRL T1,MEMPRI ; Use priority requested by user MOVEI T2,.RESNP ; from the DECnet extended pool XCALL (MSEC1,ASGRES) > ;End FTOPS20 IFN FTOPS10,< ife ftki10,< ;[JE] We live in 7.02 code... MOVEI T3,DCNACB## ; Get DECnet allocation control block MCALL (RG,MCSEC1,GTXWDS##) ; Go allocate memory >;ki10 ifn ftki10,< PUSHJ P,GETDWS## ;[JE] and thus the routine is named... >;ki10 > RET ; Tell caller we failed to get memory >;END IFE FTD36MM IFN FTLSTCOR,< IFE FTD36MM,< MOVE T2,-6(P) ;STKVAR uses 2 more CAMN T2,[XADDR. DNGTAG] ;IS THIS A CALL FROM GET ZERO WORDS? MOVE T2,-11(P) ;YES, GET ADDRESS OF HIS CALLER > IFN FTD36MM,< MOVE T2,-3(P) ;GET CALLING PC CAMN T2,[XADDR. DNGTAG] ;IS THIS A CALL FROM GET ZERO WORDS? MOVE T2,-6(P) ;YES, GET ADDRESS OF HIS CALLER > MOVEM T2,(T1) ;SAVE CALLER'S PC AT START OF BLOCK AOJ T1, ;POINT PAST WHERE WE SAVED THE PC > ;END IFN FTLOSTCOR MOVEM P1,(T1) ;STORE COUNT IN RH OF OVERHEAD WORD MOVSI T2,'D36' ;MAKE A TEST THINGY HLLM T2,(T1) ;STORE IN LEFT HALF OF FIRST WORD AOJ T1, ;RETURN POINTER TO USER PART OF BLOCK IFN FTLSTCOR,< MOVE T2,T1 ; Get address of user data ADD T2,P1 ; Point to 1 word past end of requested buffer MOVE T3,['D36COM'] ; Get value to check against MOVEM T3,(T2) ; Write value into last word in block > ;End IFN FTLSTCOR RETSKP ;RETURN SUCCESS ENDSV. SUBTTL Core manager -- Get Some Zeroed Words ;DNGWDZ - Just like DNGWDS but the words are smeared to zero. ; Note that this is quite a lot more expensive than DNGWDS. ; ; Call: ; T1/ Count of words we want ; ; Return: ; RET ;ON ALLOCATION FAILURE ; RETSKP ;WITH T1 POINTING TO WORDS ; ; Uses: T1-T4 ; ;Note: The count of words allocated is stored in the word before the ;returned pointer. XRESCD DNGWDZ:: IFE FTD36MM,< IFN FTOPS20,< DNGWZH::MOVEI T2,.RESP1 JRST DNGWZ1 DNGWZN::SKIPA T2,[.RESP2] DNGWZP::MOVEI T2,.RESP3 > IFN FTOPS10,< DNGWZH:: DNGWZN:: DNGWZP:: >> IFN FTD36MM,< DNGWZH:: DNGWZN:: DNGWZP:: > DNGWZ1: SAVEAC P1 ;TO HOLD THE COUNT ;(NOTE, GTWRDS KNOWS HOW MANY ACS ARE SAVED) MOVE P1,T1 ;SAVE THE COUNT CALL GTWRDS ;GET SOME WORDS DNGTAG: RET ;PROPOGATE ERROR RETURN ;Zero the words. MOVE T2,T1 ;ADDRESS OF BLOCK ADDI T2,-1(P1) ;POINT TO LAST WORD IN BLOCK SETZ T3, ;WHAT TO SMEAR IT WITH MOVE P1,T1 ;SAVE ADDRESS OF BLOCK CALL DNSWDS ;SMEAR ZEROES INTO BLOCK MOVE T1,P1 ;RESTORE ADDRESS OF BLOCK FOR CALLER RETSKP ; AND GIVE GOOD RETURN SUBTTL Core manager -- Free Some Words ;DNFWDS - Free what DNGWDS took away ; ; Call: ; T1/ Pointer to words allocated by DNGWDS ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,T2 INTERNAL DNFWDS XRESCD DNFWDS: SOSG T1 ;POINT T1 TO HEADER WORD BUG.(CHK,COMFWZ,D36COM,SOFT,,,< Cause: DNFWDS was called with a 0 pointer. Action: Find the caller on the stack and determine why it has no valid pointer to free space. >,RTN) HLRZ T3,(T1) ;GET THINGY TO CHECK AGAINST. CAIN T3,'D36' ;IS IT WHAT WE PUT THERE? IFSKP. MOVE T2,(P) ; Get caller's address BUG.(HLT,COMMMS,D36COM,SOFT,,<,>,< Cause: When DNGWDS gives out a block of memory, a check word is left right before the first word of memory given to the user. This word contains the length of the block in the right half, and a "check" quantity in the left to verify that this block is what is expected. This bug means that this word has either been trashed, or the pointer we have been passed is bad. Action: First determine if the pointer is bad, if the check word is trashed, or if the check word is 63D. If the check word is 63D the memory has already been returned and we are trying to return it again. If the check word is trashed then possible the owner trashed it or the user of the memory block previous to this one wrote too far. If FTD36MM=0 then the owner of the memory block is recorded in the block's header. For more detail see FREE.MAC. Data: BUFFER - Address of faulty buffer CALLER - Address of caller that provided the buffer >,RTN) ENDIF. MOVEI T2,'63D' ; Destroy check word left half HRLM T2,(T1) ; in case freed more than once HRRZ T2,(T1) ;GET COUNT OF WORDS BEING RETURNED IFN FTLSTCOR,< MOVE T3,T1 ; Get address of current position in block ADDI T3,1(T2) ; Point to first free location after requested MOVE T3,(T3) ; Get test string CAMN T3,['D36COM'] ; Does it match? IFSKP. MOVE T3,-1(T1) ; Get owner's PC BUG. (CHK,COMCWT,D36COM,SOFT,,<,>,< Cause: DNFWDS called with memory to return that had check word at end of requested buffer trashed. Action: See what routine called with the bad block and find out why the check word was smashed. >) ENDIF. > ;End IFN FTLSTCOR IFN FTHMMEM,< SKIPN T3,MRQTAB ;Pointer to request table IFSKP. ADD T3,T2 ;Index to proper place CAMGE T3,MRQMAX ;Be sure we don't go too far SOS (T3) ; and decrement request count ENDIF. > ;END FTHMMEM AOJ T2, ;ADD IN WORD OF OVERHEAD IFN FTLSTCORE,< ADDI T2,3 ;Account for check words SOJ T1, ;DECREMENT POINTER TO OUR BLOCK. SETZM (T1) ;ERASE NAME OF OWNER OF BLOCK >;END IFN FTLSTCORE IFN FTD36MM,< MOVE T3,T2 ;COPY SIZE OF RETURNING BLOCK XMOVEI T2,VBLCB ;ASSUME LARGEST BLOCK SIZE OPSTR ,CHSIZ,+LBLCB ;SEE IF IT MIGHT BE A LARGE BLOCK XMOVEI T2,LBLCB ;YES, POINTER TO CH FOR LARGE A-BLOCKS OPSTR ,CHSIZ,+BBLCB ;HOW ABOUT A LARGE-MEDIUM BLOCK? XMOVEI T2,BBLCB ;YES, POINTER TO CH FOR LARGE-MEDIUM A-BLOCKS OPSTR ,CHSIZ,+ABLCB ;HOW ABOUT A MEDIUM BLOCK? XMOVEI T2,ABLCB ;YES, POINTER TO CH FOR MEDIUM A-BLOCKS OPSTR ,CHSIZ,+SBLCB ;HOW ABOUT A SMALL BLOCK? XMOVEI T2,SBLCB ;YES, POINTER TO CH FOR SMALL A-BLOCKS CALLRET DNFRBL ;T1/ BLOCK TO FREE, T2/ CH BLOCK TO PUT IT ON >;END IFN FTD36MM IFE FTD36MM,< IFN FTOPS20,< XCALLRET (MSEC1,RELRES) ;Release memory > IFN FTOPS10,< EXCH T1,T2 ;CORE1 WANTS T1/COUNT, T2/ADDRESS ife ftki10,< ;[JE] KI10 lives with 7.02 MOVEI T3,DCNACB## ;GET ADDRESS OF DECNET ALLOCATION CONTROL BLOCK MCALL (RG,MCSEC1,GVXWDS##) ;LET GO OF OUR CORE. >;ki10 ifn ftki10,< PUSHJ P,GIVDWS## >;ki10 RET > >;END IFE FTD36MM SUBTTL Core manager -- Get a DECnet-36 message block ;DNGMSG - Get a virgin message block and enough user data space for us ; ;Call: ; T1/ Number of user data bytes needed. ;Return ; RET ;ON ALLOCATION FAILURE ; RETSKP ;T1 POINTS TO MESSAGE BLOCK, AND UD.MSD POINTS ; ; TO USER DATA FIELD, WHEREVER ALLOCATED XRESCD DNGMSG:: TRACE COM,Getting virgin message SAVEAC P1 MOVE P1,T1 ;SAVE COUNT OF USER DATA BYTES REQ'D XMOVEI T1,MBLCB ;POINTER TO CH FOR MESSAGE BLOCKS CALL DNGRBL ;(T1/T1)GO GET THE BLOCK RET ;COULDN'T GET IT, RETURN AN ERROR IFN FTLSTCOR,< MOVE T2,-2(P) ;GET CALLER'S PC MOVEM T2,(T1) ;PUT INTO FIRST HEADER WORD MOVE T2,['D36MSG'] ;PUT TEST THING MOVEM T2,1(T1) ; IN SECOND HEADER WORD ADDI T1,2 ;POINT PAST HEADER WORDS >;END IFN FTLSTCOR MOVE T2,P1 ;GET BACK NUMBER OF USER BYTES DESIRED MOVE P1,T1 ;SAVE ADDR OF BLOCK SETZRO MDALA,+UD.MSD(P1) ;TELL DNMINI WE HAVE NO USER DATA NOW CALL DNMINI ;(T1,T2)MAKE THE MSG BLK SHINY NEW JRST DNGMS1 ;ERROR. RETURN MESSAGE BLOCK FIRST MOVE T1,P1 ;PUT MB ADDRESS WHERE USER CAN FIND IT RETSKP ;GOOD RETURN, TELL CALLER WE WON DNGMS1: MOVE T1,P1 ;GET ADDR OF MSG BLOCK WE WANT TO RETURN IFN FTLSTCOR,< SUBI T1,2 ;POINT TO START OF BLOCK HLRZ T2,1(T1) ;GET TEST THING CAIN T2,'D36' ;TEST IT. IFSKP. MOVE T2,(T1) ;FAILED. GET ALLOCATOR'S ADDRESS MOVE T3,1(T1) ;GET TEST THING MOVE T4,-2(P) ;GET CALLER'S PC BUG.(HLT,COMMS3,D36COM,SOFT,,<,,,>,< Cause: A header word is trashed or there is a bad pointer. Action: Check DNMINI to see why it trashed the check word Data: BLKADR - Block address ALCADR - Address of allocator TESTWD - Test thing CALLER - Address of caller to memory management >) RET ENDIF. SETZM 1(T1) ;CLEAR TEST THING. SETZM (T1) ;CLEAR ALLOCATOR'S PC >;END IFN FTLSTCOR XMOVEI T2,MBLCB ;POINTER TO CH FOR MESSAGE BLOCKS CALLRET DNFRBL ;RELEASE THE BLOCK, AND GIVE BAD RETURN ;Get emergency message block. Same as DNGMSG except it BUGs on failure. INTERNAL DNGEMS XRESCD DNGEMS: TRACE COM,Getting virgin emergency buffer SAVEAC P1 MOVE P1,T1 ;SAVE NUMBER OF USER DATA BYTES NEEDED XMOVEI T1,MBLCB ;POINTER TO CH FOR MESSAGE BLOCKS CALL DNGRBP ;GET BLOCK, PRIV'D TO USE EMERGENCY BLKS RET ;PROPOGATE ERROR RETURN, CALLER WILL BUG IFN FTLSTCOR,< MOVE T2,-2(P) ;GET CALLER'S PC MOVEM T2,(T1) ;PUT INTO FIRST HEADER WORD MOVE T2,['D36EMS'] ;PUT TEST THING MOVEM T2,1(T1) ; IN SECOND HEADER WORD ADDI T1,2 >;END IFN FTLSTCOR MOVE T2,P1 ;GET BACK NUMBER OF USER BYTES DESIRED MOVE P1,T1 ;SAVE ADDR OF BLOCK HERE, JUST IN CASE SETZRO MDALA,+UD.MSD(P1) ;TELL DNMINI WE HAVE NO USER DATA NOW CALL DNMINP ;PRIV'D ENTRY TO GET USER-DATA BUFFER RET ;PROPOGATE ERROR RETURN, CALLER WILL BUG SETONE MBEBF,(P1) ;MARK THIS AS AN EMERGENCY BUFFER FOR ROUTER MOVE T1,P1 ;PUT MB ADDRESS WHERE USER CAN FIND IT RETSKP ;GOOD RETURN, TELL CALLER WE WON SUBTTL Core manager -- Free a DECnet-36 message block ;DNFMSG - Give back what DNGMSG gave us ; ;Call ; T1/ Pointer to message block to return ;Return ; RET ;ALWAYS ; ;Note - If MDALA points to other than UD.DAT we will assume that MDALA ; is a pointer to a separate user data block, and we will return ; that block as well. INTERNAL DNFMSG XRESCD DNFMSG: IFN FTPARANOID,< CAML T1,MBLCB ;THIS MUST COME FROM THE MBL BLOCKS IFSKP. MOVE T2,0(P) ;IT DIDN'T. CALLER'S PC BUG.(HLT,COMMPR,D36COM,SOFT,,<,>,< Cause: DNFMSG caller tried to return a piece of memory not in the range of message blocks. Action: See stack for caller and find why it is trying to return a bad message block. >) RET ENDIF. >;END IFN FTPARANOID IFN FTLSTCOR,< SUBI T1,2 ;POINT TO START OF BLOCK HLRZ T2,1(T1) ;GET TEST THING CAIN T2,'D36' ;TEST IT IFSKP. MOVE T2,(T1) ;FAILED. GET ALLOCATOR'S ADDRESS MOVE T3,1(T1) ;TEST THING MOVE T4,0(P) ;CALLER'S PC BUG.(HLT,COMMS1,D36COM,SOFT,,<,,,>,< Cause: A header word is trashed or there is a bad pointer. Data: BLKADR - Address of memory block ALCADR - Allocator's address TESTWD - Test Word CALLER - Caller to memory management >) RET ENDIF. ADDI T1,2 ;GET PAST THE HEADER WORDS >;END IFN FTLSTCOR XMOVEI T2,UD.DAT(T1) ;GET EXTENDED POINTER TO UD.DAT OPSTR ,MDALA,+UD.MSD(T1) ;GET ALLOCATED ADDRESS OF USER DATA CAMN T3,T2 ;IF MDALA ISN'T US, RELEASE HIM JRST DNFMS0 ;THE UBL IS NOT SEPARATE, JUST RELEASE MBL PUSH P,T1 ;SAVE POINTER TO MBL MOVE T1,T3 ;POINTER TO SEPARATE USER-DATA BLOCK IFN FTLSTCOR,< SUBI T1,2 ;POINT TO START OF BLOCK HLRZ T2,1(T1) ;GET TEST THING CAIN T2,'D36' ;TEST IT. IFSKP. MOVE T2,(T1) ;FAILED. GET ALLOCATOR'S ADDRESS MOVE T3,1(T1) ;TEST THING MOVE T4,-1(P) ;CALLER'S PC BUG.(HLT,COMMS2,D36COM,SOFT,,<,,,>,< Cause: A header word is trashed or there is a bad pointer. Data: BLKADR - Address of memory block ALCADR - Allocator's address TESTWD - Test Word CALLER - Caller to memory management >) POP P,T1 RET ENDIF. SETZM 1(T1) ;CLEAR TEST THING. SETZM (T1) ;CLEAR ALLOCATOR'S PC >;END IFN FTLSTCOR XMOVEI T2,UBLCB ;POINTER TO CH FOR USER DATA BLOCKS CALL DNFRBL ;RELEASE THE USER-DATA BLOCK POP P,T1 ;GET BACK POINTER TO MESSAGE BLOCK DNFMS0: IFN FTLSTCOR,< SUBI T1,2 ;THE HEADER WORDS SETZM (T1) ;CLEAR ALLOCATOR'S ADDRESS SETZM 1(T1) ;CLEAR TEST THING >;END IFN FTLSTCOR XMOVEI T2,MBLCB ;POINTER TO CH FOR MESSAGE BLOCKS CALLRET DNFRBL ;FREE THE MESSAGE BLOCK ITSELF SUBTTL Core manager -- Fixed size block allocation entry points repeat 0, < ;DNGEBL and DNFEBL will be removed completely when code is proven ;DNGEBL - Get an event block ;DNGEBP - (Doesn't exist) ; ;Call: ; ;Return: ; RET ;ON ALLOCATION FAILURE ; RETSKP ;WITH T1 POINTING TO BLOCK DNGEBL::XMOVEI T1,EBLCB ;POINTER TO CH FOR EVENT BLOCKS CALLRET DNGRBL ;ALLOCATE THE BLOCK (DON'T ZERO IT) ;DNFEBL - Free an event data block ;Call ; T1/ Pointer to block to be returned to free pool ;Return ; RET ;Always. ; ;DNFEBL is called by NTMAN DNFEBL::XMOVEI T2,EBLCB ;POINTER TO CH FOR EVENT BLOCKS CALLRET DNFRBL ;DE-ALLOCATE THE BLOCK > ;End repeat 0 SUBTTL Core manager -- Memory manager initialization code ;DNINIM - Initialize fixed core block memory manager. ;Call: ; ;Return: ; RET always. XSWAPCD DNINIM:: IFN FTOPS10,< SAVEAC ;GET US A FEW PRESERVED REGISTERS MOVE T1,DCNVFF ;GET POINTER TO DECNET CORE >;END IFN FTOPS10 IFN FTOPS20,< SAVEAC ;GET US A FEW PRESERVED REGISTERS MOVSI T1,DNBSE1 ;GET BUFFER ADDRESS (START OF DECnet SECTION) MOVE P2,T1 ;SAVE START OF BUFFER ALLOCATION >;END IFN FTOPS20 ;T1 contains pointer to next available word of pool ;P1 contains length of memory init table CHBLKN MOVX P1,CHBLKN ;POINT PAST END OF CH BLOCKS DNINM2: SOJL P1,DNINM4 ;POINT TO PREVIOUS CH BLOCK MOVE T3,P1 ;WHICH CH ARE WE WORKING ON IMULI T3,CH.LEN ;POINTER TO WHICH CH WITHIN CHBLKS XMOVEI T4,CHBLKS ;POINTER TO CHBLKS VECTOR ADD T4,T3 ;POINTER TO OUR CURRENT CH BLOCK LOAD T6,CHNUM,(T4) ;GET NUMBER OF BLOCKS FOR THIS TYPE STOR T6,CHAVL,(T4) ;SAVE NUMBER OF BLOCKS AVAILABLE JUMPLE T6,DNINM2 ;(JUST IN CASE OF DEFINING 0 BLOCKS FOR A TYPE) LOAD T5,CHSIZ,(T4) ;GET SIZE OF BLOCKS FOR THIS TYPE IFN FTFIXCOR,< CALL DNINCH ;(T1/T1)CHECK THAT BLOCK STAYS ON PAGE >; End of FTFIXCOR STOR T1,CHBOT,(T4) ;SAVE START OF POOL FOR THIS TYPE OF BLOCKS STOR T1,CHPTR,(T4) ;SAVE POINTER TO FIRST FREE BLOCK DNINM3: MOVE T2,T1 ;SAVE POINTER TO BLOCK ADD T1,T5 ;POINT TO NEXT BLOCK IFN FTFIXCOR,< CALL DNINCH ;(T1/T1)CHECK THAT BLOCK STAYS ON PAGE >; End of IFN FTFIXCOR STOR T1,FBNXT,(T2) ;STORE POINTER TO NEXT BLOCK SOJG T6,DNINM3 ;DO ANOTHER BLOCK SETZRO FBNXT,(T2) ;LAST BLOCK HAS END OF LIST INSTEAD OF POINTER JRST DNINM2 ;GO DO ANOTHER TYPE OF CORE BLOCK DNINM4: IFN FTOPS10,< MOVEM T1,DCNVFF ;SAVE ADDRESS OF DECNET FIRST FREE >; END IFN FTOPS10 IFN FTOPS20,< ;LOCK DOWN THE PAGES WE'VE JUST ALLOCATED MOVE P1,T1 ;SAVE FINAL ADDRESS IN P1 TLZ P1,-1 ;CLEAR ANY SECTION NUMBER ADDI P1,777 ;ROUND UP TO FULL PAGE LSH P1,-11 ;CONVERT TO NUMBER OF PAGES MOVE T1,P2 ;GET BACK ADDRESS OF START OF ALLOCATION XCALL (MSEC1,FPTA) ;GET THE PAGE TABLE MOVEM T1,P2 ;SAVE FIRST PAGE NUMBER DNINM6: XCALL (MSEC1,MLKPG) ;LOCK THE PAGE IN MEMORY AOS T1,P2 ;STEP TO NEXT PAGE SOJG P1,DNINM6 ;LOCK IT TOO IF ITS NEEDED >;END IFN FTOPS20 IFN FTHMMEM,< MOVEI T1,VBLSIZ ;Reserve a very large block for memory request CALL DNGWDS ; table SETZ T1, ; MOVEM T1,MRQTAB ;Save for DNGWDS/DNFWDS > ;END FTHMMEM CALL DNNMSG ;(/T1)RETURN LESSER OF # MBLs & # UBLs MOVEM T1,DCNTSB ;STORE AS TOTAL SYSTEM BUFFERS CALLRET CHKCNG ;(T1)CHECK CONGESTION THRESHOLDS ;Local subroutine to check that a block is wholly contained in a page ;only called from DNINIM, right here. ; T1/ Proposed starting address of new block ; T5/ Length of new block ;Preserves T2,T4,T5,T6 IFN FTFIXCOR,< DNINCH: CAILE T5,1000 ;BLOCK LESS THAN A PAGE IN LENGTH RET ;NO, CAN'T FIT IT IN A PAGE ANYWAY MOVX T3,777 ;MASK FOR ADDRESSES WITHIN A PAGE AND T3,T1 ;GET BLK'S OFFSET W/IN PAGE ADD T3,T5 ;WILL BLOCK TRNN T3,777000 ; CROSS PAGE BOUNDARY? RET ;NO, LEAVE ADDRESS ALONE ADDI T1,777 ;YES, ROUND TRZ T1,777 ; UP TO NEXT PAGE RET ;ONLY RETURN >; End of IFN FTFIXCOR XRESCD ;Back to resident SUBTTL Core manager -- Increment count of emergency buffers ;DNGEBF - Used to define the number of buffers to be saved for emergencies ;Call ; T1/ Number of buffers to reserve ;Return ; RET ;Not enough buffers to let you do this ; RETSKP ;Extra emergency buffers saved XRESCD DNGEBF:: TRACE COM,Reserving buffers for emergencies SYSPIF ;DELICATE STUFF, MAKE SURE NO ONE TOUCHES US CAML T1,DCNTSB ;#ASKING FOR ALL THE BUFFERS? JRST DONRET ;#YES, LOSE ADDM T1,DCNEMR ;#RAISE EMERGENCY THRESHOLD ADDM T1,DCNCNG ;# AND CONGESTION THRESHOLD ADDM T1,DCNUCG ;# AND UNCONGESTION THRESHOLD MOVNS T1 ;#LOWER SCLINK'S LIMITS ADDB T1,DCNTSB ;#TOTAL SYSTEM BUFFERS CALL CHKCNG ;#(T1)CHECK CONGESTION THRESHOLDS SYSPIN ;#ALLOW INTERRUPTS AGAIN RETSKP ;TELL CALLER WE RESERVED HIS BUFFERS ;CHKCNG check that congestion thresholds still make sense ; after other levels have been shifted ; ;Call: SYSPIF still from changing other thresholds, if needed ; T1/ Contents of DCNTSB CHKCNG: CAMGE T1,DCNCNG ;#COMPARE WITH DECLARED CONGEST THRESHOLD MOVEM T1,DCNCNG ;#CONGEST TOO LARGE, REPLACE WITH DCNTSB CAMGE T1,DCNUCG ;#COMPARE WITH DECLARED UNCONGEST THRESHOLD MOVEM T1,DCNUCG ;#UNCONGEST TOO LARGE, REPLACE WITH DCNTSB MOVE T1,DCNUCG ;#GET UN-CONGESTION THRESHOLD SUBI T1,2 ;#ASSURE A MARGIN OF AT LEAST 2 CAMGE T1,DCNCNG ;# BETWEEN CONGESTION & UNCONGESTION MOVEM T1,DCNCNG ;# TO PREVENT KAF FLIPPING BETWEEN CNG & UCG RET ;#ONLY RETURN FROM CHKCNG SUBTTL Core manager -- Return number of blocks available (for router) ;DNNMSG - Return MIN(UBL,MBL) available. ;Call ;Return ; +1, T1/ Number of blocks available for router ;Note - This is probably innacurate. Re-do later accounting for emergency ;reserves and allocations to session control. INTERNAL DNNMSG XRESCD DNNMSG: LOAD T1,CHAVL,+UBLCB ;GET NUMBER OF USER DATA BLOCKS AVAILABLE OPSTR ,CHAVL,+MBLCB ;MAKE SURE WE HAVE MORE MBL'S LOAD T1,CHAVL,+MBLCB ;NOPE, MBL'S ARE LEAST COMMON, USE THEM. RET ;RETURN SUBTTL Core manager -- Get a Block from a Free Pool ;DNGRBL - Get the first block from free pool, if enough are left ;DNGRBP - Same, Privileged to get emergency blocks ;DNGRBA - Same, but T2 is zero for non-priv'd, -1 for priv'd ;Call ; T1/ Pointer to CH block for this type of block ;Return ; RET ;ON ALLOCATION FAILURE ; RETSKP ;WITH T1 CONTAINING ADDRESS OF BLOCK DNGRBL: TDZA T2,T2 ;ZERO MEANS NO PRIVS FOR EMERGENCY BLKS DNGRBP: MOVEI T2,1 ;NON-ZERO MEANS WE HAVE PRIVS DNGRBA: SAVEAC IFN FTPARANOID,< STKVAR ;Scratch storage > DMOVE P1,T1 ;SAVE POINTER TO CH BLOCK & PRIV FLAG SYSPIF ;#CODE BELOW CANNOT BE INTERRUPTED LOAD T1,CHAVL,(P1) ;#GET CURRENTLY AVAILABLE BLOCK COUNT JE CHCON,(P1),DNGRB2 ;#JUMP IF BLK TYPE NOT CONGESTION CONTROLLED CAMG T1,DCNCNG ;#WILL WE GO BELOW CONGESTION THRESHOLD? SKIPE DCNCON ;#YES, WERE WE ALREADY CONGESTED? JRST DNGRB1 ;#NO, DON'T ANNOUNCE CONGESTION TWICE SETOM DCNCON ;#YES, SET CONGESTION FLAG SYSPIN TRACE COM,DNGRBL congested CALL NSPCG ; TELL NSP THAT WE ARE GETTING CONGESTED SYSPIF LOAD T1,CHAVL,(P1) ;#GET NEW AVAIL COUNT AFTER NSPCG CALL DNGRB1: CAMG T1,DCNEMR ;#WILL WE GO BELOW EMERGENCY THRESHOLD? JUMPE P2,DONRET ;#YES, DON'T GIVE HIM THE BLOCK UNLESS PRIV'D DNGRB2: JUMPLE T1,DONRET ;#NO, FAIL IF THERE ARE NO MORE BLOCKS OPSTRM ,CHAVL,(P1) ;#DECREMENT AVAILABLE BLOCKS LOAD T1,CHLWM,(P1) ;;; Get the low water mark so far LOAD T2,CHAVL,(P1) ;;; and current available CAMLE T1,T2 ;;; Have we gone lower STOR T2,CHLWM,(P1) ;;; Yes, remember new mark OPSTR ,CHPTR,(P1) ;#GET PTR TO FIRST AVAILABLE BLOCK BUG.(CHK,COMIEL,D36COM,SOFT,,,< Cause: CHAVL, the available count, indicated there was at least one block on the free list, but the first pointer was zero. Action: A forward pointer in a block which was returned some time ago was probably smashed. >,DONRET) LOAD T2,FBNXT,(T1) ;#GET PTR TO NEXT AVAILABLE BLOCK IFN FTPARANOID,< JUMPE T2,DNGRB3 ;IF NEXT POINTER IS ZERO, IT'S OK MOVEM T1,S1 ;SAVE POINTER TO CURRENT BLOCK MOVEM T2,S2 ;SAVE POINTER TO NEXT BLOCK MOVE T1,T2 ;GET POINTER TO NEXT BLOCK MOVE T2,P1 ;GET POINTER TO CH BLOCK CALL DNCHFB ;CHECK THE NEXT BLOCK JRST DONRET ;;; We don't ever expect to get here cause ;;; DNCHFB BUGHLT's if error MOVE T1,S1 MOVE T2,S2 DNGRB3: >;END OF IFN FTPARANOID STOR T2,CHPTR,(P1) ;#POINT PAST BLOCK WE NOW HAVE SYSPIN ;#ALLOW INTERRUPTS AGAIN IFN FTPARANOID,< MOVE T2,P1 ;COPY PTR CALL DNCHFB ;CHECK PTR TO CORE WE HAVE BEEN GIVEN RET ;IN CASE WE FIND OUR BUG >;END OF IFN FTPARANOID IFN FTLSTCOR,< LOAD T2,CHSIZ,(P1) ; Get size of this block in words ADD T2,T1 ; Point to 1 word past end MOVE T3,['D36COM'] ; Get value to check against MOVEM T3,-1(T2) ; Write value into last word in block > ;End IFN FTLSTCOR RETSKP ;RETURN SUCCESS ENDSV. ;DNFRBL - Free a block ;Call: T1/ Ptr to block to be freed ; T2/ Ptr to CH block for free list ; CALL DNFRBL ; Only Return DNFRBL: SAVEAC DMOVE P1,T1 ;T1/ SAVE ADDR OF BLOCK TO BE RETURNED ;T2/ SAVE ADDR OF CH BLOCK IFN FTPARANOID,< CALL DNCHFB ;CHECK PTR TO CORE WE HAVE BEEN GIVEN RET ;IN CASE WE FIND OUR BUG >;END OF IFN FTPARANOID IFN FTLSTCOR,< MOVE T1,P1 ; Get back address of block LOAD T2,CHSIZ,(P2) ; Get allocated size of block ADDI T1,-1(T2) ; Point to last word MOVE T1,(T1) ; Get test string CAMN T1,['D36COM'] ; Does it match? IFSKP. MOVE P2,-3(P) ; Caller's PC BUG. (CHK,COMEBT,D36COM,SOFT,,<,>,< Cause: DNFRBL called with block to return that had its last word smashed. Action: See who called with the bad block and find out why the last word was smashed. >) RET ENDIF. > ;End FTLSTCOR SYSPIF ;#KEEP DATA BASE CLEAN WHILE WE CHANGE IT LOAD T2,CHPTR,(P2) ;#ADDRESS OF CURRENT FIRST AVAIL BLOCK STOR T2,FBNXT,(P1) ;#SAVE IN OUR FREE BLOCK STOR P1,CHPTR,(P2) ;#FIRST AVAIL BLOCK IS NOW US OPSTRM ,CHAVL,(P2) ;#INCREMENT THE NUMBER OF AVAIL BLOCKS SKIPN DCNCON ;#IS SYSTEM CONGESTED? JRST DONRET ;#NO, SYSPIN AND RETURN TMNN CHCON,(P2) ;#IS BLK TYPE CONGESTION CONTROLLED? JRST DONRET ;#NO, SYSPIN AND RETURN ;Here if system is congested, whether or not we are returning a message blk. LOAD T1,CHAVL,+UBLCB ;#YES, GET NUMBER OF USER DATA BLOCKS AVAILABLE OPSTR ,CHAVL,+MBLCB ;#MAKE SURE WE HAVE MORE MBL'S LOAD T1,CHAVL,+MBLCB ;#NOPE, MBL'S ARE LEAST COMMON, USE THEM. CAMGE T1,DCNUCG ;#ARE WE AT UNCONGESTION THRESHOLD? JRST DONRET ;#NO, SYSPIN AND RETURN MOVE T1,DCNTSB ;#YES, CHECK SCTL'S RESERVATION COUNTER SUB T1,DCNRSB ;#SUBTRACT RESERVED FROM TOTAL BUFFERS CAMGE T1,DCNUCG ;#DIFFERENCE ABOVE UNCONGEST THRESH TOO? JRST DONRET ;#NO, MUST HAVE RESERVED SMALL BFRS IN MSG BLK SETZM DCNCON ;#YES, NO LONGER CONGESTED SYSPIN ;END OF CRITICAL SECTION CALLRET NSPCR ;TELL NSP & SCTL THE NEWS DONRET::SYSPIN ;GENERAL SYSPIN/RET FOR D36COM RET SUBTTL DNMCUB - Check for trashed UBL ;Call: ; T1/ Address of UBL ; ; BUGCHK's if trashed UBL detected IFN FTLSTCOR,< DNMCUB::XMOVEI T2,UBLCB ; Address of UBL core block LOAD T2,CHSIZ,(T2) ; Get allocated size of block ADDI T1,-3(T2) ; Point to last word MOVE T1,(T1) ; Get test string CAME T1,['D36COM'] ; Does it match? BUG. (CHK,D36UBT,D36COM,SOFT,,,< Cause: DNADLL called with message received that had its last word smashed. Action: See who called DNADLL with a bad block. Look for too short a buffer from DNADLL or a message too long from driver or a message beginning one or more words too far into buffer. >) RET > ;End IFN FTLSTCOR SUBTTL Core manager -- Checking routines for debugging only IFN FTCORBUG,< ;DNCHCH - Check CH pointer for validity. Debugging routine only ;Call ; T1/ CH pointer to check. ;Return ; RET ;If we find our BUG ; RETSKP ;If the CH is kosher DNCHCH: SAVEAC ;SAVE SOME ACS SYSPIF ;TURN OFF INTERRUPTS FOR A WHILE XMOVEI T2,CHBLKS ;GET POINTER TO VALID CH BLOCKS MOVE T3,T2 ;COPY IT ADDI T3,CH.LEN* ;POINTER TO LAST VALID BLOCK CAMG T1,T3 ;ARE WE BEYOND GOOD BLOCKS? CAMGE T1,T2 ;OR BELOW GOOD BLOCKS? BUG.(CHK,COMCHO,D36COM,SOFT,,,< Cause: In the core block checking routines, the internal pointer to the CH begstr applying to this type of block is bad. This may mean that your executable code has been trashed. >,DNCHX) MOVE T4,T1 ;SAVE A COPY OF CH POINTER SUB T1,T2 ;GET RELATIVE ADDRESS WITH BLOCKS IDIVI T1,CH.LEN ;FIND OUT IF WE ARE ON A BOUNDARY SKIPE T2 ;IF NO REMAINDER, THE ADDRESS IS GOOD BUG.(CHK,COMCHB,D36COM,SOFT,,,< Cause: A pointer internal to the core management routines is off by a few words. This probably means that an AC has been trashed by adding to it or XORing some bits. >,DNCHX) LOAD T1,CHAVL,(T4) ;GET NUMBER OF AVAILABLE BLOCKS OPSTR ,CHNUM,(T4) ;COMPARE AGAINST TOTAL NUMBER OF BLOCKS BUG.(CHK,COMCHA,D36COM,SOFT,,,< Cause: When checking the CH begstr for a type of block, we noticed that we have more blocks available than we started out with. Since DNCHFB is supposed to defend against this, what probably has happened is that CHNUM has been trashed. >,DNCHX) JN CHBOT,(T4),DNCHX1 ;MAKE SURE WE HAVE BEEN INITIALIZED BUG.(CHK,COMMMI,D36COM,SOFT,,,< Cause: The field CHBOT, which indicates where a free core pool starts, is zero. This field gets set when the core manager initializes. Action: If DNINIM has already been called, check it to make sure it is initializing all CH blocks. >,DNCHX) DNCHX1: AOS (P) ;GIVE SKIP RETURN DNCHX: SYSPIN ;GIVE UP INTERLOCK RET ; AND RETURN >;END OF IFN FTCORBUG SUBTTL Core manager -- Check pointer for validity IFN FTPARANOID,< ;DNCHFree Block - Check Free Block pointer for validity. ; ;Call: ; T1/ Free Block pointer to check. ; T2/ CH pointer for this Free Block ; Note, call when you think the Free Block is NOT on the free list ;Return: ; RET ;When we find our bug ; RETSKP ;If Free Block is kosher DNCHFB: SAVEAC DMOVE P1,T1 ;Save FB & CH pointers IFN FTCORBUG,< MOVE T1,T2 ;GET AC DNCHCH WANTS CALL DNCHCH ;CHECK THE CH POINTER TO MAKE SURE RET ;OOPS >; END IFN FTCORBUG LOAD T3,CHBOT,(P2) ;GET ADDRESS OF START OF POOL IFE FTFIXCOR,< ;these checks don't work on page-aligned ; pools. LOAD T4,CHNUM,(P2) ;GET NUMBER OF BLOCKS SOJ T4, ;BACK DOWN BY ONE, TO GET HIGHEST NUMBER BLOCK OPSTR ,CHSIZ,(P2) ;MULTIPLY BY SIZE ADD T4,T3 ;ADD IN LOW ADDR, GET HIGHEST LEGAL ADDR FOR FB CAMG P1,T4 ;RANGE CHECK THE FB POINTER >; End of IFE FTFIXCOR CAMGE P1,T3 ;NOT ABOVE MAX, CHECK FOR BELOW MAX BUG.(HLT,COMFBO,D36COM,SOFT,,,< Cause: A free block pointer being checked is not pointing to the free core allocated for this type of block. Action: Find out who supplied this pointer. >,RTN) IFE FTFIXCOR,< ;these checks don't work on page-aligned ; pools. MOVE T1,P1 ;GET BACK FB POINTER SUB T1,T3 ;CONVERT POINTER TO RELATIVE ADDR OPSTR ,CHSIZ,(P2) ;CONVERT TO ABSOLUTE NUMBER OF BLOCK SKIPE T2 ;MAKE SURE WE WERE ON A BLOCK BOUNDARY BUG.(HLT,COMFBT,D36COM,SOFT,,,< Cause: A free block pointer is off by a few words. This probably means that the user of this pointer had added a constant, and forgot to restore it when giving back the block. Action: Trace the user of this pointer, and make sure the pointer is valid when given to the memory manager. >,RTN) >; End of IFE FTFIXCOR IFN FTCORBUG,< ;Check the entire FB data structure, making sure all pointers in blocks ; are good, and this block isn't already on the free list. SYSPIF ;TURN OFF INTERRUPTS LOAD FREE2,CHAVL,(P2) ;GET NUMBER OF BLOCKS WE THINK ARE ON LIST LOAD T1,CHPTR,(P2) ;GET POINTER TO FIRST FB BLOCK DNCHF1: JUMPE T1,DNCHF2 ;AT END OF LIST, EXIT IFE FTFIXCOR,< ;these checks don't work on page-aligned ; pools. CAMG T1,T4 ;IS IT ABOVE HIGH RANGE? >; End of IFE FTFIXCOR CAMGE T1,T3 ;OR BELOW LOW RANGE? BUG.(CHK,COMAFB,D36COM,SOFT,,,< Cause: There is a block on a free list whose address is not in the range expected for this list. The offending pointer is in P1. Action: Somebody back on the stack is probably returning a block to the wrong free list or is returning a junk pointer. >,DNCHX) MOVE FL,T1 ;SAVE FOR DURATION OF ROUTINE IFE FTFIXCOR,< ;these checks don't work on page-aligned ; pools. SUB T1,T3 ;RELATIVE POINTER OPSTR ,CHSIZ,(P2) ;CONVERT TO ABSOLUTE BLOCK NUMBER SKIPE T2 ;MAKE SURE WE WERE ON A BLOCK BOUNDARY BUG.(CHK,COMFBB,D36COM,SOFT,,,< Cause: DNCHFB has found a block on a free list, most likely just returned to it, whose address is not on a block boundary for blocks on this free list. The offending pointer is in P1. Action: Somebody back on the stack is probably returning a junk pointer, either a real pointer to a block which has been incremented or decremented or a completely junk pointer. >,DNCHX) >; End of IFE FTFIXCOR CAMN FL,P1 ;MAKE SURE THIS ISNT THE BLOCK I HAVE BUG.(CHK,COMFBF,D36COM,SOFT,,,< Cause: The block that P1 points at is already on the free list and is being returned again. Action: Somebody back on the stack is returning a block which is already free. Either that caller is in error or some previous returner is in error. >,DNCHX) LOAD T1,FBNXT,(FL) ;GET NEXT POINTER IN THE LIST SOJA FREE2,DNCHF1 ;AND TRY AGAIN DNCHF2: SKIPE FREE2 ;ASSURE WE CHECKED RIGHT NUMBER OF BLOCKS BUG.(CHK,COMFBA,D36COM,SOFT,,,< Cause: DNCHFB walked a free list and found a different number of blocks on the list than the header indicated. Action: Somebody probably smashed a forward pointer in a block which was returned some time ago. Find out who. >,DNCHX) SYSPIN ;TURN THEM BACK ON >;END OF IFN FTCORBUG RETSKP ;INDICATE ALL WARM AND FUZZY ;DNCHMB - Check a message block pointer. Called from ROUTER. ;Call ; MB/ Pointer to message block ;Return ; Always. Will BUG if an error, but will return. INTERNAL DNCHMB XRESCD DNCHMB: SAVEAC ;WE ARE GOING TO USE THESE ACS MOVE T1,T3 ;MESSAGE BLOCK POINTER IFN FTLSTCOR,< SUBI T1,2 ;ALLOW FOR HEADER WORDS >;END IFN FTLSTCOR XMOVEI T2,MBLCB ;POINTER TO THE CH STRUCTURE WE CARE ABOUT. JRST DNCHFB ;GO AND DO COMPLETE CHECKS FOR THE POINTER >;END OF IFN FTPARANOID SUBTTL Time -- Get current time in ms. ;DNGTIM - Get a timestamp in the proper units into T1 ; ;Call: CALL DNGTIM ; Normal Return with time in T1 ;Changes T1,T2 TIMBAS==:^D1000 ;FRACTIONS OF A SECOND WITH WHICH TIME ;IS REPRESENTED. USED BY OTHER ;ROUTINES WHICH MANIPULATE TIMERS INTERNAL DNGTIM XRESCD DNGTIM: IFN FTOPS10,< MOVE T1,UPTIME## ;GET JIFFIES OF UPTIME IMULI T1,TIMBAS ;MAKE IT MILLI- PUSH P,T2 ;SAVE T2 FOR CALLER IDIVI T1,JIFSEC## ; SECONDS OF UPTIME POP P,T2 ;PROTECT CALLER >;End of IFN FTOPS10 IFN FTOPS20,< MOVE T1,TODCLK ;GET MILLSECONDS OF SYSTEM UPTIME >;End of IFN FTOPS20 RET SUBTTL Network management -- NTPARM - parameters ;NTPARM - network management operations for parameters ; ;This routine will make it easier to implement the 'set', 'read' and 'clear' ; network management functions. ; ;Call: T1/ address of parameter table ; T2/ length of parameter table (i.e. # of parameters defined) ; T3/ requested function (NF.SET, NF.RED or NF.CLR) ; P1/ address of NF block ; CALL NTPARM ; +1 return on error with T1/ network management error code ; +2 return on success ; ;The PARAMETER macro that is used to define the parameter table contains ; instructions to be executed to set, read and clear a parameter. NTPARM ; expects this instruction (that of course may be a CALL) to: ; - always return +1 ; ;When the instruction is executed, P1 will contain the NF address and T2 ; on set: the new value ; on clear: the default value specified in the table ; on read: should return with the new value ; ; NTPARM will not touch any AC except T1-T4 ; INTERNAL NTPARM XSWAPCD NTPARM: STKVAR MOVEM T1,TABADR ;Save table address MOVEM T2,TABLEN ; and table length SETZM FUNC ;Assume function is READ (FUNC EQ 0) CAIN T3,NF.SET ;Is it SET? SETOM FUNC ; -yes, set FUNC EQ -1 CAIN T3,NF.CLR ;Or CLEAR? MOVEM T3,FUNC ; -yes, move value GT 0 to FUNC ASSUME NF.CLR,GT,0 ;Loop over parameter table, AC usage is: ; T2/ parameter # ; T3/ loop index ; T4/ address of PA block LOAD T2,NFPRM,(P1) ;Get parameter number SETZ T3, ;Begin at index 0 DO. ;LOOP CAML T3,TABLEN ; Done all entries RNMXER (NF.UPT) ; -no match, return error MOVE T4,TABADR ; Get table address ADD T4,T3 ; and make pointer to current table entry MOVE T4,(T4) ; and make pointer to PA block OPSTR ,PAPNR,(T4) ;Correct parameter number? EXIT. ; -yes, exit loop AOJA T3,TOP. ; -no, loop back and try next index ENDDO. TMNN PABEX,(T4) ;Is NTMAN supplied buffer ok? IFSKP. SETOM BUFLAG ; Indicate buffer is expected TMNE NFBFF,(P1) ; Is buffer present? IFSKP. BUG. (CHK,NTNBFS,D36COM,SOFT,,,< Cause: The routine NTPARM was called to handle a network management parameter. The caller of NTPARM said that it expects the call from NTMAN to supply a buffer for the parameters to be read from or stored into. None was supplied. >) RNMXER (NF.MPE) ; Return "management program error" ENDIF. ELSE. ;Verify that buffer flag is clear (this routine handles only single value ; returns) SETZM BUFLAG ; No buffer, data appears in argument block TMNN NFBFF,(P1) ;Buffer flag set? IFSKP. ; -yes, BUG.(CHK,NTBSUP,D36COM,SOFT,,,< Cause: The routine NTPARM was called to handle a network management parameter. The routine can only handle returns of a single value, but NTMAN had supplied a multi-word buffer. >) RNMXER (NF.MPE) ; and return "management program error" ENDIF. ENDIF. ;Here when buffers are checked and table address is selected MOVX T1,NF.FCS ;This will be a flag (sigh) to indicate error SKIPL FUNC ;Is it SET? IFSKP. ; -yes, TMNE PANST,(T4) ;Can this parameter be set RNMXER (NF.OPF) ;No, return error LOAD T2,NFBUF,(P1) ; No, get new value and check it TMNE PADRC,(T4) ;Have we been told not to range check this IFSKP. ;value? OPSTR ,PAMIN,(T4) ; Less than the minimum? OPSTR ,PAMAX,(T4) ; or greater than the maximum? RNMXER (NF.IPV) ; Yes, bad value ENDIF. OPSTR ,PASET,(T4) ; Execute instruction to do SET (If the ; execute calls a routine it is not obliged ; to use T2) ELSE. SKIPG FUNC ; -no, is it CLEAR IFSKP. ; -yes, TMNE PANCL,(T4) ;Can this parameter be cleared? RNMXER (NF.OPF) ;No, return error LOAD T2,PADEF,(T4) ; Load default value as promised OPSTR ,PACLR,(T4) ; execute instruction to do CLEAR (If the ; executed intruction calls a routine the ; the routine is not obliged to use T2 ELSE. ; -no, it is READ OPSTR ,PARED,(T4) ; Get value SKIPL BUFLAG ; If buffer present data is already stored STOR T2,NFBUF,(P1) ; and return it in NF block ENDIF. ENDIF. ASSUME NF.NDP,EQ,0 JUMPLE T1,RTN ; If T1 is negative (error) or 0 (no data), ; then return error RETSKP ;All done, return ENDSV. XRESCD SUBTTL Network management -- NTCTRS - counters ;NTCTRS - network management operations for counters ; ;This routine will make it easier to implement the 'show' and 'show and zero' ; network management functions. ; ;Call: T1/ address of counter table ; T2/ length of counter table (i.e. # of counters defined) ; T3/ requested function (NF.SHO or NF.SZC) ; P1/ address of NF block ; CALL NTCTRS ; +1 return on error with T1/ network management error code ; +2 return on success ; ;The COUNTER macro that is used to define the counter table contains ; instructions to be executed to read and to clear a counter. NTCTRS ; expects this instruction (that of course may be a CALL) to: ; - always return +1 ; - return the counter value in T1 ; - not destroy any accumulators, including T2-T4 ;When the instruction is executed, P1 will contain the NF address. NTCTRS ; will not touch any AC except T1-T4 ; ;If the read/read & clear operation has to be interlocked, then the caller ; is responsible for interlocking before calling NTCTRS. INTERNAL NTCTRS XSWAPCD NTCTRS: STKVAR MOVEM T1,TABADR ;Save counter table address MOVEM T2,TABLEN ; and length of table SETZM DOCLR ;Assume read-only operation CAIN T3,NF.SZC ;Is it zero also? SETOM DOCLR ; -yes, flag clear should be done ;Verify that the 'buffer present' flag is set TMNE NFBFF,(P1) ;Is it set? IFSKP. ; -no, bugcheck and return error BUG.(CHK,NTNBUF,D36COM,SOFT,,,< Cause: NTMAN requested a show counter operation, but did not supply a buffer to store the counters in. >) RNMXER (NF.MPE) ; and return "management program error" ENDIF. ;Verify that buffer is large enough for all counters in table MOVE T1,TABLEN ;Get # of counters ASH T1,1 ; and we use two words for each counter OPSTR ,NFBLN,(P1) ;Compare with supplied size IFSKP. ; -too big, BUG.(CHK,NTBTSM,D36COM,SOFT,,,< Cause: NTMAN requested a show counter operation, but did not supply a buffer large enough to store all the counters. >) RNMXER (NF.MPE) ; -and return "management program error" ENDIF. STOR T1,NFBLN,(P1) ;Store # of words we are going to write... ;Loop over all counters, AC usage is: ; T2/ address of counter buffer ; T3/ index into counter table ; T4/ pointer to current CT block LOAD T2,NFBUF,(P1) ;Get buffer address SETZ T3, ;Start at index 0 DO. ;LOOP CAML T3,TABLEN ; Done all counters yet? RETSKP ; -yes, return suceess MOVE T4,TABADR ; Get address of counter table ADD T4,T3 ; and add in index MOVE T4,(T4) ; and make pointer to CT block LOAD T1,CTHDR,(T4) ; Get counter header (width,,nr) MOVEM T1,(T2) ; and store in buffer OPSTR ,CTRED,(T4) ; Read the value of the counter MOVEM T1,1(T2) ; and store in buffer ADDI T2,2 ; Update buffer pointer with 2 TMNN CTBMF,(T4) ; Is this a bit mapped counter? IFSKP. SETONE KBBMF,-2(T2) ; Yes, set the flag for NTMAN OPSTR ,CTBMP,(T4) ;Get the bit map MOVEM T1,(T2) ; and store for NTMAN AOJ T2, ; and advance the buffer pointer ENDIF. SKIPE DOCLR ; Should the counter be cleared? OPSTR ,CTCLR,(T4) ; -yes, do so! AOJA T3,TOP. ; Update loop index and loop back ENDDO. ;Will never get here ENDSV. XRESCD SUBTTL Trace -- Interface for exec-mode trace. IFN FTTRACE!FTMINTrace,< ;.TCRLF -- TYPE OUT AN END OF LINE ;.TTABC -- TYPE OUT A TAB ;.TRBRK -- TYPE OUT A RIGHT BRACKET (CLOSE BRACKET PAIR) ;.TSPAC -- TYPE OUT A SPACE CHARACTER .TCRLF::MOVEI T1,"M"-100 ;CARRIAGE RETURN PUSHJ P,.TCHAR ;PRINT THE CHARACTER OUT MOVEI T1,"J"-100 ;LION FEED PJRST .TCHAR ;FINISH OFF .TTABC::MOVEI T1,"I"-100 PJRST .TCHAR ;TYPE OUT A TAB .TRBRK::MOVEI T1,"]" ;RIGHT BRACKET PJRST .TCHAR ;TYPE IT OUT .TSPAC::MOVEI T1," " ;SPACE PJRST .TCHAR ;TYPE IT OUT TOO. ;.TDECW -- TYPE OUT SIGNED DECIMAL NUMBER ;.TOCTW -- TYPE OUT SIGNED OCTAL NUMBER ;.TRDXW -- TYPE OUT SIGNED NUMBER (RADIX IN T3) ; (IF RADIX .GT. 9, WILL USE ALPHAS AFTER DIGITS) ;CALL: MOVE T1,NUMBER ; PUSHJ P,.TOCTW/.TDECW/.TRDXW ;USES T1, T2, T3 .TOCTW::SKIPA T3,[10] ;INITIALIZE FOR OCTAL RADIX .TDECW::MOVEI T3,^D10 ;INITIALIZE FOR DECIMAL RADIX .TRDXW::JUMPGE T1,TRDXW1 ;CHECK FOR NEGATIVE PUSH P,T1 ;SAVE NUMBER FROM .TCHAR MOVEI T1,"-" ;YES--GET MINUS PUSHJ P,.TCHAR ;PRINT IT POP P,T1 ;RESTORE OUR NUMBER MOVMS T1 ;GET MAGNITUDE TRDXW1: IDIV T1,T3 ;DIVIDE BY RADIX PUSH P,T2 ;SAVE REMAINDER SKIPE T1 ;SEE IF ANYTHING LEFT PUSHJ P,TRDXW1 ;YES--LOOP BACK WITH PD LIST POP P,T1 ;GET BACK A DIGIT ADDI T1,"0" ;CONVERT TO ASCII CAILE T1,"9" ;SEE IF OVERFLOW DIGITS ADDI T1,"A"-"9"-1 ;YES--SWITCH TO ALPHABETICS PJRST .TCHAR ;TYPE IT AND RETURN SUBTTL Trace -- SCAN's output routines ;.TSTRG -- TYPE ASCIZ STRING ;CALL: MOVEI T1,LOCTN. OF STRING ; PUSHJ P,.TSTRG ;USES T1 .TSTRG::HRLI T1,(POINT 7) ;CONVERT ADDRESS TO POINTER TRNN T1,-1 ;SEE IF SOMETHING THERE POPJ P, ;NO--RETURN EMPTY HANDED PUSH P,T1 ;STORE IN SAFE PLACE [501] TSTRG1: ILDB T1,(P) ;GET NEXT CHARACTER [501] JUMPE T1,[ ;RETURN WHEN DONE [501] POP P,T1 ;PUT T1 BACK POPJ P,] ;RETURN PUSHJ P,.TCHAR ;OUTPUT CHARACTER JRST TSTRG1 ;LOOP UNTIL DONE SUBTTL Trace -- Routine store character in shared buffer ;.TCHAR -- TYPE OUT A CHARACTER ;CALL: MOVEI T1,CHARACTER ; PUSHJ P,.TCHAR ;This routine is the meat of the trace facility - Each character goes ;through here, being deposited in the user buffer according to a ;carefully established protocol. If any changes are made, make very ;sure D36TRC is capable of handling them. ;*#* Note 0:T2 Will be set by putting a snoop breakpoint at DCNTRA. ;*#* Note 1: The AOS SOS here assumes that any PI excursion will take less ; time than the user would to read the entire buffer ;*#* Note 2: The wrapping of the buffer must be done with SYSPIF, since ; we could have the other cpu use an invalid byte pointer ; while we are resetting stuff XP TAKBYT,0 XP LSTBYT,2 .TCHAR::SETZ T2, ;CLEAN OUT OUR AC. SNOOP WILL SET VALUE DCNTRA: SKIPN T2 ;GET ADDRESS OF USER'S BLOCK, AND MAKE SURE POPJ P, ; WE HAVE A USER'S BLOCK. IF NOT, RETURN NOW. ;(*#* Note 0 *#*) ;RESERVE A BYTE AOS T3,TAKBYT(T2) ;BUMP NUMBER OF BYTES IN BUFFER TAKEN CAML T3,MAXBYT ;IS THIS GOING TO FIT? JRST [ SOS TAKBYT(T2) ;NO, BUMP THE COUNT BACK DOWN AOS LSTBYT(T2) ;BUMP COUNT OF LOST BYTES POPJ P,] ;RETURN QUIETLY (*#* Note 1 *#*) ;WE HAVE OUR BYTE RESERVED. LET'S PUT IT IN THE BUFFER SYSPIF ;(*#* Note 2 *#*) AOS T3,CURBYT ;#INCREMENT CURRENT BYTE POSITION IN BUFFER CAML T3,LASBYT ;#DO WE HAVE TO WRAP AROUND? JRST [ SETZM CURBYT ;#RESET CURRENT BYTE POSITION MOVE T3,ZERBPT ;#GET BYTE POINTER TO THE ZEROTH BYTE IN BUFFER MOVEM T3,CURBPT ;#SAVE AS CURRENT BYTE POINTER JRST .+1] IDPB T1,CURBPT ;#DEPOSIT THE BYTE IN THE USER'S BUFFER SYSPIN ;ALLOW OTHER CPU IN CAIE T1,12 ;IS THIS A LINE FEED? RET ;NO, JUST RETURN MOVE T1,TRAJOB ;YES, GET JOB NUMBER OF TRACER JRST WAKJOB## ;WAKE HIM UP >;END OF IFN FTTRACE!FTMINTR SUBTTL TOPS10 -- AC save routines ;These routines are defined in MACSYM.REL, but we normally don't load ;with that, so here they are: IFN FTOPS10,< .SAV1:: PUSH P,.FPAC CALL 0(.SAC) TRNA AOS -1(P) POP P,.FPAC RET .SAV2:: PUSH P,.FPAC+0 PUSH P,.FPAC+1 CALL 0(.SAC) TRNA AOS -2(P) POP P,.FPAC+1 POP P,.FPAC+0 RET .SAV3:: PUSH P,.FPAC+0 PUSH P,.FPAC+1 PUSH P,.FPAC+2 CALL 0(.SAC) TRNA AOS -3(P) POP P,.FPAC+2 POP P,.FPAC+1 POP P,.FPAC+0 RET .SAV4:: ADJSP P,4 DMOVEM .FPAC+0,-3(P) DMOVEM .FPAC+2,-1(P) CALL 0(.SAC) TRNA AOS -4(P) DMOVE .FPAC+0,-3(P) DMOVE .FPAC+2,-1(P) ADJSP P,-4 RET >;END OF IFN FTOPS10 SUBTTL Kontroller data DEFINE KNMMCS,< ; Symbol,Name,Cost, Maximum receive block size KNMMAC LD.TST,TST, 1, 0 ;TST DEVICE KNMMAC LD.DTE,DTE, 3, <^D576> ;DTE DEVICE KNMMAC LD.KDP,KDP, 4, <^D576> ;KDP DEVICE KNMMAC LD.DDP,DDP, 5, <^D576> ;DDP DEVICE KNMMAC LD.CIP,CI, 2, <^D576> ;CI DEVICE IFN FTOPS20,< KNMMAC LD.ETH,NI, 1, <^D1504-%RTEHS> ;NI DEVICE >; END IFN FTOPS20 IFN FTOPS10,< KNMMAC LD.ETH,ETH, 1, <^D1504-%RTEHS> ;ETHERNET CHANNEL >; END IFN FTOPS10 KNMMAC LD.DMR,DMR, 2, <^D576> ;DMR DEVICE >;END OF KNMMCS DEFINE KNMMAC(sym,name,cost,bsize),< IFN <.-KONNAM-sym>, ASCII /name/ >;END OF KNMMAC RESCD IFN FTOPS10, KONNAM::KNMMCS IFN <.-KONNAM-LD.MAX-1>, IFN FTOPS10, DEFINE KNMMAC(sym,name,cost,bsize), KONCST::KNMMCS DEFINE KNMMAC(sym,name,cost,bsize), MXLBSZ::KNMMCS XRESCD SUBTTL Initialization routines -- Compute Core Requirements ;DCNCCR computes the total DECnet core requirements. ;Call: ; PUSHJ P,DCNCCR ;Returns: ; T1/ Size of DECnet core IFN FTOPS10,< INTERNAL DCNCCR XRENT DCNCCR ifn ftki10, SAVEAC ;SAVE P1 SETZ P1, ;START WITH ZERO PUSHJ P,D36CCR ;COMPUTE D36COM'S CORE REQUIREMENTS ADD P1,T1 ;ADD TO TOTAL PUSHJ P,SCTCCR## ;COMPUTE SCLINK'S CORE REQUIREMENTS ADD P1,T1 ;ADD TO TOTAL PUSHJ P,NSPCCR## ;COMPUTE LLINK'S CORE REQUIREMENTS ADD P1,T1 ;ADD TO TOTAL PUSHJ P,RTRCCR## ;COMPUTE ROUTER'S CORE REQUIREMENTS ADD P1,T1 ;ADD TO TOTAL PUSHJ P,DNDCCR## ;COMPUTE DNADLL'S CORE REQUIREMENTS ADD P1,T1 ;ADD TO TOTAL MOVE T1,P1 ;GET TOTAL CORE REQUIREMENTS MOVEM T1,DCNTCR ;SAVE FOR STATISTICS RET ;AND RETURN >; END IFN FTOPS10 ;D36CCR computes D36COM's core requirements. ;Call: ; PUSHJ P,D36CCR ;Returns: ; T1/ Size of D36COM core IFN FTOPS10,< D36CCR: SAVEAC ;SAVE P1 SETZ P1, ;START WITH ZERO LOAD T1,IBBSZ,+IBBLK ;GET REQUESTED SIZE OF BUFFERS ADDI T1,%RTEHS+3 ;ADD IN MAXIMUM ROUTER OVERHEAD LSH T1,-2 ;CONVERT TO WORDS ADDI T1,OVHWDS ;ALLOWANCE FOR OVERHEAD WORD(S) STOR T1,CHSIZ,+UBLCB ;SAVE IN CH BLOCK LOAD T1,IBMXB,+IBBLK ;GET NUMBER OF BUFFERS TO BUILD STOR T1,CHNUM,+UBLCB ;SAVE IN CH BLOCK MOVE T2,T1 ;GET NUMBER OF UBLS LSH T2,-2 ;INCREASE THE NUMBER OF MBLS ADD T1,T2 ;BY ONE FOURTH OF THE NUMBER OF UBLS STOR T1,CHNUM,+MBLCB ;AND SAVE IT MOVEI T3,CHBLKN ;GET NUMBER OF CH BLOCKS XMOVEI T4,CHBLKS ;AND ADDRESS OF CH BLOCKS D36CC1: LOAD T1,CHNUM,(T4) ;GET NUMBER OF THIS TYPE OF FREE BLK LOAD T2,CHSIZ,(T4) ;SIZE OF THIS TYPE OF FREE BLK IMUL T1,T2 ;MULTIPLY TO GET WORDS REQ'D ADD P1,T1 ;ADD INTO TOTAL ADDI T4,CH.LEN ;STEP TO NEXT CH BLOCK SOJG T3,D36CC1 ;LOOP OVER ALL CH BLOCKS MOVE T1,P1 ;GET MEMORY REQUIREMENTS RET ;AND RETURN >; END IFN FTOPS10 SUBTTL Initialization routines ;The DECnet initialization routine XNENT D36INI IFN FTOPS20,< SKIPN [DCN] ;Is DECnet turned on? RET ; -no, just return > IFN FTOPS10,< IFN FTXMON,< XMOVEI T1,D36LOW ;Get address of D36COM low segment database XMOVEI T2,NTMLOW## ;Get address of NTMAN low segment database CAXGE T1,SKYORG ;Ensure no problem with load order CAXL T2,SKYORG ;... JRST COMWLO ;Error, give stopcode XMOVEI T1,SCTLOW## ;Get address of SCLINK low segment database XMOVEI T2,NSPLOW## ;Get address of LLINKS low segment database CAXGE T1,SKYORG ;Ensure no problem with load order CAXL T2,SKYORG ;... JRST COMWLO ;Error, give stopcode XMOVEI T1,RTRLOW## ;Get address of ROUTER low segment database XMOVEI T2,DNDLOW## ;Get address of DNADLL low segment database CAXGE T1,SKYORG ;Ensure no problem with load order CAXL T2,SKYORG ;... JRST COMWLO ;Error, give stopcode XMOVEI T1,SCULOW## ;Get address of SCMUUO low segment database CAXL T1,SKYORG ;Ensure no problem with load order BUG.(HLT,COMWLO,D36COM,SOFT,,,,RTN) >; END IFN FTXMON >; END IFN FTOPS10 SAVEAC ;SAVE SOME ACS MOVX T1,1 ;Set D36IFG MOVEM T1,D36IFG ; to +1 to indicate DECnet is initializing IFN FTOPS10,< MOVE T1,STANAM## ;LOCAL HOST NAME (IN COMNET) STOR T1,IBNAM,+IBBLK ;STORE SIXBIT NODE NAME MOVE T1,RTRADR ;LOCAL HOST ADDRESS (IN ROUTER) MOVE T2,RTRHOM ;LOCAL HOST AREA (IN ROUTER) STOR T2,RN%ARE,T1 ;COMBINE IN T1 STOR T1,IBADR,+IBBLK ;FILL IN INITIALIZATION BLOCK MOVE T1,DCNCOR ;GET ADDRESS WHERE DECNET CORE ALLOCATION MOVEM T1,DCNVFF ;SET UP AS ADDRESS OF DECNET FIRST FREE > LOAD T1,IBADR,+IBBLK ;Make sure local node index LDB T1,[POINTR(T1,RN%NOD)] ; and OPSTR ,IBMXA,+IBBLK ; MAXIMUM ADDRESS are consistent BUG.(CHK,COMBNN,D36COM,SOFT,,,< Cause: The node number set with the NODE command in the CONFIG file is higher than the DECNET MAXIMUM-ADDRESS value set in the same file. DECnet cannot initialize. Action: Make the startup file consistent. >,RTN) LOAD T1,IBDBL,+IBBLK ; Get default buffers per link LSH T1,1 ; Allow that many for transmit and receive STOR T1,PDDQT,+DNDEFS ; and save it for SCJSYS IFN FTOPS20,< LOAD T1,IBBSZ,+IBBLK ; Get requested block size ADDI T1,%RTEHS+3 ; Add maximum Router overhead IDIVI T1,4 ; Convert to words IFE FTLSTCOR, ; Allowance for overhead word IFN FTLSTCOR, ; Overhead words for trace of lost blks STOR T1,CHSIZ,+UBLCB ; Save as size to build UBLs LOAD T1,IBMXB,+IBBLK ; Get maximum number of UBL's to build STOR T1,CHNUM,+UBLCB ; Save it for initializer MOVE T2,T1 ; Get number of UBLs LSH T2,-2 ; Increase the number of MBLs ADD T1,T2 ; by one fourth of the number of UBLs STOR T1,CHNUM,+MBLCB ; and save it >; END IFN FTOPS20 CALL DNINIM ;GO INITIALIZE OUR MEMORY MANAGER CALL SCTINI ;CALL SC WHO WILL CALL NSP AND SO ON BUG.(CHK,COMCID,D36COM,SOFT,,,< Cause: SCTINI has found some reason to object about the DECnet environment. See SCTINI for the reasons it will take a non-skip return. >,RTN) XCALL (MSEC1,NRTINI) ;INITIALIZE DECnet NRT AS WELL TRN ;EAT UP ANY POSSIBLE SKIP RETURN CALL RTRON ;TURN ON ROUTER (WHICH TURNS ON DECNET) TRN ;EAT ANY POSSIBLE SKIP RETURN IFN FTOPS20,XCALL (MSEC1,SCJINI) ;(20)INITIALIZE SCJSYS IFN FTOPS10,< MOVE T1,DCNTCR ;GET TOTAL CORE REQUIREMENTS ADD T1,DCNCOR ;ADD BASE ADDRESS OF DECNET CORE CAME T1,DCNVFF ;SHOULD MATCH CURRENT FINAL FIRST FREE ADDRESS BUG.(CHK,COMCAW,D36COM,SOFT,,,,RTN) >; END IFN FTOPS10 SETOM D36IFG ;Flag that DECnet is now initialized RET ;RETURN SUBTTL DCNJIF - DECnet Once-a-jiffy check INTERNAL DCNJIF XRENT DCNJIF CALL RTRJIF ;Call ROUTER IFN FTOPS10,< SKPCPU (0) ;On policy CPU? RET ;No, return now >; END IFN FTOPS10 CALL DNDJIF ;Call DNADLL CALLRET NSPJIF ;And LLINKS SUBTTL DCNSEC - DECnet Once-a-second check INTERNAL DCNSEC XRENT DCNSEC IFN FTOPS20,< MOVEI T1,^D1000 ;Get milliseconds in dcnsec interval MOVEM T1,DCNTIM ;Initialize count-down in stg > ;END IFN FTOPS20 IFN FTOPS10,< SOSG DCNTIM ;Time for XDCNJB checks? CALL XDCNJB ;Yes, do periodic checks >; END IFN FTOPS10 CALL RTRSEC ;Call ROUTER's second routine CALLRET SCTSEC ;Call SCLINK's second routine and return SUBTTL DCNJB0 - DECnet periodic checks INTERNAL DCNJB0 XNENT DCNJB0 IFN FTOPS10,< MOVEI T1,^D10 ;Reset DCNJB0 interval MOVEM T1,DCNTIM ;... >; END IFN FTOPS10 CALLRET NSPJB0 ;Call NSP periodic check and return SUBTTL NMX -- Privilege checking routine. INTERNAL NMXPRV XSWAPCD NMXPRV: LLMPRV:: ;USED BY LLMOP IFN FTOPS10,< MOVSI T1,JP.POK ;PRIVILEGE BIT. MCALL (RG,MCSEC1,PRVBIT##) ;ASK MONITOR IF ALLOWED. RETSKP ;HE IS RET ;RETURN TO USER > IFN FTOPS20,< MOVE T1,CAPENB ;ENABLED CAPABILITES TXNN T1, ;WHEEL OR OPERATOR? RNMXER (CAPX1) ;NO, RETURN LACK OF PRIVS RETSKP > SUBTTL NMX -- Time stamp a queued even block ;NMXTIM - Time stamp a queued event block. ;Call ; TOPS-20: ; T1/ Todclk of event. ;Return ; RET always, ; T1/ Number of julian half days, ; T2/ Number of seconds into current half day, ; T3/ Number of milliseconds into current second. INTERNAL NMXTIM XSWAPCD NMXTIM: IFN FTOPS10,< MOVE T1,DATE## ;GET CURRENT UDT (IN DAYS,,FRACTION) MOVE T2,TIME## ;GET CURRENT TIME (IN JIFFIES SINCE MIDNIGHT) LSH T1,-^D17 ;TRUNCATE TO NUMBER OF HALF DAYS. SUBI T1,124210_1 ;CONVERT DAYS SINCE 1858 TO DAYS SINCE 1977 TRNE T1,1 ;IS THIS THE SECOND HALF OF A DAY? SUB T2,[JIFSEC*^D60*^D60*^D12] ;YES, RECORD SECONDS SINCE HALF-DAY. IDIVI T2,JIFSEC ;CONVERT JIFFIES INTO SECONDS. IMULI T3,^D1000 ;CONVERT TO NUMBER OF MILLISECONDS*JIFSEC IDIVI T3,JIFSEC ;CONVERT TO NUMBER OF MILLISECONDS. SKIPL T2 ;MAKE SURE WE HAVE A POSITIVE NUMBER OF SECONDS TDNE T1,[XWD -1,600000] ;MAKE SURE NO DATE OVERFLOW BUG.(HLT,COM911,D36COM,SOFT,,,< Cause: The 2 byte julian half-day field in an event message is limited to 9 november 2021. The routine above has calculated the julian half-day, and has found that it overflowed. I doubt very much that the date itself has really gone past 2021. Probably someone smashed an AC or the routine to get the time from the monitor is returning junk. >) RET >;END IFN FTOPS10 IFN FTOPS20,< ; Enter here with Todclk in T1 SAVEAC STKVAR ;rounding flag SETZM ROUND ;intialize ;duplicate of LGTAD, except no rounding, and save the leftover MUL T1,[1B17] ;shift binary point DIV T1,JFDAY ;time since startup in T1, remainder in T2 HLRZ Q1,T2 ;convert remainder to ms, and save HRRZ Q2,T2 ;save the pittance that is left ADD T1,TADIDT ;data & time in T1 internal format ; (except leftover ms) ;find out if ODCNV% will round up. HRRZ T3,T1 ;get time MULI T3,FULDAY ; will ODCNV% DIV T3,[1B17] ; round up CAIL T4,400000 ; one second ? SETOM ROUND ;it will. remember this ;compute leftover milliseconds. HRRZ T3,T1 ;get time again MUL T3,JFDAY ;convert back to ms ADD T4,Q2 ; add that pittance to least sig. word DIV T3,[1B17] ; end of computation. MOVE Q2,T3 ;save it IDIVI T3,^D1000 ; modulo IMULI T3,^D1000 ; one SUB Q2,T3 ; thousand ADD Q1,Q2 ;total leftover milliseconds ;get date & time MOVE T2,T1 ;convert internal time to years, Julian MOVX T4, ; days & seconds ODCNV% ;(T2,T4/T2,T4) ;... ;... ;convert date to Julian half days HLRZ T1,T2 ;get year CAIL T1,FYEAR ;range CAIL T1,FYEAR+YRTABL ; check BUG.(CHK,NMXTBG,JNTMAN,SOFT,,,< Cause: The table used by NMXTIM is obsolete. Action: Create a new table. >,RTN) MOVE T1,YEARTB-FYEAR(T1) ;get number of days before this year HRRZS T2 ;isolate days SOS T2 ;don't count today.. it's not over yet. ADD T1,T2 ;total days LSH T1,1 ; half days ;diddle milliseconds & seconds HRRZ T2,T4 ;seconds since midnight MOVE T3,Q1 ;milliseconds in T3 CAIGE T3,^D1000 ;too many milliseconds ? IFSKP. SUBI T3,^D1000 ;yes. make them small. AOS T2 ;increment seconds ENDIF. SKIPN ROUND ;did ODCNV% round up ? IFSKP. SOSL T2 ;yes. take that second away. cross half day ? IFSKP. SOS T1 ;yes. take away a half day, MOVEI T2,HLFDAY-1 ; and make a lot of seconds ENDIF. ENDIF. NMXTM1: CAIGE T2,HLFDAY ;too many seconds ? IFSKP. SUBI T2,HLFDAY ;yes. make them small. AOS T1 ;increment half days JRST NMXTM1 ;and try again. ENDIF. RET ENDSV. ;end STKVAR FULDAY=^D<24*3600> ;the number of seconds in a day HLFDAY=^D<12*3600> ;the number of seconds in a half day ;this table gives the number of julian days since (& including) JAN 1 1977 ; for the years FYEAR (=1982) to FYEAR+YRTABL-1 FYEAR=^D1982 ;the first year in this table YEARTB: ^D1826 ^D2191 ^D2556 ^D2922 ^D3287 ^D3652 ^D4017 ^D4383 ^D4748 ^D5113 ^D5478 ^D5844 ^D6209 ^D6574 ^D6939 ^D7305 ^D7670 ^D8035 ^D8400 YRTABL=.-YEARTB XRESCD > SUBTTL TESTSB -- Assert that Code is Running in section 1 ;Called only by TESTS1 macro, in TOPS10, defined in D36PAR IFN FTOPS10,< IFN FTDEBUG,< IFN FTXMON,< TESTSB::BUG.(HLT,COMSC0,D36COM,SOFT,
,,< Cause: We are supposed to be running in section one or greater and yet the TESTS1 macro has found that we are running in section zero. In order to make extended addressing work, the code must be running in section one or greater. Action: This BUG. is called with a PUSHJ P, so look on the top of the stack for the address of the TESTS1 macro that detected the fault. Find the code that fell into section zero and fix it. >) POP P,CX ;GET RETURN ADDRESS HRLI CX,1 ;FORCE IT TO SECTION 1 XJRST CX ;RETURN TO CALLER IN SECTION 1 >;END IFN FTXMON >;END IFN FTDEBUG >;END IFN FTOPS10 SUBTTL TOPS20 -- User mode checking routines. IFN FTOPS20,< ;CHKBPT - Check out a byte pointer the user has passed us. ;Byte size must be null or 8 bit bytes. ;Returns +1 on failure with error in T1 ;Returns +2 on success preserving T1 & T2 ;Uses T3 INTERNAL CHKBPT XRESCD CHKBPT: JUMPE T1,RSKP ;IF NULL, THAT IS O.K. LDB T3,[POINT 6,T1,11] ;GET THE USER'S BYTE SIZE CAIN T3,^D8 ;8 BIT BYTES? RETSKP ;YES, ALL O.K. MOVX T1,NEADC% ;NO, RETURN AN ERROR RET > ;END IFN FTOPS20 SUBTTL Restored code. ifn ftki10,< D36HLT::STOPCD .,STOP,D36,D36TYP ;++ DECNET. NON RECOVERABLE. D36CHK::STOPCD D36REC,DEBUG,DCN,D36TYP ;++ DECNET. DETAILS BELOW D36INF::S0PSHJ D36IN0 ;DO A BUGINF ;FALL THROUGH TO RECOVERY (SIC) CODE. ;DIE WILL RETURN HERE AFTER DOING THE STOPCODE D36REC: PUSH P,CX ;SAVE ADDRESS OF XCT HRRZ CX,-1(CX) ;GET RH OF XCT (STEINBACH'S GUIDELINE) SKIPN CX,1(CX) ;IS THERE A RETURN ADDRESS? RET ;NOPE. RETURN .+1 pop p,(p) ;ADJSP P,-1 JRST (CX) ;AND GO TO RECOVERY ADDRESS ;COME HERE FOR A BUGINF MESSAGE D36IN0: CALL SAVT## ;SAVE ALL THE T ACS CALL SAVUM## ;SAVE A FEW MORE HRRZ U,OPRLDB## ;TYPE THIS MESSAGE OUT TO OPR0: PUSHJ P,INLMES## ;TYPE PREPARATORY INFORMATION FIRST ASCIZ \%% DECnet buginf: \ ;FALL THROUGH TO D36TYP D36TYP: MOVE T1,-1(CX) ;GET THE XCT. TLC T1,(XCT) ;CLEAR THE XCT BITS XMOVEI T1,2(T1) ;POINT TO THE DATA WE ARE INTERESTED IN IFN FTLONG,PJRST CONMES## ;PRINT THIS STUFF OUT ON THE CTY. IFN FTMEDIUM,< MOVE T1,(T1) ;GET SIXBIT WORD POINTED AT PJRST PRNAME## ;AND TYPE IT OUT IN SIXBIT > ;END IFN FTMEDIUM >;ki10 SUBTTL End of D36COM IFN FTOPS20, TNXEND IFN FTOPS20,< ;Hack for section testing INTERNAL $TSTS6 RESCD ;Come here with JSP CX,$TSTS6 $TSTS6: PUSH P,CX ;Save return address XHLLI CX,. HLRZS CX CAIN CX,XCDSEC JRST $TSTS7 PUSH P,T1 MOVE T1,(P) BUG. (CHK,NISEC6,D36COM,SOFT,,<>,< Cause: Code that should be running in section 6 is not. Data: CALADR - Address of routine not in section 6 >) POP P,T1 $TSTS7: POP P,CX JRST (CX) > ;END IFN FTOPS20 IFN FTOPS10,< RESDT D36LOW::! XRESCD >; END IFN FTOPS10 END