summaryrefslogtreecommitdiff
path: root/cocotb_try/cic3_pdm.v
blob: c53e867df7d0efe5035cd99c758ce45379cef142 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
module cic3_pdm (
    input  wire        clk,           // PDM clock
    input  wire        rst,           // active-high synchronous reset
    input  wire        pdm_in,        // 1-bit PDM data input
    input  wire [7:0]  hpf_alpha,     // HPF coefficient (0-255, 255=bypass)
    input  wire [2:0]  scale_shift,   // Right shift amount (0-7 bits)
    output reg  signed [15:0] pcm_out, // Decimated PCM output
    output reg         pcm_valid       // Output valid pulse
);

    // CIC filter parameters
    localparam DECIMATION = 64;
    localparam CIC_WIDTH = 17;  // 17 bits for safe margin against overflow
    
    // CIC integrator and comb stages
    reg signed [CIC_WIDTH-1:0] integrator1, integrator2;
    reg signed [CIC_WIDTH-1:0] comb1, comb2;
    reg signed [CIC_WIDTH-1:0] comb1_d1, comb2_d1;
    
    // Decimation counter
    reg [6:0] decim_count;  // 7 bits to match DECIMATION width
    
    // CIC output and scaling
    reg signed [CIC_WIDTH-1:0] cic_out;
    reg signed [15:0] scaled_out;
    reg cic_valid;
    
    // Leaky integrator HPF registers
    reg signed [23:0] hpf_integrator;  // 24-bit for precision
    reg signed [15:0] hpf_output;
    
    // HPF calculation wires
    wire signed [8:0] hpf_complement;
    wire signed [23:0] hpf_scaled_input;
    wire signed [23:0] hpf_dc_estimate;
    /* verilator lint_off UNUSEDSIGNAL */
    wire signed [23:0] hpf_temp_result;
    /* verilator lint_on UNUSEDSIGNAL */
    
    // HPF wire assignments
    assign hpf_complement = 9'd256 - {1'b0, hpf_alpha};
    assign hpf_scaled_input = {{8{scaled_out[15]}}, scaled_out};
    assign hpf_dc_estimate = hpf_integrator >>> 8;
    assign hpf_temp_result = hpf_scaled_input - hpf_dc_estimate;
    wire signed [CIC_WIDTH-1:0] pdm_signed = pdm_in ? 17'sd1 : -17'sd1;
    
    // CIC Integrator stages (run at PDM rate)
    always @(posedge clk) begin
        if (rst) begin
            integrator1 <= 0;
            integrator2 <= 0;
        end else begin
            integrator1 <= integrator1 + pdm_signed;
            integrator2 <= integrator2 + integrator1;
        end
    end
    
    // Decimation counter and CIC comb stages
    always @(posedge clk) begin
        if (rst) begin
            decim_count <= 0;
            comb1 <= 0;
            comb2 <= 0;
            comb1_d1 <= 0;
            comb2_d1 <= 0;
            cic_out <= 0;
            cic_valid <= 0;
        end else begin
            cic_valid <= 0;
            
            if (decim_count == DECIMATION - 1) begin
                decim_count <= 0;
                
                // Comb stage 1
                comb1 <= integrator2 - comb1_d1;
                comb1_d1 <= integrator2;
                
                // Comb stage 2
                comb2 <= comb1 - comb2_d1;
                comb2_d1 <= comb1;
                
                cic_out <= comb2;
                cic_valid <= 1;
            end else begin
                decim_count <= decim_count + 1;
            end
        end
    end
    
    // Output scaling
    always @(*) begin
        case (scale_shift)
            3'd0: scaled_out = cic_out[15:0];
            3'd1: scaled_out = cic_out[16:1];
            3'd2: scaled_out = {{1{cic_out[16]}}, cic_out[16:2]};  // Sign extend from bit 16
            3'd3: scaled_out = {{2{cic_out[16]}}, cic_out[16:3]};  // Sign extend from bit 16  
            3'd4: scaled_out = {{3{cic_out[16]}}, cic_out[16:4]};  // Sign extend from bit 16
            3'd5: scaled_out = {{4{cic_out[16]}}, cic_out[16:5]};  // Sign extend from bit 16
            3'd6: scaled_out = {{5{cic_out[16]}}, cic_out[16:6]};  // Sign extend from bit 16
            3'd7: scaled_out = {{6{cic_out[16]}}, cic_out[16:7]};  // Sign extend from bit 16
        endcase
    end
    
    // Leaky integrator-based DC blocker
    // y[n] = x[n] - dc_estimate
    // dc_estimate[n] = alpha/256 * dc_estimate[n-1] + (1-alpha/256) * x[n]
    always @(posedge clk) begin
        if (rst) begin
            hpf_integrator <= 0;
            hpf_output <= 0;
            pcm_out <= 0;
            pcm_valid <= 0;
        end else begin
            pcm_valid <= 0;
            
            if (cic_valid) begin
                if (hpf_alpha == 8'd255) begin
                    // Bypass HPF completely
                    pcm_out <= scaled_out;
                end else begin
                    // Update leaky integrator (DC estimate)
                    // integrator = alpha * integrator + (256-alpha) * input
                    hpf_integrator <= (hpf_alpha * hpf_dc_estimate) + 
                                     (hpf_complement * hpf_scaled_input);
                    
                    // Output = input - DC estimate
                    hpf_output <= hpf_temp_result[15:0];
                    pcm_out <= hpf_output;
                end
                pcm_valid <= 1;
            end
        end
    end

endmodule