|
|
  |
Счетчик на примитивах CARRY_SUM и DFFE |
|
|
|
Apr 6 2010, 15:42
|
iBuilder©
   
Группа: Свой
Сообщений: 519
Регистрация: 14-07-04
Из: Минск
Пользователь №: 322

|
Цитата(ViKo @ Apr 6 2010, 17:13)  Это - шутка? Да, я думаю это была шутка. Вы по моему занимаетесь пустой работой, главное - результат. Т.е. описываете задачу, описываете сколько нужно по времянке и всё. Я тоже помню, что в старые времена красиво было смотреть как софт на раскладке рисовал цепочки переносов, видно было где счётчики. Но как-то последнее время на это уже не обращаешь внимание: временка и ресурсы устраивают и ладненько. А в последнее время как-то всёравно стало, как оно там, пока не прижмёт. Да, что-то мне подсказывает, что такие примитивы как счётчик крайне редко получится сделать оптимальнее чем в LPM модулях сделано, времени потратите больше чем экономии будет, если будет экономия...
|
|
|
|
|
Apr 6 2010, 16:25
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(Builder @ Apr 6 2010, 18:42)  Да, я думаю это была шутка. Вы по моему занимаетесь пустой работой, главное - результат. Я думаю, работа редко бывает впустую. Вот, мы узнали, что CARRY_SUM это просто два повторителя (наверное). Счетчик, "выстроенный в шеренгу", имеет регулярную структуру, предсказуемое быстродействие, близкое к предельному, не зависимые от переукладки проекта. С вашего позволения, я еще немного "потрахаюсь". Если будет результат, доложу.
|
|
|
|
|
Apr 7 2010, 11:22
|
Вечный ламер
     
Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453

|
Цитата(ViKo @ Apr 7 2010, 06:32)  Не пахнет, потому что CARRY_SUM - это просто две цепи, одна ведет через мультиплексоры загрузки, синхронного сброса (зависит от архитектуры ПЛИС) к триггеру, а вторая - цепь переноса, ведет ко входу переноса следующего ЛЭ. А не сумматор, как можно было бы подумать. а не пахнет потому что 1. это Technology Viewer: 2. вывод Pout не подключен к счетному выводу, как задумывалось, а сиди тупо на VCC 3. логика каждого бита порта Count не зависит от других битов, а зависит только от сигналов enable, reset_n, clock и своего собственного значения. Как ЭТО может быть счетчиком, в котором, при любом способе построения, старшие биты зависят от младших ?
--------------------
|
|
|
|
|
Apr 7 2010, 11:24
|
Профессионал
    
Группа: Свой
Сообщений: 1 088
Регистрация: 20-10-09
Из: Химки
Пользователь №: 53 082

