OpenCores
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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.