⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eth_mac.vhd

📁 The GRLIB IP Library is an integrated set of reusable IP cores, designed for system-on-chip (SOC) de
💻 VHD
📖 第 1 页 / 共 2 页
字号:
-------------------------------------------------------------------------------
-- Entity:	eth_mac
-- File:        eth_mac.vhd
-- Author:      Marko Isomaki
-- Description: Ethernet Media Access Controller
-------------------------------------------------------------------------------
library ieee;
library grlib;
library gaisler; 
use ieee.std_logic_1164.all;
use grlib.stdlib.all;
use grlib.amba.all;
use grlib.tech.all;
use gaisler.net.all;
use gaisler.devices.all;
use gaisler.memory.all;
use gaisler.ethernet_mac.all;
  
entity eth_mac is
  generic(
    hindex         : integer := 0;
    pindex         : integer := 0;
    paddr          : integer := 0;
    pmask          : integer := 16#FFF#;
    pirq           : integer := 0;
    memtech        : integer := inferred;
    ifg_gap        : integer := 24; 
    attempt_limit  : integer := 16;
    backoff_limit  : integer := 10;
    slot_time      : integer := 128;
    mdcscaler      : integer range 0 to 255 := 25; 
    enable_mdio    : integer range 0 to 1 := 0;
    fifosize       : integer range 4 to 32 := 8; 
    nsync          : integer range 1 to 2 := 2); 
  port(
    rst         : in  std_ulogic;
    clk         : in  std_ulogic;
    ahbmi       : in  ahb_mst_in_type;
    ahbmo       : out ahb_mst_out_type;
    apbi        : in  apb_slv_in_type;
    apbo        : out apb_slv_out_type;
    ethi        : in  eth_in_type;
    etho        : out eth_out_type
  );
end entity;
  
