Русский
Русский
English
Статистика
Реклама

Rtl

Аппаратная реализация алгоритмов DES и TDES-EDE3

10.12.2020 14:11:17 | Автор: admin

История

Алгоритм TDES (3DES, Tripple DES) был создан в 1978 году как улучшение алгоритма DES. По сравнению с последним улучшилась криптостойкость, но в три раза увеличилось время вычисления. Несмотря на то, что на сегодняшний день наиболее распространен алгоритм AES, который принят в качестве стандарта шифрования правительством США, алгоритм TDES широко используется. Например, даже сейчас его можно встретить в системных продуктах компании Microsoft.

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

Зачем я решил это сделать и описать

Действительно, эти алгоритмы уже очень глубоко исследован и не раз был описан и написан. Однако, когда я знакомился с этой темой и первый раз ради опыта решил реализовать этот алгоритм, я столкнулся с тремя проблемами. Во-первых, его аппаратная реализация ни разу не описывалась в русскоязычном пространстве, так что я решил заполнить этот пробел своей статьей. Во-вторых, большинство англоязычных статей на эту тему написаны для реализации на ПЛИС с использованием строенных ROM блоков памяти, а меня интересовала именно реализация "для кремния". И в-третьих большинство авторов приводят только часть исходного кода, но целиком исходников не так много. При этом написание этого модуля не является сложной логической задачей, но нужно безошибочно перенести все таблицы и преобразования в код. Так что отлавливать ошибки довольно рутинная и долгая задача.

Так же интересной задачей является написание тестовых векторов, которые при небольшом количестве смогли бы покрыть большую часть блока. Тестовые векторы для DES найти можно, например в [1], а вот для TDES-EDE3 мне найти ничего не удалось.

Описание алгоритма DES

Рис. 1. Схема шифрования DESРис. 1. Схема шифрования DES

Начать знакомство с алгоритмом TDES необходимо с алгоритма DES. Приведу его краткое описание с нужными мне обозначениями.

DES является симметричным блочным алгоритмом с блоком размером 64 бит и ключом длинной 56 бит (либо расширенным ключом длинной 64 бит). Все таблицы преобразований и перестановок в удобном виде находятся в excel файле на моем гитхабе. Алгоритм шифрования представлен на рисунке 1 и состоит из следующих этапов:

  • Начальная перестановка IP. На этом этапе исходный блок размера 64 бит преобразуется в блок T такого же размера при помощи перестановки IP.

  • 16 раундов шифрования. Входной блок T0 разбивается на старшую часть L0 и R0. Далее вычисления задаются рекуррентным соотношением:

    \begin{equation} \begin{gathered} L_{i} = R_{i-1} \\ R_{i} = L_{i-1} \oplus f(R_{i-1}, k_i), \end{gathered} \end{equation}
  • Генерирование ключей ki. В первую очередь исходный ключ расширяется добавлением бит в позиции 8, 16, 24, 32, 40, 48, 56, 64 таким образом, чтобы каждый байт содержал нечетное число единиц. Хотя на практике обычно все устроено наоборот. На вход подается уже расширенный 64-битный ключ, из которого потом выбираются значимые 56 бит. Это используется для обнаружения ошибок при передаче ключей, если такое необходимо. Далее, производится перестановка KI согласно таблице (она записана для 64-битного ключа), причем добавленные биты в перестановке не участвуют. Полученный блок делится на старшую и младшую части размером 28 бит. Для получения следующего ключа используется циклическая перестановка влево значений внутри каждой части на величину, зависящую от номера раунда: для первого, второго, девятого и шестнадцатого раундов происходит перестановка на два, для всех остальных на один.

    Сам же ключ имеет длину 48 бит и выбирается из 56 битного вектора согласно преобразования KO.

  • Вычисление функции f. Аргументами функции f являются 32-битовый вектор R(i-1) и 48-битный ключ ki. Для вычисления функции f последовательно используются:

    • Функция расширения E. Расширяет 32-битовый вектор R(i-1) до 48 бит согласно таблице преобразования E.

    • Xor с ключом.

    • Преобразование S. Полученный вектор делится на 8 блоков по 6 бит каждый. Каждый из восьми блоков преобразуется согласно S-таблицам. Пара старший и младший бит из блока определяют столбец, остальные четыре бита определяют строку.

    • Перестановка P. Производится перестановка согласно таблице P. В результате получается вектор длинной 32 бита.

  • Конечная перестановка OP. После 16 раундов шифрования производится конечная перестановка согласно таблице OP.

Расшифровка DES проводится в обратном порядке (рис. 2). В раундах используется обратное преобразование сетью Фейстеля.

Рис. 2. Схема расшифровки DESРис. 2. Схема расшифровки DES

Аппаратная реализация DES

Для написания быстрой аппаратной реализации буду использовать конвейер. За основу брал работу [2], однако генерирование ключа решил делать по-другому. Стоит обсудить стадии вычислений.

Начальная перестановка не требует никаких логических элементов, так что эта стадия однозначно быстрая, то же касается конечной перестановки и всех перестановок в генерировании ключа. Вычисление ключей делается параллельно с самим шифрованием, единственная стадия вычислений, требующая времени, это расширение исходного ключа битами для обнаружения ошибок. Хотя, как я писал выше, зачастую ключ приходит уже расширенный, так что эта часть вычислений оказывается ненужной.

Самая долгая часть это раунд шифрования, а именно, вычисление функции f. Функция расширения не требует логических элементов в реализации, то же касается перестановки P. Так что потребуется время на xor с ключом, и, самое долгое, преобразование S.

Преобразование S буду реализовывать при помощи таблицы поиска.

Теперь можно обсудить конвейеризацию. Самый очевидный и практически удобный вариант разбить на стадии по каждому раунду (см. рис. 1). Так же удобно добавить входные триггеры, на рисунке это stage 0.

Перейду к блоку, который будет производить шифрование одного раунда. Это, во-первых, вычисление функции f, а во-вторых вычисление рекуррентного соотношения для Ri. На вход блока подается два вектора R(i-1) и L(i-1) длинны 32 бит и ключ ki длинны 48 бит. На выходе блока формируется результат раунда Ri и Li. Вычисление ключа сделаю в отдельном блоке. Весь код написан на языке System Verilog.

Генерация ключа производится последовательным сдвигом на каждой стадии, таким образом следующий вектор можно загружать сразу после первого раунда шифрования.

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

Так же понадобится реализация функции fdecrypt. Т.к. расшифровка производится обратной сетью Фейстеля, то по сути нужно просто поменять местами Lout и Rout в блоке fencrypt. Так же придется изменить блок генерации ключей, т.к. теперь 16-й ключ нужен на первой стадии, 15-й на второй и т.д.

Все исходники загружены на мой гитхаб.

Теперь опишу тестирование блока DES. Тестировать отдельные функции перестановки я не вижу смысла потому что для их тестирования логично подавать векторы с одним битом равным единицы и всеми остальными равными нулю, а тогда проверка результата сводится к повторению написания таблицы перестановки. Так что для их проверки выпишу несколько произвольных входных векторов и ключей.

Имеет смысл проверить S-таблицы. Для этого я выпишу 512 = 64*8 тестовых вектора с ключом такие, что они покрывают все значения в S-таблице. Я использовал все ключи key = 64'h0, а тестовые векторы генерировал таким образом: выбираю S-таблицу, выбираю в ней ячейку, которую я хочу протестировать. Выписываю вектор, в котором нужные биты для для выбранной ячейки равны единицы, а все остальные равны нулю. Далее, я делаю обратную перестановку функции расширения E и полученный 32-битный вектор дополняю нулями до 64-битного. И, наконец, делаю обратную перестановку OP. Таким образом, каждый вектор последовательно пробегает каждую ячейку S-таблицы. С получившимися тестовыми векторами можно ознакомится в файле тестбенча на гитхабе.

Для тестирования блока расшифровки я использовал те же тестовые векторы, только поменял местами входной вектор с ожидаемым результатом.

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

Теперь, у меня есть написанный и протестированный RTL модуля DES для шифрования и дешифровки.

Аппаратная реализация алгоритма TDES

Алгоритм TDES состоит из комбинации трех стадий шифрования и расшифровки. Наиболее распространен 3DES-EDE3 (encrypt-decrypt-encrypt) с тремя разными ключами. Таким образом, длина ключа 168 бит (расширенный 192 бит), размер блока все так же равен 64 бит.

Для реализации этого алгоритма нужно соединить блоки шифрования и расшифровки. При этом нужно добавить дополнительную цепочку триггеров для задержки ключа до следующих блоков на время исполнения 16 раундов. При таком соединении блоков будут последовательно происходить перестановки IP и OP, которые являются обратными. Однако при последующем синтезе эти перестановки будут оптимизированы и заменены прямыми соединениями. RTL блока находится в приложении.

Тестовые векторы строил следующим образом: взял тестовые векторы для DES шифратора, ключ из этих векторов есть ключ первой стадии TDES. Ключи второй и третьей стадии одинаковые и равны 64'hffffffffffffffff. Таким образом, я проверяю S-блоки первого шифрования TDES, т.к. далее идет расшифровка и шифрование с одинаковым ключом, то ожидаемый результат совпадает с результатом после первой стадии, а он же результат из тестов на DES. Таким же образом тестирую последнее шифрование TDES. Если сейчас все хорошо, то я считаю, что две части из трех работают правильно, а тогда я могу проверить S-блоки стадии расшифровки с теми же входными и ожидаемыми векторами, что и в DES и ключами равными 64'h0.

Таким образом получается 512*3 = 1536 тестовых вектора. Тестовые векторы для TDES находятся в файле тестбенча на гитхабе.

Итог

Я написал и протестировал RTL алгоритмов шифрования DES и TDES-EDE3. Так же я написал тестовые векторы для этих алгоритмов. Все исходники на гитхабе, надеюсь они помогут Вам в знакомстве или даже реализации этих алгоритмов. Спасибо за внимание!


Полезные ссылки:

Подробнее..

1С справа налево как мы поддержали RTL в платформе 1С Предприятие

30.07.2020 12:15:48 | Автор: admin
Платформа 1С:Предприятие локализована на 22 языка, включая английский, немецкий, французский, китайский, вьетнамский. Недавно, в версии 8.3.17, мы поддержали арабский язык.
Одна из особенностей арабского языка в том, что текст на нём пишут и читают справа налево. UI для арабского языка надо отображать зеркально по горизонтали (но не всё и не всегда тут есть тонкости), контекстное меню открывать слева от курсора и т.п.
Под катом о том, как мы поддержали RTL (right-to-left) в веб-клиенте платформы 1С:Предприятие, а ещё одна из гипотез, объясняющая, почему арабский мир пишет справа налево.
image

Немного истории


Для нас привычно письмо слева направо. Это направление письма во многом порождено тем фактом, что при записи текста на бумаге правши (а их, по статистике, около 85%) видят то, что уже написано пишущая (правая) рука не закрывает написанный текст. Левшам же приходится мучиться.

Одна из гипотез почему в арабском языке используется письмо справа налево звучит так. Языки, от которых берет свое начало арабский, зародились в те времена, когда не было бумаги и ее аналогов (папируса, пергамента и т.п.). Был только один способ фиксации информации высекать письмена на камне. А как правшам будет удобнее орудовать молотком и зубилом? Конечно же, держа зубило в левой руке и стуча по нему молотком, зажатым в правой. А в этом случае удобнее писать как раз справа налево.

Ну а теперь о том, как мы разбирались с этим наследием веков :)

Как мы приступали к задаче?


Никто из разработчиков платформы не говорил по-арабски и не имел опыта разработки RTL-интерфейсов. Мы перелопатили массу статей на тему RTL (особенно хочется поблагодарить компанию 2ГИС за проделанную работу и тщательно проработанные статьи: статья 1, статья 2). По мере изучения материала пришло понимание, что без носителя языка нам никак не обойтись. Поэтому одновременно с поиском переводчиков на арабский язык мы стали искать себе сотрудника носителя арабского языка, который бы имел нужный нам опыт, мог бы проконсультировать нас по арабской специфике интерфейсов. Просмотрев несколько кандидатов, мы нашли такого человека и приступили к работе.

Поиграем шрифтами


По умолчанию мы используем в платформе шрифт Arial, 10pt. Разработчик конкретной конфигурации может поменять шрифт у большинства элементов интерфейса, но, как показывает практика, делается этот нечасто. Т.е. в большинстве случаев пользователи программ 1С видят на экранах надписи, написанные Arial-ом.
Arial хорошо отображает 21 язык (включая китайский и вьетнамский). Но, как выяснилось благодаря нашему арабскому коллеге, арабский текст, выведенный этим шрифтом, очень мелкий и плохо читается:

100%:
image

Арабские пользователи, как правило, работают в увеличенном DPI 125%, 150%. В этом DPI ситуация улучшается, но Arial по-прежнему остаётся плохо читаемым в силу особенностей шрифта.

125%:
image

150%:
image

Мы рассмотрели несколько вариантов решения этой проблемы:

  1. Поменять шрифт по умолчанию Arial на другой, одинаково хорошо отображающий все языки, поддерживаемые платформой (включая арабский).
  2. Увеличить размер шрифта Arial до 11pt в RTL-интерфейсе.
  3. Заменить шрифт по умолчанию с Arial на более подходящий для арабского текста, а в LTR-интерфейсе продолжать использовать Arial.

При выборе решения приходилось учитывать, что шрифт Arial размером 10pt используется в платформе 1С:Предприятие очень давно, на платформе создано нами и нашими партнёрами более 1300 тиражных решений, и во всех них шрифт Arial 10pt хорошо себя показал на всех поддерживаемых ОС (Windows, Linux и macOS различных версий), а также в браузерах. Смена шрифта и/или его размера означала бы необходимость массированного тестирования пользовательского интерфейса, и многое в этих тестах автоматизации не поддаётся. Смена шрифта также означала бы, что для текущих пользователей меняется привычный интерфейс программ.

Более того, найти универсальный шрифт, хорошо отображающий все языки, включая арабский, нам не удалось. Например, шрифт Segoe UI хорошо отображает арабский даже при 10pt, но не поддерживает китайский язык, а также не поддерживается в ряде ОС. Tahoma неплохо отображает арабский текст при 10pt, но имеет проблемы с поддержкой в Linux и слишком жирное начертание латиницы/кириллицы в случае жирного шрифта (арабский жирный текст выглядит хорошо). И т.д., и т.п.

Увеличение размера шрифта по умолчанию до 11pt в RTL-интерфейсе означало бы серьёзный объём тестирования пользовательского интерфейса мы должны убедиться, что всё отрисовывается корректно, все надписи помещаются в отведённое для них место и т.п. И даже при размере 11pt Arial показывает арабские символы не идеально.
В итоге оптимальным с точки зрения трудозатрат и достигаемого эффекта оказался третий путь: мы продолжаем использовать Arial для всех символов, кроме арабских. А для арабских символов используем хорошо подходящий для этого шрифт Almarai. Для этого в CSS добавляем:

