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