Aller au contenu

Périphériques

Les périphériques d’entrées/sorties sont des composants indispensables des processeurs. Ils leur servent à interfacer et interagir avec les systèmes physiques externes.

Architecture

L’architecture d’un périphérique d’entrées/sorties distingue deux parties principales:

  • Contrôleur (CTRL)
  • Chip physique (PHY)

Architecture d'un périphérique d'entrées/sorties

Le contrôleur (CTRL - Controller) implémente la logique du périphérique. Cette logique réalise la fonction du périphérique. Pour interfacer avec le logiciel, nommé pilote de périphérique (Device Driver), le contrôleur expose les données pour sa configuration et sa gestion via une banque de registres.

Le chip physique (PHY - Physical Layer) implémente la couche physique du périphérique. Il permet d’interfacer le périphérique physique externe au processeur avec le contrôleur interne. Contrairement au contrôleur, le chip physique se place généralement à l’extérieur de la puce du processeur, sur la carte électronique (PCB - Printed Circuit Board) et à proximité du connecteur.

Registres

Le pilote utilise les registres pour opérer le périphérique. Généralement, ces registres se déclinent en trois grandes catégories :

  • Registres d’état
  • Registres de contrôle
  • Registres de données

Registres d'un contrôleur

Les registres d’état (status registers) donnent des informations sur l’état de fonctionnement actuel du périphérique, tels que sa disponibilité à émettre des données ou sur la réception de données, sur des erreurs ou malfonctions du périphérique. Ils fournissent également un feedback sur des opérations ou commandes appliquées au périphérique via les registres de contrôle.

Les registres de contrôle ou registres de commande (control registers) servent à la configuration et gestion du périphérique, tels qu’initialisation du périphérique (reset), mode de fonctionnement, contrôle des interruptions, gestion des canaux de transmissions/réceptions.

Les registres de données (data registers) se déclinent en principe en un registre de transmission (TX) et un registre de réception (RX). Derrière ces registres se cachent généralement deux tampons, un tampon d’émission de données (TX - Transmit Buffer) et un tampon de réception de données (RX - Receipt Buffer). Ces tampons permettent de réduire les contraintes temporelles sur le pilote, plus de temps avant de réagir lors de la réception de données ou possibilité d’émettre une rafale de données sans blocages.

Selon le type de périphériques, la taille de ces registres varie entre 8 bits, 16 bits et 32 bits. Si le périphérique est embarqué sur la même puce que le CPU, sa taille est généralement similaire à celle de l’architecture du processeur. Le regroupement de plusieurs bits ou champs de bits d’état, respectivement de contrôle, sur un seul registre est une pratique usuelle des concepteurs de périphériques. Cette pratique leur permet de réduire généralement la quantité de logique nécessaire au traitement des requêtes du pilote.

Contrairement aux cellules des mémoires, qui ne stockent que la donnée, un accès effectué sur un des registres d’un contrôleur engendre automatiquement une action sur périphérique, ceci indépendamment que l’accès soit une lecture ou une écriture. Il est donc essentiel de ne pas faire transiter les données de ces registres par les mémoires cache du processeur. Côté logiciel, il est également important d’éviter toute optimisation du compilateur. Sans ces précautions, le comportement souhaité du périphérique risque d’être altéré.

Interfaces

Bien que l’architecture interne des contrôleurs de périphériques d’entrés/sorties soit similaire, leur interface avec le processeur varie selon le type de périphérique et de son niveau d’intégration avec le processeur (sur la puce du processeur ou placé à l’extérieur). Cependant, pour interfacer les registres des contrôleurs avec le CPU, les processeurs distinguent généralement trois types principaux de périphériques :

  • MMIO (Memory-Mapped I/O)
  • PMIO (Port-Mapped I/O)
  • Coprocesseur

Types de périphériques

MMIO

Les registres des contrôleurs de ces périphériques d’entrées/sorties mappés en espace mémoire sont directement accessibles dans l’espace d’adressage du processeur. Le transfert de données entre les registres du CPU et ceux de ce type de contrôleurs s’effectue strictement de la même façon que celui de données avec la mémoire centrale. Par la simplicité d’accès à leurs registres, ce type de contrôleurs équipent la majorité des µP et µC.

Périphérique

La figure ci-dessus représente l’interface d’un périphérique élémentaire. Celui-ci dispose d’un registre d’état, d’un registre de contrôle et de deux registres pour le transfert de données (rx et tx). Tous les registres ont une taille fixe de 32 bits. Pour l’exemple, le périphérique est placé en mémoire, adresses 0x4000_1000 à 0x4000_1027.

La description d’un périphérique en langage de programmation se réalise généralement en C. Cette description passe par la déclaration des bits et champs contenus dans les différents registres ainsi que d’une structure contenant tous les registres comme membre de cette structure. Pour rappel, l’emplacement en mémoire des membres d’une structure correspond à l’ordre des déclarations et à la taille de chaque membre. Il est important de bien contrôler l’offset de chacun des membres et de rajouter des “padding” si nécessaire.

#define STAT_TXR  (1 <<  0)
#define STAT_RXR  (1 <<  1)
#define STAT_DONE (1 << 31)

#define CTRL_TXE  (1 <<  2)
#define CTRL_RXE  (1 <<  3)
#define CTRL_TIE  (1 <<  6)
#define CTRL_RIE  (1 <<  7)
#define CTRL_RST  (1 << 31)

struct ctrl {
   uint32_t stat;
   uint32_t ctrl;
   uint32_t pad[2];
   uint32_t tx;
   uint32_t rx;
};

Un pointeur, initialisé avec l’adresse de base du périphérique en mémoire, donne accès aux registres du contrôleur. La directive volatile est indispensable afin d’éviter toute optimisation du compilateur. Il est en effet essentiel que chaque accès aux registres du contrôleur soit effectué et non optimisé. Il est ensuite possible de piloter le périphérique. Dans l’exemple ci-dessous, le périphérique est d’abord initialisé, puis le code attend que l’initialisation se termine.

static volatile struct ctrl* io = (struct ctrl*)0x40001000;

io->ctrl = CTRL_RST;
while ((io->stat & STAT_DONE) == 0);

PMIO

Les registres des contrôleurs de ces périphériques d’entrées/sorties mappés dans l’espace des entrées/sorties (I/O), ne sont accessibles que dans un espace d’adressage distinct de celui de la mémoire centrale. Des instructions spécifiques (par exemple IN et OUT pour le jeu d’instructions x86) permettent d’accéder les registres de ces contrôleurs et de manipuler ainsi leur contenu. Ce type de contrôleurs se trouvent principalement sur des processeurs de l’architecture x86 ou x86_64.

Coprocesseurs

Les processeurs intègrent certains de leurs périphériques internes en tant que coprocesseurs. Par exemple les processeurs ARM du profil A interfacent les registres des contrôleurs de leurs mémoires caches L1 et L2, ainsi que de la MMU via un coprocesseur, le coprocesseur 15 (CP15). Dans de tels cas, le CPU dispose d’instructions spécialisées pour accéder ces registres (sur ARM, les instructions MCR et MRC).