forked from ultraembedded/cores
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspdif.v
185 lines (162 loc) · 5.29 KB
/
spdif.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//-----------------------------------------------------------------
// SPDIF Transmitter
// V0.1
// Ultra-Embedded.com
// Copyright 2012
//
// Email: [email protected]
//
// 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