/*****************************************************************************
 *                                                                           *
 * Module : MAIN.C                                                           *
 *                                                                           *
 * Module principal, initialisations, gestion des évènements : clavier,      *
 * fermeture de la fenêtre (fin du prg.)                                     *
 *                                                                           *
 *****************************************************************************/


#include  <Intuition/Intuition.h>
#include  <Exec/Interrupts.h>
#include  <Exec/Memory.h>
#include  <Exec/Tasks.h>
#include  <Devices/Timer.h>
#include  <Proto/Intuition.h>
#include  <Proto/Graphics.h>
#include  <Proto/Gadtools.h>
#include  <Proto/Exec.h>
#include  <Proto/Asl.h>
#include  <Proto/Dos.h>
#include  <String.h>

#include  "Joystick.h"
#include  "Process.h"
#include  "Invite.h"
#include  "Sound.h"
#include  "Debug.h"
#include  "Main.h"
#include  "Upd.h"


#define HAUTEUR_ECRAN      256
#define TAILLE_PLAN        ( HAUTEUR_ECRAN * 80 )
#define POS_FENETRE        0
#define HAUTEUR_FENETRE    ( HAUTEUR_ECRAN - POS_FENETRE )

#define TASK_NAME     "Z80"        /* Nom de la tache */
#define TASK_STACK    4000L        /* Taille de la pile pour la tache de fond */
#define HIGH_PRI         -1        /* Priorité normale */
#define LOW_PRI        -128        /* Priorité en tache de fond */

/*
// Etat de l'interruption 
*/
#define OFF         0
#define ON          1
#define STOPPED     2


/*
// Fonction de décodage et d'exécution des instr. Z80
*/
extern int ExecZ80( void );

extern void tsoftcode( void );


/*
// Etat du mode "debug"
*/
extern USHORT EtatDebug;

/*
// ViewPort de l'émulateur
*/
struct ViewPort * VP = NULL;

ULONG DisplayID = HIRES;    /* Mode écran */

UBYTE finProc = ETAT_RUN;      /* demande à la tache de fond de quitter */

/*
// Variable partagée (avec la tache de fond) pour le module PPI.C :
// lecture des touches du clavier
*/
UBYTE EtatLigneClav[ 16 ];

UBYTE VBL = 0;              /* Vertical Blanking Line (Bit 0 port B ppi) */

/*
// Police utilisée pour les écrans/fenêtres/gadgets
*/
struct TextAttr topaz8 =
    {
    "topaz.font", 8, 0, 0
    };


typedef struct 
    {
    struct MsgPort * PortInt;
    UBYTE FlagInt;
    } StInt;

StInt Interruption;


/*
// Structure clavier CPC
*/
typedef struct
    {
    UBYTE PortA;        /* Port A du ppi (colonne clavier) */
    UBYTE Ligne;        /* Numéro de ligne clavier ( de 0 à 9 ) */
    } stToucheClav;

/*
// Tableau de conversion des RAWKEYs AMIGA -> Touches CPC
*/
static stToucheClav TabTouches[ 128 ] =
    {
    /*
    //  un 0x0F dans le champ Ligne signifie une combinaison non utilisée
    //  ( la rom inférieure ne lit que les lignes de 0 à 9 )
    */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x00    ----        */
        { 0xFE, 0x08 },       /* RAW KEY CODE = 0x01    '1'         */
        { 0xFD, 0x08 },       /* RAW KEY CODE = 0x02    '2'         */
        { 0xFD, 0x07 },       /* RAW KEY CODE = 0x03    '3'         */
        { 0xFE, 0x07 },       /* RAW KEY CODE = 0x04    '4'         */
        { 0xFD, 0x06 },       /* RAW KEY CODE = 0x05    '5'         */
        { 0xFE, 0x06 },       /* RAW KEY CODE = 0x06    '6'         */
        { 0xFD, 0x05 },       /* RAW KEY CODE = 0x07    '7'         */
        { 0xFE, 0x05 },       /* RAW KEY CODE = 0x08    '8'         */
        { 0xFD, 0x04 },       /* RAW KEY CODE = 0x09    '9'         */
        { 0xFE, 0x04 },       /* RAW KEY CODE = 0x0a    '0'         */
        { 0xFD, 0x03 },       /* RAW KEY CODE = 0x0b    '='         */
        { 0xFE, 0x03 },       /* RAW KEY CODE = 0x0c    '£'         */
        { 0xBF, 0x02 },       /* RAW KEY CODE = 0x0d    '\'         */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x0e    ----        */
        { 0x7F, 0x01 },       /* RAW KEY CODE = 0x0f    F0          */
        { 0xF7, 0x08 },       /* RAW KEY CODE = 0x10    'A'         */
        { 0xF7, 0x07 },       /* RAW KEY CODE = 0x11    'Z'         */
        { 0xFB, 0x07 },       /* RAW KEY CODE = 0x12    'E'         */
        { 0xFB, 0x06 },       /* RAW KEY CODE = 0x13    'R'         */
        { 0xF7, 0x06 },       /* RAW KEY CODE = 0x14    'T'         */
        { 0xF7, 0x05 },       /* RAW KEY CODE = 0x15    'Y'         */
        { 0xFB, 0x05 },       /* RAW KEY CODE = 0x16    'U'         */
        { 0xF7, 0x04 },       /* RAW KEY CODE = 0x17    'I'         */
        { 0xFB, 0x04 },       /* RAW KEY CODE = 0x18    'O'         */
        { 0xF7, 0x03 },       /* RAW KEY CODE = 0x19    'P'         */
        { 0xFB, 0x03 },       /* RAW KEY CODE = 0x1a    '@'         */
        { 0xFD, 0x02 },       /* RAW KEY CODE = 0x1b    '['         */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x1c    ----        */
        { 0xDF, 0x01 },       /* RAW KEY CODE = 0x1d    F1          */
        { 0xBF, 0x01 },       /* RAW KEY CODE = 0x1e    F2          */
        { 0xDF, 0x00 },       /* RAW KEY CODE = 0x1f    F3          */
        { 0xDF, 0x08 },       /* RAW KEY CODE = 0x20    'Q'         */
        { 0xEF, 0x07 },       /* RAW KEY CODE = 0x21    'S'         */
        { 0xDF, 0x07 },       /* RAW KEY CODE = 0x22    'D'         */
        { 0xDF, 0x06 },       /* RAW KEY CODE = 0x23    'F'         */
        { 0xEF, 0x06 },       /* RAW KEY CODE = 0x24    'G'         */
        { 0xEF, 0x05 },       /* RAW KEY CODE = 0x25    'H'         */
        { 0xDF, 0x05 },       /* RAW KEY CODE = 0x26    'J'         */
        { 0xDF, 0x04 },       /* RAW KEY CODE = 0x27    'K'         */
        { 0xEF, 0x04 },       /* RAW KEY CODE = 0x28    'L'         */
        { 0xDF, 0x03 },       /* RAW KEY CODE = 0x29    'M'         */
        { 0xEF, 0x03 },       /* RAW KEY CODE = 0x2a    'ù'         */
        { 0xF7, 0x02 },       /* RAW KEY CODE = 0x2b    'µ'         */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x2c    ----        */
        { 0xEF, 0x02 },       /* RAW KEY CODE = 0x2d    F4          */
        { 0xEF, 0x01 },       /* RAW KEY CODE = 0x2e    F5          */
        { 0xEF, 0x00 },       /* RAW KEY CODE = 0x2f    F6          */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x30    ----        */
        { 0x7F, 0x08 },       /* RAW KEY CODE = 0x31    'W'         */
        { 0x7F, 0x07 },       /* RAW KEY CODE = 0x32    'X'         */
        { 0xBF, 0x07 },       /* RAW KEY CODE = 0x33    'C'         */
        { 0x7F, 0x06 },       /* RAW KEY CODE = 0x34    'V'         */
        { 0xBF, 0x06 },       /* RAW KEY CODE = 0x35    'B'         */
        { 0xBF, 0x05 },       /* RAW KEY CODE = 0x36    'N'         */
        { 0xBF, 0x04 },       /* RAW KEY CODE = 0x37    'M'         */
        { 0x7F, 0x04 },       /* RAW KEY CODE = 0x38    ','         */
        { 0x7F, 0x03 },       /* RAW KEY CODE = 0x39    ';'         */
        { 0xBF, 0x03 },       /* RAW KEY CODE = 0x3a    ':'         */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x3b    ----        */
        { 0x7F, 0x00 },       /* RAW KEY CODE = 0x3c    F'.'        */
        { 0xFB, 0x01 },       /* RAW KEY CODE = 0x3d    F7          */
        { 0xF7, 0x01 },       /* RAW KEY CODE = 0x3e    F8          */
        { 0xF7, 0x00 },       /* RAW KEY CODE = 0x3f    F9          */
        { 0x7F, 0x05 },       /* RAW KEY CODE = 0x40    ESPACE      */
        { 0x7F, 0x09 },       /* RAW KEY CODE = 0x41    DEL         */
        { 0xEF, 0x08 },       /* RAW KEY CODE = 0x42    TAB         */
        { 0xBF, 0x00 },       /* RAW KEY CODE = 0x43    ENTER       */
        { 0xFB, 0x02 },       /* RAW KEY CODE = 0x44    RETURN      */
        { 0xFB, 0x08 },       /* RAW KEY CODE = 0x45    ESC         */
        { 0xFE, 0x02 },       /* RAW KEY CODE = 0x46    CLR         */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x47    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x48    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x49    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x4a    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x4b    ----        */
        { 0xFE, 0x00 },       /* RAW KEY CODE = 0x4c    Fleche Haut   */
        { 0xFB, 0x00 },       /* RAW KEY CODE = 0x4d    Fleche Bas    */
        { 0xFD, 0x00 },       /* RAW KEY CODE = 0x4e    Fleche Droite */
        { 0xFE, 0x01 },       /* RAW KEY CODE = 0x4f    Fleche Gauche */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x50    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x51    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x52    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x53    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x54    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x55    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x56    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x57    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x58    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x59    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x5a    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x5b    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x5c    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x5d    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x5e    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x5f    ----        */
        { 0xDF, 0x02 },       /* RAW KEY CODE = 0x60    SHIFT       */
        { 0xDF, 0x02 },       /* RAW KEY CODE = 0x61    SHIFT       */
        { 0xBF, 0x08 },       /* RAW KEY CODE = 0x62    CAPS LOCK   */
        { 0x7F, 0x02 },       /* RAW KEY CODE = 0x63    CTRL        */
        { 0xFD, 0x01 },       /* RAW KEY CODE = 0x64    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x65    COPY (R-ALT) */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x66    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x67    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x68    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x69    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x6a    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x6b    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x6c    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x6d    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x6e    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x6f    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x70    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x71    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x72    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x73    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x74    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x75    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x76    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x77    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x78    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x79    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x7a    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x7b    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x7c    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x7d    ----        */
        { 0xFF, 0x0F },       /* RAW KEY CODE = 0x7e    ----        */
        { 0xFF, 0x0F }        /* RAW KEY CODE = 0x7f    ----        */
    };


