Как стать автором
Обновить

Комментарии 12

  1. использование блокирующих присваиваний (=) в последовательностном блоке (always @(posedge clk)) является некорректным;
  2. у производителей ПЛИС есть рекомендации на тему использования синхронного/асинхронного ресета и его уровня, следовать им — хороший тон;
  3. почитайте про inferred ram, inferred rom и функции readmemh, readmemb — с помощью этого можно избежать "зашивания" данных (lut[0] = ...) в код
Большое спасибо за замечания, обязательно исправлю и учту. Про блочную память слышал, просто в этом случае хотелось написать универсальное решение, которое на зависело бы от выбора производителя и модели ПЛИС, поэтому и пришлось прибегнуть к такому решению. Также не совсем было понятно, поддерживает ли IVerilog мегафункции как, например в Xilinx ISE.

Для использования inferred ram/rom не нужно явно инстанцировать какую-то IP или мегафункцию. Средства симуляции и синтеза успешно распознают написанную определенным образом Verilog-конструкцию и сами добавляют "вместо нее" блочную память (к слову, это же справедливо для умножителей, DSP-блоков, буферов и т.д.). Для Vivado см. UG901, раздел "RAM HDL Coding Guidelines", для Quartus: Quartus Handbook, раздел "Inferring Memory Functions from HDL Code".
Примеры можно посмотреть вот здесь: интерфейс Quartus — Create New File, Verilog; меню Edit -> Insert Template.
Там есть небольшие различия: какой-то код может синтезится в блокрам для квартуса, но при этом собираться на лутах под вивадой, либо наоборот. Но чаще всего можно прийти к общему знаменателю.
Еще примеры: раз, два.

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

См. Харрис&Харрис, раздел 4.5.4 "Блокирующие и неблокирующие присваивания". Приведены примеры, почему не стоит использовать блокирующие присваивания в последовательностной логике, и неблокирующие в комбинационной. В одном случае это может привести к некорректному синтезу, а в другом — к замедлению симуляции

Стандартный оператор «for» уже подразумевает использование блокирующего присваивания (переменной цикла) в последовательном блоке.
Пример — поиск старшей «1» в векторе:
always @(posedge clk) begin n<=-1; for(int i=0; i<N; i++) if(a[i]) n<=i; end
Другой пример — локальные переменные, объявленные внутри последовательного блока, и которые принимают результаты промежуточных вычислений:
alvays@(posedge clk) begin
var [7:0] a;

a = …;

end
Спасибо за статью.
Правильно ли я понял, что разрешающая способность по фазе — всего 64 точки за четверть периода?
Не удалось ли оценить, не даст ли это больше шума квантования, чем разрешение ЦАП (8 бит)?
Спасибо за комментарий. Да, верно. С одной оговоркой, что это — максимальная разрешающая способность для минимальной частоты сигнала на выходе. С ростом частоты аккумулятор фазы будет накапливаться всё быстрее, поэтому количество точек на период становится меньше, соответственно разрешающая способность тоже падает (сигнал на последнем рисунке меньше похож на синус и спектр его будет не идеальной «палкой» на частоте синуса). Возможно, неидеальность сигнала вследствие малого разрешения — это тот шум, о котором вы говорите, но не следует путать его с шумом квантования.
Параметры шума квантования определяются только разрядностью ЦАП, дисперсия = q^2/12, мат. ожидание = q/2, где q — шаг квантования (q=A/2^N), A — максимум напряжения, N — разрядность ЦАП.
ROM можно инициализировать при объявлении (удобно использовать «упакованные» массивы из SV):
reg [LUT_SIZE-1:0][6:0] lut = {7'h7F, 7'h7E,… 7'h03, 7'h00};
Насколько я помню это работает только для симуляций.
Хорошо. Для FPGA я очень давно не синтезировал.
Я думаю, что вот это будет работать для всех:
wire [LUT_SIZE-1:0][6:0] lut = {7'h7F, 7'h7E,… 7'h03, 7'h00};
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории