SPIM e MIPS Non abbiamo bisogno di una PSP per testare il codice
Michele Jazzinghen Bianchi Interessi: Game Design, Embedded Systems email: michele.bianchi@unitn.it Webpage: http://disi.unitn.it/~bianchi Ricevimento: Mi mandate una mail e ci mettiamo d accordo Non avete capito qualcosa? Fatemi domande subito, sono quì apposta.
SPIM (o meglio QtSpim) MIPS è un assembly che viene implementato in piattaforme embedded e La PS1, la PS2 e la PSP! (E l ho scoperto solo ieri!)
Vabbeh, ma comunque: LOL INTEL Rimane comunque il fatto che il nostro PC non è in grado di interpretare MIPS. Per risolvere questo installeremo un emulatore con alcune funzionalità simili ad un debugger
L url del sito è: http://spimsimulator.sourceforge. net/ Il resto sapete come farlo. Scaricare + Installare QtSpim
QtSPIM - Un overview
Scrivere codice in SPIM (a.k.a. IDE WARS)
Machissenefrega! Iniziamo subito a fare cose. Il metodo migliore per capire una cosa è farla. Proveremo dalla cosa più banale che avete visto a Programmazione 1, il BUBBLE SORT!
Il Bubble Sort Per rinfrescarci la memoria, è quell algoritmo di ordinamento che gira in O(n2), continuando a scambiare posto ai valori se sono nell ordine sbagliato. Da non confondere con lo Shaker Sort, dove si fanno passaggi andata e ritorno.
#include "stdint.h" #include "stdlib.h" #include "stdio.h" void sort (int32_t * v, uint16_t len){ int32_t i,j; void swap (int32_t * v, uint32_t k){ int32_t tmp; tmp = v[k]; v[k] = v[k+1]; v[k+1] = tmp; } for (i = 0; i < len; i++){ for (j = i - 1; j >= 0 && v[j] > v[j+1]; j--){ swap(v, j); } } } Codice in C - Parte 1
int main (int argc, char **argv){ int32_t i; int32_t data[10] = {-37, 190, 214, -41, -65, 242, -62, 13, 197, 10}; sort(data, 10); printf("array: %d", data[0]); for (i=1; i < 10; i++){ printf(", %d", data[i]); } printf(".\n"); return 0; } Codice in C - Parte 2
swap:sll $t1, $a1, 2 add $t1, $a0, $t1 # $t1 = k * 4 # $t1 = v + (k * 4) {$t1 = &v[k]} lw lw $t0, 0($t1) $t2, 4($t1) # $t0 = v[k] {temp = v[k]} # $t2 = v[k+1] sw sw $t2, 0($t1) $t0, 4($t1) # v[k] = $t2 {v[k+1]} # v[k+1] = temp jr $ra # "Return" Codice in MIPS - SWAP
sort: addi $sp, $sp, -20 sw $ra, 16($sp) sw $s3, 12($sp) sw $s2, 8($sp) sw $s1, 4($sp) sw $s0, 0($sp) move $s2, $a0 move $s3, $a1 move $s0, $zero # Allocate 5 places in the stack # $s2 = v # $s3 = len # i = 0 Codice in MIPS - SORT (Initialisation)
for1st: for2st: exit2: slt beq $t0, $s0, $s3 $t0, $zero, exit1 # if (i >= len) {$t0 = 0} # if ($t0 == 0) {goto exit1} addi $s1, $s0, -1 # j = i-1; slti bne $t0, $s1, 0 $t0, $zero, exit2 # if (j >= 0) {$t0 = 0} # if ($t0!= 0) {goto exit2} sll add lw lw slt beq $t1, $t2, $t3, $t4, $t0, $t0, # # # # # # move move $a0, $s2 $a1, $s1 # First argument = v # Second argument = j jal swap # Call swap(v, j) addi j $s1, $s1, -1 for2st # j-# Back at start of "j-for" addi j $s0, $s0, 1 for1st # i++ # $s1, 2 $s2, $t1 0($t2) 4($t2) $t4, $t3 $zero, exit2 $t1 = j * 4 Compute &v[j] $t3 = v[j] $t4 = v[j+1] if ($t4 < $t3) {$t0 = 1} if ($t0 == 0) {goto exit2} Back at start of "i-for" Codice in MIPS - SORT (For)
exit1: lw lw lw lw lw addi $sp, $s0, $s1, $s2, $s3, $ra, $sp, jr $ra 0($sp) 4($sp) 8($sp) 12($sp) 16($sp) 20 # Restore return address # Restore Stack Pointer # "Return" Codice in MIPS - SORT (Exit)
.data datarr:.word-37, 190, 214, -41, -65, 242, -62, 13, 197, 10.text main:la add jal $a0, datarr $a1, $zero, 10 sort nop nop # Load address for array # Set array length to 10 # Call sort(data, 10) # General Breakpoints #... # Le altre due chiamate quì sotto... Codice in MIPS - MAIN + DATA
UFF... È stata dura, ma se fate girare il programma in Assembly MIPS in QtSPIM e quello in C, dopo averlo passato per bene con le vostre skills da GCC HAXORZ vedrete che il risultato è lo stesso* * In C viene stampato a video, in QtSPIM viene modificato l array nella sezione.data
Una cosa, ladies and gentlemen... Il libro, nella sua tabella riassuntiva delle istruzioni fa DI TUTTO per essere confusionario (IMHO). La cosa da ricordare è: OP rd, rs, rt Non sapete quante volte ho fatto casino con l operatore slt.
Un esercizio: Vettori vs. Puntatori Per fare gli esercizi di Assembly è NECESSARIO che sappiate come funzionano i puntatori. Per iniziare proveremo a fare un esercizio dove dovrete inizializzare due vettori a 0 usando o l accesso ai vettori o l aritmetica dei puntatori.
void zeroes_vec (int32_t *vec, uint32_t len){ uint32_t i; for (i = 0; i < len; i++){ vec[i] = 0; } } void zeroes_point (int32_t *vec, uint32_t len){ int32_t *p; for (p = vec; p < &vec[len]; p++){ *p = 0; } } LOL PUNTATORI! - Il Codice in C
Try despair... (Non vi preoccupate, non sapevo neanche io cosa stavo facendo la prima volta.) OK, buon lavoro.
.data datarr: datarr2:.word -37, 190, 214, -41, -65, 242, -62, 13, 197, 10.word -37, 190, 214, -41, -65, 242, -62, 13, 197, 10.text main: la add $a0, datarr $a1, $zero, 10 # Load address for array # Set array length to 10 jal vecz # Call vecz(data, 10) la $a0, datarr2 # Load address for second array poiz # Call poiz(data2, 10) nop jal nop nop # General Breakpoints #... MGSV: Ground ZEROES - La Soluzione I
vecz: vecfor: sll move $t0, $zero $t1, $t0, 2 add $t2, $a0, $t1 sw $zero, 0($t2) addi $t0, $t0, 1 slt $t2, $t0, $a1 bne $t2, $zero, vecfor jr poiz: poifor: sll $ra move $t0, $a0 $t1, $a1, 2 add $t1, $a0, $t1 sw $zero, 0($t0) addi $t0, $t0, 4 slt $t2, $t0, $t1 bne $t2, $zero, poifor jr # i = 0 # $t0 = i * 4 # $t2 = &vec[i] # vec[i] = 0 # i++ # if (i < len) {$t2 = 1} # if ($t2!= 0) {goto vecfor} # p = vec # $t1 = len * 4 # $t1 = &vec[len] # *p = 0 # p++ # if (p < &vec[len]) {$t2 = 1} # if ($t2!= 0) {goto poifor} $ra ZEROES - La Soluzione II
Vi sentite già più tipo Gandalf Ed?
Fine, mi sa... Ora delle domande!