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