|
|
  |
Счетчик на примитивах CARRY_SUM и DFFE |
|
|
|
Apr 6 2010, 12:09
|

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

|
Quartus 9.0, Altera ACEX 1K. Пытаюсь создать счетчик, чтобы укладывался компактно в логические элементы. Для начала - фиксированного размера (с generate - свои проблемы). Как-то так: Код module CountPrim #(parameter WIDTH = 4) ( input Reset_n, Clock, Enable, output [WIDTH-1:0] Count, output POut );
wire [WIDTH-1:0] Fb; // feedback wire [WIDTH-1:0] Lt; // look table wire [WIDTH-1:0] Cr; // carry out
CARRY_SUM Cy0 (.sin(Fb[0]), .cin(1), .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]), .cin(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]), .cin(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]), .cin(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 6 2010, 12:35
|

я только учусь...
     
Группа: Модераторы
Сообщений: 3 447
Регистрация: 29-01-07
Из: Украина
Пользователь №: 24 839

|
Цитата(ViKo @ Apr 6 2010, 15:09)  Quartus 9.0, Altera ACEX 1K. Пытаюсь создать счетчик, чтобы укладывался компактно в логические элементы. Для начала - фиксированного размера (с generate - свои проблемы). Но не получаю желаемого (см. картинку). Где-то промахнулся. Поможите, люди добрые! чем Вас не устраивает такое описание Код reg [<upper>:0] <reg_name>; always @(posedge <clock> or posedge <reset>) if (<reset>) <reg_name> <= 0; else if (<clock_enable>) <reg_name> <= <reg_name> + 1; готового счетчика?
--------------------
If it doesn't work in simulation, it won't work on the board.
"Ты живешь в своих поступках, а не в теле. Ты — это твои действия, и нет другого тебя" Антуан де Сент-Экзюпери повесть "Маленький принц"
|
|
|
|
|
Apr 6 2010, 12:52
|
iBuilder©
   
Группа: Свой
Сообщений: 519
Регистрация: 14-07-04
Из: Минск
Пользователь №: 322

|
Цитата(ViKo @ Apr 6 2010, 15:45)  Не устраивает тем, что Quartus не объединяет в одном логическом элементе сумматор и триггер, а раскидывает, как захочет. На MAX+II на AHDL у меня счетчики выстраивались в линейку, с цепями переноса длиной в 24 элемента. Какую версию квартуса используете? Квартус достаточно умный для того, что-б использовать мегафункции, если только там код не сильно хитрый и не завязано на что-то ещё. Если что-то не получается, по моему проще использовать LPM функцию сложения, врятли получится написать оптимальнее чем в ней, особенно для общего случая.
|
|
|
|
|
Apr 6 2010, 13:09
|
Гуру
     
Группа: Модераторы
Сообщений: 4 011
Регистрация: 8-09-05
Из: спб
Пользователь №: 8 369

|
Цитата(ViKo @ Apr 6 2010, 17:06)  Просто счетчиков будет некоторое количество... остальное уже сказал. Самый главный вопрос: все счетчики считают одновременно и на максимальной для чипа частоте? Т.е решение "в лоб"??? Или можно сделать один счетчик и успевать им считать в нескольких каналах?
--------------------
www.iosifk.narod.ru
|
|
|
|
|
Apr 6 2010, 13:20
|

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

|
Счетчики разные, счетчиков - несколько (5-6), длинные. Я могу написать Count = Count + 1, и все будет нормально. Но хотелось бы получить конкретный ответ на свой вопрос. Что-то я напутал в CARRY_SUM. Цитата(Kuzmi4 @ Apr 6 2010, 16:09)  2 ViKo пройдитесь по форуму - помнится des00 и SM поднимали такой вопрос (только там есчё модуль был числа, а потом "плюс"). Не совсем то, что вам нужно, но сумматор там как раз таким вот хитроумным методом и был организован, и даже вроде бы через generate-ы. Смотрел, что-то видел. Но там не было CARRY_SUM. Я понимаю так, что таблица истинности у него следующая: Код CI SI SO CO 0 0 0 0 0 1 1 0 1 0 1 0 1 1 0 1
|
|
|
|
|
Apr 6 2010, 13:45
|
Знающий
   
Группа: Свой
Сообщений: 740
Регистрация: 24-07-06
Из: Minsk
Пользователь №: 19 059

|
Цитата(ViKo @ Apr 6 2010, 11:57)  Предпочитаю идеальное решение. Жалко напрасно потраченных логических элементов. а почему не берете в расчет зря потраченное время на это решение? Цитата(ViKo @ Apr 6 2010, 12:20)  Я понимаю так, что таблица истинности у него следующая: Код CI SI SO CO 0 0 0 0 0 1 1 0 1 0 1 0 1 1 0 1 похоже на правду, если хотите удостовериться - сделайте тестбенч и подайте на вход CI SI (всего лишь четыре варианта)
|
|
|
|
|
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. Но я например к таким экспериментам прихожу если не выполняются констрейны. Так что не придумываете себе забот лишних, больше чем их есть.
|
|
|
|
|
Apr 8 2010, 08:32
|

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

|
Ну, вот, к примеру. Код module CountDownReload #(parameter PERIOD = 50000) ( input Reset_n, Clock, Enable, output reg [WIDTH:0] Count ); localparam WIDTH = NumBits(PERIOD-2); always @(negedge Reset_n, posedge Clock) if (!Reset_n) Count = 0; else if (Enable) if (Count[WIDTH]) Count = Count - 1; else Count = (1 << WIDTH) | (PERIOD-2); endmodule Для ACEX получился в виде, как на картинке. Да, сумматор использует переносы, но триггеры черт знает где, выходы берутся с других мест. А вот тот же код, разложенный в Cyclone III, 18 ЛЭ Что сказать: Quartus + Cyclone = Сила! Предыдущие семейства - в топку!
Эскизы прикрепленных изображений
|
|
|
|
|
Apr 8 2010, 08:50
|

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

|
Цитата(des00 @ Apr 8 2010, 15:11)  теперь еще добавить alcr, clk_ena, sload, cnt_en как в сабжевом примере и посмотреть. очень занятные вещи видятся для разных семейств (причины уже обсуждали на этом форуме) %) Код //------------------------------------------------------------------------------ module slon ( input clk, input rst,
input cnt_en,
input [63:0] data, input load, output bit [63:0] cnt );
always_ff @(posedge clk, posedge rst) begin if(rst) begin cnt <= 0; end else begin if(cnt_en) begin if(load) begin cnt <= data; end else begin cnt <= cnt + 1; end end end end
endmodule //------------------------------------------------------------------------------
P.S. EP2C8F256I8 @ Quartus II 9.0 Build 235 06/17/2009 SJ Full Version, Service Pack Installed: 2
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 8 2010, 12:28
|
Гуру
     
