Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Labs/01. Tcl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@
Если вы не помните как создавать проекты, то обратитесь к
[материалам АПС с прошлого семестра](https://github.com/MPSU/APS/tree/master/Vivado%20Basics).

**Примечание**

Vivado часто сохраняет в Tcl-скрипте абсолютные пути к исходным файлам, например `C:/Users/.../Downloads/...`. Такой скрипт обычно корректно работает только на том компьютере, где он был создан. При переносе проекта в другую папку или на другой компьютер пути могут стать недействительными.

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

Например:

```tcl
# Абсолютный путь
set file "C:/Users/name/Downloads/demo.sv"

# Относительный путь
set file [file join "." "rtl" "demo.sv"]
```

Второй вариант удобнее тем, что при сохранении структуры проекта Tcl-скрипт проще переносить между каталогами и компьютерами.


## Экспорт скрипта для автоматизированного создания проекта в Vivado

Давайте теперь мы создадим свой первый Tcl скрипт. Этот скрипт будет сгенерирован Vivado и будет предназначаться для восстановления проекта. Затем мы будем менять и дополнять этот скрипт.
Expand Down
15 changes: 9 additions & 6 deletions Labs/06.AXI-Stream/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ module simple_valid_ready_slave
end
end

assign ready_o = ready_ff;
assign saved_data_o = data_ff;

endmodule

```
Expand Down Expand Up @@ -149,7 +152,7 @@ endmodule

У вас может возникнуть логичный вопрос: а почему бы просто не поставить регистры на сигнал `ready`, ничего не меняя? Вы можете построить временную диаграмму работы такого решения и убедиться, что оно, к сожалению, окажется неработоспособно.

Тем не менее, существует несколько вариантов решения проблемы с критическим пути по линии `ready`. Самый простой вариант представлен ниже:
Тем не менее, существует несколько вариантов решения проблемы с критическим путем по линии `ready`. Самый простой вариант представлен ниже:

```verilog
module valid_ready_pipe_2
Expand Down Expand Up @@ -424,7 +427,7 @@ AXI Stream (Advanced eXtensible Interface Stream) — это протокол д
4. `TREADY` (Ready — Готовность приёмника). Указывает, что приёмник готов принять данные. Этот сигнал генерируется Slave. Передача данных происходит только при одновременной активности `TVALID` и `TREADY` (handshake).

При этом в спецификации интерфейса AXI Stream существует важные правила, определяющие работу сигналов `TVALID` и `TREADY`
* Slave может удерживать `TREADY` = 1 во то время, когда `TREADY` = 0.
* Slave может удерживать `TREADY` = 1 в то время, когда `TVALID` = 0.
* Slave может опускать `TREADY` в 0 в любой момент времени и "слушающий этот сигнал" Master должен это учитывать.
* Однажды выставив `TVALID` в 1 Master более **не имеет права** выставлять `TVALID` в 0 до момента, пока не произойдёт рукопожатие и транзакция. То есть, Master не имеет права "передумать", выставляя флаг валидности.

Expand Down Expand Up @@ -675,7 +678,7 @@ endmodule
assign grant[0] = req[0];
assign grant[1] = ~req[0] & req[1];
assign grant[2] = ~req[0] & ~req[1] & req[2];
assign grant[3] = ~req[0] & ~req[1] & req[2] & ~req[3];
assign grant[3] = ~req[0] & ~req[1] & ~req[2] & req[3];
```

Второй способ полезен при описании конфигурируемых дизайнов, где количество портов (а значит и элементов, требующих арбитража) может параметризоваться. Данный пример не является законченным и синтезируемым, но он отлично поясняет идею, которую можно развить с помощью конструкции `for`.
Expand Down Expand Up @@ -823,7 +826,7 @@ endmodule
![](./pic/rr_arb.png)

- Мы добавили указатель `ptr_ff`, который указывает текущий приоритет. При этом, следующее значение указателя всегда выбирается таким, чтобы он указывал на следующий порт относительно того, на котором в данный момент происходит транзакция. Таким образом, приоритет порта с транзакцией на следующий такт понизится до наименьшего.
- В сердце показанного примера до сих пор находится статический арбитр, но мы делаем интересный трюк: сначала мы циклический сдвигаем вектор `req` вправо на количество бит из текущего значения `ptr_ff`, то есть, мы поворачиваем входной вектор `req` так, чтобы `ptr_ff`-й элемент имел максимальный статичный приоритет, в результате получая вектор `req_rotated`. Результат вычисления приоритета `grant_rotated` нельзя просто так использовать для управления портами, его нужно "повернуть обратно", выполнив циклический сдвиг влево на те же `ptr_ff` бит. Таким образом, мы хитрым образом вращаем биты вокруг статического приоритета, чтобы получить динамический арбитраж. Всё гениальное -- просто!
- В сердце показанного примера до сих пор находится статический арбитр, но мы делаем интересный трюк: сначала мы циклически сдвигаем вектор `req` вправо на количество бит из текущего значения `ptr_ff`, то есть, мы поворачиваем входной вектор `req` так, чтобы `ptr_ff`-й элемент имел максимальный статичный приоритет, в результате получая вектор `req_rotated`. Результат вычисления приоритета `grant_rotated` нельзя просто так использовать для управления портами, его нужно "повернуть обратно", выполнив циклический сдвиг влево на те же `ptr_ff` бит. Таким образом, мы хитрым образом вращаем биты вокруг статического приоритета, чтобы получить динамический арбитраж. Всё гениальное -- просто!

Стоит обратить внимание на то, что формирование сигналов `req_rotated` и `grant` можно описать более красивым и изящным способом, который, помимо всего прочего, легко ложится на параметризуемый дизайн с переменным числом портов.

Expand All @@ -843,7 +846,7 @@ assign grant[3:0] = grant_double[7:4];

### Коммутация потоков данных

Теперь, когда мы знакомы с концепциями fork и join, знаем про арбитраж, мы можем приступить к разработке блока коммутатора, имеющего N входов и M выходов и способного обеспечить связность любого входа с любым выходом. Такую схему, с начиная с зари развития телефонии, принято называть **crossbar switch**.
Теперь, когда мы знакомы с концепциями fork и join, знаем про арбитраж, мы можем приступить к разработке блока коммутатора, имеющего N входов и M выходов и способного обеспечить связность любого входа с любым выходом. Такую схему, начиная с зари развития телефонии, принято называть **crossbar switch**.

Суть простейшего коммутатора заключается в наборе блоков fork и join, подключенных с топологией соединений "каждый с каждым". Пример такого коммутатора на 3 входных и 3 выходных показан на рисунке ниже.

Expand Down Expand Up @@ -981,7 +984,7 @@ module axis_join_param
## Контрольные вопросы
1. Зачем нужен сигнал `ready` в интерфейсе valid-ready?
2. Что такое рукопожатие (handshake)?
3. Что такой обратное давление (backpressure)?
3. Что такое обратное давление (backpressure)?
4. Какая проблема возникает с сигналом `ready` при соединении большого количества модулей в конвейер?
5. Какие способы развязки критического пути по backpressure вы знаете? Опишите их.
6. Что такое кредитный механизм? Для чего он нужен? Как он работает?
Expand Down