DocsTech
/
YOSYS
/

~ cd 2.2. синтезатор

На этой странице мы рассмотрим готовый скрипт синтеза ПЛИС iCE40 — synth_ice40. Мы рассмотрим простую конструкцию на каждом шаге, изучим вызываемые команды и то, что они делают с конструкцией. Хотя synth_ice40 специфичен для платформы iCE40, большинство операций, которые мы будем обсуждать, являются общими для большинства скриптов синтеза ПЛИС. Таким образом, этот документ обеспечит хорошее базовое понимание того, как выполняется синтез в Yosys, независимо от используемой архитектуры.

2.2.1. Демонстрационная конструкция

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

Листинг 2.1: fifo.v
...
Копировать
// address generator/counter
module addr_gen
#( parameter MAX_DATA=256,
    localparam AWIDTH = $clog2(MAX_DATA)
) ( input en, clk, rst,
    output reg [AWIDTH-1:0] addr
);
    initial addr <= 0;

    // async reset
    // increment address when enabled
    always @(posedge clk or posedge rst)
        if (rst)
            addr <= 0;
            else if (en) begin
                if (addr == MAX_DATA-1)
                    addr <= 0;
                else
                    addr <= addr + 1;
            end
endmodule //addr_gen

// Define our top level fifo entity
module fifo
#( parameter MAX_DATA=256,
    localparam AWIDTH = $clog2(MAX_DATA)
) ( input wen, ren, clk, rst,
    input [7:0] wdata,
    output reg [7:0] rdata,
    output reg [AWIDTH:0] count
);
    // fifo storage
    // sync read before write
    wire [AWIDTH-1:0] waddr, raddr;
    reg [7:0] data [MAX_DATA-1:0];

    always @(posedge clk) begin
        if (wen)
            data[waddr] <= wdata;
        rdata <= data[raddr];
    end // storage

    // addr_gen for both write and read addresses
    addr_gen #(.MAX_DATA(MAX_DATA))
    fifo_writer (
        .en (wen),
        .clk (clk),
        .rst (rst),
        .addr (waddr)
    );

    addr_gen #(.MAX_DATA(MAX_DATA))
    fifo_reader (
        .en (ren),
        .clk (clk),
        .rst (rst),
        .addr (raddr)
    );

    // status signals
    initial count <= 0;

    always @(posedge clk or posedge rst) begin
        if (rst)
            count <= 0;
        else if (wen && !ren)
            count <= count + 1;
        else if (ren && !wen)
            count <= count - 1;
    end

endmodule

2.2.2. Загрузка конструкции

Давайте загрузим проект в Yosys. Из командной строки мы можем вызвать yosys fifo.v. Это откроет интерактивную сессию оболочки Yosys и сразу же разберет код из fifo.v и преобразует его в абстрактное синтаксическое дерево (AST). Вы должны увидеть что-то вроде следующего:
...
Копировать
$ yosys fifo.v

-- Parsing `fifo.v' using frontend ` -vlog2k' --
1. Executing Verilog-2005 frontend: fifo.v
Parsing Verilog input from `fifo.v' to AST representation.
Storing AST representation for module `$abstract\addr_gen'.
Storing AST representation for module `$abstract\fifo'.
Successfully finished Verilog frontend
Перевод:
...
Копировать
yosys fifo.v

-- Парсинг `fifo.v' с помощью фронтэнда ` -vlog2k' --
1. Осуществление фронтэнда Verilog-2005: fifo.v
Парсинг входных данных Verilog из файла `fifo.v' в AST-представление.
Кэширование AST-представления для модуля `$abstract\addr_gen'.
Кэширование AST-представления для модуля `$abstract\fifo'.
Успешно завершено создание фронтенда Verilog.

2.2.3. Элаборация

Теперь, когда мы находимся в интерактивной оболочке, мы можем вызывать команды Yosys напрямую. Наша общая цель — вызвать synth_ice40 -top fifo, но пока мы можем выполнить каждую из команд по отдельности, чтобы лучше понять, как каждая часть вносит свой вклад в поток. Мы также начнем только с одного модуля — addr_gen.

В нижней части вывода справки для synth_ice40 находится полный список команд, вызываемых этим скриптом.

Начнем с раздела, озаглавленного » begin»:

Листинг 2.2: раздел begin
...
Копировать
read_verilog -D ICE40_HX -lib -specify +/ice40/cells_sim.v
hierarchy -check -top <top>
proc

read_verilog -D ICE40_HX -lib -specify +/ice40/cells_sim.v загружает модели ячеек iCE40, что позволяет нам включить в наш проект IP-блоки, специфичные для платформы. PLL являются распространенным примером, когда нам может понадобиться напрямую ссылаться на SB_PLL40_CORE, а не полагаться на последующие передачи отображения.

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

Примечание: +/ — это динамическая ссылка на каталог общего доступа Yosys. По умолчанию это /usr/local/share/yosys. Если используется локально собранная версия Yosys из исходного каталога, то это будет папка share в том же каталоге.

2.2.3.1. Модуль addr_gen

Поскольку мы только начинаем, давайте вместо этого начнем с hierarchy -top addr_gen. Эта команда объявляет, что модулем верхнего уровня является addr_gen, а все остальное можно отбросить.

Листинг 2.3: исходный текст модуля addr_gen
...
Копировать
module addr_gen
#( parameter MAX_DATA=256,
    localparam AWIDTH = $clog2(MAX_DATA)
) ( input en, clk, rst,
    output reg [AWIDTH-1:0] addr
);
    initial addr <= 0;

    // async reset
    // increment address when enabled
    always @(posedge clk or posedge rst)
        if (rst)
            addr <= 0;
            else if (en) begin
                if (addr == MAX_DATA-1)
                    addr <= 0;
                else
                    addr <= addr + 1;
            end
endmodule //addr_gen

Примечание: hierarchy всегда должна быть первой командой после чтения конструкции. Указав верхний модуль, hierarchy также установит для него атрибут (* top *). Он используется другими командами, которым необходимо знать, какой модуль является верхним.

Листинг 2.4: вывод hierarchy -top addr_gen
...
Копировать
yosys> hierarchy -top addr_gen

2. Executing HIERARCHY pass (managing design hierarchy).

3. Executing AST frontend in derive mode using pre-parsed AST for module `\addr_gen'.
Generating RTLIL representation for module `\addr_gen'.

3.1. Analyzing design hierarchy..
Top module: \addr_gen

3.2. Analyzing design hierarchy..
Top module: \addr_gen
Removing unused module `$abstract\fifo'.
Removing unused module `$abstract\addr_gen'.
Removed 2 unused modules.
Перевод:
...
Копировать
yosys> hierarchy -top addr_gen

2. Выполнение передачи HIERARCHY (управление иерархией конструкции).

3. Формирование AST-фронтенда в режиме derive с использованием предварительно разобранного AST для модуля `\addr_gen'. Генерация RTLIL-представления для модуля `\addr_gen'.

