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

Представление цикла FOR - стили программирования

_for (i=i_start; i<i_stop; i++)

___for (j=j_start; j>j_stop; j--)

_____do_something;

 

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

как-то погожим весенним днём мне пришла в голову мысль - а как другие дяденьки и тётеньки (ну в основном конечно дяденьки) справляются с такой привычной простому смертному программеру, как цикл FOR, задачей? Есть ли на вооружении Уважаемой публики какие-нибудь обощённые методики - взаимодействующие счётчики, стили описания единой стэйт-машины или ещё чо-нить?

 

в общем, кто как видит уложение цикла вверху в аппаратуру?

оч интересно! :cranky:

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


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

vse zavisit ot togo, chto konkretnos delau, esli delau, chto tipa ustroystva sravneniya, ili ALU to staraus ne ispolzovat, tak kak to chto implimentiruetsya v zheleze, staraus delat neposredstvenno. Neskolko raz zamechal problemi s implimentaciey

 

Fore loop v osnovnom ispolzuu dlya test bench

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


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

Что есть "перенос в аппаратуру"?

Если реалиазия на ПЛИС - то очень часто то, что записано в программе как

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

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


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

да, наверно нужно срау было обЪяснить, что я имею в виду под последовательной интерпритацией.

ну давайте попробуем:

значения переменных цикла i и j участвуют в дальнейших вычислениях каких-либо функций (при этом видно что i и j друг от друга не зависят) - наиболее распространённым примером было бы вычисление адреса памяти по какой-нибудь формуле - например mem_addr=i*const_a+j*const_b. то есть в каждый цикл системы (например каждый clock) проиcxодит следующая итерация самого глубокo вложенного цыкла FOR

 

например:

 

void write(int address, int value){...}

 

~~ for (i=10;i<1024;i++)

~~~ for (j=512;j>10;j--)

~~~~ video_memory.write(i*screen_width+j, pixel_buffer);

 

будет записывать в память дисплея значение пиксель буфера в порядке от 10 до 1023 строки от 512 до 11 столбца. (ток не спрашивайте зачем -- это просто пример)

терь по-понятней? :rolleyes:

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


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

да, наверно нужно срау было обЪяснить, что я имею в виду под последовательной интерпритацией.

ну давайте попробуем:

значения переменных цикла i и j участвуют в дальнейших вычислениях каких-либо функций (при этом видно что i и j друг от друга не зависят) - наиболее распространённым примером было бы вычисление адреса памяти по какой-нибудь формуле - например mem_addr=i*const_a+j*const_b. то есть в каждый цикл системы (например каждый clock) проиcxодит следующая итерация самого глубокo вложенного цыкла FOR

 

например:

 

void write(int address, int value){...}

 

~~ for (i=10;i<1024;i++)

~~~ for (j=512;j>10;j--)

~~~~ video_memory.write(i*screen_width+j, pixel_buffer);

Существует три основных стиля программирования на VHDL - структурный, поведенческий, потоковый. Для реализации вышеуказанной конструкции по моему лучше всего подойдут первые два.

Структурный стиль - мы описываем в двух процессах

два счетчика. Оба счетчика работают от одной тактововой. Счетчик

i инкрементируется по переполнению счетчика j. Причем у обоих счетчиков задаются коэффты пересчета

 

i_count:process(clk, rst)

begin

if rst='0' then

i=10;

elsif Rising_Edge(clk) then

if j=11 then

if i=511

i=10;

else

i=i+1;

end if;

end if;

end if;

end process;

 

j_count: process(clk,rst)

begin

if rst='0' then

j=512

elsif Rising_edge(clk) then

if j=11 then

j=512

else

j=j-1;

end if;

end if;

end process;

 

process(clk,rst)

begin

---- здесь вы пишите ваши функции от i и j, синхронно к clk

end process;

 

Вообщето некторые товарищи могут сказать что это поведенчиский

стиль. Частично соглашусь. Трудно провести четкую грань.

 

С моей точки зрения вариант на поведенческом стиле будет выглядеть так

process()

begin

if (i.....) then

if (j... ) then

wait until Rising_Edge(clk);

end if;

end process

 

Во....

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


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

Спасибо, _pegas_ , нечто подобное делаю и я, хотя по-моему ваш вариант "более поведенческий", чем мой. вот мой код:

 

looper.v

//for (i=i_start; i<=i_stop; i++)

// for (j=j_start; j=>j_stop; j--)

// do_something;

module looper (clk, reset_n, i_external_cycle_block, j_external_cycle_block, i_variable_reg, j_variable_reg);

