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

Subversion Repositories gbiteth

[/] [gbiteth/] [trunk/] [rtl/] [rgmii/] [rgmii_tx_wbm.vhd] - Rev 3

Compare with Previous | Blame | View Log

-------------------------------------------------------------------------------
-- Title      : 
-- Project    : 
-------------------------------------------------------------------------------
-- File       : rgmii_tx_wbm.vhd
-- Author     : liyi  <alxiuyain@foxmail.com>
-- Company    : OE@HUST
-- Created    : 2013-05-09
-- Last update: 2013-05-26
-- Platform   : 
-- Standard   : VHDL'93/02
-------------------------------------------------------------------------------
-- Description: 
-------------------------------------------------------------------------------
-- Copyright (c) 2013 OE@HUST
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author  Description
-- 2013-05-09  1.0      liyi    Created
-------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
USE work.de2_pkg.ALL;
-------------------------------------------------------------------------------
ENTITY rgmii_tx_wbm IS
  GENERIC (
    IN_SIMULATION : BOOLEAN := FALSE);
  PORT (
    iWbClk : IN STD_LOGIC;
    iRst_n : IN STD_LOGIC;
 
    oWbM2S : OUT wbMasterToSlaveIF_t;
    iWbS2M : IN  wbSlaveToMasterIF_t;
 
    -- synthesis translate_off
    oWbM2S_addr : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
    oWbM2S_sel  : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
    oWbM2S_cyc  : OUT STD_LOGIC;
    oWbM2S_stb  : OUT STD_LOGIC;
    oWbM2S_we   : OUT STD_LOGIC;
    oWbM2S_cti  : OUT STD_LOGIC_VECTOR(2 DOWNTO 0);
    oWbM2S_bte  : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
    iWbS2M_ack  : IN  STD_LOGIC;
    iWbS2M_dat  : IN  STD_LOGIC_VECTOR(31 DOWNTO 0);
    -- synthesis translate_on
 
    -- tx buf
    iTxDone     : IN  STD_LOGIC;        -- act as an interrupt SIGNAL(if used)
    oTxDoneClr  : OUT STD_LOGIC;
    iTxDoneInfo : IN  STD_LOGIC_VECTOR(31 DOWNTO 0);
    oTxData     : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
    oTxAddr     : OUT UNSIGNED(10 DOWNTO 0);
    oTxDataWr   : OUT STD_LOGIC;
    oTxInfo     : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
    oTxInfoWr   : BUFFER STD_LOGIC;
 
    --wb
    iWbTxEnable  : IN  STD_LOGIC;
    oWbTxInt     : OUT STD_LOGIC;
    iWbTxIntClr  : IN  STD_LOGIC;
    iWbTxIntEn   : IN  STD_LOGIC;
    iWbTxAddr    : IN  STD_LOGIC_VECTOR(8 DOWNTO 2);
    iWbTxWE      : IN  STD_LOGIC;
    iWbTxData    : IN  STD_LOGIC_VECTOR(31 DOWNTO 0);
    oWbTxData    : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
    oWbTxIntInfo : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
 
    iCheckSumIPGen   : IN STD_LOGIC;
    iCheckSumTCPGen  : IN STD_LOGIC;
    iCheckSumUDPGen  : IN STD_LOGIC;
    iCheckSumICMPGen : IN STD_LOGIC
    );
 
END ENTITY rgmii_tx_wbm;
-------------------------------------------------------------------------------
ARCHITECTURE rtl OF rgmii_tx_wbm IS
 
  SIGNAL rDescWE   : STD_LOGIC;
  SIGNAL rDescAddr : UNSIGNED(6 DOWNTO 0);
  SIGNAL cDescDI   : STD_LOGIC_VECTOR(31 DOWNTO 0);
  SIGNAL rDescDO   : STD_LOGIC_VECTOR(31 DOWNTO 0);
 
  -- the length OF current frame descriptor
  SIGNAL rFrameLen     : UNSIGNED(15 DOWNTO 0):=(OTHERS => '0');
  SIGNAL rDescriptorLen : STD_LOGIC_VECTOR(15 DOWNTO 0);-- 当前descriptor的长度
  SIGNAL rStartTran    : BOOLEAN;
  SIGNAL rTransDone    : BOOLEAN;
  SIGNAL rCheckSumDone : BOOLEAN;
 
  SIGNAL cWbAck   : STD_LOGIC;
  SIGNAL rWbAck : STD_LOGIC;
  SIGNAL rLastOne : BOOLEAN;
  SIGNAL cWbData : STD_LOGIC_VECTOR(31 DOWNTO 0);
 
  -- 当前descriptor里面,从wishbone总线读取的32bit宽度数据中,
  -- 第一个和最后一个,有效字节数各为多少(大端模式)
  SIGNAL rFirstNibbleBytes : NATURAL RANGE 1 TO 4;
  SIGNAL rLastNibbleBytes  : NATURAL RANGE 1 TO 4;
  -- 一个以太网帧可能占用多个descriptor,例如帧的头和载荷在不同的物理区域,
  -- 那么下面一个信号表示这是当前帧的最后一个descriptor
  SIGNAL rLastDescriptor   : STD_LOGIC;
 
  -- the data read from outer buf to be send
  SIGNAL rDMADat  : STD_LOGIC_VECTOR(31 DOWNTO 0);
  SIGNAL rDMADatV : STD_LOGIC;
 
  -- 当前帧的最后一个wishbone读取
  SIGNAL rRellyLastOne  : BOOLEAN;
BEGIN  -- ARCHITECTURE rtl
 
  -- synthesis translate_off
  gen0 : IF IN_SIMULATION GENERATE
    cWbAck <= iWbS2M_ack;
    cWbData <= iWbS2M_dat;
  END GENERATE gen0;
  -- synthesis translate_on
  gen1 : IF NOT IN_SIMULATION GENERATE
    cWbAck <= iWbS2M.ack;
    cWbData <= iWbS2M.dat;
  END GENERATE gen1;
 
  PROCESS (iWbClk) IS
  BEGIN
    IF rising_edge(iWbClk) THEN
      rWbAck <= cWbAck;
    END IF;
  END PROCESS;
 
  csGen : BLOCK IS
    SIGNAL rTxAddr : UNSIGNED(10 DOWNTO 0);
    TYPE state_t IS (IDLE, TYPE_LEN, TAGED, STACK_TAG,IP4_PAYLOAD,
                     --ICMP, TCP, UDP,
                     IP4_HEAD, WAIT_FINISH, CS1, CS2, DONE, DONE2);
    SIGNAL rState        : state_t;
    SIGNAL rAddrRecord   : UNSIGNED(10 DOWNTO 0);
    SIGNAL rCheckSum     : UNSIGNED(31 DOWNTO 0);
    SIGNAL cCheckSum     : UNSIGNED(15 DOWNTO 0);
    SIGNAL rCheckSum2    : UNSIGNED(31 DOWNTO 0);
    SIGNAL cCheckSum2    : UNSIGNED(15 DOWNTO 0);
    SIGNAL rWordCnt      : UNSIGNED(13 DOWNTO 0):=(OTHERS => '0');
    SIGNAL rIPHeadLen    : UNSIGNED(3 DOWNTO 0);  -- IN 32bit
    SIGNAL rIPTotalLen   : UNSIGNED(15 DOWNTO 0);
    SIGNAL rProtocol     : STD_LOGIC_VECTOR(7 DOWNTO 0);
    SIGNAL cIPPayloadLen : UNSIGNED(15 DOWNTO 0);
    SIGNAL rCS1Addr      : UNSIGNED(10 DOWNTO 0);
    SIGNAL rCS2Addr      : UNSIGNED(10 DOWNTO 0);
    SIGNAL rCS1DatBak    : STD_LOGIC_VECTOR(15 DOWNTO 0);
    SIGNAL rCS2DatBak    : STD_LOGIC_VECTOR(15 DOWNTO 0);
    SIGNAL rDMADatVD1 : STD_LOGIC;
  BEGIN  -- BLOCK csGen
    cIPPayloadLen <= rIPTotalLen - to_integer(rIPHeadLen&B"00");
    cCheckSum     <= NOT (rCheckSum(31 DOWNTO 16)+rCheckSum(15 DOWNTO 0));
    cCheckSum2    <= NOT (rCheckSum2(31 DOWNTO 16)+rCheckSum2(15 DOWNTO 0));
    oTxAddr       <= rTxAddr;           -- BUFFER address
 
    PROCESS (iWbClk) IS 
    BEGIN 
      IF rising_edge(iWbClk) THEN
        rDMADatVD1 <= rDMADatV;
      END IF;
    END PROCESS;
 
    PROCESS (iWbClk, iRst_n) IS
      -- VARIABLE vTemp17 : UNSIGNED(16 DOWNTO 0);
      VARIABLE vTemp17 : NATURAL RANGE 0 TO 131071;
    BEGIN
      IF iRst_n = '0' THEN
        rTxAddr       <= (OTHERS => '0');
        rAddrRecord   <= (OTHERS => '0');
        rState        <= IDLE;
        rWordCnt      <= (OTHERS => '0');
        rCheckSumDone <= FALSE;
        rIPHeadLen    <= (OTHERS => '0');
        rIPTotalLen   <= (OTHERS => '0');
        rProtocol     <= (OTHERS => '0');
        rCheckSum2    <= (OTHERS => '0');
        rCS1Addr      <= (OTHERS => '0');
        rCS2Addr      <= (OTHERS => '0');
        rCS1DatBak    <= (OTHERS => '0');
        rCS2DatBak    <= (OTHERS => '0');
      ELSIF rising_edge(iWbClk) THEN
        rCheckSumDone <= FALSE;
        oTxDataWr     <= rDMADatV;
        oTxData       <= rDMADat;
        IF rDMADatVD1 = '1' THEN
          rTxAddr <= rTxAddr + 1;
        END IF;
        IF rDMADatV = '1' THEN
          rWordCnt <= rWordCnt + 1;
        END IF;
        IF rRellyLastOne THEN 
          rAddrRecord <= rTxAddr + 2;
          rWordCnt <= (OTHERS => '0');
        END IF;
        --IF rRellyLastOne THEN
        --  rCheckSumDone <= TRUE;
        --END IF;
        CASE rState IS
          WHEN IDLE =>
            --rWordCnt   <= (OTHERS => '0');
            rCheckSum  <= (OTHERS => '0');
            rCheckSum2 <= (OTHERS => '0');
            --IF rStartTran THEN
            --  rState <= MAC;
            --END IF;
            IF rWordCnt(1 DOWNTO 0) = B"10" AND rDMADatV = '1' THEN
              rState <= TYPE_LEN;
            END IF;
          ---------------------------------------------------------------------
          --WHEN MAC =>
          --  IF rWordCnt(1 DOWNTO 0) = B"10" AND rDMADatV = '1' THEN
          --    rState <= TYPE_LEN;
          --  END IF;
          --  IF rRellyLastOne THEN          -- this should nerver happen
          --    rCheckSumDone <= TRUE;
          --    rState        <= IDLE;
          --  END IF;
          ---------------------------------------------------------------------
          WHEN TYPE_LEN =>
            IF rDMADatV = '1' THEN
              rState <= DONE;
              CASE rDMADat(31 DOWNTO 16) IS 
                WHEN X"0800" =>         -- IPv4
                  rCheckSum            <= rCheckSum + UNSIGNED(rDMADat(15 DOWNTO 0));
                  rIPHeadLen           <= UNSIGNED(rDMADat(11 DOWNTO 8));
                  rWordCnt(3 DOWNTO 0) <= X"1";
                  rState               <= IP4_HEAD;
                WHEN X"8100" =>         -- taged,4 bytes
                  rState <= TAGED;
                WHEN X"88A8" | X"9100" =>      -- stack taged,8 bytes
                  rState <= STACK_TAG;
                WHEN OTHERS => NULL;
              END CASE;
            END IF;
            IF rRellyLastOne THEN          -- this should nerver happen
              rCheckSumDone <= TRUE;
              rState        <= IDLE;
            END IF;
          ---------------------------------------------------------------------
          WHEN TAGED =>
            IF rDMADatV = '1' THEN
              IF rDMADat(31 DOWNTO 16) = X"0800" THEN
                rCheckSum            <= rCheckSum + UNSIGNED(rDMADat(15 DOWNTO 0));
                rIPHeadLen           <= UNSIGNED(rDMADat(11 DOWNTO 8));
                rWordCnt(3 DOWNTO 0) <= X"1";
                rState               <= IP4_HEAD;
              ELSE
                rState <= DONE;
              END IF;
            END IF;
            IF rRellyLastOne THEN          -- this should nerver happen
              rCheckSumDone <= TRUE;
              rState        <= IDLE;
            END IF;
          ---------------------------------------------------------------------
          WHEN STACK_TAG =>
            IF rDMADatV = '1' THEN
              rState <= TAGED;
            END IF;
            IF rRellyLastOne THEN          -- this should nerver happen
              rCheckSumDone <= TRUE;
              rState        <= IDLE;
            END IF;
          ---------------------------------------------------------------------
          WHEN IP4_HEAD =>
            -- rCheckSum2 here used FOR pesudo head sum
            IF rDMADatV = '1' THEN
              CASE rWordCnt(3 DOWNTO 0) IS 
                -- 16位的总长度+16位的标识
                WHEN X"1" =>            -- byte 3,4,5,6
                  rIPTotalLen <= UNSIGNED(rDMADat(31 DOWNTO 16));
                  vTemp17     := to_integer(UNSIGNED(rDMADat(31 DOWNTO 16)))+
                                 to_integer(UNSIGNED(rDMADat(15 DOWNTO 0)));
                  rCheckSum <= rCheckSum + vTemp17;
                -- 3bit标志+13bit片偏移量  + 8bit TTL + 8 bit Protocol
                WHEN X"2" =>            -- byte 7,8,9,10
                  vTemp17 := to_integer(UNSIGNED(rDMADat(31 DOWNTO 16)))+
                             to_integer(UNSIGNED(rDMADat(15 DOWNTO 0)));
                  rCheckSum  <= rCheckSum + vTemp17;
                  rCheckSum2 <= X"0000"&cIPPayloadLen +
                                to_integer((UNSIGNED(rDMADat(7 DOWNTO 0))));
                  rProtocol <= rDMADat(7 DOWNTO 0);
                -- 16bit 校验和+源IP地址的高16bit
                WHEN X"3" =>            -- byte 11,12,13,14
                  -- checksum assumed TO be zero
                  -- add the higher two bytes OF Source IP Address
                  rCheckSum  <= rCheckSum + UNSIGNED(rDMADat(15 DOWNTO 0));
                  rCheckSum2 <= rCheckSum2 + UNSIGNED(rDMADat(15 DOWNTO 0));
                  rCS1DatBak <= rDMADat(15 DOWNTO 0);
                  -- 记录下相对地址,一会儿checksum计算完成后要写入
                  IF rDMADatVD1 = '1' THEN
                    rCS1Addr <= rTxAddr + 1;
                  ELSE
                    rCS1Addr <= rTxAddr;
                  END IF;
                -- 源IP地址低16bit + 目的IP地址高16bit
                WHEN X"4" =>            -- byte 15,16,17,18
                  vTemp17 := to_integer(UNSIGNED(rDMADat(31 DOWNTO 16)))+
                             to_integer(UNSIGNED(rDMADat(15 DOWNTO 0)));
                  rCheckSum  <= rCheckSum + vTemp17;
                  rCheckSum2 <= rCheckSum2 + vTemp17;
                -- 目的IP地址低16bit + 选项(或数据) 16bit
                WHEN X"5" =>
                  -- rCheckSum2 表示的伪头在这里就计算结束了
                  rCheckSum2 <= rCheckSum2 + UNSIGNED(rDMADat(31 DOWNTO 16));
                  -- 但是对于IP头的校验和,还要继续计算选项部分
                  vTemp17 := to_integer(UNSIGNED(rDMADat(31 DOWNTO 16)))+
                             to_integer(UNSIGNED(rDMADat(15 DOWNTO 0)));
                  rCheckSum  <= rCheckSum + vTemp17;
                WHEN OTHERS =>
                  vTemp17 := to_integer(UNSIGNED(rDMADat(31 DOWNTO 16)))+
                             to_integer(UNSIGNED(rDMADat(15 DOWNTO 0)));
                  rCheckSum  <= rCheckSum + vTemp17;
              END CASE;
 
              IF rIPHeadLen = rWordCnt(3 DOWNTO 0) THEN  -- ip head finished
                rCheckSum <= rCheckSum + UNSIGNED(rDMADat(31 DOWNTO 16));
                rWordCnt  <= (OTHERS => '0');
                rState    <= WAIT_FINISH;
                IF cIPPayloadLen /= X"0000" THEN 
                  CASE rProtocol IS
                    WHEN X"01" =>       -- icmp
                      rCheckSum2 <= X"0000"&UNSIGNED(rDMADat(15 DOWNTO 0));
                      rState <= IP4_PAYLOAD;
                    WHEN X"06" | X"11" =>       -- tcp
                      IF rIPHeadLen = X"5" THEN  -- 没有IP头选项部分
                        vTemp17 := to_integer(UNSIGNED(rDMADat(31 DOWNTO 16)))+
                                   to_integer(UNSIGNED(rDMADat(15 DOWNTO 0)));
                        rCheckSum2 <= rCheckSum2 + vTemp17;
                      ELSE
                        rCheckSum2 <= rCheckSum2 + UNSIGNED(rDMADat(15 DOWNTO 0));
                      END IF;
                      rState <= IP4_PAYLOAD;
                    WHEN OTHERS => NULL;
                  END CASE;
                END IF;
              END IF;
 
            END IF;
            IF rRellyLastOne THEN          -- this should nerver happen
              rCheckSumDone <= TRUE;
              rState        <= IDLE;
            END IF;
          ---------------------------------------------------------------------
          WHEN IP4_PAYLOAD =>
            IF rDMADatV = '1' THEN 
              -- 最后一个32位数据,但是,4字节不都是有效的,但是已经保证其它的无效
              -- 的数据为0了,因此,跟平常一样加起来也无所谓
              vTemp17 := to_integer(UNSIGNED(rDMADat(31 DOWNTO 16)))+
                         to_integer(UNSIGNED(rDMADat(15 DOWNTO 0)));
              rCheckSum2 <= rCheckSum2 + vTemp17;
              CASE rProtocol IS
                WHEN X"01" =>           -- icmp
                  IF rWordCnt = X"000"&B"00" THEN 
                    rCS2DatBak <= rDMADat(15 DOWNTO 0);
                    rCheckSum2 <= rCheckSum2 + UNSIGNED(rDMADat(15 DOWNTO 0));
                    IF rDMADatVD1 = '1' THEN
                      rCS2Addr <= rTxAddr + 1;
                    ELSE
                      rCS2Addr <= rTxAddr;
                    END IF;
                  END IF;
                ---------------------------------------------------------------
                WHEN X"06" =>           -- tcp
                  IF rWordCnt = X"000"&B"11" THEN 
                    rCS2DatBak <= rDMADat(31 DOWNTO 16);
                    rCheckSum2 <= rCheckSum2 + UNSIGNED(rDMADat(31 DOWNTO 16));
                    IF rDMADatVD1 = '1' THEN
                      rCS2Addr <= rTxAddr + 1;
                    ELSE
                      rCS2Addr <= rTxAddr;
                    END IF;
                  END IF;
                ---------------------------------------------------------------
                WHEN X"11" =>           -- udp
                  IF rWordCnt = X"000"&B"01" THEN 
                    rCS2DatBak <= rDMADat(15 DOWNTO 0);
                    rCheckSum2 <= rCheckSum2 + UNSIGNED(rDMADat(15 DOWNTO 0));
                    IF rDMADatVD1 = '1' THEN
                      rCS2Addr <= rTxAddr + 1;
                    ELSE
                      rCS2Addr <= rTxAddr;
                    END IF;
                  END IF;
                WHEN OTHERS => NULL;
              END CASE;              
            END IF;
 
            IF rRellyLastOne THEN 
              rState <= CS2;
            END IF;
          ---------------------------------------------------------------------
          WHEN WAIT_FINISH =>
            IF rRellyLastOne THEN 
              rState <= CS1;
            END IF;
          ---------------------------------------------------------------------
          WHEN CS1 =>                   -- ip checksum
            rTxAddr   <= rCS1Addr;
            oTxData   <= STD_LOGIC_VECTOR(cCheckSum)&rCS1DatBak;
            oTxDataWr <= '1';
            rState    <= DONE2;
          ---------------------------------------------------------------------
          WHEN CS2 =>                   -- tcp udp icmp checksum
            IF rProtocol = X"06" THEN   -- tcp
              oTxData <= rCS2DatBak&STD_LOGIC_VECTOR(cCheckSum2);
            ELSE
              oTxData <= STD_LOGIC_VECTOR(cCheckSum2)&rCS2DatBak;
            END IF;
            rTxAddr     <= rCS2Addr;
            oTxDataWr   <= '1';
            rState <= CS1;
          ---------------------------------------------------------------------
          -- 不是ipv4的帧
          WHEN DONE =>
            IF rRellyLastOne THEN
              rCheckSumDone <= TRUE;
              rState <= IDLE;
            END IF;
          ---------------------------------------------------------------------
          WHEN DONE2 =>
            oTxDataWr     <= '0';
            rState        <= IDLE;
            rCheckSumDone <= TRUE;
            rTxAddr       <= rAddrRecord;
          WHEN OTHERS => NULL;
        END CASE;
      END IF;
    END PROCESS;
  END BLOCK csGen;
 
 
  -----------------------------------------------------------------------------
  -- FOR receive dma descriptors,32x128
  -----------------------------------------------------------------------------
  blkDescriptor : BLOCK IS
    -- Build a 2-D array type for the RAM
    SUBTYPE word_t IS STD_LOGIC_VECTOR(31 DOWNTO 0);
    TYPE memory_t IS ARRAY(127 DOWNTO 0) OF word_t;
    -- Declare the RAM 
    SHARED VARIABLE ram : memory_t := (OTHERS => (OTHERS => '0'));
  BEGIN  -- BLOCK blkDescriptor
    -- Port A,wishbone slave
    PROCESS(iWbClk)
    BEGIN
      IF(rising_edge(iWbClk)) THEN
        IF(iWbTxWE = '1') THEN
          ram(to_integer(UNSIGNED(iWbTxAddr))) := iWbTxData;
        END IF;
        oWbTxData <= ram(to_integer(UNSIGNED(iWbTxAddr)));
      END IF;
    END PROCESS;
    -- Port B ,internal use
    PROCESS(iWbClk)
    BEGIN
      IF(rising_edge(iWbClk)) THEN
        IF(rDescWE = '1') THEN
          ram(to_integer(rDescAddr)) := cDescDI;
        END IF;
        rDescDO <= ram(to_integer(rDescAddr));
      END IF;
    END PROCESS;
  END BLOCK blkDescriptor;
 
  -----------------------------------------------------------------------------
  -- un-unsed
  PROCESS (iWbClk, iRst_n) IS
  BEGIN
    IF iRst_n = '0' THEN
      oTxDoneClr <= '0';
    ELSIF rising_edge(iWbClk) THEN
      oTxDoneClr <= '0';
      IF iTxDone = '1' THEN
        oTxDoneClr <= '1';
      END IF;
    END IF;
  END PROCESS;
 
  blk0 : BLOCK IS
    TYPE state_t IS (IDLE, FIND_USEABLE1, WAIT2, TRANS);
    SIGNAL rState   : state_t;
    SIGNAL cEmpty   : STD_LOGIC;
    SIGNAL cFull    : STD_LOGIC;
    SIGNAL cIntDesc : STD_LOGIC_VECTOR(5 DOWNTO 0);
    SIGNAL rWrReq   : STD_LOGIC;
    SIGNAL cRdReq   : STD_LOGIC;
    SIGNAL rIntDesc : STD_LOGIC_VECTOR(5 DOWNTO 0);
  BEGIN  -- BLOCK blk0
    cDescDI              <= (OTHERS => '0');
    oTxInfo(31)          <= '0';
    oTxInfo(15 DOWNTO 0) <= STD_LOGIC_VECTOR(rFrameLen);
 
    oWbTxIntInfo(6 DOWNTO 0) <= cIntDesc&'0';
    cRdReq                   <= iWbTxIntClr AND NOT cEmpty;
    PROCESS (iWbClk) IS
    BEGIN
      IF rising_edge(iWbClk) THEN
        IF iWbTxIntClr = '1' THEN
          oWbTxIntInfo(7) <= cEmpty;
        END IF;
      END IF;
    END PROCESS;
 
    fifo_sc_6x64_1 : ENTITY work.fifo_sc_6x64
      PORT MAP (
        clock => iWbClk,
        data  => rIntDesc,
        rdreq => cRdReq,
        wrreq => rWrReq,
        empty => cEmpty,
        full  => cFull,
        q     => cIntDesc);
 
    PROCESS (iWbClk, iRst_n) IS
    BEGIN
      IF iRst_n = '0' THEN
        oWbTxInt <= '0';
      ELSIF rising_edge(iWbClk) THEN
        IF cEmpty = '0' THEN
          oWbTxInt <= iWbTxIntEn;
        END IF;
        IF cEmpty = '1' OR iWbTxIntClr = '1' THEN
          oWbTxInt <= '0';
        END IF;
      END IF;
    END PROCESS;
 
    PROCESS (iWbClk) IS
    BEGIN
      IF rising_edge(iWbClk) THEN
        rWrReq <= '0';
        IF rTransDone THEN
        --IF rCheckSumDone THEN
          rWrReq   <= iWbTxIntEn;
          rIntDesc <= STD_LOGIC_VECTOR(rDescAddr(6 DOWNTO 1));
        END IF;
      END IF;
    END PROCESS;
 
    PROCESS (iWbClk, iRst_n) IS
    BEGIN
      IF iRst_n = '0' THEN
        rState                <= IDLE;
        rDescAddr             <= (OTHERS => '0');
        rDescWE               <= '0';
        rFrameLen             <= (OTHERS => '0');
        rStartTran            <= FALSE;
        oTxInfo(30 DOWNTO 16) <= (OTHERS => '0');
        oTxInfoWr             <= '0';
        rLastDescriptor       <= '0';
        rDescriptorLen <= (OTHERS => '0');
      ELSIF rising_edge(iWbClk) THEN
        rDescWE    <= '0';
        rStartTran <= FALSE;
        oTxInfoWr  <= '0';
        IF oTxInfoWr = '1' THEN
          rFrameLen <= (OTHERS => '0');
        END IF;
        CASE rState IS
          WHEN IDLE =>
            IF cFull = '0' AND iWbTxEnable = '1' AND
              -- NOT too much frames pending...
              iTxDoneInfo(31) = '0' THEN
              IF rDescDO(16) = '1' AND rDescDO(15 DOWNTO 0) /= X"0000" THEN  -- ready to be send
                -- 当前帧的最后一个descriptor了
                rLastDescriptor <= rDescDO(17);
                -- and theres is plenty room for this frame
                IF rDescDO(15 DOWNTO 0) < iTxDoneInfo(15 DOWNTO 0) THEN
                  -- then start sending...
                  rFrameLen             <= UNSIGNED(rDescDO(15 DOWNTO 0))+rFrameLen;
                  rDescriptorLen        <= rDescDO(15 DOWNTO 0);
                  rState                <= WAIT2;
                  -- start addr in the tx buf
                  oTxInfo(30 DOWNTO 16) <= iTxDoneInfo(30 DOWNTO 16);
                  --this will give us the location of the current frame
                  rDescAddr             <= rDescAddr + 1;
                END IF;
              ELSE                      -- find NEXT one
                rDescAddr <= rDescAddr + 2;
                rState    <= FIND_USEABLE1;
              END IF;
            END IF;
          ---------------------------------------------------------------------
          WHEN FIND_USEABLE1 =>
            rState <= IDLE;
          ---------------------------------------------------------------------
          --WHEN WAIT1 =>
          --  rState    <= WAIT2;
          WHEN WAIT2 =>
            rStartTran <= TRUE;
            rState     <= TRANS;
            rDescAddr  <= rDescAddr - 1;
            rDescWE    <= '1';
          WHEN TRANS =>
            -- 如果当前descriptor已经读入完成,并且不是最后一个,那么就不等待
            -- checksum计算完成,直接进入下一个descriptor的查找
            IF rTransDone AND rLastDescriptor = '0' THEN
              rState <= IDLE;
            ELSIF rCheckSumDone THEN
              rState    <= IDLE;
              -- this will info the tx_buf module a valid frame has been
              -- successfully writen into the buf,and ready to be send out
              oTxInfoWr <= '1';
            -- IF we clear now AND jump TO IDLE,the flag IS NOT fully cleared
            -- rDescWE   <= '1';move TO the previous state !!!BUG
            END IF;
          WHEN OTHERS => NULL;
        END CASE;
      END IF;
    END PROCESS;
  END BLOCK blk0;
 
  blk1 : BLOCK IS
    SIGNAL rCnt    : UNSIGNED(15 DOWNTO 2);
    SIGNAL rCnt64  : UNSIGNED(5 DOWNTO 0);
    TYPE state_t IS (IDLE, REFILL, WAIT1, WASTE);
    SIGNAL rState  : state_t;
    SIGNAL rCycStb : STD_LOGIC;
    SIGNAL rWbAddr : UNSIGNED(31 DOWNTO 2);
    SIGNAL rWbCti  : STD_LOGIC_VECTOR(2 DOWNTO 0);
  BEGIN  -- BLOCK blk1
    oWbM2S.bte  <= LINEAR;
    oWbM2S.cyc  <= rCycStb;
    oWbM2S.stb  <= rCycStb;
    oWbM2S.we   <= '0';
    oWbM2S.addr <= STD_LOGIC_VECTOR(rWbAddr)&B"00";
    oWbM2S.sel  <= X"F";
    oWbM2S.cti  <= rWbCti;
    -- synthesis translate_off
    oWbM2S_bte  <= LINEAR;
    oWbM2S_cyc  <= rCycStb;
    oWbM2S_stb  <= rCycStb;
    oWbM2S_we   <= '0';
    oWbM2S_addr <= STD_LOGIC_VECTOR(rWbAddr)&B"00";
    oWbM2S_sel  <= X"F";
    oWbM2S_cti  <= rWbCti;
    -- synthesis translate_on
 
    PROCESS (iWbClk, iRst_n) IS
      VARIABLE vCnt    : UNSIGNED(15 DOWNTO 2);
      VARIABLE vTemp16 : UNSIGNED(15 DOWNTO 0);
    BEGIN
      IF iRst_n = '0' THEN
        rTransDone        <= FALSE;
        rCnt64            <= (OTHERS => '0');
        rCnt              <= (OTHERS => '0');
        rState            <= IDLE;
        rCycStb           <= '0';
        rWbCti            <= CLASSIC;
        rWbAddr           <= (OTHERS => '0');
        rLastOne          <= FALSE;
        rFirstNibbleBytes <= 1;
        rLastNibbleBytes  <= 1;
      ELSIF rising_edge(iWbClk) THEN
        rTransDone <= FALSE;
        IF cWbAck = '1' THEN
          rWbAddr <= rWbAddr + 1;
          rCnt    <= rCnt - 1;
          rCnt64  <= rCnt64 - 1;
        END IF;
        CASE rState IS
          WHEN IDLE =>
            rWbAddr  <= UNSIGNED(rDescDO(31 DOWNTO 2));
 
            -- 注意,这里rFirstNibbleBytes直接记录的首次有多少
            -- 有效字节数,在大端模式下,rDescDO(1 DOWNTO 0)=B"00"表示
            -- 4字节有效,rDescDO(1 DOWNTO 0)=B"10"表示高16bit有效
            rFirstNibbleBytes <= 4 - to_integer(UNSIGNED(rDescDO(1 DOWNTO 0)));
 
            -- descriptors 给出的目标数据的起始地址很可能不是4字节对齐的
            vTemp16 := UNSIGNED(rDescriptorLen) - 4 + to_integer(UNSIGNED(rDescDO(1 DOWNTO 0)));
            IF vTemp16(1 DOWNTO 0) /= B"00" THEN
              vCnt             := vTemp16(15 DOWNTO 2)+1;
              -- rLastNibbleBytes给出的是当前descriptor最后一次32位读取中,有效的
              -- 字节数
              rLastNibbleBytes <= to_integer(vTemp16(1 DOWNTO 0));
            ELSE
              vCnt             := vTemp16(15 DOWNTO 2);
              rLastNibbleBytes <= 4;
            END IF;
            --IF rFrameLen(1 DOWNTO 0) /= B"00" THEN
            --  vCnt := UNSIGNED(rFrameLen(15 DOWNTO 2));
            --ELSE
            --  vCnt := UNSIGNED(rFrameLen(15 DOWNTO 2)) - 1;
            --END IF;
            rCnt   <= vCnt;
            rCnt64 <= (OTHERS => '1');
            IF rStartTran THEN 
              rLastOne <= FALSE;          -- last in a frame
              IF vCnt = 0 THEN
                rState   <= WAIT1;
                rWbCti   <= CLASSIC;
                rLastOne <= TRUE;
              ELSE
                rState <= REFILL;
                rWbCti <= INCR;
              END IF;
              rCycStb <= '1';
            END IF;
          ---------------------------------------------------------------------
          WHEN REFILL =>
            IF cWbAck = '1' THEN
              IF rCnt = X"000"&B"01" THEN
                rWbCti   <= LAST;
                rState   <= WAIT1;
                rLastOne <= TRUE;
              ELSIF rCnt64 = 1 THEN
                rWbCti <= LAST;
                rState <= WASTE;
              END IF;
            END IF;
          ---------------------------------------------------------------------
          WHEN WAIT1 =>
            IF cWbAck = '1' THEN
              rState     <= IDLE;
              rCycStb    <= '0';
              rTransDone <= TRUE;
            END IF;
          ---------------------------------------------------------------------
          WHEN WASTE =>
            rCnt64 <= rCnt64 + 1;
            IF rCnt64 = 16 THEN
              rCycStb <= '1';
              IF rCnt = 0 THEN
                rState   <= WAIT1;
                rWbCti   <= CLASSIC;
                rLastOne <= TRUE;
              ELSE
                rState <= REFILL;
                rWbCti <= INCR;
              END IF;
            END IF;
            IF cWbAck = '1' THEN
              rCycStb <= '0';
            END IF;
          WHEN OTHERS => NULL;
        END CASE;
      END IF;
    END PROCESS;
  END BLOCK blk1;
 
  blkDataMix : BLOCK IS
    TYPE state_t IS (ST1, ST2);
    SIGNAL rState         : state_t;
 
    -- 当前wishbone读取的,有效字节数
    SIGNAL rValidBytes    : NATURAL RANGE 1 TO 4;
    TYPE array8x8_t IS ARRAY (8 DOWNTO 1) OF STD_LOGIC_VECTOR(7 DOWNTO 0);
    SIGNAL rArray8x8_2      : array8x8_t;
    SIGNAL rArray8x8_1      : array8x8_t;  -- 实际上只使用了4 DOWNTO 1
    SIGNAL rReveivedBytes : NATURAL RANGE 0 TO 8;
    SIGNAL rStateLittle   : BOOLEAN;
    SIGNAL rLastOneD1 : BOOLEAN;
  BEGIN  -- BLOCK blkDataMix
 
    PROCESS (iWbClk, iRst_n) IS
    BEGIN
      IF iRst_n = '0' THEN
        rState <= ST1;
      ELSIF rising_edge(iWbClk) THEN
        CASE rState IS
          -- 这是每一个descriptor的第一个读取的32位数,当然,不一定全部有效
          -- rFirstNibbleBytes 会告诉我们到底有几个字节有效
          WHEN ST1 =>
            IF cWbAck = '1' THEN
              rValidBytes <= rFirstNibbleBytes;
              rArray8x8_1(1) <= cWbData(7 DOWNTO 0);
              rArray8x8_1(2) <= cWbData(15 DOWNTO 8);
              rArray8x8_1(3) <= cWbData(23 DOWNTO 16);
              rArray8x8_1(4) <= cWbData(31 DOWNTO 24);
              -- 当前descriptor只需要读一次
              IF rLastOne THEN          -- 在大端下,
                NULL;
                --rArray8x8_1(1) <= cWbData(7 DOWNTO 0);
                --rArray8x8_1(2) <= cWbData(15 DOWNTO 8);
                --rArray8x8_1(3) <= cWbData(23 DOWNTO 16);
                --rArray8x8_1(4) <= cWbData(31 DOWNTO 24);
              ELSE
                rState <= ST2;
                --rArray8x8_1(1) <= cWbData(7 DOWNTO 0);
                --rArray8x8_1(2) <= cWbData(15 DOWNTO 8);
                --rArray8x8_1(3) <= cWbData(23 DOWNTO 16);
                --rArray8x8_1(4) <= cWbData(31 DOWNTO 24);
              END IF;
            END IF;
          ---------------------------------------------------------------------
          WHEN ST2 =>
            IF cWbAck = '1' THEN
              IF rLastOne THEN
                rValidBytes <= rLastNibbleBytes;
                rState      <= ST1;
                -- 大端下,残留的最后一个是靠齐。。。
                CASE rLastNibbleBytes IS
                  WHEN 1 =>
                    rArray8x8_1(1) <= cWbData(31 DOWNTO 24);
                  WHEN 2 =>
                    rArray8x8_1(2) <= cWbData(31 DOWNTO 24);
                    rArray8x8_1(1) <= cWbData(23 DOWNTO 16);
                  WHEN 3 =>
                    rArray8x8_1(3) <= cWbData(31 DOWNTO 24);
                    rArray8x8_1(2) <= cWbData(23 DOWNTO 16);
                    rArray8x8_1(1) <= cWbData(15 DOWNTO 8);
                  WHEN 4 =>
                    rArray8x8_1(4) <= cWbData(31 DOWNTO 24);
                    rArray8x8_1(3) <= cWbData(23 DOWNTO 16);
                    rArray8x8_1(2) <= cWbData(15 DOWNTO 8);
                    rArray8x8_1(1) <= cWbData(7 DOWNTO 0);
                  WHEN OTHERS => NULL;
                END CASE;
              ELSE
                rValidBytes <= 4;
                rArray8x8_1(1) <= cWbData(7 DOWNTO 0);
                rArray8x8_1(2) <= cWbData(15 DOWNTO 8);
                rArray8x8_1(3) <= cWbData(23 DOWNTO 16);
                rArray8x8_1(4) <= cWbData(31 DOWNTO 24);
              END IF;
            END IF;
          ---------------------------------------------------------------------
          WHEN OTHERS => NULL;
        END CASE;
      END IF;
    END PROCESS;
 
    PROCESS (iWbClk) IS 
    BEGIN 
      IF rising_edge(iWbClk) THEN
        rLastOneD1 <= rLastOne;
      END IF;
    END PROCESS;
 
    PROCESS (iWbClk, iRst_n) IS
      VARIABLE vReceivedBytes : NATURAL RANGE 1 TO 8;
      VARIABLE vArray8x8 : array8x8_t;
    BEGIN
      IF iRst_n = '0' THEN
        rDMADatV       <= '0';
        rDMADat        <= (OTHERS => '0');
        rReveivedBytes <= 0;
        rRellyLastOne  <= FALSE;
        rStateLittle   <= FALSE;
      ELSIF rising_edge(iWbClk) THEN
        rDMADatV      <= '0';
        rRellyLastOne <= FALSE;
        CASE rStateLittle IS
          WHEN FALSE =>
            IF rWbAck = '1' THEN 
              vArray8x8(rValidBytes DOWNTO 1) := rArray8x8_1(rValidBytes DOWNTO 1);
              vArray8x8(8 DOWNTO rValidBytes+1) := rArray8x8_2(8-rValidBytes DOWNTO 1);
              --rArray8x8_2(rValidBytes DOWNTO 1) <= rArray8x8_1(rValidBytes DOWNTO 1);
              --rArray8x8_2(8 DOWNTO rValidBytes+1) <= rArray8x8_2(8-rValidBytes DOWNTO 1);
              rArray8x8_2 <= vArray8x8;
 
              vReceivedBytes := rReveivedBytes + rValidBytes;
              IF rLastOneD1 AND rLastDescriptor = '1' THEN
                IF vReceivedBytes > 4 THEN
                  rDMADatV              <= '1';
                  rStateLittle          <= TRUE;
                  rReveivedBytes        <= vReceivedBytes - 4;
                  rDMADat(31 DOWNTO 24) <= vArray8x8(vReceivedBytes);
                  rDMADat(23 DOWNTO 16) <= vArray8x8(vReceivedBytes-1);
                  rDMADat(15 DOWNTO 8)  <= vArray8x8(vReceivedBytes-2);
                  rDMADat(7 DOWNTO 0)   <= vArray8x8(vReceivedBytes-3);
                ELSE
                  rDMADatV       <= '1';
                  rRellyLastOne  <= TRUE;
                  rReveivedBytes <= 0;
                  CASE vReceivedBytes IS
                    WHEN 1 =>
                      rDMADat(31 DOWNTO 24) <= vArray8x8(1);
                      rDMADat(23 DOWNTO 0)  <= (OTHERS => '0');
                    WHEN 2 =>
                      rDMADat(31 DOWNTO 24) <= vArray8x8(2);
                      rDMADat(23 DOWNTO 16) <= vArray8x8(1);
                      rDMADat(15 DOWNTO 0)  <= (OTHERS => '0');
                    WHEN 3 =>
                      rDMADat(31 DOWNTO 24) <= vArray8x8(3);
                      rDMADat(23 DOWNTO 16) <= vArray8x8(2);
                      rDMADat(15 DOWNTO 8)  <= vArray8x8(1);
                      rDMADat(7 DOWNTO 0)   <= (OTHERS => '0');
                    WHEN 4 =>
                      rDMADat(31 DOWNTO 24) <= vArray8x8(4);
                      rDMADat(23 DOWNTO 16) <= vArray8x8(3);
                      rDMADat(15 DOWNTO 8)  <= vArray8x8(2);
                      rDMADat(7 DOWNTO 0)   <= vArray8x8(1);
                    WHEN OTHERS => NULL;
                  END CASE;
                END IF;
              ELSE                      -- NOT really last one
                IF vReceivedBytes >= 4 THEN
                  rDMADatV              <= '1';
                  rReveivedBytes        <= vReceivedBytes - 4;
                  rDMADat(31 DOWNTO 24) <= vArray8x8(vReceivedBytes);
                  rDMADat(23 DOWNTO 16) <= vArray8x8(vReceivedBytes-1);
                  rDMADat(15 DOWNTO 8)  <= vArray8x8(vReceivedBytes-2);
                  rDMADat(7 DOWNTO 0)   <= vArray8x8(vReceivedBytes-3);
                ELSE
                  rReveivedBytes <= vReceivedBytes;
                END IF;
              END IF;
            END IF;
          ---------------------------------------------------------------------
          WHEN TRUE =>
            rStateLittle   <= FALSE;
            rRellyLastOne  <= TRUE;
            rDMADatV       <= '1';
            rReveivedBytes <= 0;
            CASE rReveivedBytes IS
              WHEN 1 =>
                rDMADat(31 DOWNTO 24) <= rArray8x8_2(1);
                rDMADat(23 DOWNTO 0)  <= (OTHERS => '0');
              WHEN 2 =>
                rDMADat(31 DOWNTO 24) <= rArray8x8_2(2);
                rDMADat(23 DOWNTO 16) <= rArray8x8_2(1);
                rDMADat(15 DOWNTO 0)  <= (OTHERS => '0');
              WHEN 3 =>
                rDMADat(31 DOWNTO 24) <= rArray8x8_2(3);
                rDMADat(23 DOWNTO 16) <= rArray8x8_2(2);
                rDMADat(15 DOWNTO 8)  <= rArray8x8_2(1);
                rDMADat(7 DOWNTO 0)   <= (OTHERS => '0');
              -- 应该不会到4这个分支的!!
              WHEN 4 =>
                rDMADat(31 DOWNTO 24) <= rArray8x8_2(4);
                rDMADat(23 DOWNTO 16) <= rArray8x8_2(3);
                rDMADat(15 DOWNTO 8)  <= rArray8x8_2(2);
                rDMADat(7 DOWNTO 0)   <= rArray8x8_2(1);
              WHEN OTHERS => NULL;
            END CASE;
          ---------------------------------------------------------------------
          WHEN OTHERS => NULL;
        END CASE;
      END IF;
    END PROCESS;
 
  END BLOCK blkDataMix;
 
END ARCHITECTURE rtl;
 

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.