Generate instruction decoder dynamically
[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 (true)
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 step(1, true);
60 continue;
61 }
62
63 while (ss >> tmp)
64 args.push_back(tmp);
65
66 typedef void (sim_t::*interactive_func)(const std::string&, const std::vector<std::string>&);
67 std::map<std::string,interactive_func> funcs;
68
69 funcs["r"] = &sim_t::interactive_run_noisy;
70 funcs["rs"] = &sim_t::interactive_run_silent;
71 funcs["reg"] = &sim_t::interactive_reg;
72 funcs["fregs"] = &sim_t::interactive_fregs;
73 funcs["fregd"] = &sim_t::interactive_fregd;
74 funcs["mem"] = &sim_t::interactive_mem;
75 funcs["str"] = &sim_t::interactive_str;
76 funcs["until"] = &sim_t::interactive_until;
77 funcs["while"] = &sim_t::interactive_until;
78 funcs["q"] = &sim_t::interactive_quit;
79
80 try
81 {
82 if(funcs.count(cmd))
83 (this->*funcs[cmd])(cmd, args);
84 }
85 catch(trap_t t) {}
86 }
87 ctrlc_pressed = false;
88 }
89
90 void sim_t::interactive_run_noisy(const std::string& cmd, const std::vector<std::string>& args)
91 {
92 interactive_run(cmd,args,true);
93 }
94
95 void sim_t::interactive_run_silent(const std::string& cmd, const std::vector<std::string>& args)
96 {
97 interactive_run(cmd,args,false);
98 }
99
100 void sim_t::interactive_run(const std::string& cmd, const std::vector<std::string>& args, bool noisy)
101 {
102 size_t steps = args.size() ? atoll(args[0].c_str()) : -1;
103 ctrlc_pressed = false;
104 for (size_t i = 0; i < steps && !ctrlc_pressed; i++)
105 step(1, noisy);
106 }
107
108 void sim_t::interactive_quit(const std::string& cmd, const std::vector<std::string>& args)
109 {
110 exit(0);
111 }
112
113 reg_t sim_t::get_pc(const std::vector<std::string>& args)
114 {
115 if(args.size() != 1)
116 throw trap_illegal_instruction;
117
118 int p = atoi(args[0].c_str());
119 if(p >= (int)num_cores())
120 throw trap_illegal_instruction;
121
122 return procs[p]->pc;
123 }
124
125 reg_t sim_t::get_reg(const std::vector<std::string>& args)
126 {
127 if(args.size() != 2)
128 throw trap_illegal_instruction;
129
130 int p = atoi(args[0].c_str());
131 int r = atoi(args[1].c_str());
132 if(p >= (int)num_cores() || r >= NXPR)
133 throw trap_illegal_instruction;
134
135 return procs[p]->XPR[r];
136 }
137
138 reg_t sim_t::get_freg(const std::vector<std::string>& args)
139 {
140 if(args.size() != 2)
141 throw trap_illegal_instruction;
142
143 int p = atoi(args[0].c_str());
144 int r = atoi(args[1].c_str());
145 if(p >= (int)num_cores() || r >= NFPR)
146 throw trap_illegal_instruction;
147
148 return procs[p]->FPR[r];
149 }
150
151 void sim_t::interactive_reg(const std::string& cmd, const std::vector<std::string>& args)
152 {
153 fprintf(stderr, "0x%016" PRIx64 "\n", get_reg(args));
154 }
155
156 union fpr
157 {
158 reg_t r;
159 float s;
160 double d;
161 };
162
163 void sim_t::interactive_fregs(const std::string& cmd, const std::vector<std::string>& args)
164 {
165 fpr f;
166 f.r = get_freg(args);
167 fprintf(stderr, "%g\n",f.s);
168 }
169
170 void sim_t::interactive_fregd(const std::string& cmd, const std::vector<std::string>& args)
171 {
172 fpr f;
173 f.r = get_freg(args);
174 fprintf(stderr, "%g\n",f.d);
175 }
176
177 reg_t sim_t::get_mem(const std::vector<std::string>& args)
178 {
179 if(args.size() != 1 && args.size() != 2)
180 throw trap_illegal_instruction;
181
182 std::string addr_str = args[0];
183 if(args.size() == 2)
184 {
185 int p = atoi(args[0].c_str());
186 if(p >= (int)num_cores())
187 throw trap_illegal_instruction;
188 mmu->set_ptbr(procs[p]->mmu.get_ptbr());
189 addr_str = args[1];
190 }
191
192 reg_t addr = strtol(addr_str.c_str(),NULL,16), val;
193 if(addr == LONG_MAX)
194 addr = strtoul(addr_str.c_str(),NULL,16);
195
196 switch(addr % 8)
197 {
198 case 0:
199 val = mmu->load_uint64(addr);
200 break;
201 case 4:
202 val = mmu->load_uint32(addr);
203 break;
204 case 2:
205 case 6:
206 val = mmu->load_uint16(addr);
207 break;
208 default:
209 val = mmu->load_uint8(addr);
210 break;
211 }
212 return val;
213 }
214
215 void sim_t::interactive_mem(const std::string& cmd, const std::vector<std::string>& args)
216 {
217 fprintf(stderr, "0x%016" PRIx64 "\n", get_mem(args));
218 }
219
220 void sim_t::interactive_str(const std::string& cmd, const std::vector<std::string>& args)
221 {
222 if(args.size() != 1)
223 throw trap_illegal_instruction;
224
225 reg_t addr = strtol(args[0].c_str(),NULL,16);
226
227 char ch;
228 while((ch = mmu->load_uint8(addr++)))
229 putchar(ch);
230
231 putchar('\n');
232 }
233
234 void sim_t::interactive_until(const std::string& cmd, const std::vector<std::string>& args)
235 {
236 bool cmd_until = cmd == "until";
237
238 if(args.size() < 3)
239 return;
240
241 reg_t val = strtol(args[args.size()-1].c_str(),NULL,16);
242 if(val == LONG_MAX)
243 val = strtoul(args[args.size()-1].c_str(),NULL,16);
244
245 std::vector<std::string> args2;
246 args2 = std::vector<std::string>(args.begin()+1,args.end()-1);
247
248 auto func = args[0] == "reg" ? &sim_t::get_reg :
249 args[0] == "pc" ? &sim_t::get_pc :
250 args[0] == "mem" ? &sim_t::get_mem :
251 NULL;
252
253 if (func == NULL)
254 return;
255
256 ctrlc_pressed = false;
257
258 while (1)
259 {
260 reg_t current = (this->*func)(args2);
261
262 if (cmd_until == (current == val))
263 break;
264 if (ctrlc_pressed)
265 break;
266
267 step(1, false);
268 }
269 }