;
; Debug Kernal for PL/I Symbolic Debugger
;
								.enable lc
;
; This is the module that resides in the user task and performs 
; whatever operations need to be performed on behalf of the debug task.
;
; Do not modify anything in this module without good familiarity 
; with the code in DEBASM.
;

	.title	debug
	.psect	$deb$$	;psect must have this name for debinit to work

;***************************************************************************
; Version number - must be incremented any time a change is made which 
; affects the interface with the debug task, including anything that
; changes the relative locations of words referred to by the debug task
; (note that a change in the executive macros could do this); so that
; trying to debug a task that has an obsolete version results in an
; error message rather than mysterious blow-ups. The safest thing is to
; increment on every edit and on each major release of the executive.
; The version number is in a global so debug task can tell (via external 
; in debasm) the version number of the kernal in it. It is also stored
; in $db$vw so debug task can tell (by reading the .TSK) the version of
; kernal in user task.
;
	$db$vnm == 9.
;***************************************************************************


	.globl	$DSW



	.list meb

;
; macro for executive directives
;
; calling sequence:
;
;	exec  directive  <arg1,arg2,...>
;

	.macro	exec	direc args
		.mcall direc
		direc args
	.endm



break:			;breakpoint traps will come here
$db$snd::
	mov $DSW,sndpkt	;dsw gets clobbered by our send & receive, must save
	exec DIR$ <#snddpb>
	bcs error
$db$rcv::
	exec STOP$S	;save a word, dont bother checking for error on STOP -
			;can only occur if code is overwritten, & would 
			;probably also cause error on receive (such as no data)

;start-up entry point (TKB's "ODT xfer addr") - task execution starts here:

$db$xf::exec DIR$ <#rcvdpb> ;receive instruction packet from debug task
	bcc $db$pkt	;no error - execute it

$db$ndb::jmp (r0)	;no debugger - start task without it
			; (assume the error was no packet to receive)
			;changed to nop by code in first debugger message,
			; so we fall through to error handler

;on error, return dsw as status so debugger can tell user what the error was
error:	exec EXST$S <$DSW> 
	;note: EXST can only fail if our code is overwritten



;first receive is from any task 
;(first debugger message fills in the task name for subsequent receives)
$db$rdpb::
rcvdpb:	exec RCVD$ <,rcvpkt>


$db$sdpb::
snddpb:	exec SDAT$ <,sndpkt>	;debugger fills in task name before first send



$db$ptn::		;receive packet includes task name
rcvpkt:
$db$vw::.word $db$vn,0	;store kernal version number (see note above)
			;overwritten by debug rad50 task name on each receive

$db$pkt::	;code packet for send & receive
sndpkt:	.word	0,0,0,0,0,0,0,0,0,0,0,0,0	;13 words
endpkt:		;initialized to ensure mismatch on version number check by
		;debinit in a newer debugger applied to an old user .TSK


;trap vector for SVDB$ - must be static since RSX vectors through here 
; at the time of the trap
$db$tv::
	.word	0	;dont want odd address traps
	.word	0	;dont want memory protect traps
	.word	break	;where to go on BPT & single instruct traps


$db$qio::
	;..MAIN is address of main procedure for debugger initialization
	;(function word is set by debugger before each QIO)
	;PL/I always assigns TI: to lun 1
	;I/O status block is last 2 words of send/receive packet
	;parms set up for SF.GMC/SF.SMC, buffer is word before I/O status block
	;.sgd0, .auto, .STOP, .ERROR are addresses debug task needs
	;(these parm positions not used by terminal driver for SF.GMC, IO.ATT)

	exec QIO$ <..MAIN,1,,,endpkt-4,,<endpkt-6,2, .sgd0,.auto,.STOP,.ERROR>>

$db$mnp == $db$qio + Q.IOFN		;where ..MAIN pointer is
$db$sgp == $db$qio + Q.IOPL+<2*2>	;where segment descriptors pointer is
$db$ovp == $db$qio + Q.IOPL+<3*2>	;where overlay loader pointer is
$db$stp == $db$qio + Q.IOPL+<4*2>	;where .STOP pointer is
$db$erp == $db$qio + Q.IOPL+<5*2>	;where .ERROR pointer is
	.globl ..MAIN, .STOP, .ERROR
	.psect $$SGD0,rw,d,ovr
.sgd0:	;address of root segment descriptor (first item in psect $$SGD1 - cant
	;map to it directly since it's CON rather than OVR, so we use $$SGD0,
	;which immediately precedes it and is zero length)
	.psect $$AUTO,ro,i
.auto:	;address of overlay loader. cant provide addr of $ALBP2 directly
	;via global because non-overlaid tasks would then get an undefined


	.end $db$xf	;where to go on task start-up
