; Interrupt.Asm
; CauseInterrupt, DestroyInterrupt, (+ interrupt handler)
; Copyright Xerox Corporation 1979
; Copyright Xerox Corporation 1979

; last modified September 4, 1979  2:30 PM by Taft


	.ent CauseInterrupt
	.ent DestroyInterrupt
	.ent interruptPrologue
	.ent interruptsActive
	.ent interruptFinish
	.ent savedUserFinishProc

	.bext lvUserFinishProc

	.srel
CauseInterrupt:		.Cause
DestroyInterrupt:	.Destroy
interruptPrologue:	.Prologue
interruptsActive:	0	; Bits that I have turned on!
interruptFinish:	.IntFin
savedUserFinishProc:	-1	; -1 means nothing yet saved

	.zrel
InterruptEntry:		.IntEnt

	.nrel
	0			; Sacrifice to Bldr



; Offsets of things in IST (Interrupt Stack); same as in InterruptInit.Bcpl

; Prologue is in 0, 1
  R=2				; Point where AC3 will point
	.AC0=2			; Machine state....
	.AC1=3
	.AC2=4
	.AC3=5
	.PC=6
	.StkMin=7		; Old stack min
	.ACT=8.			; Active lshift 1 + carry

; Context to run the guy in:
	.NMask=9.		; New interrupt mask
	.NStack=10.
	.NStkMin=11.
	.InitPC=12.		; Procedure to call
	.StkBot=13.		; Bottom of stack -- place 335 will point to.

; Bcpl runtime location
	StkMin=335


; The following 2 prologue words are recorded in the IST.
; When an interrupt fires, control transfers to the IST, which
; saves AC3 and jsr's to common code for saving the remainder
; of the state

.Prologue:
	sta 3,.Prologue+.AC3	; State-saving prologue in each IST
	jsr @InterruptEntry


;-----------------------------------------------------------------
.IntEnt:
;-----------------------------------------------------------------
	sta 2,.AC2-R,3		; Common code to save state
	sta 1,.AC1-R,3
	sta 0,.AC0-R,3
	lda 0,@.intPC
	sta 0,.PC-R,3
	lda 0,StkMin
	sta 0,.StkMin-R,3

	lda 0,@.Active		; Save current active interrupts
	movl 0 1		; Save carry (bit 0 of active unused)
	sta 1,.ACT-R,3
	lda 1,.NMask-R,3	; Interrupts to leave on.
	and 1,0			; Compute new active
	sta 0,@.Active		; And put it down.
	eir			; Now can proceed.

; Set up new context, and call the specified procedure.
; Interrupt will be dismissed when procedure returns.

	lda 2,.NStkMin-R,3
	sta 2,StkMin
	lda 2,.NStack-R,3
	jsr @.InitPC-R,3	; Call procedure
	 0			; With no arguments.

; Restore state that was saved in the IST, and dismiss interrupt.

	lda 3 0 2		; Recover IST pointer
	dir			; Prepare to restore state
	lda 1,.ACT-R,3
	movzr 1 1		; Restore carry
	sta 1,@.Active		; Restore active
	lda 1,.StkMin-R,3
	sta 1,StkMin
	lda 1,.PC-R,3
	sta 1,@.intPC
	lda 0,.AC0-R,3
	lda 1,.AC1-R,3
	lda 2,.AC2-R,3
	lda 3,.AC3-R,3
	bri			; Off to see the world


.intPC:	500			; Place PC saved on interrupt
.Active: 453			; Active interrupts word



;-----------------------------------------------------------------
.IntFin:
;-----------------------------------------------------------------
; called on Finish or Abort to disable any interrupts that
; we may have turned on.
	sta 3 1 2
	lda 0,@.IntAct		; Turn off interrupts that are on.
	jsr .Destroy
	 1
	lda 0,@.savedUserFinishProc  ; Restore old finish routine
	lda 3,@.lvUserFinishProc
	sta 0,0,3
	lda 3 1 2
	jmp 1 3

.IntAct: interruptsActive
.savedUserFinishProc: savedUserFinishProc
.lvUserFinishProc: lvUserFinishProc



;-----------------------------------------------------------------
.Destroy:
;-----------------------------------------------------------------
; DestroyInterrupt(mask)
; Turn off interrupt channel(s) designated by mask
	com 0,0			; Prepare to "and" with active
	dir
	lda 1,@.Active
	and 0,1
	sta 1,@.Active		; All gone!
	eir
	lda 1 @.IntAct		; Update our record
	and 0 1
	sta 1 @.IntAct
	jmp 1,3			; Return



;-----------------------------------------------------------------
.Cause:
;-----------------------------------------------------------------
; CauseInterrupt(mask)
; Initiate interrupt on channel(s) designated by mask
	com 0,0		; Prepare to "or" with wakeups waiting
	dir
	lda 1,@.Wakeups
	and 0,1
	adc 0,1
	sta 1,@.Wakeups
	eir
	jmp 1,3

.Wakeups:	452


;-----------------------------------------------------------------
; DisableInterrupts() and EnableInterrupts()
;-----------------------------------------------------------------
; These are provided here so they are still available
; even if you junta the ones in the operating system

	.ent DisableInterrupts, EnableInterrupts

	.srel
DisableInterrupts:  .Disable
EnableInterrupts:  .Enable
	.nrel

.Disable: #61013	; return true if they were on
	 mkzero 0 0 skp
	mkminusone 0 0
	jmp 1,3

.Enable: eir
	jmp 1,3

	.end