; IfsInterrupt.Asm -- IFS version of interrupt handler
; CauseInterrupt, DestroyInterrupt, (+ interrupt handler)
; Copyright Xerox Corporation 1980

; last modified March 18, 1980  7:28 PM by Taft
; - save and restore interruptXJmp and interruptXPC for Extended Emulator

; Based on Interrupt.Asm, from Interrupt package,
; 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
	.XJmp=7
	.XPC=8.
	.StkMin=9.		; Old stack min
	.ACT=10.		; Active lshift 1 + carry

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

; Bcpl runtime location
	StkMin=335
; page one addresses
	base = 600		; base for page 1 addressing
	wakeupsWaiting = 452
	activeInterrupts = 453
	interruptPC = 500
	interruptXJmp = 627	; XJMP b -- interruptPC (500B) points here
	interruptXPC = 630	; real PC


; 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 2 .base
	lda 0 interruptPC-base 2
	sta 0 .PC-R 3
	lda 0 StkMin
	sta 0 .StkMin-R 3
	lda 0 interruptXJmp-base 2
	sta 0 .XJmp-R 3
	lda 0 interruptXPC-base 2
	sta 0 .XPC-R 3

	lda 0 activeInterrupts-base 2 ; 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 activeInterrupts-base 2 ; 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
	lda 2 .base
	sta 1 activeInterrupts-base 2 ; Restore active
	lda 1 .XJmp-R 3
	sta 1 interruptXJmp-base 2
	lda 1 .XPC-R 3
	sta 1 interruptXPC-base 2
	lda 1 .StkMin-R 3
	sta 1 StkMin
	lda 1 .PC-R 3
	sta 1 interruptPC-base 2
	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


.base:	base



;-----------------------------------------------------------------
.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:	wakeupsWaiting
.Active:	activeInterrupts

	.end