;======================================================================
;
;	SetCPU V1.60
;	by Dave Haynie, April 13, 1990
;	Released to the Public Domain
;
;	IDENTS.A MODULE
;
;	This module contains the functions that ID the CPU, MMU, and FPU
;	type indtalled in the system.
;
;======================================================================

	include "setcpu.i"

	cseg

	xdef	_GetCPUType	; ID the CPU
	xdef	_GetMMUType	; ID the MMU
	xdef	_GetFPUType	; ID the FPU

;======================================================================
;
;	This routine checks CPU flags early in ExecBase for extended
;	CPUs that test as a 68020 under 1.3.  If these flags are set,
;	the actual CPU/MMU type test can be skipped.
;
;======================================================================

TestFlags:
	moveq.l	#0,d0
	btst.b	#AFB_68040,ATNFLGS(a6)	; Does the OS think an '040 is here?
	beq NoEarly40
	move.l	#68040,d0
	rts
NoEarly40:
	btst.b	#AFB_68030,ATNFLGS(a6)	; Does the OS think an '030 is here?
	beq	NoEarly30
	move.l	#68030,d0		; Sure does...
NoEarly30:
	rts


;======================================================================
;
;	This function returns the type of the CPU in the system as a
;	longword: 68000, 68010, 68020, or 68030.  The testing must be done
;	in reverse order, in that any higher CPU also has the bits set for
;	a lower CPU.  Also, since 1.3 doesn't recognize the 68030, if I
;	find the 68020 bit set, I always check for the presence of a 
;	68030.
;
;	This routine should be the first test routine called under 1.2
;	and 1.3.
;
;	ULONG GetCPUType();
;
;======================================================================

_GetCPUType:
	move.l	4,a6			; Get ExecBase
	jsr	TestFlags		; Check extended CPU types
	cmp.l	#0,d0
	beq	CPURealTest
	rts
CPURealTest:
	movem.l	a4/a5,-(sp)		; Save this register
	btst.b	#AFB_68020,ATNFLGS(a6)	; Maybe a 68020
	bne	FindReal32
	btst.b	#AFB_68010,ATNFLGS(a6)	; Maybe a 68010?
	bne	Found10
	move.l	#68000,d0		; Just a measley '000
	movem.l	(sp)+,a4/a5
	rts
Found10:
	move.l	#68010,d0		; Yup, we're an '010
	movem.l	(sp)+,a4/a5
	rts
FindReal32:
	move.w	LIB_VERSION(a6),d0	; Are we in 2.0?
	cmp.w	#36,d0			; If so, we don't need to test
	bge	No40

	lea.l	SuperGCT,a5		; Get the start of the supervisor code
	CALLSYS	Supervisor

	btst.l	#CIB_BURST,d0		; Do we have a set burst bit?
	beq	No30
	move.l	#68030,d0		; It's a 68030
	bset.b	#AFB_68030,ATNFLGS(a6)
	movem.l	(sp)+,a4/a5
	rts
No30:	
	btst.l	#CIB_ENABLE40,d1	; Do we have 040 cache enable?
	beq	No40
	move.l	#68040,d0		; It's a 68040
	bset.b	#AFB_68040,ATNFLGS(a6)
	movem.l	(sp)+,a4/a5
	rts
No40:
	move.l	#68020,d0		; Guess we're a plain old '020
	movem.l	(sp)+,a4/a5
	rts

	; This routine tries to set a few interesting CACR bits, and
	; returns the actual register value that took in d0.
SuperGCT:
	MOVEC_	cacr,d1			; Get the cache register
	move.l	d1,d0			; Make a copy
	bset.l	#CIB_BURST,d0		; Set the inst burst bit 030
	bclr.l	#CIB_ENABLE,d0		; Clear the inst cache bit 030
	bset.l	#CIB_ENABLE40,d0	; Set the inst cache bit 040
	MOVEC_	d0,cacr			; Try to set the CACR
	MOVEC_	cacr,d0			; Save the real value
	MOVEC_	d1,cacr			; Restore it
	rte

;======================================================================
;
;	This function returns 0L if the system contains no MMU, 
;	68851L if the system does contain an 68851, or the CPU number
;	for CPUs with integral CPUs.
;
;	This routine seems to lock up on at least some CSA 68020 
;	boards, though it runs just fine on those from Ronin and 
;	Commodore, as well as all 68030 boards it's been tested on.
;
;	ULONG GetMMUType()
;
;======================================================================

_GetMMUType:
	move.l	4,a6			; Get ExecBase
	jsr	TestFlags		; Check extended CPU types
	cmp.l	#0,d0
	beq	MMURealTest
	rts

	; For any other machine, a real test must be done.  The test will
	; try an MMU instruction.  The instruction will fail unless we're
	; on a "bogus MMU" system, where the FPU responds as an MMU.
MMURealTest:
	movem.l	a3/a4/a5,-(sp)		; Save this stuff
	move.l	#0,a1	
	CALLSYS	FindTask		; Call FindTask(0L)
	move.l	d0,a3

	move.l	TC_TRAPCODE(a3),a4	; Change the exception vector
	move.l	#MMUTraps,TC_TRAPCODE(a3)
	
	move.l	#-1,d0			; Try to detect undecode FPU
	subq.l	#4,sp			; Get a local variable
	PMOVE_	tc,(sp)			; Let's try an MMU instruction
	addq.l	#4,sp			; Return that local
	move.l	a4,TC_TRAPCODE(a3)	; Reset exception stuff
	movem.l	(sp)+,a3/a4/a5		; and return the registers
	rts

	; This is the exception code.  No matter what machine we're on,
	; we get an exception.  If the MMU's in place, we should get a
	; privilige violation; if not, an F-Line emulation exception.
MMUTraps:
	move.l	(sp)+,d0		; Get Amiga supplied exception #
	cmpi	#11,d0			; Is it an F-Line?
	beq	MMUNope			; If so, go to the fail routine
	move.l	#68851,d0		; We have MMU
	addq.l	#4,2(sp)		; Skip the MMU instruction
	rte
MMUNope:
	moveq.l	#0,d0			; It dinna woik,
	addq.l	#4,2(sp)		; Skip the MMU instruction
	rte

;======================================================================
;
;	This function returns the type of the FPU in the system as a
;	longword: 0 (no FPU), 68881, or 68882.
;
;	ULONG GetFPUType();
;
;======================================================================

_GetFPUType:
	move.l	4,a6			; Get ExecBase
	btst.b	#AFB_68040,ATNFLGS(a6)	; Is there a 68040 here?
	beq	Look4FPU
	move.l	#68040,d0
	rts
Look4FPU:	
	move.l	a5,-(sp)		; Save this register
	btst.b	#AFB_68881,ATNFLGS(a6)	; Does the OS think an FPU is here?
	bne	FPUHere
	moveq.l	#0,d0			; No FPU here, dude
	move.l	(sp)+,a5		; Give back the register
	rts
FPUHere:
	btst.b	#AFB_68882,ATNFLGS(a6)	; How's about an '882?
	beq	FPUTest
	move.l	#68882,d0		; Sure does...
	move.l	(sp)+,a5
	rts
FPUTest:
	move.w	LIB_VERSION(a6),d0	; Are we in 2.0?
	cmp.w	#36,d0			; If so, we don't need to test
	blt	FPUTrap
	move.l	#68881,d0
	move.l	(sp)+,a5
	rts
FPUTrap:
	lea.l	FPUSuper,a5		; Get the start of the supervisor code
	CALLSYS	Supervisor
	move.l	(sp)+,a5		; Give back registers
	rts
FPUSuper:
	move.l	#68881,d0		; Assume we're a 68881
	fsave	-(sp)			; Test and check
	moveq.l	#0,d1
	move.b	1(sp),d1		; Size of this frame
	cmpi	#$18,d1
	beq FPU81
	move.l	#68882,d0		; It's a 68882
	bset.b	#AFB_68882,ATNFLGS(a6)
FPU81:
	frestore (sp)+			; Restore the stack
	rte

	end

