.MCALL .MODULE .MODULE DD,VERSION=21,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 ; DD$PRI (4) Interrupt Priority ; 4-7 possible interrupt priorities ; ; DDT$O (0) two controller support ; 0 1 controller ; 1 2 controllers ; ; DD$CSR (176500) 1st controller CSR ; DD$VEC (300) 1st controller VECTOR ; ; DD$CS2 (176510) 2nd controller CSR ; DD$VC2 (310) 2nd controller VECTOR ; ; EIS$I (MMG$T) Use SOB instruction (no code effects!) ; 0 simulate SOB ; 1 use SOB ; ; MMG$T std conditional ; TIM$IT std conditional (no code effects) ; ERL$G std conditional ;- .SBTTL GENERAL COMMENTS .ENABL LC ;+ ; ABSTRACT FOR CODE FROM WHICH THIS WAS TAKEN: ; ; THIS MODULE MAY BE ASSEMBLED TO YIELD EITHER THE RAM PORTION OF A PDT ; DRIVER WITH PRIMITIVES IN ROM OR A MODULE TO BE LINKED WITH ANOTHER ; MODULE TO MAKE AN RT11 DRIVER FROM THE ROM PRIMITIVES. ; ; AUTHOR: ; ; BILL CLOGHER VERSION 1 ; DARRELL DUFFY VERSION 2 27-APR-78 ; ; MODIFIED BY: ; BARBARA DOERRE ; 23-AUG-78 SINGLE MODULE RT11 DRIVER ; DENISE LANGLAIS ; 29-JUN-79 REMOVE 'DEVICE DRIVER LIST' (R5) AND IMPURE AREA (R4) ; 1-AUG-79 ADD DUAL CONTROLLER CODE AND SET OPTIONS ;- .SBTTL MACROS AND DEFINITIONS .MCALL .DRDEF, .MTPS, .ASSUME .ADDR ; DD IS CONTROLLED VIA A SERIAL LINE OF DL TYPE ; CONTROL REGISTERS ARE THEREFORE A DL .IIF NDF DD$PRI DD$PRI = 4 ;STANDARD PRIORITY FOR DL .IIF NDF DDT$O DDT$O = 0 ;DEFAULT TO SINGLE CONTROLLER .IIF NDF DD$CS2 DD$CS2 = 176510 ;DEFAULT CSR FOR SECOND CONTROLLER .IIF NDF DD$VC2 DD$VC2 = 310 ;DEFAULT VECTOR .DRDEF DD,34,FILST$,512.,176500,300 .IIF EQ MMG$T .DRPTR .IIF NE MMG$T .DRPTR FETCH=*NO* .DREST CLASS=DVC.DK .IIF NDF EIS$I EIS$I = MMG$T .IIF EQ EIS$I .MCALL SOB ; USE SOB INSTRUCTION UNDER XM ;THE FOLLOWING LIST OF SYMBOLICS WERE DELETED SINCE ACCESS TO THE CSR'S ;IS THROUGH A LIST OF THEIR ADDRESSES (@TICSRA AS OPPOSED TO @#TI$CSR) ;TI$CSR =: DD$CSR ;INPUT CONTROL AND STATUS ;TI$BFR =: TI$CSR+2 ;INPUT BUFFER ;TO$CSR =: TI$CSR+4 ;OUTPUT CONTROL ;TO$BFR =: TI$CSR+6 ;OUTPUT BUFFER ;TI$VEC =: DD$VEC ;INPUT VECTOR ;TO$VEC =: TI$VEC+4 ;OUTPUT VECTOR CS$INT =: 100 ;CONTROL INTERRUPT ENABLE CS$BRK =: 1 ;CONTROL BREAK ENABLE ; ERROR LOG VALUES DDCNT =: 8. ;RETRY COUNT DDNREG =: 10. ;COUNT OF REGISTERS REPORT TO EL ; RADIAL SERIAL CODES ; LEVEL 2 CODES (OPCODE BYTE) R$$NOP =: 0 ;NO OPERATION R$$INT =: 1 ;INITIALIZE R$$RED =: 2 ;READ FUNCTION R$$WRT =: 3 ;WRITE OPERATION R$$POS =: 5 ;POSITION R$$END =: 100 ;END PACKET FROM PERIPHERAL ; LEVEL 1 CODES (FLAG BYTE) R$CONT =: 20 ;CONTINUE R$INIT =: 4 ;INIT PROTOCOL R$DATA =: 1 ;DATA PACKET R$MSG =: 2 ;MESSAGE PACKET R$MSIZ =: 10. ;MESSAGE PACKET SIZE R$DSIZ =: 128. ;MAX DATA PACKET SIZE FOR DD ; MMU REGISTERS KISAR1 =: 172342 ;KERNEL PAR1 ; RMON REFERENCES SYSPTR =: 54 ; SYSCOM pointer to RMON CONFG2 =: 370 ; second configuration word BUS$ =: 000100 ; PROS$ =: 020000 ; BUS$M =: BUS$!PROS$ ;Mask for type bits BUS$X =: BUS$!PROS$ ;Strange (busless) KXJ BUS$C =: PROS$ ;CTI bus BUS$Q =: BUS$ ;QBUS BUS$U =: 0 ;UNIBUS SYSCHN =: 17 ; system channel number .READ =: 375 ; EMT code for .READ/.WRITE .WRITE =: 375 ; EMT CODE FOR .READ/.WRITE ..READ =: 010 ; Subcode for .READ ..WRIT =: 011 ; Subcode for .WRITE .SBTTL INSTALLATION CODE .ASECT .IF NE DDT$O .DRINS DD, .IFF .DRINS DD .ENDC BR 1$ ;Data device installation check .ASSUME . EQ INSSYS BR 15$ ;System device installation check (none) 1$: MOV @#SYSPTR,R0 ; get address of RMON MOV CONFG2(R0),R0 ;Get configuration word for BUS check BIC #^C,R0 ;Isolate bus bits CMP #,R0 ;Running on KXJ? BNE 15$ ;Yes, go ahead and install CMP #,R0 ;CTI bus? BEQ 2$ ; yes, don't install 15$: TST (PC)+ ; clear carry, skip setting carry 2$: SEC ; set carry RETURN ; The EMT area for reading/writing the bootstrap is placed here ; to leave room for set option code. BAREA: .BYTE SYSCHN,..READ ;CHANNEL 17, READ .BLKW ;BLOCK NUMBER .BLKW ;BUFFER ADDRESS .WORD 256. ;WORD COUNT .WORD 0 ;COMPLETION (WAIT) O.RTR1: CMP R0,R3 ;ASKING FOR TOO MANY RETRIES? BHI O.BAD ;USER IS BEING UNREASONABLE... TST R0 ;WERE NON-ZERO RETRIES SPECIFIED? BEQ O.BAD ;CAN'T ASK FOR NO RETRIES MOV R0,DRETRY ;OKAY, SET IT BR O.GOOD O.SYWL: MOV @SP,R0 ; copy return address INC R0 ; point to opcode at return CMPB #BR/400,(R0)+ ; is it a BR xxx? BNE O.BAD ; NO, old style SET MOV R0,@SP ; use alternate return (RET+2) BR O.BAD ; with carry set .ASSUME . LE 400,MESSAGE=<;Install area too big> .SBTTL SET OPTIONS .DRSET CSR, 160000, O.CSR, OCT .DRSET VECTOR, 500, O.VEC, OCT .IF NE DDT$O .DRSET CSR2, 160000, O.CSR2, OCT .DRSET VEC2, 500, O.VEC2, OCT .ENDC ;NE DDT$O .DRSET RETRY, 127., O.RTRY, NUM .IF NE ERL$G .DRSET SUCCES, -1, O.SUCC, NO .ENDC ;NE ERL$G BTCSR = + + 1000 O.RTRY: BR O.RTR1 ; MOVED TO INSTALL AREA O.CSR: CMP R0,R3 ;CSR IN RANGE? (>160000) BLO O.BAD ;NOPE... MOV R0,INSCSR ;YES, INSTALLATION CODE NEEDS IT MOV R0,DISCSR ;AND SO DOES RESORC ; When the CSR for units 0 and 1 is changed, the bootstrap must ; be altered such that it will use the correct controller. ;R1->EMT AREA .ADDR #BAREA+4,R1 ; (BUFFER ADDRESS WORD) ;R2->READ/WRITE BUFFER .ADDR #1000,R2 ; (OVERWRITES CORE COPY OF BLOCK 1) MOV R2,(R1) ;SET THE BUFFER ADDRESS MOV #BTCSR/1000,-(R1) ; AND THE BOOT BLOCK TO READ/WRITE TST -(R1) ;R1->EMT AREA MOV R0,R3 ;SAVE CSR ELSEWHERE, EMT NEEDS R0 MOV R1,R0 ;R0->EMT AREA FOR READ EMT .READ ; *** (.READW) *** BCS O.BAD MOV R3,(R2) ;SET THE NEW CSR ADD #4,(R2) ; (+4) MOV R1,R0 ;R0->EMT AREA AGAIN .ASSUME ..READ+1 EQ ..WRIT INCB 1(R0) ;CHANGE FROM 'READ' TO 'WRITE' EMT .WRITE ; *** (.WRITW) *** BCS O.SYWL MOV R1,R0 ;R0->EMT AREA (LAST TIME, HONEST) .ASSUME ..WRIT-1 EQ ..READ DECB 1(R0) ;CHANGE BACK TO A 'READ' MOV #1,2(R0) ; OF BLOCK 1 OF HANDLER EMT .READ ; ** (.READW) *** BCS O.BAD .IF NE DDT$O MOV R3,SET$L1+2 ;SET NEW CSR FOR CREATING ADDR LIST .ENDC ;NE DDT$O ;GET ADDR OF CSR ADDRESS TABLE .ADDR #TICSRA,R1 ; IN A PIC FASHION MOV #2,R0 MOV R3,(R1)+ ;SAVE RCSR, ADD R0,R3 MOV R3,(R1)+ ; RBUF, ADD R0,R3 MOV R3,(R1)+ ; XCSR, ADD R0,R3 MOV R3,@R1 ; AND XBUF O.GOOD: TST (PC)+ ;GOOD RETURN (CARRY CLEAR) O.BAD: SEC ;BAD RETURN (CARRY SET) RETURN 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,VECTAB ;VECTOR ADDR TO DRIVER TABLE TST (R0)+ ;+2 FOR PSW .IF NE DDT$O MOV R0,SET$L2+2 ;SET VECTOR USED TO CREATE ADDR LIST .ENDC ;NE DDT$O ;GET POINTER TO TIVECA .ADDR #TIVECA,R1 ; IN A PIC FASHION MOV R0,(R1)+ ;STORE ADDR OF INPUT PSW TST (R0)+ ;+2 FOR OUTPUT VECTOR MOV R0,VECTAB+6 ;VECTOR ADDR TO DRIVER TABLE TST (R0)+ ;+2 FOR PSW MOV R0,@R1 ;STORE ADDR OF OUTPUT PSW RETURN .IF NE DDT$O O.CSR2: CMP R0,R3 ;CSR IN RANGE? (>160000) BLO O.BAD ;NOPE... MOV R0,SET$L3+2 ;CHANGE CSR USED TO CREATE ADDR LIST MOV R0,DISCS2 ;AND FOR RESORC RETURN O.VEC2: 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,VECTAB+14 ;VECTOR ADDR TO DRIVER TABLE TST (R0)+ ;+2 FOR PSW MOV R0,SET$L4+2 ;SET VECTOR USED TO CREATE ADDR LIST TST (R0)+ ; +2 FOR OUTPUT VECTOR MOV R0,VECTAB+22 ;VECTOR ADDR TO DRIVER TABLE BR O.GOOD .ENDC ;NE DDT$O .IF NE ERL$G O.SUCC: MOV #0,R3 ;'SUCCESS' ENTRY POINT ; (MUST TAKE UP TWO WORDS) N.SUCC: MOV R3,SCSFLG ;'NOSUCCESS' ENTRY POINT .ASSUME O.SUCC+4 EQ N.SUCC BR O.GOOD .ENDC ;NE ERL$G .Assume . LE 1000,MESSAGE=<;SET area too big> .SBTTL START I/O ENTRY .DRBEG DD CALL STARIO ;CALL START I/O - ONLY RETNS IF ERROR ERR1: MOV DDCQE,R4 ;ERROR, R4 -> CURRENT QUEUE ELEMENT .ASSUME Q$BLKN-2 EQ Q$CSW BIS #HDERR$,@-(R4) ;SET HARD ERROR BIT IN CSW BR PDEXIT ;EXIT ON HARD ERROR ; FOR SET OPTIONS TO ALLOW VECTORS TO BE CHANGED ; KEEP .DRVTB MACRO CALLS IN THIS ORDER VECTAB: .DRVTB DD,DD$VEC,DDINT .DRVTB ,DD$VEC+4,DDINT .ASSUME .-DDSTRT LE 1000 .IF NE DDT$O .DRVTB ,DD$VC2,DDINT .DRVTB ,DD$VC2+4,DDINT .ASSUME .-DDSTRT LE 1000 .ENDC ;NE DDT$O .IF NE ERL$G SCSFLG: .WORD 0 ; :SUCCESSFUL LOGGING FLAG (DEFAULT=YES) .ASSUME .-DDSTRT LE 1000 ; =0 - LOG SUCCESSES, ; <>0 - DON'T LOG SUCCESSES .ENDC ;NE ERL$G .SBTTL DD VECTOR AND CSR ADDRESS LIST ; NOTE: ; THIS LIST WAS CREATED TO IMPLEMENT THE DUAL CONTROLLER CODE, HOWEVER ; THE LIST DEFAULTS TO THE CORRECT ADDRESSES FOR A SINGLE CONTROLLER ; SINCE ALL REFERENCES TO THE CSR'S AND VECTORS ARE THROUGH THIS LIST. ; NOT ONLY IS THE ORDER CRITICAL BUT ALSO THE FACT THAT THIS LIST MUST ; BE LOCATED IN THE FIRST BLOCK OF THE HANDLER IN ORDER FOR THE SET ; OPTIONS TO WORK (I.E. KMON READS ONLY THE FIRST 2 BLOCKS FOR A SET ; COMMAND) ; *ORDER* TICSRA: .WORD DD$CSR TIBFRA: .WORD DD$CSR+2 TOCSRA: .WORD DD$CSR+4 TOBFRA: .WORD DD$CSR+6 TIVECA: .WORD DD$VEC+2 TOVECA: .WORD DD$VEC+6 ; *END ORDER* .ASSUME .-DDSTRT LE 1000 .SBTTL INTERRUPT ENTRY .ENABL LSB BR DDABRT DDINT:: BCS 1$ ;DON'T DO .INTEN IF C=1 ON INTERRUPT (SPEED) JSR R5,@$INPTR ;JUST LIKE THE .DRAST MACRO WOULD DO .WORD ^C&^O340 ;.DRAST DD,DD$PRI,DDABRT CLR (PC)+ ;CLEAR FORK FLAG - NEEDED FOR ERROR LOGGER FKFLG: .WORD 0 ;FLAG=0 UNTIL .FORK IS DONE JMP @I$INTR ;GO TO INTERRUPT SERVICE ; HIGH SPEED INTERRUPT ENTRY 1$: MOV R4,-(SP) ;SAVE R4 CALL @I$INTR ;CALL WHERE WE LEFT OFF MOV (SP)+,R4 ;RESTORE RTI ;RETURN FROM INTERRUPT .DSABL LSB .SBTTL INTERRUPT EXIT ;+ ; INIRTN - ENABLES THE INPUT INTERRUPT AND BRANCHES TO INPRTN ; SAME INPUT AND OUTPUT AS INPRTN ; ; OUTCHR - OUTPUTS THE CHARACTER PASSED IN R5 AND FALLS INTO OUTRTN ; SAME INPUT AND OUTPUT AS OUTRTN EXCEPT R5 ON ENTRY ; CONTAINS THE CHARACTER TO OUTPUT ; ; NOTE: TWO ENTRIES (OUTRTN, INPRTN) ARE IDENTICAL ; ; JSR PC,XXXRTN ; ; RETURN SAVED IN I$INTR ; RETURN FROM INTERRUPT ;- INIRTN: BIS #CS$INT,@TICSRA ;SET THE INPUT INTERRUPT BR INPRTN ;GO RETURN OUTCHR: MOV R5,@TOBFRA ;OUTPUT A CHARACTER OUTRTN: INPRTN: MOV (SP)+,I$INTR ;SAVE RETURN INTRTN: RETURN .SBTTL COMPLETION EXIT COMPLT: BCS ERR1 ;IF CS, ERROR .IF NE ERL$G TST FKFLG ;WAS A FORK DONE BNE 1$ ;IF NE, YES, OK TO GO TO ERROR LOGGER THEN CALL FORK ;NO, MUST BE AT FORK LEVEL FOR ERROR LOGGING 1$: TST SCSFLG ;LOGGING SUCCESSES? BNE PDEXIT ;NOPE... MOV #DD$COD*400+377,R4 ;SUCCESSFUL I/O - CALL ERROR LOGGER MOV DDCQE,R5 ;CALL ERROR LOGGER FOR SUCCESS CALL @$ELPTR .ENDC ;NE ERL$G PDEXIT: .DRFIN DD ;EXIT TO COMPLETION .SBTTL FORK ROUTINE ;+ ; FORK - DO A .FORK ; ; R0 - R3 = SAME AS WHEN INTERRUPT SERVICE ENTERED ; SP -> THE RETURN PC ; FKFLG = 0 (NO .FORK DONE YET) ; ; JSR PC,FORK ; ; R0 - R3 = AVAILABLE FOR USE ; R4, R5 = SAME AS WHEN FORK WAS CALLED ; STACK = UNSPECIFIED. GUARANTEED NOT TO BE SAME ; PRIORITY = 0 (FORK LEVEL) ; FKFLG <> 0 TO INDICATE A .FORK HAS BEEN DONE ;- FORK: MOV (SP)+,FKFLG ;SAVE RETURN, POPPING STACK, AND SET FORK FLAG MOV R0,-(SP) ;SAVE REGISTERS 0-3 MOV R1,-(SP) MOV R2,-(SP) MOV R3,-(SP) MOV FKFLG,-(SP) ;GET THE RETURN ADDRESS JSR PC,@(SP)+ ;CO-ROUTINE BACK TO IT MOV (SP)+,R3 ;RESTORE THE REGISTERS MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 RTS PC ;COMPLETE THE UN-WINDING .SBTTL DDABRT - ABORT ENTRY DDABRT::BIC #1,@TIVECA ;CLEAR ANY CARRY BITS SET IN BIC #1,@TOVECA ;THE INTERRUPT PSW .MTPS #340 ;RAISE PRIORITY TO PREVENT INTERRUPTS BIC #CS$INT,@TICSRA ;NO INPUT INTERRUPTS FOR NOW BIS #CS$INT,@TOCSRA ;SET UP OUTPUT INTERRUPT CLR (PC)+ ;CLEAR THE COUNT-DOWN WORD 5$: .BLKW 10$: MOV #R$INIT,R5 ;SEND INIT CALL OUTCHR ;OUTPUT IT DECB 5$ ;WAIT A REASONABLE AMOUNT OF TIME BEQ 15$ ; AND IF NO RESPONSE, GIVE UP TRYING ; TO LEAVE IN A KNOWN STATE (AS PER ; REPLY TO SPR #47883) TSTB @TICSRA ;INPUT CHAR READY YET? BPL 10$ ;NO,KEEP SENDING INITS CALL TXINIT ;LEAVE IN A KNOWN STATE 15$: BR PDEXIT ;EXIT NOW - DRFIN .SBTTL STARIO - START I/O CODE ;+ ; STARIO - START I/O CODE ; ; R0-R4 AVAILABLE ; ; JSR PC,STARIO ; ; INTERRUPTS ENABLED, ALL SETUP TO START TRANSFER ; ; RETURN TO CALLER ON COMMAND ERROR ; ELSE RETURN TO CALLER'S CALLER ;- .ENABL LSB STARIO::CLR PK$UNT ;ASSUME FIRST UNIT MOV DDCQE,R3 ;R3 -> QUEUE ELEMENT MOVB Q$UNIT(R3),R0 ;GET THE UNIT BYTE BIC #^C<7>,R0 ;CLEAR ALL BUT THE UNIT ASR R0 ;SHIFT IT TO CHECK FOR ODD UNIT .IF EQ DDT$O BNE 10$ ;IF UNIT > 1 ERROR .ENDC ;EQ DDT$O BCC 1$ ;OK IF EVEN UNIT INC PK$UNT ;SELECT ODD UNIT FOR TRANSFER 1$: .IF NE DDT$O SET$L1: MOV #DD$CSR,R3 ;ASSUME FIRST DD CONTROLLER SET$L2: MOV #DD$VEC+2,R2 ;CSR AND VECTOR .ASSUME .-DDSTRT LE 1000 ASR R0 ;SHIFT UNIT TO CHECK FOR SECOND CONTROLLER BNE 10$ ;IF UNIT WAS 4 TO 7 ERROR BCC 2$ ;FIRST CONTROLLER WAS RIGHT SET$L3: MOV #DD$CS2,R3 ;IT'S THE SECOND CONTROLLER SET$L4: MOV #DD$VC2+2,R2 ;CSR AND VECTOR .ASSUME .-DDSTRT LE 1000 2$: .ADDR #TICSRA,R1 ;POINT TO ADDRESS LIST CMP R3,@R1 ;IS THE LIST OF ADDRESSES OK AS IS? BEQ 4$ ;YES, DON'T BOTHER TO CHANGE AGAIN MOV #4,R0 ;NO, THERE ARE FOUR TO CHANGE 3$: MOV R3,(R1)+ ;STORE THE ADDRESSES IN THE TABLE TST (R3)+ ;THEY ARE LOCATED TOGETHER SO +2 SOB R0,3$ ;MORE? MOV R2,(R1)+ ;NOW STORE THE VECTOR PSW LOCATIONS CMP (R2)+,(R2)+ ;ADD FOR THE OUTPUT VECTOR PSW ADDR MOV R2,@R1 4$: .ENDC ;NE DDT$O DRETRY = .+2 MOV #DDCNT,I$ERCT ;COMM RETRY COUNT .ASSUME .-DDSTRT LE 1000 CLR RETIO ;CLEAR THE RETRY I/O FLAG TST I$ABRT ;DO WE NEED TO ABORT THE TX? BNE RETRY ;NO OK ITS DONE INC I$ERCT ;1 RETRY REQUIRED TO INIT .ADDR #ABORT,R1 ;POINT TO ABORT BR GO ;AND START THE BALL ROLLING RETRY: MOV DDCQE,R3 ;R3 -> QUEUE ELEMENT TST RETIO ;IS I/O BEING RETRIED ? BEQ 7$ ;NO, CONTINUE ADD #Q$WCNT,R3 ;POINT AT THE WORD COUNT MOV @R3,R1 ;PICK UP THE WORD COUNT BPL 5$ ;BRANCH IF IT'S READ NEG R1 ;MAKE WORD COUNT POSITIVE 5$: ASL R1 ;MAKE IT A BYTE COUNT SUB I$BYTC,R1 ;COMPUTE NUMBER OF BYTES TRANSFERED ROR R1 ;MAKE IT WORD COUNT CLRB R1 ;ROUND DOWN TO A BLOCK MULTIPLE MOV R1,R2 ;COPY IT TST @R3 ;IS WORD COUNT POSITIVE? BPL 6$ ;YES, SUBTRACT #WORDS TRANSFERRED NEG R1 ;NO, ADD #WORDS TRANSFERRED 6$: SUB R1,@R3 ;UPDATE THE WORD COUNT .IF EQ MMG$T .ASSUME Q$WCNT-2 EQ Q$BUFF ADD R2,-(R3) ;UPDATE THE BUFFER ADDRESS ADD R2,@R3 ;TWICE FOR CORRECT ADDRESS .ASSUME Q$BUFF-2 EQ Q$FUNC TST -(R3) ;POINT AT THE Q$FUNC .IFF MOV R2,R1 ;COPY THE WORD COUNT ASHC #-5,R1 ;SHIFT IT RIGHT TO GET 32W UNIT COUNT ADD R1,Q$PAR-Q$WCNT(R3) ;UPDATE THE BUFFER ADDRESS .ASSUME Q$WCNT-4 EQ Q$FUNC CMP -(R3),-(R3) ;BACK OFF THE QUEUE ELEMENT POINTER .ENDC ;EQ MMG$T SWAB R2 ;GET THE NUMBER BLOCKS TRANSFERRED .ASSUME Q$FUNC-2 EQ Q$BLKN ADD R2,-(R3) ;UPDATE THE BLOCK NUMBER 7$: MOV #R$$RED,PK$OPC ;GUESS READ OP, CLEAR MODIFIER BYTE CLRB PK$SSQ ;CLEAR UP UNUSED STUFF CLR PK$SSQ+1 ;SINCE TX DOES NOT USE IT MOV Q$WCNT(R3),R1 ;GET WORD COUNT BPL 8$ ;POSITIVE MEANS READ MOVB #R$$WRT,PK$OPC ;MAKE IT WRITE NEG R1 ; AND MAKE A POSITIVE WORD COUNT 8$: ASL R1 ;MAKE BYTE COUNT BNE 9$ ;NORMAL I/O MOVB #R$$POS,PK$OPC ;COUNT=0 => SEEK, FUNCTION IS POSITION 9$: MOV Q$BUFF(R3),I$ADRS ;ADDRESS FOR TRANSFER .IF NE MMG$T MOV Q$PAR(R3),I$PAR ;SAVE PAR VALUE, TOO .ENDC ;NE MMG$T MOV R1,I$BYTC ;SAVE BYTE COUNT MOV R1,PK$BCT ;COPY BYTE COUNT INTO PACKET MOV @R3,PK$RCD ;STORE BLOCK NUMBER IN COMMAND PACKET .ADDR #TXGO,R1 ;MAKE THE ADDRESS OF THE TRANSFER START GO: MOV R1,I$INTR ;OUTPUT SIDE STARTS US BIS #CS$INT,@TOCSRA ;OUTPUT INTERRUPTS TST (SP)+ ;RETURN DIRECT TO MONITOR 10$: RETURN ;ERROR RETURN TO SKELETON .DSABL LSB .SBTTL TXGO - START TRANSFER FROM INTERRUPT LEVEL ;+ ; TXGO - START TRANSFER ; ; JMP TXGO ; ; TRANSFER TO COMPLETION OR ERROR ENTRY ;- TXGO: CALL FORK ;ENTER FORK STATE MOV #R$MSG,PK$FLG ;MESSAGE TYPE TO FLAG BYTE MOV #R$MSIZ,R2 ;MESSAGE SIZE FOR PACKET ;GET ADDRESS OF MESSAGE .ADDR #PK$OPC,R1 ;OPCODE IS FIRST BYTE CALL SNDPKT ;SEND A PACKET TO START IO 1$: CMPB PK$OPC,#R$$WRT ;IS IT A WRITE? BNE 2$ ;NO JSR R5,RCVPKT ;IF WRITE, RECEIVE THE CONTINUE PACKET .WORD R$CONT ;EXPECTED A CONTINUE 2$: MOV I$ADRS,R1 ;GET THE DATA ADDRESS MOV I$BYTC,R2 ; AND THE BYTE COUNT BEQ TXEND ;NO BYTES => POSITION (GET END PACKET) CMP R2,#R$DSIZ ;TOO LARGE FOR ONE PACKET? BLOS 3$ ;NOPE, USE THIS COUNT MOV #R$DSIZ,R2 ;REDUCE TO A SINGLE PACKET TRANSFER 3$: CMPB PK$OPC,#R$$WRT ;WRITE? BNE 4$ ;NO MOVB #R$DATA,PK$FLG ;YES, SET UP DATA FLAG CALL SNDPKT ;SEND DATA PACKET CMP I$BYTC,#R$DSIZ ;MORE LEFT TO DO? BLOS TXEND ;NO, FINISH UP JSR R5,RCVPKT ;YES, RECEIVE THE NEXT CONTINUE PACKET .WORD R$CONT ;EXPECT A CONTINUE BR 5$ ;GO SEND THE NEXT DATA PACKET 4$: JSR R5,RCVPKT ;READ, RECEIVE A DATA PACKET .WORD R$DATA ;EXPECT A DATA FLAG 5$: .IF EQ MMG$T ADD #R$DSIZ,I$ADRS ;ADJUST THE ADDRESS .IFF ADD #2,I$PAR ;ADJUST THE PAR BIAS TO UPDATE THE ADDR .ENDC ;EQ MMG$T SUB #R$DSIZ,I$BYTC ;COUNT ONE PACKET FROM THE WORD COUNT BHI 2$ ;STILL MORE TO GO CLR I$BYTC ;ALL HAS BEEN TRANSFERRED .SBTTL TXEND - READ THE END PACKET AFTER A TRANSFER TXEND: ;POINT TO THE MESSAGE PACKET .ADDR #I$MBFR,R1 ; BY THE PIC METHOD MOV #R$MSIZ,R2 ;THE SIZE OF A MESSAGE JSR R5,RCVPKT ;GET A PACKET .WORD R$MSG ;EXPECT A MESSAGE PACKET .SBTTL ERROR - ANALYZE AN END PACKET ERROR: CMPB PK$FLG,#R$MSG ;MESSAGE PACKET? BNE ABORTR ;NO, PROTOCOL SCREWUP, TRY REINITIALIZING CMPB I$MOPC,#R$$END ;END PACKET? BNE ABORTR ;NO, ERROR TSTB I$MSUC ;CHECK FOR SUCCESS .IF EQ ERL$G BPL CPLRTN ;OK, SO COMPLETE WITHOUT ERROR .IFF BEQ CPLRTN ;OK, SO COMPLETE WITHOUT ERROR BLT FATAL ;FATAL ERROR MOV I$ERCT,R2 ;DATA IS OK, BUT LOG CONTROLLER RETRIES CALL LOGERR ;LOG THE RETRY ATTEMPT BR CPLRTN ;NOW YOU CAN RETURN .ENDC ;EQ ERL$G FATAL: TST FKFLG ;FORK DONE? BNE 1$ ;YES, COMPLETE WITH AN ERROR CALL FORK ;ELSE GO TO FORK LEVEL .IF NE ERL$G CLR R2 ;INDICATE FATAL I/O ERROR CALL LOGERR ;LOG THE HARD ERROR .ENDC ;NE ERL$G 1$: SEC ;SET C FOR FATAL ERROR CPLRTN: BIC R4,R4 ;ZERO R4 BIC #CS$INT,@TICSRA ;ZAP INTERRUPT ENABLE BIC #CS$INT,@TOCSRA ;ON BOTH SIDES JMP COMPLT ;*C* GO TO COMPLETION EXIT .SBTTL ABORT - COMMUNICATIONS ERROR ABORTR: MOV SP,(PC)+ ;INDICATE I/O RETRY IN PROGRESS RETIO: .WORD 0 ;RETRY I/O INDICATOR ABORT: CALL TXINIT ;ABORT THE TRANSFER CLR I$ABRT ;ABORT IS NEEDED (ASSUME) TST I$ERCT ;TRIED ALL WE CAN? BLE FATAL ;YES- NO MORE TRIES INC I$ABRT ;NO IT WORKED THIS TIME MOV R3,-(SP) ;SAVE MOV R2,-(SP) ; ALL MOV R1,-(SP) ; IMPORTANT MOV R0,-(SP) ; REGISTERS CALL 9$ ;CALL SIMULATES MONITOR CALL TO STARTIO MOV (SP)+,R0 ;RESTORE MOV (SP)+,R1 ; ALL MOV (SP)+,R2 ; IMPORTANT MOV (SP)+,R3 ; REGISTERS RETURN ;RETURN FROM INTERRUPT 9$: CALL RETRY ;RETRY ENTRY IN MAIN START CODE TST (SP)+ ;DUMP NEXT RETURN TO CLEAN STACK MOV (SP)+,R0 ;RESTORE MOV (SP)+,R1 ; ALL MOV (SP)+,R2 ; IMPORTANT MOV (SP)+,R3 ; REGISTERS BR FATAL ;RETURN HERE IS FATAL .IF NE ERL$G .SBTTL LOGERR - SET UP AND CALL ERROR LOGGER ;+ ; R2 > 0 => RETRY ATTEMPT (SOFT ERROR) ; = 0 => HARD ERROR ; ; JSR PC,LOGERR ; ; ALL REGISTERS RESTORED ;- LOGERR: MOV R2,R4 ;R4 LOB = CURRENT RETRY COUNT BIS #DD$COD*400,R4 ;R4 HOB = DEVICE ID CODE MOV DRETRY,R3 SWAB R3 ADD #DDNREG,R3 ;R3=MAX RETRIES/NUMBER OF REGISTERS ;FORM THE ADDRESS OF THE REGISTER .ADDR #I$LCHR,R2 ;BUFFER IN R2 MOV DDCQE,R5 ;LOG THE ERRORS CALL @$ELPTR CLR I$LCHR ;CLEAR FOR NEXT TIME RETURN ;NO NEED TO RESTORE REGISTRS .ENDC ;NE ERL$G .SBTTL TXINIT - INIT THE TU58 ; TXINIT - INITILIZE THE TU58 ; ; IF A CHECKSUM ERROR OCCURS, AN UNEXPECTED PACKET TYPE IS RECEIVED, ; OR SOMETHING ELSE HAPPENS WHICH INDICATES THE TRANSMISSION LINE ; OR PROTOCOL IS OUT OF SYNC, WE SEND RADIAL SERIAL 'SIGNAL' TO THE DD ; ('SIGNAL' IS BREAK STATE ON THE COMM LINE). ; WE TIME BREAK WITH TWO NULL CHARS, THEN SEND TWO INIT CHARS ; AND WAIT FOR A CONT FLAG TO SAY WE ARE IN SYNC. ; IF THINGS ARE REALLY SCREWED UP, THIS COULD OCCUR FOREVER. ; TO AVOID THIS, IF 8 ATTEMPTS ARE MADE TO SIGNAL THE DD ; DURING ONE TRANSFER, WE QUIT AND RETURN A HARD ERROR. ;- TXINIT: BIC #CS$INT,@TOCSRA ;SET UP KNOWN STATE BIC #CS$INT,@TICSRA MOV (SP)+,I$SUBR ;SAVE SUBROUTINE RETURN 1$: .IF NE ERL$G TST I$ABRT ;FORCED ABORT ? BEQ 2$ ;YES, DON'T LOG AN ERROR TST FKFLG ;AT FORK LEVEL FOR ERROR LOGGING ? BNE 3$ ;YES, DON'T FORK AGAIN CALL FORK ;FORK 3$: MOV I$ERCT,R2 ;SET UP THE RETRY COUNT CALL LOGERR ;LOG THE RETRY ATTEMPT 2$: .ENDC ;NE ERL$G .MTPS #340 ;RAISE PRIORITY TO PREVENT INTERRUPT MOV #177777,@TOBFRA ;;;SEND ONES FOR TIMING BIS #,@TOCSRA ;;;SET BREAK AND INTERRUPT ENABLE CALL OUTRTN ;;;OUTPUT WAIT MOV #177777,R5 ;SEND RUBOUT FOR TIMING CALL OUTCHR ; AND WAIT ON IT BIC #CS$BRK,@TOCSRA ;SHUT OFF BREAK MOV #R$INIT,R5 ;SEND AN INIT CALL OUTCHR ; AND WAIT ON IT MOV #R$INIT,R5 ;TRY TWO JUST IN CASE CALL OUTCHR ; AND WAIT ON THE SECOND BIC #CS$INT,@TOCSRA ;TURN OFF OUTPUT INTERRUPTS TST @TIBFRA ;DUMP THE INPUT CHARACTER TO CLEAR READY CALL INIRTN ;NOW WAIT FOR THE ANSWER MOV @TIBFRA,PK$FLG ;GET THE FLAG BIC #CS$INT,@TICSRA ;NO MORE INPUT INTERRUPTS DEC I$ERCT ;TOO MANY TIMES? BLE 9$ ;YES, BAD LINE OR BAD DEVICE CMPB PK$FLG,#R$CONT ;IS IT CORRECT? BNE 1$ ;TRY AGAIN 9$: CALLR @I$SUBR ;RETURN FROM THIS SUBROUTINE .SBTTL SNDPKT - SEND RADIAL SERIAL PACKET ;+ ; SNDPKT - SEND RADIAL SERIAL PACKET ; ; R1 -> DATA ; R2 = BYTE COUNT ; PK$FLG = FLAG BYTE ; ENTRY IN FORK STATE ; ; JSR PC,SNDPKT ; ; R0,R3 = UNDEFINED ; PACKET SENT ; OUTPUT INTERRUPT DISABLED ; EXIT IN FORK STATE ;- SNDPKT: MOV (SP)+,I$SUBR ;SAVE SUBROUTINE RETURN MOV R1,I$MADR ;SAVE ADDRESS MOVB R2,PK$MBC ;SAVE BYTE COUNT IN PACKET MOV PK$FLG,PK$CKS ;INITILIZE CHECKSUM .MTPS #340 ;NO INTERRUPTS MOVB PK$FLG,@TOBFRA ;;;OUTPUT FIRST BYTE (FLAG) BIS #CS$INT,@TOCSRA ;;;ENABLE INTERRUPTS CALL OUTRTN ;;;WAIT FOR OUTPUT INTERRUPT MOVB PK$MBC,R5 ;OUTPUT MESSAGE BYTE COUNT CLRB I$TDAT+1 ;CLEAR THE HIGH BYTE OF TEMP WORD BIS #1,@TOVECA ;SET CARRY => NO .INTEN CALL OUTCHR ;AND WAIT FOR INTERRUPT 2$: .IF NE MMG$T MOV @#KISAR1,-(SP) ;SAVE OLD PAR1 MOV I$PAR,@#KISAR1 ;USE OUR OWN VALUE .ENDC ;NE MMG$T MOVB @I$MADR,@TOBFRA ;OUTPUT DATA BYTE MOVB @I$MADR,I$TDAT ;STORE THE BYTE JUST OUTPUT .IF NE MMG$T MOV (SP)+,@#KISAR1 ;RESTORE SAVED PAR1 .ENDC ;NE MMG$T INC I$MADR ;NEXT ADDRESS ADD I$TDAT,PK$CKS ;ADD IT TO THE CHECKSUM ADC PK$CKS ;END AROUND CARRY SWAB PK$CKS ;SWAP CKECKSUM FOR ODD BYTE DECB PK$MBC ;ARE WE DONE? BEQ 3$ ;YES, TIME TO CLEAR THE CARRY RETURN ;NO, KEEP ON SENDING THOSE CHARACTERS FAST 3$: BIC #1,@TOVECA ;CC => DO INTEN ADD #4$-2$,I$INTR ;SET UP THE RETURN ADDRESS RETURN ;GO BACK THE WAY YOU CAME 4$: MOVB PK$CKS,R5 ;OUTPUT CHECKSUM CALL OUTCHR ;TIL OUT MOVB PK$CKS+1,R5 ;HO HUM CALL OUTCHR ;TIL GONE BIC #CS$INT,@TOCSRA ;CLEAR INTERRUPTS, FALL THROUGH TO RETURN PKT ; PACKET ROUTINE RETURN PKTRTN: CALL FORK ;USING SKELETON DRIVER CALLR @I$SUBR ;AND RETURN FROM SUBROUTINE .SBTTL RCVPKT - RECEIVE A RADIAL SERIAL PACKET ;+ ; RCVPKT - RECEIVE A RADIAL SERIAL PACKET ; ; R1 -> DATA AREA ; R2 = BYTE COUNT ; I$EFLG EXPECTED FLAG BYTE ; ENTERED IN FORK STATE ; ; JSR PC,RCVPKT ; ; R0-R3 = UNDEFINED ; PK$FLG = FLAG RECEIVED ; I$MBFR = PACKET IF NOT EXPECTED TYPE UNLESS ; DATA PACKET IN WHICH CASE ABORT IS ENTERED ; EXIT IN FORK STATE ;- RCVPKT: MOV (R5)+,I$EFLG ;SAVE THE EXPECTED FLAG MOV R5,I$SUBR ;SAVE SUBROUTINE RETURN MOV (SP)+,R5 ;RESTORE R5 MOV R1,I$MADR ;PACKET ADDRESS SPACE .MTPS #340 ;LOCK OUT INTERRUPTS CALL INIRTN ;;;AND COME BACK HERE MOV @TIBFRA,R4 ; SAVE THE CHAR AND THE OVERRUN ERROR BMI 6$ ; ERROR ABORT THE TRANSFER MOVB R4,PK$FLG ; SAVE THE CHAR FOR A FLAG CMPB R4,I$EFLG ;FLAG EXPECTED? BEQ 2$ ;YES- OK CMPB R4,#R$MSG ;MESSAGE PACKET ? BNE 6$ ;NO, THEN UNEXPECTED ERROR .ADDR #I$MBFR,-(SP) ;MAKE ADDRESS OF MESSAGE BUFFER MOV (SP)+,I$MADR ;TO MESSAGE ADDRESS 2$: CMPB R4,#R$CONT ;CONTINUE FLAG? BEQ PKTRTN ;YES - NO MORE DATA NOW BIS #1,@TIVECA ;CS => NO .INTEN CALL INPRTN ;WAIT ON A CHAR 1$: MOV @TIBFRA,R4 ; SAVE THE CHAR AND THE OVERRUN ERROR BMI 8$ ; ERROR ABORT THE TRANSFER MOVB R4,PK$MBC ;IT'S THE MESSAGE COUNT MOV PK$FLG,PK$CKS ;INITIALIZE THE CHECKSUM ADD #4$-1$,I$INTR ;SET UP NEW RETURN 3$: RETURN ;RETURN FROM INTERRUPT 4$: MOV @TIBFRA,R4 ;SAVE THE CHAR AND OVERRUN ERROR BMI 8$ ;ERROR ABORT THE TRANSFER .IF NE MMG$T MOV @#KISAR1,-(SP) ;SAVE CURRENT PAR1 MOV I$PAR,@#KISAR1 ;USE OUR OWN VALUE .ENDC ;NE MMG$T MOVB R4,@I$MADR ;STORE THE DATA IN BUFFER .IF NE MMG$T MOV (SP)+,@#KISAR1 ;RESTORE PREVIOUS PAR1 .ENDC ;NE MMG$T INC I$MADR ;NEXT ADDRESS BIC #^C<377>,R4 ;INTERESTED ONLY IN BYTE ADD PK$CKS,R4 ;ADD IN THE CURRENT CHECKSUM ADC R4 ;ADD IN END AROUND CARRY SWAB R4 ;SWAP CHECKSUM BYTES FOR NEXT CHAR MOV R4,PK$CKS ;SAVE CHECKSUM DECB PK$MBC ;ANY MORE BYTES? BNE 3$ ;YES, GO GET 'EM BIC #1,@TIVECA ;DO .INTEN NEXT INTERRUPT ADD #7$-4$,I$INTR ;SET UP NEW RETURN POINT RETURN ;GO BACK THE WAY YOU ENTERED INTERRUPT 7$: MOV @TIBFRA,R4 ; SAVE THE CHAR AND THE OVERRUN ERROR BMI 6$ ; ERROR ABORT THE TRANSFER MOVB R4,I$TDAT ; GET THE LOW BYTE FIRST CALL INPRTN ;HIGH BYTE NEXT MOV @TIBFRA,R4 ; SAVE THE CHAR AND THE OVERRUN ERROR BMI 6$ ; ERROR ABORT THE TRANSFER MOVB R4,I$TDAT+1 ; SAVE IT BIC #CS$INT,@TICSRA ;NO MORE INTERRUPTS CMP I$TDAT,PK$CKS ;IS IT CORRECT? BNE 5$ ;CHECKSUM ERROR CMPB PK$FLG,I$EFLG ;FLAG WE EXPECTED? BEQ PKTRTN ;YES OK GO TO COMMON RETURN JMP ERROR ;NO SIGNAL ERROR 6$: .IF NE ERL$G MOV R4,I$LCHR ;STORE THAT LAST CHAR IN ERROR .ENDC ;NE ERL$G 5$: JMP ABORTR ;NOPE- FATAL ERROR 8$: .IF NE ERL$G MOV R4,I$LCHR ;SAVE THE CHAR IN ERROR .ENDC ;NE ERL$G ; GET OUT FROM INTERRUPT LEVEL BIC #1,@TIVECA ;CLEAR CARRY .ADDR #ABORTR,-(SP) ;TO ABORT MOV (SP)+,I$INTR ;AS RETURN RETURN .SBTTL DATA AREA ; *ORDER* SOME CODE DEPENDS ON THE CURRENT ORDERING OF THIS DATA I$ABRT: .WORD 0 ;ZERO FOR ABORT REQUIRED ON STARTUP I$ADRS: .WORD 0 ;ADDRESS OF DATA I$BYTC: .WORD 0 ;BYTE COUNT FOR DATA I$INTR: .WORD 0 ;INPUT INTERRUPT RETURN I$ERCT: .WORD 0 ;ERROR RETRY COUNT (COMMUNICATIONS) I$MADR: .WORD 0 ;MESSAGE ADDRESS I$TDAT: .WORD 0 ;MESSAGE TEMP DATA I$SUBR: .WORD 0 ;SUBROUTINE RETURN ADDRESS .IF NE ERL$G I$LCHR: .WORD 0 ;LAST CHARACTER INPUT .ENDC ;NE ERL$G I$EFLG: .WORD 0 ;EXPECTED FLAG BYTE I$MBFR: ;*ORDER* MESSAGE PACKET BUFFER I$MOPC: .BYTE 0 ;* MESSAGE OPCODE I$MSUC: .BYTE 0 ;* SUCCESS CODE FOR END PACKET .BYTE 0,0,0,0,0,0,0,0 ;*END* REMAINDER OF PACKET .IF NE MMG$T I$PAR: .WORD 0 ;PAR VALUE TO MAP USER BUFFER .ENDC ;NE MMG$T ; PACKET BUFFER FOR MESSAGE ; *ORDER* PK$FLG: .BYTE 0 ;FLAG BYTE PK$MBC: .BYTE 0 ;BYTE COUNT FOR PACKET PK$OPC: .BYTE 0 ;OPCODE PK$MOD: .BYTE 0 ;MODIFIER BYTE PK$UNT: .BYTE 0 ;UNIT PK$SSQ: .BYTE 0,0,0 ;SWITCH AND SEQUENCE PK$BCT: .BYTE 0,0 ;BYTE COUNT FOR DATA PK$RCD: .BYTE 0,0 ;RECORD NUMBER OF START PK$CKS: .BYTE 0,0 ;CHECKSUM FOR PACKET ; *END ORDER* .SBTTL BOOTSTRAP READ ROUTINE .DRBOT DD,BOOT1,READ . = DDBOOT+40 ;PUT THE JUMP BOOT INTO SYSCOM AREA BOOT1: JMP @#BOOT-DDBOOT ;START THE BOOTSTRAP . = DDBOOT+210 READ: MOV #DDCNT,RTRCNT ;INIT THE RETRY COUNT MOV @#B$DEVU,DDUNIT ;STORE THE UNIT NUMBER ASL R1 ;MAKE BYTE COUNT OF WORD COUNT MOV R0,DDBLK ;MOVE IN THE BLOCK (RECORD) NUMBER MOV R1,DDBTCT ;MOVE THE BYTE COUNT INTO PACKET ; INITIALIZE THE TX CONTROLLER IN CASE BRESTR: MOV R2,-(SP) ;SAVE THE START OF BUFFER ON STACK MOV (PC)+,R0 ;GET THE CSR ADDRESS+4 BOTCSR: .WORD DD$CSR+4 ;PATCH THIS WORD IF CSR CHANGED (SET) BIS #CS$BRK,@R0 ;SET BREAK FOR SIGNAL MOV (PC)+,R3 ;SEND ONES FOR TIMING .WORD 177777 CALL BCHROS ;OUTPUT THEM CONRD1: TSTB @R0 ;READY YET ? BPL CONRD1 ;NOT YET BIC #CS$BRK,@R0 ;CLEAR THE BREAK MOV (PC)+,R3 ;GET TWO INITS .BYTE R$INIT,R$INIT ;TWO INITS FOR TX CALL BCHROS ;OUTPUT BOTH INITS TST -2(R0) ;DUMP OLD CHAR CALL BICHR ;GET A CHAR FOR INPUT CMPB R3,#R$CONT ;IS IT A CONTINUE? BNE BFATAL ;NO MOV #B$CHK-DDBOOT,R4 ;POINT TO THE CHECKSUM WORD IN PACKET CLR @R4 ;INITIALIZE IT CHECKSUM MOV #B$PKT-DDBOOT,R5 ;COMMAND PACKET PATTERN 1$: MOV (R5)+,R3 ;GET NEXT TWO BYTES TO OUTPUT ADD R3,@R4 ;ADD INTO THE CHECKSUM ADC @R4 ;END AROUND CALL BCHROS ;OUTPUT THE TWO BYTES CMP R5,R4 ;ALL THE PACKET OUT ? BLOS 1$ ;NO, KEEP OUTPUTTING ; PACKET IS OUT, NOW WAIT FOR DATA PACKET FROM TX BRDPKT: CALL BICHP2 ;READ TWO CHARACTERS MOVB R3,R4 ;BYTE COUNT TO R4 ;NOTE THE C BIT IS ALREADY CLEARED RORB R4 ;MAKE IT A WORD COUNT MOV R1,-(SP) ;INIT THE CHECKSUM CMPB R1,#R$DATA ;DATA PACKET ? BNE BEND ;NOPE, END PACKET ? 2$: CALL @R5 ;INPUT 2 BYTES MOV R1,(R2)+ ;STORE IN THE BUFFER ADD R1,@SP ;BUILD THE CHECKSUM ADC @SP ;END AROUND CARRY DECB R4 ;DONE ? BGT 2$ ;IF GT - NO CALL (R5) ;GET 2 CHECKSUM BYTES CMP R1,(SP)+ ;CHECKSUM OK ? BNE BFATAL ;NO BR BRDPKT ;YES, CONTINUE ; IF WE ARE GETTING INIT,INIT,INIT,... ITS OK SINCE THE CODE ; WILL WORK AND FAIL TO FIND A GOOD SUCCESS CODE OR CHECKSUM BEND: CALL (R5) ;TWO CHARS IN TSTB R3 ;CHECK SUCCESS CODE BMI BOTH ;NO - DO RETRY OR GIVE ERROR 1$: ADD R1,@SP ;COMPUTE CHECKSUM ADC @SP ;END AROUND CALL (R5) ;INPUT CHECKSUM SOB R4,1$ ;DONE ? CMP R1,(SP)+ ;CHECKSUM OK BNE BFATAL ;WE BLEW AN END PACKET!! MOV (SP)+,R2 ;RESTORE START OF BUFFER CLC ;MAKE SURE C-BIT CLEAR UPON RETURN RETURN ;EXIT BOTH: TST (SP)+ ;DUMP THE CHECKSUM WORD BFATAL: MOV (SP)+,R2 ;RESTORE THE BUFFER ADDRESS DEC RTRCNT ;ANY RETRIES LEFT ? BNE BRESTR ;YES, TRY AGAIN BR BIOERR ;HARD ERROR - PRINT MESSAGE .SBTTL BYTE INPUT ROUTINES (BOOT) ;+ ; INPUT BYTE ROUTINES ; ; BICHP2 - INPUT BYTE IN R1 AND SWAP THE BYTES. CALLS BICHR TWICE ; ; BICHR - INPUT ONE BYTE IN R1 ; ; R0 -> TRANSMIT CSR ; R1 = PARTIAL WORD INPUT, LOW BYTE=0 [BICHR] ; ; JSR PC,BICHP2/BICHR ; ; R1 = OLD HIGH BYTE (LOW) / NEW BYTE (HIGH) ; R3 = DATA BYTE ; R5 = UNDEFINED ;- BICHP2: MOV PC,R5 ;STORE THE ENTRY POINT TO THE CLR R1 ; FOLLOWING ROUTINE CALL @PC ;ENTRY FOR TWO BYTES WITHOUT STORE BICHR: TSTB -4(R0) ;WAIT ON READY BPL BICHR ;TIL SET MOVB -2(R0),R3 ;GET BYTE BISB R3,R1 ;MAKE PARTIAL WORD SWAB R1 ;AND SET TO MAKE NEXT PART RETURN .SBTTL BYTE OUTPUT ROUTINES (BOOT) ;+ ; OUTPUT BYTE ROUTINES ; ; BCHROS - OUTPUT 2 BYTES ; ; R0 -> TRANSMIT CSR ; R3 = BYTES TO OUTPUT (LOW BYTE FIRST) ; ; JSR PC,BCHROS ;- BCHROS: CALL @PC ;OUTPUT LOW BYTE 1$: TSTB @R0 ;WAIT TIL DONE BPL 1$ MOVB R3,2(R0) ;AND OUTPUT LOW BYTE SWAB R3 ;AND SWAP THE WORD RETURN ; COMMAND PACKET PATTERN: ; ***** THIS PACKET MUST REMAIN IN ORDER ***** B$PKT: .BYTE R$MSG,R$MSIZ,R$$RED,0 DDUNIT: .WORD 0 ;UNIT BOOTED FROM .BYTE 0,0 DDBTCT: .WORD 0 ;BYTE COUNT DDBLK: .WORD 0 ;RECORD NUMBER B$CHK: .WORD 0 ;CHECKSUM RTRCNT: .WORD 0 ;RETRY COUNT . = DDBOOT+606 BOOT: MOV #10000,SP ;SET STACK POINTER MOV R0,@#B$DEVU ;SAVE THE UNIT NUMBER MOV R0,-(SP) ;SAVE ON THE STACK TOO MOV #2,R0 ;READ IN SECOND PART OF BOOT MOV #<4*400>,R1 ;EVERY BLOCK BUT THE ONE WE ARE IN MOV #1000,R2 ;INTO LOCATION 1000 CALL READ ;GO READ IT IN MOV #READ-DDBOOT,@#B$READ ;STORE START LOCATION FOR READ ROUTINE MOV #B$DNAM,@#B$DEVN ;STORE RAD50 DEVICE NAME MOV (SP)+,@#B$DEVU ;STORE THE UNIT NUMBER JMP @#B$BOOT ;START SECONDARY BOOT .DREND DD .END