Перейти к содержанию
    

Схемотехнические трюки для ПЛИСоводов

да я тоже пользуюсь 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);

 

попрошу модератора, чтобы исправил исходный пост.

 

файл с изменениями:

Ring_Buffer_gnt_forward_fwft_ram_based.txt

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то все про тему забыли... :)

у меня нет времени, работы тьма тьмущая :wacko:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

src.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да-а-а-а-а,не удалось раскрутить общественность.А жаль,умирает тема...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В качестве подпитки темы сюда можно выложить Synthesis Style Guide для разных компиляторов. У меня есть Precision® Synthesis Style Guide и HDL Coding Styles от Altera.

В принципе эти документы доступны всем, но кто их читает ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да-а-а-а-а,не удалось раскрутить общественность.А жаль,умирает тема...

у мну например цейтнот последние полгода. скоро разберусь уже с делами и буду вывешивать - есть достаточно разных мелких полезностей. так что никто не забыт и ничто не забыто. просто временно отложено.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

у мну например цейтнот последние полгода. скоро разберусь уже с делами и буду вывешивать - есть достаточно разных мелких полезностей. так что никто не забыт и ничто не забыто. просто временно отложено.

Вот,вот, именно "мелкие полезности" и представляют наибольший интерес,особенно для молодёжи.Я после праздников тоже выложу ещё один блок(вычисление модуля без квадратов и корней).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот еще вариант двухклокового FIFO, на VHDL.

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, а можно просто память читать другой ширины.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот еще вариант двухклокового FIFO, на VHDL.

красиво написано, но напрягают несколько моментов :

1. полное отсутствие синхронизаторов указателей wr_clk/rd_clk

2. сомнительная производительность цепей вида fifo_size( gray2bin(wr_g_adr), rd_b_adr ) <= conv_integer(rd_ena)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

красиво написано, но напрягают несколько моментов

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если частоты независимы, то при переводе массива битов из одного частотного домена в другой возможны сильные искажения, поскольку изменения отдельных битов могут зафиксироваться в новом домене в разных тактах. Ну, к примеру, в первом домене счетчик идет по порядку 01111B, 10000B, а во втором домене может быть 01111B, 10100B, 10000B. То есть, задержка бита 2 такова, что он опаздывает на один такт, но не всегда, а лишь иногда, при неблагоприятных фазах двух частот.

 

А код Грея замечателен тем, что последовательные значения счетчика отличаются изменением только одного бита. Поэтому при переводе величины в коде Грея на новую частоту фазовые сдвиги тактовых сигналов не могут привести к ошибкам, возможно либо новое, либо старое значение величины после возврата к обычному бинарному представлению.

 

В итоге такое фифо может работать при любых соотношениях частот. Для ФИФО, работающего на одной частоте или на кратных частотах, код Грея не нужен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Итак господа, давайте попробуем достичь результата.

Выкладывать алгоритмы работы различных очередей (устройств со сложным поведением) мне кажется смысла особого нет. Есть принципиальные вещи в способах их построения, и одной из таких вещей является компонент перехода данных из одного частотного домена в другой. Давайте попробуем формализовать эту процедуру и зафиксировать результат в виде кода на VERILOG.

 

Постановка задачи:

- реализовать мост для данных (разрядность 1 бит) из одного частотного домена в другой.

- фазы частот разные, частоты отличаются в разы (например 125 МГц и 20 МГц)

- время перехода Тpd - минимальное.

 

-------

-----------------+ +---------------------------------- импульс в домене 125МГц (один такт)

 

<-----------> Тpd

--------------------------

-------------------------------+ +-------- импульс в домене 20МГц (один такт)

Шапка модуля:

 

module xdomen (

input clk1,

input din,

 

input clk2,

output dout

);

 

<здесь находится коД....>

// предлагаем свои решения....

 

endmodule

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Постановка задачи:

- реализовать мост для данных (разрядность 1 бит) из одного частотного домена в другой.

- фазы частот разные, частоты отличаются в разы (например 125 МГц и 20 МГц)

- время перехода Тpd - минимальное.

toggle_synchronizer.v

pulse_synchronizer.v

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

не нашел куда написать, а новой темы.......

где-то спрашивал, но ответа не было.

в общем, есть для примера код:

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 никак в одну строчку не укоротить?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...