MSX Village forum

La Place des Développeurs Appeler des fonctions du Bios dans le hook H.TIMI

aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2904

Le 18/11/2020 à 01h18
Hello,
J'ai voulais tester le système de Hook du MSX mais je suis tombé sur un bug que je ne comprends vraiment pas. :hum
Dans mon programme de test, j'ai juste une fonction qui incrémente un compter, change la couleur de fond et fait un beep via des routines bios.
Elle est branché sur le hook H.TIMI (vblank).
Ca fonctionne pendant un certains temps, puis ça fait reboot le MSX !
J'ai essayé de tracer le problème avec le debugger de OpenMSX, mais tout à l'air bon :
- L'adresse du Hook contient bien des RET au début, puis les instructions asm de JUMP vers ma fonction y sont bien copiés
- Je break sans soucis dans ma fonction de hook
- Après plusieurs centaines d'itérations tout semble normal : le code à l'adresse du HOOK est toujours présent et mon compteur s'incrémente tranquillement
Une idée de ce qu'il pourrait se produire !?

Voici le code du hook :
Code C :
 
void VBlankHook()
{
    DisableInterrupt();
    timer++;
    g_BAKCLR = timer & 0x0F;
    CallBios(CHGCLR);
    CallBios(BEEP);
    EnableInterrupt();
}
 

Code ASM :
 
_VBlankHook::
    di
    ld    iy, #_timer
    inc    0 (iy)
    ld    a, 0 (iy)
    and    a, #0x0f
    ld    (BAKCLR), a
    call    CHGCLR
    call    BEEP
    ret
    ei
 


Et le code de la boucle principale :
Code C :
 
void MainLoop()
{
    SetHookFunc(H_TIMI, VBlankHook);
 
    while(1) {}
}
 

Code ASM :
 
_MainLoop::
    ld    bc, #_VBlankHook
    ld    hl, #0xfd9f
    ld    (hl), #0xc3
    ld    (H_TIMI), bc
00102$:
    jr    00102$
 


On est toujours ignorant avant de savoir.
Github    
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2904

Le 18/11/2020 à 01h36
Bon, comme souvent, c'est en essayant de bien expliquer un problème... qu'on en trouve la solution. :lol

En fait la fonction bios "BEEP" empile des datas sans les dépiler !
En tout cas, la stack augmente de 52 octets à chaque appel de ma fonction callback... jusqu'à faire un écrasement de la mémoire.
Si je commente l'appel à la fonction BEEP, la stack ne bouge plus (la fonction CHGCLR (change color) n'a donc pas de problème de "fuite", elle).

Comment est-ce possible que la fonction BEEP puisse fuiter 52 octets à chaque appel !?

Je vais continuer mes tests pour essayer d'éclaircir ce mystère... :jesors


EDIT : J'ai check que si on fait des appels à la fonction bios BEEP en dehors de la fonction du hook (dans le programme principal), il n'y a pas de "fuite" mémoire. Y a t'il une liste de fonction bios à ne pas utiliser dans les Hook ? Toutes !? Ou y a-t-il une technique pour pouvoir les utiliser sans avoir les "fuites" ?


On est toujours ignorant avant de savoir.
Github    
ericb59 Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : compte ++ Groupe : Shoutbox

Inscrit le : 17/04/2012 à 10h25

Messages: 5566

Le 18/11/2020 à 08h04
As tu regardé les fonctions d’interruption de Fusion-c 1.3
Il y en a une sur le vdp et une sur htmi
Apparemment c’est la seule méthode qui fonctionne bien depuis le dos.
Je n’en suis pas l’auteur et je n’y comprend pas grand chose en fait.

Le problème étant que le bios lui même fait des interruptions lui aussi, et qu’il faut trouver une astuce.
En tout cas c’est ce qu’il me semble ? :siffle


banniere-ericb59e
Site web    
Sector28 Membre non connecté

Villageois

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 12/05/2018 à 23h00

Messages: 561

Le 18/11/2020 à 09h58
Le BEEP prend trop de temps à s’exécuter, pendant qu'il s’exécute, une autre interuption se produit, celle-ci a son tour exécute BEEP, pendant que ce dernier s’exécute, une interuption se produit, celle-ci a son tour execute BEEP, pendant que ce dernier s’exécute, une interuption se produit, celle-ci a son tour execute BEEP, pendant que ce dernier s’exécute, une interuption se produit, celle-ci a son tour execute BEEP, pendant que ce dernier s’exécute, une interuption se produit, celle-ci a son tour execute BEEP, pendant que ce dernier s’exécute, une interuption se produit, celle-ci a son tour execute BEEP, pendant que ce dernier s’exécute, une interuption se produit, celle-ci a son tour execute BEEP, pendant que ce dernier s’exécute, une interuption se produit, celle-ci a son tour execute BEEP, pendant que ce dernier s’exécute, une interuption se produit, celle-ci a son tour execute BEEP, pendant que ce dernier s’exécute, une interuption se produit, celle-ci a son tour execute BEEP, .. puis ça plante ^^


DONALD TRUMP IS FAST APPROACHING
NEMESIS ! RETURN IMMEDIATELY !
   
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2904

Le 18/11/2020 à 10h53
ericb59 :
As tu regardé les fonctions d’interruption de Fusion-c 1.3


J'ai jeté un œil, mais les fichiers complet en assembleur sont compliqués à lire pour moi. J'ai vu que (tous) les appels au Bios se font via des lectures/écritures interslot. Ce qui est pratique si la page 0 ne pointe pas vers la Main-ROM, mais je trouve que ça alourdit/ralenti l'exécution dans le cas de base (ou la Main-ROM est présente en page 0). Je pense pas que le problème vienne de là vu que je touche pas aux pages.

