Improve performance for branchy code
[riscv-isa-sim.git] / riscv / interactive.cc
1 // See LICENSE for license details.
2
3 #include "sim.h"
4 #include "htif.h"
5 #include <sys/mman.h>
6 #include <termios.h>
7 #include <map>
8 #include <iostream>
9 #include <climits>
10 #include <cinttypes>
11 #include <assert.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sstream>
15 #include <string>
16 #include <vector>
17
18 static std::string readline(int fd)
19 {
20 struct termios tios;
21 bool noncanonical = tcgetattr(fd, &tios) == 0 && (tios.c_lflag & ICANON) == 0;
22
23 std::string s;
24 for (char ch; read(fd, &ch, 1) == 1; )
25 {
26 if (ch == '\x7f')
27 {
28 if (s.empty())
29 continue;
30 s.erase(s.end()-1);
31
32 if (noncanonical && write(fd, "\b \b", 3) != 3)
33 ; // shut up gcc
34 }
35 else if (noncanonical && write(fd, &ch, 1) != 1)
36 ; // shut up gcc
37
38 if (ch == '\n')
39 break;
40 if (ch != '\x7f')
41 s += ch;
42 }
43 return s;
44 }
45
46 void sim_t::interactive()
47 {
48 while (!htif->done())
49 {
50 std::cerr << ": " << std::flush;
51 std::string s = readline(2);
52
53 std::stringstream ss(s);
54 std::string cmd, tmp;
55 std::vector<std::string> args;
56
57 if (!(ss >> cmd))
58 {
59 set_procs_debug(true);
60 step(1);
61 continue;
62 }
63
64 while (ss >> tmp)
65 args.push_back(tmp);
66
67 typedef void (sim_t::*interactive_func)(const std::string&, const std::vector<std::string>&);
68 std::map<std::string,interactive_func> funcs;
69
70 funcs["r"] = &sim_t::interactive_run_noisy;
71 funcs["rs"] = &sim_t::interactive_run_silent;
72 funcs["reg"] = &sim_t::interactive_reg;
73 funcs["fregs"] = &sim_t::interactive_fregs;
74 funcs["fregd"] = &sim_t::interactive_fregd;
75 funcs["mem"] = &sim_t::interactive_mem;
76 funcs["str"] = &sim_t::interactive_str;
77 funcs["until"] = &sim_t::interactive_until;
78 funcs["while"] = &sim_t::interactive_until;
79 funcs["q"] = &sim_t::interactive_quit;
80
81 try
82 {
83 if(funcs.count(cmd))
84 (this->*funcs[cmd])(cmd, args);
85 }
86 catch(trap_t t) {}
87 }
88 ctrlc_pressed = false;
89 }
90
91 void sim_t::interactive_run_noisy(const std::string& cmd, const std::vector<std::string>& args)
92 {
93 interactive_run(cmd,args,true);
94 }
95
96 void sim_t::interactive_run_silent(const std::string& cmd, const std::vector<std::string>& args)
97 {
98 interactive_run(cmd,args,false);
99 }
100
101 void sim_t::interactive_run(const std::string& cmd, const std::vector<std::string>& args, bool noisy)
102 {
103 size_t steps = args.size() ? atoll(args[0].c_str()) : -1;
104 ctrlc_pressed = false;
105 set_procs_debug(noisy);
106 for (size_t i = 0; i < steps && !ctrlc_pressed && !htif->done(); i++)
107 step(1);
108 }
109
110 void sim_t::interactive_quit(const std::string& cmd, const std::vector<std::string>& args)
111 {
112 exit(0);
113 }
114
115 reg_t sim_t::get_pc(const std::vector<std::string>& args)
116 {
117 if(args.size() != 1)
118 throw trap_illegal_instruction();
119
120 int p = atoi(args[0].c_str());
121 if(p >= (int)num_cores())
122 throw trap_illegal_instruction();
123
124 return procs[p]->state.pc;
125 }
126
127 reg_t sim_t::get_reg(const std::vector<std::string>& args)
128 {
129 if(args.size() != 2)
130 throw trap_illegal_instruction();
131
132 int p = atoi(args[0].c_str());
133 int r = atoi(args[1].c_str());
134 if(p >= (int)num_cores() || r >= NXPR)
135 throw trap_illegal_instruction();
136
137 return procs[p]->state.XPR[r];
138 }
139
140 reg_t sim_t::get_freg(const std::vector<std::string>& args)
141 {
142 if(args.size() != 2)
143 throw trap_illegal_instruction();
144
145 int p = atoi(args[0].c_str());
146 int r = atoi(args[1].c_str());
147 if(p >= (int)num_cores() || r >= NFPR)
148 throw trap_illegal_instruction();
149
150 return procs[p]->state.FPR[r];
151 }
152
153 void sim_t::interactive_reg(const std::string& cmd, const std::vector<std::string>& args)
154 {
155 fprintf(stderr, "0x%016" PRIx64 "\n", get_reg(args));
156 }
157
158 union fpr
159 {
160 reg_t r;
161 float s;
162 double d;
163 };
164
165 void sim_t::interactive_fregs(const std::string& cmd, const std::vector<std::string>& args)
166 {
167 fpr f;
168 f.r = get_freg(args);
169 fprintf(stderr, "%g\n",f.s);
170 }
171
172 void sim_t::interactive_fregd(const std::string& cmd, const std::vector<std::string>& args)
173 {
174 fpr f;
175 f.r = get_freg(args);
176 fprintf(stderr, "%g\n",f.d);
177 }
178
179 reg_t sim_t::get_mem(const std::vector<std::string>& args)
180 {
181 if(args.size() != 1 && args.size() != 2)
182 throw trap_illegal_instruction();
183
184 std::string addr_str = args[0];
185 mmu_t* mmu = debug_mmu;
186 if(args.size() == 2)
187 {
188 int p = atoi(args[0].c_str());
189 if(p >= (int)num_cores())
190 throw trap_illegal_instruction();
191 mmu = procs[p]->get_mmu();
192 addr_str = args[1];
193 }
194
195 reg_t addr = strtol(addr_str.c_str(),NULL,16), val;
196 if(addr == LONG_MAX)
197 addr = strtoul(addr_str.c_str(),NULL,16);
198
199 switch(addr % 8)
200 {
201 case 0:
202 val = mmu->load_uint64(addr);
203 break;
204 case 4:
205 val = mmu->load_uint32(addr);
206 break;
207 case 2:
208 case 6:
209 val = mmu->load_uint16(addr);
210 break;
211 default:
212 val = mmu->load_uint8(addr);
213 break;
214 }
215 return val;
216 }
217
218 void sim_t::interactive_mem(const std::string& cmd, const std::vector<std::string>& args)
219 {
220 fprintf(stderr, "0x%016" PRIx64 "\n", get_mem(args));
221 }
222
223 void sim_t::interactive_str(const std::string& cmd, const std::vector<std::string>& args)
224 {
225 if(args.size() != 1)
226 throw trap_illegal_instruction();
227
228 reg_t addr = strtol(args[0].c_str(),NULL,16);
229
230 char ch;
231 while((ch = debug_mmu->load_uint8(addr++)))
232 putchar(ch);
233
234 putchar('\n');
235 }
236
237 void sim_t::interactive_until(const std::string& cmd, const std::vector<std::string>& args)
238 {
239 bool cmd_until = cmd == "until";
240
241 if(args.size() < 3)
242 return;
243
244 reg_t val = strtol(args[args.size()-1].c_str(),NULL,16);
245 if(val == LONG_MAX)
246 val = strtoul(args[args.size()-1].c_str(),NULL,16);
247
248 std::vector<std::string> args2;
249 args2 = std::vector<std::string>(args.begin()+1,args.end()-1);
250
251 auto func = args[0] == "reg" ? &sim_t::get_reg :
252 args[0] == "pc" ? &sim_t::get_pc :
253 args[0] == "mem" ? &sim_t::get_mem :
254 NULL;
255
256 if (func == NULL)
257 return;
258
259 ctrlc_pressed = false;
260
261 while (1)
262 {
263 try
264 {
265 reg_t current = (this->*func)(args2);
266
267 if (cmd_until == (current == val))
268 break;
269 if (ctrlc_pressed)
270 break;
271 }
272 catch (trap_t t) {}
273
274 set_procs_debug(false);
275 step(1);
276 }
277 }