KoMo2  1.0.0
A modern ARM emulator GUI.
DisassemblyModel.cpp
Go to the documentation of this file.
1 
10 #include <ctype.h>
11 #include <iomanip>
12 #include <iostream>
13 #include <regex>
14 #include <sstream>
15 #include "../views/MainWindowView.h"
16 #include "KoMo2Model.h"
17 
18 // Initialise static list pointers
20 
27  KoMo2Model* const parent)
28  : Model(parent), view(view) {
29  view->setModel(this);
32 }
33 
43  const auto s = buildDisassemblyRowAccessibilityString(*row);
44  row->get_accessible()->set_description(s);
45 }
46 
51  auto* const rows = getView()->getRows();
52 
53  for (long unsigned int i = 0; i < rows->size(); i++) {
54  (*rows)[i].getButton()->signal_clicked().connect(
55  sigc::bind(sigc::mem_fun(*this, &DisassemblyModel::onBreakpointToggle),
56  &(*rows)[i]));
57  }
58 }
59 
65  getView()->add_events(Gdk::SMOOTH_SCROLL_MASK);
66  getView()->signal_scroll_event().connect(
67  sigc::mem_fun(*this, &DisassemblyModel::handleScroll), false);
68 }
69 
75 const bool DisassemblyModel::handleScroll(GdkEventScroll* const e) {
76  // Increase or decrease the memory index.
77  switch (e->direction) {
78  case GDK_SCROLL_UP:
80  break;
81  case GDK_SCROLL_DOWN:
83  break;
84  case GDK_SCROLL_SMOOTH:
85  incrementMemoryIndex(e->delta_y);
86  break;
87  default:
88  return false;
89  }
90 
91  // Refresh this view only
92  refreshViews();
93  return true;
94 }
95 
103  const uint32_t formatMe) const {
104  std::stringstream stream;
105 
106  // Pads string, converts to hex
107  stream << "0x" << std::setfill('0') << std::setw(8) << std::uppercase
108  << std::hex << formatMe;
109 
110  return stream.str();
111 }
112 
118  const auto vals = getMemoryValues();
119  auto* const rows = getView()->getRows();
120 
121  // Loop through each of the fetched rows
122  for (long unsigned int i = 0; i < vals.size(); i++) {
123  auto& row = (*rows)[i];
124  auto flag = row.get_state_flags();
125 
126  updateCSSFlags(flag, row, vals[i].address);
127  row.setAddressVal(vals[i].address);
128  row.setAddress(intToFormattedHexString(vals[i].address));
129  row.setHex(vals[i].hex);
130  row.setDisassembly(vals[i].disassembly);
131  row.setBreakpoint(vals[i].breakpoint);
132 
133  const auto s = buildDisassemblyRowAccessibilityString(row);
134  row.get_accessible()->set_description(s);
135  }
136 }
137 
144  DisassemblyRows& row) {
145  // Gets a string describing the state of the breakpoint
146  // Used for the accessibility object
147  std::string bp = row.getBreakpoint() ? "breakpoint set" : "no breakpoint";
148 
149  // Removes leading 0's from addresses
150  std::stringstream gHex;
151  gHex << std::hex << row.getAddress();
152  const auto addr = std::regex_replace(gHex.str(), std::regex("^0x0{0,7}"), "");
153 
154  // Gets the mnemonic OR an English "translation"
155  const std::string disassemblyInfo =
157  : row.getDisassembly();
158 
159  std::stringstream ss;
160  ss << "address " << addr << ", " << disassemblyInfo << bp;
161 
162  return ss.str();
163 }
164 
171  const std::string mnemonic) const {
172  // Splits mnemonic string into an array, at the space
173  std::istringstream iss(mnemonic);
174  std::vector<std::string> m(std::istream_iterator<std::string>{iss},
175  std::istream_iterator<std::string>());
176 
177  // If there is nothing to convert, return - should not be met
178  if (m.size() <= 1) {
179  return mnemonic;
180  }
181 
182  // Sanitize all parameters
183  for (auto& s : m) {
184  s = sanitizeParamters(s);
185  }
186 
187  m[0] = toLowerCase(m[0]);
188  m = parseSWI(m);
189  std::string outputText = "";
190  tie(m, outputText) = parseLabel(m);
191 
192  try {
193  return buildMnemonicString(outputText + mnemonicsMap.at(m[0]), m);
194  } catch (std::out_of_range const&) {
195  // ! Only happens in mnemonic is unrecognised - consider adding to the map
196  return mnemonic;
197  }
198 }
199 
209 const std::vector<std::string> DisassemblyModel::parseDEFB(
210  std::vector<std::string> m) const {
211  if (m[0] == "defb") {
212  // Pack the string into the first paramter vector entry
213  std::string s;
214  for (long unsigned int i = 1; i < m.size(); i++) {
215  s += m[i] + " ";
216  }
217 
218  // replace anything past the final comma
219  m[1] = std::regex_replace(s, std::regex(",[^,]*$"), "");
220  }
221 
222  return m;
223 }
224 
235 const std::vector<std::string> DisassemblyModel::parseSWI(
236  std::vector<std::string> m) const {
237  if (m[0] == "swi") {
238  m[0] += " " + m[1];
239  }
240 
241  return m;
242 }
243 
254 const std::pair<std::vector<std::string>, std::string>
255 DisassemblyModel::parseLabel(std::vector<std::string> m) const {
256  std::string out = "";
257 
258  try {
259  auto t = mnemonicsMap.at(m[0]); // If not present in the map, throws
260  } catch (std::out_of_range const&) {
261  out += "At label \"" + m[0] + "\", ";
262 
263  // Remove label from vector - m[1] becomes m[0]
264  m.erase(m.begin());
265 
266  // The next element is now assumed to be the keyword.
267  m[0] = toLowerCase(m[0]);
268  m = parseSWI(m);
269  m = parseDEFB(m);
270  }
271 
272  return std::make_pair(m, out);
273 }
274 
284  std::string s,
285  std::vector<std::string> m) const {
286  for (long unsigned int i = 1; i < m.size(); i++) {
287  // Builds the regex match string
288  std::string reg = "\\?" + std::to_string(i) + "\\?";
289  // Replaces the regex match string with the parameter
290  s = std::regex_replace(s, std::regex(reg), m[i]);
291  }
292 
293  return s + ", ";
294 }
295 
301 const std::string DisassemblyModel::sanitizeParamters(std::string param) const {
302  if (param[0] == 'R' || param[0] == 'r') {
303  return "Register " + param.erase(0, 1);
304  } else if (param[0] == '#') {
305  return param.erase(0, 1);
306  } else {
307  return param;
308  }
309 }
310 
316 const std::string DisassemblyModel::toLowerCase(std::string s) const {
317  for (auto& c : s) {
318  c = ::tolower(c);
319  }
320 
321  return s;
322 }
323 
331 void DisassemblyModel::updateCSSFlags(const Gtk::StateFlags flag,
332  DisassemblyRows& row,
333  const uint32_t address) {
334  // If this is the address in program counter:
335  if (intToFormattedHexString(address) == PCValue) {
336  // Make it highlighted if it is not focused
337  if (flag == NORMAL) {
338  row.set_state_flags(PC_ADDRESS);
339  }
340  // Highlight differently if it is focused
341  else if (flag == (FOCUSED)) {
342  row.set_state_flags(PC_ADDRESS_FOCUSED);
343  }
344  }
345  // If this is NOT the address in the program counter:
346  else {
347  // If it is not focused, remove highlight
348  if (flag == PC_ADDRESS) {
349  row.set_state_flags(NORMAL);
350  }
351  // If it is focused, set the focus highlight only
352  else if (flag == (PC_ADDRESS_FOCUSED)) {
353  row.set_state_flags(FOCUSED);
354  }
355  }
356 }
357 
364 void DisassemblyModel::incrementMemoryIndex(const uint32_t val) {
365  memoryIndex += val * 4;
366 }
367 
368 // ! Virtual override functions
369 
375 
381 const bool DisassemblyModel::handleKeyPress(const GdkEventKey* const e) {
382  // if alt is held
383  if ((e->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) ==
384  GDK_MOD1_MASK) {
385  // toggle mnemonics mode, else stop
386  if (e->keyval == GDK_KEY_m || e->keyval == GDK_KEY_M) {
388  refreshViews(); // Also rebuilds the screenreader strings
389  } else {
390  return false;
391  }
392  }
393 
394  auto rows = getView()->getRows();
395 
396  // If the top row has focus and it's a key press up, handle it
397  if ((*rows)[0].has_focus() && e->keyval == GDK_KEY_Up) {
398  auto scroll = GdkEventScroll();
399  scroll.direction = GDK_SCROLL_UP;
400  handleScroll(&scroll);
401  return true;
402  }
403 
404  // If the bottom row has focus and it's a key press down, handle it
405  else if ((*rows)[rows->size() - 1].has_focus() && e->keyval == GDK_KEY_Down) {
406  auto scroll = GdkEventScroll();
407  scroll.direction = GDK_SCROLL_DOWN;
408  handleScroll(&scroll);
409  return true;
410  }
411 
412  // Identifies if a child has focus - if not, return false
413 
414  long unsigned int hasFocus = -1;
415 
416  for (long unsigned int i = 0; i < rows->size(); i++) {
417  if ((*rows)[i].has_focus()) {
418  hasFocus = i;
419  }
420  }
421 
422  if (hasFocus == static_cast<long unsigned int>(-1)) {
423  return false;
424  }
425 
426  // If enter key pressed and a child has focus, toggle its breakpoint
427  else if (e->keyval == GDK_KEY_Return) {
428  onBreakpointToggle(&(*rows)[hasFocus]);
429  return true;
430  }
431 
432  // If escape pressed and in focus, lose focus
433  else if (e->keyval == GDK_KEY_Escape) {
434  if (hasFocus < rows->size() / 2) {
435  // Help button grabs focus
436  getParent()
437  ->getMainWindow()
438  ->getControlsView()
439  ->getHelpButton()
440  ->grab_focus();
441  return true;
442  } else {
443  // output box grabs focus
444  getParent()
445  ->getMainWindow()
446  ->getTerminalView()
447  ->getTextView()
448  ->grab_focus();
449  return true;
450  }
451  }
452 
453  return false;
454 }
455 
456 // !!!!!!!!!!!!!!!!!!!!!!!
457 // ! Getters and setters !
458 // !!!!!!!!!!!!!!!!!!!!!!!
459 
465  return view;
466 }
473 const std::array<Jimulator::MemoryValues, 13>
476 }
481 void DisassemblyModel::setPCValue(const std::string val) {
482  PCValue = val;
483 }
489  englishMnemonic = val;
490 }
void setEnglishMnemonic(const bool val)
Set the value of the englishMnemonic member variable.
void setModel(DisassemblyModel *const val)
Sets the value of the model member.
const Gtk::StateFlags NORMAL
The CSS state flags for an un-highlighted memory row.
A single instance of this class represents a single read memory address and the associated data - thi...
virtual const bool handleKeyPress(const GdkEventKey *const e) override
Handles any key press events.
const Gtk::StateFlags PC_ADDRESS_FOCUSED
The CSS state flags for e memory row that has keyboard focus and is currently stored in the Program C...
const Gtk::StateFlags FOCUSED
The CSS state flags for a memory row that has keyboard focus.
const std::unordered_map< std::string, std::string > mnemonicsMap
A map pairing ARM mnemonic commands with the English translation string associated with them for the ...
const std::string getAddress() const
Get the text in the address box.
KoMo2Model *const getParent() const
Returns the parent pointer.
Definition: Model.cpp:67
TerminalView *const getTerminalView()
Get the TerminalView.
DisassemblyModel(DisassemblyView *const view, KoMo2Model *const parent)
Construct a new DisassemblyModel::DisassemblyModel object.
const bool setBreakpoint(const uint32_t address)
Sets a breakpoint.
Definition: kcmd.cpp:372
std::vector< DisassemblyRows > *const getRows()
Gets a pointer to the rows of views.
const std::string toLowerCase(std::string s) const
Converts a string to lower case.
void onBreakpointToggle(DisassemblyRows *const row)
Handle the toggling of a breakpoint within the DisassemblyView.
const bool getBreakpoint()
Returns if a breakpoint is set or not.
bool englishMnemonic
Whether or not ARM mnemonics should be read in English when being read by a screenreader, or if they should be left as ARM mnemonics.
const std::string intToFormattedHexString(const uint32_t formatMe) const
Converts a fixed width 32-bit integer to a hex string, padded with 0&#39;s to 8 characters, pre-fixed with "0x", and raised to all capitals.
JimulatorState
Describe the 5 states of Jimulator.
Definition: Model.h:19
Gtk::TextView *const getTextView()
Returns a constant pointer to the output box.
const std::string buildMnemonicString(std::string s, std::vector< std::string > m) const
Builds the output mnemonics string from the vector making up the current ARM command and the value re...
void setupButtonHandlers()
Adds button handlers to every breakpoint button.
void setBreakpoint(const bool text)
Set the state of the breakpoint button. This is a little unusual - it sets the state in terms of CSS ...
MainWindowView *const getMainWindow() const
Gets the mainWindow member variable.
Definition: KoMo2Model.cpp:136
void updateCSSFlags(const Gtk::StateFlags state, DisassemblyRows &row, const uint32_t address)
Handles setting the CSS flags for each disassembly row, which determines which CSS class it uses and ...
DisassemblyView *const view
The view this model represents.
static uint32_t memoryIndex
Fixed width integer representing the memory address of the view at the top of the container...
A file containing the definition of the KoMo2Model class.
The superclass for all other Model classes. Uses a pure virtual function, so is abastract. Keeps KoMo2Model as a friend so it alone can call setJimulatorState. This class provides basic data that are needed by all other.
Definition: Model.h:35
const Gtk::StateFlags PC_ADDRESS
The CSS state flags for if the memory row is currently stored in the Program Counter.
void refreshViews()
Refreshes the values in the views to display the new values fetched from Jimulator.
const std::string sanitizeParamters(std::string param) const
Sanitizes any of the paramters used with an ARM mnemonic.
ControlsView *const getControlsView()
Get the ControlsView.
virtual void changeJimulatorState(const JimulatorState newState) override
Handles changes of Jimulator state.
const std::string buildDisassemblyRowAccessibilityString(DisassemblyRows &val)
Generates the string to set for the accessibility model.
void incrementMemoryIndex(const uint32_t val)
Updates the list pointers to a new value. Val is multipled by 4 - for example, if val is 1...
std::string PCValue
Stores the value currently in the program counter.
const std::string convertMnemonicToEnglish(const std::string mnemonic) const
Converts a mnemonic into plain English.
The logical model of the entire application. All other models should be member variables of this mode...
Definition: KoMo2Model.h:34
Represents the entire disassembly window in the overall KoMo2 GUI. Contains several rows of memory va...
void addScrollRecognition()
Adds scroll recognition to the container object, which causes scroll events to be sent to the member ...
const std::vector< std::string > parseDEFB(std::vector< std::string > v) const
Parses the DEFB ARM mnemonic - since a single ARM command is broken into a vector by the spaces betwe...
const std::array< Jimulator::MemoryValues, 13 > getMemoryValues() const
Reads memory values from Jimulator.
const std::pair< std::vector< std::string >, std::string > parseLabel(std::vector< std::string > m) const
Parses labels from an ARM command. If the first index in the vector is not a recognised keyword...
void setPCValue(const std::string val)
Updates the value of PCValue.
Gtk::LinkButton *const getHelpButton()
Gets the helpButton member variable.
std::array< Jimulator::MemoryValues, 13 > getJimulatorMemoryValues(const uint32_t s_address_int)
Get the memory values from Jimulator, starting to s_address.
Definition: kcmd.cpp:525
const bool handleScroll(GdkEventScroll *const e)
Handles the scroll events.
const std::string getDisassembly()
Gets the disassembly text for the breakpoint row.
DisassemblyView *const getView()
Returns a pointer to the view object.
const std::vector< std::string > parseSWI(std::vector< std::string > m) const
Parses the SWI ARM mnemonic - the SWI command always takes 1 paramter, but means very different thing...
const uint32_t getAddressVal() const
Get the addressVal member.