Commit 1f5d1920 authored by Federico Vaga's avatar Federico Vaga

Merge branch 'end-point-development'

add support for UDP endpoint for RMQ
parents 5e44e243 29abd91a
*.*#
.#*
\ No newline at end of file
general-cores @ 1d8a2e8a
Subproject commit 8e7e01ef56a4af08f29fbe86f0166edd30ab903d
Subproject commit 1d8a2e8a31c0e5f7c6bd14a42f2251e4d4c3ecc0
wr-cores @ f1f97978
Subproject commit d4b42139d3cf88ebbc3bb78eb718db9f5dcce305
Subproject commit f1f97978cea46eb6ccefc3c26ea86e56c4e85651
......@@ -9,5 +9,6 @@ modules = {
"cpu",
"mqueue",
"smem",
"endpoint"
],
}
......@@ -61,6 +61,11 @@ entity mt_cpu_cb is
rmq_snk_o : out t_mt_stream_sink_out_array(0 to g_CPU_CONFIG.rmq_config.slot_count-1);
rmq_snk_i : in t_mt_stream_sink_in_array(0 to g_CPU_CONFIG.rmq_config.slot_count-1);
rmq_src_config_o : out t_mt_stream_config_out_array( 0 to g_CPU_CONFIG.rmq_config.slot_count-1);
rmq_src_config_i : in t_mt_stream_config_in_array( 0 to g_CPU_CONFIG.rmq_config.slot_count-1);
rmq_snk_config_o : out t_mt_stream_config_out_array( 0 to g_CPU_CONFIG.rmq_config.slot_count-1);
rmq_snk_config_i : in t_mt_stream_config_in_array( 0 to g_CPU_CONFIG.rmq_config.slot_count-1);
cb_csr_i : in t_mt_per_cb_csr_out;
cb_csr_o : out t_mt_per_cb_csr_in;
......@@ -352,18 +357,22 @@ begin -- arch
g_CONFIG => a_rmq_config
)
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
slave_i => cnx_master_out(c_SLAVE_RMQ),
slave_o => cnx_master_in(c_SLAVE_RMQ),
src_o => rmq_src_o,
src_i => rmq_src_i,
snk_i => rmq_snk_i,
snk_o => rmq_snk_o,
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
slave_i => cnx_master_out(c_SLAVE_RMQ),
slave_o => cnx_master_in(c_SLAVE_RMQ),
src_o => rmq_src_o,
src_i => rmq_src_i,
snk_i => rmq_snk_i,
snk_o => rmq_snk_o,
src_config_o => rmq_src_config_o,
src_config_i => rmq_src_config_i,
snk_config_o => rmq_snk_config_o,
snk_config_i => rmq_snk_config_i,
rmq_in_status_o => local_regs_in.rmq_stat_in_i(a_rmq_config.slot_count-1 downto 0),
rmq_out_status_o => local_regs_in.rmq_stat_out_i(a_rmq_config.slot_count-1 downto 0));
local_regs_in.rmq_stat_in_i(7 downto a_rmq_config.slot_count) <= (others => '0');
local_regs_in.rmq_stat_in_i(7 downto a_rmq_config.slot_count) <= (others => '0');
local_regs_in.rmq_stat_out_i(7 downto a_rmq_config.slot_count) <= (others => '0');
U_Local_Interconnect : xwb_crossbar
......
......@@ -47,12 +47,17 @@ end mt_urv_wrapper;
architecture arch of mt_urv_wrapper is
function f_x_to_zero (x : std_logic_vector) return std_logic_vector
impure function f_x_to_zero (x : std_logic_vector) return std_logic_vector
is
variable tmp : std_logic_vector(x'length-1 downto 0);
variable found_undef : boolean := false;
begin
-- synthesis translate_off
for i in 0 to x'length-1 loop
if( x(i) = 'U' or x(i) = 'Z' or x(i) = 'X' ) then
found_undef := true;
end if;
if x(i) = '1' or x(i) = 'H' then
tmp(i) := '1';
else
......@@ -60,6 +65,11 @@ architecture arch of mt_urv_wrapper is
end if;
end loop;
return tmp;
if found_undef then
report "Undefined data value read from memory" severity warning;
end if;
-- synthesis translate_on
return x;
end function f_x_to_zero;
......@@ -250,7 +260,7 @@ begin
if dwb_i.ack = '1' or bus_timeout_cnt = 100 then
if dm_wb_write = '0' then
dm_wb_rdata <= dwb_i.dat; --f_x_to_zero(dwb_i.dat);
dm_wb_rdata <= f_x_to_zero(dwb_i.dat);
dm_select_wb <= '1';
dm_load_done <= '1';
else
......
......@@ -8,4 +8,8 @@ files = [
"mt_udp_tx_framer.vhd",
"mt_wr_sink.vhd",
"mt_wr_source.vhd",
]
"mt_rmq_endpoint_tx.vhd",
"mt_rmq_endpoint_rx.vhd",
"mt_rmq_ethernet_endpoint.vhd",
"mt_endpoint_pkg.vhd"
];
-------------------------------------------------------------------------------
-- Title : Mock Turtle Core
-- Project : Mock Turtle
-------------------------------------------------------------------------------
-- File : mt_mqueue_pkg.vhd
-- Author : Tomasz Włostowski
-- Company : CERN BE-CO-HT
-- Created : 2014-04-01
-- Last update: 2018-03-26
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description:
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- Mock Turtle
-- https://gitlab.cern.ch/coht/mockturtle
--------------------------------------------------------------------------------
--
-- Global package for the Message Queues
-------------------------------------------------------------------------------
-- unit name: mt_endpoint_pkg
--
-- Copyright (c) 2014 CERN
-- description: Global package for the UDP/Ethernet RMQ endpoint.
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Copyright CERN 2014-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.mt_private_pkg.all;
use work.wishbone_pkg.all;
package mt_endpoint_pkg is
constant c_rmq_data_start_offset : integer := 32;
type t_rmq_outgoing_slot_config is record
type t_rmq_ep_tx_config is record
dst_mac : std_logic_vector(47 downto 0);
src_ip : std_logic_vector(31 downto 0);
dst_ip : std_logic_vector(31 downto 0);
......@@ -56,7 +42,7 @@ package mt_endpoint_pkg is
payload_size : std_logic_vector(15 downto 0);
end record;
type t_rmq_incoming_slot_config is record
type t_rmq_ep_rx_config is record
dst_mac : std_logic_vector(47 downto 0);
dst_ip : std_logic_vector(31 downto 0);
dst_port : std_logic_vector(15 downto 0);
......@@ -81,7 +67,7 @@ package mt_endpoint_pkg is
filter_raw : std_logic;
end record;
type t_rmq_rx_header is record
type t_rmq_ep_rx_header is record
is_udp : std_logic;
is_raw : std_logic;
is_tlv : std_logic;
......@@ -97,6 +83,6 @@ package mt_endpoint_pkg is
tlv_size : std_logic_vector(15 downto 0);
end record;
type t_rmq_outgoing_slot_config_array is
array(integer range<> ) of t_rmq_outgoing_slot_config;
type t_rmq_ep_tx_slot_config_array is
array(integer range<> ) of t_rmq_ep_tx_config;
end mt_endpoint_pkg;
......@@ -135,7 +135,7 @@ begin -- arch
end if;
end process p_fsm;
src_o.tag <= "00";
-- src_o.tag <= "00";
src_o.error <= '0';
end architecture arch;
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- Mock Turtle
-- https://gitlab.cern.ch/coht/mockturtle
--------------------------------------------------------------------------------
--
-- unit name: mt_rmq_endpoint_rx
--
-- description: Implements RX configuration registers and packet filter for a single
-- RMQ slot.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2014-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.genram_pkg.all;
use work.mt_mqueue_pkg.all;
use work.mt_endpoint_pkg.all;
entity mt_rmq_endpoint_rx is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
header_valid_i : in std_logic;
header_i : in t_rmq_ep_rx_header;
framer_snk_i : in t_mt_stream_sink_in;
framer_snk_o : out t_mt_stream_sink_out;
mq_src_i : in t_mt_stream_source_in;
mq_src_o : out t_mt_stream_source_out;
snk_config_i : in t_mt_stream_config_out;
snk_config_o : out t_mt_stream_config_in
);
end mt_rmq_endpoint_rx;
architecture arch of mt_rmq_endpoint_rx is
constant c_addr_config : integer := 0;
constant c_addr_dst_mac_hi : integer := 1;
constant c_addr_dst_mac_lo : integer := 2;
constant c_addr_ethertype : integer := 3;
constant c_addr_dst_ip : integer := 4;
constant c_addr_dst_port : integer := 5;
constant c_addr_dst_type0 : integer := 6;
constant c_addr_dst_type1 : integer := 7;
constant c_addr_dst_type2 : integer := 8;
constant c_addr_dst_type3 : integer := 9;
signal config : t_rmq_ep_rx_config;
signal match_type0, match_type1, match_type2, match_type3, match_dst_mac, match_dst_ip, match_udp, match_ethertype, match_dst_port, match_raw, match : std_logic;
signal drop : std_logic;
begin -- arch
p_write_config_regs : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
else
if snk_config_i.we = '1' then
case to_integer(unsigned(snk_config_i.adr(9 downto 2))) is
when c_addr_config =>
config.filter_udp <= snk_config_i.dat(0);
-- config.filter_tlv <= snk_config_i.dat(1);
config.filter_raw <= snk_config_i.dat(2);
config.filter_dst_mac <= snk_config_i.dat(3);
config.filter_ethertype <= snk_config_i.dat(4);
config.filter_dst_port <= snk_config_i.dat(5);
config.filter_dst_ip <= snk_config_i.dat(6);
config.filter_type0 <= snk_config_i.dat(7);
config.filter_type1 <= snk_config_i.dat(8);
config.filter_type2 <= snk_config_i.dat(9);
config.filter_type3 <= snk_config_i.dat(10);
config.store_header <= snk_config_i.dat(11);
when c_addr_dst_mac_hi =>
config.dst_mac(47 downto 32) <= snk_config_i.dat(15 downto 0);
when c_addr_dst_mac_lo =>
config.dst_mac(31 downto 0) <= snk_config_i.dat;
when c_addr_dst_ip =>
config.dst_ip <= snk_config_i.dat;
when c_addr_dst_port =>
config.dst_port <= snk_config_i.dat(15 downto 0);
when c_addr_ethertype =>
config.ethertype <= snk_config_i.dat(15 downto 0);
when c_addr_dst_type0 =>
config.type0 <= snk_config_i.dat(31 downto 0);
when c_addr_dst_type1 =>
config.type1 <= snk_config_i.dat(31 downto 0);
when c_addr_dst_type2 =>
config.type2 <= snk_config_i.dat(31 downto 0);
when c_addr_dst_type3 =>
config.type3 <= snk_config_i.dat(31 downto 0);
when others => null;
end case;
end if;
end if;
end if;
end process p_write_config_regs;
p_read_config_regs : process(snk_config_i, config)
begin
snk_config_o.dat <= (others => '0');
case to_integer(unsigned(snk_config_i.adr(9 downto 2))) is
when c_addr_config =>
snk_config_o.dat(0) <= config.filter_udp;
snk_config_o.dat(2) <= config.filter_raw;
snk_config_o.dat(3) <= config.filter_dst_mac;
snk_config_o.dat(4) <= config.filter_ethertype;
snk_config_o.dat(5) <= config.filter_dst_port;
snk_config_o.dat(6) <= config.filter_dst_ip;
snk_config_o.dat(7) <= config.filter_type0;
snk_config_o.dat(8) <= config.filter_type1;
snk_config_o.dat(9) <= config.filter_type2;
snk_config_o.dat(10) <= config.filter_type3;
snk_config_o.dat(11) <= config.store_header;
snk_config_o.dat(31 downto 12) <= (others => '0');
when c_addr_dst_mac_hi =>
snk_config_o.dat(15 downto 0) <= config.dst_mac(47 downto 32);
snk_config_o.dat(31 downto 16) <= (others => '0');
when c_addr_dst_mac_lo =>
snk_config_o.dat <= config.dst_mac(31 downto 0);
when c_addr_dst_ip =>
snk_config_o.dat <= config.dst_ip;
when c_addr_dst_port =>
snk_config_o.dat(15 downto 0) <= config.dst_port;
snk_config_o.dat(31 downto 16) <= (others => '0');
when c_addr_ethertype =>
snk_config_o.dat(15 downto 0) <= config.ethertype;
snk_config_o.dat(31 downto 16) <= (others => '0');
when c_addr_dst_type0 =>
snk_config_o.dat <= config.type0;
when c_addr_dst_type1 =>
snk_config_o.dat <= config.type1;
when c_addr_dst_type2 =>
snk_config_o.dat <= config.type2;
when c_addr_dst_type3 =>
snk_config_o.dat <= config.type3;
when others => null;
end case;
end process p_read_config_regs;
p_filter_packets : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
match <= '0';
else
match_dst_port <= '1';
match_dst_ip <= '1';
match_ethertype <= '1';
match_dst_mac <= '1';
match_udp <= '1';
match_raw <= '1';
match_type0 <= '1';
match_type1 <= '1';
match_type2 <= '1';
match_type3 <= '1';
if(config.filter_udp = '1') then
if(header_i.ethertype /= x"0800") then
match_ethertype <= '0';
end if;
if (config.filter_dst_port = '1') then
if (config.dst_port /= header_i.dst_port) then
match_dst_port <= '0';
end if;
end if;
if (config.filter_dst_ip = '1') then
if (config.dst_ip /= header_i.dst_ip) then
match_dst_ip <= '0';
end if;
end if;
if (config.filter_raw = '1') then
match_raw <= header_i.is_raw;
end if;
if (config.filter_udp = '1') then
match_udp <= header_i.is_udp;
end if;
--if (config.filter_type0 = '1') then
-- if (config.type0 /= header_i.tlv_type) then
-- match_type0 <= '0';
-- end if;
--end if;
--if (config.filter_type1 = '1') then
-- if (config.type1 /= header_i.tlv_type) then
-- match_type1 <= '0';
-- end if;
--end if;
--if (config.filter_type2 = '1') then
-- if (config.type2 /= header_i.tlv_type) then
-- match_type2 <= '0';
-- end if;
--end if;
--if (config.filter_type3 = '1') then
-- if (config.type3 /= header_i.tlv_type) then
-- match_type3 <= '0';
-- end if;
--end if;
end if;
if(config.filter_raw = '1') then
if(header_i.ethertype /= config.ethertype) then
match_ethertype <= '0';
end if;
if config.filter_dst_mac = '1' then
if (header_i.dst_mac /= config.dst_mac) then
match_dst_mac <= '0';
end if;
end if;
end if;
match <= match_type0 and match_type1 and match_type2 and match_type3 and match_dst_mac and match_dst_ip and match_ethertype and match_dst_port and match_udp and match_raw;
end if;
end if;
end process;
drop <= header_valid_i and not match and framer_snk_i.last;
mq_src_o.valid <= framer_snk_i.valid;
mq_src_o.data <= framer_snk_i.data;
mq_src_o.hdr <= framer_snk_i.hdr;
mq_src_o.last <= framer_snk_i.last;
mq_src_o.error <= framer_snk_i.error or drop;
framer_snk_o.ready <= '1';
framer_snk_o.pkt_ready <= '1';
end architecture arch;
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- Mock Turtle
-- https://gitlab.cern.ch/coht/mockturtle
--------------------------------------------------------------------------------
--
-- unit name: mt_rmq_outgoing_slot
--
-- description: Single outgoing slot (MT->world) of the Remote Message Queue.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2014-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.genram_pkg.all;
use work.mt_mqueue_pkg.all;
use work.mt_endpoint_pkg.all;
entity mt_rmq_endpoint_tx is
port (
clk_i: in std_logic;
rst_n_i : in std_logic;
snk_config_o : out t_mt_stream_config_in;
snk_config_i : in t_mt_stream_config_out;
config_o : out t_rmq_ep_tx_config
);
end mt_rmq_endpoint_tx;
architecture arch of mt_rmq_endpoint_tx is
constant c_ADDR_CONFIG : integer := 0;
constant c_ADDR_MAC_HI : integer := 1;
constant c_ADDR_MAC_LO : integer := 2;
constant c_ADDR_ETHERTYPE : integer := 3;
constant c_ADDR_DST_IP : integer := 4;
constant c_ADDR_SRC_IP : integer := 5;
constant c_ADDR_DST_PORT : integer := 6;
constant c_ADDR_SRC_PORT : integer := 7;
signal config : t_rmq_ep_tx_config;
begin -- arch
p_write_config_regs : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
else
if snk_config_i.we = '1' then
case to_integer(unsigned(snk_config_i.adr(9 downto 2))) is
when c_ADDR_CONFIG =>
config.is_udp <= snk_config_i.dat(0);
when c_ADDR_MAC_HI =>
config.dst_mac(47 downto 32) <= snk_config_i.dat(15 downto 0);
when c_ADDR_MAC_LO =>
config.dst_mac(31 downto 0) <= snk_config_i.dat;
when c_ADDR_DST_IP =>
config.dst_ip <= snk_config_i.dat;
when c_ADDR_SRC_IP =>
config.src_ip <= snk_config_i.dat;
when c_ADDR_SRC_PORT =>
config.src_port <= snk_config_i.dat(15 downto 0);
when c_ADDR_DST_PORT =>
config.dst_port <= snk_config_i.dat(15 downto 0);
when c_ADDR_ETHERTYPE =>
config.ethertype <= snk_config_i.dat(15 downto 0);
when others => null;
end case;
end if;
end if;
end if;
end process p_write_config_regs;
p_read_config_regs : process(snk_config_i)
begin
case to_integer(unsigned(snk_config_i.adr(9 downto 2))) is
when c_ADDR_CONFIG =>
snk_config_o.dat <= (0 => config.is_udp, others => '0');
when c_ADDR_MAC_HI =>
snk_config_o.dat <= x"0000" &config.dst_mac(47 downto 32);
when c_ADDR_MAC_LO =>
snk_config_o.dat <= config.dst_mac(31 downto 0);
when c_ADDR_DST_IP =>
snk_config_o.dat <= config.dst_ip;
when c_ADDR_SRC_IP =>
snk_config_o.dat <= config.src_ip;
when c_ADDR_SRC_PORT =>
snk_config_o.dat <= x"0000" & config.src_port;
when c_ADDR_DST_PORT =>
snk_config_o.dat <= x"0000" & config.dst_port;
when c_ADDR_ETHERTYPE =>
snk_config_o.dat <= x"0000" & config.ethertype;
when others =>
snk_config_o.dat <= (others => '0');
end case;
end process p_read_config_regs;
config_o <= config;
end architecture arch;
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- Mock Turtle
-- https://gitlab.cern.ch/coht/mockturtle
--------------------------------------------------------------------------------
--
-- unit name: mt_rmq_ethernet_endpoint
--
-- description: Ethernet endpoint for the Mock Turtle Core - top level
--
--
--------------------------------------------------------------------------------
-- Copyright CERN 2014-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.mock_turtle_pkg.all;
use work.gencores_pkg.all;
use work.wishbone_pkg.all;
use work.mt_mqueue_pkg.all;
use work.gencores_pkg.all;
use work.mt_endpoint_pkg.all;
use work.wr_fabric_pkg.all;
entity mt_rmq_ethernet_endpoint is
generic (
g_CONFIG : t_mt_config := c_DEFAULT_MT_CONFIG
);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
mt_rmq_i : in t_mt_rmq_endpoint_iface_out;
mt_rmq_o : out t_mt_rmq_endpoint_iface_in;
-- Fabric interface to the WR Core
eth_src_o : out t_wrf_source_out;
eth_src_i : in t_wrf_source_in;
eth_snk_o : out t_wrf_sink_out;
eth_snk_i : in t_wrf_sink_in
);
end mt_rmq_ethernet_endpoint;
architecture arch of mt_rmq_ethernet_endpoint is
type t_outgoing_config_array2d is array(0 to 7, 0 to 7) of t_rmq_ep_tx_config;
function f_count_out_slots return integer is
variable cnt : integer := 0;
begin
for i in 0 to g_CONFIG.cpu_count-1 loop
for j in 0 to g_CONFIG.cpu_config(i).rmq_config.slot_count-1 loop
cnt := cnt + 1;
end loop;
end loop;
return cnt;
end function;
function f_slot_index(cpu : integer; slot : integer) return integer is
variable cnt : integer := 0;
begin
for i in 0 to g_CONFIG.cpu_count-1 loop
for j in 0 to g_CONFIG.cpu_config(i).rmq_config.slot_count-1 loop
if(i = cpu and slot = j) then
return cnt;
else
cnt := cnt + 1;
end if;
end loop;
end loop;
return cnt;
end function;
function f_prio_encode(x : std_logic_vector) return integer is
begin
for i in 0 to x'length-1 loop
if x(i) = '1' then
return i;
end if;
end loop;
return 0;
end f_prio_encode;
type t_out_config_array is array(0 to f_count_out_slots-1) of t_rmq_ep_tx_config;
signal config_out : t_out_config_array;
signal config_out_muxed : t_rmq_ep_tx_config;
signal req_out : std_logic_vector(f_count_out_slots-1 downto 0);
signal grant_out : std_logic_vector(f_count_out_slots-1 downto 0);
signal out_snk_in_flat : t_mt_stream_sink_in_array(f_count_out_slots-1 downto 0);
signal out_snk_out_flat : t_mt_stream_sink_out_array(f_count_out_slots-1 downto 0);
signal wrsrc_snk_in, snk_muxed_in, incoming_snk_in : t_mt_stream_sink_in;
signal wrsrc_snk_out, snk_muxed_out, incoming_snk_out : t_mt_stream_sink_out;
signal wrsnk_src_in : t_mt_stream_source_in;
signal wrsnk_src_out : t_mt_stream_source_out;
signal active_out : integer range 0 to f_count_out_slots-1;
type t_output_arb_state is (IDLE, SEND);
signal out_state : t_output_arb_state;
signal incoming_header_valid : std_logic;
signal incoming_header : t_rmq_ep_rx_header;
begin
gen_foreach_cpu : for i in 0 to g_CONFIG.cpu_count-1 generate
gen_foreach_slot : for j in 0 to g_CONFIG.cpu_config(i).rmq_config.slot_count-1 generate
U_TX : entity work.mt_rmq_endpoint_tx
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
snk_config_i => mt_rmq_i.src_config_out(i)(j),
snk_config_o => mt_rmq_o.src_config_in(i)(j),
config_o => config_out(f_slot_index(i, j))
);
U_RX : entity work.mt_rmq_endpoint_rx
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
header_valid_i => incoming_header_valid,
header_i => incoming_header,
framer_snk_i => incoming_snk_in,
-- framer_snk_o => incoming_snk_out,
mq_src_o => mt_rmq_o.snk_in(i)(j),
mq_src_i => mt_rmq_i.snk_out(i)(j),
snk_config_i => mt_rmq_i.snk_config_out(i)(j),
snk_config_o => mt_rmq_o.snk_config_in(i)(j));
req_out(f_slot_index(i, j)) <= mt_rmq_i.src_out(i)(j).req;
out_snk_in_flat(f_slot_index(i, j)) <= mt_rmq_i.src_out(i)(j);
mt_rmq_o.src_in(i)(j) <= out_snk_out_flat(f_slot_index(i, j));
end generate gen_foreach_slot;
end generate gen_foreach_cpu;
U_TX_Path : entity work.mt_rmq_tx_path
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
snk_i => snk_muxed_in,
snk_o => snk_muxed_out,
src_i => wrsrc_snk_out,
src_o => wrsrc_snk_in,
config_i => config_out_muxed
);
U_WR_Source : entity work.mt_wr_source
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
snk_i => wrsrc_snk_in,
snk_o => wrsrc_snk_out,
src_i => eth_src_i,
src_o => eth_src_o);
p_arbitrate_outputs_fsm : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
out_state <= IDLE;
else
case out_state is
when IDLE =>
active_out <= f_prio_encode(req_out);
if unsigned(req_out) /= 0 then
out_state <= SEND;
end if;
when SEND =>
if req_out(active_out) = '0' then
out_state <= IDLE;
end if;
config_out_muxed <= config_out(active_out);
when others => null;
end case;
end if;
end if;
end process;
p_mux_streams_out : process(active_out, out_snk_in_flat, snk_muxed_out)
begin
snk_muxed_in <= out_snk_in_flat(active_out);
for i in 0 to f_count_out_slots-1 loop
if active_out = i then
out_snk_out_flat(i) <= snk_muxed_out;
else
out_snk_out_flat(i).ready <= '0';
out_snk_out_flat(i).pkt_ready <= '0';
end if;
end loop;
end process;
---------------------
-- RX Part
--------------------
U_WR_Sink : entity work.mt_wr_sink
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
snk_i => eth_snk_i,
snk_o => eth_snk_o,
src_o => wrsnk_src_out,
src_i => wrsnk_src_in);
U_RX_Path : entity work.mt_rmq_rx_path
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
snk_i => wrsnk_src_out,
snk_o => wrsnk_src_in,
src_i => incoming_snk_out,
src_o => incoming_snk_in,
p_header_valid_o => incoming_header_valid,
p_header_o => incoming_header);
incoming_snk_out.ready <= '1';
end arch;
......@@ -75,11 +75,20 @@ architecture arch of mt_rmq_rx_deframer is
end if;
end procedure f_rx;
function f_pick( cond : boolean; if_true: t_state; if_false: t_state) return t_state is
begin
if (cond) then
return if_true;
else
return if_false;
end if;
end f_pick;
signal dummy : std_logic_vector(15 downto 0);
signal state : t_state;
signal valid_mask : std_logic;
signal is_header : std_logic;
begin
snk_o.ready <= src_i.ready;
......@@ -87,7 +96,8 @@ begin
src_o.error <= snk_i.error;
src_o.valid <= snk_i.valid;
src_o.data <= snk_i.data;
src_o.tag <= c_MT_STREAM_TAG_HEADER when valid_mask = '0' else c_MT_STREAM_TAG_PAYLOAD;
src_o.hdr <= is_header;
-- src_o.tag <= c_MT_STREAM_TAG_HEADER when valid_mask = '0' else c_MT_STREAM_TAG_PAYLOAD;
p_fsm : process(clk_i)
variable next_state : t_state;
......@@ -97,10 +107,12 @@ begin
state <= IDLE;
p_header_valid_o <= '0';
valid_mask <= '0';
is_header <= '1';
else
case state is
when IDLE =>
is_header <= '1';
p_header_valid_o <= '0';
p_is_raw_o <= '0';
p_is_udp_o <= '0';
......@@ -183,10 +195,12 @@ begin
when UDP_CHECKSUM =>
if snk_i.valid = '1' and src_i.ready = '1' then
valid_mask <= '1';
is_header <= '0';
end if;
f_rx(state, PAYLOAD, dummy);
when PAYLOAD =>
is_header <= '0';
p_header_valid_o <= '1';
f_rx(state, PAYLOAD, dummy);
......
......@@ -28,6 +28,7 @@ use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.mt_mqueue_pkg.all;
use work.mt_endpoint_pkg.all;
entity mt_rmq_rx_path is
port (
......@@ -38,7 +39,7 @@ entity mt_rmq_rx_path is
src_i : in t_mt_stream_source_in;
src_o : out t_mt_stream_source_out;
p_header_valid_o : out std_logic;
p_header_o : out t_rmq_rx_header);
p_header_o : out t_rmq_ep_rx_header);
end entity mt_rmq_rx_path;
architecture arch of mt_rmq_rx_path is
......
......@@ -99,20 +99,20 @@ begin
tmp_src_out.valid <= tmp_valid_next;
if input_to_output = '1' then
src_out.data <= snk_i.data;
src_out.tag <= snk_i.tag;
src_out.last <= snk_i.last;
src_out.error <= snk_i.error;
src_out.hdr <= snk_i.hdr;
elsif temp_to_output = '1' then
src_out.data <= tmp_src_out.data;
src_out.tag <= tmp_src_out.tag;
src_out.last <= tmp_src_out.last;
src_out.error <= tmp_src_out.error;
src_out.hdr <= tmp_src_out.hdr;
end if;
if input_to_temp = '1' then
tmp_src_out.data <= snk_i.data;
tmp_src_out.tag <= snk_i.tag;
tmp_src_out.last <= snk_i.last;
tmp_src_out.error <= snk_i.error;
tmp_src_out.hdr <= snk_i.hdr;
end if;
end if;
end if;
......
......@@ -28,6 +28,7 @@ use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.mt_mqueue_pkg.all;
use work.mt_endpoint_pkg.all;
entity mt_rmq_tx_path is
port (
......@@ -37,14 +38,8 @@ entity mt_rmq_tx_path is
snk_o : out t_mt_stream_sink_out;
src_i : in t_mt_stream_source_in;
src_o : out t_mt_stream_source_out;
p_use_udp_i : in std_logic;
p_dst_mac_i : in std_logic_vector(47 downto 0);
p_ethertype_i : in std_logic_vector(15 downto 0);
p_src_port_i : in std_logic_vector(15 downto 0);
p_dst_port_i : in std_logic_vector(15 downto 0);
p_src_ip_i : in std_logic_vector(31 downto 0);
p_dst_ip_i : in std_logic_vector(31 downto 0);
p_payload_words_i : in std_logic_vector(15 downto 0));
config_i : t_rmq_ep_tx_config
);
end mt_rmq_tx_path;
architecture arch of mt_rmq_tx_path is
......@@ -55,7 +50,6 @@ architecture arch of mt_rmq_tx_path is
signal fwd_pipe : t_mt_stream_source_out_array(0 to 2);
signal rev_pipe : t_mt_stream_source_in_array(0 to 2);
signal p_payload_len : std_logic_vector(15 downto 0);
begin
......@@ -70,13 +64,12 @@ begin
snk_o => rev_pipe(0),
src_i => rev_pipe(1),
src_o => fwd_pipe(1),
p_src_port_i => p_src_port_i,
p_dst_port_i => p_dst_port_i,
p_src_ip_i => p_src_ip_i,
p_dst_ip_i => p_dst_ip_i,
p_payload_len_i => p_payload_len);
p_src_port_i => config_i.src_port,
p_dst_port_i => config_i.dst_port,
p_src_ip_i => config_i.src_ip,
p_dst_ip_i => config_i.dst_ip);
p_payload_len <= std_logic_vector(unsigned(p_payload_words_i) sll 1);
-- p_payload_len <= std_logic_vector(unsigned(p_payload_words_i) sll 1);
U_EthernetFramer : entity work.mt_ethernet_tx_framer
port map (
......@@ -86,8 +79,8 @@ begin
snk_o => rev_pipe(1),
src_i => rev_pipe(2),
src_o => fwd_pipe(2),
p_dst_mac_i => p_dst_mac_i,
p_ethertype_i => p_ethertype_i);
p_dst_mac_i => config_i.dst_mac,
p_ethertype_i => config_i.ethertype);
src_o <= fwd_pipe(2);
rev_pipe(2) <= src_i;
......
......@@ -40,8 +40,8 @@ entity mt_udp_tx_framer is
p_src_port_i : in std_logic_vector(15 downto 0);
p_dst_port_i : in std_logic_vector(15 downto 0);
p_src_ip_i : in std_logic_vector(31 downto 0);
p_dst_ip_i : in std_logic_vector(31 downto 0);
p_payload_len_i : in std_logic_vector(15 downto 0));
p_dst_ip_i : in std_logic_vector(31 downto 0)
);
end entity mt_udp_tx_framer;
architecture arch of mt_udp_tx_framer is
......@@ -69,6 +69,8 @@ architecture arch of mt_udp_tx_framer is
signal d_prev : std_logic_vector(15 downto 0);
signal p_payload_len : std_logic_vector(15 downto 0);
begin
p_comb : process(state, snk_i, src_i)
......@@ -101,6 +103,11 @@ begin
when IDLE =>
if snk_i.valid = '1' then
if( snk_i.hdr = '1' )then
p_payload_len <= snk_i.data(15 downto 0);
end if;
src_o.valid <= '1';
src_o.last <= '0';
src_o.data(15 downto 0) <= x"4500";
......@@ -110,7 +117,7 @@ begin
when IP_TLEN =>
f_send_hdr(
std_logic_vector(
(unsigned(p_payload_len_i) sll 1) + to_unsigned(20 + 8, 16)), IP_ID, checksum, src_o, state);
(unsigned(p_payload_len) sll 2) + to_unsigned(20 + 8, 16)), IP_ID, checksum, src_o, state);
when IP_ID =>
f_send_hdr(x"0000", IP_FLAGS, checksum, src_o, state);
......@@ -143,18 +150,19 @@ begin
f_send_hdr(p_dst_port_i, UDP_LEN, checksum, src_o, state);
when UDP_LEN =>
f_send_hdr(std_logic_vector((unsigned(p_payload_len_i) sll 1) + 8), UDP_CKSUM, checksum, src_o, state);
f_send_hdr(std_logic_vector((unsigned(p_payload_len) sll 2) + 8), UDP_CKSUM, checksum, src_o, state);
when UDP_CKSUM =>
f_send_hdr(x"0000", UDP_FIRST, checksum, src_o, state);
when UDP_FIRST =>
f_send_hdr(snk_i.data(15 downto 0), UDP_PAYLOAD, checksum, src_o, state);
src_o.valid <= not snk_i.hdr;
when UDP_PAYLOAD =>
if src_i.ready = '1' then
src_o.data(15 downto 0) <= snk_i.data(15 downto 0);
src_o.valid <= snk_i.valid;
src_o.valid <= not snk_i.hdr;
src_o.last <= snk_i.last;
end if;
if snk_i.last = '1' and snk_i.valid = '1' and src_i.ready = '1' then
......@@ -167,4 +175,6 @@ begin
end if;
end process p_fsm;
snk_o.pkt_ready <= '1';
end arch;
......@@ -146,7 +146,7 @@ begin -- arch
post_data <= fout(15 downto 0);
src_o.data(15 downto 0) <= post_data;
post_addr <= fout(17 downto 16);
src_o.tag <= post_addr;
-- src_o.tag <= post_addr;
src_o.last <= q_valid and fout(18);
src_o.error <= '0'; -- fixme
src_o.valid <= q_valid;
......
......@@ -76,7 +76,7 @@ begin -- arch
pre_dvalid <= snk_i.valid or snk_i.error;
pre_data <= snk_i.data(15 downto 0) when snk_i.error = '0' else f_marshall_wrf_status(err_status);
pre_addr <= snk_i.tag when snk_i.error = '0' else c_WRF_STATUS;
pre_addr <= c_WRF_DATA when snk_i.error = '0' else c_WRF_STATUS;
pre_eof <= snk_i.valid and snk_i.last;
fin(15 downto 0) <= pre_data;
......
......@@ -39,32 +39,31 @@ entity mock_turtle_core is
generic (
-- Message Queue and CPU configuration
g_CONFIG : t_mt_config := c_DEFAULT_MT_CONFIG;
g_CONFIG : t_mt_config := c_DEFAULT_MT_CONFIG;
-- Frequency of clk_i, in Hz
g_SYSTEM_CLOCK_FREQ : integer := 62500000;
g_SYSTEM_CLOCK_FREQ : integer := 62500000;
-- Enables/disables WR support
g_WITH_WHITE_RABBIT : boolean := FALSE);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
clk_i : in std_logic;
rst_n_i : in std_logic;
-- shared peripheral port
sp_master_o : out t_wishbone_master_out;
sp_master_i : in t_wishbone_master_in;
sp_master_o : out t_wishbone_master_out;
sp_master_i : in t_wishbone_master_in;
-- dedicated (per-cpu) peripheral port
dp_master_o : out t_wishbone_master_out_array(0 to g_CONFIG.cpu_count-1);
dp_master_i : in t_wishbone_master_in_array(0 to g_CONFIG.cpu_count-1);
-- The OUT RMQs
rmq_src_o : out t_mt_stream_source_out_array2d;
rmq_src_i : in t_mt_stream_source_in_array2d;
-- The IN RMQs
rmq_snk_o : out t_mt_stream_sink_out_array2d;
rmq_snk_i : in t_mt_stream_sink_in_array2d;
dp_master_o : out t_wishbone_master_out_array(0 to g_CONFIG.cpu_count-1);
dp_master_i : in t_wishbone_master_in_array(0 to g_CONFIG.cpu_count-1);
-- Endpoint interface
rmq_endpoint_o : out t_mt_rmq_endpoint_iface_out;
rmq_endpoint_i : in t_mt_rmq_endpoint_iface_in := c_MT_RMQ_ENDPOINT_IFACE_IN_DEFAULT_VALUE;
host_slave_i : in t_wishbone_slave_in;
host_slave_o : out t_wishbone_slave_out;
clk_ref_i : in std_logic;
tm_i : in t_mt_timing_if;
gpio_o : out std_logic_vector(31 downto 0);
gpio_i : in std_logic_vector(31 downto 0);
gpio_i : in std_logic_vector(31 downto 0) := x"00000000";
hmq_in_irq_o : out std_logic;
hmq_out_irq_o : out std_logic;
notify_irq_o : out std_logic;
......@@ -91,8 +90,8 @@ architecture arch of mock_turtle_core is
-- remapping to squeeze the host address space to 128 kB
constant c_SMEM_REMAP_BASE_OUT : t_wishbone_address_array(0 to 2) := (
0 => x"00000000", -- 0x00000-0x0bfff -> HMQ (use priority in remapper)
1 => x"00010000", -- 0x0c000-0x0ffff -> CSR, CROM
2 => x"00200000"); -- 0x10000-0x1ffff -> SMEM
1 => x"00010000", -- 0x0c000-0x0ffff -> CSR, CROM
2 => x"00200000"); -- 0x10000-0x1ffff -> SMEM
constant c_SMEM_REMAP_MASK_OUT : t_wishbone_address_array(0 to 2) := (
0 => x"0000ffff",
......@@ -130,13 +129,13 @@ architecture arch of mock_turtle_core is
constant c_SI_SLAVE_CPU0 : integer := 1;
constant c_SI_ADDRESS : t_wishbone_address_array (c_SI_WISHBONE_MASTERS-1 downto 0) := (
c_SI_MASTER_SMEM => x"00200000", -- Shared Memory
c_SI_MASTER_CROM => x"00400000", -- Config ROM
c_SI_MASTER_SMEM => x"00200000", -- Shared Memory
c_SI_MASTER_CROM => x"00400000", -- Config ROM
c_SI_MASTER_SP => x"08000000");
constant c_SI_MASK : t_wishbone_address_array (c_SI_WISHBONE_MASTERS-1 downto 0) := (
c_SI_MASTER_SMEM => x"0ff00000", -- Shared Memory
c_SI_MASTER_CROM => x"0ffff000", -- Config ROM
c_SI_MASTER_SMEM => x"0ff00000", -- Shared Memory
c_SI_MASTER_CROM => x"0ffff000", -- Config ROM
c_SI_MASTER_SP => x"08000000");
signal si_slave_in : t_wishbone_slave_in_array(c_SI_WISHBONE_SLAVES-1 downto 0);
......@@ -201,6 +200,15 @@ architecture arch of mock_turtle_core is
signal host_remapped_in : t_wishbone_slave_in;
signal host_remapped_out : t_wishbone_slave_out;
signal rmq_src_o_int : t_mt_stream_source_out_array2d;
signal rmq_src_i_int : t_mt_stream_source_in_array2d;
signal rmq_snk_o_int : t_mt_stream_sink_out_array2d;
signal rmq_snk_i_int : t_mt_stream_sink_in_array2d;
signal rmq_src_config_o_int : t_mt_stream_config_out_array2d;
signal rmq_src_config_i_int : t_mt_stream_config_in_array2d;
signal rmq_snk_config_o_int : t_mt_stream_config_out_array2d;
signal rmq_snk_config_i_int : t_mt_stream_config_in_array2d;
function f_reduce_or (x : t_word_array) return std_logic_vector
is
variable rv : std_logic_vector(31 downto 0);
......@@ -364,21 +372,26 @@ begin -- arch
g_WITH_WHITE_RABBIT => g_WITH_WHITE_RABBIT,
g_SYSTEM_CLOCK_FREQ => g_SYSTEM_CLOCK_FREQ)
port map (
clk_sys_i => clk_i,
rst_n_i => rst_n_i,
clk_ref_i => clk_ref_i,
rst_n_ref_i => rst_n_ref,
tm_i => tm_i,
sh_master_i => si_slave_out(c_SI_SLAVE_CPU0 + i),
sh_master_o => si_slave_in(C_SI_SLAVE_CPU0 + i),
dp_master_i => dp_master_i(i),
dp_master_o => dp_master_o(i),
hmq_slave_i => hmq_slave_in(i),
hmq_slave_o => hmq_slave_out(i),
rmq_src_o => rmq_src_o(i)(0 to c_CFG.rmq_config.slot_count-1),
rmq_src_i => rmq_src_i(i)(0 to c_CFG.rmq_config.slot_count-1),
rmq_snk_o => rmq_snk_o(i)(0 to c_CFG.rmq_config.slot_count-1),
rmq_snk_i => rmq_snk_i(i)(0 to c_CFG.rmq_config.slot_count-1),
clk_sys_i => clk_i,
rst_n_i => rst_n_i,
clk_ref_i => clk_ref_i,
rst_n_ref_i => rst_n_ref,
tm_i => tm_i,
sh_master_i => si_slave_out(c_SI_SLAVE_CPU0 + i),
sh_master_o => si_slave_in(C_SI_SLAVE_CPU0 + i),
dp_master_i => dp_master_i(i),
dp_master_o => dp_master_o(i),
hmq_slave_i => hmq_slave_in(i),
hmq_slave_o => hmq_slave_out(i),
rmq_src_o => rmq_src_o_int(i)(0 to c_CFG.rmq_config.slot_count-1),
rmq_src_i => rmq_src_i_int(i)(0 to c_CFG.rmq_config.slot_count-1),
rmq_snk_o => rmq_snk_o_int(i)(0 to c_CFG.rmq_config.slot_count-1),
rmq_snk_i => rmq_snk_i_int(i)(0 to c_CFG.rmq_config.slot_count-1),
rmq_src_config_o => rmq_src_config_o_int(i)(0 to c_CFG.rmq_config.slot_count-1),
rmq_src_config_i => rmq_src_config_i_int(i)(0 to c_CFG.rmq_config.slot_count-1),
rmq_snk_config_o => rmq_snk_config_o_int(i)(0 to c_CFG.rmq_config.slot_count-1),
rmq_snk_config_i => rmq_snk_config_i_int(i)(0 to c_CFG.rmq_config.slot_count-1),
cb_csr_i => per_cb_csr_fromwb(i),
cb_csr_o => per_cb_csr_towb(i),
gpio_o => cpu_gpio_out(i),
......@@ -408,8 +421,8 @@ begin -- arch
hmq_out_int_en(8*i + 7 downto 8*i)) /= X"00");
gen_unused_rmq_slots : for j in c_CFG.rmq_config.slot_count to t_maxslot_range'high generate
rmq_src_o(i)(j) <= c_MT_DUMMY_SINK_IN;
rmq_snk_o(i)(j) <= c_MT_DUMMY_SOURCE_IN;
rmq_src_o_int(i)(j) <= c_MT_DUMMY_SINK_IN;
rmq_snk_o_int(i)(j) <= c_MT_DUMMY_SOURCE_IN;
end generate gen_unused_rmq_slots;
per_cb_csr_fromwb(i) <= (
......@@ -434,8 +447,8 @@ begin -- arch
notif_value(8*i + 7 downto 8*i) <= (others => '0');
hmq_in_status(8*i + 7 downto 8*i) <= (others => '0');
hmq_out_status(8*i + 7 downto 8*i) <= (others => '0');
rmq_snk_o(i) <= (others => c_MT_DUMMY_SOURCE_IN);
rmq_src_o(i) <= (others => c_MT_DUMMY_SINK_IN);
rmq_snk_o_int(i) <= (others => c_MT_DUMMY_SOURCE_IN);
rmq_src_o_int(i) <= (others => c_MT_DUMMY_SINK_IN);
end generate gen_no_cpus;
p_notif_irq_reg: process (clk_i) is
......@@ -519,6 +532,16 @@ begin -- arch
end if;
end process p_debug_irq;
rmq_endpoint_o.snk_out <= rmq_snk_o_int;
rmq_endpoint_o.snk_config_out <= rmq_snk_config_o_int;
rmq_endpoint_o.src_out <= rmq_src_o_int;
rmq_endpoint_o.src_config_out <= rmq_src_config_o_int;
rmq_snk_i_int <= rmq_endpoint_i.snk_in;
rmq_src_i_int <= rmq_endpoint_i.src_in;
rmq_snk_config_i_int <= rmq_endpoint_i.snk_config_in;
rmq_src_config_i_int <= rmq_endpoint_i.src_config_in;
gpio_o <= f_reduce_or(cpu_gpio_out);
notify_irq <= f_to_std_logic(cpu_csr_towb.int_i /= x"00");
......
......@@ -108,6 +108,42 @@ package mock_turtle_pkg is
subtype t_mt_stream_source_in_array2d is t_mt_stream_sink_out_array2d;
subtype t_mt_stream_source_out_array2d is t_mt_stream_sink_in_array2d;
type t_mt_stream_config_in_array2d is
array(t_maxcpu_range) of t_mt_stream_config_in_array(t_maxslot_range);
type t_mt_stream_config_out_array2d is
array(t_maxcpu_range) of t_mt_stream_config_out_array(t_maxslot_range);
constant c_MT_STREAM_SINK_IN_ARRAY2D_DEFAULT_VALUE : t_mt_stream_sink_in_array2d :=
(others => (others => c_MT_DUMMY_SINK_IN ) );
constant c_MT_STREAM_SOURCE_IN_ARRAY2D_DEFAULT_VALUE : t_mt_stream_source_in_array2d :=
(others => (others => c_MT_DUMMY_SOURCE_IN ) );
constant c_MT_STREAM_CONFIG_IN_ARRAY2D_DEFAULT_VALUE : t_mt_stream_config_in_array2d :=
(others => (others => c_MT_DUMMY_EP_CONFIG_IN ) );
type t_mt_rmq_endpoint_iface_out is record
src_out : t_mt_stream_source_out_array2d;
snk_out : t_mt_stream_sink_out_array2d;
src_config_out : t_mt_stream_config_out_array2d;
snk_config_out : t_mt_stream_config_out_array2d;
end record;
type t_mt_rmq_endpoint_iface_in is record
src_in : t_mt_stream_source_in_array2d;
snk_in : t_mt_stream_sink_in_array2d;
src_config_in : t_mt_stream_config_in_array2d;
snk_config_in : t_mt_stream_config_in_array2d;
end record;
constant c_MT_RMQ_ENDPOINT_IFACE_IN_DEFAULT_VALUE : t_mt_rmq_endpoint_iface_in :=
(
c_MT_STREAM_SOURCE_IN_ARRAY2D_DEFAULT_VALUE,
c_MT_STREAM_SINK_IN_ARRAY2D_DEFAULT_VALUE,
c_MT_STREAM_CONFIG_IN_ARRAY2D_DEFAULT_VALUE,
c_MT_STREAM_CONFIG_IN_ARRAY2D_DEFAULT_VALUE
);
component mock_turtle_core is
generic (
g_CONFIG : t_mt_config := c_DEFAULT_MT_CONFIG;
......@@ -120,10 +156,8 @@ package mock_turtle_pkg is
sp_master_i : in t_wishbone_master_in := c_DUMMY_WB_MASTER_IN;
dp_master_o : out t_wishbone_master_out_array(0 to g_CONFIG.cpu_count-1);
dp_master_i : in t_wishbone_master_in_array(0 to g_CONFIG.cpu_count-1) := (others => c_DUMMY_WB_MASTER_IN);
rmq_src_o : out t_mt_stream_source_out_array2d;
rmq_src_i : in t_mt_stream_source_in_array2d := (others => (others => c_MT_DUMMY_SOURCE_IN));
rmq_snk_o : out t_mt_stream_sink_out_array2d;
rmq_snk_i : in t_mt_stream_sink_in_array2d := (others => (others => c_MT_DUMMY_SINK_IN));
rmq_endpoint_o : out t_mt_rmq_endpoint_iface_out;
rmq_endpoint_i : in t_mt_rmq_endpoint_iface_in := c_MT_RMQ_ENDPOINT_IFACE_IN_DEFAULT_VALUE;
host_slave_i : in t_wishbone_slave_in;
host_slave_o : out t_wishbone_slave_out;
clk_ref_i : in std_logic := '0';
......
......@@ -35,11 +35,12 @@ package mt_mqueue_pkg is
constant c_MT_STREAM_TAG_PAYLOAD : std_logic_vector(1 downto 0) := "01";
type t_mt_stream_sink_in is record
data : std_logic_vector(31 downto 0);
hdr : std_logic;
valid : std_logic;
last : std_logic;
error : std_logic;
req : std_logic;
data : std_logic_vector(31 downto 0);
hdr : std_logic;
valid : std_logic;
last : std_logic;
error : std_logic;
end record t_mt_stream_sink_in;
type t_mt_stream_sink_out is record
......@@ -49,25 +50,46 @@ package mt_mqueue_pkg is
pkt_ready : std_logic;
end record t_mt_stream_sink_out;
type t_mt_stream_config_out is record
adr : std_logic_vector(10 downto 0);
dat : std_logic_vector(31 downto 0);
we : std_logic;
end record t_mt_stream_config_out;
type t_mt_stream_config_in is record
dat : std_logic_vector(31 downto 0);
end record t_mt_stream_config_in;
subtype t_mt_stream_source_in is t_mt_stream_sink_out;
subtype t_mt_stream_source_out is t_mt_stream_sink_in;
constant c_MT_DUMMY_SOURCE_IN : t_mt_stream_sink_out :=
('0', '0');
constant c_MT_DUMMY_SINK_IN : t_mt_stream_sink_in :=
(x"00000000", '0', '0', '0', '0');
('0', x"00000000", '0', '0', '0', '0');
constant c_MT_DUMMY_EP_CONFIG_OUT : t_mt_stream_config_out :=
("00000000000", x"00000000", '0');
constant c_MT_DUMMY_EP_CONFIG_IN : t_mt_stream_config_in :=
(dat => x"00000000");
type t_mt_stream_sink_in_array is array(integer range<>) of t_mt_stream_sink_in;
type t_mt_stream_sink_out_array is array(integer range<>) of t_mt_stream_sink_out;
type t_mt_stream_config_out_array is array(integer range<>) of t_mt_stream_config_out;
type t_mt_stream_config_in_array is array(integer range<>) of t_mt_stream_config_in;
subtype t_mt_stream_source_in_array is t_mt_stream_sink_out_array;
subtype t_mt_stream_source_out_array is t_mt_stream_sink_in_array;
type t_mt_mqueue_slot_config is record
entries_bits : natural;
width_bits : natural;
header_bits : positive;
endpoint_id : std_logic_vector(31 downto 0);
entries_bits : natural;
width_bits : natural;
header_bits : positive;
endpoint_id : std_logic_vector(31 downto 0);
enable_config_space : boolean;
end record t_mt_mqueue_slot_config;
subtype t_maxslot_range is natural range 0 to 7;
......@@ -82,25 +104,22 @@ package mt_mqueue_pkg is
end record t_mt_mqueue_config;
constant c_DUMMY_MT_MQUEUE_SLOT : t_mt_mqueue_slot_config :=
(0, 0, 1, x"0000_0000");
(0, 0, 1, x"0000_0000", false);
constant c_DUMMY_MT_MQUEUE_CONFIG : t_mt_mqueue_config := (
slot_count => 0,
slot_config => (others => (c_DUMMY_MT_MQUEUE_SLOT)));
constant c_MT_DEFAULT_MQUEUE_CONFIG : t_mt_mqueue_config :=
(1, ((7, 3, 2, x"0000_0000"), others => (c_DUMMY_MT_MQUEUE_SLOT)));
(1, ((7, 5, 6, x"0000_0000", false), others => (c_DUMMY_MT_MQUEUE_SLOT)));
-- Bus to control an mqueue slot.
type t_slot_bus_in is record
-- Other bits are valid only when sel='1'.
sel : std_logic;
-- '0' for header, '1' for payload
hdr_n : std_logic;
sel : std_logic;
-- Byte address (8KB).
adr : std_logic_vector(12 downto 0);
-- Byte address (16KB).
adr : std_logic_vector(13 downto 0);
dat : std_logic_vector(31 downto 0);
we : std_logic;
......@@ -115,10 +134,12 @@ package mt_mqueue_pkg is
constant c_mqueue_addr_command : std_logic_vector (13 downto 0) :=
b"00_0000_0000_0000";
constant c_mqueue_addr_status : std_logic_vector (13 downto 0) :=
constant c_mqueue_addr_status : std_logic_vector (13 downto 0) :=
b"00_0000_0000_0100";
constant c_mqueue_addr_header : std_logic_vector (13 downto 0) :=
constant c_mqueue_addr_header : std_logic_vector (13 downto 0) :=
b"01_0000_0000_0000";
constant c_mqueue_addr_header_size : std_logic_vector (13 downto 0) :=
b"01_0000_0000_0100";
constant c_mqueue_addr_payload : std_logic_vector (13 downto 0) :=
b"10_0000_0000_0000";
......@@ -130,10 +151,10 @@ package mt_mqueue_pkg is
-- Mqueue slot status.
type t_slot_status_out is record
-- All entries are used.
full : std_logic;
full : std_logic;
-- No entry is used.
empty : std_logic;
empty : std_logic;
end record t_slot_status_out;
constant c_dummy_status_out : t_slot_status_out := ('0', '0');
......
......@@ -33,16 +33,24 @@ entity mt_mqueue_remote is
generic (
g_CONFIG : t_mt_mqueue_config := c_MT_DEFAULT_MQUEUE_CONFIG);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out;
-- From OUT rmq
src_o : out t_mt_stream_source_out_array(0 to g_CONFIG.slot_count-1);
src_i : in t_mt_stream_source_in_array(0 to g_CONFIG.slot_count-1);
-- To IN rmq
snk_o : out t_mt_stream_sink_out_array(0 to g_CONFIG.slot_count-1);
snk_i : in t_mt_stream_sink_in_array(0 to g_CONFIG.slot_count-1);
clk_i : in std_logic;
rst_n_i : in std_logic;
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out;
-- From OUT rmq (from CPUs to the outside world)
src_o : out t_mt_stream_source_out_array(0 to g_CONFIG.slot_count-1);
src_i : in t_mt_stream_source_in_array(0 to g_CONFIG.slot_count-1);
src_config_o : out t_mt_stream_config_out_array( 0 to g_CONFIG.slot_count-1);
src_config_i : in t_mt_stream_config_in_array( 0 to g_CONFIG.slot_count-1);
-- To IN rmq (from inside world to the CPUs)
snk_o : out t_mt_stream_sink_out_array(0 to g_CONFIG.slot_count-1);
snk_i : in t_mt_stream_sink_in_array(0 to g_CONFIG.slot_count-1);
snk_config_o : out t_mt_stream_config_out_array( 0 to g_CONFIG.slot_count-1);
snk_config_i : in t_mt_stream_config_in_array( 0 to g_CONFIG.slot_count-1);
-- RMQ status
rmq_in_status_o : out std_logic_vector(g_CONFIG.slot_count-1 downto 0);
rmq_out_status_o : out std_logic_vector(g_CONFIG.slot_count-1 downto 0));
......@@ -82,7 +90,8 @@ begin -- rtl
U_Out_SlotX : entity work.mt_mqueue_slot
generic map (
g_CONFIG => g_config.slot_config(i))
g_CONFIG => g_config.slot_config(i),
g_EP_CONFIG_MAP_PORT => "inb" )
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
......@@ -90,7 +99,10 @@ begin -- rtl
inb_i => cpu_outgoing_in(i),
inb_o => cpu_outgoing_out(i),
outb_i => ep_outgoing_in(i),
outb_o => ep_outgoing_out(i));
outb_o => ep_outgoing_out(i),
ep_config_o => src_config_o(i),
ep_config_i => src_config_i(i)
);
U_Out_Tx : entity work.mt_rmq_tx
generic map (
......@@ -108,7 +120,8 @@ begin -- rtl
U_In_SlotX : entity work.mt_mqueue_slot
generic map (
g_CONFIG => g_config.slot_config(i))
g_CONFIG => g_config.slot_config(i),
g_EP_CONFIG_MAP_PORT => "outb")
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
......@@ -116,7 +129,10 @@ begin -- rtl
outb_i => cpu_incoming_in(i),
outb_o => cpu_incoming_out(i),
inb_i => ep_incoming_in(i),
inb_o => ep_incoming_out(i));
inb_o => ep_incoming_out(i),
ep_config_o => snk_config_o(i),
ep_config_i => snk_config_i(i)
);
U_In_Rx : entity work.mt_rmq_rx
generic map (
......
......@@ -31,20 +31,25 @@ use work.mt_mqueue_pkg.all;
entity mt_mqueue_slot is
generic (
g_CONFIG : t_mt_mqueue_slot_config);
g_CONFIG : t_mt_mqueue_slot_config;
g_EP_CONFIG_MAP_PORT : string := "inb");
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
stat_o : out t_slot_status_out;
stat_o : out t_slot_status_out;
-- Input
inb_i : in t_slot_bus_in;
inb_o : out t_slot_bus_out;
inb_i : in t_slot_bus_in;
inb_o : out t_slot_bus_out;
-- Output
outb_i : in t_slot_bus_in;
outb_o : out t_slot_bus_out
outb_i : in t_slot_bus_in;
outb_o : out t_slot_bus_out;
-- Aux WB master for configuring the RMQ endpoints. Maps to the header space.
ep_config_o : out t_mt_stream_config_out;
ep_config_i : in t_mt_stream_config_in := c_MT_DUMMY_EP_CONFIG_IN
);
end mt_mqueue_slot;
......@@ -64,13 +69,13 @@ architecture arch of mt_mqueue_slot is
shared variable mem2 : t_slot_mem_array := (others => (others => '0'));
shared variable mem3 : t_slot_mem_array := (others => (others => '0'));
signal mem_raddr, mem_waddr : unsigned(c_MEMORY_ADDR_BITS-1 downto 0);
signal mem_raddr, mem_waddr : unsigned(c_MEMORY_ADDR_BITS-1 downto 0);
signal mem_rdata_in, mem_rdata_out : std_logic_vector(31 downto 0);
type t_header_mem_array is
array(0 to c_HEADER_SIZE-1) of std_logic_vector(7 downto 0);
signal hdr_raddr, hdr_waddr : unsigned(c_HEADER_ADDR_BITS-1 downto 0);
signal hdr_raddr, hdr_waddr : unsigned(c_HEADER_ADDR_BITS-1 downto 0);
signal hdr_rdata_in, hdr_rdata_out : std_logic_vector(31 downto 0);
shared variable hdr0 : t_header_mem_array := (others => (others => '0'));
......@@ -105,8 +110,11 @@ architecture arch of mt_mqueue_slot is
signal purge_int : std_logic;
type t_reg_rd is (REG_RD_STATUS, REG_RD_HEADER, REG_RD_PAYLOAD);
type t_reg_rd is (REG_RD_STATUS, REG_RD_HEADER, REG_RD_PAYLOAD, REG_RD_EP_CONFIG);
signal in_reg_rd, out_reg_rd : t_reg_rd;
signal ep_config_rdata : std_logic_vector(31 downto 0);
begin
-- Generate mem_we.
p_mem_write : process(inb_i, wr_state)
......@@ -133,20 +141,18 @@ begin
status(15 downto 8) <= std_logic_vector(occupied);
status(31 downto 28) <= (others => '0');
in_cmd_wr <= '1' when (inb_i.sel = '1'
and inb_i.we = '1'
and inb_i.hdr_n = '0'
and inb_i.adr = c_mqueue_addr_command(12 downto 0))
else '0';
in_cmd_wr <= '1' when (inb_i.sel = '1'
and inb_i.we = '1'
and inb_i.adr = c_mqueue_addr_command)
else '0';
out_cmd_wr <= '1' when (outb_i.sel = '1'
and outb_i.we = '1'
and outb_i.hdr_n = '0'
and outb_i.adr = c_mqueue_addr_command(12 downto 0))
and outb_i.adr = c_mqueue_addr_command)
else '0';
in_claim <= in_cmd_wr and inb_i.dat(c_mqueue_command_claim);
in_purge <= in_cmd_wr and inb_i.dat(c_mqueue_command_purge);
in_ready <= in_cmd_wr and inb_i.dat(c_mqueue_command_ready);
in_claim <= in_cmd_wr and inb_i.dat(c_mqueue_command_claim);
in_purge <= in_cmd_wr and inb_i.dat(c_mqueue_command_purge);
in_ready <= in_cmd_wr and inb_i.dat(c_mqueue_command_ready);
out_discard <= out_cmd_wr and outb_i.dat(c_mqueue_command_discard);
out_purge <= out_cmd_wr and outb_i.dat(c_mqueue_command_purge);
......@@ -165,13 +171,17 @@ begin
p_read_status : process(clk_i)
function f_to_reg_rd (bus_in : t_slot_bus_in) return t_reg_rd is
begin
if bus_in.hdr_n = '1' then
if bus_in.adr(13) = '1' then
return REG_RD_PAYLOAD;
else
if bus_in.adr(12) = '0' then
return REG_RD_STATUS;
else
return REG_RD_HEADER;
if bus_in.adr(11) = '1' then
return REG_RD_EP_CONFIG;
else
return REG_RD_HEADER;
end if;
end if;
end if;
end f_to_reg_rd;
......@@ -185,28 +195,30 @@ begin
with in_reg_rd select inb_o.dat <=
status when REG_RD_STATUS,
hdr_rdata_in when REG_RD_HEADER,
mem_rdata_in when REG_RD_PAYLOAD;
mem_rdata_in when REG_RD_PAYLOAD,
ep_config_i.dat when REG_RD_EP_CONFIG;
with out_reg_rd select outb_o.dat <=
status when REG_RD_STATUS,
hdr_rdata_out when REG_RD_HEADER,
mem_rdata_out when REG_RD_PAYLOAD;
mem_rdata_out when REG_RD_PAYLOAD,
ep_config_i.dat when REG_RD_EP_CONFIG;
-- Note: we do four separate memories due to a bug in Xilinx ISE which
-- does not infer properly BRAM when using one 32-bit memory
p_mem_port1 : process(clk_i)
begin
if rising_edge(clk_i) then
if mem_we(0) = '1' and inb_i.hdr_n = '1' then
if mem_we(0) = '1' and inb_i.adr(13 downto 12) = "10" then
mem0(to_integer(mem_waddr)) := inb_i.dat(7 downto 0);
end if;
if mem_we(1) = '1' and inb_i.hdr_n = '1' then
if mem_we(1) = '1' and inb_i.adr(13 downto 12) = "10" then
mem1(to_integer(mem_waddr)) := inb_i.dat(15 downto 8);
end if;
if mem_we(2) = '1' and inb_i.hdr_n = '1' then
if mem_we(2) = '1' and inb_i.adr(13 downto 12) = "10" then
mem2(to_integer(mem_waddr)) := inb_i.dat(23 downto 16);
end if;
if mem_we(3) = '1' and inb_i.hdr_n = '1' then
if mem_we(3) = '1' and inb_i.adr(13 downto 12) = "10" then
mem3(to_integer(mem_waddr)) := inb_i.dat(31 downto 24);
end if;
......@@ -232,16 +244,16 @@ begin
p_hdr_port1 : process(clk_i)
begin
if rising_edge(clk_i) then
if mem_we(0) = '1' and inb_i.hdr_n = '0' and inb_i.adr(12) = '1' then
if mem_we(0) = '1' and inb_i.adr(13 downto 12) = "01" then
hdr0(to_integer(hdr_waddr)) := inb_i.dat(7 downto 0);
end if;
if mem_we(1) = '1' and inb_i.hdr_n = '0' and inb_i.adr(12) = '1' then
if mem_we(1) = '1' and inb_i.adr(13 downto 12) = "01" then
hdr1(to_integer(hdr_waddr)) := inb_i.dat(15 downto 8);
end if;
if mem_we(2) = '1' and inb_i.hdr_n = '0' and inb_i.adr(12) = '1' then
if mem_we(2) = '1' and inb_i.adr(13 downto 12) = "01" then
hdr2(to_integer(hdr_waddr)) := inb_i.dat(23 downto 16);
end if;
if mem_we(3) = '1' and inb_i.hdr_n = '0' and inb_i.adr(12) = '1' then
if mem_we(3) = '1' and inb_i.adr(13 downto 12) = "01" then
hdr3(to_integer(hdr_waddr)) := inb_i.dat(31 downto 24);
end if;
......@@ -266,7 +278,7 @@ begin
begin
if rising_edge(clk_i) then
if rst_n_i = '0' or purge_int = '1' then
wr_state <= IDLE;
wr_state <= IDLE;
else
case wr_state is
when IDLE =>
......@@ -313,7 +325,7 @@ begin
end if;
end process p_read_side;
q_write <= '1' when wr_state = ACCEPT_DATA and in_ready = '1' else '0';
q_write <= '1' when wr_state = ACCEPT_DATA and in_ready = '1' else '0';
q_read <= '1' when rd_state = WAIT_DISCARD and out_discard = '1' else '0';
p_counters : process(clk_i)
......@@ -347,4 +359,18 @@ begin
empty <= '1' when wr_ptr = rd_ptr else '0';
stat_o <= (full => full, empty => empty);
gen_ep_config_use_inb : if g_EP_CONFIG_MAP_PORT = "inb" generate
ep_config_o.adr(10 downto 0) <= inb_i.adr(10 downto 0);
ep_config_o.dat <= inb_i.dat;
ep_config_o.we <= inb_i.sel and inb_i.we and inb_i.adr(12) and inb_i.adr(11);
end generate gen_ep_config_use_inb;
gen_ep_config_use_outb : if g_EP_CONFIG_MAP_PORT = "outb" generate
ep_config_o.adr(10 downto 0) <= outb_i.adr(10 downto 0);
ep_config_o.dat <= outb_i.dat;
ep_config_o.we <= outb_i.sel and outb_i.we and outb_i.adr(12) and outb_i.adr(11);
end generate gen_ep_config_use_outb;
end architecture arch;
......@@ -73,16 +73,14 @@ begin -- arch
gen_slots : for i in 0 to g_CONFIG.slot_count-1 generate
incoming_o(i) <=
(sel => f_to_std_logic (in_area_sel = '1' and unsigned(slot_num) = i),
hdr_n => slave_i.adr(13),
adr => slave_i.adr(12 downto 0),
adr => slave_i.adr(13 downto 0),
dat => slave_i.dat,
we => wb_write,
wmask => slave_i.sel);
outgoing_o(i) <=
(sel => f_to_std_logic (out_area_sel = '1' and unsigned(slot_num) = i),
hdr_n => slave_i.adr(13),
adr => slave_i.adr(12 downto 0),
adr => slave_i.adr(13 downto 0),
dat => slave_i.dat,
we => wb_write,
wmask => slave_i.sel);
......
......@@ -33,16 +33,16 @@ entity mt_rmq_rx is
generic (
g_CONFIG : t_mt_mqueue_slot_config);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
clk_i : in std_logic;
rst_n_i : in std_logic;
-- Input
snk_o : out t_mt_stream_sink_out;
snk_i : in t_mt_stream_sink_in;
snk_o : out t_mt_stream_sink_out;
snk_i : in t_mt_stream_sink_in;
-- Output
outb_i : in t_slot_bus_out;
outb_o : out t_slot_bus_in;
outb_i : in t_slot_bus_out;
outb_o : out t_slot_bus_in;
-- Status from output.
outb_stat_i : in t_slot_status_out);
......@@ -50,27 +50,33 @@ end mt_rmq_rx;
architecture arch of mt_rmq_rx is
type t_state_enum is (WAIT_SLOT, CLAIM, READY);
type t_state_enum is (WAIT_SLOT, CLAIM, WRITE_SIZE, READY);
type t_state is record
state : t_state_enum;
addr : unsigned(12 downto 2);
state : t_state_enum;
addr : unsigned(13 downto 0);
is_even : std_logic;
payload_size : unsigned(12 downto 0);
is_hdr_d : std_logic;
end record;
signal state, n_state : t_state;
begin
p_fsm_next: process (rst_n_i, state, outb_stat_i, snk_i)
p_fsm_next : process (rst_n_i, state, outb_stat_i, snk_i)
begin
if rst_n_i = '0' then
n_state <= (state => WAIT_SLOT,
addr => (others => 'X'));
n_state <= (state => WAIT_SLOT,
addr => (others => 'X'),
is_even => '1',
payload_size => (others => 'X'),
is_hdr_d => 'X');
snk_o <= (pkt_ready => '0',
ready => '0');
outb_o <= (sel => '0',
hdr_n => 'X',
adr => (others => 'X'),
dat => (others => 'X'),
we => 'X',
ready => '0');
outb_o <= (sel => '0',
adr => (others => 'X'),
dat => (others => 'X'),
we => 'X',
wmask => "XXXX");
else
case state.state is
......@@ -78,85 +84,143 @@ begin
if outb_stat_i.full = '0' then
-- A packet can be received. Claim it.
snk_o <= (pkt_ready => '1',
ready => '1');
outb_o <= (sel => '1',
hdr_n => '0',
adr => c_mqueue_addr_command(12 downto 0),
dat => (c_mqueue_command_claim => '1', others => '0'),
we => '1',
ready => '1');
outb_o <= (sel => '1',
adr => c_mqueue_addr_command,
dat => (c_mqueue_command_claim => '1', others => '0'),
we => '1',
wmask => "1111");
n_state <= (state => CLAIM,
addr => unsigned(c_mqueue_addr_header(12 downto 2)));
n_state <= (state => CLAIM,
addr => unsigned(c_mqueue_addr_header) + 8,
is_even => '1',
payload_size => (others => '0'),
is_hdr_d => 'X'
);
else
-- Wait until a slot is ready.
snk_o <= (pkt_ready => '0',
ready => '0');
outb_o <= (sel => '0',
hdr_n => 'X',
adr => (others => 'X'),
dat => (others => 'X'),
we => 'X',
ready => '0');
outb_o <= (sel => '0',
adr => (others => 'X'),
dat => (others => 'X'),
we => 'X',
wmask => "XXXX");
n_state <= state;
end if;
when CLAIM =>
n_state <= state;
snk_o <= (pkt_ready => '1',
ready => '1');
ready => '1');
if snk_i.valid = '1' then
-- Data available, store it.
outb_o <= (sel => '1',
hdr_n => not snk_i.hdr,
adr => std_logic_vector(state.addr & "00"),
dat => snk_i.data,
adr => std_logic_vector(state.addr),
dat => snk_i.data(7 downto 0) & snk_i.data(15 downto 8) & snk_i.data(7 downto 0) & snk_i.data(15 downto 8),
we => '1',
wmask => "1111");
if snk_i.last = '1' then
if snk_i.hdr = '0' then
-- End of payload.
n_state <= (state => READY,
addr => (others => 'X'));
else
-- End of header.
n_state <=
(state => CLAIM,
addr => unsigned(c_mqueue_addr_payload(12 downto 2)));
end if;
wmask => "0000");
if(state.is_even = '1') then
outb_o.wmask <= "0011";
else
outb_o.wmask <= "1100";
end if;
if snk_i.error = '1' then
-- Error (in the packet) or packet dropped by the EP filter
n_state.state <= WAIT_SLOT;
elsif snk_i.last = '1' then
-- End of payload.
n_state.state <= WRITE_SIZE;
else
n_state <= (state => CLAIM,
addr => state.addr + 1);
if (state.is_hdr_d = '1' and snk_i.hdr = '0') then
-- end of header
outb_o.adr <= c_mqueue_addr_payload;
outb_o.wmask <= "0011";
n_state.addr <= unsigned(c_mqueue_addr_payload);
n_state.state <= CLAIM;
n_state.is_even <= '0';
n_state.payload_size <= to_unsigned(2, 13);
n_state.is_hdr_d <= '0';
else
n_state.state <= CLAIM;
n_state.is_hdr_d <= snk_i.hdr;
n_state.is_even <= not state.is_even;
if(snk_i.hdr = '0') then
n_state.payload_size <= state.payload_size + 2;
end if;
if state.is_even = '1' then
n_state.addr <= state.addr;
else
n_state.addr <= state.addr + 4;
end if; -- even
end if; -- hdr
end if;
else
outb_o <= (sel => '0',
hdr_n => 'X',
adr => (others => 'X'),
dat => (others => 'X'),
we => 'X',
outb_o <= (sel => '0',
adr => (others => 'X'),
dat => (others => 'X'),
we => '0',
wmask => "XXXX");
n_state <= state;
end if;
when READY =>
when WRITE_SIZE =>
-- Make the slot ready.
snk_o <= (pkt_ready => '0',
ready => '0');
ready => '0');
outb_o <= (sel => '1',
hdr_n => '0',
adr => c_mqueue_addr_command(12 downto 0),
dat => (c_mqueue_command_ready => '1',
others => '0'),
adr => c_mqueue_addr_header_size,
dat => std_logic_vector(resize(state.payload_size, 32)),
we => '1',
wmask => "1111");
n_state <= (state => WAIT_SLOT,
addr => (others => 'X'));
n_state <= (state => READY,
addr => (others => 'X'),
is_even => '1',
payload_size => (others => 'X'),
is_hdr_d => 'X');
when READY =>
-- Make the slot ready.
snk_o <= (pkt_ready => '0',
ready => '0');
outb_o <= (sel => '1',
adr => c_mqueue_addr_command,
dat => (c_mqueue_command_ready => '1',
others => '0'),
we => '1',
wmask => "1111");
n_state <= (state => WAIT_SLOT,
addr => (others => 'X'),
is_even => '1',
payload_size => (others => 'X'),
is_hdr_d => 'X');
end case;
end if;
end process;
p_fsm_reg: process (clk_i, rst_n_i)
p_fsm_reg : process (clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
state <= (state => WAIT_SLOT,
addr => (others => 'X'));
state <= (state => WAIT_SLOT,
addr => (others => 'X'),
is_even => '1',
payload_size => (others => 'X'),
is_hdr_d => 'X');
else
state <= n_state;
end if;
......
This diff is collapsed.
action = "synthesis"
target = "xilinx"
fetchto = "../../ip_cores"
syn_device = "xc6slx150t"
syn_grade = "-3"
syn_package = "fgg900"
syn_top = "svec_mt_demo_wr"
syn_project = "svec_mt_demo_wr.xise"
top_module = "svec_mt_demo_wr"
syn_tool = "ise"
syn_post_project_cmd = "$(TCL_INTERPRETER) " + \
fetchto + "/general-cores/tools/sdb_desc_gen.tcl " + \
syn_tool + " $(PROJECT_FILE)"
files = [
"svec_mt_demo_wr.ucf",
]
modules = {
"local" : [
"../../top/svec_mt_demo_wr",
"../../ip_cores/wr-cores/board/svec"
],
"git" : [
"git://ohwr.org/hdl-core-lib/general-cores.git",
"git://ohwr.org/hdl-core-lib/urv-core.git",
"git://ohwr.org/hdl-core-lib/vme64x-core.git",
"git://ohwr.org/hdl-core-lib/wr-cores.git",
],
}
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -26,18 +26,68 @@
`include "mock_turtle_driver.svh"
`include "vhd_wishbone_master.svh"
import mock_turtle_pkg::*;
import wr_fabric_pkg::*;
import mt_mqueue_pkg::*;
`include "stream_mon.svh"
`include "string_utils.svh"
`timescale 1ns/1ps
typedef byte byte_vector_t[$];
function automatic byte_vector_t loadPacketFromFile(string name);
integer fd;
byte_vector_t rv;
fd = $fopen(name, "r");
if (fd == 0)
$error("Can't open '%s'", name);
while(1)
begin
string s;
int n, i;
string_array_t tokens;
n = $fgets(s, fd);
if(n<=0)
break;
tokens = tokenizeString(s);
for(i=1; i < tokens.size(); i++)
rv.push_back( parseHex(tokens[i] ) );
end
return rv;
endfunction // loadPacketFromFile
module main;
reg rst_n = 0;
reg clk_sys = 0;
t_mt_stream_source_out_array2d rmq_src_out;
t_mt_stream_source_in_array2d rmq_src_in;
t_mt_rmq_endpoint_iface_out mt2ep;
t_mt_rmq_endpoint_iface_in ep2mt;
t_wrf_source_out eth_src_out;
t_wrf_source_in eth_src_in;
t_wrf_sink_out eth_snk_out;
t_wrf_sink_in eth_snk_in;
always #8ns clk_sys <= ~clk_sys;
initial begin
......@@ -45,7 +95,11 @@ module main;
rst_n = 1;
end
mock_turtle_core # ()
//`undef USE_INTEGRATED_ENDPOINT
mock_turtle_core #
(
)
DUT (
.clk_i (clk_sys),
.rst_n_i (rst_n),
......@@ -55,10 +109,10 @@ module main;
.sp_master_i (),
.dp_master_o (),
.dp_master_i (),
.rmq_src_o (rmq_src_out),
.rmq_snk_i (rmq_src_out),
.rmq_snk_o (rmq_src_in),
.rmq_src_i (rmq_src_in),
.rmq_endpoint_o(mt2ep),
.rmq_endpoint_i(ep2mt),
.clk_ref_i (),
.tm_i (),
.gpio_o (),
......@@ -69,11 +123,54 @@ module main;
.console_irq_o ()
);
mt_rmq_ethernet_endpoint
EP (
.clk_i (clk_sys),
.rst_n_i(rst_n),
.mt_rmq_i(mt2ep),
.mt_rmq_o(ep2mt),
.eth_src_o (eth_src_out),
.eth_src_i (eth_src_in),
.eth_snk_o (eth_snk_out),
.eth_snk_i (eth_snk_in)
);
assign eth_src_in.ack = 1'b1;
assign eth_src_in.stall = 1'b0;
assign eth_src_in.err = 1'b0;
assign eth_src_in.rty = 1'b0;
// assign eth_snk_in.cyc = 1'b0;
/* stream_mon MonOut
(
.clk_i(clk_sys),
.rst_n_i(rst_n),
.snk_in_i(rmq_src_out[0][0]),
.snk_out_i(rmq_src_in[0][0])
);*/
wr_fabric_master EthSrc(
.clk_i(clk_sys),
.rst_n_i(rst_n),
.src_i(eth_snk_out),
.src_o(eth_snk_in)
);
IVHDWishboneMaster Host ( clk_sys, rst_n );
IMockTurtleIRQ IrqMonitor (`MT_ATTACH_IRQ(DUT));
string fw = "../../../tests/firmware/sim-verif/sim-verif.bin";
string fw = "../../../tests/firmware/rmq-udp-send/fw-rmq-udp-send.bin";
const uint64_t mt_base = 'h0000;
......@@ -98,7 +195,7 @@ module main;
drv.get_cpu_notifications (0, ntf);
while (ntf.size)
begin
inc_counter();
inc_counter();
ntf.delete(0);
msg = new (0, 0);
msg.header[0] = 0;
......@@ -110,7 +207,7 @@ module main;
endtask // check_cpu_notifications
task check_hmq_incoming ();
// check for pending messages in core 0, slot 0
// check from pending messages in core 0, slot 0
while (drv.hmq_pending_messages(0, 0))
begin
// Get a message from core 0, slot 0
......@@ -148,10 +245,11 @@ module main;
endtask // check_final_result
initial begin
automatic byte_vector_t pkt = loadPacketFromFile("1.dump");
#10us;
drv = new (Host.get_accessor(), mt_base, IrqMonitor);
drv = new (Host.get_accessor(), mt_base, IrqMonitor, 1'b0);
drv.init();
......@@ -171,6 +269,9 @@ module main;
drv.reset_core (0, 0);
fork
forever begin
drv.update ();
check_cpu_notifications ();
......@@ -178,6 +279,15 @@ module main;
# 1us;
end
begin
#100us;
EthSrc.send(pkt);
end
join
end // initial begin
endmodule // main
......@@ -5,6 +5,6 @@ set NumericStdNoWarnings 1
radix -hexadecimal
log -r /*
do wave.do
run -all
run 3000us
......@@ -95,10 +95,10 @@ architecture arch of svec_mt_demo is
cpu_count => 2,
cpu_config => (others =>
(memsize => 8192,
hmq_config => (2, (0 => (7, 3, 2, x"0000_0000"),
1 => (5, 4, 3, x"0000_0000"),
hmq_config => (2, (0 => (7, 3, 2, x"0000_0000", false),
1 => (5, 4, 3, x"0000_0000", false),
others => (c_DUMMY_MT_MQUEUE_SLOT))),
rmq_config => (1, (0 => (7, 2, 2, x"0000_0000"),
rmq_config => (1, (0 => (7, 2, 2, x"0000_0000", false),
others => (c_DUMMY_MT_MQUEUE_SLOT))))),
shared_mem_size => 2048);
......@@ -175,6 +175,13 @@ architecture arch of svec_mt_demo is
signal rmq_us_i : t_mt_stream_source_out_array2d;
signal rmq_us_o : t_mt_stream_source_in_array2d;
signal rmq_src_config_out : t_mt_stream_config_out_array2d;
signal rmq_snk_config_out : t_mt_stream_config_out_array2d;
signal rmq_src_config_in : t_mt_stream_config_in_array2d;
signal rmq_snk_config_in : t_mt_stream_config_in_array2d;
attribute keep : string;
attribute keep of fp_gpio_in : signal is "true";
......@@ -346,6 +353,11 @@ begin -- architecture arch
rmq_src_i => rmq_ds_i,
rmq_snk_o => rmq_us_o,
rmq_snk_i => rmq_us_i,
rmq_src_config_o => rmq_src_config_out,
rmq_src_config_i => rmq_src_config_in,
rmq_snk_config_o => rmq_snk_config_out,
rmq_snk_config_i => rmq_snk_config_in,
hmq_in_irq_o => mt_hmq_in_irq,
hmq_out_irq_o => mt_hmq_out_irq,
notify_irq_o => mt_notify_irq,
......
files = [
"svec_mt_demo_wr.vhd",
]
modules = {
"local" : [
"../../rtl",
],
}
This diff is collapsed.
......@@ -71,3 +71,85 @@ void pr_message(struct trtl_fw_msg *msg)
for (i = 0; i < h->len; i++)
pp_printf("%s: data[%d] = 0x%"PRIx32"\n\r", __func__, i , d[i]);
}
static inline void rmq_ep_out_writel( int slot, uint32_t data, uint32_t addr )
{
mq_writel( TRTL_RMQ, data, addr + TRTL_MQ_SLOT_ENDPOINT_CONFIG_START + TRTL_MQ_SLOT_OUT (slot) );
}
static inline void rmq_ep_in_writel( int slot, uint32_t data, uint32_t addr )
{
mq_writel( TRTL_RMQ, data, addr + TRTL_MQ_SLOT_ENDPOINT_CONFIG_START + TRTL_MQ_SLOT_IN (slot) );
}
static void rmq_ep_bind_in ( int slot, struct trtl_ep_address* addr )
{
uint32_t cfg = 0;
switch(addr->type)
{
case TRTL_EP_FRAME_UDP:
cfg |= TRTL_EP_FILTER_UDP;
break;
case TRTL_EP_FRAME_TLV:
cfg |= TRTL_EP_FILTER_UDP;
break;
case TRTL_EP_FRAME_RAW:
cfg |= TRTL_EP_FILTER_RAW;
break;
}
cfg |= addr->filter;
uint32_t tmp;
rmq_ep_in_writel( slot, cfg, TRTL_EP_IN_CONFIG );
tmp = ( (uint32_t)addr->dst_mac[0] << 8 ) | addr->dst_mac[1];
rmq_ep_in_writel( slot, tmp, TRTL_EP_IN_DST_MAC_HI );
tmp = ( (uint32_t)addr->dst_mac[2] << 24 ) |
( (uint32_t)addr->dst_mac[3] << 16 ) |
( (uint32_t)addr->dst_mac[4] << 8 ) |
( (uint32_t)addr->dst_mac[5] << 0 );
rmq_ep_in_writel( slot, tmp, TRTL_EP_IN_DST_MAC_LO );
rmq_ep_in_writel( slot, addr->ethertype, TRTL_EP_IN_ETHERTYPE );
rmq_ep_in_writel( slot, addr->dst_ip, TRTL_EP_IN_DST_IP );
rmq_ep_in_writel( slot, addr->dst_port, TRTL_EP_IN_DST_PORT );
}
static void rmq_ep_bind_out ( int slot, struct trtl_ep_address* addr )
{
uint32_t tmp;
rmq_ep_out_writel( slot, addr->type == TRTL_EP_FRAME_UDP ? 1 : 0, TRTL_EP_OUT_CONFIG );
tmp = ( (uint32_t)addr->dst_mac[0] << 8 ) | addr->dst_mac[1];
rmq_ep_out_writel( slot, tmp, TRTL_EP_OUT_MAC_HI );
tmp = ( (uint32_t)addr->dst_mac[2] << 24 ) |
( (uint32_t)addr->dst_mac[3] << 16 ) |
( (uint32_t)addr->dst_mac[4] << 8 ) |
( (uint32_t)addr->dst_mac[5] << 0 );
rmq_ep_out_writel( slot, tmp, TRTL_EP_OUT_MAC_LO );
rmq_ep_out_writel( slot, addr->ethertype, TRTL_EP_OUT_ETHERTYPE );
rmq_ep_out_writel( slot, addr->src_ip, TRTL_EP_OUT_SRC_IP );
rmq_ep_out_writel( slot, addr->dst_ip, TRTL_EP_OUT_DST_IP );
rmq_ep_out_writel( slot, addr->src_port, TRTL_EP_OUT_SRC_PORT );
rmq_ep_out_writel( slot, addr->dst_port, TRTL_EP_OUT_DST_PORT );
}
void mq_bind(enum trtl_mq_type type, int slot, int is_out, struct trtl_ep_address* addr)
{
if( type != TRTL_RMQ )
{
pr_error("mq_bind() not supported on HMQ slots\n\r");
return;
}
if(is_out)
rmq_ep_bind_out( slot, addr );
else
rmq_ep_bind_in( slot, addr );
}
......@@ -17,8 +17,11 @@
#include <hw/mockturtle_addresses.h>
#include <hw/mockturtle_queue.h>
#include <hw/mockturtle_endpoint.h>
#include <hw/mockturtle_cpu_lr.h>
#include <urv/riscv.h>
#include <mockturtle.h>
......@@ -385,6 +388,12 @@ static inline void mq_writel(enum trtl_mq_type type, uint32_t val, uint32_t reg)
}
static inline uint32_t mq_readl(enum trtl_mq_type type, uint32_t reg)
{
return *(volatile uint32_t *)(trtl_mq_base_address(type) + reg);
}
/**
* It gets the output slot data field pointer
* @param[in] type MQ type to use
......@@ -441,10 +450,17 @@ static inline void *mq_map_in_header(enum trtl_mq_type type, int slot)
* @copydoc TRTL_MQ_CMD_CLAIM
* @param[in] type MQ type to use
* @param[in] slot slot number
* @return 1 on success, 0 if queue busy/full
*/
static inline void mq_claim(enum trtl_mq_type type, int slot)
static inline int mq_claim(enum trtl_mq_type type, int slot)
{
uint32_t status = mq_readl(type, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_STATUS);
if( status & TRTL_MQ_SLOT_STATUS_FULL )
return 0;
mq_writel(type, TRTL_MQ_CMD_CLAIM, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
return 1;
}
/**
......@@ -470,6 +486,15 @@ static inline void mq_send(enum trtl_mq_type type, int slot)
mq_writel(type, TRTL_MQ_CMD_READY, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
}
/**
* Binds an RMQ slot to a particular IP configuration. Used when the Ethernet/UDP endpoint is enabled.
* @param[in] type MQ type to use
* @param[in] slot slot number
* @param[in] is_out non-zero if we're configuring an output slot
* @param[in] addr bind address
*/
void mq_bind(enum trtl_mq_type type, int slot, int is_out, struct trtl_ep_address* addr);
/**
* @copydoc TRTL_MQ_CMD_DISCARD
......@@ -595,6 +620,16 @@ static inline uint32_t mq_poll_out_wait(enum trtl_mq_type type, uint32_t mask,
return p;
}
static inline uint32_t trtl_get_runtime_milliseconds()
{
return riscv_rdtime();
}
static inline uint32_t trtl_get_runtime_cycles()
{
return riscv_rdcycle();
}
/**
* Shared Memory Size
......
......@@ -3,34 +3,34 @@
#ifdef __GNUC__
#define read_csr(reg) ({ unsigned long __tmp; \
#define riscv_read_csr(reg) ({ unsigned long __tmp; \
asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
__tmp; })
#define write_csr(reg, val) \
#define riscv_write_csr(reg, val) \
asm volatile ("csrw " #reg ", %0" :: "r"(val))
#define swap_csr(reg, val) ({ long __tmp; \
#define riscv_swap_csr(reg, val) ({ long __tmp; \
asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \
__tmp; })
#define set_csr(reg, bit) ({ unsigned long __tmp; \
#define riscv_set_csr(reg, bit) ({ unsigned long __tmp; \
if (__builtin_constant_p(bit) && (bit) < 32) \
asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
else \
asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
__tmp; })
#define clear_csr(reg, bit) ({ unsigned long __tmp; \
#define riscv_clear_csr(reg, bit) ({ unsigned long __tmp; \
if (__builtin_constant_p(bit) && (bit) < 32) \
asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
else \
asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
__tmp; })
#define rdtime() read_csr(time)
#define rdcycle() read_csr(cycle)
#define rdinstret() read_csr(instret)
#define riscv_rdtime() riscv_read_csr(time)
#define riscv_rdcycle() riscv_read_csr(cycle)
#define riscv_rdinstret() riscv_read_csr(instret)
#endif
......
/*
* This work is part of the White Rabbit Node Core project.
*
* Copyright (C) 2013-2014 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
/*.
* White Rabbit Node Core
*
* rt-mqueue.h: Message Queues definitions and functions
*/
#ifndef __TRTL_ENDPOINT_H
#define __TRTL_ENDPOINT_H
#define TRTL_EP_OUT_CONFIG 0
#define TRTL_EP_OUT_MAC_HI 4
#define TRTL_EP_OUT_MAC_LO 8
#define TRTL_EP_OUT_ETHERTYPE 12
#define TRTL_EP_OUT_DST_IP 16
#define TRTL_EP_OUT_SRC_IP 20
#define TRTL_EP_OUT_DST_PORT 24
#define TRTL_EP_OUT_SRC_PORT 28
#define TRTL_EP_FRAME_RAW 0
#define TRTL_EP_FRAME_UDP 1
#define TRTL_EP_FRAME_TLV 2
#define TRTL_EP_FILTER_RAW (1<<2)
#define TRTL_EP_FILTER_UDP (1<<0)
#define TRTL_EP_FILTER_DST_PORT (1<<5)
#define TRTL_EP_FILTER_ETHERTYPE (1<<5)
#define TRTL_EP_FILTER_DST_MAC (1<<3)
#define TRTL_EP_FILTER_DST_IP (1<<6)
#define TRTL_EP_FILTER_TLV0 (1<<7)
#define TRTL_EP_FILTER_TLV1 (1<<8)
#define TRTL_EP_FILTER_TLV2 (1<<9)
#define TRTL_EP_FILTER_TLV3 (1<<10)
#define TRTL_EP_IN_CONFIG 0
#define TRTL_EP_IN_DST_MAC_HI 4
#define TRTL_EP_IN_DST_MAC_LO 8
#define TRTL_EP_IN_ETHERTYPE 12
#define TRTL_EP_IN_DST_IP 16
#define TRTL_EP_IN_DST_PORT 20
#define TRTL_EP_IN_DST_TYPE0 24
#define TRTL_EP_IN_DST_TYPE1 28
#define TRTL_EP_IN_DST_TYPE2 32
#define TRTL_EP_IN_DST_TYPE3 36
struct trtl_ep_address {
uint32_t type;
uint32_t filter;
uint8_t dst_mac[6];
uint16_t ethertype;
uint32_t src_ip;
uint32_t dst_ip;
uint16_t src_port;
uint16_t dst_port;
uint32_t tlvs[4];
};
#endif
......@@ -29,6 +29,8 @@
#define TRTL_MQ_SLOT_HEADER_START 0x1000
// Start of data block
#define TRTL_MQ_SLOT_DATA_START 0x2000
// Start of endpoint control registers (RMQ only)
#define TRTL_MQ_SLOT_ENDPOINT_CONFIG_START 0x1800
// Layout of TRTL_MQ_SLOT_COMMAND register:
......
......@@ -8,6 +8,7 @@ DIRS += sim-verif
DIRS += hmq-async-recv
DIRS += hmq-async-send
DIRS += hmq-purge
DIRS += rmq-udp-send
DIRS += rt-frm
......
mainmenu "rmq_udp_send test configuration"
comment "Project specific configuration"
config FPGA_APPLICATION_ID
int "FPGA application ID"
default 0
help
Help text
config RT_APPLICATION_ID
int "RT application ID"
default 0
help
Help text
# include Mock Turtle's Kconfig
source "Kconfig.mt"
-include ../Makefile.specific
OBJS = rmq-udp-send.o
OBJS += # add other object files that you need
OUTPUT = fw-rmq-udp-send
TRTL ?= ../../../
TRTL_SW = $(TRTL)/software
CFLAGS_OPT = -O0 # disable optimization
include $(TRTL_SW)/firmware/Makefile
#include <mockturtle-rt.h>
// maximum payload size of the test packets, in 32-bit words
#define MAX_RMQ_PAYLOAD 128
// maximum header (UDP+IP+Ethernet) size of the test packets, in 32-bit words
#define MAX_RMQ_HEADER 128
#define TEST_MESSAGE_ID 0xdeadbeef
struct trtl_test_message
{
// Message id (0xdeadbeef)
uint32_t id;
// MT CPU that sent the message
uint32_t cpu;
// Sequence number
uint32_t seq;
// Statistics: total number of packets received by the MT CPU
uint32_t n_rx;
// Statistics: number of packets missed (by finding gaps in the sequential numbers)
uint32_t n_missed;
// Statistics: number of packets received with errors
uint32_t n_errors;
// Payload size in 32-bit words
uint32_t payload_len;
uint32_t payload[MAX_RMQ_PAYLOAD];
};
uint32_t tx_seq_count = 0;
uint32_t rx_count = 0;
uint32_t rx_last_id = -1;
uint32_t rx_missed = 0;
uint32_t rx_errors = 0;
void send_reply(int cpu_id, int rmq, int payload_len)
{
struct trtl_fw_msg msg;
int i;
// queue full? wait
if (!mq_claim(TRTL_RMQ, rmq))
return;
mq_map_out_message(TRTL_RMQ, rmq, &msg);
msg.header->len = payload_len + 7;
struct trtl_test_message *p = msg.payload;
p->id = TEST_MESSAGE_ID;
p->cpu = cpu_id;
p->seq = tx_seq_count++;
p->n_rx = rx_count;
p->n_missed = rx_missed;
p->n_errors = rx_errors;
p->payload_len = payload_len;
// make some dummy payload
for (int i = 0; i < payload_len; i++)
{
p->payload[i] = (((i << 16) | i) ^ 0xffff0000);
}
mq_send(TRTL_RMQ, rmq);
}
void handle_rx(int cpu_id, int rmq)
{
if (!mq_poll_in(TRTL_RMQ, 1 << rmq))
return;
struct trtl_fw_msg tmsg;
mq_map_in_message(TRTL_RMQ, rmq, &tmsg);
struct trtl_test_message *p = tmsg.payload;
if (p->id != TEST_MESSAGE_ID)
{
rx_errors++;
mq_discard(TRTL_RMQ, rmq);
return;
}
// validate the payload
for (int i = 0; i < p->payload_len; i++)
{
if (p->payload[i] != (((i << 16) | i) ^ 0xffff0000))
{
rx_errors++;
break;
}
}
// look for missing packets
if (p->seq == 0)
{
rx_missed = 0;
tx_seq_count = 0;
}
else if (rx_count != 0 && (rx_last_id + 1) != p->seq)
{
rx_missed += p->seq - rx_last_id - 1;
}
rx_last_id = p->seq;
rx_count++;
send_reply(cpu_id, rmq, p->payload_len);
mq_discard(TRTL_RMQ, rmq);
}
uint32_t last_ts = 0;
void print_stats()
{
uint32_t ts = trtl_get_runtime_milliseconds();
if ((last_ts == 0) || (ts >= (last_ts + 1000)))
{
pp_printf("Stats: RX %d, missed %d, errors %d\n\r", rx_count, rx_missed, rx_errors);
last_ts = ts;
}
}
int main()
{
int cpu = trtl_get_core_id();
int rmq = 0;
last_ts = 0;
struct trtl_ep_address bind_addr;
pp_printf("TEST for: RMQ UDP send/receive, slot %d, cpu %d\r\n", rmq, cpu);
// set up the RMQ Endpoint
// we operate only with UDP frames
bind_addr.type = TRTL_EP_FRAME_UDP;
// destination MAC: we use broadcast
bind_addr.dst_mac[0] = 0xff;
bind_addr.dst_mac[1] = 0xff;
bind_addr.dst_mac[2] = 0xff;
bind_addr.dst_mac[3] = 0xff;
bind_addr.dst_mac[4] = 0xff;
bind_addr.dst_mac[5] = 0xff;
// destination port
bind_addr.dst_port = 12345;
// source port
bind_addr.src_port = 7777;
// destination IP: 192.168.90.255 (broadcast)
bind_addr.dst_ip = 0xC0A85AFF;
// source IP: 192.168.90.255 (broadcast)
bind_addr.src_ip = 0xC0A85A11;
bind_addr.ethertype = 0x800; // IPv4
// RX filter: we want only UDP packets with matching desination port & IP address.
bind_addr.filter = TRTL_EP_FILTER_UDP | TRTL_EP_FILTER_DST_PORT | TRTL_EP_FILTER_DST_IP;
// configure outgoing channel
mq_bind(TRTL_RMQ, rmq, 1, &bind_addr);
// configure incoming channel
mq_bind(TRTL_RMQ, rmq, 0, &bind_addr);
for (;;)
{
handle_rx(cpu, rmq);
print_stats();
}
return 0;
}
-include ../Makefile.specific
OBJS = serial.o
OBJS += # add other object files that you need
OUTPUT = fw-serial
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment