torik 0 20 января, 2011 Опубликовано 20 января, 2011 · Жалоба Всем привет. Возникла такая задача: Некое устройство генерирует раз в иногда управляющее слово и сигнал записи write длительностью в один такт к нему. Это в одном клоковом домене. В другом клоковом домене есть шина авалоновская, которая должна читать это управляющее слово по сигналу read. Шина авалон выставляет сигнал чтения гораздо чаще, чем появляется новое управляющее слово. Причем при чтении регистр (? некий девайс), хранящий управляющее слово, должен сбрасываться. Это как в обычных МК, например ждем флаг завершения преобразования АЦП, который при чтении автоматически сбрасывается). Сразу же напрашивается обычное двухклоковое FIFO. Я его и поставил. Далее смотрю сигналтабом результат. Записал управляющее слово, все как надо. Читаю его раз, все норм. Следующее чтение (и все последующие) - тоже самое значение! Вроде бы должно было появиться что-то вроде 0xFF вслед за управляющим словом, не? Я что-то не так делаю или это принципиальное свойство FIFO? Вообще, какое есть более правильное решение данной проблемы? Тут имеется переход из одного клокового домена в другой, если бы мне не нужно было сбрасывать управляющее слово после чтения, я бы поставил регистр тупо и написал бы set false_patch... Однако... Приходит на ум сделать регистр с асинхронным сбросом, в качестве которого будет выступать задержанный на такт сигнал чтения, но сомнения меня одолевают в правильности такого подхода... А как реализовать FIFO самостоятельно на регистрах, без использования блоков памяти? QII10.1, Altera, Verilog (или SV) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Shtirlits 0 20 января, 2011 Опубликовано 20 января, 2011 · Жалоба А флаг empty используете ? Память совсем не обязательно использовать, скажите ядру использовать регистры. Скажите как часто должна сбоить ваша схема? Раз в сто лет, в миллиард лет? Если делать руками, то получится 2 перехода между доменами. Асинхронный сброс не поможет: при снятии сброса может прийти активный фронт клока, при активизации сброса на выходе имеет право случиться глитч. Только синхронизатор. Нужно вычислить количество регистров в цепочке при той разводке, которая получается при понуждении placer-а сделать регистры поближе, чтобы достигнуть нужной частоты сбоев. И в последнюю очередь надо задушить анализатор таймингов, чтобы не ругался. А так как толпы инженеров не могут ошибаться водка полезна стандартного ядра DualClock FIFO достаточно для надежной работы ну почти любой схемы при почти любых сочетаниях клоков. Я бы использовал готовое fifo и не парился. Ну можно исправить на регистровую реализацию, если память жалко. Синтезатор не дурак, почти все лишнее почикает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ZED 0 20 января, 2011 Опубликовано 20 января, 2011 (изменено) · Жалоба А вот так не подойдет: entity FIFO_Reg is generic(Width : integer); Port ( Data_In : in STD_LOGIC_VECTOR (Width-1 downto 0); WRITE : in STD_LOGIC; FULL : out STD_LOGIC; CLK : in STD_LOGIC; CE : in STD_LOGIC; RST : in STD_LOGIC; Dato_Out : out STD_LOGIC_VECTOR (Width-1 downto 0); READ : in STD_LOGIC; EMPTY : out STD_LOGIC:='1'); end FIFO_Reg; architecture RTL of FIFO_Reg is signal Empty_State, Empty_State_Next : std_logic:='1'; signal Data_Out_Buf, Data_Out_Next : std_logic_vector(Width-1 downto 0); begin EMPTY <= Empty_State; DO <= Data_Out_Buf; -- Sync Process -- process(CLK,nRESET) begin if RST='1' then Empty_State <= '1'; elsif rising_edge(CLK) then if CE='1' then Empty_State <= Empty_State_Next; Data_Out_Buf <= Data_Out_Next; end if; end if; end process; -- End of Sync Process -- -- Comb Process -- process(Empty_State, nWRITE, Data_In, READ, Data_Out_Buf) begin -----Default Values----- Empty_State_Next <= Empty_State; FULL <= '1'; Data_Out_Next <= Data_Out_Buf; -----Case section----- case (Empty_State) is when '1' => if WRITE='0' then FULL <= '0'; Data_Out_Next <= (others => 'X'); else Empty_State_Next <= '0'; FULL <= '0'; Data_Out_Next <= Data_In; end if; when '0' => if READ='1' then if WRITE='1' then FULL <= '0'; Data_Out_Next <= Data_In; else Empty_State_Next <= '1'; FULL <= '0'; Data_Out_Next <= (others => 'X'); end if; end if; when others=>NULL; end case; end process; end RTL; И можно последовательно подключить сколько угодно таких буферов. Изменено 20 января, 2011 пользователем ZED Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 0 20 января, 2011 Опубликовано 20 января, 2011 · Жалоба http://electronix.ru/forum/index.php?showt...st&p=831264 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vadimuzzz 0 21 января, 2011 Опубликовано 21 января, 2011 · Жалоба Сразу же напрашивается обычное двухклоковое FIFO. Я его и поставил. Далее смотрю сигналтабом результат. Записал управляющее слово, все как надо. Читаю его раз, все норм. Следующее чтение (и все последующие) - тоже самое значение! Вроде бы должно было появиться что-то вроде 0xFF вслед за управляющим словом, не? Я что-то не так делаю или это принципиальное свойство FIFO? это штатное поведение FIFO, см. http://www.altera.com/literature/ug/ug_fifo.pdf используйте флаги empty и т.п. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 21 января, 2011 Опубликовано 21 января, 2011 · Жалоба Возникла такая задача: фифо в вашей задаче вообще не нужно Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Shtirlits 0 21 января, 2011 Опубликовано 21 января, 2011 · Жалоба фифо в вашей задаче вообще не нужно Это не те роботы, которых вы ищите... А что в их задаче нужно? Какой еще готовый элемент может скрыть от пользователя тяготы перехода между клоками? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 21 января, 2011 Опубликовано 21 января, 2011 · Жалоба Второй раз даю линк, который уже дал Leka http://electronix.ru/forum/index.php?showt...mp;#entry831264 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
torik 0 21 января, 2011 Опубликовано 21 января, 2011 · Жалоба Для начала я сделал вот так: //clk1 input wrreq; //clk2 input rdreq; input read; output data; reg [31:0] fifo_contr_reg; reg read_d; //delay read signal for reset fifo_reg always @(posedge csi_avalon_clk_clk) begin read_d <= read; end //reg always @(posedge clk2 or posedge wrreq) begin //async preset (write control word from ALT2GXB) if (wrreq) begin fifo_contr_reg <= {20'd0, len, accept, crc_valid}; end else begin //sync reset after read if (read_d) fifo_contr_reg <= 0; //read from avalon else if (rdreq) data <= fifo_contr_reg; else fifo_contr_reg <= fifo_contr_reg; end end Все вроде как заработало. Но случай когда wrreq будет очень близко от rdreq очень редкий, мне его не поймать... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 21 января, 2011 Опубликовано 21 января, 2011 · Жалоба А что в их задаче нужно? почти два месяца не был на форуме, удивительно что со всеми случилось..... решение для сабжевого случая : Некое устройство генерируетраз в иногда управляющее слово и сигнал записи write длительностью в один такт к нему. Это в одном клоковом домене. В другом клоковом домене есть шина авалоновская, которая должна читать это управляющее слово по сигналу read. Шина авалон выставляет сигнал чтения гораздо чаще, чем появляется новое управляющее слово. Причем при чтении регистр (? некий девайс), хранящий управляющее слово, должен сбрасываться. module pipa (input logic iwclk, irclk, iwrite, iwdat, iread, ordat); logic write_at_wclk; logic write_at_rclk; logic wdat_latched; always_ff @(posedge iwclk) begin write_at_wclk <= iwrite; if (iwrite) wdat_latched <= iwdat; end pulse_synchronizer #( .pLENGTH ( 3 ) ) pulse_synchronizer ( .clkin ( iwclk ) , .resetin ( 1'b0 ) , .sin ( write_at_wclk ) , .clkout ( irclk ) , .resetout ( 1'b0 ) , .sout ( write_at_rclk ) ); always_ff @(posedge irclk) begin if (write_at_rclk) ordat <= wdat_latched; else if (iread) ordat <= '0; end endmodule ну и не забыть добавить set_clock_groups -exclusive -group iwclk set_clock_groups -exclusive -group irclk set_max_delay -from [get_registers {*|pipa|wdat_latched}] -to [get_registers {*|pipa|ordat}] $<Two read clock period> pulse_synchronizer.v Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
torik 0 22 января, 2011 Опубликовано 22 января, 2011 · Жалоба Очень спасибо! И не надо отсутствовать так долго на форуме.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 0 22 января, 2011 Опубликовано 22 января, 2011 · Жалоба Скажу прямо - разобраться в коде des00 за ~15 минут не смог. Прошу откликнуться тех, кто разобрался, сколько времени потратили на это - только честно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 0 22 января, 2011 Опубликовано 22 января, 2011 · Жалоба "pulse syncronizer" - может "зависнуть", если частота clkin >> clkout, и при этом частота sin >> clkout - те терять все входные импульсы после первого. Тк триггер по clkout может не поймать сброс level. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dvladim 0 23 января, 2011 Опубликовано 23 января, 2011 · Жалоба Скажу прямо - разобраться в коде des00 за ~15 минут не смог. Прошу откликнуться тех, кто разобрался, сколько времени потратили на это - только честно. 3-5 минут. На бумажке нарисовал. "pulse syncronizer" - может "зависнуть", если частота clkin >> clkout, и при этом частота sin >> clkout - те терять все входные импульсы после первого. Тк триггер по clkout может не поймать сброс level. Логично, что нужно успевать считывать слово, но задача так и была поставлена: частота чтения выше чем записи. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 0 23 января, 2011 Опубликовано 23 января, 2011 (изменено) · Жалоба Проанализировал, что именно помешало мне сходу разобраться в коде: 1) внешний модуль pulse_synchronizer визуально врезан в середину одной из двух параллельных цепочек: iwrite --> pulse_synchronizer --> write_at_wclk --> ordat iwrite --> wdat_latched --> ordat 2) выходной триггер ordat имеет два независимых входа разрешения записи: write_at_rclk --> ordat iread --> ordat Имхо, эти усложнения - излишни, после упрощения: module pipa (input logic iwclk, irclk, iwrite, iwdat, iread, ordat); logic write_at_rclk; pulse_synchronizer #(.pLENGTH( 3 )) pulse_synchronizer( .clkin ( iwclk ) , .resetin ( 1'b0 ) , .sin ( iwrite ) , .clkout ( irclk ) , .resetout ( 1'b0 ) , .sout ( write_at_rclk ) ); logic clr; always_ff @(posedge irclk) begin if (write_at_rclk) clr <= 0; else if (iread) clr <= 1; if(iread) if (clr) ordat <= 0; else ordat <= iwdat; end endmodule Изменено 23 января, 2011 пользователем Leka Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться