Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: "Схемотехнические трюки для ПЛИСоводов"
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
Страницы: 1, 2, 3, 4, 5
Maverick
Цитата(BSV @ Nov 18 2010, 15:47) *
У хилых есть еще иксаппы по теме ФИФО. Я их код причесал и параметризовал. Если интересно, могу выложить.

P.S. VHDL.

интересно...выкладывайте
Мур
http://www.kit-e.ru/archive.php
Здесь интересна статья Ильи Тарасова в номерах
2008_01_88.pdf
2008_3_90.pdf
Скачивайте!
Мур
Цитата(Мур @ Jan 19 2011, 17:47) *
http://www.kit-e.ru/archive.php
Здесь интересна статья Ильи Тарасова в номерах
2008_01_88.pdf
2008_3_90.pdf
Скачивайте!

2008_01_88.pdf тут!
http://electronix.ru/forum/index.php?s=&am...st&p=908188
ReAl
Цитата(dmitry-tomsk @ Nov 18 2010, 19:17) *
через сравнение адресов? Так ведь lfsr это не грей, между клоковыми доменами его так просто не перетащишь. Поделитесь кодом!

Так навскидку, пардон, если в ночи фигню спорол -- а если между доменами тащить однобитовую отмашку факта обращения и уже на том конце в дубликате LFSR отрабатывать адрес для сравнния?
des333
Что-то все про тему забыли... sm.gif
CaPpuCcino
Цитата(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);

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

файл с изменениями:
des00
Цитата(des333 @ Apr 13 2011, 05:30) *
Что-то все про тему забыли... sm.gif

у меня нет времени, работы тьма тьмущая wacko.gif
_Anatoliy
В схемах автоматики часто применяются интеграторы,здесь пример параметризуемого знакового интегратора с насыщением.Схема очень простая,пояснений не требуется.
_Anatoliy
Да-а-а-а-а,не удалось раскрутить общественность.А жаль,умирает тема...
warrior-2001
В качестве подпитки темы сюда можно выложить Synthesis Style Guide для разных компиляторов. У меня есть Precision® Synthesis Style Guide и HDL Coding Styles от Altera.
В принципе эти документы доступны всем, но кто их читает wink.gif
CaPpuCcino
Цитата(_Anatoliy @ Apr 29 2011, 07:54) *
Да-а-а-а-а,не удалось раскрутить общественность.А жаль,умирает тема...

у мну например цейтнот последние полгода. скоро разберусь уже с делами и буду вывешивать - есть достаточно разных мелких полезностей. так что никто не забыт и ничто не забыто. просто временно отложено.
_Anatoliy
Цитата(CaPpuCcino @ May 2 2011, 12:04) *
у мну например цейтнот последние полгода. скоро разберусь уже с делами и буду вывешивать - есть достаточно разных мелких полезностей. так что никто не забыт и ничто не забыто. просто временно отложено.

Вот,вот, именно "мелкие полезности" и представляют наибольший интерес,особенно для молодёжи.Я после праздников тоже выложу ещё один блок(вычисление модуля без квадратов и корней).
Hoodwin
Вот еще вариант двухклокового 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, а можно просто память читать другой ширины.
des00
Цитата(Hoodwin @ Jun 24 2011, 14:24) *
Вот еще вариант двухклокового FIFO, на VHDL.

красиво написано, но напрягают несколько моментов :
1. полное отсутствие синхронизаторов указателей wr_clk/rd_clk
2. сомнительная производительность цепей вида fifo_size( gray2bin(wr_g_adr), rd_b_adr ) <= conv_integer(rd_ena)
Hoodwin
Цитата
красиво написано, но напрягают несколько моментов

1. не понял, о чем речь sm.gif
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, заметно урезаны по сравнению с вставкой библиотечного блока памяти, возможности которого зависят от семейства и требуют правки кода при смене платформы.

А вообще, добавлю, что:
Цитата(Д. Кнут)
Преждевременная оптимизация — корень всех зол
gosu-art
А не просветите... зачем в ФИФО используется код Грея?
Hoodwin
Если частоты независимы, то при переводе массива битов из одного частотного домена в другой возможны сильные искажения, поскольку изменения отдельных битов могут зафиксироваться в новом домене в разных тактах. Ну, к примеру, в первом домене счетчик идет по порядку 01111B, 10000B, а во втором домене может быть 01111B, 10100B, 10000B. То есть, задержка бита 2 такова, что он опаздывает на один такт, но не всегда, а лишь иногда, при неблагоприятных фазах двух частот.

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

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

Постановка задачи:
- реализовать мост для данных (разрядность 1 бит) из одного частотного домена в другой.
- фазы частот разные, частоты отличаются в разы (например 125 МГц и 20 МГц)
- время перехода Тpd - минимальное.


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

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

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

module xdomen (
input clk1,
input din,

input clk2,
output dout
);

<здесь находится коД....>
// предлагаем свои решения....

endmodule
des00
Цитата(aosp @ Nov 22 2011, 00:23) *
Постановка задачи:
- реализовать мост для данных (разрядность 1 бит) из одного частотного домена в другой.
- фазы частот разные, частоты отличаются в разы (например 125 МГц и 20 МГц)
- время перехода Тpd - минимальное.

stu
не нашел куда написать, а новой темы.......
где-то спрашивал, но ответа не было.
в общем, есть для примера код:
Код
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 никак в одну строчку не укоротить?
Postoroniy_V
Цитата(stu @ Dec 6 2011, 22:41) *
не нашел куда написать, а новой темы.......
.На AHDL можно написать:
Код
ff[3..0]: dffe;
ff.(d, ena, clk, q) = (Din[3..0], ena, clk_GN, iDin[3..0]);

На SV никак в одну строчку не укоротить?

Код
DFFE ff_all[3:0] (.d(Din), .ena(ena), .clk(clk_GN), .q(iDin));

ключевыe слова поиска - verilog array of instance
первое что нашёл
http://dropzone.tamu.edu/~lwang/ee468/slides/lec03.pdf
gosu-art
У меня такая проблемка возникла.
Есть 32х.р. счетчик, который никогда не останавливается:

Код
always_ff@(posedge adc_mclk_mux or negedge rst_i) begin 27,648 MHz
    if (!rst_i) counter<='0;
    else if (!TRIG3_stb && TRIG3_rg_n)   counter<=32'd0; //start condition
    else counter<=counter+1'b1;
end

На другой стороне процессор с 16р шиной (clk~49 MHz ), который должен прочитать "грамотно" за два обращения текущее значение данного счетчика.
Понятное дело если его просто так читать, то получается полная каша. Ставлю защелку:
Код
always_ff@(negedge adc_mclk_mux or negedge rst_i) begin
    if (!rst_i) cnt_rg_HADC<='0;
        else if (!ff_hold) cnt_rg_HADC<=counter;
end


И, собственно, управление защелкой(LRD стоит 2 такта clk_i). Вначале читается старшее, потом младшее слово:
Код
always_ff@(posedge clk_i or negedge rst_i) begin
    if (!rst_i) fHold_value<='0;
        else if (!IOMS && !LRD) begin
                  if         (LA==pIOMS_ADC_CTRL_CNTR_L)    fHold_value<='0; //LSB      
                  else if    (LA==pIOMS_PXI_MUX_CNTR_H)      fHold_value<='1; //MSB        
        end                                         
end


always_ff@(negedge adc_mclk_mux or negedge rst_i) begin//posedge
if (!rst_i)  ff_hold<='0;
else if ( fHold_value && IOMS)  ff_hold<='1;
else if (!fHold_value && IOMS)  ff_hold<='0;

end


при таком раскладе получается, что холдится только младшее слово. Итог:
Нажмите для просмотра прикрепленного файла
В принципе устраивает. Но может как то грамотней можно сделать?
stu
Цитата(Postoroniy_V @ Dec 6 2011, 17:18) *
Код
DFFE ff_all[3:0] (.d(Din), .ena(ena), .clk(clk_GN), .q(iDin));


У меня выдает
Цитата
Error (10253): Verilog HDL Module Instantiation error at tx_8b_10b.sv(82): cannot elaborate array of instances because the declaration for the instantiated module has not been analyzed

не пойму, он дополнительно объявление требует или что?
sazh
Цитата(stu @ Dec 7 2011, 09:02) *
не пойму, он дополнительно объявление требует или что?


При переходе с AHDL на verilog без схемотехнических трюков не обойтись.
Код
reg [3:0] dffe_rg = 4'h0;

always @(posedge clk_GN)
begin
if (ena)        dffe_rg  <= Din
end
maksimp
Цитата(stu @ Dec 7 2011, 09:02) *
У меня выдает
Error (10253): Verilog HDL Module Instantiation error at tx_8b_10b.sv(82): cannot elaborate array of instances because the declaration for the instantiated module has not been analyzed
не пойму, он дополнительно объявление требует или что?

Нужно сделать свой модуль - обёртку для DFFE, и его уже можно будет вставить сразу массивом.
Например для LCELL:
Код
module lc(input in, output out);
  LCELL l (.in(in), .out(out));
endmodule

и потом
Код
wire [7:0] p, q;
lc lcq[7:0] (p, q);

Для DFFE нужно аналогично
stu
2 sazh & maksimp такие методы я понимаю. но это о5 многа букав. хотел в одну строку. как в http://electronix.ru/redirect.php?http://d...lides/lec03.pdf
хотя код ниже приемлим =)
Код
always_ff @ (posedge clk)
    if (ena) iDin <= Din;
sazh
Цитата(stu @ Dec 7 2011, 09:36) *
хотел в одну строку


Так ведь никто не поймет, что Вы наваяли.
Egor-ka
Здравствуйте, уважаемые ПЛИСоводы.
Раз уж тут обсуждаются трюки на плис, Решил написать свою задачу

Кто-нибудь пробовал использовать аналоговые свойства плис? Например, как ацп с помощью компаратора портов LVDS, формирование импульсов с точность меньше периода макс. тактовой частоты с помощью линии задержки.
Сейчас пытаюсь сделать задержку сигнала с точностью меньше периода, в симуляторе получается, а в железе нет, хотя уже замучился вручную ячейки расставлять и времена распространения сигналов подбирать.

Кто-то встречался с такими задачами?

Спасибо.
maksimp
Цитата(Egor-ka @ Dec 7 2011, 16:08) *
формирование импульсов с точность меньше периода макс. тактовой частоты с помощью линии задержки.
Сейчас пытаюсь сделать задержку сигнала с точностью меньше периода, в симуляторе получается, а в железе нет, хотя уже замучился вручную ячейки расставлять и времена распространения сигналов подбирать.

Посмотрите здесь
http://www.alteraforum.com/forum/showthrea...2133&page=2
и там по ссылкам.
А вообще искать "delay" на alteraforum.com .
Egor-ka
Цитата(maksimp @ Dec 8 2011, 10:21) *
Посмотрите здесь
http://www.alteraforum.com/forum/showthrea...2133&page=2
и там по ссылкам.
А вообще искать "delay" на alteraforum.com .


Спасибо, изучаю.

