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

Счетчик на примитивах CARRY_SUM и DFFE

У меня есть нечто подобное на AHDL, мне нравится.

 

Попробуйте еще на макросах типа 74163 с трюковыми входами. Каскадировать можно до бесконечности. Еще круче будет.

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


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

Попробуйте еще на макросах типа 74163 с трюковыми входами. Каскадировать можно до бесконечности. Еще круче будет.

Это - шутка?

 

Гляньте, какая таблица истинности вышла:

CI SI SO CO
0  0  0  0
0  1  1  0
1  0  0  1
1  1  1  1

т.е., CO повторяет CI, SO повторяет SI

:) :) :)

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


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

Это - шутка?
Да, я думаю это была шутка.

Вы по моему занимаетесь пустой работой, главное - результат.

Т.е. описываете задачу, описываете сколько нужно по времянке и всё. Я тоже помню, что в старые времена красиво было смотреть как софт на раскладке рисовал цепочки переносов, видно было где счётчики. Но как-то последнее время на это уже не обращаешь внимание: временка и ресурсы устраивают и ладненько. А в последнее время как-то всёравно стало, как оно там, пока не прижмёт.

 

Да, что-то мне подсказывает, что такие примитивы как счётчик крайне редко получится сделать оптимальнее чем в LPM модулях сделано, времени потратите больше чем экономии будет, если будет экономия...

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


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

Да, я думаю это была шутка.

Вы по моему занимаетесь пустой работой, главное - результат.

Я думаю, работа редко бывает впустую. Вот, мы узнали, что CARRY_SUM это просто два повторителя (наверное).

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

С вашего позволения, я еще немного "потрахаюсь". Если будет результат, доложу.

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


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

Но не получаю желаемого (см. картинку). Где-то промахнулся. Поможите, люди добрые!

что то счетчиком не пахнет %) post-3453-1270637946_thumb.png

тогда как в лоб post-3453-1270637954_thumb.png

видно что ква использует lpm_counter для данной архитектуры

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


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

что то счетчиком не пахнет %)

Не пахнет, потому что CARRY_SUM - это просто две цепи, одна ведет через мультиплексоры загрузки, синхронного сброса (зависит от архитектуры ПЛИС) к триггеру или еще куда подальше..., а вторая - цепь переноса, ведет ко входу переноса следующего ЛЭ. А не сумматор, как можно было бы подумать.

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


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

Не пахнет, потому что CARRY_SUM - это просто две цепи, одна ведет через мультиплексоры загрузки, синхронного сброса (зависит от архитектуры ПЛИС) к триггеру, а вторая - цепь переноса, ведет ко входу переноса следующего ЛЭ. А не сумматор, как можно было бы подумать.

а не пахнет потому что

1. это Technology Viewer:

2. вывод Pout не подключен к счетному выводу, как задумывалось, а сиди тупо на VCC

3. логика каждого бита порта Count не зависит от других битов, а зависит только от сигналов enable, reset_n, clock и своего собственного значения. Как ЭТО может быть счетчиком, в котором, при любом способе построения, старшие биты зависят от младших ?

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


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

Самый идеальный вариант - использовать мегафункцию, она специально заточена под структуру плисины.

При написании а ля counter<=counter+1 после синтеза квартус делает сумматор, который оптимизирует далее до счетчика и который проигрывает первоначальному варианту по быстродействию (немного, издержки фиттера).

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

Если хотите, чтоб на флурплане было все в линеечку и максимально упаковано, то используйте мегафункцию (чтоб при фиттере в большом проекте не размазал, ограничте область).

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


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

Объясняю, что хотел сделать. Вот образец на 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;

 

Самый идеальный вариант - использовать мегафункцию, она специально заточена под структуру плисины.

...

Согласен. Попробую и это обязательно.

 

 

Вот такой код работает. Но это только "полуфабрикат".

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

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


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

По совету участников обратился к мегафункции 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.

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


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

Вывод такой - если хочешь качества - используй LPM, если все равно - пиши по-простому, на Verilog.

module slon 
(
    input            clk,                      
    output bit [63:0] cnt
);

always_ff @(posedge clk) begin
    cnt <= cnt + 1;
end

endmodule

Floorplan:

post-1343-1270701399_thumb.png

 

Одна из ячеек (любая):

post-1343-1270701405_thumb.png

 

Что я делаю не так?

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


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

Обращается к lpm_counter. А тот представляет собой AHDL файл, который, я, собственно, и пытался "изобрести".

Вывод такой - если хочешь качества - используй LPM, если все равно - пиши по-простому, на Verilog.

Во-во, и более того, обычно достаточно просто написать: a=a+1; и квартус автоматически подключит LPM.

Единственный случай. который прихдит на ум, когда есть смысл попробовать ручками подключать, если сумматор по логике сложится с другой логике, и результат не ляжет на LPM. Но я например к таким экспериментам прихожу если не выполняются констрейны.

Так что не придумываете себе забот лишних, больше чем их есть.

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


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

Во-во, и более того, обычно достаточно просто написать: a=a+1; и квартус автоматически подключит LPM.

 

LPM counter он только на ацексе подключает. Последний квартус его уже не поддерживает.

У ацекса одна судьба - пакет max+II

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


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

LPM counter он только на ацексе подключает. Последний квартус его уже не поддерживает.

У ацекса одна судьба - пакет max+II

Не знаю, как последний, а Quartus 9.0 тот модуль, что я показал, скушал.

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


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

Что я делаю не так?

 

теперь еще добавить alcr, clk_ena, sload, cnt_en как в сабжевом примере и посмотреть. очень занятные вещи видятся для разных семейств (причины уже обсуждали на этом форуме) %)

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


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

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

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

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

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

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

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

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

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

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