399 lines
15 KiB
VHDL
399 lines
15 KiB
VHDL
|
----------------------------------------------------------------------
|
||
|
---- ----
|
||
|
---- WISHBONE SPDIF IP Core ----
|
||
|
---- ----
|
||
|
---- This file is part of the SPDIF project ----
|
||
|
---- http://www.opencores.org/cores/spdif_interface/ ----
|
||
|
---- ----
|
||
|
---- Description ----
|
||
|
---- Oversampling phase detector. Decodes bi-phase mark encoded ----
|
||
|
---- signal. Clock must be at least 8 times higher than bit rate. ----
|
||
|
---- The SPDIF bitrate must be minimum 100kHz. ----
|
||
|
---- ----
|
||
|
---- To Do: ----
|
||
|
---- - ----
|
||
|
---- ----
|
||
|
---- Author(s): ----
|
||
|
---- - Geir Drange, gedra@opencores.org ----
|
||
|
---- ----
|
||
|
----------------------------------------------------------------------
|
||
|
---- ----
|
||
|
---- Copyright (C) 2004 Authors and OPENCORES.ORG ----
|
||
|
---- ----
|
||
|
---- This source file may be used and distributed without ----
|
||
|
---- restriction provided that this copyright statement is not ----
|
||
|
---- removed from the file and that any derivative work contains ----
|
||
|
---- the original copyright notice and the associated disclaimer. ----
|
||
|
---- ----
|
||
|
---- This source file is free software; you can redistribute it ----
|
||
|
---- and/or modify it under the terms of the GNU Lesser General ----
|
||
|
---- Public License as published by the Free Software Foundation; ----
|
||
|
---- either version 2.1 of the License, or (at your option) any ----
|
||
|
---- later version. ----
|
||
|
---- ----
|
||
|
---- This source 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 Lesser General Public License for more ----
|
||
|
---- details. ----
|
||
|
---- ----
|
||
|
---- You should have received a copy of the GNU Lesser General ----
|
||
|
---- Public License along with this source; if not, download it ----
|
||
|
---- from http://www.opencores.org/lgpl.shtml ----
|
||
|
---- ----
|
||
|
----------------------------------------------------------------------
|
||
|
--
|
||
|
-- CVS Revision History
|
||
|
--
|
||
|
-- $Log: not supported by cvs2svn $
|
||
|
-- Revision 1.5 2004/07/19 16:58:37 gedra
|
||
|
-- Fixed bug.
|
||
|
--
|
||
|
-- Revision 1.4 2004/07/12 17:06:41 gedra
|
||
|
-- Fixed bug with lock event generation.
|
||
|
--
|
||
|
-- Revision 1.3 2004/07/11 16:19:50 gedra
|
||
|
-- Bug-fix.
|
||
|
--
|
||
|
-- Revision 1.2 2004/06/13 18:08:50 gedra
|
||
|
-- Renamed generic and cleaned some lint's
|
||
|
--
|
||
|
-- Revision 1.1 2004/06/06 15:43:02 gedra
|
||
|
-- Early version of the bi-phase mark decoder.
|
||
|
--
|
||
|
--
|
||
|
|
||
|
library ieee;
|
||
|
use ieee.std_logic_1164.all;
|
||
|
|
||
|
entity rx_phase_det is
|
||
|
generic (AXI_FREQ: natural := 100); -- WishBone frequency in MHz
|
||
|
port (
|
||
|
up_clk: in std_logic; -- wishbone clock
|
||
|
rxen: in std_logic; -- phase detector enable
|
||
|
spdif: in std_logic; -- SPDIF input signal
|
||
|
lock: out std_logic; -- true if locked to spdif input
|
||
|
lock_evt: out std_logic; -- lock status change event
|
||
|
rx_data: out std_logic; -- recevied data
|
||
|
rx_data_en: out std_logic; -- received data enable
|
||
|
rx_block_start: out std_logic; -- start-of-block pulse
|
||
|
rx_frame_start: out std_logic; -- start-of-frame pulse
|
||
|
rx_channel_a: out std_logic; -- 1 if channel A frame is recevied
|
||
|
rx_error: out std_logic; -- signal error was detected
|
||
|
ud_a_en: out std_logic; -- user data ch. A enable
|
||
|
ud_b_en: out std_logic; -- user data ch. B enable
|
||
|
cs_a_en: out std_logic; -- channel status ch. A enable
|
||
|
cs_b_en: out std_logic); -- channel status ch. B enable);
|
||
|
end rx_phase_det;
|
||
|
|
||
|
architecture rtl of rx_phase_det is
|
||
|
|
||
|
constant TRANSITIONS : integer := 70;
|
||
|
constant FRAMES_FOR_LOCK : integer := 3;
|
||
|
signal maxpulse, maxp, mp_cnt: integer range 0 to 16 * AXI_FREQ;
|
||
|
signal last_cnt, max_thres : integer range 0 to 16 * AXI_FREQ;
|
||
|
signal minpulse, minp, min_thres: integer range 0 to 8 * AXI_FREQ;
|
||
|
signal zspdif, spdif_in, zspdif_in, trans, ztrans : std_logic;
|
||
|
signal trans_cnt : integer range 0 to TRANSITIONS;
|
||
|
signal valid, p_long, p_short: std_logic;
|
||
|
type pulse_type is (ZERO, SHORT, MED, LONG);
|
||
|
type pulse_array is array (0 to 3) of pulse_type;
|
||
|
signal preamble: pulse_array;
|
||
|
signal new_pulse, short_idx, ilock: std_logic;
|
||
|
type frame_state is (IDLE, HUNT, FRAMESTART, FRAME_RX);
|
||
|
signal framerx : frame_state;
|
||
|
signal frame_cnt : integer range 0 to FRAMES_FOR_LOCK;
|
||
|
signal bit_cnt : integer range 0 to 63;
|
||
|
signal pre_cnt : integer range 0 to 7;
|
||
|
type preamble_types is (NONE, PRE_X, PRE_Y, PRE_Z);
|
||
|
signal new_preamble, last_preamble : preamble_types;
|
||
|
signal irx_channel_a, zilock : std_logic;
|
||
|
|
||
|
begin
|
||
|
|
||
|
-- Pulse width analyzer
|
||
|
PHDET: process (up_clk, rxen)
|
||
|
begin
|
||
|
if rxen = '0' then -- reset by configuration register bit
|
||
|
maxpulse <= 0;
|
||
|
maxp <= 0;
|
||
|
mp_cnt <= 0;
|
||
|
zspdif <= '0';
|
||
|
zspdif_in <= '0';
|
||
|
spdif_in <= '0';
|
||
|
trans_cnt <= 0;
|
||
|
minpulse <= 0;
|
||
|
minp <= 8 * AXI_FREQ;
|
||
|
last_cnt <= 0;
|
||
|
trans <= '0';
|
||
|
valid <= '0';
|
||
|
preamble <= (ZERO, ZERO, ZERO, ZERO);
|
||
|
max_thres <= 0;
|
||
|
min_thres <= 0;
|
||
|
new_preamble <= NONE;
|
||
|
ztrans <= '0';
|
||
|
new_pulse <= '0';
|
||
|
else
|
||
|
if rising_edge(up_clk) then
|
||
|
-- sync spdif signal to wishbone clock
|
||
|
zspdif <= spdif;
|
||
|
spdif_in <= zspdif;
|
||
|
-- find the longest pulse, which is the bi-phase violation
|
||
|
-- also find the shortest pulse
|
||
|
zspdif_in <= spdif_in;
|
||
|
if zspdif_in /= spdif_in then -- input transition
|
||
|
mp_cnt <= 0;
|
||
|
trans <= '1';
|
||
|
last_cnt <= mp_cnt;
|
||
|
if trans_cnt > 0 then
|
||
|
if mp_cnt > maxp then
|
||
|
maxp <= mp_cnt;
|
||
|
end if;
|
||
|
if mp_cnt < minp then
|
||
|
minp <= mp_cnt;
|
||
|
end if;
|
||
|
end if;
|
||
|
else
|
||
|
trans <= '0';
|
||
|
if mp_cnt < 16 * AXI_FREQ then
|
||
|
mp_cnt <= mp_cnt + 1;
|
||
|
end if;
|
||
|
end if;
|
||
|
-- transition counting
|
||
|
if trans = '1' then
|
||
|
if trans_cnt < TRANSITIONS then
|
||
|
trans_cnt <= trans_cnt + 1;
|
||
|
else
|
||
|
-- the max/min pulse length is updated after given # of transitions
|
||
|
trans_cnt <= 0;
|
||
|
maxpulse <= maxp;
|
||
|
maxp <= 0;
|
||
|
minpulse <= minp;
|
||
|
minp <= 8 * AXI_FREQ;
|
||
|
min_thres <= maxp / 2;
|
||
|
if maxp < 11 then
|
||
|
max_thres <= maxp - 1;
|
||
|
else
|
||
|
max_thres <= maxp - 3;
|
||
|
end if;
|
||
|
end if;
|
||
|
end if;
|
||
|
-- detection of valid SPDIF signal
|
||
|
if maxpulse > 6 then
|
||
|
valid <= '1';
|
||
|
else
|
||
|
valid <= '0';
|
||
|
end if;
|
||
|
-- bit decoding
|
||
|
if trans = '1' then
|
||
|
if (last_cnt < min_thres) and (last_cnt > 0) then
|
||
|
p_short <= '1';
|
||
|
preamble(0) <= SHORT;
|
||
|
else
|
||
|
p_short <= '0';
|
||
|
end if;
|
||
|
if last_cnt >= max_thres then
|
||
|
p_long <= '1';
|
||
|
preamble(0) <= LONG;
|
||
|
else
|
||
|
p_long <= '0';
|
||
|
end if;
|
||
|
if last_cnt = 0 then
|
||
|
preamble(0) <= ZERO;
|
||
|
end if;
|
||
|
if (last_cnt < max_thres) and (last_cnt >= min_thres) then
|
||
|
preamble(0) <= MED;
|
||
|
end if;
|
||
|
preamble(3) <= preamble(2);
|
||
|
preamble(2) <= preamble(1);
|
||
|
preamble(1) <= preamble(0);
|
||
|
end if;
|
||
|
-- preamble detection
|
||
|
if preamble(3) = LONG and preamble(2) = LONG and preamble(1) = SHORT
|
||
|
and preamble(0) = SHORT then
|
||
|
new_preamble <= PRE_X;
|
||
|
elsif preamble(3) = LONG and preamble(2) = MED and preamble(1) = SHORT
|
||
|
and preamble(0) = MED then
|
||
|
new_preamble <= PRE_Y;
|
||
|
elsif preamble(3) = LONG and preamble(2) = SHORT and preamble(1) = SHORT
|
||
|
and preamble(0) = LONG then
|
||
|
new_preamble <= PRE_Z;
|
||
|
else
|
||
|
new_preamble <= NONE;
|
||
|
end if;
|
||
|
-- delayed transition pulse for the state machine
|
||
|
ztrans <= trans;
|
||
|
new_pulse <= ztrans;
|
||
|
end if;
|
||
|
end if;
|
||
|
end process;
|
||
|
|
||
|
lock <= ilock;
|
||
|
rx_channel_a <= irx_channel_a;
|
||
|
|
||
|
-- State machine that hunt for and lock onto sub-frames
|
||
|
FRX: process (up_clk, rxen)
|
||
|
begin
|
||
|
if rxen = '0' then
|
||
|
framerx <= IDLE;
|
||
|
ilock <= '0';
|
||
|
zilock <= '0';
|
||
|
rx_data <= '0';
|
||
|
rx_data_en <= '0';
|
||
|
rx_block_start <= '0';
|
||
|
rx_frame_start <= '0';
|
||
|
irx_channel_a <= '0';
|
||
|
ud_a_en <= '0';
|
||
|
ud_b_en <= '0';
|
||
|
cs_a_en <= '0';
|
||
|
cs_b_en <= '0';
|
||
|
rx_error <= '0';
|
||
|
lock_evt <= '0';
|
||
|
bit_cnt <= 0;
|
||
|
pre_cnt <= 0;
|
||
|
short_idx <= '0';
|
||
|
frame_cnt <= 0;
|
||
|
last_preamble <= NONE;
|
||
|
elsif rising_edge(up_clk) then
|
||
|
zilock <= ilock;
|
||
|
if zilock /= ilock then -- generate event for event reg.
|
||
|
lock_evt <= '1';
|
||
|
else
|
||
|
lock_evt <= '0';
|
||
|
end if;
|
||
|
case framerx is
|
||
|
when IDLE => -- wait for recevier to be enabled
|
||
|
if valid = '1' then
|
||
|
framerx <= HUNT;
|
||
|
end if;
|
||
|
when HUNT => -- wait for preamble detection
|
||
|
frame_cnt <= 0;
|
||
|
ilock <= '0';
|
||
|
rx_error <= '0';
|
||
|
if new_pulse = '1' then
|
||
|
if new_preamble /= NONE then
|
||
|
framerx <= FRAMESTART;
|
||
|
end if;
|
||
|
end if;
|
||
|
when FRAMESTART => -- reset sub-frame bit counter
|
||
|
bit_cnt <= 0;
|
||
|
pre_cnt <= 0;
|
||
|
if frame_cnt < FRAMES_FOR_LOCK then
|
||
|
frame_cnt <= frame_cnt + 1;
|
||
|
else
|
||
|
ilock <= '1';
|
||
|
end if;
|
||
|
last_preamble <= new_preamble;
|
||
|
short_idx <= '0';
|
||
|
rx_frame_start <= '1';
|
||
|
rx_block_start <= '0';
|
||
|
framerx <= FRAME_RX;
|
||
|
when FRAME_RX => -- receive complete sub-frame
|
||
|
if new_pulse = '1' then
|
||
|
if bit_cnt < 28 then
|
||
|
case preamble(0) is
|
||
|
when ZERO =>
|
||
|
short_idx <= '0';
|
||
|
when SHORT =>
|
||
|
if short_idx = '0' then
|
||
|
short_idx <= '1';
|
||
|
else
|
||
|
-- two short pulses is a logical '1'
|
||
|
bit_cnt <= bit_cnt + 1;
|
||
|
short_idx <= '0';
|
||
|
rx_data <= '1';
|
||
|
rx_data_en <= ilock;
|
||
|
-- user data enable for the capture register
|
||
|
if bit_cnt = 25 and ilock = '1' then
|
||
|
ud_a_en <= irx_channel_a;
|
||
|
ud_b_en <= not irx_channel_a;
|
||
|
end if;
|
||
|
-- channel status enable for the capture register
|
||
|
if bit_cnt = 26 and ilock = '1' then
|
||
|
cs_a_en <= irx_channel_a;
|
||
|
cs_b_en <= not irx_channel_a;
|
||
|
end if;
|
||
|
end if;
|
||
|
when MED =>
|
||
|
-- medium pulse is logical '0'
|
||
|
bit_cnt <= bit_cnt + 1;
|
||
|
rx_data <= '0';
|
||
|
rx_data_en <= ilock;
|
||
|
short_idx <= '0';
|
||
|
-- user data enable for the capture register
|
||
|
if bit_cnt = 25 and ilock = '1' then
|
||
|
ud_a_en <= irx_channel_a;
|
||
|
ud_b_en <= not irx_channel_a;
|
||
|
end if;
|
||
|
-- channel status enable for the capture register
|
||
|
if bit_cnt = 26 and ilock = '1' then
|
||
|
cs_a_en <= irx_channel_a;
|
||
|
cs_b_en <= not irx_channel_a;
|
||
|
end if;
|
||
|
when LONG =>
|
||
|
short_idx <= '0';
|
||
|
when others =>
|
||
|
framerx <= HUNT;
|
||
|
end case;
|
||
|
else
|
||
|
-- there should be 4 pulses in preamble
|
||
|
if pre_cnt < 7 then
|
||
|
pre_cnt <= pre_cnt + 1;
|
||
|
else
|
||
|
rx_error <= '1';
|
||
|
framerx <= HUNT;
|
||
|
end if;
|
||
|
-- check for correct preamble here
|
||
|
if pre_cnt = 3 then
|
||
|
case last_preamble is
|
||
|
when PRE_X =>
|
||
|
if new_preamble = PRE_Y then
|
||
|
framerx <= FRAMESTART;
|
||
|
irx_channel_a <= '0';
|
||
|
else
|
||
|
rx_error <= '1';
|
||
|
framerx <= HUNT;
|
||
|
end if;
|
||
|
when PRE_Y =>
|
||
|
if new_preamble = PRE_X or new_preamble = PRE_Z then
|
||
|
irx_channel_a <= '1';
|
||
|
-- start of new block?
|
||
|
if new_preamble = PRE_Z then
|
||
|
rx_block_start <= '1';
|
||
|
end if;
|
||
|
framerx <= FRAMESTART;
|
||
|
else
|
||
|
rx_error <= '1';
|
||
|
framerx <= HUNT;
|
||
|
end if;
|
||
|
when PRE_Z =>
|
||
|
if new_preamble = PRE_Y then
|
||
|
irx_channel_a <= '0';
|
||
|
framerx <= FRAMESTART;
|
||
|
else
|
||
|
rx_error <= '1';
|
||
|
framerx <= HUNT;
|
||
|
end if;
|
||
|
when others =>
|
||
|
rx_error <= '1';
|
||
|
framerx <= HUNT;
|
||
|
end case;
|
||
|
end if;
|
||
|
end if;
|
||
|
else
|
||
|
rx_data_en <= '0';
|
||
|
rx_block_start <= '0';
|
||
|
rx_frame_start <= '0';
|
||
|
ud_a_en <= '0';
|
||
|
ud_b_en <= '0';
|
||
|
cs_a_en <= '0';
|
||
|
cs_b_en <= '0';
|
||
|
end if;
|
||
|
when others =>
|
||
|
framerx <= IDLE;
|
||
|
end case;
|
||
|
end if;
|
||
|
end process FRX;
|
||
|
|
||
|
end rtl;
|