nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

XCHG, QuatCore-style

Одна из самых частых операций: поменять местами значения двух переменных. Уж сколько всего напридумывали для этого:
- использовать третью переменную в качестве временной,
 t = x;
 x = y;
 y = t;

(или то же самое в ассемблере на MOV)

- хитрые битовые трюки с XOR или с арифметикой (сложение и вычитание)
- специальная команда XCHG (exchange). Но она есть только в x86, и распадается на отдельные микрооперации, и не факт, что она быстрее трёх отдельных mov. (Говорят о всяких хитростях с "блокировкой памяти", чтобы операция заведомо была атомарной в многопоточной среде, а каждая такая блокировка вещь дорогостоящая). В ARM'ах, правда, была SWP (SWAP), которая сейчас объявлена Deprecated, но и до того её использование рекомендовалось только для семафоров, где опять же нужна атомарность.

А как с этим обстоят дела в QuatCore? Легко! Например, чтобы поменять местами регистры X и Y, мы пишем:
X   Y
%CheckHazards	OFF
Y   X
%CheckHazards	ON


Код занимает 2 слова, выполняется за 2 такта, и не требует никаких дополнительных переменных!


Думаю, тем, кто лезет под кат, уже понятно, как это происходит.

Правая часть команды (SrcAddr) выполняется на такт раньше, чем левая. Поэтому сначала на шину данных поступает значение Y, и защёлкивается в регистре внутри QuatCoreSrcMux, чтобы на следующем такте этим значением занялась бы левая часть команды.

На следующем такте и в левой, и в правой части выполняется одна и та же команда, "X". В левой части в регистр X заносится новое значение из шины данных, то есть значение Y. Но "защёлкивание" произойдёт только по фронту тактового импульса. А в правой части на шину данных поступает текущее значение регистра X, и оно "защёлкнется" на регистр шины данных тоже лишь по фронту тактового импульса. "Раньше времени" перемениться оно не может, на этом зиждется вся синхронная логика! Обычно такое поведение противоречит идеологии программирования, когда СРАЗУ ЖЕ по окончании присваивания переменная (регистр) приобретает новое значение, именно поэтому, не будь директивы %CheckHazards OFF, компилятор вставил бы дополнительный NOP, чтобы новое значение успело защёлкнуться в X, прежде чем мы им воспользуемся.

И наконец, последним этапом значение из шины данных (старое значение регистра X) будет занесено в регистр Y.

Схожим образом мы можем поменять местами содержимое регистра и памяти, но только если это не регистр Acc. В Acc стоит своя собственная блокировка, задерживающая получение Acc на один такт, если в этот самый момент идёт другая операция с АЛУ. И если мы хотим менять местами регистр и память, то одновременное чтение и запись нужно делать именно регистру.

А вот обменять между собой две переменные из памяти, боюсь, не получится. Так-то у нас память ДВУХПОРТОВАЯ - допускает одновременное чтение из памяти и запись в неё же. Другое дело, что мы возможности этой двухпортовости основательно зарезали, поставив только один формирователь эффективного адреса. Но здесь само собой получится, что адрес у нас ОДИН, поэтому могло бы "прокатить", если бы не одно "НО": если не ошибаюсь, в моей ПЛИС 5576ХС4Т, как и в Flex10k, стоят блоки памяти m512, у которых в ситуации Read-During-Write (RDW, одновременное чтение и запись) новое значение "проскакивает" на выход сразу же. Оно, в принципе, понятно: память собирать из двухступенчатых триггеров (мастер-помощник, они же Master-Slave, или как их нынче называли в эпоху BLM?) слишком затратно да и не шибко нужно. Хотя в новых ПЛИС как-то умудряются дать разработчикам выбор, что должно происходить при RDW.


Хотя можно свой собственный "костыль" сделать, когда при совпадении левой и правой части команды запись будет задержана на один такт - вот тогда всё получится "в лучшем виде".

В конце концов, в аффинном алгоритме у нас была процедура SwapPoints, которой такая вещь пойдёт на пользу, сократит аж на 1 слово.


Мало того, можно три значения циклически обменять без вспомогательного регистра. Например, мы хотим, чтобы X принял значение Y, Y - значение Z, а в Z отправилось старое значение X. Вот так:

X    Y
%CheckHazards	OFF
Z    X
Y    Z
%CheckHazards	ON


Забавная штука - с марта вожусь с этим "разогнанным QuatCore", но только сегодня дошло что "так можно было" :)

Может, стоит какой-то удобный синтаксис придумать. Возможно, макрос какой.
Tags: ПЛИС, программки, работа, странные девайсы
Subscribe

  • Нахождение двух самых отдалённых точек

    Пока компьютер долго и упорно мучал симуляцию, я пытался написать на ассемблере алгоритм захвата на ближней дистанции. А сейчас на этом коде можно…

  • Слишком общительный счётчик

    Вчера я чуть поторопился отсинтезировать проект,параметры не поменял: RomWidth = 8 вместо 7, RamWidth = 9 вместо 8, и ещё EnableByteAccess=1, чтобы…

  • Балансируем конвейер QuatCore

    В пятницу у нас всё замечательно сработало на симуляции, первые 16 миллисекунд полёт нормальный. А вот прошить весь проект на ПЛИС и попробовать "в…

  • Ковыряемся с сантехникой

    Наконец-то закрыл сколько-нибудь пристойно трубы, подводящие к смесителю, в квартире в Москве: А в воскресенье побывал на даче, там очередная…

  • Мартовское велосипедное

    Продолжаю кататься на работу и с работы на велосипеде, а также в РКК Энергию и на дачу. Хотя на две недели случился перерыв, очередная поломка,…

  • Обнаружение на новом GPU - первые 16 мс

    Закончилась симуляция. UFLO и OFLO ни разу не возникли, что не может не радовать. За это время мы дошли до строки 0x10F = 271. Поглядим дамп памяти:…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 9 comments