mirror of
https://github.com/MPSU/APS.git
synced 2025-09-15 09:10:10 +00:00
Рефактор Debug manual
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
|
||||
Этот документ посвящен практикуму по поискам подобных ошибок в **SystemVerilog**-коде.
|
||||
|
||||
> Обратите внимание на то, как ставится ударение в словосочетании "временна́я диаграмма" (не "вре́менная"). В обиходе это словосочетание заменяется словом "времянка".
|
||||
|
||||
- [Руководство по поиску и исправлению ошибок в проекте](#руководство-по-поиску-и-исправлению-ошибок-в-проекте)
|
||||
- [Цель](#цель)
|
||||
- [Алгоритм поиска ошибок](#алгоритм-поиска-ошибок)
|
||||
@@ -27,13 +29,13 @@
|
||||
|
||||
1. Обычно всё начинается с сообщения в логе тестов (никто не проверяет глазами временную диаграмму сложных проектов, состоящую из тысяч сигналов, меняющихся миллионы раз за микросекунду), но на наших простых лабах, этот шаг иногда может быть и пропущен.
|
||||
Сообщение в логе обычно содержит следующую ключевую информацию: имя сигнала, на котором установилось неверное значение, и время когда это произошло. Чем лучше написаны тесты, тем больше ключевой информации будет отражено в сообщении, поэтому написание тестов является своего рода искусством.
|
||||
1. Получив имя сигнала и время, мы отправляемся на временную диаграмму и проверяем нашу ошибку. Как это сделать? Необходимо определить по коду, какие сигналы и каким образом управляют нашим сигналом. Вариантов может быть несколько:
|
||||
1. Управляющие сигналы имеют корректное значение, но логика, по которой они управляют сигналом неверна, из-за этого на нем возникает неверное значение.
|
||||
2. Получив имя сигнала и время, мы отправляемся на временную диаграмму и проверяем нашу ошибку. Как это сделать? Необходимо определить по коду, какие сигналы и каким образом управляют нашим сигналом. Вариантов может быть несколько:
|
||||
1. Управляющие сигналы имеют корректное значение, но логика, по которой они управляют сигналом неверна, из-за этого на нем возникает неверное значение.
|
||||
Это идеальный случай, при возникновении которого мы сразу же находим причину проблемы и исправляем ее.
|
||||
2. Логика управления верна, а какая-то часть управляющих сигналов имеет неверное значение (пусть для примера, неверное значение будет на управляющем сигнале `X`). Это означает, что обнаруженное несоответствие сигналов является уже следствием какой-то ошибки, и мы должны вернуться к шагу 2, проверяя источники сигналов для сигнала `X`. Так происходит до тех пор, пока мы не попадаем в тип 1.
|
||||
3. Логика управления и значения управляющих сигналов верны. Это самый сложный тип ошибок, который заключается либо в ошибке в спецификации разрабатываемого устройства, либо в САПРе или компонентах, влияющих на его работу. В рамках данного курса вас не должны заботить данные ошибки, и при их возникновении вам стоит обратиться к преподавателю (предварительно убедившись, что ошибка совершенно точно не подходит под первые два варианта).
|
||||
4. Любая возможная комбинация всех предыдущих типов.
|
||||
2. Обнаружив первопричину ошибки, мы исправляем ее (возможно дополняя набор тестов, или внеся правки в спецификацию), и повторно запускаем все тесты, чтобы убедиться в двух вещах:
|
||||
3. Обнаружив первопричину ошибки, мы исправляем ее (возможно дополняя набор тестов, или внеся правки в спецификацию), и повторно запускаем все тесты, чтобы убедиться в двух вещах:
|
||||
1. ошибка действительно исправлена
|
||||
2. исправление ошибки не породило новых ошибок
|
||||
|
||||
@@ -43,27 +45,41 @@
|
||||
|
||||
После запуска симуляции мы видим в логе множество ошибок:
|
||||
|
||||

|
||||

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

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

|
||||
|
||||
_Рисунок 2. Пример конкретной ошибки в тесте._
|
||||
|
||||
В логе сказано, что в момент времени `5ns`, на дизайн подавались координаты вектора, равные `0` и `0`, модель посчитала, что длина вектора равна нулю, в то время как дизайн вернул значение `x`.
|
||||
|
||||
## Поиск ошибки на временной диаграмме
|
||||
|
||||
Давайте найдем это место на временной диаграмме. Обычно, сразу после запуска симуляции на временной диаграмме отображено место, где симуляция остановилась (возможно с очень неподходящим масштабом). Для начала подгоним масштаб таким образом, чтобы вся временная диаграмма умещалась в окне. Это делается либо нажатием правой кнопкой мыши по в области отображения сигналов, с выбором "Full View" во всплывающем меню, либо нажатием на кнопку Затем найдем приблизительное место рядом с тем временем, что нас интересует, установим там курсор, и приблизим масштаб, периодически уточняя местоположения курсора, пока не найдем интересующее нас место.
|
||||
Давайте найдем это место на временной диаграмме. Обычно, сразу после запуска симуляции на временной диаграмме отображено место, где симуляция остановилась (возможно с очень неподходящим масштабом). Для начала подгоним масштаб таким образом, чтобы вся временная диаграмма умещалась в окне. Это делается либо нажатием правой кнопкой мыши по в области отображения сигналов, с выбором "Full View" во всплывающем меню, либо нажатием соответствующей кнопки на панели временной диаграммы (см. _рис. 4_), либо нажатием комбинации клавиш `Ctrl+0`. Затем найдем приблизительное место рядом с тем временем, что нас интересует, установим там курсор, и приблизим масштаб (покрутив колесиком мыши при зажатой клавише `Ctrl`), периодически уточняя местоположения курсора, пока не найдем интересующее нас место.
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
_Рисунок 3. Пример временной диаграммы сразу поле остановки моделирования._
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
_Рисунок 4. Пример установки масштаба временной диаграммы таким образом, чтобы та помещалась в текущем окне._
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 5. Пример временной диаграммы после подгонки масштаба._
|
||||
|
||||

|
||||
|
||||
_Рисунок 6. Установка курсора в начало моделирования, чтобы, при увеличении масштаба, временная диаграмма сходилась к началу._
|
||||
|
||||

|
||||
|
||||
_Рисунок 7. Временная диаграмма, отмасштабированная к времени ошибки с рис. 2._
|
||||
|
||||
Мы видим ровно ту информацию, которую нам предоставил тестбенч. Теперь надо разобраться в причинах возникновения X-состояния. Такое может произойти в двух ситуациях: какой-то из сигналов, формирующих этот находится в `X` или `Z` состоянии, либо же два каких-то сигнала одновременно пытаются выставить разные значения (подобный вариант встречается куда реже и в цикле ваших лабораторных вряд ли встретится).
|
||||
|
||||
@@ -71,7 +87,9 @@
|
||||
|
||||
В любом случае, первым делом необходимо определить, источник формирования значения сигнала `res`. Для этого, откроем файл с исходным кодом, где определен данный сигнал. Для этого, нажмем правой кнопкой мыши по имени сигнала на временной диаграмме, и выберем `Go To Source Code`:
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 8. Переход к месту объявления "проблемного" сигнала._
|
||||
|
||||
Открывается следующий код (с курсором на строчке `wire [31:0] res;`):
|
||||
|
||||
@@ -90,7 +108,8 @@ vector_abs dut(
|
||||
//...
|
||||
```
|
||||
|
||||
Выделив `res` мы видим, что у нас подсветился `res` в строке `abs(res)`, что означает что мы завели наш провод внутрь объекта `dut` модуля `vector_abs`, и у нас проблема второго типа (X-состояние передалось от выхода `abs` модуля `vector_abs` проводу `res` модуля `tb`).
|
||||
Выделив `res` мы видим, что у нас подсветился `res` в строке `abs(res)`. Это означает, что мы завели наш провод внутрь объекта `dut` модуля `vector_abs`, и у нас проблема второго типа (X-состояние передалось от выхода `abs` модуля `vector_abs` проводу `res` модуля `tb`).
|
||||
|
||||
В этом можно убедиться, если вытащить сигналы модуля `vector_abs` на временную диаграмму. Чтобы это сделать, надо переключиться на окно `Scope`, где размещена иерархия объектов нашего тестбенча
|
||||
|
||||
## Добавление сигналов объектов на временную диаграмму
|
||||
@@ -99,16 +118,43 @@ vector_abs dut(
|
||||
|
||||
Выделим объект `dut`. В окне `Objects` справа отобразятся все внутренние сигналы (входы/выходы, внутренние провода и регистры) объекта `dut`:
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 9. Отображение внутренних сигналов проверяемого модуля._
|
||||
|
||||
Вообще говоря, мы уже видим, что выход `abs` (к которому подключен наш провод `res`) находится в X-состоянии, но для отработки навыков, разберемся с добавлением на временную диаграмму. Можно поступить двумя способами:
|
||||
|
||||
1. Добавить все сигналы (то, что видно в окне `Objects` на временную диаграмму) из окна `Scope` для этого, либо перетаскиваем нужный нам объект, зажав левую кнопку мыши на временную диаграмму, либо жмем правой кнопкой мыши по нужному объекту, и выбираем `Add to Wave Window`
|
||||
2. Добавить отдельные сигналы из окна `Objects`. Для этого выделяем их (возможно множественное выделение через модификаторы `shift` или `ctrl`), и как и в прошлом случае, либо перетаскиваем сигналы левой кнопкой мыши, либо добавляем их через правую кнопку мыши.
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
_Рисунок 10. Добавление сигналов модуля на временную диаграмму._
|
||||
|
||||

|
||||
|
||||
_Рисунок 11. Результат добавления сигналов модуля на временную диаграмму._
|
||||
|
||||
По мере роста сложности проекта, число сигналов на временной диаграмме будет постоянно расти, в связи с чем встает вопрос группировки сигналов.
|
||||
|
||||
Для того чтобы объединить сигналы в группу, необходимо их выделить. Это можно сделать двумя способами:
|
||||
|
||||
1. "прокликав" интересующие сигналы при зажатой клавише `Ctrl`;
|
||||
2. если речь идет о диапазоне сигналов, можно выбрать сигнал с одного края, после чего, при зажатой клавише `Shift`, выбрать сигнал с другого края этого диапазона.
|
||||
|
||||
После выбора, необходимо нажать правой кнопкой мыши по выделенным сигналам, и в низу выпадающего списка выбрать `New Group`.
|
||||
|
||||

|
||||
|
||||
_Рисунок 12. Пример создания группы сигналов (контекстное меню было обрезано для удобства отображения)._
|
||||
|
||||
После создания группы, ей нужно будет дать имя. В случае, если все сигналы принадлежат одному модулю, удобно называть группу сигналов именем этого модуля.
|
||||
|
||||

|
||||
|
||||
_Рисунок 13. Пример созданной группы сигналов._
|
||||
|
||||
Данну группу можно сворачивать и разворачивать, нажимая на соответствующую стрелку слева от имени группы.
|
||||
|
||||
> Обратите внимание, что часть сигналов отображают какое-то значение (сигнал `abs` отображает X-состояние), а часть не отображают ничего. Так произошло, потому что провод `abs` **непрерывно связан** с проводом `res`, с точки зрения симулятора это одна сущность, и записывая во время моделирования значения для сигнала `res`, симулятор неявно записывал значения для сигнала `abs`, чего не скажешь про остальные сигналы, которых не было во время моделирования на временной диаграмме.
|
||||
|
||||
@@ -116,29 +162,36 @@ vector_abs dut(
|
||||
|
||||
Для того, чтобы получить отсутствующие значения, необходимо повторить моделирование. Для этого, необходимо сбросить время моделирования в 0 и запустить его снова.
|
||||
|
||||
Для этого, необходимо на панели симуляции нажать кнопку `Restart` (`|◀`), а затем кнопку `Run all` (`▶`) или `Run for` (`▶t`)
|
||||
Для этого, необходимо на панели симуляции нажать кнопку `Restart` (`|◀`), а затем кнопку `Run all` (`▶`) или `Run for` (`▶t`). Положение кнопок в окне Vivado иллюстрирует _рис. 14_.
|
||||
|
||||

|
||||
|
||||
_Рисунок 14. Расположение кнопок, управляющих моделированием в окне Vivado._
|
||||
|
||||
Панель управления симуляции с кнопками:
|
||||
|
||||
1. `Restart`, горячие клавиши: `Ctrl+Shift+F5`;
|
||||
2. `Run all`, горячая клавиша: `F3`;
|
||||
3. `Run for`, горячие клавиши: `Shift+F2`;
|
||||
4. `Relaunch Simulation`.
|
||||
|
||||
`Run for` выполняет моделирование указанного количества времени, после чего моделирование приостанавливается. Моделирование может быть остановлено так же и вручную, либо вызовом соответствующей инструкции из кода теста.
|
||||
|
||||
`Run for` выполняет моделирование указанного количества времени, после чего моделирование приостанавливается. Моделирование может быть остановлено так же и вручную, либо вызовом соответствующей инструкции из кода теста.
|
||||
`Run all` отличается от `Run for` тем, что в качестве количества моделируемого времени указывается "бесконечность", и моделирование будет остановлено только вручную, либо вызовом соответствующей инструкции.
|
||||
|
||||
> Обратите внимание, что для добавления недостающих значений добавленных сигналов лучше всего выполнять описанную выше инструкцию. Аналогичного результата можно добиться и нажатием на кнопку `Relaunch Simulation`, однако эта команда запускает повторную компиляцию и запуск симуляции, что для крупных проектов выльется в потерю времени на излишнюю компиляцию.
|
||||
|
||||

|
||||
Кроме того, чтобы курсор и лог снова не ушли далеко от места первой ошибки, можно сразу указать, необходимое нам время моделирования перед выполнением команды `Run for`: `5ns`.
|
||||
|
||||
Панель управления симуляции с кнопками:
|
||||

|
||||
|
||||
1. `Restart`
|
||||
2. `Run all`
|
||||
3. `Run for`
|
||||
4. `Relaunch Simulation`
|
||||
_Рисунок 15. Пример моделирования 5ns._
|
||||
|
||||
Кроме того, чтобы курсор и лог снова не ушли далеко от места первой ошибки, можно сразу указать, необходимое нам время моделирования перед выполнением команды `Run for`: `5ns`
|
||||
На _рис. 16_ представлен результат моделирования с новыми сигналами.
|
||||
|
||||

|
||||

|
||||
|
||||
В итоге видим следующую картину на временной диаграмме:
|
||||
|
||||

|
||||
_Рисунок 16. Результат повторного моделирования после добавления на временную диаграмму новых сигналов._
|
||||
|
||||
Видим два сигнала в Z-состоянии и один сигнал в X-состоянии. Обычно, сигналы с Z-состоянием проще всего исправить, т.к. зачастую это забытое или некорректное подключение провода. Кроме того, сигнал, зависящий от сигнала с Z-состоянием, может оказаться в X-состоянии, так что это может быть решением нашей проблемы, поэтому займемся проводами `min` и `min_half`. Сперва займемся сигналом `min` и перейдем к шагу 2 нашего алгоритма (нажимаем правой кнопкой мыши и выбираем `Go To Source Code`):
|
||||
|
||||
@@ -163,41 +216,56 @@ vector_abs dut(
|
||||
|
||||
## Исправление сигналов с Z-состоянием
|
||||
|
||||
Мы видим, что сигнал `min` подключен к выходу `min` объекта `max_min_unit` модуля `max_min`. Добавим сигналы этого модуля на временную диаграмму. Для этого, необходимо раскрыть список объектов, содержащихся в объекте `dut` иерархии объектов `Scope` и выбрать там объект `max_min_unit`:
|
||||
Мы видим, что сигнал `min` подключен к выходу `min` объекта `max_min_unit` модуля `max_min`. Добавим сигналы этого модуля на временную диаграмму. Для этого, необходимо раскрыть список объектов, содержащихся в объекте `dut` иерархии объектов `Scope` и выбрать там объект `max_min_unit`.
|
||||
|
||||

|
||||

|
||||
|
||||
Добавляем внутренние сигналы на временную диаграмму, и повторяем моделирование:
|
||||
_Рисунок 17. Добавление сигналов вложенных модулей на временную диаграмму._
|
||||
|
||||

|
||||
Добавляем внутренние сигналы на временную диаграмму, группируем их под именем `max_min`, и повторяем моделирование.
|
||||
|
||||

|
||||
|
||||
_Рисунок 18. Результат добавления и группировки сигналов подмодуля `max_min`._
|
||||
|
||||
Произошло что-то странное: все внутренние сигналы объекта `max_min_unit` "зеленые" (не имеющие X или Z состояния), однако подключенный к выходу этого модуля сигнал `min` находится в Z-состоянии. Как такое могло произойти?
|
||||
|
||||
Если присмотреться к сигналу `min`, находящемуся в Z-состоянии, можно заметить, что младшая цифра находится не в Z-состоянии, а в состоянии `0`, такое же значение стоит и на сигнале `min` объекта `max_min_unit`. Это интересно.
|
||||
Если присмотреться к этим двум сигналам еще пристальней, то можно увидеть, что у сигнала `min` объекта `dut` разрядность 32 бита, в то время как разрядность сигнала `min` объекта `max_min_unit` составляет 4 бита.
|
||||
Это и является проблемой: мы подключили 4 бита сигнала 4-разрядного сигнала `min` к младшим 4 битам 32-разрядного сигнала `min`, а остальные разряды остались не подключенными.
|
||||
|
||||
Если присмотреться к этим двум сигналам еще пристальней, то можно увидеть, что у сигнала `min` объекта `dut` разрядность 32 бита, в то время как разрядность сигнала `min` объекта `max_min_unit` составляет 4 бита.
|
||||
|
||||
Это и является проблемой: мы подключили 4 бита сигнала 4-разрядного сигнала `min` к младшим 4 битам 32-разрядного сигнала `min`, а остальные разряды остались не подключенными.
|
||||
|
||||
По всей видимости, при написании модуля `max_min`, была указана неверная разрядность сигнала `min`, вместо `31` было написано `3`. Исправим это и повторим моделирование.
|
||||
|
||||
> Обратите внимание, что поскольку мы изменили исходный код, в этот раз необходимо нажать на кнопку `Relaunch Simulation`, поскольку нужна повторная компиляция проекта.
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 19. Результат моделирования после исправления разрядности сигнала `min`.
|
||||
|
||||
В логе сообщается о 102 найденных ошибках. Ровно на одну ошибку меньше, чем было ранее. Это не означает, что в проекте осталось 102 ошибки, только то, что, исправив данную ошибку — мы действительно что-то исправили, и один из тестовых сценариев, который ранее завершался ошибкой, теперь завершился без нее.
|
||||
|
||||
В логе сообщается о 102 найденных ошибках. Это ровно на одну ошибку меньше, чем было ранее. Это не означает, что в проекте осталось 102 ошибки, только то, что, исправив данную ошибку, мы действительно что-то исправили, и теперь один из тестовых сценариев, который ранее завершался ошибкой, теперь завершился без нее.
|
||||
Помните, что если в проекте много ошибок, то часть ошибок может выправлять поведение других ошибок (хоть и не всегда, но иногда минус на минус может выдать плюс контексте ошибок проекта), поэтому надо осторожно полагаться на число найденных ошибок, если их больше нуля.
|
||||
|
||||
Посмотрим на нашу временную диаграмму снова, и выберем дальнейшие действия:
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 20. Временная диаграмма после исправления разрядности сигнала `min`._
|
||||
|
||||
Мы видим, что на временной диаграмме не осталось сигналов в X или Z-состоянии, а значит мы собрали все "низковисящие" улики нашего с вами расследования. Вернемся к месту преступления и попробуем поискать новые улики:
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 21. Первая ошибка в новом логе моделирования._
|
||||
|
||||
## Поиск ошибки в сигналах, формирующих проблемный сигнал
|
||||
|
||||
Мы видим, что первой ошибкой в логе стала не та ошибка, что была прежде. Раньше первый неверный результат мы видели в момент времени `5ns`, когда на дизайн подавались значения `0` и `0`, теперь же первой ошибкой стал момент времени `10ns`, когда на дизайн подаются значения `1` и `1`. Наше устройство считает, что результат должен равняться `3`, в то время как модель считает, что результат должен равняться `1`. Проверим, нет ли ошибки в модели и посчитаем результат самостоятельно:
|
||||
|
||||
Для определения приблизительной длины вектора в евклидовом пространстве(вычисления квадратного корня из суммы квадратов / длины гипотенузы прямоугольного треугольника) можно воспользоваться формулой:
|
||||
Для определения приблизительной длины вектора в евклидовом пространстве(вычисления квадратного корня из суммы квадратов / длины гипотенузы прямоугольного треугольника) можно воспользоваться формулой:
|
||||
|
||||
`sqrt(a^2 + b^2) ≈ max + min/2`, где `max` и `min` — большее и меньшее из пары чисел соответственно [**Ричард Лайонс: Цифровая обработка сигналов, Глава 13.2, стр. 475**].
|
||||
|
||||
Подставим наши числа в формулу (поскольку оба числа равны, не важно какое из них будет максимумом, а какое минимумом):
|
||||
@@ -206,7 +274,8 @@ vector_abs dut(
|
||||
1 + 1/2 = 1.5
|
||||
```
|
||||
|
||||
Ни модель, ни дизайн не правы?
|
||||
Ни модель, ни дизайн не правы?
|
||||
|
||||
На самом деле, наше устройство поддерживает только целочисленную арифметику, поэтому результат будет:
|
||||
|
||||
```text
|
||||
@@ -226,11 +295,15 @@ assign abs = max + min_half;
|
||||
Изучив модуль, мы понимаем, что в логике этого присваивания проблем нет, т.к. оно повторяет логику формулы `max + min/2`, складывая максимум с половиной минимума. Значит проблема в значении какого-то из этих сигналов (или обоих из них). Посчитаем значения этих сигналов самостоятельно (для сложного проекта эти значения бы посчитала модель):
|
||||
`1` и `0`.
|
||||
|
||||
Смотрим, какие значения установлены на сигналах `max` и `min_half` в момент времени `10ns`:
|
||||
Смотрим, какие значения установлены на сигналах `max` и `min_half` в момент времени `10ns`.
|
||||
|
||||

|
||||

|
||||
|
||||
Мы видим, что в момент времени `10ns` значения `max` и `min_half` изменились ак `1 -> 4` и `2 -> 8` соответственно. Нас интересуют значения `1` и `2`, т.к. в момент времени `10ns` на выходе дизайна в этот момент был установившийся результат для предыдущих значений (еще не успел посчитаться результат для новых значений).
|
||||
_Рисунок 22. Значения сигналов `max` и `min_half` в момент времени `10 ns`
|
||||
|
||||
> Обратите внимание: вы можете менять и цвета сигналов временной диаграммы через контекстное меню выделенных сигналов.
|
||||
|
||||
Мы видим, что в момент времени `10 ns` значения `max` и `min_half` изменились ак `1 -> 4` и `2 -> 8` соответственно. Нас интересуют значения `1` и `2`, т.к. в момент времени `10ns` на выходе дизайна в этот момент был установившийся результат для предыдущих значений (еще не успел посчитаться результат для новых значений).
|
||||
|
||||
Значение `max=1` совпадает с ожидаемым, в то время как `min_half=2` явно нет.
|
||||
|
||||
@@ -251,9 +324,11 @@ endmodule
|
||||
|
||||
Что делает данный модуль? Он принимает на вход значение и делит его на два. На вход данного модуля будет приходить значение минимума из нашей формулы.
|
||||
|
||||
Выход данного модуля зависит от входа `numerator` и логики сдвига влево на 1. Это значит, что проблема либо в логике, либо в значении, подаваемом на вход. Выведем сигнал `numerator` на временную диаграмму и посмотрим на его значение в момент времени `10ns`:
|
||||
Выход данного модуля зависит от входа `numerator` и логики сдвига влево на 1. Это значит, что проблема либо в логике, либо в значении, подаваемом на вход. Выведем сигнал `numerator` на временную диаграмму и посмотрим на его значение в момент времени `10ns.
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 23. Значение сигнала `numerator` в момент времени `10 ns`._
|
||||
|
||||
Мы помним, что в момент, когда дизайн начал выдавать неправильный результат, на его входы подавались числа `1` и `1`, это значит, что на вход `numerator` пришло корректное значение: минимум из этих двух чисел и правда равен `1`. Проверим логику данного модуля.
|
||||
|
||||
@@ -263,18 +338,23 @@ endmodule
|
||||
|
||||
Именно поэтому, когда мы в первый раз пытались посчитать результат "на бумаге", у нас было расхождение с моделью: когда мы делим 1 на 2, мы получаем 0.5, однако деление путем отбрасывания цифры округляет результат вниз (1/2=0, 15/10=1).
|
||||
|
||||
Как "отбросить" цифру средствами цифровой логики? Для этого используется операция сдвига вправо.
|
||||
Как "отбросить" цифру средствами цифровой логики? Для этого используется операция сдвига вправо.
|
||||
|
||||
Операция сдвига вправо в **SystemVerilog** записывается оператором `>>`. Справа от оператора указывается число "отбрасываемых цифр", в нашем случае одна. Но постойте, в логике присваивания стоит оператор `<<`. Это ошибка, исправим ее!
|
||||
|
||||
Повторяем моделирование.
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 24. Результат моделирования после исправления оператора сдвига._
|
||||
|
||||
Снова на одну ошибку меньше. Не унываем, вряд ли в проекте число ошибок больше, чем число непустых строк самого проекта. Возвращаемся к начальной ошибке:
|
||||
|
||||

|
||||

|
||||
|
||||
Мы продвинулись во времени безошибочного моделирования до `15ns`, начинаем наше расследование с начала:
|
||||
_Рисунок 25. Первая ошибка в повторном моделировании._
|
||||
|
||||
Мы продвинулись во времени безошибочного моделирования до `15 ns`, начинаем наше расследование с начала:
|
||||
|
||||
На вход дизайна подаются значения `3` и `4`, дизайн считает, что результатом вычисления `max + min/2` будет `2`, модель считает, что `5`. Посчитаем сами:
|
||||
|
||||
@@ -288,9 +368,11 @@ max + min/2 = 4 + 3/2 = 4 + 1 = 5
|
||||
|
||||
## Проблема необъявленных сигналов
|
||||
|
||||
Поскольку на временной диаграмме стало уже очень много сигналов, уберем лишние, оставив только внутренние сигналы модуля `vector_abs`:
|
||||
К этому моменту на вашей временной диаграмме скорей всего стало уже очень много сигналов. Уберем лишние, оставив только внутренние сигналы модуля `vector_abs` (для этого выделяем не нужные сигналы, и удаляем их с помощью клавиши `Delete`).
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 26. Поведение внутренних сигналов модуля `vector_abs` на временной диаграмме._
|
||||
|
||||
В глаза сразу же бросается, что сигнал `max` внешне отличается от всех остальных — он ведет себя как однобитный сигнал. Если все остальные сигналы 32-разрядные, то и сигнал `max` должен быть таким же. Перейдем к объявлению этого сигнала, чтобы это исправить (нажав правой кнопкой мыши, и выбрав `Go To Source Code`):
|
||||
|
||||
@@ -318,19 +400,26 @@ max + min/2 = 4 + 3/2 = 4 + 1 = 5
|
||||
|
||||
Для исправления этой ошибки, объявим сигнал `max` с корректной разрядностью и повторим моделирование.
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 27. Результат моделирования после объявления пропущенного сигнала._
|
||||
|
||||
## Самостоятельная работа
|
||||
|
||||
Число ошибок сократилось до 40! Мы явно на верном пути. Повторяем предыдущие шаги, вернувшись к первой ошибке:
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 28. Первая ошибка в повторном моделировании._
|
||||
|
||||
В этот раз первая ошибка осталась прежней, только теперь дизайн считает, что результат должен равняться шести (в прошлый раз дизайн выдавал `2`). Мы уже убедились, что в этом случае модель дает правильный результат, поэтому сразу перейдем к формирующим результат сигналам:
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 29. Поведение внутренних сигналов модуля `vector_abs` на временной диаграмме._
|
||||
|
||||
Видим, что значение сигнала `min_half`, формирующего значение выхода `abs` неверно (минимумом из `3` и `4` является `3`, `3/2 = 1`).
|
||||
|
||||
Видим, что значение сигнала `min_half`, формирующего значение выхода `abs` неверно (минимумом из `3` и `4` является `3`, `3/2 = 1`).
|
||||
Не отходя далеко от кассы, мы замечаем, что значение `min`, формирующее сигнал `min_half` неверно: его значение `4`, а должно быть `3`.
|
||||
|
||||
Используя [файлы исходного кода проекта](../Other/vector_abs/), попробуйте разобраться в последней обнаруженной нами ошибке.
|
||||
|
Reference in New Issue
Block a user