DebugDevice.cc 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. #include "DebugDevice.hh"
  2. #include "Clock.hh"
  3. #include "FileOperations.hh"
  4. #include "serialize.hh"
  5. #include <iostream>
  6. #include <iomanip>
  7. using std::string;
  8. namespace openmsx {
  9. DebugDevice::DebugDevice(const DeviceConfig& config)
  10. : MSXDevice(config)
  11. , fileNameSetting(
  12. getCommandController(), "debugoutput",
  13. "name of the file the debugdevice outputs to",
  14. config.getChildData("filename", "stdout"))
  15. {
  16. openOutput(fileNameSetting.getString());
  17. reset(EmuTime::dummy());
  18. }
  19. void DebugDevice::reset(EmuTime::param /*time*/)
  20. {
  21. mode = OFF;
  22. modeParameter = 0;
  23. }
  24. void DebugDevice::writeIO(word port, byte value, EmuTime::param time)
  25. {
  26. const auto& newName = fileNameSetting.getString();
  27. if (newName != fileNameString) {
  28. openOutput(newName);
  29. }
  30. switch (port & 0x01) {
  31. case 0:
  32. switch ((value & 0x30) >> 4) {
  33. case 0:
  34. mode = OFF;
  35. break;
  36. case 1:
  37. mode = SINGLEBYTE;
  38. modeParameter = value & 0x0F;
  39. break;
  40. case 2:
  41. mode = MULTIBYTE;
  42. modeParameter = value & 0x03;
  43. break;
  44. case 3:
  45. break;
  46. }
  47. if (!(value & 0x40)){
  48. (*outputstrm) << '\n' << std::flush;
  49. }
  50. break;
  51. case 1:
  52. switch (mode) {
  53. case OFF:
  54. break;
  55. case SINGLEBYTE:
  56. outputSingleByte(value, time);
  57. break;
  58. case MULTIBYTE:
  59. outputMultiByte(value);
  60. break;
  61. default:
  62. break;
  63. }
  64. break;
  65. }
  66. }
  67. void DebugDevice::outputSingleByte(byte value, EmuTime::param time)
  68. {
  69. if (modeParameter & 0x01) {
  70. displayByte(value, HEX);
  71. }
  72. if (modeParameter & 0x02) {
  73. displayByte(value, BIN);
  74. }
  75. if (modeParameter & 0x04) {
  76. displayByte(value, DEC);
  77. }
  78. if (modeParameter & 0x08) {
  79. (*outputstrm) << '\'';
  80. byte tmp = ((value >= ' ') && (value != 127)) ? value : '.';
  81. displayByte(tmp, ASC);
  82. (*outputstrm) << "' ";
  83. }
  84. Clock<3579545> zero(EmuTime::zero());
  85. (*outputstrm) << "emutime: " << std::dec << zero.getTicksTill(time);
  86. if ((modeParameter & 0x08) && ((value < ' ') || (value == 127))) {
  87. displayByte(value, ASC); // do special effects
  88. }
  89. (*outputstrm) << '\n' << std::flush;
  90. }
  91. void DebugDevice::outputMultiByte(byte value)
  92. {
  93. DisplayType dispType;
  94. switch (modeParameter) {
  95. case 0:
  96. dispType = HEX;
  97. break;
  98. case 1:
  99. dispType = BIN;
  100. break;
  101. case 2:
  102. dispType = DEC;
  103. break;
  104. case 3:
  105. default:
  106. dispType = ASC;
  107. break;
  108. }
  109. displayByte(value, dispType);
  110. }
  111. void DebugDevice::displayByte(byte value, DisplayType type)
  112. {
  113. switch (type) {
  114. case HEX:
  115. (*outputstrm) << std::hex << std::setw(2)
  116. << std::setfill('0')
  117. << int(value) << "h " << std::flush;
  118. break;
  119. case BIN: {
  120. for (byte mask = 0x80; mask; mask >>= 1) {
  121. (*outputstrm) << ((value & mask) ? '1' : '0');
  122. }
  123. (*outputstrm) << "b " << std::flush;
  124. break;
  125. }
  126. case DEC:
  127. (*outputstrm) << std::dec << std::setw(3)
  128. << std::setfill('0')
  129. << int(value) << ' ' << std::flush;
  130. break;
  131. case ASC:
  132. (*outputstrm).put(value);
  133. (*outputstrm) << std::flush;
  134. break;
  135. }
  136. }
  137. void DebugDevice::openOutput(std::string_view name)
  138. {
  139. fileNameString = name;
  140. debugOut.close();
  141. if (name == "stdout") {
  142. outputstrm = &std::cout;
  143. } else if (name == "stderr") {
  144. outputstrm = &std::cerr;
  145. } else {
  146. string realName = FileOperations::expandTilde(name);
  147. FileOperations::openofstream(debugOut, realName, std::ios::app);
  148. outputstrm = &debugOut;
  149. }
  150. }
  151. static std::initializer_list<enum_string<DebugDevice::DebugMode>> debugModeInfo = {
  152. { "OFF", DebugDevice::OFF },
  153. { "SINGLEBYTE", DebugDevice::SINGLEBYTE },
  154. { "MULTIBYTE", DebugDevice::MULTIBYTE },
  155. { "ASCII", DebugDevice::ASCII }
  156. };
  157. SERIALIZE_ENUM(DebugDevice::DebugMode, debugModeInfo);
  158. template<typename Archive>
  159. void DebugDevice::serialize(Archive& ar, unsigned /*version*/)
  160. {
  161. ar.template serializeBase<MSXDevice>(*this);
  162. ar.serialize("mode", mode,
  163. "modeParameter", modeParameter);
  164. }
  165. INSTANTIATE_SERIALIZE_METHODS(DebugDevice);
  166. REGISTER_MSXDEVICE(DebugDevice, "DebugDevice");
  167. } // namespace openmsx