Группа: Свой
Сообщений: 2 435
Регистрация: 6-10-04
Из: Петербург
Пользователь №: 804

|
Цитата(ViKo @ Apr 8 2010, 12:01)  Неужто 9.1 хуже? Или, снова... шутка? Смайлик поставьте. Error (10207): Verilog HDL error at CountDownReload.v(7): can't resolve reference to object "NumBits" Где он описан? Да и приоритетность нарушаете: The signal order is the same for all Altera device families, although as noted previously, not all device families provide every signal. The following priority order is observed: 1. Asynchronous Clear, aclr—highest priority 2. Preset, pre 3. Asynchronous Load, aload 4. Enable, ena 5. Synchronous Clear, sclr 6. Synchronous Load, sload 7. Data In, data—lowest priority
|
|
|
|
|
Apr 8 2010, 12:50
|

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

|
Цитата(des00 @ Apr 8 2010, 18:56)  я не зря перечислил нужные сигналы, Цитата теперь еще добавить alcr, clk_ena, sload, cnt_en Код module slon ( input clk, input rst,
input clk_en, input cnt_en,
input [63:0] data, input load, output bit [63:0] cnt );
always_ff @(posedge clk, posedge rst) begin if(rst) begin cnt <= 0; end else begin if(clk_en) begin if(load) begin cnt <= data; end else begin if(cnt_en) begin cnt <= cnt + 1; end end end end end
endmodule Так? Результат в смысле выстраивания счетчика в сгруппированном виде не изменился (скриншоты делать и слать лень). Цитата(des00 @ Apr 8 2010, 18:56)  посмотрите для начала на таблицу истинности lpm_counter потом сравните со своим кодом %) lpm_counter может быть сконфигурирован очень разнообразно, начиная от первого моего примера и включая этот. Какую именно конфигурацию вы имеете в виду? И что в ней мешает синтезатору слепить счетчик в сгруппированных ячейках и с использованием быстрых переносов?
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 8 2010, 13:24
|

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

