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

Embarqué Discussion :

Décalage à gauche et retenue


Sujet :

Embarqué

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Developpeur independant
    Inscrit en
    Juillet 2015
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Developpeur independant

    Informations forums :
    Inscription : Juillet 2015
    Messages : 5
    Par défaut Décalage à gauche et retenue
    Bonjour,

    Je ne sais pas si je suis dans la bonne partie du forum vu que ma question porte sur plusieurs sujet. (Microcontrôleur, assembleur et C++)

    Sauf mauvaise recherche de ma part, je n'arrive pas à trouver une réponse à mon problème.
    Habituellement je développe en assembleur, mais la mon projet est trop grand pour me le permettre.
    Pour faire simple, dans mon algorithme je souhaite faire un décalage à gauche d'une variable 8 bits et regarder si j'ai la retenue qui est définie.
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    unsigned char var;
     
    // code
     
    var <<=1;
    if (carry = 1) {
        // code
    }

    Pour le moment je ne trouve pas de réponse efficace à mon problème après avoir tester avec une variable 16bits et un ensemble de structure et d'union.

    Le code assembleur résultant est comme suis : (même résultats sur tous mes tests)
    Code asm : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    	.dwpsn	file "../src/libILI9341.cpp",line 186,column 13,is_stmt,isa 0
            RLA.W     r14                   ; [] |186| 
    	.dwpsn	file "../src/libILI9341.cpp",line 187,column 13,is_stmt,isa 0
            MOV.W     r14,r15               ; [] |187| 
            SWPB      r15                   ; [] |187| 
            MOV.B     r15,r15               ; [] |187| 
            TST.B     r15                   ; [] |187| 
            JNE       $C$L18                ; [] |187|

    Or il est possible en utilisant la retenue (je n'ai pas besoin de garder l'intégrité de la donnée, je souhaite juste observer chaque bits un par un) :
    Code asm : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    	.dwpsn	file "../src/libILI9341.cpp",line 186,column 13,is_stmt,isa 0
            RLC.B     r14                   ; [] |186| 
            JNC       $C$L18                ; [] |187|

    Cette action économise de la flash (8 octets) et de l'horloge (4 cycles) mais je n'arrive pas à dire au compilateur de faire comme ça.

    Dans la fonction j'économise 4*8*12 cycles soit 384 total. Pour un ordinateur c'est pas grand-chose, pour un microcontrôleur de 16MHz c'est beaucoup quand la fonction est souvent appelée.

    Avez vous des connaissances sur ce sujet ?

    En vous remerciant.

  2. #2
    Membre chevronné
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2004
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juin 2004
    Messages : 539
    Par défaut
    Le C étant un langage dit "portable", le test du registre d'état n'est pas possible puisqu'il est propre à chaque processeur.

    En C/C++, en principe on teste le bit avant de décaler. Dans ton exemple, pour tester si le msb est à '1':

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if (var & 0x80)
       // le bit de poids fort est à '1'
    var <<=1; // et on décale ensuite
    Autre passibilité, si tu travailles toujours sur le même µContrôleur, ton compilateur doit permettre d'inclure des lignes en langage d'assemblage qui vont te permettre d'utiliser les instructions de saut conditionnel.

    Petite remarque en passant:
    if(carry = 1){
    Fais gaffe avec le "=". Il faut utiliser le "==" si tu veux faire une comparaison.

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Developpeur independant
    Inscrit en
    Juillet 2015
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Developpeur independant

    Informations forums :
    Inscription : Juillet 2015
    Messages : 5
    Par défaut
    Merci pour cette réponse.

    Oui en effet j'ai écris un peu vite mon besoin et je n'aurai pas dû faire cette faute.

    Ce qui m'ennuie d'écrire en ASM dans le C, c'est que je ne peux pas être sûr du registre utilisé pour la variable. Je vais continuer à regarder ce côté quand même.

  4. #4
    Membre chevronné
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2004
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juin 2004
    Messages : 539
    Par défaut
    la variable ne se trouve pas dans un registre mais dans la mémoire. Le compilateur convertira le nom de la variable en son adresse en principe.

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Developpeur independant
    Inscrit en
    Juillet 2015
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Developpeur independant

    Informations forums :
    Inscription : Juillet 2015
    Messages : 5
    Par défaut
    Le code ASM mis dans mon premier post est le retour de compilation par le compilateur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    .dwpsn	file "../src/libILI9341.cpp",line 186,column 13,is_stmt,isa 0
            RLA.W     r14                   ; [] |186| 
    	.dwpsn	file "../src/libILI9341.cpp",line 187,column 13,is_stmt,isa 0
            MOV.W     r14,r15               ; [] |187| 
            SWPB      r15                   ; [] |187| 
            MOV.B     r15,r15               ; [] |187| 
            TST.B     r15                   ; [] |187| 
            JNE       $C$L18                ; [] |187|
    Ce qui se traduit en C/C++ :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
           décalage à gauche du registre 14
           copie du registre 14 vers 15
           échange des deux octets du registre 15   (on fonctionne en 16 bits)
           effacement de l'octet de poids fort du registre 15
           teste du registre 15 = zéro ?
           si non zéro > saut
    Pour des soucis de performance, je vérifie le code généré en demandant au logiciel de me garder les fichiers ASM.
    Il est observable que la variable utilisé est bien le registre 14.
    Sauf utilisation de tableau, si moins de 10 variables de 16 bits maximum sont utilisées, alors seuls des registres servent aux calculs. (1 cycle horloge par opération contre en moyenne 4 sur accès RAM)

    Pour l'utilisation de la RAM/ROM avec un registre pointant vers cette dernière, le code associé est de la forme (mélange de différents accès) : MOV @R12+, &0x200

    Le MSP430 possède 16 registres de 16bits en tout (un pour la position dans le programme (PC), un pour la pile (SP), un pour le statut (SR) qui sert aussi de générateur de constante, d'un dédié pour la génération de constante (R3) et le reste pour le programme (R4 à R15))

    Pour le moment j'arrive à indiquer au compilateur quand utiliser le SWPB, mais pas encore (mon post initial) comment utiliser une commande tel que JC ou JNC qui teste respectivement si la retenue est à 1 ou non.
    Cette commande est également disponible sur Intel depuis pas mal d'années (Exemple) et est également disponible sur MicroC Atmel tout comme sur le MicroC que j'ai utilisé durant mes cours.
    Je suis surpris que cette simple instruction n'est pas prise en compte dans les langages moderne qui permet d'économiser des ressources. qui sont de plus en plus perdu par les multi-couches des programmes.
    - Couche 0 : Processeur
    - Couche 1 : OS
    - Couche 2 : C/C++ (interpréteur Java/Python ou Navigateur web pour les machines virtuelles)
    - Couche 3 : programme haut niveau (Javascript/Java/Python)

    Chaque couche ralentissant les performances de la suivante.

    Merci pour ces informations, je vais continuer mes recherches.

  6. #6
    Membre chevronné
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2004
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juin 2004
    Messages : 539
    Par défaut
    je connais l'asm de plusieurs processeur, mais pas celui du MSP430. Je ne m'aventurerai donc pas trop de ce côté, même si je pense comprendre globalement le code asm que tu as joint.

    En principe, les compilateurs possèdent de nombreuses options dont celles de l'optimisation. Peut-être faudrait-il creuser de ce côté: optimisation de la taille du code, de sa rapidité, etc.

  7. #7
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 252
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant en Systèmes Embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2002
    Messages : 3 252
    Par défaut
    Bonjour,
    Regarde si tu n'as pas accès à une fonction qui s'appelle __get_SR_register; dans <intrinsics.h> ? C'est fait pour interroger le Status Register qui contient la "Carry"

    J'ai pas essayé, je n'ai plus de MSP430 dans mon stock pour le moment, mais ça devrait s'utiliser comme ça :

    Code C : 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
    #include <msp430.h>
    #include <intrinsics.h>
     
    int main(void)
    {
      unsigned int StatusReg = 0;
      unsigned char var;
     
      WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer
      P1DIR |= 0x01;                        // Set P1.0 to output direction
     
      var <<=1;
      StatusReg = __get_SR_register;
     
     
     if (StatusReg & 0x01) {
        // code
     }
    }

  8. #8
    Futur Membre du Club
    Homme Profil pro
    Developpeur independant
    Inscrit en
    Juillet 2015
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Developpeur independant

    Informations forums :
    Inscription : Juillet 2015
    Messages : 5
    Par défaut
    Oui j'ai déjà testé cette solution du __get_SR_register.
    Le hic c'est que le compilateur copie le registre dans un autre avant de faire la comparaison 🙂
    Donc problème similaire.

  9. #9
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 252
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant en Systèmes Embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2002
    Messages : 3 252
    Par défaut
    Citation Envoyé par Moroyoshi Voir le message
    Le hic c'est que le compilateur copie le registre dans un autre avant de faire la comparaison 🙂
    Donc problème similaire.
    Je ne suis pas sur de comprendre.

    Essaye de déclarer la variable StatusReg en volatile pour forcer le compilateur à mettre à jour l'emplacement mémoire de la variable (et non pas le registre de travail qui contient StatusReg.


    volatile unsigned int StatusReg = 0;
    Code C : 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
     
    #include <msp430.h>
    #include <intrinsics.h>
     
    int main(void)
    {
      volatile unsigned int StatusReg = 0;
      unsigned char var;
     
      WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer
      P1DIR |= 0x01;                        // Set P1.0 to output direction
     
      var <<=1;
      StatusReg = __get_SR_register;
     
     
     if (StatusReg & 0x01) {
        // code
     }
    }

  10. #10
    Futur Membre du Club
    Homme Profil pro
    Developpeur independant
    Inscrit en
    Juillet 2015
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Developpeur independant

    Informations forums :
    Inscription : Juillet 2015
    Messages : 5
    Par défaut
    Programme testé :

    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
    #include <msp430.h>
    #include <intrinsics.h>
    
    void main(void)
    {
      volatile unsigned int StatusReg = 0;
      unsigned char var = 10;
    
      WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer
      P1DIR |= 0x01;                        // Set P1.0 to output direction
    
      while (1) {
        var <<=1;
        StatusReg = __get_SR_register();
    
        if (StatusReg & 0x01) {
          P2OUT = var;
        }
      }
    }
    Résultat (réduit) :

    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
    ;*****************************************************************************
    ;* FUNCTION NAME: main                                                       *
    ;*                                                                           *
    ;*   Regs Modified     : SP,SR,r15                                           *
    ;*   Regs Used         : SP,SR,r15                                           *
    ;*   Local Frame Size  : 0 Args + 2 Auto + 0 Save = 2 byte                   *
    ;*****************************************************************************
    main:
    ;* --------------------------------------------------------------------------*
    	.dwcfi	cfa_offset, 2
    	.dwcfi	save_reg_to_mem, 16, -2
            SUB.W     #2,SP                 ; [] 
    	.dwcfi	cfa_offset, 4
    $C$DW$5	.dwtag  DW_TAG_variable
    	.dwattr $C$DW$5, DW_AT_name("StatusReg")
    	.dwattr $C$DW$5, DW_AT_TI_symbol_name("StatusReg")
    	.dwattr $C$DW$5, DW_AT_type(*$C$DW$T$21)
    	.dwattr $C$DW$5, DW_AT_location[DW_OP_breg1 0]
    
    ;* r15   assigned to var
    $C$DW$6	.dwtag  DW_TAG_variable
    	.dwattr $C$DW$6, DW_AT_name("var")
    	.dwattr $C$DW$6, DW_AT_TI_symbol_name("var")
    	.dwattr $C$DW$6, DW_AT_type(*$C$DW$T$6)
    	.dwattr $C$DW$6, DW_AT_location[DW_OP_reg15]
    
    	.dwpsn	file "../main.c",line 7,column 35,is_stmt,isa 0
            MOV.W     #0,0(SP)              ; [] |7| 
    	.dwpsn	file "../main.c",line 8,column 21,is_stmt,isa 0
            MOV.B     #10,r15               ; [] |8| 
    	.dwpsn	file "../main.c",line 10,column 3,is_stmt,isa 0
            MOV.W     #23168,&WDTCTL+0      ; [] |10| 
    	.dwpsn	file "../main.c",line 11,column 3,is_stmt,isa 0
            OR.B      #1,&P1DIR+0           ; [] |11| 
    ;* --------------------------------------------------------------------------*
    ;*   BEGIN LOOP $C$L1
    ;*
    ;*   Loop source line                : 13
    ;*   Loop closing brace source line  : 20
    ;*   Known Minimum Trip Count        : 1
    ;*   Known Maximum Trip Count        : 4294967295
    ;*   Known Max Trip Count Factor     : 1
    ;* --------------------------------------------------------------------------*
    $C$L1:    
    	.dwpsn	file "../main.c",line 14,column 5,is_stmt,isa 0
            RLA.B     r15                   ; [] |14| 
    	.dwpsn	file "../main.c",line 15,column 5,is_stmt,isa 0
            MOV.W     SR,0(SP)              ; [] |15| 
    	.dwpsn	file "../main.c",line 17,column 5,is_stmt,isa 0
            BIT.W     #1,0(SP)              ; [] |17| 
            JEQ       $C$L1                 ; [] |17| 
                                              ; [] |17| 
    ;* --------------------------------------------------------------------------*
    	.dwpsn	file "../main.c",line 18,column 7,is_stmt,isa 0
            MOV.B     r15,&P2OUT+0          ; [] |18| 
            JMP       $C$L1                 ; [] |18|
    Idée intéressante mais le MOV.W et BIT.W sont de trop.
    Voir même, est ce que le passage sur la stack avec le 0(SP) ne ralonge pas le temps de traitement ?

    En compilant avec -o4 et -mf5 on obtient le même cycle de code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    .dwpsn	file "../main.c",line 14,column 5,is_stmt,isa 0
            RLA.B     r15                   ; [] |14| 
            MOV.B     r15,r15               ; [] |14| 
    	.dwpsn	file "../main.c",line 15,column 5,is_stmt,isa 0
            MOV.W     SR,0(SP)              ; [] |15| 
    	.dwpsn	file "../main.c",line 17,column 5,is_stmt,isa 0
            BIT.W     #1,0(SP)              ; [] |17| 
            JNE       $C$L2                 ; [] |17|

  11. #11
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 641
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 641
    Par défaut
    Bonjour,

    Si le but est de récupérer le bit de poids fort, il y a un solution simple : déclarer ou caster la variable comme signé. Chaque décalage donnera une valeur négative si ce bit est à 1 et positive ou nulle sinon. Le test devient if(v < 0) ...; { 1 } else ...; {0}. Si le décalage est juste avant le test, les optimisations du compilateur peuvent éviter la comparaison (on peut toujours rêver un peu).

    Salutations

Discussions similaires

  1. Clic droit/gauche souris
    Par Mouse! dans le forum AWT/Swing
    Réponses: 4
    Dernier message: 30/05/2013, 20h34
  2. Jointure externe gauche
    Par christie dans le forum Langage SQL
    Réponses: 2
    Dernier message: 31/05/2004, 17h09
  3. 2 Count() sur deux tables en jointures gauches
    Par Alexandre T dans le forum Langage SQL
    Réponses: 2
    Dernier message: 03/09/2003, 16h53
  4. Popup avec un clic gauche
    Par Jéremy A dans le forum Composants VCL
    Réponses: 7
    Dernier message: 27/02/2003, 22h15
  5. gérer le clic gauche-droite en même temps de la sou
    Par Guigui_ dans le forum Langage
    Réponses: 4
    Dernier message: 29/11/2002, 22h52

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