mirror of https://github.com/bsnes-emu/bsnes.git
Update to v099r14 release.
byuu says: Changelog: - (u)int(max,ptr) abbreviations removed; use _t suffix now [didn't feel like they were contributing enough to be worth it] - cleaned up nall::integer,natural,real functionality - toInteger, toNatural, toReal for parsing strings to numbers - fromInteger, fromNatural, fromReal for creating strings from numbers - (string,Markup::Node,SQL-based-classes)::(integer,natural,real) left unchanged - template<typename T> numeral(T value, long padding, char padchar) -> string for print() formatting - deduces integer,natural,real based on T ... cast the value if you want to override - there still exists binary,octal,hex,pointer for explicit print() formatting - lstring -> string_vector [but using lstring = string_vector; is declared] - would be nice to remove the using lstring eventually ... but that'd probably require 10,000 lines of changes >_> - format -> string_format [no using here; format was too ambiguous] - using integer = Integer<sizeof(int)*8>; and using natural = Natural<sizeof(uint)*8>; declared - for consistency with boolean. These three are meant for creating zero-initialized values implicitly (various uses) - R65816::io() -> idle() and SPC700::io() -> idle() [more clear; frees up struct IO {} io; naming] - SFC CPU, PPU, SMP use struct IO {} io; over struct (Status,Registers) {} (status,registers); now - still some CPU::Status status values ... they didn't really fit into IO functionality ... will have to think about this more - SFC CPU, PPU, SMP now use step() exclusively instead of addClocks() calling into step() - SFC CPU joypad1_bits, joypad2_bits were unused; killed them - SFC PPU CGRAM moved into PPU::Screen; since nothing else uses it - SFC PPU OAM moved into PPU::Object; since nothing else uses it - the raw uint8[544] array is gone. OAM::read() constructs values from the OAM::Object[512] table now - this avoids having to determine how we want to sub-divide the two OAM memory sections - this also eliminates the OAM::synchronize() functionality - probably more I'm forgetting The FPS fluctuations are driving me insane. This WIP went from 128fps to 137fps. Settled on 133.5fps for the final build. But nothing I changed should have affected performance at all. This level of fluctuation makes it damn near impossible to know whether I'm speeding things up or slowing things down with changes.
This commit is contained in:
parent
67457fade4
commit
82293c95ae
|
@ -11,42 +11,17 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "099.13";
|
static const string Version = "099.14";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
|
||||||
//incremented only when serialization format changes
|
//incremented only when serialization format changes
|
||||||
static const string SerializerVersion = "099.07";
|
static const string SerializerVersion = "099.14";
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "interface.hpp"
|
#include "interface.hpp"
|
||||||
|
|
||||||
//debugging function hook:
|
|
||||||
//no overhead (and no debugger invocation) if not compiled with -DDEBUGGER
|
|
||||||
//wraps testing of function to allow invocation without a defined callback
|
|
||||||
template<typename T> struct hook;
|
|
||||||
template<typename R, typename... P> struct hook<auto (P...) -> R> {
|
|
||||||
function<auto (P...) -> R> callback;
|
|
||||||
|
|
||||||
auto operator()(P... p) const -> R {
|
|
||||||
#if defined(DEBUGGER)
|
|
||||||
if(callback) return callback(forward<P>(p)...);
|
|
||||||
#endif
|
|
||||||
return R();
|
|
||||||
}
|
|
||||||
|
|
||||||
hook() {}
|
|
||||||
hook(const hook& hook) { callback = hook.callback; }
|
|
||||||
hook(void* function) { callback = function; }
|
|
||||||
hook(auto (*function)(P...) -> R) { callback = function; }
|
|
||||||
template<typename C> hook(auto (C::*function)(P...) -> R, C* object) { callback = {function, object}; }
|
|
||||||
template<typename C> hook(auto (C::*function)(P...) const -> R, C* object) { callback = {function, object}; }
|
|
||||||
template<typename L> hook(const L& function) { callback = function; }
|
|
||||||
|
|
||||||
auto operator=(const hook& source) -> hook& { callback = source.callback; return *this; }
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(DEBUGGER)
|
#if defined(DEBUGGER)
|
||||||
#define privileged public
|
#define privileged public
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -49,7 +49,7 @@ struct Interface {
|
||||||
virtual auto audioSample(const double*, uint) -> void {}
|
virtual auto audioSample(const double*, uint) -> void {}
|
||||||
virtual auto inputPoll(uint, uint, uint) -> int16 { return 0; }
|
virtual auto inputPoll(uint, uint, uint) -> int16 { return 0; }
|
||||||
virtual auto inputRumble(uint, uint, uint, bool) -> void {}
|
virtual auto inputRumble(uint, uint, uint, bool) -> void {}
|
||||||
virtual auto dipSettings(const Markup::Node&) -> uint { return 0; }
|
virtual auto dipSettings(Markup::Node) -> uint { return 0; }
|
||||||
virtual auto notify(string text) -> void { print(text, "\n"); }
|
virtual auto notify(string text) -> void { print(text, "\n"); }
|
||||||
};
|
};
|
||||||
Bind* bind = nullptr;
|
Bind* bind = nullptr;
|
||||||
|
@ -62,7 +62,7 @@ struct Interface {
|
||||||
auto audioSample(const double* samples, uint channels) -> void { return bind->audioSample(samples, channels); }
|
auto audioSample(const double* samples, uint channels) -> void { return bind->audioSample(samples, channels); }
|
||||||
auto inputPoll(uint port, uint device, uint input) -> int16 { return bind->inputPoll(port, device, input); }
|
auto inputPoll(uint port, uint device, uint input) -> int16 { return bind->inputPoll(port, device, input); }
|
||||||
auto inputRumble(uint port, uint device, uint input, bool enable) -> void { return bind->inputRumble(port, device, input, enable); }
|
auto inputRumble(uint port, uint device, uint input, bool enable) -> void { return bind->inputRumble(port, device, input, enable); }
|
||||||
auto dipSettings(const Markup::Node& node) -> uint { return bind->dipSettings(node); }
|
auto dipSettings(Markup::Node node) -> uint { return bind->dipSettings(node); }
|
||||||
template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); }
|
template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); }
|
||||||
|
|
||||||
//information
|
//information
|
||||||
|
|
|
@ -169,8 +169,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
|
||||||
lstring codes = codeset.split("+");
|
lstring codes = codeset.split("+");
|
||||||
for(auto& code : codes) {
|
for(auto& code : codes) {
|
||||||
lstring part = code.split("/");
|
lstring part = code.split("/");
|
||||||
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1]));
|
if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
|
||||||
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,8 +168,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
|
||||||
lstring codes = codeset.split("+");
|
lstring codes = codeset.split("+");
|
||||||
for(auto& code : codes) {
|
for(auto& code : codes) {
|
||||||
lstring part = code.split("/");
|
lstring part = code.split("/");
|
||||||
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1]));
|
if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
|
||||||
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -402,7 +402,7 @@ auto R65816::disassemble(uint24 addr, bool e, bool m, bool x) -> string {
|
||||||
#undef a8
|
#undef a8
|
||||||
#undef x8
|
#undef x8
|
||||||
|
|
||||||
s.append(t, " A:{0} X:{1} Y:{2} S:{3} D:{4} B:{5} ", format{
|
s.append(t, " A:{0} X:{1} Y:{2} S:{3} D:{4} B:{5} ", string_format{
|
||||||
hex(r.a.w, 4), hex(r.x.w, 4), hex(r.y.w, 4),
|
hex(r.a.w, 4), hex(r.x.w, 4), hex(r.y.w, 4),
|
||||||
hex(r.s.w, 4), hex(r.d.w, 4), hex(r.db, 2)
|
hex(r.s.w, 4), hex(r.d.w, 4), hex(r.db, 2)
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
auto R65816::op_nop() {
|
auto R65816::op_nop() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_wdm() {
|
auto R65816::op_wdm() {
|
||||||
|
@ -7,11 +7,9 @@ L readPC();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_xba() {
|
auto R65816::op_xba() {
|
||||||
io();
|
idle();
|
||||||
L io();
|
L idle();
|
||||||
r.a.l ^= r.a.h;
|
r.a.w = r.a.w >> 8 | r.a.w << 8;
|
||||||
r.a.h ^= r.a.l;
|
|
||||||
r.a.l ^= r.a.h;
|
|
||||||
r.p.n = (r.a.l & 0x80);
|
r.p.n = (r.a.l & 0x80);
|
||||||
r.p.z = (r.a.l == 0);
|
r.p.z = (r.a.l == 0);
|
||||||
}
|
}
|
||||||
|
@ -22,10 +20,10 @@ auto R65816::op_move_b(int adjust) {
|
||||||
r.db = dp;
|
r.db = dp;
|
||||||
rd.l = readLong(sp << 16 | r.x.w);
|
rd.l = readLong(sp << 16 | r.x.w);
|
||||||
writeLong(dp << 16 | r.y.w, rd.l);
|
writeLong(dp << 16 | r.y.w, rd.l);
|
||||||
io();
|
idle();
|
||||||
r.x.l += adjust;
|
r.x.l += adjust;
|
||||||
r.y.l += adjust;
|
r.y.l += adjust;
|
||||||
L io();
|
L idle();
|
||||||
if(r.a.w--) r.pc.w -= 3;
|
if(r.a.w--) r.pc.w -= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,10 +33,10 @@ auto R65816::op_move_w(int adjust) {
|
||||||
r.db = dp;
|
r.db = dp;
|
||||||
rd.l = readLong(sp << 16 | r.x.w);
|
rd.l = readLong(sp << 16 | r.x.w);
|
||||||
writeLong(dp << 16 | r.y.w, rd.l);
|
writeLong(dp << 16 | r.y.w, rd.l);
|
||||||
io();
|
idle();
|
||||||
r.x.w += adjust;
|
r.x.w += adjust;
|
||||||
r.y.w += adjust;
|
r.y.w += adjust;
|
||||||
L io();
|
L idle();
|
||||||
if(r.a.w--) r.pc.w -= 3;
|
if(r.a.w--) r.pc.w -= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,20 +55,20 @@ L r.pc.h = readLong(vector + 1);
|
||||||
|
|
||||||
auto R65816::op_stp() {
|
auto R65816::op_stp() {
|
||||||
while(r.wai = true) {
|
while(r.wai = true) {
|
||||||
L io();
|
L idle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_wai() {
|
auto R65816::op_wai() {
|
||||||
r.wai = true;
|
r.wai = true;
|
||||||
while(r.wai) {
|
while(r.wai) {
|
||||||
L io();
|
L idle();
|
||||||
}
|
}
|
||||||
io();
|
idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_xce() {
|
auto R65816::op_xce() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
bool carry = r.p.c;
|
bool carry = r.p.c;
|
||||||
r.p.c = r.e;
|
r.p.c = r.e;
|
||||||
r.e = carry;
|
r.e = carry;
|
||||||
|
@ -83,24 +81,19 @@ L ioIRQ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//auto R65816::op_flag(bool& flag, bool value) {
|
|
||||||
//L ioIRQ();
|
|
||||||
// flag = value;
|
|
||||||
//}
|
|
||||||
|
|
||||||
auto R65816::op_set_flag(uint bit) {
|
auto R65816::op_set_flag(uint bit) {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
r.p |= 1 << bit;
|
r.p |= 1 << bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_clear_flag(uint bit) {
|
auto R65816::op_clear_flag(uint bit) {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
r.p &= ~(1 << bit);
|
r.p &= ~(1 << bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_pflag(bool mode) {
|
auto R65816::op_pflag(bool mode) {
|
||||||
rd.l = readPC();
|
rd.l = readPC();
|
||||||
L io();
|
L idle();
|
||||||
r.p = (mode ? r.p | rd.l : r.p & ~rd.l);
|
r.p = (mode ? r.p | rd.l : r.p & ~rd.l);
|
||||||
E r.p.m = 1, r.p.x = 1;
|
E r.p.m = 1, r.p.x = 1;
|
||||||
if(r.p.x) {
|
if(r.p.x) {
|
||||||
|
@ -110,89 +103,89 @@ E r.p.m = 1, r.p.x = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_transfer_b(Reg16& from, Reg16& to) {
|
auto R65816::op_transfer_b(Reg16& from, Reg16& to) {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
to.l = from.l;
|
to.l = from.l;
|
||||||
r.p.n = (to.l & 0x80);
|
r.p.n = (to.l & 0x80);
|
||||||
r.p.z = (to.l == 0);
|
r.p.z = (to.l == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_transfer_w(Reg16& from, Reg16& to) {
|
auto R65816::op_transfer_w(Reg16& from, Reg16& to) {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
to.w = from.w;
|
to.w = from.w;
|
||||||
r.p.n = (to.w & 0x8000);
|
r.p.n = (to.w & 0x8000);
|
||||||
r.p.z = (to.w == 0);
|
r.p.z = (to.w == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_tcs() {
|
auto R65816::op_tcs() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
r.s.w = r.a.w;
|
r.s.w = r.a.w;
|
||||||
E r.s.h = 0x01;
|
E r.s.h = 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_tsx_b() {
|
auto R65816::op_tsx_b() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
r.x.l = r.s.l;
|
r.x.l = r.s.l;
|
||||||
r.p.n = (r.x.l & 0x80);
|
r.p.n = (r.x.l & 0x80);
|
||||||
r.p.z = (r.x.l == 0);
|
r.p.z = (r.x.l == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_tsx_w() {
|
auto R65816::op_tsx_w() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
r.x.w = r.s.w;
|
r.x.w = r.s.w;
|
||||||
r.p.n = (r.x.w & 0x8000);
|
r.p.n = (r.x.w & 0x8000);
|
||||||
r.p.z = (r.x.w == 0);
|
r.p.z = (r.x.w == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_txs() {
|
auto R65816::op_txs() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
E r.s.l = r.x.l;
|
E r.s.l = r.x.l;
|
||||||
N r.s.w = r.x.w;
|
N r.s.w = r.x.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_push_b(Reg16& reg) {
|
auto R65816::op_push_b(Reg16& reg) {
|
||||||
io();
|
idle();
|
||||||
L writeSP(reg.l);
|
L writeSP(reg.l);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_push_w(Reg16& reg) {
|
auto R65816::op_push_w(Reg16& reg) {
|
||||||
io();
|
idle();
|
||||||
writeSP(reg.h);
|
writeSP(reg.h);
|
||||||
L writeSP(reg.l);
|
L writeSP(reg.l);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_phd() {
|
auto R65816::op_phd() {
|
||||||
io();
|
idle();
|
||||||
writeSPn(r.d.h);
|
writeSPn(r.d.h);
|
||||||
L writeSPn(r.d.l);
|
L writeSPn(r.d.l);
|
||||||
E r.s.h = 0x01;
|
E r.s.h = 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_phb() {
|
auto R65816::op_phb() {
|
||||||
io();
|
idle();
|
||||||
L writeSP(r.db);
|
L writeSP(r.db);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_phk() {
|
auto R65816::op_phk() {
|
||||||
io();
|
idle();
|
||||||
L writeSP(r.pc.b);
|
L writeSP(r.pc.b);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_php() {
|
auto R65816::op_php() {
|
||||||
io();
|
idle();
|
||||||
L writeSP(r.p);
|
L writeSP(r.p);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_pull_b(Reg16& reg) {
|
auto R65816::op_pull_b(Reg16& reg) {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
L reg.l = readSP();
|
L reg.l = readSP();
|
||||||
r.p.n = (reg.l & 0x80);
|
r.p.n = (reg.l & 0x80);
|
||||||
r.p.z = (reg.l == 0);
|
r.p.z = (reg.l == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_pull_w(Reg16& reg) {
|
auto R65816::op_pull_w(Reg16& reg) {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
reg.l = readSP();
|
reg.l = readSP();
|
||||||
L reg.h = readSP();
|
L reg.h = readSP();
|
||||||
r.p.n = (reg.w & 0x8000);
|
r.p.n = (reg.w & 0x8000);
|
||||||
|
@ -200,8 +193,8 @@ L reg.h = readSP();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_pld() {
|
auto R65816::op_pld() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
r.d.l = readSPn();
|
r.d.l = readSPn();
|
||||||
L r.d.h = readSPn();
|
L r.d.h = readSPn();
|
||||||
r.p.n = (r.d.w & 0x8000);
|
r.p.n = (r.d.w & 0x8000);
|
||||||
|
@ -210,16 +203,16 @@ E r.s.h = 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_plb() {
|
auto R65816::op_plb() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
L r.db = readSP();
|
L r.db = readSP();
|
||||||
r.p.n = (r.db & 0x80);
|
r.p.n = (r.db & 0x80);
|
||||||
r.p.z = (r.db == 0);
|
r.p.z = (r.db == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_plp() {
|
auto R65816::op_plp() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
L r.p = readSP();
|
L r.p = readSP();
|
||||||
E r.p.m = 1, r.p.x = 1;
|
E r.p.m = 1, r.p.x = 1;
|
||||||
if(r.p.x) {
|
if(r.p.x) {
|
||||||
|
@ -238,7 +231,7 @@ E r.s.h = 0x01;
|
||||||
|
|
||||||
auto R65816::op_pei() {
|
auto R65816::op_pei() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDPn(dp + 0);
|
aa.l = readDPn(dp + 0);
|
||||||
aa.h = readDPn(dp + 1);
|
aa.h = readDPn(dp + 1);
|
||||||
writeSPn(aa.h);
|
writeSPn(aa.h);
|
||||||
|
@ -249,7 +242,7 @@ E r.s.h = 0x01;
|
||||||
auto R65816::op_per() {
|
auto R65816::op_per() {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io();
|
idle();
|
||||||
rd.w = r.pc.d + (int16)aa.w;
|
rd.w = r.pc.d + (int16)aa.w;
|
||||||
writeSPn(rd.h);
|
writeSPn(rd.h);
|
||||||
L writeSPn(rd.l);
|
L writeSPn(rd.l);
|
||||||
|
|
|
@ -4,8 +4,8 @@ L rd.l = readPC();
|
||||||
} else {
|
} else {
|
||||||
rd.l = readPC();
|
rd.l = readPC();
|
||||||
aa.w = r.pc.d + (int8)rd.l;
|
aa.w = r.pc.d + (int8)rd.l;
|
||||||
io6(aa.w);
|
idle6(aa.w);
|
||||||
L io();
|
L idle();
|
||||||
r.pc.w = aa.w;
|
r.pc.w = aa.w;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,15 +13,15 @@ L io();
|
||||||
auto R65816::op_bra() {
|
auto R65816::op_bra() {
|
||||||
rd.l = readPC();
|
rd.l = readPC();
|
||||||
aa.w = r.pc.d + (int8)rd.l;
|
aa.w = r.pc.d + (int8)rd.l;
|
||||||
io6(aa.w);
|
idle6(aa.w);
|
||||||
L io();
|
L idle();
|
||||||
r.pc.w = aa.w;
|
r.pc.w = aa.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_brl() {
|
auto R65816::op_brl() {
|
||||||
rd.l = readPC();
|
rd.l = readPC();
|
||||||
rd.h = readPC();
|
rd.h = readPC();
|
||||||
L io();
|
L idle();
|
||||||
r.pc.w = r.pc.d + (int16)rd.w;
|
r.pc.w = r.pc.d + (int16)rd.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ L rd.h = readAddr(aa.w + 1);
|
||||||
auto R65816::op_jmp_iaddrx() {
|
auto R65816::op_jmp_iaddrx() {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io();
|
idle();
|
||||||
rd.l = readPB(aa.w + r.x.w + 0);
|
rd.l = readPB(aa.w + r.x.w + 0);
|
||||||
L rd.h = readPB(aa.w + r.x.w + 1);
|
L rd.h = readPB(aa.w + r.x.w + 1);
|
||||||
r.pc.w = rd.w;
|
r.pc.w = rd.w;
|
||||||
|
@ -67,7 +67,7 @@ L rd.b = readAddr(aa.w + 2);
|
||||||
auto R65816::op_jsr_addr() {
|
auto R65816::op_jsr_addr() {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io();
|
idle();
|
||||||
r.pc.w--;
|
r.pc.w--;
|
||||||
writeSP(r.pc.h);
|
writeSP(r.pc.h);
|
||||||
L writeSP(r.pc.l);
|
L writeSP(r.pc.l);
|
||||||
|
@ -78,7 +78,7 @@ auto R65816::op_jsr_long() {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
writeSPn(r.pc.b);
|
writeSPn(r.pc.b);
|
||||||
io();
|
idle();
|
||||||
aa.b = readPC();
|
aa.b = readPC();
|
||||||
r.pc.w--;
|
r.pc.w--;
|
||||||
writeSPn(r.pc.h);
|
writeSPn(r.pc.h);
|
||||||
|
@ -92,7 +92,7 @@ auto R65816::op_jsr_iaddrx() {
|
||||||
writeSPn(r.pc.h);
|
writeSPn(r.pc.h);
|
||||||
writeSPn(r.pc.l);
|
writeSPn(r.pc.l);
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io();
|
idle();
|
||||||
rd.l = readPB(aa.w + r.x.w + 0);
|
rd.l = readPB(aa.w + r.x.w + 0);
|
||||||
L rd.h = readPB(aa.w + r.x.w + 1);
|
L rd.h = readPB(aa.w + r.x.w + 1);
|
||||||
r.pc.w = rd.w;
|
r.pc.w = rd.w;
|
||||||
|
@ -100,8 +100,8 @@ E r.s.h = 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_rti() {
|
auto R65816::op_rti() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
r.p = readSP();
|
r.p = readSP();
|
||||||
E r.p.m = 1, r.p.x = 1;
|
E r.p.m = 1, r.p.x = 1;
|
||||||
if(r.p.x) {
|
if(r.p.x) {
|
||||||
|
@ -118,17 +118,17 @@ E r.p.m = 1, r.p.x = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_rts() {
|
auto R65816::op_rts() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
rd.l = readSP();
|
rd.l = readSP();
|
||||||
rd.h = readSP();
|
rd.h = readSP();
|
||||||
L io();
|
L idle();
|
||||||
r.pc.w = ++rd.w;
|
r.pc.w = ++rd.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_rtl() {
|
auto R65816::op_rtl() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
rd.l = readSPn();
|
rd.l = readSPn();
|
||||||
rd.h = readSPn();
|
rd.h = readSPn();
|
||||||
L rd.b = readSPn();
|
L rd.b = readSPn();
|
||||||
|
|
|
@ -38,7 +38,7 @@ L rd.h = readDB(aa.w + 1);
|
||||||
auto R65816::op_read_addrx_b(fp op) {
|
auto R65816::op_read_addrx_b(fp op) {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io4(aa.w, aa.w + r.x.w);
|
idle4(aa.w, aa.w + r.x.w);
|
||||||
L rd.l = readDB(aa.w + r.x.w);
|
L rd.l = readDB(aa.w + r.x.w);
|
||||||
call(op);
|
call(op);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ L rd.l = readDB(aa.w + r.x.w);
|
||||||
auto R65816::op_read_addrx_w(fp op) {
|
auto R65816::op_read_addrx_w(fp op) {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io4(aa.w, aa.w + r.x.w);
|
idle4(aa.w, aa.w + r.x.w);
|
||||||
rd.l = readDB(aa.w + r.x.w + 0);
|
rd.l = readDB(aa.w + r.x.w + 0);
|
||||||
L rd.h = readDB(aa.w + r.x.w + 1);
|
L rd.h = readDB(aa.w + r.x.w + 1);
|
||||||
call(op);
|
call(op);
|
||||||
|
@ -55,7 +55,7 @@ L rd.h = readDB(aa.w + r.x.w + 1);
|
||||||
auto R65816::op_read_addry_b(fp op) {
|
auto R65816::op_read_addry_b(fp op) {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io4(aa.w, aa.w + r.y.w);
|
idle4(aa.w, aa.w + r.y.w);
|
||||||
L rd.l = readDB(aa.w + r.y.w);
|
L rd.l = readDB(aa.w + r.y.w);
|
||||||
call(op);
|
call(op);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ L rd.l = readDB(aa.w + r.y.w);
|
||||||
auto R65816::op_read_addry_w(fp op) {
|
auto R65816::op_read_addry_w(fp op) {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io4(aa.w, aa.w + r.y.w);
|
idle4(aa.w, aa.w + r.y.w);
|
||||||
rd.l = readDB(aa.w + r.y.w + 0);
|
rd.l = readDB(aa.w + r.y.w + 0);
|
||||||
L rd.h = readDB(aa.w + r.y.w + 1);
|
L rd.h = readDB(aa.w + r.y.w + 1);
|
||||||
call(op);
|
call(op);
|
||||||
|
@ -105,14 +105,14 @@ L rd.h = readLong(aa.d + r.x.w + 1);
|
||||||
|
|
||||||
auto R65816::op_read_dp_b(fp op) {
|
auto R65816::op_read_dp_b(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
L rd.l = readDP(dp);
|
L rd.l = readDP(dp);
|
||||||
call(op);
|
call(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_read_dp_w(fp op) {
|
auto R65816::op_read_dp_w(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
rd.l = readDP(dp + 0);
|
rd.l = readDP(dp + 0);
|
||||||
L rd.h = readDP(dp + 1);
|
L rd.h = readDP(dp + 1);
|
||||||
call(op);
|
call(op);
|
||||||
|
@ -120,16 +120,16 @@ L rd.h = readDP(dp + 1);
|
||||||
|
|
||||||
auto R65816::op_read_dpr_b(fp op, Reg16& reg) {
|
auto R65816::op_read_dpr_b(fp op, Reg16& reg) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
io();
|
idle();
|
||||||
L rd.l = readDP(dp + reg.w);
|
L rd.l = readDP(dp + reg.w);
|
||||||
call(op);
|
call(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_read_dpr_w(fp op, Reg16& reg) {
|
auto R65816::op_read_dpr_w(fp op, Reg16& reg) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
io();
|
idle();
|
||||||
rd.l = readDP(dp + reg.w + 0);
|
rd.l = readDP(dp + reg.w + 0);
|
||||||
L rd.h = readDP(dp + reg.w + 1);
|
L rd.h = readDP(dp + reg.w + 1);
|
||||||
call(op);
|
call(op);
|
||||||
|
@ -137,7 +137,7 @@ L rd.h = readDP(dp + reg.w + 1);
|
||||||
|
|
||||||
auto R65816::op_read_idp_b(fp op) {
|
auto R65816::op_read_idp_b(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDP(dp + 0);
|
aa.l = readDP(dp + 0);
|
||||||
aa.h = readDP(dp + 1);
|
aa.h = readDP(dp + 1);
|
||||||
L rd.l = readDB(aa.w);
|
L rd.l = readDB(aa.w);
|
||||||
|
@ -146,7 +146,7 @@ L rd.l = readDB(aa.w);
|
||||||
|
|
||||||
auto R65816::op_read_idp_w(fp op) {
|
auto R65816::op_read_idp_w(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDP(dp + 0);
|
aa.l = readDP(dp + 0);
|
||||||
aa.h = readDP(dp + 1);
|
aa.h = readDP(dp + 1);
|
||||||
rd.l = readDB(aa.w + 0);
|
rd.l = readDB(aa.w + 0);
|
||||||
|
@ -156,8 +156,8 @@ L rd.h = readDB(aa.w + 1);
|
||||||
|
|
||||||
auto R65816::op_read_idpx_b(fp op) {
|
auto R65816::op_read_idpx_b(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
io();
|
idle();
|
||||||
aa.l = readDP(dp + r.x.w + 0);
|
aa.l = readDP(dp + r.x.w + 0);
|
||||||
aa.h = readDP(dp + r.x.w + 1);
|
aa.h = readDP(dp + r.x.w + 1);
|
||||||
L rd.l = readDB(aa.w);
|
L rd.l = readDB(aa.w);
|
||||||
|
@ -166,8 +166,8 @@ L rd.l = readDB(aa.w);
|
||||||
|
|
||||||
auto R65816::op_read_idpx_w(fp op) {
|
auto R65816::op_read_idpx_w(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
io();
|
idle();
|
||||||
aa.l = readDP(dp + r.x.w + 0);
|
aa.l = readDP(dp + r.x.w + 0);
|
||||||
aa.h = readDP(dp + r.x.w + 1);
|
aa.h = readDP(dp + r.x.w + 1);
|
||||||
rd.l = readDB(aa.w + 0);
|
rd.l = readDB(aa.w + 0);
|
||||||
|
@ -177,20 +177,20 @@ L rd.h = readDB(aa.w + 1);
|
||||||
|
|
||||||
auto R65816::op_read_idpy_b(fp op) {
|
auto R65816::op_read_idpy_b(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDP(dp + 0);
|
aa.l = readDP(dp + 0);
|
||||||
aa.h = readDP(dp + 1);
|
aa.h = readDP(dp + 1);
|
||||||
io4(aa.w, aa.w + r.y.w);
|
idle4(aa.w, aa.w + r.y.w);
|
||||||
L rd.l = readDB(aa.w + r.y.w);
|
L rd.l = readDB(aa.w + r.y.w);
|
||||||
call(op);
|
call(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_read_idpy_w(fp op) {
|
auto R65816::op_read_idpy_w(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDP(dp + 0);
|
aa.l = readDP(dp + 0);
|
||||||
aa.h = readDP(dp + 1);
|
aa.h = readDP(dp + 1);
|
||||||
io4(aa.w, aa.w + r.y.w);
|
idle4(aa.w, aa.w + r.y.w);
|
||||||
rd.l = readDB(aa.w + r.y.w + 0);
|
rd.l = readDB(aa.w + r.y.w + 0);
|
||||||
L rd.h = readDB(aa.w + r.y.w + 1);
|
L rd.h = readDB(aa.w + r.y.w + 1);
|
||||||
call(op);
|
call(op);
|
||||||
|
@ -198,7 +198,7 @@ L rd.h = readDB(aa.w + r.y.w + 1);
|
||||||
|
|
||||||
auto R65816::op_read_ildp_b(fp op) {
|
auto R65816::op_read_ildp_b(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDPn(dp + 0);
|
aa.l = readDPn(dp + 0);
|
||||||
aa.h = readDPn(dp + 1);
|
aa.h = readDPn(dp + 1);
|
||||||
aa.b = readDPn(dp + 2);
|
aa.b = readDPn(dp + 2);
|
||||||
|
@ -208,7 +208,7 @@ L rd.l = readLong(aa.d);
|
||||||
|
|
||||||
auto R65816::op_read_ildp_w(fp op) {
|
auto R65816::op_read_ildp_w(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDPn(dp + 0);
|
aa.l = readDPn(dp + 0);
|
||||||
aa.h = readDPn(dp + 1);
|
aa.h = readDPn(dp + 1);
|
||||||
aa.b = readDPn(dp + 2);
|
aa.b = readDPn(dp + 2);
|
||||||
|
@ -219,7 +219,7 @@ L rd.h = readLong(aa.d + 1);
|
||||||
|
|
||||||
auto R65816::op_read_ildpy_b(fp op) {
|
auto R65816::op_read_ildpy_b(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDPn(dp + 0);
|
aa.l = readDPn(dp + 0);
|
||||||
aa.h = readDPn(dp + 1);
|
aa.h = readDPn(dp + 1);
|
||||||
aa.b = readDPn(dp + 2);
|
aa.b = readDPn(dp + 2);
|
||||||
|
@ -229,7 +229,7 @@ L rd.l = readLong(aa.d + r.y.w);
|
||||||
|
|
||||||
auto R65816::op_read_ildpy_w(fp op) {
|
auto R65816::op_read_ildpy_w(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDPn(dp + 0);
|
aa.l = readDPn(dp + 0);
|
||||||
aa.h = readDPn(dp + 1);
|
aa.h = readDPn(dp + 1);
|
||||||
aa.b = readDPn(dp + 2);
|
aa.b = readDPn(dp + 2);
|
||||||
|
@ -240,14 +240,14 @@ L rd.h = readLong(aa.d + r.y.w + 1);
|
||||||
|
|
||||||
auto R65816::op_read_sr_b(fp op) {
|
auto R65816::op_read_sr_b(fp op) {
|
||||||
sp = readPC();
|
sp = readPC();
|
||||||
io();
|
idle();
|
||||||
L rd.l = readSP(sp);
|
L rd.l = readSP(sp);
|
||||||
call(op);
|
call(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_read_sr_w(fp op) {
|
auto R65816::op_read_sr_w(fp op) {
|
||||||
sp = readPC();
|
sp = readPC();
|
||||||
io();
|
idle();
|
||||||
rd.l = readSP(sp + 0);
|
rd.l = readSP(sp + 0);
|
||||||
L rd.h = readSP(sp + 1);
|
L rd.h = readSP(sp + 1);
|
||||||
call(op);
|
call(op);
|
||||||
|
@ -255,20 +255,20 @@ L rd.h = readSP(sp + 1);
|
||||||
|
|
||||||
auto R65816::op_read_isry_b(fp op) {
|
auto R65816::op_read_isry_b(fp op) {
|
||||||
sp = readPC();
|
sp = readPC();
|
||||||
io();
|
idle();
|
||||||
aa.l = readSP(sp + 0);
|
aa.l = readSP(sp + 0);
|
||||||
aa.h = readSP(sp + 1);
|
aa.h = readSP(sp + 1);
|
||||||
io();
|
idle();
|
||||||
L rd.l = readDB(aa.w + r.y.w);
|
L rd.l = readDB(aa.w + r.y.w);
|
||||||
call(op);
|
call(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_read_isry_w(fp op) {
|
auto R65816::op_read_isry_w(fp op) {
|
||||||
sp = readPC();
|
sp = readPC();
|
||||||
io();
|
idle();
|
||||||
aa.l = readSP(sp + 0);
|
aa.l = readSP(sp + 0);
|
||||||
aa.h = readSP(sp + 1);
|
aa.h = readSP(sp + 1);
|
||||||
io();
|
idle();
|
||||||
rd.l = readDB(aa.w + r.y.w + 0);
|
rd.l = readDB(aa.w + r.y.w + 0);
|
||||||
L rd.h = readDB(aa.w + r.y.w + 1);
|
L rd.h = readDB(aa.w + r.y.w + 1);
|
||||||
call(op);
|
call(op);
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
auto R65816::op_adjust_imm_b(Reg16& reg, int adjust) {
|
auto R65816::op_adjust_imm_b(Reg16& reg, int adjust) {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
reg.l += adjust;
|
reg.l += adjust;
|
||||||
r.p.n = (reg.l & 0x80);
|
r.p.n = (reg.l & 0x80);
|
||||||
r.p.z = (reg.l == 0);
|
r.p.z = (reg.l == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_adjust_imm_w(Reg16& reg, int adjust) {
|
auto R65816::op_adjust_imm_w(Reg16& reg, int adjust) {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
reg.w += adjust;
|
reg.w += adjust;
|
||||||
r.p.n = (reg.w & 0x8000);
|
r.p.n = (reg.w & 0x8000);
|
||||||
r.p.z = (reg.w == 0);
|
r.p.z = (reg.w == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_asl_imm_b() {
|
auto R65816::op_asl_imm_b() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
r.p.c = (r.a.l & 0x80);
|
r.p.c = (r.a.l & 0x80);
|
||||||
r.a.l <<= 1;
|
r.a.l <<= 1;
|
||||||
r.p.n = (r.a.l & 0x80);
|
r.p.n = (r.a.l & 0x80);
|
||||||
|
@ -21,7 +21,7 @@ L ioIRQ();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_asl_imm_w() {
|
auto R65816::op_asl_imm_w() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
r.p.c = (r.a.w & 0x8000);
|
r.p.c = (r.a.w & 0x8000);
|
||||||
r.a.w <<= 1;
|
r.a.w <<= 1;
|
||||||
r.p.n = (r.a.w & 0x8000);
|
r.p.n = (r.a.w & 0x8000);
|
||||||
|
@ -29,7 +29,7 @@ L ioIRQ();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_lsr_imm_b() {
|
auto R65816::op_lsr_imm_b() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
r.p.c = (r.a.l & 0x01);
|
r.p.c = (r.a.l & 0x01);
|
||||||
r.a.l >>= 1;
|
r.a.l >>= 1;
|
||||||
r.p.n = (r.a.l & 0x80);
|
r.p.n = (r.a.l & 0x80);
|
||||||
|
@ -37,7 +37,7 @@ L ioIRQ();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_lsr_imm_w() {
|
auto R65816::op_lsr_imm_w() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
r.p.c = (r.a.w & 0x0001);
|
r.p.c = (r.a.w & 0x0001);
|
||||||
r.a.w >>= 1;
|
r.a.w >>= 1;
|
||||||
r.p.n = (r.a.w & 0x8000);
|
r.p.n = (r.a.w & 0x8000);
|
||||||
|
@ -45,7 +45,7 @@ L ioIRQ();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_rol_imm_b() {
|
auto R65816::op_rol_imm_b() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
bool carry = r.p.c;
|
bool carry = r.p.c;
|
||||||
r.p.c = (r.a.l & 0x80);
|
r.p.c = (r.a.l & 0x80);
|
||||||
r.a.l = (r.a.l << 1) | carry;
|
r.a.l = (r.a.l << 1) | carry;
|
||||||
|
@ -54,7 +54,7 @@ L ioIRQ();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_rol_imm_w() {
|
auto R65816::op_rol_imm_w() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
bool carry = r.p.c;
|
bool carry = r.p.c;
|
||||||
r.p.c = (r.a.w & 0x8000);
|
r.p.c = (r.a.w & 0x8000);
|
||||||
r.a.w = (r.a.w << 1) | carry;
|
r.a.w = (r.a.w << 1) | carry;
|
||||||
|
@ -63,7 +63,7 @@ L ioIRQ();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_ror_imm_b() {
|
auto R65816::op_ror_imm_b() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
bool carry = r.p.c;
|
bool carry = r.p.c;
|
||||||
r.p.c = (r.a.l & 0x01);
|
r.p.c = (r.a.l & 0x01);
|
||||||
r.a.l = (carry << 7) | (r.a.l >> 1);
|
r.a.l = (carry << 7) | (r.a.l >> 1);
|
||||||
|
@ -72,7 +72,7 @@ L ioIRQ();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_ror_imm_w() {
|
auto R65816::op_ror_imm_w() {
|
||||||
L ioIRQ();
|
L idleIRQ();
|
||||||
bool carry = r.p.c;
|
bool carry = r.p.c;
|
||||||
r.p.c = (r.a.w & 0x0001);
|
r.p.c = (r.a.w & 0x0001);
|
||||||
r.a.w = (carry << 15) | (r.a.w >> 1);
|
r.a.w = (carry << 15) | (r.a.w >> 1);
|
||||||
|
@ -84,7 +84,7 @@ auto R65816::op_adjust_addr_b(fp op) {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
rd.l = readDB(aa.w);
|
rd.l = readDB(aa.w);
|
||||||
io();
|
idle();
|
||||||
call(op);
|
call(op);
|
||||||
L writeDB(aa.w, rd.l);
|
L writeDB(aa.w, rd.l);
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ auto R65816::op_adjust_addr_w(fp op) {
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
rd.l = readDB(aa.w + 0);
|
rd.l = readDB(aa.w + 0);
|
||||||
rd.h = readDB(aa.w + 1);
|
rd.h = readDB(aa.w + 1);
|
||||||
io();
|
idle();
|
||||||
call(op);
|
call(op);
|
||||||
writeDB(aa.w + 1, rd.h);
|
writeDB(aa.w + 1, rd.h);
|
||||||
L writeDB(aa.w + 0, rd.l);
|
L writeDB(aa.w + 0, rd.l);
|
||||||
|
@ -103,9 +103,9 @@ L writeDB(aa.w + 0, rd.l);
|
||||||
auto R65816::op_adjust_addrx_b(fp op) {
|
auto R65816::op_adjust_addrx_b(fp op) {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io();
|
idle();
|
||||||
rd.l = readDB(aa.w + r.x.w);
|
rd.l = readDB(aa.w + r.x.w);
|
||||||
io();
|
idle();
|
||||||
call(op);
|
call(op);
|
||||||
L writeDB(aa.w + r.x.w, rd.l);
|
L writeDB(aa.w + r.x.w, rd.l);
|
||||||
}
|
}
|
||||||
|
@ -113,10 +113,10 @@ L writeDB(aa.w + r.x.w, rd.l);
|
||||||
auto R65816::op_adjust_addrx_w(fp op) {
|
auto R65816::op_adjust_addrx_w(fp op) {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io();
|
idle();
|
||||||
rd.l = readDB(aa.w + r.x.w + 0);
|
rd.l = readDB(aa.w + r.x.w + 0);
|
||||||
rd.h = readDB(aa.w + r.x.w + 1);
|
rd.h = readDB(aa.w + r.x.w + 1);
|
||||||
io();
|
idle();
|
||||||
call(op);
|
call(op);
|
||||||
writeDB(aa.w + r.x.w + 1, rd.h);
|
writeDB(aa.w + r.x.w + 1, rd.h);
|
||||||
L writeDB(aa.w + r.x.w + 0, rd.l);
|
L writeDB(aa.w + r.x.w + 0, rd.l);
|
||||||
|
@ -124,19 +124,19 @@ L writeDB(aa.w + r.x.w + 0, rd.l);
|
||||||
|
|
||||||
auto R65816::op_adjust_dp_b(fp op) {
|
auto R65816::op_adjust_dp_b(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
rd.l = readDP(dp);
|
rd.l = readDP(dp);
|
||||||
io();
|
idle();
|
||||||
call(op);
|
call(op);
|
||||||
L writeDP(dp, rd.l);
|
L writeDP(dp, rd.l);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_adjust_dp_w(fp op) {
|
auto R65816::op_adjust_dp_w(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
rd.l = readDP(dp + 0);
|
rd.l = readDP(dp + 0);
|
||||||
rd.h = readDP(dp + 1);
|
rd.h = readDP(dp + 1);
|
||||||
io();
|
idle();
|
||||||
call(op);
|
call(op);
|
||||||
writeDP(dp + 1, rd.h);
|
writeDP(dp + 1, rd.h);
|
||||||
L writeDP(dp + 0, rd.l);
|
L writeDP(dp + 0, rd.l);
|
||||||
|
@ -144,21 +144,21 @@ L writeDP(dp + 0, rd.l);
|
||||||
|
|
||||||
auto R65816::op_adjust_dpx_b(fp op) {
|
auto R65816::op_adjust_dpx_b(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
io();
|
idle();
|
||||||
rd.l = readDP(dp + r.x.w);
|
rd.l = readDP(dp + r.x.w);
|
||||||
io();
|
idle();
|
||||||
call(op);
|
call(op);
|
||||||
L writeDP(dp + r.x.w, rd.l);
|
L writeDP(dp + r.x.w, rd.l);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_adjust_dpx_w(fp op) {
|
auto R65816::op_adjust_dpx_w(fp op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
io();
|
idle();
|
||||||
rd.l = readDP(dp + r.x.w + 0);
|
rd.l = readDP(dp + r.x.w + 0);
|
||||||
rd.h = readDP(dp + r.x.w + 1);
|
rd.h = readDP(dp + r.x.w + 1);
|
||||||
io();
|
idle();
|
||||||
call(op);
|
call(op);
|
||||||
writeDP(dp + r.x.w + 1, rd.h);
|
writeDP(dp + r.x.w + 1, rd.h);
|
||||||
L writeDP(dp + r.x.w + 0, rd.l);
|
L writeDP(dp + r.x.w + 0, rd.l);
|
||||||
|
|
|
@ -14,14 +14,14 @@ L writeDB(aa.w + 1, reg >> 8);
|
||||||
auto R65816::op_write_addrr_b(Reg16& reg, Reg16& idx) {
|
auto R65816::op_write_addrr_b(Reg16& reg, Reg16& idx) {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io();
|
idle();
|
||||||
L writeDB(aa.w + idx, reg);
|
L writeDB(aa.w + idx, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_write_addrr_w(Reg16& reg, Reg16& idx) {
|
auto R65816::op_write_addrr_w(Reg16& reg, Reg16& idx) {
|
||||||
aa.l = readPC();
|
aa.l = readPC();
|
||||||
aa.h = readPC();
|
aa.h = readPC();
|
||||||
io();
|
idle();
|
||||||
writeDB(aa.w + idx + 0, reg >> 0);
|
writeDB(aa.w + idx + 0, reg >> 0);
|
||||||
L writeDB(aa.w + idx + 1, reg >> 8);
|
L writeDB(aa.w + idx + 1, reg >> 8);
|
||||||
}
|
}
|
||||||
|
@ -43,35 +43,35 @@ L writeLong(aa.d + idx + 1, r.a.h);
|
||||||
|
|
||||||
auto R65816::op_write_dp_b(Reg16& reg) {
|
auto R65816::op_write_dp_b(Reg16& reg) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
L writeDP(dp, reg);
|
L writeDP(dp, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_write_dp_w(Reg16& reg) {
|
auto R65816::op_write_dp_w(Reg16& reg) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
writeDP(dp + 0, reg >> 0);
|
writeDP(dp + 0, reg >> 0);
|
||||||
L writeDP(dp + 1, reg >> 8);
|
L writeDP(dp + 1, reg >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_write_dpr_b(Reg16& reg, Reg16& idx) {
|
auto R65816::op_write_dpr_b(Reg16& reg, Reg16& idx) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
io();
|
idle();
|
||||||
L writeDP(dp + idx, reg);
|
L writeDP(dp + idx, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_write_dpr_w(Reg16& reg, Reg16& idx) {
|
auto R65816::op_write_dpr_w(Reg16& reg, Reg16& idx) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
io();
|
idle();
|
||||||
writeDP(dp + idx + 0, reg >> 0);
|
writeDP(dp + idx + 0, reg >> 0);
|
||||||
L writeDP(dp + idx + 1, reg >> 8);
|
L writeDP(dp + idx + 1, reg >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_sta_idp_b() {
|
auto R65816::op_sta_idp_b() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDP(dp + 0);
|
aa.l = readDP(dp + 0);
|
||||||
aa.h = readDP(dp + 1);
|
aa.h = readDP(dp + 1);
|
||||||
L writeDB(aa.w, r.a.l);
|
L writeDB(aa.w, r.a.l);
|
||||||
|
@ -79,7 +79,7 @@ L writeDB(aa.w, r.a.l);
|
||||||
|
|
||||||
auto R65816::op_sta_idp_w() {
|
auto R65816::op_sta_idp_w() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDP(dp + 0);
|
aa.l = readDP(dp + 0);
|
||||||
aa.h = readDP(dp + 1);
|
aa.h = readDP(dp + 1);
|
||||||
writeDB(aa.w + 0, r.a.l);
|
writeDB(aa.w + 0, r.a.l);
|
||||||
|
@ -88,7 +88,7 @@ L writeDB(aa.w + 1, r.a.h);
|
||||||
|
|
||||||
auto R65816::op_sta_ildp_b() {
|
auto R65816::op_sta_ildp_b() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDPn(dp + 0);
|
aa.l = readDPn(dp + 0);
|
||||||
aa.h = readDPn(dp + 1);
|
aa.h = readDPn(dp + 1);
|
||||||
aa.b = readDPn(dp + 2);
|
aa.b = readDPn(dp + 2);
|
||||||
|
@ -97,7 +97,7 @@ L writeLong(aa.d, r.a.l);
|
||||||
|
|
||||||
auto R65816::op_sta_ildp_w() {
|
auto R65816::op_sta_ildp_w() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDPn(dp + 0);
|
aa.l = readDPn(dp + 0);
|
||||||
aa.h = readDPn(dp + 1);
|
aa.h = readDPn(dp + 1);
|
||||||
aa.b = readDPn(dp + 2);
|
aa.b = readDPn(dp + 2);
|
||||||
|
@ -107,8 +107,8 @@ L writeLong(aa.d + 1, r.a.h);
|
||||||
|
|
||||||
auto R65816::op_sta_idpx_b() {
|
auto R65816::op_sta_idpx_b() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
io();
|
idle();
|
||||||
aa.l = readDP(dp + r.x.w + 0);
|
aa.l = readDP(dp + r.x.w + 0);
|
||||||
aa.h = readDP(dp + r.x.w + 1);
|
aa.h = readDP(dp + r.x.w + 1);
|
||||||
L writeDB(aa.w, r.a.l);
|
L writeDB(aa.w, r.a.l);
|
||||||
|
@ -116,8 +116,8 @@ L writeDB(aa.w, r.a.l);
|
||||||
|
|
||||||
auto R65816::op_sta_idpx_w() {
|
auto R65816::op_sta_idpx_w() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
io();
|
idle();
|
||||||
aa.l = readDP(dp + r.x.w + 0);
|
aa.l = readDP(dp + r.x.w + 0);
|
||||||
aa.h = readDP(dp + r.x.w + 1);
|
aa.h = readDP(dp + r.x.w + 1);
|
||||||
writeDB(aa.w + 0, r.a.l);
|
writeDB(aa.w + 0, r.a.l);
|
||||||
|
@ -126,26 +126,26 @@ L writeDB(aa.w + 1, r.a.h);
|
||||||
|
|
||||||
auto R65816::op_sta_idpy_b() {
|
auto R65816::op_sta_idpy_b() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDP(dp + 0);
|
aa.l = readDP(dp + 0);
|
||||||
aa.h = readDP(dp + 1);
|
aa.h = readDP(dp + 1);
|
||||||
io();
|
idle();
|
||||||
L writeDB(aa.w + r.y.w, r.a.l);
|
L writeDB(aa.w + r.y.w, r.a.l);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_sta_idpy_w() {
|
auto R65816::op_sta_idpy_w() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDP(dp + 0);
|
aa.l = readDP(dp + 0);
|
||||||
aa.h = readDP(dp + 1);
|
aa.h = readDP(dp + 1);
|
||||||
io();
|
idle();
|
||||||
writeDB(aa.w + r.y.w + 0, r.a.l);
|
writeDB(aa.w + r.y.w + 0, r.a.l);
|
||||||
L writeDB(aa.w + r.y.w + 1, r.a.h);
|
L writeDB(aa.w + r.y.w + 1, r.a.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_sta_ildpy_b() {
|
auto R65816::op_sta_ildpy_b() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDPn(dp + 0);
|
aa.l = readDPn(dp + 0);
|
||||||
aa.h = readDPn(dp + 1);
|
aa.h = readDPn(dp + 1);
|
||||||
aa.b = readDPn(dp + 2);
|
aa.b = readDPn(dp + 2);
|
||||||
|
@ -154,7 +154,7 @@ L writeLong(aa.d + r.y.w, r.a.l);
|
||||||
|
|
||||||
auto R65816::op_sta_ildpy_w() {
|
auto R65816::op_sta_ildpy_w() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io2();
|
idle2();
|
||||||
aa.l = readDPn(dp + 0);
|
aa.l = readDPn(dp + 0);
|
||||||
aa.h = readDPn(dp + 1);
|
aa.h = readDPn(dp + 1);
|
||||||
aa.b = readDPn(dp + 2);
|
aa.b = readDPn(dp + 2);
|
||||||
|
@ -164,32 +164,32 @@ L writeLong(aa.d + r.y.w + 1, r.a.h);
|
||||||
|
|
||||||
auto R65816::op_sta_sr_b() {
|
auto R65816::op_sta_sr_b() {
|
||||||
sp = readPC();
|
sp = readPC();
|
||||||
io();
|
idle();
|
||||||
L writeSP(sp, r.a.l);
|
L writeSP(sp, r.a.l);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_sta_sr_w() {
|
auto R65816::op_sta_sr_w() {
|
||||||
sp = readPC();
|
sp = readPC();
|
||||||
io();
|
idle();
|
||||||
writeSP(sp + 0, r.a.l);
|
writeSP(sp + 0, r.a.l);
|
||||||
L writeSP(sp + 1, r.a.h);
|
L writeSP(sp + 1, r.a.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_sta_isry_b() {
|
auto R65816::op_sta_isry_b() {
|
||||||
sp = readPC();
|
sp = readPC();
|
||||||
io();
|
idle();
|
||||||
aa.l = readSP(sp + 0);
|
aa.l = readSP(sp + 0);
|
||||||
aa.h = readSP(sp + 1);
|
aa.h = readSP(sp + 1);
|
||||||
io();
|
idle();
|
||||||
L writeDB(aa.w + r.y.w, r.a.l);
|
L writeDB(aa.w + r.y.w, r.a.l);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::op_sta_isry_w() {
|
auto R65816::op_sta_isry_w() {
|
||||||
sp = readPC();
|
sp = readPC();
|
||||||
io();
|
idle();
|
||||||
aa.l = readSP(sp + 0);
|
aa.l = readSP(sp + 0);
|
||||||
aa.h = readSP(sp + 1);
|
aa.h = readSP(sp + 1);
|
||||||
io();
|
idle();
|
||||||
writeDB(aa.w + r.y.w + 0, r.a.l);
|
writeDB(aa.w + r.y.w + 0, r.a.l);
|
||||||
L writeDB(aa.w + r.y.w + 1, r.a.h);
|
L writeDB(aa.w + r.y.w + 1, r.a.h);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Processor {
|
||||||
#include "instructions-misc.cpp"
|
#include "instructions-misc.cpp"
|
||||||
#include "switch.cpp"
|
#include "switch.cpp"
|
||||||
|
|
||||||
//immediate, 2-cycle opcodes with I/O cycle will become bus read
|
//immediate, 2-cycle opcodes with idle cycle will become bus read
|
||||||
//when an IRQ is to be triggered immediately after opcode completion.
|
//when an IRQ is to be triggered immediately after opcode completion.
|
||||||
//this affects the following opcodes:
|
//this affects the following opcodes:
|
||||||
// clc, cld, cli, clv, sec, sed, sei,
|
// clc, cld, cli, clv, sec, sed, sei,
|
||||||
|
@ -27,36 +27,36 @@ namespace Processor {
|
||||||
// tcd, tcs, tdc, tsc, tsx, txs,
|
// tcd, tcs, tdc, tsc, tsx, txs,
|
||||||
// inc, inx, iny, dec, dex, dey,
|
// inc, inx, iny, dec, dex, dey,
|
||||||
// asl, lsr, rol, ror, nop, xce.
|
// asl, lsr, rol, ror, nop, xce.
|
||||||
auto R65816::ioIRQ() -> void {
|
auto R65816::idleIRQ() -> void {
|
||||||
if(interruptPending()) {
|
if(interruptPending()) {
|
||||||
//modify I/O cycle to bus read cycle, do not increment PC
|
//modify I/O cycle to bus read cycle, do not increment PC
|
||||||
read(r.pc.d);
|
read(r.pc.d);
|
||||||
} else {
|
} else {
|
||||||
io();
|
idle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::io2() -> void {
|
auto R65816::idle2() -> void {
|
||||||
if(r.d.l != 0x00) {
|
if(r.d.l != 0x00) {
|
||||||
io();
|
idle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::io4(uint16 x, uint16 y) -> void {
|
auto R65816::idle4(uint16 x, uint16 y) -> void {
|
||||||
if(!r.p.x || (x & 0xff00) != (y & 0xff00)) {
|
if(!r.p.x || (x & 0xff00) != (y & 0xff00)) {
|
||||||
io();
|
idle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::io6(uint16 addr) -> void {
|
auto R65816::idle6(uint16 addr) -> void {
|
||||||
if(r.e && (r.pc.w & 0xff00) != (addr & 0xff00)) {
|
if(r.e && (r.pc.w & 0xff00) != (addr & 0xff00)) {
|
||||||
io();
|
idle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto R65816::interrupt() -> void {
|
auto R65816::interrupt() -> void {
|
||||||
read(r.pc.d);
|
read(r.pc.d);
|
||||||
io();
|
idle();
|
||||||
N writeSP(r.pc.b);
|
N writeSP(r.pc.b);
|
||||||
writeSP(r.pc.h);
|
writeSP(r.pc.h);
|
||||||
writeSP(r.pc.l);
|
writeSP(r.pc.l);
|
||||||
|
|
|
@ -13,20 +13,20 @@ struct R65816 {
|
||||||
|
|
||||||
using fp = auto (R65816::*)() -> void;
|
using fp = auto (R65816::*)() -> void;
|
||||||
|
|
||||||
virtual auto io() -> void = 0;
|
virtual auto idle() -> void = 0;
|
||||||
virtual auto read(uint24 addr) -> uint8 = 0;
|
virtual auto read(uint24 addr) -> uint8 = 0;
|
||||||
virtual auto write(uint24 addr, uint8 data) -> void = 0;
|
virtual auto write(uint24 addr, uint8 data) -> void = 0;
|
||||||
virtual auto lastCycle() -> void = 0;
|
virtual auto lastCycle() -> void = 0;
|
||||||
virtual auto interruptPending() const -> bool = 0;
|
virtual auto interruptPending() const -> bool = 0;
|
||||||
virtual auto interrupt() -> void;
|
|
||||||
|
|
||||||
virtual auto readDisassembler(uint24 addr) -> uint8 { return 0; }
|
virtual auto readDisassembler(uint24 addr) -> uint8 { return 0; }
|
||||||
|
|
||||||
//r65816.cpp
|
//r65816.cpp
|
||||||
alwaysinline auto ioIRQ() -> void;
|
alwaysinline auto idleIRQ() -> void;
|
||||||
alwaysinline auto io2() -> void;
|
alwaysinline auto idle2() -> void;
|
||||||
alwaysinline auto io4(uint16 x, uint16 y) -> void;
|
alwaysinline auto idle4(uint16 x, uint16 y) -> void;
|
||||||
alwaysinline auto io6(uint16 addr) -> void;
|
alwaysinline auto idle6(uint16 addr) -> void;
|
||||||
|
auto interrupt() -> void;
|
||||||
|
|
||||||
//algorithms.cpp
|
//algorithms.cpp
|
||||||
auto op_adc_b();
|
auto op_adc_b();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#define call (this->*op)
|
#define call (this->*op)
|
||||||
|
|
||||||
auto SPC700::op_adjust(fps op, reg r) {
|
auto SPC700::op_adjust(fps op, reg r) {
|
||||||
io();
|
idle();
|
||||||
r = call(r);
|
r = call(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ auto SPC700::op_adjust_dpw(int n) {
|
||||||
|
|
||||||
auto SPC700::op_adjust_dpx(fps op) {
|
auto SPC700::op_adjust_dpx(fps op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io();
|
idle();
|
||||||
rd = readDP(dp + regs.x);
|
rd = readDP(dp + regs.x);
|
||||||
rd = call(rd);
|
rd = call(rd);
|
||||||
writeDP(dp + regs.x, rd);
|
writeDP(dp + regs.x, rd);
|
||||||
|
@ -41,8 +41,8 @@ auto SPC700::op_adjust_dpx(fps op) {
|
||||||
auto SPC700::op_branch(bool condition) {
|
auto SPC700::op_branch(bool condition) {
|
||||||
rd = readPC();
|
rd = readPC();
|
||||||
if(!condition) return;
|
if(!condition) return;
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
regs.pc += (int8)rd;
|
regs.pc += (int8)rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,22 +50,22 @@ auto SPC700::op_branch_bit() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
sp = readDP(dp);
|
sp = readDP(dp);
|
||||||
rd = readPC();
|
rd = readPC();
|
||||||
io();
|
idle();
|
||||||
if((bool)(sp & (1 << (opcode >> 5))) == (bool)(opcode & 0x10)) return;
|
if((bool)(sp & (1 << (opcode >> 5))) == (bool)(opcode & 0x10)) return;
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
regs.pc += (int8)rd;
|
regs.pc += (int8)rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_pull(reg r) {
|
auto SPC700::op_pull(reg r) {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
r = readSP();
|
r = readSP();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_push(uint8 r) {
|
auto SPC700::op_push(uint8 r) {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
writeSP(r);
|
writeSP(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ auto SPC700::op_read_addr(fpb op, reg r) {
|
||||||
auto SPC700::op_read_addri(fpb op, reg r) {
|
auto SPC700::op_read_addri(fpb op, reg r) {
|
||||||
dp.l = readPC();
|
dp.l = readPC();
|
||||||
dp.h = readPC();
|
dp.h = readPC();
|
||||||
io();
|
idle();
|
||||||
rd = read(dp + r);
|
rd = read(dp + r);
|
||||||
regs.a = call(regs.a, rd);
|
regs.a = call(regs.a, rd);
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ auto SPC700::op_read_dp(fpb op, reg r) {
|
||||||
|
|
||||||
auto SPC700::op_read_dpi(fpb op, reg r, reg i) {
|
auto SPC700::op_read_dpi(fpb op, reg r, reg i) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io();
|
idle();
|
||||||
rd = readDP(dp + i);
|
rd = readDP(dp + i);
|
||||||
r = call(r, rd);
|
r = call(r, rd);
|
||||||
}
|
}
|
||||||
|
@ -105,14 +105,14 @@ auto SPC700::op_read_dpi(fpb op, reg r, reg i) {
|
||||||
auto SPC700::op_read_dpw(fpw op) {
|
auto SPC700::op_read_dpw(fpw op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
rd.l = readDP(dp++);
|
rd.l = readDP(dp++);
|
||||||
if(op != &SPC700::op_cpw) io();
|
if(op != &SPC700::op_cpw) idle();
|
||||||
rd.h = readDP(dp++);
|
rd.h = readDP(dp++);
|
||||||
regs.ya = call(regs.ya, rd);
|
regs.ya = call(regs.ya, rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_read_idpx(fpb op) {
|
auto SPC700::op_read_idpx(fpb op) {
|
||||||
dp = readPC() + regs.x;
|
dp = readPC() + regs.x;
|
||||||
io();
|
idle();
|
||||||
sp.l = readDP(dp++);
|
sp.l = readDP(dp++);
|
||||||
sp.h = readDP(dp++);
|
sp.h = readDP(dp++);
|
||||||
rd = read(sp);
|
rd = read(sp);
|
||||||
|
@ -121,7 +121,7 @@ auto SPC700::op_read_idpx(fpb op) {
|
||||||
|
|
||||||
auto SPC700::op_read_idpy(fpb op) {
|
auto SPC700::op_read_idpy(fpb op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io();
|
idle();
|
||||||
sp.l = readDP(dp++);
|
sp.l = readDP(dp++);
|
||||||
sp.h = readDP(dp++);
|
sp.h = readDP(dp++);
|
||||||
rd = read(sp + regs.y);
|
rd = read(sp + regs.y);
|
||||||
|
@ -129,7 +129,7 @@ auto SPC700::op_read_idpy(fpb op) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_read_ix(fpb op) {
|
auto SPC700::op_read_ix(fpb op) {
|
||||||
io();
|
idle();
|
||||||
rd = readDP(regs.x);
|
rd = readDP(regs.x);
|
||||||
regs.a = call(regs.a, rd);
|
regs.a = call(regs.a, rd);
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ auto SPC700::op_set_addr_bit() {
|
||||||
switch(opcode >> 5) {
|
switch(opcode >> 5) {
|
||||||
case 0: //orc addr:bit
|
case 0: //orc addr:bit
|
||||||
case 1: //orc !addr:bit
|
case 1: //orc !addr:bit
|
||||||
io();
|
idle();
|
||||||
regs.p.c |= (rd & (1 << bit)) ^ (bool)(opcode & 0x20);
|
regs.p.c |= (rd & (1 << bit)) ^ (bool)(opcode & 0x20);
|
||||||
break;
|
break;
|
||||||
case 2: //and addr:bit
|
case 2: //and addr:bit
|
||||||
|
@ -151,14 +151,14 @@ auto SPC700::op_set_addr_bit() {
|
||||||
regs.p.c &= (rd & (1 << bit)) ^ (bool)(opcode & 0x20);
|
regs.p.c &= (rd & (1 << bit)) ^ (bool)(opcode & 0x20);
|
||||||
break;
|
break;
|
||||||
case 4: //eor addr:bit
|
case 4: //eor addr:bit
|
||||||
io();
|
idle();
|
||||||
regs.p.c ^= (bool)(rd & (1 << bit));
|
regs.p.c ^= (bool)(rd & (1 << bit));
|
||||||
break;
|
break;
|
||||||
case 5: //ldc addr:bit
|
case 5: //ldc addr:bit
|
||||||
regs.p.c = (rd & (1 << bit));
|
regs.p.c = (rd & (1 << bit));
|
||||||
break;
|
break;
|
||||||
case 6: //stc addr:bit
|
case 6: //stc addr:bit
|
||||||
io();
|
idle();
|
||||||
rd = (rd & ~(1 << bit)) | (regs.p.c << bit);
|
rd = (rd & ~(1 << bit)) | (regs.p.c << bit);
|
||||||
write(dp, rd);
|
write(dp, rd);
|
||||||
break;
|
break;
|
||||||
|
@ -176,8 +176,8 @@ auto SPC700::op_set_bit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_set_flag(uint bit, bool value) {
|
auto SPC700::op_set_flag(uint bit, bool value) {
|
||||||
io();
|
idle();
|
||||||
if(bit == regs.p.i.bit) io();
|
if(bit == regs.p.i.bit) idle();
|
||||||
regs.p = value ? (regs.p | (1 << bit)) : (regs.p & ~(1 << bit));
|
regs.p = value ? (regs.p | (1 << bit)) : (regs.p & ~(1 << bit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ auto SPC700::op_test_addr(bool set) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_transfer(reg from, reg to) {
|
auto SPC700::op_transfer(reg from, reg to) {
|
||||||
io();
|
idle();
|
||||||
to = from;
|
to = from;
|
||||||
if(&to == ®s.s) return;
|
if(&to == ®s.s) return;
|
||||||
regs.p.n = (to & 0x80);
|
regs.p.n = (to & 0x80);
|
||||||
|
@ -209,7 +209,7 @@ auto SPC700::op_write_addr(reg r) {
|
||||||
auto SPC700::op_write_addri(reg i) {
|
auto SPC700::op_write_addri(reg i) {
|
||||||
dp.l = readPC();
|
dp.l = readPC();
|
||||||
dp.h = readPC();
|
dp.h = readPC();
|
||||||
io();
|
idle();
|
||||||
dp += i;
|
dp += i;
|
||||||
read(dp);
|
read(dp);
|
||||||
write(dp, regs.a);
|
write(dp, regs.a);
|
||||||
|
@ -223,7 +223,7 @@ auto SPC700::op_write_dp(reg r) {
|
||||||
|
|
||||||
auto SPC700::op_write_dpi(reg r, reg i) {
|
auto SPC700::op_write_dpi(reg r, reg i) {
|
||||||
dp = readPC() + i;
|
dp = readPC() + i;
|
||||||
io();
|
idle();
|
||||||
readDP(dp);
|
readDP(dp);
|
||||||
writeDP(dp, r);
|
writeDP(dp, r);
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ auto SPC700::op_write_dp_const(fpb op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
wr = readDP(dp);
|
wr = readDP(dp);
|
||||||
wr = call(wr, rd);
|
wr = call(wr, rd);
|
||||||
op != &SPC700::op_cmp ? writeDP(dp, wr) : io();
|
op != &SPC700::op_cmp ? writeDP(dp, wr) : idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_write_dp_dp(fpb op) {
|
auto SPC700::op_write_dp_dp(fpb op) {
|
||||||
|
@ -242,15 +242,15 @@ auto SPC700::op_write_dp_dp(fpb op) {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
if(op != &SPC700::op_st) wr = readDP(dp);
|
if(op != &SPC700::op_st) wr = readDP(dp);
|
||||||
wr = call(wr, rd);
|
wr = call(wr, rd);
|
||||||
op != &SPC700::op_cmp ? writeDP(dp, wr) : io();
|
op != &SPC700::op_cmp ? writeDP(dp, wr) : idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_write_ix_iy(fpb op) {
|
auto SPC700::op_write_ix_iy(fpb op) {
|
||||||
io();
|
idle();
|
||||||
rd = readDP(regs.y);
|
rd = readDP(regs.y);
|
||||||
wr = readDP(regs.x);
|
wr = readDP(regs.x);
|
||||||
wr = call(wr, rd);
|
wr = call(wr, rd);
|
||||||
op != &SPC700::op_cmp ? writeDP(regs.x, wr) : io();
|
op != &SPC700::op_cmp ? writeDP(regs.x, wr) : idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -259,10 +259,10 @@ auto SPC700::op_bne_dp() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
sp = readDP(dp);
|
sp = readDP(dp);
|
||||||
rd = readPC();
|
rd = readPC();
|
||||||
io();
|
idle();
|
||||||
if(regs.a == sp) return;
|
if(regs.a == sp) return;
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
regs.pc += (int8)rd;
|
regs.pc += (int8)rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,38 +272,38 @@ auto SPC700::op_bne_dpdec() {
|
||||||
writeDP(dp, --wr);
|
writeDP(dp, --wr);
|
||||||
rd = readPC();
|
rd = readPC();
|
||||||
if(wr == 0) return;
|
if(wr == 0) return;
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
regs.pc += (int8)rd;
|
regs.pc += (int8)rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_bne_dpx() {
|
auto SPC700::op_bne_dpx() {
|
||||||
dp = readPC();
|
dp = readPC();
|
||||||
io();
|
idle();
|
||||||
sp = readDP(dp + regs.x);
|
sp = readDP(dp + regs.x);
|
||||||
rd = readPC();
|
rd = readPC();
|
||||||
io();
|
idle();
|
||||||
if(regs.a == sp) return;
|
if(regs.a == sp) return;
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
regs.pc += (int8)rd;
|
regs.pc += (int8)rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_bne_ydec() {
|
auto SPC700::op_bne_ydec() {
|
||||||
rd = readPC();
|
rd = readPC();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
if(--regs.y == 0) return;
|
if(--regs.y == 0) return;
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
regs.pc += (int8)rd;
|
regs.pc += (int8)rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_brk() {
|
auto SPC700::op_brk() {
|
||||||
rd.l = read(0xffde);
|
rd.l = read(0xffde);
|
||||||
rd.h = read(0xffdf);
|
rd.h = read(0xffdf);
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
writeSP(regs.pc.h);
|
writeSP(regs.pc.h);
|
||||||
writeSP(regs.pc.l);
|
writeSP(regs.pc.l);
|
||||||
writeSP(regs.p);
|
writeSP(regs.p);
|
||||||
|
@ -313,20 +313,20 @@ auto SPC700::op_brk() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_clv() {
|
auto SPC700::op_clv() {
|
||||||
io();
|
idle();
|
||||||
regs.p.v = 0;
|
regs.p.v = 0;
|
||||||
regs.p.h = 0;
|
regs.p.h = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_cmc() {
|
auto SPC700::op_cmc() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
regs.p.c = !regs.p.c;
|
regs.p.c = !regs.p.c;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_daa() {
|
auto SPC700::op_daa() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
if(regs.p.c || (regs.a) > 0x99) {
|
if(regs.p.c || (regs.a) > 0x99) {
|
||||||
regs.a += 0x60;
|
regs.a += 0x60;
|
||||||
regs.p.c = 1;
|
regs.p.c = 1;
|
||||||
|
@ -339,8 +339,8 @@ auto SPC700::op_daa() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_das() {
|
auto SPC700::op_das() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
if(!regs.p.c || (regs.a) > 0x99) {
|
if(!regs.p.c || (regs.a) > 0x99) {
|
||||||
regs.a -= 0x60;
|
regs.a -= 0x60;
|
||||||
regs.p.c = 0;
|
regs.p.c = 0;
|
||||||
|
@ -353,17 +353,17 @@ auto SPC700::op_das() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_div_ya_x() {
|
auto SPC700::op_div_ya_x() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
ya = regs.ya;
|
ya = regs.ya;
|
||||||
//overflow set if quotient >= 256
|
//overflow set if quotient >= 256
|
||||||
regs.p.v = (regs.y >= regs.x);
|
regs.p.v = (regs.y >= regs.x);
|
||||||
|
@ -392,7 +392,7 @@ auto SPC700::op_jmp_addr() {
|
||||||
auto SPC700::op_jmp_iaddrx() {
|
auto SPC700::op_jmp_iaddrx() {
|
||||||
dp.l = readPC();
|
dp.l = readPC();
|
||||||
dp.h = readPC();
|
dp.h = readPC();
|
||||||
io();
|
idle();
|
||||||
dp += regs.x;
|
dp += regs.x;
|
||||||
rd.l = read(dp++);
|
rd.l = read(dp++);
|
||||||
rd.h = read(dp++);
|
rd.h = read(dp++);
|
||||||
|
@ -401,8 +401,8 @@ auto SPC700::op_jmp_iaddrx() {
|
||||||
|
|
||||||
auto SPC700::op_jsp_dp() {
|
auto SPC700::op_jsp_dp() {
|
||||||
rd = readPC();
|
rd = readPC();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
writeSP(regs.pc.h);
|
writeSP(regs.pc.h);
|
||||||
writeSP(regs.pc.l);
|
writeSP(regs.pc.l);
|
||||||
regs.pc = 0xff00 | rd;
|
regs.pc = 0xff00 | rd;
|
||||||
|
@ -411,9 +411,9 @@ auto SPC700::op_jsp_dp() {
|
||||||
auto SPC700::op_jsr_addr() {
|
auto SPC700::op_jsr_addr() {
|
||||||
rd.l = readPC();
|
rd.l = readPC();
|
||||||
rd.h = readPC();
|
rd.h = readPC();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
writeSP(regs.pc.h);
|
writeSP(regs.pc.h);
|
||||||
writeSP(regs.pc.l);
|
writeSP(regs.pc.l);
|
||||||
regs.pc = rd;
|
regs.pc = rd;
|
||||||
|
@ -423,31 +423,31 @@ auto SPC700::op_jst() {
|
||||||
dp = 0xffde - ((opcode >> 4) << 1);
|
dp = 0xffde - ((opcode >> 4) << 1);
|
||||||
rd.l = read(dp++);
|
rd.l = read(dp++);
|
||||||
rd.h = read(dp++);
|
rd.h = read(dp++);
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
writeSP(regs.pc.h);
|
writeSP(regs.pc.h);
|
||||||
writeSP(regs.pc.l);
|
writeSP(regs.pc.l);
|
||||||
regs.pc = rd;
|
regs.pc = rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_lda_ixinc() {
|
auto SPC700::op_lda_ixinc() {
|
||||||
io();
|
idle();
|
||||||
regs.a = readDP(regs.x++);
|
regs.a = readDP(regs.x++);
|
||||||
io();
|
idle();
|
||||||
regs.p.n = regs.a & 0x80;
|
regs.p.n = regs.a & 0x80;
|
||||||
regs.p.z = regs.a == 0;
|
regs.p.z = regs.a == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_mul_ya() {
|
auto SPC700::op_mul_ya() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
ya = regs.y * regs.a;
|
ya = regs.y * regs.a;
|
||||||
regs.a = ya;
|
regs.a = ya;
|
||||||
regs.y = ya >> 8;
|
regs.y = ya >> 8;
|
||||||
|
@ -457,12 +457,12 @@ auto SPC700::op_mul_ya() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_nop() {
|
auto SPC700::op_nop() {
|
||||||
io();
|
idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_plp() {
|
auto SPC700::op_plp() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
regs.p = readSP();
|
regs.p = readSP();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,22 +470,22 @@ auto SPC700::op_rti() {
|
||||||
regs.p = readSP();
|
regs.p = readSP();
|
||||||
rd.l = readSP();
|
rd.l = readSP();
|
||||||
rd.h = readSP();
|
rd.h = readSP();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
regs.pc = rd;
|
regs.pc = rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_rts() {
|
auto SPC700::op_rts() {
|
||||||
rd.l = readSP();
|
rd.l = readSP();
|
||||||
rd.h = readSP();
|
rd.h = readSP();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
regs.pc = rd;
|
regs.pc = rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_sta_idpx() {
|
auto SPC700::op_sta_idpx() {
|
||||||
sp = readPC() + regs.x;
|
sp = readPC() + regs.x;
|
||||||
io();
|
idle();
|
||||||
dp.l = readDP(sp++);
|
dp.l = readDP(sp++);
|
||||||
dp.h = readDP(sp++);
|
dp.h = readDP(sp++);
|
||||||
read(dp);
|
read(dp);
|
||||||
|
@ -496,21 +496,21 @@ auto SPC700::op_sta_idpy() {
|
||||||
sp = readPC();
|
sp = readPC();
|
||||||
dp.l = readDP(sp++);
|
dp.l = readDP(sp++);
|
||||||
dp.h = readDP(sp++);
|
dp.h = readDP(sp++);
|
||||||
io();
|
idle();
|
||||||
dp += regs.y;
|
dp += regs.y;
|
||||||
read(dp);
|
read(dp);
|
||||||
write(dp, regs.a);
|
write(dp, regs.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_sta_ix() {
|
auto SPC700::op_sta_ix() {
|
||||||
io();
|
idle();
|
||||||
readDP(regs.x);
|
readDP(regs.x);
|
||||||
writeDP(regs.x, regs.a);
|
writeDP(regs.x, regs.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_sta_ixinc() {
|
auto SPC700::op_sta_ixinc() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
writeDP(regs.x++, regs.a);
|
writeDP(regs.x++, regs.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,16 +523,16 @@ auto SPC700::op_stw_dp() {
|
||||||
|
|
||||||
auto SPC700::op_wait() {
|
auto SPC700::op_wait() {
|
||||||
while(true) {
|
while(true) {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC700::op_xcn() {
|
auto SPC700::op_xcn() {
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
io();
|
idle();
|
||||||
regs.a = (regs.a >> 4) | (regs.a << 4);
|
regs.a = (regs.a >> 4) | (regs.a << 4);
|
||||||
regs.p.n = regs.a & 0x80;
|
regs.p.n = regs.a & 0x80;
|
||||||
regs.p.z = regs.a == 0;
|
regs.p.z = regs.a == 0;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
struct SPC700 {
|
struct SPC700 {
|
||||||
virtual auto io() -> void = 0;
|
virtual auto idle() -> void = 0;
|
||||||
virtual auto read(uint16 addr) -> uint8 = 0;
|
virtual auto read(uint16 addr) -> uint8 = 0;
|
||||||
virtual auto write(uint16 addr, uint8 data) -> void = 0;
|
virtual auto write(uint16 addr, uint8 data) -> void = 0;
|
||||||
virtual auto readDisassembler(uint16 addr) -> uint8 = 0;
|
virtual auto readDisassembler(uint16 addr) -> uint8 = 0;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using format = string_format;
|
||||||
|
|
||||||
//todo: this is horribly broken in many cases; needs a total rewrite
|
//todo: this is horribly broken in many cases; needs a total rewrite
|
||||||
auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> string {
|
auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> string {
|
||||||
string s;
|
string s;
|
||||||
|
|
|
@ -108,7 +108,7 @@ auto SA1::vbrRead(uint24 addr, uint8 data) -> uint8 {
|
||||||
//tick() == 2 clock ticks
|
//tick() == 2 clock ticks
|
||||||
//note: bus conflict delays are not emulated at this time
|
//note: bus conflict delays are not emulated at this time
|
||||||
|
|
||||||
auto SA1::io() -> void {
|
auto SA1::idle() -> void {
|
||||||
tick();
|
tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,19 +30,6 @@ auto SA1::main() -> void {
|
||||||
instruction();
|
instruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::interrupt() -> void {
|
|
||||||
read(r.pc.d);
|
|
||||||
io();
|
|
||||||
if(!r.e) writeSP(r.pc.b);
|
|
||||||
writeSP(r.pc.h);
|
|
||||||
writeSP(r.pc.l);
|
|
||||||
writeSP(r.e ? (r.p & ~0x10) : r.p);
|
|
||||||
r.pc.w = r.vector;
|
|
||||||
r.pc.b = 0x00;
|
|
||||||
r.p.i = 1;
|
|
||||||
r.p.d = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SA1::lastCycle() -> void {
|
auto SA1::lastCycle() -> void {
|
||||||
if(mmio.sa1_nmi && !mmio.sa1_nmicl) {
|
if(mmio.sa1_nmi && !mmio.sa1_nmicl) {
|
||||||
status.interruptPending = true;
|
status.interruptPending = true;
|
||||||
|
|
|
@ -3,7 +3,6 @@ struct SA1 : Processor::R65816, Cothread {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
auto tick() -> void;
|
auto tick() -> void;
|
||||||
auto interrupt() -> void override;
|
|
||||||
|
|
||||||
alwaysinline auto triggerIRQ() -> void;
|
alwaysinline auto triggerIRQ() -> void;
|
||||||
alwaysinline auto lastCycle() -> void override;
|
alwaysinline auto lastCycle() -> void override;
|
||||||
|
@ -47,7 +46,7 @@ struct SA1 : Processor::R65816, Cothread {
|
||||||
auto busWrite(uint24 addr, uint8 data) -> void;
|
auto busWrite(uint24 addr, uint8 data) -> void;
|
||||||
auto vbrRead(uint24 addr, uint8 data = 0) -> uint8;
|
auto vbrRead(uint24 addr, uint8 data = 0) -> uint8;
|
||||||
|
|
||||||
alwaysinline auto io() -> void override;
|
alwaysinline auto idle() -> void override;
|
||||||
alwaysinline auto read(uint24 addr) -> uint8 override;
|
alwaysinline auto read(uint24 addr) -> uint8 override;
|
||||||
alwaysinline auto write(uint24 addr, uint8 data) -> void override;
|
alwaysinline auto write(uint24 addr, uint8 data) -> void override;
|
||||||
|
|
||||||
|
|
|
@ -12,25 +12,13 @@ CPU cpu;
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
|
|
||||||
auto CPU::interruptPending() const -> bool { return status.interruptPending; }
|
auto CPU::interruptPending() const -> bool { return status.interruptPending; }
|
||||||
auto CPU::pio() const -> uint8 { return status.pio; }
|
auto CPU::pio() const -> uint8 { return io.pio; }
|
||||||
auto CPU::joylatch() const -> bool { return status.joypadStrobeLatch; }
|
auto CPU::joylatch() const -> bool { return io.joypadStrobeLatch; }
|
||||||
|
|
||||||
CPU::CPU() {
|
CPU::CPU() {
|
||||||
PPUcounter::scanline = {&CPU::scanline, this};
|
PPUcounter::scanline = {&CPU::scanline, this};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::step(uint clocks) -> void {
|
|
||||||
smp.clock -= clocks * (uint64)smp.frequency;
|
|
||||||
ppu.clock -= clocks;
|
|
||||||
for(auto coprocessor : coprocessors) {
|
|
||||||
coprocessor->clock -= clocks * (uint64)coprocessor->frequency;
|
|
||||||
}
|
|
||||||
for(auto peripheral : peripherals) {
|
|
||||||
peripheral->clock -= clocks * (uint64)peripheral->frequency;
|
|
||||||
}
|
|
||||||
synchronizePeripherals();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPU::synchronizeSMP() -> void {
|
auto CPU::synchronizeSMP() -> void {
|
||||||
if(smp.clock < 0) co_switch(smp.thread);
|
if(smp.clock < 0) co_switch(smp.thread);
|
||||||
}
|
}
|
||||||
|
@ -68,12 +56,12 @@ auto CPU::main() -> void {
|
||||||
interrupt();
|
interrupt();
|
||||||
} else if(status.resetPending) {
|
} else if(status.resetPending) {
|
||||||
status.resetPending = false;
|
status.resetPending = false;
|
||||||
addClocks(132);
|
step(132);
|
||||||
r.vector = 0xfffc;
|
r.vector = 0xfffc;
|
||||||
interrupt();
|
interrupt();
|
||||||
} else if(status.powerPending) {
|
} else if(status.powerPending) {
|
||||||
status.powerPending = false;
|
status.powerPending = false;
|
||||||
addClocks(186);
|
step(186);
|
||||||
r.pc.l = bus.read(0xfffc, r.mdr);
|
r.pc.l = bus.read(0xfffc, r.mdr);
|
||||||
r.pc.h = bus.read(0xfffd, r.mdr);
|
r.pc.h = bus.read(0xfffd, r.mdr);
|
||||||
}
|
}
|
||||||
|
@ -161,49 +149,47 @@ auto CPU::reset() -> void {
|
||||||
r.vector = 0xfffc; //reset vector address
|
r.vector = 0xfffc; //reset vector address
|
||||||
|
|
||||||
//$2140-217f
|
//$2140-217f
|
||||||
for(auto& port : status.port) port = 0x00;
|
for(auto& port : io.port) port = 0x00;
|
||||||
|
|
||||||
//$2181-$2183
|
//$2181-$2183
|
||||||
status.wramAddress = 0x000000;
|
io.wramAddress = 0x000000;
|
||||||
|
|
||||||
//$4016-$4017
|
//$4016-$4017
|
||||||
status.joypadStrobeLatch = 0;
|
io.joypadStrobeLatch = 0;
|
||||||
status.joypad1_bits = ~0;
|
|
||||||
status.joypad2_bits = ~0;
|
|
||||||
|
|
||||||
//$4200
|
//$4200
|
||||||
status.nmiEnabled = false;
|
io.nmiEnabled = false;
|
||||||
status.hirqEnabled = false;
|
io.hirqEnabled = false;
|
||||||
status.virqEnabled = false;
|
io.virqEnabled = false;
|
||||||
status.autoJoypadPoll = false;
|
io.autoJoypadPoll = false;
|
||||||
|
|
||||||
//$4201
|
//$4201
|
||||||
status.pio = 0xff;
|
io.pio = 0xff;
|
||||||
|
|
||||||
//$4202-$4203
|
//$4202-$4203
|
||||||
status.wrmpya = 0xff;
|
io.wrmpya = 0xff;
|
||||||
status.wrmpyb = 0xff;
|
io.wrmpyb = 0xff;
|
||||||
|
|
||||||
//$4204-$4206
|
//$4204-$4206
|
||||||
status.wrdiva = 0xffff;
|
io.wrdiva = 0xffff;
|
||||||
status.wrdivb = 0xff;
|
io.wrdivb = 0xff;
|
||||||
|
|
||||||
//$4207-$420a
|
//$4207-$420a
|
||||||
status.hirqPos = 0x01ff;
|
io.hirqPos = 0x01ff;
|
||||||
status.virqPos = 0x01ff;
|
io.virqPos = 0x01ff;
|
||||||
|
|
||||||
//$420d
|
//$420d
|
||||||
status.romSpeed = 8;
|
io.romSpeed = 8;
|
||||||
|
|
||||||
//$4214-$4217
|
//$4214-$4217
|
||||||
status.rddiv = 0x0000;
|
io.rddiv = 0x0000;
|
||||||
status.rdmpy = 0x0000;
|
io.rdmpy = 0x0000;
|
||||||
|
|
||||||
//$4218-$421f
|
//$4218-$421f
|
||||||
status.joy1 = 0x0000;
|
io.joy1 = 0x0000;
|
||||||
status.joy2 = 0x0000;
|
io.joy2 = 0x0000;
|
||||||
status.joy3 = 0x0000;
|
io.joy3 = 0x0000;
|
||||||
status.joy4 = 0x0000;
|
io.joy4 = 0x0000;
|
||||||
|
|
||||||
//ALU
|
//ALU
|
||||||
alu.mpyctr = 0;
|
alu.mpyctr = 0;
|
||||||
|
|
|
@ -5,14 +5,13 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
|
||||||
|
|
||||||
CPU();
|
CPU();
|
||||||
|
|
||||||
alwaysinline auto step(uint clocks) -> void;
|
auto synchronizeSMP() -> void;
|
||||||
alwaysinline auto synchronizeSMP() -> void;
|
|
||||||
auto synchronizePPU() -> void;
|
auto synchronizePPU() -> void;
|
||||||
auto synchronizeCoprocessors() -> void;
|
auto synchronizeCoprocessors() -> void;
|
||||||
auto synchronizePeripherals() -> void;
|
auto synchronizePeripherals() -> void;
|
||||||
|
|
||||||
auto portRead(uint2 port) const -> uint8;
|
auto readPort(uint2 port) const -> uint8;
|
||||||
auto portWrite(uint2 port, uint8 data) -> void;
|
auto writePort(uint2 port, uint8 data) -> void;
|
||||||
|
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
|
@ -21,7 +20,7 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
//dma.cpp
|
//dma.cpp
|
||||||
auto dmaAddClocks(uint clocks) -> void;
|
auto dmaStep(uint clocks) -> void;
|
||||||
auto dmaTransferValid(uint8 bbus, uint24 abus) -> bool;
|
auto dmaTransferValid(uint8 bbus, uint24 abus) -> bool;
|
||||||
auto dmaAddressValid(uint24 abus) -> bool;
|
auto dmaAddressValid(uint24 abus) -> bool;
|
||||||
auto dmaRead(uint24 abus) -> uint8;
|
auto dmaRead(uint24 abus) -> uint8;
|
||||||
|
@ -46,7 +45,7 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
|
||||||
auto hdmaInit() -> void;
|
auto hdmaInit() -> void;
|
||||||
|
|
||||||
//memory.cpp
|
//memory.cpp
|
||||||
auto io() -> void override;
|
auto idle() -> void override;
|
||||||
auto read(uint24 addr) -> uint8 override;
|
auto read(uint24 addr) -> uint8 override;
|
||||||
auto write(uint24 addr, uint8 data) -> void override;
|
auto write(uint24 addr, uint8 data) -> void override;
|
||||||
alwaysinline auto speed(uint24 addr) const -> uint;
|
alwaysinline auto speed(uint24 addr) const -> uint;
|
||||||
|
@ -63,7 +62,7 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
|
||||||
//timing.cpp
|
//timing.cpp
|
||||||
auto dmaCounter() const -> uint;
|
auto dmaCounter() const -> uint;
|
||||||
|
|
||||||
auto addClocks(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
auto scanline() -> void;
|
auto scanline() -> void;
|
||||||
|
|
||||||
alwaysinline auto aluEdge() -> void;
|
alwaysinline auto aluEdge() -> void;
|
||||||
|
@ -138,8 +137,9 @@ privileged:
|
||||||
bool autoJoypadLatch;
|
bool autoJoypadLatch;
|
||||||
uint autoJoypadCounter;
|
uint autoJoypadCounter;
|
||||||
uint autoJoypadClock;
|
uint autoJoypadClock;
|
||||||
|
} status;
|
||||||
|
|
||||||
//MMIO
|
struct IO {
|
||||||
//$2140-217f
|
//$2140-217f
|
||||||
uint8 port[4];
|
uint8 port[4];
|
||||||
|
|
||||||
|
@ -148,8 +148,6 @@ privileged:
|
||||||
|
|
||||||
//$4016-$4017
|
//$4016-$4017
|
||||||
bool joypadStrobeLatch;
|
bool joypadStrobeLatch;
|
||||||
uint32 joypad1_bits;
|
|
||||||
uint32 joypad2_bits;
|
|
||||||
|
|
||||||
//$4200
|
//$4200
|
||||||
bool nmiEnabled;
|
bool nmiEnabled;
|
||||||
|
@ -184,7 +182,7 @@ privileged:
|
||||||
uint16 joy2;
|
uint16 joy2;
|
||||||
uint16 joy3;
|
uint16 joy3;
|
||||||
uint16 joy4;
|
uint16 joy4;
|
||||||
} status;
|
} io;
|
||||||
|
|
||||||
struct ALU {
|
struct ALU {
|
||||||
uint mpyctr;
|
uint mpyctr;
|
||||||
|
@ -218,8 +216,8 @@ privileged:
|
||||||
|
|
||||||
//$43x5-$43x6
|
//$43x5-$43x6
|
||||||
union {
|
union {
|
||||||
uint16 transferSize = 0;
|
uint16 transferSize;
|
||||||
uint16_t indirectAddress;
|
uint16 indirectAddress;
|
||||||
};
|
};
|
||||||
|
|
||||||
//$43x7
|
//$43x7
|
||||||
|
@ -237,6 +235,8 @@ privileged:
|
||||||
//internal state
|
//internal state
|
||||||
bool hdmaCompleted;
|
bool hdmaCompleted;
|
||||||
bool hdmaDoTransfer;
|
bool hdmaDoTransfer;
|
||||||
|
|
||||||
|
Channel() : transferSize(0) {}
|
||||||
} channel[8];
|
} channel[8];
|
||||||
|
|
||||||
struct Pipe {
|
struct Pipe {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
auto CPU::dmaAddClocks(uint clocks) -> void {
|
auto CPU::dmaStep(uint clocks) -> void {
|
||||||
status.dmaClocks += clocks;
|
status.dmaClocks += clocks;
|
||||||
addClocks(clocks);
|
step(clocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============
|
//=============
|
||||||
|
@ -41,14 +41,14 @@ auto CPU::dmaWrite(bool valid, uint addr, uint8 data) -> void {
|
||||||
|
|
||||||
auto CPU::dmaTransfer(bool direction, uint8 bbus, uint24 abus) -> void {
|
auto CPU::dmaTransfer(bool direction, uint8 bbus, uint24 abus) -> void {
|
||||||
if(direction == 0) {
|
if(direction == 0) {
|
||||||
dmaAddClocks(4);
|
dmaStep(4);
|
||||||
r.mdr = dmaRead(abus);
|
r.mdr = dmaRead(abus);
|
||||||
dmaAddClocks(4);
|
dmaStep(4);
|
||||||
dmaWrite(dmaTransferValid(bbus, abus), 0x2100 | bbus, r.mdr);
|
dmaWrite(dmaTransferValid(bbus, abus), 0x2100 | bbus, r.mdr);
|
||||||
} else {
|
} else {
|
||||||
dmaAddClocks(4);
|
dmaStep(4);
|
||||||
r.mdr = dmaTransferValid(bbus, abus) ? bus.read(0x2100 | bbus, r.mdr) : (uint8)0x00;
|
r.mdr = dmaTransferValid(bbus, abus) ? bus.read(0x2100 | bbus, r.mdr) : (uint8)0x00;
|
||||||
dmaAddClocks(4);
|
dmaStep(4);
|
||||||
dmaWrite(dmaAddressValid(abus), abus, r.mdr);
|
dmaWrite(dmaAddressValid(abus), abus, r.mdr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ auto CPU::hdmaActiveChannels() -> uint {
|
||||||
//==============
|
//==============
|
||||||
|
|
||||||
auto CPU::dmaRun() -> void {
|
auto CPU::dmaRun() -> void {
|
||||||
dmaAddClocks(8);
|
dmaStep(8);
|
||||||
dmaWrite(false);
|
dmaWrite(false);
|
||||||
dmaEdge();
|
dmaEdge();
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ auto CPU::dmaRun() -> void {
|
||||||
dmaEdge();
|
dmaEdge();
|
||||||
} while(channel[n].dmaEnabled && --channel[n].transferSize);
|
} while(channel[n].dmaEnabled && --channel[n].transferSize);
|
||||||
|
|
||||||
dmaAddClocks(8);
|
dmaStep(8);
|
||||||
dmaWrite(false);
|
dmaWrite(false);
|
||||||
dmaEdge();
|
dmaEdge();
|
||||||
|
|
||||||
|
@ -155,9 +155,9 @@ auto CPU::dmaRun() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::hdmaUpdate(uint n) -> void {
|
auto CPU::hdmaUpdate(uint n) -> void {
|
||||||
dmaAddClocks(4);
|
dmaStep(4);
|
||||||
r.mdr = dmaRead(channel[n].sourceBank << 16 | channel[n].hdmaAddress);
|
r.mdr = dmaRead(channel[n].sourceBank << 16 | channel[n].hdmaAddress);
|
||||||
dmaAddClocks(4);
|
dmaStep(4);
|
||||||
dmaWrite(false);
|
dmaWrite(false);
|
||||||
|
|
||||||
if((channel[n].lineCounter & 0x7f) == 0) {
|
if((channel[n].lineCounter & 0x7f) == 0) {
|
||||||
|
@ -168,18 +168,18 @@ auto CPU::hdmaUpdate(uint n) -> void {
|
||||||
channel[n].hdmaDoTransfer = !channel[n].hdmaCompleted;
|
channel[n].hdmaDoTransfer = !channel[n].hdmaCompleted;
|
||||||
|
|
||||||
if(channel[n].indirect) {
|
if(channel[n].indirect) {
|
||||||
dmaAddClocks(4);
|
dmaStep(4);
|
||||||
r.mdr = dmaRead(hdmaAddress(n));
|
r.mdr = dmaRead(hdmaAddress(n));
|
||||||
channel[n].indirectAddress = r.mdr << 8;
|
channel[n].indirectAddress = r.mdr << 8;
|
||||||
dmaAddClocks(4);
|
dmaStep(4);
|
||||||
dmaWrite(false);
|
dmaWrite(false);
|
||||||
|
|
||||||
if(!channel[n].hdmaCompleted || hdmaActiveAfter(n)) {
|
if(!channel[n].hdmaCompleted || hdmaActiveAfter(n)) {
|
||||||
dmaAddClocks(4);
|
dmaStep(4);
|
||||||
r.mdr = dmaRead(hdmaAddress(n));
|
r.mdr = dmaRead(hdmaAddress(n));
|
||||||
channel[n].indirectAddress >>= 8;
|
channel[n].indirectAddress >>= 8;
|
||||||
channel[n].indirectAddress |= r.mdr << 8;
|
channel[n].indirectAddress |= r.mdr << 8;
|
||||||
dmaAddClocks(4);
|
dmaStep(4);
|
||||||
dmaWrite(false);
|
dmaWrite(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ auto CPU::hdmaUpdate(uint n) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::hdmaRun() -> void {
|
auto CPU::hdmaRun() -> void {
|
||||||
dmaAddClocks(8);
|
dmaStep(8);
|
||||||
dmaWrite(false);
|
dmaWrite(false);
|
||||||
|
|
||||||
for(auto n : range(8)) {
|
for(auto n : range(8)) {
|
||||||
|
@ -223,7 +223,7 @@ auto CPU::hdmaInitReset() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::hdmaInit() -> void {
|
auto CPU::hdmaInit() -> void {
|
||||||
dmaAddClocks(8);
|
dmaStep(8);
|
||||||
dmaWrite(false);
|
dmaWrite(false);
|
||||||
|
|
||||||
for(auto n : range(8)) {
|
for(auto n : range(8)) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 {
|
||||||
|
|
||||||
//WMDATA
|
//WMDATA
|
||||||
case 0x2180: {
|
case 0x2180: {
|
||||||
return bus.read(0x7e0000 | status.wramAddress++, r.mdr);
|
return bus.read(0x7e0000 | io.wramAddress++, r.mdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//JOYSER0
|
//JOYSER0
|
||||||
|
@ -65,37 +65,37 @@ auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 {
|
||||||
|
|
||||||
//RDIO
|
//RDIO
|
||||||
case 0x4213: {
|
case 0x4213: {
|
||||||
return status.pio;
|
return io.pio;
|
||||||
}
|
}
|
||||||
|
|
||||||
//RDDIVL
|
//RDDIVL
|
||||||
case 0x4214: {
|
case 0x4214: {
|
||||||
return status.rddiv.byte(0);
|
return io.rddiv.byte(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//RDDIVH
|
//RDDIVH
|
||||||
case 0x4215: {
|
case 0x4215: {
|
||||||
return status.rddiv.byte(1);
|
return io.rddiv.byte(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//RDMPYL
|
//RDMPYL
|
||||||
case 0x4216: {
|
case 0x4216: {
|
||||||
return status.rdmpy.byte(0);
|
return io.rdmpy.byte(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//RDMPYH
|
//RDMPYH
|
||||||
case 0x4217: {
|
case 0x4217: {
|
||||||
return status.rdmpy.byte(1);
|
return io.rdmpy.byte(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x4218: return status.joy1.byte(0); //JOY1L
|
case 0x4218: return io.joy1.byte(0); //JOY1L
|
||||||
case 0x4219: return status.joy1.byte(1); //JOY1H
|
case 0x4219: return io.joy1.byte(1); //JOY1H
|
||||||
case 0x421a: return status.joy2.byte(0); //JOY2L
|
case 0x421a: return io.joy2.byte(0); //JOY2L
|
||||||
case 0x421b: return status.joy2.byte(1); //JOY2H
|
case 0x421b: return io.joy2.byte(1); //JOY2H
|
||||||
case 0x421c: return status.joy3.byte(0); //JOY3L
|
case 0x421c: return io.joy3.byte(0); //JOY3L
|
||||||
case 0x421d: return status.joy3.byte(1); //JOY3H
|
case 0x421d: return io.joy3.byte(1); //JOY3H
|
||||||
case 0x421e: return status.joy4.byte(0); //JOY4L
|
case 0x421e: return io.joy4.byte(0); //JOY4L
|
||||||
case 0x421f: return status.joy4.byte(1); //JOY4H
|
case 0x421f: return io.joy4.byte(1); //JOY4H
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ auto CPU::readDMA(uint24 addr, uint8 data) -> uint8 {
|
||||||
|
|
||||||
auto CPU::writeAPU(uint24 addr, uint8 data) -> void {
|
auto CPU::writeAPU(uint24 addr, uint8 data) -> void {
|
||||||
synchronizeSMP();
|
synchronizeSMP();
|
||||||
return portWrite(addr.bits(0,1), data);
|
return writePort(addr.bits(0,1), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
|
auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
|
||||||
|
@ -166,12 +166,12 @@ auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
|
||||||
|
|
||||||
//WMDATA
|
//WMDATA
|
||||||
case 0x2180: {
|
case 0x2180: {
|
||||||
return bus.write(0x7e0000 | status.wramAddress++, data);
|
return bus.write(0x7e0000 | io.wramAddress++, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x2181: status.wramAddress.bits( 0, 7) = data; return; //WMADDL
|
case 0x2181: io.wramAddress.bits( 0, 7) = data; return; //WMADDL
|
||||||
case 0x2182: status.wramAddress.bits( 8,15) = data; return; //WMADDM
|
case 0x2182: io.wramAddress.bits( 8,15) = data; return; //WMADDM
|
||||||
case 0x2183: status.wramAddress.bit (16 ) = data.bit(0); return; //WMADDH
|
case 0x2183: io.wramAddress.bit (16 ) = data.bit(0); return; //WMADDH
|
||||||
|
|
||||||
//JOYSER0
|
//JOYSER0
|
||||||
case 0x4016: {
|
case 0x4016: {
|
||||||
|
@ -185,54 +185,54 @@ auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
|
||||||
|
|
||||||
//NMITIMEN
|
//NMITIMEN
|
||||||
case 0x4200: {
|
case 0x4200: {
|
||||||
status.autoJoypadPoll = data.bit(0);
|
io.autoJoypadPoll = data.bit(0);
|
||||||
nmitimenUpdate(data);
|
nmitimenUpdate(data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//WRIO
|
//WRIO
|
||||||
case 0x4201: {
|
case 0x4201: {
|
||||||
if(status.pio.bit(7) && !data.bit(7)) ppu.latchCounters();
|
if(io.pio.bit(7) && !data.bit(7)) ppu.latchCounters();
|
||||||
status.pio = data;
|
io.pio = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//WRMPYA
|
//WRMPYA
|
||||||
case 0x4202: status.wrmpya = data; return;
|
case 0x4202: io.wrmpya = data; return;
|
||||||
|
|
||||||
//WRMPYB
|
//WRMPYB
|
||||||
case 0x4203: {
|
case 0x4203: {
|
||||||
status.rdmpy = 0;
|
io.rdmpy = 0;
|
||||||
if(alu.mpyctr || alu.divctr) return;
|
if(alu.mpyctr || alu.divctr) return;
|
||||||
|
|
||||||
status.wrmpyb = data;
|
io.wrmpyb = data;
|
||||||
status.rddiv = (status.wrmpyb << 8) | status.wrmpya;
|
io.rddiv = (io.wrmpyb << 8) | io.wrmpya;
|
||||||
|
|
||||||
alu.mpyctr = 8; //perform multiplication over the next eight cycles
|
alu.mpyctr = 8; //perform multiplication over the next eight cycles
|
||||||
alu.shift = status.wrmpyb;
|
alu.shift = io.wrmpyb;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x4204: { status.wrdiva.byte(0) = data; return; } //WRDIVL
|
case 0x4204: { io.wrdiva.byte(0) = data; return; } //WRDIVL
|
||||||
case 0x4205: { status.wrdiva.byte(1) = data; return; } //WRDIVH
|
case 0x4205: { io.wrdiva.byte(1) = data; return; } //WRDIVH
|
||||||
|
|
||||||
//WRDIVB
|
//WRDIVB
|
||||||
case 0x4206: {
|
case 0x4206: {
|
||||||
status.rdmpy = status.wrdiva;
|
io.rdmpy = io.wrdiva;
|
||||||
if(alu.mpyctr || alu.divctr) return;
|
if(alu.mpyctr || alu.divctr) return;
|
||||||
|
|
||||||
status.wrdivb = data;
|
io.wrdivb = data;
|
||||||
|
|
||||||
alu.divctr = 16; //perform division over the next sixteen cycles
|
alu.divctr = 16; //perform division over the next sixteen cycles
|
||||||
alu.shift = status.wrdivb << 16;
|
alu.shift = io.wrdivb << 16;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x4207: status.hirqPos.bits(0,7) = data; return; //HTIMEL
|
case 0x4207: io.hirqPos.bits(0,7) = data; return; //HTIMEL
|
||||||
case 0x4208: status.hirqPos.bit (8 ) = data.bit(0); return; //HTIMEH
|
case 0x4208: io.hirqPos.bit (8 ) = data.bit(0); return; //HTIMEH
|
||||||
|
|
||||||
case 0x4209: status.virqPos.bits(0,7) = data; return; //VTIMEL
|
case 0x4209: io.virqPos.bits(0,7) = data; return; //VTIMEL
|
||||||
case 0x420a: status.virqPos.bit (8 ) = data.bit(0); return; //VTIMEH
|
case 0x420a: io.virqPos.bit (8 ) = data.bit(0); return; //VTIMEH
|
||||||
|
|
||||||
//DMAEN
|
//DMAEN
|
||||||
case 0x420b: {
|
case 0x420b: {
|
||||||
|
@ -249,7 +249,7 @@ auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
|
||||||
|
|
||||||
//MEMSEL
|
//MEMSEL
|
||||||
case 0x420d: {
|
case 0x420d: {
|
||||||
status.romSpeed = data.bit(0) ? 6 : 8;
|
io.romSpeed = data.bit(0) ? 6 : 8;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ auto CPU::pollInterrupts() -> void {
|
||||||
//NMI hold
|
//NMI hold
|
||||||
if(status.nmiHold) {
|
if(status.nmiHold) {
|
||||||
status.nmiHold = false;
|
status.nmiHold = false;
|
||||||
if(status.nmiEnabled) status.nmiTransition = true;
|
if(io.nmiEnabled) status.nmiTransition = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//NMI test
|
//NMI test
|
||||||
|
@ -25,15 +25,15 @@ auto CPU::pollInterrupts() -> void {
|
||||||
//IRQ hold
|
//IRQ hold
|
||||||
status.irqHold = false;
|
status.irqHold = false;
|
||||||
if(status.irqLine) {
|
if(status.irqLine) {
|
||||||
if(status.virqEnabled || status.hirqEnabled) status.irqTransition = true;
|
if(io.virqEnabled || io.hirqEnabled) status.irqTransition = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//IRQ test
|
//IRQ test
|
||||||
bool irqValid = status.virqEnabled || status.hirqEnabled;
|
bool irqValid = io.virqEnabled || io.hirqEnabled;
|
||||||
if(irqValid) {
|
if(irqValid) {
|
||||||
if((status.virqEnabled && vcounter(10) != (status.virqPos))
|
if((io.virqEnabled && vcounter(10) != (io.virqPos))
|
||||||
|| (status.hirqEnabled && hcounter(10) != (status.hirqPos + 1) * 4)
|
|| (io.hirqEnabled && hcounter(10) != (io.hirqPos + 1) * 4)
|
||||||
|| (status.virqPos && vcounter(6) == 0) //IRQs cannot trigger on last dot of field
|
|| (io.virqPos && vcounter(6) == 0) //IRQs cannot trigger on last dot of field
|
||||||
) irqValid = false;
|
) irqValid = false;
|
||||||
}
|
}
|
||||||
if(!status.irqValid && irqValid) {
|
if(!status.irqValid && irqValid) {
|
||||||
|
@ -45,24 +45,24 @@ auto CPU::pollInterrupts() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::nmitimenUpdate(uint8 data) -> void {
|
auto CPU::nmitimenUpdate(uint8 data) -> void {
|
||||||
bool nmiEnabled = status.nmiEnabled;
|
bool nmiEnabled = io.nmiEnabled;
|
||||||
bool virqEnabled = status.virqEnabled;
|
bool virqEnabled = io.virqEnabled;
|
||||||
bool hirqEnabled = status.hirqEnabled;
|
bool hirqEnabled = io.hirqEnabled;
|
||||||
status.nmiEnabled = data & 0x80;
|
io.nmiEnabled = data & 0x80;
|
||||||
status.virqEnabled = data & 0x20;
|
io.virqEnabled = data & 0x20;
|
||||||
status.hirqEnabled = data & 0x10;
|
io.hirqEnabled = data & 0x10;
|
||||||
|
|
||||||
//0->1 edge sensitive transition
|
//0->1 edge sensitive transition
|
||||||
if(!nmiEnabled && status.nmiEnabled && status.nmiLine) {
|
if(!nmiEnabled && io.nmiEnabled && status.nmiLine) {
|
||||||
status.nmiTransition = true;
|
status.nmiTransition = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//?->1 level sensitive transition
|
//?->1 level sensitive transition
|
||||||
if(status.virqEnabled && !status.hirqEnabled && status.irqLine) {
|
if(io.virqEnabled && !io.hirqEnabled && status.irqLine) {
|
||||||
status.irqTransition = true;
|
status.irqTransition = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!status.virqEnabled && !status.hirqEnabled) {
|
if(!io.virqEnabled && !io.hirqEnabled) {
|
||||||
status.irqLine = false;
|
status.irqLine = false;
|
||||||
status.irqTransition = false;
|
status.irqTransition = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
auto CPU::stepAutoJoypadPoll() -> void {
|
auto CPU::stepAutoJoypadPoll() -> void {
|
||||||
if(vcounter() >= ppu.vdisp()) {
|
if(vcounter() >= ppu.vdisp()) {
|
||||||
//cache enable state at first iteration
|
//cache enable state at first iteration
|
||||||
if(status.autoJoypadCounter == 0) status.autoJoypadLatch = status.autoJoypadPoll;
|
if(status.autoJoypadCounter == 0) status.autoJoypadLatch = io.autoJoypadPoll;
|
||||||
status.autoJoypadActive = status.autoJoypadCounter <= 15;
|
status.autoJoypadActive = status.autoJoypadCounter <= 15;
|
||||||
|
|
||||||
if(status.autoJoypadActive && status.autoJoypadLatch) {
|
if(status.autoJoypadActive && status.autoJoypadLatch) {
|
||||||
|
@ -16,10 +16,10 @@ auto CPU::stepAutoJoypadPoll() -> void {
|
||||||
uint2 port0 = SuperFamicom::peripherals.controllerPort1->data();
|
uint2 port0 = SuperFamicom::peripherals.controllerPort1->data();
|
||||||
uint2 port1 = SuperFamicom::peripherals.controllerPort2->data();
|
uint2 port1 = SuperFamicom::peripherals.controllerPort2->data();
|
||||||
|
|
||||||
status.joy1 = status.joy1 << 1 | port0.bit(0);
|
io.joy1 = io.joy1 << 1 | port0.bit(0);
|
||||||
status.joy2 = status.joy2 << 1 | port1.bit(0);
|
io.joy2 = io.joy2 << 1 | port1.bit(0);
|
||||||
status.joy3 = status.joy3 << 1 | port0.bit(1);
|
io.joy3 = io.joy3 << 1 | port0.bit(1);
|
||||||
status.joy4 = status.joy4 << 1 | port1.bit(1);
|
io.joy4 = io.joy4 << 1 | port1.bit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status.autoJoypadCounter++;
|
status.autoJoypadCounter++;
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
auto CPU::portRead(uint2 port) const -> uint8 {
|
auto CPU::readPort(uint2 port) const -> uint8 {
|
||||||
return status.port[port];
|
return io.port[port];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::portWrite(uint2 port, uint8 data) -> void {
|
auto CPU::writePort(uint2 port, uint8 data) -> void {
|
||||||
status.port[port] = data;
|
io.port[port] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::io() -> void {
|
auto CPU::idle() -> void {
|
||||||
status.clockCount = 6;
|
status.clockCount = 6;
|
||||||
dmaEdge();
|
dmaEdge();
|
||||||
addClocks(6);
|
step(6);
|
||||||
aluEdge();
|
aluEdge();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::read(uint24 addr) -> uint8 {
|
auto CPU::read(uint24 addr) -> uint8 {
|
||||||
status.clockCount = speed(addr);
|
status.clockCount = speed(addr);
|
||||||
dmaEdge();
|
dmaEdge();
|
||||||
addClocks(status.clockCount - 4);
|
step(status.clockCount - 4);
|
||||||
r.mdr = bus.read(addr, r.mdr);
|
r.mdr = bus.read(addr, r.mdr);
|
||||||
addClocks(4);
|
step(4);
|
||||||
aluEdge();
|
aluEdge();
|
||||||
return r.mdr;
|
return r.mdr;
|
||||||
}
|
}
|
||||||
|
@ -27,15 +27,12 @@ auto CPU::write(uint24 addr, uint8 data) -> void {
|
||||||
aluEdge();
|
aluEdge();
|
||||||
status.clockCount = speed(addr);
|
status.clockCount = speed(addr);
|
||||||
dmaEdge();
|
dmaEdge();
|
||||||
addClocks(status.clockCount);
|
step(status.clockCount);
|
||||||
bus.write(addr, r.mdr = data);
|
bus.write(addr, r.mdr = data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::speed(uint24 addr) const -> uint {
|
auto CPU::speed(uint24 addr) const -> uint {
|
||||||
if(addr & 0x408000) {
|
if(addr & 0x408000) return addr & 0x800000 ? io.romSpeed : 8;
|
||||||
if(addr & 0x800000) return status.romSpeed;
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
if((addr + 0x6000) & 0x4000) return 8;
|
if((addr + 0x6000) & 0x4000) return 8;
|
||||||
if((addr - 0x4000) & 0x7e00) return 6;
|
if((addr - 0x4000) & 0x7e00) return 6;
|
||||||
return 12;
|
return 12;
|
||||||
|
|
|
@ -50,39 +50,37 @@ auto CPU::serialize(serializer& s) -> void {
|
||||||
s.integer(status.autoJoypadCounter);
|
s.integer(status.autoJoypadCounter);
|
||||||
s.integer(status.autoJoypadClock);
|
s.integer(status.autoJoypadClock);
|
||||||
|
|
||||||
s.array(status.port);
|
s.array(io.port);
|
||||||
|
|
||||||
s.integer(status.wramAddress);
|
s.integer(io.wramAddress);
|
||||||
|
|
||||||
s.integer(status.joypadStrobeLatch);
|
s.integer(io.joypadStrobeLatch);
|
||||||
s.integer(status.joypad1_bits);
|
|
||||||
s.integer(status.joypad2_bits);
|
|
||||||
|
|
||||||
s.integer(status.nmiEnabled);
|
s.integer(io.nmiEnabled);
|
||||||
s.integer(status.hirqEnabled);
|
s.integer(io.hirqEnabled);
|
||||||
s.integer(status.virqEnabled);
|
s.integer(io.virqEnabled);
|
||||||
s.integer(status.autoJoypadPoll);
|
s.integer(io.autoJoypadPoll);
|
||||||
|
|
||||||
s.integer(status.pio);
|
s.integer(io.pio);
|
||||||
|
|
||||||
s.integer(status.wrmpya);
|
s.integer(io.wrmpya);
|
||||||
s.integer(status.wrmpyb);
|
s.integer(io.wrmpyb);
|
||||||
|
|
||||||
s.integer(status.wrdiva);
|
s.integer(io.wrdiva);
|
||||||
s.integer(status.wrdivb);
|
s.integer(io.wrdivb);
|
||||||
|
|
||||||
s.integer(status.hirqPos);
|
s.integer(io.hirqPos);
|
||||||
s.integer(status.virqPos);
|
s.integer(io.virqPos);
|
||||||
|
|
||||||
s.integer(status.romSpeed);
|
s.integer(io.romSpeed);
|
||||||
|
|
||||||
s.integer(status.rddiv);
|
s.integer(io.rddiv);
|
||||||
s.integer(status.rdmpy);
|
s.integer(io.rdmpy);
|
||||||
|
|
||||||
s.integer(status.joy1);
|
s.integer(io.joy1);
|
||||||
s.integer(status.joy2);
|
s.integer(io.joy2);
|
||||||
s.integer(status.joy3);
|
s.integer(io.joy3);
|
||||||
s.integer(status.joy4);
|
s.integer(io.joy4);
|
||||||
|
|
||||||
s.integer(alu.mpyctr);
|
s.integer(alu.mpyctr);
|
||||||
s.integer(alu.divctr);
|
s.integer(alu.divctr);
|
||||||
|
|
|
@ -2,7 +2,7 @@ auto CPU::dmaCounter() const -> uint {
|
||||||
return (status.dmaCounter + hcounter()) & 7;
|
return (status.dmaCounter + hcounter()) & 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::addClocks(uint clocks) -> void {
|
auto CPU::step(uint clocks) -> void {
|
||||||
status.irqLock = false;
|
status.irqLock = false;
|
||||||
uint ticks = clocks >> 1;
|
uint ticks = clocks >> 1;
|
||||||
while(ticks--) {
|
while(ticks--) {
|
||||||
|
@ -10,7 +10,15 @@ auto CPU::addClocks(uint clocks) -> void {
|
||||||
if(hcounter() & 2) pollInterrupts();
|
if(hcounter() & 2) pollInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
step(clocks);
|
smp.clock -= clocks * (uint64)smp.frequency;
|
||||||
|
ppu.clock -= clocks;
|
||||||
|
for(auto coprocessor : coprocessors) {
|
||||||
|
coprocessor->clock -= clocks * (uint64)coprocessor->frequency;
|
||||||
|
}
|
||||||
|
for(auto peripheral : peripherals) {
|
||||||
|
peripheral->clock -= clocks * (uint64)peripheral->frequency;
|
||||||
|
}
|
||||||
|
synchronizePeripherals();
|
||||||
|
|
||||||
status.autoJoypadClock += clocks;
|
status.autoJoypadClock += clocks;
|
||||||
if(status.autoJoypadClock >= 256) {
|
if(status.autoJoypadClock >= 256) {
|
||||||
|
@ -20,7 +28,7 @@ auto CPU::addClocks(uint clocks) -> void {
|
||||||
|
|
||||||
if(!status.dramRefreshed && hcounter() >= status.dramRefreshPosition) {
|
if(!status.dramRefreshed && hcounter() >= status.dramRefreshPosition) {
|
||||||
status.dramRefreshed = true;
|
status.dramRefreshed = true;
|
||||||
addClocks(40);
|
step(40);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DEBUGGER)
|
#if defined(DEBUGGER)
|
||||||
|
@ -62,18 +70,18 @@ auto CPU::scanline() -> void {
|
||||||
auto CPU::aluEdge() -> void {
|
auto CPU::aluEdge() -> void {
|
||||||
if(alu.mpyctr) {
|
if(alu.mpyctr) {
|
||||||
alu.mpyctr--;
|
alu.mpyctr--;
|
||||||
if(status.rddiv & 1) status.rdmpy += alu.shift;
|
if(io.rddiv & 1) io.rdmpy += alu.shift;
|
||||||
status.rddiv >>= 1;
|
io.rddiv >>= 1;
|
||||||
alu.shift <<= 1;
|
alu.shift <<= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(alu.divctr) {
|
if(alu.divctr) {
|
||||||
alu.divctr--;
|
alu.divctr--;
|
||||||
status.rddiv <<= 1;
|
io.rddiv <<= 1;
|
||||||
alu.shift >>= 1;
|
alu.shift >>= 1;
|
||||||
if(status.rdmpy >= alu.shift) {
|
if(io.rdmpy >= alu.shift) {
|
||||||
status.rdmpy -= alu.shift;
|
io.rdmpy -= alu.shift;
|
||||||
status.rddiv |= 1;
|
io.rddiv |= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,11 +100,11 @@ auto CPU::dmaEdge() -> void {
|
||||||
status.hdmaPending = false;
|
status.hdmaPending = false;
|
||||||
if(hdmaEnabledChannels()) {
|
if(hdmaEnabledChannels()) {
|
||||||
if(!dmaEnabledChannels()) {
|
if(!dmaEnabledChannels()) {
|
||||||
dmaAddClocks(8 - dmaCounter());
|
dmaStep(8 - dmaCounter());
|
||||||
}
|
}
|
||||||
status.hdmaMode == 0 ? hdmaInit() : hdmaRun();
|
status.hdmaMode == 0 ? hdmaInit() : hdmaRun();
|
||||||
if(!dmaEnabledChannels()) {
|
if(!dmaEnabledChannels()) {
|
||||||
addClocks(status.clockCount - (status.dmaClocks % status.clockCount));
|
step(status.clockCount - (status.dmaClocks % status.clockCount));
|
||||||
status.dmaActive = false;
|
status.dmaActive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,9 +113,9 @@ auto CPU::dmaEdge() -> void {
|
||||||
if(status.dmaPending) {
|
if(status.dmaPending) {
|
||||||
status.dmaPending = false;
|
status.dmaPending = false;
|
||||||
if(dmaEnabledChannels()) {
|
if(dmaEnabledChannels()) {
|
||||||
dmaAddClocks(8 - dmaCounter());
|
dmaStep(8 - dmaCounter());
|
||||||
dmaRun();
|
dmaRun();
|
||||||
addClocks(status.clockCount - (status.dmaClocks % status.clockCount));
|
step(status.clockCount - (status.dmaClocks % status.clockCount));
|
||||||
status.dmaActive = false;
|
status.dmaActive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,8 +244,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
|
||||||
lstring codes = codeset.split("+");
|
lstring codes = codeset.split("+");
|
||||||
for(auto& code : codes) {
|
for(auto& code : codes) {
|
||||||
lstring part = code.split("/");
|
lstring part = code.split("/");
|
||||||
if(part.size() == 2) GameBoy::cheat.append(hex(part[0]), hex(part[1]));
|
if(part.size() == 2) GameBoy::cheat.append(part[0].hex(), part[1].hex());
|
||||||
if(part.size() == 3) GameBoy::cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
if(part.size() == 3) GameBoy::cheat.append(part[0].hex(), part[1].hex(), part[2].hex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -256,8 +256,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
|
||||||
lstring codes = codeset.split("+");
|
lstring codes = codeset.split("+");
|
||||||
for(auto& code : codes) {
|
for(auto& code : codes) {
|
||||||
lstring part = code.split("/");
|
lstring part = code.split("/");
|
||||||
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1]));
|
if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
|
||||||
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ auto Bus::map(
|
||||||
while(counter[id]) {
|
while(counter[id]) {
|
||||||
if(++id >= 256) return print("SFC error: bus map exhausted\n");
|
if(++id >= 256) return print("SFC error: bus map exhausted\n");
|
||||||
}
|
}
|
||||||
//print("map[", hex(id, 2), "] => ", addr, "\n");
|
|
||||||
|
|
||||||
reader[id] = read;
|
reader[id] = read;
|
||||||
writer[id] = write;
|
writer[id] = write;
|
||||||
|
@ -47,10 +46,10 @@ auto Bus::map(
|
||||||
for(auto& addr : addrs) {
|
for(auto& addr : addrs) {
|
||||||
auto bankRange = bank.split("-", 1L);
|
auto bankRange = bank.split("-", 1L);
|
||||||
auto addrRange = addr.split("-", 1L);
|
auto addrRange = addr.split("-", 1L);
|
||||||
uint bankLo = hex(bankRange(0));
|
uint bankLo = bankRange(0).hex();
|
||||||
uint bankHi = hex(bankRange(1, bankRange(0)));
|
uint bankHi = bankRange(1, bankRange(0)).hex();
|
||||||
uint addrLo = hex(addrRange(0));
|
uint addrLo = addrRange(0).hex();
|
||||||
uint addrHi = hex(addrRange(1, addrRange(0)));
|
uint addrHi = addrRange(1, addrRange(0)).hex();
|
||||||
|
|
||||||
for(uint bank = bankLo; bank <= bankHi; bank++) {
|
for(uint bank = bankLo; bank <= bankHi; bank++) {
|
||||||
for(uint addr = addrLo; addr <= addrHi; addr++) {
|
for(uint addr = addrLo; addr <= addrHi; addr++) {
|
||||||
|
@ -79,10 +78,10 @@ auto Bus::unmap(const string& addr) -> void {
|
||||||
for(auto& addr : addrs) {
|
for(auto& addr : addrs) {
|
||||||
auto bankRange = bank.split("-", 1L);
|
auto bankRange = bank.split("-", 1L);
|
||||||
auto addrRange = addr.split("-", 1L);
|
auto addrRange = addr.split("-", 1L);
|
||||||
uint bankLo = hex(bankRange(0));
|
uint bankLo = bankRange(0).hex();
|
||||||
uint bankHi = hex(bankRange(1, bankRange(0)));
|
uint bankHi = bankRange(1, bankRange(0)).hex();
|
||||||
uint addrLo = hex(addrRange(0));
|
uint addrLo = addrRange(0).hex();
|
||||||
uint addrHi = hex(addrRange(1, addrRange(1)));
|
uint addrHi = addrRange(1, addrRange(1)).hex();
|
||||||
|
|
||||||
for(uint bank = bankLo; bank <= bankHi; bank++) {
|
for(uint bank = bankLo; bank <= bankHi; bank++) {
|
||||||
for(uint addr = addrLo; addr <= addrHi; addr++) {
|
for(uint addr = addrLo; addr <= addrHi; addr++) {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#include "mode7.cpp"
|
#include "mode7.cpp"
|
||||||
|
|
||||||
auto PPU::Background::voffset() const -> uint16 {
|
auto PPU::Background::voffset() const -> uint16 {
|
||||||
if(r.mosaic) return latch.voffset;
|
if(io.mosaic) return latch.voffset;
|
||||||
return r.voffset;
|
return io.voffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Background::hoffset() const -> uint16 {
|
auto PPU::Background::hoffset() const -> uint16 {
|
||||||
if(r.mosaic) return latch.hoffset;
|
if(io.mosaic) return latch.hoffset;
|
||||||
return r.hoffset;
|
return io.hoffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
//V = 0, H = 0
|
//V = 0, H = 0
|
||||||
|
@ -20,70 +20,70 @@ auto PPU::Background::scanline() -> void {
|
||||||
|
|
||||||
//H = 28
|
//H = 28
|
||||||
auto PPU::Background::begin() -> void {
|
auto PPU::Background::begin() -> void {
|
||||||
bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6);
|
bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
|
||||||
x = -7;
|
x = -7;
|
||||||
y = ppu.vcounter();
|
y = ppu.vcounter();
|
||||||
|
|
||||||
if(y == 1) {
|
if(y == 1) {
|
||||||
mosaic.vcounter = r.mosaic + 1;
|
mosaic.vcounter = io.mosaic + 1;
|
||||||
mosaic.voffset = 1;
|
mosaic.voffset = 1;
|
||||||
latch.hoffset = r.hoffset;
|
latch.hoffset = io.hoffset;
|
||||||
latch.voffset = r.voffset;
|
latch.voffset = io.voffset;
|
||||||
} else if(--mosaic.vcounter == 0) {
|
} else if(--mosaic.vcounter == 0) {
|
||||||
mosaic.vcounter = r.mosaic + 1;
|
mosaic.vcounter = io.mosaic + 1;
|
||||||
mosaic.voffset += r.mosaic + 1;
|
mosaic.voffset += io.mosaic + 1;
|
||||||
latch.hoffset = r.hoffset;
|
latch.hoffset = io.hoffset;
|
||||||
latch.voffset = r.voffset;
|
latch.voffset = io.voffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
tileCounter = (7 - (latch.hoffset & 7)) << hires;
|
tileCounter = (7 - (latch.hoffset & 7)) << hires;
|
||||||
for(auto& d : data) d = 0;
|
for(auto& d : data) d = 0;
|
||||||
|
|
||||||
mosaic.hcounter = r.mosaic + 1;
|
mosaic.hcounter = io.mosaic + 1;
|
||||||
mosaic.hoffset = 0;
|
mosaic.hoffset = 0;
|
||||||
|
|
||||||
if(r.mode == Mode::Mode7) return beginMode7();
|
if(io.mode == Mode::Mode7) return beginMode7();
|
||||||
if(r.mosaic == 0) {
|
if(io.mosaic == 0) {
|
||||||
latch.hoffset = r.hoffset;
|
latch.hoffset = io.hoffset;
|
||||||
latch.voffset = r.voffset;
|
latch.voffset = io.voffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Background::getTile() -> void {
|
auto PPU::Background::getTile() -> void {
|
||||||
bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6);
|
bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
|
||||||
|
|
||||||
uint colorDepth = (r.mode == Mode::BPP2 ? 0 : r.mode == Mode::BPP4 ? 1 : 2);
|
uint colorDepth = (io.mode == Mode::BPP2 ? 0 : io.mode == Mode::BPP4 ? 1 : 2);
|
||||||
uint paletteOffset = (ppu.r.bgMode == 0 ? id << 5 : 0);
|
uint paletteOffset = (ppu.io.bgMode == 0 ? id << 5 : 0);
|
||||||
uint paletteSize = 2 << colorDepth;
|
uint paletteSize = 2 << colorDepth;
|
||||||
uint tileMask = ppu.vram.mask >> (3 + colorDepth);
|
uint tileMask = ppu.vram.mask >> (3 + colorDepth);
|
||||||
uint tiledataIndex = r.tiledataAddress >> (3 + colorDepth);
|
uint tiledataIndex = io.tiledataAddress >> (3 + colorDepth);
|
||||||
|
|
||||||
uint tileHeight = (r.tileSize == TileSize::Size8x8 ? 3 : 4);
|
uint tileHeight = (io.tileSize == TileSize::Size8x8 ? 3 : 4);
|
||||||
uint tileWidth = (!hires ? tileHeight : 4);
|
uint tileWidth = (!hires ? tileHeight : 4);
|
||||||
|
|
||||||
uint width = 256 << hires;
|
uint width = 256 << hires;
|
||||||
|
|
||||||
uint hmask = (tileHeight == 3 ? width : width << 1);
|
uint hmask = (tileHeight == 3 ? width : width << 1);
|
||||||
uint vmask = hmask;
|
uint vmask = hmask;
|
||||||
if(r.screenSize & 1) hmask <<= 1;
|
if(io.screenSize & 1) hmask <<= 1;
|
||||||
if(r.screenSize & 2) vmask <<= 1;
|
if(io.screenSize & 2) vmask <<= 1;
|
||||||
hmask--;
|
hmask--;
|
||||||
vmask--;
|
vmask--;
|
||||||
|
|
||||||
uint px = x << hires;
|
uint px = x << hires;
|
||||||
uint py = (r.mosaic == 0 ? y : mosaic.voffset);
|
uint py = (io.mosaic == 0 ? y : mosaic.voffset);
|
||||||
|
|
||||||
uint hscroll = hoffset();
|
uint hscroll = hoffset();
|
||||||
uint vscroll = voffset();
|
uint vscroll = voffset();
|
||||||
if(hires) {
|
if(hires) {
|
||||||
hscroll <<= 1;
|
hscroll <<= 1;
|
||||||
if(ppu.r.interlace) py = (py << 1) + ppu.field();
|
if(ppu.io.interlace) py = (py << 1) + ppu.field();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint hoffset = hscroll + px;
|
uint hoffset = hscroll + px;
|
||||||
uint voffset = vscroll + py;
|
uint voffset = vscroll + py;
|
||||||
|
|
||||||
if(ppu.r.bgMode == 2 || ppu.r.bgMode == 4 || ppu.r.bgMode == 6) {
|
if(ppu.io.bgMode == 2 || ppu.io.bgMode == 4 || ppu.io.bgMode == 6) {
|
||||||
uint16 offsetX = (x + (hscroll & 7));
|
uint16 offsetX = (x + (hscroll & 7));
|
||||||
|
|
||||||
if(offsetX >= 8) {
|
if(offsetX >= 8) {
|
||||||
|
@ -91,7 +91,7 @@ auto PPU::Background::getTile() -> void {
|
||||||
uint vval = ppu.bg3.getTile((offsetX - 8) + (ppu.bg3.hoffset() & ~7), ppu.bg3.voffset() + 8);
|
uint vval = ppu.bg3.getTile((offsetX - 8) + (ppu.bg3.hoffset() & ~7), ppu.bg3.voffset() + 8);
|
||||||
uint validMask = (id == ID::BG1 ? 0x2000 : 0x4000);
|
uint validMask = (id == ID::BG1 ? 0x2000 : 0x4000);
|
||||||
|
|
||||||
if(ppu.r.bgMode == 4) {
|
if(ppu.io.bgMode == 4) {
|
||||||
if(hval & validMask) {
|
if(hval & validMask) {
|
||||||
if((hval & 0x8000) == 0) {
|
if((hval & 0x8000) == 0) {
|
||||||
hoffset = offsetX + (hval & ~7);
|
hoffset = offsetX + (hval & ~7);
|
||||||
|
@ -109,9 +109,9 @@ auto PPU::Background::getTile() -> void {
|
||||||
hoffset &= hmask;
|
hoffset &= hmask;
|
||||||
voffset &= vmask;
|
voffset &= vmask;
|
||||||
|
|
||||||
uint screenX = (r.screenSize & 1 ? 32 << 5 : 0);
|
uint screenX = (io.screenSize & 1 ? 32 << 5 : 0);
|
||||||
uint screenY = (r.screenSize & 2 ? 32 << 5 : 0);
|
uint screenY = (io.screenSize & 2 ? 32 << 5 : 0);
|
||||||
if(r.screenSize == 3) screenY <<= 1;
|
if(io.screenSize == 3) screenY <<= 1;
|
||||||
|
|
||||||
uint tx = hoffset >> tileWidth;
|
uint tx = hoffset >> tileWidth;
|
||||||
uint ty = voffset >> tileHeight;
|
uint ty = voffset >> tileHeight;
|
||||||
|
@ -120,11 +120,11 @@ auto PPU::Background::getTile() -> void {
|
||||||
if(tx & 0x20) offset += screenX;
|
if(tx & 0x20) offset += screenX;
|
||||||
if(ty & 0x20) offset += screenY;
|
if(ty & 0x20) offset += screenY;
|
||||||
|
|
||||||
uint16 address = r.screenAddress + offset;
|
uint16 address = io.screenAddress + offset;
|
||||||
tile = ppu.vram[address];
|
tile = ppu.vram[address];
|
||||||
bool mirrorY = tile & 0x8000;
|
bool mirrorY = tile & 0x8000;
|
||||||
bool mirrorX = tile & 0x4000;
|
bool mirrorX = tile & 0x4000;
|
||||||
priority = r.priority[bool(tile & 0x2000)];
|
priority = io.priority[bool(tile & 0x2000)];
|
||||||
paletteNumber = (tile >> 10) & 7;
|
paletteNumber = (tile >> 10) & 7;
|
||||||
paletteIndex = paletteOffset + (paletteNumber << paletteSize);
|
paletteIndex = paletteOffset + (paletteNumber << paletteSize);
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ auto PPU::Background::getTile() -> void {
|
||||||
if(mirrorY) voffset ^= 7;
|
if(mirrorY) voffset ^= 7;
|
||||||
offset = (character << (3 + colorDepth)) + (voffset & 7);
|
offset = (character << (3 + colorDepth)) + (voffset & 7);
|
||||||
|
|
||||||
switch(r.mode) {
|
switch(io.mode) {
|
||||||
case Mode::BPP8:
|
case Mode::BPP8:
|
||||||
data[1].bits(16,31) = ppu.vram[offset + 24];
|
data[1].bits(16,31) = ppu.vram[offset + 24];
|
||||||
data[1].bits( 0,15) = ppu.vram[offset + 16];
|
data[1].bits( 0,15) = ppu.vram[offset + 16];
|
||||||
|
@ -154,7 +154,7 @@ auto PPU::Background::getTile() -> void {
|
||||||
|
|
||||||
auto PPU::Background::run(bool screen) -> void {
|
auto PPU::Background::run(bool screen) -> void {
|
||||||
if(ppu.vcounter() == 0) return;
|
if(ppu.vcounter() == 0) return;
|
||||||
bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6);
|
bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
|
||||||
|
|
||||||
if(screen == Screen::Below) {
|
if(screen == Screen::Below) {
|
||||||
output.above.priority = 0;
|
output.above.priority = 0;
|
||||||
|
@ -167,12 +167,12 @@ auto PPU::Background::run(bool screen) -> void {
|
||||||
getTile();
|
getTile();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r.mode == Mode::Mode7) return runMode7();
|
if(io.mode == Mode::Mode7) return runMode7();
|
||||||
|
|
||||||
uint8 palette = getTileColor();
|
uint8 palette = getTileColor();
|
||||||
if(x == 0) mosaic.hcounter = 1;
|
if(x == 0) mosaic.hcounter = 1;
|
||||||
if(x >= 0 && --mosaic.hcounter == 0) {
|
if(x >= 0 && --mosaic.hcounter == 0) {
|
||||||
mosaic.hcounter = r.mosaic + 1;
|
mosaic.hcounter = io.mosaic + 1;
|
||||||
mosaic.priority = priority;
|
mosaic.priority = priority;
|
||||||
mosaic.palette = palette ? paletteIndex + palette : 0;
|
mosaic.palette = palette ? paletteIndex + palette : 0;
|
||||||
mosaic.tile = tile;
|
mosaic.tile = tile;
|
||||||
|
@ -180,14 +180,14 @@ auto PPU::Background::run(bool screen) -> void {
|
||||||
if(screen == Screen::Above) x++;
|
if(screen == Screen::Above) x++;
|
||||||
if(mosaic.palette == 0) return;
|
if(mosaic.palette == 0) return;
|
||||||
|
|
||||||
if(!hires || screen == Screen::Above) if(r.aboveEnable) output.above = mosaic;
|
if(!hires || screen == Screen::Above) if(io.aboveEnable) output.above = mosaic;
|
||||||
if(!hires || screen == Screen::Below) if(r.belowEnable) output.below = mosaic;
|
if(!hires || screen == Screen::Below) if(io.belowEnable) output.below = mosaic;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Background::getTileColor() -> uint {
|
auto PPU::Background::getTileColor() -> uint {
|
||||||
uint color = 0;
|
uint color = 0;
|
||||||
|
|
||||||
switch(r.mode) {
|
switch(io.mode) {
|
||||||
case Mode::BPP8:
|
case Mode::BPP8:
|
||||||
color += data[1] >> 24 & 0x80;
|
color += data[1] >> 24 & 0x80;
|
||||||
color += data[1] >> 17 & 0x40;
|
color += data[1] >> 17 & 0x40;
|
||||||
|
@ -207,17 +207,17 @@ auto PPU::Background::getTileColor() -> uint {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Background::reset() -> void {
|
auto PPU::Background::reset() -> void {
|
||||||
r.tiledataAddress = (random(0x0000) & 0x0f) << 12;
|
io.tiledataAddress = (random(0x0000) & 0x0f) << 12;
|
||||||
r.screenAddress = (random(0x0000) & 0xfc) << 8;
|
io.screenAddress = (random(0x0000) & 0xfc) << 8;
|
||||||
r.screenSize = random(0);
|
io.screenSize = random(0);
|
||||||
r.mosaic = random(0);
|
io.mosaic = random(0);
|
||||||
r.tileSize = random(0);
|
io.tileSize = random(0);
|
||||||
r.mode = 0;
|
io.mode = 0;
|
||||||
for(auto& p : r.priority) p = 0;
|
for(auto& p : io.priority) p = 0;
|
||||||
r.aboveEnable = random(0);
|
io.aboveEnable = random(0);
|
||||||
r.belowEnable = random(0);
|
io.belowEnable = random(0);
|
||||||
r.hoffset = random(0x0000);
|
io.hoffset = random(0x0000);
|
||||||
r.voffset = random(0x0000);
|
io.voffset = random(0x0000);
|
||||||
|
|
||||||
latch.hoffset = 0;
|
latch.hoffset = 0;
|
||||||
latch.voffset = 0;
|
latch.voffset = 0;
|
||||||
|
@ -248,20 +248,20 @@ auto PPU::Background::reset() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Background::getTile(uint x, uint y) -> uint {
|
auto PPU::Background::getTile(uint x, uint y) -> uint {
|
||||||
bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6);
|
bool hires = (ppu.io.bgMode == 5 || ppu.io.bgMode == 6);
|
||||||
uint tileHeight = (r.tileSize == TileSize::Size8x8 ? 3 : 4);
|
uint tileHeight = (io.tileSize == TileSize::Size8x8 ? 3 : 4);
|
||||||
uint tileWidth = (!hires ? tileHeight : 4);
|
uint tileWidth = (!hires ? tileHeight : 4);
|
||||||
uint width = (!hires ? 256 : 512);
|
uint width = (!hires ? 256 : 512);
|
||||||
uint maskX = (tileHeight == 3 ? width : width << 1);
|
uint maskX = (tileHeight == 3 ? width : width << 1);
|
||||||
uint maskY = maskX;
|
uint maskY = maskX;
|
||||||
if(r.screenSize & 1) maskX <<= 1;
|
if(io.screenSize & 1) maskX <<= 1;
|
||||||
if(r.screenSize & 2) maskY <<= 1;
|
if(io.screenSize & 2) maskY <<= 1;
|
||||||
maskX--;
|
maskX--;
|
||||||
maskY--;
|
maskY--;
|
||||||
|
|
||||||
uint screenX = (r.screenSize & 1 ? 32 << 5 : 0);
|
uint screenX = (io.screenSize & 1 ? 32 << 5 : 0);
|
||||||
uint screenY = (r.screenSize & 2 ? 32 << 5 : 0);
|
uint screenY = (io.screenSize & 2 ? 32 << 5 : 0);
|
||||||
if(r.screenSize == 3) screenY <<= 1;
|
if(io.screenSize == 3) screenY <<= 1;
|
||||||
|
|
||||||
x = (x & maskX) >> tileWidth;
|
x = (x & maskX) >> tileWidth;
|
||||||
y = (y & maskY) >> tileHeight;
|
y = (y & maskY) >> tileHeight;
|
||||||
|
@ -270,6 +270,6 @@ auto PPU::Background::getTile(uint x, uint y) -> uint {
|
||||||
if(x & 0x20) offset += screenX;
|
if(x & 0x20) offset += screenX;
|
||||||
if(y & 0x20) offset += screenY;
|
if(y & 0x20) offset += screenY;
|
||||||
|
|
||||||
uint16 address = r.screenAddress + offset;
|
uint16 address = io.screenAddress + offset;
|
||||||
return ppu.vram[address];
|
return ppu.vram[address];
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ struct Background {
|
||||||
struct TileSize { enum : uint { Size8x8, Size16x16 }; };
|
struct TileSize { enum : uint { Size8x8, Size16x16 }; };
|
||||||
struct Screen { enum : uint { Above, Below }; };
|
struct Screen { enum : uint { Above, Below }; };
|
||||||
|
|
||||||
struct Registers {
|
struct IO {
|
||||||
uint16 tiledataAddress;
|
uint16 tiledataAddress;
|
||||||
uint16 screenAddress;
|
uint16 screenAddress;
|
||||||
uint2 screenSize;
|
uint2 screenSize;
|
||||||
|
@ -42,7 +42,7 @@ struct Background {
|
||||||
|
|
||||||
uint16 hoffset;
|
uint16 hoffset;
|
||||||
uint16 voffset;
|
uint16 voffset;
|
||||||
} r;
|
} io;
|
||||||
|
|
||||||
struct Latch {
|
struct Latch {
|
||||||
uint16 hoffset;
|
uint16 hoffset;
|
||||||
|
|
|
@ -5,18 +5,18 @@ auto PPU::Background::clip(int n) -> int {
|
||||||
|
|
||||||
//H = 28
|
//H = 28
|
||||||
auto PPU::Background::beginMode7() -> void {
|
auto PPU::Background::beginMode7() -> void {
|
||||||
latch.hoffset = ppu.r.hoffsetMode7;
|
latch.hoffset = ppu.io.hoffsetMode7;
|
||||||
latch.voffset = ppu.r.voffsetMode7;
|
latch.voffset = ppu.io.voffsetMode7;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Background::runMode7() -> void {
|
auto PPU::Background::runMode7() -> void {
|
||||||
int a = (int16)ppu.r.m7a;
|
int a = (int16)ppu.io.m7a;
|
||||||
int b = (int16)ppu.r.m7b;
|
int b = (int16)ppu.io.m7b;
|
||||||
int c = (int16)ppu.r.m7c;
|
int c = (int16)ppu.io.m7c;
|
||||||
int d = (int16)ppu.r.m7d;
|
int d = (int16)ppu.io.m7d;
|
||||||
|
|
||||||
int cx = (int13)ppu.r.m7x;
|
int cx = (int13)ppu.io.m7x;
|
||||||
int cy = (int13)ppu.r.m7y;
|
int cy = (int13)ppu.io.m7y;
|
||||||
int hoffset = (int13)latch.hoffset;
|
int hoffset = (int13)latch.hoffset;
|
||||||
int voffset = (int13)latch.voffset;
|
int voffset = (int13)latch.voffset;
|
||||||
|
|
||||||
|
@ -25,12 +25,12 @@ auto PPU::Background::runMode7() -> void {
|
||||||
uint y = ppu.bg1.mosaic.voffset; //BG2 vertical mosaic uses BG1 mosaic size
|
uint y = ppu.bg1.mosaic.voffset; //BG2 vertical mosaic uses BG1 mosaic size
|
||||||
|
|
||||||
if(--mosaic.hcounter == 0) {
|
if(--mosaic.hcounter == 0) {
|
||||||
mosaic.hcounter = r.mosaic + 1;
|
mosaic.hcounter = io.mosaic + 1;
|
||||||
mosaic.hoffset += r.mosaic + 1;
|
mosaic.hoffset += io.mosaic + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ppu.r.hflipMode7) x = 255 - x;
|
if(ppu.io.hflipMode7) x = 255 - x;
|
||||||
if(ppu.r.vflipMode7) y = 255 - y;
|
if(ppu.io.vflipMode7) y = 255 - y;
|
||||||
|
|
||||||
int psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * y) & ~63) + (cx << 8);
|
int psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * y) & ~63) + (cx << 8);
|
||||||
int psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * y) & ~63) + (cy << 8);
|
int psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * y) & ~63) + (cy << 8);
|
||||||
|
@ -44,7 +44,7 @@ auto PPU::Background::runMode7() -> void {
|
||||||
|
|
||||||
uint tile;
|
uint tile;
|
||||||
uint palette;
|
uint palette;
|
||||||
switch(ppu.r.repeatMode7) {
|
switch(ppu.io.repeatMode7) {
|
||||||
//screen repetition outside of screen area
|
//screen repetition outside of screen area
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -81,21 +81,21 @@ auto PPU::Background::runMode7() -> void {
|
||||||
|
|
||||||
uint priority;
|
uint priority;
|
||||||
if(id == ID::BG1) {
|
if(id == ID::BG1) {
|
||||||
priority = r.priority[0];
|
priority = io.priority[0];
|
||||||
} else if(id == ID::BG2) {
|
} else if(id == ID::BG2) {
|
||||||
priority = r.priority[bool(palette & 0x80)];
|
priority = io.priority[bool(palette & 0x80)];
|
||||||
palette &= 0x7f;
|
palette &= 0x7f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(palette == 0) return;
|
if(palette == 0) return;
|
||||||
|
|
||||||
if(r.aboveEnable) {
|
if(io.aboveEnable) {
|
||||||
output.above.palette = palette;
|
output.above.palette = palette;
|
||||||
output.above.priority = priority;
|
output.above.priority = priority;
|
||||||
output.above.tile = 0;
|
output.above.tile = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r.belowEnable) {
|
if(io.belowEnable) {
|
||||||
output.below.palette = palette;
|
output.below.palette = palette;
|
||||||
output.below.priority = priority;
|
output.below.priority = priority;
|
||||||
output.below.tile = 0;
|
output.below.tile = 0;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
auto PPU::getVramAddress() -> uint16 {
|
auto PPU::getVramAddress() -> uint16 {
|
||||||
uint16 address = r.vramAddress;
|
uint16 address = io.vramAddress;
|
||||||
switch(r.vramMapping) {
|
switch(io.vramMapping) {
|
||||||
case 0: return (address);
|
case 0: return (address);
|
||||||
case 1: return (address & 0xff00) | ((address & 0x001f) << 3) | ((address >> 5) & 7);
|
case 1: return (address & 0xff00) | ((address & 0x001f) << 3) | ((address >> 5) & 7);
|
||||||
case 2: return (address & 0xfe00) | ((address & 0x003f) << 3) | ((address >> 6) & 7);
|
case 2: return (address & 0xfe00) | ((address & 0x003f) << 3) | ((address >> 6) & 7);
|
||||||
|
@ -10,12 +10,11 @@ auto PPU::getVramAddress() -> uint16 {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::vramAccessible() const -> bool {
|
auto PPU::vramAccessible() const -> bool {
|
||||||
return r.displayDisable || vcounter() >= vdisp();
|
return io.displayDisable || vcounter() >= vdisp();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::oamWrite(uint addr, uint8 data) -> void {
|
auto PPU::oamWrite(uint addr, uint8 data) -> void {
|
||||||
oam[addr] = data;
|
obj.oam.write(addr, data);
|
||||||
obj.update(addr, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
||||||
|
@ -33,21 +32,21 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
||||||
|
|
||||||
//MPYL
|
//MPYL
|
||||||
case 0x2134: {
|
case 0x2134: {
|
||||||
uint result = (int16)r.m7a * (int8)(r.m7b >> 8);
|
uint result = (int16)io.m7a * (int8)(io.m7b >> 8);
|
||||||
ppu1.mdr = (result >> 0);
|
ppu1.mdr = (result >> 0);
|
||||||
return ppu1.mdr;
|
return ppu1.mdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//MPYM
|
//MPYM
|
||||||
case 0x2135: {
|
case 0x2135: {
|
||||||
uint result = (int16)r.m7a * (int8)(r.m7b >> 8);
|
uint result = (int16)io.m7a * (int8)(io.m7b >> 8);
|
||||||
ppu1.mdr = (result >> 8);
|
ppu1.mdr = (result >> 8);
|
||||||
return ppu1.mdr;
|
return ppu1.mdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//MPYH
|
//MPYH
|
||||||
case 0x2136: {
|
case 0x2136: {
|
||||||
uint result = (int16)r.m7a * (int8)(r.m7b >> 8);
|
uint result = (int16)io.m7a * (int8)(io.m7b >> 8);
|
||||||
ppu1.mdr = (result >> 16);
|
ppu1.mdr = (result >> 16);
|
||||||
return ppu1.mdr;
|
return ppu1.mdr;
|
||||||
}
|
}
|
||||||
|
@ -55,16 +54,16 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
||||||
//SLHV
|
//SLHV
|
||||||
case 0x2137: {
|
case 0x2137: {
|
||||||
if(cpu.pio() & 0x80) latchCounters();
|
if(cpu.pio() & 0x80) latchCounters();
|
||||||
return cpu.r.mdr;
|
return data; //CPU MDR
|
||||||
}
|
}
|
||||||
|
|
||||||
//OAMDATAREAD
|
//OAMDATAREAD
|
||||||
case 0x2138: {
|
case 0x2138: {
|
||||||
uint10 address = r.oamAddress++;
|
uint10 address = io.oamAddress++;
|
||||||
if(!r.displayDisable && vcounter() < vdisp()) address = latch.oamAddress;
|
if(!io.displayDisable && vcounter() < vdisp()) address = latch.oamAddress;
|
||||||
if(address & 0x0200) address &= 0x021f;
|
if(address & 0x0200) address &= 0x021f;
|
||||||
|
|
||||||
ppu1.mdr = oam[address];
|
ppu1.mdr = obj.oam.read(address);
|
||||||
obj.setFirstSprite();
|
obj.setFirstSprite();
|
||||||
return ppu1.mdr;
|
return ppu1.mdr;
|
||||||
}
|
}
|
||||||
|
@ -72,9 +71,9 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
||||||
//VMDATALREAD
|
//VMDATALREAD
|
||||||
case 0x2139: {
|
case 0x2139: {
|
||||||
ppu1.mdr = latch.vram >> 0;
|
ppu1.mdr = latch.vram >> 0;
|
||||||
if(r.vramIncrementMode == 0) {
|
if(io.vramIncrementMode == 0) {
|
||||||
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
||||||
r.vramAddress += r.vramIncrementSize;
|
io.vramAddress += io.vramIncrementSize;
|
||||||
}
|
}
|
||||||
return ppu1.mdr;
|
return ppu1.mdr;
|
||||||
}
|
}
|
||||||
|
@ -82,26 +81,26 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
||||||
//VMDATAHREAD
|
//VMDATAHREAD
|
||||||
case 0x213a: {
|
case 0x213a: {
|
||||||
ppu1.mdr = latch.vram >> 8;
|
ppu1.mdr = latch.vram >> 8;
|
||||||
if(r.vramIncrementMode == 1) {
|
if(io.vramIncrementMode == 1) {
|
||||||
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
||||||
r.vramAddress += r.vramIncrementSize;
|
io.vramAddress += io.vramIncrementSize;
|
||||||
}
|
}
|
||||||
return ppu1.mdr;
|
return ppu1.mdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//CGDATAREAD
|
//CGDATAREAD
|
||||||
case 0x213b: {
|
case 0x213b: {
|
||||||
auto address = r.cgramAddress;
|
auto address = io.cgramAddress;
|
||||||
if(!r.displayDisable
|
if(!io.displayDisable
|
||||||
&& vcounter() > 0 && vcounter() < vdisp()
|
&& vcounter() > 0 && vcounter() < vdisp()
|
||||||
&& hcounter() >= 88 && hcounter() < 1096
|
&& hcounter() >= 88 && hcounter() < 1096
|
||||||
) address = latch.cgramAddress;
|
) address = latch.cgramAddress;
|
||||||
|
|
||||||
if(r.cgramAddressLatch++) {
|
if(io.cgramAddressLatch++) {
|
||||||
ppu2.mdr = cgram[address].byte(0);
|
ppu2.mdr = screen.cgram[address].byte(0);
|
||||||
} else {
|
} else {
|
||||||
ppu2.mdr &= 0x80;
|
ppu2.mdr &= 0x80;
|
||||||
ppu2.mdr |= cgram[address].byte(1);
|
ppu2.mdr |= screen.cgram[address].byte(1);
|
||||||
}
|
}
|
||||||
return ppu2.mdr;
|
return ppu2.mdr;
|
||||||
}
|
}
|
||||||
|
@ -109,10 +108,10 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
||||||
//OPHCT
|
//OPHCT
|
||||||
case 0x213c: {
|
case 0x213c: {
|
||||||
if(latch.hcounter == 0) {
|
if(latch.hcounter == 0) {
|
||||||
ppu2.mdr = (r.hcounter >> 0);
|
ppu2.mdr = (io.hcounter >> 0);
|
||||||
} else {
|
} else {
|
||||||
ppu2.mdr &= 0xfe;
|
ppu2.mdr &= 0xfe;
|
||||||
ppu2.mdr |= (r.hcounter >> 8) & 1;
|
ppu2.mdr |= (io.hcounter >> 8) & 1;
|
||||||
}
|
}
|
||||||
latch.hcounter ^= 1;
|
latch.hcounter ^= 1;
|
||||||
return ppu2.mdr;
|
return ppu2.mdr;
|
||||||
|
@ -121,10 +120,10 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
||||||
//OPVCT
|
//OPVCT
|
||||||
case 0x213d: {
|
case 0x213d: {
|
||||||
if(latch.vcounter == 0) {
|
if(latch.vcounter == 0) {
|
||||||
ppu2.mdr = (r.vcounter >> 0);
|
ppu2.mdr = (io.vcounter >> 0);
|
||||||
} else {
|
} else {
|
||||||
ppu2.mdr &= 0xfe;
|
ppu2.mdr &= 0xfe;
|
||||||
ppu2.mdr |= (r.vcounter >> 8) & 1;
|
ppu2.mdr |= (io.vcounter >> 8) & 1;
|
||||||
}
|
}
|
||||||
latch.vcounter ^= 1;
|
latch.vcounter ^= 1;
|
||||||
return ppu2.mdr;
|
return ppu2.mdr;
|
||||||
|
@ -133,8 +132,8 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
||||||
//STAT77
|
//STAT77
|
||||||
case 0x213e: {
|
case 0x213e: {
|
||||||
ppu1.mdr &= 0x10;
|
ppu1.mdr &= 0x10;
|
||||||
ppu1.mdr |= obj.r.timeOver << 7;
|
ppu1.mdr |= obj.io.timeOver << 7;
|
||||||
ppu1.mdr |= obj.r.rangeOver << 6;
|
ppu1.mdr |= obj.io.rangeOver << 6;
|
||||||
ppu1.mdr |= ppu1.version & 0x0f;
|
ppu1.mdr |= ppu1.version & 0x0f;
|
||||||
return ppu1.mdr;
|
return ppu1.mdr;
|
||||||
}
|
}
|
||||||
|
@ -169,40 +168,40 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
|
||||||
|
|
||||||
//INIDISP
|
//INIDISP
|
||||||
case 0x2100: {
|
case 0x2100: {
|
||||||
if(r.displayDisable && vcounter() == vdisp()) obj.addressReset();
|
if(io.displayDisable && vcounter() == vdisp()) obj.addressReset();
|
||||||
r.displayBrightness = data.bits(0,3);
|
io.displayBrightness = data.bits(0,3);
|
||||||
r.displayDisable = data.bit (7);
|
io.displayDisable = data.bit (7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//OBSEL
|
//OBSEL
|
||||||
case 0x2101: {
|
case 0x2101: {
|
||||||
obj.r.tiledataAddress = data.bits(0,2) << 13;
|
obj.io.tiledataAddress = data.bits(0,2) << 13;
|
||||||
obj.r.nameSelect = data.bits(3,4);
|
obj.io.nameselect = data.bits(3,4);
|
||||||
obj.r.baseSize = data.bits(5,7);
|
obj.io.baseSize = data.bits(5,7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//OAMADDL
|
//OAMADDL
|
||||||
case 0x2102: {
|
case 0x2102: {
|
||||||
r.oamBaseAddress = (r.oamBaseAddress & 0x0200) | (data << 1);
|
io.oamBaseAddress = (io.oamBaseAddress & 0x0200) | (data << 1);
|
||||||
obj.addressReset();
|
obj.addressReset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//OAMADDH
|
//OAMADDH
|
||||||
case 0x2103: {
|
case 0x2103: {
|
||||||
r.oamPriority = data & 0x80;
|
io.oamPriority = data & 0x80;
|
||||||
r.oamBaseAddress = ((data & 0x01) << 9) | (r.oamBaseAddress & 0x01fe);
|
io.oamBaseAddress = ((data & 0x01) << 9) | (io.oamBaseAddress & 0x01fe);
|
||||||
obj.addressReset();
|
obj.addressReset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//OAMDATA
|
//OAMDATA
|
||||||
case 0x2104: {
|
case 0x2104: {
|
||||||
bool l = r.oamAddress & 1;
|
bool l = io.oamAddress & 1;
|
||||||
uint10 address = r.oamAddress++;
|
uint10 address = io.oamAddress++;
|
||||||
if(!r.displayDisable && vcounter() < vdisp()) address = latch.oamAddress;
|
if(!io.displayDisable && vcounter() < vdisp()) address = latch.oamAddress;
|
||||||
if(address & 0x0200) address &= 0x021f;
|
if(address & 0x0200) address &= 0x021f;
|
||||||
|
|
||||||
if(l == 0) latch.oam = data;
|
if(l == 0) latch.oam = data;
|
||||||
|
@ -218,12 +217,12 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
|
||||||
|
|
||||||
//BGMODE
|
//BGMODE
|
||||||
case 0x2105: {
|
case 0x2105: {
|
||||||
r.bgMode = data.bits(0,2);
|
io.bgMode = data.bits(0,2);
|
||||||
r.bgPriority = data.bit (3);
|
io.bgPriority = data.bit (3);
|
||||||
bg1.r.tileSize = data.bit (4);
|
bg1.io.tileSize = data.bit (4);
|
||||||
bg2.r.tileSize = data.bit (5);
|
bg2.io.tileSize = data.bit (5);
|
||||||
bg3.r.tileSize = data.bit (6);
|
bg3.io.tileSize = data.bit (6);
|
||||||
bg4.r.tileSize = data.bit (7);
|
bg4.io.tileSize = data.bit (7);
|
||||||
updateVideoMode();
|
updateVideoMode();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -231,140 +230,136 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
|
||||||
//MOSAIC
|
//MOSAIC
|
||||||
case 0x2106: {
|
case 0x2106: {
|
||||||
uint mosaicSize = data.bits(4,7);
|
uint mosaicSize = data.bits(4,7);
|
||||||
bg1.r.mosaic = data.bit(0) ? mosaicSize : 0;
|
bg1.io.mosaic = data.bit(0) ? mosaicSize : 0;
|
||||||
bg2.r.mosaic = data.bit(1) ? mosaicSize : 0;
|
bg2.io.mosaic = data.bit(1) ? mosaicSize : 0;
|
||||||
bg3.r.mosaic = data.bit(2) ? mosaicSize : 0;
|
bg3.io.mosaic = data.bit(2) ? mosaicSize : 0;
|
||||||
bg4.r.mosaic = data.bit(3) ? mosaicSize : 0;
|
bg4.io.mosaic = data.bit(3) ? mosaicSize : 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG1SC
|
//BG1SC
|
||||||
case 0x2107: {
|
case 0x2107: {
|
||||||
bg1.r.screenSize = data.bits(0,1);
|
bg1.io.screenSize = data.bits(0,1);
|
||||||
bg1.r.screenAddress = data.bits(2,7) << 10;
|
bg1.io.screenAddress = data.bits(2,7) << 10;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG2SC
|
//BG2SC
|
||||||
case 0x2108: {
|
case 0x2108: {
|
||||||
bg2.r.screenSize = data.bits(0,1);
|
bg2.io.screenSize = data.bits(0,1);
|
||||||
bg2.r.screenAddress = data.bits(2,7) << 10;
|
bg2.io.screenAddress = data.bits(2,7) << 10;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG3SC
|
//BG3SC
|
||||||
case 0x2109: {
|
case 0x2109: {
|
||||||
bg3.r.screenSize = data.bits(0,1);
|
bg3.io.screenSize = data.bits(0,1);
|
||||||
bg3.r.screenAddress = data.bits(2,7) << 10;
|
bg3.io.screenAddress = data.bits(2,7) << 10;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG4SC
|
//BG4SC
|
||||||
case 0x210a: {
|
case 0x210a: {
|
||||||
bg4.r.screenSize = data.bits(0,1);
|
bg4.io.screenSize = data.bits(0,1);
|
||||||
bg4.r.screenAddress = data.bits(2,7) << 10;
|
bg4.io.screenAddress = data.bits(2,7) << 10;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG12NBA
|
//BG12NBA
|
||||||
case 0x210b: {
|
case 0x210b: {
|
||||||
bg1.r.tiledataAddress = data.bits(0,3) << 12;
|
bg1.io.tiledataAddress = data.bits(0,3) << 12;
|
||||||
bg2.r.tiledataAddress = data.bits(4,7) << 12;
|
bg2.io.tiledataAddress = data.bits(4,7) << 12;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG34NBA
|
//BG34NBA
|
||||||
case 0x210c: {
|
case 0x210c: {
|
||||||
bg3.r.tiledataAddress = data.bits(0,3) << 12;
|
bg3.io.tiledataAddress = data.bits(0,3) << 12;
|
||||||
bg4.r.tiledataAddress = data.bits(4,7) << 12;
|
bg4.io.tiledataAddress = data.bits(4,7) << 12;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG1HOFS
|
//BG1HOFS
|
||||||
case 0x210d: {
|
case 0x210d: {
|
||||||
r.hoffsetMode7 = (data << 8) | latch.mode7;
|
io.hoffsetMode7 = (data << 8) | latch.mode7;
|
||||||
latch.mode7 = data;
|
latch.mode7 = data;
|
||||||
|
|
||||||
bg1.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg1.r.hoffset >> 8) & 7);
|
bg1.io.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg1.io.hoffset >> 8) & 7);
|
||||||
latch.bgofs = data;
|
latch.bgofs = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG1VOFS
|
//BG1VOFS
|
||||||
case 0x210e: {
|
case 0x210e: {
|
||||||
r.voffsetMode7 = (data << 8) | latch.mode7;
|
io.voffsetMode7 = (data << 8) | latch.mode7;
|
||||||
latch.mode7 = data;
|
latch.mode7 = data;
|
||||||
|
|
||||||
bg1.r.voffset = (data << 8) | latch.bgofs;
|
bg1.io.voffset = (data << 8) | latch.bgofs;
|
||||||
latch.bgofs = data;
|
latch.bgofs = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG2HOFS
|
//BG2HOFS
|
||||||
case 0x210f: {
|
case 0x210f: {
|
||||||
bg2.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg2.r.hoffset >> 8) & 7);
|
bg2.io.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg2.io.hoffset >> 8) & 7);
|
||||||
latch.bgofs = data;
|
latch.bgofs = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG2VOFS
|
//BG2VOFS
|
||||||
case 0x2110: {
|
case 0x2110: {
|
||||||
bg2.r.voffset = (data << 8) | latch.bgofs;
|
bg2.io.voffset = (data << 8) | latch.bgofs;
|
||||||
latch.bgofs = data;
|
latch.bgofs = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG3HOFS
|
//BG3HOFS
|
||||||
case 0x2111: {
|
case 0x2111: {
|
||||||
bg3.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg3.r.hoffset >> 8) & 7);
|
bg3.io.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg3.io.hoffset >> 8) & 7);
|
||||||
latch.bgofs = data;
|
latch.bgofs = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG3VOFS
|
//BG3VOFS
|
||||||
case 0x2112: {
|
case 0x2112: {
|
||||||
bg3.r.voffset = (data << 8) | latch.bgofs;
|
bg3.io.voffset = (data << 8) | latch.bgofs;
|
||||||
latch.bgofs = data;
|
latch.bgofs = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG4HOFS
|
//BG4HOFS
|
||||||
case 0x2113: {
|
case 0x2113: {
|
||||||
bg4.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg4.r.hoffset >> 8) & 7);
|
bg4.io.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg4.io.hoffset >> 8) & 7);
|
||||||
latch.bgofs = data;
|
latch.bgofs = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BG4VOFS
|
//BG4VOFS
|
||||||
case 0x2114: {
|
case 0x2114: {
|
||||||
bg4.r.voffset = (data << 8) | latch.bgofs;
|
bg4.io.voffset = (data << 8) | latch.bgofs;
|
||||||
latch.bgofs = data;
|
latch.bgofs = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//VMAIN
|
//VMAIN
|
||||||
case 0x2115: {
|
case 0x2115: {
|
||||||
r.vramIncrementMode = data & 0x80;
|
static const uint size[4] = {1, 32, 128, 128};
|
||||||
r.vramMapping = (data >> 2) & 3;
|
io.vramIncrementSize = size[data.bits(0,1)];
|
||||||
switch(data & 3) {
|
io.vramMapping = data.bits(2,3);
|
||||||
case 0: r.vramIncrementSize = 1; break;
|
io.vramIncrementMode = data.bit (7);
|
||||||
case 1: r.vramIncrementSize = 32; break;
|
|
||||||
case 2: r.vramIncrementSize = 128; break;
|
|
||||||
case 3: r.vramIncrementSize = 128; break;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//VMADDL
|
//VMADDL
|
||||||
case 0x2116: {
|
case 0x2116: {
|
||||||
r.vramAddress.byte(0) = data;
|
io.vramAddress.byte(0) = data;
|
||||||
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//VMADDH
|
//VMADDH
|
||||||
case 0x2117: {
|
case 0x2117: {
|
||||||
r.vramAddress.byte(1) = data;
|
io.vramAddress.byte(1) = data;
|
||||||
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -372,247 +367,247 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
|
||||||
//VMDATAL
|
//VMDATAL
|
||||||
case 0x2118: {
|
case 0x2118: {
|
||||||
if(vramAccessible()) vram[getVramAddress()].byte(0) = data;
|
if(vramAccessible()) vram[getVramAddress()].byte(0) = data;
|
||||||
if(r.vramIncrementMode == 0) r.vramAddress += r.vramIncrementSize;
|
if(io.vramIncrementMode == 0) io.vramAddress += io.vramIncrementSize;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//VMDATAH
|
//VMDATAH
|
||||||
case 0x2119: {
|
case 0x2119: {
|
||||||
if(vramAccessible()) vram[getVramAddress()].byte(1) = data;
|
if(vramAccessible()) vram[getVramAddress()].byte(1) = data;
|
||||||
if(r.vramIncrementMode == 1) r.vramAddress += r.vramIncrementSize;
|
if(io.vramIncrementMode == 1) io.vramAddress += io.vramIncrementSize;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//M7SEL
|
//M7SEL
|
||||||
case 0x211a: {
|
case 0x211a: {
|
||||||
r.hflipMode7 = data.bit (0);
|
io.hflipMode7 = data.bit (0);
|
||||||
r.vflipMode7 = data.bit (1);
|
io.vflipMode7 = data.bit (1);
|
||||||
r.repeatMode7 = data.bits(6,7);
|
io.repeatMode7 = data.bits(6,7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//M7A
|
//M7A
|
||||||
case 0x211b: {
|
case 0x211b: {
|
||||||
r.m7a = data << 8 | latch.mode7;
|
io.m7a = data << 8 | latch.mode7;
|
||||||
latch.mode7 = data;
|
latch.mode7 = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//M7B
|
//M7B
|
||||||
case 0x211c: {
|
case 0x211c: {
|
||||||
r.m7b = data << 8 | latch.mode7;
|
io.m7b = data << 8 | latch.mode7;
|
||||||
latch.mode7 = data;
|
latch.mode7 = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//M7C
|
//M7C
|
||||||
case 0x211d: {
|
case 0x211d: {
|
||||||
r.m7c = data << 8 | latch.mode7;
|
io.m7c = data << 8 | latch.mode7;
|
||||||
latch.mode7 = data;
|
latch.mode7 = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//M7D
|
//M7D
|
||||||
case 0x211e: {
|
case 0x211e: {
|
||||||
r.m7d = data << 8 | latch.mode7;
|
io.m7d = data << 8 | latch.mode7;
|
||||||
latch.mode7 = data;
|
latch.mode7 = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//M7X
|
//M7X
|
||||||
case 0x211f: {
|
case 0x211f: {
|
||||||
r.m7x = data << 8 | latch.mode7;
|
io.m7x = data << 8 | latch.mode7;
|
||||||
latch.mode7 = data;
|
latch.mode7 = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//M7Y
|
//M7Y
|
||||||
case 0x2120: {
|
case 0x2120: {
|
||||||
r.m7y = data << 8 | latch.mode7;
|
io.m7y = data << 8 | latch.mode7;
|
||||||
latch.mode7 = data;
|
latch.mode7 = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//CGADD
|
//CGADD
|
||||||
case 0x2121: {
|
case 0x2121: {
|
||||||
r.cgramAddress = data;
|
io.cgramAddress = data;
|
||||||
r.cgramAddressLatch = 0;
|
io.cgramAddressLatch = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//CGDATA
|
//CGDATA
|
||||||
case 0x2122: {
|
case 0x2122: {
|
||||||
auto address = r.cgramAddress;
|
auto address = io.cgramAddress;
|
||||||
if(!r.displayDisable
|
if(!io.displayDisable
|
||||||
&& vcounter() > 0 && vcounter() < vdisp()
|
&& vcounter() > 0 && vcounter() < vdisp()
|
||||||
&& hcounter() >= 88 && hcounter() < 1096
|
&& hcounter() >= 88 && hcounter() < 1096
|
||||||
) address = latch.cgramAddress;
|
) address = latch.cgramAddress;
|
||||||
|
|
||||||
if(r.cgramAddressLatch++ == 0) {
|
if(io.cgramAddressLatch++ == 0) {
|
||||||
latch.cgram = data;
|
latch.cgram = data;
|
||||||
} else {
|
} else {
|
||||||
cgram[address] = data.bits(0,6) << 8 | latch.cgram;
|
screen.cgram[address] = data.bits(0,6) << 8 | latch.cgram;
|
||||||
r.cgramAddress++;
|
io.cgramAddress++;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//W12SEL
|
//W12SEL
|
||||||
case 0x2123: {
|
case 0x2123: {
|
||||||
window.r.bg1.oneInvert = data.bit(0);
|
window.io.bg1.oneInvert = data.bit(0);
|
||||||
window.r.bg1.oneEnable = data.bit(1);
|
window.io.bg1.oneEnable = data.bit(1);
|
||||||
window.r.bg1.twoInvert = data.bit(2);
|
window.io.bg1.twoInvert = data.bit(2);
|
||||||
window.r.bg1.twoEnable = data.bit(3);
|
window.io.bg1.twoEnable = data.bit(3);
|
||||||
window.r.bg2.oneInvert = data.bit(4);
|
window.io.bg2.oneInvert = data.bit(4);
|
||||||
window.r.bg2.oneEnable = data.bit(5);
|
window.io.bg2.oneEnable = data.bit(5);
|
||||||
window.r.bg2.twoInvert = data.bit(6);
|
window.io.bg2.twoInvert = data.bit(6);
|
||||||
window.r.bg2.twoEnable = data.bit(7);
|
window.io.bg2.twoEnable = data.bit(7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//W34SEL
|
//W34SEL
|
||||||
case 0x2124: {
|
case 0x2124: {
|
||||||
window.r.bg3.oneInvert = data.bit(0);
|
window.io.bg3.oneInvert = data.bit(0);
|
||||||
window.r.bg3.oneEnable = data.bit(1);
|
window.io.bg3.oneEnable = data.bit(1);
|
||||||
window.r.bg3.twoInvert = data.bit(2);
|
window.io.bg3.twoInvert = data.bit(2);
|
||||||
window.r.bg3.twoEnable = data.bit(3);
|
window.io.bg3.twoEnable = data.bit(3);
|
||||||
window.r.bg4.oneInvert = data.bit(4);
|
window.io.bg4.oneInvert = data.bit(4);
|
||||||
window.r.bg4.oneEnable = data.bit(5);
|
window.io.bg4.oneEnable = data.bit(5);
|
||||||
window.r.bg4.twoInvert = data.bit(6);
|
window.io.bg4.twoInvert = data.bit(6);
|
||||||
window.r.bg4.twoEnable = data.bit(7);
|
window.io.bg4.twoEnable = data.bit(7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//WOBJSEL
|
//WOBJSEL
|
||||||
case 0x2125: {
|
case 0x2125: {
|
||||||
window.r.obj.oneInvert = data.bit(0);
|
window.io.obj.oneInvert = data.bit(0);
|
||||||
window.r.obj.oneEnable = data.bit(1);
|
window.io.obj.oneEnable = data.bit(1);
|
||||||
window.r.obj.twoInvert = data.bit(2);
|
window.io.obj.twoInvert = data.bit(2);
|
||||||
window.r.obj.twoEnable = data.bit(3);
|
window.io.obj.twoEnable = data.bit(3);
|
||||||
window.r.col.oneInvert = data.bit(4);
|
window.io.col.oneInvert = data.bit(4);
|
||||||
window.r.col.oneEnable = data.bit(5);
|
window.io.col.oneEnable = data.bit(5);
|
||||||
window.r.col.twoInvert = data.bit(6);
|
window.io.col.twoInvert = data.bit(6);
|
||||||
window.r.col.twoEnable = data.bit(7);
|
window.io.col.twoEnable = data.bit(7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//WH0
|
//WH0
|
||||||
case 0x2126: {
|
case 0x2126: {
|
||||||
window.r.oneLeft = data;
|
window.io.oneLeft = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//WH1
|
//WH1
|
||||||
case 0x2127: {
|
case 0x2127: {
|
||||||
window.r.oneRight = data;
|
window.io.oneRight = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//WH2
|
//WH2
|
||||||
case 0x2128: {
|
case 0x2128: {
|
||||||
window.r.twoLeft = data;
|
window.io.twoLeft = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//WH3
|
//WH3
|
||||||
case 0x2129: {
|
case 0x2129: {
|
||||||
window.r.twoRight = data;
|
window.io.twoRight = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//WBGLOG
|
//WBGLOG
|
||||||
case 0x212a: {
|
case 0x212a: {
|
||||||
window.r.bg1.mask = data.bits(0,1);
|
window.io.bg1.mask = data.bits(0,1);
|
||||||
window.r.bg2.mask = data.bits(2,3);
|
window.io.bg2.mask = data.bits(2,3);
|
||||||
window.r.bg3.mask = data.bits(4,5);
|
window.io.bg3.mask = data.bits(4,5);
|
||||||
window.r.bg4.mask = data.bits(6,7);
|
window.io.bg4.mask = data.bits(6,7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//WOBJLOG
|
//WOBJLOG
|
||||||
case 0x212b: {
|
case 0x212b: {
|
||||||
window.r.obj.mask = data.bits(0,1);
|
window.io.obj.mask = data.bits(0,1);
|
||||||
window.r.col.mask = data.bits(2,3);
|
window.io.col.mask = data.bits(2,3);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TM
|
//TM
|
||||||
case 0x212c: {
|
case 0x212c: {
|
||||||
bg1.r.aboveEnable = data.bit(0);
|
bg1.io.aboveEnable = data.bit(0);
|
||||||
bg2.r.aboveEnable = data.bit(1);
|
bg2.io.aboveEnable = data.bit(1);
|
||||||
bg3.r.aboveEnable = data.bit(2);
|
bg3.io.aboveEnable = data.bit(2);
|
||||||
bg4.r.aboveEnable = data.bit(3);
|
bg4.io.aboveEnable = data.bit(3);
|
||||||
obj.r.aboveEnable = data.bit(4);
|
obj.io.aboveEnable = data.bit(4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TS
|
//TS
|
||||||
case 0x212d: {
|
case 0x212d: {
|
||||||
bg1.r.belowEnable = data.bit(0);
|
bg1.io.belowEnable = data.bit(0);
|
||||||
bg2.r.belowEnable = data.bit(1);
|
bg2.io.belowEnable = data.bit(1);
|
||||||
bg3.r.belowEnable = data.bit(2);
|
bg3.io.belowEnable = data.bit(2);
|
||||||
bg4.r.belowEnable = data.bit(3);
|
bg4.io.belowEnable = data.bit(3);
|
||||||
obj.r.belowEnable = data.bit(4);
|
obj.io.belowEnable = data.bit(4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TMW
|
//TMW
|
||||||
case 0x212e: {
|
case 0x212e: {
|
||||||
window.r.bg1.aboveEnable = data.bit(0);
|
window.io.bg1.aboveEnable = data.bit(0);
|
||||||
window.r.bg2.aboveEnable = data.bit(1);
|
window.io.bg2.aboveEnable = data.bit(1);
|
||||||
window.r.bg3.aboveEnable = data.bit(2);
|
window.io.bg3.aboveEnable = data.bit(2);
|
||||||
window.r.bg4.aboveEnable = data.bit(3);
|
window.io.bg4.aboveEnable = data.bit(3);
|
||||||
window.r.obj.aboveEnable = data.bit(4);
|
window.io.obj.aboveEnable = data.bit(4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TSW
|
//TSW
|
||||||
case 0x212f: {
|
case 0x212f: {
|
||||||
window.r.bg1.belowEnable = data.bit(0);
|
window.io.bg1.belowEnable = data.bit(0);
|
||||||
window.r.bg2.belowEnable = data.bit(1);
|
window.io.bg2.belowEnable = data.bit(1);
|
||||||
window.r.bg3.belowEnable = data.bit(2);
|
window.io.bg3.belowEnable = data.bit(2);
|
||||||
window.r.bg4.belowEnable = data.bit(3);
|
window.io.bg4.belowEnable = data.bit(3);
|
||||||
window.r.obj.belowEnable = data.bit(4);
|
window.io.obj.belowEnable = data.bit(4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//CGWSEL
|
//CGWSEL
|
||||||
case 0x2130: {
|
case 0x2130: {
|
||||||
screen.r.directColor = data.bit (0);
|
screen.io.directColor = data.bit (0);
|
||||||
screen.r.blendMode = data.bit (1);
|
screen.io.blendMode = data.bit (1);
|
||||||
window.r.col.belowMask = data.bits(4,5);
|
window.io.col.belowMask = data.bits(4,5);
|
||||||
window.r.col.aboveMask = data.bits(6,7);
|
window.io.col.aboveMask = data.bits(6,7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//CGADDSUB
|
//CGADDSUB
|
||||||
case 0x2131: {
|
case 0x2131: {
|
||||||
screen.r.bg1.colorEnable = data.bit(0);
|
screen.io.bg1.colorEnable = data.bit(0);
|
||||||
screen.r.bg2.colorEnable = data.bit(1);
|
screen.io.bg2.colorEnable = data.bit(1);
|
||||||
screen.r.bg3.colorEnable = data.bit(2);
|
screen.io.bg3.colorEnable = data.bit(2);
|
||||||
screen.r.bg4.colorEnable = data.bit(3);
|
screen.io.bg4.colorEnable = data.bit(3);
|
||||||
screen.r.obj.colorEnable = data.bit(4);
|
screen.io.obj.colorEnable = data.bit(4);
|
||||||
screen.r.back.colorEnable = data.bit(5);
|
screen.io.back.colorEnable = data.bit(5);
|
||||||
screen.r.colorHalve = data.bit(6);
|
screen.io.colorHalve = data.bit(6);
|
||||||
screen.r.colorMode = data.bit(7);
|
screen.io.colorMode = data.bit(7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//COLDATA
|
//COLDATA
|
||||||
case 0x2132: {
|
case 0x2132: {
|
||||||
if(data.bit(5)) screen.r.colorRed = data.bits(0,4);
|
if(data.bit(5)) screen.io.colorRed = data.bits(0,4);
|
||||||
if(data.bit(6)) screen.r.colorGreen = data.bits(0,4);
|
if(data.bit(6)) screen.io.colorGreen = data.bits(0,4);
|
||||||
if(data.bit(7)) screen.r.colorBlue = data.bits(0,4);
|
if(data.bit(7)) screen.io.colorBlue = data.bits(0,4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//SETINI
|
//SETINI
|
||||||
case 0x2133: {
|
case 0x2133: {
|
||||||
r.interlace = data.bit(0);
|
io.interlace = data.bit(0);
|
||||||
obj.r.interlace = data.bit(1);
|
obj.io.interlace = data.bit(1);
|
||||||
r.overscan = data.bit(2);
|
io.overscan = data.bit(2);
|
||||||
r.pseudoHires = data.bit(3);
|
io.pseudoHires = data.bit(3);
|
||||||
r.extbg = data.bit(6);
|
io.extbg = data.bit(6);
|
||||||
updateVideoMode();
|
updateVideoMode();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -622,108 +617,108 @@ auto PPU::writeIO(uint24 addr, uint8 data) -> void {
|
||||||
|
|
||||||
auto PPU::latchCounters() -> void {
|
auto PPU::latchCounters() -> void {
|
||||||
cpu.synchronizePPU();
|
cpu.synchronizePPU();
|
||||||
r.hcounter = hdot();
|
io.hcounter = hdot();
|
||||||
r.vcounter = vcounter();
|
io.vcounter = vcounter();
|
||||||
latch.counters = true;
|
latch.counters = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::updateVideoMode() -> void {
|
auto PPU::updateVideoMode() -> void {
|
||||||
switch(r.bgMode) {
|
switch(io.bgMode) {
|
||||||
case 0:
|
case 0:
|
||||||
bg1.r.mode = Background::Mode::BPP2;
|
bg1.io.mode = Background::Mode::BPP2;
|
||||||
bg2.r.mode = Background::Mode::BPP2;
|
bg2.io.mode = Background::Mode::BPP2;
|
||||||
bg3.r.mode = Background::Mode::BPP2;
|
bg3.io.mode = Background::Mode::BPP2;
|
||||||
bg4.r.mode = Background::Mode::BPP2;
|
bg4.io.mode = Background::Mode::BPP2;
|
||||||
memory::assign(bg1.r.priority, 8, 11);
|
memory::assign(bg1.io.priority, 8, 11);
|
||||||
memory::assign(bg2.r.priority, 7, 10);
|
memory::assign(bg2.io.priority, 7, 10);
|
||||||
memory::assign(bg3.r.priority, 2, 5);
|
memory::assign(bg3.io.priority, 2, 5);
|
||||||
memory::assign(bg4.r.priority, 1, 4);
|
memory::assign(bg4.io.priority, 1, 4);
|
||||||
memory::assign(obj.r.priority, 3, 6, 9, 12);
|
memory::assign(obj.io.priority, 3, 6, 9, 12);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
bg1.r.mode = Background::Mode::BPP4;
|
bg1.io.mode = Background::Mode::BPP4;
|
||||||
bg2.r.mode = Background::Mode::BPP4;
|
bg2.io.mode = Background::Mode::BPP4;
|
||||||
bg3.r.mode = Background::Mode::BPP2;
|
bg3.io.mode = Background::Mode::BPP2;
|
||||||
bg4.r.mode = Background::Mode::Inactive;
|
bg4.io.mode = Background::Mode::Inactive;
|
||||||
if(r.bgPriority) {
|
if(io.bgPriority) {
|
||||||
memory::assign(bg1.r.priority, 5, 8);
|
memory::assign(bg1.io.priority, 5, 8);
|
||||||
memory::assign(bg2.r.priority, 4, 7);
|
memory::assign(bg2.io.priority, 4, 7);
|
||||||
memory::assign(bg3.r.priority, 1, 10);
|
memory::assign(bg3.io.priority, 1, 10);
|
||||||
memory::assign(obj.r.priority, 2, 3, 6, 9);
|
memory::assign(obj.io.priority, 2, 3, 6, 9);
|
||||||
} else {
|
} else {
|
||||||
memory::assign(bg1.r.priority, 6, 9);
|
memory::assign(bg1.io.priority, 6, 9);
|
||||||
memory::assign(bg2.r.priority, 5, 8);
|
memory::assign(bg2.io.priority, 5, 8);
|
||||||
memory::assign(bg3.r.priority, 1, 3);
|
memory::assign(bg3.io.priority, 1, 3);
|
||||||
memory::assign(obj.r.priority, 2, 4, 7, 10);
|
memory::assign(obj.io.priority, 2, 4, 7, 10);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
bg1.r.mode = Background::Mode::BPP4;
|
bg1.io.mode = Background::Mode::BPP4;
|
||||||
bg2.r.mode = Background::Mode::BPP4;
|
bg2.io.mode = Background::Mode::BPP4;
|
||||||
bg3.r.mode = Background::Mode::Inactive;
|
bg3.io.mode = Background::Mode::Inactive;
|
||||||
bg4.r.mode = Background::Mode::Inactive;
|
bg4.io.mode = Background::Mode::Inactive;
|
||||||
memory::assign(bg1.r.priority, 3, 7);
|
memory::assign(bg1.io.priority, 3, 7);
|
||||||
memory::assign(bg2.r.priority, 1, 5);
|
memory::assign(bg2.io.priority, 1, 5);
|
||||||
memory::assign(obj.r.priority, 2, 4, 6, 8);
|
memory::assign(obj.io.priority, 2, 4, 6, 8);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
bg1.r.mode = Background::Mode::BPP8;
|
bg1.io.mode = Background::Mode::BPP8;
|
||||||
bg2.r.mode = Background::Mode::BPP4;
|
bg2.io.mode = Background::Mode::BPP4;
|
||||||
bg3.r.mode = Background::Mode::Inactive;
|
bg3.io.mode = Background::Mode::Inactive;
|
||||||
bg4.r.mode = Background::Mode::Inactive;
|
bg4.io.mode = Background::Mode::Inactive;
|
||||||
memory::assign(bg1.r.priority, 3, 7);
|
memory::assign(bg1.io.priority, 3, 7);
|
||||||
memory::assign(bg2.r.priority, 1, 5);
|
memory::assign(bg2.io.priority, 1, 5);
|
||||||
memory::assign(obj.r.priority, 2, 4, 6, 8);
|
memory::assign(obj.io.priority, 2, 4, 6, 8);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
bg1.r.mode = Background::Mode::BPP8;
|
bg1.io.mode = Background::Mode::BPP8;
|
||||||
bg2.r.mode = Background::Mode::BPP2;
|
bg2.io.mode = Background::Mode::BPP2;
|
||||||
bg3.r.mode = Background::Mode::Inactive;
|
bg3.io.mode = Background::Mode::Inactive;
|
||||||
bg4.r.mode = Background::Mode::Inactive;
|
bg4.io.mode = Background::Mode::Inactive;
|
||||||
memory::assign(bg1.r.priority, 3, 7);
|
memory::assign(bg1.io.priority, 3, 7);
|
||||||
memory::assign(bg2.r.priority, 1, 5);
|
memory::assign(bg2.io.priority, 1, 5);
|
||||||
memory::assign(obj.r.priority, 2, 4, 6, 8);
|
memory::assign(obj.io.priority, 2, 4, 6, 8);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
bg1.r.mode = Background::Mode::BPP4;
|
bg1.io.mode = Background::Mode::BPP4;
|
||||||
bg2.r.mode = Background::Mode::BPP2;
|
bg2.io.mode = Background::Mode::BPP2;
|
||||||
bg3.r.mode = Background::Mode::Inactive;
|
bg3.io.mode = Background::Mode::Inactive;
|
||||||
bg4.r.mode = Background::Mode::Inactive;
|
bg4.io.mode = Background::Mode::Inactive;
|
||||||
memory::assign(bg1.r.priority, 3, 7);
|
memory::assign(bg1.io.priority, 3, 7);
|
||||||
memory::assign(bg2.r.priority, 1, 5);
|
memory::assign(bg2.io.priority, 1, 5);
|
||||||
memory::assign(obj.r.priority, 2, 4, 6, 8);
|
memory::assign(obj.io.priority, 2, 4, 6, 8);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
bg1.r.mode = Background::Mode::BPP4;
|
bg1.io.mode = Background::Mode::BPP4;
|
||||||
bg2.r.mode = Background::Mode::Inactive;
|
bg2.io.mode = Background::Mode::Inactive;
|
||||||
bg3.r.mode = Background::Mode::Inactive;
|
bg3.io.mode = Background::Mode::Inactive;
|
||||||
bg4.r.mode = Background::Mode::Inactive;
|
bg4.io.mode = Background::Mode::Inactive;
|
||||||
memory::assign(bg1.r.priority, 2, 5);
|
memory::assign(bg1.io.priority, 2, 5);
|
||||||
memory::assign(obj.r.priority, 1, 3, 4, 6);
|
memory::assign(obj.io.priority, 1, 3, 4, 6);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7:
|
case 7:
|
||||||
if(!r.extbg) {
|
if(!io.extbg) {
|
||||||
bg1.r.mode = Background::Mode::Mode7;
|
bg1.io.mode = Background::Mode::Mode7;
|
||||||
bg2.r.mode = Background::Mode::Inactive;
|
bg2.io.mode = Background::Mode::Inactive;
|
||||||
bg3.r.mode = Background::Mode::Inactive;
|
bg3.io.mode = Background::Mode::Inactive;
|
||||||
bg4.r.mode = Background::Mode::Inactive;
|
bg4.io.mode = Background::Mode::Inactive;
|
||||||
memory::assign(bg1.r.priority, 2);
|
memory::assign(bg1.io.priority, 2);
|
||||||
memory::assign(obj.r.priority, 1, 3, 4, 5);
|
memory::assign(obj.io.priority, 1, 3, 4, 5);
|
||||||
} else {
|
} else {
|
||||||
bg1.r.mode = Background::Mode::Mode7;
|
bg1.io.mode = Background::Mode::Mode7;
|
||||||
bg2.r.mode = Background::Mode::Mode7;
|
bg2.io.mode = Background::Mode::Mode7;
|
||||||
bg3.r.mode = Background::Mode::Inactive;
|
bg3.io.mode = Background::Mode::Inactive;
|
||||||
bg4.r.mode = Background::Mode::Inactive;
|
bg4.io.mode = Background::Mode::Inactive;
|
||||||
memory::assign(bg1.r.priority, 3);
|
memory::assign(bg1.io.priority, 3);
|
||||||
memory::assign(bg2.r.priority, 1, 5);
|
memory::assign(bg2.io.priority, 1, 5);
|
||||||
memory::assign(obj.r.priority, 2, 4, 6, 7);
|
memory::assign(obj.io.priority, 2, 4, 6, 7);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
auto PPU::Object::update(uint10 addr, uint8 data) -> void {
|
|
||||||
if(!addr.bit(9)) {
|
|
||||||
uint n = addr >> 2; //sprite#
|
|
||||||
addr &= 3;
|
|
||||||
if(addr == 0) {
|
|
||||||
list[n].x.bits(0,7) = data;
|
|
||||||
} else if(addr == 1) {
|
|
||||||
list[n].y = data;
|
|
||||||
} else if(addr == 2) {
|
|
||||||
list[n].character = data;
|
|
||||||
} else { //(addr == 3)
|
|
||||||
list[n].nameSelect = data.bit (0);
|
|
||||||
list[n].palette = data.bits(1,3);
|
|
||||||
list[n].priority = data.bits(4,5);
|
|
||||||
list[n].hflip = data.bit (6);
|
|
||||||
list[n].vflip = data.bit (7);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uint n = (addr & 0x1f) << 2; //sprite#
|
|
||||||
list[n + 0].x.bit(8) = data.bit(0);
|
|
||||||
list[n + 0].size = data.bit(1);
|
|
||||||
list[n + 1].x.bit(8) = data.bit(2);
|
|
||||||
list[n + 1].size = data.bit(3);
|
|
||||||
list[n + 2].x.bit(8) = data.bit(4);
|
|
||||||
list[n + 2].size = data.bit(5);
|
|
||||||
list[n + 3].x.bit(8) = data.bit(6);
|
|
||||||
list[n + 3].size = data.bit(7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto PPU::Object::synchronize() -> void {
|
|
||||||
for(auto n : range(544)) update(n, ppu.oam[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto PPU::Object::Sprite::width() const -> uint{
|
|
||||||
if(size == 0) {
|
|
||||||
static const uint width[] = { 8, 8, 8, 16, 16, 32, 16, 16};
|
|
||||||
return width[ppu.obj.r.baseSize];
|
|
||||||
} else {
|
|
||||||
static const uint width[] = {16, 32, 64, 32, 64, 64, 32, 32};
|
|
||||||
return width[ppu.obj.r.baseSize];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto PPU::Object::Sprite::height() const -> uint {
|
|
||||||
if(size == 0) {
|
|
||||||
if(ppu.obj.r.interlace && ppu.obj.r.baseSize >= 6) return 16; //hardware quirk
|
|
||||||
static const uint height[] = { 8, 8, 8, 16, 16, 32, 32, 32};
|
|
||||||
return height[ppu.obj.r.baseSize];
|
|
||||||
} else {
|
|
||||||
static const uint height[] = {16, 32, 64, 32, 64, 64, 64, 32};
|
|
||||||
return height[ppu.obj.r.baseSize];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
auto PPU::OAM::read(uint10 addr) -> uint8 {
|
||||||
|
if(!addr.bit(9)) {
|
||||||
|
uint n = addr >> 2; //object#
|
||||||
|
addr &= 3;
|
||||||
|
if(addr == 0) return object[n].x.bits(0,7);
|
||||||
|
if(addr == 1) return object[n].y;
|
||||||
|
if(addr == 2) return object[n].character;
|
||||||
|
return (
|
||||||
|
object[n].nameselect << 0
|
||||||
|
| object[n].palette << 1
|
||||||
|
| object[n].priority << 4
|
||||||
|
| object[n].hflip << 6
|
||||||
|
| object[n].vflip << 7
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
uint n = (addr & 0x1f) << 2; //object#
|
||||||
|
return (
|
||||||
|
object[n + 0].x.bit(8) << 0
|
||||||
|
| object[n + 0].size << 1
|
||||||
|
| object[n + 1].x.bit(8) << 2
|
||||||
|
| object[n + 1].size << 3
|
||||||
|
| object[n + 2].x.bit(8) << 4
|
||||||
|
| object[n + 2].size << 5
|
||||||
|
| object[n + 3].x.bit(8) << 6
|
||||||
|
| object[n + 3].size << 7
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PPU::OAM::write(uint10 addr, uint8 data) -> void {
|
||||||
|
if(!addr.bit(9)) {
|
||||||
|
uint n = addr >> 2; //object#
|
||||||
|
addr &= 3;
|
||||||
|
if(addr == 0) { object[n].x.bits(0,7) = data; return; }
|
||||||
|
if(addr == 1) { object[n].y = data; return; }
|
||||||
|
if(addr == 2) { object[n].character = data; return; }
|
||||||
|
object[n].nameselect = data.bit (0);
|
||||||
|
object[n].palette = data.bits(1,3);
|
||||||
|
object[n].priority = data.bits(4,5);
|
||||||
|
object[n].hflip = data.bit (6);
|
||||||
|
object[n].vflip = data.bit (7);
|
||||||
|
} else {
|
||||||
|
uint n = (addr & 0x1f) << 2; //object#
|
||||||
|
object[n + 0].x.bit(8) = data.bit(0);
|
||||||
|
object[n + 0].size = data.bit(1);
|
||||||
|
object[n + 1].x.bit(8) = data.bit(2);
|
||||||
|
object[n + 1].size = data.bit(3);
|
||||||
|
object[n + 2].x.bit(8) = data.bit(4);
|
||||||
|
object[n + 2].size = data.bit(5);
|
||||||
|
object[n + 3].x.bit(8) = data.bit(6);
|
||||||
|
object[n + 3].size = data.bit(7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PPU::OAM::Object::width() const -> uint {
|
||||||
|
if(size == 0) {
|
||||||
|
static const uint width[] = { 8, 8, 8, 16, 16, 32, 16, 16};
|
||||||
|
return width[ppu.obj.io.baseSize];
|
||||||
|
} else {
|
||||||
|
static const uint width[] = {16, 32, 64, 32, 64, 64, 32, 32};
|
||||||
|
return width[ppu.obj.io.baseSize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PPU::OAM::Object::height() const -> uint {
|
||||||
|
if(size == 0) {
|
||||||
|
if(ppu.obj.io.interlace && ppu.obj.io.baseSize >= 6) return 16; //hardware quirk
|
||||||
|
static const uint height[] = { 8, 8, 8, 16, 16, 32, 32, 32};
|
||||||
|
return height[ppu.obj.io.baseSize];
|
||||||
|
} else {
|
||||||
|
static const uint height[] = {16, 32, 64, 32, 64, 64, 64, 32};
|
||||||
|
return height[ppu.obj.io.baseSize];
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,17 @@
|
||||||
#include "list.cpp"
|
#include "oam.cpp"
|
||||||
|
|
||||||
auto PPU::Object::addressReset() -> void {
|
auto PPU::Object::addressReset() -> void {
|
||||||
ppu.r.oamAddress = ppu.r.oamBaseAddress;
|
ppu.io.oamAddress = ppu.io.oamBaseAddress;
|
||||||
setFirstSprite();
|
setFirstSprite();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Object::setFirstSprite() -> void {
|
auto PPU::Object::setFirstSprite() -> void {
|
||||||
r.firstSprite = !ppu.r.oamPriority ? 0 : ppu.r.oamAddress >> 2;
|
io.firstSprite = !ppu.io.oamPriority ? 0 : ppu.io.oamAddress >> 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Object::frame() -> void {
|
auto PPU::Object::frame() -> void {
|
||||||
r.timeOver = false;
|
io.timeOver = false;
|
||||||
r.rangeOver = false;
|
io.rangeOver = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Object::scanline() -> void {
|
auto PPU::Object::scanline() -> void {
|
||||||
|
@ -25,15 +25,15 @@ auto PPU::Object::scanline() -> void {
|
||||||
auto oamItem = t.item[t.active];
|
auto oamItem = t.item[t.active];
|
||||||
auto oamTile = t.tile[t.active];
|
auto oamTile = t.tile[t.active];
|
||||||
|
|
||||||
if(t.y == ppu.vdisp() && !ppu.r.displayDisable) addressReset();
|
if(t.y == ppu.vdisp() && !ppu.io.displayDisable) addressReset();
|
||||||
if(t.y >= ppu.vdisp() - 1) return;
|
if(t.y >= ppu.vdisp() - 1) return;
|
||||||
|
|
||||||
for(auto n : range(32)) oamItem[n].valid = false; //default to invalid
|
for(auto n : range(32)) oamItem[n].valid = false; //default to invalid
|
||||||
for(auto n : range(34)) oamTile[n].valid = false; //default to invalid
|
for(auto n : range(34)) oamTile[n].valid = false; //default to invalid
|
||||||
|
|
||||||
for(auto n : range(128)) {
|
for(auto n : range(128)) {
|
||||||
uint7 sprite = r.firstSprite + n;
|
uint7 sprite = io.firstSprite + n;
|
||||||
if(!onScanline(list[sprite])) continue;
|
if(!onScanline(oam.object[sprite])) continue;
|
||||||
if(t.itemCount++ >= 32) break;
|
if(t.itemCount++ >= 32) break;
|
||||||
oamItem[t.itemCount - 1] = {true, sprite};
|
oamItem[t.itemCount - 1] = {true, sprite};
|
||||||
}
|
}
|
||||||
|
@ -43,9 +43,9 @@ auto PPU::Object::scanline() -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Object::onScanline(Sprite& sprite) -> bool {
|
auto PPU::Object::onScanline(PPU::OAM::Object& sprite) -> bool {
|
||||||
if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false;
|
if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false;
|
||||||
int height = sprite.height() >> r.interlace;
|
int height = sprite.height() >> io.interlace;
|
||||||
if(t.y >= sprite.y && t.y < (sprite.y + height)) return true;
|
if(t.y >= sprite.y && t.y < (sprite.y + height)) return true;
|
||||||
if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true;
|
if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true;
|
||||||
return false;
|
return false;
|
||||||
|
@ -72,14 +72,14 @@ auto PPU::Object::run() -> void {
|
||||||
color += tile.data >> (shift + 21) & 8;
|
color += tile.data >> (shift + 21) & 8;
|
||||||
|
|
||||||
if(color) {
|
if(color) {
|
||||||
if(r.aboveEnable) {
|
if(io.aboveEnable) {
|
||||||
output.above.palette = tile.palette + color;
|
output.above.palette = tile.palette + color;
|
||||||
output.above.priority = r.priority[tile.priority];
|
output.above.priority = io.priority[tile.priority];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r.belowEnable) {
|
if(io.belowEnable) {
|
||||||
output.below.palette = tile.palette + color;
|
output.below.palette = tile.palette + color;
|
||||||
output.below.priority = r.priority[tile.priority];
|
output.below.priority = io.priority[tile.priority];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,12 +91,12 @@ auto PPU::Object::tilefetch() -> void {
|
||||||
|
|
||||||
for(int i = 31; i >= 0; i--) {
|
for(int i = 31; i >= 0; i--) {
|
||||||
if(!oamItem[i].valid) continue;
|
if(!oamItem[i].valid) continue;
|
||||||
const auto& sprite = list[oamItem[i].index];
|
const auto& sprite = oam.object[oamItem[i].index];
|
||||||
|
|
||||||
uint tileWidth = sprite.width() >> 3;
|
uint tileWidth = sprite.width() >> 3;
|
||||||
int x = sprite.x;
|
int x = sprite.x;
|
||||||
int y = (t.y - sprite.y) & 0xff;
|
int y = (t.y - sprite.y) & 0xff;
|
||||||
if(r.interlace) y <<= 1;
|
if(io.interlace) y <<= 1;
|
||||||
|
|
||||||
if(sprite.vflip) {
|
if(sprite.vflip) {
|
||||||
if(sprite.width() == sprite.height()) {
|
if(sprite.width() == sprite.height()) {
|
||||||
|
@ -108,18 +108,18 @@ auto PPU::Object::tilefetch() -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r.interlace) {
|
if(io.interlace) {
|
||||||
y = !sprite.vflip ? y + ppu.field() : y - ppu.field();
|
y = !sprite.vflip ? y + ppu.field() : y - ppu.field();
|
||||||
}
|
}
|
||||||
|
|
||||||
x &= 511;
|
x &= 511;
|
||||||
y &= 255;
|
y &= 255;
|
||||||
|
|
||||||
uint16 tiledataAddress = r.tiledataAddress;
|
uint16 tiledataAddress = io.tiledataAddress;
|
||||||
uint16 chrx = (sprite.character >> 0) & 15;
|
uint16 chrx = (sprite.character >> 0) & 15;
|
||||||
uint16 chry = (sprite.character >> 4) & 15;
|
uint16 chry = (sprite.character >> 4) & 15;
|
||||||
if(sprite.nameSelect) {
|
if(sprite.nameselect) {
|
||||||
tiledataAddress += (256 * 16) + (r.nameSelect << 12);
|
tiledataAddress += (256 * 16) + (io.nameselect << 12);
|
||||||
}
|
}
|
||||||
chry += (y >> 3);
|
chry += (y >> 3);
|
||||||
chry &= 15;
|
chry &= 15;
|
||||||
|
@ -142,31 +142,30 @@ auto PPU::Object::tilefetch() -> void {
|
||||||
uint16 addr = (pos & 0xfff0) + (y & 7);
|
uint16 addr = (pos & 0xfff0) + (y & 7);
|
||||||
|
|
||||||
oamTile[n].data.bits( 0,15) = ppu.vram[addr + 0];
|
oamTile[n].data.bits( 0,15) = ppu.vram[addr + 0];
|
||||||
ppu.addClocks(2);
|
ppu.step(2);
|
||||||
|
|
||||||
oamTile[n].data.bits(16,31) = ppu.vram[addr + 8];
|
oamTile[n].data.bits(16,31) = ppu.vram[addr + 8];
|
||||||
ppu.addClocks(2);
|
ppu.step(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(t.tileCount < 34) ppu.addClocks((34 - t.tileCount) * 4);
|
if(t.tileCount < 34) ppu.step((34 - t.tileCount) * 4);
|
||||||
r.timeOver |= (t.tileCount > 34);
|
io.timeOver |= (t.tileCount > 34);
|
||||||
r.rangeOver |= (t.itemCount > 32);
|
io.rangeOver |= (t.itemCount > 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Object::reset() -> void {
|
auto PPU::Object::reset() -> void {
|
||||||
for(auto n : range(128)) {
|
for(auto& object : oam.object) {
|
||||||
list[n].x = 0;
|
object.x = 0;
|
||||||
list[n].y = 0;
|
object.y = 0;
|
||||||
list[n].character = 0;
|
object.character = 0;
|
||||||
list[n].nameSelect = 0;
|
object.nameselect = 0;
|
||||||
list[n].vflip = 0;
|
object.vflip = 0;
|
||||||
list[n].hflip = 0;
|
object.hflip = 0;
|
||||||
list[n].priority = 0;
|
object.priority = 0;
|
||||||
list[n].palette = 0;
|
object.palette = 0;
|
||||||
list[n].size = 0;
|
object.size = 0;
|
||||||
}
|
}
|
||||||
synchronize();
|
|
||||||
|
|
||||||
t.x = 0;
|
t.x = 0;
|
||||||
t.y = 0;
|
t.y = 0;
|
||||||
|
@ -190,19 +189,19 @@ auto PPU::Object::reset() -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.aboveEnable = random(false);
|
io.aboveEnable = random(false);
|
||||||
r.belowEnable = random(false);
|
io.belowEnable = random(false);
|
||||||
r.interlace = random(false);
|
io.interlace = random(false);
|
||||||
|
|
||||||
r.baseSize = random(0);
|
io.baseSize = random(0);
|
||||||
r.nameSelect = random(0);
|
io.nameselect = random(0);
|
||||||
r.tiledataAddress = (random(0x0000) & 3) << 13;
|
io.tiledataAddress = (random(0x0000) & 7) << 13;
|
||||||
r.firstSprite = 0;
|
io.firstSprite = 0;
|
||||||
|
|
||||||
for(auto& p : r.priority) p = 0;
|
for(auto& p : io.priority) p = 0;
|
||||||
|
|
||||||
r.timeOver = false;
|
io.timeOver = false;
|
||||||
r.rangeOver = false;
|
io.rangeOver = false;
|
||||||
|
|
||||||
output.above.palette = 0;
|
output.above.palette = 0;
|
||||||
output.above.priority = 0;
|
output.above.priority = 0;
|
||||||
|
|
|
@ -1,3 +1,23 @@
|
||||||
|
struct OAM {
|
||||||
|
auto read(uint10 addr) -> uint8;
|
||||||
|
auto write(uint10 addr, uint8 data) -> void;
|
||||||
|
|
||||||
|
struct Object {
|
||||||
|
alwaysinline auto width() const -> uint;
|
||||||
|
alwaysinline auto height() const -> uint;
|
||||||
|
|
||||||
|
uint9 x;
|
||||||
|
uint8 y;
|
||||||
|
uint8 character;
|
||||||
|
uint1 nameselect;
|
||||||
|
uint1 vflip;
|
||||||
|
uint1 hflip;
|
||||||
|
uint2 priority;
|
||||||
|
uint3 palette;
|
||||||
|
uint1 size;
|
||||||
|
} object[128];
|
||||||
|
};
|
||||||
|
|
||||||
struct Object {
|
struct Object {
|
||||||
alwaysinline auto addressReset() -> void;
|
alwaysinline auto addressReset() -> void;
|
||||||
alwaysinline auto setFirstSprite() -> void;
|
alwaysinline auto setFirstSprite() -> void;
|
||||||
|
@ -7,22 +27,19 @@ struct Object {
|
||||||
auto tilefetch() -> void;
|
auto tilefetch() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
struct Sprite;
|
auto onScanline(PPU::OAM::Object&) -> bool;
|
||||||
auto onScanline(Sprite&) -> bool;
|
|
||||||
|
|
||||||
//list.cpp
|
|
||||||
auto update(uint10 addr, uint8 data) -> void;
|
|
||||||
auto synchronize() -> void;
|
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
struct Registers {
|
OAM oam;
|
||||||
|
|
||||||
|
struct IO {
|
||||||
bool aboveEnable;
|
bool aboveEnable;
|
||||||
bool belowEnable;
|
bool belowEnable;
|
||||||
bool interlace;
|
bool interlace;
|
||||||
|
|
||||||
uint3 baseSize;
|
uint3 baseSize;
|
||||||
uint2 nameSelect;
|
uint2 nameselect;
|
||||||
uint16 tiledataAddress;
|
uint16 tiledataAddress;
|
||||||
uint7 firstSprite;
|
uint7 firstSprite;
|
||||||
|
|
||||||
|
@ -30,7 +47,7 @@ struct Object {
|
||||||
|
|
||||||
bool timeOver;
|
bool timeOver;
|
||||||
bool rangeOver;
|
bool rangeOver;
|
||||||
} r;
|
} io;
|
||||||
|
|
||||||
struct Item {
|
struct Item {
|
||||||
bool valid;
|
bool valid;
|
||||||
|
@ -65,20 +82,5 @@ struct Object {
|
||||||
} above, below;
|
} above, below;
|
||||||
} output;
|
} output;
|
||||||
|
|
||||||
struct Sprite {
|
|
||||||
alwaysinline auto width() const -> uint;
|
|
||||||
alwaysinline auto height() const -> uint;
|
|
||||||
|
|
||||||
uint9 x;
|
|
||||||
uint8 y;
|
|
||||||
uint8 character;
|
|
||||||
uint1 nameSelect;
|
|
||||||
uint1 vflip;
|
|
||||||
uint1 hflip;
|
|
||||||
uint2 priority;
|
|
||||||
uint3 palette;
|
|
||||||
uint1 size;
|
|
||||||
} list[128];
|
|
||||||
|
|
||||||
friend class PPU;
|
friend class PPU;
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,7 +29,12 @@ PPU::~PPU() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::step(uint clocks) -> void {
|
auto PPU::step(uint clocks) -> void {
|
||||||
clock += clocks;
|
clocks >>= 1;
|
||||||
|
while(clocks--) {
|
||||||
|
tick(2);
|
||||||
|
clock += 2;
|
||||||
|
synchronizeCPU();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::synchronizeCPU() -> void {
|
auto PPU::synchronizeCPU() -> void {
|
||||||
|
@ -42,7 +47,7 @@ auto PPU::Enter() -> void {
|
||||||
|
|
||||||
auto PPU::main() -> void {
|
auto PPU::main() -> void {
|
||||||
scanline();
|
scanline();
|
||||||
addClocks(28);
|
step(28);
|
||||||
bg1.begin();
|
bg1.begin();
|
||||||
bg2.begin();
|
bg2.begin();
|
||||||
bg3.begin();
|
bg3.begin();
|
||||||
|
@ -54,7 +59,7 @@ auto PPU::main() -> void {
|
||||||
bg2.run(1);
|
bg2.run(1);
|
||||||
bg3.run(1);
|
bg3.run(1);
|
||||||
bg4.run(1);
|
bg4.run(1);
|
||||||
addClocks(2);
|
step(2);
|
||||||
|
|
||||||
bg1.run(0);
|
bg1.run(0);
|
||||||
bg2.run(0);
|
bg2.run(0);
|
||||||
|
@ -65,25 +70,16 @@ auto PPU::main() -> void {
|
||||||
window.run();
|
window.run();
|
||||||
screen.run();
|
screen.run();
|
||||||
}
|
}
|
||||||
addClocks(2);
|
step(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
addClocks(14);
|
step(14);
|
||||||
obj.tilefetch();
|
obj.tilefetch();
|
||||||
} else {
|
} else {
|
||||||
addClocks(1052 + 14 + 136);
|
step(1052 + 14 + 136);
|
||||||
}
|
}
|
||||||
|
|
||||||
addClocks(lineclocks() - 28 - 1052 - 14 - 136);
|
step(lineclocks() - 28 - 1052 - 14 - 136);
|
||||||
}
|
|
||||||
|
|
||||||
auto PPU::addClocks(uint clocks) -> void {
|
|
||||||
clocks >>= 1;
|
|
||||||
while(clocks--) {
|
|
||||||
tick(2);
|
|
||||||
step(2);
|
|
||||||
synchronizeCPU();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::load(Markup::Node node) -> bool {
|
auto PPU::load(Markup::Node node) -> bool {
|
||||||
|
@ -96,8 +92,6 @@ auto PPU::load(Markup::Node node) -> bool {
|
||||||
|
|
||||||
auto PPU::power() -> void {
|
auto PPU::power() -> void {
|
||||||
for(auto& n : vram.data) n = random(0x0000);
|
for(auto& n : vram.data) n = random(0x0000);
|
||||||
for(auto& n : oam.data) n = random(0x00);
|
|
||||||
for(auto& n : cgram.data) n = random(0x0000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::reset() -> void {
|
auto PPU::reset() -> void {
|
||||||
|
@ -125,72 +119,72 @@ auto PPU::reset() -> void {
|
||||||
latch.cgramAddress = 0x00;
|
latch.cgramAddress = 0x00;
|
||||||
|
|
||||||
//$2100 INIDISP
|
//$2100 INIDISP
|
||||||
r.displayDisable = true;
|
io.displayDisable = true;
|
||||||
r.displayBrightness = 0;
|
io.displayBrightness = 0;
|
||||||
|
|
||||||
//$2102 OAMADDL
|
//$2102 OAMADDL
|
||||||
//$2103 OAMADDH
|
//$2103 OAMADDH
|
||||||
r.oamBaseAddress = random(0x0000);
|
io.oamBaseAddress = random(0x0000);
|
||||||
r.oamAddress = random(0x0000);
|
io.oamAddress = random(0x0000);
|
||||||
r.oamPriority = random(false);
|
io.oamPriority = random(false);
|
||||||
|
|
||||||
//$2105 BGMODE
|
//$2105 BGMODE
|
||||||
r.bgPriority = false;
|
io.bgPriority = false;
|
||||||
r.bgMode = 0;
|
io.bgMode = 0;
|
||||||
|
|
||||||
//$210d BG1HOFS
|
//$210d BG1HOFS
|
||||||
r.hoffsetMode7 = random(0x0000);
|
io.hoffsetMode7 = random(0x0000);
|
||||||
|
|
||||||
//$210e BG1VOFS
|
//$210e BG1VOFS
|
||||||
r.voffsetMode7 = random(0x0000);
|
io.voffsetMode7 = random(0x0000);
|
||||||
|
|
||||||
//$2115 VMAIN
|
//$2115 VMAIN
|
||||||
r.vramIncrementMode = random(1);
|
io.vramIncrementMode = random(1);
|
||||||
r.vramMapping = random(0);
|
io.vramMapping = random(0);
|
||||||
r.vramIncrementSize = 1;
|
io.vramIncrementSize = 1;
|
||||||
|
|
||||||
//$2116 VMADDL
|
//$2116 VMADDL
|
||||||
//$2117 VMADDH
|
//$2117 VMADDH
|
||||||
r.vramAddress = random(0x0000);
|
io.vramAddress = random(0x0000);
|
||||||
|
|
||||||
//$211a M7SEL
|
//$211a M7SEL
|
||||||
r.repeatMode7 = random(0);
|
io.repeatMode7 = random(0);
|
||||||
r.vflipMode7 = random(false);
|
io.vflipMode7 = random(false);
|
||||||
r.hflipMode7 = random(false);
|
io.hflipMode7 = random(false);
|
||||||
|
|
||||||
//$211b M7A
|
//$211b M7A
|
||||||
r.m7a = random(0x0000);
|
io.m7a = random(0x0000);
|
||||||
|
|
||||||
//$211c M7B
|
//$211c M7B
|
||||||
r.m7b = random(0x0000);
|
io.m7b = random(0x0000);
|
||||||
|
|
||||||
//$211d M7C
|
//$211d M7C
|
||||||
r.m7c = random(0x0000);
|
io.m7c = random(0x0000);
|
||||||
|
|
||||||
//$211e M7D
|
//$211e M7D
|
||||||
r.m7d = random(0x0000);
|
io.m7d = random(0x0000);
|
||||||
|
|
||||||
//$211f M7X
|
//$211f M7X
|
||||||
r.m7x = random(0x0000);
|
io.m7x = random(0x0000);
|
||||||
|
|
||||||
//$2120 M7Y
|
//$2120 M7Y
|
||||||
r.m7y = random(0x0000);
|
io.m7y = random(0x0000);
|
||||||
|
|
||||||
//$2121 CGADD
|
//$2121 CGADD
|
||||||
r.cgramAddress = random(0x00);
|
io.cgramAddress = random(0x00);
|
||||||
r.cgramAddressLatch = random(0);
|
io.cgramAddressLatch = random(0);
|
||||||
|
|
||||||
//$2133 SETINI
|
//$2133 SETINI
|
||||||
r.extbg = random(false);
|
io.extbg = random(false);
|
||||||
r.pseudoHires = random(false);
|
io.pseudoHires = random(false);
|
||||||
r.overscan = false;
|
io.overscan = false;
|
||||||
r.interlace = false;
|
io.interlace = false;
|
||||||
|
|
||||||
//$213c OPHCT
|
//$213c OPHCT
|
||||||
r.hcounter = 0;
|
io.hcounter = 0;
|
||||||
|
|
||||||
//$213d OPVCT
|
//$213d OPVCT
|
||||||
r.vcounter = 0;
|
io.vcounter = 0;
|
||||||
|
|
||||||
bg1.reset();
|
bg1.reset();
|
||||||
bg2.reset();
|
bg2.reset();
|
||||||
|
@ -227,8 +221,8 @@ auto PPU::scanline() -> void {
|
||||||
|
|
||||||
auto PPU::frame() -> void {
|
auto PPU::frame() -> void {
|
||||||
obj.frame();
|
obj.frame();
|
||||||
display.interlace = r.interlace;
|
display.interlace = io.interlace;
|
||||||
display.overscan = r.overscan;
|
display.overscan = io.overscan;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::refresh() -> void {
|
auto PPU::refresh() -> void {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
struct PPU : Thread, PPUcounter {
|
struct PPU : Thread, PPUcounter {
|
||||||
alwaysinline auto interlace() const -> bool { return display.interlace; }
|
alwaysinline auto interlace() const -> bool { return display.interlace; }
|
||||||
alwaysinline auto overscan() const -> bool { return display.overscan; }
|
alwaysinline auto overscan() const -> bool { return display.overscan; }
|
||||||
alwaysinline auto vdisp() const -> uint { return r.overscan ? 240 : 225; }
|
alwaysinline auto vdisp() const -> uint { return io.overscan ? 240 : 225; }
|
||||||
|
|
||||||
PPU();
|
PPU();
|
||||||
~PPU();
|
~PPU();
|
||||||
|
@ -33,16 +33,6 @@ privileged:
|
||||||
uint mask = 0x7fff;
|
uint mask = 0x7fff;
|
||||||
} vram;
|
} vram;
|
||||||
|
|
||||||
struct OAM {
|
|
||||||
auto& operator[](uint offset) { return data[offset]; }
|
|
||||||
uint8 data[544];
|
|
||||||
} oam;
|
|
||||||
|
|
||||||
struct CGRAM {
|
|
||||||
auto& operator[](uint8 offset) { return data[offset]; }
|
|
||||||
uint15 data[256];
|
|
||||||
} cgram;
|
|
||||||
|
|
||||||
uint32* output = nullptr;
|
uint32* output = nullptr;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -50,8 +40,6 @@ privileged:
|
||||||
bool overscan;
|
bool overscan;
|
||||||
} display;
|
} display;
|
||||||
|
|
||||||
alwaysinline auto addClocks(uint) -> void;
|
|
||||||
|
|
||||||
auto scanline() -> void;
|
auto scanline() -> void;
|
||||||
auto frame() -> void;
|
auto frame() -> void;
|
||||||
auto refresh() -> void;
|
auto refresh() -> void;
|
||||||
|
@ -75,7 +63,7 @@ privileged:
|
||||||
uint8 cgramAddress;
|
uint8 cgramAddress;
|
||||||
} latch;
|
} latch;
|
||||||
|
|
||||||
struct Registers {
|
struct IO {
|
||||||
//$2100 INIDISP
|
//$2100 INIDISP
|
||||||
bool displayDisable;
|
bool displayDisable;
|
||||||
uint4 displayBrightness;
|
uint4 displayBrightness;
|
||||||
|
@ -143,7 +131,7 @@ privileged:
|
||||||
|
|
||||||
//$213d OPVCT
|
//$213d OPVCT
|
||||||
uint16 vcounter;
|
uint16 vcounter;
|
||||||
} r;
|
} io;
|
||||||
|
|
||||||
#include "background/background.hpp"
|
#include "background/background.hpp"
|
||||||
#include "object/object.hpp"
|
#include "object/object.hpp"
|
||||||
|
|
|
@ -8,32 +8,32 @@ auto PPU::Screen::scanline() -> void {
|
||||||
math.above.color = paletteColor(0);
|
math.above.color = paletteColor(0);
|
||||||
math.below.color = math.above.color;
|
math.below.color = math.above.color;
|
||||||
|
|
||||||
math.above.colorEnable = !(ppu.window.r.col.aboveMask & 1);
|
math.above.colorEnable = !(ppu.window.io.col.aboveMask & 1);
|
||||||
math.below.colorEnable = !(ppu.window.r.col.belowMask & 1) && r.back.colorEnable;
|
math.below.colorEnable = !(ppu.window.io.col.belowMask & 1) && io.back.colorEnable;
|
||||||
|
|
||||||
math.transparent = true;
|
math.transparent = true;
|
||||||
math.blendMode = false;
|
math.blendMode = false;
|
||||||
math.colorHalve = r.colorHalve && !r.blendMode && math.above.colorEnable;
|
math.colorHalve = io.colorHalve && !io.blendMode && math.above.colorEnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Screen::run() -> void {
|
auto PPU::Screen::run() -> void {
|
||||||
if(ppu.vcounter() == 0) return;
|
if(ppu.vcounter() == 0) return;
|
||||||
|
|
||||||
bool hires = ppu.r.pseudoHires || ppu.r.bgMode == 5 || ppu.r.bgMode == 6;
|
bool hires = ppu.io.pseudoHires || ppu.io.bgMode == 5 || ppu.io.bgMode == 6;
|
||||||
auto belowColor = below(hires);
|
auto belowColor = below(hires);
|
||||||
auto aboveColor = above();
|
auto aboveColor = above();
|
||||||
|
|
||||||
*lineA++ = *lineB++ = ppu.r.displayBrightness << 15 | (hires ? belowColor : aboveColor);
|
*lineA++ = *lineB++ = ppu.io.displayBrightness << 15 | (hires ? belowColor : aboveColor);
|
||||||
*lineA++ = *lineB++ = ppu.r.displayBrightness << 15 | (aboveColor);
|
*lineA++ = *lineB++ = ppu.io.displayBrightness << 15 | (aboveColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Screen::below(bool hires) -> uint16 {
|
auto PPU::Screen::below(bool hires) -> uint16 {
|
||||||
if(ppu.r.displayDisable || (!ppu.r.overscan && ppu.vcounter() >= 225)) return 0;
|
if(ppu.io.displayDisable || (!ppu.io.overscan && ppu.vcounter() >= 225)) return 0;
|
||||||
|
|
||||||
uint priority = 0;
|
uint priority = 0;
|
||||||
if(ppu.bg1.output.below.priority) {
|
if(ppu.bg1.output.below.priority) {
|
||||||
priority = ppu.bg1.output.below.priority;
|
priority = ppu.bg1.output.below.priority;
|
||||||
if(r.directColor && (ppu.r.bgMode == 3 || ppu.r.bgMode == 4 || ppu.r.bgMode == 7)) {
|
if(io.directColor && (ppu.io.bgMode == 3 || ppu.io.bgMode == 4 || ppu.io.bgMode == 7)) {
|
||||||
math.below.color = directColor(ppu.bg1.output.below.palette, ppu.bg1.output.below.tile);
|
math.below.color = directColor(ppu.bg1.output.below.palette, ppu.bg1.output.below.tile);
|
||||||
} else {
|
} else {
|
||||||
math.below.color = paletteColor(ppu.bg1.output.below.palette);
|
math.below.color = paletteColor(ppu.bg1.output.below.palette);
|
||||||
|
@ -67,53 +67,53 @@ auto PPU::Screen::below(bool hires) -> uint16 {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Screen::above() -> uint16 {
|
auto PPU::Screen::above() -> uint16 {
|
||||||
if(ppu.r.displayDisable || (!ppu.r.overscan && ppu.vcounter() >= 225)) return 0;
|
if(ppu.io.displayDisable || (!ppu.io.overscan && ppu.vcounter() >= 225)) return 0;
|
||||||
|
|
||||||
uint priority = 0;
|
uint priority = 0;
|
||||||
if(ppu.bg1.output.above.priority) {
|
if(ppu.bg1.output.above.priority) {
|
||||||
priority = ppu.bg1.output.above.priority;
|
priority = ppu.bg1.output.above.priority;
|
||||||
if(r.directColor && (ppu.r.bgMode == 3 || ppu.r.bgMode == 4 || ppu.r.bgMode == 7)) {
|
if(io.directColor && (ppu.io.bgMode == 3 || ppu.io.bgMode == 4 || ppu.io.bgMode == 7)) {
|
||||||
math.above.color = directColor(ppu.bg1.output.above.palette, ppu.bg1.output.above.tile);
|
math.above.color = directColor(ppu.bg1.output.above.palette, ppu.bg1.output.above.tile);
|
||||||
} else {
|
} else {
|
||||||
math.above.color = paletteColor(ppu.bg1.output.above.palette);
|
math.above.color = paletteColor(ppu.bg1.output.above.palette);
|
||||||
}
|
}
|
||||||
math.below.colorEnable = r.bg1.colorEnable;
|
math.below.colorEnable = io.bg1.colorEnable;
|
||||||
}
|
}
|
||||||
if(ppu.bg2.output.above.priority > priority) {
|
if(ppu.bg2.output.above.priority > priority) {
|
||||||
priority = ppu.bg2.output.above.priority;
|
priority = ppu.bg2.output.above.priority;
|
||||||
math.above.color = paletteColor(ppu.bg2.output.above.palette);
|
math.above.color = paletteColor(ppu.bg2.output.above.palette);
|
||||||
math.below.colorEnable = r.bg2.colorEnable;
|
math.below.colorEnable = io.bg2.colorEnable;
|
||||||
}
|
}
|
||||||
if(ppu.bg3.output.above.priority > priority) {
|
if(ppu.bg3.output.above.priority > priority) {
|
||||||
priority = ppu.bg3.output.above.priority;
|
priority = ppu.bg3.output.above.priority;
|
||||||
math.above.color = paletteColor(ppu.bg3.output.above.palette);
|
math.above.color = paletteColor(ppu.bg3.output.above.palette);
|
||||||
math.below.colorEnable = r.bg3.colorEnable;
|
math.below.colorEnable = io.bg3.colorEnable;
|
||||||
}
|
}
|
||||||
if(ppu.bg4.output.above.priority > priority) {
|
if(ppu.bg4.output.above.priority > priority) {
|
||||||
priority = ppu.bg4.output.above.priority;
|
priority = ppu.bg4.output.above.priority;
|
||||||
math.above.color = paletteColor(ppu.bg4.output.above.palette);
|
math.above.color = paletteColor(ppu.bg4.output.above.palette);
|
||||||
math.below.colorEnable = r.bg4.colorEnable;
|
math.below.colorEnable = io.bg4.colorEnable;
|
||||||
}
|
}
|
||||||
if(ppu.obj.output.above.priority > priority) {
|
if(ppu.obj.output.above.priority > priority) {
|
||||||
priority = ppu.obj.output.above.priority;
|
priority = ppu.obj.output.above.priority;
|
||||||
math.above.color = paletteColor(ppu.obj.output.above.palette);
|
math.above.color = paletteColor(ppu.obj.output.above.palette);
|
||||||
math.below.colorEnable = r.obj.colorEnable && ppu.obj.output.above.palette >= 192;
|
math.below.colorEnable = io.obj.colorEnable && ppu.obj.output.above.palette >= 192;
|
||||||
}
|
}
|
||||||
if(priority == 0) {
|
if(priority == 0) {
|
||||||
math.above.color = paletteColor(0);
|
math.above.color = paletteColor(0);
|
||||||
math.below.colorEnable = r.back.colorEnable;
|
math.below.colorEnable = io.back.colorEnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ppu.window.output.below.colorEnable) math.below.colorEnable = false;
|
if(!ppu.window.output.below.colorEnable) math.below.colorEnable = false;
|
||||||
math.above.colorEnable = ppu.window.output.above.colorEnable;
|
math.above.colorEnable = ppu.window.output.above.colorEnable;
|
||||||
if(!math.below.colorEnable) return math.above.colorEnable ? math.above.color : (uint15)0;
|
if(!math.below.colorEnable) return math.above.colorEnable ? math.above.color : (uint15)0;
|
||||||
|
|
||||||
if(r.blendMode && math.transparent) {
|
if(io.blendMode && math.transparent) {
|
||||||
math.blendMode = false;
|
math.blendMode = false;
|
||||||
math.colorHalve = false;
|
math.colorHalve = false;
|
||||||
} else {
|
} else {
|
||||||
math.blendMode = r.blendMode;
|
math.blendMode = io.blendMode;
|
||||||
math.colorHalve = r.colorHalve && math.above.colorEnable;
|
math.colorHalve = io.colorHalve && math.above.colorEnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
return blend(
|
return blend(
|
||||||
|
@ -123,7 +123,7 @@ auto PPU::Screen::above() -> uint16 {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Screen::blend(uint x, uint y) const -> uint15 {
|
auto PPU::Screen::blend(uint x, uint y) const -> uint15 {
|
||||||
if(!r.colorMode) {
|
if(!io.colorMode) {
|
||||||
if(!math.colorHalve) {
|
if(!math.colorHalve) {
|
||||||
uint sum = x + y;
|
uint sum = x + y;
|
||||||
uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420;
|
uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420;
|
||||||
|
@ -144,7 +144,7 @@ auto PPU::Screen::blend(uint x, uint y) const -> uint15 {
|
||||||
|
|
||||||
auto PPU::Screen::paletteColor(uint8 palette) const -> uint15 {
|
auto PPU::Screen::paletteColor(uint8 palette) const -> uint15 {
|
||||||
ppu.latch.cgramAddress = palette;
|
ppu.latch.cgramAddress = palette;
|
||||||
return ppu.cgram[palette];
|
return cgram[palette];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Screen::directColor(uint palette, uint tile) const -> uint15 {
|
auto PPU::Screen::directColor(uint palette, uint tile) const -> uint15 {
|
||||||
|
@ -157,21 +157,23 @@ auto PPU::Screen::directColor(uint palette, uint tile) const -> uint15 {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Screen::fixedColor() const -> uint15 {
|
auto PPU::Screen::fixedColor() const -> uint15 {
|
||||||
return r.colorBlue << 10 | r.colorGreen << 5 | r.colorRed << 0;
|
return io.colorBlue << 10 | io.colorGreen << 5 | io.colorRed << 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Screen::reset() -> void {
|
auto PPU::Screen::reset() -> void {
|
||||||
r.blendMode = random(false);
|
for(auto& n : cgram) n = random(0x0000);
|
||||||
r.directColor = random(false);
|
|
||||||
r.colorMode = random(false);
|
io.blendMode = random(false);
|
||||||
r.colorHalve = random(false);
|
io.directColor = random(false);
|
||||||
r.bg1.colorEnable = random(false);
|
io.colorMode = random(false);
|
||||||
r.bg2.colorEnable = random(false);
|
io.colorHalve = random(false);
|
||||||
r.bg3.colorEnable = random(false);
|
io.bg1.colorEnable = random(false);
|
||||||
r.bg4.colorEnable = random(false);
|
io.bg2.colorEnable = random(false);
|
||||||
r.obj.colorEnable = random(false);
|
io.bg3.colorEnable = random(false);
|
||||||
r.back.colorEnable = random(false);
|
io.bg4.colorEnable = random(false);
|
||||||
r.colorBlue = random(0);
|
io.obj.colorEnable = random(false);
|
||||||
r.colorGreen = random(0);
|
io.back.colorEnable = random(false);
|
||||||
r.colorRed = random(0);
|
io.colorBlue = random(0);
|
||||||
|
io.colorGreen = random(0);
|
||||||
|
io.colorRed = random(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@ struct Screen {
|
||||||
uint32* lineA;
|
uint32* lineA;
|
||||||
uint32* lineB;
|
uint32* lineB;
|
||||||
|
|
||||||
struct Registers {
|
uint15 cgram[256];
|
||||||
|
|
||||||
|
struct IO {
|
||||||
bool blendMode;
|
bool blendMode;
|
||||||
bool directColor;
|
bool directColor;
|
||||||
|
|
||||||
|
@ -29,7 +31,7 @@ struct Screen {
|
||||||
uint5 colorBlue;
|
uint5 colorBlue;
|
||||||
uint5 colorGreen;
|
uint5 colorGreen;
|
||||||
uint5 colorRed;
|
uint5 colorRed;
|
||||||
} r;
|
} io;
|
||||||
|
|
||||||
struct Math {
|
struct Math {
|
||||||
struct Screen {
|
struct Screen {
|
||||||
|
|
|
@ -16,8 +16,6 @@ auto PPU::serialize(serializer& s) -> void {
|
||||||
|
|
||||||
s.integer(vram.mask);
|
s.integer(vram.mask);
|
||||||
s.array(vram.data, vram.mask + 1);
|
s.array(vram.data, vram.mask + 1);
|
||||||
s.array(oam.data);
|
|
||||||
s.array(cgram.data);
|
|
||||||
|
|
||||||
s.integer(ppu1.version);
|
s.integer(ppu1.version);
|
||||||
s.integer(ppu1.mdr);
|
s.integer(ppu1.mdr);
|
||||||
|
@ -40,46 +38,46 @@ auto PPU::serialize(serializer& s) -> void {
|
||||||
s.integer(latch.oamAddress);
|
s.integer(latch.oamAddress);
|
||||||
s.integer(latch.cgramAddress);
|
s.integer(latch.cgramAddress);
|
||||||
|
|
||||||
s.integer(r.displayDisable);
|
s.integer(io.displayDisable);
|
||||||
s.integer(r.displayBrightness);
|
s.integer(io.displayBrightness);
|
||||||
|
|
||||||
s.integer(r.oamBaseAddress);
|
s.integer(io.oamBaseAddress);
|
||||||
s.integer(r.oamAddress);
|
s.integer(io.oamAddress);
|
||||||
s.integer(r.oamPriority);
|
s.integer(io.oamPriority);
|
||||||
|
|
||||||
s.integer(r.bgPriority);
|
s.integer(io.bgPriority);
|
||||||
s.integer(r.bgMode);
|
s.integer(io.bgMode);
|
||||||
|
|
||||||
s.integer(r.hoffsetMode7);
|
s.integer(io.hoffsetMode7);
|
||||||
s.integer(r.voffsetMode7);
|
s.integer(io.voffsetMode7);
|
||||||
|
|
||||||
s.integer(r.vramIncrementMode);
|
s.integer(io.vramIncrementMode);
|
||||||
s.integer(r.vramMapping);
|
s.integer(io.vramMapping);
|
||||||
s.integer(r.vramIncrementSize);
|
s.integer(io.vramIncrementSize);
|
||||||
|
|
||||||
s.integer(r.vramAddress);
|
s.integer(io.vramAddress);
|
||||||
|
|
||||||
s.integer(r.repeatMode7);
|
s.integer(io.repeatMode7);
|
||||||
s.integer(r.vflipMode7);
|
s.integer(io.vflipMode7);
|
||||||
s.integer(r.hflipMode7);
|
s.integer(io.hflipMode7);
|
||||||
|
|
||||||
s.integer(r.m7a);
|
s.integer(io.m7a);
|
||||||
s.integer(r.m7b);
|
s.integer(io.m7b);
|
||||||
s.integer(r.m7c);
|
s.integer(io.m7c);
|
||||||
s.integer(r.m7d);
|
s.integer(io.m7d);
|
||||||
s.integer(r.m7x);
|
s.integer(io.m7x);
|
||||||
s.integer(r.m7y);
|
s.integer(io.m7y);
|
||||||
|
|
||||||
s.integer(r.cgramAddress);
|
s.integer(io.cgramAddress);
|
||||||
s.integer(r.cgramAddressLatch);
|
s.integer(io.cgramAddressLatch);
|
||||||
|
|
||||||
s.integer(r.extbg);
|
s.integer(io.extbg);
|
||||||
s.integer(r.pseudoHires);
|
s.integer(io.pseudoHires);
|
||||||
s.integer(r.overscan);
|
s.integer(io.overscan);
|
||||||
s.integer(r.interlace);
|
s.integer(io.interlace);
|
||||||
|
|
||||||
s.integer(r.hcounter);
|
s.integer(io.hcounter);
|
||||||
s.integer(r.vcounter);
|
s.integer(io.vcounter);
|
||||||
|
|
||||||
bg1.serialize(s);
|
bg1.serialize(s);
|
||||||
bg2.serialize(s);
|
bg2.serialize(s);
|
||||||
|
@ -91,20 +89,20 @@ auto PPU::serialize(serializer& s) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Background::serialize(serializer& s) -> void {
|
auto PPU::Background::serialize(serializer& s) -> void {
|
||||||
s.integer(r.tiledataAddress);
|
s.integer(io.tiledataAddress);
|
||||||
s.integer(r.screenAddress);
|
s.integer(io.screenAddress);
|
||||||
s.integer(r.screenSize);
|
s.integer(io.screenSize);
|
||||||
s.integer(r.mosaic);
|
s.integer(io.mosaic);
|
||||||
s.integer(r.tileSize);
|
s.integer(io.tileSize);
|
||||||
|
|
||||||
s.integer(r.mode);
|
s.integer(io.mode);
|
||||||
s.array(r.priority);
|
s.array(io.priority);
|
||||||
|
|
||||||
s.integer(r.aboveEnable);
|
s.integer(io.aboveEnable);
|
||||||
s.integer(r.belowEnable);
|
s.integer(io.belowEnable);
|
||||||
|
|
||||||
s.integer(r.hoffset);
|
s.integer(io.hoffset);
|
||||||
s.integer(r.voffset);
|
s.integer(io.voffset);
|
||||||
|
|
||||||
s.integer(latch.hoffset);
|
s.integer(latch.hoffset);
|
||||||
s.integer(latch.voffset);
|
s.integer(latch.voffset);
|
||||||
|
@ -138,19 +136,31 @@ auto PPU::Background::serialize(serializer& s) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Object::serialize(serializer& s) -> void {
|
auto PPU::Object::serialize(serializer& s) -> void {
|
||||||
s.integer(r.aboveEnable);
|
for(auto& object : oam.object) {
|
||||||
s.integer(r.belowEnable);
|
s.integer(object.x);
|
||||||
s.integer(r.interlace);
|
s.integer(object.y);
|
||||||
|
s.integer(object.character);
|
||||||
|
s.integer(object.nameselect);
|
||||||
|
s.integer(object.vflip);
|
||||||
|
s.integer(object.hflip);
|
||||||
|
s.integer(object.priority);
|
||||||
|
s.integer(object.palette);
|
||||||
|
s.integer(object.size);
|
||||||
|
}
|
||||||
|
|
||||||
s.integer(r.baseSize);
|
s.integer(io.aboveEnable);
|
||||||
s.integer(r.nameSelect);
|
s.integer(io.belowEnable);
|
||||||
s.integer(r.tiledataAddress);
|
s.integer(io.interlace);
|
||||||
s.integer(r.firstSprite);
|
|
||||||
|
|
||||||
s.array(r.priority);
|
s.integer(io.baseSize);
|
||||||
|
s.integer(io.nameselect);
|
||||||
|
s.integer(io.tiledataAddress);
|
||||||
|
s.integer(io.firstSprite);
|
||||||
|
|
||||||
s.integer(r.timeOver);
|
s.array(io.priority);
|
||||||
s.integer(r.rangeOver);
|
|
||||||
|
s.integer(io.timeOver);
|
||||||
|
s.integer(io.rangeOver);
|
||||||
|
|
||||||
s.integer(t.x);
|
s.integer(t.x);
|
||||||
s.integer(t.y);
|
s.integer(t.y);
|
||||||
|
@ -179,73 +189,61 @@ auto PPU::Object::serialize(serializer& s) -> void {
|
||||||
|
|
||||||
s.integer(output.below.priority);
|
s.integer(output.below.priority);
|
||||||
s.integer(output.below.palette);
|
s.integer(output.below.palette);
|
||||||
|
|
||||||
for(auto n : range(128)) {
|
|
||||||
s.integer(list[n].x);
|
|
||||||
s.integer(list[n].y);
|
|
||||||
s.integer(list[n].character);
|
|
||||||
s.integer(list[n].nameSelect);
|
|
||||||
s.integer(list[n].vflip);
|
|
||||||
s.integer(list[n].hflip);
|
|
||||||
s.integer(list[n].priority);
|
|
||||||
s.integer(list[n].palette);
|
|
||||||
s.integer(list[n].size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Window::serialize(serializer& s) -> void {
|
auto PPU::Window::serialize(serializer& s) -> void {
|
||||||
s.integer(r.bg1.oneEnable);
|
s.integer(io.bg1.oneEnable);
|
||||||
s.integer(r.bg1.oneInvert);
|
s.integer(io.bg1.oneInvert);
|
||||||
s.integer(r.bg1.twoEnable);
|
s.integer(io.bg1.twoEnable);
|
||||||
s.integer(r.bg1.twoInvert);
|
s.integer(io.bg1.twoInvert);
|
||||||
s.integer(r.bg1.mask);
|
s.integer(io.bg1.mask);
|
||||||
s.integer(r.bg1.aboveEnable);
|
s.integer(io.bg1.aboveEnable);
|
||||||
s.integer(r.bg1.belowEnable);
|
s.integer(io.bg1.belowEnable);
|
||||||
|
|
||||||
s.integer(r.bg2.oneEnable);
|
s.integer(io.bg2.oneEnable);
|
||||||
s.integer(r.bg2.oneInvert);
|
s.integer(io.bg2.oneInvert);
|
||||||
s.integer(r.bg2.twoEnable);
|
s.integer(io.bg2.twoEnable);
|
||||||
s.integer(r.bg2.twoInvert);
|
s.integer(io.bg2.twoInvert);
|
||||||
s.integer(r.bg2.mask);
|
s.integer(io.bg2.mask);
|
||||||
s.integer(r.bg2.aboveEnable);
|
s.integer(io.bg2.aboveEnable);
|
||||||
s.integer(r.bg2.belowEnable);
|
s.integer(io.bg2.belowEnable);
|
||||||
|
|
||||||
s.integer(r.bg3.oneEnable);
|
s.integer(io.bg3.oneEnable);
|
||||||
s.integer(r.bg3.oneInvert);
|
s.integer(io.bg3.oneInvert);
|
||||||
s.integer(r.bg3.twoEnable);
|
s.integer(io.bg3.twoEnable);
|
||||||
s.integer(r.bg3.twoInvert);
|
s.integer(io.bg3.twoInvert);
|
||||||
s.integer(r.bg3.mask);
|
s.integer(io.bg3.mask);
|
||||||
s.integer(r.bg3.aboveEnable);
|
s.integer(io.bg3.aboveEnable);
|
||||||
s.integer(r.bg3.belowEnable);
|
s.integer(io.bg3.belowEnable);
|
||||||
|
|
||||||
s.integer(r.bg4.oneEnable);
|
s.integer(io.bg4.oneEnable);
|
||||||
s.integer(r.bg4.oneInvert);
|
s.integer(io.bg4.oneInvert);
|
||||||
s.integer(r.bg4.twoEnable);
|
s.integer(io.bg4.twoEnable);
|
||||||
s.integer(r.bg4.twoInvert);
|
s.integer(io.bg4.twoInvert);
|
||||||
s.integer(r.bg4.mask);
|
s.integer(io.bg4.mask);
|
||||||
s.integer(r.bg4.aboveEnable);
|
s.integer(io.bg4.aboveEnable);
|
||||||
s.integer(r.bg4.belowEnable);
|
s.integer(io.bg4.belowEnable);
|
||||||
|
|
||||||
s.integer(r.obj.oneEnable);
|
s.integer(io.obj.oneEnable);
|
||||||
s.integer(r.obj.oneInvert);
|
s.integer(io.obj.oneInvert);
|
||||||
s.integer(r.obj.twoEnable);
|
s.integer(io.obj.twoEnable);
|
||||||
s.integer(r.obj.twoInvert);
|
s.integer(io.obj.twoInvert);
|
||||||
s.integer(r.obj.mask);
|
s.integer(io.obj.mask);
|
||||||
s.integer(r.obj.aboveEnable);
|
s.integer(io.obj.aboveEnable);
|
||||||
s.integer(r.obj.belowEnable);
|
s.integer(io.obj.belowEnable);
|
||||||
|
|
||||||
s.integer(r.col.oneEnable);
|
s.integer(io.col.oneEnable);
|
||||||
s.integer(r.col.oneInvert);
|
s.integer(io.col.oneInvert);
|
||||||
s.integer(r.col.twoEnable);
|
s.integer(io.col.twoEnable);
|
||||||
s.integer(r.col.twoInvert);
|
s.integer(io.col.twoInvert);
|
||||||
s.integer(r.col.mask);
|
s.integer(io.col.mask);
|
||||||
s.integer(r.col.aboveMask);
|
s.integer(io.col.aboveMask);
|
||||||
s.integer(r.col.belowMask);
|
s.integer(io.col.belowMask);
|
||||||
|
|
||||||
s.integer(r.oneLeft);
|
s.integer(io.oneLeft);
|
||||||
s.integer(r.oneRight);
|
s.integer(io.oneRight);
|
||||||
s.integer(r.twoLeft);
|
s.integer(io.twoLeft);
|
||||||
s.integer(r.twoRight);
|
s.integer(io.twoRight);
|
||||||
|
|
||||||
s.integer(output.above.colorEnable);
|
s.integer(output.above.colorEnable);
|
||||||
s.integer(output.below.colorEnable);
|
s.integer(output.below.colorEnable);
|
||||||
|
@ -254,21 +252,23 @@ auto PPU::Window::serialize(serializer& s) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Screen::serialize(serializer& s) -> void {
|
auto PPU::Screen::serialize(serializer& s) -> void {
|
||||||
s.integer(r.blendMode);
|
s.array(cgram);
|
||||||
s.integer(r.directColor);
|
|
||||||
|
|
||||||
s.integer(r.colorMode);
|
s.integer(io.blendMode);
|
||||||
s.integer(r.colorHalve);
|
s.integer(io.directColor);
|
||||||
s.integer(r.bg1.colorEnable);
|
|
||||||
s.integer(r.bg2.colorEnable);
|
|
||||||
s.integer(r.bg3.colorEnable);
|
|
||||||
s.integer(r.bg4.colorEnable);
|
|
||||||
s.integer(r.obj.colorEnable);
|
|
||||||
s.integer(r.back.colorEnable);
|
|
||||||
|
|
||||||
s.integer(r.colorBlue);
|
s.integer(io.colorMode);
|
||||||
s.integer(r.colorGreen);
|
s.integer(io.colorHalve);
|
||||||
s.integer(r.colorRed);
|
s.integer(io.bg1.colorEnable);
|
||||||
|
s.integer(io.bg2.colorEnable);
|
||||||
|
s.integer(io.bg3.colorEnable);
|
||||||
|
s.integer(io.bg4.colorEnable);
|
||||||
|
s.integer(io.obj.colorEnable);
|
||||||
|
s.integer(io.back.colorEnable);
|
||||||
|
|
||||||
|
s.integer(io.colorBlue);
|
||||||
|
s.integer(io.colorGreen);
|
||||||
|
s.integer(io.colorRed);
|
||||||
|
|
||||||
s.integer(math.above.color);
|
s.integer(math.above.color);
|
||||||
s.integer(math.above.colorEnable);
|
s.integer(math.above.colorEnable);
|
||||||
|
|
|
@ -3,39 +3,39 @@ auto PPU::Window::scanline() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Window::run() -> void {
|
auto PPU::Window::run() -> void {
|
||||||
bool one = (x >= r.oneLeft && x <= r.oneRight);
|
bool one = (x >= io.oneLeft && x <= io.oneRight);
|
||||||
bool two = (x >= r.twoLeft && x <= r.twoRight);
|
bool two = (x >= io.twoLeft && x <= io.twoRight);
|
||||||
x++;
|
x++;
|
||||||
|
|
||||||
if(test(r.bg1.oneEnable, one ^ r.bg1.oneInvert, r.bg1.twoEnable, two ^ r.bg1.twoInvert, r.bg1.mask)) {
|
if(test(io.bg1.oneEnable, one ^ io.bg1.oneInvert, io.bg1.twoEnable, two ^ io.bg1.twoInvert, io.bg1.mask)) {
|
||||||
if(r.bg1.aboveEnable) ppu.bg1.output.above.priority = 0;
|
if(io.bg1.aboveEnable) ppu.bg1.output.above.priority = 0;
|
||||||
if(r.bg1.belowEnable) ppu.bg1.output.below.priority = 0;
|
if(io.bg1.belowEnable) ppu.bg1.output.below.priority = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(test(r.bg2.oneEnable, one ^ r.bg2.oneInvert, r.bg2.twoEnable, two ^ r.bg2.twoInvert, r.bg2.mask)) {
|
if(test(io.bg2.oneEnable, one ^ io.bg2.oneInvert, io.bg2.twoEnable, two ^ io.bg2.twoInvert, io.bg2.mask)) {
|
||||||
if(r.bg2.aboveEnable) ppu.bg2.output.above.priority = 0;
|
if(io.bg2.aboveEnable) ppu.bg2.output.above.priority = 0;
|
||||||
if(r.bg2.belowEnable) ppu.bg2.output.below.priority = 0;
|
if(io.bg2.belowEnable) ppu.bg2.output.below.priority = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(test(r.bg3.oneEnable, one ^ r.bg3.oneInvert, r.bg3.twoEnable, two ^ r.bg3.twoInvert, r.bg3.mask)) {
|
if(test(io.bg3.oneEnable, one ^ io.bg3.oneInvert, io.bg3.twoEnable, two ^ io.bg3.twoInvert, io.bg3.mask)) {
|
||||||
if(r.bg3.aboveEnable) ppu.bg3.output.above.priority = 0;
|
if(io.bg3.aboveEnable) ppu.bg3.output.above.priority = 0;
|
||||||
if(r.bg3.belowEnable) ppu.bg3.output.below.priority = 0;
|
if(io.bg3.belowEnable) ppu.bg3.output.below.priority = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(test(r.bg4.oneEnable, one ^ r.bg4.oneInvert, r.bg4.twoEnable, two ^ r.bg4.twoInvert, r.bg4.mask)) {
|
if(test(io.bg4.oneEnable, one ^ io.bg4.oneInvert, io.bg4.twoEnable, two ^ io.bg4.twoInvert, io.bg4.mask)) {
|
||||||
if(r.bg4.aboveEnable) ppu.bg4.output.above.priority = 0;
|
if(io.bg4.aboveEnable) ppu.bg4.output.above.priority = 0;
|
||||||
if(r.bg4.belowEnable) ppu.bg4.output.below.priority = 0;
|
if(io.bg4.belowEnable) ppu.bg4.output.below.priority = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(test(r.obj.oneEnable, one ^ r.obj.oneInvert, r.obj.twoEnable, two ^ r.obj.twoInvert, r.obj.mask)) {
|
if(test(io.obj.oneEnable, one ^ io.obj.oneInvert, io.obj.twoEnable, two ^ io.obj.twoInvert, io.obj.mask)) {
|
||||||
if(r.obj.aboveEnable) ppu.obj.output.above.priority = 0;
|
if(io.obj.aboveEnable) ppu.obj.output.above.priority = 0;
|
||||||
if(r.obj.belowEnable) ppu.obj.output.below.priority = 0;
|
if(io.obj.belowEnable) ppu.obj.output.below.priority = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool value = test(r.col.oneEnable, one ^ r.col.oneInvert, r.col.twoEnable, two ^ r.col.twoInvert, r.col.mask);
|
bool value = test(io.col.oneEnable, one ^ io.col.oneInvert, io.col.twoEnable, two ^ io.col.twoInvert, io.col.mask);
|
||||||
bool array[] = {true, value, !value, false};
|
bool array[] = {true, value, !value, false};
|
||||||
output.above.colorEnable = array[r.col.aboveMask];
|
output.above.colorEnable = array[io.col.aboveMask];
|
||||||
output.below.colorEnable = array[r.col.belowMask];
|
output.below.colorEnable = array[io.col.belowMask];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Window::test(bool oneEnable, bool one, bool twoEnable, bool two, uint mask) -> bool {
|
auto PPU::Window::test(bool oneEnable, bool one, bool twoEnable, bool two, uint mask) -> bool {
|
||||||
|
@ -47,58 +47,58 @@ auto PPU::Window::test(bool oneEnable, bool one, bool twoEnable, bool two, uint
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Window::reset() -> void {
|
auto PPU::Window::reset() -> void {
|
||||||
r.bg1.oneEnable = random(false);
|
io.bg1.oneEnable = random(false);
|
||||||
r.bg1.oneInvert = random(false);
|
io.bg1.oneInvert = random(false);
|
||||||
r.bg1.twoEnable = random(false);
|
io.bg1.twoEnable = random(false);
|
||||||
r.bg1.twoInvert = random(false);
|
io.bg1.twoInvert = random(false);
|
||||||
r.bg1.mask = random(0);
|
io.bg1.mask = random(0);
|
||||||
r.bg1.aboveEnable = random(false);
|
io.bg1.aboveEnable = random(false);
|
||||||
r.bg1.belowEnable = random(false);
|
io.bg1.belowEnable = random(false);
|
||||||
|
|
||||||
r.bg2.oneEnable = random(false);
|
io.bg2.oneEnable = random(false);
|
||||||
r.bg2.oneInvert = random(false);
|
io.bg2.oneInvert = random(false);
|
||||||
r.bg2.twoEnable = random(false);
|
io.bg2.twoEnable = random(false);
|
||||||
r.bg2.twoInvert = random(false);
|
io.bg2.twoInvert = random(false);
|
||||||
r.bg2.mask = random(0);
|
io.bg2.mask = random(0);
|
||||||
r.bg2.aboveEnable = random(false);
|
io.bg2.aboveEnable = random(false);
|
||||||
r.bg2.belowEnable = random(false);
|
io.bg2.belowEnable = random(false);
|
||||||
|
|
||||||
r.bg3.oneEnable = random(false);
|
io.bg3.oneEnable = random(false);
|
||||||
r.bg3.oneInvert = random(false);
|
io.bg3.oneInvert = random(false);
|
||||||
r.bg3.twoEnable = random(false);
|
io.bg3.twoEnable = random(false);
|
||||||
r.bg3.twoInvert = random(false);
|
io.bg3.twoInvert = random(false);
|
||||||
r.bg3.mask = random(0);
|
io.bg3.mask = random(0);
|
||||||
r.bg3.aboveEnable = random(false);
|
io.bg3.aboveEnable = random(false);
|
||||||
r.bg3.belowEnable = random(false);
|
io.bg3.belowEnable = random(false);
|
||||||
|
|
||||||
r.bg4.oneEnable = random(false);
|
io.bg4.oneEnable = random(false);
|
||||||
r.bg4.oneInvert = random(false);
|
io.bg4.oneInvert = random(false);
|
||||||
r.bg4.twoEnable = random(false);
|
io.bg4.twoEnable = random(false);
|
||||||
r.bg4.twoInvert = random(false);
|
io.bg4.twoInvert = random(false);
|
||||||
r.bg4.mask = random(0);
|
io.bg4.mask = random(0);
|
||||||
r.bg4.aboveEnable = random(false);
|
io.bg4.aboveEnable = random(false);
|
||||||
r.bg4.belowEnable = random(false);
|
io.bg4.belowEnable = random(false);
|
||||||
|
|
||||||
r.obj.oneEnable = random(false);
|
io.obj.oneEnable = random(false);
|
||||||
r.obj.oneInvert = random(false);
|
io.obj.oneInvert = random(false);
|
||||||
r.obj.twoEnable = random(false);
|
io.obj.twoEnable = random(false);
|
||||||
r.obj.twoInvert = random(false);
|
io.obj.twoInvert = random(false);
|
||||||
r.obj.mask = random(0);
|
io.obj.mask = random(0);
|
||||||
r.obj.aboveEnable = random(false);
|
io.obj.aboveEnable = random(false);
|
||||||
r.obj.belowEnable = random(false);
|
io.obj.belowEnable = random(false);
|
||||||
|
|
||||||
r.col.oneEnable = random(false);
|
io.col.oneEnable = random(false);
|
||||||
r.col.oneInvert = random(false);
|
io.col.oneInvert = random(false);
|
||||||
r.col.twoEnable = random(false);
|
io.col.twoEnable = random(false);
|
||||||
r.col.twoInvert = random(false);
|
io.col.twoInvert = random(false);
|
||||||
r.col.mask = random(0);
|
io.col.mask = random(0);
|
||||||
r.col.aboveMask = random(0);
|
io.col.aboveMask = random(0);
|
||||||
r.col.belowMask = random(0);
|
io.col.belowMask = random(0);
|
||||||
|
|
||||||
r.oneLeft = random(0x00);
|
io.oneLeft = random(0x00);
|
||||||
r.oneRight = random(0x00);
|
io.oneRight = random(0x00);
|
||||||
r.twoLeft = random(0x00);
|
io.twoLeft = random(0x00);
|
||||||
r.twoRight = random(0x00);
|
io.twoRight = random(0x00);
|
||||||
|
|
||||||
output.above.colorEnable = 0;
|
output.above.colorEnable = 0;
|
||||||
output.below.colorEnable = 0;
|
output.below.colorEnable = 0;
|
||||||
|
|
|
@ -6,7 +6,7 @@ struct Window {
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
struct Registers {
|
struct IO {
|
||||||
struct Layer {
|
struct Layer {
|
||||||
bool oneEnable;
|
bool oneEnable;
|
||||||
bool oneInvert;
|
bool oneInvert;
|
||||||
|
@ -31,7 +31,7 @@ struct Window {
|
||||||
uint8 oneRight;
|
uint8 oneRight;
|
||||||
uint8 twoLeft;
|
uint8 twoLeft;
|
||||||
uint8 twoRight;
|
uint8 twoRight;
|
||||||
} r;
|
} io;
|
||||||
|
|
||||||
struct Output {
|
struct Output {
|
||||||
struct Pixel {
|
struct Pixel {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
alwaysinline auto SMP::readRAM(uint16 addr) -> uint8 {
|
alwaysinline auto SMP::readRAM(uint16 addr) -> uint8 {
|
||||||
if(addr >= 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
|
if(addr >= 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f];
|
||||||
if(status.ramDisable) return 0x5a; //0xff on mini-SNES
|
if(io.ramDisable) return 0x5a; //0xff on mini-SNES
|
||||||
return apuram[addr];
|
return apuram[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
alwaysinline auto SMP::writeRAM(uint16 addr, uint8 data) -> void {
|
alwaysinline auto SMP::writeRAM(uint16 addr, uint8 data) -> void {
|
||||||
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
|
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
|
||||||
if(status.ramWritable && !status.ramDisable) apuram[addr] = data;
|
if(io.ramWritable && !io.ramDisable) apuram[addr] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SMP::readPort(uint2 port) const -> uint8 {
|
auto SMP::readPort(uint2 port) const -> uint8 {
|
||||||
|
@ -28,24 +28,24 @@ auto SMP::readBus(uint16 addr) -> uint8 {
|
||||||
return 0x00;
|
return 0x00;
|
||||||
|
|
||||||
case 0xf2: //DSPADDR
|
case 0xf2: //DSPADDR
|
||||||
return status.dspAddr;
|
return io.dspAddr;
|
||||||
|
|
||||||
case 0xf3: //DSPDATA
|
case 0xf3: //DSPDATA
|
||||||
//0x80-0xff are read-only mirrors of 0x00-0x7f
|
//0x80-0xff are read-only mirrors of 0x00-0x7f
|
||||||
return dsp.read(status.dspAddr & 0x7f);
|
return dsp.read(io.dspAddr & 0x7f);
|
||||||
|
|
||||||
case 0xf4: //CPUIO0
|
case 0xf4: //CPUIO0
|
||||||
case 0xf5: //CPUIO1
|
case 0xf5: //CPUIO1
|
||||||
case 0xf6: //CPUIO2
|
case 0xf6: //CPUIO2
|
||||||
case 0xf7: //CPUIO3
|
case 0xf7: //CPUIO3
|
||||||
synchronizeCPU();
|
synchronizeCPU();
|
||||||
return cpu.portRead(addr);
|
return cpu.readPort(addr);
|
||||||
|
|
||||||
case 0xf8: //RAM0
|
case 0xf8: //RAM0
|
||||||
return status.ram00f8;
|
return io.ram00f8;
|
||||||
|
|
||||||
case 0xf9: //RAM1
|
case 0xf9: //RAM1
|
||||||
return status.ram00f9;
|
return io.ram00f9;
|
||||||
|
|
||||||
case 0xfa: //T0TARGET
|
case 0xfa: //T0TARGET
|
||||||
case 0xfb: //T1TARGET
|
case 0xfb: //T1TARGET
|
||||||
|
@ -76,14 +76,14 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
||||||
case 0xf0: //TEST
|
case 0xf0: //TEST
|
||||||
if(regs.p.p) break; //writes only valid when P flag is clear
|
if(regs.p.p) break; //writes only valid when P flag is clear
|
||||||
|
|
||||||
status.clockSpeed = (data >> 6) & 3;
|
io.clockSpeed = (data >> 6) & 3;
|
||||||
status.timerSpeed = (data >> 4) & 3;
|
io.timerSpeed = (data >> 4) & 3;
|
||||||
status.timersEnable = data & 0x08;
|
io.timersEnable = data & 0x08;
|
||||||
status.ramDisable = data & 0x04;
|
io.ramDisable = data & 0x04;
|
||||||
status.ramWritable = data & 0x02;
|
io.ramWritable = data & 0x02;
|
||||||
status.timersDisable = data & 0x01;
|
io.timersDisable = data & 0x01;
|
||||||
|
|
||||||
status.timerStep = (1 << status.clockSpeed) + (2 << status.timerSpeed);
|
io.timerStep = (1 << io.clockSpeed) + (2 << io.timerSpeed);
|
||||||
|
|
||||||
timer0.synchronizeStage1();
|
timer0.synchronizeStage1();
|
||||||
timer1.synchronizeStage1();
|
timer1.synchronizeStage1();
|
||||||
|
@ -91,19 +91,19 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf1: //CONTROL
|
case 0xf1: //CONTROL
|
||||||
status.iplromEnable = data & 0x80;
|
io.iplromEnable = data & 0x80;
|
||||||
|
|
||||||
if(data & 0x30) {
|
if(data & 0x30) {
|
||||||
//one-time clearing of APU port read registers,
|
//one-time clearing of APU port read registers,
|
||||||
//emulated by simulating CPU writes of 0x00
|
//emulated by simulating CPU writes of 0x00
|
||||||
synchronizeCPU();
|
synchronizeCPU();
|
||||||
if(data & 0x20) {
|
if(data & 0x20) {
|
||||||
cpu.portWrite(2, 0x00);
|
cpu.writePort(2, 0x00);
|
||||||
cpu.portWrite(3, 0x00);
|
cpu.writePort(3, 0x00);
|
||||||
}
|
}
|
||||||
if(data & 0x10) {
|
if(data & 0x10) {
|
||||||
cpu.portWrite(0, 0x00);
|
cpu.writePort(0, 0x00);
|
||||||
cpu.portWrite(1, 0x00);
|
cpu.writePort(1, 0x00);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,12 +128,12 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf2: //DSPADDR
|
case 0xf2: //DSPADDR
|
||||||
status.dspAddr = data;
|
io.dspAddr = data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf3: //DSPDATA
|
case 0xf3: //DSPDATA
|
||||||
if(status.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
|
if(io.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
|
||||||
dsp.write(status.dspAddr & 0x7f, data);
|
dsp.write(io.dspAddr & 0x7f, data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf4: //CPUIO0
|
case 0xf4: //CPUIO0
|
||||||
|
@ -145,11 +145,11 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf8: //RAM0
|
case 0xf8: //RAM0
|
||||||
status.ram00f8 = data;
|
io.ram00f8 = data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf9: //RAM1
|
case 0xf9: //RAM1
|
||||||
status.ram00f9 = data;
|
io.ram00f9 = data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xfa: //T0TARGET
|
case 0xfa: //T0TARGET
|
||||||
|
@ -173,27 +173,27 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
||||||
writeRAM(addr, data); //all writes, even to MMIO registers, appear on bus
|
writeRAM(addr, data); //all writes, even to MMIO registers, appear on bus
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SMP::io() -> void {
|
auto SMP::idle() -> void {
|
||||||
addClocks(24);
|
step(24);
|
||||||
cycleEdge();
|
cycleEdge();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SMP::read(uint16 addr) -> uint8 {
|
auto SMP::read(uint16 addr) -> uint8 {
|
||||||
addClocks(12);
|
step(12);
|
||||||
uint8 data = readBus(addr);
|
uint8 data = readBus(addr);
|
||||||
addClocks(12);
|
step(12);
|
||||||
cycleEdge();
|
cycleEdge();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SMP::write(uint16 addr, uint8 data) -> void {
|
auto SMP::write(uint16 addr, uint8 data) -> void {
|
||||||
addClocks(24);
|
step(24);
|
||||||
writeBus(addr, data);
|
writeBus(addr, data);
|
||||||
cycleEdge();
|
cycleEdge();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SMP::readDisassembler(uint16 addr) -> uint8 {
|
auto SMP::readDisassembler(uint16 addr) -> uint8 {
|
||||||
if((addr & 0xfff0) == 0x00f0) return 0x00;
|
if((addr & 0xfff0) == 0x00f0) return 0x00;
|
||||||
if((addr & 0xffc0) == 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
|
if((addr & 0xffc0) == 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f];
|
||||||
return apuram[addr];
|
return apuram[addr];
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,23 +4,23 @@ auto SMP::serialize(serializer& s) -> void {
|
||||||
|
|
||||||
s.array(apuram);
|
s.array(apuram);
|
||||||
|
|
||||||
s.integer(status.clockCounter);
|
s.integer(io.clockCounter);
|
||||||
s.integer(status.dspCounter);
|
s.integer(io.dspCounter);
|
||||||
s.integer(status.timerStep);
|
s.integer(io.timerStep);
|
||||||
|
|
||||||
s.integer(status.clockSpeed);
|
s.integer(io.clockSpeed);
|
||||||
s.integer(status.timerSpeed);
|
s.integer(io.timerSpeed);
|
||||||
s.integer(status.timersEnable);
|
s.integer(io.timersEnable);
|
||||||
s.integer(status.ramDisable);
|
s.integer(io.ramDisable);
|
||||||
s.integer(status.ramWritable);
|
s.integer(io.ramWritable);
|
||||||
s.integer(status.timersDisable);
|
s.integer(io.timersDisable);
|
||||||
|
|
||||||
s.integer(status.iplromEnable);
|
s.integer(io.iplromEnable);
|
||||||
|
|
||||||
s.integer(status.dspAddr);
|
s.integer(io.dspAddr);
|
||||||
|
|
||||||
s.integer(status.ram00f8);
|
s.integer(io.ram00f8);
|
||||||
s.integer(status.ram00f9);
|
s.integer(io.ram00f9);
|
||||||
|
|
||||||
s.integer(timer0.stage0);
|
s.integer(timer0.stage0);
|
||||||
s.integer(timer0.stage1);
|
s.integer(timer0.stage1);
|
||||||
|
|
|
@ -8,11 +8,6 @@ SMP smp;
|
||||||
#include "timing.cpp"
|
#include "timing.cpp"
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
|
|
||||||
auto SMP::step(uint clocks) -> void {
|
|
||||||
clock += clocks * (uint64)cpu.frequency;
|
|
||||||
dsp.clock -= clocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SMP::synchronizeCPU() -> void {
|
auto SMP::synchronizeCPU() -> void {
|
||||||
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
||||||
}
|
}
|
||||||
|
@ -63,27 +58,27 @@ auto SMP::reset() -> void {
|
||||||
apuram[0x00f6] = 0x00;
|
apuram[0x00f6] = 0x00;
|
||||||
apuram[0x00f7] = 0x00;
|
apuram[0x00f7] = 0x00;
|
||||||
|
|
||||||
status.clockCounter = 0;
|
io.clockCounter = 0;
|
||||||
status.dspCounter = 0;
|
io.dspCounter = 0;
|
||||||
status.timerStep = 3;
|
io.timerStep = 3;
|
||||||
|
|
||||||
//$00f0
|
//$00f0
|
||||||
status.clockSpeed = 0;
|
io.clockSpeed = 0;
|
||||||
status.timerSpeed = 0;
|
io.timerSpeed = 0;
|
||||||
status.timersEnable = true;
|
io.timersEnable = true;
|
||||||
status.ramDisable = false;
|
io.ramDisable = false;
|
||||||
status.ramWritable = true;
|
io.ramWritable = true;
|
||||||
status.timersDisable = false;
|
io.timersDisable = false;
|
||||||
|
|
||||||
//$00f1
|
//$00f1
|
||||||
status.iplromEnable = true;
|
io.iplromEnable = true;
|
||||||
|
|
||||||
//$00f2
|
//$00f2
|
||||||
status.dspAddr = 0x00;
|
io.dspAddr = 0x00;
|
||||||
|
|
||||||
//$00f8,$00f9
|
//$00f8,$00f9
|
||||||
status.ram00f8 = 0x00;
|
io.ram00f8 = 0x00;
|
||||||
status.ram00f9 = 0x00;
|
io.ram00f9 = 0x00;
|
||||||
|
|
||||||
timer0.stage0 = 0;
|
timer0.stage0 = 0;
|
||||||
timer1.stage0 = 0;
|
timer1.stage0 = 0;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//Sony CXP1100Q-1
|
//Sony CXP1100Q-1
|
||||||
|
|
||||||
struct SMP : Processor::SPC700, Thread {
|
struct SMP : Processor::SPC700, Thread {
|
||||||
alwaysinline auto step(uint clocks) -> void;
|
|
||||||
alwaysinline auto synchronizeCPU() -> void;
|
alwaysinline auto synchronizeCPU() -> void;
|
||||||
alwaysinline auto synchronizeDSP() -> void;
|
alwaysinline auto synchronizeDSP() -> void;
|
||||||
|
|
||||||
|
@ -19,7 +18,7 @@ struct SMP : Processor::SPC700, Thread {
|
||||||
uint8 apuram[64 * 1024];
|
uint8 apuram[64 * 1024];
|
||||||
|
|
||||||
privileged:
|
privileged:
|
||||||
struct {
|
struct IO {
|
||||||
//timing
|
//timing
|
||||||
uint clockCounter;
|
uint clockCounter;
|
||||||
uint dspCounter;
|
uint dspCounter;
|
||||||
|
@ -42,7 +41,7 @@ privileged:
|
||||||
//$00f8,$00f9
|
//$00f8,$00f9
|
||||||
uint8 ram00f8;
|
uint8 ram00f8;
|
||||||
uint8 ram00f9;
|
uint8 ram00f9;
|
||||||
} status;
|
} io;
|
||||||
|
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
|
|
||||||
|
@ -53,15 +52,14 @@ privileged:
|
||||||
auto readBus(uint16 addr) -> uint8;
|
auto readBus(uint16 addr) -> uint8;
|
||||||
auto writeBus(uint16 addr, uint8 data) -> void;
|
auto writeBus(uint16 addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto io() -> void override;
|
auto idle() -> void override;
|
||||||
auto read(uint16 addr) -> uint8 override;
|
auto read(uint16 addr) -> uint8 override;
|
||||||
auto write(uint16 addr, uint8 data) -> void override;
|
auto write(uint16 addr, uint8 data) -> void override;
|
||||||
|
|
||||||
auto readDisassembler(uint16 addr) -> uint8 override;
|
auto readDisassembler(uint16 addr) -> uint8 override;
|
||||||
|
|
||||||
//timing.cpp
|
//timing.cpp
|
||||||
template<uint Frequency>
|
template<uint Frequency> struct Timer {
|
||||||
struct Timer {
|
|
||||||
uint8 stage0;
|
uint8 stage0;
|
||||||
uint8 stage1;
|
uint8 stage1;
|
||||||
uint8 stage2;
|
uint8 stage2;
|
||||||
|
@ -78,7 +76,7 @@ privileged:
|
||||||
Timer<192> timer1;
|
Timer<192> timer1;
|
||||||
Timer< 24> timer2;
|
Timer< 24> timer2;
|
||||||
|
|
||||||
alwaysinline auto addClocks(uint clocks) -> void;
|
alwaysinline auto step(uint clocks) -> void;
|
||||||
alwaysinline auto cycleEdge() -> void;
|
alwaysinline auto cycleEdge() -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
auto SMP::addClocks(uint clocks) -> void {
|
auto SMP::step(uint clocks) -> void {
|
||||||
step(clocks);
|
clock += clocks * (uint64)cpu.frequency;
|
||||||
|
dsp.clock -= clocks;
|
||||||
synchronizeDSP();
|
synchronizeDSP();
|
||||||
|
|
||||||
#if defined(DEBUGGER)
|
#if defined(DEBUGGER)
|
||||||
|
@ -18,18 +19,17 @@ auto SMP::cycleEdge() -> void {
|
||||||
|
|
||||||
//TEST register S-SMP speed control
|
//TEST register S-SMP speed control
|
||||||
//24 clocks have already been added for this cycle at this point
|
//24 clocks have already been added for this cycle at this point
|
||||||
switch(status.clockSpeed) {
|
switch(io.clockSpeed) {
|
||||||
case 0: break; //100% speed
|
case 0: break; //100% speed
|
||||||
case 1: addClocks(24); break; // 50% speed
|
case 1: step(24); break; // 50% speed
|
||||||
case 2: while(true) addClocks(24); // 0% speed -- locks S-SMP
|
case 2: while(true) step(24); // 0% speed -- locks S-SMP
|
||||||
case 3: addClocks(24 * 9); break; // 10% speed
|
case 3: step(24 * 9); break; // 10% speed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned Frequency>
|
template<uint Frequency> auto SMP::Timer<Frequency>::tick() -> void {
|
||||||
auto SMP::Timer<Frequency>::tick() -> void {
|
|
||||||
//stage 0 increment
|
//stage 0 increment
|
||||||
stage0 += smp.status.timerStep;
|
stage0 += smp.io.timerStep;
|
||||||
if(stage0 < Frequency) return;
|
if(stage0 < Frequency) return;
|
||||||
stage0 -= Frequency;
|
stage0 -= Frequency;
|
||||||
|
|
||||||
|
@ -38,18 +38,17 @@ auto SMP::Timer<Frequency>::tick() -> void {
|
||||||
synchronizeStage1();
|
synchronizeStage1();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned Frequency>
|
template<uint Frequency> auto SMP::Timer<Frequency>::synchronizeStage1() -> void {
|
||||||
auto SMP::Timer<Frequency>::synchronizeStage1() -> void {
|
|
||||||
bool newLine = stage1;
|
bool newLine = stage1;
|
||||||
if(smp.status.timersEnable == false) newLine = false;
|
if(!smp.io.timersEnable) newLine = false;
|
||||||
if(smp.status.timersDisable == true) newLine = false;
|
if(smp.io.timersDisable) newLine = false;
|
||||||
|
|
||||||
bool oldLine = line;
|
bool oldLine = line;
|
||||||
line = newLine;
|
line = newLine;
|
||||||
if(oldLine != 1 || newLine != 0) return; //only pulse on 1->0 transition
|
if(oldLine != 1 || newLine != 0) return; //only pulse on 1->0 transition
|
||||||
|
|
||||||
//stage 2 increment
|
//stage 2 increment
|
||||||
if(enable == false) return;
|
if(!enable) return;
|
||||||
if(++stage2 != target) return;
|
if(++stage2 != target) return;
|
||||||
|
|
||||||
//stage 3 increment
|
//stage 3 increment
|
||||||
|
|
|
@ -105,7 +105,7 @@ auto Program::inputRumble(uint port, uint device, uint input, bool enable) -> vo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::dipSettings(const Markup::Node& node) -> uint {
|
auto Program::dipSettings(Markup::Node node) -> uint {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ struct Program : Emulator::Interface::Bind {
|
||||||
auto audioSample(const double* samples, uint channels) -> void override;
|
auto audioSample(const double* samples, uint channels) -> void override;
|
||||||
auto inputPoll(uint port, uint device, uint input) -> int16 override;
|
auto inputPoll(uint port, uint device, uint input) -> int16 override;
|
||||||
auto inputRumble(uint port, uint device, uint input, bool enable) -> void override;
|
auto inputRumble(uint port, uint device, uint input, bool enable) -> void override;
|
||||||
auto dipSettings(const Markup::Node& node) -> uint override;
|
auto dipSettings(Markup::Node node) -> uint override;
|
||||||
auto notify(string text) -> void override;
|
auto notify(string text) -> void override;
|
||||||
|
|
||||||
//medium.cpp
|
//medium.cpp
|
||||||
|
|
|
@ -2,7 +2,7 @@ auto Program::stateName(uint slot, bool manager) -> string {
|
||||||
return {
|
return {
|
||||||
mediumPaths(1), "higan/states/",
|
mediumPaths(1), "higan/states/",
|
||||||
manager ? "managed/" : "quick/",
|
manager ? "managed/" : "quick/",
|
||||||
"slot-", natural(slot, 2L), ".bst"
|
"slot-", numeral(slot, 2L), ".bst"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,8 +146,8 @@ auto Interface::cheatSet(const lstring& list) -> void {
|
||||||
lstring codes = codeset.split("+");
|
lstring codes = codeset.split("+");
|
||||||
for(auto& code : codes) {
|
for(auto& code : codes) {
|
||||||
lstring part = code.split("/");
|
lstring part = code.split("/");
|
||||||
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1]));
|
if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex());
|
||||||
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,8 @@ auto pViewport::destruct() -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pViewport::handle() const -> uintptr {
|
auto pViewport::handle() const -> uintptr_t {
|
||||||
return (uintptr)cocoaViewport;
|
return (uintptr_t)cocoaViewport;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pViewport::setDroppable(bool droppable) -> void {
|
auto pViewport::setDroppable(bool droppable) -> void {
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace hiro {
|
||||||
struct pViewport : pWidget {
|
struct pViewport : pWidget {
|
||||||
Declare(Viewport, Widget)
|
Declare(Viewport, Widget)
|
||||||
|
|
||||||
auto handle() const -> uintptr;
|
auto handle() const -> uintptr_t;
|
||||||
auto setDroppable(bool droppable) -> void;
|
auto setDroppable(bool droppable) -> void;
|
||||||
|
|
||||||
CocoaViewport* cocoaViewport = nullptr;
|
CocoaViewport* cocoaViewport = nullptr;
|
||||||
|
|
|
@ -193,7 +193,7 @@ auto pIconView::_updateSelected() -> void {
|
||||||
while(p) {
|
while(p) {
|
||||||
auto path = (GtkTreePath*)p->data;
|
auto path = (GtkTreePath*)p->data;
|
||||||
char* pathString = gtk_tree_path_to_string(path);
|
char* pathString = gtk_tree_path_to_string(path);
|
||||||
unsigned position = natural(pathString);
|
unsigned position = toNatural(pathString);
|
||||||
g_free(pathString);
|
g_free(pathString);
|
||||||
selected.append(position);
|
selected.append(position);
|
||||||
p = p->next;
|
p = p->next;
|
||||||
|
|
|
@ -218,7 +218,7 @@ auto pTableView::_doContext() -> void {
|
||||||
|
|
||||||
auto pTableView::_doDataFunc(GtkTreeViewColumn* gtkColumn, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void {
|
auto pTableView::_doDataFunc(GtkTreeViewColumn* gtkColumn, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void {
|
||||||
auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter);
|
auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter);
|
||||||
auto row = natural(path);
|
auto row = toNatural(path);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
|
|
||||||
if(auto& header = state().header) {
|
if(auto& header = state().header) {
|
||||||
|
@ -271,7 +271,7 @@ auto pTableView::_doEdit(GtkCellRendererText* gtkCellRendererText, const char* p
|
||||||
for(auto& column : header->state.columns) {
|
for(auto& column : header->state.columns) {
|
||||||
if(auto delegate = column->self()) {
|
if(auto delegate = column->self()) {
|
||||||
if(gtkCellRendererText == GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) {
|
if(gtkCellRendererText == GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) {
|
||||||
auto row = natural(path);
|
auto row = toNatural(path);
|
||||||
if(auto item = self().item(row)) {
|
if(auto item = self().item(row)) {
|
||||||
if(auto cell = item->cell(column->offset())) {
|
if(auto cell = item->cell(column->offset())) {
|
||||||
if(string{text} != cell->state.text) {
|
if(string{text} != cell->state.text) {
|
||||||
|
@ -343,7 +343,7 @@ auto pTableView::_doToggle(GtkCellRendererToggle* gtkCellRendererToggle, const c
|
||||||
for(auto& column : header->state.columns) {
|
for(auto& column : header->state.columns) {
|
||||||
if(auto delegate = column->self()) {
|
if(auto delegate = column->self()) {
|
||||||
if(gtkCellRendererToggle == GTK_CELL_RENDERER_TOGGLE(delegate->gtkCellToggle)) {
|
if(gtkCellRendererToggle == GTK_CELL_RENDERER_TOGGLE(delegate->gtkCellToggle)) {
|
||||||
auto row = natural(path);
|
auto row = toNatural(path);
|
||||||
if(auto item = self().item(row)) {
|
if(auto item = self().item(row)) {
|
||||||
if(auto cell = item->cell(column->offset())) {
|
if(auto cell = item->cell(column->offset())) {
|
||||||
cell->setChecked(!cell->checked());
|
cell->setChecked(!cell->checked());
|
||||||
|
@ -371,7 +371,7 @@ auto pTableView::_updateSelected() -> void {
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
if(gtk_tree_model_get_iter(gtkTreeModel, &iter, (GtkTreePath*)p->data)) {
|
if(gtk_tree_model_get_iter(gtkTreeModel, &iter, (GtkTreePath*)p->data)) {
|
||||||
char* pathname = gtk_tree_model_get_string_from_iter(gtkTreeModel, &iter);
|
char* pathname = gtk_tree_model_get_string_from_iter(gtkTreeModel, &iter);
|
||||||
unsigned selection = natural(pathname);
|
unsigned selection = toNatural(pathname);
|
||||||
g_free(pathname);
|
g_free(pathname);
|
||||||
selected.append(selection);
|
selected.append(selection);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,83 +4,83 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
constexpr inline auto binary_(const char* s, uintmax sum = 0) -> uintmax {
|
constexpr inline auto toBinary_(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||||
return (
|
return (
|
||||||
*s == '0' || *s == '1' ? binary_(s + 1, (sum << 1) | *s - '0') :
|
*s == '0' || *s == '1' ? toBinary_(s + 1, (sum << 1) | *s - '0') :
|
||||||
*s == '\'' ? binary_(s + 1, sum) :
|
*s == '\'' ? toBinary_(s + 1, sum) :
|
||||||
sum
|
sum
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline auto octal_(const char* s, uintmax sum = 0) -> uintmax {
|
constexpr inline auto toOctal_(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||||
return (
|
return (
|
||||||
*s >= '0' && *s <= '7' ? octal_(s + 1, (sum << 3) | *s - '0') :
|
*s >= '0' && *s <= '7' ? toOctal_(s + 1, (sum << 3) | *s - '0') :
|
||||||
*s == '\'' ? octal_(s + 1, sum) :
|
*s == '\'' ? toOctal_(s + 1, sum) :
|
||||||
sum
|
sum
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline auto decimal_(const char* s, uintmax sum = 0) -> uintmax {
|
constexpr inline auto toDecimal_(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||||
return (
|
return (
|
||||||
*s >= '0' && *s <= '9' ? decimal_(s + 1, (sum * 10) + *s - '0') :
|
*s >= '0' && *s <= '9' ? toDecimal_(s + 1, (sum * 10) + *s - '0') :
|
||||||
*s == '\'' ? decimal_(s + 1, sum) :
|
*s == '\'' ? toDecimal_(s + 1, sum) :
|
||||||
sum
|
sum
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline auto hex_(const char* s, uintmax sum = 0) -> uintmax {
|
constexpr inline auto toHex_(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||||
return (
|
return (
|
||||||
*s >= 'A' && *s <= 'F' ? hex_(s + 1, (sum << 4) | *s - 'A' + 10) :
|
*s >= 'A' && *s <= 'F' ? toHex_(s + 1, (sum << 4) | *s - 'A' + 10) :
|
||||||
*s >= 'a' && *s <= 'f' ? hex_(s + 1, (sum << 4) | *s - 'a' + 10) :
|
*s >= 'a' && *s <= 'f' ? toHex_(s + 1, (sum << 4) | *s - 'a' + 10) :
|
||||||
*s >= '0' && *s <= '9' ? hex_(s + 1, (sum << 4) | *s - '0') :
|
*s >= '0' && *s <= '9' ? toHex_(s + 1, (sum << 4) | *s - '0') :
|
||||||
*s == '\'' ? hex_(s + 1, sum) :
|
*s == '\'' ? toHex_(s + 1, sum) :
|
||||||
sum
|
sum
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
constexpr inline auto binary(const char* s) -> uintmax {
|
constexpr inline auto toBinary(const char* s) -> uintmax_t {
|
||||||
return (
|
return (
|
||||||
*s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? binary_(s + 2) :
|
*s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? toBinary_(s + 2) :
|
||||||
*s == '%' ? binary_(s + 1) : binary_(s)
|
*s == '%' ? toBinary_(s + 1) : toBinary_(s)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline auto octal(const char* s) -> uintmax {
|
constexpr inline auto toOctal(const char* s) -> uintmax_t {
|
||||||
return (
|
return (
|
||||||
*s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? octal_(s + 2) :
|
*s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? toOctal_(s + 2) :
|
||||||
octal_(s)
|
toOctal_(s)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline auto hex(const char* s) -> uintmax {
|
constexpr inline auto toHex(const char* s) -> uintmax_t {
|
||||||
return (
|
return (
|
||||||
*s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? hex_(s + 2) :
|
*s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? toHex_(s + 2) :
|
||||||
*s == '$' ? hex_(s + 1) : hex_(s)
|
*s == '$' ? toHex_(s + 1) : toHex_(s)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
constexpr inline auto natural(const char* s) -> uintmax {
|
constexpr inline auto toNatural(const char* s) -> uintmax_t {
|
||||||
return (
|
return (
|
||||||
*s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? binary_(s + 2) :
|
*s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? toBinary_(s + 2) :
|
||||||
*s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? octal_(s + 2) :
|
*s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? toOctal_(s + 2) :
|
||||||
*s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? hex_(s + 2) :
|
*s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? toHex_(s + 2) :
|
||||||
*s == '%' ? binary_(s + 1) : *s == '$' ? hex_(s + 1) : decimal_(s)
|
*s == '%' ? toBinary_(s + 1) : *s == '$' ? toHex_(s + 1) : toDecimal_(s)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline auto integer(const char* s) -> intmax {
|
constexpr inline auto toInteger(const char* s) -> intmax_t {
|
||||||
return (
|
return (
|
||||||
*s == '+' ? +natural(s + 1) : *s == '-' ? -natural(s + 1) : natural(s)
|
*s == '+' ? +toNatural(s + 1) : *s == '-' ? -toNatural(s + 1) : toNatural(s)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
inline auto real(const char* s) -> double {
|
inline auto toReal(const char* s) -> double {
|
||||||
return atof(s);
|
return atof(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
nall/bit.hpp
32
nall/bit.hpp
|
@ -4,28 +4,28 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<uint bits> inline auto uclamp(const uintmax x) -> uintmax {
|
template<uint bits> inline auto uclamp(const uintmax_t x) -> uintmax_t {
|
||||||
enum : uintmax { b = 1ull << (bits - 1), y = b * 2 - 1 };
|
enum : uintmax_t { b = 1ull << (bits - 1), y = b * 2 - 1 };
|
||||||
return y + ((x - y) & -(x < y)); //min(x, y);
|
return y + ((x - y) & -(x < y)); //min(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint bits> inline auto uclip(const uintmax x) -> uintmax {
|
template<uint bits> inline auto uclip(const uintmax_t x) -> uintmax_t {
|
||||||
enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
||||||
return (x & m);
|
return (x & m);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint bits> inline auto sclamp(const intmax x) -> intmax {
|
template<uint bits> inline auto sclamp(const intmax_t x) -> intmax_t {
|
||||||
enum : intmax { b = 1ull << (bits - 1), m = b - 1 };
|
enum : intmax_t { b = 1ull << (bits - 1), m = b - 1 };
|
||||||
return (x > m) ? m : (x < -b) ? -b : x;
|
return (x > m) ? m : (x < -b) ? -b : x;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint bits> inline auto sclip(const intmax x) -> intmax {
|
template<uint bits> inline auto sclip(const intmax_t x) -> intmax_t {
|
||||||
enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
||||||
return ((x & m) ^ b) - b;
|
return ((x & m) ^ b) - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace bit {
|
namespace bit {
|
||||||
constexpr inline auto mask(const char* s, uintmax sum = 0) -> uintmax {
|
constexpr inline auto mask(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||||
return (
|
return (
|
||||||
*s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) :
|
*s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) :
|
||||||
*s == ' ' || *s == '_' ? mask(s + 1, sum) :
|
*s == ' ' || *s == '_' ? mask(s + 1, sum) :
|
||||||
|
@ -34,7 +34,7 @@ namespace bit {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline auto test(const char* s, uintmax sum = 0) -> uintmax {
|
constexpr inline auto test(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||||
return (
|
return (
|
||||||
*s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) :
|
*s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) :
|
||||||
*s == ' ' || *s == '_' ? test(s + 1, sum) :
|
*s == ' ' || *s == '_' ? test(s + 1, sum) :
|
||||||
|
@ -44,22 +44,22 @@ namespace bit {
|
||||||
}
|
}
|
||||||
|
|
||||||
//lowest(0b1110) == 0b0010
|
//lowest(0b1110) == 0b0010
|
||||||
constexpr inline auto lowest(const uintmax x) -> uintmax {
|
constexpr inline auto lowest(const uintmax_t x) -> uintmax_t {
|
||||||
return x & -x;
|
return x & -x;
|
||||||
}
|
}
|
||||||
|
|
||||||
//clear_lowest(0b1110) == 0b1100
|
//clear_lowest(0b1110) == 0b1100
|
||||||
constexpr inline auto clearLowest(const uintmax x) -> uintmax {
|
constexpr inline auto clearLowest(const uintmax_t x) -> uintmax_t {
|
||||||
return x & (x - 1);
|
return x & (x - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//set_lowest(0b0101) == 0b0111
|
//set_lowest(0b0101) == 0b0111
|
||||||
constexpr inline auto setLowest(const uintmax x) -> uintmax {
|
constexpr inline auto setLowest(const uintmax_t x) -> uintmax_t {
|
||||||
return x | (x + 1);
|
return x | (x + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//count number of bits set in a byte
|
//count number of bits set in a byte
|
||||||
inline auto count(uintmax x) -> uint {
|
inline auto count(uintmax_t x) -> uint {
|
||||||
uint count = 0;
|
uint count = 0;
|
||||||
do count += x & 1; while(x >>= 1);
|
do count += x & 1; while(x >>= 1);
|
||||||
return count;
|
return count;
|
||||||
|
@ -67,7 +67,7 @@ namespace bit {
|
||||||
|
|
||||||
//return index of the first bit set (or zero of no bits are set)
|
//return index of the first bit set (or zero of no bits are set)
|
||||||
//first(0b1000) == 3
|
//first(0b1000) == 3
|
||||||
inline auto first(uintmax x) -> uint {
|
inline auto first(uintmax_t x) -> uint {
|
||||||
uint first = 0;
|
uint first = 0;
|
||||||
while(x) { if(x & 1) break; x >>= 1; first++; }
|
while(x) { if(x & 1) break; x >>= 1; first++; }
|
||||||
return first;
|
return first;
|
||||||
|
@ -75,7 +75,7 @@ namespace bit {
|
||||||
|
|
||||||
//round up to next highest single bit:
|
//round up to next highest single bit:
|
||||||
//round(15) == 16, round(16) == 16, round(17) == 32
|
//round(15) == 16, round(16) == 16, round(17) == 32
|
||||||
inline auto round(uintmax x) -> uintmax {
|
inline auto round(uintmax_t x) -> uintmax_t {
|
||||||
if((x & (x - 1)) == 0) return x;
|
if((x & (x - 1)) == 0) return x;
|
||||||
while(x & (x - 1)) x &= x - 1;
|
while(x & (x - 1)) x &= x - 1;
|
||||||
return x << 1;
|
return x << 1;
|
||||||
|
|
|
@ -30,9 +30,9 @@ struct Node {
|
||||||
auto set(const string& value) -> void {
|
auto set(const string& value) -> void {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case Type::Boolean: *(bool*)data = (value != "false"); break;
|
case Type::Boolean: *(bool*)data = (value != "false"); break;
|
||||||
case Type::Integer: *(int*)data = integer(value); break;
|
case Type::Integer: *(int*)data = toInteger(value); break;
|
||||||
case Type::Natural: *(uint*)data = natural(value); break;
|
case Type::Natural: *(uint*)data = toNatural(value); break;
|
||||||
case Type::Double: *(double*)data = real(value); break;
|
case Type::Double: *(double*)data = toReal(value); break;
|
||||||
case Type::String: *(string*)data = value; break;
|
case Type::String: *(string*)data = value; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ struct file : inode, varint {
|
||||||
return !(data.st_mode & S_IFDIR);
|
return !(data.st_mode & S_IFDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto size(const string& filename) -> uintmax {
|
static auto size(const string& filename) -> uintmax_t {
|
||||||
#if defined(API_POSIX)
|
#if defined(API_POSIX)
|
||||||
struct stat data;
|
struct stat data;
|
||||||
stat(filename, &data);
|
stat(filename, &data);
|
||||||
|
@ -127,16 +127,16 @@ struct file : inode, varint {
|
||||||
return buffer[(file_offset++) & buffer_mask];
|
return buffer[(file_offset++) & buffer_mask];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto readl(uint length = 1) -> uintmax {
|
auto readl(uint length = 1) -> uintmax_t {
|
||||||
uintmax data = 0;
|
uintmax_t data = 0;
|
||||||
for(int i = 0; i < length; i++) {
|
for(int i = 0; i < length; i++) {
|
||||||
data |= (uintmax)read() << (i << 3);
|
data |= (uintmax_t)read() << (i << 3);
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto readm(uint length = 1) -> uintmax {
|
auto readm(uint length = 1) -> uintmax_t {
|
||||||
uintmax data = 0;
|
uintmax_t data = 0;
|
||||||
while(length--) {
|
while(length--) {
|
||||||
data <<= 8;
|
data <<= 8;
|
||||||
data |= read();
|
data |= read();
|
||||||
|
@ -164,14 +164,14 @@ struct file : inode, varint {
|
||||||
if(file_offset > file_size) file_size = file_offset;
|
if(file_offset > file_size) file_size = file_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writel(uintmax data, uint length = 1) -> void {
|
auto writel(uintmax_t data, uint length = 1) -> void {
|
||||||
while(length--) {
|
while(length--) {
|
||||||
write(data);
|
write(data);
|
||||||
data >>= 8;
|
data >>= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writem(uintmax data, uint length = 1) -> void {
|
auto writem(uintmax_t data, uint length = 1) -> void {
|
||||||
for(int i = length - 1; i >= 0; i--) {
|
for(int i = length - 1; i >= 0; i--) {
|
||||||
write(data >> (i << 3));
|
write(data >> (i << 3));
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,7 @@ struct file : inode, varint {
|
||||||
if(!fp) return; //file not open
|
if(!fp) return; //file not open
|
||||||
buffer_flush();
|
buffer_flush();
|
||||||
|
|
||||||
intmax req_offset = file_offset;
|
intmax_t req_offset = file_offset;
|
||||||
switch(index_) {
|
switch(index_) {
|
||||||
case index::absolute: req_offset = offset; break;
|
case index::absolute: req_offset = offset; break;
|
||||||
case index::relative: req_offset += offset; break;
|
case index::relative: req_offset += offset; break;
|
||||||
|
|
|
@ -94,7 +94,7 @@ auto Response::setHead() -> bool {
|
||||||
else if(response.ibeginsWith("HTTP/1.1 ")) response.itrimLeft("HTTP/1.1 ", 1L);
|
else if(response.ibeginsWith("HTTP/1.1 ")) response.itrimLeft("HTTP/1.1 ", 1L);
|
||||||
else return false;
|
else return false;
|
||||||
|
|
||||||
setResponseType(natural(response));
|
setResponseType(response.natural());
|
||||||
|
|
||||||
for(auto& header : headers) {
|
for(auto& header : headers) {
|
||||||
if(header.beginsWith(" ") || header.beginsWith("\t")) continue;
|
if(header.beginsWith(" ") || header.beginsWith("\t")) continue;
|
||||||
|
|
|
@ -101,7 +101,7 @@ auto Role::download(signed fd, Message& message) -> bool {
|
||||||
|
|
||||||
if(chunk.endsWith("\r\n") || chunk.endsWith("\n")) {
|
if(chunk.endsWith("\r\n") || chunk.endsWith("\n")) {
|
||||||
chunkReceived = true;
|
chunkReceived = true;
|
||||||
chunkLength = hex(chunk);
|
chunkLength = chunk.hex();
|
||||||
if(chunkLength == 0) break;
|
if(chunkLength == 0) break;
|
||||||
chunk.reset();
|
chunk.reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,29 +31,29 @@ auto service::command(const string& name, const string& command) -> bool {
|
||||||
" stop : stop service if it is running\n"
|
" stop : stop service if it is running\n"
|
||||||
" remove : remove semaphore lock if service crashed\n"
|
" remove : remove semaphore lock if service crashed\n"
|
||||||
" {value} : send custom command to service\n"
|
" {value} : send custom command to service\n"
|
||||||
"", format{name}), false;
|
"", string_format{name}), false;
|
||||||
|
|
||||||
if(shared.open(name, 4096)) {
|
if(shared.open(name, 4096)) {
|
||||||
if(command == "start") {
|
if(command == "start") {
|
||||||
print("[{0}] already started\n", format{name});
|
print("[{0}] already started\n", string_format{name});
|
||||||
} else if(command == "status") {
|
} else if(command == "status") {
|
||||||
print("[{0}] running\n", format{name});
|
print("[{0}] running\n", string_format{name});
|
||||||
}
|
}
|
||||||
if(auto data = shared.acquire()) {
|
if(auto data = shared.acquire()) {
|
||||||
if(command == "stop") print("[{0}] stopped\n", format{name});
|
if(command == "stop") print("[{0}] stopped\n", string_format{name});
|
||||||
memory::copy(data, command.data(), min(command.size(), 4096));
|
memory::copy(data, command.data(), min(command.size(), 4096));
|
||||||
shared.release();
|
shared.release();
|
||||||
}
|
}
|
||||||
if(command == "remove") {
|
if(command == "remove") {
|
||||||
shared.remove();
|
shared.remove();
|
||||||
print("[{0}] removed\n", format{name});
|
print("[{0}] removed\n", string_format{name});
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(command == "start") {
|
if(command == "start") {
|
||||||
if(shared.create(name, 4096)) {
|
if(shared.create(name, 4096)) {
|
||||||
print("[{0}] started\n", format{name});
|
print("[{0}] started\n", string_format{name});
|
||||||
auto pid = fork();
|
auto pid = fork();
|
||||||
if(pid == 0) {
|
if(pid == 0) {
|
||||||
signal(SIGHUP, SIG_IGN);
|
signal(SIGHUP, SIG_IGN);
|
||||||
|
@ -63,13 +63,13 @@ auto service::command(const string& name, const string& command) -> bool {
|
||||||
}
|
}
|
||||||
shared.close();
|
shared.close();
|
||||||
} else {
|
} else {
|
||||||
print("[{0}] start failed ({1})\n", format{name, strerror(errno)});
|
print("[{0}] start failed ({1})\n", string_format{name, strerror(errno)});
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(command == "status") {
|
if(command == "status") {
|
||||||
print("[{0}] stopped\n", format{name});
|
print("[{0}] stopped\n", string_format{name});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,15 +79,15 @@ template<uint Bits> struct Natural {
|
||||||
inline auto bit(uint index) -> Reference { return {*this, index, index}; }
|
inline auto bit(uint index) -> Reference { return {*this, index, index}; }
|
||||||
inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; }
|
inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; }
|
||||||
|
|
||||||
inline auto clamp(uint bits) -> uintmax {
|
inline auto clamp(uint bits) -> uintmax_t {
|
||||||
const uintmax b = 1ull << (bits - 1);
|
const uintmax_t b = 1ull << (bits - 1);
|
||||||
const uintmax m = b * 2 - 1;
|
const uintmax_t m = b * 2 - 1;
|
||||||
return data < m ? data : m;
|
return data < m ? data : m;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto clip(uint bits) -> uintmax {
|
inline auto clip(uint bits) -> uintmax_t {
|
||||||
const uintmax b = 1ull << (bits - 1);
|
const uintmax_t b = 1ull << (bits - 1);
|
||||||
const uintmax m = b * 2 - 1;
|
const uintmax_t m = b * 2 - 1;
|
||||||
return data & m;
|
return data & m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,15 +161,15 @@ template<uint Bits> struct Integer {
|
||||||
inline auto bit(uint index) -> Reference { return {*this, index, index}; }
|
inline auto bit(uint index) -> Reference { return {*this, index, index}; }
|
||||||
inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; }
|
inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; }
|
||||||
|
|
||||||
inline auto clamp(uint bits) -> intmax {
|
inline auto clamp(uint bits) -> intmax_t {
|
||||||
const intmax b = 1ull << (bits - 1);
|
const intmax_t b = 1ull << (bits - 1);
|
||||||
const intmax m = b - 1;
|
const intmax_t m = b - 1;
|
||||||
return data > m ? m : data < -b ? -b : data;
|
return data > m ? m : data < -b ? -b : data;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto clip(uint bits) -> intmax {
|
inline auto clip(uint bits) -> intmax_t {
|
||||||
const uintmax b = 1ull << (bits - 1);
|
const uintmax_t b = 1ull << (bits - 1);
|
||||||
const uintmax m = b * 2 - 1;
|
const uintmax_t m = b * 2 - 1;
|
||||||
return ((data & m) ^ b) - b;
|
return ((data & m) ^ b) - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,8 +185,8 @@ template<uint Bits> struct Real {
|
||||||
using type =
|
using type =
|
||||||
type_if<expression<Bits == 32>, float32_t,
|
type_if<expression<Bits == 32>, float32_t,
|
||||||
type_if<expression<Bits == 64>, float64_t,
|
type_if<expression<Bits == 64>, float64_t,
|
||||||
type_if<expression<Bits == 80>, float80_t,
|
//type_if<expression<Bits == 80>, float80_t,
|
||||||
void>>>;
|
void>>;
|
||||||
|
|
||||||
inline Real() : data(0.0) {}
|
inline Real() : data(0.0) {}
|
||||||
template<typename T> inline Real(const T& value) : data((type)value) {}
|
template<typename T> inline Real(const T& value) : data((type)value) {}
|
||||||
|
@ -215,9 +215,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
using boolean = nall::Boolean;
|
using boolean = nall::Boolean;
|
||||||
//note: these conflict with nall/atoi.hpp functions
|
using integer = nall::Integer<sizeof( int) * 8>;
|
||||||
//using integer = nall::Integer<sizeof( int) * 8>;
|
using natural = nall::Natural<sizeof(uint) * 8>;
|
||||||
//using natural = nall::Natural<sizeof(uint) * 8>;
|
|
||||||
|
|
||||||
using int1 = nall::Integer< 1>;
|
using int1 = nall::Integer< 1>;
|
||||||
using int2 = nall::Integer< 2>;
|
using int2 = nall::Integer< 2>;
|
||||||
|
@ -351,4 +350,4 @@ using uint64 = nall::Natural<64>;
|
||||||
|
|
||||||
using float32 = nall::Real<32>;
|
using float32 = nall::Real<32>;
|
||||||
using float64 = nall::Real<64>;
|
using float64 = nall::Real<64>;
|
||||||
using float80 = nall::Real<80>;
|
//using float80 = nall::Real<80>;
|
||||||
|
|
|
@ -63,10 +63,10 @@ struct serializer {
|
||||||
template<typename T> auto integer(T& value) -> serializer& {
|
template<typename T> auto integer(T& value) -> serializer& {
|
||||||
enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) };
|
enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) };
|
||||||
if(_mode == Save) {
|
if(_mode == Save) {
|
||||||
for(uint n = 0; n < size; n++) _data[_size++] = (uintmax)value >> (n << 3);
|
for(uint n = 0; n < size; n++) _data[_size++] = (uintmax_t)value >> (n << 3);
|
||||||
} else if(_mode == Load) {
|
} else if(_mode == Load) {
|
||||||
value = 0;
|
value = 0;
|
||||||
for(uint n = 0; n < size; n++) value |= (uintmax)_data[_size++] << (n << 3);
|
for(uint n = 0; n < size; n++) value |= (uintmax_t)_data[_size++] << (n << 3);
|
||||||
} else if(_mode == Size) {
|
} else if(_mode == Size) {
|
||||||
_size += size;
|
_size += size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,8 @@
|
||||||
|
|
||||||
using float32_t = float;
|
using float32_t = float;
|
||||||
using float64_t = double;
|
using float64_t = double;
|
||||||
using float80_t = long double;
|
//note: long double size is not reliable across platforms
|
||||||
|
//using float80_t = long double;
|
||||||
|
|
||||||
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
|
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");
|
static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size");
|
||||||
|
@ -47,12 +48,6 @@ 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(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(double) >= 8, "float64_t is not of the correct size");
|
||||||
static_assert(sizeof(long double) >= 10, "float80_t is not of the correct size");
|
//static_assert(sizeof(long double) >= 10, "float80_t is not of the correct size");
|
||||||
|
|
||||||
using intmax = intmax_t;
|
|
||||||
using intptr = intptr_t;
|
|
||||||
|
|
||||||
using uintmax = uintmax_t;
|
|
||||||
using uintptr = uintptr_t;
|
|
||||||
|
|
||||||
using uint = unsigned int;
|
using uint = unsigned int;
|
||||||
|
|
|
@ -24,8 +24,12 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct string;
|
struct string;
|
||||||
struct format;
|
struct string_view;
|
||||||
struct lstring;
|
struct string_vector;
|
||||||
|
struct string_format;
|
||||||
|
|
||||||
|
//legacy naming convention
|
||||||
|
using lstring = string_vector;
|
||||||
|
|
||||||
struct string_view {
|
struct string_view {
|
||||||
inline string_view();
|
inline string_view();
|
||||||
|
@ -61,18 +65,19 @@ template<typename T> struct stringify;
|
||||||
//format.hpp
|
//format.hpp
|
||||||
template<typename... P> inline auto print(P&&...) -> void;
|
template<typename... P> inline auto print(P&&...) -> void;
|
||||||
template<typename... P> inline auto print(FILE*, P&&...) -> void;
|
template<typename... P> inline auto print(FILE*, P&&...) -> void;
|
||||||
inline auto integer(intmax value, long precision = 0, char padchar = '0') -> string;
|
template<typename T> inline auto numeral(T value, long precision = 0, char padchar = '0') -> string;
|
||||||
inline auto natural(uintmax value, long precision = 0, char padchar = '0') -> string;
|
//inline auto integer(intmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||||
inline auto hex(uintmax value, long precision = 0, char padchar = '0') -> string;
|
//inline auto natural(uintmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||||
inline auto octal(uintmax value, long precision = 0, char padchar = '0') -> string;
|
inline auto hex(uintmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||||
inline auto binary(uintmax value, long precision = 0, char padchar = '0') -> string;
|
inline auto octal(uintmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||||
|
inline auto binary(uintmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||||
template<typename T> inline auto pointer(const T* value, long precision = 0) -> string;
|
template<typename T> inline auto pointer(const T* value, long precision = 0) -> string;
|
||||||
inline auto pointer(uintptr value, long precision = 0) -> string;
|
inline auto pointer(uintptr_t value, long precision = 0) -> string;
|
||||||
inline auto real(long double value) -> string;
|
//inline auto real(long double value) -> string;
|
||||||
|
|
||||||
//match.hpp
|
//match.hpp
|
||||||
inline auto tokenize(const char* s, const char* p) -> bool;
|
inline auto tokenize(const char* s, const char* p) -> bool;
|
||||||
inline auto tokenize(lstring& list, const char* s, const char* p) -> bool;
|
inline auto tokenize(string_vector& list, const char* s, const char* p) -> bool;
|
||||||
|
|
||||||
//path.hpp
|
//path.hpp
|
||||||
inline auto pathname(string_view self) -> string;
|
inline auto pathname(string_view self) -> string;
|
||||||
|
@ -85,10 +90,9 @@ inline auto suffixname(string_view self) -> string;
|
||||||
|
|
||||||
//utility.hpp
|
//utility.hpp
|
||||||
inline auto slice(string_view self, int offset = 0, int length = -1) -> string;
|
inline auto slice(string_view self, int offset = 0, int length = -1) -> string;
|
||||||
|
inline auto fromInteger(char* result, intmax_t value) -> char*;
|
||||||
inline auto integer(char* result, intmax value) -> char*;
|
inline auto fromNatural(char* result, uintmax_t value) -> char*;
|
||||||
inline auto natural(char* result, uintmax value) -> char*;
|
inline auto fromReal(char* str, long double value) -> uint;
|
||||||
inline auto real(char* str, long double value) -> uint;
|
|
||||||
|
|
||||||
struct string {
|
struct string {
|
||||||
using type = string;
|
using type = string;
|
||||||
|
@ -179,15 +183,16 @@ public:
|
||||||
auto end() const -> const char* { return &data()[size()]; }
|
auto end() const -> const char* { return &data()[size()]; }
|
||||||
|
|
||||||
//atoi.hpp
|
//atoi.hpp
|
||||||
inline auto integer() const -> intmax;
|
inline auto integer() const -> intmax_t;
|
||||||
inline auto natural() const -> uintmax;
|
inline auto natural() const -> uintmax_t;
|
||||||
|
inline auto hex() const -> uintmax_t;
|
||||||
inline auto real() const -> double;
|
inline auto real() const -> double;
|
||||||
|
|
||||||
//core.hpp
|
//core.hpp
|
||||||
inline auto operator[](int) const -> const char&;
|
inline auto operator[](int) const -> const char&;
|
||||||
template<typename... P> inline auto assign(P&&...) -> type&;
|
template<typename... P> inline auto assign(P&&...) -> type&;
|
||||||
template<typename T, typename... P> inline auto append(const T&, P&&...) -> type&;
|
template<typename T, typename... P> inline auto append(const T&, P&&...) -> type&;
|
||||||
template<typename... P> inline auto append(const nall::format&, P&&...) -> type&;
|
template<typename... P> inline auto append(const nall::string_format&, P&&...) -> type&;
|
||||||
inline auto append() -> type&;
|
inline auto append() -> type&;
|
||||||
template<typename T> inline auto _append(const stringify<T>&) -> string&;
|
template<typename T> inline auto _append(const stringify<T>&) -> string&;
|
||||||
inline auto length() const -> uint;
|
inline auto length() const -> uint;
|
||||||
|
@ -209,7 +214,7 @@ public:
|
||||||
inline auto ifindFrom(int offset, string_view source) const -> maybe<uint>;
|
inline auto ifindFrom(int offset, string_view source) const -> maybe<uint>;
|
||||||
|
|
||||||
//format.hpp
|
//format.hpp
|
||||||
inline auto format(const nall::format& params) -> type&;
|
inline auto format(const nall::string_format& params) -> type&;
|
||||||
|
|
||||||
//compare.hpp
|
//compare.hpp
|
||||||
template<bool> inline static auto _compare(const char*, uint, const char*, uint) -> int;
|
template<bool> inline static auto _compare(const char*, uint, const char*, uint) -> int;
|
||||||
|
@ -250,10 +255,10 @@ public:
|
||||||
inline auto iqreplace(string_view from, string_view to, long limit = LONG_MAX) -> type&;
|
inline auto iqreplace(string_view from, string_view to, long limit = LONG_MAX) -> type&;
|
||||||
|
|
||||||
//split.hpp
|
//split.hpp
|
||||||
inline auto split(string_view key, long limit = LONG_MAX) const -> lstring;
|
inline auto split(string_view key, long limit = LONG_MAX) const -> string_vector;
|
||||||
inline auto isplit(string_view key, long limit = LONG_MAX) const -> lstring;
|
inline auto isplit(string_view key, long limit = LONG_MAX) const -> string_vector;
|
||||||
inline auto qsplit(string_view key, long limit = LONG_MAX) const -> lstring;
|
inline auto qsplit(string_view key, long limit = LONG_MAX) const -> string_vector;
|
||||||
inline auto iqsplit(string_view key, long limit = LONG_MAX) const -> lstring;
|
inline auto iqsplit(string_view key, long limit = LONG_MAX) const -> string_vector;
|
||||||
|
|
||||||
//trim.hpp
|
//trim.hpp
|
||||||
inline auto trim(string_view lhs, string_view rhs, long limit = LONG_MAX) -> type&;
|
inline auto trim(string_view lhs, string_view rhs, long limit = LONG_MAX) -> type&;
|
||||||
|
@ -278,21 +283,21 @@ public:
|
||||||
inline auto size(int length, char fill = ' ') -> type&;
|
inline auto size(int length, char fill = ' ') -> type&;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lstring : vector<string> {
|
struct string_vector : vector<string> {
|
||||||
using type = lstring;
|
using type = string_vector;
|
||||||
|
|
||||||
lstring(const lstring& source) { vector::operator=(source); }
|
string_vector(const string_vector& source) { vector::operator=(source); }
|
||||||
lstring(lstring& source) { vector::operator=(source); }
|
string_vector(string_vector& source) { vector::operator=(source); }
|
||||||
lstring(lstring&& source) { vector::operator=(move(source)); }
|
string_vector(string_vector&& source) { vector::operator=(move(source)); }
|
||||||
template<typename... P> lstring(P&&... p) { append(forward<P>(p)...); }
|
template<typename... P> string_vector(P&&... p) { append(forward<P>(p)...); }
|
||||||
|
|
||||||
//list.hpp
|
//list.hpp
|
||||||
inline auto operator==(const lstring&) const -> bool;
|
inline auto operator==(const string_vector&) const -> bool;
|
||||||
inline auto operator!=(const lstring&) const -> bool;
|
inline auto operator!=(const string_vector&) const -> bool;
|
||||||
|
|
||||||
inline auto operator=(const lstring& source) -> type& { return vector::operator=(source), *this; }
|
inline auto operator=(const string_vector& source) -> type& { return vector::operator=(source), *this; }
|
||||||
inline auto operator=(lstring& source) -> type& { return vector::operator=(source), *this; }
|
inline auto operator=(string_vector& source) -> type& { return vector::operator=(source), *this; }
|
||||||
inline auto operator=(lstring&& source) -> type& { return vector::operator=(move(source)), *this; }
|
inline auto operator=(string_vector&& source) -> type& { return vector::operator=(move(source)), *this; }
|
||||||
|
|
||||||
inline auto isort() -> type&;
|
inline auto isort() -> type&;
|
||||||
|
|
||||||
|
@ -301,18 +306,18 @@ struct lstring : vector<string> {
|
||||||
|
|
||||||
inline auto find(string_view source) const -> maybe<uint>;
|
inline auto find(string_view source) const -> maybe<uint>;
|
||||||
inline auto ifind(string_view source) const -> maybe<uint>;
|
inline auto ifind(string_view source) const -> maybe<uint>;
|
||||||
inline auto match(string_view pattern) const -> lstring;
|
inline auto match(string_view pattern) const -> string_vector;
|
||||||
inline auto merge(string_view separator) const -> string;
|
inline auto merge(string_view separator) const -> string;
|
||||||
inline auto strip() -> type&;
|
inline auto strip() -> type&;
|
||||||
|
|
||||||
//split.hpp
|
//split.hpp
|
||||||
template<bool, bool> inline auto _split(string_view, string_view, long) -> lstring&;
|
template<bool, bool> inline auto _split(string_view, string_view, long) -> type&;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct format : vector<string> {
|
struct string_format : vector<string> {
|
||||||
using type = format;
|
using type = string_format;
|
||||||
|
|
||||||
template<typename... P> format(P&&... p) { reserve(sizeof...(p)); append(forward<P>(p)...); }
|
template<typename... P> string_format(P&&... p) { reserve(sizeof...(p)); append(forward<P>(p)...); }
|
||||||
template<typename T, typename... P> inline auto append(const T&, P&&... p) -> type&;
|
template<typename T, typename... P> inline auto append(const T&, P&&... p) -> type&;
|
||||||
inline auto append() -> type&;
|
inline auto append() -> type&;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,16 +2,20 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
auto string::integer() const -> intmax {
|
auto string::integer() const -> intmax_t {
|
||||||
return nall::integer(data());
|
return toInteger(data());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::natural() const -> uintmax {
|
auto string::natural() const -> uintmax_t {
|
||||||
return nall::natural(data());
|
return toNatural(data());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto string::hex() const -> uintmax_t {
|
||||||
|
return toHex(data());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::real() const -> double {
|
auto string::real() const -> double {
|
||||||
return nall::real(data());
|
return toReal(data());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,42 +33,42 @@ template<> struct stringify<char> {
|
||||||
//signed integers
|
//signed integers
|
||||||
|
|
||||||
template<> struct stringify<signed char> {
|
template<> struct stringify<signed char> {
|
||||||
stringify(signed char source) { integer(_data, source); }
|
stringify(signed char source) { fromInteger(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[2 + sizeof(signed char) * 3];
|
char _data[2 + sizeof(signed char) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<signed short> {
|
template<> struct stringify<signed short> {
|
||||||
stringify(signed short source) { integer(_data, source); }
|
stringify(signed short source) { fromInteger(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[2 + sizeof(signed short) * 3];
|
char _data[2 + sizeof(signed short) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<signed int> {
|
template<> struct stringify<signed int> {
|
||||||
stringify(signed int source) { integer(_data, source); }
|
stringify(signed int source) { fromInteger(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[2 + sizeof(signed int) * 3];
|
char _data[2 + sizeof(signed int) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<signed long> {
|
template<> struct stringify<signed long> {
|
||||||
stringify(signed long source) { integer(_data, source); }
|
stringify(signed long source) { fromInteger(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[2 + sizeof(signed long) * 3];
|
char _data[2 + sizeof(signed long) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<signed long long> {
|
template<> struct stringify<signed long long> {
|
||||||
stringify(signed long long source) { integer(_data, source); }
|
stringify(signed long long source) { fromInteger(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[2 + sizeof(signed long long) * 3];
|
char _data[2 + sizeof(signed long long) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<uint Bits> struct stringify<Integer<Bits>> {
|
template<uint Bits> struct stringify<Integer<Bits>> {
|
||||||
stringify(Integer<Bits> source) { integer(_data, source); }
|
stringify(Integer<Bits> source) { fromInteger(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[2 + sizeof(int64_t) * 3];
|
char _data[2 + sizeof(int64_t) * 3];
|
||||||
|
@ -77,42 +77,42 @@ template<uint Bits> struct stringify<Integer<Bits>> {
|
||||||
//unsigned integers
|
//unsigned integers
|
||||||
|
|
||||||
template<> struct stringify<unsigned char> {
|
template<> struct stringify<unsigned char> {
|
||||||
stringify(unsigned char source) { natural(_data, source); }
|
stringify(unsigned char source) { fromNatural(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[1 + sizeof(unsigned char) * 3];
|
char _data[1 + sizeof(unsigned char) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<unsigned short> {
|
template<> struct stringify<unsigned short> {
|
||||||
stringify(unsigned short source) { natural(_data, source); }
|
stringify(unsigned short source) { fromNatural(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[1 + sizeof(unsigned short) * 3];
|
char _data[1 + sizeof(unsigned short) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<unsigned int> {
|
template<> struct stringify<unsigned int> {
|
||||||
stringify(unsigned int source) { natural(_data, source); }
|
stringify(unsigned int source) { fromNatural(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[1 + sizeof(unsigned int) * 3];
|
char _data[1 + sizeof(unsigned int) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<unsigned long> {
|
template<> struct stringify<unsigned long> {
|
||||||
stringify(unsigned long source) { natural(_data, source); }
|
stringify(unsigned long source) { fromNatural(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[1 + sizeof(unsigned long) * 3];
|
char _data[1 + sizeof(unsigned long) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<unsigned long long> {
|
template<> struct stringify<unsigned long long> {
|
||||||
stringify(unsigned long long source) { natural(_data, source); }
|
stringify(unsigned long long source) { fromNatural(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[1 + sizeof(unsigned long long) * 3];
|
char _data[1 + sizeof(unsigned long long) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<uint Bits> struct stringify<Natural<Bits>> {
|
template<uint Bits> struct stringify<Natural<Bits>> {
|
||||||
stringify(Natural<Bits> source) { natural(_data, source); }
|
stringify(Natural<Bits> source) { fromNatural(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[1 + sizeof(uint64_t) * 3];
|
char _data[1 + sizeof(uint64_t) * 3];
|
||||||
|
@ -121,28 +121,28 @@ template<uint Bits> struct stringify<Natural<Bits>> {
|
||||||
//floating-point
|
//floating-point
|
||||||
|
|
||||||
template<> struct stringify<float> {
|
template<> struct stringify<float> {
|
||||||
stringify(float source) { real(_data, source); }
|
stringify(float source) { fromReal(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[256];
|
char _data[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<double> {
|
template<> struct stringify<double> {
|
||||||
stringify(double source) { real(_data, source); }
|
stringify(double source) { fromReal(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[256];
|
char _data[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<long double> {
|
template<> struct stringify<long double> {
|
||||||
stringify(long double source) { real(_data, source); }
|
stringify(long double source) { fromReal(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[256];
|
char _data[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<uint Bits> struct stringify<Real<Bits>> {
|
template<uint Bits> struct stringify<Real<Bits>> {
|
||||||
stringify(Real<Bits> source) { real(_data, source); }
|
stringify(Real<Bits> source) { fromReal(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> uint { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[256];
|
char _data[256];
|
||||||
|
|
|
@ -30,7 +30,7 @@ template<typename T, typename... P> auto string::append(const T& value, P&&... p
|
||||||
return append(forward<P>(p)...);
|
return append(forward<P>(p)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... P> auto string::append(const nall::format& value, P&&... p) -> string& {
|
template<typename... P> auto string::append(const nall::string_format& value, P&&... p) -> string& {
|
||||||
format(value);
|
format(value);
|
||||||
return append(forward<P>(p)...);
|
return append(forward<P>(p)...);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@ auto string::date(time_t timestamp) -> string {
|
||||||
if(timestamp == 0) timestamp = ::time(nullptr);
|
if(timestamp == 0) timestamp = ::time(nullptr);
|
||||||
tm* info = localtime(×tamp);
|
tm* info = localtime(×tamp);
|
||||||
return {
|
return {
|
||||||
nall::natural(1900 + info->tm_year, 4L), "-",
|
numeral(1900 + info->tm_year, 4L), "-",
|
||||||
nall::natural(1 + info->tm_mon, 2L), "-",
|
numeral(1 + info->tm_mon, 2L), "-",
|
||||||
nall::natural(info->tm_mday, 2L)
|
numeral(info->tm_mday, 2L)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,9 +16,9 @@ auto string::time(time_t timestamp) -> string {
|
||||||
if(timestamp == 0) timestamp = ::time(nullptr);
|
if(timestamp == 0) timestamp = ::time(nullptr);
|
||||||
tm* info = localtime(×tamp);
|
tm* info = localtime(×tamp);
|
||||||
return {
|
return {
|
||||||
nall::natural(info->tm_hour, 2L), ":",
|
numeral(info->tm_hour, 2L), ":",
|
||||||
nall::natural(info->tm_min, 2L), ":",
|
numeral(info->tm_min, 2L), ":",
|
||||||
nall::natural(info->tm_sec, 2L)
|
numeral(info->tm_sec, 2L)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ inline auto evaluateExpression(Node* node) -> string {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto evaluateInteger(Node* node) -> int64_t {
|
inline auto evaluateInteger(Node* node) -> int64_t {
|
||||||
if(node->type == Node::Type::Literal) return nall::integer(node->literal);
|
if(node->type == Node::Type::Literal) return toInteger(node->literal);
|
||||||
|
|
||||||
#define p(n) evaluateInteger(node->link[n])
|
#define p(n) evaluateInteger(node->link[n])
|
||||||
switch(node->type) {
|
switch(node->type) {
|
||||||
|
@ -99,7 +99,7 @@ inline auto integer(const string& expression) -> maybe<int64_t> {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto evaluateReal(Node* node) -> long double {
|
inline auto evaluateReal(Node* node) -> long double {
|
||||||
if(node->type == Node::Type::Literal) return nall::real(node->literal);
|
if(node->type == Node::Type::Literal) return toReal(node->literal);
|
||||||
|
|
||||||
#define p(n) evaluateReal(node->link[n])
|
#define p(n) evaluateReal(node->link[n])
|
||||||
switch(node->type) {
|
switch(node->type) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace nall {
|
||||||
//nall::format is a vector<string> of parameters that can be applied to a string
|
//nall::format is a vector<string> of parameters that can be applied to a string
|
||||||
//each {#} token will be replaced with its appropriate format parameter
|
//each {#} token will be replaced with its appropriate format parameter
|
||||||
|
|
||||||
auto string::format(const nall::format& params) -> type& {
|
auto string::format(const nall::string_format& params) -> type& {
|
||||||
auto size = (int)this->size();
|
auto size = (int)this->size();
|
||||||
auto data = (char*)memory::allocate(size);
|
auto data = (char*)memory::allocate(size);
|
||||||
memory::copy(data, this->data(), size);
|
memory::copy(data, this->data(), size);
|
||||||
|
@ -32,7 +32,7 @@ auto string::format(const nall::format& params) -> type& {
|
||||||
};
|
};
|
||||||
if(!isNumeric(&data[x + 1], &data[y - 1])) { x++; continue; }
|
if(!isNumeric(&data[x + 1], &data[y - 1])) { x++; continue; }
|
||||||
|
|
||||||
uint index = nall::natural(&data[x + 1]);
|
uint index = toNatural(&data[x + 1]);
|
||||||
if(index >= params.size()) { x++; continue; }
|
if(index >= params.size()) { x++; continue; }
|
||||||
|
|
||||||
uint sourceSize = y - x;
|
uint sourceSize = y - x;
|
||||||
|
@ -59,12 +59,12 @@ auto string::format(const nall::format& params) -> type& {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename... P> auto format::append(const T& value, P&&... p) -> format& {
|
template<typename T, typename... P> auto string_format::append(const T& value, P&&... p) -> string_format& {
|
||||||
vector<string>::append(value);
|
vector<string>::append(value);
|
||||||
return append(forward<P>(p)...);
|
return append(forward<P>(p)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto format::append() -> format& {
|
auto string_format::append() -> string_format& {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,9 +78,10 @@ template<typename... P> auto print(FILE* fp, P&&... p) -> void {
|
||||||
fwrite(s.data(), 1, s.size(), fp);
|
fwrite(s.data(), 1, s.size(), fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto integer(intmax value, long precision, char padchar) -> string {
|
/*
|
||||||
|
auto integer(intmax_t value, long precision, char padchar) -> string {
|
||||||
string buffer;
|
string buffer;
|
||||||
buffer.resize(1 + sizeof(intmax) * 3);
|
buffer.resize(1 + sizeof(intmax_t) * 3);
|
||||||
char* p = buffer.get();
|
char* p = buffer.get();
|
||||||
|
|
||||||
bool negative = value < 0;
|
bool negative = value < 0;
|
||||||
|
@ -97,9 +98,9 @@ auto integer(intmax value, long precision, char padchar) -> string {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto natural(uintmax value, long precision, char padchar) -> string {
|
auto natural(uintmax_t value, long precision, char padchar) -> string {
|
||||||
string buffer;
|
string buffer;
|
||||||
buffer.resize(sizeof(uintmax) * 3);
|
buffer.resize(sizeof(uintmax_t) * 3);
|
||||||
char* p = buffer.get();
|
char* p = buffer.get();
|
||||||
|
|
||||||
uint size = 0;
|
uint size = 0;
|
||||||
|
@ -112,10 +113,17 @@ auto natural(uintmax value, long precision, char padchar) -> string {
|
||||||
if(precision) buffer.size(precision, padchar);
|
if(precision) buffer.size(precision, padchar);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
auto hex(uintmax value, long precision, char padchar) -> string {
|
template<typename T> auto numeral(T value, long precision, char padchar) -> string {
|
||||||
|
string buffer{value};
|
||||||
|
if(precision) buffer.size(precision, padchar);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hex(uintmax_t value, long precision, char padchar) -> string {
|
||||||
string buffer;
|
string buffer;
|
||||||
buffer.resize(sizeof(uintmax) * 2);
|
buffer.resize(sizeof(uintmax_t) * 2);
|
||||||
char* p = buffer.get();
|
char* p = buffer.get();
|
||||||
|
|
||||||
uint size = 0;
|
uint size = 0;
|
||||||
|
@ -130,9 +138,9 @@ auto hex(uintmax value, long precision, char padchar) -> string {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto octal(uintmax value, long precision, char padchar) -> string {
|
auto octal(uintmax_t value, long precision, char padchar) -> string {
|
||||||
string buffer;
|
string buffer;
|
||||||
buffer.resize(sizeof(uintmax) * 3);
|
buffer.resize(sizeof(uintmax_t) * 3);
|
||||||
char* p = buffer.get();
|
char* p = buffer.get();
|
||||||
|
|
||||||
uint size = 0;
|
uint size = 0;
|
||||||
|
@ -146,9 +154,9 @@ auto octal(uintmax value, long precision, char padchar) -> string {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto binary(uintmax value, long precision, char padchar) -> string {
|
auto binary(uintmax_t value, long precision, char padchar) -> string {
|
||||||
string buffer;
|
string buffer;
|
||||||
buffer.resize(sizeof(uintmax) * 8);
|
buffer.resize(sizeof(uintmax_t) * 8);
|
||||||
char* p = buffer.get();
|
char* p = buffer.get();
|
||||||
|
|
||||||
uint size = 0;
|
uint size = 0;
|
||||||
|
@ -164,19 +172,21 @@ auto binary(uintmax value, long precision, char padchar) -> string {
|
||||||
|
|
||||||
template<typename T> auto pointer(const T* value, long precision) -> string {
|
template<typename T> auto pointer(const T* value, long precision) -> string {
|
||||||
if(value == nullptr) return "(nullptr)";
|
if(value == nullptr) return "(nullptr)";
|
||||||
return {"0x", hex((uintptr)value, precision)};
|
return {"0x", hex((uintptr_t)value, precision)};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pointer(uintptr value, long precision) -> string {
|
auto pointer(uintptr_t value, long precision) -> string {
|
||||||
if(value == 0) return "(nullptr)";
|
if(value == 0) return "(nullptr)";
|
||||||
return {"0x", hex(value, precision)};
|
return {"0x", hex(value, precision)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
auto real(long double value) -> string {
|
auto real(long double value) -> string {
|
||||||
string temp;
|
string temp;
|
||||||
temp.resize(real(nullptr, value));
|
temp.resize(fromReal(nullptr, value));
|
||||||
real(temp.get(), value);
|
fromReal(temp.get(), value);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
auto lstring::operator==(const lstring& source) const -> bool {
|
auto string_vector::operator==(const string_vector& source) const -> bool {
|
||||||
if(this == &source) return true;
|
if(this == &source) return true;
|
||||||
if(size() != source.size()) return false;
|
if(size() != source.size()) return false;
|
||||||
for(uint n = 0; n < size(); n++) {
|
for(uint n = 0; n < size(); n++) {
|
||||||
|
@ -11,50 +11,50 @@ auto lstring::operator==(const lstring& source) const -> bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::operator!=(const lstring& source) const -> bool {
|
auto string_vector::operator!=(const string_vector& source) const -> bool {
|
||||||
return !operator==(source);
|
return !operator==(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::isort() -> lstring& {
|
auto string_vector::isort() -> type& {
|
||||||
sort([](const string& x, const string& y) {
|
sort([](const string& x, const string& y) {
|
||||||
return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0;
|
return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0;
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... P> auto lstring::append(const string& data, P&&... p) -> lstring& {
|
template<typename... P> auto string_vector::append(const string& data, P&&... p) -> type& {
|
||||||
vector::append(data);
|
vector::append(data);
|
||||||
append(forward<P>(p)...);
|
append(forward<P>(p)...);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::append() -> lstring& {
|
auto string_vector::append() -> type& {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::find(string_view source) const -> maybe<uint> {
|
auto string_vector::find(string_view source) const -> maybe<uint> {
|
||||||
for(uint n = 0; n < size(); n++) {
|
for(uint n = 0; n < size(); n++) {
|
||||||
if(operator[](n).equals(source)) return n;
|
if(operator[](n).equals(source)) return n;
|
||||||
}
|
}
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::ifind(string_view source) const -> maybe<uint> {
|
auto string_vector::ifind(string_view source) const -> maybe<uint> {
|
||||||
for(uint n = 0; n < size(); n++) {
|
for(uint n = 0; n < size(); n++) {
|
||||||
if(operator[](n).iequals(source)) return n;
|
if(operator[](n).iequals(source)) return n;
|
||||||
}
|
}
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::match(string_view pattern) const -> lstring {
|
auto string_vector::match(string_view pattern) const -> type {
|
||||||
lstring result;
|
string_vector result;
|
||||||
for(uint n = 0; n < size(); n++) {
|
for(uint n = 0; n < size(); n++) {
|
||||||
if(operator[](n).match(pattern)) result.append(operator[](n));
|
if(operator[](n).match(pattern)) result.append(operator[](n));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::merge(string_view separator) const -> string {
|
auto string_vector::merge(string_view separator) const -> string {
|
||||||
string output;
|
string output;
|
||||||
for(uint n = 0; n < size(); n++) {
|
for(uint n = 0; n < size(); n++) {
|
||||||
output.append(operator[](n));
|
output.append(operator[](n));
|
||||||
|
@ -63,7 +63,7 @@ auto lstring::merge(string_view separator) const -> string {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::strip() -> lstring& {
|
auto string_vector::strip() -> type& {
|
||||||
for(uint n = 0; n < size(); n++) {
|
for(uint n = 0; n < size(); n++) {
|
||||||
operator[](n).strip();
|
operator[](n).strip();
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,8 +59,8 @@ struct Node {
|
||||||
|
|
||||||
auto text() const -> string { return value().strip(); }
|
auto text() const -> string { return value().strip(); }
|
||||||
auto boolean() const -> bool { return text() == "true"; }
|
auto boolean() const -> bool { return text() == "true"; }
|
||||||
auto integer() const -> intmax { return text().integer(); }
|
auto integer() const -> intmax_t { return text().integer(); }
|
||||||
auto natural() const -> uintmax { return text().natural(); }
|
auto natural() const -> uintmax_t { return text().natural(); }
|
||||||
auto real() const -> double { return text().real(); }
|
auto real() const -> double { return text().real(); }
|
||||||
|
|
||||||
auto setName(const string& name = "") -> Node& { shared->_name = name; return *this; }
|
auto setName(const string& name = "") -> Node& { shared->_name = name; return *this; }
|
||||||
|
|
|
@ -68,7 +68,7 @@ auto tokenize(const char* s, const char* p) -> bool {
|
||||||
return !*p;
|
return !*p;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tokenize(lstring& list, const char* s, const char* p) -> bool {
|
auto tokenize(string_vector& list, const char* s, const char* p) -> bool {
|
||||||
while(*s) {
|
while(*s) {
|
||||||
if(*p == '*') {
|
if(*p == '*') {
|
||||||
const char* b = s;
|
const char* b = s;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<bool Insensitive, bool Quoted>
|
template<bool Insensitive, bool Quoted>
|
||||||
auto lstring::_split(string_view source, string_view find, long limit) -> lstring& {
|
auto string_vector::_split(string_view source, string_view find, long limit) -> string_vector& {
|
||||||
reset();
|
reset();
|
||||||
if(limit <= 0 || find.size() == 0) return *this;
|
if(limit <= 0 || find.size() == 0) return *this;
|
||||||
|
|
||||||
|
@ -33,9 +33,9 @@ auto lstring::_split(string_view source, string_view find, long limit) -> lstrin
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::split(string_view on, long limit) const -> lstring { return lstring()._split<0, 0>(*this, on, limit); }
|
auto string::split(string_view on, long limit) const -> string_vector { return string_vector()._split<0, 0>(*this, on, limit); }
|
||||||
auto string::isplit(string_view on, long limit) const -> lstring { return lstring()._split<1, 0>(*this, on, limit); }
|
auto string::isplit(string_view on, long limit) const -> string_vector { return string_vector()._split<1, 0>(*this, on, limit); }
|
||||||
auto string::qsplit(string_view on, long limit) const -> lstring { return lstring()._split<0, 1>(*this, on, limit); }
|
auto string::qsplit(string_view on, long limit) const -> string_vector { return string_vector()._split<0, 1>(*this, on, limit); }
|
||||||
auto string::iqsplit(string_view on, long limit) const -> lstring { return lstring()._split<1, 1>(*this, on, limit); }
|
auto string::iqsplit(string_view on, long limit) const -> string_vector { return string_vector()._split<1, 1>(*this, on, limit); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ auto slice(string_view self, int offset, int length) -> string {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto integer(char* result, intmax value) -> char* {
|
auto fromInteger(char* result, intmax_t value) -> char* {
|
||||||
bool negative = value < 0;
|
bool negative = value < 0;
|
||||||
if(negative) value = -value;
|
if(negative) value = -value;
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ auto integer(char* result, intmax value) -> char* {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto natural(char* result, uintmax value) -> char* {
|
auto fromNatural(char* result, uintmax_t value) -> char* {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
uint size = 0;
|
uint size = 0;
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ auto natural(char* result, uintmax value) -> char* {
|
||||||
//using sprintf is certainly not the most ideal method to convert
|
//using sprintf is certainly not the most ideal method to convert
|
||||||
//a double to a string ... but attempting to parse a double by
|
//a double to a string ... but attempting to parse a double by
|
||||||
//hand, digit-by-digit, results in subtle rounding errors.
|
//hand, digit-by-digit, results in subtle rounding errors.
|
||||||
auto real(char* result, long double value) -> uint {
|
auto fromReal(char* result, long double value) -> uint {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
//Windows C-runtime does not support long double via sprintf()
|
//Windows C-runtime does not support long double via sprintf()
|
||||||
|
|
|
@ -19,13 +19,13 @@ namespace nall {
|
||||||
struct thread {
|
struct thread {
|
||||||
inline auto join() -> void;
|
inline auto join() -> void;
|
||||||
|
|
||||||
static inline auto create(const function<void (uintptr)>& callback, uintptr parameter = 0, uint stacksize = 0) -> thread;
|
static inline auto create(const function<void (uintptr_t)>& callback, uintptr_t parameter = 0, uint stacksize = 0) -> thread;
|
||||||
static inline auto detach() -> void;
|
static inline auto detach() -> void;
|
||||||
static inline auto exit() -> void;
|
static inline auto exit() -> void;
|
||||||
|
|
||||||
struct context {
|
struct context {
|
||||||
function<auto (uintptr) -> void> callback;
|
function<auto (uintptr_t) -> void> callback;
|
||||||
uintptr parameter = 0;
|
uintptr_t parameter = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -43,7 +43,7 @@ auto thread::join() -> void {
|
||||||
pthread_join(handle, nullptr);
|
pthread_join(handle, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto thread::create(const function<void (uintptr)>& callback, uintptr parameter, uint stacksize) -> thread {
|
auto thread::create(const function<void (uintptr_t)>& callback, uintptr_t parameter, uint stacksize) -> thread {
|
||||||
thread instance;
|
thread instance;
|
||||||
|
|
||||||
auto context = new thread::context;
|
auto context = new thread::context;
|
||||||
|
@ -76,13 +76,13 @@ struct thread {
|
||||||
inline ~thread();
|
inline ~thread();
|
||||||
inline auto join() -> void;
|
inline auto join() -> void;
|
||||||
|
|
||||||
static inline auto create(const function<void (uintptr)>& callback, uintptr parameter = 0, uint stacksize = 0) -> thread;
|
static inline auto create(const function<void (uintptr_t)>& callback, uintptr_t parameter = 0, uint stacksize = 0) -> thread;
|
||||||
static inline auto detach() -> void;
|
static inline auto detach() -> void;
|
||||||
static inline auto exit() -> void;
|
static inline auto exit() -> void;
|
||||||
|
|
||||||
struct context {
|
struct context {
|
||||||
function<auto (uintptr) -> void> callback;
|
function<auto (uintptr_t) -> void> callback;
|
||||||
uintptr parameter = 0;
|
uintptr_t parameter = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -111,7 +111,7 @@ auto thread::join() -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto thread::create(const function<void (uintptr)>& callback, uintptr parameter, uint stacksize) -> thread {
|
auto thread::create(const function<void (uintptr_t)>& callback, uintptr_t parameter, uint stacksize) -> thread {
|
||||||
thread instance;
|
thread instance;
|
||||||
|
|
||||||
auto context = new thread::context;
|
auto context = new thread::context;
|
||||||
|
|
|
@ -10,8 +10,8 @@ struct varint {
|
||||||
virtual auto read() -> uint8_t = 0;
|
virtual auto read() -> uint8_t = 0;
|
||||||
virtual auto write(uint8_t) -> void = 0;
|
virtual auto write(uint8_t) -> void = 0;
|
||||||
|
|
||||||
auto readvu() -> uintmax {
|
auto readvu() -> uintmax_t {
|
||||||
uintmax data = 0, shift = 1;
|
uintmax_t data = 0, shift = 1;
|
||||||
while(true) {
|
while(true) {
|
||||||
uint8_t x = read();
|
uint8_t x = read();
|
||||||
data += (x & 0x7f) * shift;
|
data += (x & 0x7f) * shift;
|
||||||
|
@ -22,15 +22,15 @@ struct varint {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto readvs() -> intmax {
|
auto readvs() -> intmax_t {
|
||||||
uintmax data = readvu();
|
uintmax_t data = readvu();
|
||||||
bool negate = data & 1;
|
bool negate = data & 1;
|
||||||
data >>= 1;
|
data >>= 1;
|
||||||
if(negate) data = ~data;
|
if(negate) data = ~data;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writevu(uintmax data) -> void {
|
auto writevu(uintmax_t data) -> void {
|
||||||
while(true) {
|
while(true) {
|
||||||
uint8_t x = data & 0x7f;
|
uint8_t x = data & 0x7f;
|
||||||
data >>= 7;
|
data >>= 7;
|
||||||
|
@ -40,7 +40,7 @@ struct varint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writevs(intmax data) -> void {
|
auto writevs(intmax_t data) -> void {
|
||||||
bool negate = data < 0;
|
bool negate = data < 0;
|
||||||
if(negate) data = ~data;
|
if(negate) data = ~data;
|
||||||
data = (data << 1) | negate;
|
data = (data << 1) | negate;
|
||||||
|
|
|
@ -11,15 +11,15 @@ struct file : vfs::file {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto size() const -> uintmax override {
|
auto size() const -> uintmax_t override {
|
||||||
return _fp.size();
|
return _fp.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto offset() const -> uintmax override {
|
auto offset() const -> uintmax_t override {
|
||||||
return _fp.offset();
|
return _fp.offset();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto seek(intmax offset_, index index_) -> void override {
|
auto seek(intmax_t offset_, index index_) -> void override {
|
||||||
_fp.seek(offset_, (nall::file::index)index_);
|
_fp.seek(offset_, (nall::file::index)index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,18 +5,18 @@ namespace nall { namespace vfs { namespace memory {
|
||||||
struct file : vfs::file {
|
struct file : vfs::file {
|
||||||
~file() { delete[] _data; }
|
~file() { delete[] _data; }
|
||||||
|
|
||||||
static auto open(const uint8_t* data, uintmax size) -> vfs::shared::file {
|
static auto open(const uint8_t* data, uintmax_t size) -> vfs::shared::file {
|
||||||
auto instance = shared_pointer<file>{new file};
|
auto instance = shared_pointer<file>{new file};
|
||||||
instance->_open(data, size);
|
instance->_open(data, size);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto size() const -> uintmax override { return _size; }
|
auto size() const -> uintmax_t override { return _size; }
|
||||||
auto offset() const -> uintmax override { return _offset; }
|
auto offset() const -> uintmax_t override { return _offset; }
|
||||||
|
|
||||||
auto seek(intmax offset, index mode) -> void override {
|
auto seek(intmax_t offset, index mode) -> void override {
|
||||||
if(mode == index::absolute) _offset = (uintmax)offset;
|
if(mode == index::absolute) _offset = (uintmax_t)offset;
|
||||||
if(mode == index::relative) _offset += (intmax)offset;
|
if(mode == index::relative) _offset += (intmax_t)offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto read() -> uint8_t override {
|
auto read() -> uint8_t override {
|
||||||
|
@ -34,15 +34,15 @@ private:
|
||||||
file(const file&) = delete;
|
file(const file&) = delete;
|
||||||
auto operator=(const file&) -> file& = delete;
|
auto operator=(const file&) -> file& = delete;
|
||||||
|
|
||||||
auto _open(const uint8_t* data, uintmax size) -> void {
|
auto _open(const uint8_t* data, uintmax_t size) -> void {
|
||||||
_size = size;
|
_size = size;
|
||||||
_data = new uint8_t[size];
|
_data = new uint8_t[size];
|
||||||
nall::memory::copy(_data, data, size);
|
nall::memory::copy(_data, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* _data = nullptr;
|
uint8_t* _data = nullptr;
|
||||||
uintmax _size = 0;
|
uintmax_t _size = 0;
|
||||||
uintmax _offset = 0;
|
uintmax_t _offset = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}}}
|
}}}
|
||||||
|
|
|
@ -11,10 +11,10 @@ struct file {
|
||||||
|
|
||||||
virtual ~file() = default;
|
virtual ~file() = default;
|
||||||
|
|
||||||
virtual auto size() const -> uintmax = 0;
|
virtual auto size() const -> uintmax_t = 0;
|
||||||
virtual auto offset() const -> uintmax = 0;
|
virtual auto offset() const -> uintmax_t = 0;
|
||||||
|
|
||||||
virtual auto seek(intmax offset, index = index::absolute) -> void = 0;
|
virtual auto seek(intmax_t offset, index = index::absolute) -> void = 0;
|
||||||
virtual auto read() -> uint8_t = 0;
|
virtual auto read() -> uint8_t = 0;
|
||||||
virtual auto write(uint8_t data) -> void = 0;
|
virtual auto write(uint8_t data) -> void = 0;
|
||||||
virtual auto flush() -> void {}
|
virtual auto flush() -> void {}
|
||||||
|
@ -23,19 +23,19 @@ struct file {
|
||||||
return offset() >= size();
|
return offset() >= size();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto read(void* vdata, uintmax bytes) -> void {
|
auto read(void* vdata, uintmax_t bytes) -> void {
|
||||||
auto data = (uint8_t*)vdata;
|
auto data = (uint8_t*)vdata;
|
||||||
while(bytes--) *data++ = read();
|
while(bytes--) *data++ = read();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto readl(uint bytes) -> uintmax {
|
auto readl(uint bytes) -> uintmax_t {
|
||||||
uintmax data = 0;
|
uintmax_t data = 0;
|
||||||
for(auto n : range(bytes)) data |= (uintmax)read() << n * 8;
|
for(auto n : range(bytes)) data |= (uintmax_t)read() << n * 8;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto readm(uint bytes) -> uintmax {
|
auto readm(uint bytes) -> uintmax_t {
|
||||||
uintmax data = 0;
|
uintmax_t data = 0;
|
||||||
for(auto n : range(bytes)) data = data << 8 | read();
|
for(auto n : range(bytes)) data = data << 8 | read();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -47,16 +47,16 @@ struct file {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto write(const void* vdata, uintmax bytes) -> void {
|
auto write(const void* vdata, uintmax_t bytes) -> void {
|
||||||
auto data = (const uint8_t*)vdata;
|
auto data = (const uint8_t*)vdata;
|
||||||
while(bytes--) write(*data++);
|
while(bytes--) write(*data++);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writel(uintmax data, uint bytes) -> void {
|
auto writel(uintmax_t data, uint bytes) -> void {
|
||||||
for(auto n : range(bytes)) write(data), data >>= 8;
|
for(auto n : range(bytes)) write(data), data >>= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writem(uintmax data, uint bytes) -> void {
|
auto writem(uintmax_t data, uint bytes) -> void {
|
||||||
for(auto n : rrange(bytes)) write(data >> n * 8);
|
for(auto n : rrange(bytes)) write(data >> n * 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ struct InputXlib : Input {
|
||||||
~InputXlib() { term(); }
|
~InputXlib() { term(); }
|
||||||
|
|
||||||
struct Settings {
|
struct Settings {
|
||||||
uintptr handle = 0;
|
uintptr_t handle = 0;
|
||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
auto cap(const string& name) -> bool {
|
auto cap(const string& name) -> bool {
|
||||||
|
@ -29,8 +29,8 @@ struct InputXlib : Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto set(const string& name, const any& value) -> bool {
|
auto set(const string& name, const any& value) -> bool {
|
||||||
if(name == Input::Handle && value.is<uintptr>()) {
|
if(name == Input::Handle && value.is<uintptr_t>()) {
|
||||||
settings.handle = value.get<uintptr>();
|
settings.handle = value.get<uintptr_t>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,15 +32,15 @@ struct VideoCGL : Video, OpenGL {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto get(const string& name) -> any {
|
auto get(const string& name) -> any {
|
||||||
if(name == Video::Handle) return (uintptr)settings.handle;
|
if(name == Video::Handle) return (uintptr_t)settings.handle;
|
||||||
if(name == Video::Synchronize) return settings.synchronize;
|
if(name == Video::Synchronize) return settings.synchronize;
|
||||||
if(name == Video::Filter) return settings.filter;
|
if(name == Video::Filter) return settings.filter;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto set(const string& name, const any& value) -> bool {
|
auto set(const string& name, const any& value) -> bool {
|
||||||
if(name == Video::Handle && value.is<uintptr>()) {
|
if(name == Video::Handle && value.is<uintptr_t>()) {
|
||||||
settings.handle = (NSView*)value.get<uintptr>();
|
settings.handle = (NSView*)value.get<uintptr_t>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,11 +28,11 @@ auto OpenGL::shader(const string& pathname) -> void {
|
||||||
for(auto node : document["output"]) {
|
for(auto node : document["output"]) {
|
||||||
string text = node.text();
|
string text = node.text();
|
||||||
if(node.name() == "width") {
|
if(node.name() == "width") {
|
||||||
if(text.endsWith("%")) relativeWidth = real(text.trimRight("%", 1L)) / 100.0;
|
if(text.endsWith("%")) relativeWidth = toReal(text.trimRight("%", 1L)) / 100.0;
|
||||||
else absoluteWidth = text.natural();
|
else absoluteWidth = text.natural();
|
||||||
}
|
}
|
||||||
if(node.name() == "height") {
|
if(node.name() == "height") {
|
||||||
if(text.endsWith("%")) relativeHeight = real(text.trimRight("%", 1L)) / 100.0;
|
if(text.endsWith("%")) relativeHeight = toReal(text.trimRight("%", 1L)) / 100.0;
|
||||||
else absoluteHeight = text.natural();
|
else absoluteHeight = text.natural();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ auto OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin
|
||||||
modulo = glrModulo(node["modulo"].integer());
|
modulo = glrModulo(node["modulo"].integer());
|
||||||
|
|
||||||
string w = node["width"].text(), h = node["height"].text();
|
string w = node["width"].text(), h = node["height"].text();
|
||||||
if(w.endsWith("%")) relativeWidth = real(w.trimRight("%", 1L)) / 100.0;
|
if(w.endsWith("%")) relativeWidth = toReal(w.trimRight("%", 1L)) / 100.0;
|
||||||
else absoluteWidth = w.natural();
|
else absoluteWidth = w.natural();
|
||||||
if(h.endsWith("%")) relativeHeight = real(h.trimRight("%", 1L)) / 100.0;
|
if(h.endsWith("%")) relativeHeight = toReal(h.trimRight("%", 1L)) / 100.0;
|
||||||
else absoluteHeight = h.natural();
|
else absoluteHeight = h.natural();
|
||||||
|
|
||||||
format = glrFormat(node["format"].text());
|
format = glrFormat(node["format"].text());
|
||||||
|
|
|
@ -30,15 +30,15 @@ struct VideoWGL : Video, OpenGL {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto get(const string& name) -> any {
|
auto get(const string& name) -> any {
|
||||||
if(name == Video::Handle) return (uintptr)settings.handle;
|
if(name == Video::Handle) return (uintptr_t)settings.handle;
|
||||||
if(name == Video::Synchronize) return settings.synchronize;
|
if(name == Video::Synchronize) return settings.synchronize;
|
||||||
if(name == Video::Filter) return settings.filter;
|
if(name == Video::Filter) return settings.filter;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto set(const string& name, const any& value) -> bool {
|
auto set(const string& name, const any& value) -> bool {
|
||||||
if(name == Video::Handle && value.is<uintptr>()) {
|
if(name == Video::Handle && value.is<uintptr_t>()) {
|
||||||
settings.handle = (HWND)value.get<uintptr>();
|
settings.handle = (HWND)value.get<uintptr_t>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue