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