Google
 

Trailing-Edge - PDP-10 Archives - bb-bt99q-bb - tmxkon.x23
There is 1 other file named tmxkon.x23 in the archive. Click here to see a list.
TITLE	TMXKON - TM10B DEVICE DEPENDENT CODE FOR TAPSER V106
SUBTTL T.HESS/TAH/TW/DPM	16-MAY-89

	SEARCH	F,S,DEVPRM
	$RELOC
	$HIGH

;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
; 1974,1975,1976,1977,1978,1979,1980,1982,1984,1986,1988.
;ALL RIGHTS RESERVED.

.CPYRT<1974,1988>


XP VTMXKN,106		;DEFINE VERSION NUMBER FOR STORAGE MAP
	SALL

TMXKON::ENTRY	TMXKON
	TMXDMX==10			;MAXIMUM DRIVES PER KONTROLLER
	TMXHDN==TMXDMX-1		;HIGHEST DRIVE NUMBER ON KONTROLLER
	TMXELN==2			;SIZE OF FEP TABLE

;DRIVER CHARARCTERISTICS
;	TMX	= TD2CNF
;	MTA	= MAGTAPE
;	0	= MAXIMUM DEVICES IN SYSTEM (NO LIMIT)
;	K.TMB	= KONTROLLER TYPE
;	TMXDMX	= MAXIMUM DRIVES PER KONTROLLER
;	TMXHDN	= HIGHEST DRIVE NUMBER ON KONTROLLER
;	MDSEC0	= SECTION FOR KDB/UDB
;	MDSEC0	= SECTION FOR DDB
DRVCHR	(TMX,MTA,0,K.TMB,TMXDMX,TMXHDN,MDSEC0,MDSEC0,<DR.XAD!DR.MCD!DR.GCC!DR.DDN>)


	.ORG	TKBUDB		;START OF TM10B SPECIFIC DATA
TMXUTB:! BLOCK	TMXDMX		;TABLE OF POINTERS TO UDBS
TMXIOB:!			;START OF I/O INSTRUCTIONS
TMXCOC:! BLOCK	1
TMXCIC:! BLOCK	1
TMXDIC:! BLOCK	1
TMXIOE:!			;END OF I/O INSTRUCTIONS
TTMBLK:! BLOCK	1		;BLKI/BLKO POINTER
TTMCHE:! BLOCK	1		;-1 IF CHANNEL DETECTED ERROR
TMXIUM:! BLOCK	TMXDMW		;IGNORE DRIVE MASK
TMXNUM:! BLOCK	TMXDMW		;NEW DRIVE MASK
TMXKLN:!			;LENGTH OF KDB
	.ORG

	 .ORG	TUBLEN
TMXICC:! BLOCK	1		;LAST ERROR INITIAL CONI MTC
TMXICS:! BLOCK	1		;LAST ERROR INITIAL CONI MTS
TMXFCC:! BLOCK	1		;LAST ERROR FINAL CONI MTC
TMXFCS:! BLOCK	1		;LAST ERROR FINAL CONI MTS
TMXULN:!			;LENGTH OF UDB
	 .ORG


TMXKDB:	KDBBEG	(TMX,TMXKLN)
	SETWRD	(KDBNAM,<SIXBIT/MT/>)	;KONTROLLER NAME
	SETWRD	(KDBIUN,<TKBUDB>)	;INITIAL POINTER TO UDBS
	SETWRD	(KDBCUN,<TKBUDB>)	;CURRENT POINTER TO UDBS
	SETWRD	(KDBIUM,<TMXIUM>)	;OFFSET TO IGNORE UNIT MASK
	SETWRD	(KDBNUM,<TMXNUM>)	;OFFSET TO NEW UNIT MASK
