19 std::ostringstream cpp;
21 const auto & function_name =
27 JLM_ASSERT(mem_reqs.size() == mem_resps.size());
42 #include <verilated.h>
47 #include <verilated_fst_c.h>
49 #include <verilated_vcd_c.h>
55 #include "verilator_sim.h"
57 std::unique_ptr<mm_magic_t> memories[)"
58 << mem_reqs.size() << R"(];
59 // ======== Entry point for calling kernel from host device (C code) ========
61 << c_return_type.value_or("void") <<
" " << function_name <<
"(" << c_params <<
")" << R
"(
63 // initialize memories before verilator
64 master = std::make_unique<mmio_t>(CTRL_BEAT_BYTES);)"
67 for (
size_t i = 0; i < kernel.GetOperation().
type().Arguments().size(); ++i)
69 if (rvsdg::is<llvm::PointerType>(*kernel.GetOperation().type().Arguments()[i].get()))
71 const auto res_bundle = util::assertedCast<const BundleType>(mem_resps[m]->
Type().get());
72 auto size =
JlmSize(&*res_bundle->get_element_type(
"data")) / 8;
73 cpp <<
" memories[" << m <<
"] = std::make_unique<mm_magic_t>();" << std::endl;
74 cpp <<
" memories[" << m <<
"]->init((uint8_t *) a" << i <<
", 1UL << 31, " << size
75 <<
", 64, MEMORY_LATENCY);" << std::endl;
81 verilator_init(0, nullptr);
85 // initialize struct with control addresses
86 RHLSAXI_substruct_create
87 // wait for accelerator to be ready
88 while (!read(RHLSAXI_substruct->ready));
90 // use relative addressing for now - i.e. skip pointer arguments
93 for (
size_t i = 0; i < num_c_params; ++i)
95 auto type = kernel.GetOperation().type().Arguments()[i].get();
96 if (!rvsdg::is<llvm::PointerType>(*
type))
99 cpp <<
" write(RHLSAXI_substruct->i_data_" << i <<
", a" << i <<
");" << std::endl;
105 // start the accelerator
106 write(RHLSAXI_substruct->start, 1);
107 size_t start_cycles = get_cycles();
109 // wait for computation to be done
110 while (!read(RHLSAXI_substruct->done));
111 size_t end_cycles = get_cycles();
113 if (c_return_type.has_value())
114 cpp <<
"auto result = read(RHLSAXI_substruct->o_data_0);" << std::endl;
116 std::cerr << "Accelerator took " << end_cycles - start_cycles << " cycles" << std::endl;
117 write(RHLSAXI_substruct->finish, 1);
119 if (c_return_type.has_value())
120 cpp <<
"return *(" << c_return_type.value() <<
"*)&result;" << std::endl;
124 extern "C" void reference_load(void *addr, uint64_t width) {
127 extern "C" void reference_store(void *addr, uint64_t width) {
130 extern uint64_t main_time;
131 uint64_t clock_cycles = 0;
132 extern std::unique_ptr<mmio_t> master;
136 extern VerilatedFstC *tfp;
138 extern VerilatedVcdC *tfp;
143 assert(m = dynamic_cast<mmio_t *>(master.get()));
145 // ASSUMPTION: All models have *no* combinational paths through I/O
146 // Step 1: Clock lo -> propagate signals between DUT and software models
147 AXI_LITE_SLAVE_CONNECT_VERILATOR_POS(top, io_s_ctrl, m, CTRL_BEAT_BYTES)
150 size_t m_read = 0, m_write = 0;
151 for (
size_t i = 0; i < mem_reqs.size(); i++)
153 const auto req_bundle = util::assertedCast<const BundleType>(mem_reqs[i]->
Type().get());
154 const auto res_bundle = util::assertedCast<const BundleType>(mem_resps[i]->
Type().get());
155 auto size =
JlmSize(&*res_bundle->get_element_type(
"data")) / 8;
156 const auto has_write = req_bundle->get_element_type(
"write") !=
nullptr;
159 cpp <<
" AXI_FULL_MM_CONNECT_VERILATOR_POS(top, io_m_write_" << m_write++ <<
", memories["
160 << i <<
"], " << size <<
")" << std::endl;
164 cpp <<
" AXI_FULL_READ_ONLY_MM_CONNECT_VERILATOR_POS(top, io_m_read_" << m_read++
165 <<
", memories[" << i <<
"], " << size <<
")" << std::endl;
172 tfp->dump((double)main_time);
180 top->eval(); // This shouldn't do much
183 tfp->dump((double)main_time);
190 // Step 2: Clock high, tick all software models and evaluate DUT with posedge
191 AXI_LITE_SLAVE_CONNECT_VERILATOR_POS_EDGE(top, io_s_ctrl, m)
196 for (
size_t i = 0; i < mem_reqs.size(); i++)
198 const auto bundle = util::assertedCast<const BundleType>(mem_reqs[i]->
Type().get());
199 const auto has_write = bundle->get_element_type(
"write") !=
nullptr;
202 cpp <<
" AXI_FULL_MM_CONNECT_VERILATOR_POS_EDGE(top, io_m_write_" << m_write++
203 <<
", memories[" << i <<
"])" << std::endl;
207 cpp <<
" AXI_FULL_READ_ONLY_MM_CONNECT_VERILATOR_POS_EDGE(top, io_m_read_" << m_read++
208 <<
", memories[" << i <<
"])" << std::endl;
std::vector< rvsdg::RegionArgument * > get_reg_args(const rvsdg::LambdaNode &lambda)
std::vector< rvsdg::RegionResult * > get_mem_reqs(const rvsdg::LambdaNode &lambda)
static int JlmSize(const jlm::rvsdg::Type *type)
const rvsdg::LambdaNode * get_hls_lambda(llvm::LlvmRvsdgModule &rm)
std::vector< rvsdg::RegionArgument * > get_mem_resps(const rvsdg::LambdaNode &lambda)
std::string GetText(llvm::LlvmRvsdgModule &rm) override
std::tuple< size_t, std::string, std::string > GetParameterListAsC(const rvsdg::LambdaNode &kernel)
std::optional< std::string > GetReturnTypeAsC(const rvsdg::LambdaNode &kernel)
static std::string type(const Node *n)