blob: 20990ded3b04de3f299ba6da88e126054afeb7b9 [file] [log] [blame]
// Copyright 2020 Thomas Parry
//
// SOME LICENSE
//
// Fractional N Divider
// A fractional N divider using MASH modulation.
//
// The 'data_in' value divided by the modulus will be created
// in a quantisesd number stream with high passed noise shaping
// characteristic.
//
module fractional_n_divider
# (
parameter WIDTH_INTEGER = 10,
parameter WIDTH_MODULUS = 16,
parameter ORDER = 3,
parameter DATA_WIDTH = WIDTH_INTEGER+WIDTH_MODULUS
) (
input rst,
// input and output frequencies
input input_frequency,
output output_frequency,
// a manual interface for data
input [DATA_WIDTH-1:0] divide_value,
input [1:0] dither_select,
// test outputs
output dither_output
);
// internal signals
wire [WIDTH_INTEGER-1:0] integer_value;
wire [WIDTH_MODULUS-1:0] fractional_value;
wire signed [ORDER-1:0] mash_output;
wire [WIDTH_INTEGER-1:0] count_target;
reg [WIDTH_INTEGER-1:0] count;
reg output_state;
reg dither;
reg dither_en_lfsr;
reg dither_in_lfsr;
reg dither_en_trng;
wire dither_out_lfsr;
wire dither_out_trng;
// split the divider values
assign integer_value = divide_value[DATA_WIDTH-1:WIDTH_MODULUS];
assign fractional_value = divide_value[WIDTH_MODULUS-1:0] + dither;
// instantiate the MASH modulator
mash_mod # (
.WIDTH_MODULUS(WIDTH_MODULUS),
.ORDER(ORDER)
) mash_mod_inst (
.clk(output_frequency),
.rst(rst),
.data_in(fractional_value),
.data_out(mash_output)
);
// combine the integer and fractional components
assign count_target = $unsigned($signed(integer_value) + {{(WIDTH_INTEGER-ORDER){mash_output[ORDER-1]}}, mash_output});
// count until the target is met and then output a pulse
always @(posedge rst, posedge input_frequency) begin
if (rst) begin
count = 0;
output_state = 0;
end
else begin
if (count == count_target) begin
count = 0;
output_state = 1;
end
else begin
count = count + 1;
output_state = 0;
end
end
end
assign output_frequency = output_state;
// LFSR based dither
lfsr_fib lfsr_fib_inst (
.i_clk(output_frequency),
.i_reset(rst),
.i_ce(dither_en_lfsr),
.i_in(dither_in_lfsr),
.o_bit(dither_out_lfsr)
);
// TRNG based dither
trng trng_inst (
.clk(output_frequency),
.rst(rst),
.stop(!dither_en_trng),
.random(dither_out_trng)
);
// select the dither source
always @(posedge output_frequency) begin
case(dither_select)
2'b00 :begin
dither <= 0;
dither_en_lfsr <= 0;
dither_in_lfsr <= 0;
dither_en_trng <= 0;
end
2'b01 : begin
dither <= dither_out_trng;
dither_en_lfsr <= 0;
dither_in_lfsr <= 0;
dither_en_trng <= 1;
end
2'b10 : begin
dither <= dither_out_lfsr;
dither_en_lfsr <= 1;
dither_in_lfsr <= 0;
dither_en_trng <= 0;
end
2'b11 : begin
dither <= dither_out_lfsr;
dither_en_lfsr <= 1;
dither_in_lfsr <= 1;
dither_en_trng <= 0;
end
default : begin
dither <= 0;
dither_en_lfsr <= 0;
dither_in_lfsr <= 0;
dither_en_trng <= 0;
end
endcase
end
assign dither_output = dither;
endmodule