Matrici: due indici, un indirizzo
Una matrice è una griglia di numeri disposti in righe e colonne. Una riga è una linea orizzontale della griglia, letta da sinistra a destra. Una colonna è una linea verticale della griglia, letta dall'alto verso il basso. La memoria non ha alcun concetto di righe o colonne. È una lunga sequenza di byte, lo stesso tipo di vettore trattato nella lezione precedente. Per memorizzare una matrice, le sue righe e colonne devono essere collocate una dopo l'altra in quell'unica sequenza. La scelta usuale è l'ordine row-major: memorizzare ogni numero della prima riga, poi ogni numero della seconda riga, e continuare finché ogni riga è stata collocata.
Due indici, un unico indirizzo
La posizione di un elemento in una matrice è data da due indici: l'indice di riga, a quale riga appartiene, e l'indice di colonna, a quale colonna appartiene. Il conteggio per entrambi inizia da 0, allo stesso modo in cui funzionavano gli indici nella lezione sui vettori. La memoria contiene un'unica sequenza piatta di numeri, quindi i due indici devono prima essere combinati in un unico indice appiattito: moltiplicare l'indice di riga per il numero di colonne della matrice, poi aggiungere l'indice di colonna. Da lì l'indice appiattito diventa un indirizzo di byte allo stesso modo dell'indice di un vettore: address = base + index * 4.
mul t4, t1, t3 # t4 = indice di riga * numero di colonneadd t4, t4, t2 # t4 = quello + indice di colonna (l'indice appiattito)slli t4, t4, 2 # t4 = offset in byte = indice * 4add t5, t0, t4 # t5 = indirizzo dell'elemento a questa riga e colonnalw t5, 0(t5) # t5 = valore a quell'indirizzo
moltiplica l'indice di riga per il numero di colonne. Nella lezione sui vettori la moltiplicazione poteva essere fatta con uno scorrimento perché 4 è una potenza di due, ma il numero di colonne di una matrice di solito non lo è, quindi qui viene usato invece di . L'indice di colonna viene aggiunto, e il risultato viene scalato per 4 con un altro (4 è una potenza di due, quindi uno scorrimento funziona ancora per questa parte). Questo produce l'offset in byte dell'elemento alla riga e colonna date.
Riga 0, colonna 0 corrisponde all'indice 0.
.data del tuo programma e la tua stessa lettura di esso impongono a quell'unica riga, usando l'aritmetica , e mostrata sopra. Una volta che la griglia e la riga appiattita sono comprese come una sola cosa mostrata due volte, lo stesso schema copre qualsiasi griglia di dati: le righe di pixel di un'immagine, un tabellone di gioco o un foglio di calcolo. Ognuno è un array, raggiunto con una moltiplicazione in più.Somma di una matrice
.datam: .word 1, 2, 3, 4, 5, 6, 7, 8, 9 # matrice 3x3, memorizzata riga per riga.textla t0, m # indirizzo baseli t1, 3 # numero di righeli t2, 3 # numero di colonneli t3, 0 # indice di riga corrente, inizia da 0li s0, 0 # totale correnterow_loop:beq t3, t1, row_doneli t4, 0 # indice di colonna corrente, inizia da 0col_loop:beq t4, t2, col_donemul t5, t3, t2 # indice di riga * numero di colonneadd t5, t5, t4 # + indice di colonna = indice appiattitoslli t5, t5, 2 # offset in byte = indice * 4add t6, t0, t5 # indirizzo dell'elemento a questa riga e colonnalw t6, 0(t6) # valore a quell'indirizzoadd s0, s0, t6 # totale += elementoaddi t4, t4, 1 # passa alla colonna successivaj col_loopcol_done:addi t3, t3, 1 # passa alla riga successivaj row_looprow_done:mv a0, s0 # stampa il totale: 1+2+...+9 = 45li a7, 1ecallli a7, 10ecall
Due cicli annidati indicizzano la matrice. Il ciclo esterno seleziona una riga e il ciclo interno seleziona una colonna all'interno di quella riga. moltiplica l'indice di riga per il numero di colonne. Aggiungere l'indice di colonna e scalare per 4 dà l'indirizzo di quell'elemento. Il valore memorizzato a quell'indirizzo viene caricato e aggiunto al totale corrente. Quando il ciclo interno termina una riga, il ciclo esterno passa alla riga successiva, finché tutte e 3 le righe sono state elaborate.
