Матриці: два індекси, одна адреса
Матриця — це сітка чисел, розташованих у рядках і стовпцях. Рядок — це одна горизонтальна лінія сітки, яку читають зліва направо. Стовпець — це одна вертикальна лінія сітки, яку читають згори донизу. Пам'ять не має поняття рядків чи стовпців. Це одна довга лінія байтів, той самий вид вектора, що розглядався в попередньому уроці. Щоб зберегти матрицю, її рядки та стовпці мають бути розміщені один за одним у цій єдиній лінії. Звичайний вибір — порядок row-major: зберегти кожне число першого рядка, потім кожне число другого рядка, і продовжувати, доки кожен рядок не буде розміщено.
Два індекси, одна адреса
Позиція елемента в матриці задається двома індексами: індексом рядка, до якого він належить, та індексом стовпця, до якого він належить. Відлік обох починається з 0, так само як індекси працювали в уроці про вектори. Пам'ять зберігає одну плоску послідовність чисел, тому обидва індекси спершу потрібно об'єднати в один сплощений індекс: помножте індекс рядка на кількість стовпців матриці, потім додайте індекс стовпця. Звідти сплощений індекс стає байтовою адресою так само, як індекс вектора: address = base + index * 4.
mul t4, t1, t3 # t4 = індекс рядка * кількість стовпцівadd t4, t4, t2 # t4 = that + індекс стовпця (плаский індекс)slli t4, t4, 2 # t4 = зсув у байтах = індекс * 4add t5, t0, t4 # t5 = адреса елемента в цьому рядку та стовпціlw t5, 0(t5) # t5 = значення за цією адресою
множить індекс рядка на кількість стовпців. В уроці про вектори множення можна було виконати зсувом, бо 4 — степінь двійки, але кількість стовпців матриці зазвичай нею не є, тож тут використовується замість . Індекс стовпця додається, а результат масштабується на 4 за допомогою ще одного (4 — степінь двійки, тож зсув для цієї частини все ще працює). Це дає байтове зміщення елемента в заданому рядку та стовпці.
Рядок 0, стовпець 0 відповідає індексу 0.
.data-розкладка вашої програми та ваше власне її читання, використовуючи арифметику , і , показану вище. Щойно сітка та сплощений рядок розуміються як одна річ, показана двічі, той самий шаблон охоплює будь-яку сітку даних: рядки пікселів зображення, ігрове поле або електронну таблицю. Кожна з них — один масив, до якого доступаються з одним додатковим множенням.Підсумовування матриці
.datam: .word 1, 2, 3, 4, 5, 6, 7, 8, 9 # матриця 3x3, збережена рядок за рядком.textla t0, m # базова адресаli t1, 3 # кількість рядківli t2, 3 # кількість стовпцівli t3, 0 # поточний індекс рядка, починається з 0li s0, 0 # накопичувальна сумаrow_loop:beq t3, t1, row_doneli t4, 0 # поточний індекс стовпця, починається з 0col_loop:beq t4, t2, col_donemul t5, t3, t2 # індекс рядка * кількість стовпцівadd t5, t5, t4 # + індекс стовпця = сплющений індексslli t5, t5, 2 # зсув у байтах = індекс * 4add t6, t0, t5 # адреса елемента в цьому рядку та стовпціlw t6, 0(t6) # значення за цією адресоюadd s0, s0, t6 # total += елементaddi t4, t4, 1 # перейти до наступного стовпцяj col_loopcol_done:addi t3, t3, 1 # перейти до наступного рядкаj row_looprow_done:mv a0, s0 # вивести total: 1+2+...+9 = 45li a7, 1ecallli a7, 10ecall
Два вкладені цикли індексують матрицю. Зовнішній цикл вибирає рядок, а внутрішній вибирає стовпець у цьому рядку. множить індекс рядка на кількість стовпців. Додавання індексу стовпця та масштабування на 4 дає адресу цього елемента. Значення, збережене за цією адресою, завантажується й додається до поточної суми. Коли внутрішній цикл завершує рядок, зовнішній цикл переходить до наступного рядка, доки всі 3 рядки не буде оброблено.
