module Mips:sig
..end
Le module Mips
permet l'écriture de code MIPS dans du code
OCaml, sans utiliser un préprocesseur.
Exemple : Le programme ci-dessous, donné à gauche en pur MIPS et à droite en OCaml, charge deux constantes, effectue quelques opérations arithétiques et affiche le résultat à l'écran
.text | { text =
main: | label "main"
#charge 42 dans $a0 et 23 dans $a1 | ++ comment "charge 42 dans $a0 et 23 dans $a1"
li $a0, 42 | ++ li a0 42
li $a1, 23 | ++ li a1 23
mul $a0, $a0, $a1 | ++ mul a0 a0 oreg a1 (* on utilise oreg pour dire que la dernière
| operande est un registre *)
#place le contenu de $a0 sur la pile | ++ comment "place le contenu de $a0 sur la pile"
sub $sp, $sp, 4 | ++ sub sp sp oi 4
sw $a0, 0($sp) | ++ sw a0 areg (0, sp)
|
#appelle une routine d'affichage | ++ comment "appelle la routine d'affichage"
jal print_int | ++ jal "print_int"
|
#termine | ++ comment "termine"
li $v0, 10 | ++ li v0 10
syscall | ++ syscall
|
print_int: | ++ label "print_int"
lw $a0, 0($sp) | ++ lw a0 areg (0, sp)
add $sp, $sp, 4 | ++ add sp sp oi 4
li $v0, 1 | ++ li v0 1
syscall | ++ syscall
#affiche un retour chariot | ++ comment "affiche un retour chariot"
la $a0, newline | ++ la a0 alab "newline"
li $v0, 4 | ++ li v0 4
syscall | ++ syscall
jr $ra | ++ jr ra ; (* fin du label text *)
|
.data | data =
newline: | label "newline"
.asciiz "\n" | ++ asciiz "\n" ;
| } (* fin du record *)
type 'a
asm
type abstrait pour représenter du code assembleur. Le paramètre
'a
est utilisé comme type fantôme.
typetext =
[ `text ] asm
type représentant du code assembleur se trouvant dans la zone de texte
typedata =
[ `data ] asm
type représentant du code assembleur se trouvant dans la zone de données
type
program = {
|
text : |
|
data : |
un programme est constitué d'une zone de texte et d'une zone de donnée
val print_program : Stdlib.Format.formatter -> program -> unit
print_program fmt p
imprime le code du programme p
dans le
formatter fmt
val print_in_file : file:string -> program -> unit
typeregister =
string
val v0 : register
val v1 : register
val a0 : register
val a1 : register
val a2 : register
val a3 : register
val t0 : register
val t1 : register
val t2 : register
val t3 : register
val s0 : register
val s1 : register
val ra : register
val sp : register
val fp : register
val gp : register
val zero : register
Constantes représentant les registres manipulables. zero
est
cablé à 0
typelabel =
string
Les étiquettes d'addresses sont des chaines de caractères
type 'a
operand
val oreg : register operand
val oi : int operand
val oi32 : int32 operand
type abstrait pour représenter la dernière opérande d'une expression arithmétique ainsi que 3 constantes (soit un registre, soit un entier, soit un entier 32 bits)
val li : register -> int -> text
val li32 : register -> int32 -> text
Chargement des constantes entières
val abs : register -> register -> text
abs r1 r2
stocke dans r1 la valeur absolue de r2
val neg : register -> register -> text
neg r1 r2
stocke dans r1 l'opposé de r2
val add : register -> register -> 'a operand -> 'a -> text
val sub : register -> register -> 'a operand -> 'a -> text
val mul : register -> register -> 'a operand -> 'a -> text
val rem : register -> register -> 'a operand -> 'a -> text
val div : register -> register -> 'a operand -> 'a -> text
Les 5 opérations arithmétique de base: add rdst rsrc1 ospec o
stocke dans rdst le résultat de l'opération entre rsrc1 et o. La
constant ospec spécifie si o est un immédiat, immédiat sur 32 bits
ou un registre.
Exemple:
add v0 v1 oreg v2
div v0 v1 oi 424
sub t0 a0 oi32 2147483647l
val and_ : register -> register -> register -> text
val or_ : register -> register -> register -> text
val not_ : register -> register -> text
val clz : register -> register -> text
Opérations de manipulation de bits. "et" bit à bit, "ou" bit à bit, "not" bit à bit et clz (count leading zero)
val seq : register -> register -> 'a operand -> 'a -> text
val sne : register -> register -> 'a operand -> 'a -> text
val sge : register -> register -> 'a operand -> 'a -> text
val sgt : register -> register -> 'a operand -> 'a -> text
val sle : register -> register -> 'a operand -> 'a -> text
val slt : register -> register -> 'a operand -> 'a -> text
conditionnelles sop ra rb rc
met ra
à 1 si rb op rc
et à 0
dans le cas contraire (eq : ==, ge : >=, gt : >, le : <=, lt : <=,
ne : !=)
val b : label -> text
saut inconditionnel
val beq : register -> register -> label -> text
val bne : register -> register -> label -> text
val bge : register -> register -> label -> text
val bgt : register -> register -> label -> text
val ble : register -> register -> label -> text
val blt : register -> register -> label -> text
bop ra rb label
branche vers le label label
si ra op rb
val beqz : register -> label -> text
val bnez : register -> label -> text
val bgez : register -> label -> text
val bgtz : register -> label -> text
val blez : register -> label -> text
val bltz : register -> label -> text
bopz ra rb label
branche vers le label label
si ra op 0
val jr : register -> text
jr r
Continue l'exécution à l'adresse spécifiée dans le registre
r
val jal : label -> text
jal l
Continue l'exécution à l'adresse spécifiée par le label l
,
sauve l'adresse de retour dans $ra.
val jalr : register -> text
jalr r
Continue l'exécution à l'adresse spécifiée par le
registre r
, sauve l'adresse de retour dans $ra.
type 'a
address
type abstrait pour représenter des adresses
val alab : label address
val areg : (int * register) address
Les adresses sont soit données par un label, soit par une paire décalage, registre
val la : register -> 'a address -> 'a -> text
la reg alab "foo"
charge dans reg
l'adresse du label "foo"
la reg1 areg (x, reg2)
charge dans reg1
l'adresse contenue dans
reg2
décallée de x
octets
val lbu : register -> 'a address -> 'a -> text
charge l'octet à l'adresse donnée sans extension de signe (valeur entre 0 et 255)
val lw : register -> 'a address -> 'a -> text
charge l'entier 32bits à l'adresse donnée
val sb : register -> 'a address -> 'a -> text
écrit les 8 bits de poid faible du registre donnée à l'adresse donnée
val sw : register -> 'a address -> 'a -> text
écrit le contenu du registre à l'adresse donnée
val move : register -> register -> text
val nop : [> ] asm
l'instruction vide. Peut se trouver dans du text ou du data
val label : label -> [> ] asm
un label. Peut se retrouver dans du text ou du data
val syscall : text
l'instruction syscall
val comment : string -> [> ] asm
place un commentaire dans le code généré. Peut se retrouver dans du text ou du data
val align : int -> [> ] asm
align n
aligne le code suivant l'instruction sur 2^n octets
val asciiz : string -> data
place une constante chaîne de carctères (terminées par 0) dans a zone data
val dword : int list -> data
place une liste de mots mémoires dans la zone data
val address : label list -> data
place une liste d'adresses (dénotées par des labels) dans la zone data
val space : int -> data
space n
alloue n
octets dans le segment de données
val inline : string -> [> ] asm
inline s
recopie la chaîne s
telle quelle dans le fichier assembleur
val (++) : ([< `data | `text ] as 'a) asm -> 'a asm -> 'a asm
concatène deux bouts de codes (soit text avec text, soit data avec data)
val push : register -> text
push r
place le contenu de r
au sommet de la pile.
Rappel : $sp pointe sur l'adresse de la dernière case occupée
val pop : register -> text
pop r
place le mot en sommet de pile dans r
et dépile
val popn : int -> text
popn n
dépile n
octets
val peek : register -> text
peek r
place le mot en sommet de pile dans r
sans dépiler