Files
2025-02-19 14:42:38 +01:00

535 lines
23 KiB
VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity axis_dma is
generic (
DWIDTH : positive := 32;
IDWIDTH : positive := 1;
MAX_BURSTLEN : positive := 16;
FIFO_AWIDTH : positive := 8;
polynomial_default : std_logic_vector(31 downto 0) := x"04C11DB7"
);
port (
CLK : in std_logic;
RESETN : in std_logic;
INTERRUPT : out std_logic := '0';
-- Parameters for crc calulaction
initialValue : out std_logic_vector(31 downto 0);
polynomial : out std_logic_vector(31 downto 0);
finalXOR : out std_logic_vector(31 downto 0);
inOutReflected : out std_logic_vector( 1 downto 0);
-- AXIL Slave Interface
S_AXIL_AWADDR : in std_logic_vector(7 downto 0);
S_AXIL_AWVALID : in std_logic;
S_AXIL_AWREADY : out std_logic;
S_AXIL_WDATA : in std_logic_vector(31 downto 0);
S_AXIL_WVALID : in std_logic;
S_AXIL_WREADY : out std_logic;
S_AXIL_WSTRB : in std_logic_vector((32/8)-1 downto 0);
S_AXIL_BVALID : out std_logic;
S_AXIL_BREADY : in std_logic;
S_AXIL_BRESP : out std_logic_vector(1 downto 0);
S_AXIL_ARADDR : in std_logic_vector(7 downto 0);
S_AXIL_ARVALID : in std_logic;
S_AXIL_ARREADY : out std_logic;
S_AXIL_RDATA : out std_logic_vector(31 downto 0);
S_AXIL_RVALID : out std_logic;
S_AXIL_RREADY : in std_logic;
S_AXIL_RRESP : out std_logic_vector(1 downto 0);
-- AXI Master Interface (Memory)
M_AXI_ARREADY : in std_logic;
M_AXI_ARVALID : out std_logic := '0';
M_AXI_ARADDR : out std_logic_vector(31 downto 0);
M_AXI_ARID : out std_logic_vector(IDWIDTH-1 downto 0);
M_AXI_ARLEN : out std_logic_vector( 3 downto 0);
M_AXI_ARSIZE : out std_logic_vector( 2 downto 0);
M_AXI_ARBURST : out std_logic_vector( 1 downto 0);
M_AXI_ARPROT : out std_logic_vector( 2 downto 0);
M_AXI_ARCACHE : out std_logic_vector( 3 downto 0);
M_AXI_RREADY : out std_logic;
M_AXI_RVALID : in std_logic;
M_AXI_RDATA : in std_logic_vector(DWIDTH-1 downto 0);
M_AXI_RRESP : in std_logic_vector( 1 downto 0);
M_AXI_RID : in std_logic_vector(IDWIDTH-1 downto 0);
M_AXI_RLAST : in std_logic;
M_AXI_AWREADY : in std_logic := '0';
M_AXI_AWVALID : out std_logic := '0';
M_AXI_AWADDR : out std_logic_vector(31 downto 0);
M_AXI_AWLEN : out std_logic_vector( 3 downto 0);
M_AXI_AWSIZE : out std_logic_vector( 2 downto 0);
M_AXI_AWID : out std_logic_vector(IDWIDTH-1 downto 0);
M_AXI_AWBURST : out std_logic_vector( 1 downto 0);
M_AXI_AWPROT : out std_logic_vector( 2 downto 0);
M_AXI_AWCACHE : out std_logic_vector( 3 downto 0);
M_AXI_WREADY : in std_logic := '0';
M_AXI_WVALID : out std_logic := '0';
M_AXI_WDATA : out std_logic_vector(DWIDTH-1 downto 0);
M_AXI_WSTRB : out std_logic_vector(DWIDTH/8-1 downto 0);
M_AXI_WLAST : out std_logic := '0';
M_AXI_WID : out std_logic_vector(DWIDTH-1 downto 0);
M_AXI_BREADY : out std_logic;
M_AXI_BVALID : in std_logic := '0';
M_AXI_BID : in std_logic_vector( DWIDTH-1 downto 0);
M_AXI_BRESP : in std_logic_vector( 1 downto 0);
-- AXI Streaming Target Port
S_AXIS_TVALID : in std_logic;
S_AXIS_TDATA : in std_logic_vector(31 downto 0);
S_AXIS_TLAST : in std_logic := '0';
S_AXIS_TREADY : out std_logic;
S_AXIS_NUM_AVAIL : in std_logic_vector(7 downto 0); -- FIFO
-- AXI Streaming Initiator Port
M_AXIS_TVALID : out std_logic;
M_AXIS_TDATA : out std_logic_vector(31 downto 0);
M_AXIS_TLAST : out std_logic;
M_AXIS_TREADY : in std_logic;
M_AXIS_NUM_FREE : in std_logic_vector(7 downto 0) -- FIFO
);
end entity;
architecture rtl of axis_dma is
-- AXIL Registers
signal run_reg : std_logic := '0';
signal interrupt_enable_reg : std_logic;
signal read_address_reg : std_logic_vector(31 downto 0);
signal write_address_reg : std_logic_vector(31 downto 0);
signal packet_size_reg : std_logic_vector(15 downto 0);
signal packet_number_reg : std_logic_vector(15 downto 0);
signal polynomial_reg : std_logic_vector(31 downto 0);
signal initialValue_reg : std_logic_vector(31 downto 0);
signal finalXOR_reg : std_logic_vector(31 downto 0);
signal inOut_reflected_reg : std_logic_vector( 1 downto 0);
signal axcache_reg : std_logic_vector( 7 downto 0);
-- Helper Signals
signal run_reg_set : std_logic;
signal run_reg_clear : std_logic;
-- M_AXI Read Data state machine
type read_state_t is (IDLE, REQ, WAIT_REQ_ACCEPT, READ_DATA, FINISHED);
signal read_state : read_state_t := IDLE;
-- M_AXI Write Data state machine
type write_state_t is (IDLE, REQ, WAIT_REQ_ACCEPT, WRITE_DATA, FINISHED);
signal write_state : write_state_t := IDLE;
-- control signals
signal interrupt_reset : std_logic;
signal packet_last_word : std_logic := '0';
signal interrupt_sig : std_logic := '0';
begin
-------------------------------------------
-- Interrupt
-------------------------------------------
interrupt_sig <= '1' when read_state=FINISHED and write_state=FINISHED and interrupt_enable_reg='1' else '0';
INTERRUPT <= interrupt_sig;
-------------------------------------------
-- S_AXIL Schnittstelle
-------------------------------------------
S_AXIL_BRESP <= (others=>'0'); -- No write errors
S_AXIL_RRESP <= (others=>'0'); -- No read errors
S_AXIL_ARREADY <= '1'; -- IP is always ready
S_AXIL_AWREADY <= S_AXIL_AWVALID and S_AXIL_WVALID;
S_AXIL_WREADY <= S_AXIL_AWVALID and S_AXIL_WVALID;
-- AXIL Register nach Aussen fuehren
polynomial <= polynomial_reg;
initialValue <= initialValue_reg;
inOutReflected <= inOut_reflected_reg;
finalXOR <= finalXOR_reg;
process
begin
wait until rising_edge(CLK);
if RESETN = '0' then
S_AXIL_BVALID <= '0';
S_AXIL_RVALID <= '0';
-- AXIL-Register zuruecksetzen
run_reg <= '0';
run_reg_set <= '0';
interrupt_enable_reg <= '0';
read_address_reg <= (others=>'0');
write_address_reg <= (others=>'0');
packet_number_reg <= (others=>'0');
packet_size_reg <= (others=>'0');
polynomial_reg <= polynomial_default;
initialValue_reg <= (others=>'0');
finalXOR_reg <= (others=>'0');
inOut_reflected_reg <= (others=>'0');
axcache_reg <= "00110011";
else
-- FLip Flop-Register fuer sauberes Setzen und Loeschen des Run-Signals
if interrupt_sig = '1' then
run_reg <= '0';
elsif run_reg_set = '1' then
run_reg <= '1';
elsif run_reg_clear = '1' then
run_reg <= '0';
end if;
-- Lesezugriff
if S_AXIL_RREADY = '1' then
S_AXIL_RVALID <= '0';
end if;
if S_AXIL_ARVALID = '1' then
S_AXIL_RDATA <= (others=>'0');
if S_AXIL_ARADDR(7 downto 0) = x"00" then
S_AXIL_RDATA(0) <= run_reg;
S_AXIL_RDATA(1) <= interrupt_enable_reg;
elsif S_AXIL_ARADDR(7 downto 0) = x"04" then
S_AXIL_RDATA(0) <= interrupt_sig;
elsif S_AXIL_ARADDR(7 downto 0) = x"08" then
S_AXIL_RDATA <= read_address_reg;
elsif S_AXIL_ARADDR(7 downto 0) = x"0C" then
S_AXIL_RDATA <= write_address_reg;
elsif S_AXIL_ARADDR(7 downto 0) = x"10" then
S_AXIL_RDATA(15 downto 0) <= packet_size_reg;
elsif S_AXIL_ARADDR(7 downto 0) = x"14" then
S_AXIL_RDATA(15 downto 0) <= packet_number_reg;
elsif S_AXIL_ARADDR(7 downto 0) = x"18" then
S_AXIL_RDATA <= polynomial_reg;
elsif S_AXIL_ARADDR(7 downto 0) = x"1C" then
S_AXIL_RDATA <= initialValue_reg;
elsif S_AXIL_ARADDR(7 downto 0) = x"20" then
S_AXIL_RDATA <= finalXOR_reg;
elsif S_AXIL_ARADDR(7 downto 0) = x"24" then
S_AXIL_RDATA(1 downto 0) <= inOut_reflected_reg;
elsif S_AXIL_ARADDR(7 downto 0) = x"28" then
S_AXIL_RDATA(7 downto 0) <= axcache_reg;
end if;
S_AXIL_RVALID <= '1';
end if;
if S_AXIL_BREADY = '1' then
S_AXIL_BVALID <= '0';
end if;
interrupt_reset <= '0';
run_reg_set <= '0';
if S_AXIL_AWVALID = '1' and S_AXIL_WVALID = '1' then
S_AXIL_BVALID <= '1';
-- Register schreiben
if S_AXIL_AWADDR = x"00" then
if S_AXIL_WSTRB(0) = '1' then
run_reg_set <= S_AXIL_WDATA(0);
interrupt_enable_reg <= S_AXIL_WDATA(1);
end if;
elsif S_AXIL_AWADDR = x"04" then
if S_AXIL_WSTRB(0) = '1' then
interrupt_reset <= not S_AXIL_WDATA(0);
end if;
elsif S_AXIL_AWADDR = x"08" then
if S_AXIL_WSTRB = "1111" then
read_address_reg <= S_AXIL_WDATA;
end if;
elsif S_AXIL_AWADDR = x"0C" then
if S_AXIL_WSTRB = "1111" then
write_address_reg <= S_AXIL_WDATA;
end if;
elsif S_AXIL_AWADDR = x"10" then
if S_AXIL_WSTRB(1 downto 0) = "11" then
packet_size_reg <= S_AXIL_WDATA(15 downto 0);
end if;
elsif S_AXIL_AWADDR = x"14" then
if S_AXIL_WSTRB(1 downto 0) = "11" then
packet_number_reg <= S_AXIL_WDATA(15 downto 0);
end if;
elsif S_AXIL_AWADDR = x"18" then
if S_AXIL_WSTRB = "1111" then
polynomial_reg <= S_AXIL_WDATA;
end if;
elsif S_AXIL_AWADDR = x"1C" then
if S_AXIL_WSTRB = "1111" then
initialValue_reg <= S_AXIL_WDATA;
end if;
elsif S_AXIL_AWADDR = x"20" then
if S_AXIL_WSTRB = "1111" then
finalXOR_reg <= S_AXIL_WDATA;
end if;
elsif S_AXIL_AWADDR = x"24" then
if S_AXIL_WSTRB(0) = '1' then
inOut_reflected_reg <= S_AXIL_WDATA(1 downto 0);
end if;
elsif S_AXIL_AWADDR = x"28" then
if S_AXIL_WSTRB(0) = '1' then
axcache_reg <= S_AXIL_WDATA(7 downto 0);
end if;
end if;
end if;
end if;
end process;
-------------------------------------------
-- M_AXI Read data from DRAM state machine
-------------------------------------------
M_AXI_ARSIZE <= "010" when DWIDTH=32 else "011"; -- Data width 32/64
M_AXI_ARBURST <= "01";
M_AXI_ARPROT <= "000";
M_AXI_ARCACHE <= axcache_reg(7 downto 4);
M_AXI_ARID <= (others=>'0');
M_AXI_RREADY <= '1';
process
variable packets_cnt : unsigned(15 downto 0); -- Anzahl der verbleibenden Pakete Minus 1
variable packet_data_cnt : unsigned(15 downto 0); -- Anzahl der verbleibenden Worte beim aktuellen Packet Minus 1
variable data_cnt : unsigned(31 downto 0); -- Anzahl der insgesamt verbleibenden Worte Minus 1
variable read_addr_cnt : unsigned(31 downto 0); -- Zaehler fuer Adresse fuer AXI-Lesevorgaenge
variable burst_len : unsigned( 4 downto 0); -- Burstlaenge
variable bend : unsigned( 4 downto 0); -- Hilfsvariable zu Bestimmung der Burstlaenge
begin
wait until rising_edge(CLK);
if RESETN = '0' then
packets_cnt := (others=>'0');
packet_data_cnt := (others=>'0');
data_cnt := (others=>'0');
read_addr_cnt := (others=>'0');
burst_len := (others=>'0');
bend := (others=>'0');
M_AXI_ARVALID <= '0';
M_AXI_ARADDR <= (others=>'0');
M_AXI_ARLEN <= (others=>'0');
read_state <= IDLE;
else
case read_state is
when IDLE =>
if run_reg_set = '1' then
packets_cnt := unsigned(packet_number_reg);
packet_data_cnt := unsigned(packet_size_reg);
data_cnt := (unsigned(packet_size_reg)+1) * (unsigned(packet_number_reg)+1) - 1;
read_addr_cnt := unsigned(read_address_reg);
read_state <= REQ;
end if;
when REQ =>
if (unsigned(M_AXIS_NUM_FREE) >= MAX_BURSTLEN) then -- Lesen, wenn genug Platz im FIFO frei ist
M_AXI_ARADDR <= std_logic_vector(read_addr_cnt);
M_AXI_ARVALID <= '1';
-- Burstlaenge setzen
if (data_cnt+1) >= MAX_BURSTLEN then
burst_len := to_unsigned(MAX_BURSTLEN-1,5);
else
burst_len := '0' & data_cnt(3 downto 0);
end if;
bend := "0" & read_addr_cnt(5 downto 2) + burst_len;
if read_addr_cnt(11 downto 6) = "111111" and bend(4) = '1' then -- 4k boundary crossing?
burst_len := '0' & (not (read_addr_cnt(5 downto 2)));
end if;
M_AXI_ARLEN <= std_logic_vector(burst_len(3 downto 0));
read_addr_cnt := read_addr_cnt + 4 * (burst_len+1);
read_state <= WAIT_REQ_ACCEPT;
end if;
when WAIT_REQ_ACCEPT =>
if M_AXI_ARREADY = '1' then
M_AXI_ARVALID <= '0';
-- setzen des LAST Signals fuer Edge-case packet_size = 0
if packet_data_cnt = 0 then
packet_last_word <= '1';
end if;
read_state <= READ_DATA;
end if;
when READ_DATA =>
if M_AXI_RVALID = '1' then
-- Markieren des letzten Wortes
if packet_data_cnt = 1 then
packet_last_word <= '1';
end if;
-- Zaehler runterzaehlen
if packet_data_cnt = 0 then
packet_last_word <= '0';
if packets_cnt = 0 then
else
packets_cnt := packets_cnt - 1;
packet_data_cnt := unsigned(packet_size_reg);
end if;
else
packet_data_cnt := packet_data_cnt - 1;
end if;
if M_AXI_RLAST = '1' then
packet_last_word <= '0';
if data_cnt = 0 then -- Alle Datenpakete gelesen?
if interrupt_enable_reg = '1' then
read_state <= FINISHED;
else
read_state <= IDLE;
end if;
else
read_state <= REQ;
end if;
end if;
data_cnt := data_cnt - 1;
end if;
when FINISHED =>
-- Interrupt zuruecksetzen
if interrupt_reset = '1' then
read_state <= IDLE;
end if;
when others => null;
end case;
end if;
end process;
-------------------------------------------
-- M_AXIS und S_AXIS Interface connections
-------------------------------------------
M_AXIS_TVALID <= M_AXI_RVALID;
M_AXIS_TDATA <= M_AXI_RDATA;
M_AXIS_TLAST <= M_AXI_RVALID and packet_last_word;
S_AXIS_TREADY <= '1' when (write_state=WRITE_DATA) and M_AXI_WREADY = '1' else '0';
M_AXI_WVALID <= '1' when (write_state=WRITE_DATA) and S_AXIS_TVALID = '1' else '0';
M_AXI_WDATA <= S_AXIS_TDATA;
-------------------------------------------
-- M_AXI Write data to DRAM state machine
-------------------------------------------
M_AXI_AWSIZE <= "010" when DWIDTH=32 else "011"; -- Data width 32/64
M_AXI_AWBURST <= "01";
M_AXI_AWPROT <= "000";
M_AXI_AWCACHE <= axcache_reg(3 downto 0);
M_AXI_BREADY <= '1';
M_AXI_WSTRB <= (others=>'1');
M_AXI_AWID <= (others=>'0');
M_AXI_WID <= (others=>'0');
process
variable burst_data_cnt : unsigned( 4 downto 0); -- Zaehler fuer aktuellen Burst
variable data_cnt : unsigned(31 downto 0); -- Zaehler fuer noch zu schreibende Worte
variable write_addr : unsigned(31 downto 0); -- Zaehler fuer Schreibadresse
variable bend : unsigned( 4 downto 0); -- Hilfsvariable zu Bestimmung der Burstlaenge
begin
wait until rising_edge(CLK);
if RESETN = '0' then
burst_data_cnt := (others=>'0');
data_cnt := (others=>'0');
write_addr := (others=>'0');
bend := (others=>'0');
M_AXI_AWVALID <= '0';
M_AXI_AWADDR <= (others=>'0');
M_AXI_AWLEN <= (others=>'0');
M_AXI_WLAST <= '0';
run_reg_clear <= '0';
write_state <= IDLE;
else
case write_state is
when IDLE =>
if run_reg = '1' then
-- insgesamt zu sendende Worte = Paketanzahl * Paketgroesse
data_cnt := (unsigned(packet_size_reg)+1) * (unsigned(packet_number_reg)+1) - 1 + unsigned(packet_number_reg) + 1;
write_addr := unsigned(write_address_reg);
write_state <= REQ;
end if;
when REQ =>
-- Senden wenn mindestens eine ganze Burstlaenge zu Verfuegung steht
-- oder wenn nur noch restliche Daten, die weniger als eine Burstlaenge sind zur Verfuegung stehen
if unsigned(S_AXIS_NUM_AVAIL) >= MAX_BURSTLEN or ((data_cnt+1) < MAX_BURSTLEN and unsigned(S_AXIS_NUM_AVAIL) = (data_cnt+1)) then
M_AXI_AWADDR <= std_logic_vector(write_addr);
M_AXI_AWVALID <= '1';
-- Burstlaenge setzen
if unsigned(S_AXIS_NUM_AVAIL) >= MAX_BURSTLEN then
burst_data_cnt := to_unsigned(MAX_BURSTLEN-1,5);
else
burst_data_cnt := '0' & data_cnt(3 downto 0);
end if;
bend := "0" & write_addr(5 downto 2) + burst_data_cnt;
if write_addr(11 downto 6) = "111111" and bend(4) = '1' then -- 4k boundary crossing?
burst_data_cnt := '0' & unsigned(not (write_addr(5 downto 2)));
end if;
M_AXI_AWLEN <= std_logic_vector(burst_data_cnt(3 downto 0));
write_addr := write_addr + 4 * (burst_data_cnt+1);
write_state <= WAIT_REQ_ACCEPT;
end if;
when WAIT_REQ_ACCEPT =>
if M_AXI_AWREADY = '1' then
M_AXI_AWVALID <= '0';
-- Last Signal richtig setzen fuer Edge-case: M_AXI_AWLEN = "0000"
if burst_data_cnt = 0 then
M_AXI_WLAST <= '1';
end if;
write_state <= WRITE_DATA;
end if;
when WRITE_DATA =>
if M_AXI_WREADY = '1' then
if burst_data_cnt = 1 then
M_AXI_WLAST <= '1';
end if;
if burst_data_cnt = 0 then
M_AXI_WLAST <= '0';
if data_cnt = 0 then
write_state <= FINISHED;
-- clear run register
run_reg_clear <= '1';
else
write_state <= REQ;
end if;
end if;
burst_data_cnt := burst_data_cnt - 1;
data_cnt := data_cnt - 1;
end if;
when FINISHED =>
run_reg_clear <= '0';
-- Interrupt zuruecksetzen, falls Interrupt aktiviert
if interrupt_enable_reg = '0' then
write_state <= IDLE;
elsif interrupt_reset = '1' then
write_state <= IDLE;
end if;
when others => null;
end case;
end if;
end process;
end architecture;