Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/axistream/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build
bin
*.swp
mold_example/mold_example
mold_example/mold_remover_stream
85 changes: 85 additions & 0 deletions apps/axistream/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#
# Copyright 2017 Two Sigma Open Source, LLC
#
# Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the 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.


CXXFLAGS = -std=c++11 -Wall -Werror -Wno-unused-label

# Set these
CATCH_DIR = ../catch
HLS_INCLUDE_DIR = /home/tslocal/xilinx/Vivado/2018.3/include/

SRC_DIR = src
TEST_DIR = test
TL_DIR = tl
MOLD_EXAMPLE_DIR = mold_example
BUILD_DIR = build
BIN_DIR = bin

INCLUDE_DIRS = $(SRC_DIR) $(TEST_DIR) $(TL_DIR) $(MOLD_EXAMPLE_DIR) $(CATCH_DIR) $(HLS_INCLUDE_DIR)
INCLUDE_FLAGS = $(addprefix -I,$(INCLUDE_DIRS))

SRCS = $(wildcard src/*.cc)
HDRS = $(wildcard src/*.hh)
OBJS = $(addprefix $(BUILD_DIR)/,$(notdir $(patsubst %.cc,%.o,$(SRCS))))

TEST_SRCS = $(wildcard test/*.cc)
TEST_HDRS = $(wildcard test/*.hh)
TEST_OBJS = $(addprefix $(BUILD_DIR)/,$(notdir $(patsubst %.cc,%.o,$(TEST_SRCS))))

TL_SRCS = $(wildcard tl/*.cc)
TL_HDRS = $(wildcard tl/*.hh)
TL_OBJS = $(addprefix $(BUILD_DIR)/,$(notdir $(patsubst %.cc,%.o,$(TL_SRCS))))

MOLD_EXAMPLE_SRCS = $(wildcard mold_example/*.cc)
MOLD_EXAMPLE_HDRS = $(wildcard mold_example/*.hh)
MOLD_EXAMPLE_OBJS = $(addprefix $(BUILD_DIR)/,$(notdir $(patsubst %.cc,%.o,$(MOLD_EXAMPLE_SRCS))))

BINS = $(addprefix $(BIN_DIR)/,test_main tl_main mold_example_main)

ARTIFACTS = $(OBJS) $(TEST_OBJS) $(TL_OBJS) $(MOLD_EXAMPLE_OBJS) $(BINS)

all: $(OBJS) $(TEST_OBJS) $(BINS)

$(BIN_DIR)/test_main: $(OBJS) $(TEST_OBJS)
@mkdir -p $(BIN_DIR)
$(CXX) -o $@ $^

$(BIN_DIR)/tl_main: $(OBJS) $(TL_OBJS)
@mkdir -p $(BIN_DIR)
$(CXX) -o $@ $^

$(BIN_DIR)/mold_example_main: $(OBJS) $(MOLD_EXAMPLE_OBJS)
@mkdir -p $(BIN_DIR)
$(CXX) -o $@ $^

$(BUILD_DIR)/%.o : $(SRC_DIR)/%.cc $(HDRS)
@mkdir -p $(BUILD_DIR)
$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCLUDE_FLAGS)

$(BUILD_DIR)/%.o : $(TEST_DIR)/%.cc $(HDRS)
@mkdir -p $(BUILD_DIR)
$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCLUDE_FLAGS)

$(BUILD_DIR)/%.o : $(TL_DIR)/%.cc $(HDRS)
@mkdir -p $(BUILD_DIR)
$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCLUDE_FLAGS)

$(BUILD_DIR)/%.o : $(MOLD_EXAMPLE_DIR)/%.cc $(HDRS)
@mkdir -p $(BUILD_DIR)
$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCLUDE_FLAGS)

.PHONY: clean
clean:
rm -f $(ARTIFACTS)
20 changes: 20 additions & 0 deletions apps/axistream/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Axistream

## Contents
* `src`: the library itself
* `test`: unit tests
* `tl`: a simple top-level function for HLS synthesis
* `mold_example`: an example for parsing NASDAQ ITCH marketdata events over moldudp64. (Based off of: https://github.com/Xilinx/HLS_packet_processing/tree/master/apps/mold_remover_stream)

## Building
The tests require [Catch2](https://github.com/catchorg/Catch2).
Download `catch.hpp`, and then set the `CATCH_DIR` variable in the `Makefile`
accordingly.

Configure the following 2 lines the in Makefile:
```
CATCH_DIR = ../catch
HLS_INCLUDE_DIR = /u/tsqahfus/local/tools/xilinx/Vivado/2018.3/include/
```
Comment on lines +9 to +18

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this could be a git submodule?


Then run `make`.
44 changes: 44 additions & 0 deletions apps/axistream/mold_example/mold_example.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <cstdint>
#include "mold_example.hh"
#include "axi_stream_reader.hh"
#include "ethernet.hh"
#include "ip.hh"
#include "udp.hh"
#include "moldudp64.hh"
#include "itch.hh"

void mold_example(AxiStream<8>& in_stream, hls::stream<int32_t>& out) {

@orangeturtle739 orangeturtle739 Dec 10, 2019

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stephenneuendorffer I made the mold_remover_stream example:

void process_packet(ap_uint<48> macAddresst, ap_uint<32> ipAddress, int port,
hls::stream<StreamType> &input,
hls::stream<StreamType> &output,
hls::stream<ap_uint<32> > &outputMeta) {
MACAddressT macAddress = macAddresst;
#pragma HLS inline all recursive
// Define the structure of the packets we're interested in. Generally speaking we
// have parallel access to the 'header' portion (the values are stored in registers),
// and sequential access to the 'packet' portion (the values are stored in BRAM).
auto reader = make_reader(input);
auto writer = make_writer(output);
// Read the headers from the input stream.
ethernet::header eh;
reader.get(eh);
ipv4::header ih;
reader.get(ih);
ipv4::udp_header uh;
reader.get(uh);
// Check that the packet is something we care about.
ap_uint<16> dmp_macType = eh.get<ethernet::etherType>();
bool valid = true;
MACAddressT destinationMAC = eh.get<ethernet::destinationMAC>();
if(destinationMAC != macAddress &&
destinationMAC != BROADCAST_MAC) {
#ifndef __SYNTHESIS__
std::cout << "Dropping invalid MAC address: " << macAddress.toString(16, false) << " " << destinationMAC.toString(16, false) << "\n";
// hexdump_ethernet_frame<4>(buf, len);
#endif
valid = false;
}
if(eh.get<ethernet::etherType>() != ethernet::ethernet_etherType::IPV4) {
valid = false;
}
if(ih.get<ipv4::protocol>() != ipv4::ipv4_protocol::UDP) {
valid = false;
}
if(ih.get<ipv4::destination>() != ipAddress) {
valid = false;
}
if(uh.get<ipv4::dport>() != port) {
valid = false;
}
if(valid) {
mold64::header mh;
reader.get(mh);
mold_message_loop:
// Iterate over each mold message, starting at offset 0 after the mold header.
for(int i = 0; i < mh.get<messageCount>(); i++) {
// Extract a mold message from the 'packet' portion
mold64::message_header mold_message;
reader.get(mold_message);
// Look at the mold message to figure out how long the itch message is.
int length = mold_message.get<messageLength>();
// Extract the itch message and do something with it.
// "mold_message.p" is the 'rest' of the packet after the mold message header
// Parsing a packet is a constant time operation and the data is not moved.
// Getting the fields of a 'parsed' header in this case is sequential, since it
// was originally deserialized into a Packet object.
itch::header itch_message;
//auto itch_message = itch::header::contains(message);
//itch_message.extend(length);
reader.get(itch_message);
//std::cout << "message:" << (char)itch_message.get<messageType>() << "\n";
if(itch_message.get<messageType>() == 'R') {
itch::directory_header m;
reader.read_rest();//
//reader.get(m);
//auto itch_directory_message = parse_itch_directory_hdr(message);
// itch_directory_message.serialize(output);
outputMeta << 1;
} else if(itch_message.get<messageType>() == 'A') {
itch::add_order_header m;
//reader.read_rest();//
reader.get(m);
//auto itch_add_order_message = parse_itch_add_order_hdr(message);
// itch_add_order_message.serialize(output);
outputMeta << 2;
}
}
} else {
// Dump the remaining packet
reader.read_rest();
}
}

HLS_PRAGMA(HLS interface port=in_stream axis);
HLS_PRAGMA(HLS interface port=out ap_fifo);
HLS_PRAGMA(HLS interface ap_ctrl_none port=return);

AxiStreamReader<8> reader(in_stream);
ethernet::Header e;
ip::v4::Header ip;
udp::Header udp;
moldudp64::Header mold;

reader.read<LengthPolicy::Unchecked>(e, ip, udp, mold);
if (e.get<ethernet::EtherType>() != ethernet::ETHER_TYPE::IPV4 ||
e.get<ethernet::DestinationMac>() != 0xc0ffee ||
ip.get<ip::v4::Protocol>() != ip::v4::PROTOCOL::UDP ||
ip.get<ip::v4::DestinationIP>() != 0xdeadbeef ||
udp.get<udp::DestinationPort>() != 0xf00d) {
reader.drain();
return;
}

mold_message_loop:
for(int i = 0; i < mold.get<moldudp64::MessageCount>(); i++) {
moldudp64::MessageHeader message_header;
itch::Header itch_header;
reader.read<LengthPolicy::Unchecked>(message_header, itch_header);
if(itch_header.get<itch::MessageType>() == itch::MESSAGE_TYPE::STOCK_DIRECTORY) {
reader.read<LengthPolicy::Unchecked, itch::StockDirectory>();
out.write(1);
} else if (itch_header.get<itch::MessageType>() == itch::MESSAGE_TYPE::ADD_ORDER_NO_MPID_ATTRIBUTION) {
reader.read<LengthPolicy::Unchecked, itch::AddOrder>();
out.write(2);
}
}
}
22 changes: 22 additions & 0 deletions apps/axistream/mold_example/mold_example.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2017 Two Sigma Open Source, LLC
*
* Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the 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.
*/


#pragma once

#include "axi_stream_common.hh"

void mold_example(AxiStream<8>& in_stream, hls::stream<int32_t>& out);
49 changes: 49 additions & 0 deletions apps/axistream/mold_example/mold_example_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "catch.hpp"
#include "mold_example.hh"
#include "axi_stream_reader.hh"
#include "axi_stream_writer.hh"
#include "ethernet.hh"
#include "ip.hh"
#include "udp.hh"
#include "moldudp64.hh"
#include "itch.hh"

TEST_CASE("mold_example") {
AxiStream<8> input_stream;
hls::stream<int32_t> output_stream;
AxiStreamWriter<8> writer(input_stream);

ethernet::Header e;
ip::v4::Header ip;
udp::Header udp;
moldudp64::Header mold;

e.set<ethernet::EtherType>(ethernet::ETHER_TYPE::IPV4);
e.set<ethernet::DestinationMac>(0xc0ffee);
ip.set<ip::v4::Protocol>(ip::v4::PROTOCOL::UDP);
ip.set<ip::v4::DestinationIP>(0xdeadbeef);
udp.set<udp::DestinationPort>(0xf00d);
mold.set<moldudp64::MessageCount>(2);
writer.write(e, false);
writer.write(ip, false);
writer.write(udp, false);
writer.write(mold, false);

moldudp64::MessageHeader message_header;
itch::Header itch_header;
itch::StockDirectory stock_directory;
itch::AddOrder add_order;
itch_header.set<itch::MessageType>(itch::MESSAGE_TYPE::STOCK_DIRECTORY);
writer.write(message_header, false);
writer.write(itch_header, false);
writer.write(stock_directory, false);
itch_header.set<itch::MessageType>(itch::MESSAGE_TYPE::ADD_ORDER_NO_MPID_ATTRIBUTION);
writer.write(message_header, false);
writer.write(itch_header, false);
writer.write(add_order, true);

mold_example(input_stream, output_stream);

CHECK(output_stream.read() == 1);
CHECK(output_stream.read() == 2);
}
32 changes: 32 additions & 0 deletions apps/axistream/mold_example/script.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#
# Copyright 2017 Two Sigma Open Source, LLC
#
# Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the 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.


open_project mold_example
set_top mold_example

set cppflags "-I ../src -I ../../catch -std=gnu++11"
add_files mold_example.cc -cflags "$cppflags"
add_files -tb test_main.cc -cflags "$cppflags"
add_files -tb mold_example_test.cc -cflags "$cppflags"

open_solution "solution"
set_part {xcvu9p-flgb2104-3-e}
create_clock -period 3.103 -name default
config_rtl -reset_level low
csim_design -compiler clang
csynth_design
cosim_design -compiler clang -trace_level all -ldflags "-L/usr/lib/x86_64-linux-gnu/ -B/usr/lib/x86_64-linux-gnu/"
quit
2 changes: 2 additions & 0 deletions apps/axistream/mold_example/test_main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
Loading