У меня есть реализация FIFO в Verilog, основанная на этой статье: CummingsSNUG2002SJ_FIFO
При использовании этого FIFO в качестве FIFO CDC, когда сторона чтения работала на частоте 100 МГц, а сторона записи — 8 МГц, я столкнулся с проблемой синхронизации. Обратите внимание, что проблема не воспроизводится при моделировании, будь то поведенческое, постсинтетическое или постреализация. Его можно увидеть только в отчетах о времени, предоставляемых инструментом Vivado. У меня также есть ограничение по времени для каждого такта в потоке синтеза.
Вот фрагменты кода, которые представляют интерес для вопроса:
module CDC_FIFO #(
parameter DSIZE = 28,
parameter ASIZE = 10
)(
output [DSIZE-1:0] rdata,
output wfull,
output rempty,
output r_almost_empty,
input [DSIZE-1:0] wdata,
output [ASIZE:0] wr_diff,
input winc,
input wclk,
input wrst_n,
input rinc,
input rclk,
input rrst_n
);
wire [ASIZE-1:0] waddr, raddr;
wire [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr;
localparam AWAIT_RINC = 0;
localparam AWAIT_W_TO_R = 1;
reg [ASIZE:0] rptr_save = 0;
reg [1:0] state = AWAIT_RINC;
reg r_to_w = 0;
wire w_to_r;
always @(posedge rclk) begin
case (state)
AWAIT_RINC: begin
if (rinc && !w_to_r) begin
state <= AWAIT_W_TO_R;
r_to_w <= 1;
rptr_save <= rptr;
end
else begin
r_to_w <= 0;
end
end
AWAIT_W_TO_R: begin
if (w_to_r) begin
state <= AWAIT_RINC;
r_to_w <= 0;
end
end
default: ;
endcase
end
sync_r2w #(.ADDRSIZE(ASIZE)) sync_r2w
(
.r_to_w(r_to_w),
.w_to_r(w_to_r),
.wq2_rptr(wq2_rptr),
.rptr(rptr_save),
.wclk(wclk),
.wrst_n(wrst_n)
);
// Other instantiations of other modules
endmodule;
module sync_r2w #(
parameter ADDRSIZE = 4
)(
output reg w_to_r = 0,
input r_to_w,
output [ADDRSIZE:0] wq2_rptr,
input [ADDRSIZE:0] rptr,
input wclk, wrst_n
);
reg [ADDRSIZE:0] wq1_rptr = 0;
reg [ADDRSIZE:0] wq2_rptr_reg = 0;
assign wq2_rptr = wq2_rptr_reg;
always @(posedge wclk)
begin
if (!wrst_n)
begin
{ wq2_rptr_reg,wq1_rptr} <= 0;
end
else
begin
if (w_to_r || r_to_w) begin
{ wq2_rptr_reg,wq1_rptr} <= {wq1_rptr,rptr};
end
end
end
always @(posedge wclk) begin
if (!wrst_n) begin
w_to_r <= 0;
end
else begin
w_to_r <= r_to_w;
end
end
endmodule
Проблема возникает, когда указатель чтения необходимо передать в домен записи через модуль sync_r2w. Поэтому я добавил конечный автомат в CDC_FIFO, чтобы инициировать своего рода рукопожатие между ними, чтобы быть уверенным, что rptr_save удерживает свое значение достаточно долго, чтобы сторона записи могла его обработать. Однако, похоже, это не решило мою проблему.
Вот фотография критического пути, который в данный момент терпит неудачу (один из битов rptr_save)
В чем именно проблема в моей логике, которая до сих пор не фиксирует тайминг? Мне кажется, что текущий FSM в основном ждет, пока сторона записи подтвердит, что она действительно приняла значение rptr_save, а затем «отключает» условие установления связи, чтобы предотвратить дальнейшее обновление.
Спасибо





