Почему 16-разрядные инструкции не могут получить доступ к старшим регистрам регистров общего назначения

#assembly #arm #cpu-registers #instruction-set #thumb

#сборка #arm #cpu-регистры #набор инструкций #большой палец

Вопрос:

Итак, прямо сейчас я читаю книгу «Окончательное руководство по ARM Cortex-M3 / M4» и не могу понять, почему 16-разрядные инструкции не могут получить доступ к старшим регистрам общего назначения R8-R12.

В нем говорится, что очень немногие из них действительно могут получить доступ к этим регистрам, но в основном нет.

Комментарии:

1. Если ваши инструкции имеют длину всего 16 бит, возможно кодирование 2-3 регистров операндов с 3-разрядными полями выбора регистра, но enocoding 2-3 регистра операндов с 4-разрядными полями выбора регистра.

2. Сохранение компактности за счет уменьшения кодов операций — это то, как Thumb-код может повысить производительность, особенно на машинах с ограниченным доступом к шине.

3. прежде чем читать подобную книгу, вам нужно фактическое окончательное руководство по arm (что угодно), которое является справочным руководством по архитектуре и техническим справочным руководством для рассматриваемого ядра (armv7-m для обоих), и там вы можете легко увидеть, что в кодировке для инструкций нет места для 4 бит на регистр.

Ответ №1:

16 бит означают, что команда машинного кода имеет только 16 бит для кодирования информации. для кодирования 8 регистров требуется 3 бита. Для кодирования 12 регистров требуется 4 бита. Затем нам нужно место для кодов операций и других параметров, что означает, что дополнительного бита может быть на один бит больше.

Комментарии:

1. И это предполагает инструкцию с одним регистром, такую как константа нагрузки. Для таких вещей, как арифметика, становится только хуже.

2. Почему для кодирования 8 регистров требуется 3 бита? Все регистры являются 32-разрядными. Не судите слишком строго, я только начал изучать архитектуру

3. @SL7Bot: вы должны назначить каждому регистру уникальный битовый шаблон, чтобы декодер команд знал, о каком регистре вы говорите. Для 8 уникальных битовых шаблонов вам нужно как минимум log_2 (8) = 3 бита. «Назначить уникальный битовый шаблон», конечно, в основном то же самое, что присвоить каждому регистру числовой адрес и кодировать это число в двоичном формате. Опять же: для кодирования чисел 0-7 вам нужно 3 бита.

4. Спасибо, это то, что я подумал. Теперь я понимаю

Ответ №2:

Кодирование адреса 8 регистров занимает 3 бита. Кодирование адреса 12 регистров занимает 4 бита.

Если у вас есть 3-регистровая инструкция, вам потребуется 12 бит для кодирования 3 регистров, что оставляет только 4 бита для инструкции. У вас может быть не более 16 инструкций.

Комментарии:

1. у вас все еще может быть один или несколько из этих 16 шаблонов, чтобы иметь кучу вложенных шаблонов, которые не используют три регистра. довольно часто, особенно для arm…

2. Инструкции Thumb в основном состоят из 2 операндов (например x ^= y , вместо z = x ^ y того, чтобы использовать инструкции в режиме ARM), за исключением нескольких очень распространенных инструкций, adds reg, reg, reg которые могут использовать 3 разных регистра в 16-разрядной инструкции. Но да, сохранение битов в номерах регистров по-прежнему имеет решающее значение.

Ответ №3:

Единственными фактическими окончательными руководствами по этим ядрам является документация arm. Прежде чем читать что-либо еще или изучать набор команд, вам необходимо ознакомиться с документацией; в данном случае, Справочное руководство по архитектуре ARM для ARMV7-m, а также техническое справочное руководство cortex-m3 или cortex-m4. Если в вашей книге содержится подобное утверждение и не объясняется, оно далеко от окончательного.

Это технически возможно, но это займет много места и, возможно, сведет на нет цель попытки выполнения 16-разрядных инструкций (не означает 16-разрядный процессор или регистры или что-то в этом роде, сами инструкции имеют 16 бит).). Если вы посмотрите на скомпилированный код и на то, как работают компиляторы, большая часть сгенерированного кода использует младшие регистры или может быть создана как таковая. Таким образом, это компромисс между богатством набора команд и количеством инструкций, что верно независимо от того, сколько у вас регистров.

Размер регистра не имеет значения, важно количество регистров. Для того, чтобы, например

 add r1,r2,r3
  

Вы где-то должны кодировать, какой регистр какой. Комментарий, конечно, относится к старым / оригинальным 16-разрядным инструкциям, а не к расширениям thumb2.

Итак, вам нужен шаблон, естественно, можно было бы:

 000 r0
001 r1
010 r2
011 r3
100 r4
101 r5
110 r6
111 r7
  

Если вы ограничиваете себя 8 регистрами, вам нужно всего три бита на регистр, чтобы описать, какой регистр используется для каждого поля.

Если вы хотите использовать 16 регистров в своих инструкциях, вам нужно 4 бита:

 0000 r0
0001 r1
0010 r2
....
0111 r7
1000 r8
1001 r9
....
1110 r14
1111 r15
  

