📄 ac97_fifo.vhd
字号:
end if;
end process;
status_reg(31 downto 22) <= out_fifo_level;
status_reg(21 downto 12) <= in_fifo_level;
--status_reg(11 downto 9) <= (others => '0');
status_reg(10) <= out_fifo_interrupt_en;
status_reg(9) <= in_fifo_interrupt_en;
status_reg(8) <= IpClk_ac97_reg_error;
status_reg(7) <= out_FIFO_Overrun;
status_reg(6) <= in_FIFO_Underrun;
status_reg(5) <= IpClk_codec_rdy;
status_reg(4) <= register_access_busy; --IpClk_ac97_reg_busy;
status_reg(3) <= out_Data_Exists;
status_reg(2) <= out_fifo_empty;
status_reg(1) <= in_fifo_empty;
status_reg(0) <= in_FIFO_Full;
process (Bus2IP_Clk) is
begin
if Bus2IP_Clk'event and Bus2IP_Clk = '1' then
IpClk_codec_rdy <= BitClk_codec_rdy;
IpClk_ac97_reg_busy <= BitClk_ac97_reg_busy;
IpClk_ac97_reg_error <= BitClk_ac97_reg_error;
end if;
end process;
-----------------------------------------------------------------------------
-- AC97 Access Register
-----------------------------------------------------------------------------
-- The AC97 access register is used to initiate an AC97 register
-- read or write command. This register holds the AC97 address to
-- read/write as well as the direction (IpClk_ac97_reg_read).
AC97_Access_Reg : process (Bus2IP_Clk) is
begin -- process AC97_Write_Reg_Data
if Bus2IP_Clk'event and Bus2IP_Clk = '1' then
if Bus2IP_Reset = '1' then
IpClk_ac97_reg_addr <= (others => '0');
IpClk_ac97_reg_read <= '0';
else
if Bus2IP_WrCE = '1' and AC97_CTRL_ADR = controller_addr then
IpClk_ac97_reg_addr <= Bus2IP_Data(25 to 31);
IpClk_ac97_reg_read <= Bus2IP_Data(24);
end if;
end if;
end if;
end process;
-----------------------------------------------------------------------------
-- AC97 Write data register
-----------------------------------------------------------------------------
-- AC97 Register Write Data: This register holds the data that is to
-- be written to the AC97 internal register.
--
-- Writing to this register does not cause the actual
-- write process to the AC97. Once this register has been written,
-- a command must be written to the AC97_Access_Reg to initiate the
-- actual write.
AC97_Write_Reg : process (Bus2IP_Clk) is
begin -- process AC97_Write_Reg_Data
if Bus2IP_Clk'event and Bus2IP_Clk = '1' then
if Bus2IP_Reset = '1' then
IpClk_ac97_reg_write_data <= (others => '0');
else
if Bus2IP_WrCE = '1' and controller_addr = AC97_WRITE_ADR then
IpClk_ac97_reg_write_data <= Bus2IP_Data(16 to 31);
end if;
end if;
end if;
end process;
-----------------------------------------------------------------------------
-- AC97 Access initiate one shot
-----------------------------------------------------------------------------
-- This one bit signal is asserted when a write occurs to the AC97_CTRL_ADDR.
-- This is a one-shot signal that is only asserted for one cycle
-- (Bus2IP_Clk).
-- This signal will initiate the AC97 register access state machine.
AC97_Access_S_PROCESS : process (Bus2IP_Clk) is
begin
if Bus2IP_Clk'event and Bus2IP_Clk = '1' then
if Bus2IP_WrCE = '1' and controller_addr = AC97_CTRL_ADR then
IpClk_ac97_reg_access_S <= '1'; -- one shot
else
IpClk_ac97_reg_access_S <= '0';
end if;
end if;
end process;
-- busy signal
process (Bus2IP_Clk) is
begin
if Bus2IP_Reset = '1' then
ac97_register_access_sm <= IDLE;
elsif Bus2IP_Clk'event and Bus2IP_Clk='1' then
case ac97_register_access_sm is
when IDLE =>
if IpClk_ac97_reg_access_S = '1' then
ac97_register_access_sm <= ISSUE_ACCESS;
end if;
when ISSUE_ACCESS =>
-- TODO: add time out in case the codec is not hooked up
if IpClk_ac97_reg_busy = '1' then
ac97_register_access_sm <= PROCESS_ACCESS;
end if;
when PROCESS_ACCESS =>
if IpClk_ac97_reg_busy = '0' then
ac97_register_access_sm <= IDLE;
end if;
end case;
end if;
end process;
register_access_busy <= '1' when (ac97_register_access_sm = ISSUE_ACCESS or
ac97_register_access_sm = PROCESS_ACCESS)
else '0';
-----------------------------------------------------------------------------
-- Clock crossing signals
-----------------------------------------------------------------------------
-- convert the one cycle strobe in the IpClk domain to
-- the BitClk domain.
fdcpe_1 : FDCPE
port map (
Q => IpClk_access_request,
C => '0',
CE => '0',
CLR => BitClk_ac97_reg_access_S,
D => '0',
PRE => IpClk_ac97_reg_access_S
);
process (Bit_Clk) is
begin
if Bit_Clk'event and Bit_Clk='1' then
BitClk_ac97_reg_access_St(0) <= IpClk_access_request;
BitClk_ac97_reg_access_St(1) <= BitClk_ac97_reg_access_St(0);
BitClk_ac97_reg_access_S <= BitClk_ac97_reg_access_St(0) and
(not BitClk_ac97_reg_access_St(1));
end if;
end process;
BitClk_ac97_reg_read_strobe <= BitClk_ac97_reg_access_S and
IpClk_ac97_reg_read;
BitClk_ac97_reg_write_strobe <= BitClk_ac97_reg_access_S and
(not IpClk_ac97_reg_read);
BitClk_playback_left_valid <= '1';
BitClk_playback_right_valid <= '1';
-----------------------------------------------------------------------------
-- Fifo Control Signals (asynchronous clock transfer)
--
-----------------------------------------------------------------------------
-- BitClk is slower than IpClk.
process (Bus2IP_Clk) is
begin
if Bus2IP_Clk'event and Bus2IP_clk='1' then
IpClk_playback_accept_St(0) <= BitClk_playback_left_accept;
IpClk_playback_accept_St(1) <= IpClk_playback_accept_St(0);
end if;
IpClk_playback_accept_S <= IpClk_playback_accept_St(0) and
(not IpClk_playback_accept_St(1));
end process;
process (Bus2IP_Clk) is
begin
if Bus2IP_Clk'event and Bus2IP_clk='1' then
IpClk_record_valid_St(0) <= BitClk_record_left_valid;
IpClk_record_valid_St(1) <= IpClk_record_valid_St(0);
end if;
end process;
IpClk_record_accept_S <= IpClk_record_valid_St(0) and
(not IpClk_record_valid_St(1));
in_FIFO_Read <= IpClk_playback_accept_S;
out_FIFO_Write <= IpClk_record_accept_S;
-----------------------------------------------------------------------------
-- IN_FIFO
--
-- This fifo receives data directly from the OPB bus and performs a "fifo
-- write" for each OPB write to the FIFO. The FIFO sends data directly to the
-- AC97 core and performs a "fifo read" every time a new AC97 frame is sent.
--
-----------------------------------------------------------------------------
Using_Playback_SRL : if (C_PLAYBACK = 1 and C_USE_BRAM = 0) generate
IN_FIFO : SRL_FIFO
generic map (
C_DATA_BITS => 32, -- Left and Right channel
C_DEPTH => 16)
port map (
Clk => Bus2IP_Clk,
Reset => Bus2IP_Reset,
Clear_FIFO => clear_in_fifo,
FIFO_Write => in_FIFO_Write,
Data_In => Bus2IP_Data,
FIFO_Read => in_FIFO_Read,
Data_Out => in_Data_FIFO,
FIFO_Full => in_FIFO_Full,
Data_Exists => in_Data_Exists,
FIFO_Level => in_srl_fifo_level,
Half_Full => in_FIFO_Half_Full,
Half_Empty => in_FIFO_Half_Empty);
in_fifo_level <= "000000" & in_srl_fifo_level;
in_FIFO_Empty <= not in_Data_Exists;
end generate Using_Playback_SRL;
Using_Playback_BRAM : if (C_PLAYBACK = 1 and C_USE_BRAM = 1) generate
IN_FIFO : BRAM_FIFO
port map (
Clk => Bus2IP_Clk,
Reset => Bus2IP_Reset,
Clear_FIFO => clear_in_fifo,
FIFO_Write => in_FIFO_Write,
Data_In => Bus2IP_Data,
FIFO_Read => in_FIFO_Read,
Data_Out => in_Data_FIFO,
FIFO_Level => in_fifo_level,
FULL => in_FIFO_Full,
HalfFull => in_FIFO_HALF_FULL,
HalfEmpty => in_FIFO_Half_Empty,
Overflow => open,
Underflow => open,
Empty => in_FIFO_Empty
);
in_Data_Exists <= not in_FIFO_Empty;
end generate Using_Playback_BRAM;
No_Playback : if (C_PLAYBACK = 0) generate
in_Data_FIFO <= (others => '0');
in_FIFO_Full <= '0';
in_Data_Exists <= '0';
in_FIFO_Empty <= '0';
in_fifo_level <= (others => '0');
out_fifo_level <= (others => '0');
end generate No_Playback;
-----------------------------------------------------------------------------
-- OUT_FIFO
--
-- This fifo receives data directly from the AC97 and performs a "fifo
-- write" for each AC97 frame. The FIFO sends data directly to the
-- OPB Bus core and performs a "fifo read" every time data is read from the
-- FIFO over the OPB bus.
--
-----------------------------------------------------------------------------
Using_Recording_SRL : if (C_RECORD = 1 and C_USE_BRAM = 0) generate
OUT_FIFO : SRL_FIFO
generic map (
C_DATA_BITS => 32, -- [integer]
C_DEPTH => 16) -- [integer]
port map (
Clk => Bus2IP_Clk, -- [in std_logic]
Reset => Bus2IP_Reset, -- [in std_logic]
Clear_FIFO => clear_out_fifo, -- [in std_logic]
FIFO_Write => out_FIFO_Write, -- [in std_logic]
Data_In => out_Data_FIFO,
FIFO_Read => out_FIFO_Read, -- [in std_logic]
Data_Out => out_Data_Read, -- [out std_logic_vector(0 to C_OPB_DWIDTH-1)]
FIFO_Full => out_FIFO_Full, -- [out std_logic]
Data_Exists => out_Data_Exists, -- [out std_logic]
FIFO_Level => out_srl_fifo_level,
Half_Full => out_FIFO_Half_Full, -- [out std_logic]
Half_Empty => open); -- [out std_logic]
out_fifo_level <= "000000" & out_srl_fifo_level;
out_fifo_empty <= not out_Data_exists;
end generate Using_Recording_SRL;
Using_Recording_BRAM : if (C_RECORD = 1 and C_USE_BRAM = 1) generate
OUT_FIFO : BRAM_FIFO
port map (
Clk => Bus2IP_Clk,
Reset => Bus2IP_Reset,
Clear_FIFO => clear_out_fifo,
FIFO_Write => out_FIFO_Write,
Data_In => out_Data_FIFO,
FIFO_Read => out_FIFO_Read,
Data_Out => out_Data_Read,
FIFO_Level => out_fifo_level,
FULL => out_FIFO_Full,
HalfFull => out_FIFO_HALF_FULL,
HalfEmpty => out_FIFO_HALF_Empty,
Overflow => open,
Underflow => open,
Empty => out_FIFO_Empty); -- [out std_logic]
out_Data_Exists <= not out_FIFO_Empty;
end generate Using_Recording_BRAM;
No_Recording : if (C_RECORD = 0) generate
out_Data_Read <= (others => '0');
out_FIFO_Full <= '0';
out_Data_Exists <= '0';
end generate No_Recording;
-----------------------------------------------------------------------------
-- Instanciating the core
-----------------------------------------------------------------------------
ac97_core_I : ac97_core
port map (
Reset => ac97_core_reset,
AC97_Bit_Clk => Bit_Clk,
AC97_Sync => Sync,
AC97_SData_Out => SData_Out,
AC97_SData_In => SData_In,
AC97_Reg_Addr => IpClk_ac97_reg_addr, -- async
AC97_Reg_Write_Data => IpClk_ac97_reg_write_data, -- async
AC97_Reg_Read_Data => BitClk_ac97_Reg_Read_Data,
AC97_Reg_Read_Strobe => BitClk_ac97_reg_read_strobe,
AC97_Reg_Write_Strobe => BitClk_ac97_reg_write_strobe,
AC97_Reg_Busy => BitClk_ac97_reg_busy,
AC97_Reg_Error => BitClk_ac97_reg_error,
AC97_Reg_Read_Data_Valid => BitClk_ac97_reg_data_valid,
PCM_Playback_Left => in_Data_Fifo(16 to 31),
PCM_Playback_Right => in_Data_Fifo(0 to 15),
PCM_Playback_Left_Valid => BitClk_playback_left_valid,
PCM_Playback_Right_Valid => BitClk_playback_right_valid,
PCM_Playback_Left_Accept => BitClk_playback_left_accept,
PCM_Playback_Right_Accept => BitClk_playback_right_accept,
PCM_Record_Left => out_Data_Fifo(16 to 31),
PCM_Record_Right => out_Data_Fifo(0 to 15),
PCM_Record_Left_Valid => BitClk_record_left_valid,
PCM_Record_Right_Valid => BitClk_record_right_valid,
DEBUG => debug_i,
CODEC_RDY => BitClk_codec_rdy
);
-----------------------------------------------------------------------------
-- Handling the interrupts
-----------------------------------------------------------------------------
Interrupt_Handle: process (in_FIFO_Half_Full,
in_FIFO_Full, In_Data_Exists,
in_fifo_interrupt_en,
out_FIFO_Half_Full, out_FIFO_Half_Empty,
out_FIFO_Full, out_Data_Exists,
out_fifo_interrupt_en
) is
begin -- process Playback_Interrupt_Handle
if (C_INTR_LEVEL = 1) then
Interrupt <= (in_fifo_interrupt_en and in_FIFO_Half_Empty) or
(out_fifo_interrupt_en and out_FIFO_Half_Full);
elsif (C_INTR_LEVEL = 2) then
Interrupt <= (in_fifo_interrupt_en and in_FIFO_Full) or
(out_fifo_interrupt_en and out_FIFO_Empty);
elsif (C_INTR_LEVEL = 3) then
Interrupt <= (in_fifo_interrupt_en and in_FIFO_Half_Full) or
(out_fifo_interrupt_en and out_Fifo_Half_Empty);
-- TODO: implement level 3
else
Interrupt <= '0';
end if;
end process Interrupt_Handle;
end architecture IMP;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -