Skip to content

Instantly share code, notes, and snippets.

@DatanoiseTV
Created June 20, 2024 03:01
Show Gist options
  • Save DatanoiseTV/6eed01690855a6bdc67ea86d3625fb91 to your computer and use it in GitHub Desktop.
Save DatanoiseTV/6eed01690855a6bdc67ea86d3625fb91 to your computer and use it in GitHub Desktop.
// Verilog ADAT receiver - based on https://opencores.org/projects/adat_optical_feed_forward_receiver
module ADAT_receiver (
input m_clk,
input adat_in,
output reg [3:0] adat_user, // ADAT user bits
output reg adat_wordclock, // ADAT wordclock out (approx 50% symmetry)
output reg i2s_bclk, // I2S bit clock
output reg i2s_lrclk, // I2S left-right clock
output reg i2s_data0, // I2S data channel 0
output reg i2s_data1, // I2S data channel 1
output reg i2s_data2, // I2S data channel 2
output reg i2s_data3 // I2S data channel 3
);
reg [1:0] adat_input_shift;
reg adat_edge_detect;
reg [1:0] adat_edge_shift;
reg [9:0] adat_edge_cur_time = 10'b0;
reg [9:0] adat_edge_max_time = 10'b0;
reg [15:0] wait_increase;
reg [11:0] adat_inc_word_time = 12'b0;
reg [11:0] adat_cur_word_time = 12'b0;
reg [8:0] adat_sync_mask_time = 9'b0;
reg adat_sync_mask = 1'b0;
reg [1:0] adat_sync_mask_shift = 2'b0;
reg [7:0] adat_bit_counter = 8'b0;
reg [11:0] adat_bit_sample = 12'b0;
reg adat_bit_clk;
reg [1:0] adat_data;
reg [255:0] adat_data_shift = {256{1'b1}};
reg [23:0] audio_buffer_0, audio_buffer_1, audio_buffer_2, audio_buffer_3;
reg [23:0] audio_buffer_4, audio_buffer_5, audio_buffer_6, audio_buffer_7;
reg [9:0] lrclk_cnt = 0;
reg lrclk = 0;
// Instantiate the multiplier
wire [11:0] mult_result;
mult12x8 multiplier (
.dataa(adat_cur_word_time),
.datab(adat_bit_counter),
.result(mult_result)
);
always @(posedge m_clk) begin
adat_input_shift <= {adat_input_shift[0], adat_in};
end
always @(posedge m_clk) begin
if ((adat_input_shift == 2'b01) || (adat_input_shift == 2'b10)) begin
adat_edge_detect <= 1;
adat_edge_cur_time <= 0;
end else begin
adat_edge_cur_time <= adat_edge_cur_time + 1;
adat_edge_detect <= 0;
if (adat_edge_cur_time > adat_edge_max_time) begin
adat_edge_max_time <= adat_edge_cur_time;
wait_increase <= 0;
end else begin
wait_increase <= wait_increase + 1;
if (wait_increase == (1 << (wait_increase[15:0] - 1))) begin
adat_edge_max_time <= adat_edge_max_time - 1;
end
end
end
end
always @(posedge m_clk) begin
adat_edge_shift <= {adat_edge_shift[0], adat_edge_detect};
end
always @(posedge m_clk) begin
adat_sync_mask_time <= adat_edge_max_time[9:1] + adat_edge_max_time[9:2];
if (adat_edge_cur_time <= adat_sync_mask_time) begin
adat_sync_mask <= 1;
end else begin
adat_sync_mask <= 0;
end
end
always @(posedge m_clk) begin
adat_sync_mask_shift <= {adat_sync_mask_shift[0], adat_sync_mask};
end
always @(posedge m_clk) begin
adat_inc_word_time <= adat_inc_word_time + 1;
if (adat_edge_detect && !adat_sync_mask) begin
adat_cur_word_time <= adat_inc_word_time;
adat_bit_counter <= 0; // set to bit 0 for first sample point
end
if (adat_sync_mask_shift == 2'b01) begin
adat_inc_word_time <= 0;
end
if (adat_inc_word_time == mult_result) begin
adat_bit_clk <= 1;
adat_data <= {adat_data[0], adat_in};
adat_bit_counter <= adat_bit_counter + 1;
end else begin
adat_bit_clk <= 0;
end
end
always @(posedge adat_bit_clk) begin
if ((adat_data == 2'b00) || (adat_data == 2'b11)) begin
adat_data_shift <= {adat_data_shift[254:0], 1'b0};
end else begin
adat_data_shift <= {adat_data_shift[254:0], 1'b1};
end
end
always @(posedge adat_bit_clk) begin
if (adat_bit_counter <= 8'd127) begin
adat_wordclock <= 0;
end else begin
adat_wordclock <= 1;
end
end
always @(posedge adat_bit_clk) begin
if (adat_data_shift[255:246] == 10'b0000000000) begin
adat_user <= adat_data_shift[245:242];
audio_buffer_0 <= {adat_data_shift[241:238], adat_data_shift[237:234], adat_data_shift[233:230], adat_data_shift[229:226], adat_data_shift[225:222], adat_data_shift[221:218]};
audio_buffer_1 <= {adat_data_shift[217:214], adat_data_shift[213:210], adat_data_shift[209:206], adat_data_shift[205:202], adat_data_shift[201:198], adat_data_shift[197:194]};
audio_buffer_2 <= {adat_data_shift[193:190], adat_data_shift[189:186], adat_data_shift[185:182], adat_data_shift[181:178], adat_data_shift[177:174], adat_data_shift[173:170]};
audio_buffer_3 <= {adat_data_shift[169:166], adat_data_shift[165:162], adat_data_shift[161:158], adat_data_shift[157:154], adat_data_shift[153:150], adat_data_shift[149:146]};
audio_buffer_4 <= {adat_data_shift[145:142], adat_data_shift[141:138], adat_data_shift[137:134], adat_data_shift[133:130], adat_data_shift[129:126], adat_data_shift[125:122]};
audio_buffer_5 <= {adat_data_shift[121:118], adat_data_shift[117:114], adat_data_shift[113:110], adat_data_shift[109:106], adat_data_shift[105:102], adat_data_shift[101:98]};
audio_buffer_6 <= {adat_data_shift[97:94], adat_data_shift[93:90], adat_data_shift[89:86], adat_data_shift[85:82], adat_data_shift[81:78], adat_data_shift[77:74]};
audio_buffer_7 <= {adat_data_shift[73:70], adat_data_shift[69:66], adat_data_shift[65:62], adat_data_shift[61:58], adat_data_shift[57:54], adat_data_shift[53:50]};
end
end
// I2S Bit Clock Generation
always @(posedge m_clk) begin
lrclk_cnt <= lrclk_cnt + 1;
if (lrclk_cnt == 32) begin // Assuming 32 bits per LRCLK period
lrclk <= ~lrclk;
lrclk_cnt <= 0;
end
i2s_bclk <= ~i2s_bclk; // BCLK runs at double the speed of m_clk
end
// I2S Data Transmission
always @(posedge i2s_bclk) begin
if (lrclk == 0) begin
i2s_data0 <= audio_buffer_0[23];
audio_buffer_0 <= {audio_buffer_0[22:0], 1'b0};
i2s_data1 <= audio_buffer_1[23];
audio_buffer_1 <= {audio_buffer_1[22:0], 1'b0};
i2s_data2 <= audio_buffer_2[23];
audio_buffer_2 <= {audio_buffer_2[22:0], 1'b0};
i2s_data3 <= audio_buffer_3[23];
audio_buffer_3 <= {audio_buffer_3[22:0], 1'b0};
end else begin
i2s_data0 <= audio_buffer_4[23];
audio_buffer_4 <= {audio_buffer_4[22:0], 1'b0};
i2s_data1 <= audio_buffer_5[23];
audio_buffer_5 <= {audio_buffer_5[22:0], 1'b0};
i2s_data2 <= audio_buffer_6[23];
audio_buffer_6 <= {audio_buffer_6[22:0], 1'b0};
i2s_data3 <= audio_buffer_7[23];
audio_buffer_7 <= {audio_buffer_7[22:0], 1'b0};
end
end
assign i2s_lrclk = lrclk;
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment