URL
https://opencores.org/ocsvn/spdif_transmitter/spdif_transmitter/trunk
Subversion Repositories spdif_transmitter
Compare Revisions
- This comparison shows the changes necessary to convert path
/spdif_transmitter/trunk
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/rtl/spdif_core.v
0,0 → 1,303
//----------------------------------------------------------------- |
// SPDIF Transmitter |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// If you would like a version with a more permissive license for |
// use in closed source commercial applications please contact me |
// for details. |
//----------------------------------------------------------------- |
// |
// This file is open source HDL; you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as |
// published by the Free Software Foundation; either version 2 of |
// the License, or (at your option) any later version. |
// |
// This file is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public |
// License along with this file; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
// USA |
//----------------------------------------------------------------- |
module spdif_core |
( |
input clk_i, |
input rst_i, |
|
// SPDIF bit output enable |
// Single cycle pulse synchronous to clk_i which drives |
// the output bit rate. |
// For 44.1KHz, 44100×32×2×2 = 5,644,800Hz |
// For 48KHz, 48000×32×2×2 = 6,144,000Hz |
input bit_out_en_i, |
|
// Output |
output spdif_o, |
|
// Audio interface (16-bit x 2 = RL) |
input [31:0] sample_i, |
output reg sample_req_o |
); |
|
//----------------------------------------------------------------- |
// Registers |
//----------------------------------------------------------------- |
reg [15:0] audio_sample_q; |
reg [8:0] subframe_count_q; |
|
reg load_subframe_q; |
reg [7:0] preamble_q; |
wire [31:0] subframe_w; |
|
reg [5:0] bit_count_q; |
reg bit_toggle_q; |
|
// Xilinx: Place output flop in IOB |
//synthesis attribute IOB of spdif_out_q is "TRUE" |
reg spdif_out_q; |
|
reg [5:0] parity_count_q; |
|
//----------------------------------------------------------------- |
// Subframe Counter |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
subframe_count_q <= 9'd0; |
else if (load_subframe_q) |
begin |
// 192 frames (384 subframes) in an audio block |
if (subframe_count_q == 9'd383) |
subframe_count_q <= 9'd0; |
else |
subframe_count_q <= subframe_count_q + 9'd1; |
end |
end |
|
//----------------------------------------------------------------- |
// Sample capture |
//----------------------------------------------------------------- |
reg [15:0] sample_buf_q; |
|
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
audio_sample_q <= 16'h0000; |
sample_buf_q <= 16'h0000; |
sample_req_o <= 1'b0; |
end |
else if (load_subframe_q) |
begin |
// Start of frame (first subframe)? |
if (subframe_count_q[0] == 1'b0) |
begin |
// Use left sample |
audio_sample_q <= sample_i[15:0]; |
|
// Store right sample |
sample_buf_q <= sample_i[31:16]; |
|
// Request next sample |
sample_req_o <= 1'b1; |
end |
else |
begin |
// Use right sample |
audio_sample_q <= sample_buf_q; |
|
sample_req_o <= 1'b0; |
end |
end |
else |
sample_req_o <= 1'b0; |
end |
|
// Timeslots 3 - 0 = Preamble |
assign subframe_w[3:0] = 4'b0000; |
|
// Timeslots 7 - 4 = 24-bit audio LSB |
assign subframe_w[7:4] = 4'b0000; |
|
// Timeslots 11 - 8 = 20-bit audio LSB |
assign subframe_w[11:8] = 4'b0000; |
|
// Timeslots 27 - 12 = 16-bit audio |
assign subframe_w[27:12] = audio_sample_q; |
|
// Timeslots 28 = Validity |
assign subframe_w[28] = 1'b0; // Valid |
|
// Timeslots 29 = User bit |
assign subframe_w[29] = 1'b0; |
|
// Timeslots 30 = Channel status bit |
assign subframe_w[30] = 1'b0; |
|
// Timeslots 31 = Even Parity bit (31:4) |
assign subframe_w[31] = 1'b0; |
|
//----------------------------------------------------------------- |
// Preamble |
//----------------------------------------------------------------- |
localparam PREAMBLE_Z = 8'b00010111; |
localparam PREAMBLE_Y = 8'b00100111; |
localparam PREAMBLE_X = 8'b01000111; |
|
reg [7:0] preamble_r; |
|
always @ * |
begin |
// Start of audio block? |
// Z(B) - Left channel |
if (subframe_count_q == 9'd0) |
preamble_r = PREAMBLE_Z; // Z(B) |
// Right Channel? |
else if (subframe_count_q[0] == 1'b1) |
preamble_r = PREAMBLE_Y; // Y(W) |
// Left Channel (but not start of block)? |
else |
preamble_r = PREAMBLE_X; // X(M) |
|
// If previous timeslot ended with a 1, invert preamble |
if (spdif_o) |
preamble_r = ~preamble_r; |
end |
|
always @ (posedge rst_i or posedge clk_i ) |
if (rst_i == 1'b1) |
preamble_q <= 8'h00; |
else if (load_subframe_q) |
preamble_q <= preamble_r; |
|
//----------------------------------------------------------------- |
// Parity Counter |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
parity_count_q <= 6'd0; |
end |
// Time to output a bit? |
else if (bit_out_en_i) |
begin |
// Preamble bits? |
if (bit_count_q < 6'd8) |
begin |
parity_count_q <= 6'd0; |
end |
// Normal timeslots |
else if (bit_count_q < 6'd62) |
begin |
// On first pass through this timeslot, count number of high bits |
if (bit_count_q[0] == 0 && subframe_w[bit_count_q / 2] == 1'b1) |
parity_count_q <= parity_count_q + 6'd1; |
end |
end |
end |
|
//----------------------------------------------------------------- |
// Bit Counter |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
begin |
if (rst_i == 1'b1) |
begin |
bit_count_q <= 6'b0; |
load_subframe_q <= 1'b1; |
end |
// Time to output a bit? |
else if (bit_out_en_i) |
begin |
// 32 timeslots (x2 for double frequency) |
if (bit_count_q == 6'd63) |
begin |
bit_count_q <= 6'd0; |
load_subframe_q <= 1'b1; |
end |
else |
begin |
bit_count_q <= bit_count_q + 6'd1; |
load_subframe_q <= 1'b0; |
end |
end |
else |
load_subframe_q <= 1'b0; |
end |
|
//----------------------------------------------------------------- |
// Bit half toggle |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i == 1'b1) |
bit_toggle_q <= 1'b0; |
// Time to output a bit? |
else if (bit_out_en_i) |
bit_toggle_q <= ~bit_toggle_q; |
|
//----------------------------------------------------------------- |
// Output bit (BMC encoded) |
//----------------------------------------------------------------- |
reg bit_r; |
|
always @ * |
begin |
bit_r = spdif_out_q; |
|
// Time to output a bit? |
if (bit_out_en_i) |
begin |
// Preamble bits? |
if (bit_count_q < 6'd8) |
begin |
bit_r = preamble_q[bit_count_q[2:0]]; |
end |
// Normal timeslots |
else if (bit_count_q < 6'd62) |
begin |
if (subframe_w[bit_count_q / 2] == 1'b0) |
begin |
if (bit_toggle_q == 1'b0) |
bit_r = ~spdif_out_q; |
else |
bit_r = spdif_out_q; |
end |
else |
bit_r = ~spdif_out_q; |
end |
// Parity timeslot |
else |
begin |
// Even number of high bits, make odd |
if (parity_count_q[0] == 1'b0) |
begin |
if (bit_toggle_q == 1'b0) |
bit_r = ~spdif_out_q; |
else |
bit_r = spdif_out_q; |
end |
else |
bit_r = ~spdif_out_q; |
end |
end |
end |
|
always @ (posedge rst_i or posedge clk_i ) |
if (rst_i == 1'b1) |
spdif_out_q <= 1'b0; |
else |
spdif_out_q <= bit_r; |
|
assign spdif_o = spdif_out_q; |
|
endmodule |
/rtl/spdif.v
0,0 → 1,185
//----------------------------------------------------------------- |
// SPDIF Transmitter |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// If you would like a version with a more permissive license for |
// use in closed source commercial applications please contact me |
// for details. |
//----------------------------------------------------------------- |
// |
// This file is open source HDL; you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as |
// published by the Free Software Foundation; either version 2 of |
// the License, or (at your option) any later version. |
// |
// This file is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public |
// License along with this file; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
// USA |
//----------------------------------------------------------------- |
module spdif |
|
//----------------------------------------------------------------- |
// Params |
//----------------------------------------------------------------- |
#( |
parameter CLK_RATE_KHZ = 50000, |
parameter AUDIO_RATE = 44100, |
parameter AUDIO_CLK_SRC = "EXTERNAL", // INTERNAL or EXTERNAL |
|
// Generated params |
parameter WHOLE_CYCLES = (CLK_RATE_KHZ*1000) / (AUDIO_RATE*128), |
parameter ERROR_BASE = 10000, |
parameter [63:0] ERRORS_PER_BIT = ((CLK_RATE_KHZ * 1000 * ERROR_BASE) / (AUDIO_RATE*128)) - (WHOLE_CYCLES * ERROR_BASE) |
) |
|
//----------------------------------------------------------------- |
// Ports |
//----------------------------------------------------------------- |
( |
input clk_i, |
input rst_i, |
|
// Audio clock source (only used when AUDIO_CLK_SRC=EXTERNAL) |
input audio_clk_i, |
|
// Output |
output spdif_o, |
|
// Audio interface (16-bit x 2 = RL) |
input [31:0] sample_i, |
output sample_req_o |
); |
|
//----------------------------------------------------------------- |
// External clock source |
//----------------------------------------------------------------- |
wire bit_clock_w; |
generate |
if (AUDIO_CLK_SRC == "EXTERNAL") |
begin |
// Toggling flop in audio_clk_i domain |
reg toggle_aud_clk_q; |
|
always @ (posedge rst_i or posedge audio_clk_i) |
if (rst_i) |
toggle_aud_clk_q <= 1'b0; |
else |
toggle_aud_clk_q <= ~toggle_aud_clk_q; |
|
// Resync toggle_aud_clk_q to clk_i domain |
reg resync_toggle_ms_q; |
reg resync_toggle_q; |
|
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
begin |
resync_toggle_ms_q <= 1'b0; |
resync_toggle_q <= 1'b0; |
end |
else |
begin |
resync_toggle_ms_q <= toggle_aud_clk_q; |
resync_toggle_q <= resync_toggle_ms_q; |
end |
|
reg last_toggle_q; |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
last_toggle_q <= 1'b0; |
else |
last_toggle_q <= resync_toggle_q; |
|
// Single cycle pulse on every rising edge of audio_clk_i |
assign bit_clock_w = last_toggle_q ^ resync_toggle_q; |
end |
//----------------------------------------------------------------- |
// Internal clock source |
//----------------------------------------------------------------- |
else |
begin |
reg [31:0] count_q; |
reg [31:0] error_q; |
reg bit_clk_q; |
|
// Clock pulse generator |
always @ (posedge rst_i or posedge clk_i) |
begin |
if (rst_i) |
begin |
count_q <= 32'd0; |
error_q <= 32'd0; |
bit_clk_q <= 1'b1; |
end |
else |
begin |
case (count_q) |
0 : |
begin |
bit_clk_q <= 1'b1; |
count_q <= count_q + 32'd1; |
end |
|
WHOLE_CYCLES-1: |
begin |
if (error_q < (ERROR_BASE - ERRORS_PER_BIT)) |
begin |
error_q <= error_q + ERRORS_PER_BIT; |
count_q <= 32'd0; |
end |
else |
begin |
error_q <= error_q + ERRORS_PER_BIT - ERROR_BASE; |
count_q <= count_q + 32'd1; |
end |
|
bit_clk_q <= 1'b0; |
end |
|
WHOLE_CYCLES: |
begin |
count_q <= 32'd0; |
bit_clk_q <= 1'b0; |
end |
|
default: |
begin |
count_q <= count_q + 32'd1; |
bit_clk_q <= 1'b0; |
end |
endcase |
end |
end |
|
assign bit_clock_w = bit_clk_q; |
end |
endgenerate |
|
//----------------------------------------------------------------- |
// Core SPDIF |
//----------------------------------------------------------------- |
spdif_core |
u_core |
( |
.clk_i(clk_i), |
.rst_i(rst_i), |
|
.bit_out_en_i(bit_clock_w), |
|
.spdif_o(spdif_o), |
|
.sample_i(sample_i), |
.sample_req_o(sample_req_o) |
); |
|
endmodule |