📄 ac97_core.vhd
字号:
-------------------------------------------------------------------------------
-- ac97_core.vhd
-------------------------------------------------------------------------------
--
-- Mike Wirthlin
--
-------------------------------------------------------------------------------
-- Filename: ac97_acore.vhd
--
-- Description: Provides a simple synchronous interface to a
-- AC97 codec. This was designed for the National
-- LM4549A and only supports slots 0-4.
-- This interface does not have any data buffering.
--
-- The interface to the AC97 is straightforward.
-- To transfer playback data, this interface will
-- sample the playback data and control signals
-- when the PCM_Playback_X_Accept signals are asserted.
-- This sample will
-- be sent to the codec during the next frame. The Record (
-- input) data is provided as an ouptput and is valid when
-- new_frame is asserted.
--
-- This core supports the full 20-bit PCM sample size. The
-- actual size of the PCM can be modified to a lower value for
-- easier interfacing using the C_PCM_DATA_WIDTH generic. This
-- core will stuff the remaining lsb bits with '0' if a value
-- lower than 20 is used.
--
-- This core is synchronous to the AC97_Bit_Clk and all
-- signals interfacing to this core should be synchronized to
-- this clock.
--
-- AC97 Register Interface
--
-- This core provides a simple interface to the AC97 codec registers. To write
-- a new value to the register, drive the AC97_Reg_Addr and
-- AC97_Reg_Write_Data input signals and assert the AC97_Reg_Write_Strobe
-- signal. To read a register value, drive the AC97_Reg_Addr and assert
-- the AC97_Reg_Read_Strobe signal. Once either strobe has been asserted, the
-- register interface state machine will process the request to the CODEC and
-- assert the AC97_Reg_Busy signal. The strobe control signals will be ignored
-- while the state machine is busy (the AC97 only supports one read or write
-- transaction at a time).
--
-- When the transaction is complete, the state machine will respond as
-- follows: first, the AC97_Reg_Busy signal will be deasserted indicating that
-- the transaction is complete and that the interface is ready to handle
-- another interface. If there was an error with the response (i.e. the AC97
-- codec did not respond properly to the request), the AC97_Reg_Error signal
-- will be asserted. This signal will remain asserted until a new register
-- transfer has been initiated.
--
-- On the successful completion of a register read operation, the
-- AC97_Reg_Read_Data_Valid signal will be asserted to validate the data
-- read from the AC97 controller. This signal will remain asserted until a new
-- register transaction is initiated.
--
--
-- This core will produce valid data on the AC97_SData_Out signal
-- during the following slots:
--
-- Slot 0: Tag Phase (indicates valid slots in packet)
-- Slot 1: Read/Write, Control Address
-- Slot 2: Command Data
-- Slot 3: PCM Left
-- Slot 4: PCM Right
--
-- This core will recognize valid data on the AC97_SData_In signal
-- during the following slots:
--
-- Slot 0: Codec/Slot Status Bits
-- Slot 1: Status Address / Slot Request
-- Slot 2: Status Data
-- Slot 3: PCM Record Left
-- Slot 4: PCM Record Righ
--
-- To Do:
-- - signal to validate recorded data
-- - signal to "request" playback data
--
-- VHDL-Standard: VHDL'93
-------------------------------------------------------------------------------
-- Structure:
-- - ac97_core
-- - ac97_timing
--
-------------------------------------------------------------------------------
-- Author: Mike Wirthlin
--
-- History:
--
-------------------------------------------------------------------------------
-- Naming Conventions:
-- active low signals: "*_n"
-- clock signals: "clk", "clk_div#", "clk_#x"
-- reset signals: "rst", "rst_n"
-- generics: "C_*"
-- user defined types: "*_TYPE"
-- state machine next state: "*_ns"
-- state machine current state: "*_cs"
-- combinatorial signals: "*_com"
-- pipelined or register delay signals: "*_d#"
-- counter signals: "*cnt*"
-- clock enable signals: "*_ce"
-- internal version of output port "*_i"
-- device pins: "*_pin"
-- ports: - Names begin with Uppercase
-- processes: "*_PROCESS"
-- component instantiations: "<ENTITY_>I_<#|FUNC>
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use std.TextIO.all;
library opb_ac97_v2_00_a;
use opb_ac97_v2_00_a.all;
-------------------------------------------------------------------------------
--
-- Genearics Summary
-- C_PLAYBACK: Enable playback logic. Disable to simplify circuit
-- C_RECORD: Enable record logic. Disable to simplify circuit
-- C_PCM_DATA_WIDTH:
-- AC97 specifies a 20-bit data word. HOwever, many codecs don't
-- support the full resolution (The LM4549 only supports 18). This
-- value indicates the number of data bits that will be sent/received
-- from the CODEC. Zeros will be inserted for least-significant digits.
--
-- Signal Summary
--
-- AC97_Bit_Clk:
-- Input clock generated by the AC97 Codec
-- AC97_Sync:
-- Frame synchronization signal. Generated by ac97_timing module.
-- AC97_SData_Out:
-- Serial data out. Transitions on the rising edge of bit_clk. Is
-- sampled by the CODEC on the falling edge
-- AC97_SData_In:
-- Serial data in. Transitions on the rising edge of bit_clk. Is
-- sampled by the this module on the falling edge.
-- AC97_SData_In:
-- CODEC_RDY:
-- This signal is generated by each frame from the AC97
-- Codec. It arrives each frame as the first bit of Slot 1.
-------------------------------------------------------------------------------
entity ac97_core is
generic (
C_PCM_DATA_WIDTH : integer := 16
);
port (
Reset : in std_logic;
-- signals attaching directly to AC97 codec
AC97_Bit_Clk : in std_logic;
AC97_Sync : out std_logic;
AC97_SData_Out : out std_logic;
AC97_SData_In : in std_logic;
-- AC97 register interface
AC97_Reg_Addr : in std_logic_vector(0 to 6);
AC97_Reg_Write_Data : in std_logic_vector(0 to 15);
AC97_Reg_Read_Data : out std_logic_vector(0 to 15);
AC97_Reg_Read_Strobe : in std_logic; -- initiates a "read" command
AC97_Reg_Write_Strobe : in std_logic; -- initiates a "write" command
AC97_Reg_Busy : out std_logic;
AC97_Reg_Error : out std_logic;
AC97_Reg_Read_Data_Valid : out std_logic;
-- Playback signal interface
PCM_Playback_Left: in std_logic_vector(0 to C_PCM_DATA_WIDTH-1);
PCM_Playback_Right: in std_logic_vector(0 to C_PCM_DATA_WIDTH-1);
PCM_Playback_Left_Valid: in std_logic;
PCM_Playback_Right_Valid: in std_logic;
PCM_Playback_Left_Accept: out std_logic;
PCM_Playback_Right_Accept: out std_logic;
-- Record signal interface
PCM_Record_Left: out std_logic_vector(0 to C_PCM_DATA_WIDTH-1);
PCM_Record_Right: out std_logic_vector(0 to C_PCM_DATA_WIDTH-1);
PCM_Record_Left_Valid: out std_logic;
PCM_Record_Right_Valid: out std_logic;
DEBUG : out std_logic_vector(0 to 15);
--
CODEC_RDY : out std_logic
);
end entity ac97_core;
library unisim;
use unisim.all;
architecture IMP of ac97_core is
component ac97_timing is
port (
Bit_Clk : in std_logic;
Reset : in std_logic;
Sync : out std_logic;
Bit_Num : out natural range 0 to 19;
Slot_Num : out natural range 0 to 12;
Slot_End : out std_logic;
Frame_End : out std_logic
);
end component ac97_timing;
signal last_frame_cycle : std_logic;
signal sync_i : std_logic;
signal slot_end : std_logic;
signal slot_No : natural range 0 to 12;
--signal bit_No : natural range 0 to 19;
-- register IF signals
type reg_if_states is (IDLE, WAIT_FOR_NEW_FRAME, SEND_REQUEST_FRAME,
RESPONSE_SLOT0, RESPONSE_SLOT1, RESPONSE_SLOT2,
END_STATE);
signal reg_if_state : reg_if_states := IDLE;
signal register_addr : std_logic_vector(0 to 6) := (others => '0');
signal register_data : std_logic_vector(0 to 15) := (others => '0');
signal register_write_cmd : std_logic := '0';
signal ac97_reg_error_i, ac97_reg_busy_i : std_logic := '0';
signal valid_Frame : std_logic;
signal valid_Control_Addr : std_logic;
-- Slot 0 in signals
signal record_pcm_left_valid : std_logic;
signal record_pcm_right_valid : std_logic;
--signal return_status_address_valid : std_logic;
--signal return_status_data_valid : std_logic;
signal accept_pcm_left : std_logic;
signal accept_pcm_right : std_logic;
signal new_data_out : std_logic_vector(19 downto 0) := (others => '0');
signal data_out : std_logic_vector(19 downto 0) := (others => '0');
signal data_in : std_logic_vector(19 downto 0);
signal slot0 : std_logic_vector(15 downto 0);
signal slot1 : std_logic_vector(19 downto 0);
signal slot2 : std_logic_vector(19 downto 0);
signal slot3 : std_logic_vector(19 downto 0) := (others => '0');
signal slot4 : std_logic_vector(19 downto 0) := (others => '0');
signal codec_rdy_i : std_logic := '0';
signal PCM_Record_Left_i: std_logic_vector(0 to C_PCM_DATA_WIDTH-1);
signal PCM_Record_Right_i: std_logic_vector(0 to C_PCM_DATA_WIDTH-1);
begin -- architecture IMP
-----------------------------------------------------------------------------
-- AC97 Timing Module & Interface signals
-----------------------------------------------------------------------------
ac97_timing_I_1 : ac97_timing
port map (
Bit_Clk => AC97_Bit_Clk,
Reset => Reset,
Sync => sync_i,
Bit_Num => open,
Slot_Num => slot_No,
Slot_End => slot_end,
Frame_End => last_frame_cycle
);
AC97_Sync <= sync_i;
-----------------------------------------------------------------------------
-- AC97 Register Interface
-----------------------------------------------------------------------------
-- Register state machine
register_if_PROCESS : process (AC97_Bit_Clk) is
begin
if RESET = '1' then
reg_if_state <= IDLE;
ac97_reg_busy_i <= '0';
ac97_reg_error_i <= '0';
AC97_Reg_Read_Data_Valid <= '0';
elsif AC97_Bit_Clk'event and AC97_Bit_Clk = '1' then
case reg_if_state is
-- Wait for a register transfer strobe to occur.
when IDLE =>
if (AC97_Reg_Read_Strobe = '1' or AC97_Reg_Write_Strobe = '1')
and codec_rdy_i = '1' then
reg_if_state <= WAIT_FOR_NEW_FRAME;
ac97_reg_busy_i <= '1';
ac97_reg_error_i <= '0';
AC97_Reg_Read_Data_Valid <= '0';
register_addr <= AC97_Reg_Addr;
if AC97_Reg_Write_Strobe = '1' then
register_data <= AC97_Reg_Write_Data;
register_write_cmd <= '1';
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -