; FILE: Source:modules/LocalFast.ASM          REV: 1 --- LocalFast module

;
; LocalFast module for BlizKick 1.20+
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Written by Harry "Piru" Sintonen.
; This source code is Public Domain.
;
; As I decided to drop LOCALFAST feature from BlizKick 1.20
; and after getting some requests about getting this feature
; back (hi Hexaae;), I decided to code it as a external
; module.
;
; Imlementation note: this module WILL be confused by PoolMem.
; Doesn't crash, but will refuse to install.
;
;    - Piru
;

	incdir	"include:"
	include	"exec/types.i"
	include	"exec/memory.i"
	include	"exec/execbase.i"

	include	"blizkickmodule.i"

; PoolMem uses this to indicate small pool MemHeader.
	BITDEF	MEM,POOLMEM,4


	SECTION	PATCH,CODE
_DUMMY_LABEL
	BK_PTC

; Code is run with following incoming parameters:
;
; a0=ptr to ROM start (buffer)	eg. $1DE087B8
; a1=ptr to ROM start (ROM)	eg. $00F80000 (do *not* access!)
; d0=ROM lenght in bytes	eg. $00080000
; a2=ptr to _FindResident routine (will search ROM buffer for resident tag):
;    CALL: jsr (a2)
;      IN: a0=ptr to ROM, d0=rom len, a1=ptr to resident name
;     OUT: d0=ptr to resident (buf) or NULL
; a3=ptr to _InstallModule routine (can be used to plant a "module"):
;    CALL: jsr (a3)
;      IN: a0=ptr to ROM, d0=rom len, a1=ptr to module, d6=dosbase
;     OUT: d0=success
; a4=ptr to _Printf routine (will dump some silly things (errormsg?) to stdout ;-)
;    CALL: jsr (a4)
;      IN: a0=FmtString, a1=Array (may be 0), d6=dosbase
;     OUT: -
; d6=dosbase, a6=execbase
;
; Code should return:
;
; d0=true if succeeded, false if failed.
; d1-d7/a0-a6 can be trashed. a7 *must* be preserved! ;-)

	moveq	#0,d7

	cmp.w	#37,($C,a0)		;requires V37+ rom image
	blo	.exit

	lea	(regs,pc),a5
	movem.l	d0/a0-a4,(a5)

	; find the blizzard memory header

	jsr	(-$84,a6)		; Forbid
	lea	(MemList,a6),a5
	lea	(LH_TAIL,a5),a4		; end marker
.scanloop	move.l	(a5),a5
	cmp.l	a5,a4			; list end reached?
	beq	.nomem

	move.w	(MH_ATTRIBUTES,a5),d0

	; this is a 1st PoolMem check...
	btst	#MEMB_POOLMEM,d0
	bne	.poolmem

	; Find public fast, that has no MEMF_POOLMEM, MEMF_CHIP,
	; MEMF_KICK or MEMF_LOCAL set:
	and.w	#MEMF_POOLMEM!MEMF_CHIP!MEMF_FAST!MEMF_PUBLIC!MEMF_KICK!MEMF_LOCAL,d0
	cmp.w	#MEMF_FAST!MEMF_PUBLIC,d0
	bne.b	.scanloop

	cmp.l	#$01000000,(MH_LOWER,a5) ; must be 32bit mem
	blo.b	.scanloop

	move.l	(LN_NAME,a5),d0		; some logic to check node name
	beq.b	.found
	move.l	d0,a2
	move.l	(a2),d0
	or.l	#$20202020,d0		; To lowercase
	cmp.l	#'bliz',d0
	beq.b	.found
	tst.b	(a2)			; null name -> buggy AllocMem result test!
	bne.b	.scanloop
.found
	move.l	#$07FFFF,d0		; this is a 2nd PoolMem check...
	and.l	(MH_UPPER,a5),d0
	bne	.poolmem

	move.l	(MH_LOWER,a5),d0
	move.l	(MH_UPPER,a5),d1
	clr.w	d0
	lea	(aml_regs,pc),a0
	sub.l	d0,d1
	move.l	d1,(a0)+		; size

	move.w	(MH_ATTRIBUTES,a5),d1
	and.l	#MEMF_PUBLIC!MEMF_FAST!MEMF_LOCAL!MEMF_24BITDMA,d1
	move.l	d1,(a0)+		; attrs

	move.b	(LN_PRI,a5),d1
	extb.l	d1			; sign extend b -> l
	move.l	d1,(a0)+		; pri

	move.l	d0,(a0)+		; base

	move.l	(LN_NAME,a5),d0
	beq.b	.lmpnoname
	move.l	d0,a1
	tst.b	(a1)
	beq.b	.lmpnoname
	addq.l	#4,a0
	move.l	a0,(-4,a0)		; name
	moveq	#32-2,d0
.lmpcopy	move.b	(a1)+,(a0)+
	dbeq	d0,.lmpcopy
	beq.b	.lmpnoname
	clr.b	(a0)+
.lmpnoname
	jsr	(-$8a,a6)		; Permit

	; find exec.library resident tag

	lea	(.execname,pc),a1
	movem.l	(regs,pc),d0/a0
	move.l	(findresident,pc),a2
	jsr	(a2)
	tst.l	d0
	beq	.exit

	move.l	d0,a3
	move.l	(RT_INIT,a3),d1

	;test if inside rom bounds?
	move.l	(rom_log,pc),d0
	cmp.l	d0,d1
	blo.b	.nofix
	add.l	(rom_size,pc),d0
	cmp.l	d0,d1
	bhs.b	.nofix
	; inside rom, so generate ram buffer address
	sub.l	(rom_log,pc),d1		; -$f80000
	add.l	(rom_phys,pc),d1	; +buffer
.nofix
	; d1 = RT_INIT address
	; fix our code to jump here when done

	lea	(jumpaddr+2,pc),a1
	move.l	d1,(a1)

	; install patch code...

	lea	(_localfast_module,pc),a1
	movem.l	(regs,pc),d0/a0
	move.l	(installmodule,pc),a2
	jsr	(a2)
	tst.l	d0
	beq.b	.exit

	; find ourself

	lea	(_name,pc),a1
	movem.l	(regs,pc),d0/a0
	move.l	(findresident,pc),a2
	jsr	(a2)
	tst.l	d0
	beq.b	.exit

	; fix RT_INIT to jump our patch code

	add.l	#_earlycode_RT,d0
	move.l	d0,(RT_INIT,a3)

	; all done, return success

	moveq	#1,d7
.exit
	move.l	d7,d0
	rts

.nomem	lea	(.nomemerr,pc),a0

.perr	jsr	(-$8a,a6)		; Permit
	move.l	(printf,pc),a2
	jsr	(a2)
	bra.b	.exit

.poolmem	lea	(.poolmemerr,pc),a0
	bra.b	.perr

.execname	dc.b	'exec.library',0
.nomemerr	dc.b	'LocalFast: valid memory header could not be found!',10,0
.poolmemerr	dc.b	'LocalFast: PoolMem has messed up Memory headers!',10,0


	CNOP	0,2
_localfast_module
 BK_MOD BKMF_SingleMode,_end,(0)<<24+37<<16+NT_UNKNOWN<<8+(256-128),_name,_idstr,_init

; Singlemode on,
; NEVER INIT module, requires KS V37.x or better, module type NT_UNKNOWN, priority -128.

_init	rts

_earlycode_RT	EQU	*-_localfast_module-bkm_ResTag

	; a6=execbase
	movem.l	d0-d2/a0-a1,-(sp)

	; is this memory already present?
	move.l	(aml_base,pc),a1
	lea	(256,a1),a1		; skip possible MH
	jsr	(-$216,a6)		; TypeOfMem
	tst.l	d0
	bne.b	.already		; it is, skip!

	; add the memory!
	movem.l	(aml_regs,pc),d0-d2/a0-a1
	jsr	(-$26a,a6)		; AddMemList
.already
	movem.l	(sp)+,d0-d2/a0-a1
jumpaddr	jmp	$badc0de

aml_regs	dc.l	0			; d0 size
	dc.l	0			; d1 attrs
	dc.l	0			; d2 pri
aml_base	dc.l	0			; a0 base
	dc.l	0			; a1 name
	ds.b	32			; space for memory name

_name
_idstr	dc.b	'LocalFast.patch',0
	CNOP	0,2
_end


	CNOP	0,2
regs
rom_size	ds.l	1
rom_phys	ds.l	1
rom_log	ds.l	1
findresident	ds.l	1
installmodule	ds.l	1
printf	ds.l	1



	SECTION	VERSION,DATA

	dc.b	'$VER: LocalFast_PATCH 1.0 (17.1.00)',0

