OpenCores
URL https://opencores.org/ocsvn/fade_ether_protocol/fade_ether_protocol/trunk

Subversion Repositories fade_ether_protocol

[/] [fade_ether_protocol/] [trunk/] [stable_jumbo_frames_version/] [fpga/] [src/] [desc_manager_simple.vhd] - Rev 45

Compare with Previous | Blame | View Log

-------------------------------------------------------------------------------
-- Title      : FPGA Ethernet interface - descriptor manager
-- Project    : 
-------------------------------------------------------------------------------
-- File       : desc_manager.vhd
-- Author     : Wojciech M. Zabolotny (wzab@ise.pw.edu.pl)
-- License    : BSD License
-- Company    : 
-- Created    : 2012-03-30
-- Last update: 2017-01-23
-- Platform   : 
-- Standard   : VHDL'93
-------------------------------------------------------------------------------
-- Description: This file implements the state machine, which manages the
-- table of packet descriptors, used to resend only not confirmed packets
-------------------------------------------------------------------------------
-- Copyright (c) 2012 
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author  Description
-- 2012-03-30  1.0      WZab      Created
-------------------------------------------------------------------------------
 
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
library work;
use work.pkt_ack_pkg.all;
use work.desc_mgr_pkg.all;
use work.pkt_desc_pkg.all;
 
entity desc_memory is
 
  port (
    clk       : in  std_logic;
    desc_we   : in  std_logic;
    desc_addr : in  integer range 0 to N_OF_PKTS-1;
    desc_out  : in  pkt_desc;
    desc_in   : out pkt_desc);
 
end desc_memory;
 
architecture beh1 of desc_memory is
 
  type T_PKT_DESC_MEM is array (0 to N_OF_PKTS-1) of std_logic_vector(pkt_desc_width-1 downto 0);
  signal desc_mem : T_PKT_DESC_MEM                              := (others => (others => '0'));
  signal din      : std_logic_vector(pkt_desc_width-1 downto 0) := (others => '0');
  signal dout     : std_logic_vector(pkt_desc_width-1 downto 0) := (others => '0');
  signal rdaddr   : integer range 0 to N_OF_PKTS-1;
 
 
begin  -- beh1
 
  din     <= pkt_desc_to_stlv(desc_out);
  desc_in <= stlv_to_pkt_desc(dout);
 
  process (clk)
  begin  -- process
    if (clk'event and clk = '1') then   -- rising clock edge
      if (desc_we = '1') then
        desc_mem(desc_addr) <= din;
      end if;
      rdaddr <= desc_addr;
    end if;
  end process;
  dout <= desc_mem(rdaddr);
 
end beh1;
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
library work;
use work.pkt_ack_pkg.all;
use work.desc_mgr_pkg.all;
use work.pkt_desc_pkg.all;
 
entity desc_manager is
 
  generic (
    LOG2_N_OF_PKTS : integer := LOG2_N_OF_PKTS;
    N_OF_PKTS      : integer := N_OF_PKTS
    );                                  -- Number of packet_logi buffers
 
  port (
    -- Data input interface
    dta              : in  std_logic_vector(63 downto 0);
    dta_we           : in  std_logic;
    dta_eod          : in  std_logic;
    dta_ready        : out std_logic;
    -- ETH Sender interface
    pkt_number       : out unsigned(31 downto 0);
    seq_number       : out unsigned(15 downto 0);
    cmd_response_out : out std_logic_vector(12*8-1 downto 0);
    snd_cmd_start    : out std_logic;
    snd_start        : out std_logic;
    flushed          : out std_logic;
    snd_ready        : in  std_logic;
 
    -- Data memory interface
    dmem_addr       : out std_logic_vector(LOG2_NWRDS_IN_PKT+LOG2_N_OF_PKTS-1 downto 0);
    dmem_dta        : out std_logic_vector(63 downto 0);
    dmem_we         : out std_logic;
    -- Interface to the ACK FIFO
    ack_fifo_empty  : in  std_logic;
    ack_fifo_rd_en  : out std_logic;
    ack_fifo_dout   : in  std_logic_vector(pkt_ack_width-1 downto 0);
    -- User command interface
    cmd_code        : out std_logic_vector(15 downto 0);
    cmd_seq         : out std_logic_vector(15 downto 0);
    cmd_arg         : out std_logic_vector(31 downto 0);
    cmd_run         : out std_logic;
    cmd_retr_s      : out std_logic;
    cmd_ack         : in  std_logic;
    cmd_response_in : in  std_logic_vector(8*12-1 downto 0);
    retr_count      : out std_logic_vector(31 downto 0);
    --
    transmit_data   : in  std_logic;
    transm_delay    : out unsigned(31 downto 0);
    --
    dbg             : out std_logic_vector(3 downto 0);
    --
    clk             : in  std_logic;
    rst_n           : in  std_logic);
 
end desc_manager;
 
architecture dmgr_a1 of desc_manager is
 
  constant PKT_CNT_MAX : integer := 3000;
 
 
  function is_bigger (
    constant v1, v2 : unsigned(15 downto 0))
    return boolean is
    variable res : boolean;
    variable tmp : unsigned(15 downto 0);
  begin  -- function is_bigger
    -- subtract v2-v1 modulo 2**16
    tmp := v2-v1;
    -- if the result is "negative" - bit 15 is '1'
    -- and we consider v1 to be "bigger" (in modulo sense) than v2
    if tmp(15) = '1' then
      return true;
    else
      return false;
    end if;
 
  end function is_bigger;
 
  -- To simplify description of state machines, all registers are grouped
  -- in a record :
 
  type T_DESC_MGR_REGS is record
    cmd_ack        : std_logic;
    cmd_ack_0      : std_logic;
    cmd_run        : std_logic;
    cmd_retr       : std_logic;
    cmd_code       : unsigned(15 downto 0);
    cmd_seq        : unsigned(15 downto 0);
    cmd_arg        : unsigned(31 downto 0);
    pkt            : unsigned(31 downto 0);
    cur_pkt        : unsigned(31 downto 0);
    seq            : unsigned(15 downto 0);
    ack_seq        : unsigned(15 downto 0);
    retr_flag      : std_logic;
    flushed        : std_logic;
    all_pkt_count  : integer range 0 to PKT_CNT_MAX;
    retr_pkt_count : integer range 0 to PKT_CNT_MAX;
    retr_delay     : unsigned(31 downto 0);
    retr_count     : unsigned(31 downto 0);
    transm_delay   : unsigned(31 downto 0);
    nxt            : unsigned(LOG2_N_OF_PKTS-1 downto 0);
    tail_ptr       : unsigned(LOG2_N_OF_PKTS-1 downto 0);
    head_ptr       : unsigned(LOG2_N_OF_PKTS-1 downto 0);
    retr_ptr       : unsigned(LOG2_N_OF_PKTS-1 downto 0);  -- Number of the packet buffer, which is retransmitted
                                        -- when equal to head_ptr -
                                        -- retransmission is finished
    retr_nxt       : unsigned(LOG2_N_OF_PKTS-1 downto 0);  -- buffer, which will be
                                        -- retransmitted next
                                                           -- when equal to head_ptr -- no retransmission
                                                           -- is performed
  end record;
 
  constant DESC_MGR_REGS_INI : T_DESC_MGR_REGS := (
    retr_delay     => (others => '0'),
    retr_count     => (others => '0'),
    transm_delay   => to_unsigned(16, 32),
    all_pkt_count  => 0,
    retr_pkt_count => 0,
    cmd_ack_0      => '0',
    cmd_ack        => '0',
    cmd_run        => '0',
    cmd_retr       => '0',
    cmd_code       => (others => '0'),
    cmd_seq        => (others => '0'),
    cmd_arg        => (others => '0'),
    pkt            => (others => '0'),
    seq            => (others => '0'),
    ack_seq        => (others => '0'),
    retr_flag      => '0',
    flushed        => '0',
    cur_pkt        => (others => '0'),
    nxt            => (others => '0'),
    tail_ptr       => (others => '0'),
    head_ptr       => (others => '0'),
    retr_ptr       => (others => '0'),
    retr_nxt       => (others => '0')
    );
 
  -- To simplify setting of outputs of my Mealy state machine, all combinatorial
  -- outputs are grouped in a record
  type T_DESC_MGR_COMB is record
    dta_buf_free  : std_logic;
    desc_addr     : unsigned(LOG2_N_OF_PKTS-1 downto 0);
    desc_we       : std_logic;
    ack_rd        : std_logic;
    snd_start     : std_logic;
    snd_cmd_start : std_logic;
    desc_out      : pkt_desc;
  end record;
 
  constant DESC_MGR_COMB_DEFAULT : T_DESC_MGR_COMB :=
    (
      dta_buf_free  => '0',
      desc_addr     => (others => '0'),
      desc_we       => '0',
      ack_rd        => '0',
      snd_start     => '0',
      snd_cmd_start => '0',
      desc_out      => (
        confirmed   => '0',
        valid       => '0',
        sent        => '0',
        flushed     => '0',
        pkt         => (others => '0'),
        seq         => (others => '0')
        )
      );
 
  type T_DESC_MGR_STATE is (ST_DMGR_IDLE, ST_DMGR_CMD, ST_DMGR_START, ST_DMGR_RST, ST_DMGR_RST1,
                            ST_DMGR_ACK1, ST_DMGR_INS1, ST_DMGR_INS2, ST_DMGR_ACK_TAIL,
                            ST_DMGR_ACK_TAIL_1,
                            ST_DMGR_RETR, ST_DMGR_RETR_2);
 
  signal desc_in : pkt_desc;
 
  signal r, r_i                      : T_DESC_MGR_REGS  := DESC_MGR_REGS_INI;
  signal c                           : T_DESC_MGR_COMB;
  signal dmgr_state, dmgr_state_next : T_DESC_MGR_STATE := ST_DMGR_RST;
  attribute keep                     : string;
  attribute keep of dmgr_state       : signal is "true";
 
  signal dta_buf_full   : std_logic := '0';
  signal dta_buf_flush  : std_logic := '0';
  signal stored_dta_eod : std_logic := '0';
 
  signal ack_pkt_in : pkt_ack;
 
  signal wrd_addr : integer range 0 to NWRDS_IN_PKT-1;  -- We use 64-bit words, so the
                                        -- data word address is between
                                        -- 0 and 1023
 
  component desc_memory
    port (
      clk       : in  std_logic;
      desc_we   : in  std_logic;
      desc_addr : in  integer range 0 to N_OF_PKTS-1;
      desc_out  : in  pkt_desc;
      desc_in   : out pkt_desc);
  end component;
 
 
begin  -- dmgr_a1
 
  retr_count <= std_logic_vector(r.retr_count);
 
  transm_delay   <= r.transm_delay;
  pkt_number     <= r.pkt;
  seq_number     <= r.seq;
  flushed        <= r.flushed;
  dta_ready      <= not dta_buf_full;
  snd_start      <= c.snd_start;
  ack_fifo_rd_en <= c.ack_rd;
 
  cmd_code      <= std_logic_vector(r.cmd_code);
  cmd_seq       <= std_logic_vector(r.cmd_seq);
  cmd_arg       <= std_logic_vector(r.cmd_arg);
  cmd_run       <= r.cmd_run;
  cmd_retr_s    <= r.cmd_retr;
  snd_cmd_start <= c.snd_cmd_start;
 
  ack_pkt_in <= stlv_to_pkt_ack(ack_fifo_dout);
 
  -- Transmit command response only when the command is completed
  -- (to avoid transmiting unstable values, which could e.g. affect
  -- packet CRC calculations)
  cmd_response_out <= cmd_response_in when r.cmd_ack = r.cmd_run else (others => '0');
 
  -- Packet descriptors are stored in the desc_memory
 
  desc_memory_1 : desc_memory
    port map (
      clk       => clk,
      desc_we   => c.desc_we,
      desc_addr => to_integer(c.desc_addr),
      desc_out  => c.desc_out,
      desc_in   => desc_in);
 
  -- Process used to fill the buffer memory with the data to be transmitted
  -- We simply write words to the memory buffer pointed by r.head_ptr
  -- When we write the last (0xff-th) word, we signal that the buffer
  -- is full.
  -- Additionally, when the buffer is partially filled, but the transmission
  -- is stopped, we should also signal, that the buffer must be transmitted.
  -- However in this case we should also inform the recipient about it.
  -- How we can do it?
  dta_rcv : process (clk, rst_n)
  begin  -- process dta_rcv
    if rst_n = '0' then                 -- asynchronous reset (active low)
      wrd_addr       <= 0;
      dta_buf_flush  <= '0';
      dta_buf_full   <= '0';
      dmem_we        <= '0';
      stored_dta_eod <= '0';
    elsif clk'event and clk = '1' then  -- rising clock edge
      dmem_we <= '0';
      -- if we signalled "data full", we are only waiting for
      -- dta_buf_free;
      -- However even in this state we must receive the "dta_eod" signal
      if dta_buf_full = '1' then
        if dta_eod = '1' then
          stored_dta_eod <= '1';
        end if;
        if c.dta_buf_free = '1' then
          dta_buf_full  <= '0';
          dta_buf_flush <= '0';
          wrd_addr      <= 0;
        end if;
      else
        -- end of data is signalled, mark the last buffer as full
        if (dta_eod = '1') or (stored_dta_eod = '1') then
          -- Clear the stored eod
          stored_dta_eod <= '0';
          -- In the last word of the packet, write the number of written words
          dmem_addr      <= std_logic_vector(r.head_ptr) &
                       std_logic_vector(to_unsigned(NWRDS_IN_PKT-1, LOG2_NWRDS_IN_PKT));
          dmem_dta      <= std_logic_vector(to_unsigned(wrd_addr, 64));
          dmem_we       <= '1';
          dta_buf_flush <= '1';
          dta_buf_full  <= '1';
        -- if data write requested - write it
        elsif dta_we = '1' then
          dmem_addr <= std_logic_vector(r.head_ptr) &
                       std_logic_vector(to_unsigned(wrd_addr, LOG2_NWRDS_IN_PKT));
          dmem_we  <= '1';
          dmem_dta <= dta;
          if wrd_addr < NWRDS_IN_PKT-1 then
            wrd_addr <= wrd_addr + 1;
          else
            dta_buf_flush <= '0';
            dta_buf_full  <= '1';
          end if;
        end if;
      end if;
    end if;
  end process dta_rcv;
 
 
  c1 : process (ack_fifo_empty, ack_pkt_in, cmd_ack, desc_in,
                dmgr_state, dta_buf_full, dta_buf_flush, r, snd_ready)
  begin  -- process c1
    c             <= DESC_MGR_COMB_DEFAULT;  -- set defaults
    r_i           <= r;                 -- avoid latches
    -- Synchronize command acknowledge lines
    r_i.cmd_ack_0 <= cmd_ack;
    r_i.cmd_ack   <= r.cmd_ack_0;
    if r.retr_delay /= to_unsigned(0, r.retr_delay'length) then
      r_i.retr_delay <= r.retr_delay-1;
    end if;
    dbg             <= x"0";            -- default to avoid latch
    dmgr_state_next <= dmgr_state;
    -- State machine
    case dmgr_state is
      when ST_DMGR_RST =>
        dbg             <= x"1";
        dmgr_state_next <= ST_DMGR_RST1;
      when ST_DMGR_RST1 =>
        -- We should initialize the 0th position of list descriptors
        dbg                  <= x"2";
        c.desc_addr          <= r.head_ptr;
        c.desc_out           <= desc_in;
        c.desc_out.confirmed <= '0';
        c.desc_out.valid     <= '0';
        c.desc_out.sent      <= '0';
        c.desc_out.pkt       <= to_unsigned(0, 32);
        c.desc_we            <= '1';
        dmgr_state_next      <= ST_DMGR_IDLE;
      when ST_DMGR_IDLE =>
        dbg <= x"3";
        -- First we check, if there are any packets to acknowledge
        -- or commands to execute
        if ack_fifo_empty = '0' then
          if (to_integer(ack_pkt_in.cmd) = FCMD_ACK) or
            (to_integer(ack_pkt_in.cmd) = FCMD_NACK) then
            -- Prepare for reading of the command.
            c.desc_addr     <= ack_pkt_in.pkt(LOG2_N_OF_PKTS-1 downto 0);
            dmgr_state_next <= ST_DMGR_ACK1;
          else
            -- This is a command which requires sending of response.
            -- This will be handled by the cmd_proc block (in case
            -- of START and STOP it is not the most efficient way,
            -- but still sufficient).
            -- Always request transmission of result
            r_i.cmd_retr <= '1';
            -- Check if this is a new command (just checking the sequence number,
            -- to avoid more complex logic)
            if ack_pkt_in.seq /= r.cmd_seq then
              -- If no, store the command and it's argument, and order it to be executed
              r_i.cmd_code <= ack_pkt_in.cmd;
              r_i.cmd_seq  <= ack_pkt_in.seq;
              r_i.cmd_arg  <= ack_pkt_in.pkt;
            end if;
            c.ack_rd        <= '1';     -- Confirm, that the command was read
            dmgr_state_next <= ST_DMGR_CMD;
          end if;
        elsif dta_buf_full = '1' then
          -- We should handle reception of data.
          -- If the previously filled buffer is full, pass it for transmission,
          -- and allocate the next one.
          --
          -- Calculate the number of the packet, which shoud be the next "head"
          -- packet. We utilize the fact, that calculations are performed modulo
          -- N_OF_PKTS (because pointers have length of LOG2_N_OF_PKTS)
          r_i.nxt         <= r.head_ptr + 1;
          -- Prepare for reading of the current "head" descriptor
          c.desc_addr     <= r.head_ptr;
          dmgr_state_next <= ST_DMGR_INS1;
        elsif (r.tail_ptr /= r.head_ptr) and (r.retr_delay = to_unsigned(0, r.retr_delay'length)) then
          -- We need to (re)transmit some buffers
          -- prepare reading of the descriptor, which should be transmitted
          c.desc_addr     <= r.retr_nxt;
          dmgr_state_next <= ST_DMGR_RETR;
        elsif r.cmd_retr = '1' and (r.cmd_ack = r.cmd_run) and (r.retr_delay = to_unsigned(0, r.retr_delay'length)) then
          -- No data waiting for transmission, and the command response should
          -- be transmitted
          if snd_ready = '1' then
            r_i.retr_delay  <= r.transm_delay;
            r_i.cmd_retr    <= '0';
            c.snd_cmd_start <= '1';
          end if;
        end if;
      when ST_DMGR_CMD =>
        r_i.cmd_run     <= not r.cmd_run;
        dmgr_state_next <= ST_DMGR_IDLE;
      when ST_DMGR_INS1 =>
        dbg <= x"4";
        -- First we check, if there is free space, r.nxt is the number of the
        -- future head packet.
        if (r.nxt = r.tail_ptr) then
          -- No free place! The packet, which we would like to fill is still
          -- occupied.
          -- Return to idle, waiting until something is freed.
          -- In this case we should also force retransmission
          if r.retr_delay = 0 then
            c.desc_addr     <= r.retr_nxt;
            dmgr_state_next <= ST_DMGR_RETR;
          else
            dmgr_state_next <= ST_DMGR_IDLE;
          end if;
        else
          -- We can fill the next buffer
          -- First we mark the previous head packet
          -- as valid and not confirmed
          -- We also set the "flushed" status appropriately
          c.desc_addr          <= r.head_ptr;
          c.desc_out           <= desc_in;
          c.desc_out.confirmed <= '0';
          c.desc_out.valid     <= '1';
          if dta_buf_flush = '1' then
            c.desc_out.flushed <= '1';
          else
            c.desc_out.flushed <= '0';
          end if;
          c.desc_we       <= '1';
          -- Now we move the "head" pointer
          r_i.head_ptr    <= r.nxt;
          -- Increase the packet number!
          -- We utilize the fact, that packet number automatically
          -- wraps to 0 after sending of 2**32 packets!
          r_i.cur_pkt     <= r.cur_pkt + 1;
          dmgr_state_next <= ST_DMGR_INS2;
        end if;
      when ST_DMGR_INS2 =>
        dbg                  <= x"5";
        -- We fill the new head descriptor
        c.desc_addr          <= r.head_ptr;
        c.desc_out.pkt       <= r.cur_pkt;
        c.desc_out.confirmed <= '0';
        c.desc_out.valid     <= '0';
        c.desc_out.sent      <= '0';
        c.desc_out.flushed   <= '0';
        c.desc_we            <= '1';
        -- Signal, that the buffer is freed
        c.dta_buf_free       <= '1';
        dmgr_state_next      <= ST_DMGR_IDLE;
      when ST_DMGR_ACK1 =>
        dbg <= x"6";
        -- In this state the desc memory should respond with the data of the
        -- buffered packet, so we can state, if this packet is really correctly
        -- acknowledged (here we also ignore the NACK packets!
        case to_integer(ack_pkt_in.cmd) is
          when FCMD_ACK =>
            if (ack_pkt_in.pkt = desc_in.pkt) and
              (desc_in.valid = '1') then
              -- This is really correct, unconfirmed packet
              -- Increase the counter of not-repeated ACK packets
              -- Write the confirmation
              c.desc_addr          <= ack_pkt_in.pkt(LOG2_N_OF_PKTS-1 downto 0);
              c.desc_out           <= desc_in;
              c.desc_out.valid     <= '0';
              c.desc_out.confirmed <= '1';
              c.desc_we            <= '1';
              -- Here we also handle the case, if the acknowledged packet was
              -- the one which is now scheduled for retransmission...
              if ack_pkt_in.pkt(LOG2_N_OF_PKTS-1 downto 0) = r.retr_nxt then
                r_i.retr_nxt <= r.retr_nxt + 1;
              end if;
              -- Check, if we need to update the "tail" pointer
              if r.tail_ptr = ack_pkt_in.pkt(LOG2_N_OF_PKTS-1 downto 0) then
                c.ack_rd        <= '1';
                dmgr_state_next <= ST_DMGR_ACK_TAIL;
              else
                -- If this is not the tail pointer, it means, that some packets
                -- or acknowledgements have been lost
                -- We trigger retransmission of those packets
                r_i.ack_seq     <= ack_pkt_in.seq;
                r_i.retr_nxt    <= r.tail_ptr;
                -- Set the flag stating that only "earlier"  packets should be retransmitted
                r_i.retr_flag   <= '1';
                c.ack_rd        <= '1';
                dmgr_state_next <= ST_DMGR_IDLE;
              end if;
            else
              -- This packet was already confirmed
              -- just flush the ack_fifo
              c.ack_rd        <= '1';
              dmgr_state_next <= ST_DMGR_IDLE;
            end if;
          when FCMD_NACK =>
            -- This was a NACK command, currently we simply ignore it
            -- (later on we will use it to trigger retransmission).
            c.ack_rd        <= '1';
            dmgr_state_next <= ST_DMGR_IDLE;
          when others => null;
        end case;
      when ST_DMGR_ACK_TAIL =>
        dbg             <= x"7";
        c.desc_addr     <= r.tail_ptr;
        dmgr_state_next <= ST_DMGR_ACK_TAIL_1;
      when ST_DMGR_ACK_TAIL_1 =>
        dbg <= x"8";
        -- In this state we update the "tail" pointer if necessary
        if r.tail_ptr /= r.head_ptr then
          if desc_in.confirmed = '1' then
            r_i.tail_ptr <= r.tail_ptr + 1;  -- it will wrap to 0 automatically!
            c.desc_addr  <= r.tail_ptr + 1;
          -- We remain in that state, to check the next packet descriptor
          else
            -- We return to idle
            dmgr_state_next <= ST_DMGR_IDLE;
          end if;
        else
          -- Buffer is empty - return to idle
          dmgr_state_next <= ST_DMGR_IDLE;
        end if;
      when ST_DMGR_RETR =>
        dbg <= x"9";
        -- Here we handle the transmission of a new packet, 
        -- retransmission of not confirmed packet
        -- We must be sure, that the transmitter is ready
        if snd_ready = '0' then
          -- transmitter not ready, return to idle
          dmgr_state_next <= ST_DMGR_IDLE;
        else
          -- We will be able to send the next packet, but let's check if
          -- this is not the currently filled packet
          if r.retr_nxt = r.head_ptr then
            -- All packets (re)transmitted, go to the begining of the list
            r_i.retr_nxt    <= r.tail_ptr;
            -- Clear the flag stating that only packets older than the last
            -- acknowledged should be transmitted
            r_i.retr_flag   <= '0';
            -- and return to idle.
            dmgr_state_next <= ST_DMGR_IDLE;
          else
            -- before jumping to ST_DMGR_RETR, the address bus
            -- was set to the address of r.retr_nxt, so now
            -- we can read the descriptor, and check if the packet
            -- needs to be retransmitted at all...
            r_i.pkt      <= desc_in.pkt;
            r_i.flushed  <= desc_in.flushed;
            r_i.retr_ptr <= r.retr_nxt;
            r_i.retr_nxt <= r.retr_nxt + 1;
            if desc_in.valid = '1' and desc_in.confirmed = '0' and
              ((r.retr_flag = '0') or is_bigger(r.ack_seq, desc_in.seq)) then
              if desc_in.sent = '1' then
                -- Increase count of retransmitted packets for
                -- adaptive adjustment of delay
                if r.retr_pkt_count < PKT_CNT_MAX then
                  r_i.retr_pkt_count <= r.retr_pkt_count + 1;
                end if;
                -- Adjust the cumulative retransmission counter
                r_i.retr_count <= r.retr_count + 1;
              end if;
              -- Increase count of all packets for adaptive adjustment
              -- of delay
              if r.all_pkt_count < PKT_CNT_MAX then
                r_i.all_pkt_count <= r.all_pkt_count + 1;
              end if;
              -- Mark the packet as sent
              c.desc_addr     <= r.retr_nxt;
              c.desc_out      <= desc_in;
              c.desc_out.sent <= '1';
              -- increase the sequential number
              r_i.seq         <= r.seq + 1;
              -- store the packet sequential number
              c.desc_out.seq  <= r.seq + 1;
              c.desc_we       <= '1';
              dmgr_state_next <= ST_DMGR_RETR_2;
            else
              dmgr_state_next <= ST_DMGR_IDLE;
            end if;
          end if;
        end if;
      when ST_DMGR_RETR_2 =>
        dbg         <= x"a";
        -- In this state, we simply trigger the sender!
        c.snd_start <= '1';
        if r.cmd_ack = r.cmd_run then
          -- command response will be transmitted, so clear the related flag
          r_i.cmd_retr <= '0';
        end if;
        r_i.retr_delay <= r.transm_delay;
        -- And we update the delay using the packet statistics
        -- You may change the constants used in expressions
        -- below to change speed of adjustment
        if r.all_pkt_count >= PKT_CNT_MAX then
          if r.retr_pkt_count < PKT_CNT_MAX/300 then
            if r.transm_delay > 16 then
              r_i.transm_delay <= r.transm_delay-r.transm_delay/16;
            end if;
          elsif r.retr_pkt_count > PKT_CNT_MAX/100 then
            if r.transm_delay < 1000000 then
              r_i.transm_delay <= r.transm_delay+r.transm_delay/4;
            end if;
          end if;
          r_i.all_pkt_count  <= 0;
          r_i.retr_pkt_count <= 0;
        end if;
        dmgr_state_next <= ST_DMGR_IDLE;
      when others => null;
    end case;
  end process c1;
 
-- Synchronous process
  process (clk, rst_n)
  begin  -- process
    if rst_n = '0' then                 -- asynchronous reset (active low)
      r          <= DESC_MGR_REGS_INI;
      dmgr_state <= ST_DMGR_RST;
    elsif clk'event and clk = '1' then  -- rising clock edge
      r          <= r_i;
      dmgr_state <= dmgr_state_next;
    end if;
  end process;
 
end dmgr_a1;
 
 
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.