Trailing-Edge
-
PDP-10 Archives
-
BB-V552A-SB_1983
-
d60ser.mac
There are 4 other files named d60ser.mac in the archive. Click here to see a list.
TITLE D60SER -- UUO AND INTERRUPT SERVICE FOR THE DL11 AND DTE-20 DN60 SERIES - V020
SUBTTL ED FORTMILLER/EGF and JOHN SAUTER/JBS 29 JAN 80
SEARCH F,S
$RELOC
$HIGH
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION
; 1976,1977,1978,1979,1980,1982
XP V60SER,020 ;VERSION NUMBER
ENTRY D60SER
D60SER:
;DEFINE THE DN60 FUNCTION CODES
;
F6.RD==:1 ;READ DATA
F6.WD==:2 ;WRITE DATA
F6.RDS==:3 ;READ DEVICE STATUS
F6.WDC==:4 ;WRITE DEVICE STATUS
F6.RLS==:5 ;READ LINE STATUS
F6.WLC==:6 ;WRITE LINE COMMAND
F6.R6S==:7 ;READ DN60 STATUS
F6.W6C==:^D8 ;WRITE DN60 COMMAND
F6.QMX==:^D8 ;LARGEST FUNCTION ALLOWED IN
; .QUE11 FUNCTION
F6.EXM==:^D9 ;EXAMINE PDP11 MEMORY
F6.DEP==:^D10 ;DEPOSIT INTO PDP11 MEMORY
F6.MAX==:^D10 ;LARGEST FUNCTION CODE
;BIT DEFINITIONS IN THE (LH) OF DLXCEU
;DEFINE A BIT THAT GETS SET IN THE (LH) OF DLXCEU TO
; INDICATE THAT THE .C11UQ FUNCTION IS THE ONE BEING DONE
;
D6.Q11==:1 ;.C11QU FUNCTION IN PROGRESS
;DEFINE A BIT WHICH WHEN SET IN THE (LH) OF DLXCEU INDICATES
; THAT THE JOB WAS LOCKED BEFORE ISSUING THE CAL11. UUO. THIS
; BIT WILL NOT BE SET FOR EXM/DEP AS WE DON'T SET NSHF OR NSWP
; IN THIS CASE.
;
D6.ALK==:2 ;SET IF JOB LOCKED PRIOR TO
; DOING .C11QU
;D60DSP ROUTINE CALLED BY NETSER THAT DISPATCHES TO THE PROPER FEK FUNCTION
;CALL T1 := FUNCTION CODE
; J := FEK ADDRESS
;RETURN CPOPJ
D60DSP::CAIL T1,FF.ONC ;RANGE CHECK THE FUNCTION
CAILE T1,FF.CPW ; CODE AND STOP IF BAD
STOPCD CPOPJ,DEBUG,BFC,;++ BAD FUNCTION CODE TO FEK
JRST @.+1(T1) ;DISPATCH TO APPRIOATE ROUTINE
JRST CPOPJ## ;ONCE ONLY CODE
JRST D60SEC ;ONCE/SECOND CODE
JRST CPOPJ## ;SET UP A READ REQUEST
JRST CPOPJ## ;SET UP A WRITE REQUEST
JRST CPOPJ## ;CRASH THE FEK (CPU WENT DOWN?)
JRST D60DWN## ;EXIT PRIMARY PROTOCOL
JRST D60UP## ;START PRIMARY PROTOCOL
JRST CPOPJ## ;WE DON'T CARE ABOUT STATION CONTROL
JRST CPOPJ## ;SYSTEM SLEEP. WHAT SHOULD I DO?
JRST CPOPJ## ;SYSTEM WAKE. WHAT SHOULD I DO?
;COME HERE FOR EACH DN60 ONCE A SECOND
;
D60SEC: SKIPN W,FEKUNI##(J) ;PICK UP POINTER TO BASE TABLE
POPJ P, ;NONE, DO NOTHING.
PUSHJ P,SAVE1## ;P1 USED FOR WINDOW POINTER
SKIPL P1,DLXWIN##(W) ;POINT P1 TO DL10 WINDOW
; THIS WILL SKIP IF A DTE
XCT DLXSTA##(W) ;MARK -10 AS BEING ALIVE
SKIPN T2,DLXTIM##(W) ;SEE IF TIMING (NONE 0)
POPJ P, ;NOT TIMING
SKIPE T1,DLXCEU##(W) ;CAL11. UUO BEING USED?
CAMLE T2,UPTIME## ;SEE IF WE TIMED OUT?
POPJ P, ;NOT TIMED OUT YET
SETZM DLXTIM##(W) ;CLEAR OUT TIME
D60SE3: PUSHJ P,D60WAK ;GET THE JOB OUT OF EW AND EXIT
PJUMPLE P1,D6STMO## ;TAKE CARE OF TIMEOUT WHEN
; THE PDP11 WON'T SPEAK ON A DTE.
POPJ P, ;RETURN
; THE ONCE A SECOND ROUTINE
;HERE TO FINISH THE SETUP WHEN THE PDP11 IS FIRST
; RECOGNIZED AS BEING A PDP11.
;
; CALL: JRST D60SUP ;W POINTS TO THE BASE TABLE
;
D60SUP::SETZM DLXCEU##(W) ;CLEAR CAL11. USERS JOB NUMBER
MOVE T1,[XWD MC11FN,C11FTB]
MOVEM T1,DLXCAL##(W) ;CAL11. POINTER
MOVE T1,@DLXFEK##(W) ;GET FIRST WORD OF FEK
TLO T1,FK.ONL ;SET ON-LINE BIT
HLLM T1,@DLXFEK##(W) ;PUT BACK FLAGS HALF
MOVE T1,DLXFEK##(W) ;GET FEK ADDRESS
HRRZM W,FEKUNI##(T1) ;STORE ADDRESS OF BASE TABLE
POPJ P, ;DONE WITH INITIALIZATION
SUBTTL CAL11. UUO
;COME HERE ON CAL11. UUO FROM COMDEV.
;CALLING SEQUENCE IS:
; MOVE AC,[XWD LENGTH,BLOCK]
; CAL11. AC,
; ERROR RETURN
; OK RETURN
;BLOCK: EXP FUNCTION CODE
; ARGUMENT (1) ...
;
;ENTER FROM COMDEV WITH WINDOW POINTER IN P1 OR XWD -1,DTE #,
; DL10 BASE IN W, LENGTH OF BLOCK IN T3.
;COMDEV DOES THE DISPATCH BASED ON THE FOLLOWING TABLE. THE
; HIGH ORDER BIT, IF SET, INDICATES THAT THE USER MUST HAVE
; THE "POKE" PRIV.
C11FTB: XWD 400000,DEP11 ;(0) DEPOSIT TO -11
XWD 400000,EXAM11 ;(1) EXAMINE THE -11
XWD 400000,QUE11 ;(2) PERFORM A DN60 FUNCTION
XWD 0,NAME11 ;(3) RETURN NAME OF PGM IN 11
XWD 0,DOWN11 ;(4) IS PORT UP OR DOWN?
XWD 400000,CPOPJ## ;(5) SEND
XWD 400000,CPOPJ## ;(6) RECEIVE
XWD 0,TYP11 ;(7) TYPE
MC11FN==.-C11FTB ;LENGTH OF TABLE
; VALUES OF BITS IN DLXSWD:
D60.DP==:1 ;DEPOSIT
D60.EX==:2 ;EXAMINE
D60.ER==:4 ;ADDRESS ERROR
SUBTTL CAL11. UUO ERROR CODES
COMMENT \
CODE MEANING
---- -------
1 Caller does not have POKE privledges
2 The function is undefined on this type of front end
3 Invalid DL10 port number
4 CAL11. facility in use, try again later
5 No answer from the front end after 1-2 seconds
6 Queue entry too short (DC76 only)
7 Not enough arguments
10 Examine/Deposit address was invalid (more than 16
bits or the front end flagged it as invalid), or
the deposit data was more than 16 bits
11 In QUE11, Illegal function code,
Address check, Illegal byte size, Byte offset is
outside the buffer or the buffer is too large
(requires more than 16 DL10 byte pointers)
12 DTESER couldn't get any free core
13 DTE - reload bit set or primary protocol is
not running.
14 DTE - there never will be enough EVM
\
;SUBROUTINE TO EXAMINE OR DEPOSIT PDP11 MEMORY
;
; CALL: MOVE T3,+LENGTH
; MOVEI P1,BEGINNING ADDRESS OF THE WINDOW
; OR -1,,DTE PORT NUMBER
; MOVEI W,ADDRESS OF THE BASE TABLE
;
DEP11: SUBI T3,1 ;MUST HAVE ADDRESS AND DATA
JSP T4,GETADR ;GET THE ADDRESS TO DEPOSIT INTO
PUSHJ P,GETWD1## ;GET THE WORD TO BE DEPOSITED
SKIPL T4,T1 ;MAKE SURE DEPOSIT DATA IS
CAILE T4,177777 ; IN THE RANGE OF 0-177777
PJRST ECOD10## ;**ERROR-10** BECAUSE DEPOSIT
; DATA TO LARGE.
HRLI T4,-1 ;FLAG ITS A DEPOSIT
MOVEI T1,D60.DP ;DEPOSIT FUNCTION
JRST DEPEXM ;NOW GO ATTEMPT TO DO THE DEPOSIT
EXAM11: JSP T4,GETADR ;GET THE ADDRESS TO EXAMINE
SETZ T4, ;ZERO THE DATA WORD AND FLAG EXAMINE
MOVEI T1,D60.EX ;EXAMINE FUNCTION
DEPEXM: POP P,W ;RESTORE BASE TABLE INDEX
SKIPL T3 ;SEE IF ADDRESS IS IN THE
CAILE T3,177777 ; RANGE OF 0-177777
PJRST ECOD10## ;**ERROR-10** BECAUSE OF ILLEGAL ADDRESS
JSP T2,CHKCEU ;SEE IF ANYONE USING CAL11
; **ERROR-4** IF SO
PJUMPL P1,D6SED## ;GO TAKE CARE OF DTE DEPOSIT/EXAMINE
PJRST D6DED## ;GO TAKE CARE OF DL10 DEP/EXM
;SUBROUTINE TO RETURN THE TYPE OF PDP11
;
TYP11: MOVEI T1,3 ;DN60 TYPE FRONT-END (.C1D60)
PJRST STOTC1## ;RETURN DN60 TYPE
;HERE TO GET AN EXAMINE/DEPOSIT ADDRESS
;
; CALL: JSP T4,GETADR ;T3 CONTAINS THE LENGTH
; RETURN ;UNLESS LENGTH TOO SHORT, THEN
; ; GIVE ERROR-7 TO THE USER. ON
; ; NON ERROR RETURN:
; ; AC (W) IS SAVED ON THE PDL
; ; AC (T3) CONTAINS THE ADDRESS
;
GETADR: SOJL T3,ECOD7## ;**ERROR-7** IF NOT ENOUGH ARGS
PUSH P,W ;SAVE AC (W)
PUSHJ P,GETWD1## ;GET THE ADDRESS TO EXAMINE/DEPOSIT
MOVE T3,T1 ;COPY ADDRESS HERE
JRST (T4) ;RETURN TO THE CALLER
;HERE TO PERFORM .C11QU (2) FUNCTION
;
; CALL: MOVE T3,+LENGTH
; MOVE P1,BEGINNING ADDRESS OF THE WINDOW
; OR -1,,DTE PORT NUMBER
; MOVEI W,ADDRESS OF THE BASE TABLE
;
QUE11: SUBI T3,5 ;SEE IF ENOUGH ARGS SUPPLIED
PJUMPL T3,ECOD7## ;**ERROR-7** BECAUSE NOT ENOUGH ARGS
JSP T2,CHKCEU ;SEE IF ANYONE USING THE CAL11. UUO
; **ERROR-4** IF SO
PUSHJ P,GET1WD ;GET LINE NUMBER,,DEVICE NUMBER
MOVE P2,T1 ;SAVE LINE NUMBER,,DEVICE NUMBER
PUSHJ P,GET1WD ;GET NUMBER OF BYTES,,FUNCTION CODE
HRRZ P4,T1 ;REMEMBER THE FUNCTION CODE
CAIL P4,1 ;RANGE CHECK THE FUNCTION
CAILE P4,F6.QMX ; FOR A RANGE OF 1-10.
PJRST ECOD11## ;**ERROR-11** BECAUSE OF ILLEGAL FUNCTION CODE
HLL P4,T1 ;REMEMBER TOTAL NUMBER OF BYTES
MOVSS P4 ;FUNCTION CODE,,NUMBER OF BYTES
PUSHJ P,GET1WD ;GET LENGTH OF BUFFER,,BUFFER ADDRESS
MOVE P3,T1 ;REMEMBER LENGTH,,BUFFER ADDRESS
PUSHJ P,ADRCHK ;ADDRESS CHECK THE BUFFER
PJRST ECOD11## ;**ERROR-11** BECAUSE OF ADDRESS CHECK
HLRZ T4,P3 ;GET THE LENGTH OF THE BUFFER
ANDI P3,-1 ;LEAVE ONLY THE BUFFER ADDRESS
PUSHJ P,GET1WD ;GET NUMBER OF BYTES PER WORD(12 BITS),
; POSITION OF FIRST BYTE (24 BITS)
MOVE F,T1 ;GET THE POSITION IN HERE
TLZ F,777700 ;KEEP ONLY THE POSITION OF THE FIRST BYTE
LSH T1,-^D24 ;KEEP ONLY THE NUMBER OF BYTES PER WORD
MOVEI S,4 ;ASSUME MIN NUMBER OF BYTES PER
; WORD FOR A DTE
SKIPL P1 ;BUT ARE WE TALKING TO A DTE?
MOVEI S,3 ;NO SET MIN NUMBER OF BYTES PER
; WORD FOR A DL10
CAML T1,S ;RANGE CHECK BYTE SIZE
CAILE T1,6 ; FOR A RANGE OF (3-6 FOR A DL10)
; AND (4-6 FOR A DTE)
PJRST ECOD11## ;**ERROR-11** BECAUSE OF ILLEGAL BYTE SIZE
MOVE S,T1 ; AND REMEMBER IT.
;
;TO COMPUTE THE FIRST ADDRESS USING IN THE BUFFER
;
; (BYTE POSITION)/(BYTE SIZE)+(BUFFER ADDRESS)
; AC(U) IS USED TO REMEMBER THE REMAINDER FROM
; (BYTE POSITION)/(BYTE SIZE) FOR LATER USE
;
MOVE T1,F ;GET BYTE POSITION
IDIV T1,S ;(BYTE POSITION)/(BYTE SIZE)
MOVE U,T2 ;REMEMBER THE REMAINDER
ADD T1,P3 ;PRESTO, THE FIRST ADDRESS
;
;TO COMPUTE THE LAST ADDRESS USED IN THE BUFFER
;
; (((BYTE POSITION)+(NUMBER OF BYTES)-1)/(BYTE SIZE))+(BUFFER ADDRESS)
;
MOVE T2,F ;GET POSITION OF THE FIRST BYTE
ADDI T2,-1(P4) ;ADD IN THE NUMBER OF BYTES - 1
IDIV T2,S ;NOW DIVIDE BY THE BYTE SIZE
ADD T2,P3 ;ADD THE BUFFER ADDRESS AND
; PRESTO THE LAST ADDRESS USED.
MOVE T3,P3 ;GET THE BUFFER ADDRESS
ADDI T3,-1(T4) ; AND ADD THE LENGTH-1
CAMLE T2,T3 ;SEE IF COMPUTED BUFFER
; IS WITHIN THE REAL BUFFER
PJRST ECOD11## ;**ERROR-11** BECAUSE OF ADDRESS CHECK
;
;TO COMPUTE THE WORD COUNT
;
; (LAST ADDRESS)-(FIRST ADDRESS)+1
;
SUBI T2,-1(T1) ;COMPUTE LENGTH OF BUFFER WHICH
; WE'LL REFER TO AS "WORD COUNT"
PJUMPL P1,D6SQ11## ;GO PERFORM THE FUNCTION USING A DTE
PJRST D6DQ11## ;GO PERFORM THE FUNCTION USING A DL10
;COME HERE TO RETURN THE NAME OF THE PDP-11 PROGRAM.
; IN THE CASE OF A PDP11 ON A DL10 THE NAME RETURNED
; WILL BE THE NAME THE PDP11 GAVE US BUT ON A DTE
; THE NAME WILL BE RETURNED FROM THE BASE TABLE.
;
; CALL: PUSHJ P,NAME11 ;W POINTS TO THE BASE TABLE
;
NAME11: MOVE T1,DLXNMT##(W) ;PICK UP NAME
PJRST STOTC1## ;SKIP RETURN, GIVING NAME
;COME HERE TO TELL THE STATUS OF THE PDP-11 PROGRAM.
; RETURN A 1 TO THE USER IF THE PDP11 IS UP
; OR 0 IF ITS DOWN.
;
; CALL: PUSHJ P,DOWN11 ;P1 CONTAINS DL10 WINDOW ADDRESS
; ; OR -1,,DTE NUMBER
; ;W POINTS TO THE BASE TABLE
;
DOWN11: SKIPGE P1 ;SKIP IF ON A DL10
JRST DWND6S## ;GO HANDLE A DTE
SKIPG T1,DLXDWN##(P1) ;GET STATUS
D60RT0:: TDZA T1,T1 ;PDP-11 IS DOWN
D60RT1:: MOVEI T1,1 ;UP.
PJRST STOTC1## ;SKIP RETURN.
;THIS ROUTINE IS CALLED TO PUT A JOB INTO
; THE EVENT WAIT STATE.
;
; CALL: PUSHJ P,EVWAIT ;W POINTS TO THE BASE TABLE
; RETURN ;ALWAYS
;
D60EVW::PUSH P,M ;SAVE "M"
D60EV1: MOVEI T1,EV.D60 ;THE EVENT WAIT CODE FOR THE DN60
MOVE J,.CPJOB## ;GET THE JOB NUMBER
PUSHJ P,FSLEEP## ;PUT JOB INTO EVENT WAIT
SKIPE DLXTIM##(W) ;SEE IF A DN60 WAKE
JRST D60EV1 ;NO, IT WAS SOME OTHER CLOWN
; SO GO WAIT SOME MORE.
SETZM DLXCEU##(W) ;FREE UP THE CAL11. UUO
PJRST MPOPJ## ;RESTORE "M" AND RETURN TO
; THE CALLER
;THIS ROUTINE IS CALLED TO GET A DN60 JOB OUT OF
; EVENT WAIT
;
; CALL: PUSHJ P,D60WAK ;T1 CONTANS JOB NUMBER
; ;W POINTS TO THE BASE TABLE
; RETURN ;WITH DLXTIM = 0
;
D60WAK::PUSH P,J ;SAVE J
SETZM DLXTIM##(W) ;FLAG WE GOT THE JOB OUT OF EW
PUSHJ P,D60LKC ;SEE IF WE ARE TO UNLOCK HIM
; ALSO RETURNS JOB NUMBER IN T1
PUSHJ P,D60ULJ ;YES, WE LOCKED HIM SO UNLOCK HIM
POP P,J ;RESTORE J
PJRST EWAKE## ;GO GET HIM OUT OF EW
;THIS ROUTINE IS CALLED TO PUT THE TIME IN
; THE BASE TABLE THAT THE JOB TIMES OUT AT.
;
; CALL: PUSHJ P,SETTIM ;T1 CONTAINS NUMBER OF SECONDS
; ;W POINTS TO THE BASE TABLE
; RETURN ;ALWAYS
;
D60TIM::IMULI T1,JIFSEC## ;CONVERT TO JIFFYS
ADD T1,UPTIME## ;ADDING THIS MAKES THE TIME
; THAT WE TIME-OUT AT.
MOVEM T1,DLXTIM##(W) ;SAVE SO ONCE-A-SECOND CODE
; WILL KNOW THE TIME-OUT TIME
POPJ P, ;RETURN TO CALLER
;SUBROUTINE TO GET 1 WORD FROM THE USERS BLOCK
;
; CALL: PUSHJ P,GET1WD ;
; RETURN ;T1 HAS THE WORD
;
GET1WD: PUSH P,W ;MUST PRESERVE AC(W)
PUSHJ P,GETWD1## ;GET A WORD FROM USER BLOCK
PJRST WPOPJ## ;RESTORE AC(W)
; AND RETURN WITH WORD IN AC(T1)
;SUBROUTINE TO CHECK IF THE CAL11. UUO IS IN USE
;
; CALL: JSP T2,CHKCEU ;
; RETURN ;IF NOT IN USE, IF IN
; ; USE GIVE **ERROR-4**
;
CHKCEU: HRRZ S,DLXCEU##(W) ;GET JOB NUMBER FROM BASE TABLE
CAMN J,S ;IS THIS THE USER WHO IS WAITING?
SETZM DLXCEU##(W) ;YES, MUST HAVE USED ^C
SKIPE DLXCEU##(W) ;SEE IF ANY USER WAITING
PJRST ECOD4## ;**ERROR-4** BECAUSE UUO IS BEING USED
PJRST (T2) ;RETURN TO THE CALLER
;SUBROUTINE TO UNLOCK THE JOB
;
; CALL: PUSHJ P,D60ULJ ;WITH JOB NUMBER IN T1
; CALL: PUSHJ P,D60UNL ;IF JOB NUMBER UNKNOWN (UUO LEVEL)
; RETURN ;T1 PRESERVED, J CONTAINS JOB NUMBER
;
D60ULJ::SKIPA J,T1 ;GET JOB NUMBER FROM T1
D60UNL::MOVE J,.CPJOB## ;GET THE JOB NUMBER
PUSH P,T1 ;SAVE THIS
MOVSI T1,NSHF!NSWP ;THE LOCK BITS
ANDCAM T1,JBTSTS##(J) ;CLEAR THE JOB
PJRST TPOPJ## ;RESTORE T1 AND RETURN
;SUBROUTINE TO DETERMINE IF THE JOB IS TO BE UNLOCKED
; BEFORE RETURNING THE TO USER
;
; CALL: PUSHJ P,D60LKC ;W POINTS TO THE BASE TABLE
; RETURN ;IF NEED TO UNLOCK AND T1 CONTAINS JOB NUMBER
; RETURN ;IF NOT TO UNLOCK JOB AND T1
; ; CONTAINS JOB NUMBER
;
D60LKC::MOVE T1,DLXCEU##(W) ;GET BITS,,JOB NUMBER
TLZN T1,D6.Q11 ;QUE11 FUNCTION?
PJRST CPOPJ1## ;NO, EXM/DEP
TLZN T1,D6.ALK ;YES, WAS HE LOCKED BEFORE CAL11. ?
POPJ P, ;NO, WE MUST UNLOCK HIM
PJRST CPOPJ1## ;YES, DON'T UNLOCK HIM
;SUBROUTINE TO VERIFY THAT THE REQUIRED PAGES ARE
; VALID AND IN CORE. IF VM IF THE PAGE(S) ARE NOT IN
; CORE ATTEMPT TO BRING THEM IN.
;
; CALL: PUSHJ P,ADRCHK ;P3 CONTAINS XWD LENGTH,START ADDRESS
; RETURN ;IF ANY ADDRESS ERRORS
; RETURN ;IF BUFFER IS IN CORE
;
ADRCHK: HRRZ T1,P3 ;LOW ADDRESS OF BUFFER
HLRZ T2,P3 ;THE LENGTH OF THE BUFFER
ADDI T2,-1(P3) ;LAST ADDRESS OF THE BUFFER
PUSH P,T2 ;SAVE THE LAST ADDRESS
IFN FTVM,<
ADRC1: PUSHJ P,FLTST## ;SEE IF PAGE FAULT WILL HAPPEN
PJRST UUOFLT## ;PAGE FAULT - CALL THE PFH
>;END IFN FTVM
PUSHJ P,IADRCK## ;MAKE SURE VALID ADDRESS
PJRST T2POPJ## ;BAD ADDRESS - CLEAN PDL AND NON-SKIP RETURN
IFN FTVM,<
ADDI T1,PAGSIZ## ;GO TO THE NEXT PAGE
CAMGE T1,(P) ; BEYOND THE END OF OUR BUFFER
JRST ADRC1 ;NO, CHECK THIS PAGE
>;END IFN FTVM
POP P,T1 ;GET THE LAST ADDRESS OF THE BUFFER
IFN FTVM,<
PUSHJ P,FLTST## ;SEE IF PAGE FAULT WILL HAPPEN
PJRST UUOFLT## ;PAGE FAULT - CALL THE PFH
>;END IFN FTVM
PJRST IADRCK## ;CHECK THE LAST ADDRESS
$HIGH
$LIT
D60END::END