|
Цитата(dxp @ Apr 8 2010, 16:05)  Какую именно конфигурацию вы имеете в виду? И что в ней мешает синтезатору слепить счетчик в сгруппированных ячейках и с использованием быстрых переносов? Если задействовать всё, что можно, в счетчике, то, может быть, "красивенько" уже не уложится. Код FUNCTION lpm_counter ( -- INPUTS data[LPM_WIDTH-1..0], clock, clk_en, cnt_en, updown, cin, aclr, aset, aconst, aload, sclr, sset, sconst, sload )
WITH ( -- PARAMETERS LPM_WIDTH, LPM_DIRECTION, LPM_MODULUS, LPM_AVALUE, LPM_SVALUE, LPM_PORT_UPDOWN, CARRY_CNT_EN, LABWIDE_SCLR, USE_NEW_VERSION )
RETURNS ( -- OUPUTS q[LPM_WIDTH-1..0], cout, eq[15..0]%, debug_out[6..0]% ); Правда, я уже не совсем понимаю, зачем...
|
|
|
|
|
Apr 8 2010, 13:59
|

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

|
Цитата(des00 @ Apr 8 2010, 16:53)  пример Viko MWLPM_Counter в посте №25 дает 26 плиток для третьего сыклона, ваш пример slon подрихтованный по разрядности + выход cout дает 50 плиток для того же сыклона. Видимо, дело, в cout (которого нет у dxp). Потому что последний slon на 24 разряда дает те же 26 "плиток". Приведите свой модуль. Ой, нет - 24 "плитки", 26 было для ACEX.
|
|
|
|
|
Apr 8 2010, 14:46
|
Профессионал
    
Группа: Свой
Сообщений: 1 088
Регистрация: 20-10-09
Из: Химки
Пользователь №: 53 082

|
Загнал следующий код в квартус 9.1 под stratix iv с установками по умолчанию. Код module test_counter ( input clk, input rst, output reg [15:0] cnt_out );
always @(posedge clk or posedge rst) if (rst) cnt_out<=16'd0; else cnt_out<=cnt_out+16'd1;
endmodule Проект размазался на флурплане по трем лабам и занял 20 лог ячеек, при этом раскидался в произвольном порядке. К сожалению, вставить картинку так и не смог При использовании мегафункции все получилось ровно и красиво. Поменял далее на циклон второй - красивая картиночка - все как положено. Непонятно...
Сообщение отредактировал bogaev_roman - Apr 8 2010, 14:52
|
|
|
|
|
Apr 9 2010, 05:29
|
Вечный ламер
     
Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453

|
Цитата(ViKo @ Apr 8 2010, 08:14)  Приведите свой модуль. Цитата(des00 @ Apr 8 2010, 08:20)  как разберусь откуда берутся лишние плитки приведу %) и вот опять старый мега баг квартуса, с неумением работать с сигналом sload %) немного подрихтованный slon Код module slon ( input clk, input rst,
input clk_en, input cnt_en,
input [23:0] data, input load, output bit [23:0] cnt, output bit cout, cout2 );
bit [24:0] cnt_reg; wire [24:0] cnt_next = cnt_reg + 1'b1;
always_ff @(posedge clk, posedge rst) begin if(rst) begin cnt_reg <= 0; end else begin if(clk_en) begin if(load) begin cnt_reg <= {1'b0, data}; end else begin if(cnt_en) begin cnt_reg <= cnt_next; end end end end end
assign cnt = cnt_reg[23:0]; assign cout = cnt_reg[24]; assign cout2 = cnt_next[24];
endmodule 51 плитка, стоит убрать cout2 или sload 26 плиток. Несмотря на то, что согласно "Figure 2–3. Cyclone III Family Devices LEs in Arithmetic Mode" снять сигнал переноса с последнего сумматора можно легко, ква делает для cout2, при наличии сигнала sload, отдельный сумматор. Мозгов ему в этом "крайне сложном" деле не хватает %) С MWLPM_Counter такого эффекта нет
--------------------
|
|
|
|
|
Apr 9 2010, 07:14
|
Вечный ламер
     
Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453

