1 -------------------------------------------------------------------------------     2 -- File       : UdpEngineDhcp.vhd     3 -- Company    : SLAC National Accelerator Laboratory     4 -- Created    : 2016-08-12     5 -- Last update: 2017-05-10     6 -------------------------------------------------------------------------------     7 -- Description: DHCP Engine     8 -------------------------------------------------------------------------------     9 -- This file is part of 'SLAC Firmware Standard Library'.    10 -- It is subject to the license terms in the LICENSE.txt file found in the     11 -- top-level directory of this distribution and at:     12 --    https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.     13 -- No part of 'SLAC Firmware Standard Library', including this file,     14 -- may be copied, modified, propagated, or distributed except according to     15 -- the terms contained in the LICENSE.txt file.    16 -------------------------------------------------------------------------------    19 use ieee.std_logic_1164.
all;
    20 use ieee.std_logic_unsigned.
all;
    21 use ieee.std_logic_arith.
all;
    29  --! @ingroup ethernet_UdpEngine    32       -- Simulation Generics    34       -- UDP ARP/DHCP Generics    38       -- Local Configurations    39       localMac     : 
in  slv(
47 downto 0);      --  big-Endian 
configuration    40       localIp      : 
in  slv(
31 downto 0);      --  big-Endian 
configuration     41       dhcpIp       : out slv(31 downto 0);
      --  big-Endian configuration           42       -- Interface to DHCP Engine      55    constant TIMER_1_SEC_C  :              := getTimeRatio(CLK_FREQ_G, 1.
0);
    56    constant CLIENT_HDR_C   : slv(31 downto 0)    := x"00060101";
  -- 0x01010600    57    constant SERVER_HDR_C   : slv(31 downto 0)    := x"00060102";
  -- 0x02010600    58    constant MAGIC_COOKIE_C : slv(31 downto 0)    := x"63538263";
  -- 0x63825363    73    type RegType is record    76       timer      :  range 0 to (TIMER_1_SEC_C-1);
    77       commCnt    :  range 0 to COMM_TIMEOUT_C;
    78       renewCnt   : slv(30 downto 0);
    79       leaseCnt   : slv(31 downto 0);
    80       leaseTime  : slv(31 downto 0);
    81       remoteMac  : slv(47 downto 0);
    82       remoteIp   : slv(31 downto 0);
    85       xid        : slv(31 downto 0);
    86       yiaddr     : slv(31 downto 0);
    87       siaddr     : slv(31 downto 0);
    88       yiaddrTemp : slv(31 downto 0);
    89       siaddrTemp : slv(31 downto 0);
    92       opCode     : slv(7 downto 0);
    93       len        : slv(7 downto 0);
    94       msgType    : slv(7 downto 0);
   100    constant REG_INIT_C : RegType := (   104       commCnt    => 3,                  -- Default to 3 seconds after bootup   105       renewCnt   => (others => '0'),   106       leaseCnt   => (others => '0'),   107       leaseTime  => (others => '0'),   108       remoteMac  => (others => '1'),    -- Broadcast MAC Address   109       remoteIp   => (others => '1'),    -- Broadcast IP Address   110       dhcpIP     => (others => '0'),   112       xid        => (others => '0'),   113       yiaddr     => (others => '0'),   114       siaddr     => (others => '0'),   115       yiaddrTemp => (others => '0'),   116       siaddrTemp => (others => '0'),   118       valid      => (others => '0'),   119       opCode     => (others => '0'),   120       len        => (others => '0'),   121       msgType    => (others => '0'),   127    signal r   : RegType := REG_INIT_C;
   128    signal rin : RegType;
   135    -- attribute dont_touch      : string;   136    -- attribute dont_touch of r : signal is "TRUE";   142          -- General Configurations   148          -- FIFO configurations   154          -- AXI Stream Port Configurations   170       variable v     : RegType;
   174       -- Latch the current value   180       if txSlave.tReady = '1' then   182          v.txMaster.tLast  := '0';
   183          v.txMaster.tUser  := (others => '0');
   186       -- Check 1 second heartbeat timeout   187       if r.timer = (TIMER_1_SEC_C-1) then   190          -- Set the timeout flag   193          -- Increment the counter   194          v.timer := r.timer + 1;
   197       -- Check for heart beat   198       if (r.heartbeat = '1') then   199          -- Check Communication timer   200          if (r.commCnt /= 0) then   201             -- Decrement the counter   202             v.commCnt := r.commCnt - 1;
   204          -- Check DHCP renewal timer   205          if (r.renewCnt /= 0) then   206             -- Decrement the counter   207             v.renewCnt := r.renewCnt - 1;
   209          -- Check DHCP lease timer   210          if (r.leaseCnt /= 0) then   211             -- Decrement the counter   212             v.leaseCnt := r.leaseCnt - 1;
   213             -- Check for DHCP lease expire event   214             if (r.leaseCnt = 1) then   217                -- Reset the renewal counter   218                v.renewCnt  := (others => '0');
   219                -- Broadcast the MAC/IP addresses   220                v.remoteMac := (others => '1');
   221                v.remoteIp  := (others => '1');
   224             -- Set DHCP IP address to local value   229       -- Update the variables   230       tData := rxMaster.tData((8*r.index)+7 downto (8*r.index));
   235          ----------------------------------------------------------------------   237             -- Check for inbound data   238             if (rxMaster.tValid = '1') then   241                -- Check for SOF with no EOF   242                if (ssiGetUserSof(DHCP_CONFIG_C, rxMaster) = '1') and (rxMaster.tLast = '0') then   243                   -- Check for valid DHCP server OP/HTYPE/HLEN/HOPS   244                   if rxMaster.tData(31 downto 0) = SERVER_HDR_C then   245                      -- Preset the counter   252                -- Check DHCP renewal timer   253                if (r.renewCnt = 0) then   254                   -- Check for communication timeout   255                   if r.commCnt = 0 then   258                      -- Increment the counter   265          ----------------------------------------------------------------------   267             -- Check if ready to move data   268             if v.txMaster.tValid = '0' then   269                -- Set the default value   271                v.txMaster.tData(31 downto 0) := (others => '0');
   272                -- Increment the counter   276                   -- OP/HTYPE/HLEN/HOPS   278                      v.txMaster.tData(31 downto 0) := CLIENT_HDR_C;
   279                      ssiSetUserSof(DHCP_CONFIG_C, v.txMaster, '1');
   282                      -- Save the XID as big Endian   283                      v.txMaster.tData(31 downto 24) := r.xid(7 downto 0);
   284                      v.txMaster.tData(23 downto 16) := r.xid(15 downto 8);
   285                      v.txMaster.tData(15 downto 8)  := r.xid(23 downto 16);
   286                      v.txMaster.tData(7 downto 0)   := r.xid(31 downto 24);
   289                      v.txMaster.tData(31 downto 0) := x"00080000";
   292                      -- Check for DHCP request   293                      if r.dhcpReq = '1' then   294                         v.txMaster.tData(31 downto 0) := r.siaddr;
   304                      v.txMaster.tData(31 downto 0) := MAGIC_COOKIE_C;
   307                      -- Check for DHCP Discover   308                      if r.dhcpReq = '0' then   309                         v.txMaster.tData(7 downto 0)   := toSlv(53, 8);
  -- code = DHCP Message Type   310                         v.txMaster.tData(15 downto 8)  := x"01";
  -- len = 1 byte   311                         v.txMaster.tData(23 downto 16) := x"01";
  -- DHCP Discover = 0x1   312                         v.txMaster.tLast               := '1';
   313                         -- Start the communication timer   314                         v.commCnt                      := COMM_TIMEOUT_C;
   320                         v.txMaster.tData(7 downto 0)   := toSlv(53, 8);
  -- code = DHCP Message Type   321                         v.txMaster.tData(15 downto 8)  := x"01";
  -- len = 1 byte   322                         v.txMaster.tData(23 downto 16) := x"03";
  -- DHCP request = 0x3                       324                   -- Requested IP address[15:0]   326                      v.txMaster.tData(7 downto 0)   := toSlv(50, 8);
  -- code = Requested IP address   327                      v.txMaster.tData(15 downto 8)  := x"04";
     -- len = 4 byte   328                      v.txMaster.tData(31 downto 16) := r.yiaddr(15 downto 0);
  -- YIADDR[15:0]   329                   -- Requested IP address[32:16]   331                      v.txMaster.tData(15 downto 0) := r.yiaddr(31 downto 16);
  -- YIADDR[31:16]    332                   -- Server Identifier[15:0]   334                      v.txMaster.tData(7 downto 0)   := toSlv(54, 8);
  -- code = Server Identifier   335                      v.txMaster.tData(15 downto 8)  := x"04";
     -- len = 4 byte   336                      v.txMaster.tData(31 downto 16) := r.siaddr(15 downto 0);
  -- SIADDR[15:0]   337                   -- Server Identifier[32:16]   339                      v.txMaster.tData(15 downto 0) := r.siaddr(31 downto 16);
  -- SIADDR[31:16]    340                      v.txMaster.tLast              := '1';
   341                      -- Start the communication timer   342                      v.commCnt                     := COMM_TIMEOUT_C;
   351          ----------------------------------------------------------------------   353             -- Check for request data   354             if (rxMaster.tValid = '1') then   357                -- Increment the counter   363                      -- Check if XID doesn't match   364                      if (rxMaster.tData(31 downto 24) /= r.xid(7 downto 0))   365                         or (rxMaster.tData(23 downto 16) /= r.xid(15 downto 8))   366                         or (rxMaster.tData(15 downto 8) /= r.xid(23 downto 16))   367                         or (rxMaster.tData(7 downto 0) /= r.xid(31 downto 24)) then   373                      v.yiaddrTemp := rxMaster.tData(31 downto 0);
   376                      v.siaddrTemp := rxMaster.tData(31 downto 0);
   379                      -- Check if CHADDR[31:0] doesn't match   386                      -- Check if CHADDR[47:32] doesn't match   387                      if rxMaster.tData(15 downto 0) /= localMac(47 downto 32) then   393                      -- Check if Magic cookie doesn't match                     394                      if rxMaster.tData(31 downto 0) /= MAGIC_COOKIE_C then   399                         v.valid  := (others => '0');
   408                -- Check for early packet termination   409                if (rxMaster.tLast = '1') then   414          ----------------------------------------------------------------------   416             -- Check for request data   417             if (rxMaster.tValid = '1') then   418                -- Decode State Machine   420                   ----------------------------------------------------------------   422                      -- Save the OP-code value   424                      -- Check for not "PAD" and not "End" OP-code   429                   ----------------------------------------------------------------   433                      -- Check for non-zero length   437                      else               -- Error detected   441                   ----------------------------------------------------------------   443                      -- Decrement the counter   445                      -- Check for last byte   451                      if (r.opCode = 53) then                      -- Note: Assuming zero padding   452                         -- Check for DHCP Message Type   460                      -- Check for IP address Lease Time   461                      elsif (r.opcode = 51) then   465                            v.leaseTime(31 downto 24) := tData;
   469                            v.leaseTime(23 downto 16) := tData;
   473                            v.leaseTime(15 downto 8) := tData;
   477                            v.leaseTime(7 downto 0) := tData;
   481                ----------------------------------------------------------------   490                   v.index := r.index + 1;
   492                -- Check for last transfer   493                if (rxMaster.tLast = '1') and (getTKeep(tKeep) = (r.index+1)) then   495                   if ssiGetUserEofe(DHCP_CONFIG_C, rxMaster) = '0' then   504          ----------------------------------------------------------------------   507             if uAnd(r.valid) = '1' then   509                v.yiaddr := r.yiaddrTemp;
   510                v.siaddr := r.siaddrTemp;
   511                -- Check for "DHCP Discover" request and "DHCP Offer" reply   512                if (r.dhcpReq = '0') and (r.msgType = 2) then   515                   -- Reset counter to immediately start the "DHCP request"     517                -- Check for "DHCP request" request and "DHCP ACK" reply   518                elsif (r.dhcpReq = '1') and (r.msgType = 5) then   519                   -- Set the DHCP address    521                   -- Clients begin to attempt to renew their leases    522                   -- once half the lease interval has expired.   523                   v.renewCnt := r.leaseTime(31 downto 1);
   524                   v.leaseCnt := r.leaseTime;
   529 ----------------------------------------------------------------------   537       -- Register the variable for next clock cycle   541       rxSlave  <= v.rxSlave;
   542       txMaster <= r.txMaster;
   547    seq : 
process (
clk) 
is   549       if rising_edge(clk) then   550          r <= rin after TPD_G;
   556          -- General Configurations   562          -- FIFO configurations   568          -- AXI Stream Port Configurations 
FIFO_ADDR_WIDTH_Ginteger   range  4 to  48:= 9
 
out dhcpIpslv( 31 downto  0)  
 
in ibDhcpMasterAxiStreamMasterType  
 
PIPE_STAGES_Gnatural   range  0 to  16:= 1
 
out obDhcpMasterAxiStreamMasterType  
 
AxiStreamMasterType  :=(tValid  => '0',tData  =>( others => '0'),tStrb  =>( others => '1'),tKeep  =>( others => '1'),tLast  => '0',tDest  =>( others => '0'),tId  =>( others => '0'),tUser  =>( others => '0')) AXI_STREAM_MASTER_INIT_C
 
SLAVE_AXI_CONFIG_GAxiStreamConfigType  :=   AXI_STREAM_CONFIG_INIT_C
 
SLAVE_READY_EN_Gboolean  :=   true
 
GEN_SYNC_FIFO_Gboolean  :=   false
 
out ibDhcpSlaveAxiStreamSlaveType  
 
in localIpslv( 31 downto  0)  
 
in localMacslv( 47 downto  0)  
 
INT_PIPE_STAGES_Gnatural   range  0 to  16:= 0
 
AxiStreamSlaveType  :=(tReady  => '0') AXI_STREAM_SLAVE_INIT_C
 
CLK_FREQ_Greal  := 156.25E+06
 
out sAxisSlaveAxiStreamSlaveType  
 
COMM_TIMEOUT_Gpositive  := 30
 
in sAxisMasterAxiStreamMasterType  
 
out mAxisMasterAxiStreamMasterType  
 
in mAxisSlaveAxiStreamSlaveType  
 
CASCADE_SIZE_Ginteger   range  1 to ( 2** 24):= 1
 
USE_BUILT_IN_Gboolean  :=   false
 
VALID_THOLD_Ginteger   range  0 to ( 2** 24):= 1
 
MASTER_AXI_CONFIG_GAxiStreamConfigType  :=   AXI_STREAM_CONFIG_INIT_C
 
AxiStreamConfigType  :=(TSTRB_EN_C  =>   false,TDATA_BYTES_C  => 16,TDEST_BITS_C  => 8,TID_BITS_C  => 0,TKEEP_MODE_C  =>   TKEEP_COMP_C,TUSER_BITS_C  => 4,TUSER_MODE_C  =>   TUSER_FIRST_LAST_C) EMAC_AXIS_CONFIG_C
 
in obDhcpSlaveAxiStreamSlaveType