/*
 * $Header$
 * $Locker$
 * $Log$
 */
/************************************************************************/
/* Copyright Metrowerks Corporation. (c) 1999,2000.						*/
/*----------------------------------------------------------------------*/
/* 2000/05/30		Recreated by Toshiaki Koasa.						*/
/* 1999/06/19		Created by Takashi Kashima.							*/
/*																		*/
/* module name		mw_util.c											*/
/*																		*/
/* description		Metrowerks utilities for Dreamcast SDK 1.6x			*/
/*																		*/
/* Function																*/
/*	This module is simple overlay support utilities.					*/
/*																		*/
/************************************************************************/

/* internal update logs

	Version.1.00

    2000.01.24	suppress auto inline option to MWNotifyOverlayLoaded().
    1999.09.08  support static initializer
    1999.06.19	for R2
*/

#include <shinobi.h>						/* shinobi api definition			*/
#include <sg_Cache.h>						/* cache control api definition		*/
#include <string.h>							/* string and memory functions		*/
#include "mw_utils.h"						/* my function prototype declare	*/

/*----------------------------------------------------------------------*/
/* external symbols														*/
/*----------------------------------------------------------------------*/

extern void* _overlay_group_address[];
/*
	A list of the overlay load addresses is generated
	by the linker and placed in the variable 
	"_overlay_section_addreses"
*/

/*----------------------------------------------------------------------*/
/* structure and type definition										*/
/*----------------------------------------------------------------------*/

typedef struct tagMWOverlayHeader{			/* overlay header type definition	*/
	char				identifier[3];		/* overlay file identifier			*/
	char				version;			/* version number					*/
	unsigned long		overlayID;			/* overlay id						*/
	unsigned long		loadAddress;		/* load address						*/
	unsigned long		textSize;			/* text section size				*/
	unsigned long		dataSize;			/* data section size				*/
	unsigned long		bssSize;			/* bss section size					*/
	unsigned long		staticInitBegin;	/* static initializer begin address	*/
	unsigned long		staticInitEnd;		/* static initializer end address	*/
	char				overlayName[32];	/* overlay name						*/
	} MWOverlayHeader;						/* end of definition				*/

typedef void (*StaticInitializer)(void);	/* static initializer typedef		*/

/*----------------------------------------------------------------------*/
/* support functions													*/
/*----------------------------------------------------------------------*/

