URL
https://opencores.org/ocsvn/usb11_phy_translation/usb11_phy_translation/trunk
Subversion Repositories usb11_phy_translation
Compare Revisions
- This comparison shows the changes necessary to convert path
/usb11_phy_translation
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/trunk/usb_tx_phy.vhdl
0,0 → 1,419
--======================================================================================-- |
-- Verilog to VHDL conversion by Martin Neumann martin@neumnns-mail.de -- |
-- -- |
-- /////////////////////////////////////////////////////////////////// -- |
-- // // -- |
-- // USB 1.1 PHY // -- |
-- // TX // -- |
-- // // -- |
-- // // -- |
-- // Author: Rudolf Usselmann // -- |
-- // rudi@asics.ws // -- |
-- // // -- |
-- // // -- |
-- // Downloaded from: http://www.opencores.org/cores/usb_phy/ // -- |
-- // // -- |
-- /////////////////////////////////////////////////////////////////// -- |
-- // // -- |
-- // Copyright (C) 2000-2002 Rudolf Usselmann // -- |
-- // www.asics.ws // -- |
-- // rudi@asics.ws // -- |
-- // // -- |
-- // 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY // -- |
-- // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // -- |
-- // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // -- |
-- // FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR // -- |
-- // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // -- |
-- // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // -- |
-- // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // -- |
-- // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // -- |
-- // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // -- |
-- // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // -- |
-- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // -- |
-- // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // -- |
-- // POSSIBILITY OF SUCH DAMAGE. // -- |
-- // // -- |
-- /////////////////////////////////////////////////////////////////// -- |
--======================================================================================-- |
|
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_arith.all; |
use ieee.std_logic_unsigned.all; |
|
entity usb_tx_phy is |
port ( |
clk : in std_logic; |
rst : in std_logic; |
fs_ce : in std_logic; |
phy_mode : in std_logic; |
-- Transciever Interface |
txdp, txdn, txoe : out std_logic; |
-- UTMI Interface |
DataOut_i : in std_logic_vector(7 downto 0); |
TxValid_i : in std_logic; |
TxReady_o : out std_logic |
); |
end usb_tx_phy; |
|
architecture RTL of usb_tx_phy is |
|
signal hold_reg : std_logic_vector(7 downto 0); |
signal ld_data : std_logic; |
signal ld_data_d : std_logic; |
signal ld_eop_d : std_logic; |
signal ld_sop_d : std_logic; |
signal bit_cnt : std_logic_vector(2 downto 0); |
signal sft_done_e : std_logic; |
signal append_eop : std_logic; |
signal append_eop_sync1 : std_logic; |
signal append_eop_sync2 : std_logic; |
signal append_eop_sync3 : std_logic; |
signal append_eop_sync4 : std_logic; |
signal data_done : std_logic; |
signal eop_done : std_logic; |
signal hold_reg_d : std_logic_vector(7 downto 0); |
signal one_cnt : std_logic_vector(2 downto 0); |
signal sd_bs_o : std_logic; |
signal sd_nrzi_o : std_logic; |
signal sd_raw_o : std_logic; |
signal sft_done : std_logic; |
signal sft_done_r : std_logic; |
signal state, next_state : std_logic_vector(2 downto 0); |
signal stuff : std_logic; |
signal tx_ip : std_logic; |
signal tx_ip_sync : std_logic; |
signal txoe_r1, txoe_r2 : std_logic; |
|
constant IDLE_STATE : std_logic_vector := "000"; |
constant SOP_STATE : std_logic_vector := "001"; |
constant DATA_STATE : std_logic_vector := "010"; |
constant EOP1_STATE : std_logic_vector := "011"; |
constant EOP2_STATE : std_logic_vector := "100"; |
constant WAIT_STATE : std_logic_vector := "101"; |
|
begin |
|
--======================================================================================-- |
-- Misc Logic -- |
--======================================================================================-- |
|
p_TxReady_o: process (clk, rst) |
begin |
if rst ='0' then |
TxReady_o <= '0'; |
elsif rising_edge(clk) then |
TxReady_o <= ld_data_d and TxValid_i; |
end if; |
end process; |
|
p_ld_data: process (clk) |
begin |
if rising_edge(clk) then |
ld_data <= ld_data_d; |
end if; |
end process; |
|
--======================================================================================-- |
-- Transmit in progress indicator -- |
--======================================================================================-- |
|
p_tx_ip: process (clk, rst) |
begin |
if rst ='0' then |
tx_ip <= '0'; |
elsif rising_edge(clk) then |
if ld_sop_d ='1' then |
tx_ip <= '1'; |
elsif eop_done ='1' then |
tx_ip <= '0'; |
end if; |
end if; |
end process; |
|
p_tx_ip_sync: process (clk, rst) |
begin |
if rst ='0' then |
tx_ip_sync <= '0'; |
elsif rising_edge(clk) then |
if fs_ce ='1' then |
tx_ip_sync <= tx_ip; |
end if; |
end if; |
end process; |
|
-- data_done helps us to catch cases where TxValid drops due to |
-- packet end and then gets re-asserted as a new packet starts. |
-- We might not see this because we are still transmitting. |
-- data_done should solve those cases ... |
p_data_done: process (clk, rst) |
begin |
if rst ='0' then |
data_done <= '0'; |
elsif rising_edge(clk) then |
if TxValid_i ='1' and tx_ip ='0' then |
data_done <= '1'; |
elsif TxValid_i = '0' then |
data_done <= '0'; |
end if; |
end if; |
end process; |
|
--======================================================================================-- |
-- Shift Register -- |
--======================================================================================-- |
|
p_bit_cnt: process (clk, rst) |
begin |
if rst ='0' then |
bit_cnt <= "000"; |
elsif rising_edge(clk) then |
if tx_ip_sync ='0' then |
bit_cnt <= "000"; |
elsif fs_ce ='1' and stuff ='0' then |
bit_cnt <= bit_cnt + 1; |
end if; |
end if; |
end process; |
|
p_sd_raw_o: process (clk) |
begin |
if rising_edge(clk) then |
if tx_ip_sync ='0' then |
sd_raw_o <= '0'; |
else |
sd_raw_o <= hold_reg_d(CONV_INTEGER(UNSIGNED(bit_cnt))); |
end if; |
end if; |
end process; |
|
p_sft_done: process (clk) |
begin |
if rising_edge(clk) then |
if bit_cnt = "111" then |
sft_done <= not stuff; |
else |
sft_done <= '0'; |
end if; |
end if; |
end process; |
|
p_sft_done_r: process (clk) |
begin |
if rising_edge(clk) then |
sft_done_r <= sft_done; |
end if; |
end process; |
|
sft_done_e <= sft_done and not sft_done_r; |
|
-- Out Data Hold Register |
p_hold_reg: process (clk) |
begin |
if rst ='0' then |
hold_reg <= X"00"; |
hold_reg_d <= X"00"; |
elsif rising_edge(clk) then |
if ld_sop_d ='1' then |
hold_reg <= X"80"; |
elsif ld_data ='1' then |
hold_reg <= DataOut_i; |
end if; |
hold_reg_d <= hold_reg; |
end if; |
end process; |
|
--======================================================================================-- |
-- Bit Stuffer -- |
--======================================================================================-- |
|
p_one_cnt: process (clk, rst) |
begin |
if rst ='0' then |
one_cnt <= "000"; |
elsif rising_edge(clk) then |
if tx_ip_sync ='0' then |
one_cnt <= "000"; |
elsif fs_ce ='1' then |
if sd_raw_o ='0' or stuff = '1' then |
one_cnt <= "000"; |
else |
one_cnt <= one_cnt + 1; |
end if; |
end if; |
end if; |
end process; |
|
stuff <= '1' when one_cnt = "110" else '0'; |
|
p_sd_bs_o: process (clk, rst) |
begin |
if rst ='0' then |
sd_bs_o <= '0'; |
elsif rising_edge(clk) then |
if fs_ce ='1' then |
if tx_ip_sync ='0' then |
sd_bs_o <= '0'; |
else |
if stuff ='1' then |
sd_bs_o <= '0'; |
else |
sd_bs_o <= sd_raw_o; |
end if; |
end if; |
end if; |
end if; |
end process; |
|
--======================================================================================-- |
-- NRZI Encoder -- |
--======================================================================================-- |
|
p_sd_nrzi_o: process (clk, rst) |
begin |
if rst ='0' then |
sd_nrzi_o <= '1'; |
elsif rising_edge(clk) then |
if tx_ip_sync ='0' or txoe_r1 ='0' then |
sd_nrzi_o <= '1'; |
elsif fs_ce ='1' then |
if sd_bs_o ='1' then |
sd_nrzi_o <= sd_nrzi_o; |
else |
sd_nrzi_o <= not sd_nrzi_o; |
end if; |
end if; |
end if; |
end process; |
|
--======================================================================================-- |
-- EOP append logic -- |
--======================================================================================-- |
|
p_append_eop: process (clk, rst) |
begin |
if rst ='0' then |
append_eop <= '0'; |
elsif rising_edge(clk) then |
if ld_eop_d ='1' then |
append_eop <= '1'; |
elsif append_eop_sync2 ='1' then |
append_eop <= '0'; |
end if; |
end if; |
end process; |
|
p_append_eop_sync: process (clk, rst) |
begin |
if rst ='0' then |
append_eop_sync1 <= '0'; |
append_eop_sync2 <= '0'; |
append_eop_sync3 <= '0'; |
append_eop_sync4 <= '0'; |
elsif rising_edge(clk) then |
if fs_ce ='1' then |
append_eop_sync1 <= append_eop; |
append_eop_sync2 <= append_eop_sync1; |
append_eop_sync3 <= append_eop_sync2 or -- Make sure always 2 bit wide |
(append_eop_sync3 and not append_eop_sync4); |
append_eop_sync4 <= append_eop_sync3; |
end if; |
end if; |
end process; |
|
eop_done <= append_eop_sync3; |
|
--======================================================================================-- |
-- Output Enable Logic -- |
--======================================================================================-- |
|
p_txoe: process (clk, rst) |
begin |
if rst ='0' then |
txoe_r1 <= '0'; |
txoe_r2 <= '0'; |
txoe <= '1'; |
elsif rising_edge(clk) then |
if fs_ce ='1' then |
txoe_r1 <= tx_ip_sync; |
txoe_r2 <= txoe_r1; |
txoe <= not (txoe_r1 or txoe_r2); |
end if; |
end if; |
end process; |
|
--======================================================================================-- |
-- Output Registers -- |
--======================================================================================-- |
|
p_txdpn: process (clk, rst) |
begin |
if rst ='0' then |
txdp <= '1'; |
txdn <= '0'; |
elsif rising_edge(clk) then |
if fs_ce ='1' then |
if phy_mode ='1' then |
txdp <= not append_eop_sync3 and sd_nrzi_o; |
txdn <= not append_eop_sync3 and not sd_nrzi_o; |
else |
txdp <= sd_nrzi_o; |
txdn <= append_eop_sync3; |
end if; |
end if; |
end if; |
end process; |
|
--======================================================================================-- |
-- Tx Statemashine -- |
--======================================================================================-- |
|
p_state: process (clk, rst) |
begin |
if rst ='0' then |
state <= IDLE_STATE; |
elsif rising_edge(clk) then |
state <= next_state; |
end if; |
end process; |
|
p_next_state: process (rst, state, TxValid_i, data_done, sft_done_e, eop_done, fs_ce) |
begin |
if rst='0' then |
next_state <= IDLE_STATE; |
else |
case (state) is |
when IDLE_STATE => if TxValid_i ='1' then |
next_state <= SOP_STATE; |
end if; |
when SOP_STATE => if sft_done_e ='1' then |
next_state <= DATA_STATE; |
end if; |
when DATA_STATE => if data_done ='0' and sft_done_e ='1' then |
next_state <= EOP1_STATE; |
end if; |
when EOP1_STATE => if eop_done ='1' then |
next_state <= EOP2_STATE; |
end if; |
when EOP2_STATE => if eop_done ='0' and fs_ce ='1' then |
next_state <= WAIT_STATE; |
end if; |
when others => if fs_ce = '1' then --is WAIT_STATE |
next_state <= IDLE_STATE; |
end if; |
end case; |
end if; |
end process; |
|
ld_sop_d <= TxValid_i when state = IDLE_STATE else '0'; |
ld_data_d <= sft_done_e when state = SOP_STATE or (state = DATA_STATE and data_done ='1') else '0'; |
ld_eop_d <= sft_done_e when state = Data_STATE and data_done ='0' else '0'; |
|
end RTL; |
|
/trunk/usb_rx_phy_60MHz.vhdl
0,0 → 1,486
--======================================================================================-- |
-- Verilog to VHDL conversion by Martin Neumann martin@neumnns-mail.de -- |
-- This is a 60 MHz version of the original 48 MHz design usb_rx_phy.v -- |
-- -- |
-- /////////////////////////////////////////////////////////////////// -- |
-- // // -- |
-- // USB 1.1 PHY // -- |
-- // RX & DPLL // -- |
-- // // -- |
-- // // -- |
-- // Author: Rudolf Usselmann // -- |
-- // rudi@asics.ws // -- |
-- // // -- |
-- // // -- |
-- // Downloaded from: http://www.opencores.org/cores/usb_phy/ // -- |
-- // // -- |
-- /////////////////////////////////////////////////////////////////// -- |
-- // // -- |
-- // Copyright (C) 2000-2002 Rudolf Usselmann // -- |
-- // www.asics.ws // -- |
-- // rudi@asics.ws // -- |
-- // // -- |
-- // 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY // -- |
-- // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // -- |
-- // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // -- |
-- // FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR // -- |
-- // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // -- |
-- // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // -- |
-- // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // -- |
-- // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // -- |
-- // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // -- |
-- // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // -- |
-- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // -- |
-- // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // -- |
-- // POSSIBILITY OF SUCH DAMAGE. // -- |
-- // // -- |
-- /////////////////////////////////////////////////////////////////// -- |
--======================================================================================-- |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_arith.all; |
use ieee.std_logic_unsigned.all; |
|
entity usb_rx_phy is |
port ( |
clk : in std_logic; |
rst : in std_logic; |
-- Transciever Interface |
fs_ce_o : out std_logic; |
rxd, rxdp, rxdn : in std_logic; |
-- UTMI Interface |
DataIn_o : out std_logic_vector(7 downto 0); |
RxValid_o : out std_logic; |
RxActive_o : out std_logic; |
RxError_o : out std_logic; |
RxEn_i : in std_logic; |
LineState : out std_logic_vector(1 downto 0) |
); |
end usb_rx_phy; |
|
architecture RTL of usb_rx_phy is |
|
signal fs_ce : std_logic; |
signal rxd_s0, rxd_s1, rxd_s : std_logic; |
signal rxdp_s0, rxdp_s1, rxdp_s, rxdp_s_r : std_logic; |
signal rxdn_s0, rxdn_s1, rxdn_s, rxdn_s_r : std_logic; |
signal synced_d : std_logic; |
signal k, j, se0 : std_logic; |
signal rxd_r : std_logic; |
signal rx_en : std_logic; |
signal rx_active : std_logic; |
signal bit_cnt : std_logic_vector(2 downto 0); |
signal rx_valid1, rx_valid : std_logic; |
signal shift_en : std_logic; |
signal sd_r : std_logic; |
signal sd_nrzi : std_logic; |
signal hold_reg : std_logic_vector(7 downto 0); |
signal drop_bit : std_logic; -- Indicates a stuffed bit |
signal one_cnt : std_logic_vector(2 downto 0); |
signal dpll_cntr : std_logic_vector(3 downto 0); |
signal change : std_logic; |
signal lock_en : std_logic; |
signal fs_state, fs_next_state : std_logic_vector(2 downto 0); |
signal rx_valid_r : std_logic; |
signal sync_err_d, sync_err : std_logic; |
signal bit_stuff_err, byte_err : std_logic; |
signal se0_r, se0_s : std_logic; |
|
constant FS_IDLE : std_logic_vector(2 downto 0) := "000"; |
constant K1 : std_logic_vector(2 downto 0) := "001"; |
constant J1 : std_logic_vector(2 downto 0) := "010"; |
constant K2 : std_logic_vector(2 downto 0) := "011"; |
constant J2 : std_logic_vector(2 downto 0) := "100"; |
constant K3 : std_logic_vector(2 downto 0) := "101"; |
constant J3 : std_logic_vector(2 downto 0) := "110"; |
constant K4 : std_logic_vector(2 downto 0) := "111"; |
|
begin |
|
--====================================================================================-- |
-- Misc Logic -- |
--====================================================================================-- |
|
fs_ce_o <= fs_ce; |
RxActive_o <= rx_active; |
RxValid_o <= rx_valid; |
RxError_o <= sync_err or bit_stuff_err or byte_err; |
DataIn_o <= hold_reg; |
LineState <= rxdn_s1 & rxdp_s1; |
|
p_rx_en: process (clk) |
begin |
if rising_edge(clk) then |
rx_en <= RxEn_i; |
end if; |
end process; |
|
p_sync_err: process (clk) |
begin |
if rst ='0' then |
sync_err <= '0'; |
elsif rising_edge(clk) then |
sync_err <= not rx_active and sync_err_d; |
end if; |
end process; |
|
--====================================================================================-- |
-- Synchronize Inputs -- |
--====================================================================================-- |
|
-- First synchronize to the local system clock to |
-- avoid metastability outside the sync block (*_s0). |
-- Then make sure we see the signal for at least two |
-- clock cycles stable to avoid glitches and noise |
|
p_rxd_s: process (clk) -- Avoid detecting Line Glitches and noise |
begin |
if rising_edge(clk) then |
rxd_s0 <= rxd; |
rxd_s1 <= rxd_s0; |
if rxd_s0 ='1' and rxd_s1 ='1' then |
rxd_s <= '1'; |
elsif not rxd_s0 ='1' and not rxd_s1 ='1' then |
rxd_s <= '0'; |
end if; |
end if; |
end process; |
|
p_rxdp_s: process (clk) |
begin |
if rising_edge(clk) then |
rxdp_s0 <= rxdp; |
rxdp_s1 <= rxdp_s0; |
rxdp_s_r <= rxdp_s0 and rxdp_s1; |
rxdp_s <= (rxdp_s0 and rxdp_s1) or rxdp_s_r; |
end if; |
end process; |
|
p_rxdn_s: process (clk) |
begin |
if rising_edge(clk) then |
rxdn_s0 <= rxdn; |
rxdn_s1 <= rxdn_s0; |
rxdn_s_r <= rxdn_s0 and rxdn_s1; |
rxdn_s <= (rxdn_s0 and rxdn_s1) or rxdn_s_r; |
end if; |
end process; |
|
j <= rxdp_s and not rxdn_s; |
k <= not rxdp_s and rxdn_s; |
se0 <= not rxdp_s and not rxdn_s; |
|
p_se0_s: process (clk) |
begin |
if rst ='0' then |
se0_s <= '0'; |
elsif rising_edge(clk) then |
if fs_ce ='1' then |
se0_s <= se0; |
end if; |
end if; |
end process; |
|
--====================================================================================-- |
-- DPLL, this section is modified and adopted for a 60 MHz clock (Martin Neumann) -- |
--====================================================================================-- |
|
-- This design uses a clock enable to do 12Mhz timing and not a |
-- real 12Mhz clock. Everything always runs at 60 Mhz. We want to |
-- make sure however, that the clock enable is always exactly in |
-- the middle between two virtual 12Mhz rising edges. |
-- We monitor rxdp and rxdn for any changes and do the appropiate |
-- adjustments. |
|
lock_en <= rx_en; -- Allow clock adjustments only when we are receiving |
|
p_rxd_r: process (clk) |
begin |
if rising_edge(clk) then |
rxd_r <= rxd_s; |
end if; |
end process; |
|
change <= rxd_r xor rxd_s; -- Edge detector |
|
p_dpll_cntr: process (clk, rst) |
begin |
if rst ='0' then |
dpll_cntr <= "0011"; |
elsif rising_edge(clk) then |
if lock_en = '1' and change = '1' then |
if dpll_cntr(3)='1' then |
dpll_cntr <= "0010"; -- fe_ce detected, now centered in following cycle |
else |
dpll_cntr <= "0111"; -- adjust fe_ce to center cycle |
end if; |
elsif dpll_cntr(3) = '1' then -- normal count sequence is 8->4->5->6->7->8->4... |
dpll_cntr <= "0100"; |
else |
dpll_cntr <= dpll_cntr +1; |
end if; |
end if; |
end process; |
|
fs_ce <= dpll_cntr(3); |
|
--====================================================================================-- |
-- Find Sync Pattern FSM -- |
--====================================================================================-- |
|
p_fs_state: process (clk, rst) |
begin |
if rst ='0' then |
fs_state <= FS_IDLE; |
elsif rising_edge(clk) then |
fs_state <= fs_next_state; |
end if; |
end process; |
|
p_fs_next_state: process (fs_state, fs_ce, k, j, rx_en, rx_active, se0, se0_s) |
begin |
if fs_ce='1' and rx_active='0' and se0='0' and se0_s='0' then |
case fs_state is |
when FS_IDLE => if k ='1' and rx_en ='1' then -- 0 |
fs_next_state <= K1; |
sync_err_d <= '0'; |
end if; |
when K1 => if j ='1' and rx_en ='1' then -- 1 |
fs_next_state <= J1; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when J1 => if k ='1' and rx_en ='1' then -- 2 |
fs_next_state <= K2; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when K2 => if j ='1' and rx_en ='1' then -- 3 |
fs_next_state <= J2; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when J2 => if k ='1' and rx_en ='1' then -- 4 |
fs_next_state <= K3; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when K3 => if j ='1' and rx_en ='1' then -- 5 |
fs_next_state <= J3; |
sync_err_d <= '0'; |
elsif k ='1' and rx_en ='1' then -- Allow missing first K-J |
fs_next_state <= FS_IDLE; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when J3 => if k ='1' and rx_en ='1' then -- 6 |
fs_next_state <= K4; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when K4 => if k ='1' and rx_en ='1' then -- 7 |
sync_err_d <= '0'; |
else |
sync_err_d <= '1'; |
end if; |
fs_next_state <= FS_IDLE; |
when others => fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end case; |
else |
fs_next_state <= fs_state; |
sync_err_d <= '0'; |
end if; |
end process; |
|
synced_d <= fs_ce and rx_en when (fs_state =K3 and k ='1') or -- Allow missing first K-J |
(fs_state =K4 and k ='1') else '0'; |
|
--====================================================================================-- |
-- Generate RxActive -- |
--====================================================================================-- |
|
p_rx_active: process (clk, rst) |
begin |
if rst ='0' then |
rx_active <= '0'; |
elsif rising_edge(clk) then |
if synced_d ='1' and rx_en ='1' then |
rx_active <= '1'; |
elsif se0 ='1' and rx_valid_r ='1' then |
rx_active <= '0'; |
end if; |
end if; |
end process; |
|
p_rx_valid_r: process (clk) |
begin |
if rst ='0' then |
rx_valid_r <= '0'; |
elsif rising_edge(clk) then |
if rx_valid ='1' then |
rx_valid_r <= '1'; |
elsif fs_ce ='1' then |
rx_valid_r <= '0'; |
end if; |
end if; |
end process; |
|
--====================================================================================-- |
-- NRZI Decoder -- |
--====================================================================================-- |
|
p_sd_r: process (clk) |
begin |
if rst ='0' then |
sd_r <= '0'; |
elsif rising_edge(clk) then |
if fs_ce ='1' then |
sd_r <= rxd_s; |
end if; |
end if; |
end process; |
|
p_sd_nrzi: process (clk, rst) |
begin |
if rst ='0' then |
sd_nrzi <= '0'; |
elsif rising_edge(clk) then |
if rx_active ='0' then |
sd_nrzi <= '1'; |
elsif rx_active ='1' and fs_ce ='1' then |
sd_nrzi <= not (rxd_s xor sd_r); |
end if; |
end if; |
end process; |
|
--====================================================================================-- |
-- Bit Stuff Detect -- |
--====================================================================================-- |
|
p_one_cnt: process (clk, rst) |
begin |
if rst ='0' then |
one_cnt <= "000"; |
elsif rising_edge(clk) then |
if shift_en ='0' then |
one_cnt <= "000"; |
elsif fs_ce ='1' then |
if sd_nrzi ='0' or drop_bit ='1' then |
one_cnt <= "000"; |
else |
one_cnt <= one_cnt + 1; |
end if; |
end if; |
end if; |
end process; |
|
drop_bit <= '1' when one_cnt ="110" else '0'; |
|
p_bit_stuff_err: process (clk) -- Bit Stuff Error |
begin |
if rst ='0' then |
bit_stuff_err <= '0'; |
elsif rising_edge(clk) then |
bit_stuff_err <= drop_bit and sd_nrzi and fs_ce and not se0 and rx_active; |
end if; |
end process; |
|
--====================================================================================-- |
-- Serial => Parallel converter -- |
--====================================================================================-- |
|
p_shift_en: process (clk) |
begin |
if rst ='0' then |
shift_en <= '0'; |
elsif rising_edge(clk) then |
if fs_ce ='1' then |
shift_en <= synced_d or rx_active; |
end if; |
end if; |
end process; |
|
p_hold_reg: process (clk) |
begin |
if rising_edge(clk) then |
if fs_ce ='1' and shift_en ='1' and drop_bit ='0' then |
hold_reg <= sd_nrzi & hold_reg(7 downto 1); |
end if; |
end if; |
end process; |
|
--====================================================================================-- |
-- Generate RxValid -- |
--====================================================================================-- |
|
p_bit_cnt: process (clk, rst) |
begin |
if rst ='0' then |
bit_cnt <= "000"; |
elsif rising_edge(clk) then |
if shift_en ='0' then |
bit_cnt <= "000"; |
elsif fs_ce ='1' and drop_bit ='0' then |
bit_cnt <= unsigned(bit_cnt) + 1; |
end if; |
end if; |
end process; |
|
p_rx_valid1: process (clk, rst) |
begin |
if rst ='0' then |
rx_valid1 <= '0'; |
elsif rising_edge(clk) then |
if fs_ce ='1' and drop_bit ='0' and bit_cnt ="111" then |
rx_valid1 <= '1'; |
elsif rx_valid1 ='1' and fs_ce ='1' and drop_bit ='0' then |
rx_valid1 <= '0'; |
end if; |
end if; |
end process; |
|
p_rx_valid: process (clk) |
begin |
if rst ='0' then |
rx_valid <= '0'; |
elsif rising_edge(clk) then |
rx_valid <= not drop_bit and rx_valid1 and fs_ce; |
end if; |
end process; |
|
p_se0_r: process (clk) |
begin |
if rising_edge(clk) then |
se0_r <= se0; |
end if; |
end process; |
|
p_byte_err: process (clk) |
begin |
if rst ='0' then |
byte_err <= '0'; |
elsif rising_edge(clk) then |
byte_err <= se0 and not se0_r and (bit_cnt(1) or bit_cnt(2)) and rx_active; |
end if; |
end process; |
|
end RTL; |
/trunk/usb_phy.vhdl
0,0 → 1,192
--======================================================================================-- |
-- Verilog to VHDL conversion by Martin Neumann martin@neumnns-mail.de -- |
-- -- |
-- /////////////////////////////////////////////////////////////////// -- |
-- // // -- |
-- // USB 1.1 PHY // -- |
-- // // -- |
-- // // -- |
-- // Author: Rudolf Usselmann // -- |
-- // rudi@asics.ws // -- |
-- // // -- |
-- // // -- |
-- // Downloaded from: http://www.opencores.org/cores/usb_phy/ // -- |
-- // // -- |
-- /////////////////////////////////////////////////////////////////// -- |
-- // // -- |
-- // Copyright (C) 2000-2002 Rudolf Usselmann // -- |
-- // www.asics.ws // -- |
-- // rudi@asics.ws // -- |
-- // // -- |
-- // 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY // -- |
-- // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // -- |
-- // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // -- |
-- // FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR // -- |
-- // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // -- |
-- // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // -- |
-- // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // -- |
-- // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // -- |
-- // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // -- |
-- // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // -- |
-- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // -- |
-- // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // -- |
-- // POSSIBILITY OF SUCH DAMAGE. // -- |
-- // // -- |
-- /////////////////////////////////////////////////////////////////// -- |
--======================================================================================-- |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_arith.all; |
use ieee.std_logic_unsigned.all; |
|
entity usb_phy is |
generic (usb_rst_det : boolean := TRUE); |
port ( |
clk : in std_logic; -- 60 MHz |
rst : in std_logic; |
phy_tx_mode : in std_logic; -- HIGH level for differential io mode (else single-ended) |
usb_rst : out std_logic; |
-- Transciever Interface |
rxd, rxdp, rxdn : in std_logic; |
txdp, txdn, txoe : out std_logic; |
-- UTMI Interface |
DataOut_i : in std_logic_vector(7 downto 0); |
TxValid_i : in std_logic; |
TxReady_o : out std_logic; |
DataIn_o : out std_logic_vector(7 downto 0); |
RxValid_o : out std_logic; |
RxActive_o : out std_logic; |
RxError_o : out std_logic; |
LineState_o : out std_logic_vector(1 downto 0) |
); |
end usb_phy; |
|
architecture RTL of usb_phy is |
|
--component usb_tx_phy |
--port ( |
-- clk : in std_logic; |
-- rst : in std_logic; |
-- fs_ce : in std_logic; |
-- phy_mode : in std_logic; |
-- -- Transciever Interface |
-- txdp, txdn, txoe : out std_logic; |
-- -- UTMI Interface |
-- DataOut_i : in std_logic_vector(7 downto 0); |
-- TxValid_i : in std_logic; |
-- TxReady_o : out std_logic |
--); |
--end component; |
-- |
--component usb_rx_phy |
--port ( |
-- clk : in std_logic; |
-- rst : in std_logic; |
-- -- Transciever Interface |
-- fs_ce : out std_logic; |
-- rxd, rxdp, rxdn : in std_logic; |
-- -- UTMI Interface |
-- DataIn_o : out std_logic_vector(7 downto 0); |
-- RxValid_o : out std_logic; |
-- RxActive_o : out std_logic; |
-- RxError_o : out std_logic; |
-- RxEn_i : in std_logic; |
-- LineState : out std_logic_vector(1 downto 0) |
--); |
--end component; |
|
signal LineState : std_logic_vector(1 downto 0); |
signal fs_ce : std_logic; |
signal rst_cnt : std_logic_vector(4 downto 0); |
signal txoe_out : std_logic; |
signal usb_rst_out : std_logic := '0'; |
|
begin |
|
--======================================================================================-- |
-- Misc Logic -- |
--======================================================================================-- |
|
usb_rst <= usb_rst_out; |
LineState_o <= LineState; |
txoe <= txoe_out; |
|
--======================================================================================-- |
-- TX Phy -- |
--======================================================================================-- |
|
i_tx_phy: entity work.usb_tx_phy |
port map ( |
clk => clk, |
rst => rst, |
fs_ce => fs_ce, |
phy_mode => phy_tx_mode, |
-- Transciever Interface |
txdp => txdp, |
txdn => txdn, |
txoe => txoe_out, |
-- UTMI Interface |
DataOut_i => DataOut_i, |
TxValid_i => TxValid_i, |
TxReady_o => TxReady_o |
); |
|
--======================================================================================-- |
-- RX Phy and DPLL -- |
--======================================================================================-- |
|
i_rx_phy: entity work.usb_rx_phy |
port map ( |
clk => clk, |
rst => rst, |
fs_ce_o => fs_ce, |
-- Transciever Interface |
rxd => rxd, |
rxdp => rxdp, |
rxdn => rxdn, |
-- UTMI Interface |
DataIn_o => DataIn_o, |
RxValid_o => RxValid_o, |
RxActive_o => RxActive_o, |
RxError_o => RxError_o, |
RxEn_i => txoe_out, |
LineState => LineState |
); |
|
--======================================================================================-- |
-- Generate an USB Reset if we see SE0 for at least 2.5uS -- |
--======================================================================================-- |
|
usb_rst_g : if usb_rst_det generate |
p_rst_cnt: process (clk, rst) |
begin |
if rst ='0' then |
rst_cnt <= (others => '0'); |
elsif rising_edge(clk) then |
if LineState /= "00" then |
rst_cnt <= (others => '0'); |
elsif usb_rst_out ='0' and fs_ce ='1' then |
rst_cnt <= rst_cnt + 1; |
end if; |
end if; |
end process; |
|
p_usb_rst_out: process (clk) |
begin |
if rising_edge(clk) then |
if rst_cnt = "11111" then |
usb_rst_out <= '1'; |
else |
usb_rst_out <= '0'; |
end if; |
end if; |
end process; |
end generate; |
|
end RTL; |
/trunk/usb_rx_phy.vhdl
0,0 → 1,503
--======================================================================================-- |
-- Verilog to VHDL conversion by Martin Neumann martin@neumnns-mail.de -- |
-- -- |
-- /////////////////////////////////////////////////////////////////// -- |
-- // // -- |
-- // USB 1.1 PHY // -- |
-- // RX & DPLL // -- |
-- // // -- |
-- // // -- |
-- // Author: Rudolf Usselmann // -- |
-- // rudi@asics.ws // -- |
-- // // -- |
-- // // -- |
-- // Downloaded from: http://www.opencores.org/cores/usb_phy/ // -- |
-- // // -- |
-- /////////////////////////////////////////////////////////////////// -- |
-- // // -- |
-- // Copyright (C) 2000-2002 Rudolf Usselmann // -- |
-- // www.asics.ws // -- |
-- // rudi@asics.ws // -- |
-- // // -- |
-- // 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY // -- |
-- // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // -- |
-- // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // -- |
-- // FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR // -- |
-- // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // -- |
-- // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // -- |
-- // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // -- |
-- // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // -- |
-- // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // -- |
-- // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // -- |
-- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // -- |
-- // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // -- |
-- // POSSIBILITY OF SUCH DAMAGE. // -- |
-- // // -- |
-- /////////////////////////////////////////////////////////////////// -- |
--======================================================================================-- |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_arith.all; |
use ieee.std_logic_unsigned.all; |
|
entity usb_rx_phy is |
port ( |
clk : in std_logic; |
rst : in std_logic; |
-- Transciever Interface |
fs_ce_o : out std_logic; |
rxd, rxdp, rxdn : in std_logic; |
-- UTMI Interface |
DataIn_o : out std_logic_vector(7 downto 0); |
RxValid_o : out std_logic; |
RxActive_o : out std_logic; |
RxError_o : out std_logic; |
RxEn_i : in std_logic; |
LineState : out std_logic_vector(1 downto 0) |
); |
end usb_rx_phy; |
|
architecture RTL of usb_rx_phy is |
|
signal fs_ce : std_logic; |
signal rxd_s0, rxd_s1, rxd_s : std_logic; |
signal rxdp_s0, rxdp_s1, rxdp_s, rxdp_s_r : std_logic; |
signal rxdn_s0, rxdn_s1, rxdn_s, rxdn_s_r : std_logic; |
signal synced_d : std_logic; |
signal k, j, se0 : std_logic; |
signal rxd_r : std_logic; |
signal rx_en : std_logic; |
signal rx_active : std_logic; |
signal bit_cnt : std_logic_vector(2 downto 0); |
signal rx_valid1, rx_valid : std_logic; |
signal shift_en : std_logic; |
signal sd_r : std_logic; |
signal sd_nrzi : std_logic; |
signal hold_reg : std_logic_vector(7 downto 0); |
signal drop_bit : std_logic; -- Indicates a stuffed bit |
signal one_cnt : std_logic_vector(2 downto 0); |
signal dpll_state, dpll_next_state : std_logic_vector(1 downto 0); |
signal fs_ce_d : std_logic; |
signal change : std_logic; |
signal lock_en : std_logic; |
signal fs_state, fs_next_state : std_logic_vector(2 downto 0); |
signal rx_valid_r : std_logic; |
signal sync_err_d, sync_err : std_logic; |
signal bit_stuff_err : std_logic; |
signal se0_r, byte_err : std_logic; |
signal se0_s : std_logic; |
signal fs_ce_r1, fs_ce_r2 : std_logic; |
|
constant FS_IDLE : std_logic_vector(2 downto 0) := "000"; |
constant K1 : std_logic_vector(2 downto 0) := "001"; |
constant J1 : std_logic_vector(2 downto 0) := "010"; |
constant K2 : std_logic_vector(2 downto 0) := "011"; |
constant J2 : std_logic_vector(2 downto 0) := "100"; |
constant K3 : std_logic_vector(2 downto 0) := "101"; |
constant J3 : std_logic_vector(2 downto 0) := "110"; |
constant K4 : std_logic_vector(2 downto 0) := "111"; |
|
begin |
|
--====================================================================================-- |
-- Misc Logic -- |
--====================================================================================-- |
|
fs_ce_o <= fs_ce; |
RxActive_o <= rx_active; |
RxValid_o <= rx_valid; |
RxError_o <= sync_err or bit_stuff_err or byte_err; |
DataIn_o <= hold_reg; |
LineState <= rxdn_s1 & rxdp_s1; |
|
p_rx_en: process (clk) |
begin |
if rising_edge(clk) then |
rx_en <= RxEn_i; |
end if; |
end process; |
|
p_sync_err: process (clk) |
begin |
if rising_edge(clk) then |
sync_err <= not rx_active and sync_err_d; |
end if; |
end process; |
|
--====================================================================================-- |
-- Synchronize Inputs -- |
--====================================================================================-- |
|
-- First synchronize to the local system clock to |
-- avoid metastability outside the sync block (*_s0). |
-- Then make sure we see the signal for at least two |
-- clock cycles stable to avoid glitches and noise |
|
p_rxd_s: process (clk) -- Avoid detecting Line Glitches and noise |
begin |
if rising_edge(clk) then |
rxd_s0 <= rxd; |
rxd_s1 <= rxd_s0; |
if rxd_s0 ='1' and rxd_s1 ='1' then |
rxd_s <= '1'; |
elsif not rxd_s0 ='1' and not rxd_s1 ='1' then |
rxd_s <= '0'; |
end if; |
end if; |
end process; |
|
p_rxdp_s: process (clk) |
begin |
if rising_edge(clk) then |
rxdp_s0 <= rxdp; |
rxdp_s1 <= rxdp_s0; |
rxdp_s_r <= rxdp_s0 and rxdp_s1; |
rxdp_s <= (rxdp_s0 and rxdp_s1) or rxdp_s_r; |
end if; |
end process; |
|
p_rxdn_s: process (clk) |
begin |
if rising_edge(clk) then |
rxdn_s0 <= rxdn; |
rxdn_s1 <= rxdn_s0; |
rxdn_s_r <= rxdn_s0 and rxdn_s1; |
rxdn_s <= (rxdn_s0 and rxdn_s1) or rxdn_s_r; |
end if; |
end process; |
|
j <= rxdp_s and not rxdn_s; |
k <= not rxdp_s and rxdn_s; |
se0 <= not rxdp_s and not rxdn_s; |
|
p_se0_s: process (clk) |
begin |
if rising_edge(clk) then |
if fs_ce ='1' then |
se0_s <= se0; |
end if; |
end if; |
end process; |
|
--====================================================================================-- |
-- DPLL -- |
--====================================================================================-- |
|
-- This design uses a clock enable to do 12Mhz timing and not a |
-- real 12Mhz clock. Everything always runs at 48Mhz. We want to |
-- make sure however, that the clock enable is always exactly in |
-- the middle between two virtual 12Mhz rising edges. |
-- We monitor rxdp and rxdn for any changes and do the appropiate |
-- adjustments. |
-- In addition to the locking done in the dpll FSM, we adjust the |
-- final latch enable to compensate for various sync registers ... |
|
lock_en <= rx_en; -- Allow clock adjustments only when we are receiving |
|
p_rxd_r: process (clk) |
begin |
if rising_edge(clk) then |
rxd_r <= rxd_s; |
end if; |
end process; |
|
change <= rxd_r xor rxd_s; -- Edge detector |
|
-- DPLL FSM |
p_dpll_state: process (clk, rst) |
begin |
if rst ='0' then |
dpll_state <= "01"; |
elsif rising_edge(clk) then |
dpll_state <= dpll_next_state; |
end if; |
end process; |
|
p_dpll_next_state: process (dpll_state, lock_en, change) |
begin |
case (dpll_state) is |
when "00" => |
if ((lock_en = '1') and (change = '1')) then |
dpll_next_state <= "00"; |
else |
dpll_next_state <= "01"; |
end if; |
when "01" => |
if ((lock_en = '1') and (change = '1')) then |
dpll_next_state <= "11"; |
else |
dpll_next_state <= "10"; |
end if; |
when "10" => |
if ((lock_en = '1') and (change = '1')) then |
dpll_next_state <= "00"; |
else |
dpll_next_state <= "11"; |
end if; |
when OTHERS => |
dpll_next_state <= "00"; |
end case; |
end process; |
|
fs_ce_d <= '1' when dpll_state = "01" else '0'; |
|
-- Compensate for sync registers at the input - allign full speed ... |
-- ... clock enable to be in the middle between two bit changes : |
|
p_fs_ce: process (clk) |
begin |
if rising_edge(clk) then |
fs_ce_r1 <= fs_ce_d; |
fs_ce_r2 <= fs_ce_r1; |
fs_ce <= fs_ce_r2; |
end if; |
end process; |
|
--====================================================================================-- |
-- Find Sync Pattern FSM -- |
--====================================================================================-- |
|
p_fs_state: process (clk, rst) |
begin |
if rst ='0' then |
fs_state <= FS_IDLE; |
elsif rising_edge(clk) then |
fs_state <= fs_next_state; |
end if; |
end process; |
|
p_fs_next_state: process (fs_state, fs_ce, k, j, rx_en, rx_active, se0, se0_s) |
begin |
if fs_ce='1' and rx_active='0' and se0='0' and se0_s='0' then |
case fs_state is |
when FS_IDLE => if k ='1' and rx_en ='1' then -- 0 |
fs_next_state <= K1; |
sync_err_d <= '0'; |
end if; |
when K1 => if j ='1' and rx_en ='1' then -- 1 |
fs_next_state <= J1; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when J1 => if k ='1' and rx_en ='1' then -- 2 |
fs_next_state <= K2; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when K2 => if j ='1' and rx_en ='1' then -- 3 |
fs_next_state <= J2; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when J2 => if k ='1' and rx_en ='1' then -- 4 |
fs_next_state <= K3; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when K3 => if j ='1' and rx_en ='1' then -- 5 |
fs_next_state <= J3; |
sync_err_d <= '0'; |
elsif k ='1' and rx_en ='1' then -- Allow missing first K-J |
fs_next_state <= FS_IDLE; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when J3 => if k ='1' and rx_en ='1' then -- 6 |
fs_next_state <= K4; |
sync_err_d <= '0'; |
else |
fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end if; |
when K4 => if k ='1' and rx_en ='1' then -- 7 |
sync_err_d <= '0'; |
else |
sync_err_d <= '1'; |
end if; |
fs_next_state <= FS_IDLE; |
when others => fs_next_state <= FS_IDLE; |
sync_err_d <= '1'; |
end case; |
else |
fs_next_state <= fs_state; |
sync_err_d <= '0'; |
end if; |
end process; |
|
synced_d <= fs_ce and rx_en when (fs_state =K3 and k ='1') or -- Allow missing first K-J |
(fs_state =K4 and k ='1') else '0'; |
|
--====================================================================================-- |
-- Generate RxActive -- |
--====================================================================================-- |
|
p_rx_active: process (clk, rst) |
begin |
if rst ='0' then |
rx_active <= '0'; |
elsif rising_edge(clk) then |
if synced_d ='1' and rx_en ='1' then |
rx_active <= '1'; |
elsif se0 ='1' and rx_valid_r ='1' then |
rx_active <= '0'; |
end if; |
end if; |
end process; |
|
p_rx_valid_r: process (clk) |
begin |
if rising_edge(clk) then |
if rx_valid ='1' then |
rx_valid_r <= '1'; |
elsif fs_ce ='1' then |
rx_valid_r <= '0'; |
end if; |
end if; |
end process; |
|
--====================================================================================-- |
-- NRZI Decoder -- |
--====================================================================================-- |
|
p_sd_r: process (clk) |
begin |
if rising_edge(clk) then |
if fs_ce ='1' then |
sd_r <= rxd_s; |
end if; |
end if; |
end process; |
|
p_sd_nrzi: process (clk, rst) |
begin |
if rst ='0' then |
sd_nrzi <= '0'; |
elsif rising_edge(clk) then |
if rx_active ='0' then |
sd_nrzi <= '1'; |
elsif rx_active ='1' and fs_ce ='1' then |
sd_nrzi <= not (rxd_s xor sd_r); |
end if; |
end if; |
end process; |
|
--====================================================================================-- |
-- Bit Stuff Detect -- |
--====================================================================================-- |
|
p_one_cnt: process (clk, rst) |
begin |
if rst ='0' then |
one_cnt <= "000"; |
elsif rising_edge(clk) then |
if shift_en ='0' then |
one_cnt <= "000"; |
elsif fs_ce ='1' then |
if sd_nrzi ='0' or drop_bit ='1' then |
one_cnt <= "000"; |
else |
one_cnt <= one_cnt + 1; |
end if; |
end if; |
end if; |
end process; |
|
drop_bit <= '1' when one_cnt ="110" else '0'; |
|
p_bit_stuff_err: process (clk) -- Bit Stuff Error |
begin |
if rising_edge(clk) then |
bit_stuff_err <= drop_bit and sd_nrzi and fs_ce and not se0 and rx_active; |
end if; |
end process; |
|
--====================================================================================-- |
-- Serial => Parallel converter -- |
--====================================================================================-- |
|
p_shift_en: process (clk) |
begin |
if rising_edge(clk) then |
if fs_ce ='1' then |
shift_en <= synced_d or rx_active; |
end if; |
end if; |
end process; |
|
p_hold_reg: process (clk) |
begin |
if rising_edge(clk) then |
if fs_ce ='1' and shift_en ='1' and drop_bit ='0' then |
hold_reg <= sd_nrzi & hold_reg(7 downto 1); |
end if; |
end if; |
end process; |
|
--====================================================================================-- |
-- Generate RxValid -- |
--====================================================================================-- |
|
p_bit_cnt: process (clk, rst) |
begin |
if rst ='0' then |
bit_cnt <= "000"; |
elsif rising_edge(clk) then |
if shift_en ='0' then |
bit_cnt <= "000"; |
elsif fs_ce ='1' and drop_bit ='0' then |
bit_cnt <= unsigned(bit_cnt) + 1; |
end if; |
end if; |
end process; |
|
p_rx_valid1: process (clk, rst) |
begin |
if rst ='0' then |
rx_valid1 <= '0'; |
elsif rising_edge(clk) then |
if fs_ce ='1' and drop_bit ='0' and bit_cnt ="111" then |
rx_valid1 <= '1'; |
elsif rx_valid1 ='1' and fs_ce ='1' and drop_bit ='0' then |
rx_valid1 <= '0'; |
end if; |
end if; |
end process; |
|
p_rx_valid: process (clk) |
begin |
if rising_edge(clk) then |
rx_valid <= not drop_bit and rx_valid1 and fs_ce; |
end if; |
end process; |
|
p_se0_r: process (clk) |
begin |
if rising_edge(clk) then |
se0_r <= se0; |
end if; |
end process; |
|
p_byte_err: process (clk) |
begin |
if rising_edge(clk) then |
byte_err <= se0 and not se0_r and (bit_cnt(1) or bit_cnt(2)) and rx_active; |
end if; |
end process; |
|
end RTL; |