Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как сделать большой параллельный параметризируемый сумматор?
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
count_enable
Есть N М-битных входов. Числа N и М это параметры в диапазоне N=[2..64], M=[6..16]. Как правильно написать параллельный сумматор, считающий сумму всех входов за один такт? Насколько эффективна такая конструкция в реальном железе? А то такой параллелизм мне очень упрощает задачу. Я конечно знаю что такое loop, но краем уха слышал что для большого количества входов лучше строить дерево из сумматоров вручную.
doom13
Можно так:
Код
module summ
#(
    parameter N = 16,
    parameter M = 16
)
(
    input clock,
    input [M-1:0] in [N-1:0],
    output reg [M-1:0] out
);

    genvar i;
    wire [M-1:0] res [N-1:0];
    
    generate
        for(i = 0; i < N; i = i + 1)begin : pin
            assign res[i] = (i == 0) ? in[i] : res[i-1] + in[i];
        end
    endgenerate
    
    always_ff@(posedge clock) out <= res[N-1];

endmodule
iosifk
Цитата(count_enable @ Jun 5 2014, 21:40) *
Есть N М-битных входов. Числа N и М это параметры в диапазоне N=[2..64], M=[6..16]. Как правильно написать параллельный сумматор, считающий сумму всех входов за один такт? Насколько эффективна такая конструкция в реальном железе? А то такой параллелизм мне очень упрощает задачу. Я конечно знаю что такое loop, но краем уха слышал что для большого количества входов лучше строить дерево из сумматоров вручную.

Очень странно! Loop - это только форма записи. И приведет они к точно такому же сумматору, как и "вручную"...
А вот Ваш сумматор "за 1 такт" сделает весь проект медленным. И возможно настолько медленным, что окажется быстрее суммировать за 2 или более такта, но на более высокой частоте...
count_enable
iosifk, но ведь вручную можно по разному сгруппировать сумматоры: бинарным деревом, односторонним деревом, или вообще вперемешку sm.gif. Рискнул синтезировать 64 штуки 8-битных для спартана 6: Maximum combinational path delay: 16.855ns. Для 4 сумматоров было 10 нс. Вроде не смертельно, но в RTL увидел цепочку последовательных суматоров. Т.е. ((A+B )+C)+D). Нехорошо. Можно ли как-то заставить чтобы процедурно генерировалось бинарное дерево ((A+B )+(C+D))? Тогда длина цепочки будет не N, а Log2(N).
Tiro
Цитата(count_enable @ Jun 5 2014, 22:18) *
Можно ли как-то заставить чтобы процедурно генерировалось бинарное дерево ((A+B )+(C+D))? Тогда длина цепочки будет не N, а Log2(N).

Описать сумматоры по отдельности и потом вогнать в формулу дерева. Синтезатор лишнее уберет.
des00
Код
module adder_tree
#(
  parameter int pDAT_W =  8 ,
  parameter int pNUM   = 16
)
(
  iclk ,
  iena ,
  idat ,
  oena ,
  odat
);

  //------------------------------------------------------------------------------------------------------
  //
  //------------------------------------------------------------------------------------------------------

  input  logic                iclk            ;
  input  logic                iena            ;
  input  logic [pDAT_W-1 : 0] idat [0 : pNUM-1];
  output logic                oena            ;
  output logic [pDAT_W-1 : 0] odat            ;

  //------------------------------------------------------------------------------------------------------
  //
  //------------------------------------------------------------------------------------------------------

  localparam int cADDER_NUM_PER_STAGE = pNUM/2;
  localparam int cADDER_STAGE_NUM     = clogb2(pNUM);

  logic [pDAT_W-1 : 0] acc[0 : cADDER_STAGE_NUM-1][0 : cADDER_NUM_PER_STAGE-1];
  logic                ena[0 : cADDER_STAGE_NUM-1];

  genvar i, stage;

  generate
    for (stage = 0; stage < cADDER_STAGE_NUM; stage++) begin : adder_stage_gen

      always_ff @(posedge iclk) begin
        ena[stage] <= (stage == 0) ? iena : ena[stage-1];
      end

      for (i = 0; i < (cADDER_NUM_PER_STAGE >> stage); i++) begin : adder_in_stage_gen

        always_ff @(posedge iclk) begin
          if (stage == 0) begin
            if (iena)
              acc[stage][i] <= idat[2*i] + idat[2*i+1];
          end
          else begin
            if (ena[stage-1])
              acc[stage][i] <= acc[stage-1][2*i] + acc[stage-1][2*i+1];
          end
        end

      end // adder_in_stage_gen
    end // adder_stage_gen
  endgenerate

  assign oena = ena[cADDER_STAGE_NUM-1];
  assign odat = acc[cADDER_STAGE_NUM-1][0];

endmodule
doom13
Цитата(des00 @ Jun 6 2014, 06:59) *

Только не универсальный сумматор получается, работает только для (pNUM == 2^n), как же быть для всех остальных случаев?
des00
Цитата(doom13 @ Jun 6 2014, 13:09) *
Только не универсальный сумматор получается, работает только для (pNUM == 2^n), как же быть для всех остальных случаев?

Код
    if (pORDER <= 8) begin : adder_tree_8_gen
      logic [cMULT_W-1 : 0] adder_tree__idat[0 : 7];

      always_comb begin : adder_tree_remap
        int i;
        for (i = 0; i < 8; i++) begin
          adder_tree__idat[i] = (i < pORDER) ? pipa [i] : '0;
        end
      end
  .........

это уж как нить сами .....
doom13
Цитата(des00 @ Jun 6 2014, 09:59) *

Опять не универсально получается, что со значениями (8 < pNUM < 16), (16 < pNUM < 32) и .т.д. Наверное, придётся схему на два куска бить, часть схемы до максимально возможного 2^n строить по Вашему алгоритму, второй кусок (то, что остаётся) просто сгенерить generate-ом и на выходе сложить. Получится универсальное решение.
Можно как-то применить floor() или что-то подобное для SystemVerilog?
des00
Цитата(doom13 @ Jun 6 2014, 14:45) *
Опять не универсально получается, что со значениями (8 < pNUM < 16), (16 < pNUM < 32) и .т.д. Наверное, придётся схему на два куска бить, часть схемы до максимально возможного 2^n строить по Вашему алгоритму, второй кусок (то, что остаётся) просто сгенерить generate-ом и на выходе сложить. Получится универсальное решение.

Ну вот вы это для всех и сделайте sm.gif зачем мне всю мою либу компонентов выкладывать sm.gif
doom13
Я Вашу либу и не спрашивал, просто каскадная схема, как получается, - частный случай.
На это, если можно, ответте:
Цитата(doom13 @ Jun 6 2014, 10:45) *
Можно как-то применить floor() или что-то подобное для SystemVerilog?
Timmy
Цитата(doom13 @ Jun 6 2014, 11:45) *
Опять не универсально получается, что со значениями (8 < pNUM < 16), (16 < pNUM < 32) и .т.д. Наверное, придётся схему на два куска бить, часть схемы до максимально возможного 2^n строить по Вашему алгоритму, второй кусок (то, что остаётся) просто сгенерить generate-ом и на выходе сложить. Получится универсальное решение.
Можно как-то применить floor() или что-то подобное для SystemVerilog?

Гораздо проще - если число слагаемых в текущей ступени нечётное, последнее "лишнее" слагаемое переносится на следующую ступень без сложения.
des00
Цитата(doom13 @ Jun 6 2014, 17:08) *
Можно как-то применить floor() или что-то подобное для SystemVerilog?

и чем это поможет ? описать сигналы в количестве 2**$logb2(ANY_NUM) и занулить ненужные. Для двухвходового сумматора лучше не придумано. Для трехвходового нужно будет действовать по другому.

Цитата(Timmy @ Jun 6 2014, 20:47) *
Гораздо проще - если число слагаемых в текущей ступени нечётное, последнее "лишнее" слагаемое переносится на следующую ступень без сложения.

это будет сделано автоматом сами синтезатором.
eugen_pcad_ru
Использовать параметризируемый конвейер!
Но результат не за один такт естественно.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.