/* VITE by Jean-Pierre Rivière and Pierre Philippe Launay   */

#include <stdio.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <hardware/custom.h>
#include <hardware/dmabits.h>

#define DUREE   15

#define TEXT(rp,tx,x,y) { Move((rp), (x), (y)); Text((rp), (tx), strlen(tx)); }

#ifdef L_D_M    /* large data model */
extern struct Custom custom;    /* nécessaire à cause de cela   */
#define DMACON  custom.dmacon   /* lors de l'édition de lien    */
#define DMACONR custom.dmaconr
#else   /* small data model */
#define DMACON  (*((UWORD *) 0x00dff096))
#define DMACONR (*((UWORD *) 0x00dff002))
#endif

struct Window * Fenetre;        /* fenêtre de travail   */
struct Screen * Ecran;          /* écran de travail     */
struct NewWindow NouvelleFenetre = {    /* définition de la fenêtre */
    0, 11,
    640, 200 - 11,
    0, 1,
    MOUSEBUTTONS,
    ACTIVATE,
    NULL,
    NULL,
    "La vitesse d'exécution n'est pas le seul argument à considérer...",
    NULL,
    NULL,
    160, 13,
    640, 200,
    CUSTOMSCREEN
};
struct NewScreen NouvelEcran = {    /* définition de l'écran    */
    0, 0,
    640, 200, 1,
    0, 1,
    HIRES,
    CUSTOMSCREEN,
    NULL,
    "Hello Word!",
    NULL,
    NULL
};

static struct BitMap Carte;

char Tampon [128];  /* tampon d'écriture pour les messages variables    */

UBYTE * Conclusion [] = {
    " Just for your plaisure...  ",
    ""
};

UBYTE Kick [] = "Un petit clic et ce sera la grand choc !";
UBYTE Clic [] = " Un autre clic et je m'en vais. ";

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

void terminer (void)
    /* règle les comptes pour rester bon ami avec le système    */
{
    if (Fenetre)
        CloseWindow(Fenetre);
    if (Ecran)
        CloseScreen(Ecran);
    /* Si vous n'avez pas Dice, ou SAS fermez Intuition ici    */
    OpenWorkBench();    /* c'est un conseil du CATS...  */
}

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

void debuter (void)
    /* cel met le bazar en place ou cela stoppe les frais    */
{
    /* pas d'ouverture d'Intuition, c'est automatique avec Dice
        dès qu'on se sert d'une fonction Intuition.
        Si vous n'avez pas Dice, ouvrez-la manuellement ici.    */
    if (!(Ecran = (struct Screen *) OpenScreen(&NouvelEcran))) {
        terminer();
        exit(20);
    }
    NouvelleFenetre.Screen = Ecran;
    if (!(Fenetre = (struct Window *) OpenWindow(&NouvelleFenetre))) {
        terminer();
        exit(20);
    }
    InitBitMap(&Carte, 640, 200 - 11);
}

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

void Print(struct RastPort * rp, UBYTE * texte, UWORD longueur)
    /* impression d'une ligne avec scrolling automatique
        mais sans aucun wrapping.
        Fait de manière assez moche, pas du tout réutilisable
        en dehors de ce programme pour les valeurs données.
        ..  */
{
    static UWORD ligne = 9;

    if ((ligne += 8) >= 186) {
        /* scrolling    */
        ClipBlit(rp, 10, 10 + 8, rp, 10, 10, 620, 168, 0xc0);
        ligne -= 8;
    };
    Move(rp, 10, ligne);
    Text(rp, texte, longueur);
}

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

