Accepts one ready/valid handshake at its input, along with a repeat count,
and will not accept another input handshake until input_data_repeat_count
output handshakes have been accepted. Each output handshake is a copy of
the input handshake, without the repeat count.
input_data_repeat_count must be less or equal to MAX_REPEAT_COUNT.
Loading a repeat count of zero immediately resets the buffer, and so the input handshake is sunk and so no output handshakes happen, and we immediately are ready to accept a new input handshake.
`default_nettype none
module Pipeline_Handshake_Multiplier
#(
parameter WORD_WIDTH = 0,
parameter MAX_REPEAT_COUNT = 0,
// Do not set at instantiation, except in Vivado IPI.
parameter REPEAT_COUNT_WIDTH = clog2(MAX_REPEAT_COUNT) + 1 // +1 to hold exact number, not a 0-index
)
(
input wire clock,
input wire clear,
input wire input_data_valid,
output wire input_data_ready,
input wire [WORD_WIDTH-1:0] input_data,
input wire [REPEAT_COUNT_WIDTH-1:0] input_data_repeat_count,
output wire output_data_valid,
input wire output_data_ready,
output wire [WORD_WIDTH-1:0] output_data
);
`include "clog2_function.vh"
First, let's buffer the input handshake. A Half Buffer will hold its output steady and not accept another input handshake until its output handshake completes. A repeat count of zero clears the buffer immediately.
// verilator lint_off UNOPTFLAT
wire output_data_ready_divided;
// verilator lint_on UNOPTFLAT
reg clear_input_buffer = 1'b0;
Pipeline_Half_Buffer
#(
.WORD_WIDTH (WORD_WIDTH),
.CIRCULAR_BUFFER (0) // non-zero to enable
)
input_buffer
(
.clock (clock),
.clear (clear | clear_input_buffer),
.input_valid (input_data_valid),
.input_ready (input_data_ready),
.input_data (input_data),
.output_valid (output_data_valid),
.output_ready (output_data_ready_divided),
.output_data (output_data)
);
We only need to control the buffer output ready signal and assert it once
after input_data_repeat_count module output handshakes. The repeat count
is stored in the Pulse Divider one cycle before the output handshake
becomes ready.
localparam REPEAT_ZERO = {REPEAT_COUNT_WIDTH{1'b0}};
reg module_input_handshake_done = 1'b0;
reg module_output_handshake_done = 1'b0;
always @(*) begin
module_input_handshake_done = (input_data_valid == 1'b1) && (input_data_ready == 1'b1);
clear_input_buffer = (module_input_handshake_done == 1'b1) && (input_data_repeat_count == REPEAT_ZERO);
module_output_handshake_done = (output_data_valid == 1'b1) && (output_data_ready == 1'b1);
end
NOTE: a input_data_repeat_count of zero DOES get loaded, which will cause
the Pulse_Divider to immediately load the first non-zero value it sees, but
since the input_buffer is not asserting valid at its output, any output
from the Pulse_Divider cannot complete any handshakes and has no effect.
Pulse_Divider
#(
.WORD_WIDTH (REPEAT_COUNT_WIDTH),
.INITIAL_DIVISOR (MAX_REPEAT_COUNT [REPEAT_COUNT_WIDTH-1:0])
)
output_handshake_counter
(
.clock (clock),
.restart (module_input_handshake_done),
.divisor (input_data_repeat_count),
.pulses_in (module_output_handshake_done),
.pulse_out (output_data_ready_divided),
// verilator lint_off PINCONNECTEMPTY
.div_by_zero ()
// verilator lint_on PINCONNECTEMPTY
);
endmodule