`include "power.v"

//////////////////////////////////////////////////////////////////////

// This module is prepared for less-or-equal(<=) or higher-or-equal(=>) loops.

// It is obvious that less(<) and higher(>) loops can be easily adjusted to

// the form of less-or-equal(<=) or higher-or-equal(=>) loops mearly by recalculation

// of the limits.

//////////////////////////////////////////////////////////////////////

// cycle ranges

// i-loop

parameter i_start=273;

parameter i_stop=361;

parameter i_max=max(i_start, i_stop);

// j-loop

parameter j_start=55;

parameter j_stop=51;

parameter j_max=max(j_start, j_stop);

//////////////////////////////////////////////////////////////////////

parameter i_trancation=start_stop_trancation_value (i_start, i_stop);

parameter j_trancation=start_stop_trancation_value (j_start, j_stop);

 

parameter i_cycle_reg_width=(i_trancation==0)? number_of_bits_for_value_representation(i_max):number_of_bits_for_value_represen

tation(i_stop-i_start);

parameter j_cycle_reg_width=(j_trancation==0)? number_of_bits_for_value_representation(j_max):number_of_bits_for_value_represen

tation(j_start-j_stop);

parameter i_variable_reg_width=number_of_bits_for_value_representation(i_max);

parameter j_variable_reg_width=number_of_bits_for_value_representation(j_max);

 

 

parameter i_hstart=i_start-i_trancation;

parameter i_hstop=i_stop-i_trancation;

 

parameter j_hstop=j_stop-j_trancation;

parameter j_hstart=j_start-j_trancation;

 

input clk;

input reset_n;

input i_external_cycle_block;

input j_external_cycle_block;

 

reg [i_cycle_reg_width-1:0] i_cycle_reg;

reg [j_cycle_reg_width-1:0] j_cycle_reg;

output reg [i_variable_reg_width-1:0] i_variable_reg;

output reg [j_variable_reg_width-1:0] j_variable_reg;

 

reg i_cycle_block;

reg i_internal_cycle_block;

reg j_cycle_block;

wire j_internal_cycle_block;

 

assign j_internal_cycle_block=0;

 

 

 

// for (i=i_start;i<=i_stop;i++) {

always @ (posedge clk)

begin

if (~reset_n)

begin

i_cycle_reg<=i_hstart;

end

else

begin

if (i_cycle_block==0)

begin

if (i_cycle_reg == i_hstop) i_cycle_reg<=i_hstart; else i_cycle_reg<=i_cycle_reg+1;

end

end

end

always @*

begin

i_cycle_block=i_internal_cycle_block|i_external_cycle_block;

end

 

// for (j=j_start;j>=j_stop;j--) {

always @*

begin

if (j_cycle_reg == j_hstop) i_internal_cycle_block=0; else i_internal_cycle_block=1;

end

 

always @ (posedge clk)

begin

if (~reset_n)

begin

j_cycle_reg<=j_hstart;

end

else

begin

if (j_cycle_block==0)

begin

if (j_cycle_reg == j_hstop) j_cycle_reg<=j_hstart; else j_cycle_reg<=j_cycle_reg-1;

end

end

end

always @*

begin

j_cycle_block=j_external_cycle_block|j_internal_cycle_block;

end

// }//for_j

 

// }//for_i

 

 

generate

if (start_stop_trancation_value (i_start, i_stop)!=0)

begin

reg [i_variable_reg_width-i_cycle_reg_width-1:0] i_variable_upper_bits;

reg [i_variable_reg_width-1:0] i_auxilary;

always @*

begin

i_auxilary=i_max;

i_variable_upper_bits=i_auxilary[i_variable_reg_width-1:i_cycle_reg_width];

i_variable_reg={i_variable_upper_bits,i_cycle_reg};

end

end

else

begin

always @*

begin

i_variable_reg=i_cycle_reg;

end

 

end

endgenerate

 

generate

if (start_stop_trancation_value (j_start, j_stop)!=0)

begin

reg [j_variable_reg_width-j_cycle_reg_width-1:0] j_variable_upper_bits;

reg [j_variable_reg_width-1:0] j_auxilary;

always @*

begin

j_auxilary=j_max;

j_variable_upper_bits=j_auxilary[j_variable_reg_width-1:j_cycle_reg_width];

j_variable_reg={j_variable_upper_bits,j_cycle_reg};

end

end

else

begin

always @*

begin

j_variable_reg=j_cycle_reg;

end

 

end

endgenerate

 

endmodule

power.v

function integer max(input integer a, input integer b );

begin

max = (a >= b ) ? a : b ;

end

endfunction

 

function integer number_of_bits_for_value_representation (input integer value);

integer temp;

begin

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

end

endfunction

 

function integer start_stop_trancation_value (input integer start, input integer stop);

integer difference;

integer power_diff;

integer power_max;

integer temp_diff;

integer temp_max;

integer max;

integer min;

integer min_masked;

integer max_masked;

begin

temp_diff=1;

temp_max=1;

max=(start>stop)?start:stop;

min=(start<=stop)?start:stop;

difference=(start>stop)?(start-stop):(stop-start);

power_diff=number_of_bits_for_value_representation(difference);

power_max=number_of_bits_for_value_representation(max);

repeat (power_diff)

begin

temp_diff=temp_diff*2;

end

temp_diff=temp_diff-1;

temp_diff=~temp_diff;

 

repeat (power_max)

begin

temp_max=temp_max*2;

end

temp_max=temp_max-1;

 

min_masked=(min&temp_diff)&temp_max;

max_masked=(max&temp_diff)&temp_max;

 

if ((min_masked^max_masked)==0)

start_stop_trancation_value=max&temp_diff;

else start_stop_trancation_value=0;

end

endfunction

 

Существует три основных стиля программирования на VHDL - структурный, поведенческий, потоковый. Для реализации вышеуказанной конструкции по моему лучше всего подойдут первые два.

к стсати уважаемый _pegas_ - не могли бы вы как-нть простенько обЪяснить в чём разница между структурным и потоковым описанием - у меня сложилось такое впечатление что они отличаются только единицей видиния - в одном случае блок - в другом путь данных - но при реализации разница только в реализации соединений -- или я что-т не понял?

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

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


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

A pochemu bi ne vspomnit' starika Okkama? Menee chem dva schetchika sdes' vse ravno ne budet, vichisleniye funktsii ot i, j nikuda tozhe ne denetsya, telo tsikla tozhe ostanetsya. Takim obrazom poluchaem spisok osnovnih deystvuyuschih lits etoy sceni. Kak ih soedinit' i kak rassmatrivat' s'hemu - eto uzhe vopros esteticheskih soobrazheniy, a ne inzhenernih.

 

Voobsche govorya, chem dal'she vi uydete ot zheleza, tem menee optimal'no skompiliruet vashe opisanie sintezator. Sdes' vidna analogiya s pervimi C/C++ kompilyatorami. Poka vichislitel'naya moschnost' komp'yuterov bila slaboy ochen' chasto primenyalis' optimiziruyuschie vstavki na Assemblere, po mere rosta vichislitel'noy moschnosti processorov i ob'emov pamyati Assemblernaya optimizatsiya stanovitsya vse bolee redkim yavleniem. Nuzhno, odnako, otmetit', chto i kompilyatori stanovilis' "umnee". Tak proizoydet i s VHDL/Verilog/... i drugimi sintezatorami. Kogda schet yacheek v nebol'shoy po stoimosti PLIS poydet na desyatki tisyach, a taktovie chastoti osnovatel'no perevalyat za gigaherts, togda i mozhno budet izobretat' proekti na grani sinteziruemosti - effectivnost' PLIS v kupe s taktovoy chastotoy "s'edyat" ne optimal'nost' sintezatora, a do togo vremeni vse zhe luchshe poblizhe k zhelezu.

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


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

Работаю с Quartus. Могу сказать, что можно перенести только операции над регистрами или связями. С помощью for описываешь алгоритм, по которому данные будут изменяться. Quartus на основании этого сгенерит комбинационую схему. В других случаях ничего не получиться.

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

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


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

Работаю с Quartus. Могу сказать, что можно перенести только операции над регистрами или связями. С помощью for описываешь алгоритм, по которому данные будут изменяться. Quartus на основании этого сгенерит комбинационую схему. В других случаях ничего не получиться.

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

точно - именно поэтому, если посмотреть на оба кода, вы не заметите конструкции for - потому как она в этих языках вспомогательная в случае синтеза - препроцессорная - речь как раз и идёт о стилях, которые мы используем для получения эквивалента последовательной циклической обработки данных

(людям читающим этот пост на будущее - пожалуйста не подумайте что мы мало знакомы с синтексом языков на которых пишем - для чего нужны операторы for, repeat и while в VHDL и Verilog мы догадываемся :cheers: )

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


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

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

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

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

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

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

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

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

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

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