Imax9
NEWS   ARTICLES   MINIMIG   FILES   ABOUT

Эволюция ISA…

Предлагаю вам перевод цикла The EightThirtyTwo ISA Part 6: Evolving the ISA… автора Alastair M. Robinson.

В моих детских шагах к рабочему бэкэнду VBCC у меня теперь есть достаточно полный функционал, по крайней мере, для того чтобы отправить текст “Hello world!” в UART. Еще предстоит пройти долгий путь, прежде чем он (а) заработает и (б) создаст код, который даже отдаленно эффективен, но это только начало. В процессе я нашел и устранил некоторые недостатки в ISA, а также внес несколько изменений в набор команд и кодирование.

Самое главное, что для кода C на процессоре с относительно небольшим количеством регистров крайне важно, чтобы значения могли эффективно проиндексированы в фрейме стека. Eighthirtytwo ISA не был хорошо настроен для этого. Первоначально я рассматривал возможность придания r5 особого значения в качестве индексного регистра и связанного с каждой инструкции “load indexed” и “store indexed”, что добавляло бы r5 к выбранному регистру для создания эффективного адреса, но это оказалось неуклюжим и неэлегантным.

Я уже решил включить инструкцию “addt”, а также “add”. Эти инструкции будут одинаковыми, за исключением того, что “addt” помещает результат во временный регистр вместо выбранного регистра. Мой первоначальный план состоял в том, чтобы сделать эту особенность специально для r7, чтобы “addt r[0-6]” выполнял простое сложение, помещая результат в temp, но “addt r7” помещал результат в r7, а старое содержимое r7 + 1 в регистр temp. Это фактически станет инструкцией “jsr”, использующей temp в качестве регистра ссылок; подпрограмма сохраняет temp в стеке и извлекает его в r7, когда она завершается.

[С тех пор я заметил, что особый вариант “addt r7” делает его полезным для вычисления относительных адресов переменных ПК, поэтому вместо этого я буду использовать особый вариант “add r7”, чтобы поместить старое значение + 1 в temp. Возможно, это имеет больше смысла в любом случае, поскольку в этом случае мы просто добавляем функциональность для особого варианта, а не полностью меняем его.]

Однако мне пришло в голову, что я смогу лучше использовать “addt”, если смогу загружать и хранить, используя временный регистр в качестве адреса, вместо того, чтобы использовать выбранный регистр, поэтому я определил инструкцию загрузки и хранения для этой цели. Вместе с addt они образуют небольшой кластер инструкций, которые работают в направлении, противоположном основному набору инструкций. Поскольку мы вряд ли будем использовать вычисленный адрес во второй раз до того, как он будет вытеснен из temp, я определил только предварительные и постинкрементные версии этих инструкций загрузки и хранения, поскольку это наиболее полезно при работе со стеком. С помощью этих инструкций мы теперь можем сохранять и восстанавливать регистры в функции prologue / epilogue, не сортируя каждый из них по очереди во временный регистр, как это:

function:
  exg r6 // Адрес возврата в temp
  stmpdec r6 // записать адрес возврата
  stmpdec r1
  stmpdec r2
  stmpdec r3
  stmpdec r4
  mr r6 // запись адреса возврата и четырез регистров - 7 байт.
...
  li 24
  addt r6
  ldtmpinc r1 // Загрузить значения 24 последних байт стека - 3 байта.
...
  mt r6
  ltmpinc r4
  ltmpinc r3
  ltmpinc r2
  ltmpinc r1
  ltmpinc r6
  exg r6
  mr r7 // Восстановить четыре регистра, и перейти на адрес возврата - 8 байт

Я также понял, что мне нужно иметь дело с разницей между сравнениями со знаком и без знака: хотя двоичная арифметика одинакова для двух, семантика операндов будет определять, какой из них мы считаем большим, и, следовательно, как мы интерпретируем бит переноса/заёма. Мне пришло в голову, что если я добавлю инструкцию “sgn”, которая устанавливает флаг, заставляющий следующее сравнение рассматриваться как со знаком, я могу использовать этот флаг и в других контекстах. Например, я могу использовать его, чтобы указать, что сдвиг следует рассматривать как арифметический, а не логический – таким образом, устраняя необходимость иметь инструкции “asr” и “lsr” – или, возможно, указывая, что байтовые или полусловные загрузки должны быть расширены со знаком.

Еще одна вещь, которая поразила меня, заключается в том, что, поскольку r7 является счетчиком программ, многие инструкции никогда не будут использоваться с r7 в качестве операнда – например, “and”, “or”, “xor”, “ror”, “shl”, “shr” и некоторые другие, я мог бы потенциально перегрузить эти коды операций, предоставив мне потенциальное пространство для кодирования некоторых инструкций с нулевым операндом, таких как предлагаемая инструкция “sgn”, упомянутая выше.

Набор инструкций в его нынешнем виде выглядит следующим образом:

Инструкции перемещения:

Инструкции с памятью загрузки/сохранения:

Арифметические инструкции:

Побитовые/Логические инструкции:

Прочие инструкции:

Без операнда, перегружаемые инструкции:

В следующий раз я посмотрю на сделанный вручную ассемблерный код EightThirtyTwo…


Адрес для контактов : imax9@narod.ru

Если вам понравились мои работы и вы желаете поддержать сайт - сделайте дотацию.

При копировании статьи – обязательна ссылка на авторство и источник. Без разрешения автора копирование запрещено.

© Максим Ильин 2022г.

Яндекс.Метрика