3.1. Анализ иерархии конструкции...
Модуль верхнего уровня: \addr_gen

3.2. Анализ иерархии конструкции...
Верхний модуль: \addr_gen
Удаление неиспользуемого модуля `$abstract\fifo'.
Удаление неиспользуемого модуля `$abstract\addr_gen'.
Удалены 2 неиспользуемых модуля.

Теперь наша схема addr_gen выглядит следующим образом:

модуль addr_gen после hierarchy
Рис. 2.1: модуль addr_gen после hierarchy

Такие простые операции, как addr + 1 и addr == MAX_DATA-1, можно извлечь из нашего always блока в исходном тексте модуля addr_gen. Это дает нам выделенные ячейки $add и $eq, которые мы видим. Но управляющая логика (например, if … else) и элементы памяти (например, addr <= 0) не так просты. Они помещаются в «процессы», показанные на схеме как PROC. Обратите внимание, как вторая строка ссылается на номера строк начала/конца соответствующего блока always. В случае начального блока вместо этого мы видим PROC ссылается на строку 0.

Чтобы справиться с ними, давайте представим следующую команду: proc — преобразование процессов в нетлисты. proc — это макрокоманда, подобная synth_ice40. Вместо того чтобы непосредственно изменять конструкцию, она вызывает серию других команд. В случае proc эти подкоманды работают над преобразованием поведенческой логики процессов в мультиплексоры и регистры. Давайте посмотрим, что произойдет, когда мы ее запустим. Пока что мы будем вызывать proc –noopt, чтобы предотвратить некоторые автоматические оптимизации, которые обычно происходят.

модуль addr_gen после выполнения proc -noopt
Рис. 2.2: модуль addr_gen после выполнения proc -noopt

Теперь есть несколько новых ячеек, которые были выделены из нашего always. Операторы if теперь моделируются ячейками $mux, а регистр использует ячейку $adff. Если мы посмотрим на вывод терминала, то увидим, как вызываются все различные команды proc_*. Мы рассмотрим каждую из них более подробно в разделе

2.2.3.1.1. Преобразование процедурных блоков.

Обратите внимание, что в левом верхнем углу модуля addr_gen после proc -noopt у нас есть плавающий провод, образовавшийся в результате первоначального присвоения 0 проводу addr. Однако, это начальное присвоение не поддается синтезу, поэтому его нужно будет очистить, прежде чем мы сможем сгенерировать для физического оборудования. Мы можем сделать это сейчас, вызвав clean. Мы также собираемся вызвать opt_expr, которая обычно вызывается в конце proc. Мы можем вызвать обе команды одновременно, разделив их точкой с запятой и пробелом: opt_expr; clean.

модуль addr_gen после opt_expr; clean
Рис. 2.3: модуль addr_gen после opt_expr; clean

Вы также можете заметить, что выделенная ячейка $eq, содержащая 255, изменилась на 8’11111111. Значения констант представлены в формате <ширина_бита>'<биты>, причем для 32-битных значений вместо этого используется десятичное число.

Это указывает на то, что входная константа была уменьшена с 32-битной до 8-битной ширины. Это побочный эффект выполнения opt_expr, который выполняет сворачивание констант и простую перезапись выражений.

Примечание: clean — удаляет неиспользуемые ячейки и провода, также может быть вызвана с двумя точками с запятой после любой команды, например, мы могли бы вызвать opt_expr;; вместо opt_expr; clean. Вы можете заметить, что некоторые скрипты будут оканчиваться строку символом ;;. Перед проверкой промежуточных модулей полезно провести очистку, чтобы удалить плавающие части цепи, которые остались, и в некоторых случаях это может уменьшить объем обработки, требуемый последующими командами.

2.2.3.1.2. Полный пример

Теперь давайте вернемся и проверим нашу полную конструкцию с помощью команды hierarchy -check -top fifo. Передавая опцию -check, мы также говорим команде hierarchy, что если конструкция включает в себя любые не “black box”(не примитивы) модулей, не имеющих реализации, он должен возвращать ошибку.

Обратите внимание, что если мы попытаемся выполнить эту команду сейчас, то получим ошибку. Это потому, что мы уже удалили все модули, кроме addr_gen. Мы могли бы перезапустить наш сеанс оболочки, но вместо этого давайте воспользуемся двумя новыми командами:

Листинг 2.5: перезагрузка файла fifo.v и выполнение команды hierarchy -check -top fifo
...
Копировать
yosys> design -reset

yosys> read_verilog fifo.v

11. Executing Verilog-2005 frontend: fifo.v
Parsing Verilog input from `fifo.v' to AST representation.
Generating RTLIL representation for module `\addr_gen'.
Generating RTLIL representation for module `\fifo'.
Successfully finished Verilog frontend.

yosys> hierarchy -check -top fifo

12. Executing HIERARCHY pass (managing design hierarchy).

12.1. Analyzing design hierarchy..
Top module: \fifo
Used module: \addr_gen
Parameter \MAX_DATA = 256

12.2. Executing AST frontend in derive mode using pre-parsed AST for module `\addr_gen'.
Parameter \MAX_DATA = 256
Generating RTLIL representation for module `$paramod\addr_gen\MAX_DATA=s32'00000000000000000000000100000000'.
Parameter \MAX_DATA = 256
Found cached RTLIL representation for module `$paramod\addr_gen\MAX_DATA=s32'00000000000000000000000100000000'.

