KoMo2  1.0.0
A modern ARM emulator GUI.
jimulatorInterface.cpp
Go to the documentation of this file.
1 
11 #include "jimulatorInterface.h"
12 #include <ctype.h>
13 #include <fcntl.h>
14 #include <gdk/gdkkeysyms.h>
15 #include <glib.h>
16 #include <gtk/gtk.h>
17 #include <math.h>
18 #include <signal.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/poll.h>
23 #include <sys/signal.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <termios.h>
27 #include <unistd.h>
28 #include <algorithm>
29 #include <iomanip>
30 #include <iostream>
31 #include <regex>
32 #include <string>
33 #include <unordered_map>
34 #include <vector>
35 #include <sstream>
36 
40 constexpr int SOURCE_BYTE_COUNT = 4;
41 
45 constexpr int SOURCE_FIELD_COUNT = 4;
46 
50 constexpr int SOURCE_TEXT_LENGTH = 100;
51 
55 constexpr int IN_POLL_TIMEOUT = 1000;
56 
60 constexpr int OUT_POLL_TIMEOUT = 100;
61 
65 constexpr int ADDRESS_BUS_WIDTH = 4;
66 
70 constexpr int MAX_NUMBER_OF_BREAKPOINTS = 32;
71 
75 class BreakpointInfo {
76  public:
80  unsigned char addressA[ADDRESS_BUS_WIDTH];
81 
87  unsigned char addressB[ADDRESS_BUS_WIDTH] = {0xFF, 0XFF, 0XFF, 0XFF};
88 
94  unsigned char dataA[8] = {0};
95 
101  unsigned char dataB[8] = {0};
102 
108  unsigned int misc = 0xFFFFFFFF;
109 };
110 
114 enum class BoardInstruction : unsigned char {
115  // General commands
116  START = 0xB0,
117  WOT_U_DO = 0x20,
118  STOP = 0x21,
119  CONTINUE = 0x23,
120  RESET = 0x04,
121 
122  // Terminal read/write
123  FR_WRITE = 0x12,
124  FR_READ = 0x13,
125 
126  // Breakpoint read/write
127  BP_WRITE = 0x30,
128  BP_READ = 0x31,
129  BP_SET = 0x32,
130  BP_GET = 0x33,
131 
132  // Register read/write
133  GET_REG = 0x5A,
134  SET_REG = 0x52, // Unused
135 
136  // Memory read/write
137  GET_MEM = 0x4A,
138  SET_MEM = 0x40,
139 };
140 
147 inline unsigned char operator|(BoardInstruction l, unsigned char r) {
148  return static_cast<unsigned char>(l) | r;
149 }
150 
154 class SourceFileLine {
155  public:
159  SourceFileLine* prev;
160 
164  SourceFileLine* next;
165 
169  bool hasData;
170 
174  unsigned int address;
175 
179  int dataSize[4];
180 
184  int dataValue[4];
185 
189  char* text;
190 };
191 
195 class sourceFile {
196  public:
200  SourceFileLine* pStart;
201 
205  SourceFileLine* pEnd;
206 };
207 
212 
213 // ! Forward declaring auxiliary load functions
214 
215 // Workers
216 
217 inline void flushSourceFile();
218 inline const bool readSourceFile(const char* const);
219 inline const ClientState getBoardStatus();
220 inline const std::array<unsigned char, 64> readRegistersIntoArray();
221 constexpr const int disassembleSourceFile(SourceFileLine*, unsigned int);
222 constexpr const bool moveSrc(bool firstFlag, SourceFileLine** src);
223 inline const std::string generateMemoryHex(SourceFileLine** src,
224  const uint32_t s_address,
225  int* const increment,
226  const int currentAddressI,
227  unsigned char (*memdata)[52]);
228 
229 // Low level sending
230 
231 inline void sendNBytes(int, int);
232 inline void sendChar(unsigned char);
233 inline void sendCharArray(int, unsigned char*);
234 
235 // Low level receiving
236 
237 inline const int getNBytes(int*, int);
238 inline const int getChar(unsigned char*);
239 inline const int getCharArray(int, unsigned char*);
240 
241 // Breakpoints
242 
243 constexpr const int getNextFreeBreakpoint(const int);
244 inline const bool getBreakpointStatus(unsigned int*, unsigned int*);
245 inline const bool getBreakpointDefinition(unsigned int, BreakpointInfo*);
246 inline void setBreakpointStatus(unsigned int, unsigned int);
247 inline void setBreakpointDefinition(unsigned int, BreakpointInfo*);
248 inline const std::unordered_map<u_int32_t, bool> getAllBreakpoints();
249 
250 // Helpers
251 
252 constexpr void copyStringLiterals(int, unsigned char*, unsigned char*);
253 constexpr const int numericStringSubtraction(const unsigned char* const,
254  const unsigned char* const);
255 constexpr const int numericStringToInt(int, const unsigned char* const);
256 constexpr void numericStringAndIntAddition(unsigned char* const, int);
257 inline const std::string integerArrayToHexString(int,
258  unsigned char* const,
259  const bool = false);
260 constexpr const char getLeastSignificantByte(const int);
261 
269 void Jimulator::compileJimulator(const char* const pathToBin,
270  const char* const pathToS,
271  const char* const pathToKMD) {
272  close(1);
273  dup2(compilerCommunication[1], 1);
274  close(2);
275  dup2(compilerCommunication[1], 2);
276  execlp(pathToBin, "aasm", "-lk", pathToKMD, pathToS, (char*)0);
277 }
278 
285 const bool Jimulator::loadJimulator(const char* const pathToKMD) {
286  flushSourceFile();
287  return readSourceFile(pathToKMD);
288 }
289 
294 void Jimulator::startJimulator(const int steps) {
295  if (checkBoardState() == ClientState::NORMAL ||
296  Jimulator::checkBoardState() == ClientState::BREAKPOINT) {
297  sendChar(static_cast<unsigned char>(BoardInstruction::START));
298  sendNBytes(steps, 4); // Send step count
299  }
300 }
301 
306  if (Jimulator::checkBoardState() == ClientState::NORMAL ||
307  Jimulator::checkBoardState() == ClientState::BREAKPOINT) {
308  sendChar(static_cast<unsigned char>(BoardInstruction::CONTINUE));
309  }
310 }
311 
316  sendChar(static_cast<unsigned char>(BoardInstruction::STOP));
317 }
318 
323  sendChar(static_cast<unsigned char>(BoardInstruction::RESET));
324 }
325 
331 const bool Jimulator::setBreakpoint(const uint32_t addr) {
332  unsigned int wordA = 0, wordB = 0;
333  unsigned char address[ADDRESS_BUS_WIDTH] = {0};
334 
335  // Unpack address to byte array
336  for (int i = 0; i < ADDRESS_BUS_WIDTH; i++) {
337  address[i] = getLeastSignificantByte(addr >> (8 * i));
338  }
339 
340  // Reads the breakpoints
341  if (not getBreakpointStatus(&wordA, &wordB)) {
342  return false;
343  }
344 
345  // Checks to see if a breakpoint exists at this address and turns it off if so
346  for (int i = 0; i < MAX_NUMBER_OF_BREAKPOINTS; i++) {
347  if (((wordA >> i) & 1) != 0) {
348  BreakpointInfo bp;
349 
350  // Gets breakpoint i from the list;
351  // checks if that breakpoint is set for current address;
352  // turns it off if so
353  if (getBreakpointDefinition(i, &bp) &&
354  (numericStringSubtraction(address, bp.addressA) == 0)) {
355  setBreakpointStatus(0, 1 << i);
356  return false;
357  }
358  }
359  }
360 
361  // See if there are any more breakpoints to be set, return if not
362  int temp = (~wordA) & wordB;
363  if (temp == 0) {
364  return false;
365  }
366 
367  // Set the breakpoint
368  BreakpointInfo bp;
369  copyStringLiterals(ADDRESS_BUS_WIDTH, address, bp.addressA);
370 
371  int i = getNextFreeBreakpoint(temp);
372  setBreakpointDefinition(i, &bp);
373  return true;
374 }
375 
381 const ClientState Jimulator::checkBoardState() {
382  const auto board_state = getBoardStatus();
383 
384  // Check and log error states
385  switch (board_state) {
386  case ClientState::RUNNING_SWI:
387  break;
388  case ClientState::RUNNING:
389  break;
390  case ClientState::STEPPING:
391  break;
392  case ClientState::MEMFAULT:
393  break;
394  case ClientState::BUSY:
395  break;
396  case ClientState::FINISHED:
397  break;
398  case ClientState::BREAKPOINT:
399  break;
400  default:
401  return ClientState::NORMAL;
402  break;
403  }
404 
405  return board_state;
406 }
407 
412 const std::array<std::string, 16> Jimulator::getJimulatorRegisterValues() {
413  auto bytes = readRegistersIntoArray();
414 
415  std::array<std::string, 16> ret; // vector of strings
416 
417  // Loop through the array
418  for (long unsigned int i = 0; i < ret.size(); i++) {
419  ret[i] = integerArrayToHexString(4, &bytes[i * 4], true);
420  }
421 
422  return ret;
423 }
424 
429 const std::string Jimulator::getJimulatorTerminalMessages() {
430  unsigned char string[256]; // Arbitrary size
431  unsigned char length = 1;
432 
433  std::string output("");
434 
435  while (length > 0) {
436  sendChar(static_cast<unsigned char>(BoardInstruction::FR_READ));
437  sendChar(0); // send the terminal number
438  sendChar(32);
439  getChar(&length); // get length of message
440 
441  // non-zero received from board - not an empty packet
442  if (length != 0) {
443  getCharArray(length, string); // Store the message
444  string[length] = '\0';
445  output.append((char*)string);
446  }
447  }
448 
449  return output;
450 }
451 
458 const bool Jimulator::sendTerminalInputToJimulator(const unsigned int val) {
459  unsigned int key_pressed = val;
460  unsigned char res = 0;
461 
462  // Translate key codes if necessary and understood
463  switch (key_pressed) {
464  case GDK_KEY_Return:
465  case GDK_KEY_KP_Enter:
466  key_pressed = '\n';
467  break;
468  case GDK_KEY_BackSpace:
469  key_pressed = '\b';
470  break;
471  case GDK_KEY_Tab:
472  key_pressed = '\t';
473  break;
474  case GDK_KEY_Escape:
475  key_pressed = 0x1B;
476  break;
477  case GDK_KEY_KP_0:
478  case GDK_KEY_KP_1:
479  case GDK_KEY_KP_2:
480  case GDK_KEY_KP_3:
481  case GDK_KEY_KP_4:
482  case GDK_KEY_KP_5:
483  case GDK_KEY_KP_6:
484  case GDK_KEY_KP_7:
485  case GDK_KEY_KP_8:
486  case GDK_KEY_KP_9:
487  key_pressed = key_pressed - GDK_KEY_KP_0 + '0';
488  break;
489  case GDK_KEY_KP_Add:
490  key_pressed = '+';
491  break;
492  case GDK_KEY_KP_Subtract:
493  key_pressed = '-';
494  break;
495  case GDK_KEY_KP_Multiply:
496  key_pressed = '*';
497  break;
498  case GDK_KEY_KP_Divide:
499  key_pressed = '/';
500  break;
501  case GDK_KEY_KP_Decimal:
502  key_pressed = '.';
503  break;
504  default:
505  break;
506  }
507 
508  // Sending keys to Jimulator
509  if (((key_pressed >= ' ') && (key_pressed <= 0x7F)) ||
510  (key_pressed == '\n') || (key_pressed == '\b') || (key_pressed == '\t') ||
511  (key_pressed == '\a')) {
512  sendChar(static_cast<unsigned char>(
513  BoardInstruction::FR_WRITE)); // begins a write
514  sendChar(0); // tells where to send it
515  sendChar(1); // send length 1
516  sendChar(key_pressed); // send the message - 1 char currently
517  getChar(&res); // Read the result
518  return true;
519  }
520 
521  return false;
522 }
523 
530 std::array<Jimulator::MemoryValues, 13> Jimulator::getJimulatorMemoryValues(
531  const uint32_t s_address) {
532  constexpr int count = 13; // How many values displayed in the memory window
533  constexpr int bytecount = count * ADDRESS_BUS_WIDTH; // bytes to read
534 
535  // Bit level hacking happening here - converting the integer address into
536  // an array of characters.
537  unsigned char* p = (unsigned char*)&s_address;
538  unsigned char currentAddressS[ADDRESS_BUS_WIDTH] = {p[0], p[1], p[2], p[3]};
539  currentAddressS[0] &= -4; // Normalise address down
540 
541  // Reading data into arrays!
542  unsigned char memdata[bytecount];
543  sendChar(static_cast<unsigned char>(BoardInstruction::GET_MEM));
544  sendCharArray(ADDRESS_BUS_WIDTH, currentAddressS);
545  sendNBytes(count, 2);
546  getCharArray(bytecount, memdata);
547 
548  SourceFileLine* src = NULL;
549  bool firstFlag = false;
550 
551  // Moves our src line to the relevant line of the src file
552  if (source.pStart != NULL) {
553  src = source.pStart; // Known to be valid
554  while ((src != NULL) && ((src->address < s_address) || not src->hasData)) {
555  src = src->next;
556  }
557 
558  // We fell off the end; wrap to start
559  if (src == NULL) {
560  src = source.pStart;
561  firstFlag = true;
562 
563  // Find a record with some data
564  while ((src != NULL) && not src->hasData) {
565  src = src->next;
566  }
567  }
568  }
569 
570  // ! Building an array of memory values from here
571  // Data is read into this array
572  std::array<Jimulator::MemoryValues, 13> readValues;
573  const auto bps = getAllBreakpoints();
574 
575  // Iterate over display rows
576  for (long unsigned int i = 0; i < readValues.size(); i++) {
577  int increment = 0;
578  unsigned int currentAddressI =
579  numericStringToInt(ADDRESS_BUS_WIDTH, currentAddressS);
580  readValues[i].address = currentAddressI;
581  readValues[i].hex = std::string("00000000");
582  readValues[i].disassembly = std::string("...");
583 
584  // Generate the hex
585  if (src != NULL && currentAddressI == src->address) {
586  readValues[i].disassembly =
587  std::regex_replace(std::string(src->text), std::regex(";.*$"), "");
588  readValues[i].hex = generateMemoryHex(&src, s_address, &increment,
589  currentAddressI, &memdata);
590 
591  firstFlag = moveSrc(firstFlag, &src);
592  }
593 
594  // Find if a breakpoint is set on this line
595  // if the iterator is not at the end of the map, the breakpoint was found
596  // and can be set
597  auto iter = bps.find(readValues[i].address);
598  if (iter != bps.end()) {
599  readValues[i].breakpoint = true;
600  }
601 
602  // Calculate where the next address is and move the address there
603  increment = disassembleSourceFile(src, currentAddressI);
604  numericStringAndIntAddition(currentAddressS, increment);
605  }
606 
607  return readValues;
608 }
609 
610 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
611 // !!!!!!!!!! Functions below are not included in the header file !!!!!!!!!! //
612 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
613 
620 constexpr const int getNextFreeBreakpoint(const int v) {
621  int i = 0;
622  for (; (((v >> i) & 1) == 0); i++)
623  ;
624 
625  return i;
626 }
627 
634 constexpr const char getLeastSignificantByte(const int val) {
635  return val & 0xFF;
636 }
637 
643 constexpr const int rotateRight1Byte(const int val) {
644  return val >> 8;
645 }
646 
652 constexpr const int rotateLeft1Byte(const int val) {
653  return val << 8;
654 }
655 
691 inline const bool getBreakpointStatus(unsigned int* wordA,
692  unsigned int* wordB) {
693  sendChar(static_cast<unsigned char>(BoardInstruction::BP_GET));
694  return not((getNBytes((int*)wordA, 4) != 4) ||
695  (getNBytes((int*)wordB, 4) != 4));
696 }
697 
704 constexpr const bool moveSrc(bool firstFlag, SourceFileLine** src) {
705  do {
706  if ((*src)->next != NULL) {
707  (*src) = (*src)->next;
708  } else {
709  if (not firstFlag) {
710  (*src) = source.pStart;
711  firstFlag = true;
712  } else {
713  (*src) = NULL;
714  }
715  }
716  } while (((*src) != NULL) && not(*src)->hasData);
717 
718  return firstFlag;
719 }
720 
734 inline const std::string generateMemoryHex(SourceFileLine** src,
735  const uint32_t s_address,
736  int* const increment,
737  const int currentAddressI,
738  unsigned char (*memdata)[52]) {
739  std::string hex = "";
740 
741  for (int i = 0; i < SOURCE_FIELD_COUNT; i++) {
742  if ((*src)->dataSize[i] > 0) {
743  char spaces[5] = {0};
744 
745  // Get the data string
746  auto data = integerArrayToHexString(
747  (*src)->dataSize[i],
748  &((*memdata)[currentAddressI - s_address + *increment]));
749 
750  int j = 0;
751  for (; j < (*src)->dataSize[i]; j++) {
752  spaces[j] = ' ';
753  }
754 
755  // Append to the string
756  spaces[j] = '\0';
757  hex += data;
758  hex += spaces;
759  }
760 
761  // Increase the increment
762  *increment = *increment + (*src)->dataSize[i];
763  }
764 
765  return hex;
766 }
767 
778 inline const bool getBreakpointDefinition(unsigned int breakpointlistIndex,
779  BreakpointInfo* bp) {
780  sendChar(static_cast<unsigned char>(BoardInstruction::BP_READ));
781  sendChar(breakpointlistIndex); // send the number of the definition
782 
783  if ((2 != getNBytes((int*)&(bp->misc), 2)) ||
784  (4 != getCharArray(4, bp->addressA)) ||
785  (4 != getCharArray(4, bp->addressB)) ||
786  (8 != getCharArray(8, bp->dataA)) || (8 != getCharArray(8, bp->dataB))) {
787  return false;
788  } else {
789  return true;
790  }
791 }
792 
804 constexpr const int numericStringSubtraction(const unsigned char* const s1,
805  const unsigned char* const s2) {
806  int ret = 0;
807 
808  for (int i = ADDRESS_BUS_WIDTH; i--;) {
809  ret = rotateLeft1Byte(ret) + (int)s1[i] - (int)s2[i];
810  }
811  return ret;
812 }
813 
820 constexpr void copyStringLiterals(int i,
821  unsigned char* source,
822  unsigned char* dest) {
823  while (i--) {
824  dest[i] = source[i];
825  }
826 }
827 
834 inline void setBreakpointStatus(unsigned int wordA, unsigned int wordB) {
835  sendChar(static_cast<unsigned char>(BoardInstruction::BP_SET));
836  sendNBytes(wordA, 4); // send word a
837  sendNBytes(wordB, 4); // send word b
838 }
839 
847 inline void setBreakpointDefinition(unsigned int breakpointIndex,
848  BreakpointInfo* bp) {
849  sendChar(static_cast<unsigned char>(BoardInstruction::BP_WRITE));
850  sendChar(breakpointIndex); // send the list index of the breakpoint
851  sendNBytes(bp->misc, 2);
854  sendCharArray(8, bp->dataA);
855  sendCharArray(8, bp->dataB);
856 }
857 
863 inline void sendCharArray(int length, unsigned char* data) {
864  struct pollfd pollfd;
865  pollfd.fd = writeToJimulator;
866  pollfd.events = POLLOUT;
867 
868  // See if output possible
869  if (not poll(&pollfd, 1, OUT_POLL_TIMEOUT)) {
870  std::cout << "Client system not responding!\n"; // communication problem
871  }
872 
873  // Write char_number bytes
874  if (write(writeToJimulator, data, length) == -1) {
875  std::cout << "Pipe write error!\n";
876  }
877 }
878 
883 inline void sendChar(unsigned char data) {
884  sendCharArray(1, &data);
885 }
886 
892 inline void sendNBytes(int data, int n) {
893  if (n > ADDRESS_BUS_WIDTH) {
894  n = ADDRESS_BUS_WIDTH; // Clip n
895  }
896 
897  unsigned char buffer[n];
898 
899  // Conversion to little endian
900  for (auto& c : buffer) {
901  c = getLeastSignificantByte(data);
902  data = rotateRight1Byte(data);
903  }
904 
905  sendCharArray(n, buffer);
906 }
907 
915 inline const int getCharArray(int length, unsigned char* data) {
916  int reply_count; // Number of chars fetched in latest attempt
917  int reply_total = 0;
918  struct pollfd pollfd;
919 
920  pollfd.fd = readFromJimulator;
921  pollfd.events = POLLIN;
922 
923  // while there is more to get
924  while (length > 0) {
925  // If nothing available
926  if (not poll(&pollfd, 1, IN_POLL_TIMEOUT)) {
927  reply_count = 0; // Will force loop termination
928  }
929 
930  // attempt to read the number of bytes requested and store the number of
931  // bytes received
932  else {
933  reply_count = read(readFromJimulator, data, length);
934  }
935 
936  if (reply_count == 0) {
937  length = -1; // Set to terminate
938  }
939 
940  // Set minimum to 0
941  if (reply_count < 0) {
942  reply_count = 0;
943  }
944 
945  reply_total += reply_count;
946  length -= reply_count; // Update No. bytes that are still required
947  data += reply_count; // Move the data pointer to its new location
948  }
949 
950  return reply_total; // return the number of bytes received
951 }
952 
958 inline const int getChar(unsigned char* data) {
959  return getCharArray(1, data);
960 }
961 
971 inline const int getNBytes(int* data, int n) {
972  if (n > ADDRESS_BUS_WIDTH) {
973  n = ADDRESS_BUS_WIDTH; // Clip, just in case
974  }
975 
976  char unsigned buffer[ADDRESS_BUS_WIDTH];
977  int numberOfReceivedBytes = getCharArray(n, buffer);
978  *data = 0;
979 
980  for (int i = 0; i < numberOfReceivedBytes; i++) {
981  *data = *data | (getLeastSignificantByte(buffer[i]) << (i * 8));
982  }
983 
984  return numberOfReceivedBytes;
985 }
986 
991 inline const ClientState getBoardStatus() {
992  unsigned char clientStatus = 0;
993  int stepsSinceReset;
994  int leftOfWalk;
995 
996  // If the board sends back the wrong the amount of data
997  sendChar(static_cast<unsigned char>(BoardInstruction::WOT_U_DO));
998 
999  if (getChar(&clientStatus) != 1 ||
1000  getNBytes(&leftOfWalk, 4) != 4 || // Steps remaining
1001  getNBytes(&stepsSinceReset, 4) != 4) { // Steps since reset
1002  std::cout << "board not responding\n";
1003  return ClientState::BROKEN;
1004  }
1005 
1006  // TODO: clientStatus represents what the board is doing and why - can be
1007  // reflected in the view? and the same with stepsSinceReset
1008 
1009  return static_cast<ClientState>(clientStatus);
1010 }
1011 
1018 inline const std::array<unsigned char, 64> readRegistersIntoArray() {
1019  unsigned char data[64];
1020 
1021  sendChar(static_cast<unsigned char>(BoardInstruction::GET_REG));
1022  sendNBytes(0, 4);
1023  sendNBytes(16, 2);
1024  getCharArray(64, data);
1025 
1026  std::array<unsigned char, 64> ret;
1027  std::copy(std::begin(data), std::end(data), std::begin(ret));
1028  return ret;
1029 }
1030 
1041 inline const std::string integerArrayToHexString(int i,
1042  unsigned char* const v,
1043  const bool prepend0x) {
1044  std::stringstream ss;
1045 
1046  if (prepend0x) {
1047  ss << "0x";
1048  }
1049 
1050  while (i--) {
1051  ss << std::setfill('0') << std::setw(2) << std::uppercase << std::hex
1052  << (int)v[i];
1053  }
1054 
1055  return ss.str();
1056 }
1057 
1068 constexpr const int numericStringToInt(int i, const unsigned char* const s) {
1069  int ret = 0;
1070 
1071  while (i--) {
1072  ret = rotateLeft1Byte(ret) + (s[i]);
1073  }
1074 
1075  return ret;
1076 }
1077 
1088 constexpr void numericStringAndIntAddition(unsigned char* const s, int n) {
1089  int temp = 0;
1090 
1091  for (int i = 0; i < ADDRESS_BUS_WIDTH; i++) {
1092  temp = s[i] + getLeastSignificantByte(n);
1093  s[i] = getLeastSignificantByte(temp);
1094  n = rotateRight1Byte(n); // Shift to next byte
1095  if (temp >= 0x100) {
1096  n++; // Propagate carry
1097  }
1098  }
1099 }
1100 
1109 constexpr const int disassembleSourceFile(SourceFileLine* src,
1110  unsigned int addr) {
1111  if (src == NULL || src == nullptr) {
1112  return 4;
1113  }
1114 
1115  unsigned int diff = src->address - addr; // How far to next line start?
1116 
1117  // Do have a source line, but shan't use it
1118  if (diff == 0) {
1119  src = src->next; // Use the one after
1120  if (src != NULL) {
1121  diff = src->address - addr; // if present
1122  } else {
1123  diff = 1000; // Effectively infinity
1124  }
1125  }
1126 
1127  if (diff < 4) {
1128  return diff; // Next source entry
1129  } else {
1130  return 4 - (addr % 4); // To next word alignment
1131  }
1132 }
1133 
1143 inline const std::unordered_map<u_int32_t, bool> getAllBreakpoints() {
1144  std::unordered_map<u_int32_t, bool> breakpointAddresses;
1145  unsigned int wordA, wordB;
1146  bool error = false;
1147 
1148  // If reading the breakpoints was a success, loops through all of the possible
1149  // breakpoints - if they are active, add them to the map.
1150  if (getBreakpointStatus(&wordA, &wordB)) {
1151  for (int i = 0; (i < MAX_NUMBER_OF_BREAKPOINTS) && not error; i++) {
1152  if (((wordA >> i) & 1) != 0) {
1153  BreakpointInfo bp;
1154 
1155  if (getBreakpointDefinition(i, &bp)) {
1156  u_int32_t addr = numericStringToInt(4, bp.addressA);
1157  breakpointAddresses.insert({addr, true});
1158  } else {
1159  error = true; // Read failure causes loop termination
1160  }
1161  }
1162  }
1163  }
1164 
1165  return breakpointAddresses;
1166 }
1167 
1168 // ! COMPILING STUFF BELOW! !
1169 // ! COMPILING STUFF BELOW! !
1170 // ! COMPILING STUFF BELOW! !
1171 
1175 inline void flushSourceFile() {
1176  SourceFileLine* old = source.pStart;
1177  source.pStart = NULL;
1178  source.pEnd = NULL;
1179 
1180  while (old != NULL) {
1181  if (old->text != NULL) {
1182  g_free(old->text);
1183  }
1184 
1185  SourceFileLine* trash = old;
1186  old = old->next;
1187  g_free(trash);
1188  }
1189 }
1190 
1196 constexpr const int checkHexCharacter(const char character) {
1197  if ((character >= '0') && (character <= '9')) {
1198  return character - '0';
1199  } else if ((character >= 'A') && (character <= 'F')) {
1200  return character - 'A' + 10;
1201  } else if ((character >= 'a') && (character <= 'f')) {
1202  return character - 'a' + 10;
1203  } else {
1204  return -1;
1205  }
1206 }
1207 
1215 constexpr const int readNumberFromFile(FILE* const f,
1216  char* const c,
1217  unsigned int* const n) {
1218  while ((*c == ' ') || (*c == '\t')) {
1219  *c = getc(f); // Skip spaces
1220  }
1221 
1222  int j = 0, value = 0;
1223  for (int digit = checkHexCharacter(*c); digit >= 0;
1224  digit = checkHexCharacter(*c), j++) {
1225  value = (value << 4) | digit; // Accumulate digit
1226  *c = getc(f); // Get next character
1227  } // Exits at first non-hex character (which is discarded)
1228 
1229  j = (j + 1) / 2; // Round digit count to bytes
1230 
1231  int k = 0;
1232  if (j == 0) {
1233  k = 0;
1234  } else {
1235  *n = value; // Only if n found
1236 
1237  if (j > 4) {
1238  k = 4; // Currently clips at 32-bit
1239  } else {
1240  for (k = 1; k < j; k = k << 1) {
1241  ; // Round j to 2^N
1242  }
1243  }
1244  }
1245 
1246  return k;
1247 }
1248 
1254 constexpr const unsigned int boardTranslateMemsize(const int size) {
1255  switch (size) {
1256  case 1:
1257  return 0;
1258  case 2:
1259  return 1;
1260  case 4:
1261  return 2;
1262  case 8:
1263  return 3;
1264  default:
1265  return 0;
1266  }
1267 }
1268 
1278 inline void boardSetMemory(unsigned char* const address,
1279  unsigned char* const value,
1280  const int size) {
1281  sendChar(BoardInstruction::SET_MEM | boardTranslateMemsize(size));
1282  sendCharArray(ADDRESS_BUS_WIDTH, address); // send address
1283  sendNBytes(1, 2); // send width
1284  sendCharArray(size, value);
1285 }
1286 
1292 inline const bool readSourceFile(const char* const pathToKMD) {
1293  // TODO: this function is a jumbled mess, refactor and remove sections
1294  unsigned int oldAddress, dSize[SOURCE_FIELD_COUNT],
1295  dValue[SOURCE_FIELD_COUNT];
1296  int byteTotal, textLength;
1297  char buffer[SOURCE_TEXT_LENGTH + 1]; // + 1 for terminator
1298  SourceFileLine* currentLine;
1299 
1300  // `system` runs the paramter string as a shell command (i.e. it launches a
1301  // new process) `pidof` checks to see if a process by the name `jimulator` is
1302  // running. If it fails (non-zero) It will print an error and return failure.
1303  if (system("pidof -x jimulator > /dev/null")) {
1304  std::cout << "Jimulator is not running!\n";
1305  return false;
1306  }
1307 
1308  // If file cannot be read, return false
1309  FILE* komodoSource = fopen(pathToKMD, "r");
1310  if (komodoSource == NULL) {
1311  std::cout << "Source could not be opened!\n";
1312  return false;
1313  }
1314 
1315  bool hasOldAddress = false; // Don't know where we start
1316 
1317  // Repeat until end of file
1318  while (not feof(komodoSource)) {
1319  unsigned int address = 0; // Really needed?
1320  bool flag = false; // Haven't found an address yet
1321  char c = getc(komodoSource); // The current character being parsed
1322 
1323  // If the first character is a colon, read a symbol record
1324  if (c == ':') {
1325  hasOldAddress = false; // Don't retain position
1326  }
1327 
1328  // Read a source line record
1329  else {
1330  for (int j = 0; j < SOURCE_FIELD_COUNT; j++) {
1331  dSize[j] = 0;
1332  dValue[j] = 0;
1333  }
1334 
1335  byteTotal = 0;
1336  flag = readNumberFromFile(komodoSource, &c, &address) != 0;
1337 
1338  // Read a new address - and if we got an address, try for data fields
1339  if (flag) {
1340  if (c == ':') {
1341  c = getc(komodoSource); // Skip colon
1342  }
1343 
1344  // Loop on data fields
1345  // repeat several times or until `illegal' character met
1346  for (int j = 0; j < SOURCE_FIELD_COUNT; j++) {
1347  dSize[j] = readNumberFromFile(komodoSource, &c, &dValue[j]);
1348 
1349  if (dSize[j] == 0) {
1350  break; // Quit if nothing found
1351  }
1352 
1353  byteTotal = byteTotal + dSize[j]; // Total input
1354  }
1355 
1356  oldAddress = address + byteTotal; // Predicted -next- address
1357  hasOldAddress = true;
1358  }
1359  // Address field not found Maybe something useable?
1360  else if (hasOldAddress) {
1361  address = oldAddress; // Use predicted address
1362  flag = true; // Note we do have an address
1363  }
1364 
1365  // We have a record with an address
1366  if (flag) {
1367  while ((c != ';') && (c != '\n') && not feof(komodoSource)) {
1368  c = getc(komodoSource);
1369  }
1370 
1371  // Check for field separator
1372  if (c == ';') {
1373  c = getc(komodoSource);
1374  if (c == ' ') {
1375  c = getc(komodoSource); // Skip formatting space
1376  }
1377 
1378  textLength = 0; // Measure (& buffer) source line
1379 
1380  // Everything to end of line (or clip)
1381  while ((c != '\n') && not feof(komodoSource) &&
1382  (textLength < SOURCE_TEXT_LENGTH)) {
1383  buffer[textLength++] = c;
1384  c = getc(komodoSource);
1385  }
1386 
1387  buffer[textLength++] = '\0'; // textLength now length incl. '\0'
1388  currentLine = g_new(SourceFileLine, 1); // Create new record
1389  currentLine->address = address;
1390 
1391  byteTotal = 0; // Inefficient
1392  for (int j = 0; j < SOURCE_FIELD_COUNT; j++) {
1393  currentLine->dataSize[j] = dSize[j]; // Bytes, not digits
1394  currentLine->dataValue[j] = dValue[j];
1395 
1396  if ((currentLine->dataSize[j] > 0) &&
1397  ((currentLine->dataSize[j] + byteTotal) <= SOURCE_BYTE_COUNT)) {
1398  unsigned char addr[4], data[4];
1399 
1400  for (int i = 0; i < 4; i++) {
1401  addr[i] =
1402  getLeastSignificantByte((address + byteTotal) >> (8 * i));
1403  }
1404  for (int i = 0; i < currentLine->dataSize[j]; i++) {
1405  data[i] = getLeastSignificantByte(currentLine->dataValue[j] >>
1406  (8 * i));
1407  }
1408 
1409  // Ignore Boolean error return value for now
1410  boardSetMemory(addr, data, currentLine->dataSize[j]);
1411  }
1412 
1413  byteTotal = byteTotal + currentLine->dataSize[j];
1414  currentLine->hasData = (byteTotal != 0); // If blank line
1415  }
1416 
1417  // clips source record - essential
1418  if (byteTotal > SOURCE_BYTE_COUNT) {
1419  int m = 0;
1420 
1421  for (int j = 0; j < SOURCE_FIELD_COUNT; j++) {
1422  m = m + currentLine->dataSize[j];
1423  if (m <= SOURCE_BYTE_COUNT) {
1424  dSize[j] = 0;
1425  byteTotal = byteTotal - currentLine->dataSize[j];
1426  } else {
1427  dSize[j] = currentLine->dataSize[j]; // Bytes, not digits
1428  currentLine->dataSize[j] = 0;
1429  }
1430  }
1431 
1432  // error here?
1433  std::cout << "OVERFLOW " << dSize[0] << " " << dSize[1] << " "
1434  << dSize[2] << " " << dSize[3] << " " << byteTotal
1435  << std::endl;
1436  }
1437 
1438  // Copy text to buffer
1439  currentLine->text = g_new(char, textLength);
1440  for (int j = 0; j < textLength; j++) {
1441  currentLine->text[j] = buffer[j];
1442  }
1443 
1444  SourceFileLine* temp1 = source.pStart;
1445  SourceFileLine* temp2 = NULL;
1446 
1447  while ((temp1 != NULL) && (address >= temp1->address)) {
1448  temp2 = temp1;
1449  temp1 = temp1->next;
1450  }
1451 
1452  currentLine->next = temp1;
1453  currentLine->prev = temp2;
1454 
1455  if (temp1 != NULL) {
1456  temp1->prev = currentLine;
1457  } else {
1458  source.pEnd = currentLine;
1459  }
1460 
1461  if (temp2 != NULL) {
1462  temp2->next = currentLine;
1463  } else {
1464  source.pStart = currentLine;
1465  }
1466  }
1467  } // Source line
1468  }
1469 
1470  // Get the next relevant character
1471  while ((c != '\n') && not feof(komodoSource)) {
1472  c = getc(komodoSource);
1473  }
1474  }
1475 
1476  fclose(komodoSource);
1477  return true;
1478 }
const std::string integerArrayToHexString(int, unsigned char *const, const bool=false)
Converts an array of integers into a formatted hexadecimal string.
unsigned int address
The address of the source line.
Definition: kcmd.cpp:188
Describes an entire file of a .kmd sourceFile.
Definition: kcmd.cpp:209
void sendCharArray(int, unsigned char *)
Sends an array of characters to Jimulator.
unsigned char operator|(BoardInstruction l, unsigned char r)
Performing an or between a BoardInstruction and an unsigned char.
constexpr void copyStringLiterals(int, unsigned char *, unsigned char *)
Copy one string literal into another string literal.
constexpr int IN_POLL_TIMEOUT
The maximum amount of time to wait after sending input to the pipes.
bool hasData
A flag that indicates that the line stores internal data or not.
Definition: kcmd.cpp:183
char * text
Text, as read from the source file.
Definition: kcmd.cpp:203
SourceFileLine * pEnd
The last line in a source file.
Definition: kcmd.cpp:219
void resetJimulator()
Reset the emulators running.
Definition: kcmd.cpp:363
const int getCharArray(int, unsigned char *)
reads an array of characters from Jimulator.
unsigned char addressB[ADDRESS_BUS_WIDTH]
A secondary address for a breakpoint.
Definition: kcmd.cpp:101
const std::string generateMemoryHex(SourceFileLine **src, const uint32_t s_address, int *const increment, const int currentAddressI, unsigned char(*memdata)[52])
Get the hex values from the memory data.
const bool getBreakpointStatus(unsigned int *, unsigned int *)
Gets the status of breakpoints from within Jimulator.
unsigned char dataA[8]
Data associated with the breakpoint.
Definition: kcmd.cpp:108
constexpr const unsigned int boardTranslateMemsize(const int size)
Converts a provided memory size into a Jimulator legal memory size.
void compileJimulator(std::string pathToBin, const char *const pathToS, const char *const pathToKMD)
Runs pathToS through the associated compiler binary, and outputs a .kmd file at pathToKMD.
Definition: kcmd.cpp:283
constexpr int SOURCE_FIELD_COUNT
The number of fields that can be used in a source file.
unsigned int misc
Miscellaneous information associated with the breakpoint.
Definition: kcmd.cpp:122
unsigned char addressA[ADDRESS_BUS_WIDTH]
The address of the breakpoint.
Definition: kcmd.cpp:94
const bool setBreakpoint(const uint32_t address)
Sets a breakpoint.
Definition: kcmd.cpp:372
int writeToJimulator
Stores the file descriptor used for writing to Jimulator.
Definition: kcmd.cpp:79
constexpr int SOURCE_BYTE_COUNT
The maximum number of bytes that can be read from a source file.
constexpr int OUT_POLL_TIMEOUT
The maximum amount of time to wait waiting for output from the pipes.
Describes a single line of a .kmd file.
Definition: kcmd.cpp:168
void setBreakpointStatus(unsigned int, unsigned int)
Overwrites some breakpoint information into Jimulator.
constexpr const int rotateRight1Byte(const int val)
Rotates an integers bits to the right by 1 byte.
unsigned char dataB[8]
Data associated with the secondary breakpoint.
Definition: kcmd.cpp:115
constexpr const char getLeastSignificantByte(const int)
Get the least significant byte out of an integer - if little endian, get the most signficant byte...
constexpr int SOURCE_TEXT_LENGTH
The maximum length of a line in a source file.
constexpr int ADDRESS_BUS_WIDTH
The width of Jimulators internal address bus.
void sendChar(unsigned char)
Sends a singular character to Jimulator.
constexpr const int disassembleSourceFile(SourceFileLine *, unsigned int)
Calculates the difference between the current address to display and the next address that needs to b...
void pauseJimulator()
Pauses the emulator running.
Definition: kcmd.cpp:356
SourceFileLine * pStart
The first line in a source file.
Definition: kcmd.cpp:214
const int getNBytes(int *, int)
Reads n bytes of data from Jimulator.
const std::unordered_map< u_int32_t, bool > getAllBreakpoints()
Reads all of the breakpoints from Jimulator into a map that can be indexed by address. The address is the key, with a boolean as the value to form a pair. However the boolean is redundant - since the address is the key, if you lookup an address in the map and it is present, you know that a breakpoint was found there.
constexpr const int checkHexCharacter(const char character)
Check if the passed character represents a legal hex digit.
int dataValue[4]
Stores the data values.
Definition: kcmd.cpp:198
constexpr const int numericStringSubtraction(const unsigned char *const, const unsigned char *const)
Takes two string literals of equal length which represent string forms of integers - for example...
constexpr const bool moveSrc(bool firstFlag, SourceFileLine **src)
Steps any given source line to the next valid source line.
sourceFile source
The source file that is currently loaded into Jimulator.
void startJimulator(const int steps)
Commences running the emulator.
Definition: kcmd.cpp:335
constexpr const int rotateLeft1Byte(const int val)
Rotates an integers bits to the left by 1 byte.
const bool sendTerminalInputToJimulator(const unsigned int val)
Sends terminal information to Jimulator.
Definition: kcmd.cpp:499
void setBreakpointDefinition(unsigned int, BreakpointInfo *)
Writes a new breakpoint into the breakpoint list.
constexpr int MAX_NUMBER_OF_BREAKPOINTS
The maximum number of breakpoints within the application.
const std::array< unsigned char, 64 > readRegistersIntoArray()
Gets serialized bit data from the board that represents 16 register values - 15 general purpose regis...
const bool loadJimulator(const char *const pathToKMD)
Clears the existing source object and loads the file at pathToKMD into Jimulator. ...
Definition: kcmd.cpp:326
int readFromJimulator
Stores the file descriptor used for reading from Jimulator.
Definition: kcmd.cpp:80
const int getChar(unsigned char *)
Reads a singular character from Jimulator.
void flushSourceFile()
removes all of the old references to the previous file.
constexpr const int getNextFreeBreakpoint(const int)
Gets the index of the next free breakpoint from Jimulators internal breakpoint list.
The header file associated with the jimulatorInterface.c file - specifies functions which can be acce...
SourceFileLine * next
The next line of the overall source file.
Definition: kcmd.cpp:178
SourceFileLine * prev
The previous line of the overall source file.
Definition: kcmd.cpp:173
const ClientState getBoardStatus()
Gets a code that indicates the internal state of Jimulator.
void continueJimulator()
Continues running Jimulator.
Definition: kcmd.cpp:346
constexpr void numericStringAndIntAddition(unsigned char *const, int)
Takes a string representation of an integer - for example, the string {&#39;5&#39; &#39;7&#39; &#39;2&#39;} representing the ...
const bool readSourceFile(const char *const)
Reads the source of the file pointer to by pathToKMD.
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
constexpr const int readNumberFromFile(FILE *const f, char *const c, unsigned int *const n)
Reads a n from a string of text in the .kmd file.
int compilerCommunication[2]
The pipe that handles communication between the compiler process and KoMo2.
Definition: kcmd.cpp:78
const bool getBreakpointDefinition(unsigned int, BreakpointInfo *)
Reads a breakpoint definition for use by the breakpoints callbacks.
void boardSetMemory(unsigned char *const address, unsigned char *const value, const int size)
Sets a memory value of a given address to a new value. This code is LEGACY. It used to run with a che...
Contains the information read from Jimulator about a given breakpoint.
Definition: kcmd.cpp:89
const ClientState checkBoardState()
Check the state of the board - logs what it is doing.
Definition: kcmd.cpp:422
constexpr const int numericStringToInt(int, const unsigned char *const)
Takes a string literals which represent a string form of an integer - for example, the number 5 represented as the string {&#39;5&#39;}, or the number 327 represented as the string {&#39;3&#39;, &#39;2&#39;, &#39;7&#39;} - and returns the value represented as an int. For example: Input string {&#39;8&#39;, &#39;1&#39;, &#39;8&#39;} will result in the output 818.
const std::string getJimulatorTerminalMessages()
Reads for messages from Jimulator, to display in the terminal output.
Definition: kcmd.cpp:470
void sendNBytes(int, int)
Writes n bytes of data to Jimulator.
const std::array< std::string, 16 > getJimulatorRegisterValues()
Queries a register in Jimulator to get it&#39;s current value.
Definition: kcmd.cpp:453
int dataSize[4]
Stores the size of the data fields.
Definition: kcmd.cpp:193