openMSX
DebugDevice.cc
Go to the documentation of this file.
1 #include "DebugDevice.hh"
2 #include "Clock.hh"
3 #include "FileOperations.hh"
4 #include "serialize.hh"
5 #include <iostream>
6 #include <iomanip>
7 
8 using std::string;
9 
10 namespace openmsx {
11 
13  : MSXDevice(config)
14  , fileNameSetting(
15  getCommandController(), "debugoutput",
16  "name of the file the debugdevice outputs to",
17  config.getChildData("filename", "stdout"))
18 {
19  openOutput(fileNameSetting.getString());
20  reset(EmuTime::dummy());
21 }
22 
23 void DebugDevice::reset(EmuTime::param /*time*/)
24 {
25  mode = OFF;
26  modeParameter = 0;
27 }
28 
29 void DebugDevice::writeIO(word port, byte value, EmuTime::param time)
30 {
31  const auto& newName = fileNameSetting.getString();
32  if (newName != fileNameString) {
33  openOutput(newName);
34  }
35 
36  switch (port & 0x01) {
37  case 0:
38  switch ((value & 0x30) >> 4) {
39  case 0:
40  mode = OFF;
41  break;
42  case 1:
43  mode = SINGLEBYTE;
44  modeParameter = value & 0x0F;
45  break;
46  case 2:
47  mode = MULTIBYTE;
48  modeParameter = value & 0x03;
49  break;
50  case 3:
51  break;
52  }
53  if (!(value & 0x40)){
54  (*outputstrm) << '\n' << std::flush;
55  }
56  break;
57  case 1:
58  switch (mode) {
59  case OFF:
60  break;
61  case SINGLEBYTE:
62  outputSingleByte(value, time);
63  break;
64  case MULTIBYTE:
65  outputMultiByte(value);
66  break;
67  default:
68  break;
69  }
70  break;
71  }
72 }
73 
74 void DebugDevice::outputSingleByte(byte value, EmuTime::param time)
75 {
76  if (modeParameter & 0x01) {
77  displayByte(value, HEX);
78  }
79  if (modeParameter & 0x02) {
80  displayByte(value, BIN);
81  }
82  if (modeParameter & 0x04) {
83  displayByte(value, DEC);
84  }
85  if (modeParameter & 0x08) {
86  (*outputstrm) << '\'';
87  byte tmp = ((value >= ' ') && (value != 127)) ? value : '.';
88  displayByte(tmp, ASC);
89  (*outputstrm) << "' ";
90  }
91  Clock<3579545> zero(EmuTime::zero);
92  (*outputstrm) << "emutime: " << std::dec << zero.getTicksTill(time);
93  if ((modeParameter & 0x08) && ((value < ' ') || (value == 127))) {
94  displayByte(value, ASC); // do special effects
95  }
96  (*outputstrm) << '\n' << std::flush;
97 }
98 
99 void DebugDevice::outputMultiByte(byte value)
100 {
101  DisplayType dispType;
102  switch (modeParameter) {
103  case 0:
104  dispType = HEX;
105  break;
106  case 1:
107  dispType = BIN;
108  break;
109  case 2:
110  dispType = DEC;
111  break;
112  case 3:
113  default:
114  dispType = ASC;
115  break;
116  }
117  displayByte(value, dispType);
118 }
119 
120 void DebugDevice::displayByte(byte value, DisplayType type)
121 {
122  switch (type) {
123  case HEX:
124  (*outputstrm) << std::hex << std::setw(2)
125  << std::setfill('0')
126  << int(value) << "h " << std::flush;
127  break;
128  case BIN: {
129  for (byte mask = 0x80; mask; mask >>= 1) {
130  (*outputstrm) << ((value & mask) ? '1' : '0');
131  }
132  (*outputstrm) << "b " << std::flush;
133  break;
134  }
135  case DEC:
136  (*outputstrm) << std::dec << std::setw(3)
137  << std::setfill('0')
138  << int(value) << ' ' << std::flush;
139  break;
140  case ASC:
141  (*outputstrm).put(value);
142  (*outputstrm) << std::flush;
143  break;
144  }
145 }
146 
147 void DebugDevice::openOutput(string_view name)
148 {
149  fileNameString = name.str();
150  debugOut.close();
151  if (name == "stdout") {
152  outputstrm = &std::cout;
153  } else if (name == "stderr") {
154  outputstrm = &std::cerr;
155  } else {
156  string realName = FileOperations::expandTilde(name);
157  FileOperations::openofstream(debugOut, realName, std::ios::app);
158  outputstrm = &debugOut;
159  }
160 }
161 
162 static std::initializer_list<enum_string<DebugDevice::DebugMode>> debugModeInfo = {
163  { "OFF", DebugDevice::OFF },
164  { "SINGLEBYTE", DebugDevice::SINGLEBYTE },
165  { "MULTIBYTE", DebugDevice::MULTIBYTE },
166  { "ASCII", DebugDevice::ASCII }
167 };
168 SERIALIZE_ENUM(DebugDevice::DebugMode, debugModeInfo);
169 
170 template<typename Archive>
171 void DebugDevice::serialize(Archive& ar, unsigned /*version*/)
172 {
173  ar.template serializeBase<MSXDevice>(*this);
174  ar.serialize("mode", mode);
175  ar.serialize("modeParameter", modeParameter);
176 }
178 REGISTER_MSXDEVICE(DebugDevice, "DebugDevice");
179 
180 } // namespace openmsx
unsigned getTicksTill(EmuTime::param e) const
Calculate the number of ticks for this clock until the given time.
Definition: Clock.hh:58
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
string_view getString() const
void openofstream(std::ofstream &stream, const std::string &filename)
Open an ofstream in a platform-independent manner.
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
void reset(EmuTime::param time) override
This method is called on reset.
Definition: DebugDevice.cc:23
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
void serialize(Archive &ar, unsigned version)
Definition: DebugDevice.cc:171
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX...
Definition: MSXDevice.hh:31
void writeIO(word port, byte value, EmuTime::param time) override
Write a byte to a given IO port at a certain time to this device.
Definition: DebugDevice.cc:29
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
This class implements a (close approximation) of the std::string_view class.
Definition: string_view.hh:16
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:840
std::string str() const
Definition: string_view.cc:12
string expandTilde(string_view path)
Expand the &#39;~&#39; character to the users home directory.
DebugDevice(const DeviceConfig &config)
Definition: DebugDevice.cc:12