rst_i: in std_logic;
clk_50: in std_logic; -- 50 MHz
- ws: out std_logic;
- sck: out std_logic -- 44.1028*16*2 kHz (good enough for government work)
+ -- For external use
+ mclk: out std_logic; -- MCLK, 256*LRCLK(WS)
+ ws: out std_logic; -- WS/LRCLK, 44.1028 kHz (good enough for government work)
+ sck: out std_logic;
+
+ -- For internal use, rising and falling edges of SCK in MCLK domain
+ rise: out std_logic;
+ fall: out std_logic
);
end i2s_ctrl;
architecture behavioral of i2s_ctrl is
- signal clk_orig: std_logic; -- Output from DCM
- signal clk_int: std_logic; -- DCM output after clock buffer
+ signal mclk_orig: std_logic; -- Output from DCM
+ signal mclk_int: std_logic; -- DCM output after clock buffer
+ signal sck_int: std_logic;
+ signal sck_reg: std_logic;
- signal sck_orig: std_logic; -- Further clock division
- signal sck_int: std_logic; -- Final I2S SCK after clock buffer
+ signal ws_tick: std_logic; -- For WS generation
+ signal ws_carry: std_logic;
+ signal ws_reg: std_logic := '0';
- signal ws_tick: std_logic; -- For WS generation
- signal ws_reg: std_logic := '0';
+ signal rise_int: std_logic;
+ signal fall_int: std_logic;
+ signal rise_reg: std_logic;
+ signal fall_reg: std_logic;
begin
--CLKDV_DIVIDE => 1,
CLKFX_DIVIDE => 31,
CLKFX_MULTIPLY => 7,
- CLKIN_DIVIDE_BY_2 => true,
+ CLKIN_DIVIDE_BY_2 => false,
CLKIN_PERIOD => 20.0,
--CLKOUT_PHASE_SHIFT => "NONE",
--DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS",
CLK2X => open,
CLK2X180 => open,
CLKDV => open,
- CLKFX => clk_orig,
+ CLKFX => mclk_orig,
CLKFX180 => open,
LOCKED => open,
STATUS => open,
PSDONE => open
);
- e_clkbuf: bufg
+ e_mclkbuf: bufg
port map (
- I => clk_orig,
- O => clk_int
+ I => mclk_orig,
+ O => mclk_int
);
e_sck_gen: srl16
generic map (INIT => x"0003")
port map (
- D => sck_orig,
- CLK => clk_int,
+ D => sck_int,
+ CLK => mclk_int,
A0 => '1',
A1 => '1',
A2 => '0',
A3 => '0',
- Q => sck_orig
+ Q => sck_int
);
- e_sck_buf: bufg
+ process (mclk_int, sck_int, sck_reg)
+ begin
+ if rising_edge(mclk_int) then
+ sck_reg <= sck_int;
+ end if;
+ end process;
+ rise_int <= '1' when sck_reg = '0' and sck_int = '1' else '0';
+ fall_int <= '1' when sck_reg = '1' and sck_int = '0' else '0';
+
+ e_ws_count_0: srlc16e
+ generic map (INIT => x"0000")
port map (
- I => sck_orig,
- O => sck_int
+ D => ws_tick,
+ CE => fall_int,
+ CLK => mclk_int,
+ A0 => '0',
+ A1 => '0',
+ A2 => '0',
+ A3 => '0',
+ Q => open,
+ Q15 => ws_carry
);
- e_ws_count: srlc16
+ e_ws_count_1: srlc16e
generic map (INIT => x"0001")
port map (
- D => ws_tick,
- CLK => sck_int,
+ D => ws_carry,
+ CE => fall_int,
+ CLK => mclk_int,
A0 => '0',
A1 => '0',
A2 => '0',
Q15 => ws_tick
);
- process (sck_int, ws_tick, ws_reg)
+ process (mclk_int, ws_tick, fall_int, ws_reg)
begin
- if falling_edge(sck_int) then
- if ws_tick = '1' then
+ if rising_edge(mclk_int) then
+ if ws_tick = '1' and fall_int = '1' then
ws_reg <= not ws_reg;
end if;
end if;
end process;
- ws <= ws_reg;
- sck <= sck_int;
+ mclk <= mclk_int;
+ sck <= sck_reg;
+ ws <= ws_reg;
+
+ process (mclk_int, rise_int, fall_int)
+ begin
+ if rising_edge(mclk_int) then
+ rise_reg <= rise_int;
+ fall_reg <= fall_int;
+ end if;
+ end process;
+
+ rise <= rise_reg;
+ fall <= fall_reg;
end behavioral;
entity i2s_input is
+ generic (WIDTH: positive := 32);
port (
+ mclk: in std_logic;
sck: in std_logic;
ws: in std_logic;
sd: in std_logic;
+ rise: in std_logic;
+ fall: in std_logic;
+
stb_o: out std_logic;
rdy_i: in std_logic;
- l_dat_o: out std_logic_vector(15 downto 0);
- r_dat_o: out std_logic_vector(15 downto 0)
+ l_dat_o: out std_logic_vector(WIDTH-1 downto 0);
+ r_dat_o: out std_logic_vector(WIDTH-1 downto 0)
);
end i2s_input;
architecture behavioral of i2s_input is
- signal shift_reg: std_logic_vector(15 downto 0);
+ signal shift_reg: std_logic_vector(WIDTH-1 downto 0);
signal ws_reg: std_logic;
signal ws2_reg: std_logic;
signal latch_l: std_logic;
signal latch_r: std_logic;
- signal samp_l_reg: std_logic_vector(15 downto 0);
- signal samp_r_reg: std_logic_vector(15 downto 0);
+ signal samp_l_reg: std_logic_vector(WIDTH-1 downto 0);
+ signal samp_r_reg: std_logic_vector(WIDTH-1 downto 0);
signal stb_reg: std_logic;
begin
- process (sck, ws)
+ process (mclk, rise, ws)
begin
- if rising_edge(sck) then
- shift_reg <= shift_reg(14 downto 0) & sd;
- ws2_reg <= ws_reg;
- ws_reg <= ws;
+ if rising_edge(mclk) then
+ if rise = '1' then
+ shift_reg <= shift_reg(WIDTH-2 downto 0) & sd;
+ ws2_reg <= ws_reg;
+ ws_reg <= ws;
+ end if;
end if;
end process;
latch_l <= '1' when ws_reg = '1' and ws2_reg = '0' else '0';
latch_r <= '1' when ws_reg = '0' and ws2_reg = '1' else '0';
- process (sck, latch_l, latch_r, shift_reg)
+ process (mclk, rise, latch_l, latch_r, shift_reg)
begin
- if rising_edge(sck) then
- if latch_l = '1' then
- samp_l_reg <= shift_reg;
- end if;
- if latch_r = '1' then
- samp_r_reg <= shift_reg;
+ if rising_edge(mclk) then
+ if rise = '1' then
+ if latch_l = '1' then
+ samp_l_reg <= shift_reg;
+ end if;
+ if latch_r = '1' then
+ samp_r_reg <= shift_reg;
+ end if;
end if;
end if;
end process;
- process (sck, latch_r, rdy_i)
+ process (mclk, rise, latch_r, rdy_i)
begin
- if rising_edge(sck) then
- if latch_r = '1' then
- stb_reg <= '1';
- elsif rdy_i = '1' then
- stb_reg <= '0';
+ if rising_edge(mclk) then
+ if rise = '1' then
+ if latch_r = '1' then
+ stb_reg <= '1';
+ elsif rdy_i = '1' then
+ stb_reg <= '0';
+ end if;
end if;
end if;
end process;
entity i2s_output is
+ generic (WIDTH: positive := 32);
port (
+ mclk: in std_logic;
sck: in std_logic;
ws: in std_logic;
sd: out std_logic;
+ rise: in std_logic;
+ fall: in std_logic;
+
stb_i: in std_logic;
rdy_o: out std_logic;
- l_dat_i: in std_logic_vector(15 downto 0);
- r_dat_i: in std_logic_vector(15 downto 0)
+ l_dat_i: in std_logic_vector(WIDTH-1 downto 0);
+ r_dat_i: in std_logic_vector(WIDTH-1 downto 0)
);
end i2s_output;
architecture behavioral of i2s_output is
signal ws_reg: std_logic;
- signal shift_reg: std_logic_vector(15 downto 0);
+ signal ws2_reg: std_logic;
+ signal shift_reg: std_logic_vector(WIDTH-1 downto 0);
signal latch_l: std_logic;
signal latch_r: std_logic;
begin
- sd <= shift_reg(15);
+ sd <= shift_reg(WIDTH-1);
- process (sck, ws)
+ process (mclk, fall, ws, ws_reg)
begin
- if falling_edge(sck) then
- ws_reg <= ws;
+ if rising_edge(mclk) then
+ if fall = '1' then
+ ws2_reg <= ws_reg;
+ ws_reg <= ws;
+ end if;
end if;
end process;
- latch_l <= '1' when ws = '0' and ws_reg = '1' else '0';
- latch_r <= '1' when ws = '1' and ws_reg = '0' else '0';
+ latch_l <= '1' when ws_reg = '0' and ws2_reg = '1' else '0';
+ latch_r <= '1' when ws_reg = '1' and ws2_reg = '0' else '0';
- process (sck, latch_l, latch_r, l_dat_i, r_dat_i, shift_reg)
+ process (mclk, fall, latch_l, latch_r, l_dat_i, r_dat_i, shift_reg)
begin
- if falling_edge(sck) then
- if latch_l = '1' then
- shift_reg <= l_dat_i;
- elsif latch_r = '1' then
- shift_reg <= r_dat_i;
- else
- shift_reg <= shift_reg(14 downto 0) & '0';
+ if rising_edge(mclk) then
+ if fall = '1' then
+ if latch_l = '1' then
+ shift_reg <= l_dat_i;
+ elsif latch_r = '1' then
+ shift_reg <= r_dat_i;
+ else
+ shift_reg <= shift_reg(WIDTH-2 downto 0) & '0';
+ end if;
end if;
end if;
end process;
- rdy_o <= latch_r;
+ rdy_o <= latch_r and fall;
end behavioral;
signal rst_i: std_logic;
signal clk_i: std_logic;
- signal ws: std_logic;
+ signal mclk: std_logic;
signal sck: std_logic;
+ signal ws: std_logic;
+
+ signal rise: std_logic;
+ signal fall: std_logic;
begin
rst_i => rst_i,
clk_50 => clk_i,
+ mclk => mclk,
+ sck => sck,
ws => ws,
- sck => sck
+
+ rise => rise,
+ fall => fall
);
p_clk: process
signal rst_i: std_logic;
signal clk_50: std_logic;
+ signal mclk: std_logic;
signal sck: std_logic;
signal ws: std_logic;
signal sd: std_logic;
+ signal rise: std_logic;
+ signal fall: std_logic;
+
signal stb: std_logic;
signal rdy: std_logic;
- signal l_dat: std_logic_vector(15 downto 0);
- signal r_dat: std_logic_vector(15 downto 0);
+ signal l_dat: std_logic_vector(31 downto 0);
+ signal r_dat: std_logic_vector(31 downto 0);
begin
e_uut: entity work.i2s_input
port map (
+ mclk => mclk,
sck => sck,
ws => ws,
sd => sd,
+ rise => rise,
+ fall => fall,
+
stb_o => stb,
rdy_i => rdy,
l_dat_o => l_dat,
port map (
rst_i => rst_i,
clk_50 => clk_50,
+
+ mclk => mclk,
+ sck => sck,
ws => ws,
- sck => sck
+
+ rise => rise,
+ fall => fall
);
p_clk50: process
signal rst_i: std_logic;
signal clk_50: std_logic;
+ signal mclk: std_logic;
signal sck: std_logic;
signal ws: std_logic;
signal sd: std_logic;
+ signal rise: std_logic;
+ signal fall: std_logic;
+
signal stb: std_logic;
signal rdy: std_logic;
- signal l_dat: std_logic_vector(15 downto 0);
- signal r_dat: std_logic_vector(15 downto 0);
+ signal l_dat: std_logic_vector(31 downto 0);
+ signal r_dat: std_logic_vector(31 downto 0);
signal rx_stb: std_logic;
- signal rx_l_dat: std_logic_vector(15 downto 0);
- signal rx_r_dat: std_logic_vector(15 downto 0);
+ signal rx_l_dat: std_logic_vector(31 downto 0);
+ signal rx_r_dat: std_logic_vector(31 downto 0);
begin
port map (
rst_i => rst_i,
clk_50 => clk_50,
+
+ mclk => mclk,
sck => sck,
- ws => ws
+ ws => ws,
+
+ rise => rise,
+ fall => fall
);
e_src: entity work.src_counter
generic map (WIDTH => 16)
port map (
rst_i => rst_i,
- clk_i => sck,
+ clk_i => mclk,
stb_o => stb,
rdy_i => rdy,
- dat_o => l_dat
+ dat_o => l_dat(31 downto 16)
);
+ l_dat(15 downto 0) <= (others => '0');
r_dat <= l_dat;
e_uut: entity work.i2s_output
port map (
+ mclk => mclk,
sck => sck,
ws => ws,
sd => sd,
+
+ rise => rise,
+ fall => fall,
+
stb_i => stb,
rdy_o => rdy,
l_dat_i => l_dat,
-- Not a big deal for streaming audio, so not worth fixing now.
e_rx: entity work.i2s_input
port map (
+ mclk => mclk,
sck => sck,
ws => ws,
sd => sd,
+ rise => rise,
+ fall => fall,
stb_o => rx_stb,
rdy_i => '1',
l_dat_o => rx_l_dat,