Source to mint/intr.spp


Enter a symbol's name here to quickly find it.

;
; This file has been modified as part of the FreeMiNT project. See
; the file Changes.MH for details and dates.
;

; Copyright 1992 Eric R. Smith
; Copyright 1993,1994 Atari Corporation
; All rights reserved.

%include "magic.i"
%include "locore.i"
;
; interrupt wrapping routines; these should just save registers and call
; the appropriate C handlers, unless speed is a major problem
;
	TEXT
;
; first, utilities for setting processor status level
;
	XDEF	_spl7
	XDEF	_spl
_spl7:
	move.w	sr,d0
	ori.w	#$0700,sr
	rts
_spl:
	move.w	4(sp),sr
	rts

	XDEF	_mint_5ms
	XDEF	_mint_timer
	XDEF	_mint_vbl
	XREF	_timeout	; C time routine
	XREF	_old_timer	; old GEMDOS time vector
	XREF	_old_vbl	; old GEMDOS vbl vector
	XREF	_old_5ms
	XREF	_build_context
	XREF	_restore_context
	XREF	_proc_clock		; controls process' allocation of CPU time
	XREF	_curproc
	XREF	_enter_kernel
	XREF	_leave_kernel
	XREF	_preempt
	XREF	_in_kernel
	XREF	_calc_load_average
	XREF	_uptimetick
	XREF	_checkbttys_vbl

; AKP: this code is hit once every 5ms; it updates the time fields of curproc.
_mint_5ms:
	move.l	a0,-(sp)
	subq.w	#1,_uptimetick
	move.l	_curproc,a0
	tst.w	_in_kernel
	bne.s	L_systime
	addq.l	#5,P_USRTIME(a0)	; update curproc->usrtime
	move.l	(sp)+,a0
	move.l	_old_5ms+8,-(sp)	; branch to old vector
	rts
L_systime:
	addq.l	#5,P_SYSTIME(a0)	; update curproc->systime
	move.l	(sp)+,a0
	move.l	_old_5ms+8,-(sp)
	rts

_mint_timer:
	movem.l	d0-d2/a0-a2,-(sp)	; save C registers
	jsr	_timeout
	movem.l	(sp)+,d0-d2/a0-a2
	move.l	_old_timer+8,-(sp)	; jump to GEMDOS time vector
	rts

_mint_vbl:
%ifndef ONLY030
	tst.w	LC_FRAME		; test longframe (AKP)
	beq.s	L_short1
%endif
	clr.w	-(sp)			; yes, long frames: push a frame word
L_short1:
	pea	L_comeback(pc)		; push fake PC
	move.w	sr,-(sp)		; push status register
	move.l	_old_vbl+8,-(sp)	; go service the interrupt
	rts

L_comeback:
	movem.l	d0-d2/a0-a2,-(sp)	; save C registers
	jsr	_checkbttys_vbl
	tst.w	_uptimetick
	bgt.s	L_no_uptime
	jsr	_calc_load_average	; Go test if it's time to update uptime
L_no_uptime:
	movem.l	(sp)+,d0-d2/a0-a2
	tst.w	_proc_clock		; has time expired yet?
	beq.s	L_expired		; yes -- maybe go switch processes
L_out:
	rte				; no -- just return

L_expired:
	btst	#5,(sp)			; user mode?
	bne.s	L_out			; no -- switching is not possible
	tst.w	LC_FLOPLCK		; test floppy disk lock variable
	bne.s	L_out			; if locked, can't switch
	tst.w	_in_kernel		; are we doing a kernel operation?
	bne.s	L_out
L_switch:
	clr.w	-(sp)			; no frame format needed
	move.l	_curproc,-(sp)
	addq.l	#P_CTXT0,(sp)			; to get &curproc->ctxt[SYSCALL]
	jsr	_build_context		; build context
	move.l	_curproc,a0
	move.l	(a0),sp			; use curproc->sysstack
	move.w	P_CTXT0+C_SR(a0),d7	; get saved int level
%ifdef ONLY030
	clr.w	-(sp)			; not a system call
%else
	move.w	#0,-(sp)		; not a system call
%endif
	jsr	_enter_kernel		; enter kernel
	addq.w	#2,sp
	move.w	sr,d1
	eor.w	d1,d7
	and.w	#$700,d7
	eor.w	d7,d1
	move.w	d1,sr			; vbl allowed again
	jsr	_preempt		; yield processor
	ori.w	#$700,sr		; spl7()
	jsr	_leave_kernel		; restore vectors
	move.l	_curproc,a0
	pea	4(a0)
	jsr	_restore_context	; back to user

;
; reset routine -- called on a warm boot. Note that TOS sends the
; address to which we should return in register a6. Also note that
; the stack pointer is in an unknown state, so we set up our own
;
	XDEF	_reset
	XREF	_init_tail		; see main.c
	XREF	_restr_intr

_reset:
	move.w	#$2700,sr		; avoid interruption here
	move.l	sp,_init_tail		; save A7
	lea	_init_tail+256,sp	; set up temporary stack
	movem.l	d0-d2/a0-a2,-(sp)	; save C registers
	jsr	_restr_intr		; restore interrupts
	movem.l	(sp)+,d0-d2/a0-a2	; restore registers
	move.l	_init_tail,sp
	jmp	(a6)			; reset again

;
; routine for doing a reboot
;
	XDEF	_reboot
_reboot:
	move.w	#$2700,sr		; avoid interrupts
	move.l	(0).w,sp		; get sp after reboot
	move.l	(4).w,a6		; get new reboot address
	jmp	_reset

;
; routine for mouse packet handling
;
	XDEF	_newmvec
	XDEF	_newjvec
	XREF	_mouse_handler
; Experimental three button mouse support (by jr@ms.maus.de,
; August 4, 1992
;
; Should work with the mice shipped with Atari's ASV or
; compatible ones (like Golden Image GI-6000). Might not work
; on ST/STE systems with older IKBD's or keyboards. The middle mouse
; button is wired to one of the joystick directions on joystick one.
;
; _newmvec is the same as before with two exceptions:
; 1. the first byte of the packet is saved for the joystick handler
; 2. the bit for the middle mouse button is ored in
;
; _newjvec hooks into the joystick vector and chains to the normal
; handler. The middle mouse button state is saved in a special
; register for _newmvec, and a 'fake' mouse packet is set up
; (by merging the last mouse packet header, or-ing in the
; middle button state and using 0/0 for the x/y increment).
;
; the faked_packet and third_button variables are declared at the
; end of this file

_newmvec:
	move.l	a0,-(sp)
	move.b	(a0),d0
	move.b	d0,faked_packet
	or.b	third_button,d0
	move.b	d0,(a0)
	jsr	_mouse_handler
	move.l	(sp)+,a0
	rts
;
; routine for joystick packet handling (used for three button mice)
;
	XDEF	_newjvec
	XREF	_oldjvec

_newjvec:
	move.l	a0,-(sp)	; save a0 on the stack
	move.b	2(a0),d0	; joystick direction
	and.b	#1,d0		; middle mouse button in lowest bit
	add.b	d0,d0		; times 4
	add.b	d0,d0
	move.b	d0,third_button	; save it for use in newmvec

	lea	faked_packet,a0	; 'our' faked mouse event
	move.b	(a0),d0
	and.b	#$3,d0		; unmask our mouse button
	or.b	#$F8,d0		; or in correct header
	or.b	third_button,d0	; or in the current status
	move.b	d0,(a0)		; write it back

	move.l	a0,-(sp)	; pass pointer to fake packet
	jsr	_mouse_handler	; to \dev\mouse handler
	addq.l	#4,sp		; pop parameter
	move.l	(sp)+,a0	; restore original a0 value
	move.l	_oldjvec,-(sp)	; jump to original joystick handler
	rts
;
; new ikbd keyboard interrupt vector
; kintr is a global variable that should be non-zero if a keyboard
; event occured
;
	XDEF	_new_ikbd
	XREF	_old_ikbd
	XREF	_kintr

_new_ikbd:
	move.w	#1,_kintr
	move.l	_old_ikbd+8,-(sp)
	rts			; jump to system interrupt routine

; Generic routine for handling any user-specified interrupts. On 68000, the
; vector number is stored in the high byte of the program counter.
;
	XDEF	_new_intr
	XDEF	_sig_user

_new_intr:
	movem.l	d0-d2/a0-a2,-(sp)	; save regs

%ifndef ONLY030
	tst.w	LC_FRAME	; is frame format on stack?
	bne.s	nvec		; yes, go use it
	bsr.s	ndummy		; push PC to stack
	nop
ndummy:	
	move.w	(sp)+,d0	; pop hi(PC) to d0
	addq.w	#2,sp		; pop lo(PC) off stack
	lsr.w	#8,d0		; move hi byte to vector number
	bra.s	ngot		; continue
nvec:
%endif
	move.w	30(sp),d0	; get frame word
	lsr.w	#2,d0		; move vector offset to vector number
ngot:
	move.w	d0,-(sp)	; push vector offset
	jsr		_sig_user	; send signal
	addq.w	#2,sp			; pop vector offset
	movem.l	(sp)+,d0-d2/a0-a2	; restore regs
	rte

;
; simple signal handlers
; global variables referenced:
; in_kernel: (main.c): flag to indicate that we're in the MiNT kernel
; sig_routine: (signal.c): pointer to which signal catching routine to
;          call (e.g. for SIGBUS, or whatever)
;
	XDEF	_new_bus,_new_addr,_new_ill,_new_divzero,_new_priv,_new_linef
	XDEF	_new_trace,_new_chk,_new_trapv,_new_fpcp,_new_mmu,_new_pmmuacc
	XDEF	_new_uninit,_new_spurious,_new_format,_new_cpv
	XREF	_in_kernel,_sig_routine
	XREF	_sigbus,_sigaddr,_sigill,_sigfpe,_sigpriv,_sigtrap
	XREF	_haltformat,_haltcpv
	XREF	_sig_exc
	XREF	_mcpu
	
;
; New bus error handler for memory protection: get the ssp and
; put it in the proc structure before calling
; _sigbus.  When the bus error happens in the kernel we don't save
; any contexts.
; We don't want to mess up any registers here because we might bring the
; page in and RTE.
;

_new_bus:
%ifndef ONLY030
	move.w	#$8,_sig_exc
	cmp.l	#30,_mcpu
	bne.s	noMMU
%endif
	move.l	#_mmu_sigbus,_sig_routine
%ifndef ONLY030
	bra.s	Do_sig
noMMU:
	move.l	#_nommu_sigbus,_sig_routine
%endif
Do_sig:
	move.l	a0,-(sp)		; save a0
	move.l	_curproc,a0
	move.l	sp,P_EXCSSP(a0)
	addq.l	#4,P_EXCSSP(a0)
	move.l	6(sp),P_EXCPC(a0)
	move.l	(sp)+,a0

	tst.w	_in_kernel		; are we already in the kernel?
	bne.s	Kernel			; yes
	move.w	_sig_exc,-(sp)
	move.l	_curproc,-(sp)
	addq.l	#4,(sp)			; push offset of save area
	jsr	_build_context
	move.l	_curproc,a4
	move.l	(a4),sp			; put us in the system stack
%ifdef ONLY030
	clr.w	-(sp)			; not a GEMDOS call
%else
	move.w	#0,-(sp)		; not a GEMDOS call
%endif
	jsr	_enter_kernel		; set up kernel vectors
	addq.w	#2,sp
	move.l	_sig_routine,a1		; get signal handling routine
	jsr	(a1)			; go do it
	ori.w	#$0700,sr		; spl7()
	jsr	_leave_kernel		; leave kernel
	addq.w	#4,a4			; get context save area address
	move.l	a4,-(sp)		; push it
	jsr	_restore_context	; restore the context
;
; here's what we do if we already were in the kernel
;
Kernel:
	movem.l	d0-d2/a0-a2,-(sp)	; save reggies
	move.l	_sig_routine,a1		; get handler
	jsr	(a1)			; go do it
	movem.l	(sp)+,d0-d2/a0-a2
; 68000 processor bug: rte right after movem can eat interrupts...
%ifndef ONLY030
	nop
%endif
	rte

;
; _mmu_sigbus: a pre-handler for _sigbus.  Check the reason for the bus
; error and report if it was a real access fault.
;
_mmu_sigbus:
	move.l	a2,-(sp)
	move.l	_curproc,a0
	move.l	P_EXCSSP(a0),a1		; a1 is now exception_ssp
	move.w	$A(a1),d0		; d0 is SSR
	move.l	$10(a1),a1		; a1 is the access address
	move.l	a1,P_EXCADDR(a0)	; save the access address

	ptestr	d0,(a1),#7,a2		; a2 is the table address
	move.l	a2,P_EXCTBL(a0)		; save table address in curproc
	pmove	mmusr,P_EXCMMUSR(a0)	; save resulting mmusr in curproc
	move.l	(sp)+,a2
	jmp	_sigbus		; chain to bus-error handler
%ifndef ONLY030
;
; _nommu_sigbus: handler for bus errors on machines without MMU

_nommu_sigbus:
	move.l	_curproc,a0
	move.l	P_EXCSSP(a0),a1
	lea	$10(a1),a1		; point to access address
	tst.w	LC_FRAME		; test longframe
	beq.s	NOMMU1
	addq.w	#8,a1			; on 68000, address is 8 bytes further
NOMMU1:
	move.l	(a1),P_EXCADDR(a0)	; save the access address
	jmp	_sigbus
%endif

_new_addr:
%ifndef ONLY030
	move.w	#$c,_sig_exc
%endif
	move.l	#_sigaddr,_sig_routine
	bra	Do_sig
_new_ill:
%ifndef ONLY030
	move.w	#$10,_sig_exc
%endif
	move.l	#_sigill,_sig_routine
	bra	Do_sig
_new_divzero:
%ifndef ONLY030
	move.w	#$14,_sig_exc
%endif
	move.l	#_sigfpe,_sig_routine
	bra	Do_sig
_new_linef:
%ifndef ONLY030
	move.w	#$2c,_sig_exc
%endif
	move.l	#_sigill,_sig_routine
	bra	Do_sig
_new_chk:
%ifndef ONLY030
	move.w	#$18,_sig_exc
%endif
	move.l	#_sigfpe,_sig_routine
	bra	Do_sig
_new_trapv:
%ifndef ONLY030
	move.w	#$1c,_sig_exc
%endif
	move.l	#_sigfpe,_sig_routine
	bra	Do_sig
_new_fpcp:
; don't set _sig_exc - only needed for 68000 vectors
	move.l	#_sigfpe,_sig_routine
	bra	Do_sig
_new_mmu:
; don't set _sig_exc - only needed for 68000 vectors
	move.l	#_sigill,_sig_routine
	bra	Do_sig
_new_pmmuacc:
; don't set _sig_exc - only needed for 68000 vectors
	move.l	#_sigbus,_sig_routine
	bra	Do_sig
_new_uninit:
%ifndef ONLY030
	move.w	#$3c,_sig_exc
%endif
	move.l	#_sigbus,_sig_routine
	bra	Do_sig
_new_spurious:
%ifndef ONLY030
	move.w	#$60,_sig_exc
%endif
	move.l	#_sigbus,_sig_routine
	bra	Do_sig
_new_format:
	move.l	#_haltformat,_sig_routine
	bra	Do_sig
_new_cpv:
	move.l	#_haltcpv,_sig_routine
	bra	Do_sig

	XREF	_old_priv		; old privilege violation vector
_new_priv:
%ifndef ONLY030
	move.w	#$20,_sig_exc
%endif
	move.l	#_sigpriv,_sig_routine
%ifndef ONLY030
	tst.w	LC_FRAME		; 68000s always get SIGPRIV
	beq	Do_sig
%endif
	movem.l	d0/a0,-(a7)
	move.l	10(a7),a0		; fetch exception address
	move.w	(a0),d0
	and.w	#$ffc0,d0		; partially decode move sr,...
	cmp.w	#$40c0,d0		; and test it
	movem.l	(a7)+,d0/a0		; preserves the flags
	bne	Do_sig			; doesn't look like sr,...
	move.l	_old_priv+8,-(sp)	; let our parent handle it
	rts

; XBRA vectors from main.c
	XREF	_old_dos,_old_bios,_old_xbios
	XREF	_old_divzero,_old_chk,_old_trapv

_new_trace:
	btst	#5,(a7)			; only check when called from supervisor mode
	beq.s	S_1
	cmp.l	#_old_dos+12,2(a7)	; lets not trace the kernel !
	beq.s	S_2
	cmp.l	#_old_xbios+12,2(a7)
	beq.s	S_2
	cmp.l	#_old_bios+12,2(a7)
	beq.s	S_2
	cmp.l	#_old_divzero+12,2(a7)
	beq.s	S_2
	cmp.l	#_old_trapv+12,2(a7)
	beq.s	S_2
	cmp.l	#_old_chk+12,2(a7)
	beq.s	S_2
; add any other non-traceable entities here...

S_1:	move.w	#$24,_sig_exc
	move.l	#_sigtrap,_sig_routine
	bra	Do_sig

S_2:	and.w	#$3fff,(a7)		; clear both trace bits
	rte				; and re-start the handler

;
; BIOS disk vectors for pseudo-disks like U: and X:; these are present
; just in case some program (foolishly) attempts to access these drives
; directly and gets horribly confused
;
	XREF	_old_getbpb	; old Getbpb vector
	XREF	_old_mediach	; old Mediach vector
	XREF	_old_rwabs	; old Rwabs vector
	XREF	_aliasdrv	; array of drive aliases
	XDEF	_new_getbpb
	XDEF	_new_mediach
	XDEF	_new_rwabs

_new_getbpb:
	move.w	4(sp),d0	; check the drive
	cmp.w	#$1f,d0		; legal drive?
	bhi.s	noalias0	; no
	move.w	d0,d1		; get index
	add.w	d0,d1		; convert to index
	lea	_aliasdrv,a0
	move.w	0(a0,d1.w),d1	; alias drive?
	beq.s	noalias0
	move.w	d1,d0
	subq.w	#1,d0		; adjust for aliasdrv base of '@'
	cmp.w	#$1f,d0		; is this a legal drive?
	bhi.s	nobpb		; no -- ignore it
noalias0:
	cmp.w	#$14,d0		; drive U:?
	beq.s	nobpb		; yes, no BPB available
	move.l	_old_getbpb+8,a0	; not our drive
	jmp	(a0)		; call the old vector for it
nobpb:
	moveq.l	#0,d0		; 0 means "no BPB read"
	rts

_new_mediach:
	move.w	4(sp),d0	; check the drive
	cmp.w	#$1f,d0		; legal drive?
	bhi.s	noalias1	; no
	move.w	d0,d1		; get index
	add.w	d0,d1		; convert to index
	lea	_aliasdrv,a0
	move.w	0(a0,d1.w),d1	; alias drive?
	beq.s	noalias1
	move.w	d1,d0
	subq.w	#1,d0		; adjust for aliasdrv base
	cmp.w	#$1f,d0		; legal drive?
	bhi.s	nobpb		; no -- ignore it
noalias1:
	cmp.w	#$14,d0		; drive U:?
	beq.s	nochng		; yes, no change
	move.l	_old_mediach+8,a0	; not our drive
	jmp	(a0)		; call the old vector for it
nochng:
	moveq.l	#0,d0		; 0 means "definitely no change"
	rts

_new_rwabs:
	move.w	$e(sp),d0	; check the drive
	cmp.w	#$1f,d0		; legal drive?
	bhi.s	noalias2	; no
	move.w	d0,d1		; get index
	add.w	d0,d1		; convert to index
	lea	_aliasdrv,a0
	move.w	0(a0,d1.w),d1	; alias drive?
	beq.s	noalias2
	move.w	d1,d0
	subq.w	#1,d0		; adjust for aliasdrv base
	cmp.w	#$1f,d0		; legal drive?
	bhi.s	nobpb		; no -- ignore it
noalias2:
	cmp.w	#$14,d0		; drive U:?
	beq.s	rwdone		; yes, fake it
	move.l	_old_rwabs+8,a0	; not our drive
	jmp	(a0)		; call the old vector for it
rwdone:
	moveq.l	#0,d0		; 0 means "successful operation"
	rts

	DATA
; buffer for faked mouse packet (actually only 3 bytes)

faked_packet:
	dc.l	0

; here we store the additional button state
third_button:
	dc.w	0

	END