----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
---- ----
|
---- ----
|
---- WISHBONE I2S Interface IP Core ----
|
---- WISHBONE I2S Interface IP Core ----
|
---- ----
|
---- ----
|
---- This file is part of the I2S Interface project ----
|
---- This file is part of the I2S Interface project ----
|
---- http://www.opencores.org/cores/i2s_interface/ ----
|
---- http://www.opencores.org/cores/i2s_interface/ ----
|
---- ----
|
---- ----
|
---- Description ----
|
---- Description ----
|
---- I2S encoder/decoder. ----
|
---- I2S encoder/decoder. ----
|
---- ----
|
---- ----
|
---- ----
|
---- ----
|
---- To Do: ----
|
---- To Do: ----
|
---- - ----
|
---- - ----
|
---- ----
|
---- ----
|
---- Author(s): ----
|
---- Author(s): ----
|
---- - Geir Drange, gedra@opencores.org ----
|
---- - Geir Drange, gedra@opencores.org ----
|
---- ----
|
---- ----
|
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
---- ----
|
---- ----
|
---- Copyright (C) 2004 Authors and OPENCORES.ORG ----
|
---- Copyright (C) 2004 Authors and OPENCORES.ORG ----
|
---- ----
|
---- ----
|
---- This source file may be used and distributed without ----
|
---- This source file may be used and distributed without ----
|
---- restriction provided that this copyright statement is not ----
|
---- restriction provided that this copyright statement is not ----
|
---- removed from the file and that any derivative work contains ----
|
---- removed from the file and that any derivative work contains ----
|
---- the original copyright notice and the associated disclaimer. ----
|
---- the original copyright notice and the associated disclaimer. ----
|
---- ----
|
---- ----
|
---- This source file is free software; you can redistribute it ----
|
---- This source file is free software; you can redistribute it ----
|
---- and/or modify it under the terms of the GNU General ----
|
---- and/or modify it under the terms of the GNU General ----
|
---- Public License as published by the Free Software Foundation; ----
|
---- Public License as published by the Free Software Foundation; ----
|
---- either version 2.0 of the License, or (at your option) any ----
|
---- either version 2.0 of the License, or (at your option) any ----
|
---- later version. ----
|
---- later version. ----
|
---- ----
|
---- ----
|
---- This source is distributed in the hope that it will be ----
|
---- This source is distributed in the hope that it will be ----
|
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
|
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
|
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
|
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
|
---- PURPOSE. See the GNU General Public License for more details.----
|
---- PURPOSE. See the GNU General Public License for more details.----
|
---- ----
|
---- ----
|
---- You should have received a copy of the GNU General ----
|
---- You should have received a copy of the GNU General ----
|
---- Public License along with this source; if not, download it ----
|
---- Public License along with this source; if not, download it ----
|
---- from http://www.gnu.org/licenses/gpl.txt ----
|
---- from http://www.gnu.org/licenses/gpl.txt ----
|
---- ----
|
---- ----
|
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
--
|
--
|
-- CVS Revision History
|
-- CVS Revision History
|
--
|
--
|
-- $Log: not supported by cvs2svn $
|
-- $Log: not supported by cvs2svn $
|
-- Revision 1.3 2005/06/03 17:18:08 gedra
|
-- Revision 1.3 2005/06/03 17:18:08 gedra
|
-- BugFix: LSB of transmitted word would be set to zero in slave master mode. (Credit: Julien Dumont)
|
-- BugFix: LSB of transmitted word would be set to zero in slave master mode. (Credit: Julien Dumont)
|
--
|
--
|
-- Revision 1.2 2004/08/06 18:55:05 gedra
|
-- Revision 1.2 2004/08/06 18:55:05 gedra
|
-- Removed conf_inten, and fixed bug in transmitter master mode.
|
-- Removed conf_inten, and fixed bug in transmitter master mode.
|
--
|
--
|
-- Revision 1.1 2004/08/03 18:49:43 gedra
|
-- Revision 1.1 2004/08/03 18:49:43 gedra
|
-- I2S encoder/decoder.
|
-- I2S encoder/decoder.
|
--
|
--
|
--
|
--
|
--
|
--
|
|
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.numeric_std.all;
|
use ieee.numeric_std.all;
|
|
|
entity i2s_codec is
|
entity i2s_codec is
|
generic (DATA_WIDTH : integer;
|
generic (DATA_WIDTH : integer;
|
ADDR_WIDTH : integer;
|
ADDR_WIDTH : integer;
|
IS_MASTER : integer range 0 to 1;
|
IS_MASTER : integer range 0 to 1;
|
IS_RECEIVER : integer range 0 to 1);
|
IS_RECEIVER : integer range 0 to 1);
|
port (
|
port (
|
wb_clk_i : in std_logic; -- wishbone clock
|
wb_clk_i : in std_logic; -- wishbone clock
|
conf_res : in std_logic_vector(5 downto 0); -- sample resolution
|
conf_res : in std_logic_vector(5 downto 0); -- sample resolution
|
conf_ratio : in std_logic_vector(7 downto 0); -- clock divider ratio
|
conf_ratio : in std_logic_vector(7 downto 0); -- clock divider ratio
|
conf_swap : in std_logic; -- left/right sample order
|
conf_swap : in std_logic; -- left/right sample order
|
conf_en : in std_logic; -- transmitter/recevier enable
|
conf_en : in std_logic; -- transmitter/recevier enable
|
i2s_sd_i : in std_logic; -- I2S serial data input
|
i2s_sd_i : in std_logic; -- I2S serial data input
|
i2s_sck_i : in std_logic; -- I2S clock input
|
i2s_sck_i : in std_logic; -- I2S clock input
|
i2s_ws_i : in std_logic; -- I2S word select input
|
i2s_ws_i : in std_logic; -- I2S word select input
|
sample_dat_i : in std_logic_vector(DATA_WIDTH - 1 downto 0); -- audio data
|
sample_dat_i : in std_logic_vector(DATA_WIDTH - 1 downto 0); -- audio data
|
sample_dat_o : out std_logic_vector(DATA_WIDTH - 1 downto 0); -- audio data
|
sample_dat_o : out std_logic_vector(DATA_WIDTH - 1 downto 0); -- audio data
|
mem_rdwr : out std_logic; -- sample buffer read/write
|
mem_rdwr : out std_logic; -- sample buffer read/write
|
sample_addr : out std_logic_vector(ADDR_WIDTH - 2 downto 0); -- address
|
sample_addr : out std_logic_vector(ADDR_WIDTH - 2 downto 0); -- address
|
evt_hsbf : out std_logic; -- higher sample buf empty event
|
evt_hsbf : out std_logic; -- higher sample buf empty event
|
evt_lsbf : out std_logic; -- lower sample buf empty event
|
evt_lsbf : out std_logic; -- lower sample buf empty event
|
i2s_sd_o : out std_logic; -- I2S serial data output
|
i2s_sd_o : out std_logic; -- I2S serial data output
|
i2s_sck_o : out std_logic; -- I2S clock output
|
i2s_sck_o : out std_logic; -- I2S clock output
|
i2s_ws_o : out std_logic); -- I2S word select output
|
i2s_ws_o : out std_logic); -- I2S word select output
|
end i2s_codec;
|
end i2s_codec;
|
|
|
architecture rtl of i2s_codec is
|
architecture rtl of i2s_codec is
|
|
|
signal i2s_clk_en, zsck, zzsck, zzzsck, imem_rd : std_logic;
|
signal i2s_clk_en, zsck, zzsck, zzzsck, imem_rd : std_logic;
|
signal clk_cnt : integer range 0 to 255;
|
signal clk_cnt : integer range 0 to 255;
|
signal adr_cnt : integer range 0 to 2**(ADDR_WIDTH - 1) - 1;
|
signal adr_cnt : integer range 0 to 2**(ADDR_WIDTH - 1) - 1;
|
type srx_states is (IDLE, WAIT_CLK, TRX_DATA, RX_WRITE, SYNC);
|
type srx_states is (IDLE, WAIT_CLK, TRX_DATA, RX_WRITE, SYNC);
|
signal sd_ctrl : srx_states;
|
signal sd_ctrl : srx_states;
|
signal bit_cnt, bits_to_trx : integer range 0 to 63;
|
signal bit_cnt, bits_to_trx : integer range 0 to 63;
|
signal toggle, master, neg_edge, ws_pos_edge, ws_neg_edge : std_logic;
|
signal toggle, master, neg_edge, ws_pos_edge, ws_neg_edge : std_logic;
|
signal data_in : std_logic_vector(DATA_WIDTH - 1 downto 0);
|
signal data_in : std_logic_vector(DATA_WIDTH - 1 downto 0);
|
signal zws, zzws, zzzws, i2s_ws, new_word, last_bit : std_logic;
|
signal zws, zzws, zzzws, i2s_ws, new_word, last_bit : std_logic;
|
signal imem_rdwr, receiver : std_logic;
|
signal imem_rdwr, receiver : std_logic;
|
signal ws_cnt : integer range 0 to 31;
|
signal ws_cnt : integer range 0 to 31;
|
|
|
begin
|
begin
|
|
|
-- Create signals that reflect generics
|
-- Create signals that reflect generics
|
SGM : if IS_MASTER = 1 generate
|
SGM : if IS_MASTER = 1 generate
|
master <= '1';
|
master <= '1';
|
end generate SGM;
|
end generate SGM;
|
SGS : if IS_MASTER = 0 generate
|
SGS : if IS_MASTER = 0 generate
|
master <= '0';
|
master <= '0';
|
end generate SGS;
|
end generate SGS;
|
SGRX : if IS_RECEIVER = 1 generate
|
SGRX : if IS_RECEIVER = 1 generate
|
receiver <= '1';
|
receiver <= '1';
|
end generate SGRX;
|
end generate SGRX;
|
SGTX : if IS_RECEIVER = 0 generate
|
SGTX : if IS_RECEIVER = 0 generate
|
receiver <= '0';
|
receiver <= '0';
|
end generate SGTX;
|
end generate SGTX;
|
|
|
-- I2S clock enable generation, master mode. The clock is a fraction of the
|
-- I2S clock enable generation, master mode. The clock is a fraction of the
|
-- Wishbone bus clock, determined by the conf_ratio value.
|
-- Wishbone bus clock, determined by the conf_ratio value.
|
CGM : if IS_MASTER = 1 generate
|
CGM : if IS_MASTER = 1 generate
|
CGEN : process (wb_clk_i)
|
CGEN : process (wb_clk_i)
|
begin
|
begin
|
if rising_edge(wb_clk_i) then
|
if rising_edge(wb_clk_i) then
|
if conf_en = '0' then -- disabled
|
if conf_en = '0' then -- disabled
|
i2s_clk_en <= '0';
|
i2s_clk_en <= '0';
|
clk_cnt <= 0;
|
clk_cnt <= 0;
|
neg_edge <= '0';
|
neg_edge <= '0';
|
toggle <= '0';
|
toggle <= '0';
|
else -- enabled
|
else -- enabled
|
if clk_cnt < to_integer(unsigned(conf_ratio)) + 1 then
|
if clk_cnt < to_integer(unsigned(conf_ratio)) + 1 then
|
clk_cnt <= (clk_cnt + 1) mod 256;
|
clk_cnt <= (clk_cnt + 1) mod 256;
|
i2s_clk_en <= '0';
|
i2s_clk_en <= '0';
|
else
|
else
|
clk_cnt <= 0;
|
clk_cnt <= 0;
|
i2s_clk_en <= '1';
|
i2s_clk_en <= '1';
|
neg_edge <= not neg_edge;
|
neg_edge <= not neg_edge;
|
end if;
|
end if;
|
toggle <= neg_edge;
|
toggle <= neg_edge;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process CGEN;
|
end process CGEN;
|
end generate CGM;
|
end generate CGM;
|
|
|
-- I2S clock enable generation, slave mode. The input clock signal is sampeled
|
-- I2S clock enable generation, slave mode. The input clock signal is sampeled
|
-- and the negative edge is located.
|
-- and the negative edge is located.
|
CGS : if IS_MASTER = 0 generate
|
CGS : if IS_MASTER = 0 generate
|
CGEN : process (wb_clk_i)
|
CGEN : process (wb_clk_i)
|
begin
|
begin
|
if rising_edge(wb_clk_i) then
|
if rising_edge(wb_clk_i) then
|
if conf_en = '0' then -- disabled
|
if conf_en = '0' then -- disabled
|
i2s_clk_en <= '0';
|
i2s_clk_en <= '0';
|
zsck <= '0';
|
zsck <= '0';
|
zzsck <= '0';
|
zzsck <= '0';
|
zzzsck <= '0';
|
zzzsck <= '0';
|
toggle <= '0';
|
toggle <= '0';
|
neg_edge <= '0';
|
neg_edge <= '0';
|
else -- enabled
|
else -- enabled
|
-- synchronize input clock to Wishbone clock domaine
|
-- synchronize input clock to Wishbone clock domaine
|
zsck <= i2s_sck_i;
|
zsck <= i2s_sck_i;
|
zzsck <= zsck;
|
zzsck <= zsck;
|
zzzsck <= zzsck;
|
zzzsck <= zzsck;
|
-- look for edges
|
-- look for edges
|
if zzzsck = '1' and zzsck = '0' then
|
if zzzsck = '1' and zzsck = '0' then
|
i2s_clk_en <= '1';
|
i2s_clk_en <= '1';
|
neg_edge <= '1';
|
neg_edge <= '1';
|
elsif zzzsck = '0' and zzsck = '1' then
|
elsif zzzsck = '0' and zzsck = '1' then
|
i2s_clk_en <= '1';
|
i2s_clk_en <= '1';
|
neg_edge <= '0';
|
neg_edge <= '0';
|
else
|
else
|
i2s_clk_en <= '0';
|
i2s_clk_en <= '0';
|
end if;
|
end if;
|
toggle <= neg_edge;
|
toggle <= neg_edge;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process CGEN;
|
end process CGEN;
|
end generate CGS;
|
end generate CGS;
|
|
|
-- Process to generate word select signal, master mode
|
-- Process to generate word select signal, master mode
|
WSM : if IS_MASTER = 1 generate
|
WSM : if IS_MASTER = 1 generate
|
i2s_ws_o <= i2s_ws;
|
i2s_ws_o <= i2s_ws;
|
WSG : process (wb_clk_i)
|
WSG : process (wb_clk_i)
|
begin
|
begin
|
if rising_edge(wb_clk_i) then
|
if rising_edge(wb_clk_i) then
|
if conf_en = '0' then
|
if conf_en = '0' then
|
i2s_ws <= '0';
|
i2s_ws <= '0';
|
ws_cnt <= 0;
|
ws_cnt <= 0;
|
ws_pos_edge <= '0';
|
ws_pos_edge <= '0';
|
ws_neg_edge <= '0';
|
ws_neg_edge <= '0';
|
else
|
else
|
if i2s_clk_en = '1' and toggle = '1' then
|
if i2s_clk_en = '1' and toggle = '1' then
|
if ws_cnt < bits_to_trx then
|
if ws_cnt < bits_to_trx then
|
ws_cnt <= ws_cnt + 1;
|
ws_cnt <= ws_cnt + 1;
|
else
|
else
|
i2s_ws <= not i2s_ws;
|
i2s_ws <= not i2s_ws;
|
ws_cnt <= 0;
|
ws_cnt <= 0;
|
if i2s_ws = '1' then
|
if i2s_ws = '1' then
|
ws_neg_edge <= '1';
|
ws_neg_edge <= '1';
|
else
|
else
|
ws_pos_edge <= '1';
|
ws_pos_edge <= '1';
|
end if;
|
end if;
|
end if;
|
end if;
|
else
|
else
|
ws_pos_edge <= '0';
|
ws_pos_edge <= '0';
|
ws_neg_edge <= '0';
|
ws_neg_edge <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process WSG;
|
end process WSG;
|
end generate WSM;
|
end generate WSM;
|
|
|
-- Process to detect word select edges, slave mode
|
-- Process to detect word select edges, slave mode
|
WSD : if IS_MASTER = 0 generate
|
WSD : if IS_MASTER = 0 generate
|
i2s_ws <= i2s_ws_i;
|
i2s_ws <= i2s_ws_i;
|
WSDET : process (wb_clk_i)
|
WSDET : process (wb_clk_i)
|
begin
|
begin
|
if rising_edge(wb_clk_i) then
|
if rising_edge(wb_clk_i) then
|
if conf_en = '0' then
|
if conf_en = '0' then
|
ws_pos_edge <= '0';
|
ws_pos_edge <= '0';
|
ws_neg_edge <= '0';
|
ws_neg_edge <= '0';
|
zws <= i2s_ws;
|
zws <= i2s_ws;
|
zzws <= i2s_ws;
|
zzws <= i2s_ws;
|
zzzws <= i2s_ws;
|
zzzws <= i2s_ws;
|
else
|
else
|
-- sync i2s_ws_io to our clock domaine
|
-- sync i2s_ws_io to our clock domaine
|
zws <= i2s_ws;
|
zws <= i2s_ws;
|
zzws <= zws;
|
zzws <= zws;
|
zzzws <= zzws;
|
zzzws <= zzws;
|
-- detect negative edge
|
-- detect negative edge
|
if zzzws = '1' and zzws = '0' then
|
if zzzws = '1' and zzws = '0' then
|
ws_neg_edge <= '1';
|
ws_neg_edge <= '1';
|
else
|
else
|
ws_neg_edge <= '0';
|
ws_neg_edge <= '0';
|
end if;
|
end if;
|
-- detect positive edge
|
-- detect positive edge
|
if zzzws = '0' and zzws = '1' then
|
if zzzws = '0' and zzws = '1' then
|
ws_pos_edge <= '1';
|
ws_pos_edge <= '1';
|
else
|
else
|
ws_pos_edge <= '0';
|
ws_pos_edge <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process WSDET;
|
end process WSDET;
|
end generate WSD;
|
end generate WSD;
|
|
|
-- Logic to generate clock signal, master mode
|
-- Logic to generate clock signal, master mode
|
SCKM : if IS_MASTER = 1 generate
|
SCKM : if IS_MASTER = 1 generate
|
i2s_sck_o <= toggle;
|
i2s_sck_o <= toggle;
|
end generate SCKM;
|
end generate SCKM;
|
|
|
-- Process to receive data on i2s_sd_i, or transmit data on i2s_sd_o
|
-- Process to receive data on i2s_sd_i, or transmit data on i2s_sd_o
|
sample_addr <= std_logic_vector(to_unsigned(adr_cnt, ADDR_WIDTH - 1));
|
sample_addr <= std_logic_vector(to_unsigned(adr_cnt, ADDR_WIDTH - 1));
|
mem_rdwr <= imem_rdwr;
|
mem_rdwr <= imem_rdwr;
|
sample_dat_o <= data_in;
|
sample_dat_o <= data_in;
|
|
|
SDRX : process (wb_clk_i)
|
SDRX : process (wb_clk_i)
|
begin
|
begin
|
if rising_edge(wb_clk_i) then
|
if rising_edge(wb_clk_i) then
|
if conf_en = '0' then -- codec disabled
|
if conf_en = '0' then -- codec disabled
|
imem_rdwr <= '0';
|
imem_rdwr <= '0';
|
sd_ctrl <= IDLE;
|
sd_ctrl <= IDLE;
|
data_in <= (others => '0');
|
data_in <= (others => '0');
|
bit_cnt <= 0;
|
bit_cnt <= 0;
|
bits_to_trx <= 0;
|
bits_to_trx <= 0;
|
new_word <= '0';
|
new_word <= '0';
|
last_bit <= '0';
|
last_bit <= '0';
|
adr_cnt <= 0;
|
adr_cnt <= 0;
|
evt_lsbf <= '0';
|
evt_lsbf <= '0';
|
evt_hsbf <= '0';
|
evt_hsbf <= '0';
|
i2s_sd_o <= '0';
|
i2s_sd_o <= '0';
|
else
|
else
|
case sd_ctrl is
|
case sd_ctrl is
|
when IDLE =>
|
when IDLE =>
|
imem_rdwr <= '0';
|
imem_rdwr <= '0';
|
if to_integer(unsigned(conf_res)) > 15 and
|
if to_integer(unsigned(conf_res)) > 15 and
|
to_integer(unsigned(conf_res)) < 33 then
|
to_integer(unsigned(conf_res)) < 33 then
|
bits_to_trx <= to_integer(unsigned(conf_res)) - 1;
|
bits_to_trx <= to_integer(unsigned(conf_res)) - 1;
|
else
|
else
|
bits_to_trx <= 15;
|
bits_to_trx <= 15;
|
end if;
|
end if;
|
if conf_en = '1' then
|
if conf_en = '1' then
|
if (ws_pos_edge = '1' and conf_swap = '1') or
|
if (ws_pos_edge = '1' and conf_swap = '1') or
|
(ws_neg_edge = '1' and conf_swap = '0') then
|
(ws_neg_edge = '1' and conf_swap = '0') then
|
if receiver = '1' then -- recevier
|
if receiver = '1' then -- recevier
|
sd_ctrl <= WAIT_CLK;
|
sd_ctrl <= WAIT_CLK;
|
else
|
else
|
imem_rdwr <= '1'; -- read first data if transmitter
|
imem_rdwr <= '1'; -- read first data if transmitter
|
sd_ctrl <= TRX_DATA;
|
sd_ctrl <= TRX_DATA;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
when WAIT_CLK => -- wait for first bit after WS
|
when WAIT_CLK => -- wait for first bit after WS
|
adr_cnt <= 0;
|
adr_cnt <= 0;
|
bit_cnt <= 0;
|
bit_cnt <= 0;
|
new_word <= '0';
|
new_word <= '0';
|
last_bit <= '0';
|
last_bit <= '0';
|
data_in <= (others => '0');
|
data_in <= (others => '0');
|
if i2s_clk_en = '1' and neg_edge = '0' then
|
if i2s_clk_en = '1' and neg_edge = '0' then
|
sd_ctrl <= TRX_DATA;
|
sd_ctrl <= TRX_DATA;
|
end if;
|
end if;
|
when TRX_DATA => -- transmit/receive serial data
|
when TRX_DATA => -- transmit/receive serial data
|
imem_rdwr <= '0';
|
imem_rdwr <= '0';
|
evt_hsbf <= '0';
|
evt_hsbf <= '0';
|
evt_lsbf <= '0';
|
evt_lsbf <= '0';
|
if master = '0' then
|
if master = '0' then
|
if zzzws /= zzws then
|
if zzzws /= zzws then
|
new_word <= '1';
|
new_word <= '1';
|
end if;
|
end if;
|
else
|
else
|
if ws_pos_edge = '1' or ws_neg_edge = '1' then
|
if ws_pos_edge = '1' or ws_neg_edge = '1' then
|
new_word <= '1';
|
new_word <= '1';
|
end if;
|
end if;
|
end if;
|
end if;
|
if new_word = '1' and i2s_clk_en = '1' and neg_edge = '0' then
|
if new_word = '1' and i2s_clk_en = '1' and neg_edge = '0' then
|
last_bit <= '1';
|
last_bit <= '1';
|
end if;
|
end if;
|
-- recevier operation
|
-- recevier operation
|
if receiver = '1' then
|
if receiver = '1' then
|
if i2s_clk_en = '1' and neg_edge = '1' then
|
if i2s_clk_en = '1' and neg_edge = '1' then
|
if master = '1' then -- master mode
|
if master = '1' then -- master mode
|
if bit_cnt < bits_to_trx and new_word = '0' then
|
if bit_cnt < bits_to_trx and new_word = '0' then
|
bit_cnt <= bit_cnt + 1;
|
bit_cnt <= bit_cnt + 1;
|
data_in(bits_to_trx - bit_cnt) <= i2s_sd_i;
|
data_in(bits_to_trx - bit_cnt) <= i2s_sd_i;
|
else
|
else
|
imem_rdwr <= '1';
|
imem_rdwr <= '1';
|
data_in(bits_to_trx - bit_cnt) <= i2s_sd_i;
|
data_in(bits_to_trx - bit_cnt) <= i2s_sd_i;
|
sd_ctrl <= RX_WRITE;
|
sd_ctrl <= RX_WRITE;
|
end if;
|
end if;
|
else -- slave mode
|
else -- slave mode
|
if bit_cnt <= bits_to_trx and new_word = '0' then
|
if bit_cnt <= bits_to_trx and new_word = '0' then
|
bit_cnt <= bit_cnt + 1;
|
bit_cnt <= bit_cnt + 1;
|
data_in(bits_to_trx - bit_cnt) <= i2s_sd_i;
|
data_in(bits_to_trx - bit_cnt) <= i2s_sd_i;
|
else
|
else
|
|
data_in(bits_to_trx - bit_cnt) <= i2s_sd_i;
|
imem_rdwr <= '1';
|
imem_rdwr <= '1';
|
sd_ctrl <= RX_WRITE;
|
sd_ctrl <= RX_WRITE;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
-- transmitter operation
|
-- transmitter operation
|
if receiver = '0' then
|
if receiver = '0' then
|
if master = '1' then -- master mode
|
if master = '1' then -- master mode
|
if i2s_clk_en = '1' and neg_edge = '0' then
|
if i2s_clk_en = '1' and neg_edge = '0' then
|
if bit_cnt < bits_to_trx and new_word = '0' then
|
if bit_cnt < bits_to_trx and new_word = '0' then
|
bit_cnt <= bit_cnt + 1;
|
bit_cnt <= bit_cnt + 1;
|
i2s_sd_o <= sample_dat_i(bits_to_trx - bit_cnt);
|
i2s_sd_o <= sample_dat_i(bits_to_trx - bit_cnt);
|
else
|
else
|
bit_cnt <= bit_cnt + 1;
|
bit_cnt <= bit_cnt + 1;
|
if bit_cnt > bits_to_trx then
|
if bit_cnt > bits_to_trx then
|
i2s_sd_o <= '0';
|
i2s_sd_o <= '0';
|
else
|
else
|
i2s_sd_o <= sample_dat_i(0);
|
i2s_sd_o <= sample_dat_i(0);
|
end if;
|
end if;
|
-- transmitter address counter
|
-- transmitter address counter
|
imem_rdwr <= '1';
|
imem_rdwr <= '1';
|
adr_cnt <= (adr_cnt + 1) mod 2**(ADDR_WIDTH - 1);
|
adr_cnt <= (adr_cnt + 1) mod 2**(ADDR_WIDTH - 1);
|
if adr_cnt = 2**(ADDR_WIDTH - 2) - 1 then
|
if adr_cnt = 2**(ADDR_WIDTH - 2) - 1 then
|
evt_lsbf <= '1';
|
evt_lsbf <= '1';
|
else
|
else
|
evt_lsbf <= '0';
|
evt_lsbf <= '0';
|
end if;
|
end if;
|
if adr_cnt = 2**(ADDR_WIDTH - 1) - 1 then
|
if adr_cnt = 2**(ADDR_WIDTH - 1) - 1 then
|
evt_hsbf <= '1';
|
evt_hsbf <= '1';
|
else
|
else
|
evt_hsbf <= '0';
|
evt_hsbf <= '0';
|
end if;
|
end if;
|
sd_ctrl <= SYNC;
|
sd_ctrl <= SYNC;
|
end if;
|
end if;
|
end if;
|
end if;
|
else -- slave mode
|
else -- slave mode
|
if i2s_clk_en = '1' and neg_edge = '1' then
|
if i2s_clk_en = '1' and neg_edge = '1' then
|
if bit_cnt < bits_to_trx and new_word = '0' then
|
if bit_cnt < bits_to_trx and new_word = '0' then
|
bit_cnt <= bit_cnt + 1;
|
bit_cnt <= bit_cnt + 1;
|
i2s_sd_o <= sample_dat_i(bits_to_trx - bit_cnt);
|
i2s_sd_o <= sample_dat_i(bits_to_trx - bit_cnt);
|
else
|
else
|
bit_cnt <= bit_cnt + 1;
|
bit_cnt <= bit_cnt + 1;
|
if bit_cnt > bits_to_trx then
|
if bit_cnt > bits_to_trx then
|
i2s_sd_o <= '0';
|
i2s_sd_o <= '0';
|
else
|
else
|
i2s_sd_o <= sample_dat_i(bits_to_trx - bit_cnt);
|
i2s_sd_o <= sample_dat_i(bits_to_trx - bit_cnt);
|
end if;
|
end if;
|
if new_word = '1' then -- transmitter address counter
|
if new_word = '1' then -- transmitter address counter
|
imem_rdwr <= '1';
|
imem_rdwr <= '1';
|
adr_cnt <= (adr_cnt + 1) mod 2**(ADDR_WIDTH - 1);
|
adr_cnt <= (adr_cnt + 1) mod 2**(ADDR_WIDTH - 1);
|
if adr_cnt = 2**(ADDR_WIDTH - 2) - 1 then
|
if adr_cnt = 2**(ADDR_WIDTH - 2) - 1 then
|
evt_lsbf <= '1';
|
evt_lsbf <= '1';
|
else
|
else
|
evt_lsbf <= '0';
|
evt_lsbf <= '0';
|
end if;
|
end if;
|
if adr_cnt = 2**(ADDR_WIDTH - 1) - 1 then
|
if adr_cnt = 2**(ADDR_WIDTH - 1) - 1 then
|
evt_hsbf <= '1';
|
evt_hsbf <= '1';
|
else
|
else
|
evt_hsbf <= '0';
|
evt_hsbf <= '0';
|
end if;
|
end if;
|
sd_ctrl <= SYNC;
|
sd_ctrl <= SYNC;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
when RX_WRITE => -- write received word to sample buffer
|
when RX_WRITE => -- write received word to sample buffer
|
imem_rdwr <= '0';
|
imem_rdwr <= '0';
|
adr_cnt <= (adr_cnt + 1) mod 2**(ADDR_WIDTH - 1);
|
adr_cnt <= (adr_cnt + 1) mod 2**(ADDR_WIDTH - 1);
|
if adr_cnt = 2**(ADDR_WIDTH - 2) - 1 then
|
if adr_cnt = 2**(ADDR_WIDTH - 2) - 1 then
|
evt_lsbf <= '1';
|
evt_lsbf <= '1';
|
else
|
else
|
evt_lsbf <= '0';
|
evt_lsbf <= '0';
|
end if;
|
end if;
|
if adr_cnt = 2**(ADDR_WIDTH - 1) - 1 then
|
if adr_cnt = 2**(ADDR_WIDTH - 1) - 1 then
|
evt_hsbf <= '1';
|
evt_hsbf <= '1';
|
else
|
else
|
evt_hsbf <= '0';
|
evt_hsbf <= '0';
|
end if;
|
end if;
|
sd_ctrl <= SYNC;
|
sd_ctrl <= SYNC;
|
when SYNC => -- synchronise with next word
|
when SYNC => -- synchronise with next word
|
imem_rdwr <= '0';
|
imem_rdwr <= '0';
|
evt_hsbf <= '0';
|
evt_hsbf <= '0';
|
evt_lsbf <= '0';
|
evt_lsbf <= '0';
|
bit_cnt <= 0;
|
bit_cnt <= 0;
|
if ws_pos_edge = '1' or ws_neg_edge = '1' then
|
if ws_pos_edge = '1' or ws_neg_edge = '1' then
|
new_word <= '1';
|
new_word <= '1';
|
end if;
|
end if;
|
if new_word = '1' and i2s_clk_en = '1' and neg_edge = '0' then
|
if new_word = '1' and i2s_clk_en = '1' and neg_edge = '0' then
|
last_bit <= '1';
|
last_bit <= '1';
|
end if;
|
end if;
|
if receiver = '1' then -- receive mode
|
if receiver = '1' then -- receive mode
|
if master = '1' then
|
if master = '1' then
|
new_word <= '0';
|
new_word <= '0';
|
last_bit <= '0';
|
last_bit <= '0';
|
data_in <= (others => '0');
|
data_in <= (others => '0');
|
sd_ctrl <= TRX_DATA;
|
sd_ctrl <= TRX_DATA;
|
else
|
else
|
if i2s_clk_en = '1' and neg_edge = '0' and new_word = '1' then
|
if i2s_clk_en = '1' and neg_edge = '0' and new_word = '1' then
|
new_word <= '0';
|
new_word <= '0';
|
last_bit <= '0';
|
last_bit <= '0';
|
data_in <= (others => '0');
|
data_in <= (others => '0');
|
sd_ctrl <= TRX_DATA;
|
sd_ctrl <= TRX_DATA;
|
end if;
|
end if;
|
end if;
|
end if;
|
else -- transmit mode
|
else -- transmit mode
|
if master = '1' then
|
if master = '1' then
|
new_word <= '0';
|
new_word <= '0';
|
last_bit <= '0';
|
last_bit <= '0';
|
data_in <= (others => '0');
|
data_in <= (others => '0');
|
sd_ctrl <= TRX_DATA;
|
sd_ctrl <= TRX_DATA;
|
elsif i2s_clk_en = '1' and neg_edge = '0' then
|
elsif i2s_clk_en = '1' and neg_edge = '0' then
|
new_word <= '0';
|
new_word <= '0';
|
last_bit <= '0';
|
last_bit <= '0';
|
data_in <= (others => '0');
|
data_in <= (others => '0');
|
sd_ctrl <= TRX_DATA;
|
sd_ctrl <= TRX_DATA;
|
end if;
|
end if;
|
end if;
|
end if;
|
when others => null;
|
when others => null;
|
end case;
|
end case;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process SDRX;
|
end process SDRX;
|
|
|
end rtl;
|
end rtl;
|
|
|