Takes in a number of continuous or separate pulses, multiplies their total duration by a number, then outputs that multiplied duration divided by another number. Keeps an internal remainder across divisions to avoid integer rounding error.
`default_nettype none module Pulse_Scaler #( parameter WORD_WIDTH = 0 ) ( input wire clock, input wire clock_enable, input wire clear, input wire [WORD_WIDTH-1:0] multiply_by, input wire [WORD_WIDTH-1:0] divide_by, input multiply_divide, // 0/1 --> multiply/divide input wire pulses_in, output reg pulses_out, output wire multiply_overflow ); localparam WORD_ZERO = {WORD_WIDTH{1'b0}}; initial begin pulses_out = 1'b0; end
While in multiply phase, we accumulate multiply_by
once for each
pulses_in
received. Then, while in divide phase, we de
reg accumulator_clock_enable = 1'b0; reg increment_add_sub = 1'b0; reg [WORD_WIDTH-1:0] increment_value = WORD_ZERO; reg increment_valid = 1'b0; wire [WORD_WIDTH-1:0] accumulated_value; Accumulator_Binary #( .EXTRA_PIPE_STAGES (0), .WORD_WIDTH (WORD_WIDTH), .INITIAL_VALUE (WORD_ZERO) ) pulse_storage ( .clock (clock), .clock_enable (accumulator_clock_enable), .clear (clear), // verilator lint_off PINCONNECTEMPTY .clear_done (), // verilator lint_on PINCONNECTEMPTY .increment_carry_in (1'b0), .increment_add_sub (increment_add_sub), // 0/1 --> +/- .increment_value (increment_value), .increment_valid (increment_valid), // verilator lint_off PINCONNECTEMPTY .increment_done (), // verilator lint_on PINCONNECTEMPTY .load_value (WORD_ZERO), .load_valid (1'b0), // verilator lint_off PINCONNECTEMPTY .load_done (), // verilator lint_on PINCONNECTEMPTY .accumulated_value (accumulated_value), // verilator lint_off PINCONNECTEMPTY .accumulated_value_carry_out (), // verilator lint_on PINCONNECTEMPTY .accumulated_value_signed_overflow (multiply_overflow) );
Signal when we have subtracted and the remainder in the accumulator is less than the divisor (which includes zero).
wire division_done; Arithmetic_Predicates_Binary #( .WORD_WIDTH (WORD_WIDTH) ) division_check ( .A (accumulated_value), .B (divide_by), // verilator lint_off PINCONNECTEMPTY .A_eq_B (), // verilator lint_on PINCONNECTEMPTY .A_lt_B_unsigned (division_done), // verilator lint_off PINCONNECTEMPTY .A_lte_B_unsigned (), .A_gt_B_unsigned (), .A_gte_B_unsigned (), .A_lt_B_signed (), .A_lte_B_signed (), .A_gt_B_signed (), .A_gte_B_signed () // verilator lint_on PINCONNECTEMPTY );
Control logic
always @(*) begin accumulator_clock_enable = (clock_enable == 1'b1) && !((multiply_divide == 1'b1) && (division_done == 1'b1)); increment_add_sub = multiply_divide; increment_value = (multiply_divide == 1'b0) ? multiply_by : divide_by; increment_valid = ((multiply_divide == 1'b0) && (pulses_in == 1'b1)) || (division_done == 1'b0); pulses_out = (multiply_divide == 1'b1) && (division_done == 1'b0); end endmodule