.MCALL .MODULE .MODULE DY,VERSION=30,COMMENT=,AUDIT=YES ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. .SBTTL CONDITIONAL ASSEMBLY SUMMARY ;+ ;COND ; DYT$O (0) support 2 controllers ; 0 support 1 controller ; 1 support 2 controllers ; ; DY$DD (0) support double/single density ; 0 support double/single density ; 1 support double density only ; ; DY$CSR (177170) first CSR ; DY$CS2 (177150) second CSR ; ; DY$VEC (264) first Vector ; DY$VC2 (270) second Vector ; ; MMG$T std conditional ; TIM$IT std conditional (no code effects) ; ERL$G std conditional ;- .SBTTL Edit History ;+ ; ; Edit History: ; ; 001 17-Jan-80 12:04 Chernoff, Anton (25430) [240,100] ; Correct SEEK code ; (001) ; 002 28-Jan-80 11:45 Parent, Les (75450) [240,95] ; Change retry code to interrupt driven ; Changed retry code to be interrupt driven rather than wait-on-DONE. ; This allows retries to be ^C from SJ and doesn't lock out interrupts ; during retries on LSI-11s. ; (002) ; 003 30-Jan-80 16:33 Parent, Les (75450) [240,95] ; RE-FIX SEEK PROBLEM ; (003) ; 004 31-Jan-80 16:05 Parent, Les (75450) [240,95] ; Unconditionalize Density error/No reset code ; (004) ; 005 20-Feb-80 11:54 Parent, Les (75450) [240,95] ; Re-fix the re-fixed seek fix !!! ; Check for "seeks" (word count = 0) at wrong place in code ; (005) ; 006 17-Jun-81 07:49 AM Les Parent [240,95] ; Fix XM par boundary underflow bug ; (006) ; 007 19-Feb-82 23:59 PM Martin Gentry [40,121] ; Removing double-sided floppy code, adding support for ; 1) SET CSR/VECTOR, 2) SET [NO]WRITE protect, plus ; some general source clean-up ; (007) ; 008 13-Mar-82 03:07 PM Martin Gentry [40,121] ; Adding VARSZ$ support ; Also fixing SET CSR when assembled for multiple controllers ; (008) ; 009 15-Apr-82 11:34 PM Martin Gentry [40,121] ; V5 development: set options ; (009) ; ; 010 4-Aug-85 Jim Williams ; Added .DRPTR, .DREST, and .DRSPF ; ; 011 2-Dec-87 George Stevens ; Changed clear of DYCSA in DYDONE routine to BIC of CSINT in ; DYCSA to preserve the drive density bit in RXES. ; ; 014 1-Mar-88 Jim Williams ; Moved the READ/WRITE code in set area to install area so that ; max configuration will assemble correctly. ; ; 015 12-Jul-88 Linda Banche ; Put code in for UMR support ; ; 027 10-APR-89 George Stevens ; Add clear of CSINIT to clear of CSINT in instruction before .DRFIN ; to prevent drive resets from occuring. ; ; 029 27-APR-89 George Stevens ; Add drive initialize if CSDONE is not set during I/O initiation. ; ; 030 01-Jun-90 Megan Gentry ; Fixed location of DYCSA which was causing assembly errors ; due to it being out of range of SET code ; ;- .SBTTL MACROS AND DEFINITIONS .ENABL LC ; RT-11 MACROS TO BE USED .MCALL .DRDEF .ADDR .ASSUME .BR .LIBRARY "SRC:SYSTEM.MLB" .MCALL .UBVDF .UBVDF .DSTATUS=342 ;EMT CODE FOR .DSTATUS REQUEST ; UB DEFINITIONS ; FIXED OFFSETS EQUATES (.FIXDF) $PNPTR =: 000404 ;RMON OFFSET OF PNAME TABLE P1$EXT =: 000432 ;RMON OFFSET OF $P1EXT ADDRESS $H2UB =: 000460 ;RMON OFSET OF UB ENTRY VECTOR PTR ; EXTENDED MEMORY SUBROUTINE OFFSETS FROM $P1EXT (.PIXDF) $MPMEM =: -22. ;OFFSET TO MAP KT-11 VIRTUAL TO PHYSICAL NOUMRS = 1 ; NUMBER OF PERMANENT UMRS REQUIRED ; RT-11 SYSTEM COMMUNICATIONS AREA SYSPTR = 54 ;POINTER TO BASE OF RMON PNPTR = 404 ;OFFSET FROM $RMON TO $PNAME TABLE ; SOME LOCAL MACROS .MACRO BNE. LABEL,?ALT BEQ ALT JMP LABEL ALT: .ENDM ; SOME RX02 CONTROLLER DEFAULTS .IIF NDF DYT$O, DYT$O = 0 ;DEFAULT TO ONLY ONE CONTROLLER .IIF NDF DY$DD, DY$DD = 0 ;DEFAULT TO SUPPORT BOTH DENSITIES .IIF NDF DY$CS2 DY$CS2 == 177150 ;2ND CONTROLLER CONTROL/STATUS .IIF NDF DY$VC2 DY$VC2 == 270 ;2ND CONTROLLER VECTOR .IF EQ MMG$T .DRDEF DY,6,FILST$!SPFUN$!VARSZ$,494.,177170,264 .DRPTR .IFF ;EQ MMG$T .DRDEF DY,6,FILST$!SPFUN$!VARSZ$,494.,177170,264,DMA=YES,PERMUMR=NOUMRS .DRPTR FETCH=FETCH,LOAD=FETCH,RELEASE=RELEAS,UNLOAD=RELEAS .ENDC ;EQ MMG$T .IIF EQ DY$DD .DREST CLASS=DVC.DK,MOD=DVM.DX .IIF NE DY$DD .DREST CLASS=DVC.DK ; double density only .IF NE MMG$T .DRSPF +UBTAB ;TABLE OF UB SPFUN'S .ENDC ;NE MMG$T .DRSPF <373> ;373 - GET DEVICE SIZE ;374 - UNUSED .DRSPF <375> ;375 - WRITE WITH DELETED DATA .DRSPF <376> ;376 - WRITE ABSOLUTE SECTOR .DRSPF <377> ;377 - READ ABSOLUTE SECTOR ; CONTROL AND STATUS REGISTER BIT DEFINITIONS CSGO = 1 ;INITIATE FUNCTION CSUNIT = 20 ;UNIT BIT CSDONE = 40 ;DONE BIT CSINT = 100 ;INTERUPT ENABLE CSTR = 200 ;TRANSFER REQUEST CSDN = 400 ;DOUBLE DENSITY REQUEST CSHEAD = 1000 ;SELECT SECOND HEAD CSRX02 = 4000 ;CONTROLLER IS RX02 CSINIT = 40000 ;RX11 INITIALIZE CSERR = 100000 ;ERROR DNERR = 20 ;RXDB DENSITY ERROR ; CSR FUNCTION CODES IN BITS 1-3 CSFBUF = 0*2 ;0 - FILL SILO (PRE-WRITE) CSEBUF = 1*2 ;1 - EMPTY SILO (POST-READ) CSWRT = 2*2 ;2 - WRITE SECTOR CSRD = 3*2 ;3 - READ SECTOR ;4 - UNUSED CSRDST = 5*2 ;5 - READ STATUS CSWRTD = 6*2 ;6 - WRITE SECTOR WITH DELETED DATA CSMAIN = 7*2 ;7 - MAINTENANCE .ASSUME CSRD&2 NE 0 ;2 BIT MUST BE ON IN READ .ASSUME CSWRT&2 EQ 0 ;2 BIT MUST BE OFF IN WRITE .ASSUME CSWRTD&2 EQ 0 ;2 BIT MUST BE OFF IN WRITE ; ERROR AND STATUS REGISTER BIT DEFINITIONS ESCRC = 1 ;CRC ERROR ESPAR = 2 ;PARITY ERROR ESID = 4 ;INITIALIZE DONE ESSID1 = 10 ;SIDE 1 READY ESDNER = 20 ;DENSITY ERROR ESDN = 40 ;REAL DENSITY ESDD = 100 ;DELETED DATA MARK ESDRY = 200 ;DRIVE READY ; DY CHARACTERISTICS DDNBLK = DYDSIZ*2 ;DOUBLE DENSITY SINGLE-SIDED DYNREG = 3 ;# OF REGISTERS TO READ FOR ERROR LOG. RETRY = 8. ;RETRY COUNT SPFUNC = 100000 ;SPECIAL FUNCTIONS FLAG ; (IN COMMAND WORD) ; SPECIAL FUNCTION CODES SIZ$FN = 373 ;373 - GET DEVICE SIZE ;374 - UNUSED WDD$FN = 375 ;375 - WRITE WITH DELETED DATA WRT$FN = 376 ;376 - WRITE ABSOLUTE SECTOR RED$FN = 377 ;377 - READ ABSOULTE SECTOR ;NOTE: if you add a SPFUN code here also add it to .DRSPF ;+ ; SPECIAL FUNCTION SUMMARY: ; ; CODE ACTION ; ---- ------ ; 377 ABSOLUTE SECTOR READ. ; WCNT=TRACK, BLK=SECTOR, ; BUFFER=65 WORD BUFFER FOR SINGLE DENSITY, ; 129 WORD BUFFER FOR DOUBLE DENSITY. ; FIRST WORD OF BUFFER IS DELETED DATA FLAG. ; 376 ABSOLUTE SECTOR WRITE. ARGUMENTS SAME AS READ. ; 375 ABSOLUTE SECTOR WRITE WITH DELETED DATA. 1ST WORD ; OF 65 WORD BUFFER ALWAYS SET TO 0. ; 373 GET DEVICE SIZE. ; BUFFER=1 WORD BUFFER IN WHICH DEVICE SIZE ; IN 256. WORD BLOCKS IS RETURNED ; ; IN STANDARD RT-11 MODE A 2:1 INTERLEAVE IS USED ON A SINGLE TRACK AND ; A 6 SECTOR SKEW IS USED ACROSS TRACKS. TRACK 0 IS LEFT ALONE FOR ; ANSI COMPATABILITY. ;- .SBTTL INSTALLATION CHECKS .IF EQ DYT$O .DRINS DY .IFF .DRINS DY, .ENDC ;EQ DYT$O NOP ;SAME CHECK FOR SYSTEM AND NON-SYSTEM HANDLER BIT #CSRX02,@INSCSR ;IS THE RX02 BIT ON? BNE O.GOOD ;YES, IT'S AN RX02, INSTALL IT BR O.BAD ;NOPE, AN RX01, DON'T INSTALL IT ; Routine to find the entry for DY in the monitor device tables FINDRV: .ADDR #DEVNAM,R0 ;R0->DEVICE NAME .ADDR #DAREA+1,-(SP) ;(SP)->.DSTATUS INFO AREA(+physical) EMT .DSTATUS ;*** (.DSTAT #DAREA+1,#DEVNAM) *** BCS O.BAD ;IN CASE IT'S NOT KNOWN MOV DAREA+4,R1 ;RETURN THE ENTRY POINT BEQ O.BAD ;UNLESS HANDLER'S NOT LOADED BR O.GOOD DAREA: .BLKW 4 ;.DSTAT INFORMATION BLOCK DEVNAM: .RAD50 /DY / ;DEVICE NAME ; The EMT area for reads/writes of the handler file is placed here ; to leave room for set option code BAREA: .BYTE 17,10 ;CHANNEL 17, READ .BLKW ;BLOCK NUMBER TO READ/WRITE .BLKW ;BUFFER ADDRESS .WORD 256. ;TRANSFER COUNT (WORDS) .WORD 0 ;COMPLETION (WAIT) BTCSR = ++1000 UPDBOT: ;R1->READ/WRITE EMT AREA .ADDR #BAREA+4,R1 ; (BUFFER ADDRESS WORD) ;R2->BUFFER FOR READ/WRITE .ADDR #1000,R2 ; (OVERWRITES CORE COPY OF BLOCK 1) MOV R2,(R1) ;SET THE BUFFER ADDRESS MOV #BTCSR/1000,-(R1) ;SET BLOCK NUMBER TO READ/WRITE ; (BOOT BLOCK THAT NEEDS MODIFICATION TST -(R1) ;R1->EMT AREA MOV R0,R3 ;SAVE CSR ELSEWHERE, EMT NEEDS R0 MOV R1,R0 ;R0->EMT AREA FOR READ EMT 375 ; *** (.READW) *** BCS X.BAD MOV R3,(R2) ;SET THE BOOTSTRAP CSR MOV R1,R0 ;R0->EMT AREA AGAIN INCB 1(R0) ;CHANGE FROM 'READ' TO 'WRITE' EMT 375 ; *** (.WRITW) *** BCS X.SYWL ; SY: Writelocked MOV R1,R0 ;R0->EMT AREA FOR LAST TIME DECB 1(R0) ;CHANGE BACK TO 'READ' MOV #1,2(R0) ; OF BLOCK 1 OF HANDLER EMT 375 ; *** (.READW) *** BCS X.BAD RETURN X.SYWL: ADD #2,2(SP) ; use alternate return (RET+2) X.BAD: TST (SP)+ ;Align stack BR O.BAD ;and error exit .IIF GT,<.-400> .ERROR ;INSTALLATION CODE IS TOO LARGE; .SBTTL SET OPTIONS ; The write-protect/enable SET option makes use of the new ; calling convention, i.e. the unit specified in DYn (n=0 ; if a space) is passed in r1. .DRSET CSR, 160000, O.CSR, OCT .IF EQ DYT$O .DRSET VECTOR, 500, O.VEC, OCT .IFF; EQ DYT$O .DRSET VECTOR, +1, O.VEC, OCT .DRSET CSR2, 160000, O.CSR2, OCT .DRSET VEC2, +1+6, O.VEC2, OCT .ENDC ;EQ DYT$O .DRSET RETRY, 127., O.RTRY, NUM .IF NE ERL$G .DRSET SUCCES, -1, O.SUCC, NO .ENDC .DRSET WRITE, 1, O.WP, NO O.CSR: CMP R0,R3 ;IS CSR IN RANGE? (>160000) BLO O.BAD ;NOPE... MOV R0,INSCSR ;YES, INSTALLATION CODE NEEDS IT MOV R0,DISCSR ;FILL IN DISPLAY CSR ; NOW WE CHANGE THE CSR CONTAINED IN THE BOOTSTRAP CALL UPDBOT ;Update the boot code .IF EQ DYT$O MOV R3,DYCSA ;Set RX02 controller address .IFF ;EQ DYT$O MOV R3,DYCSR ;Set first RX02 controller address .ENDC ;NE DYT$O O.GOOD: TST (PC)+ ;GOOD RETURN (CARRY CLEAR) O.BAD: SEC ;BAD RETURN (CARRY SET) RETURN .IF EQ DYT$O O.VEC: CMP R0,R3 ;VECTOR IN RANGE? (<500) BHIS O.BAD ;NOPE... BIT #3,R0 ;YES, BUT ON A VECTOR BOUNDRY? BNE O.BAD ;NOPE... MOV R0,DYSTRT ;YES, PLACE IT IN THE ENTRY AREA BR O.GOOD .IFF; EQ DYT$O O.CSR2: CMP R0,R3 ;CSR ADDRESS IN RANGE? (>160000) BLO O.BAD ;NOPE... MOV R0,DYCSR2 ;Set second RX02 controller address MOV R0,DISCS2 ; and second display CSR BR O.GOOD O.VEC: O.VEC2: CMP R0,#500 ;VECTOR ADDRESS IN RANGE? (<500) BHIS O.BAD ;NOPE... BIT #3,R0 ;YES, BUT ON A VECTOR BOUNDRY? BNE O.BAD ;NOPE... .ADDR #DY$VTB-1,R3,ADD ;Add in base address MOV R0,@R3 ;YES, PLACE IN MULTI-VECTOR TABLE BR O.GOOD .ENDC ;EQ DYT$O O.RTRY: CMP R0,R3 ;ASKING FOR TOO MANY? BHI O.BAD ;YES... CMP #2,R0 ;LESS THAN 2 RETRIES SPECIFIED? BHI O.BAD ;YES... MOV R0,DRETRY ;TELL HANDLER BR O.GOOD .IF NE ERL$G O.SUCC: MOV #0,R3 ;'SUCCESS' ENTRY POINT ; (MUST TAKE UP TWO WORDS) N.SUCC: .ASSUME O.SUCC+4 EQ N.SUCC MOV R3,SCSFLG ;'NOSUCCESS' ENTRY POINT BR O.GOOD .ENDC O.WP: NOP ;'WRITE' ENTRY POINT CLR R3 ;CLEAR FLAG N.WP: ;'NOWRITE' ENTRY POINT .ASSUME O.WP+4 EQ N.WP MOV R3,O.WPF ;SAVE THE USER'S SELECTION MOV R1,R3 ; save unit number CMP R3,#DYT$O*2+1 ;IS IT A VALID UNIT BHI O.BAD ;NOPE... ; NOW ALTER THE CODE WHICH WILL BE WRITTEN BACK TO DISK .ADDR #DYWPRO,R0 ;R0-> THE WRITE PROTECT TABLE ADD R3,R0 ; POINT TO ENTRY MOVB (PC)+,(R0) ; AND SET IT THE WAY THE USER WANTS IT O.WPF: .BLKW 1 ; NOW TO ALTER THE IN-CORE COPY OF THE PROTECTION TABLE CALL FINDRV ;IS THE HANDLER LOADED? BCS O.GOOD ;NOPE... CMP @#SYSPTR,R1 ;Is this the system handler? BHI 10$ ; no, then leave 1-shot as is MOV #100000,DYW1-DYLQE(R1) ; yes, set it 10$: ADD R3,R1 ;ADD IN UNIT OFFSET MOVB O.WPF,DYWPRO-DYLQE(R1) ;SET THE WRITE-PROTECT STATUS BR O.GOOD .IIF GT,<.-1000> .ERROR ;SET CODE IS TOO LARGE .SBTTL DRIVER REQUEST ENTRY POINT .ENABL LSB .IF EQ MMG$T .DRBEG DY .IFF ;EQ MMG$T .DRBEG DY,SPFUN=UBTAB .ENDC ;EQ MMG$T DYBASE = DYSTRT+6 BR DYENTR ;Bypass some data to get to code DYWPRO: ; : DY Write protect table .REPT DYT$O+1 .BYTE 0,0 .ENDR ;DYT$O+1 .ASSUME . LE DYSTRT+1000 .IF NE ERL$G SCSFLG: .WORD 0 ; :SUCCESSFUL LOGGING FLAG (DEFAULT=YES) ; =0 - LOG SUCCESSES, ; <>0 - DON'T LOG SUCCESES .ASSUME . LE DYSTRT+1000 .ENDC ;NE ERL$G .IF NE DYT$O .DRVTB DY,DY$VEC,DYINT .DRVTB ,DY$VC2,DYINT .ASSUME . LE DYSTRT+1000 .ENDC ;NE DYT$O DYCSA: .WORD DY$CSR ; ; Controller base address .ASSUME . LE DYSTRT+1000 .IF NE DYT$O DYCSR: .WORD DY$CSR ; : First RX02 controller address .ASSUME . LE DYSTRT+1000 DYCSR2: .WORD DY$CS2 ; : Second RX02 controller address .ASSUME . LE DYSTRT+1000 .ENDC ;NE DYT$O DYENTR: MOV (PC)+,(PC)+ ;INITIALIZE RETRY COUNT DRETRY: .WORD RETRY ; :RETRY MAXIMUM .ASSUME . LE DYSTRT+1000 DYTRY: .WORD 0 ; :RETRY COUNT MOV DYCQE,R5 ;GET POINTER TO QUEUE ELEMENT MOV (R5)+,R3 ;GET BLOCK NUMBER MOV #CSGO!CSRD!CSINT,R4 ;GUESS THAT CONTROLLER FUNCTION IS READ MOVB (R5)+,R1 ;PICK UP SPECIAL FUNCTION CODE (SIGN EXTENDED) MOVB (R5)+,R0 ;PICK UP THE UNIT NUMBER BIC #^C<7>,R0 ; AND ISOLATE THE UNIT BITS MOV R0,R2 ;COPY IT FOR LATER ASR R0 ;SHIFT IT TO CHECK FOR ODD UNIT .IF EQ DYT$O BNE 5$ ;IF UNIT IS > 1, GIVE INSTANT ERROR .ENDC ;EQ DYT$O BCC 1$ ;OK IF EVEN UNIT BIS #CSUNIT,R4 ;SELECT ODD UNIT FOR TRANSFER 1$: .IF NE DYT$O MOV DYCSR,-(SP) ;Assume first RX02 controller ASR R0 ;Check for second controller BNE 49$ ;If DY4-7, error immediately BCC 2$ ;Correct controller... MOV DYCSR2,@SP ;Use second RX02 controller 2$: MOV (SP)+,DYCSA ;Set the controller base address .ENDC ;NE DYT$O ; IF USER TURNED ON THE DRIVE AFTER THE SYSTEM HAS BEEN TURNED ON, ; THE DONE BIT MIGHT NOT BE SET BECAUSE A RESET HAS NOT OCCURED. ; IF THIS IS THE CASE, A DRIVE INITIALIZE MUST BE ISSUED IN ORDER ; TO GET THINGS GOING. MOV DYCSA,R0 ;R2 -> RX02 CSR BIT #CSDONE,(R0) ;IS DONE BIT SET? BNE 22$ ;BRANCH IF SO MOV #CSINIT,(R0) ;INITIALIZE THE DRIVE 21$: BIT #CSDONE,(R0) ;WAIT FOR DONE BIT TO SET BEQ 21$ 22$: .IF EQ DY$DD ASL R2 ;DOUBLE UNIT NUMBER FOR WORD TABLE OFFSET .ADDR #SAVDEN,R2,ADD ; TABLE OF DENSITIES MOV R2,(PC)+ ;REMEMBER THE TABLE ADDRESS DENPTR: .WORD 0 ; : POINTER TO DENSITY TABLE BIS @R2,R4 ;START BY TRYING THE PREVIOUS DENSITY .IFF ;EQ DY$DD ; DRIVER IS DUAL DENSITY ONLY BIS #CSDN,R4 ;ALWAYS USE DOUBLE DENSITY CMPB R1,#SIZ$FN ;SPECIAL SIZE FUNCTION? BNE 3$ ;NO, CONTINUE .IF EQ MMG$T MOV #DDNBLK,@(R5)+ ;RETURN DOUBLE DENSITY SIZE .IFF ;EQ MMG$T MOV #DDNBLK,-(SP) ;RETURN DOUBLE DENSITY SIZE MOV DYCQE,R4 ;CURRENT QUEUE ELEMENT CALL @$PTWRD ;STORE SIZE IN BUFFER .ENDC ;EQ MMG$T JMP DYDONE ;DONE WITH SIZE OPERATION .ENDC ;EQ DY$DD 3$: .IF EQ MMG$T MOV (R5)+,R0 ;GET THE USER'S BUFFER ADDRESS .IFF ;EQ MMG$T CALL @$MPPTR ;CONVERT MAPPED ADDRESS TO PHYSICAL ADDRESS MOV (SP)+,R0 ;GET PHYSICAL BUFFER ADDRESS LOW ORDER BITS MOV R4,(PC)+ ;SAVE CURRENT COMMAND WORD 35$: .BLKW MOV (SP)+,R4 ;GET HIGH-ORDER ADDRESS BITS <21:18> BIT #1700,R4 ;22-BIT ADDRESS SPECIFIED? BNE. DYERR ;YES, NOT VALID FOR THIS CONTROLLER SWAB R4 ;MOVE TO CORRESPONDING POSITIONS IN HIGH BYTE BIS 35$,R4 ;NOW MERGE COMMAND WORD WITH EXTENSION BITS .ENDC ;EQ MMG$T MOV @R5,WRDCNT ;GET WORD COUNT BPL 4$ ;POSITIVE MEANS READ, SO ALL SET UP ; HERE TO CHECK IF UNIT IS WRITE-PROTECTED ASL (PC)+ ; CHECK WRITE ANYWAY ONE-SHOT DYW1: .WORD .-. ; 100000 MEANS WRITE ANYWAY .ASSUME . LE DYSTRT+1000 BCS 33$ ; SKIP TEST IF WRITE ANYWAY CLR -(SP) ;SET TO GET UNIT MOVB Q.UNIT-Q.WCNT(R5),(SP) ;GET IT (PLUS OTHER CRUFT BIC #<^C3>,(SP) ; WHICH WE DISCARD NOW) ;ADD ADDRESS OF WRITE-PROTECT TABLE .ADDR #DYWPRO,(SP),ADD; TO UNIT OFFSET TSTB @(SP)+ ;CHECK UNIT WRITE STATUS BNE. DYERR ; IT'S WRITE-PROTECTED, USER CAN'T DO THIS 33$: ADD #CSWRT-CSRD,R4 ;CHANGE CSRD TO CSWRT FOR WRITE NEG WRDCNT ; AND MAKE THE WORD COUNT POSITIVE 4$: ASL R1 ;DOUBLE THE SPECIAL FUNCTION CODE BEQ 6$ ;NOT SPECIAL, LEAVE R5 WITH AN ADDRESS MOV R1,R5 ;COPY THE SPECIAL FUNCTION CODE ADD PC,R1 ;FORM PIC REFERENCE TO CHGTBL ADD CHGTBL-.(R1),R4 ;MODIFY THE CODE, SET SIGN BIT IF SPFUN .IF EQ DY$DD SUB #377*400!SIZ$FN*2,R5 ;IS THIS A GET SIZE OPERATION? BEQ 7$ ;YES, NO SPECIAL SETUP, JUST DO READ STATUS .ENDC ;EQ DY$DD .IF EQ MMG$T CLR (R0)+ ;CLEAR DELETED DATA FLAG WORD .IFF ;EQ MMG$T MOV R4,-(SP) ;SAVE THE FUNCTION CODE MOV DYCQE,R4 ;R4 -> Q.BLKN OF QUEUE CLR -(SP) ;STORE A ZERO IN THE FIRST WORD OF BUFFER CALL @$PTWRD ;Q.BUFF IS NOW ORIGINAL +2 TST (R0)+ ;ADD 2 TO R0 ALSO. MOV (SP)+,R4 ;RESTORE THE FUNCTION CODE .ENDC ;EQ MMG$T BR 7$ ;NOW GO START 49$: TST (SP)+ ;Discard incorrect CSR 5$: JMP DYERR ;ISSUE ERROR 6$: ASL R3 ;NORMAL I/O, DOUBLE BLOCK NUMBER TO GET SECTOR TST @R5 ;TRYING TO DO A "SEEK"? BEQ DYDONE ;YES, TRASH IT .IF EQ DY$DD TST @R2 ;IS IT DOUBLE DENSITY? BNE 7$ ;YES, ALL SET UP NOW ASL R3 ;NO, SECTOR = BLOCK * 4 FOR SINGLE DENSITY .ENDC ;EQ DY$DD 7$: MOV R0,BUFRAD ;SAVE USER BUFFER ADDRESS (LOW 16 BITS) MOV R3,DYLSN ; AND SECTOR NUMBER MOV R4,(PC)+ ;SAVE THE FUNCTION CODE AND SPFUN FLAG DYFUN2: .WORD 0 ; : FUNCTION CODE AND SPFUN FLAG .IF EQ DY$DD MOV R5,(PC)+ ;SAVE THE FLAG FOR SIZE SPECIAL FUNCTION SIZFLG: .WORD 0 ; : 0 IF SIZE FUNCTION, ELSE <>0 .ENDC ;EQ DY$DD MOV #CSINT,R0 ;SET COMMAND TO CAUSE AN INTERRUPT CALL INWAIT ;GO TO FORK LEVEL AND START IT UP .BR DYINIT ;DO THE REAL WORK .DSABL LSB .SBTTL START TRANSFER OR RETRY .ENABL LSB DYINIT: .IF EQ DY$DD TST SIZFLG ;GETTING THE SIZE? BNE 4$ ;NOPE, MUST BE READ OR WRITE CALL INWAIT ;YES, DO THE READ STATUS FUNCTION BIT #ESDRY,(R5) ;DRIVE READY? (RX2ES) BEQ DYERR ;NOPE, SO WE CAN'T DETERMINE DENSITY MOV #DYDSIZ,-(SP) ;GUESS AT SINGLE DENSITY SIZE BIT #ESDN,@R5 ;IS THIS A SINGLE DENSITY FLOPPY? BEQ 3$ ;YES, WE ARE DONE ASL @SP ;DOUBLE SIZE FOR DOUBLE DENSITY 3$: .IF EQ MMG$T MOV (SP)+,@BUFRAD ;STORE THE SIZE IN THE USER'S BUFFER .IFF ;EQ MMG$T MOV DYCQE,R4 ;POINT TO QUEUE ELEMENT CALL @$PTWRD ;STORE THE SIZE IN THE USER'S BUFFER .ENDC ;EQ MMG$T BR DYDONE ;DONE WITH SIZE FUNCTION .ENDC ;EQ DY$DD 4$: .IF NE MMG$T MOV R0,DYFUN2 ;SAVE CSR FUNCTION WITH CORRECT ADDRESS .ENDC ;NE MMG$T BIT #1*2,R0 ;IS THIS A WRITE FUNCTION? BNE 5$ ;NO, IT IS A READ CALL DOSILO ;FOR WRITE, GO FILL THE SILO 5$: CALL DOXFER ;DO THE TRANSFER TO OR FROM THE DISKETTE BIT #1*2,R0 ;IS THIS A READ FUNCTION? BEQ 7$ ;NO, IT IS A WRITE TST R0 ;IS IT A SPECIAL FUNCTION READ? BPL 6$ ;ORDINARY READ, IGNORE DELETED DATA MARK BIT #ESDD,@R5 ;DELETED DATA MARK FOUND ON SPFUN READ? BEQ 6$ ;NOPE .IF EQ MMG$T MOV BUFRAD,R2 ;GET ADDRESS OF USER BUFFER AREA INC -(R2) ;SET FLAG WORD TO 1 TO INDICATE DELETED DATA .IFF ;EQ MMG$T MOV R4,R1 ;SAVE CSR ADDRESS MOV DYCQE,R4 ;POINT TO QUEUE ELEMENT MOV #1,-(SP) ;STACK A 1 TO PUT INTO FLAG WORD SUB #2,Q.BUFF-Q.BLKN(R4) ;MOVE BUFFER POINTER BACK TO FIRST WORD CMP Q.BUFF-Q.BLKN(R4),#20000 ;POINTER OUT OF THIS PAR'S RANGE? BHIS 55$ ;NOPE... ADD #20000,Q.BUFF-Q.BLKN(R4) ;YES...GET IT BACK IN RANGE, SUB #200,Q.PAR-Q.BLKN(R4) ; IN THE PREVIOUS PAR SUB #200,Q.MEM-Q.BLKN(R4) ; IN THE PREVIOUS PAR 55$: CALL @$PTWRD ;STORE IN 1ST WORD. Q.BUFF IS NOW ORIGINAL+2 MOV R1,R4 ;RESTORE R4 .ENDC ;EQ MMG$T 6$: CALL DOSILO ;FOR READ, EMPTY THE SILO INTO MEMORY 7$: TST R0 ;IS THIS A SPECIAL FUNCTION? BMI DYDONE ;IF SO, WE ARE DONE AFTER 1 TRANSFER MOV R3,R2 ;COPY THE SECTOR SIZE IN WORDS ASL R2 ;DOUBLE SECTOR SIZE TO GET BYTE COUNT ADD R2,(PC)+ ;UPDATE BUFFER ADDRESS BUFRAD: .WORD 0 ; : BUFFER ADDRESS .IF NE MMG$T BCC 8$ ;NO OVERFLOW, SO SAME 32K MEMORY BANK ADD #10000,R0 ;OVERFLOW INTO BITS 17:16 OF BUS ADDRESS .ENDC ;NE MMG$T 8$: INC (PC)+ ;BUMP LOGICAL SECTOR DYLSN: .WORD 0 ; : LOGICAL SECTOR NUMBER SUB R3,(PC)+ ;REDUCE THE NUMBER OF WORDS LEFT TO TRANSFER WRDCNT: .WORD 0 ; : WORD COUNT BHI 4$ ;BRANCH IF WE ARE NOT DONE BIT #1*2,R0 ;CHECK FOR READ OPERATION BNE DYDONE ;IF READ, WE ARE DONE NOW ; ZERO-FILL PARTIAL WRITES MOV #1,WRDCNT ;PREPARE TO ZERO-FILL BY SETTING COUNT TO 1 .IF EQ MMG$T .ADDR #ZERO,R3 ; FOR TRANSFER OF ONE ZERO WORD MOV R3,BUFRAD ;CHANGE BUFFER ADDRESS TO POINT TO ZERO .IFF ;EQ MMG$T BIC #30000,R0 ;CLEAR EXTENDED MEMORY BITS BIS BUFADH,R0 ;SET EXTENDED MEMORY BITS FOR UB MOV BUFADL,BUFRAD ;GET LOW ORDER ADDRESS .ENDC ;EQ MMG$T .IF EQ DY$DD MOV #3,R1 ;GET BIT MASK TO TEST FOR BLOCK DONE BIT #CSDN,R0 ;DOUBLE DENSITY WRITE? BEQ 9$ ;NO, LOGICAL SECTOR MUST BE A MULTIPLE OF 4 ASR R1 ;YES, LOGICAL SECTOR MUST BE EVEN 9$: BIT R1,DYLSN ;DONE ZERO FILLING THIS BLOCK? .IFF ;EQ DY$DD BIT #1,DYLSN ;DONE WITH THIS BLOCK? .ENDC ;EQ DY$DD BNE 4$ ;NOPE, GO BACK TO ZERO-FILL .SBTTL DONE WITH I/O, FINISH UP AND EXIT DYDONE: .IF NE ERL$G TST SCSFLG ;LOGGING SUCCESFUL TRANSFERS? BNE 10$ ;NOPE... MOV DYCQE,R5 ;CALL ERROR LOG ON SUCCESS. MOV #DY$COD*400+377,R4 ;R4 = ID/-1, R5 -> 3RD WORD CALL @$ELPTR ;OF QUEUE ELEMENT. .ENDC ;NE ERL$G ;* Floppy interrupts must be disabled by doing a bit clear of the ;* interrupt enable bit. Attempting to clear DYCSA will cause the ;* Drive Density bit (ESDN) in RXES to be cleared. The Drive ;* Density bit is used by RSX BRUSYS when booted from a floppy with ;* the BOOT/FOR command and must reflect the density of the last ;* floppy booted. 10$: BIC #,@DYCSA ;DISABLE FLOPPY INTERRUPTS ;AND INHIBIT DRIVE RESET 11$: .DRFIN DY ;GO TO I/O COMPLETION DYABRT: MOV DYCSA,-(SP) ;Get the controller base address MOV #CSINIT,@(SP)+ ;PERFORM AN RX11 INITIALIZE CLR DYFBLK+2 ;CLEAR FORK ADDRESS TO STOP A DISPATCH BR 11$ ; AND QUIT DYERR: MOV DYCQE,R4 ;R4 -> CURRENT QUEUE ELEMENT BIS #HDERR$,@-(R4) ;SET HARD ERROR IN CSW BR 10$ ;EXIT ON HARD ERROR .DSABL LSB .SBTTL INWAIT - START FUNCTION AND WAIT FOR INTERRUPT FROM FLOPPY ;+ ; INWAIT - START FUNCTION AND WAIT FOR AN INTERRUPT FROM THE FLOPPY ; ; R0 = FUNCTION CODE TO ISSUE ; ; JSR PC,INWAIT ; ; R0 = FUNCTION CODE OF ORIGINAL OPERATION ; R3 = SECTOR SIZE IN WORDS ; R4 -> CSR ; R5 -> CSR+2 ;- INWAIT: MOV (SP)+,INTRTN ;SAVE RETURN ADDRESS MOV R0,@DYCSA ;START THE REQUESTED FUNCTION RETURN ;RETURN, WE'LL BE BACK WITH AN INTERRUPT .SBTTL INTERRUPT ENTRY POINT .DRAST DY,5,DYABRT ;AST ENTRY POINT .FORK DYFBLK ;REQUEST FORK LEVEL IMMEDIATELY CALL SETDY ;SET UP REGISTERS BMI DYERR2 ;CHECK OUT THE ERROR, RETRY INTDSP: JMP @(PC)+ ;NO ERROR, RETURN TO CALLER INTRTN: .WORD 0 ; : ADDRESS OF WAITING ROUTINE .SBTTL ERROR HANDLING - CHANGE DENSITY, RETRY DYERR2: .IF EQ DY$DD ; IF WE SUPPORT BOTH DENSITIES, RECOVER FROM A DENSITY ERROR BIT #ESDNER,@R5 ;DENSITY ERROR? BEQ 5$ ;NO, SO NO FANCY RECOVERY MOV DENPTR,R2 ;POINT TO CURRENT DENSITY WORD BIC (R2)+,R0 ;TURN OFF DOUBLE BIT IF IT IS ON NEGB -(R2) ;TRICKY WAY TO CHANGE 1->0 ;SEC/CLC ;C=1 IF DENSITY WAS DOUBLE, NOW SINGLE INCB (R2)+ ; AND 0->1 BIS -(R2),R0 ;TURN ON DOUBLE BIT IF NOW ON BMI 4$ ;IF SPECIAL FUNCTION, DON'T DIDDLE SECTOR BCS 3$ ;REGULAR I/O, BRANCH IF NOW SINGLE ASR DYLSN ;SINGLE->DOUBLE, HALVE THE LOGICAL SECTOR BR 4$ ; AND CONTINUE 3$: ASL DYLSN ;DOUBLE->SINGLE, DOUBLE THE LOGICAL SECTOR # 4$: MOV R0,DYFUN2 ;SAVE THE CORRECT DENSITY CMP DYTRY,DRETRY ;1ST DENSITY ERROR? BNE 5$ ;NO, LOG IT CALL SETDY ;SET UP REGISTERS DEC DYTRY ;COUNT DOWN # OF RETRIES BEQ DYERR ;NONE LEFT - HARD ERROR BR 9$ ;GO TRY AGAIN BUT WITHOUT DOING AN INIT .ENDC ;EQ DY$DD ;DONE WITH DENSITY RECOVERY CODE 5$: ; LOG AN ERROR (OTHER THAN THE FIRST DENSITY ERROR) .IF NE ERL$G .ADDR #DYRBUF,R3 ; POINT TO LOCATION TO STORE REGISTER INFO. MOV R3,R2 ;R2 -> REGISTERS FOR ERROR LOGGER MOV @R4,(R3)+ ;STORE RXCS MOV @R5,(R3)+ ;STORE STATUS RXES MOV #CSMAIN!CSGO,@R4 ;READ THE ERROR REGISTER ;6$: BIT #CSDONE,@R4 ;WAIT FOR READ COMPLETION ; BEQ 6$ ; MOV @R5,@R3 ;STORE IN BUFFER 6$: BIT #CSTR,(R4) ;TR ASSERTED? BEQ 6$ ;NOT YET, WAIT FOR IT... MOV R3,(R5) ;YES, TELL WHERE TO DMA INFO 61$: BIT #CSDONE,(R4) ;DONE? BEQ 61$ ;NOT YET... MOV DRETRY,R3 SWAB R3 ADD #DYNREG,R3 ;R3 = MAX RETRIES/# OF REGS MOV DYCQE,R5 ;R5 -> QUEUE MOV DYTRY,R4 ;GET CURRENT RETRY COUNT (NOTE COUNT > 0) ADD #DY$COD*400-1,R4 ;R4 = DEVICE ID IN HIGH BYTE, COUNT-1 IN LOW CALL @$ELPTR ;CALL ERROR LOGGER MOV DYCSA,R4 ;RESTORE R4 = RXCS ADDRESS 7$: .ENDC ;NE ERL$G DEC DYTRY ;COUNT DOWN # OF RETRIES BEQ DYERR ;NONE LEFT - HARD ERROR ; DYTRY MUST BE DECREMENTED HERE ; BECAUSE 'CALL INWAIT' COULD CAUSE ; A RECURSIVE ENTRY TO DYERR2 IF ; DRIVE IS NOT POWERED UP. MOV #CSINIT,@R4 ;START AN INITIALIZE ... ; INIT FIRST CLEARS CSR SO KILL TIME ; BEFORE SETTING IE !!! MOV #CSINT,R0 ;SET UP R0 WITH IE MASK, THEN GO SET IE CALL INWAIT ; AND WAIT FOR INTERRUPT ... ; WILL COME BACK HERE WHEN INIT DONE 9$: JMP DYINIT ;GO TRY OPERATION AGAIN .SBTTL DOSILO - INITIATE A SILO FILL OR EMPTY COMMAND ;+ ; DOSILO - START A SILO DMA TRANSFER ; ; R0 = ORIGINAL COMMAND CODE ; R3 = SECTOR SIZE IN WORDS ; R4 -> CSR ; R5 -> CSR+2 ; ; JSR PC,DOSILO ; ; R1,R2 = RANDOM ; RETURNS AFTER INTERRUPT LATER ;- DOSILO: MOV (SP)+,INTRTN ;SAVE INTERRUPT RETURN ADDRESS MOV WRDCNT,R2 ;GET NUMBER OF WORDS LEFT IN TRANSFER BIC #6*2,R0 ;CHANGE READ/WRITE TO EMPTY/FILL COMMAND BPL 1$ ;COUNT IS RIGHT IF NOT SPECIAL FUNCTION MOV R3,R2 ;FOR SPFUN, WORD COUNT IS ALWAYS ONE SECTOR 1$: MOV R0,@R4 ;START IT ; NOTE: WHEN RUNNING ON AN LSI, 4.5 MICRO SEC MUST ELAPSE ; BETWEEN LOADING THE FUNCTION AND TESTING THE TRANSFER BIT CMP R3,R2 ;IS SECTOR SIZE SMALLER THAN WORD COUNT LEFT? BLOS 2$ ;YES, JUST READ A SECTOR MOV R2,R3 ;NO, READ ONLY REMAINING COUNT BEQ INTDSP ;FOR SEEKS, BYPASS THE SILO OPERATION 2$: MOV BUFRAD,R2 ;GET POINTER TO BUFFER .BR DYDOFN ;GO LOAD COUNT, ADDRESS, AND START IT .SBTTL DYDOFN - START A TRANSFER OR SILO OPERATION ;+ ; DYDOFN - START AN OPERATION WITH TWO LOADS, THEN WAIT ; ; R2 = SECOND VALUE TO LOAD (TRACK # OR ADDRESS) ; R3 = FIRST VALUE TO LOAD (SECTOR # OR WORD COUNT) ; R4 -> CSR ; R5 -> CSR+2 ; ; JSR PC,DYDOFN ; ; R0 = ORIGINAL FUNCTION CODE ; R3 = SECTOR SIZE IN WORDS ;- DYDOFN: BITB #CSTR!CSDONE,@R4 ;TRANSFERRED OR DONE? BEQ DYDOFN ;NOT YET BPL DYERR2 ;ERROR MOV R3,@R5 ;SECTOR NUMBER 1$: BITB #CSTR!CSDONE,@R4;TRANSFER OR DONE? BEQ 1$ ;NOT YET BPL DYERR2 ;ERROR MOV R2,@R5 ;TRACK NUMBER RETURN ;NOW WAIT FOR INTERRUPT .SBTTL DOXFER - START A SECTOR READ OR WRITE ;+ ; DOXFER - START A SECTOR READ OR WRITE ; ; R0 = CSR COMMAND ; R4 -> CSR ; R5 -> CSR+2 ; ; JSR PC,DOXFER ; ; R3 = SECTOR SIZE IN WORDS ;- DOXFER: MOV (SP)+,INTRTN ;SAVE INTERRUPT RETURN ADDRESS MOV R0,@R4 ;INITIATE FUNCTION ; NOTE: WHEN RUNNING ON AN LSI, 4.5 MICRO SEC MUST ELAPSE ; BETWEEN LOADING THE FUNCTION AND TESTING THE TRANSFER BIT MOV WRDCNT,R2 ;IF SPECIAL FUNCTION, R2 GETS ABSOLUTE TRACK MOV DYLSN,R3 ;GET LOGICAL SECTOR NUMBER TST R0 ;IS THIS A SPECIAL FUNCTION? BMI DYDOFN ;IF SO, DON'T INTERLEAVE MOV #8.,R2 ;LOOP COUNT 2$: CMP #26.*200,R3 ;DOES 26 GO INTO DIVIDEND? BHI 3$ ;BRANCH IF NOT, C CLEAR (BHI => BCC) ADD #-26.*200,R3 ;SUBTRACT 26 FROM DIVIDEND ;SEC ;C=1 FROM 'ADD' ABOVE 3$: ROL R3 ;SHIFT DIVIDEND AND QUOTIENT DEC R2 ;DEC LOOP COUNT BGT 2$ ;BRANCH TILL DIVIDE DONE MOVB R3,R2 ;COPY TRACK NUMBER CLRB R3 ;REMOVE TRACK NUMBER FROM REMAINDER SWAB R3 ;GET REMAINDER CMP #12.,R3 ;C=1 IF 13<=R3<=25, ELSE C=0 ROL R3 ;SECTOR*2 (2:1 INTERLEAVE) ; [+1 (C) IF SECTOR 13-25] ASL R2 ;DOUBLE THE TRACK NUMBER ADD R2,R3 ;SKEW THE SECTOR ADD R2,R3 ; BY ADDING IN ADD R2,R3 ; 6 * TRACK NUMBER ASR R2 ;UNDOUBLE THE TRACK NUMBER INC R2 ; AND MAKE IT 1-76 (SKIP TRACK 0 FOR ANSI) 4$: SUB #26.,R3 ;MODULO SECTOR INTO RANGE -26,-1 BGE 4$ ;LOOP TILL REMAINDER GOES NEGATIVE ADD #27.,R3 ;PUT SECTOR IN RANGE 1,26 BR DYDOFN ;START THE TRANSFER .SBTTL SETDY - SET UP REGISTERS ;+ ; SETDY - SET UP REGISTERS FOR GENERAL USE ; ; JSR PC,SETDY ; ; R0 = FUNCTION CODE OF ORIGINAL OPERATION ; R3 = SECTOR SIZE IN WORDS ; R4 -> CSR ; R5 -> CSR+2 ;- SETDY: MOV DYFUN2,R0 ;GET THE ORIGINAL COMMAND CODE MOV #128.,R3 ;GET SIZE OF SECTOR (DUAL DENSITY) .IF EQ DY$DD TST @DENPTR ;ARE WE AT DUAL DENSITY? BNE 1$ ;YES, GUESS WAS RIGHT ASR R3 ;SET SINGLE DENSITY SIZE 1$: .ENDC ;EQ DY$DD MOV DYCSA,R4 ;GET ADDRESS OF DY CONTROLLER MOV R4,R5 ;POINT R5 TO DY DATA BUFFER TST (R5)+ ;CHECK FOR ERROR, R5 -> DATA BUFFER ; WITH ERROR INFO. RETURN ;REGISTERS ARE SET .SBTTL TABLES, FORK BLOCK, END OF DRIVER ; THIS IS THE INTERNAL BUFFER THAT REQUIRES A PERMANENT UMR ; (YES, IT'S ONLY 1 WORD LONG) ZERO: .WORD 0 ;ZERO WORD FOR 0 SECTOR TRANSFER ; CHANGES TO CSR CODE FOR SPECIAL FUNCTIONS .IF EQ DY$DD .WORD CSRDST-CSRD+SPFUNC ;373: READ STATUS TO GET VOLUME .WORD 0 ;374: UNUSED BY THE RX02 .ENDC ;EQ DY$DD .WORD CSWRTD-CSRD+SPFUNC ;375: READ+GO -> WRITE DELETED+GO .WORD CSWRT-CSRD+SPFUNC ;376: READ+GO -> WRITE+GO .WORD CSRD-CSRD+SPFUNC ;377: READ+GO -> READ+GO CHGTBL: ; READ/WRITE GET SORTED OUT EARLIER .IF EQ DY$DD ; SAVED DENSITY OF PREVIOUS OPERATION ON UNIT (1 WORD PER UNIT) SAVDEN: .WORD CSDN,CSDN ;CONTROLLER 0, UNITS 0,1 .IF NE DYT$O .WORD CSDN,CSDN ;CONTROLLER 1, UNITS 0,1 .ENDC ;NE DYT$O .ENDC ;EQ DY$DD DYFBLK: .WORD 0,0,0,0 ;DY FORK QUEUE ELEMENT .IF NE ERL$G DYRBUF: .BLKW DYNREG ;ERROR LOG STORAGE FOR REGISTERS .BLKW 4 ;AREA FOR 'READ ERROR REG' DMA INFO .ENDC ;NE ERL$G .IF NE MMG$T ; DY INTERNAL VARIABLE DEFINITIONS $ENTPT: .WORD 0 ; POINTER TO $ENTRY TABLE $PNMPT: .WORD 0 ; POINTER TO $PNAME TABLE H2UB: .WORD 0 ; POINTER TO UBVECT DYSLOT: .WORD 0 ; DY'S OFFSET IN DEVICE TABLES DYENT: .WORD 0 ; DY'S $ENTRY TABLE ENTRY POINTER DYPNA: .WORD 0 ; DY'S $PNAME TABLE ENTRY POINTER DYILQE: .WORD 0 ; DY INTERNAL QUEUE LAST QEL POINTER DYICQE: .WORD 0 ; DY INTERNAL QUEUE FIRST QEL POINTER ; DEFINITION OF THE HANDLER INTERNAL BUFFER AND THE WORDS THAT ARE ; USED TO PROGRAM DMA DEVICES THAT TRANSFER DATA TO AND FROM IT. BUFADH: .WORD 0 ; BITS 0-15 OF UNIBUS VIRTUAL POINTER TO ZERO BUFADL: .WORD 0 ; BITS 16-21 OF UNIBUS VIRTUAL POINTER TO ZERO ;TABLE OF STANDARD DMA SPFUN'S THAT DO NOT HAVE A PERMANENT UMR UBTAB: .DRSPF -, ;375 - WRITE WITH DELETED DATA .DRSPF -, ;376 - WRITE ABSOLUTE SECTOR .DRSPF -, ;377 - READ ABSOLUTE SECTOR .WORD 0 ;TABLE TERMINATOR .ENDC ;NE MMG$T .SBTTL BOOTSTRAP READ ROUTINE .DRBOT DY,BOOT1,READ1 . = DYBOOT+40 ;PUT THE JUMP BOOT INTO SYSCOM AREA BOOT1: JMP @#BOOT-DYBOOT ;START THE BOOTSTRAP .ENABL LSB . = DYBOOT+210 UNTRED: .WORD CSGO+CSRD+CSDN ;READ COMMAND FOR UNIT 0 .WORD CSGO+CSRD+CSDN+CSUNIT ;READ COMMAND FOR UNIT 1 READ1: MOV @#B$DEVU,R3 ;GET UNIT BOOTED FROM BR 100$ ; READ: MOV BTUNIT,R3 ;GET UNIT BOOTED FROM 100$: ASL R3 ;MAKE IT A BYTE OFFSET MOV UNTRED-DYBOOT(R3),REDCMD ;LOAD PROPER READ COMMAND FUNCTION ; CONVERT LSN TO TRACK,SECTOR 1$: ASL R0 ;CONVERT BLOCK TO LOGICAL SECTOR 2$: MOV (PC)+,R5 ;R5 -> CS REGISTER ADDR BOTCSR: .WORD DY$CSR ; : DY CONTROL/STATUS REGISTER 200$: BIT #CSDONE,@BOTCSR ;WAIT FOR DONE BIT BEQ 200$ ;DONE BIT NOT SET YET MOV (PC)+,(R5)+ ;INITIATE READ FUNCTION REDCMD: .WORD 0 ;STORE READ COMMAND HERE MOV R0,-(SP) ;SAVE LSN FOR LATER MOV R0,R3 ;NEED 2 COPIES OF LSN FOR MAPPER MOV R0,R4 ; CLR R0 ;INIT FOR TRACK QUOTIENT BR 4$ ;JUMP INTO DIVIDE LOOP 3$: SUB #23.,R3 ;PERFORM TRACK DISPLACEMENT 4$: INC R0 ;BUMP QUOTIENT,STARTS AT TRACK 1 SUB #26.,R4 ;TRACK=INTEGER (LSN/26) BPL 3$ ;LOOP - R4=REM (LSN/26) - 26 CMP #-14.,R4 ;SET C IF SECTOR MAPS TO 1-13 ROL R3 ;PERFROM 2:1 INTERLEAVE 5$: SUB #26.,R3 ;ADJUST SECTOR INTO RANGE -1,-26 BPL 5$ ;(DIVIDE FOR REMAINDER ONLY) ADD #27.,R3 ; MOV BOTCSR,R4 ;GET CS ADDR CALL WAIT ;WAIT SUBROUTINE MOV R3,@R5 ;LOAD SECTOR INTO RXDB CALL WAIT ;WAIT MOV R0,@R5 ;LOAD TRACK INTO RXDB 6$: BIT #CSDONE,@R4 ;WAIT FOR DONE BEQ 6$ ;NOT YET TST @R4 ;ERROR DURING TRANSFER? BMI RTRY ;ERROR MOV (PC)+,(R4) ;INITIATE EMPTY BUFFER COMMAND EMTCMD: .WORD CSEBUF+CSGO+CSDN;STORE EMTY BUFFER COMMAND HERE MOV #64.,R3 ;GET WORD COUNDT THIS TRANSFER BIT #CSDN,EMTCMD ;DOUBLE DENSITY? BEQ 7$ ;NO ASL R3 ;YES,DEFAULT TO 128. WORDS 7$: CMP R1,R3 ;64. OR 128. WORDS LEFT? BHIS 8$ ;YES MOV R1,R3 ;NO- GET RESIDUAL COUNT 8$: CALL WAIT ;WAIT MOV R3,@R5 ;LOAD WORD COUNT CALL WAIT ;WAIT MOV R2,@R5 ;LOAD BUFFER ADDR 9$: BIT #CSDONE,@R4 ;DONE? BEQ 9$ ;NOT YET TST @R4 ;ERROR DURING TRANSFER? BMI RTRY ;ERROR MOV (SP)+,R0 ;RESOTRE LSN SUB R3,R1 ;REDUCE AMT LEFT TO XFER BLE 10$ ;DONE ADD R3,R2 ;UPDATE BUFFER ADDR ADD R3,R2 ; INC R0 ;UPDATE SECTOR # BR 2$ ;AND READ MORE WAIT: BITB #CSTR!CSDONE,@R4;TRANSFER OR DONE? BMI 11$ ;TRANSFER UP BEQ WAIT ;NOT YET RTRY: MOV (SP)+,R0 ;RESTORE LSN BITB #DNERR,@R5 ;DENSITY ERROR? BEQ BIOERR ;ERROR BIC #CSDN,REDCMD ;YES-CLEAR DOUBLE DEN BIT BIC #CSDN,EMTCMD ;IN READ AND EMPTY BUFFER BR 1$ ;TRY AGAIN 10$: CLC ;MAKE SURE THE CARRY BIT CLEAR BEFORE RETURN 11$: RETURN ;ALL DONE .DSABL LSB . = DYBOOT+576 BOOT: BIT #CSDONE,@BOTCSR ;WAIT FOR DONE BIT BEQ BOOT ;DONE BIT NOT SET YET MOV #10000,SP ;SET STACK POINTER MOV R0,(PC)+ ;STORE THE BOOTED UNIT NUMBER BTUNIT: .WORD 0 ;STORE LOCATION FOR BOOTED UNIT NUMBER MOV #2,R0 ;READ IN THE SECOND PART OF THE BOOT MOV #<4*400>,R1 ;EVERY BLOCK BUT THE ONE WE ARE IN MOV #1000,R2 ;STARTING AT LOCATION 1000 CALL READ ;GO READ IT IN MOV #READ1-DYBOOT,@#B$READ ;STORE START LOCATION FOR READ ROUTINE MOV #B$DNAM,@#B$DEVN ;STORE THE RAD50 DEVICE NAME MOV BTUNIT,@#B$DEVU ;AND THE BOOTED UNIT NUMBER JMP @#B$BOOT ;START SECONDARY BOOT .DREND DY .IF NE MMG$T .SBTTL FETCH/LOAD CODE ;+ ; ; FETCH ; ; ENTRY: R0 = STARTING ADDRESS OF THIS HANDLER SERVICE ROUTINE. ; R1 = ADRESS OF GETVEC ROUTINE. ; R2 = VALUE $SLOT*2. (LENGTH OF THE $PNAME TABLE IN BYTES.) ; R3 = TYPE OF ENTRY. ; R4 = ADDRESS OF SY READ ROUTINE. ; R5 -> $ENTRY SLOT FOR THIS HANDLER. ; ;- FETCH: MOV R5,R1 ; COPY ADDRESS OF DYLQE MOV @R1,R0 ; GET ADDRESS OF DYLQE MOV @#SYSPTR,R4 ; GET START OF RMON MOV $H2UB(R4),R3 ; R3 = UBVECT POINTER MOV R3,(R0) ; H2UB = ADDRESS OF UBVECT MOV $PNPTR(R4),R3 ; R3 = RMON OFFSET TO PNAME TABLE ADD R4,R3 ; R3 -> PNAME TABLE ADDRESS MOV R3,<$PNMPT-DYBASE>(R0) ; $PNMPT -> PNAME TABLE ADDRESS ADD R2,R3 ; R3 -> $ENTRY TABLE MOV R3,<$ENTPT-DYBASE>(R0) ; $ENTPT -> $ENTRY TABLE MOV R5,(R0) ; DYENT -> DY'S $ENTRY TABLE ENTRY SUB R2,R5 ; R5 -> DY'S $PNAME TABLE ENTRY MOV R5,(R0) ; DYPNA -> DY'S $PNAME TABLE ENTRY ; ALLOCATE PERMANENT UMRS TO POINT INTO DY'S INTERNAL DMA BUFFER, ; ZERO, AND GET THE UNIBUS VIRTUAL ADDRESS. MOV #,R1 ; R1 = LOW 16 BITS OF DMABUF ADDRESS ADD R0,R1 ; CLR R2 ; R2 = HIGH 6 BITS OF DMABUF ADDRESS MOV (R0),R4 ; R4 -> PNAME ENTRY FOR DY MOV (R0),R5 ; GET UB ENTRY ADDRESS MOV R0,-(SP) ; SAVE DY STARTING ADDRESS MOV #NOUMRS,R0 ; R0 = NUMBER OF UMRS REQUIRED CALL UB.ALL(R5) ; CALL ALLUMR MOV (SP)+,R0 ; RESTORE DY STARTING ADDRESS BCS 30$ ; COULDN'T GET UMR, FAIL THE LOAD MOV R1,(R0) ; STORE UNIBUS VIRTUAL ADDRESS LOW SWAB R2 ; MOVE HI BITS TO HI BYTE ASL R2 ; SHIFT ASL R2 ; HI BITS LEFT 4 ASL R2 ; TO GET THEM INTO THE ASL R2 ; CORRECT PLACE MOV R2,(R0) ; STORE UNIBUS VIRTUAL ADDRESS HIGH CLC ; LOAD SUCCEEDED 30$: RETURN .SBTTL RELEAS/UNLOAD code ;+ ; ; RELEAS ; ; ROUTINE TO UNLOAD DY ; ; ENTRY: SAME AS FOR LOAD. ; ;- .ENABL LSB RELEAS:: MOV R5,R1 ; R1 = $ENTRY SLOT FOR DY SUB R2,R1 ; R2 -> $PNAME SLOT FOR DY MOV @#SYSPTR,R4 ; GET START OF RMON MOV $H2UB(R4),R5 ; R5 = UB ENTRY VECTOR CALL UB.RLS(R5) ; RELEASE UMRS RETURN ; AND EXIT .ENDC ;NE MMG$T .END