#include "commun.h"

//Pointeur sur l'Obect Attribute Memory (les attributs des sprites).
unsigned short *pOAM = (unsigned short*)0x7000000;

//Pointeur sur la mémoire vidéo
unsigned short *MemVideo = (unsigned short*)0x6000000;
//Pointeur sur la mémoire de la palette (256 couleurs 16 bits)
unsigned short *Palette = (unsigned short*)0x5000000;
//La palette des objets est située ailleurs, permettant 256 couleurs supplémentaires
unsigned short *PaletteObj = (unsigned short*)0x5000200;
//En mode double-buffering, le FrontBuffer.
unsigned short *FrontBuffer = (unsigned short *)0x6000000;
//En mode double-buffering, le BackBuffer.
unsigned short *BackBuffer = (unsigned short *)0x600a000;

//Indique la ligne en train d'être dessinée par le contrôleur graphique.
volatile unsigned short *CompteurScanline = (volatile unsigned short *)0x4000006;

//Pour trouver une palette spécifique
#define nPalObj(x)  (PaletteObj+(x<<4))

//Attend la VSync, c-à-d que le contrôleur graphique a fini de dessiner les 160 lignes de l'écran.
void AttendVSync()     {
    while (*CompteurScanline>=160);
    while (*CompteurScanline<160);
}

//Bascule entre le front/back buffer.
void BasculePages()      {
    if (REG_DISPCNT & 0x10)     {
        REG_DISPCNT &= ~0x10;
        MemVideo = BackBuffer;
    }
    else    {
        REG_DISPCNT |= 0x10;
        MemVideo = FrontBuffer;
    }
}

//Fonction de copie DMA (un peu comme un memcpy)
void CopieDMA (void *source, void *dest, unsigned int nbval, unsigned int mode)     {
    if (mode==DMA_16im || mode==DMA_32im)        {
        //Remplissage des registres. Cf rapport.
        REG_DMA3SAD = (unsigned int) source;
        REG_DMA3DAD = (unsigned int) dest;
        REG_DMA3CNT = nbval | mode;
    }
}

//Un peu comme un memmove.
void MemMove16bits (void *dest, void *source, unsigned int nbval)     {
    u32 reg_dma=0;

    //La source et la destination risquent de se marcher dessus. Par exemple, copier 3 octets depuis l'adresse 2 vers la 3. En temps normal, cela donnera séquenciellement:
    //- Copie de 2 vers 3
    //- Copie de 3 vers 4
    //- Copie de 4 vers 5
    //Vous avez peut-être remarqué l'embrouille.
    if (dest<=source)       {
        REG_DMA3SAD = (unsigned int) source;
        REG_DMA3DAD = (unsigned int) dest;
        reg_dma = nbval | DMA_16im;
    }
    else    {
        REG_DMA3SAD = (unsigned int) ((u16*)source+nbval-1);
        REG_DMA3DAD = (unsigned int) ((u16*)dest+nbval-1);
        //Pour éviter que chaque élément se copie lui-même, on commence par la fin
        reg_dma = nbval | DMA_16im | DMA_SRCDECREMENT | DMA_DSTDECREMENT;
    }
    
    REG_DMA3CNT = reg_dma;
}

//Un peu comme memset (la première valeur de la source est répétée tout le long)
void MemSet (void *source, void *dest, unsigned int nbval, unsigned int mode)     {
    if (mode==DMA_16im || mode==DMA_32im)        {
        REG_DMA3SAD = (unsigned int) source;
        REG_DMA3DAD = (unsigned int) dest;
        REG_DMA3CNT = nbval | mode | DMA_SRCFIXE;
    }
}

//Copie DMA en utilisant le contrôleur DMA0
void CopieDMA0 (void *source, void *dest, unsigned int nbval, unsigned int mode)     {
    if (mode==DMA_16im || mode==DMA_32im)        {
        REG_DMA0SAD = (unsigned int) source;
        REG_DMA0DAD = (unsigned int) dest;
        REG_DMA0CNT = nbval | mode;
    }
}


//Pour l'indicateur de CPU
void InitTimers()       {
    //Stoppe le timer
    R_TIM1CNT=0;
    //Le remet à zéro
    R_TIM1COUNT=0;
    //65 kHz
    M_TIM1CNT_SPEED_SELECT_SET(2);
    //Démarre
    M_TIM1CNT_TIMER_START;
}

#define UtilCPU()  (R_TIM1COUNT)
#define NouvelleTrame     InitTimers