12.3. Analyzing design hierarchy..
Top module: \fifo
Used module: $paramod\addr_gen\MAX_DATA=s32'00000000000000000000000100000000

12.4. Analyzing design hierarchy..
Top module: \fifo
Used module: $paramod\addr_gen\MAX_DATA=s32'00000000000000000000000100000000
Removing unused module `\addr_gen'.
Removed 1 unused modules.

Перевод:

...
Копировать
yosys> design -reset

yosys> read_verilog fifo.v

11. Исполнение фронтенда Verilog-2005: fifo.v
Обработка входных данных Verilog из файла `fifo.v' в AST-представление.
Генерирование RTLIL-представления для модуля `\addr_gen'.
Генерирование RTLIL-представления для модуля `\fifo'.
Успешно завершено создание фронтенда Verilog.

yosys> hierarchy -check -top fifo

12. Выполнение передачи HIERARCHY (управление иерархией конструкции).

12.1. Анализ иерархии конструкции...
Модуль верхнего уровня: \fifo
Используемый модуль: \addr_gen
Параметр \MAX_DATA = 256

12.2. Распаковка AST-фронтенда в режиме derive с использованием предварительно обработанного AST для модуля `\addr_gen'.
Параметр \MAX_DATA = 256
Генерация RTLIL-представления для модуля `$paramod\addr_gen\MAX_DATA=s32'00000000000000000000000100000000'.
Параметр \MAX_DATA = 256
Найдено кэшированное RTLIL-представление для модуля `$paramod\addr_gen\MAX_DATA=s32'00000000000000000000000100000000'.

12.3. Анализ иерархии конструкции...
Модуль верхнего уровня: \fifo
Используемый модуль: $paramod\addr_gen\MAX_DATA=s32'00000000000000000000000100000000

12.4. Анализ иерархии конструкции...
Модуль верхнего уровня: \fifo
Используемый модуль: $paramod\addr_gen\MAX_DATA=s32'00000000000000000000000100000000
Удаление неиспользуемого модуля `\addr_gen'.
Удален 1 неиспользуемый модуль.
Заметили, что на этот раз мы не увидели ни одного из этих модулей $abstract? Это потому, что когда мы запустили yosys fifo.v, первой командой, которую вызвал Yosys, была read_verilog -defer fifo.v. Параметр –defer сообщает read_verilog только чтение абстрактного синтаксического дерева и откладывает фактическую компиляцию на более позднюю команду hierarchy. Это полезно в тех случаях, когда параметры модулей по умолчанию дают некорректный код, не поддающийся синтезу. Именно поэтому Yosys откладывает компиляцию автоматически и это одна из причин, почему иерархия всегда должна быть первой командой после загрузки конструкции. Если мы знаем, что наш конструкция не столкнется с этой проблемой, мы можем пропустить -defer.

Примечание: Число перед выводом команды увеличивается с каждым ее выполнением. Не волнуйтесь, если ваши числа не совпадают с нашими! Вывод, который вы видите, происходит из того же скрипта, который был использован для генерации изображений в этом документе, включенного в исходный текст под именем fifo.ys. В нем выполняются дополнительные команды, которые вы не видите, но не бойтесь попробовать их сами или поиграть с разными командами. Вы всегда можете начать с чистого листа, вызвав exit или нажав ctrl+d (т.е. EOF) и снова запустив интерактивный терминал Yosys. ctrl+c (т.е. SIGINT) также завершит терминальную сессию, но вернет ошибку вместо того, чтобы правильно завершить работу.

Мы также можем запустить proc сейчас, чтобы завершить полную секцию begin. Поскольку схема конструкции довольно большая, мы покажем только путь данных для вывода rdata. Если вы хотите увидеть всю схему целиком, вы можете сделать это с помощью команды show — генерировать схемы с помощью graphviz. Обратите внимание, что команда show работает только с одним модулем, поэтому вам может понадобиться вызвать ее с помощью show fifo.

Выходные данные rdata после выполнения процедуры
Рис. 2.4: Выходные данные rdata после выполнения процедуры

Выделенный блок fifo_reader содержит экземпляр модуля addr_gen после proc -noopt, который мы рассматривали ранее. Обратите внимание, что тип показан как $paramod\\addr_gen\\MAX_DATA=s32’….. Это «параметрический модуль»: экземпляр модуля addr_gen с параметром MAX_DATA, установленным на заданное значение.

Другой выделенный блок — это ячейка $memrd. На данном этапе синтеза мы еще не знаем, какой тип памяти будет реализован, но мы знаем, что rdata <= data[raddr]; может быть реализовано как чтение из памяти. Обратите внимание, что ячейка $memrd здесь асинхронная, с неопределенными тактовым и разрешающим сигналами, которые показаны как входы 1’x.

2.2.4 Сглаживание

На этом этапе синтеза есть еще несколько команд, которые мы могли бы выполнить. В synth_ice40 мы получаем следующие:

Листинг 2.6: Секция сглаживания
...
Копировать
flatten
tribuf -logic
deminout

Во-первых, это flatten. Подобное сглаживание конструкций может позволить оптимизировать работу модулей, которая в противном случае была бы упущена. Давайте запустим flatten;; на нашей конструкции.

Листинг 2.7: вывод flatten;;
...
Копировать
yosys> flatten

15. Executing FLATTEN pass (flatten design).
Deleting now unused module $paramod\addr_gen\MAX_DATA=s32'00000000000000000000000100000000.
<suppressed ~2 debug messages>

yosys> clean

Removed 3 unused cells and 28 unused wires
...
Копировать
yosys> flatten

15. Выполнение передачи FLATTEN (сглаживание конструкции).
Удаление неиспользуемого модуля $paramod\addr_gen\MAX_DATA=s32'00000000000000000000000100000000.
<подавлено ~2 отладочных сообщения>

yosys> clean

Удалите 3 неиспользуемых ячейки и 28 неиспользуемых проводов.
вывод rdata после flatten;;
Рис. 2.5: вывод rdata после flatten;;

Кусочки немного сдвинулись, но мы видим, что модуль addr_gen после proc -noopt из предыдущей версии заменил блок fifo_reader в выводе rdata после proc. Мы также видим, что вывод addr был переименован в fifo_reader.addr и объединен с проводом raddr, идущим в ячейку $memrd. Это объединение проводов произошло во время вызова clean, что мы можем видеть в выводе flatten;;.

Примечание: Обычно flatten и clean объединяются в один вывод yosys> flatten;;, но здесь они появляются отдельно как побочный эффект использования echo для генерации вывода в стиле терминала.

В зависимости от целевой архитектуры, на этом этапе синтеза могут также использоваться такие команды, как tribuf с параметрами -logic и deminout . Они удаляют конструкции tristate и inout соответственно, заменяя их логикой, пригодной для отображения на ПЛИС. Поскольку в нашем примере таких конструкций нет, выполнение этих команд не изменит наш проект.

2.2.5. Сoarse-grainпредставление

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

Здесь же мы преобразуем наши FSM и блоки, такие как DSP или память. Такие элементы должны быть выведены на основе паттернов в конструкции, и для каждого из них существуют специальные проходы. На обнаружение этих паттернов также могут повлиять оптимизация и другие преобразования, выполненные ранее.

Примечание: Хотя в потоке iCE40 секция flatten и секция put proc находятся в секции begin, некоторые скрипты синтеза вместо этого включают их в эту секцию.

2.2.5.1. Часть 1

В потоке iCE40 мы начинаем со следующих команд:

Листинг 2.8: coarse секция (часть 1)
...
Копировать
opt_expr
opt_clean
check
opt -nodffe -nosdff
fsm
opt

Мы уже встречались с opt_expr , а opt_clean — это то же самое, что и clean, но с более подробным выводом. Передача check выявляет несколько очевидных проблем, которые впоследствии приведут к ошибкам. Вызов его здесь позволяет нам быстрее потерпеть неудачу, а не тратить время на то, что заведомо невозможно.

Далее следует opt -nodffe -nosdff, выполняющая набор простых оптимизаций конструкции. Эта команда также обеспечивает включение только определенного подмножества типов FF для подготовки к следующей команде: fsm извлечение и оптимизация конечных автоматов.

До сих пор путь данных для rdata оставался неизменным, поскольку rdata выводится после flatten;;. Однако следующий вызов opt приводит к изменениям. В частности, вызов opt_dff без параметра -nodffe -nosdff способен сложить одну из ячеек $mux в $adff, чтобы сформировать ячейку $adffe; показано ниже:

Листинг 2.9: вывод opt_dff
...
Копировать
yosys> opt_dff

17. Executing OPT_DFF pass (perform DFF optimizations).
Adding EN signal on $procdff$59 ($adff) from module fifo (D = $0\count[8:0], Q = \count).
Adding EN signal on $flatten\fifo_writer.$procdff$66 ($adff) from module fifo (D = $flatten\fifo_writer.$procmux$53_Y, Q = \fifo_writer.addr).
Adding EN signal on $flatten\fifo_reader.$procdff$66 ($adff) from module fifo (D = $flatten\fifo_reader.$procmux$53_Y, Q = \fifo_reader.addr).

Перевод:

...
Копировать
yosys> opt_dff

17. Выполнение OPT_DFF pass (выполнение DFF-оптимизации).
Добавление сигнала EN на $procdff$59 ($adff) из модуля fifo (D = $0\count[8:0], Q = \count).
Добавление сигнала EN на $flatten\fifo_writer.$procdff$66 ($adff) из модуля fifo (D = $flatten\fifo_writer.$procmux$53_Y, Q = \fifo_writer.addr).
Добавление сигнала EN на $flatten\fifo_reader.$procdff$66 ($adff) из модуля fifo (D = $flatten\fifo_reader.$procmux$53_Y, Q = \fifo_reader.addr).
выход rdata после opt_dff
Рис. 2.6: выход rdata после opt_dff

2.2.5.2. Часть 2

Следующая группа команд выполняет ряд оптимизаций:

Листинг 2.10: coarse секция (часть 2)
...
Копировать
peepopt
opt_clean
share
techmap -map +/cmp2lut.v -D LUT_WIDTH=4
opt_expr
opt_clean
memory_dff [-no-rw-check]

Во-первых, это wreduce — уменьшение размера слова операций, если это возможно. Если мы запустим эту функцию, то получим следующее:

Листинг 2.11: результат работы wreduce
...
Копировать
yosys> wreduce

19. Executing WREDUCE pass (reducing word size of cells).
Removed top 31 bits (of 32) from port B of cell fifo.$add$fifo.v:66$29 ($add).
Removed top 23 bits (of 32) from port Y of cell fifo.$add$fifo.v:66$29 ($add).
Removed top 31 bits (of 32) from port B of cell fifo.$sub$fifo.v:68$32 ($sub).
Removed top 23 bits (of 32) from port Y of cell fifo.$sub$fifo.v:68$32 ($sub).
Removed top 1 bits (of 2) from port B of cell fifo.$auto$opt_dff.cc:195:make_patterns_logic$72 ($ne).
Removed cell fifo.$flatten\fifo_writer.$procmux$55 ($mux).
Removed top 31 bits (of 32) from port B of cell fifo.$flatten\fifo_writer.$add$fifo.v:19$36 ($add).
Removed top 24 bits (of 32) from port Y of cell fifo.$flatten\fifo_writer.$add$fifo.v:19$36 ($add).
Removed cell fifo.$flatten\fifo_reader.$procmux$55 ($mux).
Removed top 31 bits (of 32) from port B of cell fifo.$flatten\fifo_reader.$add$fifo.v:19$36 ($add).
Removed top 24 bits (of 32) from port Y of cell fifo.$flatten\fifo_reader.$add$fifo.v:19$36 ($add).
Removed top 23 bits (of 32) from wire fifo.$add$fifo.v:66$29_Y.
Removed top 24 bits (of 32) from wire fifo.$flatten\fifo_reader.$add$fifo.v:19$36_Y.
Removed top 24 bits (of 32) from wire fifo.$flatten\fifo_writer.$add$fifo.v:19$36_Y.

