Я пытаюсь создать модуль, который принимает 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 для планирования входных данных, но не могу понять, как множитель будет выполнять эти умножения. Затем я попытался записать результат первого умножения обратно в промежуточный регистр и надеялся, что он будет использовать его повторно, но я уверен, что есть лучший способ сделать это.
Привет @Mikef, fast_mul — это множитель Карацубы-Офмана. Я взял его из этого репозитория -> github.com/JC-S/Karatsuba_multiplier_HDL/blob/master/rtl/…
Я уверен, что есть лучший способ сделать это.
В представленном вами контексте нет необходимости использовать несколько экземпляров структурного умножения.
Поведенческое моделирование работает в рабочих процессах моделирования и синтеза.
Рабочий процесс синтеза выводит два блока 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, и я стремлюсь использовать их максимально эффективно. Но спасибо за ответ, я рассмотрю возможность создания контроллера с использованием конечного автомата и отвечу вам. Хорошего дня!
Пожалуйста, добавьте код fast_mul в свой пост.