Почему регистр ARM PC указывает на инструкцию после следующей, которая должна быть выполнена?
По данным АРМ СК.
В состоянии ARM значение ПК - это адрес текущей инструкции плюс 8 байтов.
В состоянии большого пальца:
- Для команд B, BL, CBNZ и CBZ значением ПК является адрес текущей инструкции плюс 4 байта.
- Для всех других команд, использующих метки, значение ПК - это адрес текущей инструкции плюс 4 байта, причем бит [1] результата очищается до 0, чтобы выровнять его по слову.
Проще говоря, значение регистра ПК указывает на инструкцию после следующей инструкции. Это то, что я не понимаю. Обычно (особенно в x86) регистр счетчика программ используется для указания адреса следующей команды, которая должна быть выполнена.
Итак, какие предпосылки лежат в основе этого? Условное исполнение, может быть?
2 ответа
Это неприятная утечка устаревшей абстракции.
Первоначальный проект ARM имел трехступенчатый конвейер (fetch-decode-execute). Чтобы упростить конструкцию, они предпочли, чтобы ПК считывался как значение, которое в настоящее время находится в адресных строках выборки команд, а не как значение текущей выполняемой инструкции от 2 циклов назад. Поскольку большинство относительных к ПК адресов рассчитывается во время соединения, ассемблеру / компоновщику легче компенсировать это смещение из двух команд, чем спроектировать всю логику для "исправления" регистра ПК.
Конечно, это все твердо на куче "вещей, которые имели смысл 30 лет назад". А теперь представьте, что нужно для того, чтобы сохранить значимую ценность в этом регистре на сегодняшних 15+ этапных конвейерах с несколькими выпусками, вышедшими из строя, и вы, возможно, поймете, почему в наши дни трудно найти дизайнера ЦП, который думает, что компьютер выглядит как регистр это хорошая идея.
Тем не менее, с другой стороны, это не так ужасно, как слоты задержки. Вместо этого, вопреки тому, что вы предполагаете, выполнение каждой инструкции условно было на самом деле просто еще одной оптимизацией для этого смещения предварительной выборки. Вместо того, чтобы всегда принимать задержки конвейерной очистки при переходе по условному коду (или все равно выполнять то, что осталось в канале, как сумасшедший), вы можете полностью избежать очень коротких переходов; конвейер остается занятым, и декодированные инструкции могут просто выполняться как NOP, когда флаги не совпадают*. Опять же, в наши дни у нас есть эффективные предсказатели ветвлений, и в конечном итоге это скорее препятствие, чем помощь, но для 1985 года это было круто.
* "... набор инструкций с наибольшим количеством NOP на планете."
это правда...
один пример ниже: программа C:
int f,g,y;//global variables
int sum(int a, int b){
return (a+b);
}
int main(void){
f = 2;
g = 3;
y = sum(f, g);
return y;
}
скомпилировать в сборку:
00008390 <sum>:
int sum(int a, int b) {
return (a + b);
}
8390: e0800001 add r0, r0, r1
8394: e12fff1e bx lr
00008398 <main>:
int f, g, y; // global variables
int sum(int a, int b);
int main(void) {
8398: e92d4008 push {r3, lr}
f = 2;
839c: e3a00002 mov r0, #2
83a0: e59f301c ldr r3, [pc, #28] ; 83c4 <main+0x2c>
83a4: e5830000 str r0, [r3]
g = 3;
83a8: e3a01003 mov r1, #3
83ac: e59f3014 ldr r3, [pc, #20] ; 83c8 <main+0x30>
83b0: e5831000 str r1, [r3]
y = sum(f,g);
83b4: ebfffff5 bl 8390 <sum>
83b8: e59f300c ldr r3, [pc, #12] ; 83cc <main+0x34>
83bc: e5830000 str r0, [r3]
return y;
}
83c0: e8bd8008 pop {r3, pc}
83c4: 00010570 .word 0x00010570
83c8: 00010574 .word 0x00010574
83cc: 00010578 .word 0x00010578
см. приведенное выше значение LDR для ПК - здесь используется для загрузки адреса переменной f,g,y в r3.
83a0: e59f301c ldr r3, [pc, #28];83c4 main+0x2c
PC=0x83c4-28=0x83a8-0x1C = 0x83a8
Значение ПК - это просто следующая инструкция текущей текущей инструкции. так как ARM использует 32-битную инструкцию, но использует байтовый адрес, так что + 8 означает 8 байтов, длину двух инструкций.
5-ступенчатый конвейер ARM archi linefetch, декодирование, выполнение, память, обратная запись
Пятиступенчатый трубопровод ARM
регистр ПК добавляется на 4 каждые часы, поэтому, когда инструкция выпадает, текущая инструкция, регистр ПК уже прошел 2 такта! теперь это + 8. это на самом деле означает: ПК указывает на инструкцию "выборка", текущая инструкция означает инструкцию "выполнить", поэтому ПК означает выполнение следующей следующей.
Кстати: картинка из книги Харриса по цифровому дизайну и компьютерной архитектуре ARM Edition