yosys> show -notitle -format dot -prefix rdata_wreduce o:rdata %ci*

20. Generating Graphviz representation of design.
Writing dot description to `rdata_wreduce.dot'.
Dumping selected parts of module fifo to page 1.

yosys> opt_clean

21. Executing OPT_CLEAN pass (remove unused cells and wires).
Finding unused cells or wires in module \fifo..
Removed 0 unused cells and 5 unused wires.
<suppressed ~1 debug messages>

yosys> memory_dff

22. Executing MEMORY_DFF pass (merging $dff cells to $memrd).
Checking read port `\data'[0] in module `\fifo': merging output FF to cell.
Write port 0: non-transparent.
Перевод:
...
Копировать
yosys> wreduce

19. Выполнение прохода WREDUCE (уменьшение размера слова в ячейках).
Удалили 31 верхний бит (из 32) из порта B ячейки fifo.$add$fifo.v:66$29 ($add).
Удалены верхние 23 бита (из 32) из порта Y ячейки fifo.$add$fifo.v:66$29 ($add).
Удалены верхние 31 бит (из 32) из порта B ячейки fifo.$sub$fifo.v:68$32 ($sub).
Удалены верхние 23 бита (из 32) из порта Y ячейки fifo.$sub$fifo.v:68$32 ($sub).
Удалены верхние 1 бит (из 2) из порта B ячейки fifo.$auto$opt_dff.cc:195:make_patterns\_logic$72 ($ne).
Удалена ячейка fifo.$flatten\fifo_writer.$procmux$55 ($mux).
Удалены верхние 31 бит (из 32) из порта B ячейки fifo.$flatten\fifo_writer.$add$fifo.v:19$36 ($add).
Удалены верхние 24 бита (из 32) из порта Y ячейки fifo.$flatten\fifo_writer.$add$fifo.v:19$36 ($add).
Удалена ячейка fifo.$flatten\fifo_reader.$procmux$55 ($mux).
Удалили 31 верхний бит (из 32) из порта B ячейки fifo.$flatten\fifo_reader.$add$fifo.v:19$36 ($add).
Удалены верхние 24 бита (из 32) из порта Y ячейки fifo.$flatten\fifo_reader.$add$fifo.v:19$36 ($add).
Удалены верхние 23 бита (из 32) из проволочного fifo.$add$fifo.v:66$29_Y.
Удалены верхние 24 бита (из 32) из проводного fifo.$flatten\fifo_reader.$add$fifo.v:19$36_Y.
Удалены верхние 24 бита (из 32) из проводного fifo.$flatten\fifo_writer.$add$fifo.v:19$36_Y.

yosys> show -notitle -format dot -prefix rdata_wreduce o:rdata %ci\*

Генерация представления конструкции в Graphviz. Запись точечного описания в `rdata_wreduce.dot'. Выгрузка выбранных частей модуля fifo на страницу 1.

yosys> opt_clean

Выполнение pass OPT_CLEAN (удаление неиспользуемых ячеек и проводов). Нахождение неиспользуемых ячеек или проводов в модуле \fifo...

Удалено 0 неиспользуемых ячеек и 5 неиспользуемых проводов.

<подавлено ~1 отладочное сообщение>

yosys> memory_dff

22. Выполнение передачи MEMORY_DFF (объединение ячеек $dff в $memrd).
Проверка порта чтения `\data'[0] в модуле `\fifo': объединение выходных FF в ячейку.
Порт записи 0: отсутствует.

Если посмотреть на путь данных для rdata, то наиболее актуальными из этих уменьшений ширины являются те, которые влияют на fifo. $flatten\fifo_reader.$add$fifo.v. Это ячейка $add, увеличивающая адрес fifo_reader. Мы можем посмотреть на схему и увидеть, что вывод этой ячейки теперь изменился.

Следующие две (новые) команды — peepopt — коллекция peephole-оптимизаторов и share — выполнение разделения ресурсов на основе sat. Ни одна из них не влияет на нашу конструкцию, поэтому пропустим их. techmap -map +/cmp2lut.v -D LUT_WIDTH=4 оптимизирует определенные операторы сравнения, преобразуя их в LUT.

Следующей командой будет memory_dff — объединение входных/выходных DFF в порты чтения памяти.

Вывод rdata после wreduce
Рис. 2.7: Вывод rdata после wreduce
Листинг 2.12: Вывод memory_dff
...
Копировать
yosys> memory_dff

22. Executing MEMORY_DFF pass (merging $dff cells to $memrd).
Checking read port `\data'[0] in module `\fifo': merging output FF to cell.
Write port 0: non-transparent.

Перевод:

...
Копировать
yosys> memory_dff

22. Выполнение pass MEMORY_DFF (объединение ячеек $dff в $memrd).
Проверка порта чтения `\data'[0] в модуле `\fifo': объединение выходных FF в ячейку.
Порт записи 0: отсутствует.
Вывод rdata после memory_dff
Рис. 2.8: Вывод rdata после memory_dff

Как следует из названия, memory_dff объединяет вывод $dff с ячейкой $memrd и преобразует ее в $memrd_v2 (выделено). При этом порт CLK также подключается к входу clk, поскольку теперь это синхронное чтение памяти с соответствующими входами разрешения (EN=1’1) и сброса (ARST=1’0 и SRST=1’0).

2.2.5.3. Часть 3

Третья часть потока synth_ice40 — это серия команд для сопоставления с DSP. По умолчанию поток iCE40 не будет отображаться на аппаратные блоки DSP и будет выполняться только при вызове с параметром -dsp: synth_ice40 -dsp. Хотя в нашем примере нет ничего, что можно было бы сопоставить с DSP, мы все же можем вкратце рассмотреть приведенные здесь команды и описать, что они делают.

