Add option to control interface and block level protocol

- Fix converters when type is signed
- Force interface type as pragma as TCL directives on template is nearly
  impossible.
This commit is contained in:
anonymous 2022-06-15 17:00:12 +02:00
parent d26348c6ff
commit 0d6f4fc08c
Signed by: moniere
GPG key ID: 188DD5B072181C0F
7 changed files with 172 additions and 10 deletions

View file

@ -69,12 +69,64 @@ option (PEDANTIC "use -Wall and -pedantic." ON)
# Parameters
# ##################################################################################################
set (
PRM_ITF_BLK
"ap_ctrl_chain"
CACHE STRING "Block-level interface protocol."
)
set_property (
CACHE PRM_ITF_BLK
PROPERTY STRINGS
"ap_ctrl_none"
"ap_ctrl_hs"
"ap_ctrl_chain"
)
set (ITF_BLK ${PRM_ITF_BLK})
set (
PRM_ITF_IN
"axis"
CACHE STRING "Input stream interface protocol."
)
set_property (
CACHE PRM_ITF_IN
PROPERTY STRINGS
"ap_hs"
"ap_fifo"
"axis"
)
set (ITF_IN ${PRM_ITF_IN})
set (
PRM_ITF_OUT
"axis"
CACHE STRING "Output stream interface protocol."
)
set_property (
CACHE PRM_ITF_OUT
PROPERTY STRINGS
"ap_hs"
"ap_fifo"
"axis"
)
set (ITF_OUT ${PRM_ITF_OUT})
set (
PRM_TYPE
"uint32_t"
CACHE STRING "Type to convert to/from."
)
set (TYPE ${PRM_TYPE})
set (
PRM_SIGNED
OFF
CACHE BOOL "If Type is signed or not."
)
if (PRM_SIGNED)
set (SIGNED "true")
else ()
set (SIGNED "false")
endif ()
set (
PRM_STRMLEN

View file

@ -108,7 +108,9 @@ if { [ file exists "directives.tcl" ] } {
source "directives.tcl"
}
set_directive_interface -mode ap_ctrl_none ${TYPE}_${STRMLEN}_${ENDIAN}_from_bytes
# set_directive_interface -mode @ITF_BLK@ ${TYPE}_${STRMLEN}_${ENDIAN}_from_bytes
# set_directive_interface -mode @ITF_IN@ ${TYPE}_${STRMLEN}_${ENDIAN}_from_bytes strm_in
# set_directive_interface -mode @ITF_OUT@ ${TYPE}_${STRMLEN}_${ENDIAN}_from_bytes strm_out
csim_design -clean -O -argv "${NLINES}"
csynth_design

View file

@ -108,7 +108,9 @@ if { [ file exists "directives.tcl" ] } {
source "directives.tcl"
}
set_directive_interface -mode ap_ctrl_none ${TYPE}_${STRMLEN}_${ENDIAN}_to_bytes
# set_directive_interface -mode @ITF_BLK@ ${TYPE}_${STRMLEN}_${ENDIAN}_to_bytes
# set_directive_interface -mode @ITF_IN@ ${TYPE}_${STRMLEN}_${ENDIAN}_from_bytes strm_in
# set_directive_interface -mode @ITF_OUT@ ${TYPE}_${STRMLEN}_${ENDIAN}_from_bytes strm_out
csim_design -clean -O -argv "${NLINES}"
csynth_design

View file

@ -41,11 +41,11 @@
#include <cstdint>
#include <hls_stream.h>
template <uint32_t stream_len = 1, bool LittleEndian = true>
template <uint32_t stream_len = 1, bool LittleEndian = true, bool use_sign = false>
class CConverterFromBytes;
template <uint32_t stream_len>
class CConverterFromBytes<stream_len, true> {
class CConverterFromBytes<stream_len, true, false> {
public:
template <typename T, uint32_t sizeofT = sizeof(T)>
static void process(hls::stream<uint8_t> & strm_in, hls::stream<T> & strm_out) {
@ -69,7 +69,7 @@ public:
};
template <uint32_t stream_len>
class CConverterFromBytes<stream_len, false> {
class CConverterFromBytes<stream_len, false, false> {
public:
template <typename T, uint32_t sizeofT = sizeof(T)>
static void process(hls::stream<uint8_t> & strm_in, hls::stream<T> & strm_out) {
@ -92,4 +92,52 @@ public:
}
};
template <uint32_t stream_len>
class CConverterFromBytes<stream_len, true, true> {
public:
template <typename T, uint32_t sizeofT = sizeof(T)>
static void process(hls::stream<uint8_t> & strm_in, hls::stream<T> & strm_out) {
#if !defined(XILINX_MAJOR)
static_assert(std::numeric_limits<T>::is_integer, "T must be an integer C-type.");
static_assert(std::is_signed<T>(), "T must be a signed type.");
#endif
LOOP_STR_B2T_LE:
for (uint32_t u = 0; u < stream_len; u++) {
ap_int<sizeofT * 8> word_buffer = 0;
LOOP_BYTE_B2T_LE:
for (uint32_t v = 0; v < sizeofT; v++) {
const ap_uint<8> byte_buffer = strm_in.read();
word_buffer >>= 8;
word_buffer(sizeofT * 8 - 1, (sizeofT - 1) * 8) = byte_buffer.range();
}
strm_out.write(word_buffer);
}
}
};
template <uint32_t stream_len>
class CConverterFromBytes<stream_len, false, true> {
public:
template <typename T, uint32_t sizeofT = sizeof(T)>
static void process(hls::stream<uint8_t> & strm_in, hls::stream<T> & strm_out) {
#if !defined(XILINX_MAJOR)
static_assert(std::numeric_limits<T>::is_integer, "T must be an integer C-type.");
static_assert(std::is_signed<T>(), "T must be an signed type.");
#endif
LOOP_STR_B2T_BE:
for (uint32_t u = 0; u < stream_len; u++) {
ap_int<sizeofT * 8> word_buffer = 0;
LOOP_BYTE_B2T_BE:
for (uint32_t v = 0; v < sizeofT; v++) {
const ap_uint<8> byte_buffer = strm_in.read();
word_buffer <<= 8;
word_buffer(7, 0) = byte_buffer.range();
}
strm_out.write(word_buffer);
}
}
};
#endif // _CONVERTER_FROM_BYTES_HPP_

View file

@ -41,11 +41,11 @@
#include <cstdint>
#include <hls_stream.h>
template <uint32_t stream_len = 1, bool LittleEndian = true>
template <uint32_t stream_len = 1, bool LittleEndian = true, bool use_sign = false>
class CConverterToBytes;
template <uint32_t stream_len>
class CConverterToBytes<stream_len, true> {
class CConverterToBytes<stream_len, true, false> {
public:
template <typename T, uint32_t sizeofT = sizeof(T)>
static void process(hls::stream<T> & strm_in, hls::stream<uint8_t> & strm_out) {
@ -68,7 +68,7 @@ public:
};
template <uint32_t stream_len>
class CConverterToBytes<stream_len, false> {
class CConverterToBytes<stream_len, false, false> {
public:
template <typename T, uint32_t sizeofT = sizeof(T)>
static void process(hls::stream<T> & strm_in, hls::stream<uint8_t> & strm_out) {
@ -90,4 +90,52 @@ public:
}
};
// SIGNED
template <uint32_t stream_len>
class CConverterToBytes<stream_len, true, true> {
public:
template <typename T, uint32_t sizeofT = sizeof(T)>
static void process(hls::stream<T> & strm_in, hls::stream<uint8_t> & strm_out) {
#if !defined(XILINX_MAJOR)
static_assert(std::numeric_limits<T>::is_integer, "T must be an integer C-type.");
static_assert(std::is_signed<T>(), "T must be an signed type.");
#endif
LOOP_STR_T2B_LE:
for (uint32_t u = 0; u < stream_len; u++) {
ap_int<sizeofT * 8> word_buffer = strm_in.read();
LOOP_BYTE_T2B_LE:
for (uint32_t v = 0; v < sizeofT; v++) {
const ap_uint<8> byte_buffer = word_buffer(7, 0);
strm_out.write(byte_buffer);
word_buffer >>= 8;
}
}
}
};
template <uint32_t stream_len>
class CConverterToBytes<stream_len, false, true> {
public:
template <typename T, uint32_t sizeofT = sizeof(T)>
static void process(hls::stream<T> & strm_in, hls::stream<uint8_t> & strm_out) {
#if !defined(XILINX_MAJOR)
static_assert(std::numeric_limits<T>::is_integer, "T must be an integer C-type.");
static_assert(std::is_signed<T>(), "T must be an signed type.");
#endif
LOOP_STR_T2B_BE:
for (uint32_t u = 0; u < stream_len; u++) {
ap_int<sizeofT * 8> word_buffer = strm_in.read();
LOOP_BYTE_T2B_BE:
for (uint32_t v = 0; v < sizeofT; v++) {
const ap_uint<8> byte_buffer = word_buffer(sizeofT * 8 - 1, (sizeofT - 1) * 8);
strm_out.write(byte_buffer);
word_buffer <<= 8;
}
}
}
};
#endif // _CONVERTER_TO_BYTES_HPP_

View file

@ -37,5 +37,10 @@
#include "top_converters/@TYPE@_@STRMLEN@_@ENDIAN@_from_bytes.hpp"
void @TYPE@_@STRMLEN@_@ENDIAN@_from_bytes(hls::stream<uint8_t> & strm_in, hls::stream<@TYPE@> & strm_out) {
CConverterFromBytes<@STRMLEN@, @ENDIAN@>::process(strm_in, strm_out);
// clang-foramt off
#pragma HLS interface @ITF_BLK@ port=return
#pragma HLS interface @ITF_IN@ port=strm_in
#pragma HLS interface @ITF_OUT@ port=strm_out
// clang-foramt on
CConverterFromBytes<@STRMLEN@, @ENDIAN@, @SIGNED@>::process(strm_in, strm_out);
}

View file

@ -37,5 +37,10 @@
#include "top_converters/@TYPE@_@STRMLEN@_@ENDIAN@_to_bytes.hpp"
void @TYPE@_@STRMLEN@_@ENDIAN@_to_bytes(hls::stream<@TYPE@> & strm_in, hls::stream<uint8_t> & strm_out) {
CConverterToBytes<@STRMLEN@, @ENDIAN@>::process(strm_in, strm_out);
// clang-foramt off
#pragma HLS interface @ITF_BLK@ port=return
#pragma HLS interface @ITF_IN@ port=strm_in
#pragma HLS interface @ITF_OUT@ port=strm_out
// clang-foramt on
CConverterToBytes<@STRMLEN@, @ENDIAN@, @SIGNED@>::process(strm_in, strm_out);
}