Add AC97 output driver.
This commit is contained in:
parent
9c73463282
commit
47e53fff56
|
@ -0,0 +1,180 @@
|
|||
--
|
||||
-- Simple core for AC97 audio output.
|
||||
-- Only tested with LM4550 on Digilent Atlys board.
|
||||
--
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity ac97out is
|
||||
|
||||
port (
|
||||
-- AC97 bit clock.
|
||||
bitclk: in std_logic;
|
||||
|
||||
-- Synchronous reset, active high.
|
||||
rst: in std_logic;
|
||||
|
||||
-- Input samples for left and right channel.
|
||||
data_left: in signed(19 downto 0);
|
||||
data_right: in signed(19 downto 0);
|
||||
|
||||
-- Data handshake.
|
||||
data_valid: in std_logic;
|
||||
data_ready: out std_logic;
|
||||
|
||||
-- AC97 interface signals.
|
||||
ac97_sdo: out std_logic;
|
||||
ac97_sync: out std_logic );
|
||||
|
||||
end entity;
|
||||
|
||||
architecture rtl of ac97out is
|
||||
|
||||
-- Initialization sequence.
|
||||
type init_table_type is array(0 to 7) of std_logic_vector(23 downto 0);
|
||||
constant init_table: init_table_type := (
|
||||
-- write 0x0000 to register 0x00: soft reset
|
||||
x"000000",
|
||||
-- write 0x0000 to register 0x02: set master volume to maximum
|
||||
x"020000",
|
||||
-- write 0x0000 to register 0x04: set headphone volume to maximum
|
||||
x"040000",
|
||||
-- write 0x0000 to register 0x06: set mono_out volume to maximum
|
||||
x"060000",
|
||||
-- write 0x0808 to register 0x18: set PCM out volume to 0 dB
|
||||
x"180808",
|
||||
-- dummy read from register 0x00
|
||||
x"800000",
|
||||
x"800000",
|
||||
x"800000" );
|
||||
|
||||
-- Output registers.
|
||||
signal r_ready: std_logic;
|
||||
signal r_sdo: std_logic;
|
||||
signal r_sync: std_logic;
|
||||
|
||||
-- Bit counter.
|
||||
signal r_bitcnt: unsigned(7 downto 0);
|
||||
signal r_lastbit: std_logic;
|
||||
signal r_firstbit: std_logic;
|
||||
|
||||
-- Initialization state machine.
|
||||
signal r_initdone: std_logic;
|
||||
signal r_initstep: unsigned(2 downto 0);
|
||||
signal r_initword: std_logic_vector(23 downto 0);
|
||||
|
||||
-- Data for next frame.
|
||||
signal r_datavalid: std_logic;
|
||||
signal r_dataleft: std_logic_vector(19 downto 0);
|
||||
signal r_dataright: std_logic_vector(19 downto 0);
|
||||
|
||||
-- Frame data shift register (tag + slots 1 .. 4)
|
||||
signal r_sdoshift: std_logic_vector(95 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Drive outputs.
|
||||
data_ready <= r_ready;
|
||||
ac97_sdo <= r_sdo;
|
||||
ac97_sync <= r_sync;
|
||||
|
||||
-- Synchronous process.
|
||||
process (bitclk) is
|
||||
begin
|
||||
if rising_edge(bitclk) then
|
||||
|
||||
-- Drive SYNC high on first bit of frame.
|
||||
r_sync <= r_firstbit;
|
||||
|
||||
-- Push next data bit to output.
|
||||
r_sdo <= r_sdoshift(r_sdoshift'high);
|
||||
r_sdoshift <= r_sdoshift(r_sdoshift'high-1 downto 0) & "0";
|
||||
|
||||
-- Fetch data from init table.
|
||||
r_initword <= init_table(to_integer(r_initstep));
|
||||
|
||||
-- Prepare next frame.
|
||||
if r_lastbit = '1' then
|
||||
|
||||
-- sdoshift(95:80) = TAG
|
||||
-- bit 15 = master valid bit
|
||||
-- bit 14 = slot 1 valid
|
||||
-- bit 13 = slot 2 valid
|
||||
-- bit 12 = slot 3 valid
|
||||
-- bit 11 = slot 4 valid
|
||||
|
||||
-- Always set frame valid.
|
||||
r_sdoshift(95) <= '1';
|
||||
|
||||
-- Set slots 1 and 2 valid if we are initializing.
|
||||
r_sdoshift(94) <= not r_initdone;
|
||||
r_sdoshift(93) <= not r_initdone;
|
||||
|
||||
-- Set slots 3 and 4 valid if we have valid data.
|
||||
r_sdoshift(92) <= r_datavalid;
|
||||
r_sdoshift(91) <= r_datavalid;
|
||||
|
||||
-- Remaining tag bits always zero.
|
||||
r_sdoshift(90 downto 80) <= (others => '0');
|
||||
|
||||
-- Slot 1: Register read/write command.
|
||||
-- bit 19 = read (1) or write (0)
|
||||
-- bit 18:12 = address
|
||||
r_sdoshift(79 downto 72) <= r_initword(23 downto 16);
|
||||
r_sdoshift(71 downto 0) <= (others => '0');
|
||||
|
||||
-- Slot 2: Register write data.
|
||||
-- bit 19:4 = data
|
||||
r_sdoshift(59 downto 44) <= r_initword(15 downto 0);
|
||||
r_sdoshift(43 downto 40) <= (others => '0');
|
||||
|
||||
-- Update init pointer.
|
||||
r_initstep <= r_initstep + 1;
|
||||
if r_initstep = 7 then
|
||||
r_initdone <= '1';
|
||||
end if;
|
||||
|
||||
-- Slots 3 and 4: left and right sample value.
|
||||
r_sdoshift(39 downto 20) <= r_dataleft;
|
||||
r_sdoshift(19 downto 0) <= r_dataright;
|
||||
|
||||
-- Consume sample values.
|
||||
r_datavalid <= '0';
|
||||
|
||||
end if;
|
||||
|
||||
-- Update bit counter.
|
||||
r_bitcnt <= r_bitcnt - 1;
|
||||
r_firstbit <= r_lastbit;
|
||||
if r_bitcnt = 1 then
|
||||
r_lastbit <= '1';
|
||||
else
|
||||
r_lastbit <= '0';
|
||||
end if;
|
||||
|
||||
-- Capture input data.
|
||||
if r_ready = '1' and data_valid = '1' then
|
||||
r_datavalid <= '1';
|
||||
r_dataleft <= std_logic_vector(data_left);
|
||||
r_dataright <= std_logic_vector(data_right);
|
||||
end if;
|
||||
|
||||
-- Update ready flag.
|
||||
r_ready <= (not r_datavalid) and (not data_valid);
|
||||
|
||||
-- Synchronous reset.
|
||||
if rst = '1' then
|
||||
r_initdone <= '0';
|
||||
r_initstep <= (others => '0');
|
||||
r_bitcnt <= (others => '0');
|
||||
r_firstbit <= '0';
|
||||
r_datavalid <= '0';
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end architecture;
|
||||
|
Loading…
Reference in New Issue