Как я могу запланировать несколько входов в экземпляр модуля SystemVerilog?

Я пытаюсь создать модуль, который принимает 32-битный ввод (параметризованный) и выводит куб ввода. Наивный подход будет следующим:

module cuber #(
    BW = 32
) (
    input logic [BW-1:0] in0,
    output logic [BW*2-1:0] cubed_op
);

logic [BW*2-1:0] inter_l;

fast_mul #(.BW(BW))
fm_inst_1 (
  .input1(in0),
  .input2(in0),
  .product(inter_l)
);

fast_mul #(.BW(BW))
fm_inst_2 (
  .input1(inter_l),
  .input2(in0),
  .product(cubed_op)
);

endmodule

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

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

Пожалуйста, добавьте код fast_mul в свой пост.

Mikef 11.06.2024 18:23

Привет @Mikef, fast_mul — это множитель Карацубы-Офмана. Я взял его из этого репозитория -> github.com/JC-S/Karatsuba_multiplier_HDL/blob/master/rtl/…

Suhas 12.06.2024 07:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
95
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я уверен, что есть лучший способ сделать это.

В представленном вами контексте нет необходимости использовать несколько экземпляров структурного умножения.
Поведенческое моделирование работает в рабочих процессах моделирования и синтеза.

Рабочий процесс синтеза выводит два блока DSP FPGA примерно каскадно для выполнения умножения.

Я пытаюсь использовать FIFO для планирования ввода

Фифо не имеет ничего общего с умножением. Используйте fifo, когда вам нужно поведение буферизации/задержки/накопления FIFO. При необходимости используйте регистр для хранения промежуточных значений.

Если вы предпочитаете структурный дизайн, создайте два экземпляра множителя, и у вас будет базовая структура множителя. Большинство FPGA имеют несколько доступных блоков DSP. Создание экземпляра двух модулей не приведет к повторному использованию одного физического ресурса.

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

У вас есть как минимум одна ошибка в том, что вы опубликовали.
Кубирование N бит дает 3N бит, а не 2N.

Если вы предпочитаете выполнять мультиплексы с использованием структурного моделирования, результат первого составит 32 бита, умноженные на 32 бита, что составляет 64 бита. Выход второго — 32 бита, умноженные на 64 бита, что составляет 96 бит.

Если для определения проблемы требовалась параметризованная мощность, то структурная модель могла бы быть лучше, потому что вы могли бы использовать цикл генерации для создания 2**WHATEVER_PARAMETER необходим.

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

Лучшая модель зависит от контекста.

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

module cuber #(
    BW = 32
) (
  input  logic [BW       -  1:0] in0,
  output logic [(BW * 3) -  1:0] cubed_op
);

  always_comb
    cubed_op = in0 * in0 * in0;

endmodule

Маленькая симка это производит

time = 0, in0 =        2, cubed_op =               8, log2 cubed =   3
time = 1, in0 =        4, cubed_op =              64, log2 cubed =   6
time = 2, in0 =        8, cubed_op =             512, log2 cubed =   9
time = 3, in0 =       16, cubed_op =            4096, log2 cubed =  12
time = 4, in0 =      256, cubed_op =        16777216, log2 cubed =  24
time = 5, in0 =     2048, cubed_op =      8589934592, log2 cubed =  33
time = 6, in0 = 4294967295, cubed_op = 79228162458924105385300197375, log2 cubed =  96

Я распечатал журнал base2, чтобы отобразить количество битов, используемых для куба.

Последний вектор в момент времени 6 — это максимальное значение входных данных (2**32 — 1), поэтому вы можете видеть, что он работает для больших чисел и занимает 3N бит.


Вот версия конечного автомата, которая использует только одно умножение. Мул выполняет квадрат в первом такте, затем куб во 2-м. Конструкция принимает данные с рабочим циклом 50%.

module cuber
   (input logic [7:0] data_in,
    input logic val_in,
    input logic clk,
    input logic rst,
    output logic val_out,
    output logic [15:0] mul_out);
  
  // locals
  typedef enum logic [1:0] {SQUARE=2'b00,CUBE=2'b01} T_SM_ENUM;
  //  
  logic [31:0] mul_in_32; 
  logic [63:0] mul_in_64;
  logic [95:0] mul_out_96;
  logic        val_del1,val_del2;
  logic        mux_sel_out64_nout96;
  T_SM_ENUM    current_state, next_state;
  
  // rename
  assign mul_in_32 = data_in;
  
  // mux
  always_comb
    if (mux_sel_out64_nout96)
      mul_in_64 = data_in;
    else
      mul_in_64 = mul_out_96[63:0];
  
  // SM Combinational proc
  always_comb begin :SM
      // outputs
      mux_sel_out64_nout96 = 0;
      // NS
      next_state = current_state;
      
      case(current_state)
        SQUARE: begin
          // outputs
          if (val_in)
            mux_sel_out64_nout96 = 1;
          // NS
          if (val_in)
            next_state = CUBE;
        end
        
        CUBE: begin
          // outputs
          if (val_in)
            mux_sel_out64_nout96 = 1;
          // NS
          if (val_in)        
            next_state = SQUARE;
        end
        
        default:
          next_state = SQUARE;
      endcase
    end :SM
  
  // sync proc general use
  always_ff @(posedge clk)
    if (rst) begin
       current_state = SQUARE;  
       val_del1 <= 0;
       val_del2 <= 0;
      end
    else  begin
       current_state <= next_state;
      val_del1 <= val_in;
      val_del2 <= val_del1;
    end
      
  // sync proc for single mul
  always_ff @(posedge clk)
    if (rst) 
       mul_out_96 <= '0;
     else       
       mul_out_96 <= mul_in_32 * mul_in_64;
  
  // rename
  assign mul_out = mul_out_96;
  assign val_out = val_del2;
  
endmodule

И «$монитор» результатов:

# time =   0, reset = 1,val_in = 0, data_in =  x, mul_out =     x, val_out = x
# time =   5, reset = 0,val_in = 0, data_in =  x, mul_out =     0, val_out = 0
# time =  15, reset = 0,val_in = 0, data_in =  x, mul_out =     x, val_out = 0
# time =  35, reset = 0,val_in = 1, data_in =  4, mul_out =     x, val_out = 0
# time =  45, reset = 0,val_in = 0, data_in =  4, mul_out =    16, val_out = 0
# time =  55, reset = 0,val_in = 1, data_in = 16, mul_out =    64, val_out = 1
# time =  65, reset = 0,val_in = 0, data_in = 16, mul_out =   256, val_out = 0
# time =  75, reset = 0,val_in = 0, data_in = 16, mul_out =  4096, val_out = 1
# time =  85, reset = 0,val_in = 0, data_in = 16, mul_out =     0, val_out = 0

Тест выдает 4 как вектор, а тест выдаёт 64 на два такта позже. выдает 16 и через два такта выдает 4096.

Ах да, государственная машина имеет смысл. Причина, по которой я хочу повторно использовать один и тот же экземпляр, заключается в том, что этот кубер является частью более крупного алгоритма, который работает с битами большего размера (> 256 бит). Я мог бы использовать простой оператор *, но для больших размеров бит это занимает слишком много времени. ресурсов DSP, и я стремлюсь использовать их максимально эффективно. Но спасибо за ответ, я рассмотрю возможность создания контроллера с использованием конечного автомата и отвечу вам. Хорошего дня!

Suhas 12.06.2024 07:23

Другие вопросы по теме