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

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

Была у меня похожая задача, на 100 МГц на циклоне 3 схема работала.

ISK, не могли бы подробнее рассказать что к чему? Уже несколько часов потратил, никак не разберусь - толи устал, толи способностей не хватает(

Переменной point_cnt вы что задаёте? Также меня интересует начальное состояние cmp_res... В зависимости от него в строке cmp_res_reg(15) независимо от add_sub_res будет либо X"8000" , либо X"FFFF"... Ничего не понимаю, объясните пожалуйста подробнее.

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


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

Вобщем, с кодом ISKа разобраться так и не смог, сделал свой вариант.

Если входной массив разбить по 4 слова, и использовать не сравнение значений, а разность(т.е. логику ускоренного переноса), то получается довольно неплохо.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

library UNISIM;
use UNISIM.VComponents.all;

entity Sort_Four is
generic( 
wigth      			: natural 		:= 16);
Port ( 
clk					: in std_logic; 
in_word				: in std_logic_vector((4*wigth - 1) downto 0);	
----
out_index			: out std_logic_vector(1 downto 0);	
out_data			: out std_logic_vector((wigth - 1) downto 0));	
end Sort_Four;

architecture Behavioral of Sort_Four is

-----------------------------------------------------------
-----------------------------------------------------------
attribute syn_hier 		: string;
attribute syn_hier of Behavioral	: architecture is "hard";

attribute syn_keep 		: boolean;	
-----------------------------------------------------------
-----------------------------------------------------------
type word_type is array (0 to 3) of std_logic_vector((wigth - 1) downto 0);										
signal word, word_1d 	: word_type;

signal sub_0f 			: std_logic_vector(1 downto 0);
signal word_mux_st, word_mux_ml		: std_logic_vector((wigth - 1) downto 0);
signal sub_1f 			: std_logic;
signal sub_general		: std_logic_vector(2 downto 0);

-- signal data_1d, data	: std_logic_vector((order - 1) downto 0); 

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

begin


-----------------------------------------------------------
-----------------------------------------------------------
process (clk)				
begin 
if (clk = '1' and clk'event) then
for i in 0 to 3 loop	
	word_1d(i)		<= in_word(((i + 1)*wigth - 1) downto i*wigth);
	word(i)			<= word_1d(i);		
   end loop;	
end if;	
end process; 

-----------------------------------------------------------
-----------------------------------------------------------
process (word)
variable sub_w32_temp, sub_w10_temp : std_logic_vector((wigth - 1) downto 0);				
begin
sub_w32_temp		:= (word(3) + (not word(2)) + 1);
sub_w10_temp		:= (word(1) + (not word(0)) + 1);
sub_0f				<= (sub_w32_temp(wigth - 1)&sub_w10_temp(wigth - 1));
end process; 

word_mux_st				<= word(3) when sub_0f(1) = '1' else word(2);
word_mux_ml				<= (not word(1)) when sub_0f(0) = '1' else (not word(0));

-----------------------------------------------------------
-----------------------------------------------------------
process (word_mux_st, word_mux_ml)
variable word_mux_temp 	: std_logic_vector((wigth - 1) downto 0);				
begin
word_mux_temp		:= (word_mux_st + word_mux_ml + 1);
sub_1f				<= word_mux_temp(wigth - 1);
end process; 


-----------------------------------------------------------
-----------------------------------------------------------
-- process (clk)				
-- begin 
-- if (clk = '1' and clk'event) then	
-- if sub_1f = '1' then
	-- if sub_0f(1) = '1' then
		-- data_1d		<= word(3);
	-- else
		-- data_1d		<= word(2);
	-- end if;
-- else
	-- if sub_0f(0) = '1' then
		-- data_1d		<= word(1);
	-- else
		-- data_1d		<= word(0);
	-- end if;	
-- end if;
-- data				<= data_1d;
-- end if;	
-- end process; 

-- out_data				<= data;
-----------------------------------------------------------
-----------------------------------------------------------
sub_general				<= (sub_1f&sub_0f);
process (sub_general, word)
begin
   case sub_general is
    when "000"   	=> out_data <= word(0);
					out_index	<= "00";
    when "001"   	=> out_data <= word(0);
					out_index	<= "00";
    when "010"   	=> out_data <= word(1);
					out_index	<= "01";
    when "011"   	=> out_data <= word(1);
					out_index	<= "01";
    when "100"   	=> out_data <= word(2);
					out_index	<= "10";
    when "101"   	=> out_data <= word(2);
					out_index	<= "10";
    when "110"   	=> out_data <= word(3);
					out_index	<= "11";
    when "111"   	=> out_data <= word(3);
					out_index	<= "11";
       when others  	=> null;
   end case;
end process;


end Behavioral;

При входном массиве 16x16 получается 8 слоёв логики(не считая carry-chain), и для V6-1 схема разводится на 185МГц...

Жалко только, что мне надо 300 - буду ставить конвеер(

Изменено пользователем TRILLER

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


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

Быстрый счетчик реализуется на нескольких сумматорах с зарегистренным переносом. Сложение по факту выполняется за несколько тактов.

Я использовал 4 сумматора +1, +2, +3 и +4 от общего регистра, который обновляется раз в 4 такта от сумматора +4, а результаты сложений перебираются каждый такт мультиплексором. В результате получаешь счетчик работающий не в реальном времени, но собирающийся на частоте +30... 40 % к однопроходному.

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


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

всем привет! учусь на втором курсе.задали сделать семестровую работу по теме: "Моделирование САУ Адаптивного робота:Проектирование в виде системы на кристалле или интегральная схема - на основе метода ПЛИС, используя VHDL..но я не знаю как(VHDL не проходили даже)...помогите пожалуйста!

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


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

всем привет! учусь на втором курсе.задали сделать семестровую работу по теме: "Моделирование САУ Адаптивного робота:Проектирование в виде системы на кристалле или интегральная схема - на основе метода ПЛИС, используя VHDL..но я не знаю как(VHDL не проходили даже)...помогите пожалуйста!

1. Написать алгоритм работы робота

2. По нему сделать блок-схему алгоритма

3. По ней сделать блок-схему вычислителя.

4. Проверить ее в маткадах-иатлабах

5. Вычислитель реализовать в ПЛИС...

 

Вот собственно и все... Первые 4 пункта можно делать, ничего не зная о ПЛИС... Или мало зная о ПЛИС.

Потом задать преподу вопрос: почему заставляют делать то, чему не учили...

 

Мы готовы ответить на конкретный вопрос, но не делать за Вас всю работу. Нам это не интересно, это Ваша проблема, а не наша...

 

Да и тему надо перенести в другой раздел.... Либо для "начинающих", либо "предлагаю работу"....

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


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

2 вопроса:

а) чем содержательно должен отличаться подразумеваемый раздел от 4-ого раздела по ПЛИС "Системы на ПЛИС - System on Programmable Chip" (он открывался для обсуждения корок)? большей мелкозернистостью обсуждаемых модулей?

б) по какому принципу будет организовываться структура раздела? надеюсь каталогизация подразумевается?

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


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

может кому будет нужно

`timescale 1ns / 1ps

//

module divider #

(

parameter WIDTH_DIVIDENT = 27,

parameter WIDTH_DIVIDER = 9

)

(

// global

input Clock,

// input

input DivIn,

input [WIDTH_DIVIDENT-1 : 0] Divident,

input [WIDTH_DIVIDER-1 : 0] Divider,

// output

output wire DivOut,

output wire [WIDTH_DIVIDENT-1 : 0] Result,

output wire [WIDTH_DIVIDER-1 : 0] Fractional,

// debug

output wire Test

);

 

 

//

wire [0 : 0] Comp [WIDTH_DIVIDENT-1 : 0];

wire [WIDTH_DIVIDER-1 : 0] CarryTemp [WIDTH_DIVIDENT-1 : 0];

 

 

 

// sift registers

reg [0 : 0] DivTemp [WIDTH_DIVIDENT-1 : 0];

reg [WIDTH_DIVIDENT-1 : 0] ResultTemp [WIDTH_DIVIDENT-1 : 0];

reg [WIDTH_DIVIDENT+WIDTH_DIVIDER-1 : 0] DividentTemp [WIDTH_DIVIDENT-1 : 0];

reg [WIDTH_DIVIDER-1 : 0] DividerTemp [WIDTH_DIVIDENT-1 : 0];

 

// first

always @(posedge Clock) begin

DivTemp[0][0 : 0] = DivIn;

ResultTemp[0][WIDTH_DIVIDENT-1 : 0] = (Comp[0]) ? 8'd1 : 8'd0;

DividentTemp[0][WIDTH_DIVIDENT+WIDTH_DIVIDER-2 : 0] = {{(WIDTH_DIVIDER-1){1'b0}}, Divident[WIDTH_DIVIDENT-1 : 0]};

DividerTemp[0][WIDTH_DIVIDER-1 : 0] = Divider[WIDTH_DIVIDER-1 : 0];

end //always

 

// next all

genvar i;

generate

for (i=1; i<WIDTH_DIVIDENT; i=i+1)

begin: shift

always @(posedge Clock) begin

DivTemp[0 : 0] = DivTemp[i-1][0 : 0];

ResultTemp[WIDTH_DIVIDENT-1 : 0] = {(ResultTemp[i-1][WIDTH_DIVIDENT-2 : 0]), ((Comp) ? 1'b1 : 1'b0)};

DividentTemp[WIDTH_DIVIDENT+WIDTH_DIVIDER-2 : 0] = {CarryTemp[i-1][WIDTH_DIVIDER-2 : 0], DividentTemp[i-1][WIDTH_DIVIDENT-2 : 0], 1'b0};

DividerTemp[WIDTH_DIVIDER-1 : 0] = DividerTemp[i-1][WIDTH_DIVIDER-1 : 0];

end //always

end

endgenerate

 

 

// calculate

genvar j;

generate

for (j=0; j<WIDTH_DIVIDENT; j=j+1)

begin: calc

assign Comp[j][0 : 0] = (DividentTemp[j][WIDTH_DIVIDENT+WIDTH_DIVIDER-2 :WIDTH_DIVIDENT-1] >= DividerTemp[j][WIDTH_DIVIDER-1 : 0]) ? 1'b1 : 1'b0;

assign CarryTemp[j][WIDTH_DIVIDER-1 : 0] = (Comp[j]) ? (DividentTemp[j][WIDTH_DIVIDENT+WIDTH_DIVIDER-2 :WIDTH_DIVIDENT-1] - DividerTemp[j][WIDTH_DIVIDER-1 : 0]) : DividentTemp[j][WIDTH_DIVIDENT+WIDTH_DIVIDER-2 :WIDTH_DIVIDENT-1];

end

endgenerate

 

 

// fractional

reg [WIDTH_DIVIDER-1 : 0] FractionalReg;

always @(posedge Clock)

FractionalReg[WIDTH_DIVIDER-1 : 0] = CarryTemp[WIDTH_DIVIDENT-1];

 

 

// result valid

reg DivReg;

always @(posedge Clock)

DivReg = DivTemp[WIDTH_DIVIDENT-1][0 : 0];

 

 

// output

assign Result[WIDTH_DIVIDENT-1 : 0] = ResultTemp[WIDTH_DIVIDENT-1];

assign Fractional[WIDTH_DIVIDER-1 : 0] = FractionalReg[WIDTH_DIVIDER-1 : 0];

assign DivOut = DivReg;

 

 

// debug

assign Test = 1'b0;

 

 

endmodule //divider

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


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

может кому будет нужно

...

Оформите в виде исходного файла + простенького тб в архиве

блоки

// next all
...

// calculate
...

имхо лучше сделать как обычные циклы под always@(posedge Clock) и always@(*) соответственно

ну и если вруг не лениво, то небольшую справку по результатам имплементации на любой понравившейся ПЛИС, чтобы человек, если вдруг заинтересуется, имел представление во что это ему может вылиться.

 

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


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

вот другая реализация. Это простые делители - первый итерационный, а этот нет

 

// Fast Array Divider 8 bit to 4 bit

module fast_array_divider (a_in, d_in, q_out, r_out);

 

input [7:0] a_in;

input [3:0] d_in;

output [7:0] q_out; wire [7:0] q_out;

output [3:0] r_out; wire [3:0] r_out;

 

wire [12:1] a;

wire [4:1] d;

wire [8:1] q;

wire [8:5] r;

 

 

wire c_0_3, c_0_2, c_0_1, c_0_0;

wire s_0_3, s_0_2, s_0_1, s_0_0;

wire q1_inv;

restoring_array_divider array_0_0 ( a[2], d[1], c_0_1, q1_inv, c_0_0, s_0_0);

restoring_array_divider array_0_1 ( a[3], d[2], c_0_2, q1_inv, c_0_1, s_0_1);

restoring_array_divider array_0_2 ( a[4], d[3], c_0_3, q1_inv, c_0_2, s_0_2);

restoring_array_divider array_0_3 ( a[5], d[4], 1'b0, q1_inv, c_0_3, s_0_3);

assign q[1] = ( a[1] | !c_0_0 );

assign q1_inv=!q[1];

 

wire c_1_3, c_1_2, c_1_1, c_1_0;

wire s_1_3, s_1_2, s_1_1, s_1_0;

wire q2_inv;

restoring_array_divider array_1_0 ( s_0_1, d[1], c_1_1, q2_inv, c_1_0, s_1_0);

restoring_array_divider array_1_1 ( s_0_2, d[2], c_1_2, q2_inv, c_1_1, s_1_1);

restoring_array_divider array_1_2 ( s_0_3, d[3], c_1_3, q2_inv, c_1_2, s_1_2);

restoring_array_divider array_1_3 ( a[6], d[4], 1'b0, q2_inv, c_1_3, s_1_3);

assign q[2] = ( s_0_0 | !c_1_0 );

assign q2_inv=!q[2];

 

wire c_2_3, c_2_2, c_2_1, c_2_0;

wire s_2_3, s_2_2, s_2_1, s_2_0;

wire q3_inv;

restoring_array_divider array_2_0 ( s_1_1, d[1], c_2_1, q3_inv, c_2_0, s_2_0);

restoring_array_divider array_2_1 ( s_1_2, d[2], c_2_2, q3_inv, c_2_1, s_2_1);

restoring_array_divider array_2_2 ( s_1_3, d[3], c_2_3, q3_inv, c_2_2, s_2_2);

restoring_array_divider array_2_3 ( a[7], d[4], 1'b0, q3_inv, c_2_3, s_2_3);

assign q[3] = ( s_1_0 | !c_2_0 );

assign q3_inv=!q[3];

 

wire c_3_3, c_3_2, c_3_1, c_3_0;

wire s_3_3, s_3_2, s_3_1, s_3_0;

wire q4_inv;

restoring_array_divider array_3_0 ( s_2_1, d[1], c_3_1, q4_inv, c_3_0, s_3_0);

restoring_array_divider array_3_1 ( s_2_2, d[2], c_3_2, q4_inv, c_3_1, s_3_1);

restoring_array_divider array_3_2 ( s_2_3, d[3], c_3_3, q4_inv, c_3_2, s_3_2);

restoring_array_divider array_3_3 ( a[8], d[4], 1'b0, q4_inv, c_3_3, s_3_3);

assign q[4] = ( s_2_0 | !c_3_0 );

assign q4_inv=!q[4];

 

wire c_4_3, c_4_2, c_4_1, c_4_0;

wire s_4_3, s_4_2, s_4_1, s_4_0;

wire q5_inv;

restoring_array_divider array_4_0 ( s_3_1, d[1], c_4_1, q5_inv, c_4_0, s_4_0);

restoring_array_divider array_4_1 ( s_3_2, d[2], c_4_2, q5_inv, c_4_1, s_4_1);

restoring_array_divider array_4_2 ( s_3_3, d[3], c_4_3, q5_inv, c_4_2, s_4_2);

restoring_array_divider array_4_3 ( a[9], d[4], 1'b0, q5_inv, c_4_3, s_4_3);

assign q[5] = ( s_3_0 | !c_4_0 );

assign q5_inv=!q[5];

 

wire c_5_3, c_5_2, c_5_1, c_5_0;

wire s_5_3, s_5_2, s_5_1, s_5_0;

wire q6_inv;

restoring_array_divider array_5_0 ( s_4_1, d[1], c_5_1, q6_inv, c_5_0, s_5_0);

restoring_array_divider array_5_1 ( s_4_2, d[2], c_5_2, q6_inv, c_5_1, s_5_1);

restoring_array_divider array_5_2 ( s_4_3, d[3], c_5_3, q6_inv, c_5_2, s_5_2);

restoring_array_divider array_5_3 ( a[10], d[4], 1'b0, q6_inv, c_5_3, s_5_3);

assign q[6] = ( s_4_0 | !c_5_0 );

assign q6_inv=!q[6];

 

wire c_6_3, c_6_2, c_6_1, c_6_0;

wire s_6_3, s_6_2, s_6_1, s_6_0;

wire q7_inv;

restoring_array_divider array_6_0 ( s_5_1, d[1], c_6_1, q7_inv, c_6_0, s_6_0);

restoring_array_divider array_6_1 ( s_5_2, d[2], c_6_2, q7_inv, c_6_1, s_6_1);

restoring_array_divider array_6_2 ( s_5_3, d[3], c_6_3, q7_inv, c_6_2, s_6_2);

restoring_array_divider array_6_3 ( a[11], d[4], 1'b0, q7_inv, c_6_3, s_6_3);

assign q[7] = ( s_5_0 | !c_6_0 );

assign q7_inv=!q[7];

 

wire c_7_3, c_7_2, c_7_1, c_7_0;

wire s_7_3, s_7_2, s_7_1, s_7_0;

wire q8_inv;

restoring_array_divider array_7_0 ( s_6_1, d[1], c_7_1, q8_inv, c_7_0, s_7_0);

restoring_array_divider array_7_1 ( s_6_2, d[2], c_7_2, q8_inv, c_7_1, s_7_1);

restoring_array_divider array_7_2 ( s_6_3, d[3], c_7_3, q8_inv, c_7_2, s_7_2);

restoring_array_divider array_7_3 ( a[12], d[4], 1'b0, q8_inv, c_7_3, s_7_3);

assign q[8] = ( s_6_0 | !c_7_0 );

assign q8_inv=!q[8];

 

 

assign r[8:5]={s_7_3, s_7_2, s_7_1, s_7_0};

 

assign a[12:1]={a_in[0], a_in[1], a_in[2], a_in[3], a_in[4], a_in[5], a_in[6], a_in[7], 4'b0000};

assign d[4:1]={d_in[0], d_in[1], d_in[2], d_in[3]};

assign q_out[7:0]={q[1] ,q[2], q[3], q[4], q[5], q[6], q[7], q[8]};

assign r_out[3:0]={r[5], r[6], r[7], r[8]};

 

endmodule //fast_array_divider

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


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

Ну что,продолжим?

Параметризуемый полифазный фильтр КИХ. Количество фаз - 2.

Реализация - вторая прямая форма,порядок чётный,ИХ симметричная.

FilterPoly_2x.rar

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


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

Решил поделиться алгоритмом:

Например, вам надо понять, является ли введенное число степенью двойки или нет. Для этого вы можете просто делить это число на 2, пока не получите двойку на последнем шаге. Этот алгоритм будет работать, он выдаст результат, но на больших числах будет тратить много лишнего времени. А можете написать простое выражение в одну строку: x & (x-1) == 0. Тут используется немного битовой магии, но результат будет тем же, но за гораздо меньшее время.

 

PS Надеюсь будет кому-то полезным...

 

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


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

А можете написать простое выражение в одну строку: x & (x-1) == 0. Тут используется немного битовой магии, но результат будет тем же, но за гораздо меньшее время.
Вы не читали "Трюки для программистов"?

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


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

Решил поделиться алгоритмом:

Например, вам надо понять, является ли введенное число степенью двойки или нет. Для этого вы можете просто делить это число на 2, пока не получите двойку на последнем шаге. Этот алгоритм будет работать, он выдаст результат, но на больших числах будет тратить много лишнего времени. А можете написать простое выражение в одну строку: x & (x-1) == 0. Тут используется немного битовой магии, но результат будет тем же, но за гораздо меньшее время.

Здесь надо не делить на 2, а подсчитать количество единичных битов, и сравнить его с единицей. Поскольку конкретное значение количества единичных битов вычислять не требуется, стандартная архитектура решения этой задачи упрощается. Например, для 15 бит на Ксайлинксах потребуется три пары LUT5 на нижнем слое логики, и один LUT6 на следующем, как раз один слайс. Нижний слой выдаёт по трём группам из пяти бит значения "нет единиц", "одна единица", "больше одной единицы", а верхний LUT6 выносит окончательный вердикт.

А через вычитание потребуются 4 слайса только для вычитания и потом ещё 2 на логику.

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


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

Если число делится на 2, у него только одна единица среди битов. 4-входовая LUT выдает 1 для чисел 0001, 0010, 0100, 1000. Следующая такая же LUT принимает 4 выхода с предыдущего слоя, и т.д. Красота.

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


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

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

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

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

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

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

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

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

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

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