Листинг 2.13: coarse секция (часть 3)
...
Копировать
wreduce t:$mul
techmap -map +/mul2dsp.v -map +/ice40/dsp_map.v -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=16 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_Y_MINWIDTH=11 -D DSP_NAME=$__MUL16X16 (if -dsp)
select a:mul2dsp                    (if -dsp)
setattr -unset mul2dsp                (if -dsp)
opt_expr -fine                        (if -dsp)
wreduce                                (if -dsp)
select -clear                        (if -dsp)
ice40_dsp                            (if -dsp)
chtype -set $mul t:$__soft_mul        (if -dsp)

wreduce t:$mul снова выполняет уменьшение ширины, на этот раз только для ячеек типа $mul. techmap -map +/mul2dsp.v -map +/ice40/dsp_map.v … -D DSP_NAME=$__MUL16X16 использует techmap для отображения ячеек $mul на $__MUL16X16, которые, в свою очередь, отображаются на iCE40 SB_MAC16. Все множители, которые не совместимы с преобразованием в $__MUL16X16, перемаркируются в $__soft_mul, прежде чем chtype изменит их обратно на $mul.

Во время преобразования mul2dsp некоторые промежуточные сигналы помечаются атрибутом mul2dsp. Вызвав select a:mul2dsp, мы ограничиваем действие следующих команд только ячейками и проводами, используемыми для этих сигналов. setattr удаляет ненужный теперь атрибут mul2dsp. opt_expr мы уже встречали для сокращения констант и простого переписывания выражений, опция -fine просто обеспечивает более тонкую оптимизацию. Затем мы в последний раз выполняем уменьшение ширины и очищаем выборку.

Наконец, у нас есть ice40_dsp: подобно команде memory_dff, которую мы видели в предыдущем разделе, эта команда объединяет все окружающие регистры в ячейку SB_MAC16. Сюда входят не только входные/выходные регистры, но и регистры конвейера(pipeline) и даже post-adder, где это применимо: превращая умножение + сложение в одно умножение-суммирование.

2.2.5.4. Часть 4

Это подводит нас к четвертой и последней части потока синтеза iCE40:

Листинг 2.14: coarse секция (часть 4)
...
Копировать
alumacc
opt
memory -nomap [-no-rw-check]
opt_clean

Если раньше для каждого типа арифметических операций была своя ячейка, например $add, то теперь мы хотим разделить их на ячейки $alu и $macc, которые помогут выявить возможности для повторного использования логики. Для этого мы запустим alumacc, который, как мы видим, произведет следующие изменения в нашем примере:

Листинг 2.15: вывод alumacc
...
Копировать
yosys> alumacc

24. Executing ALUMACC pass (create $alu and $macc cells).
Extracting $alu and $macc cells in module fifo:
    creating $macc model for $add$fifo.v:66$29 ($add).
    creating $macc model for $flatten\fifo_reader.$add$fifo.v:19$36 ($add).
    creating $macc model for $flatten\fifo_writer.$add$fifo.v:19$36 ($add).
    creating $macc model for $sub$fifo.v:68$32 ($sub).
    creating $alu model for $macc $sub$fifo.v:68$32.
    creating $alu model for $macc $flatten\fifo_writer.$add$fifo.v:19$36.
    creating $alu model for $macc $flatten\fifo_reader.$add$fifo.v:19$36.
    creating $alu model for $macc $add$fifo.v:66$29.
    creating $alu cell for $add$fifo.v:66$29: $auto$alumacc.cc:485:replace_alu$87
    creating $alu cell for $flatten\fifo_reader.$add$fifo.v:19$36: $auto$alumacc.cc:485:replace_alu$90
    creating $alu cell for $flatten\fifo_writer.$add$fifo.v:19$36: $auto$alumacc.cc:485:replace_alu$93
    creating $alu cell for $sub$fifo.v:68$32: $auto$alumacc.cc:485:replace_alu$96
    created 4 $alu and 0 $macc cells.
Перевод:
...
Копировать
yosys> alumacc

1.  Выполнение передачи ALUMACC (создание ячеек $alu и $macc).
Извлечение ячеек $alu и $macc в модуль fifo:
    Создание модели $macc для $add$fifo.v:66$29 ($add).
    Создание $macc модели для $flatten\fifo_reader.$add$fifo.v:19$36 ($add).
    Создание $macc модели для $flatten\fifo_writer.$add$fifo.v:19$36 ($add).
    Создание $macc модели для $sub$fifo.v:68$32 ($sub).
    Создание модели $alu для $macc $sub$fifo.v:68$32.
    Создание модели $alu для $macc $flatten\fifo_writer.$add$fifo.v:19$36.
    Создание модели $alu для $macc $flatten\fifo_reader.$add$fifo.v:19$36. создание модели $alu для $macc $add$fifo.v:66$29.
    Создание ячейки $alu для $add$fifo.v:66$29: $auto$alumacc.cc:485:replace_alu$87
    создание ячейки $alu для $flatten\fifo_reader.$add$fifo.v:19$36: $auto$alumacc.cc:485:replace_alu$90
    создание ячейки $alu для $flatten\fifo_writer.$add$fifo.v:19$36: $auto$alumacc.cc:485:replace_alu$93
    Создание ячейки $alu для $sub$fifo.v:68$32: $auto$alumacc.cc:485:replace_alu$96 создало 4 ячейки $alu и 0 ячеек $macc.

После того как эти ячейки вставлены, вызов opt может объединить ячейки, которые теперь идентичны, но могли быть пропущены, например, из-за разницы между $add и $sub.

Другой новой командой в этой части является memory — перевод памяти в базовые ячейки.

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

Взглянув на схему после запуска memory_collect, мы видим, что наша ячейка $memrd_v2 была заменена ячейкой $mem_v2 с именем data, тем же именем, которое мы использовали в fifo.v. Там, где раньше у нас был один набор сигналы адреса и разрешения, теперь у нас есть один набор для чтения (RD_*) и один для записи (WR_*), а также вход WR_DATA и выход RD_DATA.