architecture rtl of eth_mac is
  constant fabits : integer := log2(fifosize);
  constant fifozero : std_logic_vector(log2(fabits) downto 0) :=
                      (others => '0');
  constant burstlength : integer := fifosize / 2;
  constant burstbits : integer := log2(burstlength);
  constant ctrlopcode : std_logic_vector(15 downto 0) := X"8808"; 
  constant broadcast  : std_logic_vector(47 downto 0) := X"FFFFFFFFFFFF";
  constant maxSize : std_logic_vector(10 downto 0) :=
    conv_std_logic_vector(1514,11);
  constant zero11  : std_logic_vector(10 downto 0) := (others => '0');
  
  constant REVISION : amba_version_type := 0;

  constant pconfig : apb_config_type := (
  0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_ETHMAC, 0, REVISION, pirq),
  1 => apb_iobar(paddr, pmask));

  type txd_state_type is (idle, desc_read, check_desc, req, fill_fifo,
                          check_result, write_result);
  type rxd_state_type is (idle, desc_read, check_desc, read_req, read_fifo,
                          discard, write_status, write_status2);

  type ctrl_reg_type is record
    txen	: std_ulogic;
    rxen        : std_ulogic;
    tx_irqen    : std_ulogic;
    rx_irqen    : std_ulogic; 
    full_duplex : std_ulogic; 
    prom        : std_ulogic;
  end record;

  type status_reg_type is record
    tx_int : std_ulogic;
    rx_int : std_ulogic;
    rx_err : std_ulogic;
    tx_err : std_ulogic;
  end record;

  type mdio_ctrl_reg_type is record
    phyadr   : std_logic_vector(4 downto 0);
    regadr   : std_logic_vector(4 downto 0);
    write    : std_ulogic;
    read     : std_ulogic;
    data     : std_logic_vector(15 downto 0);
    nvalid   : std_ulogic;
    busy     : std_ulogic;
    linkfail : std_ulogic;
  end record;

  subtype mac_addr_reg_type is std_logic_vector(47 downto 0); 

  type fifo_access_in_type is record
    renable   : std_ulogic;    
    raddress  : std_logic_vector(fabits-1 downto 0);
    write     : std_ulogic;
    waddress  : std_logic_vector(fabits-1 downto 0);
    datain    : std_logic_vector(31 downto 0);
  end record;

  type fifo_access_out_type is record
    data      : std_logic_vector(31 downto 0);
  end record;

  type reg_type is record
    --user registers
    ctrl        : ctrl_reg_type;
    status      : status_reg_type;
    mdio_ctrl   : mdio_ctrl_reg_type;
    mac_addr    : mac_addr_reg_type;
    txdesc      : std_logic_vector(31 downto 10);
    rxdesc      : std_logic_vector(31 downto 10);
    
    --master tx interface
    txdsel          : std_logic_vector(9 downto 0);
    tmsto           : eth_tx_ahb_in_type;
    txdstate        : txd_state_type;
    txwrap          : std_ulogic;
    txden           : std_ulogic;
    txaddr          : std_logic_vector(31 downto 0);
    txlength        : std_logic_vector(10 downto 0);
    txburstcnt      : std_logic_vector(burstbits downto 0);
    tfwpnt          : std_logic_vector(fabits-1 downto 0);
    tfrpnt          : std_logic_vector(fabits-1 downto 0);
    tfcnt           : std_logic_vector(fabits downto 0); 
    txcnt           : std_logic_vector(10 downto 0);
    txstart         : std_ulogic;
    txrenable       : std_ulogic;
    txirqgen        : std_ulogic;
    txstatus        : std_logic_vector(1 downto 0);
    txvalid         : std_ulogic; 
    txdata          : std_logic_vector(31 downto 0);
    txprevaddr      : std_logic_vector(31 downto 0);
    writeok         : std_ulogic;

    txread          : std_logic_vector(nsync downto 0);
    txrestart       : std_logic_vector(nsync downto 0);
    txdone          : std_logic_vector(nsync downto 0);
    txstart_sync    : std_ulogic;
    txread_ack      : std_ulogic;
      
    --master rx interface 
    rxdsel          : std_logic_vector(9 downto 0);
    rmsto           : eth_rx_ahb_in_type;
    rxdstate        : rxd_state_type;
    rxstatus        : std_logic_vector(2 downto 0);
    rxaddr          : std_logic_vector(31 downto 0);
    rxlength        : std_logic_vector(10 downto 0);
    rxwrap          : std_ulogic;
    rfwpnt          : std_logic_vector(fabits-1 downto 0);
    rfrpnt          : std_logic_vector(fabits-1 downto 0);
    rfcnt           : std_logic_vector(fabits downto 0);
    rxcnt           : std_logic_vector(10 downto 0);
    rxwriteok       : std_ulogic;
    rxdoneold       : std_ulogic;
    rxdoneack       : std_ulogic; 
    rxdone          : std_logic_vector(nsync downto 0);
    rxstart         : std_logic_vector(nsync downto 0);
    rxwrite         : std_logic_vector(nsync downto 0);
    rxwriteack      : std_ulogic; 
    rxoverrun       : std_ulogic;
    rxburstcnt      : std_logic_vector(burstbits downto 0);
    addrnok         : std_ulogic;
    ctrlpkt         : std_ulogic;
    check           : std_ulogic;
    checkdata       : std_logic_vector(31 downto 0);
    usesizefield    : std_ulogic;

    --mdio
    mdiostart       : std_ulogic;
    emdio_done      : std_logic_vector(nsync downto 0);
  end record;

  signal txfi, rxfi : fifo_access_in_type;
  signal txfo, rxfo : fifo_access_out_type;

  signal tmsto      : eth_tx_ahb_in_type;
  signal tmsti      : eth_tx_ahb_out_type;

  signal rmsto      : eth_rx_ahb_in_type;
  signal rmsti      : eth_rx_ahb_out_type; 

  signal etxi       : eth_tx_in_type;
  signal etxo       : eth_tx_out_type;

  signal erxi       : eth_rx_in_type;
  signal erxo       : eth_rx_out_type;

  signal emdioi     : eth_mdio_in_type;
  signal emdioo     : eth_mdio_out_type;
  
  signal r, rin     : reg_type;
