/*
	COLORS
*/
#undef RGB
#define RGB(r, g, b)        ((r) + ((g) << 5) + ((b) << 10))
#define RVB(r, g, b)        ((coeffs[r]) + ((coeffs[g]) << 5) + ((coeffs[b]) << 10))

/*
	TIMERS

*/
#define TIMER_DISABLED		0
#define TIMER_ENABLED		(1 << 7)
#define TIMER_SPEED(n)		(n)
#define TIMER_COUNT_UP		(1 << 2)
#define TIMER_IRQ_ENABLE	(1 << 6)

static inline u16 gbaGetTimerValue(u32 timerNumber)
{
	return *(vu16*)(REG_BASE + 0x100 + 4 * timerNumber);
}

// The timer should be disabled first!
static inline void gbaSetTimerValue(u32 timerNumber, u16 newValue)
{
	*(vu16*)(REG_BASE + 0x100 + 4 * timerNumber) = newValue;
}

static inline u16 gbaGetTimerControl(u32 timerNumber)
{
	return *(vu16*)(REG_BASE + 0x102 + 4 * timerNumber);
}

static inline void gbaSetTimerControl(u32 timerNumber, u16 newValue)
{
	*(vu16*)(REG_BASE + 0x102 + 4 * timerNumber) = newValue;
}

/*
	SPECIAL FX

	These are helpers only, you may also access those registers directly.
*/
enum {SFX_NONE = 0, SFX_ALPHA, SFX_FADE_WHITE, SFX_FADE_BLACK};

static inline u16 gbaGetBlendingMode()	{ return REG_BLDCNT; }
static inline void gbaSetBlendingMode(u16 effectType, u16 sourcePlanes, u16 destinationPlanes)
	{ REG_BLDCNT = effectType << 6 | sourcePlanes | destinationPlanes << 8; }

// Coefficients d'alpha blending, 0 <= {eva, evb} <= 31
static inline u16 gbaGetAlphaCoeff()	{ return REG_BLDALPHA; }
static inline void gbaSetAlphaCoeff(eva, evb)
	{ REG_BLDALPHA = eva | evb << 8; }

// 0 (transparent) - 31 (opaque)
static inline u16 gbaGetFadeCoeff()	{ return REG_BLDY; }
static inline void gbaSetFadeCoeff(coeff)
	{ REG_BLDY = coeff; }

/*
	INPUT
*/
#define REG_KEYS (~(REG_KEYINPUT) & 0x3ff)


/*
	DISPLAY
*/
#define VRAM_SIZE			(64 << 10)

extern const unsigned char *coeffs;

#define nPalObj(x)		(PaletteNormale + 256 + ((x) << 4))
#define nPalBG(x)		(PaletteNormale + ((x) << 4))

typedef unsigned char car;

extern void ChargePalette(const unsigned short *palette, unsigned short *dest, unsigned char fin);

#define REG_STOPCNT * (volatile unsigned char *) 0x4000301

extern void AttendVSync();
extern void AttendVSyncRapide();

// Dma copy modes
#define DMA_16im			(DMA_ENABLE | DMA_IMMEDIATE | DMA16)
#define DMA_32im			(DMA_ENABLE | DMA_IMMEDIATE | DMA32)

extern void CopieDMA(void *source, void *dest, unsigned int nbval, unsigned int mode);
extern void CopieDMA0(void *source, void *dest, unsigned int nbval, unsigned int mode);

static inline void CopieDMA0Ex(void *source, void *dest, unsigned int nbval, unsigned int mode)
{
	u32 controlValue = nbval | mode;
	// Attend que le canal DMA soit libre
	while (REG_DMA0CNT & DMA_ENABLE);
	REG_DMA0SAD = (u32)source;
	REG_DMA0DAD = (u32)dest;
	REG_DMA0CNT = controlValue;
}

extern void MemSet(void *source, void *dest, unsigned int nbval, unsigned int mode);

extern void MemMove16bits(void *dest, void *source, unsigned int nbval);

//extern void CreeTablesGamma(double gamma);
extern void InitTimers();
#define UtilCPU()        gbaGetTimerValue(1)
extern void NouvelleTrame();

/*
	Memory
*/
#define InitZero(dest) \
        ( \
{ \
        u32 zero = 0; _memset(dest, &zero, sizeof(dest)); \
} \
        )

extern void _memset(void *dest, void *source, unsigned int nbval);

/*
	Maths
*/
extern u32 IWRAM_CODE modulo(s32 i, u32 x, u32 y);
extern u32 IWRAM_CODE division(s32 i, u32 x, u32 y);
