Commit 9ecd15d5 authored by Federico Vaga's avatar Federico Vaga

Merge remote-tracking branch 'eth_endpoint' into fvaga-proposed_master

parents 85f75878 86c87a12
......@@ -3,7 +3,7 @@
#
# Author: Adam Wujek, CERN 2017
TB_DIRS=mock_turtle_core svec_mt_demo spec_mt_demo
TB_DIRS=mock_turtle_core svec_mt_demo spec_mt_demo mt_eth_ep
#TB_DIRS+=spec_ref_design-verification
test_results_xml=test_results.xml
......@@ -13,6 +13,7 @@ all: $(TB_DIRS) summary summary_total summary_xml
MT_VERF_RT_BIN = ../../tests/firmware/sim-verif/sim-verif.bin
MT_DEMO_RT_BIN = ../../demos/hello_world/firmware/fw-01/fw-hello.bin
MT_ETH_RT_BIN = ../../tests/firmware/rmq-udp-send/fw-rmq-udp-send.bin
mock_turtle_core: $(MT_VERF_RT_BIN)
......@@ -20,7 +21,9 @@ svec_mt_demo: $(MT_DEMO_RT_BIN)
spec_mt_demo: $(MT_DEMO_RT_BIN)
$(MT_DEMO_RT_BIN) $(MT_VERF_RT_BIN):
mt_eth_ep: $(MT_ETH_RT_BIN)
$(MT_DEMO_RT_BIN) $(MT_VERF_RT_BIN) $(MT_ETH_RT_BIN):
$(MAKE) -C $(@D) defconfig
$(MAKE) -C $(@D)
......@@ -132,4 +135,3 @@ clean:
rm -f $$d/Makefile; \
fi \
done
......@@ -13,8 +13,9 @@ vcom_opt = "-93 -mixedsvvh"
include_dirs = [
"../include/",
"../include/regs/",
"../../ip_cores/urv-core/rtl/",
"../../ip_cores/wr-cores/sim",
"../../ip_cores/general-cores/sim/",
"../../ip_cores/urv-core/rtl/",
]
files = [
......
......@@ -24,6 +24,10 @@
`include "mock_turtle_driver.svh"
`include "vhd_wishbone_master.svh"
`include "if_wb_master.svh"
`include "if_wb_slave.svh"
`include "wb_packet_sink.svh"
`include "wb_packet_source.svh"
import mock_turtle_pkg::*;
......@@ -31,50 +35,8 @@ 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;
......@@ -94,11 +56,49 @@ module main;
rst_n = 1;
end
//`undef USE_INTEGRATED_ENDPOINT
mock_turtle_core #
IWishboneMaster
#(
.g_data_width(16),
.g_addr_width(2))
U_wrf_source
(
)
.clk_i(clk_sys),
.rst_n_i(rst_n)
);
assign eth_snk_in.adr = U_wrf_source.adr;
assign eth_snk_in.dat = U_wrf_source.dat_o;
assign eth_snk_in.cyc = U_wrf_source.cyc;
assign eth_snk_in.stb = U_wrf_source.stb;
assign eth_snk_in.we = U_wrf_source.we;
assign eth_snk_in.sel = U_wrf_source.sel;
assign U_wrf_source.ack = eth_snk_out.ack;
assign U_wrf_source.stall = eth_snk_out.stall;
assign U_wrf_source.err = eth_snk_out.err;
assign U_wrf_source.rty = eth_snk_out.rty;
IWishboneSlave
#(
.g_data_width(16),
.g_addr_width(2))
U_wrf_sink
(
.clk_i(clk_sys),
.rst_n_i(rst_n)
);
assign U_wrf_sink.adr = eth_src_out.adr;
assign U_wrf_sink.dat_i = eth_src_out.dat;
assign U_wrf_sink.cyc = eth_src_out.cyc;
assign U_wrf_sink.stb = eth_src_out.stb;
assign U_wrf_sink.we = eth_src_out.we;
assign U_wrf_sink.sel = eth_src_out.sel;
assign eth_src_in.ack = U_wrf_sink.ack;
assign eth_src_in.stall = U_wrf_sink.stall;
assign eth_src_in.err = U_wrf_sink.err;
assign eth_src_in.rty = U_wrf_sink.rty;
mock_turtle_core #()
DUT (
.clk_i (clk_sys),
.rst_n_i (rst_n),
......@@ -122,14 +122,20 @@ module main;
.console_irq_o ()
);
mt_rmq_ethernet_endpoint
mt_ep_ethernet_single
EP (
.clk_i (clk_sys),
.rst_n_i(rst_n),
.mt_rmq_i(mt2ep),
.mt_rmq_o(ep2mt),
.rmq_src_i(mt2ep.snk_out[0][0]),
.rmq_src_o(ep2mt.snk_in[0][0]),
.rmq_src_config_i(mt2ep.snk_config_out[0][0]),
.rmq_src_config_o(ep2mt.snk_config_in[0][0]),
.rmq_snk_i(mt2ep.src_out[0][0]),
.rmq_snk_o(ep2mt.src_in[0][0]),
.rmq_snk_config_i(mt2ep.src_config_out[0][0]),
.rmq_snk_config_o(ep2mt.src_config_in[0][0]),
.eth_src_o (eth_src_out),
.eth_src_i (eth_src_in),
......@@ -138,33 +144,7 @@ module main;
.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 );
IVHDWishboneMaster Host (clk_sys, rst_n);
IMockTurtleIRQ IrqMonitor (`MT_ATTACH_IRQ(DUT));
......@@ -175,11 +155,12 @@ module main;
MockTurtleDriver drv;
initial begin
automatic byte_vector_t pkt = loadPacketFromFile("1.dump");
automatic WBPacketSink sink = new(U_wrf_sink.get_accessor());
automatic WBPacketSource src = new(U_wrf_source.get_accessor());
#10us;
drv = new (Host.get_accessor(), mt_base, IrqMonitor, 1'b0);
drv = new (Host.get_accessor(), mt_base, IrqMonitor);
drv.init();
......@@ -194,19 +175,36 @@ module main;
fork
forever begin
t_notify_queue ntf;
// Wait for interrupts
drv.update ();
// Check notifications.
drv.get_cpu_notifications (0, ntf);
if (ntf.size) begin
$display ("Simulation PASSED");
$finish;
end
# 1us;
end
begin
#100us;
EthSrc.send(pkt);
forever begin
EthPacket pkt;
sink.recv(pkt);
pkt.dump;
for(int i = 24; i < pkt.payload.size(); i++)
pkt.payload[i] = ~pkt.payload[i];
src.send(pkt);
end
begin
#400us;
$fatal (1, "Simulation FAILED");
end
join
end // initial begin
endmodule // main
#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)
static void send_pkt(int rmq, unsigned val)
{
struct trtl_fw_msg msg;
// queue full? wait
if (!mq_claim(TRTL_RMQ, rmq))
return;
while (!mq_claim(TRTL_RMQ, rmq))
;
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;
unsigned *p = msg.payload;
msg.header->len = 2;
// make some dummy payload
for (int i = 0; i < payload_len; i++)
{
p->payload[i] = (((i << 16) | i) ^ 0xffff0000);
}
p[0] = TEST_MESSAGE_ID;
p[1] = val;
mq_send(TRTL_RMQ, rmq);
}
void handle_rx(int cpu_id, int rmq)
static unsigned handle_rx(int rmq)
{
if (!mq_poll_in(TRTL_RMQ, 1 << rmq))
return;
unsigned res;
while (!mq_poll_in(TRTL_RMQ, 1 << rmq))
;
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);
unsigned *p = tmsg.payload;
res = p[1];
mq_discard(TRTL_RMQ, rmq);
}
pp_printf("Recv id=%x, val=%x\n", p[0], p[1]);
uint32_t last_ts = 0;
mq_discard(TRTL_RMQ, rmq);
void print_stats()
{
uint32_t ts = trtl_get_runtime_milliseconds();
if ((last_ts == 0) || (ts >= (last_ts + 1000)))
{
pp_printf("Stats: RX %"PRId32", missed %"PRId32", errors %"PRId32"\n\r",
rx_count, rx_missed, rx_errors);
last_ts = ts;
}
return res;
}
int main()
{
int cpu = trtl_get_core_id();
unsigned v;
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);
pp_printf("RMQ UDP EP test\n");
// set up the RMQ Endpoint
......@@ -147,7 +64,7 @@ int main()
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
......@@ -159,17 +76,23 @@ int main()
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;
bind_addr.filter |= TRTL_EP_FILTER_ENABLE;
// 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();
}
send_pkt(0, 0x123);
v = handle_rx(0);
pp_printf("rx(1): %x\n", v);
send_pkt(0, v);
v = handle_rx(0);
pp_printf("rx(2): %x\n", v);
if (v == 0x123) {
lr_writel(v, MT_CPU_LR_REG_NTF_INT);
}
return 0;
}
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