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