Думал, может, кто-то из отечественных плисоводов это делал...
ZED
Вот решил написать свой вариант FIFO-буфера, правда я его в кристалле не тестировал. Прошу покритиковать.
CODE
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity FIFO is
generic (Addr_Size : natural := 3; -- Разрядность адреса (глубина FIFO)
Data_Size : natural := 32); -- Разрядность данных
port (RST : in std_logic; -- Сброс
CLK_WR : in std_logic; -- Тактовый сигнал для записи
WE : in std_logic; -- Разрешение записи (Write Enable)
Data_WR : in std_logic_vector(Data_Size - 1 downto 0); -- Данные, записываемые в буфер
CLK_RD : in std_logic; -- Тактовый сигнал для чтения
RE : in std_logic; -- Разрешение чтения (Read Enable)
Data_RD : out std_logic_vector(Data_Size - 1 downto 0); -- Данные, читаемые из буфера
Full : out std_logic; -- Флаг того, что буфер полон
Empty : out std_logic); -- Флаг того, что буфер пуст
end entity FIFO;


architecture RTL of FIFO is

type FIFO_RAM_Type is array (0 to 2**Addr_Size - 1) of std_logic_vector(Data_Size - 1 downto 0);
signal FIFO_RAM : FIFO_RAM_Type;

