В ветке комментариев об ответе на этот вопрос: Неправильные выводы в сущности VHDL было указано:
«С целыми числами у вас нет контроля или доступа к внутреннему логическому представлению в FPGA, в то время как SLV позволяет вам делать такие трюки, как эффективное использование цепи переноса».
Итак, при каких обстоятельствах вы обнаружили, что лучше кодировать, используя вектор представления битов, чем использовать целые числа s для доступа к внутреннему представлению? И какие преимущества вы измерили (с точки зрения площади чипа, тактовой частоты, задержки или иным образом)?
Ответы:
Я написал код, предложенный двумя другими авторами, как в форме, так
vector
и вinteger
форме, заботясь о том, чтобы обе версии работали как можно более одинаково.Я сравнил результаты моделирования и затем синтезировал их, используя Synplify Pro для Xilinx Spartan 6. Приведенные ниже примеры кода вставлены из рабочего кода, поэтому вы сможете использовать их с вашим любимым синтезатором и посмотреть, будет ли он вести себя так же.
Downcounters
Во-первых, downcounter, как предположил Дэвид Кесснер:
Векторная архитектура:
Целочисленная архитектура
Результаты
С точки зрения кода, целое число кажется мне более предпочтительным, поскольку оно позволяет избежать
to_unsigned()
вызовов. В противном случае не так много, чтобы выбрать.Запуск через Synplify Pro с
top := 16#7fff_fffe#
производительностью 66 LUT дляvector
версии и 64 LUT дляinteger
версии. Обе версии широко используют цепь для переноски. Обе тактовые частоты превышают 280 МГц . Синтезатор вполне способен наладить правильное использование цепи переноса - я визуально проверил с помощью средства просмотра RTL, что аналогичная логика создается с обоими. Очевидно, что счетчик с компаратором будет больше, но это будет то же самое и с целыми числами, и с векторами снова.Деление на 2 ** n счетчиков
Предложил ajs410:
Векторная архитектура
Целочисленная архитектура
Вы должны перепрыгнуть через несколько обручей, чтобы избежать просто использования,
to_unsigned
а затем выбирать биты, что явно даст тот же эффект, что и выше:Результаты
С точки зрения кода, в этом случае
vector
версия явно лучше!Что касается результатов синтеза, то для этого небольшого примера целочисленная версия (как и предсказывал ajs410) действительно производит 3 дополнительных LUT как часть компараторов, я был слишком оптимистичен в отношении синтезатора, хотя он работает с ужасно запутанным фрагментом кода!
Другое использование
Векторы - это явный выигрыш, если вы хотите, чтобы арифметика была развернута (счетчики могут быть выполнены даже одной строкой):
против
хотя по крайней мере из этого кода ясно, что автор намеревался обернуться вокруг.
Что-то, чего я не использовал в реальном коде, но задумался:
Функция «естественного обертывания» также может быть использована для «вычислений через переполнения». Когда вы знаете, что выходные данные цепочки сложений / вычитаний и умножений ограничены, вам не нужно хранить старшие биты промежуточных вычислений, поскольку (в дополнении к 2-м) они получатся «в стирке» к тому времени, как вы доберетесь до выхода. Мне сказали, что этот документ содержит доказательство этого, но я выглядел немного глупо, чтобы быстро оценить! Теория компьютерного сложения и переполнения - HL Garner
Использование
integer
s в этой ситуации приведет к ошибкам симуляции при их переносе, даже если мы знаем, что в конце они развернутся.И, как отметил Филипп, когда вам нужно число больше 2 ** 31, у вас нет выбора, кроме как использовать векторы.
источник
variable c : unsigned(32 downto 0);
... неc
33-битная переменная тогда?При написании VHDL я настоятельно рекомендую использовать std_logic_vector (slv) вместо integer (int) для СИГНАЛОВ . (С другой стороны, использование int для обобщений, некоторых констант и некоторых переменных может быть очень полезным.) Проще говоря, если вы объявляете сигнал типа int или вам нужно указать диапазон для целого числа, то вы, вероятно, делаете что-то не так.
Проблема с int в том, что VHDL-программист понятия не имеет, что такое внутреннее логическое представление int, и поэтому мы не можем этим воспользоваться. Например, если я определяю int в диапазоне от 1 до 10, я понятия не имею, как компилятор кодирует эти значения. Надеюсь, это будет закодировано как 4 бита, но мы не знаем много за этим. Если бы вы могли исследовать сигналы внутри ПЛИС, это могло бы быть закодировано от «0001» до «1010» или от «0000» до «1001». Также возможно, что он закодирован таким образом, который не имеет никакого смысла для нас, людей.
Вместо этого мы должны просто использовать slv вместо int, потому что тогда у нас есть контроль над кодированием, а также прямой доступ к отдельным битам. Прямой доступ важен, как вы увидите позже.
Мы могли бы просто приводить int к slv всякий раз, когда нам нужен доступ к отдельным битам, но это становится действительно грязным, очень быстрым. Это как получить худшее из обоих миров вместо лучшего из обоих. Ваш код будет трудно оптимизировать для компилятора и почти невозможно прочитать. Я не рекомендую это.
Итак, как я уже сказал, с SLV вы можете контролировать кодирование битов и прямой доступ к битам. Так что вы можете сделать с этим? Я покажу вам пару примеров. Допустим, вам нужно выводить импульс один раз каждые 4 294 000 000 часов. Вот как бы вы сделали это с помощью int:
И тот же код, используя slv:
Большая часть этого кода идентична между int и slv, по крайней мере, в смысле размера и скорости результирующей логики. Конечно, один считает, а другой считает, но это не важно для этого примера.
Разница в «важной линии».
В примере с int это приведет к компаратору с 32 входами. С LUT с 4 входами, которые использует Xilinx Spartan-3, для этого потребуется 11 LUT и 3 уровня логики. Некоторые компиляторы могут преобразовать это в вычитание, которое будет использовать цепочку переноса и охватывать эквивалент 32 LUT, но может работать быстрее, чем 3 уровня логики.
В примере с slv нет 32-битного сравнения, так что это «ноль LUT, ноль уровней логики». Единственным штрафом является то, что наш счетчик - это один дополнительный бит. Поскольку дополнительная синхронизация для этого дополнительного бита счетчика находится в цепочке переноса, дополнительная задержка синхронизации "почти равна нулю".
Конечно, это крайний пример, так как большинство людей не будут использовать 32-битный счетчик таким образом. Это относится к меньшим счетчикам, но разница будет менее существенной, но все же существенной.
Это только один пример того, как использовать slv через int для ускорения синхронизации. Есть много других способов использовать slv - это только воображение.
Обновление: добавлен материал для учета комментариев Мартина Томпсона об использовании int с "if (count-1) <0"
(Примечание: я предполагаю, что вы имели в виду «if count <0», поскольку это сделало бы его более эквивалентным моей версии slv и избавило бы от необходимости этого дополнительного вычитания.)
При некоторых обстоятельствах это может генерировать предполагаемую реализацию логики, но не гарантируется, что она будет работать постоянно. Это будет зависеть от вашего кода и от того, как ваш компилятор кодирует значение int.
В зависимости от вашего компилятора и от того, как вы указываете диапазон вашего int, вполне возможно, что нулевое значение int не кодирует битовый вектор «0000 ... 0000», когда оно попадает в логику FPGA. Чтобы ваш вариант работал, он должен кодироваться как «0000 ... 0000».
Например, допустим, вы определили int для диапазона от -5 до +5. Вы ожидаете, что значение 0 будет закодировано в 4 бита, таких как «0000», и +5 как «0101» и -5 как «1011». Это типичная схема кодирования с двумя дополнениями.
Но не думайте, что компилятор будет использовать два дополнения. Хотя это и необычно, комплимент может привести к «лучшей» логике. Или компилятор может использовать своего рода «смещенную» кодировку, где -5 кодируется как «0000», 0 - как «0101», а +5 - как «1010».
Если кодировка int является «правильной», то компилятор, скорее всего, определит, что делать с битом переноса. Но если это неверно, то полученная логика будет ужасной.
Возможно, что использование int таким способом может привести к разумному размеру и скорости логики, но это не гарантия. Переключение на другой компилятор (например, с XST на Synopsis) или переход на другую архитектуру ПЛИС может привести к неправильным результатам.
Unsigned / Signed vs. slv - это еще одна дискуссия. Вы можете поблагодарить правительственный комитет США за предоставленную нам возможность выбора в VHDL. :) Я использую slv, потому что это стандарт взаимодействия модулей и ядер. Кроме этого, и некоторых других случаев в симуляциях, я не думаю, что есть огромное преимущество в использовании slv по сравнению с подписанным / неподписанным. Я также не уверен, поддерживают ли подписанные / неподписанные сигналы поддержки три заявленные.
источник
if (count-1) < 0
я думаю, что синтезатор выведет бит выполнения и выдаст ту же схему, что и в вашем примере slv. Кроме того, не должны ли мы использоватьunsigned
тип в эти дни :)Мой совет: попробуйте оба варианта, а затем посмотрите на сводные, картографические и маршрутные отчеты. Эти отчеты точно подскажут, сколько LUT потребляет каждый подход, а также максимальную скорость, с которой может работать логика.
Я согласен с Дэвидом Кесснером, что вы находитесь во власти своего набора инструментов, и нет «правильного» ответа. Синтез - это чёрная магия, и лучший способ узнать, что произошло, - это внимательно и тщательно прочитать подготовленные отчеты. Инструменты Xilinx позволяют даже видеть внутри ПЛИС, вплоть до того, как запрограммирована каждая LUT, как соединена цепь переноса, как коммутационная матрица соединяет все LUT и т. Д.
Для другого драматического примера подхода г-на Кесснера представьте, что вы хотите иметь несколько тактовых частот на 1/2, 1/4, 1/8, 1/16 и т. Д. Вы можете использовать целое число, которое постоянно подсчитывает каждый цикл, и затем иметь несколько компараторов по отношению к этому целочисленному значению, при этом каждый выход компаратора формирует различное тактовое деление. В зависимости от количества компараторов разветвление может стать неоправданно большим и начать потреблять дополнительные LUT только для буферизации. Подход SLV будет просто принимать каждый отдельный бит вектора в качестве вывода.
источник
Одной из очевидных причин является то, что знаковые и беззнаковые допускают большие значения, чем 32-разрядное целое число. Это недостаток в дизайне языка VHDL, который не является существенным. Новая версия VHDL может исправить это, требуя целочисленных значений для поддержки произвольного размера (сродни BigInt в Java).
Кроме того, мне очень интересно услышать о тестах, которые по-разному работают для целых чисел по сравнению с векторами.
Кстати, Ян Decaluwe написал хорошее эссе об этом: эти Ints сделаны для Countin '
источник