Компилятор cc21k предполагает регистров процессоров для различных целей. В соответствии с этими целями и правилами модификации этих регистров подпрограммами пользователя (на ассемблере) регистры можно разделить на следующие категории:
- регистры компилятора (Compiler Registers), которые используются компилятором для собственных целей и должны содержать указанные в таблице значения. Не следует изменять значения этих регистров, так как компилятор предполагает, что эти регистры всегда имеют значения, приведенные в таблице. Дополнительно следует отметить, что все L-регистры (кроме L6 и L7) должны быть равны 0 в любой точке вызова процедуры и возврата из процедуры. Если какой-либо из L-регистров был модифицирован, то при вызове функции или возврате управления в вызывающую подпрограмму, его следует обнулить. Подпрограммы – обработчики прерываний должны сохранять (в памяти) и сбрасывать L-регистры в 0 до использования соответствующих им I-регистров для любых инструкций с пост-модификацией.
Регистр | Значение | Правило использования |
M5, M13 | Не модифицировать | |
M6, M14 | Не модифицировать | |
M7, M15 | -1 | Не модифицировать |
B6, B7 | база стека | Не модифицировать |
L6, L7 | длина стека | Не модифицировать |
L0, L1, L2, L3, L4, L5, L8, L9, L10, L11, L12, L13, L14, L15 | Доступны для временного использования. После использования – восстановить |
- регистры, зарегистрированные пользователем (User Registers), задание (перечисление) которых в опциях компилятора вынуждает компилятор отказаться от использования этих регистров. Если же компилятору не будет хватать регистров, он проигнорирует запрет на их использование. Следует заметить, что "заказ" регистра L, требует резервирования соответствующего I-регистра и наоборот, в противном случае возможны ошибки на этапе выполнения. Чем больше зарезервировано регистров для пользовательских целей, тем ниже может оказаться "качество" кода, сгенерированного компилятором;
Регистр | Значение | Правило использования |
i0, n0, l0, m0, i1, b1, l1, m1, i8, b8, l8, m8, i9, b9, l9, m9, mrb, ustat1, ustat2, ustat3, ustat4 | Задается пользователем | Если не зарезервированы явно, то можно использовать для временного пользования, а по окончании восстановить прежние значения. Если явно зарезервированы под пользовательские цели в опциях компилятора, то можно использовать без ограничения. |
- регистры, сохраняемые при вызове (Call Preserved Registers), представляют собой набор регистров, которые должны быть сохранены в "прологе" функции и затем восстановлены в "эпилоге" функции, если эта функция написана на ассемблере. Естественно, что если функция не изменяет регистры данной группы, то сохранять и восстанавливать их необязательно. При этом, если используется сохраняемый при вызове I-регистр, то необходимо сохранить (и затем восстановить) не только этот I-регистр, но и соответствующий ему L-регистр. Значительная часть библиотечных функций работает в предположении, что процессор работает в определенном режиме, определяемом, в частности, регистрами параметром и управления. Если эти значения будут изменены и затем выполнен вызов стандартной функции, то результат ее работы будет непредсказуем. Поэтому при необходимости изменения режимов работы процессора (регистры MODE1 и MODE2) "хорошим тоном" считается сохранение их старых значений и их восстановление при вызове другой функции и при возврате в вызывающую функцию.
B0, B1, B2, B3, B5, B8, B9, B10, B11, B14, B15 |
I0, I1, I2, I3, I5, I8, I9, I10, I11, I14, I15 |
MODE1, MODE2 |
MRB, MRF |
M0, M1, M2, M3, M8, M9, M10, M11 |
R3, R5, R6, R7, R9, R10, R11, R13, R14, R15 |
USTAT1, USTAT2 |
По умолчанию run-time окружение С/С++ предполагает, что режим процессора определяется задается следующими установками (задача обеспечить эти установки ложится на инициализационный код):
а) не используется бит-реверсная адресация;
б) используется основной (не теневой) набор регистров;
в) используется точность.PRESICION=32 (32-битовые ПЗ-числа) и режим округления до ближайшего целого;
г) запрещено насыщение АЛУ (бит ALUSAT=0);
д) для ADSP-2116x разрешены циклические буферы (бит CBUFEN=1 в регистре MODE1);
- временные или рабочие регистры (Scratch Registers) не требуют сохранения и восстановления, изменение их содержимого при вызове функций или вставке ассемблерного кода не "волнует" компилятор. К таким регистрам относятся:
B4, B12, B13 |
R0, R1, R2, R4, R8, R12 |
I4, I12, I13 |
M4, M12 |
PX |
Для процессора ADSP-2116x все регистры данных процессорного элемента PEy являются Scratch-регистрами;
- отдельный набор регистров (Stack Registers) резервируется и всегда используется для работы со стеком. Подпрограммы на ассемблере должны строго выполнять правила работы с ними, приведенные в таблице.
Регистр | Значение | Правило использования |
I7 | Указатель стека (Stack Pointer) | Модифицируется при работе со стеком, восстановить при возврате из подпрограммы |
I6 | Указатель фрейма стека (Frame Pointer) | Модифицируется при работе со стеком, восстановить при возврате из подпрограммы |
I12 | Адрес возврата | Загружается адресом возврата при выходе из функции |
- альтернативные регистры (Alternate Registers) не используются средой выполнения и доступны для использования в ассемблерных подпрограммах. Однако при их использовании следует учитывать, что при переключении регистров I6 и I7 (DAG1) на теневой набор может быть нарушена работа со стеком. Поэтому при использовании теневых регистров, особенно I6/I7 прерывания должны быть запрещены. Кроме того, самый быстрый диспетчер прерываний (super fast interrupt dispatcher) для переключения контекста сам использует теневые регистры вместо сохранения регистров в стеке среды выполнения. Поэтому во избежание конфликтов желательно не применять данный вид диспетчера прерываний при использовании теневых регистров в ассемблерных вставках.