|
Самый идеальный вариант - использовать мегафункцию, она специально заточена под структуру плисины. При написании а ля counter<=counter+1 после синтеза квартус делает сумматор, который оптимизирует далее до счетчика и который проигрывает первоначальному варианту по быстродействию (немного, издержки фиттера). Если делать на вентильном уровне, то квартус придет к тому же варианту что и с мегафункцией  (проверял на небольшой разрядности). Если хотите, чтоб на флурплане было все в линеечку и максимально упаковано, то используйте мегафункцию (чтоб при фиттере в большом проекте не размазал, ограничте область).
|
|
|
|
|
Apr 7 2010, 11:52
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Объясняю, что хотел сделать. Вот образец на AHDL. Для ACEX счетчик выстраивается ровненько, с цепями переноса из разряда в разряд и триггерами в тех же ЛЭ. Для Cyclone - уже нет. Хочу сделать подобное на Verilog. Код Title "Counter with Syncronous Reset";
%-- Library 2005 ViKo -------------------------- Counter with syncronous enable, load, reset direction - increment (default) or decrement carry-out - asyncronous, can be triggered outside
Нельзя использовать слишком много индивидуальных загрузок и сбросов - не удастся разложить, не хватит каналов, можно вылететь из-за ошибки. Но можно использовать несколько сигналов для групп.
%----------------------------------------------- Parameters ( Wid = 8, -- counter width Dir = "up" -- "down" or "up" );
------------------------------------------------ Subdesign ViKoCount ( Clk : input; -- Clock Ena : input = Vcc; -- Enable (input_pulse) Dat[Wid-1..0] : input = Gnd; -- Data for load nLd[Wid-1..0] : input = Vcc; -- /Load nRes[Wid-1..0] : input = Vcc; -- /Reset Q[Wid-1..0] : output; -- Outputs P : output; -- Carry output )
------------------------------------------------ Variable Ct[Wid-1..0] : dff; -- Counter cells Cy[Wid-1..0] : carry; -- Carry nodes
------------------------------------------------ Begin
Ct[].clk = Clk; Ct0.d = ((Ct0 $ Ena) & nLd0 # Dat0 & !nLd0) & nRes0; if Dir == "down" generate Cy0 = !Ct0; -- & nRes0; else generate Cy0 = Ct0; -- & nRes0; end generate; for i in 1 to Wid-1 generate Ct[i].d = ((Ct[i] $ (Cy[i-1] & Ena)) & nLd[i] # Dat[i] & !nLd[i]) & nRes[i]; if Dir == "down" generate Cy[i] = !Ct[i] & Cy[i-1]; -- & nRes[i]; else generate Cy[i] = Ct[i] & Cy[i-1]; -- & nRes[i]; end generate; end generate; Q[] = Ct[]; P = Cy[Wid-1]; -- Out with glitch End; Цитата(bogaev_roman @ Apr 7 2010, 14:39)  Самый идеальный вариант - использовать мегафункцию, она специально заточена под структуру плисины. ... Согласен. Попробую и это обязательно. Вот такой код работает. Но это только "полуфабрикат". Код module CountPrim #(parameter WIDTH = 4) ( input Reset_n, Clock, Enable, output [WIDTH-1:0] Count, output POut, input Down );
wire [WIDTH-1:0] Fb; // feedback wire [WIDTH-1:0] Lt; // lookUp table wire [WIDTH-1:0] Cr; // carry out
CARRY_SUM Cy0 (.sin(!Fb[0]), .cin(Fb[0] ^ Down), .sout(Lt[0]), .cout(Cr[0])); DFFE Ff0 (.d(Lt[0]), .clk(Clock), .clrn(Reset_n), .prn(1), .ena(Enable), .q(Fb[0]));
CARRY_SUM Cy1 (.sin(Fb[1] ^ Cr[0]), .cin((Fb[1] ^ Down) & Cr[0] ), .sout(Lt[1]), .cout(Cr[1])); DFFE Ff1 (.d(Lt[1]), .clk(Clock), .clrn(Reset_n), .prn(1), .ena(Enable), .q(Fb[1]));
CARRY_SUM Cy2 (.sin(Fb[2] ^ Cr[1]), .cin((Fb[2] ^ Down) & Cr[1]), .sout(Lt[2]), .cout(Cr[2])); DFFE Ff2 (.d(Lt[2]), .clk(Clock), .clrn(Reset_n), .prn(1), .ena(Enable), .q(Fb[2]));
CARRY_SUM Cy3 (.sin(Fb[3] ^ Cr[2]), .cin((Fb[3] ^ Down) & Cr[2]), .sout(Lt[3]), .cout(Cr[3])); DFFE Ff3 (.d(Lt[3]), .clk(Clock), .clrn(Reset_n), .prn(1), .ena(Enable), .q(Fb[3]));
assign Count = Fb; assign POut = Cr[3];
endmodule
|
|
|
|
|
Apr 7 2010, 13:36
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
По совету участников обратился к мегафункции LPM_COUNTER, с помощью Визарда создал Verilog модуль, который можно вставлять в свой проект, причем, кое-что можно и менять, например, разрядность. Раскладывается, как положено, быстродействие отличное. Большего мне не надо. Вот он какой, модуль. Код module MWLPM_Counter ( aclr, clk_en, clock, cnt_en, data, sload, cout, q);
input aclr; input clk_en; input clock; input cnt_en; input [23:0] data; input sload; output cout; output [23:0] q;
wire sub_wire0; wire [23:0] sub_wire1; wire cout = sub_wire0; wire [23:0] q = sub_wire1[7:0];
lpm_counter lpm_counter_component ( .sload (sload), .clk_en (clk_en), .aclr (aclr), .clock (clock), .data (data), .cnt_en (cnt_en), .cout (sub_wire0), .q (sub_wire1), .aload (1'b0), .aset (1'b0), .cin (1'b1), .eq (), .sclr (1'b0), .sset (1'b0), .updown (1'b1)); defparam lpm_counter_component.lpm_direction = "UP", lpm_counter_component.lpm_port_updown = "PORT_UNUSED", lpm_counter_component.lpm_type = "LPM_COUNTER", lpm_counter_component.lpm_width = 24;
endmodule Обращается к lpm_counter. А тот представляет собой AHDL файл, который, я, собственно, и пытался "изобрести". Вывод такой - если хочешь качества - используй LPM, если все равно - пиши по-простому, на Verilog.
|
|
|
|
|
Apr 8 2010, 04:38
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(ViKo @ Apr 7 2010, 20:51)  Вывод такой - если хочешь качества - используй LPM, если все равно - пиши по-простому, на Verilog. Код module slon ( input clk, output bit [63:0] cnt );
always_ff @(posedge clk) begin cnt <= cnt + 1; end
endmodule Floorplan:
Одна из ячеек (любая):
Что я делаю не так?
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 8 2010, 06:13
|
iBuilder©
   
Группа: Свой
Сообщений: 519
Регистрация: 14-07-04
Из: Минск
Пользователь №: 322

|
Цитата(ViKo @ Apr 7 2010, 16:51)  Обращается к lpm_counter. А тот представляет собой AHDL файл, который, я, собственно, и пытался "изобрести". Вывод такой - если хочешь качества - используй LPM, если все равно - пиши по-простому, на Verilog. Во-во, и более того, обычно достаточно просто написать: a=a+1; и квартус автоматически подключит LPM. Единственный случай. который прихдит на ум, когда есть смысл попробовать ручками подключать, если сумматор по логике сложится с другой логике, и результат не ляжет на LPM. Но я например к таким экспериментам прихожу если не выполняются констрейны. Так что не придумываете себе забот лишних, больше чем их есть.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|