Un pointeur est un groupe de cases mémoires (2 ou 4 octets
suivants les implémentations) pouvant contenir une adresse,
exemple:
char C;
char *PtC;
C est une variable de type char et PtC est un
pointeur
pouvant pointer des objets de type char.
L'opérateur & donne l'adresse d'un objet; pour faire
pointer PtC vers C il faut donc utiliser l'instruction:
PtC = &C; /* l'adresse de C est rangée dans PtC. */
L'opérateur étoile (*) représente
l'opérateur
d'indirection. Si on l'applique a un pointeur, il donne accès a
l'objet pointe par ce
pointeur. Les 2 exemples suivants montrent comment utiliser les
opérateurs
& et *:
exemple1:
char c;
char *p;
p = &c; /*
l'adresse de c est rangée dans p */
*p = 'd'; /* c vaut
maintenant
le caractère 'd' */
int tab[10];
int *pt;
exemple2:
pt = &tab[5]; /* l'adresse de
la case 5 du tableau tab est rangée dans pt */
*pt =
12;
/* la case 5 de tab vaut maintenant 12 */
pt = pt + 1; /* pt pointe
maintenant la case 6 de tab */
*pt =
34;
/* la case 6 de tab vaut maintenant 34 */
#define PIA 0xF00043A1 /* adresse de base du PIA sur le kit 68040 */
/* deplacement a ajouter a l'adresse PIA pour
atteindre
* les registres du PIA:
*/
#define CRA
2
/* reg de contrôle du port A */
#define DDRA 0 /* reg de
contrôle
du port A */
#define ORA 0
/* reg de lecture/écriture du port A */
#define CRB 6 /*
reg de contrôle du port B */
#define DDRB 4 /* reg de direction
du port B */
#define ORB 4 /*
reg de lecture/écriture du port B */
Vous devez commencer par déclarer un pointeur capable de pointer les registres du PIA.
Une simple question: qu'elle est le type de donnée des registres d'un circuit PIA 6821 ?
Les registres du PIA sont sur 8 bits soit 1 octet.
Quel est le type dans du langage C qui code des données sur 1 octet ?
Et bien la réponse n'est pas trivial car elle
dépend
de du compilateur C que vous utilisez. Un petit truc pour
résoudre
cette question: l'opérateur sizeof applique a une
variable
ou bien directement a un type vous retourne la taille en octets de
cette
variable ou de ce type. Le programme suivant vous montre l'utilisation
de l'opérateur sizeof:
#include <stdio.h>
main() {
char TabChar[10];
int TabInt[10];
printf("taille
d'un
char = %d octet\n",sizeof( char ));
printf("taille d'un unsigned char = %d
octet\n",sizeof(
unsignedchar ));
printf("taille
d'un
int = %d octets\n",sizeof( int ));
printf("taille d'un unsigned int = %d
octets\n",sizeof(
unsigned int ));
printf("taille d'un
short int
= %d octets\n",sizeof( short int ));
printf("taille d'un float = %d
octets\n",sizeof(
float ));
printf("taille d'un double = %d
octets\n",sizeof(
double ));
printf("taille du tableau char
TabChar[10] =
%d
octets\n",sizeof( TabChar ));
printf("taille du tableau int
TabInt[10]
= %d octets\n",sizeof( TabInt ));
}
Remarque: sur le kit 68040 la fonction printf n'est pas disponible, vous pouvez utiliser les fonctions suivantes:
puts( uitoa( sizeof( short int ) ) );
L'exécution de ce programme donne:
taille d'un
char = 1 octet
taille d'un unsigned char = 1 octet
taille
d'un
int = 4 octets
taille d'un unsigned int = 4 octets
taille d'un short int = 2 octets
taille d'un float = 4 octets
taille d'un double = 8 octets
taille du tableau char TabChar[10] = 10 octets
taille du tableau int TabInt[10] = 40 octets
On prendra le type char pour coder les registres 8 bits
du PIA. La déclaration du pointeur peut être la
suivante:
char *PtRegPIA;
On peut initialiser (faire pointer) PtRegPIA soit dans
le code principal avec l'instruction:
PtRegPIA = (char *) PIA;
Soit directement dans la déclaration:
char *PtRegPIA = (char *) PIA;
Remarque au sujet du "cast" (char *): Ce cast est nécessaire pour signifier au compilateur que PIA est une adresse d'un objet de type char (char = 1 octets ou 8 bits pour les registres de notre PIA).
Si l'on veut affecter la valeur 00 dans le registre CRB
il suffit d'utiliser l'instruction suivante:
*(PtRegPIA + CRB) = 0x00;
PtRegPia pointe sur le premier registre du PIA, on ajoute le déplacement CRB pour pointer sur CRB. L'opérateur * permet de modifier le contenu pointer c'est a dire mettre la valeur 0x00 dans le registre CRB. Cette instruction est relativement lourde, mais en utilisant la notation tableau l'instruction devient limpide:
PtRegPIA[ CRB ] = 0x00; /* qui est équivalent a *(PtRegPIA + CRB) = 0x00; */
On peut encore simplifier la notation *(PtRegPIA + CRB) en
masquant
sa complexité a l'aide d'un define:
#define PtRegPIA
0x05CEF1
/* adresse de base du PIA */
#define CRB *(char *) (PtRegPIA + 6) /* reg de controle du port B */
et voici son utilisation:
CRB = 0x00;
Après l'action du pré-processeur (qui est automatiquement lance avant la compilation) l'instruction précédente devient:
*(char *) (0x05CEF1 + 6) = 0x00;
| |
|
|
|
| |
|
|
- déplacement pour attendre le registre CRB.
| |
|
- l'adresse de base du PIA.
| | -
déclaration
du pointeur.
| - pointeur sur char.
|- opérateur d'indirection: pour avoir accès au
contenu pointé.
Trouver la déclaration du define n'est pas facile
mais
l'utilisation devient est extrêmement simple. Maintenant vous
devez
pouvoir aisément manipuler les pointeurs pour atteindre tous les
adresses du kit 68040.
Lors de la reconnaissance d'interruption, une copie interne du SR est effectuée, le processeur passe en mode superviseur le masque d'interruption est mis au niveau de l'interruption prise en compte (le processeur ne pourra alors être interrompu que par une interruption de niveau supérieur). Le processeur attend le numéro de vecteur du circuit qui vient de l'interrompre en effectuant une lecture:
- Place les lignes FC2,FC1 et FC0 a 1 1 1
- Place le niveau de l'interruption sur les lignes A3, A2 et A1
- Active les lignes AS\, UDS\ et LDS\
Si le circuit interrompant ne peut pas fournir de numéro de vecteur (cas d'un circuit périphérique 68xx), une logique externe activer le signal VPA\ du processeur pour que celui-ci génère en interne un numéro de vecteur: c'est l'auto vectorisation. Mais sur notre kit 68040 c'est de la logique programmable qui dans le cas d'interruption provenant du PTM ou du PIA génère un vecteurs comme le montre le tableau suivant:
Désignation | Niveau | adresse | Provenance de l'interruption |
auto vecteur de niveau 4 | 4 | [VBR] + $70 | IRQ PTM 6840 |
auto vecteur de niveau 2 | 2 | [VBR ]+ $68 | IRQA PIA 6821 |
[VBR] = contenu du registre Vecteur Base Registre.
Lorsque le numéro de vecteur est obtenu, le processeur sauve
les registres PC et SR sur la pile superviseur (SSP).
La valeur du PC empilée à l'adresse de
l'instruction
qui aurait été exécutée en l'absence
d'interruption.
Le processeur recherche alors dans la table des vecteurs
l'adresse
du programme de traitement de l'interruption et l'exécute.
L'adresse
de début de la table des vecteurs d'interruptions est contenue
dans
le registre VBR (Vecteur Base Register).
Numéro de vecteur | [VBR] + offset | Utilisation | |
Déc. | Hexa. | ||
0 | 0 | 000 | Initialisation du SSP après un RESET |
- | 4 | 004 | Initialisation du PC après un RESET |
2 | 8 | 008 | Erreur bus |
3 | 12 | 00C | Erreur d'adresse |
4 | 16 | 010 | Instruction illégale |
5 | 20 | 014 | Division par zéro |
6 | 24 | 018 | Instruction CHK |
7 | 28 | 01C | Instruction TRAPV |
8 | 32 | 020 | Violation de privilège |
9 | 36 | 024 | Trace |
10 | 40 | 028 | Émulateur ligne 1010 |
11 | 44 | 02C | Émulateur ligne 1111 |
12-14 | 48 | 030 | réserve |
15 | 60 | 03C | Interruption non initialisée |
16-23 | 64-95 | 04C-05F | réservé |
24 | 96 | 060 | Interruption parasite |
26 | 100 | 064 | Auto-Vecteur d'interruption Niveau 1 |
26 | 104 | 068 | Auto-Vecteur d'interruption Niveau 2 |
27 | 108 | 06C | Auto-Vecteur d'interruption Niveau 3 |
28 | 112 | 070 | Auto-Vecteur d'interruption Niveau 4 |
29 | 116 | 074 | Auto-Vecteur d'interruption Niveau 5 |
30 | 120 | 078 | Auto-Vecteur d'interruption Niveau 6 |
31 | 124 | 07C | Auto-Vecteur d'interruption Niveau 7 |
32-47 | 128-191 | 080-0BF | Vecteurs d'instruction TRAP |
48-63 | 192-255 | 0C0-0FF | Réservé |
64-255 | 256-1023 | 100-3FF | Vecteurs d'interruption utilisateur |
main()
{
/* Initialisation de la table des vecteurs d'it
*/
static void (**TabVect)() = (void (**)())
AdrTabVect;
/* Mise en place du vecteurs d'it IRQ du PTM */
TabVect[ VECT_PTM ] = InterruptionPTM;
.
.
.
}
TabVect est un pointeur qui pointe vers un tableau qui contient des adresses de fonctions.