Google
 

Trailing-Edge - PDP-10 Archives - dec-10-omona-u-mc9 - tm2kon.mac
There are 13 other files named tm2kon.mac in the archive. Click here to see a list.
TITLE TM2KON - RH10/TM02 (TU16) DRIVER FOR TAPSER  V020
SUBTTL	T WACHS/TW	30 NOV 76
	SEARCH F,S
	$RELOC
	$HIGH
;***COPYRIGHT 1975,1976,1977 DIGITAL EQUIPMENT CORP, MAYNARD MASS.****
XP VTM2KN,020
	SALL

ENTRY	TM2KON
TM2KON::



;DISPATCH TABLE FOR TAPSER CALLS
TM2DSP::JRST	TM2INI
	JRST	TM2RES
	JRST	TM2SIO
	JRST	TM2INT
	POPJ	P,
	POPJ	P,			;IDLENESS **********
	JRST	CPOPJ1##		;TEST IF CTL IS ON-LINE
	JRST	TM2SCH			;CAUSE A SCHEDULE CYCLE



DEFINE STALL,<
XLIST
	IMULI	P,1
IFN FTKL10,<
	IMULI	P,1
>
LIST
>

	;OFFSETS INTO TKBCCL
	TKBFLG==TKBCCL##+2		;FLAGS FROM FNCTBL
	TKBCHR==TKBCCL##+3		;CHARACTER (FRAME) COUNT
	TKBSCH==TKBCCL##+4		;-1 IF A SCHEDULE CYCLE
	SUBTTL PARAMETERS

	;DRIVE REGISTERS USED IN DATAO'S

	DO.CS1==0B5		;DRIVE CONTROL REGISTER
	DO.DS==1B5		;STATUS REGISTER
	DO.ER==2B5		;ERROR REGISTER
	DO.MR==3B5		;MAINTENANCE REG
	DO.AS==4B5		;ATTN SUMMARY
	DO.FC==5B5		;FRAME COUNTER
	DO.DT==6B5		;DRIVE TYPE
	DO.CK==7B5		;CHK CHARACTER REG
	DO.SN==10B5		;SERIAL NUMBER
	DO.TC==11B5		;TAPE CONTROL REGISTER


	;DRIVE FUNCTIONS LOADED INTO DRIVE CONTROL REG

	DF.NOP==1		;NO-OP
	DF.UNL==3		;UNLOAD (REWIND OFF-LINE)
	DF.INT==5		;ILLEGAL FUNCTION TO CAUSE AN INTERRUPT
	DF.REW==7		;REWIND
	DF.CLR==11		;DRV CLR
	DF.RIPS==21		;READ-IN, PRESET
	DF.ERA==25		;ERASE
	DF.WTM==27		;WRITE TAPE MARK
	DF.SPF==31		;SPACE FWD
	DF.SPR==33		;SPACE REVERSE
	DF.WCF==51		;WRITE CHK FWD (READ FWD)
	DF.WCR==57		;WRITE CHK REV (READ REV)
	DF.WTF==61		;WRITE FORWARD
	DF.RDF==71		;READ FORWARD
	DF.RDR==77		;READ REVERSE


	DXES==200000		;DISABLE XFER ON ERROR STOP BIT

	;TAPE CONTROL REGISTER
	TC.PAR==1B32			;ON IF WRITE EVEN PARITY
	;DRIVE STATUS REGISTER

	DS.ATA==1B20		;ATTENTION
	DS.ERR==1B21		;COMPOSITE ERROR
	DS.PIP==1B22		;POSITIONING IN PROGRESS
	DS.MOL==1B23		;MEDIUM ON LINE
	DS.WRL==1B24		;WRITE LOCKED
	DS.EOT==1B25		;END OF TAPE
	DS.DPR==1B27		;DRIVE PRESENT
	DS.DRY==1B28		;DRIVE READY (NOT GO)
	DS.SSC==1B29		;SLAVE STATUS CHANGE
	DS.PES==1B30		;PHASE ENCODED STATUS
	DS.SDN==1B31		;SHUTDOWN BIT
	DS.IDB==1B32		;IDENT BURST (FOR PE)
	DS.TM==1B33		;TAPE MARK
	DS.BOT==1B34		;BEGINNING OF TAPE
	DS.SLA==1B35		;SLAVE ATTENTION
	DS.OK==DS.EOT!DS.PES!DS.TM!DS.BOT!DS.SSC!DS.SDN!DS.IDB	;BITS WHICH DON'T MATTER
	DS.GUD==DS.MOL!DS.DPR!DS.DRY	;THESE BITS MUST BE ON


	;DRIVE ERROR REGISTER

	ER.COR==1B20		;CORRECTABLE DATA/ CRC ERROR
	ER.UNS==1B21		;UNSAFE
	ER.OPI==1B22		;OPERATION INCOMPLETE
	ER.DTE==1B23		;DRIVE TIMING ERROR
	ER.NEF==1B24		;NON-EXISTANT FUNCTION
	ER.CS==1B25		;CORRECTABLE SKEW/ ILLEGAL TAPE MARK
	ER.FCE==1B26		;FRAME COUNT ERROR
	ER.NSG==1B27		;NON-STANDARD GAP (CRAP IN THE GAP)
	ER.LRC==1B28		;LRC ERROR/ FORMAT (PREAMBLE POSTAMBLE) ERROR
	ER.INC==1B29		;INCORRECTABLE DATA/ VERTICAL PARITY ERROR
	ER.DPA==1B30		;DATA BUS PARITY ERROR
	ER.FMT==1B31		;FORMAT ERROR
	ER.CPA==1B32		;CBUS PARITY ERROR
	ER.RMR==1B33		;REG MODIFICATION REFUSED
	ER.ILR==1B34		;ILLEGAL REGISTER ADR
	ER.ILF==1B35		;ILLEGAL FUNCTION
	;RH10 BITS, FUNCTIONS
	DO1CRC==40B5		;RH10 CONTROL REG
	DO1CDB==50		;RH10 DATA BUFFER
	DO1CRA==54B5		;RH10 RAE REGISTER

	;CONI/CONO BITS
	;LH BITS
	CI1ILF==400		;ILLEGAL FUNCTION
	CI1SDR==200		;SELECTED DRIVE REGISTER ACCESS ERROR
	CI1CDP==4		;CHAN DATA PARITY ERROR
	CI1CWP==2		;CHAN COMMAND WORD PARITY ERROR
	CI1NXM==1		;CHAN-DETECTED NXM

	;RH BITS
	CI1DBP==400000		;DATA BUS PARITY ERROR
	CI1EXC==200000		;EXCEPTION
	CI1CER==100000		;CHAN ERROR (CWPE,CDPE, NXM)
	CI1WRT==40000		;COMMAND WORD WRITTEN
	CI1OVR==20000		;OVERRUN
	CI1DRE==10000		;DRIVE RESPONSE ERROR
	CI1ILC==4000		;ILLEGAL COMMAND
	CI1PSF==2000		;POWER SUPPLY FAILURE
	CI1CBO==200		;CONTROL BUS OVERRUN
	CI1RAE==100		;REGISTER ACCESS ERROR
	CI1ATN==40		;ATTENTION
	CI1BSY==20		;BUSY
	CI1DON==10		;DONE

	CO1ATN==40		;ENABLE FOR ATTENTIONS INTRPTS
	CO1STP==20		;CLEAR BUSY, SET DONE

	CI1ERR==536220
	CO1CLR==734210		;CLEAR ALL ERRORS


	;DATAI/DATAO BITS
	DIERRS==3600		;DIB ERRORS
	CBTO==2000		;CONTROL BUS TIMEOUT
	LR==4000		;(LH)LOAD REGISTER
