module Mips:sig..end
Mips permet l'écriture de code MIPS dans du code
OCaml, sans utiliser un préprocesseur. Un exemple complet est
donné ci-dessous, dans la section exemple.
Un descriptif détaillé des instructions peut être trouvé dans l'appendice A de: 'Computer Organization and Design: The Hardware/Software Interface.' (Hennessy & Patterson, Elsevier). Le pdf de l'appendice A est disponible à cette URL:
http://pages.cs.wisc.edu/~larus/HP_AppA.pdf
type 'a asm
'a est utilisé comme type fantôme.typetext =[ `text ] asm
typedata =[ `data ] asm
type program = {
|
text : |
|
data : |
val print_program : Format.formatter -> program -> unitprint_program fmt p imprime le code du programme p dans le
formatter fmttype 'a register
'a est un type fantôme représentant encodant le fait
que le registre est un registre général (type word) ou un registre du co-processeur
flottant (type double).typeword =[ `word ]
typedouble =[ `double ]
val v0 : word register
val v1 : word register
val a0 : word register
val a1 : word register
val a2 : word register
val a3 : word register
val t0 : word register
val t1 : word register
val t2 : word register
val t3 : word register
val s0 : word register
val s1 : word register
val ra : word register
val sp : word register
val fp : word register
val gp : word register
val zero : word registerval f0 : double register
val f2 : double register
val f4 : double register
val f6 : double register
val f8 : double register
val f10 : double register
val f12 : double registertypelabel =string
type 'a operand
val oreg : word register operand
val oi : int operand
val oi32 : int32 operandval li : word register -> int -> text
val li32 : word register -> int32 -> textval abs : word register -> word register -> textabs r1 r2 stocke dans r1 la valeur absolue de r2val neg : word register -> word register -> textneg r1 r2 stocke dans r1 l'opposé de r2val add : word register ->
word register -> 'a operand -> 'a -> text
val sub : word register ->
word register -> 'a operand -> 'a -> text
val mul : word register ->
word register -> 'a operand -> 'a -> text
val div : word register ->
word register -> 'a operand -> 'a -> text
val rem : word register ->
word register -> 'a operand -> 'a -> textadd rdst rsrc1 ospec o
stocke dans rdst le résultat de l'opération entre rsrc1 et o. La
constante 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 cvt_d_w : double register -> double register -> 'a asmcvt_d_w f1 f2 convertit l'entier placé dans le registre f2 en
flottant double précision et place le résultat dans f1val cvt_w_d : double register -> double register -> 'a asmcvt_w_d f1 f2 convertit le flottant double précision placé dans
le registre f2 en entier et place le résultat dans f1val abs_d : double register -> double register -> textabs_d f1 f2 stocke dans f1 la valeur absolue de f2val neg_d : double register -> double register -> textneg_d f1 f2 stocke dans f1 l'opposé de f2val add_d : double register ->
double register -> double register -> text
val sub_d : double register ->
double register -> double register -> text
val mul_d : double register ->
double register -> double register -> text
val div_d : double register ->
double register -> double register -> textval clz : word register -> word register -> text
val and_ : word register ->
word register -> word register -> text
val or_ : word register ->
word register -> word register -> text
val not_ : word register -> word register -> textval seq : word register ->
word register -> word register -> text
val sge : word register ->
word register -> word register -> text
val sgt : word register ->
word register -> word register -> text
val sle : word register ->
word register -> word register -> text
val slt : word register ->
word register -> word register -> text
val sne : word register ->
word register -> word register -> textsop ra rb rc met ra à 1 si rb op rc et à 0
dans le cas contraire (eq : ==, ge : >=, gt : >, le :
<=, lt : <=, ne : !=)val c_eq_d : double register -> double register -> textval c_le_d : double register -> double register -> text
val c_lt_d : double register -> double register -> texts_op_d fa fb met le registre de condition du
co-processeur flottant à 1 si ra op rb et à 0 dans le cas
contraire (eq : ==, le : <=, lt : <=). Les instructions
bclf et bclt permettent de tester le registre de condition.val b : label -> textval beq : word register -> word register -> label -> text
val bne : word register -> word register -> label -> text
val bge : word register -> word register -> label -> text
val bgt : word register -> word register -> label -> text
val ble : word register -> word register -> label -> text
val blt : word register -> word register -> label -> textbop ra rb label branche vers le label label si ra op rbval beqz : word register -> label -> text
val bnez : word register -> label -> text
val bgez : word register -> label -> text
val bgtz : word register -> label -> text
val blez : word register -> label -> text
val bltz : word register -> label -> textbopz ra rb label branche vers le label label si ra op 0val bc1f : label -> textbc1f label saute vers le label label si le registre de condition
du co-processeur flottant vaut 0val bc1t : label -> textbc1f label saute vers le label label si le registre de condition
du co-processeur flottant vaut 1val jr : word register -> textjr r Continue l'exécution à l'adresse spécifiée dans le registre
rval jal : label -> textjal l Continue l'exécution à l'adresse spécifiée par le label l,
sauve l'adresse de retour dans $ra.val jalr : word register -> textjalr 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 * 'a register) addressval la : word register -> 'a address -> 'a -> textla 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 octetsval lbu : word register -> 'a address -> 'a -> textval lb : word register -> 'a address -> 'a -> 'b asmval lw : word register -> 'a address -> 'a -> textval lwc1 : double register -> 'a address -> 'a -> textval ldc1 : double register -> 'a address -> 'a -> textval sb : word register -> 'a address -> 'a -> textval sw : word register -> 'a address -> 'a -> textval swc1 : double register -> 'a address -> 'a -> textval sdc1 : double register -> 'a address -> 'a -> textval move : word register -> word register -> textmove rd rs copie le registre source rs dans le registre
destination rdval mov_d : double register -> double register -> textmov_d fd fs copie le registre source flottant fs dans le registre
destination fdval mfc1 : word register -> double register -> textmfc1 r1 f1 copie le registre f1 du co-processeur flottant vers le registre
général r1val mtc1 : word register -> double register -> textmfc1 r1 f1 copie le registre général r1 dans le registre f1
du co-processeur flottant.val nop : [> ] asm
val label : label -> [> ] asmval syscall : textval comment : string -> [> ] asmval align : int -> [> ] asmalign n aligne le code suivant l'instruction sur 2^n octetsval space : int -> dataspace n réserve n octets non initialisés dans la zone dataval asciiz : string -> dataval word : int list -> dataval address : label list -> dataval double : float list -> dataval (@@) : ([< `data | `text ] as 'a) asm -> 'a asm -> 'a asmval (++) : ([< `data | `text ] as 'a) asm -> 'a asm -> 'a asm@@val set_stack_alignment : int -> unit
val get_stack_alignment : unit -> intset_stack_alignment lève une exception si l'alignement n'est pas une
puissance de 2.val push : [< `double | `word ] register -> textpush r place le contenu de r au sommet de la pile. $sp pointe
sur l'adresse de la dernière case occupéeval peek : [< `double | `word ] register -> textpeek r place la valeur en sommet de pile dans r sans dépilerval pop : [< `double | `word ] register -> textpop r place la valeur en sommet de pile dans r et dépile
.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 *)