Coyote/examples_hw/apps/tcp_iperf/hls/axi_utils.hpp

1394 lines
30 KiB
C++

/*
* Copyright (c) 2019, Systems Group, ETH Zurich
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <hls_stream.h>
#include "ap_int.h"
#include <stdint.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#if defined( __VITIS_HLS__)
#include "ap_axi_sdata.h"
#endif
//Adaptation of ap_axiu<>
/*template <int D>
struct axis
{
ap_uint<D> data;
ap_uint<D/8> keep;
ap_uint<1> last;
axis() {}
axis(ap_uint<D> data, ap_uint<D/8> keep, ap_uint<1> last)
:data(data), keep(keep), last(last) {}
};*/
template <int D>
struct net_axis
{
ap_uint<D> data;
ap_uint<D/8> keep;
ap_uint<1> last;
net_axis() {}
net_axis(ap_uint<D> data, ap_uint<D/8> keep, ap_uint<1> last)
:data(data), keep(keep), last(last) {}
};
#if defined( __VITIS_HLS__)
template <int WIDTH>
void convert_net_axis_to_axis(hls::stream<net_axis<WIDTH> >& input,
hls::stream<ap_axiu<WIDTH, 0, 0, 0> >& output)
{
#pragma HLS pipeline II=1
net_axis<WIDTH> inputWord;
ap_axiu<WIDTH, 0, 0, 0> outputWord;
if (!input.empty())
{
inputWord = input.read();
outputWord.data = inputWord.data;
outputWord.keep = inputWord.keep;
outputWord.last = inputWord.last;
output.write(outputWord);
}
}
template <int WIDTH>
void convert_axis_to_net_axis(hls::stream<ap_axiu<WIDTH, 0, 0, 0> >& input,
hls::stream<net_axis<WIDTH> >& output)
{
#pragma HLS pipeline II=1
ap_axiu<WIDTH, 0, 0, 0> inputWord;
net_axis<WIDTH> outputWord;
if (!input.empty())
{
inputWord = input.read();
outputWord.data = inputWord.data;
outputWord.keep = inputWord.keep;
outputWord.last = inputWord.last;
output.write(outputWord);
}
}
#endif
template<int D>
ap_uint<D> reverse(const ap_uint<D>& w)
{
ap_uint<D> temp;
for (int i = 0; i < D/8; i++)
{
#pragma HLS UNROLL
temp(i*8+7, i*8) = w(D-(i*8)-1, D-(i*8)-8);
}
return temp;
}
template<int D>
ap_uint<D> reverse_bits(const ap_uint<D>& w)
{
ap_uint<D> temp;
for (int i = 0; i < D; i++)
{
#pragma HLS UNROLL
temp[i] = w[D-i-1];
}
return temp;
}
template<int D>
bool scan(std::istream& inputFile, ap_uint<D>& data)
{
uint16_t temp;
for (int i = 0; i < D/8; i++)
{
if (inputFile >> std::hex >> temp)
{
data(i*8+7, i*8) = temp;
}
else
{
//std::cerr << "[ERROR]: could not scan input" << std::endl;
return false;
}
}
return (bool) inputFile;
}
template<int D>
bool scan(std::istream& inputFile, net_axis<D>& word)
{
uint16_t temp;
uint32_t keepTemp;
uint16_t lastTemp;
for (int i = 0; i < D/8; i++)
{
if (inputFile >> std::hex >> temp)
{
word.data(i*8+7, i*8) = temp;
}
else
{
//std::cerr << "[ERROR]: could not scan input" << std::endl;
return false;
}
}
inputFile >> keepTemp;
inputFile >> lastTemp;
word.keep = keepTemp;
word.last = lastTemp;
//if (!inputFile)
// std::cerr << "[ERROR]: could not scan input" << std::endl;
return (bool) inputFile;
}
template<int D>
bool scanLE(std::istream& inputFile, ap_uint<D>& data)
{
uint16_t temp;
for (int i = (D/8)-1; i >= 0; i--)
{
if (inputFile >> std::hex >> temp)
{
data(i*8+7, i*8) = temp;
}
else
{
//std::cerr << "[ERROR]: could not scan input" << std::endl;
return false;
}
}
return (bool) inputFile;
}
template<int D>
bool scanLE(std::istream& inputFile, net_axis<D>& word)
{
uint16_t temp;
uint32_t keepTemp;
uint16_t lastTemp;
for (int i = (D/8)-1; i >= 0; i--)
{
if (inputFile >> std::hex >> temp)
{
word.data(i*8+7, i*8) = temp;
}
else
{
//std::cerr << "[ERROR]: could not scan input" << std::endl;
return false;
}
}
inputFile >> keepTemp;
inputFile >> lastTemp;
word.keep = keepTemp;
word.last = lastTemp;
return (bool) inputFile;
}
template<int D>
void print(std::ostream& output, ap_uint<D> data)
{
output << std::hex;
output << std::setfill('0');
for (int i = 0; i < D/8; i++)
{
output << std::noshowbase << std::setw(2) << (uint16_t) data(i*8+7, i*8) << " ";
}
}
template<int D>
void print(std::ostream& output, net_axis<D>& word)
{
#ifndef __SYNTHESIS__
output << std::hex;
output << std::setfill('0');
for (int i = 0; i < D/8; i++)
{
output << std::noshowbase << std::setw(2) << (uint16_t) word.data(i*8+7, i*8) << " ";
}
output << std::setw(D/8/4) << (uint64_t) word.keep << " ";
output << std::setw(1) << (uint16_t)word.last;
#endif
}
template<int D>
void printLE(std::ostream& output, ap_uint<D>& data)
{
#ifndef __SYNTHESIS__
output << std::hex;
output << std::setfill('0') ;
for (int i = (D/8)-1; i >= 0; i--)
{
output << std::noshowbase << std::setw(2) << (uint16_t) data(i*8+7, i*8) << " ";
}
#endif
}
template<int D>
void printLE(std::ostream& output, net_axis<D>& word)
{
#ifndef __SYNTHESIS__
output << std::hex;
output << std::setfill('0') ;
for (int i = (D/8)-1; i >= 0; i--)
{
output << std::noshowbase << std::setw(2) << (uint16_t) word.data(i*8+7, i*8) << " ";
}
output << std::setw(D/8/4) << (uint64_t) word.keep << " ";
output << std::setw(1) << (uint16_t)word.last;
#endif
}
template <int W, int D, int DUMMY>
void increaseStreamWidth(hls::stream<net_axis<W> >& input, hls::stream<net_axis<W*D> >&output)
{
#pragma HLS INLINE
static int count = 0;
static net_axis<W*D> temp;
if (!input.empty())
{
net_axis<W> currWord = input.read();
temp.data((W*count)+W-1, (W*count)) = currWord.data;
temp.keep(((W/8)*count+(W/8)-1), ((W/8)*count)) = currWord.keep;
temp.last = currWord.last;
count++;
if (currWord.last || count == D)
{
output.write(temp);
count = 0;
#ifndef __SYNTHESIS__
temp.data = 0;
#endif
temp.keep = 0;
}
}
}
template <int W, int D, int DUMMY>
void reduceStreamWidth(hls::stream<net_axis<W> >& input, hls::stream<net_axis<W/D> >&output)
{
#pragma HLS INLINE
enum fsmStateType {FIRST, SECOND};
static fsmStateType fsmState = FIRST;
static int count = 0;
static net_axis<W> currWord;
net_axis<W/D> temp;
switch (fsmState)
{
case FIRST:
if (!input.empty())
{
input.read(currWord);
temp.data = currWord.data((W/D)-1, 0);
temp.keep = currWord.keep(((W/D)/8)-1, 0);
temp.last = (currWord.keep[(W/8)/D] == 0); //(currWord.keep((W/8)-1, (W/8)/2) == 0);
output.write(temp);
if (currWord.keep[(W/8)/D])
{
count = 1;
fsmState = SECOND;
}
//shift word
currWord.data(W-(W/D)-1, 0) = currWord.data(W-1, W/D);
currWord.keep((W/8)-((W/8)/D)-1, 0) = currWord.keep((W/8)-1, (W/8)/D);
currWord.keep((W/8)-1, (W/8)-((W/8)/D)) = 0;
}
break;
case SECOND:
temp.data = currWord.data((W/D)-1, 0);
temp.keep = currWord.keep(((W/D)/8)-1, 0);
if (count < D-1)
{
temp.last = (currWord.keep[(W/8)/D] == 0); //(currWord.keep((W/8)-1, (W/8)/2) == 0);
}
else
{
temp.last = currWord.last;
}
output.write(temp);
//shift word
currWord.data(W-(W/D)-1, 0) = currWord.data(W-1, W/D);
currWord.keep((W/8)-((W/8)/D)-1, 0) = currWord.keep((W/8)-1, (W/8)/D);
currWord.keep((W/8)-1, (W/8)-((W/8)/D)) = 0;
count++;
if (count == D || temp.last)
{
fsmState = FIRST;
}
break;
}
}
template <int W, int DUMMY>
void convertStreamWidth(hls::stream<net_axis<W> >& input, hls::stream<net_axis<W> >&output)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
if (!input.empty())
{
output.write(input.read());
}
}
template <int W, int DUMMY>
void convertStreamWidth(hls::stream<net_axis<W> >& input, hls::stream<net_axis<W*2> >&output)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
increaseStreamWidth<W,2,DUMMY>(input, output);
}
template <int W, int DUMMY>
void convertStreamWidth(hls::stream<net_axis<W> >& input, hls::stream<net_axis<W*4> >&output)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
increaseStreamWidth<W,4,DUMMY>(input, output);
}
template <int W, int DUMMY>
void convertStreamWidth(hls::stream<net_axis<W> >& input, hls::stream<net_axis<W*8> >&output)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
increaseStreamWidth<W,8,DUMMY>(input, output);
}
template <int W, int DUMMY>
void convertStreamWidth(hls::stream<net_axis<W> >& input, hls::stream<net_axis<W/2> >&output)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
reduceStreamWidth<W,2,DUMMY>(input, output);
}
template <int W, int DUMMY>
void convertStreamWidth(hls::stream<net_axis<W> >& input, hls::stream<net_axis<W/4> >&output)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
reduceStreamWidth<W,4,DUMMY>(input, output);
}
template <int W, int DUMMY>
void convertStreamWidth(hls::stream<net_axis<W> >& input, hls::stream<net_axis<W/8> >&output)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
reduceStreamWidth<W,8,DUMMY>(input, output);
}
// The 2nd template parameter is a hack to use this function multiple times
template <typename T, int W, int whatever>
void rshiftWordByOctet( uint16_t offset,
hls::stream<T>& input,
hls::stream<T>& output)
{
#pragma HLS inline off
#pragma HLS pipeline II=1 //TODO this has a bug, the bug might come from how it is used
enum fsmStateType {PKG, REMAINDER};
static fsmStateType fsmState = PKG;
static bool rs_firstWord = (offset != 0);
static T prevWord;
T currWord;
T sendWord;
sendWord.last = 0;
switch (fsmState)
{
case PKG:
if (!input.empty())
{
input.read(currWord);
if (!rs_firstWord)
{
if (offset == 0)
{
sendWord = currWord;
}
else
{
sendWord.data((W-1)-(8*offset), 0) = prevWord.data((W-1), 8*offset);
sendWord.data((W-1), W-(8*offset)) = currWord.data((8*offset)-1, 0);
sendWord.keep((W/8-1)-offset, 0) = prevWord.keep((W/8-1), offset);
sendWord.keep((W/8-1), (W/8)-offset) = currWord.keep(offset-1, 0);
sendWord.last = (currWord.keep((W/8-1), offset) == 0);
//sendWord.dest = currWord.dest;
//assignDest(sendWord, currWord);
}//else offset
output.write(sendWord);
}
prevWord = currWord;
rs_firstWord = false;
if (currWord.last)
{
rs_firstWord = (offset != 0);
//rs_writeRemainder = (sendWord.last == 0);
if (!sendWord.last)
{
fsmState = REMAINDER;
}
}
//}//else offset
}
break;
case REMAINDER:
sendWord.data((W-1)-(8*offset), 0) = prevWord.data((W-1), 8*offset);
sendWord.data((W-1), W-(8*offset)) = 0;
sendWord.keep((W/8-1)-offset, 0) = prevWord.keep((W/8-1), offset);
sendWord.keep((W/8-1), (W/8)-offset) = 0;
sendWord.last = 1;
//sendWord.dest = prevWord.dest;
//assignDest(sendWord, currWord);
output.write(sendWord);
fsmState = PKG;
break;
}
}
// The 2nd template parameter is a hack to use this function multiple times
template <int W, int whatever>
void lshiftWordByOctet( uint16_t offset,
hls::stream<net_axis<W> >& input,
hls::stream<net_axis<W> >& output)
{
#pragma HLS inline off
#pragma HLS pipeline II=1
static bool ls_firstWord = true;
static bool ls_writeRemainder = false;
static net_axis<W> prevWord;
net_axis<W> currWord;
net_axis<W> sendWord;
//TODO use states
if (ls_writeRemainder)
{
sendWord.data((8*offset)-1, 0) = prevWord.data((W-1), W-(8*offset));
sendWord.data((W-1), (8*offset)) = 0;
sendWord.keep(offset-1, 0) = prevWord.keep((W/8-1), (W/8)-offset);
sendWord.keep((W/8-1), offset) = 0;
sendWord.last = 1;
output.write(sendWord);
ls_writeRemainder = false;
}
else if (!input.empty())
{
input.read(currWord);
if (offset == 0)
{
output.write(currWord);
}
else
{
if (ls_firstWord)
{
sendWord.data((8*offset)-1, 0) = 0;
sendWord.data((W-1), (8*offset)) = currWord.data((W-1)-(8*offset), 0);
sendWord.keep(offset-1, 0) = 0xFFFFFFFF;
sendWord.keep((W/8-1), offset) = currWord.keep((W/8-1)-offset, 0);
sendWord.last = (currWord.keep((W/8-1), (W/8)-offset) == 0);
}
else
{
sendWord.data((8*offset)-1, 0) = prevWord.data((W-1), W-(8*offset));
sendWord.data((W-1), (8*offset)) = currWord.data((W-1)-(8*offset), 0);
sendWord.keep(offset-1, 0) = prevWord.keep((W/8-1), (W/8)-offset);
sendWord.keep((W/8-1), offset) = currWord.keep((W/8-1)-offset, 0);
sendWord.last = (currWord.keep((W/8-1), (W/8)-offset) == 0);
}
output.write(sendWord);
prevWord = currWord;
ls_firstWord = false;
if (currWord.last)
{
ls_firstWord = true;
ls_writeRemainder = !sendWord.last;
}
} //else offset
}
}
//TODO move to utils
template <typename T>
void stream_merger(hls::stream<T>& in1, hls::stream<T>& in2, hls::stream<T>& out)
{
#pragma HLS PIPELINE II=1
#pragma HLS inline off
if (!in1.empty())
{
out.write(in1.read());
}
else if (!in2.empty())
{
out.write(in2.read());
}
}
template <typename T>
void stream_merger( hls::stream<ap_uint<1> >& originIn,
hls::stream<T>& input0,
hls::stream<T>& input1,
hls::stream<T>& output)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
enum stateType {IDLE, FWD0, FWD1};
static stateType state = IDLE;
T word;
ap_uint<1> origin;
switch (state)
{
case IDLE:
if (!originIn.empty())
{
originIn.read(origin);
if (origin == 0)
{
if (!input0.empty())
{
input0.read(word);
output.write(word);
}
else
{
state = FWD0;
}
}
else
{
if (!input1.empty())
{
input1.read(word);
output.write(word);
}
else
{
state = FWD1;
}
}
}
break;
case FWD0:
if (!input0.empty())
{
input0.read(word);
output.write(word);
state = IDLE;
}
break;
case FWD1:
if (!input1.empty())
{
input1.read(word);
output.write(word);
state = IDLE;
}
break;
}//switch
}
template <class T, int DUMMY>
void fair_merger(hls::stream<T>& in0, hls::stream<T>& in1, hls::stream<T>& out)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
static bool merge_pref = true;
if (merge_pref)
{
if (!in0.empty())
{
out.write(in0.read());
merge_pref = false;
}
else if(!in1.empty())
{
out.write(in1.read());
}
}
else
{
if(!in1.empty())
{
out.write(in1.read());
merge_pref = true;
}
else if (!in0.empty())
{
out.write(in0.read());
}
}
}
template <int W>
void fair_pkg_merger(hls::stream<net_axis<W> >& in0, hls::stream<net_axis<W> >& in1, hls::stream<net_axis<W> >& out)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
enum fpmStateType{IDLE, FWD0, FWD1};
static fpmStateType state = IDLE;
static bool merge_pref = true;
net_axis<W> currWord;
currWord.last = 0;
switch (state)
{
case IDLE:
if (merge_pref)
{
if (!in0.empty())
{
in0.read(currWord);
out.write(currWord);
state = FWD1;
}
else if(!in1.empty())
{
in1.read(currWord);
out.write(currWord);
state = FWD1;
}
}
else
{
if(!in1.empty())
{
in1.read(currWord);
out.write(currWord);
state = FWD1;
}
else if (!in0.empty())
{
in0.read(currWord);
out.write(currWord);
state = FWD0;
}
}
if (currWord.last)
{
state = IDLE;
}
break;
case FWD0:
if (!in0.empty())
{
in0.read(currWord);
out.write(currWord);
if (currWord.last)
{
merge_pref = false;
state = IDLE;
}
}
break;
case FWD1:
if (!in1.empty())
{
in1.read(currWord);
out.write(currWord);
if (currWord.last)
{
merge_pref = true;
state = IDLE;
}
}
break;
}//switch
}
template <int W>
void stream_pkg_merger( hls::stream<ap_uint<1> >& originIn,
hls::stream<net_axis<W> >& input0,
hls::stream<net_axis<W> >& input1,
hls::stream<net_axis<W> >& output)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
enum stateType {IDLE, FWD0, FWD1};
static stateType state = IDLE;
net_axis<W> currWord;
ap_uint<1> origin;
switch (state)
{
case IDLE:
if (!originIn.empty())
{
originIn.read(origin);
if (origin == 0)
{
if (!input0.empty())
{
input0.read(currWord);
output.write(currWord);
if (!currWord.last)
{
state = FWD0;
}
}
else
{
state = FWD0;
}
}
else
{
if (!input1.empty())
{
input1.read(currWord);
output.write(currWord);
if (!currWord.last)
{
state = FWD1;
}
}
else
{
state = FWD1;
}
}
}
break;
case FWD0:
if (!input0.empty())
{
input0.read(currWord);
output.write(currWord);
if (currWord.last)
{
state = IDLE;
}
}
break;
case FWD1:
if (!input1.empty())
{
input1.read(currWord);
output.write(currWord);
if (currWord.last)
{
state = IDLE;
}
}
break;
}//switch
}
template <int W>
void stream_pkg_splitter( hls::stream<ap_uint<1> >& destIn,
hls::stream<net_axis<W> >& input,
hls::stream<net_axis<W> >& output0,
hls::stream<net_axis<W> >& output1)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
enum stateType {IDLE, FWD0, FWD1};
static stateType state = IDLE;
net_axis<W> currWord;
ap_uint<1> dest;
switch (state)
{
case IDLE:
if (!destIn.empty())
{
destIn.read(dest);
state = (dest == 0) ? FWD0 : FWD1;
if (!input.empty())
{
input.read(currWord);
if (dest == 0)
{
output0.write(currWord);
}
else
{
output1.write(currWord);
}
if (currWord.last)
{
state = IDLE;
}
}
}
break;
case FWD0:
if (!input.empty())
{
input.read(currWord);
output0.write(currWord);
if (currWord.last)
{
state = IDLE;
}
}
break;
case FWD1:
if (!input.empty())
{
input.read(currWord);
output1.write(currWord);
if (currWord.last)
{
state = IDLE;
}
}
break;
}//switch
}
template <int W>
void pass_valid_pkg(hls::stream<bool>& pkgValidIn,
hls::stream<net_axis<W> >& input,
hls::stream<net_axis<W> >& output)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
enum fsmStateType {VALID, FWD, DROP};
static fsmStateType state = VALID;
switch (state)
{
case VALID:
if (!pkgValidIn.empty() && !input.empty())
{
bool valid = pkgValidIn.read();
net_axis<W> word = input.read();
if (valid)
{
output.write(word);
if (!word.last)
{
state = FWD;
}
}
else
{
if (!word.last)
{
state = DROP;
}
}
}
break;
case FWD:
if (!input.empty())
{
net_axis<W> word = input.read();
output.write(word);
if (word.last)
{
state = VALID;
}
}
break;
case DROP:
if (!input.empty())
{
net_axis<W> word = input.read();
if (word.last)
{
state = VALID;
}
}
break;
} //switch
}
template <class T>
void toe_duplicate_stream( hls::stream<T>& in,
hls::stream<T>& out0,
hls::stream<T>& out1)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
if (!in.empty())
{
T item = in.read();
out0.write(item);
out1.write(item);
}
}
template <class T>
void ip_handler_duplicate_stream( hls::stream<T>& in,
hls::stream<T>& out0,
hls::stream<T>& out1)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE off
if (!in.empty())
{
T item = in.read();
out0.write(item);
out1.write(item);
}
}
ap_uint<64> lenToKeep(ap_uint<6> length);
ap_uint<8> keepToLen(ap_uint<64> keepValue);
template<int WIDTH>
net_axis<WIDTH> alignWords(ap_uint<6> offset, net_axis<WIDTH> prevWord, net_axis<WIDTH> currWord)
{
net_axis<WIDTH> alignedWord;
alignedWord.data(WIDTH-1, WIDTH - (offset*8)) = currWord.data(offset*8-1, 0);
alignedWord.keep(WIDTH/8-1, WIDTH/8 - offset) = currWord.keep(offset - 1, 0);
alignedWord.data(WIDTH - (offset*8) -1, 0) = prevWord.data(WIDTH-1, offset*8);
alignedWord.keep(WIDTH/8 - offset - 1, 0) = prevWord.keep(WIDTH/8-1, offset);
//alignedWord.last = (currWord.keep[offset] == 0);
return alignedWord;
}
// SOLUTION NEEDED --------------------------------------------------------------------------------------------------------------------------------------------------
// The 2nd template parameter is a hack to use this function multiple times
template <int W, int whatever>
void udp_lshiftWordByOctet( uint16_t offset,
hls::stream<net_axis<W> >& input,
hls::stream<net_axis<W> >& output)
{
#pragma HLS inline off
#pragma HLS pipeline II=1
static bool ls_firstWord = true;
static bool ls_writeRemainder = false;
static net_axis<W> prevWord;
net_axis<W> currWord;
net_axis<W> sendWord;
//TODO use states
if (ls_writeRemainder)
{
sendWord.data((8*offset)-1, 0) = prevWord.data((W-1), W-(8*offset));
sendWord.data((W-1), (8*offset)) = 0;
sendWord.keep(offset-1, 0) = prevWord.keep((W/8-1), (W/8)-offset);
sendWord.keep((W/8-1), offset) = 0;
sendWord.last = 1;
output.write(sendWord);
ls_writeRemainder = false;
}
else if (!input.empty())
{
input.read(currWord);
if (offset == 0)
{
output.write(currWord);
}
else
{
if (ls_firstWord)
{
sendWord.data((8*offset)-1, 0) = 0;
sendWord.data((W-1), (8*offset)) = currWord.data((W-1)-(8*offset), 0);
sendWord.keep(offset-1, 0) = 0xFFFFFFFF;
sendWord.keep((W/8-1), offset) = currWord.keep((W/8-1)-offset, 0);
sendWord.last = (currWord.keep((W/8-1), (W/8)-offset) == 0);
}
else
{
sendWord.data((8*offset)-1, 0) = prevWord.data((W-1), W-(8*offset));
sendWord.data((W-1), (8*offset)) = currWord.data((W-1)-(8*offset), 0);
sendWord.keep(offset-1, 0) = prevWord.keep((W/8-1), (W/8)-offset);
sendWord.keep((W/8-1), offset) = currWord.keep((W/8-1)-offset, 0);
sendWord.last = (currWord.keep((W/8-1), (W/8)-offset) == 0);
}
output.write(sendWord);
prevWord = currWord;
ls_firstWord = false;
if (currWord.last)
{
ls_firstWord = true;
ls_writeRemainder = !sendWord.last;
}
} //else offset
}
}
// The 2nd template parameter is a hack to use this function multiple times
template <int W, int whatever>
void mac_lshiftWordByOctet( uint16_t offset,
hls::stream<net_axis<W> >& input,
hls::stream<net_axis<W> >& output)
{
#pragma HLS inline off
#pragma HLS pipeline II=1
static bool ls_firstWord = true;
static bool ls_writeRemainder = false;
static net_axis<W> prevWord;
net_axis<W> currWord;
net_axis<W> sendWord;
//TODO use states
if (ls_writeRemainder)
{
sendWord.data((8*offset)-1, 0) = prevWord.data((W-1), W-(8*offset));
sendWord.data((W-1), (8*offset)) = 0;
sendWord.keep(offset-1, 0) = prevWord.keep((W/8-1), (W/8)-offset);
sendWord.keep((W/8-1), offset) = 0;
sendWord.last = 1;
output.write(sendWord);
ls_writeRemainder = false;
}
else if (!input.empty())
{
input.read(currWord);
if (offset == 0)
{
output.write(currWord);
}
else
{
if (ls_firstWord)
{
sendWord.data((8*offset)-1, 0) = 0;
sendWord.data((W-1), (8*offset)) = currWord.data((W-1)-(8*offset), 0);
sendWord.keep(offset-1, 0) = 0xFFFFFFFF;
sendWord.keep((W/8-1), offset) = currWord.keep((W/8-1)-offset, 0);
sendWord.last = (currWord.keep((W/8-1), (W/8)-offset) == 0);
}
else
{
sendWord.data((8*offset)-1, 0) = prevWord.data((W-1), W-(8*offset));
sendWord.data((W-1), (8*offset)) = currWord.data((W-1)-(8*offset), 0);
sendWord.keep(offset-1, 0) = prevWord.keep((W/8-1), (W/8)-offset);
sendWord.keep((W/8-1), offset) = currWord.keep((W/8-1)-offset, 0);
sendWord.last = (currWord.keep((W/8-1), (W/8)-offset) == 0);
}
output.write(sendWord);
prevWord = currWord;
ls_firstWord = false;
if (currWord.last)
{
ls_firstWord = true;
ls_writeRemainder = !sendWord.last;
}
} //else offset
}
}
// The 2nd template parameter is a hack to use this function multiple times
template <int W, int whatever>
void ipv4_lshiftWordByOctet( uint16_t offset,
hls::stream<net_axis<W> >& input,
hls::stream<net_axis<W> >& output)
{
#pragma HLS inline off
#pragma HLS pipeline II=1
static bool ls_firstWord = true;
static bool ls_writeRemainder = false;
static net_axis<W> prevWord;
net_axis<W> currWord;
net_axis<W> sendWord;
//TODO use states
if (ls_writeRemainder)
{
sendWord.data((8*offset)-1, 0) = prevWord.data((W-1), W-(8*offset));
sendWord.data((W-1), (8*offset)) = 0;
sendWord.keep(offset-1, 0) = prevWord.keep((W/8-1), (W/8)-offset);
sendWord.keep((W/8-1), offset) = 0;
sendWord.last = 1;
output.write(sendWord);
ls_writeRemainder = false;
}
else if (!input.empty())
{
input.read(currWord);
if (offset == 0)
{
output.write(currWord);
}
else
{
if (ls_firstWord)
{
sendWord.data((8*offset)-1, 0) = 0;
sendWord.data((W-1), (8*offset)) = currWord.data((W-1)-(8*offset), 0);
sendWord.keep(offset-1, 0) = 0xFFFFFFFF;
sendWord.keep((W/8-1), offset) = currWord.keep((W/8-1)-offset, 0);
sendWord.last = (currWord.keep((W/8-1), (W/8)-offset) == 0);
}
else
{
sendWord.data((8*offset)-1, 0) = prevWord.data((W-1), W-(8*offset));
sendWord.data((W-1), (8*offset)) = currWord.data((W-1)-(8*offset), 0);
sendWord.keep(offset-1, 0) = prevWord.keep((W/8-1), (W/8)-offset);
sendWord.keep((W/8-1), offset) = currWord.keep((W/8-1)-offset, 0);
sendWord.last = (currWord.keep((W/8-1), (W/8)-offset) == 0);
}
output.write(sendWord);
prevWord = currWord;
ls_firstWord = false;
if (currWord.last)
{
ls_firstWord = true;
ls_writeRemainder = !sendWord.last;
}
} //else offset
}
}
// The 2nd template parameter is a hack to use this function multiple times
template <typename T, int W, int whatever>
void ip_handler_rshiftWordByOctet( uint16_t offset,
hls::stream<T>& input,
hls::stream<T>& output)
{
#pragma HLS inline off
#pragma HLS pipeline II=1 //TODO this has a bug, the bug might come from how it is used
enum fsmStateType {PKG, REMAINDER};
static fsmStateType fsmState = PKG;
static bool rs_firstWord = (offset != 0);
static T prevWord;
T currWord;
T sendWord;
sendWord.last = 0;
switch (fsmState)
{
case PKG:
if (!input.empty())
{
input.read(currWord);
if (!rs_firstWord)
{
if (offset == 0)
{
sendWord = currWord;
}
else
{
sendWord.data((W-1)-(8*offset), 0) = prevWord.data((W-1), 8*offset);
sendWord.data((W-1), W-(8*offset)) = currWord.data((8*offset)-1, 0);
sendWord.keep((W/8-1)-offset, 0) = prevWord.keep((W/8-1), offset);
sendWord.keep((W/8-1), (W/8)-offset) = currWord.keep(offset-1, 0);
sendWord.last = (currWord.keep((W/8-1), offset) == 0);
//sendWord.dest = currWord.dest;
//assignDest(sendWord, currWord);
}//else offset
output.write(sendWord);
}
prevWord = currWord;
rs_firstWord = false;
if (currWord.last)
{
rs_firstWord = (offset != 0);
//rs_writeRemainder = (sendWord.last == 0);
if (!sendWord.last)
{
fsmState = REMAINDER;
}
}
//}//else offset
}
break;
case REMAINDER:
sendWord.data((W-1)-(8*offset), 0) = prevWord.data((W-1), 8*offset);
sendWord.data((W-1), W-(8*offset)) = 0;
sendWord.keep((W/8-1)-offset, 0) = prevWord.keep((W/8-1), offset);
sendWord.keep((W/8-1), (W/8)-offset) = 0;
sendWord.last = 1;
//sendWord.dest = prevWord.dest;
//assignDest(sendWord, currWord);
output.write(sendWord);
fsmState = PKG;
break;
}
}
// The 2nd template parameter is a hack to use this function multiple times
template <typename T, int W, int whatever>
void udp_rshiftWordByOctet( uint16_t offset,
hls::stream<T>& input,
hls::stream<T>& output)
{
#pragma HLS inline off
#pragma HLS pipeline II=1 //TODO this has a bug, the bug might come from how it is used
enum fsmStateType {PKG, REMAINDER};
static fsmStateType fsmState = PKG;
static bool rs_firstWord = (offset != 0);
static T prevWord;
T currWord;
T sendWord;
sendWord.last = 0;
switch (fsmState)
{
case PKG:
if (!input.empty())
{
input.read(currWord);
if (!rs_firstWord)
{
if (offset == 0)
{
sendWord = currWord;
}
else
{
sendWord.data((W-1)-(8*offset), 0) = prevWord.data((W-1), 8*offset);
sendWord.data((W-1), W-(8*offset)) = currWord.data((8*offset)-1, 0);
sendWord.keep((W/8-1)-offset, 0) = prevWord.keep((W/8-1), offset);
sendWord.keep((W/8-1), (W/8)-offset) = currWord.keep(offset-1, 0);
sendWord.last = (currWord.keep((W/8-1), offset) == 0);
//sendWord.dest = currWord.dest;
//assignDest(sendWord, currWord);
}//else offset
output.write(sendWord);
}
prevWord = currWord;
rs_firstWord = false;
if (currWord.last)
{
rs_firstWord = (offset != 0);
//rs_writeRemainder = (sendWord.last == 0);
if (!sendWord.last)
{
fsmState = REMAINDER;
}
}
//}//else offset
}
break;
case REMAINDER:
sendWord.data((W-1)-(8*offset), 0) = prevWord.data((W-1), 8*offset);
sendWord.data((W-1), W-(8*offset)) = 0;
sendWord.keep((W/8-1)-offset, 0) = prevWord.keep((W/8-1), offset);
sendWord.keep((W/8-1), (W/8)-offset) = 0;
sendWord.last = 1;
//sendWord.dest = prevWord.dest;
//assignDest(sendWord, currWord);
output.write(sendWord);
fsmState = PKG;
break;
}
}