Files
lab-rv32i-freertos-c-notifi…/vendor/Hazard3/test/sim/tb_common/tb_cli.cpp
T

163 lines
6.5 KiB
C++

#include "tb_cli.h"
#include "tb_constants.h"
#include <iostream>
static const char *help_str =
"Usage: tb [--bin x.bin] [--port n] [--vpi-port n] [--vcd x.vcd] [--dump start end] \\\n"
" [--cycles n] [--cpuret] [--jtagdump x] [--jtagreplay x] [--vpi-poll n] \\\n"
" [--gdb-port n] [--uart0-port n] [--uart1-port n]\n"
" [--vpi-clk-per-tck n]\n"
"\n"
" --bin x.bin : Flat binary file loaded to address 0x0 in RAM\n"
" --vcd x.vcd : Path to dump waveforms to\n"
" --dump start end : Print out memory contents from start to end (exclusive)\n"
" after execution finishes. Can be passed multiple times.\n"
" --cycles n : Maximum number of cycles to run before exiting.\n"
" Default is 0 (no maximum).\n"
" --port n : Port number to listen for openocd remote bitbang. Sim\n"
" runs in lockstep with JTAG bitbang, not free-running.\n"
" --vpi-port n : Port number to listen for openocd jtag_vpi. Faster than\n"
" remote bitbang, and sim is free-running.\n"
" --vpi-poll n : When using --vpi-port, back off up to n core cycles\n"
" between socket polls when OpenOCD is idle (0 = every cycle).\n"
" --gdb-port n : Listen for GDB RSP directly (no OpenOCD/JTAG).\n"
" --uart0-port n : Expose testbench UART0 as a TCP stream.\n"
" --uart1-port n : Expose testbench UART1 as a TCP stream.\n"
" --vpi-clk-per-tck n : When using --vpi-port, run n core clock cycles per\n"
" JTAG TCK cycle during OpenOCD TMS sequences, so DMI/APB\n"
" CDC can make progress without huge BUSY delays.\n"
" --cpuret : Testbench's return code is the return code written to\n"
" IO_EXIT by the CPU, or -1 if timed out.\n"
" --jtagdump : Dump OpenOCD JTAG bitbang commands to a file so they\n"
" can be replayed. (Lower perf impact than VCD dumping)\n"
" --jtagreplay : Play back some dumped OpenOCD JTAG bitbang commands\n"
" --logfile path : File to write testbench stdout\n"
" --sigfile path : File to write only the data from --dump commands\n"
" (hex, 32 bits per line, same as riscv-arch-test)\n"
#ifdef CXXRTL_DEBUG_AGENT
" --debug : Run CXXRTL debugger\n"
#endif
;
static void exit_help(std::string errtext = "") {
std::cerr << errtext << help_str;
exit(-1);
}
void tb_parse_args(int argc, char **argv, tb_cli_args &args) {
for (int i = 1; i < argc; ++i) {
std::string s(argv[i]);
if (s.substr(0, 11) == "+verilator+") {
// Skip arguments passed directly to verilator context
i += 1;
} else if (s.rfind("--", 0) != 0) {
std::cerr << "Unexpected positional argument " << s << "\n";
exit_help("");
} else if (s == "--bin") {
if (argc - i < 2)
exit_help("Option --bin requires an argument\n");
args.load_bin = true;
args.bin_path = argv[i + 1];
i += 1;
} else if (s == "--vcd") {
if (argc - i < 2)
exit_help("Option --vcd requires an argument\n");
args.dump_waves = true;
args.waves_path = argv[i + 1];
i += 1;
} else if (s == "--logfile") {
if (argc - i < 2)
exit_help("Option --logfile requires an argument\n");
args.log_path = argv[i + 1];
i += 1;
} else if (s == "--sigfile") {
if (argc - i < 2)
exit_help("Option --sigfile requires an argument\n");
args.sig_path = argv[i + 1];
i += 1;
} else if (s == "--jtagdump") {
if (argc - i < 2)
exit_help("Option --jtagdump requires an argument\n");
args.dump_jtag = true;
args.jtag_dump_path = argv[i + 1];
i += 1;
} else if (s == "--jtagreplay") {
if (argc - i < 2)
exit_help("Option --jtagreplay requires an argument\n");
args.replay_jtag = true;
args.jtag_replay_path = argv[i + 1];
i += 1;
} else if (s == "--dump") {
if (argc - i < 3)
exit_help("Option --dump requires 2 arguments\n");
uint32_t first = std::stoul(argv[i + 1], 0, 0);
uint32_t last = std::stoul(argv[i + 2], 0, 0);
if (first < MEM_BASE || last > MEM_BASE + MEM_SIZE || first > last) {
std::cerr << "Invalid memory range\n";
exit(-1);
}
args.dump_ranges.push_back(std::pair<uint32_t, uint32_t>(
first, last
));
i += 2;
} else if (s == "--cycles") {
if (argc - i < 2)
exit_help("Option --cycles requires an argument\n");
args.max_cycles = std::stol(argv[i + 1], 0, 0);
i += 1;
} else if (s == "--port") {
if (argc - i < 2)
exit_help("Option --port requires an argument\n");
args.port = std::stol(argv[i + 1], 0, 0);
i += 1;
} else if (s == "--vpi-port") {
if (argc - i < 2)
exit_help("Option --vpi-port requires an argument\n");
args.vpi_port = std::stol(argv[i + 1], 0, 0);
i += 1;
} else if (s == "--gdb-port") {
if (argc - i < 2)
exit_help("Option --gdb-port requires an argument\n");
args.gdb_port = std::stol(argv[i + 1], 0, 0);
i += 1;
} else if (s == "--uart0-port") {
if (argc - i < 2)
exit_help("Option --uart0-port requires an argument\n");
args.uart0_port = std::stol(argv[i + 1], 0, 0);
i += 1;
} else if (s == "--uart1-port") {
if (argc - i < 2)
exit_help("Option --uart1-port requires an argument\n");
args.uart1_port = std::stol(argv[i + 1], 0, 0);
i += 1;
} else if (s == "--vpi-poll") {
if (argc - i < 2)
exit_help("Option --vpi-poll requires an argument\n");
args.vpi_poll_cycles = (uint32_t)std::stoul(argv[i + 1], 0, 0);
i += 1;
} else if (s == "--vpi-clk-per-tck") {
if (argc - i < 2)
exit_help("Option --vpi-clk-per-tck requires an argument\n");
args.vpi_clk_per_tck = (uint32_t)std::stoul(argv[i + 1], 0, 0);
i += 1;
} else if (s == "--cpuret") {
args.propagate_return_code = true;
#ifdef CXXRTL_DEBUG_AGENT
} else if (s == "--debug") {
args.run_agent = true;
#endif
} else {
std::cerr << "Unrecognised argument " << s << "\n";
exit_help("");
}
}
if (!(args.load_bin || args.port != 0 || args.vpi_port != 0 || args.gdb_port != 0 || args.replay_jtag))
exit_help("At least one of --bin, --port, --vpi-port, --gdb-port or --jtagreplay must be specified.\n");
if ((args.port != 0) + (args.vpi_port != 0) + (args.gdb_port != 0) > 1)
exit_help("Can't combine --port/--vpi-port/--gdb-port\n");
if (args.dump_jtag && args.port == 0)
exit_help("--jtagdump is only supported with --port (remote bitbang)\n");
if (args.replay_jtag && (args.port != 0 || args.vpi_port != 0 || args.gdb_port != 0))
exit_help("Can't specify --jtagreplay together with --port/--vpi-port/--gdb-port\n");
}