@font-face {  font-family: 'Almarai';  font-style: normal;  font-weight: 400;  font-display: swap;  src: local('Almarai'),        local('Almarai-Regular'),       url(http://personeltest.ru/aways/fonts.gstatic.com/s/almarai/v2/tsstApxBaigK_hnnQ1iFo0C3.woff2)             format('woff2');  unicode-range:        U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC;}

и далее везде, где нужно использовать шрифт по умолчанию, задаём шрифт таким образом:
font-family: 'Almarai', Arial, sans-serif;

Прелесть этого подхода в том, что, если в интерфейсе нет ни одного символа, попадающего в диапазон unicode-range, то такой шрифт даже не загрузится. Но как только такой символ появится, браузер сам загрузит шрифт (или использует его локальную версию) и отобразит символ нужным шрифтом.

Переворот интерфейса


Как и следовало ожидать, HTML-вёрстка веб-клиента не была готова к перевороту. Совершив первый шаг, поставив на корневом элементе атрибут dir=rtl и добавив стиль html[dir=rtl] {text-align: right;}, мы приступили к кропотливой работе. В ходе этой работы мы выработали ряд практик, которыми хотим здесь поделиться.

Симметрия


Рассмотрим на примере кнопок. Кнопки в платформе могут содержать в себе картинку, текст и маркер выпадающего списка. И всё это в любом составе на усмотрение разработчиков прикладных решений на базе платформы.

В колонке до RTL графически представлены исходные отступы элементов кнопки. Очевидна зависимость величины отступов от наличия элементов в кнопке, а также от последовательности их расположения. Если есть картинка, то тексту не нужен левый отступ, если картинка справа, то у картинки отрицательный сдвиг, если есть маркер выпадающего списка контейнеру с текстом больше отступ справа, если маркер сразу после картинки у него еще отступ справа. Слишком много если, за исключением кнопки только с текстом, у которого симметричные отступы. Симметричные! Если распределить отступы симметрично, то и переворачивать нечего. Это и стало основной идеей.

В колонке после RTL показаны новые симметричные отступы на тех же самых кнопках. Осталось решить нюанс с отступом между картинкой и маркером списка. Решение хотелось универсальное для любой ориентации. Сам треугольник рисуется верхним бордером на псевдоэлементе, а отступ ему нужен, только если он после картинки. Вот под таким условием добавляется еще псевдоэлемент шириной в необходимый отступ. Треугольник и отступ сами поменяются местами при смене ориентации.

image

Примечание. Все приведённые ниже примеры по умолчанию приведены для LTR-интерфейса. Чтобы увидеть, как пример выглядит в RTL-интерфейсе, смените dir=ltr на dir=rtl.

<!DOCTYPE html><html dir="ltr"><head><style>.button {    display: inline-flex;    align-items: center;    border: 1px solid #A0A0A0;    border-radius: 3px;    height: 26px;    padding: 0 8px;}.buttonImg {    background: #A0A0A0;    width: 16px;    height: 16px;}.buttonBox {    margin: 0 8px;}.buttonDrop {    display: flex;}.buttonDrop:after {    content: '';    display: block;    border-width: 3px 3px 0;    border-style: solid;    border-left-color: transparent;    border-right-color: transparent;}.buttonImg + .buttonDrop::before {    content: '';    display: block;    width: 8px;    overflow: hidden;}</style></head><body><a class="button">    <span class="buttonImg"></span>    <span class="buttonBox">Настройки</span>    <span class="buttonDrop"></span></a><a class="button">    <span class="buttonImg"></span>    <span class="buttonDrop"></span></a></body></html>

Мы стараемся избегать лишних элементов, псевдоэлементов и обёрток. Но, делая выбор в данном случае между увеличением условий в CSS и добавлением псевдоэлемента, победило решение с псевдоэлементом в силу своей универсальности. Таких кнопок бывает на форме немного, поэтому производительность при добавлении элементов не пострадает даже в Internet Explorer.

Принцип симметрии оказался полезен и при прокрутке наших панелей. Чтобы сдвинуть содержимое по горизонтали, ранее применялось единичное свойство margin-left: -Npx;.

image

Теперь устанавливается значение симметричное margin: 0 -Npx;, т.е. для левого и правого сразу, а куда сдвинуть знает сам браузер, в зависимости от указанного направления.

Атомарные классы


Одной из возможностей нашей платформы является возможность динамически менять контент и его расположение на форме на лету по вкусу каждого пользователя. Нередкий случай изменений выравнивание текста по горизонтали: слева, справа или по центру. Достигается это простым выравниваем text-align с соответствующим значением. Разворот для RTL означал бы расширение условий в скриптах и стилях для каждого контрола и для каждого случая его позиционирования. Минимальное решение обошлось в 4 строчки:

.taStart {    text-align: left;} html[dir=rtl] .taStart {    text-align: right;}.taEnd {    text-align: right;}html[dir=rtl] .taEnd {    text-align: left;}


Таким образом, в необходимых местах происходит установка класса с необходимым выравниванием и его легкая замена в случае необходимости. Осталось только заменить в установку выравнивания с style=text-align: ... на соответствующий класс.
По такому же принципу происходит установка другого вида выравнивания float.

.floatStart {    float: left;} html[dir=rtl] .floatStart {    float: right;}.floatEnd {    float: right;}html[dir=rtl] .floatEnd {    float: left;}


И, как же без него, класс для зеркального отображения, например, иконок, который так же устанавливается в любые контейнеры, где необходим зеркальное отображение в RTL-интерфейсе.

html[dir=rtl] .rtlScale {    transform: scaleX(-1);}


Антискейл


Разобравшись с простыми линейными элементами, пришло время переходить к сложным. Есть и такие в нашей платформе, например, тумблеры. Они могут оказаться разной геометрической формы. С расположением элементов справился браузер, отступы в наших тумблерах изначально симметричные. Так в чем же проблема? Проблема в скруглениях рамок.
Скругления рамок рассчитываются для каждого элемента тумблера в зависимости его положения. Слева-сверху, справа-сверху, справа-сверху и справа-снизу вариации различны.

Можно перевернуть контейнер с тумблером целиком, но что делать с текстом, который тоже перевернется? Этот прием мы назвали антискейл. Контейнеру, которому необходимо отобразиться зеркально, добавляем атомарный класс rtlScale, а его дочернему элементу добавляем свойство наследования transform: inherit;. В LTR-интерфейсе данный метод будет проигнорирован, а для RTL-интерфейса, текст, перевернувшись дважды, отобразится как надо.

image

<!DOCTYPE html><html dir="ltr"><head><style>html[dir=rtl] .rtlScale {    transform: scaleX(-1);}.tumbler {    display: inline-flex;    border-radius: 4px 0 0 4px;    border: 1px solid #A0A0A0;    padding: 4px 8px;}.tumblerBox {    transform: inherit;}</style></head><body><div class="tumbler rtlScale">    <div class="tumblerBox">не знаю</div></div></body></html>


Flexbox


Конечно же, к сожалению, не мы придумали эту потрясающую технологию, но с большим удовольствием использовали её возможности в наших целях. Например, в панели разделов. Кнопки прокрутки этой панели не занимают места, появляются поверх панели при возможности прокрутки в ту или иную сторону. Вполне логичная реализация position: absolute; right/left: 0; оказалась не универсальной, поэтому мы от неё отказались. В итоге универсальное решение стало выглядеть так: родительскому контейнеру кнопки прокрутки устанавливаем нулевую ширину, чтобы не занимал место, а кнопке прокрутке, расположенной в конце, сменили ориентацию через flex-direction: row-reverse;.

image

Таким образом, кнопка в конце строки прижимается к концу строки контейнера с нулевой шириной и отображается назад поверх панели.

<!DOCTYPE html><html dir="ltr"><head><style>.panel {    display: inline-flex;    background: #fbed9e;    height: 64px;    width: 250px;}.content {    width: 100%;}.scroll {    display: flex;    position: relative;     width: 0; }.scrollBack {    order: -1; }.scrollNext {    flex-direction: row-reverse; }.scroll div {    display: flex;     flex: 0 0 auto;     justify-content: center;     align-items: center;     background: rgba(255,255,255,0.5);     width: 75px; }</style></head><body><div class="panel">    <div class="content">Контент панели</div>    <div class="scroll scrollBack">        <div>Назад</div>    </div>    <div class="scroll scrollNext">        <div>Вперёд</div>    </div></div></body></html>


Кстати, идея с нулевой шириной оказалась полезна и при решении других задач. В платформе повсеместно используются выпадающие элементы (контекстные меню, выпадающие списки и др.). Расчёт позиционирования сложный и тонкий, следовательно, зеркальное отображение требует еще большей сложности и тонкости.

image

Решение поместить выпадающий элемент в контейнер нулевых размеров (так называемый якорь). Якорь позиционируется абсолютно в необходимую точку интерфейса, а его содержимое своим стартовым краем прижимается к стартовому краю якоря, располагая контент в нужную сторону.

<!DOCTYPE html><html dir="ltr"><head><style>.anchor {    border: 1px solid red;     position: absolute;     width: 100px;     height: 50px;     max-width: 0;     max-height: 0;     top: 25%;    left: 50%;}.anchorContent {    background: #FFF;     border: 1px solid #A0A0A0;     width: inherit;     height: inherit;     padding: 4px 8px; }</style></head><body><div class="anchor">    <div class="anchorContent">Контент якоря</div></div></body></html>


Абсолютно спозиционированные элементы


Там, где нельзя обойтись без абсолютного позиционирования элементов (style=position: absolute; или style=position: fixed;), dir=rtl бессилен. На помощь приходит подход, когда горизонтальная координата применяется не к стилю left, а right.

image

При этом если в JS при расчётах координат идёт обращение к свойствам scrollLeft, offsetLeft у элементов, то в RTL-интерфейсе использование этих свойств напрямую может привести к неожиданным последствиям. Нужно высчитывать значение этих свойств по-другому. Хорошо зарекомендовала себя реализация подобного функционала в Google Closure Library, которую мы используем в веб-клиенте: см. https://github.com/google/closure-library/blob/master/closure/goog/style/bidi.js.

В итоге


Мы это сделали! Перевернули и сохранили наш исходный код в едином варианте под LTR и RTL-интерфейсы. Необходимости пока не возникло, но при желании мы сможем на одной странице отобразить две формы разной направленности одновременно. И кстати, применив наши приёмы, в итоге мы получили итоговый CSS-файл легче на 25%.
А ещё мы поддержали RTL в тонком (нативном) клиенте 1C, который работает в Windows, Linux и macOS, но это тема для отдельной статьи.
Подробнее..

Перевод Примеры применения переменных CSS на практике

30.04.2021 14:04:59 | Автор: admin

Когда я впервые попробовал использовать переменные CSS, у меня не было полного представления об их возможностях. Правильное их использование позволяет существенно сократить время и трудозатраты на решение определённых задач в CSS.


Если вы ещё не работали с переменными CSS, рекомендую прочитать эту статью, чтобы познакомиться с ними. Как только вы их освоите, работа станет намного проще. Цель этой статьи сосредоточить внимание на разных случаях практического использования переменных CSS помимо их применения для создания маркеров дизайна, таких как цвета.

Вы готовы? Тогда вперёд!

В чём основная проблема?

Если вы используете переменные CSS так же, как и препроцессоры CSS (например в Sass), то вы не полностью реализуете все их преимущества. Рассмотрите следующий пример:

:root {    --brand-primary: #7777e9;    --brand-secondary: #c96fde;}.title {    color: var(--brand-primary);}

И тут нет никакой разницы с нижеприведённым примером в Sass:

$brand-primary: #7777e9;$brand-secondary: #c96fde;.title {    color: $brand-primary;}

Да, применение переменных CSS в качестве переменных цвета ни в коей мере не является ошибкой. Но это всё равно, что покупать Apple MacBook M1 для посещения интернет-сайтов, хотя с этим и так хорошо справляется ваш старый настольный ПК, собранный в 2012 году. Какой смысл покупать ультрасовременный компьютер и делать на нём то же самое, никак не используя весь спектр его возможностей? Как вы понимаете, примерно так я и думаю об использовании переменных CSS для сохранения информации о цветах.

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

Примеры и случаи практического использования

Полные формы записи свойств

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

<!-- Base component --><header class="page-header">    <h2>...</h2>    <p>...</p></header><!-- Component variation --><header class="page-header page-header--compact">    <h2>...</h2>    <p>...</p></header>
.page-header {    --padding-start: 2.5rem;    --padding-block: 2rem;    padding: var(--padding-block) 1rem var(--padding-block) var(--padding-start);}.page-header--compact {    --padding-start: 1.5rem;    --padding-block: 1rem;}

Обратите внимание, для изменения заполнения нам потребуется всего лишь изменить значение переменной CSS. Без неё нам было бы необходимо вручную вводить полную форму записи свойства внутреннего отступа padding, чтобы изменить только одно значение в нём.

.page-header {    padding: 2rem 1rem 2rem 1.5rem;}.page-header--compact {    padding: 1rem 1rem 1rem 2.5rem;}

Всё вышесказанное применимо и для свойства внешнего отступа margin.

Свойства CSS background

Что касается свойств CSS для работы с фоном, то и здесь переменные CSS помогают сократить объём создаваемого нами кода. И даже больше того: благодаря их применению сам код CSS легче читать.

Хранение значений URL

При работе с интерфейсом пользователя вам может потребоваться добавить какое-либо изображение в декоративных целях. В таком случае хорошим решением будет использование элементов <div> и background-image. Если интерфейс должен быть динамическим, то значения для изображения нужно подставлять с помощью JavaScript.

Без применения переменных CSS соответствующий код HTML будет выглядеть так:

<section     class="newsletter"     style="background-image: url('/assets/ui/decoraitve/newsletter-lg-aj1891101.svg')"></section>

Но вместо того, чтобы напрямую изменять свойство background-image, мы можем сделать следующее.

<section     class="newsletter"     style="--thumb:url('/assets/ui/decoraitve/newsletter-lg-aj1891101.svg')"></section>
.newsletter {    background-image: var(--thumb);    background-size: cover;    background-position: 100% 50%;}

Обратите внимание, что необходимо включить элемент url() без переменной CSS.

Положение фонового изображения

В приведённом выше примере фоновое изображение помещается справа. Для макетов с направлением текста справа налево (RTL) положение фона следует перевернуть.

.newsletter {    --pos: 100% 50%;    background-image: var(--thumb);    background-size: cover;    background-position: 100% 50%;}html[dir="rtl] .newsletter {    -background-position: 0% 50%;}

Чтобы упростить эту задачу, мы можем воспользоваться переменными CSS.

.newsletter {    /* other styles */    background-position: var(--pos);}html[dir="rtl] .newsletter {    --pos: 0% 50%;}

Угловой градиент: часть 1

Угловой градиент также можно применять при создании макетов для нескольких языков. По умолчанию он может быть равен 45deg, и, возможно, потребуется изменить его на -45deg для макетов RTL.

.element {    --angle: 90deg;    background: linear-gradient(var(--angle), #4088vb, #C05858);}html[dir="rtl] .element {    --angle: -90deg;}

Угловой градиент: часть 2

В случае с угловым градиентом использование переменных CSS с радиальными градиентами действительно существенно упрощает настройку положения. В следующем примере положение градиента изменяется при помощи переменной --pos.

А здесь показано, как можно сделать то же самое без переменных CSS.

.card {    background: radial-gradient(        circle 200px at center top,        rgba(64, 136, 203, 0.5),        #f7f7f7    );}

Теперь предположим, что у нас есть какой-то вариант карточки .card-2 и он должен находиться в другом положении. Необходимо написать следующий код:

.card-2 {    background: radial-gradient(        circle 200px at center top,        rgba(64, 136, 203, 0.5),        #f7f7f7    );}

Таким образом, переписывается всё определение градиента. Можно ли сделать лучше? Определённо. Обратите внимание, что единственным настраиваемым значением для этого варианта является переменная --pos.

.card {    --pos: center top;    background: radial-gradient(        circle 200px at var(--pos),        rgba(64, 136, 203, 0.5),        #f7f7f7    );}.card-2 {    --pos: left top;}

Свойство clip-path

Весьма полезным случаем использования переменной CSS является изменение с её помощью значений clip-path: polygon() при переходе с настольных на мобильные устройства.

На показанном выше рисунке необходимо изменить положение вершин многоугольника. С помощью переменных CSS сделать это намного проще.

.hero {    --first: 4% 7%;    --second: 80% 0;    --thrid: 100% 95%;    --fourth: 10% 100%;    clip-path: polygon(var(--first), var(--second), var(--thrid), var(--fourth));}@media (min-width: 40rem) {    .hero {        --second: 96% 0;        --thrid: 92% 82%;    }}

Если вы хотите узнать больше о свойстве CSS clip-path, здесь вы найдёте статью за авторством вашего покорного слуги.

Элемент флажка

Великолепный пример использования переменных CSS это применение их в сочетании с функцией определения цветов hsla(). Таким образом мы можем создавать динамические компоненты, которые затем можно менять, корректируя одну или несколько переменных CSS.

Первое, что я сделал, это определил значения hsla() для корневого элемента компонента.

.form-item {    --primary-h: 240;    --primary-s: 56%;    --primary-l: 63%;    --primary-alpha: 100%;}

Теперь я могу использовать эти свойства в функции определения цветов hsla().

/* The circle that appears on hover */.form-item__label:after {    --primary-alpha: 0;    background-color: hsla(        var(--primary-h),        var(--primary-s),        var(--primary-l),        var(--primary-alpha)    );}.form-item__label:hover:after {    --primary-alpha: 15%;}

Код SVG, встроенный в CSS

Когда-то я работал над пользовательским интерфейсом для проекта одного клиента и столкнулся с такой ситуацией. У нас был раздел с двумя лентами (одна сверху, а вторая снизу). Мне необходимо было изменить цвет, угол поворота и размер этих лент, не создавая отдельный код CSS для каждой из них. Спасением стали переменные CSS!

Прежде всего я подготовил требуемый код SVG в Adobe Illustrator. Я разделил каждую ленту на три слоя:

  • светлые области;

  • тёмные области;

  • базовый слой.

Затем я экспортировал этот код SVG и поместил его в элементах <defs> так, чтобы легко можно было использовать его повторно. Обратите внимание, я также добавил ключевое слово currentColor! Это и есть то самое магическое значение, которое заставит всё работать.

Наконец, теперь нам необходимо определить размер и угол поворота в CSS.

.tape {    width: var(--size);    transform: rotate(var(--angle));}
<svg class="tape" style="--angle: 10deg; color: red; --size: 120px;" aria-hidden="true" focusable="false" viewBox="0 0 123 47">  <use href="#tape"></use></svg>

Готово. Мы создали собственный код SVG, который можно настраивать по мере необходимости. Впечатляет, не правда ли?

Создание миксинов (примесей-шаблонов), таких, как в Sass

Об этой интересной возможности я узнал из рекомендуемого мною к просмотру выступления Ли Веру (Lea Verou). Идея состоит в том, чтобы установить исходные переменные CSS для определённого свойства, а затем переопределять их, когда это понадобится.

Здесь показан пример, как мы можем использовать эту возможность. Очень часто мне необходимо, чтобы враппер был центрирован, для чего можно добавить margin: 0 auto к соответствующему элементу враппера. В тех случаях, когда необходимо отцентрировать какой-то свой элемент, мы можем выполнить следующее:

<div class="featured-section u-center"></div>
.u-center {  --mx: initial;  --my: initial;  margin: var(--my) var(--mx);}.featured-section {  --mx: auto;  --my: 2rem;}

Во-первых, я создал служебный класс .u-center с заданными по умолчанию значениями для горизонтальных и вертикальных внешних отступов. Я могу добавить этот класс к элементу и затем переопределить переменные CSS. Это может оказаться очень полезным, например, если элементу нужны определённые внешние отступы только с верхней и нижней сторон.

Использование функции calc()

Функция calc() в сочетании с переменными CSS может очень пригодиться. Мы можем создать какой-то базовый размер для компонента, а затем, меняя только одну переменную, можем делать его больше или меньше.

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

.c-avatar {  width: calc(var(--size, 32) * 1px);  height: calc(var(--size, 32) * 1px);}

Обратите внимание, я использовал функцию var(--size, 32). Если переменная --size не определена, то значение 32 будет использовано как резервное значение. Важно указать 1px, чтобы добавить px к результирующему числу.

Таким образом, мы можем создавать вариации классов, просто добавляя переменную CSS --size.

.c-avatar--medium {    --size: 64;}.c-avatar--large {    --size: 128;}

Псевдоэлементы

С помощью переменных CSS можно изменять свойство псевдоэлемента, поскольку оно наследуется от родительского элемента. Рассмотрите следующий пример:

В заголовке раздела содержится декоративная фиолетовая линия, которая является псевдоэлементом. Мы можем передать переменную CSS данному заголовку, и этот псевдоэлемент унаследует её.

.section-title {    --dot-color: #829be9;}.section-title:before {    content: "";    background-color: var(--dot-color);}

Но, кроме того, мы также можем имитировать изменение цвета псевдоэлемента с помощью Javascript.

Встроенные стили

Другим примером полезного применения переменных CSS является использование их в качестве встроенных стилей. И тут открывается множество возможностей для настройки какого-либо компонента путём изменения одной или нескольких переменных.

Рассмотрите следующий пример.

.o-grid {    display: grid;    grid-template-columns: repeat(auto-fit, minmax(var(--item-width, 200px), 1fr);    grid-gap: var(--gap);}

У нас есть настроенный грид и заданное по умолчанию для ширины элемента грида значение 200px. В коде HTML мы можем переопределить его, переустановив значение для переменной CSS.

<!-- Example 1 --><div class="o-grid" style="--item-width: 250px;">     <div></div>     <div></div>     <div></div></div><!-- Example 2 --><div class="o-grid" style="--item-width: 350px;">     <div></div>     <div></div>     <div></div></div>

Ну разве это не полезно? Если вы хотите узнать больше о переменных CSS со встроенными стилями, я уже писал об этом более подробно.

Заключение

Как вы могли убедиться, существует множество примеров использования переменных CSS помимо определения цветов с их помощью. Уверен, то что я показал, это лишь самые поверхностные варианты их применения. Если вы придумали какой-то свой уникальный вариант использования поделитесь им в комментариях!

Если фронтенд-разработка для вас давно родная стихия можно уже задуматься о грейде доFullstack-разработчика, настоящего универсала веб-разработки, которому будут рады в любом крупном проекте. На нашем курсе, помимо современной программы, вас ждет много практики в разных форматах от преподавателей с опытом коммерческой разработки. Приходите учиться, будет сложно, но интересно!

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Перевод Взгляд на Tailwind CSS

23.05.2021 18:15:00 | Автор: admin

В этом году я видел много шумихи вокруг популярного фреймворка CSS, Tailwind CSS. И подумал, что поделюсь некоторыми мыслями и опасениями по поводу этого фреймворка UI. Я приобрёл небольшой опыт написания CSS с подходом utility-first (полезность прежде всего), когда начал свою карьеру в разработке интерфейсов, несколько лет назад.

К старту курса о Frontend-разработке делимся статьёй, автор которой решил, возможно, несколько изменить то, как воспринимается Tailwind, рассказать как о положительных, так и об отрицательных сторонах фреймворка, особенно в контексте работы с мультиязычными сайтами.


Вещи, которые я считаю интересными

Вам не нужно закрывать файл с HTML

Основной заголовок на официальном сайте Tailwind гласит:

Быстрое создание современных веб-сайтов, даже не покидая HTML.

Я согласен, что писать код в одном месте может быть быстрее, чем переключаться между разными файлами. Однако оставить в стороне свой HTML для меня не проблема. Это может помочь переключить контекст между разметкой и стилями. Разделение файлов HTML и CSS может помочь мне лучше сосредоточиться на выполнении поставленной задачи. Однако, когда разметка и стили смешиваются, когда вы работаете над сложным, многоязычным, отзывчивым сайтом и пользовательским интерфейсом с темами, всё может пойти наперекосяк.

Когда я работаю с Tailwind, это похоже на то, как если бы я держал две ручки: одну для набросков, а другую для раскрашивания. Одновременное написание разметки и CSS напоминает мне эти две ручки.

Tailwind сильно отличается тем, что у цветной ручки есть ограничения или сдерживающие факторы. Другими словами, можно раскрашивать только предустановленными цветами. По мне так лучше сосредоточиться на написании доступной, семантической разметки, а затем отдельно работать со стилизацией.

Проектные ограничения

В дизайн-системе мы обычно определяем цвет, интервал, размер и другие свойства. Работа разработчика сильно упрощается, когда есть пределы тому, что он может сделать. Tailwind накладывает хорошие ограничения. Идея определения пользовательских конфигурационных файлов очень полезна.

Именование классов CSS

О названиях классов CSS думать не нужно и это может ускорить реализацию макетов в вебе. Я нахожу это полезным в случае, когда ваш босс пишет вам, что есть срочный лендинг, который должен быть сделан сегодня, и у вас только 3 часа, чтобы написать его. Tailwind может помочь быстро достичь результата.

Однако, если вы придерживаетесь разделения разметки и стилей, разработка займёт гораздо больше времени. Ещё одно полезное применение Tailwind это соревнование или хакатон. Самое главное на таких событиях сделать работу и что-то получить за неё. Никому не будет дела до того, как вы написали CSS, верно?

То, с чем я не согласен

Tailwind не фреймворк utility-first

Подзаголовок на их веб-сайте сообщает, что CSS Tailwind:

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

Из увиденного я сделал вывод, что Tailwind это только утилитарный (utility-only) фреймворк. Может быть, название "только утилитарный" повлияет на то, как его воспримут новички? Я редко вижу какой-то сайт, использующий Tailwind и применяющий концепцию utility-first.

Длинный список классов может запутать

Обратите внимание на то, что я знаю о методе @apply. Рассмотрим пример из документации Tailwind:

<input  class="block appearance-none bg-white placeholder-gray-600 border border-indigo-200 rounded w-full py-3 px-4 text-gray-700 leading-5 focus:outline-none focus:border-indigo-400 focus:placeholder-gray-400 focus:ring-2 focus:ring-indigo-200"  placeholder="jane@example.com"/>

Это поле ввода с 17 классами CSS. Что проще: читать классы один за одним горизонтально или сканировать их сверху вниз? Вот так поле будет выглядеть стиль этого поля в файле CSS:

.c-input {  display: block;  appearance: none;  background-color: #fff;  @include placeholder(grey);  border: 1px solid rgba(199, 210, 254, var(--tw-border-opacity));  border-radius: 0.25rem;  padding: 0.75rem 1rem;  line-height: 1.25rem;  color: rgba(55, 65, 81, var(--tw-text-opacity));}.c-input:focus {  /* Focus styles.. */}

Я могу прочитать и понять, какие стили содержит это поле ввода, гораздо быстрее, чем в ситуации, когда сканирую HTML. Возможно, существуют плагины для редакторов кода, которые автоматически форматируют HTML-классы так, чтобы каждый из них располагался отдельно [на отдельной строке], но в DevTools браузера этого нет.

Я знаю о методе @apply, но каждый раз, когда я думаю о нём, я прихожу к выводу, что он противоречит основной концепции Tailwind. Вот тот же пример (поле ввода):

.c-input {  @apply block appearance-none bg-white placeholder-gray-600 border border-indigo-200 rounded w-full py-3 px-4 text-gray-700 leading-5 focus:outline-none focus:border-indigo-400 focus:placeholder-gray-400 focus:ring-2 focus:ring-indigo-200;}

Посмотрите на длину списка классов. Если в Tailwind в приоритете полезность, то почему в официальной документации Tailwind или в Tailwind UI мы редко видим @apply? Опять же, я вижу Tailwind как только утилитарный фреймворк.

Всегда нужно давать имена элементам

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

Привет, есть новости о bg-white w-full py-3 px-4?

На самом деле фраза будет такой:

Есть новости о дизайне поляризованной карты?

В конце дня вам нужно будет сесть и подумать об уникальном, выразительном названии для каждого компонента проекта, который вы пытаетесь разработать. Это применимо, конечно, к ситуации, когда вы хотите масштабировать и поддерживать проект в течение длительного времени. Некоторое время назад я шутил с другом вот о чём: что, если мы отложим традиционное именование в сторону и будем называть себя не традиционными именами, а как в коде ниже:

<person class="hair-brown length-[175] face-rounded"></person>

Код выше бессмыслица. Гораздо лучше такой код:

<person class="ahmad"></person>

Некоторые классы запутывают

Когда я только начинал использовать Tailwind, мне нужно было добавить класс, который отвечает за свойство align-items: center. Моей первой мыслью было воспользоваться align-center, но это не сработало.

Я посмотрел в документацию и впал в замешательство. Класс items-center добавит CSS-свойство align-items: center, где класс align-middle будет содержать vertical-align: middle. Чтобы запомнить их, требуется немного мышечной памяти.

Опытные веб-разработчики могут легко адаптироваться к этому, и это не будет для них большой проблемой. Но самое интересное для новичка в CSS. Изучение Tailwind без уверенного знания CSS может привести к недопониманию в будущем. Например, если разработчик начал свою карьеру только с Tailwind, то, когда его попросят написать CSS с нуля, он не сможет этого сделать. Я не говорю, что это невозможно, но это потребует времени и усилий.

Tailwind затрудняет настройку дизайна в браузере

Я занимаюсь как дизайном, так и frontend-разработкой, поэтому редактирование в браузере с помощью DevTools для меня крайне важно. С Tailwind работа в DevTools может стать сложнее. Скажем, например, я хочу изменить отступы для компонента. Когда я изменяю значение класса py-3, это влияет на каждый использующий его элемент страницы.

Единственный способ убрать его открыть меню .cls в DevTools, после чего класс можно будет переключить. Однако это не решает проблему. Что я могу сделать в этом случае? Добавить встроенный стиль через DevTools, а это мне не нравится. Проблема решится, если просто давать элементам названия. Добавлю к этому факт: общий размер файла полной сборки Tailwind составляет 12 МБ. Редактирование CSS в DevTools будет очень медленным.

Это означает, что разработка в браузере неэффективна. Недавно команда Tailwind выпустила компилятор JIT (just in time), удаляющий неиспользуемый CSS. Это мешает всей идее дизайна в браузере.

Я набрал back и получил длинный список всех доступных классов CSS. При JIT-компиляции таких подсказок не будет.

Tailwind неудобен для многоязычных сайтов

Чтобы вы больше понимали, добавлю: я работаю над веб-сайтами, которые должны работать как на английском (с направлением слева направо, LTR), так и на арабском (с направлением справа налево, RTL). Рассмотрим такой код:

/* LTR: left to right */.c-input {  padding-left: 2rem;}

В отдельном файле CSS для RTL стиль будет выглядеть так:

/* RTL: Right to left */.c-input {  padding-left: 0;  padding-right: 2rem;}

В приведённом выше примере padding следует развернуть в зависимости от направления страницы (слева направо или справа налево). Для этого уже есть плагины, но они решают проблему только с внешней стороны. Первый найденный мной делает следующее:

html[dir="rtl"] .ml-2 {   margin-right: 1rem; }

Для меня это не очень хорошее решение. Второй найденный плагин немного отличался от первого:

[dir="rtl"] .rtl\:text-2xl {  font-size: 1.5rem;  line-height: 2rem;}

Такой код может очень быстро выйти из-под контроля. Исследуя один веб-сайт, я заметил более 30 классов CSS.

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

Чтобы помочь в создании многоязычного веб-сайта, сейчас я использую Bi-App Sass. Вот пример:

.elem {  display: flex;  @include margin-left(10px);  @include border-right(2px solid #000);}

Код скомпилируется в два разных файла CSS. Файл ltr:

/* LTR Styles */.elem {  display: flex;  margin-left: 10px;  border-right: 2px solid #000;}

Подробнее о стилизации RTL читайте в этом руководстве от вашего покорного слуги.

Я не всегда работаю с шаблонами

Одна из проблем Tailwind заключается в том, что, если у вас есть список карточек и вы хотите изменить определённый набор классов, вам придётся вручную просматривать их в редакторе кода. Это не будет проблемой, если вы используете в своём продукте частичные файлы CSS (partial) или компоненты. Вы можете один раз написать HTML, и любое изменение будет отражено везде, где используется этот компонент.

Это не всегда так. Я работаю над простыми страницами index.html, где усилия в разделении на части или компоненты себя не оправдывают. В этом случае работа с Tailwind и редактирование CSS могут стать процессом, чреватым ошибками, поскольку вы даже не можете использовать функцию "Найти и заменить": она может пропустить некоторые другие элементы на странице.

Tailwind делает веб-сайты похожими

Команда Tailwind создала набор продуманных компонентов под названием Tailwind UI, которые легко настраиваются и готовы к использованию в вашем проекте.

Внешний вид и функциональность компонентов приятные, и мне это нравится. Хотя есть проблемы, если сайт использует Tailwind UI, есть большая вероятность, что я предскажу использовать его.

Обычно, когда вы работа Tailwind UI, это означает, что у вас нет времени на создание индивидуального дизайна, поэтому вам нужно что-то, что можно быстро запустить, верно? И это хороший вариант применения, за исключением одной детали: применение Tailwind приведёт к тому, что многие сайты будут выглядеть похожими друг на друга, подобно тому, что было много лет назад с Bootstrap.

Некоторые свойства или особенности CSS использовать невозможно

К примеру, не включено свойство clip-path, и я полностью понимаю причину. Предположим, мы хотим включить его как компонент. Где мы должны написать код? Здесь:

<article class="block appearance-none bg-white placeholder-gray-600 border border-indigo-200 rounded w-full py-3></article>

Либо примерно так включить его в конфигурацию Tailwind:

// tailwind.config.jsmodule.exports = {  theme: {    clipPath: {      // Configure your clip-path values here    }  }};

Или же сделать следующее:

.card {  @apply block appearance-none bg-white placeholder-gray-600 border border-indigo-200 rounded w-full py-3;  clip-path: inset(20px 20px 50px 20px);}

Заключительные мысли

Может ли Tailwind оборачивать CSS в свои классы во время компиляции?

Представьте себе, что Tailwind появляется только во время компиляции. То есть вы пишете обычный CSS с именованием и всё такое, а умный компилятор преобразует ваш CSS в утилитарные классы. Это было бы воплощением мечты.

Утилитарные классы мощный инструмент, если не перестараться

В своих текущих проектах я использую комбинацию утилитарных классов и обычного CSS. Для меня это идеальное сочетание. Я не теряю возможности утилитарных классов и в то же время использую их, не загромождая HTML.

Фронтенд довольно часто выбирают как точку входа в IT. Но фронтенд это не только внешнее оформление сайтов, но и работа с базами данных, а также внешними API. Фронтенд требует системной, комплексной подготовки. Если вам или вашим знакомым интересно это направление разработки можете присмотреться к нашему курсу о Frontend-разработке, где мы касаемся не только вышеупомянутых тем, но и разработки отзывчивых сайтов при помощи flexbox, работаем с методологией БЭМ и затрагиваем другие аспекты фронтенда.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Перевод Погружаемся в логические свойства CSS

13.03.2021 20:20:43 | Автор: admin

Поддержка логических свойств CSS со временем становится лучше. Однако мне по-прежнему трудно запомнить их, когда использую их в проекте. Что означают start и end? Несколько сложно охватить все детали без проб и ошибок.

В этой статье я нацелен прокачать вас и пробежаться по использованию логических свойств, чтобы возникло твёрдое понимание, у дизайнеров, говорящих на английском и арабском языках. Я попытался придумать визуальное объяснение логических свойств, которое, надеюсь, будет понятным. Готовы? Погружаемся!

Вступление

Основная идея логических свойств в том, что мы не будем использовать свойства направлений CSS как есть. Вместо этого мы привяжемся к прописанному в HTML направлению. Позволяющие сделать подобное свойства называются логическими. Посмотрите на пример:

У нас есть карточка, содержащая аватар и текст. В макете слева направо поле расположено справа от аватара и наоборот, в макете слева направо поле отражено и расположено слева. Вот так это пишется без логических свойств:

.avatar {  margin-right: 1rem;}html[dir="rtl"] .avatar {  margin-right: 0;  margin-left: 1rem;}

Обратите внимание, что margin-rightв макете справа налево сброшено в 0, оно здесь не нужно. Представьте, что мы делаем это для большого проекта; кода слишком много. Но логические свойства решают проблему.

.avatar {  margin-inline-end: 1rem;}

Нам нужно только установить margin-inline-end, и свойство будет работать по-разному в зависимости от направления в HTML-документе. Мощно, правда?

Разница между inline и block

Используя логические свойства, вы обычно видите inline млм block. Давайте посмотрим, что они означают.

Смысл inlineи blockменяется исходя из режима письма. В языках вроде английского inlineнаправлен горизонтально, а block вертикально. В языках вроде японского всё наоборот: inlineнаправлено вертикально, block горизонтально.

Что означает inline?

В подобных английскому и арабскому языках inlineнаправлено горизонтально. В английском start указывает на левую (left) сторону в макетах слева направо (на английском языке) и он же указывает на правую (right) сторону в арабских макетах, которые справа налево. В макетах справа налево start указывает на правую сторону, end на левую.

В примере ниже круг имеет поле (margin) с правой стороны. В макетах справа налево поле должно быть слева. Запомните, что свойства start и end зависят от контекста направления макета:

Визуализация начала и конца

Начало и конец улицы

Чтобы прояснить, что же означают start и end, я покажу пример на картинке:

Мне нравится представлять это как начало и конец улицы. Когда направление слева направо, начало находится слева, а конец справа. Когда направление справа налево, всё наоборот.

Направление чтения

Другой способ запомнить принцип думать о направлении чтения. Английский текст начинается слева и заканчивается справа, арабский текст начинается справа и заканчивается слева.

Какие свойства можно применять как логические?

Большую часть свойств CSS можно применять как логические. Вот основные из них:

  • размеры: высота, ширина (height, width);

  • margin, border, padding, их подвиды;

  • обтекание (floating), позиционирование;

  • выравнивание текста.

Я не могу перечислить все логические свойства здесь: их много. Пожалуйста, прочитайте весь список на MDN.

Примеры и применение

Первый пример

Теперь, когда я рассказал об основах, позвольте мне показать пример UI, чтобы убедиться, что у вас есть твёрдое понимание.

У нас есть компонент со следующими свойствами:

  • left-padding и right-padding;

  • рамка (border) с левой стороны;

  • поле (margin) для иконки.

Вот так можно справиться с макетом слева направо.

.card {  padding-left: 2.5rem;  padding-right: 1rem;  border-left: 6px solid blue;}.card__icon {  margin-right: 1rem;}

А так с макетом справа налево; направления должны быть отражены.

html[dir="rtl"] .card {  padding-right: 2.5rem;  padding-left: 1rem;  border-left: 0;  border-right: 6px solid blue;}html[dir="rtl"] .card__icon {  margin-right: 1rem;}

И снова много работы. Но мы можем минимизировать CSS-код, вот так:

.card {  padding-inline-start: 2.5rem;  padding-inline-end: 1rem;  border-inline-start: 6px solid blue;}.card__icon {  margin-inline-end: 1rem;}

Второй пример: выравнивание текста

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

В английском подобное выравнивается справа, в арабском слева. Это правило прекрасный кандидат, чтобы продемонстрировать логические свойства CSS.

.indicator {  text-align: end;}

Вот как мы описали бы изложенное выше без логических свойств:

.indicator {  text-align: right;}html[dir="rtl"] .indicator {  text-align: left;}

Третий пример: позиционирование

Когда какой-то элемент позиционируется абсолютно, мы должны уделить внимание свойствам right и left:

.menu__toggle {  position: absolute;  right: 1rem;  top: 1rem;}html[dir="rtl"] .menu__toggle {  right: auto;  left: 1rem;}

Мы можем сократить код выше при помощи свойства inset Его поддержка не идеальна, но за ним будущее. Свойство inset-inline-endв макетах слева направо эквивалент правой стороны, а в макетах справа налево эквивалент левой стороны для макетов справа налево.Код выше можно написать так:

.menu__toggle {  position: absolute;  inset-inline-end: 1rem;  top: 1rem;}

Кроме того, top может выступать как inset-block-start, но это не нужно в нашем случае: мы не работаем с японским или с веб-сайтом на восточном языке.

Пример 4: float

Вы можете удивиться применению float в 2021 году. Когда у нас есть фигура и мы хотим, чтобы текст её обтекал, без старого доброго свойства floatэто не будет работать. Вот, как мы можем воплотить идею:

img {  float: left;  shape-outside: circle(50%);  margin-right: 20px;}

Код работает в макетах слева направо, для направления справа налево код CSS будет вроде такого:

html[dir="rtl"] img {  float: right;  margin-right: 0;  margin-left: 20px;}

При помощи логических свойств код на CSS сокращается, вот так:

img {  float: inline-start;  shape-outside: circle(50%);  margin-inline-end: 20px;}

Намного проще, правда?

Логические по своей природе свойства

Grid и flexbox по умолчанию логические свойства. Это означает, что они отражают направление автоматически. При помощи этих свойств CSS-код сеток и компонентов для мультиязычных сайтов сокращается до минимума.

В следующем примере у нас grid-обёртка. Обратите внимание, что элементы упорядочены согласно направления.

Чего бы мне хотелось

Единственное моё желание на данный момент, чтобы свойство background-colorстало логическим.

Зачем? Чтобы добавить иконку как изображение фона так, чтобы она разворачивалась в зависимости от направления. К сожалению, свойства вроде background-position-inlineу нас нет. Вот, что я напишу сейчас.

.input {  background: url("mail.svg") left 0.5rem center/24px no-repeat;  padding-inline-start: 2.4rem;}html[dir="rtl"] {  background: url("icon.svg") right 0.5rem center/24px no-repeat;}

Если вы хотите больше узнать о стилизации справа налево, написал о ней расширенное руководство. Надеюсь, оно вам понравится. А если хотите больше уделить время веб-разработке, то у нас как раз скоро стартует новый поток соответствующего курса.

Узнайте, как прокачаться в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Новостной дайджест событий из мира FPGAПЛИС 007 (2020_12)

31.12.2020 12:04:32 | Автор: admin

Здравствуйте друзья.


Продолжаем публиковать новости из мира FPGA/ПЛИС.


В 2020 опубликовано 238 новостей, запущены FPGA стримы и проведена первая отечественная FPGA конференция. Подборка за декабрьи ссылки на все упоминания под катом.




Ссылки:


  • Краткий 90-минутный видео-обзор прошедших событий в FPGA отрасли здесь
  • Материалы прошедшей FPGA конференции и ссылки на материалы здесьи отчет на хабре
  • Записи FPGA стримов здесь


PS: Стримы проводят ребята вот с этого проекта. Подкидывайте им идеи для стримов или присоединяйтесь в качестве гостя, если надумаете рассказать что-то интересное из мира FPGA/ПЛИС



FPGA декабрь новости



Зимний хакатон от QuickSilicon


Выполнение MicroBlaze приложений на PSU DDR в Vitis


Инструменты FPGA с открытым исходным кодом и поддержка Renode для MCU Core-V


Решаем проблему разбиения чисел на PYNQ


Следующий уровень светодиодного стрима


Небольшой бесплатный курс по VHDL на Udemy


Модельное проектирование ПЛИС и ASIC в контексте функциональной безопасности


Школа FPGA/SoC для применения в атомной промышленности и связанной с ней приборостроении


UVM обновилась согласно стандарту IEEE 1800.2-2020


Доступны материалы конференции Synopsys Verification Day 2020


Silexica запускает первый коммерческий плагин для Vitis HLS


Реализация интерпретатора CHIP-8 на Verilog


Установка Cocotb на Windows 10 для повышения производительности проверки проектов ПЛИС


ECPIX-5 современная отладочная плата на Lattice ECP5


Релиз Sigasi Studio 4.10


Глубокое обучение на FPGA


Конкурс от QuickLogic совместно с SensiML


Qomu MCU + eFPGA Development Kit, который помещается внутри USB-порта


Вебинар: Верификация с использованием OSVVM


Светодиодно-ленточный релакс FPGA стрим сегодня в 20:00 Мск


Ускорения отладки RTL для ПЛИС


О разработке на Плис в соответствии с DO254


Самоконфигурируемая трехмерная мультиПЛИСовая адаптивная платформа


Microchips Анонсировала доступность PolarFire для космического применения


Опубликованы материалы конференции Nokia и Intel


FPGA конференция в Сколково


Intel Open FPGA Stack Простая разработка пользовательских платформ


Изучаем Vivado Methodology Report


Все воркшопы Адама Тейлора в этом году


HBM2 и тензорные блоки ключевые особенности Intel FPGA


Запись субботнего стрима GoWin первое знакомство доступна на Youtube


Обзор научных работ, связанных с FPGA


Компания Samsung разработала прототип голографического дисплея с использованием FPGA


Повышение производительности разработки с Vivado и SystemVerilog


Новые возможности VHDL2019


FPGA конференция и хакатон от Intel и Nokia


Саммит разработчиков oneAPI 2020


Вебинар: Accelerating Data Channels to 112 Gbps PAM4: A Case Study in Real-World FPGA Implementation


Освоение DPC++ для программирования гетерогенных систем с использованием C++ и SYCL


Реализация глубоких нейронных сетей на ПЛИС


Делаем UART на HLS


QuickLogic присоединяется к партнерской программе Samsung SAFE IP



Это был заключительный новостной дайджест в этом году. Надеюсь, что среди опубликованных подборок за год вы смогли найти для себя что-то новое. Мы продолжим делать новостные дайджесты по тематике FPGA, давая вам возможность быть в курсе последних новинок и событий в мире программируемой логики.


Подробнее..
Категории: Новости , Дайджест , Intel , Fpga , Gowin , Плис , Rtl , Lattice , Risc-v , Xilinx , Hdl , Migen , Litex

Из песочницы Расчет временных ограничений для ПЛИС простым языком

16.07.2020 14:23:13 | Автор: admin
Здравствуйте. Эта статья написана для самых-самых новичков в мире ПЛИС. В ней я попытаюсь максимально просто и понятно рассказать что такое временные ограничения (timing constraints), накладываемые на проекты под ПЛИС.

Статья создана на основе собственного опыта попыток объяснить тему самому себе, студентам-практикантам и любопытным коллегам так, чтобы не погружаться в заумные академические дебри, а максимально просто, прозрачно, на пальцах. Я учился работать с ПЛИС без учебы и подготовки и знаю по своему опыту как трудно что-то понять не имея теоретического базиса в этой теме и в схемотехнике. Если на данную статью наткнется некий мэтр и воскликнет, что описанное элементарно, то посмею не согласиться. Для какого-нибудь студента четвертого курса статья будет полезной и поможет разобраться во всех этих слэках, сетапах и холдах.

В статье я буду использовать термины с дублированием их английского варианта в скобках. Это делается потому, что единая терминология не устоялась, а с дублированием проще понять о каком понятии идет речь и при необходимости найти информацию о нем в англоязычных источниках.

Введение


Проведу короткое введение на языке простых понятий.

Для того, чтобы в ПЛИС что-то работало, в нее нужно загрузить (залить, зашить) файл прошивки, с помощью программатора и утилиты прошивания. Файл прошивки является продуктом компиляции САПРом некоторого проекта папки с файлами, каждый из которых описывает какую-либо сторону проекта. В простых случаях пользователь описывает сам лишь файлы с исходным кодом, файл с распиновкой и файл с временными ограничениями. Из этой триады только файл временных ограничений является формально необязательной частью проекта. Собственно, если ваш проект не содержит частот выше 30-50 МГц, то вполне вероятно, что этот файл и не пригодится. Однако, если проект содержит высокие тактовые частоты и не укомплектован файлом временных ограничений, то вы не узнаете о том, что ваш проект не будет успевать обрабатывать данные.

Файл временных ограничений призван дать компилятору необходимые указания для расчета всех длительностей передач данных в ПЛИС. Пользуясь результатами такого расчета разработчик может видеть в каких частях проекта есть запас по времени, а следовательно и по частоте, а где такого запаса нет.

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

Таким образом, синхронные схемы состоят из межрегистровых передач данных (RTL, register transfer logic, r2r transfer). И ключевой аспект временного анализа состоит в измерении слэка (slack). Это слово буквально переводится как провисание, запас по времени, но в русскоязычной среде чаще употребляют кальку с английского слэк. В рамках межрегистровой передачи речь идет о слэках предустановки (Setup) и слэках удержания (Hold).

Межрегистровая передача


Межрегистровая передача (рис. 1) рассматривается как система из двух последовательно включенных регистров, которые работают на синхронных в общем случае клоках. В простом случае на одном клоке. Один регистр является источником (source), а другой является получателем данных (destination). Между ними на пути данных находится некая произвольно определенная пользователем комбинационная логика. Она несинхронная так как не имеет в себе элементов памяти с синхронизирующим сигналом, наподобие регистров. Эта логика и есть то поведение, те логические операции, которые пользователь описывает своим кодом. Регистры это те однобитные переменные, которым пользователь дает имена в коде и оперирует по отдельности, либо объединяя в вектора и массивы.

image
Рис. 1. Схема передачи данных от регистра к регистру

Существует два понятия, связанные с приемом данных регистром-получателем: Setup time и Hold time. Они очерчивают собой диапазон времени, в течение которого сигнал на входе получателя должен быть стабильным и актуальным. Стабильным по существу означает, что его напряжение должно быть очень близко к одному из двух логических состояний 0 или 1, а не болтаться между ними с вероятностью перепутывания. Актуальным означает, что этот бит информации должен по смыслу относиться к этому такту клока, который его захватит, а не запоздавший бит от предыдущего такта.

Setup time время предустановки, минимальное время, за которое до прихода фронта клока сигнал данных уже должен установиться в стабильное состояние.

Hold time время удержания, минимальное время, которое после прихода фронта клока сигнал данных должен всё ещё удерживаться в стабильном состоянии.

То есть данные на входе получателя должны быть стабильными и актуальными не только в момент прихода фронта клока, но и на протяжении некоторого защитного интервала времени вокруг него (рис.2), длительностью не менее (Setup_time + Hold_time).

image
Рис. 2. Смысл Setup Time и Hold time как защитного интервала

Величины Setup time и Hold time жестко определены производителем ПЛИС. Они зависят от технологии производства кристалла и для анализа считаются константами, одинаковыми для каждого регистра в кристалле. В любом случае, эти величины никак не зависят от пользователя, их учет является задачей только для утилиты временного анализа. Нам важно только знать что они существуют и не равны нулю.

Суть временного анализа заключается в том, чтобы для каждой пары регистров в проекте, между которыми есть прямая передача данных на синхронных клоках, рассчитать запасы по времени (слэки), которые есть у данных на то, чтобы быть стабильными в течение защитного интервала. Таких r2r пар в проекте много, тысячи, а то и миллионы, но каждая из них должна быть проанализирована для того, чтобы убедиться в работоспособности проекта.

Слэков, соответственно, тоже два Setup Slack и Hold Slack (рис.3).

Setup Slack характеризует собой запас по времени, который имеют данные от момента стабилизации до начала интервала Setup time.

Hold Slack характеризует собой запас по времени, который имеют данные от окончания интервала Hold time до потери данными стабильности.

Слэки должны быть положительными и на всякий случай чем больше тем лучше. Если слэк отрицательный то условие стабильности данных на входе не выполняется и данные будут биться.

image
Рис. 3. Положение слэков во времени

Расчет слэков


Теперь перейдем к тому, как эти слэки рассчитываются. Начнем с Setup Slack.
Рассмотрим схему передачи данных на рис. 4.

image
Рис. 4. Схема передачи данных

Здесь мы вводим такие понятия как фронт запуска, фронт захвата, момент прибытия данных, момент ожидания данных и момент прибытия клока.

Фронт запуска (Launch Edge) это фронт клока, пришедший на вход регистра-источника и запустивший процесс передачи данных.

Фронт захвата (Latch Edge) это фронт клока, следующий после Launch Edge через один период клока, который приходит на регистр-получатель и заставляет его захватить данные на входе.

Момент прибытия данных (Data Arrival Time) определяется как время фактического прибытия данных на регистр-получатель.

Момент ожидания данных (Data Required Time) определяется как время, за которое данные должны дойти до получателя до наступления времени предустановки на регистре-получателе.

Момент прибытия клока (Clock Arrival Time) определяется как время прохождения фронта захвата от тактового входа всей схемы к тактовому входу получателя.
Под тактовым входом всей системы обычно понимается выход глобального клокового буфера или выход PLL, то есть единая точка, из которой тактовый сигнал расходится до всех регистров своего тактового домена. В самом примитивном случае это ножка ПЛИС, к которой подведен тактовый генератор.

Как соотносится момент прибытия данных с фронтом запуска?

Мы рассматриваем прибытие данных, как прохождение через цепь с регистром некоторого события, инициированного фронтом запуска.

Фронт запуска появляется на тактовом входе системы, затем он за некоторое время доходит до входа регистра-источника, затем за некоторое этот регистр срабатывает и отдает на выход новые данные, затем эти данные проходят через цепи комбинационной логики до регистра-получателя. Рассматривается самый медленный вариант прохода данных, поэтому двое слагаемых идут с приставкой max.

$Data Arrival Time = Launch Edge + \max t_{CLK} + t_{CO} + \max t_D $


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

Слагаемое $\max t_{CLK}$ это максимальное время, за которое фронт запуска дойдет до тактового входа источника. Анализатор как правило не оценивает точно это время, он просто берет диапазон времени от точно не менее чем до точно не более чем и в данную формулу подставляет верхнюю границу точно не более чем. Эта величина не зависит от пользователя. Компилятор сам решает где расположить регистр на кристалле и сам учитывает время прохождения клока до него. Сеть соединений, по которым тактовый сигнал расходится к регистрам, спроектирована таким образом, чтобы тактовый сигнал доходил до любого регистра практически за одинаковое время. Поэтому на самом деле разница между $\max t_{CLK}$ и $\min t_{CLK}$ крайне мала, но все же учитывается.

Слагаемое $t_{CO}$ это время срабатывания регистра (clock-to-output time), которое регистр тратит на то, чтобы увидев фронт на тактовом входе поменять данные на своем выходе. Анализатор считает эту величину равной для всех регистров на кристалле. Эта величина не зависит от пользователя.

Последнее слагаемое $\max t_D$ это максимальное время прохождения события (данных) через комбинационную логику между регистрами, которая определяется пользователем. Вот эта величина как раз сильно зависит от пользователя. Она выражает степень громоздкости, неаккуратности создания проекта пользователем. Т.е. слишком сложные аппаратные конструкции, требующие слишком много комбинационной логики, дадут и слишком большое время прохождения данных через эту логику.

Момент прибытия клока на получатель рассчитывается проще:

$Clock Arrival Time = Latch Edge + \min t_{CLK}' $


Это момент, в который фронт захвата дойдет до тактового входа регистра-получателя.
Слагаемое $\min t_{CLK}'$ это минимальное время, за которое фронт захвата дойдет до тактового входа получателя, то есть по аналогии с предыдущей формулой это время точно не менее чем. Черточка в данном случае означает что речь идет о тактовом входе получателя, а не источника.

Момент ожидания данных определяется как время, за которое данные должны дойти к получателю до наступления времени предустановки на регистре-получателе:

$Data Required Time = Clock Arrival Time t_{SU} CSU$


Слагаемое $t_{SU}$ это уже известное нам Setup time, которое считается одинаковым для каждого регистра на кристалле. Это время не зависит от пользователя.

Слагаемое $CSU$ это Clock Setup Uncertainty, неопределенность времени предустановки. Как и любая другая неопределенность во временном анализе CSU не является физическим процессом, а является способом отразить в анализе влияние джиттера или просто способом ввести в анализ защитный интервал времени на всякий случай. Простыми словами, это запас времени на учтение сложноописываемых процессов.

Теперь, когда эти термины определены, мы можем определить слэк предустановки как разницу между временем, которое разрешено потратить на путь до получателя, и временем, которое этот путь фактически займет.

$Clock Setup Slack = Data Required Time Data Arrival Time $


Теперь раскроем эти слагаемые и немного переставим местами:

$Clock Setup Slack = Latch Edge + \min t_{CLK}' t_{SU} CSU -$

$ (Launch Edge + \max t_{CLK} + t_{CO} + \max t_D) $

$Clock Setup Slack = Latch Edge-Launch Edge-\max t_D $

$-CSU+( \min t_{CLK}'-\max t_{CLK}) t_{SU} t_{CO}$

$=Period-\max t_D CSU+ \min t_{CS} t_{SU} t_{CO}$


Здесь появились новые слагаемые.

Про период понятно, это период тактовой частоты, т.е. время между Launch Edge и Latch Edge.
Слагаемое $\min t_{CS}$ это растекание клока (clock skew) минимальная величина разброса времени прихода одного фронта клока от тактового входа системы до разные синхронные регистры. Минимальное растекание клока определяется как разница между наименьшей задержкой клока к получателю и наибольшей задержкой клока к источнику $\min t_{CS} = \min t_{CLK}' - \max t_{CLK}$. Анализатор не делает разницы в оценке этого времени для разных регистров на кристалле.

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

На рисунке 5 показано как формулу слэка можно представить графически:

image
Рис. 5. Графическое представление выражения Setup Slack

Здесь показаны соотношения на фоне тактового сигнала, причем это тактовый сигнал на тактовом входе системы, а не на входе какого-либо из регистров.

Теперь похожим образом рассчитаем слэк удержания.

Его тоже можно представить выражением, в котором слагаемые поменялись знаками:

$Clock Hold Slack = Data Arrival Time Data Required Time$


Вот только эти слагаемые теперь рассматриваются с другой стороны.

$Data Arrival Time = Launch Edge + \min t_{CLK} + t_{CO} + \min t_D $


Теперь здесь рассматривается самый быстрый вариант прохода данных и там, где было max стало min.

Момент прибытия фронта клока также рассматривается в ином ключе, как самый поздний из возможных:

$Clock Arrival Time = Latch Edge + \max t_{CLK}' $


Важно отметить, что в случае рассмотрения Hold Slack фронты Launch Edge и Latch Edge это один и тот же фронт, а не два разных фронта, разделенных периодом клока. Регистру-получателю в данной ситуации нужно успеть удержать данные на входе в течение времени удержания от прихода фронта клока. Но данные меняет на его входе этот же фронт, пришедший где-то в другом месте на регистр-источник. Поэтому в анализе слэка удержания разница $Latch Edge - Launch Edge$ равна нулю, а не периоду.

Требуемое время в данном случае определяется как время, за которое данные должны не меняться на входе данных получателя, чтобы не зацепить время удержания:

$Data Required Time = Clock Arrival Time + t_H + CHU$


Слагаемое $t_H$ это уже известное нам Hold time, время удержания. Оно считается одинаковым для каждого регистра на кристалле и не зависит от пользователя.
Слагаемое $CHU$ это Clock Hold Uncertainty, неопределенность времени удержания. Оно несет в общем тот же смысл, что и CSU, да и как правило берётся равным ему.

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

$Clock Hold Slack = \min t_D-\max t_{CS} + t_{CO} -t_H - CHU$

$\max t_{CS} = \max t_{CLK}'-\min t_{CLK}$


Ура, мы узнали как рассчитываются слэки. Как использовать эти знания?
Давайте посмотрим на выражения слэков еще раз:

$Clock Setup Slack=Period-\max t_D CSU+ \min t_{CS} t_{SU} t_{CO}$

$Clock Hold Slack = \min t_D -\max t_{CS} + t_{CO} -t_H - CHU$


Если какие-то слэки проекта стали отрицательными, то поменять их мы можем поменяв их слагаемые.

Мы видим слагаемые, которые не зависят от пользователя, а зависят только от технологии кристалла. Это $t_{SU}, t_H, t_{CS}, t_{CO}$.
Мы видим слагаемые CSU и CHU, которые анализатор как правило берет равными параметру CU Clock Uncertainty, нестабильность тактовой частоты. Этот параметр вообще говоря невелик, десятки пикосекунд. Он указывается пользователем в файле ограничений. А пользователь его в свою очередь берет из спецификации на тактовый генератор. Считается что клоковый буфер или внутренняя PLL ПЛИС, которые принимают внешний клок от генератора и преобразуют во внутренний клок на тактовый вход системы, сохраняют величину CU той же, что получена от генератора. Если CU не указать, то анализатор выставит ей некоторое значение по умолчанию, например Quartus ставит 20 пс. В общем случае это слагаемое говорит нам о том, что лучше использовать для тактирования высокостабильные генераторы с величиной нестабильности порядка 20-60 пс.

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

И, наконец, слагаемое $t_D$ характеризует по сути эффективность написанного кода. Отсюда следует и основной способ решения проблем со слэками переписать как следует. Большое время $t_D$ появляется у слишком сложных аппаратных конструкции, требующих слишком много комбинационной логики. Если такие сложные конструкции появились у вас в проекте, то классический способ решения проблемы разбить одну сложную r2r передачу на несколько простых, вставив еще 1-2 регистра в последовательность операций. При этом вырастет задержка в тактах на выполнение операции, но зато увеличится быстродействие операции. Например, сложение за один такт нескольких векторов это не очень хорошая идея. Складывать несколько векторов лучше по очереди, с промежуточными суммами. Некоторые сложные конструкции бывает невозможно разбить на конвейер из нескольких простых тогда такую логику нужно переписывать как-нибудь принципиально иначе.

Дополнение


Выше был представлен способ расчета слэков, характерный для человеческого представления о происходящих процессах. Тут фронт идет..., данные идут.... Если интересно, то в качестве дополнения расскажу как представляет себе данные расчеты анализатор временных ограничений.

Анализатор группирует слагаемые иначе, исходя из своих машинных резонов.
Он оперирует понятиями Clock Setup Relationship (SR) и
Clock Hold Relationship (HR) которые можно перевести как соотношение времени между инициирующим фронтами для предустановки и удержания соответственно.

$SR = Setup Latch Edge - Setup Launch Edge-CSU$

$HR = Hold Latch Edge - Hold Launch Edge-CHU$


На рисунке 6 можно увидеть о каких фронтах идет речь:

image
Рис. 6. Фронты, используемые в расчетах слэков.

Можно сразу преобразовать полученные выражения в более понятный вид:

$SR = Period-CSU$

$HR = CHU$


Наибольшее межрегистровое время (Largest r2r Required) это максимальное время, имеющееся для того, чтобы данные дошли к получателю до начала интервала предустановки:

$Largest\ r2r\ Required = SR + \min t_{CS} t_{CO} t_{SU}$


Самая длинная межрегистровая задержка (longest r2r Delay) это время, необходимое для передачи данных из исходного регистра в регистр назначения по самому длинному пути:

$Longest\ r2r\ Delay = \max t_D$


Теперь мы можем определить слэк предустановки как разницу между временем, доступным для достижения регистра назначения, и фактическим временем, чтобы добраться туда:

$ClockSetupSlack = Largest\ r2r\ Required Longest\ r2r\ Delay$


Раскрытие слагаемых этой формулы даст нам уже знакомое представление слэка предустановки:

$Clock Setup Slack=Period-\max t_D CSU+ \min t_{CS} t_{SU} t_{CO}$


Теперь про слэк удержания. Наименьшее межрегистровое требование (smallest r2r Requirement) это время, необходимое для удержания данных на входе регистра назначения:

$Smallest\ r2r\ Required = HR + \max t_{CS} \min t_{CO} + t_H$


Кратчайшая межрегистровая задержка:

$Shortest\ r2r\ Delay = t_D$


Теперь определяем слэк предустановки как разницу между быстрейшим временем ухода данных со входа получателя и временем, которое требуется их там удерживать:

$ClockHoldSlack = Shortest\ r2r\ Delay Smallest\ r2r\ Required$


При раскрытии слагаемых выражение также принимает уже знакомый вид:

$Clock Hold Slack = \min t_D -\max t_{CS} + t_{CO} -t_H - CHU$


Теперь вы знаете что такое слэк, а значит можете самостоятельно изучать отчеты анализатора временных ограничений и отлаживать быстродействие своего проекта.
Подробнее..
Категории: Fpga , Slack , Constraints , Altera , Rtl

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru