View Single Post
Old 21 October 2019, 00:57   #5
mcgeezer
Registered User

 
Join Date: Oct 2017
Location: Sunderland, England
Posts: 1,576
So I've implemeted a couple of these functions now and added another few.

The function added is amgUnloadAsset() - it's pretty simple.

Code:
NAME
        amgUnloadAsset - Release handle and ram held by an asset


SYNOPSIS
        amgUnloadAsset(assetHandle)
                         d0


FUNCTION
        The specified handle is marked with a status of unused within its structure.
	The address and length pointers of the handle are left in tact, these are
	subsequently used to deallocate the ram of the asset using LVOFreeMem().


INPUTS
        handle - (d0) A previously allocated handle using amgLoadAndUnpackRncAsset().



RESULTS
        NULL


ERRORS

As I've implemented the functions I can post them here.

We have six files in total

main.asm - this has the main calling program.
loader.asm/loader.dat - this is what does the load header, allocate ram, read packed file, unpack file.
handle.asm/handle.dat - this contains the code for managing handles
unpack.asm - RNC unpacker


The main program looks like this, it simply reads the header of an RNC packed file, reads the unpacked size from the header, allocates that amount of ram, loads and unpacks the whole file to that allocated ram, allocates a handle for that asset that has been loaded....then... deallocates the handle and frees ram. This is pretty much a key aspect into managing assets in an Amiga game.

Code:
ExecBase:               	equ     4

        cseg

        basereg data,a4
        near    a4

CODE_BASE:

	bra	MAIN

	CNOP	0,4
		
        include i/custom.i              ; Custom Register definitions
        include i/cia.i                 ; CIA Hardware definitions
        include 'exec/types.i'
	include 'exec/exec.i'
	include 'exec/exec_lib.i'
	include 'libraries/dos.i'
	include 'libraries/dos_lib.i'
        include 'hardware/blit.i'
        include 'hardware/dmabits.i'	
        include s/unpack.asm
	include s/loader.asm
	include s/handle.asm
	
	
MAIN:
; Reserve a4 and a5 for global pointers.
	lea	data,a4					
	lea	CHIPBASE,a5				

; Open the DOS library
	move.l  ExecBase,a6				; handle[d0] = OpenLibrary=(version[d0],libname[a1])
	lea     DOSNAME(a4),a1
	moveq   #0,d0
	jsr     _LVOOpenLibrary(a6)
	move.l	d0,DOSBASE(a4)				; save DOSBASE for file reading

	lea	asset_lower(a4),a0			; rawHandle = amgLoadAndUnpackRncAsset(*name[a0], memtype[d1])
	moveq	#0,d0
	moveq	#MEMF_CHIP,d1
	bsr	amgLoadAndUnpackRncAsset
; d0 has allocated handle number

; now lets unload the asset from memory.
	bsr	amgUnloadAsset				; amgUnloadUnpackedAsset(handle[d0])
	
	move.l  ExecBase,a6				; Close the DOS library.
	move.l  DOSBASE(a4),a1
	jsr     _LVOCloseLibrary(a6)

; End program
        moveq   #0,d0
        rts
	
; Data section here.

        dseg
	

dats:
	include s/loader.dat
	include s/handle.dat

DOSBASE:	dc.l	0
DOSNAME:	dc.b	'dos.library',0
		even

asset_lower:	dc.b	"dh1:Rygar/ry_lower.rnc",0		; Packed RNC file to load.
		even

data:

loader.asm looks like this...

Code:
mode_old   =1005
mode_new   =1006
	
; rawHandle = amgLoadAndUnpackRncAsset(*name, memtype)
;    d0                                  a0     d1

