Je travaille sur un projet intégré (cible PowerPC, Compilateur de marque Freescale Metrowerks) où les registres sont mappés sur la mémoire et définis dans de jolis bitfields pour former les drapeaux de bits individuels faciles.
Pour le moment, nous sommes Utilisation de cette fonctionnalité pour effacer les indicateurs d'interruption et le transfert de données de contrôle. Bien que je n'ai pas encore remarqué de bugs, j'étais curieux si c'est sûr. Y a-t-il un moyen d'utiliser des champs de bits en toute sécurité, ou dois-je envelopper chacun dans Disable_interrupts ... Activer_interrupts? P>
Pour clarifier: L'en-tête fourni avec le micro a des champs tels que P>
union { vuint16_t R; struct { vuint16_t MTM:1; /* message buffer transmission mode */ vuint16_t CHNLA:1; /* channel assignement */ vuint16_t CHNLB:1; /* channel assignement */ vuint16_t CCFE:1; /* cycle counter filter enable */ vuint16_t CCFMSK:6; /* cycle counter filter mask */ vuint16_t CCFVAL:6; /* cycle counter filter value */ } B; } MBCCFR;
6 Réponses :
L'atomicité dépend de la cible et du compilateur. AVR-GCC, par exemple, TRYS Pour détecter l'accès au bit et l'émetteur de bits ou des instructions claires si possible. Vérifiez la sortie de l'assembleur pour être sûr ... p>
Edit: Voici une ressource pour les instructions atomiques sur PowerPC directement à partir de la bouche du cheval: p>
Quand cela peut, mais toutes les adresses ne l'appuient pas, et cela ne peut être fait que si l'adresse est connue à l'heure de la compilation.
@Negoose Oui, mieux pour l'épeler comme vous l'avez fait que d'impliquer comme je l'ai fait.
Il est correct de supposer que les champs de réglage ne sont pas atomiques. La norme C n'est pas particulièrement claire sur la manière dont les champs de bit doivent être mis en œuvre et divers compilateurs vont de différentes manières. p>
Si vous vous souciez vraiment de votre architecture et de votre compilateur de votre cible, désassemblez un code d'objet. P>
Généralement, votre code atteindra le résultat souhaité, mais sera beaucoup moins efficace que le code utilisant des macros et des décalages. Cela dit, il est probablement plus lisible d'utiliser vos champs de bits si vous ne vous souciez pas de la performance ici. P>
Vous pouvez toujours écrire une fonction d'emballage de setter pour les bits atomiques, si vous êtes préoccupé par les futurs codeurs (y compris vous-même) étant confus. P>
Cela dépend totalement de l'architecture et du compilateur si les opérations Bitfield sont atomiques ou non. Mon expérience personnelle raconte: n'utilisez pas de champs de bit si vous n'êtes pas obligé. p>
Oui, votre hypothèse est correcte, en ce sens que vous ne pouvez pas supposer d'atomicité. Sur une plate-forme spécifique, vous pourriez l'obtenir comme un supplément, mais vous ne pouvez pas compter sur elle en tout cas. P>
Fondamentalement, le compilateur effectue un masquage et des choses pour vous. Il pourrait peut-être profiter des cas d'angle ou des instructions spéciales. Si vous êtes intéressé par l'efficacité, regardez dans l'assembleur que votre compilateur produit avec cela, il est généralement instructif. En règle générale, je dirais que les compilateurs modernes produisent du code aussi efficace que l'effort de programmation moyen. Le véritable twiddeling de bits profonds pour votre compilateur spécifique pourrait peut-être gagner des cycles. P>
Je suis à peu près sûr que sur PowerPC, ce n'est pas atomique, mais si votre cible est un système de base unique, vous pouvez simplement:
void update_reg_from_isr(unsigned * reg_addr, unsigned set, unsigned clear, unsigned toggle) { unsigned reg = *reg_addr; reg |= set; reg &= ~clear; reg ^= toggle; *reg_addr = reg; } void update_reg(unsigned * reg_addr, unsigned set, unsigned clear, unsigned toggle) { interrupts_block(); update_reg_from_isr(reg_addr, set, clear, toggle); interrupts_enable(); }
Wow, cela ressemble à une recette pour l'impasse: le processeur a démarre la section critique, regarde l'adresse. Le processeur B démarre la section critique, regarde l'adresse. Processeur une finition écrit. Le processeur B termine l'écriture. Processeur un regard sur l'adresse. Ça a changé! Processeur a réécrire des données. Le processeur B regarde l'adresse. Ça a changé! Le processeur B réécrit les données. Continuez dans une boucle infinie. (Désolé pour le formatage. Les commentaires ne semblent pas l'aimer.)
@Nathon: C'est un peu plus compliqué et simple que cela, mais cela fait longtemps que j'ai lu la documentation. Il y avait vraiment quelque chose qui empêchait d'être une situation d'impasse, mais a également permis de plus de flexibilité que l'approche unique d'instruction atomique utilisée sur d'autres architectures. Il se serait peut-être que l'écriture finale à la RAM ne s'est pas produite si un autre processeur avait écrit à cette adresse après que ce transformateur ait commencé à le regarder.
Il est connu sous le nom de "charge liée / stockage conditionnel" sur certaines architectures. PPC appelle cela lwarx code> (chargez le mot et la réserve indexé) et
stewcx. Code> (stockez Word indexé (et enregistrement)). Le magasin est conditionnel sur personne d'autre ayant écrit à la mémoire; Un processeur va toujours gagner. De plus, la "réservation" est effacée sur des commutateurs contextuels. De toute façon, vous ne voulez pas le faire sur des fitfields de matériel ...
@tc.: est la raison pour laquelle vous ne le feriez pas directement sur un registre de matériel mappé de mémoire est directement car il peut changer sans délivrer une adresse stocker i> adresse i> sur le bus de mémoire (où adresse i> est l'adresse réservée {l'adresse du fichier bitfield}). Ça fait longtemps. Je ne me souviens pas si quand j'ai écrit cela avant que je pensais faire ça ou mettre un verrou autour de lui, mais que ce ne serait pas protégé contre le registre matériel étant modifié hors bus (vraiment volatile).
Je n'ai fait aucune programmation matérielle, mais mon expérience est que les accès atomiques sont rarement utiles de manière isolée. Vous voudrez probablement quelque chose de plus comme "Collez une adresse dans l'enregistrement A, collez une longueur dans le registre B, démarrez DMA E / S en traduisant les bits dans le registre C". L'autre chose est que beaucoup de registres matériels sont des octets individuels, alors que les instructions réservées à la charge / magasin de PPC agissent sur des mots entiers (ou des mots doubles); Le Bitfield de la question est seulement un demi-document.
Je pense que l'utilisation de bitfields pour modéliser les registres matériels n'est pas une bonne idée. p>
Voilà tellement sur la manière dont les champs de bit sont gérés par un compilateur, définis par la mise en œuvre (y compris la manière dont les champs couvrent les limites d'octets ou de mots sont manipulés, des problèmes d'endansesse et exactement comment l'obtention, la définition et l'effacement des bits sont mises en œuvre). Voir C / C ++: ordre de champ de bit de force et alignement A > p>
Pour vérifier que les accès au registre sont traités sur la manière dont vous pourriez vous attendre ou que vous avez besoin d'eux pour être manipulés, vous devez étudier avec soin les documents du compilateur et / ou regarder le code émis. Je suppose que si les en-têtes fournis avec le microprocesseur Toolset utilisent des utilisables, vous pouvez supposer que la plupart de mes préoccupations sont prises en charge. Cependant, je suppose que cet accès atomique n'est pas nécessairement ... p>
Je pense qu'il est préférable de gérer ce type d'accès au niveau des registres matériels à l'aide de fonctions (ou de macros, si vous devez) effectuer des opérations explicites de lecture / de modification / d'écriture avec le masque de bits dont vous avez besoin, si c'est ce que vous avez besoin. processeur nécessite. p>
Ces fonctions pourraient être modifiées pour les architectures prenant en charge les accès atomiques au niveau des bits (tels que l'adressage "bit bit" de l'arme cortex M3). Je ne sais pas si le PowerPC prend en charge quelque chose comme ça - le M3 est le seul processeur que j'ai traité qui le supporte de manière générale. Et même le bandage binaire de M3 prend en charge les accès 1 bits; Si vous traitez avec un domaine composé de 6 bits de large, vous devez revenir au scénario de lecture / modification / écriture. P>
Ai-je raison de penser que le
v code> in
vuint16_t code> signifie "volatil"?
Oui, les types sont volatils car ils sont tous des emplacements de registre mappé de mémoire. Il y a aussi des instructions d'alignement que j'ai laissées pour garder les choses courtes.
Évitez les champs de bit et utilisez le masque et décalez-vous à la place.