D6 От RTL-кода до готового к tapeout
На этапе E вы уже прошли полный процесс проектирования процессора minirv. Теперь подробнее рассмотрим отдельные шаги этого процесса:
- Функциональная верификация — проверка с помощью RTL-симуляции того, соответствует ли поведение схемы, описанной RTL-кодом, ожиданиям
- Оценка схемы — преобразование логических элементов RTL-кода в нетлист физических стандартных ячеек (standard cells) с помощью синтезатора
- Физическое проектирование — преобразование нетлист стандартные ячейки в топологию, готовый к tapeout
RTL-симуляция — функциональная верификация
Вы уже использовали Verilator для RTL-симуляции, но, возможно, пока не понимаете, как RTL-симуляция работает внутри.
На самом деле сущность RTL-симуляции заключается в использовании программного обеспечения для имитации поведения аппаратной схемы. Поэтому, чтобы реализовать RTL-симуляцию, нам необходимо подумать, как использовать конечный автомат C-программы для реализации конечного автомата цифровой схемы. Для этого сначала вспомним C-программу с точки зрения модели конечного автомата:
| C-программа | Цифровая схема | |
|---|---|---|
| Состояние | Переменные | Последовательностная логическая схема |
| Событие-воздействие | Выполнение операторов | Обработка комбинационной логикой |
| Правило перехода состояния | Семантика операторов | Комбинационная логика |
Чтобы реализовать конечный автомат цифровой схемы с помощью конечного автомата C-программы, нам необходимо разработать C-программу со следующей функциональностью:
- Представлять состояние схемы состоянием C-программы, то есть реализовать последовательностную логическую схему с помощью переменных C-программы.
- Реализовать правила переходов состояния цифровой схемы с помощью правил переходов состояния C-программы, то есть реализовать логику комбинационной схемы с помощью операторов языка C.
Вспомним Verilog-код модуля бегущего огня:
module light(
input clk,
input rst,
output reg [15:0] led
);
reg [31:0] count;
always @(posedge clk) begin
if (rst) begin led <= 1; count <= 0; end
else begin
if (count == 0) led <= {led[14:0], led[15]};
count <= (count >= 5000000 ? 32'b0 : count + 1);
end
end
endmodule
Согласно схеме, описанной приведённым выше Verilog-кодом, мы можем разработать C-программу для выполнения RTL-уровневой симуляции этой схемы:
#include <stdio.h>
#include <stdint.h>
#define _CONCAT(x, y) x ## y
#define CONCAT(x, y) _CONCAT(x, y)
#define BITMASK(bits) ((1ull << (bits)) - 1)
// similar to x[hi:lo] in verilog
#define BITS(x, hi, lo) (((x) >> (lo)) & BITMASK((hi) - (lo) + 1))
#define DEF_WIRE(name, w) uint64_t name : w
#define DEF_REG(name, w) uint64_t name : w; \
uint64_t CONCAT(name, _next) : w; \
uint64_t CONCAT(name, _update) : 1
#define EVAL(c, name, val) do { \
c->CONCAT(name, _next) = (val); \
c->CONCAT(name, _update) = 1; \
} while (0)
#define UPDATE(c, name) do { \
if (c->CONCAT(name, _update)) { \
c->name = c->CONCAT(name, _next); \
} \
} while (0)
typedef struct {
DEF_WIRE(clk, 1);
DEF_WIRE(rst, 1);
DEF_REG (led, 16);
DEF_REG (count, 32);
} Circuit;
static Circuit circuit;
static void cycle(Circuit *c) {
c->led_update = 0;
c->count_update = 0;
if (c->rst) {
EVAL(c, led, 1);
EVAL(c, count, 0);
} else {
if (c->count == 0) {
EVAL(c, led, (BITS(c->led, 14, 0) << 1) | BITS(c->led, 15, 15));
}
EVAL(c, count, c->count >= 5000000 ? 0 : c->count + 1);
}
UPDATE(c, led);
UPDATE(c, count);
}
static void reset(Circuit *c) {
c->rst = 1;
cycle(c);
c->rst = 0;
}
static void display(Circuit *c) {
static uint16_t last_led = 0;
if (last_led != c->led) { // only update display when c->led changes
for (int i = 0; i < 16; i ++) {
putchar(BITS(c->led, i, i) ? 'o' : '.');
}
putchar('\r');
fflush(stdout);
last_led = c->led;
}
}
int main() {
reset(&circuit);
while (1) {
cycle(&circuit);
display(&circuit);
}
return 0;
}
Программа реализует последовательностную логическую схему посредством структурной переменной circuit, которая включает led и count. Хотя clk и rst не относятся к последовательностной логической схеме, они являются частью состояния схемы как её входы, поэтому также присутствуют в структуре. Кроме того, программа реализует логику комбинационной схемы с помощью операторов языка C. Как видно, содержимое функции cycle() выше в основном является прямым переводом соответствующего Verilog-кода, за исключением введения некоторых промежуточных переменных с суффиксом next и флагов обновления с суффиксом update. Эти промежуточные переменные введены для реализации семантики неблокирующих присваиваний Verilog, то есть обновление соответствующих сигналов должно ждать до конца цикла. Поэтому во время симуляции результаты вычислений комбинационной логики сначала временно сохраняются в этих промежуточных переменных и устанавливаются флаги обновления; только в конце цикла результаты вычислений фактически записываются в переменные, соответствующие последовательностным логическим элементам, согласно флагам обновления.
Цикл while в функции main() показывает основной процесс RTL-симуляции: непрерывное выполнение функции cycle() реализует функцию «вычислить и обновить новое состояние на основе входов и текущего состояния». Именно это по сути и является способом работы цифровых схем. Однако перед входом в цикл while схему также необходимо сбросить с помощью функции reset(). Кроме того, хотя функция display() не относится к самой схеме, чтобы показать её функциональность, display() выводит соответствующий символ в зависимости от состояния каждого бита сигнала led, тем самым отображая эффект бегущего огня в терминале.
Приведённая выше программа симуляции написана вручную. Но если разработчикам пришлось бы вручную писать соответствующую программу симуляции для каждого проекта схемы, чтобы выполнять функциональную верификацию, это создало бы множество неудобств. Поэтому разработчики обычно используют программное обеспечение RTL-симулятора, которое автоматически преобразует RTL-код в C-программу, используемую для моделирования поведения схемы. Эта C-программа и является программой симуляции схемы, соответствующей RTL-коду.
Использованный вами ранее Verilator является примером такого RTL-симулятора.
Поведение Verilog при симуляции и стиль написания кода
Подобно стандарту языка C, семантика языка Verilog во время симуляции определяется стандартом Verilog. Глава 11 руководства раскрывает сущность языка Verilog. Эта глава небольшая — всего 5 страниц, — но содержит огромный объём информации (yzh считает эту часть настолько важной, что её стоило бы перенести ближе к началу, в главу 3 руководства). Однако эти основы не рассматриваются в традиционных учебниках и большинстве материалов по Verilog, поэтому подавляющее большинство разработчиков Verilog, даже некоторые специалисты с большим опытом, не знают о существовании этой семантики и потому не могут точно понимать различия между Verilog в двух сценариях использования: симуляции и синтезе.
Во введении стандарта Verilog сказано:
Он был разработан ... для различных средств проектирования, включая
верификацию, симуляцию, временной анализ, анализ тестируемости и синтез.
Это показывает, что Verilog был предложен для целого набора средств проектирования схем. Поэтому все эти инструменты можно рассматривать как конкретные реализации стандарта Verilog, включая инструменты симуляции, временного анализа, анализа тестируемости, синтеза и так далее. Однако слово simulation встречается в стандарте Verilog гораздо чаще (356 раз), чем synthesis (4 раза), поэтому стандарт Verilog всё же в большей степени ориентирован на инструменты симуляции.
Я умею писать Verilog — разве этого недостаточно? Зачем мне всё это знать?
На самом деле многие разработчики Verilog действительно не знают сущности Verilog, но всё равно могут проектировать схемы, поведение которых в основном соответствует ожиданиям, следуя определённым рекомендациям по стилю Verilog. Однако они не знают сущности, лежащей в основе этих рекомендаций, и не способны судить, корректна ли конкретная рекомендация. Когда при симуляции возникает неожиданная ситуация, они не могут проанализировать причину проблемы и вынуждены случайным образом менять код. Если исправить проблему не удаётся, они могут даже начать думать, что в симуляторе есть ошибка...
В качестве небольшого теста ниже приведено несколько рекомендаций и утверждений о Verilog, но некоторые из них неверны. Попробуйте найти их:
- Использование
#0может принудительно задержать присваивание до конца текущего момента времени симуляции. - В одном и том же блоке операторов
begin-endвыполнение нескольких неблокирующих присваиваний одной и той же переменной приводит к неопределённое поведение. - При описании комбинационных логических элементов с помощью блока
alwaysнельзя использовать неблокирующие присваивания. - Переменной нельзя присваивать значение в нескольких блоках
always. - Не рекомендуется использовать системную задачу
$display, поскольку иногда она не может корректно вывести значение переменной. $displayне может вывести результат неблокирующего присваивания.
Если вы планируете использовать Verilog в дальнейшей разработке и не можете определить, какие из приведённых выше утверждений верны, мы настоятельно рекомендуем внимательно разобраться в этом разделе.
Выполнение Verilog-кода
Мы знаем, что выполнение программы на C означает изменение состояния объектов в некотором порядке вычислений, соответствующем стандарту. Тогда что означает «выполнение» в Verilog? Чтобы получить точный ответ, необходимо обратиться к стандарту Verilog. Раздел 11.1 определяет, что означает «выполнение Verilog-кода»:
Элементы, составляющие Verilog HDL, могут использоваться для описания поведения
электронного оборудования на различных уровнях абстракции. HDL должен быть
параллельным языком программирования. Выполнение некоторых языковых конструкций
определяется параллельным выполнением блоков или процессов. Важно понимать,
какой порядок выполнения гарантирован пользователю, а какой является неопределённым.
Хотя Verilog HDL используется не только для симуляции, семантика языка определена
для симуляции, а всё остальное абстрагируется от этого базового определения.
Иными словами, язык Verilog используется для описания поведения аппаратуры на различных уровнях абстракции, включая системный уровень, поведенческий уровень, уровень RTL, gate level и транзисторный уровень. HDL является параллельным языком программирования, и выполнение некоторых языковых компонентов определяется как параллельное выполнение блоков кода или процессов. Для пользователя Verilog крайне важно понимать, какой порядок выполнения гарантирован стандартом, а какой является неопределённым. Хотя сценарии использования Verilog не ограничиваются симуляцией, семантика Verilog определяется для симуляции, а семантика остальных сценариев абстрагируется на основе этого базового определения.
Вы почувствовали, что ваше понимание Verilog перевернулось?
По сути Verilog действительно является параллельным языком программирования! Более того, стандарт языка Verilog определён для симуляции, а не для RTL-проектирования! Кроме того, в некоторых сценариях семантика Verilog является неопределённой! Это в некоторой степени похоже на неуточнённое поведение или неопределённое поведение языка C: необходимо понимать, какие стили написания кода создают неопределённость, а затем избегать таких стилей при использовании Verilog, тем самым гарантируя детерминированное поведение описываемого объекта.
Это означает, что семантика некоторого Verilog-кода может не соответствовать вашей интуиции или поведение при симуляции может отличаться от поведения после синтеза. Если раньше вы использовали Verilog и сталкивались с ситуацией «симуляция прошла, но на FPGA всё работает неправильно», после исключения специфических проблем FPGA, если причина всё ещё непонятна, очень вероятно, что вы не до конца поняли описанную выше сущность языка Verilog. Сейчас самое время углубить это понимание!
Событийная симуляция
Раздел 11.2 стандарта Verilog описывает процесс симуляции:
Verilog HDL определяется в терминах дискретной событийной модели выполнения.
Выберем несколько ключевых фрагментов и продолжим объяснение:
Процессы — это объекты, которые могут вычисляться, могут иметь состояние и могут
реагировать на изменения своих входов, формируя выходы. К процессам относятся
примитивы, модули, процедурные блоки initial и always, непрерывные присваивания,
асинхронные задачи и процедурные операторы присваивания.
В Verilog «процессы» — это объекты, которые могут вычисляться. У этих объектов есть собственное состояние, и когда их входы изменяются, они могут реагировать на изменения и формировать выходы. К процессам относятся примитивы, модули, процедурные блоки initial и always, непрерывные присваивания, асинхронные задачи и процедурные операторы присваивания.
Каждое изменение значения net или переменной в моделируемой схеме, а также
именованное событие, рассматривается как событие обновления.
Процессы чувствительны к событиям обновления. Когда выполняется событие
обновления, все процессы, чувствительные к нему, вычисляются в произвольном
порядке. Вычисление процесса также является событием и называется событием
вычисления.
В моделируемой схеме изменение значения net или переменной, а также именованное событие, рассматривается как «событие обновления». Процессы чувствительны к событиям обновления. После выполнения события обновления все чувствительные к нему процессы будут вычислены, причём порядок их вычисления произволен. Вычисление процесса само также является событием и называется «событие вычисления».
События могут происходить в разные моменты времени. Чтобы отслеживать события
и гарантировать их обработку в правильном порядке, события хранятся в очереди
событий, упорядоченной по времени симуляции. Помещение события в очередь
называется планированием события.
События происходят в разные моменты времени симуляции. Чтобы гарантировать обработку событий в правильном порядке, их необходимо хранить в очереди событий, упорядоченной по времени симуляции. Помещение события в очередь называется «планирование события».
Как видно, семантика компонентов языка Verilog целиком связана с событиями. Процесс симуляции — это процесс обработки этих событий в некотором корректном порядке. Во время обработки событий состояния объектов в схеме изменяются. Мы ожидаем, что эти изменения соответствуют ожидаемому поведению схемы, тем самым реализуя моделирование поведения аппаратной схемы.
Иерархическая очередь событий
Согласно стандарту Verilog, очередь событий логически содержит следующие 5 областей, каждая из которых используется для обработки соответствующего типа событий:
- Область активные события, обозначаемая как , хранит события, происходящие в текущий момент времени симуляции и готовые к обработке.
- Область неактивные события, обозначаемая как , хранит события, происходящие в текущий момент времени симуляции, но не подлежащие немедленной обработке; эти события могут быть обработаны только тогда, когда пуста.
- Область событий обновления неблокирующих присваиваний, обозначаемая как , хранит события, вычисление которых уже было выполнено ранее, но присваивание должно произойти в конце текущего времени симуляции; эти события могут быть обработаны только когда и пусты.
- Область события мониторинга, обозначаемая как , хранит события, связанные с операциями мониторинга; их можно обрабатывать только когда , и пусты.
- Область будущие события, обозначаемая как , хранит события, которые должны быть обработаны в будущие моменты времени симуляции.
Событие добавляется в разные области в зависимости от его типа, а затем по определённым правилам переносится в ; после обработки оно удаляется из очереди событий. Некоторые правила генерации событий выглядят следующим образом:
- Явная нулевая задержка (
#0) может приостановить соответствующий процесс и создаёт событие в . - Неблокирующее присваивание создаёт событие в .
- Системные задачи
$monitorи$strobeсоздают событие в в каждый момент времени симуляции. - Вычисление PLI-процессов создаёт событие в .
На основе описанного выше порядка обработки разных событий стандарт Verilog приводит эталонную реализацию движка обработки событий, являющегося основным циклом Verilog-симулятора:
while (there are events) {
if (no active events) {
if (there are inactive events) {
activate all inactive events;
} else if (there are nonblocking assign update events) {
activate all nonblocking assign update events;
} else if (there are monitor events) {
activate all monitor events;
} else {
advance T to the next event time;
activate all inactive events for time T;
}
}
E = any active event;
if (E is an update event) {
update the modified object;
add evaluation events for sensitive processes to event queue;
} else { /* shall be an evaluation event */
evaluate the process;
add update events to the event queue;
}
}
Движок обработки событий повторяет следующие операции:
- Если в есть события, извлечь одно событие
E- Если
Eявляется событием обновления:- Обновить соответствующий объект
- Добавить вычисления процессов, чувствительных к этому событию, в очередь событий как события вычисления
- Иначе
Eявляется событием вычисления:- Вычислить процесс
- Добавить поведение присваивания в очередь событий как событие обновления
- Если
- Иначе, то есть если пуста:
- Если не пуста, перенести все события из в
- Иначе, если не пуста, перенести все события из в
- Иначе, если не пуста, перенести все события из в
- Иначе:
- Продвинуть время симуляции на одну единицу
- Перенести все события из , относящиеся к текущему времени симуляции, в или в соответствии с их типами
Verilog-код != C-код
Для преподавателей цифровой схемотехники одна из самых неприятных проблем состоит в том, что при изучении Verilog студенты легко начинают писать Verilog-код с мышлением программиста на C. Даже если преподаватель много раз подчёркивает, что «Verilog нельзя писать как C», большинство студентов всё равно не понимают глубинный смысл этой фразы: если его нельзя писать как C, то что же тогда такое Verilog?
Именно поэтому здесь приводится содержимое стандарта Verilog — чтобы дать ответ на этот вопрос. Приведённый выше цикл обработки событий напрямую показывает разницу между Verilog-кодом и C-кодом. Возьмём i = i + 1: в C-программе под действием компилятора эта строка в конечном итоге превращается в инструкцию вроде addi a0, a0, 1, которая непосредственно выполняется процессором; в Verilog эта строка преобразуется в событие вычисления и событие обновления, которые выполняют операцию сложения и операцию присваивания под управлением движка обработки событий, а также порождают новые события в чувствительных к ним процессах.
На самом деле написанный вами Verilog-код в конечном счёте преобразуется в отдельные события согласно правилам стандарта. Симулятор обрабатывает эти события в некотором порядке, соответствующем стандарту, и через результаты этой обработки отображает совокупное поведение аппаратной схемы, тем самым моделируя её.
Планирование событий для операций присваивания
Согласно разделу 11.6 стандарта Verilog, операции присваивания преобразуются в поведенчески эквивалентные процессы и таким образом создают соответствующие события, которые затем обрабатываются симулятором. Рассмотрим несколько распространённых операций присваивания. Для простоты сначала будем считать, что информация о задержке (#) отсутствует.
- Непрерывное присваивание, то есть оператор
assign, соответствует процессу, чувствительному ко всем исходным операндам выражения. Когда значение выражения изменяется, создаётся событие обновления и добавляется в . В частности, процесс непрерывного присваивания создаёт событие вычисления в момент времени0, чтобы реализовать распространение констант. - Блокирующее присваивание внутри процесса сначала вычисляет правую часть выражения присваивания на основе текущих значений объектов, затем немедленно вычисляет целевой объект в левой части, обновляет его и генерирует события, вызванные этим обновлением. После этого выполнение процесса может последовательно перейти к следующему оператору или могут быть обработаны другие активные события.
- Неблокирующее присваивание внутри процесса сначала вычисляет правую часть выражения и целевой объект слева на основе текущих значений объектов, после чего создаёт событие в для текущего момента времени симуляции.
Новое понимание блокирующих и неблокирующих присваиваний
Для преподавателей цифровой схемотехники вторая большая проблема состоит в том, что студентам трудно понять различие между блокирующим присваиванием и неблокирующее присваивание. В языке C существует лишь один вид присваивания, а в Verilog их несколько. Чтобы действительно понять различие между этими способами присваивания, снова необходимо вернуться к сущности Verilog — событийной модели.
Вопреки интуиции многих людей, в событийной модели Verilog конкретную операцию выражения присваивания необходимо рассматривать как две подоперации: сначала операция вычисления, выполняющую вычисление правой части выражения, затем операция обновления, записывающую вычисленный результат в объект, указанный левой частью выражения.
Согласно описанному выше поведению планирования событий, главное различие между блокирующим и неблокирующим присваиваниями заключается именно в способе выполнения операции обновления. У блокирующего присваивания операция обновления выполняется немедленно вместе с операцией вычисления без создания отдельного событие обновления; у неблокирующего присваивания операция вычисления и операция обновления разделены. После выполнения операция вычисления создаётся событие обновления, принадлежащий , и это событие может быть обработано только когда и пусты. Именно из-за этого присваивание фактически происходит в разное время, различные события получают возможность увидеть результат присваивания в разные моменты, что влияет на поведение этих событий и в конечном счёте — на общее поведение схемы.
Используйте событийную модель для анализа поведения Verilog-кода
Рассмотрите следующий код. Предположим, что в момент времени t значения равны a = 1, b = 2, c = 3, d = 4, e = 5. Попробуйте с помощью событийной модели определить значения переменных в момент времени t+1.
always @(posedge clk) begin
b = a;
c <= b;
d = c;
e <= d;
a = e;
end
- Соединения портов — входное соединение
.a(expr)рассматривается как оператор непрерывного присваиванияassign a = expr;; выходное соединение.b(net)рассматривается какassign net = b;. - Функции и задачи — параметры при вызове передаются по значению. При возврате поведение «замены места вызова возвращаемым значением» обрабатывается как блокирующее присваивание.
Стандарт Verilog также определяет, как преобразовывать в события и другие случаи, включая задание задержек, использование procedural непрерывное присваивание, обработку поведения на транзисторный уровень и так далее. Когда вам потребуется разобраться с ними, обратитесь к соответствующим разделам руководства.
Порядок обработки событий
На самом деле порядок обработки событий не является на 100% детерминированным. Согласно определению стандарта Verilog, неопределённость в основном имеет два источника:
- Когда в очереди событий присутствует несколько активные события, порядок их обработки произволен.
- В behavioral модули операторы без контроля времени, то есть без выражений
#и@, не обязаны обрабатываться как единое событие. При вычислении оператора в behavioral module симулятор может в любой момент приостановить его выполнение и поместить оставшиеся операции в очередь событий как активное событие. Это позволяет чередовать выполнение разных процессов, но порядок такого чередования неопределён и не контролируется пользователем.
Почему Verilog вообще вводит такую неопределённость? Чтобы ответить на этот вопрос, необходимо вспомнить, как работает реальная аппаратная схема. Поведение аппаратных схем по своей природе параллельно: множество компонентов естественным образом работают одновременно.
- С точки зрения соответствия модели схемы реальной схеме нет причин задавать порядок работы между этими компонентами. Если искусственно зафиксировать такой порядок, модель уже не сможет полностью отражать работу реальной схемы. Особенно важно, что если в реальной схеме существует проблема, но модель не позволяет её выявить и вовремя исправить, моделирование теряет смысл.
- С точки зрения программной сущности симулятора он способен обрабатывать разные события только последовательно. Неопределённость, определённая стандартом Verilog, фактически является «ослаблением» требований к порядку обработки событий: если между двумя событиями нет зависимости, не требуется заставлять симулятор обрабатывать их в конкретном порядке. Более того, симулятор даже может применять некоторые методы параллельной оптимизации для событий без зависимостей, тем самым лучше имитируя параллельность компонентов схемы.
Чтобы полностью понимать поведение Verilog-кода, необходимо также учитывать определённость порядка обработки событий. Для удобства введём отношение порядка , где означает, что событие обрабатывается раньше события . Приведённый выше движок обработки событий фактически подразумевает некоторые правила порядка:
Правило порядка 1— если создаётся во время обработки , то , поскольку для обработки сначала должна завершиться обработка .Правило порядка 2— если в некоторый момент симуляции , и , то , поскольку движок сначала обрабатывает все события в , и только затем события в .
Помимо этих неявных правил, стандарт Verilog явно определяет следующие два правила:
Правило порядка 3— операторы внутри одного блокаbegin-endдолжны выполняться в порядке их записи. То есть для двух операторов и в одном блокеbegin-end, если , то выполняется раньше .Правило порядка 4— операции неблокирующего присваивания должны выполняться в порядке исполнения соответствующих операторов. То есть если , а операции вычисления соответствующих выражений присваивания — это и соответственно, причём , тогда .
Например, в стандарте Verilog приводится следующий пример:
initial begin
a <= 0; // (1)
a <= 1; // (2)
end
Используем для обозначения «событие вычисления выражения » и для обозначения «событие обновления объекта ». Тогда оператор (1) можно разложить на два события: и . Аналогично оператор (2) раскладывается на и . Применив приведённые выше правила порядка, получаем:
- По
Правилу порядка 1: и . - По
Правилу порядка 2: и . - По
Правилу порядка 3: . - По
Правилу порядка 4: .
Объединив эти выводы, получаем единственно возможный порядок: . То есть в этом примере симулятор может обрабатывать события только в таком порядке. Поэтому при симуляции объекту a сначала будет присвоено 0, а затем 1.
Симуляторы и программы симуляции
Вернёмся к примеру бегущего света и проанализируем порядок обработки событий в нём.
module light(
input clk,
input rst,
output reg [15:0] led
);
reg [31:0] count;
always @(posedge clk) begin
if (rst) begin led <= 1; count <= 0; end
else begin
if (count == 0) led <= {led[14:0], led[15]};
count <= (count >= 5000000 ? 32'b0 : count + 1);
end
end
endmodule
Предположим, приходит фронт clk. В этот момент времени симуляции могут возникнуть следующие события:
Применив правила порядка, получаем:
- При
rst = 1: . - При
rst = 0иcount = 0: . - При
rst = 0иcount != 0: .
Получив этот порядок обработки событий, мы можем напрямую реализовать его C-кодом. Макросы EVAL() и UPDATE() ниже реализуют семантику события вычисления и события обновления соответственно:
#define EVAL(c, name, val) do { \
c->CONCAT(name, _next) = (val); \
c->CONCAT(name, _update) = 1; \
} while (0)
#define UPDATE(c, name) do { \
if (c->CONCAT(name, _update)) { \
c->name = c->CONCAT(name, _next); \
} \
} while (0)
static void cycle(Circuit *c) {
c->led_update = 0;
c->count_update = 0;
if (c->rst) {
EVAL(c, led, 1);
EVAL(c, count, 0);
} else {
if (c->count == 0) {
EVAL(c, led, (BITS(c->led, 14, 0) << 1) | BITS(c->led, 15, 15));
}
EVAL(c, count, c->count >= 5000000 ? 0 : c->count + 1);
}
UPDATE(c, led);
UPDATE(c, count);
}
Хотя этот C-код реализует моделирование схемы бегущего света, в нём отсутствует понятие «очереди событий»: события, определённые стандартом Verilog, не извлекаются из очереди в этом C-коде, а напрямую «развёрнуты» в определённом порядке, соответствующем правилам стандарта Verilog. На самом деле определение очереди событий в стандарте Verilog является логическим:
Очередь событий Verilog логически разделена на пять различных областей.
Поэтому программа симуляции не обязана явно поддерживать порядок между событиями с помощью структуры данных queue; достаточно, чтобы порядок обработки событий соответствовал стандарту Verilog.
Описанный выше метод симуляции, при котором события «разворачиваются» в определённом порядке, называется цикловой симуляцией. Такой способ использует цикл как гранулярность моделирования и в каждом цикле симуляции вычисляет все компоненты схемы. Порядок вычислений определяется до начала симуляции и относится к статическому планированию событий. Поскольку события уже «развёрнуты» в заданном порядке, во время симуляции не требуется планировать их динамически. С одной стороны, это устраняет накладные расходы на планирование; с другой стороны, после такого «разворачивания» программа симуляции получает больше возможностей для оптимизации, поэтому эффективность симуляции выше. Однако цикловая симуляция не поддерживает временная информация, поэтому может использоваться только для функциональной верификации синхронных схем. Открытый симулятор Verilator использует именно этот способ.
Разберитесь в поведении программы симуляции, генерируемой Verilator
Скомпилируйте схему бегущего света с помощью Verilator и попробуйте разобраться в поведении сгенерированного C++-кода.
В противоположность этому эталонная реализация движка обработки событий, приведённая ранее из стандарта Verilog, называется событийной симуляцией. В событийной симуляции порядок вычисления схемы определяется непосредственно в процессе симуляции и относится к динамическому планированию событий. Поэтому во время симуляции требуются дополнительные расходы на поддержание очереди событий и их планирование. По сравнению с цикловой симуляцией эффективность ниже. Однако благодаря существованию очереди событий событийная симуляция поддерживает временная информация и может использоваться для функциональной и временной верификации синхронных, асинхронных и смешанных схем. Открытый симулятор iVerilog и большинство коммерческих симуляторов, например VCS, используют такой способ.
Гонки данных
Корректная реальная схема должна выдавать согласованные результаты даже тогда, когда различные её компоненты работают параллельно. Поэтому и модель схемы при описанной выше неопределённости должна давать одинаковый результат независимо от порядка обработки событий. И наоборот, если существуют два разных порядка обработки событий, приводящие к разным результатам симуляции, возникает гонка данных. В стандарте Verilog это называется race condition, что по смыслу совпадает с гонкой данных. В общем случае, если при симуляции существует гонка данных, описанная модель схемы не является корректной моделью реальной аппаратной схемы.
Рассмотрим следующий пример:
always @(posedge clk or negedge rstn) begin
if (!rstn) a = 1'b0;
else a = b; // (1)
end
always @(posedge clk or negedge rstn) begin
if (!rstn) b = 1'b1;
else b = a; // (2)
end
В коде присутствуют два блока always, то есть два процесса. Предположим, в некоторый момент a = 0, b = 1, rstn = 1, после чего приходит фронт clk. Поскольку операция вычисления и операция обновления блокирующего присваивания выполняются вместе, введём операцию . Тогда операторы (1) и (2) можно представить следующими событиями:
По стандарту Verilog порядок обработки нескольких активных событий произволен, поэтому другие правила порядка здесь применить нельзя. Все возможные порядки таковы:
- , результат:
a = 1,b = 1 - , результат:
a = 0,b = 0
Таким образом, в приведённом коде существует гонка данных. Если симулятор выбирает разные порядки обработки событий, результаты симуляции также различаются. Это в некоторой степени похоже на неуточнённое поведение в языке C. Разные результаты могут появляться в разных симуляторах, в разных версиях одного симулятора, в нескольких запусках одной и той же версии и даже в разные моменты симуляции одного запуска. Все эти случаи соответствуют стандарту Verilog. Поэтому при наличии гонки данных результат симуляции может быть трудно предсказать.
Проанализируйте поведение Verilog-кода с помощью событийной модели (2)
Замените блокирующие присваивания в приведённом выше коде на неблокирующие и снова проанализируйте возможные порядки обработки событий и результаты. Сохраняется ли гонка данных после изменения? Почему?
always @(posedge clk or negedge rstn) begin
if (!rstn) a <= 1'b0;
else a <= b;
end
always @(posedge clk or negedge rstn) begin
if (!rstn) b <= 1'b1;
else b <= a;
end
Рассмотрим ещё один пример:
always @(posedge clk or negedge rstn) begin
if (!rstn) a = 1'b0;
else a = 1;
end
always @(posedge clk) begin
$display("a = %d", a);
end
Предположим, в некоторый момент a = 0, rstn = 1 и приходит фронт clk. Аналогичным образом получаем два события:
Обратите внимание, что событие системной задачи $display, то есть , принадлежит . Возможны два порядка:
- , выводит
a = 1 - , выводит
a = 0
Следовательно, и в этом коде есть гонка данных. Хотя он не связан с поведением самой аппаратной схемы, выбор симулятором разных порядков обработки событий всё равно приводит к различным результатам симуляции, что может запутать разработчика при отладке.
Проанализируйте поведение Verilog-кода с помощью событийной модели (3)
Замените $display в приведённом выше коде на $strobe и снова проанализируйте возможные порядки обработки событий и результаты. Сохраняется ли гонка данных? Почему?
always @(posedge clk or negedge rstn) begin
if (!rstn) a = 1'b0;
else a = 1;
end
always @(posedge clk) begin
$strobe("a = %d", a);
end
На основе приведённых примеров можно сформулировать необходимое и достаточное условие существования гонки данных. Гонка данных существует в Verilog-коде тогда и только тогда, когда присутствуют два события и , связанные с одним и тем же объектом , и одновременно выполняются следующие условия:
- Порядок обработки между и неопределён
- Как минимум одно из событий и обновляет
Хороший стиль написания кода Verilog
Чтобы устранить гонку данных, необходимо устранить события, удовлетворяющие приведённым выше условиям. Однако по мере роста проекта вручную определять наличие гонки данных становится очень трудно. Для решения этой проблемы многие книги и материалы по Verilog рекомендуют хорошие правила написания кода. Если разработчик следует этим правилам, большинство гонок данных можно устранить, увеличивая вероятность того, что поведение спроектированной схемы будет соответствовать ожиданиям.
Например, статья "Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!" предлагает следующие рекомендации по написанию кода Verilog и утверждает, что их соблюдение устраняет более 90% гонок данных:
- При моделировании последовательностных схем используйте неблокирующие присваивания.
- При моделировании latch-схем используйте неблокирующие присваивания.
- При построении моделей комбинационной логики с помощью блоков
alwaysиспользуйте блокирующие присваивания. - Если в одном блоке
alwaysодновременно описывается последовательностная и комбинационная логика, используйте неблокирующие присваивания. - Не используйте одновременно неблокирующие и блокирующие присваивания в одном блоке
always. - Не присваивайте значение одной и той же переменной более чем в одном блоке
always. - Для вывода значений переменных, которым присваивается значение неблокирующим присваиванием, используйте системную задачу
$strobe. - Не используйте задержки
#0в присваиваниях.
После знакомства с событийной моделью мы можем разобрать причины этих рекомендаций:
- Неблокирующие присваивания используются для описания последовательностной логики потому, что их события обновления обрабатываются только после событий из и . Эта характеристика соответствует свойству «последовательностный логический элемент выполняет запись только при приходе следующего такта».
- Latch редко используются в синхронных схемах, поэтому здесь подробно рассматривать их не будем.
- Блокирующие присваивания используются для описания комбинационной логики потому, что операция обновления такого присваивания выполняется немедленно в , поэтому другие события могут сразу увидеть обновлённый результат и использовать его в дальнейших вычислениях. Это соответствует свойству «выход комбинационной логики изменяется сразу при изменении входа».
- Это связано с синтезируемой семантикой Verilog, которая будет рассмотрена ниже.
- Как и предыдущая рекомендация, эта также связана с синтезируемой семантикой Verilog.
- Разные блоки
alwaysотносятся к разным процессам, а порядок вычисления разных процессов неопределён. Кроме того, присваивание значения переменной создаёт событие обновления. Это точно удовлетворяет необходимому и достаточному условию гонки данных, поэтому гонка данных неизбежна. - события обновления неблокирующих присваиваний принадлежат , а события системной задачи
$strobe— . Поэтому$strobeможет выводить значения переменных уже после обновления неблокирующими присваиваниями. - События, создаваемые
#0, принадлежат , поэтому время их обработки находится между и . Если не понимать порядок обработки событий, можно легко написать код, поведение которого не соответствует ожиданиям.
Я умею писать Verilog — зачем мне всё это знать?
В самом начале раздела приводилось несколько рекомендаций и утверждений о Verilog, некоторые из которых неверны. Попробуйте найти ошибочные и объяснить, почему они неверны:
- Использование
#0может принудительно задержать присваивание до конца текущего момента времени симуляции. - В одном и том же блоке
begin-endвыполнение нескольких неблокирующих присваиваний одной и той же переменной приводит к неопределённое поведение. - При описании комбинационной логики блоком
alwaysнельзя использовать неблокирующие присваивания. - Переменной нельзя присваивать значение в нескольких блоках
always. - Не рекомендуется использовать
$display, поскольку иногда он не может корректно вывести значение переменной. $displayне может вывести результат неблокирующего присваивания.
Больше примеров и анализа
В статье "Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!" также приведено множество примеров и анализов. Если вы планируете использовать Verilog, мы настоятельно рекомендуем прочитать её.
Я умею писать Verilog — зачем мне всё это знать? (2)
Разумеется, даже если вы следуете множеству рекомендаций, всегда остаётся тот самый условный 10%-ный шанс случайно написать код с гонкой данных. Когда вы понимаете детали событийной модели, у вас появляется возможность самостоятельно анализировать и устранять гонки данных в коде.
Кроме того, чтобы понять этот материал, требуется всего около одного часа. По сравнению с временем, которое в будущем уйдёт на отладку, этот час почти ничего не стоит. Уже только возможность избежать нескольких дней бессмысленной отладки делает такую инвестицию времени полностью оправданной.
Логический синтез — от RTL-кода к нетлисту
RTL-код является лишь описанием схемы, а симуляция всего лишь использует программу для имитации поведения схемы. Если схему необходимо изготовить, фабрике требуется гораздо более подробная информация. В частности, фабрике нужен файл топологии формата GDSII (Graphic Design System II), описывающий физическое положение каждого элемента схемы: например, AND gate находится в координате (3, 4), а провод проходит между (4, 2) и (0, 2). Чтобы преобразовать RTL-код в такую GDS-топологию, необходим целый набор EDA-инструментов, последовательно выполняющих несколько этапов. Например, этап размещения определяет координаты каждого логического элемента, а этап трассировки определяет, как соединить логические элементы проводниками.
Обычно фабрика предоставляет Process Design Kit, сокращённо PDK, который содержит набор ресурсов для конкретного технологического процесса: модели устройств, правила проектирования, технологические ограничения, файлы верификации, библиотеки стандартных ячеек и так далее. Инженеры физического проектирования используют PDK для создания схем, соответствующих производственным требованиям фабрики. Библиотека стандартных ячеек в PDK содержит логические элементы, поддерживаемые данной технологией; они называются стандартными ячейками. Стандартные ячейки являются частью объектов, описываемых в GDS-топологии, и одновременно являются минимальными единицами, с которыми работают EDA-инструменты.
Логический синтез, или просто «синтез», — это процесс преобразования RTL-описания в стандартные ячейки. Кроме того, GDS-топология также записывает соединения, то есть топологию, между стандартными ячейками с помощью проводников. Эти отношения соединения изначально описаны в RTL-коде как связи между схемами и модулями, поэтому синтезатор должен сохранить их в результатах синтеза для последующих этапов и в конечном итоге передать в GDS-топологии. Итак, результатом работы синтезатора является нетлист стандартных ячеек, содержащий как преобразованные стандартные ячейки, так и связи между ними.
На этапе E вы уже использовали ECC для синтеза и оценки NPC.
ECC использует открытый RTL-синтезатор yosys для синтеза RTL-кода и отображает результат синтеза на открытый 55-нм PDK ICsprout55.
Первый открытый PDK в Китае и самый передовой открытый PDK в мире на момент выпуска
ICsprout55 — открытый PDK, независимо разработанный Zhejiang Chuangxin Integrated Circuit Co., Ltd. и выпущенный в октябре 2025 года при содействии команды ECOS Института вычислительных технологий Китайской академии наук. ICsprout55 основан на зрелом 55-нм CMOS-техпроцессе, является первым открытым PDK, выпущенным в Китае, и на момент выпуска был самым передовым открытым PDK в отрасли. Это важный прорыв для глобальной экосистемы open-source chip.
Ранее конспекты «One Student One Chip» использовали другой открытый PDK — nangate45. Однако этот PDK предназначен только для академических исследований; количество и качество его стандартных ячеек уступают коммерческим PDK, он не может использоваться для tapeout и не применяется ни одной фабрикой в производственных линиях. Выпуск ICsprout55 восполняет этот пробел и значительно приближает нас к цели «выполнить tapeout полностью открытого процессорного чипа на основе open-source IP + open-source SoC + open-source EDA + open-source PDK».
Благодарим Zhejiang Chuangxin Integrated Circuit Co., Ltd. за вклад в область open-source chip!
Сначала можно распаковать этот файл командой gunzip, а затем открыть полученный .v-файл. После знакомства с процессом синтеза на примере можно посмотреть синтезированный нетлист. Найдите результат синтеза в директории result и откройте находящийся там файл .netlist.v. Можно увидеть, что многие сигналы в нетлисте определены побитно, а также инстанцируется множество подмодулей с именами вроде NOR2X0P5H7L, OAI22X6H7L. Эти подмодули и являются стандартными ячейками, предоставляемыми PDK ICsprout55.
Итак, как синтезатор преобразует RTL-код в нетлист? В качестве примера используем следующий счётчик и на нём рассмотрим процесс синтеза yosys. При необходимости можно обращаться к официальному руководству yosys.
// counter.v
module counter(
input clk,
input rst,
input en,
output reg [1:0] count
);
always @(posedge clk) begin
if (rst) count <= 2'd0;
else if (en) count <= count + 2'd1;
end
endmodule
Парсинг
Заставить yosys прочитать и разобрать исходный файл можно следующей командой:
$ yosys counter.v
-- Parsing `counter.v' using frontend ` -vlog2k' --
1. Executing Verilog-2005 frontend: counter.v
Parsing Verilog input from `counter.v' to AST representation.
Storing AST representation for module `$abstract\counter'.
Successfully finished Verilog frontend.
yosys>
Как видно, yosys разбирает counter.v и преобразует его в Abstract Syntax Tree (AST), после чего выводит приглашение командной строки yosys>. Чтобы выйти из yosys, введите exit.
Процесс разбора исходного файла очень похож на компиляцию языка C и также включает лексический анализ и синтаксический анализ. Если удалить одну из точек с запятой ; в исходном файле и снова выполнить команду, yosys сообщит следующую ошибку:
counter.v:10: ERROR: syntax error, unexpected TOK_ELSE
Elaboration
Работа этапа elaboration включает разбор отношений инстанцирования между модулями, вычисление параметров экземпляров модулей, заполнение имён экземпляров и привязок портов и так далее.
Запустить elaboration в yosys можно следующей командой:
yosys> hierarchy -check -top counter
2. Executing HIERARCHY pass (managing design hierarchy).
3. Executing AST frontend in derive mode using pre-parsed AST for module `\counter'.
Generating RTLIL representation for module `\counter'.
3.1. Analyzing design hierarchy..
Top module: \counter
3.2. Analyzing design hierarchy..
Top module: \counter
Removing unused module `$abstract\counter'.
Removed 1 unused modules.
Как видно, команда hierarchy также требует указать модуль верхнего уровня. yosys использует его как отправную точку и последовательно раскрывает все инстанцированные подмодули, тем самым определяя границы всего design; неинстанцированные модули удаляются. Одновременно этап elaboration преобразует AST всего проекта в RTLIL — промежуточный язык yosys, что очень похоже на этап генерации промежуточного кода при компиляции C.
Семантический анализ
Можно предположить, что на этапе elaboration yosys также выполняется работа, похожая на семантический анализ при компиляции C. Например, если заменить posedge clk в counter.v на posedge counter, при выполнении команды hierarchy yosys выдаст ошибку:
counter.v:8: ERROR: Found posedge/negedge event on a signal that is not 1 bit wide!
Если добавить в counter.v оператор инстанцирования mymodule abc(clk, rst);, yosys выдаст:
ERROR: Module `\mymodule' referenced in module `\counter' in cell `\abc' is not part of the design.
Как видно, обе ошибки соответствуют синтаксису Verilog, поэтому их невозможно обнаружить на этапе parsing.
Генерация промежуточного кода
После успешного выполнения hierarchy можно посмотреть RTLIL всего проекта. Команда dump выводит текущий RTLIL в терминал:
yosys> dump
Либо можно записать RTLIL в файл командой write_rtlil:
yosys> write_rtlil counter.rtlil
Например, содержимое counter.rtlil выглядит следующим образом:
autoidx 3
attribute \hdlname "counter"
attribute \top 1
attribute \src "counter.v:2.1-12.10"
module \counter
attribute \src "counter.v:8.3-11.6"
wire width 2 $0\count[1:0]
attribute \src "counter.v:10.27-10.39"
wire width 2 $add$counter.v:10$2_Y
attribute \src "counter.v:3.9-3.12"
wire input 1 \clk
attribute \src "counter.v:6.20-6.25"
wire width 2 output 4 \count
attribute \src "counter.v:5.9-5.11"
wire input 3 \en
attribute \src "counter.v:4.9-4.12"
wire input 2 \rst
attribute \src "counter.v:10.27-10.39"
cell $add $add$counter.v:10$2
parameter \A_SIGNED 0
parameter \A_WIDTH 2
parameter \B_SIGNED 0
parameter \B_WIDTH 2
parameter \Y_WIDTH 2
connect \A \count
connect \B 2'01
connect \Y $add$counter.v:10$2_Y
end
attribute \src "counter.v:8.3-11.6"
process $proc$counter.v:8$1
assign $0\count[1:0] \count
attribute \src "counter.v:9.5-10.40"
switch \rst
attribute \src "counter.v:9.9-9.12"
case 1'1
assign $0\count[1:0] 2'00
attribute \src "counter.v:10.5-10.9"
case
attribute \src "counter.v:10.10-10.40"
switch \en
attribute \src "counter.v:10.14-10.16"
case 1'1
assign $0\count[1:0] $add$counter.v:10$2_Y
case
end
end
sync posedge \clk
update \count $0\count[1:0]
end
end
Кратко разберём полученный RTLIL. Подробнее можно прочитать в соответствующем руководстве yosys:
attributeиспользуется для обозначения различных атрибутов. Например,attribute \src "counter.v:10.27-10.39"указывает положение соответствующего элемента в исходном файле — с 27-го по 39-й столбец строки 10 файлаcounter.v.wire width 2 $0\count[1:0]означает объявление сигнала шириной2с именем$0\count[1:0](обратите внимание: символы$,\,[,:и]являются частью имени).cell $add $add$counter.v:10$2означает инстанцирование cell типа$addс именем$add$counter.v:10$2. Конкретные параметры cell задаются с помощьюparameter. Например,parameter \A_WIDTH 2означает, что ширина портаAравна2, аparameter \A_SIGNED 0— что портAявляется unsigned. Соединения портов задаются с помощьюconnect; например,connect \Y $add$counter.v:10$2_Yозначает, что портYсоединён с сигналом$add$counter.v:10$2_Y.processпредставляет процесс поведенческого описания, гдеassignозначает присваивание сигналу,switch-case— условное присваивание в зависимости от значения сигнала, аsync— обновление сигнала при выполнении условия.
Хотя синтаксис RTLIL отличается от Verilog, всё равно можно почувствовать, что RTLIL также описывает аппаратную схему; более того, process явно соответствует always в Verilog-коде. Некоторые операторы уже заменены cells, например + заменён на $add. Поэтому по сравнению с исходным Verilog-кодом текущий RTLIL уже ближе к нетлисту. Cells вроде $add относятся к внутренней библиотеке cells yosys.
Топологические связи RTLIL можно визуализировать в виде структурной диаграммы. Для этого, возможно, потребуется установить средство просмотра файлов типа Graphviz dot:
apt-get install xdot
После этого можно выполнить в yosys команду show, которая автоматически вызовет xdot или подобный инструмент:
yosys> show
Файл структурной диаграммы, генерируемый show, по умолчанию сохраняется как ~/.yosys_show.dot. Повторное выполнение show перезаписывает его. При необходимости можно вручную скопировать файл в другую директорию и открыть его с помощью xdot.
Посмотрите структурную диаграмму
Используйте команду show, чтобы посмотреть текущую структурную диаграмму и лучше понять RTLIL.
Крупнозернистый синтез
Этап coarse-grain synthesis выполняет обработку на основе «крупнозернистого представления» проекта. Здесь coarse-grain representation означает описание design с помощью word-level cells. Word-level cells являются частью внутренней библиотеки yosys, находятся на сравнительно высоком уровне абстракции и поддерживают многобитную ширину и параметры. По стилю имён word-level cells обычно имеют префикс $. Упомянутый выше $add относится к word-level cells. Другие примеры — $shift для сдвига, $mux для выбора и так далее.
Преобразование процедурных описаний в крупнозернистое представление
Текущий RTLIL всё ещё содержит процедурные описания вроде process, которые на структурной диаграмме отображаются как узлы PROC. Они не относятся к coarse-grain representation, поэтому над ними нельзя выполнять обработку, предназначенную для этого представления. Сначала yosys должен преобразовать все процедурные описания в coarse-grain representation. Это выполняется командой proc:
yosys> proc
Команда proc фактически является макрокомандой, которая последовательно вызывает ряд подкоманд:
| Шаг | Подкоманда | Описание |
|---|---|---|
| 1 | proc_clean | Удалить пустые ветви и пустые процедурные описания |
| 2 | proc_rmdead | Удалить недостижимые ветви case |
| 3 | proc_prune | Удалить избыточные операции присваивания, перезаписываемые последующими присваиваниями |
| 4 | proc_init | Преобразовать операции init в процедурные описания в атрибуты init соответствующих сигналов |
| 5 | proc_arst | Распознать асинхронные сбросы |
| 6 | proc_rom | Когда это уместно, преобразовать операции switch в процедурные описания в ROM |
| 7 | proc_mux | Преобразовать операции switch в $mux cells, то есть мультиплексоры |
| 8 | proc_dlatch | Преобразовать latch в cells типа D-latch |
| 9 | proc_dff | Преобразовать триггер в cells типа D-триггер |
| 10 | proc_memwr | Преобразовать операции записи памяти в $memwr cells |
| 11 | proc_clean | Удалить пустые ветви и пустые процедурные описания |
| 12 | opt_expr -keepdc | Выполнить оптимизации, связанные с выражениями |
Некоторые подкоманды очень похожи на техники оптимизации при компиляции C, поэтому понять их должно быть несложно. В целом proc в основном преобразует части switch-case процедурные описания в RTLIL в $mux cells, а описания sync — в D-latch или D-триггер cells, в результате получая полное coarse-grain representation.
Посмотрите структурную диаграмму (2)
Используйте show, чтобы посмотреть текущую структурную диаграмму, и сравните её до и после выполнения proc.
Оптимизация
Подобно оптимизации при компиляции, синтезаторы обычно также предоставляют функции оптимизации, позволяя разработчикам сосредоточиться на архитектурном и логическом проектировании и не думать слишком много о производительности схемы непосредственно во время разработки. Синтезатор обычно способен обеспечить достаточно хороший базовый уровень качества.
После получения полного coarse-grain representation можно применить ряд оптимизаций для улучшения design. Это выполняется командой opt:
yosys> opt
Как и proc, opt является макрокомандой, последовательно вызывающей ряд подкоманд:
| Шаг | Подкоманда | Описание |
|---|---|---|
| 1 | opt_expr | Свёртка констант и простое переписывание выражений |
| 2 | opt_merge -nomux | Объединение одинаковых cells, кроме cells типа selector |
do | Начало цикла | |
| 3 | opt_muxtree | Удаление недостижимых ветвей во вложенных selectors |
| 4 | opt_reduce | Упрощение многовходовых selectors, AND gates и OR gates |
| 5 | opt_merge | Объединение одинаковых cells |
| 6 | opt_share | Объединение cells с одинаковыми входами и типом, которые не активируются одновременно |
| 7 | opt_dff | Константная оптимизация D-триггеры и объединение clock/reset signals |
| 8 | opt_clean | Удаление бесполезных cells и nets |
| 9 | opt_expr | Свёртка констант и простое переписывание выражений |
while (changed) | Если design изменился, перейти к шагу 3 и продолжить цикл |
Ниже приведены некоторые распространённые техники оптимизации. Для удобства понимания семантика до и после оптимизации показана на Verilog-коде.
- Свёртка констант и простое переписывание выражений (
opt_expr) — если вход выражения является определённой константой или выражение соответствует специальному шаблону, его можно упростить. В следующем примере результатa != aвсегда равен0, поэтому выражение можно оптимизировать доassign x = 1'b0; после применения constant propagation результатb | xвсегда равенb, поэтому можно получитьassign y = b;; кроме того, поскольку ширинаcравна 1, выражениеc == 0эквивалентно~c, и его можно заменить наassign z = ~c;. Синтезатор может заменить соответствующие cells результатами вычислений, упрощая схему.
// before optimization | after optimization
wire a, b, c, x, y, z; | wire a, b, c, x, y, z;
// ...... | // ......
assign x = a != a; | assign x = 1'0;
assign y = b | x; | assign y = b;
assign z = c == x; | assign z = ~c;
- Объединение одинаковых cells (
opt_merge) — несколько cells с одинаковыми функциями и входами можно объединить в одну, позволив её выходу управлять исходными выходными сигналами и уменьшив число cells. В следующем примере две операцииa + bиb + aимеют одинаковую функцию и входы, поэтомуxможет напрямую управлятьy, устраняя один сумматор.
// before optimization | after optimization
wire a, b, x, y; | wire a, b, x, y;
// ...... | // ......
assign x = a + b; | assign x = a + b;
assign y = b + a; | assign y = x;
Компромисс между площадью и производительностью
Следует отметить, что хотя эта оптимизация уменьшает количество cells, она увеличивает fan-out cell, то есть количество downstream cells, подключённых к её выходу. При прочих равных увеличение fan-out повышает задержку схемы.
В качестве бытовой аналогии можно представить выход cell как кран, подающий воду в downstream-бассейн. Только когда бассейн наполнится, можно открыть ворота — подобно переключению транзисторов downstream. До оптимизации два крана по отдельности наполняют два своих бассейна; после оптимизации один кран экономится, но теперь он должен одновременно наполнять два бассейна. При неизменной скорости потока требуется больше времени, и это время похоже на задержку схемы.
В случаях, когда необходимо оптимизировать задержку, наоборот, используется метод «дублирования cells», увеличивающий количество «кранов». Поэтому объединение или дублирование cells является компромиссом между площадью и производительностью.
- Удаление недостижимых ветвей во вложенных selectors (
opt_muxtree) — во вложенных selectors некоторые ветви могут быть недостижимы из-за противоречащих условий и могут быть удалены. В следующем примере результат внутреннего selectora ? b : cне может бытьc, поскольку для этого внешний сигнал выбора должен иметьa = 1, а внутренний —a = 0, что противоречиво. Поэтому внутренний selector можно заменить наb, упрощая схему.
// before optimization | after optimization
wire a, b, c, d, x; | wire a, b, c, d, x;
// ...... | // ......
assign x = a ? (a ? b : c) : d; | assign x = a ? b : d;
- Упрощение многовходовых selectors, AND gates и OR gates (
opt_reduce) — некоторые входы многовходовых selectors, AND и OR могут быть одинаковыми и поэтому могут быть устранены или объединены. В следующем примере до оптимизации необходимо выбрать между двумя 32-битными сигналами для полученияimm, но у этих двух сигналов биты 12–31 соответственно совпадают с битом 11: в одном случае это0, в другом —inst[31]. Поэтому входы selector можно оптимизировать: сначала выбирать только биты 0–11 какimm[11:0], а затем использовать выбранный бит 11 какimm[31:20]. После оптимизации ширина data side selector уменьшается с 32 до 12. Аналогично для reduction AND&imm: поскольку биты 12–31immсовпадают с битом 11, их можно удалить, и результат остаётся равным&imm[11:0]. После оптимизации ширина входа AND gate уменьшается с 32 до 12.
// before optimization | after optimization
wire [31:0] inst, imm; | wire [31:0] inst, imm;
wire sel, x; | wire sel, x;
// ...... | // ......
assign imm = !sel ? 32'b0 : | assign imm[11:0] = !sel ? 12'b0 : inst[31:20];
{{20{inst[31]}}, inst[31:20]};| assign imm[31:20] = {20{imm[11]}};
assign x = &imm; | assign x = &imm[11:0];
- Константная оптимизация D-триггеры (
opt_dff) — если data input D-триггер является константой, его можно заменить самой константой и удалить соответствующий D-триггер cell. В следующем примере data input D-триггерrявляется константой, поэтому его можно напрямую оптимизировать до постоянного сигнала.
// before optimization | after optimization
reg [31:0] r; | wire [31:0] r;
// ...... | // ......
always @ (posedge clk) | assign r = 32'hdeadbeef;
r <= 32'hdeadbeef; |
- Удаление бесполезных cells и nets (
opt_clean) — если некоторые cells и nets не влияют на выход модуля, их можно удалить. В следующем примере nettне влияет на выходной портx, поэтому его можно удалить вместе с cella & b.
// before optimization | after optimization
module m( | module m(
input a, b; | input a, b;
output x; | output x;
); | );
wire t; | assign x = a + b;
assign x = a + b; | endmodule
assign t = a & b; |
endmodule |
Кроме описанных техник, в процессе синтеза используется множество других оптимизаций, например уменьшение bit width и peephole optimization. Здесь подробно их рассматривать не будем. Заинтересованные студенты могут обратиться к документации yosys или другим материалам.
Посмотрите структурную диаграмму (3)
Используйте show, чтобы посмотреть текущую структурную диаграмму и сравнить её до и после выполнения opt.
Распознавание и обработка конечных автоматов
Ранее мы вводили модель конечного автомата компьютерных систем и объясняли, что цифровую схему также можно рассматривать как конечный автомат. Здесь finite state machine (FSM) более конкретно означает часть design, реализованную цифровой логикой и обладающую характеристиками конечного автомата.
Например, вы, вероятно, уже выполняли на HDLBits задачу вроде «распознать три последовательных 1». Для неё можно составить следующую таблицу переходов состояния; элементы таблицы означают «следующее состояние/выход»:
| Значение | Вход 0 | Вход 1 | |
|---|---|---|---|
S0 | Начальное состояние | S0/0 | S1/0 |
S1 | Распознан один 1 | S0/0 | S2/0 |
S2 | Распознаны два 1 | S0/0 | S2/1 |
Более сложные FSM могут содержать избыточные состояния или состояния, входы и выходы, которые можно объединить, однако такие ситуации трудно обнаруживать на уровне word-level cells операторного типа. Поэтому синтезатор обычно сначала распознаёт FSM на word-level cells, затем анализирует и оптимизирует её согласно семантике FSM и в конце снова отображает её в word-level cells.
В yosys это выполняется командой fsm:
yosys> fsm
fsm также является макрокомандой, последовательно вызывающей подкоманды для обработки FSM. Основные шаги:
fsm_detect— обнаружение FSM: поиск FSM в RTLIL по определённым правилам и маркировка связанных cells специальными атрибутамиfsm_extract— извлечение FSM: замена отмеченных cells на$fsmcells и извлечение таблицы переходов состоянияfsm_opt— оптимизация FSM по таблице переходов: удаление бесполезных выходов, объединение одинаковых upstream inputs, объединение разных входов с одинаковым выходом в одном состоянии, упрощение состояний согласно константным входам и так далееfsm_recode— перекодирование FSM, то есть написание кода сигналов состояния one-hot codesfsm_map— отображение cells, преобразующее обработанные$fsmcells обратно в word-level cells
Однако counter.v не содержит FSM, поэтому команда fsm на него не повлияет. Теоретически, согласно модели конечного автомата цифровых схем, любую цифровую схему можно попытаться рассматривать целиком как FSM, но полученная таблица переходов будет огромной: уже для одного 32-битного регистра существует состояний. Это создаёт две проблемы: во-первых, объём вычислений для обработки такого пространства состояний намного превышает возможности современных компьютеров; во-вторых, такие состояния имеют очень низкую схожесть по входам, выходам и следующему состоянию, поэтому найти оптимизируемые состояния или сигналы почти невозможно. Поэтому модель конечного автомата цифровой схемы используется для понимания базовых принципов, но на практике не применяется таким способом для FSM optimization.
Распознавание и обработка памяти
Ещё один тип cells, требующий специальной обработки, — память. В yosys обработка памяти в RTLIL выполняется командой memory:
yosys> memory
memory также является макрокомандой, последовательно вызывающей ряд подкоманд. Обработка включает, например, объединение триггеры перед и после памяти в read/write cells памяти, объединение нескольких read/write cells в одну multi-port memory cell и так далее.
В FPGA flow типы физической памяти немногочисленны, например LUT RAM, Block RAM и FF, поэтому FPGA-синтезатор может автоматически распознать память в RTL-коде указанным способом и отобразить её на физические memory devices согласно распознанным атрибутам. Благодаря программируемости FPGA синтезатор может выполнять динамическое распределение памяти «по требованию»: определять необходимый объём памяти из RTL-кода и отображать его на доступные memory devices.
В ASIC flow всё иначе. Для повышения производительности memory cells ASIC не содержат программируемой функциональности; вместо этого библиотека стандартных ячеек предоставляет несколько вариантов памяти с фиксированными спецификациями, из которых RTL-разработчик выбирает подходящий. Такие memory cells имеют разные характеристики производительности, площади и энергопотребления. Например, чтобы реализовать функцию памяти 64x64 на RTL-уровне, разработчик может выбрать одну memory cell 64x64 или две cells 32x64 и соединить их. Первый вариант занимает меньшую суммарную площадь, но может иметь большую задержку чтения; второй занимает больше площади, но может иметь лучшую задержку. Кроме того, разные конфигурации памяти имеют разную геометрическую форму, что влияет на последующие размещение и трассировку. Из-за этих взаимосвязанных факторов синтезатору трудно автоматически распознавать и отображать память, поэтому RTL-разработчик должен самостоятельно выбирать конфигурацию памяти в соответствии с целями design и вручную инстанцировать memory cells как подмодули в RTL-коде.
Можно сказать, что различие в использовании памяти между ASIC flow и FPGA flow отражает компромисс между производительностью и гибкостью: ASIC стремится к более высокой производительности, но обладает меньшей гибкостью, поэтому распределение памяти «по требованию» затруднено и разработчик сам выбирает конкретные конфигурации; FPGA гораздо гибче, но программируемая природа memory devices снижает производительность по сравнению с ASIC.
Однако counter.v не содержит памяти, поэтому команда memory также не оказывает на него влияния. В ближайшее время мы не будем работать со схемами, содержащими подобные memory cells. К вопросу памяти вернёмся на этапе A.
Мелкозернистый синтез
Этап fine-grain synthesis обрабатывает «мелкозернистое представление» design. Как упоминалось выше, fine-grain representation описывает проект gate-level cells. Во внутренней библиотеке yosys есть категория gate-level cells. В отличие от cells coarse-grain representation, эти gate-level cells имеют ширину данных 1 бит и не предоставляют параметров. По стилю имён они обычно называются в форме $_XXX_, где XXX записывается в верхнем регистре, что отличает их от word-level cells.
Сначала coarse-grain representation необходимо преобразовать в fine-grain representation. Это выполняется командой techmap:
yosys> techmap
Команда techmap заменяет cells текущего design реализациями cells из указанной библиотеки. Если библиотека не указана, используется внутренняя gate-level cell library yosys.
После замены на gate-level cells необходимо также разделить некоторые многобитные nets и порты; иначе RTLIL будет содержать ненужные операции bit extraction и concatenation. Это можно сделать командой:
yosys> splitnets -ports
Затем можно выполнить opt -full, чтобы yosys провёл оптимизацию, удалил бесполезные cells и nets, после чего посмотреть структурную диаграмму.
Можно увидеть, что D-триггер cell шириной 2 бита из coarse-grain representation разделилась на две D-триггер cells шириной 1 бит, а adder $add также разложился на несколько gate-level cells. Поэтому текущее fine-grain representation ещё ближе к нетлисту.
Посмотрите структурную диаграмму (4)
Используйте show, чтобы посмотреть текущую структурную диаграмму и сравнить её до и после выполнения techmap.
Технологическое отображение
Технологическое отображение означает отображение технологически независимого представления схемы на реализацию конкретной технологии. На этом этапе fine-grain representation проект отображается на стандартные ячейки целевой технологии. Чтобы показать эффект технологического отображения, используем простую библиотеку стандартных ячеек из руководства yosys:
library(demo) {
cell(BUF) {
area: 6;
pin(A) { direction: input; }
pin(Y) { direction: output;
function: "A"; }
}
cell(NOT) {
area: 3;
pin(A) { direction: input; }
pin(Y) { direction: output;
function: "A'"; }
}
cell(NAND) {
area: 4;
pin(A) { direction: input; }
pin(B) { direction: input; }
pin(Y) { direction: output;
function: "(A*B)'"; }
}
cell(NOR) {
area: 4;
pin(A) { direction: input; }
pin(B) { direction: input; }
pin(Y) { direction: output;
function: "(A+B)'"; }
}
cell(DFF) {
area: 18;
ff(IQ, IQN) { clocked_on: C;
next_state: D; }
pin(C) { direction: input;
clock: true; }
pin(D) { direction: input; }
pin(Q) { direction: output;
function: "IQ"; }
}
}
Сохраните этот текст в файл cell.lib. Он описывает атрибуты стандартных ячеек в текстовом виде. В частности:
- Площадь cell, обычно в единицах
- Pins с указанием направления; output pins также содержат атрибут
function, задаваемый логическим выражением; clock input pin триггер также содержит атрибутclock, указывающий, что этот pin является clock signal
В yosys технологическое отображение выполняется в два шага. Сначала отображаются sequential logic cells:
yosys> dfflibmap -liberty cell.lib
После выполнения команды и просмотра структурной диаграммы можно увидеть, что gate-level cell $_SDFFE_PP0P_ заменена на DFF и несколько $_MUX_ cells, где DFF — стандартная ячейка из cell.lib. Дополнительные $_MUX_ появляются потому, что в cell.lib нет стандартная ячейка с функцией, полностью совпадающей с $_SDFFE_PP0P_. Согласно руководству yosys, $_SDFFE_PP0P_ — это «D-триггер по положительному фронту с active-high synchronous reset и active-high enable», тогда как единственная sequential logic cell DFF в cell.lib — обычный D-триггер. Поэтому для реализации функций synchronous reset и enable требуется дополнительная комбинационная логика.
Однако на структурной диаграмме выходной pin Q cell DFF может появиться слева, то есть со стороны входов. Это связано с тем, что cell.lib является внешней библиотекой для yosys, и команда show по умолчанию не знает атрибуты стандартной ячейки DFF. Чтобы исправить это, можно сначала загрузить библиотеку:
yosys> read_liberty -lib cell.lib
После успешного чтения повторно выполните show.
Посмотрите структурную диаграмму (5)
Используйте show, чтобы посмотреть текущую структурную диаграмму и сравнить её до и после выполнения dfflibmap.
Затем выполняется технологическое отображение комбинационных cells:
yosys> abc -liberty cell.lib
Команда abc вызывает внешний инструмент ABC, выполняющий технологическое отображение комбинационных logic cells. Все gate-level cells заменяются стандартными ячейками из cell.lib. В конце команда clean удаляет бесполезные cells и соединения, после чего получается окончательный нетлист и завершается преобразование RTL-кода в нетлист.
Посмотрите структурную диаграмму (6)
Используйте show, чтобы посмотреть текущую структурную диаграмму и сравнить её до и после выполнения abc.
технологическое отображение и команда techmap в yosys
На предыдущем этапе fine-grain synthesis мы использовали команду techmap, название которой также является сокращением от Technology Mapping. Официальное руководство yosys разделяет технологическое отображение на два шага: сначала отображение word-level cells на gate-level cells, затем отображение gate-level cells на стандартные ячейки целевой технологии.
Это отличается от понятия технологического отображения, используемого в этих конспектах: здесь акцент делается на переходе «от абстрактного к конкретному». Чтобы соответствовать понятию, принятому в отрасли, мы не используем трактовку из официального руководства yosys. Поэтому «первый шаг технологическое отображение» в руководстве yosys соответствует «fine-grain synthesis» в этих конспектах, а «второй шаг технологическое отображение» — собственно «технологическое отображение» в конспектах.
Генерация нетлист и отчётов
В конце нетлист записывается в файл командой write_verilog, а информация об используемых стандартных ячеек выводится командой stat:
yosys> write_verilog netlist.v
yosys> stat -liberty cell.lib
Разберитесь в процессе синтеза по log-файлу yosys
Вы уже синтезировали проект бегущего огня. Попробуйте посмотреть log-файл yosys в директории yosys-sta/result и понять процесс синтеза с помощью приведённого выше объяснения. Попробуйте изучить log-файл Yosys light/runs/default/Synthesis_yosys/log/Synthesis.log и понять процесс синтеза на основе материала выше.
Чтобы не вводить команды Yosys вручную каждый раз, ECC управляет Yosys при синтезе с помощью скрипта. Соответствующий скрипт находится в ecc/_internal/chipcompiler/tools/yosys/scripts/yosys_synthesis.tcl. Если вы хотите подробнее изучить команды Yosys, обратитесь к официальной документации Yosys или введите help xxx в командной строке Yosys для просмотра информации о команде xxx.
Семантика RTL-синтеза Verilog
Чтобы понять, какой RTL-код превращается в какие стандартные ячейки, необходимо учитывать семантику RTL-синтеза. Однако стандарт Verilog определяет семантику симуляции Verilog и не подходит непосредственно для сценария RTL synthesis. Поэтому стандарт Verilog RTL Synthesis отдельно описывает семантику языка Verilog в сценарии синтеза. Синтезатор читает Verilog-код и преобразует его в семантически эквивалентные стандартные ячейки согласно этому стандарту.
Раздел 1.1 стандарта Verilog RTL Synthesis вводит контекст RTL-синтеза:
Этот стандарт определяет набор правил моделирования для написания описаний
Verilog® HDL, предназначенных для синтеза. Соблюдение этих правил гарантирует
совместимость Verilog HDL-описаний между средствами RTL-синтеза, соответствующими
этому стандарту. Стандарт определяет, как семантика Verilog HDL используется,
например, для описания логики, чувствительной к уровню и фронту. Он также
описывает синтаксис языка с точки зрения того, что должно и что не должно
поддерживаться для обеспечения совместимости.
Использование этого стандарта повышает переносимость проектов на Verilog HDL
между средствами синтеза, соответствующими стандарту. Кроме того, оно минимизирует
вероятность функционального расхождения между RTL-моделью и синтезированным netlist.
Ключевые моменты:
- Стандарт описывает, какие части синтаксиса Verilog должны поддерживаться синтезаторами, а какие не поддерживаются. Это показывает, что синтаксис Verilog, поддерживаемый синтезаторами, является лишь подмножеством полного синтаксиса Verilog.
- Следование стандарту повышает переносимость Verilog-design между разными синтезаторами, чтобы соответствующие стандарту синтезаторы интерпретировали соответствующий код с одинаковой семантикой.
- Следование стандарту также минимизирует потенциальный риск функционального несоответствия между RTL-моделью и синтезированным нетлисту.
RTFM
Прочитайте главу 5 Modeling hardware elements стандарта Verilog RTL Synthesis, чтобы понять, какой Verilog-код синтезируется в какие схемы.
Этот материал занимает всего около 10 страниц, но он авторитетнее любых других учебных материалов по Verilog и содержит множество примеров и объяснений, включая подробное описание того, в каких сценариях x и z являются synthesizable.
На самом деле некоторые приведённые выше рекомендации по стилю Verilog основаны именно на спецификациях стандарта Verilog RTL Synthesis.
Поскольку семантика симуляции и синтеза не полностью совпадает, один и тот же Verilog-код может вести себя по-разному в этих двух сценариях. В chip design flow и симуляция, и синтез являются обязательными этапами, а с учётом физического проектирования и manufacturing поведение создаваемого Verilog-кода должно определяться результатом синтеза. Поэтому необходимо избегать кода, поведение которого расходится между симуляцией и синтезом.
Приложение B Functional mismatches стандарта Verilog RTL Synthesis описывает несколько таких ситуаций. Раздел B.1 приводит пример неопределённого поведения:
always @(posedge clock) begin
a = 0;
a = 1;
end
always @(posedge clock)
b = a;
Проанализируйте поведение Verilog-кода с помощью событийной модели (4)
Используйте событийную модель, чтобы объяснить, почему в приведённом выше коде существует гонка данных.
В этом примере синтезатор может свободно выбрать либо 0, либо 1 в качестве входа триггер b. Но какой бы вариант ни был выбран, из-за существования гонки данных поведение синтезированного нетлиста может не совпадать с результатом симуляции.
RTFM (2)
Прочитайте приложение B стандарта Verilog RTL Synthesis и узнайте, какие ещё ситуации способны вызвать функциональное несоответствие между синтезированным нетлисту и поведением при симуляции.
Преимущества Chisel
Если вы планируете проектировать схемы на Chisel, вам не нужно учитывать описанные выше гонки данных и functional mismatches, поскольку семантика Chisel гарантирует, что генерируемый Verilog-код не содержит этих проблем.
Оценка схем с помощью открытых EDA-инструментов
Поскольку стандартные ячейки в нетлисте являются физически производимыми и обладают различными физическими атрибутами, после получения нетлист мы можем предварительно оценить качество схемы. Существует несколько измерений качества, а три наиболее распространённых — производительность, энергопотребление и площадь; вместе они называются PPA (Performance, Power, Area).
Оценка площади
Проще всего оценить площадь. В .lib уже указаны атрибуты площади стандартных ячеек. Синтезатору достаточно подсчитать, сколько раз каждая стандартная ячейка инстанцирована в нетлисте, чтобы получить общую площадь текущего design.
Оценка производительности
Производительность схемы в основном измеряется частотой, то есть «сколько раз в секунду схема максимально способна выполнить работу». Это определяется тем, «какое минимальное время необходимо для выполнения одной работы». Под «одной работой» будем понимать «обновление состояния последовательностных логических элементов под действием clock signal». Поскольку эти показатели связаны со временем, процесс их анализа называется timing analysis.
Вспомним модель конечного автомата цифровой схемы: последовательностные элементы обновляют состояние при приходе clock signal. «Состояние» по сути является данными, которые должны быть вычислены комбинационной логикой. Но вычисление комбинационной логики требует определённой задержки, поэтому clock frequency необходимо выбирать так, чтобы интервал между двумя тактами, то есть period, полностью вмещал задержку комбинационной логики. Иначе data signal, используемый для обновления состояния, ещё не будет стабильным результатом вычисления, и поведение схемы не будет соответствовать design.
+------------------+
+-->| Sequential Logic |----+
| +------------------+ |
| next state | current state
| |
| +---------------------+ |
+--| Combinational Logic |<-+
+---------------------+
Поэтому оценка производительности схемы означает вывод максимально допустимой частоты на основе задержек комбинационных путей. Если фактическая рабочая частота выше этой максимальной частоты, новые состояния некоторых последовательностных элементов не будут соответствовать ожиданиям, и схема не сможет корректно работать.
Цена более высокой скорости
Некоторые энтузиасты электроники разгоняют процессоры, заставляя их работать на частоте выше максимальной частоты, заявленной производителем, чтобы получить более высокую производительность. Однако при неудачном разгоне компьютер становится нестабильным и через некоторое время может зависнуть.
Фундаментальная причина зависания та же, что описана выше: процессор работает слишком быстро, некоторые последовательностные логические элементы обновляются не теми данными, которые ожидались, и в итоге процессор попадает в некорректное состояние.
В схеме существует множество комбинационных элементов, а рабочая частота ограничивается комбинационным путём с наибольшей задержкой. Этот путь называется critical path. Чтобы найти critical path, EDA-инструменты считывают информацию о задержках стандартных ячеек из библиотеки стандартных ячеек, анализируют синтезированный нетлист и вычисляют суммарную задержку всех стандартных ячеек на каждом комбинационном пути; путь с наибольшей суммарной задержкой является critical path. Такая оценка выполняется на основе нетлиста и delay information библиотека стандартных ячеек и не требует моделирования процесса работы схемы, поэтому называется статический временной анализ (STA). Следует отметить, что cell.lib выше был лишь упрощённым примером и не содержит delay information, поэтому для STA он непригоден.
Однако библиотека стандартных ячеек ICsprout55 уже содержит полную информацию о задержках cells. После того как ECC завершает синтез и получает нетлист, отображённый на стандартные ячейки ICsprout55, он передаёт нетлист и файл с информацией о стандартных ячейках из PDK в открытый инструмент статического временного анализа iSTA. iSTA быстро оценивает задержки путей RTL design и сообщает несколько путей с наибольшим отклонением от целевой частоты.
Оцените производительность схемы
Попробуйте оценить производительность схемы через ECC Compiler и прочитайте отчёт статический временной анализ, чтобы определить максимальную частоту, на которой может работать целевая схема.
Пока мы не требуем понимания всех деталей отчёта; больше материала по STA будет на этапе B. Если детали интересуют уже сейчас, обратитесь к этому руководству или найдите материалы о чтении timing reports. Другие инструменты также генерируют timing reports; их формат может отличаться, но большинство используемых понятий одинаковы.
На самом деле полученный таким способом timing report не может полностью отражать частоту готового tapeout-чипа. нетлист содержит только стандартные ячейки и их топологию, но не физические координаты cells. Если две стандартные ячейки физически расположены далеко друг от друга, сигналу между ними требуется дополнительное время для распространения — это называется задержка соединения. Атрибуты задержки стандартных ячеек в библиотеке описывают только задержку прохождения сигнала непосредственно через cell — задержка логики. Полная задержка должна включать и задержка логики, и задержка соединения. Поэтому частота, полученная указанным выше способом, основана только на задержка логики. Только после размещения и трассировка EDA-инструменты получают достаточно точную информацию о задержка соединения и могут оценить частоту, более близкую к реальному tapeout.
Означает ли это, что текущая оценка частоты бесполезна? Нет. С одной стороны, физическое проектирование также требует времени; для сложных high-performance processors один прогон физического проектирования может занимать даже несколько дней. Чтобы получить более точные данные о задержке и частоте, проектная команда должна потратить больше времени, что снижает скорость итераций. С другой стороны, хотя задержка логики не является окончательной задержкой, она уже задаёт верхнюю границу частоты и способна выявлять проблемы RTL-логики, например чрезмерно сложные комбинационные схемы. Этого достаточно для предварительной оценки RTL design и быстрых итераций оптимизации. Методы оптимизации подробнее будут рассмотрены на этапе B.
Для процессора частота — не единственная характеристика производительности. Частота также означает количество тактов в секунду, но далеко не каждый такт обязательно содержит «полезную работу». Задача процессора — выполнять программы, поэтому его производительность следует понимать как «эффективность выполнения программ». Более конкретно процессор выполняет инструкции программы. Если процессор имеет очень высокую частоту, но тратит много тактов на выполнение одной инструкции, в целом его нельзя считать отличным процессором. Поэтому нужен ещё один показатель эффективности выполнения инструкций — IPC (Instructions Per Cycle), измеряющий среднее число инструкций, выполняемых процессором за один цикл. Измерение и оптимизацию IPC мы продолжим обсуждать на этапе B.
Оценка энергопотребления
Для оценки энергопотребления схемы необходимо оценить сумму энергопотребления всех стандартных ячеек. EDA-инструменты считывают power information стандартных ячеек из библиотеки, вычисляют энергопотребление каждой cell и затем суммарное энергопотребление схемы. Как и в случае оценки задержки, простой пример cell.lib выше не содержит power information и не подходит для power analysis.
библиотека стандартных ячеек ICsprout55 содержит полную информацию об энергопотреблении. Инструмент iSTA, вызываемый ECC после синтеза, способен оценивать не только производительность RTL design, но и его энергопотребление: iSTA быстро рассчитывает и сообщает энергопотребление каждой стандартной ячейки и общее энергопотребление RTL design.
Оцените энергопотребление схемы
На примере проекта бегущего огня отчёт power analysis находится в light/runs/default/Synthesis_yosys/report/post_synthesis/power.rpt.
Попробуйте прочитать этот отчёт и познакомиться с информацией об энергопотреблении схемы.
В отчёте приводятся три типа энергопотребления:
Internal Power— внутреннее энергопотребление. Когда транзисторы переключаются, nMOS и pMOS не меняют состояние мгновенно, и в течение очень короткого времени оба одновременно проводят ток. Это создаёт ток короткого замыкания от питания к земле. Мощность, связанная с этим током, называется internal power, или short-circuit power. Internal power является частью dynamic power.Switching Power— энергопотребление переключений. При переключении CMOS-схемы между0и1соответствующая эквивалентная ёмкость должна заряжаться или разряжаться. Энергия этого процесса называется switching power. Она также относится к dynamic power. То есть dynamic power состоит из internal power и switching power.Leakage Power— энергопотребление утечек. В идеальном случае в отсечённом транзисторе между source и drain ток не течёт. В реальности из-за различных физических эффектов существует небольшой leakage current. Мощность, создаваемая этим током, называется leakage power. Поскольку она существует даже без переключений транзисторов, её также называют static power.
Ограничения открытых EDA-инструментов
Качество синтеза yosys не очень высоко и всё ещё уступает коммерческим синтезаторам. Однако для post-synthesis timing evaluation этот недостаток не оказывает серьёзного влияния. Даже если абсолютное качество синтеза yosys невысоко, относительные изменения результатов всё равно могут направлять RTL-оптимизацию.
Нужна ли FPGA для изучения «One Student One Chip»?
В основном — нет:
- С точки зрения точности flow yosys ориентирован на ASIC design; и его принципы, и отчёты лучше подходят для «One Student One Chip». FPGA flow имеет другие принципы и не может заменить ASIC flow. Даже если FPGA flow проходит успешно, стандартный ASIC flow всё равно требует нетлист функциональной симуляции и временную симуляцию.
- С точки зрения времени основная польза FPGA — ускорение симуляции. Если задача симуляции и без того выполняется быстро, преимущество FPGA невелико. В полном flow преимущество FPGA проявляется лишь когда выполняется:
Обычно имеет порядок часов, тогда как обычно занимает несколько минут. Поэтому неравенство может выполняться только если также достигает порядка часов. При изучении «One Student One Chip» вы редко столкнётесь с симуляциями такой длительности. А когда это произойдёт, к FPGA evaluation flow будут предъявляться более высокие требования; к этому вопросу мы вернёмся на этапе B.
- С точки зрения сложности отладки возможности FPGA сильно ограничены: доступна в основном низкоуровневая waveform information в ограниченном временном и пространственном окне. Software simulation значительно гибче, и для повышения эффективности отладки можно использовать множество программных методов.
PDK и библиотека стандартных ячеек
Упомянутый выше cell.lib был лишь простым примером библиотеки стандартных ячеек. Теперь познакомимся с PDK ICsprout55. Вы уже использовали ICsprout55 при синтезе проекта бегущего огня. Можно открыть синтезированный нетлист и увидеть, что инстанцированные в нём cells являются стандартными ячейками ICsprout55.
Содержимое PDK
Как упоминалось выше, PDK содержит множество ресурсов конкретного process node: device models, правила проектирования, process constraints, verification files, библиотеки стандартных ячеек и так далее. библиотека стандартных ячеек представляет собой набор стандартных ячеек и их атрибутов; эти атрибуты включают logical functions, transistor structures, timing, энергопотребление, physical dimensions и другую информацию. Обычно информация распределена между несколькими форматами файлов PDK; .lib — только один из них. Например, ICsprout55 содержит следующие файлы (список неполный):
.
├── IP
│ ├── IO # IO library
│ └── STD_cell # Standard cell library
│ └── ics55_LLSC_H7C_V1p10C100 # Version number
│ ├── ics55_LLSC_H7CL # LVT standard cells
│ │ ├── cdl
│ │ │ └── ics55_LLSC_H7CL.cdl # Transistor-level information of standard cells
│ │ ├── cell_list
│ │ │ └── ics55_LLSC_H7CL.txt # Name list of standard cells
│ │ ├── doc # Documentation of standard cells
│ │ ├── lef
│ │ │ └── ics55_LLSC_H7CL.lef # Physical geometry information of standard cells
│ │ ├── liberty
│ │ │ └── ics55_LLSC_H7CL_typ_tt_1p2_25_nldm.lib # Logical functions
│ │ │ # and PPA information of standard cells
│ │ └── verilog
│ │ └── ics55_LLSC_H7CL.v # Verilog behavioral simulation models of standard cells
│ └── ics55_LLSC_H7CR
└── prtech
└── techLEF
└── N551P6M.lef # Process-related design specifications
Все эти файлы являются текстовыми и могут быть открыты обычным текстовым редактором.
Название открытой сейчас библиотеки стандартных ячеек в ICsprout55 — ics55_LLSC_H7C_V1p10C100. Здесь ics55 — сокращение ICsprout55, LLSC означает Low Leakage Standard Cell, H7 означает высоту стандартных ячеек в 7 tracks, C — major version (ранее существовали версии A и B), а V1p10C100 — конкретная minor version.
В полном processor design flow разные этапы используют разные файлы. Например, технологическое отображение при синтезе читает .lib и по logical functions стандартные ячейки отображает логически эквивалентные подсхемы на подходящие cells; симуляцию нетлиста читает .v, чтобы RTL simulator моделировал поведение на уровне стандартные ячейки и проверял функциональную эквивалентность синтезированного нетлиста; размещение читает .lef, чтобы по физическим размерам cells определить их расположение.
Структура чипа с точки зрения технологического процесса
Чтобы понимать информацию PDK и последующие этапы физического проектирования, сначала необходимо представить структуру чипа с технологической точки зрения. В производство полупроводников физическая структура чипа иерархична. Например, боковой разрез чипа некоторого процесса можно представить так:
-------------------- M7 ------ Power
| | | | | | | | |
-------------------- M6 ------ Clock
| | | | | | | | |
-------------------- M5 --+
| | | | | | | | | |
-------------------- M4 |
| | | | | | | | | +--- Wiring between standard cells
-------------------- M3 |
| | | | | | | | | |
-------------------- M2 --+
| | | | | | | | |
-------------------- M1 ------ Wiring between transistors
| | | | | | | | | <------- Via
===================== Poly-silicon --+
+++++++++++++++++++++ dielectric +--- Transistors
ooooooooooooooooooooo Silicon substrate --+
Самый нижний слой — кремниевая подложка, содержащий source и drain транзисторов; над ним расположен диэлектрический слой, также называемый слой подзатворного оксида, обычно из диоксида кремния; выше находится слой поликремния, образующий gate транзисторов. Эти три слоя реализуют физическую структуру транзистора.
Над слой поликремния находятся несколько слои металлизации, проводимость которых используется для передачи сигналов, соединения транзисторов и формирования функций gate circuits или стандартные ячейки. Соединения бывают двух видов: внутрислойные и межслойные. Первые прокладываются в пределах одного слой металлизации, вторые проходят между разными layers через vias. Связи между компонентами, описанные в RTL logic design, физически реализуются именно металлизацией.
Для различения слои металлизации им присваивают номера: чем больше номер, тем выше слой. Разные layers имеют разные требования к ширине и расстоянию между проводниками и выполняют разные роли:
| слой металлизации | Ширина проводника | Расстояние | Характеристики | Роль |
|---|---|---|---|---|
| Нижний | Маленькая | Маленькое | Высокое сопротивление, небольшая дальность, высокая плотность трассировки | Соединение транзисторов для формирования gate circuits и стандартные ячейки |
| Средний | Средняя | Среднее | Среднее сопротивление, средняя дальность и плотность | Соединение стандартных ячеек и реализация основной логики |
| Верхний | Большая | Большое | Низкое сопротивление, большая дальность, низкая плотность трассировки | Питание |
Количество слои металлизации зависит от технологии. Например, структура выше обозначается 1P7M: P означает Poly, а M — Metal, следовательно 1P7M содержит 1 слой поликремния и 7 слои металлизации. В этом примере M1 — нижний слой, M2–M6 — средние, M7 — верхний. Таким образом, 5 средних слоёв доступны специально для соединений стандартные ячейки.
Среди сигналов между стандартными ячейками clock signals отличаются от data signals. Clock должен подключаться к большому числу триггеры, поэтому путь его распространения длиннее, чем у обычных data signals; обычно используется более широкий проводник, например в 2 раза шире data signal. Backend engineers задают эти параметры EDA-инструментам. Они также выбирают слой металлизации для clock; теоретически можно использовать любой средний слой, но часто выбирают слой непосредственно под верхним — например M6 в схеме выше.
Более современные процессы обычно предоставляют больше layers, например 1P9M, 1P11M, что увеличивает пространство трассировки между стандартными ячейками. Но для производства требуется больше masks металлизации, поэтому растёт стоимость.
Атрибуты слои металлизации записываются в process LEF PDK. LEF имеет расширение .lef и использует формат Library Exchange Format. В текстовом виде он описывает физические слои процесса: слои металлизации, vias, топология rules и так далее.
vim icsprout55/prtech/techLEF/N551P6M.lef
Например, в файле можно найти определение LAYER MET1; связанные поля описывают первый слой металлизации.
LAYER MET1
TYPE ROUTING ;
DIRECTION HORIZONTAL ;
PITCH 0.2 0.2 ;
WIDTH 0.09 ;
OFFSET 0.1 0.1 ;
AREA 0.042 ;
SPACING 0.09 ;
MAXWIDTH 10 ;
MINENCLOSEDAREA 0.18 ;
CAPACITANCE CPERSQDIST 0.0007630 ;
EDGECAPACITANCE 0.0000339 ;
RESISTANCE RPERSQ 0.1122 ;
DCCURRENTDENSITY AVERAGE 1.5 ;
END MET1
Поле TYPE имеет значение ROUTING, то есть layer используется для трассировки. WIDTH и PITCH задают соответственно минимальную ширину проводника и минимальное расстояние между проводниками в единицах , как показано ниже. Подробнее о LEF можно прочитать в руководстве.
WIDTH
|
<-+->
| | | |
| | | |
| | | |
| | | |
|wire | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | PITCH | |
| | | | |
| | | | |
| | | | |
|<---------------+-------------->|
Перед слои металлизации также можно увидеть LAYER POLY, но у него есть только поле TYPE. слой поликремния вместе с диэлектрический слой и кремниевая подложка используется для формирования транзисторов; параметры транзисторов задаются технологией и для backend-задачи физического проектирования практически фиксированы, тогда как слои металлизации EDA-инструменты могут использовать динамически для трассировки. Поэтому в LEF достаточно объявить существование POLY; дополнительные технологические детали записаны в других файлах, например GDS. Аналогично диэлектрический слой и кремниевая подложка функционально тесно связаны с слой поликремния и вообще не обязаны присутствовать в LEF.
Изучите слои металлизации ICsprout55
Прочитайте process LEF ICsprout55. Сколько слои металлизации он содержит? Попробуйте по ширине и spacing определить назначение каждого слоя.
Если процессор очень сложен, например out-of-order superscalar high-performance processor, число проводников между стандартными ячейками становится огромным, создавая сильную нагрузку на трассировку. Проводникам приходится делать обходы, что увеличивает площадь чипа, задержка соединения и снижает частоту. При слишком высокой congestion трассировка может вообще завершиться неудачно, и корректный чип невозможно будет изготовить. Поэтому для high-performance processors обычно выбирают технологии с большим числом слои металлизации. Например, команда Xiangshan в процессе проектирования экспериментировала с переходом с 1P9M на 1P11M; без изменения RTL-кода это позволило уменьшить задержка соединения и повысить частоту.
Технологические процессы с несколькими poly-silicon layers
Не все процессы имеют только один слой поликремния. Для некоторых применений используются дополнительные poly layers. Например, memory cells flash memory используют floating-gate transistors — специальные транзисторы с двумя gates. Floating gate может находиться в состояниях «заряд хранится» и «заряд не хранится», представляя 0 и 1; control gate используется для управления чтением и записью. Для таких транзисторов flash memory может использовать процесс 2P8M, где два poly-silicon layers реализуют floating gate и control gate соответственно.
Атрибуты стандартных ячеек
библиотека стандартных ячеек в PDK обычно содержит множество cells. Чтобы было проще понимать их свойства, имена стандартных ячеек обычно следуют определённым соглашениям. В ICsprout55 используется схема function + drive strength + H + number of tracks + threshold voltage. Например, NAND2X1H7L означает 2-input NAND gate, drive strength X1, то есть единичную стандартную drive strength, высоту 7 tracks и LVT threshold voltage. OR3X0P5H7R означает 3-input OR gate, drive strength X0P5, то есть 0.5 стандартной drive strength (P обозначает десятичную точку), высоту 7 tracks и RVT threshold voltage. Далее на примере NAND2X1H7L рассмотрим соответствующие файлы библиотеки и атрибуты стандартных ячеек.
LIB-файлы — функция, timing и энергопотребление
LIB-файлы имеют расширение .lib и используют формат Liberty Timing File. Они описывают в текстовом виде функции стандартных ячеек, а также timing и энергопотребление при определённых условиях.
cd icsprout55/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/
vim ics55_LLSC_H7CL/liberty/ics55_LLSC_H7CL_typ_tt_1p2_25_nldm.lib
При простом просмотре видно, что LIB-файл состоит из header fields и описаний множества стандартные ячейки (cell). Например, можно напрямую найти NAND2X1H7L:
cell (NAND2X1H7L) {
area : 1.12;
cell_footprint : "NAND2X1H7L";
cell_leakage_power : 0.434974;
pg_pin (VDD) {
pg_type : primary_power;
voltage_name : "VDD";
}
pg_pin (VSS) {
pg_type : primary_ground;
voltage_name : "VSS";
}
leakage_power () {
value : 0.312371;
when : "(A * B * !Y)";
related_pg_pin : VDD;
}
leakage_power () {
value : 0;
when : "(A * B * !Y)";
related_pg_pin : VSS;
}
leakage_power () {
value : 0.82883;
when : "(A * !B * Y)";
related_pg_pin : VDD;
}
leakage_power () {
value : 0;
when : "(A * !B * Y)";
related_pg_pin : VSS;
}
leakage_power () {
value : 0.565379;
when : "(!A * B * Y)";
related_pg_pin : VDD;
}
leakage_power () {
value : 0;
when : "(!A * B * Y)";
related_pg_pin : VSS;
}
leakage_power () {
value : 0.0333159;
when : "(!A * !B * Y)";
related_pg_pin : VDD;
}
leakage_power () {
value : 0;
when : "(!A * !B * Y)";
related_pg_pin : VSS;
}
leakage_power () {
value : 0.434974;
related_pg_pin : VDD;
}
leakage_power () {
value : 0;
related_pg_pin : VSS;
}
pin (Y) {
direction : output;
function : "(!A) + (!B)";
output_voltage : default_VDD_VSS_output;
power_down_function : "(!VDD) + (VSS)";
related_ground_pin : VSS;
related_power_pin : VDD;
max_capacitance : 0.055;
timing () { ...... }
timing () { ...... }
internal_power () { ...... }
internal_power () { ...... }
internal_power () { ...... }
internal_power () { ...... }
}
pin (A) {
direction : input;
driver_waveform_fall : "PreDriver20.5:fall";
driver_waveform_rise : "PreDriver20.5:rise";
input_voltage : default_VDD_VSS_input;
related_ground_pin : VSS;
related_power_pin : VDD;
max_transition : 0.795659;
capacitance : 0.000898206;
rise_capacitance : 0.000898206;
rise_capacitance_range (0.000705173, 0.000898206);
fall_capacitance : 0.000888785;
fall_capacitance_range (0.000696354, 0.000888785);
internal_power () { ...... }
internal_power () { ...... }
}
pin (B) {
direction : input;
driver_waveform_fall : "PreDriver20.5:fall";
driver_waveform_rise : "PreDriver20.5:rise";
input_voltage : default_VDD_VSS_input;
related_ground_pin : VSS;
related_power_pin : VDD;
max_transition : 0.795659;
capacitance : 0.000953054;
rise_capacitance : 0.000953054;
rise_capacitance_range (0.000589512, 0.000953054);
fall_capacitance : 0.000952783;
fall_capacitance_range (0.000588209, 0.000952783);
internal_power () { ...... }
internal_power () { ...... }
}
}
На данном этапе мы уже можем понять следующие атрибуты; единицы некоторых из них определены в header fields:
- Area (
area), обычно в - Leakage power (
leakage_power), включая leakage power стандартная ячейка при различных условиях - Internal power (
internal_power), включая внутреннее энергопотребление стандартная ячейка при различных условиях - Pins (
pin), включая направление (direction), capacitance и т. д.; для output pins дополнительно:- Функция (
function), задаваемая логическим выражением, по которому можно понять функцию стандартная ячейка - Timing (
timing), содержащий задержки стандартной ячейки при различных условиях
- Функция (
Немного подробнее о area. Чип является трёхмерным объектом, и стандартные ячейки также существуют в трёхмерном пространстве. Для удобства предположим, что чип расположен горизонтально и введена трёхмерная система координат. Площадь стандартной ячейки означает площадь её проекции на горизонтальную плоскость, то есть площадь в top view. С учётом структуры процесса это также площадь, занимаемая стандартная ячейка в слой поликремния и нижних слои металлизации.
Из этих атрибутов видно, что LIB-файлы в основном используются для synthesis, timing analysis и power analysis. Например, yosys при технологическом отображении читает LIB и по полю function решает, какие подсхемы отображать на какие стандартные ячейки, сохраняя логическую эквивалентность нетлист исходному RTL. iSTA по полям timing рассчитывает задержка логики стандартные ячейки при разных условиях и в итоге сообщает самые длинные пути нетлист.
RTFM
Приведённый LIB-файл содержит миллионы строк, поэтому читать его напрямую неудобно. Рекомендуется пользоваться data book стандартные ячейки: icsprout55/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CL/doc/ics55_LLSC_H7CL_TYPICAL_V1P2_T25.pdf.
Если нужно понять конкретное значение каждого поля LIB, обратитесь к руководству формата Liberty Timing File.
Verilog-файлы — behavioral models
Один из способов проверить эквивалентность синтезированного нетлиста исходному RTL design — выполнить симуляцию нетлиста, то есть моделировать нетлист вместе с поведением стандартных ячеек. Хотя поле function в LIB также описывает поведение cells, RTL simulators обычно не понимают LIB. Поэтому библиотека стандартных ячеек обычно предоставляет Verilog behavioral models.
В ICsprout55 behavioral models находятся здесь:
cd icsprout55/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/
vim ics55_LLSC_H7CL/verilog/ics55_LLSC_H7CL.v
Например, модель NAND2X1H7L выглядит так:
module NAND2X1H7L (Y, A, B);
output Y;
input A, B;
nand (Y, A, B);
endmodule //NAND2X1H7L
Как видно, здесь функция стандартной ячейки просто ещё раз реализована на Verilog. Встроенный primitive nand реализует 2-input NAND gate. Если передать нетлист вместе с файлом behavioral models RTL-симулятору, он сможет инстанцировать стандартные ячейки из нетлиста по определениям модулей в model file и выполнить симуляцию на уровне нетлиста.
Behavioral models ICsprout55 могут использоваться не только для функциональной симуляции, но и содержат подробную временная информация, задаваемую операторами specify, поэтому позволяют выполнять временную симуляцию нетлист.
LEF-файлы — информация о физической геометрии
Выше уже рассматривались process-related LEF. Существует также LEF, связанный непосредственно со стандартными ячейками и описывающий их физическую геометрию.
cd icsprout55/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/
vim ics55_LLSC_H7CL/lef/ics55_LLSC_H7CL.lef
Например, NAND2X1H7L описан следующим образом:
MACRO NAND2X1H7L
CLASS CORE ;
ORIGIN 0 0 ;
FOREIGN NAND2X1H7L 0 0 ;
SIZE 0.8 BY 1.4 ;
SYMMETRY X Y ;
SITE core7 ;
PIN A
DIRECTION INPUT ;
USE SIGNAL ;
PORT
LAYER MET1 ;
RECT 0.055 0.425 0.23 0.59 ;
END
END A
......
END NAND2X1H7L
SYMMETRY X Y означает, что стандартную ячейку можно симметрично отражать относительно оси или для улучшения размещения, например уменьшения задержка соединения до конкретного порта. Поле PIN описывает атрибуты pin, включая направление (DIRECTION) и геометрию порта (PORT). PORT указывает, что порт занимает прямоугольник на layer MET1, форма которого задаётся RECT.
SITE задаёт правило выравнивания при размещении. Значение core7 ссылается на правило, определённое в process LEF:
SITE core7
SIZE 0.200 BY 1.400 ;
CLASS CORE ;
SYMMETRY Y ;
END core7
SYMMETRY Y означает возможность симметричного размещения относительно оси $y. SIZE 0.200 BY 1.400задаёт сетку0.2 X 1.4: координата по $x$ при placement должна быть кратна 0.2, а координата по $y$ — кратна 1.4. Если снова посмотреть на SIZEдляNAND2X1H7L, размеры 0.8по $x$ и1.4по $y$ являются целыми кратными0.2и1.4. В более общем смысле SITE` определяет grid cell, и по размеру каждая стандартная ячейка представляет собой прямоугольник из одной или нескольких таких grid cells.
Таким образом, LEF подробно описывает геометрию стандартных ячеек. Эта информация позволяет EDA-инструментам корректно размещать cells внутри чипа.
CDL-файлы — описание транзисторной структуры
CDL-файлы имеют расширение .cdl и основаны на Circuit Description Language, который в текстовом виде описывает transistor structure стандартные ячейки.
cd icsprout55/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/
vim ics55_LLSC_H7CL/cdl/ics55_LLSC_H7CL.cdl
Формат описания транзисторной структуры:
.SUBCKT subcircuit name port1 port2 ...
transistor instance name drain gate source substrate transistor type channel width channel length
...
.ENDS
Для NAND2X1H7L:
.SUBCKT NAND2X1H7L A B VDD VSS Y
*.PININFO A:I B:I Y:O VDD:B VSS:B
MMN0 Y B net6 VSS nm1p2_lvt_lp W=210n L=60n m=1
MMN1 net6 A VSS VSS nm1p2_lvt_lp W=210n L=60n m=1
MMP1 Y B VDD VDD pm1p2_lvt_lp W=270n L=60n m=1
MMP0 Y A VDD VDD pm1p2_lvt_lp W=270n L=60n m=1
.ENDS
Строки, начинающиеся с *, являются комментариями. .SUBCKT определяет subcircuit, то есть стандартная ячейка, с именем NAND2X1H7L и пятью портами A, B, VDD, VSS, Y. Строка MMN0 инстанцирует nMOS transistor MMN0: drain подключён к Y, gate — к B, source — к net net6, substrate — к VSS; используется transistor type nm1p2_lvt_lp, ширина и длина channel равны соответственно и . Остальные строки аналогичным образом описывают другие transistors и их соединения.
Нарисуйте transistor structure по CDL
Попробуйте нарисовать transistor structure стандартная ячейка NAND2X1H7L по приведённому CDL и проверьте, действительно ли его функция соответствует NAND gate.
Transistor structure из CDL в основном используется для transistor-level SPICE simulation и для проверки соответствия GDS-топологии логике нетлиста. Последняя проверка называется LVS (Layout Versus Schematic).
GDS-файлы — физический топология
GDS-файлы имеют расширение .gds и содержат всю физическую и технологическую информацию, необходимую для производства стандартная ячейка. Это не текстовый формат; для чтения нужны специальные инструменты. GDS ICsprout55 пока не открыт. Однако «One Student One Chip» не требует понимания конкретного содержимого GDS, поэтому здесь подробно его рассматривать не будем.
Классификация стандартные ячейки
В библиотеке стандартных ячеек существует множество типов cells. Их можно классифицировать по функции, включая следующие категории. В общем случае первые пять категорий и clock buffers являются обязательными, чтобы базовые функции различных designs могли быть реализованы корректно. Дополнительные типы cells позволяют получать лучший design для конкретного сценария или предоставлять более удобные функции тестирования и отладки чипа.
Logic gate cells
Logic gate cells включают basic logic gates — AND, OR, NOT и так далее — и complex logic gates.
Разберитесь в функции complex logic gate cells
В LIB ICsprout55 есть стандартные ячейки с именами вроде OAI22X1H7L, функция которых не очевидна. Найдите атрибуты OAI22X1H7L и определите её функцию.
Из LIB видно, что функция OAI22X1H7L сложнее одного logic gate. По законам де Моргана логическое выражение output port можно преобразовать:
(!A0 * !A1) + (!B0 * !B1) = !(A0 + A1) + !(B0 + B1) = !((A0 + A1) * (B0 + B1))
Здесь + означает OR, * — AND, ! — NOT. Таким образом, функция включает два 2-input OR gates, один 2-input AND gate и один NOT gate. Такой gate называется complex gate. Если посмотреть площади соответствующих стандартных ячеек:
area(OAI22X1H7L) = 1.96
area(OR2X1H7L)*2 + area(AND2X1H7L) + area(INVX1H7L) = 1.68*2 + 1.68 + 0.84 = 5.88
Площадь OAI22X1H7L значительно меньше, чем у набора логически эквивалентных basic logic gates. Это связано с тем, что логические функции AND и OR на уровне transistor series/parallel соединений реализуются дешевле, чем через отдельные AND/OR cells. Экономия касается не только площади, но и delay и power. Поэтому библиотека стандартных ячеек содержит не только простые gates, но и transistor-level complex gates вроде OAI22X1H7L, позволяя получать лучший PPA.
Разберитесь в transistor structure OAI22
Найдите transistor structure OAI22X1H7L в CDL. Сколько transistors она содержит? Попробуйте понять, как структура реализует логическое выражение OAI22X1H7L.
Именование OAI22
Имя OAI22 несёт смысл: OAI означает Or-And-Invert, а 22 — две группы входных сигналов по два в каждой. Пусть входы — A0, A1, B0, B1. Сначала Or применяется внутри каждой группы: A0 | A1 и B0 | B1; затем результаты объединяются And: (A0 | A1) & (B0 | B1); наконец выполняется Invert, получая !((A0 | A1) & (B0 | B1)).
Разберитесь в функции complex logic gate cells (2)
Аналогично существует стандартная ячейка AOI221. Попробуйте по имени записать её логическое выражение и сравнить его с function в библиотеке стандартных ячеек.
Суффиксы X1, X4 и т. п. обозначают drive strength. Drive strength — ток, который стандартная ячейка способна source или sink при сохранении заданного диапазона напряжения; он влияет на время переключения downstream cells. Поэтому NAND2X1H7L, NAND2X2H7L и NAND2X4H7L логически полностью эквивалентны, но NAND2X4H7L предоставляет большую drive strength и быстрее переключает downstream logic. Однако для этого нужны более крупные или дополнительные transistors, поэтому площадь и энергопотребление NAND2X4H7L выше.
Разберитесь в drive strength
Сравните соответствующие атрибуты NAND2X1H7L, NAND2X2H7L и NAND2X4H7L, включая площадь и энергопотребление.
Разберитесь в drive strength (2)
Посмотрите transistor structure NAND2X2H7L. Чем она отличается от NAND2X1H7L?
С учётом компромисса между performance, area и power стандартные ячейки с высокой drive strength обычно используются на critical paths, чтобы уменьшить delay и повысить frequency; cells с меньшей drive strength применяются на non-critical paths, не влияющих на frequency, чтобы уменьшить общую площадь и power без снижения частоты.
Sequential cells
Sequential cells включают триггеры, latches и другие элементы, в том числе различные типы с clear/set terminals или без них, например DFFX1H7L.
Нарисуйте transistor structure по CDL (2)
Найдите transistor structure DFFX1H7L в CDL. TSINV — tristate inverter; его структура описана в .SUBCKT TSINV. Нарисуйте transistor structure DFFX1H7L по CDL. Из скольких transistors состоит эта стандартная ячейка? Попробуйте понять, как эта структура реализует функцию триггер.
I/O cells
Чип взаимодействует с внешним миром через I/O cells. Они соединяют внутренние I/O signals чипа с metal bonding pads. После производства packaging выводит от этих pads металлические pins, через которые внешние сигналы взаимодействуют с внутренними I/O signals.
I/O cells ICsprout55 можно посмотреть в соответствующем LIB:
cd icsprout55/IP/IO/ICsprout_55LLULP1233_IO_251013/
vim liberty/ICSIOA_N55_3P3_tt_1p2_3p3_25c.lib
I/O cells делятся на:
- Data I/O cells, также GPIO, для входа и выхода data signals, например
P65_1233_PBMUX. - Core power cells для питания transistors внутри чипа, включая source power VSS и drain power VDD, например
P65_1233_VSS1иP65_1233_VDD1. - I/O power cells для питания data I/O cells, например
P65_1233_VSSIO3иP65_1233_VDDIO3. Data I/O cells намного сложнее обычных стандартных ячеек, поэтому их требования к питанию отличаются; core power cells нельзя использовать для питания data I/O cells.
Хотя I/O cells являются частью библиотеки стандартных ячеек, их площадь на несколько порядков больше обычных стандартных ячеек. Связь с внешним миром предъявляет дополнительные требования: высокая drive strength для отправки сигналов наружу, protection circuits против внешнего статического электричества, соответствие физическим размерам и требованиям пайки chip pins, включая spacing, metal thickness и reserved blank areas для предотвращения short circuits. Поэтому circuit-level implementation I/O cells намного сложнее, чем обычных стандартных ячеек.
Изучите размеры I/O cells
Найдите в ICsprout55 размеры 2-input NAND gate и одной I/O cell и сравните их.
Driver cells
Driver cells используются для усиления drive strength signal, обеспечения signal integrity и оптимизации timing/load. Если сигнал проходит слишком большое расстояние или имеет слишком большой fan-out, его delay может сильно увеличиться из-за недостаточной drive strength, а форма сигнала может искажаться. Вставка driver cells помогает решить эти проблемы. В частности:
- Логически non-inverting driver cells, также buffers, имеют выход, логически равный входу. В ICsprout55 это
BUFX1H7L,BUFX2H7L,BUFX4H7Lи т. д.; большее число послеXозначает более высокую drive strength. - Логически inverting driver cells, также inverters, функционально эквивалентны NOT gate и также существуют с разными drive strengths.
Physical cells
Physical cells сами не имеют логической функции и решают задачи backend-задачи физического проектирования, не связанные непосредственно с логикой схемы. Распространённые типы:
- Pull-up/pull-down cells. У них нет inputs, только outputs; они предоставляют
logic 0иlogic 1. В ICsprout55 это соответственноTIELOH7LиTIEHIH7L. - Filler cells. Заполняют пустые области чипа, обеспечивая непрерывность определённых layers, например power layer, и предотвращая производственные дефекты. В ICsprout55:
FILLER1H7L,FILLER2H7Lи т. д. - Decoupling cells (decap). Уменьшают влияние dynamic voltage drop при одновременном переключении большого количества cells. В ICsprout55:
FILLCAP4H7L,FILLCAP8H7Lи др. - Antenna effect repair cells. На этапе ion etching производства при определённых условиях может возникнуть antenna effect, способный пробить transistors. Размещение специальных cells в подходящих местах устраняет этот эффект. В ICsprout55:
ANT2H7L,ANT4H7L.
Macro cells
Macro cells — это стандартные ячейки со специфическими функциями, физическая реализация которых заранее разработана vendor, например wafer fab или IP vendor, и которые имеют сравнительно большую площадь: SRAM, DDR PHY и т. п. SRAM — распространённый macro cell в processor design. ICsprout55 пока не открыл соответствующие macro cells.
Complex function units
Complex function units включают мультиплексоры, half-adders, full-adders, comparators и т. д. По сравнению с построением эквивалентной функции из basic logic gates, предоставление таких функций как стандартные ячейки позволяет добиться лучшего PPA. В ICsprout55 сюда относятся MUX2X1H7L, MUXI2X1H7L, ADDHX1H7L, ADDFX1H7L и др.
Full-custom circuits complex cells
На примере ADDHX1H7L найдите площадь и transistor structure стандартная ячейка. Предположим, библиотека не содержит half-adder cell и half-adder нужно построить из basic logic gates. Рассчитайте требуемую площадь и число transistors в этом случае.
Clock-specific cells
Clock-specific cells специально предназначены для clock signals и включают clock buffers, clock gating cells, logic gates для обработки clock и т. д. Обычные стандартные ячейки вроде AND gates или buffers не подходят для clock из-за особенностей clock signal:
- Даже небольшое изменение clock может нарушить работу триггеры. Например, glitch из-за jitter может быть ошибочно воспринят триггер как clock edge.
- Delay clock signal влияет на timing триггеры и, следовательно, на рабочую frequency всей схемы.
- Все триггеры подключены к clock, поэтому fan-out clock signal очень велик, а расстояние распространения большое, что требует сильной drive strength. Как уже упоминалось, clock обычно прокладывается более широкими проводниками.
Поэтому разработчики библиотеки стандартных ячеек специально проектируют clock-specific cells с low jitter, low delay и high drive strength.
В ICsprout55 к ним относятся ICGX1H7L, ICGNX1H7L и др.
Power management cells
Power management cells используются для low-power design и включают power gating cells, isolation cells и т. д. ICsprout55 пока такие cells не открыл.
Test and debug cells
Test and debug cells поддерживают тестирование и отладку произведённых chips, включая scan chain cells, Built-In Self Test (BIST) control cells и т. д.
Scan chain cells используются в Design for Testability (DFT). На основе обычных триггеры они добавляют scan enable SE и scan input SI. Когда SE активен, SI используется для обновления триггер. Таким образом, разработчик может извне загружать заданные состояния в триггеры и использовать это для отладки произведённого chip. Однако scan chain cells имеют большую площадь и энергопотребление, чем обычные триггеры.
В ICsprout55 test/debug cells включают SDFFX1H7L, SDFFSX1H7L, SDFFRX1H7L и т. д.
Изучите все стандартные ячейки
Используя соответствующие файлы PDK, подробнее изучите стандартные ячейки ICsprout55. По комментариям и functional attributes можно понять назначение каждой cell. После этого у вас появится базовое понимание того, как ваш RTL-код обрабатывается синтезатором.
PVT corners
Задержка схемы в основном определяется тремя факторами: Process, Voltage и Temperature. Вместе они называются PVT parameters. Backend engineers обычно выбирают несколько комбинаций PVT parameters как набор рабочих окружений и на этапе проектирования стараются гарантировать, что будущий chip сможет корректно работать в каждом из них. Эти окружения называются PVT corners.
В библиотеке стандартных ячеек разные PVT corners представлены разными LIB-файлами. Имена и площади стандартных ячеек в них одинаковы, но timing и энергопотребление различаются. Используя разные LIB при оценке, backend engineers могут определить, будет ли chip корректно работать в соответствующем PVT corner.
Process variation — неконтролируемые отклонения, возникающие при производстве chips. Например, условия для chips в центре wafer отличаются от условий у края; толщина слои металлизации transistors неоднородна; doping concentration substrate неодинакова и так далее. Всё это влияет на resistance и capacitance transistors и в конечном счёте на их delay: transistors могут становиться быстрее или медленнее.
Чтобы проверить корректную работу схемы при разных transistor delays, обычно определяют несколько случаев по скорости работы transistors — process corners. Их имена обычно состоят из двух букв. Первая обозначает скорость nMOS, вторая — pMOS. Скорость делится на typical (t), fast (f) и slow (s), причём fast и slow определяются относительно typical. В итоге используются пять комбинаций: ss, tt, ff, sf, fs. Например, fs означает, что nMOS работает быстрее typical, а pMOS — медленнее typical.
pMOS
^
| sf ff
fast + o-------------o
| | |
| | tt |
| | o |
| | |
| |ss |fs
slow + o-------------o
|
+----+-------------+---> nMOS
slow fast
Является ли `tt` «corner»?
Если на координатной плоскости по X отложить скорость nMOS, а по Y — скорость pMOS, ss, ff, sf и fs окажутся четырьмя углами прямоугольника — отсюда и термин process corner. tt находится в центре и строго говоря «углом» не является. Но как typical case backend engineers всё равно относят его к process corners.
Для ss, tt, ff скорости nMOS и pMOS изменяются примерно одинаково, поэтому в основном меняется delay, а общая функция CMOS остаётся прежней. В sf и fs один тип transistor ускоряется, а другой замедляется, из-за чего delay CMOS при переходе 0 -> 1 отличается от delay при 1 -> 0. Для корректной работы circuit elements определять delay parameters необходимо осторожнее. Но реальные process variations обладают случайностью, и вероятность того, что скорости nMOS и pMOS изменятся точно в противоположных направлениях, мала. Поэтому backend engineers часто не рассматривают sf и fs; ICsprout55 также не предоставляет для них LIB.
Process corners и модели процессоров Intel
Из-за process variation chips одной партии могут иметь разную производительность. Intel может использовать это для binning: chips одной партии, попавшие в разные process corners, продаются как разные уровни моделей. Например, большая часть chips около tt может продаваться как i5; небольшое число более быстрых chips около ff способно работать на более высокой frequency и продаваться дороже как i7; chips около ss, работающие на меньшей frequency, могут продаваться дешевле как i3 вместо выбраковки.
Voltage рабочего окружения также не является постоянным. Например, ток через power network создаёт падение напряжения на её resistance, поэтому input voltage стандартные ячейки в разных местах немного отличается: cells рядом с power I/O получают более высокое напряжение и работают быстрее; удалённые cells из-за voltage drop получают меньшее напряжение и работают медленнее. Кроме того, power supply может содержать white noise, поэтому даже у одной и той же cell скорость транзисторов колеблется во времени. Чтобы учитывать voltage fluctuation, backend engineers обычно должны гарантировать корректную работу схемы в диапазоне стандартного рабочего напряжения, то есть .
Temperature также влияет на скорость транзисторов. С одной стороны, влияет ambient temperature: chips могут работать в горячих factory workshops или в низкотемпературных условиях. С другой стороны, даже при одинаковой внешней температуре разные области chip нагреваются по-разному: там, где выше transistor density или switching frequency, выделяется больше тепла. По сравнению с комнатной температурой повышение temperature обычно замедляет транзисторы. Согласно thermodynamic effect, при высокой temperature particles обладают большей энергией и atoms semiconductor сильнее вибрируют в crystal lattice. Эти вибрации меняют направление движения electrons в transistor channel, уменьшая current и, следовательно, скорость транзистора. Поэтому для повышения robustness необходимо учитывать разные temperatures.
Имена LIB-файлов обычно содержат PVT corner. Например, ss_1p08_125 означает process corner ss, voltage 1.08V, temperature 125°C; ff_1p32_m40 — ff, 1.32V, -40°C. В integrated circuits часто вместо десятичной точки используется p (point): 1p08. Это связано и с ограничениями старых file systems/EDA tools, и с лучшей визуальной различимостью. Аналогично m (minus) может заменять -. Разные vendors используют разные conventions: например 1v08 для 1.08V, n40 для -40°C и т. д.
Попробуйте результаты оценки при разных PVT corners
ICsprout55 предоставляет LIB для разных PVT corners в icsprout55/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CL/liberty. Измените ecc.toml, который читает ECC, заменяя LIB на файлы разных PVT corners, затем повторно оцените performance и сравните результаты.
Поскольку PVT corners описывают работу одной и той же стандартная ячейка в разных окружениях, внутренняя структура и геометрия cell при разных corners полностью одинаковы. Поэтому разные LIB должны содержать лишь разную timing и power information. Оценивать chip под конкретным PVT corner означает отвечать на вопрос: «какой будет его performance, если в будущем он работает в окружении этого corner?». Реально измеренная производительность зависит от фактического рабочего окружения. Если оно не совпадает с PVT corner, использованным при design, report EDA tool не будет полностью соответствовать measured performance.
PVT corners и overclocking
Некоторые энтузиасты используют water cooling или даже liquid nitrogen для разгона процессоров и добиваются стабильной работы на более высокой frequency. Попробуйте объяснить с точки зрения PVT corners, почему такие методы позволяют успешно разгонять процессор.
Маркетинговые стратегии vendors
Некоторые vendors могут использовать разницу между PVT corner и реальным рабочим окружением в маркетинге. Например, vendor проектирует chip под ff_1p32_m40, EDA tool сообщает максимальную frequency 2GHz, и vendor рекламирует chip как 2GHz. Но после покупки пользователи обнаруживают, что реально chip стабильно работает максимум на 1.5GHz.
С одной стороны, пользователи работают примерно при 25°C, а не -40°C; с другой стороны, большинство chips партии находятся ближе к typical process variation, а ff встречается реже. Если бы vendor использовал tt_1p2_25, report EDA tool был бы ближе к реальному пользовательскому сценарию.
Поэтому, если заявленная frequency не является измеренным результатом, необходимо обращать внимание, при каком PVT corner она была оценена, чтобы объективнее оценивать реальную работу chip.
Threshold Voltage
Вспомним принцип работы транзисторов: разность между gate voltage и source voltage должна превысить определённый threshold, чтобы транзистор проводил ток; иначе он закрыт. Транзисторы с разными thresholds имеют разные электрические характеристики, поэтому стандартные ячейки из них также отличаются.
Разные threshold voltages в основном используются для компромисса между delay и static power. При более высоком threshold transistor требуется больше времени для перехода из cut-off в conducting state, поэтому delay выше. Static power, как упоминалось выше, в основном создаётся leakage current. В современной CMOS-технологии значительная часть leakage приходится на sub-threshold current. Когда транзистор переходит из conducting в cut-off, он не мгновенно становится идеальным изолятором, а проходит «sub-threshold» state. В этом состоянии возле gate остаётся слабое electric field, которое всё ещё притягивает небольшое число electrons. Хотя они не формируют полноценный channel между source и drain, возникает небольшой current от drain к source — sub-threshold current. При прочих равных:
где и не зависят от . Поскольку sub-threshold current составляет значительную часть leakage current, static power можно приблизительно считать:
где — supply voltage. Чем выше threshold voltage, тем меньше leakage current и static power. При снижении threshold voltage static power экспоненциально возрастает.
Однако стандартные ячейки с одинаковой logical function, но разными threshold voltages обычно имеют одинаковую area. Различные thresholds реализуются изменением параметров самого транзистора, например doping concentration substrate или thickness gate dielectric. Это не меняет размеры и расположение транзисторов внутри стандартной ячейки, поэтому не меняется и площадь.
стандартные ячейки обычно делятся по threshold voltage на HVT (High Voltage Threshold), RVT (Regular Voltage Threshold), LVT (Low Voltage Threshold), ULVT (Ultra-Low Voltage Threshold). HVT имеет самый высокий threshold, минимальный static power, но максимальный delay; ULVT — наоборот, минимальный threshold и delay, но максимальный static power. Некоторые vendors называют RVT как SVT (Standard Voltage Threshold). Некоторые процессы также предлагают UHVT (Ultra-High Voltage Threshold). ICsprout55 предоставляет HVT, RVT и LVT.
Попробуйте разные threshold voltages
todo
Backend engineers выбирают threshold voltage согласно application scenario chip. Для low-power application предпочитают HVT; для high-performance — LVT или ULVT. Если нужны обе цели, применяют hybrid design: LVT/ULVT на critical paths для снижения delay и повышения frequency; RVT/HVT на non-critical paths для уменьшения общего static power без снижения frequency. Например, согласно статье о Xiangshan, опубликованной на MICRO, в первом поколении processor chip Xiangshan распределение стандартные ячейки по threshold voltage было: ULVT 1.04%, LVT 19.32%, SVT 25.19%, HVT 53.67%.
Количество tracks
Number of tracks — один из атрибутов стандартная ячейка и ещё один способ выражения её height. Здесь «height» — не проекция на -axis в трёхмерном пространстве, а размер проекции на -axis; размер по называется «width». Поэтому backend terminology в описании размеров отличается от обычной геометрической терминологии: backend width, height, thickness примерно соответствуют геометрическим «length», «width», «height».
Мы уже знаем, что PITCH слой металлизации описывает минимальный wire spacing. Чтобы упростить размещение и трассировку, height стандартные ячейки обычно делают целым кратным PITCH; это кратное и называется number of tracks. слои металлизации много, но стандартные ячейки обязательно используют M1, поэтому обычно tracks рассчитываются относительно PITCH M1.
В одной библиотеке стандартных ячеек высота cells обычно одинаковы, что дополнительно упрощает размещение. Поэтому библиотеки также можно характеризовать number of tracks. Например, если стандартные ячейки имеют высоту 6 tracks, их называют 6T standard cells.
Разберитесь с number of tracks ICsprout55
Выше уже упоминалось количество tracks ICsprout55. Найдите необходимые параметры в соответствующих файлах, самостоятельно вычислите number of tracks стандартные ячейки ICsprout55 и проверьте соответствие.
стандартные ячейки с меньшим number of tracks, например 6T или 7T, имеют меньшую area и power, но weaker drive strength, поэтому транзисторы переключаются медленнее и performance ниже. Cells с большим числом tracks, например 12T или 13T, дают higher performance, но занимают больше area и потребляют больше power. Промежуточные варианты 9T/10T дают более сбалансированный PPA.
Некоторые PDK предоставляют несколько библиотеки стандартных ячеек с разным number of tracks. Backend engineers выбирают библиотеку согласно application scenario. Но после выбора одной library нельзя смешивать cells с разным number of tracks в одной схеме. Это отличается от threshold voltage: одна library может содержать cells нескольких thresholds, которые допускается смешивать. ICsprout55 также имеет 9T библиотека стандартных ячеек, но она пока не открыта.
Физическое проектирование — от нетлиста до топологии, готовой к tapeout
Физическое проектирование — это процесс отображения стандартных ячеек и их соединений из нетлиста в трёхмерное пространство реального чипа. EDA-инструменты должны определить координаты каждой стандартной ячейки и направления проводников так, чтобы cells в разных координатах были соединены согласно топологии нетлиста и реализовывали ту же функцию. Файл, записывающий координаты стандартных ячеек и направления wires, и есть упомянутая выше GDS-топология. В конце EDA tools также должны проверить, может ли полученный чип быть корректно изготовлен и соответствуют ли его показатели ожиданиям.
После понимания process structure легко понять сущность физического проектирования: необходимо определить содержимое каждого layer — какую площадь выбрать для chip (floorplan), какие стандартные ячейки и где разместить в lower layers (floorplan, placement), как соединить cells в middle layers (routing), как организовать clock (clock tree synthesis) и power в higher layers (power planning). Ниже рассмотрим эти этапы.
-------------------- M7 <----- Power Planning
| | | | | | | | |
-------------------- M6 <----- Clock Tree Synthesis
| | | | | | | | |
-------------------- M5 <-+
| | | | | | | | | |
-------------------- M4 |
| | | | | | | | | +--- Routing
-------------------- M3 |
| | | | | | | | | |
-------------------- M2 <-+
| | | | | | | | |
-------------------- M1 <-+
| | | | | | | | | +--- Floorplan, Placement
===================== Poly-silicon <-+
+++++++++++++++++++++ dielectric
ooooooooooooooooooooo Silicon substrate
Поскольку физическое проектирование работает с реальными circuits, инженеры физического проектирования должны хорошо понимать electronics. Однако в «One Student One Chip» вам достаточно примерно понимать этапы преобразования нетлиста в tapeout-ready топологию, чтобы осознавать взаимное влияние logic design (RTL design) и физическое проектирование. Запоминать все детали backend flow не требуется.
Floorplan
Основная задача floorplan — определить размер chip и разместить cells, положение которых затем уже не будет изменяться. В этот этап входят следующие работы.
Определение размера chip
Как и area стандартные ячейки, die size означает площадь проекции chip на плоскость — площадь прямоугольника в top view. Это также площадь каждого слой металлизации и поэтому называется chip area. Thickness chip, то есть размер вдоль -axis, определяется выбранным process, например 1P7M. После выбора process thickness обычно уже не является настраиваемым параметром и на этапе физическое проектирование почти не рассматривается.
Согласно process structure, chip area в основном состоит из площади транзисторов и шин. Площадь транзисторов включает области source/drain кремниевая подложка и gate слой поликремния. Но библиотека стандартных ячеек уже сообщает area каждой cell, поэтому пользователю или EDA tool не нужно работать с transistor dimensions. Wires бывают vertical, вдоль через vias, и horizontal, внутри слой металлизации. Проекция via на плоскость — точка, horizontal wire — линия. Формально они не имеют площади, но производственные правила требуют минимальный зазор между vias и wires, иначе возникают interference и даже short circuit. Поэтому трассировка фактически также требует area.
На этапе floorplan трассировка ещё не выполнен, поэтому точную площадь wires определить нельзя. Размер chip обычно оценивают по area report после synthesis, то есть суммарной площади стандартных ячеек. При оценке задают ожидаемую долю площади cells в общей площади chip — utilization. По опыту utilization обычно составляет примерно 60%–80%. Например, если после synthesis суммарная area стандартные ячейки равна , а target utilization — 70%, ожидаемая chip area составляет .
Выбор utilization — компромисс между стоимостью и сложностью design. Высокий utilization означает мало места для трассировки, больше congestion и detours, повышенный задержка соединения, меньшую frequency и даже риск сбоя трассировки. Слишком низкий utilization оставляет много пустой area, увеличивая стоимость manufacturing, которая обычно пропорциональна площади.
Engineers выбирают utilization по свойствам chip и опыту. Небольшие chips с простой topology легче place/route, поэтому допускают больший utilization. Для сложных крупных chips необходимо оставлять больше пространства. Опытные engineers способны устанавливать более высокое utilization; новичкам полезнее начинать с низкого значения. В больших проектах обычно выполняется много rounds физическое проектирование, и параметры следующего round корректируются по предыдущему результату — congestion, оставшейся area и т. д. — пока не будет достигнут требуемый performance без лишней cost.
Определение длин сторон chip
После приблизительной площади необходимо определить размеры по и . Помимо synthesized стандартная ячейка area важным фактором является количество chip pins, а влияние pins зависит от packaging. Распространённый вариант — QFP (Quad Flat Package), где pins расположены по четырём сторонам chip, поэтому размер chip связан с их количеством.
| | |
+----+----+----+----+
| |
---+ +---
| |
---+ +---
| |
---+ +---
| |
+----+----+----+----+
| | |
Каждому chip pin соответствует I/O cell, поэтому влияние числа pins на chip size фактически определяется размерами I/O cells. С одной стороны, I/O cells на несколько порядков больше обычных стандартных ячеек. С другой стороны, некоторые I/O cells используются для power и не могут передавать data, поэтому реальное число планируемых pins больше числа communication pins. Доля и density power pins зависят от size, process, энергопотребление и других свойств chip. Process manual обычно даёт рекомендации. В целом чем больше chip и выше power, тем больше требуется power pins.
Например, если chip требует 90 communication pins и предположить, что 1/3 всех pins должны быть power pins, фактически требуется pins, поэтому можно выбрать стандартный package на 144 pins. Если pins равномерно распределены по четырём сторонам, на каждой стороне около pins. Пусть используется ICsprout55 и размер I/O cell равен , а process позволяет ставить cells вплотную. Тогда side length = , а minimum area = . То есть даже если utilization давал оценку , после учёта pins и package требуется . Если process требует gaps между I/O cells, сторона и площадь будут ещё больше.
Обязательно ли chip должен быть квадратным?
Симметрия квадрата упрощает часть последующих задач, например power planning и clock tree synthesis, где желательно, чтобы расстояния от source до target points сильно не различались. Но стороны chip не обязаны быть одинаковыми. Если помещаются все необходимые I/O cells, физическое проектирование успешно завершается, выполняются manufacturing constraints vendor и реализуем выбранный package, chip можно отправлять на tapeout.
Поэтому количество chip pins как ресурс должно быть определено ещё на specification definition stage. По числу pins также можно быстро оценить minimum area. Например, если требуется только 28 communication pins, при той же доле power pins можно использовать package 44 pins. Для ICsprout55 minimum area будет .
Ещё один фактор размера — special macro cells. Поскольку macro cells заранее спроектированы, их форма фиксирована. Для некоторых macro cells chip должен иметь определённые размеры. Например, DDR PHY модули могут размещаться на I/O boundary и иметь L-shaped geometry; тогда длинная сторона chip должна быть длиннее длинной стороны macro, иначе разместить DDR PHY невозможно.
После учёта этих условий можно предварительно определить размер chip:
+-----------------------------------------+
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
+-----------------------------------------+
Размещение I/O cells
После выбора chip size нужно разместить I/O cells по периметру. Обычно придерживаются следующих принципов:
- Data I/O cells, соответствующие функционально связанным top-level ports, размещают физически рядом. Data I/O cells логически соответствуют top-level ports и будут соединяться с внутренними стандартными ячейками wires. Такое размещение уменьшает задержка соединения. Если связанные ports поставить на противоположных сторонах или по диагонали chip, одному сигналу придётся идти значительно более длинным wire.
| | | | | |
+----+----+----+----+ +----+----+----+----+
| | | |
A---+--+ +--- A---+--+ +---
| o | | o |
B---+--+ +--- ---+ + +---
| | | | |
---+ +--- ---+ +----------------+---B
| | | |
+----+----+----+----+ +----+----+----+----+
| | | | | |
- Core power cells и I/O power cells размещают согласно требованиям density power pins process manual. Например, процесс может требовать по одной power cell на каждые две data I/O cells.
+-----------------------------------------+
| I I P p I I P p I I P p I |
| |
|p I|
| |
|P P|
| | I Data I/O Cell
|I p| p Core Power Cell
| | P I/O Power Cell
|I I|
| |
|I I|
| |
|p p|
| |
|P P|
| |
| I p P I I p P I I p P I I |
+-----------------------------------------+
Размещение macro cells
Ещё одна задача — размещение macro cells. Их area намного больше, чем обычных стандартных ячеек. Например, SRAM 64x64, если учитывать только memory cells, требует transistors, тогда как 2-input NAND стандартная ячейка — только 4. Поэтому macro cells размещают заранее; иначе после размещения стандартные ячейки будет трудно освободить большую непрерывную область.
+-----------------------------------------+
| I I P p I I P p I I P p I |
| |
|p I|
| +-------+ |
|P | MMMMM | P|
| | MMMMM | | I Data I/O Cell
|I | MMMMM | p| p Core Power Cell
| +-------+ | P I/O Power Cell
|I I| M Macro Cell
| +-------+ |
|I | MMMMM | I|
| +-------+ |
|p p|
| |
|P P|
| |
| I p P I I p P I I p P I I |
+-----------------------------------------+
Как и I/O cells, macro cells размещают с учётом функции: функционально связанные macro cells стараются расположить рядом, чтобы избежать длинных wires и снижения frequency.
Powerplan
Цель power planning — спланировать chip-level distribution power wires и обеспечить надёжное питание. Основные задачи:
- Планирование I/O power ring. Физически ring окружает I/O cells по периметру chip и подключается к power ports I/O cells; питание поступает от I/O power cells. Для передачи сигналов за пределы chip I/O cells требуют высокой drive strength, поэтому их supply отличается от обычных стандартных ячеек и планируется отдельно.
- Планирование core power ring. Физически он похож на I/O power ring, но находится внутри I/O cells и окружает core chip, формируя основной trunk power network. Он питается от core power cells и обеспечивает равномерный supply для стандартных ячеек внутри chip.
- Планирование power stripes внутри chip. Они образуют пересекающуюся сетку и равномерно доставляют power к macro cells и стандартным ячейкам. На этапе размещения эти stripes будут соединены с source и drain gate circuits внутри стандартных ячеек.
Для краткости рисунок показывает только одну power stripe; в реальном design их несколько и они пересекаются.
+-----------------------------------------+
| I I P p I I P p I I P p I |
| ####################################### |
|p#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#I|
| #% +-------+ %# |
|P#% | MMMMM | %#P|
| #% | MMMMM | %# | I Data I/O Cell
|I#% | MMMMM | %#p| p Core Power Cell
| #% +-------+ %# | P I/O Power Cell
|I#% %#I| M Macro Cell
| #% +-------+ %# | # I/O Power Ring
|I#% | MMMMM | %#I| % Core Power Ring
| #% +-------+ %# | = Power Stripe
|p#%===================================%#p|
| #% %# |
|P#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#P|
| ####################################### |
| I p P I I p P I I p P I I |
+-----------------------------------------+
Во время работы готового chip питание входит через power supply pins, распространяется по power rings вокруг chip, затем через power stripes доставляется к стандартным ячейкам в разных областях и прикладывает необходимые voltages к source/drain транзисторов, позволяя им работать согласно электрические характеристики.
Некоторые сложные chips также поддерживают power-management functions, например multiple voltage domains и power gating. Планирование этих функций также выполняется на этом этапе.
Размещение
Цель размещения — разместить стандартные ячейки внутри chip и определить физические координаты каждой cell. Размещение не может быть произвольным и должно соблюдать ряд правил:
- Стандартные ячейки не должны перекрываться. Хотя chip является трёхмерным объектом, согласно process structure cells реализуются транзисторы в нижних слоях и соединениями lower слои металлизации. Транзисторы разных cells должны занимать разные позиции; их координаты по фактически одинаковы. Поэтому в top view стандартные ячейки не могут overlap.
- размещение стандартных ячеек должно удовлетворять условиям alignment. Такие атрибуты, как SITE и number of tracks, фактически ограничивают допустимые позиции cells. Alignment по SITE позволяет легко соединять power stripes, созданные на этапе power planning, с стандартными ячейками. Number of tracks помогает трассировке соблюдать минимальный зазор metal wires, то есть
PITCH. Если размещение не соответствует alignment constraints, EDA tool придётся с большим трудом строить физически допустимый design.
--- +------+ +------------+----------+ +---+
^ |======|==|============|==========|====|===| <- VSS power stripe
| | | | | | | |
height --+ | | | | | | |
| | | | | | | |
v |======|==|============|==========|====|===| <- VDD power stripe
--- +------+ +------------+----------+ +---+
OR2 AOI221 AND4 NAND2
+-----------------------------------------+
| I I P p I I P p I I P p I |
| ####################################### |
|p#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#I|
| #% +-------+ @@ @@ @ @ @%# |
|P#% | MMMMM | @ @@@ @@ @@%#P|
| #% | MMMMM | @ @ @%# | I Data I/O Cell
|I#% | MMMMM | @ %#p| p Core Power Cell
| #% +-------+ @ @@ @ %# | P I/O Power Cell
|I#% %#I| M Macro Cell
| #% @ @ @ @@ @ +-------+ %# | # I/O Power Ring
|I#% @ @ @ @ @ @ | MMMMM | %#I| % Core Power Ring
| #% @ @ @ @ @ @ +-------+@%# | = Power Stripe
|p#%===================================%#p| @ Standard Cell
| #% @ @ @ @ @ @ @%# |
|P#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#P|
| ####################################### |
| I p P I I p P I I p P I I |
+-----------------------------------------+
Помимо соблюдения manufacturing rules EDA tools также пытаются улучшить качество схемы. Некоторые методы:
- Размещать логически связанные стандартные ячейки ближе друг к другу. Подобно размещение data I/O cells, большое физическое расстояние между связанными cells создаёт большой задержка соединения при трассировке и снижает chip frequency.
- Отражать стандартные ячейки. Как упоминалось выше,
SYMMETRYв LEF показывает допустимое отражение cell относительно или для улучшения размещения, например уменьшения задержка соединения до порта. Если портpнаходится слева у cellA, но должен соединяться с cellB, находящейся справа,Aможно отразить относительно -axis, перенесяpна правую сторону и сократив расстояние доB. - Уменьшать congestion. Если стандартные ячейки слишком плотно сконцентрированы в некоторой области, последующая трассировка становится сложнее, wires вынуждены делать detours, растёт задержка соединения и может возникнуть сбой трассировки. EDA tool может распределить cells более равномерно, оставляя пространство для трассировки.
Размер filler cells
библиотеки стандартных ячеек обычно предоставляют filler cells разных размеров для заполнения пустых позиций. Для ICsprout55 найдите размер самой маленькой filler cell. Как он связан с SITE стандартные ячейки и почему?
Clock Tree Synthesis (CTS)
Цель clock tree synthesis — построить clock network, доставляющую clock signal к clock terminals всех sequential cells. Clock network обычно имеет один или несколько sources, например clock pins или outputs PLL. Если считать sources корневыми nodes, а sequential cells — leaf nodes, сеть похожа на одно или несколько деревьев, растущих от roots к leaves, поэтому называется clock tree.
На этапе RTL design clock считается идеальным. В реальном физическом проектировании это не так, и необходимо учитывать физические свойства clock signal, которые уже кратко обсуждались в разделе clock-specific cells. Построенный clock tree должен обеспечивать:
- Low latency. Clock propagation имеет delay. Часть причин EDA tools могут оптимизировать, например длину wires: расстояние от source до clock ports триггеры должно быть как можно меньше. Другие причины, например delay самого clock source, оптимизировать невозможно и их нужно учитывать в модели.
- Low skew. В RTL идеальный clock приходит ко всем триггеры одновременно. В реальности cells расположены в разных местах, поэтому один и тот же clock приходит в разные триггеры в немного разные моменты — это clock skew. Для уменьшения skew EDA tool тщательно планирует clock wires, чтобы задержка соединения от source до каждого триггер был максимально одинаковым.
- Low jitter. Jitter — естественное свойство электрических сигналов, зависящее от process parameters, и EDA tool не может полностью устранить его. Поэтому jitter необходимо учитывать при timing model, иначе оценка delay будет слишком оптимистичной. Реальный jitter может нарушить такие timing conditions и привести к некорректной работе chip.
- High drive. Для высокой drive strength clock обычно в clock tree вставляются специальные clock buffers.
Эти свойства частично конфликтуют. Некоторые wire topologies дают low skew, но высокий задержка соединения. Clock buffers увеличивают drive strength, но одновременно меняют delay путей и могут ухудшить skew. Поэтому EDA tools должны комплексно строить clock tree, удовлетворяющий требованиям в целом.
Для простоты рисунок показывает только часть clock tree; реально он должен подключаться ко всем sequential cells.
+-----------------------------------------+
| I I P p I I P p I I P p I |
| ####################################### |
|p#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#I|
| #% +-------+ @@o @@ @ @ @%# |
|P#% | MMMMM | @o @@@ @@ o@@%#P|
| #% | MMMMM | @ o @ o o @%# | I Data I/O Cell
|I#% | MMMMM | o o @ o %#p| p Core Power Cell
| #% +-------+ @o @@ o @ o %# | P I/O Power Cell
|I#% oooooooooooooooooooooooooooooooooo%#I|<-- clk M Macro Cell
| #% @ @ @ @@o @ o +-------+ %# | # I/O Power Ring
|I#% @ @ @ @ o @ @o | MMMMM | %#I| % Core Power Ring
| #% @ @ @ @ o @ @ +-------+@%# | = Power Stripe
|p#%===================================%#p| @ Standard Cell
| #% @ @ @ o @ @ @ oo@%# | o Clock Tree
|P#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#P|
| ####################################### |
| I p P I I p P I I p P I I |
+-----------------------------------------+
Трассировка
Цель трассировки — соединить стандартные ячейки после размещения проводниками согласно топологии нетлиста. В large-scale и very-large-scale integrated circuits количество стандартных ячеек и соединений очень велико; если хотя бы один wire невозможно провести, трассировка считается failed. Чтобы повысить вероятность успеха, трассировка обычно делят на глобальная трассировка и детальная трассировка.
Если провести аналогию с дорожным планированием города, глобальная трассировка похож на проектирование основных дорог: необходимо обеспечить connectivity разных районов, не делать дороги чрезмерно извилистыми и избегать congestion. Детальная трассировка затем разбивает эти основные маршруты на реальные lanes, по которым traffic может двигаться между соединёнными пунктами.
В chip трассировка глобальная трассировка планирует coarse-grained wire schemes и распределяет ресурсы трассировки: number of tracks, направления wires, vias между слои металлизации и т. д. трассировка tool объединяет несколько tracks в grid и пытается соединить стандартные ячейки через grid, формируя «grid paths», подобные магистральным дорогам. При сохранении connectivity он ищет относительно короткую и не слишком congested схему. Детальная трассировка на основе глобальной трассировки выбирает конкретные tracks внутри grid paths и физически соединяет стандартные ячейки.
+-----------------------------------------+
| I I P p I I P p I I P p I |
| ####################################### |
|p#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#I|
| #% +-------+..@@o @@..@... .....@.@%# |
|P#% | MMMMM | .@o.....@@@..... @@ o@@%#P|
| #% | MMMMM |..@ o @ o . . o @%# | I Data I/O Cell
|I#% | MMMMM | . o o @ . o .%#p| p Core Power Cell
| #% +-------+ .@o @@...o ....@ o .%# | P I/O Power Cell
|I#% oooooooooooooooooooooooooooooooooo%#I|<-- clk M Macro Cell
| #% @ ..@...@ ..@@o @... o +-------+.%# | # I/O Power Ring
|I#% @....@ .@.. @ o @. .@o .| MMMMM |.%#I| % Core Power Ring
| #% @...@...@ .@ o @ ..@..+-------+@%# | = Power Stripe
|p#%===================================%#p| @ Standard Cell
| #% @...@ .@ o @... @.....@.. oo@%# | o Clock Tree
|P#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#P| . Wire
| ####################################### |
| I p P I I p P I I p P I I |
+-----------------------------------------+
На этом все основные работы физического проектирования завершены: содержимое каждого слоя чипа определено. Теперь можно сформировать GDS-топологию, описывающую все стандартные ячейки и wires в каждом слое.
Sign-off analysis
Цель sign-off analysis — убедиться, что топология после физического проектирования действительно производим. С одной стороны, топология должен удовлетворять front-end design metrics, включая PPA; с другой — производственные требования wafer fab. Строго говоря, sign-off analysis не относится непосредственно к физическому проектированию, но без него топология нельзя считать tapeout-ready, иначе произведённый chip может не работать.
Sign-off analysis включает, среди прочего:
- статический временной анализ. После физического проектирования известны точные позиции стандартных ячеек в трёхмерном пространстве, направления, длины, изгибы всех wires. Поэтому можно точно моделировать задержка логики и задержка соединения каждого path, включая задержка распространения, jitter и skew clock signal. Это даёт более точный timing result и позволяет проверить достижение целевая частота.
- анализ энергопотребления. Аналогично после физического проектирования можно получить более точную оценку power и проверить целевое ограничение по мощности.
- анализ целостности сигнала. Анализ crosstalk между соседними wires и проверка того, что signals передаются без искажений в условиях noise и crosstalk.
- Physical Verification (PV). Проверка физической структуры chip. При нарушениях размещения/трассировки необходимо исправить и проверить снова. PV включает:
Design Rule Check (DRC). Проверка соответствия GDS-топологии правилам проектирования фабрики, включая poly-silicon и слои металлизации: минимальная ширина проводника, минимальный зазор и т. д. Некоторые PDK записывают rules в текстовых файлах, которые EDA tools последовательно проверяют. Например:
# The minimum width of the metal1 layer is 65nm metal1.width(65.nm, euclidian).output("METAL1.1", "METAL1.1 : Minimum width of metal1 : 65nm") # The minimum spacing of the via6 layer is 160nm via6.space(160.nm, euclidian).output("VIA6.2", "VIA6.2 : Minimum spacing of via6 : 160nm")Electrical Rule Check (ERC). Проверка электрических проблем, например dangling wires и short circuits.
Layout Versus Schematic (LVS). Проверка соответствия GDS-топологии, то есть physical circuit, и нетлиста, то есть logical circuit.
От tapeout-ready топология до работающего chip
После получения tapeout-ready топология необходимы ещё следующие шаги:
- Backend design team передаёт GDS-топологию фабрике, которая изготавливает masks по топологии.
- Wafer fab использует masks для массового производства wafers. На одном wafer находится много dies; wafer разрезается на отдельные dies.
- Dies передаются packaging house, которая выполняет packaging согласно выбранной package scheme и получает готовые chips.
- Finished chips передаются команде development board, которая проектирует board и припаивает chips.
- Development board передаётся пользователю, который развёртывает software на chip и запускает его.
SA
