mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-06 16:14:42 +00:00
130 lines
4.9 KiB
Verilog
130 lines
4.9 KiB
Verilog
// sigmadelta.v
|
|
// two channel second order sigma delta dac
|
|
// taken from Minimig
|
|
|
|
// audio data processing
|
|
// stereo sigma/delta bitstream modulator
|
|
module sigma_delta_dac (
|
|
input clk, // bus clock
|
|
input [14:0] ldatasum, // left channel data
|
|
input [14:0] rdatasum, // right channel data
|
|
output reg left=0, // left bitstream output
|
|
output reg right=0 // right bitsteam output
|
|
);
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
// local signals
|
|
localparam DW = 15;
|
|
localparam CW = 2;
|
|
localparam RW = 4;
|
|
localparam A1W = 2;
|
|
localparam A2W = 5;
|
|
|
|
wire [DW+2+0 -1:0] sd_l_er0, sd_r_er0;
|
|
reg [DW+2+0 -1:0] sd_l_er0_prev=0, sd_r_er0_prev=0;
|
|
wire [DW+A1W+2-1:0] sd_l_aca1, sd_r_aca1;
|
|
wire [DW+A2W+2-1:0] sd_l_aca2, sd_r_aca2;
|
|
reg [DW+A1W+2-1:0] sd_l_ac1=0, sd_r_ac1=0;
|
|
reg [DW+A2W+2-1:0] sd_l_ac2=0, sd_r_ac2=0;
|
|
wire [DW+A2W+3-1:0] sd_l_quant, sd_r_quant;
|
|
|
|
// LPF noise LFSR
|
|
reg [24-1:0] seed1 = 24'h654321;
|
|
reg [19-1:0] seed2 = 19'h12345;
|
|
reg [24-1:0] seed_sum=0, seed_prev=0, seed_out=0;
|
|
always @ (posedge clk) begin
|
|
if (&seed1)
|
|
seed1 <= #1 24'h654321;
|
|
else
|
|
seed1 <= #1 {seed1[22:0], ~(seed1[23] ^ seed1[22] ^ seed1[21] ^ seed1[16])};
|
|
end
|
|
always @ (posedge clk) begin
|
|
if (&seed2)
|
|
seed2 <= #1 19'h12345;
|
|
else
|
|
seed2 <= #1 {seed2[17:0], ~(seed2[18] ^ seed2[17] ^ seed2[16] ^ seed2[13] ^ seed2[0])};
|
|
end
|
|
always @ (posedge clk) begin
|
|
seed_sum <= #1 seed1 + {5'b0, seed2};
|
|
seed_prev <= #1 seed_sum;
|
|
seed_out <= #1 seed_sum - seed_prev;
|
|
end
|
|
|
|
// linear interpolate
|
|
localparam ID=4; // counter size, also 2^ID = interpolation rate
|
|
reg [ID+0-1:0] int_cnt = 0;
|
|
always @ (posedge clk) int_cnt <= #1 int_cnt + 'd1;
|
|
|
|
reg [DW+0-1:0] ldata_cur=0, ldata_prev=0;
|
|
reg [DW+0-1:0] rdata_cur=0, rdata_prev=0;
|
|
wire [DW+1-1:0] ldata_step, rdata_step;
|
|
reg [DW+ID-1:0] ldata_int=0, rdata_int=0;
|
|
wire [DW+0-1:0] ldata_int_out, rdata_int_out;
|
|
assign ldata_step = {ldata_cur[DW-1], ldata_cur} - {ldata_prev[DW-1], ldata_prev}; // signed subtract
|
|
assign rdata_step = {rdata_cur[DW-1], rdata_cur} - {rdata_prev[DW-1], rdata_prev}; // signed subtract
|
|
always @ (posedge clk) begin
|
|
if (~|int_cnt) begin
|
|
ldata_prev <= #1 ldata_cur;
|
|
ldata_cur <= #1 ldatasum; //{~ldatasum[DW-1], ldatasum[DW-2:0]}; // convert to offset binary, samples no longer signed!
|
|
rdata_prev <= #1 rdata_cur;
|
|
rdata_cur <= #1 rdatasum; //{~rdatasum[DW-1], rdatasum[DW-2:0]}; // convert to offset binary, samples no longer signed!
|
|
ldata_int <= #1 {ldata_cur[DW-1], ldata_cur, {ID{1'b0}}};
|
|
rdata_int <= #1 {rdata_cur[DW-1], rdata_cur, {ID{1'b0}}};
|
|
end else begin
|
|
ldata_int <= #1 ldata_int + {{ID{ldata_step[DW+1-1]}}, ldata_step};
|
|
rdata_int <= #1 rdata_int + {{ID{rdata_step[DW+1-1]}}, rdata_step};
|
|
end
|
|
end
|
|
assign ldata_int_out = ldata_int[DW+ID-1:ID];
|
|
assign rdata_int_out = rdata_int[DW+ID-1:ID];
|
|
|
|
// input gain x3
|
|
wire [DW+2-1:0] ldata_gain, rdata_gain;
|
|
assign ldata_gain = {ldata_int_out[DW-1], ldata_int_out, 1'b0} + {{(2){ldata_int_out[DW-1]}}, ldata_int_out};
|
|
assign rdata_gain = {rdata_int_out[DW-1], rdata_int_out, 1'b0} + {{(2){rdata_int_out[DW-1]}}, rdata_int_out};
|
|
|
|
/*
|
|
// random dither to 15 bits
|
|
reg [DW-1:0] ldata=0, rdata=0;
|
|
always @ (posedge clk) begin
|
|
ldata <= #1 ldata_gain[DW+2-1:2] + ( (~(&ldata_gain[DW+2-1-1:2]) && (ldata_gain[1:0] > seed_out[1:0])) ? 15'd1 : 15'd0 );
|
|
rdata <= #1 rdata_gain[DW+2-1:2] + ( (~(&ldata_gain[DW+2-1-1:2]) && (ldata_gain[1:0] > seed_out[1:0])) ? 15'd1 : 15'd0 );
|
|
end
|
|
*/
|
|
|
|
// accumulator adders
|
|
assign sd_l_aca1 = {{(A1W){ldata_gain[DW+2-1]}}, ldata_gain} - {{(A1W){sd_l_er0[DW+2-1]}}, sd_l_er0} + sd_l_ac1;
|
|
assign sd_r_aca1 = {{(A1W){rdata_gain[DW+2-1]}}, rdata_gain} - {{(A1W){sd_r_er0[DW+2-1]}}, sd_r_er0} + sd_r_ac1;
|
|
|
|
assign sd_l_aca2 = {{(A2W-A1W){sd_l_aca1[DW+A1W+2-1]}}, sd_l_aca1} - {{(A2W){sd_l_er0[DW+2-1]}}, sd_l_er0} - {{(A2W+1){sd_l_er0_prev[DW+2-1]}}, sd_l_er0_prev[DW+2-1:1]} + sd_l_ac2;
|
|
assign sd_r_aca2 = {{(A2W-A1W){sd_r_aca1[DW+A1W+2-1]}}, sd_r_aca1} - {{(A2W){sd_r_er0[DW+2-1]}}, sd_r_er0} - {{(A2W+1){sd_r_er0_prev[DW+2-1]}}, sd_r_er0_prev[DW+2-1:1]} + sd_r_ac2;
|
|
|
|
// accumulators
|
|
always @ (posedge clk) begin
|
|
sd_l_ac1 <= #1 sd_l_aca1;
|
|
sd_r_ac1 <= #1 sd_r_aca1;
|
|
sd_l_ac2 <= #1 sd_l_aca2;
|
|
sd_r_ac2 <= #1 sd_r_aca2;
|
|
end
|
|
|
|
// value for quantizaton
|
|
assign sd_l_quant = {sd_l_ac2[DW+A2W+2-1], sd_l_ac2} + {{(DW+A2W+3-RW){seed_out[RW-1]}}, seed_out[RW-1:0]};
|
|
assign sd_r_quant = {sd_r_ac2[DW+A2W+2-1], sd_r_ac2} + {{(DW+A2W+3-RW){seed_out[RW-1]}}, seed_out[RW-1:0]};
|
|
|
|
// error feedback
|
|
assign sd_l_er0 = sd_l_quant[DW+A2W+3-1] ? {1'b1, {(DW+2-1){1'b0}}} : {1'b0, {(DW+2-1){1'b1}}};
|
|
assign sd_r_er0 = sd_r_quant[DW+A2W+3-1] ? {1'b1, {(DW+2-1){1'b0}}} : {1'b0, {(DW+2-1){1'b1}}};
|
|
always @ (posedge clk) begin
|
|
sd_l_er0_prev <= #1 (&sd_l_er0) ? sd_l_er0 : sd_l_er0+1;
|
|
sd_r_er0_prev <= #1 (&sd_r_er0) ? sd_r_er0 : sd_r_er0+1;
|
|
end
|
|
|
|
// output
|
|
always @ (posedge clk) begin
|
|
left <= #1 (~|ldata_gain) ? ~left : ~sd_l_er0[DW+2-1];
|
|
right <= #1 (~|rdata_gain) ? ~right : ~sd_r_er0[DW+2-1];
|
|
end
|
|
|
|
endmodule
|