diff --git a/synth/digilent_atlys/ac97out.vhdl b/synth/digilent_atlys/ac97out.vhdl
index 15342e7..511ea13 100644
--- a/synth/digilent_atlys/ac97out.vhdl
+++ b/synth/digilent_atlys/ac97out.vhdl
@@ -1,5 +1,8 @@
--
-- Simple core for AC97 audio output.
+--
+-- Sets output volume to -12 dB,
+-- then plays stereo PCM data at 48 kHz sample rate.
-- Only tested with LM4550 on Digilent Atlys board.
--
@@ -13,8 +16,8 @@ entity ac97out is
-- AC97 bit clock.
bitclk: in std_logic;
- -- Synchronous reset, active high.
- rst: in std_logic;
+ -- Asynchronous reset, active low.
+ resetn: in std_logic;
-- Input samples for left and right channel.
data_left: in signed(19 downto 0);
@@ -25,6 +28,7 @@ entity ac97out is
data_ready: out std_logic;
-- AC97 interface signals.
+ ac97_sdi: in std_logic;
ac97_sdo: out std_logic;
ac97_sync: out std_logic );
@@ -37,12 +41,12 @@ architecture rtl of ac97out is
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 0x0000 to register 0x02: set master volume to -12 dB
+ x"020808",
+ -- write 0x0000 to register 0x04: set headphone volume to -12 dB
+ x"040808",
+ -- write 0x0000 to register 0x06: set mono_out volume to -12 dB
+ x"060008",
-- write 0x0808 to register 0x18: set PCM out volume to 0 dB
x"180808",
-- dummy read from register 0x00
@@ -51,15 +55,21 @@ architecture rtl of ac97out is
x"800000" );
-- Output registers.
+ signal r_ready: std_logic;
signal r_sdo: std_logic;
signal r_sync: std_logic;
+ -- Reset synchronization.
+ signal r_rstsync: std_logic_vector(7 downto 0);
+
-- Bit counter.
signal r_bitcnt: unsigned(7 downto 0);
signal r_lastbit: std_logic;
- signal r_firstbit: std_logic;
+ signal r_endsync: std_logic;
-- Initialization state machine.
+ signal r_initwait: unsigned(5 downto 0);
+ signal r_initbusy: std_logic;
signal r_initdone: std_logic;
signal r_initstep: unsigned(2 downto 0);
signal r_initword: std_logic_vector(23 downto 0);
@@ -72,20 +82,46 @@ architecture rtl of ac97out is
-- Frame data shift register (tag + slots 1 .. 4)
signal r_sdoshift: std_logic_vector(95 downto 0);
+ -- AC97 bit input register
+ signal r_sdi: std_logic;
+
begin
-- Drive outputs.
- data_ready <= not r_datavalid;
+ data_ready <= r_ready;
ac97_sdo <= r_sdo;
ac97_sync <= r_sync;
-- Synchronous process.
+ -- Sample AC97_SDI on falling edge of BITCLK.
process (bitclk) is
begin
- if rising_edge(bitclk) then
+ if falling_edge(bitclk) then
+ r_sdi <= ac97_sdi;
+ end if;
+ end process;
- -- Drive SYNC high on first bit of frame.
- r_sync <= r_firstbit;
+ -- Synchronous process.
+ process (bitclk, resetn) is
+ begin
+ if resetn = '0' then
+
+ -- Asynchronous reset.
+ r_rstsync <= (others => '0');
+ r_ready <= '0';
+
+ -- Outputs to codec must be low during reset.
+ r_sdo <= '0';
+ r_sync <= '0';
+
+ elsif rising_edge(bitclk) then
+
+ -- Drive SYNC high for 16 cycles at start of frame.
+ if r_lastbit = '1' then
+ r_sync <= '1';
+ elsif r_endsync = '1' then
+ r_sync <= '0';
+ end if;
-- Push next data bit to output.
r_sdo <= r_sdoshift(r_sdoshift'high);
@@ -108,8 +144,8 @@ begin
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;
+ r_sdoshift(94) <= r_initbusy;
+ r_sdoshift(93) <= r_initbusy;
-- Set slots 3 and 4 valid if we have valid data.
r_sdoshift(92) <= r_datavalid;
@@ -122,7 +158,7 @@ begin
-- 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');
+ r_sdoshift(71 downto 60) <= (others => '0');
-- Slot 2: Register write data.
-- bit 19:4 = data
@@ -130,42 +166,65 @@ begin
r_sdoshift(43 downto 40) <= (others => '0');
-- Update init pointer.
- r_initstep <= r_initstep + 1;
+ if r_initbusy = '1' then
+ r_initstep <= r_initstep + 1;
+ end if;
if r_initstep = 7 then
+ r_initbusy <= '0';
r_initdone <= '1';
end if;
+ -- Update init delay counter (wait for 1.3 ms after reset).
+ r_initwait <= r_initwait - 1;
+ if r_initwait = 0 then
+ r_initstep <= (others => '0');
+ r_initbusy <= not r_initdone;
+ 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';
+ r_ready <= '1';
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;
+ if r_bitcnt = 241 then
+ r_endsync <= '1';
+ else
+ r_endsync <= '0';
+ end if;
-- Capture input data.
- if r_datavalid = '0' and data_valid = '1' then
+ if r_ready = '1' and data_valid = '1' then
+ r_ready <= '0';
r_datavalid <= '1';
r_dataleft <= std_logic_vector(data_left);
r_dataright <= std_logic_vector(data_right);
end if;
+ -- Release synchronous reset.
+ r_rstsync <= "1" & r_rstsync(7 downto 1);
+
-- Synchronous reset.
- if rst = '1' then
+ if r_rstsync(0) = '0' then
+ r_ready <= '0';
+ r_sdo <= '0';
+ r_sync <= '0';
+ r_initbusy <= '0';
r_initdone <= '0';
+ r_initwait <= (others => '1');
r_initstep <= (others => '0');
r_bitcnt <= (others => '0');
- r_firstbit <= '0';
r_datavalid <= '0';
end if;
diff --git a/synth/digilent_atlys/atlys.ucf b/synth/digilent_atlys/atlys.ucf
index 82f36d2..39385f9 100644
--- a/synth/digilent_atlys/atlys.ucf
+++ b/synth/digilent_atlys/atlys.ucf
@@ -7,7 +7,7 @@ NET "clk" TNM_NET = "clk" ;
TIMESPEC "TS_clk" = PERIOD "clk" 10 ns HIGH 50% ;
# Reset button
-NET "resetn" LOC = "T15" | IOSTANDARD = LVCMOS18 ;
+NET "resetn" LOC = "T15" | IOSTANDARD = LVCMOS33 ;
# LEDs
NET "led<0>" LOC = "U18" | IOSTANDARD = LVCMOS33 | SLEW = QUIETIO ;
@@ -21,7 +21,7 @@ NET "led<7>" LOC = "N12" | IOSTANDARD = LVCMOS33 | SLEW = QUIETIO ;
# USB serial port J17
NET "uartrx" LOC = "A16" | IOSTANDARD = LVCMOS33 ;
-NET "uarttx" LOC = "B16" | IOSTANDARD = LVCMOS33 ;
+NET "uarttx" LOC = "B16" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
# Audio
NET "ac97_bitclk" LOC = "L13" | IOSTANDARD = LVCMOS33 ;
diff --git a/synth/digilent_atlys/test_sincos.gise b/synth/digilent_atlys/test_sincos.gise
index 37c1a56..547659c 100644
--- a/synth/digilent_atlys/test_sincos.gise
+++ b/synth/digilent_atlys/test_sincos.gise
@@ -103,7 +103,7 @@
-
+
@@ -121,11 +121,11 @@
-
+
-
+
@@ -134,10 +134,12 @@
-
+
+
+
@@ -148,7 +150,7 @@
-
+
@@ -163,7 +165,7 @@
-
+
@@ -176,7 +178,7 @@
-
+
diff --git a/synth/digilent_atlys/test_sincos.xise b/synth/digilent_atlys/test_sincos.xise
index c7924ce..4bcda47 100644
--- a/synth/digilent_atlys/test_sincos.xise
+++ b/synth/digilent_atlys/test_sincos.xise
@@ -246,6 +246,7 @@
+
diff --git a/synth/digilent_atlys/top_test_sincos.vhdl b/synth/digilent_atlys/top_test_sincos.vhdl
index 85cda59..c57c5e6 100644
--- a/synth/digilent_atlys/top_test_sincos.vhdl
+++ b/synth/digilent_atlys/top_test_sincos.vhdl
@@ -73,7 +73,6 @@ architecture rtl of top_test_sincos is
signal r_ac97_rstcnt: unsigned(7 downto 0);
signal r_ac97_rst: std_logic;
- signal r_ac97_rstsync: std_logic_vector(7 downto 0);
signal r_ac97_phase: unsigned(19 downto 0);
signal s_ac97_sine: signed(17 downto 0);
signal s_ac97_dataleft: signed(19 downto 0);
@@ -109,14 +108,16 @@ begin
u2: entity work.ac97out
port map (
bitclk => ac97_bitclk,
- rst => r_ac97_rstsync(0),
+ resetn => r_ac97_rst,
data_left => s_ac97_dataleft,
data_right => s_ac97_dataright,
data_valid => '1',
data_ready => s_ac97_ready,
+ ac97_sdi => ac97_sdi,
ac97_sdo => ac97_sdo,
ac97_sync => ac97_sync );
+ -- Pad 18-bit signed samples to 20-bit.
s_ac97_dataleft <= s_ac97_sine & "00";
s_ac97_dataright <= s_ac97_sine & "00";
@@ -157,13 +158,9 @@ begin
end process;
-- Synchronous process in AC97 bitclock domain.
- process (ac97_bitclk, r_ac97_rst) is
+ process (ac97_bitclk) is
begin
- if r_ac97_rst = '0' then
- r_ac97_rstsync <= (others => '1');
- r_ac97_phase <= (others => '0');
- elsif rising_edge(ac97_bitclk) then
- r_ac97_rstsync <= "0" & r_ac97_rstsync(7 downto 1);
+ if rising_edge(ac97_bitclk) then
if s_ac97_ready = '1' then
r_ac97_phase <= r_ac97_phase + tone_freq;
end if;