CHAP2
Microprocesseur MIPS R3000
Architecture externe
1. Introduction
MIPS (de l'anglais Microprocessor without interlocked pipeline stages) est une architecture de microprocesseur de type RISC. Elle fut développée par la compagnie MIPS Computer Systems Inc., basée à Mountain View en Californie. Les processeurs fabriqués selon cette architecture sont utilisés dans plusieurs systèmes. On les retrouve dans plusieurs systèmes embarqués (embedded systems en anglais), comme les ordinateurs de poche, les routeurs Cisco et les consoles de jeux vidéo (Nintendo 64 et Sony PlayStation, PlayStation 2 et PSP). Vers la fin des années 1990, on estimait que les processeurs dérivés de l'architecture MIPS occupaient le tiers des processeurs RISC produits.
Les premières implémentations de l'architecture MIPS étaient de 32 bits (autant au niveau des registres que des chemins de données), mais par la suite, on a développé des implémentations de 64 bits.
Il existe plusieurs jeux d'instructions MIPS qui sont rétro compatibles (backward compatible): MIPS I, MIPS II, MIPS III, MIPS IV, et MIPS V ainsi que MIPS32 et MIPS64. MIPS32 et MIPS64, qui se basent sur MIPS II et MIPS V, ont étés introduites comme jeux d'instructions normalisés. Des extensions sont aussi disponibles telles que : MIPS-3D, une unité à virgule flottante (FPU) simplifiée de type SIMD pour les calculs 3D de base.
Les jeux d'instructions de base (en particulier MIPS I) sont efficaces qu'un bon nombre de cours d'architecture des ordinateurs, autant dans les universités que les écoles techniques, se portent sur l'étude de l'architecture MIPS. Cette architecture est suffisamment simple pour présenter les principes de base de l'architecture des processeurs, et suffisamment puissante pour supporter un système d'exploitation multi-tâches tel qu'UNIX.
Les jeux d'instructions de base (en particulier MIPS I) sont efficaces qu'un bon nombre de cours d'architecture des ordinateurs, autant dans les universités que les écoles techniques, se portent sur l'étude de l'architecture MIPS. Cette architecture est suffisamment simple pour présenter les principes de base de l'architecture des processeurs, et suffisamment puissante pour supporter un système d'exploitation multi-tâches tel qu'UNIX.
2. Caractéristiques
L'architecture externe est l'interface entre le processeur et le programmeur. Ce cours sera plus orienté vers l'architecture interne. Une architecture externe est composée de :
- Les registres visibles.
- L'adressage de la mémoire.
- Le jeu d'instructions.
- Les mécanismes de traitement des interruptions et exceptions.
2.1. Organisation de la mémoire
Dans l’architecture MIPS R3000, l’espace adressable est divisé en deux segments: le segment utilisateur, et le segment système (noyau). Un programme utilisateur utilise généralement trois sous-segments (appelés sections) dans le segment utilisateur:
- la section text contient le code exécutable en mode utilisateur. Elle est implantée conventionnellement à l’adresse 0x00400000. Sa taille est fixe et calculée lors de l’assemblage. La principale tâche de l’assembleur consiste à générer le code binaire correspondant au programme source décrit en langage d’assemblage, qui sera chargé en mémoire dans cette section.
- la section data contient les données globales manipulées par le programme utilisateur. Elle est implantée conventionnellement à l’adresse 0x10000000. Sa taille est fixe et calculée lors de l’assemblage. Les valeurs contenues dans cette section peuvent être initialisées grâce à des directives contenues dans le programme source en langage d’assemblage.
- la section stack contient la pile d’exécution du programme utilisateur. Sa taille varie au cours de l’exécution. Elle est implantée conventionnellement à l’adresse 0x7FFFF000. La pile s’étend vers les adresses décroissantes.
Trois sections sont également définies dans le segment noyau (kernel):
- la section ktext contient le code exécutable en mode noyau. Elle est implantée conventionnellement à l’adresse 0x80000000. Sa taille est fixe et calculée lors de l’assemblage.
- la section kdata contient les données globales manipulées par le système d’exploitation en mode noyau. Elle est implantée conventionnellement à l’adresse 0xC0000000. Sa taille est fixe et calculée lors de l’assemblage.
- la section kstack contient la pile d’exécution du noyau. Sa taille varie au cours de l’exécution. Elle est implantée conventionnellement. l’adresse 0xFFFFF000. Cette pile s’étend vers les adresses décroissantes.
2.2. Registres visibles du logiciel
Le processeur MIPS possède 32 registres de travail accessibles au programmeur. Chaque registre est connu par son numéro, qui varie entre 0 et 31, et est préfixé par un $. Par exemple, le registre 31 sera noté $ra dans l’assembleur. En dehors du registre $zero qui contient toujours la valeur 0, tous les registres sont identiques du point de vue de la machine. Ils sont directement adressés par les instructions, et permettent de stocker des résultats de calculs intermédiaires. Afin de normaliser et de simplifier l’écriture du logiciel, des conventions d’utilisation des registres sont définies. Ces conventions sont particulièrement nécessaires lors des appels de fonctions.- PC Registre compteur de programme (Program Counter). Ce registre contient l'adresse de l’instruction en cours d’exécution. Sa valeur est modifiée par toutes les instructions.
- HI et LO Registres pour la multiplication ou la division Ces deux registres 32 bits sont utilisés pour stocker le résultat d'une multiplication ou d'une division, qui est un mot de 64 bits.
2.3. Registres protégés
L’architecture MIPS définit 32 registres (numérotés de 0 à 31), qui ne sont accessibles, en lecture comme en écriture, que par les instructions privilégiées (c’est à dire les instructions qui ne peuvent être exécutées qu’en mode superviseur). On dit qu’ils appartiennent au "coprocesseur système". En pratique, cette version du processeur MIPS R3000 en utilise 4 pour la gestion des interruptions et des exceptions.SR: Registre d’état (Status Register). Il contient en particulier le bit qui définit le mode : superviseur ou utilisateur, ainsi que les bits de masquage des interruptions. (Ce registre possède le numéro 12)
CR : Registre de cause (Cause Register). En cas d’interruption ou d’exception, son contenu définit la cause pour laquelle on fait appel au pro-gramme de traitement des interruptions et des exceptions. (Ce registre possède le numéro 13).
EPC : Registre d’exception (Exception Program Counter). Il contient l’adresse de retour (PC+4) en cas d’interruption. Il contient l’adresse de l’instruction fautive en cas d’exception (PC). (Ce registre possède le numéro 14)
BAR: Registre d’adresse illégale (Bad Address Register). En cas d’exception de type "adresse illégale", il contient la valeur de l’adresse mal formée. (Ce registre possède le numéro 8)
Les arguments d'une instruction :
La plupart des instructions nécessitent un ou plusieurs arguments. Si une instruction nécessite plusieurs arguments, ces arguments sont séparés par des virgules. Dans une instruction assembleur, on aura en général comme premier argument le registre dans lequel est mis le résultat de l’opération, puis ensuite le premier registre source, puis enfin le second registre source ou une constante.Exemple 1: add $v1, $v0, $at # équivalent à: $v1 ← $v0 + $at
Règle syntaxique
On définit ci-dessous les principales règles d’écriture d'un programme source.-Les noms de fichiers: Contenant un programme source en langage d’assemblage doivent être suffixé par « .asm ». Exemple: mips1.asm
-Les commentaires: Ils commencent par un # et s’achèvent à la fin de la ligne courante.
Exemple 2: # Premier programme, Bonjour tout le monde!
.data # Segment de données
entier : .byte 5 # case mémoire contenant 5
-Les entiers : Une valeur entière décimale est notée,par exemple, 250 (sans préfixe), une valeur entière octale est notée 0372 (préfixée par un zéro) et une valeur entière hexadécimale est notée 0xFA (préfixée par zéro suivi de x). En hexadécimal, les lettres de A à F peuvent être écrites en majuscule ou en minuscule.
-Les chaînes de caractères: Elles sont simplement entre guillemets, et peuvent contenir les caractères d’échappement du langage C. Exemple : "Oh la jolie chaîne avec retour à la ligne\n".
-Les labels: Ce sont des mnémoniques correspondant à des adresses en mémoire. Ces adresses peuvent être soit des adresses de variables stockées en mémoire (principalement dans la section data), soit des adresses de sauts (principalement dans la section text). Ce sont des chaînes de caractères qui commencent par une lettre, majuscule ou minuscule, un "$", un "_", ou un "." suivi par un nombre quelconque de ces mêmes caractères auxquels on peut ajouter des chiffres. Lors de la déclaration, ils doivent être suffixés par le caractère « : ». Pour y référer, on supprime le « : ».
Exemple 3: .data
message: .asciiz "Ceci est une chaîne de caractères...\n"
entier : .word 250, 0372, 0xfa # trois valeurs identiques
.text
_main:
message: .asciiz "Ceci est une chaîne de caractères...\n"
entier : .word 250, 0372, 0xfa # trois valeurs identiques
.text
_main:
li $v0,4 # charger 4 dans $v0
la $a0, message # charger @message dans $a0
syscall # afficher le contenu de message
-Types de données/tailles: Les types de données de base comprennent les nombres entiers, les nombres à virgule flottante et les caractères.
L’architecture I prend en charge les formats de stockage de données de l'octet, demi-mot, ou la taille des mots. La virgule flottante doit être de taille mot (32 bits) ou double mot (64 bits). Les données de caractère sont généralement un octet et une chaîne est une série d'octets séquentiels.
L'architecture MIPS prend en charge les types de données/tailles suivantes:
De plus, l'architecture MIPS telle que simulée sur Mars est little-endian. Cela signifie que le plus petit octet (LSB) est stocké dans l'adresse de mémoire la plus basse. L'octet le plus significatif (MSB) est stocké dans l'emplacement de mémoire le plus élevé.
Pour un mot (32 bits), le MSB et LSB sont attribués comme indiqué ci-dessous.
MSB LSB
Par exemple, en supposant les déclarations suivantes:
.data
num1: .word 0x0000002A
num2: .word 0x004C4B40
Pour une architecture little-endian, l'image de la mémoire serait comme suit:
-Les immédiats : Ce sont les opérandes contenus dans l’instruction. Ce sont des constantes. Ce sont soit des entiers, soit des labels. Ces constantes doivent respecter une taille maximum qui est fonction de l’instruction qui l’utilise : 16 ou 26 bits.
la $a0, message # charger @message dans $a0
syscall # afficher le contenu de message
-Types de données/tailles: Les types de données de base comprennent les nombres entiers, les nombres à virgule flottante et les caractères.
L’architecture I prend en charge les formats de stockage de données de l'octet, demi-mot, ou la taille des mots. La virgule flottante doit être de taille mot (32 bits) ou double mot (64 bits). Les données de caractère sont généralement un octet et une chaîne est une série d'octets séquentiels.
L'architecture MIPS prend en charge les types de données/tailles suivantes:
- byte : entier de 8 bits
- half : entier 16 bits
- word : entier 32 bits
- float : nombre à virgule flottante 32 bits
- double : nombre à virgule flottante de 64 bits
De plus, l'architecture MIPS telle que simulée sur Mars est little-endian. Cela signifie que le plus petit octet (LSB) est stocké dans l'adresse de mémoire la plus basse. L'octet le plus significatif (MSB) est stocké dans l'emplacement de mémoire le plus élevé.
Pour un mot (32 bits), le MSB et LSB sont attribués comme indiqué ci-dessous.
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Par exemple, en supposant les déclarations suivantes:
.data
num1: .word 0x0000002A
num2: .word 0x004C4B40
Pour une architecture little-endian, l'image de la mémoire serait comme suit:
Nom de la variable | Valeur | Adresse |
? | 0x1001000C | |
00 | 0x1001000B | |
4C | 0x1001000A | |
4B | 0x10010009 | |
num2 à | 40 | 0x10010008 |
00 | 0x10010007 | |
00 | 0x10010006 | |
00 | 0x10010005 | |
num1 à | 2A | 0x10010004 |
? | 0x10010003 |
-Les immédiats : Ce sont les opérandes contenus dans l’instruction. Ce sont des constantes. Ce sont soit des entiers, soit des labels. Ces constantes doivent respecter une taille maximum qui est fonction de l’instruction qui l’utilise : 16 ou 26 bits.
-Les arguments : Si une instruction nécessite plusieurs arguments, comme par exemple l’addition entre deux registres, ces arguments sont séparés par des virgules. Dans une instruction assembleur, on aura en général comme argument en premier le registre dans lequel est mis le résultat de l’opération, puis ensuite le
premier registre source, puis enfin le second registre source ou une constante.
Exemple: add $3, $2, $1 # $3←$2+$1
-Adressage mémoire : Le MIPS ne possède qu’un unique mode d’adressage : l’adressage indirect registre avec déplacement. Ainsi l’accès à une case mémoire à partir de l’adresse présente dans un registre se note par le déplacement, c.-à-d. un entier comme défini précédemment, suivi du registre entre parenthèses.
Exemples : 11($12), 013($12) 0xB($12).
Ces trois exemples indiquent la case mémoire ayant comme adresse le contenu du registre $12 plus 11.
S’il n’y a pas d’entier devant la parenthèse ouvrante, le déplacement est nul.
En revanche, il n’est pas possible d’écrire des sauts à des adresses absolues ou relatives constantes,
comme par exemple un j 0x400000 ou un bnez $3, -12. Il faut nécessairement utiliser des labels.
3. Jeu d’instructions
Une instruction MIPS est un mot de 32 bits. Il y a trois catégories (formats) d’instruction :Format R :
31 26 | 25 21 | 20 16 | 15 11 | 10 6 | 5 0 |
opcode | rs | rt | rd | sh | func |
Format I :
31 26 | 25 21 | 20 16 | 15 | 0 | |
opcode | rs | rt | imm16 |
Format J :
31 26 | 25 | 0 | |||
opcode | imm26 |
Dans ce qui suit, nous notons rd la valeur du champs rd, c’est à dire un entier entre 0 et 31 car rd est codé sur 5 bits, et indiquons par $rd le registre indexé par ce champs. Si $rd est le membre de gauche d’une affectation, alors nous en imposons la valeur, si il fait parti du membre de droite, nous en lisons la valeur. Nous ne pouvons en aucun cas modifier rd qui est une constante décidée lors de la compilation.
Notons qu’un registre source peut être le registre destination d’une même instruction assembleur. Un opérande immédiat sera noté imm, et sa taille sera spécifié dans la description de l’instruction.
Les instructions de saut prennent comme argument une étiquette, où label, qui est utilisée pour calculer l’adresse de saut. Toutes les instructions modifient implicitement ou explicitement un registre non accessible du logiciel, le program counter noté $pc. Pour lever l’ambiguïté liée aux calculs des sauts relatifs au $pc, nous noterons que l’adresse de l’instruction en cours d’exécution est toujours égale à $pc-4, car $pc est incrémenté (pour passer à l’instruction suivante) en même temps que l’instruction à exécutée est chargée. Le $pc à droite d’une affectation est donc toujours égal à l’adresse de l’instruction courante plus 4.
Attention : le MIPS R3000 est un processeur pipeline tel que l’instruction qui suit un branchement (relatif ou absolu) est toujours exécutée.On appel cet emplacement le delay slot et on dit que le branchement effectif est retardé d’une instruction.
Le résultat d’une multiplication ou d’une division est mis dans deux registres spéciaux, $hi pour les poids forts (multiplication) ou le reste (division), et $lo pour les poids faibles (multiplication) ou le quotient (division).
Exemple 3.1: Programme pour lire un entier donné par l'utilisateur
# Program to read an integer number from a user, and print that number back to the console.
.text
main:
# Prompt for the integer to enter
li $v0, 4
la $a0, prompt
syscall
# Read the integer and save it in $s0
li $v0, 5
syscall
move $s0, $v0
# Save number in memory
sw $s0, number
# Output the text
li $v0, 4
la $a0, output
syscall
# Output the number
li $v0, 1
move $a0, $s0
syscall
# Exit the program
.text
main:
# Prompt for the integer to enter
li $v0, 4
la $a0, prompt
syscall
# Read the integer and save it in $s0
li $v0, 5
syscall
move $s0, $v0
# Save number in memory
sw $s0, number
# Output the text
li $v0, 4
la $a0, output
syscall
# Output the number
li $v0, 1
move $a0, $s0
syscall
# Exit the program
li $v0, 10
syscall
.data
number: .word 0
prompt: .asciiz "\nPlease enter an integer: "
output: .asciiz "\nYou typed the number "
.text
main:
# Prompt for the string to enter
li $v0, 4
la $a0, prompt
syscall
# Read the string.
li $ v0, 8
la $a0, input
lw $a1, inputSize
syscall
# Output the text
li $v0, 4
la $a0, output
syscall
# Output the string
li $v0, 4
la $a0, input
syscall
# Exit the program
li $v0, 10
syscall
.data
input: .space 11
inputSize: .word 12
prompt: .asciiz "\nPlease enter an string: "
output: .asciiz "\nYou typed the string: "
syscall
.data
number: .word 0
prompt: .asciiz "\nPlease enter an integer: "
output: .asciiz "\nYou typed the number "
Exemple 3.2: Programme pour lire une chaine de caractères donnée par l'utilisateur
# Program to read a string from a user, and print that string back to the console..text
main:
# Prompt for the string to enter
li $v0, 4
la $a0, prompt
syscall
# Read the string.
li $ v0, 8
la $a0, input
lw $a1, inputSize
syscall
# Output the text
li $v0, 4
la $a0, output
syscall
# Output the string
li $v0, 4
la $a0, input
syscall
# Exit the program
li $v0, 10
syscall
.data
input: .space 11
inputSize: .word 12
prompt: .asciiz "\nPlease enter an string: "
output: .asciiz "\nYou typed the string: "
- Instructions d’entrées/sorties : MIPS permet de communiquer avec le système de façon simple par la ` commande syscall. La fonction utilisée est déterminée selon la valeur de : $v0.
Commandes | Code syscall | Arguments | Résultats |
print integer | 1 | $a0 = value | (none) |
print float | 2 | $f12 = float value | (none) |
print double | 3 | $f12 = double value | (none) |
print string | 4 | $a0 = address of string | (none) |
read integer | 5 | (none) | $v0 = value read |
read float | 6 | (none) | $f0 = value read |
read double | 7 | (none) | $f0 = value read |
read string | 8 | $a0 = address where string to be stored $a1 = number of characters to read + 1 | (none) |
memory allocation | 9 | $a0 = number of bytes of storage desired | $v0 = address of block |
exit (end of program) | 10 | (none) | (none) |
print character | 11 | $a0 = integer | (none) |
read character | 12 | (none) | char in $v0 |
3.1 Assemblage d’une instruction R-type:
3.1 Assemblage d’une instruction R-type:
R | Op | Rs | Rt | Rd | Shamt | Funct |
op 6 bits toujours zéro!
rs 5 bits 1er registre argument (de données)
rt 5 bits 2eme registre argument (de données)
rd 5 bits registre destination (résultat)
shamt 5 bits utiliser dans les instructions de décalage (toujours 0)
funct 6 bits code de l’opération à effectuer.
Noter que le registre destination est le troisième registre dans le code machine
Exemple : add $t1, $t2, $t3
rs = 10(10)= 01010(2) ($t2 = $10)
rt = 11(10)= 01011(2) ($t3 = $11)
rd = 9(10)) = 01001(2) ($t1 = $9)
funct = 32(10) = 100000(2) (code fonction pour add)
shamt = 0(10) = 00000(2) (n’est pas une instruction de decalage)
R | 0 | 10 | 11 | 9 | 0 | 32 |
R | 000000 | 01010 | 01011 | 01001 | 00000 | 1000000 |
0000 0001 0100 1011 0100 1000 0010 0000
0x014B4820
Instruction | funct |
add | 32 |
sub | 34 |
mult | 24 |
div | 26 |
jr | 8 |
3.2 Assemblage d’une instruction I-type:
I | Op | Rs | Rt | Address/immediate |
op 6 bits code de l’opération à effectuer.
rs 5 bits 1er registre argument (de données)
rt 5 bits destination ou 2eme registre argument
ad/imm 16 bits valeur de la constante ou de l'adresse contenu dans l’instruction
Noter que le registre destination est dans le deuxième registre dans le code machine
Exemple : addi $t4, $t5, 0x43
op = 8(10)) = 1000(2) (voir code pour addi)
rs = 13(10)= 01101(2) ($t5= $13)
rt = 1210)= 01100(2) ($t4 = $12)
imm = 67(10)= 43(16) = 0000 0000 0100 0011 (2) (Valeur de la constante)
I | 8 | 13 | 12 | 67 |
I | 001000 | 01101 | 01100 | 0000 0000 0100 0011 |
0010 0001 1010 1100 0000 0000 0100 0011
0x21AC0043
Instruction | op |
addi | 8 |
andi | 12 |
beq | 4 |
bne | 5 |
ori | 13 |
slti | 10 |
xori | 14 |
3.2.1 Instructions de branchement Conditionnel :
beq $t0, $t1, label
I : | op | rs | rt | address/immediate |
op 6 bits code de l’opération à effectuer.
rs 5 bits 1er registre argument (de données)
rt 5 bits destination ou 2eme registre argument
imm 16 bits valeur de l’offset contenu dans l’instruction
a) Calcule du saut positif (offset) : Nombre d‘instructions à partir de l’instruction suivante
beq $t0, $t1, skip
nop # 0 (ici début)
nop # 1
nop # 2
skip: nop # 3
b) Calcule du saut négatif (offset) :
loop: nop # -5
nop # -4
nop # -3
nop # -2
beq $t0, $t1, loop # -1
nop # 0 (ici début)
3.2.2 Assemblage d’une instruction de branchement Conditionnel:
beq $t0, $t1, label
nop #0
nop #1
label: nop #2
op = 4(10)) = 0100(2) (voir code pour beq)
rs = 8(10)= 01000(2) ($t0= $8)
rt = 910)= 01001(2) ($t1 = $9)
imm = 2(10)= 2(16) = 0000 0000 0000 0010 (2) (Valeur de l’offset)
I : | 4 | 8 | 9 | 2 |
I : | 000100 | 01000 | 01001 | 0000000000000010 |
0001 0001 0000 1001 0000 0000 0000 0010
0x11090002
3.2 Assemblage d’une instruction J-type:
J : | op | target address |
op 6 bits code de l’opération à effectuer.
target address 26 bits valeur de l’adresse absolue contenu dans l’instruction
jr : est une instruction R-type
j, jal : instructions de saut (instructions J-type)
b, beq, bgez, bgezal, bgtz, blez, bltz, bltzal, bne : instructions de branchement (instructions J-type)
-adressage Relative vs. Absolu :
Instructions de Branchements – (offset est relative) : PC = PC + 4 + offset x4
Instructions de Sauts – (): PC = (PC & 0xF0000000) | (adresse x 4)
Noter que “adresse absolue” s’étend sur une région mémoire de 256 Mo = 2^28 Mo.
Exemple :
0x0200 0000 . . . . . . 0x0200 00A4 . . . . . . 0x0204 C100 | j label . . . . . . label: nop . . . . . . j label |
J : | J | target address |
op = 2(10)) = 00010(2) (voir code pour J)
target address = 200 00A4(16) /4 (Enlever le 1er chiffre Hex.et les deux derniers bits)
= 0010 0000 0000 0000 0000 1010 0100(2) (Valeur Bin de target address)
= 00 1000 0000 0000 0000 0010 1001(2) (Valeur Bin de target address)
= 0800029(16) (Valeur Hexde target address)
J : | J | label |
J : | 2 | 0x800029 |
J : | 0000 10 | 00 1000 0000 0000 0000 0010 1001 |
0000 1000 1000 0000 0000 0000 0010 1001
0x08800029Subscribe by Email
Follow Updates Articles from This Blog via Email
No Comments