Source

License

Index

Pulse Scaler

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

Back to FPGA Design Elements

fpgacpu.ca