#ifdef __cplusplus							/* when c++ activated,				*/
extern "C" {								/* start c linkage					*/
#endif										/* __cplusplus						*/

/*----------------------------------------------------------------------*/
/* MWGetGroupAddress - get overlay group address						*/
/*----------------------------------------------------------------------*/

void* MWGetGroupAddress(					/* get overlay group address		*/
	unsigned int	index)					/* overlay group id					*/
	{
	return(_overlay_group_address[index]);	/* report overlay group address		*/
	}										/* end of MWGetGroupAddress			*/

/*----------------------------------------------------------------------*/
/* MWbload - load binary file to memory									*/
/*----------------------------------------------------------------------*/

Sint32 MWbload(								/* report loaded file size,			*/
											/* 0 if read failed					*/
	const char*			fileName,			/* file name						*/
	void*				address)			/* load address						*/
	{
	GDFS				gdfs;				/* file handle						*/
	Bool				isDone;				/* done status						*/
	Sint32				fileSize;			/* file size						*/
	Sint32				sctSize;			/* sector size						*/
	Sint32				rc;					/* async read result code			*/
	void*				buff;				/* load temp buffer					*/

	gdfs = gdFsOpen(fileName,NULL);			/* open binary file					*/
	if(gdfs == NULL)						/* if can't open,					*/
		return(0);							/* report failed					*/
	buff = NULL;							/* clear read buffer pointer		*/
	isDone = gdFsGetFileSize(gdfs,			/* get binary file size				*/
		&fileSize);							/*									*/
	if(!isDone)								/* if can't get binary file size,	*/
		goto errorExit;						/* jump to error exit process		*/
	sctSize	= gdFsCalcSctSize(fileSize);	/* calc sector size from file size	*/
	buff = syMalloc(						/* allocate read buffer				*/
		(Uint32)sctSize * GDD_FS_SCTSIZE);	/*									*/
	if(buff == NULL)						/* if can't allocate,				*/
		goto errorExit;						/* jump to error exit process		*/
	rc = gdFsReqRd32(gdfs,sctSize,buff);	/* async read start					*/
	if(rc < 0)								/* if can't read,					*/
		goto errorExit;						/* jump to error exit				*/
	rc = gdFsGetStat(gdfs);					/* check read status				*/
	while(rc == GDD_STAT_READ)				/* wait read completed				*/
		rc = gdFsGetStat(gdfs);				/* check read status				*/
	gdFsClose(gdfs);						/* close binary file				*/
	syCacheOCBP(address,(Uint32)fileSize);	/* cache write back					*/
	memcpy(address,buff,(Uint32)fileSize);	/* copy to memory					*/
	syFree(buff);							/* free overlay file temprary buff	*/
	return(fileSize);						/* report overlay file size			*/

errorExit:									/* error exit process				*/
	gdFsClose(gdfs);						/* close overlay file				*/
	if(buff != NULL)						/* if exist overlay temp buffer,	*/
		syFree(buff);						/* free overlay temprary buff		*/
	return(0);								/* report failed					*/
	}										/* end of MWBload					*/

/*----------------------------------------------------------------------*/
/* MWNotifyOverlayLoaded - overlay loaded notify						*/
/*----------------------------------------------------------------------*/

#pragma auto_inline off						/* disable auto inline option		*/
void MWNotifyOverlayLoaded(					/* report nothing					*/
	const void*			address)			/* overlay loaded address			*/
	{
	#pragma	unused(address)					/* mark 'address' is unuse			*/
	return;									/* report nothing					*/
	}										/* end of MWNotifyOverlayLoaded		*/
#pragma auto_inline reset					/* reset auto inline option			*/

/*----------------------------------------------------------------------*/
/* MWInitOverlay - initialize overlay									*/
/*----------------------------------------------------------------------*/

void MWInitOverlay(							/* report nothing					*/
	const void*			address,			/* overlay load address				*/
	Sint32				fileSize)			/* overlay file size				*/
	{
	MWOverlayHeader*	ovHdr;				/* overlay header address			*/
	Uint32				bssSize;			/* bss size							*/
	Uint32				bssAdr;				/* bss address						*/
	StaticInitializer*	sInitBegin;			/* static initializer table begin	*/
	StaticInitializer*	sInitEnd;			/* static initializer table end		*/
	StaticInitializer*	p;					/* current static initializer		*/

	ovHdr = (MWOverlayHeader*)address;		/* get overlay header address		*/
	sInitBegin = (StaticInitializer*)		/* get static initializer table		*/
		ovHdr->staticInitBegin;				/* begin address					*/
	sInitEnd = (StaticInitializer*)			/* get static initializer table		*/
		ovHdr->staticInitEnd;				/* end address						*/
	bssSize = ovHdr->bssSize;				/* get bss size						*/
	syCachePurgeAll();						/* purge cache all					*/
	syCacheICI();							/* invalidate instruction cache		*/
	if(bssSize > 0){						/* if exist bss area,				*/
		bssAdr = (Uint32)address + fileSize;/* calc bss start address			*/
		if(bssAdr & 0x00000007)				/* when not aligned 8 bytes			*/
			bssAdr							/* align 8 bytes					*/
				= (bssAdr & 0xfffffff8) + 8;/*									*/
		memset((void*)bssAdr,0x00,bssSize);	/* clear bss area					*/
		}									/*									*/
	for (p = sInitBegin; p != sInitEnd; p++)/* call all static initializer in	*/
		(*p)();								/* table							*/
	return;									/* report nothing					*/
	}										/* end of MWInitOverlay				*/

/*----------------------------------------------------------------------*/
/* MWLoadOverlay - load overlay											*/
/*----------------------------------------------------------------------*/

Sint32 MWLoadOverlay(						/* report 1 if success,	0 if not	*/
											/* false if not						*/
	const char*			fileName,			/* overlay file name				*/
	void*				address)			/* load address						*/
	{
	Sint32				readSize;			/* overlay file size				*/

	readSize = MWbload(fileName,address);	/* load overlay file				*/
	if(readSize == 0)						/* if can't load overlay,			*/
		return(0);							/* report failed					*/
	MWInitOverlay(address,readSize);		/* initialize overlay				*/
	MWNotifyOverlayLoaded(address);			/* overlay loaded notify			*/
	return(1);								/* report success					*/
	}										/* end of MWLoadOverlay				*/

#ifdef __cplusplus							/* when c++ activated,				*/
	}										/* end of c linkage					*/
#endif										/* __cplusplus						*/
