	.title	Entrap
	.ident	*01.02*
;+
; **-Entrap-AST / SST Interface and Autoload Context Preservation Routine
;
; Version 01.02
;
; Dave A. Klotzbach	April 29, 1982
;
; This routine is called from an AST or SST  transfer  vector  set  up  by  the
; calling program. The vector has the following format: 
;
;		+-------------------------------+
;	0	|				|
;               +--    JSR     R1,@#ENTRAP    --+
;	2	|				|
;		+-------------------------------+
;       4       | Number Of Items On Trap Stack |       See Note, Below
;		+-------------------------------+
;       6       | AST/SST Routine Entry Address |
;		+-------------------------------+
;
; Inputs:
;
;       r1   =Address of 2nd half of trap vector
;       0(sp)=Saved r1 contents
;       2(sp)=Remainder of AST / SST stack (depends on the type of trap)
;
; Outputs:
;
;	Saves  the  current  Autoload Overlay mapping context (if the task is
;	overlaid) and calls the specified AST or SST  service  routine.  Upon
;	re-entry  it  restores  the mapping context (if necessary), cleans up
;	the stack, and effects an AST or SST exit. 
;
; Note:
;
;	The  COUNT  element  (3rd  word)  in  the  transfer  vector  must  be
;	initialized with care. For  an  AST,  it  is  the  number  of  excess
;	trap-specific  parameters.  That  is, the number does not include the
;	common 4 words in the AST stack (Event Flag Mask Word,  PS,  PC,  and
;	$DSW).  For  an SST, the value is the negative of the total number of
;	words on the stack, including the usual 2 words (PS and PC). 
;
; This  subroutine  is  usually called from an AST / SST vector set up by the
; calling program. This vector can be expressed in a C structure as follows : 
;
;	typedef struct{
;	   int     JSR_R1;         /* the actual command to call routine   */
;	   int     (*entrap)();    /* the routine to be called             */
;          int     count;          /* the number of "active" arguments     */
;	   int     (*srvrtn)();    /* user defined subroutine              */
;	} TRAP_VECTOR;
;
; A QIOW AST vector is then initialized as follows :
;
;       static TRAP_VECTOR qiow_ast = { 04137,&entrap,1,&ast_routine };
;
; Alternatively, the vector can be set up in MACRO-11 :
;
;	.MACRO	TRPVEC	SRVRTN,COUNT
;	jsr	r1,@#entrap		;transfer to entrap first
;	.word	COUNT			;system trap stack code word
;	.word	SRVRTN			;trap service routine addr
;	.ENDM	TRPVEC
;
; A memory-protect SST vector would then be initialized as follows :
;
;       V$MPRO: TRPVEC  MEMSST,-5  ;SET UP THE MEMORY-PROTECT SST ROUTINE VECTOR
;
; The work area is located in the $$OVDT psect and is structured as follows :
;
;		+-------------------------------+
;	0	|	Overlay Load LUN	|	.novly, n.ovly *
;		+-------------------------------+
;	2	| Address of First Segment Desc	|	.nstbl, n.stbl +
;		+-------------------------------+
;	4	|	  Overlay Load		|	.niost, n.iost
;		+---	       I/O	     ---+
;	6	|	  Status Block		|
;		+-------------------------------+
;	10	| Overlay Load Error Subroutine	|	.naler, n.aler +
;		+-------------------------------+
;	12	|    Segment Descriptor Size	|	.nszsg, n.szsg *
;		+-------------------------------+
;	14	| Load and Map Segment Routine	|	.nrdsg, n.rdsg +
;		+-------------------------------+
;	16	|   Unmap Segment(s) Routine	|	.nmrks, n.mrks +
;		+-------------------------------+
;	20	| Total Number Of Task Segments	|	.nsegs, n.segs !
;		+-------------------------------+
;	22	| Top Address Of Segment Stack	|	.nroot, n.root !
;		+-------------------------------+
;	24	|     Segment Stack Pointer	|	.nstpt, n.stpt !
;		+-------------------------------+
;
;       * - The Overlay Load LUN and the Segment Descriptor  Size  words  are
;	    filled  in by the Task Builder. The Segment Descriptor size is 6,
;	    8, or 9 words long,  depending  on  whether  manual  loading  and
;	    memory-resident overlays are used. The Task Builder Automatically
;	    allocates  a  Logical  Unit,  assigns  the load device to it, and
;	    fills in the number. 
;
;       + - The address of the first Segment Descriptor, and the addresses of
;	    the  Overlay  Load Failure Routine, the Load and Map Segment, and
;	    Unmap Conflicting Segment(s) Routines are filled in  at  assembly
;	    time by the Ovdat module. 
;	    
;       ! - The  Top  Address  of Segment Stack and Segment Stack Pointer are
;	    filled in at assembly time by this module.  The  Number  of  Task
;	    Segments  is  initialized  at run-time by the Ovlini routine. The
;	    Segment Stack area is allocated at assembly time by  this  module
;	    ule,  with  a  default  size of 12. words. This is adequate for a
;	    task with 4 overlaid segments to have  an  overlaid  SST  routine
;	    interrupt an overlaid AST routine which has itself interrupted an
;	    overlaid task-level routine. These words are optional and present
;	    only  if  this  module  is  explicitly included in the Task-Build
;	    command file  (E.g.  lb:[1,1]syslib/lb:endat).  The  end  of  the
;	    overlay  work  area  is determined from the address of the $$OVDU
;	    psect. 
;
; The Segment Stack area is located in the $$STCK psect, as follows :
;
;		+-------------------------------+
;		|  1st Segment's Root Address	|	<- .nroot
;		+-------------------------------+
;		|  2nd Segment's Root Address	|
;		+-------------------------------+
;				.		
;				.		
;				.		
;		+-------------------------------+
;		|  Nth Segment's Root Address	|
;		+-------------------------------+
;		|	      Empty		|
;		+-------------------------------+
;				.		
;				.		
;				.		
;		+-------------------------------+
;		|	      Empty		|
;		+-------------------------------+
;		|     Nth Set Of N Words Of	|	<- .nstpt, while running
;		+---      Saved Segment      ---+
;		|     Descriptor Addresses	|
;		+-------------------------------+
;				.		
;				.		
;				.		
;		+-------------------------------+
;		|     2nd Set Of N Words Of	|
;		+---      Saved Segment      ---+
;		|     Descriptor Addresses	|
;		+-------------------------------+
;		|     1st Set Of N Words Of	|
;		+---      Saved Segment      ---+
;		|     Descriptor Addresses	|
;		+-------------------------------+
;							<- .nstpt, initially
;
; The Segment Stack area may be enlarged by means of the Task-Builder's
; EXTSCT option.  For example,
;
;	TKB>extsct=$$stck:20		!make the Segment Stack 28. words long.
;-
	
	.mcall	alodf$,	astx$s,	dsar$s,	enar$s
	alodf$			; Define the segment descriptor symbols
	.globl	.nsegs		; Force the autoload extensions to load
	
	.list	meb
	.nlist	toc
	.page
	.psect	$$resl
	
Entrap::
Restra::
	mov	r0,-(sp)	; Save r0
	mov     (r1)+,-(sp)     ; Save the code number;
	call	ovfout		; Find all of the overlay segments currently maped
	call    @0(r1)          ; Call the users service routine
	call    ovmap           ; Restore previous context.
	mov	2(sp),r0	; Restore R0
	mov	4(sp),r1	; Restore R1
	asl     (sp)            ; Convert Code to byte count
	bvs	5$		; Trying to do a "Cluster" call ?
	bge     3$              ; Do an ast 100$.
	sub     (sp),sp         ; Fix sst stack
	tst	(sp)+		; Copied from the original
	rti                     ; And continue execution.
3$:
	add	(sp),sp		;
	add	#6,sp		; Fix the stack
	astx$s                  ; Ast
;
; Else all hell breaks loose.
;
5$:
	iot
	.page
	.sbttl  OVFOUT - Find the outer/ upper most segment mapped
;+
; ** OVFOUT - Find the outer/uppermost segment currently mapped
;
; This  routine  in  conjunction  with "ovlini" and "ovfix", establish And
; maintain the mapping for a system using ast/sst's.  This  routine  finds
; which  of  the  segments  on  each of the "root" segments are mapped. By
; knowing this information it will be possible to reconstruct the  mapping
; thread back out to the functions in effect at this time. 
;
;-
	
OVFOUT::
	call	$saval		; Save all of the registers.
	mov	@#n.ovpt,r0	; Get the address of the work area
	beq	100$		; EQ - There is no work area
	
	tst	n.segs(r0)	; Has it been initialized?
	bne	1$		; NE - Yes it has
	call	ovlini		; Initialize the overlays.
1$:
	mov	n.root(r0),r2	; Point to the segment work area
	mov	n.stpt(r0),r1	; Get the current stack pointer
	mov	n.segs(r0),r4	; Number of roots to test
2$:
	mov	(r2)+,r3	; Get a address of the root segment.
6$:
	mov	r3,r5		; Save  the entry pointer
3$:
	bit	#ss.nld,(r3)	; Is this segment mapped?
	bne	4$		; NE - no
	tst	s.lkup(r3)	; Is there a higher level?
	beq	7$		; EQ - no, that's it for this segment
	mov	s.lkup(r3),r3	; Go to the next higher level
	br	6$		; Look at that one
4$:
	mov	s.lknt(r3),r3	; Link to the next
	cmp	r3,r5		; Is this the one we started on?
	bne	3$		; NE - no, go traipse thru that list
	mov	s.lkdn(r3),r3	; Previous level was highest mapped. If window
				; isn't mapped at all, this will be a zero.
7$:	
	mov	r3,-(r1)	; Push this descriptor address
	cmp	r1,r2		; Have we a stack under flow?
	bhi	10$		; Still safe.
	iot			; Off we go into the wild blue yonder.
10$:
	sob	r4,2$		; Continue?
	mov	r1,n.stpt(r0)	; Save the current stack pointer
100$:
	return
	.page
	.sbttl OVLINI - Overlay support initialization
;+
; ** ovlini - Initialize the overlay/ast support structures.
;
; This  routine  will  initialize  the  control variables for the modified
; overlay system. In this system it will be possible for the programmer to
; use both overlays and AST/SST's in the same program. 
;
; Ovlini calls $saval so it will not disrupt any of the registers.
;
;-
OVLINI::
	call	$saval		; Save all of the registers
	mov	@#n.ovpt,r0	; Get the work area pointer
;	beq	100$		; If no overlays then exit.
	
	mov	n.stbl(r0),r1	; Point to the first segment descriptor
	mov	n.root(r0),r2	; Point to the root of the segment heap.
1$:
	tst	(r1)		; Is this a real segment?
	beq	100$		; EQ - No so we are done.
	tst	s.lkdn(r1)	; Is this a root segment?
	bne	2$		; NE - No so get next segment
	
	mov	r1,(r2)+	; Save the root segment
	inc	n.segs(r0)	; Count it
2$:
	add	n.szsg(r0),r1	; Point to the next segment
	br	1$		; And try the next one
100$:
	return			; And quit.
	.page
	.sbttl OVMAP
;+
; ** OVMAP - Map the overlays back in with out calling them
;
; This routine is virtually  the  same  as  the  one  in  $auto  with  the
; exception that it will not call the routine at the outer most level when
; complete. 
;-
ovmap::
	call	$saval		; Save all of the registers
	dsar$s			; Don't let an AST interrupt an SST
	mov	@#$dsw,-(sp)	; Save the status for later
	mov	@#n.ovpt,r0	; Get the overlay work space pointer
	mov	n.stpt(r0),r1	; Point to the first segment to load
	mov	n.segs(r0),r4	; Get the number of segments to map.
1$:
	mov	(r1)+,r2	; Get the segment to be loaded
	bit	#ss.nld,(r2)	; Is this segment already loaded?
	beq	2$		; EQ - Segment loaded get the next one
	
	call	@n.mrks(r0)	; Clear all branches in the way
	call	lbranch		; Load this branch
2$:
	sob	r4,1$		; And continue till done
	mov	r1,n.stpt(r0)	; Restore stack pointer
	cmp	(sp)+,#is.suc	; Were ASTs actually disabled earlier ?
	bne	3$		; NE - no, they had already been disabled
	enar$s			; Otherwise, re-enable their recognition
3$:
	return			;
	
;
; Load overlay segment branch
;
lbranch:
	call	$saval		; Save the regs.
101$:
	clr	r3		; Let $rdseg use the default flag
	clr	r4		; And iosb
	clr	r5		; And ast
	tst	s.size(r2)	; Is this a zero length segment?
	bne	102$		; NE - obviously not.
	
	bic	#ss.nld,(r2)	; It's as good as loaded
	br	103$		;
102$:
	call	@n.rdsg(r0)	; Load or map the segment
	bcc	103$		; CC - all done
	call	@n.aler(r0)	; Call the error handling routine
	br	101$		; And try again
103$:
	mov	s.lkdn(r2),r2	; Move a step closer to the root
	beq	104$		; EQ - We are at the root
	bit	#ss.nld,(r2)	; Is this one loaded?
	bne	101$		; Ne - No so go load it
	br	103$		; Else find the next one
104$:	
	return			; All done bye-bye
	.end
