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