	.TITLE	TSKCOM
	.IDENT	"V1.9"
	.NLIST	BEX,CND
;
;   Author:	D. Mischler	20-OCT-87
;
;   This module implements the communications with DBGAID.
;
; V1.1	D. Mischler  05-JAN-88	Major redesign.
; V1.2	D. Mischler  17-JAN-88	Correct address window limit checking.
; V1.3	D. Mischler  01-FEB-88	Maintain multiple WDBs & region attachments.
; V1.4	D. Mischler  16-JUL-88	Fix bug in mapping context processing.
; V1.5	D. Mischler  17-NOV-88	Minor optimizations, fix MCR DEBUG.
; V1.6	D. Mischler  22-NOV-88	Use fast mapping when possible (if X$FMAP).
; V1.7	D. Mischler  27-NOV-88	Improve fast mapping determination.
; V1.8	D. Mischler  30-NOV-88	Do not change length when fast mapping.
; V1.9	D. Mischler  03-DEC-88	Minor speed improvements in T$MAP.
;
	.MCALL	CRAW$,DIR$,DTRG$,GIN$,MAP$S,RREF$,SDAT$S,WDBBK$,WDBDF$,WSIG$S
	WDBDF$

;
;   WDB structure offset definitions.
;
	.ASECT
	.=0
W.XWDB:	.BLKB	W.NLGH	; Window definition block (must be at offset zero).
W.XBAS:	.BLKW	1	; Virtual base address mapped through window.
W.XLNK:	.BLKW	1	; Link to next WDB.
W.XMAX:	.BLKW	1	; Maximum target address mapped through this window.
W.XRGN:	.BLKW	1	; Target task region ID.
W.XTAR:	.BLKW	1	; Target task WDB address.
W.XLEN:			; Length of WDB structure.
	.PAGE
	.PSECT	DATA,D,RW
;
;   Data definitions.
;
CRTADW:	CRAW$	PROWDB			; Create address window DPB.
CURWDB::.WORD	0			; Currently mapped WDB.
DETACH:	DTRG$	RDB			; Detach region DPB.
FNDTSK:	GIN$	GI.TSK,TSKBUF,3,0,0	; Find task DPB.
TSKNAM	==	.-4			; Target task name.
MAPCTX:	.WORD	0			; Mapping context buffer address.
	.IF DF	X$FMAP
MAPWDB::.WORD	0			; Last WDB mapped with MAP$ directive.
	.ENDC	; DF X$FMAP
PROWDB:	WDBBK$	7,128.,,,,<WS.64B!WS.UDS>,RCVBUF
RCVBUF:	.BLKW	10.			; Receive message buffer.
RSPBUF	=	RCVBUF+4		; Response packet address.
RCVREF:	RREF$	PROWDB			; Receive by reference DPB.
RDB:	.WORD	0,0,0,0,0,0,0,0		; Dummy RDB for DTRG$.
TSKBUF:	.BLKW	2			; Returned task name.
TSK.TS:	.BLKW	1			; Returned 1st task status word.
WDBFRE:	.WORD	0			; Free WDB structure list.
WDBLST::.WORD	0			; List of active WDBs.
;
;   Task mapping tables.
;
ASPTBL::.WORD	UDSTBL,UISTBL,SISTBL	; Address space table.
UDSTBL:	.BLKW	8.			; User data space WDB addresses.
UISTBL:	.BLKW	8.			; User instruction space WDB addresses.
SISTBL:	.BLKW	8.			; Supervisor I space WDB addresses.
TMTLEN	=	.-UDSTBL
	.PAGE
	.PSECT	CODE,I,RO
;
;   Cause the target task to exit.
;
T$EXIT::TST	TSKCTX		; Is there a target task?
	BEQ	10$		; No, just exit.
	MOV	#CT.XIT,-(SP)	; Build a command packet.
	MOV	SP,R0		; Point to it.
	CALL	T$SEND		; Send exit command.
	TST	(SP)+		; Clean up stack.
10$:	RETURN

;
;   Subroutine to cause the target task to proceed with execution.
;
T$PRO::	MOV	#UDSTBL,R0	; Point to first mapping table.
	MOV	#TMTLEN/4,R1	; Get length of all mapping tables.
10$:	CLR	(R0)+		; Zero all mapping tables.
	CLR	(R0)+
	SOB	R1,10$
;   Detach from all target task regions.
20$:	MOV	WDBLST,R0	; Get an active WDB address, zero?
	BEQ	30$		; Yes, send proceed command packet.
	MOV	W.XLNK(R0),WDBLST    ; Unlink WDB structure.
	MOV	W.NRID(R0),RDB+R.GID ; Set up region ID.
	DIR$	#DETACH		; Detach from region.
	MOV	WDBFRE,(R0)	; Link free WDBs to current one.
	MOV	R0,WDBFRE	; Make it free as well.
	BR	20$
;   Send proceed command.
30$:	MOV	#CT.PRO,-(SP)	; Build a command packet.
	MOV	SP,R0		; Point to it.
	CALL	T$SEND		; Send it.
	TST	(SP)+		; Clean up stack.
	CLR	MAPCTX		; Indicate mapping context buffer is needed.
	.IF DF	X$FMAP
	CLR	MAPWDB		; No window is currently mapped.
	.ENDC	; DF X$FMAP
;   Change all register symbol values to offsets.
	MOV	REGSYM,R0	; Point to first register symbol block, OK?
	BEQ	RCVMSG		; No, no register symbols are defined.
40$:	SUB	TSKCTX,S.VALU(R0) ; Convert value to an offset.
	MOV	(R0),R0		; Point to next register symbol, OK?
	BNE	40$		; Yes, turn its value into an offset.
	BR	RCVMSG		; Wait for a response and return.
	.PAGE
;
;   Subroutine to initiate communications with the target task.
;
T$STRT::
	DIR$	#FNDTSK,T$DEAD		; Get task status, terminate if error.
	MOV	TSKBUF,TSKNAM		; Copy complete task name.
	MOV	TSKBUF+2,TSKNAM+2
	MOV	#E.AWMF,R1		; Point to possible error message.
	DIR$	#CRTADW,T$ABRT		; Create an address window.
RCVMSG:	CALLR	T$RECV			; Wait for a message and return.

;
;   Handle an undecodeable DBGAID packet.
;   On entry:	R0 points to packet.
;
T$IPKT::
	MOV	R0,-(SP)	; Save packet address.
	MOV	#TRMBUF,R0	; Point to terminal buffer.
	MOV	$DBG$T,R1	; Get first task name word.
	CALL	C$R50		; Convert it to ASCII.
	MOV	$DBG$T+2,R1	; Get second task name word.
	CALL	C$R50		; Convert it to ASCII.
	CLRB	(R0)		; Terminate task name.
	MOV	#TRMBUF,R0	; Point to debugger task name.
	MOV	#E.DAFU,R1	; Point to error message.
	CALL	ERROR		; Display it.
	MOV	(SP)+,R0	; Recover packet address.
	BPT			; Trap to internal DBGAID.
	RETURN
	.PAGE
	.ENABL	LSB
;
;   Subroutine to map a specified address in the target task.
;   On entry:	R0 contains desired address space.
;		R5 contains desired target address.
;   On exit:	R1 contains debugger virtual address, carry set if error.
;		R0 is destroyed by this routine.
;
T$MAP::	MOV	R5,R1		; Copy target task address.
	BIC	#^C<160000>,R1	; Mask to APR number.
	SWAB	R1		; Put APR number in low byte.
	.IF LE	USEASH-4
	ASH	#-4,R1		; Shift it to make a word index.
	.IFF
	ASR	R1		; Shift it to make a word index.
	ASR	R1
	ASR	R1
	ASR	R1
	.ENDC
	ADD	ASPTBL(R0),R1	; Point to appropriate WDB address.
	MOV	(R1),R0		; Is there a WDB for specified address?
	BEQ	60$		; No, exit with failure.
	CMP	R0,CURWDB	; Is desired WDB currently mapped?
	BEQ	CMAPNG		; Yes, see if it must be re-mapped.
;   Desired WDB is not currently mapped.  Request if necessary and map it.
	CALL	FNDWDB		; Find the appropriate WDB, OK?
	BCC	CMAPNG		; Yes, go map it.
	MOV	R0,-(SP)	; Push WDB address for command packet.
	MOV	#CT.SWR,-(SP)	; Push command type.
	MOV	SP,R0		; Point to command packet.
	CALL	T$SEND		; Send window request to target task.
	CMP	(SP)+,(SP)+	; Remove command packet from stack.
	CALL	T$RECV		; Receive the response.
	CMP	#RT.WIN,R.TYP(R0) ; Is packet type correct?
	BEQ	20$		; Yes, continue.
	CALL	T$IPKT		; Handle unexpected packet type.
20$:	MOV	CURWDB,R0	; Point to the WDB.
	MOV	R0,(R1)		; Point APR table entry to debugger WDB.
;   See if the window is mapped correctly.  R0 points to the WDB.
CMAPNG:	CMP	R5,W.XMAX(R0)	; Is requested address mappable?
	BHI	60$		; No, exit with failure.
	MOV	R5,R1		; Copy target task address.
	SUB	W.XBAS(R0),R1	; Produce window address offset in bytes.
	ROR	R1		; Pick up carry (indicates borrow).
	.IF LE	USEASH-5
	ASH	#-5,R1		; Convert offset to 64-byte blocks.
	.IFF
	ASR	R1		; Convert offset to 64-byte blocks.
	ASR	R1
	ASR	R1
	ASR	R1
	ASR	R1
	.ENDC
	CMP	R1,W.NLEN(R0)	; Is desired address mapped by the window?
	BLO	50$		; Yes, calculate debugger virtual address.
	.PAGE
;
;   Re-map the window to overlap the desired location.
;
	ADD	R1,W.NOFF(R0)	; Adjust region offset.
	.IF LE	USEASH-6
	ASH	#6,R1		; Produce window offset in bytes.
	.IFF
	ASL	R1		; Produce window offset in bytes.
	ASL	R1
	ASL	R1
	ASL	R1
	ASL	R1
	ASL	R1
	.ENDC
	ADD	R1,W.XBAS(R0)	; Adjust window base address.
	.IF DF	X$FMAP
	MOV	MAPWDB,R1		; Get address of last window mapped, OK?
	BEQ	40$			; No, forget it.
	CMP	R0,R1			; Same as current window?
	BEQ	30$			; Yes, use fast mapping.
	CMP	W.XRGN(R0),W.XRGN(R1)	; Do windows map same target region?
	BNE	40$			; No, start over with MAP$.
	MOV	W.NSTS(R0),-(SP)	; Get desired access rights.
	BIC	W.NSTS(R1),(SP)		; Mask out legal access.
	BIT	#WS.WRT!WS.RED,(SP)+	; Is desired access enabled?
	BNE	40$			; No, use MAP$ directive.
;
;   Perform fast mapping.  R0 points to WDB.
;
30$:	MOV	R3,-(SP)	; Save R3,
	MOV	R2,-(SP)	;  and R2.
	MOV	R0,-(SP)	; Save WDB address.
	MOV	W.NOFF(R0),R1	; Get window offset.
	MOV	#000170,R0	; Get window ID (user data space APR 7).
	IOT			; Issue fast mapping call.
	ROL	R0		; Set carry if failure.
	MOV	(SP)+,R0	; Recover WDB address.
	MOV	(SP)+,R2	; Recover saved registers.
	MOV	(SP)+,R3	; Is everything OK?
	BCC	50$		; Yes, re-enter common code.
;
;   Can't use fast mapping or fast mapping failed.
;
	.IFTF	; DF X$FMAP
40$:	CLR	W.NLEN(R0)	; Map as much of the region as possible.
	MAP$S	R0		; Attempt to map the desired area, OK?
	BCS	60$		; No, exit with failure.
	.IFT	; DF X$FMAP
	MOV	R0,MAPWDB	; Remember which window was MAP$ed.
	.ENDC	; DF X$FMAP
;   Window is mapped correctly.  Calculate debugger virtual address.
50$:	MOV	R5,R1		; Copy virtual address again.
	SUB	W.XBAS(R0),R1	; Get offset from window base address.
	ADD	W.NBAS(R0),R1	; Add debugger virtual base of window.
	CLC			; Indicate success.
	RETURN
;   Desired address cannot be mapped.
60$:	SEC			; Indicate failure.
	RETURN
	.DSABL	LSB
	.PAGE
;
;   Subroutine to send a message to a task.
;   On entry:	R0 points to command packet.
;
T$SEND::
	SDAT$S	#TSKNAM,R0		; Send transmission buffer, OK?
	BCS	T$DEAD			; No, complain.
	RETURN
