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