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