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

Autres architectures Assembleur Discussion :

Switch case en asm ?


Sujet :

Autres architectures Assembleur

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2006
    Messages : 18
    Points : 54
    Points
    54
    Par défaut Switch case en asm ?
    Bonjour,

    Je me remet à l'asm après plus de 20 ans sans. C'est un peu rude. Je viens demander un peu d'aide ici, même si ça ne concerne pas spécifiquement l'asm x86. J'essaie de faire un mini interpreteur d'un petit bytecode que j'ai défini pour un microcontroler. Meme si la question est sans doute classique, je me demande comment faire l'équivalent d'un switch/case en asm spécifiquement pour interpéter l'octet de chaque bytecode, les uns apres les autres. En gros à chaque octet correspond un bout de code asm à executer. Il y a surement x façons de faire, mais je cherche évidemment la plus rapide :
    1/ j'ai exclu les cmp et call/jmp à la chaine, beaucoup trop long
    2/ j'ai imaginé fonctionner par dichotomie pour accélérer, mais ça me parait encore trop lent
    3/ peut être pourrait on faire une table avec les adresses des bouts de codes, et utiliser l'octet du bytecode à traiter comme index de cette table ?
    4/ j'imagine qu'on pourrait utiliser l'octet, le multiplier par une valeur (liée à la taille de chaque bloc d'instructions) et faire le saut en fonction du résultat. par contre ça impose que tous les blocs fassent la même taille, quite à perdre de la place...

    Bon, j'imagine qu'il y a des méthodes plus intelligentes, mais je ne trouve pas ? Et Google ne m'a pas vraiment aidé sur ce coup...

    MERCI

    ps : inutile de me donner du code asm86 tout cuit, seul l'algo/idée me suffit... puisque c'est pour un asm non x86...

  2. #2
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 226
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 226
    Points : 10 188
    Points
    10 188
    Par défaut
    Cool un post intéressant
    (un truc qui ne parle pas de x86-16 bits ^^)
    tout dépend de ton besoin.

    Pour ma part si c'est juste quelque if(switch/case) on général on définie comme dans ce code le label sortant donc en plus simplifié (en pseudo asm)
    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
     
     
    cmp reg1,1
    beq CASE1
     
    cmp reg1,2
    beq CASE2
     
    cmp reg1,3
    beq CASE3
     
    cmp reg1,4
    beq CASE4
     
     
    CASE1:
    //code
    jmp  L_OUT
     
    CASE2:
    //code
    jmp  L_OUT
     
    CASE3:
    //code
    jmp  L_OUT
     
    CASE4:
    //code
    jmp  L_OUT
     
     
     
    L_OUT:



    par exemple sur un de mes code , je l'ai fait un peu différaient (la raison est que c'est un proc 8 bit et les beq ne peuvent sauter que 128 octet max) :
    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
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
     
    upload_offset:
     
     
    	mov a,!toffset
    	cmp a,#0
    	bne +
    		jmp !upload_offsetc0
    	+:
    	cmp a,#1
    	bne +
    		jmp !upload_offsetc1
    	+:
    	cmp a,#2
    	bne +
    		jmp !upload_offsetc2
    	+:
    	cmp a,#3
    	bne +
    		jmp !upload_offsetc3
    	+:
    	cmp a,#4
    	bne +
    		jmp !upload_offsetc4
    	+:
    	cmp a,#5
    	bne +
    		jmp !upload_offsetc5
    	+:
    	cmp a,#6
    	bne +
    		jmp !upload_offsetc6
    	+:
    	cmp a,#7
    	bne +
    		jmp !upload_offsetc7
    	+:
     
    	ret
     
    upload_offsetc0:
    	MIDI_offset 0
    	ret
     
    upload_offsetc1:
    	MIDI_offset 1
    	ret
     
    upload_offsetc2:
    	MIDI_offset 2
    	ret
     
    upload_offsetc3:
    	MIDI_offset 3
    	ret
     
    upload_offsetc4:
    	MIDI_offset 4
    	ret
     
    upload_offsetc5:
    	MIDI_offset 5
    	ret
     
    upload_offsetc6:
    	MIDI_offset 6
    	ret
     
    upload_offsetc7:
    	MIDI_offset 7
    	ret

    Si c'est un microcontrolleur et que le compilateur est un gcc , l'option -S te donnera son code asm
    par exemple pour :
    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
     
    int main()
    {
        int var,a;
    	switch(var)
      {
    	case 1:
    		 a+= 5;
    	break;
     
    	case 2:
    		 a+= 15;
    	break;
      }
     
     
     
     
     
    	return 0;
    }
    on a en asm atmel :
    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
    56
    57
     
    	.file	"main.c"
    __SP_H__ = 0x3e
    __SP_L__ = 0x3d
    __SREG__ = 0x3f
    __tmp_reg__ = 0
    __zero_reg__ = 1
    	.text
    .global	main
    	.type	main, @function
    main:
    	push r28
    	push r29
    	rcall .
    	rcall .
    	in r28,__SP_L__
    	in r29,__SP_H__
    /* prologue: function */
    /* frame size = 4 */
    /* stack size = 6 */
    .L__stack_usage = 6
    	ldd r24,Y+1
    	ldd r25,Y+2
    	cpi r24,1
    	cpc r25,__zero_reg__
    	breq .L3
    	cpi r24,2
    	cpc r25,__zero_reg__
    	breq .L4
    	rjmp .L2
    .L3:
    	ldd r24,Y+3
    	ldd r25,Y+4
    	adiw r24,5
    	std Y+4,r25
    	std Y+3,r24
    	rjmp .L2
    .L4:
    	ldd r24,Y+3
    	ldd r25,Y+4
    	adiw r24,15
    	std Y+4,r25
    	std Y+3,r24
    	nop
    .L2:
    	ldi r24,0
    	ldi r25,0
    /* epilogue start */
    	pop __tmp_reg__
    	pop __tmp_reg__
    	pop __tmp_reg__
    	pop __tmp_reg__
    	pop r29
    	pop r28
    	ret
    	.size	main, .-main
    	.ident	"GCC: (Fedora 4.7.2-1.fc18) 4.7.2"


    4/ j'imagine qu'on pourrait utiliser l'octet, le multiplier par une valeur (liée à la taille de chaque bloc d'instructions) et faire le saut en fonction du résultat. par contre ça impose que tous les blocs fassent la même taille, quite à perdre de la place...
    Je l'ai deja utilisé et enfaîte le mieux c'est que c'est un bloc appelle une fonction ou un jump , vu que leur taille est facile a connaître.
    Mais c'est plus un pointeur de function qu'il faut utiliser , mais je les utilises que pour charger des donnés différent , par exemple le 1 charge des donnés , le 2 charge d'autre données etc , jamais vraiment pour la logique du code.

    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
     
    //code qui calcul MEM_TEMP donc  MEM_TEMP = Map_Level_out + (opcode* valeur)
    // ici opcode est la taille de jsl adresse + rts
    	ldx #0
    	jsr (MEM_TEMP,x) //saute a Map_Level_out mais a des endroits différents level 1 ,2 ou 3
     
    	rts
     
    Map_Level_out:
     
    	jsl Map_Level1_out
    	rts
     
    	jsl Map_Level2_out
    	rts
     
    	jsl Map_Level3_out
    	rts

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2006
    Messages : 18
    Points : 54
    Points
    54
    Par défaut Merci !
    Merci pour ta réponse !

    Ta première proposition ne me parait pas ce que je veux. Tu fais des comparaison à la chaine et c'est justement ce que je veux éviter... Si je teste le opcode 100, je dois faire 99 tests pour arriver au bon code ! Pour un langage à bytecode, qui doit donc etre rapide, c'est raté ! (ou alors je n'ai pas compris ton code...)

    Pour info, c'est pour le microcontroleur propeller parallax. J'ai posé la question sur leur forum et j'ai de sacré bonnes idées : http://forums.parallax.com/discussio...-in-asm#latest

    je pense que je dois avancer plus sur mon code pour décider de comment faire cette boucle et ce test. Je viendrai surement donner le résultat de mon boulot ici... A+ !

  4. #4
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 226
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 226
    Points : 10 188
    Points
    10 188
    Par défaut
    il y'a différente façon oui , alors je te conseille de faire un pointeur de fonction (comme mon derniers exemple) , tu met une valeur et tu calcul le bon pointeur qui sautera du coup sur la bonne fonction .

    D'ailleurs sur mon dernier bout de code c'est aussi une des raisons que j'utilise le pointeur de fonction vu que j'avais prévu 200-300 map ne voulant pas faire plein de if , j'ai opté pour cette solution.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Je ne sais pas si je réponds à ta question mais voici une esquisse de programme assez classique qui semble correspondre à ce que tu demandes. Le principe en est simple : on dispose d'une valeur fournie dans AL qui doit déclencher un process si elle est contenue dans une table pointée par ValeursDetect. Si cette valeur est dans la table, on se sert de l'offset trouvé pour pointer la table des process correspondants. Du coup, on peut appeler ledit process par un CALL. Je n'entre pas dans les détails sauf si tu le souhaites. Attention, c'est du "vite-fait" et je n'ai pas pris la peine de tester!

    Code Asm : 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
    .DATA
    ValeursDetect	db 5h
    			db 17h
    			db 23h
    			db 48h
     
    TableProcess	dd offset Process1
    			dd offset Process2
    			dd offset Process3
    			dd offset Process4
     
    .CODE
    ; la donnée devant déclencher l'un ou l'autre process est contenue dans AL
    START:
    	mov  ecx,4 	; compteur 
    	mov  esi,offset ValeursDetect
     
    BCLE:
    	cmp [esi],AL	
    	je Trouve	; valeur trouvée dans la table !
    	inc esi
    	loop BCLE
    	jmp Fin		; exit car aucune valeur trouvée
     
    ;---- Process identifié => on va voir la table des process 
    Trouve:
    	sub  esi,offset ValeursDetect
    	shl  esi,2			; multiplication par 4
    	call [esi+TableProcess]		; appel du process sélectionné
    	jmp Fin
     
    Process1:
    ;	(instructions) 
    	ret 
    Process2:
    ;	(instructions)  
    	ret
    Process3:
    ;	(instructions)  
    	ret
    Process4:
    ;	(instructions)  
    	ret 
     
    ;---- Fin du programme 
    FIN:
    Fichiers attachés Fichiers attachés
    Dernière modification par Obsidian ; 09/04/2017 à 18h57. Motif: Balises [CODE].

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2006
    Messages : 18
    Points : 54
    Points
    54
    Par défaut
    Merci pour ta réponse Asmou...

    Mais en gros tu testes toi aussi les valeurs les unes après les autres, dans une boucle. Donc si je cherche le saut correspondant à la valeur 100, je dois d'abord faire 99 tests... pas très optimisé comme fonctionnement. En tous cas pas assez pour espérer faire un langage à bytecode qui doit être vraiment optimisé, car par nature beaucoup plus lent que de l'asm "natif"... Mais j'ai des pistes, je vais creuser tout ça...

  7. #7
    Membre chevronné
    Avatar de Forthman
    Homme Profil pro
    conception mécanique
    Inscrit en
    Janvier 2005
    Messages
    702
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Tarn et Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : conception mécanique
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2005
    Messages : 702
    Points : 1 905
    Points
    1 905
    Par défaut
    Pour faire ce genre de test, je vois principalement deux possibilités (qui ont déjà été données)
    - la classique imbrication de IF THEN
    point fort : compacte
    points faible : lisibilité et vitesse d'exécution (pour optimiser on peut placer les cas les plus fréquents en premier s'ils sont connus)

    - utilisation d'un tableau d'adresses de sous-programmes
    points forts : lisibilité et vitesse d'exécution
    point faible : suivant le nombre de valeurs à tester ça peut être un gouffre en quantité de RAM allouée

    sur une architecture 32 bits, avec une valeur en entrée sur 1 octets, il nous faut un tableau de 256x4 = 1Ko
    et si la valeur en entrée est une valeur 16 bits, le tableau devra faire 256Ko

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2006
    Messages : 18
    Points : 54
    Points
    54
    Par défaut
    Merci pour ta réponse. Oui il y a x façons de faire, mais évidemment des methodes plus optimisées que d'autres (et on ne fait pas de l'asm pour faire un truc lent et moche en général). Je renvoie tout le monde à la discussion sur le foum propeller (j'ai mis le lien dans une de mes précédentes réponses); beaucoup de propositions efficaces... maintenant reste plus qu'à...

  9. #9
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par henri_b Voir le message
    Merci pour ta réponse. Oui il y a x façons de faire, mais évidemment des methodes plus optimisées que d'autres (et on ne fait pas de l'asm pour faire un truc lent et moche en général). Je renvoie tout le monde à la discussion sur le foum propeller (j'ai mis le lien dans une de mes précédentes réponses); beaucoup de propositions efficaces... maintenant reste plus qu'à...
    En fait, il n'y a pas de règle générale d'hyper-optimisation et tu n'y arrives qu'avec des techniques difficilement portables d'un programme à un autre. Seul point commun : une dépense de ressources parfois considérable. Dans une procédure de fenêtre (callback), par exemple, je préfère une succession de CMP car ça préserve la lisibilité du source, même si ça donne des boutons aux puristes...

  10. #10
    Membre chevronné

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 391
    Points : 1 779
    Points
    1 779
    Par défaut
    Il manque une étape ici !
    Un CPU ... c'est ni plus ni moins que de la logique câblée sur une puce !
    La manière la plus élégante est de s'appuyer sur l'encodage des registres, modes d'adressage, conditions, opérations... au niveau des bits de l'instruction.
    C'est le meilleur moyen pour faire une optimisation correcte vitesse/taille du code !

Discussions similaires

  1. [Language]Probleme de switch case
    Par nana1 dans le forum Langage
    Réponses: 20
    Dernier message: 17/11/2005, 01h49
  2. switch case pour deux variable en meme temps
    Par petitours dans le forum C
    Réponses: 3
    Dernier message: 06/11/2005, 20h20
  3. [Tableaux] Problème avec Switch case
    Par philippef dans le forum Langage
    Réponses: 4
    Dernier message: 07/09/2005, 17h37
  4. probleme gestion condition switch - case
    Par DarkMax dans le forum Langage
    Réponses: 5
    Dernier message: 07/09/2005, 15h25
  5. [Language] aide sur les switch case
    Par pouss dans le forum Langage
    Réponses: 3
    Dernier message: 05/04/2005, 12h34

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