void boulot (UWORD duree)
{
    ULONG depsec, depmic, dep1, mic1;
    register ULONG finsec, finmic; /* mesures  */
    struct IntuiMessage * imess;    /* message Intuition                */
    register struct RastPort * rp;           /* RastPort de la fenêtre           */
    register UWORD nbop;    /* nombre de bouclages  */
    UWORD dmacon;   /* valeur de sauvegarde du registre Dmacon          */
    UWORD y;    /* ligne d'affichage    */
    UBYTE mot [111];
    UBYTE i;    /* compteur */

    /* mise en place de l'outil de travail  */
    debuter();
    for (i = -1; ++i < 110; mot[i] = 'A' + (i % 26));
    mot[110] = '\0';
    rp = Fenetre->RPort;
    sprintf(Tampon, "Attention : %d secondes de patience.", duree);
    SetDrMd(rp, JAM2);
    TEXT(rp, Tampon, 21, y = 27);
    TEXT(rp, Tampon, 20, y);
    TEXT(rp, Tampon, 21, y - 1);
    SetDrMd(rp, COMPLEMENT);
    TEXT(rp, Tampon, 20, y - 1);
    SetDrMd(rp, JAM2);
    TEXT(rp, Kick, 20, y += 12);
    nbop=0;
    /* attente du clic (bouton pressé)  */
    Wait(1 << Fenetre->UserPort->mp_SigBit);
    imess = (struct IntuiMessage *) GetMsg(Fenetre->UserPort);
    ReplyMsg(imess);
    /* gain de vitesse en coupant le maximum de DMA possible    */
    dmacon = DMACONR;
    DMACON = DMAF_RASTER | DMAF_BLITHOG;
    /* procédure de synchronisation */
    CurrentTime(&dep1, &mic1);
    dep1++;
    do {
        CurrentTime(&depsec, &depmic);
    }while (depsec != dep1);
    depsec += duree;
    /* boucle de test   */
    do {
        Print(rp, mot + nbop % 26, 77);
        nbop++;
        CurrentTime(&finsec, &finmic);
    }while (finsec < depsec);
    /* rétablissement de la DMA */
    DMACON = dmacon | DMAF_SETCLR;
    SetDrMd(rp, JAM2 | INVERSVID);
    /* l'evênement suivant est forcément le relacher du bouton du départ */
    Wait(1 << Fenetre->UserPort->mp_SigBit);
    imess = (struct IntuiMessage *) GetMsg(Fenetre->UserPort);
    ReplyMsg(imess);
    /* écriture des messages relatif au test    */
    sprintf(Tampon, "  départ : %ld s %ld µs ", depsec -= duree, depmic);
    TEXT(rp, Tampon, 20, y += 8);
    sprintf(Tampon, " arrivée : %ld s %ld µs ", finsec, finmic);
    TEXT(rp, Tampon, 20, y += 8);
    sprintf(Tampon, " L'opération a été effectuée %d fois. ", nbop);
    TEXT(rp, Tampon, 20, y += 8);
    sprintf(Tampon, " soit %d µs par itération. ",
            (int) ((1000000 * (finsec - depsec) + finmic - depmic) / nbop));
    TEXT(rp, Tampon, 20, y += 8);
    for (i = 0; i < 6; i++)
        TEXT(rp, Conclusion[i], 20, y+= 8);
    /* prenez le temps de lire  */
    TEXT(rp, Clic, 80, y + 8);
    /* puis on attend le clic, qui est forcément l'événement suivant */
    Wait(1 << Fenetre->UserPort->mp_SigBit);
    imess = (struct IntuiMessage *) GetMsg(Fenetre->UserPort);
    ReplyMsg(imess);
    /* on n'attend pas le relever du bouton car on va se saborder   */
    terminer();
}

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

void main (int narg, char *parg[])
    /* traitement à partir du shell */

{
    UWORD duree;    /* durée du test en secondes    */

    /* syntaxe d'appel : larve <durée_en_sec>   */
    if (narg == 2)
        duree=atoi(parg[1]);
    else
        duree = DUREE;
    boulot(duree);
    exit(0);
}


void * wbmain (void * msg)
    /* traitement à partir du Workbench */
{
    boulot(15);
    return msg;
}
