Pixel UDP port demo
This commit is contained in:
parent
ba1aa9181e
commit
01fe200d92
2 changed files with 177 additions and 62 deletions
142
gen_liteeth.py
142
gen_liteeth.py
|
@ -28,6 +28,7 @@ from liteeth.common import *
|
|||
from liteeth import phy as liteeth_phys
|
||||
from liteeth.mac import LiteEthMAC
|
||||
from liteeth.core import LiteEthUDPIPCore
|
||||
from liteeth.core.udp import LiteEthUDP
|
||||
|
||||
# IOs ----------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -40,12 +41,8 @@ _io = [
|
|||
("sys_reset", 1, Pins(1)),
|
||||
|
||||
# IP/MAC Address.
|
||||
("mac_address", 0, Pins(48)),
|
||||
("ip_address", 0, Pins(32)),
|
||||
|
||||
# Interrupt
|
||||
("interrupt", 0, Pins(1)),
|
||||
|
||||
# MII PHY Pads
|
||||
("mii_eth_clocks", 0,
|
||||
Subsignal("tx", Pins(1)),
|
||||
|
@ -63,61 +60,10 @@ _io = [
|
|||
Subsignal("col", Pins(1)),
|
||||
Subsignal("crs", Pins(1))
|
||||
),
|
||||
|
||||
# RMII PHY Pads
|
||||
("rmii_eth_clocks", 0,
|
||||
Subsignal("ref_clk", Pins(1))
|
||||
),
|
||||
("rmii_eth", 0,
|
||||
Subsignal("rst_n", Pins(1)),
|
||||
Subsignal("rx_data", Pins(2)),
|
||||
Subsignal("crs_dv", Pins(1)),
|
||||
Subsignal("tx_en", Pins(1)),
|
||||
Subsignal("tx_data", Pins(2)),
|
||||
Subsignal("mdc", Pins(1)),
|
||||
Subsignal("mdio", Pins(1)),
|
||||
),
|
||||
|
||||
# GMII PHY Pads
|
||||
("gmii_eth_clocks", 0,
|
||||
Subsignal("tx", Pins(1)),
|
||||
Subsignal("gtx", Pins(1)),
|
||||
Subsignal("rx", Pins(1))
|
||||
),
|
||||
("gmii_eth", 0,
|
||||
Subsignal("rst_n", Pins(1)),
|
||||
Subsignal("int_n", Pins(1)),
|
||||
Subsignal("mdio", Pins(1)),
|
||||
Subsignal("mdc", Pins(1)),
|
||||
Subsignal("rx_dv", Pins(1)),
|
||||
Subsignal("rx_er", Pins(1)),
|
||||
Subsignal("rx_data", Pins(8)),
|
||||
Subsignal("tx_en", Pins(1)),
|
||||
Subsignal("tx_er", Pins(1)),
|
||||
Subsignal("tx_data", Pins(8)),
|
||||
Subsignal("col", Pins(1)),
|
||||
Subsignal("crs", Pins(1))
|
||||
),
|
||||
|
||||
# RGMII PHY Pads
|
||||
("rgmii_eth_clocks", 0,
|
||||
Subsignal("tx", Pins(1)),
|
||||
Subsignal("rx", Pins(1))
|
||||
),
|
||||
("rgmii_eth", 0,
|
||||
Subsignal("rst_n", Pins(1)),
|
||||
Subsignal("int_n", Pins(1)),
|
||||
Subsignal("mdio", Pins(1)),
|
||||
Subsignal("mdc", Pins(1)),
|
||||
Subsignal("rx_ctl", Pins(1)),
|
||||
Subsignal("rx_data", Pins(4)),
|
||||
Subsignal("tx_ctl", Pins(1)),
|
||||
Subsignal("tx_data", Pins(4))
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def get_udp_port_ios(name, data_width):
|
||||
def get_udp_streamer_port_ios(name, data_width):
|
||||
return [
|
||||
(f"{name}", 0,
|
||||
Subsignal("ip_address", Pins(32)),
|
||||
|
@ -137,6 +83,36 @@ def get_udp_port_ios(name, data_width):
|
|||
]
|
||||
|
||||
|
||||
def get_udp_port_ios(name, data_width):
|
||||
return [
|
||||
(f"{name}", 0,
|
||||
Subsignal("bind_port", Pins(16)),
|
||||
|
||||
# Sink.
|
||||
Subsignal("sink_dst_ip_address", Pins(32)),
|
||||
Subsignal("sink_dst_port", Pins(16)),
|
||||
|
||||
Subsignal("sink_length", Pins(16)),
|
||||
Subsignal("sink_valid", Pins(1)),
|
||||
Subsignal("sink_last", Pins(1)),
|
||||
Subsignal("sink_last_be", Pins(data_width // 8)),
|
||||
Subsignal("sink_ready", Pins(1)),
|
||||
Subsignal("sink_data", Pins(data_width)),
|
||||
|
||||
# Source.
|
||||
Subsignal("source_src_ip_address", Pins(32)),
|
||||
Subsignal("source_src_port", Pins(16)),
|
||||
|
||||
Subsignal("source_length", Pins(16)),
|
||||
Subsignal("source_valid", Pins(1)),
|
||||
Subsignal("source_last", Pins(1)),
|
||||
Subsignal("source_last_be", Pins(data_width // 8)),
|
||||
Subsignal("source_ready", Pins(1)),
|
||||
Subsignal("source_data", Pins(data_width)),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class PHYCore(SoCMini):
|
||||
def __init__(self, platform):
|
||||
super().__init__(platform, clk_freq=CLK_FREQ)
|
||||
|
@ -178,6 +154,16 @@ class PHYCore(SoCMini):
|
|||
)
|
||||
|
||||
|
||||
class UDPPort(Module, AutoCSR):
|
||||
def __init__(self, udp_core: LiteEthUDP, bind_port, data_width=8, cd="sys"):
|
||||
udp_port = udp_core.crossbar.get_port(bind_port, dw=data_width, cd=cd)
|
||||
self.sink = udp_port.sink
|
||||
self.comb += [
|
||||
self.sink.src_port.eq(bind_port),
|
||||
]
|
||||
self.source = udp_port.source
|
||||
|
||||
|
||||
class UDPCore(PHYCore):
|
||||
def __init__(self, platform):
|
||||
from liteeth.frontend.stream import LiteEthUDPStreamer
|
||||
|
@ -199,7 +185,7 @@ class UDPCore(PHYCore):
|
|||
# DHCP port
|
||||
data_width = 32
|
||||
|
||||
platform.add_extension(get_udp_port_ios(
|
||||
platform.add_extension(get_udp_streamer_port_ios(
|
||||
"dhcp",
|
||||
data_width=data_width,
|
||||
))
|
||||
|
@ -229,6 +215,46 @@ class UDPCore(PHYCore):
|
|||
dhcp_ios.source_data.eq(dhcp_streamer.source.data),
|
||||
]
|
||||
|
||||
# Pixel port
|
||||
data_width = 32
|
||||
|
||||
platform.add_extension(get_udp_port_ios(
|
||||
"pixel",
|
||||
data_width=data_width,
|
||||
))
|
||||
pixel_ios = platform.request("pixel")
|
||||
|
||||
pixel_port = UDPPort(
|
||||
self.core.udp,
|
||||
bind_port=pixel_ios.bind_port,
|
||||
data_width=data_width,
|
||||
)
|
||||
self.submodules += pixel_port
|
||||
|
||||
self.comb += [
|
||||
# Connect UDP Sink IOs to UDPPort
|
||||
pixel_port.sink.ip_address.eq(pixel_ios.sink_dst_ip_address),
|
||||
pixel_port.sink.dst_port.eq(pixel_ios.sink_dst_port),
|
||||
|
||||
pixel_port.sink.length.eq(pixel_ios.sink_length),
|
||||
pixel_port.sink.valid.eq(pixel_ios.sink_valid),
|
||||
pixel_port.sink.last.eq(pixel_ios.sink_last),
|
||||
pixel_port.sink.last_be.eq(pixel_ios.sink_last_be),
|
||||
pixel_ios.sink_ready.eq(pixel_port.sink.ready),
|
||||
pixel_port.sink.data.eq(pixel_ios.sink_data),
|
||||
|
||||
# Connect UDPPort to UDP Source IOs.
|
||||
pixel_ios.source_src_ip_address.eq(pixel_port.source.ip_address),
|
||||
pixel_ios.source_src_port.eq(pixel_port.source.src_port),
|
||||
|
||||
pixel_ios.source_length.eq(pixel_port.source.length),
|
||||
pixel_ios.source_valid.eq(pixel_port.source.valid),
|
||||
pixel_ios.source_last.eq(pixel_port.source.last),
|
||||
pixel_ios.source_last_be.eq(pixel_port.source.last_be),
|
||||
pixel_port.source.ready.eq(pixel_ios.source_ready),
|
||||
pixel_ios.source_data.eq(pixel_port.source.data),
|
||||
]
|
||||
|
||||
# Build --------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
@ -244,7 +270,7 @@ def main():
|
|||
platform = XilinxPlatform(
|
||||
"xc7a35ticsg324-1L",
|
||||
io=[],
|
||||
toolchain="symbiflow"
|
||||
toolchain="yosys+nextpnr"
|
||||
)
|
||||
platform.add_extension(_io)
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ architecture a of arty_a7 is
|
|||
port (
|
||||
sys_clock : in std_logic;
|
||||
sys_reset : in std_logic;
|
||||
|
||||
mii_eth_clocks_tx : in std_logic;
|
||||
mii_eth_clocks_rx : in std_logic;
|
||||
mii_eth_rst_n : out std_logic;
|
||||
|
@ -65,20 +66,55 @@ architecture a of arty_a7 is
|
|||
mii_eth_tx_data : out std_logic_vector(3 downto 0);
|
||||
mii_eth_col : in std_logic;
|
||||
mii_eth_crs : in std_logic;
|
||||
|
||||
ip_address : in std_logic_vector(31 downto 0);
|
||||
|
||||
--== DHCP PORT ==--
|
||||
dhcp_ip_address : in std_logic_vector(31 downto 0);
|
||||
|
||||
dhcp_sink_valid : in std_logic;
|
||||
dhcp_sink_last : in std_logic;
|
||||
dhcp_sink_ready : out std_logic;
|
||||
dhcp_sink_data : in std_logic_vector(31 downto 0);
|
||||
|
||||
dhcp_source_valid : out std_logic;
|
||||
dhcp_source_last : out std_logic;
|
||||
dhcp_source_ready : in std_logic;
|
||||
dhcp_source_data : out std_logic_vector(31 downto 0)
|
||||
dhcp_source_data : out std_logic_vector(31 downto 0);
|
||||
|
||||
--== PIXEL DATA PORT ==--
|
||||
pixel_bind_port : in std_logic_vector(15 downto 0);
|
||||
|
||||
-- sink
|
||||
pixel_sink_dst_ip_address : in std_logic_vector(31 downto 0);
|
||||
pixel_sink_dst_port : in std_logic_vector(15 downto 0);
|
||||
|
||||
pixel_sink_length : in std_logic_vector(15 downto 0);
|
||||
pixel_sink_valid : in std_logic;
|
||||
pixel_sink_last : in std_logic;
|
||||
pixel_sink_last_be : in std_logic_vector(3 downto 0);
|
||||
pixel_sink_ready : out std_logic;
|
||||
pixel_sink_data : in std_logic_vector(31 downto 0);
|
||||
|
||||
-- source
|
||||
pixel_source_src_ip_address : out std_logic_vector(31 downto 0);
|
||||
pixel_source_src_port : out std_logic_vector(15 downto 0);
|
||||
|
||||
pixel_source_length : out std_logic_vector(15 downto 0);
|
||||
pixel_source_valid : out std_logic;
|
||||
pixel_source_last : out std_logic;
|
||||
pixel_source_last_be : out std_logic_vector(3 downto 0);
|
||||
pixel_source_ready : in std_logic;
|
||||
pixel_source_data : out std_logic_vector(31 downto 0)
|
||||
);
|
||||
end component;
|
||||
|
||||
signal dhcp_source_valid : std_logic;
|
||||
signal pixel_sink_length : std_logic_vector(15 downto 0);
|
||||
signal pixel_sink_valid : std_logic;
|
||||
signal pixel_sink_last : std_logic;
|
||||
signal pixel_sink_last_be : std_logic_vector(3 downto 0);
|
||||
signal pixel_sink_ready : std_logic;
|
||||
signal pixel_sink_data : std_logic_vector(31 downto 0);
|
||||
|
||||
component PLLE2_BASE
|
||||
generic (
|
||||
|
@ -181,8 +217,32 @@ begin
|
|||
dhcp_sink_last => '1',
|
||||
dhcp_sink_data => x"cafebebe",
|
||||
|
||||
dhcp_source_valid => dhcp_source_valid,
|
||||
dhcp_source_ready => '1'
|
||||
dhcp_source_ready => '1',
|
||||
|
||||
--== PIXEL DATA PORT ==--
|
||||
pixel_bind_port => x"effd", -- port 61437 - "PIXEL"
|
||||
|
||||
-- sink
|
||||
pixel_sink_dst_ip_address => x"0a141e29",
|
||||
pixel_sink_dst_port => x"303a", -- port 12346
|
||||
|
||||
pixel_sink_length => pixel_sink_length,
|
||||
pixel_sink_valid => pixel_sink_valid,
|
||||
pixel_sink_last => pixel_sink_last,
|
||||
pixel_sink_last_be => pixel_sink_last_be,
|
||||
pixel_sink_ready => pixel_sink_ready,
|
||||
pixel_sink_data => pixel_sink_data,
|
||||
|
||||
-- source
|
||||
pixel_source_src_ip_address => open,
|
||||
pixel_source_src_port => open,
|
||||
|
||||
pixel_source_length => open,
|
||||
pixel_source_valid => open,
|
||||
pixel_source_last => open,
|
||||
pixel_source_last_be => open,
|
||||
pixel_source_ready => '1',
|
||||
pixel_source_data => open
|
||||
);
|
||||
|
||||
-- 800 MHz VCO
|
||||
|
@ -259,6 +319,35 @@ begin
|
|||
pmod_d(6) <= '0';
|
||||
pmod_d(7) <= '0';
|
||||
|
||||
sender: process(clk_sys)
|
||||
constant COUNTER_MAX: natural := 80000000;
|
||||
variable counter: natural range 0 to COUNTER_MAX;
|
||||
|
||||
constant NUM_WORDS: natural := 10;
|
||||
variable words_sent: natural range 0 to NUM_WORDS;
|
||||
begin
|
||||
if rising_edge(clk_sys) then
|
||||
if counter = COUNTER_MAX then
|
||||
pixel_sink_length <= std_logic_vector(to_unsigned(NUM_WORDS, 16));
|
||||
pixel_sink_data <= std_logic_vector(to_unsigned(16#30# + words_sent, 32));
|
||||
pixel_sink_valid <= '1';
|
||||
|
||||
pixel_sink_last <= '1' when words_sent = NUM_WORDS-1 else '0';
|
||||
|
||||
if words_sent = NUM_WORDS then
|
||||
pixel_sink_valid <= '0';
|
||||
counter := 0;
|
||||
words_sent := 0;
|
||||
elsif pixel_sink_ready then
|
||||
words_sent := words_sent + 1;
|
||||
end if;
|
||||
else
|
||||
counter := counter + 1;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
pixel_sink_last_be <= (pixel_sink_last, others => '0');
|
||||
|
||||
splink: entity work.splink
|
||||
generic map (
|
||||
NUM_DRIVERS => NUM_DRIVERS
|
||||
|
|
Loading…
Reference in a new issue