--================================================================================
================================================--
-- Функция преобразования из двоичного кода в код Грея: --
--================================================================================
================================================--
function Bin_to_Gray (D: unsigned) return unsigned is
variable Q : unsigned(D'range);
begin
Q := ('0' & D(D'high downto 1)) xor D;
return Q;
end function Bin_to_Gray;
--================================================================================
================================================--


--================================================================================
================================================--
-- Функция преобразования кода Грея в двоичный код: --
--================================================================================
================================================--
function Gray_to_Bin (D: in unsigned) return unsigned is
variable Q: unsigned(D'high downto D'low);
begin
Q(D'high) := D(D'high);
for i in D'high - 1 downto D'low loop
Q(i) := D(i) xor Q(i + 1);
end loop;
return Q;
end function;
--================================================================================
================================================--

signal Addr_Write_Gray : unsigned(Addr_Size downto 0); -- Адрес записи данных в буфер в коде Грея
signal Addr_Write_Gray_Next : unsigned(Addr_Size downto 0); -- Следующий адрес записи данных в буфер в коде Грея
signal Addr_Read_Gray : unsigned(Addr_Size downto 0); -- Адрес чтения данных из буфера в коде Грея

signal Addr_Write_Bin : unsigned(Addr_Size downto 0); -- Адрес записи данных в буфер в двоичном коде
signal Addr_Write_Bin_Next : unsigned(Addr_Size downto 0); -- Следующий адрес записи данных в буфер в двоичном коде
signal Addr_Read_Bin : unsigned(Addr_Size downto 0); -- Адрес чтения данных из буфера в двоичном коде

signal WE_Allow : std_logic; -- Разрешение записи данных в FIFO-буфер
signal RE_Allow : std_logic; -- Разрешение чтения данных из FIFO-буфера

signal Full_Match : std_logic; -- Сравнение адресов записи и чтения для флага того, что буфер полон
signal Empty_Match : std_logic; -- Сравнение адресов записи и чтения для флага того, что буфер пуст
begin

-- Адрес записи данных в буфер в двоичном коде: --
process(RST, CLK_WR)
begin
if (RST = '1') then
Addr_Write_Bin <= (others => '0');
elsif (Rising_Edge(CLK_WR)) then
if(WE_Allow = '1') then
Addr_Write_Bin <= Addr_Write_Bin + 1;
end if;
end if;
end process;

-- Следующий адрес записи данных в буфер в двоичном коде: --
process(RST, CLK_WR)
begin
if (RST = '1') then
Addr_Write_Bin_Next <= TO_UNSIGNED(1, Addr_Size + 1);
elsif (Rising_Edge(CLK_WR)) then
if(WE_Allow = '1') then
Addr_Write_Bin_Next <= Addr_Write_Bin_Next + 1;
end if;
end if;
end process;

-- Адрес записи данных в FIFO-буфер в коде Грея: --
Addr_Write_Gray <= Bin_to_Gray(Addr_Write_Bin);

-- Следующий адрес записи данных в буфер в коде Грея: --
Addr_Write_Gray_Next <= Bin_to_Gray(Addr_Write_Bin_Next);

-- Адрес чтения данных из буфера в двоичном коде: --
process(RST, CLK_RD)
begin
if (RST = '1') then
Addr_Read_Bin <= (others => '0');
elsif (Rising_Edge(CLK_RD)) then
if(RE_Allow = '1') then
Addr_Read_Bin <= Addr_Read_Bin + 1;
end if;
end if;
end process;

-- Адрес чтения данных из FIFO-буфера: --
Addr_Read_Gray <= Bin_to_Gray(Addr_Read_Bin);

-- Запись данных в FIFO-буфер: --
process
begin
wait until (rising_edge(CLK_WR));
if(WE_Allow = '1') then
FIFO_RAM(TO_INTEGER(Addr_Write_Gray(Addr_Size - 1 downto 0))) <= Data_WR;
end if;
end process;

-- Чтение данных из FIFO-буфера: --
process
begin
wait until (rising_edge(CLK_RD));
if(RE_Allow = '1') then
Data_RD <= FIFO_RAM(TO_INTEGER(Addr_Read_Gray(Addr_Size - 1 downto 0)));
end if;
end process;

-- Разрешение записи данных в FIFO-буфер: --
WE_Allow <= '1' when (WE = '1' and Full_Match = '0') else '0';

-- Разрешение чтения данных из FIFO-буфера: --
RE_Allow <= '1' when (RE = '1' and Empty_Match = '0') else '0';

-- Сравнение адресов записи и чтения для флага того, что буфер полон: --
Full_Match <= '1' when (Addr_Write_Bin(Addr_Size - 1 downto 0) = Addr_Read_Bin(Addr_Size - 1 downto 0) and Addr_Write_Bin(Addr_Size) /= Addr_Read_Bin(Addr_Size) and (RE = '0' or (RE = '1' and WE = '1'))) else '0';

-- Флаг того, что буфер полон: --
Full <= '1' when (Full_Match = '1' or (Addr_Write_Bin_Next(Addr_Size - 1 downto 0) = Addr_Read_Bin(Addr_Size - 1 downto 0) and Addr_Write_Bin_Next(Addr_Size) /= Addr_Read_Bin(Addr_Size) and (RE = '0' and WE = '1'))) else '0';

-- Сравнение адресов записи и чтения для флага того, что буфер пуст: --
Empty_Match <= '1' when (Addr_Write_Bin = Addr_Read_Bin and (WE = '0' or (RE = '1' and WE = '1'))) else '0';

-- Флаг того, что буфер пуст: --
Empty <= Empty_Match;
end architecture RTL;
_Anatoliy
Параметризуемый фильтр КИХ.
Реализация - вторая прямая форма,порядок чётный,ИХ симметричная,латентность - 2 такта не зависимо от порядка.
_Anatoliy
Вот теперь я понимаю почему проекты с опенкорес всегда требуют рихтовки и подгонки laughing.gif
Устранил баги и упростил.
aosp
Нужна структура быстрого счетчика для FPGA ALTERA ARRIA2GX C5.
Счетчик нужен на разрядность 32, скорость счета до 500МГц, тип счетчика не важен, количество счетных значений 2^32...
Кто поделится мыслями или практикой реализации?
bogaev_roman
Цитата(aosp @ Feb 28 2012, 17:20) *
Кто поделится мыслями или практикой реализации?

Дробить на несколько мелких счетчиков, соединенных последовательно.
des00
Цитата(aosp @ Feb 28 2012, 07:20) *
Кто поделится мыслями или практикой реализации?

много раз обсуждалось, идея здесь

Serhiy_UA
Цитата(aosp @ Feb 28 2012, 17:20) *
Кто поделится мыслями или практикой реализации?

Самый быстрый – асинхронный; только при считывании из него кода, его надо остановить.
Еще быстрее - кольцевой на кодах Грея, но там потом надо пересчитывать в двоичную форму, и останавливать не надо. Последовательная цепочка на D-триггерах с кольцом обратной связи через инвертор.
des00
Цитата(Serhiy_UA @ Feb 28 2012, 07:54) *
Самый быстрый – асинхронный; только при считывании из него кода, его надо остановить.
Еще быстрее - кольцевой на кодах Грея, но там потом надо пересчитывать в двоичную форму, и останавливать не надо.

ПСП счетчик и счетчик на кодах джонсона забыли %)
Kuzmi4
Собственно есть такая задача, думаю как раз для этого раздела: каждый такт выбираем индекс входных данных [15:0] для минимального значения (среди этих входных данных).
То есть имеем, например, такие входных данных: [порт№0] -> 7, [порт№1] -> 4, [порт№2] -> 1, [порт№3] -> 9,
И значит минимальный индекс будет 2 ([порт№2] -> 1). Значения произвольные (в смысле они не сортированы) и меняются каждый такт, выдавать индекс нужно тоже каждый такт.
Решение в лоб, говорит что максимум МГц так 35 можно для 16 входных 8битных портов на S6 (44 слоя комбинаторики). Ковыряние в умных книгах и поиск в инете выдал только такое заключение:
Цитата
If the arrays are unsorted then you must do a linear search to find the largest value in each.
. Что как то не радует.
Возможно у кого то появятся идеи как это сделать не прибегая к линейной проверке?
arexol
Цитата(Kuzmi4 @ Oct 2 2012, 09:39) *
Собственно есть такая задача, думаю как раз для этого раздела: каждый такт выбираем индекс входных данных [15:0] для минимального значения (среди этих входных данных).
То есть имеем, например, такие входных данных: [порт№0] -> 7, [порт№1] -> 4, [порт№2] -> 1, [порт№3] -> 9,
И значит минимальный индекс будет 2 ([порт№2] -> 1). Значения произвольные (в смысле они не сортированы) и меняются каждый такт, выдавать индекс нужно тоже каждый такт.
Решение в лоб, говорит что максимум МГц так 35 можно для 16 входных 8битных портов на S6 (44 слоя комбинаторики). Ковыряние в умных книгах и поиск в инете выдал только такое заключение: . Что как то не радует.
Возможно у кого то появятся идеи как это сделать не прибегая к линейной проверке?



Вроде вот такая регулярная структура родилась на вскидку (кружки это компараторы на больше - небыло сил бороться с виио sm.gif )

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



Serhiy_UA
Цитата(Kuzmi4 @ Oct 2 2012, 09:39) *
Возможно у кого то появятся идеи как это сделать не прибегая к линейной проверке?

1. пузырьковая сортировка на конвейере... Использовал при медианной фильтрации.
2. ассоциативный спецвычислитель...

Не понятно, что такое линейная проверка. Какое требуется быстродействие?
Kuzmi4
Данные для сравнения и вычисления индекса для минимальног опорта меняются каждый такт, то есть индекс нужно вычислять тоже за 1 такт. Желательно бы получить частоту хоть в 100МГц. Как вы понимаете, конвеер здесь не получится сделать.
Линейная проверка - это как в оригинале - берём и влоб перебираем/сравниваем все значения сразу.
ISK
Так всё равно непонятно, почему нельзя сделать конвейер. Результат будет выдаваться тоже каждый такт, только с задержкой в N тактов. Или это критично?
ViKo
Может, это очевидно, но нужно сравнить сначала соседние пары - 8 сравнений параллельно, проходят те, что меньше. Затем среди новых кандидатов попарно проводить 4 сравнения. Затем 2 сравнения. И, наконец, одно, завершающее.
Kuzmi4
2 ISK
это сравнение, только часть глобального вычисления - потому нужно считать каждый такт. Если есть уверенность что за N тактов не будет повторяющегся значения то можно и конвеер, но уверенности нет - изначально задано что данные идут произвольные и нет гарантии что они не будут одинаковые.

2 ViKo
arexol уже ранее предложил такую идею laughing.gif
ViKo
Цитата(Kuzmi4 @ Oct 2 2012, 11:25) *
2 ViKo
arexol уже ранее предложил такую идею laughing.gif

Наверное. Только на картинке это трудно понять. laughing.gif И... "16 уровней логики" wacko.gif
ISK
Цитата(Kuzmi4 @ Oct 2 2012, 11:25) *
2 ISK
Если есть уверенность что за N тактов не будет повторяющегся значения то можно и конвеер, но уверенности нет - изначально задано что данные идут произвольные и нет гарантии что они не будут одинаковые.



Всё равно не могу понять, какое отношение имеет повторение/неповторение данных для конвейера. В упрощённом виде для этого достаточно поставить регистр после мультиплексора на каждом уровне вычислителя.
Serhiy_UA
Хотя можно по arexol и ViKo...
Kuzmi4
2 ISK
глобальная идеология там мутноватая, я сам не сразу въехал, но в 2х словах вот так оно выглядит:
приходят данные, делается их кодирование, параметр кодирования изменяется от 0 до 15, для каждого параметра - свой счётчик он считает общую длинну закодированных данных для своего К-параметра, высчитывается индекс счётчика с минимальной длинной, это индекс и будет К-параметр, который будет использоваться для кодирования следующих данных в следующем такте. Ну и так по кругу - адаптивный механизм. Потому находить минимальный индекс, когда значения могу повторяться нужно каждый такт.
ISK
Была у меня похожая задача, на 100 МГц на циклоне 3 схема работала.

Код
        process (add_sub_res,point_cnt,cmp_res) begin        
            for j in 15 downto 0 loop
                for i in 15 downto 0 loop
                    if ((j = i) or (i > point_cnt)) then cmp_res(j)(i) <= '1';
                    elsif (j > point_cnt) then cmp_res(j)(i) <= '0';
                    else
                        if (j > i) then cmp_res(j)(i) <= not cmp_res(i)(j);
                        else
                            if (add_sub_res(j) < add_sub_res(i)) then cmp_res(j)(i) <= '1'; else cmp_res(j)(i) <= '0'; end if;
                        end if;
                    end if;
                end loop;
            end loop;
        end process;

        cmp_res_reg <= cmp_res;    

    --    process (cmp_res_reg) begin                    -- определение: единица, если все биты cmp_res(i) == единицы
          
and_loop:        for i in 0 to 15 generate
                      cmp_res_and(i) <=    cmp_res_reg(i)(0) and cmp_res_reg(i)(1) and cmp_res_reg(i)(2) and cmp_res_reg(i)(3) and cmp_res_reg(i)(4) and cmp_res_reg(i)(5) and cmp_res_reg(i)(6) and cmp_res_reg(i)(7) and
                            cmp_res_reg(i)(8) and cmp_res_reg(i)(9) and cmp_res_reg(i)(10) and cmp_res_reg(i)(11) and cmp_res_reg(i)(12) and cmp_res_reg(i)(13) and cmp_res_reg(i)(14) and cmp_res_reg(i)(15);                    
            --end loop;
        end generate;
        

s1: with cmp_res_and select
    point_find_result <= 0 when "0000000000000001",
                1 when     "0000000000000010",
                2 when    "0000000000000100",
                3 when    "0000000000001000",
                4 when    "0000000000010000",
                5 when    "0000000000100000",
                6 when    "0000000001000000",
                7 when    "0000000010000000",
                8 when    "0000000100000000",
                9 when    "0000001000000000",
                10 when    "0000010000000000",
                11 when    "0000100000000000",
                12 when    "0001000000000000",
                13 when    "0010000000000000",
                14 when    "0100000000000000",
                15 when others;
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.