IFN FTMP,<SETWRD (TKBFCT,<TKBICT##>)>	;FAIRNESS COUNTER FOR QUEUED I/O
	SETWRD	(<TMXCOC>,<CONO  000,(T1)>)
	SETWRD	(<TMXCIC>,<CONI  000,T1>)
	SETWRD	(<TMXDIC>,<DATAI 000,T1>)
	KDBEND


TMXUDB:	UDBBEG	(TMX,TMXULN)
	SETWRD	(UDBNAM,<SIXBIT/MT/>)	;DRIVE NAME
	SETWRD	(TUBIEP,<-TMXELN,,TMXICC>) ;INITIAL ERROR POINTER
	SETWRD	(TUBFEP,<-TMXELN,,TMXFCC>) ;FINAL ERROR POINTER
	UDBEND


EQUATE	(LOCAL,0,<TMXULP,TMXULB,TMXCKT>)
EQUATE	(LOCAL,CPOPJ##,<TMXCMD,TMXONL,TMXLOD,TMXEDL>)
EQUATE	(LOCAL,CPOPJ2##,<TMXBSY>)

TMXICD==TAPICD##		;PROTOTYPE INTERRUPT CODE ADDRESS
TMXICL==TAPICL##		;PROTOTYPE INTERRUPT CODE ADDRESS
TMXINT==TAPINT##		;INTERRUPT SERVICE
TMXELG==TPELGX##		;MAKE AN ERROR LOG ENTRY

TMXDSP:	DRVDSP	(TMX,TAPCHN##,TDVDDB##,TDVLEN##,TPMDIA##)
	TPK	(TMX,NO,377777)	;SERVICE DEPENDENT DISPATCH

;DEFAULT MONGEN'ED DEVICE TABLE
DEFMDT:	MDKL10	(7,220,0,0,<MD.KON>)	;DEVICE CODE 220
	MDTERM				;TERMINATE TABLE
;BYTE POINTERS

CTYUNI:	POINT	CM.UNS,T1,CM.UNP	;UNIT # IN CMD REG
CTYFCN:	POINT	CM.CMS,T1,CM.CMP	;FCN CODE IN CMD REG

;OFFSETS INTO TKBCCL

TKBSAV==TKBCCL+2	;PLACE TO SAVE TM10A IOWD
TKBUNI==TKBCCL+3	;CURRENT UNIT SELECTED (-1 IF NONE)


MTAFLG==TAPCHN##*10
;DEFINITIONS FOR COMMAND REGISTER

CM.UNS==3		;SIZE OF UNIT FIELD
CM.UNP==^D20		;RIGHT MOST BIT

CM.PAR==1B21		;1=ODD PARITY, 0=EVEN PARITY
CM.CDF==1B22		;CORE DUMP FORMAT (9TK ONLY)

CM.CMS==4		;COMMAND BYTE SIZE
CM.CMP==^D26		;RIGHT MOST BIT
	CM.FNO==00		;NO-OP
	CM.FUR==10		;UNIT READY
	CM.FRW==01		;REWIND
	CM.FUN==11		;REWIND / UNLOAD
	CM.FRD==02		;READ
	CM.FR1==12		;READ ACROSS BOUNDARIES
	CM.FRC==03		;READ / COMPARE
	CM.FR2==13		;READ / COMPARE ACROSS BOUNDARIES
	CM.FWR==04		;WRITE
	CM.FWL==14		;WRITE AFTER LONG ERG
	CM.FTM==05		;WRITE TAPE MARK
	CM.FLG==15		;WRITE 3" BLANK TAPE
	CM.FFB==06		;SKIP FORWARD BLOCK
	CM.FFF==16		;SKIP FORWARD FILE
	CM.FBB==07		;SKIP BACKWARD BLOCK
	CM.FBF==17		;SKIP BACKWARD FILE

CM.NUE==1B27		;NEXT UNIT INTERUPT ENABLE
CM.DNS==2		;DENSITY BYTE SIZE
CM.DNP==^D29		;RIGHT MOST BIT
	CM.D2==000		;200 BPI
	CM.D5==100		;556 BPI
	CM.D8==200		;800 BPI
	CM.DMX==3		;MAX IORB DENSITY VALUE WE CAN HANDLE

CM.MSF==7B32		;MASK FOR FLAGS PIA
CM.MSD==7		;MASK FOR DATA PIA

;FLAGS IN LH SIDE (CONI ONLY)

CM.NUS==3		;NEXT UNIT BYTE SIZE
CM.NUP==^D17		;RIGHT MOST BIT
CM.EOR==1B14		;WRITE EOF (MAINT)

NOPMSK==760300		;UNIT,PARITY,DENSITY,FORMAT MASK
;DEFINITIONS FOR STATUS REGISTER

CI.CHN==1B9		;DF10C FLAG
			;UNKNOWN
CI.CPE==1B11		;CONTROL WORD PARITY ERROR (TM10B)
CI.NXM==1B12		;NON EX MEM (TM10B)
CI.DPE==1B13		;DATA PARITY ERROR (TM10B)
CI.CWW==1B14		;CONTROL WORD WRITTEN (TM10B)

CI.CCS==3		;CHARACTER COUNTER BYTE SIZE
CI.CCP==^D17		;RIGHT MOST BIT

;BITS IN RH SIDE

CI.HNG==1B18		;UNIT HUNG
CI.REW==1B19		;REWINDING
CI.LDP==1B20		;TAPE AT LOAD POINT (BOT)
CI.ILL==1B21		;ILLEGAL OPERATION
CI.TPE==1B22		;TAPE PARITY ERROR
CI.EOF==1B23		;END OF FILE (TAPE MARK SEEN)
CI.EOT==1B24		;TAPE INDICATE (EOT)
CI.RCE==1B25		;READ / COMPARE ERROR
CI.RLD==1B26		;RECORD LENGTH DIFFERS
CI.DLE==1B27		;DATA LATE ERROR (OVERRUN)
CI.BDT==1B28		;BAD TAPE FLAG
CI.JBD==1B29		;JOB DONE
CI.IDL==1B30		;UNIT IDLE
CI.CHE==1B31		;CHANNEL ERROR (BITS 11,12,13,OR 14)
CI.WLK==1B32		;UNIT WRITE LOCKED
CI.7TK==1B33		;7 TRACK UNIT
CI.LNU==1B34		;LOAD NEXT UNIT
CI.DAT==1B35		;DATA REQUEST

;BITS USED FOR CONO TMS,

CO.CPE==1B31		;CLEAR PARITY ERROR
CO.CCW==1B32		;CLEAR CONTROL WORD WRITTEN
CO.WCW==1B33		;WRITE CONTROL WORD
CO.MBH==1B34		;MOVE BR TO HR
CO.STP==1B35		;STOP CURRENT COMMAND

ALLERS==CI.DLE!CI.TPE!CI.BDT!CI.RCE!CI.ILL!CI.HNG!CI.CHE
			;ALL ERROR FLAGS OF INTEREST
SUBTTL TAPE INTERUPT SERVICE
;CALLED FROM TAPSER WITH W := KDB

TMXISR:	XCT	TMXCIC(W)	;GET COMMAND REG
	LDB	T2,CTYUNI	;GET UNIT SELECTED
	PUSHJ	P,SETUDB##	;SET UP U
	  PJRST	SETM1		;NON-EX UNIT
	XCT	TMXCIC(W)	;GET CMD REG AGAIN
	MOVEM	T1,TMXFCC(U)	;SAVE IN UDB
	LDB	T4,CTYFCN	;GET FCN
	XCT	KDBCNI(W)	;GET STATUS REG
	MOVEM	T1,TMXFCS(U)	;STASH STATUS REG IN UDB
	PUSHJ	P,CHKIRB##	;GET IORB
	  JRST	TAPDIS##	;NONE - DISMISS INT.
	MOVE	T3,TMXFCS(U)	;GET STATUS IN T3
	CAIN	T4,CM.FUR	;IF A NOP
	JRST	TMXSTS		;READ THE STATUS NOW
	MOVSI	T2,TUSBOT##	;CLEAR BOT INDICATION
	ANDCAM	T2,TUBSTS(U)	;  WE WILL SET IT AGAIN IF NECESSARY
	LDB	T2,PRBFCN##	;GET DESIRED FCN
	CAILE	T2,TMIMAX	;CHECK VALIDITY
	JRST	TAPIFI##	;FUNCTION ERROR
	JRST	@TMIDSP(T2)	;DO IT

TMIDSP:	IFIW	TAPIFI##	;(00) ILLEGAL
	IFIW	TMIRD		;(01) READ
	IFIW	TMIWT		;(02) WRITE
	IFIW	TAPIFI##	;(03) READ BACKWARDS (ILLEGAL)
	IFIW	TMISR		;(04) SKIP RECORD
	IFIW	TMIBR		;(05) BACKSPACE RECORD
	IFIW	TMISF		;(06) SKIP FILE
	IFIW	TMIBF		;(07) BACKSPACE FILE
	IFIW	TMIEG		;(10) ERASE GAP
	IFIW	TAPIFI##	;(11) DSE (ILLEGAL)
	IFIW	TMIRW		;(12) REWIND
	IFIW	TMIUN		;(13) REWIND / UNLOAD
	IFIW	TMITM		;(14) WRITE TAPE MARK
	IFIW	TMXOFL		;(15) FAKED INTERRUPT IF UNIT OFF-LINE
	IFIW	TMIRD		;(16) CORRECTION READ
	IFIW	TMIRD		;(17) READ LOW THRESHOLD
TMIMAX==.-TMIDSP-1
;ROUTINE TO MAKE CONTROLLER IDLE

CLRCTL:	LDB	T2,TUYKTP##	;UNIT TYPE
	JUMPN	T2,TMXIDL	;GO IF TM10B
	MOVE	T2,[JSR	PIERR##] ;DON'T LEAVE DATAI/O ADDRESS
	MOVEM	T2,@KDBICP(W)	; HANGING AROUND IN PI LOC
TMXIDL:	PUSH	P,T1		;SAVE IORB
	SETZM	TTMCHE(W)	;CLEAR ERROR FLAG
	HLLZS	@KDBCSO(W)	;NO MORE INTS
	XCT	TMXCIC(W)	;GET CTL CMD REG
	ANDI	T1,NOPMSK	;PRESERVE UNIT # ETC.
	XCT	TMXCOC(W)	;DO NO-OP TO DRIVE W/ PIA=0
	SETOM	TKBUNI(W)	;NO UNIT SELECTED
	PJRST	TPOPJ##		;RETURN

;HERE TO RESET ACTIVE I/O

TMXRES:	XCT	TMXCIC(W)
	MOVEM	T1,TMXFCC(U)
	XCT	KDBCNI(W)
	MOVEM	T1,TMXFCS(U)
	MOVEI	T1,CO.STP	;STOP CURRENT COMMAND
	XCT	KDBCNO(W)	;...
	MOVSI	T2,TKSSEL##	;SELECT BIT
	HRRZ	T1,TUBQUE(U)	;GET HEAD OF Q
	JUMPE	T1,CLRCTL	;NONE - EXIT
	TDNE	T2,TKBSTS(W)	;SELECTED?
	PUSHJ	P,ZAPEXL	;YES - FIX IOWD
	PJRST	CLRCTL		;CLEAR WORLD & EXIT


;ROUTINE TO CAUSE AN INTERUPT TO FORCE A SCHEDULE CYCLE

TMXSCH:	MOVE	T1,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	LSH	T1,^D35-CM.UNP
	IORI	T1,CM.NUE+MTAFLG ;INT ON NEXT UNIT AVAIL
	MOVEI	T2,CI.LNU	;ENABLE FOR LOAD NEXT UNIT
	CONO	PI,PI.OFF	;AVOID RACE
	HRRM	T2,@KDBCSO(W)	;...
	XCT	TMXCOC(W)	;...
	CONO	PI,PI.ON
	POPJ	P,
TMXCFG:	MOVEI	T1,6		;MUST DISTINGUISH TM10A FROM TM10B
	CONO	PI,PI.OFF	;DON'T ALLOW INTERRUPTS
	XCT	.CPCNO##	;CONO DEV,(T1)
	XCT	.CPCNI##	;CONI DEV,T1
	MOVE	T2,T1		;COPY RESULTS
	MOVEI	T1,0		;SET PIA BACK TO 0
	XCT	.CPCNO##	;CONO DEV,(T1)
	CONO	PI,PI.ON	;TURN PI SYSTEM BACK ON
	TRNE	T2,1		;TM10A RETURNS A 7
	JRST	CPOPJ1##	;TM10A NEEDS 18-BIT CHANNELS SO GIVE UP
	XMOVEI	T1,TMXMDT##	;MONGEN'ED DEVICE TABLE
	XMOVEI	T2,DEFMDT	;DEFAULT TABLE
	MOVNI	T3,1		;NO MASSBUS UNIT OR DRIVE INFORMATION
	MOVEI	T4,MD.KON	;MATCH ON KONTROLLER DEFINITION
	PUSHJ	P,AUTMDT##	;SCAN THE TABLES
	  JRST	CPOPJ1##	;NO MATCHES
	PUSHJ	P,SAVE1##	;SAVE P1
	MOVSI	T1,0		;I/O BUS-STYLE CHANNEL
	PUSHJ	P,AUTCHN##	;BUILD A CHANNEL DATA BLOCK
	  POPJ	P,		;NO CORE
	HLRZ	T1,P1		;GET MASSBUS UNIT NUMBER
	PUSHJ	P,AUTKDB##	;BUILD A KDB
	  POPJ	P,		;GIVE UP IF NO CORE
	PUSHJ	P,TAPCSA##	;SET UP CSO CONI ADDRESS
	MOVSI	T1,-<TMXIOE-TMXIOB> ;-LENGTH
	XMOVEI	T2,TMXIOB(W)	;STARTING ADDRESS
	HRRZ	T3,.CPDVC##	;DEVICE CODE
	ADDI	T3,1		;CONVERT STATUS DVC TO COMMAND DVC
	PUSHJ	P,AUTDVC##	;FILL IN DEVICE CODES
	PUSHJ	P,TMXCF3	;PUT CONTROLLER INTO A KNOWN STATE

TMXCF1:	MOVSI	P1,-1		;NO MASSBUS UNIT,,DRIVE 0

TMXCF2:	PUSHJ	P,TMXDRV	;AUTOCONFIGURE A SINGLE DRIVE
	  JFCL			;IGNORE ERRORS
	HRRZ	T1,P1		;GET DRIVE NUMBER
	CAIGE	T1,TMXHDN	;DONE ALL DRIVES?
	AOJA	P1,TMXCF2	;LOOP BACK FOR MORE

TMXCF3:	PUSHJ	P,CLRCTL	;CLEAR WORLD
	MOVE	T2,KDBICP(W)	;GET PNTR TO PI LOC
	MOVEM	T1,1(T2)	;PUT IN PLACE
	JRST	CPOPJ1##	;TRY ANOTHER DEVICE ON SAME CHANNEL
TMXDRV:	XMOVEI	T1,TMXMDT##	;MONGEN'ED DEVICE TABLE
	XMOVEI	T2,DEFMDT	;AND THE DEFAULT TABLE
	MOVE	T3,P1		;DRIVE INFORMATION
	PUSHJ	P,AUTMDT##	;FOUND A DRIVE MATCH?
	  POPJ	P,		;NO
	MOVE	T2,T1		;COPY DRIVE INFO
	TRO	T2,TUCIRD##+TUCD20##+TUCD55##+TUCD80##+K.TMB
	HRLZ	T1,P1		;PHYSICAL DRIVE NUMBER
	HRR	T1,P1		;UDB TABLE INDEX
	XMOVEI	T3,HNGTBL	;POINT TO HUNG TIMER TABLE
	MOVE	T4,['TU40  ']	;ASSUME 9-TRACK
	TRNE	T2,TUC7TK##	;7-TRACK?
	TRO	T4,10000	;YES
	PUSHJ	P,TAPDRV##	;BUILD AND LINK UP UDB AND DDB
	  JFCL			;FAILED
	JRST	CPOPJ1##	;RETURN
SUBTTL START I/O

;ROUTINE TO START I/O
;USER JOB MUST BE NAILED DOWN - CAUSE SELECTION INTERUPT
;OR JUST START I/O IF UNIT ALREADY SELECTED
TMXSIO:	MOVSI	T1,TKSOFL##	;SET THE UNIT ON-LINE
	ANDCAM	T1,TUBSTS(U)	; WILL SET OFF-LINE IF IT ISN'T OK
	MOVE	T1,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	LSH	T1,^D35-CM.UNP	;PUT IN PROPER PLACE
	XCT	TMXCOC(W)	;SELECT UNIT

	XCT	KDBCNI(W)	;GET CTL STATUS
	MOVEM	T1,TMXFCS(U)	;SAVE IN UDB

;HERE WHEN DESIRED DRIVE HAS BEEN SELECTED
;CHECK FOR ERRORS AND UNIT IDLE
	PUSHJ	P,CHKIRB##	;GET IORB
	  JRST	TAPDIS##	;NONE
	MOVE	T3,TMXFCS(U)	;GET STATUS REG
	MOVSI	T4,TUSWTL##	;WRITE LOCKED BIT
	ANDCAM	T4,TUBSTS(U)
	TRNE	T3,CI.WLK	;WRITE LOCKED?
	IORM	T4,TUBSTS(U)	;YES -SET BIT
	LDB	T2,PRBFCN##	;SEE WHAT FCN
	TRC	T3,CI.LNU	;MAKE NEXT TEST EASIER
	TRNN	T3,CI.REW!CI.IDL!CI.LNU ;IS UNIT READY OR REWINDING?
	HRROI	T2,RB.FYB	;NO, SET UP AS A YELLOW BALL
	DPB	T2,PRBFCN##	; FOR INTERRUPT LEVEL TO USE AS A FLAG
	CAIN	T2,RB.FYB	;STATUS CHECK?
	JRST	STSSEL		;YES - GO HANDLE
	TRNE	T3,CI.HNG!CI.ILL!CI.CHE
	JRST	TMXOFL		;UNIT OFFLINE
	PUSH	P,T2		;SAVE T2
	SETZM	TTMCHE(W)	;CLEAR CHL ERROR FLAG
	MOVE	T2,KDBICP(W)	;SET UP ICPC IF TM10B
	XCT	KDBDTO(W)	;...
	POP	P,T2		;RESTORE T2
	PUSHJ	P,SETCMD	;SET UNIT,PAR,DENS,COMPAT,FCN
	  PJRST	STSSEL		;WRITE LOCKED
	MOVEI	T3,CI.HNG!CI.ILL!CI.JBD!CI.CHE
DOIT:	MOVEI	T1,MTAFLG(T2)	;ADD PIA & MOVE TO T1
	CONO	PI,PI.OFF	;SAVE US FROM OTHERS
	HRRM	T3,@KDBCSO(W)	;SET UP INT MASK
	XCT	TMXCOC(W)	;START DEVICE
	CONO	PI,PI.ON	;OK NOW
NXTINT:	TDZA	T1,T1		;MORE INTERRUPTS COMING
SETM1:	MOVNI	T1,1
	POPJ	P,		;EXIT THIS INT
;HERE TO READ STATUS. HAVE TO HANDLE AFTER AN INTERRUPT
STSSEL:	MOVE	T2,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	LSH	T2,^D35-CM.UNP	;PUT IT IN RIGHT PLACE
	TRO	T2,<CM.FUR>B<CM.CMP>+CM.NUE
	MOVEI	T3,CI.HNG!CI.ILL!CI.JBD!CI.CHE!CI.LNU
	JRST	DOIT		;GO CAUSE A UNIT-SELECTED INTERRUPT

;HERE TO GET UNIT STATUS UPDATE ON REQUEST

TMXSTS:	TRNE	T3,CI.HNG	;IF HUNG?
	JRST	TMXOFL		;MUST BE OFF-LINE
	TRNN	T3,CI.LDP	;AT LOAD POINT?
	TRNN	T3,CI.REW	;OR NOT REW'D
	PUSHJ	P,REWDON##	;YES - SET BOT / CLR REW
	PJRST	TMIDON		;EXIT INTERUPT

;HERE IF NO STATUS WORTH REMEMBERING

TMXOFL:	MOVSI	T2,RB.SOL!RB.SER!RB.SNM ;SET OFF-LINE STATUS
	IORM	T2,TRBSTS(T1)
	MOVSI	T2,TKSOFL##	;TELL UPPER LEVEL THAT THE TAPE ISN'T THERE
	IORM	T2,TUBSTS(U)
	PUSHJ	P,CLRCTL	;RESET CTL
	PJRST	TMIDON		;AND RETURN
SUBTTL COMMAND SETUP
;ROUTINE TO SET UP CMD
;T1 := IORB FOR THIS REQUEST
;T3 CONTAINS CONI MTS,  - DESTROYED
;T2 := COMMAND FOR CTL ON EXIT

SETCMD:	LDB	T4,PRBFCN##	;GET DESIRED FCN
	SKIPN	T2,IOFTAB(T4)	;CHECK LEGAL
	JRST	SETILG		;NOPE - ERROR
	TLNE	T2,(IOXWRT)	;WRITE OP?
	JRST	SETCMW		;YES - CHECK WRITE LOCK
	PUSH	P,TTMBLK(W)	;GET BLKI OR ZERO
SETCM1:	MOVE	T2,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	LSH	T2,^D35-CM.UNP	;WHERE IT WILL DO THE MOST GOOD
	IOR	T2,IOFTAB(T4)	;GET FCN CODE
	TLZ	T2,(IOXREW!IOXWRT)	;CLR UNWANTED BITS
	POP	P,T4		;GET BLKI/O
	HRR	T4,@IRBACC(T1)	;GET DATA ADDRS OR SPACING COUNT
	TLZE	T2,(IOXLST)	;DATA?
	JRST	[PUSHJ P,SETCMX	;DO CTL SPECIFIC SETUP
		 JRST SETCM2]	;PROCEED
	TLZN	T2,(IOXSPC)	;SPACING OP?
	JRST	[MOVEI T4,0	;NO - ILLEGAL DATA REQUEST
		 JRST SETCM2]	;SET IN CHL AREA
	MOVNI	T4,-1(T4)	;GET COUNT -1 NEGATED
	JUMPE	T4,[TRZ T2,7	;CLEAR DATA PIA IF ONLY ONE
		    JRST SETCM2];AND STORE ZERO
	LDB	T3,TUYKTP##	;GET KONTROLLER TYPE
	JUMPE	T3,.+4		;NO CHL IF TM10A
	LSH	T4,4		;ONLY 14 BITS OF INFO
	HRLZM	T4,TKBCCL(W)	;SAVE IN CHL PGM AREA
	HRLZ	T4,TTMBLK(W)	;GET BLKO OR ZERO
	HRRI	T4,TKBCCL(W)	;SET ADDRS
	SETZM	TKBCCL+1(W)	;CHL HALT IF TM10B
SETCM2:	MOVEM	T4,@KDBICP(W)	;PUT IN CORRECT PLACE
	LDB	T4,PRBMOD##	;GET DESIRED MODE
	CAIN	T4,RB.MCD	;CORE-DUMP?
	IORI	T2,CM.CDF	;YES - SET BIT
	LDB	T4,PRBDEN##	;GET DENSITY BYTE
	CAILE	T4,CM.DMX	;CHECK MAX
	MOVEI	T4,CM.DMX
	DPB	T4,PRBDEN##	;REMEMBER SELECTED DENSITY
	IOR	T2,[CM.PAR+0
		    CM.PAR+CM.D2
		    CM.PAR+CM.D5
		    CM.PAR+CM.D8](T4)
	MOVSI	T4,RB.PAR	;CHECK PARITY
	TDNE	T4,TRBFNC(T1)	;ON FOR EVEN PARITY
	TRZ	T2,CM.PAR	;CLEAR BIT IN CMD
	PJRST	CPOPJ1##	;GIVE GOOD RETURN

;SET IMPROPER MODE AND RETURN

SETILG:	MOVSI	T2,RB.SIL!RB.SER	;ILLEGAL OP
	IORM	T2,TRBSTS(T1)	;SET IN IORB
	POPJ	P,		;ERROR RETURN
;HERE IF WRITING - CHECK WRLK

SETCMW:	MOVS	T2,TTMBLK(W)	;GET BLKO OR ZERO
	PUSH	P,T2		;SAVE ON PDL
	TRNN	T3,CI.WLK	;WRITE LOCKED?
	JRST	SETCM1		;NO - PROCEED
	MOVSI	T2,RB.SLK!RB.SER	;AND IN IORB
	IORM	T2,TRBSTS(T1)	;...
	PJRST	SETCM1	;ERROR RETURN

;ROUTINE TO SETUP CMD LIST TERMINATION WORD FOR
;SPECIFIC CONTROLLER (A OR B)
;T4 := ADDRS OF CHL PGM

SETCMX:	LDB	T3,TUYKTP##
	JRST	@[SETCXA
		  SETCXB](T3)	;DISPATCH ACCORDING TO TYPE

;HERE FOR TM10A

SETCXA:	MOVE	T3,0(T4)	;SAVE ADDRS
	HRLM	T3,@IRBACC(T1)	;  OF FIRST WORD FOR WORD-COUNT
	MOVEM	T3,TKBSAV(W)	;BLKI/O WORD SAVED
	POPJ	P,		;  COMPUTATION AND RETURN

;HERE FOR TM10B

SETCXB:	HLRZ	T3,@IRBACC(T1)	;END OF XFER LIST
	PUSH	P,T2		;SAVE AN AC
	MOVEI	T2,DF10ZR##	;HANDY ZERO
	MOVEM	T2,0(T3)	;CHL JUMP TO ZERO
	POP	P,T2		;RESTORE USED AC
	SETZM	DF10ZR##	;GRNTEE ZERO
	POPJ	P,		;RETURN
;TABLE FOR I/O FUNCTIONS - ALREADY IN POSITION

DEFINE IOT(CMD,BITS) <
	BITS+<CMD>B<CM.CMP>
>

;ALLOWABLE SPECIAL FCN BITS

IOXLST==1B0		;DATA XFER LIST REQUIRED
IOXSPC==1B1		;SPACING OPERATION
IOXREW==1B2		;REWIND
IOXWRT==1B3		;WRITE OPERATION

IOFTAB:	0			;0 - ILLEGAL
	IOT(CM.FRD,IOXLST)	;1 - READ
	IOT(CM.FWR,IOXLST!IOXWRT) ;2 - WRITE
	0			;3 - ILLEGAL
	IOT(CM.FFB,IOXSPC)	;4 - FORWARD SPACE BLOCK
	IOT(CM.FBB,IOXSPC)	;5 - BACKWARD SPACE BLOCK
	IOT(CM.FFF,IOXSPC)	;6 - FORWARD SPACE FILE
	IOT(CM.FBF,IOXSPC)	;7 - BACKSPACE FILE
	IOT(CM.FLG,IOXWRT)	;10 - WRITE LONG GAP
	0			;11 - ILLEGAL
	IOT(CM.FRW,IOXREW)	;12 - REWIND
	IOT(CM.FUN,0)		;13 - REWIND / UNLOAD
	IOT(CM.FTM,IOXWRT)	;14 - WRITE TAPE MARK
	IOT(CM.FFB,IOXSPC)	;USED WHEN UNIT DETECTED OFF-LINE
	IOT(CM.FRD,IOXLST)	;16 - CORRECTION READ
	IOT(CM.FRD,IOXLST)	;17 - READ LOW THRESHOLD


;HUNG TIMER TABLE
	EXP	^D320			;MAXIMUM TIMEOUT VALUE
HNGTBL:	BYTE(9)	^D000,^D031,^D031,^D000	;IL,RD,WT,RB
	BYTE(9)	^D031,^D031,^D320,^D320	;SR,BR,SF,BF
	BYTE(9)	^D031,^D000,^D150,^D150	;LG,SE,RW,RU
	BYTE(9)	^D031,^D031,^D031,^D031	;TM,YB,CR,RL
SUBTTL READ
;HERE ON DONE INTERUPT FOR READ

TMIRD:	PUSHJ	P,TMCKMV	;SEE IF TAPE MOVED
	  JSP	T4,TMERD0	;NO - PROBS
	PUSHJ	P,CHRCT		;GET CHARACTER COUNT
	  JRST	[MOVSI T4,RB.STL+RB.SER
		 IORM T4,TRBSTS(T1)
		 JRST .+1]
	MOVEM	T2,TRBRCT(T1)	;SAVE COUNT IN IORB
	MOVE	T3,TMXFCS(U)	;RESTORE STATUS
	SKIPN	TTMCHE(W)	;CHL ERROR
	TRNE	T3,CI.CHE	;???
	JRST	TMECHN		;YES - HANDLE
	PUSHJ	P,TMSTM		;ENCOUNTER EOF?
	  JRST	TMIRD1		;NO - GO ON
	AOS	TUBFIL(U)	;PLUS 1 MORE FILE
TMIRD1:	TRNE	T3,ALLERS	;CHECK BADNESS
	JSP	T4,TMERD1	;ERROR - HANDLE
	MOVE	T2,TRBRCT(T1)	;GET CHAR COUNT FOR THIS RECORD
	ADDM	T2,TUBCRD(U)	;AND UPDATE STATISTICS
	ADDM	T2,TKBCRD(W)
	ADDM	T2,.CPTFI##

;HERE TO FINISH INTERUPT AND EXIT TO TAPSER

TMIDON:	PUSHJ	P,ZAPEXL	;CLEAN UP
	MOVE	T3,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	MOVEM	T3,TKBUNI(W)	;AND SAVE IT FOR LATER CHECK
	HLRZ	T3,TRBSTS(T1)	;LOOK AT FLAGS
	JUMPE	T3,CPOPJ##	;RETURN IF NONE
	MOVSI	T2,RB.EXC	;ELSE SET EXCEPTION
	IORM	T2,TRBFNC(T1)	;IN IORB
	POPJ	P,		;AND RETURN

;ROUTINE TO FIXUP TM10B XFER LIST

ZAPEXL:	LDB	T3,TUYKTP##	;GET TYPE
	HLRZ	T2,@IRBACC(T1)	;PNTR TO END OF XFER LIST
	JUMPE	T2,CPOPJ##	;RETURN IF NONE
	JUMPE	T3,ZAPEXA	;JUMP IF TM10A
	SETZM	0(T2)		;CLEAR IT
	POPJ	P,		;RETURN

;RESTORE BLKI/O WORD

ZAPEXA:	MOVE	T2,TKBSAV(W)
	HRRZ	T3,@IRBACC(T1)	;PNTR TO XFER LIST
	MOVEM	T2,0(T3)	;STORE WORD
	POPJ	P,		;RETURN
SUBTTL WRITE
;HERE ON DONE INTERUPT FOR WRITE

TMIWT:	PUSHJ	P,TMCKMV	;DID IT MOVE
	  JSP	T4,TMEWT0	;NO - TRY TO FIX
	SKIPN	TTMCHE(W)	;CHL ERROR?
	TRNE	T3,CI.CHE
	JRST	TMECHN		;YES - LOOK AT THAT
	MOVSI	T2,RB.SET	;NOW CHECK EOT
	TRNE	T3,CI.EOT	;???
	IORM	T2,TRBSTS(T1)	;SET INFO IN IORB
	TRNE	T3,ALLERS	;EVERYTHING OK?
	JSP	T4,TMEWT1	;NO - TRY TO FIX
	PUSHJ	P,CHRCT		;GET CHARACTER COUNT
	  JFCL			;DON'T CARE
	ADDM	T2,TUBCWR(U)	;ADD TO STATS
	ADDM	T2,TKBCWR(W)
	ADDM	T2,.CPTFO##
	PJRST	TMIDON		;AND EXIT

;HERE ON DONE INTERUPT FOR WRITE TAPE MARK

TMITM:	MOVSI	T2,RB.SET	;JUST IN CASE
	TRNE	T3,CI.EOT	;WE SAW A TI
	IORM	T2,TRBSTS(T1)	;SET FLG IF SEEN
	TRNE	T3,ALLERS	;ANYTHING WRONG?
	JSP	T4,TMEWT1	;YES - SORRY
	SETZM	TUBREC(U)	;ZEROTH RECORD
	AOS	TUBFIL(U)	;AND 1 MORE FILE
	PJRST	TMIDON		;EXIT

;ROUTINE SET SAY WE'VE SEEN A TAPE MARK
;ALSO RESETS RECORD COUNTER

TMSTM:	TRNN	T3,CI.EOF	;SEEN EOF?
	POPJ	P,		;NO - RETURN
	MOVSI	T2,RB.STM	;IORB FLAG ALSO
	IORM	T2,TRBSTS(T1)	;...
	SETZM	TUBREC(U)	;CLEAR RECORD COUNT
	PJRST	CPOPJ1##	;SKIP RETURN FOR FURTHER PROCESSING
SUBTTL REWIND/UNLOAD/BACKSPACE RECORD
;HERE ON INTERUPT AFTER STARTING REWIND

TMIUN:	MOVE	T2,TUBSTS(U)
	TLZ	T2,TUSREW##	;NOT REWINDING
	JRST	TMIRWU		;CARRY ON

TMIRW:	TRNE	T3,CI.HNG!CI.ILL	;CHECK BADNESS
	JSP	T4,TMERW	;HANDLE PROBLEM
	MOVE	T2,TUBSTS(U)	;SAY WE ARE REWINDING
	TLO	T2,TUSREW##
TMIRWU:	MOVEM	T2,TUBSTS(U)
	TRNE	T3,CI.LDP	;ALREADY DONE?
	PUSHJ	P,REWDON##	;YES - CLEAN UP THEN
	SETZM	TUBREC(U)	;IN CASE WE DON'T FINISH
	SETZM	TUBFIL(U)	;CLEAR THESE NOW
	PJRST	TMIDON		;AND EXIT

;HERE ON DONE INTERUPT FROM BACKSPACE RECORD

TMIBF:!
TMIBR:	TRNE	T3,CI.HNG!CI.CHE ;DEVICE PROBS?
	JSP	T4,TMERD1	;WHOOPS PROBLEM
	PUSHJ	P,TMSTM		;LOOK FOR TM
	  JRST	TMIBR1		;NONE SEEN
	SOS	TUBFIL(U)	;ONE  LESS FILE
TMIBR1:	SOS	TUBREC(U)	;ALSO ONE LESS RECORD
	TRNN	T3,CI.LDP	;SEE IF WE CRASHED INTO BOT
	PJRST	TMIDON		;NO - DONE
	MOVSI	T2,RB.SBT!RB.SNM ;YES - LITE BITS
	SKIPN	TUBREC(U)	;TRY TO GUESS IF TAPE MOVED
	SKIPE	TUBFIL(U)	;  BY SEEING IF AT LOGICAL BOT
	TLZ	T2,RB.SNM	;FIRST TIME HERE
	IORM	T2,TRBSTS(T1)	;SET RESULT IN IORB
	MOVSI	T2,TUSBOT##	;AND UDB
	IORM	T2,TUBSTS(U)	;...
	SETZM	TUBREC(U)	;GET THINGS RIGHT
	SETZM	TUBFIL(U)
	PJRST	TMIDON		;EXIT
SUBTTL SKIP RECORD/FILE/ERASE GAP

;HERE ON DONE INTERUPT FROM SKIP FORWARD RECORD/FILE

TMISF:!
TMISR:	PUSHJ	P,TMCKMV	;SEE IF WE MOVED?
	  JSP	T4,TMERD0	;NOPE
	TRNE	T3,ALLERS	;CHECK ERRORS
	JSP	T4,TMERD1	;HANDLE IT
	PUSHJ	P,TMSTM		;CHECK FOR TAPE MARK
	  JRST	TMIDON		;NO TAPE MARK
	AOS	TUBFIL(U)	;INCR FILE COUNTER
	JRST	TMIDON		;AND EXIT

;HERE ON DONE INTERUPT FROM ERASE GAP

TMIEG:	MOVSI	T2,RB.SET	;IN CASE TAPE INDICATE
	TRNE	T3,CI.EOT	;SEEN ONE?
	IORM	T2,TRBSTS(T1)	;YES - SET BIT
	TRNE	T3,CI.HNG!CI.ILL!CI.CHE	;ERROR ALLOWED
	JRST	TMEWT1		;YES - TREAT IT
	PJRST	TMIDON		;EXIT INT
;HERE FOR CHANNEL ERROR

TMECHN:	TLNN	T3,(CI.DPE)	;DATA PARITY ERROR?
	JRST	TMECH1		;NO - HANDLE NOW
	MOVEI	T1,CO.STP!CO.CPE
	XCT	KDBCNO(W)	;STOP CHL & CLEAR ERROR
	MOVEM	T3,TTMCHE(W)	;FLAG ERROR SAVE CONI BITS
	PJRST	NXTINT		;AND WAIT FOR JOB DONE

TMECH1:	MOVE	T2,TTMCHE(W)	;GET ERROR CONI BITS
	MOVEM	T2,TMXFCS(U)	; SO DAEMON GETS THEM
	PUSHJ	P,SAVE1##	;SAVE P1
	MOVEI	T2,CHENXM##	;ASSUME NXM
	MOVSI	T4,IOCHNX	; ...
	TLNE	T3,(CI.DPE!CI.CPE)
	MOVEI	T2,CHEMPE##	;NO - PARITY ERROR
	TLNE	T3,(CI.DPE!CI.CPE)
	MOVSI	T4,IOCHMP	; ...
	PUSH	P,T1		;SAVE IORB PNTR
	MOVE	T1,KDBICP(W)	;PNTR TO CCW
	MOVE	P1,KDBCHN(W)	;PNTR TO CHL DATA BLOCK
	MOVE	F,TUBCUR(U)	;PNTR TO DDB
	IORM	T4,CHNNUM##(P1)	;MARK MEMORY ERROR FOR LATER SWEEP
	SKIPN	TUBERR(U)	;CALL ERRCON ON FIRST ERROR ONLY
	PUSHJ	P,0(T2)		;EXERCISE ROUTINE
	MOVEI	T1,CO.CCW	;CLEAR CONTROL WORD WRITTEN
	XCT	KDBCNO(W)	;...
	POP	P,T1		;RESTOR IORB
	MOVSI	T2,RB.SER!RB.SED
	IORM	T2,TRBSTS(T1)	;TELL HIM WORLD ENDED
	PJRST	TMIDON		;RETURN - NO RETRIES

;ROUTINE TO DETERMINE IF TAPE MOVED (DIVINATION)

TMCKMV:	TRNE	T3,CI.HNG!CI.ILL
	POPJ	P,		;TRY THIS FOR NOW
	AOS	TUBREC(U)	;MOVIN' ALONG
	JRST	CPOPJ1##	;SKIP RETURN
;ERRORS DETECTED DURING WRITE OPERATIONS

TMEWT0:	MOVSI	T2,RB.SNM!RB.SED	;TAPE DIDN'T MOVE
	IORM	T2,TRBSTS(T1)
TMEWT1:	PUSHJ	P,TMEANL	;ANALYSE ERROR
	MOVSI	T2,RB.SLK	;CHECK FOR WRITE LOCK
	TRNE	T3,CI.WLK
	IORM	T2,TRBSTS(T1)	;YES - SET BIT
	PJRST	TMIDON		;EXIT INTERUPT

;ERRORS DETECTED DURING READ / SPACING OPS

TMERD0:	MOVSI	T2,RB.SNM!RB.SED	;TAPE DIDN'T MOVE
	IORM	T2,TRBSTS(T1)
TMERD1:	PUSHJ	P,TMEANL	;ERROR ANALYSIS
	PJRST	TMIDON		;EXIT INT

;PROBLEM STARTING REWIND

TMERW:	MOVSI	T2,RB.SED!RB.SNM!RB.SOL
	IORM	T2,TRBSTS(T1)	;SET OFF-LINE ETC.
	PUSHJ	P,CLRCTL	;RESET CTL
	PJRST	TMIDON		;EXIT INT
;ROUTINE TO ANALYSE ERROR BITS IN RH(T3)

TMEANL:	MOVEI	T2,0		;SET INITIAL ZERO
	TRNE	T3,CI.HNG
	JRST	TMEOFL		;DRIVE OFF-LINE
	TRNE	T3,CI.ILL
	JRST	TMECMR		;COMMAND REJECT
	TRNE	T3,CI.DLE
	JRST	TMEOVR		;OVERRUN
	TRNE	T3,CI.TPE!CI.BDT!CI.RCE
	JRST	TMEDC		;DATA CHECK
TMEXIT:	IORM	T2,TRBSTS(T1)	;SET SELECTED BITS
	POPJ	P,		;RETURN

TMEOFL:	PUSHJ	P,TMXOFL	;SET UNIT OFF-LINE
TMECMR:	MOVSI	T2,RB.SNM!RB.SED	;SET BITS (TAPE DIDN'T MOVE)
	PJRST	TMEXIT

TMEDC:	TLO	T2,RB.SDE	;DATA ERROR
TMEOVR:	TLO	T2,RB.SED	;ERROR DETECTED - RETRY
	PJRST	TMEXIT
SUBTTL COMPUTE CHARACTER COUNTS
;ROUTINE COMPUTES CHARACTER COUNT
;RETURNS COUNT IN T2 , T1 SAVED
;CALLED WITH C(T3) := CONI MTS,

CHRCT:	PUSH	P,T1		;SAVE IORB PNTR
	LDB	T2,TUYKTP##	;GET CNTRL TYPE
	PUSHJ	P,@[WRDCTA
		    WRDCTB](T2)	;CALL CORRECT ROUTINE
	  SKIPA			;LENGTH ERROR RETURN
	AOS	-1(P)		;SET FOR SKIP RETURN
	MOVEI	T2,-1(T1)	;WORD COUNT -1 INTO T2
	HLRZ	T4,T3		;NOW PLAY WITH BC CHAR CNT
	ANDI	T4,7		;TO DETERMINE BYTE RESIDUE
	JUMPE	T4,[AOJA T2,CHRCT1]	;IF ZERO RE-ADJUST WORD COUNT
CHRCT1:	DPB	T4,PMTNCR##	;SAVE RESIDUE FOR MTCHR.
	HRLM	T2,TUBCHR(U)	;STORE LAST WORD COUNT FOR MTCHR.
	TRNE	T3,CI.7TK	;REAL EASY IF 7-TRACK
	JRST	CHRCT2		;...
	XCT	TMXCIC(W)	;9TK - SEE WHAT MODE
	MOVEI	T3,5		;ASSUME CORE-DUMP
	TRNN	T1,CM.CDF	;IS IT?
	MOVEI	T3,4		;NO - COMPAT THEN
	IMUL	T2,T3		;CONVERT TO BYTES
	ADD	T2,T4		;PLUS REMAINDER
	XCT	TMXDIC(W)	;AND FETCH CRC
CHRCT3:	DPB	T1,PMTCRC##	;STORE IT FOR MTCHR.
	PJRST	TPOPJ##		;RESTORE T1 AND EXIT

CHRCT2:	MOVE	T1,(P)		;GET IORB
	LDB	T1,PRBMOD##	;MODE
	IMUL	T2,TMODTB##(T1)	;CHARS TAPUUO THINKS ARE IN A WORD

	ADD	T2,T4		;PLUS LEFT OVERS
	MOVEI	T1,0		;NO CRC FOR 7TK
	JRST	CHRCT3
;ROUTINE TO COMPUTE WORD COUNT FOR TM10A
;RETURNS WORD COUNT IN T1 , T3 PRESERVE
;CALLED WITH T1 := IORB

WRDCTA:	HRRZ	T4,@IRBACC(T1)	;ADDRS OF RESIDUE PNTR
	HLRZ	T2,@IRBACC(T1)	;ADR OF FIRST WORD -1
	HRRZ	T1,0(T4)	;LAST ADDRS
	SUB	T1,T2		;DIFFERENCE IS WORD COUNT
	TRNE	T3,CI.RLD	;CHECK LENGTH ERROR
	SKIPGE	0(T4)		;YES - SHORT RECORDS OK
	JRST	CPOPJ1##	;OK - LEN .LE. ACTUAL
	POPJ	P,		;ERRORR IF RECORD TOO LARGE

;ROUTINE TO COMPUTE WORD COUNT FOR TM10B
;CALLING CONVENTIONS SAME AS WRDCTA

WRDCTB:	MOVE	T1,KDBICP(W)	;PNTR TO INITIAL CONTROL WORD
	PUSHJ	P,SAVE1##	;SAVE P1
	MOVE	P1,KDBCHN(W)	;ADDRS OF CDB

	PUSH	P,T3		;SAVE T3
	PUSHJ	P,WRDCNX##	;CALL ROUTINE IN COMMON
	POP	P,T3		;RESTORE T3
	TRNN	T3,CI.RLD	;LENGTH = REQUEST?
	JRST	CPOPJ1##	;OK - GIVE GOOD RETURN
	MOVE	T2,KDBICP(W)	;ICPC PNTR
	HLRZ	T2,1(T2)	;LH TERMINATION WORD
	LSH	T2,-4		;DF10C HAS 14 BIT ADDRS
	SKIPN	(T2)		;ARE WE AT END OF LIST
	SOJA	T1,CPOPJ##	;YES - RECORD IS TOO LONG
	SOJA	T1,CPOPJ1##	;NO - SHORT RECORD, OK

TMXEND:	END