add comment
[riscv-isa-sim.git] / riscv / interactive.cc
1 // See LICENSE for license details.
2
3 #include "decode.h"
4 #include "disasm.h"
5 #include "sim.h"
6 #ifdef SPIKE_SIMPLEV
7 #include "sv_mmu.h"
8 #else
9 #include "mmu.h"
10 #endif
11 #include <sys/mman.h>
12 #include <termios.h>
13 #include <map>
14 #include <iostream>
15 #include <climits>
16 #include <cinttypes>
17 #include <assert.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <sstream>
21 #include <string>
22 #include <vector>
23 #include <algorithm>
24 #include <math.h>
25
26 DECLARE_TRAP(-1, interactive)
27
28 processor_t *sim_t::get_core(const std::string& i)
29 {
30 char *ptr;
31 unsigned long p = strtoul(i.c_str(), &ptr, 10);
32 if (*ptr || p >= procs.size())
33 throw trap_interactive();
34 return get_core(p);
35 }
36
37 static std::string readline(int fd)
38 {
39 struct termios tios;
40 bool noncanonical = tcgetattr(fd, &tios) == 0 && (tios.c_lflag & ICANON) == 0;
41
42 std::string s;
43 for (char ch; read(fd, &ch, 1) == 1; )
44 {
45 if (ch == '\x7f')
46 {
47 if (s.empty())
48 continue;
49 s.erase(s.end()-1);
50
51 if (noncanonical && write(fd, "\b \b", 3) != 3)
52 ; // shut up gcc
53 }
54 else if (noncanonical && write(fd, &ch, 1) != 1)
55 ; // shut up gcc
56
57 if (ch == '\n')
58 break;
59 if (ch != '\x7f')
60 s += ch;
61 }
62 return s;
63 }
64
65 void sim_t::interactive()
66 {
67 typedef void (sim_t::*interactive_func)(const std::string&, const std::vector<std::string>&);
68 std::map<std::string,interactive_func> funcs;
69
70 funcs["run"] = &sim_t::interactive_run_noisy;
71 funcs["r"] = funcs["run"];
72 funcs["rs"] = &sim_t::interactive_run_silent;
73 funcs["reg"] = &sim_t::interactive_reg;
74 funcs["freg"] = &sim_t::interactive_freg;
75 funcs["fregs"] = &sim_t::interactive_fregs;
76 funcs["fregd"] = &sim_t::interactive_fregd;
77 funcs["pc"] = &sim_t::interactive_pc;
78 funcs["mem"] = &sim_t::interactive_mem;
79 funcs["str"] = &sim_t::interactive_str;
80 funcs["until"] = &sim_t::interactive_until;
81 funcs["while"] = &sim_t::interactive_until;
82 funcs["quit"] = &sim_t::interactive_quit;
83 funcs["q"] = funcs["quit"];
84 funcs["help"] = &sim_t::interactive_help;
85 funcs["h"] = funcs["help"];
86
87 while (!done())
88 {
89 std::cerr << ": " << std::flush;
90 std::string s = readline(2);
91
92 std::stringstream ss(s);
93 std::string cmd, tmp;
94 std::vector<std::string> args;
95
96 if (!(ss >> cmd))
97 {
98 set_procs_debug(true);
99 step(1);
100 continue;
101 }
102
103 while (ss >> tmp)
104 args.push_back(tmp);
105
106 try
107 {
108 if(funcs.count(cmd))
109 (this->*funcs[cmd])(cmd, args);
110 else
111 fprintf(stderr, "Unknown command %s\n", cmd.c_str());
112 }
113 catch(trap_t t) {}
114 }
115 ctrlc_pressed = false;
116 }
117
118 void sim_t::interactive_help(const std::string& cmd, const std::vector<std::string>& args)
119 {
120 std::cerr <<
121 "Interactive commands:\n"
122 "reg <core> [reg] # Display [reg] (all if omitted) in <core>\n"
123 "fregs <core> <reg> # Display single precision <reg> in <core>\n"
124 "fregd <core> <reg> # Display double precision <reg> in <core>\n"
125 "pc <core> # Show current PC in <core>\n"
126 "mem <hex addr> # Show contents of physical memory\n"
127 "str <hex addr> # Show NUL-terminated C string\n"
128 "until reg <core> <reg> <val> # Stop when <reg> in <core> hits <val>\n"
129 "until pc <core> <val> # Stop when PC in <core> hits <val>\n"
130 "until mem <addr> <val> # Stop when memory <addr> becomes <val>\n"
131 "while reg <core> <reg> <val> # Run while <reg> in <core> is <val>\n"
132 "while pc <core> <val> # Run while PC in <core> is <val>\n"
133 "while mem <addr> <val> # Run while memory <addr> is <val>\n"
134 "run [count] # Resume noisy execution (until CTRL+C, or [count] insns)\n"
135 "r [count] Alias for run\n"
136 "rs [count] # Resume silent execution (until CTRL+C, or [count] insns)\n"
137 "quit # End the simulation\n"
138 "q Alias for quit\n"
139 "help # This screen!\n"
140 "h Alias for help\n"
141 "Note: Hitting enter is the same as: run 1\n"
142 << std::flush;
143 }
144
145 void sim_t::interactive_run_noisy(const std::string& cmd, const std::vector<std::string>& args)
146 {
147 interactive_run(cmd,args,true);
148 }
149
150 void sim_t::interactive_run_silent(const std::string& cmd, const std::vector<std::string>& args)
151 {
152 interactive_run(cmd,args,false);
153 }
154
155 void sim_t::interactive_run(const std::string& cmd, const std::vector<std::string>& args, bool noisy)
156 {
157 size_t steps = args.size() ? atoll(args[0].c_str()) : -1;
158 ctrlc_pressed = false;
159 set_procs_debug(noisy);
160 for (size_t i = 0; i < steps && !ctrlc_pressed && !done(); i++)
161 step(1);
162 }
163
164 void sim_t::interactive_quit(const std::string& cmd, const std::vector<std::string>& args)
165 {
166 exit(0);
167 }
168
169 reg_t sim_t::get_pc(const std::vector<std::string>& args)
170 {
171 if(args.size() != 1)
172 throw trap_interactive();
173
174 processor_t *p = get_core(args[0]);
175 return p->get_state()->pc;
176 }
177
178 void sim_t::interactive_pc(const std::string& cmd, const std::vector<std::string>& args)
179 {
180 fprintf(stderr, "0x%016" PRIx64 "\n", get_pc(args));
181 }
182
183 reg_t sim_t::get_reg(const std::vector<std::string>& args)
184 {
185 if(args.size() != 2)
186 throw trap_interactive();
187
188 processor_t *p = get_core(args[0]);
189
190 unsigned long r = std::find(xpr_name, xpr_name + NXPR, args[1]) - xpr_name;
191 if (r == NXPR) {
192 char *ptr;
193 r = strtoul(args[1].c_str(), &ptr, 10);
194 if (*ptr) {
195 #define DECLARE_CSR(name, number) if (args[1] == #name) return p->get_csr(number);
196 #include "encoding.h" // generates if's for all csrs
197 r = NXPR; // else case (csr name not found)
198 #undef DECLARE_CSR
199 }
200 }
201
202 if (r >= NXPR)
203 throw trap_interactive();
204
205 return p->get_state()->XPR[r];
206 }
207
208 freg_t sim_t::get_freg(const std::vector<std::string>& args)
209 {
210 if(args.size() != 2)
211 throw trap_interactive();
212
213 processor_t *p = get_core(args[0]);
214 int r = std::find(fpr_name, fpr_name + NFPR, args[1]) - fpr_name;
215 if (r == NFPR)
216 r = atoi(args[1].c_str());
217 if (r >= NFPR)
218 throw trap_interactive();
219
220 return p->get_state()->FPR[r];
221 }
222
223 void sim_t::interactive_reg(const std::string& cmd, const std::vector<std::string>& args)
224 {
225 if (args.size() == 1) {
226 // Show all the regs!
227 processor_t *p = get_core(args[0]);
228
229 for (int r = 0; r < NXPR; ++r) {
230 fprintf(stderr, "%-4s: 0x%016" PRIx64 " ", xpr_name[r], p->get_state()->XPR[r]);
231 if ((r + 1) % 4 == 0)
232 fprintf(stderr, "\n");
233 }
234 } else
235 fprintf(stderr, "0x%016" PRIx64 "\n", get_reg(args));
236 }
237
238 union fpr
239 {
240 freg_t r;
241 float s;
242 double d;
243 };
244
245 void sim_t::interactive_freg(const std::string& cmd, const std::vector<std::string>& args)
246 {
247 freg_t r = get_freg(args);
248 fprintf(stderr, "0x%016" PRIx64 "%016" PRIx64 "\n", r.v[1], r.v[0]);
249 }
250
251 void sim_t::interactive_fregs(const std::string& cmd, const std::vector<std::string>& args)
252 {
253 fpr f;
254 f.r = get_freg(args);
255 fprintf(stderr, "%g\n", isBoxedF32(f.r) ? (double)f.s : NAN);
256 }
257
258 void sim_t::interactive_fregd(const std::string& cmd, const std::vector<std::string>& args)
259 {
260 fpr f;
261 f.r = get_freg(args);
262 fprintf(stderr, "%g\n", isBoxedF64(f.r) ? f.d : NAN);
263 }
264
265 reg_t sim_t::get_mem(const std::vector<std::string>& args)
266 {
267 if(args.size() != 1 && args.size() != 2)
268 throw trap_interactive();
269
270 std::string addr_str = args[0];
271 #ifdef SPIKE_SIMPLEV
272 sv_mmu_t* mmu = debug_mmu;
273 #else
274 mmu_t* mmu = debug_mmu;
275 #endif
276 if(args.size() == 2)
277 {
278 processor_t *p = get_core(args[0]);
279 mmu = p->get_mmu();
280 addr_str = args[1];
281 }
282
283 reg_t addr = strtol(addr_str.c_str(),NULL,16), val;
284 if(addr == LONG_MAX)
285 addr = strtoul(addr_str.c_str(),NULL,16);
286
287 switch(addr % 8)
288 {
289 case 0:
290 val = mmu->load_uint64(addr);
291 break;
292 case 4:
293 val = mmu->load_uint32(addr);
294 break;
295 case 2:
296 case 6:
297 val = mmu->load_uint16(addr);
298 break;
299 default:
300 val = mmu->load_uint8(addr);
301 break;
302 }
303 return val;
304 }
305
306 void sim_t::interactive_mem(const std::string& cmd, const std::vector<std::string>& args)
307 {
308 fprintf(stderr, "0x%016" PRIx64 "\n", get_mem(args));
309 }
310
311 void sim_t::interactive_str(const std::string& cmd, const std::vector<std::string>& args)
312 {
313 if(args.size() != 1)
314 throw trap_interactive();
315
316 reg_t addr = strtol(args[0].c_str(),NULL,16);
317
318 char ch;
319 while((ch = debug_mmu->load_uint8(addr))) {
320 putchar(ch);
321 addr += 1;
322 }
323
324 putchar('\n');
325 }
326
327 void sim_t::interactive_until(const std::string& cmd, const std::vector<std::string>& args)
328 {
329 bool cmd_until = cmd == "until";
330
331 if(args.size() < 3)
332 return;
333
334 reg_t val = strtol(args[args.size()-1].c_str(),NULL,16);
335 if(val == LONG_MAX)
336 val = strtoul(args[args.size()-1].c_str(),NULL,16);
337
338 std::vector<std::string> args2;
339 args2 = std::vector<std::string>(args.begin()+1,args.end()-1);
340
341 auto func = args[0] == "reg" ? &sim_t::get_reg :
342 args[0] == "pc" ? &sim_t::get_pc :
343 args[0] == "mem" ? &sim_t::get_mem :
344 NULL;
345
346 if (func == NULL)
347 return;
348
349 ctrlc_pressed = false;
350
351 while (1)
352 {
353 try
354 {
355 reg_t current = (this->*func)(args2);
356
357 if (cmd_until == (current == val))
358 break;
359 if (ctrlc_pressed)
360 break;
361 }
362 catch (trap_t t) {}
363
364 set_procs_debug(false);
365 step(1);
366 }
367 }