Canola
0.8.D001
|
00001 // 00002 // canola - canon canola 1614p emulator 00003 // Copyright (C) 2011, 2012 Peter Miller 00004 // 00005 // This program is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License, version 3, as 00007 // published by the Free Software Foundation. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License along 00015 // with this program. If not, see <http://www.gnu.org/licenses/>. 00016 // 00017 00018 #include <lib/config.h> 00019 #include <libexplain/fopen.h> 00020 00021 #include <lib/std_string_printf.h> 00022 00023 #include <canola/debugger/gnome.h> 00024 00025 00026 debugger_gnome::~debugger_gnome() 00027 { 00028 } 00029 00030 00031 static void 00032 mono(Gtk::TextView &w) 00033 { 00034 w.set_editable(false); 00035 00036 Pango::FontDescription fdesc; 00037 fdesc.set_family("monospace"); 00038 w.override_font(fdesc); 00039 00040 // create a "red" tag so that we can use it later 00041 Glib::RefPtr<Gtk::TextTag> tp = 00042 w.get_buffer()->create_tag("red"); 00043 tp->property_foreground().set_value("red"); 00044 } 00045 00046 00047 debugger_gnome::debugger_gnome() : 00048 x_reg_name("X Register:"), 00049 y_reg_name("Y Register:"), 00050 address_name("Address:"), 00051 address_value(Gtk::Adjustment::create(1, 1, 240, 1)), 00052 address_value_changed_signal_enable(false), 00053 address_value_changed_signal_instance(), 00054 opcode_name("Opcode:"), 00055 mstate_name("State:") 00056 { 00057 const int spacing = 20; 00058 00059 left_panel.set_row_spacings(1); 00060 00061 for (int j = 0; j < 14; ++j) 00062 { 00063 std::string text = std_string_printf("Memory %d:", j + 1); 00064 memory_name[j].set_text(text); 00065 } 00066 00067 left_panel.attach(address_name, 0, 1, 0, 1); 00068 left_panel.attach(address_value, 1, 2, 0, 1); 00069 address_name.set_alignment(Gtk::ALIGN_START); 00070 address_value.set_wrap(); 00071 address_value.set_numeric(); 00072 address_value.signal_value_changed().connect 00073 ( 00074 sigc::mem_fun(*this, &debugger_gnome::on_address_value_changed) 00075 ); 00076 00077 left_panel.attach(opcode_name, 0, 1, 1, 2); 00078 left_panel.attach(opcode_value, 1, 2, 1, 2); 00079 opcode_name.set_alignment(Gtk::ALIGN_START); 00080 mono(opcode_value); 00081 opcode_value.set_size_request(100, -1); 00082 00083 left_panel.attach(x_reg_name, 0, 1, 2, 3); 00084 left_panel.attach(x_reg_value, 1, 2, 2, 3); 00085 mono(x_reg_value); 00086 x_reg_name.set_alignment(Gtk::ALIGN_START); 00087 00088 left_panel.attach(y_reg_name, 0, 1, 3, 4); 00089 left_panel.attach(y_reg_value, 1, 2, 3, 4); 00090 mono(y_reg_value); 00091 y_reg_name.set_alignment(Gtk::ALIGN_START); 00092 00093 left_panel.attach(mstate_name, 0, 1, 4, 5); 00094 left_panel.attach(mstate_value, 1, 2, 4, 5); 00095 mono(mstate_value); 00096 mstate_name.set_alignment(Gtk::ALIGN_START); 00097 00098 for (int j = 0; j < 14; ++j) 00099 { 00100 left_panel.attach(memory_name[j], 0, 1, 5 + j, 6 + j); 00101 left_panel.attach(memory_value[j], 1, 2, 5 + j, 6 + j); 00102 mono(memory_value[j]); 00103 memory_name[j].set_alignment(Gtk::ALIGN_START); 00104 } 00105 mono(source_code); 00106 source_code_scroller.add(source_code); 00107 source_code_scroller.set_policy(Gtk::POLICY_AUTOMATIC, 00108 Gtk::POLICY_AUTOMATIC); 00109 source_code_frame.add(source_code_scroller); 00110 00111 pack_start(left_panel, Gtk::PACK_SHRINK); 00112 pack_start(source_code_frame); 00113 set_spacing(spacing); 00114 00115 set_border_width(spacing); 00116 show_all_children(); 00117 00118 address_value_changed_signal_enable = true; 00119 } 00120 00121 00122 static void 00123 red_number(Gtk::TextView &tv, const std::string &text) 00124 { 00125 tv.get_buffer()->set_text(""); 00126 tv.get_buffer()->insert_with_tag(tv.get_buffer()->end(), text, "red"); 00127 } 00128 00129 00130 static void 00131 black_number(Gtk::TextView &tv, const std::string &text) 00132 { 00133 tv.get_buffer()->set_text(text); 00134 } 00135 00136 00137 static void 00138 textview_number(Gtk::TextView &tv, const number &value) 00139 { 00140 if (value.sign() < 0) 00141 red_number(tv, value.to_string()); 00142 else 00143 black_number(tv, value.to_string()); 00144 } 00145 00146 00147 void 00148 debugger_gnome::display_x_register(const number &value) 00149 { 00150 textview_number(x_reg_value, value); 00151 } 00152 00153 00154 void 00155 debugger_gnome::display_y_register(const number &value) 00156 { 00157 textview_number(y_reg_value, value); 00158 } 00159 00160 00161 void 00162 debugger_gnome::display_memory(int num, const number &value) 00163 { 00164 assert(num >= 1); 00165 assert(num <= 14); 00166 if (value == 0) 00167 memory_value[num - 1].get_buffer()->set_text(""); 00168 else 00169 textview_number(memory_value[num - 1], value); 00170 } 00171 00172 00173 void 00174 debugger_gnome::display_address(int n) 00175 { 00176 address_value_changed_signal_enable = false; 00177 address_value.set_range((n ? 1 : 0), 240); 00178 address_value.set_value(n); 00179 address_value.update(); // needed? 00180 address_value_changed_signal_enable = true; 00181 } 00182 00183 00184 void 00185 debugger_gnome::on_address_value_changed(void) 00186 { 00187 if (address_value_changed_signal_enable) 00188 { 00189 int n = address_value.get_value_as_int(); 00190 address_value_changed_signal_instance.emit(n); 00191 } 00192 } 00193 00194 00195 debugger_gnome::address_value_changed_signal_t & 00196 debugger_gnome::address_value_changed_signal(void) 00197 { 00198 return address_value_changed_signal_instance; 00199 } 00200 00201 00202 void 00203 debugger_gnome::display_opcode(opcode_t op) 00204 { 00205 std::string text = opcode_raw_name(op); 00206 if (opcode_valid(op)) 00207 black_number(opcode_value, text + " " + ::opcode_name(op)); 00208 else 00209 red_number(opcode_value, text); 00210 } 00211 00212 00213 static std::string 00214 basename(const std::string &filename) 00215 { 00216 const char *slash = strrchr(filename.c_str(), '/'); 00217 if (!slash) 00218 return filename; 00219 return std::string(slash + 1); 00220 } 00221 00222 00223 void 00224 debugger_gnome::display_location(const location::pointer &loc) 00225 { 00226 if (!loc) 00227 return; 00228 if (filename != loc->get_filename()) 00229 { 00230 // Maybe we could use a tabbed window and display more than one 00231 // source file, as needed. Could happen if they use include 00232 // files (e.g. for standard subroutines). However, experience 00233 // says this isn't a huge problem (the files are tiny compared 00234 // to modern source files). 00235 filename = loc->get_filename(); 00236 Glib::RefPtr<Gtk::TextBuffer> tb = source_code.get_buffer(); 00237 tb->set_text(""); 00238 00239 // read the entire contents of the file into the source code text view 00240 FILE *fp = fopen(filename.c_str(), "r"); 00241 if (!fp) 00242 { 00243 tb->set_text(explain_fopen(filename.c_str(), "r")); 00244 return; 00245 } 00246 00247 for (;;) 00248 { 00249 char buffer[4096]; 00250 size_t n = fread(buffer, 1, sizeof(buffer), fp); 00251 if (!n) 00252 break; 00253 tb->insert(tb->end(), buffer, buffer + n); 00254 } 00255 fclose(fp); 00256 } 00257 00258 { 00259 std::string num = std_string_printf(": %d", loc->get_line_number()); 00260 source_code_frame.set_label(basename(loc->get_filename()) + num); 00261 } 00262 00263 // highlight the text 00264 Glib::RefPtr<Gtk::TextBuffer> tb = source_code.get_buffer(); 00265 Gtk::TextIter lo = tb->get_iter_at_offset(loc->get_start()); 00266 Gtk::TextIter hi = tb->get_iter_at_offset(loc->get_end()); 00267 tb->place_cursor(hi); 00268 tb->select_range(lo, hi); 00269 00270 // scroll the highlighted text onto the display 00271 source_code.scroll_to(lo); 00272 } 00273 00274 00275 void 00276 debugger_gnome::display_mstate(const char *text) 00277 { 00278 mstate_value.get_buffer()->set_text(text); 00279 }