Если вы хотите, чтобы в вашем наборе команд было 32 регистра (обычно не ARM thumb), тогда пять бит:

 00000 r0
00001 r1
10000 r16
11111 r31
  

Примечание

 2 to the power 0 is 1
2 to the power 1 is 2
2 to the power 2 is 4
2 to the power 3 is 8
2 to the power 4 is 16
2 to the power 5 is 32
2 to the power 16 is 65536
  

и так далее.

Если вы хотите описать 8 вещей, требуется 3 бита, если вы хотите описать 16 вещей, требуется 4 бита.

16 бит означает потенциально 65536 уникальных инструкций. Документ ARM хорошо показывает, как он раскладывает свои наборы команд, он склоняется к максимизации количества и возможных функций инструкций по сравнению с, скажем, MIPS, который сначала склоняется к простоте логики декодирования, а затем ко второму (компромиссы в дизайне).

Пропуск вперед, например, верхние 6 бит инструкции являются кодом операции

 00xxxx shift, add, subtract, move, and compare
010000 data processing instructions
010001 special data
01001x ...
  

и так далее. Показано по-разному в зависимости от того, какой ARM ARM вы загружаете.

Им не нужно было реализовывать какие-либо три инструкции регистра, но они решили. Если бы эти инструкции поддерживали r0-r15 для каждого операнда, то это означает, что требуется 12 бит, а для кодирования остается четыре бита, включая один или несколько из них, чтобы указать этот класс инструкций, а остальные — какой операнд, вы, вероятно, уничтожили бы по крайней мере половину возможных инструкций (один бит, выделенный дляуказывает, является ли это трехрегистрационной инструкцией или нет), оставляя 7 возможных операций или одну четверть пространства команд (два бита), оставляя 2 бита для выбора операнда, что делает его не очень многофункциональным. Вместо этого они фактически заняли 1/4 часть пространства команд, но оставили не менее 5 бит для операнда и / или других функций (немедленных и т. Д.).

Таким образом, кодировка T1 для add равна

 0001100mmmnnnddd
  

Два верхних бита указывают, какая это группа инструкций, если вы посмотрите, вы увидите, что бит 10 указывает немедленный или регистровый биты mmm — это регистр или немедленное значение между 0 и 7, часто программист хочет увеличить на 1 или 2 или какое-то небольшое число, и ему приходитсяпринудительно выполнить инструкцию и записать регистр, чтобы поместить это небольшое число, а компромисс с записью некоторого пространства команд — это баланс здесь.

В любом случае, здесь вы видите, что для регистров rm, rn и rd для этой кодировки инструкций есть три бита. (добавьте rd, rn, rm), и это указывает, что r0-r7 возможно для любого из этих полей.

Чтобы сделать его более полным, существует инструкция mov high register, которая позволяет вам перемещать high / low, low / high или high / high, технически low / low, но они предпочитают, чтобы вы использовали другую кодировку, как указано в документации. Одним из них может быть add rd, rn, # 0, относящийся к трем указанным выше регистрам. И это то, что вы видите, что делает gnu assembler

 .thumb
mov r1,r2
mov r10,r2
mov r1,r11
mov r10,r11
    
00000000 <.text>:
   0:   1c11        adds    r1, r2, #0
   2:   4692        mov r10, r2
   4:   4659        mov r1, r11
   6:   46da        mov r10, r11
  

Суть в том, что есть способ перехода к старшим регистрам и обратно, который быстрее, чем в / из стека (без цикла памяти), поэтому компилятор все равно может выбрать использование одного / нескольких старших регистров (понимая, что push / pop ограничен по очевидным причинам (читайте документы), поэтому нет необходимостиесть ли затраты на их сохранение и восстановление, это компромисс).

Поэтому вы должны придерживаться фактического окончательного руководства по чему-то, а не того, что претендует на это.

Единственное, что вы почти никогда нигде не найдете, если только вы не оказались в мозге / кубе / офисе / конференц-зале в тот момент (ы), когда дизайнер (ы) внедрил набор команд или конкретную инструкцию, — это «почему» они это сделали. (почему нет трех регистров и, xor и т. Д.) Итак, несмотря на другие ответы, комментарии и выше, это потому, что они этого хотели. И если вам нужно знать больше, вы, возможно, можете получить работу в arm, и, возможно, они все еще там и могут проводить с вами время, но я бы ожидал, что они уйдут на пенсию.

И прошло так много времени, что ответ от вовлеченных сторон, вероятно, будет отличаться в зависимости от того, кто что и когда сказал все эти годы назад. Но при попытке взять 32-разрядный набор команд и сопоставить подмножество с 16-разрядными инструкциями, чтобы удвоить количество инструкций на единицу пространства, пытаясь при этом быть достаточно богатым, чтобы не сильно увеличивать количество инструкций на задачу, ограничивая большинство инструкций нижними регистрами общего назначения для архитектуры, подобнойэто кажется очевидным выбором дизайна. Мне пришлось бы пересмотреть MIPS, эквивалентный thumb, чтобы посмотреть, что они сделали, я бы ожидал, что они сделали то же самое. Аналогично, мне также пришлось бы пересмотреть risc-v и любой другой, который сделал то же самое.

Поймите, это был выбор дизайна, а не требование в любом случае.