	Page	58,132
	Title	INT.ASM 	Interrupt Processor
;******************************************************************************
;
;   Name:	INT.ASM 	Interrupt Processor
;
;   Group:	Emulator
;
;   Revision:	1.00
;
;   Date:	January 30, 1988
;
;   Author:	Randy W. Spurlock
;
;******************************************************************************
;
;  Module Functional Description:
;
;		This module contains all the code for the Apple
;	emulator interrupt handler.
;
;******************************************************************************
;
;  Changes:
;
;    DATE     REVISION				DESCRIPTION
;  --------   --------	-------------------------------------------------------
;   1/30/88	1.00	Original
;
;******************************************************************************
	Page
;
;  Public Declarations
;
	Public	Int_Init		; Interrupt initialization routine
	Public	Int_Reset		; Interrupt reset routine
	Public	Int_Update		; Emulator interrupt update routine
	Public	Interrupt		; Interrupt processing routine
	Public	Dummy_Int		; Dummy interrupt processing routine
;
;  External Declarations
;
	Extrn	Timer_Int:Near		; Timer interrupt routine	(TIMER)
	Extrn	Timer_Init:Near 	; Timer initialization routine	(TIMER)
	Extrn	Timer_Reset:Near	; Timer reset routine		(TIMER)
	Extrn	Key_Int:Near		; Keyboard interrupt routine (KEYBOARD)
	Extrn	Emulator:Near		; Emulator entry point	      (EMULATE)
	Extrn	Error:Near		; Apple emulator error routine	(APPLE)
	Extrn	Exit:Near		; Apple emulator exit routine	(APPLE)
	Extrn	Int_Table:Word		; Interrupt jump table		 (DATA)
	Extrn	Original_Int_8:Dword	; Original interrupt 8 vector	 (DATA)
	Extrn	Original_Int_9:Dword	; Original interrupt 9 vector	 (DATA)
	Extrn	System_Flag:Byte	; Apple emulator system flag byte(DATA)
	Extrn	Emulate_Flag:Byte	; Emulator interrupt flag byte	 (DATA)
;
;  LOCAL Equates
;
MAX_INTERRUPT	Equ	08h		; Maximum interrupt count value
INT_TIMER	Equ	08h		; Timer hardware interrupt number
INT_KEY 	Equ	09h		; Keyboard hardware interrupt number
INT_MASK	Equ	7Fh		; Dummy interrupt clear mask value
;
;  Define any include files needed
;
	Include 	Macros.inc	; Include the macro definitions
	Include 	Equates.inc	; Include the equate definitions
	Include 	Strucs.inc	; Include the structure definitions
	.286c				; Include 80286 instructions
	Page
;
;  Define the emulator code segment
;
Emulate Segment Word Public 'EMULATE'   ; Emulator code segment
	Assume	cs:Emulate, ds:Nothing, es:Nothing
	Subttl	Int_Init	Interrupt Initialization
	Page	+
;******************************************************************************
;
;	Int_Init()
;
;		Save the required registers
;		Save the original interrupt 8 (Timer) vector
;		Save the original interrupt 9 (Keyboard) vector
;		Set the new interrupt 8 vector
;		Call the timer initialization routine
;		Set the new interrupt 9 vector
;		Set the interrupt patched flag
;		Restore the required registers
;		Return to the caller
;
;	Registers on Entry:
;
;		None
;
;	Registers on Exit:
;
;		None
;
;******************************************************************************
		Even			; Force procedure to even address
Int_Init	Proc	Near		; Interrupt initialization procedure
	Save	ax,bx,dx,ds,es		; Save the required registers
	mov	ah,GET_VECTOR		; Get interrupt vector function code
	mov	al,INT_TIMER		; Get timer hardware interrupt (8)
	int	DOS			; Get the current timer interrupt
	mov	Word Ptr cs:[Original_Int_8 + 0],bx
	mov	Word Ptr cs:[Original_Int_8 + 2],es
	mov	ah,GET_VECTOR		; Get interrupt vector function code
	mov	al,INT_KEY		; Get keyboard hardware interrupt (9)
	int	DOS			; Get the current keyboard interrupt
	mov	Word Ptr cs:[Original_Int_9 + 0],bx
	mov	Word Ptr cs:[Original_Int_9 + 2],es
	mov	ax,cs			; Get the current CS register value
	mov	ds,ax			; Setup DS to current CS value
	lea	dx,cs:[Timer_Int]	; Get the new timer interrupt offset
	mov	ah,SET_VECTOR		; Get set interrupt vector function code
	mov	al,INT_TIMER		; Get timer hardware interrupt (8)
	int	DOS			; Set the new timer interrupt
	call	Timer_Init		; Call the timer initialization routine
	lea	dx,cs:[Key_Int] 	; Get the new keyboard interrupt offset
	mov	ah,SET_VECTOR		; Get set interrupt vector function code
	mov	al,INT_KEY		; Get keyboard hardware interrupt (9)
	int	DOS			; Set the new keyboard interrupt
	or	cs:[System_Flag],PATCHED; Set interrupts patched flag
	Restore ax,bx,dx,ds,es		; Restore the required registers
	ret				; Return to the caller
Int_Init	Endp			; End of the Int_Init procedure
	Subttl	Int_Reset	Interrupt Reset
	Page	+
;******************************************************************************
;
;	Int_Reset()
;
;		Save the required registers
;		If interrupts have been patched
;			Call the timer reset routine
;			Restore the original interrupt 8 (Timer) vector
;			Restore the original interrupt 9 (Keyboard) vector
;		Endif interrupts not patched
;		Restore the required registers
;		Return to the caller
;
;	Registers on Entry:
;
;		None
;
;	Registers on Exit:
;
;		None
;
;******************************************************************************
		Even			; Force procedure to even address
Int_Reset	Proc	Near		; Interrupt reset procedure
	Save	ax,dx,ds		; Save the required registers
	test	cs:[System_Flag],PATCHED; Check for interrupts patched
	jz	Reset_Done		; Jump if interrupts not patched
	call	Timer_Reset		; Call the timer reset routine
	mov	ah,SET_VECTOR		; Get the set interrupt function code
	mov	al,INT_TIMER		; Get timer hardware interrupt (8)
	mov	dx,Word Ptr cs:[Original_Int_8 + 0]
	mov	ds,Word Ptr cs:[Original_Int_8 + 2]
	int	DOS			; Restore original timer interrupt
	mov	ah,SET_VECTOR		; Get the set interrupt function code
	mov	al,INT_KEY		; Get keyboard hardware interrupt (9)
	mov	dx,Word Ptr cs:[Original_Int_9 + 0]
	mov	ds,Word Ptr cs:[Original_Int_9 + 2]
	int	DOS			; Restore original keyboard interrupt
Reset_Done:
	Restore ax,dx,ds		; Restore the required registers
	ret				; Return to the caller
Int_Reset	Endp			; End of the Int_Reset procedure
	Subttl	Int_Update	Emulator Interrupt Update Routine
	Page	+
;******************************************************************************
;
;	Int_Update(RAM_Space, Registers, Address, Stack_Frame)
;
;		Save the required registers
;		If currently executing 65C02 emulator
;			If there is a pending interrupt request
;				Set the emulator interrupt flag bit
;			Endif
;		Endif
;		Restore the required registers
;		Return control to the caller
;
;	Registers on Entry:
;
;		DL    - 65C02 Accumulator
;		DH    - 65C02 processor flags
;		CL    - 65C02 Y index register
;		CH    - 65C02 X index register
;		BX    - 65C02 Stack pointer
;		SI    - 65C02 Program counter
;		DI    - Current opcode address
;		DS    - 65C02 RAM space
;		SS:SP - Stack Frame
;
;	Registers on Exit:
;
;		AX    - Destroyed
;		DH    - Emulator interrupt set if interrupt pending
;
;******************************************************************************
		Even			; Force procedure to even address
Int_Update	Proc	Near		; Emulator interrupt update procedure
	Save	bp			; Save the required registers
	mov	bp,sp			; Setup access to the stack frame
	mov	ax,cs			; Get the Emulate code segment value
	cmp	ax,ss:[bp.Current_CS]	; Check for executing in Emulate segment
	jne	Update_Exit		; Jump if NOT in the Emulate segment
	lea	ax,cs:[Emulator]	; Get emulator entry point address
	cmp	ax,ss:[bp.Current_IP]	; Check for executing 65C02 emulator
	jbe	Update_Exit		; Jump if NOT in 65C02 emulator
	test	cs:[Emulate_Flag],INT_REQUEST
	jz	Update_Exit		; Jump if no pending interrupt
	or	dh,CPU_R		; Set emulator interrupt flag bit
Update_Exit:
	Restore bp			; Restore the required registers
	ret				; Return control to the caller
Int_Update	Endp			; End of the Interrupt procedure
	Subttl	Interrupt	Interrupt Processor
	Page	+
;******************************************************************************
;
;	Interrupt(RAM_Space, Registers, Address)
;
;		Clear the emulator interrupt flag bit
;		Setup Interrupt_Counter (MAX_INTERRUPT - 1 = 7)
;		While Interrupt_Counter >= 0
;			If this interrupt bit is set
;				Jump to the correct routine for interrupt
;			Endif
;			Decrement the Interrupt_Counter
;		Endwhile
;		Go process the next opcode (Never gets here)
;
;	Registers on Entry:
;
;		DL    - 65C02 Accumulator
;		DH    - 65C02 processor flags
;		CL    - 65C02 Y index register
;		CH    - 65C02 X index register
;		BX    - 65C02 Stack pointer
;		SI    - 65C02 Program counter
;		DI    - Current opcode address
;		DS    - 65C02 RAM space
;
;	Registers on Exit:
;
;		AX    - Destroyed
;		BP    - Destroyed
;
;******************************************************************************
		Even			; Force procedure to even address
Interrupt	Proc	Near		; Interrupt processing procedure
	and	dh,Not CPU_R		; Clear emulator interrupt flag bit
	mov	ah,MAX_INTERRUPT - 1	; Get the maximum interrupt count - 1
	mov	al,cs:[Emulate_Flag]	; Get the emulator flags (Interrupt)
Interrupt_Loop:
	shr	al,1			; Check for interrupt occurred
	jnc	Next_Interrupt		; Jump if this is not the interrupt
	mov	al,ah			; Get the interrupt number
	xor	ah,ah			; Convert interrupt number to full word
	shl	ax,1			; Convert interrupt to table index
	mov	bp,ax			; Setup to go to the correct routine
	jmp	cs:[bp + Int_Table]	; Jump to the correct interrupt routine
Next_Interrupt:
	dec	ah			; Decrement the interrupt counter
	jns	Interrupt_Loop		; Jump if more interrupts to check
	jmp	di			; Go process next opcode (Never here)
Interrupt	Endp			; End of the Interrupt procedure
	Subttl	Dummy_Int	Dummy Interrupt Routine
	Page	+
;******************************************************************************
;
;	Dummy_Int(Interrupt_Number, RAM_Space, Registers, Address)
;
;		Save the required registers
;		Calculate interrupt mask value
;		Clear the pending dummy interrupt
;		Restore the required registers
;		Go process the next opcode
;
;	Registers on Entry:
;
;		DL    - 65C02 Accumulator
;		DH    - 65C02 processor flags
;		CL    - 65C02 Y index register
;		CH    - 65C02 X index register
;		BX    - 65C02 Stack pointer
;		SI    - 65C02 Program counter
;		AX    - Interrupt number (Doubled)
;		DI    - Current opcode address
;		DS    - 65C02 RAM space
;
;	Registers on Exit:
;
;		AX    - Destroyed
;
;******************************************************************************
		Even			; Force procedure to even address
Dummy_Int	Proc	Near		; Interrupt processing procedure
	Save	cx			; Save the required registers
	shr	ax,1			; Restore the interrupt number
	mov	ah,INT_MASK		; Get interrupt mask value
	mov	cl,al			; Get the interrupt number in CL
	ror	ah,cl			; Rotate interrupt mask into position
	and	cs:[Emulate_Flag],ah	; Clear the current dummy interrupt
	Restore cx			; Restore the required registers
	jmp	di			; Go process the current opcode
Dummy_Int	Endp			; End of the Dummy_Int procedure
;******************************************************************************
;
;	Define the end of the Emulator Code Segment
;
;******************************************************************************
Emulate Ends
	End				; End of the Int module
