*
*                          DiskSpeed v4.0
*                                by
*                           Michael Sinz
*
*             Copyright (c) 1989 by MKSoft Development
*
*                      MKSoft Development
*                      163 Appledore Drive
*                      Downingtown, PA 19335
*
* Yes, this is yet another disk speed testing program, but with a few
* differences.  It was designed to give the most accurate results of the
* true disk performance in the system.  For this reason many of
* DiskSpeed's results may look either lower or higher than current disk
* performance tests.
*
******************************************************************************
*                                                                            *
*      Reading legal mush can turn your brain into guacamole!                *
*                                                                            *
*              So here is some of that legal mush:                           *
*                                                                            *
* Permission is hereby granted to distribute this program's source           *
* executable, and documentation for non-commercial purposes, so long as the  *
* copyright notices are not removed from the sources, executable or          *
* documentation.  This program may not be distributed for a profit without   *
* the express written consent of the author Michael Sinz.                    *
*                                                                            *
* This program is not in the public domain.                                  *
*                                                                            *
* Fred Fish is expressly granted permission to distribute this program's     *
* source and executable as part of the "Fred Fish freely redistributable     *
* Amiga software library."                                                   *
*                                                                            *
* Permission is expressly granted for this program and it's source to be     *
* distributed as part of the Amicus Amiga software disks, and the            *
* First Amiga User Group's Hot Mix disks.                                    *
*                                                                            *
******************************************************************************
*
	INCLUDE	"exec/types.i"
	INCLUDE	"exec/tasks.i"
	INCLUDE	"exec/lists.i"
	INCLUDE	"exec/libraries.i"
*
******************************************************************************
*
* This section of code is used to test CPU availability.  It was important
* that it be in assembly as it would otherwise be unpredictable.
*
	SECTION	"CPU_TEST",CODE
*
	xdef	_CPU_Use_Base
	xdef	_CPU_State_Flag
	xdef	_CPU_Count_Low
	xdef	_CPU_Count_High
	xdef	@Init_CPU_Available
	xdef	@Free_CPU_Available
	xdef	@CPU_Calibrate
*
	xref	_LVOAddTask
	xref	_LVORemTask
	xref	_AbsExecBase
*
******************************************************************************
*
* This init routine does all sorts of work to install the task...
*
@Init_CPU_Available:
		lea	_CPU_State_Flag(pc),a0	; Point at state flag...
		moveq.l	#0,d0			; Get a NULL...
		move.l	d0,(a0)+		; Clear state flag...
		move.l	d0,(a0)+		; Clear low count...
		move.l	d0,(a0)+		; Clear high count...
		move.l	(a0),d0		; Check if we are already running...
		bne.s	Task_Set	; If so, we don't start again...
*
		lea	_CPU_Use_Base(pc),a1	; Point at use flag...
		tst.l	(a1)			; Check if we are to run...
		beq.s	Task_Set		; If not, we just return...
*
* The task is not running...  First, clear the task structure...
*
		lea	Task_Struct(pc),a1	; Point at task structure...
		moveq.l	#TC_SIZE-1,d1		; We want to clear the task
Clear_TC:	move.b	d0,(a1)+		; Clear a byte...
		dbra	d1,Clear_TC		; Clear all of the task...
*
* Ok, now set up the task structure and get going...
*
		movem.l	a2/a3/a6,-(sp)		; Save these...
		lea	CPU_Available(pc),a2	; Initial PC...
		move.l	d0,a3			; NULL final PC...
		lea	Task_Struct(pc),a1	; Point at task structure...
		lea	TC_MEMENTRY(a1),a0	; Point at the TC_MEMENTRY
		NEWLIST	a0			; list header; initialize it.
		lea	Stack_Lower(pc),a0	; Point at low stack...
		move.l	a0,TC_SPLOWER(a1)	; Set the task structure...
		lea	Stack_Upper(pc),a0	; Task upper stack...
		move.l	a0,TC_SPUPPER(a1)	; Set the task structure...
		move.l	a0,TC_SPREG(a1)		; Starting point...
		move.b	#NT_TASK,LN_TYPE(a1)	; It is a task...
		move.b	#-127,LN_PRI(a1)	; Set to minimal priority...
		move.l	_AbsExecBase,a6		; Get ExecBase...
		jsr	_LVOAddTask(a6)		; Add the task...
