summaryrefslogtreecommitdiff
path: root/cocotb_try/cic3_pdm.v
blob: 9e96742dd0c4a3c08d60fdb92b4ec2d4b4661996 (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
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 [2:0]  scale_shift,   // Right shift amount (0-7 bits)
    input  wire [7:0]  dc_alpha,      // DC removal alpha (0=bypass, 255=strong removal)
    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;
    
    // DC removal filter registers
    reg signed [19:0] dc_accumulator;  // 20-bit to prevent overflow
    
    
    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]};
            3'd3: scaled_out = {{2{cic_out[16]}}, cic_out[16:3]};
            3'd4: scaled_out = {{3{cic_out[16]}}, cic_out[16:4]};
            3'd5: scaled_out = {{4{cic_out[16]}}, cic_out[16:5]};
            3'd6: scaled_out = {{5{cic_out[16]}}, cic_out[16:6]};
            3'd7: scaled_out = {{6{cic_out[16]}}, cic_out[16:7]};
        endcase
    end
    
    // DC removal filter - runs at decimated rate
    always @(posedge clk) begin
        if (rst) begin
            dc_accumulator <= 20'sd0;
            pcm_out <= 0;
            pcm_valid <= 0;
        end else begin
            pcm_valid <= 0;
            
            if (cic_valid) begin
                if (dc_alpha == 8'd0) begin
                    // Bypass DC removal
                    pcm_out <= scaled_out;
                end else begin
                    // Simple leaky integrator with sign extension
                    case (dc_alpha)
                        8'd1:   dc_accumulator <= dc_accumulator - (dc_accumulator >>> 12) + {{4{scaled_out[15]}}, scaled_out};
                        8'd16:  dc_accumulator <= dc_accumulator - (dc_accumulator >>> 8) + {{4{scaled_out[15]}}, scaled_out};
                        8'd64:  dc_accumulator <= dc_accumulator - (dc_accumulator >>> 6) + {{4{scaled_out[15]}}, scaled_out};
                        8'd128:  dc_accumulator <= dc_accumulator - (dc_accumulator >>> 5) + {{4{scaled_out[15]}}, scaled_out};
                        8'd255: dc_accumulator <= dc_accumulator - (dc_accumulator >>> 4) + {{4{scaled_out[15]}}, scaled_out};
                        default: dc_accumulator <= dc_accumulator - (dc_accumulator >>> 8) + {{4{scaled_out[15]}}, scaled_out};
                    endcase
                    
                    // Output = input - DC estimate (using OLD estimate to avoid combinational loop)
                    pcm_out <= scaled_out - dc_accumulator[19:4];
                end
                pcm_valid <= 1;
            end
        end
    end
endmodule