Vivado HLS is a handy(?) high-level synthesis (HLS) tool that supports C++11 features. However, its C-RTL co-simulation (cosim) is broken in the sense that it doesn’t fully support C++11. The cosim compiler seems to be stuck at g++
4.6.3 forever. This makes it impossible to make fancy stuff like Google Test work as part of the testbench with the cosim compiler.
Let’s recap the situation:
- We are talking about the Linux toolchains.
- The cosim framework is designed to be started via a TCL command and it is hard to invoke it manually.
- The cosim framework requires that the testbench contains a main function so you cannot make the cosim executable a library and link it with other programs.
- The cosim compiler is a customized version of
g++
4.6.3 and cannot be upgraded or replaced. Note that althoughclang++
is provided as an alternative, it never worked for me. - Although some ldflags work, I never got the cosim compiler correctly link a library against the source code.
山重水复疑无路,柳暗花明又一村。————陆游
When there’s a will, there’s a way — the ABI is still compatible, isn’t it? You can compile whatever program with whichever compiler, as long as it can be loaded as a shared object by the cosim executable. So the idea is clear:
- Compile the fancy part of the code into a shared object with whichever compiler you want (just keep the ABI compatible). To create a shared object with
g++
orclang++
, add-fPIC
when compiling and add-shared
when linking. - Make the cosim executable load the shared object at runtime. This can be done with something like this
#include <dlfcn.h> // This function pointer will be used to invoke the function in the shared object. void (*entry_function)(); void* handle = dlopen("foo.so", RTLD_LAZY); if (handle == nullptr) { clog << dlerror() << endl; exit(EXIT_FAILURE); } entry_function = reinterpret_cast<void(*)()>(dlsym(handle, "EntryFunction")); char *error; if ((error = dlerror()) != nullptr) { clog << dlerror() << endl; exit(EXIT_FAILURE); } (*entry_function)(); // Don't dlclose(handle) or cosim won't work.</void(*)()></dlfcn.h>
- If the function invoked in the shared object needs to invoke the hardware module, put the top-level function in a wrapper instead of invoking it directly. This is because cosim is actually doing a source-to-source transformation to the testbench and invoking a top-level module directly will only run C simulation. Note that you need to export the symbols in the testbench by adding
-Wl,--export-dynamic
to theldflags
of thecosim_design
TCL command to invoke functions in the testbench from the shared object. - Compile the antique part of the code with the cosim compiler. Add
-ldl
to theldflags
of thecosim_design
TCL command to enable dynamic library loading.
I managed to get cosim working with Google Test!
References