Временные ограничения используются инструментом Timing Analyser, а не симуляцией. Моделирование с обратной аннотацией работает как аппаратное обеспечение, используя время установки и удержания для создания выходных данных волн/симулятора. При моделировании RTL используется модель моделирования планировщика событий Verilog. Вы не увидите никакого влияния временных ограничений при моделировании.
Анализатор времени Vivado не знает о поведении вашей логики. Он знает задержки через примитивы Xilinx, такие как срезы, LUT, провода, буферы. clk2out задержка регистров и выходов ОЗУ (не полный список, вы поняли). Задержки от одного домена к другому не имеют особого смысла с точки зрения анализа. Анализатор синхронизации не знает, что вы поместили в этот путь хороший FIFO, обрабатывающий CDC, с двумя тактовыми сигналами и двумя ограничениями.
По умолчанию анализатор синхронизации определяет время между каждым путем и любым другим путем во всех доменах тактовой частоты, имеющих ограничение. Если у вас есть пути, пересекающие домены, инструмент покажет этот путь как неверный. Целью этого является показать пользователю: «Эй, вы пересекли тактовые домены». Если вы позаботились о разработке логики, которая обрабатывает CDC (например, CDC, обрабатывающий FIYO от Каммингса), то сообщаемый путь можно игнорировать, поскольку вы обработали CDC. Основная цель статического временного анализа имеет смысл только в пределах одной и той же тактовой области.
Обычно анализатор времени используется для суммирования задержек на всех путях от регистра к регистру в тактовой области (выполняется для всех тактовых доменов). Если задержка пути короче периода тактов, путь проходит успешно, в противном случае он терпит неудачу.
Что делать Несколько вариантов
Щелкните правой кнопкой мыши по ошибочному пути в инструменте «Анализ времени» и выполните «Установить ложный путь», сохраните ложный путь в том же файле ограничений, в котором находятся ограничения часов. Запустите инструменты еще раз, и путь не будет помечен как ошибка. Могут появиться дополнительные пути. Сделайте то же самое с ними, если вы уверены, что соответствующая логика RTL обрабатывает CDC.
Создайте ограничение максимальной задержки. Это поддерживает некоторую связь между двумя доменами, так что логика для обеих сторон FiFO оказывается рядом с другой в проекте. Рекомендации здесь async-fifos-как-мы-можем-эффективно-сделать-и-ограничить-их и здесь Какие ограничения нужны
Более общий подход — установить асинхронные группы часов Как, когда зачем устанавливать асинхронные группы часов. Если этой ссылки недостаточно, найдите дополнительную информацию по запросу «установить асинхронные группы часов».
На этой странице Xilinx рекомендуется установить асинхронные группы часов установить асинхронные группы часов.
Вот раздел в контексте
set_clock_groups -asynchronous -group {xilinx_jtag_tck}
set_clock_groups -asynchronous -group {clkA PLL1_c0 PLL1_c1 }
set_clock_groups -asynchronous -group {clkB PLL2_c0 PLL2_c1 }
set_clock_groups -asynchronous -group {dsp_clk PLL3_c0 PLL3_c1 PLL3_c2}
In general, it is recommended to add all clocks to the group.
Exceptions are:
1) DDR and GXB designs, where there are a large number of clocks added to the design that the user does not know about.
95% of these clocks have paths only to domains that are relevant or are cut in the .xdc files that get created, so they do not need to be taken into consideration.
2) Virtual clocks are recommended for all I/O interfaces (except for source-synch outputs).
Virtual clocks are not added here because the only paths they connect to are I/O's that are explicitly designated and they tend to only have real paths.
If they are added, it will not cause any issues.
Refer to (UG903) Vivado Design Suite User Guide: Using Constraints for more information.
Xilinx называет процесс настройки ограничений для нового дизайна «базовым планированием». Объяснение можно найти здесь Базовое определение дизайна
Альтернативное решение Используйте каталог IP-адресов Xilinx для создания FIFO CDC. Указанная проблема не возникнет, поскольку IP-адрес Xilinx содержит ложные пути или пути max_delay, где это необходимо. IP Catalog также создает имитационную модель, которую можно использовать для моделирования RTL. Не обязательно рекомендовать это; это что-то еще, что вы могли бы сделать. Разработка собственного проекта и использование Xilinx IP имеют свои недостатки.
Спасибо большое за такой подробный ответ! Я действительно знал о решении с установкой ложного пути, однако мне казалось, что это «грязный обходной путь»… как я могу быть абсолютно уверен, что CDC работает правильно? Я думал, что инструмент на самом деле способен подчеркнуть, что это не так и что моя логика, похоже, не работает должным образом.
Мне также, вероятно, следует установить (* ASYNC_REG = "TRUE" *) на обоих моих синхронизаторах (запись/чтение, чтение/запись). Похоже, что инструмент все еще не видит, что эти атрибуты установлены (получает предупреждения).
Добавлено больше возможностей для ограничений и ссылок. Асинхронная проверка FIFO выходит за рамки этого вопроса уже давно. Если вы не уверены в IP-адресе и не поддерживается его владельцем, рассмотрите возможность использования IP-адреса Xilinx.
Точнее, существует ограничение для adc_clk, которое является внешним и имеет частоту 8 МГц, а внутренняя тактовая частота — это clock_fpga_0, которая фактически поступает из ZYNQ.