Bonjour,
J’écris un logiciel qui émule une machine qui a existé il y a maintenant plus de 25 ans. Il s’agit d’un ordinateur à base de MC6801/3 (un ancien processeur / microcontroleur 8 bits de Motorola) qui opérait l’OS Flex2.
Un bout de code fourche (fork) puis chaque branche ouvre un terminal (xterm, urxvt ou autre konsole), l’un exécutant l’émulateur avec son moniteur-débugger et l’autre simulant simplement une VT52. J’usqu’à maintenant, pas de problème, et le projet est bien avancé, bien qu'il reste beaucoup à faire. Il existe une commande du débogeur/moniteur qui permet de générer une interruption du processeur émulé (NMI ou IRQ), et cette partie se passe bien.
J’ai voulu être interrompu régulièrement (comme le matériel d’antan) et ai utilisé setitimer() pour ça. Mode ITIMER_REAL → SIGALRM. Tout fonctionne bien si ce n’est que le programme d’émulation s’arrête. J’ai beau chercher à savoir pourquoi, rien n’y fait : je ne trouve pas. Je ne sais pas où me mettre (avec le débogeur DDD) pour voir d’où vient le problème. J’imagine qu’un autre signal (d’erreur, probablement) est généré et que le handler par défaut de ce signal provoque l’abandon, mais je n’imagine pas de solution pour intercepter afin de débugger.
L’"allumage" du timer:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 pthread_mutex_t tiMut=PTHREAD_MUTEX_INITIALIZER; sig_atomic_t mSC=0; static void EmuEndPeriod (void) { // void (and !int sig) To escape the warning /// ************************************************************************** /* The handler is invoqued with SIGALRM (|SIGPROF|SIGVTALRM) signa. The kBitIRQ of _6303.IrqFlgs or kBitNMI of _6303.IrqFlgs will be set to initiate an interrution while stepping. As in the real word, it is the responsability of the emulated program to "acknowledge" the concerned bit. */ pthread_mutex_lock(&tiMut); //sig=0; // To escape the warning mSC+=1; // EmuIsGone ? _6303.IrqFlgs|=kBitNMI :0; // Sets the bit NMI pthread_mutex_unlock(&tiMut); } int EmuStep (void) { /// ************************************************************************** // Returns 0 if the opcode [_EmuGetMem(_6303.Pc)] is invalide pthread_mutex_lock(&tiMut); if ((i=mSC)) mSC=0; pthread_mutex_unlock(&tiMut); if (i) { if (gTimer2_NMI) { if(!(gRunner2-=i) || gRunner2&kBit(15)) { // Expiration if virtualy <0 gRunner2=gTimer2_NMI+gRunner2; // Re-init the timer _6303.IrqFlgs|=kBitNMI; // Sets the bit NMI } } if (gTimer4_IRQ) { if(!(gRunner4-=i) || gRunner4&kBit(15)) { // Expiration if 0 gRunner4=gTimer4_IRQ+gRunner4; // Re-init the timer _6303.IrqFlgs|=kBitIRQ; // Sets the bit IRQ } } } /** Interruption treatment is placed here to permit the execution of at least one instruction after the registers had been pushed in stack. One of the 10 bits corresponding to the IRQ is set somewhere in this function (see EmuSpcActLeave(), above). See IrqFlgs definition NOTE */ if (_6303.IrqFlgs) { // All bits if (_6303.IrqFlgs&kBitRST) { // Immediat and unconditional action _6303.IrqFlgs&=~kBitRST; EmuReset(); return(1); } else if ((_6303.IrqFlgs&kBitNMI) && // NMInterrupt request ((_6303.IrqPre^_6303.IrqFlgs)&kBitNMI)) // Falling edge (↑ indeed) EmuEnterIt(Vect_NMI); else if ((_6303.IrqFlgs&kBitIRQ) && (!(_6303.Cc&kI))) EmuEnterIt(Vect_IRQ); } _6303.IrqPre=_6303.IrqFlgs; // Note of the current state (solely for NMI)
Vous aurez compris que ma question est : savez-vous comment je pourrais me sortir de là ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 const struct itimerval gPeriod={{ 2, 10000 }, { 2, 10000 }}; void SetFreeRunner (void) { /// ************************************************************************** // ITIMER_REAL:SIGALRM | ITIMER_VIRTUAL:SIGVTALRM | ITIMER_PROF:SIGPROF static struct sigaction sa; // http://mtodorovic.developpez.com/linux/programmation-avancee/?page=page_8 memset(&sa, 0, sizeof (sa)); sa.sa_handler=(void(*)(int))&EmuEndPeriod; sigaction(SIGALRM, &sa, NULL); if (setitimer(ITIMER_REAL, &gPeriod, NULL)<0) // PerrExit("setitimer() a provoqué une erreur", 1); }
À noter que je placerai le tout en ligne et sous licence GNU. S'il vous tente de jeter un œil sur le projet, faites le moi savoir.
Je vous remercie pour l'attention que vous aurez porté à ce post.
Cordialement
Merci à Jérome.
Partager