*
*******************************************************************************
*
* Check to see if we are running in V37 ROM or better.  If so,
* we want to use the result of the AddTask() call...  Otherwise
* we just want the task structure address...
*
		cmp.w	#36,LIB_VERSION(a6)	; Check if exec is > V36
		bcc.s	TooNew			; If greater than V36, skip...
		lea	Task_Struct(pc),a1	; Get task structure...
		move.l	a1,d0			; Put it into d0...
TooNew:
*
*******************************************************************************
*
		movem.l	(sp)+,a2/a3/a6		; Restore...
Set_Task:	lea	CPU_Task(pc),a0		; Point at storage...
		move.l	d0,(a0)			; Save the pointer...
*
* D0 is now either a task pointer or NULL since it did not get added...
*
Task_Set:	rts
*
******************************************************************************
*
* This routine will kill the task...
*
@Free_CPU_Available:
		move.l	CPU_Task(pc),d0		; Check if we have a task...
		beq.s	Task_Set		; If not, just return...
		move.l	d0,a1			; Point at task...
		move.l	a6,-(sp)		; Save a6...
		move.l	_AbsExecBase,a6		; Get ExecBase...
		jsr	_LVORemTask(a6)		; Remove the task...
		move.l	(sp)+,a6		; Restore a6...
		moveq.l	#0,d0			; Clear d0...
		bra.s	Set_Task		; Set the task pointer...
*
******************************************************************************
*
* This routine will set up and then count the number of times through the loop
* below.  Since CPUs may become very fast, the counters are 64-bits.  This
* should last for a long time!  (Currently, it would most likely never need
* more than the first 32-bit word...)
*
CPU_Available:	lea	_CPU_State_Flag(pc),a0	; Set up some pointers
		lea	_CPU_Count_Low(pc),a1
		lea	_CPU_Count_High(pc),a2
*
* Here, we check if the state flag is zero.  Once it is, we drop
* down into the next routine...
*
CheckState:	tst.l	(a0)		; Check if we got the green-light.
		bne.s	CheckState	; If not, try again...
*
* Now, we count the low order counter.  If it does not wrap, we loop back...
*
		addq.l	#1,(a1)		; Add 1 to low order counter...
		bne.s	CheckState	; If we did not wrap, we go back...
*
* Since the low order counter just wrapped, we now count the high order...
* Note that we assume that there would never be an overflow in the high order
* counter word.
*
		addq.l	#1,(a2)		; Add 1 to high order counter...
		bra.s	CheckState	; Loop back...
*
******************************************************************************
*
* This routine is used to calibrate the CPU available number...
*
@CPU_Calibrate:	lea	_CPU_Count_Low(pc),a0	; Get up pointer...
*
* Now, we want to make the same instructions so that timing will
* be the same...
*
Calibrate:	tst.l	(a0)		; Check if we are done...
		beq.s	CalibrateDone	; If so, exit...
*
* Now, count backwards until we get to 0...
*
		subq.l	#1,(a0)		; Subtract 1 from low order counter...
		bne.s	Calibrate	; Loop back for some more...
*
* We get here when done with the calibration loop...
*
CalibrateDone:	rts
*
******************************************************************************
*
_CPU_Use_Base:		dc.l	0	; Set to TRUE in order to use CPU...
_CPU_State_Flag:	dc.l	0	; Used to control this routine...
_CPU_Count_Low:		dc.l	0	; The low-order word for CPU count
_CPU_Count_High:	dc.l	0	; The high-order word for CPU count
CPU_Task:		dc.l	0	; The task pointer...
*
******************************************************************************
*
Stack_Lower:		ds.l	80	; 80 long-words of stack for task
Stack_Upper:		dc.l	0
Task_Struct:		ds.b	TC_SIZE	; The task structure...
Task_Name:		dc.b	'MKSoft DiskSpeed CPU Test',0
*
******************************************************************************
*
		END
