IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Assembleur Discussion :

[Pentium] Optimisation - Alignement


Sujet :

Assembleur

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut [Pentium] Optimisation - Alignement
    La documentation du 486 mentionne 3 cycles d'horloge pour les instructions shl, shr, sar. Mais sur le pentium, ces instructions peuvent etre utilisé dans le pairing. Est-ce que ca veut dire que sur les pentiums ces instructions ne prennent de base qu'un cycle ? et si oui, est-ce seulement les pentiums ?

    Autre question. En considerant les codes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      mov ax, [ebx]
      mov dx, [ebx+2]
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
      mov edx,  [ebx]
      mov ax, dx
      shr edx, 16
    La deuxième version prends vraissemblablement plus de cycles d'horloge, mais elle ne contient qu'un seul accès à la mémoire. Laquelle des deux versions est la plus rapide ? Est-ce que cette rapidité est liée au caching ?

    (Sinon au cas ou, vous connaissez un bon debugueur-desassembleur tournat sous windows pour programmes dos ?)

  2. #2
    Invité
    Invité(e)
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      mov edx,  [ebx] 
      mov ax, dx 
      shr edx, 16
    La deuxième version prends vraissemblablement plus de cycles d'horloge, mais elle ne contient qu'un seul accès à la mémoire. Laquelle des deux versions est la plus rapide ? Est-ce que cette rapidité est liée au caching ?
    Tu mélange tu 16/32 bits sur edx ce que les procs n'apprécie pas (c'est un partial register stall)
    En faisant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    mov edx,  [ebx] 
      mov eax, edx 
      shr edx, 16
    c'est déjà mieux...

    Laquelle des deux versions est la plus rapide ?
    Ca depend... du code avant et après (pour le pairing), si les données en ebx sont alignés sur 4 octect ou non....
    De plus, tu a un seul accès mémoire mais une chaîne de dépendance sur edx (le proc ne peut pas faire mov eax,edx tant que edx n'est pas chargé).
    Au contraire dans la première version le proc peut éxecuter les 2 mov en parallèle (mais ca prend plus de 2 cycles...)

    Pour plus d'info sur les optimisation Intel depuis le Pentium
    http://www.nondot.org/sabre/os/files...imization.html

    On ce qui concerne les cycles de SHR reg,imm (et SHL...) elle s'execute en 1 cycle sur un Pentium/PentiumMMX.
    mais elle ne s s'execute que dans l'unité U (ce qui limite le pairing).
    Sur proc > PPro, on compte plutôt les µops+cycles de latence maintenant.
    L'optimisation devient un vrai casse-tête sur ces procs et compter les cycles est trés difficile.

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    oki, merci ! mais si j'utilisais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
      mov edx,  [ebx] 
      mov ax, dx 
      shr edx, 16
    c'est parcee que je sait que les 16 bits de poid fort de eax, sont à 0.
    donc si je repose correctement ma question ca donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
      xor eax, eax
      mov edx, [ebx]
      mov ax, dx
      shr edx, 16
    il y a un meilleur moyen de faire ca ? (c'est un structure que je retrouve souvent dans mon projet, et le moindre cycle que je peux gagner améliore les performances.

  4. #4
    Invité
    Invité(e)
    Par défaut
    Essaye ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    mov edx, [ebx] 
    mov eax, edx 
    shr edx, 16
    and eax, 0x0000FFFF ; annule les bits de poids haut
    En fin tout ça dépend de ton proc. Si c'est sur 486, il faut peut-être mieux utiliser la première version.

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    euh.. je programme pas que pour moi, ca aurait été cool que ca soit mieux pour tout le monde. M'enfin je peux pas faire une version pour chaque processeur, je compte déja pas les dixaines d'heures que j'ai passée a coder ca...

    Mais je me repose une autre question :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      mov ax, [ebx] 
      mov dx, [ebx+2]
    d'accord il n'y a pas de chaine de dépendance, mais il y a deux accès a la mémoire successif, et le proc est bien obligé d'attendre que l'acces soit fini non ?

    Autre question de codage plus général. Si je veux que mon coded sois rapide, je dois m'arranger pour que il soit le plus petit possible ? (pour le cache ?)
    Parce que la plus grande partie de mon optimisation était de faire des tables, plein de tables et de macro. Ca va bien plus vite en cycle d'horloge, mais il n'y a pas une perte dee vitesse due a la trop grand eparpillation deds données ?

  6. #6
    Invité
    Invité(e)
    Par défaut
    mais il y a deux accès a la mémoire successif, et le proc est bien obligé d'attendre que l'acces soit fini non ?
    Oui.
    Autre question de codage plus général. Si je veux que mon coded sois rapide, je dois m'arranger pour que il soit le plus petit possible ? (pour le cache ?)
    Et là non: le code le plus court n'est généralement pas le plus rapide. Exemple: dérouler une boucle par 2 ou 4 améliore les performances.
    De plus les routines de plus de 16k sont rares en asm (taille du L1 code à partir du PMMX sauf P4).
    mais il n'y a pas une perte dee vitesse due a la trop grand eparpillation deds données ?
    Exact... pour les données il faut éviter des appels successif a des blocs mémoire "distant" pour éviter de devoir rafraîchir le cache de données L1.
    Exemple: je suppose que edi,esi pointe sur deux DWORD "distant" dans TAS, alors si tu fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    mov eax , [edi]
    mov edx , [esi]
    alors, lors du deuxième mov, le proc doit charger une nouvelle ligne du cache de donnée L1 (différent du cache code) depuis le L2, et surement aussi de la mémoire vers le L2.
    Il faut donc regrouper les accès d'une même région mémoire.

    En conclusion, la gestion des caches (code et données) est compliqué: c'est d'ailleurs le proc qui s'en occupe tout seul et heureusement. Il existe toutefois de nombreuse technique pour les "utiliser" (en fait pour que le proc mette ce qu'on veut en cache).
    Regarde le "AMD Athlon Processor x86 Code Optimization Guide" à l'adresse
    http://www.amd.com/us-en/assets/cont...docs/22007.pdf
    et pour Intel,
    http://www.intel.com/design/pentiumi...als/245127.htm
    Globalement, on optimise de la même manière sur Athlon et P6.

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    euh moi mon code a base de macros et de tables il est totu en assembleur, mais il fait 80 ko... je suis dans la merde pour le cache L1, surtout que windows doit en plus en bouffer pas mal a reprendre le controle pour passer d'un thread a un autre non ?

  8. #8
    Invité
    Invité(e)
    Par défaut
    surtout que windows doit en plus en bouffer pas mal a reprendre le controle pour passer d'un thread a un autre non
    Pour la préemption, c'est le proc qui fait le gros du travail. De toutes façons, il ne faut pas oublier que, lors d'une session normale (ie sans jeux...), ton proc ne fait RIEN 99% du temps.
    La préemption n'influe pas trop sur les perfs (si tu n'execute pas 2 gros calculs en même temps bien sur): essaye des chronos avec un thread de calcul en priorité IDLE et TIME_CRITICAL et tu verras que le gain est négligeable (pourtant bcp moins de préemption).

    il est totu en assembleur, mais il fait 80 ko
    Si c'est une seule routine, c'est gênant. L'important dans cas est de ne pas avoir de saut trop grand, ni de bloucle trop grosse (ie < L1 code)
    Remarque: sur un Athlon/Duron, le cache L1 de code est de 64k (le data aussi, ce qui explique une partie des perfs de ces procs/Intel).

  9. #9
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    ben c un emulateur la partie boucle c'est ca :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    DebutBloc:
      dec ecx
      js FinBloc
     
      mov edx, [ebx]
      xor eax, eax
      mov ax, dx
      push DebutBloc
      jmp TbIns16[eax*4]
    TbIns16 fait 256 ko ... euh, il vaut mieux que je raepasse à une table 8 bits ?

    Ensuit pour la majortié des opcodes, il y a le traitement du mod r/m, qui se fait a peu près de la même manière, par exemple pour des opérandes 16 bits :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    shr eax, 8
    call MODRM16[eax*4]
    et puis après c'est du traitement particulier pour chaque instruction... Tu n'aurais pas un peu de temps pour regarder ??

    http://perso.wanadoo.fr/blustuff/emu86/

    sinon, dis moi jeuste comment je devrait mieux organiser mon code... En tout cas c'est déja très gentil de m'avoir autant répondu :)) merci beaucoup !

  10. #10
    Invité
    Invité(e)
    Par défaut
    D'après ce que je comprends,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    push DebutBloc  ; adresse de retour
    jmp TbIns16[eax*4]    ; je suppose que ça termine par un ret
    sert à emuler un call. C'est mauvais... les procs préfère les call/ret.

    Il vaut mieux faire dans EmulerBloc

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    CalculeSS
    CalculeDS
    CalculeES
    CalculeEBX
    mov ecx, NbInstructions
    jecxz FinBloc  ; au cas ou
     
    DebutBloc: mov edx, [ebx]
               xor eax, eax
               mov ax, dx             
               call TbIns16[eax*4]    
               dec  ecx
               jnz DebutBloc
    Le goulot d'étranglement n'est pas la suite mov edx,... mais bien le call à une adresse dynamique (via eax) (même remarque pour le mod r/m).
    Ca trouble les mécanisme de prédiction de branchement et autre.
    Je ne suis pas spécialiste de l'émulation mais optimiser un émulateur est effectivement diffile (ce n'est pas pour rien que les émulateurs necessite en général des config musclés).
    Je ne vois pas comment utiliser le cache au maximum... ni comment changer les call dynamique en statique.

    Un conseil: laisse tomber l'asm pur et fait le en C/C++ avec fontion asm inline quand nécessaire. Les compilateurs on fait d'enorme progrès grace à l'adressage linéaire qui leur simplifie la vie. Il y a de bonne chance que ce soit plus rapide que de l'asm pur

  11. #11
    Membre actif

    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    339
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 339
    Points : 279
    Points
    279
    Par défaut
    (Sinon au cas ou, vous connaissez un bon debugueur-desassembleur tournat sous windows pour programmes dos ?)
    Moi j'utilise W32Dasm (v8.93). Je le trouve pas mal (un peu difficile au début surtout qu'il est en anglais). Il désassemble et debugge les exe et les com. Il indique quelques liens dûs au jmp near ou je, jb, jz ......

    J'utilise aussi Hackman et je trouve que W32Dasm est plus puissant (et surtout plus rapide)

    Donc si ça t'intéresse dis-le moi (il fait <1MO)
    Ma boule de cristal s'était éclaircie et puis plus rien. Alors je me suis mis à internet et maintenant j'ai plus de renseignements qu'avec cette satané boule .....

  12. #12
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    ah non, je repasserait pas au C... Bochs est en C, est d'après mes derniers tests, j'émule 4 à 10 fois plus vite suivant les instructions... (en sachant bien que les instructions en pmode seront plus lourdes donc l'ecart sera forcement plus faible, mais c'est déja enorme) Ce qui me gène surtout en C, c'est que je n'aurais pas la magnifique boucle de préprocesseur qui crée les mod r/m, et difficilement la plus grosse des optimisations, qui vise a supprimer l'utilité de MachineVirtuelle.r_eip en utilisant

    ebx = MachineVirtuelle.RAM + MachineVirtuelle.cs * 16 + MachineVirtuelle.eip

    Ces deux dernières optimisation on augmenté de 50 à 80 % les performances d'après les tests. Et la manière dont j'ai codé tout ca, me facilite grandement la tache pour passer au pmode et adressage / opérandes 32 bits. En C, je vosi vraiment pas comment coder ca aussi bien.

    Il y aurait un moyen de rendre le call statique. En modifiant sois même l'opcode. Ca se fait ca ? il suffirait de changer l'adresse du saut, en le remplacant simplement par l'adresse ce que contient eax :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      lea eax, [eax * 4 + TabIns16]
      mov [LabelCall +1], eax
    ca se fait ca ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      push DebutBloc
      jmp TbIns16[eax*4]
    Ca je l'ai lu dans MASM. Il parait que c'était une optimisation pour le pentium... m'enfin si c'est faux.
    Je croyais avoir lu aussi que jecxz, il ne fallait plus l'utiliser

    merci bcp d'avoir regardé mon code (ca devait etre assez horrible non ? :) )

  13. #13
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    Cmment un compilateur pourrait faire un truc plus rapide ? et c'est quoi l'adressage linéaire ? C'est pas trop grave que mon programme prenne plus d'1 mo en mémoire quand il est chargé ?

  14. #14
    Invité
    Invité(e)
    Par défaut
    Cmment un compilateur pourrait faire un truc plus rapide ? c'est quoi l'adressage linéaire
    En mode réel la mémoire est segmentée: un pointeur c'est [segment:offset]. Et un segment de mémoire fait 64k: si un tableau dépasse 64k (donc un tableau de pointeur allouée dynamyquement), on passe son temps à faire des "les di,...", sauvegarder les registres de segments (ds,es) etc... Et pour ça, l'humain se débrouille bcp mieux qu'un compilateur: en ASM sous DOS, même mal codé, on gagne toujours en vitesse.

    En mode protégée, plus de segmentation !!! C'est l'adressage linéaire: tu peut accéder directement à 4Go de RAM.
    De plus, tu peut profiter des accès mémoire de la forme [edi+4*ecx+54]. Ca simplifie énormément la tâche du compilo.

    De plus, les procs actuels (architecture P6) peuvent exectuer les instructions dans le désordre (donc plus besoin de réarranger les instructions pour profiter à fond du pairing). Pour ce faire, il utilise un renommage des registres (en fait il passe par des registres temporaire) qui élimine aussi certaine dépendence etc...
    Ca rapttape les déficiences du compilo...

    C'est pas trop grave que mon programme prenne plus d'1 mo en mémoire quand il est chargé ?
    En mp, aucun pb.

    Il parait que c'était une optimisation pour le pentium... m'enfin si c'est faux
    Pour le pentium, j'avoue que je ne sais pas trop mais pour les supérieurs c'est clair qu'il faut toujours avoir le couple call/ret (tu mets en défault les prédiction de branchement et autre: plus une prédiction est bonne, comme sur P6, plus une erreur coûte cher...). Pour trancher essaye, c'est vite fait.

    Je croyais avoir lu aussi que jecxz, il ne fallait plus l'utiliser
    C'est vrai, mais pour un seul appel en dehors des boucles... de plus jecxz à l'avantage de n'avoir pas besoin de test/cmp donc ne touche pas aux flags ce qui peut être intéressant.

    En conclusion, if faut savoir sur quel procs ton émulateur va tourner en général et optimiser pour celui-ci.

    PS: En bonus deux remarques sur ton code
    Utilise movzx pour eviter les partial register stall (!!! sur des procs >= PPro !!!):
    Exemples
    1- de CalculeDS
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
                    xor eax, eax
                    mov ax, MachineVirtuelle.r_ds
    devient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                    movzx eax , MachineVirtuelle.r_ds
    2- de RequerirInterruption
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
       xor eax, eax                           
       mov al, cl
    devient
    Comme c'est une combinaison que tu utilise souvent, le gain peut être intéressant.


    Utilise les possiblités d'adressage par index.
    Exemples:
    1- de InitialiserModule
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    			mov ecx, 100h
    @@:			mov [eax], offset Interruption_non_geree
    			mov [ebx], offset Sortie_non_geree
    			mov [edx], offset Enree_non_geree
    			add eax, 4
    			add ebx, 4
    			add edx, 4
    			dec ecx
    			jnz @b
    devient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    			mov ecx, 100h-1h
    @@:			mov [eax+4*ecx], offset Interruption_non_geree
    			mov [ebx+4*ecx], offset Sortie_non_geree
    			mov [edx+4*ecx], offset Enree_non_geree
    			dec ecx
    			jns @b
    Note que dans ce cas, on va dans les sens décroissant des pointeurs. Il est d'ailleurs trés intéressant de dérouler ce genre de boucle.


    2- de ReferencerInt
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    			mov edx, eax                    
    			shl eax, 2			
    			mov edi, MachineVirtuelle.RAM	
    			add edi, eax                    
    			mov [edi], edx
    devient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    			mov edi, MachineVirtuelle.RAM	
                            mov [edi+2*eax] , eax

  15. #15
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    merciiii pour les bonus :)). Je vais mettrre des movzx partout

    en fait masm qui m'a mit en erreur disait ca :

    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
     
    movzx r16, rm8  486+       xor bx, bx           MOVZX is faster and
                               mov bl, al           smaller on the 386.
     
                                                    On the 486+ XOR/MOV
     
    movzx r32, rm8  486+       xor ebx, ebx         is faster. Possible
                               mov bl, al           pairing on the Pentium.
                                                    (source can be reg or mem)
     
    movzx r32, rm16 486+       xor ebx, ebx         disadvantage: modifies flags
                               mov bx, ax
     
    call dest1      286+       push offset dest2    When CALL is followed by
    jmp  dest2                 jmp  dest1           a JMP, change the return
                                                    address to the JMP destination.
     
    call dest1      all        jmp  dest1           When a CALL is followed by a
    ret                                             RET, the CALL can be replaced
     
                                                    by a JMP.

    Pour les CalculDS, RequerirInterruption, InitialisaerModule, ReferencerInt, c'est très gentil gentil, mais ca va pas bcp optimiser, elles sont appellées que très peu souvent ces fonction...

    En fait ce que j'aurais aimé aussi savoir, c'est si un compilateur aurait pu faire mieux, que ce que moi j'ai fait en asm, puisqu'il y a quand même deds optimisations que j'ai faites impossible à faire par un compilateur. En clair j'ai codé tout ca pour rien ?

    Et le fait qu'il prenne 1 Mo n'est pas du tout gênant pour le caching ?

    Le call/ret je peux pas le tester, la je suis sur un K6 II, 500 Mhz, enfin je crois qu'il ne prevoie rien du tout lui ?

    et pour mon historie de

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      lea eax, [eax *4 + TabIns16]
      mov AdresseCall, eax
     
      db E8
    AdresseCall dd 0
    ca marche ou pas ?

    Dis comment tu fait pour savoir autant de choses et avoir le temps de me répondre ? :))

    En tout cas je crois que je pourrais jamais te remercier assez pour ton aide :)

  16. #16
    Invité
    Invité(e)
    Par défaut
    Le call/ret je peux pas le tester, la je suis sur un K6 II, 500 Mhz, enfin je crois qu'il ne prevoie rien du tout lui ?
    Tu vois bien que MASM précise que c'est quand le call est suivi d'un jmp qu'il est préférable de faire push jmp. Donc call/ret toujours même sur K6.

    Pour les CalculDS, RequerirInterruption, InitialisaerModule, ReferencerInt, c'est très gentil gentil, mais ca va pas bcp optimiser, elles sont appellées que très peu souvent ces fonction...
    J'ai pris ses routines aux hasard. Ce qu'il faut retenir, c'est les méthodes.

    En fait ce que j'aurais aimé aussi savoir, c'est si un compilateur aurait pu faire mieux, que ce que moi j'ai fait en asm, puisqu'il y a quand même deds optimisations que j'ai faites impossible à faire par un compilateur.
    Il a des chances qu'un compilo fasse mieux. Les compilos connaisse mieux que nous les optimisations possibles. De plus il aligne le code, les données etc...
    Le meilleur compilo pour l'optimisation est celui.. d'Intel (on s'y attendait) .

    En clair j'ai codé tout ca pour rien ?
    On ne code jamais pour rien ne serait-ce par tout ce qu'on apprend au passage.


    Et le fait qu'il prenne 1 Mo n'est pas du tout gênant pour le caching ?
    La taille du programme n'est pas importante. Ce qu'il faut c'est que les routines critiques tienne dans le L1.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Code: 
      lea eax, [eax *4 + TabIns16] 
      mov AdresseCall, eax 
     
      db E8 
    AdresseCall dd 0
    ca marche ou pas ?
    Ca doit être pire, Le "self-modifying code" est à PROSCRIRE (cf doc Intel et AMD).
    Sans compter que ca ne marche pas à cause du pipeline: quand il execute le mov AdresseCall, la suite (db E8 etc...) est DEJA dans le pipeline.

    Dis comment tu fait pour savoir autant de choses et avoir le temps de me répondre
    15 ans de programmation + nombreuses nuits à éplucher les docs + test = patience.
    J'ai le temps de te répondre car je suis développeur mais je travaille chez moi (je ne passe au boulot qu'une fois par semaine), c'est donc moi qui gère mon temps...

  17. #17
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    Les compilateurs auraient-il pu créer les même optimisations là :

    - Reserver ebx pour l'adresxse de l'opcode actuellement émulé ? Sachant que je l'ai réservé étant certain, qu'il ne serait jamais utilisé dans aucune instruction. Je savais quoiqu'il arrive, qu'il étati préférable de stocker la valeur des registres si nécessaire dans la pile, plutot que de changer la valeur de ebx, parce que je savais, qu'a chaque instrtuction, j'en avais besoin.

    - Creer 32 tables des mod r/m que je construit avec des directives FOR du preprocesseurs, que je n'ai retrouvée que dans MASM et NASM ?

    - Utiliser lahf et sahf, qui permette d'avoir de recreer l'état des flags sans tests supplémentaires ?

    - Creer des tables de lables tout court ? mon compilateur a une manière bizzare de gerer les pointeurs sur fonction...

    le call était bien suivi d'un jmp, puisque j'avais réorganisé la boucle pour que les tests soient en début ce qui donnait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      call TabIns16[eax*4]
      jmp DebutBoucle
    m'enfin ca c'est parce que je faisait un saut si zero, et non pas un saut si non zero, ce qui serait logique, mais vu que j'ai retouché de nombreuses fois cette fonction, j'avais oublié de modifier ce passage.

    Si j'observe bien c'est que la seule routine critique et la boucle qui contient le call TabIns16[eax*4]

  18. #18
    Invité
    Invité(e)
    Par défaut
    Attention, je n'ai pas dis que ce serait simple en C !!!

    - Pour générer tes tables, tu peut faire un petit prog qui génère le fichier c (ou h). C'est une technique souvent utilisé...
    - Dans le cas de lahf utilise de l'asm inline, il est toutefois préférable de gérer toi-même les flags
    - pour ebx, tu peut utiliser une variable: cela réduit la "pression" sur les registres et tu peut optimiser les macro des instructions.

    J'ai trouvé ce projet OpenSource (emu86 !!) en C pur sur le net
    http://cvs.berlios.de/cgi-bin/viewcv...u86/emu86/src/
    (et d'ailleurs, le fichier cpu_modrm.h est bien généré par programme....)

    Le C a en plus l'avantage de la portabilité ce qui est intéressant pour un émulateur non ?

    PS:
    Le call/ret je peux pas le tester, la je suis sur un K6 II, 500 Mhz, enfin je crois qu'il ne prevoie rien du tout lui ?
    Tu peut le tester, je viens de télécharger la doc d'optimisation du K6-2 et le fonctionnement sur ce point est identique à l'architecture P6.

  19. #19
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2002
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2002
    Messages : 7
    Points : 7
    Points
    7
    Par défaut
    pour un desassembleur Ida me semble tres bon ...
    pour debugguer du 16b j utilise trw2000...( c est ptet pas le meilleur mais c est mieux, pour une fois, que SoftIce)
    mais je crois qu il existe d autre debug sous dos ..(sans parler de l infame Td..)

  20. #20
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    Il compile ca comment les switchs le compilateur ?? (j'ai du mal a croire que ca procedure en C pour le mod r/m est plus rapide que la mienne. (Déja au niveau de l'algorithme la mienne est plus rapide)

    Mon code pour l'emulation du x86 est portable unix. Moi je m'arette là. Mais de toutes facons, il y a un tas de fonctions de l'API Win32 que j'utilise pour l'emulation, donc il va falloir que je fasse une version unix en changenat ces fonctions. Et puis je vais utiliser OpenGL. Honnetement je fait un émulateur x86 pour 486+. Et là l'assembleur me suffit.

    Si je gère les flags, je perd enormement de temps AMLIN, je peux pas me permettre de tester le resultat sous toutes ses coutures... regarde un peu quelque une des instructions, il n'y a que très peu d'instructions a chaque fois.

    Quant a l'alignement des données, je peux le faire moi même. Si je me souviens bien, il y a des directives pour que l'assembleur le fasse.

    J'ai passé enormement de temps a coder/optimiser ce truc. J'ai vraiment du mal a voir, comment je pourrais faire mieux en C, d'autant que ca me prendrait encore beaucoup de temps, et que de l'asm inline + des fichiers générés aléatoirement + les optimisations d'algo qui donne des codes tordus, ce sera vraiment un suplice pour les adeptes du C a lire, et ca ne sera pas tellement portable.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 3 123 DernièreDernière

Discussions similaires

  1. Optimisation de votre SGBDR et de vos requêtes...
    Par SQLpro dans le forum Langage SQL
    Réponses: 35
    Dernier message: 11/01/2013, 11h49
  2. JBuilder7 & JTable Colonne alignement
    Par Tonton Luc dans le forum JBuilder
    Réponses: 5
    Dernier message: 06/11/2002, 17h32
  3. [Datareport] Alignement
    Par SpaceFrog dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 05/11/2002, 11h53
  4. [VB6] [Printer] Chiffres alignés à droite
    Par Laye dans le forum VB 6 et antérieur
    Réponses: 7
    Dernier message: 03/10/2002, 18h36
  5. [langage] Optimiser la lecture d'un fichier
    Par And_the_problem_is dans le forum Langage
    Réponses: 2
    Dernier message: 11/06/2002, 10h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo