RT-11 5.x install tapes?

Jörg Hoppe j_hoppe at t-online.de
Fri Mar 10 13:56:34 CST 2017


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
> --------------------------------------------------




More information about the cctech mailing list