File:  [Atari MiNT] / MiNT / src / intr.spp
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:59:03 2018 UTC (8 years, 1 month ago) by root
Branches: mint, MAIN
CVS tags: mint112, HEAD
MiNT 1.12

; Copyright 1992 Eric R. Smith

; Copyright 1993,1994 Atari Corporation

; All rights reserved.



%include "magic.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	($59e).w		; 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	($43e).w		; 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 [email protected],

; 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	($59e).w	; 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

	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	($59e).w		; 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	($59e).w		; 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


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.