mirror of
https://github.com/MiSTer-devel/MacPlus_MiSTer.git
synced 2024-12-03 10:49:42 +00:00
297 lines
4.4 KiB
Verilog
297 lines
4.4 KiB
Verilog
|
|
module audio_out
|
|
#(
|
|
parameter CLK_RATE = 24576000
|
|
)
|
|
(
|
|
input reset,
|
|
input clk,
|
|
|
|
//0 - 48KHz, 1 - 96KHz
|
|
input sample_rate,
|
|
|
|
input [31:0] flt_rate,
|
|
input [39:0] cx,
|
|
input [7:0] cx0,
|
|
input [7:0] cx1,
|
|
input [7:0] cx2,
|
|
input [23:0] cy0,
|
|
input [23:0] cy1,
|
|
input [23:0] cy2,
|
|
|
|
input [4:0] att,
|
|
input [1:0] mix,
|
|
|
|
input is_signed,
|
|
input [15:0] core_l,
|
|
input [15:0] core_r,
|
|
|
|
input [15:0] alsa_l,
|
|
input [15:0] alsa_r,
|
|
|
|
// I2S
|
|
output i2s_bclk,
|
|
output i2s_lrclk,
|
|
output i2s_data,
|
|
|
|
// SPDIF
|
|
output spdif,
|
|
|
|
// Sigma-Delta DAC
|
|
output dac_l,
|
|
output dac_r
|
|
);
|
|
|
|
localparam AUDIO_RATE = 48000;
|
|
localparam AUDIO_DW = 16;
|
|
|
|
localparam CE_RATE = AUDIO_RATE*AUDIO_DW*8;
|
|
localparam FILTER_DIV = (CE_RATE/(AUDIO_RATE*32))-1;
|
|
|
|
wire [31:0] real_ce = sample_rate ? {CE_RATE[30:0],1'b0} : CE_RATE[31:0];
|
|
|
|
reg mclk_ce;
|
|
always @(posedge clk) begin
|
|
reg [31:0] cnt;
|
|
|
|
mclk_ce = 0;
|
|
cnt = cnt + real_ce;
|
|
if(cnt >= CLK_RATE) begin
|
|
cnt = cnt - CLK_RATE;
|
|
mclk_ce = 1;
|
|
end
|
|
end
|
|
|
|
reg i2s_ce;
|
|
always @(posedge clk) begin
|
|
reg div;
|
|
i2s_ce <= 0;
|
|
if(mclk_ce) begin
|
|
div <= ~div;
|
|
i2s_ce <= div;
|
|
end
|
|
end
|
|
|
|
i2s i2s
|
|
(
|
|
.reset(reset),
|
|
|
|
.clk(clk),
|
|
.ce(i2s_ce),
|
|
|
|
.sclk(i2s_bclk),
|
|
.lrclk(i2s_lrclk),
|
|
.sdata(i2s_data),
|
|
|
|
.left_chan(al),
|
|
.right_chan(ar)
|
|
);
|
|
|
|
spdif toslink
|
|
(
|
|
.rst_i(reset),
|
|
|
|
.clk_i(clk),
|
|
.bit_out_en_i(mclk_ce),
|
|
|
|
.sample_i({ar,al}),
|
|
.spdif_o(spdif)
|
|
);
|
|
|
|
sigma_delta_dac #(15) sd_l
|
|
(
|
|
.CLK(clk),
|
|
.RESET(reset),
|
|
.DACin({~al[15], al[14:0]}),
|
|
.DACout(dac_l)
|
|
);
|
|
|
|
sigma_delta_dac #(15) sd_r
|
|
(
|
|
.CLK(clk),
|
|
.RESET(reset),
|
|
.DACin({~ar[15], ar[14:0]}),
|
|
.DACout(dac_r)
|
|
);
|
|
|
|
reg sample_ce;
|
|
always @(posedge clk) begin
|
|
reg [8:0] div = 0;
|
|
reg [1:0] add = 0;
|
|
|
|
div <= div + add;
|
|
if(!div) begin
|
|
div <= 2'd1 << sample_rate;
|
|
add <= 2'd1 << sample_rate;
|
|
end
|
|
|
|
sample_ce <= !div;
|
|
end
|
|
|
|
reg flt_ce;
|
|
always @(posedge clk) begin
|
|
reg [31:0] cnt = 0;
|
|
|
|
flt_ce = 0;
|
|
cnt = cnt + {flt_rate[30:0],1'b0};
|
|
if(cnt >= CLK_RATE) begin
|
|
cnt = cnt - CLK_RATE;
|
|
flt_ce = 1;
|
|
end
|
|
end
|
|
|
|
reg [15:0] cl,cr;
|
|
always @(posedge clk) begin
|
|
reg [15:0] cl1,cl2;
|
|
reg [15:0] cr1,cr2;
|
|
|
|
cl1 <= core_l; cl2 <= cl1;
|
|
if(cl2 == cl1) cl <= cl2;
|
|
|
|
cr1 <= core_r; cr2 <= cr1;
|
|
if(cr2 == cr1) cr <= cr2;
|
|
end
|
|
|
|
reg a_en1 = 0, a_en2 = 0;
|
|
always @(posedge clk, posedge reset) begin
|
|
reg [1:0] dly1 = 0;
|
|
reg [14:0] dly2 = 0;
|
|
|
|
if(reset) begin
|
|
dly1 <= 0;
|
|
dly2 <= 0;
|
|
a_en1 <= 0;
|
|
a_en2 <= 0;
|
|
end
|
|
else begin
|
|
if(flt_ce) begin
|
|
if(~&dly1) dly1 <= dly1 + 1'd1;
|
|
else a_en1 <= 1;
|
|
end
|
|
|
|
if(sample_ce) begin
|
|
if(!dly2[13+sample_rate]) dly2 <= dly2 + 1'd1;
|
|
else a_en2 <= 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
wire [15:0] acl, acr;
|
|
IIR_filter #(.use_params(0)) IIR_filter
|
|
(
|
|
.clk(clk),
|
|
.reset(reset),
|
|
|
|
.ce(flt_ce & a_en1),
|
|
.sample_ce(sample_ce),
|
|
|
|
.cx(cx),
|
|
.cx0(cx0),
|
|
.cx1(cx1),
|
|
.cx2(cx2),
|
|
.cy0(cy0),
|
|
.cy1(cy1),
|
|
.cy2(cy2),
|
|
|
|
.input_l({~is_signed ^ cl[15], cl[14:0]}),
|
|
.input_r({~is_signed ^ cr[15], cr[14:0]}),
|
|
.output_l(acl),
|
|
.output_r(acr)
|
|
);
|
|
|
|
wire [15:0] adl;
|
|
DC_blocker dcb_l
|
|
(
|
|
.clk(clk),
|
|
.ce(sample_ce),
|
|
.sample_rate(sample_rate),
|
|
.mute(~a_en2),
|
|
.din(acl),
|
|
.dout(adl)
|
|
);
|
|
|
|
wire [15:0] adr;
|
|
DC_blocker dcb_r
|
|
(
|
|
.clk(clk),
|
|
.ce(sample_ce),
|
|
.sample_rate(sample_rate),
|
|
.mute(~a_en2),
|
|
.din(acr),
|
|
.dout(adr)
|
|
);
|
|
|
|
wire [15:0] al, audio_l_pre;
|
|
aud_mix_top audmix_l
|
|
(
|
|
.clk(clk),
|
|
.ce(sample_ce),
|
|
.att(att),
|
|
.mix(mix),
|
|
|
|
.core_audio(adl),
|
|
.pre_in(audio_r_pre),
|
|
.linux_audio(alsa_l),
|
|
|
|
.pre_out(audio_l_pre),
|
|
.out(al)
|
|
);
|
|
|
|
wire [15:0] ar, audio_r_pre;
|
|
aud_mix_top audmix_r
|
|
(
|
|
.clk(clk),
|
|
.ce(sample_ce),
|
|
.att(att),
|
|
.mix(mix),
|
|
|
|
.core_audio(adr),
|
|
.pre_in(audio_l_pre),
|
|
.linux_audio(alsa_r),
|
|
|
|
.pre_out(audio_r_pre),
|
|
.out(ar)
|
|
);
|
|
|
|
endmodule
|
|
|
|
module aud_mix_top
|
|
(
|
|
input clk,
|
|
input ce,
|
|
|
|
input [4:0] att,
|
|
input [1:0] mix,
|
|
|
|
input [15:0] core_audio,
|
|
input [15:0] linux_audio,
|
|
input [15:0] pre_in,
|
|
|
|
output reg [15:0] pre_out = 0,
|
|
output reg [15:0] out = 0
|
|
);
|
|
|
|
reg signed [16:0] a1, a2, a3, a4;
|
|
always @(posedge clk) if (ce) begin
|
|
|
|
a1 <= {core_audio[15],core_audio};
|
|
a2 <= a1 + {linux_audio[15],linux_audio};
|
|
|
|
pre_out <= a2[16:1];
|
|
|
|
case(mix)
|
|
0: a3 <= a2;
|
|
1: a3 <= $signed(a2) - $signed(a2[16:3]) + $signed(pre_in[15:2]);
|
|
2: a3 <= $signed(a2) - $signed(a2[16:2]) + $signed(pre_in[15:1]);
|
|
3: a3 <= {a2[16],a2[16:1]} + {pre_in[15],pre_in};
|
|
endcase
|
|
|
|
if(att[4]) a4 <= 0;
|
|
else a4 <= a3 >>> att[3:0];
|
|
|
|
//clamping
|
|
out <= ^a4[16:15] ? {a4[16],{15{a4[15]}}} : a4[15:0];
|
|
end
|
|
|
|
endmodule
|