*   StopClick	version 1.0  for SetCPU1.6 users
*	Written by Ismo Suihko,  August 4, 1990    (isuihko@ujocs.joensuu.fi)
*	Released to the Public Domain
*
*	Routines _GetMMUType and TestFlags are borrowed from SetCPU1.6,
*	which is written by Dave Haynie.
*	Also include file setcpu.i is borrowed from SetCPU sources.
*
* Stops clicking of empty drives by patching 1.3 KS V34.5 ROM (check
* it with command 'version') image loaded in 2-bit RAM with
* 'SetCPU FASTROM'. Disk drive heads will after the patch be stepped
* (silently) in a negative rather than positive direction during the
* regular system checks for a disk change.
* Version 1.6 of SetCPU isn't doing that patch anymore.
* StopClick also fixes trackdisk read/write bug (just like NoClick did).
* This patching is possible, because ROM image isn't protected at all.
* StopClick does nothing, if there isn't MMU and the given address
* doesn't seem to contain right version of the ROM image, so it
* is safe to run this even if you sometimes boot on 68000 mode.
*
* Based on the NoClick program, which is written by Norman Iscove.
* It didn't work on my system, because of SetPatch and TDpatch13
* (TDpatch13 comes with CrossDos (a great product!)).
*
* USAGE:
*   First check the address of the KERNEL by using command 'SetCPU VERBOSE'
*   If you have A2620 or A2630 with 2 MB 32-bit RAM, then output may
*   contain this line
*     KERNEL: (PADDR: $  3a0000) (VADDR: $  fc0000) (SIZE: 256K)
*			 ^^^^^^
*   Then give that address as a parameter to StopClick, like
*     StopClick 3a0000	  ;(you can use numbers 0-9 and letters A-F and a-f)
*   Don't put '$' before the address, because it is used by shell.
*   Put StopClick to a startup-sequence after SetCPU FASTROM when you have
*   checked what the address of the KERNEL is. If you add there more memory,
*   you have to check the address again and do modifications if necessary.
*
*   e.g.
*	SetCPU FASTROM
*	stopclick 3a0000    ; KERNEL is at address $3a0000
*
* There aren't any checks if there is a FASTROM image REALLY IN USE.
* We only check, if there are signs of a 1.3 KS V34.2 ROM image..
* If FASTROM has been actice once, but then disactivated, the image could
* still be in the 32-bit RAM, so it is found from there, and patches are
* made but without any effect (and no harm either).
*
* Return codes:
*   0	complete success, fixes made now or they had been made earlier
*   5	no MMU (Memory Management Unit)
*  10	no KS ROM image found, or wrong version of ROM
*  15	KS ROM image found, but modifications couldn't be done??
*  99	invalid parameter
* We get return code 5 always if there isn't a MMU.
*
* BUGS:
*   No known bugs.
*   Maybe the address of KERNEL could be found by this program somehow...
*
* Sometimes clicking will end only after a couple of seconds, just like
* with NoClick. Don't ask me why it happens so, as I don't know.
* And there may be some odd floppy disk drives which don't like to step
* in a negative direction. I haven't yet heard anyone who owns such a drive.
*
* History:
*  V0.9  Jun 23, 1990  works, do we need more?
*  V1.0  Aug 04, 1990  some more checking, now we check if there is a MMU,
*		       earlier we checked only if there was a '020 or better.
*		       program is now 480 bytes long
*  V?.?  ??? ??, ????  will find the address of the ROM image by itself
*
* To compile first get the setcpu.i include file from the SetCPU1.6 sources,
* comment out (add ';'s) the last two lines containing the text
* ;	 machine mc68020
* ;		 mc68881
* and then compile with commands
*   Assem StopClick.a -o StopClick.o -i INC:
*   Blink StopClick.o to StopClick
* Makefile is also provided for easier compilation and linking.


* exec.library routines
LVODisable	EQU -120
LVOEnable	EQU -126
LVOCloseLibrary EQU -414
LVOOpenLibrary	EQU -552
* dos.library routines
LVOWrite	EQU -48
LVOOutput	EQU -60

* some macros, etc.
 include "setcpu.i"


	movem.l d0/a0,-(sp)     save information of command line parameters

	bsr	_GetMMUType
	tst.l	d0		is there a MMU? 68851 or 68030?
	bne.s	scan
* no MMU
	addq.l	#8,sp		forget parameters before quitting
	moveq	#5,d0		no MMU
	bra	exit

scan
	movem.l (sp)+,d0/a0
* Now check, if there is a valid hexadesimal address given
	subq.l	#1,d0		take out end of line (null)
	beq.s	scan_err	is there any parameters at all

	subq.l	#1,d0		counter (length of the parameter)
	moveq	#0,d1		result
	moveq	#0,d2		character from the command line
scan_loop
	move.b	(a0)+,d2        get a character from the command line

	cmpi.b	#' ',d2         check for the end of hex number
	beq.s	scan_ready	is it a space
	cmpi.b	#';',d2
	beq.s	scan_ready	is it a start of a comment
	cmpi.b	#9,d2
	beq.s	scan_ready	is it a tab

	moveq	#'0',d3
	cmpi.b	#'9',d2
	ble.s	scan_number
	bclr.l	#5,d2		[a-f] -> [A-F]
	cmpi.b	#'A',d2
	blt.s	scan_err	less than 'A'
	cmpi.b	#'F',d2
	bgt.s	scan_err	greater than 'F'
	moveq	#'A'-10,d3
scan_number
	sub.b	d3,d2
	blt.s	scan_err	less than '0'
	asl.l	#4,d1		multiply by $10
	add.l	d2,d1
	dbra	d0,scan_loop
scan_ready
	tst.w	d1		should be of form xxxx0000
	beq.s	check

scan_err
	moveq	#99,d0
	bra.s	exit

check
	movea.l d1,a2		address of possible ROM image

* Now check if the given address may contain ROM image with exec of V34.2
	cmpi.w	#' 3',$1c(a2)
	bne.s	bad_rom
	cmpi.l	#'4.2 ',$1e(a2)
	bne.s	bad_rom

* add offset of trackdisk.device, should be of version 34.1
	adda.l	#$29564,a2
	cmpi.l	#'34.1',$36(a2)
	beq.s	patch
bad_rom
	moveq	#10,d0		no ROM image found
	bra.s	exit

patch
	moveq	#2,d7		2 patches
* disable interrupts
	CALLSYS Disable

* first we check, if we need to patch, then we check was the patch successful

* Stop the clicks
* fix 'bchg #$01,$41(a3)' to 'bset #$01,$41(a3)'
	lea	$104(a2),a0
	cmpi.w	#$086b,(a0)
	bne.s	1$
	move.w	#$08eb,(a0)
1$
	cmpi.w	#$08eb,(a0)
	bne.s	2$
	subq	#1,d7

2$
* Repair trackdisk read/write bug originally at $feaf9c (1.3)
* fix 'cmp.l $8000,d0' to 'cmpi.l #$8000,d0'
	lea	$1a38(a2),a0
	cmpi.w	#$b0b9,(a0)
	bne.s	3$
	move.w	#$0c80,(a0)
3$
	cmpi.w	#$0c80,(a0)
	bne.s	4$
	subq	#1,d7
4$
* enable interrupts
	CALLSYS Enable

	move.l	d7,d0		if d7 = 0, patching was succesful
	beq.s	exit
	moveq	#15,d0		patches failed??

exit
	tst.b	d0
	beq.s	real_exit

* print the usage text
	move.l	d0,-(sp)        push the return code
	lea	dosname(pc),a1
	moveq	#0,d0
	CALLSYS OpenLibrary
	tst.l	d0
	beq.s	2$
	move.l	d0,a5
	exg	a5,a6
	jsr	LVOOutput(a6)
	move.l	d0,d1
	beq.s	1$
	lea	usage(pc),a0
	move.l	a0,d2
	moveq	#usagelen,d3
	jsr	LVOWrite(a6)
1$
	exg	a5,a6
	move.l	a5,a1
	CALLSYS CloseLibrary
2$
	move.l	(sp)+,d0        pop the return code

real_exit
	rts



* The following routines are borroved from SetCPU1.6 sources.
* I optimized the code a slightly to make my program smaller than 488
* bytes, because otherwise it would have taken 1+2 disk blocks using OFS.
* I removed also the 68040 check, because at this context we don't need
* to know whether there is exactly '030 or '040 as both have MMU.


;======================================================================
;
;	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.s	 NoEarly40
*	 move.l  #68040,d0
*	 rts
*NoEarly40:
	btst.b	#AFB_68030,ATNFLGS(a6)  ; Does the OS think an '030 is here?
	beq.s	NoEarly30
	move.l	#68030,d0		; Sure does...
NoEarly30:
	rts


;======================================================================
;
;	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
	bsr	TestFlags		; Check extended CPU types
	tst.l	d0
	beq.s	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
	suba.l	a1,a1
	CALLSYS FindTask		; Call FindTask(0L)
	move.l	d0,a3

	move.l	TC_TRAPCODE(a3),a4      ; Change the exception vector
	lea	MMUTraps(pc),a0
	move.l	a0,TC_TRAPCODE(a3)

	moveq.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.s	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



* some strings

dosname dc.b	'dos.library',0
usage	dc.b	'StopClick v1.0 by IS.  '
	dc.b	'Usage: StopClick address-of-1.3-KS-FASTROM-image',10
usagelen EQU	*-usage

	END

