Non abbiamo bisogno di una PSP per testare il codice
Transcript
Non abbiamo bisogno di una PSP per testare il codice
SPIM e MIPS Non abbiamo bisogno di una PSP per testare il codice Michele “Jazzinghen” Bianchi Interessi: Game Design, Embedded Systems eMail: [email protected] 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!