Alan,
thanks!
- I saw that neither 5.5 nor 5.6 has no DD, but 5.0 -5.4G and 5.7 has.
Didn't understand the reason.
- Also DD.MAC in the 5.0 - 5.4 and 5.7 changes often.
I tested tu58fs with oversized TU58 tape for 5.3 and 5.7, the number of
blocks is always patched into into offset 0x2c, 0x2d in DD.SYS
- I made a working DD.SYS with
.macro DD,
.link DD,
.rename DD.SAV DD.SYS
Do you know how to make DDX.SYS? Must be a conditional MACRO symbol.
Joerg
for work on TU58 emulator "tu58fs"
I'd like to experiment with
oversized tape images under RT-11 5.5, 5.6 and 5.7. The images I
know about are the classiccmp collections, Earl Evans pointed me
to the RT11DV50.ISO archive.
However, in these images the TU58 driver files
DD.MAC/DD.SYS/DDX.SYS are mostly missing. Strange, because they
claim to be pristine.
Somebody knows about original RT-11 V5 installation tape images?
Here is the
DD.MAC file you are looking for. It was part of
the RT-11 v5.6 sources that Mentec supplied to the Y2K update
team to make v5.7. Since the last modification was in 1979,
it is safe to assume that it applies to all recent versions.
Have fun!
Alan
--------------------------------------------------
.MCALL .MODULE
.MODULE DD,VERSION=21,COMMENT=<DECtape II Handler>,AUDIT=YES
; COPYRIGHT (c) 1989 BY
; DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
; ALL RIGHTS RESERVED
;
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
;ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND 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. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
;TRANSFERRED.
;
;THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
;AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
;CORPORATION.
;
;DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
;SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
.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,<DD$CS2>
.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<BUS$M>,R0 ;Isolate bus bits
CMP #<BUS$X>,R0 ;Running on KXJ?
BNE 15$ ;Yes, go ahead and install
CMP #<BUS$C>,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, at 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 = <DDEND-DDSTRT> + <BOTCSR-DDBOOT> + 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,<BTCSR&777>(R2) ;SET THE NEW CSR
ADD #4,<BTCSR&777>(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, at 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, at 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$, at -(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<DD$PRI*^O40>&^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, at TICSRA ;SET THE INPUT INTERRUPT
BR INPRTN ;GO RETURN
OUTCHR: MOV R5, at 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, at TIVECA ;CLEAR ANY CARRY BITS SET IN
BIC #1, at TOVECA ;THE INTERRUPT PSW
.MTPS #340 ;RAISE PRIORITY TO PREVENT INTERRUPTS
BIC #CS$INT, at TICSRA ;NO INPUT INTERRUPTS FOR NOW
BIS #CS$INT, at 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, at 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, at 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, at 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, at 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, at 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, at TICSRA ;ZAP INTERRUPT ENABLE
BIC #CS$INT, at 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, at TOCSRA ;SET UP KNOWN STATE
BIC #CS$INT, at 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, at TOBFRA ;;;SEND ONES FOR TIMING
BIS #<CS$INT!CS$BRK>, at 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, at 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, at 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, at 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, at TOBFRA ;;;OUTPUT FIRST BYTE (FLAG)
BIS #CS$INT, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at 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
--------------------------------------------------