/*
// Sauvegarde du Message-Port de la fenêtre principale de l'émulateur
*/
static struct MsgPort * msgp = NULL;


/*
// Nom des fichiers images des Roms du CPC...
*/
char NomLrom[ 256 ] = "LROM";
char NomUrom[ 256 ] = "UROM";
char NomRom7[ 256 ] = "ROM7";


/*
// Affiche un requester avec le message d'erreur
*/
void AfficheErreur( char * Message )
{
    static struct IntuiText texte = { 0, 0, JAM1, 15, 5, NULL, NULL, NULL };
    static struct IntuiText messOK = { 0, 0, JAM1, 6, 3, NULL, "OK", NULL };

    texte.IText = Message;
    AutoRequest( NULL, &texte, NULL, &messOK, 0, 0, 320, 72 );
}


static void APropos( struct Screen * Ecran )
{
    static struct IntuiText Textes[] = 
        {
        1, 0, JAM1,  40,  0, &topaz8, NULL, &Textes[ 1 ],
        1, 0, JAM1, 120, 10, &topaz8, ( UBYTE * )"Programme FREEWARE", &Textes[ 2 ],
        1, 0, JAM1,   0, 20, &topaz8, ( UBYTE * )"Remerciements à GOLDRUNNER (Thierry DE CARVALHO)", &Textes[ 3 ],
        1, 0, JAM1,  28, 30, &topaz8, ( UBYTE * )"ainsi qu'à DAKENN DOUR (Emmanuel ROUSSIN),", &Textes[ 4 ],
        1, 0, JAM1,  80, 40, &topaz8, ( UBYTE * )"ABSYS (Frédéric BELLEC),", &Textes[ 5 ],
        1, 0, JAM1,  80, 50, &topaz8, ( UBYTE * )"THE CYBORG (Alexis NASR),", &Textes[ 6 ],
        1, 0, JAM1,  80, 60, &topaz8, ( UBYTE * )"GRYZOR (Nicolas FRANCK),", &Textes[ 7 ],
        1, 0, JAM1,  80, 70, &topaz8, ( UBYTE * )"SoLO/CORPSE (Mike THOMAS).", NULL,
        };
    static struct IntuiText messOK = { 0, 0, JAM1, 6, 3, NULL, "OK", NULL };

    Textes[ 0 ].IText = vers + 7;
    AutoRequest( NULL, Textes, NULL, &messOK, 170, 80, 300, 112 );
    ScreenToFront( Ecran );
}


/*
// Affiche quelques informations de "débuggage" utiles sur AMI-CPC...
*/
static void AfficheInfosVecteurs( struct Screen * Ecran )
{
    static char * Chaine1 = "Point d'entrée routine d'émulation      0x00000000";
    static char * Chaine2 = "Adresse de base RAM CPC (64K linéaire)  0x00000000";
    static char * Chaine3 = "Adresse de base RAM CPC (>64K)          0x00000000";
    static char * Chaine4 = "Adresse de base ROM Inférieure CPC      0x00000000";
    static char * Chaine5 = "Adresse de base ROM Supérieure CPC      0x00000000";
    static char * Chaine6 = "Adresse de base ROM DISC (AMSDOS) CPC   0x00000000";
    static char * Chaine7 = "Adresse de base Mémoire Ecran CPC       0x00000000";
    static char * Chaine8 = "Mode écran sélectionné                  0x00000000";
    struct Window * Fenetre;
    struct Screen * Workbench;
    struct IntuiMessage * Message;

    if ( Workbench = LockPubScreen( ( UBYTE * )"Workbench" ) )
        {
        if ( Fenetre = OpenWindowTags( NULL
                                     , WA_Left,      0
                                     , WA_Top,       0
                                     , WA_Width,     640
                                     , WA_Height,    128
                                     , WA_IDCMP,     IDCMP_CLOSEWINDOW
                                                   | IDCMP_REFRESHWINDOW
                                     , WA_Flags,     WFLG_ACTIVATE
                                                   | WFLG_DRAGBAR 
                                                   | WFLG_DEPTHGADGET 
                                                   | WFLG_CLOSEGADGET
                                                   | WFLG_SMART_REFRESH
                                     , WA_Title,     "Infos AMI-CPC"
                                     , WA_PubScreen, Workbench
                                     , TAG_DONE
                                     )
           )
            {
            int fin = 0;

            UnlockPubScreen( NULL, Workbench );
            WBenchToFront();
            Hex( Chaine1 + strlen( Chaine1 ) - 8, ( ULONG )ExecZ80, 8 );
            Hex( Chaine2 + strlen( Chaine2 ) - 8, ( ULONG )&RAM_00, 8 );
            Hex( Chaine3 + strlen( Chaine3 ) - 8, ( ULONG )&RAM_C4, 8 );
            Hex( Chaine4 + strlen( Chaine4 ) - 8, ( ULONG )ROMINF, 8 );
            Hex( Chaine5 + strlen( Chaine5 ) - 8, ( ULONG )ROMSUP, 8 );
            Hex( Chaine6 + strlen( Chaine6 ) - 8, ( ULONG )ROMDISC, 8 );
            Hex( Chaine7 + strlen( Chaine7 ) - 8, ( ULONG )BitmapEcran, 8 );
            Hex( Chaine8 + strlen( Chaine8 ) - 8, ( ULONG )DisplayID, 8 );
            AfficheChaine( Fenetre, Chaine1, 10, 10 );
            AfficheChaine( Fenetre, Chaine2, 10, 25 );
            AfficheChaine( Fenetre, Chaine3, 10, 35 );
            AfficheChaine( Fenetre, Chaine4, 10, 45 );
            AfficheChaine( Fenetre, Chaine5, 10, 55 );
            AfficheChaine( Fenetre, Chaine6, 10, 65 );
            AfficheChaine( Fenetre, Chaine7, 10, 80 );
            AfficheChaine( Fenetre, Chaine8, 10, 95 );
            while ( ! fin )
                {
                /*
                // Attente messages
                */
                WaitPort( Fenetre->UserPort );
                while( Message = ( struct IntuiMessage * )GetMsg( ( struct MsgPort * )Fenetre->UserPort ) )
                    {
                    ReplyMsg( ( struct Message * )Message );
                    if ( Message->Class == CLOSEWINDOW )
                        fin = 1;
                    }
                }
            CloseWindow( Fenetre );
            ScreenToFront( Ecran );
            }
        else
            UnlockPubScreen( NULL, Workbench );
        }
}