T$DEAD:	MOV	#E.NACT,R1		; Point to error message.
T$ABRT:	CALL	ERROR			; Display it.
	JMP	ABORT			; Terminate.

;
;   Subroutine to receive a message from a task.
;   On exit:	R0 points to response packet.
;
T$RECV::
	JSR	R5,.SAVR1	; Save everything but R0.
	CALL	SETWDB		; Set up WDB for message reception.
10$:	WSIG$S			; Wait for a significant event.
	DIR$	#RCVREF		; Receive a message, OK?
	BCC	20$		; Yes, set up for exit.
	DIR$	#FNDTSK		; Get task status, OK?
	BCS	T$DEAD		; No, terminate.
	TST	TSK.TS		; Is the target task executing?
	BPL	10$		; Yes, give it another try.
	BR	T$DEAD		; Abort with error message.
;   A message has been received: check sender and packet type.
20$:	MOV	#RCVBUF,R0	; Point to sender task name.
	CMP	(R0)+,TSKNAM	; Is first task name word OK?
	BNE	10$		; No, try again.
	CMP	(R0)+,TSKNAM+2	; How about the second task name word?
	BNE	10$		; Nope, keep trying.
	CMP	#RT.DEB,(R0)	; Is the packet an MCR DEBUG command?
	BNE	30$		; No, take the packet and run.
	MOV	#-1,MCRDEB	; Flag MCR DEBUG packet received.
	MOV	CURWDB,R0	; Point to window definition block.
	MOV	W.NRID(R0),RDB+R.GID ; Set up region ID.
	DIR$	#DETACH		; Detach from region.
	BR	10$		; Try again.
;   Process incoming address window.
30$:	MOV	CURWDB,R1		; Get current WDB address.
	MOV	R.WDB(R0),W.XTAR(R1)	; Remember target task WDB address.
	MOV	R.VDAT(R0),W.XRGN(R1)	; Get target task region ID.
	MOVB	R.APR(R0),R2		; Get base APR in target task.
	SWAB	R2			; Put it in the high byte.
	.IF LE	USEASH-5
	ASH	#5,R2		; It belongs in the top 3 bits.
	.IFF
	ASL	R2		; It belongs in the top 3 bits.
	ASL	R2
	ASL	R2
	ASL	R2
	ASL	R2
	.ENDC
	MOV	R2,W.XBAS(R1)	; Save window base address.
	MOV	W.NLEN(R1),R3	; Fetch WDB mapping length word.
	CLR	W.NLEN(R1)	; Indicate window is not currently mapped.
	.IF LE	USEASH-6
	ASH	#6,R3		; Make mapping length into address offset.
	.IFF
	ASL	R3		; Make mapping length into address offset.
	ASL	R3
	ASL	R3
	ASL	R3
	ASL	R3
	ASL	R3
	.ENDC
	ADD	R2,R3		; Produce maximum virtual address + 1.
	DEC	R3		; Reduce it to get maximum virtual address.
	MOV	R3,W.XMAX(R1)	; Save it.
	TST	MAPCTX		; Is mapping context needed?
	BNE	100$		; No, just exit.
	.PAGE
;
;   Process mapping context buffer.  The current window must be correct.
;
	CLR	W.XRGN(R1)	; Context window always maps task region.
	TSTB	R.ASPC(R0)	; Is data space in use?
	BEQ	35$		; Yes, maintain I/D space distinction.
	MOV	#UISTBL,ASPTBL	; Force user D references to user I space.
35$:	MOV	R.TCTX(R0),TSKCTX ; Save virtual address of task context.
	MOV	R.MCTX(R0),R5	; Get virtual address of map context buffer.
	MOV	R5,MAPCTX	; Save for posterity.
	MOV	R1,R0		; Copy WDB address.
	CALL	CMAPNG		; Point to start of mapping context buffer.
;   Process window definition blocks in target task context buffer.
40$:	MOV	W.NSTS(R1),R2	; Get window status.
	BIT	#WS.MAP,R2	; Is this window mapped?
	BEQ	80$		; No, look at the next one.
	MOV	#UISTBL,R3	; Assume window is in user instruction space.
	BIT	#WS.UDS,R2	; Is window actually in user data space?
	BNE	50$		; Yes, set APR table pointer accordingly.
	BIT	#WS.SIS,R2	; Is window actually in super I space?
	BEQ	60$		; No, it really is in user instruction space.
	MOV	#SISTBL,R3	; Point to super mode APR mapping table.
	BR	60$
