module cic_filter #( parameter size = 3, // number of channels parameter width = 12 // bit width of the input data (unsigned) ) ( input wire clock, frame, reset, input wire [size*width-1:0] inp_data, output wire [size*widthr-1:0] out_data, output wire [size*widthr-1:0] out_data2, output wire [size*widthr-1:0] out_data3 ); localparam widthr = width + 13; /* 4-bit LFSR with additional bits to keep track of previous values */ reg [15:0] int_lfsr_reg, int_lfsr_next; reg int_wren_reg, int_wren_next; reg [1:0] int_chan_reg, int_chan_next; reg [2:0] int_case_reg, int_case_next; reg [7:0] int_addr_reg, int_addr_next; wire [9:0] int_addr_wire; reg [size*widthr-1:0] acc_data_reg [2:0], acc_data_next [2:0]; reg [size*widthr-1:0] int_data_reg [5:0], int_data_next [5:0]; wire [size*widthr-1:0] acc_data_wire [2:0], del_data_wire [1:0]; integer i; genvar j; generate for (j = 0; j < size; j = j + 1) begin : INT_DATA assign acc_data_wire[0][j*widthr+widthr-1:j*widthr] = {{(widthr-width){1'b0}}, inp_data[j*width+width-1:j*width]}; // -2*del_data_1 + del_data_2 + inp_data + result parallel_add #( .msw_subtract("YES"), .representation("SIGNED"), .result_alignment("LSB"), .shift(0), .size(4), .width(widthr), .widthr(widthr)) acc_unit_1 ( .data({ {del_data_wire[0][j*widthr+widthr-1],del_data_wire[0][j*widthr+widthr-3:j*widthr], 1'b0}, {del_data_wire[1][j*widthr+widthr-1:j*widthr]}, {acc_data_reg[0][j*widthr+widthr-1:j*widthr]}, {acc_data_reg[1][j*widthr+widthr-1:j*widthr]}}), .result(acc_data_wire[1][j*widthr+widthr-1:j*widthr])); parallel_add #( .msw_subtract("NO"), .representation("SIGNED"), .result_alignment("LSB"), .shift(0), .size(2), .width(widthr), .widthr(widthr)) acc_unit_2 ( .data({ {acc_data_reg[1][j*widthr+widthr-1:j*widthr]}, {acc_data_reg[2][j*widthr+widthr-1:j*widthr]}}), .result(acc_data_wire[2][j*widthr+widthr-1:j*widthr])); end endgenerate cic_pipeline #( .width(size*widthr)) cic_pipeline_unit ( .clock(clock), .data(acc_data_reg[0]), .rdaddress_a({int_addr_wire[9:8], int_addr_wire[3:0]}), .rdaddress_b({int_addr_wire[9:8], int_addr_wire[7:4]}), .wraddress(int_addr_reg), .wren(int_wren_reg), .qa(del_data_wire[0]), .qb(del_data_wire[1])); lpm_mux #( .lpm_size(3), .lpm_type("LPM_MUX"), .lpm_width(10), .lpm_widths(2)) mux_unit_1 ( .sel(int_chan_next), .data({ 2'd2, int_lfsr_reg[2*5+3:2*5], int_lfsr_reg[5+3:5], 2'd1, int_lfsr_reg[2*4+3:2*4], int_lfsr_reg[4+3:4], 2'd0, int_lfsr_reg[2*3+3:2*3], int_lfsr_reg[3+3:3]}), .result(int_addr_wire)); always @(posedge clock) begin if (reset) begin int_wren_reg <= 1'b1; int_chan_reg <= 2'd0; int_case_reg <= 3'd0; int_addr_reg <= 8'd0; for(i = 0; i <= 2; i = i + 1) begin acc_data_reg[i] <= {(size*widthr){1'b0}}; end for(i = 0; i <= 5; i = i + 1) begin int_data_reg[i] <= {(size*widthr){1'b0}}; end int_lfsr_reg <= 16'd0; end else begin int_wren_reg <= int_wren_next; int_chan_reg <= int_chan_next; int_case_reg <= int_case_next; int_addr_reg <= int_addr_next; for(i = 0; i <= 2; i = i + 1) begin acc_data_reg[i] <= acc_data_next[i]; end for(i = 0; i <= 5; i = i + 1) begin int_data_reg[i] <= int_data_next[i]; end int_lfsr_reg <= int_lfsr_next; end end always @* begin int_wren_next = int_wren_reg; int_chan_next = int_chan_reg; int_case_next = int_case_reg; int_addr_next = int_addr_reg; for(i = 0; i <= 2; i = i + 1) begin acc_data_next[i] = acc_data_reg[i]; end for(i = 0; i <= 5; i = i + 1) begin int_data_next[i] = int_data_reg[i]; end int_lfsr_next = int_lfsr_reg; case (int_case_reg) 0: begin // write zeros int_wren_next = 1'b1; int_addr_next = 8'd0; for(i = 0; i <= 2; i = i + 1) begin acc_data_next[i] = {(size*widthr){1'b0}}; end for(i = 0; i <= 5; i = i + 1) begin int_data_next[i] = {(size*widthr){1'b0}}; end int_case_next = 3'd1; end 1: begin // write zeros int_addr_next = int_addr_reg + 8'd1; if (&int_addr_reg) begin int_wren_next = 1'b0; int_chan_next = 2'd0; int_lfsr_next = 16'h7650; int_case_next = 3'd2; end end 2: // frame begin if (frame) begin int_wren_next = 1'b1; int_addr_next = {4'd0, int_lfsr_reg[3:0]}; // set read addr for 2nd pipeline int_chan_next = 2'd1; // prepare registers for 1st sum acc_data_next[0] = acc_data_wire[0]; acc_data_next[1] = int_data_reg[0]; acc_data_next[2] = int_data_reg[1]; int_case_next = 3'd3; end end 3: // 1st sum begin int_addr_next = {4'd1, int_lfsr_reg[3:0]}; // set read addr for 3rd pipeline int_chan_next = 2'd2; // prepare registers for 2nd sum acc_data_next[0] = int_data_reg[1]; acc_data_next[1] = int_data_reg[2]; acc_data_next[2] = int_data_reg[3]; // register 1st sum int_data_next[0] = acc_data_wire[1]; int_data_next[1] = acc_data_wire[2]; int_case_next = 3'd4; end 4: // 2nd sum begin int_addr_next = {4'd2, int_lfsr_reg[3:0]}; // prepare registers for 3rd sum acc_data_next[0] = int_data_reg[3]; acc_data_next[1] = int_data_reg[4]; acc_data_next[2] = int_data_reg[5]; // register 2nd sum int_data_next[2] = acc_data_wire[1]; int_data_next[3] = acc_data_wire[2]; int_lfsr_next = {int_lfsr_reg[14:0], int_lfsr_reg[2] ~^ int_lfsr_reg[3]}; int_case_next = 3'd5; end 5: // 3rd sum begin int_wren_next = 1'b0; // set read addr for 1st pipeline int_chan_next = 2'd0; // register 3rd sum int_data_next[4] = acc_data_wire[1]; int_data_next[5] = acc_data_wire[2]; int_case_next = 3'd2; end default: begin int_case_next = 3'd0; end endcase end assign out_data = int_data_reg[1]; assign out_data2 = int_data_reg[3]; assign out_data3 = int_data_reg[5]; endmodule