You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(6) |
Nov
(80) |
Dec
(239) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(168) |
Feb
(177) |
Mar
(233) |
Apr
(172) |
May
(74) |
Jun
(107) |
Jul
(77) |
Aug
(133) |
Sep
(85) |
Oct
(108) |
Nov
(87) |
Dec
(96) |
2003 |
Jan
(218) |
Feb
(134) |
Mar
(273) |
Apr
(127) |
May
(304) |
Jun
(498) |
Jul
(231) |
Aug
(301) |
Sep
(181) |
Oct
(258) |
Nov
(229) |
Dec
(207) |
2004 |
Jan
(169) |
Feb
(181) |
Mar
(255) |
Apr
(468) |
May
(467) |
Jun
(241) |
Jul
(146) |
Aug
(157) |
Sep
(260) |
Oct
(656) |
Nov
(148) |
Dec
(199) |
2005 |
Jan
(257) |
Feb
(250) |
Mar
(206) |
Apr
(102) |
May
(215) |
Jun
(251) |
Jul
(104) |
Aug
(116) |
Sep
(176) |
Oct
(154) |
Nov
(281) |
Dec
(212) |
2006 |
Jan
(255) |
Feb
(157) |
Mar
(145) |
Apr
(179) |
May
(170) |
Jun
(96) |
Jul
(153) |
Aug
(106) |
Sep
(222) |
Oct
(94) |
Nov
(88) |
Dec
(66) |
2007 |
Jan
(59) |
Feb
(105) |
Mar
(114) |
Apr
(193) |
May
(145) |
Jun
(120) |
Jul
(79) |
Aug
(114) |
Sep
(234) |
Oct
(105) |
Nov
(113) |
Dec
(163) |
2008 |
Jan
(96) |
Feb
(35) |
Mar
(105) |
Apr
(64) |
May
(85) |
Jun
(92) |
Jul
(139) |
Aug
(81) |
Sep
(84) |
Oct
(55) |
Nov
(45) |
Dec
(56) |
2009 |
Jan
(110) |
Feb
(184) |
Mar
(150) |
Apr
(235) |
May
(267) |
Jun
(169) |
Jul
(180) |
Aug
(141) |
Sep
(191) |
Oct
(103) |
Nov
(118) |
Dec
(225) |
2010 |
Jan
(149) |
Feb
(90) |
Mar
(62) |
Apr
(46) |
May
(30) |
Jun
(110) |
Jul
(48) |
Aug
(45) |
Sep
(37) |
Oct
(36) |
Nov
(48) |
Dec
(81) |
2011 |
Jan
(75) |
Feb
(39) |
Mar
(105) |
Apr
(67) |
May
(31) |
Jun
(19) |
Jul
(16) |
Aug
(43) |
Sep
(36) |
Oct
(15) |
Nov
(9) |
Dec
(24) |
2012 |
Jan
(52) |
Feb
(34) |
Mar
(34) |
Apr
(35) |
May
(81) |
Jun
(114) |
Jul
(77) |
Aug
(68) |
Sep
(57) |
Oct
(30) |
Nov
(75) |
Dec
(116) |
2013 |
Jan
(30) |
Feb
(42) |
Mar
(30) |
Apr
(45) |
May
(49) |
Jun
(29) |
Jul
(63) |
Aug
(62) |
Sep
(21) |
Oct
(21) |
Nov
(58) |
Dec
(32) |
2014 |
Jan
(86) |
Feb
(48) |
Mar
(21) |
Apr
(20) |
May
(68) |
Jun
(42) |
Jul
(33) |
Aug
(28) |
Sep
(33) |
Oct
(23) |
Nov
(43) |
Dec
(11) |
2015 |
Jan
(13) |
Feb
(13) |
Mar
(13) |
Apr
(12) |
May
(50) |
Jun
(10) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2019 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Wouter V. <m97...@us...> - 2015-05-07 18:03:52
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 66481e5ceb6451dc09fb01b40768b88e803ac06e (commit) from 58d99581db80c165c4a6c0e0ad1e973392270c16 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 66481e5ceb6451dc09fb01b40768b88e803ac06e Author: m9710797 <ver...@gm...> Date: Thu May 7 20:03:38 2015 +0200 Semaphore class was removed .. adjust vs build ----------------------------------------------------------------------- Summary of changes: build/msvc/openmsx.vcxproj | 2 -- build/msvc/openmsx.vcxproj.filters | 6 ------ 2 files changed, 0 insertions(+), 8 deletions(-) diff --git a/build/msvc/openmsx.vcxproj b/build/msvc/openmsx.vcxproj index 2bad3b1..394f07d 100644 --- a/build/msvc/openmsx.vcxproj +++ b/build/msvc/openmsx.vcxproj @@ -583,7 +583,6 @@ <ClCompile Include="$(OpenMSXSrcDir)\sound\YMF262.cc" /> <ClCompile Include="$(OpenMSXSrcDir)\sound\YMF278.cc" /> <ClCompile Include="$(OpenMSXSrcDir)\thread\CondVar.cc" /> - <ClCompile Include="$(OpenMSXSrcDir)\thread\Semaphore.cc" /> <ClCompile Include="$(OpenMSXSrcDir)\thread\Thread.cc" /> <ClCompile Include="$(OpenMSXSrcDir)\thread\Timer.cc" /> <ClCompile Include="$(OpenMSXSrcDir)\utils\Tiger.cc" /> @@ -1122,7 +1121,6 @@ <None Include="$(OpenMSXSrcDir)\sound\YMF262.hh" /> <None Include="$(OpenMSXSrcDir)\sound\YMF278.hh" /> <None Include="$(OpenMSXSrcDir)\thread\CondVar.hh" /> - <None Include="$(OpenMSXSrcDir)\thread\Semaphore.hh" /> <None Include="$(OpenMSXSrcDir)\thread\Thread.hh" /> <None Include="$(OpenMSXSrcDir)\thread\Timer.hh" /> <None Include="$(OpenMSXSrcDir)\utils\Aligned.hh" /> diff --git a/build/msvc/openmsx.vcxproj.filters b/build/msvc/openmsx.vcxproj.filters index 4e267fe..0fb5d1a 100644 --- a/build/msvc/openmsx.vcxproj.filters +++ b/build/msvc/openmsx.vcxproj.filters @@ -885,9 +885,6 @@ <ClCompile Include="$(OpenMSXSrcDir)\thread\CondVar.cc"> <Filter>thread</Filter> </ClCompile> - <ClCompile Include="$(OpenMSXSrcDir)\thread\Semaphore.cc"> - <Filter>thread</Filter> - </ClCompile> <ClCompile Include="$(OpenMSXSrcDir)\thread\Thread.cc"> <Filter>thread</Filter> </ClCompile> @@ -2234,9 +2231,6 @@ <None Include="$(OpenMSXSrcDir)\thread\CondVar.hh"> <Filter>thread</Filter> </None> - <None Include="$(OpenMSXSrcDir)\thread\Semaphore.hh"> - <Filter>thread</Filter> - </None> <None Include="$(OpenMSXSrcDir)\thread\Thread.hh"> <Filter>thread</Filter> </None> hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-05-07 17:56:25
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 58d99581db80c165c4a6c0e0ad1e973392270c16 (commit) from 0891dcddee295be825b4525e4a83120eabc1ba09 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 58d99581db80c165c4a6c0e0ad1e973392270c16 Author: Wouter Vermaelen <ver...@gm...> Date: Thu May 7 15:15:28 2015 +0200 Replace our Semaphore wrapper with std::mutex We didn't actually need the counting-feature of a Semaphore. The only values our semaphores took were 0 and 1, and in that case a mutex is fine as well. (Maybe in the past we had other uses as well? I didn't check). C++11 offers std::mutex (actually our Semaphore class was already rewritten to use that). So this patch uses std::mutex directly. Most of this patch are mechanical replacements: Semaphore -> std::mutex ScopedLock -> std::lock_guard<std::mutex> or std::unique_lock<std::mutex> The difference between lock_guard and unique_lock is small: https://stackoverflow.com/questions/20516773/stdunique-lockstdmutex-or-stdlock-guardstdmutex Short summary: * unique_lock is a strict superset of lock_guard * the more limitted functionality of lock_guard may more clearly convey the intend of the code. So I'm using lock_guard were possible and lock_guard were needed (only in EventDistributor). ----------------------------------------------------------------------- Summary of changes: src/Reactor.cc | 7 ++-- src/Reactor.hh | 10 +++--- src/events/CliConnection.cc | 8 ++-- src/events/CliConnection.hh | 4 +- src/events/EventDistributor.cc | 15 ++++----- src/events/EventDistributor.hh | 4 +- src/events/GlobalCliComm.cc | 13 ++++---- src/events/GlobalCliComm.hh | 4 +- src/file/PreCacheFile.cc | 14 ++------- src/file/PreCacheFile.hh | 5 +-- src/serial/MidiInCoreMIDI.cc | 18 +++++------ src/serial/MidiInCoreMIDI.hh | 6 ++-- src/serial/MidiInReader.cc | 12 ++++---- src/serial/MidiInReader.hh | 4 +- src/serial/MidiInWindows.cc | 14 ++++---- src/serial/MidiInWindows.hh | 4 +- src/serial/RS232Tester.cc | 12 ++++---- src/serial/RS232Tester.hh | 4 +- src/thread/Semaphore.cc | 24 --------------- src/thread/Semaphore.hh | 64 ---------------------------------------- 20 files changed, 72 insertions(+), 174 deletions(-) delete mode 100644 src/thread/Semaphore.cc delete mode 100644 src/thread/Semaphore.hh diff --git a/src/Reactor.cc b/src/Reactor.cc index 970c2a1..8af9e58 100644 --- a/src/Reactor.cc +++ b/src/Reactor.cc @@ -173,8 +173,7 @@ private: Reactor::Reactor() - : mbSem(1) - , activeBoard(nullptr) + : activeBoard(nullptr) , blockedCounter(0) , paused(false) , running(true) @@ -437,7 +436,7 @@ void Reactor::switchBoard(MSXMotherBoard* newBoard) // Don't hold the lock for longer than the actual switch. // In the past we had a potential for deadlocks here, because // (indirectly) the code below still acquires other locks. - ScopedLock lock(mbSem); + std::lock_guard<std::mutex> lock(mbMutex); activeBoard = newBoard; } eventDistributor->distributeEvent( @@ -484,7 +483,7 @@ void Reactor::enterMainLoop() activeBoard->exitCPULoopSync(); } } else { - ScopedLock lock(mbSem); + std::lock_guard<std::mutex> lock(mbMutex); if (activeBoard) { activeBoard->exitCPULoopAsync(); } diff --git a/src/Reactor.hh b/src/Reactor.hh index 93eba79..a23150b 100644 --- a/src/Reactor.hh +++ b/src/Reactor.hh @@ -3,12 +3,12 @@ #include "Observer.hh" #include "EventListener.hh" -#include "Semaphore.hh" #include "noncopyable.hh" #include "string_ref.hh" #include "openmsx.hh" #include <string> #include <memory> +#include <mutex> #include <vector> namespace openmsx { @@ -125,8 +125,8 @@ private: void unpause(); void pause(); - Semaphore mbSem; // this should come first, because it's still used by - // the destructors of the unique_ptr below + std::mutex mbMutex; // this should come first, because it's still used by + // the destructors of the unique_ptr below // note: order of unique_ptr's is important std::unique_ptr<RTScheduler> rtScheduler; @@ -171,10 +171,10 @@ private: // Locking rules for activeBoard access: // - main thread can always access activeBoard without taking a lock // - changing activeBoard handle can only be done in the main thread - // and needs to take the mbSem lock + // and needs to take the mbMutex lock // - non-main thread can only access activeBoard via specific // member functions (atm only via enterMainLoop()), it needs to take - // the mbSem lock + // the mbMutex lock Boards boards; Boards garbageBoards; MSXMotherBoard* activeBoard; // either nullptr or a board inside 'boards' diff --git a/src/events/CliConnection.cc b/src/events/CliConnection.cc index 0edc0c1..06f2a1e 100644 --- a/src/events/CliConnection.cc +++ b/src/events/CliConnection.cc @@ -317,7 +317,7 @@ SocketConnection::SocketConnection(CommandController& commandController, EventDistributor& eventDistributor, SOCKET sd_) : CliConnection(commandController, eventDistributor) - , sem(1), sd(sd_), established(false) + , sd(sd_), established(false) { } @@ -332,7 +332,7 @@ void SocketConnection::run() #ifdef _WIN32 bool ok; { - ScopedLock lock(sem); + std::lock_guard<std::mutex> lock(mutex); // Authenticate and authorize the caller SocketStreamWrapper stream(sd); SspiNegotiateServer server(stream); @@ -376,7 +376,7 @@ void SocketConnection::output(string_ref message) while (bytesLeft) { int bytesSend; { - ScopedLock lock(sem); + std::lock_guard<std::mutex> lock(mutex); if (sd == OPENMSX_INVALID_SOCKET) return; bytesSend = sock_send(sd, &data[pos], bytesLeft); } @@ -392,7 +392,7 @@ void SocketConnection::output(string_ref message) void SocketConnection::close() { - ScopedLock lock(sem); + std::lock_guard<std::mutex> lock(mutex); if (sd != OPENMSX_INVALID_SOCKET) { SOCKET _sd = sd; sd = OPENMSX_INVALID_SOCKET; diff --git a/src/events/CliConnection.hh b/src/events/CliConnection.hh index 58c14bf..c80905f 100644 --- a/src/events/CliConnection.hh +++ b/src/events/CliConnection.hh @@ -3,11 +3,11 @@ #include "CliListener.hh" #include "Thread.hh" -#include "Semaphore.hh" #include "EventListener.hh" #include "Socket.hh" #include "CliComm.hh" #include "AdhocCliCommParser.hh" +#include <mutex> #include <string> namespace openmsx { @@ -128,7 +128,7 @@ private: void close() override; void run() override; - Semaphore sem; + std::mutex mutex; SOCKET sd; bool established; }; diff --git a/src/events/EventDistributor.cc b/src/events/EventDistributor.cc index 82809de..524c18e 100644 --- a/src/events/EventDistributor.cc +++ b/src/events/EventDistributor.cc @@ -17,14 +17,13 @@ namespace openmsx { EventDistributor::EventDistributor(Reactor& reactor_) : reactor(reactor_) - , sem(1) { } void EventDistributor::registerEventListener( EventType type, EventListener& listener, Priority priority) { - ScopedLock lock(sem); + std::lock_guard<std::mutex> lock(mutex); auto& priorityMap = listeners[type]; for (auto* l : values(priorityMap)) { // a listener may only be registered once for each type @@ -39,7 +38,7 @@ void EventDistributor::registerEventListener( void EventDistributor::unregisterEventListener( EventType type, EventListener& listener) { - ScopedLock lock(sem); + std::lock_guard<std::mutex> lock(mutex); auto& priorityMap = listeners[type]; priorityMap.erase(find_if_unguarded(priorityMap, [&](PriorityMap::value_type v) { return v.second == &listener; })); @@ -54,7 +53,7 @@ void EventDistributor::distributeEvent(const EventPtr& event) // TODO: Is it useful to test for 0 listeners or should we just always // queue the event? assert(event); - ScopedLock lock(sem); + std::unique_lock<std::mutex> lock(mutex); if (!listeners[event->getType()].empty()) { scheduledEvents.push_back(event); // must release lock, otherwise there's a deadlock: @@ -63,7 +62,7 @@ void EventDistributor::distributeEvent(const EventPtr& event) // thread 2: EventDistributor::distributeEvent() // Reactor::enterMainLoop() cond.signalAll(); - lock.release(); + lock.unlock(); reactor.enterMainLoop(); } } @@ -84,7 +83,7 @@ void EventDistributor::deliverEvents() reactor.getInterpreter().poll(); reactor.getRTScheduler().execute(); - ScopedLock lock(sem); + std::unique_lock<std::mutex> lock(mutex); // It's possible that executing an event triggers scheduling of another // event. We also want to execute those secondary events. That's why // we have this while loop here. @@ -99,7 +98,7 @@ void EventDistributor::deliverEvents() for (auto& event : eventsCopy) { auto type = event->getType(); auto priorityMapCopy = listeners[type]; - sem.up(); + lock.unlock(); unsigned blockPriority = unsigned(-1); // allow all for (auto& p : priorityMapCopy) { // It's possible delivery to one of the previous @@ -114,7 +113,7 @@ void EventDistributor::deliverEvents() blockPriority = block; } } - sem.down(); + lock.lock(); } } } diff --git a/src/events/EventDistributor.hh b/src/events/EventDistributor.hh index 3f73ed7..e9af26e 100644 --- a/src/events/EventDistributor.hh +++ b/src/events/EventDistributor.hh @@ -2,10 +2,10 @@ #define EVENTDISTRIBUTOR_HH #include "Event.hh" -#include "Semaphore.hh" #include "CondVar.hh" #include "noncopyable.hh" #include <memory> +#include <mutex> #include <utility> #include <vector> @@ -77,7 +77,7 @@ private: PriorityMap listeners[NUM_EVENT_TYPES]; using EventQueue = std::vector<EventPtr>; EventQueue scheduledEvents; - Semaphore sem; + std::mutex mutex; CondVar cond; }; diff --git a/src/events/GlobalCliComm.cc b/src/events/GlobalCliComm.cc index ef92d7e..2a03843 100644 --- a/src/events/GlobalCliComm.cc +++ b/src/events/GlobalCliComm.cc @@ -11,8 +11,7 @@ namespace openmsx { GlobalCliComm::GlobalCliComm() - : sem(1) - , delivering(false) + : delivering(false) , allowExternalCommands(false) { } @@ -26,7 +25,7 @@ GlobalCliComm::~GlobalCliComm() void GlobalCliComm::addListener(std::unique_ptr<CliListener> listener) { // can be called from any thread - ScopedLock lock(sem); + std::lock_guard<std::mutex> lock(mutex); auto* p = listener.get(); listeners.push_back(std::move(listener)); if (allowExternalCommands) { @@ -39,7 +38,7 @@ void GlobalCliComm::addListener(std::unique_ptr<CliListener> listener) std::unique_ptr<CliListener> GlobalCliComm::removeListener(CliListener& listener) { // can be called from any thread - ScopedLock lock(sem); + std::lock_guard<std::mutex> lock(mutex); auto it = find_if_unguarded(listeners, [&](const std::unique_ptr<CliListener>& ptr) { return ptr.get() == &listener; }); @@ -65,7 +64,7 @@ void GlobalCliComm::log(LogLevel level, string_ref message) if (delivering) { // Don't allow recursive calls, this would hang while trying to - // acquire the Semaphore below. But also when we would change + // acquire the mutex below. But also when we would change // this to a recursive-mutex, this could result in an infinite // loop. // One example of a recursive invocation is when something goes @@ -76,7 +75,7 @@ void GlobalCliComm::log(LogLevel level, string_ref message) } ScopedAssign<bool> sa(delivering, true); - ScopedLock lock(sem); + std::lock_guard<std::mutex> lock(mutex); if (!listeners.empty()) { for (auto& l : listeners) { l->log(level, message); @@ -106,7 +105,7 @@ void GlobalCliComm::updateHelper(UpdateType type, string_ref machine, string_ref name, string_ref value) { assert(Thread::isMainThread()); - ScopedLock lock(sem); + std::lock_guard<std::mutex> lock(mutex); for (auto& l : listeners) { l->update(type, machine, name, value); } diff --git a/src/events/GlobalCliComm.hh b/src/events/GlobalCliComm.hh index 7f56479..4636d76 100644 --- a/src/events/GlobalCliComm.hh +++ b/src/events/GlobalCliComm.hh @@ -2,10 +2,10 @@ #define GLOBALCLICOMM_HH #include "CliComm.hh" -#include "Semaphore.hh" #include "StringMap.hh" #include "noncopyable.hh" #include <memory> +#include <mutex> #include <vector> namespace openmsx { @@ -37,7 +37,7 @@ private: StringMap<std::string> prevValues[NUM_UPDATES]; std::vector<std::unique_ptr<CliListener>> listeners; - Semaphore sem; // lock access to listeners member + std::mutex mutex; // lock access to listeners member bool delivering; bool allowExternalCommands; diff --git a/src/file/PreCacheFile.cc b/src/file/PreCacheFile.cc index c868ef8..e71d031 100644 --- a/src/file/PreCacheFile.cc +++ b/src/file/PreCacheFile.cc @@ -7,17 +7,14 @@ namespace openmsx { PreCacheFile::PreCacheFile(const std::string& name_) - : name(name_), thread(this), sem(1), exitLoop(false) + : name(name_), thread(this), exitLoop(false) { thread.start(); } PreCacheFile::~PreCacheFile() { - { - ScopedLock lock(sem); - exitLoop = true; - } + exitLoop = true; thread.join(); } @@ -42,12 +39,7 @@ void PreCacheFile::run() unsigned block = 0; unsigned repeat = 0; while (true) { - bool exitLoop2; - { - ScopedLock lock(sem); - exitLoop2 = exitLoop; - } - if (exitLoop2) break; + if (exitLoop) break; char buf[BLOCK_SIZE]; if (fseek(file.get(), block * BLOCK_SIZE, SEEK_SET)) break; diff --git a/src/file/PreCacheFile.hh b/src/file/PreCacheFile.hh index 0bd17a4..cd89971 100644 --- a/src/file/PreCacheFile.hh +++ b/src/file/PreCacheFile.hh @@ -2,7 +2,7 @@ #define PRECACHEFILE_HH #include "Thread.hh" -#include "Semaphore.hh" +#include <atomic> #include <string> namespace openmsx { @@ -25,8 +25,7 @@ private: const std::string name; Thread thread; - Semaphore sem; - bool exitLoop; // locked by sem + std::atomic<bool> exitLoop; }; } // namespace openmsx diff --git a/src/serial/MidiInCoreMIDI.cc b/src/serial/MidiInCoreMIDI.cc index feb3215..2b6a38b 100644 --- a/src/serial/MidiInCoreMIDI.cc +++ b/src/serial/MidiInCoreMIDI.cc @@ -33,7 +33,6 @@ MidiInCoreMIDI::MidiInCoreMIDI(EventDistributor& eventDistributor_, Scheduler& scheduler_, MIDIEndpointRef endpoint_) : eventDistributor(eventDistributor_) , scheduler(scheduler_) - , lock(1) , endpoint(endpoint_) { // Get a user-presentable name for the endpoint. @@ -112,7 +111,7 @@ void MidiInCoreMIDI::sendPacketList(const MIDIPacketList *packetList, void MidiInCoreMIDI::sendPacketList(const MIDIPacketList *packetList, void * /*srcConnRefCon*/) { { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); const MIDIPacket *packet = &packetList->packet[0]; for (UInt32 i = 0; i < packetList->numPackets; i++) { for (UInt16 j = 0; j < packet->length; j++) { @@ -130,7 +129,7 @@ void MidiInCoreMIDI::signal(EmuTime::param time) { auto connector = static_cast<MidiInConnector*>(getConnector()); if (!connector->acceptsData()) { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.clear(); return; } @@ -140,7 +139,7 @@ void MidiInCoreMIDI::signal(EmuTime::param time) byte data; { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); if (queue.empty()) return; data = queue.pop_front(); } @@ -153,7 +152,7 @@ int MidiInCoreMIDI::signalEvent(const std::shared_ptr<const Event>& /*event*/) if (isPluggedIn()) { signal(scheduler.getCurrentTime()); } else { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.clear(); } return 0; @@ -173,7 +172,6 @@ MidiInCoreMIDIVirtual::MidiInCoreMIDIVirtual(EventDistributor& eventDistributor_ Scheduler& scheduler_) : eventDistributor(eventDistributor_) , scheduler(scheduler_) - , lock(1) , client(0) , endpoint(0) { @@ -241,7 +239,7 @@ void MidiInCoreMIDIVirtual::sendPacketList(const MIDIPacketList *packetList, void * /*srcConnRefCon*/) { { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); const MIDIPacket *packet = &packetList->packet[0]; for (UInt32 i = 0; i < packetList->numPackets; i++) { for (UInt16 j = 0; j < packet->length; j++) { @@ -259,7 +257,7 @@ void MidiInCoreMIDIVirtual::signal(EmuTime::param time) { auto connector = static_cast<MidiInConnector*>(getConnector()); if (!connector->acceptsData()) { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.clear(); return; } @@ -269,7 +267,7 @@ void MidiInCoreMIDIVirtual::signal(EmuTime::param time) byte data; { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); if (queue.empty()) return; data = queue.pop_front(); } @@ -283,7 +281,7 @@ int MidiInCoreMIDIVirtual::signalEvent( if (isPluggedIn()) { signal(scheduler.getCurrentTime()); } else { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.clear(); } return 0; diff --git a/src/serial/MidiInCoreMIDI.hh b/src/serial/MidiInCoreMIDI.hh index 6fa19d2..1a7fce1 100644 --- a/src/serial/MidiInCoreMIDI.hh +++ b/src/serial/MidiInCoreMIDI.hh @@ -5,11 +5,11 @@ #include "MidiInDevice.hh" #include "EventListener.hh" -#include "Semaphore.hh" #include "openmsx.hh" #include "serialize_meta.hh" #include "circular_buffer.hh" #include <CoreMIDI/MIDIServices.h> +#include <mutex> namespace openmsx { @@ -56,7 +56,7 @@ private: EventDistributor& eventDistributor; Scheduler& scheduler; cb_queue<byte> queue; - Semaphore lock; // to protect queue + std::mutex mutex; // to protect queue MIDIClientRef client; MIDIPortRef port; @@ -100,7 +100,7 @@ private: EventDistributor& eventDistributor; Scheduler& scheduler; cb_queue<byte> queue; - Semaphore lock; // to protect queue + std::mutex mutex; // to protect queue MIDIClientRef client; MIDIEndpointRef endpoint; diff --git a/src/serial/MidiInReader.cc b/src/serial/MidiInReader.cc index 65ae585..c595316 100644 --- a/src/serial/MidiInReader.cc +++ b/src/serial/MidiInReader.cc @@ -18,7 +18,7 @@ MidiInReader::MidiInReader(EventDistributor& eventDistributor_, Scheduler& scheduler_, CommandController& commandController) : eventDistributor(eventDistributor_), scheduler(scheduler_) - , thread(this), lock(1) + , thread(this) , readFilenameSetting( commandController, "midi-in-readfilename", "filename of the file where the MIDI input is read from", @@ -53,7 +53,7 @@ void MidiInReader::plugHelper(Connector& connector_, EmuTime::param /*time*/) void MidiInReader::unplugHelper(EmuTime::param /*time*/) { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); thread.stop(); file.reset(); } @@ -85,7 +85,7 @@ void MidiInReader::run() assert(isPluggedIn()); { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.push_back(buf); } eventDistributor.distributeEvent( @@ -98,7 +98,7 @@ void MidiInReader::signal(EmuTime::param time) { auto connector = static_cast<MidiInConnector*>(getConnector()); if (!connector->acceptsData()) { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.clear(); return; } @@ -108,7 +108,7 @@ void MidiInReader::signal(EmuTime::param time) byte data; { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); if (queue.empty()) return; data = queue.pop_front(); } @@ -121,7 +121,7 @@ int MidiInReader::signalEvent(const std::shared_ptr<const Event>& /*event*/) if (isPluggedIn()) { signal(scheduler.getCurrentTime()); } else { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.clear(); } return 0; diff --git a/src/serial/MidiInReader.hh b/src/serial/MidiInReader.hh index 8b7124f..a4e830a 100644 --- a/src/serial/MidiInReader.hh +++ b/src/serial/MidiInReader.hh @@ -6,10 +6,10 @@ #include "EventListener.hh" #include "FilenameSetting.hh" #include "FileOperations.hh" -#include "Semaphore.hh" #include "openmsx.hh" #include "circular_buffer.hh" #include <cstdio> +#include <mutex> namespace openmsx { @@ -49,7 +49,7 @@ private: Thread thread; FileOperations::FILE_t file; cb_queue<byte> queue; - Semaphore lock; // to protect queue + std::mutex mutex; // to protect queue FilenameSetting readFilenameSetting; }; diff --git a/src/serial/MidiInWindows.cc b/src/serial/MidiInWindows.cc index 8b04cc2..66cbed7 100644 --- a/src/serial/MidiInWindows.cc +++ b/src/serial/MidiInWindows.cc @@ -38,7 +38,7 @@ void MidiInWindows::registerAll(EventDistributor& eventDistributor, MidiInWindows::MidiInWindows(EventDistributor& eventDistributor_, Scheduler& scheduler_, unsigned num) : eventDistributor(eventDistributor_), scheduler(scheduler_) - , thread(this), devidx(unsigned(-1)), lock(1) + , thread(this), devidx(unsigned(-1)) { name = w32_midiInGetVFN(num); desc = w32_midiInGetRDN(num); @@ -73,7 +73,7 @@ void MidiInWindows::plugHelper(Connector& connector_, EmuTime::param /*time*/) void MidiInWindows::unplugHelper(EmuTime::param /*time*/) { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); thread.stop(); if (devidx != unsigned(-1)) { w32_midiInClose(devidx); @@ -95,7 +95,7 @@ void MidiInWindows::procLongMsg(LPMIDIHDR p) { if (p->dwBytesRecorded) { { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); for (unsigned i = 0; i < p->dwBytesRecorded; ++i) { queue.push_back(p->lpData[i]); } @@ -116,7 +116,7 @@ void MidiInWindows::procShortMsg(DWORD param) default: num = 1; break; } - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); while (num--) { queue.push_back(param & 0xFF); param >>= 8; @@ -166,7 +166,7 @@ void MidiInWindows::signal(EmuTime::param time) { auto connector = static_cast<MidiInConnector*>(getConnector()); if (!connector->acceptsData()) { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.clear(); return; } @@ -174,7 +174,7 @@ void MidiInWindows::signal(EmuTime::param time) byte data; { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); if (queue.empty()) return; data = queue.pop_front(); } @@ -187,7 +187,7 @@ int MidiInWindows::signalEvent(const std::shared_ptr<const Event>& /*event*/) if (isPluggedIn()) { signal(scheduler.getCurrentTime()); } else { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.clear(); } return 0; diff --git a/src/serial/MidiInWindows.hh b/src/serial/MidiInWindows.hh index 5ead1e3..5c9a90a 100644 --- a/src/serial/MidiInWindows.hh +++ b/src/serial/MidiInWindows.hh @@ -11,11 +11,11 @@ #include "MidiInDevice.hh" #include "Thread.hh" #include "EventListener.hh" -#include "Semaphore.hh" #include "serialize_meta.hh" #include "circular_buffer.hh" #include <windows.h> #include <mmsystem.h> +#include <mutex> namespace openmsx { @@ -65,7 +65,7 @@ private: unsigned devidx; DWORD thrdid; cb_queue<byte> queue; - Semaphore lock; // to protect queue + std::mutex mutex; // to protect queue std::string name; std::string desc; }; diff --git a/src/serial/RS232Tester.cc b/src/serial/RS232Tester.cc index eae6487..8e72800 100644 --- a/src/serial/RS232Tester.cc +++ b/src/serial/RS232Tester.cc @@ -12,7 +12,7 @@ RS232Tester::RS232Tester(EventDistributor& eventDistributor_, Scheduler& scheduler_, CommandController& commandController) : eventDistributor(eventDistributor_), scheduler(scheduler_) - , thread(this), lock(1) + , thread(this) , rs232InputFilenameSetting( commandController, "rs232-inputfilename", "filename of the file where the RS232 input is read from", @@ -65,7 +65,7 @@ void RS232Tester::unplugHelper(EmuTime::param /*time*/) outFile.close(); // input - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); thread.stop(); inFile.reset(); } @@ -95,7 +95,7 @@ void RS232Tester::run() continue; } assert(isPluggedIn()); - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.push_back(buf); eventDistributor.distributeEvent( std::make_shared<SimpleEvent>(OPENMSX_RS232_TESTER_EVENT)); @@ -107,13 +107,13 @@ void RS232Tester::signal(EmuTime::param time) { auto connector = static_cast<RS232Connector*>(getConnector()); if (!connector->acceptsData()) { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.clear(); return; } if (!connector->ready()) return; - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); if (queue.empty()) return; connector->recvByte(queue.pop_front(), time); } @@ -124,7 +124,7 @@ int RS232Tester::signalEvent(const std::shared_ptr<const Event>& /*event*/) if (isPluggedIn()) { signal(scheduler.getCurrentTime()); } else { - ScopedLock l(lock); + std::lock_guard<std::mutex> lock(mutex); queue.clear(); } return 0; diff --git a/src/serial/RS232Tester.hh b/src/serial/RS232Tester.hh index 21c1603..b3c43fb 100644 --- a/src/serial/RS232Tester.hh +++ b/src/serial/RS232Tester.hh @@ -6,10 +6,10 @@ #include "EventListener.hh" #include "FilenameSetting.hh" #include "FileOperations.hh" -#include "Semaphore.hh" #include "openmsx.hh" #include "circular_buffer.hh" #include <fstream> +#include <mutex> #include <cstdio> namespace openmsx { @@ -53,7 +53,7 @@ private: Thread thread; FileOperations::FILE_t inFile; cb_queue<byte> queue; - Semaphore lock; // to protect queue + std::mutex mutex; // to protect queue std::ofstream outFile; diff --git a/src/thread/Semaphore.cc b/src/thread/Semaphore.cc deleted file mode 100644 index 90012d7..0000000 --- a/src/thread/Semaphore.cc +++ /dev/null @@ -1,24 +0,0 @@ -#include "Semaphore.hh" - -namespace openmsx { - -Semaphore::Semaphore(unsigned value) - : value(value) -{ -} - -void Semaphore::up() -{ - std::unique_lock<std::mutex> lock(mutex); - value++; - condition.notify_one(); -} - -void Semaphore::down() -{ - std::unique_lock<std::mutex> lock(mutex); - condition.wait(lock, [&]() { return value != 0; }); - value--; -} - -} // namespace openmsx diff --git a/src/thread/Semaphore.hh b/src/thread/Semaphore.hh deleted file mode 100644 index 8157586..0000000 --- a/src/thread/Semaphore.hh +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef SEMAPHORE_HH -#define SEMAPHORE_HH - -#include "noncopyable.hh" -#include <cassert> -#include <condition_variable> -#include <mutex> - -namespace openmsx { - -class Semaphore : private noncopyable -{ -public: - explicit Semaphore(unsigned value); - void up(); - void down(); - -private: - std::mutex mutex; - std::condition_variable condition; - unsigned value; -}; - -class ScopedLock : private noncopyable -{ -public: - ScopedLock() - : lock(nullptr) - { - } - - explicit ScopedLock(Semaphore& lock_) - : lock(nullptr) - { - take(lock_); - } - - ~ScopedLock() - { - release(); - } - - void take(Semaphore& lock_) - { - assert(!lock); - lock = &lock_; - lock->down(); - } - - void release() - { - if (lock) { - lock->up(); - lock = nullptr; - } - } - -private: - Semaphore* lock; -}; - -} // namespace openmsx - -#endif hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-05-07 17:01:22
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 0891dcddee295be825b4525e4a83120eabc1ba09 (commit) from b680ee26336be288022d29a0b901b72b0c83a142 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 0891dcddee295be825b4525e4a83120eabc1ba09 Author: wouter <ver...@gm...> Date: Thu Jul 11 12:10:34 2013 +0200 Replace clock_gettime() with c++11 steady_clock Unfortunately the vs2013 version is buggy (should be fixed in vs2015). So for visual studio we still use the SDL version. ----------------------------------------------------------------------- Summary of changes: build/systemfuncs.py | 7 ----- src/thread/Timer.cc | 66 +++++++++++++++---------------------------------- 2 files changed, 20 insertions(+), 53 deletions(-) diff --git a/build/systemfuncs.py b/build/systemfuncs.py index 632f58b..908464a 100644 --- a/build/systemfuncs.py +++ b/build/systemfuncs.py @@ -20,13 +20,6 @@ class FTruncateFunction(SystemFunction): def iterHeaders(cls, targetPlatform): yield '<unistd.h>' -class ClockGetTimeFunction(SystemFunction): - name = 'clock_gettime' - - @classmethod - def iterHeaders(cls, targetPlatform): - yield '<time.h>' - class MMapFunction(SystemFunction): name = 'mmap' diff --git a/src/thread/Timer.cc b/src/thread/Timer.cc index 0083d43..fcc24c9 100644 --- a/src/thread/Timer.cc +++ b/src/thread/Timer.cc @@ -1,16 +1,10 @@ #include "Timer.hh" #include "systemfuncs.hh" -#if HAVE_CLOCK_GETTIME -#include <ctime> -#endif #if HAVE_USLEEP #include <unistdp.hh> #endif -#if defined _WIN32 -#include <windows.h> -#endif +#include <chrono> #include <SDL.h> -#include <cassert> namespace openmsx { namespace Timer { @@ -25,48 +19,28 @@ uint64_t getTime() { static uint64_t lastTime = 0; uint64_t now; -/* QueryPerformanceCounter() has problems on modern CPUs, - * - on dual core CPUs time can ge backwards (a bit) when your process - * get scheduled on the other core - * - the resolution of the timer can vary on CPUs that can change its - * clock frequency (for power managment) -##if defined _WIN32 - static LONGLONG hfFrequency = 0; - - LARGE_INTEGER li; - if (!hfFrequency) { - if (QueryPerformanceFrequency(&li)) { - hfFrequency = li.QuadPart; - } else { - return getSDLTicks(); - } - } - QueryPerformanceCounter(&li); - // Assumes that the timer never wraps. The mask is just to - // ensure that the multiplication doesn't wrap. - now = (li.QuadPart & (int64_t(-1) >> 20)) * 1000000 / hfFrequency; -*/ - // clock_gettime doesn't seem to work properly on MinGW/Win32 cross compilation -#if HAVE_CLOCK_GETTIME && defined(_POSIX_MONOTONIC_CLOCK) && !(defined(_WIN32) && defined(__GNUC__)) - // Note: in the past we used the more portable gettimeofday() function, - // but the result of that function is not always monotonic. - timespec ts; - int result = clock_gettime(CLOCK_MONOTONIC, &ts); - assert(result == 0); (void)result; - now = static_cast<uint64_t>(ts.tv_sec) * 1000000 + - static_cast<uint64_t>(ts.tv_nsec) / 1000; +#ifndef _MSC_VER + using namespace std::chrono; + now = duration_cast<microseconds>( + steady_clock::now().time_since_epoch()).count(); #else - now = getSDLTicks(); + // Visual studio 2012 does offer std::chrono, but unfortunately it's + // buggy and low resolution. So for now we still use SDL. See also: + // http://stackoverflow.com/questions/11488075/vs11-is-steady-clock-steady + // https://connect.microsoft.com/VisualStudio/feedback/details/753115/ + now = static_cast<uint64_t>(SDL_GetTicks()) * 1000; #endif - if (now < lastTime) { - // This shouldn't happen, time should never go backwards. - // Though there appears to be a bug in some Linux kernels - // so that occasionally clock_gettime(CLOCK_MONOTONIC) _does_ - // go back in time slightly. When that happens we return the - // last time again. - return lastTime; - } + + // Other parts of openMSX may crash if this function ever returns a + // value that is less than a previously returned value. Hence this + // extra check. + // SDL_GetTicks() is not guaranteed to return monotonic values. + // steady_clock OTOH should be monotonic. It's implemented in terms of + // clock_gettime(CLOCK_MONOTONIC). Unfortunately in older linux + // versions we've seen buggy implementation that once in a while did + // return time points slightly in the past. + if (now < lastTime) return lastTime; lastTime = now; return now; } hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-05-06 18:31:43
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via b680ee26336be288022d29a0b901b72b0c83a142 (commit) from da45d6bb27b5edc0ca7a20a7e8eca532907cfcd6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b680ee26336be288022d29a0b901b72b0c83a142 Author: m9710797 <ver...@gm...> Date: Wed May 6 20:19:55 2015 +0200 Fixed bug when calling freeAligned() on nullptr We have 3 implementations for mallocAligned()/freeAligned(): - when available we use posix_memalign()/free() - with visual studio we use _aligned_malloc()/_aligned_free() - and as a fallback we use malloc()/free() + extra book keeping for the alignment. (Only?) when compiling openMSX with mingw (gcc on windows) the 3rd version is used. In the first two variants freeAligned(nullptr) is allowed (and does nothing). Though in the 3rd variant (in our manual book keeping code) it triggered an assert. I've extended the 3rd variant to allow freeing nullptr's. ----------------------------------------------------------------------- Summary of changes: src/utils/MemoryOps.cc | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/src/utils/MemoryOps.cc b/src/utils/MemoryOps.cc index e3b3fa4..ebd3ad2 100644 --- a/src/utils/MemoryOps.cc +++ b/src/utils/MemoryOps.cc @@ -263,12 +263,14 @@ public: } void insert(void* aligned, void* unaligned) { + if (!aligned) return; assert(none_of(begin(allocMap), end(allocMap), EqualTupleValue<0>(aligned))); allocMap.emplace_back(aligned, unaligned); } void* remove(void* aligned) { + if (!aligned) return nullptr; // LIFO order is more likely than FIFO -> search backwards auto it = find_if_unguarded(allocMap.rbegin(), allocMap.rend(), EqualTupleValue<0>(aligned)); hooks/post-receive -- openMSX (main) |
From: Maarten t. H. <mth...@us...> - 2015-05-06 08:41:08
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via da45d6bb27b5edc0ca7a20a7e8eca532907cfcd6 (commit) from b0692eeb81c526d18f018af4cacb70f7367694c2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit da45d6bb27b5edc0ca7a20a7e8eca532907cfcd6 Author: Maarten ter Huurne <ma...@tr...> Date: Wed May 6 10:35:52 2015 +0200 Reimplement CondVar using C++11 primitives This removes the dependency on SDL. ----------------------------------------------------------------------- Summary of changes: src/thread/CondVar.cc | 29 +++++++++-------------------- src/thread/CondVar.hh | 11 ++++------- 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/src/thread/CondVar.cc b/src/thread/CondVar.cc index 8f0d173..537867a 100644 --- a/src/thread/CondVar.cc +++ b/src/thread/CondVar.cc @@ -1,41 +1,30 @@ #include "CondVar.hh" -#include <SDL.h> -namespace openmsx { - -CondVar::CondVar() -{ - mutex = SDL_CreateMutex(); - cond = SDL_CreateCond(); -} +#include <chrono> -CondVar::~CondVar() -{ - SDL_DestroyCond(cond); - SDL_DestroyMutex(mutex); -} +namespace openmsx { void CondVar::wait() { - SDL_mutexP(mutex); - SDL_CondWait(cond, mutex); + std::unique_lock<std::mutex> lock(mutex); + condition.wait(lock); } bool CondVar::waitTimeout(unsigned us) { - SDL_mutexP(mutex); - int result = SDL_CondWaitTimeout(cond, mutex, us / 1000); - return result == SDL_MUTEX_TIMEDOUT; + std::chrono::microseconds duration(us); + std::unique_lock<std::mutex> lock(mutex); + return condition.wait_for(lock, duration) == std::cv_status::timeout; } void CondVar::signal() { - SDL_CondSignal(cond); + condition.notify_one(); } void CondVar::signalAll() { - SDL_CondBroadcast(cond); + condition.notify_all(); } } // namespace openmsx diff --git a/src/thread/CondVar.hh b/src/thread/CondVar.hh index 6875465..07ab978 100644 --- a/src/thread/CondVar.hh +++ b/src/thread/CondVar.hh @@ -1,17 +1,14 @@ #ifndef CONDVAR_HH #define CONDVAR_HH -struct SDL_cond; -struct SDL_mutex; +#include <condition_variable> +#include <mutex> namespace openmsx { class CondVar { public: - CondVar(); - ~CondVar(); - /** Block till another thread signals this condition variable. */ void wait(); @@ -31,8 +28,8 @@ public: void signalAll(); private: - SDL_cond* cond; - SDL_mutex* mutex; + std::mutex mutex; + std::condition_variable condition; }; } // namespace openmsx hooks/post-receive -- openMSX (main) |
From: Manuel B. <man...@us...> - 2015-05-01 20:10:02
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via b0692eeb81c526d18f018af4cacb70f7367694c2 (commit) via 839068112036eb5f66df57ad27242a61bae8ae0e (commit) from 057214c6b5fd30480b36ebe04e7226f48659cf82 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b0692eeb81c526d18f018af4cacb70f7367694c2 Author: Manuel Bilderbeek <Man...@gm...> Date: Fri May 1 22:09:39 2015 +0200 Make use of -maxnofextrasnapshots for auto-save commit 839068112036eb5f66df57ad27242a61bae8ae0e Author: Manuel Bilderbeek <Man...@gm...> Date: Fri May 1 22:09:21 2015 +0200 Oops, forgot to commit merge error fix... ----------------------------------------------------------------------- Summary of changes: share/scripts/_reverse.tcl | 2 +- src/ReverseManager.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/scripts/_reverse.tcl b/share/scripts/_reverse.tcl index 70f269d..c272531 100644 --- a/share/scripts/_reverse.tcl +++ b/share/scripts/_reverse.tcl @@ -269,7 +269,7 @@ proc auto_save_replay_loop {} { variable auto_save_after_id if {$::auto_save_replay} { - reverse savereplay $::auto_save_replay_filename + reverse savereplay -maxnofextrasnapshots 0 $::auto_save_replay_filename set auto_save_after_id [after realtime $::auto_save_replay_interval "reverse::auto_save_replay_loop"] } diff --git a/src/ReverseManager.cc b/src/ReverseManager.cc index 574a0d8..bef31c4 100644 --- a/src/ReverseManager.cc +++ b/src/ReverseManager.cc @@ -605,7 +605,7 @@ void ReverseManager::saveReplay( // this is a new one, add it to the list of snapshots Reactor::Board board = reactor.createEmptyMotherBoard(); MemInputArchive in(it->second.savestate.data(), - it->second.size()); + it->second.size); in.serialize("machine", *board); replay.motherBoards.push_back(move(board)); lastAddedIt = it; hooks/post-receive -- openMSX (main) |
From: Manuel B. <man...@us...> - 2015-05-01 20:04:35
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 057214c6b5fd30480b36ebe04e7226f48659cf82 (commit) from 047b6fbfdc0217d236858b2c17a10c40da34ac23 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 057214c6b5fd30480b36ebe04e7226f48659cf82 Author: Manuel Bilderbeek <Man...@gm...> Date: Fri May 1 21:43:26 2015 +0200 Allow influencing the amount of snapshots in a replay file This is mostly implemented to allow a very low number of snapshots, for cases where this is not important: most particularly, an auto-saved replay. For some reason, for a low amount of snapshots, the amount is sometimes larger than what I expected, but guess this was already the case with the fixed number of 10 from before this patch, as the only thing that this patch does is make that fixed number variable. ----------------------------------------------------------------------- Summary of changes: src/ReverseManager.cc | 88 ++++++++++++++++++++++++++++++------------------ src/ReverseManager.hh | 3 +- 2 files changed, 57 insertions(+), 34 deletions(-) diff --git a/src/ReverseManager.cc b/src/ReverseManager.cc index 27c95a8..574a0d8 100644 --- a/src/ReverseManager.cc +++ b/src/ReverseManager.cc @@ -525,7 +525,8 @@ void ReverseManager::transferState(MSXMotherBoard& newBoard) newBoard.getMSXCommandController().transferSettings(oldController); } -void ReverseManager::saveReplay(array_ref<TclObject> tokens, TclObject& result) +void ReverseManager::saveReplay( + Interpreter& interp, array_ref<TclObject> tokens, TclObject& result) { const auto& chunks = history.chunks; if (chunks.empty()) { @@ -533,6 +534,7 @@ void ReverseManager::saveReplay(array_ref<TclObject> tokens, TclObject& result) } string filename; + int maxNofExtraSnapshots = MAX_NOF_SNAPSHOTS; switch (tokens.size()) { case 2: // nothing @@ -540,6 +542,24 @@ void ReverseManager::saveReplay(array_ref<TclObject> tokens, TclObject& result) case 3: filename = tokens[2].getString().str(); break; + case 4: + case 5: + size_t tn; + for (tn = 2; tn < (tokens.size() - 1); ++tn) { + if (tokens[tn].getString() == "-maxnofextrasnapshots") { + maxNofExtraSnapshots = tokens[tn + 1].getInt(interp); + break; + } + } + if (tn == (tokens.size() - 1)) throw SyntaxError(); + if (tokens.size() == 5) { + filename = tokens[tn == 2 ? 4 : 2].getString().str(); + } + if (maxNofExtraSnapshots < 0) { + throw CommandException("Maximum number of snapshots should be at least 0"); + } + + break; default: throw SyntaxError(); } @@ -561,41 +581,43 @@ void ReverseManager::saveReplay(array_ref<TclObject> tokens, TclObject& result) in.serialize("machine", *initialBoard); replay.motherBoards.push_back(move(initialBoard)); - // determine which extra snapshots to put in the replay - const auto& startTime = begin(chunks)->second.time; - // for the end time, try to take MAX_DIST_1_BEFORE_LAST_SNAPSHOT - // seconds before the normal end time so that we get an extra snapshot - // at that point, which is comfortable if you want to reverse from the - // last snapshot after loading the replay. - const auto& lastChunkTime = chunks.rbegin()->second.time; - const auto& endTime = ((startTime + MAX_DIST_1_BEFORE_LAST_SNAPSHOT) < lastChunkTime) ? lastChunkTime - MAX_DIST_1_BEFORE_LAST_SNAPSHOT : lastChunkTime; - EmuDuration totalLength = endTime - startTime; - EmuDuration partitionLength = totalLength.divRoundUp(MAX_NOF_SNAPSHOTS); - partitionLength = std::max(MIN_PARTITION_LENGTH, partitionLength); - EmuTime nextPartitionEnd = startTime + partitionLength; - auto it = begin(chunks); - auto lastAddedIt = begin(chunks); // already added - while (it != end(chunks)) { - ++it; - if (it == end(chunks) || (it->second.time > nextPartitionEnd)) { - --it; - assert(it->second.time <= nextPartitionEnd); - if (it != lastAddedIt) { - // this is a new one, add it to the list of snapshots - Reactor::Board board = reactor.createEmptyMotherBoard(); - MemInputArchive in(it->second.savestate.data(), - it->second.size); - in.serialize("machine", *board); - replay.motherBoards.push_back(move(board)); - lastAddedIt = it; - } + if (maxNofExtraSnapshots > 0) { + // determine which extra snapshots to put in the replay + const auto& startTime = begin(chunks)->second.time; + // for the end time, try to take MAX_DIST_1_BEFORE_LAST_SNAPSHOT + // seconds before the normal end time so that we get an extra snapshot + // at that point, which is comfortable if you want to reverse from the + // last snapshot after loading the replay. + const auto& lastChunkTime = chunks.rbegin()->second.time; + const auto& endTime = ((startTime + MAX_DIST_1_BEFORE_LAST_SNAPSHOT) < lastChunkTime) ? lastChunkTime - MAX_DIST_1_BEFORE_LAST_SNAPSHOT : lastChunkTime; + EmuDuration totalLength = endTime - startTime; + EmuDuration partitionLength = totalLength.divRoundUp(maxNofExtraSnapshots); + partitionLength = std::max(MIN_PARTITION_LENGTH, partitionLength); + EmuTime nextPartitionEnd = startTime + partitionLength; + auto it = begin(chunks); + auto lastAddedIt = begin(chunks); // already added + while (it != end(chunks)) { ++it; - while (it != end(chunks) && it->second.time > nextPartitionEnd) { - nextPartitionEnd += partitionLength; + if (it == end(chunks) || (it->second.time > nextPartitionEnd)) { + --it; + assert(it->second.time <= nextPartitionEnd); + if (it != lastAddedIt) { + // this is a new one, add it to the list of snapshots + Reactor::Board board = reactor.createEmptyMotherBoard(); + MemInputArchive in(it->second.savestate.data(), + it->second.size()); + in.serialize("machine", *board); + replay.motherBoards.push_back(move(board)); + lastAddedIt = it; + } + ++it; + while (it != end(chunks) && it->second.time > nextPartitionEnd) { + nextPartitionEnd += partitionLength; + } } } + assert(lastAddedIt == --end(chunks)); // last snapshot must be included } - assert(lastAddedIt == --end(chunks)); // last snapshot must be included // add sentinel when there isn't one yet bool addSentinel = history.events.empty() || @@ -982,7 +1004,7 @@ void ReverseManager::ReverseCmd::execute(array_ref<TclObject> tokens, TclObject& } else if (subcommand == "goto") { manager.goTo(tokens); } else if (subcommand == "savereplay") { - return manager.saveReplay(tokens, result); + return manager.saveReplay(interp, tokens, result); } else if (subcommand == "loadreplay") { return manager.loadReplay(interp, tokens, result); } else if (subcommand == "viewonlymode") { diff --git a/src/ReverseManager.hh b/src/ReverseManager.hh index 4a62c01..be0cb67 100644 --- a/src/ReverseManager.hh +++ b/src/ReverseManager.hh @@ -83,7 +83,8 @@ private: void debugInfo(TclObject& result) const; void goBack(array_ref<TclObject> tokens); void goTo(array_ref<TclObject> tokens); - void saveReplay(array_ref<TclObject> tokens, TclObject& result); + void saveReplay(Interpreter& interp, + array_ref<TclObject> tokens, TclObject& result); void loadReplay(Interpreter& interp, array_ref<TclObject> tokens, TclObject& result); hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-05-01 12:53:25
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 047b6fbfdc0217d236858b2c17a10c40da34ac23 (commit) from 204544ed9ad1aaf8e5459c1a6cc4a39f127698e2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 047b6fbfdc0217d236858b2c17a10c40da34ac23 Author: m9710797 <ver...@gm...> Date: Fri May 1 14:53:17 2015 +0200 add workaround for vs2103 ----------------------------------------------------------------------- Summary of changes: src/sound/ResampleHQ.cc | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-) diff --git a/src/sound/ResampleHQ.cc b/src/sound/ResampleHQ.cc index e1e1347..ebddac9 100644 --- a/src/sound/ResampleHQ.cc +++ b/src/sound/ResampleHQ.cc @@ -64,6 +64,23 @@ private: Table table; unsigned filterLen; unsigned count; + + // workaround for vs013: normally these are auto-generated + Element(double ratio_, Table&& table_, unsigned filterLen_, unsigned count_) + : ratio(ratio_), table(std::move(table_)) + , filterLen(filterLen_), count(count_) {} + Element(Element&& e) + : ratio (std::move(e.ratio)) + , table (std::move(e.table)) + , filterLen(std::move(e.filterLen)) + , count (std::move(e.count)) {} + Element& operator=(Element&& e) { + ratio = std::move(e.ratio); + table = std::move(e.table); + filterLen = std::move(e.filterLen); + count = std::move(e.count); + return *this; + } }; std::vector<Element> cache; // typically 1-4 entries -> unsorted vector }; hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-05-01 12:40:32
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 204544ed9ad1aaf8e5459c1a6cc4a39f127698e2 (commit) from d368dbbcf7183e74dc9d22839f2a5feace2224fc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 204544ed9ad1aaf8e5459c1a6cc4a39f127698e2 Author: m9710797 <ver...@gm...> Date: Fri May 1 14:40:20 2015 +0200 visual studio fixes after rev aca56d288ec ----------------------------------------------------------------------- Summary of changes: src/utils/win32-arggen.cc | 13 ++++++------- src/utils/win32-arggen.hh | 1 + 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/utils/win32-arggen.cc b/src/utils/win32-arggen.cc index 42d1411..c7d8972 100644 --- a/src/utils/win32-arggen.cc +++ b/src/utils/win32-arggen.cc @@ -10,28 +10,27 @@ namespace openmsx { ArgumentGenerator::~ArgumentGenerator() { - for (unsigned i = 0; i < argv.size(); ++i) { + for (int i = 0; i < argc; ++i) { free(argv[i]); } } -char** ArgumentGenerator::GetArguments(int& argc) +char** ArgumentGenerator::GetArguments(int& argc_) { if (argv.empty()) { - int cArgs; - LPWSTR* pszArglist = CommandLineToArgvW(GetCommandLineW(), &cArgs); + LPWSTR* pszArglist = CommandLineToArgvW(GetCommandLineW(), &argc); if (!pszArglist) { throw MSXException("Failed to obtain command line arguments"); } - argv.resize(cArgs); - for (int i = 0; i < cArgs; ++i) { + argv.resize(argc); + for (int i = 0; i < argc; ++i) { argv[i] = strdup(utf8::utf16to8(pszArglist[i]).c_str()); } LocalFree(pszArglist); } - argc = int(argv.size()); + argc_ = argc; return argv.data(); } diff --git a/src/utils/win32-arggen.hh b/src/utils/win32-arggen.hh index c5eda72..a35398c 100644 --- a/src/utils/win32-arggen.hh +++ b/src/utils/win32-arggen.hh @@ -15,6 +15,7 @@ public: private: MemBuffer<char*> argv; + int argc; }; #endif hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-05-01 12:25:09
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via d368dbbcf7183e74dc9d22839f2a5feace2224fc (commit) via 79aeb0df593a81392e74cb150e7f08011ae41b95 (commit) via aca56d288eca6f7b1d42e6b19437103a88382de1 (commit) via 1f5b4210c18038930fbee77d32c65db2624972f0 (commit) via bc059307c27a7f8b2a923942edd23677251331dd (commit) from 160bce2e8979840bdf3337b5c5736925d007129f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit d368dbbcf7183e74dc9d22839f2a5feace2224fc Author: Wouter Vermaelen <ver...@gm...> Date: Thu Apr 30 14:52:28 2015 +0200 Made Rom objects movable OpenMSX has several rom mappers. They all contain a unique_ptr<Rom> instead of holding the Rom object by value. This causes an extra indirection whenever the content of the rom is being accessed (though the cacheline mechanism mitigates most of this cost). The reason for this extra indirection is that the Rom object is constructed before the mapper object is constructed (for most other MSXDevices that internally use a Rom this is not the case). The reason is that for mapper type detection we first need to investigate the content of the rom before we know the mapper type (e.g. by looking up the rom-checksum in a database or by some mapper guessing heuristics). The original solution was to first create a Rom object and then pass a (unique_)pointer to this Rom to the mapper constructor. After this patch we instead move the Rom object into the mapper object. By far the majority of the changes in this patch are boring mechanical changes. The only tricky part is the Rom move-constructor. Internally Rom contains a RomDebuggable object, and that one has a back-pointer to the Rom object. So when the Rom is moved that back-pointer needs to be updated. commit 79aeb0df593a81392e74cb150e7f08011ae41b95 Author: m9710797 <ver...@gm...> Date: Fri May 1 13:13:36 2015 +0200 Make more use of MemBuffer The previous patch made MemBuffer more light-weight. Actually there's no overhead anymore compared to directly using malloc/realloc/free. So convert (most) code that was still doing this to MemBuffer. commit aca56d288eca6f7b1d42e6b19437103a88382de1 Author: Wouter Vermaelen <ver...@gm...> Date: Thu Apr 30 16:53:42 2015 +0200 Don't store size in MemBuffer MemBuffer is basically a wrapper around malloc/realloc/free, though it's type-safe and it offers extra functionality like alignment. Before this patch MemBuffer internally stored both a pointer to the allocated memory block and the size of that block. This patch removes that size field. The size field was used to - offer STL-style begin()/end() iterators, none of the openMSX code uses this - offer a size() method The size() method is used, but only by about half of the MemBuffer users. Those users now have to manually keep track of the size. This change makes MemBuffer really a zero-overhead replacement for malloc. commit 1f5b4210c18038930fbee77d32c65db2624972f0 Author: Wouter Vermaelen <ver...@gm...> Date: Wed Apr 29 17:17:15 2015 +0200 Made File objects moveable + default-constructable Before this patch a File object always refers to an open file. If the code only sometimes needed an open file it typically used a unique_ptr<File> and when no file is currently needed it could use a nullptr. The previous patch made the internal implementation of a File object a single (unique_)pointer. So if we have unique_ptr<File> we actually have a pointer to a pointer. That seems like an unnecessary indirection. Let's try to improve that. The main change of this patch is to give a File object an additional possible state: it can now also represent a closed file handle. In other words a closed file handle does not refer to a file (the internal representation of the File object is a nullptr in this case). So now code can use a File object (by value) to represent both open and closed files (closed is equivalent to no file in this case). Another reason why unique_ptr<File> was used is to pass File objects around. The current implementation doesn't allow to make copies of File objects, so passing unique_ptr's was a good fit. Though we can make File objects movable and get rid of the extra indirection. This is the second major change of this patch. The rest of this patch (the majority) are mechanical changes that make use of the two above features. So we change - unique_ptr<File> -> File (and becaue of this replace '->' with '.') - check for nullptr -> check for is_open() - file.reset() -> file.close() commit bc059307c27a7f8b2a923942edd23677251331dd Author: m9710797 <ver...@gm...> Date: Thu Apr 30 20:31:36 2015 +0200 Remove FilePool/sha1 stuff from File class The File class is a generic file handling class, it allows to read/write files, it offers stuff like mmap(), it transparently handles (g)zipped files, etc. It can also calculate the sha1 of a file in an efficient way by using the FilePool cache. Though this sha1 stuff adds a significant (relative) overhead to each File object (the object size increases from 8 to 36 bytes). The interface of the class and the class invariants also become uglier (e.g. the getSha1Sum() method can only be called after setFilePool() is called, and setFilePool() can only be called at most once). Only the minority of the users of the File class actually need the extra sha1 functionality. So let's see if we can separate the basic file handling from the extra sha1 functionality. There was already a mechanism to calculate the sha1 for a file, namely FilePool::getSha1Sum(File&). Under the hood File::getSha1Sum() was implemented using the former function. Let's compare these two: - FilePool::getSha1Sum(File&) does a (O(N)) lookup of the filename. If found and if the file-modification-timestamp matches we return a cached sha1 value. If not we read the whole file and calculate the sha1 (and store the result in the cache). - File::getSha1Sum() has a local sha1-cache cache (O(1) lookup). So if the sha1 of this File object has already been calculated before we can immediately return the result, otherwise we fall back to the previous method. Though only for certain file types we request the sha1 for the same File object more than once. More on this below. When the File::write() method is called, both the local cache in the File object and the FilePool cache for this file are invalidated. Though when a file is been written to, the file modification timestamp changes, and the FilePool cache already becomes invalid. I mentioned that only for certain file types we repeatedly request the sha1. These are the cassette, rom and disk images (because the sha1 ends up in the period savestate snapshots of the reverse system). - Actually for cassette images (wav or cas) the sha1 is only calculated once and cached in the CassetteImage object (ATM we do not support writing to wav files). - Similar for rom images the sha1 is calculated once and cached in the ROM object. Detail: because of IPS patches the rom-sha1 might be different from the file-sha1. Also not all ROMs are backed by a file (see code for more details). That's why ROM has it's own sha1-cache instead of reusing the cache in the associated File object. - For disk images the (old) code _mostly_ relies on the sha1-cache in the File object. Though because of stuff like IPS patches and DirAsDsk (not backed by a File object) also the Disk classes already had a local sha1-cache, it's just not used consistently (this patch changes that). Of course it is possible to write to disks, in that case the local sha1-cache must be invalidated. So actually there's no good reason to keep the sha1 functionality in the generic File class. And thus this patch removes it. As already mentioned, this patch also reworks the sha1-caching mechanism in the Disk classes. ----------------------------------------------------------------------- Summary of changes: src/PrinterPortLogger.cc | 13 +++--- src/PrinterPortLogger.hh | 5 +- src/Reactor.cc | 3 +- src/ReverseManager.cc | 16 ++++--- src/ReverseManager.hh | 1 + src/SchedulerQueue.hh | 52 +++++++++++------------- src/cassette/CasImage.cc | 4 +- src/cassette/CassettePlayer.cc | 6 +- src/cassette/WavImage.cc | 4 +- src/fdc/DMKDiskImage.cc | 5 +- src/fdc/DMKDiskImage.hh | 2 +- src/fdc/DSKDiskImage.cc | 7 ++- src/fdc/DSKDiskImage.hh | 2 +- src/fdc/DiskChanger.cc | 40 +++++++++---------- src/fdc/DiskChanger.hh | 15 ++----- src/fdc/DiskFactory.cc | 2 - src/fdc/MSXtar.cc | 8 ++- src/fdc/RamDSKDiskImage.cc | 2 +- src/fdc/SectorAccessibleDisk.cc | 35 +++++++++------- src/fdc/SectorAccessibleDisk.hh | 4 +- src/fdc/XSADiskImage.cc | 15 ++++--- src/file/CompressedFileAdapter.cc | 8 ++-- src/file/CompressedFileAdapter.hh | 1 + src/file/File.cc | 44 +++++++++----------- src/file/File.hh | 44 +++++++++------------ src/file/FilePool.cc | 47 +++++++++++----------- src/file/FilePool.hh | 23 +++++------ src/file/GZFileAdapter.cc | 2 +- src/file/ZipFileAdapter.cc | 2 +- src/file/ZlibInflate.cc | 15 ++++--- src/file/ZlibInflate.hh | 2 +- src/ide/HD.cc | 52 ++++++++++++------------- src/ide/HD.hh | 6 +- src/ide/IDECDROM.cc | 21 +++++----- src/ide/IDECDROM.hh | 4 +- src/ide/SCSILS120.cc | 51 ++++++++++++------------ src/ide/SCSILS120.hh | 6 +- src/memory/MSXRom.cc | 13 ++---- src/memory/MSXRom.hh | 10 +--- src/memory/MegaFlashRomSCCPlus.cc | 5 +- src/memory/MegaFlashRomSCCPlus.hh | 2 +- src/memory/MegaFlashRomSCCPlusSD.cc | 5 +- src/memory/MegaFlashRomSCCPlusSD.hh | 2 +- src/memory/Ram.cc | 18 +++++---- src/memory/Ram.hh | 3 +- src/memory/Rom.cc | 69 ++++++++++++++++++++------------ src/memory/Rom.hh | 10 +++-- src/memory/RomArc.cc | 5 +- src/memory/RomArc.hh | 2 +- src/memory/RomAscii16_2.cc | 10 +---- src/memory/RomAscii16_2.hh | 4 +- src/memory/RomAscii16kB.cc | 5 +- src/memory/RomAscii16kB.hh | 2 +- src/memory/RomAscii8_8.cc | 9 +--- src/memory/RomAscii8_8.hh | 3 +- src/memory/RomAscii8kB.cc | 5 +- src/memory/RomAscii8kB.hh | 2 +- src/memory/RomBlocks.cc | 21 +++++----- src/memory/RomBlocks.hh | 2 +- src/memory/RomCrossBlaim.cc | 5 +- src/memory/RomCrossBlaim.hh | 2 +- src/memory/RomDRAM.cc | 5 +- src/memory/RomDRAM.hh | 2 +- src/memory/RomDooly.cc | 7 +-- src/memory/RomDooly.hh | 2 +- src/memory/RomFSA1FM.cc | 15 +++---- src/memory/RomFSA1FM.hh | 4 +- src/memory/RomFactory.cc | 6 +- src/memory/RomGameMaster2.cc | 9 +--- src/memory/RomGameMaster2.hh | 3 +- src/memory/RomGeneric16kB.cc | 5 +- src/memory/RomGeneric16kB.hh | 2 +- src/memory/RomGeneric8kB.cc | 5 +- src/memory/RomGeneric8kB.hh | 2 +- src/memory/RomHalnote.cc | 11 +---- src/memory/RomHalnote.hh | 3 +- src/memory/RomHarryFox.cc | 5 +- src/memory/RomHarryFox.hh | 2 +- src/memory/RomHolyQuran.cc | 5 +- src/memory/RomHolyQuran.hh | 2 +- src/memory/RomHolyQuran2.cc | 15 +++---- src/memory/RomHolyQuran2.hh | 2 +- src/memory/RomKonami.cc | 5 +- src/memory/RomKonami.hh | 2 +- src/memory/RomKonamiKeyboardMaster.cc | 5 +- src/memory/RomKonamiKeyboardMaster.hh | 2 +- src/memory/RomKonamiSCC.cc | 5 +- src/memory/RomKonamiSCC.hh | 2 +- src/memory/RomMSXDOS2.cc | 5 +- src/memory/RomMSXDOS2.hh | 2 +- src/memory/RomMSXtra.cc | 9 ++-- src/memory/RomMSXtra.hh | 2 +- src/memory/RomMajutsushi.cc | 5 +- src/memory/RomMajutsushi.hh | 2 +- src/memory/RomManbow2.cc | 5 +- src/memory/RomManbow2.hh | 3 +- src/memory/RomMatraInk.cc | 5 +- src/memory/RomMatraInk.hh | 2 +- src/memory/RomMultiRom.cc | 11 +---- src/memory/RomMultiRom.hh | 3 +- src/memory/RomNational.cc | 9 +--- src/memory/RomNational.hh | 3 +- src/memory/RomNettouYakyuu.cc | 5 +- src/memory/RomNettouYakyuu.hh | 2 +- src/memory/RomPadial16kB.cc | 5 +- src/memory/RomPadial16kB.hh | 2 +- src/memory/RomPadial8kB.cc | 5 +- src/memory/RomPadial8kB.hh | 2 +- src/memory/RomPageNN.cc | 5 +- src/memory/RomPageNN.hh | 2 +- src/memory/RomPanasonic.cc | 7 +--- src/memory/RomPanasonic.hh | 3 +- src/memory/RomPlain.cc | 21 +++++----- src/memory/RomPlain.hh | 2 +- src/memory/RomPlayBall.cc | 5 +- src/memory/RomPlayBall.hh | 2 +- src/memory/RomRType.cc | 5 +- src/memory/RomRType.hh | 2 +- src/memory/RomSuperLodeRunner.cc | 5 +- src/memory/RomSuperLodeRunner.hh | 2 +- src/memory/RomSuperSwangi.cc | 5 +- src/memory/RomSuperSwangi.hh | 2 +- src/memory/RomSynthesizer.cc | 5 +- src/memory/RomSynthesizer.hh | 2 +- src/memory/RomZemina126in1.cc | 5 +- src/memory/RomZemina126in1.hh | 2 +- src/memory/RomZemina80in1.cc | 5 +- src/memory/RomZemina80in1.hh | 2 +- src/memory/RomZemina90in1.cc | 5 +- src/memory/RomZemina90in1.hh | 2 +- src/serial/Midi_w32.cc | 48 ++++++++--------------- src/serial/Midi_w32.hh | 4 +- src/serialize.cc | 6 +-- src/serialize.hh | 2 +- src/sound/ResampleHQ.cc | 28 +++++++------ src/sound/SDLSoundDriver.cc | 20 +++++----- src/sound/SDLSoundDriver.hh | 1 + src/sound/SoundDevice.cc | 15 +++---- src/sound/YMF278.cc | 33 ++++++++-------- src/sound/YMF278.hh | 1 + src/utils/MemBuffer.hh | 55 +++++++++++++------------- src/utils/SerializeBuffer.cc | 38 ++++++------------ src/utils/SerializeBuffer.hh | 29 ++++++-------- src/utils/TigerTree.cc | 21 +++++----- src/video/AviWriter.cc | 19 ++++----- src/video/AviWriter.hh | 4 +- src/video/PostProcessor.cc | 33 +++++++--------- src/video/PostProcessor.hh | 3 - src/video/RawFrame.cc | 11 +---- src/video/RawFrame.hh | 5 +- src/video/SDLOffScreenSurface.cc | 13 +----- src/video/SDLOffScreenSurface.hh | 4 +- src/video/SDLSurfacePtr.hh | 32 +++++---------- src/video/ZMBVEncoder.cc | 5 ++- src/video/scalers/MLAAScaler.cc | 12 ++---- 155 files changed, 696 insertions(+), 845 deletions(-) diff --git a/src/PrinterPortLogger.cc b/src/PrinterPortLogger.cc index 7ab49ba..bca9228 100644 --- a/src/PrinterPortLogger.cc +++ b/src/PrinterPortLogger.cc @@ -1,7 +1,6 @@ #include "PrinterPortLogger.hh" #include "PlugException.hh" #include "FileException.hh" -#include "File.hh" #include "serialize.hh" #include "memory.hh" @@ -33,10 +32,10 @@ bool PrinterPortLogger::getStatus(EmuTime::param /*time*/) void PrinterPortLogger::setStrobe(bool strobe, EmuTime::param /*time*/) { - if (file && !strobe && prevStrobe) { + if (file.is_open() && !strobe && prevStrobe) { // falling edge - file->write(&toPrint, 1); - file->flush(); // optimize when it turns out flushing + file.write(&toPrint, 1); + file.flush(); // optimize when it turns out flushing // every time is too slow } prevStrobe = strobe; @@ -51,8 +50,8 @@ void PrinterPortLogger::plugHelper( Connector& /*connector*/, EmuTime::param /*time*/) { try { - file = make_unique<File>(logFilenameSetting.getString(), - File::TRUNCATE); + file = File(logFilenameSetting.getString(), + File::TRUNCATE); } catch (FileException& e) { throw PlugException("Couldn't plug printer logger: " + e.getMessage()); @@ -61,7 +60,7 @@ void PrinterPortLogger::plugHelper( void PrinterPortLogger::unplugHelper(EmuTime::param /*time*/) { - file.reset(); + file.close(); } const std::string& PrinterPortLogger::getName() const diff --git a/src/PrinterPortLogger.hh b/src/PrinterPortLogger.hh index 96515b9..af2ab61 100644 --- a/src/PrinterPortLogger.hh +++ b/src/PrinterPortLogger.hh @@ -3,12 +3,11 @@ #include "PrinterPortDevice.hh" #include "FilenameSetting.hh" -#include <memory> +#include "File.hh" namespace openmsx { class CommandController; -class File; class PrinterPortLogger final : public PrinterPortDevice { @@ -32,7 +31,7 @@ public: private: FilenameSetting logFilenameSetting; - std::unique_ptr<File> file; + File file; byte toPrint; bool prevStrobe; }; diff --git a/src/Reactor.cc b/src/Reactor.cc index 57a38e6..970c2a1 100644 --- a/src/Reactor.cc +++ b/src/Reactor.cc @@ -203,8 +203,7 @@ void Reactor::init() diskManipulator = make_unique<DiskManipulator>( *globalCommandController, *this); virtualDrive = make_unique<DiskChanger>( - "virtual_drive", *globalCommandController, - *diskFactory, *diskManipulator, true); + *this, "virtual_drive"); filePool = make_unique<FilePool>( *globalCommandController, *eventDistributor); userSettings = make_unique<UserSettings>( diff --git a/src/ReverseManager.cc b/src/ReverseManager.cc index c969b94..27c95a8 100644 --- a/src/ReverseManager.cc +++ b/src/ReverseManager.cc @@ -121,6 +121,7 @@ ReverseManager::ReverseChunk::ReverseChunk() ReverseManager::ReverseChunk::ReverseChunk(ReverseChunk&& rhs) : time (move(rhs.time)) , savestate (move(rhs.savestate)) + , size (move(rhs.size)) , eventCount(move(rhs.eventCount)) { } @@ -130,6 +131,7 @@ ReverseManager::ReverseChunk& ReverseManager::ReverseChunk::operator=( { time = move(rhs.time); savestate = move(rhs.savestate); + size = move(rhs.size); eventCount = move(rhs.eventCount); return *this; } @@ -279,9 +281,9 @@ void ReverseManager::debugInfo(TclObject& result) const res << p.first << ' ' << (chunk.time - EmuTime::zero).toDouble() << ' ' << ((chunk.time - EmuTime::zero).toDouble() / (getCurrentTime() - EmuTime::zero).toDouble()) * 100 << '%' - << " (" << chunk.savestate.size() << ')' + << " (" << chunk.size << ')' << " (next event index: " << chunk.eventCount << ")\n"; - totalSize += chunk.savestate.size(); + totalSize += chunk.size; } res << "total size: " << totalSize << '\n'; result.setString(string(res)); @@ -421,7 +423,7 @@ void ReverseManager::goTo( newBoard_ = reactor.createEmptyMotherBoard(); newBoard = newBoard_.get(); MemInputArchive in(it->second.savestate.data(), - it->second.savestate.size()); + it->second.size); in.serialize("machine", *newBoard); if (eventDelay) { @@ -555,7 +557,7 @@ void ReverseManager::saveReplay(array_ref<TclObject> tokens, TclObject& result) // restore first snapshot to be able to serialize it to a file auto initialBoard = reactor.createEmptyMotherBoard(); MemInputArchive in(begin(chunks)->second.savestate.data(), - begin(chunks)->second.savestate.size()); + begin(chunks)->second.size); in.serialize("machine", *initialBoard); replay.motherBoards.push_back(move(initialBoard)); @@ -582,7 +584,7 @@ void ReverseManager::saveReplay(array_ref<TclObject> tokens, TclObject& result) // this is a new one, add it to the list of snapshots Reactor::Board board = reactor.createEmptyMotherBoard(); MemInputArchive in(it->second.savestate.data(), - it->second.savestate.size()); + it->second.size); in.serialize("machine", *board); replay.motherBoards.push_back(move(board)); lastAddedIt = it; @@ -725,7 +727,7 @@ void ReverseManager::loadReplay( MemOutputArchive out; out.serialize("machine", *m); - newChunk.savestate = out.releaseBuffer(); + newChunk.savestate = out.releaseBuffer(newChunk.size); // update replayIndex // TODO: should we use <= instead?? @@ -864,7 +866,7 @@ void ReverseManager::takeSnapshot(EmuTime::param time) out.serialize("machine", motherBoard); ReverseChunk& newChunk = history.chunks[seqNum]; newChunk.time = time; - newChunk.savestate = out.releaseBuffer(); + newChunk.savestate = out.releaseBuffer(newChunk.size); newChunk.eventCount = replayIndex; } diff --git a/src/ReverseManager.hh b/src/ReverseManager.hh index bae5872..4a62c01 100644 --- a/src/ReverseManager.hh +++ b/src/ReverseManager.hh @@ -56,6 +56,7 @@ private: EmuTime time; MemBuffer<uint8_t> savestate; + size_t size; // Number of recorded events (or replay index) when this // snapshot was created. So when going back replay should diff --git a/src/SchedulerQueue.hh b/src/SchedulerQueue.hh index 9982d2d..2ac7a34 100644 --- a/src/SchedulerQueue.hh +++ b/src/SchedulerQueue.hh @@ -1,11 +1,14 @@ #ifndef SCHEDULERQUEUE_HH #define SCHEDULERQUEUE_HH +#include "MemBuffer.hh" #include "likely.hh" #include <algorithm> #include <cassert> #include <cstdlib> +namespace openmsx { + // This is similar to a sorted vector<T>. Though this container can have spare // capacity both at the front and at the end (vector only at the end). This // means that when you remove the smallest element and insert a new element @@ -16,25 +19,18 @@ template<typename T> class SchedulerQueue { public: + static const int CAPACITY = 32; // initial capacity + static const int SPARE_FRONT = 1; SchedulerQueue() + : storage (CAPACITY + 1) // one extra for sentinel + , storageEnd(storage.data() + CAPACITY) + , useBegin (storage.data() + SPARE_FRONT) + , useEnd (useBegin) { - static const int CAPACITY = 32; // initial capacity - static const int SPARE_FRONT = 1; - - // Allocate one extra to be able to store sentinel. - storageBegin = static_cast<T*>(malloc((CAPACITY + 1) * sizeof(T))); - storageEnd = storageBegin + CAPACITY; - useBegin = storageBegin + SPARE_FRONT; - useEnd = useBegin; } - ~SchedulerQueue() - { - free(storageBegin); - } - - size_t capacity() const { return storageEnd - storageBegin; } - size_t spareFront() const { return useBegin - storageBegin; } + size_t capacity() const { return storageEnd - storage.data(); } + size_t spareFront() const { return useBegin - storage.data(); } size_t spareBack() const { return storageEnd - useEnd; } size_t size() const { return useEnd - useBegin; } bool empty() const { return useEnd == useBegin; } @@ -66,7 +62,7 @@ public: while (!less(t, *it)) ++it; if ((it - useBegin) <= (useEnd - it)) { - if (likely(useBegin != storageBegin)) { + if (likely(useBegin != storage.data())) { insertFront(it, t); } else if (useEnd != storageEnd) { insertBack(it, t); @@ -76,7 +72,7 @@ public: } else { if (likely(useEnd != storageEnd)) { insertBack(it, t); - } else if (useBegin != storageBegin) { + } else if (useBegin != storage.data()) { insertFront(it, t); } else { insertRealloc(it, t); @@ -131,29 +127,29 @@ private: { static const int SPARE_FRONT = 1; - size_t oldSize = storageEnd - storageBegin; + size_t oldSize = storageEnd - storage.data(); size_t newSize = oldSize * 2; - // Allocate one extra to be able to store sentinel. - T* newStorage = static_cast<T*>(malloc((newSize + 1) * sizeof(T))); - T* newUseBegin = newStorage + SPARE_FRONT; + MemBuffer<T> newStorage(newSize + 1); // one extra for sentinel + T* newUseBegin = newStorage.data() + SPARE_FRONT; std::copy(useBegin, it, newUseBegin); *(newUseBegin + (it - useBegin)) = t; std::copy(it, useEnd, newUseBegin + (it - useBegin) + 1); - free(storageBegin); - storageBegin = newStorage; - storageEnd = newStorage + newSize; - useBegin = newUseBegin; - useEnd = useBegin + oldSize + 1; + storage = std::move(newStorage); + storageEnd = storage.data() + newSize; + useBegin = newUseBegin; + useEnd = useBegin + oldSize + 1; } private: - // Invariant: storageBegin <= useBegin <= useEnd <= storageEnd - T* storageBegin; + // Invariant: storage.data() <= useBegin <= useEnd <= storageEnd + MemBuffer<T> storage; T* storageEnd; T* useBegin; T* useEnd; }; +} // namespace openmsx + #endif // SCHEDULERQUEUE_HH diff --git a/src/cassette/CasImage.cc b/src/cassette/CasImage.cc index c95c855..e811ae8 100644 --- a/src/cassette/CasImage.cc +++ b/src/cassette/CasImage.cc @@ -1,5 +1,6 @@ #include "CasImage.hh" #include "File.hh" +#include "FilePool.hh" #include "Filename.hh" #include "CliComm.hh" #include "Clock.hh" @@ -224,8 +225,7 @@ void CasImage::convert(const Filename& filename, FilePool& filePool, CliComm& cl } // conversion successful, now calc sha1sum - file.setFilePool(filePool); - setSha1Sum(file.getSha1Sum()); + setSha1Sum(filePool.getSha1Sum(file)); } } // namespace openmsx diff --git a/src/cassette/CassettePlayer.cc b/src/cassette/CassettePlayer.cc index 86e3265..a3b59a2 100644 --- a/src/cassette/CassettePlayer.cc +++ b/src/cassette/CassettePlayer.cc @@ -865,9 +865,9 @@ void CassettePlayer::serialize(Archive& ar, unsigned version) casImage.updateAfterLoadState(); if (!oldChecksum.empty() && !FileOperations::exists(casImage.getResolved())) { - if (auto file = filePool.getFile( - FilePool::TAPE, oldChecksum)) { - casImage.setResolved(file->getURL()); + auto file = filePool.getFile(FilePool::TAPE, oldChecksum); + if (file.is_open()) { + casImage.setResolved(file.getURL()); } } try { diff --git a/src/cassette/WavImage.cc b/src/cassette/WavImage.cc index 38550bc..486da18 100644 --- a/src/cassette/WavImage.cc +++ b/src/cassette/WavImage.cc @@ -1,6 +1,7 @@ #include "WavImage.hh" #include "LocalFileReference.hh" #include "File.hh" +#include "FilePool.hh" #include "Math.hh" #include "memory.hh" #include "xrange.hh" @@ -17,8 +18,7 @@ WavImage::WavImage(const Filename& filename, FilePool& filePool) // used by an external API (see comments in LocalFileReference // for details). File file(filename); - file.setFilePool(filePool); - setSha1Sum(file.getSha1Sum()); + setSha1Sum(filePool.getSha1Sum(file)); localFile = LocalFileReference(file); } wav = WavData(localFile.getFilename(), 16, 0); diff --git a/src/fdc/DMKDiskImage.cc b/src/fdc/DMKDiskImage.cc index b4b695f..a830b6f 100644 --- a/src/fdc/DMKDiskImage.cc +++ b/src/fdc/DMKDiskImage.cc @@ -2,6 +2,7 @@ #include "RawTrack.hh" #include "DiskExceptions.hh" #include "File.hh" +#include "FilePool.hh" #include <algorithm> #include <cassert> @@ -194,9 +195,9 @@ bool DMKDiskImage::isWriteProtectedImpl() const return writeProtected || file->isReadOnly(); } -Sha1Sum DMKDiskImage::getSha1Sum() +Sha1Sum DMKDiskImage::getSha1SumImpl(FilePool& filepool) { - return file->getSha1Sum(); + return filepool.getSha1Sum(*file); } void DMKDiskImage::detectGeometryFallback() diff --git a/src/fdc/DMKDiskImage.hh b/src/fdc/DMKDiskImage.hh index 0566de9..f305807 100644 --- a/src/fdc/DMKDiskImage.hh +++ b/src/fdc/DMKDiskImage.hh @@ -26,7 +26,7 @@ public: void writeSectorImpl(size_t sector, const SectorBuffer& buf) override; size_t getNbSectorsImpl() const override; bool isWriteProtectedImpl() const override; - Sha1Sum getSha1Sum() override; + Sha1Sum getSha1SumImpl(FilePool& filepool) override; private: void detectGeometryFallback() override; diff --git a/src/fdc/DSKDiskImage.cc b/src/fdc/DSKDiskImage.cc index 9dbecb6..6b1db10 100644 --- a/src/fdc/DSKDiskImage.cc +++ b/src/fdc/DSKDiskImage.cc @@ -1,5 +1,6 @@ #include "DSKDiskImage.hh" #include "File.hh" +#include "FilePool.hh" namespace openmsx { @@ -39,12 +40,12 @@ bool DSKDiskImage::isWriteProtectedImpl() const return file->isReadOnly(); } -Sha1Sum DSKDiskImage::getSha1Sum() +Sha1Sum DSKDiskImage::getSha1SumImpl(FilePool& filePool) { if (hasPatches()) { - return SectorAccessibleDisk::getSha1Sum(); + return SectorAccessibleDisk::getSha1SumImpl(filePool); } - return file->getSha1Sum(); + return filePool.getSha1Sum(*file); } } // namespace openmsx diff --git a/src/fdc/DSKDiskImage.hh b/src/fdc/DSKDiskImage.hh index bc49718..bbf7c41 100644 --- a/src/fdc/DSKDiskImage.hh +++ b/src/fdc/DSKDiskImage.hh @@ -19,7 +19,7 @@ private: void readSectorImpl (size_t sector, SectorBuffer& buf) override; void writeSectorImpl(size_t sector, const SectorBuffer& buf) override; bool isWriteProtectedImpl() const override; - Sha1Sum getSha1Sum() override; + Sha1Sum getSha1SumImpl(FilePool& filepool) override; const std::shared_ptr<File> file; }; diff --git a/src/fdc/DiskChanger.cc b/src/fdc/DiskChanger.cc index f459eff..3a258a6 100644 --- a/src/fdc/DiskChanger.cc +++ b/src/fdc/DiskChanger.cc @@ -48,39 +48,32 @@ DiskChanger::DiskChanger(MSXMotherBoard& board, const string& driveName_, bool createCmd, bool isDoubleSidedDrive) - : controller(board.getCommandController()) + : reactor(board.getReactor()) + , controller(board.getCommandController()) , stateChangeDistributor(&board.getStateChangeDistributor()) , scheduler(&board.getScheduler()) - , filePool(&board.getReactor().getFilePool()) - , diskFactory(board.getReactor().getDiskFactory()) - , manipulator(board.getReactor().getDiskManipulator()) , driveName(driveName_) , doubleSidedDrive(isDoubleSidedDrive) { init(board.getMachineID() + "::", createCmd); } -DiskChanger::DiskChanger(const string& driveName_, - CommandController& controller_, - DiskFactory& diskFactory_, - DiskManipulator& manipulator_, - bool createCmd) - : controller(controller_) +DiskChanger::DiskChanger(Reactor& reactor_, const string& driveName_) + : reactor(reactor_) + , controller(reactor.getCommandController()) , stateChangeDistributor(nullptr) , scheduler(nullptr) - , filePool(nullptr) - , diskFactory(diskFactory_) - , manipulator(manipulator_) , driveName(driveName_) , doubleSidedDrive(true) // irrelevant, but needs a value { - init("", createCmd); + init("", true); } void DiskChanger::init(const string& prefix, bool createCmd) { if (createCmd) createCommand(); ejectDisk(); + auto& manipulator = reactor.getDiskManipulator(); manipulator.registerDrive(*this, prefix); if (stateChangeDistributor) { stateChangeDistributor->registerListener(*this); @@ -98,6 +91,7 @@ DiskChanger::~DiskChanger() if (stateChangeDistributor) { stateChangeDistributor->unregisterListener(*this); } + auto& manipulator = reactor.getDiskManipulator(); manipulator.unregisterDrive(*this); } @@ -173,6 +167,7 @@ int DiskChanger::insertDisk(string_ref filename) void DiskChanger::insertDisk(array_ref<TclObject> args) { const string& diskImage = FileOperations::getConventionalPath(args[1].getString()); + auto& diskFactory = reactor.getDiskFactory(); std::unique_ptr<Disk> newDisk(diskFactory.createDisk(diskImage, *this)); for (unsigned i = 2; i < args.size(); ++i) { Filename filename(args[i].getString().str(), userFileContext()); @@ -301,9 +296,9 @@ bool DiskCommand::needRecord(array_ref<TclObject> tokens) const return tokens.size() > 1; } -static string calcSha1(SectorAccessibleDisk* disk) +static string calcSha1(SectorAccessibleDisk* disk, FilePool& filePool) { - return disk ? disk->getSha1Sum().toString() : ""; + return disk ? disk->getSha1Sum(filePool).toString() : ""; } // version 1: initial version @@ -331,9 +326,10 @@ void DiskChanger::serialize(Archive& ar, unsigned version) } ar.serialize("patches", patches); + auto& filePool = reactor.getFilePool(); string oldChecksum; if (!ar.isLoader()) { - oldChecksum = calcSha1(getSectorAccessibleDisk()); + oldChecksum = calcSha1(getSectorAccessibleDisk(), filePool); } ar.serialize("checksum", oldChecksum); @@ -348,11 +344,11 @@ void DiskChanger::serialize(Archive& ar, unsigned version) // alternative is to prefer the exact sha1sum match. // I'm not sure which alternative is better. if (!FileOperations::exists(name)) { - assert(filePool); assert(!oldChecksum.empty()); - if (auto file = filePool->getFile( - FilePool::DISK, Sha1Sum(oldChecksum))) { - name = file->getURL(); + auto file = filePool.getFile( + FilePool::DISK, Sha1Sum(oldChecksum)); + if (file.is_open()) { + name = file.getURL(); } } vector<TclObject> args = @@ -373,7 +369,7 @@ void DiskChanger::serialize(Archive& ar, unsigned version) } } - string newChecksum = calcSha1(getSectorAccessibleDisk()); + string newChecksum = calcSha1(getSectorAccessibleDisk(), filePool); if (oldChecksum != newChecksum) { controller.getCliComm().printWarning( "The content of the diskimage " + diff --git a/src/fdc/DiskChanger.hh b/src/fdc/DiskChanger.hh index 7bef379..b6d1d55 100644 --- a/src/fdc/DiskChanger.hh +++ b/src/fdc/DiskChanger.hh @@ -14,10 +14,8 @@ namespace openmsx { class CommandController; class StateChangeDistributor; class Scheduler; -class FilePool; class MSXMotherBoard; -class DiskFactory; -class DiskManipulator; +class Reactor; class Disk; class DiskCommand; class TclObject; @@ -31,11 +29,8 @@ public: const std::string& driveName, bool createCommand = true, bool isDoubleSidedDrive = true); - DiskChanger(const std::string& driveName, - CommandController& commandController, - DiskFactory& diskFactory, - DiskManipulator& manipulator, - bool createCommand); + DiskChanger(Reactor& reactor, + const std::string& driveName); // for virtual_drive ~DiskChanger(); void createCommand(); @@ -72,12 +67,10 @@ private: void signalStateChange(const std::shared_ptr<StateChange>& event) override; void stopReplay(EmuTime::param time) override; + Reactor& reactor; CommandController& controller; StateChangeDistributor* stateChangeDistributor; Scheduler* scheduler; - FilePool* filePool; - DiskFactory& diskFactory; - DiskManipulator& manipulator; const std::string driveName; std::unique_ptr<Disk> disk; diff --git a/src/fdc/DiskFactory.cc b/src/fdc/DiskFactory.cc index 9fa984d..c8e6881 100644 --- a/src/fdc/DiskFactory.cc +++ b/src/fdc/DiskFactory.cc @@ -54,8 +54,6 @@ std::unique_ptr<Disk> DiskFactory::createDisk( } try { auto file = std::make_shared<File>(filename, File::PRE_CACHE); - file->setFilePool(reactor.getFilePool()); - try { // first try XSA return make_unique<XSADiskImage>(filename, *file); diff --git a/src/fdc/MSXtar.cc b/src/fdc/MSXtar.cc index af5c3db..c8e9695 100644 --- a/src/fdc/MSXtar.cc +++ b/src/fdc/MSXtar.cc @@ -103,8 +103,9 @@ void MSXtar::parseBootSector(const MSXBootSector& boot) void MSXtar::writeLogicalSector(unsigned sector, const SectorBuffer& buf) { + assert(!fatBuffer.empty()); unsigned fatSector = sector - 1; - if ((fatSector < sectorsPerFat) && !fatBuffer.empty()) { + if (fatSector < sectorsPerFat) { // we have a cache and this is a sector of the 1st FAT // --> update cache memcpy(&fatBuffer[fatSector], &buf, sizeof(buf)); @@ -116,8 +117,9 @@ void MSXtar::writeLogicalSector(unsigned sector, const SectorBuffer& buf) void MSXtar::readLogicalSector(unsigned sector, SectorBuffer& buf) { + assert(!fatBuffer.empty()); unsigned fatSector = sector - 1; - if ((fatSector < sectorsPerFat) && !fatBuffer.empty()) { + if (fatSector < sectorsPerFat) { // we have a cache and this is a sector of the 1st FAT // --> read from cache memcpy(&buf, &fatBuffer[fatSector], sizeof(buf)); @@ -152,7 +154,7 @@ MSXtar::~MSXtar() { if (!fatCacheDirty) return; - for (unsigned i = 0; i < fatBuffer.size(); ++i) { + for (unsigned i = 0; i < sectorsPerFat; ++i) { try { disk.writeSector(i + 1, fatBuffer[i]); } catch (MSXException&) { diff --git a/src/fdc/RamDSKDiskImage.cc b/src/fdc/RamDSKDiskImage.cc index 4b6bc56..c01f2fb 100644 --- a/src/fdc/RamDSKDiskImage.cc +++ b/src/fdc/RamDSKDiskImage.cc @@ -8,7 +8,7 @@ RamDSKDiskImage::RamDSKDiskImage(size_t size) : SectorBasedDisk(DiskName(Filename(), "ramdsk")) , data(size / sizeof(SectorBuffer)) { - setNbSectors(data.size()); + setNbSectors(size / sizeof(SectorBuffer)); DiskImageUtils::format(*this); } diff --git a/src/fdc/SectorAccessibleDisk.cc b/src/fdc/SectorAccessibleDisk.cc index 009772a..b7c12f4 100644 --- a/src/fdc/SectorAccessibleDisk.cc +++ b/src/fdc/SectorAccessibleDisk.cc @@ -80,28 +80,33 @@ bool SectorAccessibleDisk::hasPatches() const return !patch->isEmptyPatch(); } -Sha1Sum SectorAccessibleDisk::getSha1Sum() +Sha1Sum SectorAccessibleDisk::getSha1Sum(FilePool& filePool) { checkCaches(); if (sha1cache.empty()) { - try { - setPeekMode(true); - SHA1 sha1; - for (auto i : xrange(getNbSectors())) { - SectorBuffer buf; - readSector(i, buf); - sha1.update(buf.raw, sizeof(buf)); - } - sha1cache = sha1.digest(); - setPeekMode(false); - } catch (MSXException&) { - setPeekMode(false); - throw; - } + sha1cache = getSha1SumImpl(filePool); } return sha1cache; } +Sha1Sum SectorAccessibleDisk::getSha1SumImpl(FilePool& /*filePool*/) +{ + try { + setPeekMode(true); + SHA1 sha1; + for (auto i : xrange(getNbSectors())) { + SectorBuffer buf; + readSector(i, buf); + sha1.update(buf.raw, sizeof(buf)); + } + setPeekMode(false); + return sha1.digest(); + } catch (MSXException&) { + setPeekMode(false); + throw; + } +} + int SectorAccessibleDisk::readSectors ( SectorBuffer* buffers, size_t startSector, size_t nbSectors) { diff --git a/src/fdc/SectorAccessibleDisk.hh b/src/fdc/SectorAccessibleDisk.hh index 1dbf717..1ad7b88 100644 --- a/src/fdc/SectorAccessibleDisk.hh +++ b/src/fdc/SectorAccessibleDisk.hh @@ -9,6 +9,7 @@ namespace openmsx { +class FilePool; class PatchInterface; class SectorAccessibleDisk @@ -35,7 +36,7 @@ public: /** Calculate SHA1 of the content of this disk. * This value is cached (and flushed on writes). */ - virtual Sha1Sum getSha1Sum(); + Sha1Sum getSha1Sum(FilePool& filepool); // For compatibility with nowind // - read/write multiple sectors instead of one-per-one @@ -58,6 +59,7 @@ protected: virtual void checkCaches(); virtual void flushCaches(); + virtual Sha1Sum getSha1SumImpl(FilePool& filepool); private: virtual void readSectorImpl (size_t sector, SectorBuffer& buf) = 0; diff --git a/src/fdc/XSADiskImage.cc b/src/fdc/XSADiskImage.cc index e04c7b8..b15cf05 100644 --- a/src/fdc/XSADiskImage.cc +++ b/src/fdc/XSADiskImage.cc @@ -12,7 +12,7 @@ class XSAExtractor { public: explicit XSAExtractor(File& file); - void getData(MemBuffer<SectorBuffer>& data); + unsigned getData(MemBuffer<SectorBuffer>& data); private: static const int MAXSTRLEN = 254; @@ -37,6 +37,7 @@ private: MemBuffer<SectorBuffer> outBuf; // the output buffer const byte* inBufPos; // pos in input buffer const byte* inBufEnd; + unsigned sectors; int updHufCnt; int cpDist[TBLSIZE + 1]; @@ -57,8 +58,8 @@ XSADiskImage::XSADiskImage(Filename& filename, File& file) : SectorBasedDisk(filename) { XSAExtractor extractor(file); - extractor.getData(data); - setNbSectors(data.size()); + unsigned sectors = extractor.getData(data); + setNbSectors(sectors); } void XSADiskImage::readSectorImpl(size_t sector, SectorBuffer& buf) @@ -99,10 +100,11 @@ XSAExtractor::XSAExtractor(File& file) unLz77(); } -void XSAExtractor::getData(MemBuffer<SectorBuffer>& data) +unsigned XSAExtractor::getData(MemBuffer<SectorBuffer>& data) { // destroys internal outBuf, but that's ok data.swap(outBuf); + return sectors; } // Get the next character from the input buffer @@ -122,7 +124,8 @@ void XSAExtractor::chkHeader() for (int i = 0, base = 1; i < 4; ++i, base <<= 8) { outBufLen += base * charIn(); } - outBuf.resize((outBufLen + 511) / 512); + sectors = (outBufLen + 511) / 512; + outBuf.resize(sectors); // skip compressed length inBufPos += 4; @@ -136,7 +139,7 @@ void XSAExtractor::unLz77() { bitCnt = 0; // no bits read yet - size_t remaining = outBuf.size() * sizeof(SectorBuffer); + size_t remaining = sectors * sizeof(SectorBuffer); byte* out = outBuf.data()->raw; size_t outIdx = 0; while (true) { diff --git a/src/file/CompressedFileAdapter.cc b/src/file/CompressedFileAdapter.cc index 932d3cd..0254877 100644 --- a/src/file/CompressedFileAdapter.cc +++ b/src/file/CompressedFileAdapter.cc @@ -48,10 +48,10 @@ void CompressedFileAdapter::decompress() void CompressedFileAdapter::read(void* buffer, size_t num) { decompress(); - const MemBuffer<byte>& buf = decompressed->buf; - if (buf.size() < (pos + num)) { + if (decompressed->size < (pos + num)) { throw FileException("Read beyond end of file"); } + const auto& buf = decompressed->buf; memcpy(buffer, buf.data() + pos, num); pos += num; } @@ -64,7 +64,7 @@ void CompressedFileAdapter::write(const void* /*buffer*/, size_t /*num*/) const byte* CompressedFileAdapter::mmap(size_t& size) { decompress(); - size = decompressed->buf.size(); + size = decompressed->size; return reinterpret_cast<const byte*>(decompressed->buf.data()); } @@ -76,7 +76,7 @@ void CompressedFileAdapter::munmap() size_t CompressedFileAdapter::getSize() { decompress(); - return decompressed->buf.size(); + return decompressed->size; } void CompressedFileAdapter::seek(size_t newpos) diff --git a/src/file/CompressedFileAdapter.hh b/src/file/CompressedFileAdapter.hh index 2576312..809d004 100644 --- a/src/file/CompressedFileAdapter.hh +++ b/src/file/CompressedFileAdapter.hh @@ -12,6 +12,7 @@ class CompressedFileAdapter : public FileBase public: struct Decompressed { MemBuffer<byte> buf; + size_t size; std::string originalName; std::string cachedURL; time_t cachedModificationDate; diff --git a/src/file/File.cc b/src/file/File.cc index 51b219d..ef43802 100644 --- a/src/file/File.cc +++ b/src/file/File.cc @@ -1,6 +1,5 @@ #include "File.hh" #include "Filename.hh" -#include "FilePool.hh" #include "LocalFile.hh" #include "GZFileAdapter.hh" #include "ZipFileAdapter.hh" @@ -13,6 +12,10 @@ using std::string; namespace openmsx { +File::File() +{ +} + static std::unique_ptr<FileBase> init(string_ref url, File::OpenMode mode) { static const byte GZ_HEADER[3] = { 0x1F, 0x8B, 0x08 }; @@ -39,25 +42,26 @@ static std::unique_ptr<FileBase> init(string_ref url, File::OpenMode mode) File::File(const Filename& filename, OpenMode mode) : file(init(filename.getResolved(), mode)) - , filepool(nullptr) { } File::File(string_ref url, OpenMode mode) : file(init(url, mode)) - , filepool(nullptr) { } File::File(string_ref filename, const char* mode) : file(make_unique<LocalFile>(filename, mode)) - , filepool(nullptr) { } File::File(const Filename& filename, const char* mode) : file(make_unique<LocalFile>(filename.getResolved(), mode)) - , filepool(nullptr) +{ +} + +File::File(File&& other) + : file(std::move(other.file)) { } @@ -65,6 +69,17 @@ File::~File() { } +File& File::operator=(File&& other) +{ + file = std::move(other.file); + return *this; +} + +void File::close() +{ + file.reset(); +} + void File::read(void* buffer, size_t num) { file->read(buffer, num); @@ -72,10 +87,6 @@ void File::read(void* buffer, size_t num) void File::write(const void* buffer, size_t num) { - if (filepool) { - cachedSha1.clear(); - filepool->removeSha1Sum(*this); - } file->write(buffer, num); } @@ -140,19 +151,4 @@ time_t File::getModificationDate() return file->getModificationDate(); } -Sha1Sum File::getSha1Sum() -{ - assert(filepool); // must be set - if (cachedSha1.empty()) { - cachedSha1 = filepool->getSha1Sum(*this); - } - return cachedSha1; -} - -void File::setFilePool(FilePool& filepool_) -{ - assert(!filepool); // can only be set once - filepool = &filepool_; -} - } // namespace openmsx diff --git a/src/file/File.hh b/src/file/File.hh index 2af4b0b..7189e74 100644 --- a/src/file/File.hh +++ b/src/file/File.hh @@ -1,9 +1,7 @@ #ifndef FILE_HH #define FILE_HH -#include "sha1.hh" #include "openmsx.hh" -#include "noncopyable.hh" #include "string_ref.hh" #include <memory> #include <ctime> @@ -12,9 +10,8 @@ namespace openmsx { class Filename; class FileBase; -class FilePool; -class File : private noncopyable +class File { public: enum OpenMode { @@ -26,6 +23,12 @@ public: PRE_CACHE, }; + /** Create a closed file handle. + * The only valid operations on such an object are is_open() and the + * move-assignment operator. + */ + File(); + /** Create file object and open underlying file. * @param filename Name of the file to be opened. * @param mode Mode to open the file in: @@ -44,9 +47,20 @@ public: */ File(string_ref filename, const char* mode); File(const Filename& filename, const char* mode); + File(File&& other); ~File(); + File& operator=(File&& other); + + /** Return true iff this file handle refers to an open file. */ + bool is_open() const { return file.get(); } + + /** Close the current file. + * Equivalent to assigning a default constructed value to this object. + */ + void close(); + /** Read from file. * @param buffer Destination address * @param num Number of bytes to read @@ -125,23 +139,6 @@ public: */ time_t getModificationDate(); - /** Calculate sha1sum of this file. - * - * If the FilePool was set (see setFilePool()), the calculation can - * possibly be avoided by using the pool as a cache. - * Note that currently it's even an error to call this method without - * first having called setFilePool(), we might change this in the - * future. - */ - Sha1Sum getSha1Sum(); - - /** Set FilePool, see also getSha1Sum() - * FilePool is used to lookup/store sha1sum<->filename mappings. But - * also to invalidate these mappings on writes to this file (the file - * modification date is used as well to detect writes). - */ - void setFilePool(FilePool& filepool); - private: friend class LocalFileReference; /** This is an internal method used by LocalFileReference. @@ -150,10 +147,7 @@ private: */ const std::string getLocalReference() const; - const std::unique_ptr<FileBase> file; - - FilePool* filepool; - Sha1Sum cachedSha1; + std::unique_ptr<FileBase> file; }; } // namespace openmsx diff --git a/src/file/FilePool.cc b/src/file/FilePool.cc index c61c888..89e4880 100644 --- a/src/file/FilePool.cc +++ b/src/file/FilePool.cc @@ -249,11 +249,10 @@ FilePool::Directories FilePool::getDirectories() const return result; } -unique_ptr<File> FilePool::getFile(FileType fileType, const Sha1Sum& sha1sum) +File FilePool::getFile(FileType fileType, const Sha1Sum& sha1sum) { - unique_ptr<File> result; - result = getFromPool(sha1sum); - if (result) return result; + File result = getFromPool(sha1sum); + if (result.is_open()) return result; // not found in cache, need to scan directories ScanProgress progress; @@ -271,7 +270,7 @@ unique_ptr<File> FilePool::getFile(FileType fileType, const Sha1Sum& sha1sum) if (d.types & fileType) { string path = FileOperations::expandTilde(d.path); result = scanDirectory(sha1sum, path, d.path, progress); - if (result) return result; + if (result.is_open()) return result; } } @@ -315,7 +314,7 @@ static Sha1Sum calcSha1sum(File& file, CliComm& cliComm, EventDistributor& distr return sha1.digest(); } -unique_ptr<File> FilePool::getFromPool(const Sha1Sum& sha1sum) +File FilePool::getFromPool(const Sha1Sum& sha1sum) { auto bound = equal_range(begin(pool), end(pool), sha1sum, LessTupleElement<0>()); @@ -327,8 +326,8 @@ unique_ptr<File> FilePool::getFromPool(const Sha1Sum& sha1sum) auto& time = get<1>(*it); const auto& filename = get<2>(*it); try { - auto file = make_unique<File>(filename); - auto newTime = file->getModificationDate(); + File file(filename); + auto newTime = file.getModificationDate(); if (time == newTime) { // When modification time is unchanged, assume // sha1sum is also unchanged. So avoid @@ -337,7 +336,7 @@ unique_ptr<File> FilePool::getFromPool(const Sha1Sum& sha1sum) } time = newTime; // update timestamp needWrite = true; - auto newSum = calcSha1sum(*file, cliComm, distributor); + auto newSum = calcSha1sum(file, cliComm, distributor); if (newSum == sha1sum) { // Modification time was changed, but // (recalculated) sha1sum is still the same. @@ -359,10 +358,10 @@ unique_ptr<File> FilePool::getFromPool(const Sha1Sum& sha1sum) --last; } } - return nullptr; // not found + return File(); // not found } -unique_ptr<File> FilePool::scanDirectory( +File FilePool::scanDirectory( const Sha1Sum& sha1sum, const string& directory, const string& poolPath, ScanProgress& progress) { @@ -372,13 +371,13 @@ unique_ptr<File> FilePool::scanDirectory( // Scanning can take a long time. Allow to exit // openmsx when it takes too long. Stop scanning // by pretending we didn't find the file. - return nullptr; + return File(); } string file = d->d_name; string path = directory + '/' + file; FileOperations::Stat st; if (FileOperations::getStat(path, st)) { - unique_ptr<File> result; + File result; if (FileOperations::isRegularFile(st)) { result = scanFile(sha1sum, path, st, poolPath, progress); } else if (FileOperations::isDirectory(st)) { @@ -386,15 +385,15 @@ unique_ptr<File> FilePool::scanDirectory( result = scanDirectory(sha1sum, path, poolPath, progress); } } - if (result) return result; + if (result.is_open()) return result; } } - return nullptr; // not found + return File(); // not found } -unique_ptr<File> FilePool::scanFile(const Sha1Sum& sha1sum, const string& filename, - const FileOperations::Stat& st, const string& poolPath, - ScanProgress& progress) +File FilePool::scanFile(const Sha1Sum& sha1sum, const string& filename, + const FileOperations::Stat& st, const string& poolPath, + ScanProgress& progress) { ++progress.amountScanned; // Periodically send a progress message with the current filename @@ -415,8 +414,8 @@ unique_ptr<File> FilePool::scanFile(const Sha1Sum& sha1sum, const string& filena if (it == end(pool)) { // not in pool try { - auto file = make_unique<File>(filename); - auto sum = calcSha1sum(*file, cliComm, distributor); + File file(filename); + auto sum = calcSha1sum(file, cliComm, distributor); auto time = FileOperations::getModificationDate(st); insert(sum, time, filename); if (sum == sha1sum) { @@ -433,12 +432,12 @@ unique_ptr<File> FilePool::scanFile(const Sha1Sum& sha1sum, const string& filena if (time == get<1>(*it)) { // db is still up to date if (get<0>(*it) == sha1sum) { - return make_unique<File>(filename); + return File(filename); } } else { // db outdated - auto file = make_unique<File>(filename); - auto sum = calcSha1sum(*file, cliComm, distributor); + File file(filename); + auto sum = calcSha1sum(file, cliComm, distributor); get<1>(*it) = time; adjust(it, sum); if (sum == sha1sum) { @@ -450,7 +449,7 @@ unique_ptr<File> FilePool::scanFile(const Sha1Sum& sha1sum, const string& filena remove(it); } } - return nullptr; // not found + return File(); // not found } FilePool::Pool::iterator FilePool::findInDatabase(const string& filename) diff --git a/src/file/FilePool.hh b/src/file/FilePool.hh index 09eb088..a68a88e 100644 --- a/src/file/FilePool.hh +++ b/src/file/FilePool.hh @@ -7,7 +7,6 @@ #include "EventListener.hh" #include "sha1.hh" #include "noncopyable.hh" -#include <memory> #include <string> #include <tuple> #include <vector> @@ -36,7 +35,7 @@ public: * If found it returns the (already opened) file, * if not found it returns nullptr. */ - std::unique_ptr<File> getFile(FileType fileType, const Sha1Sum& sha1sum); + File getFile(FileType fileType, const Sha1Sum& sha1sum); /** Calculate sha1sum for the given File object. * If possible the result is retrieved from cache, avoiding the @@ -71,16 +70,16 @@ private: void readSha1sums(); void writeSha1sums(); - std::unique_ptr<File> getFromPool(const Sha1Sum& sha1sum); - std::unique_ptr<File> scanDirectory(const Sha1Sum& sha1sum, - const std::string& directory, - const std::string& poolPath, - ScanProgress& progress); - std::unique_ptr<File> scanFile(const Sha1Sum& sha1sum, - const std::string& filename, - const FileOperations::Stat& st, - const std::string& poolPath, - ScanProgress& progress); + File getFromPool(const Sha1Sum& sha1sum); + File scanDirectory(const Sha1Sum& sha1sum, + const std::string& directory, + const std::string& poolPath, + ScanProgress& progress); + File scanFile(const Sha1Sum& sha1sum, + const std::string& filename, + const FileOperations::Stat& st, + const std::string& poolPath, + ScanProgress& progress); Pool::iterator findInDatabase(const std::string& filename); Directories getDirectories() const; diff --git a/src/file/GZFileAdapter.cc b/src/file/GZFileAdapter.cc index fb5d7f0..d07c362 100644 --- a/src/file/GZFileAdapter.cc +++ b/src/file/GZFileAdapter.cc @@ -61,7 +61,7 @@ void GZFileAdapter::decompress(FileBase& file, Decompressed& decompressed) if (!skipHeader(zlib, decompressed.originalName)) { throw FileException("Not a gzip header"); } - zlib.inflate(decompressed.buf); + decompressed.size = zlib.inflate(decompressed.buf); } } // namespace openmsx diff --git a/src/file/ZipFileAdapter.cc b/src/file/ZipFileAdapter.cc index 5c987a3..ea6fffc 100644 --- a/src/file/ZipFileAdapter.cc +++ b/src/file/ZipFileAdapter.cc @@ -37,7 +37,7 @@ void ZipFileAdapter::decompress(FileBase& file, Decompressed& decompressed) decompressed.originalName = zlib.getString(filenameLen); // original filename zlib.skip(extraFieldLen); // skip "extra field" - zlib.inflate(decompressed.buf, origSize); + decompressed.size = zlib.inflate(decompressed.buf, origSize); } } // namespace openmsx diff --git a/src/file/ZlibInflate.cc b/src/file/ZlibInflate.cc index f7f86b4..e633471 100644 --- a/src/file/ZlibInflate.cc +++ b/src/file/ZlibInflate.cc @@ -80,7 +80,7 @@ std::string ZlibInflate::getCString() return result; } -void ZlibInflate::inflate(MemBuffer<byte>& output, size_t sizeHint) +size_t ZlibInflate::inflate(MemBuffer<byte>& output, size_t sizeHint) { int initErr = inflateInit2(&s, -MAX_WBITS); if (initErr != Z_OK) { @@ -89,8 +89,9 @@ void ZlibInflate::inflate(MemBuffer<byte>& output, size_t sizeHint) } wasInit = true; - output.resize(sizeHint); - s.avail_out = uInt(output.size()); // TODO overflow? + size_t outSize = sizeHint; + output.resize(outSize); + s.avail_out = uInt(outSize); // TODO overflow? while (true) { s.next_out = output.data() + s.total_out; int err = ::inflate(&s, Z_NO_FLUSH); @@ -101,13 +102,15 @@ void ZlibInflate::inflate(MemBuffer<byte>& output, size_t sizeHint) throw FileException(StringOp::Builder() << "Error decompressing gzip: " << zError(err)); } - auto oldSize = output.size(); - output.resize(oldSize * 2); // double buffer size - s.avail_out = uInt(output.size() - oldSize); // TODO overflow? + auto oldSize = outSize; + outSize = oldSize * 2; // double buffer size + output.resize(outSize); + s.avail_out = uInt(outSize - oldSize); // TODO overflow? } // set actual size output.resize(s.total_out); + return s.total_out; } } // namespace openmsx diff --git a/src/file/ZlibInflate.hh b/src/file/ZlibInflate.hh index 915f81e..799b1e6 100644 --- a/src/file/ZlibInflate.hh +++ b/src/file/ZlibInflate.hh @@ -21,7 +21,7 @@ public: std::string getString(size_t len); std::string getCString(); - void inflate(MemBuffer<byte>& output, size_t sizeHint = 65536); + size_t inflate(MemBuffer<byte>& output, size_t sizeHint = 65536); private: z_stream s; diff --git a/src/ide/HD.cc b/src/ide/HD.cc index 98e60e5..a348863 100644 --- a/src/ide/HD.cc +++ b/src/ide/HD.cc @@ -1,7 +1,7 @@ #include "HD.hh" -#include "File.hh" #include "FileContext.hh" #include "FileException.hh" +#include "FilePool.hh" #include "DeviceConfig.hh" #include "CliComm.hh" #include "MSXMotherBoard.hh" @@ -42,9 +42,8 @@ HD::HD(const DeviceConfig& config) string resolved = config.getFileContext().resolveCreate(original); filename = Filename(resolved); try { - file = make_unique<File>(filename); - filesize = file->getSize(); - file->setFilePool(motherBoard.getReactor().getFilePool()); + file = File(filename); + filesize = file.getSize(); tigerTree = make_unique<TigerTree>(*this, filesize, filename.getResolved()); } catch (FileException&) { @@ -76,7 +75,7 @@ HD::~HD() void HD::openImage() { - if (file) return; + if (file.is_open()) return; // image didn't exist yet, create new if (alreadyTried) { @@ -84,9 +83,8 @@ void HD::openImage() } alreadyTried = true; try { - file = make_unique<File>(filename, File::CREATE); - file->truncate(filesize); - file->setFilePool(motherBoard.getReactor().getFilePool()); + file = File(filename, File::CREATE); + file.truncate(filesize); tigerTree = make_unique<TigerTree>(*this, filesize, filename.getResolved()); } catch (FileException& e) { @@ -98,10 +96,9 @@ void HD::openImage() void HD::switchImage(const Filename& name) { - file = make_unique<File>(name); + file = File(name); filename = name; - filesize = file->getSize(); - file->setFilePool(motherBoard.getReactor().getFilePool()); + filesize = file.getSize(); tigerTree = make_unique<TigerTree>(*this, filesize, filename.getResolved()); motherBoard.getMSXCliComm().update(CliComm::MEDIA, g... [truncated message content] |
From: Wouter V. <m97...@us...> - 2015-04-29 20:21:32
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 160bce2e8979840bdf3337b5c5736925d007129f (commit) via f6590e7fb3c8bbaa6a359af35b223fbd6c554d00 (commit) from f97456b9da60b450b959346fbd19350a080d2249 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 160bce2e8979840bdf3337b5c5736925d007129f Author: Wouter Vermaelen <ver...@gm...> Date: Wed Apr 29 16:21:47 2015 +0200 Store DebugCondition by value Similar to the previous patch, but now for DebugConditions instead of BreakPoints. We still have vector<shared_ptr<WatchPoint>>, there we cannot easily get rid of the shared_ptr because WatchPoints are actually polymorphic (meaning we store a mix of different subtypes). We also still have vector<unique_ptr<ProbeBreakPoint>>, but ProbeBreakPoint has reference variables, so we cannot currently copy those objects. commit f6590e7fb3c8bbaa6a359af35b223fbd6c554d00 Author: Wouter Vermaelen <ver...@gm...> Date: Wed Apr 29 16:12:53 2015 +0200 Store Breakpoints by value Before we stored breakpoints as vector<shared_ptr<BreakPoint>> now they're stored as vector<BreakPoint> When one (or more) breakpoint(s) hit, we execute a Tcl command. It's possible that Tcl command will add or remove other breakpoints (= change the vector we're iterating over) or remove the current breakpoint (= delete the BreakPoint object we're currently using). To avoid these two potential problems, before starting to execute the Tcl commands, we take a copy of the subset of the to-be-executed breakpoints. This way we can freely modify the breakpoint vector (we're now iterating over the copy) and even delete the current breakpoint object (we're working on the copy). Because we're making copies, the original idea was to store the BreakPoint objects by shared_ptr, that way copying an object can be done by increasing a reference count. Now instead we make an actual copy of the BreakPoint objects. Let's compare both approaches: - Typically we frequently (every instruction(*)) check whether a breakpoint is hit, but only rarely execute a breakpoint. So we should optimize for the former case. Checking whether a bp is hit requires checking the address fields of the bp objects (the bp's are sorted on address, so this is a O(log(n)) operation). If we store the objects by (shared) pointer we have an extra indirection to access the address field. - Breakpoint objects are relatively small (about 24 bytes) so copying them is anyway very cheap. Copying a shared_ptr requires incrementing a reference count with atomic instructions (even though here we're only using a single thread), that is likely slower. - Note that before revision 3cfaaf14 (made a few hours ago), breakpoint objects had two additional reference member variables. So it was technically not even possible to copy them (even though the references actually always had the same value). (*) If there are no breakpoints defined, we have an optimized code path that doesn't check for breakpoints. ----------------------------------------------------------------------- Summary of changes: src/cpu/MSXCPUInterface.cc | 15 +++++------ src/cpu/MSXCPUInterface.hh | 26 ++++++++------------- src/debugger/Debugger.cc | 54 ++++++++++++++++++++----------------------- 3 files changed, 42 insertions(+), 53 deletions(-) diff --git a/src/cpu/MSXCPUInterface.cc b/src/cpu/MSXCPUInterface.cc index 628d77b..f556fe9 100644 --- a/src/cpu/MSXCPUInterface.cc +++ b/src/cpu/MSXCPUInterface.cc @@ -673,10 +673,10 @@ void MSXCPUInterface::writeSlottedMem(unsigned address, byte value, } } -void MSXCPUInterface::insertBreakPoint(const shared_ptr<BreakPoint>& bp) +void MSXCPUInterface::insertBreakPoint(const BreakPoint& bp) { auto it = upper_bound(begin(breakPoints), end(breakPoints), - bp->getAddress(), CompareBreakpoints()); + bp, CompareBreakpoints()); breakPoints.insert(it, bp); } @@ -685,8 +685,7 @@ void MSXCPUInterface::removeBreakPoint(const BreakPoint& bp) auto range = equal_range(begin(breakPoints), end(breakPoints), bp.getAddress(), CompareBreakpoints()); breakPoints.erase(find_if_unguarded(range.first, range.second, - [&](const shared_ptr<BreakPoint>& i) { - return i.get() == &bp; })); + [&](const BreakPoint& i) { return &i == &bp; })); } void MSXCPUInterface::checkBreakPoints( @@ -701,11 +700,11 @@ void MSXCPUInterface::checkBreakPoints( auto& cliComm = motherBoard.getReactor().getGlobalCliComm(); auto& interp = motherBoard.getReactor().getInterpreter(); for (auto& p : bpCopy) { - p->checkAndExecute(cliComm, interp); + p.checkAndExecute(cliComm, interp); } auto condCopy = conditions; for (auto& c : condCopy) { - c->checkAndExecute(cliComm, interp); + c.checkAndExecute(cliComm, interp); } } @@ -759,7 +758,7 @@ void MSXCPUInterface::removeWatchPoint(shared_ptr<WatchPoint> watchPoint) } } -void MSXCPUInterface::setCondition(const shared_ptr<DebugCondition>& cond) +void MSXCPUInterface::setCondition(const DebugCondition& cond) { conditions.push_back(cond); } @@ -767,7 +766,7 @@ void MSXCPUInterface::setCondition(const shared_ptr<DebugCondition>& cond) void MSXCPUInterface::removeCondition(const DebugCondition& cond) { conditions.erase(find_if_unguarded(conditions, - [&](std::shared_ptr<DebugCondition>& e) { return e.get() == &cond; })); + [&](DebugCondition& e) { return &e == &cond; })); } void MSXCPUInterface::registerIOWatch(WatchPoint& watchPoint, MSXDevice** devices) diff --git a/src/cpu/MSXCPUInterface.hh b/src/cpu/MSXCPUInterface.hh index 9a53cf0..e8f3b56 100644 --- a/src/cpu/MSXCPUInterface.hh +++ b/src/cpu/MSXCPUInterface.hh @@ -27,17 +27,14 @@ class DebugCondition; class CartridgeSlotManager; struct CompareBreakpoints { - bool operator()(const std::shared_ptr<BreakPoint>& x, - const std::shared_ptr<BreakPoint>& y) const { - return x->getAddress() < y->getAddress(); + bool operator()(const BreakPoint& x, const BreakPoint& y) const { + return x.getAddress() < y.getAddress(); } - bool operator()(const std::shared_ptr<BreakPoint>& x, - word y) const { - return x->getAddress() < y; + bool operator()(const BreakPoint& x, word y) const { + return x.getAddress() < y; } - bool operator()(word x, - const std::shared_ptr<BreakPoint>& y) const { - return x < y->getAddress(); + bool operator()(word x, const BreakPoint& y) const { + return x < y.getAddress(); } }; @@ -190,11 +187,9 @@ public: DummyDevice& getDummyDevice() { return *dummyDevice; } - static void insertBreakPoint(const std::shared_ptr<BreakPoint>& bp); + static void insertBreakPoint(const BreakPoint& bp); static void removeBreakPoint(const BreakPoint& bp); - // note: must be shared_ptr (not unique_ptr), see checkBreakPoints() - // TODO use multi_set sorted on BreakPoint->getAddress() - using BreakPoints = std::vector<std::shared_ptr<BreakPoint>>; + using BreakPoints = std::vector<BreakPoint>; static const BreakPoints& getBreakPoints() { return breakPoints; } void setWatchPoint(const std::shared_ptr<WatchPoint>& watchPoint); @@ -203,10 +198,9 @@ public: using WatchPoints = std::vector<std::shared_ptr<WatchPoint>>; const WatchPoints& getWatchPoints() const { return watchPoints; } - static void setCondition(const std::shared_ptr<DebugCondition>& cond); + static void setCondition(const DebugCondition& cond); static void removeCondition(const DebugCondition& cond); - // note: must be shared_ptr (not unique_ptr), see checkBreakPoints() - using Conditions = std::vector<std::shared_ptr<DebugCondition>>; + using Conditions = std::vector<DebugCondition>; static const Conditions& getConditions() { return conditions; } static bool isBreaked() { return breaked; } diff --git a/src/debugger/Debugger.cc b/src/debugger/Debugger.cc index e671e50..47f0d83 100644 --- a/src/debugger/Debugger.cc +++ b/src/debugger/Debugger.cc @@ -386,10 +386,8 @@ void Debugger::Cmd::writeBlock(array_ref<TclObject> tokens, TclObject& /*result* void Debugger::Cmd::setBreakPoint(array_ref<TclObject> tokens, TclObject& result) { - shared_ptr<BreakPoint> bp; TclObject command("debug break"); TclObject condition; - word addr; switch (tokens.size()) { case 5: // command @@ -399,9 +397,10 @@ void Debugger::Cmd::setBreakPoint(array_ref<TclObject> tokens, TclObject& result condition = tokens[3]; // fall-through case 3: { // address - auto& interp = getInterpreter(); - addr = getAddress(interp, tokens); - bp = make_shared<BreakPoint>(addr, command, condition); + word addr = getAddress(getInterpreter(), tokens); + BreakPoint bp(addr, command, condition); + result.setString(StringOp::Builder() << "bp#" << bp.getId()); + debugger.motherBoard.getCPUInterface().insertBreakPoint(bp); break; } default: @@ -411,8 +410,6 @@ void Debugger::Cmd::setBreakPoint(array_ref<TclObject> tokens, TclObject& result throw CommandException("Too many arguments."); } } - result.setString(StringOp::Builder() << "bp#" << bp->getId()); - debugger.motherBoard.getCPUInterface().insertBreakPoint(bp); } void Debugger::Cmd::removeBreakPoint( @@ -430,12 +427,11 @@ void Debugger::Cmd::removeBreakPoint( try { unsigned id = fast_stou(tmp.substr(3)); auto it = find_if(begin(breakPoints), end(breakPoints), - [&](const shared_ptr<BreakPoint>& bp) { - return bp->getId() == id; }); + [&](const BreakPoint& bp) { return bp.getId() == id; }); if (it == end(breakPoints)) { throw CommandException("No such breakpoint: " + tmp); } - interface.removeBreakPoint(**it); + interface.removeBreakPoint(*it); } catch (std::invalid_argument&) { // parse error in fast_stou() throw CommandException("No such breakpoint: " + tmp); @@ -446,13 +442,13 @@ void Debugger::Cmd::removeBreakPoint( auto range = equal_range(begin(breakPoints), end(breakPoints), addr, CompareBreakpoints()); auto it = find_if(range.first, range.second, - [&](const shared_ptr<BreakPoint>& bp) { - return bp->getCondition().empty(); }); + [&](const BreakPoint& bp) { + return bp.getCondition().empty(); }); if (it == range.second) { throw CommandException( "No (unconditional) breakpoint at address: " + tmp); } - interface.removeBreakPoint(**it); + interface.removeBreakPoint(*it); } } @@ -463,10 +459,10 @@ void Debugger::Cmd::listBreakPoints( auto& interface = debugger.motherBoard.getCPUInterface(); for (auto& bp : interface.getBreakPoints()) { TclObject line; - line.addListElement(StringOp::Builder() << "bp#" << bp->getId()); - line.addListElement("0x" + StringOp::toHexString(bp->getAddress(), 4)); - line.addListElement(bp->getCondition()); - line.addListElement(bp->getCommand()); + line.addListElement(StringOp::Builder() << "bp#" << bp.getId()); + line.addListElement("0x" + StringOp::toHexString(bp.getAddress(), 4)); + line.addListElement(bp.getCondition()); + line.addListElement(bp.getCommand()); res += line.getString() + '\n'; } result.setString(res); @@ -605,7 +601,6 @@ void Debugger::Cmd::listWatchPoints( void Debugger::Cmd::setCondition(array_ref<TclObject> tokens, TclObject& result) { - shared_ptr<DebugCondition> dc; TclObject command("debug break"); TclObject condition; @@ -613,10 +608,13 @@ void Debugger::Cmd::setCondition(array_ref<TclObject> tokens, TclObject& result) case 4: // command command = tokens[3]; // fall-through - case 3: // condition + case 3: { // condition condition = tokens[2]; - dc = make_shared<DebugCondition>(command, condition); + DebugCondition dc(command, condition); + result.setString(StringOp::Builder() << "cond#" << dc.getId()); + debugger.motherBoard.getCPUInterface().setCondition(dc); break; + } default: if (tokens.size() < 3) { throw CommandException("Too few arguments."); @@ -624,8 +622,6 @@ void Debugger::Cmd::setCondition(array_ref<TclObject> tokens, TclObject& result) throw CommandException("Too many arguments."); } } - result.setString(StringOp::Builder() << "cond#" << dc->getId()); - debugger.motherBoard.getCPUInterface().setCondition(dc); } void Debugger::Cmd::removeCondition( @@ -642,8 +638,8 @@ void Debugger::Cmd::removeCondition( unsigned id = fast_stou(tmp.substr(5)); auto& interface = debugger.motherBoard.getCPUInterface(); for (auto& c : interface.getConditions()) { - if (c->getId() == id) { - interface.removeCondition(*c); + if (c.getId() == id) { + interface.removeCondition(c); return; } } @@ -661,9 +657,9 @@ void Debugger::Cmd::listConditions( auto& interface = debugger.motherBoard.getCPUInterface(); for (auto& c : interface.getConditions()) { TclObject line; - line.addListElement(StringOp::Builder() << "cond#" << c->getId()); - line.addListElement(c->getCondition()); - line.addListElement(c->getCommand()); + line.addListElement(StringOp::Builder() << "cond#" << c.getId()); + line.addListElement(c.getCondition()); + line.addListElement(c.getCommand()); res += line.getString() + '\n'; } result.setString(res); @@ -1009,7 +1005,7 @@ vector<string> Debugger::Cmd::getBreakPointIds() const vector<string> bpids; auto& interface = debugger.motherBoard.getCPUInterface(); for (auto& bp : interface.getBreakPoints()) { - bpids.push_back(StringOp::Builder() << "bp#" << bp->getId()); + bpids.push_back(StringOp::Builder() << "bp#" << bp.getId()); } return bpids; } @@ -1027,7 +1023,7 @@ vector<string> Debugger::Cmd::getConditionIds() const vector<string> condids; auto& interface = debugger.motherBoard.getCPUInterface(); for (auto& c : interface.getConditions()) { - condids.push_back(StringOp::Builder() << "cond#" << c->getId()); + condids.push_back(StringOp::Builder() << "cond#" << c.getId()); } return condids; } hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-04-29 19:06:36
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via f97456b9da60b450b959346fbd19350a080d2249 (commit) via 3cfaaf145fbaa173d71c59f9da4606e802b48fd0 (commit) from d6381ef37f507914c976a2309427d2de1093259f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit f97456b9da60b450b959346fbd19350a080d2249 Author: Wouter Vermaelen <ver...@gm...> Date: Wed Apr 29 15:49:19 2015 +0200 Remove workaround for VS2012 According to the (now removed) comments, this was a workaround for visual studio 2012: it didn't support c++11 variadic templates yet. VS2013 should have them, so I'm removing the workaround. commit 3cfaaf145fbaa173d71c59f9da4606e802b48fd0 Author: Wouter Vermaelen <ver...@gm...> Date: Wed Apr 29 15:47:20 2015 +0200 Don't store clicomm/interp in BreakPointBase The BreakPointBase class (base class for BreakPoint, WatchPoint, DebugCondition, ProbeBreakPoint) has two member variables 'GlobalCliComm& cliComm' and 'Interpreter& interp'. For _every_ BreakPointBase object these two members have the same value because there's only one GlobalCliComm and only one Interpreter object. So these two member variables don't contribute much. The implementation of some of the methods in BreakPointBase does actually use the 'cliComm' and 'interp' variables. Though instead of storing these (same) values in every object we can also pass them as extra parameters to the methods that need them. ----------------------------------------------------------------------- Summary of changes: src/cpu/BreakPoint.cc | 5 ++--- src/cpu/BreakPoint.hh | 7 +++---- src/cpu/BreakPointBase.cc | 13 +++++-------- src/cpu/BreakPointBase.hh | 18 +++++------------- src/cpu/CPUCore.cc | 2 +- src/cpu/DebugCondition.cc | 5 ++--- src/cpu/DebugCondition.hh | 5 ++--- src/cpu/MSXCPUInterface.cc | 14 +++++++++----- src/cpu/MSXCPUInterface.hh | 7 ++++--- src/cpu/MSXWatchIODevice.cc | 20 +++++++++++--------- src/cpu/MSXWatchIODevice.hh | 3 +-- src/cpu/WatchPoint.cc | 5 ++--- src/cpu/WatchPoint.hh | 11 +++++------ src/debugger/Debugger.cc | 36 ++++++++---------------------------- src/debugger/Debugger.hh | 6 +++--- src/debugger/ProbeBreakPoint.cc | 11 +++++++---- src/debugger/ProbeBreakPoint.hh | 4 +--- 17 files changed, 71 insertions(+), 101 deletions(-) diff --git a/src/cpu/BreakPoint.cc b/src/cpu/BreakPoint.cc index 33bfe84..a8a6b9d 100644 --- a/src/cpu/BreakPoint.cc +++ b/src/cpu/BreakPoint.cc @@ -5,9 +5,8 @@ namespace openmsx { unsigned BreakPoint::lastId = 0; -BreakPoint::BreakPoint(GlobalCliComm& cliComm, Interpreter& interp, - word address_, TclObject command, TclObject condition) - : BreakPointBase(cliComm, interp, command, condition) +BreakPoint::BreakPoint(word address_, TclObject command, TclObject condition) + : BreakPointBase(command, condition) , id(++lastId) , address(address_) { diff --git a/src/cpu/BreakPoint.hh b/src/cpu/BreakPoint.hh index e4f090e..8792a75 100644 --- a/src/cpu/BreakPoint.hh +++ b/src/cpu/BreakPoint.hh @@ -13,15 +13,14 @@ namespace openmsx { class BreakPoint final : public BreakPointBase { public: - BreakPoint(GlobalCliComm& CliComm, Interpreter& interp, word address, - TclObject command, TclObject condition); + BreakPoint(word address, TclObject command, TclObject condition); word getAddress() const { return address; } unsigned getId() const { return id; } private: - const unsigned id; - const word address; + unsigned id; + word address; static unsigned lastId; }; diff --git a/src/cpu/BreakPointBase.cc b/src/cpu/BreakPointBase.cc index 3c59494..9e4abca 100644 --- a/src/cpu/BreakPointBase.cc +++ b/src/cpu/BreakPointBase.cc @@ -1,20 +1,17 @@ #include "BreakPointBase.hh" -#include "TclObject.hh" #include "CommandException.hh" #include "GlobalCliComm.hh" #include "ScopedAssign.hh" namespace openmsx { -BreakPointBase::BreakPointBase(GlobalCliComm& cliComm_, Interpreter& interp_, - TclObject command_, TclObject condition_) - : cliComm(cliComm_), interp(interp_) - , command(command_), condition(condition_) +BreakPointBase::BreakPointBase(TclObject command_, TclObject condition_) + : command(command_), condition(condition_) , executing(false) { } -bool BreakPointBase::isTrue() const +bool BreakPointBase::isTrue(GlobalCliComm& cliComm, Interpreter& interp) const { if (condition.getString().empty()) { // unconditional bp @@ -28,14 +25,14 @@ bool BreakPointBase::isTrue() const } } -void BreakPointBase::checkAndExecute() +void BreakPointBase::checkAndExecute(GlobalCliComm& cliComm, Interpreter& interp) { if (executing) { // no recursive execution return; } ScopedAssign<bool> sa(executing, true); - if (isTrue()) { + if (isTrue(cliComm, interp)) { try { command.executeCommand(interp, true); // compile command } catch (CommandException& e) { diff --git a/src/cpu/BreakPointBase.hh b/src/cpu/BreakPointBase.hh index 187a6f4..1662956 100644 --- a/src/cpu/BreakPointBase.hh +++ b/src/cpu/BreakPointBase.hh @@ -2,18 +2,16 @@ #define BREAKPOINTBASE_HH #include "TclObject.hh" -#include "noncopyable.hh" #include "string_ref.hh" -class Interpreter; - namespace openmsx { +class Interpreter; class GlobalCliComm; /** Base class for CPU break and watch points. */ -class BreakPointBase : private noncopyable +class BreakPointBase { public: string_ref getCondition() const { return condition.getString(); } @@ -21,23 +19,17 @@ public: TclObject getConditionObj() const { return condition; } TclObject getCommandObj() const { return command; } - void checkAndExecute(); - - // get associated interpreter - Interpreter& getInterpreter() const { return interp; } + void checkAndExecute(GlobalCliComm& cliComm, Interpreter& interp); protected: // Note: we require GlobalCliComm here because breakpoint objects can // be transfered to different MSX machines, and so the MSXCliComm // object won't remain valid. - BreakPointBase(GlobalCliComm& cliComm, Interpreter& interp, - TclObject command, TclObject condition); + BreakPointBase(TclObject command, TclObject condition); private: - bool isTrue() const; + bool isTrue(GlobalCliComm& cliComm, Interpreter& interp) const; - GlobalCliComm& cliComm; - Interpreter& interp; TclObject command; TclObject condition; bool executing; diff --git a/src/cpu/CPUCore.cc b/src/cpu/CPUCore.cc index 6f19da6..4bccb12 100644 --- a/src/cpu/CPUCore.cc +++ b/src/cpu/CPUCore.cc @@ -2564,7 +2564,7 @@ template<class T> void CPUCore<T>::execute2(bool fastForward) } } else { while (!needExitCPULoop()) { - if (interface->checkBreakPoints(getPC())) { + if (interface->checkBreakPoints(getPC(), motherboard)) { assert(interface->isBreaked()); break; } diff --git a/src/cpu/DebugCondition.cc b/src/cpu/DebugCondition.cc index efdd560..eca6294 100644 --- a/src/cpu/DebugCondition.cc +++ b/src/cpu/DebugCondition.cc @@ -4,9 +4,8 @@ namespace openmsx { unsigned DebugCondition::lastId = 0; -DebugCondition::DebugCondition(GlobalCliComm& cliComm, Interpreter& interp, - TclObject command, TclObject condition) - : BreakPointBase(cliComm, interp, command, condition) +DebugCondition::DebugCondition(TclObject command, TclObject condition) + : BreakPointBase(command, condition) , id(++lastId) { } diff --git a/src/cpu/DebugCondition.hh b/src/cpu/DebugCondition.hh index 17fcd89..2446027 100644 --- a/src/cpu/DebugCondition.hh +++ b/src/cpu/DebugCondition.hh @@ -11,12 +11,11 @@ namespace openmsx { class DebugCondition final : public BreakPointBase { public: - DebugCondition(GlobalCliComm& CliComm, Interpreter& interp, - TclObject command, TclObject condition); + DebugCondition(TclObject command, TclObject condition); unsigned getId() const { return id; } private: - const unsigned id; + unsigned id; static unsigned lastId; }; diff --git a/src/cpu/MSXCPUInterface.cc b/src/cpu/MSXCPUInterface.cc index 21f1e08..628d77b 100644 --- a/src/cpu/MSXCPUInterface.cc +++ b/src/cpu/MSXCPUInterface.cc @@ -691,18 +691,21 @@ void MSXCPUInterface::removeBreakPoint(const BreakPoint& bp) void MSXCPUInterface::checkBreakPoints( std::pair<BreakPoints::const_iterator, - BreakPoints::const_iterator> range) + BreakPoints::const_iterator> range, + MSXMotherBoard& motherBoard) { // create copy for the case that breakpoint/condition removes itself // - keeps object alive by holding a shared_ptr to it // - avoids iterating over a changing collection BreakPoints bpCopy(range.first, range.second); + auto& cliComm = motherBoard.getReactor().getGlobalCliComm(); + auto& interp = motherBoard.getReactor().getInterpreter(); for (auto& p : bpCopy) { - p->checkAndExecute(); + p->checkAndExecute(cliComm, interp); } auto condCopy = conditions; for (auto& c : condCopy) { - c->checkAndExecute(); + c->checkAndExecute(cliComm, interp); } } @@ -841,7 +844,8 @@ void MSXCPUInterface::executeMemWatch(WatchPoint::Type type, assert(!watchPoints.empty()); if (isFastForward()) return; - auto& interp = watchPoints.front()->getInterpreter(); + auto& cliComm = motherBoard.getReactor().getGlobalCliComm(); + auto& interp = motherBoard.getReactor().getInterpreter(); interp.setVariable("wp_last_address", TclObject(int(address))); if (value != ~0u) { interp.setVariable("wp_last_value", TclObject(int(value))); @@ -852,7 +856,7 @@ void MSXCPUInterface::executeMemWatch(WatchPoint::Type type, if ((w->getBeginAddress() <= address) && (w->getEndAddress() >= address) && (w->getType() == type)) { - w->checkAndExecute(); + w->checkAndExecute(cliComm, interp); } } diff --git a/src/cpu/MSXCPUInterface.hh b/src/cpu/MSXCPUInterface.hh index fe90586..9a53cf0 100644 --- a/src/cpu/MSXCPUInterface.hh +++ b/src/cpu/MSXCPUInterface.hh @@ -225,7 +225,7 @@ public: { return !breakPoints.empty() || !conditions.empty(); } - static bool checkBreakPoints(unsigned pc) + static bool checkBreakPoints(unsigned pc, MSXMotherBoard& motherBoard) { auto range = equal_range(begin(breakPoints), end(breakPoints), pc, CompareBreakpoints()); @@ -234,7 +234,7 @@ public: } // slow path non-inlined - checkBreakPoints(range); + checkBreakPoints(range, motherBoard); return isBreaked(); } @@ -267,7 +267,8 @@ private: static void checkBreakPoints(std::pair<BreakPoints::const_iterator, - BreakPoints::const_iterator> range); + BreakPoints::const_iterator> range, + MSXMotherBoard& motherBoard); void removeAllWatchPoints(); void registerIOWatch (WatchPoint& watchPoint, MSXDevice** devices); diff --git a/src/cpu/MSXWatchIODevice.cc b/src/cpu/MSXWatchIODevice.cc index e949fcc..99fc24d 100644 --- a/src/cpu/MSXWatchIODevice.cc +++ b/src/cpu/MSXWatchIODevice.cc @@ -10,15 +10,13 @@ namespace openmsx { // class WatchIO -WatchIO::WatchIO(MSXMotherBoard& motherboard, +WatchIO::WatchIO(MSXMotherBoard& motherboard_, WatchPoint::Type type, unsigned beginAddr, unsigned endAddr, TclObject command, TclObject condition, unsigned newId /*= -1*/) - : WatchPoint(motherboard.getReactor().getGlobalCliComm(), - motherboard.getReactor().getInterpreter(), - command, condition, type, beginAddr, endAddr, newId) - , cpuInterface(motherboard.getCPUInterface()) + : WatchPoint(command, condition, type, beginAddr, endAddr, newId) + , motherboard(motherboard_) { for (unsigned i = byte(beginAddr); i <= byte(endAddr); ++i) { ios.push_back(make_unique<MSXWatchIODevice>( @@ -38,9 +36,11 @@ MSXWatchIODevice& WatchIO::getDevice(byte port) void WatchIO::doReadCallback(unsigned port) { + auto& cpuInterface = motherboard.getCPUInterface(); if (cpuInterface.isFastForward()) return; - auto& interp = getInterpreter(); + auto& cliComm = motherboard.getReactor().getGlobalCliComm(); + auto& interp = motherboard.getReactor().getInterpreter(); interp.setVariable("wp_last_address", TclObject(int(port))); // keep this object alive by holding a shared_ptr to it, for the case @@ -48,22 +48,24 @@ void WatchIO::doReadCallback(unsigned port) // TODO can be implemented more efficiently by using // std::shared_ptr::shared_from_this MSXCPUInterface::WatchPoints wpCopy(cpuInterface.getWatchPoints()); - checkAndExecute(); + checkAndExecute(cliComm, interp); interp.unsetVariable("wp_last_address"); } void WatchIO::doWriteCallback(unsigned port, unsigned value) { + auto& cpuInterface = motherboard.getCPUInterface(); if (cpuInterface.isFastForward()) return; - auto& interp = getInterpreter(); + auto& cliComm = motherboard.getReactor().getGlobalCliComm(); + auto& interp = motherboard.getReactor().getInterpreter(); interp.setVariable("wp_last_address", TclObject(int(port))); interp.setVariable("wp_last_value", TclObject(int(value))); // see comment in doReadCallback() above MSXCPUInterface::WatchPoints wpCopy(cpuInterface.getWatchPoints()); - checkAndExecute(); + checkAndExecute(cliComm, interp); interp.unsetVariable("wp_last_address"); interp.unsetVariable("wp_last_value"); diff --git a/src/cpu/MSXWatchIODevice.hh b/src/cpu/MSXWatchIODevice.hh index 35704c8..40edacf 100644 --- a/src/cpu/MSXWatchIODevice.hh +++ b/src/cpu/MSXWatchIODevice.hh @@ -7,7 +7,6 @@ namespace openmsx { -class MSXCPUInterface; class MSXWatchIODevice; class WatchIO final : public WatchPoint @@ -26,7 +25,7 @@ private: void doReadCallback(unsigned port); void doWriteCallback(unsigned port, unsigned value); - MSXCPUInterface& cpuInterface; + MSXMotherBoard& motherboard; std::vector<std::unique_ptr<MSXWatchIODevice>> ios; friend class MSXWatchIODevice; diff --git a/src/cpu/WatchPoint.cc b/src/cpu/WatchPoint.cc index e7fc57e..b1411fc 100644 --- a/src/cpu/WatchPoint.cc +++ b/src/cpu/WatchPoint.cc @@ -5,11 +5,10 @@ namespace openmsx { unsigned WatchPoint::lastId = 0; -WatchPoint::WatchPoint(GlobalCliComm& cliComm, Interpreter& interp, - TclObject command, TclObject condition, +WatchPoint::WatchPoint(TclObject command, TclObject condition, Type type_, unsigned beginAddr_, unsigned endAddr_, unsigned newId /*= -1*/) - : BreakPointBase(cliComm, interp, command, condition) + : BreakPointBase(command, condition) , id((newId == unsigned(-1)) ? ++lastId : newId) , beginAddr(beginAddr_), endAddr(endAddr_), type(type_) { diff --git a/src/cpu/WatchPoint.hh b/src/cpu/WatchPoint.hh index 34d4bf9..171bcb5 100644 --- a/src/cpu/WatchPoint.hh +++ b/src/cpu/WatchPoint.hh @@ -16,8 +16,7 @@ public: /** Begin and end address are inclusive (IOW range = [begin, end]) */ - WatchPoint(GlobalCliComm& CliComm, Interpreter& interp, - TclObject command, TclObject condition, + WatchPoint(TclObject command, TclObject condition, Type type, unsigned beginAddr, unsigned endAddr, unsigned newId = -1); virtual ~WatchPoint(); // needed for dynamic_cast @@ -28,10 +27,10 @@ public: unsigned getEndAddress() const { return endAddr; } private: - const unsigned id; - const unsigned beginAddr; - const unsigned endAddr; - const Type type; + unsigned id; + unsigned beginAddr; + unsigned endAddr; + Type type; static unsigned lastId; }; diff --git a/src/debugger/Debugger.cc b/src/debugger/Debugger.cc index 22e3874..e671e50 100644 --- a/src/debugger/Debugger.cc +++ b/src/debugger/Debugger.cc @@ -34,7 +34,7 @@ Debugger::Debugger(MSXMotherBoard& motherBoard_) , cmd(motherBoard.getCommandController(), motherBoard.getStateChangeDistributor(), motherBoard.getScheduler(), - motherBoard.getReactor().getGlobalCliComm(), *this) + *this) , cpu(nullptr) { } @@ -108,8 +108,6 @@ unsigned Debugger::insertProbeBreakPoint( ProbeBase& probe, unsigned newId /*= -1*/) { auto bp = make_unique<ProbeBreakPoint>( - motherBoard.getReactor().getGlobalCliComm(), - motherBoard.getReactor().getInterpreter(), command, condition, *this, probe, newId); unsigned result = bp->getId(); probeBreakPoints.push_back(std::move(bp)); @@ -159,28 +157,12 @@ unsigned Debugger::setWatchPoint(TclObject command, TclObject condition, { shared_ptr<WatchPoint> wp; if ((type == WatchPoint::READ_IO) || (type == WatchPoint::WRITE_IO)) { - // Workaround visual studio 2012 limitation: - // True variadic templates are not yet supported. Instead the - // visual stdio's standard library supports make_shared with - // (only) upto 5 parameters. It is possible to increase this - // limit to 10 (by defining _VARIADIC_MAX) but that also - // slows down compilation. It's easy enough to work around. - // Also the next version of visual studio (still to be - // release in 2012) will properly support this. - //wp = make_shared<WatchIO>( - // motherBoard, type, beginAddr, endAddr, - // command, condition, newId); - wp.reset(new WatchIO( + wp = make_shared<WatchIO>( motherBoard, type, beginAddr, endAddr, - command, condition, newId)); + command, condition, newId); } else { - //wp = make_shared<WatchPoint>( - // motherBoard.getReactor().getGlobalCliComm(), - // command, condition, type, beginAddr, endAddr, newId); - wp.reset(new WatchPoint( - motherBoard.getReactor().getGlobalCliComm(), - motherBoard.getReactor().getInterpreter(), - command, condition, type, beginAddr, endAddr, newId)); + wp = make_shared<WatchPoint>( + command, condition, type, beginAddr, endAddr, newId); } motherBoard.getCPUInterface().setWatchPoint(wp); return wp->getId(); @@ -227,11 +209,9 @@ static word getAddress(Interpreter& interp, array_ref<TclObject> tokens) Debugger::Cmd::Cmd(CommandController& commandController, StateChangeDistributor& stateChangeDistributor, - Scheduler& scheduler, GlobalCliComm& cliComm_, - Debugger& debugger_) + Scheduler& scheduler, Debugger& debugger_) : RecordedCommand(commandController, stateChangeDistributor, scheduler, "debug") - , cliComm(cliComm_) , debugger(debugger_) { } @@ -421,7 +401,7 @@ void Debugger::Cmd::setBreakPoint(array_ref<TclObject> tokens, TclObject& result case 3: { // address auto& interp = getInterpreter(); addr = getAddress(interp, tokens); - bp = make_shared<BreakPoint>(cliComm, interp, addr, command, condition); + bp = make_shared<BreakPoint>(addr, command, condition); break; } default: @@ -635,7 +615,7 @@ void Debugger::Cmd::setCondition(array_ref<TclObject> tokens, TclObject& result) // fall-through case 3: // condition condition = tokens[2]; - dc = make_shared<DebugCondition>(cliComm, getInterpreter(), command, condition); + dc = make_shared<DebugCondition>(command, condition); break; default: if (tokens.size() < 3) { diff --git a/src/debugger/Debugger.hh b/src/debugger/Debugger.hh index 436dcac..9ed8a74 100644 --- a/src/debugger/Debugger.hh +++ b/src/debugger/Debugger.hh @@ -36,6 +36,8 @@ public: void transfer(Debugger& other); + MSXMotherBoard& getMotherBoard() { return motherBoard; } + private: Debuggable& getDebuggable(string_ref name); ProbeBase& getProbe(string_ref name); @@ -56,8 +58,7 @@ private: public: Cmd(CommandController& commandController, StateChangeDistributor& stateChangeDistributor, - Scheduler& scheduler, GlobalCliComm& cliComm, - Debugger& debugger); + Scheduler& scheduler, Debugger& debugger); bool needRecord(array_ref<TclObject> tokens) const override; void execute(array_ref<TclObject> tokens, TclObject& result, EmuTime::param time) override; @@ -92,7 +93,6 @@ private: void probeRemoveBreakPoint(array_ref<TclObject> tokens, TclObject& result); void probeListBreakPoints(array_ref<TclObject> tokens, TclObject& result); - GlobalCliComm& cliComm; Debugger& debugger; } cmd; diff --git a/src/debugger/ProbeBreakPoint.cc b/src/debugger/ProbeBreakPoint.cc index 9b43b5e..169ac84 100644 --- a/src/debugger/ProbeBreakPoint.cc +++ b/src/debugger/ProbeBreakPoint.cc @@ -1,6 +1,8 @@ #include "ProbeBreakPoint.hh" #include "Probe.hh" #include "Debugger.hh" +#include "MSXMotherBoard.hh" +#include "Reactor.hh" #include "TclObject.hh" namespace openmsx { @@ -8,14 +10,12 @@ namespace openmsx { unsigned ProbeBreakPoint::lastId = 0; ProbeBreakPoint::ProbeBreakPoint( - GlobalCliComm& cliComm, - Interpreter& interp, TclObject command, TclObject condition, Debugger& debugger_, ProbeBase& probe_, unsigned newId /*= -1*/) - : BreakPointBase(cliComm, interp, command, condition) + : BreakPointBase(command, condition) , debugger(debugger_) , probe(probe_) , id((newId == unsigned(-1)) ? ++lastId : newId) @@ -30,7 +30,10 @@ ProbeBreakPoint::~ProbeBreakPoint() void ProbeBreakPoint::update(const ProbeBase& /*subject*/) { - checkAndExecute(); + auto& reactor = debugger.getMotherBoard().getReactor(); + auto& cliComm = reactor.getGlobalCliComm(); + auto& interp = reactor.getInterpreter(); + checkAndExecute(cliComm, interp); } void ProbeBreakPoint::subjectDeleted(const ProbeBase& /*subject*/) diff --git a/src/debugger/ProbeBreakPoint.hh b/src/debugger/ProbeBreakPoint.hh index da0625f..75112c5 100644 --- a/src/debugger/ProbeBreakPoint.hh +++ b/src/debugger/ProbeBreakPoint.hh @@ -13,9 +13,7 @@ class ProbeBreakPoint final : public BreakPointBase , private Observer<ProbeBase> { public: - ProbeBreakPoint(GlobalCliComm& CliComm, - Interpreter& interp, - TclObject command, + ProbeBreakPoint(TclObject command, TclObject condition, Debugger& debugger, ProbeBase& probe, hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-04-29 17:57:13
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via d6381ef37f507914c976a2309427d2de1093259f (commit) via 43a4db957a4f1812140ae1228e0ad74404516b24 (commit) via 6b4b8eb3271ad082b5d93f20aca1315f607b24b9 (commit) from bc5b8d4d1fee151c9ca88f920aff652d5c14dc69 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit d6381ef37f507914c976a2309427d2de1093259f Author: Wouter Vermaelen <ver...@gm...> Date: Wed Apr 29 14:53:14 2015 +0200 Inline trivial TclObject methods + add move operations The TclObject constructors, destructor, assignment-operator are all very small functions (they mostly only call one function in libtcl). So inlining them has almost no code-size cost but it does improve performance. I also added move-operations. Though only move-assignment is (slightly) simpler compared to the corresponding copy-operation (because tcl_obj is internally reference counted). commit 43a4db957a4f1812140ae1228e0ad74404516b24 Author: Wouter Vermaelen <ver...@gm...> Date: Wed Apr 29 13:46:46 2015 +0200 Optimize (colored) text drawing in the console in openGL The openmsx console rendering code keeps a cache of previously rendered text fragments (because mostly the same text is drawn on consecutive frames). The console also supports colored text. Before this patch two fragments of the same text but with a different color were distinct cache objects. For the SDL renderer this is still the case after this patch. For the openGL renderer however we now always render text in white (to a texture) and apply the color only in the actual draw command. The advantage is that if the same text fragment appears in multiple colors in the console (in openGL) we only have to render that text once (and draw the texture multiple times in different colors). Drawing in different colors (implemented as multiplying the texture colors) is practically free in openGL. In fact the current shader already contained those color multiplications (but all but the alpha-component were multiplications by 1.0 before). commit 6b4b8eb3271ad082b5d93f20aca1315f607b24b9 Author: Wouter Vermaelen <ver...@gm...> Date: Wed Apr 29 12:35:21 2015 +0200 Removed bw-compat code for the 'update' command Over 5 years ago in revision a5b7b21b we renamed the 'update' command to 'openmsx_update' because it clashed with the native Tcl update command. That revsion also added backwards compatibility code so that old scripts that used 'update' (the openmsx variant) kept working, but print a deprecation warning. This patch removes the backwards compatibility code (over 5 years of warnings should be enough ;-) Note that this does _not_ break old savestates, only old scripts in external applications controlling openMSX. ----------------------------------------------------------------------- Summary of changes: src/commands/GlobalCommandController.cc | 27 +---------------- src/commands/GlobalCommandController.hh | 3 +- src/commands/TclObject.cc | 51 ------------------------------- src/commands/TclObject.hh | 34 +++++++++++++++----- src/console/OSDConsoleRenderer.cc | 26 +++++++++++----- src/video/BaseImage.hh | 6 +++- src/video/GLImage.cc | 31 ++++++++++-------- src/video/GLImage.hh | 6 ++-- src/video/SDLImage.cc | 6 +++- src/video/SDLImage.hh | 2 +- 10 files changed, 76 insertions(+), 116 deletions(-) diff --git a/src/commands/GlobalCommandController.cc b/src/commands/GlobalCommandController.cc index b3c100a..687ce59 100644 --- a/src/commands/GlobalCommandController.cc +++ b/src/commands/GlobalCommandController.cc @@ -34,36 +34,11 @@ GlobalCommandController::GlobalCommandController( , settingsConfig(*this, hotKey) , helpCmd(*this) , tabCompletionCmd(*this) + , updateCmd(*this) , platformInfo(getOpenMSXInfoCommand()) , versionInfo (getOpenMSXInfoCommand()) , romInfoTopic(getOpenMSXInfoCommand()) { - // For backwards compatibility: - // In the past we had an openMSX command 'update'. This was a mistake - // because it overlaps with the native Tcl command with the same name. - // We renamed 'update' to 'openmsx_update'. And installed a wrapper - // around 'update' that either forwards to the native Tcl command or - // to the 'openmsx_update' command. - // In future openMSX versions this wrapper will be removed. - interpreter.execute("rename update __tcl_update"); - interpreter.execute( - "proc update { args } {\n" - " if {$args == \"\"} {\n" - " __tcl_update\n" - " } elseif {$args == \"idletasks\"} {\n" - " __tcl_update idletasks\n" - " } else {\n" - " puts stderr \"Warning: the openMSX \\'update\\' command " - "overlapped with a native Tcl command " - "and has been renamed to \\'openmsx_update\\'. " - "In future openMSX releases this forwarder " - "will stop working, so please change your " - "scripts to use the \\'openmsx_update\\' " - "command instead of \\'update\\'.\"\n" - " eval \"openmsx_update $args\"\n" - " }\n" - "}\n"); - updateCmd = make_unique<UpdateCmd>(*this); } GlobalCommandController::~GlobalCommandController() diff --git a/src/commands/GlobalCommandController.hh b/src/commands/GlobalCommandController.hh index 53cda71..8712d67 100644 --- a/src/commands/GlobalCommandController.hh +++ b/src/commands/GlobalCommandController.hh @@ -141,8 +141,7 @@ private: void tabCompletion(std::vector<std::string>& tokens) const override; private: CliConnection& getConnection(); - }; - std::unique_ptr<UpdateCmd> updateCmd; + } updateCmd; class PlatformInfo final : public InfoTopic { public: diff --git a/src/commands/TclObject.cc b/src/commands/TclObject.cc index fbe439e..04ad66a 100644 --- a/src/commands/TclObject.cc +++ b/src/commands/TclObject.cc @@ -1,60 +1,9 @@ #include "TclObject.hh" #include "Interpreter.hh" #include "CommandException.hh" -#include <tcl.h> namespace openmsx { -TclObject::TclObject() -{ - init(Tcl_NewObj()); -} - -TclObject::TclObject(Tcl_Obj* obj_) -{ - init(obj_); -} - -TclObject::TclObject(string_ref value) -{ - init(Tcl_NewStringObj(value.data(), int(value.size()))); -} - -TclObject::TclObject(int value) -{ - init(Tcl_NewIntObj(value)); -} - -TclObject::TclObject(double value) -{ - init(Tcl_NewDoubleObj(value)); -} - -TclObject::TclObject(const TclObject& object) -{ - init(object.obj); -} - -void TclObject::init(Tcl_Obj* obj_) -{ - obj = obj_; - Tcl_IncrRefCount(obj); -} - -TclObject::~TclObject() -{ - Tcl_DecrRefCount(obj); -} - -TclObject& TclObject::operator=(const TclObject& other) -{ - if (&other != this) { - Tcl_DecrRefCount(obj); - init(other.obj); - } - return *this; -} - static void throwException(Tcl_Interp* interp) { string_ref message = interp ? Tcl_GetStringResult(interp) diff --git a/src/commands/TclObject.hh b/src/commands/TclObject.hh index f33373f..efa2f29 100644 --- a/src/commands/TclObject.hh +++ b/src/commands/TclObject.hh @@ -3,6 +3,7 @@ #include "string_ref.hh" #include "openmsx.hh" +#include <tcl.h> #include <iterator> #include <cassert> @@ -55,16 +56,27 @@ class TclObject }; public: - TclObject(); - explicit TclObject(Tcl_Obj* object); - explicit TclObject(string_ref value); - explicit TclObject(int value); - explicit TclObject(double value); - TclObject(const TclObject& object); - ~TclObject(); + TclObject() { init(Tcl_NewObj()); } + explicit TclObject(Tcl_Obj* o) { init(o); } + explicit TclObject(string_ref v) { init(Tcl_NewStringObj(v.data(), int(v.size()))); } + explicit TclObject(int v) { init(Tcl_NewIntObj(v)); } + explicit TclObject(double v) { init(Tcl_NewDoubleObj(v)); } + TclObject(const TclObject& o) { init(o.obj); } + TclObject( TclObject&& o) { init(o.obj); } + ~TclObject() { Tcl_DecrRefCount(obj); } // assignment operator so we can use vector<TclObject> - TclObject& operator=(const TclObject& other); + TclObject& operator=(const TclObject& other) { + if (&other != this) { + Tcl_DecrRefCount(obj); + init(other.obj); + } + return *this; + } + TclObject& operator=(TclObject&& other) { + std::swap(obj, other.obj); + return *this; + } // get underlying Tcl_Obj Tcl_Obj* getTclObject() { return obj; } @@ -119,7 +131,11 @@ public: } private: - void init(Tcl_Obj* obj_); + void init(Tcl_Obj* obj_) { + obj = obj_; + Tcl_IncrRefCount(obj); + } + void addListElement(Tcl_Obj* element); unsigned getListLengthUnchecked() const; TclObject getListIndexUnchecked(unsigned index) const; diff --git a/src/console/OSDConsoleRenderer.cc b/src/console/OSDConsoleRenderer.cc index 8cda122..96f7478 100644 --- a/src/console/OSDConsoleRenderer.cc +++ b/src/console/OSDConsoleRenderer.cc @@ -318,13 +318,14 @@ void OSDConsoleRenderer::drawText2(OutputSurface& output, string_ref text, if (!getFromCache(text, rgb, image, width)) { string textStr = text.str(); SDLSurfacePtr surf; + unsigned rgb2 = openGL ? 0xffffff : rgb; // openGL -> always render white try { unsigned dummyHeight; font.getSize(textStr, width, dummyHeight); surf = font.render(textStr, - (rgb >> 16) & 0xff, - (rgb >> 8) & 0xff, - (rgb >> 0) & 0xff); + (rgb2 >> 16) & 0xff, + (rgb2 >> 8) & 0xff, + (rgb2 >> 0) & 0xff); } catch (MSXException& e) { static bool alreadyPrinted = false; if (!alreadyPrinted) { @@ -349,7 +350,16 @@ void OSDConsoleRenderer::drawText2(OutputSurface& output, string_ref text, image = image2.get(); insertInCache(textStr, rgb, std::move(image2), width); } - if (image) image->draw(output, x, y, alpha); + if (image) { + if (openGL) { + byte r = (rgb >> 16) & 0xff; + byte g = (rgb >> 8) & 0xff; + byte b = (rgb >> 0) & 0xff; + image->draw(output, x, y, r, g, b, alpha); + } else { + image->draw(output, x, y, alpha); + } + } x += width; // in case of trailing whitespace width != image->getWidth() } @@ -361,7 +371,8 @@ bool OSDConsoleRenderer::getFromCache(string_ref text, unsigned rgb, // duplicate items (e.g. the command prompt '> ') degrade this // heuristic). auto it = cacheHint; - if ((it->text == text) && (it->rgb == rgb)) { + // For openGL ignore rgb + if ((it->text == text) && (openGL || (it->rgb == rgb))) { goto found; } @@ -370,7 +381,7 @@ bool OSDConsoleRenderer::getFromCache(string_ref text, unsigned rgb, // in the N first positions in the cache (in approx reverse order). for (it = begin(textCache); it != end(textCache); ++it) { if (it->text != text) continue; - if (it->rgb != rgb ) continue; + if (!openGL && (it->rgb != rgb)) continue; found: image = it->image.get(); width = it->width; cacheHint = it; @@ -398,8 +409,7 @@ void OSDConsoleRenderer::insertInCache( } textCache.pop_back(); } - textCache.push_front(TextCacheElement( - text, rgb, std::move(image), width)); + textCache.emplace_front(text, rgb, std::move(image), width); } void OSDConsoleRenderer::clearCache() diff --git a/src/video/BaseImage.hh b/src/video/BaseImage.hh index 929e737..077767c 100644 --- a/src/video/BaseImage.hh +++ b/src/video/BaseImage.hh @@ -20,9 +20,13 @@ public: virtual ~BaseImage() {} virtual void draw(OutputSurface& output, int x, int y, - byte alpha = 255) = 0; + byte r, byte g, byte b, byte alpha) = 0; virtual int getWidth() const = 0; virtual int getHeight() const = 0; + + void draw(OutputSurface& output, int x, int y, byte alpha = 255) { + draw(output, x, y, 255, 255, 255, alpha); + } }; } // namespace openmsx diff --git a/src/video/GLImage.cc b/src/video/GLImage.cc index c2469ca..fc07889 100644 --- a/src/video/GLImage.cc +++ b/src/video/GLImage.cc @@ -87,11 +87,11 @@ GLImage::GLImage(int width_, int height_, unsigned rgba) height = height_; borderSize = 0; for (int i = 0; i < 4; ++i) { - r[i] = (rgba >> 24) & 0xff; - g[i] = (rgba >> 16) & 0xff; - b[i] = (rgba >> 8) & 0xff; + bgR[i] = (rgba >> 24) & 0xff; + bgG[i] = (rgba >> 16) & 0xff; + bgB[i] = (rgba >> 8) & 0xff; unsigned alpha = (rgba >> 0) & 0xff; - a[i] = (alpha == 255) ? 256 : alpha; + bgA[i] = (alpha == 255) ? 256 : alpha; } } @@ -104,11 +104,11 @@ GLImage::GLImage(int width_, int height_, const unsigned* rgba, height = height_; borderSize = borderSize_; for (int i = 0; i < 4; ++i) { - r[i] = (rgba[i] >> 24) & 0xff; - g[i] = (rgba[i] >> 16) & 0xff; - b[i] = (rgba[i] >> 8) & 0xff; + bgR[i] = (rgba[i] >> 24) & 0xff; + bgG[i] = (rgba[i] >> 16) & 0xff; + bgB[i] = (rgba[i] >> 8) & 0xff; unsigned alpha = (rgba[i] >> 0) & 0xff; - a[i] = (alpha == 255) ? 256 : alpha; + bgA[i] = (alpha == 255) ? 256 : alpha; } borderR = (borderRGBA >> 24) & 0xff; @@ -123,7 +123,7 @@ GLImage::GLImage(SDLSurfacePtr image) { } -void GLImage::draw(OutputSurface& /*output*/, int x, int y, byte alpha) +void GLImage::draw(OutputSurface& /*output*/, int x, int y, byte r, byte g, byte b, byte alpha) { // 4-----------------7 // | | @@ -160,7 +160,7 @@ void GLImage::draw(OutputSurface& /*output*/, int x, int y, byte alpha) gl::context->progTex.activate(); glUniform4f(gl::context->unifTexColor, - 1.0f, 1.0f, 1.0f, alpha / 255.0f); + r / 255.0f, g / 255.0f, b / 255.0f, alpha / 255.0f); glUniformMatrix4fv(gl::context->unifTexMvp, 1, GL_FALSE, &gl::context->pixelMvp[0][0]); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, pos + 4); @@ -169,6 +169,9 @@ void GLImage::draw(OutputSurface& /*output*/, int x, int y, byte alpha) texture.bind(); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } else { + assert(r == 255); + assert(g == 255); + assert(b == 255); gl::context->progFill.activate(); glUniformMatrix4fv(gl::context->unifFillMvp, 1, GL_FALSE, &gl::context->pixelMvp[0][0]); @@ -191,10 +194,10 @@ void GLImage::draw(OutputSurface& /*output*/, int x, int y, byte alpha) // interior byte col[4][4] = { - { r[0], g[0], b[0], byte((a[0] * alpha) / 256) }, - { r[2], g[2], b[2], byte((a[2] * alpha) / 256) }, - { r[3], g[3], b[3], byte((a[3] * alpha) / 256) }, - { r[1], g[1], b[1], byte((a[1] * alpha) / 256) }, + { bgR[0], bgG[0], bgB[0], byte((bgA[0] * alpha) / 256) }, + { bgR[2], bgG[2], bgB[2], byte((bgA[2] * alpha) / 256) }, + { bgR[3], bgG[3], bgB[3], byte((bgA[3] * alpha) / 256) }, + { bgR[1], bgG[1], bgB[1], byte((bgA[1] * alpha) / 256) }, }; glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, col); glEnableVertexAttribArray(1); diff --git a/src/video/GLImage.hh b/src/video/GLImage.hh index deb7c9a..4723cfd 100644 --- a/src/video/GLImage.hh +++ b/src/video/GLImage.hh @@ -22,7 +22,7 @@ public: int borderSize, unsigned borderRGBA); void draw(OutputSurface& output, int x, int y, - byte alpha = 255) override; + byte r, byte g, byte b, byte alpha) override; int getWidth() const override { return width; } int getHeight() const override { return height; } @@ -32,8 +32,8 @@ private: int height; GLfloat texCoord[4]; int borderSize; - int a[4], borderA; - byte r[4], g[4], b[4]; + int bgA[4], borderA; + byte bgR[4], bgG[4], bgB[4]; byte borderR, borderG, borderB; }; diff --git a/src/video/SDLImage.cc b/src/video/SDLImage.cc index 65009c8..05ef6dd 100644 --- a/src/video/SDLImage.cc +++ b/src/video/SDLImage.cc @@ -585,8 +585,12 @@ void SDLImage::allocateWorkImage() } } -void SDLImage::draw(OutputSurface& output, int x, int y, byte alpha) +void SDLImage::draw(OutputSurface& output, int x, int y, byte r, byte g, byte b, byte alpha) { + assert(r == 255); (void)r; + assert(g == 255); (void)g; + assert(b == 255); (void)b; + if (!image) return; if (flipX) x -= image->w; if (flipY) y -= image->h; diff --git a/src/video/SDLImage.hh b/src/video/SDLImage.hh index bd3b810..781c212 100644 --- a/src/video/SDLImage.hh +++ b/src/video/SDLImage.hh @@ -19,7 +19,7 @@ public: unsigned borderSize, unsigned borderRGBA); void draw(OutputSurface& output, int x, int y, - byte alpha = 255) override; + byte r, byte g, byte b, byte alpha) override; int getWidth() const override; int getHeight() const override; hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-04-29 17:19:06
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via bc5b8d4d1fee151c9ca88f920aff652d5c14dc69 (commit) from 6e7f4c62b640a379ca6e7fee17cbd7d0cfe137ff (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit bc5b8d4d1fee151c9ca88f920aff652d5c14dc69 Author: m9710797 <ver...@gm...> Date: Wed Apr 29 19:17:29 2015 +0200 Workaround VS2013 =default issue As hinted at in the previous commit .. it seems VS2013 indeed doesn't properly support '=default' yet. Adding a workaround. ----------------------------------------------------------------------- Summary of changes: src/file/LocalFileReference.hh | 13 +++++++++++-- 1 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/file/LocalFileReference.hh b/src/file/LocalFileReference.hh index 7dfc2be..16e47db 100644 --- a/src/file/LocalFileReference.hh +++ b/src/file/LocalFileReference.hh @@ -37,9 +37,18 @@ public: ~LocalFileReference(); // non-copyable, but moveable LocalFileReference(const LocalFileReference&) = delete; - LocalFileReference(LocalFileReference&&) = default; LocalFileReference& operator=(const LocalFileReference&) = delete; - LocalFileReference& operator=(LocalFileReference&&) = default; + // =default is not yet supported in VS2013, or not for move-operations(?) + //LocalFileReference(LocalFileReference&&) = default; + //LocalFileReference& operator=(LocalFileReference&&) = default; + LocalFileReference(LocalFileReference&& other) + : tmpFile(std::move(other.tmpFile)) + , tmpDir (std::move(other.tmpDir)) {} + LocalFileReference& operator=(LocalFileReference&& other) { + tmpFile = std::move(other.tmpFile); + tmpDir = std::move(other.tmpDir); + return *this; + } /** Returns path to a local uncompressed version of this file. * This path only remains valid as long as this object is in scope. hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-04-29 16:56:47
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 6e7f4c62b640a379ca6e7fee17cbd7d0cfe137ff (commit) via 95698a1fbf974f848d1eef51010895524e2b4085 (commit) via 0461258f54bc698ba395acf2c39fbd46676850ee (commit) via 39b970749d2343d05eda5815b3a6b9c5e0a8f26f (commit) from 7dbd6b2d051bcff281ccff48a159f4adf9fd9c58 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6e7f4c62b640a379ca6e7fee17cbd7d0cfe137ff Author: Wouter Vermaelen <ver...@gm...> Date: Wed Apr 29 12:20:50 2015 +0200 Made LocalFileReference objects move-only Before this pathc LocalFileReference objects were neither copyable nor moveable. Now they are moveable but not copyable. This allows to avoid having to heap-allocate temporary LocalFileReference objects. This patch uses c++11 '=delete' and '=default' syntax. I'm not sure VS2013 already supports it ... let's find out ... commit 95698a1fbf974f848d1eef51010895524e2b4085 Author: Wouter Vermaelen <ver...@gm...> Date: Wed Apr 29 10:51:14 2015 +0200 Cleanup ownership of CliListener objects in GlobalCliComm The ownership rules of CliListener objects in GlobalCliComm were a bit odd (see comments in the (old) code). This patch cleans it up. commit 0461258f54bc698ba395acf2c39fbd46676850ee Author: Wouter Vermaelen <ver...@gm...> Date: Wed Apr 29 10:12:36 2015 +0200 [2/2] Changed FileContext into a value-type This means we store FileContext objects by value instead of allocating them on the heap and storing a (unique) pointer to them. (Actually only HardwareConfig was (still) doing this). Originally FileContext was an (abstract) base class with several concrete subclasses (e.g. SystemFileContext, UserFileContext, ...). So storing these objects by pointer made sense. Some time ago we've already moved all member variables/methods from the subclasses to the base class. So the subclasses only offered different ways to construct the base class. This patch removes the subclasses and instead turns them into helper function that construct a FileContext object. The majority of this patch are mechanical renames: UserFileContext -> userFileContext SystemFileContext -> systemFileContext ... After this patch the only code that holds FileContext by (unique) pointer is backwards-compatibility savestate code. commit 39b970749d2343d05eda5815b3a6b9c5e0a8f26f Author: Wouter Vermaelen <ver...@gm...> Date: Tue Apr 28 17:09:20 2015 +0200 [1/2] Hold HardwareConfig::context by-value Changed the type of the HardwareConfig::context member variable from unique_ptr<FileContext> to FileContext. This was the only (remaining) place where we use heap-allocated FileContext objects. ----------------------------------------------------------------------- Summary of changes: src/CartridgeSlotManager.cc | 2 +- src/CommandLineParser.cc | 10 +++--- src/Reactor.cc | 8 ++-- src/ReverseManager.cc | 5 +-- src/cassette/CassettePlayer.cc | 9 ++--- src/cassette/CassettePort.cc | 1 - src/cassette/WavImage.cc | 6 ++-- src/config/HardwareConfig.cc | 31 +++++++++--------- src/config/HardwareConfig.hh | 10 +++--- src/config/SettingsConfig.cc | 6 ++-- src/console/CommandConsole.cc | 7 ++-- src/console/OSDConsoleRenderer.cc | 4 +- src/console/OSDRectangle.cc | 2 +- src/console/OSDText.cc | 4 +- src/console/TTFFont.cc | 6 ++-- src/events/CliServer.cc | 6 ++-- src/events/GlobalCliComm.cc | 27 ++++++++-------- src/events/GlobalCliComm.hh | 7 ++-- src/events/TclCallbackMessages.cc | 5 ++- src/fdc/DiskChanger.cc | 5 +-- src/fdc/DiskFactory.cc | 2 +- src/fdc/DiskManipulator.cc | 4 +- src/fdc/NowindCommand.cc | 2 +- src/file/FileContext.cc | 59 +++++++++++++++++++---------------- src/file/FileContext.hh | 52 +++++++----------------------- src/file/FilePool.cc | 2 +- src/file/Filename.cc | 2 +- src/file/LocalFileReference.hh | 11 +++++-- src/ide/HDCommand.cc | 4 +- src/ide/IDECDROM.cc | 4 +- src/ide/SCSILS120.cc | 4 +- src/input/UnicodeKeymap.cc | 2 +- src/laserdisc/LaserdiscPlayer.cc | 4 +- src/memory/RomDatabase.cc | 2 +- src/settings/FilenameSetting.cc | 2 +- src/sound/SamplePlayer.cc | 2 +- src/video/AviRecorder.cc | 2 +- src/video/Display.cc | 2 +- src/video/GLUtil.cc | 2 +- src/video/VisibleSurface.cc | 2 +- src/video/scalers/GLHQLiteScaler.cc | 2 +- src/video/scalers/GLHQScaler.cc | 2 +- 42 files changed, 155 insertions(+), 176 deletions(-) diff --git a/src/CartridgeSlotManager.cc b/src/CartridgeSlotManager.cc index a30c4db..b7d0ef8 100644 --- a/src/CartridgeSlotManager.cc +++ b/src/CartridgeSlotManager.cc @@ -376,7 +376,7 @@ void CartridgeSlotManager::CartCmd::tabCompletion(vector<string>& tokens) const if (tokens.size() < 3) { extra = { "eject", "insert" }; } - completeFileName(tokens, UserFileContext(), extra); + completeFileName(tokens, userFileContext(), extra); } bool CartridgeSlotManager::CartCmd::needRecord(array_ref<TclObject> tokens) const diff --git a/src/CommandLineParser.cc b/src/CommandLineParser.cc index 5fe54b0..ec2db47 100644 --- a/src/CommandLineParser.cc +++ b/src/CommandLineParser.cc @@ -133,7 +133,7 @@ bool CommandLineParser::parseFileName(const string& arg, array_ref<string>& cmdL bool processed = parseFileNameInner(arg, arg, cmdLine); if (!processed) { try { - File file(UserFileContext().resolve(arg)); + File file(userFileContext().resolve(arg)); string originalName = file.getOriginalName(); processed = parseFileNameInner(originalName, arg, cmdLine); } catch (FileException&) { @@ -191,14 +191,14 @@ void CommandLineParser::parse(int argc, char** argv) // if there already is a XML-StdioConnection, we // can't also show plain messages on stdout auto& cliComm = reactor.getGlobalCliComm(); - cliComm.addListener(new StdioMessages()); + cliComm.addListener(make_unique<StdioMessages>()); } if (!haveSettings) { auto& settingsConfig = reactor.getGlobalCommandController().getSettingsConfig(); // Load default settings file in case the user // didn't specify one. - SystemFileContext context; + auto context = systemFileContext(); string filename = "settings.xml"; try { settingsConfig.loadSetting(context, filename); @@ -351,7 +351,7 @@ void CommandLineParser::ControlOption::parseOption( } else { throw FatalError("Unknown control type: '" + type + '\''); } - cliComm.addListener(connection.release()); + cliComm.addListener(std::move(connection)); parser.parseStatus = CommandLineParser::CONTROL; } @@ -564,7 +564,7 @@ void CommandLineParser::SettingOption::parseOption( try { auto& settingsConfig = parser.reactor.getGlobalCommandController().getSettingsConfig(); settingsConfig.loadSetting( - CurrentDirFileContext(), getArgument(option, cmdLine)); + currentDirFileContext(), getArgument(option, cmdLine)); parser.haveSettings = true; } catch (FileException& e) { throw FatalError(e.getMessage()); diff --git a/src/Reactor.cc b/src/Reactor.cc index 9b0735a..57a38e6 100644 --- a/src/Reactor.cc +++ b/src/Reactor.cc @@ -288,7 +288,7 @@ InfoCommand& Reactor::getOpenMSXInfoCommand() vector<string> Reactor::getHwConfigs(string_ref type) { vector<string> result; - for (auto& p : SystemFileContext().getPaths()) { + for (auto& p : systemFileContext().getPaths()) { const auto& path = FileOperations::join(p, type); ReadDir configsDir(path); while (auto* entry = configsDir.getEntry()) { @@ -499,7 +499,7 @@ void Reactor::run(CommandLineParser& parser) // execute init.tcl try { commandController.source( - PreferSystemFileContext().resolve("init.tcl")); + preferSystemFileContext().resolve("init.tcl")); } catch (FileException&) { // no init.tcl, ignore } @@ -507,7 +507,7 @@ void Reactor::run(CommandLineParser& parser) // execute startup scripts for (auto& s : parser.getStartupScripts()) { try { - commandController.source(UserFileContext().resolve(s)); + commandController.source(userFileContext().resolve(s)); } catch (FileException& e) { throw FatalError("Couldn't execute script: " + e.getMessage()); @@ -992,7 +992,7 @@ string RestoreMachineCommand::help(const vector<string>& /*tokens*/) const void RestoreMachineCommand::tabCompletion(vector<string>& tokens) const { // TODO: add the default files (state files in user's savestates dir) - completeFileName(tokens, UserFileContext()); + completeFileName(tokens, userFileContext()); } diff --git a/src/ReverseManager.cc b/src/ReverseManager.cc index 1d3e372..c969b94 100644 --- a/src/ReverseManager.cc +++ b/src/ReverseManager.cc @@ -651,7 +651,7 @@ void ReverseManager::loadReplay( if (arguments.size() != 1) throw SyntaxError(); // resolve the filename - UserDataFileContext context(REPLAY_DIR); + auto context = userDataFileContext(REPLAY_DIR); string fileNameArg = arguments[0]; string filename; try { @@ -1032,8 +1032,7 @@ void ReverseManager::ReverseCmd::tabCompletion(vector<string>& tokens) const if (tokens[1] == "loadreplay") { cmds = { "-goto", "-viewonly" }; } - UserDataFileContext context(REPLAY_DIR); - completeFileName(tokens, context, cmds); + completeFileName(tokens, userDataFileContext(REPLAY_DIR), cmds); } else if (tokens[1] == "viewonlymode") { static const char* const options[] = { "true", "false" }; completeString(tokens, options); diff --git a/src/cassette/CassettePlayer.cc b/src/cassette/CassettePlayer.cc index 71342d2..86e3265 100644 --- a/src/cassette/CassettePlayer.cc +++ b/src/cassette/CassettePlayer.cc @@ -50,7 +50,6 @@ #include <algorithm> #include <cassert> -using std::unique_ptr; using std::string; using std::vector; @@ -644,7 +643,7 @@ void CassettePlayer::TapeCommand::execute( } else if (tokens[1].getString() == "insert" && tokens.size() == 3) { try { result.setString("Changing tape"); - Filename filename(tokens[2].getString().str(), UserFileContext()); + Filename filename(tokens[2].getString().str(), userFileContext()); cassettePlayer.playTape(filename, time); } catch (MSXException& e) { throw CommandException(e.getMessage()); @@ -715,7 +714,7 @@ void CassettePlayer::TapeCommand::execute( } else { try { result.setString("Changing tape"); - Filename filename(tokens[1].getString().str(), UserFileContext()); + Filename filename(tokens[1].getString().str(), userFileContext()); cassettePlayer.playTape(filename, time); } catch (MSXException& e) { throw CommandException(e.getMessage()); @@ -812,9 +811,9 @@ void CassettePlayer::TapeCommand::tabCompletion(vector<string>& tokens) const "play", "getpos", "getlength", //"record", }; - completeFileName(tokens, UserFileContext(), cmds); + completeFileName(tokens, userFileContext(), cmds); } else if ((tokens.size() == 3) && (tokens[1] == "insert")) { - completeFileName(tokens, UserFileContext()); + completeFileName(tokens, userFileContext()); } else if ((tokens.size() == 3) && (tokens[1] == "motorcontrol")) { static const char* const extra[] = { "on", "off" }; completeString(tokens, extra); diff --git a/src/cassette/CassettePort.cc b/src/cassette/CassettePort.cc index 25daaa9..8776b54 100644 --- a/src/cassette/CassettePort.cc +++ b/src/cassette/CassettePort.cc @@ -13,7 +13,6 @@ #include "serialize.hh" #include "memory.hh" -using std::unique_ptr; using std::string; namespace openmsx { diff --git a/src/cassette/WavImage.cc b/src/cassette/WavImage.cc index 7570074..38550bc 100644 --- a/src/cassette/WavImage.cc +++ b/src/cassette/WavImage.cc @@ -11,7 +11,7 @@ namespace openmsx { WavImage::WavImage(const Filename& filename, FilePool& filePool) : clock(EmuTime::zero) { - std::unique_ptr<LocalFileReference> localFile; + LocalFileReference localFile; { // File object must be destroyed before localFile is actually // used by an external API (see comments in LocalFileReference @@ -19,9 +19,9 @@ WavImage::WavImage(const Filename& filename, FilePool& filePool) File file(filename); file.setFilePool(filePool); setSha1Sum(file.getSha1Sum()); - localFile = make_unique<LocalFileReference>(file); + localFile = LocalFileReference(file); } - wav = WavData(localFile->getFilename(), 16, 0); + wav = WavData(localFile.getFilename(), 16, 0); clock.setFreq(wav.getFreq()); // calculate the average to subtract it later (simple DC filter) diff --git a/src/config/HardwareConfig.cc b/src/config/HardwareConfig.cc index 80f379e..fa4469b 100644 --- a/src/config/HardwareConfig.cc +++ b/src/config/HardwareConfig.cc @@ -4,7 +4,6 @@ #include "DeviceConfig.hh" #include "XMLElement.hh" #include "LocalFileReference.hh" -#include "FileContext.hh" #include "FileOperations.hh" #include "MSXMotherBoard.hh" #include "CartridgeSlotManager.hh" @@ -51,7 +50,7 @@ unique_ptr<HardwareConfig> HardwareConfig::createRomConfig( { auto result = make_unique<HardwareConfig>(motherBoard, "rom"); const auto& sramfile = FileOperations::getFilename(romfile); - auto context = make_unique<UserFileContext>("roms/" + sramfile); + auto context = userFileContext("roms/" + sramfile); vector<string_ref> ipsfiles; string_ref mapper; @@ -68,7 +67,7 @@ unique_ptr<HardwareConfig> HardwareConfig::createRomConfig( } string_ref arg = it->getString(); if (option == "-ips") { - if (!FileOperations::isRegularFile(context->resolve(arg))) { + if (!FileOperations::isRegularFile(context.resolve(arg))) { throw MSXException("Invalid IPS file: " + arg); } ipsfiles.push_back(arg); @@ -85,7 +84,7 @@ unique_ptr<HardwareConfig> HardwareConfig::createRomConfig( } string resolvedFilename = FileOperations::getAbsolutePath( - context->resolve(romfile)); + context.resolve(romfile)); if (!FileOperations::isRegularFile(resolvedFilename)) { throw MSXException("Invalid ROM file: " + resolvedFilename); } @@ -194,11 +193,6 @@ void HardwareConfig::testRemove() const } } -void HardwareConfig::setFileContext(unique_ptr<FileContext> context_) -{ - context = move(context_); -} - const XMLElement& HardwareConfig::getDevices() const { return getConfig().getChild("devices"); @@ -223,7 +217,7 @@ XMLElement HardwareConfig::loadConfig(const string& filename) string HardwareConfig::getFilename(string_ref type, string_ref name) { - SystemFileContext context; + auto context = systemFileContext(); try { // try <name>.xml return context.resolve(FileOperations::join( @@ -247,8 +241,7 @@ void HardwareConfig::load(string_ref type) assert(!userName.empty()); const auto& baseName = FileOperations::getBaseName(filename); - setFileContext(make_unique<ConfigFileContext>( - baseName, hwName, userName)); + setFileContext(configFileContext(baseName, hwName, userName)); } void HardwareConfig::parseSlots() @@ -385,6 +378,7 @@ void HardwareConfig::setSlot(string_ref slotname) // version 1: initial version // version 2: moved FileContext here (was part of config) // version 3: hold 'config' by-value instead of by-pointer +// version 4: hold 'context' by-value instead of by-pointer template<typename Archive> void HardwareConfig::serialize(Archive& ar, unsigned version) { @@ -398,10 +392,17 @@ void HardwareConfig::serialize(Archive& ar, unsigned version) } ar.serialize("config", config); // fills in getLastSerializedFileContext() if (ar.versionAtLeast(version, 2)) { - ar.serialize("context", context); + if (ar.versionAtLeast(version, 4)) { + ar.serialize("context", context); + } else { + std::unique_ptr<FileContext> ctxt; + ar.serialize("context", ctxt); + if (ctxt) context = *ctxt; + } } else { - context = XMLElement::getLastSerializedFileContext(); - assert(context); + auto ctxt = XMLElement::getLastSerializedFileContext(); + assert(ctxt); + context = *ctxt; } if (ar.isLoader()) { if (!motherBoard.getMachineConfig()) { diff --git a/src/config/HardwareConfig.hh b/src/config/HardwareConfig.hh index f8b6161..8c4f905 100644 --- a/src/config/HardwareConfig.hh +++ b/src/config/HardwareConfig.hh @@ -2,6 +2,7 @@ #define HARDWARECONFIG_HH #include "XMLElement.hh" +#include "FileContext.hh" #include "serialize_meta.hh" #include "serialize_constr.hh" #include "noncopyable.hh" @@ -15,7 +16,6 @@ namespace openmsx { class MSXMotherBoard; class MSXDevice; -class FileContext; class TclObject; class HardwareConfig : private noncopyable @@ -36,8 +36,8 @@ public: MSXMotherBoard& getMotherBoard() const { return motherBoard; } - const FileContext& getFileContext() const { return *context; } - void setFileContext(std::unique_ptr<FileContext> context); + const FileContext& getFileContext() const { return context; } + void setFileContext(FileContext&& ctxt) { context = std::move(ctxt); } const XMLElement& getConfig() const { return config; } const std::string& getName() const { return name; } @@ -74,7 +74,7 @@ private: std::string hwName; std::string userName; XMLElement config; - std::unique_ptr<FileContext> context; + FileContext context; bool externalSlots[4][4]; bool externalPrimSlots[4]; @@ -87,7 +87,7 @@ private: friend struct SerializeConstructorArgs<HardwareConfig>; }; -SERIALIZE_CLASS_VERSION(HardwareConfig, 3); +SERIALIZE_CLASS_VERSION(HardwareConfig, 4); template<> struct SerializeConstructorArgs<HardwareConfig> { diff --git a/src/config/SettingsConfig.cc b/src/config/SettingsConfig.cc index face912..8067985 100644 --- a/src/config/SettingsConfig.cc +++ b/src/config/SettingsConfig.cc @@ -113,7 +113,7 @@ string SettingsConfig::SaveSettingsCommand::help(const vector<string>& /*tokens* void SettingsConfig::SaveSettingsCommand::tabCompletion(vector<string>& tokens) const { if (tokens.size() == 2) { - completeFileName(tokens, SystemFileContext()); + completeFileName(tokens, systemFileContext()); } } @@ -134,7 +134,7 @@ void SettingsConfig::LoadSettingsCommand::execute( if (tokens.size() != 2) { throw SyntaxError(); } - settingsConfig.loadSetting(SystemFileContext(), tokens[1].getString()); + settingsConfig.loadSetting(systemFileContext(), tokens[1].getString()); } string SettingsConfig::LoadSettingsCommand::help(const vector<string>& /*tokens*/) const @@ -145,7 +145,7 @@ string SettingsConfig::LoadSettingsCommand::help(const vector<string>& /*tokens* void SettingsConfig::LoadSettingsCommand::tabCompletion(vector<string>& tokens) const { if (tokens.size() == 2) { - completeFileName(tokens, SystemFileContext()); + completeFileName(tokens, systemFileContext()); } } diff --git a/src/console/CommandConsole.cc b/src/console/CommandConsole.cc index 97fda77..f829e06 100644 --- a/src/console/CommandConsole.cc +++ b/src/console/CommandConsole.cc @@ -162,10 +162,9 @@ CommandConsole::~CommandConsole() void CommandConsole::saveHistory() { try { - UserFileContext context("console"); std::ofstream outputfile; FileOperations::openofstream(outputfile, - context.resolveCreate("history.txt")); + userFileContext("console").resolveCreate("history.txt")); if (!outputfile) { throw FileException( "Error while saving the console history."); @@ -181,9 +180,9 @@ void CommandConsole::saveHistory() void CommandConsole::loadHistory() { try { - UserFileContext context("console"); std::ifstream inputfile( - context.resolveCreate("history.txt").c_str()); + userFileContext("console"). + resolveCreate("history.txt").c_str()); string line; while (inputfile) { getline(inputfile, line); diff --git a/src/console/OSDConsoleRenderer.cc b/src/console/OSDConsoleRenderer.cc index 0fa8b03..8cda122 100644 --- a/src/console/OSDConsoleRenderer.cc +++ b/src/console/OSDConsoleRenderer.cc @@ -273,7 +273,7 @@ bool OSDConsoleRenderer::updateConsoleRect() void OSDConsoleRenderer::loadFont(string_ref value) { - string filename = SystemFileContext().resolve(value); + string filename = systemFileContext().resolve(value); auto newFont = TTFFont(filename, fontSizeSetting.getInt()); if (!newFont.isFixedWidth()) { throw MSXException(value + " is not a monospaced font"); @@ -288,7 +288,7 @@ void OSDConsoleRenderer::loadBackground(string_ref value) backgroundImage.reset(); return; } - string filename = SystemFileContext().resolve(value); + string filename = systemFileContext().resolve(value); if (!openGL) { backgroundImage = make_unique<SDLImage>(filename, destW, destH); } diff --git a/src/console/OSDRectangle.cc b/src/console/OSDRectangle.cc index 0b5d224..0ef1ee8 100644 --- a/src/console/OSDRectangle.cc +++ b/src/console/OSDRectangle.cc @@ -183,7 +183,7 @@ template <typename IMAGE> std::unique_ptr<BaseImage> OSDRectangle::create( assert(bs >= 0); return make_unique<IMAGE>(sw, sh, getRGBA4(), bs, borderRGBA); } else { - string file = SystemFileContext().resolve(imageName); + string file = systemFileContext().resolve(imageName); if (takeImageDimensions()) { double factor = getScaleFactor(output) * scale; return make_unique<IMAGE>(file, factor); diff --git a/src/console/OSDText.cc b/src/console/OSDText.cc index 80e4e03..019886f 100644 --- a/src/console/OSDText.cc +++ b/src/console/OSDText.cc @@ -54,7 +54,7 @@ void OSDText::setProperty( } else if (name == "-font") { string val = value.getString().str(); if (fontfile != val) { - string file = SystemFileContext().resolve(val); + string file = systemFileContext().resolve(val); if (!FileOperations::isRegularFile(file)) { throw CommandException("Not a valid font file: " + val); } @@ -175,7 +175,7 @@ template <typename IMAGE> std::unique_ptr<BaseImage> OSDText::create( int scale = getScaleFactor(output); if (font.empty()) { try { - string file = SystemFileContext().resolve(fontfile); + string file = systemFileContext().resolve(fontfile); int ptSize = size * scale; font = TTFFont(file, ptSize); } catch (MSXException& e) { diff --git a/src/console/TTFFont.cc b/src/console/TTFFont.cc index 5149ceb..f94f501 100644 --- a/src/console/TTFFont.cc +++ b/src/console/TTFFont.cc @@ -65,7 +65,7 @@ private: return *this; } - std::unique_ptr<LocalFileReference> file; + LocalFileReference file; TTF_Font* font; std::string name; int size; @@ -126,8 +126,8 @@ TTF_Font* TTFFontPool::get(const string& filename, int ptSize) SDLTTF::instance(); // init library FontInfo info; - info.file = make_unique<LocalFileReference>(filename); - auto* result = TTF_OpenFont(info.file->getFilename().c_str(), ptSize); + info.file = LocalFileReference(filename); + auto* result = TTF_OpenFont(info.file.getFilename().c_str(), ptSize); if (!result) { throw MSXException(TTF_GetError()); } diff --git a/src/events/CliServer.cc b/src/events/CliServer.cc index 4c68e7c..3c7d623 100644 --- a/src/events/CliServer.cc +++ b/src/events/CliServer.cc @@ -4,6 +4,7 @@ #include "StringOp.hh" #include "FileOperations.hh" #include "MSXException.hh" +#include "memory.hh" #include "random.hh" #include "statp.hh" #include <string> @@ -257,9 +258,8 @@ void CliServer::mainLoop() // sock_close(listenSock); // hangs on win32 return; } - CliListener* connection = new SocketConnection( - commandController, eventDistributor, sd); - cliComm.addListener(connection); + cliComm.addListener(make_unique<SocketConnection>( + commandController, eventDistributor, sd)); } } diff --git a/src/events/GlobalCliComm.cc b/src/events/GlobalCliComm.cc index e75ce77..ef92d7e 100644 --- a/src/events/GlobalCliComm.cc +++ b/src/events/GlobalCliComm.cc @@ -21,40 +21,39 @@ GlobalCliComm::~GlobalCliComm() { assert(Thread::isMainThread()); assert(!delivering); - - ScopedLock lock(sem); - // TODO GlobalCliComm has unusual ownership semantics. - // Try to rework it. - for (auto& l : listeners) { - delete l; - } } -void GlobalCliComm::addListener(CliListener* listener) +void GlobalCliComm::addListener(std::unique_ptr<CliListener> listener) { // can be called from any thread ScopedLock lock(sem); - listeners.push_back(listener); + auto* p = listener.get(); + listeners.push_back(std::move(listener)); if (allowExternalCommands) { - if (auto* conn = dynamic_cast<CliConnection*>(listener)) { + if (auto* conn = dynamic_cast<CliConnection*>(p)) { conn->start(); } } } -void GlobalCliComm::removeListener(CliListener* listener) +std::unique_ptr<CliListener> GlobalCliComm::removeListener(CliListener& listener) { // can be called from any thread ScopedLock lock(sem); - listeners.erase(find_unguarded(listeners, listener)); + auto it = find_if_unguarded(listeners, + [&](const std::unique_ptr<CliListener>& ptr) { + return ptr.get() == &listener; }); + auto result = std::move(*it); + listeners.erase(it); + return result; } void GlobalCliComm::setAllowExternalCommands() { assert(!allowExternalCommands); // should only be called once allowExternalCommands = true; - for (auto* listener : listeners) { - if (auto* conn = dynamic_cast<CliConnection*>(listener)) { + for (auto& listener : listeners) { + if (auto* conn = dynamic_cast<CliConnection*>(listener.get())) { conn->start(); } } diff --git a/src/events/GlobalCliComm.hh b/src/events/GlobalCliComm.hh index 4085489..7f56479 100644 --- a/src/events/GlobalCliComm.hh +++ b/src/events/GlobalCliComm.hh @@ -5,6 +5,7 @@ #include "Semaphore.hh" #include "StringMap.hh" #include "noncopyable.hh" +#include <memory> #include <vector> namespace openmsx { @@ -17,8 +18,8 @@ public: GlobalCliComm(); ~GlobalCliComm(); - void addListener(CliListener* listener); - void removeListener(CliListener* listener); + void addListener(std::unique_ptr<CliListener> listener); + std::unique_ptr<CliListener> removeListener(CliListener& listener); // Before this method has been called commands send over external // connections are not yet processed (but they keep pending). @@ -35,7 +36,7 @@ private: StringMap<std::string> prevValues[NUM_UPDATES]; - std::vector<CliListener*> listeners; + std::vector<std::unique_ptr<CliListener>> listeners; Semaphore sem; // lock access to listeners member bool delivering; bool allowExternalCommands; diff --git a/src/events/TclCallbackMessages.cc b/src/events/TclCallbackMessages.cc index a4095ac..443c1e8 100644 --- a/src/events/TclCallbackMessages.cc +++ b/src/events/TclCallbackMessages.cc @@ -12,12 +12,13 @@ TclCallbackMessages::TclCallbackMessages(GlobalCliComm& cliComm_, false, // don't print callback err on cliComm (would cause infinite loop) false) // don't save setting { - cliComm.addListener(this); + cliComm.addListener(std::unique_ptr<CliListener>(this)); // wrap in unique_ptr } TclCallbackMessages::~TclCallbackMessages() { - cliComm.removeListener(this); + std::unique_ptr<CliListener> ptr = cliComm.removeListener(*this); + ptr.release(); } void TclCallbackMessages::log(CliComm::LogLevel level, string_ref message) diff --git a/src/fdc/DiskChanger.cc b/src/fdc/DiskChanger.cc index 3d8a453..f459eff 100644 --- a/src/fdc/DiskChanger.cc +++ b/src/fdc/DiskChanger.cc @@ -172,11 +172,10 @@ int DiskChanger::insertDisk(string_ref filename) void DiskChanger::insertDisk(array_ref<TclObject> args) { - UserFileContext context; const string& diskImage = FileOperations::getConventionalPath(args[1].getString()); std::unique_ptr<Disk> newDisk(diskFactory.createDisk(diskImage, *this)); for (unsigned i = 2; i < args.size(); ++i) { - Filename filename(args[i].getString().str(), context); + Filename filename(args[i].getString().str(), userFileContext()); newDisk->applyPatch(filename); } @@ -293,7 +292,7 @@ void DiskCommand::tabCompletion(vector<string>& tokens) const static const char* const extra[] = { "eject", "ramdsk", "insert", }; - completeFileName(tokens, UserFileContext(), extra); + completeFileName(tokens, userFileContext(), extra); } } diff --git a/src/fdc/DiskFactory.cc b/src/fdc/DiskFactory.cc index 8a5eeb5..9fa984d 100644 --- a/src/fdc/DiskFactory.cc +++ b/src/fdc/DiskFactory.cc @@ -40,7 +40,7 @@ std::unique_ptr<Disk> DiskFactory::createDisk( return make_unique<RamDSKDiskImage>(); } - Filename filename(diskImage, UserFileContext()); + Filename filename(diskImage, userFileContext()); try { // First try DirAsDSK return make_unique<DirAsDSK>( diff --git a/src/fdc/DiskManipulator.cc b/src/fdc/DiskManipulator.cc index f366d81..cf3a6c3 100644 --- a/src/fdc/DiskManipulator.cc +++ b/src/fdc/DiskManipulator.cc @@ -294,7 +294,7 @@ void DiskManipulator::tabCompletion(vector<string>& tokens) const completeString(tokens, cmds); } else if ((tokens.size() == 3) && (tokens[1] == "create")) { - completeFileName(tokens, UserFileContext()); + completeFileName(tokens, userFileContext()); } else if (tokens.size() == 3) { vector<string> names; @@ -326,7 +326,7 @@ void DiskManipulator::tabCompletion(vector<string>& tokens) const if ((tokens[1] == "savedsk") || (tokens[1] == "import") || (tokens[1] == "export")) { - completeFileName(tokens, UserFileContext()); + completeFileName(tokens, userFileContext()); } else if (tokens[1] == "create") { static const char* const cmds[] = { "360", "720", "32M", "-dos1" diff --git a/src/fdc/NowindCommand.cc b/src/fdc/NowindCommand.cc index 3052ef8..0c61072 100644 --- a/src/fdc/NowindCommand.cc +++ b/src/fdc/NowindCommand.cc @@ -336,7 +336,7 @@ void NowindCommand::tabCompletion(vector<string>& tokens) const "-i", "--image", "-m", "--hdimage", }; - completeFileName(tokens, UserFileContext(), extra); + completeFileName(tokens, userFileContext(), extra); } } // namespace openmsx diff --git a/src/file/FileContext.cc b/src/file/FileContext.cc index 0a20cf7..d712b7a 100644 --- a/src/file/FileContext.cc +++ b/src/file/FileContext.cc @@ -69,6 +69,11 @@ static string resolveHelper(const vector<string>& pathList, throw FileException(filename + " not found in this context"); } +FileContext::FileContext(vector<string>&& paths_, vector<string>&& savePaths_) + : paths(std::move(paths_)), savePaths(std::move(savePaths_)) +{ +} + const string FileContext::resolve(string_ref filename) const { vector<string> pathList = getPathsHelper(paths); @@ -106,6 +111,14 @@ bool FileContext::isUserContext() const return contains(paths, USER_DIRS); } +template<typename Archive> +void FileContext::serialize(Archive& ar, unsigned /*version*/) +{ + ar.serialize("paths", paths); + ar.serialize("savePaths", savePaths); +} +INSTANTIATE_SERIALIZE_METHODS(FileContext); + /// static string backSubstSymbols(const string& path) @@ -126,53 +139,45 @@ static string backSubstSymbols(const string& path) return path; } -ConfigFileContext::ConfigFileContext(string_ref path, - string_ref hwDescr, - string_ref userName) +FileContext configFileContext(string_ref path, string_ref hwDescr, string_ref userName) { - paths = { backSubstSymbols(FileOperations::expandTilde(path)) }; - savePaths = { FileOperations::join( - USER_OPENMSX, "persistent", hwDescr, userName) }; + return { { backSubstSymbols(FileOperations::expandTilde(path)) }, + { FileOperations::join( + USER_OPENMSX, "persistent", hwDescr, userName) } }; } -SystemFileContext::SystemFileContext() +FileContext systemFileContext() { - paths = { USER_DATA, SYSTEM_DATA }; - savePaths = { USER_DATA }; + return { { USER_DATA, SYSTEM_DATA }, + { USER_DATA } }; } -PreferSystemFileContext::PreferSystemFileContext() +FileContext preferSystemFileContext() { - paths = { SYSTEM_DATA, USER_DATA }; // first system dir + return { { SYSTEM_DATA, USER_DATA }, // first system dir + {} }; } -UserFileContext::UserFileContext(string_ref savePath) +FileContext userFileContext(string_ref savePath) { - paths = { "", USER_DIRS }; + vector<string> savePaths; if (!savePath.empty()) { savePaths = { FileOperations::join( USER_OPENMSX, "persistent", savePath) }; } + return { { "", USER_DIRS }, std::move(savePaths) }; } -UserDataFileContext::UserDataFileContext(string_ref subDir) +FileContext userDataFileContext(string_ref subDir) { - paths.emplace_back(); - paths.emplace_back(USER_OPENMSX + '/' + subDir); + return { { "", USER_OPENMSX + '/' + subDir }, + {} }; } -CurrentDirFileContext::CurrentDirFileContext() -{ - paths = { "" }; -} - - -template<typename Archive> -void FileContext::serialize(Archive& ar, unsigned /*version*/) +FileContext currentDirFileContext() { - ar.serialize("paths", paths); - ar.serialize("savePaths", savePaths); + return { { "" }, + {} }; } -INSTANTIATE_SERIALIZE_METHODS(FileContext); } // namespace openmsx diff --git a/src/file/FileContext.hh b/src/file/FileContext.hh index 02619ba..f2bb9d7 100644 --- a/src/file/FileContext.hh +++ b/src/file/FileContext.hh @@ -6,9 +6,13 @@ namespace openmsx { -class FileContext +class FileContext final { public: + FileContext() {} + FileContext(std::vector<std::string>&& paths, + std::vector<std::string>&& savePaths); + const std::string resolve (string_ref filename) const; const std::string resolveCreate(string_ref filename) const; @@ -18,49 +22,17 @@ public: template<typename Archive> void serialize(Archive& ar, unsigned version); -protected: +private: std::vector<std::string> paths; std::vector<std::string> savePaths; }; - -class ConfigFileContext : public FileContext -{ -public: - ConfigFileContext(string_ref path, - string_ref hwDescr, - string_ref userName); -}; - -class SystemFileContext : public FileContext -{ -public: - SystemFileContext(); -}; - -class PreferSystemFileContext : public FileContext -{ -public: - PreferSystemFileContext(); -}; - -class UserFileContext : public FileContext -{ -public: - explicit UserFileContext(string_ref savePath = ""); -}; - -class UserDataFileContext : public FileContext -{ -public: - explicit UserDataFileContext(string_ref subdir); -}; - -class CurrentDirFileContext : public FileContext -{ -public: - CurrentDirFileContext(); -}; +FileContext configFileContext(string_ref path, string_ref hwDescr, string_ref userName); +FileContext systemFileContext(); +FileContext preferSystemFileContext(); +FileContext userFileContext(string_ref savePath = ""); +FileContext userDataFileContext(string_ref subdir); +FileContext currentDirFileContext(); } // namespace openmsx diff --git a/src/file/FilePool.cc b/src/file/FilePool.cc index fd95651..c61c888 100644 --- a/src/file/FilePool.cc +++ b/src/file/FilePool.cc @@ -35,7 +35,7 @@ static string initialFilePoolSettingValue() { TclObject result; - for (auto& p : SystemFileContext().getPaths()) { + for (auto& p : systemFileContext().getPaths()) { TclObject entry1; entry1.addListElement("-path"); entry1.addListElement(FileOperations::join(p, "systemroms")); diff --git a/src/file/Filename.cc b/src/file/Filename.cc index 3cb8304..e8bfb9b 100644 --- a/src/file/Filename.cc +++ b/src/file/Filename.cc @@ -34,7 +34,7 @@ void Filename::updateAfterLoadState() try { resolvedFilename = FileOperations::getAbsolutePath( - UserFileContext().resolve(originalFilename)); + userFileContext().resolve(originalFilename)); } catch (MSXException&) { // nothing } diff --git a/src/file/LocalFileReference.hh b/src/file/LocalFileReference.hh index 5213d4c..7dfc2be 100644 --- a/src/file/LocalFileReference.hh +++ b/src/file/LocalFileReference.hh @@ -1,7 +1,6 @@ #ifndef LOCALFILEREFERENCE_HH #define LOCALFILEREFERENCE_HH -#include "noncopyable.hh" #include <string> namespace openmsx { @@ -9,7 +8,7 @@ namespace openmsx { class File; class Filename; -/** Helper class to use files is APIs other than openmsx::File. +/** Helper class to use files in APIs other than openmsx::File. * The openMSX File class has support for (g)zipped files (or maybe in the * future files over http, ftp, ...). Sometimes you need to pass a filename * to an API that doesn't support this (for example SDL_LoadWav()). This @@ -28,13 +27,19 @@ class Filename; * the file in read-write mode (for example IMG_Load() does this). The * implementation of this class does not keep a reference to the file. */ -class LocalFileReference : private noncopyable +class LocalFileReference { public: + LocalFileReference() {} explicit LocalFileReference(const Filename& filename); explicit LocalFileReference(const std::string& url); explicit LocalFileReference(File& file); ~LocalFileReference(); + // non-copyable, but moveable + LocalFileReference(const LocalFileReference&) = delete; + LocalFileReference(LocalFileReference&&) = default; + LocalFileReference& operator=(const LocalFileReference&) = delete; + LocalFileReference& operator=(LocalFileReference&&) = default; /** Returns path to a local uncompressed version of this file. * This path only remains valid as long as this object is in scope. diff --git a/src/ide/HDCommand.cc b/src/ide/HDCommand.cc index dec5223..08fc7ad 100644 --- a/src/ide/HDCommand.cc +++ b/src/ide/HDCommand.cc @@ -54,7 +54,7 @@ void HDCommand::execute(array_ref<TclObject> tokens, TclObject& result, } try { Filename filename(tokens[fileToken].getString().str(), - UserFileContext()); + userFileContext()); hd.switchImage(filename); // Note: the diskX command doesn't do this either, // so this has not been converted to TclObject style here @@ -79,7 +79,7 @@ void HDCommand::tabCompletion(vector<string>& tokens) const if (tokens.size() < 3) { extra = { "insert" }; } - completeFileName(tokens, UserFileContext(), extra); + completeFileName(tokens, userFileContext(), extra); } bool HDCommand::needRecord(array_ref<TclObject> tokens) const diff --git a/src/ide/IDECDROM.cc b/src/ide/IDECDROM.cc index 4ceff17..e89bceb 100644 --- a/src/ide/IDECDROM.cc +++ b/src/ide/IDECDROM.cc @@ -363,7 +363,7 @@ void CDXCommand::execute(array_ref<TclObject> tokens, TclObject& result, } } try { - string filename = UserFileContext().resolve( + string filename = userFileContext().resolve( tokens[fileToken].getString().str()); cd.insert(filename); // return filename; // Note: the diskX command doesn't do this either, so this has not been converted to TclObject style here @@ -387,7 +387,7 @@ string CDXCommand::help(const vector<string>& /*tokens*/) const void CDXCommand::tabCompletion(vector<string>& tokens) const { static const char* const extra[] = { "eject", "insert" }; - completeFileName(tokens, UserFileContext(), extra); + completeFileName(tokens, userFileContext(), extra); } diff --git a/src/ide/SCSILS120.cc b/src/ide/SCSILS120.cc index 8eb395e..540d5b2 100644 --- a/src/ide/SCSILS120.cc +++ b/src/ide/SCSILS120.cc @@ -792,7 +792,7 @@ void LSXCommand::execute(array_ref<TclObject> tokens, TclObject& result, } } try { - string filename = UserFileContext().resolve( + string filename = userFileContext().resolve( tokens[fileToken].getString().str()); ls.insert(filename); // return filename; // Note: the diskX command doesn't do this either, so this has not been converted to TclObject style here @@ -816,7 +816,7 @@ string LSXCommand::help(const vector<string>& /*tokens*/) const void LSXCommand::tabCompletion(vector<string>& tokens) const { static const char* const extra[] = { "eject", "insert" }; - completeFileName(tokens, UserFileContext(), extra); + completeFileName(tokens, userFileContext(), extra); } diff --git a/src/input/UnicodeKeymap.cc b/src/input/UnicodeKeymap.cc index adf9b8a..8e04244 100644 --- a/src/input/UnicodeKeymap.cc +++ b/src/input/UnicodeKeymap.cc @@ -96,7 +96,7 @@ static bool segmentStartsWith(const char* begin, const char* end, const char (&s UnicodeKeymap::UnicodeKeymap(string_ref keyboardType) : emptyInfo(KeyInfo()) { - auto filename = SystemFileContext().resolve( + auto filename = systemFileContext().resolve( "unicodemaps/unicodemap." + keyboardType); try { File file(filename); diff --git a/src/laserdisc/LaserdiscPlayer.cc b/src/laserdisc/LaserdiscPlayer.cc index 87564e2..6cf9ad3 100644 --- a/src/laserdisc/LaserdiscPlayer.cc +++ b/src/laserdisc/LaserdiscPlayer.cc @@ -85,7 +85,7 @@ void LaserdiscPlayer::Command::tabCompletion(vector<string>& tokens) const static const char* const extra[] = { "eject", "insert" }; completeString(tokens, extra); } else if (tokens.size() == 3 && tokens[1] == "insert") { - completeFileName(tokens, UserFileContext()); + completeFileName(tokens, userFileContext()); } } @@ -628,7 +628,7 @@ void LaserdiscPlayer::nextFrame(EmuTime::param time) void LaserdiscPlayer::setImageName(string newImage, EmuTime::param time) { stop(time); - oggImage = Filename(std::move(newImage), UserFileContext()); + oggImage = Filename(std::move(newImage), userFileContext()); video = make_unique<OggReader>(oggImage, motherBoard.getMSXCliComm()); unsigned inputRate = video->getSampleRate(); diff --git a/src/memory/RomDatabase.cc b/src/memory/RomDatabase.cc index ca579ae..168efad 100644 --- a/src/memory/RomDatabase.cc +++ b/src/memory/RomDatabase.cc @@ -561,7 +561,7 @@ RomDatabase::RomDatabase(GlobalCommandController& commandController, CliComm& cl db.reserve(3500); UnknownTypes unknownTypes; // first user- then system-directory - vector<string> paths = SystemFileContext().getPaths(); + vector<string> paths = systemFileContext().getPaths(); for (auto& p : paths) { string filename = FileOperations::join(p, "softwaredb.xml"); try { diff --git a/src/settings/FilenameSetting.cc b/src/settings/FilenameSetting.cc index 5311c16..4fbea89 100644 --- a/src/settings/FilenameSetting.cc +++ b/src/settings/FilenameSetting.cc @@ -21,7 +21,7 @@ string_ref FilenameSetting::getTypeString() const void FilenameSetting::tabCompletion(std::vector<std::string>& tokens) const { - Completer::completeFileName(tokens, SystemFileContext()); + Completer::completeFileName(tokens, systemFileContext()); } } // namespace openmsx diff --git a/src/sound/SamplePlayer.cc b/src/sound/SamplePlayer.cc index 984c919..5e678f0 100644 --- a/src/sound/SamplePlayer.cc +++ b/src/sound/SamplePlayer.cc @@ -19,7 +19,7 @@ SamplePlayer::SamplePlayer(const std::string& name, const std::string& desc, bool alreadyWarned = false; samples.resize(numSamples); // initialize with empty wavs - SystemFileContext context; + auto context = systemFileContext(); for (unsigned i = 0; i < numSamples; ++i) { try { std::string filename = StringOp::Builder() << diff --git a/src/video/AviRecorder.cc b/src/video/AviRecorder.cc index 4aff921..4516790 100644 --- a/src/video/AviRecorder.cc +++ b/src/video/AviRecorder.cc @@ -357,7 +357,7 @@ void AviRecorder::Cmd::tabCompletion(vector<string>& tokens) const "-prefix", "-videoonly", "-audioonly", "-doublesize", "-triplesize", "-mono", "-stereo", }; - completeFileName(tokens, UserFileContext(), options); + completeFileName(tokens, userFileContext(), options); } } diff --git a/src/video/Display.cc b/src/video/Display.cc index 0d969b5..8415bae 100644 --- a/src/video/Display.cc +++ b/src/video/Display.cc @@ -502,7 +502,7 @@ void Display::ScreenShotCmd::tabCompletion(vector<string>& tokens) const static const char* const extra[] = { "-prefix", "-raw", "-doublesize", "-with-osd", "-no-sprites", }; - completeFileName(tokens, UserFileContext(), extra); + completeFileName(tokens, userFileContext(), extra); } diff --git a/src/video/GLUtil.cc b/src/video/GLUtil.cc index c8a18d7..a9d1b80 100644 --- a/src/video/GLUtil.cc +++ b/src/video/GLUtil.cc @@ -155,7 +155,7 @@ bool PixelBuffers::enabled = true; // Utility function used by Shader. static string readTextFile(const string& filename) { - File file(SystemFileContext().resolve(filename)); + File file(systemFileContext().resolve(filename)); size_t size; const byte* data = file.mmap(size); return string(reinterpret_cast<const char*>(data), size); diff --git a/src/video/VisibleSurface.cc b/src/video/VisibleSurface.cc index a07fe8a..86043d4 100644 --- a/src/video/VisibleSurface.cc +++ b/src/video/VisibleSurface.cc @@ -103,7 +103,7 @@ VisibleSurface::VisibleSurface( // always use 32x32 icon on Windows, for some reason you get badly scaled icons there #ifndef _WIN32 try { - iconSurf = PNG::load(PreferSystemFileContext().resolve("icons/openMSX-logo-256.png"), true); + iconSurf = PNG::load(preferSystemFileContext().resolve("icons/openMSX-logo-256.png"), true); } catch (MSXException& e) { cliComm.printWarning("Falling back to built in 32x32 icon, because failed to load icon: " + e.getMessage()); #endif diff --git a/src/video/scalers/GLHQLiteScaler.cc b/src/video/scalers/GLHQLiteScaler.cc index 3549945..c3ffed7 100644 --- a/src/video/scalers/GLHQLiteScaler.cc +++ b/src/video/scalers/GLHQLiteScaler.cc @@ -35,7 +35,7 @@ GLHQLiteScaler::GLHQLiteScaler(GLScaler& fallback_) nullptr); // data edgeBuffer.setImage(320, 240); - SystemFileContext context; + auto context = systemFileContext(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); for (int i = 0; i < 3; ++i) { int n = i + 2; diff --git a/src/video/scalers/GLHQScaler.cc b/src/video/scalers/GLHQScaler.cc index c3122c3..3c4da6b 100644 --- a/src/video/scalers/GLHQScaler.cc +++ b/src/video/scalers/GLHQScaler.cc @@ -36,7 +36,7 @@ GLHQScaler::GLHQScaler(GLScaler& fallback_) nullptr); // data edgeBuffer.setImage(320, 240); - SystemFileContext context; + auto context = systemFileContext(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); for (int i = 0; i < 3; ++i) { int n = i + 2; hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-04-28 17:03:45
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 7dbd6b2d051bcff281ccff48a159f4adf9fd9c58 (commit) via 1da0474e7d99259b8888b5b9ddfcb7e9e86b433c (commit) via 2f2c002426b19a00ee86707dbea88956efa7b7f6 (commit) via 224c831e0c4783537c2d65ffe6039f1f194e8b10 (commit) via bac228ef4ea35597b58b36520e2bb8a4c9d68deb (commit) from 0538d8dc9c3a04b5b70ea7a809450bbe45a2f726 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 7dbd6b2d051bcff281ccff48a159f4adf9fd9c58 Author: m9710797 <ver...@gm...> Date: Tue Apr 28 18:34:27 2015 +0200 [5/5] Remove pimpl from YM2151 commit 1da0474e7d99259b8888b5b9ddfcb7e9e86b433c Author: Wouter Vermaelen <ver...@gm...> Date: Tue Apr 28 16:06:43 2015 +0200 [4/5] Remove pimpl from VLM5030 commit 2f2c002426b19a00ee86707dbea88956efa7b7f6 Author: Wouter Vermaelen <ver...@gm...> Date: Tue Apr 28 16:38:09 2015 +0200 [3/5] Remove pimpl from YMF278 commit 224c831e0c4783537c2d65ffe6039f1f194e8b10 Author: Wouter Vermaelen <ver...@gm...> Date: Tue Apr 28 16:27:06 2015 +0200 [2/5] Remove pimpl from YMF262 commit bac228ef4ea35597b58b36520e2bb8a4c9d68deb Author: Wouter Vermaelen <ver...@gm...> Date: Tue Apr 28 15:40:37 2015 +0200 [1/5] Remove pimpl from Y8950 When building openmsx with gcc-5.1 using LTO (Link Time Optimizations) I got a warning about ODR-violations (One Definition Rule). And indeed both Y8950.cc and YMF262.cc instantiated enum_string<EnvelopeState> with each a different definition for the EnvelopeState enum. Easiest fix is to qualify both EnvelopeState enums, so either define them in the Y8950/YMF262 class or in some (different) namespace. I initially tried the namespace approach, but it was more difficult than it should be because of the pimpl-idiom that was used by both classes. In lots of other code we've already removed the pimpl-idiom because compile times are no longer a big issue (no longer worth the added complexity). As far as I can see there are only 5 classes remaining that use pimpl: Y8950, YMF262, YMF278, YM2151 and VLM5030 This patch series removes the pimpl-idiom from these 5 classes. This moves the EnvelopeState enum into the Y8950/YMF262 class and thus solves the ODR-violation. ----------------------------------------------------------------------- Summary of changes: src/sound/VLM5030.cc | 162 ++--------- src/sound/VLM5030.hh | 57 ++++- src/sound/Y8950.cc | 516 ++++++++--------------------------- src/sound/Y8950.hh | 179 ++++++++++++- src/sound/Y8950Adpcm.cc | 5 +- src/sound/Y8950Adpcm.hh | 9 +- src/sound/Y8950KeyboardConnector.cc | 6 + src/sound/Y8950KeyboardConnector.hh | 1 + src/sound/YM2151.cc | 263 ++---------------- src/sound/YM2151.hh | 167 +++++++++++- src/sound/YMF262.cc | 463 +++++++------------------------- src/sound/YMF262.hh | 198 +++++++++++++- src/sound/YMF278.cc | 274 +++---------------- src/sound/YMF278.hh | 116 ++++++++- 14 files changed, 1019 insertions(+), 1397 deletions(-) diff --git a/src/sound/VLM5030.cc b/src/sound/VLM5030.cc index 3c58442..555f00b 100644 --- a/src/sound/VLM5030.cc +++ b/src/sound/VLM5030.cc @@ -75,86 +75,16 @@ chirp 12-..: vokume 0 : silent */ #include "VLM5030.hh" -#include "ResampledSoundDevice.hh" -#include "Rom.hh" #include "DeviceConfig.hh" #include "XMLElement.hh" #include "FileOperations.hh" #include "serialize.hh" -#include "memory.hh" #include "random.hh" #include <cstring> #include <cstdint> namespace openmsx { -class VLM5030::Impl final : public ResampledSoundDevice -{ -public: - Impl(const std::string& name, const std::string& desc, - const std::string& romFilename, const DeviceConfig& config); - ~Impl(); - - void reset(); - void writeData(byte data); - void writeControl(byte data, EmuTime::param time); - bool getBSY(EmuTime::param time) const; - - template<typename Archive> - void serialize(Archive& ar, unsigned version); - -private: - void setRST(bool pin); - void setVCU(bool pin); - void setST (bool pin); - - // SoundDevice - void generateChannels(int** bufs, unsigned num) override; - - void setupParameter(byte param); - int getBits(unsigned sbit, unsigned bits); - int parseFrame(); - - std::unique_ptr<Rom> rom; - int address_mask; - - // state of option paramter - int frame_size; - int pitch_offset; - - // these contain data describing the current and previous voice frames - // these are all used to contain the current state of the sound generation - unsigned current_energy; - unsigned current_pitch; - int current_k[10]; - int x[10]; - - word address; - word vcu_addr_h; - - int16_t old_k[10]; - int16_t new_k[10]; - int16_t target_k[10]; - word old_energy; - word new_energy; - word target_energy; - byte old_pitch; - byte new_pitch; - byte target_pitch; - - byte interp_step; - byte interp_count; // number of interp periods - byte sample_count; // sample number within interp - byte pitch_count; - - byte latch_data; - byte parameter; - byte phase; - bool pin_BSY; - bool pin_ST; - bool pin_VCU; - bool pin_RST; -}; // interpolator per frame static const int FR_SIZE = 4; @@ -243,18 +173,18 @@ static const int16_t K5_table[] = { 0, -8127, -16384, -24511, 32638, 24511, 16254, 8127 }; -int VLM5030::Impl::getBits(unsigned sbit, unsigned bits) +int VLM5030::getBits(unsigned sbit, unsigned bits) { unsigned offset = address + (sbit / 8); - unsigned data = (*rom)[(offset + 0) & address_mask] + - (*rom)[(offset + 1) & address_mask] * 256; + unsigned data = rom[(offset + 0) & address_mask] + + rom[(offset + 1) & address_mask] * 256; data >>= (sbit & 7); data &= (0xFF >> (8 - bits)); return data; } // get next frame -int VLM5030::Impl::parseFrame() +int VLM5030::parseFrame() { // remember previous frame old_energy = new_energy; @@ -263,7 +193,7 @@ int VLM5030::Impl::parseFrame() old_k[i] = new_k[i]; } // command byte check - byte cmd = (*rom)[address & address_mask]; + byte cmd = rom[address & address_mask]; if (cmd & 0x01) { // extend frame new_energy = new_pitch = 0; @@ -302,7 +232,7 @@ int VLM5030::Impl::parseFrame() } // decode and buffering data -void VLM5030::Impl::generateChannels(int** bufs, unsigned length) +void VLM5030::generateChannels(int** bufs, unsigned length) { // Single channel device: replace content of bufs[0] (not add to it). if (phase == PH_IDLE) { @@ -439,7 +369,7 @@ phase_stop: } // setup parameteroption when RST=H -void VLM5030::Impl::setupParameter(byte param) +void VLM5030::setupParameter(byte param) { // latch parameter value parameter = param; @@ -466,7 +396,7 @@ void VLM5030::Impl::setupParameter(byte param) } } -void VLM5030::Impl::reset() +void VLM5030::reset() { phase = PH_RESET; address = 0; @@ -488,19 +418,19 @@ void VLM5030::Impl::reset() } // get BSY pin level -bool VLM5030::Impl::getBSY(EmuTime::param time) const +bool VLM5030::getBSY(EmuTime::param time) const { - const_cast<Impl*>(this)->updateStream(time); + const_cast<VLM5030*>(this)->updateStream(time); return pin_BSY; } // latch control data -void VLM5030::Impl::writeData(byte data) +void VLM5030::writeData(byte data) { latch_data = data; } -void VLM5030::Impl::writeControl(byte data, EmuTime::param time) +void VLM5030::writeControl(byte data, EmuTime::param time) { updateStream(time); setRST((data & 0x01) != 0); @@ -509,7 +439,7 @@ void VLM5030::Impl::writeControl(byte data, EmuTime::param time) } // set RST pin level : reset / set table address A8-A15 -void VLM5030::Impl::setRST(bool pin) +void VLM5030::setRST(bool pin) { if (pin_RST) { if (!pin) { // H -> L : latch parameters @@ -527,14 +457,14 @@ void VLM5030::Impl::setRST(bool pin) } // set VCU pin level : ?? unknown -void VLM5030::Impl::setVCU(bool pin) +void VLM5030::setVCU(bool pin) { // direct mode / indirect mode pin_VCU = pin; } // set ST pin level : set table address A0-A7 / start speech -void VLM5030::Impl::setST(bool pin) +void VLM5030::setST(bool pin) { if (pin_ST == pin) { // pin level unchanged @@ -555,8 +485,8 @@ void VLM5030::Impl::setST(bool pin) } else { // indirect access mode int table = (latch_data & 0xfe) + ((int(latch_data) & 1) << 8); - address = (((*rom)[(table + 0) & address_mask]) << 8) | - (*rom)[(table + 1) & address_mask]; + address = ((rom[(table + 0) & address_mask]) << 8) | + rom[(table + 1) & address_mask]; } // reset process status sample_count = frame_size; @@ -575,9 +505,8 @@ void VLM5030::Impl::setST(bool pin) } } -VLM5030::Impl::Impl(const std::string& name, const std::string& desc, - const std::string& romFilename, const DeviceConfig& config) - : ResampledSoundDevice(config.getMotherBoard(), name, desc, 1) + +static XMLElement getRomConfig(const std::string& name, const std::string& romFilename) { XMLElement voiceROMconfig(name); voiceROMconfig.addAttribute("id", "name"); @@ -588,9 +517,14 @@ VLM5030::Impl::Impl(const std::string& name, const std::string& desc, "filename", FileOperations::stripExtension(romFilename) + "_voice.rom"); romElement.addChild( // or hardcoded filename in ditto dir "filename", "keyboardmaster/voice.rom"); - rom = make_unique<Rom>( - name + " ROM", "rom", DeviceConfig(config, voiceROMconfig)); + return voiceROMconfig; +} +VLM5030::VLM5030(const std::string& name, const std::string& desc, + const std::string& romFilename, const DeviceConfig& config) + : ResampledSoundDevice(config.getMotherBoard(), name, desc, 1) + , rom(name + " ROM", "rom", DeviceConfig(config, getRomConfig(name, romFilename))) +{ // reset input pins pin_RST = pin_ST = pin_VCU = false; latch_data = 0; @@ -598,7 +532,7 @@ VLM5030::Impl::Impl(const std::string& name, const std::string& desc, reset(); phase = PH_IDLE; - address_mask = rom->getSize() - 1; + address_mask = rom.getSize() - 1; const int CLOCK_FREQ = 3579545; double input = CLOCK_FREQ / 440.0; @@ -607,13 +541,13 @@ VLM5030::Impl::Impl(const std::string& name, const std::string& desc, registerSound(config); } -VLM5030::Impl::~Impl() +VLM5030::~VLM5030() { unregisterSound(); } template<typename Archive> -void VLM5030::Impl::serialize(Archive& ar, unsigned /*version*/) +void VLM5030::serialize(Archive& ar, unsigned /*version*/) { ar.serialize("address_mask", address_mask); ar.serialize("frame_size", frame_size); @@ -646,44 +580,6 @@ void VLM5030::Impl::serialize(Archive& ar, unsigned /*version*/) ar.serialize("pin_RST", pin_RST); } - -// class VLM5030 - -VLM5030::VLM5030(const std::string& name, const std::string& desc, - const std::string& romFilename, const DeviceConfig& config) - : pimpl(make_unique<Impl>(name, desc, romFilename, config)) -{ -} - -VLM5030::~VLM5030() -{ -} - -void VLM5030::reset() -{ - pimpl->reset(); -} - -void VLM5030::writeData(byte data) -{ - pimpl->writeData(data); -} - -void VLM5030::writeControl(byte data, EmuTime::param time) -{ - pimpl->writeControl(data, time); -} - -bool VLM5030::getBSY(EmuTime::param time) const -{ - return pimpl->getBSY(time); -} - -template<typename Archive> -void VLM5030::serialize(Archive& ar, unsigned version) -{ - pimpl->serialize(ar, version); -} INSTANTIATE_SERIALIZE_METHODS(VLM5030); } // namespace openmsx diff --git a/src/sound/VLM5030.hh b/src/sound/VLM5030.hh index 2d15529..21ce150 100644 --- a/src/sound/VLM5030.hh +++ b/src/sound/VLM5030.hh @@ -1,16 +1,17 @@ #ifndef VLM5030_HH #define VLM5030_HH +#include "ResampledSoundDevice.hh" +#include "Rom.hh" #include "EmuTime.hh" #include "openmsx.hh" #include <string> -#include <memory> namespace openmsx { class DeviceConfig; -class VLM5030 +class VLM5030 final : public ResampledSoundDevice { public: VLM5030(const std::string& name, const std::string& desc, @@ -31,8 +32,56 @@ public: void serialize(Archive& ar, unsigned version); private: - class Impl; - const std::unique_ptr<Impl> pimpl; + void setRST(bool pin); + void setVCU(bool pin); + void setST (bool pin); + + // SoundDevice + void generateChannels(int** bufs, unsigned num) override; + + void setupParameter(byte param); + int getBits(unsigned sbit, unsigned bits); + int parseFrame(); + + Rom rom; + int address_mask; + + // state of option paramter + int frame_size; + int pitch_offset; + + // these contain data describing the current and previous voice frames + // these are all used to contain the current state of the sound generation + unsigned current_energy; + unsigned current_pitch; + int current_k[10]; + int x[10]; + + word address; + word vcu_addr_h; + + int16_t old_k[10]; + int16_t new_k[10]; + int16_t target_k[10]; + word old_energy; + word new_energy; + word target_energy; + byte old_pitch; + byte new_pitch; + byte target_pitch; + + byte interp_step; + byte interp_count; // number of interp periods + byte sample_count; // sample number within interp + byte pitch_count; + + byte latch_data; + byte parameter; + byte phase; + bool pin_BSY; + bool pin_ST; + bool pin_VCU; + bool pin_RST; }; } // namespace openmsx diff --git a/src/sound/Y8950.cc b/src/sound/Y8950.cc index a6114ab..dcbed17 100644 --- a/src/sound/Y8950.cc +++ b/src/sound/Y8950.cc @@ -5,224 +5,22 @@ */ #include "Y8950.hh" -#include "Y8950Adpcm.hh" -#include "Y8950KeyboardConnector.hh" #include "Y8950Periphery.hh" #include "MSXAudio.hh" -#include "ResampledSoundDevice.hh" -#include "EmuTimer.hh" -#include "SimpleDebuggable.hh" -#include "IRQHelper.hh" #include "DeviceConfig.hh" #include "MSXMotherBoard.hh" -#include "DACSound16S.hh" -#include "FixedPoint.hh" #include "Math.hh" #include "serialize.hh" -#include "memory.hh" #include <algorithm> #include <cmath> namespace openmsx { -// Dynamic range of envelope -static const int EG_BITS = 9; -static const unsigned EG_MUTE = 1 << EG_BITS; - -// Bits for envelope phase incremental counter -static const int EG_DP_BITS = 23; -using EnvPhaseIndex = FixedPoint<EG_DP_BITS - EG_BITS>; -static const EnvPhaseIndex EG_DP_MAX = EnvPhaseIndex(EG_MUTE); - - -class Y8950Debuggable final : public SimpleDebuggable -{ -public: - Y8950Debuggable(MSXMotherBoard& motherBoard, Y8950& y8950, - const std::string& name); - byte read(unsigned address, EmuTime::param time) override; - void write(unsigned address, byte value, EmuTime::param time) override; -private: - Y8950& y8950; -}; - - -class Y8950Patch { -public: - Y8950Patch(); - void reset(); - - void setKeyScaleRate(bool value) { - KR = value ? 9 : 11; - } - void setFeedbackShift(byte value) { - FB = value ? 8 - value : 0; - } - - template<typename Archive> - void serialize(Archive& ar, unsigned version); - - bool AM, PM, EG; - byte KR; // 0,1 transformed to 9,11 - byte ML; // 0-15 - byte KL; // 0-3 - byte TL; // 0-63 - byte FB; // 0,1-7 transformed to 0,7-1 - byte AR; // 0-15 - byte DR; // 0-15 - byte SL; // 0-15 - byte RR; // 0-15 -}; - -enum KeyPart { KEY_MAIN = 1, KEY_RHYTHM = 2 }; -enum EnvelopeState { ATTACK, DECAY, SUSTAIN, RELEASE, FINISH }; - -class Y8950Slot { -public: - void reset(); - - inline bool isActive() const; - inline void slotOn (KeyPart part); - inline void slotOff(KeyPart part); - - inline unsigned calc_phase(int lfo_pm); - inline unsigned calc_envelope(int lfo_am); - inline int calc_slot_car(int lfo_pm, int lfo_am, int fm); - inline int calc_slot_mod(int lfo_pm, int lfo_am); - inline int calc_slot_tom(int lfo_pm, int lfo_am); - inline int calc_slot_snare(int lfo_pm, int lfo_am, int whitenoise); - inline int calc_slot_cym(int lfo_am, int a, int b); - inline int calc_slot_hat(int lfo_am, int a, int b, int whitenoise); - - inline void updateAll(unsigned freq); - inline void updatePG(unsigned freq); - inline void updateTLL(unsigned freq); - inline void updateRKS(unsigned freq); - inline void updateEG(); - - template<typename Archive> - void serialize(Archive& ar, unsigned version); - - // OUTPUT - int feedback; - int output; // Output value of slot - - // for Phase Generator (PG) - unsigned phase; // Phase - unsigned dphase; // Phase increment amount - - // for Envelope Generator (EG) - EnvPhaseIndex* dphaseARTableRks; - EnvPhaseIndex* dphaseDRTableRks; - int tll; // Total Level + Key scale level - EnvelopeState eg_mode; // Current state - EnvPhaseIndex eg_phase; // Phase - EnvPhaseIndex eg_dphase;// Phase increment amount - - Y8950Patch patch; - byte key; -}; +static const unsigned EG_MUTE = 1 << Y8950::EG_BITS; +static const Y8950::EnvPhaseIndex EG_DP_MAX = Y8950::EnvPhaseIndex(EG_MUTE); static const unsigned MOD = 0; static const unsigned CAR = 1; -class Y8950Channel { -public: - Y8950Channel(); - void reset(); - inline void setFreq(unsigned freq); - inline void keyOn (KeyPart part); - inline void keyOff(KeyPart part); - - template<typename Archive> - void serialize(Archive& ar, unsigned version); - - Y8950Slot slot[2]; - unsigned freq; // combined F-Number and Block - bool alg; -}; - -class Y8950::Impl final : private ResampledSoundDevice, private EmuTimerCallback -{ -public: - Impl(Y8950& self, const std::string& name, const DeviceConfig& config, - unsigned sampleRam, MSXAudio& audio); - void init(const DeviceConfig& config, EmuTime::param time); - ~Impl(); - - void setEnabled(bool enabled, EmuTime::param time); - void clearRam(); - void reset(EmuTime::param time); - void writeReg(byte reg, byte data, EmuTime::param time); - byte readReg(byte reg, EmuTime::param time); - byte peekReg(byte reg, EmuTime::param time) const; - byte readStatus(EmuTime::param time); - byte peekStatus(EmuTime::param time) const; - - void setStatus(byte flags); - void resetStatus(byte flags); - byte peekRawStatus() const; - - template<typename Archive> - void serialize(Archive& ar, unsigned version); - -private: - // SoundDevice - int getAmplificationFactor() const override; - void generateChannels(int** bufs, unsigned num) override; - - inline void keyOn_BD(); - inline void keyOn_SD(); - inline void keyOn_TOM(); - inline void keyOn_HH(); - inline void keyOn_CYM(); - inline void keyOff_BD(); - inline void keyOff_SD(); - inline void keyOff_TOM(); - inline void keyOff_HH(); - inline void keyOff_CYM(); - inline void setRythmMode(int data); - void update_key_status(); - - bool checkMuteHelper(); - - void changeStatusMask(byte newMask); - - void callback(byte flag) override; - - - MSXMotherBoard& motherBoard; - Y8950Periphery& periphery; - const std::unique_ptr<Y8950Adpcm> adpcm; - const std::unique_ptr<Y8950KeyboardConnector> connector; - const std::unique_ptr<DACSound16S> dac13; // 13-bit (exponential) DAC - const std::unique_ptr<Y8950Debuggable> debuggable; - - const std::unique_ptr<EmuTimer> timer1; // 80us timer - const std::unique_ptr<EmuTimer> timer2; // 320us timer - IRQHelper irq; - - byte reg[0x100]; - - Y8950Channel ch[9]; - - unsigned pm_phase; // Pitch Modulator - unsigned am_phase; // Amp Modulator - - // Noise Generator - int noise_seed; - unsigned noiseA_phase; - unsigned noiseB_phase; - unsigned noiseA_dphase; - unsigned noiseB_dphase; - - byte status; // STATUS Register - byte statusMask; // bit=0 -> masked - bool rythm_mode; - bool am_mode; - bool pm_mode; - bool enabled; -}; - static const double EG_STEP = 0.1875; // 3/16 static const double SL_STEP = 3.0; @@ -255,9 +53,9 @@ static const int DP_BASE_BITS = DP_BITS - PG_BITS; static unsigned sintable[PG_WIDTH]; // Phase incr table for Attack. -static EnvPhaseIndex dphaseARTable[16][16]; +static Y8950::EnvPhaseIndex dphaseARTable[16][16]; // Phase incr table for Decay and Release. -static EnvPhaseIndex dphaseDRTable[16][16]; +static Y8950::EnvPhaseIndex dphaseDRTable[16][16]; // TL Table. static int tllTable[16 * 8][4]; @@ -495,12 +293,12 @@ static void makeTllTable() static void makeDphaseARTable() { for (unsigned Rks = 0; Rks < 16; ++Rks) { - dphaseARTable[Rks][0] = EnvPhaseIndex(0); + dphaseARTable[Rks][0] = Y8950::EnvPhaseIndex(0); for (unsigned AR = 1; AR < 15; ++AR) { unsigned RM = std::min(AR + (Rks >> 2), 15u); unsigned RL = Rks & 3; dphaseARTable[Rks][AR] = - EnvPhaseIndex(12 * (RL + 4)) >> (15 - RM); + Y8950::EnvPhaseIndex(12 * (RL + 4)) >> (15 - RM); } dphaseARTable[Rks][15] = EG_DP_MAX; } @@ -510,25 +308,25 @@ static void makeDphaseARTable() static void makeDphaseDRTable() { for (unsigned Rks = 0; Rks < 16; ++Rks) { - dphaseDRTable[Rks][0] = EnvPhaseIndex(0); + dphaseDRTable[Rks][0] = Y8950::EnvPhaseIndex(0); for (unsigned DR = 1; DR < 16; ++DR) { unsigned RM = std::min(DR + (Rks >> 2), 15u); unsigned RL = Rks & 3; dphaseDRTable[Rks][DR] = - EnvPhaseIndex(RL + 4) >> (15 - RM); + Y8950::EnvPhaseIndex(RL + 4) >> (15 - RM); } } } -// class Y8950Patch +// class Y8950::Patch -Y8950Patch::Y8950Patch() +Y8950::Patch::Patch() { reset(); } -void Y8950Patch::reset() +void Y8950::Patch::reset() { AM = false; PM = false; @@ -545,9 +343,9 @@ void Y8950Patch::reset() } -// class Y8950Slot +// class Y8950::Slot -void Y8950Slot::reset() +void Y8950::Slot::reset() { phase = 0; output = 0; @@ -562,7 +360,7 @@ void Y8950Slot::reset() updateAll(0); } -void Y8950Slot::updatePG(unsigned freq) +void Y8950::Slot::updatePG(unsigned freq) { static const int mltable[16] = { 1, 1*2, 2*2, 3*2, 4*2, 5*2, 6*2 , 7*2, @@ -574,12 +372,12 @@ void Y8950Slot::updatePG(unsigned freq) dphase = ((fnum * mltable[patch.ML]) << block) >> (21 - DP_BITS); } -void Y8950Slot::updateTLL(unsigned freq) +void Y8950::Slot::updateTLL(unsigned freq) { tll = tllTable[freq >> 6][patch.KL] + patch.TL * TL_PER_EG; } -void Y8950Slot::updateRKS(unsigned freq) +void Y8950::Slot::updateRKS(unsigned freq) { unsigned rks = freq >> patch.KR; assert(rks < 16); @@ -587,7 +385,7 @@ void Y8950Slot::updateRKS(unsigned freq) dphaseDRTableRks = dphaseDRTable[rks]; } -void Y8950Slot::updateEG() +void Y8950::Slot::updateEG() { switch (eg_mode) { case ATTACK: @@ -601,12 +399,12 @@ void Y8950Slot::updateEG() eg_dphase = dphaseDRTableRks[patch.RR]; break; case FINISH: - eg_dphase = EnvPhaseIndex(0); + eg_dphase = Y8950::EnvPhaseIndex(0); break; } } -void Y8950Slot::updateAll(unsigned freq) +void Y8950::Slot::updateAll(unsigned freq) { updatePG(freq); updateTLL(freq); @@ -614,30 +412,30 @@ void Y8950Slot::updateAll(unsigned freq) updateEG(); // EG should be last } -bool Y8950Slot::isActive() const +bool Y8950::Slot::isActive() const { return eg_mode != FINISH; } // Slot key on -void Y8950Slot::slotOn(KeyPart part) +void Y8950::Slot::slotOn(KeyPart part) { if (!key) { eg_mode = ATTACK; phase = 0; - eg_phase = EnvPhaseIndex(RA_ADJUST_TABLE[eg_phase.toInt()]); + eg_phase = Y8950::EnvPhaseIndex(RA_ADJUST_TABLE[eg_phase.toInt()]); } key |= part; } // Slot key off -void Y8950Slot::slotOff(KeyPart part) +void Y8950::Slot::slotOff(KeyPart part) { if (key) { key &= ~part; if (!key) { if (eg_mode == ATTACK) { - eg_phase = EnvPhaseIndex(AR_ADJUST_TABLE[eg_phase.toInt()]); + eg_phase = Y8950::EnvPhaseIndex(AR_ADJUST_TABLE[eg_phase.toInt()]); } eg_mode = RELEASE; } @@ -645,14 +443,14 @@ void Y8950Slot::slotOff(KeyPart part) } -// class Y8950Channel +// class Y8950::Channel -Y8950Channel::Y8950Channel() +Y8950::Channel::Channel() { reset(); } -void Y8950Channel::reset() +void Y8950::Channel::reset() { setFreq(0); slot[MOD].reset(); @@ -661,51 +459,38 @@ void Y8950Channel::reset() } // Set frequency (combined F-Number (10bit) and Block (3bit)) -void Y8950Channel::setFreq(unsigned freq_) +void Y8950::Channel::setFreq(unsigned freq_) { freq = freq_; } -void Y8950Channel::keyOn(KeyPart part) +void Y8950::Channel::keyOn(KeyPart part) { slot[MOD].slotOn(part); slot[CAR].slotOn(part); } -void Y8950Channel::keyOff(KeyPart part) +void Y8950::Channel::keyOff(KeyPart part) { slot[MOD].slotOff(part); slot[CAR].slotOff(part); } -Y8950::Impl::Impl(Y8950& self, const std::string& name, - const DeviceConfig& config, unsigned sampleRam, - MSXAudio& audio) +Y8950::Y8950(const std::string& name, const DeviceConfig& config, + unsigned sampleRam, EmuTime::param time, MSXAudio& audio) : ResampledSoundDevice(config.getMotherBoard(), name, "MSX-AUDIO", 9 + 5 + 1) , motherBoard(config.getMotherBoard()) , periphery(audio.createPeriphery(getName())) - , adpcm(make_unique<Y8950Adpcm>( - self, config, name, sampleRam)) - , connector(make_unique<Y8950KeyboardConnector>( - motherBoard.getPluggingController())) - , dac13(make_unique<DACSound16S>( - name + " DAC", "MSX-AUDIO 13-bit DAC", config)) - , debuggable(make_unique<Y8950Debuggable>( - motherBoard, self, getName())) + , adpcm(*this, config, name, sampleRam) + , connector(motherBoard.getPluggingController()) + , dac13(name + " DAC", "MSX-AUDIO 13-bit DAC", config) + , debuggable(motherBoard, *this, getName()) , timer1(EmuTimer::createOPL3_1(motherBoard.getScheduler(), *this)) , timer2(EmuTimer::createOPL3_2(motherBoard.getScheduler(), *this)) , irq(motherBoard, getName() + ".IRQ") , enabled(true) { -} - -// Constructor is split in two phases (actual constructor and this init() -// method). Reason is that adpcm->reset() calls setStatus() via the Y8950 -// object, but before constructor is finished the pointer from Y8950 to -// Y8950Impl is not yet initialized. -void Y8950::Impl::init(const DeviceConfig& config, EmuTime::param time) -{ makePmTable(); makeAdjustTable(); makeDB2LinTable(); @@ -722,18 +507,18 @@ void Y8950::Impl::init(const DeviceConfig& config, EmuTime::param time) registerSound(config); } -Y8950::Impl::~Impl() +Y8950::~Y8950() { unregisterSound(); } -void Y8950::Impl::clearRam() +void Y8950::clearRam() { - adpcm->clearRam(); + adpcm.clearRam(); } // Reset whole of opl except patch datas. -void Y8950::Impl::reset(EmuTime::param time) +void Y8950::reset(EmuTime::param time) { for (auto& c : ch) c.reset(); @@ -758,26 +543,26 @@ void Y8950::Impl::reset(EmuTime::param time) statusMask = 0; irq.reset(); - adpcm->reset(time); + adpcm.reset(time); } // Drum key on -void Y8950::Impl::keyOn_BD() { ch[6].keyOn(KEY_RHYTHM); } -void Y8950::Impl::keyOn_HH() { ch[7].slot[MOD].slotOn(KEY_RHYTHM); } -void Y8950::Impl::keyOn_SD() { ch[7].slot[CAR].slotOn(KEY_RHYTHM); } -void Y8950::Impl::keyOn_TOM() { ch[8].slot[MOD].slotOn(KEY_RHYTHM); } -void Y8950::Impl::keyOn_CYM() { ch[8].slot[CAR].slotOn(KEY_RHYTHM); } +void Y8950::keyOn_BD() { ch[6].keyOn(KEY_RHYTHM); } +void Y8950::keyOn_HH() { ch[7].slot[MOD].slotOn(KEY_RHYTHM); } +void Y8950::keyOn_SD() { ch[7].slot[CAR].slotOn(KEY_RHYTHM); } +void Y8950::keyOn_TOM() { ch[8].slot[MOD].slotOn(KEY_RHYTHM); } +void Y8950::keyOn_CYM() { ch[8].slot[CAR].slotOn(KEY_RHYTHM); } // Drum key off -void Y8950::Impl::keyOff_BD() { ch[6].keyOff(KEY_RHYTHM); } -void Y8950::Impl::keyOff_HH() { ch[7].slot[MOD].slotOff(KEY_RHYTHM); } -void Y8950::Impl::keyOff_SD() { ch[7].slot[CAR].slotOff(KEY_RHYTHM); } -void Y8950::Impl::keyOff_TOM(){ ch[8].slot[MOD].slotOff(KEY_RHYTHM); } -void Y8950::Impl::keyOff_CYM(){ ch[8].slot[CAR].slotOff(KEY_RHYTHM); } +void Y8950::keyOff_BD() { ch[6].keyOff(KEY_RHYTHM); } +void Y8950::keyOff_HH() { ch[7].slot[MOD].slotOff(KEY_RHYTHM); } +void Y8950::keyOff_SD() { ch[7].slot[CAR].slotOff(KEY_RHYTHM); } +void Y8950::keyOff_TOM(){ ch[8].slot[MOD].slotOff(KEY_RHYTHM); } +void Y8950::keyOff_CYM(){ ch[8].slot[CAR].slotOff(KEY_RHYTHM); } // Change Rhythm Mode -void Y8950::Impl::setRythmMode(int data) +void Y8950::setRythmMode(int data) { bool newMode = (data & 32) != 0; if (rythm_mode != newMode) { @@ -794,7 +579,7 @@ void Y8950::Impl::setRythmMode(int data) } // recalculate 'key' from register settings -void Y8950::Impl::update_key_status() +void Y8950::update_key_status() { for (unsigned i = 0; i < 9; ++i) { int main = (reg[0xb0 + i] & 0x20) ? KEY_MAIN : 0; @@ -823,7 +608,7 @@ static inline int wave2_8pi(int e) return (shift > 0) ? (e >> shift) : (e << -shift); } -unsigned Y8950Slot::calc_phase(int lfo_pm) +unsigned Y8950::Slot::calc_phase(int lfo_pm) { if (patch.PM) { phase += (dphase * lfo_pm) >> PM_AMP_BITS; @@ -833,12 +618,12 @@ unsigned Y8950Slot::calc_phase(int lfo_pm) return phase >> DP_BASE_BITS; } -#define S2E(x) EnvPhaseIndex(int(x / EG_STEP)) -static const EnvPhaseIndex SL[16] = { +#define S2E(x) Y8950::EnvPhaseIndex(int(x / EG_STEP)) +static const Y8950::EnvPhaseIndex SL[16] = { S2E( 0), S2E( 3), S2E( 6), S2E( 9), S2E(12), S2E(15), S2E(18), S2E(21), S2E(24), S2E(27), S2E(30), S2E(33), S2E(36), S2E(39), S2E(42), S2E(93) }; -unsigned Y8950Slot::calc_envelope(int lfo_am) +unsigned Y8950::Slot::calc_envelope(int lfo_am) { unsigned egout = 0; switch (eg_mode) { @@ -846,7 +631,7 @@ unsigned Y8950Slot::calc_envelope(int lfo_am) eg_phase += eg_dphase; if (eg_phase >= EG_DP_MAX) { egout = 0; - eg_phase = EnvPhaseIndex(0); + eg_phase = Y8950::EnvPhaseIndex(0); eg_mode = DECAY; updateEG(); } else { @@ -898,14 +683,14 @@ unsigned Y8950Slot::calc_envelope(int lfo_am) return std::min<unsigned>(egout, DB_MUTE - 1); } -int Y8950Slot::calc_slot_car(int lfo_pm, int lfo_am, int fm) +int Y8950::Slot::calc_slot_car(int lfo_pm, int lfo_am, int fm) { unsigned egout = calc_envelope(lfo_am); int pgout = calc_phase(lfo_pm) + wave2_8pi(fm); return dB2LinTab[sintable[pgout & PG_MASK] + egout]; } -int Y8950Slot::calc_slot_mod(int lfo_pm, int lfo_am) +int Y8950::Slot::calc_slot_mod(int lfo_pm, int lfo_am) { unsigned egout = calc_envelope(lfo_am); unsigned pgout = calc_phase(lfo_pm); @@ -919,14 +704,14 @@ int Y8950Slot::calc_slot_mod(int lfo_pm, int lfo_am) return feedback; } -int Y8950Slot::calc_slot_tom(int lfo_pm, int lfo_am) +int Y8950::Slot::calc_slot_tom(int lfo_pm, int lfo_am) { unsigned egout = calc_envelope(lfo_am); unsigned pgout = calc_phase(lfo_pm); return dB2LinTab[sintable[pgout & PG_MASK] + egout]; } -int Y8950Slot::calc_slot_snare(int lfo_pm, int lfo_am, int whitenoise) +int Y8950::Slot::calc_slot_snare(int lfo_pm, int lfo_am, int whitenoise) { unsigned egout = calc_envelope(lfo_am); unsigned pgout = calc_phase(lfo_pm); @@ -934,14 +719,14 @@ int Y8950Slot::calc_slot_snare(int lfo_pm, int lfo_am, int whitenoise) return (dB2LinTab[tmp + egout] + dB2LinTab[egout + whitenoise]) >> 1; } -int Y8950Slot::calc_slot_cym(int lfo_am, int a, int b) +int Y8950::Slot::calc_slot_cym(int lfo_am, int a, int b) { unsigned egout = calc_envelope(lfo_am); return (dB2LinTab[egout + a] + dB2LinTab[egout + b]) >> 1; } // HI-HAT -int Y8950Slot::calc_slot_hat(int lfo_am, int a, int b, int whitenoise) +int Y8950::Slot::calc_slot_hat(int lfo_am, int a, int b, int whitenoise) { unsigned egout = calc_envelope(lfo_am); return (dB2LinTab[egout + whitenoise] + @@ -949,18 +734,18 @@ int Y8950Slot::calc_slot_hat(int lfo_am, int a, int b, int whitenoise) dB2LinTab[egout + b]) >> 2; } -int Y8950::Impl::getAmplificationFactor() const +int Y8950::getAmplificationFactor() const { return 1 << (15 - DB2LIN_AMP_BITS); } -void Y8950::Impl::setEnabled(bool enabled_, EmuTime::param time) +void Y8950::setEnabled(bool enabled_, EmuTime::param time) { updateStream(time); enabled = enabled_; } -bool Y8950::Impl::checkMuteHelper() +bool Y8950::checkMuteHelper() { if (!enabled) { return true; @@ -980,10 +765,10 @@ bool Y8950::Impl::checkMuteHelper() if (ch[8].slot[CAR].isActive()) return false; } - return adpcm->isMuted(); + return adpcm.isMuted(); } -void Y8950::Impl::generateChannels(int** bufs, unsigned num) +void Y8950::generateChannels(int** bufs, unsigned num) { // TODO implement per-channel mute (instead of all-or-nothing) if (checkMuteHelper()) { @@ -1071,7 +856,7 @@ void Y8950::Impl::generateChannels(int** bufs, unsigned num) //bufs[13] += 0; } - bufs[14][sample] += adpcm->calcSample(); + bufs[14][sample] += adpcm.calcSample(); } } @@ -1079,7 +864,7 @@ void Y8950::Impl::generateChannels(int** bufs, unsigned num) // I/O Ctrl // -void Y8950::Impl::writeReg(byte rg, byte data, EmuTime::param time) +void Y8950::writeReg(byte rg, byte data, EmuTime::param time) { int stbl[32] = { 0, 2, 4, 1, 3, 5, -1, -1, @@ -1148,11 +933,11 @@ void Y8950::Impl::writeReg(byte rg, byte data, EmuTime::param time) timer2->setStart((data & Y8950::R04_ST2) != 0, time); reg[rg] = data; } - adpcm->resetStatus(); + adpcm.resetStatus(); break; case 0x06: // (KEYBOARD OUT) - connector->write(data, time); + connector.write(data, time); reg[rg] = data; break; @@ -1173,7 +958,7 @@ void Y8950::Impl::writeReg(byte rg, byte data, EmuTime::param time) case 0x12: // ENVELOP CONTROL case 0x1A: // PCM-DATA reg[rg] = data; - adpcm->writeReg(rg, data, time); + adpcm.writeReg(rg, data, time); break; case 0x15: // DAC-DATA (bit9-2) @@ -1183,7 +968,7 @@ void Y8950::Impl::writeReg(byte rg, byte data, EmuTime::param time) + reg[0x16]; tmp = (tmp * 4) >> (7 - reg[0x17]); tmp = Math::clipIntToShort(tmp); - dac13->writeDAC(tmp, time); + dac13.writeDAC(tmp, time); } break; case 0x16: // (bit1-0) @@ -1210,8 +995,8 @@ void Y8950::Impl::writeReg(byte rg, byte data, EmuTime::param time) case 0x20: { int s = stbl[rg & 0x1f]; if (s >= 0) { - Y8950Channel& chan = ch[s / 2]; - Y8950Slot& slot = chan.slot[s & 1]; + auto& chan = ch[s / 2]; + auto& slot = chan.slot[s & 1]; slot.patch.AM = (data >> 7) & 1; slot.patch.PM = (data >> 6) & 1; slot.patch.EG = (data >> 5) & 1; @@ -1225,8 +1010,8 @@ void Y8950::Impl::writeReg(byte rg, byte data, EmuTime::param time) case 0x40: { int s = stbl[rg & 0x1f]; if (s >= 0) { - Y8950Channel& chan = ch[s / 2]; - Y8950Slot& slot = chan.slot[s & 1]; + auto& chan = ch[s / 2]; + auto& slot = chan.slot[s & 1]; slot.patch.KL = (data >> 6) & 3; slot.patch.TL = (data >> 0) & 63; slot.updateAll(chan.freq); @@ -1237,7 +1022,7 @@ void Y8950::Impl::writeReg(byte rg, byte data, EmuTime::param time) case 0x60: { int s = stbl[rg & 0x1f]; if (s >= 0) { - Y8950Slot& slot = ch[s / 2].slot[s & 1]; + auto& slot = ch[s / 2].slot[s & 1]; slot.patch.AR = (data >> 4) & 15; slot.patch.DR = (data >> 0) & 15; slot.updateEG(); @@ -1248,7 +1033,7 @@ void Y8950::Impl::writeReg(byte rg, byte data, EmuTime::param time) case 0x80: { int s = stbl[rg & 0x1f]; if (s >= 0) { - Y8950Slot& slot = ch[s / 2].slot[s & 1]; + auto& slot = ch[s / 2].slot[s & 1]; slot.patch.SL = (data >> 4) & 15; slot.patch.RR = (data >> 0) & 15; slot.updateEG(); @@ -1322,7 +1107,7 @@ void Y8950::Impl::writeReg(byte rg, byte data, EmuTime::param time) } } -byte Y8950::Impl::readReg(byte rg, EmuTime::param time) +byte Y8950::readReg(byte rg, EmuTime::param time) { updateStream(time); // TODO only when necessary @@ -1332,7 +1117,7 @@ byte Y8950::Impl::readReg(byte rg, EmuTime::param time) case 0x13: // ??? case 0x14: // ??? case 0x1A: // PCM-DATA - result = adpcm->readReg(rg, time); + result = adpcm.readReg(rg, time); break; default: result = peekReg(rg, time); @@ -1340,17 +1125,17 @@ byte Y8950::Impl::readReg(byte rg, EmuTime::param time) return result; } -byte Y8950::Impl::peekReg(byte rg, EmuTime::param time) const +byte Y8950::peekReg(byte rg, EmuTime::param time) const { switch (rg) { case 0x05: // (KEYBOARD IN) - return connector->read(time); // TODO peek iso read + return connector.peek(time); case 0x0F: // ADPCM-DATA case 0x13: // ??? case 0x14: // ??? case 0x1A: // PCM-DATA - return adpcm->peekReg(rg, time); + return adpcm.peekReg(rg, time); case 0x19: { // I/O DATA byte input = periphery.read(time); @@ -1363,25 +1148,25 @@ byte Y8950::Impl::peekReg(byte rg, EmuTime::param time) const } } -byte Y8950::Impl::readStatus(EmuTime::param time) +byte Y8950::readStatus(EmuTime::param time) { byte result = peekStatus(time); //std::cout << "status: " << (int)result << std::endl; return result; } -byte Y8950::Impl::peekStatus(EmuTime::param time) const +byte Y8950::peekStatus(EmuTime::param time) const { - adpcm->sync(time); + const_cast<Y8950Adpcm&>(adpcm).sync(time); return (status & (0x80 | statusMask)) | 0x06; // bit 1 and 2 are always 1 } -void Y8950::Impl::callback(byte flag) +void Y8950::callback(byte flag) { setStatus(flag); } -void Y8950::Impl::setStatus(byte flags) +void Y8950::setStatus(byte flags) { status |= flags; if (status & statusMask) { @@ -1389,7 +1174,7 @@ void Y8950::Impl::setStatus(byte flags) irq.set(); } } -void Y8950::Impl::resetStatus(byte flags) +void Y8950::resetStatus(byte flags) { status &= ~flags; if (!(status & statusMask)) { @@ -1397,11 +1182,11 @@ void Y8950::Impl::resetStatus(byte flags) irq.reset(); } } -byte Y8950::Impl::peekRawStatus() const +byte Y8950::peekRawStatus() const { return status; } -void Y8950::Impl::changeStatusMask(byte newMask) +void Y8950::changeStatusMask(byte newMask) { statusMask = newMask; status &= statusMask; @@ -1416,7 +1201,7 @@ void Y8950::Impl::changeStatusMask(byte newMask) template<typename Archive> -void Y8950Patch::serialize(Archive& ar, unsigned /*version*/) +void Y8950::Patch::serialize(Archive& ar, unsigned /*version*/) { ar.serialize("AM", AM); ar.serialize("PM", PM); @@ -1432,14 +1217,14 @@ void Y8950Patch::serialize(Archive& ar, unsigned /*version*/) ar.serialize("RR", RR); } -static enum_string<EnvelopeState> envelopeStateInfo[]= { - { "ATTACK", ATTACK }, - { "DECAY", DECAY }, - { "SUSTAIN", SUSTAIN }, - { "RELEASE", RELEASE }, - { "FINISH", FINISH } +static enum_string<Y8950::EnvelopeState> envelopeStateInfo[]= { + { "ATTACK", Y8950::ATTACK }, + { "DECAY", Y8950::DECAY }, + { "SUSTAIN", Y8950::SUSTAIN }, + { "RELEASE", Y8950::RELEASE }, + { "FINISH", Y8950::FINISH } }; -SERIALIZE_ENUM(EnvelopeState, envelopeStateInfo); +SERIALIZE_ENUM(Y8950::EnvelopeState, envelopeStateInfo); // version 1: initial version // version 2: 'slotStatus' is replaced with 'key' and no longer serialized @@ -1447,7 +1232,7 @@ SERIALIZE_ENUM(EnvelopeState, envelopeStateInfo); // version 3: serialize 'eg_mode' as an enum instead of an int, also merged // the 2 enum values SUSHOLD and SUSTINE into SUSTAIN template<typename Archive> -void Y8950Slot::serialize(Archive& ar, unsigned version) +void Y8950::Slot::serialize(Archive& ar, unsigned version) { ar.serialize("feedback", feedback); ar.serialize("output", output); @@ -1470,14 +1255,14 @@ void Y8950Slot::serialize(Archive& ar, unsigned version) } } - // These are restored by call to updateAll() in Y8950Channel::serialize() + // These are restored by call to updateAll() in Y8950::Channel::serialize() // dphase, tll, dphaseARTableRks, dphaseDRTableRks, eg_dphase // These are restored by update_key_status(): // key } template<typename Archive> -void Y8950Channel::serialize(Archive& ar, unsigned /*version*/) +void Y8950::Channel::serialize(Archive& ar, unsigned /*version*/) { ar.serialize("mod", slot[MOD]); ar.serialize("car", slot[CAR]); @@ -1491,10 +1276,10 @@ void Y8950Channel::serialize(Archive& ar, unsigned /*version*/) } template<typename Archive> -void Y8950::Impl::serialize(Archive& ar, unsigned /*version*/) +void Y8950::serialize(Archive& ar, unsigned /*version*/) { - ar.serialize("keyboardConnector", *connector); - ar.serialize("adpcm", *adpcm); + ar.serialize("keyboardConnector", connector); + ar.serialize("adpcm", adpcm); ar.serialize("timer1", *timer1); ar.serialize("timer2", *timer2); ar.serialize("irq", irq); @@ -1531,99 +1316,24 @@ void Y8950::Impl::serialize(Archive& ar, unsigned /*version*/) // SimpleDebuggable -Y8950Debuggable::Y8950Debuggable(MSXMotherBoard& motherBoard, Y8950& y8950_, - const std::string& name) +Y8950::Debuggable::Debuggable(MSXMotherBoard& motherBoard, Y8950& y8950_, + const std::string& name) : SimpleDebuggable(motherBoard, name + " regs", "MSX-AUDIO", 0x100) , y8950(y8950_) { } -byte Y8950Debuggable::read(unsigned address, EmuTime::param time) +byte Y8950::Debuggable::read(unsigned address, EmuTime::param time) { return y8950.peekReg(address, time); } -void Y8950Debuggable::write(unsigned address, byte value, EmuTime::param time) +void Y8950::Debuggable::write(unsigned address, byte value, EmuTime::param time) { y8950.writeReg(address, value, time); } - -// class Y8950 - -Y8950::Y8950(const std::string& name, const DeviceConfig& config, - unsigned sampleRam, EmuTime::param time, - MSXAudio& audio) - : pimpl(make_unique<Impl>(*this, name, config, sampleRam, audio)) -{ - pimpl->init(config, time); -} - -Y8950::~Y8950() -{ -} - -void Y8950::setEnabled(bool enabled, EmuTime::param time) -{ - pimpl->setEnabled(enabled, time); -} - -void Y8950::clearRam() -{ - pimpl->clearRam(); -} - -void Y8950::reset(EmuTime::param time) -{ - pimpl->reset(time); -} - -void Y8950::writeReg(byte reg, byte data, EmuTime::param time) -{ - pimpl->writeReg(reg, data, time); -} - -byte Y8950::readReg(byte reg, EmuTime::param time) -{ - return pimpl->readReg(reg, time); -} - -byte Y8950::peekReg(byte reg, EmuTime::param time) const -{ - return pimpl->peekReg(reg, time); -} - -byte Y8950::readStatus(EmuTime::param time) -{ - return pimpl->readStatus(time); -} - -byte Y8950::peekStatus(EmuTime::param time) const -{ - return pimpl->peekStatus(time); -} - -void Y8950::setStatus(byte flags) -{ - pimpl->setStatus(flags); -} - -void Y8950::resetStatus(byte flags) -{ - pimpl->resetStatus(flags); -} - -byte Y8950::peekRawStatus() const -{ - return pimpl->peekRawStatus(); -} - -template<typename Archive> -void Y8950::serialize(Archive& ar, unsigned version) -{ - pimpl->serialize(ar, version); -} INSTANTIATE_SERIALIZE_METHODS(Y8950); -SERIALIZE_CLASS_VERSION(Y8950Slot, 3); +SERIALIZE_CLASS_VERSION(Y8950::Slot, 3); } // namespace openmsx diff --git a/src/sound/Y8950.hh b/src/sound/Y8950.hh index 0921242..3ec0f56 100644 --- a/src/sound/Y8950.hh +++ b/src/sound/Y8950.hh @@ -1,7 +1,15 @@ #ifndef Y8950_HH #define Y8950_HH +#include "Y8950Adpcm.hh" +#include "Y8950KeyboardConnector.hh" +#include "ResampledSoundDevice.hh" +#include "DACSound16S.hh" +#include "SimpleDebuggable.hh" +#include "IRQHelper.hh" +#include "EmuTimer.hh" #include "EmuTime.hh" +#include "FixedPoint.hh" #include "openmsx.hh" #include <string> #include <memory> @@ -10,8 +18,9 @@ namespace openmsx { class MSXAudio; class DeviceConfig; +class Y8950Periphery; -class Y8950 +class Y8950 final : private ResampledSoundDevice, private EmuTimerCallback { public: static const int CLOCK_FREQ = 3579545; @@ -63,8 +72,172 @@ public: void serialize(Archive& ar, unsigned version); private: - class Impl; - const std::unique_ptr<Impl> pimpl; + // SoundDevice + int getAmplificationFactor() const override; + void generateChannels(int** bufs, unsigned num) override; + + inline void keyOn_BD(); + inline void keyOn_SD(); + inline void keyOn_TOM(); + inline void keyOn_HH(); + inline void keyOn_CYM(); + inline void keyOff_BD(); + inline void keyOff_SD(); + inline void keyOff_TOM(); + inline void keyOff_HH(); + inline void keyOff_CYM(); + inline void setRythmMode(int data); + void update_key_status(); + + bool checkMuteHelper(); + + void changeStatusMask(byte newMask); + + void callback(byte flag) override; + +public: + // Dynamic range of envelope + static const int EG_BITS = 9; + + // Bits for envelope phase incremental counter + static const int EG_DP_BITS = 23; + using EnvPhaseIndex = FixedPoint<EG_DP_BITS - EG_BITS>; + + enum EnvelopeState { ATTACK, DECAY, SUSTAIN, RELEASE, FINISH }; + +private: + enum KeyPart { KEY_MAIN = 1, KEY_RHYTHM = 2 }; + + class Patch { + public: + Patch(); + void reset(); + + void setKeyScaleRate(bool value) { + KR = value ? 9 : 11; + } + void setFeedbackShift(byte value) { + FB = value ? 8 - value : 0; + } + + template<typename Archive> + void serialize(Archive& ar, unsigned version); + + bool AM, PM, EG; + byte KR; // 0,1 transformed to 9,11 + byte ML; // 0-15 + byte KL; // 0-3 + byte TL; // 0-63 + byte FB; // 0,1-7 transformed to 0,7-1 + byte AR; // 0-15 + byte DR; // 0-15 + byte SL; // 0-15 + byte RR; // 0-15 + }; + + class Slot { + public: + void reset(); + + inline bool isActive() const; + inline void slotOn (KeyPart part); + inline void slotOff(KeyPart part); + + inline unsigned calc_phase(int lfo_pm); + inline unsigned calc_envelope(int lfo_am); + inline int calc_slot_car(int lfo_pm, int lfo_am, int fm); + inline int calc_slot_mod(int lfo_pm, int lfo_am); + inline int calc_slot_tom(int lfo_pm, int lfo_am); + inline int calc_slot_snare(int lfo_pm, int lfo_am, int whitenoise); + inline int calc_slot_cym(int lfo_am, int a, int b); + inline int calc_slot_hat(int lfo_am, int a, int b, int whitenoise); + + inline void updateAll(unsigned freq); + inline void updatePG(unsigned freq); + inline void updateTLL(unsigned freq); + inline void updateRKS(unsigned freq); + inline void updateEG(); + + template<typename Archive> + void serialize(Archive& ar, unsigned version); + + // OUTPUT + int feedback; + int output; // Output value of slot + + // for Phase Generator (PG) + unsigned phase; // Phase + unsigned dphase; // Phase increment amount + + // for Envelope Generator (EG) + EnvPhaseIndex* dphaseARTableRks; + EnvPhaseIndex* dphaseDRTableRks; + int tll; // Total Level + Key scale level + EnvelopeState eg_mode; // Current state + EnvPhaseIndex eg_phase; // Phase + EnvPhaseIndex eg_dphase;// Phase increment amount + + Patch patch; + byte key; + }; + + class Channel { + public: + Channel(); + void reset(); + inline void setFreq(unsigned freq); + inline void keyOn (KeyPart part); + inline void keyOff(KeyPart part); + + template<typename Archive> + void serialize(Archive& ar, unsigned version); + + Slot slot[2]; + unsigned freq; // combined F-Number and Block + bool alg; + }; + + class Debuggable final : public SimpleDebuggable { + public: + Debuggable(MSXMotherBoard& motherBoard, Y8950& y8950, + const std::string& name); + byte read(unsigned address, EmuTime::param time) override; + void write(unsigned address, byte value, EmuTime::param time) override; + private: + Y8950& y8950; + }; + + MSXMotherBoard& motherBoard; + Y8950Periphery& periphery; + Y8950Adpcm adpcm; + Y8950KeyboardConnector connector; + DACSound16S dac13; // 13-bit (exponential) DAC + Debuggable debuggable; + + const std::unique_ptr<EmuTimer> timer1; // 80us timer + const std::unique_ptr<EmuTimer> timer2; // 320us timer + IRQHelper irq; + + byte reg[0x100]; + + Channel ch[9]; + + unsigned pm_phase; // Pitch Modulator + unsigned am_phase; // Amp Modulator + + // Noise Generator + int noise_seed; + unsigned noiseA_phase; + unsigned noiseB_phase; + unsigned noiseA_dphase; + unsigned noiseB_dphase; + + byte status; // STATUS Register + byte statusMask; // bit=0 -> masked + bool rythm_mode; + bool am_mode; + bool pm_mode; + bool enabled; }; } // namespace openmsx diff --git a/src/sound/Y8950Adpcm.cc b/src/sound/Y8950Adpcm.cc index fa3246b..dd61752 100644 --- a/src/sound/Y8950Adpcm.cc +++ b/src/sound/Y8950Adpcm.cc @@ -9,6 +9,7 @@ // 100% realtime speed (which is most of the time better for sound quality). #include "Y8950Adpcm.hh" +#include "Y8950.hh" #include "Clock.hh" #include "DeviceConfig.hh" #include "MSXMotherBoard.hh" @@ -299,9 +300,9 @@ byte Y8950Adpcm::readReg(byte rg, EmuTime::param time) return result; } -byte Y8950Adpcm::peekReg(byte rg, EmuTime::param time) +byte Y8950Adpcm::peekReg(byte rg, EmuTime::param time) const { - sync(time); // TODO only when needed + const_cast<Y8950Adpcm*>(this)->sync(time); // TODO only when needed return peekReg(rg); } diff --git a/src/sound/Y8950Adpcm.hh b/src/sound/Y8950Adpcm.hh index 10b94b0..ac1748c 100644 --- a/src/sound/Y8950Adpcm.hh +++ b/src/sound/Y8950Adpcm.hh @@ -1,7 +1,6 @@ #ifndef Y8950ADPCM_HH #define Y8950ADPCM_HH -#include "Y8950.hh" #include "Ram.hh" #include "Schedulable.hh" #include "Clock.hh" @@ -11,6 +10,7 @@ namespace openmsx { class DeviceConfig; +class Y8950; class Y8950Adpcm final : public Schedulable { @@ -24,7 +24,7 @@ public: bool isMuted() const; void writeReg(byte rg, byte data, EmuTime::param time); byte readReg(byte rg, EmuTime::param time); - byte peekReg(byte rg, EmuTime::param time); + byte peekReg(byte rg, EmuTime::param time) const; int calcSample(); void sync(EmuTime::param time); void resetStatus(); @@ -63,7 +63,10 @@ private: Y8950& y8950; Ram ram; - Clock<Y8950::CLOCK_FREQ, Y8950::CLOCK_FREQ_DIV> clock; + // copy/pasted from Y8950.hh + static const int CLOCK_FREQ = 3579545; + static const int CLOCK_FREQ_DIV = 72; + Clock<CLOCK_FREQ, CLOCK_FREQ_DIV> clock; PlayData emu; // used for emulator behaviour (read back of sample data) PlayData aud; // used by audio generation thread diff --git a/src/sound/Y8950KeyboardConnector.cc b/src/sound/Y8950KeyboardConnector.cc index 268a5ee..0a14fdf 100644 --- a/src/sound/Y8950KeyboardConnector.cc +++ b/src/sound/Y8950KeyboardConnector.cc @@ -28,6 +28,12 @@ byte Y8950KeyboardConnector::read(EmuTime::param time) return getPluggedKeyb().read(time); } +byte Y8950KeyboardConnector::peek(EmuTime::param time) const +{ + // TODO implement proper peek + return const_cast<Y8950KeyboardConnector*>(this)->read(time); +} + const std::string Y8950KeyboardConnector::getDescription() const { return "MSX-AUDIO keyboard connector"; diff --git a/src/sound/Y8950KeyboardConnector.hh b/src/sound/Y8950KeyboardConnector.hh index 01a5b9f..c7711b7 100644 --- a/src/sound/Y8950KeyboardConnector.hh +++ b/src/sound/Y8950KeyboardConnector.hh @@ -15,6 +15,7 @@ public: void write(byte data, EmuTime::param time); byte read(EmuTime::param time); + byte peek(EmuTime::param time) const; Y8950KeyboardDevice& getPluggedKeyb() const; // Connector diff --git a/src/sound/YM2151.cc b/src/sound/YM2151.cc index 6d51744..50fb5ba 100644 --- a/src/sound/YM2151.cc +++ b/src/sound/YM2151.cc @@ -5,190 +5,13 @@ ******************************************************************************/ #include "YM2151.hh" -#include "ResampledSoundDevice.hh" -#include "EmuTimer.hh" -#include "IRQHelper.hh" #include "DeviceConfig.hh" #include "serialize.hh" -#include "memory.hh" #include <cmath> #include <cstring> namespace openmsx { -class YM2151::Impl final : public ResampledSoundDevice, private EmuTimerCallback -{ -public: - Impl(const std::string& name, const std::string& desc, - const DeviceConfig& config, EmuTime::param time); - ~Impl(); - void reset(EmuTime::param time); - void writeReg(byte r, byte v, EmuTime::param time); - byte readStatus() const; - - template<typename Archive> - void serialize(Archive& ar, unsigned version); - -private: - // a single operator - struct YM2151Operator { - template<typename Archive> - void serialize(Archive& ar, unsigned version); - - int* connect; // operator output 'direction' - int* mem_connect; // where to put the delayed sample (MEM) - - unsigned phase; // accumulated operator phase - unsigned freq; // operator frequency count - int dt1; // current DT1 (detune 1 phase inc/decrement) value - unsigned mul; // frequency count multiply - unsigned dt1_i; // DT1 index * 32 - unsigned dt2; // current DT2 (detune 2) value - - int mem_value; // delayed sample (MEM) value - - // channel specific data - // note: each operator number 0 contains channel specific data - unsigned fb_shift; // feedback shift value for operators 0 in each channel - int fb_out_curr; // operator feedback value (used only by operators 0) - int fb_out_prev; // previous feedback value (used only by operators 0) - unsigned kc; // channel KC (copied to all operators) - unsigned kc_i; // just for speedup - unsigned pms; // channel PMS - unsigned ams; // channel AMS - - unsigned AMmask; // LFO Amplitude Modulation enable mask - unsigned state; // Envelope state: 4-attack(AR) - // 3-decay(D1R) - // 2-sustain(D2R) - // 1-release(RR) - // 0-off - unsigned tl; // Total attenuation Level - int volume; // current envelope attenuation level - unsigned d1l; // envelope switches to sustain state after - - unsigned key; // 0=last key was KEY OFF, 1=last key was KEY ON - - unsigned ks; // key scale - unsigned ar; // attack rate - unsigned d1r; // decay rate - unsigned d2r; // sustain rate - unsigned rr; // release rate - - byte eg_sh_ar; // (attack state) - byte eg_sel_ar; // (attack state) - byte eg_sh_d1r; // (decay state) - byte eg_sel_d1r; // (decay state) - // reaching this level - byte eg_sh_d2r; // (sustain state) - byte eg_sel_d2r; // (sustain state) - byte eg_sh_rr; // (release state) - byte eg_sel_rr; // (release state) - }; - - void setConnect(YM2151Operator* om1, int cha, int v); - - // SoundDevice - void generateChannels(int** bufs, unsigned num) override; - - void callback(byte flag) override; - void setStatus(byte flags); - void resetStatus(byte flags); - - void initTables(); - void initChipTables(); - - // operator methods - void envelopeKONKOFF(YM2151Operator* op, int v); - static void refreshEG(YM2151Operator* op); - int opCalc(YM2151Operator* op, unsigned env, int pm); - int opCalc1(YM2151Operator* op, unsigned env, int pm); - inline unsigned volumeCalc(YM2151Operator* op, unsigned AM); - inline void keyOn(YM2151Operator* op, unsigned keySet); - inline void keyOff(YM2151Operator* op, unsigned keyClear); - - // general chip mehods - void chanCalc(unsigned chan); - void chan7Calc(); - - void advanceEG(); - void advance(); - - bool checkMuteHelper(); - - IRQHelper irq; - - // Timers (see EmuTimer class for details about timing) - const std::unique_ptr<EmuTimer> timer1; - const std::unique_ptr<EmuTimer> timer2; - - YM2151Operator oper[32]; // the 32 operators - - unsigned pan[16]; // channels output masks (0xffffffff = enable) - - unsigned eg_cnt; // global envelope generator counter - unsigned eg_timer; // global envelope generator counter - // works at frequency = chipclock/64/3 - unsigned lfo_phase; // accumulated LFO phase (0 to 255) - unsigned lfo_timer; // LFO timer - unsigned lfo_overflow; // LFO generates new output when lfo_timer - // reaches this value - unsigned lfo_counter; // LFO phase increment counter - unsigned lfo_counter_add;// step of lfo_counter - unsigned lfa; // LFO current AM output - int lfp; // LFO current PM output - - unsigned noise; // noise enable/period register - // bit 7 - noise enable, bits 4-0 - noise period - unsigned noise_rng; // 17 bit noise shift register - int noise_p; // current noise 'phase' - unsigned noise_f; // current noise period - - unsigned csm_req; // CSM KEY ON / KEY OFF sequence request - - unsigned irq_enable; // IRQ enable for timer B (bit 3) and timer A - // (bit 2); bit 7 - CSM mode (keyon to all - // slots, everytime timer A overflows) - unsigned status; // chip status (BUSY, IRQ Flags) - - // Frequency-deltas to get the closest frequency possible. - // There are 11 octaves because of DT2 (max 950 cents over base frequency) - // and LFO phase modulation (max 800 cents below AND over base frequency) - // Summary: octave explanation - // 0 note code - LFO PM - // 1 note code - // 2 note code - // 3 note code - // 4 note code - // 5 note code - // 6 note code - // 7 note code - // 8 note code - // 9 note code + DT2 + LFO PM - // 10 note code + DT2 + LFO PM - unsigned freq[11 * 768]; // 11 octaves, 768 'cents' per octave // No Save - - // Frequency deltas for DT1. These deltas alter operator frequency - // after it has been taken from frequency-deltas table. - int dt1_freq[8 * 32]; // 8 DT1 levels, 32 KC values // No Save - unsigned noise_tab[32]; // 17bit Noise Generator periods // No Save - - int chanout[8]; - int m2, c1, c2; // Phase Modulation input for operators 2,3,4 - int mem; // one sample delay memory - - word timer_A_val; - - byte lfo_wsel; // LFO waveform (0-saw, 1-square, 2-triangle, - // 3-random noise) - byte amd; // LFO Amplitude Modulation Depth - signed char pmd; // LFO Phase Modulation Depth - - byte test; // TEST register - byte ct; // output control pins (bit1-CT2, bit0-CT1) - - byte regs[256]; // only used for serialization ATM -}; // TODO void ym2151WritePortCallback(void* ref, unsigned port, byte value); static const int FREQ_SH = 16; // 16.16 fixed point (frequency calculations) @@ -470,7 +293,7 @@ static byte lfo_noise_waveform[256] = { 0xE2,0x4D,0x8A,0xA6,0x46,0x95,0x0F,0x8F,0xF5,0x15,0x97,0x32,0xD4,0x28,0x1E,0x55 }; -void YM2151::Impl::initTables() +void YM2151::initTables() { for (int x = 0; x < TL_RES_LEN; ++x) { double m = (1 << 16) / exp2((x + 1) * (ENV_STEP / 4.0) / 8.0); @@ -523,7 +346,7 @@ void YM2151::Impl::initTables() } } -void YM2151::Impl::initChipTables() +void YM2151::initChipTables() { // this loop calculates Hertz values for notes from c-0 to b-7 // including 64 'cents' (100/64 that is 1.5625 of real cent) per note @@ -585,7 +408,7 @@ void YM2151::Impl::initChipTables() } } -void YM2151::Impl::keyOn(YM2151Operator* op, unsigned keySet) { +void YM2151::keyOn(YM2151Operator* op, unsigned keySet) { if (!op->key) { op->phase = 0; /* clear phase */ op->state = EG_ATT; /* KEY ON = attack */ @@ -600,7 +423,7 @@ void YM2151::Impl::keyOn(YM2151Operator* op, unsigned keySet) { op->key |= keySet; } -void YM2151::Impl::keyOff(YM2151Operator* op, unsigned keyClear) { +void YM2151::keyOff(YM2151Operator* op, unsigned keyClear) { if (op->key) { op->key &= keyClear; if (!op->key) { @@ -611,7 +434,7 @@ void YM2151::Impl::keyOff(YM2151Operator* op, unsigned keyClear) { } } -void YM2151::Impl::envelopeKONKOFF(YM2151Operator* op, int v) +void YM2151::envelopeKONKOFF(YM2151Operator* op, int v) { if (v & 0x08) { // M1 keyOn (op + 0, 1); @@ -635,7 +458,7 @@ void YM2151::Impl::envelopeKONKOFF(YM2151Operator* op, int v) } } -void YM2151::Impl::setConnect(YM2151Operator* om1, int cha, int v) +void YM2151::setConnect(YM2151Operator* om1, int cha, int v) { YM2151Operator* om2 = om1 + 1; YM2151Operator* oc1 = om1 + 2; @@ -723,7 +546,7 @@ void YM2151::Impl::setConnect(YM2151Operator* om1, int cha, int v) } } -void YM2151::Impl::refreshEG(YM2151Operator* op) +void YM2151::refreshEG(YM2151Operator* op) { unsigned kc = op->kc; @@ -792,7 +615,7 @@ void YM2151::Impl::refreshEG(YM2151Operator* op) op->eg_sel_rr = eg_rate_select[op->rr + v]; } -void YM2151::Impl::writeReg(byte r, byte v, EmuTime::param time) +void YM2151::writeReg(byte r, byte v, EmuTime::param time) { updateStream(time); @@ -1008,7 +831,7 @@ void YM2151::Impl::writeRe... [truncated message content] |
From: Wouter V. <m97...@us...> - 2015-04-27 16:53:00
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 0538d8dc9c3a04b5b70ea7a809450bbe45a2f726 (commit) from 7ddab26e99ff0df6792752129ab70fbcea1b03cf (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 0538d8dc9c3a04b5b70ea7a809450bbe45a2f726 Author: m9710797 <ver...@gm...> Date: Mon Apr 27 18:51:23 2015 +0200 Small tweaks to Metal gear overlay script Mostly avoid calculations when not necessary (e.g. no need to update widgets when in the weapon screen). ----------------------------------------------------------------------- Summary of changes: share/scripts/_metal_gear_overlay.tcl | 94 +++++++++++++++------------------ 1 files changed, 43 insertions(+), 51 deletions(-) diff --git a/share/scripts/_metal_gear_overlay.tcl b/share/scripts/_metal_gear_overlay.tcl index 938e64d..4c3ab23 100644 --- a/share/scripts/_metal_gear_overlay.tcl +++ b/share/scripts/_metal_gear_overlay.tcl @@ -46,26 +46,22 @@ proc init {} { variable currentfield variable map_feature_enabled - #Create OSD elements + # Create OSD elements osd_widgets::msx_init metal_gear for {set i 0} {$i < $num_enemies} {incr i} { osd_widgets::create_power_bar metal_gear.powerbar$i 16 2 0xff0080b0 0x00000080 0xffffffC0 osd_widgets::create_power_bar metal_gear.punchbar$i 16 2 0x0080ffb0 0x00000080 0xffffffC0 + set max_hp($i) 0 + set punch_max_hp($i) 0 } osd_widgets::create_power_bar metal_gear.powerbarsnake 24 2 0x00ff00b0 0x00000080 0xffffffC0 osd_widgets::create_power_bar metal_gear.boss 24 8 0x00ff00b0 0x00000080 0xffffffC0 - for {set i 0} {$i < 256} {incr i} { - set max_hp($i) 0 - set punch_max_hp($i) 0 - } - set currentfield 0 if {$map_feature_enabled} { - for {set y 0} {$y < 16} {incr y} { for {set x 0} {$x < 16} {incr x} { set field [expr {$x + ($y * 16)}] @@ -74,27 +70,25 @@ proc init {} { } } - #Start the overlay refresh + # Start the overlay refresh update_overlay } -proc update_overlay {} { +proc update_impl {} { variable max_hp variable punch_max_hp variable num_enemies variable enemy_names variable currentfield - variable metal_gear_overlay_active variable map_feature_enabled - if {!$metal_gear_overlay_active} return - # check for field change - if {$currentfield != [peek 0xC130]} { + set newfield [peek 0xC130] + if {$currentfield != $newfield} { set previousfield $currentfield - set currentfield [peek 0xC130] + set currentfield $newfield - #clear out old HP values if field has changed + # clear out old HP values if field has changed for {set i 0} {$i < $num_enemies} {incr i} { set punch_max_hp($i) 0 set max_hp($i) 0 @@ -105,42 +99,31 @@ proc update_overlay {} { } } - #check if not in demo or weapon/item screen - if {[peek 0xC012] == 0x00 || [peek 0xC012] == 0x47 || [peek 0xC012] == 0x50 || [peek 0xC151] != 0} { - osd configure metal_gear -y 999 - } else { - osd configure metal_gear -y 0 - } - for {set i 0; set addr 0xD000} {$i < $num_enemies} {incr i; incr addr 0x80} { set enemy_type [peek $addr] - set enemy_hp [expr {0 + [peek [expr {$addr + 0x0D}]]}] - set enemy_punch_hp [expr {3 - [peek [expr $addr + 0x7A]]}] - - if {$enemy_punch_hp > $punch_max_hp($i)} { - set punch_max_hp($i) $enemy_punch_hp - } - if {$enemy_hp > $max_hp($i)} { - set max_hp($i) $enemy_hp - } - - set pos_x [expr { 0 + [peek [expr {$addr + 5}]]}] - set pos_y [expr { 0 + [peek [expr {$addr + 3}]]}] - + set enemy_hp [peek [expr {$addr + 0x0D}]] if {$enemy_type > 0 && $enemy_hp > 0} { - set power [expr {1.00 * $enemy_hp / $max_hp($i)}] - set punch_power [expr {1.00 * $enemy_punch_hp / $punch_max_hp($i)}] + set pos_x [peek [expr {$addr + 5}]] + set pos_y [peek [expr {$addr + 3}]] + if {$enemy_hp > $max_hp($i)} { + set max_hp($i) $enemy_hp + } + set power [expr {1.00 * $enemy_hp / $max_hp($i)}] set text "HP: $enemy_hp $i [lindex $enemy_names $enemy_type] - #$enemy_type" - osd_widgets::update_power_bar metal_gear.powerbar$i $pos_x $pos_y $power $text + osd_widgets::update_power_bar metal_gear.powerbar$i $pos_x $pos_y $power $text # only show the punch bar when the enemy can be punched + set enemy_punch_hp [expr {3 - [peek [expr {$addr + 0x7A}]]}] if {$enemy_punch_hp > 0} { + if {$enemy_punch_hp > $punch_max_hp($i)} { + set punch_max_hp($i) $enemy_punch_hp + } + set punch_power [expr {1.00 * $enemy_punch_hp / $punch_max_hp($i)}] osd_widgets::update_power_bar metal_gear.punchbar$i $pos_x [expr {$pos_y + 5}] $punch_power "" } else { osd_widgets::update_power_bar metal_gear.punchbar$i -50 -50 0 "" } - } else { osd_widgets::update_power_bar metal_gear.powerbar$i -50 -50 0 "" osd_widgets::update_power_bar metal_gear.punchbar$i -50 -50 0 "" @@ -149,39 +132,48 @@ proc update_overlay {} { # get stats for snake set snake_hp [peek 0xC131] - set power [expr {1.00 * $snake_hp / 48}] + set power [expr {$snake_hp / 48.0}] set poisoned [peek 0xC139] set pos_x [peek 0xC184] set pos_y [peek 0xc182] + set text "" if {$poisoned == 1} { set power 0 - set text "POISONED ($pos_x,$pos_y) HP: $snake_hp" - } else { - set text "($pos_x,$pos_y) HP: $snake_hp" + set text "POISONED " } + append text "($pos_x,$pos_y) HP: $snake_hp" osd_widgets::update_power_bar metal_gear.powerbarsnake [expr {$pos_x - 13}] [expr {$pos_y + 20}] $power $text +} +proc update_overlay {} { + variable metal_gear_overlay_active + if {!$metal_gear_overlay_active} return + + # check if not in demo or weapon/item screen + set c012 [peek 0xC012] + if {$c012 == 0x00 || $c012 == 0x47 || $c012 == 0x50 || [peek 0xC151] != 0} { + osd configure metal_gear -y 999 + } else { + osd configure metal_gear -y 0 + update_impl + } after frame [namespace code update_overlay] } proc toggle_metal_gear_overlay {} { variable metal_gear_overlay_active - set metal_gear_overlay_active [expr {!$metal_gear_overlay_active}] - if {$metal_gear_overlay_active} { init - update_overlay - osd::display_message "Metal Gear overlay activated" info - return "Metal Gear overlay activated!" + set text "Metal Gear overlay activated!" } else { - set retval "" osd destroy metal_gear - osd::display_message "Metal Gear overlay deactivated" info - return "Metal Gear overlay deactivated." + set text "Metal Gear overlay deactivated." } + osd::display_message $text info + return $text } namespace export toggle_metal_gear_overlay hooks/post-receive -- openMSX (main) |
From: Manuel B. <man...@us...> - 2015-04-27 15:00:58
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 7ddab26e99ff0df6792752129ab70fbcea1b03cf (commit) from 580cade6ffe6311abd2f5a6b592a6369a61318ed (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 7ddab26e99ff0df6792752129ab70fbcea1b03cf Author: Manuel Bilderbeek <Man...@gm...> Date: Mon Apr 27 16:59:35 2015 +0200 Added Metal Gear overlay Thanks to Vampier, Dunnius and BiFi for the initial implementation. ----------------------------------------------------------------------- Summary of changes: share/scripts/_metal_gear_overlay.tcl | 191 +++++++++++++++++++++++++++++++++ share/scripts/lazy.tcl | 1 + 2 files changed, 192 insertions(+), 0 deletions(-) create mode 100644 share/scripts/_metal_gear_overlay.tcl diff --git a/share/scripts/_metal_gear_overlay.tcl b/share/scripts/_metal_gear_overlay.tcl new file mode 100644 index 0000000..938e64d --- /dev/null +++ b/share/scripts/_metal_gear_overlay.tcl @@ -0,0 +1,191 @@ +# This script is based on: +# openMSX metal gear overlay script 2014/12/07 +# By Dunnius / Bifi / Vampier + +namespace eval metal_gear_overlay { + +variable num_enemies 11 +variable max_hp +variable punch_max_hp +variable currentfield +# the map feature is disabled here in code, because it isn't very useful yet +variable map_feature_enabled false +variable metal_gear_overlay_active false + +variable enemy_names [list \ + "" "01" "Bridge Segment" "Ellen Screaming 'help me'" "Soldier - Pattern 1" \ + "Soldier - Pattern 2" "Camera" "Landmine" "Gas cloud" "Enemy - Tank" \ + "Soldier - (Alert)" "Soldier - Red (Alert)" "Tank Shell" \ + "Soldier - Shooting" "Soldier - Guard" "Roller" "Trap Floor" "Metal Gear" \ + "Enemy - Bulldozer" "Soldier - Truck" "Soldier - Flying" \ + "Soldier - Fly to the Switch" "Soldier - Flying (Alert)" "Unknown3" \ + "Soldier - Run to the Switch" "Guard Dog" "Mr. Arnold" "Basement Guard Dogs" \ + "Soldier - Guard to building 3" "Event - Dogs will appear" "Soldier - Pattern 3" \ + "Scorpion" "Big Boss" "Shoot Gunner" "Machine Gun Kid" "Laser fence" \ + "Fire Trooper" "Fire ball" "Hind-D" "Event - Incoming tank shells" \ + "Event - Guards will switch shifts" "Coward Duck" "Unknown8" \ + "Shoot Gunner - Bullet" "Power Switch" "Event - Snake Gets Captured" \ + "Event - Access to building 2" "Bullet 1" "Soldier - Stationary Guard" \ + "POW" "Ellen" "Grey Fox" "Dr. Petrovich" "Laser Camera" "36" "Fake Dr. Petrovich" \ + "Unknown9" "Soldier - Silencer Guards" "Unknown11" "Bullet 2" \ + "Machine Gun Kid - Bullet" "Bullet 3" "Tank - Bullet" "Boomerang" "Zzz" \ + "Unknown13" "Unknown14" "Unknown15" "44" "45" "46" "47" "48" "49" "4A" \ + "4B" "4C" "4D" "4E" "4F" "50" "51" "52" "53" "54" "55" "56" "57" "58" \ + "59" "5A" "5B" "5C" "5D" "5E" "5F" "60" "61" "62" "63" "64" "65" "66" ] + +set_help_text toggle_metal_gear_overlay \ +"Shows OSD widgets that help you play Metal Gear. Only useful if you +are actually running this game... If you are not, you may get a lot of weird +stuff on your screen :) It mostly shows Snake and enemy properties on screen +and events that will happen." + +proc init {} { + variable num_enemies + variable max_hp + variable punch_max_hp + variable currentfield + variable map_feature_enabled + + #Create OSD elements + osd_widgets::msx_init metal_gear + + for {set i 0} {$i < $num_enemies} {incr i} { + osd_widgets::create_power_bar metal_gear.powerbar$i 16 2 0xff0080b0 0x00000080 0xffffffC0 + osd_widgets::create_power_bar metal_gear.punchbar$i 16 2 0x0080ffb0 0x00000080 0xffffffC0 + } + + osd_widgets::create_power_bar metal_gear.powerbarsnake 24 2 0x00ff00b0 0x00000080 0xffffffC0 + osd_widgets::create_power_bar metal_gear.boss 24 8 0x00ff00b0 0x00000080 0xffffffC0 + + for {set i 0} {$i < 256} {incr i} { + set max_hp($i) 0 + set punch_max_hp($i) 0 + } + + set currentfield 0 + + if {$map_feature_enabled} { + + for {set y 0} {$y < 16} {incr y} { + for {set x 0} {$x < 16} {incr x} { + set field [expr {$x + ($y * 16)}] + osd create rectangle metal_gear.field$field -x [expr {($x * 3) + 1}] -y [expr {($y * 3) + 1}] -relw 2 -relh 2 -rgba 0x0000ff80 + } + } + } + + #Start the overlay refresh + update_overlay +} + +proc update_overlay {} { + variable max_hp + variable punch_max_hp + variable num_enemies + variable enemy_names + variable currentfield + variable metal_gear_overlay_active + variable map_feature_enabled + + if {!$metal_gear_overlay_active} return + + # check for field change + if {$currentfield != [peek 0xC130]} { + set previousfield $currentfield + set currentfield [peek 0xC130] + + #clear out old HP values if field has changed + for {set i 0} {$i < $num_enemies} {incr i} { + set punch_max_hp($i) 0 + set max_hp($i) 0 + } + if {$map_feature_enabled} { + osd configure metal_gear.field$previousfield -rgba 0x00ff0080 + osd configure metal_gear.field$currentfield -rgba 0xffffff80 + } + } + + #check if not in demo or weapon/item screen + if {[peek 0xC012] == 0x00 || [peek 0xC012] == 0x47 || [peek 0xC012] == 0x50 || [peek 0xC151] != 0} { + osd configure metal_gear -y 999 + } else { + osd configure metal_gear -y 0 + } + + for {set i 0; set addr 0xD000} {$i < $num_enemies} {incr i; incr addr 0x80} { + set enemy_type [peek $addr] + set enemy_hp [expr {0 + [peek [expr {$addr + 0x0D}]]}] + set enemy_punch_hp [expr {3 - [peek [expr $addr + 0x7A]]}] + + if {$enemy_punch_hp > $punch_max_hp($i)} { + set punch_max_hp($i) $enemy_punch_hp + } + if {$enemy_hp > $max_hp($i)} { + set max_hp($i) $enemy_hp + } + + set pos_x [expr { 0 + [peek [expr {$addr + 5}]]}] + set pos_y [expr { 0 + [peek [expr {$addr + 3}]]}] + + if {$enemy_type > 0 && $enemy_hp > 0} { + set power [expr {1.00 * $enemy_hp / $max_hp($i)}] + set punch_power [expr {1.00 * $enemy_punch_hp / $punch_max_hp($i)}] + + set text "HP: $enemy_hp $i [lindex $enemy_names $enemy_type] - #$enemy_type" + osd_widgets::update_power_bar metal_gear.powerbar$i $pos_x $pos_y $power $text + + # only show the punch bar when the enemy can be punched + if {$enemy_punch_hp > 0} { + osd_widgets::update_power_bar metal_gear.punchbar$i $pos_x [expr {$pos_y + 5}] $punch_power "" + } else { + osd_widgets::update_power_bar metal_gear.punchbar$i -50 -50 0 "" + } + + } else { + osd_widgets::update_power_bar metal_gear.powerbar$i -50 -50 0 "" + osd_widgets::update_power_bar metal_gear.punchbar$i -50 -50 0 "" + } + } + + # get stats for snake + set snake_hp [peek 0xC131] + set power [expr {1.00 * $snake_hp / 48}] + set poisoned [peek 0xC139] + set pos_x [peek 0xC184] + set pos_y [peek 0xc182] + + if {$poisoned == 1} { + set power 0 + set text "POISONED ($pos_x,$pos_y) HP: $snake_hp" + } else { + set text "($pos_x,$pos_y) HP: $snake_hp" + } + + osd_widgets::update_power_bar metal_gear.powerbarsnake [expr {$pos_x - 13}] [expr {$pos_y + 20}] $power $text + + after frame [namespace code update_overlay] +} + +proc toggle_metal_gear_overlay {} { + variable metal_gear_overlay_active + + set metal_gear_overlay_active [expr {!$metal_gear_overlay_active}] + + if {$metal_gear_overlay_active} { + init + update_overlay + osd::display_message "Metal Gear overlay activated" info + return "Metal Gear overlay activated!" + } else { + set retval "" + osd destroy metal_gear + osd::display_message "Metal Gear overlay deactivated" info + return "Metal Gear overlay deactivated." + } +} + +namespace export toggle_metal_gear_overlay + +};# namespace metal_gear_overlay + +namespace import metal_gear_overlay::* diff --git a/share/scripts/lazy.tcl b/share/scripts/lazy.tcl index 42fd350..0629202 100644 --- a/share/scripts/lazy.tcl +++ b/share/scripts/lazy.tcl @@ -17,6 +17,7 @@ register_lazy "_example_tools.tcl" {get_screen listing get_color_count} register_lazy "_filepool.tcl" {filepool get_paths_for_type} register_lazy "_guess_title.tcl" {guess_title guess_rom_title} register_lazy "_info_panel.tcl" toggle_info_panel +register_lazy "_metal_gear_overlay.tcl" {toggle_metal_gear_overlay} register_lazy "_mog-overlay.tcl" {toggle_mog_overlay toggle_mog_editor} register_lazy "_monitor.tcl" monitor_type register_lazy "_multi_screenshot.tcl" multi_screenshot hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-04-22 19:55:43
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 580cade6ffe6311abd2f5a6b592a6369a61318ed (commit) from 22b0d61e7ad679473bdc06362e2cc8cd9fcc83c4 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 580cade6ffe6311abd2f5a6b592a6369a61318ed Author: m9710797 <ver...@gm...> Date: Wed Apr 22 21:51:08 2015 +0200 Enabled -Wdouble-promotion and fixed all warnings We already used this flag in the past (and fixed the warnings at that time). But it wasn't enabled in the default build because the flag is only available from gcc-4.6. We now require at least gcc-4.7, so we can permanently enable this warning. ----------------------------------------------------------------------- Summary of changes: build/main.mk | 3 +-- src/video/FBPostProcessor.cc | 14 +++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/build/main.mk b/build/main.mk index 9945af2..d0eae24 100644 --- a/build/main.mk +++ b/build/main.mk @@ -344,8 +344,7 @@ ifneq ($(filter %g++,$(CXX))$(filter g++%,$(CXX))$(findstring /g++-,$(CXX)),) # Enable C++11 COMPILE_FLAGS+=-std=gnu++0x # Stricter warning and error reporting. - COMPILE_FLAGS+=-Wall -Wextra -Wundef -Wunused-macros - # -Wdouble-promotion <-- this is useful, but only support from gcc-4.6 + COMPILE_FLAGS+=-Wall -Wextra -Wundef -Wunused-macros -Wdouble-promotion # Flag that is not accepted by old GCC versions. COMPILE_FLAGS+=$(shell \ echo | $(CXX) -E -Wno-missing-field-initializers - >/dev/null 2>&1 \ diff --git a/src/video/FBPostProcessor.cc b/src/video/FBPostProcessor.cc index 4fd905b..78836fc 100644 --- a/src/video/FBPostProcessor.cc +++ b/src/video/FBPostProcessor.cc @@ -32,13 +32,13 @@ void FBPostProcessor<Pixel>::preCalcNoise(float factor) { // We skip noise drawing if the factor is 0, so there is no point in // initializing the random data in that case. - if (factor == 0) return; + if (factor == 0.0f) return; // for 32bpp groups of 4 consecutive noiseBuf elements (starting at // 4 element boundaries) must have the same value. Later optimizations // depend on it. - double scale[4]; + float scale[4]; if (sizeof(Pixel) == 4) { // 32bpp // TODO ATM we compensate for big endian here. A better @@ -50,16 +50,16 @@ void FBPostProcessor<Pixel>::preCalcNoise(float factor) // TODO we can also fill the array with 'factor' and only set // 'alpha' to 0.0. But PixelOperations doesn't offer a simple // way to get the position of the alpha byte (yet). - scale[0] = scale[1] = scale[2] = scale[3] = 0.0; + scale[0] = scale[1] = scale[2] = scale[3] = 0.0f; scale[pixelOps.red (p)] = factor; scale[pixelOps.green(p)] = factor; scale[pixelOps.blue (p)] = factor; } else { // 16bpp - scale[0] = (pixelOps.getMaxRed() / 255.0) * factor; - scale[1] = (pixelOps.getMaxGreen() / 255.0) * factor; - scale[2] = (pixelOps.getMaxBlue() / 255.0) * factor; - scale[3] = 0.0; + scale[0] = (pixelOps.getMaxRed() / 255.0f) * factor; + scale[1] = (pixelOps.getMaxGreen() / 255.0f) * factor; + scale[2] = (pixelOps.getMaxBlue() / 255.0f) * factor; + scale[3] = 0.0f; } auto& generator = global_urng(); // fast (non-cryptographic) random numbers hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-04-22 18:22:03
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 22b0d61e7ad679473bdc06362e2cc8cd9fcc83c4 (commit) from 4735fd2ec8c84507b38ca6cbbf279026f413ed42 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 22b0d61e7ad679473bdc06362e2cc8cd9fcc83c4 Author: m9710797 <ver...@gm...> Date: Wed Apr 22 20:20:59 2015 +0200 Fix bug#572 function isAbsolutePath(path) don't work on Windows Thanks rogermmbr. ----------------------------------------------------------------------- Summary of changes: src/file/FileOperations.cc | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/src/file/FileOperations.cc b/src/file/FileOperations.cc index d51def9..88d9aea 100644 --- a/src/file/FileOperations.cc +++ b/src/file/FileOperations.cc @@ -468,7 +468,8 @@ string getAbsolutePath(string_ref path) bool isAbsolutePath(string_ref path) { #ifdef _WIN32 - if ((path.size() >= 3) && (path[1] == ':') && (path[2] == '/')) { + if ((path.size() >= 3) && (path[1] == ':') && + ((path[2] == '/') || (path[2] == '\\'))) { char drive = tolower(path[0]); if (('a' <= drive) && (drive <= 'z')) { return true; hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-04-15 18:07:58
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 4735fd2ec8c84507b38ca6cbbf279026f413ed42 (commit) from ef6393830ac755e41a7a6188965a9dc80c6e798b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 4735fd2ec8c84507b38ca6cbbf279026f413ed42 Author: m9710797 <ver...@gm...> Date: Wed Apr 15 20:05:08 2015 +0200 Partially revert previous patch It seems Android doesn't have the log2() function (even though it's mandated by C++11). exp2() does not give problems? Maybe in the future we can again revert this workaround. ----------------------------------------------------------------------- Summary of changes: src/sound/YM2151.cc | 3 ++- src/sound/YM2413Burczynski.cc | 3 ++- src/sound/YMF262.cc | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sound/YM2151.cc b/src/sound/YM2151.cc index 4c5c93e..6d51744 100644 --- a/src/sound/YM2151.cc +++ b/src/sound/YM2151.cc @@ -497,12 +497,13 @@ void YM2151::Impl::initTables() } } + static const double LOG2 = log(2.0); for (int i = 0; i < SIN_LEN; ++i) { // non-standard sinus double m = sin((i * 2 + 1) * M_PI / SIN_LEN); // verified on the real chip // we never reach zero here due to (i * 2 + 1) - double o = -8.0 * log2(std::abs(m)); // convert to decibels + double o = -8.0 * log(std::abs(m)) / LOG2; // convert to decibels o = o / (ENV_STEP / 4); int n = int(2.0 * o); diff --git a/src/sound/YM2413Burczynski.cc b/src/sound/YM2413Burczynski.cc index ac93bb7..34e0516 100644 --- a/src/sound/YM2413Burczynski.cc +++ b/src/sound/YM2413Burczynski.cc @@ -627,11 +627,12 @@ static void initTables() unsigned* full = &sin_tab[0 * SIN_LEN]; // waveform 0: standard sinus unsigned* half = &sin_tab[1 * SIN_LEN]; // waveform 1: positive part of sinus + static const double LOG2 = log(2.0); for (int i = 0; i < SIN_LEN / 4; ++i) { // checked on real hardware, see also // http://docs.google.com/Doc?id=dd8kqn9f_13cqjkf4gp double m = sin(((i * 2) + 1) * M_PI / SIN_LEN); - int n = int(round(log2(m) * -256.0)); + int n = int(round(log(m) / LOG2 * -256.0)); full[i] = half[i] = 2 * n; } for (int i = 0; i < SIN_LEN / 4; ++i) { diff --git a/src/sound/YMF262.cc b/src/sound/YMF262.cc index 88679de..04b1dae 100644 --- a/src/sound/YMF262.cc +++ b/src/sound/YMF262.cc @@ -1023,11 +1023,12 @@ void YMF262::Impl::init_tables() } } + static const double LOG2 = log(2.0); for (int i = 0; i < SIN_LEN; i++) { // non-standard sinus double m = sin(((i * 2) + 1) * M_PI / SIN_LEN); // checked against the real chip // we never reach zero here due to ((i * 2) + 1) - double o = -8.0 * log2(std::abs(m)); // convert to 'decibels' + double o = -8.0 * log(std::abs(m)) / LOG2; // convert to 'decibels' o = o / (ENV_STEP / 4); int n = int(2 * o); hooks/post-receive -- openMSX (main) |
From: Wouter V. <m97...@us...> - 2015-04-14 19:00:57
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via ef6393830ac755e41a7a6188965a9dc80c6e798b (commit) from 37f88ff768af8bf5b090fc185c32f0c569d422ef (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit ef6393830ac755e41a7a6188965a9dc80c6e798b Author: Wouter Vermaelen <ver...@gm...> Date: Mon Apr 13 16:00:09 2015 +0200 Use c++11 functions log2() and exp2() Replace log(x) / log(2) -> log2(x) pow(2, x) -> exp2(x) The functions log2() and exp2() are new in c++11 (copied from c99). They more directly specify the intent. (They may or may not execute faster and they may or may not yield a more numerically accurate result, but neither matters much in this context). Note that there is a log10() function in c++11 (we're already using it) but no exp10() function (it's part of glibc as an extension, it's not part of c++11). I've also simplified log(1 / x) -> -log(x) ----------------------------------------------------------------------- Summary of changes: src/sound/Y8950.cc | 6 +++--- src/sound/YM2151.cc | 9 ++------- src/sound/YM2413Burczynski.cc | 4 ++-- src/sound/YMF262.cc | 7 ++----- src/sound/YMF278.cc | 2 +- 5 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/sound/Y8950.cc b/src/sound/Y8950.cc index c549a05..a6114ab 100644 --- a/src/sound/Y8950.cc +++ b/src/sound/Y8950.cc @@ -270,7 +270,7 @@ static unsigned RA_ADJUST_TABLE[EG_MUTE + 1]; // Dynamic range static const int DB_BITS = 9; static const int DB_MUTE = 1 << DB_BITS; -// PM table is calcurated by PM_AMP * pow(2, PM_DEPTH * sin(x) / 1200) +// PM table is calcurated by PM_AMP * exp2(PM_DEPTH * sin(x) / 1200) static const int PM_AMP_BITS = 8; static const int PM_AMP = 1 << PM_AMP_BITS; @@ -466,8 +466,8 @@ static void makeSinTable() static void makePmTable() { for (int i = 0; i < PM_PG_WIDTH; ++i) { - pmtable[0][i] = int(double(PM_AMP) * pow(2, double(PM_DEPTH) * sin(2.0 * M_PI * i / PM_PG_WIDTH) / 1200)); - pmtable[1][i] = int(double(PM_AMP) * pow(2, double(PM_DEPTH2) * sin(2.0 * M_PI * i / PM_PG_WIDTH) / 1200)); + pmtable[0][i] = int(double(PM_AMP) * exp2(double(PM_DEPTH) * sin(2.0 * M_PI * i / PM_PG_WIDTH) / 1200)); + pmtable[1][i] = int(double(PM_AMP) * exp2(double(PM_DEPTH2) * sin(2.0 * M_PI * i / PM_PG_WIDTH) / 1200)); } } diff --git a/src/sound/YM2151.cc b/src/sound/YM2151.cc index 88d9875..4c5c93e 100644 --- a/src/sound/YM2151.cc +++ b/src/sound/YM2151.cc @@ -473,7 +473,7 @@ static byte lfo_noise_waveform[256] = { void YM2151::Impl::initTables() { for (int x = 0; x < TL_RES_LEN; ++x) { - double m = (1 << 16) / pow(2, (x + 1) * (ENV_STEP / 4.0) / 8.0); + double m = (1 << 16) / exp2((x + 1) * (ENV_STEP / 4.0) / 8.0); m = floor(m); // we never reach (1 << 16) here due to the (x + 1) @@ -502,12 +502,7 @@ void YM2151::Impl::initTables() double m = sin((i * 2 + 1) * M_PI / SIN_LEN); // verified on the real chip // we never reach zero here due to (i * 2 + 1) - double o; - if (m > 0.0) { // convert to decibels - o = 8 * log( 1.0 / m) / log(2.0); - } else { - o = 8 * log(-1.0 / m) / log(2.0); - } + double o = -8.0 * log2(std::abs(m)); // convert to decibels o = o / (ENV_STEP / 4); int n = int(2.0 * o); diff --git a/src/sound/YM2413Burczynski.cc b/src/sound/YM2413Burczynski.cc index 31e849b..ac93bb7 100644 --- a/src/sound/YM2413Burczynski.cc +++ b/src/sound/YM2413Burczynski.cc @@ -610,7 +610,7 @@ static void initTables() alreadyInit = true; for (int x = 0; x < TL_RES_LEN; ++x) { - double m = (1 << 16) / pow(2, (x + 1) * (ENV_STEP / 4.0) / 8.0); + double m = (1 << 16) / exp2((x + 1) * (ENV_STEP / 4.0) / 8.0); m = floor(m); // we never reach (1 << 16) here due to the (x + 1) @@ -631,7 +631,7 @@ static void initTables() // checked on real hardware, see also // http://docs.google.com/Doc?id=dd8kqn9f_13cqjkf4gp double m = sin(((i * 2) + 1) * M_PI / SIN_LEN); - int n = int(round(log(m) * (-256.0 / log(2.0)))); + int n = int(round(log2(m) * -256.0)); full[i] = half[i] = 2 * n; } for (int i = 0; i < SIN_LEN / 4; ++i) { diff --git a/src/sound/YMF262.cc b/src/sound/YMF262.cc index 1ed0957..88679de 100644 --- a/src/sound/YMF262.cc +++ b/src/sound/YMF262.cc @@ -1004,7 +1004,7 @@ void YMF262::Impl::init_tables() alreadyInit = true; for (int x = 0; x < TL_RES_LEN; x++) { - double m = (1 << 16) / pow(2, (x + 1) * (ENV_STEP / 4.0) / 8.0); + double m = (1 << 16) / exp2((x + 1) * (ENV_STEP / 4.0) / 8.0); m = floor(m); // we never reach (1<<16) here due to the (x+1) @@ -1023,14 +1023,11 @@ void YMF262::Impl::init_tables() } } - const double LOG2 = ::log(2.0); for (int i = 0; i < SIN_LEN; i++) { // non-standard sinus double m = sin(((i * 2) + 1) * M_PI / SIN_LEN); // checked against the real chip // we never reach zero here due to ((i * 2) + 1) - double o = (m > 0.0) ? - 8 * ::log( 1.0 / m) / LOG2: // convert to 'decibels' - 8 * ::log(-1.0 / m) / LOG2; // convert to 'decibels' + double o = -8.0 * log2(std::abs(m)); // convert to 'decibels' o = o / (ENV_STEP / 4); int n = int(2 * o); diff --git a/src/sound/YMF278.cc b/src/sound/YMF278.cc index 03223fe..06a05b3 100644 --- a/src/sound/YMF278.cc +++ b/src/sound/YMF278.cc @@ -906,7 +906,7 @@ YMF278::Impl::Impl(YMF278& self, const std::string& name, int ramSize, // Volume table, 1 = -0.375dB, 8 = -3dB, 256 = -96dB for (int i = 0; i < 256; ++i) { - volume[i] = int(32768.0 * pow(2.0, (-0.375 / 6) * i)); + volume[i] = int(32768.0 * exp2((-0.375 / 6) * i)); } for (int i = 256; i < 256 * 4; ++i) { volume[i] = 0; hooks/post-receive -- openMSX (main) |
From: Patrick v. A. <va...@us...> - 2015-03-29 06:19:53
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 37f88ff768af8bf5b090fc185c32f0c569d422ef (commit) from b3abc9775aaf0706e6ca54f7ef2b133a6f1fd288 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 37f88ff768af8bf5b090fc185c32f0c569d422ef Author: Patrick van Arkel <vam...@us...> Date: Sat Mar 28 23:19:43 2015 -0700 romdb update ----------------------------------------------------------------------- Summary of changes: share/softwaredb.xml | 30 ++++++++++++++++++++---------- 1 files changed, 20 insertions(+), 10 deletions(-) diff --git a/share/softwaredb.xml b/share/softwaredb.xml index 3439177..b7cc6e7 100644 --- a/share/softwaredb.xml +++ b/share/softwaredb.xml @@ -1,13 +1,13 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE softwaredb SYSTEM "softwaredb1.dtd"> -<softwaredb timestamp="1416080566"> +<softwaredb timestamp="1427609756"> <!-- Credits --> <![CDATA[ The softwaredb.xml file contains information about rom mapper types Copyright 2003 Nicolas Beyaert (Initial Database) Copyright 2004-2013 BlueMSX Team -Copyright 2005-2014 openMSX Team +Copyright 2005-2015 openMSX Team Generation MSXIDs by www.generation-msx.nl ]]> @@ -4610,6 +4610,14 @@ Generation MSXIDs by www.generation-msx.nl <dump><original value="true">GoodMSX</original><rom><hash>f2ec3714138175212b6b6e28b5da4361cc4b5471</hash></rom></dump> </software> <software> + <title>Gunsmoke</title> + <system>MSX</system> + <company>Prosoft</company> + <year>1990</year> + <country>KR</country> + <dump><rom><hash>b27aef37ab7327e12a8d4460b89af391d3789961</hash></rom></dump> +</software> +<software> <title>Guru Logic</title> <system>MSX</system> <company>Karoshi Corporation</company> @@ -4948,18 +4956,20 @@ Generation MSXIDs by www.generation-msx.nl <year>1987</year> <country>JP</country> <dump><megarom><type>ASCII8</type><hash>fed52c0455ce1e7cef80cd144c3d0ef3636134e5</hash><remark>[RC-747]</remark></megarom></dump> - <dump><original value="true">GoodMSX</original><megarom><type>Konami</type><hash>d723f2eb1c887db5448fd56be5e7c57e60d88e63</hash><remark>[a1][RC-747]</remark></megarom></dump> + <dump><original value="true">GoodMSX</original><megarom><type>Konami</type><hash>d723f2eb1c887db5448fd56be5e7c57e60d88e63</hash><remark>[RC-747] / [a1]</remark></megarom></dump> <dump><original value="true">GoodMSX</original><megarom><type>Konami</type><hash>612c18616bc800d9eb69b9da3cd29eca31f50c1c</hash><remark>[RC-747]</remark></megarom></dump> <dump><megarom><type>Konami</type><hash>300f20adde3941ab10eb158db48250e8e856a911</hash><remark>[RC-747]</remark></megarom></dump> <dump><megarom><type>Konami</type><hash>875bbb27f6a54e5d123dc8a6df4bf46f97c23a57</hash><remark>[RC-747]</remark></megarom></dump> <dump><megarom><type>ASCII8</type><hash>45760316a4ebc74ddd55ee163c5aeaaafe965d2c</hash><remark>[RC-747] / Vampier cheat</remark></megarom></dump> <dump><megarom><type>Konami</type><hash>7e5024e6e6aecd05ec6c885786a4aac287ed110b</hash><remark>[RC-747] / Ulver crack</remark></megarom></dump> <dump><megarom><type>Konami</type><hash>357c0c2e9b3b2970c587c96f86a6b7272160f54a</hash><remark>[RC-747]</remark></megarom></dump> - <dump><megarom><type>Konami</type><hash>45c108f04c1abd12bfa5d2222e578bda6ef54c39</hash></megarom></dump> - <dump><megarom><type>Konami</type><hash>0329a79f82f67f3799124f3539eccaaa37adca08</hash></megarom></dump> - <dump><megarom><type>Konami</type><hash>a0a49baa3755dfeddb993f978efd2fdb7d1e2c79</hash></megarom></dump> - <dump><megarom><type>Konami</type><hash>d37d24f73b1f819b676bcbf97217cdb39c9d8916</hash></megarom></dump> - <dump><megarom><type>Konami</type><hash>ed67e8266c152f3020543fb5b3061c9a57a3ca1f</hash></megarom></dump> + <dump><megarom><type>Konami</type><hash>45c108f04c1abd12bfa5d2222e578bda6ef54c39</hash><remark>[RC-747]</remark></megarom></dump> + <dump><megarom><type>Konami</type><hash>0329a79f82f67f3799124f3539eccaaa37adca08</hash><remark>[RC-747]</remark></megarom></dump> + <dump><megarom><type>Konami</type><hash>a0a49baa3755dfeddb993f978efd2fdb7d1e2c79</hash><remark>[RC-747]</remark></megarom></dump> + <dump><megarom><type>Konami</type><hash>d37d24f73b1f819b676bcbf97217cdb39c9d8916</hash><remark>[RC-747]</remark></megarom></dump> + <dump><megarom><type>Konami</type><hash>ed67e8266c152f3020543fb5b3061c9a57a3ca1f</hash><remark>[RC-747]</remark></megarom></dump> + <dump><original value="false">translated</original><megarom><type>Konami</type><hash>7b0b379c6f46552a6f5a0408b8182e8e79540f7f</hash><remark>[RC-747]</remark></megarom></dump> + <dump><original value="false">translated</original><megarom><type>Konami</type><hash>581eac8e476e2c95aae88befddef1ff3dc81c872</hash><remark>[RC-747] / fully patched (Turbo and speed fix)</remark></megarom></dump> </software> <software> <title>Hisha</title> @@ -12924,6 +12934,6 @@ Generation MSXIDs by www.generation-msx.nl </software> </softwaredb> <!-- -Roms in this XML file:3227 -Created on Sat Nov 15 20:42:56 CET 2014 +Roms in this XML file:3230 +Created on Sun Mar 29 8:16:09 CEST 2015 --> \ No newline at end of file hooks/post-receive -- openMSX (main) |
From: Manuel B. <man...@us...> - 2015-03-24 22:26:30
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via b3abc9775aaf0706e6ca54f7ef2b133a6f1fd288 (commit) from 4678b7e8608643e8cdfc59fd4b886af34a8b5cbb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b3abc9775aaf0706e6ca54f7ef2b133a6f1fd288 Author: Manuel Bilderbeek <Man...@gm...> Date: Tue Mar 24 23:26:01 2015 +0100 Make cashandler more robust against setting the hack multiple times ----------------------------------------------------------------------- Summary of changes: share/scripts/cashandler.tcl | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/share/scripts/cashandler.tcl b/share/scripts/cashandler.tcl index 188e013..1efe7c8 100644 --- a/share/scripts/cashandler.tcl +++ b/share/scripts/cashandler.tcl @@ -9,21 +9,25 @@ works when inserting cassettes when the MSX is already started up, not when inserting them via the openMSX command line." false variable old_value $::fast_cas_load_hack_enabled +variable hack_is_already_enabled false proc set_hack {} { + variable hack_is_already_enabled # example: turboR.. # for now, ignore the commands... it's quite complex to # get this 100% water tight with adding/removing machines # at run time if {[catch "machine_info connector cassetteport"]} return - if {$::fast_cas_load_hack_enabled} { + if {$::fast_cas_load_hack_enabled && !$hack_is_already_enabled} { interp hide {} cassetteplayer interp alias {} cassetteplayer {} cashandler::tapedeck + set hack_is_already_enabled true puts "Fast cas load hack installed." - } else { + } elseif {!$::fast_cas_load_hack_enabled && $hack_is_already_enabled} { interp alias {} cassetteplayer {} interp expose {} cassetteplayer + set hack_is_already_enabled false puts "Fast cas load hack uninstalled." } } hooks/post-receive -- openMSX (main) |
From: Manuel B. <man...@us...> - 2015-03-24 22:12:34
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "openMSX (main)". The branch, master has been updated via 4678b7e8608643e8cdfc59fd4b886af34a8b5cbb (commit) from b23cc74ab876e2ea51efc7e0fd0a3d1a97bbaaf3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 4678b7e8608643e8cdfc59fd4b886af34a8b5cbb Author: Manuel Bilderbeek <Man...@gm...> Date: Tue Mar 24 23:12:18 2015 +0100 Document auto_save_replay setting ----------------------------------------------------------------------- Summary of changes: doc/manual/commands.html | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/doc/manual/commands.html b/doc/manual/commands.html index dd4b891..9587dbd 100644 --- a/doc/manual/commands.html +++ b/doc/manual/commands.html @@ -88,6 +88,7 @@ <li><a class="internal" href="#autoruncassettes">autoruncassettes</a></li> <li><a class="internal" href="#autorunlaserdisc">autorunlaserdisc</a></li> <li><a class="internal" href="#auto_enable_reverse">auto_enable_reverse</a></li> + <li><a class="internal" href="#auto_save_replay">auto_save_replay</a></li> <li><a class="internal" href="#blur">blur</a></li> <li><a class="internal" href="#bootsector">bootsector</a></li> <li><a class="internal" href="#brightness">brightness</a></li> @@ -2733,6 +2734,11 @@ <td>Enable the reverse feature and the reverse bar when openMSX starts</td> </tr> </table> + + <h3><a id="auto_save_replay">auto_save_replay</a></h3> + + <p>Enable this setting to make automatic backups of your current replay. The replay is saved to the filename specified in the <code>auto_save_replay_filename</code> setting (default: "auto_save") at an interval as specified by the <code>auto_save_replay_interval</code> setting (default: 30 seconds). The interval is in real clock time, not in MSX time.</p> + <h3><a id="blur">blur</a></h3> <p>Sets the amount of horizontal blur effect. A value of 0 turns off blur, while 100 selects maximum blur.</p> hooks/post-receive -- openMSX (main) |