* QuickROM - uses 68060 or 68040 MMU to remap Kickstart in FAST RAM
* First written by Simon N Goodwin October 10th 1996, PUBLIC DOMAIN
* Updated January 1997: automatically senses the Kickstart ROM size
* and can be re-assembled for page sizes other than the default 4K.
* First upload to Aminet, version 36.07, May 1998.
*
* This program works like KSREMAP and ROM2FAST, but it's compatible
* with more systems, smaller than the former, and more capable than
* the latter. Written and tested on a Mark 2 Cyberstorm 68060, more
* than doubling the speed of access to Kickstart code. Also tested
* on GVP G-FORCE 68060, Commodore's 3640 (helps a bit, but hampered
* by its very slow 'fast' RAM interface) Warp Engine 68040/33 and a
* Mark 1 Cyberstorm, which was even faster than the Mark 2 - though
* it's a shame that Phase Five's Mark 1 SCSI add-on never worked as
* it should have done. Nic Wilson's KickSpeed tester (from Set040)
* reads ROM 2.4 times faster on my Mark 1 Cyberstorm hardware after
* running QuickROM. 
*
* The advantages of QuickROM over the proprietary versions are:
*
* Allocates RAM from the top of memory to minimise fragmentation.
*
* Allows de-allocation as well as allocation, freeing 516K memory.
*
* More diagnostics for cases when it won't work (Exec result codes).
*
* Freely distributable including the Devpac Source code (this is it)
* with copious comments explaining its strengths and weaknesses.
*
* Does not use undocumented 68060.library hooks, so it should work
* fine on any other 68060 or 68040 system with an MMU, unlike some.
*
* Works with 1 Mb ROMs as well as Commodore 512K ones, and uses the
* documented method to find the ROM size, so it should suit other
* sizes too, as long as they're in the first 32 Mb of address space
* (likely as the MAGIC_ROM_SIZE needs to be at address 16 Mb - 20).
*
* Limitations are:
*
* No messages. Check the return code to find out EXACTLY what happened.
*
* Requires an MMU, and won't work with old 68030, 68451 or 68851 ones.
* There are already plenty of Kickstart re-mappers for those systems.
*
* May get confused in the MMU table setup or ROM location is radically
* changed in some future Amiga. This program is inevitably architecture-
* and processor-specific, although I've tried to make it fairly flexible.
*
* History and Predictions:
*
* Code was originally designed to shadow the 512K ROM at $00F80000; this
* suited all Commodore Amiga ROMs from Kickstart 1.4 to 3.1, but new 1Mb
* versions are expected one day, so the updated code includes changes to
* look for them, from address $00F00000 up. It still expects ROM sizes to
* be a multiple of 256K, where that's the size of a pointer-level table
* entry, as it works in units of one complete 256K mapping table.
*
*   The Third Edition of the Amiga Hardware Reference Manual documents
*   on page 224 a technique for finding the size and hence the start
*   address of the ROM, making reference to these 'magic' constants:
*
MAGIC_ROMEND equ	$01000000		End of C= Kickstarts
MAGIC_SIZEOFFSET equ	-20		Offset to ROM size.L
*
* When testing modifications, check the MMU start pointer offset and
* number of pointer-level entries modified in TableFix, as well as the
* ROM address and size. If it's past $01FFFFFF you'll need to use a
* later root pointer to find the required first pointer level entry.
*
* The re-mapping area includes one extra MMU page of RAM to ensure page
* alignment. It uses eight bytes after the ROM image (guaranteed to be
* available by heap alignment rules) to point back to the start of the
* allocation and watermark the area "MMU!". All current systems use 4K
* pages but some effort has been made to make the code adjust to other
* page sizes, if re-assembled with the following constant adjusted:
*
PAGE_SIZE	equ	4096
*
* PLEASE NOTE: the code has not been tested with 8K pages, as they're not
* used in any known Amiga; similarly it assumes 256K areas for each pointer
* level table entry, as these are standard on current 68040 and 68060s. It
* will probably require radical change for new or non-68040/68060 MMUs
*
******************************************************************************
*
* This is the program itself. It uses 68020+ opcodes as well as the MMU,
* so it starts by checking ExecBase to ensure that the processor is suitable.
* 
QuickROM	move.l  	4.w,a6                	Find EXEC
	btst  	#3,$129(a6)     	Test for a 68060 or 68040
        	beq.s	Too_Old

        	lea.l	FindMMU,a5        	
       	jsr    	-30(a6)        	EXEC Supervisor function
        	tst.w	d0		Is MMU enabled in TC? If so,
        	bpl.s	MMU_off		bit 15=1 (on 68040/060 only)

	if	PAGE_SIZE=4096
	
        	add.w	d0,d0		Check we're using 4K pages: if
        	bpl.s	Pages_OK		so, TC bit 14 should be zero

Pages_8K	moveq	#24,d0		FAIL! MMU using 8K pages
	rts

	endc
	
Pages_OK    move.l	a0,d0		Copy and test Root Pointer
        	bne.s	got_MMU		Zero is definitely not enough
        	
no_MMU	moveq	#28,d0		FAIL! MMU not initialised
	rts
	
MMU_off	moveq	#26,d0		FAIL! MMU not enabled
	rts	
	
