labor-mst/xillinux-syn/vhdl/src/i2s_audio.v
2020-04-26 11:42:06 +02:00

151 lines
3.9 KiB
Verilog

module i2s_audio
(
input bus_clk,
input quiesce,
input clk_100,
output reg audio_mclk,
output reg audio_dac,
input audio_adc,
input audio_bclk,
input audio_lrclk,
input user_w_audio_wren,
input [31:0] user_w_audio_data,
output user_w_audio_full,
input user_w_audio_open,
input user_r_audio_rden,
output [31:0] user_r_audio_data,
output user_r_audio_empty,
output user_r_audio_eof,
input user_r_audio_open
);
reg audio_adc_reg;
reg audio_bclk_reg;
reg audio_lrclk_reg;
reg audio_lrclk_reg_d;
reg [1:0] clk_div;
reg [15:0] play_shreg;
reg [1:0] bclk_d;
reg fifo_rd_en;
wire bclk_rising, bclk_falling;
wire [31:0] play_fifo_data;
reg [31:0] record_shreg;
reg [4:0] record_count;
reg write_when_done;
reg fifo_wr_en;
// synthesis attribute IOB of audio_mclk is TRUE
// synthesis attribute IOB of audio_dac is TRUE
// synthesis attribute IOB of audio_adc_reg is TRUE
// synthesis attribute IOB of audio_bclk_reg is TRUE
// synthesis attribute IOB of audio_lrclk_reg is TRUE
assign user_r_audio_eof = 0;
// Produce a 25 MHz clock for MCLK
always @(posedge clk_100)
begin
clk_div <= clk_div + 1;
audio_mclk <= clk_div[1];
end
assign bclk_rising = (bclk_d == 2'b01);
assign bclk_falling = (bclk_d == 2'b10);
// BCLK runs at 3.072 MHz, so the signals are sampled and handled
// synchronously, with an obvious delay, which is negligble compared
// with a BCLK clock cycle.
always @(posedge bus_clk)
begin
audio_adc_reg <= audio_adc;
audio_bclk_reg <= audio_bclk;
audio_lrclk_reg <= audio_lrclk;
bclk_d <= { bclk_d, audio_bclk_reg };
if (bclk_rising)
audio_lrclk_reg_d <= audio_lrclk_reg;
// Playback
fifo_rd_en <= 0; // Possibly overridden below
if (bclk_rising && !audio_lrclk_reg && audio_lrclk_reg_d)
play_shreg <= play_fifo_data[31:16]; // Left channel
else if (bclk_rising && audio_lrclk_reg && !audio_lrclk_reg_d)
begin
play_shreg <= play_fifo_data[15:0]; // Right channel
fifo_rd_en <= 1;
end
else if (bclk_falling)
begin
audio_dac <= play_shreg[15];
play_shreg <= { play_shreg, 1'b0 };
end
// Recording
fifo_wr_en <= 0; // Possibly overridden below
if (bclk_rising && (record_count != 0))
begin
record_shreg <= { record_shreg, audio_adc_reg };
record_count <= record_count - 1;
if (record_count == 1)
begin
fifo_wr_en <= write_when_done;
write_when_done <= 0;
end
end
if (bclk_rising && !audio_lrclk_reg && audio_lrclk_reg_d)
begin
record_count <= 16;
write_when_done <= 0;
end
else if (bclk_rising && audio_lrclk_reg && !audio_lrclk_reg_d)
begin
record_count <= 16;
write_when_done <= 1;
end
end
// Note that there is no check on the empty line. If the FIFO is empty,
// it will emit the same output all the time, so the audio output will be
// silent, which is fairly OK for an underrun.
fifo_32x512 playback_fifo
(
.clk(bus_clk),
.srst(!user_w_audio_open),
.din(user_w_audio_data), // Bus [31 : 0]
.wr_en(user_w_audio_wren),
.rd_en(fifo_rd_en),
.dout(play_fifo_data), // Bus [31 : 0]
.full(user_w_audio_full),
.empty());
// The full lines isn't checked. Not much to do on an overrun
fifo_32x512 record_fifo
(
.clk(bus_clk),
.srst(!user_r_audio_open),
.din(record_shreg), // Bus [31 : 0]
.wr_en(fifo_wr_en),
.rd_en(user_r_audio_rden),
.dout(user_r_audio_data), // Bus [31 : 0]
.full(),
.empty(user_r_audio_empty));
endmodule