|
UPD. Ну так и есть, немного хендмейда и те же 26 плиток на третьем сыклоне %) Код wire [24:0] cnt_reg; wire [24:0] cnt_next = cnt_reg + cnt_en; wire [24:0] cnt_init = {1'b0, data};
genvar i; generate for (i = 0; i < $size(cnt_reg); i++) begin : dff_gen dffeas dffeas ( .clk ( clk ) , .d ( cnt_next [i] ) , .ena ( clk_en ) , .asdata ( cnt_init [i] ) , .clrn ( rst ) , .sload ( load ) , .q ( cnt_reg [i] ) ); end endgenerate
assign cnt = cnt_reg[23:0]; assign cout = cnt_reg[24]; assign cout2 = cnt_next[24]; Не любит ква сигнал sload, ох как не любит. Если мне память не изменяет, тянется это еще с 7 ой версии %)
--------------------
|
|
|
|
|
Apr 9 2010, 09:01
|

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

|
Цитата(sazh @ Apr 8 2010, 21:21)  Ну накрутили. Снимаю шляпу. Хотел, чтобы загрузка в ACEX шла нулем, согласно архитектуре. Ваш пример работает в Cyclone III быстрее. Наверное, потому, что в Циклон загрузка идет единицей sload . to des00Посмотрите на картинку для последнего slon'а. По-моему, все проблемы в сигнале cnt_en, который, вообще говоря, хрен знает зачем нужен. Есть же clk_en.
Эскизы прикрепленных изображений
|
|
|
|
|
Apr 9 2010, 10:07
|
Вечный ламер
     
Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453

|
Цитата(ViKo @ Apr 9 2010, 03:16)  Посмотрите на картинку для последнего slon'а. я думал что вы уже поняли что квартусовскому RTL вьюверу не верю и им не пользуюсь. Только Technology mapper. %) Цитата По-моему, все проблемы в сигнале cnt_en, который, вообще говоря, хрен знает зачем нужен. Есть же clk_en. Ну почему, нужна вещь в некоторых применениях. Да и в мегафункции lpm_counter он был с ее основания %)
--------------------
|
|
|
|
|
Apr 9 2010, 11:54
|

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

|
Смотрю в картинку "Figure 2–5. Cyclone III Family Devices LEs in Arithmetic Mode" (у меня 2-5). Не могу представить, как можно сделать сумматор для счетчика, и обходной путь, когда cnt_en запрещает счет, и выход переноса для следующего разряда. Левый нижний мультиплексор сообще нарисован по-идиотски, что выбирает, чем выбирает? Дальше-то просто - sload, data3, clock, ena. Т.е., возможно, это не глюк, а суровая реальность. P.S. Впрочем, и без cnt_en результат тот же  Upd. Устройство ЛЭ лучше смотреть в Resource Property Editor (который выскакивает в Chip Planner) - там все видно, как надо. День провозился с последним slon'ом, но так и не смог добиться того, что выдал des00 с использованием dffeas. Хочется верить, что это не глюк, а какая-то логическая нестыковка между Verilog и Cyclone. Вот и получается, что без примитивов перфект-качества не получить?
|
|
|
|
|
Apr 10 2010, 02:23
|
Вечный ламер
     
Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453

