Jump to content

    
Sign in to follow this  
des00

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

Recommended Posts

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

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

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

Share this post


Link to post
Share on other sites

Вобщем, с кодом 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 - буду ставить конвеер(

Edited by TRILLER

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

Share this post


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

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

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

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

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

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

 

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

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

 

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

 

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

Share this post


Link to post
Share on other sites

2 вопроса:

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

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

Share this post


Link to post
Share on other sites

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

`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

Share this post


Link to post
Share on other sites
может кому будет нужно

...

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

блоки

// next all
...

// calculate
...

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

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

 

Share this post


Link to post
Share on other sites

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

 

// 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

Share this post


Link to post
Share on other sites

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

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

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

FilterPoly_2x.rar

Share this post


Link to post
Share on other sites

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

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

 

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

 

Share this post


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

Share this post


Link to post
Share on other sites
Решил поделиться алгоритмом:

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

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this