Télécharger le document (10 pages) - Philippe J. Giabbanelli

Transcription

Télécharger le document (10 pages) - Philippe J. Giabbanelli
Low Level Programming
Notes du cours de Lin Jensen, septembre-décembre 2006
I.
Quelques rappels de calcul
Les nombres en hexadécimal sont précédés de 0x pour éviter une confusion dans les bases. Quand on veut
multiplier 0x3FCB par 2, il suffit de le convertir en binaire et d’opérer un décalage :
0111 1111 1001 0110, soit le résultat 0x7F96. On rappelle que chaque nombre s’écrit sur 4 bits.
Pour soustraite lorsqu’on a des nombres signés, on boucle. Ainsi 0000 moins 1 nous donne 1111.
La règle du complément à deux consiste à inverser les bits et à rajouter 1 :
0101 = 5 → 1010 (inversion) → 1011 (ajout du 1) : -5
0110 = 6 → 1001 → 1010 = - 6
Il y a donc un seul circuit pour toute l’arithmétique, puisque les nombres négatifs sont convertis grâce à la
règle du complément à deux. De même, il n’y a pas de circuit soustracteur mais juste un additionneur ; on
utilise la règle du complément à deux en cas de soustraction. Le résultat doit être complémenté à nouveau
pour l’exprimer en notation décimale. Par exemple si l’on obtient 111110, en le complémentant on obtient
000010 soit +2 ; donc le nombre obtenu était -2.
II.
Eléments d’architecture d’un ordinateur MIPS
Control
Unit
Instruction Adress Decode (IAD)
instruction
Address bus
ADD
MEMORY
1
5
6
$1
$2
$3
Par exemple un 0 dans l’IAD va faire un ADD.
Philippe Giabbanelli
Data bus
1 – Fetch instruction
2 - Decode
3 – Increment program count
4 – Execute instructions
↑ OLD MIPS
MIPS
1 ← MIPS Notes sur l’assembleur
Le Program Count (PC) nous donne l’instruction à exécuter. Si on passe d’une instruction à l’autre
linéairement, alors on passe de la 0 à la 4, i.e. on avance de 4 bytes.
On notera qu’il y a différents langages d’assembleur. Par exemple, il y a différentes syntaxes pour les
processeurs Intel. En plus des syntaxes, les noms des commandes et des registres ne sont pas les mêmes.
En assembleur x86 on trouve par exemple les registres eax et ebx, tandis qu’en MIPS on a des $t0, etc.
Les opinions sur la syntaxe sont également divisés dans le sens de lecture des commandes : de gauche à
droite, ou de droite à gauche. Est-il mieux d’écrire ADD $3 $2 $1 pour $3 ← $2+$1 ou $3+$2 → $1.
Processeur 6502, Atari
III.
Quand on dépasse des bornes lors d’un calcul, on parle d’arithmetic
overflow, cela entraîne des erreurs. Certains processeurs le détecte et font un
trap ou interruption request, d’autres ne réagissent pas ; ils utilisent en
général un overflow flag, chargé dans les processeurs x86 par les instructions
arithmétiques et de comparaison (équivalent à une soustraction sans stockage
de résultat), et non utilisé par les opérations logiques. Ne pas confondre : la
division par 0 n’est pas un arithmetic overflow ; la division par 0 est
mathématique indéfinie : ce n’est pas que sa valeur est trop large, mais plutôt
qu’elle n’a pas de valeur !
Opérations arithmétiques et premiers programmes MIPS
EDIT
ASSEMBLE
LINK TO THE LIBRARIES
EXECUTE
SYNTAX ERROR
We will use SPIM or XSPIM to show which line of the program code is going to be executed. We will
also use bank of test data, i.e. tests units, with MIPS MARK (command mipsmark file.a). At the end, we use
submit116 file.a.
In MIPS, the
results always go
back to register.
## Text segment
.text
.globl __start
__start:
lw $t1, mynum
li $t2, 5
add $t3, $t1, $t2
sw $t3, mynum
# execution starts here
# load word mynum into temporary register 1
# load immediate (for a constant) 5
# add the numbers and put them into t3
# store word from register to memory (location of mysum)
.data
mynum: .word 1
mysum: .word 0
# will be changed to 6 at the end
If we want to
move something
from a register to
a data, we use
instruction store.
If we want to
take something,
then we use load.
A simple operating system is simulator system calls, called syscall. It tells the O/S that we need help.
Register $v0 has to contain the service number, i.e. what we want syscall to do for us. Another registers
will be use by the service. $a0 stands for argument 0 for any kind of a call..
Service
Call code Arguments (input)
Results
print integer
1
$a0 = integer
print string
4
$a0 = address of string Prints every character until the terminating ‘\0’
read integer
5
(none)
$v0 holds integer that was entered
read string
8
$a0=address to store
$a1= length limit
characters are stored
exit
10
(none)
Ends the program
Philippe Giabbanelli
signed decimal integer printed in console window
2
Notes sur l’assembleur MIPS
# the goal of the program is to add 2 + 3 and print “5 oranges”
.text
.globl __start
__start:
lw $t0, mynum
# t0 ← 2 (mynum)
li $t1, 3
# t1 ← 3
add $a0, $t0, $t1
# a0 ← mynum + 3
li $v0, 1
# ready to print an int
syscall
# ask the OS to run service 1
la $a0, str
# load the address of str
li $v0, 4
# ready to print a string
syscall
# print the string
li $v0, 10
# ready to end
syscall
# exit
Il y a des pseudo-instructions qui
sont ensuite expansées, comme
neg $t3, $t0 → sub $t0, $0, $t0
Où $0 contient toujours 0.
La forme normale est :
<add|sub> Rdest, Rsrc1, src2
Où src2 est un registre ou une
constante. Parfois, addi est utilisé
pour la forme à 2 registres et une
constante. Il y aussi un raccourci :
add $t0, 1 → add $t0, $t0, 1
Cela marche de la même manière
avec la soustraction, mais il n’y a
pas de subi. C’est plutôt :
addi $t5, $t0, -5
sub $t5, $t5, 4 ≡ addi $t5, $t5, -4
.data
mynum: .word 2
# a word is 32 bits. mynum is a label
str: .asciiz “oranges\n” # asciiz ends the string with \0
Avec ‘mul Rdest, Rsrc1, src2’, on fait une multiplication de nombres signés et on stocke le résultat sur 32
bits. Or, multiplier 32 bits par 32 bits peut donner un résultat sur 64 bits, et alors ça ne loge pas, il y a une
arithmetic overflow. La pseudo-instruction mulo regarde s’il y a overflow, et arrête proprement la chose ;
c’est implémenté par plusieurs instructions, pour disposer de la vérification.
L’instruction div marche de même manière que mul :
li $t0, 20
div $a0, $t0, 3
li $v0, 1
syscall
# affiche 6, à savoir le résultat de la division entière
Avec rem Rdest, Rsrc1, src2 on obtient le reste (remainder) de la division. Il y a aussi une version nonsignée de la multiplication et de la division, en mettant un ‘u’ à la fin (exemple : mulou).
L’instruction réelle de la machine pour la multiplication est mult Rsrc1, Rsrc2. Comme le résultat fait 64
bits, il est stocké dans deux registres :
S’ajoutent aux
Register hi
Register lo
32 registres de
l’ordinateur
En contrôlant l’allure de hi et de lo, on sait s’il y a eu overflow ou non. C’est le même principe avec la
division, où on met le quotient en lo et le reste en hi.
lw $t0, apples
div $t1, $t0, 8
rem $t2, $t0, 8
# apples / student
# remainder
Philippe Giabbanelli
li $1, 8
div $t0, $1
mflo $t1
li $1, 8
div $t0, $1
mfhi $t2
expansion
3
Optimisation
(compilateur)
li $1, 8
div $t1, $1
mflo $t2
mflo $t3
Notes sur l’assembleur MIPS
# The problem is to find a point on a line, given by the equation: y = slope*x + intercept for some value
# x, calculate and print the corresponding y value that is (nearly) on the line. Since we are doing integer
# arithmetic, slope will be given as two numbers, dy and dx, see figure. You will need to multiply before
# dividing, and the answer will be only approximate, simply ignore any remainder.
.text
.globl __start
__start:
# execution starts here
la $a0, hi
li $v0, 4
syscall
# we print a welcome message `cause we are polite
# be ready to print the message
# ok the message has been print
lw $t0,x
lw $t1,dy
mult $t0,$t1
mflo $t2
lw $t1,dx
div $t2,$t1
mflo $t1
lw $t0, intercept
add $t3,$t0,$t1
sw $t3, y
# let us have the variable we want to compute... x
# and here we get dy
# we multiply the number, it goes in Lo
# the result is now in register t2 `cause we know it is a little number
li $v0, 4
la $a0,ans
syscall
lw $a0,y
li $v0, 1
syscall
li $v0,4
la $a0,endl
syscall
li $v0,10
syscall
# be ready to print
# "answer ="
# and now we have (dy.x)/dx
# we move the result from Low because we assume it is the quotient
# we make the final computing for additionning every part of the expression
# we store the final result in the variable y
# print the answer
# print "\n"
# exit program
# ciao !
## -----------------------------------------------------.data
x:
.word 9
# find y for this value
dy: .word 10
# vertical rise
dx: .word 6
# horizontal run
intercept: .word -2
#line crosses y-axis here
y:
.word -99
#optionally use this memory...
ans: .asciiz "answer = "
endl: .asciiz "\n"
hi: .asciiz "hi there we are gonna make some calculus\n"
Philippe Giabbanelli
4
Notes sur l’assembleur MIPS
IV.
Control Flow Instructions
On discerne trois patterns : appel de functions (call functions), sauter une partie (skip), boucle (loop).
?
T
Branch to label
F
Keep going in
normal way
Instruction
Branch to
label if
beq Rsrc1,
Src2, label
Rsrc1 = Src2
bne Rsrc1,
Src2, label
Rsrc1 <> Src2
blt Rsrc1,
Src2, label
Rsrc1 < Src2
bgt Rsrc1,
Src2, label
Rsrc1 > Src2
bgtu
ble Rsrc1,
Rsrc1 <= Src2
Src2, label
bleu
bge Rsrc1,
Rsrc1 >= Src2
Src2, label
bgeu
Unsigned
bltu
On utilisera principalement l’instruction ‘j’ qui permet d’aller à un
label. Par exemple, j backthere saute à au label (étiquette) backthere.
# affichons un message 5 fois
.text
.globl –start
li $t0, 5
# initialization of loop counter
la $a0, mess
li $v0, 4
again :
beqz $t0, done
# while t0 != 0…
syscall
# loop body
sub $t0, 1
# decrement t0
j again
# go to the test
done:
li $v0, 10
syscall
.data
mess: .asciiz “hello again\n”
# affiche un message
# nombre de fois : ∞
.text
.globl –start
la $a0, mess
li $v0, 4
again :
syscall
j again
done:
li $v0, 10
syscall
.data
mess: .asciiz “hey\n”
On utilise aussi les pseudo-instructions
avec un z à la fin pour signifier « zéro ».
beqz $t0, done → beq $t0, $0, done
.text
.globl –start
--start
li $v0, 4
la $a0, what # ‘what is the temperature ?’
syscall
li $v0, 5
# read int, store result in $v0
syscall
move $t0, $v0
blt $t0, 5, chilly
# s’il fait moins de 5°C
la $a0, nice
# ‘it’s hot !’
li $v0, 4
syscall
j endif
chilly :
la $a0, cold
# ‘brr !’
li $v0, 4
syscall
endif:
li $v0, 10
syscall
Philippe Giabbanelli
Ces instructions de branchement sont parmi les soucis
qu’engendre l’écriture d’un code assembleur à la main.
En effet, si le programme devient gros et qu’il y a
plusieurs boucles, on risque de leur attribuer les
mêmes labels… un compilateur utilise un générateur
de label, qui asure qu’il n’a pas déjà été utilisé.
{sum non-negative numbers}
sum := 0
num := 0
WHILE num >= 0 DO
sum := sum + num
read (num)
ENDWHILE
{write 10 lines}
FOR countdown := 10 downto 1 DO
print ("Hello again...")
ENDFOR
# add $t0, $0, $0 really:
# set up print arguments before loop
move $t0, $0 #sum=0
la $a0, hello_again
move $v0, $0 #num=0
li $v0, 4 #print string call
while5:
li $t0, 10 # countdown
bltz $v0, endwhile5
for10:
add $t0, $v0
beqz $t0, endfor10
#
---- $v0 switches role here
syscall #print another line
li $v0, 5 #read int call
sub $t0, 1 #decr. countdown
syscall
j for10
j while5
endfor10:
endwhile5:
5
Notes sur l’assembleur MIPS
V.
Parcours d’un tableau
T
3 +0
Soit un tableau T d’entiers {3, 6, 9, 2}. T[2] représente le contenu du mot mémoire
6 +4
adressé par T + 2 * sizeof(int), c’est-à-dire habituellement T + 2*4 = 2 + 8.
9 +8
2 +12
En MIPS, on peut charger l’adresse d’un registre, i.e. créer une sorte de pointeur.
lw $t3, ($t0)
# les ( ) signifient qu’on ce qui est pointé par t0, c’est de l’adressage indirect
Nous allons donc transcrire nos pointeurs C en assembleur, comme suit :
int arr[] = {3, 6, 9, 2} ;
.globl –start
int *a = arr ;
--start
int sum = 0;
move $t2, $0
# t2 = sum = 0
while(i<4){
la $t0, arr
# t0 points to array, we load address
sum += *a;
li $t1, 0
# loop counter
a++; i++;
while:
}
bge $t1, 4, endwhile # opposite of the loop condition
lw $t3, ($t0)
# t3 = *a, pointed value
add $t2, $t2, $t3
# sum += *a
Procédons de même pour déterminer
add $t0, 4
# a++, point to the next element
la taille d’une chaîne de caractère.
add $t1, 1
# i++, loop counter
Nous savons qu’une chaîne, au sens C,
j while
se termine toujours par le caractère \0,
endwhile:
# we can print the result if we want
à savoir 0000 0000 en binaire. Si on écrit
li $v0, 10
ceci en C, on peut s’aider du fait que 0 est
syscall
faux et tout le reste est vrai. D’où :
char *nextchar = ans ;
.data
int count = 0 ;
arr: word 3,6,9,-2
while(*nextchar++) count++;
Quand on veut transcrire en code assembleur, on commence par poser les variables :
# t1 : compteur
t0 : nextchar
t2 : character pointed to
# string length
la $t0, ans
# points to string
li $t1, 0
# count = 0. The same than doing move $t1, $0
lenloop:
lb $t2, ($t0)
# load byte (character) pointed by t0
beqz $t2, lendone # while char ≠ ‘\0’
add $t0, 1
# advance pointer
# copy of a string
add $t1, 1
# increase count
--start:
j lenloop
li $t0, 0
lendone:
# $t1 is now string length
copyloop :
lb $t1, mystring($t0) # load char
De même avec la copie d’une chaîne de caractère :
sb $t1, copy($t0)
# copy it
char copy[15] ;
char copy[15];
beqz
$t1,
endcopy
# if \0, end
pcopy = copy ;
pcopy = copy;
add $t0, 1
# else continue
char this ;
while(*pcopy++ = *nextchar++)
j
copyloop
while(this = *nextchar++)
{;}
endcopy :
*pcopy++ = this;
la $a0, copy
li $v0, 4
syscall
# print the string
On utilise ici un nouveau mode d’adressage : indexed addressing.
li $v0, 10
syscall
Philippe Giabbanelli
6
Notes sur l’assembleur MIPS
Exercice 2
Faire la somme des entiers non divisibles par 4 dans un tableau.
Exercice 1
Permuter deux à deux les composants
d’une chaîne de caractère de longueur
paire.
la $s0, numbers
# a pointer to 'navigate' through the array
li $s1, 5
# numbers of elements in the array
li $s2, 0
# final sum. OUR result !
loop:
lw $a0, ($s0) # taking the number as argument for function
beqz $s1, endloop
# is it done ? if so, stop counting !
jal isDivisableFour
beqz $v0, skip
lw $t1, ($s0) # load the word from memory
add $s2, $s2, $t1 # add because not divisable by 4
skip:
add $s0, 4
# go to the next digit by jumping 4 bits
sub $s1, 1
# decrement the loop counter
j loop
endloop:
la $a0, ans # write "sum = "
li $v0, 4
syscall
move $a0, $s2 # write the value we computed
li $v0, 1
syscall
la $a0, endl # write the end of line (carriage return)
li $v0, 4
syscall
li $v0, 10 # end the program
syscall
isDivisableFour:
# we want to know if it begins with a 00
and $t0, $a0, 3 # see the first two digits, which must be 00
sne $v0, $t0, $0 # if it's not 0, there it's not divisable
jr $ra
# $v0 is 0 if it's not divisable, and 1 else.
.text
.globl __start
__start:
# execution starts here */
#the algorithm is very easy :
#while(character pointed by array is not 0)
# swap *(array) and *(array + 1)
la $t0, chararray # t0 is pointer to char
loop:
lb $t1, ($t0)
# put (*t0) in t1, as temp
beqz $t1, endloop # if *(t0) = '\0', stop
lb $t2, 1($t0)
# load register’s content
sb $t2, ($t0)
# put *(t0) = *(t0 + 1)
sb $t1, 1($t0)
# the letter are swap
add $t0, 2
# go to next pair
j loop
# we begin the loop again
endloop:
li $v0, 4
la $a0, chararray
syscall
# we print the result
li $v0, 10
syscall
# and we close the program
.data
chararray:
.asciiz "abcdef"
endl: .asciiz "\n"
.data
#*/
numbers:
.word 3,4,12,28,17
ans: .asciiz "sum = "
endl: .asciiz "\n"
VI.
Les différents modes d’adressage
Immediate adressing : li $v0, 10
Direct memory addressing : lw $t0, mynum
Indirect addressing : lb $t0, ($t2)
Indexed addressing : lb $t0, mystring($t3)
(register and constant)
(register and memory)
(store in register the value pointed by another register)
(mystring is a big constant number
(t3 starts at 0 and get incrementend : 0, 1, 2…
If it is a string, then we go from one to one and we load a byte : lb $t0, mystring($t3), where t3 = 0, 1, 2…
If is an array of integers, then we load a word : lw $t4, mynum($t5), where t5 = 0, 4, 8, 12…
Philippe Giabbanelli
7
Notes sur l’assembleur MIPS
VII.
Utilisation de la pile
On utilise le stack pointer $sp (valeur $29, initialisé par le système d’exploitation).
Pour chaque appel d’une fonction à une autre, le schéma est le suivant :
save $ra
jal function
restore $ra
jr $ra
Push 42
Push 47
Pop $v0
li $t0, 42
# push $t0 on the stack
sub $sp, 4
sw $t0, ($sp)
add $t0, 4
# now 47
sub $sp, 4
# push t0
sw $t0, ($sp)
lw $v0, ($sp)
add $sp, 4
Code segment
Data segment
On ajoute à la pile pour créer de
l’espace, et on soustrait pour libérer.
li $t0, 0x40 # the number that we are going to use as a mask
lw $s0, ($sp) # the number in top of the stack is the amount of numbers in the stack
add $sp, 4
# POP !
li $s1, 0
# the current sum
addition:
beqz $s0, done # have we saw all the numbers ? If so, we stop.
jal popword
and $t1, $v0, $t0
beqz $t1, skip # if the number doesn't have the bit set, we skip it
add $s1, $s1, $v0 # else we sum it
skip:
sub $s0, $s0, 1
j addition
done:
la $a0, ans # we print "sum is = "
li $v0, 4
syscall
move $a0, $s1 # we print the sum that we have computed
li $v0, 1
syscall
la $a0, endl # we print an endline
li $v0, 4
syscall
li $v0, 10 # we end the program
syscall
popword:
lw $v0, ($sp)
add $sp, 4
j $ra
Philippe Giabbanelli
## The program must sum numbers
## stored on the stack that have bit 6 set.
## The word on the top of the stack tells
## you how many numbers are in the sequence.
## Do not include this first word in the sum.
8
Notes sur l’assembleur MIPS
Heap
↓
↑
Stack
search:
# launcher to the algorithm
sub $sp, 4
sw $ra,($sp)
jal search_start
# we launch the algorithm
lw $ra, ($sp) # restore return adress
add $sp, 4
# free the space on stack
jr $ra # the result is already in $v0 because of search_start
search_start:
# a1 is the level in which we are ; a0 is the current node
sub $sp, $sp, 12
sw $ra,($sp)
sw $a1,4($sp)
sw $a0,8($sp)
lw $a0,($a0) # take the pointer to the string as parameter a1
jal store_path
lw $a0, 8($sp)
lw $t0,12($a0) # t0 is the value in the node
li $t3, 1
bne $t0, $t3, ssskip1 # if value == 1...
li $v0, 1
# v0 = 1
lw $ra,($sp) # we take the return
## Write a function named search that will do a
addi $sp,12 # free the space
## depth first search of a tree for a marked
jr $ra
# and return
## node. A marked node is one that has a value
## field equal to 1. Only one node in the tree is
ssskip1:
## marked.
lw $t1, 4($a0) # pointer to the left tree
##
beqz $t1, ssskip2
# if we have a left node
## The parameters to search are a pointer to the
lw $a1, 4($sp) # current level in a0
## tree and the current depth. On each recursive
addi $a1, 1 # increase it
## call add 1 to the depth. This parameter is
move $a0, $t1 # give the node as parameter
## used to keep track of the path from the root
jal search_start
## to the marked node; as you visit a node, you
beqz $v0, ssskip2
# if result is true
## will call a procedure named store_path to
lw $ra, ($sp) # take return
## record the fact that you have visited this
addi $sp, 12 # free space
## node. The code for store_path and print_path
jr $ra
# return
## (called after you get back from the procedure)
## have been written for you -- all you need to
ssskip2:
## do is understand how to set up their parameters
lw $a0, 8($sp)
## and make the call.
lw $t2, 8($a0) # pointer to the right tree
##
beqz $t2, sssend
# same stuff than previously
## The code for search could look like:
lw $a1, 4($sp)
##
call store_path
addi $a1, 1
##
if (value == 1)
move $a0, $t2
##
return 1
jal search_start
##
if (left tree exists)
beqz $v0, sssend
##
if (search(left tree, depth+1))
lw $ra, ($sp)
##
return 1
addi $sp, 12
##
if
(right tree exists)
jr $ra
##
return search(right tree, depth+1)
sssend:
##
return 0
li $v0, 0
# else we didn't find it : v0 = 0
##
lw $ra, ($sp) # load return, free space, return
## Output format must be:
addi $sp, 12
## "apple-->orange-->plum-->grape-->star-->passion"
jr $ra
Philippe Giabbanelli
9
Notes sur l’assembleur MIPS
# Formal algorithm that we will implement
# evaluate(Tree T){
#
if( OPERATOR )
#
return OPERATOR :: Right, Left
#
else if ( NUMBER )
#
return Number
## Write a function "evaluate" that will return the integer result
## of evaluating an arithmetic expression tree.
## Argument is a pointer to the root of the tree. Each node contains
## -- an operation: '+', '-', '*', or '/'
##
followed by two pointers (not null) to a subtree
## OR
## -- the value 0, followed by an integer
# Nodes will either contain an operator and 2 pointers, or 0 and one binary number
evaluate:
# a0 is the root of the expression tree
move $t0, $ra
jal isOperator
move $ra, $t0
bgt $v0, $0, numberDetected
sub $sp, 12
sw $ra, 0($sp) # 0($sp) = return adress
sw $a0, 4($sp) # 4($sp) = our node
lw $a0, 4($a0) # point to the first subtree
jal evaluate
# call on first subtree
sw $v0, 8($sp) # 8($sp) = result from the first subtree
lw $a0, 4($sp) # point to the root...
lw $a0, 8($a0) # ...and take its subtree
jal evaluate
# call on the other subtree
lw $t0, 4($sp) # what is the kind of operator that we had ?
lw $t0, ($t0)
lw $t1, 8($sp)
# result from the first subtree
bne $t0, '+', step2
# RETURN 1 IF NOT AN OPERATOR.
# apply +
isOperator:
add $v0, $t1, $v0
# v0 = subtree1 + subtree2
sub $sp, 4
j stepEnd
sw $a0, ($sp)
step2:
lw $a0, ($a0)
bne $t0, '-', step3
bne $a0, '+', oStep2
# apply j oEndTrue
sub $v0, $t1, $v0
# v0 = subtree1 - subtree2
oStep2:
j stepEnd
bne $a0, '-', oStep3
step3:
j oEndTrue
bne $t0, '*', step4
oStep3:
# apply *
bne $a0, '/', oStep4
mul $v0, $t1, $v0
# v0 = subtree1 * subtree2
j oEndTrue
j stepEnd
oStep4:
step4:
bne $a0, '*', oEndFalse
# apply /
j oEndTrue
div $v0, $t1, $v0
# v0 = subtree1 / subtree2
oEndFalse:
stepEnd:
li $v0, 1
lw $ra, 0($sp)
lw $a0, ($sp)
add $sp, 12
add $sp, 4
jr $ra
jr $ra
numberDetected:
oEndTrue:
lw $t0, 4($a0) # take the number...
li $v0, -1
add $v0, $t0, $0
# put the number in v0
lw $a0, ($sp)
jr $ra
add $sp, 4
jr $ra
Philippe Giabbanelli
10
Notes sur l’assembleur MIPS