163 lines
6.5 KiB
C++
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");
|
|
}
|