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 if (m < mem_reqs.size())
73 const auto res_bundle = util::assertedCast<const BundleType>(mem_resps[m]->
Type().get());
74 auto size =
JlmSize(&*res_bundle->get_element_type(
"data")) / 8;
75 cpp <<
" memories[" << m <<
"] = std::make_unique<mm_magic_t>();" << std::endl;
76 cpp <<
" memories[" << m <<
"]->init((uint8_t *) a" << i <<
", 1UL << 31, " << size
77 <<
", 64, MEMORY_LATENCY);" << std::endl;
84 verilator_init(0, nullptr);
88 // initialize struct with control addresses
89 RHLSAXI_substruct_create
90 // wait for accelerator to be ready
91 while (!read(RHLSAXI_substruct->ready));
93 // use relative addressing for now - i.e. skip pointer arguments
96 for (
size_t i = 0; i < num_c_params; ++i)
98 auto type = kernel.GetOperation().type().Arguments()[i].get();
99 if (!rvsdg::is<llvm::PointerType>(*type))
102 cpp <<
" write(RHLSAXI_substruct->i_data_" << i <<
", a" << i <<
");" << std::endl;
108 // start the accelerator
109 write(RHLSAXI_substruct->start, 1);
110 size_t start_cycles = get_cycles();
112 // wait for computation to be done
113 while (!read(RHLSAXI_substruct->done));
114 size_t end_cycles = get_cycles();
116 if (c_return_type.has_value())
117 cpp <<
"auto result = read(RHLSAXI_substruct->o_data_0);" << std::endl;
119 std::cerr << "Accelerator took " << end_cycles - start_cycles << " cycles" << std::endl;
120 write(RHLSAXI_substruct->finish, 1);
122 if (c_return_type.has_value())
123 cpp <<
"return *(" << c_return_type.value() <<
"*)&result;" << std::endl;
127 extern "C" void reference_load(void *addr, uint64_t width) {
130 extern "C" void reference_store(void *addr, uint64_t width) {
133 extern uint64_t main_time;
134 uint64_t clock_cycles = 0;
135 extern std::unique_ptr<mmio_t> master;
139 extern VerilatedFstC *tfp;
141 extern VerilatedVcdC *tfp;
146 assert(m = dynamic_cast<mmio_t *>(master.get()));
148 // ASSUMPTION: All models have *no* combinational paths through I/O
149 // Step 1: Clock lo -> propagate signals between DUT and software models
150 AXI_LITE_SLAVE_CONNECT_VERILATOR_POS(top, io_s_ctrl, m, CTRL_BEAT_BYTES)
153 size_t m_read = 0, m_write = 0;
154 for (
size_t i = 0; i < mem_reqs.size(); i++)
156 const auto req_bundle = util::assertedCast<const BundleType>(mem_reqs[i]->
Type().get());
157 const auto res_bundle = util::assertedCast<const BundleType>(mem_resps[i]->
Type().get());
158 auto size =
JlmSize(&*res_bundle->get_element_type(
"data")) / 8;
159 const auto has_write = req_bundle->get_element_type(
"write") !=
nullptr;
162 cpp <<
" AXI_FULL_MM_CONNECT_VERILATOR_POS(top, io_m_write_" << m_write++ <<
", memories["
163 << i <<
"], " << size <<
")" << std::endl;
167 cpp <<
" AXI_FULL_READ_ONLY_MM_CONNECT_VERILATOR_POS(top, io_m_read_" << m_read++
168 <<
", memories[" << i <<
"], " << size <<
")" << std::endl;
175 tfp->dump((double)main_time);
183 top->eval(); // This shouldn't do much
186 tfp->dump((double)main_time);
193 // Step 2: Clock high, tick all software models and evaluate DUT with posedge
194 AXI_LITE_SLAVE_CONNECT_VERILATOR_POS_EDGE(top, io_s_ctrl, m)
199 for (
size_t i = 0; i < mem_reqs.size(); i++)
201 const auto bundle = util::assertedCast<const BundleType>(mem_reqs[i]->
Type().get());
202 const auto has_write = bundle->get_element_type(
"write") !=
nullptr;
205 cpp <<
" AXI_FULL_MM_CONNECT_VERILATOR_POS_EDGE(top, io_m_write_" << m_write++
206 <<
", memories[" << i <<
"])" << std::endl;
210 cpp <<
" AXI_FULL_READ_ONLY_MM_CONNECT_VERILATOR_POS_EDGE(top, io_m_read_" << m_read++
211 <<
", 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)