;****************************************************************
;**           :
;** Project   : Personal Logic Debugger (PLD)
;** Filename  : INT.ASM
;** Author    : Don Lekei
;** Status    : Experimental
;** Date      : 08/27/93
;** Purpose   : Interrupt handler
;**           :
;****************************************************************
;
;**********************************************************************
;* Interrupt vector processor
;*
;* This MUST be the first code in segment CODE.  Jumps to the appropriate
;* handler for the detected enabled interrupt.  The order of processing
;* determines interrupt priority. Individual routines are responsible
;* for permitting further interrupts.
;*
;* >>> THIS CODE MUST BE RECURSABLE AND MUST NOT AFFECT W OR STATUS! <<<
;*     ============================================================
;*
;**********************************************************************

	.seg CODE

	.if (* != _INTVEC)	;make sure this code is in the right place
	 .error "Interrup vector address",$a
	.endif

PROCINT:
	.if (PICDEVICE == 1671)
;--- A/D interrupt ---
	btfss	ADIE		;skip if interrupt enabled
	goto	_not_iad	;not enabled
	btfsc	ADIF		;not A/D interrupt
	goto	I_ADC		;A/D Interrupt!
_not_iad:
	.endif

;--- RTCC interrupt ---
	btfss	RTIE		;skip if interrupt enabled
	goto	_not_irt	;not enabled
	btfsc	RTIF		;not RTCC interrupt
	goto	I_RTCC		;A/D Interrupt!
_not_irt:
;--- RB Change interrupt ---
	btfss	RBIE		;skip if interrupt enabled
	goto	_not_irb		;not enabled
	btfsc	RBIF		;not RB change interrupt
	goto	I_RB		;PORT B change Interrupt!
_not_irb:
;--- RB0 INT interrupt ---
	btfss	INTE		;skip if interrupt enabled
	goto	_not_int	;not enabled
	btfsc	INTF		;not INT interrupt
	goto I_INT		;RB0 edge interrupt
_not_int:
	.if (PICDEVICE == 1684)
;--- EEPROM interrupt ---
	btfss	EEIE		;skip if interrupt enabled
	goto	_not_iee	;not enabled
	btfsc	EEIF		;not EEPROM interrupt
	goto	I_EE		;EEPROM Interrupt!
_not_iee:
	.endif

	retfie


;**********************************************************************
;* RB0 edge interrupt (unused)
;**********************************************************************

I_INT:
	CLB	INTE		;clear unwanted enable!
	retfie			;exit

;**********************************************************************
;* RB CHANGE interrupt (unused)
;**********************************************************************

I_RB:
	CLB	RBIE		;clear unwanted enable!
	retfie			;exit

;**********************************************************************
;* RTCC overflow interrupt handler
;**********************************************************************
	.seg	REGS	;file space used by this function
_RT_WSAVE:	.ds 1	;w register save
_RT_STAT:	.ds 1	;STATUS save
	.seg	CODE

I_RTCC:
	CLB	RTIE		;disable interrupt to prevent recursion
	SEB	GIE		;enable other interrupts
	CLB	RTIF            ;clear flag
	movwf	_RT_WSAVE	;save W
	movfw	STATUS		;get STATUS
	movwf	_RT_STAT	;save STATUS

	movfw	_RT_STAT	;get STATUS
	movwf   STATUS		;restore saved status
	swapf	_RT_WSAVE	;restore W without affecting status
	swapf	_RT_WSAVE,W	;w is restored
	CLB	GIE		;disable interrupts
	SEB	RTIE		;re-enable this one
	retfie			;exit (re-enabling interrupts)


;**********************************************************************
;* A/D Conversion complete interrupt
;*
;* This is used as the main heartbeat to operate the LCD display, so the
;* RTCC is free to be a pulse counter. In a 16c84 application, this would
;* need to be moved to the RTCC interrupt.  Note: timing is approximate,
;* but close enough for lcd-etc.
;* 
;* Runs 3 pseudo-interrupts using TICKER as a state driver:
;* 
;*      when TICKER < 0 : TICKER counts UP for I_KBD invocations. 
;* 
;*      when TICKER > 0 : TICKER counts down for I_LOGIC calls.
;* 
;*      when TICKER = 0 : TICKER is set to TICK_TIME before I_LCD call (3 ms).
;*      (I_LCD schedules I_KBD when appropriate)
;* 
;**********************************************************************

TICK_CYCS	= 100		;# CPU cycles per tick (80+18+1)

TICK_TIME	= 3*MSEC + (TICK_CYCS/2) / TICK_CYCS	;LCD Timeout  

	.seg	REGS	;file space used by this function
_ADC_WSAVE:	.ds 1	;w register save
_ADC_STAT:	.ds 1	;STATUS save
TICKER:		.ds 1   ;countdown for heartbeat / up for KBD 98 cycle steps
B.TICKDIR	= 7,TICKER	;1=KBD, count up. 0=LCD, count down
	.seg	CODE

	                        ;           Cycles from interrupt ~= 5(+~4?)
I_ADC:                          ;                                    
	CLB	ADIE		;disable interrupt to prevent recursion  9
	SEB	GIE		;enable other interrupts                 10
	CLB	ADIF		;                                        11
	clb	RP0		;make sure we get the PORTS!             12
	movwf	_ADC_WSAVE	;save W                                  13
	movfw	STATUS		;get STATUS                              14
	movwf	_ADC_STAT	;save STATUS                             15
	movfw	ADRES           ;get current analog value                16
	movwf	VSENSE		;save voltage                            17
	btfss	B.TICKDIR                                                18
	goto	_iad_dn 	;count down... lcd state                 19,20
	seb	GO		;restart A/D
	incfsz	TICKER		;count keyboard states
	goto	I_KBD		;do Keyboard scan step for negative (-1)

	incf	TICKER		;force LCD STATE
_iad_dn:
	seb	GO		;restart A/D
	decfsz	TICKER          ;
	goto	I_LOGIC		;middle tick... do logic probe
	seb	B.NEWLOGIC	;flag - first new cycle
	movlw	TICK_TIME	;init TICKER
	movwf	TICKER		;set ticker
	decfsz	LCD_STATE	;next LCD_STATE
	goto	I_LCD	        ;do LCD scan
	movlw	MAX_LCD_STATE+1 ;set next LCD state
	movwf	LCD_STATE	;init for next time around
	movlw	-2              ;force kbd scan next time
	movwf	TICKER		;set state to -2 to cause a KBD scan
	goto	TICK_EXIT	;goto TICK_EXIT (actual code is in KBD rtn)

;
;TICK_EXIT is done as a macro to make it simpler to move from 16c71 to -84
;since this exit is interrupt specific. It is invoked by each of the sub-
;interrupts to exit.
;

TICK_EXIT .macro
	movfw	_ADC_STAT	;get STATUS                          
	movwf   STATUS		;restore saved status
	swapf	_ADC_WSAVE	;restore W without affecting status
	swapf	_ADC_WSAVE,W	;w is restored
	CLB	GIE		;disable interrupts
	SEB	ADIE		;re-enable this one
	retfie			;exit
	.bank 0			;reset bank tracking
	.endm

	.bank 0			;reset bank tracking
