module class_d(
input clk,
input rst_n,
input i2s_sck,
input i2s_ws,
input i2s_sd,
output o_pwm
);
wire [15:0] l_data;
i2s_rx I2S_RX(
.clk ( clk_d02 ),
.rst_n ( rst_n ),
.i2s_sck ( i2s_sck ),
.i2s_ws ( i2s_ws ),
.i2s_sd ( i2s_sd ),
.o_l_data ( l_data ),
.o_l_data_en( l_data_en )
);
//interpolating INT_FILTER(
//
//);
reg [19:0]r_left_data;
always @(posedge clk or negedge rst_n ) begin
if( ~rst_n ) r_left_data <= 0;
else if( l_data_en )r_left_data <= {l_data, 4′b0};
end
wire [3:0] sdm_data;
// forced data
parameter PCM_DEPTH = 256*1024;
reg [7:0]pcm_data[0:PCM_DEPTH-1];
initial $readmemh("01K_768kSample_16bit.pcm.txt", pcm_data);
reg [17:0] pcm_index;
wire[18:0] pcm_index_l, pcm_index_r;
initial #1 pcm_index = 0;
assign pcm_index_l = pcm_index*4;
assign pcm_index_r = pcm_index_l + 2;
wire[15:0] data_l;
wire[15:0] data_r;
assign data_l = { pcm_data[pcm_index_l+1], pcm_data[pcm_index_l] };
assign data_r = { pcm_data[pcm_index_r+1], pcm_data[pcm_index_r] };
wire clk_d32;
always @(posedge clk_d32 or negedge rst_n) begin
if( !rst_n ) begin
pcm_index <= 0;
end
else begin
pcm_index <= pcm_index + 1;
end
end
wire [15:0] forced_data;
assign forced_data = { data_l[15:0] };
sdm SDM(
.clk ( clk ),
.rst_n ( rst_n ),
.i_data ( forced_data ),
.i_ddc ( o_pwm ),
.o_sdm ( sdm_data )
);
wire [31:0] luted_data;
pwm_lut LUT(
.clk ( clk_d32 ),
.rst_n ( rst_n ),
.i_sdm_data ( sdm_data ),
.o_pwm_data ( luted_data )
);
shift_reg LINE_OUT(
.clk ( clk ),
.rst_n ( rst_n ),
.i_pwm_data ( luted_data ),
.o_pwm ( o_pwm )
);
clk_d02 CLK_D02(
.i_clk ( clk ),
.rst_n ( rst_n ),
.o_clk ( clk_d02 )
);
clk_d16 CLK_D32(
.i_clk ( clk ),
.rst_n ( rst_n ),
.o_clk ( clk_d32 )
);
endmodule
module i2s_rx(
input clk,
input rst_n,
input i2s_sck,
input i2s_ws,
input i2s_sd,
output reg[15:0] o_l_data,
output reg o_l_data_en
);
reg sck_p1, sck_p2;
always @(posedge clk or negedge rst_n) begin: sck_sample
if( ~rst_n ) begin
sck_p1 <= 0;
sck_p2 <= 0;
end
else begin
sck_p2 <= sck_p1;
sck_p1 <= i2s_sck;
end
end
reg ws_p1, ws_p2;
always @(posedge clk or negedge rst_n) begin: ws_sample
if( ~rst_n ) begin
ws_p1 <= 0;
ws_p2 <= 0;
end
else begin
ws_p2 <= ws_p1;
ws_p1 <= i2s_ws;
end
end
assign sck_hp = ~sck_p2 & sck_p1;
reg [4:0] r_cnt;
always @( posedge clk or negedge rst_n ) begin: counter
if( ~rst_n ) begin
r_cnt <= 0;
end
else begin
if( r_cnt > 17 ) ;
else if( ws_p1 != ws_p2 ) r_cnt <= 0;
else if( sck_hp ) r_cnt <= r_cnt + 1;
end
end
always @(posedge clk or negedge rst_n ) begin: b_l_data
if( ~rst_n ) begin
o_l_data <= 0;
end
else if( sck_hp & ws_p2 == 1′b1) begin
case ( r_cnt )
5′h00: ;
5′h01: begin o_l_data[15] <= i2s_sd; o_l_data_en <= 1′b0; end
5′h02: begin o_l_data[14] <= i2s_sd; end
5′h03: begin o_l_data[13] <= i2s_sd; end
5′h04: begin o_l_data[12] <= i2s_sd; end
5′h05: begin o_l_data[11] <= i2s_sd; end
5′h06: begin o_l_data[10] <= i2s_sd; end
5′h07: begin o_l_data[09] <= i2s_sd; end
5′h08: begin o_l_data[08] <= i2s_sd; end
5′h09: begin o_l_data[07] <= i2s_sd; end
5′h0a: begin o_l_data[06] <= i2s_sd; end
5′h0b: begin o_l_data[05] <= i2s_sd; end
5′h0c: begin o_l_data[04] <= i2s_sd; end
5′h0d: begin o_l_data[03] <= i2s_sd; end
5′h0e: begin o_l_data[02] <= i2s_sd; end
5′h0f: begin o_l_data[01] <= i2s_sd; end
5′h10: begin o_l_data[00] <= i2s_sd; o_l_data_en <= 1′b1; end
endcase
end
end
endmodule
module sdm(
input clk,
input rst_n,
input [15: 0] i_data, // signed data
input i_ddc,
output [ 3: 0] o_sdm
);
parameter
w_fb = 16,
w_s1 = w_fb + 4;
// 1st order
wire[15:0] feedback_1st;
assign feedback_1st[15:0]
= i_ddc == 1 ? 16′h7fff
: 16′h8001;
reg [23:0] r_accm_1st;
wire[16:0] diff_1st_sum; // 1st differential
assign diff_1st_sum[16:0] = { i_data[15], i_data[15:0] } - { feedback_1st[15], feedback_1st[15:0] };
wire [24:0] accm_1st_sum; // 1st accumulator
wire [23:0] accm_1st;
assign accm_1st_sum[24:0] = { {8{diff_1st_sum[16]}} ,diff_1st_sum[16:0] } + { r_accm_1st[23], r_accm_1st[23:0] };
assign accm_1st[23:0]
= accm_1st_sum[24:23] == 2′b01 ? 24′h7f_ffff
: accm_1st_sum[24:23] == 2′b10 ? 24′h80_0001
: accm_1st_sum[23: 0];
always @(negedge clk or negedge rst_n) begin: reg_accm_1st
if( ~rst_n ) begin
r_accm_1st[23:0] <= #1 24′h0;
end
else begin
r_accm_1st <= #1 accm_1st;
end
end
// 2nd order
wire[23:0] feedback_2nd;
assign feedback_2nd[23:0]
= i_ddc == 1 ? 24′h7f_ffff
: 24′h80_0001;
reg [31:0] r_accm_2nd;
wire[24:0] diff_2nd_sum; // 2nd differential
assign diff_2nd_sum[24:0] = { accm_1st[23], accm_1st[23:0] } - { feedback_2nd[23], feedback_2nd[23:0] };
wire [32:0] accm_2nd_sum; // 2nd accumulator
wire [31:0] accm_2nd;
assign accm_2nd_sum[32:0] = { {8{diff_2nd_sum[24]}} ,diff_2nd_sum[24:0] } + { r_accm_2nd[31], r_accm_2nd[31:0] };
assign accm_2nd[31:0]
= accm_2nd_sum[32:31] == 2′b01 ? 32′h7fff_ffff
: accm_2nd_sum[32:31] == 2′b10 ? 32′h8000_0001
: accm_2nd_sum[31: 0];
always @(negedge clk or negedge rst_n) begin: reg_accm_2nd
if( ~rst_n ) begin
r_accm_2nd[31:0] <= #1 32′h0;
end
else begin
r_accm_2nd <= #1 accm_2nd;
end
end
// // decimation filter
// reg [3:0] r_step;
// always @(posedge clk or negedge rst_n ) begin: step
// if( ~rst_n ) begin
// r_step <= 1′b0;
// end
// else begin
// r_step <= r_step + 1;
// end
// end
//
// wire [8:0] sdm_sum_o;
// wire [7:0] sdm_sum;
// reg [7:0] r_integrator_sdm;
//
// assign sdm_sum_o[8:0] = { r_integrator_sdm[7], r_integrator_sdm[7:0] } + { {5{r_accm_2nd[31]}}, r_accm_2nd[31:28] };
// assign sdm_sum[7:0]
// = sdm_sum_o[8:7] == 2′b01 ? 8′h7f
// : sdm_sum_o[8:7] == 2′b10 ? 8′h80
// : sdm_sum_o[7:0];
//
// always @(posedge clk or negedge rst_n ) begin: integrator_sdm
// if( ~rst_n ) r_integrator_sdm <= 1′b0;
// else if( r_step == 4′h0 ) r_integrator_sdm <= 0;
// else r_integrator_sdm <= sdm_sum[7:0];
// end
//
// always @(posedge clk or negedge rst_n ) begin: out_sdm
// if( ~rst_n ) o_sdm <= 1′b0;
// else if( r_step == 4′h0 ) o_sdm <= r_integrator_sdm[7:4];
// end
assign o_sdm = accm_2nd[31:28];
endmodule
module pwm_lut(
input clk,
input rst_n,
input [ 3: 0] i_sdm_data,
output [31: 0] o_pwm_data
);
reg [31:0] r_pwm_data;
always @(posedge clk or negedge rst_n) begin: pwm
if( ~rst_n ) begin
r_pwm_data <= 0;
end
else begin
case ( i_sdm_data )
4′h7: r_pwm_data <= { {01{1′b0}}, {31{1′b1}} };
4′h6: r_pwm_data <= { {03{1′b0}}, {29{1′b1}} };
4′h5: r_pwm_data <= { {05{1′b0}}, {27{1′b1}} };
4′h4: r_pwm_data <= { {07{1′b0}}, {25{1′b1}} };
4′h3: r_pwm_data <= { {09{1′b0}}, {23{1′b1}} };
4′h2: r_pwm_data <= { {11{1′b0}}, {21{1′b1}} };
4′h1: r_pwm_data <= { {13{1′b0}}, {19{1′b1}} };
4′h0: r_pwm_data <= { {15{1′b0}}, {17{1′b1}} };
4′hf: r_pwm_data <= { {17{1′b0}}, {15{1′b1}} };
4′he: r_pwm_data <= { {19{1′b0}}, {13{1′b1}} };
4′hd: r_pwm_data <= { {21{1′b0}}, {11{1′b1}} };
4′hc: r_pwm_data <= { {23{1′b0}}, {09{1′b1}} };
4′hb: r_pwm_data <= { {25{1′b0}}, {07{1′b1}} };
4′ha: r_pwm_data <= { {27{1′b0}}, {05{1′b1}} };
4′h9: r_pwm_data <= { {29{1′b0}}, {03{1′b1}} };
4′h8: r_pwm_data <= { {31{1′b0}}, {01{1′b1}} };
endcase
end
end
assign o_pwm_data = r_pwm_data[31:0];
endmodule
module shift_reg(
input clk,
input rst_n,
input [31: 0] i_pwm_data,
output o_pwm
);
reg [4:0] r_step;
always @(posedge clk or negedge rst_n ) begin: step
if( ~rst_n ) begin
r_step <= 1′b0;
end
else begin
r_step <= r_step + 1;
end
end
reg r_reverse;
always @(posedge clk or negedge rst_n ) begin: reverse
if( ~rst_n ) begin
r_reverse <= 1′b0;
end
else begin
if( r_step == 0) r_reverse <= ~r_reverse;
end
end
reg [31:0] r_shift;
always @(posedge clk or negedge rst_n ) begin: shift
if( ~rst_n ) begin
r_shift <= 0;
end
else begin
if( r_step == 0 ) r_shift <= i_pwm_data;
else if( r_reverse ) r_shift <= { 1′b0, r_shift[31:1] };
else r_shift <= { r_shift[30:0], 1′b0 };
end
end
reg r_pwm;
always @(posedge clk or negedge rst_n) begin: pwm
if( ~rst_n ) begin
r_pwm <= 1′b0;
end
else begin
if( r_reverse ) r_pwm <= r_shift[0];
else r_pwm <= r_shift[31];
end
end
assign o_pwm = r_pwm;
// ***********dump pwm
integer fp_pwm;
initial fp_pwm= $fopen("pwm.txt");
always@(negedge clk) $fwrite(fp_pwm,"%h\n",o_pwm);
endmodule