; FILE: Source:modules/ChipSaver.ASM          REV: 51 --- Copies chipmem to fast

;
; ChipSaver patch for BlizKick
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; This module copies chip memory to fast memory if  if RMB is pressed during
; reboot. Creates ExoticRipper compatible image ($100 -image).
;
; Suggested by Max Romanoff.
;
; Written by Harry Sintonen.
; This source code is Public Domain.
;

;FASTBUFHEAD_LEN EQU	256*1024		;skip first 256K (prevent trashing)
CHIPBEGSAVE_LEN	EQU	64*1024			;save lenght (must be multiple of 64)

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

	include	"exec/execbase.i"

	include	"blizkickmodule.i"	; Some required...

	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! ;-)

	cmp.w	#37,($C,a0)		;requires V37+ rom image
	bhs.b	.cont
	moveq	#0,d0
	rts

.cont	moveq	#0,d7

	move.l	d0,-(sp)
	bsr	FindBlizMemMid
	move.l	d0,d1
	move.l	(sp)+,d0
	tst.l	d1
	beq.b	.noblizmem
;	add.l	#FASTBUFHEAD_LEN,d1
	lea	(_absdstp_1,pc),a5	;fix chipbegsave buffer adr
	move.l	d1,(a5)
	lea	(_absdstp_2,pc),a5
	move.l	d1,(a5)

	move.l	a0,a5
	move.l	#$13FC0003,d1
	move.w	#512-1,d2
.findl	subq.w	#1,d2
	beq.b	.badrom
	addq.l	#2,a5
	cmp.l	(a5),d1
	bne.b	.findl

	move.l	a5,d1			;d1=jump pos (buf)
	moveq	#8,d3
	add.l	d1,d3
	sub.l	a0,d3
	add.l	a1,d3			;d3=return jump pos (rom)

	move.l	a0,-(sp)
	move.l	d1,a0			;copy original code
	lea	(_instpos,pc),a5
	move.l	(a0)+,(a5)+
	move.l	(a0)+,(a5)+

	lea	(_jmpromp,pc),a0	;fix returning jmp
	move.l	d3,(a0)

	move.l	d1,a5			;create jmp
	move.w	#$4EF9,(a5)+
	move.l	#_earlycode_RT,(a5)	;add RT!!
	move.l	(sp)+,a0

	move.l	d0,d5
	lea	(_copier_module,pc),a1
	jsr	(a3)			;call _InstallModule
	move.l	d0,d1
	move.l	d5,d0
	tst.l	d1
	beq.b	.nomod

	lea	(_name,pc),a1
	jsr	(a2)			;call _FindResident
	tst.l	d0
	beq.b	.nomod
	add.l	d0,(a5)			;add RT!

	moveq	#1,d7
.nomod
.badrom
.noblizmem	move.l	d7,d0
	rts


FindBlizMemMid	movem.l	d1-a6,-(sp)
	moveq	#0,d1
	jsr	(-$84,a6)		;Forbid
	lea	(MemList,a6),a5
	lea	(4,a5),a4
.scanloop	move.l	(a5),a5
	cmp.l	a5,a4
	beq.b	.notfound
	move.w	(MH_ATTRIBUTES,a5),d0
	and.w	#MEMF_CHIP!MEMF_FAST!MEMF_PUBLIC,d0	;Public fast?
	cmp.w	#MEMF_FAST!MEMF_PUBLIC,d0
	bne.b	.scanloop
	cmp.l	#$01000000,(MH_LOWER,a5)	;32bit?
	blo.b	.scanloop
	move.l	(LN_NAME,a5),d0
	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	(MH_LOWER,a5),d1
.notfound	jsr	(-$8A,a6)		;Permit
	move.l	d1,d0			;must set d0!!
	beq.b	.exit

	move.l	(MH_UPPER,a5),d0
	sub.l	d1,d0
	lsr.l	#2,d0			;add ¼th
	add.l	d1,d0
	and.w	#$FFF0,d0

.exit	movem.l	(sp)+,d1-a6
	rts

	CNOP	0,4
_copier_module
 BK_MOD BKMF_SingleMode,_end,(RTF_COLDSTART)<<24+37<<16+NT_UNKNOWN<<8+104,_name,_idstr,_init

; Singlemode on,
; COLDSTART module, requires KS V37.x or better, module type NT_UNKNOWN, priority 104.
; At priority 104 fastmem should be available.

_init	btst	#6,$BFE001		;test LMB
	beq	.sexit			;if pressed don't copy
	movem.l	d0-a6,-(sp)

	lea	$DFF000,a5
	move.w	#$FFFF,($34,a5)		;pin 9 to write mode! ($0C00)

	moveq	#1-1,d0			; Wait for two vertical blankings
.wait1	btst	#0,($5,a5)		; (Could wait only 300 µs!)
	bne.b	.wait1
.wait2	btst	#0,($5,a5)
	beq.b	.wait2
	dbf	d0,.wait1

	btst	#10-8,($16,a5)		;test RMB
	bne	.exit			;if not pressed don't copy

	move.l	(4).w,a6
	move.l	(MaxLocMem,a6),d2

	move.l	d2,d0
	move.l	#MEMF_FAST!MEMF_PUBLIC!MEMF_REVERSE,d1	; buggy on pre-39
	jsr	(-$C6,a6)		;AllocMem
	tst.l	d0
	beq.b	.exit
	move.l	d0,a2

	move.l	a2,a1

	lea	$0BAD0000,a0
_absdstp_1	EQU	*-4
	move.w	#CHIPBEGSAVE_LEN/8-1,d0
.cscopy	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	dbf	d0,.cscopy

	lea	CHIPBEGSAVE_LEN,a0
	move.l	d2,d0
	sub.l	a0,d0

	lsr.l	#6,d0			;/64
	subq.l	#1,d0
	move.l	d2,d7
	moveq	#4*4,d6
.copy	move.w	d0,($180,a5)
	movem.l	(a0)+,d1-d4		;16
	movem.l	d1-d4,(a1)
	add.l	d6,a1
	movem.l	(a0)+,d1-d4		;16
	movem.l	d1-d4,(a1)
	add.l	d6,a1
	movem.l	(a0)+,d1-d4		;16
	movem.l	d1-d4,(a1)
	add.l	d6,a1
	movem.l	(a0)+,d1-d4		;16
	movem.l	d1-d4,(a1)
	add.l	d6,a1
	dbf	d0,.copy
	move.l	d7,d2

	move.l	a2,$100.w
	move.l	#$DEADBEEF,(a2)+
	move.l	d2,(a2)+
	clr.l	(a2)

	move.w	#0,($180,a5)

.exit	movem.l	(sp)+,d0-a6
.sexit	rts

_earlycode_RT	EQU	*-_copier_module-bkm_ResTag
	sub.l	a0,a0
	lea	$0BAD0000,a1
_absdstp_2	EQU	*-4
	move.w	#CHIPBEGSAVE_LEN/8-1,d0
.ecopy	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	dbf	d0,.ecopy
_instpos	nop
	nop
	nop
	nop
	jmp	$0BAD0000		;jmppos+10
_jmpromp	EQU	*-4

_name
_idstr	dc.b	'ChipSaver',0
	CNOP	0,2
_end

	SECTION	VERSION,DATA

	dc.b	'$VER: ChipSaver_PATCH 1.0 (21.5.97)',0

	END