/*
// Création et ouverture de la fenêtre avec ses gadgets
*/
static int OuvrirFenetre( struct Screen * Ecran
                        , struct Window ** Fenetre
                        )
{
    static UWORD chip Pointeur[] = { 0, 0, 0, 0, 0, 0, 0, 0 };

    if ( * Fenetre = OpenWindowTags( NULL
                                   , WA_Left, 0
                                   , WA_Top, POS_FENETRE
                                   , WA_Width, 640
                                   , WA_Height, HAUTEUR_FENETRE
                                   , WA_IDCMP, IDCMP_RAWKEY
                                             | IDCMP_ACTIVEWINDOW
                                             | IDCMP_INACTIVEWINDOW
                                   , WA_Flags, WFLG_ACTIVATE
                                             | WFLG_BACKDROP
                                             | WFLG_BORDERLESS
                                             | WFLG_NOCAREREFRESH
                                   , WA_CustomScreen, Ecran
                                   , TAG_DONE
                                   )
       )
        {
        SetPointer( * Fenetre, Pointeur, 1, 1, 0, 0 );
        return( 1 );
        }
    return( 0 );
}


/*
// Met la tache Z80 à la priorité haute
*/
static struct Task * SetHighPri( void )
{
    struct Task * tache = FindTask( TASK_NAME );

    if ( tache )
        SetTaskPri( tache, HIGH_PRI );

    return( tache );
}


/*
// Met la tache Z80 à la priorité basse
*/
static struct Task * SetLowPri( void )
{
    struct Task * tache = FindTask( TASK_NAME );

    if ( tache )
        SetTaskPri( tache, LOW_PRI );

    return( tache );
}


/*
// Démarre la tache d'émulation du CPC
*/
static int StartCPC( void )
{
    struct Task * this = FindTask( NULL );

    return( StartProcess( this, TASK_NAME, ExecZ80, HIGH_PRI, TASK_STACK ) );
}