begin
  
  comb : process(rst, ethi, r, apbi, rmsti, tmsti, txfo, rxfo, etxo,
                 erxo, emdioi) is
  variable v             : reg_type;
  variable vpirq         : std_logic_vector(NAHBIRQ-1 downto 0);
  variable prdata        : std_logic_vector(31 downto 0);
  variable txvalid       : std_ulogic;
  variable vtxfi         : fifo_access_in_type; 
  variable vrxfi         : fifo_access_in_type;
  variable rxactive      : std_ulogic;
  variable lengthav      : std_ulogic;
  variable txdone        : std_ulogic;
  variable txread        : std_ulogic;
  variable txrestart     : std_ulogic;
  variable rxstart       : std_ulogic;
  variable rxdone        : std_ulogic;
  variable rxwrite       : std_ulogic;
  variable emdio_done    : std_ulogic;
  begin 
    v := r; prdata := (others => '0'); vpirq := (others => '0');
    rxactive := (not r.rxoverrun) and r.ctrl.rxen; v.check := '0';
    lengthav := r.rxdoneold or r.usesizefield;
    
    vtxfi.datain := tmsti.data;
    vtxfi.raddress := r.tfrpnt; vtxfi.write := '0';
    vtxfi.waddress := r.tfwpnt; vtxfi.renable := r.txrenable;

    vrxfi.datain := erxo.data; 
    vrxfi.write := '0'; vrxfi.waddress := r.rfwpnt;
    vrxfi.renable := rxactive;

    --synchronization
    v.txdone(0)     := etxo.done;
    v.txread(0)     := etxo.read;
    v.txrestart(0)  := etxo.restart;
    v.rxstart(0)    := erxo.start;
    v.rxdone(0)     := erxo.done;
    v.rxwrite(0)    := erxo.write;
    v.emdio_done(0) := emdioo.done;
    
    if nsync = 2 then
      v.txdone(1)     := r.txdone(0);
      v.txread(1)     := r.txread(0);
      v.txrestart(1)  := r.txrestart(0);
      v.rxstart(1)    := r.rxstart(0);
      v.rxdone(1)     := r.rxdone(0);
      v.rxwrite(1)    := r.rxwrite(0);
      v.emdio_done(1) := r.emdio_done(0);
    end if;

    txdone     := r.txdone(nsync)     xor r.txdone(nsync-1);
    txread     := r.txread(nsync)     xor r.txread(nsync-1);
    txrestart  := r.txrestart(nsync)  xor r.txrestart(nsync-1);
    rxstart    := r.rxstart(nsync)    xor r.rxstart(nsync-1);
    rxdone     := r.rxdone(nsync)     xor r.rxdone(nsync-1);
    rxwrite    := r.rxwrite(nsync)    xor r.rxwrite(nsync-1);
    emdio_done := r.emdio_done(nsync) xor r.emdio_done(nsync-1); 

    v.rxdoneold := rxdone or r.rxdoneold; 
    
    if txdone = '1' then
      v.txstatus := etxo.status;
    end if;
    
-------------------------------------------------------------------------------
-- HOST INTERFACE -------------------------------------------------------------
-------------------------------------------------------------------------------
   --SLAVE INTERFACE

   --write
   if (apbi.psel(pindex) and apbi.penable and apbi.pwrite) = '1' then
     case apbi.paddr(5 downto 2) is
     when "0000" => --ctrl reg
       v.ctrl.prom        := apbi.pwdata(5); 
       v.ctrl.full_duplex := apbi.pwdata(4);
       v.ctrl.rx_irqen    := apbi.pwdata(3);
       v.ctrl.tx_irqen    := apbi.pwdata(2);
       v.ctrl.rxen        := apbi.pwdata(1);
       v.ctrl.txen        := apbi.pwdata(0);
     when "0001" => --status/int source reg
       v.status.tx_int    := apbi.pwdata(3);
       v.status.rx_int    := apbi.pwdata(2);
       v.status.tx_err    := apbi.pwdata(1);
       v.status.rx_err    := apbi.pwdata(0);
     when "0010" => --mac addr msb/mdio address
       v.mac_addr(47 downto 32) := apbi.pwdata(15 downto 0);
     when "0011" => --mac addr lsb
       v.mac_addr(31 downto 0)  := apbi.pwdata(31 downto 0);
     when "0100" => --mdio ctrl/status
       if enable_mdio = 1 then 
         v.mdio_ctrl.data   := apbi.pwdata(31 downto 16);
         v.mdio_ctrl.phyadr := apbi.pwdata(15 downto 11);
         v.mdio_ctrl.regadr := apbi.pwdata(10 downto 6);
         v.mdio_ctrl.read   := apbi.pwdata(1);
         v.mdio_ctrl.write  := apbi.pwdata(0);
         if (v.mdio_ctrl.read or v.mdio_ctrl.write) = '1' then
           v.mdiostart := not r.mdiostart; v.mdio_ctrl.busy := '1';
         end if; 
       end if;
     when "0101" => --tx descriptor 
       v.txdesc := apbi.pwdata(31 downto 10);
     when "0110" => --rx descriptor
       v.rxdesc := apbi.pwdata(31 downto 10);
     when others => null; 
     end case; 
   end if;

   --read
   case apbi.paddr(5 downto 2) is
   when "0000" => --ctrl reg
     prdata(5 downto 0) :=  r.ctrl.prom & r.ctrl.full_duplex & r.ctrl.rx_irqen
     & r.ctrl.tx_irqen & r.ctrl.rxen & r.ctrl.txen; 
   when "0001" => --status/int source reg
     prdata(3 downto 0) := r.status.tx_int & r.status.rx_int
     & r.status.tx_err & r.status.rx_err; 
   when "0010" => --mac addr msb/mdio address
     prdata(15 downto 0) := r.mac_addr(47 downto 32);
   when "0011" => --mac addr lsb
     prdata := r.mac_addr(31 downto 0); 
   when "0100" => --mdio ctrl/status
     prdata(31 downto 6) := r.mdio_ctrl.data & r.mdio_ctrl.phyadr &
     r.mdio_ctrl.regadr;  
     prdata(4 downto 0) := r.mdio_ctrl.nvalid & r.mdio_ctrl.busy &
     r.mdio_ctrl.linkfail & r.mdio_ctrl.read & r.mdio_ctrl.write; 
   when "0101" => --tx descriptor 
     prdata(31 downto 10) := r.txdesc;
     prdata(9 downto 0)   := r.txdsel;
   when "0110" => --rx descriptor
     prdata(31 downto 10) := r.rxdesc;
     prdata(9 downto 0)   := r.rxdsel;
   when others => null; 
   end case;   
      
   --MASTER INTERFACE

   --tx dataflow fsm
      
   case r.txdstate is
   when idle =>
     v.txrenable := '0'; v.txcnt := (others => '0');
     if r.ctrl.txen = '1' then
       v.txdstate := desc_read; v.tmsto.write := '0';  
       v.tmsto.addr := r.txdesc & r.txdsel; v.tmsto.req := '1';
     end if;
     if r.txirqgen = '1' then
       vpirq(pirq) := '1'; v.txirqgen := '0';
       if r.txstatus = "00" then v.status.tx_int := '1';
       else v.status.tx_err := '1'; end if;
     end if;
   when desc_read =>
     v.tmsto.write := '0'; v.txstatus := (others => '0'); 
     v.tfwpnt := (others => '0'); v.tfrpnt := (others => '0');
     v.tfcnt := (others => '0');
     if tmsti.grant = '1' then 
       v.tmsto.addr := r.tmsto.addr + 4;
     end if;
     if tmsti.ready = '1' then
       v.tmsto.req := '0'; v.txcnt := r.txcnt + 1; 
       case r.txcnt(1 downto 0) is
       when "00" => v.txlength  := tmsti.data(10 downto 0);
                    v.txden     := tmsti.data(11);
                    v.txwrap    := tmsti.data(12);
                    v.ctrl.txen := tmsti.data(11);
       when "01" => v.txaddr    := tmsti.data;
                    v.txdstate  := check_desc;
       when others => null;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -