mirror of https://github.com/bsnes-emu/bsnes.git
Update to v095r10 release.
byuu says: Changelog: - int_t<bits> replaced with Integer<bits> - uint_t<bits> replaced with Natural<bits> - fixed "Synchronize Audio" menu option that broke recently - all of sfc/performance ported to "auto function() -> return;" syntax With this WIP, all of higan is finally ported over to the new function declaration syntax. Thank the gods. There's still going to be periodic disruption for diffs from porting over signed->int, unsigned->uint, and whatever we come up with for the new Natural<> and Integer<> classes. But the worst of it's behind us now.
This commit is contained in:
parent
65a3306ad5
commit
78d49d3873
|
@ -7,7 +7,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "095.09";
|
||||
static const string Version = "095.10";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -57,7 +57,7 @@ auto APU::Noise::write(uint r, uint8 data) -> void {
|
|||
|
||||
if(initialize) {
|
||||
enable = dac_enable();
|
||||
lfsr = ~0U;
|
||||
lfsr = -1;
|
||||
envelope_period = envelope_frequency;
|
||||
volume = envelope_volume;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ auto APU::Noise::write(uint addr, uint8 byte) -> void {
|
|||
|
||||
if(initialize) {
|
||||
enable = envelope.dacEnable();
|
||||
lfsr = ~0u;
|
||||
lfsr = -1;
|
||||
envelope.period = envelope.frequency;
|
||||
volume = envelope.volume;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <nall/matrix.hpp>
|
||||
#include <nall/maybe.hpp>
|
||||
#include <nall/memory.hpp>
|
||||
#include <nall/primitives.hpp>
|
||||
#include <nall/property.hpp>
|
||||
#include <nall/random.hpp>
|
||||
#include <nall/range.hpp>
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
#ifndef NALL_PRIMITIVES_HPP
|
||||
#define NALL_PRIMITIVES_HPP
|
||||
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/traits.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct Boolean {
|
||||
inline Boolean() : data(false) {}
|
||||
inline Boolean(bool value) : data(value) {}
|
||||
|
||||
inline operator bool() const { return data; }
|
||||
inline auto& operator=(const bool value) { data = value; return *this; }
|
||||
|
||||
inline auto serialize(serializer& s) { s(data); }
|
||||
|
||||
bool data;
|
||||
};
|
||||
|
||||
template<uint Bits> struct Natural {
|
||||
using type =
|
||||
type_if<expression<Bits <= 8>, uint8_t,
|
||||
type_if<expression<Bits <= 16>, uint16_t,
|
||||
type_if<expression<Bits <= 32>, uint32_t,
|
||||
type_if<expression<Bits <= 64>, uint64_t,
|
||||
void>>>>;
|
||||
|
||||
enum : type { Mask = ~0ull >> (64 - Bits) };
|
||||
|
||||
inline Natural() : data(0) {}
|
||||
inline Natural(const type value) : data(clip(value)) {}
|
||||
template<uint B> inline Natural(const Natural<B> value) : data(clip(value)) {}
|
||||
|
||||
inline operator type() const { return data; }
|
||||
inline auto& operator=(const type value) { data = clip(value); return *this; }
|
||||
template<uint B> inline auto& operator=(const Natural<B> value) { data = clip(value); return *this; }
|
||||
|
||||
inline auto operator++(int) { type value = data; data = clip(data + 1); return value; }
|
||||
inline auto operator--(int) { type value = data; data = clip(data - 1); return value; }
|
||||
|
||||
inline auto& operator++() { data = clip(data + 1); return *this; }
|
||||
inline auto& operator--() { data = clip(data - 1); return *this; }
|
||||
|
||||
inline auto& operator &=(const type value) { data = clip(data & value); return *this; }
|
||||
inline auto& operator |=(const type value) { data = clip(data | value); return *this; }
|
||||
inline auto& operator ^=(const type value) { data = clip(data ^ value); return *this; }
|
||||
inline auto& operator<<=(const type value) { data = clip(data << value); return *this; }
|
||||
inline auto& operator>>=(const type value) { data = clip(data >> value); return *this; }
|
||||
inline auto& operator +=(const type value) { data = clip(data + value); return *this; }
|
||||
inline auto& operator -=(const type value) { data = clip(data - value); return *this; }
|
||||
inline auto& operator *=(const type value) { data = clip(data * value); return *this; }
|
||||
inline auto& operator /=(const type value) { data = clip(data / value); return *this; }
|
||||
inline auto& operator %=(const type value) { data = clip(data % value); return *this; }
|
||||
|
||||
inline auto serialize(serializer& s) { s(data); }
|
||||
|
||||
template<uint Lo, uint Hi> struct Range {
|
||||
enum : type { RangeBits = Hi - Lo + 1, RangeMask = (((1ull << RangeBits) - 1) << Lo) & Mask };
|
||||
|
||||
inline operator type() const {
|
||||
return (self() & RangeMask) >> Lo;
|
||||
}
|
||||
|
||||
inline auto& operator=(const type value) {
|
||||
self() = (self() & ~RangeMask) | ((value << Lo) & RangeMask);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
inline auto self() const -> type& { return *(type*)this; }
|
||||
};
|
||||
|
||||
union {
|
||||
type data;
|
||||
|
||||
Range< 0, 7> b0;
|
||||
Range< 8, 15> b1;
|
||||
Range<16, 23> b2;
|
||||
Range<24, 31> b3;
|
||||
Range<32, 39> b4;
|
||||
Range<40, 47> b5;
|
||||
Range<48, 55> b6;
|
||||
Range<56, 63> b7;
|
||||
|
||||
Range< 0, 15> h0;
|
||||
Range<16, 31> h1;
|
||||
Range<32, 47> h2;
|
||||
Range<48, 63> h3;
|
||||
|
||||
Range< 0, 31> w0;
|
||||
Range<32, 63> w1;
|
||||
};
|
||||
|
||||
private:
|
||||
auto clip(type value) const -> type {
|
||||
return value & Mask;
|
||||
}
|
||||
};
|
||||
|
||||
template<uint Bits> struct Integer {
|
||||
using type =
|
||||
type_if<expression<Bits <= 8>, int8_t,
|
||||
type_if<expression<Bits <= 16>, int16_t,
|
||||
type_if<expression<Bits <= 32>, int32_t,
|
||||
type_if<expression<Bits <= 64>, int64_t,
|
||||
void>>>>;
|
||||
using utype = typename Natural<Bits>::type;
|
||||
|
||||
enum : utype { Mask = ~0ull >> (64 - Bits), Sign = 1ull << (Bits - 1) };
|
||||
|
||||
inline Integer() : data(0) {}
|
||||
inline Integer(const type value) : data(clip(value)) {}
|
||||
template<uint B> inline Integer(const Integer<B> value) : data(clip(value)) {}
|
||||
|
||||
inline operator type() const { return data; }
|
||||
inline auto& operator=(const type value) { data = clip(value); return *this; }
|
||||
template<uint B> inline auto& operator=(const Integer<B> value) { data = clip(value); return *this; }
|
||||
|
||||
inline auto operator++(int) { type value = data; data = clip(data + 1); return value; }
|
||||
inline auto operator--(int) { type value = data; data = clip(data - 1); return value; }
|
||||
|
||||
inline auto& operator++() { data = clip(data + 1); return *this; }
|
||||
inline auto& operator--() { data = clip(data - 1); return *this; }
|
||||
|
||||
inline auto& operator &=(const type value) { data = clip(data & value); return *this; }
|
||||
inline auto& operator |=(const type value) { data = clip(data | value); return *this; }
|
||||
inline auto& operator ^=(const type value) { data = clip(data ^ value); return *this; }
|
||||
inline auto& operator<<=(const type value) { data = clip(data << value); return *this; }
|
||||
inline auto& operator>>=(const type value) { data = clip(data >> value); return *this; }
|
||||
inline auto& operator +=(const type value) { data = clip(data + value); return *this; }
|
||||
inline auto& operator -=(const type value) { data = clip(data - value); return *this; }
|
||||
inline auto& operator *=(const type value) { data = clip(data * value); return *this; }
|
||||
inline auto& operator /=(const type value) { data = clip(data / value); return *this; }
|
||||
inline auto& operator %=(const type value) { data = clip(data % value); return *this; }
|
||||
|
||||
inline auto serialize(serializer& s) { s(data); }
|
||||
|
||||
template<uint Lo, uint Hi> struct Range {
|
||||
enum : utype { RangeBits = Hi - Lo + 1, RangeMask = (((1ull << RangeBits) - 1) << Lo) & Mask };
|
||||
|
||||
inline operator utype() const {
|
||||
return (self() & RangeMask) >> Lo;
|
||||
}
|
||||
|
||||
inline auto& operator=(const utype value) {
|
||||
self() = (((self() & ~RangeMask) | ((value << Lo) & RangeMask)) ^ Sign) - Sign;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
inline auto self() const -> utype& { return *(utype*)this; }
|
||||
};
|
||||
|
||||
union {
|
||||
type data;
|
||||
|
||||
Range< 0, 7> b0;
|
||||
Range< 8, 15> b1;
|
||||
Range<16, 23> b2;
|
||||
Range<24, 31> b3;
|
||||
Range<32, 39> b4;
|
||||
Range<40, 47> b5;
|
||||
Range<48, 55> b6;
|
||||
Range<56, 63> b7;
|
||||
|
||||
Range< 0, 15> h0;
|
||||
Range<16, 31> h1;
|
||||
Range<32, 47> h2;
|
||||
Range<48, 63> h3;
|
||||
|
||||
Range< 0, 31> w0;
|
||||
Range<32, 63> w1;
|
||||
};
|
||||
|
||||
private:
|
||||
auto clip(type value) const -> type {
|
||||
return ((value & Mask) ^ Sign) - Sign;
|
||||
}
|
||||
};
|
||||
|
||||
template<uint Bits> struct Real {
|
||||
using type =
|
||||
type_if<expression<Bits == 32>, float32_t,
|
||||
type_if<expression<Bits == 64>, float64_t,
|
||||
type_if<expression<Bits == 80>, float80_t,
|
||||
void>>>;
|
||||
|
||||
inline Real() : data(0.0) {}
|
||||
inline Real(const type value) : data(value) {}
|
||||
template<uint B> inline Real(const Real<B> value) : data((type)value) {}
|
||||
|
||||
inline operator type() const { return data; }
|
||||
inline auto& operator=(const type value) { data = value; return *this; }
|
||||
template<uint B> inline auto& operator=(const Real<B> value) { data = (type)value; return *this; }
|
||||
|
||||
inline auto operator++(int) { type value = data; ++data; return value; }
|
||||
inline auto operator--(int) { type value = data; --data; return value; }
|
||||
|
||||
inline auto& operator++() { data++; return *this; }
|
||||
inline auto& operator--() { data--; return *this; }
|
||||
|
||||
inline auto& operator+=(const type value) { data = data + value; return *this; }
|
||||
inline auto& operator-=(const type value) { data = data - value; return *this; }
|
||||
inline auto& operator*=(const type value) { data = data * value; return *this; }
|
||||
inline auto& operator/=(const type value) { data = data / value; return *this; }
|
||||
inline auto& operator%=(const type value) { data = data % value; return *this; }
|
||||
|
||||
inline auto serialize(serializer& s) { s(data); }
|
||||
|
||||
type data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -32,7 +32,9 @@
|
|||
using uint128_t = unsigned __int128;
|
||||
#endif
|
||||
|
||||
namespace nall {
|
||||
using float32_t = float;
|
||||
using float64_t = double;
|
||||
using float80_t = long double;
|
||||
|
||||
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
|
||||
static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size");
|
||||
|
@ -44,6 +46,10 @@ static_assert(sizeof(uint16_t) == 2, "int16_t is not of the correct size");
|
|||
static_assert(sizeof(uint32_t) == 4, "int32_t is not of the correct size");
|
||||
static_assert(sizeof(uint64_t) == 8, "int64_t is not of the correct size");
|
||||
|
||||
static_assert(sizeof(float) >= 4, "float32_t is not of the correct size");
|
||||
static_assert(sizeof(double) >= 8, "float64_t is not of the correct size");
|
||||
static_assert(sizeof(long double) >= 10, "float80_t is not of the correct size");
|
||||
|
||||
using int8 = int8_t;
|
||||
using int16 = int16_t;
|
||||
using int32 = int32_t;
|
||||
|
@ -64,6 +70,4 @@ using int128 = int128_t;
|
|||
using uint128 = uint128_t;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <nall/function.hpp>
|
||||
#include <nall/intrinsics.hpp>
|
||||
#include <nall/memory.hpp>
|
||||
#include <nall/primitives.hpp>
|
||||
#include <nall/shared-pointer.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
|
|
@ -21,7 +21,7 @@ template<typename T> struct stringify;
|
|||
//format.hpp
|
||||
template<typename... P> inline auto print(P&&...) -> void;
|
||||
inline auto integer(intmax value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto decimal(uintmax value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto natural(uintmax value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto hex(uintmax value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto octal(uintmax value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto binary(uintmax value, long precision = 0, char padchar = '0') -> string;
|
||||
|
@ -61,7 +61,7 @@ inline auto temppath() -> string;
|
|||
inline auto slice(rstring self, int offset = 0, int length = -1) -> string;
|
||||
|
||||
inline auto integer(char* result, intmax value) -> char*;
|
||||
inline auto decimal(char* result, uintmax value) -> char*;
|
||||
inline auto natural(char* result, uintmax value) -> char*;
|
||||
inline auto real(char* str, long double value) -> uint;
|
||||
|
||||
struct string {
|
||||
|
|
|
@ -5,199 +5,215 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
//base types
|
||||
//booleans
|
||||
|
||||
template<> struct stringify<bool> {
|
||||
bool _value;
|
||||
stringify(bool value) : _value(value) {}
|
||||
auto data() const -> const char* { return _value ? "true" : "false"; }
|
||||
auto size() const -> unsigned { return _value ? 4 : 5; }
|
||||
stringify(bool value) : _value(value) {}
|
||||
bool _value;
|
||||
};
|
||||
|
||||
template<> struct stringify<Boolean> {
|
||||
stringify(bool value) : _value(value) {}
|
||||
auto data() const -> const char* { return _value ? "true" : "false"; }
|
||||
auto size() const -> uint { return _value ? 4 : 5; }
|
||||
bool _value;
|
||||
};
|
||||
|
||||
//characters
|
||||
|
||||
template<> struct stringify<char> {
|
||||
char _data[2];
|
||||
stringify(char source) { _data[0] = source; _data[1] = 0; }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return 1; }
|
||||
stringify(char source) { _data[0] = source; _data[1] = 0; }
|
||||
char _data[2];
|
||||
};
|
||||
|
||||
//signed integers
|
||||
|
||||
template<> struct stringify<signed char> {
|
||||
char _data[2 + sizeof(signed char) * 3];
|
||||
stringify(signed char source) { integer(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(signed char source) { integer(_data, source); }
|
||||
char _data[2 + sizeof(signed char) * 3];
|
||||
};
|
||||
|
||||
template<> struct stringify<signed short> {
|
||||
char _data[2 + sizeof(signed short) * 3];
|
||||
stringify(signed short source) { integer(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(signed short source) { integer(_data, source); }
|
||||
char _data[2 + sizeof(signed short) * 3];
|
||||
};
|
||||
|
||||
template<> struct stringify<signed int> {
|
||||
char _data[2 + sizeof(signed int) * 3];
|
||||
stringify(signed int source) { integer(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(signed int source) { integer(_data, source); }
|
||||
char _data[2 + sizeof(signed int) * 3];
|
||||
};
|
||||
|
||||
template<> struct stringify<signed long> {
|
||||
char _data[2 + sizeof(signed long) * 3];
|
||||
stringify(signed long source) { integer(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(signed long source) { integer(_data, source); }
|
||||
char _data[2 + sizeof(signed long) * 3];
|
||||
};
|
||||
|
||||
template<> struct stringify<signed long long> {
|
||||
char _data[2 + sizeof(signed long long) * 3];
|
||||
stringify(signed long long source) { integer(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(signed long long source) { integer(_data, source); }
|
||||
char _data[2 + sizeof(signed long long) * 3];
|
||||
};
|
||||
|
||||
template<unsigned bits> struct stringify<int_t<bits>> {
|
||||
char _data[2 + sizeof(intmax_t) * 3];
|
||||
template<uint Bits> struct stringify<Integer<Bits>> {
|
||||
stringify(Integer<Bits> source) { integer(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(int_t<bits> source) { integer(_data, source); }
|
||||
auto size() const -> uint { return strlen(_data); }
|
||||
char _data[2 + sizeof(int64_t) * 3];
|
||||
};
|
||||
|
||||
//unsigned integers
|
||||
|
||||
template<> struct stringify<unsigned char> {
|
||||
char _data[1 + sizeof(unsigned char) * 3];
|
||||
stringify(unsigned char source) { natural(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(unsigned char source) { decimal(_data, source); }
|
||||
char _data[1 + sizeof(unsigned char) * 3];
|
||||
};
|
||||
|
||||
template<> struct stringify<unsigned short> {
|
||||
char _data[1 + sizeof(unsigned short) * 3];
|
||||
stringify(unsigned short source) { natural(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(unsigned short source) { decimal(_data, source); }
|
||||
char _data[1 + sizeof(unsigned short) * 3];
|
||||
};
|
||||
|
||||
template<> struct stringify<unsigned int> {
|
||||
char _data[1 + sizeof(unsigned int) * 3];
|
||||
stringify(unsigned int source) { natural(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(unsigned int source) { decimal(_data, source); }
|
||||
char _data[1 + sizeof(unsigned int) * 3];
|
||||
};
|
||||
|
||||
template<> struct stringify<unsigned long> {
|
||||
char _data[1 + sizeof(unsigned long) * 3];
|
||||
stringify(unsigned long source) { natural(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(unsigned long source) { decimal(_data, source); }
|
||||
char _data[1 + sizeof(unsigned long) * 3];
|
||||
};
|
||||
|
||||
template<> struct stringify<unsigned long long> {
|
||||
char _data[1 + sizeof(unsigned long long) * 3];
|
||||
stringify(unsigned long long source) { natural(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(unsigned long long source) { decimal(_data, source); }
|
||||
char _data[1 + sizeof(unsigned long long) * 3];
|
||||
};
|
||||
|
||||
template<unsigned bits> struct stringify<uint_t<bits>> {
|
||||
char _data[1 + sizeof(uintmax_t) * 3];
|
||||
template<uint Bits> struct stringify<Natural<Bits>> {
|
||||
stringify(Natural<Bits> source) { natural(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(uint_t<bits> source) { decimal(_data, source); }
|
||||
auto size() const -> uint { return strlen(_data); }
|
||||
char _data[1 + sizeof(uint64_t) * 3];
|
||||
};
|
||||
|
||||
//floating-point
|
||||
|
||||
template<> struct stringify<float> {
|
||||
char _data[256];
|
||||
stringify(float source) { real(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(float source) { real(_data, source); }
|
||||
char _data[256];
|
||||
};
|
||||
|
||||
template<> struct stringify<double> {
|
||||
char _data[256];
|
||||
stringify(double source) { real(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(double source) { real(_data, source); }
|
||||
char _data[256];
|
||||
};
|
||||
|
||||
template<> struct stringify<long double> {
|
||||
char _data[256];
|
||||
stringify(long double source) { real(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(long double source) { real(_data, source); }
|
||||
char _data[256];
|
||||
};
|
||||
|
||||
template<uint Bits> struct stringify<Real<Bits>> {
|
||||
stringify(Real<Bits> source) { real(_data, source); }
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> uint { return strlen(_data); }
|
||||
char _data[256];
|
||||
};
|
||||
|
||||
//arrays
|
||||
|
||||
template<> struct stringify<vector<uint8_t>> {
|
||||
vector<char> _text;
|
||||
auto data() const -> const char* { return _text.data(); }
|
||||
auto size() const -> unsigned { return _text.size(); }
|
||||
stringify(vector<uint8_t> source) {
|
||||
_text.resize(source.size());
|
||||
memory::copy(_text.data(), source.data(), source.size());
|
||||
}
|
||||
auto data() const -> const char* { return _text.data(); }
|
||||
auto size() const -> unsigned { return _text.size(); }
|
||||
vector<char> _text;
|
||||
};
|
||||
|
||||
template<> struct stringify<const vector<uint8_t>&> {
|
||||
vector<char> _text;
|
||||
auto data() const -> const char* { return _text.data(); }
|
||||
auto size() const -> unsigned { return _text.size(); }
|
||||
stringify(const vector<uint8_t>& source) {
|
||||
_text.resize(source.size());
|
||||
memory::copy(_text.data(), source.data(), source.size());
|
||||
}
|
||||
auto data() const -> const char* { return _text.data(); }
|
||||
auto size() const -> unsigned { return _text.size(); }
|
||||
vector<char> _text;
|
||||
};
|
||||
|
||||
//char arrays
|
||||
|
||||
template<> struct stringify<char*> {
|
||||
const char* _data;
|
||||
stringify(char* source) : _data(source ? source : "") {}
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(char* source) : _data(source ? source : "") {}
|
||||
const char* _data;
|
||||
};
|
||||
|
||||
template<> struct stringify<const char*> {
|
||||
const char* _data;
|
||||
stringify(const char* source) : _data(source ? source : "") {}
|
||||
auto data() const -> const char* { return _data; }
|
||||
auto size() const -> unsigned { return strlen(_data); }
|
||||
stringify(const char* source) : _data(source ? source : "") {}
|
||||
const char* _data;
|
||||
};
|
||||
|
||||
//strings
|
||||
|
||||
template<> struct stringify<string> {
|
||||
const string& _text;
|
||||
stringify(const string& source) : _text(source) {}
|
||||
auto data() const -> const char* { return _text.data(); }
|
||||
auto size() const -> unsigned { return _text.size(); }
|
||||
stringify(const string& source) : _text(source) {}
|
||||
const string& _text;
|
||||
};
|
||||
|
||||
template<> struct stringify<const string&> {
|
||||
const string& _text;
|
||||
stringify(const string& source) : _text(source) {}
|
||||
auto data() const -> const char* { return _text.data(); }
|
||||
auto size() const -> unsigned { return _text.size(); }
|
||||
stringify(const string& source) : _text(source) {}
|
||||
const string& _text;
|
||||
};
|
||||
|
||||
template<> struct stringify<string_view> {
|
||||
const string_view& _view;
|
||||
stringify(const string_view& source) : _view(source) {}
|
||||
auto data() const -> const char* { return _view.data(); }
|
||||
auto size() const -> unsigned { return _view.size(); }
|
||||
stringify(const string_view& source) : _view(source) {}
|
||||
const string_view& _view;
|
||||
};
|
||||
|
||||
template<> struct stringify<const string_view&> {
|
||||
const string_view& _view;
|
||||
stringify(const string_view& source) : _view(source) {}
|
||||
auto data() const -> const char* { return _view.data(); }
|
||||
auto size() const -> unsigned { return _view.size(); }
|
||||
stringify(const string_view& source) : _view(source) {}
|
||||
const string_view& _view;
|
||||
};
|
||||
|
||||
//
|
||||
|
|
|
@ -6,9 +6,9 @@ auto string::date(time_t timestamp) -> string {
|
|||
if(timestamp == 0) timestamp = ::time(nullptr);
|
||||
tm* info = localtime(×tamp);
|
||||
return {
|
||||
nall::decimal(1900 + info->tm_year, 4L), "-",
|
||||
nall::decimal(1 + info->tm_mon, 2L), "-",
|
||||
nall::decimal(info->tm_mday, 2L)
|
||||
nall::natural(1900 + info->tm_year, 4L), "-",
|
||||
nall::natural(1 + info->tm_mon, 2L), "-",
|
||||
nall::natural(info->tm_mday, 2L)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,9 @@ auto string::time(time_t timestamp) -> string {
|
|||
if(timestamp == 0) timestamp = ::time(nullptr);
|
||||
tm* info = localtime(×tamp);
|
||||
return {
|
||||
nall::decimal(info->tm_hour, 2L), ":",
|
||||
nall::decimal(info->tm_min, 2L), ":",
|
||||
nall::decimal(info->tm_sec, 2L)
|
||||
nall::natural(info->tm_hour, 2L), ":",
|
||||
nall::natural(info->tm_min, 2L), ":",
|
||||
nall::natural(info->tm_sec, 2L)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ auto integer(intmax value, long precision, char padchar) -> string {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
auto decimal(uintmax value, long precision, char padchar) -> string {
|
||||
auto natural(uintmax value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax) * 3);
|
||||
char* p = buffer.get();
|
||||
|
|
|
@ -111,7 +111,7 @@ auto integer(char* result, intmax value) -> char* {
|
|||
return result;
|
||||
}
|
||||
|
||||
auto decimal(char* result, uintmax value) -> char* {
|
||||
auto natural(char* result, uintmax value) -> char* {
|
||||
char buffer[64];
|
||||
uint size = 0;
|
||||
|
||||
|
|
320
nall/varint.hpp
320
nall/varint.hpp
|
@ -1,7 +1,7 @@
|
|||
#ifndef NALL_VARINT_HPP
|
||||
#define NALL_VARINT_HPP
|
||||
|
||||
#include <nall/bit.hpp>
|
||||
#include <nall/primitives.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
|
@ -49,70 +49,6 @@ struct varint {
|
|||
}
|
||||
};
|
||||
|
||||
template<unsigned bits> struct uint_t {
|
||||
using type_t = type_if<expression<bits <= 8 * sizeof(unsigned)>, unsigned, uintmax_t>;
|
||||
|
||||
inline operator type_t() const { return data; }
|
||||
inline auto operator ++(int) { type_t r = data; data = uclip<bits>(data + 1); return r; }
|
||||
inline auto operator --(int) { type_t r = data; data = uclip<bits>(data - 1); return r; }
|
||||
inline auto operator ++() { return data = uclip<bits>(data + 1); }
|
||||
inline auto operator --() { return data = uclip<bits>(data - 1); }
|
||||
inline auto operator =(const type_t i) { return data = uclip<bits>(i); }
|
||||
inline auto operator |=(const type_t i) { return data = uclip<bits>(data | i); }
|
||||
inline auto operator ^=(const type_t i) { return data = uclip<bits>(data ^ i); }
|
||||
inline auto operator &=(const type_t i) { return data = uclip<bits>(data & i); }
|
||||
inline auto operator<<=(const type_t i) { return data = uclip<bits>(data << i); }
|
||||
inline auto operator>>=(const type_t i) { return data = uclip<bits>(data >> i); }
|
||||
inline auto operator +=(const type_t i) { return data = uclip<bits>(data + i); }
|
||||
inline auto operator -=(const type_t i) { return data = uclip<bits>(data - i); }
|
||||
inline auto operator *=(const type_t i) { return data = uclip<bits>(data * i); }
|
||||
inline auto operator /=(const type_t i) { return data = uclip<bits>(data / i); }
|
||||
inline auto operator %=(const type_t i) { return data = uclip<bits>(data % i); }
|
||||
|
||||
inline uint_t() : data(0) {}
|
||||
inline uint_t(const type_t i) : data(uclip<bits>(i)) {}
|
||||
|
||||
template<unsigned s> inline uint_t(const uint_t<s>& i) : data(uclip<bits>(i)) {}
|
||||
template<unsigned s> inline auto operator=(const uint_t<s>& i) { return data = uclip<bits>((type_t)i); }
|
||||
|
||||
auto serialize(serializer& s) { s(data); }
|
||||
|
||||
private:
|
||||
type_t data;
|
||||
};
|
||||
|
||||
template<unsigned bits> struct int_t {
|
||||
using type_t = type_if<expression<bits <= 8 * sizeof(signed)>, signed, intmax_t>;
|
||||
|
||||
inline operator type_t() const { return data; }
|
||||
inline auto operator ++(int) { type_t r = data; data = sclip<bits>(data + 1); return r; }
|
||||
inline auto operator --(int) { type_t r = data; data = sclip<bits>(data - 1); return r; }
|
||||
inline auto operator ++() { return data = sclip<bits>(data + 1); }
|
||||
inline auto operator --() { return data = sclip<bits>(data - 1); }
|
||||
inline auto operator =(const type_t i) { return data = sclip<bits>(i); }
|
||||
inline auto operator |=(const type_t i) { return data = sclip<bits>(data | i); }
|
||||
inline auto operator ^=(const type_t i) { return data = sclip<bits>(data ^ i); }
|
||||
inline auto operator &=(const type_t i) { return data = sclip<bits>(data & i); }
|
||||
inline auto operator<<=(const type_t i) { return data = sclip<bits>(data << i); }
|
||||
inline auto operator>>=(const type_t i) { return data = sclip<bits>(data >> i); }
|
||||
inline auto operator +=(const type_t i) { return data = sclip<bits>(data + i); }
|
||||
inline auto operator -=(const type_t i) { return data = sclip<bits>(data - i); }
|
||||
inline auto operator *=(const type_t i) { return data = sclip<bits>(data * i); }
|
||||
inline auto operator /=(const type_t i) { return data = sclip<bits>(data / i); }
|
||||
inline auto operator %=(const type_t i) { return data = sclip<bits>(data % i); }
|
||||
|
||||
inline int_t() : data(0) {}
|
||||
inline int_t(const type_t i) : data(sclip<bits>(i)) {}
|
||||
|
||||
template<unsigned s> inline int_t(const int_t<s>& i) : data(sclip<bits>(i)) {}
|
||||
template<unsigned s> inline auto operator=(const int_t<s>& i) { return data = sclip<bits>((type_t)i); }
|
||||
|
||||
auto serialize(serializer& s) { s(data); }
|
||||
|
||||
private:
|
||||
type_t data;
|
||||
};
|
||||
|
||||
template<typename type_t> struct varuint_t {
|
||||
inline operator type_t() const { return data; }
|
||||
inline auto operator ++(int) { type_t r = data; data = (data + 1) & mask; return r; }
|
||||
|
@ -144,132 +80,134 @@ private:
|
|||
|
||||
}
|
||||
|
||||
using int1 = nall::int_t<1>;
|
||||
using int2 = nall::int_t<2>;
|
||||
using int3 = nall::int_t<3>;
|
||||
using int4 = nall::int_t<4>;
|
||||
using int5 = nall::int_t<5>;
|
||||
using int6 = nall::int_t<6>;
|
||||
using int7 = nall::int_t<7>;
|
||||
using int1 = nall::Integer< 1>;
|
||||
using int2 = nall::Integer< 2>;
|
||||
using int3 = nall::Integer< 3>;
|
||||
using int4 = nall::Integer< 4>;
|
||||
using int5 = nall::Integer< 5>;
|
||||
using int6 = nall::Integer< 6>;
|
||||
using int7 = nall::Integer< 7>;
|
||||
//using int8 = nall::Integer< 8>;
|
||||
using int9 = nall::Integer< 9>;
|
||||
using int10 = nall::Integer<10>;
|
||||
using int11 = nall::Integer<11>;
|
||||
using int12 = nall::Integer<12>;
|
||||
using int13 = nall::Integer<13>;
|
||||
using int14 = nall::Integer<14>;
|
||||
using int15 = nall::Integer<15>;
|
||||
//using int16 = nall::Integer<16>;
|
||||
using int17 = nall::Integer<17>;
|
||||
using int18 = nall::Integer<18>;
|
||||
using int19 = nall::Integer<19>;
|
||||
using int20 = nall::Integer<20>;
|
||||
using int21 = nall::Integer<21>;
|
||||
using int22 = nall::Integer<22>;
|
||||
using int23 = nall::Integer<23>;
|
||||
using int24 = nall::Integer<24>;
|
||||
using int25 = nall::Integer<25>;
|
||||
using int26 = nall::Integer<26>;
|
||||
using int27 = nall::Integer<27>;
|
||||
using int28 = nall::Integer<28>;
|
||||
using int29 = nall::Integer<29>;
|
||||
using int30 = nall::Integer<30>;
|
||||
using int31 = nall::Integer<31>;
|
||||
//using int32 = nall::Integer<32>;
|
||||
using int33 = nall::Integer<33>;
|
||||
using int34 = nall::Integer<34>;
|
||||
using int35 = nall::Integer<35>;
|
||||
using int36 = nall::Integer<36>;
|
||||
using int37 = nall::Integer<37>;
|
||||
using int38 = nall::Integer<38>;
|
||||
using int39 = nall::Integer<39>;
|
||||
using int40 = nall::Integer<40>;
|
||||
using int41 = nall::Integer<41>;
|
||||
using int42 = nall::Integer<42>;
|
||||
using int43 = nall::Integer<43>;
|
||||
using int44 = nall::Integer<44>;
|
||||
using int45 = nall::Integer<45>;
|
||||
using int46 = nall::Integer<46>;
|
||||
using int47 = nall::Integer<47>;
|
||||
using int48 = nall::Integer<48>;
|
||||
using int49 = nall::Integer<49>;
|
||||
using int50 = nall::Integer<50>;
|
||||
using int51 = nall::Integer<51>;
|
||||
using int52 = nall::Integer<52>;
|
||||
using int53 = nall::Integer<53>;
|
||||
using int54 = nall::Integer<54>;
|
||||
using int55 = nall::Integer<55>;
|
||||
using int56 = nall::Integer<56>;
|
||||
using int57 = nall::Integer<57>;
|
||||
using int58 = nall::Integer<58>;
|
||||
using int59 = nall::Integer<59>;
|
||||
using int60 = nall::Integer<60>;
|
||||
using int61 = nall::Integer<61>;
|
||||
using int62 = nall::Integer<62>;
|
||||
using int63 = nall::Integer<63>;
|
||||
//using int64 = nall::Integer<64>;
|
||||
|
||||
using int9 = nall::int_t<9>;
|
||||
using int10 = nall::int_t<10>;
|
||||
using int11 = nall::int_t<11>;
|
||||
using int12 = nall::int_t<12>;
|
||||
using int13 = nall::int_t<13>;
|
||||
using int14 = nall::int_t<14>;
|
||||
using int15 = nall::int_t<15>;
|
||||
|
||||
using int17 = nall::int_t<17>;
|
||||
using int18 = nall::int_t<18>;
|
||||
using int19 = nall::int_t<19>;
|
||||
using int20 = nall::int_t<20>;
|
||||
using int21 = nall::int_t<21>;
|
||||
using int22 = nall::int_t<22>;
|
||||
using int23 = nall::int_t<23>;
|
||||
using int24 = nall::int_t<24>;
|
||||
using int25 = nall::int_t<25>;
|
||||
using int26 = nall::int_t<26>;
|
||||
using int27 = nall::int_t<27>;
|
||||
using int28 = nall::int_t<28>;
|
||||
using int29 = nall::int_t<29>;
|
||||
using int30 = nall::int_t<30>;
|
||||
using int31 = nall::int_t<31>;
|
||||
|
||||
using int33 = nall::int_t<33>;
|
||||
using int34 = nall::int_t<34>;
|
||||
using int35 = nall::int_t<35>;
|
||||
using int36 = nall::int_t<36>;
|
||||
using int37 = nall::int_t<37>;
|
||||
using int38 = nall::int_t<38>;
|
||||
using int39 = nall::int_t<39>;
|
||||
using int40 = nall::int_t<40>;
|
||||
using int41 = nall::int_t<41>;
|
||||
using int42 = nall::int_t<42>;
|
||||
using int43 = nall::int_t<43>;
|
||||
using int44 = nall::int_t<44>;
|
||||
using int45 = nall::int_t<45>;
|
||||
using int46 = nall::int_t<46>;
|
||||
using int47 = nall::int_t<47>;
|
||||
using int48 = nall::int_t<48>;
|
||||
using int49 = nall::int_t<49>;
|
||||
using int50 = nall::int_t<50>;
|
||||
using int51 = nall::int_t<51>;
|
||||
using int52 = nall::int_t<52>;
|
||||
using int53 = nall::int_t<53>;
|
||||
using int54 = nall::int_t<54>;
|
||||
using int55 = nall::int_t<55>;
|
||||
using int56 = nall::int_t<56>;
|
||||
using int57 = nall::int_t<57>;
|
||||
using int58 = nall::int_t<58>;
|
||||
using int59 = nall::int_t<59>;
|
||||
using int60 = nall::int_t<60>;
|
||||
using int61 = nall::int_t<61>;
|
||||
using int62 = nall::int_t<62>;
|
||||
using int63 = nall::int_t<63>;
|
||||
|
||||
using uint1 = nall::uint_t<1>;
|
||||
using uint2 = nall::uint_t<2>;
|
||||
using uint3 = nall::uint_t<3>;
|
||||
using uint4 = nall::uint_t<4>;
|
||||
using uint5 = nall::uint_t<5>;
|
||||
using uint6 = nall::uint_t<6>;
|
||||
using uint7 = nall::uint_t<7>;
|
||||
|
||||
using uint9 = nall::uint_t<9>;
|
||||
using uint10 = nall::uint_t<10>;
|
||||
using uint11 = nall::uint_t<11>;
|
||||
using uint12 = nall::uint_t<12>;
|
||||
using uint13 = nall::uint_t<13>;
|
||||
using uint14 = nall::uint_t<14>;
|
||||
using uint15 = nall::uint_t<15>;
|
||||
|
||||
using uint17 = nall::uint_t<17>;
|
||||
using uint18 = nall::uint_t<18>;
|
||||
using uint19 = nall::uint_t<19>;
|
||||
using uint20 = nall::uint_t<20>;
|
||||
using uint21 = nall::uint_t<21>;
|
||||
using uint22 = nall::uint_t<22>;
|
||||
using uint23 = nall::uint_t<23>;
|
||||
using uint24 = nall::uint_t<24>;
|
||||
using uint25 = nall::uint_t<25>;
|
||||
using uint26 = nall::uint_t<26>;
|
||||
using uint27 = nall::uint_t<27>;
|
||||
using uint28 = nall::uint_t<28>;
|
||||
using uint29 = nall::uint_t<29>;
|
||||
using uint30 = nall::uint_t<30>;
|
||||
using uint31 = nall::uint_t<31>;
|
||||
|
||||
using uint33 = nall::uint_t<33>;
|
||||
using uint34 = nall::uint_t<34>;
|
||||
using uint35 = nall::uint_t<35>;
|
||||
using uint36 = nall::uint_t<36>;
|
||||
using uint37 = nall::uint_t<37>;
|
||||
using uint38 = nall::uint_t<38>;
|
||||
using uint39 = nall::uint_t<39>;
|
||||
using uint40 = nall::uint_t<40>;
|
||||
using uint41 = nall::uint_t<41>;
|
||||
using uint42 = nall::uint_t<42>;
|
||||
using uint43 = nall::uint_t<43>;
|
||||
using uint44 = nall::uint_t<44>;
|
||||
using uint45 = nall::uint_t<45>;
|
||||
using uint46 = nall::uint_t<46>;
|
||||
using uint47 = nall::uint_t<47>;
|
||||
using uint48 = nall::uint_t<48>;
|
||||
using uint49 = nall::uint_t<49>;
|
||||
using uint50 = nall::uint_t<50>;
|
||||
using uint51 = nall::uint_t<51>;
|
||||
using uint52 = nall::uint_t<52>;
|
||||
using uint53 = nall::uint_t<53>;
|
||||
using uint54 = nall::uint_t<54>;
|
||||
using uint55 = nall::uint_t<55>;
|
||||
using uint56 = nall::uint_t<56>;
|
||||
using uint57 = nall::uint_t<57>;
|
||||
using uint58 = nall::uint_t<58>;
|
||||
using uint59 = nall::uint_t<59>;
|
||||
using uint60 = nall::uint_t<60>;
|
||||
using uint61 = nall::uint_t<61>;
|
||||
using uint62 = nall::uint_t<62>;
|
||||
using uint63 = nall::uint_t<63>;
|
||||
using uint1 = nall::Natural< 1>;
|
||||
using uint2 = nall::Natural< 2>;
|
||||
using uint3 = nall::Natural< 3>;
|
||||
using uint4 = nall::Natural< 4>;
|
||||
using uint5 = nall::Natural< 5>;
|
||||
using uint6 = nall::Natural< 6>;
|
||||
using uint7 = nall::Natural< 7>;
|
||||
//using uint8 = nall::Natural< 8>;
|
||||
using uint9 = nall::Natural< 9>;
|
||||
using uint10 = nall::Natural<10>;
|
||||
using uint11 = nall::Natural<11>;
|
||||
using uint12 = nall::Natural<12>;
|
||||
using uint13 = nall::Natural<13>;
|
||||
using uint14 = nall::Natural<14>;
|
||||
using uint15 = nall::Natural<15>;
|
||||
//using uint16 = nall::Natural<16>;
|
||||
using uint17 = nall::Natural<17>;
|
||||
using uint18 = nall::Natural<18>;
|
||||
using uint19 = nall::Natural<19>;
|
||||
using uint20 = nall::Natural<20>;
|
||||
using uint21 = nall::Natural<21>;
|
||||
using uint22 = nall::Natural<22>;
|
||||
using uint23 = nall::Natural<23>;
|
||||
using uint24 = nall::Natural<24>;
|
||||
using uint25 = nall::Natural<25>;
|
||||
using uint26 = nall::Natural<26>;
|
||||
using uint27 = nall::Natural<27>;
|
||||
using uint28 = nall::Natural<28>;
|
||||
using uint29 = nall::Natural<29>;
|
||||
using uint30 = nall::Natural<30>;
|
||||
using uint31 = nall::Natural<31>;
|
||||
//using uint32 = nall::Natural<32>;
|
||||
using uint33 = nall::Natural<33>;
|
||||
using uint34 = nall::Natural<34>;
|
||||
using uint35 = nall::Natural<35>;
|
||||
using uint36 = nall::Natural<36>;
|
||||
using uint37 = nall::Natural<37>;
|
||||
using uint38 = nall::Natural<38>;
|
||||
using uint39 = nall::Natural<39>;
|
||||
using uint40 = nall::Natural<40>;
|
||||
using uint41 = nall::Natural<41>;
|
||||
using uint42 = nall::Natural<42>;
|
||||
using uint43 = nall::Natural<43>;
|
||||
using uint44 = nall::Natural<44>;
|
||||
using uint45 = nall::Natural<45>;
|
||||
using uint46 = nall::Natural<46>;
|
||||
using uint47 = nall::Natural<47>;
|
||||
using uint48 = nall::Natural<48>;
|
||||
using uint49 = nall::Natural<49>;
|
||||
using uint50 = nall::Natural<50>;
|
||||
using uint51 = nall::Natural<51>;
|
||||
using uint52 = nall::Natural<52>;
|
||||
using uint53 = nall::Natural<53>;
|
||||
using uint54 = nall::Natural<54>;
|
||||
using uint55 = nall::Natural<55>;
|
||||
using uint56 = nall::Natural<56>;
|
||||
using uint57 = nall::Natural<57>;
|
||||
using uint58 = nall::Natural<58>;
|
||||
using uint59 = nall::Natural<59>;
|
||||
using uint60 = nall::Natural<60>;
|
||||
using uint61 = nall::Natural<61>;
|
||||
using uint62 = nall::Natural<62>;
|
||||
using uint63 = nall::Natural<63>;
|
||||
//using uint64 = nall::Natural<64>;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <sfc/sfc.hpp>
|
||||
|
||||
#define CPU_CPP
|
||||
namespace SuperFamicom {
|
||||
|
||||
CPU cpu;
|
||||
|
@ -11,10 +10,14 @@ CPU cpu;
|
|||
#include "mmio.cpp"
|
||||
#include "timing.cpp"
|
||||
|
||||
void CPU::step(unsigned clocks) {
|
||||
CPU::CPU() : queue(512, {&CPU::queue_event, this}) {
|
||||
PPUcounter::scanline = {&CPU::scanline, this};
|
||||
}
|
||||
|
||||
auto CPU::step(uint clocks) -> void {
|
||||
smp.clock -= clocks * (uint64)smp.frequency;
|
||||
ppu.clock -= clocks;
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
for(uint i = 0; i < coprocessors.size(); i++) {
|
||||
auto& chip = *coprocessors[i];
|
||||
chip.clock -= clocks * (uint64)chip.frequency;
|
||||
}
|
||||
|
@ -23,7 +26,7 @@ void CPU::step(unsigned clocks) {
|
|||
synchronizeDevices();
|
||||
}
|
||||
|
||||
void CPU::synchronizeSMP() {
|
||||
auto CPU::synchronizeSMP() -> void {
|
||||
if(SMP::Threaded == true) {
|
||||
if(smp.clock < 0) co_switch(smp.thread);
|
||||
} else {
|
||||
|
@ -31,7 +34,7 @@ void CPU::synchronizeSMP() {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::synchronizePPU() {
|
||||
auto CPU::synchronizePPU() -> void {
|
||||
if(PPU::Threaded == true) {
|
||||
if(ppu.clock < 0) co_switch(ppu.thread);
|
||||
} else {
|
||||
|
@ -39,21 +42,21 @@ void CPU::synchronizePPU() {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::synchronizeCoprocessors() {
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
auto CPU::synchronizeCoprocessors() -> void {
|
||||
for(uint i = 0; i < coprocessors.size(); i++) {
|
||||
auto& chip = *coprocessors[i];
|
||||
if(chip.clock < 0) co_switch(chip.thread);
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::synchronizeDevices() {
|
||||
auto CPU::synchronizeDevices() -> void {
|
||||
if(device.controllerPort1->clock < 0) co_switch(device.controllerPort1->thread);
|
||||
if(device.controllerPort2->clock < 0) co_switch(device.controllerPort2->thread);
|
||||
}
|
||||
|
||||
void CPU::Enter() { cpu.enter(); }
|
||||
auto CPU::Enter() -> void { cpu.enter(); }
|
||||
|
||||
void CPU::enter() {
|
||||
auto CPU::enter() -> void {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
|
@ -76,9 +79,9 @@ void CPU::enter() {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::enable() {
|
||||
function<uint8 (unsigned)> reader = {&CPU::mmio_read, (CPU*)&cpu};
|
||||
function<void (unsigned, uint8)> writer = {&CPU::mmio_write, (CPU*)&cpu};
|
||||
auto CPU::enable() -> void {
|
||||
function<uint8 (uint)> reader = {&CPU::mmio_read, (CPU*)&cpu};
|
||||
function<void (uint, uint8)> writer = {&CPU::mmio_write, (CPU*)&cpu};
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x2183);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x2183);
|
||||
|
@ -92,15 +95,15 @@ void CPU::enable() {
|
|||
bus.map(reader, writer, 0x00, 0x3f, 0x4300, 0x437f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x4300, 0x437f);
|
||||
|
||||
reader = [](unsigned addr) { return cpu.wram[addr]; };
|
||||
writer = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
reader = [](uint addr) { return cpu.wram[addr]; };
|
||||
writer = [](uint addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x0000, 0x1fff, 0x002000);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x0000, 0x1fff, 0x002000);
|
||||
bus.map(reader, writer, 0x7e, 0x7f, 0x0000, 0xffff, 0x020000);
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
auto CPU::power() -> void {
|
||||
regs.a = 0x0000;
|
||||
regs.x = 0x0000;
|
||||
regs.y = 0x0000;
|
||||
|
@ -109,7 +112,7 @@ void CPU::power() {
|
|||
reset();
|
||||
}
|
||||
|
||||
void CPU::reset() {
|
||||
auto CPU::reset() -> void {
|
||||
create(Enter, system.cpuFrequency());
|
||||
coprocessors.reset();
|
||||
PPUcounter::reset();
|
||||
|
@ -166,11 +169,4 @@ void CPU::reset() {
|
|||
dma_reset();
|
||||
}
|
||||
|
||||
CPU::CPU() : queue(512, {&CPU::queue_event, this}) {
|
||||
PPUcounter::scanline = {&CPU::scanline, this};
|
||||
}
|
||||
|
||||
CPU::~CPU() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,72 +1,74 @@
|
|||
struct CPU : Processor::R65816, Thread, public PPUcounter {
|
||||
uint8 wram[128 * 1024];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
vector<Thread*> coprocessors;
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronizeSMP();
|
||||
void synchronizePPU();
|
||||
void synchronizeCoprocessors();
|
||||
void synchronizeDevices();
|
||||
|
||||
uint8 pio();
|
||||
bool joylatch();
|
||||
bool interrupt_pending();
|
||||
uint8 port_read(uint8 port);
|
||||
void port_write(uint8 port, uint8 data);
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
void op_io();
|
||||
uint8 op_read(unsigned addr);
|
||||
void op_write(unsigned addr, uint8 data);
|
||||
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
CPU();
|
||||
~CPU();
|
||||
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto synchronizeSMP() -> void;
|
||||
auto synchronizePPU() -> void;
|
||||
auto synchronizeCoprocessors() -> void;
|
||||
auto synchronizeDevices() -> void;
|
||||
|
||||
auto pio() -> uint8;
|
||||
auto joylatch() -> bool;
|
||||
auto interrupt_pending() -> bool;
|
||||
auto port_read(uint8 port) -> uint8;
|
||||
auto port_write(uint8 port, uint8 data) -> void;
|
||||
auto mmio_read(uint addr) -> uint8;
|
||||
auto mmio_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto op_io() -> void;
|
||||
auto op_read(uint addr) -> uint8;
|
||||
auto op_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto enter() -> void;
|
||||
auto enable() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint8 wram[128 * 1024];
|
||||
vector<Thread*> coprocessors;
|
||||
|
||||
private:
|
||||
//cpu
|
||||
static void Enter();
|
||||
static auto Enter() -> void;
|
||||
|
||||
//timing
|
||||
auto queue_event(uint id) -> void;
|
||||
auto last_cycle() -> void;
|
||||
auto add_clocks(uint clocks) -> void;
|
||||
auto scanline() -> void;
|
||||
auto run_auto_joypad_poll() -> void;
|
||||
|
||||
struct QueueEvent {
|
||||
enum : unsigned {
|
||||
enum : uint {
|
||||
DramRefresh,
|
||||
HdmaRun,
|
||||
};
|
||||
};
|
||||
nall::priority_queue<unsigned> queue;
|
||||
void queue_event(unsigned id);
|
||||
void last_cycle();
|
||||
void add_clocks(unsigned clocks);
|
||||
void scanline();
|
||||
void run_auto_joypad_poll();
|
||||
nall::priority_queue<uint> queue;
|
||||
|
||||
//memory
|
||||
unsigned speed(unsigned addr) const;
|
||||
auto speed(uint addr) const -> uint;
|
||||
|
||||
//dma
|
||||
bool dma_transfer_valid(uint8 bbus, unsigned abus);
|
||||
bool dma_addr_valid(unsigned abus);
|
||||
uint8 dma_read(unsigned abus);
|
||||
void dma_write(bool valid, unsigned addr, uint8 data);
|
||||
void dma_transfer(bool direction, uint8 bbus, unsigned abus);
|
||||
uint8 dma_bbus(unsigned i, unsigned index);
|
||||
unsigned dma_addr(unsigned i);
|
||||
unsigned hdma_addr(unsigned i);
|
||||
unsigned hdma_iaddr(unsigned i);
|
||||
void dma_run();
|
||||
bool hdma_active_after(unsigned i);
|
||||
void hdma_update(unsigned i);
|
||||
void hdma_run();
|
||||
void hdma_init();
|
||||
void dma_reset();
|
||||
auto dma_transfer_valid(uint8 bbus, uint abus) -> bool;
|
||||
auto dma_addr_valid(uint abus) -> bool;
|
||||
auto dma_read(uint abus) -> uint8;
|
||||
auto dma_write(bool valid, uint addr, uint8 data) -> void;
|
||||
auto dma_transfer(bool direction, uint8 bbus, uint abus) -> void;
|
||||
auto dma_bbus(uint i, uint index) -> uint8;
|
||||
auto dma_addr(uint i) -> uint;
|
||||
auto hdma_addr(uint i) -> uint;
|
||||
auto hdma_iaddr(uint i) -> uint;
|
||||
auto dma_run() -> void;
|
||||
auto hdma_active_after(uint i) -> bool;
|
||||
auto hdma_update(uint i) -> void;
|
||||
auto hdma_run() -> void;
|
||||
auto hdma_init() -> void;
|
||||
auto dma_reset() -> void;
|
||||
|
||||
//registers
|
||||
uint8 port_data[4];
|
||||
|
@ -114,7 +116,7 @@ private:
|
|||
bool irq_lock;
|
||||
bool hdma_pending;
|
||||
|
||||
unsigned wram_addr;
|
||||
uint wram_addr;
|
||||
|
||||
bool joypad_strobe_latch;
|
||||
|
||||
|
@ -133,7 +135,7 @@ private:
|
|||
uint16 htime;
|
||||
uint16 vtime;
|
||||
|
||||
unsigned rom_speed;
|
||||
uint rom_speed;
|
||||
|
||||
uint16 rddiv;
|
||||
uint16 rdmpy;
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
bool CPU::dma_transfer_valid(uint8 bbus, unsigned abus) {
|
||||
auto CPU::dma_transfer_valid(uint8 bbus, uint abus) -> bool {
|
||||
//transfers from WRAM to WRAM are invalid; chip only has one address bus
|
||||
if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPU::dma_addr_valid(unsigned abus) {
|
||||
auto CPU::dma_addr_valid(uint abus) -> bool {
|
||||
//A-bus access to B-bus or S-CPU registers are invalid
|
||||
if((abus & 0x40ff00) == 0x2100) return false; //$[00-3f|80-bf]:[2100-21ff]
|
||||
if((abus & 0x40fe00) == 0x4000) return false; //$[00-3f|80-bf]:[4000-41ff]
|
||||
|
@ -15,16 +13,16 @@ bool CPU::dma_addr_valid(unsigned abus) {
|
|||
return true;
|
||||
}
|
||||
|
||||
uint8 CPU::dma_read(unsigned abus) {
|
||||
auto CPU::dma_read(uint abus) -> uint8 {
|
||||
if(dma_addr_valid(abus) == false) return 0x00;
|
||||
return bus.read(abus);
|
||||
}
|
||||
|
||||
void CPU::dma_write(bool valid, unsigned addr, uint8 data) {
|
||||
auto CPU::dma_write(bool valid, uint addr, uint8 data) -> void {
|
||||
if(valid) bus.write(addr, data);
|
||||
}
|
||||
|
||||
void CPU::dma_transfer(bool direction, uint8 bbus, unsigned abus) {
|
||||
auto CPU::dma_transfer(bool direction, uint8 bbus, uint abus) -> void {
|
||||
if(direction == 0) {
|
||||
uint8 data = dma_read(abus);
|
||||
add_clocks(8);
|
||||
|
@ -36,7 +34,7 @@ void CPU::dma_transfer(bool direction, uint8 bbus, unsigned abus) {
|
|||
}
|
||||
}
|
||||
|
||||
uint8 CPU::dma_bbus(unsigned i, unsigned index) {
|
||||
auto CPU::dma_bbus(uint i, uint index) -> uint8 {
|
||||
switch(channel[i].transfer_mode) { default:
|
||||
case 0: return (channel[i].dest_addr); //0
|
||||
case 1: return (channel[i].dest_addr + (index & 1)); //0,1
|
||||
|
@ -49,8 +47,8 @@ uint8 CPU::dma_bbus(unsigned i, unsigned index) {
|
|||
}
|
||||
}
|
||||
|
||||
unsigned CPU::dma_addr(unsigned i) {
|
||||
unsigned result = (channel[i].source_bank << 16) | (channel[i].source_addr);
|
||||
auto CPU::dma_addr(uint i) -> uint {
|
||||
uint result = (channel[i].source_bank << 16) | (channel[i].source_addr);
|
||||
|
||||
if(channel[i].fixed_transfer == false) {
|
||||
if(channel[i].reverse_transfer == false) {
|
||||
|
@ -63,22 +61,22 @@ unsigned CPU::dma_addr(unsigned i) {
|
|||
return result;
|
||||
}
|
||||
|
||||
unsigned CPU::hdma_addr(unsigned i) {
|
||||
auto CPU::hdma_addr(uint i) -> uint {
|
||||
return (channel[i].source_bank << 16) | (channel[i].hdma_addr++);
|
||||
}
|
||||
|
||||
unsigned CPU::hdma_iaddr(unsigned i) {
|
||||
auto CPU::hdma_iaddr(uint i) -> uint {
|
||||
return (channel[i].indirect_bank << 16) | (channel[i].indirect_addr++);
|
||||
}
|
||||
|
||||
void CPU::dma_run() {
|
||||
auto CPU::dma_run() -> void {
|
||||
add_clocks(16);
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
if(channel[i].dma_enabled == false) continue;
|
||||
add_clocks(8);
|
||||
|
||||
unsigned index = 0;
|
||||
uint index = 0;
|
||||
do {
|
||||
dma_transfer(channel[i].direction, dma_bbus(i, index++), dma_addr(i));
|
||||
} while(channel[i].dma_enabled && --channel[i].transfer_size);
|
||||
|
@ -89,14 +87,14 @@ void CPU::dma_run() {
|
|||
status.irq_lock = true;
|
||||
}
|
||||
|
||||
bool CPU::hdma_active_after(unsigned i) {
|
||||
for(unsigned n = i + 1; i < 8; i++) {
|
||||
auto CPU::hdma_active_after(uint i) -> bool {
|
||||
for(uint n = i + 1; i < 8; i++) {
|
||||
if(channel[i].hdma_enabled && !channel[i].hdma_completed) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CPU::hdma_update(unsigned i) {
|
||||
auto CPU::hdma_update(uint i) -> void {
|
||||
if((channel[i].line_counter & 0x7f) == 0) {
|
||||
channel[i].line_counter = dma_read(hdma_addr(i));
|
||||
channel[i].hdma_completed = (channel[i].line_counter == 0);
|
||||
|
@ -117,29 +115,29 @@ void CPU::hdma_update(unsigned i) {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::hdma_run() {
|
||||
unsigned channels = 0;
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
auto CPU::hdma_run() -> void {
|
||||
uint channels = 0;
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
if(channel[i].hdma_enabled) channels++;
|
||||
}
|
||||
if(channels == 0) return;
|
||||
|
||||
add_clocks(16);
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
if(channel[i].hdma_enabled == false || channel[i].hdma_completed == true) continue;
|
||||
channel[i].dma_enabled = false;
|
||||
|
||||
if(channel[i].hdma_do_transfer) {
|
||||
static const unsigned transfer_length[] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
||||
unsigned length = transfer_length[channel[i].transfer_mode];
|
||||
for(unsigned index = 0; index < length; index++) {
|
||||
unsigned addr = channel[i].indirect == false ? hdma_addr(i) : hdma_iaddr(i);
|
||||
static const uint transfer_length[] = {1, 2, 2, 4, 4, 4, 2, 4};
|
||||
uint length = transfer_length[channel[i].transfer_mode];
|
||||
for(uint index = 0; index < length; index++) {
|
||||
uint addr = channel[i].indirect == false ? hdma_addr(i) : hdma_iaddr(i);
|
||||
dma_transfer(channel[i].direction, dma_bbus(i, index), addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
if(channel[i].hdma_enabled == false || channel[i].hdma_completed == true) continue;
|
||||
|
||||
channel[i].line_counter--;
|
||||
|
@ -150,8 +148,8 @@ void CPU::hdma_run() {
|
|||
status.irq_lock = true;
|
||||
}
|
||||
|
||||
void CPU::hdma_init() {
|
||||
unsigned channels = 0;
|
||||
auto CPU::hdma_init() -> void {
|
||||
uint channels = 0;
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
channel[i].hdma_completed = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
|
@ -160,7 +158,7 @@ void CPU::hdma_init() {
|
|||
if(channels == 0) return;
|
||||
|
||||
add_clocks(16);
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
if(!channel[i].hdma_enabled) continue;
|
||||
channel[i].dma_enabled = false;
|
||||
|
||||
|
@ -172,8 +170,8 @@ void CPU::hdma_init() {
|
|||
status.irq_lock = true;
|
||||
}
|
||||
|
||||
void CPU::dma_reset() {
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
auto CPU::dma_reset() -> void {
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
channel[i].dma_enabled = false;
|
||||
channel[i].hdma_enabled = false;
|
||||
|
||||
|
@ -200,5 +198,3 @@ void CPU::dma_reset() {
|
|||
channel[i].hdma_do_transfer = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,41 +1,39 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
uint8 CPU::pio() {
|
||||
auto CPU::pio() -> uint8 {
|
||||
return status.pio;
|
||||
}
|
||||
|
||||
bool CPU::joylatch() {
|
||||
auto CPU::joylatch() -> bool {
|
||||
return status.joypad_strobe_latch;
|
||||
}
|
||||
|
||||
bool CPU::interrupt_pending() {
|
||||
auto CPU::interrupt_pending() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8 CPU::port_read(uint8 port) {
|
||||
auto CPU::port_read(uint8 port) -> uint8 {
|
||||
return port_data[port & 3];
|
||||
}
|
||||
|
||||
void CPU::port_write(uint8 port, uint8 data) {
|
||||
auto CPU::port_write(uint8 port, uint8 data) -> void {
|
||||
port_data[port & 3] = data;
|
||||
}
|
||||
|
||||
void CPU::op_io() {
|
||||
auto CPU::op_io() -> void {
|
||||
add_clocks(6);
|
||||
}
|
||||
|
||||
uint8 CPU::op_read(unsigned addr) {
|
||||
auto CPU::op_read(uint addr) -> uint8 {
|
||||
regs.mdr = bus.read(addr);
|
||||
add_clocks(speed(addr));
|
||||
return regs.mdr;
|
||||
}
|
||||
|
||||
void CPU::op_write(unsigned addr, uint8 data) {
|
||||
auto CPU::op_write(uint addr, uint8 data) -> void {
|
||||
add_clocks(speed(addr));
|
||||
bus.write(addr, regs.mdr = data);
|
||||
}
|
||||
|
||||
unsigned CPU::speed(unsigned addr) const {
|
||||
auto CPU::speed(uint addr) const -> uint {
|
||||
if(addr & 0x408000) {
|
||||
if(addr & 0x800000) return status.rom_speed;
|
||||
return 8;
|
||||
|
@ -44,5 +42,3 @@ unsigned CPU::speed(unsigned addr) const {
|
|||
if((addr - 0x4000) & 0x7e00) return 6;
|
||||
return 12;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
uint8 CPU::mmio_read(unsigned addr) {
|
||||
auto CPU::mmio_read(uint addr) -> uint8 {
|
||||
if((addr & 0xffc0) == 0x2140) {
|
||||
synchronizeSMP();
|
||||
return smp.port_read(addr & 3);
|
||||
|
@ -97,7 +95,7 @@ uint8 CPU::mmio_read(unsigned addr) {
|
|||
return regs.mdr;
|
||||
}
|
||||
|
||||
void CPU::mmio_write(unsigned addr, uint8 data) {
|
||||
auto CPU::mmio_write(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xffc0) == 0x2140) {
|
||||
synchronizeSMP();
|
||||
port_write(addr & 3, data);
|
||||
|
@ -230,7 +228,7 @@ void CPU::mmio_write(unsigned addr, uint8 data) {
|
|||
}
|
||||
|
||||
if((addr & 0xff80) == 0x4300) {
|
||||
unsigned i = (addr >> 4) & 7;
|
||||
uint i = (addr >> 4) & 7;
|
||||
switch(addr & 0xff8f) {
|
||||
case 0x4300: {
|
||||
channel[i].direction = data & 0x80;
|
||||
|
@ -299,5 +297,3 @@ void CPU::mmio_write(unsigned addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::serialize(serializer& s) {
|
||||
auto CPU::serialize(serializer& s) -> void {
|
||||
R65816::serialize(s);
|
||||
Thread::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
@ -10,7 +8,7 @@ void CPU::serialize(serializer& s) {
|
|||
queue.serialize(s);
|
||||
s.array(port_data);
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
for(uint i = 0; i < 8; i++) {
|
||||
s.integer(channel[i].dma_enabled);
|
||||
s.integer(channel[i].hdma_enabled);
|
||||
|
||||
|
@ -82,5 +80,3 @@ void CPU::serialize(serializer& s) {
|
|||
s.integer(status.joy4l);
|
||||
s.integer(status.joy4h);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::queue_event(unsigned id) {
|
||||
auto CPU::queue_event(uint id) -> void {
|
||||
switch(id) {
|
||||
case QueueEvent::DramRefresh: return add_clocks(40);
|
||||
case QueueEvent::HdmaRun: return hdma_run();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::last_cycle() {
|
||||
auto CPU::last_cycle() -> void {
|
||||
if(status.irq_lock) {
|
||||
status.irq_lock = false;
|
||||
return;
|
||||
|
@ -26,18 +24,18 @@ void CPU::last_cycle() {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::add_clocks(unsigned clocks) {
|
||||
auto CPU::add_clocks(uint clocks) -> void {
|
||||
if(status.hirq_enabled) {
|
||||
if(status.virq_enabled) {
|
||||
unsigned cpu_time = vcounter() * 1364 + hcounter();
|
||||
unsigned irq_time = status.vtime * 1364 + status.htime * 4;
|
||||
unsigned framelines = (system.region() == System::Region::NTSC ? 262 : 312) + (ppu.interlace() && !field());
|
||||
uint cpu_time = vcounter() * 1364 + hcounter();
|
||||
uint irq_time = status.vtime * 1364 + status.htime * 4;
|
||||
uint framelines = (system.region() == System::Region::NTSC ? 262 : 312) + (ppu.interlace() && !field());
|
||||
if(cpu_time > irq_time) irq_time += framelines * 1364;
|
||||
bool irq_valid = status.irq_valid;
|
||||
status.irq_valid = cpu_time <= irq_time && cpu_time + clocks > irq_time;
|
||||
if(!irq_valid && status.irq_valid) status.irq_line = true;
|
||||
} else {
|
||||
unsigned irq_time = status.htime * 4;
|
||||
uint irq_time = status.htime * 4;
|
||||
if(hcounter() > irq_time) irq_time += 1364;
|
||||
bool irq_valid = status.irq_valid;
|
||||
status.irq_valid = hcounter() <= irq_time && hcounter() + clocks > irq_time;
|
||||
|
@ -58,7 +56,7 @@ void CPU::add_clocks(unsigned clocks) {
|
|||
step(clocks);
|
||||
}
|
||||
|
||||
void CPU::scanline() {
|
||||
auto CPU::scanline() -> void {
|
||||
synchronizeSMP();
|
||||
synchronizePPU();
|
||||
synchronizeCoprocessors();
|
||||
|
@ -86,14 +84,14 @@ void CPU::scanline() {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::run_auto_joypad_poll() {
|
||||
auto CPU::run_auto_joypad_poll() -> void {
|
||||
device.controllerPort1->latch(1);
|
||||
device.controllerPort2->latch(1);
|
||||
device.controllerPort1->latch(0);
|
||||
device.controllerPort2->latch(0);
|
||||
|
||||
uint16 joy1 = 0, joy2 = 0, joy3 = 0, joy4 = 0;
|
||||
for(unsigned i = 0; i < 16; i++) {
|
||||
for(uint i = 0; i < 16; i++) {
|
||||
uint8 port0 = device.controllerPort1->data();
|
||||
uint8 port1 = device.controllerPort2->data();
|
||||
|
||||
|
@ -115,5 +113,3 @@ void CPU::run_auto_joypad_poll() {
|
|||
status.joy4l = joy4;
|
||||
status.joy4h = joy4 >> 8;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,12 +1,30 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
#include "mode7.cpp"
|
||||
|
||||
unsigned PPU::Background::get_tile(unsigned hoffset, unsigned voffset) {
|
||||
unsigned tile_x = (hoffset & mask_x) >> tile_width;
|
||||
unsigned tile_y = (voffset & mask_y) >> tile_height;
|
||||
PPU::Background::Background(PPU& self, uint id) : self(self), id(id) {
|
||||
priority0_enable = true;
|
||||
priority1_enable = true;
|
||||
|
||||
unsigned tile_pos = ((tile_y & 0x1f) << 5) + (tile_x & 0x1f);
|
||||
opt_valid_bit = (id == ID::BG1 ? 0x2000 : id == ID::BG2 ? 0x4000 : 0x0000);
|
||||
|
||||
mosaic_table = new uint16*[16];
|
||||
for(uint m = 0; m < 16; m++) {
|
||||
mosaic_table[m] = new uint16[4096];
|
||||
for(uint x = 0; x < 4096; x++) {
|
||||
mosaic_table[m][x] = (x / (m + 1)) * (m + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PPU::Background::~Background() {
|
||||
for(uint m = 0; m < 16; m++) delete[] mosaic_table[m];
|
||||
delete[] mosaic_table;
|
||||
}
|
||||
|
||||
auto PPU::Background::get_tile(uint hoffset, uint voffset) -> uint {
|
||||
uint tile_x = (hoffset & mask_x) >> tile_width;
|
||||
uint tile_y = (voffset & mask_y) >> tile_height;
|
||||
|
||||
uint tile_pos = ((tile_y & 0x1f) << 5) + (tile_x & 0x1f);
|
||||
if(tile_y & 0x20) tile_pos += scy;
|
||||
if(tile_x & 0x20) tile_pos += scx;
|
||||
|
||||
|
@ -14,8 +32,8 @@ unsigned PPU::Background::get_tile(unsigned hoffset, unsigned voffset) {
|
|||
return (ppu.vram[tiledata_addr + 0] << 0) + (ppu.vram[tiledata_addr + 1] << 8);
|
||||
}
|
||||
|
||||
void PPU::Background::offset_per_tile(unsigned x, unsigned y, unsigned& hoffset, unsigned& voffset) {
|
||||
unsigned opt_x = (x + (hscroll & 7)), hval, vval;
|
||||
auto PPU::Background::offset_per_tile(uint x, uint y, uint& hoffset, uint& voffset) -> void {
|
||||
uint opt_x = (x + (hscroll & 7)), hval, vval;
|
||||
if(opt_x >= 8) {
|
||||
hval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0);
|
||||
if(self.regs.bgmode != 4)
|
||||
|
@ -40,7 +58,7 @@ void PPU::Background::offset_per_tile(unsigned x, unsigned y, unsigned& hoffset,
|
|||
}
|
||||
}
|
||||
|
||||
void PPU::Background::scanline() {
|
||||
auto PPU::Background::scanline() -> void {
|
||||
if(self.vcounter() == 1) {
|
||||
mosaic_vcounter = regs.mosaic + 1;
|
||||
mosaic_voffset = 1;
|
||||
|
@ -68,7 +86,7 @@ void PPU::Background::scanline() {
|
|||
if(regs.screen_size == 3) scy <<= 1;
|
||||
}
|
||||
|
||||
void PPU::Background::render() {
|
||||
auto PPU::Background::render() -> void {
|
||||
if(regs.mode == Mode::Inactive) return;
|
||||
if(regs.main_enable == false && regs.sub_enable == false) return;
|
||||
|
||||
|
@ -76,38 +94,38 @@ void PPU::Background::render() {
|
|||
if(regs.sub_enable) window.render(1);
|
||||
if(regs.mode == Mode::Mode7) return render_mode7();
|
||||
|
||||
unsigned priority0 = (priority0_enable ? regs.priority0 : 0);
|
||||
unsigned priority1 = (priority1_enable ? regs.priority1 : 0);
|
||||
uint priority0 = (priority0_enable ? regs.priority0 : 0);
|
||||
uint priority1 = (priority1_enable ? regs.priority1 : 0);
|
||||
if(priority0 + priority1 == 0) return;
|
||||
|
||||
unsigned mosaic_hcounter = 1;
|
||||
unsigned mosaic_palette = 0;
|
||||
unsigned mosaic_priority = 0;
|
||||
unsigned mosaic_color = 0;
|
||||
uint mosaic_hcounter = 1;
|
||||
uint mosaic_palette = 0;
|
||||
uint mosaic_priority = 0;
|
||||
uint mosaic_color = 0;
|
||||
|
||||
const unsigned bgpal_index = (self.regs.bgmode == 0 ? id << 5 : 0);
|
||||
const unsigned pal_size = 2 << regs.mode;
|
||||
const unsigned tile_mask = 0x0fff >> regs.mode;
|
||||
const unsigned tiledata_index = regs.tiledata_addr >> (4 + regs.mode);
|
||||
const uint bgpal_index = (self.regs.bgmode == 0 ? id << 5 : 0);
|
||||
const uint pal_size = 2 << regs.mode;
|
||||
const uint tile_mask = 0x0fff >> regs.mode;
|
||||
const uint tiledata_index = regs.tiledata_addr >> (4 + regs.mode);
|
||||
|
||||
hscroll = regs.hoffset;
|
||||
vscroll = regs.voffset;
|
||||
|
||||
unsigned y = (regs.mosaic == 0 ? self.vcounter() : mosaic_voffset);
|
||||
uint y = (regs.mosaic == 0 ? self.vcounter() : mosaic_voffset);
|
||||
if(hires) {
|
||||
hscroll <<= 1;
|
||||
if(self.regs.interlace) y = (y << 1) + self.field();
|
||||
}
|
||||
|
||||
unsigned tile_pri, tile_num;
|
||||
unsigned pal_index, pal_num;
|
||||
unsigned hoffset, voffset, col;
|
||||
uint tile_pri, tile_num;
|
||||
uint pal_index, pal_num;
|
||||
uint hoffset, voffset, col;
|
||||
bool mirror_x, mirror_y;
|
||||
|
||||
const bool is_opt_mode = (self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6);
|
||||
const bool is_direct_color_mode = (self.screen.regs.direct_color == true && id == ID::BG1 && (self.regs.bgmode == 3 || self.regs.bgmode == 4));
|
||||
|
||||
signed x = 0 - (hscroll & 7);
|
||||
int x = 0 - (hscroll & 7);
|
||||
while(x < width) {
|
||||
hoffset = x + hscroll;
|
||||
voffset = y + vscroll;
|
||||
|
@ -127,12 +145,12 @@ void PPU::Background::render() {
|
|||
tile_num = ((tile_num & 0x03ff) + tiledata_index) & tile_mask;
|
||||
|
||||
if(mirror_y) voffset ^= 7;
|
||||
unsigned mirror_xmask = !mirror_x ? 0 : 7;
|
||||
uint mirror_xmask = !mirror_x ? 0 : 7;
|
||||
|
||||
uint8* tiledata = self.cache.tile(regs.mode, tile_num);
|
||||
tiledata += ((voffset & 7) * 8);
|
||||
|
||||
for(unsigned n = 0; n < 8; n++, x++) {
|
||||
for(uint n = 0; n < 8; n++, x++) {
|
||||
if(x & width) continue;
|
||||
if(--mosaic_hcounter == 0) {
|
||||
mosaic_hcounter = regs.mosaic + 1;
|
||||
|
@ -150,7 +168,7 @@ void PPU::Background::render() {
|
|||
if(regs.main_enable && !window.main[x]) self.screen.output.plot_main(x, mosaic_color, mosaic_priority, id);
|
||||
if(regs.sub_enable && !window.sub[x]) self.screen.output.plot_sub(x, mosaic_color, mosaic_priority, id);
|
||||
} else {
|
||||
signed half_x = x >> 1;
|
||||
int half_x = x >> 1;
|
||||
if(x & 1) {
|
||||
if(regs.main_enable && !window.main[half_x]) self.screen.output.plot_main(half_x, mosaic_color, mosaic_priority, id);
|
||||
} else {
|
||||
|
@ -160,25 +178,3 @@ void PPU::Background::render() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
PPU::Background::Background(PPU& self, unsigned id) : self(self), id(id) {
|
||||
priority0_enable = true;
|
||||
priority1_enable = true;
|
||||
|
||||
opt_valid_bit = (id == ID::BG1 ? 0x2000 : id == ID::BG2 ? 0x4000 : 0x0000);
|
||||
|
||||
mosaic_table = new uint16*[16];
|
||||
for(unsigned m = 0; m < 16; m++) {
|
||||
mosaic_table[m] = new uint16[4096];
|
||||
for(unsigned x = 0; x < 4096; x++) {
|
||||
mosaic_table[m][x] = (x / (m + 1)) * (m + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PPU::Background::~Background() {
|
||||
for(unsigned m = 0; m < 16; m++) delete[] mosaic_table[m];
|
||||
delete[] mosaic_table;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,66 +1,68 @@
|
|||
class Background {
|
||||
struct ID { enum { BG1, BG2, BG3, BG4 }; };
|
||||
struct Mode { enum { BPP2, BPP4, BPP8, Mode7, Inactive }; };
|
||||
struct ScreenSize { enum { Size32x32, Size32x64, Size64x32, Size64x64 }; };
|
||||
struct TileSize { enum { Size8x8, Size16x16 }; };
|
||||
struct ID { enum : uint { BG1, BG2, BG3, BG4 }; };
|
||||
struct Mode { enum : uint { BPP2, BPP4, BPP8, Mode7, Inactive }; };
|
||||
struct ScreenSize { enum : uint { Size32x32, Size32x64, Size64x32, Size64x64 }; };
|
||||
struct TileSize { enum : uint { Size8x8, Size16x16 }; };
|
||||
|
||||
Background(PPU& self, uint id);
|
||||
~Background();
|
||||
|
||||
alwaysinline auto get_tile(uint hoffset, uint voffset) -> uint;
|
||||
auto offset_per_tile(uint x, uint y, uint& hoffset, uint& voffset) -> void;
|
||||
auto scanline() -> void;
|
||||
auto render() -> void;
|
||||
auto render_mode7() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
PPU& self;
|
||||
|
||||
bool priority0_enable;
|
||||
bool priority1_enable;
|
||||
|
||||
struct Regs {
|
||||
unsigned mode;
|
||||
unsigned priority0;
|
||||
unsigned priority1;
|
||||
uint mode;
|
||||
uint priority0;
|
||||
uint priority1;
|
||||
|
||||
bool tile_size;
|
||||
unsigned mosaic;
|
||||
uint mosaic;
|
||||
|
||||
unsigned screen_addr;
|
||||
unsigned screen_size;
|
||||
unsigned tiledata_addr;
|
||||
uint screen_addr;
|
||||
uint screen_size;
|
||||
uint tiledata_addr;
|
||||
|
||||
unsigned hoffset;
|
||||
unsigned voffset;
|
||||
uint hoffset;
|
||||
uint voffset;
|
||||
|
||||
bool main_enable;
|
||||
bool sub_enable;
|
||||
} regs;
|
||||
|
||||
uint16 **mosaic_table;
|
||||
uint16** mosaic_table;
|
||||
|
||||
const unsigned id;
|
||||
unsigned opt_valid_bit;
|
||||
const uint id;
|
||||
uint opt_valid_bit;
|
||||
|
||||
bool hires;
|
||||
signed width;
|
||||
|
||||
unsigned tile_width;
|
||||
unsigned tile_height;
|
||||
uint tile_width;
|
||||
uint tile_height;
|
||||
|
||||
unsigned mask_x;
|
||||
unsigned mask_y;
|
||||
uint mask_x;
|
||||
uint mask_y;
|
||||
|
||||
unsigned scx;
|
||||
unsigned scy;
|
||||
uint scx;
|
||||
uint scy;
|
||||
|
||||
unsigned hscroll;
|
||||
unsigned vscroll;
|
||||
uint hscroll;
|
||||
uint vscroll;
|
||||
|
||||
unsigned mosaic_vcounter;
|
||||
unsigned mosaic_voffset;
|
||||
uint mosaic_vcounter;
|
||||
uint mosaic_voffset;
|
||||
|
||||
LayerWindow window;
|
||||
|
||||
alwaysinline unsigned get_tile(unsigned hoffset, unsigned voffset);
|
||||
void offset_per_tile(unsigned x, unsigned y, unsigned& hoffset, unsigned& voffset);
|
||||
void scanline();
|
||||
void render();
|
||||
void render_mode7();
|
||||
|
||||
void serialize(serializer&);
|
||||
Background(PPU& self, unsigned id);
|
||||
~Background();
|
||||
|
||||
PPU& self;
|
||||
friend class PPU;
|
||||
};
|
||||
|
|
|
@ -1,22 +1,20 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
#define Clip(x) (((x) & 0x2000) ? ((x) | ~0x03ff) : ((x) & 0x03ff))
|
||||
|
||||
void PPU::Background::render_mode7() {
|
||||
signed px, py;
|
||||
signed tx, ty, tile, palette;
|
||||
auto PPU::Background::render_mode7() -> void {
|
||||
int px, py;
|
||||
int tx, ty, tile, palette;
|
||||
|
||||
signed a = sclip<16>(self.regs.m7a);
|
||||
signed b = sclip<16>(self.regs.m7b);
|
||||
signed c = sclip<16>(self.regs.m7c);
|
||||
signed d = sclip<16>(self.regs.m7d);
|
||||
int a = sclip<16>(self.regs.m7a);
|
||||
int b = sclip<16>(self.regs.m7b);
|
||||
int c = sclip<16>(self.regs.m7c);
|
||||
int d = sclip<16>(self.regs.m7d);
|
||||
|
||||
signed cx = sclip<13>(self.regs.m7x);
|
||||
signed cy = sclip<13>(self.regs.m7y);
|
||||
signed hofs = sclip<13>(self.regs.mode7_hoffset);
|
||||
signed vofs = sclip<13>(self.regs.mode7_voffset);
|
||||
int cx = sclip<13>(self.regs.m7x);
|
||||
int cy = sclip<13>(self.regs.m7y);
|
||||
int hofs = sclip<13>(self.regs.mode7_hoffset);
|
||||
int vofs = sclip<13>(self.regs.mode7_voffset);
|
||||
|
||||
signed y = (self.regs.mode7_vflip == false ? self.vcounter() : 255 - self.vcounter());
|
||||
int y = (self.regs.mode7_vflip == false ? self.vcounter() : 255 - self.vcounter());
|
||||
|
||||
uint16* mosaic_x;
|
||||
uint16* mosaic_y;
|
||||
|
@ -28,13 +26,13 @@ void PPU::Background::render_mode7() {
|
|||
mosaic_y = mosaic_table[self.bg1.regs.mosaic];
|
||||
}
|
||||
|
||||
unsigned priority0 = (priority0_enable ? regs.priority0 : 0);
|
||||
unsigned priority1 = (priority1_enable ? regs.priority1 : 0);
|
||||
uint priority0 = (priority0_enable ? regs.priority0 : 0);
|
||||
uint priority1 = (priority1_enable ? regs.priority1 : 0);
|
||||
if(priority0 + priority1 == 0) return;
|
||||
|
||||
signed psx = ((a * Clip(hofs - cx)) & ~63) + ((b * Clip(vofs - cy)) & ~63) + ((b * mosaic_y[y]) & ~63) + (cx << 8);
|
||||
signed psy = ((c * Clip(hofs - cx)) & ~63) + ((d * Clip(vofs - cy)) & ~63) + ((d * mosaic_y[y]) & ~63) + (cy << 8);
|
||||
for(signed x = 0; x < 256; x++) {
|
||||
int psx = ((a * Clip(hofs - cx)) & ~63) + ((b * Clip(vofs - cy)) & ~63) + ((b * mosaic_y[y]) & ~63) + (cx << 8);
|
||||
int psy = ((c * Clip(hofs - cx)) & ~63) + ((d * Clip(vofs - cy)) & ~63) + ((d * mosaic_y[y]) & ~63) + (cy << 8);
|
||||
for(int x = 0; x < 256; x++) {
|
||||
px = (psx + (a * mosaic_x[x])) >> 8;
|
||||
py = (psy + (c * mosaic_x[x])) >> 8;
|
||||
|
||||
|
@ -78,7 +76,7 @@ void PPU::Background::render_mode7() {
|
|||
}
|
||||
}
|
||||
|
||||
unsigned priority;
|
||||
uint priority;
|
||||
if(id == ID::BG1) {
|
||||
priority = priority0;
|
||||
} else {
|
||||
|
@ -87,9 +85,9 @@ void PPU::Background::render_mode7() {
|
|||
}
|
||||
|
||||
if(palette == 0) continue;
|
||||
unsigned plot_x = (self.regs.mode7_hflip == false ? x : 255 - x);
|
||||
uint plot_x = (self.regs.mode7_hflip == false ? x : 255 - x);
|
||||
|
||||
unsigned color;
|
||||
uint color;
|
||||
if(self.screen.regs.direct_color && id == ID::BG1) {
|
||||
color = self.screen.get_direct_color(0, palette);
|
||||
} else {
|
||||
|
@ -102,5 +100,3 @@ void PPU::Background::render_mode7() {
|
|||
}
|
||||
|
||||
#undef Clip
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
#ifdef PPU_CPP
|
||||
PPU::Cache::Cache(PPU& self) : self(self) {
|
||||
tiledata[0] = new uint8[262144]();
|
||||
tiledata[1] = new uint8[131072]();
|
||||
tiledata[2] = new uint8[ 65536]();
|
||||
tilevalid[0] = new uint8[ 4096]();
|
||||
tilevalid[1] = new uint8[ 2048]();
|
||||
tilevalid[2] = new uint8[ 1024]();
|
||||
}
|
||||
|
||||
uint8* PPU::Cache::tile_2bpp(unsigned tile) {
|
||||
auto PPU::Cache::tile_2bpp(uint tile) -> uint8* {
|
||||
if(tilevalid[0][tile] == 0) {
|
||||
tilevalid[0][tile] = 1;
|
||||
uint8* output = (uint8*)tiledata[0] + (tile << 6);
|
||||
unsigned offset = tile << 4;
|
||||
unsigned y = 8;
|
||||
unsigned color, d0, d1;
|
||||
uint offset = tile << 4;
|
||||
uint y = 8;
|
||||
uint color, d0, d1;
|
||||
while(y--) {
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
|
@ -29,13 +36,13 @@ uint8* PPU::Cache::tile_2bpp(unsigned tile) {
|
|||
return tiledata[0] + (tile << 6);
|
||||
}
|
||||
|
||||
uint8* PPU::Cache::tile_4bpp(unsigned tile) {
|
||||
auto PPU::Cache::tile_4bpp(uint tile) -> uint8* {
|
||||
if(tilevalid[1][tile] == 0) {
|
||||
tilevalid[1][tile] = 1;
|
||||
uint8* output = (uint8*)tiledata[1] + (tile << 6);
|
||||
unsigned offset = tile << 5;
|
||||
unsigned y = 8;
|
||||
unsigned color, d0, d1, d2, d3;
|
||||
uint offset = tile << 5;
|
||||
uint y = 8;
|
||||
uint color, d0, d1, d2, d3;
|
||||
while(y--) {
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
|
@ -62,13 +69,13 @@ uint8* PPU::Cache::tile_4bpp(unsigned tile) {
|
|||
return tiledata[1] + (tile << 6);
|
||||
}
|
||||
|
||||
uint8* PPU::Cache::tile_8bpp(unsigned tile) {
|
||||
auto PPU::Cache::tile_8bpp(uint tile) -> uint8* {
|
||||
if(tilevalid[2][tile] == 0) {
|
||||
tilevalid[2][tile] = 1;
|
||||
uint8* output = (uint8*)tiledata[2] + (tile << 6);
|
||||
unsigned offset = tile << 6;
|
||||
unsigned y = 8;
|
||||
unsigned color, d0, d1, d2, d3, d4, d5, d6, d7;
|
||||
uint offset = tile << 6;
|
||||
uint y = 8;
|
||||
uint color, d0, d1, d2, d3, d4, d5, d6, d7;
|
||||
while(y--) {
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
|
@ -103,21 +110,10 @@ uint8* PPU::Cache::tile_8bpp(unsigned tile) {
|
|||
return tiledata[2] + (tile << 6);
|
||||
}
|
||||
|
||||
uint8* PPU::Cache::tile(unsigned bpp, unsigned tile) {
|
||||
auto PPU::Cache::tile(uint bpp, uint tile) -> uint8* {
|
||||
switch(bpp) {
|
||||
case 0: return tile_2bpp(tile);
|
||||
case 1: return tile_4bpp(tile);
|
||||
case 2: return tile_8bpp(tile);
|
||||
case 0: return tile_2bpp(tile);
|
||||
case 1: return tile_4bpp(tile);
|
||||
case 2: return tile_8bpp(tile);
|
||||
}
|
||||
}
|
||||
|
||||
PPU::Cache::Cache(PPU& self) : self(self) {
|
||||
tiledata[0] = new uint8[262144]();
|
||||
tiledata[1] = new uint8[131072]();
|
||||
tiledata[2] = new uint8[ 65536]();
|
||||
tilevalid[0] = new uint8[ 4096]();
|
||||
tilevalid[1] = new uint8[ 2048]();
|
||||
tilevalid[2] = new uint8[ 1024]();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
struct Cache {
|
||||
Cache(PPU& self);
|
||||
|
||||
auto tile_2bpp(uint tile) -> uint8*;
|
||||
auto tile_4bpp(uint tile) -> uint8*;
|
||||
auto tile_8bpp(uint tile) -> uint8*;
|
||||
auto tile(uint bpp, uint tile) -> uint8*;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
PPU& self;
|
||||
uint8* tiledata[3];
|
||||
uint8* tilevalid[3];
|
||||
|
||||
uint8* tile_2bpp(unsigned tile);
|
||||
uint8* tile_4bpp(unsigned tile);
|
||||
uint8* tile_8bpp(unsigned tile);
|
||||
uint8* tile(unsigned bpp, unsigned tile);
|
||||
|
||||
void serialize(serializer&);
|
||||
Cache(PPU& self);
|
||||
|
||||
PPU& self;
|
||||
friend class PPU;
|
||||
};
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
void PPU::latch_counters() {
|
||||
auto PPU::latch_counters() -> void {
|
||||
regs.hcounter = cpu.hdot();
|
||||
regs.vcounter = cpu.vcounter();
|
||||
regs.counters_latched = true;
|
||||
}
|
||||
|
||||
bool PPU::interlace() const { return display.interlace; }
|
||||
bool PPU::overscan() const { return display.overscan; }
|
||||
bool PPU::hires() const { return regs.pseudo_hires || regs.bgmode == 5 || regs.bgmode == 6; }
|
||||
auto PPU::interlace() const -> bool { return display.interlace; }
|
||||
auto PPU::overscan() const -> bool { return display.overscan; }
|
||||
auto PPU::hires() const -> bool { return regs.pseudo_hires || regs.bgmode == 5 || regs.bgmode == 6; }
|
||||
|
||||
uint16 PPU::get_vram_addr() {
|
||||
auto PPU::get_vram_addr() -> uint16 {
|
||||
uint16 addr = regs.vram_addr;
|
||||
switch(regs.vram_mapping) {
|
||||
case 0: break;
|
||||
|
@ -21,13 +19,13 @@ uint16 PPU::get_vram_addr() {
|
|||
return (addr << 1);
|
||||
}
|
||||
|
||||
uint8 PPU::vram_read(unsigned addr) {
|
||||
auto PPU::vram_read(uint addr) -> uint8 {
|
||||
if(regs.display_disable) return vram[addr];
|
||||
if(cpu.vcounter() >= display.height) return vram[addr];
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void PPU::vram_write(unsigned addr, uint8 data) {
|
||||
auto PPU::vram_write(uint addr, uint8 data) -> void {
|
||||
if(regs.display_disable || cpu.vcounter() >= display.height) {
|
||||
vram[addr] = data;
|
||||
cache.tilevalid[0][addr >> 4] = false;
|
||||
|
@ -37,29 +35,29 @@ void PPU::vram_write(unsigned addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
uint8 PPU::oam_read(unsigned addr) {
|
||||
auto PPU::oam_read(uint addr) -> uint8 {
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
if(regs.display_disable) return oam[addr];
|
||||
if(cpu.vcounter() >= display.height) return oam[addr];
|
||||
return oam[0x0218];
|
||||
}
|
||||
|
||||
void PPU::oam_write(unsigned addr, uint8 data) {
|
||||
auto PPU::oam_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
if(!regs.display_disable && cpu.vcounter() < display.height) addr = 0x0218;
|
||||
oam[addr] = data;
|
||||
sprite.update_list(addr, data);
|
||||
}
|
||||
|
||||
uint8 PPU::cgram_read(unsigned addr) {
|
||||
auto PPU::cgram_read(uint addr) -> uint8 {
|
||||
return cgram[addr];
|
||||
}
|
||||
|
||||
void PPU::cgram_write(unsigned addr, uint8 data) {
|
||||
auto PPU::cgram_write(uint addr, uint8 data) -> void {
|
||||
cgram[addr] = data;
|
||||
}
|
||||
|
||||
void PPU::mmio_update_video_mode() {
|
||||
auto PPU::mmio_update_video_mode() -> void {
|
||||
switch(regs.bgmode) {
|
||||
case 0: {
|
||||
bg1.regs.mode = Background::Mode::BPP2; bg1.regs.priority0 = 8; bg1.regs.priority1 = 11;
|
||||
|
@ -157,7 +155,7 @@ void PPU::mmio_update_video_mode() {
|
|||
}
|
||||
}
|
||||
|
||||
uint8 PPU::mmio_read(unsigned addr) {
|
||||
auto PPU::mmio_read(uint addr) -> uint8 {
|
||||
cpu.synchronizePPU();
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
|
@ -278,7 +276,7 @@ uint8 PPU::mmio_read(unsigned addr) {
|
|||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
auto PPU::mmio_write(uint addr, uint8 data) -> void {
|
||||
cpu.synchronizePPU();
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
|
@ -680,7 +678,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void PPU::mmio_reset() {
|
||||
auto PPU::mmio_reset() -> void {
|
||||
//internal
|
||||
regs.ppu1_mdr = 0;
|
||||
regs.ppu2_mdr = 0;
|
||||
|
@ -887,5 +885,3 @@ void PPU::mmio_reset() {
|
|||
|
||||
mmio_update_video_mode();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
public:
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
auto mmio_read(uint addr) -> uint8;
|
||||
auto mmio_write(uint addr, uint8 data) -> void;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -21,7 +21,7 @@ struct Regs {
|
|||
|
||||
//$2100
|
||||
bool display_disable;
|
||||
unsigned display_brightness;
|
||||
uint display_brightness;
|
||||
|
||||
//$2102-$2103
|
||||
uint16 oam_baseaddr;
|
||||
|
@ -30,7 +30,7 @@ struct Regs {
|
|||
|
||||
//$2105
|
||||
bool bg3_priority;
|
||||
unsigned bgmode;
|
||||
uint bgmode;
|
||||
|
||||
//$210d
|
||||
uint16 mode7_hoffset;
|
||||
|
@ -40,14 +40,14 @@ struct Regs {
|
|||
|
||||
//$2115
|
||||
bool vram_incmode;
|
||||
unsigned vram_mapping;
|
||||
unsigned vram_incsize;
|
||||
uint vram_mapping;
|
||||
uint vram_incsize;
|
||||
|
||||
//$2116-$2117
|
||||
uint16 vram_addr;
|
||||
|
||||
//$211a
|
||||
unsigned mode7_repeat;
|
||||
uint mode7_repeat;
|
||||
bool mode7_vflip;
|
||||
bool mode7_hflip;
|
||||
|
||||
|
@ -63,10 +63,10 @@ struct Regs {
|
|||
uint16 cgram_addr;
|
||||
|
||||
//$2126-$212a
|
||||
unsigned window_one_left;
|
||||
unsigned window_one_right;
|
||||
unsigned window_two_left;
|
||||
unsigned window_two_right;
|
||||
uint window_one_left;
|
||||
uint window_one_right;
|
||||
uint window_two_left;
|
||||
uint window_two_right;
|
||||
|
||||
//$2133
|
||||
bool mode7_extbg;
|
||||
|
@ -81,15 +81,15 @@ struct Regs {
|
|||
uint16 vcounter;
|
||||
} regs;
|
||||
|
||||
uint16 get_vram_addr();
|
||||
uint8 vram_read(unsigned addr);
|
||||
void vram_write(unsigned addr, uint8 data);
|
||||
auto get_vram_addr() -> uint16;
|
||||
auto vram_read(uint addr) -> uint8;
|
||||
auto vram_write(uint addr, uint8 data) -> void;
|
||||
|
||||
uint8 oam_read(unsigned addr);
|
||||
void oam_write(unsigned addr, uint8 data);
|
||||
auto oam_read(uint addr) -> uint8;
|
||||
auto oam_write(uint addr, uint8 data) -> void;
|
||||
|
||||
uint8 cgram_read(unsigned addr);
|
||||
void cgram_write(unsigned addr, uint8 data);
|
||||
auto cgram_read(uint addr) -> uint8;
|
||||
auto cgram_write(uint addr, uint8 data) -> void;
|
||||
|
||||
void mmio_update_video_mode();
|
||||
void mmio_reset();
|
||||
auto mmio_update_video_mode() -> void;
|
||||
auto mmio_reset() -> void;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <sfc/sfc.hpp>
|
||||
|
||||
#define PPU_CPP
|
||||
namespace SuperFamicom {
|
||||
|
||||
PPU ppu;
|
||||
|
@ -13,120 +12,6 @@ PPU ppu;
|
|||
#include "screen/screen.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
void PPU::step(unsigned clocks) {
|
||||
clock += clocks;
|
||||
}
|
||||
|
||||
void PPU::synchronize_cpu() {
|
||||
if(CPU::Threaded == true) {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
} else {
|
||||
while(clock >= 0) cpu.enter();
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::Enter() { ppu.enter(); }
|
||||
|
||||
void PPU::enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
scanline();
|
||||
if(vcounter() < display.height && vcounter()) {
|
||||
add_clocks(512);
|
||||
render_scanline();
|
||||
add_clocks(lineclocks() - 512);
|
||||
} else {
|
||||
add_clocks(lineclocks());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::add_clocks(unsigned clocks) {
|
||||
tick(clocks);
|
||||
step(clocks);
|
||||
synchronize_cpu();
|
||||
}
|
||||
|
||||
void PPU::render_scanline() {
|
||||
if(display.framecounter) return; //skip this frame?
|
||||
bg1.scanline();
|
||||
bg2.scanline();
|
||||
bg3.scanline();
|
||||
bg4.scanline();
|
||||
if(regs.display_disable) return screen.render_black();
|
||||
screen.scanline();
|
||||
bg1.render();
|
||||
bg2.render();
|
||||
bg3.render();
|
||||
bg4.render();
|
||||
sprite.render();
|
||||
screen.render();
|
||||
}
|
||||
|
||||
void PPU::scanline() {
|
||||
display.width = !hires() ? 256 : 512;
|
||||
display.height = !overscan() ? 225 : 240;
|
||||
if(vcounter() == 0) frame();
|
||||
if(vcounter() == display.height && regs.display_disable == false) sprite.address_reset();
|
||||
}
|
||||
|
||||
void PPU::frame() {
|
||||
sprite.frame();
|
||||
system.frame();
|
||||
display.interlace = regs.interlace;
|
||||
display.overscan = regs.overscan;
|
||||
display.framecounter = display.frameskip == 0 ? 0 : (display.framecounter + 1) % display.frameskip;
|
||||
}
|
||||
|
||||
void PPU::enable() {
|
||||
function<uint8 (unsigned)> reader = {&PPU::mmio_read, (PPU*)&ppu};
|
||||
function<void (unsigned, uint8)> writer = {&PPU::mmio_write, (PPU*)&ppu};
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);
|
||||
}
|
||||
|
||||
void PPU::power() {
|
||||
for(auto& n : vram) n = 0;
|
||||
for(auto& n : oam) n = 0;
|
||||
for(auto& n : cgram) n = 0;
|
||||
reset();
|
||||
}
|
||||
|
||||
void PPU::reset() {
|
||||
create(Enter, system.cpuFrequency());
|
||||
PPUcounter::reset();
|
||||
memset(surface, 0, 512 * 512 * sizeof(uint32));
|
||||
mmio_reset();
|
||||
display.interlace = false;
|
||||
display.overscan = false;
|
||||
}
|
||||
|
||||
void PPU::layer_enable(unsigned layer, unsigned priority, bool enable) {
|
||||
switch(layer * 4 + priority) {
|
||||
case 0: bg1.priority0_enable = enable; break;
|
||||
case 1: bg1.priority1_enable = enable; break;
|
||||
case 4: bg2.priority0_enable = enable; break;
|
||||
case 5: bg2.priority1_enable = enable; break;
|
||||
case 8: bg3.priority0_enable = enable; break;
|
||||
case 9: bg3.priority1_enable = enable; break;
|
||||
case 12: bg4.priority0_enable = enable; break;
|
||||
case 13: bg4.priority1_enable = enable; break;
|
||||
case 16: sprite.priority0_enable = enable; break;
|
||||
case 17: sprite.priority1_enable = enable; break;
|
||||
case 18: sprite.priority2_enable = enable; break;
|
||||
case 19: sprite.priority3_enable = enable; break;
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::set_frameskip(unsigned frameskip) {
|
||||
display.frameskip = frameskip;
|
||||
display.framecounter = 0;
|
||||
}
|
||||
|
||||
PPU::PPU() :
|
||||
cache(*this),
|
||||
bg1(*this, Background::ID::BG1),
|
||||
|
@ -147,4 +32,118 @@ PPU::~PPU() {
|
|||
delete[] surface;
|
||||
}
|
||||
|
||||
auto PPU::step(uint clocks) -> void {
|
||||
clock += clocks;
|
||||
}
|
||||
|
||||
auto PPU::synchronizeCPU() -> void {
|
||||
if(CPU::Threaded == true) {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
} else {
|
||||
while(clock >= 0) cpu.enter();
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::Enter() -> void { ppu.enter(); }
|
||||
|
||||
auto PPU::enter() -> void {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
scanline();
|
||||
if(vcounter() < display.height && vcounter()) {
|
||||
add_clocks(512);
|
||||
render_scanline();
|
||||
add_clocks(lineclocks() - 512);
|
||||
} else {
|
||||
add_clocks(lineclocks());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::add_clocks(uint clocks) -> void {
|
||||
tick(clocks);
|
||||
step(clocks);
|
||||
synchronizeCPU();
|
||||
}
|
||||
|
||||
auto PPU::render_scanline() -> void {
|
||||
if(display.framecounter) return; //skip this frame?
|
||||
bg1.scanline();
|
||||
bg2.scanline();
|
||||
bg3.scanline();
|
||||
bg4.scanline();
|
||||
if(regs.display_disable) return screen.render_black();
|
||||
screen.scanline();
|
||||
bg1.render();
|
||||
bg2.render();
|
||||
bg3.render();
|
||||
bg4.render();
|
||||
sprite.render();
|
||||
screen.render();
|
||||
}
|
||||
|
||||
auto PPU::scanline() -> void {
|
||||
display.width = !hires() ? 256 : 512;
|
||||
display.height = !overscan() ? 225 : 240;
|
||||
if(vcounter() == 0) frame();
|
||||
if(vcounter() == display.height && regs.display_disable == false) sprite.address_reset();
|
||||
}
|
||||
|
||||
auto PPU::frame() -> void {
|
||||
sprite.frame();
|
||||
system.frame();
|
||||
display.interlace = regs.interlace;
|
||||
display.overscan = regs.overscan;
|
||||
display.framecounter = display.frameskip == 0 ? 0 : (display.framecounter + 1) % display.frameskip;
|
||||
}
|
||||
|
||||
auto PPU::enable() -> void {
|
||||
function<uint8 (uint)> reader = {&PPU::mmio_read, (PPU*)&ppu};
|
||||
function<void (uint, uint8)> writer = {&PPU::mmio_write, (PPU*)&ppu};
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);
|
||||
}
|
||||
|
||||
auto PPU::power() -> void {
|
||||
for(auto& n : vram) n = 0;
|
||||
for(auto& n : oam) n = 0;
|
||||
for(auto& n : cgram) n = 0;
|
||||
reset();
|
||||
}
|
||||
|
||||
auto PPU::reset() -> void {
|
||||
create(Enter, system.cpuFrequency());
|
||||
PPUcounter::reset();
|
||||
memset(surface, 0, 512 * 512 * sizeof(uint32));
|
||||
mmio_reset();
|
||||
display.interlace = false;
|
||||
display.overscan = false;
|
||||
}
|
||||
|
||||
auto PPU::layer_enable(uint layer, uint priority, bool enable) -> void {
|
||||
switch(layer * 4 + priority) {
|
||||
case 0: bg1.priority0_enable = enable; break;
|
||||
case 1: bg1.priority1_enable = enable; break;
|
||||
case 4: bg2.priority0_enable = enable; break;
|
||||
case 5: bg2.priority1_enable = enable; break;
|
||||
case 8: bg3.priority0_enable = enable; break;
|
||||
case 9: bg3.priority1_enable = enable; break;
|
||||
case 12: bg4.priority0_enable = enable; break;
|
||||
case 13: bg4.priority1_enable = enable; break;
|
||||
case 16: sprite.priority0_enable = enable; break;
|
||||
case 17: sprite.priority1_enable = enable; break;
|
||||
case 18: sprite.priority2_enable = enable; break;
|
||||
case 19: sprite.priority3_enable = enable; break;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::set_frameskip(uint frameskip) -> void {
|
||||
display.frameskip = frameskip;
|
||||
display.framecounter = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,31 +1,33 @@
|
|||
struct PPU : Thread, public PPUcounter {
|
||||
enum : bool { Threaded = true };
|
||||
|
||||
PPU();
|
||||
~PPU();
|
||||
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto synchronizeCPU() -> void;
|
||||
|
||||
auto latch_counters() -> void;
|
||||
auto interlace() const -> bool;
|
||||
auto overscan() const -> bool;
|
||||
auto hires() const -> bool;
|
||||
|
||||
auto enter() -> void;
|
||||
auto enable() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
auto scanline() -> void;
|
||||
auto frame() -> void;
|
||||
|
||||
auto layer_enable(uint layer, uint priority, bool enable) -> void;
|
||||
auto set_frameskip(uint frameskip) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint8 vram[64 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
|
||||
void latch_counters();
|
||||
bool interlace() const;
|
||||
bool overscan() const;
|
||||
bool hires() const;
|
||||
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
void scanline();
|
||||
void frame();
|
||||
|
||||
void layer_enable(unsigned layer, unsigned priority, bool enable);
|
||||
void set_frameskip(unsigned frameskip);
|
||||
|
||||
void serialize(serializer&);
|
||||
PPU();
|
||||
~PPU();
|
||||
|
||||
private:
|
||||
uint32* surface;
|
||||
uint32* output;
|
||||
|
@ -48,15 +50,15 @@ private:
|
|||
struct Display {
|
||||
bool interlace;
|
||||
bool overscan;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned frameskip;
|
||||
unsigned framecounter;
|
||||
uint width;
|
||||
uint height;
|
||||
uint frameskip;
|
||||
uint framecounter;
|
||||
} display;
|
||||
|
||||
static void Enter();
|
||||
void add_clocks(unsigned clocks);
|
||||
void render_scanline();
|
||||
static auto Enter() -> void;
|
||||
auto add_clocks(uint clocks) -> void;
|
||||
auto render_scanline() -> void;
|
||||
|
||||
friend class PPU::Cache;
|
||||
friend class PPU::Background;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifdef PPU_CPP
|
||||
PPU::Screen::Screen(PPU& self) : self(self) {
|
||||
}
|
||||
|
||||
unsigned PPU::Screen::get_palette(unsigned color) {
|
||||
auto PPU::Screen::get_palette(uint color) -> uint {
|
||||
#if defined(ENDIAN_LSB)
|
||||
return ((uint16*)ppu.cgram)[color];
|
||||
#else
|
||||
|
@ -9,24 +10,24 @@ unsigned PPU::Screen::get_palette(unsigned color) {
|
|||
#endif
|
||||
}
|
||||
|
||||
unsigned PPU::Screen::get_direct_color(unsigned p, unsigned t) {
|
||||
auto PPU::Screen::get_direct_color(uint p, uint t) -> uint {
|
||||
return ((t & 7) << 2) | ((p & 1) << 1) |
|
||||
(((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) |
|
||||
((t >> 6) << 13) | ((p >> 2) << 12);
|
||||
}
|
||||
|
||||
uint16 PPU::Screen::addsub(unsigned x, unsigned y, bool halve) {
|
||||
auto PPU::Screen::addsub(uint x, uint y, bool halve) -> uint16 {
|
||||
if(!regs.color_mode) {
|
||||
if(!halve) {
|
||||
unsigned sum = x + y;
|
||||
unsigned carry = (sum - ((x ^ y) & 0x0421)) & 0x8420;
|
||||
uint sum = x + y;
|
||||
uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420;
|
||||
return (sum - carry) | (carry - (carry >> 5));
|
||||
} else {
|
||||
return (x + y - ((x ^ y) & 0x0421)) >> 1;
|
||||
}
|
||||
} else {
|
||||
unsigned diff = x - y + 0x8420;
|
||||
unsigned borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420;
|
||||
uint diff = x - y + 0x8420;
|
||||
uint borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420;
|
||||
if(!halve) {
|
||||
return (diff - borrow) & (borrow - (borrow >> 5));
|
||||
} else {
|
||||
|
@ -35,12 +36,12 @@ uint16 PPU::Screen::addsub(unsigned x, unsigned y, bool halve) {
|
|||
}
|
||||
}
|
||||
|
||||
void PPU::Screen::scanline() {
|
||||
unsigned main_color = get_palette(0);
|
||||
unsigned sub_color = (self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6)
|
||||
? regs.color : main_color;
|
||||
auto PPU::Screen::scanline() -> void {
|
||||
uint main_color = get_palette(0);
|
||||
uint sub_color = (self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6)
|
||||
? regs.color : main_color;
|
||||
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
output.main[x].color = main_color;
|
||||
output.main[x].priority = 0;
|
||||
output.main[x].source = 6;
|
||||
|
@ -54,13 +55,13 @@ void PPU::Screen::scanline() {
|
|||
window.render(1);
|
||||
}
|
||||
|
||||
void PPU::Screen::render_black() {
|
||||
auto PPU::Screen::render_black() -> void {
|
||||
uint32* data = self.output + self.vcounter() * 1024;
|
||||
if(self.interlace() && self.field()) data += 512;
|
||||
memset(data, 0, self.display.width << 2);
|
||||
}
|
||||
|
||||
uint16 PPU::Screen::get_pixel_main(unsigned x) {
|
||||
auto PPU::Screen::get_pixel_main(uint x) -> uint16 {
|
||||
auto main = output.main[x];
|
||||
auto sub = output.sub[x];
|
||||
|
||||
|
@ -87,7 +88,7 @@ uint16 PPU::Screen::get_pixel_main(unsigned x) {
|
|||
return main.color;
|
||||
}
|
||||
|
||||
uint16 PPU::Screen::get_pixel_sub(unsigned x) {
|
||||
auto PPU::Screen::get_pixel_sub(uint x) -> uint16 {
|
||||
auto main = output.sub[x];
|
||||
auto sub = output.main[x];
|
||||
|
||||
|
@ -114,29 +115,23 @@ uint16 PPU::Screen::get_pixel_sub(unsigned x) {
|
|||
return main.color;
|
||||
}
|
||||
|
||||
void PPU::Screen::render() {
|
||||
auto PPU::Screen::render() -> void {
|
||||
uint32* data = self.output + self.vcounter() * 1024;
|
||||
if(self.interlace() && self.field()) data += 512;
|
||||
|
||||
if(!self.regs.pseudo_hires && self.regs.bgmode != 5 && self.regs.bgmode != 6) {
|
||||
for(unsigned i = 0; i < 256; i++) {
|
||||
for(uint i = 0; i < 256; i++) {
|
||||
data[i] = self.regs.display_brightness << 15 | get_pixel_main(i);
|
||||
}
|
||||
} else {
|
||||
for(unsigned i = 0; i < 256; i++) {
|
||||
for(uint i = 0; i < 256; i++) {
|
||||
*data++ = self.regs.display_brightness << 15 | get_pixel_sub(i);
|
||||
*data++ = self.regs.display_brightness << 15 | get_pixel_main(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PPU::Screen::Screen(PPU& self) : self(self) {
|
||||
}
|
||||
|
||||
PPU::Screen::~Screen() {
|
||||
}
|
||||
|
||||
void PPU::Screen::Output::plot_main(unsigned x, unsigned color, unsigned priority, unsigned source) {
|
||||
auto PPU::Screen::Output::plot_main(uint x, uint color, uint priority, uint source) -> void {
|
||||
if(priority > main[x].priority) {
|
||||
main[x].color = color;
|
||||
main[x].priority = priority;
|
||||
|
@ -144,12 +139,10 @@ void PPU::Screen::Output::plot_main(unsigned x, unsigned color, unsigned priorit
|
|||
}
|
||||
}
|
||||
|
||||
void PPU::Screen::Output::plot_sub(unsigned x, unsigned color, unsigned priority, unsigned source) {
|
||||
auto PPU::Screen::Output::plot_sub(uint x, uint color, uint priority, uint source) -> void {
|
||||
if(priority > sub[x].priority) {
|
||||
sub[x].color = color;
|
||||
sub[x].priority = priority;
|
||||
sub[x].source = source;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,19 @@
|
|||
class Screen {
|
||||
Screen(PPU& self);
|
||||
|
||||
alwaysinline auto get_palette(uint color) -> uint;
|
||||
auto get_direct_color(uint palette, uint tile) -> uint;
|
||||
alwaysinline auto addsub(uint x, uint y, bool halve) -> uint16;
|
||||
auto scanline() -> void;
|
||||
auto render_black() -> void;
|
||||
alwaysinline auto get_pixel_main(uint x) -> uint16;
|
||||
alwaysinline auto get_pixel_sub(uint x) -> uint16;
|
||||
auto render() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
PPU& self;
|
||||
|
||||
struct Regs {
|
||||
bool addsub_mode;
|
||||
bool direct_color;
|
||||
|
@ -7,38 +22,24 @@ class Screen {
|
|||
bool color_halve;
|
||||
bool color_enable[7];
|
||||
|
||||
unsigned color_b;
|
||||
unsigned color_g;
|
||||
unsigned color_r;
|
||||
unsigned color;
|
||||
uint color_b;
|
||||
uint color_g;
|
||||
uint color_r;
|
||||
uint color;
|
||||
} regs;
|
||||
|
||||
struct Output {
|
||||
struct Pixel {
|
||||
unsigned color;
|
||||
unsigned priority;
|
||||
unsigned source;
|
||||
} main[256], sub[256];
|
||||
alwaysinline auto plot_main(uint x, uint color, uint priority, uint source) -> void;
|
||||
alwaysinline auto plot_sub(uint x, uint color, uint priority, uint source) -> void;
|
||||
|
||||
alwaysinline void plot_main(unsigned x, unsigned color, unsigned priority, unsigned source);
|
||||
alwaysinline void plot_sub(unsigned x, unsigned color, unsigned priority, unsigned source);
|
||||
struct Pixel {
|
||||
uint color;
|
||||
uint priority;
|
||||
uint source;
|
||||
} main[256], sub[256];
|
||||
} output;
|
||||
|
||||
ColorWindow window;
|
||||
|
||||
alwaysinline unsigned get_palette(unsigned color);
|
||||
unsigned get_direct_color(unsigned palette, unsigned tile);
|
||||
alwaysinline uint16 addsub(unsigned x, unsigned y, bool halve);
|
||||
void scanline();
|
||||
void render_black();
|
||||
alwaysinline uint16 get_pixel_main(unsigned x);
|
||||
alwaysinline uint16 get_pixel_sub(unsigned x);
|
||||
void render();
|
||||
|
||||
void serialize(serializer&);
|
||||
Screen(PPU& self);
|
||||
~Screen();
|
||||
|
||||
PPU& self;
|
||||
friend class PPU;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
void PPUcounter::serialize(serializer& s) {
|
||||
auto PPUcounter::serialize(serializer& s) -> void {
|
||||
s.integer(status.interlace);
|
||||
s.integer(status.field);
|
||||
s.integer(status.vcounter);
|
||||
|
@ -12,7 +10,7 @@ void PPUcounter::serialize(serializer& s) {
|
|||
s.integer(history.index);
|
||||
}
|
||||
|
||||
void PPU::serialize(serializer& s) {
|
||||
auto PPU::serialize(serializer& s) -> void {
|
||||
Thread::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
|
@ -94,14 +92,14 @@ void PPU::serialize(serializer& s) {
|
|||
s.integer(regs.vcounter);
|
||||
}
|
||||
|
||||
void PPU::Cache::serialize(serializer& s) {
|
||||
auto PPU::Cache::serialize(serializer& s) -> void {
|
||||
//rather than save ~512KB worth of cached tiledata, invalidate it all
|
||||
for(unsigned i = 0; i < 4096; i++) tilevalid[0][i] = false;
|
||||
for(unsigned i = 0; i < 2048; i++) tilevalid[1][i] = false;
|
||||
for(unsigned i = 0; i < 1024; i++) tilevalid[2][i] = false;
|
||||
for(uint i = 0; i < 4096; i++) tilevalid[0][i] = false;
|
||||
for(uint i = 0; i < 2048; i++) tilevalid[1][i] = false;
|
||||
for(uint i = 0; i < 1024; i++) tilevalid[2][i] = false;
|
||||
}
|
||||
|
||||
void PPU::Background::serialize(serializer &s) {
|
||||
auto PPU::Background::serialize(serializer& s) -> void {
|
||||
s.integer(regs.mode);
|
||||
s.integer(regs.priority0);
|
||||
s.integer(regs.priority1);
|
||||
|
@ -140,7 +138,7 @@ void PPU::Background::serialize(serializer &s) {
|
|||
window.serialize(s);
|
||||
}
|
||||
|
||||
void PPU::Sprite::serialize(serializer& s) {
|
||||
auto PPU::Sprite::serialize(serializer& s) -> void {
|
||||
s.integer(regs.priority0);
|
||||
s.integer(regs.priority1);
|
||||
s.integer(regs.priority2);
|
||||
|
@ -159,7 +157,7 @@ void PPU::Sprite::serialize(serializer& s) {
|
|||
s.integer(regs.time_over);
|
||||
s.integer(regs.range_over);
|
||||
|
||||
for(unsigned i = 0; i < 128; i++) {
|
||||
for(uint i = 0; i < 128; i++) {
|
||||
s.integer(list[i].width);
|
||||
s.integer(list[i].height);
|
||||
s.integer(list[i].x);
|
||||
|
@ -175,7 +173,7 @@ void PPU::Sprite::serialize(serializer& s) {
|
|||
s.integer(list_valid);
|
||||
|
||||
s.array(itemlist);
|
||||
for(unsigned i = 0; i < 34; i++) {
|
||||
for(uint i = 0; i < 34; i++) {
|
||||
s.integer(tilelist[i].x);
|
||||
s.integer(tilelist[i].y);
|
||||
s.integer(tilelist[i].priority);
|
||||
|
@ -190,7 +188,7 @@ void PPU::Sprite::serialize(serializer& s) {
|
|||
window.serialize(s);
|
||||
}
|
||||
|
||||
void PPU::Screen::serialize(serializer& s) {
|
||||
auto PPU::Screen::serialize(serializer& s) -> void {
|
||||
s.integer(regs.addsub_mode);
|
||||
s.integer(regs.direct_color);
|
||||
|
||||
|
@ -203,7 +201,7 @@ void PPU::Screen::serialize(serializer& s) {
|
|||
s.integer(regs.color_r);
|
||||
s.integer(regs.color);
|
||||
|
||||
for(unsigned i = 0; i < 256; i++) {
|
||||
for(uint i = 0; i < 256; i++) {
|
||||
s.integer(output.main[i].color);
|
||||
s.integer(output.main[i].priority);
|
||||
s.integer(output.main[i].source);
|
||||
|
@ -216,7 +214,7 @@ void PPU::Screen::serialize(serializer& s) {
|
|||
window.serialize(s);
|
||||
}
|
||||
|
||||
void PPU::LayerWindow::serialize(serializer& s) {
|
||||
auto PPU::LayerWindow::serialize(serializer& s) -> void {
|
||||
s.integer(one_enable);
|
||||
s.integer(one_invert);
|
||||
s.integer(two_enable);
|
||||
|
@ -231,7 +229,7 @@ void PPU::LayerWindow::serialize(serializer& s) {
|
|||
s.array(sub);
|
||||
}
|
||||
|
||||
void PPU::ColorWindow::serialize(serializer& s) {
|
||||
auto PPU::ColorWindow::serialize(serializer& s) -> void {
|
||||
s.integer(one_enable);
|
||||
s.integer(one_invert);
|
||||
s.integer(two_enable);
|
||||
|
@ -245,5 +243,3 @@ void PPU::ColorWindow::serialize(serializer& s) {
|
|||
s.array(main);
|
||||
s.array(sub);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
#ifdef PPU_CPP
|
||||
PPU::Sprite::Sprite(PPU& self) : self(self) {
|
||||
priority0_enable = true;
|
||||
priority1_enable = true;
|
||||
priority2_enable = true;
|
||||
priority3_enable = true;
|
||||
}
|
||||
|
||||
void PPU::Sprite::frame() {
|
||||
auto PPU::Sprite::frame() -> void {
|
||||
regs.time_over = false;
|
||||
regs.range_over = false;
|
||||
}
|
||||
|
||||
void PPU::Sprite::update_list(unsigned addr, uint8 data) {
|
||||
auto PPU::Sprite::update_list(uint addr, uint8 data) -> void {
|
||||
if(addr < 0x0200) {
|
||||
unsigned i = addr >> 2;
|
||||
uint i = addr >> 2;
|
||||
switch(addr & 3) {
|
||||
case 0: list[i].x = (list[i].x & 0x0100) | data; break;
|
||||
case 1: list[i].y = (data + 1) & 0xff; break;
|
||||
|
@ -20,7 +25,7 @@ void PPU::Sprite::update_list(unsigned addr, uint8 data) {
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
unsigned i = (addr & 0x1f) << 2;
|
||||
uint i = (addr & 0x1f) << 2;
|
||||
list[i + 0].x = ((data & 0x01) << 8) | (list[i + 0].x & 0xff);
|
||||
list[i + 0].size = data & 0x02;
|
||||
list[i + 1].x = ((data & 0x04) << 6) | (list[i + 1].x & 0xff);
|
||||
|
@ -33,36 +38,36 @@ void PPU::Sprite::update_list(unsigned addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void PPU::Sprite::address_reset() {
|
||||
auto PPU::Sprite::address_reset() -> void {
|
||||
self.regs.oam_addr = self.regs.oam_baseaddr << 1;
|
||||
set_first();
|
||||
}
|
||||
|
||||
void PPU::Sprite::set_first() {
|
||||
auto PPU::Sprite::set_first() -> void {
|
||||
regs.first_sprite = (self.regs.oam_priority == false ? 0 : (self.regs.oam_addr >> 2) & 127);
|
||||
}
|
||||
|
||||
bool PPU::Sprite::on_scanline(unsigned sprite) {
|
||||
auto PPU::Sprite::on_scanline(uint sprite) -> bool {
|
||||
auto& s = list[sprite];
|
||||
if(s.x > 256 && (s.x + s.width - 1) < 512) return false;
|
||||
signed height = (regs.interlace == false ? s.height : s.height >> 1);
|
||||
int height = (regs.interlace == false ? s.height : s.height >> 1);
|
||||
if(self.vcounter() >= s.y && self.vcounter() < (s.y + height)) return true;
|
||||
if((s.y + height) >= 256 && self.vcounter() < ((s.y + height) & 255)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PPU::Sprite::render() {
|
||||
auto PPU::Sprite::render() -> void {
|
||||
if(list_valid == false) {
|
||||
list_valid = true;
|
||||
for(unsigned i = 0; i < 128; i++) {
|
||||
for(uint i = 0; i < 128; i++) {
|
||||
if(list[i].size == 0) {
|
||||
static unsigned width[] = { 8, 8, 8, 16, 16, 32, 16, 16 };
|
||||
static unsigned height[] = { 8, 8, 8, 16, 16, 32, 32, 32 };
|
||||
static uint width[] = {8, 8, 8, 16, 16, 32, 16, 16};
|
||||
static uint height[] = {8, 8, 8, 16, 16, 32, 32, 32};
|
||||
list[i].width = width[regs.base_size];
|
||||
list[i].height = height[regs.base_size];
|
||||
} else {
|
||||
static unsigned width[] = { 16, 32, 64, 32, 64, 64, 32, 32 };
|
||||
static unsigned height[] = { 16, 32, 64, 32, 64, 64, 64, 32 };
|
||||
static uint width[] = {16, 32, 64, 32, 64, 64, 32, 32};
|
||||
static uint height[] = {16, 32, 64, 32, 64, 64, 64, 32};
|
||||
list[i].width = width[regs.base_size];
|
||||
list[i].height = height[regs.base_size];
|
||||
if(regs.interlace && regs.base_size >= 6) list[i].height = 16;
|
||||
|
@ -70,25 +75,25 @@ void PPU::Sprite::render() {
|
|||
}
|
||||
}
|
||||
|
||||
unsigned itemcount = 0;
|
||||
unsigned tilecount = 0;
|
||||
uint itemcount = 0;
|
||||
uint tilecount = 0;
|
||||
memset(output.priority, 0xff, 256);
|
||||
memset(itemlist, 0xff, 32);
|
||||
for(unsigned i = 0; i < 34; i++) tilelist[i].tile = 0xffff;
|
||||
for(uint i = 0; i < 34; i++) tilelist[i].tile = 0xffff;
|
||||
|
||||
for(unsigned i = 0; i < 128; i++) {
|
||||
unsigned s = (regs.first_sprite + i) & 127;
|
||||
for(uint i = 0; i < 128; i++) {
|
||||
uint s = (regs.first_sprite + i) & 127;
|
||||
if(on_scanline(s) == false) continue;
|
||||
if(itemcount++ >= 32) break;
|
||||
itemlist[itemcount - 1] = s;
|
||||
}
|
||||
|
||||
for(signed i = 31; i >= 0; i--) {
|
||||
for(int i = 31; i >= 0; i--) {
|
||||
if(itemlist[i] == 0xff) continue;
|
||||
auto& s = list[itemlist[i]];
|
||||
unsigned tile_width = s.width >> 3;
|
||||
signed x = s.x;
|
||||
signed y = (self.vcounter() - s.y) & 0xff;
|
||||
uint tile_width = s.width >> 3;
|
||||
int x = s.x;
|
||||
int y = (self.vcounter() - s.y) & 0xff;
|
||||
if(regs.interlace) y <<= 1;
|
||||
|
||||
if(s.vflip) {
|
||||
|
@ -116,20 +121,20 @@ void PPU::Sprite::render() {
|
|||
chry &= 15;
|
||||
chry <<= 4;
|
||||
|
||||
for(unsigned tx = 0; tx < tile_width; tx++) {
|
||||
unsigned sx = (x + (tx << 3)) & 511;
|
||||
for(uint tx = 0; tx < tile_width; tx++) {
|
||||
uint sx = (x + (tx << 3)) & 511;
|
||||
if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;
|
||||
if(tilecount++ >= 34) break;
|
||||
|
||||
unsigned n = tilecount - 1;
|
||||
uint n = tilecount - 1;
|
||||
tilelist[n].x = sx;
|
||||
tilelist[n].y = y;
|
||||
tilelist[n].priority = s.priority;
|
||||
tilelist[n].palette = 128 + (s.palette << 4);
|
||||
tilelist[n].hflip = s.hflip;
|
||||
|
||||
unsigned mx = (s.hflip == false) ? tx : ((tile_width - 1) - tx);
|
||||
unsigned pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5);
|
||||
uint mx = (s.hflip == false) ? tx : ((tile_width - 1) - tx);
|
||||
uint pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5);
|
||||
tilelist[n].tile = (pos >> 5) & 0x07ff;
|
||||
}
|
||||
}
|
||||
|
@ -139,17 +144,17 @@ void PPU::Sprite::render() {
|
|||
|
||||
if(regs.main_enable == false && regs.sub_enable == false) return;
|
||||
|
||||
for(unsigned i = 0; i < 34; i++) {
|
||||
for(uint i = 0; i < 34; i++) {
|
||||
if(tilelist[i].tile == 0xffff) continue;
|
||||
|
||||
auto& t = tilelist[i];
|
||||
uint8* tiledata = self.cache.tile_4bpp(t.tile);
|
||||
tiledata += (t.y & 7) << 3;
|
||||
unsigned sx = t.x;
|
||||
for(unsigned x = 0; x < 8; x++) {
|
||||
uint sx = t.x;
|
||||
for(uint x = 0; x < 8; x++) {
|
||||
sx &= 511;
|
||||
if(sx < 256) {
|
||||
unsigned color = *(tiledata + (t.hflip == false ? x : 7 - x));
|
||||
uint color = *(tiledata + (t.hflip == false ? x : 7 - x));
|
||||
if(color) {
|
||||
color += t.palette;
|
||||
output.palette[sx] = color;
|
||||
|
@ -163,28 +168,19 @@ void PPU::Sprite::render() {
|
|||
if(regs.main_enable) window.render(0);
|
||||
if(regs.sub_enable) window.render(1);
|
||||
|
||||
unsigned priority0 = (priority0_enable ? regs.priority0 : 0);
|
||||
unsigned priority1 = (priority1_enable ? regs.priority1 : 0);
|
||||
unsigned priority2 = (priority2_enable ? regs.priority2 : 0);
|
||||
unsigned priority3 = (priority3_enable ? regs.priority3 : 0);
|
||||
uint priority0 = (priority0_enable ? regs.priority0 : 0);
|
||||
uint priority1 = (priority1_enable ? regs.priority1 : 0);
|
||||
uint priority2 = (priority2_enable ? regs.priority2 : 0);
|
||||
uint priority3 = (priority3_enable ? regs.priority3 : 0);
|
||||
if(priority0 + priority1 + priority2 + priority3 == 0) return;
|
||||
const unsigned priority_table[] = { priority0, priority1, priority2, priority3 };
|
||||
const uint priority_table[] = {priority0, priority1, priority2, priority3};
|
||||
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
if(output.priority[x] == 0xff) continue;
|
||||
unsigned priority = priority_table[output.priority[x]];
|
||||
unsigned palette = output.palette[x];
|
||||
unsigned color = self.screen.get_palette(output.palette[x]);
|
||||
uint priority = priority_table[output.priority[x]];
|
||||
uint palette = output.palette[x];
|
||||
uint color = self.screen.get_palette(output.palette[x]);
|
||||
if(regs.main_enable && !window.main[x]) self.screen.output.plot_main(x, color, priority, 4 + (palette < 192));
|
||||
if(regs.sub_enable && !window.sub[x]) self.screen.output.plot_sub(x, color, priority, 4 + (palette < 192));
|
||||
}
|
||||
}
|
||||
|
||||
PPU::Sprite::Sprite(PPU& self) : self(self) {
|
||||
priority0_enable = true;
|
||||
priority1_enable = true;
|
||||
priority2_enable = true;
|
||||
priority3_enable = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,19 +1,32 @@
|
|||
class Sprite {
|
||||
Sprite(PPU& self);
|
||||
|
||||
auto frame() -> void;
|
||||
auto update_list(uint addr, uint8 data) -> void;
|
||||
auto address_reset() -> void;
|
||||
auto set_first() -> void;
|
||||
alwaysinline auto on_scanline(uint sprite) -> bool;
|
||||
auto render() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
PPU& self;
|
||||
|
||||
bool priority0_enable;
|
||||
bool priority1_enable;
|
||||
bool priority2_enable;
|
||||
bool priority3_enable;
|
||||
|
||||
struct Regs {
|
||||
unsigned priority0;
|
||||
unsigned priority1;
|
||||
unsigned priority2;
|
||||
unsigned priority3;
|
||||
uint priority0;
|
||||
uint priority1;
|
||||
uint priority2;
|
||||
uint priority3;
|
||||
|
||||
unsigned base_size;
|
||||
unsigned nameselect;
|
||||
unsigned tiledata_addr;
|
||||
unsigned first_sprite;
|
||||
uint base_size;
|
||||
uint nameselect;
|
||||
uint tiledata_addr;
|
||||
uint first_sprite;
|
||||
|
||||
bool main_enable;
|
||||
bool sub_enable;
|
||||
|
@ -25,27 +38,27 @@ class Sprite {
|
|||
} regs;
|
||||
|
||||
struct List {
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned x;
|
||||
unsigned y;
|
||||
unsigned character;
|
||||
uint width;
|
||||
uint height;
|
||||
uint x;
|
||||
uint y;
|
||||
uint character;
|
||||
bool use_nameselect;
|
||||
bool vflip;
|
||||
bool hflip;
|
||||
unsigned palette;
|
||||
unsigned priority;
|
||||
uint palette;
|
||||
uint priority;
|
||||
bool size;
|
||||
} list[128];
|
||||
bool list_valid;
|
||||
|
||||
uint8 itemlist[32];
|
||||
struct TileList {
|
||||
unsigned x;
|
||||
unsigned y;
|
||||
unsigned priority;
|
||||
unsigned palette;
|
||||
unsigned tile;
|
||||
uint x;
|
||||
uint y;
|
||||
uint priority;
|
||||
uint palette;
|
||||
uint tile;
|
||||
bool hflip;
|
||||
} tilelist[34];
|
||||
|
||||
|
@ -56,16 +69,5 @@ class Sprite {
|
|||
|
||||
LayerWindow window;
|
||||
|
||||
void frame();
|
||||
void update_list(unsigned addr, uint8 data);
|
||||
void address_reset();
|
||||
void set_first();
|
||||
alwaysinline bool on_scanline(unsigned sprite);
|
||||
void render();
|
||||
|
||||
void serialize(serializer&);
|
||||
Sprite(PPU& self);
|
||||
|
||||
PPU& self;
|
||||
friend class PPU;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
void PPU::LayerWindow::render(bool screen) {
|
||||
auto PPU::LayerWindow::render(bool screen) -> void {
|
||||
uint8* output;
|
||||
if(screen == 0) {
|
||||
output = main;
|
||||
|
@ -23,7 +21,7 @@ void PPU::LayerWindow::render(bool screen) {
|
|||
|
||||
if(one_enable == true && two_enable == false) {
|
||||
bool set = 1 ^ one_invert, clr = !set;
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
output[x] = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ? set : clr;
|
||||
}
|
||||
return;
|
||||
|
@ -31,13 +29,13 @@ void PPU::LayerWindow::render(bool screen) {
|
|||
|
||||
if(one_enable == false && two_enable == true) {
|
||||
bool set = 1 ^ two_invert, clr = !set;
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
output[x] = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ? set : clr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
bool one_mask = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ^ one_invert;
|
||||
bool two_mask = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ^ two_invert;
|
||||
switch(mask) {
|
||||
|
@ -51,7 +49,7 @@ void PPU::LayerWindow::render(bool screen) {
|
|||
|
||||
//
|
||||
|
||||
void PPU::ColorWindow::render(bool screen) {
|
||||
auto PPU::ColorWindow::render(bool screen) -> void {
|
||||
uint8* output = (screen == 0 ? main : sub);
|
||||
bool set = 1, clr = 0;
|
||||
|
||||
|
@ -69,7 +67,7 @@ void PPU::ColorWindow::render(bool screen) {
|
|||
|
||||
if(one_enable == true && two_enable == false) {
|
||||
if(one_invert) { set ^= 1; clr ^= 1; }
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
output[x] = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ? set : clr;
|
||||
}
|
||||
return;
|
||||
|
@ -77,13 +75,13 @@ void PPU::ColorWindow::render(bool screen) {
|
|||
|
||||
if(one_enable == false && two_enable == true) {
|
||||
if(two_invert) { set ^= 1; clr ^= 1; }
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
output[x] = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ? set : clr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
for(uint x = 0; x < 256; x++) {
|
||||
bool one_mask = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ^ one_invert;
|
||||
bool two_mask = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ^ two_invert;
|
||||
switch(mask) {
|
||||
|
@ -94,5 +92,3 @@ void PPU::ColorWindow::render(bool screen) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
struct LayerWindow {
|
||||
auto render(bool screen) -> void;
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool one_enable;
|
||||
bool one_invert;
|
||||
bool two_enable;
|
||||
bool two_invert;
|
||||
|
||||
unsigned mask;
|
||||
uint mask;
|
||||
|
||||
bool main_enable;
|
||||
bool sub_enable;
|
||||
|
||||
uint8 main[256];
|
||||
uint8 sub[256];
|
||||
|
||||
void render(bool screen);
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
struct ColorWindow {
|
||||
auto render(bool screen) -> void;
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool one_enable;
|
||||
bool one_invert;
|
||||
bool two_enable;
|
||||
bool two_invert;
|
||||
|
||||
unsigned mask;
|
||||
uint mask;
|
||||
|
||||
unsigned main_mask;
|
||||
unsigned sub_mask;
|
||||
uint main_mask;
|
||||
uint sub_mask;
|
||||
|
||||
uint8 main[256];
|
||||
uint8 sub[256];
|
||||
|
||||
void render(bool screen);
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
uint8 SMP::op_adc(uint8 x, uint8 y) {
|
||||
auto SMP::op_adc(uint8 x, uint8 y) -> uint8 {
|
||||
int r = x + y + regs.p.c;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.v = ~(x ^ y) & (x ^ r) & 0x80;
|
||||
|
@ -8,7 +8,7 @@ uint8 SMP::op_adc(uint8 x, uint8 y) {
|
|||
return r;
|
||||
}
|
||||
|
||||
uint16 SMP::op_addw(uint16 x, uint16 y) {
|
||||
auto SMP::op_addw(uint16 x, uint16 y) -> uint16 {
|
||||
uint16 r;
|
||||
regs.p.c = 0;
|
||||
r = op_adc(x, y);
|
||||
|
@ -17,14 +17,14 @@ uint16 SMP::op_addw(uint16 x, uint16 y) {
|
|||
return r;
|
||||
}
|
||||
|
||||
uint8 SMP::op_and(uint8 x, uint8 y) {
|
||||
auto SMP::op_and(uint8 x, uint8 y) -> uint8 {
|
||||
x &= y;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 SMP::op_cmp(uint8 x, uint8 y) {
|
||||
auto SMP::op_cmp(uint8 x, uint8 y) -> uint8 {
|
||||
int r = x - y;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
|
@ -32,7 +32,7 @@ uint8 SMP::op_cmp(uint8 x, uint8 y) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint16 SMP::op_cmpw(uint16 x, uint16 y) {
|
||||
auto SMP::op_cmpw(uint16 x, uint16 y) -> uint16 {
|
||||
int r = x - y;
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
|
@ -40,21 +40,21 @@ uint16 SMP::op_cmpw(uint16 x, uint16 y) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint8 SMP::op_eor(uint8 x, uint8 y) {
|
||||
auto SMP::op_eor(uint8 x, uint8 y) -> uint8 {
|
||||
x ^= y;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 SMP::op_or(uint8 x, uint8 y) {
|
||||
auto SMP::op_or(uint8 x, uint8 y) -> uint8 {
|
||||
x |= y;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 SMP::op_sbc(uint8 x, uint8 y) {
|
||||
auto SMP::op_sbc(uint8 x, uint8 y) -> uint8 {
|
||||
int r = x - y - !regs.p.c;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.v = (x ^ y) & (x ^ r) & 0x80;
|
||||
|
@ -64,7 +64,7 @@ uint8 SMP::op_sbc(uint8 x, uint8 y) {
|
|||
return r;
|
||||
}
|
||||
|
||||
uint16 SMP::op_subw(uint16 x, uint16 y) {
|
||||
auto SMP::op_subw(uint16 x, uint16 y) -> uint16 {
|
||||
uint16 r;
|
||||
regs.p.c = 1;
|
||||
r = op_sbc(x, y);
|
||||
|
@ -73,21 +73,21 @@ uint16 SMP::op_subw(uint16 x, uint16 y) {
|
|||
return r;
|
||||
}
|
||||
|
||||
uint8 SMP::op_inc(uint8 x) {
|
||||
auto SMP::op_inc(uint8 x) -> uint8 {
|
||||
x++;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 SMP::op_dec(uint8 x) {
|
||||
auto SMP::op_dec(uint8 x) -> uint8 {
|
||||
x--;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 SMP::op_asl(uint8 x) {
|
||||
auto SMP::op_asl(uint8 x) -> uint8 {
|
||||
regs.p.c = x & 0x80;
|
||||
x <<= 1;
|
||||
regs.p.n = x & 0x80;
|
||||
|
@ -95,7 +95,7 @@ uint8 SMP::op_asl(uint8 x) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint8 SMP::op_lsr(uint8 x) {
|
||||
auto SMP::op_lsr(uint8 x) -> uint8 {
|
||||
regs.p.c = x & 0x01;
|
||||
x >>= 1;
|
||||
regs.p.n = x & 0x80;
|
||||
|
@ -103,8 +103,8 @@ uint8 SMP::op_lsr(uint8 x) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint8 SMP::op_rol(uint8 x) {
|
||||
unsigned carry = (unsigned)regs.p.c;
|
||||
auto SMP::op_rol(uint8 x) -> uint8 {
|
||||
auto carry = (uint)regs.p.c;
|
||||
regs.p.c = x & 0x80;
|
||||
x = (x << 1) | carry;
|
||||
regs.p.n = x & 0x80;
|
||||
|
@ -112,8 +112,8 @@ uint8 SMP::op_rol(uint8 x) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint8 SMP::op_ror(uint8 x) {
|
||||
unsigned carry = (unsigned)regs.p.c << 7;
|
||||
auto SMP::op_ror(uint8 x) -> uint8 {
|
||||
auto carry = (uint)regs.p.c << 7;
|
||||
regs.p.c = x & 0x01;
|
||||
x = carry | (x >> 1);
|
||||
regs.p.n = x & 0x80;
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
void SMP::tick() {
|
||||
auto SMP::tick() -> void {
|
||||
timer0.tick();
|
||||
timer1.tick();
|
||||
timer2.tick();
|
||||
|
||||
clock += cycle_step_cpu;
|
||||
dsp.clock -= 24;
|
||||
synchronize_dsp();
|
||||
synchronizeDSP();
|
||||
}
|
||||
|
||||
void SMP::op_io() {
|
||||
auto SMP::op_io() -> void {
|
||||
#if defined(CYCLE_ACCURATE)
|
||||
tick();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8 SMP::op_read(uint16 addr) {
|
||||
auto SMP::op_read(uint16 addr) -> uint8 {
|
||||
#if defined(CYCLE_ACCURATE)
|
||||
tick();
|
||||
#endif
|
||||
|
@ -23,7 +23,7 @@ uint8 SMP::op_read(uint16 addr) {
|
|||
return apuram[addr];
|
||||
}
|
||||
|
||||
void SMP::op_write(uint16 addr, uint8 data) {
|
||||
auto SMP::op_write(uint16 addr, uint8 data) -> void {
|
||||
#if defined(CYCLE_ACCURATE)
|
||||
tick();
|
||||
#endif
|
||||
|
@ -31,7 +31,7 @@ void SMP::op_write(uint16 addr, uint8 data) {
|
|||
apuram[addr] = data; //all writes go to RAM, even MMIO writes
|
||||
}
|
||||
|
||||
void SMP::op_step() {
|
||||
auto SMP::op_step() -> void {
|
||||
#define op_readpc() op_read(regs.pc++)
|
||||
#define op_readdp(addr) op_read((regs.p.p << 8) + addr)
|
||||
#define op_writedp(addr, data) op_write((regs.p.p << 8) + addr, data)
|
||||
|
@ -55,7 +55,7 @@ void SMP::op_step() {
|
|||
|
||||
#else
|
||||
|
||||
unsigned opcode = op_readpc();
|
||||
uint opcode = op_readpc();
|
||||
switch(opcode) {
|
||||
#include "core/op_misc.cpp"
|
||||
#include "core/op_mov.cpp"
|
||||
|
@ -77,7 +77,7 @@ void SMP::op_step() {
|
|||
#endif
|
||||
}
|
||||
|
||||
const unsigned SMP::cycle_count_table[256] = {
|
||||
const uint SMP::cycle_count_table[256] = {
|
||||
#define c 12
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,6,8, //0
|
||||
|
|
|
@ -8,10 +8,10 @@ static bool cycle_accurate;
|
|||
struct opcode_t {
|
||||
string name;
|
||||
lstring args;
|
||||
unsigned opcode;
|
||||
uint opcode;
|
||||
};
|
||||
|
||||
void generate(const char* sourceFilename, const char* targetFilename) {
|
||||
auto generate(const char* sourceFilename, const char* targetFilename) -> void {
|
||||
file fp;
|
||||
fp.open(targetFilename, file::mode::write);
|
||||
|
||||
|
@ -28,7 +28,7 @@ void generate(const char* sourceFilename, const char* targetFilename) {
|
|||
|
||||
linear_vector<opcode_t> array;
|
||||
|
||||
unsigned sourceStart = 0;
|
||||
uint sourceStart = 0;
|
||||
foreach(line, lines, currentLine) {
|
||||
line.transform("()", "``");
|
||||
lstring part;
|
||||
|
@ -54,7 +54,7 @@ void generate(const char* sourceFilename, const char* targetFilename) {
|
|||
foreach(opcode, array) {
|
||||
fp.print("case 0x", hex(opcode.opcode, 2L), ": {\n");
|
||||
|
||||
for(unsigned n = sourceStart; n < lines.size(); n++) {
|
||||
for(uint n = sourceStart; n < lines.size(); n++) {
|
||||
if(lines[n] == "}") break;
|
||||
|
||||
string output;
|
||||
|
@ -88,7 +88,7 @@ void generate(const char* sourceFilename, const char* targetFilename) {
|
|||
fp.print("case 0x", hex(opcode.opcode, 2L), ": {\n");
|
||||
fp.print(" switch(opcode_cycle++) {\n");
|
||||
|
||||
for(unsigned n = sourceStart; n < lines.size(); n++) {
|
||||
for(uint n = sourceStart; n < lines.size(); n++) {
|
||||
if(lines[n] == "}") break;
|
||||
|
||||
bool nextLineEndsCycle = false;
|
||||
|
@ -135,7 +135,7 @@ void generate(const char* sourceFilename, const char* targetFilename) {
|
|||
fp.close();
|
||||
}
|
||||
|
||||
int main() {
|
||||
auto main() -> int {
|
||||
cycle_accurate = false;
|
||||
generate("op_misc.b", "op_misc.cpp");
|
||||
generate("op_mov.b", "op_mov.cpp" );
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
uint8 SMP::disassemble_read(uint16 addr) {
|
||||
auto SMP::disassemble_read(uint16 addr) -> uint8 {
|
||||
if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f];
|
||||
return smp.apuram[addr];
|
||||
}
|
||||
|
||||
uint16 SMP::relb(int8 offset, int op_len) {
|
||||
auto SMP::relb(int8 offset, int op_len) -> uint16 {
|
||||
uint16 pc = regs.pc + op_len;
|
||||
return pc + offset;
|
||||
}
|
||||
|
||||
void SMP::disassemble_opcode(char* output, uint16 addr) {
|
||||
auto SMP::disassemble_opcode(char* output, uint16 addr) -> void {
|
||||
char* s;
|
||||
char t[512];
|
||||
uint8 op, op0, op1;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
unsigned SMP::port_read(unsigned addr) {
|
||||
auto SMP::port_read(uint addr) -> uint {
|
||||
return apuram[0xf4 + (addr & 3)];
|
||||
}
|
||||
|
||||
void SMP::port_write(unsigned addr, unsigned data) {
|
||||
auto SMP::port_write(uint addr, uint data) -> void {
|
||||
apuram[0xf4 + (addr & 3)] = data;
|
||||
}
|
||||
|
||||
unsigned SMP::mmio_read(unsigned addr) {
|
||||
auto SMP::mmio_read(uint addr) -> uint {
|
||||
switch(addr) {
|
||||
|
||||
case 0xf2:
|
||||
|
@ -19,7 +19,7 @@ unsigned SMP::mmio_read(unsigned addr) {
|
|||
case 0xf5:
|
||||
case 0xf6:
|
||||
case 0xf7:
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
return cpu.port_read(addr);
|
||||
|
||||
case 0xf8:
|
||||
|
@ -51,14 +51,14 @@ unsigned SMP::mmio_read(unsigned addr) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void SMP::mmio_write(unsigned addr, unsigned data) {
|
||||
auto SMP::mmio_write(uint addr, uint data) -> void {
|
||||
switch(addr) {
|
||||
|
||||
case 0xf1:
|
||||
status.iplrom_enable = data & 0x80;
|
||||
|
||||
if(data & 0x30) {
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
if(data & 0x20) {
|
||||
cpu.port_write(3, 0x00);
|
||||
cpu.port_write(2, 0x00);
|
||||
|
@ -102,7 +102,7 @@ void SMP::mmio_write(unsigned addr, unsigned data) {
|
|||
case 0xf5:
|
||||
case 0xf6:
|
||||
case 0xf7:
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
port_write(addr, data);
|
||||
break;
|
||||
|
||||
|
|
|
@ -12,7 +12,12 @@ SMP smp;
|
|||
#include "memory.cpp"
|
||||
#include "timing.cpp"
|
||||
|
||||
void SMP::synchronize_cpu() {
|
||||
SMP::SMP() {
|
||||
apuram = new uint8[64 * 1024];
|
||||
for(auto& byte : iplrom) byte = 0;
|
||||
}
|
||||
|
||||
auto SMP::synchronizeCPU() -> void {
|
||||
if(CPU::Threaded == true) {
|
||||
//if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
} else {
|
||||
|
@ -20,7 +25,7 @@ void SMP::synchronize_cpu() {
|
|||
}
|
||||
}
|
||||
|
||||
void SMP::synchronize_dsp() {
|
||||
auto SMP::synchronizeDSP() -> void {
|
||||
if(DSP::Threaded == true) {
|
||||
//if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread);
|
||||
} else {
|
||||
|
@ -28,11 +33,11 @@ void SMP::synchronize_dsp() {
|
|||
}
|
||||
}
|
||||
|
||||
void SMP::enter() {
|
||||
auto SMP::enter() -> void {
|
||||
while(clock < 0) op_step();
|
||||
}
|
||||
|
||||
void SMP::power() {
|
||||
auto SMP::power() -> void {
|
||||
Thread::frequency = system.apuFrequency();
|
||||
Thread::clock = 0;
|
||||
|
||||
|
@ -40,7 +45,7 @@ void SMP::power() {
|
|||
timer1.target = 0;
|
||||
timer2.target = 0;
|
||||
|
||||
for(unsigned n = 0; n < 256; n++) {
|
||||
for(uint n = 0; n < 256; n++) {
|
||||
cycle_table_dsp[n] = (cycle_count_table[n] * 24);
|
||||
cycle_table_cpu[n] = (cycle_count_table[n] * 24) * cpu.frequency;
|
||||
}
|
||||
|
@ -50,8 +55,8 @@ void SMP::power() {
|
|||
reset();
|
||||
}
|
||||
|
||||
void SMP::reset() {
|
||||
for(unsigned n = 0x0000; n <= 0xffff; n++) apuram[n] = 0x00;
|
||||
auto SMP::reset() -> void {
|
||||
for(uint n = 0x0000; n <= 0xffff; n++) apuram[n] = 0x00;
|
||||
|
||||
opcode_number = 0;
|
||||
opcode_cycle = 0;
|
||||
|
@ -80,7 +85,7 @@ void SMP::reset() {
|
|||
timer0.stage3_ticks = timer1.stage3_ticks = timer2.stage3_ticks = 0;
|
||||
}
|
||||
|
||||
void SMP::serialize(serializer& s) {
|
||||
auto SMP::serialize(serializer& s) -> void {
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(apuram, 64 * 1024);
|
||||
|
@ -137,12 +142,4 @@ void SMP::serialize(serializer& s) {
|
|||
s.integer(timer2.stage3_ticks);
|
||||
}
|
||||
|
||||
SMP::SMP() {
|
||||
apuram = new uint8[64 * 1024];
|
||||
for(auto& byte : iplrom) byte = 0;
|
||||
}
|
||||
|
||||
SMP::~SMP() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,49 +1,69 @@
|
|||
struct SMP : Thread {
|
||||
enum : bool { Threaded = false };
|
||||
|
||||
SMP();
|
||||
|
||||
alwaysinline auto synchronizeCPU() -> void;
|
||||
alwaysinline auto synchronizeDSP() -> void;
|
||||
|
||||
auto port_read(uint port) -> uint;
|
||||
auto port_write(uint port, unsigned data) -> void;
|
||||
|
||||
auto mmio_read(uint addr) -> uint;
|
||||
auto mmio_write(uint addr, uint data) -> void;
|
||||
|
||||
auto enter() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
auto disassemble_opcode(char* output, uint16 addr) -> void;
|
||||
|
||||
uint8 iplrom[64];
|
||||
uint8* apuram;
|
||||
|
||||
enum : bool { Threaded = false };
|
||||
alwaysinline void synchronize_cpu();
|
||||
alwaysinline void synchronize_dsp();
|
||||
|
||||
unsigned port_read(unsigned port);
|
||||
void port_write(unsigned port, unsigned data);
|
||||
|
||||
unsigned mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, unsigned data);
|
||||
|
||||
void enter();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
SMP();
|
||||
~SMP();
|
||||
|
||||
void disassemble_opcode(char *output, uint16 addr);
|
||||
|
||||
//private:
|
||||
struct Flags {
|
||||
bool n, v, p, b, h, i, z, c;
|
||||
auto tick() -> void;
|
||||
alwaysinline auto op_io() -> void;
|
||||
alwaysinline auto op_read(uint16 addr) -> uint8;
|
||||
alwaysinline auto op_write(uint16 addr, uint8 data) -> void;
|
||||
alwaysinline auto op_step() -> void;
|
||||
|
||||
alwaysinline operator unsigned() const {
|
||||
auto op_adc (uint8 x, uint8 y) -> uint8;
|
||||
auto op_addw(uint16 x, uint16 y) -> uint16;
|
||||
auto op_and (uint8 x, uint8 y) -> uint8;
|
||||
auto op_cmp (uint8 x, uint8 y) -> uint8;
|
||||
auto op_cmpw(uint16 x, uint16 y) -> uint16;
|
||||
auto op_eor (uint8 x, uint8 y) -> uint8;
|
||||
auto op_inc (uint8 x) -> uint8;
|
||||
auto op_dec (uint8 x) -> uint8;
|
||||
auto op_or (uint8 x, uint8 y) -> uint8;
|
||||
auto op_sbc (uint8 x, uint8 y) -> uint8;
|
||||
auto op_subw(uint16 x, uint16 y) -> uint16;
|
||||
auto op_asl (uint8 x) -> uint8;
|
||||
auto op_lsr (uint8 x) -> uint8;
|
||||
auto op_rol (uint8 x) -> uint8;
|
||||
auto op_ror (uint8 x) -> uint8;
|
||||
|
||||
struct Flags {
|
||||
alwaysinline operator uint() const {
|
||||
return (n << 7) | (v << 6) | (p << 5) | (b << 4)
|
||||
| (h << 3) | (i << 2) | (z << 1) | (c << 0);
|
||||
};
|
||||
|
||||
alwaysinline unsigned operator=(unsigned data) {
|
||||
alwaysinline auto operator=(uint data) -> uint {
|
||||
n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10;
|
||||
h = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
|
||||
return data;
|
||||
}
|
||||
|
||||
alwaysinline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); }
|
||||
alwaysinline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); }
|
||||
alwaysinline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); }
|
||||
};
|
||||
alwaysinline auto operator|=(uint data) -> uint { return operator=(operator uint() | data); }
|
||||
alwaysinline auto operator^=(uint data) -> uint { return operator=(operator uint() ^ data); }
|
||||
alwaysinline auto operator&=(uint data) -> uint { return operator=(operator uint() & data); }
|
||||
|
||||
unsigned opcode_number;
|
||||
unsigned opcode_cycle;
|
||||
bool n, v, p, b, h, i, z, c;
|
||||
};
|
||||
|
||||
struct Regs {
|
||||
uint16 pc;
|
||||
|
@ -63,54 +83,36 @@ struct SMP : Thread {
|
|||
bool iplrom_enable;
|
||||
|
||||
//$00f2
|
||||
unsigned dsp_addr;
|
||||
uint dsp_addr;
|
||||
|
||||
//$00f8,$00f9
|
||||
unsigned ram00f8;
|
||||
unsigned ram00f9;
|
||||
uint ram00f8;
|
||||
uint ram00f9;
|
||||
} status;
|
||||
|
||||
template<unsigned frequency>
|
||||
uint opcode_number;
|
||||
uint opcode_cycle;
|
||||
|
||||
template<uint frequency>
|
||||
struct Timer {
|
||||
auto tick() -> void;
|
||||
auto tick(uint clocks) -> void;
|
||||
|
||||
bool enable;
|
||||
uint8 target;
|
||||
uint8 stage1_ticks;
|
||||
uint8 stage2_ticks;
|
||||
uint8 stage3_ticks;
|
||||
|
||||
void tick();
|
||||
void tick(unsigned clocks);
|
||||
};
|
||||
|
||||
Timer<128> timer0;
|
||||
Timer<128> timer1;
|
||||
Timer< 16> timer2;
|
||||
|
||||
void tick();
|
||||
alwaysinline void op_io();
|
||||
alwaysinline uint8 op_read(uint16 addr);
|
||||
alwaysinline void op_write(uint16 addr, uint8 data);
|
||||
alwaysinline void op_step();
|
||||
static const unsigned cycle_count_table[256];
|
||||
static const uint cycle_count_table[256];
|
||||
uint64 cycle_table_cpu[256];
|
||||
unsigned cycle_table_dsp[256];
|
||||
uint cycle_table_dsp[256];
|
||||
uint64 cycle_step_cpu;
|
||||
|
||||
uint8 op_adc (uint8 x, uint8 y);
|
||||
uint16 op_addw(uint16 x, uint16 y);
|
||||
uint8 op_and (uint8 x, uint8 y);
|
||||
uint8 op_cmp (uint8 x, uint8 y);
|
||||
uint16 op_cmpw(uint16 x, uint16 y);
|
||||
uint8 op_eor (uint8 x, uint8 y);
|
||||
uint8 op_inc (uint8 x);
|
||||
uint8 op_dec (uint8 x);
|
||||
uint8 op_or (uint8 x, uint8 y);
|
||||
uint8 op_sbc (uint8 x, uint8 y);
|
||||
uint16 op_subw(uint16 x, uint16 y);
|
||||
uint8 op_asl (uint8 x);
|
||||
uint8 op_lsr (uint8 x);
|
||||
uint8 op_rol (uint8 x);
|
||||
uint8 op_ror (uint8 x);
|
||||
};
|
||||
|
||||
extern SMP smp;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
template<unsigned cycle_frequency>
|
||||
void SMP::Timer<cycle_frequency>::tick() {
|
||||
template<uint cycle_frequency>
|
||||
auto SMP::Timer<cycle_frequency>::tick() -> void {
|
||||
if(++stage1_ticks < cycle_frequency) return;
|
||||
|
||||
stage1_ticks = 0;
|
||||
|
@ -11,8 +11,8 @@ void SMP::Timer<cycle_frequency>::tick() {
|
|||
stage3_ticks = (stage3_ticks + 1) & 15;
|
||||
}
|
||||
|
||||
template<unsigned cycle_frequency>
|
||||
void SMP::Timer<cycle_frequency>::tick(unsigned clocks) {
|
||||
template<uint cycle_frequency>
|
||||
auto SMP::Timer<cycle_frequency>::tick(uint clocks) -> void {
|
||||
stage1_ticks += clocks;
|
||||
if(stage1_ticks < cycle_frequency) return;
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ Presentation::Presentation() {
|
|||
});
|
||||
synchronizeAudio.setText("Synchronize Audio").setChecked(settings["Audio/Synchronize"].boolean()).onToggle([&] {
|
||||
settings["Audio/Synchronize"].setValue(synchronizeAudio.checked());
|
||||
audio->set(Audio::Synchronize, synchronizeVideo.checked());
|
||||
audio->set(Audio::Synchronize, synchronizeAudio.checked());
|
||||
});
|
||||
muteAudio.setText("Mute Audio").setChecked(settings["Audio/Mute"].boolean()).onToggle([&] {
|
||||
settings["Audio/Mute"].setValue(muteAudio.checked());
|
||||
|
|
|
@ -2,7 +2,7 @@ auto Program::stateName(unsigned slot, bool manager) -> string {
|
|||
return {
|
||||
folderPaths[0], "higan/states/",
|
||||
manager ? "managed/" : "quick/",
|
||||
"slot-", decimal(slot, 2L), ".bst"
|
||||
"slot-", natural(slot, 2L), ".bst"
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue