;======================================================================
;
;	SetCPU V1.60
;	by Dave Haynie, April 13, 1990
;	Released to the Public Domain
;
;	REBOOT.A MODULE
;
;	This module contains functions that do the clever reset magic
;	needed for KickStart imaging.
;
;======================================================================

	include "setcpu.i"

	cseg

	xdef	_RAMBoot	; Effects the reboot into a RAM image
	xdef	_BootCode	; Actual main reboot code
	xdef	_BootCodeSize	; Size of this magic code
	xdef	_CleanBoot	; Boot back to system ROM, reset Exec
	xdef	_ResetCode	; Smart reset routine
	xdef	_ResetCodeSize	; Size of this magic code

;======================================================================
;
;	This is the RAMBoot routine as called from C.  The C code has
;	set up the tag structure with valid MMU data and a pointer to
;	the main reset routine in safe memory.  The routine will fetch
;	the systag from the stack, then call the safe routine in the
;	supervisor mode.  That call is the last kernal call used; the
;	reset routine itself doesn't use any ROM routines, so it can
;	safely turn off the MMU before it goes to work, methinks.
;
;	void RAMBoot(struct systag *tag, LONG ClearExec,LONG Delay)
;
;======================================================================

_RAMBoot:
	move.l	4(sp),a2		; Get the systag where we can use it
	move.l	8(sp),d4		; KeepExec?
	move.l	12(sp),d5		; Delay value
	move.l	4,a6
	lea.l	TrickyBits,a5		; Get the supervisor code
	CALLSYS	Supervisor		; Go to supervisor mode
	rts				; We never get here!

;======================================================================
;
;	This is the start of the supervisor portion of the reboot code.
;	This code gets things in the registers the ChipRAM code 
;	requires, loads up a reset routine into cache, freezes the
;	cache, resets, waits for the CIA chips, and then calls the
;	ChipRAM code portion which will turn the MMU on and jump to
;	ROM's start address.
;
;	a2	SetCPU system tag
;	a6	ExecBase
;	d4	KeepExec Flag
;	d5	Boot Delay
;
;======================================================================

TrickyBits:
	move.l	TAG_ROMSTART(a2),a4	; Get the ROM jump address
	move.l	TAG_RESETCODE(a2),a3	; Get the ChipRAM based code
	lea.l	TAG_CRP_0(a2),a1	; Get CRP register
	lea.l	TAG_TC(a2),a0		; Get TC register

	and.l	#$7fffffff,(a0)		; Turn off MMU
	PMOVE_	(a0),tc			; -> $f010,$4000			
	or.l	#$80000000,(a0)		; Prep for startup
	PMOVE_	(a1),crp		; -> $f011,$4c00

	cmp.l	#0,d4			; If asked for, zap ExecBase good
	bne	1$
	moveq.l	#0,d0
	move.l	d0,$4
1$
	move.l	#1,d1			; Make sure inst cache is on!
	MOVEC_	d1,cacr

	move.l	#1,d3			; First pass, no delay
	lea.l	CacheRun,a6		; Get the initial branch address

RSTLoop:	
	jmp (a6)

RSTIt:
	reset				; Clobber the system
	reset

CacheRun:
	move.w	ANYCREG,d1		; Set a spell, take yer shoes off
	subq.l	#1,d3
	bne	CacheRun
	move.b	#3,$bfe201		; Turn off Amiga ROM Overlay
	move.b	#2,$bfe001

	cmp.l	a3,a6			; Last time through?
	beq	RSTLoop			; If so, go back
	
	move.l	a3,a6			; No?  Get the address,
	move.l	d5,d3			;          the delay
	move.l	#3,d1			;          freeze the cache
	MOVEC_	d1,cacr			
	bra	RSTIt			; And Up to the reset stuff

;======================================================================
;
;	This is the RAM reboot code, which is called to reset the 
;	system into the new ROM, which is of course now in some magic
;	and safe place.  The ROM's jump address in in A4 when this
;	code is called, and the TC register is in A0.
;
;======================================================================

RAMBootCode:
	move.l	#0,d1			; Turn all caches off
	MOVEC_	d1,cacr
	move.l	#10,d1			; Let 'em know we're here
1$
	bchg	#1,$bfe001
	move.l	#80000,d0
2$	subq.l	#1,d0
	bne	2$
	dbra	d1,1$

	PMOVE_	(a0),tc			; Turn on the MMU
	jmp	(a4)			; Start up the ROM
	nop
	nop
	nop
	nop
RAMBootEnd:

_BootCode:
	dc.l	RAMBootCode
_BootCodeSize:
	dc.l	RAMBootEnd-RAMBootCode+1

;======================================================================
;
;	This routine forces a boot back to ROM, clearing out the 
;	ExecBase and turning off the MMU and caches.  
;
;	void CleanBoot(void)
;
;======================================================================

_CleanBoot:
	move.l	4,a6

	lea	1$,a5
	CALLSYS	Supervisor
	rts
1$
	move.l	#0,(sp)			; Turn off MMU
	move.l	sp,a0
	PMOVE_	(a0),tc			; -> $f010,$4000

	move.l	#0,d1			; Turn all caches off
	MOVEC_	d1,cacr

	move.l	4,a6			; Clear out ExecBase
	move.l	#0,$4

	move.l	$00f80000,d0		; Which kind of real ROM?
	cmp.l	#$11144ef9,d0
	beq	2$
	move.l	$00fc0004,a0
	bra 3$
2$
	move.l	$00f80004,a0		; We have a 512K ROM
3$
	reset
	reset
	jmp (a0)
	nop
	nop
	nop
	nop
CleanBootEnd:

;======================================================================
;
;	Pointers to the smart reset routine, and the length of this
;	routine.  Currently I'm using the CleanBoot routine, which will
;	get the machine back to the ROM OS.  A better smart reset routine
;	could boot back to the virtual ROM rather than the physcial ROM.
;
;======================================================================

_ResetCode:
	dc.l	_CleanBoot
_ResetCodeSize:
	dc.l	CleanBootEnd-_CleanBoot+1

	end