;RH20
;REGISTERS
DO.CT2==710000			;SECONDARY TRANSFER CONTROL
DO.PBA==72B5			;PRIMARY BLOCK ADDRESS
DO.CT1==73B5			;PRIMARY TRANSFER CONTROL
DO.IVI==74B5			;INTERRUPT VECTOR INDEX

;CONI/CONO
CI.RAE==4000			;REGISTER ACCESS ERROR
CO.RAE==4000			;CLEAR RAE
CI.ERR==515000
CO.CLR==5010
CO.MBE==400		;MASSBUS ENABLE
CI.ATN==200		;ATTENTION (COMES UP EVEN IF NOT ENABLED)

;DATAO
DO.DRE==400			;DISABLE REGISTER ACCESS ERROR STOP

;DATAO STCR (LH)
D2.RCP==2000			;RESET CHANNEL PC
D2.SCS==200			;STORE CHANNEL STATUS

;DATAI
DI.TRA==200			;TRANSFER (SHOULD BE ON)
DI.CPE==1000			;CONTROL BUS PARITY ERROR

;CHANNEL LOGOUT AREA
CS1MPE==1B1			;MEM PARITY ERROR
CS1NSE==1B2			;NEGATION OF SBUS ERR
CS1NXM==1B4			;NXM
CS1RHE==1B10			;RH20 ERROR
CS1LWC==1B11			;LONG WORD COUNT
CS1SWC==1B12			;SHORT WORD COUNT
CS1OVR==1B13			;OVERRUN
CS1ERR==32020,,0		;ALL CHAN LOGOUT ERRS
;HERE TO START IO
TM2SIO:	PUSHJ	P,CHKIRB##	;GET IORB FOR THIS OP
	  JRST	TAPDIS##	;NONE, GO AWAY
IFE FTKL10,<
	PUSHJ	P,SAVE1##	;SAVE P1
>
IFN FTKL10,<
	PUSHJ	P,SAVST2	;SAVE ACS, SET P2=0 IF RH10, =1 IF RH20