amgLoadAndUnpackRncAsset:
	movem.l	d1-d7/a0-a1,-(a7)		; Save Registers
	move.l	d1,d5				; Save Requested Memory Type
	move.l	a0,d6				; Save filename pointer (we'll be needing it twice)
	
; Open the file for reading
	move.l	a0,d1				; handle[d0] = LVOOpenFile(filename[d1],mode[d2])
	move.l  DOSBASE(a4),a6       
        move.l  #mode_old,d2
        jsr     _LVOOpen(a6)         		
	tst.l	d0				
	bmi	.open_error
	
; Read the RNC header file
	move.l	d0,d4				; Save handle for LVOClose
	
	lea	amgRncHeaderBuffer(a4),a0	; Buffer to read RNC header bytes
	move.l	a0,d2				; bytes[d0] = LVORead(handle[d1],buffer[d2],size[d3])		
	moveq	#20,d3				
        jsr     _LVORead(a6)         		
	tst.l	d0				; Was there an error?
	bmi	.header_error
	cmp.l	d0,d3				; Did we read the correct number of bytes?
	bne	.read_error
; Close the file
	move.l	d4,d1				; result = LVOClose(handle[d1])
        move.l  DOSBASE(a4),a6       	
        jsr     _LVOClose(a6)        
	
; Check the RNC header
	lea	amgRncHeaderBuffer(a4),a0	; Get pointer to the read header
	move.l	(a0),d0
	lsr.l	#8,d0
	cmp.l	#"RNC",d0			; Is it RNC?
	bne	.rnc_error

; Allocate ram based on RNC header	
	move.l	4(a0),d0			; address[d0] = LVOAllocMem(buffsize[d0],MEM_TYPE[d1])
	move.l	d5,d1				
        move.l  ExecBase,a6
        jsr     _LVOAllocMem(a6)
	tst.l	d0
	bmi.s	.alloc_error
	
	move.l	d0,d4				; Save the allocated buffer origin
	
; Open the file again and read it.
	move.l	d6,d1				; handle[d0] = LVOOpenFile(filename[d1],mode[d2])
	move.l  DOSBASE(a4),a6       
        move.l  #mode_old,d2
        jsr     _LVOOpen(a6)         		
	tst.l	d0
	bmi.s	.open_error
	move.l	d0,d5				; Save handle for read and close.
	
	
; Read the entire file
	move.l	d4,d2				; bytes[d0] = LVORead(handle[d1],buffer[d2],size[d3])
	move.l	#$ffffff,d3		
        jsr     _LVORead(a6)         	
	tst.l	d0
	bmi.s	.read_error
	
; Close the file
	move.l	d5,d1				; result = LVOClose(handle[d1])
        move.l  DOSBASE(a4),a6       
        jsr     _LVOClose(a6)        

; Allocate a new handle here for the asset that was just read.
	bsr	amgAllocateHandle		; assetHandle[d0], handleOrigin[a0] = amgAllocateHandle()
	tst.l	d0
	bmi.s	.handle_error
	move.l	d0,d1				; Save handle
	
	move.l	d2,a1
	move.l	d4,HANDLE_STRUCT_ADDRESS(a0)	; Save the address of the asset in ram in the handle
	move.l	4(a1),HANDLE_STRUCT_LENGTH(a0)	; Save the length of the asset in ram in the handle
	
	move.l	a1,a0				; UnpackSize[d0] = Unpack[source[a0],dest[a0]
	bsr	Unpack
	
; Verify the unpack size against what was in the header
	lea	amgHandlesStruct(a4),a0
	lsl.w	#4,d1
	cmp.l	HANDLE_STRUCT_LENGTH(a0,d1),d0
	bne.s	.unpack_error
	
	move.l	d1,d0
	


	bra	.exit				; All done.
	        	
.open_error:
	moveq	#ERROR_HANDLE_FILE_OPEN,d0
	bra.s	.exit
.header_error:
	moveq	#ERROR_HANDLE_HEADER_NOT_FOUND,d0
	bra.s	.exit
.alloc_error:
	moveq	#ERROR_HANDLE_ALLOCATE_FAIL,d0
	bra.s	.exit
.read_error:
	moveq	#ERROR_HANDLE_FILE_READ,d0
	bra.s	.exit
.rnc_error:
	moveq	#ERROR_HANDLE_RNC,d0
	bra.s	.exit
.handle_error:
	moveq	#ERROR_HANDLE_GENERIC,d0
	bra.s	.exit
.unpack_error:
	moveq	#ERROR_HANDLE_UNPACK,d0
	bra.s	.exit
	nop
.exit:	
	movem.l	(a7)+,d1-d7/a0-a1
	rts
	



; d0=handle number
amgUnloadAsset:
; Now lets release the handle and the memory we just allocated.
	lsr.w	#4,d0
	bsr	amgReleaseHandle		; handleOrigin[a0] = amgReleaseHandle(assetHandle[d0])

	move.l	HANDLE_STRUCT_ADDRESS(a0),a1
	move.l	HANDLE_STRUCT_LENGTH(a0),d1
	move.l  ExecBase,a6
	jsr     _LVOFreeMem(a6)
	rts
loader.dat looks like this

Code:
			CNOP	0,4

amgRncHeaderBuffer:	
			ds.w	20

			CNOP	0,4

handle.asm looks like this...

Code:
maxHandles:			equ	20		

; Error return codes for handles.
ERROR_HANDLE_FILE_OPEN:		equ	-1
ERROR_HANDLE_HEADER_NOT_FOUND:	equ	-2
ERROR_HANDLE_ALLOCATE_FAIL:	equ	-3
ERROR_HANDLE_FILE_READ:		equ	-4
ERROR_HANDLE_RNC:		equ	-5
ERROR_HANDLE_GENERIC:		equ	-6
ERROR_HANDLE_UNPACK:		equ	-7


; Handle structure indexes
HANDLE_STRUCT_STATUS:		equ	0
HANDLE_STRUCT_TYPE:		equ	1
HANDLE_STRUCT_ADDRESS:		equ	2
HANDLE_STRUCT_LENGTH:		equ	6

; OUTPUTS:
; Returns new handle number in d0
; Returns pointer to handle structure in a0
amgAllocateHandle:
	move.l	d7,-(a7)
	lea	amgHandleAllocs(a4),a0
	moveq	#0,d0
	moveq	#maxHandles-1,d7
.loop:	tst.w	(a0)+
	bmi.s	.found
	addq.w	#1,d0
	dbf	d7,.loop
	moveq	#-1,d0
	bra.s	.exit
	
.found:
	subq.w	#2,a0
	move.w	d0,(a0)
.exit:
	move.l	d0,d7
	lsl.w	#4,d7
	lea	amgHandlesStruct(a4),a0
	add.l	d7,a0
	move.b	d0,(a0)

	move.l	(a7)+,d7
	rts
	

; Frees up a handle previously allocated with amgAllocateHandle()
; INPUT [d0] = handle to release	
amgReleaseHandle:
	lea	amgHandleAllocs(a4),a0
	move.w	#-1,(a0,d0*2)

	lea	amgHandlesStruct(a4),a0
	lsl.w	#4,d0
	add.l	d0,a0
	move.w	#-1,(a0)
	rts
and handle.dat like this...

Code:
amgHandleCurrent:	dc.w	0			; Current handle pointer

amgHandleAllocs:	
			rept	maxHandles
			dc.w	-1
			endr
			
amgHandlesStruct:
			rept	maxHandles
			dc.b	-1			; Status -1/0
			dc.b	-1			; Type (-1 = unallocated)
			dc.l	0			; Address
			dc.l	0			; Length
			dc.b	"HANDLE"		; Padding.
			endr

Also included in the archive I have uploaded is the RNC unpack code.

And a link to the source code is here.

For those who want to follow along I will do a video showing setting up the tool chain and debugging the source here, feel free though to give it a try yourself if you want to race ahead.

http://109.228.4.199/downloads/Tutorial%201.zip
mcgeezer is offline  
 
Page generated in 0.04434 seconds with 11 queries