Too_Old	moveq	#30,d0		FAIL! 68060 or 68040 required
	rts

	dc.b	'$VER: QuickROM v36.07 (3-May-1998) by Simon N Goodwin',0
	even

Bad_Copy	moveq	#20,d0		FAIL! Remapped by someone else
	rts		

* EXEC Supervisor routine to extract MMU configuration register details 

FindMMU	movec	urp,a0
	movec	tc,d0
	rte    	

No_Room	moveq	#22,d0		FAIL! More FAST RAM needed
 	rts

******************************************************************************
*
* If we get thus far we're basically onto a winner. We've got an 060 or 040,
* 4K memory mapping is enabled. Code has been extended to allow undoing, and
* the memory to be reclaimed, if it is re-invoked when already in use.
*
* Register usage:
*
* D0, D1, A0, A1 scratch and system
* D4 Size of physical ROM
* D7 MMU table address mask
*
* A4 Start of physical ROM
* A5 End of physical ROM
*
got_MMU	move.l	(a0),d0		MMU pointer table for 1st 32 Mb
	move.l	#$FFFFFE00,d7	Mask to clear lower 9 bits
	and.l	d7,d0		Mask allows safe .W in offset
	lea.l	MAGIC_ROMEND,a5	End of ROM
	move.l	a5,a4		
	move.l	MAGIC_SIZEOFFSET(a5),d4 Size of ROM
	moveq	#16,d1		Shift to divide start*4 by 256K
	sub.l	d4,a4		Start of ROM
	move.l	a4,d5
	
* The pointers handle 256K each, so if the ROM is at $00F80000 as usual the
* first associated long word pointer will be entry 62, counting from 0, in the
* pointer-level table, since 62*256K = 15.5 Mb = $00F80000 (as any fule kno).

	lsr.l	d1,d5		Expect 62*4 for ROM at $F80000
	add.w	d5,d0		Offset to first page pointer
	move.l	d0,a2		Save first pointer table entry
	move.l	(a2),d1		Find first page table entry
	and.l	d7,d1		Mask out page usage flags
	move.l	(d1.l),d1		Get page table entry
	and.l	d7,d1		Physical address for this page
	cmp.l	a4,d1		Is it pointing at ROM already?
	beq.s	Create		If so, we can soon change that!

* It's already re-mapped, so try to un-map it

	add.l	d4,d1		Point past end of ROM
	move.l	d1,a1
	move.l	(a1)+,d6		Pick up past pointer
	beq.s	Bad_Copy		Check it's non zero!
	
	moveq	#7,d1		Mask for lower three bits
	and.l	d6,d1		  which should all be zero
	bne.s	Bad_Copy		Check alignment is plausible

	cmp.l	#'MMU!',(a1)	Check for our odd signature
	bne.s	Bad_Copy

	move.l	a4,d2	
	bsr.s	TableFix		Point MMU tables back to ROM

	move.l	d6,a1		Where to deallocate
	move.l	#PAGE_SIZE,d0
	add.l	d4,d0		ROM size and a bit

	jsr	-210(a6)		FreeMem

	moveq	#0,d0		No error
	rts
	
* Allocate memory

Create	move.l	#$00040004,d1	MEMF_REVERSE and MEMF_FAST
	move.l	d4,d0		Deduced ROM size
	add.l	#PAGE_SIZE,d0	...and a bit for overlap

	jsr	-198(a6)		AllocMem

	move.l	a4,a0		Computed ROM address
	move.l	d0,d2		Copy returned address
	beq.s	No_Room

	move.l	d0,a3		Save base of allocated RAM
	
* Ensure correct alignment on a page boundary

	move.l	d4,d0		ROM size
	add.l	#PAGE_SIZE-1,d2
	and.l	#$FFFFFFFF-PAGE_SIZE+1,d2
	move.l	d2,a1		Where to copy TO
	move.l	a3,(a1,d0.l)	Store real base at end of copy
	move.l	#'MMU!',4(a1,d0.l)	Put watermark in last 4 bytes
	
* Copy ROM there

	jsr	-624(a6)		CopyMemQuick, A0 to A1 for D0

* This subroutine updates the MMU page table, whether mapping or unmapping
		
TableFix	jsr    	-120(a6)        	Disable, implies Forbid

* Fix the MMU tables by pointing them at the new copy
* D2 points at the 'new' ROM image to be used, and D4 is its size.
* A2 points to the MMU pointer table entry for the first 256K of ROM space

	move.l	d4,d1		Work out size in pointer pages
	moveq	#18,d0		Shift factor to divide by 256K
	lsr.l	d0,d1		Number of pointers to be tweaked
	addq.l	#1,d2		Set Resident flag for pages
	subq.l	#1,d1		Adjust for DBRA

Pointers	move.l	d7,d0
	and.l	(a2)+,d0		Pointer to MMU block to remap
	move.l	d0,a0		Masked to 512 boundary
	moveq	#63,d0		Count 4K blocks

Pages	move.l	d2,(a0)+		Masked page pointer
	add.l	#PAGE_SIZE,d2
	dbra	d0,Pages

	dbra	d1,Pointers

	jsr    	-126(a6)        	Enable, implies Permit
	
	moveq	#0,d0		Admit nothing
	rts
	
	end
	