|
Цитата(ViKo @ Apr 9 2010, 06:09)  Не могу представить, как можно сделать сумматор для счетчика, и обходной путь, когда cnt_en запрещает счет, и выход переноса для следующего разряда. за счет цепей register bypass можно получить на тех же ресурсах комбинационный и регистровый выход сумматора. в lpm_counter cnt_en запрещает счет, но не запрещает формирование сигнала переноса. Кодом его можно описать двояко : 1) как в приведенном мной коде (кстати в этом случае cout завязан на cnt_en) 2) сумматор сделать константным (развязав cout и cnt_en), но усложнив логику формирования сигнала ena типа так clk_ena & (sload | (~sload & cnt_en)) Цитата Upd. Устройство ЛЭ лучше смотреть в Resource Property Editor (который выскакивает в Chip Planner) - там все видно, как надо. мне даташита хватает %) Цитата Вот и получается, что без примитивов перфект-качества не получить? вообще ква достаточно оптимально разводит, но вот сей эффект имеет место быть, когда я что-то делаю под альтеру, что должно использовать sload, я пишу два варианта и добавляю `ifdef __USE_ALTERA_MACRO__ %) Цитата Хочется верить, что это не глюк, а какая-то логическая нестыковка между Verilog и Cyclone. Вот за что мне нравиться форум, что ответы порой находятся сами собой. Читая ваш вопрос, случайно открыл даташит на второй сыклон и сравнил с третьим. Вуаля. Во втором сыклоне в арифметическом режиме нет register bypass. А ква не хватает ума что бы поставить последний LE в цепочке в нормальный режим (в котором register bypass есть). Ребята с альтеры сэкономили, архитектуру чипа улучшили, а вот маппер похоже оставили от второго сыклона. Индусы блин %(
Эскизы прикрепленных изображений
--------------------
|
|
|
|
|
Apr 10 2010, 18:27
|

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

|
Приколы продолжаются. "Хэндмэйд" des00 отказался укладываться в ACEX1K (Auto device selected by fitter), наверное, каналов не хватило? Код Error: Cannot route source node "dff_gen[11].dffeas" of type logic cell to destination node "cnt[11]" of type I/O pin Error: Cannot route source node "dff_gen[11].dffeas" of type logic cell to destination node "lpm_add_sub:Add0|addcore:adder|a_csnbuffer:result_node|cs_buffer[11]" of type logic cell Error: Cannot route source node "dff_gen[24].dffeas" of type logic cell to destination node "cout" of type I/O pin Error: Cannot route source node "dff_gen[24].dffeas" of type logic cell to destination node "lpm_add_sub:Add0|addcore:adder|unreg_res_node[24]" of type logic cell Error: Cannot route source node "lpm_add_sub:Add0|addcore:adder|a_csnbuffer:result_node|cs_buffer[5]" of type logic cell to destination node "dff_gen[5].dffeas" of type logic cell Error: Cannot route source node "lpm_add_sub:Add0|addcore:adder|a_csnbuffer:result_node|cs_buffer[7]" of type logic cell to destination node "dff_gen[7].dffeas" of type logic cell Error: Can't find fit Error: Quartus II Fitter was unsuccessful. 7 errors, 0 warnings А в ACEX1K100 - влез. Немного видоизмененный (и только с асинхронным выходом переноса) влез в удвоенное количество ЛЭ. Код module CounterDFFEAS #(parameter WIDTH = 24) ( input Reset_n, input Clock, input Enable, input Load, input [WIDTH-1:0] Data, output [WIDTH-1:0] CntOut, output POut ); wire [WIDTH-1:0] Count; wire [WIDTH:0] Next = Count + 1; genvar i; generate for (i=0; i<WIDTH; i++) begin : ffc dffeas dffeas ( .d (Next[i]), .clk (Clock), .clrn (Reset_n), .ena (Enable), .asdata (Data[i]), .sload (Load), .q (Count[i]) ); end endgenerate
assign CntOut = Count; assign POut = Next[WIDTH]; endmodule И только MWLPM_Counter, как уже говорилось, упаковался компактно. Еще одна особенность - если длина счетчика небольшая (смотрел для приведенного выше счетчика при длине 4 на Cyclone III), то цепи переноса из разряда в разряд не используются.
|
|
|
|
|
Apr 11 2010, 05:32
|
Вечный ламер
     
Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453

|
Цитата(ViKo @ Apr 10 2010, 13:42)  Приколы продолжаются. "Хэндмэйд" des00 отказался укладываться в ACEX1K (Auto device selected by fitter), наверное, каналов не хватило? у меня 9.0сп2 собрал без каких либо проблем а так, Код wire [24:0] cnt_reg; wire [24:0] cnt_next; wire [24:0] carry_cnt; wire [24:0] cnt_init = {1'b0, data};
genvar i; generate for (i = 0; i < $size(cnt_reg); i++) begin : dff_gen
carry_sum carry_sum ( .sin ( cnt_reg [i] ), .cin ( (i == 0) ? 1'b1 : carry_cnt[i-1] ), .sout ( cnt_next [i] ), .cout ( carry_cnt [i] ) );
dffeas dffeas ( .clk ( clk ) , .d ( cnt_next [i] ) , .ena ( clk_en ) , .asdata ( cnt_init [i] ) , .clrn ( rst ) , .sload ( load ) , .q ( cnt_reg [i] ) ); end endgenerate
assign cnt = cnt_reg[23:0]; assign cout = cnt_reg[24]; assign cout2 = cnt_next[24]; даже уложился в 27 плиток для асекса (как MWLPM_Counter для него же), и в 1 у плитку для сыклонов %) Цитата Еще одна особенность - если длина счетчика небольшая (смотрел для приведенного выше счетчика при длине 4 на Cyclone III), то цепи переноса из разряда в разряд не используются. это не удивительно и достаточно очевидно %)
--------------------
|
|
|
|
|
Apr 11 2010, 07:28
|

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

|
Цитата(des00 @ Apr 11 2010, 08:47)  у меня 9.0сп2 собрал без каких либо проблем У меня 9.0 без СП, придется по-новее пошукать. Цитата а так,... ...не работает, потому что нет сумматора. Об этом я уже писал в начале. Я уже было обрадовался - вот оно! Похоже, остался еще шаг до цели Цитата это не удивительно и достаточно очевидно %) Точно! Где можно обойтись параллельным выполнением операции, последовательное не нужно.
|
|
|
|
|
Apr 11 2010, 07:45
|
Вечный ламер
     
Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453

|
Цитата(ViKo @ Apr 11 2010, 01:43)  ...не работает, потому что нет сумматора. Об этом я уже писал в начале. а так Код carry_sum carry_sum ( .sin ( cnt_reg [i] ), .cin ( (i == 0) ? cnt_en : carry_cnt[i-1] ), .sout ( cnt_next [i] ), .cout ( carry_cnt [i] ) ); чем не сумматор %))) ЗЫ. Те же 27 плиток %) UPD. бугааа, повелся на поводу у людей, взято из файла altera_primitives.v Код module carry_sum (sin, cin, sout, cout); input sin; input cin; output sout; output cout;
assign sout = sin; assign cout = cin; endmodule это не сумматор, это всего лишь указание использовать быстрые цепи переноса
Эскизы прикрепленных изображений
--------------------
|
|
|
|
|
Apr 11 2010, 08:26
|
Вечный ламер
     
Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453

|
Цитата(ViKo @ Apr 11 2010, 02:34)  Ja-ja, naturlich! (как-то так  Меня терзает предчувствие, что не упакуется сумматор с триггерами даже если между ними и забить CARRY_SUM. Все больше склоняюсь к этому. Уже проверил, где там у меня MAXPlus+II инсталлятор  так сумматор получили, теперь осталось только втолковать квартусу что все это ложиться в одну плитку в соответствии с режимом "Clearable Counter Mode" LE асекса указанного в даташите ACEX 1K Programmable Logic Device Family Data Sheet Код wire [1:0] sum [0 : 24];
wire cnt_en_wire = cnt_en;
genvar i; generate for (i = 0; i < $size(cnt_reg); i++) begin : dff_gen
assign sum[i][0] = cnt_reg[i] ^ ((i == 0) ? cnt_en_wire : carry_cnt[i-1]); assign sum[i][1] = cnt_reg[i] & ((i == 0) ? cnt_en_wire : carry_cnt[i-1]); carry_sum carry_sum ( .sin ( sum[i][0] ), .cin ( sum[i][1] ), .sout ( cnt_next [i] ), .cout ( carry_cnt [i] ) );
--------------------
|
|
|
|
|
Apr 11 2010, 13:19
|
Вечный ламер
     
Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453

|
Путем ковыряния даташита на асекс и квартуса у меня сложилось следующее понимание : альтеровцы как всегда всех ввели в заблуждение. Режим работы ячейки асекса Clearable Counter ModeЦитата The clearable counter mode is similar to the up/down counter mode, but it supports a synchronous clear instead of the up/down control. The clear function is substituted for the cascade-in signal in the up/down counter mode. Two 3-input LUTs are used; one generates the counter data, and the other generates the fast carry bit. Synchronous loading is provided by a 2-to-1 multiplexer. The output of this multiplexer is AND ed with a synchronous clear signal. квартусу недоступен, он слишком туп для этого. Он ставит лют в арифметический регистр и sload в такой LE уже не ложиться, (см даташит на асекс). Помимо этого добавление к вышеуказанному коду сигнала sclr раздувает код до 74 плиток, хотя по даташиту это должно лечь в аппаратный AND в LE. Вывод : Надо пользовать в таких тяжелых случаях мегафункцию и не париться %)
--------------------
|
|
|
|
|
Apr 11 2010, 13:49
|
Вечный ламер
     
Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453

|
Цитата(ViKo @ Apr 11 2010, 07:59)  Вопрос принципиальный. Можно конвертировать из *.tdf в *.v (если б это что-то упростило  , синтезировать счетчик в упакованном виде. Что же не дает? Может быть, настройки какие-то хитрые есть, атрибуты? не дает, то, что при синтезе tdf используется синтезатор с языка AHDL, а при синтезе с v синтезатор с языка Verilog. И далеко не факт что команда разработчиков обоих синтезаторов была одна и та же. Просто кто-то, в свое время, сильно схалявил, а команда тестеров вовремя эту халяву не заметила. Потом пошли сыклоны, вторые, третьи и как то всем стало не до асексов. Своего рода плевок в вечность (как в свое время с шиной ISA) %)
--------------------
|
|
|
|
|
Apr 11 2010, 14:48
|
Гуру
     
Группа: Свой
Сообщений: 2 435
Регистрация: 6-10-04
Из: Петербург
Пользователь №: 804

|
Цитата(ViKo @ Apr 11 2010, 16:59)  Вопрос принципиальный. Можно конвертировать из *.tdf в *.v Сранивать с tdf некорректно. Это описание по сути - графическое представление lpm функций в текстовом виде (нет понятия в этом языке фронта клока) При переходе на поведенческое описание - меняется даже стиль описания. используйте lpm в крайних случаях. Например когда по ресурсам не проходите. В чем принцип, да еще на ацексе. (5 лет назад рисовал его в максе, если надо в нем и дорисую)
|
|
|
|
|
Apr 11 2010, 16:03
|

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

|
Я его сделал (Quartus, Coutner, Carry)!  Код module CountCarry #(parameter WIDTH = 24) ( input rst, input clk, input clk_en, input cnt_en, input load, input [WIDTH-1:0] data, output [WIDTH-1:0] cnt, output cout, cout2 ); wire [WIDTH:0] cnt_reg; wire [WIDTH:0] cnt_next; wire [WIDTH:0] cnt_carry; wire [WIDTH:0] cnt_init = {1'b0, data};
genvar i; generate for (i=0; i<=WIDTH; i++) begin : dff_gen
carry carry ( .in ((i ? cnt_carry[i-1] : cnt_en) & cnt_reg[i]), .out (cnt_carry[i]) );
dffeas dffeas ( .clk (clk), .d ((i ? cnt_carry[i-1] : cnt_en) ^ cnt_reg[i]), .ena (clk_en), .asdata (cnt_init[i]), .clrn (rst), .sload (load), .q (cnt_reg[i]) ); end endgenerate
assign cnt = cnt_reg[WIDTH-1:0]; assign cout = cnt_reg[WIDTH]; assign cout2 = cnt_next[WIDTH];
endmodule 28 ЛЭ для ACEX, один из которых - чисто инвертор для load. Не зря в хэлпе говорится, что CARRY оставлен для совместимости с проектами на MAXPlus. Благодарю "коллективный разум" форума, и des00 персонально!
|
|
|
|
|
Apr 12 2010, 21:20
|

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

|
Выход переполнения счетчика (который выдается наружу) нужно брать не с выхода суммы последнего сумматора, а с выхода переноса. Вот - "правильный" счетчик, со всеми достоинствами - регулярной структурой, предсказуемым быстродействием, и компакный. Только выбирайте синхронный выход переполнения (там их два). Код module CountPrim #( parameter WIDTH = 8, // number of bits parameter DIRECT = "UP" // count direction: "UP" or "DOWN" ) ( input rst_n, // async reset input clk_en, // clock enable all flip-flops input clk, input cnt_en, // count enable input load, // hi-level sync load input [WIDTH-1:0] data, // data for sync load output bit [WIDTH-1:0] cnt, // bits of counter output bit rcry, // ripple carry output bit tcry // triggered (sync) carry ); wire [WIDTH:-1] cnt_cry;
carry cryin ( .in (cnt_en), .out (cnt_cry[-1]) );
genvar i; generate for (i=0; i<WIDTH; i++) begin : bitgen if (DIRECT == "DOWN") carry crycnt ( .in (cnt_cry[i-1] & !cnt[i]), .out (cnt_cry[i]) ); else // "UP" carry crycnt ( .in (cnt_cry[i-1] & cnt[i]), .out (cnt_cry[i]) ); dffeas dffcnt ( .clk (clk), .d (cnt_cry[i-1] ^ cnt[i]), .ena (clk_en), .asdata (data[i]), .clrn (rst_n), .sload (load), .q (cnt[i]) ); end endgenerate
assign rcry = cnt_cry[WIDTH-1]; dffeas dffcry ( .clk (clk), .d (rcry), .ena (clk_en), .clrn (rst_n), .q (tcry) ); endmodule
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|