Files
verilator/src/V3EmitCMain.cpp
T

187 lines
7.3 KiB
C++
Raw Normal View History

2020-04-21 20:45:23 -04:00
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Emit C++ for tree
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of either the GNU Lesser General Public License Version 3
// or the Perl Artistic License Version 2.0.
// SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
2020-04-21 20:45:23 -04:00
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
2022-08-05 10:56:57 +01:00
#include "V3EmitCMain.h"
2020-04-21 20:45:23 -04:00
#include "V3EmitC.h"
#include "V3EmitCBase.h"
#include <map>
2022-09-18 20:53:42 +01:00
VL_DEFINE_DEBUG_FUNCTIONS;
2020-04-21 20:45:23 -04:00
//######################################################################
class EmitCMain final : EmitCBaseVisitorConst {
2020-04-21 20:45:23 -04:00
// METHODS
// VISITORS
2020-05-16 18:02:54 -04:00
// This visitor doesn't really iterate, but exist to appease base class
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } // LCOV_EXCL_LINE
2020-04-21 20:45:23 -04:00
public:
// CONSTRUCTORS
EmitCMain() { emitInt(); }
2020-04-21 20:45:23 -04:00
private:
// MAIN METHOD
void emitInt() {
// Not defining main_time/vl_time_stamp, so
v3Global.opt.addCFlags("-DVL_TIME_CONTEXT"); // On MSVC++ anyways
// Optional main top name argument, with empty string replacement
string topName = v3Global.opt.mainTopName();
if (topName == "-") topName = "";
openNewOutputSourceFile(EmitCUtil::topClassName() + "__main", false, false,
"main() simulation loop, created with --main");
2020-04-21 20:45:23 -04:00
puts("\n");
// Heavily commented output, as users are likely to look at or copy this code
2020-04-21 20:45:23 -04:00
puts("#include \"verilated.h\"\n");
2026-02-28 09:42:28 -05:00
if (v3Global.opt.vpi()) puts("#include \"verilated_vpi.h\"\n");
puts("#include \"" + EmitCUtil::topClassName() + ".h\"\n");
2025-12-26 12:59:35 -05:00
if (v3Global.opt.debugRuntimeTimeout()) {
puts("\n");
puts("#include <csignal>\n");
}
2026-02-28 09:42:28 -05:00
puts("\n");
2020-04-21 20:45:23 -04:00
2026-02-28 09:42:28 -05:00
if (v3Global.opt.vpi()) {
puts("// User VPI code adds to this array to get startup main() callbacks\n");
puts("extern \"C\" void (*vlog_startup_routines[])() VL_ATTR_WEAK;\n");
puts("\n");
}
puts("//======================\n\n");
2020-04-21 20:45:23 -04:00
2025-12-26 12:59:35 -05:00
if (v3Global.opt.debugRuntimeTimeout()) {
puts("void alarmHandler(int signum) {\n");
// Add newline so %Error is at beginning-of-line, as might get the alarm
// when in the middle of some other print with no newline
puts(" VL_PRINTF_MT(\"\\n\");\n");
2025-12-26 12:59:35 -05:00
puts(" VL_FATAL_MT(\"\", 0, \"\", \"Alarm signal received,"s
+ " '--debug-runtime-timeout "s
+ std::to_string(v3Global.opt.debugRuntimeTimeout()) + "' exceeded\\n\");\n");
puts("}\n");
puts("\n");
}
2020-04-21 20:45:23 -04:00
puts("int main(int argc, char** argv, char**) {\n");
puts("// Setup context, defaults, and parse command line\n");
2020-04-21 20:45:23 -04:00
puts("Verilated::debug(0);\n");
puts("const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};\n");
2022-10-09 14:16:44 -04:00
if (v3Global.opt.trace()) puts("contextp->traceEverOn(true);\n");
puts("contextp->threads(" + std::to_string(v3Global.opt.threads()) + ");\n");
puts("contextp->commandArgs(argc, argv);\n");
puts("\n");
2025-12-26 12:59:35 -05:00
if (v3Global.opt.debugRuntimeTimeout()) {
puts("signal(SIGALRM, alarmHandler);\n");
puts("alarm("s + std::to_string(v3Global.opt.debugRuntimeTimeout()) + ");\n");
puts("\n");
}
2020-04-21 20:45:23 -04:00
puts("// Construct the Verilated model, from Vtop.h generated from Verilating\n");
puts("const std::unique_ptr<" + EmitCUtil::topClassName() + "> topp{new "
+ EmitCUtil::topClassName() + "{contextp.get(), \"" + topName + "\"}};\n");
puts("\n");
2026-02-28 09:42:28 -05:00
if (v3Global.opt.vpi()) {
// VPI shared libraries requested via +verilator+vpi+<lib> are loaded by
// contextp->commandArgs() above, before the statically-linked startup routines.
2026-02-28 09:42:28 -05:00
puts("// Hook VPI startup routines and invoke callback\n");
puts("if (vlog_startup_routines) {\n");
puts(/**/ "for (auto routinep = &vlog_startup_routines[0]; *routinep; routinep++)"
" (*routinep)();\n");
puts("}\n");
puts("VerilatedVpi::callCbs(cbStartOfSimulation);\n");
puts("\n");
}
2020-04-21 20:45:23 -04:00
puts("// Simulate until $finish\n");
puts("while (VL_LIKELY(!contextp->gotFinish())) {\n");
2026-02-28 09:42:28 -05:00
if (v3Global.opt.vpi()) {
puts(/**/ "// VPI callbacks\n");
puts(/**/ "VerilatedVpi::callTimedCbs();\n");
puts(/**/ "VerilatedVpi::callCbs(cbNextSimTime);\n"); // Before next event queue
puts(/**/ "VerilatedVpi::callCbs(cbAtStartOfSimTime);\n"); // Before time queue
}
2020-04-23 21:22:47 -04:00
puts(/**/ "// Evaluate model\n");
puts(/**/ "topp->eval();\n");
2026-02-28 09:42:28 -05:00
if (v3Global.opt.vpi()) {
puts(/**/ "// VPI callbacks\n");
puts(/**/ "VerilatedVpi::callValueCbs();\n");
puts(/**/ "VerilatedVpi::callCbs(cbAtEndOfSimTime);\n"); // After nonblocking events
puts(/**/ "VerilatedVpi::callCbs(cbReadWriteSynch);\n"); // After a specified time
puts(/**/ "VerilatedVpi::callCbs(cbReadOnlySynch);\n"); // After cbReadWriteSynch
}
2020-04-23 21:22:47 -04:00
puts(/**/ "// Advance time\n");
if (v3Global.rootp()->delaySchedulerp() || v3Global.opt.timing()) {
2022-08-22 14:26:32 +02:00
puts("if (!topp->eventsPending()) break;\n");
}
2026-02-28 09:42:28 -05:00
const std::string nextSlot = v3Global.rootp()->delaySchedulerp() ? "topp->nextTimeSlot()"
: "contextp->time() + 1";
if (v3Global.opt.vpi()) {
puts("contextp->time(std::min("s + nextSlot + ", VerilatedVpi::cbNextDeadline()));\n");
2022-08-22 14:26:32 +02:00
} else {
2026-02-28 09:42:28 -05:00
puts("contextp->time("s + nextSlot + ");\n");
2022-08-22 14:26:32 +02:00
}
2020-04-23 21:22:47 -04:00
puts("}\n");
puts("\n");
puts("if (VL_LIKELY(!contextp->gotFinish())) {\n");
2020-04-23 21:22:47 -04:00
puts(/**/ "VL_DEBUG_IF(VL_PRINTF(\"+ Exiting without $finish; no events left\\n\"););\n");
2020-04-21 20:45:23 -04:00
puts("}\n");
puts("\n");
puts("// Execute 'final' processes\n");
2020-04-21 20:45:23 -04:00
puts("topp->final();\n");
2026-02-28 09:42:28 -05:00
if (v3Global.opt.vpi()) puts("VerilatedVpi::callCbs(cbEndOfSimulation);\n");
puts("\n");
if (v3Global.opt.coverage()) {
puts("// Write coverage data (since Verilated with --coverage)\n");
2026-05-24 22:08:55 +00:00
if (v3Global.opt.coveragePerInstance()) {
puts("contextp->coveragep()->forcePerInstance(true);\n");
}
puts("contextp->coveragep()->write();\n");
puts("\n");
}
puts("// Print statistical summary report\n");
2024-03-30 13:16:36 -04:00
puts("contextp->statsPrintSummary();\n");
puts("\n");
puts("return 0;\n");
2020-04-21 20:45:23 -04:00
puts("}\n");
closeOutputFile();
2020-04-21 20:45:23 -04:00
}
};
//######################################################################
// EmitC class functions
void V3EmitCMain::emit() {
UINFO(2, __FUNCTION__ << ":");
{ const EmitCMain visitor; }
2020-04-21 20:45:23 -04:00
}