; This file belongs to FreeMiNT. It is not a part of the original MiNT distribution.
; 
; Hardware detection for MiNT.
; 
; This code _must_ be compiled as -m68030
; 
; begin 11/98
; last change 1999-06-11
; 
; Author: J”rg Westheide - <joerg_westheide@su.maus.de>
; 
; please send suggestions or bug reports to me or
; the MiNT mailing list
; 
; Detection of Harun Scheutzows ST-ESCC (Joerg)
; Detection of CPU and FPU model (Draco)
;

	XREF _detect_hardware

	TEXT

;
; This function detects peripheral hardware components and returns a 
; bit vector of the found components. A set bit indicates, that a 
; component was found. The meaning of the bits are:
; 
;   bit  component
; --------------------
;    0   ST-ESCC
;  1-31  reserved (=0)
;

	TEXT

_detect_hardware:

	moveq	#0,d0				; initialize return value
	
;**** detect ST-ESCC (Harun Scheutzow's extension to normal ST(E)s providing modem2 and serial2) ****

	move.l	sp,a1				; save stack pointer
	move.l	(8).w,a0			; save bus error vector
	move.l	#no_stescc,(8).w		; set temporary new bus error vector
	nop					; flush write pipeline (>= 040)
	move.w	SR,d1

; it was ori.w #0700,SR, but i don't think this was really meant so.
; 700 dec is $02bc hex, so it really raised the IPL, but MFP
; interrupts were't disabled (they're IPL 5 IIRC).

	ori.w	#$0700,SR			; disable interrupts

; The next instruction will cause a bus error if there is no 
; ST-compatible MFP, which makes the odd addresses $FFFFFA01 -
; $FFFFFA3F accessible and is neccessary for the ST-ESCC extension
	
	move.b	#3,($FFFFFA31).w		; select register 3, channel B
	
; If we reach the following instruction we have a ST-compatible MFP.
; If there is an ST-ESCC we have already selected register 3 of channel B,
; otherwise we wrote the #3 to "nowhere" and will read a $FF from there
	
	tst.b	($FFFFFA31).w			; register is always 0 if ST-ESCC present
	bne	no_stescc			; no -> no ST-ESCC present
	move.w	#$FA35,_ControlRegA+2		; set register adresses to ST-ESCC's
	move.w	#$FA37,_DataRegA+2
	move.w	#$FA31,_ControlRegB+2
	move.w	#$FA33,_DataRegB+2
	bset	#$00,d0				; mark ST-ESCC present
no_stescc:					; bus error occured or reg 3 != 0 -> ST-ESCC not present
	move.w	d1,SR				; enable interrupts
	move.l	a0,(8).w			; restore  bus error vector
	nop					; flush write pipeline (>= 040)
	move.l	a1,sp				; restore stack pointer

;**** next detection should start here

	rts

	DATA

;**** variables to set in ST-ESCC detection ****

	XDEF _ControlRegA
	XDEF _DataRegA
	XDEF _ControlRegB
	XDEF _DataRegB

_ControlRegA:	dc.l $FFFF8C81
_DataRegA:	dc.l $FFFF8C83
_ControlRegB:	dc.l $FFFF8C85
_DataRegB:	dc.l $FFFF8C87

	TEXT
;
; CPU detection, experimental (draco@atari.org).
;
; Return value:
;
; $0000 - 68000
; $000a - 68010
; $0014 - 68020
; $001e - 68030
; $0028 - 68040
; $003c - 68060
;

	XDEF	_detect_cpu

_detect_cpu:	
	move.l	($10).w,a1	; save the illegal instr. exception vector
	move.l	($f4).w,a2	; save the unimplemented instr. exception vector
	lea	exit(PC),a0
	move.l	a0,($10).w	; set either vector	
	move.l	a0,($f4).w
	move.l	sp,a0		; save the ssp
	nop			; eventually flush pipelines

; on 68000 we try out a `move from CCR'.

	clr.l   d0              ; assume 68000
	move.w	ccr,d0		; legal on 68010+
	moveq	#$0a,d0

; CACR is present only in 68020+

	movec	cacr,d1		; get cache control register
	move.l	d1,d2		; hold a copy for later
	ori.w	#$8100,d1	; enable '030 data and '040 instruction caches
	movec	d1,cacr		; set new cache controls
	movec	cacr,d1		; read it back to check the effects
	movec	d2,cacr		; restore original CACR settings
	tst.w	d1		; if 15th bit was set, this is a 68040+
	bmi.s	x040
	moveq	#$14,d0		; assume 68020
	btst	#$08,d1		; check if 68030 data cache was enabled
	beq.s	exit		; a zero here means no data cache, i.e. 68020
	moveq	#$1e,d0		; data cache enabled means 68030
	bra.s	exit

; 68040 or 68060. Quad word mulu test.

x040:	moveq	#$3c,d0		; assume 68060
	dc.l	$4c102401	; mulu.l (a0),d1-d2
	moveq	#$28,d0		; no fault -> this is 68040
exit:	move.l	a2,($f4).w	; restore stuff and exit
	move.l	a1,($10).w
	move.l	a0,sp
	nop			; flush pipelines
	rts

; FPU type detection, experimental (draco@atari.org).
;
; This can only detect the hardware FPU, any software emulation
; will be ignored.
;
; NOTICE: the _FPU cookie value for 68060 is not defined by Atari!
;         *** How does it look like on a Hades060? ***
;
; Return value is cookie value for _FPU slot or a zero if no FPU
; is present:
;
; $00000000, no FPU
; $00020000, 68881 or 68882
; $00040000, 68881 for sure
; $00060000, 68882 for sure
; $00080000, 68040 internal FPU
; $00100000, 68060 internal FPU
;
; The detection algorithm goes as follows:
;
; - FNOP is executed. If a Line-F exception follows, then there's no FPU
;   in coprocessor mode. If the CPU is >= 68020, no FPU is assumed.
; - if FNOP doesn't take an exception, an FPU attached in coprocessor mode
;   is present. Then if 68040 or 68060 CPU was detected previously, an appropriate
;   FPU type is assumed. Otherwise the stackframe is checked for magic value
;   indicating 68882 and if it is different, a 68881 is assumed.
;
; I am very interested if this will really work on everything =)
; On a 68030/68882 tandem it does.

	XDEF	_detect_fpu
	XREF	_mcpu

_detect_fpu:
	move.l	sp,a0		; save the ssp
	clr.l	d0		; assume no FPU
	move.l	($2c).w,a1	; save the Line-F vector
	move.l	($08).w,a2
	move.l	#fexit,d1
	move.l	d1,($2c).w	; install temporary Line-F
	move.l	d1,($08).w
	nop			; flush pipelines

	move.l	_mcpu,d1	; check if 68000 or 68010
	cmpi.w	#20,d1
	bmi.s	sfp
	
	fnop
	clr.l	-(sp)		; push NULL frame
	clr.l	-(sp)		; extra longs for 68060
	clr.l	-(sp)
	frestore (sp)+		; reset the FPU into NULL state
	fnop			; force it into IDLE state
	fsave	-(sp)		; save the IDLE frame

	moveq	#$10,d0		; assume 68060 FPU (cookie $00100000)
	cmpi.w	#60,d1		; d1 is loaded above the FPU code
	beq.s	fexit
	moveq	#$08,d0		; if not 060, maybe a 040 (cookie $00080000)
	cmpi.w	#40,d1
	beq.s	fexit
	moveq	#$06,d0		; if neither, so maybe a 68882 (cookie $00060000)
	move.b	(sp)+,d1		
	cmpi.b	#$1f,d1
	beq.s	fexit
	moveq	#$04,d0		; must be 68881
	bra.s	fexit
sfp:	tst.w	($fa40).w	; CIR
	moveq	#$01,d0		; memory mapped FPU
fexit:	move.l	a1,($2c).w	; restore Line-F
	move.l	a2,($08).w
	move.l	a0,sp
	nop			; flush pipelines
	swap	d0
	rts
