openMSX
WatchPoint.cc
Go to the documentation of this file.
1#include "WatchPoint.hh"
2
3#include "Interpreter.hh"
4#include "MSXCPUInterface.hh"
5#include "MSXMotherBoard.hh"
6#include "Reactor.hh"
8#include "TclObject.hh"
9
10#include "checked_cast.hh"
11#include "one_of.hh"
12
13#include <cassert>
14#include <memory>
15
16namespace openmsx {
17
18// class WatchPoint
19
20void WatchPoint::registerIOWatch(MSXMotherBoard& motherBoard, std::span<MSXDevice*, 256> devices)
21{
22 if (!beginAddr || !endAddr || !isEnabled()) return;
24 assert(!registered);
25 assert(*beginAddr < 0x100 && *endAddr < 0x100 && *beginAddr <= *endAddr);
26 for (unsigned port = *beginAddr; port <= *endAddr; ++port) {
27 // create new MSXWatchIOdevice ...
28 auto& dev = ios.emplace_back(std::make_unique<MSXWatchIODevice>(
29 *motherBoard.getMachineConfig(), *this));
30 // ... and insert (prepend) in chain
31 dev->getDevicePtr() = devices[port];
32 devices[port] = dev.get();
33 }
34 registered = true;
35}
36
37void WatchPoint::unregisterIOWatch(std::span<MSXDevice*, 256> devices)
38{
39 if (!beginAddr || !endAddr || !isEnabled()) return;
41 assert(registered);
42 assert(*beginAddr < 0x100 && *endAddr < 0x100 && *beginAddr <= *endAddr);
43 for (unsigned port = *beginAddr; port <= *endAddr; ++port) {
44 // find pointer to watchpoint
45 MSXDevice** prev = &devices[port];
46 while (*prev != ios[port - *beginAddr].get()) {
47 prev = &checked_cast<MSXWatchIODevice*>(*prev)->getDevicePtr();
48 }
49 // remove watchpoint from chain
50 *prev = checked_cast<MSXWatchIODevice*>(*prev)->getDevicePtr();
51 }
52 ios.clear();
53 registered = false;
54}
55
56void WatchPoint::doReadCallback(MSXMotherBoard& motherBoard, unsigned port)
57{
58 auto& cpuInterface = motherBoard.getCPUInterface();
59 if (cpuInterface.isFastForward()) return;
60
61 auto& reactor = motherBoard.getReactor();
62 auto& cliComm = reactor.getGlobalCliComm();
63 auto& interp = reactor.getInterpreter();
64 interp.setVariable(TclObject("wp_last_address"), TclObject(int(port)));
65
66 // keep this object alive by holding a shared_ptr to it, for the case
67 // this watchpoint deletes itself in checkAndExecute()
68 auto keepAlive = shared_from_this();
69 auto scopedBlock = motherBoard.getStateChangeDistributor().tempBlockNewEventsDuringReplay();
70 if (bool remove = checkAndExecute(cliComm, interp); remove) {
71 cpuInterface.removeWatchPoint(keepAlive);
72 }
73
74 interp.unsetVariable("wp_last_address");
75}
76
77void WatchPoint::doWriteCallback(MSXMotherBoard& motherBoard, unsigned port, unsigned value)
78{
79 auto& cpuInterface = motherBoard.getCPUInterface();
80 if (cpuInterface.isFastForward()) return;
81
82 auto& reactor = motherBoard.getReactor();
83 auto& cliComm = reactor.getGlobalCliComm();
84 auto& interp = reactor.getInterpreter();
85 interp.setVariable(TclObject("wp_last_address"), TclObject(int(port)));
86 interp.setVariable(TclObject("wp_last_value"), TclObject(int(value)));
87
88 // see comment in doReadCallback() above
89 auto keepAlive = shared_from_this();
90 auto scopedBlock = motherBoard.getStateChangeDistributor().tempBlockNewEventsDuringReplay();
91 if (bool remove = checkAndExecute(cliComm, interp); remove) {
92 cpuInterface.removeWatchPoint(keepAlive);
93 }
94
95 interp.unsetVariable("wp_last_address");
96 interp.unsetVariable("wp_last_value");
97}
98
99
100// class MSXWatchIODevice
101
103 const HardwareConfig& hwConf, WatchPoint& wp_)
104 : MSXMultiDevice(hwConf)
105 , wp(wp_)
106{
107}
108
109const std::string& MSXWatchIODevice::getName() const
110{
111 assert(device);
112 return device->getName();
113}
114
115byte MSXWatchIODevice::peekIO(word port, EmuTime::param time) const
116{
117 assert(device);
118 return device->peekIO(port, time);
119}
120
121byte MSXWatchIODevice::readIO(word port, EmuTime::param time)
122{
123 assert(device);
124
125 // first trigger watchpoint, then read from device
126 wp.doReadCallback(getMotherBoard(), port);
127 return device->readIO(port, time);
128}
129
130void MSXWatchIODevice::writeIO(word port, byte value, EmuTime::param time)
131{
132 assert(device);
133
134 // first write to device, then trigger watchpoint
135 device->writeIO(port, value, time);
136 wp.doWriteCallback(getMotherBoard(), port, value);
137}
138
139} // namespace openmsx
bool checkAndExecute(GlobalCliComm &cliComm, Interpreter &interp)
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.hh:36
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition MSXDevice.cc:70
virtual void writeIO(word port, byte value, EmuTime::param time)
Write a byte to a given IO port at a certain time to this device.
Definition MSXDevice.cc:408
virtual byte peekIO(word port, EmuTime::param time) const
Read a byte from a given IO port.
Definition MSXDevice.cc:413
virtual const std::string & getName() const
Returns a human-readable name for this device.
Definition MSXDevice.cc:375
virtual byte readIO(word port, EmuTime::param time)
Read a byte from an IO port at a certain time from this device.
Definition MSXDevice.cc:402
const HardwareConfig * getMachineConfig() const
MSXCPUInterface & getCPUInterface()
StateChangeDistributor & getStateChangeDistributor()
MSXWatchIODevice(const HardwareConfig &hwConf, WatchPoint &wp)
GlobalCliComm & getGlobalCliComm()
Definition Reactor.hh:90
void registerIOWatch(MSXMotherBoard &motherBoard, std::span< MSXDevice *, 256 > devices)
Definition WatchPoint.cc:20
Type getType() const
void unregisterIOWatch(std::span< MSXDevice *, 256 > devices)
Definition WatchPoint.cc:37
This file implemented 3 utility functions:
Definition Autofire.cc:11
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
auto remove(ForwardRange &&range, const T &value)
Definition ranges.hh:291