mirror of
https://github.com/stella-emu/stella.git
synced 2026-10-11 22:29:55 +00:00
Merge branch 'master' into feature/resizable-ui
This commit is contained in:
+3
-6
@@ -24,7 +24,7 @@ include:
|
||||
|
||||
# Linux ARM 64-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/linux-arm64.yml'
|
||||
file: '/linux-aarch64.yml'
|
||||
|
||||
# MacOS 64-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
@@ -90,14 +90,11 @@ libretro-build-linux-x64:
|
||||
CXXFLAGS: -Wno-deprecated-declarations # Deprecation warnings aren't helpful on the libretro Gitlab
|
||||
|
||||
# Linux ARM 64-bit
|
||||
libretro-build-linux-arm64:
|
||||
libretro-build-linux-aarch64:
|
||||
extends:
|
||||
- .libretro-linux-arm64-make-default
|
||||
- .libretro-linux-aarch64-make-default
|
||||
- .core-defs
|
||||
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-arm64-ubuntu:backports
|
||||
variables:
|
||||
CC: /usr/bin/gcc-12
|
||||
CXX: /usr/bin/g++-12
|
||||
CXXFLAGS: -Wno-deprecated-declarations # Deprecation warnings aren't helpful on the libretro Gitlab
|
||||
|
||||
# MacOS 64-bit
|
||||
|
||||
@@ -13,7 +13,6 @@ Uses a custom shell configure script + GNU Make (not CMake or autotools).
|
||||
```bash
|
||||
./configure # First-time setup; generates config.mak
|
||||
make -j$(nproc) # Build main stella executable (output: out/stella)
|
||||
make test # Build and run unit tests (Google Test, output: out.test/stella-test)
|
||||
make clean # Remove object files
|
||||
make distclean # Remove object files + config.mak
|
||||
make DEBUG=1 # Debug build with symbols and _GLIBCXX_DEBUG
|
||||
|
||||
@@ -81,7 +81,7 @@ void JPGLibrary::loadImage(string_view filename, FBSurface& surface,
|
||||
const auto width = static_cast<uInt32>(njGetWidth());
|
||||
const auto height = static_cast<uInt32>(njGetHeight());
|
||||
const bool isColor = njIsColor() != 0;
|
||||
const auto bytesPerPixel = isColor ? 3uz : 1uz;
|
||||
const auto bytesPerPixel = isColor ? 3UZ : 1UZ;
|
||||
|
||||
// njGetImage() points into nanojpeg's internal buffer — no extra copy needed
|
||||
const ByteSpan pixels{ njGetImage(),
|
||||
|
||||
@@ -79,8 +79,8 @@ void Logger::logMessage(string_view message, Level level)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Logger::setLogParameters(int logLevel, bool logToConsole)
|
||||
{
|
||||
if (logLevel >= std::to_underlying(Level::MIN) &&
|
||||
logLevel <= std::to_underlying(Level::MAX))
|
||||
if (std::cmp_greater_equal(logLevel, std::to_underlying(Level::MIN)) &&
|
||||
std::cmp_less_equal(logLevel, std::to_underlying(Level::MAX)))
|
||||
{
|
||||
myLogLevel = logLevel;
|
||||
myLogToConsole = logToConsole;
|
||||
|
||||
@@ -894,7 +894,7 @@ void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value)
|
||||
{
|
||||
const bool isLeft = (j->type == LEFT_STELLADAPTOR ||
|
||||
j->type == LEFT_2600DAPTOR);
|
||||
const auto port = isLeft ? 0uz : 1uz;
|
||||
const auto port = isLeft ? 0UZ : 1UZ;
|
||||
const auto& ctrl = isLeft ? myOSystem.console().leftController()
|
||||
: myOSystem.console().rightController();
|
||||
if(myOSystem.hasConsole() && ctrl.type() == Controller::Type::Driving)
|
||||
|
||||
@@ -174,7 +174,7 @@ class PhysicalJoystickHandler
|
||||
friend std::ostream& operator<<(std::ostream& os, const PhysicalJoystickHandler& jh);
|
||||
|
||||
static constexpr JoyDir convertAxisValue(int value) {
|
||||
return value == std::to_underlying(JoyDir::NONE)
|
||||
return std::cmp_equal(value, std::to_underlying(JoyDir::NONE))
|
||||
? JoyDir::NONE
|
||||
: value > 0 ? JoyDir::POS : JoyDir::NEG;
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ void PNGLibrary::loadImage(string_view filename, FBSurface& surface,
|
||||
|
||||
// And read directly into the surface buffer
|
||||
auto* row = reinterpret_cast<png_bytep>(base);
|
||||
for(auto y = 0uz; y < height; ++y, row += rowStride)
|
||||
for(auto y = 0UZ; y < height; ++y, row += rowStride)
|
||||
png_read_row(png_ptr, reinterpret_cast<png_bytep>(row), nullptr);
|
||||
|
||||
// We're finished reading
|
||||
@@ -258,7 +258,7 @@ void PNGLibrary::saveImage(string_view filename, const FBSurface& surface,
|
||||
+ srcRect.y() * rowStride
|
||||
+ srcRect.x() * sizeof(uInt32);
|
||||
|
||||
for(auto y = 0uz; y < height; ++y, row += rowStride)
|
||||
for(auto y = 0UZ; y < height; ++y, row += rowStride)
|
||||
png_write_row(png_ptr, reinterpret_cast<png_bytep>(row));
|
||||
|
||||
// We're finished writing
|
||||
@@ -464,7 +464,7 @@ void PNGLibrary::writeMetaData(png_structp png_ptr, png_infop info_ptr,
|
||||
return;
|
||||
|
||||
std::vector<png_text> text_ptr(numMetaData);
|
||||
for(auto i = 0uz; i < numMetaData; ++i)
|
||||
for(auto i = 0UZ; i < numMetaData; ++i)
|
||||
{
|
||||
text_ptr[i].key = const_cast<char*>(metaData[i].first.c_str());
|
||||
text_ptr[i].text = const_cast<char*>(metaData[i].second.toCString());
|
||||
|
||||
@@ -370,7 +370,7 @@ PaletteArray PaletteHandler::adjustedPalette(const PaletteArray& palette) const
|
||||
adjust[i] = powf(i * toFloat, gamma) * contrast + brightness;
|
||||
|
||||
// Transform original palette into destination palette
|
||||
for(auto i = 0uz; i < destPalette.size(); i += 2)
|
||||
for(auto i = 0UZ; i < destPalette.size(); i += 2)
|
||||
{
|
||||
const uInt32 pixel = palette[i];
|
||||
int r = (pixel >> 16) & 0xff;
|
||||
|
||||
@@ -359,7 +359,7 @@ string RewindManager::getUnitString(Int64 cycles)
|
||||
|
||||
const uInt64 u_cycles = std::abs(cycles);
|
||||
|
||||
auto i = 0uz;
|
||||
auto i = 0UZ;
|
||||
for(i = 0; i < UNIT_NAMES.size() - 1; ++i)
|
||||
{
|
||||
// use the lower unit up to twice the nextCycles unit, except for an exact match of the nextCycles unit
|
||||
|
||||
@@ -39,7 +39,7 @@ class StateManager
|
||||
// MovieRecord,
|
||||
// MoviePlayback
|
||||
};
|
||||
static constexpr string_view STATE_HEADER = "07000003state";
|
||||
static constexpr string_view STATE_HEADER = "07000004state";
|
||||
|
||||
/**
|
||||
Create a new statemananger class.
|
||||
|
||||
@@ -68,7 +68,7 @@ class StringParser
|
||||
|
||||
void parseLines()
|
||||
{
|
||||
auto start = 0uz;
|
||||
auto start = 0UZ;
|
||||
const size_t n = myBuffer.size();
|
||||
|
||||
while(start < n)
|
||||
@@ -84,7 +84,7 @@ class StringParser
|
||||
|
||||
void parseWrapped(size_t maxlen)
|
||||
{
|
||||
auto start = 0uz;
|
||||
auto start = 0UZ;
|
||||
const size_t n = myBuffer.size();
|
||||
|
||||
while(start < n)
|
||||
@@ -100,7 +100,7 @@ class StringParser
|
||||
|
||||
void wrapLine(string_view line, size_t maxlen)
|
||||
{
|
||||
auto beg = 0uz;
|
||||
auto beg = 0UZ;
|
||||
|
||||
while(beg < line.size())
|
||||
{
|
||||
|
||||
@@ -218,7 +218,7 @@ void ZipHandler::ZipFile::initialize()
|
||||
myHeaders.clear();
|
||||
myHeaders.reserve(myEcd.cdTotalEntries);
|
||||
|
||||
auto pos = 0uz;
|
||||
auto pos = 0UZ;
|
||||
while(pos < myCd.size())
|
||||
{
|
||||
// Ensure the fixed-size part of the entry header lies within the central
|
||||
@@ -350,7 +350,7 @@ void ZipHandler::ZipFile::ensureIndex() const
|
||||
|
||||
myHeaderIndex.reserve(myHeaders.size());
|
||||
|
||||
for(auto i = 0uz; i < myHeaders.size(); ++i)
|
||||
for(auto i = 0UZ; i < myHeaders.size(); ++i)
|
||||
myHeaderIndex.emplace(myHeaders[i].filename, i);
|
||||
|
||||
myIndexBuilt = true;
|
||||
|
||||
@@ -138,7 +138,7 @@ void LanczosResampler::fillFragment(float* fragment, uInt32 length)
|
||||
const bool stereoOut = myFormatTo.stereo;
|
||||
const size_t outputSamples = stereoOut ? (length >> 1) : length;
|
||||
|
||||
for (auto i = 0uz; i < outputSamples; ++i) {
|
||||
for (auto i = 0UZ; i < outputSamples; ++i) {
|
||||
const float* kernel = myPrecomputedKernels.get() +
|
||||
static_cast<size_t>(myCurrentKernelIndex) * myKernelSize;
|
||||
if (++myCurrentKernelIndex == myPrecomputedKernelCount)
|
||||
|
||||
@@ -53,7 +53,7 @@ void SimpleResampler::fillFragment(float* fragment, uInt32 length)
|
||||
const size_t outputSamples = stereoOut ? (length >> 1) : length;
|
||||
|
||||
// For the following math, remember that myTimeIndex = time * myFormatFrom.sampleRate * myFormatTo.sampleRate
|
||||
for (auto i = 0uz; i < outputSamples; ++i) {
|
||||
for (auto i = 0UZ; i < outputSamples; ++i) {
|
||||
if (stereoIn) {
|
||||
const float sampleL = static_cast<float>(
|
||||
myCurrentFragment[2*static_cast<size_t>(myFragmentIndex)]) * SAMPLE_SCALE;
|
||||
|
||||
+17
-17
@@ -238,12 +238,12 @@ namespace BSPF
|
||||
constexpr bool isLowerAscii(char c) { return c >= 'a' && c <= 'z'; }
|
||||
|
||||
// Convert string to given case
|
||||
inline const string& toUpperCase(string& s)
|
||||
constexpr string& toUpperCase(string& s)
|
||||
{
|
||||
std::ranges::transform(s, s.begin(), [](char c){ return toUpperAscii(c); });
|
||||
return s;
|
||||
}
|
||||
inline const string& toLowerCase(string& s)
|
||||
constexpr string& toLowerCase(string& s)
|
||||
{
|
||||
std::ranges::transform(s, s.begin(), [](char c){ return toLowerAscii(c); });
|
||||
return s;
|
||||
@@ -251,7 +251,7 @@ namespace BSPF
|
||||
|
||||
// Convert string to integer, using default value on any error
|
||||
template<int BASE = 10>
|
||||
inline int stoi(string_view s, int defaultValue = 0)
|
||||
constexpr int stoi(string_view s, int defaultValue = 0)
|
||||
{
|
||||
// Skip leading spaces safely
|
||||
const auto pos = s.find_first_not_of(' ');
|
||||
@@ -270,7 +270,7 @@ namespace BSPF
|
||||
{
|
||||
// Only compare up to the length of the shorter string
|
||||
const auto maxsize = std::min(s1.size(), s2.size());
|
||||
for(auto i = 0uz; i < maxsize; ++i)
|
||||
for(auto i = 0UZ; i < maxsize; ++i)
|
||||
{
|
||||
const char c1 = toUpperAscii(s1[i]);
|
||||
const char c2 = toUpperAscii(s2[i]);
|
||||
@@ -336,8 +336,8 @@ namespace BSPF
|
||||
return false;
|
||||
|
||||
// Remaining characters must appear in order
|
||||
auto pos = 1uz;
|
||||
for(auto j = 1uz; j < s2.size(); ++j)
|
||||
auto pos = 1UZ;
|
||||
for(auto j = 1UZ; j < s2.size(); ++j)
|
||||
{
|
||||
const char target = toUpperAscii(s2[j]);
|
||||
while(pos < s1.size() && toUpperAscii(s1[pos]) != target)
|
||||
@@ -358,15 +358,15 @@ namespace BSPF
|
||||
if(s1.empty() || s2.empty()) return false;
|
||||
|
||||
// Skip leading '_' for both strings if both start with it
|
||||
const auto ofs = (s1[0] == '_' && s2[0] == '_') ? 1uz : 0uz;
|
||||
const auto ofs = (s1[0] == '_' && s2[0] == '_') ? 1UZ : 0UZ;
|
||||
|
||||
// First character must match (case insensitive)
|
||||
if(toUpperAscii(s1[ofs]) != toUpperAscii(s2[ofs]))
|
||||
return false;
|
||||
|
||||
auto pos = 1uz + ofs; // current search position in s1 (absolute)
|
||||
auto pos = 1UZ + ofs; // current search position in s1 (absolute)
|
||||
|
||||
for(auto j = 1uz + ofs; j < s2.size(); ++j)
|
||||
for(auto j = 1UZ + ofs; j < s2.size(); ++j)
|
||||
{
|
||||
const char c2 = s2[j];
|
||||
|
||||
@@ -422,10 +422,10 @@ namespace BSPF
|
||||
pattern = effectivePat;
|
||||
}
|
||||
|
||||
auto si = 0uz; // current position in str
|
||||
auto pi = 0uz; // current position in pattern
|
||||
auto si = 0UZ; // current position in str
|
||||
auto pi = 0UZ; // current position in pattern
|
||||
auto starPi = string_view::npos; // position of last '*' in pattern
|
||||
auto starSi = 0uz; // position in str when last '*' was matched
|
||||
auto starSi = 0UZ; // position in str when last '*' was matched
|
||||
|
||||
while(si < str.length())
|
||||
{
|
||||
@@ -464,7 +464,7 @@ namespace BSPF
|
||||
constexpr void replaceAll(string& str, string_view from, string_view to)
|
||||
{
|
||||
if(from.empty()) return;
|
||||
auto start_pos = 0uz;
|
||||
auto start_pos = 0UZ;
|
||||
while((start_pos = str.find(from, start_pos)) != string_view::npos)
|
||||
{
|
||||
str.replace(start_pos, from.length(), to);
|
||||
@@ -490,7 +490,7 @@ namespace BSPF
|
||||
// name from a (potentially shared/imported) properties entry is concatenated
|
||||
// into a save/snapshot path. Both '/' and '\' are replaced regardless of
|
||||
// platform so the result can't escape its intended directory.
|
||||
inline string sanitizeFilename(string_view name)
|
||||
constexpr string sanitizeFilename(string_view name)
|
||||
{
|
||||
string result{name};
|
||||
std::ranges::replace(result, '/', '_');
|
||||
@@ -532,10 +532,10 @@ namespace BSPF
|
||||
if(image.size() < sigsize)
|
||||
return false;
|
||||
|
||||
auto count = 0uz;
|
||||
for(auto i = 0uz; i <= image.size() - sigsize; ++i)
|
||||
auto count = 0UZ;
|
||||
for(auto i = 0UZ; i <= image.size() - sigsize; ++i)
|
||||
{
|
||||
auto j = 0uz;
|
||||
auto j = 0UZ;
|
||||
for(j = 0; j < sigsize; ++j)
|
||||
{
|
||||
if(image[i + j] != signature[j])
|
||||
|
||||
@@ -47,7 +47,7 @@ void AtariNTSC::generateKernels()
|
||||
constexpr float PALETTE_SCALE = rgb_unit / 255.F;
|
||||
|
||||
const uInt8* ptr = myRGBPalette.data();
|
||||
for(auto entry = 0uz; entry < myRGBPalette.size() / 3; ++entry)
|
||||
for(auto entry = 0UZ; entry < myRGBPalette.size() / 3; ++entry)
|
||||
{
|
||||
const float r = (*ptr++) * PALETTE_SCALE + rgb_offset,
|
||||
g = (*ptr++) * PALETTE_SCALE + rgb_offset,
|
||||
|
||||
@@ -25,7 +25,7 @@ void BreakpointMap::add(const Breakpoint& breakpoint, uInt32 flags)
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void BreakpointMap::add(uInt16 addr, uInt8 bank, uInt32 flags)
|
||||
void BreakpointMap::add(uInt16 addr, uInt16 bank, uInt32 flags)
|
||||
{
|
||||
add(Breakpoint(addr, bank), flags);
|
||||
}
|
||||
@@ -42,7 +42,7 @@ void BreakpointMap::erase(const Breakpoint& breakpoint)
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void BreakpointMap::erase(uInt16 addr, uInt8 bank)
|
||||
void BreakpointMap::erase(uInt16 addr, uInt16 bank)
|
||||
{
|
||||
erase(Breakpoint(addr, bank));
|
||||
}
|
||||
@@ -55,7 +55,7 @@ uInt32 BreakpointMap::get(const Breakpoint& breakpoint) const
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 BreakpointMap::get(uInt16 addr, uInt8 bank) const
|
||||
uInt32 BreakpointMap::get(uInt16 addr, uInt16 bank) const
|
||||
{
|
||||
return get(Breakpoint(addr, bank));
|
||||
}
|
||||
@@ -67,7 +67,7 @@ bool BreakpointMap::check(const Breakpoint& breakpoint) const
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool BreakpointMap::check(uInt16 addr, uInt8 bank) const
|
||||
bool BreakpointMap::check(uInt16 addr, uInt16 bank) const
|
||||
{
|
||||
return check(Breakpoint(addr, bank));
|
||||
}
|
||||
|
||||
@@ -31,15 +31,15 @@ class BreakpointMap
|
||||
{
|
||||
public:
|
||||
// breakpoint flags
|
||||
static constexpr uInt32 ONE_SHOT = 1 << 0; // used for 'trace' command
|
||||
static constexpr uInt8 ANY_BANK = 255; // breakpoint valid in any bank
|
||||
static constexpr uInt32 ONE_SHOT = 1 << 0; // used for 'trace' command
|
||||
static constexpr uInt16 ANY_BANK = 0xffff; // breakpoint valid in any bank
|
||||
|
||||
struct Breakpoint
|
||||
{
|
||||
uInt16 addr{0};
|
||||
uInt8 bank{0};
|
||||
uInt16 bank{0};
|
||||
|
||||
constexpr Breakpoint(uInt16 c_addr, uInt8 c_bank) : addr{c_addr}, bank{c_bank} { }
|
||||
constexpr Breakpoint(uInt16 c_addr, uInt16 c_bank) : addr{c_addr}, bank{c_bank} { }
|
||||
|
||||
bool operator==(const Breakpoint& other) const
|
||||
{
|
||||
@@ -62,19 +62,19 @@ class BreakpointMap
|
||||
|
||||
/** Add new breakpoint */
|
||||
void add(const Breakpoint& breakpoint, uInt32 flags = 0);
|
||||
void add(uInt16 addr, uInt8 bank, uInt32 flags = 0);
|
||||
void add(uInt16 addr, uInt16 bank, uInt32 flags = 0);
|
||||
|
||||
/** Erase breakpoint */
|
||||
void erase(const Breakpoint& breakpoint);
|
||||
void erase(uInt16 addr, uInt8 bank);
|
||||
void erase(uInt16 addr, uInt16 bank);
|
||||
|
||||
/** Get info for breakpoint */
|
||||
uInt32 get(const Breakpoint& breakpoint) const;
|
||||
uInt32 get(uInt16 addr, uInt8 bank) const;
|
||||
uInt32 get(uInt16 addr, uInt16 bank) const;
|
||||
|
||||
/** Check if a breakpoint exists */
|
||||
bool check(const Breakpoint& breakpoint) const;
|
||||
bool check(uInt16 addr, uInt8 bank) const;
|
||||
bool check(uInt16 addr, uInt16 bank) const;
|
||||
|
||||
/** Returns a sorted list of breakpoints */
|
||||
BreakpointList getBreakpoints() const;
|
||||
|
||||
@@ -1161,7 +1161,7 @@ string CartDebug::clearConfig(int bank)
|
||||
endbank = startbank + 1;
|
||||
}
|
||||
|
||||
auto count = 0uz;
|
||||
auto count = 0UZ;
|
||||
for(uInt32 b = startbank; b < endbank; ++b)
|
||||
{
|
||||
count += myBankInfo[b].directiveList.size();
|
||||
|
||||
@@ -358,7 +358,7 @@ string Debugger::setRAM(const IntArray& args)
|
||||
|
||||
const size_t count = args.size(), written = count - 1;
|
||||
int address = args[0];
|
||||
for(auto i = 1uz; i < count; ++i)
|
||||
for(auto i = 1UZ; i < count; ++i)
|
||||
mySystem.pokeOob(address++, args[i]);
|
||||
|
||||
return std::format("changed {} {}", written,
|
||||
@@ -443,7 +443,7 @@ int Debugger::trace()
|
||||
const int targetPC = myCpuDebug->pc() + 3; // return address
|
||||
|
||||
// set temporary breakpoint at target PC (if not existing already)
|
||||
const Int8 bank = myCartDebug->getBank(targetPC);
|
||||
const uInt16 bank = myCartDebug->getBank(targetPC);
|
||||
if(!checkBreakPoint(targetPC, bank))
|
||||
{
|
||||
// add temporary breakpoint and remove later
|
||||
@@ -463,7 +463,7 @@ int Debugger::trace()
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::setBreakPoint(uInt16 addr, uInt8 bank, uInt32 flags) const
|
||||
bool Debugger::setBreakPoint(uInt16 addr, uInt16 bank, uInt32 flags) const
|
||||
{
|
||||
if(checkBreakPoint(addr, bank))
|
||||
return false;
|
||||
@@ -473,7 +473,7 @@ bool Debugger::setBreakPoint(uInt16 addr, uInt8 bank, uInt32 flags) const
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::clearBreakPoint(uInt16 addr, uInt8 bank) const
|
||||
bool Debugger::clearBreakPoint(uInt16 addr, uInt16 bank) const
|
||||
{
|
||||
if(!checkBreakPoint(addr, bank))
|
||||
return false;
|
||||
@@ -483,13 +483,13 @@ bool Debugger::clearBreakPoint(uInt16 addr, uInt8 bank) const
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::checkBreakPoint(uInt16 addr, uInt8 bank) const
|
||||
bool Debugger::checkBreakPoint(uInt16 addr, uInt16 bank) const
|
||||
{
|
||||
return breakPoints().check(addr, bank);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::toggleBreakPoint(uInt16 addr, uInt8 bank) const
|
||||
bool Debugger::toggleBreakPoint(uInt16 addr, uInt16 bank) const
|
||||
{
|
||||
if(checkBreakPoint(addr, bank))
|
||||
clearBreakPoint(addr, bank);
|
||||
@@ -1060,7 +1060,7 @@ Debugger::FunctionDefMap Debugger::getFunctionDefMap() const
|
||||
string Debugger::builtinHelp()
|
||||
{
|
||||
std::ostringstream buf;
|
||||
auto c_maxlen = 0uz, i_maxlen = 0uz;
|
||||
auto c_maxlen = 0UZ, i_maxlen = 0UZ;
|
||||
|
||||
// Get column widths for aligned output (functions)
|
||||
for(const auto& func: ourBuiltinFunctions)
|
||||
|
||||
@@ -50,6 +50,7 @@ class TiaWindow;
|
||||
#include "DebuggerDialog.hxx"
|
||||
#include "FrameBufferConstants.hxx"
|
||||
#include "Cart.hxx"
|
||||
#include "BreakpointMap.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
@@ -215,7 +216,7 @@ class Debugger : public DialogContainer
|
||||
|
||||
Returns true if successfully set
|
||||
*/
|
||||
bool setBreakPoint(uInt16 addr, uInt8 bank = ANY_BANK,
|
||||
bool setBreakPoint(uInt16 addr, uInt16 bank = BreakpointMap::ANY_BANK,
|
||||
uInt32 flags = 0) const;
|
||||
|
||||
/**
|
||||
@@ -223,21 +224,21 @@ class Debugger : public DialogContainer
|
||||
|
||||
Returns true if successfully cleared
|
||||
*/
|
||||
bool clearBreakPoint(uInt16 addr, uInt8 bank) const;
|
||||
bool clearBreakPoint(uInt16 addr, uInt16 bank) const;
|
||||
|
||||
/**
|
||||
Toggles a breakpoint
|
||||
|
||||
Returns new state of breakpoint
|
||||
*/
|
||||
bool toggleBreakPoint(uInt16 addr, uInt8 bank) const;
|
||||
bool toggleBreakPoint(uInt16 addr, uInt16 bank) const;
|
||||
|
||||
/**
|
||||
Checks for a breakpoint.
|
||||
|
||||
Returns true if existing, else false
|
||||
*/
|
||||
bool checkBreakPoint(uInt16 addr, uInt8 bank) const;
|
||||
bool checkBreakPoint(uInt16 addr, uInt16 bank) const;
|
||||
|
||||
/**
|
||||
Run the debugger command and return the result.
|
||||
@@ -448,7 +449,6 @@ class Debugger : public DialogContainer
|
||||
static std::array<BuiltinFunction, 18> ourBuiltinFunctions;
|
||||
static std::array<PseudoRegister, 18> ourPseudoRegisters;
|
||||
|
||||
static constexpr Int8 ANY_BANK = -1;
|
||||
bool myFirstLog{true};
|
||||
|
||||
private:
|
||||
|
||||
@@ -990,14 +990,18 @@ void DebuggerParser::executeBreak()
|
||||
{
|
||||
const uInt32 romBankCount = debugger.cartDebug().romBankCount();
|
||||
const uInt16 addr = (argCount == 0) ? debugger.cpuDebug().pc() : args[0];
|
||||
uInt8 bank = 0;
|
||||
// "all banks" is only ever requested explicitly (as bank 'ff'); an
|
||||
// auto-detected current bank of 255 is a real bank, never a wildcard
|
||||
bool allBanks = false;
|
||||
uInt16 bank = 0;
|
||||
|
||||
if(argCount < 2)
|
||||
bank = debugger.cartDebug().getBank(addr);
|
||||
else
|
||||
{
|
||||
bank = args[1];
|
||||
if(bank >= romBankCount && bank != 0xff)
|
||||
allBanks = (bank == 0xff);
|
||||
if(bank >= romBankCount && !allBanks)
|
||||
{
|
||||
commandResult << red("invalid bank");
|
||||
return;
|
||||
@@ -1005,7 +1009,7 @@ void DebuggerParser::executeBreak()
|
||||
}
|
||||
|
||||
// Helper to format a single breakpoint result line
|
||||
const auto formatBreak = [&](int b)
|
||||
const auto formatBreak = [&](uInt16 b)
|
||||
{
|
||||
const bool set = debugger.toggleBreakPoint(addr, b);
|
||||
std::format_to(std::ostreambuf_iterator(commandResult),
|
||||
@@ -1016,7 +1020,7 @@ void DebuggerParser::executeBreak()
|
||||
" in bank #{}", b);
|
||||
};
|
||||
|
||||
if(bank != 0xff)
|
||||
if(!allBanks)
|
||||
{
|
||||
formatBreak(bank);
|
||||
}
|
||||
@@ -1548,7 +1552,7 @@ void DebuggerParser::executeHelp()
|
||||
if(argCount == 0) // normal help, show all commands
|
||||
{
|
||||
static const size_t clen = []() {
|
||||
auto len = 0uz;
|
||||
auto len = 0UZ;
|
||||
for(const auto& c: commands)
|
||||
len = std::max(len, c.cmdString.length());
|
||||
return len;
|
||||
@@ -1742,7 +1746,7 @@ void DebuggerParser::executeListBreaks()
|
||||
if(count % 6)
|
||||
buf += ", ";
|
||||
buf += debugger.cartDebug().getLabel(bp.addr, true, 4);
|
||||
if(bp.bank != 255)
|
||||
if(bp.bank != BreakpointMap::ANY_BANK)
|
||||
std::format_to(std::back_inserter(buf), " #{}", static_cast<int>(bp.bank));
|
||||
else
|
||||
buf += " *";
|
||||
@@ -2044,7 +2048,7 @@ void DebuggerParser::executeRunTo()
|
||||
progress.setRange(0, static_cast<int>(max_iterations), 5);
|
||||
progress.open();
|
||||
|
||||
auto count = 0uz;
|
||||
auto count = 0UZ;
|
||||
bool done = false;
|
||||
do {
|
||||
debugger.step(false);
|
||||
|
||||
@@ -105,6 +105,10 @@ bool TimerMap::load(Serializer& in)
|
||||
{
|
||||
clear();
|
||||
const uInt32 count = in.getInt();
|
||||
// Sanity cap: timers are hand-created in the debugger, so a huge count is
|
||||
// a corrupt save file. Reject rather than attempt a giant allocation
|
||||
if(count > 0x10000)
|
||||
return false;
|
||||
myList.resize(count);
|
||||
for(auto& t: myList)
|
||||
t.load(in);
|
||||
|
||||
@@ -83,9 +83,9 @@ void BoosterWidget::loadConfig()
|
||||
myPins[kJFire]->setState(!getPin(ourPinNo[kJFire]));
|
||||
|
||||
myPins[kJBooster]->setState(
|
||||
getPin(Controller::AnalogPin::Five) == AnalogReadout::connectToVcc());
|
||||
myPins[kJTrigger]->setState(
|
||||
getPin(Controller::AnalogPin::Nine) == AnalogReadout::connectToVcc());
|
||||
myPins[kJTrigger]->setState(
|
||||
getPin(Controller::AnalogPin::Five) == AnalogReadout::connectToVcc());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -104,12 +104,12 @@ void BoosterWidget::handleCommand(
|
||||
setPin(ourPinNo[id], !myPins[id]->getState());
|
||||
break;
|
||||
case kJBooster:
|
||||
setPin(Controller::AnalogPin::Five,
|
||||
setPin(Controller::AnalogPin::Nine,
|
||||
myPins[id]->getState() ? AnalogReadout::connectToVcc() :
|
||||
AnalogReadout::disconnect());
|
||||
break;
|
||||
case kJTrigger:
|
||||
setPin(Controller::AnalogPin::Nine,
|
||||
setPin(Controller::AnalogPin::Five,
|
||||
myPins[id]->getState() ? AnalogReadout::connectToVcc() :
|
||||
AnalogReadout::disconnect());
|
||||
break;
|
||||
|
||||
@@ -81,7 +81,7 @@ void GenesisWidget::loadConfig()
|
||||
myPins[kJBbtn]->setState(!getPin(ourPinNo[kJBbtn]));
|
||||
|
||||
myPins[kJCbtn]->setState(
|
||||
getPin(Controller::AnalogPin::Five) == AnalogReadout::connectToGround());
|
||||
getPin(Controller::AnalogPin::Nine) == AnalogReadout::connectToGround());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -100,7 +100,7 @@ void GenesisWidget::handleCommand(
|
||||
setPin(ourPinNo[id], !myPins[id]->getState());
|
||||
break;
|
||||
case kJCbtn:
|
||||
setPin(Controller::AnalogPin::Five,
|
||||
setPin(Controller::AnalogPin::Nine,
|
||||
myPins[id]->getState() ? AnalogReadout::connectToGround() :
|
||||
AnalogReadout::connectToVcc());
|
||||
break;
|
||||
|
||||
@@ -109,9 +109,9 @@ void PaddleWidget::layoutContent(GUI::BoxLayout& col)
|
||||
void PaddleWidget::loadConfig()
|
||||
{
|
||||
myP0Resistance->setValue(static_cast<Int32>(AnalogReadout::MAX_POT_RESISTANCE -
|
||||
getPin(Controller::AnalogPin::Nine).resistance));
|
||||
myP1Resistance->setValue(static_cast<Int32>(AnalogReadout::MAX_POT_RESISTANCE -
|
||||
getPin(Controller::AnalogPin::Five).resistance));
|
||||
myP1Resistance->setValue(static_cast<Int32>(AnalogReadout::MAX_POT_RESISTANCE -
|
||||
getPin(Controller::AnalogPin::Nine).resistance));
|
||||
myP0Fire->setState(!getPin(Controller::DigitalPin::Four));
|
||||
myP1Fire->setState(!getPin(Controller::DigitalPin::Three));
|
||||
}
|
||||
@@ -123,11 +123,11 @@ void PaddleWidget::handleCommand(
|
||||
switch(cmd)
|
||||
{
|
||||
case kP0Changed:
|
||||
setPin(Controller::AnalogPin::Nine,
|
||||
setPin(Controller::AnalogPin::Five,
|
||||
AnalogReadout::connectToVcc(AnalogReadout::MAX_POT_RESISTANCE - myP0Resistance->getValue()));
|
||||
break;
|
||||
case kP1Changed:
|
||||
setPin(Controller::AnalogPin::Five,
|
||||
setPin(Controller::AnalogPin::Nine,
|
||||
AnalogReadout::connectToVcc(AnalogReadout::MAX_POT_RESISTANCE - myP1Resistance->getValue()));
|
||||
break;
|
||||
case kP0Fire:
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
//============================================================================
|
||||
|
||||
#include <cctype>
|
||||
#include <limits>
|
||||
|
||||
#include "Base.hxx"
|
||||
#include "Debugger.hxx"
|
||||
@@ -94,7 +95,8 @@ private:
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// const_to_int converts a string to a number in the current or overridden base.
|
||||
// Returns -1 on error; negative numbers are the parser's responsibility.
|
||||
// Returns -1 on error (including overflow); negative numbers are the parser's
|
||||
// responsibility.
|
||||
int Lexer::const_to_int(string_view s)
|
||||
{
|
||||
Common::Base::Fmt format = Common::Base::format();
|
||||
@@ -108,29 +110,42 @@ int Lexer::const_to_int(string_view s)
|
||||
}
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
// A bare base prefix with no digits following it (e.g. "$" on its own)
|
||||
// is not a valid numeral.
|
||||
if (s.empty())
|
||||
return -1;
|
||||
|
||||
// Accumulate in Int64 and bail as soon as the value can no longer fit in
|
||||
// the int NUMBER token; this both avoids signed-overflow UB on long/
|
||||
// adversarial numerals and bounds the work done on them.
|
||||
static constexpr Int64 kMax = std::numeric_limits<int>::max();
|
||||
Int64 ret = 0;
|
||||
|
||||
switch (format) {
|
||||
case Common::Base::Fmt::_2:
|
||||
for (const char c : s) {
|
||||
if (c != '0' && c != '1') return -1;
|
||||
ret = ret * 2 + (c - '0');
|
||||
if (ret > kMax) return -1;
|
||||
}
|
||||
return ret;
|
||||
return static_cast<int>(ret);
|
||||
|
||||
case Common::Base::Fmt::_10:
|
||||
for (const char c : s) {
|
||||
if (!isdigit(c)) return -1;
|
||||
ret = ret * 10 + (c - '0');
|
||||
if (ret > kMax) return -1;
|
||||
}
|
||||
return ret;
|
||||
return static_cast<int>(ret);
|
||||
|
||||
case Common::Base::Fmt::_16:
|
||||
for (const char c : s) {
|
||||
if (!isxdigit(c)) return -1;
|
||||
const int dig = (c - '0');
|
||||
ret = ret * 16 + (dig > 9 ? tolower(c) - 'a' + 10 : dig);
|
||||
if (ret > kMax) return -1;
|
||||
}
|
||||
return ret;
|
||||
return static_cast<int>(ret);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
@@ -200,7 +215,7 @@ parser::symbol_type Lexer::yylex()
|
||||
{
|
||||
char o{0}, p{0};
|
||||
|
||||
while (*myC != '\0') {
|
||||
while (myC != myEnd) {
|
||||
switch (myState) {
|
||||
case State::SPACE:
|
||||
if (isspace(*myC))
|
||||
@@ -216,7 +231,7 @@ parser::symbol_type Lexer::yylex()
|
||||
case State::IDENTIFIER: {
|
||||
myIdbuf.clear();
|
||||
myIdbuf += *myC++;
|
||||
while (is_identifier(*myC))
|
||||
while (myC != myEnd && is_identifier(*myC))
|
||||
myIdbuf += *myC++;
|
||||
myState = State::DEFAULT;
|
||||
|
||||
@@ -245,7 +260,7 @@ parser::symbol_type Lexer::yylex()
|
||||
|
||||
case State::OPERATOR:
|
||||
o = *myC++;
|
||||
if (!*myC)
|
||||
if (myC == myEnd)
|
||||
return make_char_tok(o);
|
||||
if (isspace(*myC)) {
|
||||
myState = State::SPACE;
|
||||
@@ -314,8 +329,19 @@ namespace {
|
||||
} // namespace
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Expression trees are evaluated and destroyed recursively (one C++ stack
|
||||
// frame per nesting level), so an absurdly long, deeply-nested expression
|
||||
// (chained operators, nested parens/derefs) could exhaust the stack. Capping
|
||||
// the input length bounds the tree depth well below any risk of that.
|
||||
static constexpr size_t kMaxExpressionLength = 1024;
|
||||
|
||||
unique_ptr<Expression> parse(string_view in)
|
||||
{
|
||||
if (in.size() > kMaxExpressionLength) {
|
||||
s_errorMsg() = "Expression too long";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unique_ptr<Expression> result;
|
||||
string parseError;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
//============================================================================
|
||||
|
||||
#include "MediaFactory.hxx"
|
||||
#include "Serializer.hxx"
|
||||
#include "System.hxx"
|
||||
#include "AtariVox.hxx"
|
||||
|
||||
@@ -145,3 +146,43 @@ void AtariVox::reset()
|
||||
myLastDataWriteCycle = 0;
|
||||
SaveKey::reset();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool AtariVox::save(Serializer& out) const
|
||||
{
|
||||
if(!SaveKey::save(out)) return false;
|
||||
try
|
||||
{
|
||||
out.putByte(myShiftCount);
|
||||
out.putShort(myShiftRegister);
|
||||
out.putLong(myLastDataWriteCycle);
|
||||
out.putBool(myReadyStateSoftFlow);
|
||||
out.putBool(myCTSFlip);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "ERROR: AtariVox::save\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool AtariVox::load(Serializer& in)
|
||||
{
|
||||
if(!SaveKey::load(in)) return false;
|
||||
try
|
||||
{
|
||||
myShiftCount = in.getByte();
|
||||
myShiftRegister = in.getShort();
|
||||
myLastDataWriteCycle = in.getLong();
|
||||
myReadyStateSoftFlow = in.getBool();
|
||||
myCTSFlip = in.getBool();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "ERROR: AtariVox::load\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -95,6 +95,14 @@ class AtariVox : public SaveKey
|
||||
return Controller::about(swappedPorts) + myAboutString;
|
||||
}
|
||||
|
||||
/**
|
||||
Save/load the controller state. Extends the base (which handles the
|
||||
EEPROM) with the SpeakJet serial shift state, so a state saved mid-byte
|
||||
doesn't drop the partially-shifted speech byte.
|
||||
*/
|
||||
bool save(Serializer& out) const override;
|
||||
bool load(Serializer& in) override;
|
||||
|
||||
private:
|
||||
void clockDataIn(bool value);
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ BoosterGrip::BoosterGrip(Jack jack, const Event& event, const System& system)
|
||||
myTriggerEvent = Event::RightJoystickFire9;
|
||||
}
|
||||
|
||||
setPin(AnalogPin::Five, AnalogReadout::disconnect());
|
||||
setPin(AnalogPin::Nine, AnalogReadout::disconnect());
|
||||
setPin(AnalogPin::Five, AnalogReadout::disconnect());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -49,10 +49,10 @@ void BoosterGrip::updateButtons()
|
||||
const bool boosterPressed = myEvent.get(myBoosterEvent) != 0 ||
|
||||
mousePressed(Event::MouseButtonRightValue);
|
||||
const bool triggerPressed = myEvent.get(myTriggerEvent) != 0;
|
||||
setPin(AnalogPin::Five, boosterPressed
|
||||
setPin(AnalogPin::Nine, boosterPressed
|
||||
? AnalogReadout::connectToVcc()
|
||||
: AnalogReadout::disconnect());
|
||||
setPin(AnalogPin::Nine, triggerPressed
|
||||
setPin(AnalogPin::Five, triggerPressed
|
||||
? AnalogReadout::connectToVcc()
|
||||
: AnalogReadout::disconnect());
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ Cartridge2K::Cartridge2K(ByteSpan image, string_view md5,
|
||||
const size_t size = std::min(image.size(), bsSize);
|
||||
|
||||
// Set image size to closest power-of-two for the given size
|
||||
auto newSize = 1uz; myBankShift = 0;
|
||||
auto newSize = 1UZ; myBankShift = 0;
|
||||
while(newSize < size)
|
||||
{
|
||||
newSize <<= 1;
|
||||
@@ -45,7 +45,7 @@ Cartridge2K::Cartridge2K(ByteSpan image, string_view md5,
|
||||
myImage.assign(System::PAGE_SIZE, 0);
|
||||
// newSize is rounded up to a power of two, so it may exceed the actual
|
||||
// image size; clamp the source read to avoid reading past the image
|
||||
for(auto i = 0uz; i < System::PAGE_SIZE; i += newSize)
|
||||
for(auto i = 0UZ; i < System::PAGE_SIZE; i += newSize)
|
||||
std::copy_n(image.data(), std::min(newSize, size), myImage.data() + i);
|
||||
myBankShift = System::PAGE_SHIFT;
|
||||
}
|
||||
|
||||
@@ -408,6 +408,19 @@ bool Cartridge4A50::load(Serializer& in)
|
||||
myIsRomMiddle = in.getBool();
|
||||
myIsRomHigh = in.getBool();
|
||||
|
||||
// Reject a corrupt save state whose slice offsets, combined with the
|
||||
// ROM/RAM flags, would index myImage/myRAM out of bounds in peek()/poke().
|
||||
// Each expression is the worst-case index (max address mask) of the
|
||||
// matching access there
|
||||
const auto inBounds = [](size_t index, size_t size) { return index < size; };
|
||||
if(!((myIsRomLow ? inBounds(0x7ffU + mySliceLow, myImage.size())
|
||||
: inBounds(0x7ffU + mySliceLow, myRAM.size())) &&
|
||||
(myIsRomMiddle ? inBounds(0x7ffU + mySliceMiddle + 0x10000U, myImage.size())
|
||||
: inBounds(0x7ffU + mySliceMiddle, myRAM.size())) &&
|
||||
(myIsRomHigh ? inBounds(0x0ffU + mySliceHigh + 0x10000U, myImage.size())
|
||||
: inBounds(0x0ffU + mySliceHigh, myRAM.size()))))
|
||||
return false;
|
||||
|
||||
// Last address and data values
|
||||
myLastData = in.getByte();
|
||||
myLastAddress = in.getShort();
|
||||
|
||||
+15
-5
@@ -225,12 +225,12 @@ void CartridgeAR::finalizeLoad(uInt32 block)
|
||||
myHeader[3] = static_cast<uInt8>(NUM_PAGES);
|
||||
|
||||
// Page-map: page j in the block lives at bank (j/8), page (j%8) in bank
|
||||
for(auto j = 0uz; j < NUM_PAGES; ++j)
|
||||
for(auto j = 0UZ; j < NUM_PAGES; ++j)
|
||||
myHeader[16 + j] = static_cast<uInt8>(((j % 8) << 2) | (j / 8));
|
||||
|
||||
// Per-page checksums: must satisfy checksum(data) + map + ck == 0x55
|
||||
const size_t base = static_cast<size_t>(block) * LOAD_SIZE;
|
||||
for(auto j = 0uz; j < NUM_PAGES; ++j)
|
||||
for(auto j = 0UZ; j < NUM_PAGES; ++j)
|
||||
{
|
||||
const ByteSpan src = ByteSpan{myLoadImages}.subspan(base + j * 256, 256);
|
||||
myHeader[64 + j] = static_cast<uInt8>(
|
||||
@@ -432,7 +432,7 @@ void CartridgeAR::loadIntoRAM(uInt8 load)
|
||||
// past myHeader (page/checksum tables) or myLoadImages
|
||||
bool invalidPageChecksumSeen = false;
|
||||
const size_t numPages = std::min<size_t>(myHeader[3], RAM_SIZE / 256);
|
||||
for(auto j = 0uz; j < numPages; ++j)
|
||||
for(auto j = 0UZ; j < numPages; ++j)
|
||||
{
|
||||
const size_t bank = myHeader[16 + j] & 0b00011;
|
||||
const size_t page = (myHeader[16 + j] & 0b11100) >> 2;
|
||||
@@ -570,6 +570,11 @@ bool CartridgeAR::load(Serializer& in)
|
||||
// Indicates the offset within the image for the corresponding bank
|
||||
in.getIntArray(myImageOffset);
|
||||
|
||||
// Reject a corrupt save state whose bank offsets would index myImage
|
||||
// (8K) out of bounds in peek()/poke(); a valid offset is at most RAM_SIZE
|
||||
if(myImageOffset[0] > RAM_SIZE || myImageOffset[1] > RAM_SIZE)
|
||||
return false;
|
||||
|
||||
// The 6K of RAM and 2K of ROM contained in the Supercharger
|
||||
in.getByteArray(myImage);
|
||||
|
||||
@@ -579,6 +584,11 @@ bool CartridgeAR::load(Serializer& in)
|
||||
// Indicates how many 8448 loads there are
|
||||
myNumberOfLoadImages = in.getByte();
|
||||
|
||||
// Reject a corrupt count that would read past myLoadImages, whose size is
|
||||
// fixed at construction to (actual load count * LOAD_SIZE)
|
||||
if(static_cast<size_t>(myNumberOfLoadImages) * LOAD_SIZE > myLoadImages.size())
|
||||
return false;
|
||||
|
||||
// All of the 8448 byte loads associated with the game
|
||||
// Note that the size of this array is myNumberOfLoadImages * 8448
|
||||
in.getByteArray(ByteMSpan{myLoadImages}.first(myNumberOfLoadImages * LOAD_SIZE));
|
||||
@@ -659,7 +669,7 @@ CartridgeAR::loadPCM(const FSNode& file)
|
||||
if(file.read(magic, 4) < 4) return {};
|
||||
|
||||
float* buf = nullptr;
|
||||
auto frameCount = 0uz;
|
||||
auto frameCount = 0UZ;
|
||||
unsigned int channels = 0, sampleRate = 0;
|
||||
bool freeAsWAV = false;
|
||||
|
||||
@@ -712,7 +722,7 @@ CartridgeAR::loadPCM(const FSNode& file)
|
||||
if(channels > 1)
|
||||
{
|
||||
const float scale = 1.F / static_cast<float>(channels);
|
||||
for(auto i = 0uz; i < frameCount; ++i)
|
||||
for(auto i = 0UZ; i < frameCount; ++i)
|
||||
{
|
||||
float sum = 0.F;
|
||||
for(uInt32 ch = 0; ch < channels; ++ch)
|
||||
|
||||
@@ -195,7 +195,7 @@ inline void CartridgeBUS::updateMusicModeDataFetchers()
|
||||
|
||||
// Let's update counters and flags of the music mode data fetchers
|
||||
if(wholeClocks > 0)
|
||||
for(auto x = 0uz; x < myMusicCounters.size(); ++x)
|
||||
for(auto x = 0UZ; x < myMusicCounters.size(); ++x)
|
||||
myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
|
||||
}
|
||||
|
||||
@@ -785,7 +785,9 @@ bool CartridgeBUS::bank(uInt16 bank, uInt16)
|
||||
if(hotspotsLocked()) return false;
|
||||
|
||||
// Remember what bank we're in
|
||||
myBankOffset = bank << 12;
|
||||
// Constrain to a valid bank so a corrupt bank value (e.g. from a
|
||||
// tampered save state) can never offset myProgramImage[] out of bounds
|
||||
myBankOffset = (bank % romBankCount()) << 12;
|
||||
|
||||
// Setup the page access methods for the current bank
|
||||
System::PageAccess access(this, System::PageAccessType::READ);
|
||||
|
||||
@@ -171,7 +171,7 @@ FORCE_INLINE void CartridgeCDF::updateMusicModeDataFetchers()
|
||||
|
||||
// Let's update counters and flags of the music mode data fetchers
|
||||
if(wholeClocks > 0)
|
||||
for(auto x = 0uz; x < myMusicCounters.size(); ++x)
|
||||
for(auto x = 0UZ; x < myMusicCounters.size(); ++x)
|
||||
myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
|
||||
}
|
||||
|
||||
@@ -454,7 +454,9 @@ bool CartridgeCDF::bank(uInt16 bank, uInt16)
|
||||
if(hotspotsLocked()) return false;
|
||||
|
||||
// Remember what bank we're in
|
||||
myBankOffset = bank << 12;
|
||||
// Constrain to a valid bank so a corrupt bank value (e.g. from a
|
||||
// tampered save state) can never offset myProgramImage[] out of bounds
|
||||
myBankOffset = (bank % romBankCount()) << 12;
|
||||
|
||||
// Setup the page access methods for the current bank
|
||||
System::PageAccess access(this, System::PageAccessType::READ);
|
||||
|
||||
@@ -115,7 +115,9 @@ bool CartridgeCM::bank(uInt16 bank, uInt16)
|
||||
if(hotspotsLocked()) return false;
|
||||
|
||||
// Remember what bank we're in
|
||||
myBankOffset = bank << 12;
|
||||
// Constrain to a valid bank so a corrupt bank value (e.g. from a
|
||||
// tampered save state) can never offset myImage[] out of bounds
|
||||
myBankOffset = (bank % romBankCount()) << 12;
|
||||
|
||||
// Although this scheme contains four 4K ROM banks and one 2K RAM bank,
|
||||
// it's easier to think of things in terms of 2K slices, as follows:
|
||||
|
||||
+15
-2
@@ -253,7 +253,9 @@ bool CartridgeCTY::bank(uInt16 bank, uInt16)
|
||||
if(hotspotsLocked()) return false;
|
||||
|
||||
// Remember what bank we're in
|
||||
myBankOffset = bank << 12;
|
||||
// Constrain to a valid bank so a corrupt bank value (e.g. from a
|
||||
// tampered save state) can never offset myImage[] out of bounds
|
||||
myBankOffset = (bank % romBankCount()) << 12;
|
||||
|
||||
// Setup the page access methods for the current bank
|
||||
System::PageAccess access(this, System::PageAccessType::READ);
|
||||
@@ -347,7 +349,18 @@ bool CartridgeCTY::load(Serializer& in)
|
||||
myFractionalClocks = in.getDouble();
|
||||
in.getIntArray(myMusicCounters);
|
||||
in.getIntArray(myMusicFrequencies);
|
||||
myFrequencyImage = ByteSpan{myTuneData}.subspan(in.getLong());
|
||||
|
||||
// Validate the tune offset from the save file before indexing myTuneData;
|
||||
// a corrupt offset would otherwise build an out-of-bounds subspan. A valid
|
||||
// tune is always 4K and 4K-aligned, so require a full tune to remain
|
||||
const uInt64 tuneOffset = in.getLong();
|
||||
if(tuneOffset > myTuneData.size() - 4_KB)
|
||||
return false;
|
||||
myFrequencyImage = ByteSpan{myTuneData}.subspan(tuneOffset);
|
||||
|
||||
// Guard the tune position so note indexing stays within the current tune
|
||||
if((static_cast<size_t>(myTunePosition) + 1) * 3 > myFrequencyImage.size())
|
||||
myTunePosition = 0;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ CartridgeCV::CartridgeCV(ByteSpan image, string_view md5,
|
||||
const size_t size = image.size();
|
||||
if(size <= 2_KB)
|
||||
{
|
||||
for(auto i = 0uz; i < 2_KB; i += size)
|
||||
for(auto i = 0UZ; i < 2_KB; i += size)
|
||||
// Copy the ROM of <=2K files to the 2nd half of the 4K ROM
|
||||
// The 1st half is used for RAM
|
||||
// A non-power-of-2 size won't tile [2K, 4K) evenly, so clamp the
|
||||
|
||||
@@ -203,7 +203,7 @@ namespace // anonymous namespace, to keep these functions private
|
||||
*/
|
||||
string_view stripCollectionPrefix(string_view stem)
|
||||
{
|
||||
auto p = 0uz;
|
||||
auto p = 0UZ;
|
||||
while(p < stem.size() && std::isdigit(static_cast<unsigned char>(stem[p])))
|
||||
++p;
|
||||
if(p > 0 && p + 2 < stem.size() && stem.substr(p, 3) == " - ")
|
||||
|
||||
@@ -402,6 +402,10 @@ bool CartridgeDPC::load(Serializer& in)
|
||||
|
||||
// The counter registers for the data fetchers
|
||||
in.getShortArray(myCounters);
|
||||
// Counters are 11-bit in hardware and index the 2K display image via
|
||||
// (2047 - counter); mask so a corrupt save file can't index out of bounds
|
||||
for(auto& counter: myCounters)
|
||||
counter &= 0x07ff;
|
||||
|
||||
// The flag registers for the data fetchers
|
||||
in.getByteArray(myFlags);
|
||||
|
||||
@@ -174,7 +174,7 @@ FORCE_INLINE void CartridgeDPCPlus::updateMusicModeDataFetchers()
|
||||
|
||||
// Let's update counters and flags of the music mode data fetchers
|
||||
if(wholeClocks > 0)
|
||||
for(auto x = 0uz; x < myMusicCounters.size(); ++x)
|
||||
for(auto x = 0UZ; x < myMusicCounters.size(); ++x)
|
||||
myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
|
||||
}
|
||||
|
||||
@@ -633,7 +633,9 @@ bool CartridgeDPCPlus::bank(uInt16 bank, uInt16)
|
||||
if(hotspotsLocked()) return false;
|
||||
|
||||
// Remember what bank we're in
|
||||
myBankOffset = bank << 12;
|
||||
// Constrain to a valid bank so a corrupt bank value (e.g. from a
|
||||
// tampered save state) can never offset myProgramImage[] out of bounds
|
||||
myBankOffset = (bank % romBankCount()) << 12;
|
||||
|
||||
// Setup the page access methods for the current bank
|
||||
System::PageAccess access(this, System::PageAccessType::READ);
|
||||
@@ -773,9 +775,17 @@ bool CartridgeDPCPlus::load(Serializer& in)
|
||||
|
||||
// The counter registers for the data fetchers
|
||||
in.getShortArray(myCounters);
|
||||
// Counters are 12-bit in hardware and index the 4K display image; mask so
|
||||
// a corrupt save file can't index out of bounds (in peek() or the poke()
|
||||
// write path, which uses the counter before re-masking it)
|
||||
for(auto& counter: myCounters)
|
||||
counter &= 0x0fff;
|
||||
|
||||
// The counter registers for the fractional data fetchers
|
||||
in.getIntArray(myFractionalCounters);
|
||||
// Fractional counters are 20-bit; (counter >> 8) indexes the display image
|
||||
for(auto& counter: myFractionalCounters)
|
||||
counter &= 0x0fffff;
|
||||
|
||||
// The fractional registers for the data fetchers
|
||||
in.getByteArray(myFractionalIncrements);
|
||||
@@ -795,6 +805,9 @@ bool CartridgeDPCPlus::load(Serializer& in)
|
||||
|
||||
// The music waveforms
|
||||
in.getShortArray(myMusicWaveforms);
|
||||
// Waveforms are 7-bit; (waveform << 5) indexes the display image
|
||||
for(auto& waveform: myMusicWaveforms)
|
||||
waveform &= 0x7f;
|
||||
|
||||
// The random number generator register
|
||||
myRandomNumber = in.getInt();
|
||||
|
||||
@@ -45,7 +45,7 @@ void CartridgeDevCard::install(System& system)
|
||||
|
||||
System::PageAccess access(this, System::PageAccessType::READWRITE);
|
||||
|
||||
for(auto win = 0uz; win < NUM_WINDOWS; ++win)
|
||||
for(auto win = 0UZ; win < NUM_WINDOWS; ++win)
|
||||
{
|
||||
const auto winBase = static_cast<uInt32>(win * WINDOW_SIZE);
|
||||
for(uInt32 addr = WINDOWS[win]; addr < WINDOWS[win] + WINDOW_SIZE;
|
||||
|
||||
+14
-5
@@ -95,21 +95,22 @@ void CartridgeE7::install(System& system)
|
||||
|
||||
System::PageAccess access(this, System::PageAccessType::READ);
|
||||
|
||||
// The hotspots at $1FE0-$1FE7 live in the page starting here; that page is
|
||||
// handled separately below since it must dispatch through peek()/poke()
|
||||
constexpr uInt16 HOTSPOT_PAGE = 0x1FE0 & ~System::PAGE_MASK;
|
||||
|
||||
// Set the page accessing methods for the hot spots
|
||||
for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
|
||||
addr += System::PAGE_SIZE)
|
||||
for(uInt16 addr = HOTSPOT_PAGE; addr < 0x2000; addr += System::PAGE_SIZE)
|
||||
{
|
||||
access.romAccessBase = &myRomAccessBase[0x1fc0];
|
||||
access.romPeekCounter = &myRomAccessCounter[0x1fc0];
|
||||
access.romPokeCounter = &myRomAccessCounter[0x1fc0 + myAccessSize];
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
/*setAccess(0x1FE0 & ~System::PAGE_MASK, System::PAGE_SIZE,
|
||||
0, nullptr, 0x1fc0, System::PA_NONE, 0x1fc0);*/
|
||||
|
||||
// Setup the second segment to always point to the last ROM bank
|
||||
const auto offset = static_cast<uInt16>(myRAMBank * BANK_SIZE);
|
||||
setAccess(0x1A00, 0x1FE0U & (~System::PAGE_MASK - 0x1A00),
|
||||
setAccess(0x1A00, HOTSPOT_PAGE - 0x1A00,
|
||||
offset, myImage.data(), offset,
|
||||
System::PageAccessType::READ, static_cast<uInt16>(BANK_SIZE - 1));
|
||||
myCurrentBank[1] = myRAMBank;
|
||||
@@ -239,6 +240,10 @@ void CartridgeE7::bankRAM(uInt16 bank)
|
||||
{
|
||||
if(hotspotsLocked()) return;
|
||||
|
||||
// Constrain to a valid RAM bank (there are 4, as in the 0x1800 hotspots)
|
||||
// so a corrupt value can't map page access outside myRAM
|
||||
bank &= 0x03;
|
||||
|
||||
// Remember what bank we're in
|
||||
myCurrentRAM = bank;
|
||||
const uInt16 offset = bank << 8; // * RAM_BANK_SIZE (256)
|
||||
@@ -257,6 +262,10 @@ bool CartridgeE7::bank(uInt16 bank, uInt16)
|
||||
{
|
||||
if(hotspotsLocked()) return false;
|
||||
|
||||
// Constrain to a valid bank so a corrupt value (e.g. from a tampered save
|
||||
// state) can't map page access outside the ROM image
|
||||
bank %= romBankCount();
|
||||
|
||||
// Remember what bank we're in
|
||||
myCurrentBank[0] = bank;
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace {
|
||||
{
|
||||
stream << "\nELF sections:\n\n";
|
||||
|
||||
auto i = 0uz;
|
||||
auto i = 0UZ;
|
||||
for (const auto& section: elf.getSections()) {
|
||||
if (section.type != 0x00) stream << i << " " << section << '\n';
|
||||
i++;
|
||||
@@ -88,7 +88,7 @@ namespace {
|
||||
const auto& sections = parser.getSections();
|
||||
const auto& relocatedSections = linker.getRelocatedSections();
|
||||
|
||||
for (auto i = 0uz; i < sections.size(); i++) {
|
||||
for (auto i = 0UZ; i < sections.size(); i++) {
|
||||
if (!relocatedSections[i]) continue;
|
||||
|
||||
stream
|
||||
@@ -103,7 +103,7 @@ namespace {
|
||||
const auto& symbols = parser.getSymbols();
|
||||
const auto& relocatedSymbols = linker.getRelocatedSymbols();
|
||||
|
||||
for (auto i = 0uz; i < symbols.size(); i++) {
|
||||
for (auto i = 0UZ; i < symbols.size(); i++) {
|
||||
if (!relocatedSymbols[i]) continue;
|
||||
|
||||
stream
|
||||
|
||||
@@ -108,7 +108,8 @@ bool CartridgeFE::poke(uInt16 address, uInt8 value)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeFE::save(Serializer& out) const
|
||||
{
|
||||
CartridgeEnhanced::save(out);
|
||||
if(!CartridgeEnhanced::save(out))
|
||||
return false;
|
||||
try
|
||||
{
|
||||
out.putBool(myLastAccessWasFE);
|
||||
@@ -125,7 +126,8 @@ bool CartridgeFE::save(Serializer& out) const
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeFE::load(Serializer& in)
|
||||
{
|
||||
CartridgeEnhanced::load(in);
|
||||
if(!CartridgeEnhanced::load(in))
|
||||
return false;
|
||||
try
|
||||
{
|
||||
myLastAccessWasFE = in.getBool();
|
||||
|
||||
@@ -104,7 +104,8 @@ bool CartridgeMDM::bank(uInt16 bank, uInt16)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeMDM::save(Serializer& out) const
|
||||
{
|
||||
CartridgeEnhanced::save(out);
|
||||
if(!CartridgeEnhanced::save(out))
|
||||
return false;
|
||||
try
|
||||
{
|
||||
out.putBool(myBankingDisabled);
|
||||
@@ -121,7 +122,8 @@ bool CartridgeMDM::save(Serializer& out) const
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeMDM::load(Serializer& in)
|
||||
{
|
||||
CartridgeEnhanced::load(in);
|
||||
if(!CartridgeEnhanced::load(in))
|
||||
return false;
|
||||
try
|
||||
{
|
||||
myBankingDisabled = in.getBool();
|
||||
|
||||
+19
-20
@@ -200,14 +200,11 @@ namespace {
|
||||
out.putByteArray(myBuffer1);
|
||||
out.putByteArray(myBuffer2);
|
||||
|
||||
#if 0 // FIXME - determine whether we need to load/save this
|
||||
const uInt8* myAudio
|
||||
const uInt8* myGraph
|
||||
const uInt8* myGraphOverride
|
||||
const uInt8* myTimecode
|
||||
const uInt8* myColor
|
||||
const uInt8* myColorBK
|
||||
#endif
|
||||
// The stream cursors (myAudio/myGraph/myGraphOverride/myTimecode/
|
||||
// myColor/myColorBK) are pointers into the buffers above and are
|
||||
// intentionally not serialized: they are re-derived from the buffer
|
||||
// layout at the next field boundary (swapField), so a mid-field load
|
||||
// costs at most a partial frame of A/V, which then self-corrects.
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
@@ -222,14 +219,8 @@ namespace {
|
||||
in.getByteArray(myBuffer1);
|
||||
in.getByteArray(myBuffer2);
|
||||
|
||||
#if 0 // FIXME - determine whether we need to load/save this
|
||||
const uInt8* myAudio
|
||||
const uInt8* myGraph
|
||||
const uInt8* myGraphOverride
|
||||
const uInt8* myTimecode
|
||||
const uInt8* myColor
|
||||
const uInt8* myColorBK
|
||||
#endif
|
||||
// See save(): the stream cursors are re-derived at the next field
|
||||
// boundary, so they are intentionally not part of the save format.
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
@@ -1566,8 +1557,10 @@ bool MovieCart::save(Serializer& out) const
|
||||
out.putByte(myButtonsValue);
|
||||
|
||||
out.putByte(myVolume);
|
||||
// FIXME - determine whether we need to load/save this
|
||||
// const uInt8* myVolumeScale{scales[DEFAULT_LEVEL]};
|
||||
// myMute is a multi-frame countdown that gates the volume; it doesn't
|
||||
// self-correct on its own, so it is saved. myVolumeScale is not: it is
|
||||
// re-derived from myVolume every frame in runStateMachine().
|
||||
out.putByte(myMute);
|
||||
out.putByte(myFirstAudioVal);
|
||||
}
|
||||
catch(...)
|
||||
@@ -1604,6 +1597,9 @@ bool MovieCart::load(Serializer& in)
|
||||
|
||||
myMode = in.getByte();
|
||||
myBright = in.getByte();
|
||||
// myBright indexes shiftBright[] via (v & 0x0f) + myBright; clamp as the
|
||||
// emulation does so a corrupt save file can't index out of bounds
|
||||
if(myBright >= MAX_LEVEL) myBright = MAX_LEVEL - 1;
|
||||
myForceColor = in.getByte();
|
||||
|
||||
// expressed in frames
|
||||
@@ -1620,8 +1616,11 @@ bool MovieCart::load(Serializer& in)
|
||||
myButtonsValue = in.getByte();
|
||||
|
||||
myVolume = in.getByte();
|
||||
// FIXME - determine whether we need to load/save this
|
||||
// const uInt8* myVolumeScale{scales[DEFAULT_LEVEL]};
|
||||
// myVolume indexes scales[]; clamp as the emulation does so a corrupt save
|
||||
// file can't index out of bounds
|
||||
if(myVolume >= MAX_LEVEL) myVolume = MAX_LEVEL - 1;
|
||||
// See save(): myMute is saved; myVolumeScale is re-derived from myVolume
|
||||
myMute = in.getByte();
|
||||
myFirstAudioVal = in.getByte();
|
||||
}
|
||||
catch(...)
|
||||
|
||||
@@ -54,7 +54,8 @@ bool CartridgeTVBoy::bank(uInt16 bank, uInt16)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeTVBoy::save(Serializer& out) const
|
||||
{
|
||||
CartridgeEnhanced::save(out);
|
||||
if(!CartridgeEnhanced::save(out))
|
||||
return false;
|
||||
try
|
||||
{
|
||||
out.putBool(myBankingDisabled);
|
||||
@@ -71,7 +72,8 @@ bool CartridgeTVBoy::save(Serializer& out) const
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeTVBoy::load(Serializer& in)
|
||||
{
|
||||
CartridgeEnhanced::load(in);
|
||||
if(!CartridgeEnhanced::load(in))
|
||||
return false;
|
||||
try
|
||||
{
|
||||
myBankingDisabled = in.getBool();
|
||||
|
||||
@@ -124,7 +124,8 @@ uInt16 CartridgeWD::getBank(uInt16) const
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeWD::save(Serializer& out) const
|
||||
{
|
||||
CartridgeEnhanced::save(out);
|
||||
if(!CartridgeEnhanced::save(out))
|
||||
return false;
|
||||
try
|
||||
{
|
||||
out.putShort(myCurrentBank);
|
||||
@@ -143,7 +144,8 @@ bool CartridgeWD::save(Serializer& out) const
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeWD::load(Serializer& in)
|
||||
{
|
||||
CartridgeEnhanced::load(in);
|
||||
if(!CartridgeEnhanced::load(in))
|
||||
return false;
|
||||
try
|
||||
{
|
||||
myCurrentBank = in.getShort();
|
||||
|
||||
+10
-10
@@ -49,25 +49,25 @@ void CompuMate::update()
|
||||
using DP = Controller::DigitalPin;
|
||||
using AP = Controller::AnalogPin;
|
||||
|
||||
lp.setPin(AP::Nine, AnalogReadout::connectToGround());
|
||||
lp.setPin(AP::Five, AnalogReadout::connectToVcc());
|
||||
lp.setPin(AP::Five, AnalogReadout::connectToGround());
|
||||
lp.setPin(AP::Nine, AnalogReadout::connectToVcc());
|
||||
lp.setPin(DP::Six, true);
|
||||
rp.setPin(AP::Nine, AnalogReadout::connectToVcc());
|
||||
rp.setPin(AP::Five, AnalogReadout::connectToGround());
|
||||
rp.setPin(AP::Five, AnalogReadout::connectToVcc());
|
||||
rp.setPin(AP::Nine, AnalogReadout::connectToGround());
|
||||
rp.setPin(DP::Six, true);
|
||||
rp.setPin(DP::Three, true);
|
||||
rp.setPin(DP::Four, true);
|
||||
|
||||
if(myEvent.get(Event::CompuMateFunc))
|
||||
lp.setPin(AP::Nine, AnalogReadout::connectToVcc());
|
||||
lp.setPin(AP::Five, AnalogReadout::connectToVcc());
|
||||
if(myEvent.get(Event::CompuMateShift))
|
||||
rp.setPin(AP::Five, AnalogReadout::connectToVcc());
|
||||
rp.setPin(AP::Nine, AnalogReadout::connectToVcc());
|
||||
|
||||
// LUT for CompuMate keys; faster than manual if statements
|
||||
struct ColMap {
|
||||
E lp6, rp3, rp6, rp4;
|
||||
E shiftKey; // key that mimics Shift+lp6 (sets RP.A5 high)
|
||||
E funcKey; // key that mimics Func+rp4 (sets LP.A9 high)
|
||||
E shiftKey; // key that mimics Shift+lp6 (sets RP.A9 high)
|
||||
E funcKey; // key that mimics Func+rp4 (sets LP.A5 high)
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -122,11 +122,11 @@ void CompuMate::update()
|
||||
rp.setPin(DP::Four, false);
|
||||
|
||||
if(col.shiftKey != E::NoType && myEvent.get(col.shiftKey)) {
|
||||
rp.setPin(AP::Five, AnalogReadout::connectToVcc());
|
||||
rp.setPin(AP::Nine, AnalogReadout::connectToVcc());
|
||||
lp.setPin(DP::Six, false);
|
||||
}
|
||||
if(col.funcKey != E::NoType && myEvent.get(col.funcKey)) {
|
||||
lp.setPin(AP::Nine, AnalogReadout::connectToVcc());
|
||||
lp.setPin(AP::Five, AnalogReadout::connectToVcc());
|
||||
rp.setPin(DP::Four, false);
|
||||
}
|
||||
if(myBackspaceReleaseCycle && mySystem.cycles() >= myBackspaceReleaseCycle)
|
||||
|
||||
@@ -124,11 +124,11 @@ class CompuMate
|
||||
myHandler{handler}
|
||||
{
|
||||
if(jack == Controller::Jack::Left) {
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToGround());
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
|
||||
} else {
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc());
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToGround());
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc());
|
||||
} else {
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToGround());
|
||||
}
|
||||
}
|
||||
~CMControl() override = default;
|
||||
|
||||
@@ -46,11 +46,11 @@ class System;
|
||||
pin 2 D5 PIA SWCHA D1 PIA SWCHA
|
||||
pin 3 D6 PIA SWCHA D2 PIA SWCHA
|
||||
pin 4 D7 PIA SWCHA D3 PIA SWCHA
|
||||
pin 5 D7 TIA INPT1 (Dumped) D7 TIA INPT3 (Dumped)
|
||||
pin 5 D7 TIA INPT0 (Dumped) D7 TIA INPT2 (Dumped)
|
||||
pin 6 D7 TIA INPT4 (Latched) D7 TIA INPT5 (Latched)
|
||||
pin 7 +5 +5
|
||||
pin 8 GND GND
|
||||
pin 9 D7 TIA INPT0 (Dumped) D7 TIA INPT2 (Dumped)
|
||||
pin 9 D7 TIA INPT1 (Dumped) D7 TIA INPT3 (Dumped)
|
||||
|
||||
Each of the pins connected to the PIA can be configured as an
|
||||
input or output pin. The "dumped" TIA pins are used to charge
|
||||
@@ -389,7 +389,7 @@ class Controller : public Serializable
|
||||
bound.fill(Event::NoType);
|
||||
|
||||
bool pressed = false;
|
||||
auto i = 0uz;
|
||||
auto i = 0UZ;
|
||||
for(const Event::Type event: events)
|
||||
{
|
||||
bound[i++] = event;
|
||||
|
||||
@@ -585,6 +585,15 @@ void CortexM0::MemoryRegion::loadDirtyBits(Serializer& in)
|
||||
accessWatermarkLow = in.getInt();
|
||||
accessWatermarkHigh = in.getInt();
|
||||
|
||||
// Validate the watermarks read from the save file before using them to build
|
||||
// a span into backingStore. Without this a corrupt range yields an
|
||||
// out-of-bounds write, or (via unsigned underflow of high - low + 1) an
|
||||
// enormous one. The checks are ordered so no subtraction can itself
|
||||
// underflow: base <= low <= high < base + size
|
||||
if (accessWatermarkLow < base || accessWatermarkHigh < accessWatermarkLow ||
|
||||
accessWatermarkHigh - base >= size)
|
||||
throw std::runtime_error("invalid ARM memory region watermark");
|
||||
|
||||
switch (type) {
|
||||
case MemoryRegionType::directCode:
|
||||
in.getByteArray(std::span{
|
||||
@@ -650,14 +659,14 @@ bool CortexM0::load(Serializer& in)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CortexM0::saveDirtyRegions(Serializer& out) const
|
||||
{
|
||||
for (auto i = 0uz; i < myNextRegionIndex; i++)
|
||||
for (auto i = 0UZ; i < myNextRegionIndex; i++)
|
||||
myRegions[i].saveDirtyBits(out);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CortexM0::loadDirtyRegions(Serializer& in)
|
||||
{
|
||||
for (auto i = 0uz; i < myNextRegionIndex; i++)
|
||||
for (auto i = 0UZ; i < myNextRegionIndex; i++)
|
||||
myRegions[i].loadDirtyBits(in);
|
||||
|
||||
recompileCodeRegions();
|
||||
|
||||
@@ -92,7 +92,7 @@ void Driving::updateButtons()
|
||||
// to this controller, so each can change the button within the input window
|
||||
// instead of latching a static aggregate.
|
||||
std::array<Event::Type, MAX_PIN_EVENTS> fire{myFireEvent};
|
||||
auto n = 1uz;
|
||||
auto n = 1UZ;
|
||||
if(myControlID > -1)
|
||||
{
|
||||
// The single fire button is triggered by both mouse buttons
|
||||
|
||||
@@ -403,7 +403,7 @@ int FBSurface::drawString(const GUI::Font& font, string_view s,
|
||||
|
||||
int x0 = x, x1 = 0;
|
||||
|
||||
for(auto i = 0uz; i < str.size(); ++i)
|
||||
for(auto i = 0UZ; i < str.size(); ++i)
|
||||
{
|
||||
w = font.getCharWidth(str[i]);
|
||||
if(x + w > rightX)
|
||||
|
||||
@@ -899,7 +899,7 @@ void FrameBuffer::setUIPalette()
|
||||
const uInt32 bShift = std::countr_zero(bMask());
|
||||
const uInt32 aMask_ = aMask();
|
||||
|
||||
for(auto i = 0uz; i < ui_palette.size(); ++i)
|
||||
for(auto i = 0UZ; i < ui_palette.size(); ++i)
|
||||
{
|
||||
const uInt32 rgb = ui_palette[i];
|
||||
myFullPalette[kColor + i] = aMask_
|
||||
@@ -924,7 +924,7 @@ void FrameBuffer::setDisasmPalette()
|
||||
const uInt32 bShift = std::countr_zero(bMask());
|
||||
const uInt32 aMask_ = aMask();
|
||||
|
||||
for(auto i = 0uz; i < dp.size(); ++i)
|
||||
for(auto i = 0UZ; i < dp.size(); ++i)
|
||||
{
|
||||
const uInt32 rgb = dp[i];
|
||||
myFullPalette[kUINColors + i] = aMask_
|
||||
|
||||
@@ -23,8 +23,8 @@ Genesis::Genesis(Jack jack, const Event& event, const System& system)
|
||||
myButtonCEvent{(myJack == Jack::Left) ? Event::LeftJoystickFire5
|
||||
: Event::RightJoystickFire5}
|
||||
{
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc());
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -39,7 +39,7 @@ void Genesis::updateButtons()
|
||||
// the input window).
|
||||
const bool buttonCPressed = myEvent.get(myButtonCEvent) != 0 ||
|
||||
mousePressed(Event::MouseButtonRightValue);
|
||||
setPin(AnalogPin::Five, buttonCPressed
|
||||
setPin(AnalogPin::Nine, buttonCPressed
|
||||
? AnalogReadout::connectToGround()
|
||||
: AnalogReadout::connectToVcc());
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
The standard Sega Genesis controller works with the 2600 console for
|
||||
joystick directions and some of the buttons. Button 'B' corresponds to
|
||||
the normal fire button (joy0fire), while button 'C' is read through
|
||||
INPT1 (analog pin 5).
|
||||
INPT1 (analog pin 9).
|
||||
|
||||
@author Stephen Anthony
|
||||
*/
|
||||
|
||||
@@ -32,8 +32,8 @@ Joy2BPlus::Joy2BPlus(Jack jack, const Event& event, const System& system)
|
||||
myButton3Event = Event::RightJoystickFire9;
|
||||
}
|
||||
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc());
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -48,10 +48,10 @@ void Joy2BPlus::updateButtons()
|
||||
const bool buttonCPressed = myEvent.get(myButtonCEvent) != 0 ||
|
||||
mousePressed(Event::MouseButtonRightValue);
|
||||
const bool button3Pressed = myEvent.get(myButton3Event) != 0;
|
||||
setPin(AnalogPin::Five, buttonCPressed
|
||||
setPin(AnalogPin::Nine, buttonCPressed
|
||||
? AnalogReadout::connectToGround()
|
||||
: AnalogReadout::connectToVcc());
|
||||
setPin(AnalogPin::Nine, button3Pressed
|
||||
setPin(AnalogPin::Five, button3Pressed
|
||||
? AnalogReadout::connectToGround()
|
||||
: AnalogReadout::connectToVcc());
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
/**
|
||||
The Joy 2B+ controller works with the 2600 console for joystick directions
|
||||
and some of the buttons. Button 'B' corresponds to the normal fire button
|
||||
(joy0fire), while button 'C' is read through INPT1 (analog pin 5) and
|
||||
button '3' through INPT0 (analog pin 9).
|
||||
(joy0fire), while button 'C' is read through INPT1 (analog pin 9) and
|
||||
button '3' through INPT0 (analog pin 5).
|
||||
|
||||
@author Thomas Jentzsch
|
||||
*/
|
||||
|
||||
@@ -77,7 +77,7 @@ void Joystick::updateFire(bool bothButtonsFire)
|
||||
// controller, the mouse button(s) that also trigger it, so each can change
|
||||
// the button within the input window instead of latching a static aggregate.
|
||||
std::array<Event::Type, MAX_PIN_EVENTS> fire{myFireEvent};
|
||||
auto n = 1uz;
|
||||
auto n = 1UZ;
|
||||
if(myControlID > -1)
|
||||
{
|
||||
fire[n++] = Event::MouseButtonLeftValue;
|
||||
|
||||
@@ -112,6 +112,6 @@ void Keyboard::write(DigitalPin pin, bool value)
|
||||
const ColumnState stateCol2 = processColumn(col2);
|
||||
|
||||
setPin(DigitalPin::Six, stateCol2 != ColumnState::gnd);
|
||||
setPin(AnalogPin::Five, columnStateToAnalogSignal(stateCol1));
|
||||
setPin(AnalogPin::Nine, columnStateToAnalogSignal(stateCol0));
|
||||
setPin(AnalogPin::Nine, columnStateToAnalogSignal(stateCol1));
|
||||
setPin(AnalogPin::Five, columnStateToAnalogSignal(stateCol0));
|
||||
}
|
||||
|
||||
@@ -223,7 +223,18 @@ bool KidVid::load(Serializer& in)
|
||||
myBlockIdx = in.getInt();
|
||||
myBlock = in.getInt();
|
||||
|
||||
// Reject a corrupt save state whose indices would read past the read-only
|
||||
// KidVid data tables: myTape drives tapeIndex()/ourBlocks[], mySongPointer
|
||||
// indexes ourSongPositions[], and (myIdx >> 3) indexes ourData[]
|
||||
if(myTape > 4 ||
|
||||
mySongPointer >= ourSongPositions.size() ||
|
||||
(myIdx >> 3) >= ourData.size())
|
||||
return false;
|
||||
|
||||
myContinueSong = myFilesFound && mySongPlaying;
|
||||
// The song-continue path in update() indexes ourSongPositions[mySongPointer - 1]
|
||||
if(mySongPointer == 0)
|
||||
myContinueSong = false;
|
||||
|
||||
return Controller::load(in);
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
||||
|
||||
if(myBreakPoints.isInitialized())
|
||||
{
|
||||
const uInt8 bank = mySystem->cart().getBank(PC);
|
||||
const uInt16 bank = mySystem->cart().getBank(PC);
|
||||
|
||||
if(myBreakPoints.check(PC, bank))
|
||||
{
|
||||
@@ -461,12 +461,17 @@ bool M6502::save(Serializer& out) const
|
||||
out.putShort(myLastAddress);
|
||||
out.putShort(myLastPeekAddress);
|
||||
out.putShort(myLastPokeAddress);
|
||||
// Base (non-mirrored) peek/poke addresses shown in the debugger
|
||||
out.putShort(myLastPeekBaseAddress);
|
||||
out.putShort(myLastPokeBaseAddress);
|
||||
out.putShort(myDataAddressForPoke);
|
||||
out.putInt(myLastSrcAddressS);
|
||||
out.putInt(myLastSrcAddressA);
|
||||
out.putInt(myLastSrcAddressX);
|
||||
out.putInt(myLastSrcAddressY);
|
||||
out.putByte(myFlags);
|
||||
// Cycles of the last instruction, read via the debugger (_iCycles)
|
||||
out.putByte(icycles);
|
||||
|
||||
out.putBool(myHaltRequested);
|
||||
out.putLong(myLastBreakCycle);
|
||||
@@ -512,12 +517,15 @@ bool M6502::load(Serializer& in)
|
||||
myLastAddress = in.getShort();
|
||||
myLastPeekAddress = in.getShort();
|
||||
myLastPokeAddress = in.getShort();
|
||||
myLastPeekBaseAddress = in.getShort();
|
||||
myLastPokeBaseAddress = in.getShort();
|
||||
myDataAddressForPoke = in.getShort();
|
||||
myLastSrcAddressS = in.getInt();
|
||||
myLastSrcAddressA = in.getInt();
|
||||
myLastSrcAddressX = in.getInt();
|
||||
myLastSrcAddressY = in.getInt();
|
||||
myFlags = in.getByte();
|
||||
icycles = in.getByte();
|
||||
|
||||
myHaltRequested = in.getBool();
|
||||
myLastBreakCycle = in.getLong();
|
||||
|
||||
@@ -410,6 +410,8 @@ bool M6532::save(Serializer& out) const
|
||||
out.putLong(mySetTimerCycle);
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
out.putInt(myTimReadCycles);
|
||||
out.putBool(myTimWrappedOnRead);
|
||||
out.putBool(myTimWrappedOnWrite);
|
||||
#endif
|
||||
|
||||
out.putByte(myDDRA);
|
||||
@@ -443,12 +445,19 @@ bool M6532::load(Serializer& in)
|
||||
myTimer = in.getInt();
|
||||
mySubTimer = in.getInt();
|
||||
myDivider = in.getInt();
|
||||
// myDivider must be one of the four legal timer intervals; anything else
|
||||
// (e.g. 0) corrupts myDividerShift (shift-by-255) and the (myDivider - 1)
|
||||
// bit masks used on the hot path
|
||||
if(myDivider != 1 && myDivider != 8 && myDivider != 64 && myDivider != 1024)
|
||||
return false;
|
||||
myDividerShift = static_cast<uInt8>(std::bit_width(myDivider) - 1);
|
||||
myWrappedThisCycle = in.getBool();
|
||||
myLastCycle = in.getLong();
|
||||
mySetTimerCycle = in.getLong();
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myTimReadCycles = in.getInt();
|
||||
myTimWrappedOnRead = in.getBool();
|
||||
myTimWrappedOnWrite = in.getBool();
|
||||
#endif
|
||||
|
||||
myDDRA = in.getByte();
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "Control.hxx"
|
||||
#include "FSNode.hxx"
|
||||
#include "Serializer.hxx"
|
||||
#include "System.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
@@ -119,6 +120,68 @@ class MicroChip24LC
|
||||
*/
|
||||
bool isPageUsed(uInt32 page) const;
|
||||
|
||||
/**
|
||||
Save the current I2C engine state to the given Serializer. The EEPROM
|
||||
data array is persisted separately (to its .dat file), so only the
|
||||
transient transaction state is serialized here. This matters when a
|
||||
state is saved mid-transaction: without it the in-flight byte/page write
|
||||
is lost, and the ROM's remaining clocks are parsed as a new command.
|
||||
*/
|
||||
bool save(Serializer& out) const {
|
||||
try {
|
||||
out.putBool(mySDA);
|
||||
out.putBool(mySCL);
|
||||
out.putBool(myTimerActive);
|
||||
out.putLong(myCyclesWhenTimerSet);
|
||||
out.putLong(myCyclesWhenSDASet);
|
||||
out.putLong(myCyclesWhenSCLSet);
|
||||
|
||||
out.putByte(static_cast<uInt8>(jpee_state));
|
||||
out.putBool(jpee_mdat);
|
||||
out.putBool(jpee_sdat);
|
||||
out.putBool(jpee_mclk);
|
||||
out.putBool(jpee_ad_known);
|
||||
out.putInt(jpee_pptr);
|
||||
out.putInt(jpee_nb);
|
||||
out.putInt(jpee_address);
|
||||
out.putByteArray(jpee_packet);
|
||||
}
|
||||
catch(...) {
|
||||
cerr << "ERROR: MicroChip24LC::save\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool load(Serializer& in) {
|
||||
try {
|
||||
mySDA = in.getBool();
|
||||
mySCL = in.getBool();
|
||||
myTimerActive = in.getBool();
|
||||
myCyclesWhenTimerSet = in.getLong();
|
||||
myCyclesWhenSDASet = in.getLong();
|
||||
myCyclesWhenSCLSet = in.getLong();
|
||||
|
||||
jpee_state = static_cast<JPEEState>(in.getByte());
|
||||
jpee_mdat = in.getBool();
|
||||
jpee_sdat = in.getBool();
|
||||
jpee_mclk = in.getBool();
|
||||
jpee_ad_known = in.getBool();
|
||||
jpee_pptr = in.getInt();
|
||||
// jpee_pptr bounds the write-commit read loop in jpee_data_stop(),
|
||||
// so reject a corrupt value that would read past jpee_packet
|
||||
if(jpee_pptr > jpee_packet.size()) return false;
|
||||
jpee_nb = in.getInt();
|
||||
jpee_address = in.getInt();
|
||||
in.getByteArray(jpee_packet);
|
||||
}
|
||||
catch(...) {
|
||||
cerr << "ERROR: MicroChip24LC::load\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
Process simultaneous SDA and SCL pin updates.
|
||||
|
||||
@@ -132,12 +132,12 @@ bool OSystem::initialize(const Settings::Options& options)
|
||||
STELLA_VERSION,
|
||||
myFeatures,
|
||||
myBuildInfo,
|
||||
AsciiFold::toAscii(myBaseDir.getShortPath()),
|
||||
AsciiFold::toAscii(myStateDir.getShortPath()),
|
||||
AsciiFold::toAscii(myNVRamDir.getShortPath()),
|
||||
AsciiFold::toAscii(baseDir().getShortPath()),
|
||||
AsciiFold::toAscii(stateDir().getShortPath()),
|
||||
AsciiFold::toAscii(nvramDir().getShortPath()),
|
||||
AsciiFold::toAscii(describePersistence()),
|
||||
AsciiFold::toAscii(myCheatFile.getShortPath()),
|
||||
AsciiFold::toAscii(myPaletteFile.getShortPath())));
|
||||
AsciiFold::toAscii(cheatFile().getShortPath()),
|
||||
AsciiFold::toAscii(paletteFile().getShortPath())));
|
||||
|
||||
// NOTE: The framebuffer MUST be created before any other object!!!
|
||||
// Get relevant information about the video hardware
|
||||
|
||||
@@ -27,8 +27,8 @@ Paddles::Paddles(Jack jack, const Event& event, const System& system,
|
||||
{
|
||||
// We must start with a physical valid resistance (e.g. 0);
|
||||
// see commit 38b452e1a047a0dca38c5bcce7c271d40f76736e for more information
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc());
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
|
||||
|
||||
// The following logic reflects that mapping paddles to different
|
||||
// devices can be extremely complex
|
||||
@@ -166,7 +166,7 @@ void Paddles::updateA()
|
||||
// events driving the fire button (the fire event plus any mouse buttons
|
||||
// mapped to this paddle) so it can be bound for replay within the input window.
|
||||
std::array<Event::Type, MAX_PIN_EVENTS> fire{myAFireEvent};
|
||||
auto n = 1uz;
|
||||
auto n = 1UZ;
|
||||
|
||||
// Paddle movement is a very difficult thing to accurately emulate,
|
||||
// since it originally came from an analog device that had very
|
||||
@@ -184,7 +184,7 @@ void Paddles::updateA()
|
||||
updateMouseA(fire, n);
|
||||
updateDigitalAxesA();
|
||||
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc(
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc(
|
||||
AnalogReadout::MAX_POT_RESISTANCE * myPosition[0]));
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ bool Paddles::updateAnalogAxesA()
|
||||
if(std::abs(myLastAxisX - sa_xaxis) > 10)
|
||||
{
|
||||
conditionAxisInput(myLastAxisX, sa_xaxis);
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc(
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc(
|
||||
AnalogReadout::MAX_POT_RESISTANCE * BSPF::clamp(
|
||||
(ANALOG_MAX_VALUE - (sa_xaxis * SENSITIVITY + XCENTER)) / float{ANALOG_RANGE},
|
||||
0.F, 1.F)));
|
||||
@@ -339,14 +339,14 @@ void Paddles::updateB()
|
||||
// events driving the fire button so it can be bound for replay within the
|
||||
// input window.
|
||||
std::array<Event::Type, MAX_PIN_EVENTS> fire{myBFireEvent};
|
||||
auto n = 1uz;
|
||||
auto n = 1UZ;
|
||||
|
||||
if(!updateAnalogAxesB())
|
||||
{
|
||||
updateMouseB(fire, n);
|
||||
updateDigitalAxesB();
|
||||
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc(
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc(
|
||||
AnalogReadout::MAX_POT_RESISTANCE * myPosition[1]));
|
||||
}
|
||||
|
||||
@@ -363,7 +363,7 @@ bool Paddles::updateAnalogAxesB()
|
||||
if(std::abs(myLastAxisY - sa_yaxis) > 10)
|
||||
{
|
||||
conditionAxisInput(myLastAxisY, sa_yaxis);
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc(
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc(
|
||||
AnalogReadout::MAX_POT_RESISTANCE * BSPF::clamp(
|
||||
(ANALOG_MAX_VALUE - (sa_yaxis * SENSITIVITY + YCENTER)) / float{ANALOG_RANGE},
|
||||
0.F, 1.F)));
|
||||
|
||||
@@ -380,8 +380,8 @@ bool PlusROM::isValidHost(string_view host)
|
||||
return false;
|
||||
|
||||
// Each dot-separated label must be 1..63 characters (RFC 1035)
|
||||
auto start = 0uz;
|
||||
for(auto i = 0uz; i <= host.size(); ++i)
|
||||
auto start = 0UZ;
|
||||
for(auto i = 0UZ; i <= host.size(); ++i)
|
||||
{
|
||||
if(i == host.size() || host[i] == '.')
|
||||
{
|
||||
|
||||
@@ -100,7 +100,7 @@ void PointingDevice::update()
|
||||
// trigger it. Binding the pin (rather than a static setPin) lets the button
|
||||
// change within the input window like the other controllers
|
||||
std::array<Event::Type, MAX_PIN_EVENTS> fire{Event::LeftJoystickFire};
|
||||
auto n = 1uz;
|
||||
auto n = 1UZ;
|
||||
if(myMouseEnabled)
|
||||
{
|
||||
fire[n++] = Event::MouseButtonLeftValue;
|
||||
|
||||
@@ -40,7 +40,7 @@ bool Properties::save(KeyValueRepository& repo) const
|
||||
KVRMap props;
|
||||
|
||||
auto* atomic = repo.atomic();
|
||||
for(auto i = 0uz; i < NUM_PROPS; ++i)
|
||||
for(auto i = 0UZ; i < NUM_PROPS; ++i)
|
||||
{
|
||||
if(myProperties[i] == defaultValue(i))
|
||||
{
|
||||
@@ -119,7 +119,7 @@ void Properties::reset(PropType key)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Properties::setDefaults()
|
||||
{
|
||||
for(auto i = 0uz; i < NUM_PROPS; ++i)
|
||||
for(auto i = 0UZ; i < NUM_PROPS; ++i)
|
||||
myProperties[i] = defaultValue(i);
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ PropType Properties::getPropType(string_view name)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Properties::print() const
|
||||
{
|
||||
for(auto i = 0uz; i < NUM_PROPS; ++i)
|
||||
for(auto i = 0UZ; i < NUM_PROPS; ++i)
|
||||
{
|
||||
if(i > 0) cout << '|';
|
||||
cout << myProperties[i];
|
||||
@@ -171,7 +171,7 @@ void Properties::print() const
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Properties::printHeader()
|
||||
{
|
||||
for(auto i = 0uz; i < NUM_PROPS; ++i)
|
||||
for(auto i = 0UZ; i < NUM_PROPS; ++i)
|
||||
{
|
||||
if(i > 0) cout << '|';
|
||||
cout << ourPropertyNames[i];
|
||||
|
||||
@@ -89,7 +89,7 @@ bool PropertiesSet::getMD5(string_view md5, Properties& properties,
|
||||
BSPF::compareIgnoreCase((*it)[std::to_underlying(PropType::Cart_MD5)], md5) == 0)
|
||||
{
|
||||
const auto& entry = *it;
|
||||
for(auto p = 0uz; p < Properties::NUM_PROPS; ++p)
|
||||
for(auto p = 0UZ; p < Properties::NUM_PROPS; ++p)
|
||||
if(entry[p][0] != 0)
|
||||
properties.set(static_cast<PropType>(p), entry[p]);
|
||||
|
||||
@@ -180,7 +180,7 @@ void PropertiesSet::print() const
|
||||
for(const auto& DefProp: DefProps)
|
||||
{
|
||||
properties.setDefaults();
|
||||
for(auto p = 0uz; p < Properties::NUM_PROPS; ++p)
|
||||
for(auto p = 0UZ; p < Properties::NUM_PROPS; ++p)
|
||||
if(DefProp[p][0] != 0)
|
||||
properties.set(static_cast<PropType>(p), DefProp[p]);
|
||||
|
||||
|
||||
@@ -73,8 +73,8 @@ QuadTari::QuadTari(Jack jack, const OSystem& osystem, const System& system,
|
||||
mySecondController = addController(secondType, true);
|
||||
|
||||
// QuadTari auto detection setting
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToGround());
|
||||
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc());
|
||||
setPin(AnalogPin::Five, AnalogReadout::connectToGround());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
@@ -112,3 +112,15 @@ bool SaveKey::isPageUsed(uInt32 page) const
|
||||
{
|
||||
return myEEPROM->isPageUsed(page);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SaveKey::save(Serializer& out) const
|
||||
{
|
||||
return Controller::save(out) && myEEPROM->save(out);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SaveKey::load(Serializer& in)
|
||||
{
|
||||
return Controller::load(in) && myEEPROM->load(in);
|
||||
}
|
||||
|
||||
@@ -111,6 +111,14 @@ class SaveKey : public Controller
|
||||
/** Returns true if the page is used by the current ROM */
|
||||
bool isPageUsed(uInt32 page) const;
|
||||
|
||||
/**
|
||||
Save/load the controller state, including the EEPROM's in-flight I2C
|
||||
transaction state. The EEPROM data array is persisted separately, to
|
||||
its own file.
|
||||
*/
|
||||
bool save(Serializer& out) const override;
|
||||
bool load(Serializer& in) override;
|
||||
|
||||
private:
|
||||
// The EEPROM used in the SaveKey
|
||||
unique_ptr<MT24LC256> myEEPROM;
|
||||
|
||||
@@ -292,7 +292,7 @@ class Serializer
|
||||
|
||||
// Buffer small writes to a vector, and flush to disk occasionally
|
||||
void writeBuffered(const uInt8* data, size_t dataSize) {
|
||||
auto offset = 0uz;
|
||||
auto offset = 0UZ;
|
||||
while(dataSize > 0) {
|
||||
const size_t space = MAX_BUF_SIZE - bufferPos;
|
||||
const size_t toWrite = std::min(space, dataSize);
|
||||
|
||||
@@ -119,8 +119,8 @@ const FBSurface& TIASurface::baseSurface(Common::Rect& rect) const
|
||||
uInt32 *buf_ptr{nullptr}, pitch{0};
|
||||
myBaseTiaSurface->basePtr(buf_ptr, pitch);
|
||||
|
||||
for(auto y = 0uz; y < height; ++y)
|
||||
for(auto x = 0uz; x < width; ++x)
|
||||
for(auto y = 0UZ; y < height; ++y)
|
||||
for(auto x = 0UZ; x < width; ++x)
|
||||
*buf_ptr++ = myPalette[*(myTIA->frameBuffer() + y * tiaw + x / 2)];
|
||||
|
||||
return *myBaseTiaSurface;
|
||||
|
||||
@@ -73,7 +73,7 @@ bool BusTransactionQueue::save(Serializer& out) const
|
||||
out.putShort(myNextInjectAddress);
|
||||
out.putLong(myTimestamp);
|
||||
|
||||
for (auto i = 0uz; i < myQueueSize; i++)
|
||||
for (auto i = 0UZ; i < myQueueSize; i++)
|
||||
myQueue[(myQueueNext + i) % myQueueCapacity].serialize(out);
|
||||
}
|
||||
catch (...) {
|
||||
@@ -96,7 +96,7 @@ bool BusTransactionQueue::load(Serializer& in)
|
||||
|
||||
if (myQueueSize > myQueueCapacity) return false;
|
||||
|
||||
for (auto i = 0uz; i < myQueueSize; i++)
|
||||
for (auto i = 0UZ; i < myQueueSize; i++)
|
||||
myQueue[i].deserialize(in);
|
||||
}
|
||||
catch(...) {
|
||||
|
||||
@@ -163,7 +163,7 @@ const vector<uInt32>& ElfLinker::getPreinitArray() const
|
||||
ElfLinker::RelocatedSymbol ElfLinker::findRelocatedSymbol(string_view name) const
|
||||
{
|
||||
const auto& symbols = myElf.getSymbols();
|
||||
for (auto i = 0uz; i < symbols.size(); i++) {
|
||||
for (auto i = 0UZ; i < symbols.size(); i++) {
|
||||
if (symbols[i].name != name) continue;
|
||||
|
||||
if (!myRelocatedSymbols[i])
|
||||
@@ -232,7 +232,7 @@ void ElfLinker::relocateSections()
|
||||
myRelocatedSections.resize(sections.size(), std::nullopt);
|
||||
|
||||
// relocate everything that is not .bss
|
||||
for (auto i = 0uz; i < sections.size(); i++) {
|
||||
for (auto i = 0UZ; i < sections.size(); i++) {
|
||||
const auto& section = sections[i];
|
||||
|
||||
const auto segmentType = determineSegmentType(section);
|
||||
@@ -251,7 +251,7 @@ void ElfLinker::relocateSections()
|
||||
}
|
||||
|
||||
// relocate all .bss sections
|
||||
for (auto i = 0uz; i < sections.size(); i++) {
|
||||
for (auto i = 0UZ; i < sections.size(); i++) {
|
||||
const auto& section = sections[i];
|
||||
|
||||
if (section.type == ElfFile::SHT_NOBITS) {
|
||||
@@ -290,7 +290,7 @@ void ElfLinker::copySections()
|
||||
const auto& sections = myElf.getSections();
|
||||
|
||||
// copy segment data
|
||||
for (auto i = 0uz; i < sections.size(); i++) {
|
||||
for (auto i = 0UZ; i < sections.size(); i++) {
|
||||
const auto& relocatedSection = myRelocatedSections[i];
|
||||
if (!relocatedSection) continue;
|
||||
|
||||
@@ -366,7 +366,7 @@ void ElfLinker::relocateSymbols(const vector<ExternalSymbol>& externalSymbols)
|
||||
const auto& symbols = myElf.getSymbols();
|
||||
myRelocatedSymbols.resize(symbols.size(), std::nullopt);
|
||||
|
||||
for (auto i = 0uz; i < symbols.size(); i++) {
|
||||
for (auto i = 0UZ; i < symbols.size(); i++) {
|
||||
const auto& symbol = symbols[i];
|
||||
|
||||
if (symbol.section == ElfFile::SHN_ABS) {
|
||||
@@ -401,7 +401,7 @@ void ElfLinker::applyRelocationsToSections()
|
||||
const auto& sections = myElf.getSections();
|
||||
|
||||
// apply relocations
|
||||
for (auto iSection = 0uz; iSection < sections.size(); iSection++) {
|
||||
for (auto iSection = 0UZ; iSection < sections.size(); iSection++) {
|
||||
const auto& relocations = myElf.getRelocations(iSection);
|
||||
if (!relocations) continue;
|
||||
if (!myRelocatedSections[iSection]) continue;
|
||||
@@ -421,7 +421,7 @@ void ElfLinker::copyInitArrays(vector<uInt32>& initArray, const std::unordered_m
|
||||
for (const auto& [iSection, offset]: relocatedInitArrays) {
|
||||
const auto& section = sections[iSection];
|
||||
|
||||
for (auto i = 0uz; i < section.size; i += 4)
|
||||
for (auto i = 0UZ; i < section.size; i += 4)
|
||||
initArray[(offset + i) >> 2] = read32(elfData + section.offset + i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,9 +293,9 @@ const ElfParser::Section* ElfParser::getSymtab() const
|
||||
const ElfParser::Section* ElfParser::getStrtab() const
|
||||
{
|
||||
const Section* strtab = nullptr;
|
||||
auto count = 0uz;
|
||||
auto count = 0UZ;
|
||||
|
||||
for (auto i = 0uz; i < mySections.size(); i++) {
|
||||
for (auto i = 0UZ; i < mySections.size(); i++) {
|
||||
if (mySections[i].type != SHT_STRTAB || i == myHeader.shstrIndex) continue;
|
||||
|
||||
strtab = &mySections[i];
|
||||
|
||||
@@ -121,7 +121,7 @@ bool VcsLib::save(Serializer& out) const
|
||||
out.putBool(myIsWaitingForRead);
|
||||
out.putShort(myWaitingForReadAddress);
|
||||
out.putShort(myCurrentAddress);
|
||||
out.putBool(myCurrentValue);
|
||||
out.putByte(myCurrentValue);
|
||||
|
||||
if (!myRand.save(out)) return false;
|
||||
}
|
||||
@@ -145,7 +145,7 @@ bool VcsLib::load(Serializer& in)
|
||||
myIsWaitingForRead = in.getBool();
|
||||
myWaitingForReadAddress = in.getShort();
|
||||
myCurrentAddress = in.getShort();
|
||||
myCurrentValue = in.getBool();
|
||||
myCurrentValue = in.getByte();
|
||||
|
||||
if (!myRand.load(in)) return false;
|
||||
}
|
||||
|
||||
@@ -177,11 +177,15 @@ bool Audio::loadSamples(Serializer& in)
|
||||
try
|
||||
{
|
||||
const uInt64 sampleSize = in.getLong();
|
||||
// The raw sample bytes can't exceed the size of the stream they came from;
|
||||
// reject a corrupt size before attempting the allocation
|
||||
if(sampleSize > in.size())
|
||||
return false;
|
||||
ByteArray samples(sampleSize);
|
||||
in.getByteArray(samples);
|
||||
|
||||
// Feed all loaded samples into the audio queue
|
||||
for(auto i = 0uz; i < sampleSize; ++i)
|
||||
for(auto i = 0UZ; i < sampleSize; ++i)
|
||||
{
|
||||
const uInt8 sample = samples[i];
|
||||
const uInt8 sample0 = sample & 0x0f;
|
||||
|
||||
@@ -180,6 +180,7 @@ bool DelayQueue<length, capacity>::load(Serializer& in)
|
||||
}
|
||||
|
||||
myIndex = in.getByte();
|
||||
if (myIndex >= length) throw std::runtime_error("invalid delay queue index");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
||||
@@ -354,7 +354,9 @@ bool Missile::load(Serializer& in)
|
||||
myRenderCounter = in.getByte();
|
||||
myCopy = in.getByte();
|
||||
|
||||
myDecodesOffset = in.getByte();
|
||||
// Mask as in setNusiz(); the decode table has only 8 entries, so an
|
||||
// out-of-range offset from a corrupt save file must not index past it
|
||||
myDecodesOffset = in.getByte() & 0x07;
|
||||
myDecodes = DrawCounterDecodes::get().missileDecodes()[myDecodesOffset];
|
||||
|
||||
myColor = in.getByte();
|
||||
|
||||
@@ -529,7 +529,9 @@ bool Player::load(Serializer& in)
|
||||
mySampleCounter = in.getByte();
|
||||
myDividerChangeCounter = in.getByte();
|
||||
|
||||
myDecodesOffset = in.getByte();
|
||||
// Mask as in setNusiz(); the decode table has only 8 entries, so an
|
||||
// out-of-range offset from a corrupt save file must not index past it
|
||||
myDecodesOffset = in.getByte() & 0x07;
|
||||
myDecodes = DrawCounterDecodes::get().playerDecodes()[myDecodesOffset];
|
||||
|
||||
myPatternOld = in.getByte();
|
||||
|
||||
+34
-13
@@ -324,6 +324,11 @@ bool TIA::save(Serializer& out) const
|
||||
for (const AnalogReadout& analogReadout : myAnalogReadouts)
|
||||
if(!analogReadout.save(out)) return false;
|
||||
|
||||
// Cache of the last analog connection pushed to each readout; preserved so
|
||||
// the change-detection in updateAnalogReadout() stays consistent on reload
|
||||
for(const auto& conn: myLastAnalogConnections)
|
||||
if(!conn.save(out)) return false;
|
||||
|
||||
if(!myInput0.save(out)) return false;
|
||||
if(!myInput1.save(out)) return false;
|
||||
|
||||
@@ -367,6 +372,12 @@ bool TIA::save(Serializer& out) const
|
||||
out.putByte(myPFColorDelay);
|
||||
out.putByte(myBKColorDelay);
|
||||
out.putByte(myPlSwapDelay);
|
||||
|
||||
// Dump-ports state; dumpPortsCycles() (used by e.g. QuadTari to pick a
|
||||
// sub-controller) is measured relative to myDumpPortsCycles, so both must
|
||||
// be preserved across save/load
|
||||
out.putBool(myArePortsDumped);
|
||||
out.putLong(myDumpPortsCycles);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
@@ -397,6 +408,9 @@ bool TIA::load(Serializer& in)
|
||||
for (AnalogReadout& analogReadout : myAnalogReadouts)
|
||||
if(!analogReadout.load(in)) return false;
|
||||
|
||||
for(auto& conn: myLastAnalogConnections)
|
||||
if(!conn.load(in)) return false;
|
||||
|
||||
if(!myInput0.load(in)) return false;
|
||||
if(!myInput1.load(in)) return false;
|
||||
|
||||
@@ -441,14 +455,21 @@ bool TIA::load(Serializer& in)
|
||||
myBKColorDelay = in.getByte();
|
||||
myPlSwapDelay = in.getByte();
|
||||
|
||||
myArePortsDumped = in.getBool();
|
||||
myDumpPortsCycles = in.getLong();
|
||||
|
||||
// Re-apply dev settings
|
||||
applyDeveloperSettings();
|
||||
|
||||
// myCurrentRowPtr is derived state not stored in the save file; recompute
|
||||
// it from the restored y so renderPixel() writes to the correct scanline,
|
||||
// including when the debugger saves and loads state mid-scanline
|
||||
// including when the debugger saves and loads state mid-scanline. Clamp y
|
||||
// to the buffer height so a corrupt save file can't push the row pointer
|
||||
// (and thus renderPixel's writes) past the end of myBackBuffer
|
||||
const uInt32 y = std::min(myFrameManager->getY(),
|
||||
TIAConstants::frameBufferHeight - 1);
|
||||
myCurrentRowPtr = myBackBuffer.data() +
|
||||
static_cast<size_t>(myFrameManager->getY()) * TIAConstants::H_PIXEL;
|
||||
static_cast<size_t>(y) * TIAConstants::H_PIXEL;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
@@ -469,11 +490,11 @@ void TIA::bindToControllers()
|
||||
switch (pin) {
|
||||
using enum Controller::AnalogPin;
|
||||
case Five:
|
||||
updateAnalogReadout(1);
|
||||
updateAnalogReadout(0);
|
||||
break;
|
||||
|
||||
case Nine:
|
||||
updateAnalogReadout(0);
|
||||
updateAnalogReadout(1);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -489,11 +510,11 @@ void TIA::bindToControllers()
|
||||
switch (pin) {
|
||||
using enum Controller::AnalogPin;
|
||||
case Five:
|
||||
updateAnalogReadout(3);
|
||||
updateAnalogReadout(2);
|
||||
break;
|
||||
|
||||
case Nine:
|
||||
updateAnalogReadout(2);
|
||||
updateAnalogReadout(3);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1316,7 +1337,7 @@ bool TIA::enableFixedColors(bool enable)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool TIA::setFixedColorPalette(string_view colors)
|
||||
{
|
||||
for(auto i = 0uz; i < std::min(6uz, colors.size()); ++i)
|
||||
for(auto i = 0UZ; i < std::min(6UZ, colors.size()); ++i)
|
||||
{
|
||||
switch(colors[i])
|
||||
{
|
||||
@@ -2279,19 +2300,19 @@ void TIA::updateAnalogReadout(uInt8 idx)
|
||||
AnalogReadout::Connection connection{};
|
||||
switch (idx) {
|
||||
case 0:
|
||||
connection = myConsole.leftController().read(Controller::AnalogPin::Nine);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
connection = myConsole.leftController().read(Controller::AnalogPin::Five);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
connection = myConsole.leftController().read(Controller::AnalogPin::Nine);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
connection = myConsole.rightController().read(Controller::AnalogPin::Nine);
|
||||
connection = myConsole.rightController().read(Controller::AnalogPin::Five);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
connection = myConsole.rightController().read(Controller::AnalogPin::Five);
|
||||
connection = myConsole.rightController().read(Controller::AnalogPin::Nine);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -240,6 +240,14 @@ bool FrameManager::onSave(Serializer& out) const
|
||||
out.putBool(myVsyncPending);
|
||||
out.putInt(myVsyncPendingLines);
|
||||
|
||||
// Cycle stamps used to measure VSYNC/VBLANK duration for jitter emulation.
|
||||
// A state may legally be saved mid-VSYNC (myVsyncPending set), so these must
|
||||
// be preserved or the next frame's jitter is computed from stale values
|
||||
out.putLong(myVsyncStart);
|
||||
out.putLong(myVsyncEnd);
|
||||
out.putLong(myVblankStart);
|
||||
out.putLong(myVblankCycles);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -261,6 +269,11 @@ bool FrameManager::onLoad(Serializer& in)
|
||||
myVsyncPending = in.getBool();
|
||||
myVsyncPendingLines = in.getInt();
|
||||
|
||||
myVsyncStart = in.getLong();
|
||||
myVsyncEnd = in.getLong();
|
||||
myVblankStart = in.getLong();
|
||||
myVblankCycles = in.getLong();
|
||||
|
||||
recalculateMetrics();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -117,8 +117,8 @@ void ComboDialog::loadConfig()
|
||||
{
|
||||
StringList events = instance().eventHandler().getComboListForEvent(myComboEvent);
|
||||
|
||||
const auto size = std::min(events.size(), 8uz);
|
||||
for(auto i = 0uz; i < size; ++i)
|
||||
const auto size = std::min(events.size(), 8UZ);
|
||||
for(auto i = 0UZ; i < size; ++i)
|
||||
myEvents[i]->setSelected("", events[i]);
|
||||
|
||||
// Fill any remaining items to 'None'
|
||||
|
||||
@@ -1351,7 +1351,7 @@ void LauncherDialog::openContextMenu(int x, int y)
|
||||
|
||||
// Format items for menu, aligning all shortcuts to the right
|
||||
VariantList varItems;
|
||||
auto maxLen = 0uz;
|
||||
auto maxLen = 0UZ;
|
||||
for(auto& item: items)
|
||||
maxLen = std::max(maxLen, item.label.length());
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ void NavigationWidget::PathWidget::setPath(string_view path)
|
||||
cutFirst = true;
|
||||
|
||||
// Update/add widgets for path parts display
|
||||
auto idx = 0uz;
|
||||
auto idx = 0UZ;
|
||||
for(auto it = nodes.rbegin(); it != nodes.rend(); ++it, ++idx)
|
||||
{
|
||||
string name = it->getName();
|
||||
|
||||
@@ -235,7 +235,7 @@ class SoundLIBRETRO : public Sound
|
||||
const uInt32 frameSize = myChannels * (myBitsPerSample / 8);
|
||||
const double step = static_cast<double>(mySampleRate) / outputRate;
|
||||
|
||||
for(auto i = 0uz; i < numSamples && myPos < myEnd; ++i)
|
||||
for(auto i = 0UZ; i < numSamples && myPos < myEnd; ++i)
|
||||
{
|
||||
const Int16 wavL = sample(myPos);
|
||||
const Int16 wavR = (myChannels > 1) ? sample(myPos + myBitsPerSample / 8) : wavL;
|
||||
|
||||
@@ -54,7 +54,7 @@ void post_message(const char* msg, retro_log_level level, unsigned duration_ms =
|
||||
{
|
||||
const retro_message_ext ext = {
|
||||
msg, duration_ms,
|
||||
level == RETRO_LOG_ERROR ? 3u : 1u,
|
||||
level == RETRO_LOG_ERROR ? 3U : 1U,
|
||||
level, RETRO_MESSAGE_TARGET_ALL, RETRO_MESSAGE_TYPE_NOTIFICATION, -1
|
||||
};
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE_EXT, (void*)&ext);
|
||||
|
||||
@@ -34,7 +34,7 @@ FSNodePOSIX::FSNodePOSIX(string_view path, bool verify)
|
||||
if(_path[0] == '~')
|
||||
{
|
||||
// Skip the '/' after '~' if present to avoid double slash
|
||||
const auto replaceLen = (_path.size() > 1 && _path[1] == '/') ? 2uz : 1uz;
|
||||
const auto replaceLen = (_path.size() > 1 && _path[1] == '/') ? 2UZ : 1UZ;
|
||||
_path.replace(0, replaceLen, XDGPaths::instance().home());
|
||||
}
|
||||
else if(_path[0] == '.')
|
||||
|
||||
Reference in New Issue
Block a user