Added PLL/clock generator and SD RC model

This commit is contained in:
Joppe Blondel
2025-10-19 15:36:55 +02:00
parent 3b04f3a6be
commit eb7caaf2c5
10 changed files with 615 additions and 16 deletions

12
rtl/core/clk_gen.v Normal file
View File

@@ -0,0 +1,12 @@
`timescale 1ns/1ps
// =============================================================================
// Clock generator/PLL
// Simple pass through
// =============================================================================
module clk_gen(
input wire clk_in,
output wire clk_out_15
);
assign clk_out_15 = clk_in;
endmodule

65
rtl/core/mul_const.v Normal file
View File

@@ -0,0 +1,65 @@
`timescale 1ns/1ps
// =============================================================================
// Multiply a value by a constant
// Use a shift-add algorithm instead of a multiplier
// parameters:
// -- W : data width
// -- C : constant
// inout:
// -- x : input of width W
// -- y : output of widht 2W
// =============================================================================
module mul_const_shiftadd#(
parameter integer W = 16,
parameter integer C = 16'sh7fff
)(
input wire signed [W-1:0] x,
output wire signed [2*W-1:0] y
);
// Absolute value and sign of C
localparam integer C_NEG = (C < 0) ? 1 : 0;
localparam integer C_ABS = (C < 0) ? -C : C;
// Find MSB index of C_ABS to size the network
function integer msb_index;
input integer v;
integer i;
begin
msb_index = -1;
for (i = 0; i < 32; i = i + 1)
if (v >> i) msb_index = i;
end
endfunction
localparam integer I_MAX = (C_ABS == 0) ? 0 : msb_index(C_ABS);
// Partial products
wire signed [W+I_MAX:0] part [0:I_MAX];
genvar i;
generate
for (i = 0; i <= I_MAX; i = i + 1) begin : GEN_PARTS
assign part[i] = (C_ABS[i]) ? ($signed(x) <<< i) : { (W+I_MAX+1){1'b0} };
end
endgenerate
// Adder chain (simple; replace with tree if you want higher performance)
wire signed [W+I_MAX:0] sum [0:I_MAX];
generate
if (I_MAX == 0) begin
assign sum[0] = part[0];
end else begin
assign sum[0] = part[0];
for (i = 1; i <= I_MAX; i = i + 1) begin : GEN_SUM
assign sum[i] = sum[i-1] + part[i];
end
end
endgenerate
// Apply sign of C
wire signed [W+I_MAX:0] mag = (I_MAX==0) ? part[0] : sum[I_MAX];
wire signed [W+I_MAX:0] prod = C_NEG ? -mag : mag;
// Stretch to fixed y width (truncate/extend as you wish outside)
assign y = prod;
endmodule

View File

@@ -0,0 +1,47 @@
`timescale 1ns/1ps
// =============================================================================
// RC model to convert sigma delta samples to Q1.15
// Models the RC circuit on the outside of the FPGA
// Uses: Yn+1 = Yn + (sd - Yn)*(1-exp(-T/RC))
// parameters:
// -- alpha_q15 : the 1-exp(-T/RC), defaults to R=3k3, C=220p and T=1/15MHz
// rounded to only use two bits (0b3b -> 0b00), the less
// bits the better
// inout:
// -- clk : input clock
// -- resetn : reset signal
// -- sd_sample : 1 bit sample output from sd sampler
// -- sample_q15 : output samples in q1.15
// =============================================================================
module sigmadelta_rcmodel_q15 #(
parameter integer alpha_q15 = 16'sh0b00
)(
input wire clk,
input wire resetn,
input wire sd_sample,
output wire [15:0] sample_q15
);
reg signed [15:0] y_q15;
wire signed [15:0] sd_q15 = sd_sample ? 16'sh7fff : 16'sh0000;
wire signed [15:0] e_q15 = sd_q15 - y_q15;
wire signed [31:0] prod_q30;
// Use shift-add algorithm for multiplication
mul_const_shiftadd #(.C(alpha_q15)) alpha_times_e (e_q15, prod_q30);
wire signed [15:0] y_next_q15 = y_q15 + (prod_q30>>>15);
// clamp to [0, 0x7FFF] (keeps signal view tidy)
function signed [15:0] clamp01_q15(input signed [15:0] v);
if (v < 16'sd0000) clamp01_q15 = 16'sd0000;
else if (v > 16'sh7FFF) clamp01_q15 = 16'sh7FFF;
else clamp01_q15 = v;
endfunction
always @(posedge clk or negedge resetn) begin
if (!resetn) y_q15 <= 16'sd0000;
else y_q15 <= clamp01_q15(y_next_q15);
end
assign sample_q15 = y_q15;
endmodule