;   Here if address window maps user data space.
50$:	MOV	#UDSTBL,R3	; Point to user data space APR mapping table.
60$:	MOVB	W.NAPR(R1),R2	; Get starting APR number.
	ADD	R2,R3		; Point to the appropriate WDB pointer.
	ADD	R2,R3
	MOV	W.NLEN(R1),R4	; Get number of 64-byte blocks mapped.
70$:	MOV	R1,(R3)		; Save WDB pointer for this APR.
	SUB	W.NBAS(R0),(R3)	; Subtract debugger window base address.
	ADD	W.XBAS(R0),(R3)	; Add target task window base address.
	BIS	#1,(R3)+	; Make result odd to flag target task address.
	INC	R2		; Bump APR number.
	CMP	R2,#7		; Is another APR possible?
	BHI	80$		; No, don't screw up.
	SUB	#128.,R4	; Does this WDB use the next APR also?
	BHI	70$		; Yes, set it up as well.
80$:	ADD	#W.NLGH,R1	; Point to next WDB.
	TST	(R1)		; End of mapping context buffer?
	BPL	40$		; No, process this WDB.
	MOV	#RSPBUF,R0	; Point to response packet.
;   Convert register symbol offsets back into values.
	MOV	REGSYM,R1	; Point to first register symbol block, OK?
	BEQ	100$		; No, no register symbols are defined.
90$:	ADD	TSKCTX,S.VALU(R1) ; Convert offset to a value.
	MOV	(R1),R1		; Point to next register symbol, OK?
	BNE	90$		; Yes, turn its value into an offset.
100$:	RETURN
	.PAGE
;
;   Subroutine to set up a WDB for message reception.
;
SETWDB:	MOV	WDBFRE,R0	; Get a WDB from free list, OK?
	BNE	10$		; Yes, unlink it from the list.
	MOV	#W.XLEN,R0	; Get length of WDB structure.
	CALL	U$RQCB		; Allocate a WDB structure, OK?
	BCC	20$		; Yes, re-enter common code.
	MOV	#E.AWMF,R1	; Point to error message.
	CALLR	T$ABRT		; Display error and exit.
;   WDB has been gotten from free list.
10$:	MOV	(R0),WDBFRE	; Save address of next free WDB.
20$:	MOV	R0,RCVREF+R.REBA; Save WDB address in RREF$ DPB.
	MOV	R0,CURWDB	; Make it the current WDB too.
	MOV	WDBLST,W.XLNK(R0) ; Link next WDB to current one.
	MOV	R0,WDBLST	; Head list with current WDB.
	MOV	#PROWDB,R1	; Point to prototype WDB.
	MOV	#8.,R2		; Get WDB length in words.
30$:	MOV	(R1)+,(R0)+	; Copy prototype WDB over new one.
	SOB	R2,30$
	RETURN

;
;   Subroutine to find the appropriate WDB if it has been sent.
;   On entry:	R0 contains WDB from APR table.
;		R1 points to APR table entry.
;
FNDWDB:	MOV	R2,-(SP)	; Save R2.
	BIT	#1,R0		; Is WDB address in target task?
	BEQ	40$		; No, just make it current.
	DEC	R0		; Correct target task WDB address.
	MOV	WDBLST,R2	; Get address of first active WDB, zero?
	BEQ	20$		; Yes, WDB must be requested.
10$:	CMP	R0,W.XTAR(R2)	; Is this WDB correct?
	BEQ	30$		; Yes, update APR table.
	MOV	W.XLNK(R2),R2	; Get address of next active WDB, zero?
	BNE	10$		; No, keep looking.
20$:	SEC			; Indicate window must be requested.
	BR	45$		; Pop R2 and exit.
;   Found correct debugger WDB.
30$:	MOV	R2,R0		; Copy WDB address to expected location.
	MOV	R0,(R1)		; Update APR table WDB address.
40$:	MOV	R0,CURWDB	; Make selected window current.
	CLR	W.NLEN(R0)	; Force remapping.
45$:	MOV	(SP)+,R2	; Recover saved R2.
	RETURN

	.END
