|
|
  |
"Схемотехнические трюки для ПЛИСоводов", создание аналога "Алгоритмические трюки для программистов" |
|
|
|
Apr 16 2011, 22:14
|

тоже уже Гуру
     
Группа: Свой
Сообщений: 2 047
Регистрация: 13-06-05
Из: Кёлн - Санкт-Петербург
Пользователь №: 5 973

|
Цитата(CaPpuCcino @ Nov 15 2010, 18:14)  да я тоже пользуюсь 2-пробельной табуляцией. именно поэтому так широко размазано и получилось. но думаю это переживабельно.
очередь с рукопожатием на обоих портах. может быть сконфигурирована на использование block RAM так и на обычной логике (в зависимости от установленного атрибута). для указателей на концы очереди использована тривиальная схема кодирования (бинарный код) так что не советую использовать в самолётах, спутниках и в районе экватора. можно только для поиграться. есть две ноги для заглядывания в будущее (может быть полезны для поддержания непрерывного потока данных интерфейсных КА).
замеры не делал, потому как там мало управляющей логики.
описание: parameterizable queue with a trivial pointer encodings can be implementer eather with on-chip Block RAM or distributed memory, subject to synthesis attribute setting of the stack memory when implemeted with a RAM block adopt the first-word-falls-through policy for zero latency immediate pop provides forward read and write grant signals for smooth operation of FSMs controlling the data-flows on both ports of the channel(queue) блин, други, я чичас чуть не поседел! ВНИМАНИЕ! выложенное фифо содержит ошибку!!!ошибка в неправильном расчёте ширины счётчиков при помощи стандартной функции $clog2() раньше два параметра рассчитывались с помощью самописной функции localparam ptr_width=number_of_bits_for_value_representation(stack_depth-1); localparam cnt_width=number_of_bits_for_value_representation(stack_depth); вот эта функция Код function int number_of_bits_for_value_representation(input int value); int temp; temp = 2; number_of_bits_for_value_representation = 1; while (temp<=value) begin number_of_bits_for_value_representation = number_of_bits_for_value_representation+1; temp = temp*2; end endfunction перед отправкой на форум я решил выпендриться и заменил расчёт этих параметров на localparam ptr_width=$clog2(stack_depth-1); localparam cnt_width=$clog2(stack_depth); и не проверив работу в симуляторе и не подумав о том, что результат будет уже другой - ширина для cnt_width на один бит меньше, чем положено представляете мои ощущения, когда я в четверг запустил систему, которая была полностью отлажена и которую я не трогал пол года. 2 дня сидел разбирался почему система перестала корректно работать. в общем звиняйте итого. чтобы правильно работало с $clog2 нужно написать вот так localparam ptr_width=$clog2(stack_depth); localparam cnt_width=$clog2(stack_depth+1); попрошу модератора, чтобы исправил исходный пост. файл с изменениями:
--------------------
И снова на арене цирка - дрессированные клоуны!! Оказываем консультации по электронике за симпу круглосуточно.
|
|
|
|
|
Apr 29 2011, 07:01
|
Местный
  
Группа: Свой
Сообщений: 375
Регистрация: 9-10-08
Из: Таганрог, Ростовская обл.
Пользователь №: 40 792

|
В качестве подпитки темы сюда можно выложить Synthesis Style Guide для разных компиляторов. У меня есть Precision® Synthesis Style Guide и HDL Coding Styles от Altera. В принципе эти документы доступны всем, но кто их читает
--------------------
Глупцы игнорируют сложность. Прагматики терпят ее. Некоторые могут избегать ее. Гении ее устраняют.
|
|
|
|
|
Jun 24 2011, 19:24
|
Знающий
   
Группа: Участник
Сообщений: 881
Регистрация: 21-03-10
Из: _// \\_
Пользователь №: 56 107

|
Вот еще вариант двухклокового FIFO, на VHDL. CODE library ieee; library ieee; use IEEE.std_logic_1164.all, IEEE.std_logic_unsigned.all, IEEE.std_logic_arith.all;
entity dc_fifo is GENERIC ( WIDTHA : integer := 8; WIDTH : integer := 8 ); PORT ( rst : in std_logic;
wr_clk: in std_logic; -- write clock wr_ena: in std_logic; -- write clock enable wr_dta: in std_logic_vector(WIDTH-1 downto 0); -- write data rd_clk: in std_logic; -- read clock rd_ena: in std_logic; -- read enable rd_dta: out std_logic_vector(WIDTH-1 downto 0); -- read data
rd_empty, rd_full, rd_half : out boolean; -- read side status wr_empty, wr_full, wr_half : out boolean -- write side status );
end dc_fifo;
architecture behavior of dc_fifo is
constant N : integer := (2**WIDTHA); constant ADR_MAX : integer := (2**WIDTHA)-1;
subtype ADDRESS is integer range 0 to ADR_MAX; subtype DATA is std_logic_vector(WIDTH-1 downto 0); type FIFO_RAM is array (0 to ADR_MAX) of DATA;
-- binary representation of addersses signal wr_b_adr : ADDRESS; signal rd_b_adr : ADDRESS; -- gray code representation of addresses signal wr_g_adr : ADDRESS; signal rd_g_adr : ADDRESS; -- next write signal signal wr_add : integer range 0 to 1; signal wr_next : ADDRESS;
signal ram : FIFO_RAM; attribute syn_ramstyle : string; attribute syn_ramstyle of ram : signal is "no_rw_check";
function bin2gray( a : ADDRESS ) return ADDRESS is variable u, v : std_logic_vector( WIDTHA-1 downto 0 ); variable b : ADDRESS; begin v := conv_std_logic_vector( a, WIDTHA ); u := v xor ('0' & v(WIDTHA-1 downto 1)); b := ADDRESS(conv_integer('0' & u)); return b; end;
function gray2bin( a : ADDRESS ) return ADDRESS is variable u, v : std_logic_vector( WIDTHA-1 downto 0 ); variable b : ADDRESS; variable x : std_logic; begin v := conv_std_logic_vector( a, WIDTHA );
for i in u'range loop x := '0'; for j in v'range loop if (j>=i) then x := x xor v(j); end if; end loop; u(i) := x; end loop;
b := ADDRESS(conv_integer('0' & u)); return b; end;
function fifo_size( w, r : ADDRESS ) return ADDRESS is constant N : integer := (2**WIDTHA); variable b : ADDRESS; begin b := (N + w - r) mod N; return b; end;
begin
wr_add <= 1 when wr_ena='1' else 0; wr_next <= ( wr_b_adr + wr_add ) mod N;
WRITE_PART:process(rst,wr_clk) begin if rst='0' then wr_b_adr <= 0; wr_g_adr <= bin2gray( 0 ); wr_empty <= true; wr_full <= false; wr_half <= false; elsif rising_edge(wr_clk) then
-- fix values. Needed for better inferring RAM block wr_b_adr <= wr_next; wr_g_adr <= bin2gray( wr_next );
wr_empty <= fifo_size( wr_b_adr, gray2bin(rd_g_adr) ) < 2; wr_full <= fifo_size( wr_b_adr, gray2bin(rd_g_adr) ) >= N-4; wr_half <= fifo_size( wr_b_adr, gray2bin(rd_g_adr) ) >= N/2;
end if; end process;
RAM_STORE:process(wr_clk) begin -- perform write, no reset dependency if rising_edge(wr_clk) then if wr_ena='1' then ram(wr_b_adr) <= wr_dta; end if; end if; end process;
READ_PART:process(rst,rd_clk) begin if rst='0' then rd_b_adr <= 0; rd_g_adr <= bin2gray( 0 ); rd_empty <= true; rd_full <= false; rd_half <= false; elsif rising_edge(rd_clk) then if rd_ena='1' then rd_b_adr <= (rd_b_adr+1) mod N; rd_g_adr <= bin2gray( (rd_b_adr+1) mod N ); end if; -- fifo status on the reader part rd_empty <= fifo_size( gray2bin(wr_g_adr), rd_b_adr ) <= conv_integer(rd_ena); rd_full <= fifo_size( gray2bin(wr_g_adr), rd_b_adr ) >= N-2; rd_half <= fifo_size( gray2bin(wr_g_adr), rd_b_adr ) >= N/2; end if; end process;
RAM_PEEK:process(rd_clk) begin -- read register for dual-port RAM inferring if rising_edge(rd_clk) then if rd_ena='1' then rd_dta <= ram(rd_b_adr); end if; end if; end process;
end behavior; Где-то еще развлекался с преобразованием ширины шины на входе и выходе. Идея такая же как у базового FIFO, только запись или чтение добавляют к одному из счетчиков не 1, а 2^n. Например, Шина PCI имеет разрядность 32 бита, а кор заточен под 8. Можно делать регистры перепаковки снаружи обычного FIFO, а можно просто память читать другой ширины.
|
|
|
|
|
Jun 25 2011, 06:07
|
Знающий
   
Группа: Участник
Сообщений: 881
Регистрация: 21-03-10
Из: _// \\_
Пользователь №: 56 107

|
Цитата красиво написано, но напрягают несколько моментов 1. не понял, о чем речь  2. вообще производительность получалась вполне приличная, во всяком случае она примерно соответствовала производительности встроенной памяти, на которой и строилось FIFO. Генерацию статусов можно при желании и поменять, увеличив задержки их формирования и подняв частотку. Например, Код fifo_size( gray2bin(wr_g_adr), rd_b_adr ) <= conv_integer(rd_ena) можно заменить на Код wr_b_adr <= gray2bin(wr_g_adr); rd_empty <= fifo_size( wr_b_adr, rd_b_adr ) <= conv_integer(rd_ena) Я вообще в этом коде делал упор на то, чтобы он синтезировался (автогенерировался блок встроенной памяти) под подобные любые семейства для Альтеры и Xilinx (Spartan-Cyclone, Virtex-Stratix). Проблема в том, что возможности блока памяти, формально выводимого из описания на VHDL, заметно урезаны по сравнению с вставкой библиотечного блока памяти, возможности которого зависят от семейства и требуют правки кода при смене платформы. А вообще, добавлю, что: Цитата(Д. Кнут) Преждевременная оптимизация — корень всех зол
Сообщение отредактировал Hoodwin - Jun 25 2011, 06:13
|
|
|
|
|
Jul 13 2011, 04:11
|
Знающий
   
Группа: Участник
Сообщений: 881
Регистрация: 21-03-10
Из: _// \\_
Пользователь №: 56 107

|
Если частоты независимы, то при переводе массива битов из одного частотного домена в другой возможны сильные искажения, поскольку изменения отдельных битов могут зафиксироваться в новом домене в разных тактах. Ну, к примеру, в первом домене счетчик идет по порядку 01111B, 10000B, а во втором домене может быть 01111B, 10100B, 10000B. То есть, задержка бита 2 такова, что он опаздывает на один такт, но не всегда, а лишь иногда, при неблагоприятных фазах двух частот.
А код Грея замечателен тем, что последовательные значения счетчика отличаются изменением только одного бита. Поэтому при переводе величины в коде Грея на новую частоту фазовые сдвиги тактовых сигналов не могут привести к ошибкам, возможно либо новое, либо старое значение величины после возврата к обычному бинарному представлению.
В итоге такое фифо может работать при любых соотношениях частот. Для ФИФО, работающего на одной частоте или на кратных частотах, код Грея не нужен.
|
|
|
|
|
Nov 22 2011, 05:23
|

к.т.н.
  
Группа: Модераторы
Сообщений: 242
Регистрация: 21-06-04
Из: Санкт–Петербург, Россия
Пользователь №: 75

|
Итак господа, давайте попробуем достичь результата. Выкладывать алгоритмы работы различных очередей (устройств со сложным поведением) мне кажется смысла особого нет. Есть принципиальные вещи в способах их построения, и одной из таких вещей является компонент перехода данных из одного частотного домена в другой. Давайте попробуем формализовать эту процедуру и зафиксировать результат в виде кода на VERILOG. Постановка задачи: - реализовать мост для данных (разрядность 1 бит) из одного частотного домена в другой. - фазы частот разные, частоты отличаются в разы (например 125 МГц и 20 МГц) - время перехода Тpd - минимальное. ------- -----------------+ +---------------------------------- импульс в домене 125МГц (один такт)
<-----------> Тpd -------------------------- -------------------------------+ +-------- импульс в домене 20МГц (один такт)
Шапка модуля: module xdomen ( input clk1, input din, input clk2, output dout ); <здесь находится коД....> // предлагаем свои решения.... endmodule
|
|
|
|
|
Dec 6 2011, 13:41
|

Местный
  
Группа: Свой
Сообщений: 235
Регистрация: 11-11-09
Пользователь №: 53 561

|
не нашел куда написать, а новой темы....... где-то спрашивал, но ответа не было. в общем, есть для примера код: Код DFFE ff0 (.d(Din[0]), .ena(ena), .clk(clk_GN), .q(iDin[0])); DFFE ff1 (.d(Din[1]), .ena(ena), .clk(clk_GN), .q(iDin[1])); DFFE ff2 (.d(Din[2]), .ena(ena), .clk(clk_GN), .q(iDin[2])); DFFE ff3 (.d(Din[3]), .ena(ena), .clk(clk_GN), .q(iDin[3])); На AHDL можно написать: Код ff[3..0]: dffe; ff.(d, ena, clk, q) = (Din[3..0], ena, clk_GN, iDin[3..0]); На SV никак в одну строчку не укоротить?
--------------------
Мы ведь работаем, чтобы жить, а не живем, чтобы работать??? ;)
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|