
;/* Total Football - Fastram loader (HD Installer)
  * ----------------------------------------------
  * Requirements: 3MB of free continious fastram available (for the 3
  * mirrored game disks)
  *
  * This source code is provided here so that;
  *
  * 1) Domark may possibly learn from it ... hehehe :)
  * 2) Other people (assembly coders) can fix all these types of game to work
  *    from hard-disk with ease...
  *
  * This source is fully freeware! do what you wish with it!
  *
  * Even use it in commercial games if you want.. go on see if I care!
  *
  */

_custom			=	$DFF000
intena			=	$9A
color			=	$180
dmacon			=	$96
fmode			=	$1fc
bplcon3			=	$106

AbsExecBase		=	$4
MaxLocMem		=	$3E
MaxExtMem		=	$4E
AttnFlags		=	$128

tv_UserIntVects		=	$100
tv_TrapInstrVects	=	$80

_LVOSupervisor		=	-30
_LVOOldOpenLibrary	=	-408
_LVOFindTask		=	$FFFFFEDA
_LVOWaitPort		=	$FFFFFE80
_LVOGetMsg		=	$FFFFFE8C
_LVOReplyMsg		=	$FFFFFE86
_LVOForbid		=	$FFFFFF7C
_LVOPermit		=	$FFFFFF76
_LVOOpen		=	$FFFFFFE2
_LVORead		=	$FFFFFFD6
_LVOClose		=	$FFFFFFDC
		
pr_CLI			=	$AC
pr_MsgPort		=	$5C

MODE_OLDFILE		=	$3ED

CACRF_CopyBack		=	$80000000	* Enable Copyback mode (`040+)
CACRF_EnableE		=	$40000000	* Enable External Caches
CACRF_WriteAllocate	=	$00002000	* Enable Write Allocate (`030+)
CACRF_DBE		=	$00001000	* Data Burst (`030+)
CACRF_ClearD		=	$00000800	* Flush Data Cache (`030+)
CACRF_FreezeD		=	$00000200	* Freeze Data Cache (`030+)
CACRF_EnableD		=	$00000100	* Enable Data Cache (`030+)
CACRF_IBE		=	$00000010	* Inst Burst (`030+)
CACRF_ClearI		=	$00000008	* Flush Inst Cache (`020+)
CACRF_FreezeI		=	$00000002	* Freeze Inst Cache (`020+)
CACRF_EnableI		=	$00000001	* Enable Inst Cache (`020+)

* Enable Instruction-cache()
* Enable Data-cache()
* Enable Write-allocate()

		section	fastram,code_f

*-------------- handle a workbench startup..

HD_Install:	move.l	d0,d7			;save CLI params len
		move.l	a0,a5			;save CLI params ptr
		suba.l	a1,a1			;clear a1
		move.l	4.w,a6			;get execbase
		jsr	_LVOFindTask(a6)	;find *THIS* task
		move.l	d0,a4			;get task ptr
		move.l	d7,d0			;restore CLI params len
		move.l	a5,a0			;restore CLI params ptr
		tst.l	pr_CLI(a4)		;did we originate from CLI?
		bne.s	ProgStart		;yes...call our program

		lea	pr_MsgPort(a4),a0	;from wb.. handle wb_startup
		move.l	a0,a4
		jsr	_LVOWaitPort(a6)	;wait for a message
		move.l	a4,a0
		jsr	_LVOGetMsg(a6)		;then get it
		move.l	d0,-(sp)
		bsr.s	ProgStart

		move.l	d0,d7			;save CLI Return code
		move.l	4.w,a6
		jsr	_LVOForbid(a6)
		move.l	(sp)+,a1
		jsr	_LVOReplyMsg(a6)
		move.l	d7,d0			;exit code
		rts

ProgStart	move.l	4.w,a6
		lea	DOSName(pc),a1		* lib name in a1
  		jsr	_LVOOldOpenLibrary(a6)	* try to open library
  		move.l	d0,_DOSBase		* store lib base
  		beq.w	bad_file		* cleanup and quit if fail

*-------------- load disk 1 mirror into fastram..

		lea	disk1.txt(pc),a0
		lea	diskdata+901120*0,a1
		bsr	RealLoadDOSFile
		tst.l	d0
		bne.w	bad_file

*-------------- load disk 2 mirror into fastram..
		
		lea	disk2.txt(pc),a0
		lea	diskdata+901120*1,a1
		bsr	RealLoadDOSFile
		tst.l	d0
		bne.w	bad_file

*-------------- load disk 3 mirror into fastram..

		lea	disk3.txt(pc),a0
		lea	diskdata+901120*2,a1
		bsr	RealLoadDOSFile
		tst.l	d0
		bne.w	bad_file

*-------------- now take over machine now..

		move.l	4.w,a6
		lea	Caches(pc),a5
		jmp	_LVOSupervisor(a6)	* enter supervise mode!

*-------------- turn off all dma, interrupts, etc.		

Caches:		move.w	#$7FFF,$dff096		* no dmacon
		move.w	#$7FFF,$dff09a		* no intena
		move.w	#$7FFF,$dff09c		* no intreq

*-------------- patch AGA hardware to reset to defaults (null)

		move.w	#$0,_custom+fmode	* no AGA 64-bit fetchmodes..
		move.w	#$0,_custom+bplcon3	* no extra bitplane control

*-------------- turn OFF cpu caches.. (sob!)

		move.l	#CACRF_FreezeI+CACRF_FreezeD+CACRF_WriteAllocate,d0
		movec	d0,cacr

*-------------- reset vectorbase to zeropage 
		moveq	#0,d0
		movec	d0,vbr

*-------------- init our fastram loader..

		lea	diskdata,a0		* disk image`s buffer
		lea	blockmem,a1		* 512 Bytes fastram buffer
		jsr	InitDOSLoad		

*-------------- load in the game loader..

* NB:
* ---
* All these lame and dirty absolute addresses are needed because the original
* game is address relocated to $19268 in chipram!! ARRRGG!!!!! Wake up DOMARK!
*

		lea	chipload.txt(pc),a0
		lea	$19268,a1
		jsr	fastload

*-------------- re-direct he game`s hardware disk loader to our fastram loader

		move.l	(AbsExecBase).l,a6
		lea	($4000).l,sp		 * set absolute stack (doh!)
		lea	(tv_UserIntVects).l,a0 
		move.w	(AttnFlags,a6),($2F6,a0) * total football`s main
		move.l	(MaxLocMem,a6),($2F8,a0) * loader expect`s at these
		move.l	(MaxExtMem,a6),($2FC,a0) * low memory addresses to
		move.l	#$480,$400.w		 * have these variables
		move.l	#$880,$404.w             * which is pretty lame eh!

		lea	$19268,a0		* a0.l = base of game loader

		move.w	#$4e75,$2500(a0)	* no drive select grinds
						* patched to simply "RTS"
						
		move.w	#$4ef9,$25e6(a0)	* patch loader to "JMP" to the
		move.l	#fastload,$25e6+2(a0)	* address of our 'fastload'
	
		move.w	#$600e,$23e0(a0)	* skip past disk select checks
						* patched to "BRA.S"..
						
		jmp	(a0)			* jump into the game!

		cnop	0,4
RealLoadDOSFile:
		move.l	a1,a4
		move.l	a0,d1
		move.l	#MODE_OLDFILE,d2	* open mode
		move.l	_DOSBase,a6
		jsr	_LVOOpen(a6)		* open file
		move.l	d0,d6			* save filehandle
		beq.s	err			* open error result?
		move.l	d6,d1			* filehandle
		move.l	a4,d2			* buffer
		move.l	#901120,d3		* l = length read
		jsr	_LVORead(a6)		* call Read/Write
		move.l	d0,d2			* save read length
		beq.s	err
		move.l	d6,d1			* filebuffer
		jsr	_LVOClose(a6)		* Close File
		moveq	#0,d0
		rts
err:		moveq	#-1,d0
		rts

bad_file:	move.w	#$f00,$dff180		* red flash of screen..

		moveq	#5,d0			* exit to dos.. (warn)
		rts

_DOSBase	dc.l	0
DOSName:	dc.b	'dos.library',0
		even
chipload.txt:	dc.b	'chipram.exe',0
		even
disk1.txt:	dc.b	'total:total1',0
disk2.txt:	dc.b	'total:total2',0
disk3.txt:	dc.b	'total:total3',0

		cnop	0,4
fastload:	movem.l	d0-a6,-(sp)
		moveq	#0,d0			* d0.w = disk to load from
		bsr.b	LoadDOSFile
		movem.l	(sp)+,d0-a6

		movem.l	d0-a6,-(sp)
		moveq	#1,d0			* d0.w = disk to load from
		bsr.b	LoadDOSFile
		movem.l	(sp)+,d0-a6

		movem.l	d0-a6,-(sp)
		moveq	#2,d0			* d0.w = disk to load from
		bsr.b	LoadDOSFile
		movem.l	(sp)+,d0-a6

		moveq	#0,d0
		rts

* FASTRAM AmigaDOSFile Loader
* ---------------------------
* $Inputs:	a0.l = filename
*		a1.l = load buffer
*		d0.w = number of disk to load from..
*
* $Outputs:	d0.l = resultcode
*

error    	=	0	* 0-1 (.W)
disk_number	=	1	* 1-2 (.W)
load_address 	=	2	* 2-6 (.L)

LoadBase:	bra.b	LoadDOSFile		* 00 jump table..
		bra.w	InitDOSLoad		* 01

		cnop	0,4			* quad aligned..
LoadDOSFile:	movem.l d2-d7/a0-a4/a6,-(a7)
		move.l	a0,a6
		move.l	a1,a5
		move.l	a5,-(sp)
		bsr.b	Find_file
		move.l	(sp)+,d1
		sub.l	a5,d1
		moveq	#0,d0			* d0.l = result code..
		move.b	(a2),d0
		neg.l	d1			* d1.l = load length..
		movem.l (a7)+,d2-d7/a0-a4/a6
		rts

		cnop	0,4
Find_file	lea	variables(pc),a2
		move.b	d0,disk_number(a2)
		move.l	a5,load_address(a2)
		clr.b	(a2)
		move.l	blockbuff_ptr(pc),a0	* get disk's root dir.
		move.w	#880,d0
		bsr.w	Get_block
		tst.b	(a2)
		bne.w	file_eror
find_files_root_dir_loop
		move.l	a6,a4
		moveq	#0,d0	
dir_loop	move.b	(a4),d7			* find file's root dir
		beq.s	root_dir
		cmpi.b	#"/",d7			* and get length of subdir name
		beq.s	oblique 		* if required.
		addq.w	#1,a4
		addq.w	#1,d0
		bra.b	dir_loop

		cnop	0,4
oblique		move.w	d0,d7			* d0 = dir name length
		move.w	d0,d6		
		subq.w	#1,d7
		bsr.w	hash_name		* hash dir name into d0
		move.l	$18(a0,d0.w*4),d0	* header block for this hash
		beq.w	file_not_found
get_dir_header	bsr.w	Get_block
		tst.b	(a2)
		bne.w	file_eror
		bsr.w	compare_names
		tst.w	d7
		beq.s	next_in_chain
		addq.w	#1,a4
		move.l	a4,a6
		bra.b	find_files_root_dir_loop

		cnop	0,4
next_in_chain	move.l	$1f0(a0),d0
		bne.b	get_dir_header
		bra.b	file_not_found

		cnop	0,4
root_dir	move.w	d0,d7			* length of file name
		move.w	d0,d6
		subq.w	#1,d7
		bsr.b	hash_name	
		move.l	$18(a0,d0.w*4),d0	* header block number for this hash
		beq.b	file_not_found
get_header	bsr.w	Get_block
		tst.b	(a2)
		bne.b	file_eror
		bsr.w	compare_names
		tst.w	d7
		bne.s	correct_file_header
		move.l	$1f0(a0),d0		* any more in hash chain?
		bne.b	get_header
		bra.b	file_not_found

		cnop	0,4
correct_file_header
		cmpi.l	#-3,$1fc(a0)		* make sure its a file header
		beq.s	file_header
		move.b	#2,(a2)		* not a file header-error
		bra.b	file_eror

		cnop	0,4
file_header	move.l	load_address(a2),a5
		move.l	$144(a0),d6		* length of file.
		subq.l	#1,d6	
transfer_loop	move.l	$10(a0),d0		* next block location
		beq.b	file_not_found
		bsr.w	Get_block
		tst.b	(a2)
		bne.b	file_eror
		lea	$18(a0),a3		* 1st data longword in dos_block
		moveq	#(488/4)-1,d7
make_file	subq.l	#4,d6
		bmi.s	last_bytes
		move.l	(a3)+,(a5)+	
		dbf	d7,make_file
		bra.b	transfer_loop

		cnop	0,4
last_bytes	addq.w	#4,d6
lb_loop		move.b	(a3)+,(a5)+	
		dbf	d6,lb_loop
		rts

		cnop	0,4
file_not_found	move.b	#3,(a2)			* file not found-error
file_eror	rts

		cnop	0,4
hash_name	move.l	a6,a3
hash_loop	moveq	#0,d2			* hash file name at a6
		move.b	(a3)+,d2		* length-1 in d7.
		cmpi.b	#$60,d2
		bls.s	capital
		cmpi.b	#$7a,d2
		bhi.s	capital
		subi.b	#$20,d2
capital		mulu	#13,d0
		add.l	d2,d0
		andi.l	#$7ff,d0
		dbf	d7,hash_loop
		divu	#72,d0
		swap	d0			* d0=hash number
		rts

		cnop	0,4
compare_names	moveq	#0,d7
		cmp.b	$1b0(a0),d6		* d6=length of name being tested
		bne.s	name_fail
		move.w	d6,d5
		move.l	a6,a3
		lea	$1b1(a0),a5
		subq.w	#1,d5	
comp_loop	move.b	(a3)+,d1		* Case desensitize filename
		move.b	(a5)+,d2		* compare.
		andi.b	#$df,d1
		andi.b	#$df,d2
		cmp.b	d1,d2
		dbne	d5,comp_loop
		tst.w	d5
		bpl.s	name_fail
		moveq	#1,d7
name_fail	rts

* a0.l block buffer
* d0.w block number required ($0 - $6df)

disktable:	dc.l	901120*0		* disk 0
		dc.l	901120*1		* disk 1
		dc.l	901120*2		* disk 2
		dc.l	901120*3		* disk 3

		cnop	0,4
Get_block	movem.l	a0-a6/d0-d7,-(a7)
		andi.l	#$ffff,d0
		cmpi.w	#$6df,d0		* check range
		bls.b	blk_in_range
		move.b	#1,(a2)
		bra.w	No_reload

		cnop	0,4
blk_in_range:	move.w	d0,d1
		swap	d0
		clr.w	d0
		swap	d0
		mulu	#512,d0
		move.l	a0,a1
		moveq	#0,d2
		move.b	disk_number(a2),d2
		add.w	d2,d2
		add.w	d2,d2
		move.l	diskdata_ptr(pc),a0	* disk base
		add.l	disktable(pc,d2.w),a0	* offset to correct disk..
		add.l	d0,a0			* offset to correct position..
		nop	;make copy on longword ...
		movem.l	(a0)+,d1-d7/a2-a6	* get data into regs
		movem.l	d1-d7/a2-a6,(a1)	* push it into memory..
		movem.l	(a0)+,d1-d7/a2-a6	* get data into regs
		movem.l	d1-d7/a2-a6,48*1(a1)	* push it into memory..
		movem.l	(a0)+,d1-d7/a2-a6	* get data into regs
		movem.l	d1-d7/a2-a6,48*2(a1)	* push it into memory..
		movem.l	(a0)+,d1-d7/a2-a6	* get data into regs
		movem.l	d1-d7/a2-a6,48*3(a1)	* push it into memory..
		movem.l	(a0)+,d1-d7/a2-a6	* get data into regs
		movem.l	d1-d7/a2-a6,48*4(a1)	* push it into memory..
		movem.l	(a0)+,d1-d7/a2-a6	* get data into regs
		movem.l	d1-d7/a2-a6,48*5(a1)	* push it into memory..
		movem.l	(a0)+,d1-d7/a2-a6	* get data into regs
		movem.l	d1-d7/a2-a6,48*6(a1)	* push it into memory..
		movem.l	(a0)+,d1-d7/a2-a6	* get data into regs
		movem.l	d1-d7/a2-a6,48*7(a1)	* push it into memory..
		movem.l	(a0)+,d1-d7/a2-a6	* get data into regs
		movem.l	d1-d7/a2-a6,48*8(a1)	* push it into memory..
		movem.l	(a0)+,d1-d7/a2-a6	* get data into regs
		movem.l	d1-d7/a2-a6,48*9(a1)	* push it into memory..
		movem.l	(a0)+,d1-d7/a2		* get data into regs
		movem.l	d1-d7/a2,48*10(a1)	* push it into memory..
No_reload	movem.l	(a7)+,a0-a6/d0-d7
		rts

InitDOSLoad:	lea	diskdata_ptr(pc),a2
		move.l	a0,(a2)
		move.l	a1,blockbuff_ptr-diskdata_ptr(a2)
		rts
		
diskdata_ptr:	ds.l	1
blockbuff_ptr	ds.l	1
variables	ds.b	8

		section	fastmemblock,bss_f		* force into fastram!

blockmem:	ds.b	512
diskdata:	ds.b	901120*3			* 3 disks of fastram
							* buffers