/*
// Utilise un requester ASL pour sélectionner un fichier
*/
static void SelectFichier( struct Screen * Ecran )
{
    /* Pour sauvegardes des derniers paramètres... */
    static char Repertoire[ 256 ] = { 0 };
    static char Fichier[ 256 ] = { 0 };
    static WORD LeftEdge = 170, TopEdge = 56, Width = 300, Height = 400;

    struct FileRequester * req;
    char nomFic[ 256 ];

    if ( SetLowPri() )
        {
        WBenchToFront();
        req = ( struct FileRequester * )AllocAslRequest( ASL_FileRequest
                                                       , TAG_DONE 
                                                       );
        if ( req )
            {
            if ( AslRequestTags( req
                               , ASLFR_InitialPattern,  "#?.(CPC|DSK)"
                               , ASLFR_InitialFile,     Fichier
                               , ASLFR_InitialDrawer,   Repertoire
                               , ASLFR_InitialLeftEdge, LeftEdge
                               , ASLFR_InitialTopEdge,  TopEdge
                               , ASLFR_InitialWidth,    Width
                               , ASLFR_InitialHeight,   Height
                               , ASLFR_DoPatterns,      TRUE
                               , TAG_DONE
                               ) 
               )
                {
                /*
                // Extraction du nom du fichier et du répertoire et mémorisation
                */
                strcpy( Repertoire, req->fr_Drawer );
                strcpy( Fichier, req->fr_File );
                strcpy( nomFic, Repertoire );
                if (  ( * nomFic )
                   && ( nomFic[ strlen( nomFic ) - 1 ] != ':' )
                   && ( nomFic[ strlen( nomFic ) - 1 ] != '/' )
                   )
                    strcat( nomFic, "/" );
                strcat( nomFic, req->fr_File );
                EndUPD();
                InitUPD( nomFic );
                }
            /*
            // Mémorisation de la taille/position de la fenêtre du requester
            */
            LeftEdge = req->fr_LeftEdge;
            TopEdge  = req->fr_TopEdge;
            Width    = req->fr_Width;
            Height   = req->fr_Height;
            FreeAslRequest( ( APTR )req );
            }
        ScreenToFront( Ecran );
        SetHighPri();
        }
}


/*
// Fonction appelée lors de la détection d'une instruction Z80 incorrecte
// ou non codée. Envoie le message "appui sur la touche F5" à la fenêtre
// de l'émulateur...
*/
void __asm SendDebug( void )
{
    int cnt = 0;

    if ( msgp )
        {
        struct MsgPort * RepMsg = ( struct MsgPort * )CreatePort( "R-Z80", 0 );
        if ( RepMsg )
            {
            struct IntuiMessage * msg;
            struct IntuiMessage Message;

            Message.ExecMessage.mn_Node.ln_Type = NT_MESSAGE;
            Message.ExecMessage.mn_ReplyPort = RepMsg;
            Message.ExecMessage.mn_Length = sizeof( struct IntuiMessage );
            Message.Class = RAWKEY;
            Message.Code = 0x54;

            PutMsg( msgp, ( struct Message * )&Message );
            WaitPort( RepMsg );

            while( msg = (struct IntuiMessage * )GetMsg( RepMsg ) )
                ;

            DeletePort( RepMsg );

            while( ! EtatDebug )
                {
                Delay( 1 );
                if ( cnt++ > 10 )
                    break;
                }
            }
        }
}


