mirror of https://github.com/stella-emu/stella.git
...and the usual missing new files
This commit is contained in:
parent
3de6002c46
commit
4633f4e394
|
@ -0,0 +1,148 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// SSSS tt lll lll
|
||||||
|
// SS SS tt ll ll
|
||||||
|
// SS tttttt eeee ll ll aaaa
|
||||||
|
// SSSS tt ee ee ll ll aa
|
||||||
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||||
|
// SS SS tt ee ll ll aa aa
|
||||||
|
// SSSS ttt eeeee llll llll aaaaa
|
||||||
|
//
|
||||||
|
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||||
|
// and the Stella Team
|
||||||
|
//
|
||||||
|
// See the file "License.txt" for information on usage and redistribution of
|
||||||
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
#include "TimerMap.hxx"
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODOs:
|
||||||
|
x unordered_multimap (not required for just a few timers)
|
||||||
|
o 13 vs 16 bit, use ADDRESS_MASK & ANY_BANK, when???
|
||||||
|
? timer line display in disassembly? (color, symbol,...?)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
uInt32 TimerMap::add(const uInt16 fromAddr, const uInt16 toAddr,
|
||||||
|
const uInt8 fromBank, const uInt8 toBank)
|
||||||
|
{
|
||||||
|
const TimerPoint tpFrom(fromAddr, fromBank);
|
||||||
|
const TimerPoint tpTo(toAddr, toBank);
|
||||||
|
const Timer complete(tpFrom, tpTo);
|
||||||
|
|
||||||
|
myList.push_back(complete);
|
||||||
|
myFromMap.insert(TimerPair(tpFrom, &myList.back()));
|
||||||
|
myToMap.insert(TimerPair(tpTo, &myList.back()));
|
||||||
|
|
||||||
|
return size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
uInt32 TimerMap::add(const uInt16 addr, const uInt8 bank)
|
||||||
|
{
|
||||||
|
const uInt32 idx = size() - 1;
|
||||||
|
const bool isPartialTimer = size() && get(idx).isPartial;
|
||||||
|
const TimerPoint tp(addr, bank);
|
||||||
|
|
||||||
|
if(!isPartialTimer)
|
||||||
|
{
|
||||||
|
const Timer partial(tp);
|
||||||
|
|
||||||
|
myList.push_back(partial);
|
||||||
|
myFromMap.insert(TimerPair(tp, &myList.back()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Timer& partial = myList[idx];
|
||||||
|
|
||||||
|
partial.setTo(tp);
|
||||||
|
myToMap.insert(TimerPair(tp, &partial));
|
||||||
|
}
|
||||||
|
return size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool TimerMap::erase(const uInt32 idx)
|
||||||
|
{
|
||||||
|
if(size() > idx)
|
||||||
|
{
|
||||||
|
const Timer* timer = &myList[idx];
|
||||||
|
const TimerPoint tpFrom(timer->from);
|
||||||
|
const TimerPoint tpTo(timer->to);
|
||||||
|
|
||||||
|
// Find address in from and to maps, TODO what happens if not found???
|
||||||
|
const auto from = myFromMap.equal_range(tpFrom);
|
||||||
|
for(auto it = from.first; it != from.second; ++it)
|
||||||
|
if(it->second == timer)
|
||||||
|
{
|
||||||
|
myFromMap.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto to = myToMap.equal_range(tpTo);
|
||||||
|
for(auto it = to.first; it != to.second; ++it)
|
||||||
|
if(it->second == timer)
|
||||||
|
{
|
||||||
|
myToMap.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally remove from list
|
||||||
|
myList.erase(myList.begin() + idx);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void TimerMap::clear()
|
||||||
|
{
|
||||||
|
myList.clear();
|
||||||
|
myFromMap.clear();
|
||||||
|
myToMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void TimerMap::reset()
|
||||||
|
{
|
||||||
|
for(auto it = myList.begin(); it != myList.end(); ++it)
|
||||||
|
it->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void TimerMap::update(const uInt16 addr, const uInt8 bank,
|
||||||
|
const uInt64 cycles)
|
||||||
|
{
|
||||||
|
// 13 bit timerpoint
|
||||||
|
if((addr & ADDRESS_MASK) != addr)
|
||||||
|
{
|
||||||
|
TimerPoint tp(addr, bank); // -> addr & ADDRESS_MASK
|
||||||
|
|
||||||
|
// Find address in from and to maps
|
||||||
|
const auto from = myFromMap.equal_range(tp);
|
||||||
|
for(auto it = from.first; it != from.second; ++it)
|
||||||
|
if(!it->second->isPartial)
|
||||||
|
it->second->start(cycles);
|
||||||
|
|
||||||
|
const auto to = myToMap.equal_range(tp);
|
||||||
|
for(auto it = to.first; it != to.second; ++it)
|
||||||
|
if(!it->second->isPartial)
|
||||||
|
it->second->stop(cycles);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 16 bit timerpoint
|
||||||
|
TimerPoint tp(addr, bank, false); // -> addr
|
||||||
|
|
||||||
|
// Find address in from and to maps
|
||||||
|
const auto from = myFromMap.equal_range(tp);
|
||||||
|
for(auto it = from.first; it != from.second; ++it)
|
||||||
|
if(!it->second->isPartial)
|
||||||
|
it->second->start(cycles);
|
||||||
|
|
||||||
|
const auto to = myToMap.equal_range(tp);
|
||||||
|
for(auto it = to.first; it != to.second; ++it)
|
||||||
|
if(!it->second->isPartial)
|
||||||
|
it->second->stop(cycles);
|
||||||
|
}
|
|
@ -0,0 +1,249 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// SSSS tt lll lll
|
||||||
|
// SS SS tt ll ll
|
||||||
|
// SS tttttt eeee ll ll aaaa
|
||||||
|
// SSSS tt ee ee ll ll aa
|
||||||
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||||
|
// SS SS tt ee ll ll aa aa
|
||||||
|
// SSSS ttt eeeee llll llll aaaaa
|
||||||
|
//
|
||||||
|
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||||
|
// and the Stella Team
|
||||||
|
//
|
||||||
|
// See the file "License.txt" for information on usage and redistribution of
|
||||||
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
#ifndef TIMER_MAP_HXX
|
||||||
|
#define TIMER_MAP_HXX
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#include "bspf.hxx"
|
||||||
|
|
||||||
|
/**
|
||||||
|
This class handles debugger timers. Each timer needs a 'from' and a 'to'
|
||||||
|
address.
|
||||||
|
|
||||||
|
@author Thomas Jentzsch
|
||||||
|
*/
|
||||||
|
class TimerMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr uInt8 ANY_BANK = 255; // timer breakpoint valid in any bank
|
||||||
|
|
||||||
|
//private:
|
||||||
|
static constexpr uInt16 ADDRESS_MASK = 0x1fff; // either 0x1fff or 0xffff (not needed then)
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct TimerPoint
|
||||||
|
{
|
||||||
|
uInt16 addr{0};
|
||||||
|
uInt8 bank{ANY_BANK};
|
||||||
|
|
||||||
|
explicit constexpr TimerPoint(uInt16 c_addr, uInt8 c_bank, bool mask = true)
|
||||||
|
: addr{c_addr}, bank{c_bank}
|
||||||
|
{
|
||||||
|
if(mask && bank != ANY_BANK)
|
||||||
|
addr = addr & ADDRESS_MASK;
|
||||||
|
}
|
||||||
|
TimerPoint()
|
||||||
|
: addr{0}, bank(ANY_BANK) {}
|
||||||
|
|
||||||
|
#if 0 // unused
|
||||||
|
bool operator==(const TimerPoint& other) const
|
||||||
|
{
|
||||||
|
if(addr == other.addr)
|
||||||
|
{
|
||||||
|
if(bank == ANY_BANK || other.bank == ANY_BANK)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return bank == other.bank;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool operator<(const TimerPoint& other) const
|
||||||
|
{
|
||||||
|
if(bank == ANY_BANK || other.bank == ANY_BANK)
|
||||||
|
return addr < other.addr;
|
||||||
|
|
||||||
|
return bank < other.bank || (bank == other.bank && addr < other.addr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct Timer
|
||||||
|
{
|
||||||
|
TimerPoint from{};
|
||||||
|
TimerPoint to{};
|
||||||
|
bool isPartial{false};
|
||||||
|
|
||||||
|
uInt64 execs{0};
|
||||||
|
uInt64 lastCycles{0};
|
||||||
|
uInt64 totalCycles{0};
|
||||||
|
uInt64 minCycles{ULONG_MAX};
|
||||||
|
uInt64 maxCycles{0};
|
||||||
|
bool isStarted{false};
|
||||||
|
|
||||||
|
explicit constexpr Timer(const TimerPoint& c_from, const TimerPoint& c_to)
|
||||||
|
: from{c_from}, to{c_to}
|
||||||
|
{
|
||||||
|
//if(to.bank == ANY_BANK) // TODO: check if this is required
|
||||||
|
//{
|
||||||
|
// to.bank = from.bank;
|
||||||
|
// if(to.bank != ANY_BANK)
|
||||||
|
// to.addr &= ADDRESS_MASK;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer(uInt16 fromAddr, uInt16 toAddr, uInt8 fromBank, uInt8 toBank)
|
||||||
|
{
|
||||||
|
Timer(TimerPoint(fromAddr, fromBank), TimerPoint(fromAddr, fromBank));
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer(const TimerPoint& tp)
|
||||||
|
{
|
||||||
|
if(!isPartial)
|
||||||
|
{
|
||||||
|
from = tp;
|
||||||
|
isPartial = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
to = tp;
|
||||||
|
isPartial = false;
|
||||||
|
|
||||||
|
//if(to.bank == ANY_BANK) // TODO: check if this is required
|
||||||
|
//{
|
||||||
|
// to.bank = from.bank;
|
||||||
|
// if(to.bank != ANY_BANK)
|
||||||
|
// to.addr &= ADDRESS_MASK;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer(uInt16 addr, uInt8 bank)
|
||||||
|
{
|
||||||
|
Timer(TimerPoint(addr, bank));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 // unused
|
||||||
|
bool operator==(const Timer& other) const
|
||||||
|
{
|
||||||
|
cerr << from.addr << ", " << to.addr << endl;
|
||||||
|
if(from.addr == other.from.addr && to.addr == other.to.addr)
|
||||||
|
{
|
||||||
|
if((from.bank == ANY_BANK || other.from.bank == ANY_BANK) &&
|
||||||
|
(to.bank == ANY_BANK || other.to.bank == ANY_BANK))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return from.bank == other.from.bank && to.bank == other.to.bank;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const Timer& other) const
|
||||||
|
{
|
||||||
|
if(from.bank < other.from.bank || (from.bank == other.from.bank && from.addr < other.from.addr))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(from.bank == other.from.bank && from.addr == other.from.addr)
|
||||||
|
return to.bank < other.to.bank || (to.bank == other.to.bank && to.addr < other.to.addr);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setTo(const TimerPoint& tp)
|
||||||
|
{
|
||||||
|
to = tp;
|
||||||
|
isPartial = false;
|
||||||
|
|
||||||
|
//if(to.bank == ANY_BANK) // TODO: check if this is required
|
||||||
|
//{
|
||||||
|
// to.bank = from.bank;
|
||||||
|
// if(to.bank != ANY_BANK)
|
||||||
|
// to.addr &= ADDRESS_MASK;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
execs = lastCycles = totalCycles = maxCycles = 0;
|
||||||
|
minCycles = ULONG_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the timer
|
||||||
|
void start(uInt64 cycles)
|
||||||
|
{
|
||||||
|
lastCycles = cycles;
|
||||||
|
isStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the timer and update stats
|
||||||
|
void stop(uInt64 cycles)
|
||||||
|
{
|
||||||
|
if(isStarted)
|
||||||
|
{
|
||||||
|
const uInt64 diffCycles = cycles - lastCycles;
|
||||||
|
|
||||||
|
++execs;
|
||||||
|
totalCycles += diffCycles;
|
||||||
|
minCycles = std::min(minCycles, diffCycles);
|
||||||
|
maxCycles = std::max(maxCycles, diffCycles);
|
||||||
|
isStarted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uInt32 averageCycles() const {
|
||||||
|
return execs ? std::round(totalCycles / execs) : 0; }
|
||||||
|
}; // Timer
|
||||||
|
|
||||||
|
explicit TimerMap() = default;
|
||||||
|
|
||||||
|
bool isInitialized() const { return myList.size(); }
|
||||||
|
|
||||||
|
/** Add new timer */
|
||||||
|
uInt32 add(const uInt16 fromAddr, const uInt16 toAddr,
|
||||||
|
const uInt8 fromBank, const uInt8 toBank);
|
||||||
|
uInt32 add(const uInt16 addr, const uInt8 bank);
|
||||||
|
|
||||||
|
/** Erase timer */
|
||||||
|
bool erase(const uInt32 idx);
|
||||||
|
|
||||||
|
/** Clear all timers */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/** Reset all timers */
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/** Get timer */
|
||||||
|
const Timer& get(const uInt32 idx) const { return myList[idx]; };
|
||||||
|
uInt32 size() const { return static_cast<uInt32>(myList.size()); }
|
||||||
|
|
||||||
|
/** Update timer */
|
||||||
|
void update(const uInt16 addr, const uInt8 bank,
|
||||||
|
const uInt64 cycles);
|
||||||
|
|
||||||
|
private:
|
||||||
|
using TimerList = std::deque<Timer>; // makes sure that the element pointers do NOT change
|
||||||
|
using TimerPair = std::pair<TimerPoint, Timer*>;
|
||||||
|
using FromMap = std::multimap<TimerPoint, Timer*>;
|
||||||
|
using ToMap = std::multimap<TimerPoint, Timer*>;
|
||||||
|
|
||||||
|
TimerList myList;
|
||||||
|
FromMap myFromMap;
|
||||||
|
ToMap myToMap;
|
||||||
|
|
||||||
|
// Following constructors and assignment operators not supported
|
||||||
|
TimerMap(const TimerMap&) = delete;
|
||||||
|
TimerMap(TimerMap&&) = delete;
|
||||||
|
TimerMap& operator=(const TimerMap&) = delete;
|
||||||
|
TimerMap& operator=(TimerMap&&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue