Add <functional> to files that use std::function
[lsnes.git] / src / core / memorywatch.cpp
blob9726f754a420f00026b39e0b7f7bfb3d839ae900
1 #include "core/command.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/framebuffer.hpp"
4 #include "core/instance.hpp"
5 #include "core/memorywatch.hpp"
6 #include "core/messages.hpp"
7 #include "core/project.hpp"
8 #include "core/rom.hpp"
9 #include "core/window.hpp"
10 #include "fonts/wrapper.hpp"
11 #include "library/directory.hpp"
12 #include "library/framebuffer-font2.hpp"
13 #include "library/globalwrap.hpp"
14 #include "library/int24.hpp"
15 #include "library/mathexpr-ntype.hpp"
16 #include "library/memoryspace.hpp"
17 #include "library/memorywatch-fb.hpp"
18 #include "library/memorywatch.hpp"
19 #include "library/memorywatch-list.hpp"
20 #include "library/memorywatch-null.hpp"
21 #include "library/string.hpp"
23 #include <functional>
24 #include <cstdio>
25 #include <cstdlib>
26 #include <list>
27 #include <iomanip>
28 #include <stack>
29 #include <cmath>
30 #include <sstream>
31 #include <map>
33 namespace
35 globalwrap<std::map<std::string, std::pair<framebuffer::font2*, size_t>>> S_fonts_in_use;
37 framebuffer::font2& get_builtin_font2()
39 static framebuffer::font2 f(main_font);
40 return f;
43 framebuffer::font2* get_font(const std::string filename)
45 //Handle NULL font.
46 if(filename == "")
47 return &get_builtin_font2();
48 std::string abs_filename = directory::absolute_path(filename);
49 if(S_fonts_in_use().count(abs_filename)) {
50 S_fonts_in_use()[abs_filename].second++;
51 return S_fonts_in_use()[abs_filename].first;
53 framebuffer::font2* f = new framebuffer::font2(abs_filename);
54 try {
55 S_fonts_in_use()[abs_filename] = std::make_pair(f, 1);
56 } catch(...) {
57 delete f;
58 throw;
60 return f;
62 void put_font(framebuffer::font2* font)
64 //Handle NULL font (always there).
65 if(!font)
66 return;
67 //Find font using this.
68 std::string filename;
69 for(auto& i : S_fonts_in_use())
70 if(i.second.first == font)
71 filename = i.first;
72 if(filename == "")
73 return;
74 S_fonts_in_use()[filename].second--;
75 if(!S_fonts_in_use()[filename].second) {
76 delete S_fonts_in_use()[filename].first;
77 S_fonts_in_use().erase(filename);
81 std::string json_string_default(const JSON::node& node, const std::string& pointer, const std::string& dflt)
83 return (node.type_of(pointer) == JSON::string) ? node[pointer].as_string8() : dflt;
86 uint64_t json_unsigned_default(const JSON::node& node, const std::string& pointer, uint64_t dflt)
88 return (node.type_of(pointer) == JSON::number) ? node[pointer].as_uint() : dflt;
91 int64_t json_signed_default(const JSON::node& node, const std::string& pointer, int64_t dflt)
93 return (node.type_of(pointer) == JSON::number) ? node[pointer].as_int() : dflt;
96 bool json_boolean_default(const JSON::node& node, const std::string& pointer, bool dflt)
98 return (node.type_of(pointer) == JSON::boolean) ? node[pointer].as_bool() : dflt;
101 void dummy_target_fn(const std::string& n, const std::string& v) {}
104 struct regread_oper : public mathexpr::operinfo
106 regread_oper();
107 ~regread_oper();
108 //The first promise is the register name.
109 void evaluate(mathexpr::value target, std::vector<std::function<mathexpr::value()>> promises);
110 //Fields.
111 bool signed_flag;
112 loaded_rom* rom;
115 regread_oper::regread_oper()
116 : operinfo("(readregister)")
118 signed_flag = false;
119 rom = NULL;
121 regread_oper::~regread_oper()
124 void regread_oper::evaluate(mathexpr::value target, std::vector<std::function<mathexpr::value()>> promises)
126 if(promises.size() != 1)
127 throw mathexpr::error(mathexpr::error::ARGCOUNT, "register read operator takes 1 argument");
128 std::string rname;
129 try {
130 mathexpr::value val = promises[0]();
131 void* res = val._value;
132 rname = val.type->tostring(res);
133 } catch(std::exception& e) {
134 throw mathexpr::error(mathexpr::error::ADDR, e.what());
136 const interface_device_reg* regs = rom->get_registers();
137 bool found = false;
138 for(size_t i = 0; regs && regs[i].name; i++) {
139 if(rname != regs[i].name)
140 continue;
141 found = true;
142 if(regs[i].boolean) {
143 bool v = (regs[i].read() != 0);
144 target.type->parse_b(target._value, v);
145 } else if(signed_flag) {
146 int64_t v = regs[i].read();
147 target.type->parse_s(target._value, v);
148 } else {
149 uint64_t v = regs[i].read();
150 target.type->parse_u(target._value, v);
152 return;
154 if(!found) {
155 //N/A value.
156 throw mathexpr::error(mathexpr::error::ADDR, "No such register");
161 memwatch_printer::memwatch_printer()
163 position = PC_MEMORYWATCH;
164 cond_enable = false;
165 onscreen_alt_origin_x = false;
166 onscreen_alt_origin_y = false;
167 onscreen_cliprange_x = false;
168 onscreen_cliprange_y = false;
169 onscreen_fg_color = 0xFFFFFF;
170 onscreen_bg_color = -1;
171 onscreen_halo_color = 0;
174 JSON::node memwatch_printer::serialize()
176 JSON::node ndata(JSON::object);
177 switch(position) {
178 case PC_DISABLED: ndata["position"] = JSON::s("disabled"); break;
179 case PC_MEMORYWATCH: ndata["position"] = JSON::s("memorywatch"); break;
180 case PC_ONSCREEN: ndata["position"] = JSON::s("onscreen"); break;
182 ndata["cond_enable"] = JSON::b(cond_enable);
183 ndata["enabled"] = JSON::s(enabled);
184 ndata["onscreen_xpos"] = JSON::s(onscreen_xpos);
185 ndata["onscreen_ypos"] = JSON::s(onscreen_ypos);
186 ndata["onscreen_alt_origin_x"] = JSON::b(onscreen_alt_origin_x);
187 ndata["onscreen_alt_origin_y"] = JSON::b(onscreen_alt_origin_y);
188 ndata["onscreen_cliprange_x"] = JSON::b(onscreen_cliprange_x);
189 ndata["onscreen_cliprange_y"] = JSON::b(onscreen_cliprange_y);
190 ndata["onscreen_font"] = JSON::s(onscreen_font);
191 ndata["onscreen_fg_color"] = JSON::i(onscreen_fg_color);
192 ndata["onscreen_bg_color"] = JSON::i(onscreen_bg_color);
193 ndata["onscreen_halo_color"] = JSON::i(onscreen_halo_color);
194 return ndata;
197 void memwatch_printer::unserialize(const JSON::node& node)
199 std::string _position = json_string_default(node, "position", "");
200 if(_position == "disabled") position = PC_DISABLED;
201 else if(_position == "memorywatch") position = PC_MEMORYWATCH;
202 else if(_position == "onscreen") position = PC_ONSCREEN;
203 else position = PC_MEMORYWATCH;
204 cond_enable = json_boolean_default(node, "cond_enable", false);
205 enabled = json_string_default(node, "enabled", "");
206 onscreen_xpos = json_string_default(node, "onscreen_xpos", "");
207 onscreen_ypos = json_string_default(node, "onscreen_ypos", "");
208 onscreen_alt_origin_x = json_boolean_default(node, "onscreen_alt_origin_x", false);
209 onscreen_alt_origin_y = json_boolean_default(node, "onscreen_alt_origin_y", false);
210 onscreen_cliprange_x = json_boolean_default(node, "onscreen_cliprange_x", false);
211 onscreen_cliprange_y = json_boolean_default(node, "onscreen_cliprange_y", false);
212 onscreen_font = json_string_default(node, "onscreen_font", "");
213 onscreen_fg_color = json_signed_default(node, "onscreen_fg_color", false);
214 onscreen_bg_color = json_signed_default(node, "onscreen_bg_color", false);
215 onscreen_halo_color = json_signed_default(node, "onscreen_halo_color", false);
218 GC::pointer<memorywatch::item_printer> memwatch_printer::get_printer_obj(
219 std::function<GC::pointer<mathexpr::mathexpr>(const std::string& n)> vars)
221 GC::pointer<memorywatch::item_printer> ptr;
222 memorywatch::output_list* l;
223 memorywatch::output_fb* f;
225 std::string _enabled = (enabled != "") ? enabled : "true";
227 switch(position) {
228 case PC_DISABLED:
229 ptr = GC::pointer<memorywatch::item_printer>(new memorywatch::output_null);
230 break;
231 case PC_MEMORYWATCH:
232 ptr = GC::pointer<memorywatch::item_printer>(new memorywatch::output_list);
233 l = dynamic_cast<memorywatch::output_list*>(ptr.as_pointer());
234 l->cond_enable = cond_enable;
235 try {
236 if(l->cond_enable)
237 l->enabled = mathexpr::mathexpr::parse(*mathexpr::expression_value(), _enabled, vars);
238 else
239 l->enabled = mathexpr::mathexpr::parse(*mathexpr::expression_value(), "true", vars);
240 } catch(std::exception& e) {
241 (stringfmt() << "Error while parsing conditional: " << e.what()).throwex();
243 l->set_output(dummy_target_fn);
244 break;
245 case PC_ONSCREEN:
246 ptr = GC::pointer<memorywatch::item_printer>(new memorywatch::output_fb);
247 f = dynamic_cast<memorywatch::output_fb*>(ptr.as_pointer());
248 f->font = NULL;
249 f->set_dtor_cb([](memorywatch::output_fb& obj) { put_font(obj.font); });
250 f->cond_enable = cond_enable;
251 std::string while_parsing = "(unknown)";
252 try {
253 while_parsing = "conditional";
254 if(f->cond_enable)
255 f->enabled = mathexpr::mathexpr::parse(*mathexpr::expression_value(), _enabled, vars);
256 else
257 f->enabled = mathexpr::mathexpr::parse(*mathexpr::expression_value(), "true", vars);
258 while_parsing = "X position";
259 f->pos_x = mathexpr::mathexpr::parse(*mathexpr::expression_value(), onscreen_xpos, vars);
260 while_parsing = "Y position";
261 f->pos_y = mathexpr::mathexpr::parse(*mathexpr::expression_value(), onscreen_ypos, vars);
262 } catch(std::exception& e) {
263 (stringfmt() << "Error while parsing " << while_parsing << ": " << e.what()).throwex();
265 f->alt_origin_x = onscreen_alt_origin_x;
266 f->alt_origin_y = onscreen_alt_origin_y;
267 f->cliprange_x = onscreen_cliprange_x;
268 f->cliprange_y = onscreen_cliprange_y;
269 f->fg = onscreen_fg_color;
270 f->bg = onscreen_bg_color;
271 f->halo = onscreen_halo_color;
272 try {
273 f->font = get_font(onscreen_font);
274 } catch(std::exception& e) {
275 messages << "Bad font '" << onscreen_font << "': " << e.what() << std::endl;
276 f->font = &get_builtin_font2();
278 break;
280 return ptr;
283 memwatch_item::memwatch_item()
285 bytes = 0;
286 signed_flag = false;
287 float_flag = false;
288 endianess = 0;
289 scale_div = 1;
290 addr_base = 0;
291 addr_size = 0;
294 JSON::node memwatch_item::serialize()
296 JSON::node ndata(JSON::object);
297 ndata["printer"] = printer.serialize();
298 ndata["expr"] = JSON::s(expr);
299 ndata["format"] = JSON::s(format);
300 ndata["bytes"] = JSON::u(bytes);
301 ndata["signed"] = JSON::b(signed_flag);
302 ndata["float"] = JSON::b(float_flag);
303 ndata["endianess"] = JSON::i(endianess);
304 ndata["scale_div"] = JSON::u(scale_div);
305 ndata["addr_base"] = JSON::u(addr_base);
306 ndata["addr_size"] = JSON::u(addr_size);
307 return ndata;
310 void memwatch_item::unserialize(const JSON::node& node)
312 if(node.type_of("printer") == JSON::object)
313 printer.unserialize(node["printer"]);
314 else
315 printer = memwatch_printer();
316 expr = json_string_default(node, "expr", "0");
317 format = json_string_default(node, "format", "");
318 bytes = json_unsigned_default(node, "bytes", 0);
319 signed_flag = json_boolean_default(node, "signed", false);
320 float_flag = json_boolean_default(node, "float", false);
321 endianess = json_signed_default(node, "endianess", false);
322 scale_div = json_unsigned_default(node, "scale_div", 1);
323 addr_base = json_unsigned_default(node, "addr_base", 0);
324 addr_size = json_unsigned_default(node, "addr_size", 0);
327 mathexpr::operinfo* memwatch_item::get_memread_oper(memory_space& memory, loaded_rom& rom)
329 if(addr_base == 0xFFFFFFFFFFFFFFFFULL && addr_size == 0) {
330 //Hack: Registers.
331 regread_oper* o = new regread_oper;
332 o->rom = &rom;
333 o->signed_flag = signed_flag;
334 return o;
336 if(!bytes)
337 return NULL;
338 memorywatch::memread_oper* o = new memorywatch::memread_oper;
339 o->bytes = bytes;
340 o->signed_flag = signed_flag;
341 o->float_flag = float_flag;
342 o->endianess = endianess;
343 o->scale_div = scale_div;
344 o->addr_base = addr_base;
345 o->addr_size = addr_size;
346 o->mspace = &memory;
347 return o;
350 void memwatch_item::compatiblity_unserialize(memory_space& memory, const std::string& item)
352 regex_results r;
353 if(!(r = regex("C0x([0-9A-Fa-f]{1,16})z([bBwWoOdDqQfF])(H([0-9A-Ga-g]))?", item)))
354 throw std::runtime_error("Unknown compatiblity memory watch");
355 std::string _addr = r[1];
356 std::string _type = r[2];
357 std::string _hext = r[4];
358 uint64_t addr = strtoull(_addr.c_str(), NULL, 16);
359 char type = _type[0];
360 char hext = (_hext != "") ? _hext[0] : 0;
361 switch(type) {
362 case 'b': bytes = 1; signed_flag = true; float_flag = false; break;
363 case 'B': bytes = 1; signed_flag = false; float_flag = false; break;
364 case 'w': bytes = 2; signed_flag = true; float_flag = false; break;
365 case 'W': bytes = 2; signed_flag = false; float_flag = false; break;
366 case 'o': bytes = 3; signed_flag = true; float_flag = false; break;
367 case 'O': bytes = 3; signed_flag = false; float_flag = false; break;
368 case 'd': bytes = 4; signed_flag = true; float_flag = false; break;
369 case 'D': bytes = 4; signed_flag = false; float_flag = false; break;
370 case 'q': bytes = 8; signed_flag = true; float_flag = false; break;
371 case 'Q': bytes = 8; signed_flag = false; float_flag = false; break;
372 case 'f': bytes = 4; signed_flag = true; float_flag = true; break;
373 case 'F': bytes = 8; signed_flag = true; float_flag = true; break;
374 default: bytes = 0; break;
376 auto mdata = memory.lookup(addr);
377 if(mdata.first) {
378 addr = mdata.second;
379 addr_base = mdata.first->base;
380 addr_size = mdata.first->size;
381 endianess = mdata.first->endian;
382 } else {
383 addr_base = 0;
384 addr_size = 0;
385 endianess = -1;
387 if(hext) {
388 unsigned width;
389 if(hext >= '0' && hext <= '9')
390 width = hext - '0';
391 else
392 width = (hext & 0x1F) + 9;
393 format = (stringfmt() << "%0" << width << "x").str();
394 } else
395 format = "";
396 expr = (stringfmt() << "0x" << std::hex << addr).str();
397 scale_div = 1;
398 printer.position = memwatch_printer::PC_MEMORYWATCH;
399 printer.cond_enable = false;
400 printer.enabled = "true";
401 printer.onscreen_xpos = "0";
402 printer.onscreen_ypos = "0";
403 printer.onscreen_alt_origin_x = false;
404 printer.onscreen_alt_origin_y = false;
405 printer.onscreen_cliprange_x = false;
406 printer.onscreen_cliprange_y = false;
407 printer.onscreen_font = "";
408 printer.onscreen_fg_color = 0xFFFFFF;
409 printer.onscreen_bg_color = -1;
410 printer.onscreen_halo_color = 0;
413 memwatch_set::memwatch_set(memory_space& _memory, project_state& _project, emu_framebuffer& _fbuf,
414 loaded_rom& _rom)
415 : memory(_memory), project(_project), fbuf(_fbuf), rom(_rom)
419 std::set<std::string> memwatch_set::enumerate()
421 std::set<std::string> r;
422 for(auto& i : items)
423 r.insert(i.first);
424 return r;
427 void memwatch_set::clear(const std::string& name)
429 std::map<std::string, memwatch_item> nitems = items;
430 nitems.erase(name);
431 rebuild(nitems);
432 std::swap(items, nitems);
433 auto pr = project.get();
434 if(pr) {
435 pr->watches.erase(name);
436 pr->flush();
438 fbuf.redraw_framebuffer();
441 void memwatch_set::set(const std::string& name, const std::string& item)
443 memwatch_item _item;
444 if(item != "" && item[0] != '{') {
445 //Compatiblity.
446 try {
447 _item.compatiblity_unserialize(memory, item);
448 } catch(std::exception& e) {
449 messages << "Can't handle old memory watch '" << name << "'" << std::endl;
450 return;
452 } else
453 _item.unserialize(JSON::node(item));
454 set(name, _item);
457 memwatch_item& memwatch_set::get(const std::string& name)
459 if(!items.count(name))
460 throw std::runtime_error("No such memory watch named '" + name + "'");
461 return items.find(name)->second;
464 std::string memwatch_set::get_string(const std::string& name, JSON::printer* printer)
466 auto& x = get(name);
467 auto y = x.serialize();
468 auto z = y.serialize(printer);
469 return z;
472 void memwatch_set::watch(struct framebuffer::queue& rq)
474 //Set framebuffer for all FB watches.
475 watch_set.foreach([&rq](memorywatch::item& i) {
476 memorywatch::output_fb* fb = dynamic_cast<memorywatch::output_fb*>(i.printer.as_pointer());
477 if(fb)
478 fb->set_rqueue(rq);
480 watch_set.refresh();
481 erase_unused_watches();
484 bool memwatch_set::rename(const std::string& oldname, const std::string& newname)
486 std::map<std::string, memwatch_item> nitems = items;
487 if(nitems.count(newname))
488 return false;
489 if(!nitems.count(oldname))
490 return false;
491 nitems.insert(std::make_pair(newname, nitems.find(oldname)->second));
492 nitems.erase(oldname);
493 rebuild(nitems);
494 std::swap(items, nitems);
495 auto pr = project.get();
496 if(pr) {
497 pr->watches.erase(oldname);
498 pr->watches[newname] = get_string(newname);
499 pr->flush();
501 fbuf.redraw_framebuffer();
502 return true;
505 void memwatch_set::set(const std::string& name, memwatch_item& item)
507 std::map<std::string, memwatch_item> nitems = items;
508 nitems.erase(name); //Insert does not insert if already existing.
509 nitems.insert(std::make_pair(name, item));
510 rebuild(nitems);
511 std::swap(items, nitems);
512 auto pr = project.get();
513 if(pr) {
514 pr->watches[name] = get_string(name);
515 pr->flush();
517 fbuf.redraw_framebuffer();
520 std::string memwatch_set::get_value(const std::string& name)
522 return watch_set.get(name).get_value();
525 void memwatch_set::set_multi(std::list<std::pair<std::string, memwatch_item>>& list)
527 std::map<std::string, memwatch_item> nitems = items;
528 for(auto& i : list)
529 nitems.insert(i);
530 rebuild(nitems);
531 std::swap(items, nitems);
532 auto pr = project.get();
533 if(pr) {
534 for(auto& i : list)
535 pr->watches[i.first] = get_string(i.first);
536 pr->flush();
538 fbuf.redraw_framebuffer();
541 void memwatch_set::set_multi(std::list<std::pair<std::string, std::string>>& list)
543 std::list<std::pair<std::string, memwatch_item>> _list;
544 for(auto& i: list) {
545 memwatch_item it;
546 it.unserialize(JSON::node(i.second));
547 _list.push_back(std::make_pair(i.first, it));
549 set_multi(_list);
552 void memwatch_set::clear_multi(const std::set<std::string>& names)
554 std::map<std::string, memwatch_item> nitems = items;
555 for(auto& i : names)
556 nitems.erase(i);
557 rebuild(nitems);
558 std::swap(items, nitems);
559 auto pr = project.get();
560 if(pr) {
561 for(auto& i : names)
562 pr->watches.erase(i);
563 pr->flush();
565 fbuf.redraw_framebuffer();
568 void memwatch_set::rebuild(std::map<std::string, memwatch_item>& nitems)
571 memorywatch::set new_set;
572 std::map<std::string, GC::pointer<mathexpr::mathexpr>> vars;
573 auto vars_fn = [&vars](const std::string& n) -> GC::pointer<mathexpr::mathexpr> {
574 if(!vars.count(n))
575 vars[n] = GC::pointer<mathexpr::mathexpr>(GC::obj_tag(),
576 mathexpr::expression_value());
577 return vars[n];
579 for(auto& i : nitems) {
580 mathexpr::operinfo* memread_oper = i.second.get_memread_oper(memory, rom);
581 try {
582 GC::pointer<mathexpr::mathexpr> rt_expr;
583 GC::pointer<memorywatch::item_printer> rt_printer;
584 std::vector<GC::pointer<mathexpr::mathexpr>> v;
585 try {
586 rt_expr = mathexpr::mathexpr::parse(*mathexpr::expression_value(),
587 i.second.expr, vars_fn);
588 } catch(std::exception& e) {
589 (stringfmt() << "Error while parsing address/expression: "
590 << e.what()).throwex();
592 v.push_back(rt_expr);
593 if(memread_oper) {
594 rt_expr = GC::pointer<mathexpr::mathexpr>(GC::obj_tag(),
595 mathexpr::expression_value(), memread_oper, v, true);
596 memread_oper = NULL;
598 rt_printer = i.second.printer.get_printer_obj(vars_fn);
600 //Set final callback for list objects (since it wasn't known on creation).
601 auto list_obj = dynamic_cast<memorywatch::output_list*>(rt_printer.as_pointer());
602 if(list_obj)
603 list_obj->set_output([this](const std::string& n, const std::string& v) {
604 this->watch_output(n, v);
607 memorywatch::item it(*mathexpr::expression_value());
608 *vars_fn(i.first) = *rt_expr;
609 it.expr = vars_fn(i.first);
610 it.printer = rt_printer;
611 it.format = i.second.format;
612 new_set.create(i.first, it);
613 } catch(...) {
614 delete memread_oper;
615 throw;
618 watch_set.swap(new_set);
620 GC::item::do_gc();
623 void memwatch_set::watch_output(const std::string& name, const std::string& value)
625 used_memorywatches[name] = true;
626 window_vars[name] = utf8::to32(value);
629 void memwatch_set::erase_unused_watches()
631 for(auto& i : used_memorywatches) {
632 if(!i.second)
633 window_vars.erase(i.first);
634 i.second = false;