📄 eth_mac.vhd
字号:
-------------------------------------------------------------------------------
-- 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 + -