Trailing-Edge - PDP-10 Archives - decuslib10-07 - 43,50433/paspsi.mac
There are 4 other files named paspsi.mac in the archive. Click here to see a list.
title PASPSI

;This here is a set of routines for using the PSI system in PASCAL.
;Each condition established is assigned an "index".  Internally this
;is the index into various tables.  As far as the user is concerned it
;is simply a small non-negative integer.  The user is assumed to have
;read the writeup on PSI in the monitor calls manual.

;WARNING:  The interrupt handler is not reentrant.  This means that we
;are in big trouble if the user does a PSIADD specifying that interrupts
;remain enabled when at interrupt level.  If you want to make it
;reentrant, consider:
;  use some AC other than 17 in the dispatch process, so the stack is
;	always valid
;  see if the code around INTMOD is reentrant
;  figure out a way to make the critical section stuff support multiple
;	levels of interrupts.  Probably they would have to be stacked.
;  change code so no variables in low seg are used.  Do everything on
;	the stack

;edit history

;2 - make LH of saved procedure addr be zero, since use it for indirection
;	From J Hammer at CSL

len==20		;assembly parameter: maximum no. of conditions active
		;(i.e. all values of index must be less than len)

search uuosym

b=2	;first argument

entry	psiadd,psirem,psiini,psion,psioff,psiclr


vector:		;This is the main vector for the psi system
repeat len,<
	disp+2*%i	;new PC - entry point for interrupt
	0		;old PC
	1b2		;indicates no more interrupts until debreak
	0		;status
dispt:	block len	;pascal routine to call on interrupt
disp:		;This is the place where interrupt handling begins
repeat len,<
	movem 17,apracs+17
	jsp 17,intmod
pisys:	block 3*len	;this contains argument blocks for PISYS.

apracs:	block 20	;place to store ac's
index:	block 1	;place to store index on entry
resume:	block 1	;stores addr of appropriate OLD PC word in vector when
		;resuming a critical section

intmod:		;This is the main interrupt processor and dispatcher
	movem 17,index	;tells us which place we came from (index*2)
	skipge in.crt##	;in critical section?
	jrst docrit	;yes - resume it
	movei 17,apracs
	blt 17,apracs+16
	move 17,apracs+17	;we need to use the pdl pointer!
	hrrz b,index	;this is pointer into disp.
	subi b,disp+2	;this gives index into disp
	lsh b,-1	;divide by 2   arg1 = "index"
	move f,b	;f will be index*4, pointer into vector
	imuli f,4
	move c,vector+.psvop(f)	;arg2 = "old PC"
	hrrz d,vector+.psvfl(f)	;arg3 = "reason"
	move e,vector+.psvis(f)	;arg4 = "status"
;The following assumes that we can start our stack above the
;main program's.  This will work unless we have interrupted a
;call of a procedure with more than 5 words of parameters.  In
;that case stuff is put above the top of stack pointer.
;I don't have a general solution, but for any given program
;you can easily find out the maximum offset it uses above the
;stack and use that in the following line instead of the 200.
;200 should be enough except if big arrays are being passed by
	hrri p,200(p)		;give us some space, just for luck
	caig 15,40(p)
	jsp 1,corerr##		;get more core if needed
	movei f,tty##	;save state of TTY system
	push p,2(f)
	push p,36(f)
	push p,37(f)
	push p,43(f)
	movei f,ttyout##
	push p,43(f)
	push p,1(p)		;routine will garbage p-1
	pushj p,@dispt(b)	;go to SAIL routine. note it can look at a,b,c
	pop p,0(p)
	movei e,ttyout##
	pop p,43(e)
	movei e,tty##
	pop p,43(e)
	pop p,37(e)
	pop p,36(e)
	pop p,2(e)
	movem 15,apracs+15	;use new value of 15 if it changed
	hrlzi 17,apracs	;now restore the world
	blt 17,17
	debrk.		;will return to interrupted thing
	  halt .
	  halt .

;index = psiadd(type,reasonbits,proc,control)
;	Adds a condition. Does not turn on PSI system.  Also makes like INTMAP.
;		type - code for type of interrupt
;		reasonbits - condition for I/O interrupts, 0 otherwise
;		proc - procedure to call for immediate interrupt
;		control - for setting LH of word 3 of vector
;	Returns index, or -1 if table full

psiadd:	setz a,		;a will be index
   ;compute index for new entry
psia1:	skipn dispt(a)	;is this entry in use?
	jrst psia2	;no - use it
	caige a,len-1	;yes - last one checked?
	aoja a,psia2	;no - try again
	setom 1(p)	;table full - return -1
	popj p,

   ;set up what will happen at interrupt
psia2:	hrrzm 4,dispt(a);[2] dispatch addr

   ;set up block at vector
	move d,a	;d = a*4, offset into vector
	lsh d,2
	hrlz 5,5	;flag bits go in lh
	movem 5,vector+.psvfl(d)

   ;set up block for pisys.
	move e,a	;e = a*3, offset into pisys
	imuli e,3
	hrl c,d		;vector offset in LH - reason in RH
	movem c,pisys+1(e)
	movem 2,pisys(e);type
	setzm pisys+2(e);must be zero

   ;do the pisys
	movsi b,(ps.fac)
	hrri b,pisys(e)
	pisys. b,
	 halt .
	movem a,1(p)	;return index
	popj p,

;	removes a condition set up by psiadd, and clears table entries
;		index - return from psimap

psirem:	move a,b	;save index
	imuli b,3	;index into pisys
	movei b,pisys(b)
	hrli b,(ps.frc)	;turn off condition
	pisys. b,
	  halt .
	setzm dispt(a)	;release the entry
	popj p,

;	clears all pending interrupts for one condition
;		index - return from psiadd for the condition

psiclr:	imuli b,3	;index into pisys
	movei b,pisys(b)
	hrli b,(ps.fcs)	;clebr bll interrupts
	pisys. b,
	  halt .
	popj p,

;	Must be done before any psion or psioff. Mainly does PIINI.
;		no arguments

psiini:	movei a,vector
	piini. a,
	  halt .
	setzm dispt		;clear old interrupts
	move a,[dispt,,dispt+1]
	blt a,dispt+len-1
	popj p,

;	Turns on PSI system
;	Turns off PSI system

psion:	skipa a,[ps.fon]
psioff:	movsi a,(ps.fof)
	pisys. a,
	  halt .
	popj p,

	subttl Critical section code

entry enterc,leavec

;Here from INTMOD when interrupted in critical section - go back to user
docrit:	hrrz 17,17		;get addr only of place in dispt
	subi 17,disp+2		;compute index in vector
	lsh 17,1		;now have index * 4
	movei 17,vector+.psvop(17) ;now get addr of OLD PC word
	tlo 17,(Z @)		;make it indirect
	movem 17,resume		;and save it for resuming code
	sos in.crt		;make incrit be -2
	move 17,apracs+17	;now return to user
	jrstf @resume

;Here from LEAVEC when leaving an critical section that was resumed by
;DOCRIT.  Go back and handle the interrupt
conint:	hrrzs resume		;clear indirect bit in RESUME
	pop p,@resume		;put return PC into OLD PC word
	setzm in.crt		;no longer in critical section
	movem 17,apracs+17	;now simulate interrupt dispatch
	move 17,index
	jrst intmod

;ENTERC - called by user to enter critical section
enterc:	setom in.crt		;say in critical section
	popj p,

;LEAVEC - called by user at end of critical section, to resume interrupts
leavec:	aosge in.crt		;clear flag unless an interrupt happened
	pushj p,conint		;interrupt happened, continue it
	popj p,