>
	LDB	T4,PRBFCN##	;FUNCTION
	SKIPN	P1,FNCTBL(T4)	;LEGAL?
	JRST	ILLFNC		;NO
	SKIPGE	T2,TRBRCT(T1)	;IF POSITIVE IN ERROR RECOVERY
	MOVEM	T2,TT2UVA##(W)	;REAL IOWD - SAVE IT
	LDB	T2,[POINT 3,TUBAKA##(U),17] ;YES, GET DRIVE NUMBER
	LDB	T4,PRBDEN##	;GET DENSITY
	CAILE	T4,MAXDEN	;LEGAL?
	MOVEI	T4,MAXDEN	;TOO HIGH - MAKE IT THE HIGHEST
	DPB	T4,PRBDEN##	;SAVE 
	SKIPGE	T4,DENTBL(T4)	;LEGAL DENSITY?
	JRST	ILLFNC		;NO
	TRO	T2,(T4)		;YES, PUT DENSITY INTO COMMAND
	MOVSI	T4,RB.PAR	;EVEN PARITY?
	TDNE	T4,TRBLNK(T1)
	TRO	T2,TC.PAR	;YES, TELL THE HARDWARE
	LDB	T4,PRBMOD##	;GET MODE
	SKIPGE	T4,MODTBL(T4)	;LEGAL?
	JRST	ILLFNC		;NO
	TRO	T2,(T4)		;YES, TELL THE HARDWARE
	MOVEI	T3,CO.MBE	;DONT ALLOW INTERRUPTS (BIT IGNORED IF RH10)
	XCT	TT2CO3##(W)	;(REWINDING DRIVE)
	HRLI	T2,(DO.TC)	;SET TO TALK TO TAPE CNTRL REG
	PUSHJ	P,WTREG		;TELL MODE, DENSITY, SLAVE #, PARITY
	HRLI	T3,-1		;1ST TIME THROUGH
TM2SI2:	MOVSI	T2,(DO.DS)	;READ THE STATUS REGISTER OF THE SLAVE
	PUSHJ	P,RDREGX
	TRNE	T2,DS.BOT	;BOT?
	JUMPL	P1,[MOVE P1,FNCNOP ;YES, DONT DO IT
		    MOVSI T3,RB.SNM!RB.SBT ;IF THE DRIVE IS AT BOT
		    IORM T3,TRBSTS(T1) ;INDICATE NO MOTION, BOT
		    JRST .+1]	;AND CONTINUE
	TLNN	P1,(TB.WRT)	;ARE WE READING?
	TRZ	T2,DS.WRL	;YES, WRITE-LOCKED TAPE IS OK
	SKIPL	T3
	TRZ	T2,DS.ATA	;IF DID A DRIVE CLEAR IGNORE ATTN
	TRZ	T2,DS.OK	;CLEAR THE BITS WHICH DON'T MATTER
	CAIE	T2,DS.GUD	;IS THE DRIVE OK?
	JRST	NOSTRT		;NO, INVESTIGATE FURTHER
				;YES, CONTINUE
	TLNN	P1,(TB.DAT)	;DATA OPERATION?
	JRST	TM2SI3		;NO
	HLRE	T2,TT2UVA##(W)	;YES, GET WORD COUNT
	HLRZS	T4		;NO OF FRAMES PER WORD
	IMULI	T2,(T4)		;COMPUTE FRAME COUNT
	MOVNM	T2,TKBCHR(W)	;SAVE IN KDB
	TLNE	P1,(TB.NFC!TB.OFC) ;0 OR -1 TO F.C.?
TM2SI3:	SETZ	T2,		;YES
	TLNE	P1,(TB.NFC!TB.DAT) ;IF T2 IS ALREADY SET,
	JRST	NOFC		;GO
	TLNE	P1,(TB.OFC)	;IF -1 TO F.C.
	SOJA	T2,NOFC		;GO
	MOVN	T2,TRBXCW(T1)	;GET -NO OF RECS TO SPACE
NOFC:	ANDI	T2,177777	;ONLY 16 BIT'S WORTH
	HRLI	T2,(DO.FC)	;TALK TO FRAME COUNT REG
	PUSHJ	P,WTREGX	;TELL IT HOW MUCH TO DO
TM2SI4:	HRRZ	T2,TKBICP##(W)	;ICWA
	HRRZ	T3,TRBXCW(T1)	;CHAN LIST
IFN FTKL10,<
	SKIPE	P2		;IF AN RH20,
	TLO	T3,RH2JMP##	; MAKE A JUMP-WORD
>
	MOVEM	T3,(T2)		;POINT ICWA AT IO LIST
IFN FTKL10,<
	SKIPE	P2		;IF AN RH20,
	TDZA	T2,T2		; ICWA ISNT IN COMMAND
>
	LSH	T2,6		;POSITION ICWA FOR DATAO
	TRO	T2,(P1)		;INSERT FUNCTION
	TLNE	P1,(TB.DAT)	;TALK TO CS1 IF SPACE OP,
IFE FTKL10,<
	TDO	T2,[DO1CRC!DXES]  ;TALK TO RH10 IF DATA OP
>
IFN FTKL10,<
	TDO	T2,[DO1CRC!DXES;TALK TO RH10 CNTRL REG
		DO.CT2!D2.RCP!D2.SCS,,377700](P2) ;OR RH20 CNTRL REG
>
	MOVEM	T2,TT2REG##+3(U)	;SAVE LAST COMMAND IN UDB
	MOVEM	P1,TKBFLG(W)	;REMEMBER WHAT WE ARE DOING
	PUSHJ	P,WTREG		;GO START UP THE WORLD
	MOVEI	T3,TAPCHN##+CO.MBE ;PIA
	TLNN	P1,(TB.DAT)	;DATA OPERATION?
	TRO	T3,CO1ATN	;NO, ENABLE FOR ATTENTIONS
				;CONTINUE
IFN FTKL10,<
	JUMPE	P2,TM2SI6	;NO SWEAT IF RH10
	MOVEI	T2,CI.ATN	;IF A DATA OPERATION
	TLNE	P1,(TB.DAT)	; WE DONT ENABLE FOR ATTENTIONS
	ANDCAM	T2,TKBCSO##(W)	; BUT THE ATTEN BIT LIGHTS IN CONI ANYWAY
	XCT	TT2CI2##(W)	;DID WE WIN IN THE SETUP?
	TRNE	T2,CI.RAE
	TRO	T3,20		;NO, CAUSE AN IMMEDIATE INTERRUPT
	MOVE	T2,TT2IVO##	;SET UP INTERRUPT VECTOR ADDRESS
	XCT	TT2DO2##(W)
>
TM2SI6:	XCT	TT2CO3##(W)	;TURN ON RH10 PI
	POPJ	P,		;GO AWAY AND WAIT FOR INTERRUPT


;HERE IF THE DRIVE STATUS REGISTER ISN'T RIGHT
NOSTRT:	CAIE	T2,DS.GUD!DS.WRL ;ONLY WRITE-LOCK?
	JRST	BADSTS		;NO, IT REALLY IS BAD
	SKIPA	T2,[RB.SLK!RB.SER,,]	;WRITE-LOCKED
ILLFNC:	MOVSI	T2,RB.SER!RB.SIL	;ILLEGAL FUNCTION
ILLORM:	IORM	T2,TRBSTS(T1)	;TELL TAPUUO WHAT THE PROBLEM IS
	MOVE	P1,FNCNOP	;DO AN OP TO GET TO PI LEVEL
	LDB	T2,[POINT 3,TUBAKA##(U),17]
	HRLI	T2,(DO.TC)	;TELL THE TM02 WHAT DRIVE
	PUSHJ	P,WTREG
	JRST	TM2SI4		;GO CAUSE AN INTERRUPT

BADSTS:	JUMPL	T3,BADST2	;IF NOT FIRST TIME,
	MOVSI	T2,TKSOFL	;SET DRIVE OFF-LINE
	IORM	T2,TUBSTS##(U)
	MOVSI	T2,RB.SOL!RB.SER ;SAY THE DRIVE IS DOWN
	JRST	ILLORM
BADST2:	MOVSI	T2,(DO.TC)	;FIRST TIME-CLEAR DRIVE
	PUSHJ	P,RDREGX
	PUSH	P,T2		;SAVE TAPE CNTRL REG
	PUSHJ	P,CLRDRV	;DRVPOL CHANGES TC REG
	POP	P,T2
	HRLI	T2,(DO.TC)
	PUSHJ	P,WTREGX	;RESTORE TC REG
	JRST	TM2SI2		;AND TRY AGAIN
;INTERRUPT CODE
TM2INT:	MOVE	U,TKBCUN##(W)	;UNIT WE'RE TALKING TO (MAYBE)
	MOVE	U,(U)
	PUSHJ	P,SAVE3##	;SAVE SOME ACS
IFN FTKL10,<
	PUSHJ	P,SETP2		;SET P2=0 IF RH10, =1 IF RH20
	XCT	TT2CI2##(W)	;CONI
	TRNE	T2,CI.RAE	;REGISTER ACCESS ERROR?
	JRST	TM2IN3		;YES, GO CLEAR IT AND RETRY
>
	MOVSI	T2,(DO.DS)	;READ STATUS REGISTER NOW, TALKING
	PUSHJ	P,RDREG		; TO TC REG LATER MAY CHANGE IT
	PUSH	P,T2		;SAVE STATUS REG
	SETZ	T3,		;TALK TO THE TM02, UNIT 0 WILL DO
	MOVSI	T2,(DO.AS)	;READ THE ATTN SUMMARY REGISTER
	PUSHJ	P,RDREGX
	ANDI	T2,377		;JUST THE ATTENTION BITS
	JUMPE	T2,TM2IN2	;GO IF NO ATTN IS UP
	HRLI	T2,(DO.AS)	;CLEAR THE BITS WE JUST READ
	PUSHJ	P,WTREGX
	HRRZ	T1,T2
TM2IN1:	LSHC	T1,-1		;NEXT UNIT
	JUMPGE	T2,NXTM02	;GO IF ATTN NOT UP FOR IT
	MOVE	T4,T3		;SAVE UNIT NUMBER
	LSH	T4,3		;POSITION TO RIGHT PLACE
	PUSHJ	P,DRVPL1	;POLL THE DRIVES FOR REW DONE
NXTM02:	JUMPE	T1,TM2IN2	;GO IF ALL DONE
	AOJA	T3,TM2IN1	;THERE IS ANOTHER - TEST NEXT UNIT

;HERE AFTER ALL ATTN'S HANDLED, IF THERE WERE ANY
TM2IN2:	LDB	T2,[POINT 3,TUBAKA##(U),17] ;SLAVE NUMBER
	HRLI	T2,(DO.TC)	;SET TO RECONNECT TO DRIVE, DRVPOL MIGHT HAVE
	PUSHJ	P,WTREG		; SET TO TALK TO ANOTHER SLAVE
	POP	P,T4		;STATUS REGISTER
TM2IN3:	SKIPL	T1,TKBSCH(W)	;SCHEDULE CYCLE?
	SKIPN	T1,TKBFLG(W)	;OR OPERATION IN PROGRESS?
	JRST	[SETZM TKBSCH(W)
		 PJRST	CLRCTL]  ;RETURN 0 OR -1 TO TAPSER
	SETZM	TKBFLG(W)	;NOW NO OP IS GOING
	MOVE	P1,T1		;FLAGS IN P1
	LDB	P3,[POINT 4,P1,17] ;INDEX FOR FUNCTION IN P3
	PUSHJ	P,CHKIRB##	;GET THE IORB
	  JRST	TAPDIS##	;NOTHING THERE - GO AWAY
	XCT	TT2DI2##(W)	;DATAI
	HLL	T3,T2		;SAVE (DBTO,CBTO)
	XCT	TT2CI2##(W)	;CONI
	TLNN	T3,CBTO		;IF NOT CNTRL BUS TIMEOUT
	TRZ	T2,CI1DRE	; IGNORE DRIVE RESPONSE ERR
IFE FTKL10,<
	TRNE	T2,CI1ERR	;ERROR?
>
IFN FTKL10,<
	JUMPE	P2,TM2IN4	;EASY WIN IF RH10
	MOVE	T3,TKBICP(W)	;RH20, GET LOGOUT AREA
	HLL	T2,1(T3)	;GET ERROR BITS FROM ICWA+1
	TLNN	P1,(TB.DAT)	;IF NOT A DATA OPERATION
	TLZA	T2,-1		; IGNORE ERROR BITS, THEY'RE USELESS
	TLC	T2,(CS1NSE)	;MAKE BIT=1 IF AN ERROR
TM2IN4:	TDNE	T2,[CI1ERR	;ERROR?
		CS1ERR!CI.ERR](P2)
>
	JRST	CHNERR		;TOO BAD!
	CAIN	P3,RB.FYB	;YELLOW BALL/ILLEGAL FNCTN?
	JRST	INTNOP		;YES, GO HANDLE IT
	TRNN	T4,DS.ERR	;ERROR?
	JRST	TSTERR		;NO
	MOVSI	T2,(DO.ER)	;YES, READ ERROR REG
	PUSHJ	P,RDREG	;(ONLY CALL RDREG ON "REAL" ERROR)
	HRL	T4,T2		;T4=ERROR,,STATUS
	JRST	TSTBOT
TSTERR:	SKIPE	TUBERR##(U)	;IN ERROR RETRY?
	PUSHJ	P,RDREGS	;YES, GET FINAL (GOOD) REGISTERS
TSTBOT:	MOVSI	T2,TUSBOT##	;CLEAR BOT
	ANDCAM	T2,TUBSTS##(U)
	TRNE	T4,DS.BOT	;AND SET IT IF WE REALLY ARE
	IORM	T2,TUBSTS##(U)	; AT BOT
	MOVSI	T2,TUSWTL##	;CLEAR WRITE-LOCK
	ANDCAM	T2,TUBSTS##(U)
	TRNE	T4,DS.WRL	;AND SET IT AGAN IF WE REALLY ARE
	IORM	T2,TUBSTS##(U)	; WRITE LOCKED
	TRNN	T4,DS.BOT	;AT BOT?
	JRST	TSTMOV		;NO
	TLO	T1,RB.SBT	;YES, TELL TAPUUO
	PUSHJ	P,UNIBOT##	;CLEAR TUBREC,FIL; SET TUBSTS
	JUMPGE	P1,TSTMOV	;IF WE MOVED BACKWARDS INTO BOT,
	TLZE	T4,ER.OPI!ER.NEF ; THESE REALLY AREN'T ERRORS
	JRST	NOMOVE		;IF ON WE DIDN'T MOVE TAPE
TSTMOV:	TLNN	T4,ER.ILF!ER.RMR!ER.NEF!ER.UNS
	JRST	MOVED		;TAPE REALLY MOVED
	TLOA	T1,RB.SNM!RB.SED ;TAPE DIDN'T MOVE
NOMOVE:	TLO	T1,RB.SNM
	JRST	TM2GO		;CONTINUE
MOVED:	TLNE	P1,(TB.REV)	;REVERSE?
	SOSA	TUBREC##(U)	;DECR OR INCR RECORD COUNT
	AOS	TUBREC##(U)
	TRNN	T4,DS.TM	;PASS OVER (OR JUST WROTE) EOF?
	JRST	NOTM		;NO
	TLNE	P1,(TB.REV)	;YES, INCR OR DECR FILE COUNT
	SOSA	TUBFIL##(U)
	AOS	TUBFIL##(U)
	SETZM	TUBREC##(U)	;AT 0TH RECORD ********* -1 IF REV?
	TLNN	P1,(TB.WRT)	;IF NOT WRITING AN EOF,
	TLO	T1,RB.STM	; TELL TAPUUO WHAT WE SAW
NOTM:	TLNE	P1,(TB.WRT)	;IF WRITING,
	TRNN	T4,DS.EOT	;AND WE SAW EOT
	CAIA
	TLO	T1,RB.SET	;TELL TAPUUO
TM2GO:	JRST	@INTABL(P3)	;GO TO SPECIFIC INTRPT HANDLER


INTABL:	TAPIFI##
	INTRD			;(1)READ FORWARD
	INTWRT			;(2)WRITE
	INTRD			;(3)READ BACKWARDS
	INTSPC			;(4)SKIP RECORD
	INTSPC			;(5)BACKSPACE RECORD
	TAPIFI##		;(6)SKIP FILE
	TAPIFI##		;(7)BACKSPACE FILE
	INTERA			;(10)ERASE GAP
	TAPIFI##		;(11)DATA SECURITY ERASE
	INTREW			;(12)REWIND
	INTUNL			;(13)UNLOAD
	INTWTM			;(14)WRITE TAPE MARK
	INTNOP			;(15)YELLOW BALL/ILLEGAL FUNCTIONS
	INTRD			;(16)CORRECTION READ
	INTRD			;(17)LOW-THRESHOLD READ
;HERE ON READ INTERRUPT
INTRD:	MOVSI	T2,(DO.FC)	;READ THE FRAME COUNTER
	PUSHJ	P,RDREG
	MOVEM	T2,TRBRCT(T1)	;SAVE CHAR-COUNT OF RECORD
	MOVEM	T2,TUBCCR##(U)
	ADDM	T2,TUBCRD##(U)	;UPDATE TOTAL STATS
	CAMLE	T2,TKBCHR(W)	;TOO LARGE A RECORD?
	TLO	T1,RB.STL!RB.SER ;YES, TELL TAPUUO
	LDB	T3,PRBMOD##	;MODE
	IDIV	T2,TMODTB##(T3);COMPUTE NUMBER OF WORDS XFERRED
	HRLM	T2,TUBCHR##(U)	;SAVE WORDS
	DPB	T3,PMTNCR##	;SAVE RESIDUE
	CAIE	P3,RB.FRB	;IF READ BACKWARDS
	JRST	DONE
	SKIPE	T3		;IF NOT EVEN NO OF WORDS
	ADDI	T2,1		;BUMP WRDCNT
	JUMPE	T2,DONE
	HRRZ	P1,TT2UVA##(W)	;GET USER VIRTUAL ADDRESS
IFN FTKA10,<
	TLO	P1,R
>
IFN FTKI10!FTKL10,<
	MOVE	F,TUBCUR##(U)	;MAKE JOB ADDRESSABLE
	PUSHJ	P,SVEUF##
>
	PUSH	P,T1
	LDB	T3,PRBMOD##	;SINCE THE TM02 READS BACKWARDS
	MOVE	T2,TKBCHR(W)	; IN REVERSE ORDER, HALVES SWAPPED
	IDIV	T2,TMODTB##(T3)  ; WE HAVE TO REARRANGE THE DATA
	AOS	P3,P1		;FIRST WORD
	ADDI	P3,-1(T2)	;LAST WORD
	LSH	T2,-1
INTRD1:	EXCTUX	<MOVE T3,@P1>	;GET 2 WORDS
	EXCTUX	<MOVE T1,@P3>
	EXCTXU	<MOVSM T3,@P3>	;SWAP HALVES AND INVERT ORDER
	EXCTXU	<MOVSM T1,@P1>
	ADDI	P1,1
	SUBI	P3,1
	SOJG	T2,INTRD1	;DO FOR WHOLE BLOCK
	POP	P,T1
	CAMN	P1,P3		;IF AN ODD NUMBER OF WORDS,
	EXCTUU	<MOVSS @P1>	; SWAP HALVES OF MIDDLE WORD OF BLOCK
;HERE AFTER AN OPERATION IS THROUGH
DONE:	TLNE	T4,-1		;ERROR BIT UP?
	PUSHJ	P,TM2ERR	;YES, GO HANDLE IT
TRBSTO:	HLLZ	T2,T1		;BITS WE WANT TO TELL TAPUUO ABOUT
	IORM	T2,TRBSTS(T1)	;STORE IN THE IORB
TRBEXC:	MOVSI	T2,RB.EXC
	TLZE	T1,-1		;ANY FUNNY THINGS?
	IORM	T2,TRBLNK(T1)	;YES, AN EXCEPTION HAS OCCURRED
CLRCTL:
IFE FTKL10,<
	MOVEI	T3,CO1CLR	;CLEAR ALL ERRORS
>
IFN FTKL10,<
	MOVE	T3,[CO1CLR
		CO.CLR+CO.MBE](P2)
>
	XCT	TT2CO3##(W)
CLRCTX:
IFN FTKL10,<
	MOVEI	T2,CI.ATN	;IF AN RH20 WE MIGHT HAVE CLEARED ATTEN
	SKIPE	P2		; FROM THE CONSO MASK,
	IORM	T2,TKBCSO##(W)	; SO RESET IT
>
	MOVEI	T3,TAPCHN##+CO1ATN+CO.MBE ;ENABLE FOR INTERRUPTS
	XCT	TT2CO3##(W)
	SETZM	TKBFLG(W)	;NOTHING HAPPENING NOW
	POPJ	P,		;AND RETURN
;HERE ON WRITE INTERPT
INTWRT:	MOVE	T2,TKBCHR(W)	;NO OF FRAMES WE WROTE
	ADDM	T2,TUBCWR##(U)	;UPDATE STATS
	JRST	DONE		;AND FINISH UP
INTSPC:	JRST	DONE

INTWTM:	JRST	DONE

INTERA:	SOS	TUBREC##(U)	;IT ISN'T ANOTHER RECORD
	JRST	DONE

INTUNL:	MOVSI	T2,TKSOFL##	;CLEAR OFF-LINE SO TAPSER
	ANDCAM	T2,TUBSTS##(U)	; WON'T GRUMBLE AT USER
	TLO	T1,RB.SOL	;SAY DRIVE IS OFF-LINE
INTREW:	MOVSI	T2,TUSREW##	;SAY WE'RE REWINDING
	IORM	T2,TUBSTS##(U)
	TRNN	T4,DS.PIP	;ARE WE?
	PUSHJ	P,REWDON##	;NO, MUST HAVE FINISH
	SETZM	TUBREC##(U)	;CLEAR STATS
	SETZM	TUBFIL##(U)
	JRST	DONE		;AND FINISH UP

INTNOP:	PUSHJ	P,CLRDRV	;CLEAR THE DRIVE
	HLL	T1,TRBSTS(T1)	;GET ERROR BITS
	JRST	TRBEXC		;SET EXCEPTION IF AN ERROR
;HERE ON CONI ERROR BIT
CHNERR:
IFE FTKL10,<
	TLNN	T2,CI1SDR	;SELECTED DRIVE RAE?
>
IFN FTKL10,<
	TDNN	T2,[CI1SDR,,
		CI.RAE](P2)
>
	JRST	NORAE		;NO
IFN FTKL10,<
	JUMPE	P2,CHNER1
	TLO	T1,RB.SNM!RB.SED ;YES, NO TAPE MOTION+ERROR
	JRST	TRBSTO
CHNER1:>
	MOVEI	T2,1		;YES, POSITION A BIT
	LDB	T3,[POINT 3,TUBAKA##(U),14]
	LSH	T2,(T3)
	HRLI	T2,(DO1CRA)	;CLEAR REG ACCESS ERROR
	PUSHJ	P,WTREG
	JRST	CHNRTY		;AND RETRY THE OPERATION
NORAE:IFE FTKL10,<
	TLNN	T2,CI1CDP!CI1CWP!CI1NXM ;MEMORY ERR?
>
IFN FTKL10,<
	TDNN	T2,[CI1CDP!CI1CWP!CI1NXM,,
		CS1MPE!CS1NXM](P2)
>
	JRST	CHNRTY		;NO, JUST RETRY
	PUSHJ	P,SAVE1##	;YES
	MOVEI	T3,CHNNXM##	;SET TO CALL RIGHT ROUTINE
IFE FTKL10,<
	TLNN	T2,CI1NXM	;NXM?
>
IFN FTKL10,<
	TDNN	T2,[CI1NXM,,
		CS1NXM](P2)
>
	MOVEI	T3,CHNMPE##
	PUSH	P,T1		;SAE T1
	HRRZ	T1,TKBICP##(W)	;T1=ICWA
	HRRZ	P1,TKBCDB##(W)	;P1=CDB
	PUSHJ	P,(T3)		;GO CALL ERRCON
	POP	P,T1
CHNRTY:	TLO	T1,RB.SED	;INDICATE AN ERROR
	PJRST	TRBSTO		;FINISH UP
;HERE ON ERROR BIT IN TM02
TM2ERR:	TLNN	T4,ER.UNS!ER.FMT!ER.ILR!ER.ILF!ER.OPI!ER.NEF
	JRST	TM2ER1		;NOT AN IMMEDIATE PROBLEM
	TLNE	T4,ER.UNS	;REALLY BAD PROBLEM
	TLO	T1,RB.SOL	;OFFLINE IF UNSAFE IS UP
	TLO	T1,RB.SED!RB.SER ;NON-RECOVERABLE ERROR
	PJRST	CLRDRV		;DRIVE-CLEAR AND RETURN
TM2ER1:	TLNE	P1,(TB.WRT)	;IF READING,
	JRST	TM2ER2
	TLZ	T4,ER.NSG!ER.FCE		 ;THESE AREN'T ERRORS

	TRNE	T4,DS.PES	;IF IN PE MODE
	TLZ	T4,ER.COR!ER.CS!ER.LRC ;THESE AREN'T ERRORS
TM2ER2:	TLNN	T4,ER.COR!ER.CS!ER.FCE!ER.NSG!ER.LRC!ER.DPA!ER.INC!ER.DTE!ER.CPA
	PJRST	CLRDRV		;NOT A "REAL" ERROR, CLEAR DRIVE AND RETURN
	TLNN	T4,ER.COR!ER.CS!ER.INC!ER.LRC ;REAL ERROR
	TLOA	T1,RB.SED	;PLAIN ERROR
	TLO	T1,RB.SDE!RB.SED  ;DATA ERROR
	PUSHJ	P,RDREGS	;READ DRIVE REGS INTO UDB
				;FALL INTO CLRDRV AND RETURN
;DUE TO THE PROBLEM OF DRIVE CLEAR MAKING DS.SSC GO AWAY
; IF SOME OTHER SLAVE BROUGHT IT UP, WE HAVE TO POLL THE DRIVES
; AFTER A DRIVE CLEAR TO FIND ANY THAT MAY HAVE FINISHED REWINDING
CLRDRV:	MOVEI	T2,DF.CLR	;CLEAR THE DRIVE
	PUSHJ	P,WTREG

DRVPOL:	PUSH	P,T4		;SAVE T4
	PUSHJ	P,.+2
	PJRST	T4POPJ##	;RESTORE T4 AND RETURN
	HLRZ	T4,TUBAKA##(U)	;TM02 # + SLAVE NUMBER
	ANDI	T4,70		;TM02 NUMBER
DRVPL1:	MOVE	T2,T4
	ADD	T4,TKBIUN##(W)	;POSITION TO RIGHT PART OF KDB
	LSH	T2,^D21		;SHIFT TM02 #
	ADD	T2,T4		;FORM LH OF AOBJN WORD
	JUMPGE	T2,CPOPJ##	;WE DON'T KNOW ABOUT THIS TM02 IF NOT NEG.
	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	PUSH	P,U		;SAVE U
	HRLI	T4,P1		;SET INDEX FOR RIGHT SLAVE NUMBER
	MOVSI	T2,(DO.DS)	;READ STATUS REG
	PUSHJ	P,RDREGX
	TRNN	T2,DS.SSC	;SLAVE STATUS CHANGE?
	JRST	DRVPL2		;NO
	MOVSI	P1,-10		;YES, HAVE TO FIND A DRIVE
	MOVSI	T3,TUSREW##	; WE CAN CLEAR - ANY SLAVE WHICH ISNT
FNDCLR:	SKIPE	T2,@T4		; REWINDING WILL DO (EVEN NON-EXISTENT ONES)
	TDNN	T3,TUBSTS##(T2)
	JRST	FNDCL2		;THIS ONE IS OK
FNDCL1:	AOBJN	P1,FNDCLR	;REWINDING - TRY NEXT DRIVE
	MOVEI	P1,7		;NONE THERE, TRY DRIVE 7
FNDCL2:	SKIPE	T2,TKBFLG(W)	;IF WE'RE ACTIVELY TALKING TO A DRIVE
	HRRZ	T2,TKBCUN##(W)	;DONT CLEAR THAT DRIVE
	CAIN	T2,@T4
	JUMPL	P1,FNDCL1	;SO TRY ANOTHER
	MOVE	T2,P1		;WE CAN DO A DRIVE CLEAR ON THIS ONE
	HRLI	T2,(DO.TC)	;TALK TO THIS DRIVE
	PUSHJ	P,WTREGX
	MOVEI	T2,DF.CLR	;DO A DRIVE CLEAR
	PUSHJ	P,WTREGX
DRVPL2:	MOVSI	P1,-10		;SET TO LOOK AT ALL DRIVES
DRVPL3:	SKIPN	U,@T4		;POINT U AT UDB
	JRST	UPOPJ##		;NONE, WE'RE DONE
	MOVSI	T2,(DO.TC)	;SET TO TALK TO THIS DRIVE
	HRR	T2,P1
	PUSHJ	P,WTREGX	;CONNECT TO IT
	MOVSI	T2,(DO.DS)
	PUSHJ	P,RDREGX	;READ STAUS REGISTER
	MOVSI	P3,TKSOFL##
IFN FTMDA,<
	TDNE	P3,TUBSTS##(U)	;IF DRIVE WAS OFF-LINE
	TRNN	T2,DS.MOL	; AND IS NOW ON-LINE
	CAIA
	PUSHJ	P,NOWON		;LET THE WORLD KNOW
>
	TRNE	T2,DS.MOL	;OFF LINE?
	ANDCAB	P3,TUBSTS##(U)	;NO
	TRNN	T2,DS.MOL
	IORB	P3,TUBSTS##(U)	;YES
	TLNE	P3,TUSREW##	;WAS IT LAST REWINDING?
	TRNE	T2,DS.PIP	;YES, IS IT NOW
	JRST	DRVPL4		;YES, CONTINUE WITH NEXT DRIVE
	PUSHJ	P,REWDON##	;THROUGH REWINDING, TELL TAPUUO
DRVPL4:	AOBJN	P1,DRVPL3	;GO TEST NEXT DRIVE
	JRST	UPOPJ##		;DONE, RETURN
IFN FTMDA,<
;SUBROUTINE TO TELL TAPUUO WHEN A SLAVE COMES ON-LINE
;PRESERVES ALL ACS
NOWON:	PUSHJ	P,SAVT##	;SAVE T1-T4
	PJRST	TPMONL##	;AND TELL TAPUUO
>
;HERE TO INITIALIZE THE TM02
TM2INI:	MOVEI	T1,TUCIRD##	;TELL TAPUUO WE GET AN INTERRUPT
	MOVE	T2,TKBCUN##(W)	; WHEN A REWIND FINISHES
TM2INL:	SKIPE	T3,(T2)		;NEXT DRIVE
	IORM	T1,TUBSTS##(T3);SET BIT IN IT
	AOBJN	T2,TM2INL
IFN FTKL10,<
	PUSHJ	P,SAVST2	;SAVE ACS, SET UP P2
>
	PUSH	P,F		;SAVE F FOR SYSINI
	MOVE	T1,DEVNAM(F)	;GET NAME AS SET UP BY COMDEV
	MOVE	T4,TKBIUN##(W)	;SET TO LOOP OVER ALL UNITS
TM2INN:	SKIPN	U,(T4)		;GET A UNIT
	JRST	TM2INX		;NOT THERE
	HRRZ	T2,TUBADR##(U)	;HET UDB
	DPB	T2,PUNIT##	;STORE RIGHT UNIT
	LSHC	T2,-3		;SET RIGHT NAME IN DDB
	LSH	T2,^D15
	LSHC	T2,3		;HAVE TO FIDDLE CAUSE MORE THAN 1 TM02 DOES
	ADD	T2,T1		; VERY FUNNY THINGS TO THE NAMES
	MOVEM	T2,DEVNAM(F)	;EG MTA21
	LDB	T2,[POINT 3,TUBAKA##(U),17]
	HRLI	T2,(DO.TC)	;SELECT RIGHT SLAVE
	PUSHJ	P,WTREG
	MOVSI	T2,(DO.SN)	;READ SERIAL NUMBER
	PUSHJ	P,RDREG		;AND STORE IN UDB
	MOVEM	T2,TT2REG##+14(U)  ;FOR DIAGNOSTICS
	MOVSI	T2,(DO.DS)	;READ STATUS REG
	PUSHJ	P,RDREG
	MOVSI	T3,TKSOFL##
	TRNN	T2,DS.MOL	;IF NOT MEDIUM-ON-LINE
	IORM	T3,TUBSTS##(U)	; THE DRIVE IS OFF-LINE
	HLRZ	F,DEVSER(F)
TM2INX:	AOBJN	T4,TM2INN
	POP	P,F
IFE FTKL10,<
	MOVEI	T1,CI1DON+CI1ATN ;WHAT WE WANT TO INTERRUPT ON
>
IFN FTKL10,<
	MOVE	T1,[CI1DON+CI1ATN
		CI.RAE+CI.ATN+CI1DON](P2)
>
	HRRM	T1,TKBCSO##(W)	;SET IN CONSO
IFN FTKL10,<
	JUMPE	P2,CLRCTL	;EASY IF RH10
	MOVEI	T3,CO.MBE!CO.RAE ;RH20, CLEAR POSSIBLE REG ACCESS ERROR
	XCT	TT2CO3##(W)	; (ON IF NON-EX DRIVE)
	MOVE	T2,TT2IVO##	;SET UP INTERRUPT VECTOR ADDR
	XCT	TT2DO2##(W)
>
	JRST	CLRCTL		;CLEAR RH10 AND RETURN
;HERE TO CAUSE A SCHEDULE CYCLE
TM2SCH:
IFN FTKL10,<
	PUSHJ	P,SAVST2	;SAVE ACS, SET UP P2
>
	SETOM	TKBSCH(W)	;SET FLAG
	JRST	TM2RS1		;CAUSE AN INTERRUPT

;HERE TO RESET AN ACTIVE DRIVE
TM2RES:
IFN FTKL10,<
	PUSHJ	P,SAVST2	;SAVE ACS, SET UP P2
>
	PUSHJ	P,CLRDRV
TM2RS1:	MOVEI	T3,CO1STP	;CLEAR BUSY, SET DONE
	XCT	TT2CO3##(W)	;DO IT
	JRST	CLRCTX		;CLEA RH10 AND RETURN
;READ A REGISTER - ENTER, EXIT WITH FNCN IN T2
;RESPECTS T1,T4
RDREG:	LDB	T3,[POINT 3,TUBAKA##(U),14] ;TM02 NUMBER
RDREGX:	TLO	T2,(T3)
IFN FTKL10,<
	SKIPE	P2		;IF AN RH20,
	TLO	T2,DO.DRE	; DISABLE REGISTER ACCESS ERR INTERRUPT
>
	XCT	TT2DO2##(W)	;SAY WHAT WE WANT TO READ
	STALL
	XCT	TT2DI2##(W)	;READ IT
	ANDI	T2,177777	;ONLY 16 BITS
	POPJ	P,		;AND RETURN

;ROUTINE TO WRITE A REGISTER
;ENTER T2=WHAT TO DO THE DATAO WITH
;RESPECTS T1, T4
WTREG:	LDB	T3,[POINT 3,TUBAKA##(U),14] ;TM02 NUMBER
WTREGX:	TLO	T2,LR(T3)	;LIGHT LR
IFN FTKL10,<
	SKIPE	P2		;IF AN RH20,
	TLO	T2,DO.DRE	;NO INTERRUPT ON RAE
>
	XCT	TT2DO2##(W)	;DATAO
	POPJ	P,		;AND RETURN

IFN FTKL10,<
;PRESERVES T1
SAVST2:	POP	P,T4		;SAVE RETURN ADDRESS
	PUSHJ	P,SAVE2##	;SAVE P1,P2
	PUSH	P,T4		;RESTORE RETURN ADDR

;SUBROUTINE TO SET UP P2 =0 FOR RH10, =1 FOR RH20
;PRESERVES T1,T4
SETP2:	LDB	P2,[POINT 3,TT2DO2##(W),5] ;GET CONTROLLER CODE
	CAIE	P2,5		;RH20?
	TDZA	P2,P2		;NO, P2=0
	MOVEI	P2,1		;YES, P2=1
	JUMPE	P2,CPOPJ##	;GO IF AN RH10
	MOVEI	T3,CO.MBE	;RH20, ENSURE THAT MASSBUS IS ENABLED
	XCT	TT2CO3##(W)
	POPJ	P,		;AND REURN
>
;ROUTINE TO READ REGISTERS ON ERROR
RDREGS:	XCT	TT2CI2##(W)
	MOVEM	T2,TT2REG##(U)	;SAVE CONI
IFE FTKL10,<
	MOVSI	T2,(DO1CRC)
>
IFN FTKL10,<
	MOVE	T2,[DO1CRC
	DO.CT1](P2)
>
	PUSHJ	P,RDREG
	MOVEM	T2,TT2REG##+1(U)	;DATAI RH10 CNTRL REG
IFE FTKL10,<
	MOVSI	T2,(DO1CDB)
>
IFN FTKL10,<
	MOVE	T2,[DO1CDB
		DO.PBA](P2)
>
	PUSHJ	P,RDREGX
	MOVEM	T2,TT2REG##+2(U)	;DATAI RH10 DATA BUFFER
	PUSH	P,T1
	MOVEI	T1,TT2REG##+4(U)	;(REG+3 = LAST COMMAND)
	HRLI	T1,-12		;READ 12 REGISTERS
	SETZ	T2,		; STARTING AT 0
RDREG1:	PUSHJ	P,RDREGX
	MOVEM	T2,(T1)		;STORE DATA IN UDB
	HLRZ	T2,T1		;SET FOR NEXT REGISTER
	ADDI	T2,13
	LSH	T2,^D18+14
	AOBJN	T1,RDREG1
	JRST	TPOPJ##
;TABLES TO CONTROL IO 
TB.REV==1B0
TB.WRT==1B1
TB.DAT==1B2
TB.SPC==1B3
TB.RD==1B4
TB.ERA==1B5
TB.WTM==1B6
TB.NFC==1B7
TB.OFC==1B8				;SET -1 IN FRAME COUNTER
TB.REW==1B9

FNCTBL:	0					;0 - ILLEGAL
	TB.DAT!TB.RD!TB.NFC!DF.RDF!1B17		;1 - READ FORWARD
	TB.WRT!TB.DAT!DF.WTF!2B17		;2 - WRITE
	TB.DAT!TB.RD!TB.NFC!TB.REV!DF.RDR!3B17	;3 - READ REVERSE
	TB.SPC!DF.SPF!4B17			;4 - SKIP RECORD
	TB.SPC!TB.REV!DF.SPR!5B17		;5 - BACKSPACE RECORD
	0					;6 - SKIP FILE (ILLEGAL)
	0					;7 - BACKSPACE FILE (ILLEGAL)
	TB.WRT!TB.ERA!TB.OFC!DF.ERA!10B17	;10 - ERASE
	0					;11 - DATA SECURITY ERASE (ILLEGAL)
	TB.NFC!TB.REW!TB.REV!DF.REW!12B17	;12 - REWIND
	TB.NFC!DF.UNL!13B17			;13 - REW, UNLOAD
	TB.WRT!TB.WTM!TB.OFC!DF.WTM!14B17	;14 - WRITE TAPE MARK
FNCNOP:	TB.SPC!DF.INT!15B17			;15 - YELLOW BALL
	TB.DAT!TB.RD!TB.NFC!DF.RDF!16B17	;16 - CORRECTION READ
	TB.DAT!TB.RD!TB.NFC!DF.RDF!17B17	;17 - LOW THRESHOLD READ

;FRAMES/WORD,,MODE
MODTBL:	-1					;0 - ILLEGAL
	5,,0B31					;1 - CORE DUMP
	4,,3B31					;2 -  BYTE (4 B-BIT BYTES/WRD)
	-1					;3 -SIXBIT...ILLEGAL
	5,,2B31					;4 - 7 BIT (ASCII)
	6,,1B31					;5 - 7 TRACK CORE DUMP

DENTBL:	-1
	0B27					;200
	1B27					;556
	2B27					;800
	4B27					;1600
MAXDEN==.-DENTBL-1
TM2END:	END