/*
// Fonction principale : lecture des évenements...
*/
static void GestionMessages( struct Screen * Ecran
                           , APTR VisualInfo
                           , struct Window * Fenetre
                           )
{
    struct IntuiMessage * Message;
    UBYTE c;
    stToucheClav clav;
    struct MsgPort port;
    struct Interrupt softint;
    struct timerequest *tr;

    /*
    // Sauvegarde le "message-port" de la fenêtre
    */
    msgp = Fenetre->UserPort;


    /*
    // Interruption du timer.device
    */
    NewList( &( port.mp_MsgList ) );
    softint.is_Code = tsoftcode;
    softint.is_Data = &Interruption;
    softint.is_Node.ln_Pri = 0;
    port.mp_Node.ln_Type = NT_MSGPORT;
    port.mp_Flags = PA_SOFTINT;
    port.mp_SigTask = ( struct Task * )&softint;
    if ( tr = ( struct timerequest * )CreateExtIO( &port
                                                 , sizeof( struct timerequest )
                                                 ) 
       )
        {
        if ( ! ( OpenDevice( "timer.device"
                           , UNIT_ECLOCK
                           , ( struct IORequest * )tr
                           , 0
                           ) 
               ) 
           )
            {
            /*
            // Démarrage interruptions
            */
            Interruption.FlagInt = ON;
            Interruption.PortInt = &port;
            tr->tr_node.io_Command = TR_ADDREQUEST;
            tr->tr_time.tv_micro = FreqInt;
            BeginIO( ( struct IORequest * )tr );

            /*
            // Démarrage tache gestion Joystick
            */
            if ( StartJoy( FindTask( NULL ), "JOY.Z80", HIGH_PRI, TASK_STACK ) )
                {
                /*
                // Démarrage tache Z80
                */
                if ( StartCPC() )
                    {
                    while ( finProc != ETAT_FIN )
                        {
                        /*
                        // Attente messages
                        */
                        WaitPort( Fenetre->UserPort );
                        while ( Message = ( struct IntuiMessage * )GetMsg( Fenetre->UserPort ) )
                            {
                            ReplyMsg( ( struct Message * )Message );
                            switch ( Message->Class )
                                {
                                case RAWKEY :
                                    /*
                                    // Gestion clavier -> transformation RAWKEY Amiga
                                    // En code lignes et colonnes du CPC
                                    */
                                    c = Message->Code;
                                    clav = TabTouches[ c & 0x7F ];                

                                    if ( ! ( c & 0x80 ) )
                                        /* Appui */
                                        EtatLigneClav[ clav.Ligne ] &= clav.PortA;
                                    else
                                        /* Relachement */
                                        EtatLigneClav[ clav.Ligne ] |= ~clav.PortA;

                                    switch( c )
                                        {
                                        case 0x50 :             /* touche F1 */
                                            FreqInt = FREQ_1;
                                            break;

                                        case 0x51 :             /* touche F2 */
                                            FreqInt = FREQ_2;
                                            break;

                                        case 0x52 :             /* touche F3 */
                                            FreqInt = FREQ_3;
                                            break;

                                        case 0x53 :             /* touche F4 */
                                            FreqInt = FREQ_4;
                                            break;

                                        case 0x54 :             /* touche F5 */
                                            if ( ! EtatDebug )
                                                DebugMode( Ecran, VisualInfo );
                                            break;

                                        case 0x55 :             /* touche F6 */
                                            APropos( Ecran );
                                            break;

                                        case 0x56 :             /* touche F7 */
                                            SelectFichier( Ecran );
                                            break;

                                        case 0x57 :             /* touche F8 */
                                            ResetUPD();
                                            finProc = ETAT_RESET;
                                            while( finProc == ETAT_RESET )
                                                Delay( 1 );

                                            break;

                                        case 0x58 :             /* touche F9 */
                                            AfficheInfosVecteurs( Ecran );
                                            break;

                                        case 0x59 :             /* touche F10 */
                                            finProc = ETAT_FIN;
                                            break;
                                        }
                                    break;

                                case ACTIVEWINDOW :
                                    /* La fenêtre redeviens active
                                       Passage en priorité supérieure de
                                       la tache Z80 */
                                    SetHighPri();
                                    break;

                                case INACTIVEWINDOW :
                                    /* La fenêtre deviens inactive ->
                                       Passage en priorité inférieure de
                                       la tache Z80 */
                                    SetLowPri();
                                    break;
                                }
                            }
                        }
                    WaitProcess();
                    }
                WaitEndJoy();
                }
            Interruption.FlagInt =  OFF;
            while( Interruption.FlagInt != STOPPED ) 
                Delay( 10 );

            CloseDevice( ( struct IORequest * )tr );
            }
        DeleteExtIO( ( struct IORequest * )tr );
        }
}


/*
// Ajoute une valeur Hexadécimal sur 2 digits à une chaine
*/
static STRPTR ConcatHex2( STRPTR mess, UBYTE val )
{
    static STRPTR hexChaine = "0123456789ABCDEF";
    static char chaine[ 80 ];

    int l = strlen( mess );

    memcpy( chaine, mess, l );
    chaine[ l++ ] = hexChaine[ val >> 4 ];
    chaine[ l++ ] = hexChaine[ val & 15 ];
    chaine[ l ] = 0;
    return( chaine );
}


/*
// Ouvre l'écran de l'émulateur
*/
static struct Screen * GetEcran( ULONG DisplayID )
{
    static USHORT Look3D[] = { 0xFFFF };
    static struct BitMap StBitmap;
    struct Screen * Ecran;
    int i;
    
    InitBitMap( &StBitmap, 4, 640, HAUTEUR_ECRAN );

    for ( i = 0; i < 4; i++ )
        StBitmap.Planes[ i ] = ( PLANEPTR )( &BitmapEcran[ i * TAILLE_PLAN ] );

    Ecran = OpenScreenTags( NULL
                          , SA_Left,          0
                          , SA_Top,           0
                          , SA_Width,         640
                          , SA_Height,        HAUTEUR_ECRAN
                          , SA_Depth,         4
                          , SA_Type,          CUSTOMSCREEN | CUSTOMBITMAP
                          , SA_DisplayID,     DisplayID
                          , SA_BitMap,        &StBitmap
                          , SA_Quiet,         TRUE
                          , SA_ShowTitle,     FALSE
                          , SA_Font,          &topaz8
                          , SA_Pens,          Look3D
                          , TAG_DONE 
                          );
    VP = &Ecran->ViewPort;
    return( Ecran );
}


/*
// Lecture des ROMs du CPC
*/
static BOOL LectureROMs( void )
{
    BPTR handle;

    handle = Open( NomLrom, MODE_OLDFILE );      /* Rom inférieure (bios) */
    if ( handle )
        {
        Read( handle, ROMINF, 0x4000 );
        Close( handle );
        handle = Open( NomUrom, MODE_OLDFILE );  /* Rom supérieure (basic) */
        if ( handle )
            {
            Read( handle, ROMSUP, 0x4000 );
            Close( handle );
            handle = Open( NomRom7, MODE_OLDFILE );  /* Rom disc (AMSDOS) */
            if ( handle )
                {
                Read( handle, ROMDISC, 0x4000 );
                Close( handle );
                return( TRUE );
                }
            }
        }
    return( FALSE );
}


/*
// no comment...
*/
int main( int argc, char ** argv )
{
    struct Window * Fenetre;
    struct Screen * Ecran;

    APTR VisualInfo;
    
    GfxBase = ( struct GfxBase * )OpenLibrary( "graphics.library", 0 );
    if ( GfxBase )
        {
        if ( AfficheInvite( &argc, argv ) == BOUTON_OK ) /* Fenêtre démarrage */
            {
            if ( InitSound() )                           /* Init. audio.device */
                {
                if ( LectureROMs() )                     /* Lecture des ROMS CPC... */
                    {
                    if ( Ecran = GetEcran( DisplayID) )  /* Ouverture Ecran */
                        {
                        if ( VisualInfo = GetVisualInfo( Ecran, TAG_DONE ) )
                            {                
                            if ( OuvrirFenetre( Ecran, &Fenetre ) )
                                {
                                if ( argc ==2 )
                                    InitUPD( argv[ 1 ] );
                                else
                                    InitUPD( "DISC.CPC" );

                                GestionMessages( Ecran, VisualInfo, Fenetre );
                                CloseWindow( Fenetre );
                                EndUPD();
                                }
                            else
                                AfficheErreur( "Impossible d'ouvrir la fenêtre." );
                            FreeVisualInfo( VisualInfo );
                            }
                        else
                            AfficheErreur( "Impossible d'obtenir le VisualInfo de l'écran." );
                        CloseScreen( Ecran );
                        }
                    else
                        AfficheErreur( "Impossible d'ouvrir l'écran." );
                    }
                else
                    AfficheErreur( "Impossible de lire les ROMs CPC." );
                }
            else
                AfficheErreur( "Impossible d'allouer les canaux audio." );
            EndSound();
            }
        }
    else
        AfficheErreur( "Impossible d'ouvrir la Graphics.Library." );

    if ( ErreurED < 256 )
        AfficheErreur( ConcatHex2( "Erreur : ED ", ErreurED ) );

    if ( ErreurIX < 256 )
        AfficheErreur( ConcatHex2( "Erreur : DD ", ErreurIX ) );

    if ( ErreurCBIX < 256 )
        AfficheErreur( ConcatHex2( "Erreur : DD CB ", ErreurCBIX ) );

    if ( ErreurIY < 256 )
        AfficheErreur( ConcatHex2( "Erreur : FD ", ErreurIY ) );
        
    return( 0 );
}