вывод rdata после alumacc
Рис. 2.9: вывод rdata после alumacc
вывод rdata после memory_collect
Рис. 2.10: вывод rdata после memory_collect

2.2.5.5. Заключение

Дойдя до конца грубозернистого представления, мы также могли бы добраться до этого места, выполнив synth_ice40 -top fifo -run :map_ram после загрузки конструкции. Опция -run <from_label>:<to_label> с пустой <from_label> запускается с секции begin, а <to_label> запускается до секции map_ram, но включая ее.

2.2.6. Сопоставление аппаратных средств

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

Если вы пропустили вызов read_verilog -D ICE40_HX -lib -specify +/ice40/cells_sim.v ранее, сделайте это сейчас.

2.2.6.1. Блоки памяти

Для отображения на блоки памяти используется комбинация memory_libmap и techmap.

Листинг 2.16: секция map_ram

...
Копировать
memory_libmap -lib +/ice40/brams.txt -lib +/ice40/spram.txt [-no-auto-huge] [-no-auto-block] (-no-auto-huge unless -spram, -no-auto-block if -nobram)
techmap -map +/ice40/brams_map.v -map +/ice40/spram_map.v
ice40_braminit
вывод rdata после секции map_ram
Рис. 2.11: вывод rdata после секции map_ram

Секция map_ram преобразует общий $mem_v2 в iCE40 SB_RAM40_4K (выделено). Мы также видим, что адрес памяти был изменен, а биты данных были переупорядочены (или перемешаны). Также теперь есть ячейка $mux, управляющая значением rdata. В файле fifo.v мы записали память в режиме чтения перед записью, однако SB_RAM40_4K имеет неопределенное поведение при чтении с одного и того же адреса и записи на него в одном и том же цикле. В результате была добавлена дополнительная логика, чтобы сгенерированная схема соответствовала поведению verilog.

Если мы запустим memory_libmap под командой debug, то увидим варианты, которые были определены для отображения, а также затраты каждого из них и то, какая логика требует эмуляции.
...
Копировать
yosys> debug memory_libmap -lib +/ice40/brams.txt -lib +/ice40/spram.txt -no-auto-huge
4. Executing MEMORY_LIBMAP pass (mapping memories to cells).
Memory fifo.data mapping candidates (post-geometry):
- logic fallback
    - cost: 2048.000000
- $__ICE40_RAM4K_:
    - option HAS_BE 0
    - emulation score: 7
    - replicates (for ports): 1
    - replicates (for data): 1
    - mux score: 0
    - demux score: 0
    - cost: 78.000000
    - abits 11 dbits 2 4 8 16
    - chosen base width 8
    - swizzle 0 1 2 3 4 5 6 7
    - emulate read-first behavior
    - write port 0: port group W
        - widths 2 4 8
    - read port 0: port group R
        - widths 2 4 8 16
        - emulate transparency with write port 0
- $__ICE40_RAM4K_:
    - option HAS_BE 1
    - emulation score: 7
    - replicates (for ports): 1
    - replicates (for data): 1
    - mux score: 0
    - demux score: 0
    - cost: 78.000000
    - abits 11 dbits 2 4 8 16
    - byte width 1
    - chosen base width 8
    - swizzle 0 1 2 3 4 5 6 7
    - emulate read-first behavior
    - write port 0: port group W
        - widths 16
    - read port 0: port group R
        - widths 2 4 8 16
        - emulate transparency with write port 0
Memory fifo.data mapping candidates (after post-geometry prune):
- logic fallback
    - cost: 2048.000000
- $__ICE40_RAM4K_:
    - option HAS_BE 0
    - emulation score: 7
    - replicates (for ports): 1
    - replicates (for data): 1
    - mux score: 0
    - demux score: 0
    - cost: 78.000000
    - abits 11 dbits 2 4 8 16
    - chosen base width 8
    - swizzle 0 1 2 3 4 5 6 7
    - emulate read-first behavior
    - write port 0: port group W
        - widths 2 4 8
    - read port 0: port group R
        - widths 2 4 8 16
        - emulate transparency with write port 0
mapping memory fifo.data via $__ICE40_RAM4K_

Ячейка $__ICE40_RAM4K_ определена в файле techlibs/ice40/brams.txt, а отображение на SB_RAM40_4K выполняется с помощью techmap, используя techlibs/ice40/brams_map.v. Любые оставшиеся ячейки памяти затем преобразуются в триггеры (thelogic fallback) с помощью memory_map .

Листинг 2.17: секция map_ffram
...
Копировать
opt -fast -mux_undef -undriven -fine
memory_map
opt -undriven -fine

Примечание: Визуальный беспорядок на выходном порту RDATA (выделено) является досадным побочным эффектом opt_clean для битов данных, подвергшихся выборке. При подключении входного порта $mux непосредственно к RDATA для уменьшения количества проводов, провод $techmap579\data.0.0.RDATA становится визуально более сложным.

вывод rdata после секции map_ffram
Рис. 2.12: вывод rdata после секции map_ffram

2.2.6.2. Арифметика

Использует техкарту для отображения базовой арифметической логики на аппаратное обеспечение. Здесь наблюдается некоторый всплеск ячеек, поскольку многобитные $mux и $adffe заменяются однобитными $_MUX_ и $_DFFE_PP0P_, а $alu заменяется примитивными $_OR_ и $_NOT_ вентилями и ячейкой $lut.

вывод rdata после секции map_gates
Рис. 2.13: вывод rdata после секции map_gates
Листинг 2.18: секция map_gates
...
Копировать
ice40_wrapcarry
techmap -map +/techmap.v -map +/ice40/arith_map.v
opt -fast
abc -dff -D 1 (only if -retime)
ice40_opt

2.2.6.3. Flip-flops

Преобразуйте FF в типы, поддерживаемые аппаратно, с помощью dfflegalize , а затем используйте techmap для их отображения.

В нашем примере это преобразует ячейки $_DFFE_PP0P_ в SB_DFFER. Мы также запускаем здесь simplemap, чтобы преобразовать все оставшиеся ячейки, которые не удалось отобразить на аппаратное обеспечение, в примитивы уровня вентилей. Это включает оптимизацию ячеек $_MUX_, где один из входов является константой 1’0, заменяя ее ячейкой $_AND_.

Листинг 2.19: секция map_ffs

...
Копировать
dfflegalize -cell $_DFF_?_ 0 -cell $_DFFE_?P_ 0 -cell $_DFF_?P?_ 0 -cell $_DFFE_?P?P_ 0 -cell $_SDFF_?P?_ 0 -cell $_SDFFCE_?P?P_ 0 -cell $_DLATCH_?_ x -mince -1
techmap -map +/ice40/ff_map.v
opt_expr -mux_undef
simplemap
ice40_opt -full
вывод rdata после секции map_ffs
Рис. 2.14: вывод rdata после секции map_ffs

2.2.6.4. LUTs

abc и techmap используются для отображения LUT. Преобразование примитивных типов ячеек для использования ячеек $lut и SB_CARRY.

Листинг 2.20: секция map_luts

...
Копировать
abc (only if -abc2)
ice40_opt (only if -abc2)
techmap -map +/ice40/latches_map.v
simplemap (if -noabc or -flowmap)
techmap -map +/gate2lut.v -D LUT_WIDTH=4 (only if -noabc)
flowmap -maxlut 4 (only if -flowmap)
read_verilog -D ICE40_HX -icells -lib -specify +/ice40/abc9_model.v
abc9 -W 250
ice40_wrapcarry -unwrap
techmap -map +/ice40/ff_map.v
clean
opt_lut -tech ice40
вывод rdata после секции map_luts
Рис. 2.15: вывод rdata после секции map_luts

Наконец, мы используем techmap для сопоставления общих ячеек $lut с ячейками iCE40 SB_LUT4.

Листинг 2.21: секция map_cells

...
Копировать
techmap -map +/ice40/cells_map.v (skip if -vpr)
clean
вывод rdata после секции map_cells
Рис. 2.16: вывод rdata после секции map_cells

2.2.6.5. Другие клетки

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

Эти команды обычно находятся либо в секции map_cells, либо после секции check, в зависимости от потока.

2.2.7. Заключительные шаги

На следующем этапе работы с синтезатором iCE40 выполняется проверка правильности и окончательное приведение в порядок:

Листинг 2.22: секция проверки
...
Копировать
autoname
hierarchy -check
stat
check -noinit
blackbox =A:whitebox

Новыми командами здесь являются:

Вывод stat полезен для проверки использования ресурсов. Он предоставляет список ячеек, используемых в конструкции, и количество каждой из них, а также количество других используемых ресурсов, таких как провода и процессы. Для данной конструкции финальный вызов stat должен выглядеть следующим образом:
...
Копировать
yosys> stat -top fifo

17. Printing statistics.

=== fifo ===

    Number of wires: 95
    Number of wire bits: 262
    Number of public wires: 95
    Number of public wire bits: 262
    Number of ports: 7
    Number of port bits: 29
    Number of memories: 0
    Number of memory bits: 0
    Number of processes: 0
    Number of cells: 138
        $scopeinfo 2
        SB_CARRY 26
        SB_DFF 26
        SB_DFFER 25
        SB_LUT4 58
        SB_RAM40_4K 1

Обратите внимание, что параметр -top fifo здесь необязателен. stat автоматически будет использовать модуль с установленным атрибутом top, которым был fifo, когда мы вызывали hierarchy. Если ни один модуль не отмечен как top, то статистика будет показана для каждого выбранного модуля.

Вывод статистики также полезен в качестве своеобразной проверки на рациональность: Поскольку мы уже запустили proc , мы не ожидаем, что будут какие-либо процессы. Мы также ожидаем, что данные будут использовать аппаратную память(примитив); если бы вместо SB_RAM40_4K мы увидели большое количество используемых флип-флопов, то могли бы заподозрить неладное.

Если бы мы вместо этого вызвали stat сразу после read_verilog fifo.v, то увидели бы совсем другое:
...
Копировать
yosys> stat

2. Printing statistics.

=== fifo ===

    Number of wires: 28
    Number of wire bits: 219
    Number of public wires: 9
    Number of public wire bits: 45
    Number of ports: 7
    Number of port bits: 29
    Number of memories: 1
    Number of memory bits: 2048
    Number of processes: 3
    Number of cells: 9
        $add 1
        $logic_and 2
        $logic_not 2
        $memrd 1
        $sub 1
        addr_gen 2

=== addr_gen ===

    Number of wires: 8
    Number of wire bits: 60
    Number of public wires: 4
    Number of public wire bits: 11
    Number of ports: 4
    Number of port bits: 11
    Number of memories: 0
    Number of memory bits: 0
    Number of processes: 2
    Number of cells: 2
        $add 1
        $eq 1

Обратите внимание, что fifo и addr_gen перечислены отдельно, а статистика для fifo показывает 2 модуля addr_gen. Поскольку память еще не была отображена, мы также видим, что имеется 1 память с 2048 битами памяти, что соответствует нашей памяти данных шириной 8 бит с 256 значениями (8 * 256 = 2048).

2.2.7.1. Выходные данные синтеза

В потоке синтеза iCE40 доступны следующие режимы вывода:

Например, если мы вызвали synth_ice40 -top fifo -json fifo.json, наш синтезированный конструкция fifo будет выведен в виде fifo.json. Затем мы можем прочитать этот конструкцию обратно в Yosys с помощью read_json, но не забудьте сначала использовать design -reset или открыть новый интерактивный терминал. Полученный JSON-вывод также может быть загружен в nextpnr для выполнения размещения и маршрутизации; но это выходит за рамки данной документации.

Главная
Курсы
Вебинары
1. Что такое Yosys
2.1. Установка Yosys
2.2. Синтезатор
Закрыть