Sector28 :
Le BEEP prend trop de temps à s’exécuter, pendant qu'il s’exécute, une autre interuption se produit, celle-ci a son tour exécute BEEP, pendant que ce dernier s’exécute, une interuption se produit [..] puis ça plante ^^


:lol

Pourtant, je désactive les interruptions avec DI/EI durant l'exécution du hook... :gne


On est toujours ignorant avant de savoir.
Github    
Sector28 Membre non connecté

Villageois

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 12/05/2018 à 23h00

Messages: 561

Le 18/11/2020 à 12h23
Il y a un EI dans les routines CHGCRL et BEEP.


DONALD TRUMP IS FAST APPROACHING
NEMESIS ! RETURN IMMEDIATELY !
   
Sector28 Membre non connecté

Villageois

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 12/05/2018 à 23h00

Messages: 561

Le 18/11/2020 à 12h32
J'ai un peu modifié ..
Code :
void main(void)
{
  ...
  int sem=0;
  ...
}
void VBlankHook()
{
/*  DisableInterrupt();*/
    timer++;
    g_BAKCLR = timer & 0x0F;
    if (!sem) {
        sem=1;
        CallBios(CHGCLR);
        CallBios(BEEP);
        sem=0;
    }
/*  EnableInterrupt(); */
}


DONALD TRUMP IS FAST APPROACHING
NEMESIS ! RETURN IMMEDIATELY !
   
Sector28 Membre non connecté

Villageois

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 12/05/2018 à 23h00

Messages: 561

Le 18/11/2020 à 12h34
Il faut garder à l'esprit qu'une sous-routine d'interruption peut être interrompue par elle-même !


DONALD TRUMP IS FAST APPROACHING
NEMESIS ! RETURN IMMEDIATELY !
   
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2904

Le 18/11/2020 à 14h48
Sector28 :
J'ai un peu modifié ..


Tu viens de réinventer les Mutex, qu'on utilise en programmation multi-thread. :top

Ca peut être utile, mais dans mon cas particulier, je pensais plutôt essayer de mettre en place un système de deferred hook.
L'idée c'est d'utiliser la boucle principale pour synchroniser les hooks.
En gros, au lieu de s'exécuter, les hooks vont s'enregistrer dans une liste, puis dans la boucle principale je vais dépiler la liste et exécuter les fonctions en série.
J'ai pas grand espoir, mais si j'arrivais à faire tenir le code d'enregistrement dans la liste en 4 bytes de code, je pourrais directement le stocker dans l'espace RAM alloué aux hooks.
Sinon, il faudra que je passe par une fonction intermédiaire.


On est toujours ignorant avant de savoir.
Github    
Sector28 Membre non connecté

Villageois

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 12/05/2018 à 23h00

Messages: 561

Le 18/11/2020 à 15h21
Pourquoi ne pas faire tourner ton programme entièrement sous interruptions vbl, et transformer ta boucle principale en séquence de sous-routines ?
Le programme principal (en dehors des interruptions) se résumerait à ceci:
Code :

; initialisation du vecteur irq
...
...
...
boucle: jr boucle



DONALD TRUMP IS FAST APPROACHING
NEMESIS ! RETURN IMMEDIATELY !
   
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2904

Le 18/11/2020 à 15h40
C'est une question d'habitude. Même sur un moteur comme Unreal Engine 4, toute la partie multi-threadée est encapsulé de tel sorte que coté jeu, tu ne gères que des évènements "en séquence" et que tu n'as donc plus du tout besoin de t'inquiéter des problèmes de concurrence. C'est une philosophie qui me plait et qui peut n'avoir que très peu d'impact sur les perfs si c'est bien fait.


On est toujours ignorant avant de savoir.
Github    
ericb59 Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : compte ++ Groupe : Shoutbox

Inscrit le : 17/04/2012 à 10h25

Messages: 5566

Le 18/11/2020 à 16h51


banniere-ericb59e
Site web    
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2904

Le 18/11/2020 à 18h04


Super intéressant !
Faudra que je regarder les spécifications de fonction __critical, __interrupt() et __preserves_regs().
Après, j'ai l'impression qu'il n'y a pas de solution miracle.
Si on utilise les interruptions, faut gérer d'une façon ou d'une autre les cas de concurrence.


On est toujours ignorant avant de savoir.
Github    
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2904

Le 18/11/2020 à 18h13
Un article intéressant sur les interruptions : http://map.grauw.nl/articles/interrupts.php


On est toujours ignorant avant de savoir.
Github    
Metalion Membre non connecté

Conseiller Municipal

Rang

Avatar

Inscrit le : 23/12/2009 à 15h32

Messages: 1503

Le 13/01/2021 à 21h10
Sector28 :
Pourquoi ne pas faire tourner ton programme entièrement sous interruptions vbl, et transformer ta boucle principale en séquence de sous-routines ?

C'est la technique utilisée par Konami dans ses jeux sur MSX.

aoineko :
Ca peut être utile, mais dans mon cas particulier, je pensais plutôt essayer de mettre en place un système de deferred hook. L'idée c'est d'utiliser la boucle principale pour synchroniser les hooks. En gros, au lieu de s'exécuter, les hooks vont s'enregistrer dans une liste, puis dans la boucle principale je vais dépiler la liste et exécuter les fonctions en série.

Très intéressant cette technique ...
Tu peux développer ?


MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
   
Répondre
Vous n'êtes pas autorisé à écrire dans cette catégorie